diff options
| author | Michael Biebl <biebl@debian.org> | 2018-05-11 22:08:45 +0200 |
|---|---|---|
| committer | Michael Biebl <biebl@debian.org> | 2018-05-11 22:08:45 +0200 |
| commit | ee9c73a923909e23a649407be77e25235d769e25 (patch) | |
| tree | e21c923621fa278e737da693df9eb60ea31a6067 /src | |
| parent | f60117b41d5433be1b4a96d82cd11d0c3dce9b63 (diff) | |
New upstream version 1.10.8 upstream/1.10.8
Diffstat (limited to 'src')
380 files changed, 21884 insertions, 26168 deletions
diff --git a/src/NetworkManagerUtils.c b/src/NetworkManagerUtils.c index b208ffc6..89bd357f 100644 --- a/src/NetworkManagerUtils.c +++ b/src/NetworkManagerUtils.c @@ -31,6 +31,7 @@ #include "nm-core-internal.h" #include "platform/nm-platform.h" +#include "nm-exported-object.h" #include "nm-auth-utils.h" /*****************************************************************************/ @@ -67,93 +68,98 @@ nm_utils_get_shared_wifi_permission (NMConnection *connection) /*****************************************************************************/ static char * -get_new_connection_name (NMConnection *const*existing_connections, +get_new_connection_name (const GSList *existing, const char *preferred, const char *fallback_prefix) { - gs_free const char **existing_names = NULL; - guint i, existing_len = 0; + GSList *names = NULL; + const GSList *iter; + char *cname = NULL; + int i = 0; + gboolean preferred_found = FALSE; g_assert (fallback_prefix); - if (existing_connections) { - existing_len = NM_PTRARRAY_LEN (existing_connections); - existing_names = g_new (const char *, existing_len); - for (i = 0; i < existing_len; i++) { - NMConnection *candidate; - const char *id; + for (iter = existing; iter; iter = g_slist_next (iter)) { + NMConnection *candidate = NM_CONNECTION (iter->data); + const char *id; - candidate = existing_connections[i]; - nm_assert (NM_IS_CONNECTION (candidate)); + id = nm_connection_get_id (candidate); + g_assert (id); + names = g_slist_append (names, (gpointer) id); - id = nm_connection_get_id (candidate); - nm_assert (id); - - existing_names[i] = id; - - if ( preferred - && nm_streq (preferred, id)) { - /* the preferred name is already taken. Forget about it. */ - preferred = NULL; - } - } - nm_assert (!existing_connections[i]); + if (preferred && !preferred_found && (strcmp (preferred, id) == 0)) + preferred_found = TRUE; } /* Return the preferred name if it was unique */ - if (preferred) + if (preferred && !preferred_found) { + g_slist_free (names); return g_strdup (preferred); + } /* Otherwise find the next available unique connection name using the given * connection name template. */ - for (i = 1; TRUE; i++) { + while (!cname && (i++ < 10000)) { char *temp; + gboolean found = FALSE; - /* TRANSLATORS: the first %s is a prefix for the connection id, such + /* Translators: the first %s is a prefix for the connection id, such * as "Wired Connection" or "VPN Connection". The %d is a number * that is combined with the first argument to create a unique * connection id. */ - temp = g_strdup_printf (C_("connection id fallback", "%s %u"), + temp = g_strdup_printf (C_("connection id fallback", "%s %d"), fallback_prefix, i); - - if (nm_utils_strv_find_first ((char **) existing_names, - existing_len, - temp) < 0) - return temp; - - g_free (temp); + for (iter = names; iter; iter = g_slist_next (iter)) { + if (!strcmp (iter->data, temp)) { + found = TRUE; + break; + } + } + if (!found) + cname = temp; + else + g_free (temp); } + + g_slist_free (names); + return cname; } static char * get_new_connection_ifname (NMPlatform *platform, - NMConnection *const*existing_connections, + const GSList *existing, const char *prefix) { - guint i, j; - - for (i = 0; TRUE; i++) { - char *name; + int i; + char *name; + const GSList *iter; + gboolean found; + for (i = 0; i < 500; i++) { name = g_strdup_printf ("%s%d", prefix, i); if (nm_platform_link_get_by_ifname (platform, name)) goto next; - if (existing_connections) { - for (j = 0; existing_connections[j]; j++) { - if (nm_streq0 (nm_connection_get_interface_name (existing_connections[j]), - name)) - goto next; + for (iter = existing, found = FALSE; iter; iter = g_slist_next (iter)) { + NMConnection *candidate = iter->data; + + if (g_strcmp0 (nm_connection_get_interface_name (candidate), name) == 0) { + found = TRUE; + break; } } - return name; + if (!found) + return name; -next: + next: g_free (name); } + + return NULL; } const char * @@ -245,7 +251,7 @@ void nm_utils_complete_generic (NMPlatform *platform, NMConnection *connection, const char *ctype, - NMConnection *const*existing_connections, + const GSList *existing, const char *preferred_id, const char *fallback_id_prefix, const char *ifname_prefix, @@ -272,14 +278,14 @@ nm_utils_complete_generic (NMPlatform *platform, /* Add a connection ID if absent */ if (!nm_setting_connection_get_id (s_con)) { - id = get_new_connection_name (existing_connections, preferred_id, fallback_id_prefix); + id = get_new_connection_name (existing, preferred_id, fallback_id_prefix); g_object_set (G_OBJECT (s_con), NM_SETTING_CONNECTION_ID, id, NULL); g_free (id); } /* Add an interface name, if requested */ if (ifname_prefix && !nm_setting_connection_get_interface_name (s_con)) { - ifname = get_new_connection_ifname (platform, existing_connections, ifname_prefix); + ifname = get_new_connection_ifname (platform, existing, ifname_prefix); g_object_set (G_OBJECT (s_con), NM_SETTING_CONNECTION_INTERFACE_NAME, ifname, NULL); g_free (ifname); } @@ -874,37 +880,58 @@ nm_utils_match_connection (NMConnection *const*connections, /*****************************************************************************/ -int -nm_match_spec_device_by_pllink (const NMPlatformLink *pllink, - const char *match_device_type, - const GSList *specs, - int no_match_value) +/** + * nm_utils_g_value_set_object_path: + * @value: a #GValue, initialized to store an object path + * @object: (allow-none): an #NMExportedObject + * + * Sets @value to @object's object path. If @object is %NULL, or not + * exported, @value is set to "/". + */ +void +nm_utils_g_value_set_object_path (GValue *value, gpointer object) +{ + g_return_if_fail (!object || NM_IS_EXPORTED_OBJECT (object)); + + if (object && nm_exported_object_is_exported (object)) + g_value_set_string (value, nm_exported_object_get_path (object)); + else + g_value_set_string (value, "/"); +} + +/** + * nm_utils_g_value_set_object_path_array: + * @value: a #GValue, initialized to store an object path + * @objects: a #GSList of #NMExportedObjects + * @filter_func: (allow-none): function to call on each object in @objects + * @user_data: data to pass to @filter_func + * + * Sets @value to an array of object paths of the objects in @objects. + */ +void +nm_utils_g_value_set_object_path_array (GValue *value, + GSList *objects, + NMUtilsObjectFunc filter_func, + gpointer user_data) { - NMMatchSpecMatchType m; - - /* we can only match by certain properties that are available on the - * platform link (and even @pllink might be missing. - * - * It's still useful because of specs like "*" and "except:interface-name:eth0", - * which match even in that case. */ - m = nm_match_spec_device (specs, - pllink ? pllink->name : NULL, - match_device_type, - pllink ? pllink->driver : NULL, - NULL, - NULL, - NULL); - - switch (m) { - case NM_MATCH_SPEC_MATCH: - return TRUE; - case NM_MATCH_SPEC_NEG_MATCH: - return FALSE; - case NM_MATCH_SPEC_NO_MATCH: - return no_match_value; + char **paths; + guint i; + GSList *iter; + + paths = g_new (char *, g_slist_length (objects) + 1); + for (i = 0, iter = objects; iter; iter = iter->next) { + NMExportedObject *object = iter->data; + const char *path; + + path = nm_exported_object_get_path (object); + if (!path) + continue; + if (filter_func && !filter_func ((GObject *) object, user_data)) + continue; + paths[i++] = g_strdup (path); } - nm_assert_not_reached (); - return no_match_value; + paths[i] = NULL; + g_value_take_boxed (value, paths); } - +/*****************************************************************************/ diff --git a/src/NetworkManagerUtils.h b/src/NetworkManagerUtils.h index 13bdb67e..e5f28b27 100644 --- a/src/NetworkManagerUtils.h +++ b/src/NetworkManagerUtils.h @@ -31,7 +31,7 @@ const char *nm_utils_get_shared_wifi_permission (NMConnection *connection); void nm_utils_complete_generic (NMPlatform *platform, NMConnection *connection, const char *ctype, - NMConnection *const*existing_connections, + const GSList *existing, const char *preferred_id, const char *fallback_id_prefix, const char *ifname_prefix, @@ -48,10 +48,21 @@ NMConnection *nm_utils_match_connection (NMConnection *const*connections, NMUtilsMatchFilterFunc match_filter_func, gpointer match_filter_data); -int nm_match_spec_device_by_pllink (const NMPlatformLink *pllink, - const char *match_device_type, - const GSList *specs, - int no_match_value); +void nm_utils_g_value_set_object_path (GValue *value, gpointer object); + +/** + * NMUtilsObjectFunc: + * @object: the object to filter on + * @user_data: data passed to the function from the caller + * + * Returns: %TRUE if the object should be used, %FALSE if not + */ +typedef gboolean (*NMUtilsObjectFunc) (GObject *object, gpointer user_data); + +void nm_utils_g_value_set_object_path_array (GValue *value, + GSList *objects, + NMUtilsObjectFunc filter_func, + gpointer user_data); /*****************************************************************************/ diff --git a/src/devices/adsl/meson.build b/src/devices/adsl/meson.build deleted file mode 100644 index 4b0fade0..00000000 --- a/src/devices/adsl/meson.build +++ /dev/null @@ -1,34 +0,0 @@ -sources = files( - 'nm-atm-manager.c', - 'nm-device-adsl.c' -) - -deps = [ - libudev_dep, - nm_dep -] - -libnm_device_plugin_adsl = shared_module( - 'nm-device-plugin-adsl', - sources: sources, - dependencies: deps, - link_args: ldflags_linker_script_devices, - link_depends: linker_script_devices, - install: true, - install_dir: nm_pkglibdir -) - -core_plugins += libnm_device_plugin_adsl - -run_target( - 'check-local-devices-adsl', - command: [check_exports, libnm_device_plugin_adsl.full_path(), linker_script_devices], - depends: libnm_device_plugin_adsl -) - -# FIXME: check_so_symbols replacement -''' -check-local-devices-adsl: src/devices/adsl/libnm-device-plugin-adsl.la - $(srcdir)/tools/check-exports.sh $(builddir)/src/devices/adsl/.libs/libnm-device-plugin-adsl.so "$(srcdir)/linker-script-devices.ver" - $(call check_so_symbols,$(builddir)/src/devices/adsl/.libs/libnm-device-plugin-adsl.so) -''' diff --git a/src/devices/adsl/nm-device-adsl.c b/src/devices/adsl/nm-device-adsl.c index 91331376..e9bd41ae 100644 --- a/src/devices/adsl/nm-device-adsl.c +++ b/src/devices/adsl/nm-device-adsl.c @@ -39,6 +39,8 @@ #include "nm-setting-adsl.h" #include "nm-utils.h" +#include "introspection/org.freedesktop.NetworkManager.Device.Adsl.h" + #include "devices/nm-device-logging.h" _LOG_DECLARE_SELF (NMDeviceAdsl); @@ -114,7 +116,7 @@ static gboolean complete_connection (NMDevice *device, NMConnection *connection, const char *specific_object, - NMConnection *const*existing_connections, + const GSList *existing_connections, GError **error) { NMSettingAdsl *s_adsl; @@ -135,6 +137,8 @@ complete_connection (NMDevice *device, _("ADSL connection"), NULL, FALSE); /* No IPv6 yet by default */ + + return TRUE; } @@ -427,22 +431,8 @@ ppp_state_changed (NMPPPManager *ppp_manager, NMPPPStatus status, gpointer user_ } static void -ppp_ifindex_set (NMPPPManager *ppp_manager, - int ifindex, - const char *iface, - gpointer user_data) -{ - NMDevice *device = NM_DEVICE (user_data); - - if (!nm_device_set_ip_ifindex (device, ifindex)) { - nm_device_state_changed (device, - NM_DEVICE_STATE_FAILED, - NM_DEVICE_STATE_REASON_IP_CONFIG_UNAVAILABLE); - } -} - -static void ppp_ip4_config (NMPPPManager *ppp_manager, + const char *iface, NMIP4Config *config, gpointer user_data) { @@ -450,6 +440,7 @@ ppp_ip4_config (NMPPPManager *ppp_manager, /* Ignore PPP IP4 events that come in after initial configuration */ if (nm_device_activate_ip4_state_in_conf (device)) { + nm_device_set_ip_iface (device, iface); nm_device_activate_schedule_ip4_config_result (device, config); } } @@ -508,9 +499,6 @@ act_stage3_ip4_config_start (NMDevice *device, g_signal_connect (priv->ppp_manager, NM_PPP_MANAGER_SIGNAL_STATE_CHANGED, G_CALLBACK (ppp_state_changed), self); - g_signal_connect (priv->ppp_manager, NM_PPP_MANAGER_SIGNAL_IFINDEX_SET, - G_CALLBACK (ppp_ifindex_set), - self); g_signal_connect (priv->ppp_manager, NM_PPP_MANAGER_SIGNAL_IP4_CONFIG, G_CALLBACK (ppp_ip4_config), self); @@ -651,24 +639,10 @@ dispose (GObject *object) G_OBJECT_CLASS (nm_device_adsl_parent_class)->dispose (object); } -static const NMDBusInterfaceInfoExtended interface_info_device_adsl = { - .parent = NM_DEFINE_GDBUS_INTERFACE_INFO_INIT ( - NM_DBUS_INTERFACE_DEVICE_ADSL, - .signals = NM_DEFINE_GDBUS_SIGNAL_INFOS ( - &nm_signal_info_property_changed_legacy, - ), - .properties = NM_DEFINE_GDBUS_PROPERTY_INFOS ( - NM_DEFINE_DBUS_PROPERTY_INFO_EXTENDED_READABLE_L ("Carrier", "b", NM_DEVICE_CARRIER), - ), - ), - .legacy_property_changed = TRUE, -}; - static void nm_device_adsl_class_init (NMDeviceAdslClass *klass) { GObjectClass *object_class = G_OBJECT_CLASS (klass); - NMDBusObjectClass *dbus_object_class = NM_DBUS_OBJECT_CLASS (klass); NMDeviceClass *parent_class = NM_DEVICE_CLASS (klass); object_class->constructed = constructed; @@ -676,8 +650,6 @@ nm_device_adsl_class_init (NMDeviceAdslClass *klass) object_class->get_property = get_property; object_class->set_property = set_property; - dbus_object_class->interface_infos = NM_DBUS_INTERFACE_INFOS (&interface_info_device_adsl); - parent_class->get_generic_capabilities = get_generic_capabilities; parent_class->check_connection_compatible = check_connection_compatible; @@ -694,4 +666,8 @@ nm_device_adsl_class_init (NMDeviceAdslClass *klass) G_PARAM_STATIC_STRINGS); g_object_class_install_properties (object_class, _PROPERTY_ENUMS_LAST, obj_properties); + + nm_exported_object_class_add_interface (NM_EXPORTED_OBJECT_CLASS (klass), + NMDBUS_TYPE_DEVICE_ADSL_SKELETON, + NULL); } diff --git a/src/devices/bluetooth/meson.build b/src/devices/bluetooth/meson.build deleted file mode 100644 index eb200679..00000000 --- a/src/devices/bluetooth/meson.build +++ /dev/null @@ -1,45 +0,0 @@ -sources = files( - 'nm-bluez-device.c', - 'nm-bluez-manager.c', - 'nm-bluez4-adapter.c', - 'nm-bluez4-manager.c', - 'nm-bluez5-manager.c', - 'nm-bt-error.c', - 'nm-device-bt.c' -) - -deps = [ - libnm_wwan_dep, - nm_dep -] - -if enable_bluez5_dun - sources += files('nm-bluez5-dun.c') - - deps += bluez5_dep -endif - -libnm_device_plugin_bluetooth = shared_module( - 'nm-device-plugin-bluetooth', - sources: sources, - dependencies: deps, - link_args: ldflags_linker_script_devices, - link_depends: linker_script_devices, - install: true, - install_dir: nm_pkglibdir -) - -core_plugins += libnm_device_plugin_bluetooth - -run_target( - 'check-local-devices-bluetooth', - command: [check_exports, libnm_device_plugin_bluetooth.full_path(), linker_script_devices], - depends: libnm_device_plugin_bluetooth -) - -# FIXME: check_so_symbols replacement -''' -check-local-devices-bluetooth: src/devices/bluetooth/libnm-device-plugin-bluetooth.la - $(srcdir)/tools/check-exports.sh $(builddir)/src/devices/bluetooth/.libs/libnm-device-plugin-bluetooth.so "$(srcdir)/linker-script-devices.ver" - $(call check_so_symbols,$(builddir)/src/devices/bluetooth/.libs/libnm-device-plugin-bluetooth.so) -''' diff --git a/src/devices/bluetooth/nm-bluez-device.c b/src/devices/bluetooth/nm-bluez-device.c index cc9e38c8..bd3cf18a 100644 --- a/src/devices/bluetooth/nm-bluez-device.c +++ b/src/devices/bluetooth/nm-bluez-device.c @@ -254,7 +254,7 @@ pan_connection_check_create (NMBluezDevice *self) g_assert (connection_compatible (self, added)); g_assert (nm_connection_compare (added, connection, NM_SETTING_COMPARE_FLAG_EXACT)); - nm_settings_connection_set_flags (NM_SETTINGS_CONNECTION (added), NM_SETTINGS_CONNECTION_INT_FLAGS_NM_GENERATED, TRUE); + nm_settings_connection_set_flags (NM_SETTINGS_CONNECTION (added), NM_SETTINGS_CONNECTION_FLAGS_NM_GENERATED, TRUE); priv->connections = g_slist_prepend (priv->connections, g_object_ref (added)); priv->pan_connection = added; @@ -1186,7 +1186,7 @@ dispose (GObject *object) /* Check whether we want to remove the created connection. If so, we take a reference * and delete it at the end of dispose(). */ if (NM_FLAGS_HAS (nm_settings_connection_get_flags (NM_SETTINGS_CONNECTION (priv->pan_connection)), - NM_SETTINGS_CONNECTION_INT_FLAGS_NM_GENERATED)) + NM_SETTINGS_CONNECTION_FLAGS_NM_GENERATED)) to_delete = g_object_ref (priv->pan_connection); priv->pan_connection = NULL; diff --git a/src/devices/bluetooth/nm-bluez4-adapter.c b/src/devices/bluetooth/nm-bluez4-adapter.c index c8ef7a27..0f19f998 100644 --- a/src/devices/bluetooth/nm-bluez4-adapter.c +++ b/src/devices/bluetooth/nm-bluez4-adapter.c @@ -25,6 +25,7 @@ #include <string.h> #include "nm-dbus-interface.h" +#include "nm-utils/nm-hash-utils.h" #include "nm-bluez-device.h" #include "nm-bluez-common.h" #include "nm-core-internal.h" diff --git a/src/devices/bluetooth/nm-bluez5-manager.c b/src/devices/bluetooth/nm-bluez5-manager.c index 5d3bd23a..de3f4072 100644 --- a/src/devices/bluetooth/nm-bluez5-manager.c +++ b/src/devices/bluetooth/nm-bluez5-manager.c @@ -30,7 +30,7 @@ #include "nm-core-internal.h" -#include "c-list/src/c-list.h" +#include "nm-utils/c-list.h" #include "nm-bluez-device.h" #include "nm-bluez-common.h" #include "devices/nm-device-bridge.h" diff --git a/src/devices/bluetooth/nm-device-bt.c b/src/devices/bluetooth/nm-device-bt.c index 1d237d92..977c1e1a 100644 --- a/src/devices/bluetooth/nm-device-bt.c +++ b/src/devices/bluetooth/nm-device-bt.c @@ -43,6 +43,8 @@ #include "devices/wwan/nm-modem-manager.h" #include "devices/wwan/nm-modem.h" +#include "introspection/org.freedesktop.NetworkManager.Device.Bluetooth.h" + #include "devices/nm-device-logging.h" _LOG_DECLARE_SELF(NMDeviceBt); @@ -215,7 +217,7 @@ static gboolean complete_connection (NMDevice *device, NMConnection *connection, const char *specific_object, - NMConnection *const*existing_connections, + const GSList *existing_connections, GError **error) { NMDeviceBtPrivate *priv = NM_DEVICE_BT_GET_PRIVATE ((NMDeviceBt *) device); @@ -538,16 +540,11 @@ modem_ip4_config_result (NMModem *modem, } static void -ip_ifindex_changed_cb (NMModem *modem, GParamSpec *pspec, gpointer user_data) +data_port_changed_cb (NMModem *modem, GParamSpec *pspec, gpointer user_data) { - NMDevice *device = NM_DEVICE (user_data); + NMDevice *self = NM_DEVICE (user_data); - if (!nm_device_set_ip_ifindex (device, - nm_modem_get_ip_ifindex (modem))) { - nm_device_state_changed (device, - NM_DEVICE_STATE_FAILED, - NM_DEVICE_STATE_REASON_IP_CONFIG_UNAVAILABLE); - } + nm_device_set_ip_iface (self, nm_modem_get_data_port (modem)); } static gboolean @@ -643,24 +640,29 @@ component_added (NMDevice *device, GObject *component) NMDeviceBt *self = NM_DEVICE_BT (device); NMDeviceBtPrivate *priv = NM_DEVICE_BT_GET_PRIVATE (self); NMModem *modem; + const gchar *modem_data_port; + const gchar *modem_control_port; + char *base; NMDeviceState state; NMDeviceStateReason failure_reason = NM_DEVICE_STATE_REASON_NONE; - if ( !component - || !NM_IS_MODEM (component)) + if (!component || !NM_IS_MODEM (component)) return FALSE; - modem = NM_MODEM (component); + + modem_data_port = nm_modem_get_data_port (modem); + modem_control_port = nm_modem_get_control_port (modem); + g_return_val_if_fail (modem_data_port != NULL || modem_control_port != NULL, FALSE); + if (!priv->rfcomm_iface) return FALSE; - { - gs_free char *base = NULL; - - base = g_path_get_basename (priv->rfcomm_iface); - if (!nm_streq (base, nm_modem_get_control_port (modem))) - return FALSE; + base = g_path_get_basename (priv->rfcomm_iface); + if (g_strcmp0 (base, modem_data_port) && g_strcmp0 (base, modem_control_port)) { + g_free (base); + return FALSE; } + g_free (base); /* Got the modem */ nm_clear_g_source (&priv->timeout_id); @@ -694,7 +696,7 @@ component_added (NMDevice *device, GObject *component) g_signal_connect (modem, NM_MODEM_STATE_CHANGED, G_CALLBACK (modem_state_cb), self); g_signal_connect (modem, NM_MODEM_REMOVED, G_CALLBACK (modem_removed_cb), self); - g_signal_connect (modem, "notify::" NM_MODEM_IP_IFINDEX, G_CALLBACK (ip_ifindex_changed_cb), self); + g_signal_connect (modem, "notify::" NM_MODEM_DATA_PORT, G_CALLBACK (data_port_changed_cb), self); /* Kick off the modem connection */ if (!modem_stage1 (self, modem, &failure_reason)) @@ -751,7 +753,7 @@ bluez_connect_cb (GObject *object, GAsyncResult *res, void *user_data) { - gs_unref_object NMDeviceBt *self = NM_DEVICE_BT (user_data); + NMDeviceBt *self = NM_DEVICE_BT (user_data); NMDeviceBtPrivate *priv = NM_DEVICE_BT_GET_PRIVATE (self); GError *error = NULL; const char *device; @@ -759,9 +761,6 @@ bluez_connect_cb (GObject *object, device = nm_bluez_device_connect_finish (NM_BLUEZ_DEVICE (object), res, &error); - if (!nm_device_is_activating (NM_DEVICE (self))) - return; - if (!device) { _LOGW (LOGD_BT, "Error connecting with bluez: %s", error->message); g_clear_error (&error); @@ -769,6 +768,7 @@ bluez_connect_cb (GObject *object, nm_device_state_changed (NM_DEVICE (self), NM_DEVICE_STATE_FAILED, NM_DEVICE_STATE_REASON_BT_FAILED); + g_object_unref (self); return; } @@ -776,13 +776,7 @@ bluez_connect_cb (GObject *object, g_free (priv->rfcomm_iface); priv->rfcomm_iface = g_strdup (device); } else if (priv->bt_type == NM_BT_CAPABILITY_NAP) { - if (!nm_device_set_ip_iface (NM_DEVICE (self), device)) { - _LOGW (LOGD_BT, "Error connecting with bluez: cannot find device %s", device); - nm_device_state_changed (NM_DEVICE (self), - NM_DEVICE_STATE_FAILED, - NM_DEVICE_STATE_REASON_BT_FAILED); - return; - } + nm_device_set_ip_iface (NM_DEVICE (self), device); } _LOGD (LOGD_BT, "connect request successful"); @@ -790,6 +784,7 @@ bluez_connect_cb (GObject *object, /* Stage 3 gets scheduled when Bluez says we're connected */ priv->have_iface = TRUE; check_connect_continue (self); + g_object_unref (self); } static void @@ -1150,26 +1145,10 @@ finalize (GObject *object) G_OBJECT_CLASS (nm_device_bt_parent_class)->finalize (object); } -static const NMDBusInterfaceInfoExtended interface_info_device_bluetooth = { - .parent = NM_DEFINE_GDBUS_INTERFACE_INFO_INIT ( - NM_DBUS_INTERFACE_DEVICE_BLUETOOTH, - .signals = NM_DEFINE_GDBUS_SIGNAL_INFOS ( - &nm_signal_info_property_changed_legacy, - ), - .properties = NM_DEFINE_GDBUS_PROPERTY_INFOS ( - NM_DEFINE_DBUS_PROPERTY_INFO_EXTENDED_READABLE_L ("HwAddress", "s", NM_DEVICE_HW_ADDRESS), - NM_DEFINE_DBUS_PROPERTY_INFO_EXTENDED_READABLE_L ("Name", "s", NM_DEVICE_BT_NAME), - NM_DEFINE_DBUS_PROPERTY_INFO_EXTENDED_READABLE_L ("BtCapabilities", "u", NM_DEVICE_BT_CAPABILITIES), - ), - ), - .legacy_property_changed = TRUE, -}; - static void nm_device_bt_class_init (NMDeviceBtClass *klass) { GObjectClass *object_class = G_OBJECT_CLASS (klass); - NMDBusObjectClass *dbus_object_class = NM_DBUS_OBJECT_CLASS (klass); NMDeviceClass *device_class = NM_DEVICE_CLASS (klass); object_class->constructed = constructed; @@ -1178,8 +1157,6 @@ nm_device_bt_class_init (NMDeviceBtClass *klass) object_class->dispose = dispose; object_class->finalize = finalize; - dbus_object_class->interface_infos = NM_DBUS_INTERFACE_INFOS (&interface_info_device_bluetooth); - device_class->get_generic_capabilities = get_generic_capabilities; device_class->can_auto_connect = can_auto_connect; device_class->deactivate = deactivate; @@ -1223,4 +1200,8 @@ nm_device_bt_class_init (NMDeviceBtClass *klass) G_TYPE_NONE, 2, G_TYPE_UINT /*guint32 in_bytes*/, G_TYPE_UINT /*guint32 out_bytes*/); + + nm_exported_object_class_add_interface (NM_EXPORTED_OBJECT_CLASS (klass), + NMDBUS_TYPE_DEVICE_BLUETOOTH_SKELETON, + NULL); } diff --git a/src/devices/meson.build b/src/devices/meson.build deleted file mode 100644 index 2d874659..00000000 --- a/src/devices/meson.build +++ /dev/null @@ -1,22 +0,0 @@ -subdir('adsl') - -if enable_modem_manager - subdir('wwan') - subdir('bluetooth') -endif - -if enable_wifi - subdir('wifi') -endif - -if enable_teamdctl - subdir('team') -endif - -if enable_ovs - subdir('ovs') -endif - -if enable_tests - subdir('tests') -endif diff --git a/src/devices/nm-acd-manager.c b/src/devices/nm-acd-manager.c deleted file mode 100644 index 1bade4ff..00000000 --- a/src/devices/nm-acd-manager.c +++ /dev/null @@ -1,489 +0,0 @@ -/* -*- Mode: C; tab-width: 4; indent-tabs-mode: t; c-basic-offset: 4 -*- */ -/* NetworkManager -- Network link manager - * - * This program is free software; you can redistribute it and/or modify - * it under the terms of the GNU General Public License as published by - * the Free Software Foundation; either version 2 of the License, or - * (at your option) any later version. - * - * This program is distributed in the hope that it will be useful, - * but WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the - * GNU General Public License for more details. - * - * Copyright (C) 2015-2018 Red Hat, Inc. - */ - -#include "nm-default.h" - -#include "nm-acd-manager.h" - -#include <netinet/in.h> -#include <sys/types.h> -#include <sys/wait.h> - -#include "platform/nm-platform.h" -#include "nm-utils.h" -#include "NetworkManagerUtils.h" -#include "n-acd/src/n-acd.h" - -/*****************************************************************************/ - -typedef enum { - STATE_INIT, - STATE_PROBING, - STATE_PROBE_DONE, - STATE_ANNOUNCING, -} State; - -typedef struct { - in_addr_t address; - gboolean duplicate; - NMAcdManager *manager; - NAcd *acd; - GIOChannel *channel; - guint event_id; -} AddressInfo; - -enum { - PROBE_TERMINATED, - LAST_SIGNAL, -}; - -static guint signals[LAST_SIGNAL] = { 0 }; - -typedef struct { - int ifindex; - guint8 hwaddr[ETH_ALEN]; - State state; - GHashTable *addresses; - guint completed; -} NMAcdManagerPrivate; - -struct _NMAcdManager { - GObject parent; - NMAcdManagerPrivate _priv; -}; - -struct _NMAcdManagerClass { - GObjectClass parent; -}; - -G_DEFINE_TYPE (NMAcdManager, nm_acd_manager, G_TYPE_OBJECT) - -#define NM_ACD_MANAGER_GET_PRIVATE(self) _NM_GET_PRIVATE (self, NMAcdManager, NM_IS_ACD_MANAGER) - -/*****************************************************************************/ - -#define _NMLOG_DOMAIN LOGD_IP4 -#define _NMLOG_PREFIX_NAME "acd" -#define _NMLOG(level, ...) \ - G_STMT_START { \ - char _sbuf[64]; \ - int _ifindex = (self) ? NM_ACD_MANAGER_GET_PRIVATE (self)->ifindex : 0; \ - \ - nm_log ((level), _NMLOG_DOMAIN, \ - nm_platform_link_get_name (NM_PLATFORM_GET, _ifindex), \ - NULL, \ - "%s%s: " _NM_UTILS_MACRO_FIRST (__VA_ARGS__), \ - _NMLOG_PREFIX_NAME, \ - self ? nm_sprintf_buf (_sbuf, "[%p,%d]", self, _ifindex) : "" \ - _NM_UTILS_MACRO_REST (__VA_ARGS__)); \ - } G_STMT_END - -/*****************************************************************************/ - -static const char * -_acd_event_to_string (unsigned int event) -{ - switch (event) { - case N_ACD_EVENT_READY: - return "ready"; - case N_ACD_EVENT_USED: - return "used"; - case N_ACD_EVENT_DEFENDED: - return "defended"; - case N_ACD_EVENT_CONFLICT: - return "conflict"; - case N_ACD_EVENT_DOWN: - return "down"; - } - return NULL; -} - -#define acd_event_to_string(event) NM_UTILS_LOOKUP_STR (_acd_event_to_string, event) - -static const char * -_acd_error_to_string (int error) -{ - if (error < 0) - return strerror(-error); - - switch (error) { - case _N_ACD_E_SUCCESS: - return "success"; - case N_ACD_E_DONE: - return "no more events (engine running)"; - case N_ACD_E_STOPPED: - return "no more events (engine stopped)"; - case N_ACD_E_PREEMPTED: - return "preempted"; - case N_ACD_E_INVALID_ARGUMENT: - return "invalid argument"; - case N_ACD_E_BUSY: - return "busy"; - } - return NULL; -} - -#define acd_error_to_string(error) NM_UTILS_LOOKUP_STR (_acd_error_to_string, error) - -/*****************************************************************************/ - -/** - * nm_acd_manager_add_address: - * @self: a #NMAcdManager - * @address: an IP address - * - * Add @address to the list of IP addresses to probe. - - * Returns: %TRUE on success, %FALSE if the address was already in the list - */ -gboolean -nm_acd_manager_add_address (NMAcdManager *self, in_addr_t address) -{ - NMAcdManagerPrivate *priv; - AddressInfo *info; - - g_return_val_if_fail (NM_IS_ACD_MANAGER (self), FALSE); - priv = NM_ACD_MANAGER_GET_PRIVATE (self); - g_return_val_if_fail (priv->state == STATE_INIT, FALSE); - - if (g_hash_table_lookup (priv->addresses, GUINT_TO_POINTER (address))) - return FALSE; - - info = g_slice_new0 (AddressInfo); - info->address = address; - info->manager = self; - - g_hash_table_insert (priv->addresses, GUINT_TO_POINTER (address), info); - - return TRUE; -} - -static gboolean -acd_event (GIOChannel *source, GIOCondition condition, gpointer data) -{ - AddressInfo *info = data; - NMAcdManager *self = info->manager; - NMAcdManagerPrivate *priv = NM_ACD_MANAGER_GET_PRIVATE (self); - NAcdEvent *event; - char address_str[INET_ADDRSTRLEN]; - gs_free char *hwaddr_str = NULL; - int r; - - if ( n_acd_dispatch (info->acd) - || n_acd_pop_event (info->acd, &event)) - return G_SOURCE_CONTINUE; - - switch (event->event) { - case N_ACD_EVENT_READY: - info->duplicate = FALSE; - if (priv->state == STATE_ANNOUNCING) { - r = n_acd_announce (info->acd, N_ACD_DEFEND_ONCE); - if (r) { - _LOGW ("couldn't announce address %s on interface '%s': %s", - nm_utils_inet4_ntop (info->address, address_str), - nm_platform_link_get_name (NM_PLATFORM_GET, priv->ifindex), - acd_error_to_string (r)); - } else { - _LOGD ("announcing address %s", - nm_utils_inet4_ntop (info->address, address_str)); - } - } - break; - case N_ACD_EVENT_USED: - info->duplicate = TRUE; - break; - case N_ACD_EVENT_DEFENDED: - _LOGD ("defended address %s from host %s", - nm_utils_inet4_ntop (info->address, address_str), - (hwaddr_str = nm_utils_hwaddr_ntoa (event->defended.sender, - event->defended.n_sender))); - break; - case N_ACD_EVENT_CONFLICT: - _LOGW ("conflict for address %s detected with host %s on interface '%s'", - nm_utils_inet4_ntop (info->address, address_str), - (hwaddr_str = nm_utils_hwaddr_ntoa (event->defended.sender, - event->defended.n_sender)), - nm_platform_link_get_name (NM_PLATFORM_GET, priv->ifindex)); - break; - default: - _LOGD ("event '%s' for address %s", - acd_event_to_string (event->event), - nm_utils_inet4_ntop (info->address, address_str)); - return G_SOURCE_CONTINUE; - } - - if ( priv->state == STATE_PROBING - && ++priv->completed == g_hash_table_size (priv->addresses)) { - priv->state = STATE_PROBE_DONE; - g_signal_emit (self, signals[PROBE_TERMINATED], 0); - } - - return G_SOURCE_CONTINUE; -} - -static gboolean -acd_probe_start (NMAcdManager *self, - AddressInfo *info, - guint64 timeout) -{ - NMAcdManagerPrivate *priv = NM_ACD_MANAGER_GET_PRIVATE (self); - NAcdConfig *config; - int r, fd; - - r = n_acd_new (&info->acd); - if (r) { - _LOGW ("could not create ACD for %s on interface '%s': %s", - nm_utils_inet4_ntop (info->address, NULL), - nm_platform_link_get_name (NM_PLATFORM_GET, priv->ifindex), - acd_error_to_string (r)); - return FALSE; - } - - n_acd_get_fd (info->acd, &fd); - info->channel = g_io_channel_unix_new (fd); - info->event_id = g_io_add_watch (info->channel, G_IO_IN, acd_event, info); - - config = &(NAcdConfig) { - .ifindex = priv->ifindex, - .mac = priv->hwaddr, - .n_mac = ETH_ALEN, - .ip = info->address, - .timeout_msec = timeout, - .transport = N_ACD_TRANSPORT_ETHERNET, - }; - - r = n_acd_start (info->acd, config); - if (r) { - _LOGW ("could not start probe for %s on interface '%s': %s", - nm_utils_inet4_ntop (info->address, NULL), - nm_platform_link_get_name (NM_PLATFORM_GET, priv->ifindex), - acd_error_to_string (r)); - return FALSE; - } - - _LOGD ("start probe for %s", nm_utils_inet4_ntop (info->address, NULL)); - - return TRUE; -} - -/** - * nm_acd_manager_start_probe: - * @self: a #NMAcdManager - * @timeout: maximum probe duration in milliseconds - * @error: location to store error, or %NULL - * - * Start probing IP addresses for duplicates; when the probe terminates a - * PROBE_TERMINATED signal is emitted. - * - * Returns: %TRUE if at least one probe could be started, %FALSE otherwise - */ -gboolean -nm_acd_manager_start_probe (NMAcdManager *self, guint timeout) -{ - NMAcdManagerPrivate *priv; - GHashTableIter iter; - AddressInfo *info; - gboolean success = FALSE; - - g_return_val_if_fail (NM_IS_ACD_MANAGER (self), FALSE); - priv = NM_ACD_MANAGER_GET_PRIVATE (self); - g_return_val_if_fail (priv->state == STATE_INIT, FALSE); - - priv->completed = 0; - - g_hash_table_iter_init (&iter, priv->addresses); - while (g_hash_table_iter_next (&iter, NULL, (gpointer *) &info)) - success |= acd_probe_start (self, info, timeout); - - if (success) - priv->state = STATE_PROBING; - - return success; -} - -/** - * nm_acd_manager_reset: - * @self: a #NMAcdManager - * - * Stop any operation in progress and reset @self to the initial state. - */ -void -nm_acd_manager_reset (NMAcdManager *self) -{ - NMAcdManagerPrivate *priv; - - g_return_if_fail (NM_IS_ACD_MANAGER (self)); - priv = NM_ACD_MANAGER_GET_PRIVATE (self); - - g_hash_table_remove_all (priv->addresses); - - priv->state = STATE_INIT; -} - -/** - * nm_acd_manager_destroy: - * @self: the #NMAcdManager - * - * Calls nm_acd_manager_reset() and unrefs @self. - */ -void -nm_acd_manager_destroy (NMAcdManager *self) -{ - g_return_if_fail (NM_IS_ACD_MANAGER (self)); - - nm_acd_manager_reset (self); - g_object_unref (self); -} - -/** - * nm_acd_manager_check_address: - * @self: a #NMAcdManager - * @address: an IP address - * - * Check if an IP address is duplicate. @address must have been added with - * nm_acd_manager_add_address(). - * - * Returns: %TRUE if the address is not duplicate, %FALSE otherwise - */ -gboolean -nm_acd_manager_check_address (NMAcdManager *self, in_addr_t address) -{ - NMAcdManagerPrivate *priv; - AddressInfo *info; - - g_return_val_if_fail (NM_IS_ACD_MANAGER (self), FALSE); - priv = NM_ACD_MANAGER_GET_PRIVATE (self); - g_return_val_if_fail ( priv->state == STATE_INIT - || priv->state == STATE_PROBE_DONE, FALSE); - - info = g_hash_table_lookup (priv->addresses, GUINT_TO_POINTER (address)); - g_return_val_if_fail (info, FALSE); - - return !info->duplicate; -} - -/** - * nm_acd_manager_announce_addresses: - * @self: a #NMAcdManager - * - * Start announcing addresses. - */ -void -nm_acd_manager_announce_addresses (NMAcdManager *self) -{ - NMAcdManagerPrivate *priv = NM_ACD_MANAGER_GET_PRIVATE (self); - GHashTableIter iter; - AddressInfo *info; - int r; - - if (priv->state == STATE_INIT) { - /* n-acd can't announce without probing, therefore let's - * start a fake probe with zero timeout and then perform - * the announce. */ - priv->state = STATE_ANNOUNCING; - g_hash_table_iter_init (&iter, priv->addresses); - while (g_hash_table_iter_next (&iter, NULL, (gpointer *) &info)) { - if (!acd_probe_start (self, info, 0)) { - _LOGW ("couldn't announce address %s on interface '%s'", - nm_utils_inet4_ntop (info->address, NULL), - nm_platform_link_get_name (NM_PLATFORM_GET, priv->ifindex)); - } - } - } else if (priv->state == STATE_PROBE_DONE) { - priv->state = STATE_ANNOUNCING; - g_hash_table_iter_init (&iter, priv->addresses); - while (g_hash_table_iter_next (&iter, NULL, (gpointer *) &info)) { - if (info->duplicate) - continue; - r = n_acd_announce (info->acd, N_ACD_DEFEND_ONCE); - if (r) { - _LOGW ("couldn't announce address %s on interface '%s': %s", - nm_utils_inet4_ntop (info->address, NULL), - nm_platform_link_get_name (NM_PLATFORM_GET, priv->ifindex), - acd_error_to_string (r)); - } else - _LOGD ("announcing address %s", nm_utils_inet4_ntop (info->address, NULL)); - } - } else - nm_assert_not_reached (); -} - -static void -destroy_address_info (gpointer data) -{ - AddressInfo *info = (AddressInfo *) data; - - g_clear_pointer (&info->channel, g_io_channel_unref); - g_clear_pointer (&info->acd, n_acd_free); - nm_clear_g_source (&info->event_id); - - g_slice_free (AddressInfo, info); -} - -/*****************************************************************************/ - -static void -nm_acd_manager_init (NMAcdManager *self) -{ - NMAcdManagerPrivate *priv = NM_ACD_MANAGER_GET_PRIVATE (self); - - priv->addresses = g_hash_table_new_full (nm_direct_hash, NULL, - NULL, destroy_address_info); - priv->state = STATE_INIT; -} - -NMAcdManager * -nm_acd_manager_new (int ifindex, const guint8 *hwaddr, size_t hwaddr_len) -{ - NMAcdManager *self; - NMAcdManagerPrivate *priv; - - g_return_val_if_fail (hwaddr, NULL); - g_return_val_if_fail (hwaddr_len == ETH_ALEN, NULL); - - self = g_object_new (NM_TYPE_ACD_MANAGER, NULL); - priv = NM_ACD_MANAGER_GET_PRIVATE (self); - priv->ifindex = ifindex; - memcpy (priv->hwaddr, hwaddr, ETH_ALEN); - - return self; -} - -static void -dispose (GObject *object) -{ - NMAcdManager *self = NM_ACD_MANAGER (object); - NMAcdManagerPrivate *priv = NM_ACD_MANAGER_GET_PRIVATE (self); - - g_clear_pointer (&priv->addresses, g_hash_table_destroy); - - G_OBJECT_CLASS (nm_acd_manager_parent_class)->dispose (object); -} - -static void -nm_acd_manager_class_init (NMAcdManagerClass *klass) -{ - GObjectClass *object_class = G_OBJECT_CLASS (klass); - - object_class->dispose = dispose; - - signals[PROBE_TERMINATED] = - g_signal_new (NM_ACD_MANAGER_PROBE_TERMINATED, - G_OBJECT_CLASS_TYPE (object_class), - G_SIGNAL_RUN_FIRST, - 0, NULL, NULL, NULL, - G_TYPE_NONE, 0); -} diff --git a/src/devices/nm-acd-manager.h b/src/devices/nm-acd-manager.h deleted file mode 100644 index eeede5da..00000000 --- a/src/devices/nm-acd-manager.h +++ /dev/null @@ -1,43 +0,0 @@ -/* -*- Mode: C; tab-width: 4; indent-tabs-mode: t; c-basic-offset: 4 -*- */ -/* NetworkManager -- Network link manager - * - * This program is free software; you can redistribute it and/or modify - * it under the terms of the GNU General Public License as published by - * the Free Software Foundation; either version 2 of the License, or - * (at your option) any later version. - * - * This program is distributed in the hope that it will be useful, - * but WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the - * GNU General Public License for more details. - * - * Copyright (C) 2015-2018 Red Hat, Inc. - */ - -#ifndef __NM_ACD_MANAGER__ -#define __NM_ACD_MANAGER__ - -#include <netinet/in.h> - -#define NM_TYPE_ACD_MANAGER (nm_acd_manager_get_type ()) -#define NM_ACD_MANAGER(obj) (G_TYPE_CHECK_INSTANCE_CAST ((obj), NM_TYPE_ACD_MANAGER, NMAcdManager)) -#define NM_ACD_MANAGER_CLASS(klass) (G_TYPE_CHECK_CLASS_CAST ((klass), NM_TYPE_ACD_MANAGER, NMAcdManagerClass)) -#define NM_IS_ACD_MANAGER(obj) (G_TYPE_CHECK_INSTANCE_TYPE ((obj), NM_TYPE_ACD_MANAGER)) -#define NM_IS_ACD_MANAGER_CLASS(klass) (G_TYPE_CHECK_CLASS_TYPE ((klass), NM_TYPE_ACD_MANAGER)) -#define NM_ACD_MANAGER_GET_CLASS(obj) (G_TYPE_INSTANCE_GET_CLASS ((obj), NM_TYPE_ACD_MANAGER, NMAcdManagerClass)) - -#define NM_ACD_MANAGER_PROBE_TERMINATED "probe-terminated" - -typedef struct _NMAcdManagerClass NMAcdManagerClass; - -GType nm_acd_manager_get_type (void); - -NMAcdManager *nm_acd_manager_new (int ifindex, const guint8 *hwaddr, size_t hwaddr_len); -void nm_acd_manager_destroy (NMAcdManager *self); -gboolean nm_acd_manager_add_address (NMAcdManager *self, in_addr_t address); -gboolean nm_acd_manager_start_probe (NMAcdManager *self, guint timeout); -gboolean nm_acd_manager_check_address (NMAcdManager *self, in_addr_t address); -void nm_acd_manager_announce_addresses (NMAcdManager *self); -void nm_acd_manager_reset (NMAcdManager *self); - -#endif /* __NM_ACD_MANAGER__ */ diff --git a/src/devices/nm-arping-manager.c b/src/devices/nm-arping-manager.c new file mode 100644 index 00000000..51f80e08 --- /dev/null +++ b/src/devices/nm-arping-manager.c @@ -0,0 +1,474 @@ +/* -*- Mode: C; tab-width: 4; indent-tabs-mode: t; c-basic-offset: 4 -*- */ +/* NetworkManager -- Network link manager + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation; either version 2 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * Copyright (C) 2015 Red Hat, Inc. + */ + +#include "nm-default.h" + +#include "nm-arping-manager.h" + +#include <netinet/in.h> +#include <sys/types.h> +#include <sys/wait.h> + +#include "platform/nm-platform.h" +#include "nm-utils.h" +#include "NetworkManagerUtils.h" + +/*****************************************************************************/ + +typedef enum { + STATE_INIT, + STATE_PROBING, + STATE_PROBE_DONE, + STATE_ANNOUNCING, +} State; + +typedef struct { + in_addr_t address; + GPid pid; + guint watch; + gboolean duplicate; + NMArpingManager *manager; +} AddressInfo; + +/*****************************************************************************/ + +enum { + PROBE_TERMINATED, + LAST_SIGNAL, +}; + +static guint signals[LAST_SIGNAL] = { 0 }; + +typedef struct { + int ifindex; + State state; + GHashTable *addresses; + guint completed; + guint timer; + guint round2_id; +} NMArpingManagerPrivate; + +struct _NMArpingManager { + GObject parent; + NMArpingManagerPrivate _priv; +}; + +struct _NMArpingManagerClass { + GObjectClass parent; +}; + +G_DEFINE_TYPE (NMArpingManager, nm_arping_manager, G_TYPE_OBJECT) + +#define NM_ARPING_MANAGER_GET_PRIVATE(self) _NM_GET_PRIVATE (self, NMArpingManager, NM_IS_ARPING_MANAGER) + +/*****************************************************************************/ + +#define _NMLOG_DOMAIN LOGD_IP4 +#define _NMLOG_PREFIX_NAME "arping" +#define _NMLOG(level, ...) \ + G_STMT_START { \ + char _sbuf[64]; \ + int _ifindex = (self) ? NM_ARPING_MANAGER_GET_PRIVATE (self)->ifindex : 0; \ + \ + nm_log ((level), _NMLOG_DOMAIN, \ + nm_platform_link_get_name (NM_PLATFORM_GET, _ifindex), \ + NULL, \ + "%s%s: " _NM_UTILS_MACRO_FIRST (__VA_ARGS__), \ + _NMLOG_PREFIX_NAME, \ + self ? nm_sprintf_buf (_sbuf, "[%p,%d]", self, _ifindex) : "" \ + _NM_UTILS_MACRO_REST (__VA_ARGS__)); \ + } G_STMT_END + +/*****************************************************************************/ + +/** + * nm_arping_manager_add_address: + * @self: a #NMArpingManager + * @address: an IP address + * + * Add @address to the list of IP addresses to probe. + + * Returns: %TRUE on success, %FALSE if the address was already in the list + */ +gboolean +nm_arping_manager_add_address (NMArpingManager *self, in_addr_t address) +{ + NMArpingManagerPrivate *priv; + AddressInfo *info; + + g_return_val_if_fail (NM_IS_ARPING_MANAGER (self), FALSE); + priv = NM_ARPING_MANAGER_GET_PRIVATE (self); + g_return_val_if_fail (priv->state == STATE_INIT, FALSE); + + if (g_hash_table_lookup (priv->addresses, GUINT_TO_POINTER (address))) { + _LOGD ("address already exists"); + return FALSE; + } + + info = g_slice_new0 (AddressInfo); + info->address = address; + info->manager = self; + + g_hash_table_insert (priv->addresses, GUINT_TO_POINTER (address), info); + + return TRUE; +} + +static void +arping_watch_cb (GPid pid, gint status, gpointer user_data) +{ + AddressInfo *info = user_data; + NMArpingManager *self = info->manager; + NMArpingManagerPrivate *priv = NM_ARPING_MANAGER_GET_PRIVATE (self); + const char *addr; + + info->pid = 0; + info->watch = 0; + addr = nm_utils_inet4_ntop (info->address, NULL); + + if (WIFEXITED (status)) { + if (WEXITSTATUS (status) != 0) { + _LOGD ("%s already used in the %s network", + addr, nm_platform_link_get_name (NM_PLATFORM_GET, priv->ifindex)); + info->duplicate = TRUE; + } else + _LOGD ("DAD succeeded for %s", addr); + } else { + _LOGD ("stopped unexpectedly with status %d for %s", status, addr); + } + + if (++priv->completed == g_hash_table_size (priv->addresses)) { + priv->state = STATE_PROBE_DONE; + nm_clear_g_source (&priv->timer); + g_signal_emit (self, signals[PROBE_TERMINATED], 0); + } +} + +static gboolean +arping_timeout_cb (gpointer user_data) +{ + NMArpingManager *self = user_data; + NMArpingManagerPrivate *priv = NM_ARPING_MANAGER_GET_PRIVATE (self); + GHashTableIter iter; + AddressInfo *info; + + priv->timer = 0; + + g_hash_table_iter_init (&iter, priv->addresses); + while (g_hash_table_iter_next (&iter, NULL, (gpointer *) &info)) { + nm_clear_g_source (&info->watch); + if (info->pid) { + _LOGD ("DAD timed out for %s", + nm_utils_inet4_ntop (info->address, NULL)); + nm_utils_kill_child_async (info->pid, SIGTERM, LOGD_IP4, + "arping", 1000, NULL, NULL); + info->pid = 0; + } + } + + priv->state = STATE_PROBE_DONE; + g_signal_emit (self, signals[PROBE_TERMINATED], 0); + + return G_SOURCE_REMOVE; +} + +/** + * nm_arping_manager_start_probe: + * @self: a #NMArpingManager + * @timeout: maximum probe duration in milliseconds + * @error: location to store error, or %NULL + * + * Start probing IP addresses for duplicates; when the probe terminates a + * PROBE_TERMINATED signal is emitted. + * + * Returns: %TRUE if at least one probe could be started, %FALSE otherwise + */ +gboolean +nm_arping_manager_start_probe (NMArpingManager *self, guint timeout, GError **error) +{ + const char *argv[] = { NULL, "-D", "-q", "-I", NULL, "-c", NULL, "-w", NULL, NULL, NULL }; + NMArpingManagerPrivate *priv; + GHashTableIter iter; + AddressInfo *info; + gs_free char *timeout_str = NULL; + gboolean success = FALSE; + + g_return_val_if_fail (NM_IS_ARPING_MANAGER (self), FALSE); + g_return_val_if_fail (!error || !*error, FALSE); + g_return_val_if_fail (timeout, FALSE); + + priv = NM_ARPING_MANAGER_GET_PRIVATE (self); + g_return_val_if_fail (priv->state == STATE_INIT, FALSE); + + argv[4] = nm_platform_link_get_name (NM_PLATFORM_GET, priv->ifindex); + if (!argv[4]) { + /* The device was probably just removed. */ + g_set_error (error, NM_DEVICE_ERROR, NM_DEVICE_ERROR_FAILED, + "can't find a name for ifindex %d", priv->ifindex); + return FALSE; + } + + priv->completed = 0; + + argv[0] = nm_utils_find_helper ("arping", NULL, NULL); + if (!argv[0]) { + g_set_error_literal (error, NM_DEVICE_ERROR, NM_DEVICE_ERROR_FAILED, + "arping could not be found"); + return FALSE; + } + + timeout_str = g_strdup_printf ("%u", timeout / 1000 + 2); + argv[6] = timeout_str; + argv[8] = timeout_str; + + g_hash_table_iter_init (&iter, priv->addresses); + + while (g_hash_table_iter_next (&iter, NULL, (gpointer *) &info)) { + gs_free char *tmp_str = NULL; + + argv[9] = nm_utils_inet4_ntop (info->address, NULL); + _LOGD ("run %s", (tmp_str = g_strjoinv (" ", (char **) argv))); + + if (g_spawn_async (NULL, (char **) argv, NULL, + G_SPAWN_STDOUT_TO_DEV_NULL | + G_SPAWN_STDERR_TO_DEV_NULL | + G_SPAWN_DO_NOT_REAP_CHILD, + NULL, NULL, &info->pid, NULL)) { + info->watch = g_child_watch_add (info->pid, arping_watch_cb, info); + success = TRUE; + } + } + + if (success) { + priv->timer = g_timeout_add (timeout, arping_timeout_cb, self); + priv->state = STATE_PROBING; + } else { + g_set_error_literal (error, NM_DEVICE_ERROR, NM_DEVICE_ERROR_FAILED, + "could not spawn arping process"); + } + + return success; +} + +/** + * nm_arping_manager_reset: + * @self: a #NMArpingManager + * + * Stop any operation in progress and reset @self to the initial state. + */ +void +nm_arping_manager_reset (NMArpingManager *self) +{ + NMArpingManagerPrivate *priv; + + g_return_if_fail (NM_IS_ARPING_MANAGER (self)); + priv = NM_ARPING_MANAGER_GET_PRIVATE (self); + + nm_clear_g_source (&priv->timer); + nm_clear_g_source (&priv->round2_id); + g_hash_table_remove_all (priv->addresses); + + priv->state = STATE_INIT; +} + +/** + * nm_arping_manager_destroy: + * @self: the #NMArpingManager + * + * Calls nm_arping_manager_reset() and unrefs @self. + */ +void +nm_arping_manager_destroy (NMArpingManager *self) +{ + g_return_if_fail (NM_IS_ARPING_MANAGER (self)); + + nm_arping_manager_reset (self); + g_object_unref (self); +} + +/** + * nm_arping_manager_check_address: + * @self: a #NMArpingManager + * @address: an IP address + * + * Check if an IP address is duplicate. @address must have been added with + * nm_arping_manager_add_address(). + * + * Returns: %TRUE if the address is not duplicate, %FALSE otherwise + */ +gboolean +nm_arping_manager_check_address (NMArpingManager *self, in_addr_t address) +{ + NMArpingManagerPrivate *priv; + AddressInfo *info; + + g_return_val_if_fail (NM_IS_ARPING_MANAGER (self), FALSE); + priv = NM_ARPING_MANAGER_GET_PRIVATE (self); + g_return_val_if_fail ( priv->state == STATE_INIT + || priv->state == STATE_PROBE_DONE, FALSE); + + info = g_hash_table_lookup (priv->addresses, GUINT_TO_POINTER (address)); + g_return_val_if_fail (info, FALSE); + + return !info->duplicate; +} + +static void +send_announcements (NMArpingManager *self, const char *mode_arg) +{ + NMArpingManagerPrivate *priv = NM_ARPING_MANAGER_GET_PRIVATE (self); + const char *argv[] = { NULL, mode_arg, "-q", "-I", NULL, "-c", "1", NULL, NULL }; + int ip_arg = G_N_ELEMENTS (argv) - 2; + GError *error = NULL; + GHashTableIter iter; + AddressInfo *info; + + argv[4] = nm_platform_link_get_name (NM_PLATFORM_GET, priv->ifindex); + if (!argv[4]) { + /* The device was probably just removed. */ + _LOGW ("can't find a name for ifindex %d", priv->ifindex); + return; + } + + argv[0] = nm_utils_find_helper ("arping", NULL, NULL); + if (!argv[0]) { + _LOGW ("arping could not be found; no ARPs will be sent"); + return; + } + + g_hash_table_iter_init (&iter, priv->addresses); + + while (g_hash_table_iter_next (&iter, NULL, (gpointer *) &info)) { + gs_free char *tmp_str = NULL; + gboolean success; + + if (info->duplicate) + continue; + + argv[ip_arg] = nm_utils_inet4_ntop (info->address, NULL); + _LOGD ("run %s", (tmp_str = g_strjoinv (" ", (char **) argv))); + + success = g_spawn_async (NULL, (char **) argv, NULL, + G_SPAWN_STDOUT_TO_DEV_NULL | + G_SPAWN_STDERR_TO_DEV_NULL, + NULL, NULL, NULL, &error); + if (!success) { + _LOGW ("could not send ARP for address %s: %s", argv[ip_arg], + error->message); + g_clear_error (&error); + } + } +} + +static gboolean +arp_announce_round2 (gpointer self) +{ + NMArpingManagerPrivate *priv = NM_ARPING_MANAGER_GET_PRIVATE ((NMArpingManager *) self); + + priv->round2_id = 0; + send_announcements (self, "-U"); + priv->state = STATE_INIT; + g_hash_table_remove_all (priv->addresses); + + return G_SOURCE_REMOVE; +} + +/** + * nm_arping_manager_announce_addresses: + * @self: a #NMArpingManager + * + * Start announcing addresses. + */ +void +nm_arping_manager_announce_addresses (NMArpingManager *self) +{ + NMArpingManagerPrivate *priv = NM_ARPING_MANAGER_GET_PRIVATE (self); + + g_return_if_fail ( priv->state == STATE_INIT + || priv->state == STATE_PROBE_DONE); + + send_announcements (self, "-A"); + nm_clear_g_source (&priv->round2_id); + priv->round2_id = g_timeout_add_seconds (2, arp_announce_round2, self); + priv->state = STATE_ANNOUNCING; +} + +static void +destroy_address_info (gpointer data) +{ + AddressInfo *info = (AddressInfo *) data; + + nm_clear_g_source (&info->watch); + + if (info->pid) { + nm_utils_kill_child_async (info->pid, SIGTERM, LOGD_IP4, "arping", + 1000, NULL, NULL); + } + + g_slice_free (AddressInfo, info); +} + +/*****************************************************************************/ + +static void +nm_arping_manager_init (NMArpingManager *self) +{ + NMArpingManagerPrivate *priv = NM_ARPING_MANAGER_GET_PRIVATE (self); + + priv->addresses = g_hash_table_new_full (g_direct_hash, g_direct_equal, + NULL, destroy_address_info); + priv->state = STATE_INIT; +} + +NMArpingManager * +nm_arping_manager_new (int ifindex) +{ + NMArpingManager *self; + NMArpingManagerPrivate *priv; + + self = g_object_new (NM_TYPE_ARPING_MANAGER, NULL); + priv = NM_ARPING_MANAGER_GET_PRIVATE (self); + priv->ifindex = ifindex; + return self; +} + +static void +dispose (GObject *object) +{ + NMArpingManager *self = NM_ARPING_MANAGER (object); + NMArpingManagerPrivate *priv = NM_ARPING_MANAGER_GET_PRIVATE (self); + + nm_clear_g_source (&priv->timer); + nm_clear_g_source (&priv->round2_id); + g_clear_pointer (&priv->addresses, g_hash_table_destroy); + + G_OBJECT_CLASS (nm_arping_manager_parent_class)->dispose (object); +} + +static void +nm_arping_manager_class_init (NMArpingManagerClass *klass) +{ + GObjectClass *object_class = G_OBJECT_CLASS (klass); + + object_class->dispose = dispose; + + signals[PROBE_TERMINATED] = + g_signal_new (NM_ARPING_MANAGER_PROBE_TERMINATED, + G_OBJECT_CLASS_TYPE (object_class), + G_SIGNAL_RUN_FIRST, + 0, NULL, NULL, NULL, + G_TYPE_NONE, 0); +} diff --git a/src/devices/nm-arping-manager.h b/src/devices/nm-arping-manager.h new file mode 100644 index 00000000..c8a86af0 --- /dev/null +++ b/src/devices/nm-arping-manager.h @@ -0,0 +1,43 @@ +/* -*- Mode: C; tab-width: 4; indent-tabs-mode: t; c-basic-offset: 4 -*- */ +/* NetworkManager -- Network link manager + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation; either version 2 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * Copyright (C) 2015 Red Hat, Inc. + */ + +#ifndef __NM_ARPING_MANAGER__ +#define __NM_ARPING_MANAGER__ + +#include <netinet/in.h> + +#define NM_TYPE_ARPING_MANAGER (nm_arping_manager_get_type ()) +#define NM_ARPING_MANAGER(obj) (G_TYPE_CHECK_INSTANCE_CAST ((obj), NM_TYPE_ARPING_MANAGER, NMArpingManager)) +#define NM_ARPING_MANAGER_CLASS(klass) (G_TYPE_CHECK_CLASS_CAST ((klass), NM_TYPE_ARPING_MANAGER, NMArpingManagerClass)) +#define NM_IS_ARPING_MANAGER(obj) (G_TYPE_CHECK_INSTANCE_TYPE ((obj), NM_TYPE_ARPING_MANAGER)) +#define NM_IS_ARPING_MANAGER_CLASS(klass) (G_TYPE_CHECK_CLASS_TYPE ((klass), NM_TYPE_ARPING_MANAGER)) +#define NM_ARPING_MANAGER_GET_CLASS(obj) (G_TYPE_INSTANCE_GET_CLASS ((obj), NM_TYPE_ARPING_MANAGER, NMArpingManagerClass)) + +#define NM_ARPING_MANAGER_PROBE_TERMINATED "probe-terminated" + +typedef struct _NMArpingManagerClass NMArpingManagerClass; + +GType nm_arping_manager_get_type (void); + +NMArpingManager *nm_arping_manager_new (int ifindex); +void nm_arping_manager_destroy (NMArpingManager *self); +gboolean nm_arping_manager_add_address (NMArpingManager *self, in_addr_t address); +gboolean nm_arping_manager_start_probe (NMArpingManager *self, guint timeout, GError **error); +gboolean nm_arping_manager_check_address (NMArpingManager *self, in_addr_t address); +void nm_arping_manager_announce_addresses (NMArpingManager *self); +void nm_arping_manager_reset (NMArpingManager *self); + +#endif /* __NM_ARPING_MANAGER__ */ diff --git a/src/devices/nm-device-bond.c b/src/devices/nm-device-bond.c index 2dd9494a..910dd0bf 100644 --- a/src/devices/nm-device-bond.c +++ b/src/devices/nm-device-bond.c @@ -32,6 +32,8 @@ #include "nm-core-internal.h" #include "nm-ip4-config.h" +#include "introspection/org.freedesktop.NetworkManager.Device.Bond.h" + #include "nm-device-logging.h" _LOG_DECLARE_SELF(NMDeviceBond); @@ -76,7 +78,7 @@ static gboolean complete_connection (NMDevice *device, NMConnection *connection, const char *specific_object, - NMConnection *const*existing_connections, + const GSList *existing_connections, GError **error) { NMSettingBond *s_bond; @@ -605,31 +607,13 @@ nm_device_bond_init (NMDeviceBond * self) nm_assert (nm_device_is_master (NM_DEVICE (self))); } -static const NMDBusInterfaceInfoExtended interface_info_device_bond = { - .parent = NM_DEFINE_GDBUS_INTERFACE_INFO_INIT ( - NM_DBUS_INTERFACE_DEVICE_BOND, - .signals = NM_DEFINE_GDBUS_SIGNAL_INFOS ( - &nm_signal_info_property_changed_legacy, - ), - .properties = NM_DEFINE_GDBUS_PROPERTY_INFOS ( - NM_DEFINE_DBUS_PROPERTY_INFO_EXTENDED_READABLE_L ("HwAddress", "s", NM_DEVICE_HW_ADDRESS), - NM_DEFINE_DBUS_PROPERTY_INFO_EXTENDED_READABLE_L ("Carrier", "b", NM_DEVICE_CARRIER), - NM_DEFINE_DBUS_PROPERTY_INFO_EXTENDED_READABLE_L ("Slaves", "ao", NM_DEVICE_SLAVES), - ), - ), - .legacy_property_changed = TRUE, -}; - static void nm_device_bond_class_init (NMDeviceBondClass *klass) { - NMDBusObjectClass *dbus_object_class = NM_DBUS_OBJECT_CLASS (klass); NMDeviceClass *parent_class = NM_DEVICE_CLASS (klass); NM_DEVICE_CLASS_DECLARE_TYPES (klass, NM_SETTING_BOND_SETTING_NAME, NM_LINK_TYPE_BOND) - dbus_object_class->interface_infos = NM_DBUS_INTERFACE_INFOS (&interface_info_device_bond); - parent_class->is_master = TRUE; parent_class->get_generic_capabilities = get_generic_capabilities; parent_class->check_connection_compatible = check_connection_compatible; @@ -645,6 +629,10 @@ nm_device_bond_class_init (NMDeviceBondClass *klass) parent_class->release_slave = release_slave; parent_class->can_reapply_change = can_reapply_change; parent_class->reapply_connection = reapply_connection; + + nm_exported_object_class_add_interface (NM_EXPORTED_OBJECT_CLASS (klass), + NMDBUS_TYPE_DEVICE_BOND_SKELETON, + NULL); } /*****************************************************************************/ diff --git a/src/devices/nm-device-bridge.c b/src/devices/nm-device-bridge.c index c81a0253..74689aef 100644 --- a/src/devices/nm-device-bridge.c +++ b/src/devices/nm-device-bridge.c @@ -30,6 +30,8 @@ #include "nm-device-factory.h" #include "nm-core-internal.h" +#include "introspection/org.freedesktop.NetworkManager.Device.Bridge.h" + #include "nm-device-logging.h" _LOG_DECLARE_SELF(NMDeviceBridge); @@ -115,7 +117,7 @@ static gboolean complete_connection (NMDevice *device, NMConnection *connection, const char *specific_object, - NMConnection *const*existing_connections, + const GSList *existing_connections, GError **error) { NMSettingBridge *s_bridge; @@ -486,31 +488,13 @@ nm_device_bridge_init (NMDeviceBridge * self) nm_assert (nm_device_is_master (NM_DEVICE (self))); } -static const NMDBusInterfaceInfoExtended interface_info_device_bridge = { - .parent = NM_DEFINE_GDBUS_INTERFACE_INFO_INIT ( - NM_DBUS_INTERFACE_DEVICE_BRIDGE, - .signals = NM_DEFINE_GDBUS_SIGNAL_INFOS ( - &nm_signal_info_property_changed_legacy, - ), - .properties = NM_DEFINE_GDBUS_PROPERTY_INFOS ( - NM_DEFINE_DBUS_PROPERTY_INFO_EXTENDED_READABLE_L ("HwAddress", "s", NM_DEVICE_HW_ADDRESS), - NM_DEFINE_DBUS_PROPERTY_INFO_EXTENDED_READABLE_L ("Carrier", "b", NM_DEVICE_CARRIER), - NM_DEFINE_DBUS_PROPERTY_INFO_EXTENDED_READABLE_L ("Slaves", "ao", NM_DEVICE_SLAVES), - ), - ), - .legacy_property_changed = TRUE, -}; - static void nm_device_bridge_class_init (NMDeviceBridgeClass *klass) { - NMDBusObjectClass *dbus_object_class = NM_DBUS_OBJECT_CLASS (klass); NMDeviceClass *parent_class = NM_DEVICE_CLASS (klass); NM_DEVICE_CLASS_DECLARE_TYPES (klass, NM_SETTING_BRIDGE_SETTING_NAME, NM_LINK_TYPE_BRIDGE) - dbus_object_class->interface_infos = NM_DBUS_INTERFACE_INFOS (&interface_info_device_bridge); - parent_class->is_master = TRUE; parent_class->get_generic_capabilities = get_generic_capabilities; parent_class->check_connection_compatible = check_connection_compatible; @@ -527,6 +511,10 @@ nm_device_bridge_class_init (NMDeviceBridgeClass *klass) parent_class->enslave_slave = enslave_slave; parent_class->release_slave = release_slave; parent_class->get_configured_mtu = nm_device_get_configured_mtu_for_wired; + + nm_exported_object_class_add_interface (NM_EXPORTED_OBJECT_CLASS (klass), + NMDBUS_TYPE_DEVICE_BRIDGE_SKELETON, + NULL); } /*****************************************************************************/ diff --git a/src/devices/nm-device-dummy.c b/src/devices/nm-device-dummy.c index f8bc8e75..085c44e6 100644 --- a/src/devices/nm-device-dummy.c +++ b/src/devices/nm-device-dummy.c @@ -28,6 +28,8 @@ #include "nm-setting-dummy.h" #include "nm-core-internal.h" +#include "introspection/org.freedesktop.NetworkManager.Device.Dummy.h" + #include "nm-device-logging.h" _LOG_DECLARE_SELF(NMDeviceDummy); @@ -55,7 +57,7 @@ static gboolean complete_connection (NMDevice *device, NMConnection *connection, const char *specific_object, - NMConnection *const*existing_connections, + const GSList *existing_connections, GError **error) { NMSettingDummy *s_dummy; @@ -154,29 +156,13 @@ nm_device_dummy_init (NMDeviceDummy *self) { } -static const NMDBusInterfaceInfoExtended interface_info_device_dummy = { - .parent = NM_DEFINE_GDBUS_INTERFACE_INFO_INIT ( - NM_DBUS_INTERFACE_DEVICE_DUMMY, - .signals = NM_DEFINE_GDBUS_SIGNAL_INFOS ( - &nm_signal_info_property_changed_legacy, - ), - .properties = NM_DEFINE_GDBUS_PROPERTY_INFOS ( - NM_DEFINE_DBUS_PROPERTY_INFO_EXTENDED_READABLE_L ("HwAddress", "s", NM_DEVICE_HW_ADDRESS), - ), - ), - .legacy_property_changed = TRUE, -}; - static void nm_device_dummy_class_init (NMDeviceDummyClass *klass) { - NMDBusObjectClass *dbus_object_class = NM_DBUS_OBJECT_CLASS (klass); NMDeviceClass *device_class = NM_DEVICE_CLASS (klass); NM_DEVICE_CLASS_DECLARE_TYPES (klass, NULL, NM_LINK_TYPE_DUMMY) - dbus_object_class->interface_infos = NM_DBUS_INTERFACE_INFOS (&interface_info_device_dummy); - device_class->connection_type = NM_SETTING_DUMMY_SETTING_NAME; device_class->complete_connection = complete_connection; device_class->check_connection_compatible = check_connection_compatible; @@ -185,6 +171,10 @@ nm_device_dummy_class_init (NMDeviceDummyClass *klass) device_class->update_connection = update_connection; device_class->act_stage1_prepare = act_stage1_prepare; device_class->get_configured_mtu = nm_device_get_configured_mtu_for_wired; + + nm_exported_object_class_add_interface (NM_EXPORTED_OBJECT_CLASS (klass), + NMDBUS_TYPE_DEVICE_DUMMY_SKELETON, + NULL); } diff --git a/src/devices/nm-device-ethernet.c b/src/devices/nm-device-ethernet.c index 9b46545b..3ca86e06 100644 --- a/src/devices/nm-device-ethernet.c +++ b/src/devices/nm-device-ethernet.c @@ -28,6 +28,7 @@ #include <stdlib.h> #include <unistd.h> #include <errno.h> + #include <libudev.h> #include "nm-device-private.h" @@ -50,7 +51,8 @@ #include "nm-device-factory.h" #include "nm-core-internal.h" #include "NetworkManagerUtils.h" -#include "nm-utils/nm-udev-utils.h" + +#include "introspection/org.freedesktop.NetworkManager.Device.Wired.h" #include "nm-device-logging.h" _LOG_DECLARE_SELF(NMDeviceEthernet); @@ -548,7 +550,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); + config = nm_supplicant_config_new (); security = nm_connection_get_setting_802_1x (connection); if (!nm_supplicant_config_add_setting_8021x (config, security, con_uuid, mtu, TRUE, error)) { @@ -656,9 +658,12 @@ handle_auth_or_fail (NMDeviceEthernet *self, NMActRequest *req, gboolean new_secrets) { + NMDeviceEthernetPrivate *priv; const char *setting_name; NMConnection *applied_connection; + priv = NM_DEVICE_ETHERNET_GET_PRIVATE (self); + if (!nm_device_auth_retries_try_next (NM_DEVICE (self))) return NM_ACT_STAGE_RETURN_FAILURE; @@ -668,14 +673,13 @@ handle_auth_or_fail (NMDeviceEthernet *self, applied_connection = nm_act_request_get_applied_connection (req); setting_name = nm_connection_need_secrets (applied_connection, NULL); - if (!setting_name) { + if (setting_name) { + 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)); + } else _LOGI (LOGD_DEVICE, "Cleared secrets, but setting didn't need any secrets."); - return NM_ACT_STAGE_RETURN_FAILURE; - } - 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; } @@ -738,7 +742,7 @@ supplicant_interface_init (NMDeviceEthernet *self) return FALSE; } - /* Listen for its state signals */ + /* Listen for it's state signals */ priv->supplicant.iface_state_id = g_signal_connect (priv->supplicant.iface, NM_SUPPLICANT_INTERFACE_STATE, G_CALLBACK (supplicant_iface_state_cb), @@ -952,22 +956,8 @@ ppp_state_changed (NMPPPManager *ppp_manager, NMPPPStatus status, gpointer user_ } static void -ppp_ifindex_set (NMPPPManager *ppp_manager, - int ifindex, - const char *iface, - gpointer user_data) -{ - NMDevice *device = NM_DEVICE (user_data); - - if (!nm_device_set_ip_ifindex (device, ifindex)) { - nm_device_state_changed (device, - NM_DEVICE_STATE_FAILED, - NM_DEVICE_STATE_REASON_IP_CONFIG_UNAVAILABLE); - } -} - -static void ppp_ip4_config (NMPPPManager *ppp_manager, + const char *iface, NMIP4Config *config, gpointer user_data) { @@ -975,6 +965,7 @@ ppp_ip4_config (NMPPPManager *ppp_manager, /* Ignore PPP IP4 events that come in after initial configuration */ if (nm_device_activate_ip4_state_in_conf (device)) { + nm_device_set_ip_iface (device, iface); nm_device_activate_schedule_ip4_config_result (device, config); } } @@ -1021,9 +1012,6 @@ pppoe_stage3_ip4_config_start (NMDeviceEthernet *self, NMDeviceStateReason *out_ g_signal_connect (priv->ppp_manager, NM_PPP_MANAGER_SIGNAL_STATE_CHANGED, G_CALLBACK (ppp_state_changed), self); - g_signal_connect (priv->ppp_manager, NM_PPP_MANAGER_SIGNAL_IFINDEX_SET, - G_CALLBACK (ppp_ifindex_set), - self); g_signal_connect (priv->ppp_manager, NM_PPP_MANAGER_SIGNAL_IP4_CONFIG, G_CALLBACK (ppp_ip4_config), self); @@ -1373,7 +1361,7 @@ static gboolean complete_connection (NMDevice *device, NMConnection *connection, const char *specific_object, - NMConnection *const*existing_connections, + const GSList *existing_connections, GError **error) { NMSettingWired *s_wired; @@ -1437,9 +1425,7 @@ new_default_connection (NMDevice *self) NMConnection *connection; NMSettingsConnection *const*connections; NMSetting *setting; - struct udev_device *dev; const char *perm_hw_addr; - const char *uprop = "0"; gs_free char *defname = NULL; gs_free char *uuid = NULL; gs_free char *machine_id = NULL; @@ -1484,26 +1470,6 @@ new_default_connection (NMDevice *self) g_object_set (setting, NM_SETTING_WIRED_MAC_ADDRESS, perm_hw_addr, NULL); nm_connection_add_setting (connection, setting); - /* Check if we should create a Link-Local only connection */ - dev = nm_platform_link_get_udev_device (nm_device_get_platform (NM_DEVICE (self)), nm_device_get_ip_ifindex (self)); - if (dev) - uprop = udev_device_get_property_value (dev, "NM_AUTO_DEFAULT_LINK_LOCAL_ONLY"); - - if (nm_udev_utils_property_as_boolean (uprop)) { - setting = nm_setting_ip4_config_new (); - g_object_set (setting, - NM_SETTING_IP_CONFIG_METHOD, NM_SETTING_IP4_CONFIG_METHOD_LINK_LOCAL, - NULL); - nm_connection_add_setting (connection, setting); - - setting = nm_setting_ip6_config_new (); - g_object_set (setting, - NM_SETTING_IP_CONFIG_METHOD, NM_SETTING_IP6_CONFIG_METHOD_LINK_LOCAL, - NM_SETTING_IP_CONFIG_MAY_FAIL, TRUE, - NULL); - nm_connection_add_setting (connection, setting); - } - return connection; } @@ -1735,28 +1701,10 @@ set_property (GObject *object, guint prop_id, } } -static const NMDBusInterfaceInfoExtended interface_info_device_wired = { - .parent = NM_DEFINE_GDBUS_INTERFACE_INFO_INIT ( - NM_DBUS_INTERFACE_DEVICE_WIRED, - .signals = NM_DEFINE_GDBUS_SIGNAL_INFOS ( - &nm_signal_info_property_changed_legacy, - ), - .properties = NM_DEFINE_GDBUS_PROPERTY_INFOS ( - NM_DEFINE_DBUS_PROPERTY_INFO_EXTENDED_READABLE_L ("HwAddress", "s", NM_DEVICE_HW_ADDRESS), - NM_DEFINE_DBUS_PROPERTY_INFO_EXTENDED_READABLE_L ("PermHwAddress", "s", NM_DEVICE_PERM_HW_ADDRESS), - NM_DEFINE_DBUS_PROPERTY_INFO_EXTENDED_READABLE_L ("Speed", "u", NM_DEVICE_ETHERNET_SPEED), - NM_DEFINE_DBUS_PROPERTY_INFO_EXTENDED_READABLE_L ("S390Subchannels", "as", NM_DEVICE_ETHERNET_S390_SUBCHANNELS), - NM_DEFINE_DBUS_PROPERTY_INFO_EXTENDED_READABLE_L ("Carrier", "b", NM_DEVICE_CARRIER), - ), - ), - .legacy_property_changed = TRUE, -}; - static void nm_device_ethernet_class_init (NMDeviceEthernetClass *klass) { GObjectClass *object_class = G_OBJECT_CLASS (klass); - NMDBusObjectClass *dbus_object_class = NM_DBUS_OBJECT_CLASS (klass); NMDeviceClass *parent_class = NM_DEVICE_CLASS (klass); g_type_class_add_private (object_class, sizeof (NMDeviceEthernetPrivate)); @@ -1768,8 +1716,6 @@ nm_device_ethernet_class_init (NMDeviceEthernetClass *klass) object_class->get_property = get_property; object_class->set_property = set_property; - dbus_object_class->interface_infos = NM_DBUS_INTERFACE_INFOS (&interface_info_device_wired); - parent_class->get_generic_capabilities = get_generic_capabilities; parent_class->check_connection_compatible = check_connection_compatible; parent_class->complete_connection = complete_connection; @@ -1803,6 +1749,10 @@ nm_device_ethernet_class_init (NMDeviceEthernetClass *klass) G_PARAM_STATIC_STRINGS); g_object_class_install_properties (object_class, _PROPERTY_ENUMS_LAST, obj_properties); + + nm_exported_object_class_add_interface (NM_EXPORTED_OBJECT_CLASS (klass), + NMDBUS_TYPE_DEVICE_ETHERNET_SKELETON, + NULL); } /*****************************************************************************/ diff --git a/src/devices/nm-device-ethernet.h b/src/devices/nm-device-ethernet.h index 22fae293..a50a7d85 100644 --- a/src/devices/nm-device-ethernet.h +++ b/src/devices/nm-device-ethernet.h @@ -24,12 +24,12 @@ #include "nm-device.h" -#define NM_TYPE_DEVICE_ETHERNET (nm_device_ethernet_get_type ()) -#define NM_DEVICE_ETHERNET(obj) (G_TYPE_CHECK_INSTANCE_CAST ((obj), NM_TYPE_DEVICE_ETHERNET, NMDeviceEthernet)) -#define NM_DEVICE_ETHERNET_CLASS(klass) (G_TYPE_CHECK_CLASS_CAST ((klass), NM_TYPE_DEVICE_ETHERNET, NMDeviceEthernetClass)) -#define NM_IS_DEVICE_ETHERNET(obj) (G_TYPE_CHECK_INSTANCE_TYPE ((obj), NM_TYPE_DEVICE_ETHERNET)) -#define NM_IS_DEVICE_ETHERNET_CLASS(klass) (G_TYPE_CHECK_CLASS_TYPE ((klass), NM_TYPE_DEVICE_ETHERNET)) -#define NM_DEVICE_ETHERNET_GET_CLASS(obj) (G_TYPE_INSTANCE_GET_CLASS ((obj), NM_TYPE_DEVICE_ETHERNET, NMDeviceEthernetClass)) +#define NM_TYPE_DEVICE_ETHERNET (nm_device_ethernet_get_type ()) +#define NM_DEVICE_ETHERNET(obj) (G_TYPE_CHECK_INSTANCE_CAST ((obj), NM_TYPE_DEVICE_ETHERNET, NMDeviceEthernet)) +#define NM_DEVICE_ETHERNET_CLASS(klass) (G_TYPE_CHECK_CLASS_CAST ((klass), NM_TYPE_DEVICE_ETHERNET, NMDeviceEthernetClass)) +#define NM_IS_DEVICE_ETHERNET(obj) (G_TYPE_CHECK_INSTANCE_TYPE ((obj), NM_TYPE_DEVICE_ETHERNET)) +#define NM_IS_DEVICE_ETHERNET_CLASS(klass) (G_TYPE_CHECK_CLASS_TYPE ((klass), NM_TYPE_DEVICE_ETHERNET)) +#define NM_DEVICE_ETHERNET_GET_CLASS(obj) (G_TYPE_INSTANCE_GET_CLASS ((obj), NM_TYPE_DEVICE_ETHERNET, NMDeviceEthernetClass)) #define NM_DEVICE_ETHERNET_SPEED "speed" #define NM_DEVICE_ETHERNET_S390_SUBCHANNELS "s390-subchannels" @@ -37,12 +37,12 @@ struct _NMDeviceEthernetPrivate; typedef struct { - NMDevice parent; - struct _NMDeviceEthernetPrivate *_priv; + NMDevice parent; + struct _NMDeviceEthernetPrivate *_priv; } NMDeviceEthernet; typedef struct { - NMDeviceClass parent; + NMDeviceClass parent; } NMDeviceEthernetClass; GType nm_device_ethernet_get_type (void); diff --git a/src/devices/nm-device-factory.c b/src/devices/nm-device-factory.c index d8e30346..97f011c5 100644 --- a/src/devices/nm-device-factory.c +++ b/src/devices/nm-device-factory.c @@ -340,16 +340,42 @@ factories_list_unref (GSList *list) g_slist_free_full (list, g_object_unref); } -static void -load_factories_from_dir (const char *dirname, - NMDeviceFactoryManagerFactoryFunc callback, - gpointer user_data) +void +nm_device_factory_manager_load_factories (NMDeviceFactoryManagerFactoryFunc callback, + gpointer user_data) { NMDeviceFactory *factory; GError *error = NULL; char **path, **paths; - paths = nm_utils_read_plugin_paths (dirname, PLUGIN_PREFIX); + g_return_if_fail (factories_by_link == NULL); + g_return_if_fail (factories_by_setting == NULL); + + factories_by_link = g_hash_table_new_full (g_direct_hash, g_direct_equal, NULL, g_object_unref); + factories_by_setting = g_hash_table_new_full (nm_str_hash, g_str_equal, NULL, (GDestroyNotify) factories_list_unref); + +#define _ADD_INTERNAL(get_type_fcn) \ + G_STMT_START { \ + GType get_type_fcn (void); \ + _load_internal_factory (get_type_fcn (), \ + callback, user_data); \ + } G_STMT_END + + _ADD_INTERNAL (nm_bond_device_factory_get_type); + _ADD_INTERNAL (nm_bridge_device_factory_get_type); + _ADD_INTERNAL (nm_dummy_device_factory_get_type); + _ADD_INTERNAL (nm_ethernet_device_factory_get_type); + _ADD_INTERNAL (nm_infiniband_device_factory_get_type); + _ADD_INTERNAL (nm_ip_tunnel_device_factory_get_type); + _ADD_INTERNAL (nm_macsec_device_factory_get_type); + _ADD_INTERNAL (nm_macvlan_device_factory_get_type); + _ADD_INTERNAL (nm_ppp_device_factory_get_type); + _ADD_INTERNAL (nm_tun_device_factory_get_type); + _ADD_INTERNAL (nm_veth_device_factory_get_type); + _ADD_INTERNAL (nm_vlan_device_factory_get_type); + _ADD_INTERNAL (nm_vxlan_device_factory_get_type); + + paths = nm_utils_read_plugin_paths (NMPLUGINDIR, PLUGIN_PREFIX); if (!paths) return; @@ -394,36 +420,3 @@ load_factories_from_dir (const char *dirname, g_strfreev (paths); } -void -nm_device_factory_manager_load_factories (NMDeviceFactoryManagerFactoryFunc callback, - gpointer user_data) -{ - g_return_if_fail (factories_by_link == NULL); - g_return_if_fail (factories_by_setting == NULL); - - factories_by_link = g_hash_table_new_full (nm_direct_hash, NULL, NULL, g_object_unref); - factories_by_setting = g_hash_table_new_full (nm_str_hash, g_str_equal, NULL, (GDestroyNotify) factories_list_unref); - -#define _ADD_INTERNAL(get_type_fcn) \ - G_STMT_START { \ - GType get_type_fcn (void); \ - _load_internal_factory (get_type_fcn (), \ - callback, user_data); \ - } G_STMT_END - - _ADD_INTERNAL (nm_bond_device_factory_get_type); - _ADD_INTERNAL (nm_bridge_device_factory_get_type); - _ADD_INTERNAL (nm_dummy_device_factory_get_type); - _ADD_INTERNAL (nm_ethernet_device_factory_get_type); - _ADD_INTERNAL (nm_infiniband_device_factory_get_type); - _ADD_INTERNAL (nm_ip_tunnel_device_factory_get_type); - _ADD_INTERNAL (nm_macsec_device_factory_get_type); - _ADD_INTERNAL (nm_macvlan_device_factory_get_type); - _ADD_INTERNAL (nm_ppp_device_factory_get_type); - _ADD_INTERNAL (nm_tun_device_factory_get_type); - _ADD_INTERNAL (nm_veth_device_factory_get_type); - _ADD_INTERNAL (nm_vlan_device_factory_get_type); - _ADD_INTERNAL (nm_vxlan_device_factory_get_type); - - load_factories_from_dir (NMPLUGINDIR, callback, user_data); -} diff --git a/src/devices/nm-device-generic.c b/src/devices/nm-device-generic.c index 27eaf8d6..f6a670b2 100644 --- a/src/devices/nm-device-generic.c +++ b/src/devices/nm-device-generic.c @@ -26,6 +26,8 @@ #include "platform/nm-platform.h" #include "nm-core-internal.h" +#include "introspection/org.freedesktop.NetworkManager.Device.Generic.h" + /*****************************************************************************/ NM_GOBJECT_PROPERTIES_DEFINE_BASE ( @@ -201,25 +203,10 @@ dispose (GObject *object) G_OBJECT_CLASS (nm_device_generic_parent_class)->dispose (object); } -static const NMDBusInterfaceInfoExtended interface_info_device_generic = { - .parent = NM_DEFINE_GDBUS_INTERFACE_INFO_INIT ( - NM_DBUS_INTERFACE_DEVICE_GENERIC, - .signals = NM_DEFINE_GDBUS_SIGNAL_INFOS ( - &nm_signal_info_property_changed_legacy, - ), - .properties = NM_DEFINE_GDBUS_PROPERTY_INFOS ( - NM_DEFINE_DBUS_PROPERTY_INFO_EXTENDED_READABLE_L ("HwAddress", "s", NM_DEVICE_HW_ADDRESS), - NM_DEFINE_DBUS_PROPERTY_INFO_EXTENDED_READABLE_L ("TypeDescription", "s", NM_DEVICE_GENERIC_TYPE_DESCRIPTION), - ), - ), - .legacy_property_changed = TRUE, -}; - static void nm_device_generic_class_init (NMDeviceGenericClass *klass) { GObjectClass *object_class = G_OBJECT_CLASS (klass); - NMDBusObjectClass *dbus_object_class = NM_DBUS_OBJECT_CLASS (klass); NMDeviceClass *parent_class = NM_DEVICE_CLASS (klass); NM_DEVICE_CLASS_DECLARE_TYPES (klass, NM_SETTING_GENERIC_SETTING_NAME, NM_LINK_TYPE_ANY) @@ -229,8 +216,6 @@ nm_device_generic_class_init (NMDeviceGenericClass *klass) object_class->get_property = get_property; object_class->set_property = set_property; - dbus_object_class->interface_infos = NM_DBUS_INTERFACE_INFOS (&interface_info_device_generic); - parent_class->realize_start_notify = realize_start_notify; parent_class->get_generic_capabilities = get_generic_capabilities; parent_class->get_type_description = get_type_description; @@ -244,4 +229,8 @@ nm_device_generic_class_init (NMDeviceGenericClass *klass) G_PARAM_STATIC_STRINGS); g_object_class_install_properties (object_class, _PROPERTY_ENUMS_LAST, obj_properties); + + nm_exported_object_class_add_interface (NM_EXPORTED_OBJECT_CLASS (klass), + NMDBUS_TYPE_DEVICE_GENERIC_SKELETON, + NULL); } diff --git a/src/devices/nm-device-infiniband.c b/src/devices/nm-device-infiniband.c index 781bbd69..09ad2855 100644 --- a/src/devices/nm-device-infiniband.c +++ b/src/devices/nm-device-infiniband.c @@ -32,6 +32,8 @@ #include "nm-device-factory.h" #include "nm-core-internal.h" +#include "introspection/org.freedesktop.NetworkManager.Device.Infiniband.h" + #define NM_DEVICE_INFINIBAND_IS_PARTITION "is-partition" /*****************************************************************************/ @@ -175,7 +177,7 @@ static gboolean complete_connection (NMDevice *device, NMConnection *connection, const char *specific_object, - NMConnection *const*existing_connections, + const GSList *existing_connections, GError **error) { NMSettingInfiniband *s_infiniband; @@ -366,25 +368,10 @@ nm_device_infiniband_init (NMDeviceInfiniband * self) { } -static const NMDBusInterfaceInfoExtended interface_info_device_infiniband = { - .parent = NM_DEFINE_GDBUS_INTERFACE_INFO_INIT ( - NM_DBUS_INTERFACE_DEVICE_INFINIBAND, - .signals = NM_DEFINE_GDBUS_SIGNAL_INFOS ( - &nm_signal_info_property_changed_legacy, - ), - .properties = NM_DEFINE_GDBUS_PROPERTY_INFOS ( - NM_DEFINE_DBUS_PROPERTY_INFO_EXTENDED_READABLE_L ("HwAddress", "s", NM_DEVICE_HW_ADDRESS), - NM_DEFINE_DBUS_PROPERTY_INFO_EXTENDED_READABLE_L ("Carrier", "b", NM_DEVICE_CARRIER), - ), - ), - .legacy_property_changed = TRUE, -}; - static void nm_device_infiniband_class_init (NMDeviceInfinibandClass *klass) { GObjectClass *object_class = G_OBJECT_CLASS (klass); - NMDBusObjectClass *dbus_object_class = NM_DBUS_OBJECT_CLASS (klass); NMDeviceClass *parent_class = NM_DEVICE_CLASS (klass); NM_DEVICE_CLASS_DECLARE_TYPES (klass, NM_SETTING_INFINIBAND_SETTING_NAME, NM_LINK_TYPE_INFINIBAND) @@ -392,8 +379,6 @@ nm_device_infiniband_class_init (NMDeviceInfinibandClass *klass) object_class->get_property = get_property; object_class->set_property = set_property; - dbus_object_class->interface_infos = NM_DBUS_INTERFACE_INFOS (&interface_info_device_infiniband); - parent_class->create_and_realize = create_and_realize; parent_class->unrealize = unrealize; parent_class->get_generic_capabilities = get_generic_capabilities; @@ -411,6 +396,10 @@ nm_device_infiniband_class_init (NMDeviceInfinibandClass *klass) G_PARAM_STATIC_STRINGS); g_object_class_install_properties (object_class, _PROPERTY_ENUMS_LAST, obj_properties); + + nm_exported_object_class_add_interface (NM_EXPORTED_OBJECT_CLASS (klass), + NMDBUS_TYPE_DEVICE_INFINIBAND_SKELETON, + NULL); } /*****************************************************************************/ @@ -444,7 +433,7 @@ create_device (NMDeviceFactory *factory, NM_DEVICE_TYPE_DESC, "InfiniBand", NM_DEVICE_DEVICE_TYPE, NM_DEVICE_TYPE_INFINIBAND, NM_DEVICE_LINK_TYPE, NM_LINK_TYPE_INFINIBAND, - /* NOTE: Partition should probably be a different link type! */ + /* XXX: Partition should probably be a different link type! */ NM_DEVICE_INFINIBAND_IS_PARTITION, is_partition, NULL); } diff --git a/src/devices/nm-device-ip-tunnel.c b/src/devices/nm-device-ip-tunnel.c index 59ca9ed5..af3cfe4c 100644 --- a/src/devices/nm-device-ip-tunnel.c +++ b/src/devices/nm-device-ip-tunnel.c @@ -37,6 +37,8 @@ #include "nm-act-request.h" #include "nm-ip4-config.h" +#include "introspection/org.freedesktop.NetworkManager.Device.IPTunnel.h" + #include "nm-device-logging.h" _LOG_DECLARE_SELF(NMDeviceIPTunnel); @@ -53,7 +55,6 @@ NM_GOBJECT_PROPERTIES_DEFINE (NMDeviceIPTunnel, PROP_OUTPUT_KEY, PROP_ENCAPSULATION_LIMIT, PROP_FLOW_LABEL, - PROP_FLAGS, ); typedef struct { @@ -68,7 +69,6 @@ typedef struct { char *output_key; guint8 encap_limit; guint32 flow_label; - NMIPTunnelFlags flags; } NMDeviceIPTunnelPrivate; struct _NMDeviceIPTunnel { @@ -86,30 +86,6 @@ G_DEFINE_TYPE (NMDeviceIPTunnel, nm_device_ip_tunnel, NM_TYPE_DEVICE) /*****************************************************************************/ -static guint32 -ip6tnl_flags_setting_to_plat (NMIPTunnelFlags flags) -{ - G_STATIC_ASSERT (NM_IP_TUNNEL_FLAG_IP6_IGN_ENCAP_LIMIT == IP6_TNL_F_IGN_ENCAP_LIMIT); - G_STATIC_ASSERT (NM_IP_TUNNEL_FLAG_IP6_USE_ORIG_TCLASS == IP6_TNL_F_USE_ORIG_TCLASS); - G_STATIC_ASSERT (NM_IP_TUNNEL_FLAG_IP6_USE_ORIG_FLOWLABEL == IP6_TNL_F_USE_ORIG_FLOWLABEL); - G_STATIC_ASSERT (NM_IP_TUNNEL_FLAG_IP6_MIP6_DEV == IP6_TNL_F_MIP6_DEV); - G_STATIC_ASSERT (NM_IP_TUNNEL_FLAG_IP6_RCV_DSCP_COPY == IP6_TNL_F_RCV_DSCP_COPY); - G_STATIC_ASSERT (NM_IP_TUNNEL_FLAG_IP6_USE_ORIG_FWMARK == IP6_TNL_F_USE_ORIG_FWMARK); - - /* NOTE: "accidentally", the numeric values correspond. - * For flags added in the future, that might no longer - * be the case. */ - return flags & _NM_IP_TUNNEL_FLAG_ALL_IP6TNL; -} - -static NMIPTunnelFlags -ip6tnl_flags_plat_to_setting (guint32 flags) -{ - return flags & ((guint32) _NM_IP_TUNNEL_FLAG_ALL_IP6TNL); -} - -/*****************************************************************************/ - static gboolean address_equal_pp (int family, const char *a, const char *b) { @@ -153,7 +129,6 @@ update_properties_from_ifindex (NMDevice *device, int ifindex) guint8 ttl = 0, tos = 0, encap_limit = 0; gboolean pmtud = FALSE; guint32 flow_label = 0; - NMIPTunnelFlags flags = NM_IP_TUNNEL_FLAG_NONE; char *key; if (ifindex <= 0) { @@ -271,7 +246,6 @@ clear: tos = lnk->tclass; encap_limit = lnk->encap_limit; flow_label = lnk->flow_label; - flags = ip6tnl_flags_plat_to_setting (lnk->flags); } else g_return_if_reached (); @@ -333,11 +307,6 @@ out: priv->flow_label = flow_label; _notify (self, PROP_FLOW_LABEL); } - - if (priv->flags != flags) { - priv->flags = flags; - _notify (self, PROP_FLAGS); - } } static void @@ -358,7 +327,7 @@ static gboolean complete_connection (NMDevice *device, NMConnection *connection, const char *specific_object, - NMConnection *const*existing_connections, + const GSList *existing_connections, GError **error) { NMSettingIPTunnel *s_ip_tunnel; @@ -716,7 +685,6 @@ create_and_realize (NMDevice *device, lnk_ip6tnl.encap_limit = nm_setting_ip_tunnel_get_encapsulation_limit (s_ip_tunnel); lnk_ip6tnl.flow_label = nm_setting_ip_tunnel_get_flow_label (s_ip_tunnel); lnk_ip6tnl.proto = nm_setting_ip_tunnel_get_mode (s_ip_tunnel) == NM_IP_TUNNEL_MODE_IPIP6 ? IPPROTO_IPIP : IPPROTO_IPV6; - lnk_ip6tnl.flags = ip6tnl_flags_setting_to_plat (nm_setting_ip_tunnel_get_flags (s_ip_tunnel)); plerr = nm_platform_link_ip6tnl_add (nm_device_get_platform (device), iface, &lnk_ip6tnl, out_plink); if (plerr != NM_PLATFORM_ERROR_SUCCESS) { @@ -846,9 +814,6 @@ get_property (GObject *object, guint prop_id, case PROP_FLOW_LABEL: g_value_set_uint (value, priv->flow_label); break; - case PROP_FLAGS: - g_value_set_uint (value, priv->flags); - break; default: G_OBJECT_WARN_INVALID_PROPERTY_ID (object, prop_id, pspec); break; @@ -905,35 +870,10 @@ dispose (GObject *object) G_OBJECT_CLASS (nm_device_ip_tunnel_parent_class)->dispose (object); } -static const NMDBusInterfaceInfoExtended interface_info_device_ip_tunnel = { - .parent = NM_DEFINE_GDBUS_INTERFACE_INFO_INIT ( - NM_DBUS_INTERFACE_DEVICE_IP_TUNNEL, - .signals = NM_DEFINE_GDBUS_SIGNAL_INFOS ( - &nm_signal_info_property_changed_legacy, - ), - .properties = NM_DEFINE_GDBUS_PROPERTY_INFOS ( - NM_DEFINE_DBUS_PROPERTY_INFO_EXTENDED_READABLE_L ("Mode", "u", NM_DEVICE_IP_TUNNEL_MODE), - NM_DEFINE_DBUS_PROPERTY_INFO_EXTENDED_READABLE_L ("Parent", "o", NM_DEVICE_PARENT), - NM_DEFINE_DBUS_PROPERTY_INFO_EXTENDED_READABLE_L ("Local", "s", NM_DEVICE_IP_TUNNEL_LOCAL), - NM_DEFINE_DBUS_PROPERTY_INFO_EXTENDED_READABLE_L ("Remote", "s", NM_DEVICE_IP_TUNNEL_REMOTE), - NM_DEFINE_DBUS_PROPERTY_INFO_EXTENDED_READABLE_L ("Ttl", "y", NM_DEVICE_IP_TUNNEL_TTL), - NM_DEFINE_DBUS_PROPERTY_INFO_EXTENDED_READABLE_L ("Tos", "y", NM_DEVICE_IP_TUNNEL_TOS), - NM_DEFINE_DBUS_PROPERTY_INFO_EXTENDED_READABLE_L ("PathMtuDiscovery", "b", NM_DEVICE_IP_TUNNEL_PATH_MTU_DISCOVERY), - NM_DEFINE_DBUS_PROPERTY_INFO_EXTENDED_READABLE_L ("InputKey", "s", NM_DEVICE_IP_TUNNEL_INPUT_KEY), - NM_DEFINE_DBUS_PROPERTY_INFO_EXTENDED_READABLE_L ("OutputKey", "s", NM_DEVICE_IP_TUNNEL_OUTPUT_KEY), - NM_DEFINE_DBUS_PROPERTY_INFO_EXTENDED_READABLE_L ("EncapsulationLimit", "y", NM_DEVICE_IP_TUNNEL_ENCAPSULATION_LIMIT), - NM_DEFINE_DBUS_PROPERTY_INFO_EXTENDED_READABLE_L ("FlowLabel", "u", NM_DEVICE_IP_TUNNEL_FLOW_LABEL), - NM_DEFINE_DBUS_PROPERTY_INFO_EXTENDED_READABLE_L ("Flags", "u", NM_DEVICE_IP_TUNNEL_FLAGS), - ), - ), - .legacy_property_changed = TRUE, -}; - static void nm_device_ip_tunnel_class_init (NMDeviceIPTunnelClass *klass) { GObjectClass *object_class = G_OBJECT_CLASS (klass); - NMDBusObjectClass *dbus_object_class = NM_DBUS_OBJECT_CLASS (klass); NMDeviceClass *device_class = NM_DEVICE_CLASS (klass); object_class->constructed = constructed; @@ -941,8 +881,6 @@ nm_device_ip_tunnel_class_init (NMDeviceIPTunnelClass *klass) object_class->get_property = get_property; object_class->set_property = set_property; - dbus_object_class->interface_infos = NM_DBUS_INTERFACE_INFOS (&interface_info_device_ip_tunnel); - device_class->link_changed = link_changed; device_class->can_reapply_change = can_reapply_change; device_class->complete_connection = complete_connection; @@ -1021,13 +959,11 @@ nm_device_ip_tunnel_class_init (NMDeviceIPTunnelClass *klass) G_PARAM_READABLE | G_PARAM_STATIC_STRINGS); - obj_properties[PROP_FLAGS] = - g_param_spec_uint (NM_DEVICE_IP_TUNNEL_FLAGS, "", "", - 0, G_MAXUINT32, 0, - G_PARAM_READWRITE | - G_PARAM_STATIC_STRINGS); - g_object_class_install_properties (object_class, _PROPERTY_ENUMS_LAST, obj_properties); + + nm_exported_object_class_add_interface (NM_EXPORTED_OBJECT_CLASS (klass), + NMDBUS_TYPE_DEVICE_IPTUNNEL_SKELETON, + NULL); } /*****************************************************************************/ diff --git a/src/devices/nm-device-ip-tunnel.h b/src/devices/nm-device-ip-tunnel.h index 1109ace4..4bff6e33 100644 --- a/src/devices/nm-device-ip-tunnel.h +++ b/src/devices/nm-device-ip-tunnel.h @@ -41,7 +41,9 @@ #define NM_DEVICE_IP_TUNNEL_OUTPUT_KEY "output-key" #define NM_DEVICE_IP_TUNNEL_ENCAPSULATION_LIMIT "encapsulation-limit" #define NM_DEVICE_IP_TUNNEL_FLOW_LABEL "flow-label" -#define NM_DEVICE_IP_TUNNEL_FLAGS "flags" + +/* defined in the parent class, but exposed on D-Bus by the subclass. */ +#define NM_DEVICE_IP_TUNNEL_PARENT NM_DEVICE_PARENT typedef struct _NMDeviceIPTunnel NMDeviceIPTunnel; typedef struct _NMDeviceIPTunnelClass NMDeviceIPTunnelClass; diff --git a/src/devices/nm-device-macsec.c b/src/devices/nm-device-macsec.c index 895ea34f..5ef8f938 100644 --- a/src/devices/nm-device-macsec.c +++ b/src/devices/nm-device-macsec.c @@ -33,6 +33,8 @@ #include "supplicant/nm-supplicant-interface.h" #include "supplicant/nm-supplicant-config.h" +#include "introspection/org.freedesktop.NetworkManager.Device.Macsec.h" + #include "nm-device-logging.h" _LOG_DECLARE_SELF(NMDeviceMacsec); @@ -184,12 +186,8 @@ update_properties (NMDevice *device) nm_device_parent_set_ifindex (device, props->parent_ifindex); #define CHECK_PROPERTY_CHANGED(field, prop) \ - G_STMT_START { \ - if (priv->props.field != props->field) { \ - priv->props.field = props->field; \ - _notify (self, prop); \ - } \ - } G_STMT_END + if (props->field != priv->props.field) \ + _notify (self, prop) CHECK_PROPERTY_CHANGED (sci, PROP_SCI); CHECK_PROPERTY_CHANGED (cipher_suite, PROP_CIPHER_SUITE); @@ -204,6 +202,7 @@ update_properties (NMDevice *device) CHECK_PROPERTY_CHANGED (scb, PROP_SCB); CHECK_PROPERTY_CHANGED (replay_protect, PROP_REPLAY_PROTECT); + priv->props = *props; g_object_thaw_notify ((GObject *) device); } @@ -223,7 +222,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); + config = nm_supplicant_config_new (); s_macsec = (NMSettingMacsec *) nm_device_get_applied_setting (NM_DEVICE (self), NM_TYPE_SETTING_MACSEC); @@ -478,9 +477,12 @@ handle_auth_or_fail (NMDeviceMacsec *self, NMActRequest *req, gboolean new_secrets) { + NMDeviceMacsecPrivate *priv; const char *setting_name; NMConnection *applied_connection; + priv = NM_DEVICE_MACSEC_GET_PRIVATE (self); + if (!nm_device_auth_retries_try_next (NM_DEVICE (self))) return NM_ACT_STAGE_RETURN_FAILURE; @@ -490,14 +492,13 @@ handle_auth_or_fail (NMDeviceMacsec *self, applied_connection = nm_act_request_get_applied_connection (req); setting_name = nm_connection_need_secrets (applied_connection, NULL); - if (!setting_name) { + if (setting_name) { + 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)); + } else _LOGI (LOGD_DEVICE, "Cleared secrets, but setting didn't need any secrets."); - return NM_ACT_STAGE_RETURN_FAILURE; - } - 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; } @@ -811,36 +812,10 @@ dispose (GObject *object) G_OBJECT_CLASS (nm_device_macsec_parent_class)->dispose (object); } -static const NMDBusInterfaceInfoExtended interface_info_device_macsec = { - .parent = NM_DEFINE_GDBUS_INTERFACE_INFO_INIT ( - NM_DBUS_INTERFACE_DEVICE_MACSEC, - .signals = NM_DEFINE_GDBUS_SIGNAL_INFOS ( - &nm_signal_info_property_changed_legacy, - ), - .properties = NM_DEFINE_GDBUS_PROPERTY_INFOS ( - NM_DEFINE_DBUS_PROPERTY_INFO_EXTENDED_READABLE_L ("Parent", "o", NM_DEVICE_PARENT), - NM_DEFINE_DBUS_PROPERTY_INFO_EXTENDED_READABLE_L ("Sci", "t", NM_DEVICE_MACSEC_SCI), - NM_DEFINE_DBUS_PROPERTY_INFO_EXTENDED_READABLE_L ("IcvLength", "y", NM_DEVICE_MACSEC_ICV_LENGTH), - NM_DEFINE_DBUS_PROPERTY_INFO_EXTENDED_READABLE_L ("CipherSuite", "t", NM_DEVICE_MACSEC_CIPHER_SUITE), - NM_DEFINE_DBUS_PROPERTY_INFO_EXTENDED_READABLE_L ("Window", "u", NM_DEVICE_MACSEC_WINDOW), - NM_DEFINE_DBUS_PROPERTY_INFO_EXTENDED_READABLE_L ("EncodingSa", "y", NM_DEVICE_MACSEC_ENCODING_SA), - NM_DEFINE_DBUS_PROPERTY_INFO_EXTENDED_READABLE_L ("Validation", "s", NM_DEVICE_MACSEC_VALIDATION), - NM_DEFINE_DBUS_PROPERTY_INFO_EXTENDED_READABLE_L ("Encrypt", "b", NM_DEVICE_MACSEC_ENCRYPT), - NM_DEFINE_DBUS_PROPERTY_INFO_EXTENDED_READABLE_L ("Protect", "b", NM_DEVICE_MACSEC_PROTECT), - NM_DEFINE_DBUS_PROPERTY_INFO_EXTENDED_READABLE_L ("IncludeSci", "b", NM_DEVICE_MACSEC_INCLUDE_SCI), - NM_DEFINE_DBUS_PROPERTY_INFO_EXTENDED_READABLE_L ("Es", "b", NM_DEVICE_MACSEC_ES), - NM_DEFINE_DBUS_PROPERTY_INFO_EXTENDED_READABLE_L ("Scb", "b", NM_DEVICE_MACSEC_SCB), - NM_DEFINE_DBUS_PROPERTY_INFO_EXTENDED_READABLE_L ("ReplayProtect", "b", NM_DEVICE_MACSEC_REPLAY_PROTECT), - ), - ), - .legacy_property_changed = TRUE, -}; - static void nm_device_macsec_class_init (NMDeviceMacsecClass *klass) { GObjectClass *object_class = G_OBJECT_CLASS (klass); - NMDBusObjectClass *dbus_object_class = NM_DBUS_OBJECT_CLASS (klass); NMDeviceClass *parent_class = NM_DEVICE_CLASS (klass); NM_DEVICE_CLASS_DECLARE_TYPES (klass, NULL, NM_LINK_TYPE_MACSEC) @@ -848,8 +823,6 @@ nm_device_macsec_class_init (NMDeviceMacsecClass *klass) object_class->get_property = get_property; object_class->dispose = dispose; - dbus_object_class->interface_infos = NM_DBUS_INTERFACE_INFOS (&interface_info_device_macsec); - parent_class->act_stage2_config = act_stage2_config; parent_class->check_connection_compatible = check_connection_compatible; parent_class->create_and_realize = create_and_realize; @@ -913,6 +886,10 @@ nm_device_macsec_class_init (NMDeviceMacsecClass *klass) G_PARAM_READABLE | G_PARAM_STATIC_STRINGS); g_object_class_install_properties (object_class, _PROPERTY_ENUMS_LAST, obj_properties); + + nm_exported_object_class_add_interface (NM_EXPORTED_OBJECT_CLASS (klass), + NMDBUS_TYPE_DEVICE_MACSEC_SKELETON, + NULL); } /*************************************************************/ diff --git a/src/devices/nm-device-macsec.h b/src/devices/nm-device-macsec.h index 23e9d2c9..17b33bf5 100644 --- a/src/devices/nm-device-macsec.h +++ b/src/devices/nm-device-macsec.h @@ -43,6 +43,9 @@ #define NM_DEVICE_MACSEC_SCB "scb" #define NM_DEVICE_MACSEC_REPLAY_PROTECT "replay-protect" +/* defined in the parent class, but exposed on D-Bus by the subclass. */ +#define NM_DEVICE_MACSEC_PARENT NM_DEVICE_PARENT + typedef struct _NMDeviceMacsec NMDeviceMacsec; typedef struct _NMDeviceMacsecClass NMDeviceMacsecClass; diff --git a/src/devices/nm-device-macvlan.c b/src/devices/nm-device-macvlan.c index b8e748d6..2a461543 100644 --- a/src/devices/nm-device-macvlan.c +++ b/src/devices/nm-device-macvlan.c @@ -36,6 +36,8 @@ #include "nm-ip4-config.h" #include "nm-utils.h" +#include "introspection/org.freedesktop.NetworkManager.Device.Macvlan.h" + #include "nm-device-logging.h" _LOG_DECLARE_SELF(NMDeviceMacvlan); @@ -195,17 +197,12 @@ update_properties (NMDevice *device) g_object_freeze_notify (object); nm_device_parent_set_ifindex (device, plink->parent); + if (priv->props.mode != props->mode) + _notify (self, PROP_MODE); + if (priv->props.no_promisc != props->no_promisc) + _notify (self, PROP_NO_PROMISC); -#define CHECK_PROPERTY_CHANGED(field, prop) \ - G_STMT_START { \ - if (priv->props.field != props->field) { \ - priv->props.field = props->field; \ - _notify (self, prop); \ - } \ - } G_STMT_END - - CHECK_PROPERTY_CHANGED (mode, PROP_MODE); - CHECK_PROPERTY_CHANGED (no_promisc, PROP_NO_PROMISC); + priv->props = *props; g_object_thaw_notify (object); } @@ -334,7 +331,7 @@ static gboolean complete_connection (NMDevice *device, NMConnection *connection, const char *specific_object, - NMConnection *const*existing_connections, + const GSList *existing_connections, GError **error) { NMSettingMacvlan *s_macvlan; @@ -473,27 +470,10 @@ nm_device_macvlan_init (NMDeviceMacvlan *self) { } -static const NMDBusInterfaceInfoExtended interface_info_device_macvlan = { - .parent = NM_DEFINE_GDBUS_INTERFACE_INFO_INIT ( - NM_DBUS_INTERFACE_DEVICE_MACVLAN, - .signals = NM_DEFINE_GDBUS_SIGNAL_INFOS ( - &nm_signal_info_property_changed_legacy, - ), - .properties = NM_DEFINE_GDBUS_PROPERTY_INFOS ( - NM_DEFINE_DBUS_PROPERTY_INFO_EXTENDED_READABLE_L ("Parent", "o", NM_DEVICE_PARENT), - NM_DEFINE_DBUS_PROPERTY_INFO_EXTENDED_READABLE_L ("Mode", "s", NM_DEVICE_MACVLAN_MODE), - NM_DEFINE_DBUS_PROPERTY_INFO_EXTENDED_READABLE_L ("NoPromisc", "b", NM_DEVICE_MACVLAN_NO_PROMISC), - NM_DEFINE_DBUS_PROPERTY_INFO_EXTENDED_READABLE_L ("Tab", "b", NM_DEVICE_MACVLAN_TAP), - ), - ), - .legacy_property_changed = TRUE, -}; - static void nm_device_macvlan_class_init (NMDeviceMacvlanClass *klass) { GObjectClass *object_class = G_OBJECT_CLASS (klass); - NMDBusObjectClass *dbus_object_class = NM_DBUS_OBJECT_CLASS (klass); NMDeviceClass *device_class = NM_DEVICE_CLASS (klass); NM_DEVICE_CLASS_DECLARE_TYPES (klass, NULL, NM_LINK_TYPE_MACVLAN, NM_LINK_TYPE_MACVTAP) @@ -501,8 +481,6 @@ nm_device_macvlan_class_init (NMDeviceMacvlanClass *klass) object_class->get_property = get_property; object_class->set_property = set_property; - dbus_object_class->interface_infos = NM_DBUS_INTERFACE_INFOS (&interface_info_device_macvlan); - device_class->act_stage1_prepare = act_stage1_prepare; device_class->check_connection_compatible = check_connection_compatible; device_class->complete_connection = complete_connection; @@ -535,6 +513,10 @@ nm_device_macvlan_class_init (NMDeviceMacvlanClass *klass) G_PARAM_STATIC_STRINGS); g_object_class_install_properties (object_class, _PROPERTY_ENUMS_LAST, obj_properties); + + nm_exported_object_class_add_interface (NM_EXPORTED_OBJECT_CLASS (klass), + NMDBUS_TYPE_DEVICE_MACVLAN_SKELETON, + NULL); } /*****************************************************************************/ diff --git a/src/devices/nm-device-macvlan.h b/src/devices/nm-device-macvlan.h index c7d4be7c..e6d3a333 100644 --- a/src/devices/nm-device-macvlan.h +++ b/src/devices/nm-device-macvlan.h @@ -34,6 +34,9 @@ #define NM_DEVICE_MACVLAN_NO_PROMISC "no-promisc" #define NM_DEVICE_MACVLAN_TAP "tap" +/* defined in the parent class, but exposed on D-Bus by the subclass. */ +#define NM_DEVICE_MACVLAN_PARENT NM_DEVICE_PARENT + typedef struct _NMDeviceMacvlan NMDeviceMacvlan; typedef struct _NMDeviceMacvlanClass NMDeviceMacvlanClass; diff --git a/src/devices/nm-device-ppp.c b/src/devices/nm-device-ppp.c index 94df0cae..639ec44a 100644 --- a/src/devices/nm-device-ppp.c +++ b/src/devices/nm-device-ppp.c @@ -26,6 +26,8 @@ #include "ppp/nm-ppp-manager-call.h" #include "ppp/nm-ppp-status.h" +#include "introspection/org.freedesktop.NetworkManager.Device.Ppp.h" + #include "nm-device-logging.h" _LOG_DECLARE_SELF(NMDevicePpp); @@ -33,7 +35,8 @@ _LOG_DECLARE_SELF(NMDevicePpp); typedef struct _NMDevicePppPrivate { NMPPPManager *ppp_manager; - NMIP4Config *ip4_config; + NMIP4Config *pending_ip4_config; + char *pending_ifname; } NMDevicePppPrivate; struct _NMDevicePpp { @@ -85,52 +88,46 @@ ppp_state_changed (NMPPPManager *ppp_manager, NMPPPStatus status, gpointer user_ case NM_PPP_STATUS_DEAD: nm_device_state_changed (device, NM_DEVICE_STATE_FAILED, NM_DEVICE_STATE_REASON_PPP_FAILED); break; + case NM_PPP_STATUS_RUNNING: + nm_device_activate_schedule_stage3_ip_config_start (device); + break; default: break; } } static void -ppp_ifindex_set (NMPPPManager *ppp_manager, - int ifindex, - const char *iface, - gpointer user_data) -{ - NMDevice *device = NM_DEVICE (user_data); - gs_free char *old_name = NULL; - - if (!nm_device_take_over_link (device, ifindex, &old_name)) { - nm_device_state_changed (device, NM_DEVICE_STATE_FAILED, - NM_DEVICE_STATE_REASON_IP_CONFIG_UNAVAILABLE); - return; - } - - if (old_name) - nm_manager_remove_device (nm_manager_get (), old_name, NM_DEVICE_TYPE_PPP); - - nm_device_activate_schedule_stage3_ip_config_start (device); -} - -static void ppp_ip4_config (NMPPPManager *ppp_manager, + const char *iface, NMIP4Config *config, gpointer user_data) { NMDevice *device = NM_DEVICE (user_data); NMDevicePpp *self = NM_DEVICE_PPP (device); NMDevicePppPrivate *priv = NM_DEVICE_PPP_GET_PRIVATE (self); + gboolean renamed; _LOGT (LOGD_DEVICE | LOGD_PPP, "received IPv4 config from pppd"); if (nm_device_get_state (device) == NM_DEVICE_STATE_IP_CONFIG) { if (nm_device_activate_ip4_state_in_conf (device)) { + if (!nm_device_take_over_link (device, iface, &renamed)) { + nm_device_state_changed (device, NM_DEVICE_STATE_FAILED, + NM_DEVICE_STATE_REASON_IP_CONFIG_UNAVAILABLE); + return; + } + if (renamed) + nm_manager_remove_device (nm_manager_get (), iface, NM_DEVICE_TYPE_PPP); + nm_device_activate_schedule_ip4_config_result (device, config); return; } } else { - if (priv->ip4_config) - g_object_unref (priv->ip4_config); - priv->ip4_config = g_object_ref (config); + if (priv->pending_ip4_config) + g_object_unref (priv->pending_ip4_config); + priv->pending_ip4_config = g_object_ref (config); + g_free (priv->pending_ifname); + priv->pending_ifname = g_strdup (iface); } } @@ -149,7 +146,8 @@ act_stage2_config (NMDevice *device, NMDeviceStateReason *out_failure_reason) s_pppoe = (NMSettingPppoe *) nm_device_get_applied_setting ((NMDevice *) self, NM_TYPE_SETTING_PPPOE); g_return_val_if_fail (s_pppoe, NM_ACT_STAGE_RETURN_FAILURE); - g_clear_object (&priv->ip4_config); + g_clear_object (&priv->pending_ip4_config); + nm_clear_g_free (&priv->pending_ifname); priv->ppp_manager = nm_ppp_manager_create (nm_setting_pppoe_get_parent (s_pppoe), &error); @@ -177,9 +175,6 @@ act_stage2_config (NMDevice *device, NMDeviceStateReason *out_failure_reason) g_signal_connect (priv->ppp_manager, NM_PPP_MANAGER_SIGNAL_STATE_CHANGED, G_CALLBACK (ppp_state_changed), self); - g_signal_connect (priv->ppp_manager, NM_PPP_MANAGER_SIGNAL_IFINDEX_SET, - G_CALLBACK (ppp_ifindex_set), - self); g_signal_connect (priv->ppp_manager, NM_PPP_MANAGER_SIGNAL_IP4_CONFIG, G_CALLBACK (ppp_ip4_config), self); @@ -194,12 +189,17 @@ act_stage3_ip4_config_start (NMDevice *device, { NMDevicePpp *self = NM_DEVICE_PPP (device); NMDevicePppPrivate *priv = NM_DEVICE_PPP_GET_PRIVATE (self); + gboolean renamed; - if (priv->ip4_config) { + if (priv->pending_ip4_config) { + if (!nm_device_take_over_link (device, priv->pending_ifname, &renamed)) + return NM_ACT_STAGE_RETURN_FAILURE; + if (renamed) + nm_manager_remove_device (nm_manager_get (), priv->pending_ifname, NM_DEVICE_TYPE_PPP); if (out_config) - *out_config = g_steal_pointer (&priv->ip4_config); + *out_config = g_steal_pointer (&priv->pending_ip4_config); else - g_clear_object (&priv->ip4_config); + g_clear_object (&priv->pending_ip4_config); return NM_ACT_STAGE_RETURN_SUCCESS; } @@ -207,6 +207,14 @@ act_stage3_ip4_config_start (NMDevice *device, return NM_ACT_STAGE_RETURN_POSTPONE; } +static NMActStageReturn +act_stage3_ip6_config_start (NMDevice *self, + NMIP6Config **out_config, + NMDeviceStateReason *out_failure_reason) +{ + return NM_ACT_STAGE_RETURN_IP_FAIL; +} + static gboolean create_and_realize (NMDevice *device, NMConnection *connection, @@ -255,40 +263,33 @@ dispose (GObject *object) NMDevicePpp *self = NM_DEVICE_PPP (object); NMDevicePppPrivate *priv = NM_DEVICE_PPP_GET_PRIVATE (self); - g_clear_object (&priv->ip4_config); + g_clear_object (&priv->pending_ip4_config); + nm_clear_g_free (&priv->pending_ifname); G_OBJECT_CLASS (nm_device_ppp_parent_class)->dispose (object); } -static const NMDBusInterfaceInfoExtended interface_info_device_ppp = { - .parent = NM_DEFINE_GDBUS_INTERFACE_INFO_INIT ( - NM_DBUS_INTERFACE_DEVICE_PPP, - .signals = NM_DEFINE_GDBUS_SIGNAL_INFOS ( - &nm_signal_info_property_changed_legacy, - ), - ), - .legacy_property_changed = TRUE, -}; - static void nm_device_ppp_class_init (NMDevicePppClass *klass) { GObjectClass *object_class = G_OBJECT_CLASS (klass); - NMDBusObjectClass *dbus_object_class = NM_DBUS_OBJECT_CLASS (klass); NMDeviceClass *parent_class = NM_DEVICE_CLASS (klass); NM_DEVICE_CLASS_DECLARE_TYPES (klass, NM_SETTING_PPPOE_SETTING_NAME, NM_LINK_TYPE_PPP) object_class->dispose = dispose; - dbus_object_class->interface_infos = NM_DBUS_INTERFACE_INFOS (&interface_info_device_ppp); - parent_class->act_stage2_config = act_stage2_config; parent_class->act_stage3_ip4_config_start = act_stage3_ip4_config_start; + parent_class->act_stage3_ip6_config_start = act_stage3_ip6_config_start; parent_class->check_connection_compatible = check_connection_compatible; parent_class->create_and_realize = create_and_realize; parent_class->deactivate = deactivate; parent_class->get_generic_capabilities = get_generic_capabilities; + + nm_exported_object_class_add_interface (NM_EXPORTED_OBJECT_CLASS (klass), + NMDBUS_TYPE_DEVICE_PPP_SKELETON, + NULL); } /*****************************************************************************/ diff --git a/src/devices/nm-device-private.h b/src/devices/nm-device-private.h index b0d3ffa4..f1486c54 100644 --- a/src/devices/nm-device-private.h +++ b/src/devices/nm-device-private.h @@ -45,8 +45,6 @@ enum NMActStageReturn { NMSettings *nm_device_get_settings (NMDevice *self); -gboolean nm_device_set_ip_ifindex (NMDevice *self, int ifindex); - gboolean nm_device_set_ip_iface (NMDevice *self, const char *iface); void nm_device_activate_schedule_stage3_ip_config_start (NMDevice *device); @@ -59,7 +57,7 @@ gboolean nm_device_bring_up (NMDevice *self, gboolean wait, gboolean *no_firmwar void nm_device_take_down (NMDevice *self, gboolean block); -gboolean nm_device_take_over_link (NMDevice *self, int ifindex, char **old_name); +gboolean nm_device_take_over_link (NMDevice *self, const char *ifname, gboolean *renamed); gboolean nm_device_hw_addr_set (NMDevice *device, const char *addr, @@ -141,4 +139,4 @@ gboolean nm_device_match_hwaddr (NMDevice *device, NMConnection *connection, gboolean fail_if_no_hwaddr); -#endif /* NM_DEVICE_PRIVATE_H */ +#endif /* NM_DEVICE_PRIVATE_H */ diff --git a/src/devices/nm-device-tun.c b/src/devices/nm-device-tun.c index c3ce4b73..a7d7c0bf 100644 --- a/src/devices/nm-device-tun.c +++ b/src/devices/nm-device-tun.c @@ -25,7 +25,6 @@ #include <stdlib.h> #include <string.h> #include <sys/types.h> -#include <linux/if_tun.h> #include "nm-act-request.h" #include "nm-device-private.h" @@ -35,6 +34,8 @@ #include "nm-setting-tun.h" #include "nm-core-internal.h" +#include "introspection/org.freedesktop.NetworkManager.Device.Tun.h" + #include "nm-device-logging.h" _LOG_DECLARE_SELF(NMDeviceTun); @@ -50,7 +51,8 @@ NM_GOBJECT_PROPERTIES_DEFINE (NMDeviceTun, ); typedef struct { - NMPlatformLnkTun props; + NMPlatformTunProperties props; + const char *mode; } NMDeviceTunPrivate; struct _NMDeviceTun { @@ -69,62 +71,48 @@ G_DEFINE_TYPE (NMDeviceTun, nm_device_tun, NM_TYPE_DEVICE) /*****************************************************************************/ static void -update_properties_from_struct (NMDeviceTun *self, - const NMPlatformLnkTun *props) -{ - NMDeviceTunPrivate *priv = NM_DEVICE_TUN_GET_PRIVATE (self); - const NMPlatformLnkTun props0 = { }; - - if (!props) { - /* allow passing %NULL to reset all properties. */ - props = &props0; - } - - g_object_freeze_notify (G_OBJECT (self)); - -#define CHECK_PROPERTY_CHANGED_VALID(field, prop) \ - G_STMT_START { \ - if ( priv->props.field != props->field \ - || priv->props.field##_valid != props->field##_valid) { \ - priv->props.field##_valid = props->field##_valid; \ - priv->props.field = props->field; \ - _notify (self, prop); \ - } \ - } G_STMT_END - -#define CHECK_PROPERTY_CHANGED(field, prop) \ - G_STMT_START { \ - if (priv->props.field != props->field) { \ - priv->props.field = props->field; \ - _notify (self, prop); \ - } \ - } G_STMT_END - - CHECK_PROPERTY_CHANGED_VALID (owner, PROP_OWNER); - CHECK_PROPERTY_CHANGED_VALID (group, PROP_GROUP); - CHECK_PROPERTY_CHANGED (type, PROP_MODE); - CHECK_PROPERTY_CHANGED (pi, PROP_NO_PI); - CHECK_PROPERTY_CHANGED (vnet_hdr, PROP_VNET_HDR); - CHECK_PROPERTY_CHANGED (multi_queue, PROP_MULTI_QUEUE); - - g_object_thaw_notify (G_OBJECT (self)); -} - -static void update_properties (NMDeviceTun *self) { - NMPlatformLnkTun props_storage; - const NMPlatformLnkTun *props = NULL; + NMDeviceTunPrivate *priv = NM_DEVICE_TUN_GET_PRIVATE (self); + GObject *object = G_OBJECT (self); + NMPlatformTunProperties props; int ifindex; ifindex = nm_device_get_ifindex (NM_DEVICE (self)); - if ( ifindex > 0 - && nm_platform_link_tun_get_properties (nm_device_get_platform (NM_DEVICE (self)), - ifindex, - &props_storage)) - props = &props_storage; - - update_properties_from_struct (self, props); + if (ifindex > 0) { + if (!nm_platform_link_tun_get_properties (nm_device_get_platform (NM_DEVICE (self)), ifindex, &props)) { + _LOGD (LOGD_DEVICE, "tun-properties: cannot loading tun properties from platform for ifindex %d", ifindex); + ifindex = 0; + } else if (g_strcmp0 (priv->mode, props.mode) != 0) { + /* if the mode differs, we ignore what we loaded. A NMDeviceTun cannot + * change the mode after construction. */ + _LOGD (LOGD_DEVICE, "tun-properties: loading tun properties yielded tun-mode %s%s%s, but %s%s%s expected (ifindex %d)", + NM_PRINT_FMT_QUOTE_STRING (props.mode), + NM_PRINT_FMT_QUOTE_STRING (priv->mode), + ifindex); + ifindex = 0; + } + } else + _LOGD (LOGD_DEVICE, "tun-properties: ignore loading properties due to missing ifindex"); + if (ifindex <= 0) + memset (&props, 0, sizeof (props)); + + g_object_freeze_notify (object); + + if (priv->props.owner != props.owner) + _notify (self, PROP_OWNER); + if (priv->props.group != props.group) + _notify (self, PROP_GROUP); + if (priv->props.no_pi != props.no_pi) + _notify (self, PROP_NO_PI); + if (priv->props.vnet_hdr != props.vnet_hdr) + _notify (self, PROP_VNET_HDR); + if (priv->props.multi_queue != props.multi_queue) + _notify (self, PROP_MULTI_QUEUE); + + memcpy (&priv->props, &props, sizeof (NMPlatformTunProperties)); + + g_object_thaw_notify (object); } static NMDeviceCapabilities @@ -145,7 +133,7 @@ static gboolean complete_connection (NMDevice *device, NMConnection *connection, const char *specific_object, - NMConnection *const*existing_connections, + const GSList *existing_connections, GError **error) { NMSettingTun *s_tun; @@ -169,57 +157,61 @@ complete_connection (NMDevice *device, return TRUE; } +static int +tun_mode_from_string (const char *string) +{ + if (!g_strcmp0 (string, "tap")) + return NM_SETTING_TUN_MODE_TAP; + else + return NM_SETTING_TUN_MODE_TUN; +} + static void update_connection (NMDevice *device, NMConnection *connection) { NMDeviceTun *self = NM_DEVICE_TUN (device); - NMDeviceTunPrivate *priv = NM_DEVICE_TUN_GET_PRIVATE (self); - NMSettingTun *s_tun; + NMSettingTun *s_tun = nm_connection_get_setting_tun (connection); + NMPlatformTunProperties props; NMSettingTunMode mode; - char s_buf[100]; - const char *str; - - /* Note: since we read tun properties from sysctl for older kernels, - * we don't get proper change notifications. Make sure that all our - * tun properties are up to date at this point. We should not do this, - * if we would entirely rely on netlink events. */ - update_properties (NM_DEVICE_TUN (device)); + gint64 user, group; + char *str; - switch (priv->props.type) { - case IFF_TUN: mode = NM_SETTING_TUN_MODE_TUN; break; - case IFF_TAP: mode = NM_SETTING_TUN_MODE_TAP; break; - default: - /* Huh? */ - return; - } - - s_tun = nm_connection_get_setting_tun (connection); if (!s_tun) { s_tun = (NMSettingTun *) nm_setting_tun_new (); nm_connection_add_setting (connection, (NMSetting *) s_tun); } + if (!nm_platform_link_tun_get_properties (nm_device_get_platform (device), nm_device_get_ifindex (device), &props)) { + _LOGW (LOGD_PLATFORM, "failed to get TUN interface info while updating connection."); + return; + } + + mode = tun_mode_from_string (props.mode); + if (mode != nm_setting_tun_get_mode (s_tun)) - g_object_set (G_OBJECT (s_tun), NM_SETTING_TUN_MODE, (guint) mode, NULL); + g_object_set (G_OBJECT (s_tun), NM_SETTING_TUN_MODE, mode, NULL); + + user = _nm_utils_ascii_str_to_int64 (nm_setting_tun_get_owner (s_tun), 10, 0, G_MAXINT32, -1); + group = _nm_utils_ascii_str_to_int64 (nm_setting_tun_get_group (s_tun), 10, 0, G_MAXINT32, -1); - str = priv->props.owner_valid - ? nm_sprintf_buf (s_buf, "%" G_GINT32_FORMAT, priv->props.owner) - : NULL; - if (!nm_streq0 (str, nm_setting_tun_get_owner (s_tun))) + if (props.owner != user) { + str = props.owner >= 0 ? g_strdup_printf ("%" G_GINT32_FORMAT, (gint32) props.owner) : NULL; g_object_set (G_OBJECT (s_tun), NM_SETTING_TUN_OWNER, str, NULL); + g_free (str); + } - str = priv->props.group_valid - ? nm_sprintf_buf (s_buf, "%" G_GINT32_FORMAT, priv->props.group) - : NULL; - if (!nm_streq0 (str, nm_setting_tun_get_group (s_tun))) + if (props.group != group) { + str = props.group >= 0 ? g_strdup_printf ("%" G_GINT32_FORMAT, (gint32) props.group) : NULL; g_object_set (G_OBJECT (s_tun), NM_SETTING_TUN_GROUP, str, NULL); + g_free (str); + } - if (priv->props.pi != nm_setting_tun_get_pi (s_tun)) - g_object_set (G_OBJECT (s_tun), NM_SETTING_TUN_PI, (gboolean) priv->props.pi, NULL); - if (priv->props.vnet_hdr != nm_setting_tun_get_vnet_hdr (s_tun)) - g_object_set (G_OBJECT (s_tun), NM_SETTING_TUN_VNET_HDR, (gboolean) priv->props.vnet_hdr, NULL); - if (priv->props.multi_queue != nm_setting_tun_get_multi_queue (s_tun)) - g_object_set (G_OBJECT (s_tun), NM_SETTING_TUN_MULTI_QUEUE, (gboolean) priv->props.multi_queue, NULL); + if ((!props.no_pi) != nm_setting_tun_get_pi (s_tun)) + g_object_set (G_OBJECT (s_tun), NM_SETTING_TUN_PI, !props.no_pi, NULL); + if (props.vnet_hdr != nm_setting_tun_get_vnet_hdr (s_tun)) + g_object_set (G_OBJECT (s_tun), NM_SETTING_TUN_VNET_HDR, props.vnet_hdr, NULL); + if (props.multi_queue != nm_setting_tun_get_multi_queue (s_tun)) + g_object_set (G_OBJECT (s_tun), NM_SETTING_TUN_MULTI_QUEUE, props.multi_queue, NULL); } static gboolean @@ -230,42 +222,23 @@ create_and_realize (NMDevice *device, GError **error) { const char *iface = nm_device_get_iface (device); - NMPlatformLnkTun props = { }; NMPlatformError plerr; NMSettingTun *s_tun; - gint64 owner, group; + gint64 user, group; s_tun = nm_connection_get_setting_tun (connection); - g_return_val_if_fail (s_tun, FALSE); - - switch (nm_setting_tun_get_mode (s_tun)) { - case NM_SETTING_TUN_MODE_TAP: props.type = IFF_TAP; break; - case NM_SETTING_TUN_MODE_TUN: props.type = IFF_TUN; break; - default: - g_return_val_if_reached (FALSE); - } + g_assert (s_tun); - owner = _nm_utils_ascii_str_to_int64 (nm_setting_tun_get_owner (s_tun), 10, 0, G_MAXINT32, -1); - if (owner != -1) { - props.owner_valid = TRUE; - props.owner = owner; - } + user = _nm_utils_ascii_str_to_int64 (nm_setting_tun_get_owner (s_tun), 10, 0, G_MAXINT32, -1); group = _nm_utils_ascii_str_to_int64 (nm_setting_tun_get_group (s_tun), 10, 0, G_MAXINT32, -1); - if (group != -1) { - props.group_valid = TRUE; - props.group = group; - } - props.pi = nm_setting_tun_get_pi (s_tun); - props.vnet_hdr = nm_setting_tun_get_vnet_hdr (s_tun); - props.multi_queue = nm_setting_tun_get_multi_queue (s_tun); - props.persist = TRUE; - - plerr = nm_platform_link_tun_add (nm_device_get_platform (device), - iface, - &props, - out_plink, - NULL); + plerr = nm_platform_link_tun_add (nm_device_get_platform (device), iface, + nm_setting_tun_get_mode (s_tun) == NM_SETTING_TUN_MODE_TAP, + user, group, + nm_setting_tun_get_pi (s_tun), + nm_setting_tun_get_vnet_hdr (s_tun), + nm_setting_tun_get_multi_queue (s_tun), + out_plink); if (plerr != NM_PLATFORM_ERROR_SUCCESS) { g_set_error (error, NM_DEVICE_ERROR, NM_DEVICE_ERROR_CREATION_FAILED, "Failed to create TUN/TAP interface '%s' for '%s': %s", @@ -279,22 +252,13 @@ create_and_realize (NMDevice *device, } static gboolean -_same_og (const char *str, gboolean og_valid, guint32 og_num) -{ - gint64 v; - - v = _nm_utils_ascii_str_to_int64 (str, 10, 0, G_MAXINT32, -1); - return (!og_valid && ( v == (gint64) -1)) - || ( og_valid && (((guint32) v) == og_num )); -} - -static gboolean check_connection_compatible (NMDevice *device, NMConnection *connection) { NMDeviceTun *self = NM_DEVICE_TUN (device); NMDeviceTunPrivate *priv = NM_DEVICE_TUN_GET_PRIVATE (self); NMSettingTunMode mode; NMSettingTun *s_tun; + gint64 user, group; if (!NM_DEVICE_CLASS (nm_device_tun_parent_class)->check_connection_compatible (device, connection)) return FALSE; @@ -304,21 +268,18 @@ check_connection_compatible (NMDevice *device, NMConnection *connection) return FALSE; if (nm_device_is_real (device)) { - switch (priv->props.type) { - case IFF_TUN: mode = NM_SETTING_TUN_MODE_TUN; break; - case IFF_TAP: mode = NM_SETTING_TUN_MODE_TAP; break; - default: - /* Huh? */ - return FALSE; - } - + mode = tun_mode_from_string (priv->mode); if (mode != nm_setting_tun_get_mode (s_tun)) return FALSE; - if (!_same_og (nm_setting_tun_get_owner (s_tun), priv->props.owner_valid, priv->props.owner)) + + user = _nm_utils_ascii_str_to_int64 (nm_setting_tun_get_owner (s_tun), 10, 0, G_MAXINT32, -1); + group = _nm_utils_ascii_str_to_int64 (nm_setting_tun_get_group (s_tun), 10, 0, G_MAXINT32, -1); + + if (user != priv->props.owner) return FALSE; - if (!_same_og (nm_setting_tun_get_group (s_tun), priv->props.group_valid, priv->props.group)) + if (group != priv->props.group) return FALSE; - if (nm_setting_tun_get_pi (s_tun) != priv->props.pi) + if (nm_setting_tun_get_pi (s_tun) == priv->props.no_pi) return FALSE; if (nm_setting_tun_get_vnet_hdr (s_tun) != priv->props.vnet_hdr) return FALSE; @@ -341,7 +302,7 @@ act_stage1_prepare (NMDevice *device, NMDeviceStateReason *out_failure_reason) return ret; /* Nothing to do for TUN devices */ - if (priv->props.type == IFF_TUN) + if (g_strcmp0 (priv->mode, "tap")) return NM_ACT_STAGE_RETURN_SUCCESS; if (!nm_device_hw_addr_set_cloned (device, nm_device_get_applied_connection (device), FALSE)) @@ -353,8 +314,16 @@ act_stage1_prepare (NMDevice *device, NMDeviceStateReason *out_failure_reason) static void unrealize_notify (NMDevice *device) { + NMDeviceTun *self = NM_DEVICE_TUN (device); + NMDeviceTunPrivate *priv = NM_DEVICE_TUN_GET_PRIVATE (self); + guint i; + NM_DEVICE_CLASS (nm_device_tun_parent_class)->unrealize_notify (device); - update_properties_from_struct (NM_DEVICE_TUN (device), NULL); + + memset (&priv->props, 0, sizeof (NMPlatformTunProperties)); + + for (i = 1; i < _PROPERTY_ENUMS_LAST; i++) + g_object_notify_by_pspec ((GObject *) self, obj_properties[i]); } /*****************************************************************************/ @@ -365,25 +334,19 @@ get_property (GObject *object, guint prop_id, { NMDeviceTun *self = NM_DEVICE_TUN (object); NMDeviceTunPrivate *priv = NM_DEVICE_TUN_GET_PRIVATE (self); - const char *s; switch (prop_id) { case PROP_OWNER: - g_value_set_int64 (value, priv->props.owner_valid ? (gint64) priv->props.owner : (gint64) -1); + g_value_set_int64 (value, priv->props.owner); break; case PROP_GROUP: - g_value_set_int64 (value, priv->props.group_valid ? (gint64) priv->props.group : (gint64) -1); + g_value_set_int64 (value, priv->props.group); break; case PROP_MODE: - switch (priv->props.type) { - case IFF_TUN: s = "tun"; break; - case IFF_TAP: s = "tap"; break; - default: s = NULL; break; - } - g_value_set_static_string (value, s); + g_value_set_string (value, priv->mode); break; case PROP_NO_PI: - g_value_set_boolean (value, !priv->props.pi); + g_value_set_boolean (value, priv->props.no_pi); break; case PROP_VNET_HDR: g_value_set_boolean (value, priv->props.vnet_hdr); @@ -397,6 +360,33 @@ get_property (GObject *object, guint prop_id, } } +static void +set_property (GObject *object, guint prop_id, + const GValue *value, GParamSpec *pspec) +{ + NMDeviceTun *self = NM_DEVICE_TUN (object); + NMDeviceTunPrivate *priv = NM_DEVICE_TUN_GET_PRIVATE (self); + const char *str; + + switch (prop_id) { + case PROP_MODE: + /* construct-only */ + str = g_value_get_string (value); + + /* mode is G_PARAM_STATIC_STRINGS */ + if (g_strcmp0 (str, "tun") == 0) + priv->mode = "tun"; + else if (g_strcmp0 (str, "tap") == 0) + priv->mode = "tap"; + else + g_return_if_fail (FALSE); + break; + default: + G_OBJECT_WARN_INVALID_PROPERTY_ID (object, prop_id, pspec); + break; + } +} + /*****************************************************************************/ static void @@ -404,37 +394,16 @@ nm_device_tun_init (NMDeviceTun *self) { } -static const NMDBusInterfaceInfoExtended interface_info_device_tun = { - .parent = NM_DEFINE_GDBUS_INTERFACE_INFO_INIT ( - NM_DBUS_INTERFACE_DEVICE_TUN, - .signals = NM_DEFINE_GDBUS_SIGNAL_INFOS ( - &nm_signal_info_property_changed_legacy, - ), - .properties = NM_DEFINE_GDBUS_PROPERTY_INFOS ( - NM_DEFINE_DBUS_PROPERTY_INFO_EXTENDED_READABLE_L ("Owner", "x", NM_DEVICE_TUN_OWNER), - NM_DEFINE_DBUS_PROPERTY_INFO_EXTENDED_READABLE_L ("Group", "x", NM_DEVICE_TUN_GROUP), - NM_DEFINE_DBUS_PROPERTY_INFO_EXTENDED_READABLE_L ("Mode", "s", NM_DEVICE_TUN_MODE), - NM_DEFINE_DBUS_PROPERTY_INFO_EXTENDED_READABLE_L ("NoPi", "b", NM_DEVICE_TUN_NO_PI), - NM_DEFINE_DBUS_PROPERTY_INFO_EXTENDED_READABLE_L ("VnetHdr", "b", NM_DEVICE_TUN_VNET_HDR), - NM_DEFINE_DBUS_PROPERTY_INFO_EXTENDED_READABLE_L ("MultiQueue", "b", NM_DEVICE_TUN_MULTI_QUEUE), - NM_DEFINE_DBUS_PROPERTY_INFO_EXTENDED_READABLE_L ("HwAddress", "s", NM_DEVICE_HW_ADDRESS), - ), - ), - .legacy_property_changed = TRUE, -}; - static void nm_device_tun_class_init (NMDeviceTunClass *klass) { GObjectClass *object_class = G_OBJECT_CLASS (klass); - NMDBusObjectClass *dbus_object_class = NM_DBUS_OBJECT_CLASS (klass); NMDeviceClass *device_class = NM_DEVICE_CLASS (klass); - NM_DEVICE_CLASS_DECLARE_TYPES (klass, NULL, NM_LINK_TYPE_TUN) + NM_DEVICE_CLASS_DECLARE_TYPES (klass, NULL, NM_LINK_TYPE_TUN, NM_LINK_TYPE_TAP) object_class->get_property = get_property; - - dbus_object_class->interface_infos = NM_DBUS_INTERFACE_INFOS (&interface_info_device_tun); + object_class->set_property = set_property; device_class->connection_type = NM_SETTING_TUN_SETTING_NAME; device_class->link_changed = link_changed; @@ -459,8 +428,9 @@ nm_device_tun_class_init (NMDeviceTunClass *klass) obj_properties[PROP_MODE] = g_param_spec_string (NM_DEVICE_TUN_MODE, "", "", - NULL, - G_PARAM_READABLE | G_PARAM_STATIC_STRINGS); + "tun", + G_PARAM_READWRITE | G_PARAM_CONSTRUCT_ONLY | + G_PARAM_STATIC_STRINGS); obj_properties[PROP_NO_PI] = g_param_spec_boolean (NM_DEVICE_TUN_NO_PI, "", "", @@ -478,6 +448,10 @@ nm_device_tun_class_init (NMDeviceTunClass *klass) G_PARAM_READABLE | G_PARAM_STATIC_STRINGS); g_object_class_install_properties (object_class, _PROPERTY_ENUMS_LAST, obj_properties); + + nm_exported_object_class_add_interface (NM_EXPORTED_OBJECT_CLASS (klass), + NMDBUS_TYPE_DEVICE_TUN_SKELETON, + NULL); } @@ -493,19 +467,42 @@ create_device (NMDeviceFactory *factory, NMConnection *connection, gboolean *out_ignore) { - g_return_val_if_fail (!plink || plink->type == NM_LINK_TYPE_TUN, NULL); - g_return_val_if_fail (!connection || nm_streq0 (nm_connection_get_connection_type (connection), NM_SETTING_TUN_SETTING_NAME), NULL); + NMSettingTun *s_tun; + NMLinkType link_type = NM_LINK_TYPE_UNKNOWN; + const char *mode; + + if (plink) { + link_type = plink->type; + } else if (connection) { + s_tun = nm_connection_get_setting_tun (connection); + if (!s_tun) + return NULL; + switch (nm_setting_tun_get_mode (s_tun)) { + case NM_SETTING_TUN_MODE_TUN: + link_type = NM_LINK_TYPE_TUN; + break; + case NM_SETTING_TUN_MODE_TAP: + link_type = NM_LINK_TYPE_TAP; + break; + case NM_SETTING_TUN_MODE_UNKNOWN: + g_return_val_if_reached (NULL); + } + } + + g_return_val_if_fail (link_type != NM_LINK_TYPE_UNKNOWN, NULL); + mode = link_type == NM_LINK_TYPE_TUN ? "tun" : "tap"; return (NMDevice *) g_object_new (NM_TYPE_DEVICE_TUN, NM_DEVICE_IFACE, iface, NM_DEVICE_TYPE_DESC, "Tun", NM_DEVICE_DEVICE_TYPE, NM_DEVICE_TYPE_TUN, - NM_DEVICE_LINK_TYPE, (guint) NM_LINK_TYPE_TUN, + NM_DEVICE_LINK_TYPE, link_type, + NM_DEVICE_TUN_MODE, mode, NULL); } NM_DEVICE_FACTORY_DEFINE_INTERNAL (TUN, Tun, tun, - NM_DEVICE_FACTORY_DECLARE_LINK_TYPES (NM_LINK_TYPE_TUN) + NM_DEVICE_FACTORY_DECLARE_LINK_TYPES (NM_LINK_TYPE_TUN, NM_LINK_TYPE_TAP) NM_DEVICE_FACTORY_DECLARE_SETTING_TYPES (NM_SETTING_TUN_SETTING_NAME), factory_class->create_device = create_device; ); diff --git a/src/devices/nm-device-veth.c b/src/devices/nm-device-veth.c index 186173eb..a8c4bcc8 100644 --- a/src/devices/nm-device-veth.c +++ b/src/devices/nm-device-veth.c @@ -30,6 +30,8 @@ #include "platform/nm-platform.h" #include "nm-device-factory.h" +#include "introspection/org.freedesktop.NetworkManager.Device.Veth.h" + #include "nm-device-logging.h" _LOG_DECLARE_SELF(NMDeviceVeth); @@ -99,18 +101,11 @@ nm_device_veth_init (NMDeviceVeth *self) } static void -parent_changed_notify (NMDevice *device, - int old_ifindex, - NMDevice *old_parent, - int new_ifindex, - NMDevice *new_parent) +notify (GObject *object, GParamSpec *pspec) { - NM_DEVICE_CLASS (nm_device_veth_parent_class)->parent_changed_notify (device, - old_ifindex, - old_parent, - new_ifindex, - new_parent); - _notify (NM_DEVICE_VETH (device), PROP_PEER); + if (nm_streq (pspec->name, NM_DEVICE_PARENT)) + _notify (NM_DEVICE_VETH (object), PROP_PEER); + G_OBJECT_CLASS (nm_device_veth_parent_class)->notify (object, pspec); } static void @@ -125,7 +120,7 @@ get_property (GObject *object, guint prop_id, peer = nm_device_parent_get_device (NM_DEVICE (self)); if (peer && !NM_IS_DEVICE_VETH (peer)) peer = NULL; - nm_dbus_utils_g_value_set_object_path (value, peer); + nm_utils_g_value_set_object_path (value, peer); break; default: G_OBJECT_WARN_INVALID_PROPERTY_ID (object, prop_id, pspec); @@ -133,35 +128,19 @@ get_property (GObject *object, guint prop_id, } } -static const NMDBusInterfaceInfoExtended interface_info_device_veth = { - .parent = NM_DEFINE_GDBUS_INTERFACE_INFO_INIT ( - NM_DBUS_INTERFACE_DEVICE_VETH, - .signals = NM_DEFINE_GDBUS_SIGNAL_INFOS ( - &nm_signal_info_property_changed_legacy, - ), - .properties = NM_DEFINE_GDBUS_PROPERTY_INFOS ( - NM_DEFINE_DBUS_PROPERTY_INFO_EXTENDED_READABLE_L ("Peer", "o", NM_DEVICE_VETH_PEER), - ), - ), - .legacy_property_changed = TRUE, -}; - static void nm_device_veth_class_init (NMDeviceVethClass *klass) { GObjectClass *object_class = G_OBJECT_CLASS (klass); - NMDBusObjectClass *dbus_object_class = NM_DBUS_OBJECT_CLASS (klass); NMDeviceClass *device_class = NM_DEVICE_CLASS (klass); NM_DEVICE_CLASS_DECLARE_TYPES (klass, NULL, NM_LINK_TYPE_VETH) object_class->get_property = get_property; - - dbus_object_class->interface_infos = NM_DBUS_INTERFACE_INFOS (&interface_info_device_veth); + object_class->notify = notify; device_class->can_unmanaged_external_down = can_unmanaged_external_down; device_class->link_changed = link_changed; - device_class->parent_changed_notify = parent_changed_notify; obj_properties[PROP_PEER] = g_param_spec_string (NM_DEVICE_VETH_PEER, "", "", @@ -170,6 +149,10 @@ nm_device_veth_class_init (NMDeviceVethClass *klass) G_PARAM_STATIC_STRINGS); g_object_class_install_properties (object_class, _PROPERTY_ENUMS_LAST, obj_properties); + + nm_exported_object_class_add_interface (NM_EXPORTED_OBJECT_CLASS (klass), + NMDBUS_TYPE_DEVICE_VETH_SKELETON, + NULL); } /*****************************************************************************/ diff --git a/src/devices/nm-device-vlan.c b/src/devices/nm-device-vlan.c index ae6a0f36..81512335 100644 --- a/src/devices/nm-device-vlan.c +++ b/src/devices/nm-device-vlan.c @@ -37,6 +37,8 @@ #include "nm-core-internal.h" #include "platform/nmp-object.h" +#include "introspection/org.freedesktop.NetworkManager.Device.Vlan.h" + #include "nm-device-logging.h" _LOG_DECLARE_SELF(NMDeviceVlan); @@ -132,7 +134,7 @@ parent_hwaddr_maybe_changed (NMDevice *parent, */ s_ip6 = nm_connection_get_setting_ip6_config (connection); if (s_ip6) - nm_device_reactivate_ip6_config (NM_DEVICE (self), s_ip6, s_ip6); + nm_device_reactivate_ip6_config (NM_DEVICE (self), s_ip6, s_ip6, FALSE); } } @@ -379,7 +381,7 @@ static gboolean complete_connection (NMDevice *device, NMConnection *connection, const char *specific_object, - NMConnection *const*existing_connections, + const GSList *existing_connections, GError **error) { NMSettingVlan *s_vlan; @@ -575,35 +577,16 @@ nm_device_vlan_init (NMDeviceVlan * self) { } -static const NMDBusInterfaceInfoExtended interface_info_device_vlan = { - .parent = NM_DEFINE_GDBUS_INTERFACE_INFO_INIT ( - NM_DBUS_INTERFACE_DEVICE_VLAN, - .signals = NM_DEFINE_GDBUS_SIGNAL_INFOS ( - &nm_signal_info_property_changed_legacy, - ), - .properties = NM_DEFINE_GDBUS_PROPERTY_INFOS ( - NM_DEFINE_DBUS_PROPERTY_INFO_EXTENDED_READABLE_L ("HwAddress", "s", NM_DEVICE_HW_ADDRESS), - NM_DEFINE_DBUS_PROPERTY_INFO_EXTENDED_READABLE_L ("Carrier", "b", NM_DEVICE_CARRIER), - NM_DEFINE_DBUS_PROPERTY_INFO_EXTENDED_READABLE_L ("Parent", "o", NM_DEVICE_PARENT), - NM_DEFINE_DBUS_PROPERTY_INFO_EXTENDED_READABLE_L ("VlanId", "u", NM_DEVICE_VLAN_ID), - ), - ), - .legacy_property_changed = TRUE, -}; - static void nm_device_vlan_class_init (NMDeviceVlanClass *klass) { GObjectClass *object_class = G_OBJECT_CLASS (klass); - NMDBusObjectClass *dbus_object_class = NM_DBUS_OBJECT_CLASS (klass); NMDeviceClass *parent_class = NM_DEVICE_CLASS (klass); NM_DEVICE_CLASS_DECLARE_TYPES (klass, NM_SETTING_VLAN_SETTING_NAME, NM_LINK_TYPE_VLAN) object_class->get_property = get_property; - dbus_object_class->interface_infos = NM_DBUS_INTERFACE_INFOS (&interface_info_device_vlan); - parent_class->create_and_realize = create_and_realize; parent_class->link_changed = link_changed; parent_class->unrealize_notify = unrealize_notify; @@ -625,6 +608,10 @@ nm_device_vlan_class_init (NMDeviceVlanClass *klass) | G_PARAM_STATIC_STRINGS); g_object_class_install_properties (object_class, _PROPERTY_ENUMS_LAST, obj_properties); + + nm_exported_object_class_add_interface (NM_EXPORTED_OBJECT_CLASS (klass), + NMDBUS_TYPE_DEVICE_VLAN_SKELETON, + NULL); } /*****************************************************************************/ diff --git a/src/devices/nm-device-vlan.h b/src/devices/nm-device-vlan.h index 375e8fa4..0d788940 100644 --- a/src/devices/nm-device-vlan.h +++ b/src/devices/nm-device-vlan.h @@ -36,8 +36,12 @@ typedef enum { NM_VLAN_ERROR_CONNECTION_INCOMPATIBLE, /*< nick=ConnectionIncompatible >*/ } NMVlanError; +/* D-Bus exported properties */ #define NM_DEVICE_VLAN_ID "vlan-id" +/* defined in the parent class, but exposed on D-Bus by the subclass. */ +#define NM_DEVICE_VLAN_PARENT NM_DEVICE_PARENT + typedef struct _NMDeviceVlan NMDeviceVlan; typedef struct _NMDeviceVlanClass NMDeviceVlanClass; diff --git a/src/devices/nm-device-vxlan.c b/src/devices/nm-device-vxlan.c index e1252223..d9efe840 100644 --- a/src/devices/nm-device-vxlan.c +++ b/src/devices/nm-device-vxlan.c @@ -35,6 +35,8 @@ #include "nm-act-request.h" #include "nm-ip4-config.h" +#include "introspection/org.freedesktop.NetworkManager.Device.Vxlan.h" + #include "nm-device-logging.h" _LOG_DECLARE_SELF(NMDeviceVxlan); @@ -95,40 +97,42 @@ update_properties (NMDevice *device) if (priv->props.parent_ifindex != props->parent_ifindex) nm_device_parent_set_ifindex (device, props->parent_ifindex); - -#define CHECK_PROPERTY_CHANGED(field, prop) \ - G_STMT_START { \ - if (priv->props.field != props->field) { \ - priv->props.field = props->field; \ - _notify (self, prop); \ - } \ - } G_STMT_END - -#define CHECK_PROPERTY_CHANGED_IN6ADDR(field, prop) \ - G_STMT_START { \ - if (memcmp (&priv->props.field, &props->field, sizeof (props->field)) != 0) { \ - priv->props.field = props->field; \ - _notify (self, prop); \ - } \ - } G_STMT_END - - CHECK_PROPERTY_CHANGED (id, PROP_ID); - CHECK_PROPERTY_CHANGED (local, PROP_LOCAL); - CHECK_PROPERTY_CHANGED_IN6ADDR (local6, PROP_LOCAL); - CHECK_PROPERTY_CHANGED (group, PROP_GROUP); - CHECK_PROPERTY_CHANGED_IN6ADDR (group6, PROP_GROUP); - CHECK_PROPERTY_CHANGED (tos, PROP_TOS); - CHECK_PROPERTY_CHANGED (ttl, PROP_TTL); - CHECK_PROPERTY_CHANGED (learning, PROP_LEARNING); - CHECK_PROPERTY_CHANGED (ageing, PROP_AGEING); - CHECK_PROPERTY_CHANGED (limit, PROP_LIMIT); - CHECK_PROPERTY_CHANGED (src_port_min, PROP_SRC_PORT_MIN); - CHECK_PROPERTY_CHANGED (src_port_max, PROP_SRC_PORT_MAX); - CHECK_PROPERTY_CHANGED (dst_port, PROP_DST_PORT); - CHECK_PROPERTY_CHANGED (proxy, PROP_PROXY); - CHECK_PROPERTY_CHANGED (rsc, PROP_RSC); - CHECK_PROPERTY_CHANGED (l2miss, PROP_L2MISS); - CHECK_PROPERTY_CHANGED (l3miss, PROP_L3MISS); + if (priv->props.id != props->id) + _notify (self, PROP_ID); + if (priv->props.local != props->local) + _notify (self, PROP_LOCAL); + if (memcmp (&priv->props.local6, &props->local6, sizeof (props->local6)) != 0) + _notify (self, PROP_LOCAL); + if (priv->props.group != props->group) + _notify (self, PROP_GROUP); + if (memcmp (&priv->props.group6, &props->group6, sizeof (props->group6)) != 0) + _notify (self, PROP_GROUP); + if (priv->props.tos != props->tos) + _notify (self, PROP_TOS); + if (priv->props.ttl != props->ttl) + _notify (self, PROP_TTL); + if (priv->props.learning != props->learning) + _notify (self, PROP_LEARNING); + if (priv->props.ageing != props->ageing) + _notify (self, PROP_AGEING); + if (priv->props.limit != props->limit) + _notify (self, PROP_LIMIT); + if (priv->props.src_port_min != props->src_port_min) + _notify (self, PROP_SRC_PORT_MIN); + if (priv->props.src_port_max != props->src_port_max) + _notify (self, PROP_SRC_PORT_MAX); + if (priv->props.dst_port != props->dst_port) + _notify (self, PROP_DST_PORT); + if (priv->props.proxy != props->proxy) + _notify (self, PROP_PROXY); + if (priv->props.rsc != props->rsc) + _notify (self, PROP_RSC); + if (priv->props.l2miss != props->l2miss) + _notify (self, PROP_L2MISS); + if (priv->props.l3miss != props->l3miss) + _notify (self, PROP_L3MISS); + + priv->props = *props; g_object_thaw_notify (object); } @@ -314,7 +318,7 @@ static gboolean complete_connection (NMDevice *device, NMConnection *connection, const char *specific_object, - NMConnection *const*existing_connections, + const GSList *existing_connections, GError **error) { NMSettingVxlan *s_vxlan; @@ -541,48 +545,16 @@ nm_device_vxlan_init (NMDeviceVxlan *self) { } -static const NMDBusInterfaceInfoExtended interface_info_device_vxlan = { - .parent = NM_DEFINE_GDBUS_INTERFACE_INFO_INIT ( - NM_DBUS_INTERFACE_DEVICE_VXLAN, - .signals = NM_DEFINE_GDBUS_SIGNAL_INFOS ( - &nm_signal_info_property_changed_legacy, - ), - .properties = NM_DEFINE_GDBUS_PROPERTY_INFOS ( - NM_DEFINE_DBUS_PROPERTY_INFO_EXTENDED_READABLE_L ("Parent", "o", NM_DEVICE_PARENT), - NM_DEFINE_DBUS_PROPERTY_INFO_EXTENDED_READABLE_L ("HwAddress", "s", NM_DEVICE_HW_ADDRESS), - NM_DEFINE_DBUS_PROPERTY_INFO_EXTENDED_READABLE_L ("Id", "u", NM_DEVICE_VXLAN_ID), - NM_DEFINE_DBUS_PROPERTY_INFO_EXTENDED_READABLE_L ("Group", "s", NM_DEVICE_VXLAN_GROUP), - NM_DEFINE_DBUS_PROPERTY_INFO_EXTENDED_READABLE_L ("Local", "s", NM_DEVICE_VXLAN_LOCAL), - NM_DEFINE_DBUS_PROPERTY_INFO_EXTENDED_READABLE_L ("Tos", "y", NM_DEVICE_VXLAN_TOS), - NM_DEFINE_DBUS_PROPERTY_INFO_EXTENDED_READABLE_L ("Ttl", "y", NM_DEVICE_VXLAN_TTL), - NM_DEFINE_DBUS_PROPERTY_INFO_EXTENDED_READABLE_L ("Learning", "b", NM_DEVICE_VXLAN_LEARNING), - NM_DEFINE_DBUS_PROPERTY_INFO_EXTENDED_READABLE_L ("Ageing", "u", NM_DEVICE_VXLAN_AGEING), - NM_DEFINE_DBUS_PROPERTY_INFO_EXTENDED_READABLE_L ("Limit", "u", NM_DEVICE_VXLAN_LIMIT), - NM_DEFINE_DBUS_PROPERTY_INFO_EXTENDED_READABLE_L ("DstPort", "q", NM_DEVICE_VXLAN_DST_PORT), - NM_DEFINE_DBUS_PROPERTY_INFO_EXTENDED_READABLE_L ("SrcPortMin", "q", NM_DEVICE_VXLAN_SRC_PORT_MIN), - NM_DEFINE_DBUS_PROPERTY_INFO_EXTENDED_READABLE_L ("SrcPortMax", "q", NM_DEVICE_VXLAN_SRC_PORT_MAX), - NM_DEFINE_DBUS_PROPERTY_INFO_EXTENDED_READABLE_L ("Proxy", "b", NM_DEVICE_VXLAN_PROXY), - NM_DEFINE_DBUS_PROPERTY_INFO_EXTENDED_READABLE_L ("Rsc", "b", NM_DEVICE_VXLAN_RSC), - NM_DEFINE_DBUS_PROPERTY_INFO_EXTENDED_READABLE_L ("L2miss", "b", NM_DEVICE_VXLAN_L2MISS), - NM_DEFINE_DBUS_PROPERTY_INFO_EXTENDED_READABLE_L ("L3miss", "b", NM_DEVICE_VXLAN_L3MISS), - ), - ), - .legacy_property_changed = TRUE, -}; - static void nm_device_vxlan_class_init (NMDeviceVxlanClass *klass) { GObjectClass *object_class = G_OBJECT_CLASS (klass); - NMDBusObjectClass *dbus_object_class = NM_DBUS_OBJECT_CLASS (klass); NMDeviceClass *device_class = NM_DEVICE_CLASS (klass); NM_DEVICE_CLASS_DECLARE_TYPES (klass, NULL, NM_LINK_TYPE_VXLAN) object_class->get_property = get_property; - dbus_object_class->interface_infos = NM_DBUS_INTERFACE_INFOS (&interface_info_device_vxlan); - device_class->link_changed = link_changed; device_class->unrealize_notify = unrealize_notify; device_class->connection_type = NM_SETTING_VXLAN_SETTING_NAME; @@ -685,6 +657,10 @@ nm_device_vxlan_class_init (NMDeviceVxlanClass *klass) G_PARAM_STATIC_STRINGS); g_object_class_install_properties (object_class, _PROPERTY_ENUMS_LAST, obj_properties); + + nm_exported_object_class_add_interface (NM_EXPORTED_OBJECT_CLASS (klass), + NMDBUS_TYPE_DEVICE_VXLAN_SKELETON, + NULL); } /*****************************************************************************/ diff --git a/src/devices/nm-device-vxlan.h b/src/devices/nm-device-vxlan.h index 511b7156..6f0102dc 100644 --- a/src/devices/nm-device-vxlan.h +++ b/src/devices/nm-device-vxlan.h @@ -46,6 +46,9 @@ #define NM_DEVICE_VXLAN_L2MISS "l2miss" #define NM_DEVICE_VXLAN_L3MISS "l3miss" +/* defined in the parent class, but exposed on D-Bus by the subclass. */ +#define NM_DEVICE_VXLAN_PARENT NM_DEVICE_PARENT + typedef struct _NMDeviceVxlan NMDeviceVxlan; typedef struct _NMDeviceVxlanClass NMDeviceVxlanClass; diff --git a/src/devices/nm-device.c b/src/devices/nm-device.c index 815de29a..e79bc541 100644 --- a/src/devices/nm-device.c +++ b/src/devices/nm-device.c @@ -34,7 +34,6 @@ #include <arpa/inet.h> #include <fcntl.h> #include <linux/if_addr.h> -#include <linux/if_arp.h> #include <linux/rtnetlink.h> #include <linux/pkt_sched.h> @@ -49,7 +48,6 @@ #include "ndisc/nm-ndisc.h" #include "ndisc/nm-lndp-ndisc.h" #include "dhcp/nm-dhcp-manager.h" -#include "dhcp/nm-dhcp-utils.h" #include "nm-act-request.h" #include "nm-proxy-config.h" #include "nm-ip4-config.h" @@ -66,13 +64,13 @@ #include "nm-netns.h" #include "nm-dispatcher.h" #include "nm-config.h" -#include "c-list/src/c-list.h" +#include "nm-utils/c-list.h" #include "dns/nm-dns-manager.h" -#include "nm-acd-manager.h" #include "nm-core-internal.h" #include "systemd/nm-sd.h" #include "nm-lldp-listener.h" #include "nm-audit-manager.h" +#include "nm-arping-manager.h" #include "nm-connectivity.h" #include "nm-dbus-interface.h" #include "nm-device-vlan.h" @@ -80,6 +78,9 @@ #include "nm-device-logging.h" _LOG_DECLARE_SELF (NMDevice); +#include "introspection/org.freedesktop.NetworkManager.Device.h" +#include "introspection/org.freedesktop.NetworkManager.Device.Statistics.h" + /*****************************************************************************/ #define DEFAULT_AUTOCONNECT TRUE @@ -129,13 +130,13 @@ typedef struct { int ifindex; } DeleteOnDeactivateData; -typedef void (*AcdCallback) (NMDevice *, NMIP4Config **, gboolean); +typedef void (*ArpingCallback) (NMDevice *, NMIP4Config **, gboolean); typedef struct { - AcdCallback callback; + ArpingCallback callback; NMDevice *device; NMIP4Config **configs; -} AcdData; +} ArpingData; typedef enum { HW_ADDR_TYPE_UNSET = 0, @@ -151,24 +152,6 @@ typedef enum { FIREWALL_STATE_WAIT_IP_CONFIG, } FirewallState; -typedef struct { - NMIPConfig *orig; /* the original configuration applied to the device */ - NMIPConfig *current; /* configuration after external changes. NULL means - that the original configuration didn't change. */ -} AppliedConfig; - -struct _NMDeviceConnectivityHandle { - CList concheck_lst; - NMDevice *self; - NMDeviceConnectivityCallback callback; - gpointer user_data; - NMConnectivityCheckHandle *c_handle; - guint64 seq; - bool is_periodic:1; - bool is_periodic_bump:1; - bool is_periodic_bump_on_complete:1; -}; - /*****************************************************************************/ enum { @@ -182,7 +165,6 @@ enum { REMOVED, RECHECK_AUTO_ACTIVATE, RECHECK_ASSUME, - CONNECTIVITY_CHANGED, LAST_SIGNAL, }; static guint signals[LAST_SIGNAL] = { 0 }; @@ -247,18 +229,12 @@ typedef struct _NMDevicePrivate { NMDeviceStateReason reason; } queued_state; - union { - struct { - guint queued_ip_config_id_6; - guint queued_ip_config_id_4; - }; - guint queued_ip_config_id_x[2]; - }; - + guint queued_ip4_config_id; + guint queued_ip6_config_id; GSList *pending_actions; GSList *dad6_failed_addrs; - NMDBusTrackObjPath parent_device; + NMDevice *parent_device; char * udi; char * iface; /* may change, could be renamed by user */ @@ -282,13 +258,11 @@ typedef struct _NMDevicePrivate { bool queued_ip4_config_pending:1; bool queued_ip6_config_pending:1; - bool update_ip_config_completed_v4:1; - bool update_ip_config_completed_v6:1; - char * ip_iface; int ip_ifindex; NMDeviceType type; char * type_desc; + char * type_description; NMLinkType link_type; NMDeviceCapabilities capabilities; char * driver; @@ -323,7 +297,9 @@ typedef struct _NMDevicePrivate { NMActRequest * queued_act_request; bool queued_act_request_is_waiting_for_carrier:1; - NMDBusTrackObjPath act_request; + bool act_request_public:1; + NMActRequest *act_request; + gulong act_request_id; ActivationHandleData act_handle4; /* for layer2 and IPv4. */ ActivationHandleData act_handle6; guint recheck_assume_id; @@ -380,12 +356,6 @@ typedef struct _NMDevicePrivate { NMDeviceAutoconnectBlockedFlags autoconnect_blocked_flags:4; - bool is_enslaved:1; - bool master_ready_handled:1; - - bool ipv6ll_handle:1; /* TRUE if NM handles the device's IPv6LL address */ - bool ipv6ll_has:1; - /* Generic DHCP stuff */ char * dhcp_anycast_address; @@ -396,56 +366,17 @@ typedef struct _NMDevicePrivate { NMPacrunnerManager *pacrunner_manager; NMPacrunnerCallId *pacrunner_call_id; - /* IP configuration info. Combined config from VPN, settings, and device */ - union { - struct { - NMIP6Config *ip_config_6; - NMIP4Config *ip_config_4; - }; - NMIPConfig *ip_config_x[2]; - }; - + /* IP4 configuration info */ + NMIP4Config * ip4_config; /* Combined config from VPN, settings, and device */ union { const IpState ip4_state; IpState ip4_state_; }; - AppliedConfig dev_ip4_config; /* Config from DHCP, PPP, LLv4, etc */ - - /* config from the setting */ - union { - struct { - NMIP6Config *con_ip_config_6; - NMIP4Config *con_ip_config_4; - }; - NMIPConfig *con_ip_config_x[2]; - }; - - /* Stuff added outside NM */ - union { - struct { - NMIP6Config *ext_ip_config_6; - NMIP4Config *ext_ip_config_4; - }; - NMIPConfig *ext_ip_config_x[2]; - }; - - /* VPNs which use this device */ - union { - struct { - GSList *vpn_configs_6; - GSList *vpn_configs_4; - }; - GSList *vpn_configs_x[2]; - }; - - /* WWAN configuration */ - union { - struct { - AppliedConfig wwan_ip_config_6; - AppliedConfig wwan_ip_config_4; - }; - AppliedConfig wwan_ip_config_x[2]; - }; + NMIP4Config * con_ip4_config; /* config from the setting */ + NMIP4Config * dev_ip4_config; /* Config from DHCP, PPP, LLv4, etc */ + NMIP4Config * ext_ip4_config; /* Stuff added outside NM */ + NMIP4Config * wwan_ip4_config; /* WWAN configuration */ + GSList * vpn4_configs; /* VPNs which use this device */ bool v4_has_shadowed_routes; const char *ip4_rp_filter; @@ -465,8 +396,8 @@ typedef struct _NMDevicePrivate { guint timeout; guint watch; GPid pid; - char *binary; - char *address; + const char *binary; + const char *address; guint deadline; } gw_ping; @@ -487,17 +418,22 @@ typedef struct _NMDevicePrivate { /* IPv4 DAD stuff */ struct { GSList * dad_list; - NMAcdManager * announcing; - } acd; + NMArpingManager * announcing; + } arping; + /* IP6 configuration info */ + NMIP6Config * ip6_config; union { const IpState ip6_state; IpState ip6_state_; }; - AppliedConfig ac_ip6_config; /* config from IPv6 autoconfiguration */ + NMIP6Config * con_ip6_config; /* config from the setting */ + NMIP6Config * wwan_ip6_config; + NMIP6Config * ext_ip6_config; /* Stuff added outside NM */ NMIP6Config * ext_ip6_config_captured; /* Configuration captured from platform. */ + GSList * vpn6_configs; /* VPNs which use this device */ + bool nm_ipv6ll; /* TRUE if NM handles the device's IPv6LL address */ NMIP6Config * dad6_ip6_config; - struct in6_addr ipv6ll_addr; GHashTable * rt6_temporary_not_available; @@ -505,6 +441,8 @@ typedef struct _NMDevicePrivate { gulong ndisc_changed_id; gulong ndisc_timeout_id; NMSettingIP6ConfigPrivacy ndisc_use_tempaddr; + /* IP6 config from autoconf */ + NMIP6Config * ac_ip6_config; guint linklocal6_timeout_id; guint8 linklocal6_dad_counter; @@ -518,7 +456,7 @@ typedef struct _NMDevicePrivate { gulong prefix_sigid; NMDhcp6Config * config; /* IP6 config from DHCP */ - AppliedConfig ip6_config; + NMIP6Config * ip6_config; /* Event ID of the current IP6 config from DHCP */ char * event_id; guint needed_prefixes; @@ -530,6 +468,8 @@ typedef struct _NMDevicePrivate { /* master interface for bridge/bond/team slave */ NMDevice * master; + bool is_enslaved; + bool master_ready_handled; gulong master_ready_id; /* slave management */ @@ -542,26 +482,9 @@ typedef struct _NMDevicePrivate { NMNetns *netns; NMLldpListener *lldp_listener; - - NMConnectivity *concheck_mgr; - - /* if periodic checks are enabled, this is the source id for the next check. */ - guint concheck_p_cur_id; - - /* the currently configured max periodic interval. */ - guint concheck_p_max_interval; - - /* the current interval. If we are probing, the interval might be lower - * then the configured max interval. */ - guint concheck_p_cur_interval; - - /* the timestamp, when we last scheduled the timer concheck_p_cur_id with current interval - * concheck_p_cur_interval. */ - gint64 concheck_p_cur_basetime_ns; - NMConnectivityState connectivity_state; - - CList concheck_lst_head; + gulong concheck_periodic_id; + guint64 concheck_seq; guint check_delete_unrealized_id; @@ -574,35 +497,35 @@ typedef struct _NMDevicePrivate { } NMDevicePrivate; -G_DEFINE_ABSTRACT_TYPE (NMDevice, nm_device, NM_TYPE_DBUS_OBJECT) +G_DEFINE_ABSTRACT_TYPE (NMDevice, nm_device, NM_TYPE_EXPORTED_OBJECT) #define NM_DEVICE_GET_PRIVATE(self) _NM_GET_PRIVATE_PTR(self, NMDevice, NM_IS_DEVICE) /*****************************************************************************/ -static const NMDBusInterfaceInfoExtended interface_info_device; -static const GDBusSignalInfo signal_info_state_changed; - static void nm_device_set_proxy_config (NMDevice *self, const char *pac_url); -static gboolean update_ext_ip_config (NMDevice *self, int addr_family, gboolean intersect_configs); +static gboolean update_ext_ip_config (NMDevice *self, int addr_family, gboolean initial, gboolean intersect_configs); -static gboolean nm_device_set_ip_config (NMDevice *self, - int addr_family, - NMIPConfig *config, - gboolean commit, - GPtrArray *ip4_dev_route_blacklist); +static gboolean nm_device_set_ip4_config (NMDevice *self, + NMIP4Config *config, + gboolean commit, + GPtrArray *ip4_dev_route_blacklist); +static gboolean ip4_config_merge_and_apply (NMDevice *self, + gboolean commit); -static gboolean ip_config_merge_and_apply (NMDevice *self, - int addr_family, - gboolean commit); +static gboolean nm_device_set_ip6_config (NMDevice *self, + NMIP6Config *config, + gboolean commit); +static gboolean ip6_config_merge_and_apply (NMDevice *self, + gboolean commit); static gboolean nm_device_master_add_slave (NMDevice *self, NMDevice *slave, gboolean configure); static void nm_device_slave_notify_enslave (NMDevice *self, gboolean success); static void nm_device_slave_notify_release (NMDevice *self, NMDeviceStateReason reason); -static void addrconf6_start_with_link_ready (NMDevice *self); -static gboolean linklocal6_start (NMDevice *self); +static gboolean addrconf6_start_with_link_ready (NMDevice *self); +static NMActStageReturn linklocal6_start (NMDevice *self); static void _carrier_wait_check_queued_act_request (NMDevice *self); static gint64 _get_carrier_wait_ms (NMDevice *self); @@ -632,8 +555,6 @@ static void _set_mtu (NMDevice *self, guint32 mtu); static void _commit_mtu (NMDevice *self, const NMIP4Config *config); static void _cancel_activation (NMDevice *self); -static void concheck_update_state (NMDevice *self, NMConnectivityState state, gboolean is_periodic); - /*****************************************************************************/ NM_UTILS_LOOKUP_STR_DEFINE_STATIC (queued_state_to_string, NMDeviceState, @@ -758,16 +679,6 @@ nm_device_get_platform (NMDevice *self) return nm_netns_get_platform (nm_device_get_netns (self)); } -static NMConnectivity * -concheck_get_mgr (NMDevice *self) -{ - NMDevicePrivate *priv = NM_DEVICE_GET_PRIVATE (self); - - if (G_UNLIKELY (!priv->concheck_mgr)) - priv->concheck_mgr = g_object_ref (nm_connectivity_get ()); - return priv->concheck_mgr; -} - static NMIP4Config * _ip4_config_new (NMDevice *self) { @@ -782,105 +693,6 @@ _ip6_config_new (NMDevice *self) nm_device_get_ip_ifindex (self)); } -static NMIPConfig * -_ip_config_new (NMDevice *self, int addr_family) -{ - nm_assert_addr_family (addr_family); - - return addr_family == AF_INET - ? (gpointer) _ip4_config_new (self) - : (gpointer) _ip6_config_new (self); -} - -static void -applied_config_clear (AppliedConfig *config) -{ - g_clear_object (&config->current); - g_clear_object (&config->orig); -} - -static void -applied_config_init (AppliedConfig *config, gpointer ip_config) -{ - nm_g_object_ref (ip_config); - applied_config_clear (config); - config->orig = ip_config; -} - -static void -applied_config_init_new (AppliedConfig *config, NMDevice *self, int addr_family) -{ - gs_unref_object NMIPConfig *c = _ip_config_new (self, addr_family); - - applied_config_init (config, c); -} - -static NMIPConfig * -applied_config_get_current (AppliedConfig *config) -{ - return config->current ?: config->orig; -} - -static void -applied_config_add_address (AppliedConfig *config, const NMPlatformIPAddress *address) -{ - if (config->orig) - nm_ip_config_add_address (config->orig, address); - else - nm_assert (!config->current); - - if (config->current) - nm_ip_config_add_address (config->current, address); -} - -static void -applied_config_add_nameserver (AppliedConfig *config, const NMIPAddr *ns) -{ - if (config->orig) - nm_ip_config_add_nameserver (config->orig, ns); - else - nm_assert (!config->current); - - if (config->current) - nm_ip_config_add_nameserver (config->current, ns); -} - -static void -applied_config_add_search (AppliedConfig *config, const char *new) -{ - if (config->orig) - nm_ip_config_add_search (config->orig, new); - else - nm_assert (!config->current); - - if (config->current) - nm_ip_config_add_search (config->current, new); -} - -static void -applied_config_reset_searches (AppliedConfig *config) -{ - if (config->orig) - nm_ip_config_reset_searches (config->orig); - else - nm_assert (!config->current); - - if (config->current) - nm_ip_config_reset_searches (config->current); -} - -static void -applied_config_reset_nameservers (AppliedConfig *config) -{ - if (config->orig) - nm_ip_config_reset_nameservers (config->orig); - else - nm_assert (!config->current); - - if (config->current) - nm_ip_config_reset_nameservers (config->current); -} - /*****************************************************************************/ NM_UTILS_LOOKUP_STR_DEFINE_STATIC (_sys_iface_state_to_str, NMDeviceSysIfaceState, @@ -1010,18 +822,29 @@ nm_device_assume_state_reset (NMDevice *self) /*****************************************************************************/ static void -init_ip_config_dns_priority (NMDevice *self, NMIPConfig *config) +init_ip4_config_dns_priority (NMDevice *self, NMIP4Config *config) { gs_free char *value = NULL; gint priority; value = nm_config_data_get_connection_default (NM_CONFIG_GET_DATA, - (nm_ip_config_get_addr_family (config) == AF_INET) - ? "ipv4.dns-priority" - : "ipv6.dns-priority", + "ipv4.dns-priority", self); priority = _nm_utils_ascii_str_to_int64 (value, 10, G_MININT, G_MAXINT, 0); - nm_ip_config_set_dns_priority (config, priority ?: NM_DNS_PRIORITY_DEFAULT_NORMAL); + nm_ip4_config_set_dns_priority (config, priority ?: NM_DNS_PRIORITY_DEFAULT_NORMAL); +} + +static void +init_ip6_config_dns_priority (NMDevice *self, NMIP6Config *config) +{ + gs_free char *value = NULL; + gint priority; + + value = nm_config_data_get_connection_default (NM_CONFIG_GET_DATA, + "ipv6.dns-priority", + self); + priority = _nm_utils_ascii_str_to_int64 (value, 10, G_MININT, G_MAXINT, 0); + nm_ip6_config_set_dns_priority (config, priority ?: NM_DNS_PRIORITY_DEFAULT_NORMAL); } /*****************************************************************************/ @@ -1060,11 +883,6 @@ nm_device_ipv4_sysctl_get_effective_uint32 (NMDevice *self, const char *property if (!nm_device_get_ip_ifindex (self)) return fallback; - /* for this kind of sysctl (e.g. "rp_filter"), kernel effectively uses the - * MAX of the per-device value and the "all" value. - * - * Also do that, by reading both sysctls and return the maximum. */ - v = nm_platform_sysctl_get_int_checked (nm_device_get_platform (self), NMP_SYSCTL_PATHID_ABSOLUTE (nm_utils_sysctl_ip_conf_path (AF_INET, buf, @@ -1230,7 +1048,7 @@ _set_ip_state (NMDevice *self, int addr_family, IpState new_state) p = (addr_family == AF_INET) ? &priv->ip4_state_ - : &priv->ip6_state_; + : &priv->ip6_state_; if (*p != new_state) { _LOGT (LOGD_DEVICE, "ip%c-state: set to %d (%s)", @@ -1271,26 +1089,28 @@ nm_device_get_iface (NMDevice *self) } gboolean -nm_device_take_over_link (NMDevice *self, int ifindex, char **old_name) +nm_device_take_over_link (NMDevice *self, const char *ifname, gboolean *renamed) { NMDevicePrivate *priv = NM_DEVICE_GET_PRIVATE (self); const NMPlatformLink *plink; NMPlatform *platform; gboolean up, success = TRUE; - gs_free char *name = NULL; + int ifindex; g_return_val_if_fail (priv->ifindex <= 0, FALSE); + g_return_val_if_fail (ifname, FALSE); - NM_SET_OUT (old_name, NULL); + NM_SET_OUT (renamed, FALSE); platform = nm_device_get_platform (self); - plink = nm_platform_link_get (platform, ifindex); + plink = nm_platform_link_get_by_ifname (platform, ifname); if (!plink) return FALSE; - if (!nm_streq (plink->name, nm_device_get_iface (self))) { + ifindex = plink->ifindex; + + if (!nm_streq (ifname, nm_device_get_iface (self))) { up = NM_FLAGS_HAS (plink->n_ifi_flags, IFF_UP); - name = g_strdup (plink->name); /* Rename the link to the device ifname */ if (up) @@ -1299,8 +1119,7 @@ nm_device_take_over_link (NMDevice *self, int ifindex, char **old_name) if (up) nm_platform_link_set_up (platform, ifindex, NULL); - if (success) - NM_SET_OUT (old_name, g_steal_pointer (&name)); + NM_SET_OUT (renamed, success); } if (success) { @@ -1372,102 +1191,71 @@ nm_device_get_ip_ifindex (const NMDevice *self) return priv->ip_iface ? priv->ip_ifindex : priv->ifindex; } -static void -_set_ip_ifindex (NMDevice *self, - int ifindex, - const char *ifname) +/** + * nm_device_set_ip_iface: + * @self: the #NMDevice + * @iface: the new IP interface name + * + * Updates the IP interface name and possibly the ifindex. + * + * Returns: %TRUE if the anything (name or ifindex) changed, %FALSE if nothing + * changed. + */ +gboolean +nm_device_set_ip_iface (NMDevice *self, const char *iface) { - NMDevicePrivate *priv = NM_DEVICE_GET_PRIVATE (self); - NMPlatform *platform; - gboolean eq_name; - - /* normalize arguments */ - if (ifindex <= 0) { - ifindex = 0; - ifname = NULL; - } - - eq_name = nm_streq0 (priv->ip_iface, ifname); + NMDevicePrivate *priv; + int ifindex; - if ( eq_name - && priv->ip_ifindex == ifindex) - return; + g_return_val_if_fail (NM_IS_DEVICE (self), FALSE); - _LOGD (LOGD_DEVICE, "ip-ifindex: update ip-interface to %s%s%s, ifindex %d", - NM_PRINT_FMT_QUOTE_STRING (ifname), - ifindex); + priv = NM_DEVICE_GET_PRIVATE (self); + if (nm_streq0 (iface, priv->ip_iface)) { + if (!iface) + return FALSE; + ifindex = nm_platform_if_nametoindex (nm_device_get_platform (self), iface); + if ( ifindex <= 0 + || priv->ip_ifindex == ifindex) + return FALSE; - priv->ip_ifindex = ifindex; - if (!eq_name) { + priv->ip_ifindex = ifindex; + _LOGD (LOGD_DEVICE, "ip-ifname: update ifindex for ifname '%s': %d", iface, priv->ip_ifindex); + } else { g_free (priv->ip_iface); - priv->ip_iface = g_strdup (ifname); - _notify (self, PROP_IP_IFACE); + priv->ip_iface = g_strdup (iface); + + if (iface) { + /* The @iface name is not in sync with the platform cache. + * So, there is no point asking the platform cache to resolve + * the ifindex. Instead, we can only hope that the interface + * with this name still exists and we resolve the ifindex + * anew. + */ + priv->ip_ifindex = nm_platform_if_nametoindex (nm_device_get_platform (self), iface); + if (priv->ip_ifindex > 0) + _LOGD (LOGD_DEVICE, "ip-ifname: set ifname '%s', ifindex %d", iface, priv->ip_ifindex); + else + _LOGW (LOGD_DEVICE, "ip-ifname: set ifname '%s', unknown ifindex", iface); + } else { + priv->ip_ifindex = 0; + _LOGD (LOGD_DEVICE, "ip-ifname: clear ifname"); + } } if (priv->ip_ifindex > 0) { - platform = nm_device_get_platform (self); - - nm_platform_process_events_ensure_link (platform, - priv->ip_ifindex, - priv->ip_iface); - - if (nm_platform_check_kernel_support (platform, + if (nm_platform_check_kernel_support (nm_device_get_platform (self), NM_PLATFORM_KERNEL_SUPPORT_USER_IPV6LL)) - nm_platform_link_set_user_ipv6ll_enabled (platform, priv->ip_ifindex, TRUE); + nm_platform_link_set_user_ipv6ll_enabled (nm_device_get_platform (self), priv->ip_ifindex, TRUE); - if (!nm_platform_link_is_up (platform, priv->ip_ifindex)) - nm_platform_link_set_up (platform, priv->ip_ifindex, NULL); + if (!nm_platform_link_is_up (nm_device_get_platform (self), priv->ip_ifindex)) + nm_platform_link_set_up (nm_device_get_platform (self), priv->ip_ifindex, NULL); } /* We don't care about any saved values from the old iface */ g_hash_table_remove_all (priv->ip6_saved_properties); -} -gboolean -nm_device_set_ip_ifindex (NMDevice *self, int ifindex) -{ - char ifname_buf[IFNAMSIZ]; - const char *ifname = NULL; - - g_return_val_if_fail (NM_IS_DEVICE (self), FALSE); - g_return_val_if_fail (nm_device_is_activating (self), FALSE); - - if (ifindex > 0) { - ifname = nm_platform_if_indextoname (nm_device_get_platform (self), ifindex, ifname_buf); - if (!ifname) - _LOGW (LOGD_DEVICE, "ip-ifindex: ifindex %d not found", ifindex); - } - - _set_ip_ifindex (self, ifindex, ifname); - return ifindex > 0; -} - -/** - * nm_device_set_ip_iface: - * @self: the #NMDevice - * @ifname: the new IP interface name - * - * Updates the IP interface name and possibly the ifindex. - * - * Returns: %TRUE if an interface with name @ifname exists, - * and %FALSE, if @ifname is %NULL or no such interface exists. - */ -gboolean -nm_device_set_ip_iface (NMDevice *self, const char *ifname) -{ - int ifindex = 0; - - g_return_val_if_fail (NM_IS_DEVICE (self), FALSE); - g_return_val_if_fail (nm_device_is_activating (self), FALSE); - - if (ifname) { - ifindex = nm_platform_if_nametoindex (nm_device_get_platform (self), ifname); - if (ifindex <= 0) - _LOGW (LOGD_DEVICE, "ip-ifindex: ifname %s not found", ifname); - } - - _set_ip_ifindex (self, ifindex, ifname); - return ifindex > 0; + _notify (self, PROP_IP_IFACE); + return TRUE; } static gboolean @@ -1514,9 +1302,12 @@ nm_device_parent_get_ifindex (NMDevice *self) NMDevice * nm_device_parent_get_device (NMDevice *self) { + NMDevicePrivate *priv; + g_return_val_if_fail (NM_IS_DEVICE (self), NULL); - return NM_DEVICE_GET_PRIVATE (self)->parent_device.obj; + priv = NM_DEVICE_GET_PRIVATE (self); + return priv->parent_device; } static void @@ -1538,7 +1329,7 @@ _parent_set_ifindex (NMDevice *self, NMDevice *parent_device; gboolean changed = FALSE; int old_ifindex; - gs_unref_object NMDevice *old_device = NULL; + NMDevice *old_device; g_return_val_if_fail (NM_IS_DEVICE (self), FALSE); @@ -1548,15 +1339,16 @@ _parent_set_ifindex (NMDevice *self, parent_ifindex = 0; old_ifindex = priv->parent_ifindex; + old_device = priv->parent_device; if (priv->parent_ifindex == parent_ifindex) { if (parent_ifindex > 0) { if ( !force_check - && priv->parent_device.obj - && nm_device_get_ifindex (priv->parent_device.obj) == parent_ifindex) + && priv->parent_device + && nm_device_get_ifindex (priv->parent_device) == parent_ifindex) return FALSE; } else { - if (!priv->parent_device.obj) + if (!priv->parent_device) return FALSE; } } else { @@ -1571,23 +1363,24 @@ _parent_set_ifindex (NMDevice *self, } else parent_device = NULL; - if (parent_device != priv->parent_device.obj) { - old_device = nm_g_object_ref (priv->parent_device.obj); - nm_dbus_track_obj_path_set (&priv->parent_device, parent_device, TRUE); + if (parent_device != priv->parent_device) { + priv->parent_device = parent_device; changed = TRUE; } if (changed) { if (priv->parent_ifindex <= 0) _LOGD (LOGD_DEVICE, "parent: clear"); - else if (!priv->parent_device.obj) + else if (!priv->parent_device) _LOGD (LOGD_DEVICE, "parent: ifindex %d, no device", priv->parent_ifindex); else { _LOGD (LOGD_DEVICE, "parent: ifindex %d, device %p, %s", priv->parent_ifindex, - priv->parent_device.obj, nm_device_get_iface (priv->parent_device.obj)); + priv->parent_device, nm_device_get_iface (priv->parent_device)); } - NM_DEVICE_GET_CLASS (self)->parent_changed_notify (self, old_ifindex, old_device, priv->parent_ifindex, priv->parent_device.obj); + NM_DEVICE_GET_CLASS (self)->parent_changed_notify (self, old_ifindex, old_device, priv->parent_ifindex, priv->parent_device); + + _notify (self, PROP_PARENT); } return changed; } @@ -1612,7 +1405,7 @@ nm_device_parent_notify_changed (NMDevice *self, priv = NM_DEVICE_GET_PRIVATE (self); if (priv->parent_ifindex > 0) { - if ( priv->parent_device.obj == change_candidate + if ( priv->parent_device == change_candidate || priv->parent_ifindex == nm_device_get_ifindex (change_candidate)) return _parent_set_ifindex (self, priv->parent_ifindex, device_removed); } @@ -1918,13 +1711,16 @@ nm_device_get_route_metric_default (NMDeviceType device_type) static gboolean default_route_metric_penalty_detect (NMDevice *self) { +#if WITH_CONCHECK NMDevicePrivate *priv = NM_DEVICE_GET_PRIVATE (self); /* currently we don't differentiate between IPv4 and IPv6 when detecting * connectivity. */ if ( priv->connectivity_state != NM_CONNECTIVITY_FULL - && nm_connectivity_check_enabled (concheck_get_mgr (self))) + && nm_connectivity_check_enabled (nm_connectivity_get ())) { return TRUE; + } +#endif return FALSE; } @@ -1992,34 +1788,6 @@ out: return nm_utils_ip_route_metric_normalize (addr_family, route_metric); } -static NMSettingConnectionMdns -_get_mdns (NMDevice *self) -{ - NMConnection *connection; - NMSettingConnectionMdns mdns = NM_SETTING_CONNECTION_MDNS_DEFAULT; - - g_return_val_if_fail (NM_IS_DEVICE (self), NM_SETTING_CONNECTION_MDNS_DEFAULT); - - connection = nm_device_get_applied_connection (self); - if (connection) - mdns = nm_setting_connection_get_mdns (nm_connection_get_setting_connection (connection)); - - if (mdns == NM_SETTING_CONNECTION_MDNS_DEFAULT) { - gs_free char *value = NULL; - - value = nm_config_data_get_connection_default (NM_CONFIG_GET_DATA, - "connection.mdns", - self); - mdns = _nm_utils_ascii_str_to_int64 (value, - 10, - NM_SETTING_CONNECTION_MDNS_NO, - NM_SETTING_CONNECTION_MDNS_YES, - NM_SETTING_CONNECTION_MDNS_DEFAULT); - } - - return mdns; -} - guint32 nm_device_get_route_table (NMDevice *self, int addr_family, @@ -2096,12 +1864,12 @@ nm_device_get_best_default_route (NMDevice *self, switch (addr_family) { case AF_INET: - return priv->ip_config_4 ? nm_ip4_config_best_default_route_get (priv->ip_config_4) : NULL; + return priv->ip4_config ? nm_ip4_config_best_default_route_get (priv->ip4_config) : NULL; case AF_INET6: - return priv->ip_config_6 ? nm_ip6_config_best_default_route_get (priv->ip_config_6) : NULL; + return priv->ip6_config ? nm_ip6_config_best_default_route_get (priv->ip6_config) : NULL; case AF_UNSPEC: - return (priv->ip_config_4 ? nm_ip4_config_best_default_route_get (priv->ip_config_4) : NULL) - ?: (priv->ip_config_6 ? nm_ip6_config_best_default_route_get (priv->ip_config_6) : NULL); + return (priv->ip4_config ? nm_ip4_config_best_default_route_get (priv->ip4_config) : NULL) + ?: (priv->ip6_config ? nm_ip6_config_best_default_route_get (priv->ip6_config) : NULL); default: g_return_val_if_reached (NULL); } @@ -2129,23 +1897,18 @@ nm_device_get_type_description (NMDevice *self) static const char * get_type_description (NMDevice *self) { - NMDeviceClass *klass; - - nm_assert (NM_IS_DEVICE (self)); + NMDevicePrivate *priv = NM_DEVICE_GET_PRIVATE (self); - klass = NM_DEVICE_GET_CLASS (self); - if (G_UNLIKELY (!klass->default_type_description)) { + if (!priv->type_description) { const char *typename; - gs_free char *s = NULL; typename = G_OBJECT_TYPE_NAME (self); if (g_str_has_prefix (typename, "NMDevice")) typename += 8; - s = g_ascii_strdown (typename, -1); - klass->default_type_description = g_intern_string (s); + priv->type_description = g_ascii_strdown (typename, -1); } - return klass->default_type_description; + return priv->type_description; } gboolean @@ -2159,7 +1922,7 @@ nm_device_get_act_request (NMDevice *self) { g_return_val_if_fail (NM_IS_DEVICE (self), NULL); - return NM_DEVICE_GET_PRIVATE (self)->act_request.obj; + return NM_DEVICE_GET_PRIVATE (self)->act_request; } NMSettingsConnection * @@ -2167,7 +1930,7 @@ nm_device_get_settings_connection (NMDevice *self) { NMDevicePrivate *priv = NM_DEVICE_GET_PRIVATE (self); - return priv->act_request.obj ? nm_act_request_get_settings_connection (priv->act_request.obj) : NULL; + return priv->act_request ? nm_act_request_get_settings_connection (priv->act_request) : NULL; } NMConnection * @@ -2179,7 +1942,7 @@ nm_device_get_applied_connection (NMDevice *self) priv = NM_DEVICE_GET_PRIVATE (self); - return priv->act_request.obj ? nm_act_request_get_applied_connection (priv->act_request.obj) : NULL; + return priv->act_request ? nm_act_request_get_applied_connection (priv->act_request) : NULL; } gboolean @@ -2187,10 +1950,10 @@ nm_device_has_unmodified_applied_connection (NMDevice *self, NMSettingCompareFla { NMDevicePrivate *priv = NM_DEVICE_GET_PRIVATE (self); - if (!priv->act_request.obj) + if (!priv->act_request) return FALSE; - return nm_active_connection_has_unmodified_applied_connection ((NMActiveConnection *) priv->act_request.obj, compare_flags); + return nm_active_connection_has_unmodified_applied_connection ((NMActiveConnection *) priv->act_request, compare_flags); } NMSetting * @@ -2218,549 +1981,127 @@ nm_device_get_physical_port_id (NMDevice *self) /*****************************************************************************/ -typedef enum { - CONCHECK_SCHEDULE_UPDATE_INTERVAL, - CONCHECK_SCHEDULE_CHECK_EXTERNAL, - CONCHECK_SCHEDULE_CHECK_PERIODIC, - CONCHECK_SCHEDULE_RETURNED_MIN, - CONCHECK_SCHEDULE_RETURNED_BUMP, - CONCHECK_SCHEDULE_RETURNED_MAX, -} ConcheckScheduleMode; - -static NMDeviceConnectivityHandle *concheck_start (NMDevice *self, - NMDeviceConnectivityCallback callback, - gpointer user_data, - gboolean is_periodic); - -static void concheck_periodic_schedule_set (NMDevice *self, - ConcheckScheduleMode mode); - -static gboolean -concheck_periodic_timeout_cb (gpointer user_data) -{ - NMDevice *self = user_data; - - _LOGt (LOGD_CONCHECK, "connectivity: periodic timeout"); - concheck_periodic_schedule_set (self, CONCHECK_SCHEDULE_CHECK_PERIODIC); - return G_SOURCE_REMOVE; -} - -static gboolean -concheck_is_possible (NMDevice *self) -{ - NMDevicePrivate *priv = NM_DEVICE_GET_PRIVATE (self); - - if ( !nm_device_is_real (self) - || NM_FLAGS_HAS (priv->unmanaged_flags, NM_UNMANAGED_LOOPBACK)) - return FALSE; - - /* we enable periodic checks for every device state (except UNKNOWN). Especially with - * unmanaged devices, it is interesting to know whether we have connectivity on that device. */ - if (priv->state == NM_DEVICE_STATE_UNKNOWN) - return FALSE; - - return TRUE; -} - -static gboolean -concheck_periodic_schedule_do (NMDevice *self, gint64 interval_ns) -{ - NMDevicePrivate *priv = NM_DEVICE_GET_PRIVATE (self); - gboolean periodic_check_disabled = FALSE; - - /* we always cancel whatever was pending. */ - if (nm_clear_g_source (&priv->concheck_p_cur_id)) - periodic_check_disabled = TRUE; - - if (priv->concheck_p_max_interval == 0) { - /* periodic checks are disabled */ - goto out; - } - - nm_assert (interval_ns >= 0); - - if (!concheck_is_possible (self)) - goto out; - - _LOGT (LOGD_CONCHECK, "connectivity: periodic-check: %sscheduled in %u milliseconds (%u seconds interval)", - periodic_check_disabled ? "re-" : "", - (guint) (interval_ns / NM_UTILS_NS_PER_MSEC), - priv->concheck_p_cur_interval); - - nm_assert (priv->concheck_p_cur_interval > 0); - priv->concheck_p_cur_id = g_timeout_add (interval_ns / NM_UTILS_NS_PER_MSEC, - concheck_periodic_timeout_cb, - self); - return TRUE; -out: - if (periodic_check_disabled) - _LOGT (LOGD_CONCHECK, "connectivity: periodic-check: unscheduled"); - return FALSE; -} - -#define CONCHECK_P_PROBE_INTERVAL 1 - -static void -concheck_periodic_schedule_set (NMDevice *self, - ConcheckScheduleMode mode) -{ - NMDevicePrivate *priv = NM_DEVICE_GET_PRIVATE (self); - gint64 new_expiry, exp_expiry, cur_expiry, tdiff; - gint64 now_ns = 0; - - if (priv->concheck_p_max_interval == 0) { - /* periodic check is disabled. Nothing to do. */ - return; - } - - if (!priv->concheck_p_cur_id) { - /* we currently don't have a timeout scheduled. No need to reschedule - * another one... */ - if (mode == CONCHECK_SCHEDULE_UPDATE_INTERVAL) { - /* ... unless, we are initalizing. In this case, setup the current current - * interval and schedule a perform a check right away. */ - priv->concheck_p_cur_interval = NM_MIN (priv->concheck_p_max_interval, CONCHECK_P_PROBE_INTERVAL); - priv->concheck_p_cur_basetime_ns = nm_utils_get_monotonic_timestamp_ns_cached (&now_ns); - if (concheck_periodic_schedule_do (self, priv->concheck_p_cur_interval * NM_UTILS_NS_PER_SECOND)) - concheck_start (self, NULL, NULL, TRUE); - } - return; - } - - switch (mode) { - case CONCHECK_SCHEDULE_UPDATE_INTERVAL: - /* called with "UPDATE_INTERVAL" and already have a concheck_p_cur_id scheduled. */ - - nm_assert (priv->concheck_p_max_interval > 0); - nm_assert (priv->concheck_p_cur_interval > 0); - - if (priv->concheck_p_cur_interval <= priv->concheck_p_max_interval) { - /* we currently have a shorter interval set, than what we now have. Either, - * because we are probing, or because the previous max interval was shorter. - * - * Either way, the current timer is set just fine. Nothing to do, we will - * probe our way up. */ - return; - } - - cur_expiry = priv->concheck_p_cur_basetime_ns + (priv->concheck_p_max_interval * NM_UTILS_NS_PER_SECOND); - nm_utils_get_monotonic_timestamp_ns_cached (&now_ns); - - priv->concheck_p_cur_interval = priv->concheck_p_max_interval; - if (cur_expiry <= now_ns) { - /* Since the last time we scheduled a periodic check, already more than the - * new max_interval passed. We need to start a check right away (and - * schedule a timeout in cur-interval in the future). */ - priv->concheck_p_cur_basetime_ns = now_ns; - if (concheck_periodic_schedule_do (self, priv->concheck_p_cur_interval * NM_UTILS_NS_PER_SECOND)) - concheck_start (self, NULL, NULL, TRUE); - } else { - /* we are reducing the max-interval to a shorter interval that we have currently - * scheduled (with cur_interval). - * - * However, since the last time we scheduled the check, not even the new max-interval - * expired. All we need to do, is reschedule the timer to expire sooner. The cur_basetime - * is unchanged. */ - concheck_periodic_schedule_do (self, cur_expiry - now_ns); - } - return; - - case CONCHECK_SCHEDULE_CHECK_EXTERNAL: - /* a external connectivity check delays our periodic check. We reset the counter. */ - priv->concheck_p_cur_basetime_ns = nm_utils_get_monotonic_timestamp_ns_cached (&now_ns); - concheck_periodic_schedule_do (self, priv->concheck_p_cur_interval * NM_UTILS_NS_PER_SECOND); - return; - - case CONCHECK_SCHEDULE_CHECK_PERIODIC: - { - gboolean any_periodic_pending; - NMDeviceConnectivityHandle *handle; - guint old_interval = priv->concheck_p_cur_interval; - - any_periodic_pending = FALSE; - c_list_for_each_entry (handle, &priv->concheck_lst_head, concheck_lst) { - if (handle->is_periodic_bump) { - handle->is_periodic_bump = FALSE; - handle->is_periodic_bump_on_complete = FALSE; - any_periodic_pending = TRUE; - } - } - if (any_periodic_pending) { - /* we reached a timeout to schedule a new periodic request, however we still - * have period requests pending that didn't complete yet. We need to bump the - * interval already. */ - priv->concheck_p_cur_interval = NM_MIN (old_interval * 2, priv->concheck_p_max_interval); - } - - /* we just reached a timeout. The expected expiry (exp_expiry) should be - * pretty close to now_ns. - * - * We want to reschedule the timeout at exp_expiry (aka now) + cur_interval. */ - nm_utils_get_monotonic_timestamp_ns_cached (&now_ns); - exp_expiry = priv->concheck_p_cur_basetime_ns + (old_interval * NM_UTILS_NS_PER_SECOND); - new_expiry = exp_expiry + (priv->concheck_p_cur_interval * NM_UTILS_NS_PER_SECOND); - tdiff = NM_MAX (new_expiry - now_ns, 0); - priv->concheck_p_cur_basetime_ns = (now_ns + tdiff) - (priv->concheck_p_cur_interval * NM_UTILS_NS_PER_SECOND); - concheck_periodic_schedule_do (self, tdiff); - handle = concheck_start (self, NULL, NULL, TRUE); - if (old_interval != priv->concheck_p_cur_interval) { - /* we just bumped the interval already when scheduling this check. - * When the handle returns, don't bump a second time. - * - * But if we reach the timeout again before the handle returns (this - * code here) we will still bump the interval. */ - handle->is_periodic_bump_on_complete = FALSE; - } - return; - } - - /* we just got an event that we lost connectivity (that is, concheck returned). We reset - * the interval to min/max or increase the probe interval (bump). */ - case CONCHECK_SCHEDULE_RETURNED_MIN: - priv->concheck_p_cur_interval = NM_MIN (priv->concheck_p_max_interval, CONCHECK_P_PROBE_INTERVAL); - break; - case CONCHECK_SCHEDULE_RETURNED_MAX: - priv->concheck_p_cur_interval = priv->concheck_p_max_interval; - break; - case CONCHECK_SCHEDULE_RETURNED_BUMP: - priv->concheck_p_cur_interval = NM_MIN (priv->concheck_p_cur_interval * 2, priv->concheck_p_max_interval); - break; - } - - /* we are here, because we returned from a connectivity check and adjust the current interval. - * - * But note that we calculate the new timeout based on the time when we scheduled the - * last check, instead of counting from now. The reaons 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_p_cur_basetime_ns + (priv->concheck_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_p_cur_basetime_ns = now_ns + tdiff - (priv->concheck_p_cur_interval * NM_UTILS_NS_PER_SECOND); - concheck_periodic_schedule_do (self, tdiff); -} - -void -nm_device_check_connectivity_update_interval (NMDevice *self) -{ - NMDevicePrivate *priv = NM_DEVICE_GET_PRIVATE (self); - guint new_interval; - - new_interval = nm_connectivity_get_interval (concheck_get_mgr (self)); - - new_interval = NM_MIN (new_interval, 7 *24 * 3600); - - if (new_interval != priv->concheck_p_max_interval) { - _LOGT (LOGD_CONCHECK, "connectivity: periodic-check: set interval to %u seconds", new_interval); - priv->concheck_p_max_interval = new_interval; - } - - if (!new_interval) { - /* this will cancel any potentially pending timeout. */ - concheck_periodic_schedule_do (self, 0); - - /* also update the fake connectivity state. */ - concheck_update_state (self, NM_CONNECTIVITY_FAKE, TRUE); - return; - } - - concheck_periodic_schedule_set (self, CONCHECK_SCHEDULE_UPDATE_INTERVAL); -} - static void -concheck_update_state (NMDevice *self, NMConnectivityState state, gboolean allow_periodic_bump) +update_connectivity_state (NMDevice *self, NMConnectivityState state) { NMDevicePrivate *priv = NM_DEVICE_GET_PRIVATE (self); - /* @state is a result of the connectivity check. We only expect a precise - * number of possible values. */ - nm_assert (NM_IN_SET (state, NM_CONNECTIVITY_LIMITED, - NM_CONNECTIVITY_PORTAL, - NM_CONNECTIVITY_FULL, - NM_CONNECTIVITY_FAKE, - NM_CONNECTIVITY_ERROR)); - - if (state == NM_CONNECTIVITY_ERROR) { - /* on error, we don't change the current connectivity state, - * except making UNKNOWN to NONE. */ - state = priv->connectivity_state; - if (state == NM_CONNECTIVITY_UNKNOWN) - state = NM_CONNECTIVITY_NONE; - } else if (state == NM_CONNECTIVITY_FAKE) { - /* If the connectivity check is disabled and we obtain a fake - * result, make an optimistic guess. */ + /* If the connectivity check is disabled, make an optimistic guess. */ + if (state == NM_CONNECTIVITY_UNKNOWN) { if (priv->state == NM_DEVICE_STATE_ACTIVATED) { - /* FIXME: the fake connectivity state depends on the availablility of - * a default route. However, we have no mechanism that rechecks the - * value if a device route appears/disappears after the device - * was activated. */ if (nm_device_get_best_default_route (self, AF_UNSPEC)) state = NM_CONNECTIVITY_FULL; else state = NM_CONNECTIVITY_LIMITED; - } else + } else { state = NM_CONNECTIVITY_NONE; + } } - if (priv->connectivity_state == state) { - /* we got a connectivty update, but the state didn't change. If we were probing, - * we bump the probe frequency. */ - if (allow_periodic_bump) - concheck_periodic_schedule_set (self, CONCHECK_SCHEDULE_RETURNED_BUMP); - return; - } - /* we need to update the probe interval before emitting signals. Emitting - * a signal might call back into NMDevice and change the probe settings. - * So, do that first. */ - if (state == NM_CONNECTIVITY_FULL) { - /* we reached full connectivity state. Stop probing by setting the - * interval to the max. */ - concheck_periodic_schedule_set (self, CONCHECK_SCHEDULE_RETURNED_MAX); - } else if (priv->connectivity_state == NM_CONNECTIVITY_FULL) { - /* we are about to loose connectivity. (re)start probing by setting - * the timeout interval to the min. */ - concheck_periodic_schedule_set (self, CONCHECK_SCHEDULE_RETURNED_MIN); - } else { - if (allow_periodic_bump) - concheck_periodic_schedule_set (self, CONCHECK_SCHEDULE_RETURNED_BUMP); - } - - _LOGD (LOGD_CONCHECK, "connectivity state changed from %s to %s", - nm_connectivity_state_to_string (priv->connectivity_state), - nm_connectivity_state_to_string (state)); - priv->connectivity_state = state; - - _notify (self, PROP_CONNECTIVITY); - g_signal_emit (self, signals[CONNECTIVITY_CHANGED], 0); + if (priv->connectivity_state != state) { +#if WITH_CONCHECK + _LOGD (LOGD_CONCHECK, "state changed from %s to %s", + nm_connectivity_state_to_string (priv->connectivity_state), + nm_connectivity_state_to_string (state)); +#endif + priv->connectivity_state = state; + _notify (self, PROP_CONNECTIVITY); - if ( priv->state == NM_DEVICE_STATE_ACTIVATED - && !nm_device_sys_iface_state_is_external (self)) { - if ( nm_device_get_best_default_route (self, AF_INET) - && !ip_config_merge_and_apply (self, AF_INET, TRUE)) - _LOGW (LOGD_IP4, "Failed to update IPv4 route metric"); - if ( nm_device_get_best_default_route (self, AF_INET6) - && !ip_config_merge_and_apply (self, AF_INET6, TRUE)) - _LOGW (LOGD_IP6, "Failed to update IPv6 route metric"); + if ( priv->state == NM_DEVICE_STATE_ACTIVATED + && !nm_device_sys_iface_state_is_external (self)) { + if ( nm_device_get_best_default_route (self, AF_INET) + && !ip4_config_merge_and_apply (self, TRUE)) + _LOGW (LOGD_IP4, "Failed to update IPv4 route metric"); + if ( nm_device_get_best_default_route (self, AF_INET6) + && !ip6_config_merge_and_apply (self, TRUE)) + _LOGW (LOGD_IP6, "Failed to update IPv6 route metric"); + } } } +typedef struct { + NMDevice *self; + NMDeviceConnectivityCallback callback; + gpointer user_data; + guint64 seq; +} ConnectivityCheckData; + static void -concheck_handle_complete (NMDeviceConnectivityHandle *handle, - GError *error) +concheck_done (ConnectivityCheckData *data) { - /* The moment we invoke the callback, we unlink it. It signals - * that @handle is handled -- as far as the callee of callback - * is concerned. */ - c_list_unlink (&handle->concheck_lst); - - if (handle->c_handle) - nm_connectivity_check_cancel (handle->c_handle); - - if (handle->callback) { - handle->callback (handle->self, - handle, - NM_DEVICE_GET_PRIVATE (handle->self)->connectivity_state, - error, - handle->user_data); - } + NMDevice *self = data->self; + NMDevicePrivate *priv = NM_DEVICE_GET_PRIVATE (self); - g_slice_free (NMDeviceConnectivityHandle, handle); + /* The unsolicited connectivity checks don't hook a callback. */ + if (data->callback) + data->callback (data->self, priv->connectivity_state, data->user_data); + g_object_unref (data->self); + g_slice_free (ConnectivityCheckData, data); } +#if WITH_CONCHECK static void -concheck_cb (NMConnectivity *connectivity, - NMConnectivityCheckHandle *c_handle, - NMConnectivityState state, - GError *error, - gpointer user_data) +concheck_cb (GObject *source_object, GAsyncResult *result, gpointer user_data) { - _nm_unused gs_unref_object NMDevice *self_keep_alive = NULL; - NMDevice *self; - NMDevicePrivate *priv; - NMDeviceConnectivityHandle *handle; - NMDeviceConnectivityHandle *other_handle; - gboolean handle_is_alive; - gboolean allow_periodic_bump; - gboolean any_periodic_before; - gboolean any_periodic_after; - guint64 seq; - - handle = user_data; - nm_assert (handle->c_handle == c_handle); - nm_assert (NM_IS_DEVICE (handle->self)); - - handle->c_handle = NULL; - self = handle->self; - - if (nm_utils_error_is_cancelled (error, FALSE)) { - /* the only place where we nm_connectivity_check_cancel(@c_handle), is - * from inside concheck_handle_complete(). This is a recursive call, - * nothing to do. */ - _LOGT (LOGD_CONCHECK, "connectivity: complete check (seq:%llu, cancelled)", - (long long unsigned) handle->seq); - return; - } - - self_keep_alive = g_object_ref (self); - - _LOGT (LOGD_CONCHECK, "connectivity: complete check (seq:%llu, state:%s%s%s%s)", - (long long unsigned) handle->seq, - nm_connectivity_state_to_string (state), - NM_PRINT_FMT_QUOTED (error, ", error: ", error->message, "", "")); - - /* we keep NMConnectivity instance alive. It cannot be disposing. */ - nm_assert (!nm_utils_error_is_cancelled (error, TRUE)); - - /* keep @self alive, while we invoke callbacks. */ - priv = NM_DEVICE_GET_PRIVATE (self); - - nm_assert (!handle || c_list_contains (&priv->concheck_lst_head, &handle->concheck_lst)); - - seq = handle->seq; - - /* find out, if there are any periodic checks pending (either whether they - * were scheduled before or after @handle. */ - any_periodic_before = FALSE; - any_periodic_after = FALSE; - c_list_for_each_entry (other_handle, &priv->concheck_lst_head, concheck_lst) { - if (other_handle->is_periodic_bump_on_complete) { - if (other_handle->seq < seq) - any_periodic_before = TRUE; - else if (other_handle->seq > seq) - any_periodic_after = TRUE; - } - } - if (NM_IN_SET (state, NM_CONNECTIVITY_ERROR)) { - /* the request failed. We consider this periodic check only as completed if - * this was a periodic check, and there are not checks pending (either - * before or after this one). - * - * We allow_periodic_bump, if the request failed and there are - * still other requests periodic pending. */ - allow_periodic_bump = handle->is_periodic_bump_on_complete - && !any_periodic_before - && !any_periodic_after; - } else { - /* the request succeeded. This marks the completion of a periodic check, - * if this handle was periodic, or any previously scheduled one (that - * we are going to complete below). */ - allow_periodic_bump = handle->is_periodic_bump_on_complete - || any_periodic_before; - } - - /* first update the new state, and emit signals. */ - concheck_update_state (self, state, allow_periodic_bump); - - handle_is_alive = FALSE; - - /* we might have invoked callbacks during concheck_update_state(). The caller might have - * cancelled and thus destroyed @handle. We have to check whether handle is still alive, - * by searching it in the list of alive handles. - * - * Also, we might want to complete all pending callbacks that were started before - * @handle, as they are automatically obsoleted. */ -check_handles: - c_list_for_each_entry (other_handle, &priv->concheck_lst_head, concheck_lst) { - if (other_handle->seq >= seq) { - /* it's not guaranteed that @handle is still in the list. It might already - * be canceled while invoking callbacks for a previous other_handle. - * If it is already cancelled, @handle is a dangling pointer. - * - * Since @seq is assigned uniquely and increasing, either @other_handle is - * @handle (and thus, handle is alive), or it isn't. */ - if (other_handle == handle) - handle_is_alive = TRUE; - break; - } - - nm_assert (other_handle != handle); - - if (!NM_IN_SET (state, NM_CONNECTIVITY_ERROR)) { - /* we also want to complete handles that were started before the current - * @handle. Their response is out-dated. */ - concheck_handle_complete (other_handle, NULL); - - /* we invoked callbacks, other handles might be cancelled and removed from the list. - * Need to iterate the list from the start. */ - goto check_handles; - } - } + ConnectivityCheckData *data = user_data; + NMDevice *self = data->self; + NMDevicePrivate *priv = NM_DEVICE_GET_PRIVATE (self); + NMConnectivity *connectivity = NM_CONNECTIVITY (source_object); + NMConnectivityState state; + GError *error = NULL; - if (!handle_is_alive) { - /* We didn't find @handle in the list of alive handles. Thus, the handles - * was cancelled while we were invoking events. Nothing to do, and don't - * touch the dangling pointer. */ - return; + state = nm_connectivity_check_finish (connectivity, result, &error); + if (error) { + _LOGW (LOGD_DEVICE, "connectivity checking on '%s' failed: %s", + nm_device_get_iface (self), error->message); + g_error_free (error); } - concheck_handle_complete (handle, NULL); + if (data->seq == priv->concheck_seq) + update_connectivity_state (data->self, state); + concheck_done (data); } +#endif /* WITH_CONCHECK */ -static NMDeviceConnectivityHandle * -concheck_start (NMDevice *self, - NMDeviceConnectivityCallback callback, - gpointer user_data, - gboolean is_periodic) +static gboolean +no_concheck (gpointer user_data) { - static guint64 seq_counter = 0; - NMDevicePrivate *priv; - NMDeviceConnectivityHandle *handle; - - g_return_val_if_fail (NM_IS_DEVICE (self), NULL); - - priv = NM_DEVICE_GET_PRIVATE (self); - - handle = g_slice_new0 (NMDeviceConnectivityHandle); - handle->seq = ++seq_counter; - handle->self = self; - handle->callback = callback; - handle->user_data = user_data; - handle->is_periodic = is_periodic; - handle->is_periodic_bump = is_periodic; - handle->is_periodic_bump_on_complete = is_periodic; + ConnectivityCheckData *data = user_data; - c_list_link_tail (&priv->concheck_lst_head, &handle->concheck_lst); - - _LOGT (LOGD_CONCHECK, "connectivity: start check (seq:%llu%s)", - (long long unsigned) handle->seq, - is_periodic ? ", periodic-check" : ""); - - handle->c_handle = nm_connectivity_check_start (concheck_get_mgr (self), - nm_device_get_ip_iface (self), - concheck_cb, - handle); - return handle; + concheck_done (data); + return G_SOURCE_REMOVE; } -NMDeviceConnectivityHandle * +void nm_device_check_connectivity (NMDevice *self, NMDeviceConnectivityCallback callback, gpointer user_data) { - NMDeviceConnectivityHandle *handle; - - if (!concheck_is_possible (self)) - return NULL; - - concheck_periodic_schedule_set (self, CONCHECK_SCHEDULE_CHECK_EXTERNAL); - handle = concheck_start (self, callback, user_data, FALSE); - return handle; -} + ConnectivityCheckData *data; +#if WITH_CONCHECK + NMDevicePrivate *priv = NM_DEVICE_GET_PRIVATE (self); +#endif -void -nm_device_check_connectivity_cancel (NMDeviceConnectivityHandle *handle) -{ - gs_free_error GError *cancelled_error = NULL; + data = g_slice_new0 (ConnectivityCheckData); + data->self = g_object_ref (self); + data->callback = callback; + data->user_data = user_data; - g_return_if_fail (handle); - g_return_if_fail (NM_IS_DEVICE (handle->self)); - g_return_if_fail (!c_list_is_empty (&handle->concheck_lst)); +#if WITH_CONCHECK + if (priv->concheck_periodic_id) { + data->seq = ++priv->concheck_seq; - /* nobody has access to periodic handles, and cannot cancel - * them externally. */ - nm_assert (!handle->is_periodic); + /* Kick off a real connectivity check. */ + nm_connectivity_check_async (nm_connectivity_get (), + nm_device_get_ip_iface (self), + concheck_cb, + data); + return; + } +#endif - nm_utils_error_set_cancelled (&cancelled_error, FALSE, "NMDevice"); - concheck_handle_complete (handle, cancelled_error); + /* Fake one. */ + g_idle_add (no_concheck, data); } NMConnectivityState @@ -2771,6 +2112,43 @@ nm_device_get_connectivity_state (NMDevice *self) return NM_DEVICE_GET_PRIVATE (self)->connectivity_state; } +#if WITH_CONCHECK +static void +concheck_periodic (NMConnectivity *connectivity, NMDevice *self) +{ + nm_device_check_connectivity (self, NULL, NULL); +} +#endif + +static void +concheck_periodic_update (NMDevice *self) +{ +#if WITH_CONCHECK + NMDevicePrivate *priv = NM_DEVICE_GET_PRIVATE (self); + gboolean check_enable; + + check_enable = (priv->state == NM_DEVICE_STATE_ACTIVATED) + && nm_device_get_best_default_route (self, AF_UNSPEC); + + if (check_enable && !priv->concheck_periodic_id) { + /* We just gained a default route. Enable periodic checking. */ + priv->concheck_periodic_id = g_signal_connect (nm_connectivity_get (), + NM_CONNECTIVITY_PERIODIC_CHECK, + G_CALLBACK (concheck_periodic), self); + /* Also kick off a check right away. */ + nm_device_check_connectivity (self, NULL, NULL); + } else if (!check_enable && priv->concheck_periodic_id) { + /* The default route has gone off, and so has connectivity. */ + nm_clear_g_signal_handler (nm_connectivity_get (), &priv->concheck_periodic_id); + update_connectivity_state (self, NM_CONNECTIVITY_NONE); + } +#else + /* update_connectivity_state() figures out how to lie about + * connectivity state if the actual state is not really known. */ + update_connectivity_state (self, NM_CONNECTIVITY_UNKNOWN); +#endif +} + /*****************************************************************************/ static SlaveInfo * @@ -2848,7 +2226,7 @@ nm_device_master_enslave_slave (NMDevice *self, NMDevice *slave, NMConnection *c /* Since slave devices don't have their own IP configuration, * set the MTU here. */ - _commit_mtu (slave, NM_DEVICE_GET_PRIVATE (slave)->ip_config_4); + _commit_mtu (slave, NM_DEVICE_GET_PRIVATE (slave)->ip4_config); return success; } @@ -2986,6 +2364,8 @@ nm_device_update_dynamic_ip_setup (NMDevice *self) { NMDevicePrivate *priv; GError *error = NULL; + gconstpointer addr; + size_t addr_length; g_return_if_fail (NM_IS_DEVICE (self)); @@ -3018,6 +2398,8 @@ nm_device_update_dynamic_ip_setup (NMDevice *self) if (priv->lldp_listener && nm_lldp_listener_is_running (priv->lldp_listener)) { nm_lldp_listener_stop (priv->lldp_listener); + addr = nm_platform_link_get_address (nm_device_get_platform (self), priv->ifindex, &addr_length); + if (!nm_lldp_listener_start (priv->lldp_listener, nm_device_get_ifindex (self), &error)) { _LOGD (LOGD_DEVICE, "LLDP listener %p could not be restarted: %s", priv->lldp_listener, error->message); @@ -3054,12 +2436,12 @@ carrier_changed (NMDevice *self, gboolean carrier) * is restored. */ if (priv->state == NM_DEVICE_STATE_ACTIVATED) nm_device_update_dynamic_ip_setup (self); - else { - if (nm_device_activate_ip4_state_in_wait (self)) - nm_device_activate_stage3_ip4_start (self); - if (nm_device_activate_ip6_state_in_wait (self)) - nm_device_activate_stage3_ip6_start (self); - } + /* If needed, also resume IP configuration that is + * waiting for carrier. */ + if (nm_device_activate_ip4_state_in_wait (self)) + nm_device_activate_stage3_ip4_start (self); + if (nm_device_activate_ip6_state_in_wait (self)) + nm_device_activate_stage3_ip6_start (self); return; } /* fall-through and change state of device */ @@ -3254,14 +2636,12 @@ ndisc_set_router_config (NMNDisc *ndisc, NMDevice *self) now = nm_utils_get_monotonic_timestamp_s (); - head_entry = nm_ip6_config_lookup_addresses (priv->ip_config_6); + head_entry = nm_ip6_config_lookup_addresses (priv->ip6_config); addresses = g_array_sized_new (FALSE, TRUE, sizeof (NMNDiscAddress), head_entry ? head_entry->len : 0); nm_dedup_multi_iter_for_each (&ipconf_iter, head_entry) { const NMPlatformIP6Address *addr = NMP_OBJECT_CAST_IP6_ADDRESS (ipconf_iter.current->obj); NMNDiscAddress *ndisc_addr; - guint32 lifetime, preferred; - gint32 base; if (IN6_IS_ADDR_LINKLOCAL (&addr->address)) continue; @@ -3273,35 +2653,19 @@ ndisc_set_router_config (NMNDisc *ndisc, NMDevice *self) if (addr->plen != 64) continue; - /* resolve the timestamps relative to a new base. - * - * Note that for convenience, platform @addr might have timestamp and/or - * lifetime unset. We don't allow that flexibility for ndisc and require - * well defined timestamps. */ - if (addr->timestamp) { - nm_assert (addr->timestamp < G_MAXINT32); - base = addr->timestamp; - } else - base = now; - - lifetime = nm_utils_lifetime_get (addr->timestamp, addr->lifetime, addr->preferred, - base, &preferred); - if (!lifetime) - continue; - g_array_set_size (addresses, addresses->len+1); ndisc_addr = &g_array_index (addresses, NMNDiscAddress, addresses->len-1); ndisc_addr->address = addr->address; - ndisc_addr->timestamp = base; - ndisc_addr->lifetime = lifetime; - ndisc_addr->preferred = preferred; + ndisc_addr->timestamp = addr->timestamp; + ndisc_addr->lifetime = addr->lifetime; + ndisc_addr->preferred = addr->preferred; } - len = nm_ip6_config_get_num_nameservers (priv->ip_config_6); + len = nm_ip6_config_get_num_nameservers (priv->ip6_config); dns_servers = g_array_sized_new (FALSE, TRUE, sizeof (NMNDiscDNSServer), len); g_array_set_size (dns_servers, len); for (i = 0; i < len; i++) { - const struct in6_addr *nameserver = nm_ip6_config_get_nameserver (priv->ip_config_6, i); + const struct in6_addr *nameserver = nm_ip6_config_get_nameserver (priv->ip6_config, i); NMNDiscDNSServer *ndisc_nameserver; ndisc_nameserver = &g_array_index (dns_servers, NMNDiscDNSServer, i); @@ -3310,11 +2674,11 @@ ndisc_set_router_config (NMNDisc *ndisc, NMDevice *self) ndisc_nameserver->lifetime = NM_NDISC_ROUTER_LIFETIME; } - len = nm_ip6_config_get_num_searches (priv->ip_config_6); + len = nm_ip6_config_get_num_searches (priv->ip6_config); dns_domains = g_array_sized_new (FALSE, TRUE, sizeof (NMNDiscDNSDomain), len); g_array_set_size (dns_domains, len); for (i = 0; i < len; i++) { - const char *search = nm_ip6_config_get_search (priv->ip_config_6, i); + const char *search = nm_ip6_config_get_search (priv->ip6_config, i); NMNDiscDNSDomain *ndisc_search; ndisc_search = &g_array_index (dns_domains, NMNDiscDNSDomain, i); @@ -3440,11 +2804,11 @@ device_link_changed (NMDevice *self) /* the link was down and just came up. That happens for example, while changing MTU. * We must restore IP configuration. */ if (priv->ip4_state == IP_DONE) { - if (!ip_config_merge_and_apply (self, AF_INET, TRUE)) + if (!ip4_config_merge_and_apply (self, TRUE)) _LOGW (LOGD_IP4, "failed applying IP4 config after link comes up again"); } if (priv->ip6_state == IP_DONE) { - if (!ip_config_merge_and_apply (self, AF_INET6, TRUE)) + if (!ip6_config_merge_and_apply (self, TRUE)) _LOGW (LOGD_IP6, "failed applying IP6 config after link comes up again"); } } @@ -3948,8 +3312,8 @@ realize_start_setup (NMDevice *self, g_return_if_fail (nm_device_get_unmanaged_flags (self, NM_UNMANAGED_PLATFORM_INIT)); g_return_if_fail (priv->ip_ifindex <= 0); g_return_if_fail (priv->ip_iface == NULL); - g_return_if_fail (!priv->queued_ip_config_id_4); - g_return_if_fail (!priv->queued_ip_config_id_6); + g_return_if_fail (!priv->queued_ip4_config_id); + g_return_if_fail (!priv->queued_ip6_config_id); _LOGD (LOGD_DEVICE, "start setup of %s, kernel ifindex %d", G_OBJECT_TYPE_NAME (self), plink ? plink->ifindex : 0); @@ -3996,7 +3360,7 @@ realize_start_setup (NMDevice *self, if (nm_platform_check_kernel_support (nm_device_get_platform (self), NM_PLATFORM_KERNEL_SUPPORT_USER_IPV6LL)) - priv->ipv6ll_handle = nm_platform_link_get_user_ipv6ll_enabled (nm_device_get_platform (self), priv->ifindex); + priv->nm_ipv6ll = nm_platform_link_get_user_ipv6ll_enabled (nm_device_get_platform (self), priv->ifindex); if (nm_platform_link_supports_sriov (nm_device_get_platform (self), priv->ifindex)) capabilities |= NM_DEVICE_CAP_SRIOV; @@ -4095,9 +3459,6 @@ nm_device_realize_finish (NMDevice *self, const NMPlatformLink *plink) if (plink) device_recheck_slave_status (self, plink); - priv->update_ip_config_completed_v4 = FALSE; - priv->update_ip_config_completed_v6 = FALSE; - priv->real = TRUE; _notify (self, PROP_REAL); @@ -4323,7 +3684,7 @@ nm_device_notify_component_added (NMDevice *self, GObject *component) * because that ethernet interface is controlled by the WWAN device and cannot * be used independently of the WWAN device. * - * Returns: %TRUE if @self or its components own the interface name, + * Returns: %TRUE if @self or it's components owns the interface name, * %FALSE if not */ gboolean @@ -4613,7 +3974,7 @@ check_ip_state (NMDevice *self, gboolean may_fail, gboolean full_state_update) /* Don't progress into IP_CHECK or SECONDARIES if we're waiting for the * master to enslave us. */ - if ( nm_active_connection_get_master (NM_ACTIVE_CONNECTION (priv->act_request.obj)) + if ( nm_active_connection_get_master (NM_ACTIVE_CONNECTION (priv->act_request)) && !priv->is_enslaved) return; @@ -4801,8 +4162,8 @@ nm_device_removed (NMDevice *self, gboolean unconfigure_ip_config) if (!unconfigure_ip_config) return; - nm_device_set_ip_config (self, AF_INET, NULL, FALSE, NULL); - nm_device_set_ip_config (self, AF_INET6, NULL, FALSE, NULL); + nm_device_set_ip4_config (self, NULL, FALSE, NULL); + nm_device_set_ip6_config (self, NULL, FALSE); } static gboolean @@ -5054,9 +4415,9 @@ device_has_config (NMDevice *self) NMDevicePrivate *priv = NM_DEVICE_GET_PRIVATE (self); /* Check for IP configuration. */ - if (priv->ip_config_4 && nm_ip4_config_get_num_addresses (priv->ip_config_4)) + if (priv->ip4_config && nm_ip4_config_get_num_addresses (priv->ip4_config)) return TRUE; - if (priv->ip_config_6 && nm_ip6_config_get_num_addresses (priv->ip_config_6)) + if (priv->ip6_config && nm_ip6_config_get_num_addresses (priv->ip6_config)) return TRUE; /* The existence of a software device is good enough. */ @@ -5181,10 +4542,10 @@ nm_device_generate_connection (NMDevice *self, } } else { /* Only regular and master devices get IP configuration; slaves do not */ - s_ip4 = nm_ip4_config_create_setting (priv->ip_config_4); + s_ip4 = nm_ip4_config_create_setting (priv->ip4_config); nm_connection_add_setting (connection, s_ip4); - s_ip6 = nm_ip6_config_create_setting (priv->ip_config_6); + s_ip6 = nm_ip6_config_create_setting (priv->ip6_config); nm_connection_add_setting (connection, s_ip6); nm_connection_add_setting (connection, nm_setting_proxy_new ()); @@ -5241,45 +4602,34 @@ nm_device_generate_connection (NMDevice *self, return g_steal_pointer (&connection); } -/** - * nm_device_complete_connection: - * - * Complete the connection. This is solely used for AddAndActivate where the user - * may pass in an incomplete connection and a device, and the device tries to - * make sense of it and complete it for activation. Otherwise, this is not - * used. - * - * Returns: success or failure. - */ gboolean nm_device_complete_connection (NMDevice *self, NMConnection *connection, const char *specific_object, - NMConnection *const*existing_connections, + const GSList *existing_connections, GError **error) { - NMDeviceClass *klass; - - g_return_val_if_fail (NM_IS_DEVICE (self), FALSE); - g_return_val_if_fail (NM_IS_CONNECTION (connection), FALSE); + gboolean success = FALSE; - klass = NM_DEVICE_GET_CLASS (self); + g_return_val_if_fail (self != NULL, FALSE); + g_return_val_if_fail (connection != NULL, FALSE); - if (!klass->complete_connection) { + if (!NM_DEVICE_GET_CLASS (self)->complete_connection) { g_set_error (error, NM_DEVICE_ERROR, NM_DEVICE_ERROR_INVALID_CONNECTION, "Device class %s had no complete_connection method", G_OBJECT_TYPE_NAME (self)); return FALSE; } - if (!klass->complete_connection (self, - connection, - specific_object, - existing_connections, - error)) - return FALSE; + success = NM_DEVICE_GET_CLASS (self)->complete_connection (self, + connection, + specific_object, + existing_connections, + error); + if (success) + success = nm_connection_verify (connection, error); - return nm_connection_verify (connection, error); + return success; } gboolean @@ -5388,12 +4738,15 @@ nm_device_check_connection_compatible (NMDevice *self, NMConnection *connection) gboolean nm_device_check_slave_connection_compatible (NMDevice *self, NMConnection *slave) { + NMDevicePrivate *priv; NMSettingConnection *s_con; const char *connection_type, *slave_type; g_return_val_if_fail (NM_IS_DEVICE (self), FALSE); g_return_val_if_fail (NM_IS_CONNECTION (slave), FALSE); + priv = NM_DEVICE_GET_PRIVATE (self); + if (!nm_device_is_master (self)) return FALSE; @@ -5806,9 +5159,8 @@ activate_stage1_device_prepare (NMDevice *self) _set_ip_state (self, AF_INET6, IP_NONE); /* Notify the new ActiveConnection along with the state change */ - nm_dbus_track_obj_path_set (&priv->act_request, - priv->act_request.obj, - TRUE); + priv->act_request_public = TRUE; + _notify (self, PROP_ACTIVE_CONNECTION); nm_device_state_changed (self, NM_DEVICE_STATE_PREPARE, NM_DEVICE_STATE_REASON_NONE); @@ -5844,7 +5196,7 @@ nm_device_activate_schedule_stage1_device_prepare (NMDevice *self) g_return_if_fail (NM_IS_DEVICE (self)); priv = NM_DEVICE_GET_PRIVATE (self); - g_return_if_fail (priv->act_request.obj); + g_return_if_fail (priv->act_request); activation_source_schedule (self, activate_stage1_device_prepare, AF_INET); } @@ -5862,6 +5214,8 @@ lldp_init (NMDevice *self, gboolean restart) if (priv->ifindex > 0 && lldp_rx_enabled (self)) { gs_free_error GError *error = NULL; + gconstpointer addr; + size_t addr_length; if (priv->lldp_listener) { if (restart && nm_lldp_listener_is_running (priv->lldp_listener)) @@ -5875,6 +5229,8 @@ lldp_init (NMDevice *self, gboolean restart) } if (!nm_lldp_listener_is_running (priv->lldp_listener)) { + addr = nm_platform_link_get_address (nm_device_get_platform (self), priv->ifindex, &addr_length); + if (nm_lldp_listener_start (priv->lldp_listener, nm_device_get_ifindex (self), &error)) _LOGD (LOGD_DEVICE, "LLDP listener %p started", priv->lldp_listener); else { @@ -6021,7 +5377,7 @@ activate_stage2_device_config (NMDevice *self) if (slave_state == NM_DEVICE_STATE_IP_CONFIG) nm_device_master_enslave_slave (self, info->slave, nm_device_get_applied_connection (info->slave)); - else if ( priv->act_request.obj + else if ( priv->act_request && nm_device_sys_iface_state_is_external (self) && slave_state <= NM_DEVICE_STATE_DISCONNECTED) nm_device_queue_recheck_assume (info->slave); @@ -6046,10 +5402,10 @@ nm_device_activate_schedule_stage2_device_config (NMDevice *self) g_return_if_fail (NM_IS_DEVICE (self)); priv = NM_DEVICE_GET_PRIVATE (self); - g_return_if_fail (priv->act_request.obj); + g_return_if_fail (priv->act_request); if (!priv->master_ready_handled) { - NMActiveConnection *active = NM_ACTIVE_CONNECTION (priv->act_request.obj); + NMActiveConnection *active = NM_ACTIVE_CONNECTION (priv->act_request); NMActiveConnection *master; master = nm_active_connection_get_master (active); @@ -6087,9 +5443,13 @@ nm_device_ip_method_failed (NMDevice *self, int addr_family, NMDeviceStateReason reason) { + NMDevicePrivate *priv; + g_return_if_fail (NM_IS_DEVICE (self)); g_return_if_fail (NM_IN_SET (addr_family, AF_INET, AF_INET6)); + priv = NM_DEVICE_GET_PRIVATE (self); + _set_ip_state (self, addr_family, IP_FAIL); if (get_ip_config_may_fail (self, addr_family)) @@ -6130,16 +5490,16 @@ get_ipv4_dad_timeout (NMDevice *self) } static void -acd_data_destroy (gpointer ptr, GClosure *closure) +arping_data_destroy (gpointer ptr, GClosure *closure) { - AcdData *data = ptr; + ArpingData *data = ptr; int i; if (data) { for (i = 0; data->configs && data->configs[i]; i++) g_object_unref (data->configs[i]); g_free (data->configs); - g_slice_free (AcdData, data); + g_slice_free (ArpingData, data); } } @@ -6159,7 +5519,7 @@ ipv4_manual_method_apply (NMDevice *self, NMIP4Config **configs, gboolean succes } static void -acd_manager_probe_terminated (NMAcdManager *acd_manager, AcdData *data) +arping_manager_probe_terminated (NMArpingManager *arping_manager, ArpingData *data) { NMDevice *self; NMDevicePrivate *priv; @@ -6174,7 +5534,7 @@ acd_manager_probe_terminated (NMAcdManager *acd_manager, AcdData *data) for (i = 0; data->configs && data->configs[i]; i++) { nm_ip_config_iter_ip4_address_for_each (&ipconf_iter, data->configs[i], &address) { - result = nm_acd_manager_check_address (acd_manager, address->address); + result = nm_arping_manager_check_address (arping_manager, address->address); success &= result; _NMLOG (result ? LOGL_DEBUG : LOGL_WARN, @@ -6187,8 +5547,8 @@ acd_manager_probe_terminated (NMAcdManager *acd_manager, AcdData *data) data->callback (self, data->configs, success); - priv->acd.dad_list = g_slist_remove (priv->acd.dad_list, acd_manager); - nm_acd_manager_destroy (acd_manager); + priv->arping.dad_list = g_slist_remove (priv->arping.dad_list, arping_manager); + nm_arping_manager_destroy (arping_manager); } /** @@ -6202,17 +5562,18 @@ acd_manager_probe_terminated (NMAcdManager *acd_manager, AcdData *data) * be started. @configs will be unreferenced after @cb has been called. */ static void -ipv4_dad_start (NMDevice *self, NMIP4Config **configs, AcdCallback cb) +ipv4_dad_start (NMDevice *self, NMIP4Config **configs, ArpingCallback cb) { NMDevicePrivate *priv = NM_DEVICE_GET_PRIVATE (self); - NMAcdManager *acd_manager; + NMArpingManager *arping_manager; const NMPlatformIP4Address *address; NMDedupMultiIter ipconf_iter; - AcdData *data; + ArpingData *data; guint timeout; gboolean ret, addr_found; - const guint8 *hwaddr_arr; - size_t length; + const guint8 *hw_addr; + size_t hw_addr_len = 0; + GError *error = NULL; guint i; g_return_if_fail (NM_IS_DEVICE (self)); @@ -6227,14 +5588,14 @@ ipv4_dad_start (NMDevice *self, NMIP4Config **configs, AcdCallback cb) } timeout = get_ipv4_dad_timeout (self); - hwaddr_arr = nm_platform_link_get_address (nm_device_get_platform (self), - nm_device_get_ip_ifindex (self), - &length); + hw_addr = nm_platform_link_get_address (nm_device_get_platform (self), + nm_device_get_ip_ifindex (self), + &hw_addr_len); if ( !timeout - || !hwaddr_arr + || !hw_addr + || !hw_addr_len || !addr_found - || length != ETH_ALEN || nm_device_sys_iface_state_is_external_or_assume (self)) { /* DAD not needed, signal success */ @@ -6247,36 +5608,36 @@ ipv4_dad_start (NMDevice *self, NMIP4Config **configs, AcdCallback cb) return; } - /* don't take additional references of @acd_manager that outlive @self. + /* don't take additional references of @arping_manager that outlive @self. * Otherwise, the callback can be invoked on a dangling pointer as we don't * disconnect the handler. */ - acd_manager = nm_acd_manager_new (nm_device_get_ip_ifindex (self), hwaddr_arr, length); - priv->acd.dad_list = g_slist_append (priv->acd.dad_list, acd_manager); + arping_manager = nm_arping_manager_new (nm_device_get_ip_ifindex (self)); + priv->arping.dad_list = g_slist_append (priv->arping.dad_list, arping_manager); - data = g_slice_new0 (AcdData); + data = g_slice_new0 (ArpingData); data->configs = configs; data->callback = cb; data->device = self; for (i = 0; configs[i]; i++) { nm_ip_config_iter_ip4_address_for_each (&ipconf_iter, configs[i], &address) - nm_acd_manager_add_address (acd_manager, address->address); + nm_arping_manager_add_address (arping_manager, address->address); } - g_signal_connect_data (acd_manager, NM_ACD_MANAGER_PROBE_TERMINATED, - G_CALLBACK (acd_manager_probe_terminated), data, - acd_data_destroy, 0); + g_signal_connect_data (arping_manager, NM_ARPING_MANAGER_PROBE_TERMINATED, + G_CALLBACK (arping_manager_probe_terminated), data, + arping_data_destroy, 0); - ret = nm_acd_manager_start_probe (acd_manager, timeout); + ret = nm_arping_manager_start_probe (arping_manager, timeout, &error); if (!ret) { - _LOGW (LOGD_DEVICE, "acd probe failed"); + _LOGW (LOGD_DEVICE, "arping probe failed: %s", error->message); /* DAD could not be started, signal success */ cb (self, configs, TRUE); - priv->acd.dad_list = g_slist_remove (priv->acd.dad_list, acd_manager); - nm_acd_manager_destroy (acd_manager); + priv->arping.dad_list = g_slist_remove (priv->arping.dad_list, arping_manager); + nm_arping_manager_destroy (arping_manager); } } @@ -6338,10 +5699,10 @@ nm_device_handle_ipv4ll_event (sd_ipv4ll *ll, int event, void *data) NMIP4Config *config; int r; - if (priv->act_request.obj == NULL) + if (priv->act_request == NULL) return; - connection = nm_act_request_get_applied_connection (priv->act_request.obj); + connection = nm_act_request_get_applied_connection (priv->act_request); g_assert (connection); /* Ignore if the connection isn't an AutoIP connection */ @@ -6375,8 +5736,9 @@ nm_device_handle_ipv4ll_event (sd_ipv4ll *ll, int event, void *data) nm_clear_g_source (&priv->ipv4ll_timeout); nm_device_activate_schedule_ip4_config_result (self, config); } else if (priv->ip4_state == IP_DONE) { - applied_config_init (&priv->dev_ip4_config, config); - if (!ip_config_merge_and_apply (self, AF_INET, TRUE)) { + g_clear_object (&priv->dev_ip4_config); + priv->dev_ip4_config = g_object_ref (config); + if (!ip4_config_merge_and_apply (self, TRUE)) { _LOGE (LOGD_AUTOIP4, "failed to update IP4 config for autoip change."); nm_device_ip_method_failed (self, AF_INET, NM_DEVICE_STATE_REASON_AUTOIP_FAILED); } @@ -6472,42 +5834,55 @@ ipv4ll_start (NMDevice *self) /*****************************************************************************/ static void -ensure_con_ip_config (NMDevice *self, int addr_family) +ensure_con_ip4_config (NMDevice *self) { NMDevicePrivate *priv = NM_DEVICE_GET_PRIVATE (self); NMConnection *connection; - const gboolean IS_IPv4 = (addr_family == AF_INET); - NMIPConfig *con_ip_config; - if (priv->con_ip_config_x[IS_IPv4]) + if (priv->con_ip4_config) return; connection = nm_device_get_applied_connection (self); if (!connection) return; - con_ip_config = _ip_config_new (self, addr_family); + priv->con_ip4_config = _ip4_config_new (self); + nm_ip4_config_merge_setting (priv->con_ip4_config, + nm_connection_get_setting_ip4_config (connection), + nm_device_get_route_table (self, AF_INET, TRUE), + nm_device_get_route_metric (self, AF_INET)); - if (IS_IPv4) { - nm_ip4_config_merge_setting (NM_IP4_CONFIG (con_ip_config), - nm_connection_get_setting_ip4_config (connection), - _get_mdns (self), - nm_device_get_route_table (self, addr_family, TRUE), - nm_device_get_route_metric (self, addr_family)); - } else { - nm_ip6_config_merge_setting (NM_IP6_CONFIG (con_ip_config), - nm_connection_get_setting_ip6_config (connection), - nm_device_get_route_table (self, addr_family, TRUE), - nm_device_get_route_metric (self, addr_family)); + if (nm_device_sys_iface_state_is_external_or_assume (self)) { + /* For assumed connections ignore all addresses and routes. */ + nm_ip4_config_reset_addresses (priv->con_ip4_config); + nm_ip4_config_reset_routes (priv->con_ip4_config); } +} + +static void +ensure_con_ip6_config (NMDevice *self) +{ + NMDevicePrivate *priv = NM_DEVICE_GET_PRIVATE (self); + NMConnection *connection; + + if (priv->con_ip6_config) + return; + + connection = nm_device_get_applied_connection (self); + if (!connection) + return; + + priv->con_ip6_config = _ip6_config_new (self); + nm_ip6_config_merge_setting (priv->con_ip6_config, + nm_connection_get_setting_ip6_config (connection), + nm_device_get_route_table (self, AF_INET6, TRUE), + nm_device_get_route_metric (self, AF_INET6)); if (nm_device_sys_iface_state_is_external_or_assume (self)) { /* For assumed connections ignore all addresses and routes. */ - nm_ip_config_reset_addresses (con_ip_config); - nm_ip_config_reset_routes (con_ip_config); + nm_ip6_config_reset_addresses (priv->con_ip6_config); + nm_ip6_config_reset_routes (priv->con_ip6_config); } - - priv->con_ip_config_x[IS_IPv4] = con_ip_config; } /*****************************************************************************/ @@ -6535,222 +5910,105 @@ dhcp4_cleanup (NMDevice *self, CleanupType cleanup_type, gboolean release) } if (priv->dhcp4.config) { - nm_dbus_object_clear_and_unexport (&priv->dhcp4.config); + nm_exported_object_clear_and_unexport (&priv->dhcp4.config); _notify (self, PROP_DHCP4_CONFIG); } } static gboolean -ip_config_merge_and_apply (NMDevice *self, - int addr_family, - gboolean commit) +ip4_config_merge_and_apply (NMDevice *self, + gboolean commit) { NMDevicePrivate *priv = NM_DEVICE_GET_PRIVATE (self); - gboolean success; - gs_unref_object NMIPConfig *composite = NULL; - NMIPConfig *config; - gs_unref_ptrarray GPtrArray *ip4_dev_route_blacklist = NULL; NMConnection *connection; + gboolean success; + NMIP4Config *composite; gboolean ignore_auto_routes = FALSE; gboolean ignore_auto_dns = FALSE; gboolean ignore_default_routes = FALSE; GSList *iter; - const char *ip6_addr_gen_token = NULL; - const gboolean IS_IPv4 = (addr_family == AF_INET); + gs_unref_ptrarray GPtrArray *ip4_dev_route_blacklist = NULL; if (nm_device_sys_iface_state_is_external (self)) - commit = FALSE; - - connection = nm_device_get_applied_connection (self); + commit = 0; /* Apply ignore-auto-routes and ignore-auto-dns settings */ + connection = nm_device_get_applied_connection (self); if (connection) { - NMSettingIPConfig *s_ip = IS_IPv4 - ? nm_connection_get_setting_ip4_config (connection) - : nm_connection_get_setting_ip6_config (connection); + NMSettingIPConfig *s_ip4 = nm_connection_get_setting_ip4_config (connection); - if (s_ip) { - ignore_auto_routes = nm_setting_ip_config_get_ignore_auto_routes (s_ip); - ignore_auto_dns = nm_setting_ip_config_get_ignore_auto_dns (s_ip); + if (s_ip4) { + ignore_auto_routes = nm_setting_ip_config_get_ignore_auto_routes (s_ip4); + ignore_auto_dns = nm_setting_ip_config_get_ignore_auto_dns (s_ip4); /* if the connection has an explicit gateway, we also ignore * the default routes from other sources. */ - ignore_default_routes = nm_setting_ip_config_get_never_default (s_ip) - || nm_setting_ip_config_get_gateway (s_ip); - - if (!IS_IPv4) { - NMSettingIP6Config *s_ip6 = NM_SETTING_IP6_CONFIG (s_ip); - - if (nm_setting_ip6_config_get_addr_gen_mode (s_ip6) == NM_SETTING_IP6_CONFIG_ADDR_GEN_MODE_EUI64) - ip6_addr_gen_token = nm_setting_ip6_config_get_token (s_ip6); - } + ignore_default_routes = nm_setting_ip_config_get_never_default (s_ip4) + || nm_setting_ip_config_get_gateway (s_ip4); } } - composite = _ip_config_new (self, addr_family); - - if (!IS_IPv4) { - nm_ip6_config_set_privacy (NM_IP6_CONFIG (composite), - priv->ndisc - ? priv->ndisc_use_tempaddr - : NM_SETTING_IP6_CONFIG_PRIVACY_UNKNOWN); - } - - init_ip_config_dns_priority (self, composite); + composite = _ip4_config_new (self); + init_ip4_config_dns_priority (self, composite); if (commit) { - if (priv->queued_ip_config_id_x[IS_IPv4]) - update_ext_ip_config (self, addr_family, FALSE); - ensure_con_ip_config (self, addr_family); - } - - if (!IS_IPv4) { - if ( commit - && priv->ipv6ll_has) { - const NMPlatformIP6Address ll_a = { - .address = priv->ipv6ll_addr, - .plen = 64, - .addr_source = NM_IP_CONFIG_SOURCE_IP6LL, - }; - const NMPlatformIP6Route ll_r = { - .network.s6_addr16[0] = htons (0xfe80u), - .plen = 64, - .metric = nm_device_get_route_metric (self, addr_family), - .rt_source = NM_IP_CONFIG_SOURCE_IP6LL, - }; - - nm_assert (IN6_IS_ADDR_LINKLOCAL (&priv->ipv6ll_addr)); - - nm_ip6_config_add_address (NM_IP6_CONFIG (composite), &ll_a); - nm_ip6_config_add_route (NM_IP6_CONFIG (composite), &ll_r, NULL); - } - } - - if (commit) { - gboolean v; - - v = default_route_metric_penalty_detect (self); - if (IS_IPv4) - priv->default_route_metric_penalty_ip4_has = v; - else - priv->default_route_metric_penalty_ip6_has = v; - } - - /* Merge all the IP configs into the composite config */ - - if (IS_IPv4) { - config = applied_config_get_current (&priv->dev_ip4_config); - if (config) { - nm_ip4_config_merge (NM_IP4_CONFIG (composite), NM_IP4_CONFIG (config), - (ignore_auto_routes ? NM_IP_CONFIG_MERGE_NO_ROUTES : 0) - | (ignore_default_routes ? NM_IP_CONFIG_MERGE_NO_DEFAULT_ROUTES : 0) - | (ignore_auto_dns ? NM_IP_CONFIG_MERGE_NO_DNS : 0), - default_route_metric_penalty_get (self, addr_family)); - } + if (priv->queued_ip4_config_id) + update_ext_ip_config (self, AF_INET, FALSE, FALSE); + ensure_con_ip4_config (self); } - if (!IS_IPv4) { - config = applied_config_get_current (&priv->ac_ip6_config); - if (config) { - nm_ip6_config_merge (NM_IP6_CONFIG (composite), NM_IP6_CONFIG (config), - (ignore_auto_routes ? NM_IP_CONFIG_MERGE_NO_ROUTES : 0) - | (ignore_default_routes ? NM_IP_CONFIG_MERGE_NO_DEFAULT_ROUTES : 0) - | (ignore_auto_dns ? NM_IP_CONFIG_MERGE_NO_DNS : 0), - default_route_metric_penalty_get (self, addr_family)); - } - } + if (commit) + priv->default_route_metric_penalty_ip4_has = default_route_metric_penalty_detect (self); - if (!IS_IPv4) { - config = applied_config_get_current (&priv->dhcp6.ip6_config); - if (config) { - nm_ip6_config_merge (NM_IP6_CONFIG (composite), NM_IP6_CONFIG (config), - (ignore_auto_routes ? NM_IP_CONFIG_MERGE_NO_ROUTES : 0) - | (ignore_default_routes ? NM_IP_CONFIG_MERGE_NO_DEFAULT_ROUTES : 0) - | (ignore_auto_dns ? NM_IP_CONFIG_MERGE_NO_DNS : 0), - default_route_metric_penalty_get (self, addr_family)); - } + if (priv->dev_ip4_config) { + nm_ip4_config_merge (composite, priv->dev_ip4_config, + (ignore_auto_routes ? NM_IP_CONFIG_MERGE_NO_ROUTES : 0) + | (ignore_default_routes ? NM_IP_CONFIG_MERGE_NO_DEFAULT_ROUTES : 0) + | (ignore_auto_dns ? NM_IP_CONFIG_MERGE_NO_DNS : 0), + default_route_metric_penalty_get (self, AF_INET)); } - for (iter = priv->vpn_configs_x[IS_IPv4]; iter; iter = iter->next) - nm_ip_config_merge (composite, iter->data, NM_IP_CONFIG_MERGE_DEFAULT, 0); + for (iter = priv->vpn4_configs; iter; iter = iter->next) + nm_ip4_config_merge (composite, iter->data, NM_IP_CONFIG_MERGE_DEFAULT, 0); - if (priv->ext_ip_config_x[IS_IPv4]) - nm_ip_config_merge (composite, priv->ext_ip_config_x[IS_IPv4], NM_IP_CONFIG_MERGE_DEFAULT, 0); + if (priv->ext_ip4_config) + nm_ip4_config_merge (composite, priv->ext_ip4_config, NM_IP_CONFIG_MERGE_DEFAULT, 0); /* Merge WWAN config *last* to ensure modem-given settings overwrite * any external stuff set by pppd or other scripts. */ - config = applied_config_get_current (&priv->wwan_ip_config_x[IS_IPv4]); - if (config) { - nm_ip_config_merge (composite, config, - (ignore_auto_routes ? NM_IP_CONFIG_MERGE_NO_ROUTES : 0) - | (ignore_default_routes ? NM_IP_CONFIG_MERGE_NO_DEFAULT_ROUTES : 0) - | (ignore_auto_dns ? NM_IP_CONFIG_MERGE_NO_DNS : 0), - default_route_metric_penalty_get (self, addr_family)); - } - - if (!IS_IPv4) { - if (priv->rt6_temporary_not_available) { - const NMPObject *o; - GHashTableIter hiter; - - g_hash_table_iter_init (&hiter, priv->rt6_temporary_not_available); - while (g_hash_table_iter_next (&hiter, (gpointer *) &o, NULL)) { - nm_ip6_config_add_route (NM_IP6_CONFIG (composite), - NMP_OBJECT_CAST_IP6_ROUTE (o), - NULL); - } - } + if (priv->wwan_ip4_config) { + nm_ip4_config_merge (composite, priv->wwan_ip4_config, + (ignore_auto_routes ? NM_IP_CONFIG_MERGE_NO_ROUTES : 0) + | (ignore_default_routes ? NM_IP_CONFIG_MERGE_NO_DEFAULT_ROUTES : 0) + | (ignore_auto_dns ? NM_IP_CONFIG_MERGE_NO_DNS : 0), + default_route_metric_penalty_get (self, AF_INET)); } /* Merge user overrides into the composite config. For assumed connections, - * con_ip_config_x is empty. */ - if (priv->con_ip_config_x[IS_IPv4]) { - nm_ip_config_merge (composite, priv->con_ip_config_x[IS_IPv4], NM_IP_CONFIG_MERGE_DEFAULT, - default_route_metric_penalty_get (self, addr_family)); + * con_ip4_config is empty. */ + if (priv->con_ip4_config) { + nm_ip4_config_merge (composite, priv->con_ip4_config, NM_IP_CONFIG_MERGE_DEFAULT, + default_route_metric_penalty_get (self, AF_INET)); } if (commit) { - if (IS_IPv4) { - nm_ip4_config_add_dependent_routes (NM_IP4_CONFIG (composite), - nm_device_get_route_table (self, addr_family, TRUE), - nm_device_get_route_metric (self, addr_family), - &ip4_dev_route_blacklist); - } else { - nm_ip6_config_add_dependent_routes (NM_IP6_CONFIG (composite), - nm_device_get_route_table (self, addr_family, TRUE), - nm_device_get_route_metric (self, addr_family)); - } + nm_ip4_config_add_dependent_routes (composite, + nm_device_get_route_table (self, AF_INET, TRUE), + nm_device_get_route_metric (self, AF_INET), + &ip4_dev_route_blacklist); } - if (IS_IPv4) { - if (commit) { - if (NM_DEVICE_GET_CLASS (self)->ip4_config_pre_commit) - NM_DEVICE_GET_CLASS (self)->ip4_config_pre_commit (self, NM_IP4_CONFIG (composite)); - } - } - - if (!IS_IPv4) { - if (commit) { - NMUtilsIPv6IfaceId iid; - - if ( ip6_addr_gen_token - && nm_utils_ipv6_interface_identifier_get_from_token (&iid, ip6_addr_gen_token)) { - nm_platform_link_set_ipv6_token (nm_device_get_platform (self), - nm_device_get_ip_ifindex (self), - iid); - } - } - } - - success = nm_device_set_ip_config (self, addr_family, composite, commit, ip4_dev_route_blacklist); if (commit) { - if (IS_IPv4) - priv->v4_commit_first_time = FALSE; - else - priv->v6_commit_first_time = FALSE; + if (NM_DEVICE_GET_CLASS (self)->ip4_config_pre_commit) + NM_DEVICE_GET_CLASS (self)->ip4_config_pre_commit (self, composite); } + success = nm_device_set_ip4_config (self, composite, commit, ip4_dev_route_blacklist); + g_object_unref (composite); + + if (commit) + priv->v4_commit_first_time = FALSE; return success; } @@ -6761,9 +6019,10 @@ dhcp4_lease_change (NMDevice *self, NMIP4Config *config) g_return_val_if_fail (config, FALSE); - applied_config_init (&priv->dev_ip4_config, config); + g_clear_object (&priv->dev_ip4_config); + priv->dev_ip4_config = g_object_ref (config); - if (!ip_config_merge_and_apply (self, AF_INET, TRUE)) { + if (!ip4_config_merge_and_apply (self, TRUE)) { _LOGW (LOGD_DHCP4, "failed to update IPv4 config for DHCP change."); return FALSE; } @@ -6803,8 +6062,8 @@ dhcp4_fail (NMDevice *self, gboolean timeout) * on the interface. */ if ( priv->ip4_state == IP_DONE - && priv->con_ip_config_4 - && nm_ip4_config_get_num_addresses (priv->con_ip_config_4) > 0) + && priv->con_ip4_config + && nm_ip4_config_get_num_addresses (priv->con_ip4_config) > 0) goto clear_config; /* Fail the method in case of timeout or failure during initial @@ -6835,7 +6094,7 @@ dhcp4_fail (NMDevice *self, gboolean timeout) clear_config: /* The previous configuration is no longer valid */ if (priv->dhcp4.config) { - nm_dbus_object_clear_and_unexport (&priv->dhcp4.config); + nm_exported_object_clear_and_unexport (&priv->dhcp4.config); priv->dhcp4.config = nm_dhcp4_config_new (); _notify (self, PROP_DHCP4_CONFIG); } @@ -6900,7 +6159,6 @@ dhcp4_state_changed (NMDhcpClient *client, manual = _ip4_config_new (self); nm_ip4_config_merge_setting (manual, nm_connection_get_setting_ip4_config (connection), - NM_SETTING_CONNECTION_MDNS_DEFAULT, nm_device_get_route_table (self, AF_INET, TRUE), nm_device_get_route_metric (self, AF_INET)); @@ -6976,100 +6234,14 @@ get_dhcp_timeout (NMDevice *self, int addr_family) return timeout ?: NM_DHCP_TIMEOUT_DEFAULT; } -static GBytes * -dhcp4_get_client_id (NMDevice *self, NMConnection *connection) -{ - NMSettingIPConfig *s_ip4; - const char *client_id; - gs_free char *client_id_default = NULL; - guint8 *client_id_buf; - gboolean is_mac; - - s_ip4 = nm_connection_get_setting_ip4_config (connection); - client_id = nm_setting_ip4_config_get_dhcp_client_id (NM_SETTING_IP4_CONFIG (s_ip4)); - - if (!client_id) { - client_id_default = nm_config_data_get_connection_default (NM_CONFIG_GET_DATA, - "ipv4.dhcp-client-id", self); - if (client_id_default && client_id_default[0]) - client_id = client_id_default; - } - - if (!client_id) - return NULL; - - if ( (is_mac = nm_streq (client_id, "mac")) - || nm_streq (client_id, "perm-mac")) { - const char *hwaddr; - char addr_buf[NM_UTILS_HWADDR_LEN_MAX]; - gsize addr_len; - guint8 addr_type; - - hwaddr = is_mac - ? nm_device_get_hw_address (self) - : nm_device_get_permanent_hw_address (self); - if (!hwaddr) - return NULL; - - if (!_nm_utils_hwaddr_aton (hwaddr, addr_buf, sizeof (addr_buf), &addr_len)) - g_return_val_if_reached (NULL); - - switch (addr_len) { - case ETH_ALEN: - addr_type = ARPHRD_ETHER; - break; - default: - /* unsupported type. */ - return NULL; - } - - client_id_buf = g_malloc (addr_len + 1); - client_id_buf[0] = addr_type; - memcpy (&client_id_buf[1], addr_buf, addr_len); - return g_bytes_new_take (client_id_buf, addr_len + 1); - } - - if (nm_streq (client_id, "stable")) { - NMUtilsStableType stable_type; - const char *stable_id; - GChecksum *sum; - guint8 buf[20]; - gsize buf_size; - guint32 salted_header; - - stable_id = _get_stable_id (self, connection, &stable_type); - if (!stable_id) - g_return_val_if_reached (NULL); - - salted_header = htonl (2011610591 + stable_type); - - sum = g_checksum_new (G_CHECKSUM_SHA1); - - g_checksum_update (sum, (const guchar *) &salted_header, sizeof (salted_header)); - g_checksum_update (sum, (const guchar *) stable_id, strlen (stable_id)); - - buf_size = sizeof (buf); - g_checksum_get_digest (sum, buf, &buf_size); - nm_assert (buf_size == sizeof (buf)); - - g_checksum_free (sum); - - client_id_buf = g_malloc (1 + 15); - client_id_buf[0] = 0; - memcpy (&client_id_buf[1], buf, 15); - return g_bytes_new_take (client_id_buf, 1 + 15); - } - - return nm_dhcp_utils_client_id_string_to_bytes (client_id); -} - static NMActStageReturn dhcp4_start (NMDevice *self) { NMDevicePrivate *priv = NM_DEVICE_GET_PRIVATE (self); NMSettingIPConfig *s_ip4; - gs_unref_bytes GBytes *hwaddr = NULL; - gs_unref_bytes GBytes *client_id = NULL; + const guint8 *hw_addr; + size_t hw_addr_len = 0; + GByteArray *tmp = NULL; NMConnection *connection; connection = nm_device_get_applied_connection (self); @@ -7078,31 +6250,36 @@ 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); + nm_exported_object_clear_and_unexport (&priv->dhcp4.config); priv->dhcp4.config = nm_dhcp4_config_new (); - hwaddr = nm_platform_link_get_address_as_bytes (nm_device_get_platform (self), - nm_device_get_ip_ifindex (self)); - - client_id = dhcp4_get_client_id (self, connection); + hw_addr = nm_platform_link_get_address (nm_device_get_platform (self), nm_device_get_ip_ifindex (self), &hw_addr_len); + if (hw_addr_len) { + tmp = g_byte_array_sized_new (hw_addr_len); + g_byte_array_append (tmp, hw_addr, hw_addr_len); + } + /* Begin DHCP on the interface */ 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, + tmp, nm_connection_get_uuid (connection), nm_device_get_route_table (self, AF_INET, TRUE), 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)), - client_id, + nm_setting_ip4_config_get_dhcp_client_id (NM_SETTING_IP4_CONFIG (s_ip4)), get_dhcp_timeout (self, AF_INET), priv->dhcp_anycast_address, NULL); + if (tmp) + g_byte_array_free (tmp, TRUE); + if (!priv->dhcp4.client) return NM_ACT_STAGE_RETURN_FAILURE; @@ -7175,7 +6352,7 @@ shared4_new_config (NMDevice *self, NMConnection *connection) guint32 count = 0; if (G_UNLIKELY (!shared_ips)) - shared_ips = g_hash_table_new (nm_direct_hash, NULL); + shared_ips = g_hash_table_new (g_direct_hash, g_direct_equal); else { while (g_hash_table_lookup (shared_ips, GUINT_TO_POINTER (start + count))) { count += ntohl (0x100); @@ -7360,7 +6537,6 @@ act_stage3_ip4_config_start (NMDevice *self, config = _ip4_config_new (self); nm_ip4_config_merge_setting (config, nm_connection_get_setting_ip4_config (connection), - NM_SETTING_CONNECTION_MDNS_DEFAULT, nm_device_get_route_table (self, AF_INET, TRUE), nm_device_get_route_metric (self, AF_INET)); @@ -7397,7 +6573,7 @@ dhcp6_cleanup (NMDevice *self, CleanupType cleanup_type, gboolean release) NMDevicePrivate *priv = NM_DEVICE_GET_PRIVATE (self); priv->dhcp6.mode = NM_NDISC_DHCP_LEVEL_NONE; - applied_config_clear (&priv->dhcp6.ip6_config); + g_clear_object (&priv->dhcp6.ip6_config); g_clear_pointer (&priv->dhcp6.event_id, g_free); nm_clear_g_source (&priv->dhcp6.grace_id); @@ -7415,18 +6591,148 @@ dhcp6_cleanup (NMDevice *self, CleanupType cleanup_type, gboolean release) nm_device_remove_pending_action (self, NM_PENDING_ACTION_DHCP6, FALSE); if (priv->dhcp6.config) { - nm_dbus_object_clear_and_unexport (&priv->dhcp6.config); + nm_exported_object_clear_and_unexport (&priv->dhcp6.config); _notify (self, PROP_DHCP6_CONFIG); } } static gboolean +ip6_config_merge_and_apply (NMDevice *self, + gboolean commit) +{ + NMDevicePrivate *priv = NM_DEVICE_GET_PRIVATE (self); + NMConnection *connection; + gboolean success; + NMIP6Config *composite; + gboolean ignore_auto_routes = FALSE; + gboolean ignore_auto_dns = FALSE; + gboolean ignore_default_routes = FALSE; + const char *token = NULL; + GSList *iter; + + if (nm_device_sys_iface_state_is_external (self)) + commit = 0; + + /* Apply ignore-auto-routes and ignore-auto-dns settings */ + connection = nm_device_get_applied_connection (self); + if (connection) { + NMSettingIPConfig *s_ip6 = nm_connection_get_setting_ip6_config (connection); + + if (s_ip6) { + NMSettingIP6Config *ip6 = NM_SETTING_IP6_CONFIG (s_ip6); + + ignore_auto_routes = nm_setting_ip_config_get_ignore_auto_routes (s_ip6); + ignore_auto_dns = nm_setting_ip_config_get_ignore_auto_dns (s_ip6); + + /* if the connection has an explicit gateway, we also ignore + * the default routes from other sources. */ + ignore_default_routes = nm_setting_ip_config_get_never_default (s_ip6) + || nm_setting_ip_config_get_gateway (s_ip6); + + if (nm_setting_ip6_config_get_addr_gen_mode (ip6) == NM_SETTING_IP6_CONFIG_ADDR_GEN_MODE_EUI64) + token = nm_setting_ip6_config_get_token (ip6); + } + } + + composite = _ip6_config_new (self); + nm_ip6_config_set_privacy (composite, + priv->ndisc ? + priv->ndisc_use_tempaddr : + NM_SETTING_IP6_CONFIG_PRIVACY_UNKNOWN); + init_ip6_config_dns_priority (self, composite); + + if (commit) { + if (priv->queued_ip6_config_id) + update_ext_ip_config (self, AF_INET6, FALSE, FALSE); + ensure_con_ip6_config (self); + } + + if (commit) + priv->default_route_metric_penalty_ip6_has = default_route_metric_penalty_detect (self); + + /* Merge all the IP configs into the composite config */ + if (priv->ac_ip6_config) { + nm_ip6_config_merge (composite, priv->ac_ip6_config, + (ignore_auto_routes ? NM_IP_CONFIG_MERGE_NO_ROUTES : 0) + | (ignore_default_routes ? NM_IP_CONFIG_MERGE_NO_DEFAULT_ROUTES : 0) + | (ignore_auto_dns ? NM_IP_CONFIG_MERGE_NO_DNS : 0), + default_route_metric_penalty_get (self, AF_INET6)); + } + if (priv->dhcp6.ip6_config) { + nm_ip6_config_merge (composite, priv->dhcp6.ip6_config, + (ignore_auto_routes ? NM_IP_CONFIG_MERGE_NO_ROUTES : 0) + | (ignore_default_routes ? NM_IP_CONFIG_MERGE_NO_DEFAULT_ROUTES : 0) + | (ignore_auto_dns ? NM_IP_CONFIG_MERGE_NO_DNS : 0), + default_route_metric_penalty_get (self, AF_INET6)); + } + + for (iter = priv->vpn6_configs; iter; iter = iter->next) + nm_ip6_config_merge (composite, iter->data, NM_IP_CONFIG_MERGE_DEFAULT, 0); + + if (priv->ext_ip6_config) + nm_ip6_config_merge (composite, priv->ext_ip6_config, NM_IP_CONFIG_MERGE_DEFAULT, 0); + + /* Merge WWAN config *last* to ensure modem-given settings overwrite + * any external stuff set by pppd or other scripts. + */ + if (priv->wwan_ip6_config) { + nm_ip6_config_merge (composite, priv->wwan_ip6_config, + (ignore_auto_routes ? NM_IP_CONFIG_MERGE_NO_ROUTES : 0) + | (ignore_default_routes ? NM_IP_CONFIG_MERGE_NO_DEFAULT_ROUTES : 0) + | (ignore_auto_dns ? NM_IP_CONFIG_MERGE_NO_DNS : 0), + default_route_metric_penalty_get (self, AF_INET6)); + } + + if (priv->rt6_temporary_not_available) { + const NMPObject *o; + GHashTableIter hiter; + + g_hash_table_iter_init (&hiter, priv->rt6_temporary_not_available); + while (g_hash_table_iter_next (&hiter, (gpointer *) &o, NULL)) { + nm_ip6_config_add_route (composite, + NMP_OBJECT_CAST_IP6_ROUTE (o), + NULL); + } + } + + /* Merge user overrides into the composite config. For assumed connections, + * con_ip6_config is empty. */ + if (priv->con_ip6_config) { + nm_ip6_config_merge (composite, priv->con_ip6_config, NM_IP_CONFIG_MERGE_DEFAULT, + default_route_metric_penalty_get (self, AF_INET6)); + } + + if (commit) { + nm_ip6_config_add_dependent_routes (composite, + nm_device_get_route_table (self, AF_INET6, TRUE), + nm_device_get_route_metric (self, AF_INET6)); + } + + /* Allow setting MTU etc */ + if (commit) { + NMUtilsIPv6IfaceId iid; + + if (token && nm_utils_ipv6_interface_identifier_get_from_token (&iid, token)) { + nm_platform_link_set_ipv6_token (nm_device_get_platform (self), + nm_device_get_ip_ifindex (self), + iid); + } + } + + success = nm_device_set_ip6_config (self, composite, commit); + g_object_unref (composite); + if (commit) + priv->v6_commit_first_time = FALSE; + return success; +} + +static gboolean dhcp6_lease_change (NMDevice *self) { NMDevicePrivate *priv = NM_DEVICE_GET_PRIVATE (self); NMSettingsConnection *settings_connection; - if (!applied_config_get_current (&priv->dhcp6.ip6_config)) { + if (priv->dhcp6.ip6_config == NULL) { _LOGW (LOGD_DHCP6, "failed to get DHCPv6 config for rebind"); return FALSE; } @@ -7437,7 +6743,7 @@ dhcp6_lease_change (NMDevice *self) g_assert (settings_connection); /* Apply the updated config */ - if (!ip_config_merge_and_apply (self, AF_INET6, TRUE)) { + if (!ip6_config_merge_and_apply (self, TRUE)) { _LOGW (LOGD_DHCP6, "failed to update IPv6 config in response to DHCP event"); return FALSE; } @@ -7481,8 +6787,8 @@ dhcp6_fail (NMDevice *self, gboolean timeout) * on the interface. */ if ( priv->ip6_state == IP_DONE - && priv->con_ip_config_6 - && nm_ip6_config_get_num_addresses (priv->con_ip_config_6)) + && priv->con_ip6_config + && nm_ip6_config_get_num_addresses (priv->con_ip6_config)) goto clear_config; /* Fail the method in case of timeout or failure during initial @@ -7519,7 +6825,7 @@ dhcp6_fail (NMDevice *self, gboolean timeout) clear_config: /* The previous configuration is no longer valid */ if (priv->dhcp6.config) { - nm_dbus_object_clear_and_unexport (&priv->dhcp6.config); + nm_exported_object_clear_and_unexport (&priv->dhcp6.config); priv->dhcp6.config = nm_dhcp6_config_new (); _notify (self, PROP_DHCP6_CONFIG); } @@ -7571,16 +6877,16 @@ dhcp6_state_changed (NMDhcpClient *client, const NMPlatformIP6Address *a; nm_ip_config_iter_ip6_address_for_each (&ipconf_iter, ip6_config, &a) - applied_config_add_address (&priv->dhcp6.ip6_config, NM_PLATFORM_IP_ADDRESS_CAST (a)); + nm_ip6_config_add_address (priv->dhcp6.ip6_config, a); } else { + g_clear_object (&priv->dhcp6.ip6_config); g_clear_pointer (&priv->dhcp6.event_id, g_free); if (ip6_config) { - applied_config_init (&priv->dhcp6.ip6_config, ip6_config); + priv->dhcp6.ip6_config = g_object_ref (ip6_config); priv->dhcp6.event_id = g_strdup (event_id); nm_dhcp6_config_set_options (priv->dhcp6.config, options); _notify (self, PROP_DHCP6_CONFIG); - } else - applied_config_clear (&priv->dhcp6.ip6_config); + } } /* After long time we have been able to renew the lease: @@ -7590,7 +6896,7 @@ dhcp6_state_changed (NMDhcpClient *client, _set_ip_state (self, AF_INET6, IP_CONF); if (priv->ip6_state == IP_CONF) { - if (!applied_config_get_current (&priv->dhcp6.ip6_config)) { + if (priv->dhcp6.ip6_config == NULL) { nm_device_ip_method_failed (self, AF_INET6, NM_DEVICE_STATE_REASON_DHCP_FAILED); break; } @@ -7641,32 +6947,34 @@ dhcp6_start_with_link_ready (NMDevice *self, NMConnection *connection) { NMDevicePrivate *priv = NM_DEVICE_GET_PRIVATE (self); NMSettingIPConfig *s_ip6; - gs_unref_bytes GBytes *hwaddr = NULL; + GByteArray *tmp = NULL; + const guint8 *hw_addr; + size_t hw_addr_len = 0; const NMPlatformIP6Address *ll_addr = NULL; g_assert (connection); s_ip6 = nm_connection_get_setting_ip6_config (connection); g_assert (s_ip6); - if (priv->ext_ip6_config_captured) { - ll_addr = nm_ip6_config_find_first_address (priv->ext_ip6_config_captured, - NM_PLATFORM_MATCH_WITH_ADDRTYPE_LINKLOCAL - | NM_PLATFORM_MATCH_WITH_ADDRSTATE_NORMAL); - } + if (priv->ext_ip6_config_captured) + ll_addr = nm_ip6_config_get_address_first_nontentative (priv->ext_ip6_config_captured, TRUE); if (!ll_addr) { _LOGW (LOGD_DHCP6, "can't start DHCPv6: no link-local address"); return FALSE; } - hwaddr = nm_platform_link_get_address_as_bytes (nm_device_get_platform (self), - nm_device_get_ip_ifindex (self)); + hw_addr = nm_platform_link_get_address (nm_device_get_platform (self), nm_device_get_ip_ifindex (self), &hw_addr_len); + if (hw_addr_len) { + tmp = g_byte_array_sized_new (hw_addr_len); + g_byte_array_append (tmp, hw_addr, hw_addr_len); + } 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, + tmp, &ll_addr->address, nm_connection_get_uuid (connection), nm_device_get_route_table (self, AF_INET6, TRUE), @@ -7678,6 +6986,8 @@ dhcp6_start_with_link_ready (NMDevice *self, NMConnection *connection) (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); + if (tmp) + g_byte_array_free (tmp, TRUE); if (priv->dhcp6.client) { priv->dhcp6.state_sigid = g_signal_connect (priv->dhcp6.client, @@ -7703,11 +7013,11 @@ dhcp6_start (NMDevice *self, gboolean wait_for_ll) NMConnection *connection; NMSettingIPConfig *s_ip6; - nm_dbus_object_clear_and_unexport (&priv->dhcp6.config); + nm_exported_object_clear_and_unexport (&priv->dhcp6.config); priv->dhcp6.config = nm_dhcp6_config_new (); - nm_assert (!applied_config_get_current (&priv->dhcp6.ip6_config)); - applied_config_clear (&priv->dhcp6.ip6_config); + g_warn_if_fail (priv->dhcp6.ip6_config == NULL); + g_clear_object (&priv->dhcp6.ip6_config); g_clear_pointer (&priv->dhcp6.event_id, g_free); connection = nm_device_get_applied_connection (self); @@ -7718,12 +7028,17 @@ dhcp6_start (NMDevice *self, gboolean wait_for_ll) nm_device_add_pending_action (self, NM_PENDING_ACTION_DHCP6, TRUE); if (wait_for_ll) { + NMActStageReturn ret; + /* ensure link local is ready... */ - if (!linklocal6_start (self)) { - /* wait for the LL address to show up */ + ret = linklocal6_start (self); + if (ret == NM_ACT_STAGE_RETURN_POSTPONE) { + /* success; wait for the LL address to show up */ return TRUE; } - /* already have the LL address; kick off DHCP */ + + /* success; already have the LL address; kick off DHCP */ + g_assert (ret == NM_ACT_STAGE_RETURN_SUCCESS); } if (!dhcp6_start_with_link_ready (self, connection)) @@ -7785,19 +7100,19 @@ nm_device_use_ip6_subnet (NMDevice *self, const NMPlatformIP6Address *subnet) NMDevicePrivate *priv = NM_DEVICE_GET_PRIVATE (self); NMPlatformIP6Address address = *subnet; - if (!applied_config_get_current (&priv->ac_ip6_config)) - applied_config_init_new (&priv->ac_ip6_config, self, AF_INET6); + if (!priv->ac_ip6_config) + priv->ac_ip6_config = _ip6_config_new (self); /* Assign a ::1 address in the subnet for us. */ address.address.s6_addr32[3] |= htonl (1); - applied_config_add_address (&priv->ac_ip6_config, NM_PLATFORM_IP_ADDRESS_CAST (&address)); + nm_ip6_config_add_address (priv->ac_ip6_config, &address); _LOGD (LOGD_IP6, "ipv6-pd: using %s address (preferred for %u seconds)", nm_utils_inet6_ntop (&address.address, NULL), subnet->preferred); /* This also updates the ndisc if there are actual changes. */ - if (!ip_config_merge_and_apply (self, AF_INET6, TRUE)) + if (!ip6_config_merge_and_apply (self, TRUE)) _LOGW (LOGD_IP6, "ipv6-pd: failed applying IP6 config for connection sharing"); } @@ -7812,11 +7127,11 @@ nm_device_copy_ip6_dns_config (NMDevice *self, NMDevice *from_device) NMIP6Config *from_config = NULL; guint i, len; - if (applied_config_get_current (&priv->ac_ip6_config)) { - applied_config_reset_nameservers (&priv->ac_ip6_config); - applied_config_reset_searches (&priv->ac_ip6_config); + if (priv->ac_ip6_config) { + nm_ip6_config_reset_nameservers (priv->ac_ip6_config); + nm_ip6_config_reset_searches (priv->ac_ip6_config); } else - applied_config_init_new (&priv->ac_ip6_config, self, AF_INET6); + priv->ac_ip6_config = _ip6_config_new (self); if (from_device) from_config = nm_device_get_ip6_config (from_device); @@ -7825,28 +7140,34 @@ nm_device_copy_ip6_dns_config (NMDevice *self, NMDevice *from_device) len = nm_ip6_config_get_num_nameservers (from_config); for (i = 0; i < len; i++) { - applied_config_add_nameserver (&priv->ac_ip6_config, - (const NMIPAddr *) nm_ip6_config_get_nameserver (from_config, i)); + nm_ip6_config_add_nameserver (priv->ac_ip6_config, + nm_ip6_config_get_nameserver (from_config, i)); } len = nm_ip6_config_get_num_searches (from_config); for (i = 0; i < len; i++) { - applied_config_add_search (&priv->ac_ip6_config, - nm_ip6_config_get_search (from_config, i)); + nm_ip6_config_add_search (priv->ac_ip6_config, + nm_ip6_config_get_search (from_config, i)); } - if (!ip_config_merge_and_apply (self, AF_INET6, TRUE)) + if (!ip6_config_merge_and_apply (self, TRUE)) _LOGW (LOGD_IP6, "ipv6-pd: failed applying DNS config for connection sharing"); } /*****************************************************************************/ static void -linklocal6_failed (NMDevice *self) +linklocal6_cleanup (NMDevice *self) { NMDevicePrivate *priv = NM_DEVICE_GET_PRIVATE (self); nm_clear_g_source (&priv->linklocal6_timeout_id); +} + +static void +linklocal6_failed (NMDevice *self) +{ + linklocal6_cleanup (self); nm_device_activate_schedule_ip6_config_timeout (self); } @@ -7861,26 +7182,17 @@ linklocal6_timeout_cb (gpointer user_data) } static void -linklocal6_check_complete (NMDevice *self) +linklocal6_complete (NMDevice *self) { NMDevicePrivate *priv = NM_DEVICE_GET_PRIVATE (self); NMConnection *connection; const char *method; - if (!priv->linklocal6_timeout_id) { - /* we are not waiting for linklocal to complete. Nothing to do. */ - return; - } + g_assert (priv->linklocal6_timeout_id); + g_assert (priv->ext_ip6_config_captured); + g_assert (nm_ip6_config_get_address_first_nontentative (priv->ext_ip6_config_captured, TRUE)); - if ( !priv->ext_ip6_config_captured - || !nm_ip6_config_find_first_address (priv->ext_ip6_config_captured, - NM_PLATFORM_MATCH_WITH_ADDRTYPE_LINKLOCAL - | NM_PLATFORM_MATCH_WITH_ADDRSTATE_NORMAL)) { - /* we don't have a non-tentative link local address yet. Wait longer. */ - return; - } - - nm_clear_g_source (&priv->linklocal6_timeout_id); + linklocal6_cleanup (self); connection = nm_device_get_applied_connection (self); g_assert (connection); @@ -7890,9 +7202,12 @@ linklocal6_check_complete (NMDevice *self) _LOGD (LOGD_DEVICE, "linklocal6: waiting for link-local addresses successful, continue with method %s", method); if ( strcmp (method, NM_SETTING_IP6_CONFIG_METHOD_AUTO) == 0 - || strcmp (method, NM_SETTING_IP6_CONFIG_METHOD_SHARED) == 0) - addrconf6_start_with_link_ready (self); - else if (strcmp (method, NM_SETTING_IP6_CONFIG_METHOD_DHCP) == 0) { + || strcmp (method, NM_SETTING_IP6_CONFIG_METHOD_SHARED) == 0) { + if (!addrconf6_start_with_link_ready (self)) { + /* Time out IPv6 instead of failing the entire activation */ + nm_device_activate_schedule_ip6_config_timeout (self); + } + } else if (strcmp (method, NM_SETTING_IP6_CONFIG_METHOD_DHCP) == 0) { if (!dhcp6_start_with_link_ready (self, connection)) { /* Time out IPv6 instead of failing the entire activation */ nm_device_activate_schedule_ip6_config_timeout (self); @@ -7907,26 +7222,27 @@ static void check_and_add_ipv6ll_addr (NMDevice *self) { NMDevicePrivate *priv = NM_DEVICE_GET_PRIVATE (self); + int ip_ifindex = nm_device_get_ip_ifindex (self); struct in6_addr lladdr; NMConnection *connection; NMSettingIP6Config *s_ip6 = NULL; GError *error = NULL; - const char *addr_type; - if (!priv->ipv6ll_handle) + if (priv->nm_ipv6ll == FALSE) return; - if ( priv->ext_ip6_config_captured - && nm_ip6_config_find_first_address (priv->ext_ip6_config_captured, - NM_PLATFORM_MATCH_WITH_ADDRTYPE_LINKLOCAL - | NM_PLATFORM_MATCH_WITH_ADDRSTATE_NORMAL - | NM_PLATFORM_MATCH_WITH_ADDRSTATE_TENTATIVE)) { - /* Already have an LL address, nothing to do */ - return; - } + if (priv->ext_ip6_config_captured) { + NMDedupMultiIter ipconf_iter; + const NMPlatformIP6Address *addr; - priv->ipv6ll_has = FALSE; - memset (&priv->ipv6ll_addr, 0, sizeof (priv->ipv6ll_addr)); + nm_ip_config_iter_ip6_address_for_each (&ipconf_iter, priv->ext_ip6_config_captured, &addr) { + if ( IN6_IS_ADDR_LINKLOCAL (&addr->address) + && !(addr->n_ifa_flags & IFA_F_DADFAILED)) { + /* Already have an LL address, nothing to do */ + return; + } + } + } memset (&lladdr, 0, sizeof (lladdr)); lladdr.s6_addr16[0] = htons (0xfe80); @@ -7952,7 +7268,7 @@ check_and_add_ipv6ll_addr (NMDevice *self) linklocal6_failed (self); return; } - addr_type = "stable-privacy"; + _LOGD (LOGD_IP6, "linklocal6: using IPv6 stable-privacy addressing"); } else { NMUtilsIPv6IfaceId iid; @@ -7968,30 +7284,37 @@ check_and_add_ipv6ll_addr (NMDevice *self) _LOGW (LOGD_IP6, "linklocal6: failed to get interface identifier; IPv6 cannot continue"); return; } + _LOGD (LOGD_IP6, "linklocal6: using EUI-64 identifier to generate IPv6LL address"); + nm_utils_ipv6_addr_set_interface_identifier (&lladdr, iid); - addr_type = "EUI-64"; } - _LOGD (LOGD_IP6, "linklocal6: generated %s IPv6LL address %s", addr_type, nm_utils_inet6_ntop (&lladdr, NULL)); - priv->ipv6ll_has = TRUE; - priv->ipv6ll_addr = lladdr; - ip_config_merge_and_apply (self, AF_INET6, TRUE); + _LOGD (LOGD_IP6, "linklocal6: adding IPv6LL address %s", nm_utils_inet6_ntop (&lladdr, NULL)); + if (!nm_platform_ip6_address_add (nm_device_get_platform (self), + ip_ifindex, + lladdr, + 64, + in6addr_any, + NM_PLATFORM_LIFETIME_PERMANENT, + NM_PLATFORM_LIFETIME_PERMANENT, + 0)) { + _LOGW (LOGD_IP6, "failed to add IPv6 link-local address %s", + nm_utils_inet6_ntop (&lladdr, NULL)); + } } -static gboolean +static NMActStageReturn linklocal6_start (NMDevice *self) { NMDevicePrivate *priv = NM_DEVICE_GET_PRIVATE (self); NMConnection *connection; const char *method; - nm_clear_g_source (&priv->linklocal6_timeout_id); + linklocal6_cleanup (self); if ( priv->ext_ip6_config_captured - && nm_ip6_config_find_first_address (priv->ext_ip6_config_captured, - NM_PLATFORM_MATCH_WITH_ADDRTYPE_LINKLOCAL - | NM_PLATFORM_MATCH_WITH_ADDRSTATE_NORMAL)) - return TRUE; + && nm_ip6_config_get_address_first_nontentative (priv->ext_ip6_config_captured, TRUE)) + return NM_ACT_STAGE_RETURN_SUCCESS; connection = nm_device_get_applied_connection (self); g_assert (connection); @@ -8007,7 +7330,8 @@ linklocal6_start (NMDevice *self) * (rh #1101809) */ priv->linklocal6_timeout_id = g_timeout_add_seconds (15, linklocal6_timeout_cb, self); - return FALSE; + + return NM_ACT_STAGE_RETURN_POSTPONE; } /*****************************************************************************/ @@ -8072,7 +7396,7 @@ _set_mtu (NMDevice *self, guint32 mtu) if (priv->master) { /* changing the MTU of a slave, might require the master to reset - * its MTU. Note that the master usually cannot set a MTU larger + * it's MTU. Note that the master usually cannot set a MTU larger * then the slave's. Hence, when the slave increases the MTU, * master might want to retry setting the MTU. */ nm_device_commit_mtu (priv->master); @@ -8249,7 +7573,7 @@ nm_device_commit_mtu (NMDevice *self) if ( state >= NM_DEVICE_STATE_CONFIG && state < NM_DEVICE_STATE_DEACTIVATING) { _LOGT (LOGD_DEVICE, "mtu: commit-mtu..."); - _commit_mtu (self, NM_DEVICE_GET_PRIVATE (self)->ip_config_4); + _commit_mtu (self, NM_DEVICE_GET_PRIVATE (self)->ip4_config); } else _LOGT (LOGD_DEVICE, "mtu: commit-mtu... skip due to state %s", nm_device_state_to_str (state)); } @@ -8261,10 +7585,10 @@ ndisc_config_changed (NMNDisc *ndisc, const NMNDiscData *rdata, guint changed_in NMDevicePrivate *priv = NM_DEVICE_GET_PRIVATE (self); guint i; - g_return_if_fail (priv->act_request.obj); + g_return_if_fail (priv->act_request); - if (!applied_config_get_current (&priv->ac_ip6_config)) - applied_config_init_new (&priv->ac_ip6_config, self, AF_INET6); + if (!priv->ac_ip6_config) + priv->ac_ip6_config = _ip6_config_new (self); if (changed & NM_NDISC_CONFIG_ADDRESSES) { guint8 plen; @@ -8285,23 +7609,16 @@ ndisc_config_changed (NMNDisc *ndisc, const NMNDiscData *rdata, guint changed_in } else plen = 128; - nm_ip6_config_reset_addresses_ndisc ((NMIP6Config *) priv->ac_ip6_config.orig, + nm_ip6_config_reset_addresses_ndisc (priv->ac_ip6_config, rdata->addresses, rdata->addresses_n, plen, ifa_flags); - if (priv->ac_ip6_config.current) { - nm_ip6_config_reset_addresses_ndisc ((NMIP6Config *) priv->ac_ip6_config.current, - rdata->addresses, - rdata->addresses_n, - plen, - ifa_flags); - } } if (NM_FLAGS_ANY (changed, NM_NDISC_CONFIG_ROUTES | NM_NDISC_CONFIG_GATEWAYS)) { - nm_ip6_config_reset_routes_ndisc ((NMIP6Config *) priv->ac_ip6_config.orig, + nm_ip6_config_reset_routes_ndisc (priv->ac_ip6_config, rdata->gateways, rdata->gateways_n, rdata->routes, @@ -8310,34 +7627,22 @@ ndisc_config_changed (NMNDisc *ndisc, const NMNDiscData *rdata, guint changed_in nm_device_get_route_metric (self, AF_INET6), nm_platform_check_kernel_support (nm_device_get_platform (self), NM_PLATFORM_KERNEL_SUPPORT_RTA_PREF)); - if (priv->ac_ip6_config.current) { - nm_ip6_config_reset_routes_ndisc ((NMIP6Config *) priv->ac_ip6_config.current, - rdata->gateways, - rdata->gateways_n, - rdata->routes, - rdata->routes_n, - nm_device_get_route_table (self, AF_INET6, TRUE), - nm_device_get_route_metric (self, AF_INET6), - nm_platform_check_kernel_support (nm_device_get_platform (self), - NM_PLATFORM_KERNEL_SUPPORT_RTA_PREF)); - } - } if (changed & NM_NDISC_CONFIG_DNS_SERVERS) { /* Rebuild DNS server list from neighbor discovery cache. */ - applied_config_reset_nameservers (&priv->ac_ip6_config); + nm_ip6_config_reset_nameservers (priv->ac_ip6_config); for (i = 0; i < rdata->dns_servers_n; i++) - applied_config_add_nameserver (&priv->ac_ip6_config, (const NMIPAddr *) &rdata->dns_servers[i].address); + nm_ip6_config_add_nameserver (priv->ac_ip6_config, &rdata->dns_servers[i].address); } if (changed & NM_NDISC_CONFIG_DNS_DOMAINS) { /* Rebuild domain list from neighbor discovery cache. */ - applied_config_reset_searches (&priv->ac_ip6_config); + nm_ip6_config_reset_searches (priv->ac_ip6_config); for (i = 0; i < rdata->dns_domains_n; i++) - applied_config_add_search (&priv->ac_ip6_config, rdata->dns_domains[i].domain); + nm_ip6_config_add_search (priv->ac_ip6_config, rdata->dns_domains[i].domain); } if (changed & NM_NDISC_CONFIG_DHCP_LEVEL) { @@ -8387,21 +7692,16 @@ ndisc_ra_timeout (NMNDisc *ndisc, NMDevice *self) * ever receive one, then time out IPv6. But if there is other * IPv6 configuration, like manual IPv6 addresses or external IPv6 * config, consider that sufficient for IPv6 success. - * - * FIXME: it doesn't seem correct to determine this based on which - * addresses we find inside priv->ip_config_6. */ - if ( priv->ip_config_6 - && nm_ip6_config_find_first_address (priv->ip_config_6, - NM_PLATFORM_MATCH_WITH_ADDRTYPE_NORMAL - | NM_PLATFORM_MATCH_WITH_ADDRSTATE__ANY)) + if ( priv->ip6_config + && nm_ip6_config_get_address_first_nontentative (priv->ip6_config, FALSE)) nm_device_activate_schedule_ip6_config_result (self); else nm_device_activate_schedule_ip6_config_timeout (self); } } -static void +static gboolean addrconf6_start_with_link_ready (NMDevice *self) { NMDevicePrivate *priv = NM_DEVICE_GET_PRIVATE (self); @@ -8419,10 +7719,12 @@ addrconf6_start_with_link_ready (NMDevice *self) } /* Apply any manual configuration before starting RA */ - if (!ip_config_merge_and_apply (self, AF_INET6, TRUE)) + if (!ip6_config_merge_and_apply (self, TRUE)) { _LOGW (LOGD_IP6, "failed to apply manual IPv6 configuration"); + g_clear_object (&priv->con_ip6_config); + } - /* FIXME: These sysctls would probably be better set by the lndp ndisc itself. */ + /* XXX: These sysctls would probably be better set by the lndp ndisc itself. */ switch (nm_ndisc_get_node_type (priv->ndisc)) { case NM_NDISC_NODE_TYPE_HOST: /* Accepting prefixes from discovered routers. */ @@ -8453,7 +7755,7 @@ addrconf6_start_with_link_ready (NMDevice *self) ndisc_set_router_config (priv->ndisc, self); nm_ndisc_start (priv->ndisc); - return; + return TRUE; } static NMNDiscNodeType @@ -8476,6 +7778,7 @@ addrconf6_start (NMDevice *self, NMSettingIP6ConfigPrivacy use_tempaddr) { NMDevicePrivate *priv = NM_DEVICE_GET_PRIVATE (self); NMConnection *connection; + NMActStageReturn ret; NMSettingIP6Config *s_ip6 = NULL; GError *error = NULL; NMUtilsStableType stable_type; @@ -8484,8 +7787,11 @@ addrconf6_start (NMDevice *self, NMSettingIP6ConfigPrivacy use_tempaddr) connection = nm_device_get_applied_connection (self); g_assert (connection); - nm_assert (!applied_config_get_current (&priv->ac_ip6_config)); - applied_config_clear (&priv->ac_ip6_config); + g_warn_if_fail (priv->ac_ip6_config == NULL); + if (priv->ac_ip6_config) { + g_object_unref (priv->ac_ip6_config); + priv->ac_ip6_config = NULL; + } g_clear_pointer (&priv->rt6_temporary_not_available, g_hash_table_unref); nm_clear_g_source (&priv->rt6_temporary_not_available_id); @@ -8522,14 +7828,15 @@ addrconf6_start (NMDevice *self, NMSettingIP6ConfigPrivacy use_tempaddr) nm_device_add_pending_action (self, NM_PENDING_ACTION_AUTOCONF6, TRUE); /* ensure link local is ready... */ - if (!linklocal6_start (self)) { - /* wait for the LL address to show up */ + ret = linklocal6_start (self); + if (ret == NM_ACT_STAGE_RETURN_POSTPONE) { + /* success; wait for the LL address to show up */ return TRUE; } - /* already have the LL address; kick off neighbor discovery */ - addrconf6_start_with_link_ready (self); - return TRUE; + /* success; already have the LL address; kick off neighbor discovery */ + g_assert (ret == NM_ACT_STAGE_RETURN_SUCCESS); + return addrconf6_start_with_link_ready (self); } static void @@ -8542,7 +7849,7 @@ addrconf6_cleanup (NMDevice *self) nm_device_remove_pending_action (self, NM_PENDING_ACTION_AUTOCONF6, FALSE); - applied_config_clear (&priv->ac_ip6_config); + g_clear_object (&priv->ac_ip6_config); g_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); @@ -8596,8 +7903,7 @@ restore_ip6_properties (NMDevice *self) g_hash_table_iter_init (&iter, priv->ip6_saved_properties); while (g_hash_table_iter_next (&iter, &key, &value)) { /* Don't touch "disable_ipv6" if we're doing userland IPv6LL */ - if ( priv->ipv6ll_handle - && nm_streq (key, "disable_ipv6")) + if (priv->nm_ipv6ll && strcmp (key, "disable_ipv6") == 0) continue; nm_device_ipv6_sysctl_set (self, key, value); } @@ -8607,7 +7913,7 @@ static inline void set_disable_ipv6 (NMDevice *self, const char *value) { /* We only touch disable_ipv6 when NM is not managing the IPv6LL address */ - if (!NM_DEVICE_GET_PRIVATE (self)->ipv6ll_handle) + if (NM_DEVICE_GET_PRIVATE (self)->nm_ipv6ll == FALSE) nm_device_ipv6_sysctl_set (self, "disable_ipv6", value); } @@ -8622,7 +7928,7 @@ set_nm_ipv6ll (NMDevice *self, gboolean enable) NM_PLATFORM_KERNEL_SUPPORT_USER_IPV6LL)) return; - priv->ipv6ll_handle = enable; + priv->nm_ipv6ll = enable; if (ifindex > 0) { NMPlatformError plerr; const char *detail = enable ? "enable" : "disable"; @@ -8771,14 +8077,14 @@ act_stage3_ip6_config_start (NMDevice *self, if (strcmp (method, NM_SETTING_IP6_CONFIG_METHOD_IGNORE) == 0) { if ( !priv->master && !nm_device_sys_iface_state_is_external (self)) { - gboolean ipv6ll_handle_old = priv->ipv6ll_handle; + gboolean old_nm_ipv6ll = priv->nm_ipv6ll; /* When activating an IPv6 'ignore' connection we need to revert back * to kernel IPv6LL, but the kernel won't actually assign an address * to the interface until disable_ipv6 is bounced. */ set_nm_ipv6ll (self, FALSE); - if (ipv6ll_handle_old) + if (old_nm_ipv6ll == TRUE) nm_device_ipv6_sysctl_set (self, "disable_ipv6", "1"); restore_ip6_properties (self); } @@ -8789,7 +8095,7 @@ act_stage3_ip6_config_start (NMDevice *self, * expose any ipv6 sysctls or allow presence of any addresses on the interface, * including LL, which * would make it impossible to autoconfigure MTU to a * correct value. */ - _commit_mtu (self, priv->ip_config_4); + _commit_mtu (self, priv->ip4_config); /* Any method past this point requires an IPv6LL address. Use NM-controlled * IPv6LL if this is not an assumed connection, since assumed connections @@ -8810,6 +8116,7 @@ act_stage3_ip6_config_start (NMDevice *self, priv->ext_ip6_config_captured = nm_ip6_config_capture (nm_device_get_multi_index (self), nm_device_get_platform (self), nm_device_get_ip_ifindex (self), + FALSE, NM_SETTING_IP6_CONFIG_PRIVACY_UNKNOWN); ip6_privacy = _ip6_privacy_get (self); @@ -8822,9 +8129,7 @@ act_stage3_ip6_config_start (NMDevice *self, } else ret = NM_ACT_STAGE_RETURN_POSTPONE; } else if (strcmp (method, NM_SETTING_IP6_CONFIG_METHOD_LINK_LOCAL) == 0) { - ret = linklocal6_start (self) - ? NM_ACT_STAGE_RETURN_SUCCESS - : NM_ACT_STAGE_RETURN_POSTPONE; + ret = linklocal6_start (self); } else if (strcmp (method, NM_SETTING_IP6_CONFIG_METHOD_DHCP) == 0) { priv->dhcp6.mode = NM_NDISC_DHCP_LEVEL_MANAGED; if (!dhcp6_start (self, TRUE)) { @@ -8934,8 +8239,8 @@ nm_device_activate_stage3_ip6_start (NMDevice *self) /* Here we get a static IPv6 config, like for Shared where it's * autogenerated or from modems where it comes from ModemManager. */ - nm_assert (!applied_config_get_current (&priv->ac_ip6_config)); - applied_config_init (&priv->ac_ip6_config, ip6_config); + g_warn_if_fail (priv->ac_ip6_config == NULL); + priv->ac_ip6_config = ip6_config; nm_device_activate_schedule_ip6_config_result (self); } else if (ret == NM_ACT_STAGE_RETURN_IP_DONE) { _set_ip_state (self, AF_INET6, IP_DONE); @@ -9073,7 +8378,7 @@ nm_device_activate_schedule_stage3_ip_config_start (NMDevice *self) g_return_if_fail (NM_IS_DEVICE (self)); priv = NM_DEVICE_GET_PRIVATE (self); - g_return_if_fail (priv->act_request.obj); + g_return_if_fail (priv->act_request); /* Add the interface to the specified firewall zone */ if (priv->fw_state == FIREWALL_STATE_UNMANAGED) { @@ -9145,7 +8450,7 @@ nm_device_activate_schedule_ip4_config_timeout (NMDevice *self) g_return_if_fail (NM_IS_DEVICE (self)); priv = NM_DEVICE_GET_PRIVATE (self); - g_return_if_fail (priv->act_request.obj); + g_return_if_fail (priv->act_request); activation_source_schedule (self, activate_stage4_ip4_config_timeout, AF_INET); } @@ -9201,7 +8506,7 @@ nm_device_activate_schedule_ip6_config_timeout (NMDevice *self) g_return_if_fail (NM_IS_DEVICE (self)); priv = NM_DEVICE_GET_PRIVATE (self); - g_return_if_fail (priv->act_request.obj); + g_return_if_fail (priv->act_request); activation_source_schedule (self, activate_stage4_ip6_config_timeout, AF_INET6); } @@ -9319,9 +8624,9 @@ arp_cleanup (NMDevice *self) { NMDevicePrivate *priv = NM_DEVICE_GET_PRIVATE (self); - if (priv->acd.announcing) { - nm_acd_manager_destroy (priv->acd.announcing); - priv->acd.announcing = NULL; + if (priv->arping.announcing) { + nm_arping_manager_destroy (priv->arping.announcing); + priv->arping.announcing = NULL; } } @@ -9341,7 +8646,7 @@ arp_announce (NMDevice *self) nm_device_get_ip_ifindex (self), &hw_addr_len); - if (!hw_addr || hw_addr_len != ETH_ALEN) + if (!hw_addr_len || !hw_addr) return; /* We only care about manually-configured addresses; DHCP- and autoip-configured @@ -9357,19 +8662,19 @@ arp_announce (NMDevice *self) if (num == 0) return; - priv->acd.announcing = nm_acd_manager_new (nm_device_get_ip_ifindex (self), hw_addr, hw_addr_len); + priv->arping.announcing = nm_arping_manager_new (nm_device_get_ip_ifindex (self)); for (i = 0; i < num; i++) { NMIPAddress *ip = nm_setting_ip_config_get_address (s_ip4, i); in_addr_t addr; if (inet_pton (AF_INET, nm_ip_address_get_address (ip), &addr) == 1) - nm_acd_manager_add_address (priv->acd.announcing, addr); + nm_arping_manager_add_address (priv->arping.announcing, addr); else g_warn_if_reached (); } - nm_acd_manager_announce_addresses (priv->acd.announcing); + nm_arping_manager_announce_addresses (priv->arping.announcing); } static void @@ -9394,7 +8699,8 @@ activate_stage5_ip4_config_result (NMDevice *self) _LOGW (LOGD_DEVICE, "interface %s not up for IP configuration", nm_device_get_ip_iface (self)); } - if (!ip_config_merge_and_apply (self, AF_INET, TRUE)) { + /* NULL to use the existing priv->dev_ip4_config */ + if (!ip4_config_merge_and_apply (self, TRUE)) { _LOGD (LOGD_DEVICE | LOGD_IP4, "Activation: Stage 5 of 5 (IPv4 Commit) failed"); nm_device_ip_method_failed (self, AF_INET, NM_DEVICE_STATE_REASON_CONFIG_FAILED); return; @@ -9406,7 +8712,7 @@ activate_stage5_ip4_config_result (NMDevice *self) if (strcmp (method, NM_SETTING_IP4_CONFIG_METHOD_SHARED) == 0) { gs_free_error GError *error = NULL; - if (!start_sharing (self, priv->ip_config_4, &error)) { + if (!start_sharing (self, priv->ip4_config, &error)) { _LOGW (LOGD_SHARING, "Activation: Stage 5 of 5 (IPv4 Commit) start sharing failed: %s", error->message); nm_device_ip_method_failed (self, AF_INET, NM_DEVICE_STATE_REASON_SHARED_START_FAILED); return; @@ -9442,7 +8748,10 @@ nm_device_activate_schedule_ip4_config_result (NMDevice *self, NMIP4Config *conf g_return_if_fail (NM_IS_DEVICE (self)); priv = NM_DEVICE_GET_PRIVATE (self); - applied_config_init (&priv->dev_ip4_config, config); + g_clear_object (&priv->dev_ip4_config); + if (config) + priv->dev_ip4_config = g_object_ref (config); + activation_source_schedule (self, activate_stage5_ip4_config_result, AF_INET); } @@ -9467,32 +8776,6 @@ nm_device_activate_ip4_state_done (NMDevice *self) return NM_DEVICE_GET_PRIVATE (self)->ip4_state == IP_DONE; } -static void -dad6_add_pending_address (NMDevice *self, - NMPlatform *platform, - int ifindex, - const struct in6_addr *address, - NMIP6Config **dad6_config) -{ - const NMPlatformIP6Address *pl_addr; - - pl_addr = nm_platform_ip6_address_get (platform, - ifindex, - *address); - if ( pl_addr - && NM_FLAGS_HAS (pl_addr->n_ifa_flags, IFA_F_TENTATIVE) - && !NM_FLAGS_HAS (pl_addr->n_ifa_flags, IFA_F_DADFAILED) - && !NM_FLAGS_HAS (pl_addr->n_ifa_flags, IFA_F_OPTIMISTIC)) { - _LOGt (LOGD_DEVICE, "IPv6 DAD: pending address %s", - nm_platform_ip6_address_to_string (pl_addr, NULL, 0)); - - if (!*dad6_config) - *dad6_config = _ip6_config_new (self); - - nm_ip6_config_add_address (*dad6_config, pl_addr); - } -} - /* * Returns a NMIP6Config containing NM-configured addresses which * have the tentative flag, or NULL if none is present. @@ -9501,43 +8784,42 @@ static NMIP6Config * dad6_get_pending_addresses (NMDevice *self) { NMDevicePrivate *priv = NM_DEVICE_GET_PRIVATE (self); - NMIP6Config *confs[] = { (NMIP6Config *) applied_config_get_current (&priv->ac_ip6_config), - (NMIP6Config *) applied_config_get_current (&priv->dhcp6.ip6_config), - priv->con_ip_config_6, - (NMIP6Config *) applied_config_get_current (&priv->wwan_ip_config_6) }; - const NMPlatformIP6Address *addr; + NMIP6Config *confs[] = { priv->ac_ip6_config, + priv->dhcp6.ip6_config, + priv->con_ip6_config, + priv->wwan_ip6_config }; + const NMPlatformIP6Address *addr, *pl_addr; NMIP6Config *dad6_config = NULL; NMDedupMultiIter ipconf_iter; guint i; int ifindex; - NMPlatform *platform; ifindex = nm_device_get_ip_ifindex (self); g_return_val_if_fail (ifindex > 0, NULL); - platform = nm_device_get_platform (self); - - if (priv->ipv6ll_has) { - dad6_add_pending_address (self, - platform, - ifindex, - &priv->ipv6ll_addr, - &dad6_config); - } - /* We are interested only in addresses that we have explicitly configured, * not in externally added ones. */ for (i = 0; i < G_N_ELEMENTS (confs); i++) { - if (!confs[i]) - continue; - - nm_ip_config_iter_ip6_address_for_each (&ipconf_iter, confs[i], &addr) { - dad6_add_pending_address (self, - platform, - ifindex, - &addr->address, - &dad6_config); + if (confs[i]) { + + nm_ip_config_iter_ip6_address_for_each (&ipconf_iter, confs[i], &addr) { + pl_addr = nm_platform_ip6_address_get (nm_device_get_platform (self), + ifindex, + addr->address); + if ( pl_addr + && NM_FLAGS_HAS (pl_addr->n_ifa_flags, IFA_F_TENTATIVE) + && !NM_FLAGS_HAS (pl_addr->n_ifa_flags, IFA_F_DADFAILED) + && !NM_FLAGS_HAS (pl_addr->n_ifa_flags, IFA_F_OPTIMISTIC)) { + _LOGt (LOGD_DEVICE, "IPv6 DAD: pending address %s", + nm_platform_ip6_address_to_string (pl_addr, NULL, 0)); + + if (!dad6_config) + dad6_config = _ip6_config_new (self); + + nm_ip6_config_add_address (dad6_config, pl_addr); + } + } } } @@ -9569,10 +8851,10 @@ activate_stage5_ip6_config_commit (NMDevice *self) _LOGW (LOGD_DEVICE, "interface %s not up for IP configuration", nm_device_get_ip_iface (self)); } - if (ip_config_merge_and_apply (self, AF_INET6, TRUE)) { + if (ip6_config_merge_and_apply (self, TRUE)) { if ( priv->dhcp6.mode != NM_NDISC_DHCP_LEVEL_NONE && priv->ip6_state == IP_CONF) { - if (applied_config_get_current (&priv->dhcp6.ip6_config)) { + if (priv->dhcp6.ip6_config) { /* If IPv6 wasn't the first IP to complete, and DHCP was used, * then ensure dispatcher scripts get the DHCP lease information. */ @@ -9659,26 +8941,43 @@ nm_device_activate_ip6_state_done (NMDevice *self) /*****************************************************************************/ static void +act_request_set_cb (NMActRequest *act_request, + GParamSpec *pspec, + NMDevice *self) +{ + _notify (self, PROP_ACTIVE_CONNECTION); +} + +static void act_request_set (NMDevice *self, NMActRequest *act_request) { NMDevicePrivate *priv; + gs_unref_object NMActRequest *old_act_requst = NULL; nm_assert (NM_IS_DEVICE (self)); nm_assert (!act_request || NM_IS_ACT_REQUEST (act_request)); priv = NM_DEVICE_GET_PRIVATE (self); - if ( !priv->act_request.visible - && priv->act_request.obj == act_request) + if ( !priv->act_request_public + && priv->act_request == act_request) return; /* always clear the public flag. The few callers that set a new @act_request * don't want that the property is public yet. */ - nm_dbus_track_obj_path_set (&priv->act_request, - act_request, - FALSE); + priv->act_request_public = FALSE; + + nm_clear_g_signal_handler (priv->act_request, &priv->act_request_id); + + old_act_requst = priv->act_request; + priv->act_request = nm_g_object_ref (act_request); if (act_request) { + priv->act_request_id = g_signal_connect (act_request, + "notify::"NM_EXPORTED_OBJECT_PATH, + G_CALLBACK (act_request_set_cb), + self); + switch (nm_active_connection_get_activation_type (NM_ACTIVE_CONNECTION (act_request))) { case NM_ACTIVATION_TYPE_EXTERNAL: break; @@ -9695,6 +8994,8 @@ act_request_set (NMDevice *self, NMActRequest *act_request) break; } } + + _notify (self, PROP_ACTIVE_CONNECTION); } static void @@ -9720,9 +9021,9 @@ _update_ip4_address (NMDevice *self) g_return_if_fail (NM_IS_DEVICE (self)); - if ( priv->ip_config_4 + if ( priv->ip4_config && ip_config_valid (priv->state) - && (address = nm_ip4_config_get_first_address (priv->ip_config_4))) { + && (address = nm_ip4_config_get_first_address (priv->ip4_config))) { if (address->address != priv->ip4_address) { priv->ip4_address = address->address; _notify (self, PROP_IP4_ADDRESS); @@ -9816,31 +9117,37 @@ delete_on_deactivate_check_and_schedule (NMDevice *self, int ifindex) } static void -_cleanup_ip_pre (NMDevice *self, int addr_family, CleanupType cleanup_type) +_cleanup_ip4_pre (NMDevice *self, CleanupType cleanup_type) { NMDevicePrivate *priv = NM_DEVICE_GET_PRIVATE (self); - const gboolean IS_IPv4 = (addr_family == AF_INET); - _set_ip_state (self, addr_family, IP_NONE); + _set_ip_state (self, AF_INET, IP_NONE); - if (nm_clear_g_source (&priv->queued_ip_config_id_x[IS_IPv4])) { - _LOGD (LOGD_DEVICE, "clearing queued IP%c config change", - nm_utils_addr_family_to_char (addr_family)); - } + if (nm_clear_g_source (&priv->queued_ip4_config_id)) + _LOGD (LOGD_DEVICE, "clearing queued IP4 config change"); + priv->queued_ip4_config_pending = FALSE; - if (IS_IPv4) { - priv->queued_ip4_config_pending = FALSE; - dhcp4_cleanup (self, cleanup_type, FALSE); - arp_cleanup (self); - dnsmasq_cleanup (self); - ipv4ll_cleanup (self); - } else { - priv->queued_ip6_config_pending = FALSE; - g_clear_object (&priv->dad6_ip6_config); - dhcp6_cleanup (self, cleanup_type, FALSE); - nm_clear_g_source (&priv->linklocal6_timeout_id); - addrconf6_cleanup (self); - } + dhcp4_cleanup (self, cleanup_type, FALSE); + arp_cleanup (self); + dnsmasq_cleanup (self); + ipv4ll_cleanup (self); +} + +static void +_cleanup_ip6_pre (NMDevice *self, CleanupType cleanup_type) +{ + NMDevicePrivate *priv = NM_DEVICE_GET_PRIVATE (self); + + _set_ip_state (self, AF_INET6, IP_NONE); + + if (nm_clear_g_source (&priv->queued_ip6_config_id)) + _LOGD (LOGD_DEVICE, "clearing queued IP6 config change"); + priv->queued_ip6_config_pending = FALSE; + + g_clear_object (&priv->dad6_ip6_config); + dhcp6_cleanup (self, cleanup_type, FALSE); + linklocal6_cleanup (self); + addrconf6_cleanup (self); } gboolean @@ -9859,7 +9166,7 @@ _nm_device_hash_check_invalid_keys (GHashTable *hash, const char *setting_name, gs_unref_hashtable GHashTable *check_dups = g_hash_table_new_full (nm_str_hash, g_str_equal, NULL, NULL); for (i = 0; argv[i]; i++) { - if (!g_hash_table_add (check_dups, (char *) argv[i])) + if (!nm_g_hash_table_add (check_dups, (char *) argv[i])) nm_assert (FALSE); } nm_assert (g_hash_table_size (check_dups) > 0); @@ -9910,7 +9217,8 @@ _nm_device_hash_check_invalid_keys (GHashTable *hash, const char *setting_name, void nm_device_reactivate_ip4_config (NMDevice *self, NMSettingIPConfig *s_ip4_old, - NMSettingIPConfig *s_ip4_new) + NMSettingIPConfig *s_ip4_new, + gboolean force_restart) { NMDevicePrivate *priv; const char *method_old, *method_new; @@ -9919,31 +9227,31 @@ nm_device_reactivate_ip4_config (NMDevice *self, priv = NM_DEVICE_GET_PRIVATE (self); if (priv->ip4_state != IP_NONE) { - g_clear_object (&priv->con_ip_config_4); - g_clear_object (&priv->ext_ip_config_4); - g_clear_object (&priv->dev_ip4_config.current); - g_clear_object (&priv->wwan_ip_config_4.current); - priv->con_ip_config_4 = _ip4_config_new (self); - nm_ip4_config_merge_setting (priv->con_ip_config_4, + g_clear_object (&priv->con_ip4_config); + g_clear_object (&priv->ext_ip4_config); + priv->con_ip4_config = _ip4_config_new (self); + nm_ip4_config_merge_setting (priv->con_ip4_config, s_ip4_new, - _get_mdns (self), nm_device_get_route_table (self, AF_INET, TRUE), nm_device_get_route_metric (self, AF_INET)); - method_old = s_ip4_old - ? nm_setting_ip_config_get_method (s_ip4_old) - : NM_SETTING_IP4_CONFIG_METHOD_DISABLED; - method_new = s_ip4_new - ? nm_setting_ip_config_get_method (s_ip4_new) - : NM_SETTING_IP4_CONFIG_METHOD_DISABLED; + if (!force_restart) { + method_old = s_ip4_old + ? nm_setting_ip_config_get_method (s_ip4_old) + : NM_SETTING_IP4_CONFIG_METHOD_DISABLED; + method_new = s_ip4_new + ? nm_setting_ip_config_get_method (s_ip4_new) + : NM_SETTING_IP4_CONFIG_METHOD_DISABLED; + force_restart = !nm_streq0 (method_old, method_new); + } - if (!nm_streq0 (method_old, method_new)) { - _cleanup_ip_pre (self, AF_INET, CLEANUP_TYPE_DECONFIGURE); + if (force_restart) { + _cleanup_ip4_pre (self, CLEANUP_TYPE_DECONFIGURE); _set_ip_state (self, AF_INET, IP_WAIT); if (!nm_device_activate_stage3_ip4_start (self)) _LOGW (LOGD_IP4, "Failed to apply IPv4 configuration"); } else { - if (!ip_config_merge_and_apply (self, AF_INET, TRUE)) + if (!ip4_config_merge_and_apply (self, TRUE)) _LOGW (LOGD_IP4, "Failed to reapply IPv4 configuration"); } } @@ -9952,7 +9260,8 @@ nm_device_reactivate_ip4_config (NMDevice *self, void nm_device_reactivate_ip6_config (NMDevice *self, NMSettingIPConfig *s_ip6_old, - NMSettingIPConfig *s_ip6_new) + NMSettingIPConfig *s_ip6_new, + gboolean force_restart) { NMDevicePrivate *priv; const char *method_old, *method_new; @@ -9961,34 +9270,31 @@ nm_device_reactivate_ip6_config (NMDevice *self, priv = NM_DEVICE_GET_PRIVATE (self); if (priv->ip6_state != IP_NONE) { - g_clear_object (&priv->con_ip_config_6); - g_clear_object (&priv->ext_ip_config_6); - g_clear_object (&priv->ac_ip6_config.current); - g_clear_object (&priv->dhcp6.ip6_config.current); - g_clear_object (&priv->wwan_ip_config_6.current); - if ( priv->ipv6ll_handle - && !IN6_IS_ADDR_UNSPECIFIED (&priv->ipv6ll_addr)) - priv->ipv6ll_has = TRUE; - priv->con_ip_config_6 = _ip6_config_new (self); - nm_ip6_config_merge_setting (priv->con_ip_config_6, + g_clear_object (&priv->con_ip6_config); + g_clear_object (&priv->ext_ip6_config); + priv->con_ip6_config = _ip6_config_new (self); + nm_ip6_config_merge_setting (priv->con_ip6_config, s_ip6_new, nm_device_get_route_table (self, AF_INET6, TRUE), nm_device_get_route_metric (self, AF_INET6)); - method_old = s_ip6_old - ? nm_setting_ip_config_get_method (s_ip6_old) - : NM_SETTING_IP6_CONFIG_METHOD_IGNORE; - method_new = s_ip6_new - ? nm_setting_ip_config_get_method (s_ip6_new) - : NM_SETTING_IP6_CONFIG_METHOD_IGNORE; + if (!force_restart) { + method_old = s_ip6_old + ? nm_setting_ip_config_get_method (s_ip6_old) + : NM_SETTING_IP6_CONFIG_METHOD_IGNORE; + method_new = s_ip6_new + ? nm_setting_ip_config_get_method (s_ip6_new) + : NM_SETTING_IP6_CONFIG_METHOD_IGNORE; + force_restart = !nm_streq0 (method_old, method_new); + } - if (!nm_streq0 (method_old, method_new)) { - _cleanup_ip_pre (self, AF_INET6, CLEANUP_TYPE_DECONFIGURE); + if (force_restart) { + _cleanup_ip6_pre (self, CLEANUP_TYPE_DECONFIGURE); _set_ip_state (self, AF_INET6, IP_WAIT); if (!nm_device_activate_stage3_ip6_start (self)) _LOGW (LOGD_IP6, "Failed to apply IPv6 configuration"); } else { - if (!ip_config_merge_and_apply (self, AF_INET6, TRUE)) + if (!ip6_config_merge_and_apply (self, TRUE)) _LOGW (LOGD_IP4, "Failed to reapply IPv6 configuration"); } } @@ -10033,7 +9339,7 @@ can_reapply_change (NMDevice *self, const char *setting_name, * allowed to differ. * * This includes UUID, there is no principal problem with reapplying a - * connection and changing its UUID. In fact, disallowing it makes it + * connection and changing it's UUID. In fact, disallowing it makes it * cumbersome for the user to reapply any connection but the original * settings-connection. */ return nm_device_hash_check_invalid_keys (diffs, @@ -10159,7 +9465,7 @@ check_and_reapply_connection (NMDevice *self, } if ( version_id != 0 - && version_id != nm_active_connection_version_id_get ((NMActiveConnection *) priv->act_request.obj)) { + && version_id != nm_active_connection_version_id_get ((NMActiveConnection *) priv->act_request)) { g_set_error_literal (error, NM_DEVICE_ERROR, NM_DEVICE_ERROR_VERSION_ID_MISMATCH, @@ -10172,10 +9478,10 @@ check_and_reapply_connection (NMDevice *self, *************************************************************************/ if (diffs) - nm_active_connection_version_id_bump ((NMActiveConnection *) priv->act_request.obj); + nm_active_connection_version_id_bump ((NMActiveConnection *) priv->act_request); _LOGD (LOGD_DEVICE, "reapply (version-id %llu%s)", - (unsigned long long) nm_active_connection_version_id_get (((NMActiveConnection *) priv->act_request.obj)), + (unsigned long long) nm_active_connection_version_id_get (((NMActiveConnection *) priv->act_request)), diffs ? "" : " (unmodified)"); if (diffs) { @@ -10231,8 +9537,8 @@ check_and_reapply_connection (NMDevice *self, s_ip6_old = nm_connection_get_setting_ip6_config (con_old); s_ip6_new = nm_connection_get_setting_ip6_config (con_new); - nm_device_reactivate_ip4_config (self, s_ip4_old, s_ip4_new); - nm_device_reactivate_ip6_config (self, s_ip6_old, s_ip6_new); + nm_device_reactivate_ip4_config (self, s_ip4_old, s_ip4_new, TRUE); + nm_device_reactivate_ip6_config (self, s_ip6_old, s_ip6_new, TRUE); reactivate_proxy_config (self); @@ -10301,33 +9607,25 @@ reapply_cb (NMDevice *self, } static void -impl_device_reapply (NMDBusObject *obj, - const NMDBusInterfaceInfoExtended *interface_info, - const NMDBusMethodInfoExtended *method_info, - GDBusConnection *dbus_connection, - const char *sender, - GDBusMethodInvocation *invocation, - GVariant *parameters) +impl_device_reapply (NMDevice *self, + GDBusMethodInvocation *context, + GVariant *settings, + guint64 version_id, + guint32 flags) { - NMDevice *self = NM_DEVICE (obj); NMDevicePrivate *priv = NM_DEVICE_GET_PRIVATE (self); NMSettingsConnection *settings_connection; NMConnection *connection = NULL; GError *error = NULL; ReapplyData *reapply_data; - gs_unref_variant GVariant *settings = NULL; - guint64 version_id; - guint32 flags; - - g_variant_get (parameters, "(@a{sa{sv}}tu)", &settings, &version_id, &flags); /* No flags supported as of now. */ if (flags != 0) { error = g_error_new_literal (NM_DEVICE_ERROR, NM_DEVICE_ERROR_FAILED, "Invalid flags specified"); - nm_audit_log_device_op (NM_AUDIT_OP_DEVICE_REAPPLY, self, FALSE, NULL, invocation, error->message); - g_dbus_method_invocation_take_error (invocation, error); + nm_audit_log_device_op (NM_AUDIT_OP_DEVICE_REAPPLY, self, FALSE, NULL, context, error->message); + g_dbus_method_invocation_take_error (context, error); return; } @@ -10335,8 +9633,8 @@ impl_device_reapply (NMDBusObject *obj, error = g_error_new_literal (NM_DEVICE_ERROR, NM_DEVICE_ERROR_NOT_ACTIVE, "Device is not activated"); - nm_audit_log_device_op (NM_AUDIT_OP_DEVICE_REAPPLY, self, FALSE, NULL, invocation, error->message); - g_dbus_method_invocation_take_error (invocation, error); + nm_audit_log_device_op (NM_AUDIT_OP_DEVICE_REAPPLY, self, FALSE, NULL, context, error->message); + g_dbus_method_invocation_take_error (context, error); return; } @@ -10351,8 +9649,8 @@ impl_device_reapply (NMDBusObject *obj, &error); if (!connection) { g_prefix_error (&error, "The settings specified are invalid: "); - nm_audit_log_device_op (NM_AUDIT_OP_DEVICE_REAPPLY, self, FALSE, NULL, invocation, error->message); - g_dbus_method_invocation_take_error (invocation, error); + nm_audit_log_device_op (NM_AUDIT_OP_DEVICE_REAPPLY, self, FALSE, NULL, context, error->message); + g_dbus_method_invocation_take_error (context, error); return; } nm_connection_clear_secrets (connection); @@ -10365,8 +9663,9 @@ impl_device_reapply (NMDBusObject *obj, } else reapply_data = NULL; + /* Ask the manager to authenticate this request for us */ g_signal_emit (self, signals[AUTH_REQUEST], 0, - invocation, + context, nm_device_get_applied_connection (self), NM_AUTH_PERMISSION_NETWORK_CONTROL, TRUE, @@ -10425,44 +9724,40 @@ get_applied_connection_cb (NMDevice *self, g_dbus_method_invocation_return_value (context, g_variant_new ("(@a{sa{sv}}t)", settings, - nm_active_connection_version_id_get ((NMActiveConnection *) priv->act_request.obj))); + nm_active_connection_version_id_get ((NMActiveConnection *) priv->act_request))); } static void -impl_device_get_applied_connection (NMDBusObject *obj, - const NMDBusInterfaceInfoExtended *interface_info, - const NMDBusMethodInfoExtended *method_info, - GDBusConnection *connection, - const char *sender, - GDBusMethodInvocation *invocation, - GVariant *parameters) +impl_device_get_applied_connection (NMDevice *self, + GDBusMethodInvocation *context, + guint32 flags) { - NMDevice *self = NM_DEVICE (obj); NMConnection *applied_connection; - guint32 flags; + GError *error = NULL; - g_variant_get (parameters, "(u)", &flags); + g_return_if_fail (NM_IS_DEVICE (self)); /* No flags supported as of now. */ if (flags != 0) { - g_dbus_method_invocation_return_error_literal (invocation, - NM_DEVICE_ERROR, - NM_DEVICE_ERROR_FAILED, - "Invalid flags specified"); + error = g_error_new_literal (NM_DEVICE_ERROR, + NM_DEVICE_ERROR_FAILED, + "Invalid flags specified"); + g_dbus_method_invocation_take_error (context, error); return; } applied_connection = nm_device_get_applied_connection (self); if (!applied_connection) { - g_dbus_method_invocation_return_error_literal (invocation, - NM_DEVICE_ERROR, - NM_DEVICE_ERROR_NOT_ACTIVE, - "Device is not activated"); + error = g_error_new_literal (NM_DEVICE_ERROR, + NM_DEVICE_ERROR_NOT_ACTIVE, + "Device is not activated"); + g_dbus_method_invocation_take_error (context, error); return; } + /* Ask the manager to authenticate this request for us */ g_signal_emit (self, signals[AUTH_REQUEST], 0, - invocation, + context, applied_connection, NM_AUTH_PERMISSION_NETWORK_CONTROL, TRUE, @@ -10611,31 +9906,25 @@ _clear_queued_act_request (NMDevicePrivate *priv) } static void -impl_device_disconnect (NMDBusObject *obj, - const NMDBusInterfaceInfoExtended *interface_info, - const NMDBusMethodInfoExtended *method_info, - GDBusConnection *dbus_connection, - const char *sender, - GDBusMethodInvocation *invocation, - GVariant *parameters) +impl_device_disconnect (NMDevice *self, GDBusMethodInvocation *context) { - NMDevice *self = NM_DEVICE (obj); - NMDevicePrivate *priv = NM_DEVICE_GET_PRIVATE (self); NMConnection *connection; + GError *error = NULL; - if (!priv->act_request.obj) { - g_dbus_method_invocation_return_error_literal (invocation, - NM_DEVICE_ERROR, - NM_DEVICE_ERROR_NOT_ACTIVE, - "This device is not active"); + if (NM_DEVICE_GET_PRIVATE (self)->act_request == NULL) { + error = g_error_new_literal (NM_DEVICE_ERROR, + NM_DEVICE_ERROR_NOT_ACTIVE, + "This device is not active"); + g_dbus_method_invocation_take_error (context, error); return; } connection = nm_device_get_applied_connection (self); - nm_assert (connection); + g_assert (connection); + /* Ask the manager to authenticate this request for us */ g_signal_emit (self, signals[AUTH_REQUEST], 0, - invocation, + context, connection, NM_AUTH_PERMISSION_NETWORK_CONTROL, TRUE, @@ -10667,27 +9956,21 @@ delete_cb (NMDevice *self, } static void -impl_device_delete (NMDBusObject *obj, - const NMDBusInterfaceInfoExtended *interface_info, - const NMDBusMethodInfoExtended *method_info, - GDBusConnection *connection, - const char *sender, - GDBusMethodInvocation *invocation, - GVariant *parameters) +impl_device_delete (NMDevice *self, GDBusMethodInvocation *context) { - NMDevice *self = NM_DEVICE (obj); + GError *error = NULL; - if ( !nm_device_is_software (self) - || !nm_device_is_real (self)) { - g_dbus_method_invocation_return_error_literal (invocation, - NM_DEVICE_ERROR, - NM_DEVICE_ERROR_NOT_SOFTWARE, - "This device is not a software device or is not realized"); + if (!nm_device_is_software (self) || !nm_device_is_real (self)) { + error = g_error_new_literal (NM_DEVICE_ERROR, + NM_DEVICE_ERROR_NOT_SOFTWARE, + "This device is not a software device or is not realized"); + g_dbus_method_invocation_take_error (context, error); return; } + /* Ask the manager to authenticate this request for us */ g_signal_emit (self, signals[AUTH_REQUEST], 0, - invocation, + context, NULL, NM_AUTH_PERMISSION_NETWORK_CONTROL, TRUE, @@ -10811,8 +10094,8 @@ nm_device_steal_connection (NMDevice *self, NMSettingsConnection *connection) && connection == nm_active_connection_get_settings_connection (NM_ACTIVE_CONNECTION (priv->queued_act_request))) _clear_queued_act_request (priv); - if ( priv->act_request.obj - && connection == nm_active_connection_get_settings_connection (NM_ACTIVE_CONNECTION (priv->act_request.obj)) + if ( priv->act_request + && connection == nm_active_connection_get_settings_connection (NM_ACTIVE_CONNECTION (priv->act_request)) && priv->state < NM_DEVICE_STATE_DEACTIVATING) { nm_device_state_changed (self, NM_DEVICE_STATE_DEACTIVATING, @@ -10828,7 +10111,7 @@ nm_device_queue_activation (NMDevice *self, NMActRequest *req) must_queue = _carrier_wait_check_act_request_must_queue (self, req); - if ( !priv->act_request.obj + if ( !priv->act_request && !must_queue && nm_device_is_real (self)) { _device_activate (self, req); @@ -10843,7 +10126,7 @@ nm_device_queue_activation (NMDevice *self, NMActRequest *req) _LOGD (LOGD_DEVICE, "queue activation request waiting for %s", must_queue ? "carrier" : "currently active connection to disconnect"); /* Deactivate existing activation request first */ - if (priv->act_request.obj) { + if (priv->act_request) { _LOGI (LOGD_DEVICE, "disconnecting for new activation request."); nm_device_state_changed (self, NM_DEVICE_STATE_DEACTIVATING, @@ -10928,155 +10211,116 @@ nm_device_get_ip4_config (NMDevice *self) { g_return_val_if_fail (NM_IS_DEVICE (self), NULL); - return NM_DEVICE_GET_PRIVATE (self)->ip_config_4; + return NM_DEVICE_GET_PRIVATE (self)->ip4_config; } static gboolean -nm_device_set_ip_config (NMDevice *self, - int addr_family, - NMIPConfig *new_config, - gboolean commit, - GPtrArray *ip4_dev_route_blacklist) +nm_device_set_ip4_config (NMDevice *self, + NMIP4Config *new_config, + gboolean commit, + GPtrArray *ip4_dev_route_blacklist) { - NMDevicePrivate *priv = NM_DEVICE_GET_PRIVATE (self); - const gboolean IS_IPv4 = (addr_family == AF_INET); - NMIPConfig *old_config; + NMDevicePrivate *priv; + NMIP4Config *old_config = NULL; gboolean has_changes = FALSE; gboolean success = TRUE; - NMSettingsConnection *settings_connection; - nm_assert_addr_family (addr_family); - nm_assert (!new_config || nm_ip_config_get_addr_family (new_config) == addr_family); + g_return_val_if_fail (NM_IS_DEVICE (self), FALSE); + + _LOGD (LOGD_IP4, "ip4-config: update (commit=%d, new-config=%p)", + commit, new_config); + nm_assert ( !new_config || ( new_config && ({ int ip_ifindex = nm_device_get_ip_ifindex (self); ( ip_ifindex > 0 - && ip_ifindex == nm_ip_config_get_ifindex (new_config)); + && ip_ifindex == nm_ip4_config_get_ifindex (new_config)); }))); - nm_assert (IS_IPv4 || !ip4_dev_route_blacklist); - _LOGD (LOGD_IP_from_af (addr_family), - "ip%c-config: update (commit=%d, new-config=%p)", - nm_utils_addr_family_to_char (addr_family), - commit, - new_config); + priv = NM_DEVICE_GET_PRIVATE (self); + + old_config = priv->ip4_config; /* Always commit to nm-platform to update lifetimes */ if (commit && new_config) { - - _commit_mtu (self, - IS_IPv4 - ? NM_IP4_CONFIG (new_config) - : priv->ip_config_4); - - if (IS_IPv4) { - success = nm_ip4_config_commit (NM_IP4_CONFIG (new_config), - nm_device_get_platform (self), - nm_device_get_route_table (self, addr_family, FALSE) - ? NM_IP_ROUTE_TABLE_SYNC_MODE_FULL - : NM_IP_ROUTE_TABLE_SYNC_MODE_MAIN); - nm_platform_ip4_dev_route_blacklist_set (nm_device_get_platform (self), - nm_ip_config_get_ifindex (new_config), - ip4_dev_route_blacklist); + _commit_mtu (self, new_config); + success = nm_ip4_config_commit (new_config, + nm_device_get_platform (self), + nm_device_get_route_table (self, AF_INET, FALSE) + ? NM_IP_ROUTE_TABLE_SYNC_MODE_FULL + : NM_IP_ROUTE_TABLE_SYNC_MODE_MAIN); + nm_platform_ip4_dev_route_blacklist_set (nm_device_get_platform (self), + nm_ip4_config_get_ifindex (new_config), + ip4_dev_route_blacklist); + } + + if (new_config) { + if (old_config) { + /* has_changes is set only on relevant changes, because when the configuration changes, + * this causes a re-read and reset. This should only happen for relevant changes */ + nm_ip4_config_replace (old_config, new_config, &has_changes); + if (has_changes) { + _LOGD (LOGD_IP4, "ip4-config: update IP4Config instance (%s)", + nm_exported_object_get_path (NM_EXPORTED_OBJECT (old_config))); + } } else { - gs_unref_ptrarray GPtrArray *temporary_not_available = NULL; - - success = nm_ip6_config_commit (NM_IP6_CONFIG (new_config), - nm_device_get_platform (self), - nm_device_get_route_table (self, addr_family, FALSE) - ? NM_IP_ROUTE_TABLE_SYNC_MODE_FULL - : NM_IP_ROUTE_TABLE_SYNC_MODE_MAIN, - &temporary_not_available); - - if (!_rt6_temporary_not_available_set (self, temporary_not_available)) - success = FALSE; - } - } + has_changes = TRUE; + priv->ip4_config = g_object_ref (new_config); - old_config = priv->ip_config_x[IS_IPv4]; + if (success && !nm_exported_object_is_exported (NM_EXPORTED_OBJECT (new_config))) + nm_exported_object_export (NM_EXPORTED_OBJECT (new_config)); - if (new_config && old_config) { - /* has_changes is set only on relevant changes, because when the configuration changes, - * this causes a re-read and reset. This should only happen for relevant changes */ - nm_ip_config_replace (old_config, new_config, &has_changes); - if (has_changes) { - _LOGD (LOGD_IP_from_af (addr_family), - "ip%c-config: update IP Config instance (%s)", - nm_utils_addr_family_to_char (addr_family), - nm_dbus_object_get_path (NM_DBUS_OBJECT (old_config))); + _LOGD (LOGD_IP4, "ip4-config: set IP4Config instance (%s)", + nm_exported_object_get_path (NM_EXPORTED_OBJECT (new_config))); } - } else if (new_config /*&& !old_config*/) { - has_changes = TRUE; - priv->ip_config_x[IS_IPv4] = g_object_ref (new_config); - if (!nm_dbus_object_is_exported (NM_DBUS_OBJECT (new_config))) - nm_dbus_object_export (NM_DBUS_OBJECT (new_config)); - - _LOGD (LOGD_IP_from_af (addr_family), - "ip%c-config: set IP Config instance (%s)", - nm_utils_addr_family_to_char (addr_family), - nm_dbus_object_get_path (NM_DBUS_OBJECT (new_config))); - } else if (old_config /*&& !new_config*/) { + } else if (old_config) { has_changes = TRUE; - priv->ip_config_x[IS_IPv4] = NULL; - _LOGD (LOGD_IP_from_af (addr_family), - "ip%c-config: clear IP Config instance (%s)", - nm_utils_addr_family_to_char (addr_family), - nm_dbus_object_get_path (NM_DBUS_OBJECT (old_config))); - if (IS_IPv4) { - /* Device config is invalid if combined config is invalid */ - applied_config_clear (&priv->dev_ip4_config); - } else - priv->needs_ip6_subnet = FALSE; + priv->ip4_config = NULL; + _LOGD (LOGD_IP4, "ip4-config: clear IP4Config instance (%s)", + nm_exported_object_get_path (NM_EXPORTED_OBJECT (old_config))); + /* Device config is invalid if combined config is invalid */ + g_clear_object (&priv->dev_ip4_config); } - if (IS_IPv4) { - if (!nm_device_sys_iface_state_is_external_or_assume (self)) - ip4_rp_filter_update (self); - } + concheck_periodic_update (self); - if (has_changes) { + if (!nm_device_sys_iface_state_is_external_or_assume (self)) + ip4_rp_filter_update (self); - if (IS_IPv4) - _update_ip4_address (self); + if (has_changes) { + NMSettingsConnection *settings_connection; - if (old_config != priv->ip_config_x[IS_IPv4]) - _notify (self, IS_IPv4 ? PROP_IP4_CONFIG : PROP_IP6_CONFIG); + _update_ip4_address (self); - g_signal_emit (self, - signals[IS_IPv4 ? IP4_CONFIG_CHANGED : IP6_CONFIG_CHANGED], - 0, - priv->ip_config_x[IS_IPv4], - old_config); + if (old_config != priv->ip4_config) + _notify (self, PROP_IP4_CONFIG); + g_signal_emit (self, signals[IP4_CONFIG_CHANGED], 0, priv->ip4_config, old_config); - if (old_config != priv->ip_config_x[IS_IPv4]) - nm_dbus_object_clear_and_unexport (&old_config); + if (old_config != priv->ip4_config) + nm_exported_object_clear_and_unexport (&old_config); if ( nm_device_sys_iface_state_is_external (self) && (settings_connection = nm_device_get_settings_connection (self)) && NM_FLAGS_HAS (nm_settings_connection_get_flags (settings_connection), - NM_SETTINGS_CONNECTION_INT_FLAGS_NM_GENERATED) - && nm_active_connection_get_activation_type (NM_ACTIVE_CONNECTION (priv->act_request.obj)) == NM_ACTIVATION_TYPE_EXTERNAL) { + NM_SETTINGS_CONNECTION_FLAGS_NM_GENERATED) + && nm_active_connection_get_activation_type (NM_ACTIVE_CONNECTION (priv->act_request)) == NM_ACTIVATION_TYPE_EXTERNAL) { + NMSetting *s_ip4; + g_object_freeze_notify (G_OBJECT (settings_connection)); - nm_connection_add_setting (NM_CONNECTION (settings_connection), - IS_IPv4 - ? nm_ip4_config_create_setting (priv->ip_config_4) - : nm_ip6_config_create_setting (priv->ip_config_6)); + + nm_connection_remove_setting (NM_CONNECTION (settings_connection), NM_TYPE_SETTING_IP4_CONFIG); + s_ip4 = nm_ip4_config_create_setting (priv->ip4_config); + nm_connection_add_setting (NM_CONNECTION (settings_connection), s_ip4); + g_object_thaw_notify (G_OBJECT (settings_connection)); } nm_device_queue_recheck_assume (self); - - if (!IS_IPv4) { - if (priv->ndisc) - ndisc_set_router_config (priv->ndisc, self); - } } - nm_assert (!old_config || old_config == priv->ip_config_x[IS_IPv4]); - return success; } @@ -11123,11 +10367,11 @@ nm_device_replace_vpn4_config (NMDevice *self, NMIP4Config *old, NMIP4Config *co nm_assert (!old || nm_ip4_config_get_ifindex (old) == nm_device_get_ip_ifindex (self)); nm_assert (!config || nm_ip4_config_get_ifindex (config) == nm_device_get_ip_ifindex (self)); - if (!_replace_vpn_config_in_list (&priv->vpn_configs_4, (GObject *) old, (GObject *) config)) + if (!_replace_vpn_config_in_list (&priv->vpn4_configs, (GObject *) old, (GObject *) config)) return; /* NULL to use existing configs */ - if (!ip_config_merge_and_apply (self, AF_INET, TRUE)) + if (!ip4_config_merge_and_apply (self, TRUE)) _LOGW (LOGD_IP4, "failed to set VPN routes for device"); } @@ -11136,11 +10380,125 @@ nm_device_set_wwan_ip4_config (NMDevice *self, NMIP4Config *config) { NMDevicePrivate *priv = NM_DEVICE_GET_PRIVATE (self); - applied_config_init (&priv->wwan_ip_config_4, config); - if (!ip_config_merge_and_apply (self, AF_INET, TRUE)) + if (priv->wwan_ip4_config == config) + return; + + g_clear_object (&priv->wwan_ip4_config); + if (config) + priv->wwan_ip4_config = g_object_ref (config); + + /* NULL to use existing configs */ + if (!ip4_config_merge_and_apply (self, TRUE)) _LOGW (LOGD_IP4, "failed to set WWAN IPv4 configuration"); } +static gboolean +nm_device_set_ip6_config (NMDevice *self, + NMIP6Config *new_config, + gboolean commit) +{ + NMDevicePrivate *priv; + NMIP6Config *old_config = NULL; + gboolean has_changes = FALSE; + gboolean success = TRUE; + + g_return_val_if_fail (NM_IS_DEVICE (self), FALSE); + + _LOGD (LOGD_IP6, "ip6-config: update (commit=%d, new-config=%p)", + commit, new_config); + + nm_assert ( !new_config + || ( new_config + && ({ + int ip_ifindex = nm_device_get_ip_ifindex (self); + + ( ip_ifindex > 0 + && ip_ifindex == nm_ip6_config_get_ifindex (new_config)); + }))); + + priv = NM_DEVICE_GET_PRIVATE (self); + + old_config = priv->ip6_config; + + /* Always commit to nm-platform to update lifetimes */ + if (commit && new_config) { + gs_unref_ptrarray GPtrArray *temporary_not_available = NULL; + + _commit_mtu (self, priv->ip4_config); + + success = nm_ip6_config_commit (new_config, + nm_device_get_platform (self), + nm_device_get_route_table (self, AF_INET6, FALSE) + ? NM_IP_ROUTE_TABLE_SYNC_MODE_FULL + : NM_IP_ROUTE_TABLE_SYNC_MODE_MAIN, + &temporary_not_available); + + if (!_rt6_temporary_not_available_set (self, temporary_not_available)) + success = FALSE; + } + + if (new_config) { + if (old_config) { + /* has_changes is set only on relevant changes, because when the configuration changes, + * this causes a re-read and reset. This should only happen for relevant changes */ + nm_ip6_config_replace (old_config, new_config, &has_changes); + if (has_changes) { + _LOGD (LOGD_IP6, "ip6-config: update IP6Config instance (%s)", + nm_exported_object_get_path (NM_EXPORTED_OBJECT (old_config))); + } + } else { + has_changes = TRUE; + priv->ip6_config = g_object_ref (new_config); + + if (success && !nm_exported_object_is_exported (NM_EXPORTED_OBJECT (new_config))) + nm_exported_object_export (NM_EXPORTED_OBJECT (new_config)); + + _LOGD (LOGD_IP6, "ip6-config: set IP6Config instance (%s)", + nm_exported_object_get_path (NM_EXPORTED_OBJECT (new_config))); + } + } else if (old_config) { + has_changes = TRUE; + priv->ip6_config = NULL; + priv->needs_ip6_subnet = FALSE; + _LOGD (LOGD_IP6, "ip6-config: clear IP6Config instance (%s)", + nm_exported_object_get_path (NM_EXPORTED_OBJECT (old_config))); + } + + if (has_changes) { + NMSettingsConnection *settings_connection; + + if (old_config != priv->ip6_config) + _notify (self, PROP_IP6_CONFIG); + g_signal_emit (self, signals[IP6_CONFIG_CHANGED], 0, priv->ip6_config, old_config); + + if (old_config != priv->ip6_config) + nm_exported_object_clear_and_unexport (&old_config); + + if ( nm_device_sys_iface_state_is_external (self) + && (settings_connection = nm_device_get_settings_connection (self)) + && NM_FLAGS_HAS (nm_settings_connection_get_flags (settings_connection), + NM_SETTINGS_CONNECTION_FLAGS_NM_GENERATED) + && nm_active_connection_get_activation_type (NM_ACTIVE_CONNECTION (priv->act_request)) == NM_ACTIVATION_TYPE_EXTERNAL) { + NMSetting *s_ip6; + + g_object_freeze_notify (G_OBJECT (settings_connection)); + + nm_connection_remove_setting (NM_CONNECTION (settings_connection), NM_TYPE_SETTING_IP6_CONFIG); + s_ip6 = nm_ip6_config_create_setting (priv->ip6_config); + nm_connection_add_setting (NM_CONNECTION (settings_connection), s_ip6); + + g_object_thaw_notify (G_OBJECT (settings_connection)); + } + + nm_device_queue_recheck_assume (self); + + if (priv->ndisc) + ndisc_set_router_config (priv->ndisc, self); + } + + return success; +} + void nm_device_replace_vpn6_config (NMDevice *self, NMIP6Config *old, NMIP6Config *config) { @@ -11151,11 +10509,11 @@ nm_device_replace_vpn6_config (NMDevice *self, NMIP6Config *old, NMIP6Config *co nm_assert (!old || nm_ip6_config_get_ifindex (old) == nm_device_get_ip_ifindex (self)); nm_assert (!config || nm_ip6_config_get_ifindex (config) == nm_device_get_ip_ifindex (self)); - if (!_replace_vpn_config_in_list (&priv->vpn_configs_6, (GObject *) old, (GObject *) config)) + if (!_replace_vpn_config_in_list (&priv->vpn6_configs, (GObject *) old, (GObject *) config)) return; /* NULL to use existing configs */ - if (!ip_config_merge_and_apply (self, AF_INET6, TRUE)) + if (!ip6_config_merge_and_apply (self, TRUE)) _LOGW (LOGD_IP6, "failed to set VPN routes for device"); } @@ -11164,8 +10522,15 @@ nm_device_set_wwan_ip6_config (NMDevice *self, NMIP6Config *config) { NMDevicePrivate *priv = NM_DEVICE_GET_PRIVATE (self); - applied_config_init (&priv->wwan_ip_config_6, config); - if (!ip_config_merge_and_apply (self, AF_INET6, TRUE)) + if (priv->wwan_ip6_config == config) + return; + + g_clear_object (&priv->wwan_ip6_config); + if (config) + priv->wwan_ip6_config = g_object_ref (config); + + /* NULL to use existing configs */ + if (!ip6_config_merge_and_apply (self, TRUE)) _LOGW (LOGD_IP6, "failed to set WWAN IPv6 configuration"); } @@ -11182,7 +10547,7 @@ nm_device_get_ip6_config (NMDevice *self) { g_return_val_if_fail (NM_IS_DEVICE (self), NULL); - return NM_DEVICE_GET_PRIVATE (self)->ip_config_6; + return NM_DEVICE_GET_PRIVATE (self)->ip6_config; } /*****************************************************************************/ @@ -11373,7 +10738,7 @@ start_ping (NMDevice *self, priv->gw_ping.log_domain = log_domain; priv->gw_ping.address = g_strdup (address); priv->gw_ping.binary = g_strdup (binary); - priv->gw_ping.deadline = timeout + 10; /* the proper termination is enforced by a timer */ + priv->gw_ping.deadline = timeout + 10; /* the proper termination is enforced by a timer */ if (spawn_ping (self)) { priv->gw_ping.watch = g_child_watch_add (priv->gw_ping.pid, ip_check_ping_watch_cb, self); @@ -11416,15 +10781,15 @@ nm_device_start_ip_check (NMDevice *self) if (timeout) { const NMPObject *gw; - if (priv->ip_config_4 && priv->ip4_state == IP_DONE) { - gw = nm_ip4_config_best_default_route_get (priv->ip_config_4); + if (priv->ip4_config && priv->ip4_state == IP_DONE) { + gw = nm_ip4_config_best_default_route_get (priv->ip4_config); if (gw) { nm_utils_inet4_ntop (NMP_OBJECT_CAST_IP4_ROUTE (gw)->gateway, buf); ping_binary = nm_utils_find_helper ("ping", "/usr/bin/ping", NULL); log_domain = LOGD_IP4; } - } else if (priv->ip_config_6 && priv->ip6_state == IP_DONE) { - gw = nm_ip6_config_best_default_route_get (priv->ip_config_6); + } else if (priv->ip6_config && priv->ip6_state == IP_DONE) { + gw = nm_ip6_config_best_default_route_get (priv->ip6_config); if (gw) { nm_utils_inet6_ntop (&NMP_OBJECT_CAST_IP6_ROUTE (gw)->gateway, buf); ping_binary = nm_utils_find_helper ("ping6", "/usr/bin/ping6", NULL); @@ -11564,11 +10929,11 @@ nm_device_bring_up (NMDevice *self, gboolean block, gboolean *no_firmware) /* when the link comes up, we must restore IP configuration if necessary. */ if (priv->ip4_state == IP_DONE) { - if (!ip_config_merge_and_apply (self, AF_INET, TRUE)) + if (!ip4_config_merge_and_apply (self, TRUE)) _LOGW (LOGD_IP4, "failed applying IP4 config after bringing link up"); } if (priv->ip6_state == IP_DONE) { - if (!ip_config_merge_and_apply (self, AF_INET6, TRUE)) + if (!ip6_config_merge_and_apply (self, TRUE)) _LOGW (LOGD_IP6, "failed applying IP6 config after bringing link up"); } @@ -11633,37 +10998,122 @@ nm_device_get_firmware_missing (NMDevice *self) return NM_DEVICE_GET_PRIVATE (self)->firmware_missing; } +static NMIP4Config * +find_ip4_lease_config (NMDevice *self, + NMConnection *connection, + NMIP4Config *ext_ip4_config) +{ + const char *ip_iface = nm_device_get_ip_iface (self); + int ip_ifindex = nm_device_get_ip_ifindex (self); + GSList *leases, *liter; + NMIP4Config *found = NULL; + + g_return_val_if_fail (NM_IS_IP4_CONFIG (ext_ip4_config), NULL); + g_return_val_if_fail (NM_IS_CONNECTION (connection), NULL); + + leases = nm_dhcp_manager_get_lease_ip_configs (nm_dhcp_manager_get (), + nm_device_get_multi_index (self), + AF_INET, + ip_iface, + ip_ifindex, + nm_connection_get_uuid (connection), + nm_device_get_route_table (self, AF_INET, TRUE), + nm_device_get_route_metric (self, AF_INET)); + for (liter = leases; liter && !found; liter = liter->next) { + NMIP4Config *lease_config = liter->data; + const NMPlatformIP4Address *address = nm_ip4_config_get_first_address (lease_config); + const NMPObject *gw1, *gw2; + + g_assert (address); + if (!nm_ip4_config_address_exists (ext_ip4_config, address)) + continue; + gw1 = nm_ip4_config_best_default_route_get (lease_config); + if (!gw1) + continue; + gw2 = nm_ip4_config_best_default_route_get (ext_ip4_config); + if (!gw2) + continue; + if (NMP_OBJECT_CAST_IP4_ROUTE (gw1)->gateway != NMP_OBJECT_CAST_IP4_ROUTE (gw2)->gateway) + continue; + found = g_object_ref (lease_config); + } + + g_slist_free_full (leases, g_object_unref); + return found; +} + static void -intersect_ext_config (NMDevice *self, AppliedConfig *config) +capture_lease_config (NMDevice *self, + NMIP4Config *ext_ip4_config, + NMIP4Config **out_ip4_config, + NMIP6Config *ext_ip6_config, + NMIP6Config **out_ip6_config) { NMDevicePrivate *priv = NM_DEVICE_GET_PRIVATE (self); - NMIPConfig *ext; - guint32 penalty; - int family; + NMSettingsConnection *const*connections; + guint i; + gboolean dhcp_used = FALSE; + NMDedupMultiIter ipconf_iter; + + /* Ensure at least one address on the device has a non-infinite lifetime, + * otherwise DHCP cannot possibly be active on the device right now. + */ + if (ext_ip4_config && out_ip4_config) { + const NMPlatformIP4Address *addr; + + nm_ip_config_iter_ip4_address_for_each (&ipconf_iter, ext_ip4_config, &addr) { + if (addr->lifetime != NM_PLATFORM_LIFETIME_PERMANENT) { + dhcp_used = TRUE; + break; + } + } + } else if (ext_ip6_config && out_ip6_config) { + const NMPlatformIP6Address *addr; + + nm_ip_config_iter_ip6_address_for_each (&ipconf_iter, ext_ip6_config, &addr) { + if (addr->lifetime != NM_PLATFORM_LIFETIME_PERMANENT) { + dhcp_used = TRUE; + break; + } + } + } else { + g_return_if_fail ( (ext_ip6_config && out_ip6_config) + || (ext_ip4_config && out_ip4_config)); + } - if (!config->orig) + if (!dhcp_used) return; - family = nm_ip_config_get_addr_family (config->orig); - penalty = default_route_metric_penalty_get (self, family); - ext = family == AF_INET - ? (NMIPConfig *) priv->ext_ip_config_4 - : (NMIPConfig *) priv->ext_ip_config_6; + connections = nm_settings_get_connections (priv->settings, NULL); + for (i = 0; connections[i]; i++) { + NMConnection *candidate = (NMConnection *) connections[i]; + const char *method; + + if (!nm_device_check_connection_compatible (self, candidate)) + continue; - if (config->current) - nm_ip_config_intersect (config->current, ext, penalty); - else { - config->current = nm_ip_config_intersect_alloc (config->orig, - ext, - penalty); + /* IPv4 leases */ + method = nm_utils_get_ip_config_method (candidate, NM_TYPE_SETTING_IP4_CONFIG); + if (out_ip4_config && strcmp (method, NM_SETTING_IP4_CONFIG_METHOD_AUTO) == 0) { + *out_ip4_config = find_ip4_lease_config (self, candidate, ext_ip4_config); + if (*out_ip4_config) + return; + } + + /* IPv6 leases */ + method = nm_utils_get_ip_config_method (candidate, NM_TYPE_SETTING_IP6_CONFIG); + if (out_ip6_config && strcmp (method, NM_SETTING_IP6_CONFIG_METHOD_AUTO) == 0) { + /* FIXME: implement find_ip6_lease_config() */ + } } } static gboolean -update_ext_ip_config (NMDevice *self, int addr_family, gboolean intersect_configs) +update_ext_ip_config (NMDevice *self, int addr_family, gboolean initial, gboolean intersect_configs) { NMDevicePrivate *priv = NM_DEVICE_GET_PRIVATE (self); int ifindex; + gboolean capture_resolv_conf; GSList *iter; nm_assert_addr_family (addr_family); @@ -11672,110 +11122,122 @@ update_ext_ip_config (NMDevice *self, int addr_family, gboolean intersect_config if (!ifindex) return FALSE; + capture_resolv_conf = initial + && nm_dns_manager_get_resolv_conf_explicit (nm_dns_manager_get ()); + if (addr_family == AF_INET) { - g_clear_object (&priv->ext_ip_config_4); - priv->ext_ip_config_4 = nm_ip4_config_capture (nm_device_get_multi_index (self), + g_clear_object (&priv->ext_ip4_config); + priv->ext_ip4_config = nm_ip4_config_capture (nm_device_get_multi_index (self), nm_device_get_platform (self), - ifindex); - if (priv->ext_ip_config_4) { + ifindex, + capture_resolv_conf); + if (priv->ext_ip4_config) { + if (initial) { + g_clear_object (&priv->dev_ip4_config); + capture_lease_config (self, priv->ext_ip4_config, &priv->dev_ip4_config, NULL, NULL); + } + if (intersect_configs) { /* This function was called upon external changes. Remove the configuration * (addresses,routes) that is no longer present externally from the internal * config. This way, we don't re-add addresses that were manually removed * by the user. */ - if (priv->con_ip_config_4) { - nm_ip4_config_intersect (priv->con_ip_config_4, priv->ext_ip_config_4, + if (priv->con_ip4_config) { + nm_ip4_config_intersect (priv->con_ip4_config, priv->ext_ip4_config, default_route_metric_penalty_get (self, AF_INET)); } - - intersect_ext_config (self, &priv->dev_ip4_config); - intersect_ext_config (self, &priv->wwan_ip_config_4); - - for (iter = priv->vpn_configs_4; iter; iter = iter->next) - nm_ip4_config_intersect (iter->data, priv->ext_ip_config_4, 0); + if (priv->dev_ip4_config) { + nm_ip4_config_intersect (priv->dev_ip4_config, priv->ext_ip4_config, + default_route_metric_penalty_get (self, AF_INET)); + } + if (priv->wwan_ip4_config) { + nm_ip4_config_intersect (priv->wwan_ip4_config, priv->ext_ip4_config, + default_route_metric_penalty_get (self, AF_INET)); + } + for (iter = priv->vpn4_configs; iter; iter = iter->next) + nm_ip4_config_intersect (iter->data, priv->ext_ip4_config, 0); } - /* Remove parts from ext_ip_config_4 to only contain the information that + /* Remove parts from ext_ip4_config to only contain the information that * was configured externally -- we already have the same configuration from * internal origins. */ - if (priv->con_ip_config_4) { - nm_ip4_config_subtract (priv->ext_ip_config_4, priv->con_ip_config_4, + if (priv->con_ip4_config) { + nm_ip4_config_subtract (priv->ext_ip4_config, priv->con_ip4_config, default_route_metric_penalty_get (self, AF_INET)); } - if (applied_config_get_current (&priv->dev_ip4_config)) { - nm_ip_config_subtract ((NMIPConfig *) priv->ext_ip_config_4, - applied_config_get_current (&priv->dev_ip4_config), - default_route_metric_penalty_get (self, AF_INET)); + if (priv->dev_ip4_config) { + nm_ip4_config_subtract (priv->ext_ip4_config, priv->dev_ip4_config, + default_route_metric_penalty_get (self, AF_INET)); } - if (applied_config_get_current (&priv->wwan_ip_config_4)) { - nm_ip_config_subtract ((NMIPConfig *) priv->ext_ip_config_4, - applied_config_get_current (&priv->wwan_ip_config_4), - default_route_metric_penalty_get (self, AF_INET)); + if (priv->wwan_ip4_config) { + nm_ip4_config_subtract (priv->ext_ip4_config, priv->wwan_ip4_config, + default_route_metric_penalty_get (self, AF_INET)); } - for (iter = priv->vpn_configs_4; iter; iter = iter->next) - nm_ip4_config_subtract (priv->ext_ip_config_4, iter->data, 0); + for (iter = priv->vpn4_configs; iter; iter = iter->next) + nm_ip4_config_subtract (priv->ext_ip4_config, iter->data, 0); } } else { nm_assert (addr_family == AF_INET6); - g_clear_object (&priv->ext_ip_config_6); + g_clear_object (&priv->ext_ip6_config); g_clear_object (&priv->ext_ip6_config_captured); priv->ext_ip6_config_captured = nm_ip6_config_capture (nm_device_get_multi_index (self), nm_device_get_platform (self), ifindex, + capture_resolv_conf, NM_SETTING_IP6_CONFIG_PRIVACY_UNKNOWN); if (priv->ext_ip6_config_captured) { - priv->ext_ip_config_6 = nm_ip6_config_new_cloned (priv->ext_ip6_config_captured); + priv->ext_ip6_config = nm_ip6_config_new_cloned (priv->ext_ip6_config_captured); if (intersect_configs) { /* This function was called upon external changes. Remove the configuration * (addresses,routes) that is no longer present externally from the internal * config. This way, we don't re-add addresses that were manually removed * by the user. */ - if (priv->con_ip_config_6) { - nm_ip6_config_intersect (priv->con_ip_config_6, priv->ext_ip_config_6, + if (priv->con_ip6_config) { + nm_ip6_config_intersect (priv->con_ip6_config, priv->ext_ip6_config, default_route_metric_penalty_get (self, AF_INET6)); } - - intersect_ext_config (self, &priv->ac_ip6_config); - intersect_ext_config (self, &priv->dhcp6.ip6_config); - intersect_ext_config (self, &priv->wwan_ip_config_6); - - for (iter = priv->vpn_configs_6; iter; iter = iter->next) - nm_ip6_config_intersect (iter->data, priv->ext_ip_config_6, 0); - - if ( priv->ipv6ll_has - && !nm_ip6_config_lookup_address (priv->ext_ip_config_6, &priv->ipv6ll_addr)) - priv->ipv6ll_has = FALSE; + if (priv->ac_ip6_config) { + nm_ip6_config_intersect (priv->ac_ip6_config, priv->ext_ip6_config, + default_route_metric_penalty_get (self, AF_INET6)); + } + if (priv->dhcp6.ip6_config) { + nm_ip6_config_intersect (priv->dhcp6.ip6_config, priv->ext_ip6_config, + default_route_metric_penalty_get (self, AF_INET6)); + } + if (priv->wwan_ip6_config) { + nm_ip6_config_intersect (priv->wwan_ip6_config, priv->ext_ip6_config, + default_route_metric_penalty_get (self, AF_INET6)); + } + for (iter = priv->vpn6_configs; iter; iter = iter->next) + nm_ip6_config_intersect (iter->data, priv->ext_ip6_config, 0); } - /* Remove parts from ext_ip_config_6 to only contain the information that + /* Remove parts from ext_ip6_config to only contain the information that * was configured externally -- we already have the same configuration from * internal origins. */ - if (priv->con_ip_config_6) { - nm_ip6_config_subtract (priv->ext_ip_config_6, priv->con_ip_config_6, + if (priv->con_ip6_config) { + nm_ip6_config_subtract (priv->ext_ip6_config, priv->con_ip6_config, default_route_metric_penalty_get (self, AF_INET6)); } - if (applied_config_get_current (&priv->ac_ip6_config)) { - nm_ip_config_subtract ((NMIPConfig *) priv->ext_ip_config_6, - applied_config_get_current (&priv->ac_ip6_config), - default_route_metric_penalty_get (self, AF_INET6)); + if (priv->ac_ip6_config) { + nm_ip6_config_subtract (priv->ext_ip6_config, priv->ac_ip6_config, + default_route_metric_penalty_get (self, AF_INET6)); } - if (applied_config_get_current (&priv->dhcp6.ip6_config)) { - nm_ip_config_subtract ((NMIPConfig *) priv->ext_ip_config_6, - applied_config_get_current (&priv->dhcp6.ip6_config), - default_route_metric_penalty_get (self, AF_INET6)); + if (priv->dhcp6.ip6_config) { + nm_ip6_config_subtract (priv->ext_ip6_config, priv->dhcp6.ip6_config, + default_route_metric_penalty_get (self, AF_INET6)); } - if (applied_config_get_current (&priv->wwan_ip_config_6)) { - nm_ip_config_subtract ((NMIPConfig *) priv->ext_ip_config_6, - applied_config_get_current (&priv->wwan_ip_config_6), - default_route_metric_penalty_get (self, AF_INET6)); + if (priv->wwan_ip6_config) { + nm_ip6_config_subtract (priv->ext_ip6_config, priv->wwan_ip6_config, + default_route_metric_penalty_get (self, AF_INET6)); } - for (iter = priv->vpn_configs_6; iter; iter = iter->next) - nm_ip6_config_subtract (priv->ext_ip_config_6, iter->data, 0); + for (iter = priv->vpn6_configs; iter; iter = iter->next) + nm_ip6_config_subtract (priv->ext_ip6_config, iter->data, 0); } } @@ -11783,139 +11245,156 @@ update_ext_ip_config (NMDevice *self, int addr_family, gboolean intersect_config } static void -update_ip_config (NMDevice *self, int addr_family) +update_ip_config (NMDevice *self, int addr_family, gboolean initial) { NMDevicePrivate *priv = NM_DEVICE_GET_PRIVATE (self); nm_assert_addr_family (addr_family); - if (addr_family == AF_INET) - priv->update_ip_config_completed_v4 = TRUE; - else - priv->update_ip_config_completed_v6 = TRUE; - - if (update_ext_ip_config (self, addr_family, TRUE)) { + if (update_ext_ip_config (self, addr_family, initial, TRUE)) { if (addr_family == AF_INET) { - if (priv->ext_ip_config_4) - ip_config_merge_and_apply (self, AF_INET, FALSE); + if (priv->ext_ip4_config) + ip4_config_merge_and_apply (self, FALSE); } else { if (priv->ext_ip6_config_captured) - ip_config_merge_and_apply (self, AF_INET6, FALSE); + ip6_config_merge_and_apply (self, FALSE); } } + + if ( addr_family == AF_INET6 + && priv->linklocal6_timeout_id + && priv->ext_ip6_config_captured + && nm_ip6_config_get_address_first_nontentative (priv->ext_ip6_config_captured, TRUE)) { + /* linklocal6 is ready now, do the state transition... we are also + * invoked as g_idle_add, so no problems with reentrance doing it now. + */ + linklocal6_complete (self); + } } void nm_device_capture_initial_config (NMDevice *self) { - NMDevicePrivate *priv = NM_DEVICE_GET_PRIVATE (self); - - if (!priv->update_ip_config_completed_v4) - update_ip_config (self, AF_INET); - if (!priv->update_ip_config_completed_v6) - update_ip_config (self, AF_INET6); + update_ip_config (self, AF_INET, TRUE); + update_ip_config (self, AF_INET6, TRUE); } static gboolean -queued_ip_config_change (NMDevice *self, int addr_family) +queued_ip4_config_change (gpointer user_data) { + NMDevice *self = user_data; NMDevicePrivate *priv; - gboolean need_ipv6ll = FALSE; - const gboolean IS_IPv4 = (addr_family == AF_INET); - NMPlatform *platform; g_return_val_if_fail (NM_IS_DEVICE (self), G_SOURCE_REMOVE); priv = NM_DEVICE_GET_PRIVATE (self); - nm_assert (IS_IPv4 ? !priv->queued_ip4_config_pending : !priv->queued_ip6_config_pending); + nm_assert (!priv->queued_ip4_config_pending); /* Wait for any queued state changes */ if (priv->queued_state.id) - return G_SOURCE_CONTINUE; + return TRUE; - priv->queued_ip_config_id_x[IS_IPv4] = 0; + priv->queued_ip4_config_id = 0; /* If a commit is scheduled, this function would potentially interfere with * it changing IP configurations before they are applied. Postpone the * update in such case. */ if (activation_source_is_scheduled (self, - IS_IPv4 - ? activate_stage5_ip4_config_result - : activate_stage5_ip6_config_commit, - addr_family)) { - if (IS_IPv4) { - priv->queued_ip4_config_pending = FALSE; - priv->queued_ip_config_id_4 = g_idle_add (queued_ip4_config_change, self); - } else { - priv->queued_ip6_config_pending = FALSE; - priv->queued_ip_config_id_6 = g_idle_add (queued_ip6_config_change, self); - } - _LOGT (LOGD_DEVICE, "IP%c update was postponed", - nm_utils_addr_family_to_char (addr_family)); - } else { - update_ip_config (self, addr_family); + activate_stage5_ip4_config_result, + AF_INET)) { + priv->queued_ip4_config_pending = FALSE; + priv->queued_ip4_config_id = g_idle_add (queued_ip4_config_change, self); + _LOGT (LOGD_DEVICE, "IP4 update was postponed"); + } else + update_ip_config (self, AF_INET, FALSE); - if (!IS_IPv4) { - /* Check whether we need to complete waiting for link-local. - * We are also called from an idle handler, so no problem doing state transitions - * now. */ - linklocal6_check_complete (self); - } + set_unmanaged_external_down (self, TRUE); + + if (!nm_device_sys_iface_state_is_external_or_assume (self)) { + priv->v4_has_shadowed_routes = _v4_has_shadowed_routes_detect (self);; + ip4_rp_filter_update (self); } - if (!IS_IPv4) { - if ( priv->state < NM_DEVICE_STATE_DEACTIVATING - && (platform = nm_device_get_platform (self)) - && nm_platform_link_get (platform, priv->ifindex)) { - /* Handle DAD failures */ - while (priv->dad6_failed_addrs) { - nm_auto_nmpobj const NMPObject *obj = NULL; - const NMPlatformIP6Address *addr; + return FALSE; +} - obj = priv->dad6_failed_addrs->data; - priv->dad6_failed_addrs = g_slist_delete_link (priv->dad6_failed_addrs, priv->dad6_failed_addrs); +static gboolean +queued_ip6_config_change (gpointer user_data) +{ + NMDevice *self = user_data; + NMDevicePrivate *priv; + GSList *iter; + gboolean need_ipv6ll = FALSE; - if (!nm_ndisc_dad_addr_is_fail_candidate (platform, obj)) - continue; + g_return_val_if_fail (NM_IS_DEVICE (self), G_SOURCE_REMOVE); - addr = NMP_OBJECT_CAST_IP6_ADDRESS (obj); + priv = NM_DEVICE_GET_PRIVATE (self); - _LOGI (LOGD_IP6, "ipv6: duplicate address check failed for the %s address", - nm_platform_ip6_address_to_string (addr, NULL, 0)); + nm_assert (!priv->queued_ip4_config_pending); - if (IN6_IS_ADDR_LINKLOCAL (&addr->address)) - need_ipv6ll = TRUE; - else if (priv->ndisc) - nm_ndisc_dad_failed (priv->ndisc, &addr->address); - } + /* Wait for any queued state changes */ + if (priv->queued_state.id) + return TRUE; - /* If no IPv6 link-local address exists but other addresses do then we - * must add the LL address to remain conformant with RFC 3513 chapter 2.1 - * ("Addressing Model"): "All interfaces are required to have at least - * one link-local unicast address". - */ - if ( priv->ip_config_6 - && nm_ip6_config_get_num_addresses (priv->ip_config_6)) - need_ipv6ll = TRUE; + priv->queued_ip6_config_id = 0; - if (need_ipv6ll) - check_and_add_ipv6ll_addr (self); - } else { - g_slist_free_full (priv->dad6_failed_addrs, (GDestroyNotify) nmp_object_unref); - priv->dad6_failed_addrs = NULL; + /* If a commit is scheduled, this function would potentially interfere with + * it changing IP configurations before they are applied. Postpone the + * update in such case. + */ + if (activation_source_is_scheduled (self, + activate_stage5_ip6_config_commit, + AF_INET6)) { + priv->queued_ip6_config_pending = FALSE; + priv->queued_ip6_config_id = g_idle_add (queued_ip6_config_change, self); + _LOGT (LOGD_DEVICE, "IP6 update was postponed"); + } else + update_ip_config (self, AF_INET6, FALSE); + + if (priv->state < NM_DEVICE_STATE_DEACTIVATING + && nm_platform_link_get (nm_device_get_platform (self), priv->ifindex)) { + /* Handle DAD failures */ + for (iter = priv->dad6_failed_addrs; iter; iter = g_slist_next (iter)) { + NMPlatformIP6Address *addr = iter->data; + + if (addr->addr_source >= NM_IP_CONFIG_SOURCE_USER) + continue; + + _LOGI (LOGD_IP6, "ipv6: duplicate address check failed for the %s address", + nm_platform_ip6_address_to_string (addr, NULL, 0)); + + if (IN6_IS_ADDR_LINKLOCAL (&addr->address)) + need_ipv6ll = TRUE; + else if (priv->ndisc) + nm_ndisc_dad_failed (priv->ndisc, &addr->address); } - /* Check if DAD is still pending */ - if ( priv->ip6_state == IP_CONF - && priv->dad6_ip6_config - && priv->ext_ip6_config_captured - && !nm_ip6_config_has_any_dad_pending (priv->ext_ip6_config_captured, - priv->dad6_ip6_config)) { + /* If no IPv6 link-local address exists but other addresses do then we + * must add the LL address to remain conformant with RFC 3513 chapter 2.1 + * ("Addressing Model"): "All interfaces are required to have at least + * one link-local unicast address". + */ + if (priv->ip6_config && nm_ip6_config_get_num_addresses (priv->ip6_config)) + need_ipv6ll = TRUE; + + if (need_ipv6ll) + check_and_add_ipv6ll_addr (self); + } + + g_slist_free_full (priv->dad6_failed_addrs, g_free); + priv->dad6_failed_addrs = NULL; + + /* Check if DAD is still pending */ + if ( priv->ip6_state == IP_CONF + && priv->dad6_ip6_config + && priv->ext_ip6_config_captured) { + if (!nm_ip6_config_has_any_dad_pending (priv->ext_ip6_config_captured, + priv->dad6_ip6_config)) { _LOGD (LOGD_DEVICE | LOGD_IP6, "IPv6 DAD terminated"); g_clear_object (&priv->dad6_ip6_config); - _set_ip_state (self, addr_family, IP_DONE); + _set_ip_state (self, AF_INET6, IP_DONE); check_ip_state (self, FALSE, TRUE); if (priv->rt6_temporary_not_available) nm_device_activate_schedule_ip6_config_result (self); @@ -11924,40 +11403,21 @@ queued_ip_config_change (NMDevice *self, int addr_family) set_unmanaged_external_down (self, TRUE); - if (IS_IPv4) { - if (!nm_device_sys_iface_state_is_external_or_assume (self)) { - priv->v4_has_shadowed_routes = _v4_has_shadowed_routes_detect (self);; - ip4_rp_filter_update (self); - } - } - - return G_SOURCE_REMOVE; -} - -static gboolean -queued_ip4_config_change (gpointer user_data) -{ - return queued_ip_config_change (user_data, AF_INET); -} - -static gboolean -queued_ip6_config_change (gpointer user_data) -{ - return queued_ip_config_change (user_data, AF_INET6); + return FALSE; } static void device_ipx_changed (NMPlatform *platform, int obj_type_i, int ifindex, - gconstpointer platform_object, + gpointer platform_object, int change_type_i, NMDevice *self) { const NMPObjectType obj_type = obj_type_i; const NMPlatformSignalChangeType change_type = change_type_i; NMDevicePrivate *priv; - const NMPlatformIP6Address *addr; + NMPlatformIP6Address *addr; if (nm_device_get_ip_ifindex (self) != ifindex) return; @@ -11969,10 +11429,10 @@ device_ipx_changed (NMPlatform *platform, case NMP_OBJECT_TYPE_IP4_ROUTE: if (nm_device_get_unmanaged_flags (self, NM_UNMANAGED_PLATFORM_INIT)) { priv->queued_ip4_config_pending = TRUE; - nm_assert_se (!nm_clear_g_source (&priv->queued_ip_config_id_4)); - } else if (!priv->queued_ip_config_id_4) { + nm_assert_se (!nm_clear_g_source (&priv->queued_ip4_config_id)); + } else if (!priv->queued_ip4_config_id) { priv->queued_ip4_config_pending = FALSE; - priv->queued_ip_config_id_4 = g_idle_add (queued_ip4_config_change, self); + priv->queued_ip4_config_id = g_idle_add (queued_ip4_config_change, self); _LOGD (LOGD_DEVICE, "queued IP4 config change"); } break; @@ -11981,18 +11441,19 @@ device_ipx_changed (NMPlatform *platform, if ( priv->state > NM_DEVICE_STATE_DISCONNECTED && priv->state < NM_DEVICE_STATE_DEACTIVATING - && nm_ndisc_dad_addr_is_fail_candidate_event (change_type, addr)) { - priv->dad6_failed_addrs = g_slist_prepend (priv->dad6_failed_addrs, - (gpointer) nmp_object_ref (NMP_OBJECT_UP_CAST (addr))); + && ( (change_type == NM_PLATFORM_SIGNAL_CHANGED && addr->n_ifa_flags & IFA_F_DADFAILED) + || (change_type == NM_PLATFORM_SIGNAL_REMOVED && addr->n_ifa_flags & IFA_F_TENTATIVE))) { + priv->dad6_failed_addrs = g_slist_append (priv->dad6_failed_addrs, + g_memdup (addr, sizeof (NMPlatformIP6Address))); } /* fall through */ case NMP_OBJECT_TYPE_IP6_ROUTE: if (nm_device_get_unmanaged_flags (self, NM_UNMANAGED_PLATFORM_INIT)) { priv->queued_ip6_config_pending = TRUE; - nm_assert_se (!nm_clear_g_source (&priv->queued_ip_config_id_6)); - } else if (!priv->queued_ip_config_id_6) { + nm_assert_se (!nm_clear_g_source (&priv->queued_ip6_config_id)); + } else if (!priv->queued_ip6_config_id) { priv->queued_ip6_config_pending = FALSE; - priv->queued_ip_config_id_6 = g_idle_add (queued_ip6_config_change, self); + priv->queued_ip6_config_id = g_idle_add (queued_ip6_config_change, self); _LOGD (LOGD_DEVICE, "queued IP6 config change"); } break; @@ -12260,14 +11721,14 @@ _set_unmanaged_flags (NMDevice *self, if (priv->queued_ip4_config_pending) { priv->queued_ip4_config_pending = FALSE; - nm_assert_se (!nm_clear_g_source (&priv->queued_ip_config_id_4)); - priv->queued_ip_config_id_4 = g_idle_add (queued_ip4_config_change, self); + nm_assert_se (!nm_clear_g_source (&priv->queued_ip4_config_id)); + priv->queued_ip4_config_id = g_idle_add (queued_ip4_config_change, self); } if (priv->queued_ip6_config_pending) { priv->queued_ip6_config_pending = FALSE; - nm_assert_se (!nm_clear_g_source (&priv->queued_ip_config_id_6)); - priv->queued_ip_config_id_6 = g_idle_add (queued_ip6_config_change, self); + nm_assert_se (!nm_clear_g_source (&priv->queued_ip6_config_id)); + priv->queued_ip6_config_id = g_idle_add (queued_ip6_config_change, self); } if (!priv->pending_actions) { @@ -12533,7 +11994,7 @@ nm_device_reapply_settings_immediately (NMDevice *self) if (g_strcmp0 ((zone = nm_setting_connection_get_zone (s_con_settings)), nm_setting_connection_get_zone (s_con_applied)) != 0) { - version_id = nm_active_connection_version_id_bump ((NMActiveConnection *) self->_priv->act_request.obj); + version_id = nm_active_connection_version_id_bump ((NMActiveConnection *) self->_priv->act_request); _LOGD (LOGD_DEVICE, "reapply setting: zone = %s%s%s (version-id %llu)", NM_PRINT_FMT_QUOTE_STRING (zone), (unsigned long long) version_id); g_object_set (G_OBJECT (s_con_applied), @@ -12545,7 +12006,7 @@ nm_device_reapply_settings_immediately (NMDevice *self) if ((metered = nm_setting_connection_get_metered (s_con_settings)) != nm_setting_connection_get_metered (s_con_applied)) { - version_id = nm_active_connection_version_id_bump ((NMActiveConnection *) self->_priv->act_request.obj); + version_id = nm_active_connection_version_id_bump ((NMActiveConnection *) self->_priv->act_request); _LOGD (LOGD_DEVICE, "reapply setting: metered = %d (version-id %llu)", (int) metered, (unsigned long long) version_id); g_object_set (G_OBJECT (s_con_applied), @@ -12601,27 +12062,13 @@ nm_device_update_metered (NMDevice *self) /* Try to guess a value using the metered flag in IP configuration */ if (value == NM_METERED_INVALID) { - if ( priv->ip_config_4 + if ( priv->ip4_config && priv->ip4_state == IP_DONE - && nm_ip4_config_get_metered (priv->ip_config_4)) - value = NM_METERED_GUESS_YES; - } - - /* Otherwise look at connection type. For Bluetooth, we look at the type of - * Bluetooth sharing: for PANU/DUN (where we are receiving internet from - * another device) we set GUESS_YES; for NAP (where we are sharing internet - * to another device) we set GUESS_NO. We ignore WiMAX here as it’s no - * longer supported by NetworkManager. */ - if ( value == NM_METERED_INVALID - && nm_connection_is_type (connection, NM_SETTING_BLUETOOTH_SETTING_NAME)) { - - if (_nm_connection_get_setting_bluetooth_for_nap (connection)) { - /* NAP types are not metered, but other types are. */ - value = NM_METERED_GUESS_NO; - } else + && nm_ip4_config_get_metered (priv->ip4_config)) value = NM_METERED_GUESS_YES; } + /* Otherwise look at connection type */ if (value == NM_METERED_INVALID) { if ( nm_connection_is_type (connection, NM_SETTING_GSM_SETTING_NAME) || nm_connection_is_type (connection, NM_SETTING_CDMA_SETTING_NAME)) @@ -12712,7 +12159,7 @@ nm_device_check_connection_available (NMDevice *self, for (i = 0; i <= NM_DEVICE_CHECK_CON_AVAILABLE_ALL; i++) { for (j = 1; j <= NM_DEVICE_CHECK_CON_AVAILABLE_ALL; j <<= 1) { - if (NM_FLAGS_ANY (i, j)) { + if (NM_FLAGS_HAS (i, j)) { k = i & ~j; nm_assert ( available_all[i] == available_all[k] || available_all[i]); @@ -12737,7 +12184,7 @@ available_connections_del_all (NMDevice *self) static gboolean available_connections_add (NMDevice *self, NMConnection *connection) { - return g_hash_table_add (self->_priv->available_connections, g_object_ref (connection)); + return nm_g_hash_table_add (self->_priv->available_connections, g_object_ref (connection)); } static gboolean @@ -12795,7 +12242,7 @@ nm_device_recheck_available_connections (NMDevice *self) priv = NM_DEVICE_GET_PRIVATE(self); if (g_hash_table_size (priv->available_connections) > 0) { - prune_list = g_hash_table_new (nm_direct_hash, NULL); + prune_list = g_hash_table_new (g_direct_hash, g_direct_equal); g_hash_table_iter_init (&h_iter, priv->available_connections); while (g_hash_table_iter_next (&h_iter, (gpointer *) &connection, NULL)) g_hash_table_add (prune_list, connection); @@ -12904,19 +12351,19 @@ cp_connection_added_or_updated (NMDevice *self, NMConnection *connection) } static void -cp_connection_added (NMSettings *settings, NMConnection *connection, gpointer user_data) +cp_connection_added (NMConnectionProvider *cp, NMConnection *connection, gpointer user_data) { cp_connection_added_or_updated (user_data, connection); } static void -cp_connection_updated (NMSettings *settings, NMConnection *connection, gboolean by_user, gpointer user_data) +cp_connection_updated (NMConnectionProvider *cp, NMConnection *connection, gboolean by_user, gpointer user_data) { cp_connection_added_or_updated (user_data, connection); } static void -cp_connection_removed (NMSettings *settings, NMConnection *connection, gpointer user_data) +cp_connection_removed (NMConnectionProvider *cp, NMConnection *connection, gpointer user_data) { NMDevice *self = user_data; @@ -13098,8 +12545,8 @@ _cleanup_generic_pre (NMDevice *self, CleanupType cleanup_type) queued_state_clear (self); - _cleanup_ip_pre (self, AF_INET, cleanup_type); - _cleanup_ip_pre (self, AF_INET6, cleanup_type); + _cleanup_ip4_pre (self, cleanup_type); + _cleanup_ip6_pre (self, cleanup_type); } static void @@ -13121,41 +12568,39 @@ _cleanup_generic_post (NMDevice *self, CleanupType cleanup_type) /* Clean up IP configs; this does not actually deconfigure the * interface; the caller must flush routes and addresses explicitly. */ - nm_device_set_ip_config (self, AF_INET, NULL, TRUE, NULL); - nm_device_set_ip_config (self, AF_INET6, NULL, TRUE, NULL); + nm_device_set_ip4_config (self, NULL, TRUE, NULL); + nm_device_set_ip6_config (self, NULL, TRUE); g_clear_object (&priv->proxy_config); - g_clear_object (&priv->con_ip_config_4); - applied_config_clear (&priv->dev_ip4_config); - applied_config_clear (&priv->wwan_ip_config_4); - g_clear_object (&priv->ext_ip_config_4); - g_clear_object (&priv->ip_config_4); - g_clear_object (&priv->con_ip_config_6); - applied_config_clear (&priv->ac_ip6_config); - g_clear_object (&priv->ext_ip_config_6); + g_clear_object (&priv->con_ip4_config); + g_clear_object (&priv->dev_ip4_config); + g_clear_object (&priv->ext_ip4_config); + g_clear_object (&priv->wwan_ip4_config); + g_clear_object (&priv->ip4_config); + g_clear_object (&priv->con_ip6_config); + g_clear_object (&priv->ac_ip6_config); + g_clear_object (&priv->ext_ip6_config); g_clear_object (&priv->ext_ip6_config_captured); - applied_config_clear (&priv->wwan_ip_config_6); - g_clear_object (&priv->ip_config_6); + g_clear_object (&priv->wwan_ip6_config); + g_clear_object (&priv->ip6_config); g_clear_object (&priv->dad6_ip6_config); - 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_g_source (&priv->rt6_temporary_not_available_id); - g_slist_free_full (priv->vpn_configs_4, g_object_unref); - priv->vpn_configs_4 = NULL; - g_slist_free_full (priv->vpn_configs_6, g_object_unref); - priv->vpn_configs_6 = NULL; + g_slist_free_full (priv->vpn4_configs, g_object_unref); + priv->vpn4_configs = NULL; + g_slist_free_full (priv->vpn6_configs, g_object_unref); + priv->vpn6_configs = NULL; - /* We no longer accept the delegations. nm_device_set_ip_config(NULL) + /* We no longer accept the delegations. nm_device_set_ip6_config(NULL) * above disables them. */ nm_assert (priv->needs_ip6_subnet == FALSE); - if (priv->act_request.obj) { - nm_active_connection_set_default (NM_ACTIVE_CONNECTION (priv->act_request.obj), AF_INET, FALSE); + if (priv->act_request) { + nm_active_connection_set_default (NM_ACTIVE_CONNECTION (priv->act_request), AF_INET, FALSE); priv->master_ready_handled = FALSE; - nm_clear_g_signal_handler (priv->act_request.obj, &priv->master_ready_id); + nm_clear_g_signal_handler (priv->act_request, &priv->master_ready_id); act_request_set (self, NULL); } @@ -13177,7 +12622,7 @@ _cleanup_generic_post (NMDevice *self, CleanupType cleanup_type) * those are identified by ip_iface, not by iface (which might be a tty * or ATM device). */ - _set_ip_ifindex (self, 0, NULL); + nm_device_set_ip_iface (self, NULL); } /* @@ -13297,10 +12742,10 @@ find_dhcp4_address (NMDevice *self) const NMPlatformIP4Address *a; NMDedupMultiIter ipconf_iter; - if (!priv->ip_config_4) + if (!priv->ip4_config) return NULL; - nm_ip_config_iter_ip4_address_for_each (&ipconf_iter, priv->ip_config_4, &a) { + nm_ip_config_iter_ip4_address_for_each (&ipconf_iter, priv->ip4_config, &a) { if (a->addr_source == NM_IP_CONFIG_SOURCE_DHCP) return g_strdup (nm_utils_inet4_ntop (a->address, NULL)); } @@ -13607,7 +13052,7 @@ _set_state_full (NMDevice *self, g_cancellable_cancel (priv->deactivating_cancellable); /* Cache the activation request for the dispatcher */ - req = nm_g_object_ref (priv->act_request.obj); + req = nm_g_object_ref (priv->act_request); if ( state > NM_DEVICE_STATE_UNMANAGED && state <= NM_DEVICE_STATE_ACTIVATED @@ -13715,8 +13160,8 @@ _set_state_full (NMDevice *self, /* Clean up any half-done IP operations if the device's layer2 * finds out it needs authentication during IP config. */ - _cleanup_ip_pre (self, AF_INET, CLEANUP_TYPE_DECONFIGURE); - _cleanup_ip_pre (self, AF_INET6, CLEANUP_TYPE_DECONFIGURE); + _cleanup_ip4_pre (self, CLEANUP_TYPE_DECONFIGURE); + _cleanup_ip6_pre (self, CLEANUP_TYPE_DECONFIGURE); } break; default: @@ -13730,13 +13175,6 @@ _set_state_full (NMDevice *self, _notify (self, PROP_STATE); _notify (self, PROP_STATE_REASON); - nm_dbus_object_emit_signal (NM_DBUS_OBJECT (self), - &interface_info_device, - &signal_info_state_changed, - "(uuu)", - (guint32) state, - (guint32) old_state, - (guint32) reason); g_signal_emit (self, signals[STATE_CHANGED], 0, (guint) state, (guint) old_state, (guint) reason); /* Post-process the event after internal notification */ @@ -13887,7 +13325,7 @@ _set_state_full (NMDevice *self, if (ip_config_valid (old_state) && !ip_config_valid (state)) notify_ip_properties (self); - nm_device_check_connectivity_update_interval (self); + concheck_periodic_update (self); /* Dispose of the cached activation request */ if (req) @@ -14849,15 +14287,8 @@ nm_device_init (NMDevice *self) self->_priv = priv; - c_list_init (&priv->concheck_lst_head); - c_list_init (&self->devices_lst); c_list_init (&priv->slaves); - priv->connectivity_state = NM_CONNECTIVITY_UNKNOWN; - - nm_dbus_track_obj_path_init (&priv->parent_device, G_OBJECT (self), obj_properties[PROP_PARENT]); - nm_dbus_track_obj_path_init (&priv->act_request, G_OBJECT (self), obj_properties[PROP_ACTIVE_CONNECTION]); - priv->netns = g_object_ref (NM_NETNS_GET); priv->autoconnect_blocked_flags = DEFAULT_AUTOCONNECT @@ -14872,7 +14303,7 @@ nm_device_init (NMDevice *self) priv->rfkill_type = RFKILL_TYPE_UNKNOWN; priv->unmanaged_flags = NM_UNMANAGED_PLATFORM_INIT; priv->unmanaged_mask = priv->unmanaged_flags; - priv->available_connections = g_hash_table_new_full (nm_direct_hash, NULL, g_object_unref, NULL); + priv->available_connections = g_hash_table_new_full (g_direct_hash, g_direct_equal, g_object_unref, NULL); priv->ip6_saved_properties = g_hash_table_new_full (nm_str_hash, g_str_equal, NULL, g_free); priv->sys_iface_state = NM_DEVICE_SYS_IFACE_STATE_EXTERNAL; @@ -14971,19 +14402,9 @@ dispose (GObject *object) NMDevice *self = NM_DEVICE (object); NMDevicePrivate *priv = NM_DEVICE_GET_PRIVATE (self); NMPlatform *platform; - NMDeviceConnectivityHandle *con_handle; - gs_free_error GError *cancelled_error = NULL; _LOGD (LOGD_DEVICE, "disposing"); - nm_assert (c_list_is_empty (&self->devices_lst)); - - while ((con_handle = c_list_first_entry (&priv->concheck_lst_head, NMDeviceConnectivityHandle, concheck_lst))) { - if (!cancelled_error) - nm_utils_error_set_cancelled (&cancelled_error, FALSE, "NMDevice"); - concheck_handle_complete (con_handle, cancelled_error); - } - nm_clear_g_cancellable (&priv->deactivating_cancellable); nm_device_assume_state_reset (self); @@ -14994,8 +14415,8 @@ dispose (GObject *object) g_signal_handlers_disconnect_by_func (platform, G_CALLBACK (device_ipx_changed), self); g_signal_handlers_disconnect_by_func (platform, G_CALLBACK (link_changed_cb), self); - g_slist_free_full (priv->acd.dad_list, (GDestroyNotify) nm_acd_manager_destroy); - priv->acd.dad_list = NULL; + g_slist_free_full (priv->arping.dad_list, (GDestroyNotify) nm_arping_manager_destroy); + priv->arping.dad_list = NULL; arp_cleanup (self); @@ -15057,8 +14478,6 @@ dispose (GObject *object) g_clear_object (&priv->lldp_listener); } - nm_clear_g_source (&priv->concheck_p_cur_id); - G_OBJECT_CLASS (nm_device_parent_class)->dispose (object); if (nm_clear_g_source (&priv->queued_state.id)) { @@ -15081,7 +14500,7 @@ finalize (GObject *object) g_free (priv->hw_addr_perm); g_free (priv->hw_addr_initial); g_slist_free (priv->pending_actions); - g_slist_free_full (priv->dad6_failed_addrs, (GDestroyNotify) nmp_object_unref); + g_slist_free_full (priv->dad6_failed_addrs, g_free); g_clear_pointer (&priv->physical_port_id, g_free); g_free (priv->udi); g_free (priv->iface); @@ -15090,22 +14509,19 @@ finalize (GObject *object) g_free (priv->driver_version); g_free (priv->firmware_version); g_free (priv->type_desc); + g_free (priv->type_description); g_free (priv->dhcp_anycast_address); g_free (priv->current_stable_id); g_hash_table_unref (priv->ip6_saved_properties); g_hash_table_unref (priv->available_connections); - nm_dbus_track_obj_path_deinit (&priv->parent_device); - nm_dbus_track_obj_path_deinit (&priv->act_request); - G_OBJECT_CLASS (nm_device_parent_class)->finalize (object); /* for testing, NMDeviceTest does not invoke NMDevice::constructed, * and thus @settings might be unset. */ - nm_g_object_unref (priv->settings); - - nm_g_object_unref (priv->concheck_mgr); + if (priv->settings) + g_object_unref (priv->settings); g_object_unref (priv->netns); } @@ -15215,6 +14631,9 @@ get_property (GObject *object, guint prop_id, { NMDevice *self = NM_DEVICE (object); NMDevicePrivate *priv = NM_DEVICE_GET_PRIVATE (self); + GPtrArray *array; + GHashTableIter iter; + NMConnection *connection; GVariantBuilder array_builder; switch (prop_id) { @@ -15270,16 +14689,16 @@ get_property (GObject *object, guint prop_id, 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); + nm_utils_g_value_set_object_path (value, ip_config_valid (priv->state) ? priv->ip4_config : NULL); break; case PROP_DHCP4_CONFIG: - nm_dbus_utils_g_value_set_object_path (value, ip_config_valid (priv->state) ? priv->dhcp4.config : NULL); + nm_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); + nm_utils_g_value_set_object_path (value, ip_config_valid (priv->state) ? priv->ip6_config : NULL); break; case PROP_DHCP6_CONFIG: - nm_dbus_utils_g_value_set_object_path (value, ip_config_valid (priv->state) ? priv->dhcp6.config : NULL); + nm_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); @@ -15289,7 +14708,7 @@ get_property (GObject *object, guint prop_id, 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)); + nm_utils_g_value_set_object_path (value, priv->act_request_public ? priv->act_request : NULL); break; case PROP_DEVICE_TYPE: g_value_set_uint (value, priv->type); @@ -15320,9 +14739,12 @@ get_property (GObject *object, guint prop_id, 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); + array = g_ptr_array_sized_new (g_hash_table_size (priv->available_connections)); + g_hash_table_iter_init (&iter, priv->available_connections); + while (g_hash_table_iter_next (&iter, (gpointer) &connection, NULL)) + g_ptr_array_add (array, g_strdup (nm_connection_get_path (connection))); + g_ptr_array_add (array, NULL); + g_value_take_boxed (value, (char **) g_ptr_array_free (array, FALSE)); break; case PROP_PHYSICAL_PORT_ID: g_value_set_string (value, priv->physical_port_id); @@ -15331,7 +14753,7 @@ get_property (GObject *object, guint prop_id, 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)); + nm_utils_g_value_set_object_path (value, priv->parent_device); break; case PROP_HW_ADDRESS: g_value_set_string (value, priv->hw_addr); @@ -15376,7 +14798,7 @@ get_property (GObject *object, guint prop_id, if (!NM_DEVICE_GET_PRIVATE (info->slave)->is_enslaved) continue; - path = nm_dbus_object_get_path (NM_DBUS_OBJECT (info->slave)); + path = nm_exported_object_get_path ((NMExportedObject *) info->slave); if (path) slave_list[i++] = g_strdup (path); } @@ -15403,115 +14825,15 @@ get_property (GObject *object, guint prop_id, } } -static const GDBusSignalInfo signal_info_state_changed = NM_DEFINE_GDBUS_SIGNAL_INFO_INIT ( - "StateChanged", - .args = NM_DEFINE_GDBUS_ARG_INFOS ( - NM_DEFINE_GDBUS_ARG_INFO ("new_state", "u"), - NM_DEFINE_GDBUS_ARG_INFO ("old_state", "u"), - NM_DEFINE_GDBUS_ARG_INFO ("reason", "u"), - ), -); - -static const NMDBusInterfaceInfoExtended interface_info_device = { - .parent = NM_DEFINE_GDBUS_INTERFACE_INFO_INIT ( - NM_DBUS_INTERFACE_DEVICE, - .methods = NM_DEFINE_GDBUS_METHOD_INFOS ( - NM_DEFINE_DBUS_METHOD_INFO_EXTENDED ( - NM_DEFINE_GDBUS_METHOD_INFO_INIT ( - "Reapply", - .in_args = NM_DEFINE_GDBUS_ARG_INFOS ( - NM_DEFINE_GDBUS_ARG_INFO ("connection", "a{sa{sv}}"), - NM_DEFINE_GDBUS_ARG_INFO ("version_id", "t"), - NM_DEFINE_GDBUS_ARG_INFO ("flags", "u"), - ), - ), - .handle = impl_device_reapply, - ), - NM_DEFINE_DBUS_METHOD_INFO_EXTENDED ( - NM_DEFINE_GDBUS_METHOD_INFO_INIT ( - "GetAppliedConnection", - .in_args = NM_DEFINE_GDBUS_ARG_INFOS ( - NM_DEFINE_GDBUS_ARG_INFO ("flags", "u"), - ), - .out_args = NM_DEFINE_GDBUS_ARG_INFOS ( - NM_DEFINE_GDBUS_ARG_INFO ("connection", "a{sa{sv}}"), - NM_DEFINE_GDBUS_ARG_INFO ("version_id", "t"), - ), - ), - .handle = impl_device_get_applied_connection, - ), - NM_DEFINE_DBUS_METHOD_INFO_EXTENDED ( - NM_DEFINE_GDBUS_METHOD_INFO_INIT ( - "Disconnect", - ), - .handle = impl_device_disconnect, - ), - NM_DEFINE_DBUS_METHOD_INFO_EXTENDED ( - NM_DEFINE_GDBUS_METHOD_INFO_INIT ( - "Delete", - ), - .handle = impl_device_delete, - ), - ), - .signals = NM_DEFINE_GDBUS_SIGNAL_INFOS ( - &signal_info_state_changed, - ), - .properties = NM_DEFINE_GDBUS_PROPERTY_INFOS ( - NM_DEFINE_DBUS_PROPERTY_INFO_EXTENDED_READABLE_L ("Udi", "s", NM_DEVICE_UDI), - NM_DEFINE_DBUS_PROPERTY_INFO_EXTENDED_READABLE_L ("Interface", "s", NM_DEVICE_IFACE), - NM_DEFINE_DBUS_PROPERTY_INFO_EXTENDED_READABLE_L ("IpInterface", "s", NM_DEVICE_IP_IFACE), - NM_DEFINE_DBUS_PROPERTY_INFO_EXTENDED_READABLE_L ("Driver", "s", NM_DEVICE_DRIVER), - NM_DEFINE_DBUS_PROPERTY_INFO_EXTENDED_READABLE_L ("DriverVersion", "s", NM_DEVICE_DRIVER_VERSION), - NM_DEFINE_DBUS_PROPERTY_INFO_EXTENDED_READABLE_L ("FirmwareVersion", "s", NM_DEVICE_FIRMWARE_VERSION), - NM_DEFINE_DBUS_PROPERTY_INFO_EXTENDED_READABLE_L ("Capabilities", "u", NM_DEVICE_CAPABILITIES), - NM_DEFINE_DBUS_PROPERTY_INFO_EXTENDED_READABLE_L ("Ip4Address", "u", NM_DEVICE_IP4_ADDRESS), - NM_DEFINE_DBUS_PROPERTY_INFO_EXTENDED_READABLE_L ("State", "u", NM_DEVICE_STATE), - NM_DEFINE_DBUS_PROPERTY_INFO_EXTENDED_READABLE_L ("StateReason", "(uu)", NM_DEVICE_STATE_REASON), - NM_DEFINE_DBUS_PROPERTY_INFO_EXTENDED_READABLE_L ("ActiveConnection", "o", NM_DEVICE_ACTIVE_CONNECTION), - NM_DEFINE_DBUS_PROPERTY_INFO_EXTENDED_READABLE_L ("Ip4Config", "o", NM_DEVICE_IP4_CONFIG), - NM_DEFINE_DBUS_PROPERTY_INFO_EXTENDED_READABLE_L ("Dhcp4Config", "o", NM_DEVICE_DHCP4_CONFIG), - NM_DEFINE_DBUS_PROPERTY_INFO_EXTENDED_READABLE_L ("Ip6Config", "o", NM_DEVICE_IP6_CONFIG), - NM_DEFINE_DBUS_PROPERTY_INFO_EXTENDED_READABLE_L ("Dhcp6Config", "o", NM_DEVICE_DHCP6_CONFIG), - NM_DEFINE_DBUS_PROPERTY_INFO_EXTENDED_READWRITABLE_L ("Managed", "b", NM_DEVICE_MANAGED, NM_AUTH_PERMISSION_NETWORK_CONTROL, NM_AUDIT_OP_DEVICE_MANAGED), - NM_DEFINE_DBUS_PROPERTY_INFO_EXTENDED_READWRITABLE_L ("Autoconnect", "b", NM_DEVICE_AUTOCONNECT, NM_AUTH_PERMISSION_NETWORK_CONTROL, NM_AUDIT_OP_DEVICE_AUTOCONNECT), - NM_DEFINE_DBUS_PROPERTY_INFO_EXTENDED_READABLE_L ("FirmwareMissing", "b", NM_DEVICE_FIRMWARE_MISSING), - NM_DEFINE_DBUS_PROPERTY_INFO_EXTENDED_READABLE_L ("NmPluginMissing", "b", NM_DEVICE_NM_PLUGIN_MISSING), - NM_DEFINE_DBUS_PROPERTY_INFO_EXTENDED_READABLE_L ("DeviceType", "u", NM_DEVICE_DEVICE_TYPE), - NM_DEFINE_DBUS_PROPERTY_INFO_EXTENDED_READABLE_L ("AvailableConnections", "ao", NM_DEVICE_AVAILABLE_CONNECTIONS), - NM_DEFINE_DBUS_PROPERTY_INFO_EXTENDED_READABLE_L ("PhysicalPortId", "s", NM_DEVICE_PHYSICAL_PORT_ID), - NM_DEFINE_DBUS_PROPERTY_INFO_EXTENDED_READABLE_L ("Mtu", "u", NM_DEVICE_MTU), - NM_DEFINE_DBUS_PROPERTY_INFO_EXTENDED_READABLE_L ("Metered", "u", NM_DEVICE_METERED), - NM_DEFINE_DBUS_PROPERTY_INFO_EXTENDED_READABLE_L ("LldpNeighbors", "aa{sv}", NM_DEVICE_LLDP_NEIGHBORS), - NM_DEFINE_DBUS_PROPERTY_INFO_EXTENDED_READABLE_L ("Real", "b", NM_DEVICE_REAL), - ), - ), -}; - -const NMDBusInterfaceInfoExtended nm_interface_info_device_statistics = { - .parent = NM_DEFINE_GDBUS_INTERFACE_INFO_INIT ( - NM_DBUS_INTERFACE_DEVICE_STATISTICS, - .signals = NM_DEFINE_GDBUS_SIGNAL_INFOS ( - &nm_signal_info_property_changed_legacy, - ), - .properties = NM_DEFINE_GDBUS_PROPERTY_INFOS ( - NM_DEFINE_DBUS_PROPERTY_INFO_EXTENDED_READWRITABLE ("RefreshRateMs", "u", NM_DEVICE_STATISTICS_REFRESH_RATE_MS, NM_AUTH_PERMISSION_ENABLE_DISABLE_STATISTICS, NM_AUDIT_OP_STATISTICS), - NM_DEFINE_DBUS_PROPERTY_INFO_EXTENDED_READABLE ("TxBytes", "t", NM_DEVICE_STATISTICS_TX_BYTES), - NM_DEFINE_DBUS_PROPERTY_INFO_EXTENDED_READABLE ("RxBytes", "t", NM_DEVICE_STATISTICS_RX_BYTES), - ), - ), -}; - static void nm_device_class_init (NMDeviceClass *klass) { GObjectClass *object_class = G_OBJECT_CLASS (klass); - NMDBusObjectClass *dbus_object_class = NM_DBUS_OBJECT_CLASS (klass); + NMExportedObjectClass *exported_object_class = NM_EXPORTED_OBJECT_CLASS (klass); g_type_class_add_private (object_class, sizeof (NMDevicePrivate)); - dbus_object_class->export_path = NM_DBUS_EXPORT_PATH_NUMBERED (NM_DBUS_PATH"/Devices"); - dbus_object_class->interface_infos = NM_DBUS_INTERFACE_INFOS (&interface_info_device, - &nm_interface_info_device_statistics); + exported_object_class->export_path = NM_EXPORT_PATH_NUMBERED (NM_DBUS_PATH"/Devices"); object_class->dispose = dispose; object_class->finalize = finalize; @@ -15743,6 +15065,7 @@ nm_device_class_init (NMDeviceClass *klass) G_PARAM_READABLE | G_PARAM_STATIC_STRINGS); + /* Statistics */ obj_properties[PROP_REFRESH_RATE_MS] = g_param_spec_uint (NM_DEVICE_STATISTICS_REFRESH_RATE_MS, "", "", 0, UINT32_MAX, 0, @@ -15759,6 +15082,7 @@ nm_device_class_init (NMDeviceClass *klass) G_PARAM_READABLE | G_PARAM_STATIC_STRINGS); + /* Connectivity */ obj_properties[PROP_CONNECTIVITY] = g_param_spec_uint (NM_DEVICE_CONNECTIVITY, "", "", NM_CONNECTIVITY_UNKNOWN, NM_CONNECTIVITY_FULL, NM_CONNECTIVITY_UNKNOWN, @@ -15841,11 +15165,15 @@ nm_device_class_init (NMDeviceClass *klass) 0, NULL, NULL, NULL, G_TYPE_NONE, 0); - signals[CONNECTIVITY_CHANGED] = - g_signal_new (NM_DEVICE_CONNECTIVITY_CHANGED, - G_OBJECT_CLASS_TYPE (object_class), - G_SIGNAL_RUN_FIRST, - 0, NULL, NULL, - g_cclosure_marshal_VOID__VOID, - G_TYPE_NONE, 0); + nm_exported_object_class_add_interface (NM_EXPORTED_OBJECT_CLASS (klass), + NMDBUS_TYPE_DEVICE_SKELETON, + "Reapply", impl_device_reapply, + "GetAppliedConnection", impl_device_get_applied_connection, + "Disconnect", impl_device_disconnect, + "Delete", impl_device_delete, + NULL); + + nm_exported_object_class_add_interface (NM_EXPORTED_OBJECT_CLASS (klass), + NMDBUS_TYPE_DEVICE_STATISTICS_SKELETON, + NULL); } diff --git a/src/devices/nm-device.h b/src/devices/nm-device.h index 66720f01..ac73ee0c 100644 --- a/src/devices/nm-device.h +++ b/src/devices/nm-device.h @@ -24,8 +24,7 @@ #include <netinet/in.h> -#include "nm-setting-connection.h" -#include "nm-dbus-object.h" +#include "nm-exported-object.h" #include "nm-dbus-interface.h" #include "nm-connection.h" #include "nm-rfkill-manager.h" @@ -114,7 +113,8 @@ nm_device_state_reason_check (NMDeviceStateReason reason) #define NM_DEVICE_PARENT "parent" /* the "slaves" property is internal in the parent class, but exposed - * by the derived classes NMDeviceBond, NMDeviceBridge and NMDeviceTeam. */ + * by the derived classes NMDeviceBond, NMDeviceBridge and NMDeviceTeam. + * It is thus important that the property name matches. */ #define NM_DEVICE_SLAVES "slaves" /* partially internal */ #define NM_DEVICE_TYPE_DESC "type-desc" /* Internal only */ @@ -135,7 +135,6 @@ nm_device_state_reason_check (NMDeviceStateReason reason) #define NM_DEVICE_STATE_CHANGED "state-changed" #define NM_DEVICE_LINK_INITIALIZED "link-initialized" #define NM_DEVICE_AUTOCONNECT_ALLOWED "autoconnect-allowed" -#define NM_DEVICE_CONNECTIVITY_CHANGED "connectivity-changed" #define NM_DEVICE_STATISTICS_REFRESH_RATE_MS "refresh-rate-ms" #define NM_DEVICE_STATISTICS_TX_BYTES "tx-bytes" @@ -173,9 +172,10 @@ typedef enum { /*< skip >*/ struct _NMDevicePrivate; struct _NMDevice { - NMDBusObject parent; + NMExportedObject parent; + + /* private */ struct _NMDevicePrivate *_priv; - CList devices_lst; }; /* The flags have an relaxing meaning, that means, specifying more flags, can make @@ -190,9 +190,7 @@ typedef enum { /*< skip >*/ } NMDeviceCheckDevAvailableFlags; typedef struct { - NMDBusObjectClass parent; - - const char *default_type_description; + NMExportedObjectClass parent; const char *connection_type; const NMLinkType *link_types; @@ -314,7 +312,7 @@ typedef struct { gboolean (* complete_connection) (NMDevice *self, NMConnection *connection, const char *specific_object, - NMConnection *const*existing_connections, + const GSList *existing_connections, GError **error); NMActStageReturn (* act_stage1_prepare) (NMDevice *self, @@ -522,7 +520,7 @@ gboolean nm_device_can_auto_connect (NMDevice *self, gboolean nm_device_complete_connection (NMDevice *device, NMConnection *connection, const char *specific_object, - NMConnection *const*existing_connections, + const GSList *existing_connection, GError **error); gboolean nm_device_check_connection_compatible (NMDevice *device, NMConnection *connection); @@ -756,10 +754,12 @@ void nm_device_update_firewall_zone (NMDevice *self); void nm_device_update_metered (NMDevice *self); void nm_device_reactivate_ip4_config (NMDevice *device, NMSettingIPConfig *s_ip4_old, - NMSettingIPConfig *s_ip4_new); + NMSettingIPConfig *s_ip4_new, + gboolean force_restart); void nm_device_reactivate_ip6_config (NMDevice *device, NMSettingIPConfig *s_ip6_old, - NMSettingIPConfig *s_ip6_new); + NMSettingIPConfig *s_ip6_new, + gboolean force_restart); gboolean nm_device_update_hw_address (NMDevice *self); void nm_device_update_initial_hw_address (NMDevice *self); @@ -776,22 +776,12 @@ gboolean nm_device_hw_addr_get_cloned (NMDevice *self, gboolean *preserve, GError **error); -typedef struct _NMDeviceConnectivityHandle NMDeviceConnectivityHandle; - typedef void (*NMDeviceConnectivityCallback) (NMDevice *self, - NMDeviceConnectivityHandle *handle, NMConnectivityState state, - GError *error, gpointer user_data); - -void nm_device_check_connectivity_update_interval (NMDevice *self); - -NMDeviceConnectivityHandle *nm_device_check_connectivity (NMDevice *self, - NMDeviceConnectivityCallback callback, - gpointer user_data); - -void nm_device_check_connectivity_cancel (NMDeviceConnectivityHandle *handle); - +void nm_device_check_connectivity (NMDevice *self, + NMDeviceConnectivityCallback callback, + gpointer user_data); NMConnectivityState nm_device_get_connectivity_state (NMDevice *self); typedef struct _NMBtVTableNetworkServer NMBtVTableNetworkServer; diff --git a/src/devices/nm-lldp-listener.c b/src/devices/nm-lldp-listener.c index f637825b..2ed2a7d9 100644 --- a/src/devices/nm-lldp-listener.c +++ b/src/devices/nm-lldp-listener.c @@ -286,21 +286,19 @@ lldp_neighbor_id_hash (gconstpointer ptr) } static int -lldp_neighbor_id_cmp (const LldpNeighbor *x, const LldpNeighbor *y) +lldp_neighbor_id_cmp (gconstpointer a, gconstpointer b) { - NM_CMP_SELF (x, y); - NM_CMP_FIELD (x, y, chassis_id_type); - NM_CMP_FIELD (x, y, port_id_type); - NM_CMP_FIELD_STR0 (x, y, chassis_id); - NM_CMP_FIELD_STR0 (x, y, port_id); - return 0; -} - -static int -lldp_neighbor_id_cmp_p (gconstpointer a, gconstpointer b, gpointer user_data) -{ - return lldp_neighbor_id_cmp (*((const LldpNeighbor *const*) a), - *((const LldpNeighbor *const*) b)); + const LldpNeighbor *x = a, *y = b; + int c; + + if (x->chassis_id_type != y->chassis_id_type) + return x->chassis_id_type < y->chassis_id_type ? -1 : 1; + if (x->port_id_type != y->port_id_type) + return x->port_id_type < y->port_id_type ? -1 : 1; + c = g_strcmp0 (x->chassis_id, y->chassis_id); + if (c == 0) + c = g_strcmp0 (x->port_id, y->port_id); + return c < 0 ? -1 : (c > 0 ? 1 : 0); } static gboolean @@ -840,23 +838,20 @@ GVariant * nm_lldp_listener_get_neighbors (NMLldpListener *self) { NMLldpListenerPrivate *priv; + GVariantBuilder array_builder; + GList *neighbors, *iter; g_return_val_if_fail (NM_IS_LLDP_LISTENER (self), FALSE); priv = NM_LLDP_LISTENER_GET_PRIVATE (self); - if (G_UNLIKELY (!priv->variant)) { - GVariantBuilder array_builder; - gs_free LldpNeighbor **neighbors = NULL; - guint i, n; - + if (!priv->variant) { g_variant_builder_init (&array_builder, G_VARIANT_TYPE ("aa{sv}")); - neighbors = (LldpNeighbor **) nm_utils_hash_keys_to_array (priv->lldp_neighbors, - lldp_neighbor_id_cmp_p, - NULL, - &n); - for (i = 0; i < n; i++) - g_variant_builder_add_value (&array_builder, lldp_neighbor_to_variant (neighbors[i])); + neighbors = g_hash_table_get_keys (priv->lldp_neighbors); + neighbors = g_list_sort (neighbors, lldp_neighbor_id_cmp); + for (iter = neighbors; iter; iter = iter->next) + g_variant_builder_add_value (&array_builder, lldp_neighbor_to_variant (iter->data)); + g_list_free (neighbors); priv->variant = g_variant_ref_sink (g_variant_builder_end (&array_builder)); } return priv->variant; diff --git a/src/devices/ovs/meson.build b/src/devices/ovs/meson.build deleted file mode 100644 index 7b1c4617..00000000 --- a/src/devices/ovs/meson.build +++ /dev/null @@ -1,38 +0,0 @@ -sources = files( - 'nm-device-ovs-bridge.c', - 'nm-device-ovs-interface.c', - 'nm-device-ovs-port.c', - 'nm-ovsdb.c', - 'nm-ovs-factory.c' -) - -deps = [ - jansson_dep, - nm_dep -] - -libnm_device_plugin_ovs = shared_module( - 'nm-device-plugin-ovs', - sources: sources, - dependencies: deps, - c_args: '-DRUNSTATEDIR="@0@"'.format(nm_runstatedir), - link_args: ldflags_linker_script_devices, - link_depends: linker_script_devices, - install: true, - install_dir: nm_pkglibdir -) - -core_plugins += libnm_device_plugin_ovs - -run_target( - 'check-local-devices-ovs', - command: [check_exports, libnm_device_plugin_ovs.full_path(), linker_script_devices], - depends: libnm_device_plugin_ovs -) - -# FIXME: check_so_symbols replacement -''' -check-local-devices-ovs: src/devices/ovs/libnm-device-plugin-ovs.la - $(srcdir)/tools/check-exports.sh $(builddir)/src/devices/ovs/.libs/libnm-device-plugin-ovs.so "$(srcdir)/linker-script-devices.ver" - $(call check_so_symbols,$(builddir)/src/devices/ovs/.libs/libnm-device-plugin-ovs.so) -''' diff --git a/src/devices/ovs/nm-device-ovs-bridge.c b/src/devices/ovs/nm-device-ovs-bridge.c index 5244ca8b..53ea2b82 100644 --- a/src/devices/ovs/nm-device-ovs-bridge.c +++ b/src/devices/ovs/nm-device-ovs-bridge.c @@ -28,8 +28,10 @@ #include "nm-setting-connection.h" #include "nm-setting-ovs-bridge.h" +#include "introspection/org.freedesktop.NetworkManager.Device.OvsBridge.h" + #include "devices/nm-device-logging.h" -_LOG_DECLARE_SELF (NMDeviceOvsBridge); +_LOG_DECLARE_SELF(NMDeviceOvsBridge); /*****************************************************************************/ @@ -131,24 +133,11 @@ nm_device_ovs_bridge_init (NMDeviceOvsBridge *self) { } -static const NMDBusInterfaceInfoExtended interface_info_device_ovs_bridge = { - .parent = NM_DEFINE_GDBUS_INTERFACE_INFO_INIT ( - NM_DBUS_INTERFACE_DEVICE_OVS_BRIDGE, - .signals = NM_DEFINE_GDBUS_SIGNAL_INFOS ( - &nm_signal_info_property_changed_legacy, - ), - ), - .legacy_property_changed = TRUE, -}; - static void nm_device_ovs_bridge_class_init (NMDeviceOvsBridgeClass *klass) { - NMDBusObjectClass *dbus_object_class = NM_DBUS_OBJECT_CLASS (klass); NMDeviceClass *device_class = NM_DEVICE_CLASS (klass); - dbus_object_class->interface_infos = NM_DBUS_INTERFACE_INFOS (&interface_info_device_ovs_bridge); - device_class->connection_type = NM_SETTING_OVS_BRIDGE_SETTING_NAME; device_class->is_master = TRUE; device_class->get_type_description = get_type_description; @@ -160,4 +149,8 @@ nm_device_ovs_bridge_class_init (NMDeviceOvsBridgeClass *klass) device_class->act_stage3_ip6_config_start = act_stage3_ip6_config_start; device_class->enslave_slave = enslave_slave; device_class->release_slave = release_slave; + + nm_exported_object_class_add_interface (NM_EXPORTED_OBJECT_CLASS (klass), + NMDBUS_TYPE_DEVICE_OVS_BRIDGE_SKELETON, + NULL); } diff --git a/src/devices/ovs/nm-device-ovs-interface.c b/src/devices/ovs/nm-device-ovs-interface.c index eefe38c8..ce32c2dd 100644 --- a/src/devices/ovs/nm-device-ovs-interface.c +++ b/src/devices/ovs/nm-device-ovs-interface.c @@ -28,6 +28,8 @@ #include "nm-setting-ovs-interface.h" #include "nm-setting-ovs-port.h" +#include "introspection/org.freedesktop.NetworkManager.Device.OvsInterface.h" + #include "devices/nm-device-logging.h" _LOG_DECLARE_SELF(NMDeviceOvsInterface); @@ -183,26 +185,13 @@ nm_device_ovs_interface_init (NMDeviceOvsInterface *self) { } -static const NMDBusInterfaceInfoExtended interface_info_device_ovs_interface = { - .parent = NM_DEFINE_GDBUS_INTERFACE_INFO_INIT ( - NM_DBUS_INTERFACE_DEVICE_OVS_INTERFACE, - .signals = NM_DEFINE_GDBUS_SIGNAL_INFOS ( - &nm_signal_info_property_changed_legacy, - ), - ), - .legacy_property_changed = TRUE, -}; - static void nm_device_ovs_interface_class_init (NMDeviceOvsInterfaceClass *klass) { - NMDBusObjectClass *dbus_object_class = NM_DBUS_OBJECT_CLASS (klass); NMDeviceClass *device_class = NM_DEVICE_CLASS (klass); NM_DEVICE_CLASS_DECLARE_TYPES (klass, NULL, NM_LINK_TYPE_OPENVSWITCH); - dbus_object_class->interface_infos = NM_DBUS_INTERFACE_INFOS (&interface_info_device_ovs_interface); - device_class->connection_type = NM_SETTING_OVS_INTERFACE_SETTING_NAME; device_class->get_type_description = get_type_description; device_class->create_and_realize = create_and_realize; @@ -213,4 +202,8 @@ nm_device_ovs_interface_class_init (NMDeviceOvsInterfaceClass *klass) device_class->act_stage3_ip4_config_start = act_stage3_ip4_config_start; device_class->act_stage3_ip6_config_start = act_stage3_ip6_config_start; device_class->can_unmanaged_external_down = can_unmanaged_external_down; + + nm_exported_object_class_add_interface (NM_EXPORTED_OBJECT_CLASS (klass), + NMDBUS_TYPE_DEVICE_OVS_INTERFACE_SKELETON, + NULL); } diff --git a/src/devices/ovs/nm-device-ovs-port.c b/src/devices/ovs/nm-device-ovs-port.c index 3f1fe974..cb0915af 100644 --- a/src/devices/ovs/nm-device-ovs-port.c +++ b/src/devices/ovs/nm-device-ovs-port.c @@ -28,8 +28,10 @@ #include "nm-setting-ovs-port.h" #include "nm-setting-ovs-port.h" +#include "introspection/org.freedesktop.NetworkManager.Device.OvsPort.h" + #include "devices/nm-device-logging.h" -_LOG_DECLARE_SELF (NMDeviceOvsPort); +_LOG_DECLARE_SELF(NMDeviceOvsPort); /*****************************************************************************/ @@ -178,24 +180,11 @@ nm_device_ovs_port_init (NMDeviceOvsPort *self) { } -static const NMDBusInterfaceInfoExtended interface_info_device_ovs_port = { - .parent = NM_DEFINE_GDBUS_INTERFACE_INFO_INIT ( - NM_DBUS_INTERFACE_DEVICE_OVS_PORT, - .signals = NM_DEFINE_GDBUS_SIGNAL_INFOS ( - &nm_signal_info_property_changed_legacy, - ), - ), - .legacy_property_changed = TRUE, -}; - static void nm_device_ovs_port_class_init (NMDeviceOvsPortClass *klass) { - NMDBusObjectClass *dbus_object_class = NM_DBUS_OBJECT_CLASS (klass); NMDeviceClass *device_class = NM_DEVICE_CLASS (klass); - dbus_object_class->interface_infos = NM_DBUS_INTERFACE_INFOS (&interface_info_device_ovs_port); - device_class->connection_type = NM_SETTING_OVS_PORT_SETTING_NAME; device_class->is_master = TRUE; device_class->get_type_description = get_type_description; @@ -206,4 +195,8 @@ nm_device_ovs_port_class_init (NMDeviceOvsPortClass *klass) device_class->act_stage3_ip6_config_start = act_stage3_ip6_config_start; device_class->enslave_slave = enslave_slave; device_class->release_slave = release_slave; + + nm_exported_object_class_add_interface (NM_EXPORTED_OBJECT_CLASS (klass), + NMDBUS_TYPE_DEVICE_OVS_PORT_SKELETON, + NULL); } diff --git a/src/devices/ovs/nm-ovsdb.c b/src/devices/ovs/nm-ovsdb.c index b8f5a935..92fcfa01 100644 --- a/src/devices/ovs/nm-ovsdb.c +++ b/src/devices/ovs/nm-ovsdb.c @@ -22,20 +22,37 @@ #include "nm-ovsdb.h" #include <string.h> +#include <jansson.h> #include <gmodule.h> #include <gio/gunixsocketaddress.h> -#include "nm-utils/nm-jansson.h" #include "devices/nm-device.h" #include "platform/nm-platform.h" #include "nm-core-internal.h" -/*****************************************************************************/ +/* Added in Jansson v2.4 (released Sep 23 2012), but travis.ci has v2.2. */ +#ifndef json_boolean +#define json_boolean(val) ((val) ? json_true() : json_false()) +#endif + +/* Added in Jansson v2.5 (released Sep 19 2013), but travis.ci has v2.2. */ +#ifndef json_array_foreach +#define json_array_foreach(array, index, value) \ + for (index = 0; \ + index < json_array_size(array) && (value = json_array_get(array, index)); \ + index++) +#endif -#if JANSSON_VERSION_HEX < 0x020400 -#warning "requires at least libjansson 2.4" +/* Added in Jansson v2.3 (released Jan 27 2012) */ +#ifndef json_object_foreach +#define json_object_foreach(object, key, value) \ + for(key = json_object_iter_key(json_object_iter(object)); \ + key && (value = json_object_iter_value(json_object_key_to_iter(key))); \ + key = json_object_iter_key(json_object_iter_next(object, json_object_key_to_iter(key)))) #endif +/*****************************************************************************/ + typedef struct { char *name; char *connection_uuid; @@ -78,7 +95,7 @@ typedef struct { GHashTable *interfaces; /* interface uuid => OpenvswitchInterface */ GHashTable *ports; /* port uuid => OpenvswitchPort */ GHashTable *bridges; /* bridge uuid => OpenvswitchBridge */ - char *db_uuid; + const char *db_uuid; } NMOvsdbPrivate; struct _NMOvsdb { @@ -127,7 +144,7 @@ typedef struct { OvsdbMethodCallback callback; gpointer user_data; union { - char *ifname; + const char *ifname; struct { NMConnection *bridge; NMConnection *port; @@ -867,7 +884,7 @@ ovsdb_got_update (NMOvsdb *self, json_t *msg) if (ovs) { iter = json_object_iter (ovs); - priv->db_uuid = iter ? g_strdup (json_object_iter_key (iter)) : NULL; + priv->db_uuid = g_strdup (iter ? json_object_iter_key (iter) : NULL); } /* Interfaces */ diff --git a/src/devices/team/meson.build b/src/devices/team/meson.build deleted file mode 100644 index 4a533bc5..00000000 --- a/src/devices/team/meson.build +++ /dev/null @@ -1,35 +0,0 @@ -sources = files( - 'nm-device-team.c', - 'nm-team-factory.c' -) - -deps = [ - jansson_dep, - libteamdctl_dep, - nm_dep -] - -libnm_device_plugin_team = shared_module( - 'nm-device-plugin-team', - sources: sources, - dependencies: deps, - link_args: ldflags_linker_script_devices, - link_depends: linker_script_devices, - install: true, - install_dir: nm_pkglibdir -) - -core_plugins += libnm_device_plugin_team - -run_target( - 'check-local-devices-team', - command: [check_exports, libnm_device_plugin_team.full_path(), linker_script_devices], - depends: libnm_device_plugin_team -) - -# FIXME: check_so_symbols replacement -''' -check-local-devices-team: src/devices/team/libnm-device-plugin-team.la - $(srcdir)/tools/check-exports.sh $(builddir)/src/devices/team/.libs/libnm-device-plugin-team.so "$(srcdir)/linker-script-devices.ver" - $(call check_so_symbols,$(builddir)/src/devices/team/.libs/libnm-device-plugin-team.so) -''' diff --git a/src/devices/team/nm-device-team.c b/src/devices/team/nm-device-team.c index f83ba22b..098cd437 100644 --- a/src/devices/team/nm-device-team.c +++ b/src/devices/team/nm-device-team.c @@ -28,8 +28,8 @@ #include <sys/wait.h> #include <teamdctl.h> #include <stdlib.h> +#include <jansson.h> -#include "nm-utils/nm-jansson.h" #include "NetworkManagerUtils.h" #include "devices/nm-device-private.h" #include "platform/nm-platform.h" @@ -37,6 +37,8 @@ #include "nm-ip4-config.h" #include "nm-dbus-compat.h" +#include "introspection/org.freedesktop.NetworkManager.Device.Team.h" + #include "devices/nm-device-logging.h" _LOG_DECLARE_SELF(NMDeviceTeam); @@ -104,7 +106,7 @@ static gboolean complete_connection (NMDevice *device, NMConnection *connection, const char *specific_object, - NMConnection *const*existing_connections, + const GSList *existing_connections, GError **error) { NMSettingTeam *s_team; @@ -889,27 +891,10 @@ dispose (GObject *object) G_OBJECT_CLASS (nm_device_team_parent_class)->dispose (object); } -static const NMDBusInterfaceInfoExtended interface_info_device_team = { - .parent = NM_DEFINE_GDBUS_INTERFACE_INFO_INIT ( - NM_DBUS_INTERFACE_DEVICE_TEAM, - .signals = NM_DEFINE_GDBUS_SIGNAL_INFOS ( - &nm_signal_info_property_changed_legacy, - ), - .properties = NM_DEFINE_GDBUS_PROPERTY_INFOS ( - NM_DEFINE_DBUS_PROPERTY_INFO_EXTENDED_READABLE_L ("HwAddress", "s", NM_DEVICE_HW_ADDRESS), - NM_DEFINE_DBUS_PROPERTY_INFO_EXTENDED_READABLE_L ("Carrier", "b", NM_DEVICE_CARRIER), - NM_DEFINE_DBUS_PROPERTY_INFO_EXTENDED_READABLE_L ("Slaves", "ao", NM_DEVICE_SLAVES), - NM_DEFINE_DBUS_PROPERTY_INFO_EXTENDED_READABLE_L ("Config", "s", NM_DEVICE_TEAM_CONFIG), - ), - ), - .legacy_property_changed = TRUE, -}; - static void nm_device_team_class_init (NMDeviceTeamClass *klass) { GObjectClass *object_class = G_OBJECT_CLASS (klass); - NMDBusObjectClass *dbus_object_class = NM_DBUS_OBJECT_CLASS (klass); NMDeviceClass *parent_class = NM_DEVICE_CLASS (klass); NM_DEVICE_CLASS_DECLARE_TYPES (klass, NM_SETTING_TEAM_SETTING_NAME, NM_LINK_TYPE_TEAM) @@ -918,8 +903,6 @@ nm_device_team_class_init (NMDeviceTeamClass *klass) object_class->dispose = dispose; object_class->get_property = get_property; - dbus_object_class->interface_infos = NM_DBUS_INTERFACE_INFOS (&interface_info_device_team); - parent_class->is_master = TRUE; parent_class->create_and_realize = create_and_realize; parent_class->get_generic_capabilities = get_generic_capabilities; @@ -941,4 +924,8 @@ nm_device_team_class_init (NMDeviceTeamClass *klass) G_PARAM_STATIC_STRINGS); g_object_class_install_properties (object_class, _PROPERTY_ENUMS_LAST, obj_properties); + + nm_exported_object_class_add_interface (NM_EXPORTED_OBJECT_CLASS (klass), + NMDBUS_TYPE_DEVICE_TEAM_SKELETON, + NULL); } diff --git a/src/devices/tests/meson.build b/src/devices/tests/meson.build deleted file mode 100644 index 02c61ced..00000000 --- a/src/devices/tests/meson.build +++ /dev/null @@ -1,18 +0,0 @@ -test_units = [ - 'test-acd', - 'test-lldp' -] - -foreach test_unit: test_units - exe = executable( - test_unit, - test_unit + '.c', - dependencies: test_nm_dep - ) - - test( - 'devices/' + test_unit, - test_script, - args: test_args + [exe.full_path()] - ) -endforeach diff --git a/src/devices/tests/test-acd.c b/src/devices/tests/test-arping.c index 8a2852a2..f0537545 100644 --- a/src/devices/tests/test-acd.c +++ b/src/devices/tests/test-arping.c @@ -20,7 +20,7 @@ #include "nm-default.h" -#include "devices/nm-acd-manager.h" +#include "devices/nm-arping-manager.h" #include "platform/tests/test-common.h" #define IFACE_VETH0 "nm-test-veth0" @@ -34,10 +34,6 @@ typedef struct { int ifindex0; int ifindex1; - const guint8 *hwaddr0; - const guint8 *hwaddr1; - size_t hwaddr0_len; - size_t hwaddr1_len; } test_fixture; static void @@ -49,9 +45,6 @@ fixture_setup (test_fixture *fixture, gconstpointer user_data) g_assert (nm_platform_link_set_up (NM_PLATFORM_GET, fixture->ifindex0, NULL)); g_assert (nm_platform_link_set_up (NM_PLATFORM_GET, fixture->ifindex1, NULL)); - - fixture->hwaddr0 = nm_platform_link_get_address (NM_PLATFORM_GET, fixture->ifindex0, &fixture->hwaddr0_len); - fixture->hwaddr1 = nm_platform_link_get_address (NM_PLATFORM_GET, fixture->ifindex1, &fixture->hwaddr1_len); } typedef struct { @@ -61,21 +54,26 @@ typedef struct { } TestInfo; static void -acd_manager_probe_terminated (NMAcdManager *acd_manager, GMainLoop *loop) +arping_manager_probe_terminated (NMArpingManager *arping_manager, GMainLoop *loop) { g_main_loop_quit (loop); } static void -test_acd_common (test_fixture *fixture, TestInfo *info) +test_arping_common (test_fixture *fixture, TestInfo *info) { - gs_unref_object NMAcdManager *manager = NULL; + gs_unref_object NMArpingManager *manager = NULL; GMainLoop *loop; int i; const guint WAIT_TIME_OPTIMISTIC = 50; guint wait_time; gulong signal_id; + if (!nm_utils_find_helper ("arping", NULL, NULL)) { + g_test_skip ("arping binary is missing"); + return; + } + /* first, try with a short waittime. We hope that this is long enough * to successfully complete the test. Only if that's not the case, we * assume the computer is currently busy (high load) and we retry with @@ -83,11 +81,11 @@ test_acd_common (test_fixture *fixture, TestInfo *info) wait_time = WAIT_TIME_OPTIMISTIC; again: - manager = nm_acd_manager_new (fixture->ifindex0, fixture->hwaddr0, fixture->hwaddr0_len); + manager = nm_arping_manager_new (fixture->ifindex0); g_assert (manager != NULL); for (i = 0; info->addresses[i]; i++) - g_assert (nm_acd_manager_add_address (manager, info->addresses[i])); + g_assert (nm_arping_manager_add_address (manager, info->addresses[i])); for (i = 0; info->peer_addresses[i]; i++) { nmtstp_ip4_address_add (NULL, FALSE, fixture->ifindex1, info->peer_addresses[i], @@ -95,9 +93,9 @@ again: } loop = g_main_loop_new (NULL, FALSE); - signal_id = g_signal_connect (manager, NM_ACD_MANAGER_PROBE_TERMINATED, - G_CALLBACK (acd_manager_probe_terminated), loop); - g_assert (nm_acd_manager_start_probe (manager, wait_time)); + signal_id = g_signal_connect (manager, NM_ARPING_MANAGER_PROBE_TERMINATED, + G_CALLBACK (arping_manager_probe_terminated), loop); + g_assert (nm_arping_manager_start_probe (manager, wait_time, NULL)); g_assert (nmtst_main_loop_run (loop, 2000)); g_signal_handler_disconnect (manager, signal_id); g_main_loop_unref (loop); @@ -105,7 +103,7 @@ again: for (i = 0; info->addresses[i]; i++) { gboolean val; - val = nm_acd_manager_check_address (manager, info->addresses[i]); + val = nm_arping_manager_check_address (manager, info->addresses[i]); if (val == info->expected_result[i]) continue; @@ -124,41 +122,23 @@ again: } static void -test_acd_probe_1 (test_fixture *fixture, gconstpointer user_data) +test_arping_1 (test_fixture *fixture, gconstpointer user_data) { TestInfo info = { .addresses = { ADDR1, ADDR2, ADDR3 }, .peer_addresses = { ADDR4 }, .expected_result = { TRUE, TRUE, TRUE } }; - test_acd_common (fixture, &info); + test_arping_common (fixture, &info); } static void -test_acd_probe_2 (test_fixture *fixture, gconstpointer user_data) +test_arping_2 (test_fixture *fixture, gconstpointer user_data) { TestInfo info = { .addresses = { ADDR1, ADDR2, ADDR3, ADDR4 }, .peer_addresses = { ADDR3, ADDR2 }, .expected_result = { TRUE, FALSE, FALSE, TRUE } }; - test_acd_common (fixture, &info); -} - -static void -test_acd_announce (test_fixture *fixture, gconstpointer user_data) -{ - gs_unref_object NMAcdManager *manager = NULL; - GMainLoop *loop; - - manager = nm_acd_manager_new (fixture->ifindex0, fixture->hwaddr0, fixture->hwaddr0_len); - g_assert (manager != NULL); - - g_assert (nm_acd_manager_add_address (manager, ADDR1)); - g_assert (nm_acd_manager_add_address (manager, ADDR2)); - - loop = g_main_loop_new (NULL, FALSE); - nm_acd_manager_announce_addresses (manager); - g_assert (!nmtst_main_loop_run (loop, 200)); - g_main_loop_unref (loop); + test_arping_common (fixture, &info); } static void @@ -179,7 +159,6 @@ _nmtstp_init_tests (int *argc, char ***argv) void _nmtstp_setup_tests (void) { - g_test_add ("/acd/probe/1", test_fixture, NULL, fixture_setup, test_acd_probe_1, fixture_teardown); - g_test_add ("/acd/probe/2", test_fixture, NULL, fixture_setup, test_acd_probe_2, fixture_teardown); - g_test_add ("/acd/announce", test_fixture, NULL, fixture_setup, test_acd_announce, fixture_teardown); + g_test_add ("/arping/1", test_fixture, NULL, fixture_setup, test_arping_1, fixture_teardown); + g_test_add ("/arping/2", test_fixture, NULL, fixture_setup, test_arping_2, fixture_teardown); } diff --git a/src/devices/tests/test-lldp.c b/src/devices/tests/test-lldp.c index 5d0625f8..c3c4f0d2 100644 --- a/src/devices/tests/test-lldp.c +++ b/src/devices/tests/test-lldp.c @@ -347,7 +347,8 @@ static void _test_recv_fixture_setup (TestRecvFixture *fixture, gconstpointer user_data) { const NMPlatformLink *link; - nm_auto_close int fd = -1; + struct ifreq ifr = { }; + int fd, s; fd = open ("/dev/net/tun", O_RDWR | O_CLOEXEC); if (fd == -1) { @@ -356,45 +357,20 @@ _test_recv_fixture_setup (TestRecvFixture *fixture, gconstpointer user_data) return; } - if (nmtst_get_rand_bool ()) { - const NMPlatformLnkTun lnk = { - .type = IFF_TAP, - .pi = FALSE, - .vnet_hdr = FALSE, - .multi_queue = FALSE, - .persist = FALSE, - }; - - nm_close (nm_steal_fd (&fd)); - - link = nmtstp_link_tun_add (NM_PLATFORM_GET, - FALSE, - TEST_IFNAME, - &lnk, - &fd); - g_assert (link); - nmtstp_link_set_updown (NM_PLATFORM_GET, -1, link->ifindex, TRUE); - link = nmtstp_assert_wait_for_link (NM_PLATFORM_GET, TEST_IFNAME, NM_LINK_TYPE_TUN, 0); - } else { - int s; - struct ifreq ifr = { }; - - ifr.ifr_flags = IFF_TAP | IFF_NO_PI; - nm_utils_ifname_cpy (ifr.ifr_name, TEST_IFNAME); - g_assert (ioctl (fd, TUNSETIFF, &ifr) >= 0); - - /* Bring the interface up */ - s = socket (AF_INET, SOCK_DGRAM | SOCK_CLOEXEC, 0); - g_assert (s >= 0); - ifr.ifr_flags |= IFF_UP; - g_assert (ioctl (s, SIOCSIFFLAGS, &ifr) >= 0); - nm_close (s); - - link = nmtstp_assert_wait_for_link (NM_PLATFORM_GET, TEST_IFNAME, NM_LINK_TYPE_TUN, 100); - } + ifr.ifr_flags = IFF_TAP | IFF_NO_PI; + nm_utils_ifname_cpy (ifr.ifr_name, TEST_IFNAME); + g_assert (ioctl (fd, TUNSETIFF, &ifr) >= 0); + + /* Bring the interface up */ + s = socket (AF_INET, SOCK_DGRAM | SOCK_CLOEXEC, 0); + g_assert (s >= 0); + ifr.ifr_flags |= IFF_UP; + g_assert (ioctl (s, SIOCSIFFLAGS, &ifr) >= 0); + nm_close (s); + link = nmtstp_assert_wait_for_link (NM_PLATFORM_GET, TEST_IFNAME, NM_LINK_TYPE_TAP, 100); fixture->ifindex = link->ifindex; - fixture->fd = nm_steal_fd (&fd); + fixture->fd = fd; memcpy (fixture->mac, link->addr.data, ETH_ALEN); } diff --git a/src/devices/wifi/meson.build b/src/devices/wifi/meson.build deleted file mode 100644 index 27eaeea6..00000000 --- a/src/devices/wifi/meson.build +++ /dev/null @@ -1,51 +0,0 @@ -common_sources = files( - 'nm-wifi-ap.c', - 'nm-wifi-utils.c' -) - -sources = common_sources + files( - 'nm-wifi-factory.c', - 'nm-wifi-common.c', - 'nm-device-wifi.c', - 'nm-device-olpc-mesh.c' -) - -if enable_iwd - sources += files( - 'nm-device-iwd.c', - 'nm-iwd-manager.c', - ) -endif - -deps = [ - nm_dep -] - -libnm_device_plugin_wifi = shared_module( - 'nm-device-plugin-wifi', - sources: sources, - dependencies: deps, - link_args: ldflags_linker_script_devices, - link_depends: linker_script_devices, - install: true, - install_dir: nm_pkglibdir -) - -core_plugins += libnm_device_plugin_wifi - -run_target( - 'check-local-devices-wifi', - command: [check_exports, libnm_device_plugin_wifi.full_path(), linker_script_devices], - depends: libnm_device_plugin_wifi -) - -# FIXME: check_so_symbols replacement -''' -check-local-devices-wifi: src/devices/wifi/libnm-device-plugin-wifi.la - $(srcdir)/tools/check-exports.sh $(builddir)/src/devices/wifi/.libs/libnm-device-plugin-wifi.so "$(srcdir)/linker-script-devices.ver" - $(call check_so_symbols,$(builddir)/src/devices/wifi/.libs/libnm-device-plugin-wifi.so) -''' - -if enable_tests - subdir('tests') -endif diff --git a/src/devices/wifi/nm-device-iwd.c b/src/devices/wifi/nm-device-iwd.c deleted file mode 100644 index eeff5bd3..00000000 --- a/src/devices/wifi/nm-device-iwd.c +++ /dev/null @@ -1,1921 +0,0 @@ -/* -*- Mode: C; tab-width: 4; indent-tabs-mode: t; c-basic-offset: 4 -*- */ -/* NetworkManager -- Network link manager - * - * This program is free software; you can redistribute it and/or modify - * it under the terms of the GNU General Public License as published by - * the Free Software Foundation; either version 2 of the License, or - * (at your option) any later version. - * - * This program is distributed in the hope that it will be useful, - * but WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the - * GNU General Public License for more details. - * - * You should have received a copy of the GNU General Public License along - * with this program; if not, write to the Free Software Foundation, Inc., - * 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA. - * - * Copyright (C) 2017 Intel Corporation - */ - -#include "nm-default.h" - -#include "nm-device-iwd.h" - -#include <string.h> - -#include "nm-common-macros.h" -#include "devices/nm-device.h" -#include "devices/nm-device-private.h" -#include "nm-utils.h" -#include "nm-act-request.h" -#include "nm-setting-connection.h" -#include "nm-setting-wireless.h" -#include "nm-setting-wireless-security.h" -#include "nm-setting-8021x.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 "devices/nm-device-logging.h" -_LOG_DECLARE_SELF(NMDeviceIwd); - -/*****************************************************************************/ - -NM_GOBJECT_PROPERTIES_DEFINE (NMDeviceIwd, - PROP_MODE, - PROP_BITRATE, - PROP_ACCESS_POINTS, - PROP_ACTIVE_ACCESS_POINT, - PROP_CAPABILITIES, - PROP_SCANNING, -); - -enum { - SCANNING_PROHIBITED, - - LAST_SIGNAL -}; - -static guint signals[LAST_SIGNAL] = { 0 }; - -typedef struct { - GDBusObject * dbus_obj; - GDBusProxy * dbus_proxy; - CList aps_lst_head; - NMWifiAP * current_ap; - GCancellable * cancellable; - NMDeviceWifiCapabilities capabilities; - NMActRequestGetSecretsCallId *wifi_secrets_id; - GDBusMethodInvocation *secrets_request; - guint periodic_scan_id; - bool enabled:1; - bool can_scan:1; - bool can_connect:1; - bool scanning:1; - bool scan_requested:1; -} NMDeviceIwdPrivate; - -struct _NMDeviceIwd { - NMDevice parent; - NMDeviceIwdPrivate _priv; -}; - -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) - -/*****************************************************************************/ - -static void schedule_periodic_scan (NMDeviceIwd *self, - NMDeviceState current_state); - -/*****************************************************************************/ - -static void -_ap_dump (NMDeviceIwd *self, - NMLogLevel log_level, - const NMWifiAP *ap, - const char *prefix, - gint32 now_s) -{ - 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)); -} - -/* Callers ensure we're not removing current_ap */ -static void -ap_add_remove (NMDeviceIwd *self, - gboolean is_adding, /* or else is removing */ - NMWifiAP *ap, - gboolean recheck_available_connections) -{ - NMDeviceIwdPrivate *priv = NM_DEVICE_IWD_GET_PRIVATE (self); - - if (is_adding) { - g_object_ref (ap); - ap->wifi_device = NM_DEVICE (self); - c_list_link_tail (&priv->aps_lst_head, &ap->aps_lst); - nm_dbus_object_export (NM_DBUS_OBJECT (ap)); - _ap_dump (self, LOGL_DEBUG, ap, "added", 0); - 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); - } - - _notify (self, PROP_ACCESS_POINTS); - - if (!is_adding) { - nm_device_wifi_emit_signal_access_point (NM_DEVICE (self), ap, FALSE); - nm_dbus_object_clear_and_unexport (&ap); - } - - nm_device_emit_recheck_auto_activate (NM_DEVICE (self)); - if (recheck_available_connections) - nm_device_recheck_available_connections (NM_DEVICE (self)); -} - -static void -set_current_ap (NMDeviceIwd *self, NMWifiAP *new_ap, gboolean recheck_available_connections) -{ - NMDeviceIwdPrivate *priv; - NMWifiAP *old_ap; - - g_return_if_fail (NM_IS_DEVICE_IWD (self)); - - priv = NM_DEVICE_IWD_GET_PRIVATE (self); - old_ap = priv->current_ap; - - if (old_ap == new_ap) - return; - - if (new_ap) - priv->current_ap = g_object_ref (new_ap); - else - priv->current_ap = NULL; - - if (old_ap) { - if (nm_wifi_ap_get_fake (old_ap)) - ap_add_remove (self, FALSE, old_ap, recheck_available_connections); - g_object_unref (old_ap); - } - - _notify (self, PROP_ACTIVE_ACCESS_POINT); - _notify (self, PROP_MODE); -} - -static void -remove_all_aps (NMDeviceIwd *self) -{ - NMDeviceIwdPrivate *priv = NM_DEVICE_IWD_GET_PRIVATE (self); - NMWifiAP *ap, *ap_safe; - - if (c_list_is_empty (&priv->aps_lst_head)) - return; - - set_current_ap (self, NULL, FALSE); - - c_list_for_each_entry_safe (ap, ap_safe, &priv->aps_lst_head, aps_lst) - ap_add_remove (self, FALSE, ap, FALSE); - - nm_device_emit_recheck_auto_activate (NM_DEVICE (self)); - nm_device_recheck_available_connections (NM_DEVICE (self)); -} - -static GVariant * -vardict_from_network_type (const gchar *type) -{ - GVariantBuilder builder; - const gchar *key_mgmt = ""; - const gchar *pairwise = "ccmp"; - - if (!strcmp (type, "psk")) - key_mgmt = "wpa-psk"; - else if (!strcmp (type, "8021x")) - key_mgmt = "wpa-eap"; - else - return NULL; - - 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); -} - -static void -get_ordered_networks_cb (GObject *source, GAsyncResult *res, gpointer user_data) -{ - NMDeviceIwd *self = user_data; - NMDeviceIwdPrivate *priv = NM_DEVICE_IWD_GET_PRIVATE (self); - gs_free_error GError *error = NULL; - gs_unref_variant GVariant *variant = NULL; - GVariantIter *networks; - const gchar *path, *name, *type; - int16_t signal; - NMWifiAP *ap, *ap_safe; - gboolean changed = FALSE; - GHashTableIter ap_iter; - gs_unref_hashtable GHashTable *new_aps = NULL; - - variant = _nm_dbus_proxy_call_finish (G_DBUS_PROXY (source), res, - G_VARIANT_TYPE ("(a(osns))"), - &error); - if (!variant) { - _LOGE (LOGD_WIFI, "Device.GetOrderedNetworks failed: %s", - error->message); - return; - } - - new_aps = g_hash_table_new_full (nm_str_hash, g_str_equal, NULL, g_object_unref); - - g_variant_get (variant, "(a(osns))", &networks); - - while (g_variant_iter_next (networks, "(&o&sn&s)", &path, &name, &signal, &type)) { - GVariantBuilder builder; - gs_unref_variant GVariant *props = NULL; - GVariant *rsn; - static uint32_t ap_id = 0; - uint8_t bssid[6]; - - /* - * What we get from IWD are networks, or ESSs, that may - * contain multiple APs, or BSSs, each. We don't get - * information about any specific BSSs within an ESS but - * we can safely present each ESS as an individual BSS to - * NM, which will be seen as ESSs comprising a single BSS - * each. NM won't be able to handle roaming but IWD already - * does that. We fake the BSSIDs as they don't play any - * role either. - */ - bssid[0] = 0x00; - bssid[1] = 0x01; - bssid[2] = 0x02; - bssid[3] = ap_id >> 16; - bssid[4] = ap_id >> 8; - bssid[5] = ap_id++; - - /* WEP not supported */ - if (!strcmp (type, "wep")) - continue; - - 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); - - props = g_variant_new ("a{sv}", &builder); - - ap = nm_wifi_ap_new_from_properties (path, props); - if (name[0] != '\0') - nm_wifi_ap_set_ssid (ap, (const guint8 *) name, strlen (name)); - 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 (new_aps, - (gpointer) nm_wifi_ap_get_supplicant_path (ap), - ap); - } - - g_variant_iter_free (networks); - - c_list_for_each_entry_safe (ap, ap_safe, &priv->aps_lst_head, aps_lst) { - - ap = g_hash_table_lookup (new_aps, - nm_wifi_ap_get_supplicant_path (ap)); - if (ap) { - if (nm_wifi_ap_set_strength (ap, nm_wifi_ap_get_strength (ap))) { - _ap_dump (self, LOGL_TRACE, ap, "updated", 0); - changed = TRUE; - } - g_hash_table_remove (new_aps, - nm_wifi_ap_get_supplicant_path (ap)); - continue; - } - - if (ap == priv->current_ap) { - /* Normally IWD will prevent the current AP from being - * removed from the list and set a low signal strength, - * but just making sure. - */ - continue; - } - - ap_add_remove (self, FALSE, ap, FALSE); - changed = TRUE; - } - - g_hash_table_iter_init (&ap_iter, new_aps); - while (g_hash_table_iter_next (&ap_iter, NULL, (gpointer) &ap)) { - ap_add_remove (self, TRUE, ap, FALSE); - g_hash_table_iter_remove (&ap_iter); - changed = TRUE; - } - - if (changed) { - nm_device_emit_recheck_auto_activate (NM_DEVICE (self)); - nm_device_recheck_available_connections (NM_DEVICE (self)); - } -} - -static void -update_aps (NMDeviceIwd *self) -{ - NMDeviceIwdPrivate *priv = NM_DEVICE_IWD_GET_PRIVATE (self); - - if (!priv->cancellable) - priv->cancellable = g_cancellable_new (); - - g_dbus_proxy_call (priv->dbus_proxy, "GetOrderedNetworks", - g_variant_new ("()"), G_DBUS_CALL_FLAGS_NONE, - 2000, priv->cancellable, - get_ordered_networks_cb, self); -} - -static void -send_disconnect (NMDeviceIwd *self) -{ - NMDeviceIwdPrivate *priv = NM_DEVICE_IWD_GET_PRIVATE (self); - - g_dbus_proxy_call (priv->dbus_proxy, "Disconnect", g_variant_new ("()"), - G_DBUS_CALL_FLAGS_NONE, -1, NULL, NULL, NULL); -} - -static void -wifi_secrets_cancel (NMDeviceIwd *self) -{ - NMDeviceIwdPrivate *priv = NM_DEVICE_IWD_GET_PRIVATE (self); - - if (priv->wifi_secrets_id) - nm_act_request_cancel_secrets (NULL, priv->wifi_secrets_id); - nm_assert (!priv->wifi_secrets_id); - - if (priv->secrets_request) { - g_dbus_method_invocation_return_error_literal (priv->secrets_request, NM_DEVICE_ERROR, - NM_DEVICE_ERROR_INVALID_CONNECTION, - "NM secrets request cancelled"); - priv->secrets_request = NULL; - } - -} - -static void -cleanup_association_attempt (NMDeviceIwd *self, gboolean disconnect) -{ - NMDeviceIwdPrivate *priv = NM_DEVICE_IWD_GET_PRIVATE (self); - - wifi_secrets_cancel (self); - - set_current_ap (self, NULL, TRUE); - - if (disconnect && priv->dbus_obj) - send_disconnect (self); -} - -static void -deactivate (NMDevice *device) -{ - cleanup_association_attempt (NM_DEVICE_IWD (device), TRUE); -} - -static gboolean -deactivate_async_finish (NMDevice *device, GAsyncResult *res, GError **error) -{ - NMDeviceIwdPrivate *priv = NM_DEVICE_IWD_GET_PRIVATE (NM_DEVICE_IWD (device)); - gs_unref_variant GVariant *variant = NULL; - - variant = g_dbus_proxy_call_finish (priv->dbus_proxy, res, error); - return variant != NULL; -} - -typedef struct { - NMDeviceIwd *self; - GAsyncReadyCallback callback; - gpointer user_data; -} DeactivateContext; - -static void -disconnect_cb (GObject *source, GAsyncResult *res, gpointer user_data) -{ - DeactivateContext *ctx = user_data; - - ctx->callback (G_OBJECT (ctx->self), res, ctx->user_data); - - g_object_unref (ctx->self); - g_slice_free (DeactivateContext, ctx); -} - -static void -deactivate_async (NMDevice *device, - GCancellable *cancellable, - GAsyncReadyCallback callback, - gpointer user_data) -{ - NMDeviceIwd *self = NM_DEVICE_IWD (device); - NMDeviceIwdPrivate *priv = NM_DEVICE_IWD_GET_PRIVATE (self); - DeactivateContext *ctx; - - ctx = g_slice_new0 (DeactivateContext); - ctx->self = g_object_ref (self); - ctx->callback = callback; - ctx->user_data = user_data; - - g_dbus_proxy_call (priv->dbus_proxy, "Disconnect", g_variant_new ("()"), - G_DBUS_CALL_FLAGS_NONE, -1, cancellable, disconnect_cb, ctx); -} - -static NMIwdNetworkSecurity -get_connection_iwd_security (NMConnection *connection) -{ - NMSettingWirelessSecurity *s_wireless_sec; - const char *key_mgmt = NULL; - - s_wireless_sec = nm_connection_get_setting_wireless_security (connection); - if (!s_wireless_sec) - return NM_IWD_NETWORK_SECURITY_NONE; - - key_mgmt = nm_setting_wireless_security_get_key_mgmt (s_wireless_sec); - nm_assert (key_mgmt); - - if (!strcmp (key_mgmt, "none") || !strcmp (key_mgmt, "ieee8021x")) - return NM_IWD_NETWORK_SECURITY_WEP; - - if (!strcmp (key_mgmt, "wpa-psk")) - return NM_IWD_NETWORK_SECURITY_PSK; - - nm_assert (!strcmp (key_mgmt, "wpa-eap")); - return NM_IWD_NETWORK_SECURITY_8021X; -} - -static gboolean -is_connection_known_network (NMConnection *connection) -{ - NMSettingWireless *s_wireless; - GBytes *ssid; - gs_free gchar *str_ssid = NULL; - - s_wireless = nm_connection_get_setting_wireless (connection); - if (!s_wireless) - return FALSE; - - ssid = nm_setting_wireless_get_ssid (s_wireless); - if (!ssid) - return FALSE; - - str_ssid = nm_utils_ssid_to_utf8 (g_bytes_get_data (ssid, NULL), - g_bytes_get_size (ssid)); - - return nm_iwd_manager_is_known_network (nm_iwd_manager_get (), - str_ssid, - get_connection_iwd_security (connection)); -} - -static gboolean -check_connection_compatible (NMDevice *device, NMConnection *connection) -{ - NMSettingConnection *s_con; - NMSettingWireless *s_wireless; - const char *mac; - const char * const *mac_blacklist; - int i; - const char *mode; - const char *perm_hw_addr; - - if (!NM_DEVICE_CLASS (nm_device_iwd_parent_class)->check_connection_compatible (device, connection)) - return FALSE; - - s_con = nm_connection_get_setting_connection (connection); - g_assert (s_con); - - if (strcmp (nm_setting_connection_get_connection_type (s_con), NM_SETTING_WIRELESS_SETTING_NAME)) - return FALSE; - - s_wireless = nm_connection_get_setting_wireless (connection); - if (!s_wireless) - return FALSE; - - perm_hw_addr = nm_device_get_permanent_hw_address (device); - mac = nm_setting_wireless_get_mac_address (s_wireless); - if (perm_hw_addr) { - if (mac && !nm_utils_hwaddr_matches (mac, -1, perm_hw_addr, -1)) - return FALSE; - - /* Check for MAC address blacklist */ - mac_blacklist = nm_setting_wireless_get_mac_address_blacklist (s_wireless); - for (i = 0; mac_blacklist[i]; i++) { - if (!nm_utils_hwaddr_valid (mac_blacklist[i], ETH_ALEN)) { - g_warn_if_reached (); - return FALSE; - } - - if (nm_utils_hwaddr_matches (mac_blacklist[i], -1, perm_hw_addr, -1)) - return FALSE; - } - } else if (mac) - return FALSE; - - mode = nm_setting_wireless_get_mode (s_wireless); - if (g_strcmp0 (mode, NM_SETTING_WIRELESS_MODE_INFRA) != 0) - return FALSE; - - /* 8021x networks can only be used if they've been provisioned on the IWD side and - * thus are Known Networks. - */ - if (get_connection_iwd_security (connection) == NM_IWD_NETWORK_SECURITY_8021X) { - if (!is_connection_known_network (connection)) - return FALSE; - } - - return TRUE; -} - -static gboolean -check_connection_available (NMDevice *device, - NMConnection *connection, - NMDeviceCheckConAvailableFlags flags, - const char *specific_object) -{ - NMDeviceIwd *self = NM_DEVICE_IWD (device); - NMDeviceIwdPrivate *priv = NM_DEVICE_IWD_GET_PRIVATE (self); - NMSettingWireless *s_wifi; - const char *mode; - - s_wifi = nm_connection_get_setting_wireless (connection); - g_return_val_if_fail (s_wifi, FALSE); - - /* Only Infrastrusture mode at this time */ - mode = nm_setting_wireless_get_mode (s_wifi); - if (g_strcmp0 (mode, NM_SETTING_WIRELESS_MODE_INFRA) != 0) - return FALSE; - - /* Hidden SSIDs not supported yet */ - if (nm_setting_wireless_get_hidden (s_wifi)) - return FALSE; - - /* 8021x networks can only be used if they've been provisioned on the IWD side and - * thus are Known Networks. - */ - if (get_connection_iwd_security (connection) == NM_IWD_NETWORK_SECURITY_8021X) { - if (!is_connection_known_network (connection)) - return FALSE; - } - - /* a connection that is available for a certain @specific_object, MUST - * also be available in general (without @specific_object). */ - - if (specific_object) { - NMWifiAP *ap; - - ap = nm_wifi_ap_lookup_for_device (NM_DEVICE (self), specific_object); - return ap ? nm_wifi_ap_check_compatible (ap, connection) : FALSE; - } - - if (NM_FLAGS_HAS (flags, _NM_DEVICE_CHECK_CON_AVAILABLE_FOR_USER_REQUEST_IGNORE_AP)) - return TRUE; - - /* Check at least one AP is compatible with this connection */ - return !!nm_wifi_aps_find_first_compatible (&priv->aps_lst_head, connection); -} - -static gboolean -complete_connection (NMDevice *device, - NMConnection *connection, - const char *specific_object, - NMConnection *const*existing_connections, - GError **error) -{ - NMDeviceIwd *self = NM_DEVICE_IWD (device); - NMDeviceIwdPrivate *priv = NM_DEVICE_IWD_GET_PRIVATE (self); - NMSettingWireless *s_wifi; - const char *setting_mac; - char *str_ssid = NULL; - NMWifiAP *ap; - const GByteArray *ssid = NULL; - GByteArray *tmp_ssid = NULL; - GBytes *setting_ssid = NULL; - const char *perm_hw_addr; - const char *mode; - - s_wifi = nm_connection_get_setting_wireless (connection); - - mode = s_wifi ? nm_setting_wireless_get_mode (s_wifi) : NULL; - - if (s_wifi && !nm_streq0 (mode, NM_SETTING_WIRELESS_MODE_INFRA)) { - g_set_error_literal (error, - NM_DEVICE_ERROR, - NM_DEVICE_ERROR_INVALID_CONNECTION, - "Only Infrastructure mode is supported."); - return FALSE; - } - - if (!specific_object) { - /* If not given a specific object, we need at minimum an SSID */ - if (!s_wifi) { - g_set_error_literal (error, - NM_DEVICE_ERROR, - NM_DEVICE_ERROR_INVALID_CONNECTION, - "A 'wireless' setting is required if no AP path was given."); - return FALSE; - } - - setting_ssid = nm_setting_wireless_get_ssid (s_wifi); - if (!setting_ssid || g_bytes_get_size (setting_ssid) == 0) { - g_set_error_literal (error, - NM_DEVICE_ERROR, - NM_DEVICE_ERROR_INVALID_CONNECTION, - "A 'wireless' setting with a valid SSID is required if no AP path was given."); - return FALSE; - } - - /* Find a compatible AP in the scan list */ - ap = nm_wifi_aps_find_first_compatible (&priv->aps_lst_head, connection); - if (!ap) { - g_set_error_literal (error, - NM_DEVICE_ERROR, - NM_DEVICE_ERROR_INVALID_CONNECTION, - "No compatible AP in the scan list and hidden SSIDs not supported."); - return FALSE; - } - } else { - ap = nm_wifi_ap_lookup_for_device (NM_DEVICE (self), specific_object); - if (!ap) { - g_set_error (error, - NM_DEVICE_ERROR, - NM_DEVICE_ERROR_SPECIFIC_OBJECT_NOT_FOUND, - "The access point %s was not in the scan list.", - specific_object); - return FALSE; - } - } - - /* Add a wifi setting if one doesn't exist yet */ - if (!s_wifi) { - s_wifi = (NMSettingWireless *) nm_setting_wireless_new (); - nm_connection_add_setting (connection, NM_SETTING (s_wifi)); - } - - ssid = nm_wifi_ap_get_ssid (ap); - - if (ssid == NULL) { - g_set_error_literal (error, - NM_DEVICE_ERROR, - NM_DEVICE_ERROR_INVALID_CONNECTION, - "A 'wireless' setting with a valid SSID is required."); - return FALSE; - } - - if (!nm_wifi_ap_complete_connection (ap, - connection, - nm_wifi_utils_is_manf_default_ssid (ssid), - error)) { - if (tmp_ssid) - g_byte_array_unref (tmp_ssid); - return FALSE; - } - - str_ssid = nm_utils_ssid_to_utf8 (ssid->data, ssid->len); - - nm_utils_complete_generic (nm_device_get_platform (device), - connection, - NM_SETTING_WIRELESS_SETTING_NAME, - existing_connections, - str_ssid, - str_ssid, - NULL, - TRUE); - g_free (str_ssid); - if (tmp_ssid) - g_byte_array_unref (tmp_ssid); - - /* 8021x networks can only be used if they've been provisioned on the IWD side and - * thus are Known Networks. - */ - if (get_connection_iwd_security (connection) == NM_IWD_NETWORK_SECURITY_8021X) { - if (!is_connection_known_network (connection)) { - g_set_error_literal (error, - NM_CONNECTION_ERROR, - NM_DEVICE_ERROR_INVALID_CONNECTION, - "This 8021x network has not been provisioned on this machine"); - return FALSE; - } - } - - perm_hw_addr = nm_device_get_permanent_hw_address (device); - if (perm_hw_addr) { - setting_mac = nm_setting_wireless_get_mac_address (s_wifi); - if (setting_mac) { - /* Make sure the setting MAC (if any) matches the device's permanent MAC */ - if (!nm_utils_hwaddr_matches (setting_mac, -1, perm_hw_addr, -1)) { - g_set_error_literal (error, - NM_CONNECTION_ERROR, - NM_CONNECTION_ERROR_INVALID_PROPERTY, - "connection does not match device"); - g_prefix_error (error, "%s.%s: ", NM_SETTING_WIRELESS_SETTING_NAME, NM_SETTING_WIRELESS_MAC_ADDRESS); - return FALSE; - } - } else { - guint8 tmp[ETH_ALEN]; - - /* Lock the connection to this device by default if it uses a - * permanent MAC address (ie not a 'locally administered' one) - */ - nm_utils_hwaddr_aton (perm_hw_addr, tmp, ETH_ALEN); - if (!(tmp[0] & 0x02)) { - g_object_set (G_OBJECT (s_wifi), - NM_SETTING_WIRELESS_MAC_ADDRESS, perm_hw_addr, - NULL); - } - } - } - - return TRUE; -} - -static gboolean -is_available (NMDevice *device, NMDeviceCheckDevAvailableFlags flags) -{ - NMDeviceIwd *self = NM_DEVICE_IWD (device); - NMDeviceIwdPrivate *priv = NM_DEVICE_IWD_GET_PRIVATE (self); - gs_unref_variant GVariant *value = NULL; - - if (!priv->enabled || !priv->dbus_obj) - return FALSE; - - value = g_dbus_proxy_get_cached_property (priv->dbus_proxy, "Powered"); - return g_variant_get_boolean (value); -} - -static gboolean -get_autoconnect_allowed (NMDevice *device) -{ - NMDeviceIwdPrivate *priv = NM_DEVICE_IWD_GET_PRIVATE (NM_DEVICE_IWD (device)); - - return is_available (device, NM_DEVICE_CHECK_DEV_AVAILABLE_NONE) - && priv->can_connect; -} - -static gboolean -can_auto_connect (NMDevice *device, - NMConnection *connection, - char **specific_object) -{ - NMDeviceIwd *self = NM_DEVICE_IWD (device); - NMDeviceIwdPrivate *priv = NM_DEVICE_IWD_GET_PRIVATE (self); - NMSettingWireless *s_wifi; - NMWifiAP *ap; - const char *mode; - guint64 timestamp = 0; - - nm_assert (!specific_object || !*specific_object); - - if (!NM_DEVICE_CLASS (nm_device_iwd_parent_class)->can_auto_connect (device, connection, NULL)) - return FALSE; - - s_wifi = nm_connection_get_setting_wireless (connection); - g_return_val_if_fail (s_wifi, FALSE); - - /* Only Infrastrusture mode */ - mode = nm_setting_wireless_get_mode (s_wifi); - if (g_strcmp0 (mode, NM_SETTING_WIRELESS_MODE_INFRA) != 0) - return FALSE; - - /* Don't autoconnect to networks that have been tried at least once - * but haven't been successful, since these are often accidental choices - * from the menu and the user may not know the password. - */ - if (nm_settings_connection_get_timestamp (NM_SETTINGS_CONNECTION (connection), ×tamp)) { - if (timestamp == 0) - return FALSE; - } - - /* 8021x networks can only be used if they've been provisioned on the IWD side and - * thus are Known Networks. - */ - if (get_connection_iwd_security (connection) == NM_IWD_NETWORK_SECURITY_8021X) { - if (!is_connection_known_network (connection)) - return FALSE; - } - - ap = nm_wifi_aps_find_first_compatible (&priv->aps_lst_head, connection); - if (ap) { - /* All good; connection is usable */ - NM_SET_OUT (specific_object, g_strdup (nm_dbus_object_get_path (NM_DBUS_OBJECT (ap)))); - return TRUE; - } - - return FALSE; -} - -const CList * -_nm_device_iwd_get_aps (NMDeviceIwd *self) -{ - return &NM_DEVICE_IWD_GET_PRIVATE (self)->aps_lst_head; -} - -static 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) -{ - NMDeviceIwd *self = user_data; - NMDeviceIwdPrivate *priv; - gs_free_error GError *error = NULL; - - if ( !_nm_dbus_proxy_call_finish (G_DBUS_PROXY (source), res, - G_VARIANT_TYPE ("()"), &error) - && g_error_matches (error, G_IO_ERROR, G_IO_ERROR_CANCELLED)) - return; - - priv = NM_DEVICE_IWD_GET_PRIVATE (self); - priv->scan_requested = FALSE; - - /* On success, priv->scanning becomes true right before or right - * after this callback, so the next automatic scan will be - * scheduled when priv->scanning goes back to false. On error, - * schedule a retry now. - */ - if (error && !priv->scanning) { - NMDeviceState state = nm_device_get_state (NM_DEVICE (self)); - - schedule_periodic_scan (self, state); - } -} - -static void -dbus_request_scan_cb (NMDevice *device, - GDBusMethodInvocation *context, - NMAuthSubject *subject, - GError *error, - gpointer user_data) -{ - NMDeviceIwd *self = NM_DEVICE_IWD (device); - NMDeviceIwdPrivate *priv; - gs_unref_variant GVariant *scan_options = user_data; - - if (error) { - g_dbus_method_invocation_return_gerror (context, error); - return; - } - - if (check_scanning_prohibited (self, FALSE)) { - g_dbus_method_invocation_return_error_literal (context, - NM_DEVICE_ERROR, - NM_DEVICE_ERROR_NOT_ALLOWED, - "Scanning not allowed at this time"); - return; - } - - priv = NM_DEVICE_IWD_GET_PRIVATE (self); - - if ( !priv->enabled - || !priv->dbus_obj - || nm_device_get_state (device) < NM_DEVICE_STATE_DISCONNECTED - || nm_device_is_activating (device)) { - g_dbus_method_invocation_return_error_literal (context, - NM_DEVICE_ERROR, - NM_DEVICE_ERROR_NOT_ALLOWED, - "Scanning not allowed while unavailable"); - return; - } - - if (scan_options) { - gs_unref_variant GVariant *val = g_variant_lookup_value (scan_options, "ssids", NULL); - - if (val) { - g_dbus_method_invocation_return_error_literal (context, - NM_DEVICE_ERROR, - NM_DEVICE_ERROR_NOT_ALLOWED, - "'ssid' scan option not supported"); - return; - } - } - - if (!priv->scanning && !priv->scan_requested) { - g_dbus_proxy_call (priv->dbus_proxy, "Scan", - g_variant_new ("()"), - G_DBUS_CALL_FLAGS_NONE, -1, - priv->cancellable, scan_cb, self); - priv->scan_requested = TRUE; - } - - g_dbus_method_invocation_return_value (context, NULL); -} - -void -_nm_device_iwd_request_scan (NMDeviceIwd *self, - GVariant *options, - GDBusMethodInvocation *invocation) -{ - NMDeviceIwdPrivate *priv = NM_DEVICE_IWD_GET_PRIVATE (self); - NMDevice *device = NM_DEVICE (self); - - if ( !priv->enabled - || !priv->dbus_obj - || nm_device_get_state (device) < NM_DEVICE_STATE_DISCONNECTED - || nm_device_is_activating (device)) { - g_dbus_method_invocation_return_error_literal (invocation, - NM_DEVICE_ERROR, - NM_DEVICE_ERROR_NOT_ALLOWED, - "Scanning not allowed while unavailable"); - return; - } - - g_signal_emit_by_name (device, - NM_DEVICE_AUTH_REQUEST, - invocation, - NULL, - NM_AUTH_PERMISSION_NETWORK_CONTROL, - TRUE, - dbus_request_scan_cb, - options ? g_variant_ref (options) : NULL); -} - -static gboolean -scanning_prohibited (NMDeviceIwd *self, gboolean periodic) -{ - NMDeviceIwdPrivate *priv = NM_DEVICE_IWD_GET_PRIVATE (self); - - g_return_val_if_fail (priv->dbus_obj != NULL, TRUE); - - switch (nm_device_get_state (NM_DEVICE (self))) { - case NM_DEVICE_STATE_UNKNOWN: - case NM_DEVICE_STATE_UNMANAGED: - case NM_DEVICE_STATE_UNAVAILABLE: - case NM_DEVICE_STATE_PREPARE: - case NM_DEVICE_STATE_CONFIG: - case NM_DEVICE_STATE_NEED_AUTH: - case NM_DEVICE_STATE_IP_CONFIG: - case NM_DEVICE_STATE_IP_CHECK: - case NM_DEVICE_STATE_SECONDARIES: - case NM_DEVICE_STATE_DEACTIVATING: - /* Prohibit scans when unusable or activating */ - return TRUE; - case NM_DEVICE_STATE_DISCONNECTED: - case NM_DEVICE_STATE_FAILED: - /* Can always scan when disconnected */ - return FALSE; - case NM_DEVICE_STATE_ACTIVATED: - break; - } - - /* Prohibit scans if IWD is busy */ - return !priv->can_scan; -} - -static void -wifi_secrets_cb (NMActRequest *req, - NMActRequestGetSecretsCallId *call_id, - NMSettingsConnection *s_connection, - GError *error, - gpointer user_data) -{ - NMDevice *device = user_data; - NMDeviceIwd *self = user_data; - NMDeviceIwdPrivate *priv; - NMSettingWirelessSecurity *s_wireless_sec; - const gchar *psk; - - g_return_if_fail (NM_IS_DEVICE_IWD (self)); - g_return_if_fail (NM_IS_ACT_REQUEST (req)); - - priv = NM_DEVICE_IWD_GET_PRIVATE (self); - - g_return_if_fail (priv->wifi_secrets_id == call_id); - - priv->wifi_secrets_id = NULL; - - if (g_error_matches (error, G_IO_ERROR, G_IO_ERROR_CANCELLED)) - return; - - g_return_if_fail (priv->secrets_request); - g_return_if_fail (req == nm_device_get_act_request (device)); - g_return_if_fail (nm_act_request_get_settings_connection (req) == s_connection); - - if (nm_device_get_state (device) != NM_DEVICE_STATE_NEED_AUTH) - goto secrets_error; - - if (error) { - _LOGW (LOGD_WIFI, "%s", error->message); - goto secrets_error; - } - - s_wireless_sec = nm_connection_get_setting_wireless_security (nm_act_request_get_applied_connection (req)); - if (!s_wireless_sec) - goto secrets_error; - - psk = nm_setting_wireless_security_get_psk (s_wireless_sec); - if (!psk) - goto secrets_error; - - _LOGD (LOGD_DEVICE | LOGD_WIFI, - "Returning a new PSK to the IWD Agent"); - - g_dbus_method_invocation_return_value (priv->secrets_request, - g_variant_new ("(s)", psk)); - priv->secrets_request = NULL; - - /* Change state back to what it was before NEED_AUTH */ - nm_device_state_changed (device, NM_DEVICE_STATE_CONFIG, NM_DEVICE_STATE_REASON_NONE); - return; - -secrets_error: - if (priv->secrets_request) { - g_dbus_method_invocation_return_error_literal (priv->secrets_request, NM_DEVICE_ERROR, - NM_DEVICE_ERROR_INVALID_CONNECTION, - "NM secrets request failed"); - priv->secrets_request = NULL; - } - - nm_device_state_changed (device, - NM_DEVICE_STATE_FAILED, - NM_DEVICE_STATE_REASON_NO_SECRETS); - - cleanup_association_attempt (self, TRUE); -} - -static void -wifi_secrets_get_secrets (NMDeviceIwd *self, - const char *setting_name, - NMSecretAgentGetSecretsFlags flags) -{ - NMDeviceIwdPrivate *priv = NM_DEVICE_IWD_GET_PRIVATE (self); - NMActRequest *req; - - wifi_secrets_cancel (self); - - req = nm_device_get_act_request (NM_DEVICE (self)); - g_return_if_fail (NM_IS_ACT_REQUEST (req)); - - priv->wifi_secrets_id = nm_act_request_get_secrets (req, - TRUE, - setting_name, - flags, - NULL, - wifi_secrets_cb, - self); -} - -static void -network_connect_cb (GObject *source, GAsyncResult *res, gpointer user_data) -{ - NMDeviceIwd *self = user_data; - NMDevice *device = NM_DEVICE (self); - gs_free_error GError *error = NULL; - NMConnection *connection; - NMSettingWireless *s_wifi; - GBytes *ssid; - gs_free gchar *str_ssid = NULL; - - if (!_nm_dbus_proxy_call_finish (G_DBUS_PROXY (source), res, - G_VARIANT_TYPE ("()"), - &error)) { - gs_free gchar *dbus_error = NULL; - - /* Connection failed; radio problems or if the network wasn't - * open, the passwords or certificates may be wrong. - */ - - _LOGE (LOGD_DEVICE | LOGD_WIFI, - "Activation: (wifi) Network.Connect failed: %s", - error->message); - - connection = nm_device_get_applied_connection (device); - if (!connection) - goto failed; - - if (g_error_matches (error, G_IO_ERROR, G_IO_ERROR_DBUS_ERROR)) - dbus_error = g_dbus_error_get_remote_error (error); - - /* If secrets were wrong, we'd be getting a net.connman.iwd.Failed */ - if (nm_streq0 (dbus_error, "net.connman.iwd.Failed")) { - nm_connection_clear_secrets (connection); - - nm_device_state_changed (device, NM_DEVICE_STATE_FAILED, - NM_DEVICE_STATE_REASON_NO_SECRETS); - } else if ( !nm_utils_error_is_cancelled (error, TRUE) - && nm_device_is_activating (device)) - goto failed; - - /* Call Disconnect to make sure IWD's autoconnect is disabled */ - cleanup_association_attempt (self, TRUE); - - return; - } - - nm_assert (nm_device_get_state (device) == NM_DEVICE_STATE_CONFIG); - - connection = nm_device_get_applied_connection (device); - if (!connection) - goto failed; - - s_wifi = nm_connection_get_setting_wireless (connection); - if (!s_wifi) - goto failed; - - ssid = nm_setting_wireless_get_ssid (s_wifi); - if (!ssid) - goto failed; - - str_ssid = nm_utils_ssid_to_utf8 (g_bytes_get_data (ssid, NULL), - g_bytes_get_size (ssid)); - - _LOGI (LOGD_DEVICE | LOGD_WIFI, - "Activation: (wifi) Stage 2 of 5 (Device Configure) successful. Connected to '%s'.", - str_ssid); - nm_device_activate_schedule_stage3_ip_config_start (device); - - nm_iwd_manager_network_connected (nm_iwd_manager_get (), str_ssid, - get_connection_iwd_security (connection)); - - return; - -failed: - cleanup_association_attempt (self, FALSE); - nm_device_queue_state (device, NM_DEVICE_STATE_FAILED, - NM_DEVICE_STATE_REASON_SUPPLICANT_FAILED); -} - -static void -set_powered (NMDeviceIwd *self, gboolean powered) -{ - NMDeviceIwdPrivate *priv = NM_DEVICE_IWD_GET_PRIVATE (self); - - g_dbus_proxy_call (priv->dbus_proxy, - "org.freedesktop.DBus.Properties.Set", - g_variant_new ("(ssv)", NM_IWD_DEVICE_INTERFACE, - "Powered", - g_variant_new ("b", powered)), - G_DBUS_CALL_FLAGS_NONE, 2000, - NULL, NULL, NULL); -} - -/*****************************************************************************/ - -static NMActStageReturn -act_stage1_prepare (NMDevice *device, NMDeviceStateReason *out_failure_reason) -{ - NMDeviceIwd *self = NM_DEVICE_IWD (device); - NMDeviceIwdPrivate *priv = NM_DEVICE_IWD_GET_PRIVATE (self); - NMActStageReturn ret; - NMWifiAP *ap = NULL; - NMActRequest *req; - NMConnection *connection; - NMSettingWireless *s_wireless; - const char *ap_path; - - ret = NM_DEVICE_CLASS (nm_device_iwd_parent_class)->act_stage1_prepare (device, out_failure_reason); - if (ret != NM_ACT_STAGE_RETURN_SUCCESS) - return ret; - - req = nm_device_get_act_request (device); - g_return_val_if_fail (req, NM_ACT_STAGE_RETURN_FAILURE); - - connection = nm_act_request_get_applied_connection (req); - g_return_val_if_fail (connection, NM_ACT_STAGE_RETURN_FAILURE); - - s_wireless = nm_connection_get_setting_wireless (connection); - g_return_val_if_fail (s_wireless, NM_ACT_STAGE_RETURN_FAILURE); - - ap_path = nm_active_connection_get_specific_object (NM_ACTIVE_CONNECTION (req)); - ap = ap_path ? nm_wifi_ap_lookup_for_device (NM_DEVICE (self), ap_path) : NULL; - if (!ap) { - ap = nm_wifi_aps_find_first_compatible (&priv->aps_lst_head, connection); - - /* TODO: assuming hidden networks aren't supported do we need - * to consider the case of APs that are not in the scan list - * yet, for which nm-device-wifi.c creates the temporary fake - * AP object? - */ - - nm_active_connection_set_specific_object (NM_ACTIVE_CONNECTION (req), - nm_dbus_object_get_path (NM_DBUS_OBJECT (ap))); - } - - set_current_ap (self, ap, FALSE); - return NM_ACT_STAGE_RETURN_SUCCESS; -} - -static NMActStageReturn -act_stage2_config (NMDevice *device, NMDeviceStateReason *out_failure_reason) -{ - NMDeviceIwd *self = NM_DEVICE_IWD (device); - NMDeviceIwdPrivate *priv = NM_DEVICE_IWD_GET_PRIVATE (self); - NMActStageReturn ret = NM_ACT_STAGE_RETURN_FAILURE; - NMActRequest *req; - NMWifiAP *ap; - NMConnection *connection; - GError *error = NULL; - GDBusProxy *network_proxy; - - req = nm_device_get_act_request (device); - g_return_val_if_fail (req, NM_ACT_STAGE_RETURN_FAILURE); - - ap = priv->current_ap; - if (!ap) { - NM_SET_OUT (out_failure_reason, NM_DEVICE_STATE_REASON_SUPPLICANT_FAILED); - goto out; - } - - connection = nm_act_request_get_applied_connection (req); - g_assert (connection); - - /* 802.1x networks that are not IWD Known Networks will definitely - * fail, for other combinations we will let the Connect call fail - * or ask us for any missing secrets through the Agent. - */ - if ( !is_connection_known_network (connection) - && nm_connection_get_setting_802_1x (connection)) { - _LOGI (LOGD_DEVICE | LOGD_WIFI, - "Activation: (wifi) access point '%s' has 802.1x security, but is not configured.", - nm_connection_get_id (connection)); - - NM_SET_OUT (out_failure_reason, NM_DEVICE_STATE_REASON_NO_SECRETS); - ret = NM_ACT_STAGE_RETURN_FAILURE; - goto out; - } - - /* Locate the IWD Network object */ - network_proxy = g_dbus_proxy_new_for_bus_sync (NM_IWD_BUS_TYPE, - G_DBUS_PROXY_FLAGS_DO_NOT_LOAD_PROPERTIES | - G_DBUS_PROXY_FLAGS_DO_NOT_CONNECT_SIGNALS, - NULL, - NM_IWD_SERVICE, - nm_wifi_ap_get_supplicant_path (ap), - NM_IWD_NETWORK_INTERFACE, - NULL, &error); - if (!network_proxy) { - _LOGE (LOGD_DEVICE | LOGD_WIFI, - "Activation: (wifi) could not get Network interface proxy for %s: %s", - nm_wifi_ap_get_supplicant_path (ap), - error->message); - g_clear_error (&error); - NM_SET_OUT (out_failure_reason, NM_DEVICE_STATE_REASON_SUPPLICANT_FAILED); - goto out; - } - - if (!priv->cancellable) - priv->cancellable = g_cancellable_new (); - - /* Call Network.Connect. No timeout because IWD already handles - * timeouts. - */ - g_dbus_proxy_call (network_proxy, "Connect", - g_variant_new ("()"), - G_DBUS_CALL_FLAGS_NONE, G_MAXINT, - priv->cancellable, network_connect_cb, self); - - g_object_unref (network_proxy); - - /* 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, FALSE); - - return ret; -} - -static guint32 -get_configured_mtu (NMDevice *device, gboolean *out_is_user_config) -{ - NMSettingWireless *setting; - gint64 mtu_default; - guint32 mtu; - - nm_assert (NM_IS_DEVICE (device)); - nm_assert (out_is_user_config); - - setting = NM_SETTING_WIRELESS (nm_device_get_applied_setting (device, NM_TYPE_SETTING_WIRELESS)); - if (!setting) - g_return_val_if_reached (0); - - mtu = nm_setting_wireless_get_mtu (setting); - if (mtu == 0) { - mtu_default = nm_device_get_configured_mtu_from_connection_default (device, "wifi.mtu"); - if (mtu_default >= 0) { - *out_is_user_config = TRUE; - return (guint32) mtu_default; - } - } - *out_is_user_config = (mtu != 0); - return mtu; -} - -static gboolean -periodic_scan_timeout_cb (gpointer user_data) -{ - NMDeviceIwd *self = user_data; - NMDeviceIwdPrivate *priv = NM_DEVICE_IWD_GET_PRIVATE (self); - - priv->periodic_scan_id = 0; - - if (priv->scanning || priv->scan_requested) - return FALSE; - - g_dbus_proxy_call (priv->dbus_proxy, "Scan", g_variant_new ("()"), - G_DBUS_CALL_FLAGS_NONE, -1, - priv->cancellable, scan_cb, self); - priv->scan_requested = TRUE; - - return FALSE; -} - -static void -schedule_periodic_scan (NMDeviceIwd *self, NMDeviceState current_state) -{ - NMDeviceIwdPrivate *priv = NM_DEVICE_IWD_GET_PRIVATE (self); - guint interval; - - if (current_state <= NM_DEVICE_STATE_UNAVAILABLE) - return; - - if (current_state == NM_DEVICE_STATE_DISCONNECTED) - interval = 10; - else - interval = 20; - - nm_clear_g_source (&priv->periodic_scan_id); - priv->periodic_scan_id = g_timeout_add_seconds (interval, - periodic_scan_timeout_cb, - self); -} - -static void -device_state_changed (NMDevice *device, - NMDeviceState new_state, - NMDeviceState old_state, - NMDeviceStateReason reason) -{ - NMDeviceIwd *self = NM_DEVICE_IWD (device); - NMDeviceIwdPrivate *priv = NM_DEVICE_IWD_GET_PRIVATE (self); - - if (new_state <= NM_DEVICE_STATE_UNAVAILABLE) { - remove_all_aps (self); - nm_clear_g_source (&priv->periodic_scan_id); - } else if (old_state <= NM_DEVICE_STATE_UNAVAILABLE) { - update_aps (self); - schedule_periodic_scan (self, new_state); - } - - switch (new_state) { - case NM_DEVICE_STATE_UNMANAGED: - break; - case NM_DEVICE_STATE_UNAVAILABLE: - /* - * If the device is enabled and the IWD manager is ready, - * transition to DISCONNECTED because the device is now - * ready to use. - */ - if (priv->enabled && priv->dbus_obj) { - nm_device_queue_recheck_available (device, - NM_DEVICE_STATE_REASON_SUPPLICANT_AVAILABLE, - NM_DEVICE_STATE_REASON_SUPPLICANT_FAILED); - } - break; - case NM_DEVICE_STATE_NEED_AUTH: - break; - case NM_DEVICE_STATE_IP_CHECK: - break; - case NM_DEVICE_STATE_ACTIVATED: - break; - case NM_DEVICE_STATE_FAILED: - break; - case NM_DEVICE_STATE_DISCONNECTED: - break; - default: - break; - } -} - -static gboolean -get_enabled (NMDevice *device) -{ - return NM_DEVICE_IWD_GET_PRIVATE ((NMDeviceIwd *) device)->enabled; -} - -static void -set_enabled (NMDevice *device, gboolean enabled) -{ - NMDeviceIwd *self = NM_DEVICE_IWD (device); - NMDeviceIwdPrivate *priv = NM_DEVICE_IWD_GET_PRIVATE (self); - NMDeviceState state; - - enabled = !!enabled; - - if (priv->enabled == enabled) - return; - - priv->enabled = enabled; - - _LOGD (LOGD_WIFI, "device now %s", enabled ? "enabled" : "disabled"); - - state = nm_device_get_state (device); - if (state < NM_DEVICE_STATE_UNAVAILABLE) { - _LOGD (LOGD_WIFI, "(%s): device blocked by UNMANAGED state", - enabled ? "enable" : "disable"); - return; - } - - if (priv->dbus_proxy) - set_powered (self, enabled); - - if (enabled) { - if (state != NM_DEVICE_STATE_UNAVAILABLE) - _LOGW (LOGD_CORE, "not in expected unavailable state!"); - - if (priv->dbus_obj) - nm_device_queue_recheck_available (device, - NM_DEVICE_STATE_REASON_SUPPLICANT_AVAILABLE, - NM_DEVICE_STATE_REASON_SUPPLICANT_FAILED); - } else { - nm_device_state_changed (device, - NM_DEVICE_STATE_UNAVAILABLE, - NM_DEVICE_STATE_REASON_NONE); - } -} - -static gboolean -can_reapply_change (NMDevice *device, - const char *setting_name, - NMSetting *s_old, - NMSetting *s_new, - GHashTable *diffs, - GError **error) -{ - NMDeviceClass *device_class; - - /* Only handle wireless setting here, delegate other settings to parent class */ - if (nm_streq (setting_name, NM_SETTING_WIRELESS_SETTING_NAME)) { - return nm_device_hash_check_invalid_keys (diffs, - NM_SETTING_WIRELESS_SETTING_NAME, - error, - NM_SETTING_WIRELESS_MTU); /* reapplied with IP config */ - } - - device_class = NM_DEVICE_CLASS (nm_device_iwd_parent_class); - return device_class->can_reapply_change (device, - setting_name, - s_old, - s_new, - diffs, - error); -} - -/*****************************************************************************/ - -static void -get_property (GObject *object, guint prop_id, - GValue *value, GParamSpec *pspec) -{ - NMDeviceIwd *self = NM_DEVICE_IWD (object); - NMDeviceIwdPrivate *priv = NM_DEVICE_IWD_GET_PRIVATE (self); - const char **list; - - switch (prop_id) { - case PROP_MODE: - if (priv->current_ap) - g_value_set_uint (value, NM_802_11_MODE_INFRA); - else - g_value_set_uint (value, NM_802_11_MODE_UNKNOWN); - break; - case PROP_BITRATE: - g_value_set_uint (value, 65000); - break; - case PROP_CAPABILITIES: - g_value_set_uint (value, priv->capabilities); - break; - case PROP_ACCESS_POINTS: - list = nm_wifi_aps_get_paths (&priv->aps_lst_head, TRUE); - g_value_take_boxed (value, nm_utils_strv_make_deep_copied (list)); - break; - case PROP_ACTIVE_ACCESS_POINT: - nm_dbus_utils_g_value_set_object_path (value, priv->current_ap); - break; - case PROP_SCANNING: - g_value_set_boolean (value, priv->scanning); - break; - 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) -{ - NMDeviceIwd *device = NM_DEVICE_IWD (object); - NMDeviceIwdPrivate *priv = NM_DEVICE_IWD_GET_PRIVATE (device); - - switch (prop_id) { - case PROP_CAPABILITIES: - /* construct-only */ - priv->capabilities = g_value_get_uint (value); - break; - default: - G_OBJECT_WARN_INVALID_PROPERTY_ID (object, prop_id, pspec); - break; - } -} - -/*****************************************************************************/ - -static void -state_changed (NMDeviceIwd *self, const gchar *new_state) -{ - NMDeviceIwdPrivate *priv = NM_DEVICE_IWD_GET_PRIVATE (self); - NMDevice *device = NM_DEVICE (self); - NMDeviceState dev_state = nm_device_get_state (device); - gboolean iwd_connection = FALSE; - gboolean can_connect; - - _LOGI (LOGD_DEVICE | LOGD_WIFI, "new IWD device state is %s", new_state); - - if ( dev_state >= NM_DEVICE_STATE_CONFIG - && dev_state <= NM_DEVICE_STATE_ACTIVATED) - iwd_connection = TRUE; - - /* Don't allow scanning while connecting, disconnecting or roaming */ - priv->can_scan = NM_IN_STRSET (new_state, "connected", "disconnected"); - - /* Don't allow new connection until iwd exits disconnecting */ - can_connect = NM_IN_STRSET (new_state, "disconnected"); - if (can_connect != priv->can_connect) { - priv->can_connect = can_connect; - nm_device_emit_recheck_auto_activate (device); - } - - if (NM_IN_STRSET (new_state, "connecting", "connected", "roaming")) { - /* If we were connecting, do nothing, the confirmation of - * a connection success is handled in the Device.Connect - * method return callback. Otherwise IWD must have connected - * without Network Manager's will so for simplicity force a - * disconnect. - */ - if (iwd_connection) - return; - - _LOGW (LOGD_DEVICE | LOGD_WIFI, - "Unsolicited connection success, asking IWD to disconnect"); - send_disconnect (self); - - return; - } else if (NM_IN_STRSET (new_state, "disconnecting", "disconnected")) { - if (!iwd_connection) - return; - - /* Call Disconnect on the IWD device object to make sure it - * disables its own autoconnect. - * - * Note we could instead call net.connman.iwd.KnownNetworks.ForgetNetwork - * and leave the device in autoconnect. This way if NetworkManager - * changes any settings for this connection, they'd be taken into - * account on the next connection attempt. But both methods are - * a hack, we'll perhaps need an IWD API to "connect once" without - * storing anything. - */ - send_disconnect (self); - - /* - * If IWD is still handling the Connect call, let our callback - * for the dbus method handle the failure. - */ - if (dev_state == NM_DEVICE_STATE_CONFIG) - return; - - nm_device_state_changed (device, - NM_DEVICE_STATE_FAILED, - NM_DEVICE_STATE_REASON_SUPPLICANT_DISCONNECT); - - return; - } - - _LOGE (LOGD_WIFI, "State %s unknown", new_state); -} - -static void -scanning_changed (NMDeviceIwd *self, gboolean new_scanning) -{ - NMDeviceIwdPrivate *priv = NM_DEVICE_IWD_GET_PRIVATE (self); - NMDeviceState state = nm_device_get_state (NM_DEVICE (self)); - - if (new_scanning == priv->scanning) - return; - - priv->scanning = new_scanning; - - _notify (self, PROP_SCANNING); - - if (!priv->scanning) { - update_aps (self); - - if (!priv->scan_requested) - schedule_periodic_scan (self, state); - } -} - -static void -powered_changed (NMDeviceIwd *self, gboolean new_powered) -{ - nm_device_queue_recheck_available (NM_DEVICE (self), - NM_DEVICE_STATE_REASON_SUPPLICANT_AVAILABLE, - NM_DEVICE_STATE_REASON_SUPPLICANT_FAILED); -} - -static void -properties_changed (GDBusProxy *proxy, GVariant *changed_properties, - GStrv invalidate_properties, gpointer user_data) -{ - NMDeviceIwd *self = user_data; - GVariantIter *iter; - const gchar *key; - GVariant *value; - - g_variant_get (changed_properties, "a{sv}", &iter); - while (g_variant_iter_next (iter, "{&sv}", &key, &value)) { - if (!strcmp (key, "State")) - state_changed (self, g_variant_get_string (value, NULL)); - - if (!strcmp (key, "Scanning")) - scanning_changed (self, g_variant_get_boolean (value)); - - if (!strcmp (key, "Powered")) - powered_changed (self, g_variant_get_boolean (value)); - - g_variant_unref (value); - } - - g_variant_iter_free (iter); -} - -void -nm_device_iwd_set_dbus_object (NMDeviceIwd *self, GDBusObject *object) -{ - NMDeviceIwdPrivate *priv = NM_DEVICE_IWD_GET_PRIVATE (self); - GDBusInterface *interface; - GVariant *value; - - if (!nm_g_object_ref_set ((GObject **) &priv->dbus_obj, (GObject *) object)) - return; - - if (priv->dbus_proxy) { - g_signal_handlers_disconnect_by_func (priv->dbus_proxy, - properties_changed, self); - - g_clear_object (&priv->dbus_proxy); - } - - if (priv->enabled) - nm_device_queue_recheck_available (NM_DEVICE (self), - NM_DEVICE_STATE_REASON_SUPPLICANT_AVAILABLE, - NM_DEVICE_STATE_REASON_SUPPLICANT_FAILED); - - if (!object) { - priv->can_scan = FALSE; - - cleanup_association_attempt (self, FALSE); - return; - } - - interface = g_dbus_object_get_interface (object, NM_IWD_DEVICE_INTERFACE); - priv->dbus_proxy = G_DBUS_PROXY (interface); - - value = g_dbus_proxy_get_cached_property (priv->dbus_proxy, "Scanning"); - priv->scanning = g_variant_get_boolean (value); - g_variant_unref (value); - priv->scan_requested = FALSE; - - value = g_dbus_proxy_get_cached_property (priv->dbus_proxy, "State"); - state_changed (self, g_variant_get_string (value, NULL)); - g_variant_unref (value); - - g_signal_connect (priv->dbus_proxy, "g-properties-changed", - G_CALLBACK (properties_changed), self); - - set_powered (self, priv->enabled); - - /* Call Disconnect to make sure IWD's autoconnect is disabled. - * Autoconnect is the default state after device is brought UP. - */ - if (priv->enabled) - send_disconnect (self); -} - -gboolean -nm_device_iwd_agent_psk_query (NMDeviceIwd *self, - GDBusMethodInvocation *invocation) -{ - NMDeviceIwdPrivate *priv = NM_DEVICE_IWD_GET_PRIVATE (self); - NMActRequest *req; - NMSettingWirelessSecurity *s_wireless_sec; - const gchar *psk; - - req = nm_device_get_act_request (NM_DEVICE (self)); - if (!req) - return FALSE; - - s_wireless_sec = nm_connection_get_setting_wireless_security (nm_act_request_get_applied_connection (req)); - if (!s_wireless_sec) - return FALSE; - - psk = nm_setting_wireless_security_get_psk (s_wireless_sec); - if (psk) { - _LOGD (LOGD_DEVICE | LOGD_WIFI, - "Returning the PSK to the IWD Agent"); - - g_dbus_method_invocation_return_value (invocation, - g_variant_new ("(s)", psk)); - return TRUE; - } - - nm_device_state_changed (NM_DEVICE (self), NM_DEVICE_STATE_NEED_AUTH, - NM_DEVICE_STATE_REASON_NO_SECRETS); - wifi_secrets_get_secrets (self, - NM_SETTING_WIRELESS_SECURITY_SETTING_NAME, - NM_SECRET_AGENT_GET_SECRETS_FLAG_ALLOW_INTERACTION - | NM_SECRET_AGENT_GET_SECRETS_FLAG_REQUEST_NEW); - - priv->secrets_request = invocation; - return TRUE; -} - -/*****************************************************************************/ - -static const char * -get_type_description (NMDevice *device) -{ - nm_assert (NM_IS_DEVICE_IWD (device)); - - return "wifi"; -} - -/*****************************************************************************/ - -static void -nm_device_iwd_init (NMDeviceIwd *self) -{ - NMDeviceIwdPrivate *priv = NM_DEVICE_IWD_GET_PRIVATE (self); - - c_list_init (&priv->aps_lst_head); - - /* Make sure the manager is running */ - (void) nm_iwd_manager_get (); -} - -NMDevice * -nm_device_iwd_new (const char *iface, NMDeviceWifiCapabilities capabilities) -{ - return g_object_new (NM_TYPE_DEVICE_IWD, - NM_DEVICE_IFACE, iface, - NM_DEVICE_TYPE_DESC, "802.11 WiFi", - NM_DEVICE_DEVICE_TYPE, NM_DEVICE_TYPE_WIFI, - NM_DEVICE_LINK_TYPE, NM_LINK_TYPE_WIFI, - NM_DEVICE_RFKILL_TYPE, RFKILL_TYPE_WLAN, - NM_DEVICE_IWD_CAPABILITIES, (guint) capabilities, - NULL); -} - -static void -dispose (GObject *object) -{ - NMDeviceIwd *self = NM_DEVICE_IWD (object); - NMDeviceIwdPrivate *priv = NM_DEVICE_IWD_GET_PRIVATE (self); - - nm_clear_g_cancellable (&priv->cancellable); - - nm_clear_g_source (&priv->periodic_scan_id); - - cleanup_association_attempt (self, TRUE); - - g_clear_object (&priv->dbus_proxy); - g_clear_object (&priv->dbus_obj); - - remove_all_aps (self); - - G_OBJECT_CLASS (nm_device_iwd_parent_class)->dispose (object); - - nm_assert (c_list_is_empty (&priv->aps_lst_head)); -} - -static void -nm_device_iwd_class_init (NMDeviceIwdClass *klass) -{ - GObjectClass *object_class = G_OBJECT_CLASS (klass); - NMDBusObjectClass *dbus_object_class = NM_DBUS_OBJECT_CLASS (klass); - NMDeviceClass *parent_class = NM_DEVICE_CLASS (klass); - - NM_DEVICE_CLASS_DECLARE_TYPES (klass, NM_SETTING_WIRELESS_SETTING_NAME, NM_LINK_TYPE_WIFI) - - object_class->get_property = get_property; - object_class->set_property = set_property; - object_class->dispose = dispose; - - dbus_object_class->interface_infos = NM_DBUS_INTERFACE_INFOS (&nm_interface_info_device_wireless); - - parent_class->can_auto_connect = can_auto_connect; - parent_class->is_available = is_available; - parent_class->get_autoconnect_allowed = get_autoconnect_allowed; - parent_class->check_connection_compatible = check_connection_compatible; - parent_class->check_connection_available = check_connection_available; - parent_class->complete_connection = complete_connection; - parent_class->get_enabled = get_enabled; - parent_class->set_enabled = set_enabled; - parent_class->get_type_description = get_type_description; - - parent_class->act_stage1_prepare = act_stage1_prepare; - parent_class->act_stage2_config = act_stage2_config; - parent_class->get_configured_mtu = get_configured_mtu; - parent_class->deactivate = deactivate; - parent_class->deactivate_async = deactivate_async; - parent_class->deactivate_async_finish = deactivate_async_finish; - parent_class->can_reapply_change = can_reapply_change; - - parent_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, - NM_802_11_MODE_AP, - NM_802_11_MODE_INFRA, - G_PARAM_READABLE | - G_PARAM_STATIC_STRINGS); - - obj_properties[PROP_BITRATE] = - g_param_spec_uint (NM_DEVICE_IWD_BITRATE, "", "", - 0, G_MAXUINT32, 0, - G_PARAM_READABLE | - G_PARAM_STATIC_STRINGS); - - obj_properties[PROP_ACCESS_POINTS] = - g_param_spec_boxed (NM_DEVICE_IWD_ACCESS_POINTS, "", "", - G_TYPE_STRV, - G_PARAM_READABLE | - G_PARAM_STATIC_STRINGS); - - obj_properties[PROP_ACTIVE_ACCESS_POINT] = - g_param_spec_string (NM_DEVICE_IWD_ACTIVE_ACCESS_POINT, "", "", - NULL, - G_PARAM_READABLE | - G_PARAM_STATIC_STRINGS); - - obj_properties[PROP_CAPABILITIES] = - g_param_spec_uint (NM_DEVICE_IWD_CAPABILITIES, "", "", - 0, G_MAXUINT32, NM_WIFI_DEVICE_CAP_NONE, - G_PARAM_READWRITE | - G_PARAM_CONSTRUCT_ONLY | - G_PARAM_STATIC_STRINGS); - - obj_properties[PROP_SCANNING] = - g_param_spec_boolean (NM_DEVICE_IWD_SCANNING, "", "", - FALSE, - 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 deleted file mode 100644 index 699ba1bb..00000000 --- a/src/devices/wifi/nm-device-iwd.h +++ /dev/null @@ -1,62 +0,0 @@ -/* -*- Mode: C; tab-width: 4; indent-tabs-mode: t; c-basic-offset: 4 -*- */ -/* NetworkManager -- Network link manager - * - * This program is free software; you can redistribute it and/or modify - * it under the terms of the GNU General Public License as published by - * the Free Software Foundation; either version 2 of the License, or - * (at your option) any later version. - * - * This program is distributed in the hope that it will be useful, - * but WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the - * GNU General Public License for more details. - * - * You should have received a copy of the GNU General Public License along - * with this program; if not, write to the Free Software Foundation, Inc., - * 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA. - * - * Copyright (C) 2017 Intel Corporation - */ - -#ifndef __NETWORKMANAGER_DEVICE_IWD_H__ -#define __NETWORKMANAGER_DEVICE_IWD_H__ - -#include "devices/nm-device.h" -#include "nm-wifi-ap.h" -#include "nm-device-wifi.h" - -#define NM_TYPE_DEVICE_IWD (nm_device_iwd_get_type ()) -#define NM_DEVICE_IWD(obj) (G_TYPE_CHECK_INSTANCE_CAST ((obj), NM_TYPE_DEVICE_IWD, NMDeviceIwd)) -#define NM_DEVICE_IWD_CLASS(klass) (G_TYPE_CHECK_CLASS_CAST ((klass), NM_TYPE_DEVICE_IWD, NMDeviceIwdClass)) -#define NM_IS_DEVICE_IWD(obj) (G_TYPE_CHECK_INSTANCE_TYPE ((obj), NM_TYPE_DEVICE_IWD)) -#define NM_IS_DEVICE_IWD_CLASS(klass) (G_TYPE_CHECK_CLASS_TYPE ((klass), NM_TYPE_DEVICE_IWD)) -#define NM_DEVICE_IWD_GET_CLASS(obj) (G_TYPE_INSTANCE_GET_CLASS ((obj), NM_TYPE_DEVICE_IWD, NMDeviceIwdClass)) - -#define NM_DEVICE_IWD_MODE NM_DEVICE_WIFI_MODE -#define NM_DEVICE_IWD_BITRATE NM_DEVICE_WIFI_BITRATE -#define NM_DEVICE_IWD_ACCESS_POINTS NM_DEVICE_WIFI_ACCESS_POINTS -#define NM_DEVICE_IWD_ACTIVE_ACCESS_POINT NM_DEVICE_WIFI_ACTIVE_ACCESS_POINT -#define NM_DEVICE_IWD_CAPABILITIES NM_DEVICE_WIFI_CAPABILITIES -#define NM_DEVICE_IWD_SCANNING NM_DEVICE_WIFI_SCANNING - -#define NM_DEVICE_IWD_SCANNING_PROHIBITED NM_DEVICE_WIFI_SCANNING_PROHIBITED - -typedef struct _NMDeviceIwd NMDeviceIwd; -typedef struct _NMDeviceIwdClass NMDeviceIwdClass; - -GType nm_device_iwd_get_type (void); - -NMDevice *nm_device_iwd_new (const char *iface, NMDeviceWifiCapabilities capabilities); - -void nm_device_iwd_set_dbus_object (NMDeviceIwd *device, GDBusObject *object); - -gboolean nm_device_iwd_agent_psk_query (NMDeviceIwd *device, - GDBusMethodInvocation *invocation); - -const CList *_nm_device_iwd_get_aps (NMDeviceIwd *self); - -void _nm_device_iwd_request_scan (NMDeviceIwd *self, - GVariant *options, - GDBusMethodInvocation *invocation); - -#endif /* __NETWORKMANAGER_DEVICE_IWD_H__ */ diff --git a/src/devices/wifi/nm-device-olpc-mesh.c b/src/devices/wifi/nm-device-olpc-mesh.c index cd2c68af..3a4a027a 100644 --- a/src/devices/wifi/nm-device-olpc-mesh.c +++ b/src/devices/wifi/nm-device-olpc-mesh.c @@ -48,6 +48,11 @@ #include "nm-manager.h" #include "platform/nm-platform.h" +/* This is a bug; but we can't really change API now... */ +#include "nm-vpn-dbus-interface.h" + +#include "introspection/org.freedesktop.NetworkManager.Device.OlpcMesh.h" + #include "devices/nm-device-logging.h" _LOG_DECLARE_SELF(NMDeviceOlpcMesh); @@ -113,7 +118,7 @@ static gboolean complete_connection (NMDevice *device, NMConnection *connection, const char *specific_object, - NMConnection *const*existing_connections, + const GSList *existing_connections, GError **error) { NMSettingOlpcMesh *s_mesh; @@ -387,8 +392,7 @@ static void find_companion (NMDeviceOlpcMesh *self) { NMDeviceOlpcMeshPrivate *priv = NM_DEVICE_OLPC_MESH_GET_PRIVATE (self); - const CList *tmp_lst; - NMDevice *candidate; + const GSList *list; if (priv->companion) return; @@ -396,8 +400,8 @@ find_companion (NMDeviceOlpcMesh *self) nm_device_add_pending_action (NM_DEVICE (self), NM_PENDING_ACTION_WAITING_FOR_COMPANION, TRUE); /* Try to find the companion if it's already known to the NMManager */ - nm_manager_for_each_device (priv->manager, candidate, tmp_lst) { - if (check_companion (self, candidate)) { + for (list = nm_manager_get_devices (priv->manager); list ; list = g_slist_next (list)) { + if (check_companion (self, NM_DEVICE (list->data))) { nm_device_queue_recheck_available (NM_DEVICE (self), NM_DEVICE_STATE_REASON_NONE, NM_DEVICE_STATE_REASON_NONE); @@ -436,7 +440,7 @@ get_property (GObject *object, guint prop_id, switch (prop_id) { case PROP_COMPANION: - nm_dbus_utils_g_value_set_object_path (value, priv->companion); + nm_utils_g_value_set_object_path (value, priv->companion); break; case PROP_ACTIVE_CHANNEL: g_value_set_uint (value, nm_platform_mesh_get_channel (nm_device_get_platform (device), nm_device_get_ifindex (device))); @@ -496,26 +500,10 @@ dispose (GObject *object) G_OBJECT_CLASS (nm_device_olpc_mesh_parent_class)->dispose (object); } -static const NMDBusInterfaceInfoExtended interface_info_device_olpc_mesh = { - .parent = NM_DEFINE_GDBUS_INTERFACE_INFO_INIT ( - NM_DBUS_INTERFACE_DEVICE_OLPC_MESH, - .signals = NM_DEFINE_GDBUS_SIGNAL_INFOS ( - &nm_signal_info_property_changed_legacy, - ), - .properties = NM_DEFINE_GDBUS_PROPERTY_INFOS ( - NM_DEFINE_DBUS_PROPERTY_INFO_EXTENDED_READABLE_L ("HwAddress", "s", NM_DEVICE_HW_ADDRESS), - NM_DEFINE_DBUS_PROPERTY_INFO_EXTENDED_READABLE_L ("Companion", "o", NM_DEVICE_OLPC_MESH_COMPANION), - NM_DEFINE_DBUS_PROPERTY_INFO_EXTENDED_READABLE_L ("ActiveChannel", "u", NM_DEVICE_OLPC_MESH_ACTIVE_CHANNEL), - ), - ), - .legacy_property_changed = TRUE, -}; - static void nm_device_olpc_mesh_class_init (NMDeviceOlpcMeshClass *klass) { GObjectClass *object_class = G_OBJECT_CLASS (klass); - NMDBusObjectClass *dbus_object_class = NM_DBUS_OBJECT_CLASS (klass); NMDeviceClass *parent_class = NM_DEVICE_CLASS (klass); NM_DEVICE_CLASS_DECLARE_TYPES (klass, NM_SETTING_OLPC_MESH_SETTING_NAME, NM_LINK_TYPE_OLPC_MESH) @@ -524,8 +512,6 @@ nm_device_olpc_mesh_class_init (NMDeviceOlpcMeshClass *klass) object_class->get_property = get_property; object_class->dispose = dispose; - dbus_object_class->interface_infos = NM_DBUS_INTERFACE_INFOS (&interface_info_device_olpc_mesh); - parent_class->check_connection_compatible = check_connection_compatible; parent_class->get_autoconnect_allowed = get_autoconnect_allowed; parent_class->complete_connection = complete_connection; @@ -548,5 +534,9 @@ nm_device_olpc_mesh_class_init (NMDeviceOlpcMeshClass *klass) G_PARAM_STATIC_STRINGS); g_object_class_install_properties (object_class, _PROPERTY_ENUMS_LAST, obj_properties); + + nm_exported_object_class_add_interface (NM_EXPORTED_OBJECT_CLASS (klass), + NMDBUS_TYPE_DEVICE_OLPC_MESH_SKELETON, + NULL); } diff --git a/src/devices/wifi/nm-device-wifi.c b/src/devices/wifi/nm-device-wifi.c index de4af42c..bf021095 100644 --- a/src/devices/wifi/nm-device-wifi.c +++ b/src/devices/wifi/nm-device-wifi.c @@ -28,11 +28,9 @@ #include <unistd.h> #include <errno.h> -#include "nm-wifi-ap.h" #include "nm-common-macros.h" #include "devices/nm-device.h" #include "devices/nm-device-private.h" -#include "nm-dbus-manager.h" #include "nm-utils.h" #include "NetworkManagerUtils.h" #include "nm-act-request.h" @@ -50,11 +48,11 @@ #include "nm-auth-utils.h" #include "settings/nm-settings-connection.h" #include "settings/nm-settings.h" -#include "nm-wifi-utils.h" -#include "nm-wifi-common.h" #include "nm-core-internal.h" #include "nm-config.h" +#include "introspection/org.freedesktop.NetworkManager.Device.Wireless.h" + #include "devices/nm-device-logging.h" _LOG_DECLARE_SELF(NMDeviceWifi); @@ -77,6 +75,8 @@ NM_GOBJECT_PROPERTIES_DEFINE (NMDeviceWifi, ); enum { + ACCESS_POINT_ADDED, + ACCESS_POINT_REMOVED, SCANNING_PROHIBITED, LAST_SIGNAL @@ -87,8 +87,7 @@ static guint signals[LAST_SIGNAL] = { 0 }; typedef struct { gint8 invalid_strength_counter; - CList aps_lst_head; - + GHashTable * aps; NMWifiAP * current_ap; guint32 rate; bool enabled:1; /* rfkilled or not */ @@ -188,7 +187,7 @@ static void request_wireless_scan (NMDeviceWifi *self, const GPtrArray *ssids); static void ap_add_remove (NMDeviceWifi *self, - gboolean is_adding, + guint signum, NMWifiAP *ap, gboolean recheck_available_connections); @@ -346,6 +345,30 @@ supplicant_interface_release (NMDeviceWifi *self) _notify_scanning (self); } +static NMWifiAP * +get_ap_by_path (NMDeviceWifi *self, const char *path) +{ + g_return_val_if_fail (path != NULL, NULL); + return g_hash_table_lookup (NM_DEVICE_WIFI_GET_PRIVATE (self)->aps, path); + +} + +static NMWifiAP * +get_ap_by_supplicant_path (NMDeviceWifi *self, const char *path) +{ + GHashTableIter iter; + NMWifiAP *ap; + + g_return_val_if_fail (path != NULL, NULL); + + g_hash_table_iter_init (&iter, NM_DEVICE_WIFI_GET_PRIVATE (self)->aps); + while (g_hash_table_iter_next (&iter, NULL, (gpointer) &ap)) { + if (g_strcmp0 (path, nm_wifi_ap_get_supplicant_path (ap)) == 0) + return ap; + } + return NULL; +} + static void update_seen_bssids_cache (NMDeviceWifi *self, NMWifiAP *ap) { @@ -392,7 +415,7 @@ set_current_ap (NMDeviceWifi *self, NMWifiAP *new_ap, gboolean recheck_available /* Remove any AP from the internal list if it was created by NM or isn't known to the supplicant */ if (mode == NM_802_11_MODE_ADHOC || mode == NM_802_11_MODE_AP || nm_wifi_ap_get_fake (old_ap)) - ap_add_remove (self, FALSE, old_ap, recheck_available_connections); + ap_add_remove (self, ACCESS_POINT_REMOVED, old_ap, recheck_available_connections); g_object_unref (old_ap); } @@ -459,32 +482,32 @@ periodic_update_cb (gpointer user_data) static void ap_add_remove (NMDeviceWifi *self, - gboolean is_adding, /* or else removing */ + guint signum, NMWifiAP *ap, gboolean recheck_available_connections) { NMDeviceWifiPrivate *priv = NM_DEVICE_WIFI_GET_PRIVATE (self); - if (is_adding) { - g_object_ref (ap); - ap->wifi_device = NM_DEVICE (self); - c_list_link_tail (&priv->aps_lst_head, &ap->aps_lst); - nm_dbus_object_export (NM_DBUS_OBJECT (ap)); + nm_assert (NM_IN_SET (signum, ACCESS_POINT_ADDED, ACCESS_POINT_REMOVED)); + + if (signum == ACCESS_POINT_ADDED) { + g_hash_table_insert (priv->aps, + (gpointer) nm_exported_object_export ((NMExportedObject *) ap), + g_object_ref (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); + } else _ap_dump (self, LOGL_DEBUG, ap, "removed", 0); - } - _notify (self, PROP_ACCESS_POINTS); + g_signal_emit (self, signals[signum], 0, ap); - if (!is_adding) { - nm_device_wifi_emit_signal_access_point (NM_DEVICE (self), ap, FALSE); - nm_dbus_object_clear_and_unexport (&ap); + if (signum == ACCESS_POINT_REMOVED) { + g_hash_table_remove (priv->aps, nm_exported_object_get_path ((NMExportedObject *) ap)); + nm_exported_object_unexport ((NMExportedObject *) ap); + g_object_unref (ap); } + _notify (self, PROP_ACCESS_POINTS); + nm_device_emit_recheck_auto_activate (NM_DEVICE (self)); if (recheck_available_connections) nm_device_recheck_available_connections (NM_DEVICE (self)); @@ -494,15 +517,20 @@ static void remove_all_aps (NMDeviceWifi *self) { NMDeviceWifiPrivate *priv = NM_DEVICE_WIFI_GET_PRIVATE (self); + GHashTableIter iter; NMWifiAP *ap; - if (c_list_is_empty (&priv->aps_lst_head)) + if (!g_hash_table_size (priv->aps)) return; set_current_ap (self, NULL, FALSE); - while ((ap = c_list_first_entry (&priv->aps_lst_head, NMWifiAP, aps_lst))) - ap_add_remove (self, FALSE, ap, FALSE); +again: + g_hash_table_iter_init (&iter, priv->aps); + if (g_hash_table_iter_next (&iter, NULL, (gpointer) &ap)) { + ap_add_remove (self, ACCESS_POINT_REMOVED, ap, FALSE); + goto again; + } nm_device_recheck_available_connections (NM_DEVICE (self)); } @@ -652,14 +680,35 @@ check_connection_compatible (NMDevice *device, NMConnection *connection) return TRUE; } +static NMWifiAP * +find_first_compatible_ap (NMDeviceWifi *self, + NMConnection *connection, + gboolean allow_unstable_order) +{ + GHashTableIter iter; + NMWifiAP *ap; + NMWifiAP *cand_ap = NULL; + + g_return_val_if_fail (connection != NULL, NULL); + + g_hash_table_iter_init (&iter, NM_DEVICE_WIFI_GET_PRIVATE (self)->aps); + while (g_hash_table_iter_next (&iter, NULL, (gpointer) &ap)) { + if (!nm_wifi_ap_check_compatible (ap, connection)) + continue; + if (allow_unstable_order) + return ap; + if (!cand_ap || (nm_wifi_ap_get_id (cand_ap) < nm_wifi_ap_get_id (ap))) + cand_ap = ap; + } + return cand_ap; +} + static gboolean check_connection_available (NMDevice *device, NMConnection *connection, NMDeviceCheckConAvailableFlags flags, const char *specific_object) { - NMDeviceWifi *self = NM_DEVICE_WIFI (device); - NMDeviceWifiPrivate *priv = NM_DEVICE_WIFI_GET_PRIVATE (self); NMSettingWireless *s_wifi; const char *mode; @@ -672,7 +721,7 @@ check_connection_available (NMDevice *device, if (specific_object) { NMWifiAP *ap; - ap = nm_wifi_ap_lookup_for_device (NM_DEVICE (self), specific_object); + ap = get_ap_by_path (NM_DEVICE_WIFI (device), specific_object); return ap ? nm_wifi_ap_check_compatible (ap, connection) : FALSE; } @@ -696,18 +745,50 @@ check_connection_available (NMDevice *device, return TRUE; /* check at least one AP is compatible with this connection */ - return !!nm_wifi_aps_find_first_compatible (&priv->aps_lst_head, connection); + return !!find_first_compatible_ap (NM_DEVICE_WIFI (device), connection, TRUE); +} + +static gboolean +is_manf_default_ssid (const GByteArray *ssid) +{ + int i; + /* + * List of manufacturer default SSIDs that are often unchanged by users. + * + * NOTE: this list should *not* contain networks that you would like to + * automatically roam to like "Starbucks" or "AT&T" or "T-Mobile HotSpot". + */ + static const char *manf_defaults[] = { + "linksys", + "linksys-a", + "linksys-g", + "default", + "belkin54g", + "NETGEAR", + "o2DSL", + "WLAN", + "ALICE-WLAN", + "Speedport W 501V", + "TURBONETT", + }; + + for (i = 0; i < G_N_ELEMENTS (manf_defaults); i++) { + if (ssid->len == strlen (manf_defaults[i])) { + if (memcmp (manf_defaults[i], ssid->data, ssid->len) == 0) + return TRUE; + } + } + return FALSE; } static gboolean complete_connection (NMDevice *device, NMConnection *connection, const char *specific_object, - NMConnection *const*existing_connections, + const GSList *existing_connections, GError **error) { NMDeviceWifi *self = NM_DEVICE_WIFI (device); - NMDeviceWifiPrivate *priv = NM_DEVICE_WIFI_GET_PRIVATE (self); NMSettingWireless *s_wifi; const char *setting_mac; char *str_ssid = NULL; @@ -744,7 +825,7 @@ complete_connection (NMDevice *device, if (!nm_streq0 (mode, NM_SETTING_WIRELESS_MODE_AP)) { /* Find a compatible AP in the scan list */ - ap = nm_wifi_aps_find_first_compatible (&priv->aps_lst_head, connection); + ap = find_first_compatible_ap (self, connection, FALSE); /* If we still don't have an AP, then the WiFI settings needs to be * fully specified by the client. Might not be able to find an AP @@ -766,7 +847,7 @@ complete_connection (NMDevice *device, return FALSE; ap = NULL; } else { - ap = nm_wifi_ap_lookup_for_device (NM_DEVICE (self), specific_object); + ap = get_ap_by_path (self, specific_object); if (!ap) { g_set_error (error, NM_DEVICE_ERROR, @@ -819,7 +900,7 @@ complete_connection (NMDevice *device, */ if (!nm_wifi_ap_complete_connection (ap, connection, - nm_wifi_utils_is_manf_default_ssid (ssid), + is_manf_default_ssid (ssid), error)) { if (tmp_ssid) g_byte_array_unref (tmp_ssid); @@ -926,7 +1007,6 @@ can_auto_connect (NMDevice *device, char **specific_object) { NMDeviceWifi *self = NM_DEVICE_WIFI (device); - NMDeviceWifiPrivate *priv = NM_DEVICE_WIFI_GET_PRIVATE (self); NMSettingWireless *s_wifi; NMWifiAP *ap; const char *method, *mode; @@ -958,20 +1038,102 @@ can_auto_connect (NMDevice *device, return FALSE; } - ap = nm_wifi_aps_find_first_compatible (&priv->aps_lst_head, connection); + ap = find_first_compatible_ap (self, connection, FALSE); if (ap) { /* All good; connection is usable */ - NM_SET_OUT (specific_object, g_strdup (nm_dbus_object_get_path (NM_DBUS_OBJECT (ap)))); + NM_SET_OUT (specific_object, g_strdup (nm_exported_object_get_path (NM_EXPORTED_OBJECT (ap)))); return TRUE; } return FALSE; } -const CList * -_nm_device_wifi_get_aps (NMDeviceWifi *self) +static int +ap_id_compare (gconstpointer p_a, gconstpointer p_b, gpointer user_data) +{ + guint64 a_id = nm_wifi_ap_get_id (*((NMWifiAP **) p_a)); + guint64 b_id = nm_wifi_ap_get_id (*((NMWifiAP **) p_b)); + + return a_id < b_id ? -1 : (a_id == b_id ? 0 : 1); +} + +static NMWifiAP ** +ap_list_get_sorted (NMDeviceWifi *self, gboolean include_without_ssid) +{ + NMDeviceWifiPrivate *priv; + NMWifiAP **list; + GHashTableIter iter; + NMWifiAP *ap; + gsize i, n; + + priv = NM_DEVICE_WIFI_GET_PRIVATE (self); + + n = g_hash_table_size (priv->aps); + list = g_new (NMWifiAP *, n + 1); + + i = 0; + if (n > 0) { + g_hash_table_iter_init (&iter, priv->aps); + while (g_hash_table_iter_next (&iter, NULL, (gpointer) &ap)) { + nm_assert (i < n); + if ( include_without_ssid + || nm_wifi_ap_get_ssid (ap)) + list[i++] = ap; + } + nm_assert (i <= n); + nm_assert (!include_without_ssid || i == n); + + g_qsort_with_data (list, + i, + sizeof (gpointer), + ap_id_compare, + NULL); + } + list[i] = NULL; + return list; +} + +static const char ** +ap_list_get_sorted_paths (NMDeviceWifi *self, gboolean include_without_ssid) { - return &NM_DEVICE_WIFI_GET_PRIVATE (self)->aps_lst_head; + gpointer *list; + gsize i, j; + + list = (gpointer *) ap_list_get_sorted (self, include_without_ssid); + for (i = 0, j = 0; list[i]; i++) { + NMWifiAP *ap = list[i]; + const char *path; + + /* update @list inplace to hold instead the export-path. */ + path = nm_exported_object_get_path (NM_EXPORTED_OBJECT (ap)); + nm_assert (path); + list[j++] = (gpointer) path; + } + return (const char **) list; +} + +static void +impl_device_wifi_get_access_points (NMDeviceWifi *self, + GDBusMethodInvocation *context) +{ + gs_free const char **list = NULL; + GVariant *v; + + list = ap_list_get_sorted_paths (self, FALSE); + v = g_variant_new_objv (list, -1); + g_dbus_method_invocation_return_value (context, g_variant_new_tuple (&v, 1)); +} + +static void +impl_device_wifi_get_all_access_points (NMDeviceWifi *self, + GDBusMethodInvocation *context) +{ + gs_free const char **list = NULL; + GVariant *v; + + list = ap_list_get_sorted_paths (self, TRUE); + v = g_variant_new_objv (list, -1); + g_dbus_method_invocation_return_value (context, g_variant_new_tuple (&v, 1)); } static void @@ -991,7 +1153,7 @@ _hw_addr_set_scanning (NMDeviceWifi *self, gboolean do_reset) priv = NM_DEVICE_WIFI_GET_PRIVATE (self); randomize = nm_config_data_get_device_config_boolean (NM_CONFIG_GET_DATA, - NM_CONFIG_KEYFILE_KEY_DEVICE_WIFI_SCAN_RAND_MAC_ADDRESS, + "wifi.scan-rand-mac-address", device, TRUE, TRUE); @@ -1077,6 +1239,7 @@ dbus_request_scan_cb (NMDevice *device, gpointer user_data) { NMDeviceWifi *self = NM_DEVICE_WIFI (device); + NMDeviceWifiPrivate *priv; gs_unref_variant GVariant *scan_options = user_data; gs_unref_ptrarray GPtrArray *ssids = NULL; @@ -1093,6 +1256,8 @@ dbus_request_scan_cb (NMDevice *device, return; } + priv = NM_DEVICE_WIFI_GET_PRIVATE (self); + if (scan_options) { gs_unref_variant GVariant *val = g_variant_lookup_value (scan_options, "ssids", NULL); @@ -1119,10 +1284,10 @@ dbus_request_scan_cb (NMDevice *device, g_dbus_method_invocation_return_value (context, NULL); } -void -_nm_device_wifi_request_scan (NMDeviceWifi *self, - GVariant *options, - GDBusMethodInvocation *invocation) +static void +impl_device_wifi_request_scan (NMDeviceWifi *self, + GDBusMethodInvocation *context, + GVariant *options) { NMDeviceWifiPrivate *priv = NM_DEVICE_WIFI_GET_PRIVATE (self); NMDevice *device = NM_DEVICE (self); @@ -1132,7 +1297,7 @@ _nm_device_wifi_request_scan (NMDeviceWifi *self, || !priv->sup_iface || nm_device_get_state (device) < NM_DEVICE_STATE_DISCONNECTED || nm_device_is_activating (device)) { - g_dbus_method_invocation_return_error_literal (invocation, + g_dbus_method_invocation_return_error_literal (context, NM_DEVICE_ERROR, NM_DEVICE_ERROR_NOT_ALLOWED, "Scanning not allowed while unavailable or activating"); @@ -1140,7 +1305,7 @@ _nm_device_wifi_request_scan (NMDeviceWifi *self, } if (nm_supplicant_interface_get_scanning (priv->sup_iface)) { - g_dbus_method_invocation_return_error_literal (invocation, + g_dbus_method_invocation_return_error_literal (context, NM_DEVICE_ERROR, NM_DEVICE_ERROR_NOT_ALLOWED, "Scanning not allowed while already scanning"); @@ -1149,16 +1314,17 @@ _nm_device_wifi_request_scan (NMDeviceWifi *self, last_scan = nm_supplicant_interface_get_last_scan_time (priv->sup_iface); if (last_scan && (nm_utils_get_monotonic_timestamp_s () - last_scan) < 10) { - g_dbus_method_invocation_return_error_literal (invocation, + g_dbus_method_invocation_return_error_literal (context, NM_DEVICE_ERROR, NM_DEVICE_ERROR_NOT_ALLOWED, "Scanning not allowed immediately following previous scan"); return; } + /* Ask the manager to authenticate this request for us */ g_signal_emit_by_name (device, NM_DEVICE_AUTH_REQUEST, - invocation, + context, NULL, NM_AUTH_PERMISSION_NETWORK_CONTROL, TRUE, @@ -1442,15 +1608,17 @@ ap_list_dump (gpointer user_data) priv->ap_dump_id = 0; if (_LOGD_ENABLED (LOGD_WIFI_SCAN)) { - NMWifiAP *ap; + gs_free NMWifiAP **list = NULL; + gsize i; gint32 now_s = nm_utils_get_monotonic_timestamp_s (); _LOGD (LOGD_WIFI_SCAN, "APs: [now:%u last:%u next:%u]", now_s, priv->last_scan, 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); + list = ap_list_get_sorted (self, TRUE); + for (i = 0; list[i]; i++) + _ap_dump (self, LOGL_DEBUG, list[i], "dump", now_s); } return G_SOURCE_REMOVE; } @@ -1521,7 +1689,7 @@ supplicant_iface_bss_updated_cb (NMSupplicantInterface *iface, if (NM_DEVICE_WIFI_GET_PRIVATE (self)->mode == NM_802_11_MODE_AP) return; - found_ap = nm_wifi_aps_find_by_supplicant_path (&priv->aps_lst_head, object_path); + found_ap = get_ap_by_supplicant_path (self, object_path); if (found_ap) { if (!nm_wifi_ap_update_from_properties (found_ap, object_path, properties)) return; @@ -1553,7 +1721,7 @@ supplicant_iface_bss_updated_cb (NMSupplicantInterface *iface, } } - ap_add_remove (self, TRUE, ap, TRUE); + ap_add_remove (self, ACCESS_POINT_ADDED, ap, TRUE); } /* Update the current AP if the supplicant notified a current BSS change @@ -1577,7 +1745,7 @@ supplicant_iface_bss_removed_cb (NMSupplicantInterface *iface, 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); + ap = get_ap_by_supplicant_path (self, object_path); if (!ap) return; @@ -1590,7 +1758,7 @@ supplicant_iface_bss_removed_cb (NMSupplicantInterface *iface, if (nm_wifi_ap_set_fake (ap, TRUE)) _ap_dump (self, LOGL_DEBUG, ap, "updated", 0); } else { - ap_add_remove (self, FALSE, ap, TRUE); + ap_add_remove (self, ACCESS_POINT_REMOVED, ap, TRUE); schedule_ap_list_dump (self); } } @@ -2121,7 +2289,7 @@ supplicant_iface_notify_current_bss (NMSupplicantInterface *iface, 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 = get_ap_by_supplicant_path (self, current_bss); if (new_ap != priv->current_ap) { const char *new_bssid = NULL; @@ -2329,7 +2497,6 @@ build_supplicant_config (NMDeviceWifi *self, NMSettingWireless *s_wireless; NMSettingWirelessSecurity *s_wireless_sec; NMSettingWirelessSecurityPmf pmf; - NMSettingWirelessSecurityFils fils; gs_free char *value = NULL; g_return_val_if_fail (priv->sup_iface, NULL); @@ -2337,9 +2504,7 @@ 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); + config = nm_supplicant_config_new (); /* Warn if AP mode may not be supported */ if ( g_strcmp0 (nm_setting_wireless_get_mode (s_wireless), NM_SETTING_WIRELESS_MODE_AP) == 0 @@ -2381,16 +2546,24 @@ build_supplicant_config (NMDeviceWifi *self, NM_SETTING_WIRELESS_SECURITY_PMF_OPTIONAL); } - /* Configure FILS (802.11ai) */ - fils = nm_setting_wireless_security_get_fils (s_wireless_sec); - if (fils == NM_SETTING_WIRELESS_SECURITY_FILS_DEFAULT) { - value = nm_config_data_get_connection_default (NM_CONFIG_GET_DATA, - "wifi-sec.fils", - NM_DEVICE (self)); - fils = _nm_utils_ascii_str_to_int64 (value, 10, - NM_SETTING_WIRELESS_SECURITY_FILS_DISABLE, - NM_SETTING_WIRELESS_SECURITY_FILS_REQUIRED, - NM_SETTING_WIRELESS_SECURITY_FILS_OPTIONAL); + /* Don't try to enable PMF on non-WPA networks */ + if (!NM_IN_STRSET (nm_setting_wireless_security_get_key_mgmt (s_wireless_sec), + "wpa-eap", + "wpa-psk")) + pmf = NM_SETTING_WIRELESS_SECURITY_PMF_DISABLE; + + /* Check if we actually support PMF */ + if (nm_supplicant_interface_get_pmf_support (priv->sup_iface) != NM_SUPPLICANT_FEATURE_YES) { + if (pmf == NM_SETTING_WIRELESS_SECURITY_PMF_REQUIRED) { + g_set_error_literal (error, NM_SUPPLICANT_ERROR, NM_SUPPLICANT_ERROR_CONFIG, + "Supplicant does not support PMF"); + goto error; + } else if (pmf == NM_SETTING_WIRELESS_SECURITY_PMF_OPTIONAL) { + /* To be on the safe side, assume no support if we can't determine + * capabilities. + */ + pmf = NM_SETTING_WIRELESS_SECURITY_PMF_DISABLE; + } } s_8021x = nm_connection_get_setting_802_1x (connection); @@ -2400,7 +2573,6 @@ build_supplicant_config (NMDeviceWifi *self, con_uuid, mtu, pmf, - fils, error)) { g_prefix_error (error, "802-11-wireless-security: "); goto error; @@ -2482,16 +2654,16 @@ act_stage1_prepare (NMDevice *device, NMDeviceStateReason *out_failure_reason) /* AP mode never uses a specific object or existing scanned AP */ if (priv->mode != NM_802_11_MODE_AP) { ap_path = nm_active_connection_get_specific_object (NM_ACTIVE_CONNECTION (req)); - ap = ap_path ? nm_wifi_ap_lookup_for_device (NM_DEVICE (self), ap_path) : NULL; + ap = ap_path ? get_ap_by_path (self, ap_path) : NULL; if (ap) goto done; - ap = nm_wifi_aps_find_first_compatible (&priv->aps_lst_head, connection); + ap = find_first_compatible_ap (self, connection, FALSE); } if (ap) { nm_active_connection_set_specific_object (NM_ACTIVE_CONNECTION (req), - nm_dbus_object_get_path (NM_DBUS_OBJECT (ap))); + nm_exported_object_get_path (NM_EXPORTED_OBJECT (ap))); goto done; } @@ -2508,11 +2680,11 @@ act_stage1_prepare (NMDevice *device, NMDeviceStateReason *out_failure_reason) nm_wifi_ap_set_address (ap, nm_device_get_hw_address (device)); g_object_freeze_notify (G_OBJECT (self)); - ap_add_remove (self, TRUE, ap, TRUE); + ap_add_remove (self, ACCESS_POINT_ADDED, ap, TRUE); g_object_thaw_notify (G_OBJECT (self)); set_current_ap (self, ap, FALSE); nm_active_connection_set_specific_object (NM_ACTIVE_CONNECTION (req), - nm_dbus_object_get_path (NM_DBUS_OBJECT (ap))); + nm_exported_object_get_path (NM_EXPORTED_OBJECT (ap))); return NM_ACT_STAGE_RETURN_SUCCESS; done: @@ -2883,10 +3055,13 @@ activation_success_handler (NMDevice *device) NMDeviceWifiPrivate *priv = NM_DEVICE_WIFI_GET_PRIVATE (self); int ifindex = nm_device_get_ifindex (device); NMActRequest *req; + NMConnection *applied_connection; req = nm_device_get_act_request (device); g_assert (req); + applied_connection = nm_act_request_get_applied_connection (req); + /* Clear any critical protocol notification in the wifi stack */ nm_platform_wifi_indicate_addressing_running (nm_device_get_platform (device), ifindex, FALSE); @@ -2924,7 +3099,7 @@ activation_success_handler (NMDevice *device) } nm_active_connection_set_specific_object (NM_ACTIVE_CONNECTION (req), - nm_dbus_object_get_path (NM_DBUS_OBJECT (priv->current_ap))); + nm_exported_object_get_path (NM_EXPORTED_OBJECT (priv->current_ap))); } periodic_update (self); @@ -3102,7 +3277,8 @@ get_property (GObject *object, guint prop_id, { NMDeviceWifi *self = NM_DEVICE_WIFI (object); NMDeviceWifiPrivate *priv = NM_DEVICE_WIFI_GET_PRIVATE (self); - const char **list; + gsize i; + char **list; switch (prop_id) { case PROP_MODE: @@ -3115,11 +3291,13 @@ get_property (GObject *object, guint prop_id, g_value_set_uint (value, priv->capabilities); break; case PROP_ACCESS_POINTS: - list = nm_wifi_aps_get_paths (&priv->aps_lst_head, TRUE); - g_value_take_boxed (value, nm_utils_strv_make_deep_copied (list)); + list = (char **) ap_list_get_sorted_paths (self, TRUE); + for (i = 0; list[i]; i++) + list[i] = g_strdup (list[i]); + g_value_take_boxed (value, list); break; case PROP_ACTIVE_ACCESS_POINT: - nm_dbus_utils_g_value_set_object_path (value, priv->current_ap); + nm_utils_g_value_set_object_path (value, priv->current_ap); break; case PROP_SCANNING: g_value_set_boolean (value, priv->is_scanning); @@ -3155,9 +3333,8 @@ nm_device_wifi_init (NMDeviceWifi *self) { NMDeviceWifiPrivate *priv = NM_DEVICE_WIFI_GET_PRIVATE (self); - c_list_init (&priv->aps_lst_head); - priv->mode = NM_802_11_MODE_INFRA; + priv->aps = g_hash_table_new (nm_str_hash, g_str_equal); } static void @@ -3215,7 +3392,9 @@ finalize (GObject *object) NMDeviceWifi *self = NM_DEVICE_WIFI (object); NMDeviceWifiPrivate *priv = NM_DEVICE_WIFI_GET_PRIVATE (self); - nm_assert (c_list_is_empty (&priv->aps_lst_head)); + nm_assert (g_hash_table_size (priv->aps) == 0); + + g_hash_table_unref (priv->aps); G_OBJECT_CLASS (nm_device_wifi_parent_class)->finalize (object); } @@ -3224,7 +3403,6 @@ static void nm_device_wifi_class_init (NMDeviceWifiClass *klass) { GObjectClass *object_class = G_OBJECT_CLASS (klass); - NMDBusObjectClass *dbus_object_class = NM_DBUS_OBJECT_CLASS (klass); NMDeviceClass *parent_class = NM_DEVICE_CLASS (klass); NM_DEVICE_CLASS_DECLARE_TYPES (klass, NM_SETTING_WIRELESS_SETTING_NAME, NM_LINK_TYPE_WIFI) @@ -3235,8 +3413,6 @@ nm_device_wifi_class_init (NMDeviceWifiClass *klass) object_class->dispose = dispose; object_class->finalize = finalize; - dbus_object_class->interface_infos = NM_DBUS_INTERFACE_INFOS (&nm_interface_info_device_wireless); - parent_class->can_auto_connect = can_auto_connect; parent_class->get_autoconnect_allowed = get_autoconnect_allowed; parent_class->is_available = is_available; @@ -3303,6 +3479,24 @@ nm_device_wifi_class_init (NMDeviceWifiClass *klass) g_object_class_install_properties (object_class, _PROPERTY_ENUMS_LAST, obj_properties); + signals[ACCESS_POINT_ADDED] = + g_signal_new (NM_DEVICE_WIFI_ACCESS_POINT_ADDED, + G_OBJECT_CLASS_TYPE (object_class), + G_SIGNAL_RUN_FIRST, + 0, + NULL, NULL, NULL, + G_TYPE_NONE, 1, + NM_TYPE_WIFI_AP); + + signals[ACCESS_POINT_REMOVED] = + g_signal_new (NM_DEVICE_WIFI_ACCESS_POINT_REMOVED, + G_OBJECT_CLASS_TYPE (object_class), + G_SIGNAL_RUN_FIRST, + 0, + NULL, NULL, NULL, + G_TYPE_NONE, 1, + NM_TYPE_WIFI_AP); + signals[SCANNING_PROHIBITED] = g_signal_new (NM_DEVICE_WIFI_SCANNING_PROHIBITED, G_OBJECT_CLASS_TYPE (object_class), @@ -3310,4 +3504,13 @@ nm_device_wifi_class_init (NMDeviceWifiClass *klass) G_STRUCT_OFFSET (NMDeviceWifiClass, scanning_prohibited), NULL, NULL, NULL, G_TYPE_BOOLEAN, 1, G_TYPE_BOOLEAN); + + nm_exported_object_class_add_interface (NM_EXPORTED_OBJECT_CLASS (klass), + NMDBUS_TYPE_DEVICE_WIFI_SKELETON, + "GetAccessPoints", impl_device_wifi_get_access_points, + "GetAllAccessPoints", impl_device_wifi_get_all_access_points, + "RequestScan", impl_device_wifi_request_scan, + NULL); } + + diff --git a/src/devices/wifi/nm-device-wifi.h b/src/devices/wifi/nm-device-wifi.h index c13b00de..09707d4f 100644 --- a/src/devices/wifi/nm-device-wifi.h +++ b/src/devices/wifi/nm-device-wifi.h @@ -23,6 +23,7 @@ #define __NETWORKMANAGER_DEVICE_WIFI_H__ #include "devices/nm-device.h" +#include "nm-wifi-ap.h" #define NM_TYPE_DEVICE_WIFI (nm_device_wifi_get_type ()) #define NM_DEVICE_WIFI(obj) (G_TYPE_CHECK_INSTANCE_CAST ((obj), NM_TYPE_DEVICE_WIFI, NMDeviceWifi)) @@ -38,6 +39,11 @@ #define NM_DEVICE_WIFI_CAPABILITIES "wireless-capabilities" #define NM_DEVICE_WIFI_SCANNING "scanning" +/* signals */ +#define NM_DEVICE_WIFI_ACCESS_POINT_ADDED "access-point-added" +#define NM_DEVICE_WIFI_ACCESS_POINT_REMOVED "access-point-removed" + +/* internal signals */ #define NM_DEVICE_WIFI_SCANNING_PROHIBITED "scanning-prohibited" typedef struct _NMDeviceWifi NMDeviceWifi; @@ -47,10 +53,4 @@ GType nm_device_wifi_get_type (void); NMDevice * nm_device_wifi_new (const char *iface, NMDeviceWifiCapabilities capabilities); -const CList *_nm_device_wifi_get_aps (NMDeviceWifi *self); - -void _nm_device_wifi_request_scan (NMDeviceWifi *self, - GVariant *options, - GDBusMethodInvocation *invocation); - #endif /* __NETWORKMANAGER_DEVICE_WIFI_H__ */ diff --git a/src/devices/wifi/nm-iwd-manager.c b/src/devices/wifi/nm-iwd-manager.c deleted file mode 100644 index 450009f0..00000000 --- a/src/devices/wifi/nm-iwd-manager.c +++ /dev/null @@ -1,694 +0,0 @@ -/* -*- Mode: C; tab-width: 4; indent-tabs-mode: t; c-basic-offset: 4 -*- */ -/* NetworkManager -- Network link manager - * - * This program is free software; you can redistribute it and/or modify - * it under the terms of the GNU General Public License as published by - * the Free Software Foundation; either version 2 of the License, or - * (at your option) any later version. - * - * This program is distributed in the hope that it will be useful, - * but WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the - * GNU General Public License for more details. - * - * You should have received a copy of the GNU General Public License along - * with this program; if not, write to the Free Software Foundation, Inc., - * 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA. - * - * Copyright (C) 2017 Intel Corporation - */ - -#include "nm-default.h" - -#include "nm-iwd-manager.h" - -#include <string.h> -#include <net/if.h> - -#include "nm-logging.h" -#include "nm-core-internal.h" -#include "nm-manager.h" -#include "nm-device-iwd.h" -#include "nm-utils/nm-random-utils.h" - -/*****************************************************************************/ - -typedef struct { - gchar *name; - NMIwdNetworkSecurity security; -} KnownNetworkData; - -typedef struct { - NMManager *manager; - GCancellable *cancellable; - gboolean running; - GDBusObjectManager *object_manager; - guint agent_id; - gchar *agent_path; - GSList *known_networks; -} NMIwdManagerPrivate; - -struct _NMIwdManager { - GObject parent; - NMIwdManagerPrivate _priv; -}; - -struct _NMIwdManagerClass { - GObjectClass parent; -}; - -G_DEFINE_TYPE (NMIwdManager, nm_iwd_manager, G_TYPE_OBJECT) - -#define NM_IWD_MANAGER_GET_PRIVATE(self) _NM_GET_PRIVATE (self, NMIwdManager, NM_IS_IWD_MANAGER) - -/*****************************************************************************/ - -#define _NMLOG_PREFIX_NAME "iwd-manager" -#define _NMLOG_DOMAIN LOGD_WIFI - -#define _NMLOG(level, ...) \ - G_STMT_START { \ - if (nm_logging_enabled (level, _NMLOG_DOMAIN)) { \ - char __prefix[32]; \ - \ - if (self) \ - g_snprintf (__prefix, sizeof (__prefix), "%s[%p]", ""_NMLOG_PREFIX_NAME"", (self)); \ - else \ - g_strlcpy (__prefix, _NMLOG_PREFIX_NAME, sizeof (__prefix)); \ - _nm_log ((level), (_NMLOG_DOMAIN), 0, NULL, NULL, \ - "%s: " _NM_UTILS_MACRO_FIRST(__VA_ARGS__), \ - __prefix _NM_UTILS_MACRO_REST(__VA_ARGS__)); \ - } \ - } G_STMT_END - -/*****************************************************************************/ - -static void -psk_agent_dbus_method_cb (GDBusConnection *connection, - const gchar *sender, const gchar *object_path, - const gchar *interface_name, const gchar *method_name, - GVariant *parameters, - GDBusMethodInvocation *invocation, - gpointer user_data) -{ - NMIwdManager *self = user_data; - NMIwdManagerPrivate *priv = NM_IWD_MANAGER_GET_PRIVATE (self); - GDBusObjectManagerClient *omc = G_DBUS_OBJECT_MANAGER_CLIENT (priv->object_manager); - const gchar *network_path, *device_path, *ifname; - gs_unref_object GDBusInterface *network = NULL, *device_obj = NULL; - gs_unref_variant GVariant *value = NULL; - gint ifindex; - NMDevice *device; - - /* Be paranoid and check the sender address */ - if (!nm_streq0 (g_dbus_object_manager_client_get_name_owner (omc), sender)) - goto return_error; - - g_variant_get (parameters, "(&o)", &network_path); - - network = g_dbus_object_manager_get_interface (priv->object_manager, - network_path, - NM_IWD_NETWORK_INTERFACE); - value = g_dbus_proxy_get_cached_property (G_DBUS_PROXY (network), "Device"); - device_path = g_variant_get_string (value, NULL); - - if (!device_path) { - _LOGE ("Device not cached for network %s in IWD Agent request", - network_path); - goto return_error; - } - - device_obj = g_dbus_object_manager_get_interface (priv->object_manager, - device_path, - NM_IWD_DEVICE_INTERFACE); - g_variant_unref (value); - value = g_dbus_proxy_get_cached_property (G_DBUS_PROXY (device_obj), "Name"); - ifname = g_variant_get_string (value, NULL); - - if (!ifname) { - _LOGE ("Name not cached for device %s in IWD Agent request", - device_path); - goto return_error; - } - - ifindex = if_nametoindex (ifname); - if (!ifindex) { - _LOGE ("if_nametoindex failed for Name %s for Device at %s: %i", - ifname, device_path, errno); - goto return_error; - } - - device = nm_manager_get_device_by_ifindex (priv->manager, ifindex); - if (!NM_IS_DEVICE_IWD (device)) { - _LOGE ("IWD device named %s is not a Wifi device in IWD Agent request", - ifname); - goto return_error; - } - - if (nm_device_iwd_agent_psk_query (NM_DEVICE_IWD (device), invocation)) - return; - - _LOGE ("Device %s did not handle the IWD Agent request", ifname); - -return_error: - /* IWD doesn't look at the specific error */ - g_dbus_method_invocation_return_error_literal (invocation, NM_DEVICE_ERROR, - NM_DEVICE_ERROR_INVALID_CONNECTION, - "No PSK available for this connection"); -} - - -static guint -psk_agent_export (GDBusConnection *connection, gpointer user_data, - gchar **agent_path, GError **error) -{ - static const GDBusArgInfo request_passphrase_arg_network = { - -1, - (gchar *) "network", - (gchar *) "o", - NULL, - }; - static const GDBusArgInfo *const request_passphrase_in_args[] = { - &request_passphrase_arg_network, - NULL, - }; - static const GDBusArgInfo request_passphrase_arg_passphrase = { - -1, - (gchar *) "passphrase", - (gchar *) "s", - NULL, - }; - static const GDBusArgInfo *const request_passphrase_out_args[] = { - &request_passphrase_arg_passphrase, - NULL, - }; - static const GDBusMethodInfo request_passphrase_info = { - -1, - (gchar *) "RequestPassphrase", - (GDBusArgInfo **) &request_passphrase_in_args, - (GDBusArgInfo **) &request_passphrase_out_args, - NULL, - }; - static const GDBusMethodInfo *const method_info[] = { - &request_passphrase_info, - NULL, - }; - static GDBusInterfaceInfo interface_info = { - -1, - (gchar *) "net.connman.iwd.Agent", - (GDBusMethodInfo **) &method_info, - NULL, - NULL, - NULL, - }; - static GDBusInterfaceVTable vtable = { - psk_agent_dbus_method_cb, - NULL, - NULL, - }; - - gchar path[50]; - unsigned int rnd; - guint id; - - if (!nm_utils_random_bytes (&rnd, sizeof (rnd))) { - g_set_error_literal (error, - NM_DEVICE_ERROR, - NM_DEVICE_ERROR_FAILED, - "Can't read urandom."); - return 0; - } - - nm_sprintf_buf (path, "/agent/%u", rnd); - - id = g_dbus_connection_register_object (connection, path, - &interface_info, &vtable, - user_data, NULL, error); - - if (id) - *agent_path = g_strdup (path); - return id; -} - -static void -register_agent (NMIwdManager *self) -{ - NMIwdManagerPrivate *priv = NM_IWD_MANAGER_GET_PRIVATE (self); - GDBusInterface *agent_manager; - - agent_manager = g_dbus_object_manager_get_interface (priv->object_manager, - "/", - NM_IWD_AGENT_MANAGER_INTERFACE); - - /* Register our agent */ - g_dbus_proxy_call (G_DBUS_PROXY (agent_manager), - "RegisterAgent", - g_variant_new ("(o)", priv->agent_path), - G_DBUS_CALL_FLAGS_NONE, -1, - NULL, NULL, NULL); - - g_object_unref (agent_manager); -} - -/*****************************************************************************/ - -static void -set_device_dbus_object (NMIwdManager *self, GDBusInterface *interface, - GDBusObject *object) -{ - NMIwdManagerPrivate *priv = NM_IWD_MANAGER_GET_PRIVATE (self); - GDBusProxy *proxy; - GVariant *value; - const char *ifname; - gint ifindex; - NMDevice *device; - - if (!priv->running) - return; - - g_return_if_fail (G_IS_DBUS_PROXY (interface)); - - proxy = G_DBUS_PROXY (interface); - - if (strcmp (g_dbus_proxy_get_interface_name (proxy), - NM_IWD_DEVICE_INTERFACE)) - return; - - value = g_dbus_proxy_get_cached_property (proxy, "Name"); - if (!value) { - _LOGE ("Name not cached for Device at %s", - g_dbus_proxy_get_object_path (proxy)); - return; - } - - ifname = g_variant_get_string (value, NULL); - ifindex = if_nametoindex (ifname); - g_variant_unref (value); - - if (!ifindex) { - _LOGE ("if_nametoindex failed for Name %s for Device at %s: %i", - ifname, g_dbus_proxy_get_object_path (proxy), errno); - return; - } - - device = nm_manager_get_device_by_ifindex (priv->manager, ifindex); - if (!NM_IS_DEVICE_IWD (device)) { - _LOGE ("IWD device named %s is not a Wifi device", ifname); - return; - } - - nm_device_iwd_set_dbus_object (NM_DEVICE_IWD (device), object); -} - -static void -interface_added (GDBusObjectManager *object_manager, GDBusObject *object, - GDBusInterface *interface, gpointer user_data) -{ - NMIwdManager *self = user_data; - - set_device_dbus_object (self, interface, object); -} - -static void -interface_removed (GDBusObjectManager *object_manager, GDBusObject *object, - GDBusInterface *interface, gpointer user_data) -{ - NMIwdManager *self = user_data; - - /* - * TODO: we may need to save the GDBusInterface or GDBusObject - * pointer in the hash table because we may be no longer able to - * access the Name property or map the name to ifindex with - * if_nametoindex at this point. - */ - - set_device_dbus_object (self, interface, NULL); -} - -static gboolean -_om_has_name_owner (GDBusObjectManager *object_manager) -{ - gs_free char *name_owner = NULL; - - nm_assert (G_IS_DBUS_OBJECT_MANAGER_CLIENT (object_manager)); - - name_owner = g_dbus_object_manager_client_get_name_owner (G_DBUS_OBJECT_MANAGER_CLIENT (object_manager)); - return !!name_owner; -} - -static void -object_added (NMIwdManager *self, GDBusObject *object) -{ - GList *interfaces, *iter; - - interfaces = g_dbus_object_get_interfaces (object); - for (iter = interfaces; iter; iter = iter->next) { - GDBusInterface *interface = G_DBUS_INTERFACE (iter->data); - - set_device_dbus_object (self, interface, object); - } - - g_list_free_full (interfaces, g_object_unref); -} - -static void -known_network_free (KnownNetworkData *network) -{ - g_free (network->name); - g_free (network); -} - -static void -list_known_networks_cb (GObject *source, GAsyncResult *res, gpointer user_data) -{ - NMIwdManager *self = user_data; - NMIwdManagerPrivate *priv = NM_IWD_MANAGER_GET_PRIVATE (self); - gs_free_error GError *error = NULL; - gs_unref_variant GVariant *variant = NULL; - GVariantIter *networks, *props; - - variant = _nm_dbus_proxy_call_finish (G_DBUS_PROXY (source), res, - G_VARIANT_TYPE ("(aa{sv})"), - &error); - if (!variant) { - _LOGE ("ListKnownNetworks() failed: %s", error->message); - return; - } - - g_slist_free_full (priv->known_networks, (GDestroyNotify) known_network_free); - priv->known_networks = NULL; - - g_variant_get (variant, "(aa{sv})", &networks); - - while (g_variant_iter_next (networks, "a{sv}", &props)) { - const gchar *key; - const gchar *name = NULL; - const gchar *type = NULL; - GVariant *val; - KnownNetworkData *network_data; - - while (g_variant_iter_next (props, "{&sv}", &key, &val)) { - if (!strcmp (key, "Name")) - name = g_variant_get_string (val, NULL); - - if (!strcmp (key, "Type")) - type = g_variant_get_string (val, NULL); - - g_variant_unref (val); - } - - if (!name || !type) - goto next; - - network_data = g_new (KnownNetworkData, 1); - network_data->name = g_strdup (name); - if (!strcmp (type, "open")) - network_data->security = NM_IWD_NETWORK_SECURITY_NONE; - else if (!strcmp (type, "psk")) - network_data->security = NM_IWD_NETWORK_SECURITY_PSK; - else if (!strcmp (type, "8021x")) - network_data->security = NM_IWD_NETWORK_SECURITY_8021X; - - priv->known_networks = g_slist_append (priv->known_networks, - network_data); - -next: - g_variant_iter_free (props); - } - - g_variant_iter_free (networks); - - /* For completness we may want to call nm_device_emit_recheck_auto_activate - * and nm_device_recheck_available_connections for all affected devices - * now but the ListKnownNetworks call should have been really fast, - * faster than any scan on any newly created devices could have happened. - */ -} - -static void -update_known_networks (NMIwdManager *self) -{ - NMIwdManagerPrivate *priv = NM_IWD_MANAGER_GET_PRIVATE (self); - GDBusInterface *known_networks_if; - - known_networks_if = g_dbus_object_manager_get_interface (priv->object_manager, - "/", - NM_IWD_KNOWN_NETWORKS_INTERFACE); - - g_dbus_proxy_call (G_DBUS_PROXY (known_networks_if), - "ListKnownNetworks", - g_variant_new ("()"), - G_DBUS_CALL_FLAGS_NONE, -1, - priv->cancellable, list_known_networks_cb, self); - - g_object_unref (known_networks_if); -} - -static void prepare_object_manager (NMIwdManager *self); - -static void -name_owner_changed (GObject *object, GParamSpec *pspec, gpointer user_data) -{ - NMIwdManager *self = user_data; - NMIwdManagerPrivate *priv = NM_IWD_MANAGER_GET_PRIVATE (self); - GDBusObjectManager *object_manager = G_DBUS_OBJECT_MANAGER (object); - - nm_assert (object_manager == priv->object_manager); - - if (_om_has_name_owner (object_manager)) { - g_signal_handlers_disconnect_by_data (object_manager, self); - g_clear_object (&priv->object_manager); - prepare_object_manager (self); - } else { - const CList *tmp_lst; - NMDevice *device; - - if (!priv->running) - return; - - priv->running = false; - - nm_manager_for_each_device (priv->manager, device, tmp_lst) { - if (NM_IS_DEVICE_IWD (device)) { - nm_device_iwd_set_dbus_object (NM_DEVICE_IWD (device), - NULL); - } - } - } -} - -static void -device_added (NMManager *manager, NMDevice *device, gpointer user_data) -{ - NMIwdManager *self = user_data; - NMIwdManagerPrivate *priv = NM_IWD_MANAGER_GET_PRIVATE (self); - GList *objects, *iter; - - if (!NM_IS_DEVICE_IWD (device)) - return; - - if (!priv->running) - return; - - objects = g_dbus_object_manager_get_objects (priv->object_manager); - for (iter = objects; iter; iter = iter->next) { - GDBusObject *object = G_DBUS_OBJECT (iter->data); - GDBusInterface *interface; - GDBusProxy *proxy; - GVariant *value; - const char *obj_ifname; - - interface = g_dbus_object_get_interface (object, - NM_IWD_DEVICE_INTERFACE); - if (!interface) - continue; - - proxy = G_DBUS_PROXY (interface); - value = g_dbus_proxy_get_cached_property (proxy, "Name"); - if (!value) { - g_object_unref (interface); - continue; - } - - obj_ifname = g_variant_get_string (value, NULL); - g_variant_unref (value); - g_object_unref (interface); - - if (strcmp (nm_device_get_iface (device), obj_ifname)) - continue; - - nm_device_iwd_set_dbus_object (NM_DEVICE_IWD (device), object); - break; - } - - g_list_free_full (objects, g_object_unref); -} - -static void -got_object_manager (GObject *object, GAsyncResult *result, gpointer user_data) -{ - NMIwdManager *self = user_data; - NMIwdManagerPrivate *priv = NM_IWD_MANAGER_GET_PRIVATE (self); - GError *error = NULL; - GDBusObjectManager *object_manager; - GDBusConnection *connection; - - object_manager = g_dbus_object_manager_client_new_for_bus_finish (result, &error); - if (object_manager == NULL) { - _LOGE ("failed to acquire IWD Object Manager: Wi-Fi will not be available (%s)", - NM_G_ERROR_MSG (error)); - g_clear_error (&error); - return; - } - - priv->object_manager = object_manager; - - g_signal_connect (priv->object_manager, "notify::name-owner", - G_CALLBACK (name_owner_changed), self); - - nm_assert (G_IS_DBUS_OBJECT_MANAGER_CLIENT (object_manager)); - - connection = g_dbus_object_manager_client_get_connection (G_DBUS_OBJECT_MANAGER_CLIENT (object_manager)); - - priv->agent_id = psk_agent_export (connection, self, - &priv->agent_path, &error); - if (!priv->agent_id) { - _LOGE ("failed to export the IWD Agent: PSK/8021x WiFi networks will not work: %s", - NM_G_ERROR_MSG (error)); - g_clear_error (&error); - } - - if (_om_has_name_owner (object_manager)) { - GList *objects, *iter; - - priv->running = true; - - g_signal_connect (priv->object_manager, "interface-added", - G_CALLBACK (interface_added), self); - g_signal_connect (priv->object_manager, "interface-removed", - G_CALLBACK (interface_removed), self); - - objects = g_dbus_object_manager_get_objects (object_manager); - for (iter = objects; iter; iter = iter->next) - object_added (self, G_DBUS_OBJECT (iter->data)); - - g_list_free_full (objects, g_object_unref); - - if (priv->agent_id) - register_agent (self); - - update_known_networks (self); - } -} - -static void -prepare_object_manager (NMIwdManager *self) -{ - NMIwdManagerPrivate *priv = NM_IWD_MANAGER_GET_PRIVATE (self); - - g_dbus_object_manager_client_new_for_bus (NM_IWD_BUS_TYPE, - G_DBUS_OBJECT_MANAGER_CLIENT_FLAGS_DO_NOT_AUTO_START, - NM_IWD_SERVICE, "/", - NULL, NULL, NULL, - priv->cancellable, - got_object_manager, self); -} - -gboolean -nm_iwd_manager_is_known_network (NMIwdManager *self, const gchar *name, - NMIwdNetworkSecurity security) -{ - NMIwdManagerPrivate *priv = NM_IWD_MANAGER_GET_PRIVATE (self); - const GSList *iter; - - for (iter = priv->known_networks; iter; iter = g_slist_next (iter)) { - const KnownNetworkData *network = iter->data; - - if (!strcmp (network->name, name) && network->security == security) - return true; - } - - return false; -} - -void -nm_iwd_manager_network_connected (NMIwdManager *self, const gchar *name, - NMIwdNetworkSecurity security) -{ - NMIwdManagerPrivate *priv = NM_IWD_MANAGER_GET_PRIVATE (self); - KnownNetworkData *network_data; - - if (nm_iwd_manager_is_known_network (self, name, security)) - return; - - network_data = g_new (KnownNetworkData, 1); - network_data->name = g_strdup (name); - network_data->security = security; - priv->known_networks = g_slist_append (priv->known_networks, network_data); -} - -/*****************************************************************************/ - -NM_DEFINE_SINGLETON_GETTER (NMIwdManager, nm_iwd_manager_get, - NM_TYPE_IWD_MANAGER); - -static void -nm_iwd_manager_init (NMIwdManager *self) -{ - NMIwdManagerPrivate *priv = NM_IWD_MANAGER_GET_PRIVATE (self); - - priv->manager = g_object_ref (nm_manager_get ()); - g_signal_connect (priv->manager, NM_MANAGER_DEVICE_ADDED, - G_CALLBACK (device_added), self); - - priv->cancellable = g_cancellable_new (); - - prepare_object_manager (self); -} - -static void -dispose (GObject *object) -{ - NMIwdManager *self = (NMIwdManager *) object; - NMIwdManagerPrivate *priv = NM_IWD_MANAGER_GET_PRIVATE (self); - - if (priv->object_manager) { - if (priv->agent_id) { - GDBusConnection *connection; - GDBusObjectManagerClient *omc = G_DBUS_OBJECT_MANAGER_CLIENT (priv->object_manager); - - /* No need to unregister the agent as IWD will detect - * our DBus connection being closed. - */ - - connection = g_dbus_object_manager_client_get_connection (omc); - - g_dbus_connection_unregister_object (connection, priv->agent_id); - priv->agent_id = 0; - } - - g_clear_object (&priv->object_manager); - } - - nm_clear_g_free (&priv->agent_path); - - nm_clear_g_cancellable (&priv->cancellable); - - g_slist_free_full (priv->known_networks, (GDestroyNotify) known_network_free); - priv->known_networks = NULL; - - if (priv->manager) { - g_signal_handlers_disconnect_by_data (priv->manager, self); - g_clear_object (&priv->manager); - } - - G_OBJECT_CLASS (nm_iwd_manager_parent_class)->dispose (object); -} - -static void -nm_iwd_manager_class_init (NMIwdManagerClass *klass) -{ - GObjectClass *object_class = G_OBJECT_CLASS (klass); - - object_class->dispose = dispose; -} diff --git a/src/devices/wifi/nm-iwd-manager.h b/src/devices/wifi/nm-iwd-manager.h deleted file mode 100644 index 8e6b66ff..00000000 --- a/src/devices/wifi/nm-iwd-manager.h +++ /dev/null @@ -1,65 +0,0 @@ -/* -*- Mode: C; tab-width: 4; indent-tabs-mode: t; c-basic-offset: 4 -*- */ -/* NetworkManager -- Network link manager - * - * This program is free software; you can redistribute it and/or modify - * it under the terms of the GNU General Public License as published by - * the Free Software Foundation; either version 2 of the License, or - * (at your option) any later version. - * - * This program is distributed in the hope that it will be useful, - * but WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the - * GNU General Public License for more details. - * - * You should have received a copy of the GNU General Public License along - * with this program; if not, write to the Free Software Foundation, Inc., - * 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA. - * - * Copyright (C) 2017 Intel Corporation - */ - -#ifndef __NETWORKMANAGER_IWD_MANAGER_H__ -#define __NETWORKMANAGER_IWD_MANAGER_H__ - -#include "devices/nm-device.h" - -#define NM_IWD_BUS_TYPE G_BUS_TYPE_SYSTEM -#define NM_IWD_SERVICE "net.connman.iwd" - -#define NM_IWD_AGENT_MANAGER_INTERFACE "net.connman.iwd.AgentManager" -#define NM_IWD_WIPHY_INTERFACE "net.connman.iwd.Adapter" -#define NM_IWD_DEVICE_INTERFACE "net.connman.iwd.Device" -#define NM_IWD_NETWORK_INTERFACE "net.connman.iwd.Network" -#define NM_IWD_AGENT_INTERFACE "net.connman.iwd.Agent" -#define NM_IWD_WSC_INTERFACE \ - "net.connman.iwd.WiFiSimpleConfiguration" -#define NM_IWD_KNOWN_NETWORKS_INTERFACE "net.connman.iwd.KnownNetworks" -#define NM_IWD_SIGNAL_AGENT_INTERFACE "net.connman.iwd.SignalLevelAgent" - -typedef enum { - NM_IWD_NETWORK_SECURITY_NONE, - NM_IWD_NETWORK_SECURITY_WEP, - NM_IWD_NETWORK_SECURITY_PSK, - NM_IWD_NETWORK_SECURITY_8021X, -} NMIwdNetworkSecurity; - -#define NM_TYPE_IWD_MANAGER (nm_iwd_manager_get_type ()) -#define NM_IWD_MANAGER(obj) (G_TYPE_CHECK_INSTANCE_CAST ((obj), NM_TYPE_IWD_MANAGER, NMIwdManager)) -#define NM_IWD_MANAGER_CLASS(klass) (G_TYPE_CHECK_CLASS_CAST ((klass), NM_TYPE_IWD_MANAGER, NMIwdManagerClass)) -#define NM_IS_IWD_MANAGER(obj) (G_TYPE_CHECK_INSTANCE_TYPE ((obj), NM_TYPE_IWD_MANAGER)) -#define NM_IS_IWD_MANAGER_CLASS(klass) (G_TYPE_CHECK_CLASS_TYPE ((klass), NM_TYPE_IWD_MANAGER)) -#define NM_IWD_MANAGER_GET_CLASS(obj) (G_TYPE_INSTANCE_GET_CLASS ((obj), NM_TYPE_IWD_MANAGER, NMIwdManagerClass)) - -typedef struct _NMIwdManager NMIwdManager; -typedef struct _NMIwdManagerClass NMIwdManagerClass; - -GType nm_iwd_manager_get_type (void); - -NMIwdManager *nm_iwd_manager_get (void); - -gboolean nm_iwd_manager_is_known_network (NMIwdManager *self, const gchar *name, - NMIwdNetworkSecurity security); -void nm_iwd_manager_network_connected (NMIwdManager *self, const gchar *name, - NMIwdNetworkSecurity security); - -#endif /* __NETWORKMANAGER_IWD_MANAGER_H__ */ diff --git a/src/devices/wifi/nm-wifi-ap.c b/src/devices/wifi/nm-wifi-ap.c index dd6d1deb..bc823af0 100644 --- a/src/devices/wifi/nm-wifi-ap.c +++ b/src/devices/wifi/nm-wifi-ap.c @@ -21,20 +21,19 @@ #include "nm-default.h" -#include "nm-wifi-ap.h" - #include <string.h> #include <stdlib.h> -#include "nm-setting-wireless.h" - +#include "nm-wifi-ap.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-dbus-manager.h" + +#include "nm-setting-wireless.h" + +#include "introspection/org.freedesktop.NetworkManager.AccessPoint.h" #define PROTO_WPA "wpa" #define PROTO_RSN "rsn" @@ -54,7 +53,7 @@ NM_GOBJECT_PROPERTIES_DEFINE (NMWifiAP, PROP_LAST_SEEN, ); -struct _NMWifiAPPrivate { +typedef struct { char *supplicant_path; /* D-Bus object path of this AP from wpa_supplicant */ /* Scanned or cached values */ @@ -73,17 +72,20 @@ struct _NMWifiAPPrivate { 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()) */ -}; +} NMWifiAPPrivate; -typedef struct _NMWifiAPPrivate NMWifiAPPrivate; +struct _NMWifiAP { + NMExportedObject parent; + NMWifiAPPrivate _priv; +}; struct _NMWifiAPClass { - NMDBusObjectClass parent; + NMExportedObjectClass parent; }; -G_DEFINE_TYPE (NMWifiAP, nm_wifi_ap, NM_TYPE_DBUS_OBJECT) +G_DEFINE_TYPE (NMWifiAP, nm_wifi_ap, NM_TYPE_EXPORTED_OBJECT) -#define NM_WIFI_AP_GET_PRIVATE(self) _NM_GET_PRIVATE_PTR(self, NMWifiAP, NM_IS_WIFI_AP) +#define NM_WIFI_AP_GET_PRIVATE(self) _NM_GET_PRIVATE(self, NMWifiAP, NM_IS_WIFI_AP) /*****************************************************************************/ @@ -95,24 +97,30 @@ nm_wifi_ap_get_supplicant_path (NMWifiAP *ap) return NM_WIFI_AP_GET_PRIVATE (ap)->supplicant_path; } -const GByteArray * -nm_wifi_ap_get_ssid (const NMWifiAP *ap) +guint64 +nm_wifi_ap_get_id (NMWifiAP *ap) { - g_return_val_if_fail (NM_IS_WIFI_AP (ap), NULL); + const char *path; + guint64 i; - return NM_WIFI_AP_GET_PRIVATE (ap)->ssid; + g_return_val_if_fail (NM_IS_WIFI_AP (ap), 0); + + path = nm_exported_object_get_path (NM_EXPORTED_OBJECT (ap)); + g_return_val_if_fail (path, 0); + + nm_assert (g_str_has_prefix (path, NM_DBUS_PATH_ACCESS_POINT"/")); + + i = _nm_utils_ascii_str_to_int64 (&path[NM_STRLEN (NM_DBUS_PATH_ACCESS_POINT"/")], 10, 1, G_MAXINT64, 0); + + nm_assert (i); + return i; } -static GVariant * -nm_wifi_ap_get_ssid_as_variant (const NMWifiAP *self) +const GByteArray * nm_wifi_ap_get_ssid (const NMWifiAP *ap) { - const NMWifiAPPrivate *priv = NM_WIFI_AP_GET_PRIVATE (self); + g_return_val_if_fail (NM_IS_WIFI_AP (ap), NULL); - if (priv->ssid) { - return g_variant_new_fixed_array (G_VARIANT_TYPE_BYTE, - priv->ssid->data, priv->ssid->len, 1); - } else - return g_variant_new_array (G_VARIANT_TYPE_BYTE, NULL, 0); + return NM_WIFI_AP_GET_PRIVATE (ap)->ssid; } gboolean @@ -322,7 +330,7 @@ guint32 nm_wifi_ap_get_max_bitrate (NMWifiAP *ap) { g_return_val_if_fail (NM_IS_WIFI_AP (ap), 0); - g_return_val_if_fail (nm_dbus_object_is_exported (NM_DBUS_OBJECT (ap)), 0); + g_return_val_if_fail (nm_exported_object_is_exported (NM_EXPORTED_OBJECT (ap)), 0); return NM_WIFI_AP_GET_PRIVATE (ap)->max_bitrate; } @@ -407,9 +415,7 @@ security_from_vardict (GVariant *security) && array) { if (g_strv_contains (array, "wpa-psk")) flags |= NM_802_11_AP_SEC_KEY_MGMT_PSK; - if (g_strv_contains (array, "wpa-eap") || - g_strv_contains (array, "wpa-fils-sha256") || - g_strv_contains (array, "wpa-fils-sha384")) + if (g_strv_contains (array, "wpa-eap")) flags |= NM_802_11_AP_SEC_KEY_MGMT_802_1X; g_free (array); } @@ -630,7 +636,7 @@ get_max_rate_vht_160_ss3 (int mcs) static gboolean get_max_rate_ht (const guint8 *bytes, guint len, guint32 *out_maxrate) { - guint32 i; + guint32 mcs, i; guint8 ht_cap_info; const guint8 *supported_mcs_set; guint32 rate; @@ -647,6 +653,7 @@ get_max_rate_ht (const guint8 *bytes, guint len, guint32 *out_maxrate) *out_maxrate = 0; /* Find the maximum supported mcs rate */ + mcs = -1; for (i = 0; i <= 76; i++) { unsigned int mcs_octet = i / 8; unsigned int MCS_RATE_BIT = 1 << i % 8; @@ -970,7 +977,7 @@ nm_wifi_ap_to_string (const NMWifiAP *self, if (priv->supplicant_path) supplicant_id = strrchr (priv->supplicant_path, '/') ?: supplicant_id; - export_path = nm_dbus_object_get_path (NM_DBUS_OBJECT (self)); + export_path = nm_exported_object_get_path (NM_EXPORTED_OBJECT (self)); if (export_path) export_path = strrchr (export_path, '/') ?: export_path; else @@ -1112,8 +1119,8 @@ static void get_property (GObject *object, guint prop_id, GValue *value, GParamSpec *pspec) { - NMWifiAP *self = NM_WIFI_AP (object); - NMWifiAPPrivate *priv = NM_WIFI_AP_GET_PRIVATE (self); + NMWifiAPPrivate *priv = NM_WIFI_AP_GET_PRIVATE ((NMWifiAP *) object); + GVariant *ssid; switch (prop_id) { case PROP_FLAGS: @@ -1126,7 +1133,12 @@ get_property (GObject *object, guint prop_id, g_value_set_uint (value, priv->rsn_flags); break; case PROP_SSID: - g_value_take_variant (value, nm_wifi_ap_get_ssid_as_variant (self)); + if (priv->ssid) { + ssid = g_variant_new_fixed_array (G_VARIANT_TYPE_BYTE, + priv->ssid->data, priv->ssid->len, 1); + } else + ssid = g_variant_new_array (G_VARIANT_TYPE_BYTE, NULL, 0); + g_value_take_variant (value, ssid); break; case PROP_FREQUENCY: g_value_set_uint (value, priv->freq); @@ -1158,15 +1170,9 @@ get_property (GObject *object, guint prop_id, /*****************************************************************************/ static void -nm_wifi_ap_init (NMWifiAP *self) +nm_wifi_ap_init (NMWifiAP *ap) { - NMWifiAPPrivate *priv; - - priv = G_TYPE_INSTANCE_GET_PRIVATE (self, NM_TYPE_WIFI_AP, NMWifiAPPrivate); - - self->_priv = priv; - - c_list_init (&self->aps_lst); + NMWifiAPPrivate *priv = NM_WIFI_AP_GET_PRIVATE (ap); priv->mode = NM_802_11_MODE_INFRA; priv->flags = NM_802_11_AP_FLAGS_NONE; @@ -1326,11 +1332,7 @@ error: static void finalize (GObject *object) { - NMWifiAP *self = NM_WIFI_AP (object); - NMWifiAPPrivate *priv = NM_WIFI_AP_GET_PRIVATE (self); - - nm_assert (!self->wifi_device); - nm_assert (c_list_is_empty (&self->aps_lst)); + NMWifiAPPrivate *priv = NM_WIFI_AP_GET_PRIVATE ((NMWifiAP *) object); g_free (priv->supplicant_path); if (priv->ssid) @@ -1340,28 +1342,6 @@ finalize (GObject *object) G_OBJECT_CLASS (nm_wifi_ap_parent_class)->finalize (object); } -static const NMDBusInterfaceInfoExtended interface_info_access_point = { - .parent = NM_DEFINE_GDBUS_INTERFACE_INFO_INIT ( - NM_DBUS_INTERFACE_ACCESS_POINT, - .signals = NM_DEFINE_GDBUS_SIGNAL_INFOS ( - &nm_signal_info_property_changed_legacy, - ), - .properties = NM_DEFINE_GDBUS_PROPERTY_INFOS ( - NM_DEFINE_DBUS_PROPERTY_INFO_EXTENDED_READABLE_L ("Flags", "u", NM_WIFI_AP_FLAGS), - NM_DEFINE_DBUS_PROPERTY_INFO_EXTENDED_READABLE_L ("WpaFlags", "u", NM_WIFI_AP_WPA_FLAGS), - NM_DEFINE_DBUS_PROPERTY_INFO_EXTENDED_READABLE_L ("RsnFlags", "u", NM_WIFI_AP_RSN_FLAGS), - NM_DEFINE_DBUS_PROPERTY_INFO_EXTENDED_READABLE_L ("Ssid", "ay", NM_WIFI_AP_SSID), - NM_DEFINE_DBUS_PROPERTY_INFO_EXTENDED_READABLE_L ("Frequency", "u", NM_WIFI_AP_FREQUENCY), - NM_DEFINE_DBUS_PROPERTY_INFO_EXTENDED_READABLE_L ("HwAddress", "s", NM_WIFI_AP_HW_ADDRESS), - NM_DEFINE_DBUS_PROPERTY_INFO_EXTENDED_READABLE_L ("Mode", "u", NM_WIFI_AP_MODE), - NM_DEFINE_DBUS_PROPERTY_INFO_EXTENDED_READABLE_L ("MaxBitrate", "u", NM_WIFI_AP_MAX_BITRATE), - NM_DEFINE_DBUS_PROPERTY_INFO_EXTENDED_READABLE_L ("Strength", "y", NM_WIFI_AP_STRENGTH), - NM_DEFINE_DBUS_PROPERTY_INFO_EXTENDED_READABLE_L ("LastSeen", "i", NM_WIFI_AP_LAST_SEEN), - ), - ), - .legacy_property_changed = TRUE, -}; - static void nm_wifi_ap_class_init (NMWifiAPClass *ap_class) { @@ -1379,12 +1359,9 @@ nm_wifi_ap_class_init (NMWifiAPClass *ap_class) | NM_802_11_AP_SEC_KEY_MGMT_802_1X ) GObjectClass *object_class = G_OBJECT_CLASS (ap_class); - NMDBusObjectClass *dbus_object_class = NM_DBUS_OBJECT_CLASS (ap_class); - - g_type_class_add_private (object_class, sizeof (NMWifiAPPrivate)); + NMExportedObjectClass *exported_object_class = NM_EXPORTED_OBJECT_CLASS (ap_class); - dbus_object_class->export_path = NM_DBUS_EXPORT_PATH_NUMBERED (NM_DBUS_PATH_ACCESS_POINT); - dbus_object_class->interface_infos = NM_DBUS_INTERFACE_INFOS (&interface_info_access_point); + exported_object_class->export_path = NM_EXPORT_PATH_NUMBERED (NM_DBUS_PATH_ACCESS_POINT); object_class->get_property = get_property; object_class->finalize = finalize; @@ -1447,85 +1424,9 @@ nm_wifi_ap_class_init (NMWifiAPClass *ap_class) G_PARAM_READABLE | G_PARAM_STATIC_STRINGS); g_object_class_install_properties (object_class, _PROPERTY_ENUMS_LAST, obj_properties); -} - -/*****************************************************************************/ -const char ** -nm_wifi_aps_get_paths (const CList *aps_lst_head, gboolean include_without_ssid) -{ - NMWifiAP *ap; - gsize i, n; - const char **list; - const char *path; - - n = c_list_length (aps_lst_head); - list = g_new (const char *, n + 1); - - i = 0; - if (n > 0) { - c_list_for_each_entry (ap, aps_lst_head, aps_lst) { - nm_assert (i < n); - if ( !include_without_ssid - && !nm_wifi_ap_get_ssid (ap)) - continue; - - path = nm_dbus_object_get_path (NM_DBUS_OBJECT (ap)); - nm_assert (path); - - list[i++] = path; - } - nm_assert (i <= n); - nm_assert (!include_without_ssid || i == n); - } - list[i] = NULL; - return list; + nm_exported_object_class_add_interface (NM_EXPORTED_OBJECT_CLASS (ap_class), + NMDBUS_TYPE_ACCESS_POINT_SKELETON, + NULL); } -NMWifiAP * -nm_wifi_aps_find_first_compatible (const CList *aps_lst_head, - NMConnection *connection) -{ - NMWifiAP *ap; - - g_return_val_if_fail (connection, NULL); - - c_list_for_each_entry (ap, aps_lst_head, aps_lst) { - if (nm_wifi_ap_check_compatible (ap, connection)) - return ap; - } - return NULL; -} - -NMWifiAP * -nm_wifi_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 * -nm_wifi_ap_lookup_for_device (NMDevice *device, const char *exported_path) -{ - NMWifiAP *ap; - - g_return_val_if_fail (NM_IS_DEVICE (device), NULL); - - ap = (NMWifiAP *) nm_dbus_manager_lookup_object (nm_dbus_object_get_manager (NM_DBUS_OBJECT (device)), - exported_path); - if ( !ap - || !NM_IS_WIFI_AP (ap) - || ap->wifi_device != device) - return NULL; - - return ap; -} diff --git a/src/devices/wifi/nm-wifi-ap.h b/src/devices/wifi/nm-wifi-ap.h index 4fdeee93..dd5a4ad1 100644 --- a/src/devices/wifi/nm-wifi-ap.h +++ b/src/devices/wifi/nm-wifi-ap.h @@ -22,7 +22,7 @@ #ifndef __NM_WIFI_AP_H__ #define __NM_WIFI_AP_H__ -#include "nm-dbus-object.h" +#include "nm-exported-object.h" #include "nm-dbus-interface.h" #include "nm-connection.h" @@ -44,13 +44,7 @@ #define NM_WIFI_AP_STRENGTH "strength" #define NM_WIFI_AP_LAST_SEEN "last-seen" -typedef struct { - NMDBusObject parent; - NMDevice *wifi_device; - CList aps_lst; - struct _NMWifiAPPrivate *_priv; -} NMWifiAP; - +typedef struct _NMWifiAP NMWifiAP; typedef struct _NMWifiAPClass NMWifiAPClass; GType nm_wifi_ap_get_type (void); @@ -72,6 +66,7 @@ gboolean nm_wifi_ap_complete_connection (NMWifiAP *self, GError **error); const char * nm_wifi_ap_get_supplicant_path (NMWifiAP *ap); +guint64 nm_wifi_ap_get_id (NMWifiAP *ap); const GByteArray *nm_wifi_ap_get_ssid (const NMWifiAP *ap); gboolean nm_wifi_ap_set_ssid (NMWifiAP *ap, const guint8 *ssid, @@ -100,14 +95,4 @@ const char *nm_wifi_ap_to_string (const NMWifiAP *self, gulong buf_len, gint32 now_s); -const char **nm_wifi_aps_get_paths (const CList *aps_lst_head, - gboolean include_without_ssid); - -NMWifiAP *nm_wifi_aps_find_first_compatible (const CList *aps_lst_head, - NMConnection *connection); - -NMWifiAP *nm_wifi_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-common.c b/src/devices/wifi/nm-wifi-common.c deleted file mode 100644 index 47c0ce67..00000000 --- a/src/devices/wifi/nm-wifi-common.c +++ /dev/null @@ -1,205 +0,0 @@ -/*-*- Mode: C; tab-width: 4; indent-tabs-mode: t; c-basic-offset: 4 -*- */ -/* - * This library is free software; you can redistribute it and/or - * modify it under the terms of the GNU Lesser General Public - * License as published by the Free Software Foundation; either - * version 2 of the License, or (at your option) any later version. - * - * This library is distributed in the hope that it will be useful, - * but WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU - * Lesser General Public License for more details. - * - * You should have received a copy of the GNU Lesser General Public - * License along with this library; if not, write to the - * Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor, - * Boston, MA 02110-1301 USA. - * - * (C) Copyright 2018 Red Hat, Inc. - */ - -#include "nm-default.h" - -#include "nm-wifi-common.h" - -#include "devices/nm-device.h" -#include "nm-wifi-ap.h" -#include "nm-device-wifi.h" -#include "nm-dbus-manager.h" - -#if WITH_IWD -#include "nm-device-iwd.h" -#endif - -/*****************************************************************************/ - -void -nm_device_wifi_emit_signal_access_point (NMDevice *device, - NMWifiAP *ap, - gboolean is_added /* or else is_removed */) -{ - nm_dbus_object_emit_signal (NM_DBUS_OBJECT (device), - &nm_interface_info_device_wireless, - is_added - ? &nm_signal_info_wireless_access_point_added - : &nm_signal_info_wireless_access_point_removed, - "(o)", - nm_dbus_object_get_path (NM_DBUS_OBJECT (ap))); -} - -/*****************************************************************************/ - -static const CList * -_dispatch_get_aps (NMDevice *device) -{ -#if WITH_IWD - if (NM_IS_DEVICE_IWD (device)) - return _nm_device_iwd_get_aps (NM_DEVICE_IWD (device)); -#endif - return _nm_device_wifi_get_aps (NM_DEVICE_WIFI (device)); -} - -static void -_dispatch_request_scan (NMDevice *device, - GVariant *options, - GDBusMethodInvocation *invocation) -{ -#if WITH_IWD - if (NM_IS_DEVICE_IWD (device)) { - _nm_device_iwd_request_scan (NM_DEVICE_IWD (device), - options, - invocation); - } -#endif - _nm_device_wifi_request_scan (NM_DEVICE_WIFI (device), - options, - invocation); -} - -static void -impl_device_wifi_get_access_points (NMDBusObject *obj, - const NMDBusInterfaceInfoExtended *interface_info, - const NMDBusMethodInfoExtended *method_info, - GDBusConnection *connection, - const char *sender, - GDBusMethodInvocation *invocation, - GVariant *parameters) -{ - gs_free const char **list = NULL; - GVariant *v; - const CList *all_aps; - - /* NOTE: this handler is called both for NMDevicwWifi and NMDeviceIwd. */ - - all_aps = _dispatch_get_aps (NM_DEVICE (obj)); - list = nm_wifi_aps_get_paths (all_aps, FALSE); - v = g_variant_new_objv (list, -1); - g_dbus_method_invocation_return_value (invocation, - g_variant_new_tuple (&v, 1)); -} - -static void -impl_device_wifi_get_all_access_points (NMDBusObject *obj, - const NMDBusInterfaceInfoExtended *interface_info, - const NMDBusMethodInfoExtended *method_info, - GDBusConnection *connection, - const char *sender, - GDBusMethodInvocation *invocation, - GVariant *parameters) -{ - gs_free const char **list = NULL; - GVariant *v; - const CList *all_aps; - - /* NOTE: this handler is called both for NMDevicwWifi and NMDeviceIwd. */ - - all_aps = _dispatch_get_aps (NM_DEVICE (obj)); - list = nm_wifi_aps_get_paths (all_aps, TRUE); - v = g_variant_new_objv (list, -1); - g_dbus_method_invocation_return_value (invocation, - g_variant_new_tuple (&v, 1)); -} - -static void -impl_device_wifi_request_scan (NMDBusObject *obj, - const NMDBusInterfaceInfoExtended *interface_info, - const NMDBusMethodInfoExtended *method_info, - GDBusConnection *connection, - const char *sender, - GDBusMethodInvocation *invocation, - GVariant *parameters) -{ - gs_unref_variant GVariant *options = NULL; - - /* NOTE: this handler is called both for NMDevicwWifi and NMDeviceIwd. */ - - g_variant_get (parameters, "(@a{sv})", &options); - - _dispatch_request_scan (NM_DEVICE (obj), - options, - invocation); -} - -const GDBusSignalInfo nm_signal_info_wireless_access_point_added = NM_DEFINE_GDBUS_SIGNAL_INFO_INIT ( - "AccessPointAdded", - .args = NM_DEFINE_GDBUS_ARG_INFOS ( - NM_DEFINE_GDBUS_ARG_INFO ("access_point", "o"), - ), -); - -const GDBusSignalInfo nm_signal_info_wireless_access_point_removed = NM_DEFINE_GDBUS_SIGNAL_INFO_INIT ( - "AccessPointRemoved", - .args = NM_DEFINE_GDBUS_ARG_INFOS ( - NM_DEFINE_GDBUS_ARG_INFO ("access_point", "o"), - ), -); - -const NMDBusInterfaceInfoExtended nm_interface_info_device_wireless = { - .parent = NM_DEFINE_GDBUS_INTERFACE_INFO_INIT ( - NM_DBUS_INTERFACE_DEVICE_WIRELESS, - .methods = NM_DEFINE_GDBUS_METHOD_INFOS ( - NM_DEFINE_DBUS_METHOD_INFO_EXTENDED ( - NM_DEFINE_GDBUS_METHOD_INFO_INIT ( - "GetAccessPoints", - .out_args = NM_DEFINE_GDBUS_ARG_INFOS ( - NM_DEFINE_GDBUS_ARG_INFO ("access_points", "ao"), - ), - ), - .handle = impl_device_wifi_get_access_points, - ), - NM_DEFINE_DBUS_METHOD_INFO_EXTENDED ( - NM_DEFINE_GDBUS_METHOD_INFO_INIT ( - "GetAllAccessPoints", - .out_args = NM_DEFINE_GDBUS_ARG_INFOS ( - NM_DEFINE_GDBUS_ARG_INFO ("access_points", "ao"), - ), - ), - .handle = impl_device_wifi_get_all_access_points, - ), - NM_DEFINE_DBUS_METHOD_INFO_EXTENDED ( - NM_DEFINE_GDBUS_METHOD_INFO_INIT ( - "RequestScan", - .in_args = NM_DEFINE_GDBUS_ARG_INFOS ( - NM_DEFINE_GDBUS_ARG_INFO ("options", "a{sv}"), - ), - ), - .handle = impl_device_wifi_request_scan, - ), - ), - .signals = NM_DEFINE_GDBUS_SIGNAL_INFOS ( - &nm_signal_info_property_changed_legacy, - &nm_signal_info_wireless_access_point_added, - &nm_signal_info_wireless_access_point_removed, - ), - .properties = NM_DEFINE_GDBUS_PROPERTY_INFOS ( - NM_DEFINE_DBUS_PROPERTY_INFO_EXTENDED_READABLE_L ("HwAddress", "s", NM_DEVICE_HW_ADDRESS), - NM_DEFINE_DBUS_PROPERTY_INFO_EXTENDED_READABLE_L ("PermHwAddress", "s", NM_DEVICE_PERM_HW_ADDRESS), - NM_DEFINE_DBUS_PROPERTY_INFO_EXTENDED_READABLE_L ("Mode", "u", NM_DEVICE_WIFI_MODE), - NM_DEFINE_DBUS_PROPERTY_INFO_EXTENDED_READABLE_L ("BitRate", "u", NM_DEVICE_WIFI_BITRATE), - NM_DEFINE_DBUS_PROPERTY_INFO_EXTENDED_READABLE_L ("AccessPoints", "ao", NM_DEVICE_WIFI_ACCESS_POINTS), - NM_DEFINE_DBUS_PROPERTY_INFO_EXTENDED_READABLE_L ("ActiveAccessPoint", "o", NM_DEVICE_WIFI_ACTIVE_ACCESS_POINT), - NM_DEFINE_DBUS_PROPERTY_INFO_EXTENDED_READABLE_L ("WirelessCapabilities", "u", NM_DEVICE_WIFI_CAPABILITIES), - ), - ), - .legacy_property_changed = TRUE, -}; diff --git a/src/devices/wifi/nm-wifi-common.h b/src/devices/wifi/nm-wifi-common.h deleted file mode 100644 index 91cbeb55..00000000 --- a/src/devices/wifi/nm-wifi-common.h +++ /dev/null @@ -1,37 +0,0 @@ -/* -*- Mode: C; tab-width: 4; indent-tabs-mode: t; c-basic-offset: 4 -*- */ -/* - * This library is free software; you can redistribute it and/or - * modify it under the terms of the GNU Lesser General Public - * License as published by the Free Software Foundation; either - * version 2 of the License, or (at your option) any later version. - * - * This library is distributed in the hope that it will be useful, - * but WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU - * Lesser General Public License for more details. - * - * You should have received a copy of the GNU Lesser General Public - * License along with this library; if not, write to the - * Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor, - * Boston, MA 02110-1301 USA. - * - * (C) Copyright 2018 Red Hat, Inc. - */ - -#ifndef __NM_WIFI_COMMON_H__ -#define __NM_WIFI_COMMON_H__ - -#include "nm-dbus-utils.h" -#include "nm-wifi-ap.h" - -/*****************************************************************************/ - -void nm_device_wifi_emit_signal_access_point (NMDevice *device, - NMWifiAP *ap, - gboolean is_added /* or else is_removed */); - -extern const NMDBusInterfaceInfoExtended nm_interface_info_device_wireless; -extern const GDBusSignalInfo nm_signal_info_wireless_access_point_added; -extern const GDBusSignalInfo nm_signal_info_wireless_access_point_removed; - -#endif /* __NM_WIFI_COMMON_H__ */ diff --git a/src/devices/wifi/nm-wifi-factory.c b/src/devices/wifi/nm-wifi-factory.c index 6b8e5fb8..a1752634 100644 --- a/src/devices/wifi/nm-wifi-factory.c +++ b/src/devices/wifi/nm-wifi-factory.c @@ -27,10 +27,8 @@ #include "nm-setting-olpc-mesh.h" #include "nm-device-wifi.h" #include "nm-device-olpc-mesh.h" -#include "nm-device-iwd.h" #include "settings/nm-settings-connection.h" #include "platform/nm-platform.h" -#include "nm-config.h" /*****************************************************************************/ @@ -77,7 +75,6 @@ create_device (NMDeviceFactory *factory, { NMDeviceWifiCapabilities capabilities; NM80211Mode mode; - gs_free char *backend = NULL; g_return_val_if_fail (iface != NULL, NULL); g_return_val_if_fail (plink != NULL, NULL); @@ -101,30 +98,10 @@ create_device (NMDeviceFactory *factory, return NULL; } - if (plink->type != NM_LINK_TYPE_WIFI) - return nm_device_olpc_mesh_new (iface); - - backend = nm_config_data_get_device_config_by_pllink (NM_CONFIG_GET_DATA, - NM_CONFIG_KEYFILE_KEY_DEVICE_WIFI_BACKEND, - plink, - "wifi", - NULL); - nm_strstrip (backend); - - nm_log_dbg (LOGD_PLATFORM | LOGD_WIFI, - "(%s) config: backend is %s%s%s%s", - iface, - NM_PRINT_FMT_QUOTE_STRING (backend), - WITH_IWD ? " (iwd support enabled)" : ""); - if (!backend || !strcasecmp (backend, "wpa_supplicant")) + if (plink->type == NM_LINK_TYPE_WIFI) return nm_device_wifi_new (iface, capabilities); -#if WITH_IWD - else if (!strcasecmp (backend, "iwd")) - return nm_device_iwd_new (iface, capabilities); -#endif - - nm_log_warn (LOGD_PLATFORM | LOGD_WIFI, "(%s) config: unknown or unsupported wifi-backend %s", iface, backend); - return NULL; + else + return nm_device_olpc_mesh_new (iface); } /*****************************************************************************/ diff --git a/src/devices/wifi/nm-wifi-utils.c b/src/devices/wifi/nm-wifi-utils.c index 044bd392..3ff82004 100644 --- a/src/devices/wifi/nm-wifi-utils.c +++ b/src/devices/wifi/nm-wifi-utils.c @@ -782,35 +782,3 @@ nm_wifi_utils_level_to_quality (gint val) return CLAMP (val, 0, 100); } -gboolean -nm_wifi_utils_is_manf_default_ssid (const GByteArray *ssid) -{ - int i; - /* - * List of manufacturer default SSIDs that are often unchanged by users. - * - * NOTE: this list should *not* contain networks that you would like to - * automatically roam to like "Starbucks" or "AT&T" or "T-Mobile HotSpot". - */ - static const char *manf_defaults[] = { - "linksys", - "linksys-a", - "linksys-g", - "default", - "belkin54g", - "NETGEAR", - "o2DSL", - "WLAN", - "ALICE-WLAN", - "Speedport W 501V", - "TURBONETT", - }; - - for (i = 0; i < G_N_ELEMENTS (manf_defaults); i++) { - if (ssid->len == strlen (manf_defaults[i])) { - if (memcmp (manf_defaults[i], ssid->data, ssid->len) == 0) - return TRUE; - } - } - return FALSE; -} diff --git a/src/devices/wifi/nm-wifi-utils.h b/src/devices/wifi/nm-wifi-utils.h index def64dd6..1b6c2f4b 100644 --- a/src/devices/wifi/nm-wifi-utils.h +++ b/src/devices/wifi/nm-wifi-utils.h @@ -39,6 +39,4 @@ gboolean nm_wifi_utils_complete_connection (const GByteArray *ssid, guint32 nm_wifi_utils_level_to_quality (gint val); -gboolean nm_wifi_utils_is_manf_default_ssid (const GByteArray *ssid); - #endif /* __NM_WIFI_UTILS_H__ */ diff --git a/src/devices/wifi/tests/meson.build b/src/devices/wifi/tests/meson.build deleted file mode 100644 index bb8f7c27..00000000 --- a/src/devices/wifi/tests/meson.build +++ /dev/null @@ -1,13 +0,0 @@ -test_unit = 'test-general' - -exe = executable( - 'wifi-' + test_unit, - [test_unit + '.c'] + common_sources, - dependencies: test_nm_dep -) - -test( - 'devices/wifi/' + test_unit, - test_script, - args: test_args + [exe.full_path()] -) diff --git a/src/devices/wwan/libnm-wwan.ver b/src/devices/wwan/libnm-wwan.ver index 70b954c5..6efcb03f 100644 --- a/src/devices/wwan/libnm-wwan.ver +++ b/src/devices/wwan/libnm-wwan.ver @@ -11,10 +11,10 @@ global: nm_modem_get_capabilities; nm_modem_get_configured_mtu; nm_modem_get_control_port; + nm_modem_get_data_port; nm_modem_get_driver; nm_modem_get_iid; nm_modem_get_path; - nm_modem_get_ip_ifindex; nm_modem_get_secrets; nm_modem_get_state; nm_modem_get_type; diff --git a/src/devices/wwan/meson.build b/src/devices/wwan/meson.build deleted file mode 100644 index 032b3585..00000000 --- a/src/devices/wwan/meson.build +++ /dev/null @@ -1,75 +0,0 @@ -sources = files( - 'nm-modem-broadband.c', - 'nm-modem.c', - 'nm-modem-manager.c' -) - -deps = [ - libsystemd_dep, - mm_glib_dep, - nm_dep -] - -if enable_ofono - sources += files('nm-modem-ofono.c') -endif - -linker_script = join_paths(meson.current_source_dir(), 'libnm-wwan.ver') - -libnm_wwan = shared_module( - 'nm-wwan', - sources: sources, - dependencies: deps, - link_args: [ - '-Wl,--version-script,@0@'.format(linker_script), - ], - link_depends: linker_script, - install: true, - install_dir: nm_pkglibdir -) - -libnm_wwan_dep = declare_dependency( - include_directories: include_directories('.'), - link_with: libnm_wwan -) - -core_plugins += libnm_wwan - -run_target( - 'check-wwan', - command: [check_exports, libnm_wwan.full_path(), linker_script], - depends: libnm_wwan -) - -sources = files( - 'nm-device-modem.c', - 'nm-wwan-factory.c' -) - -libnm_device_plugin_wwan = shared_module( - 'nm-device-plugin-wwan', - sources: sources, - dependencies: deps, - link_with: libnm_wwan, - link_args: ldflags_linker_script_devices, - link_depends: linker_script_devices, - install: true, - install_dir: nm_pkglibdir -) - -core_plugins += libnm_device_plugin_wwan - -run_target( - 'check-local-devices-wwan', - command: [check_exports, libnm_device_plugin_wwan.full_path(), linker_script_devices], - depends: libnm_device_plugin_wwan -) - -# FIXME: check_so_symbols replacement -''' -check-local-devices-wwan: src/devices/wwan/libnm-device-plugin-wwan.la src/devices/wwan/libnm-wwan.la - $(srcdir)/tools/check-exports.sh $(builddir)/src/devices/wwan/.libs/libnm-device-plugin-wwan.so "$(srcdir)/linker-script-devices.ver" - $(call check_so_symbols,$(builddir)/src/devices/wwan/.libs/libnm-device-plugin-wwan.so) - $(srcdir)/tools/check-exports.sh $(builddir)/src/devices/wwan/.libs/libnm-wwan.so "$(srcdir)/src/devices/wwan/libnm-wwan.ver" - $(call check_so_symbols,$(builddir)/src/devices/wwan/.libs/libnm-wwan.so) -''' diff --git a/src/devices/wwan/nm-device-modem.c b/src/devices/wwan/nm-device-modem.c index 2a3e9ebe..b79d145d 100644 --- a/src/devices/wwan/nm-device-modem.c +++ b/src/devices/wwan/nm-device-modem.c @@ -32,6 +32,8 @@ #include "NetworkManagerUtils.h" #include "nm-core-internal.h" +#include "introspection/org.freedesktop.NetworkManager.Device.Modem.h" + #include "devices/nm-device-logging.h" _LOG_DECLARE_SELF(NMDeviceModem); @@ -258,26 +260,21 @@ modem_ip6_config_result (NMModem *modem, } static void -ip_ifindex_changed_cb (NMModem *modem, GParamSpec *pspec, gpointer user_data) +data_port_changed_cb (NMModem *modem, GParamSpec *pspec, gpointer user_data) { - NMDevice *device = NM_DEVICE (user_data); - - if (!nm_device_is_activating (device)) - return; + NMDevice *self = NM_DEVICE (user_data); + gboolean changed; - if (!nm_device_set_ip_ifindex (device, - nm_modem_get_ip_ifindex (modem))) { - nm_device_state_changed (device, - NM_DEVICE_STATE_FAILED, - NM_DEVICE_STATE_REASON_IP_CONFIG_UNAVAILABLE); - return; - } + /* We set the IP iface in the device as soon as we know it, so that we + * properly ifup it if needed */ + changed = nm_device_set_ip_iface (self, nm_modem_get_data_port (modem)); /* Disable IPv6 immediately on the interface since NM handles IPv6 * internally, and leaving it enabled could allow the kernel's IPv6 * RA handling code to run before NM is ready. */ - nm_device_ipv6_sysctl_set (device, "disable_ipv6", "1"); + if (changed) + nm_device_ipv6_sysctl_set (self, "disable_ipv6", "1"); } static void @@ -434,7 +431,7 @@ static gboolean complete_connection (NMDevice *device, NMConnection *connection, const char *specific_object, - NMConnection *const*existing_connections, + const GSList *existing_connections, GError **error) { NMDeviceModemPrivate *priv = NM_DEVICE_MODEM_GET_PRIVATE ((NMDeviceModem *) device); @@ -632,7 +629,11 @@ set_modem (NMDeviceModem *self, NMModem *modem) g_signal_connect (modem, NM_MODEM_STATE_CHANGED, G_CALLBACK (modem_state_cb), self); g_signal_connect (modem, NM_MODEM_REMOVED, G_CALLBACK (modem_removed_cb), self); - g_signal_connect (modem, "notify::" NM_MODEM_IP_IFINDEX, G_CALLBACK (ip_ifindex_changed_cb), self); + /* In the old ModemManager the data port is known from the very beginning; + * while in the new ModemManager the data port is set afterwards when the bearer gets + * created */ + g_signal_connect (modem, "notify::" NM_MODEM_DATA_PORT, G_CALLBACK (data_port_changed_cb), self); + g_signal_connect (modem, "notify::" NM_MODEM_DEVICE_ID, G_CALLBACK (ids_changed_cb), self); g_signal_connect (modem, "notify::" NM_MODEM_SIM_ID, G_CALLBACK (ids_changed_cb), self); g_signal_connect (modem, "notify::" NM_MODEM_SIM_OPERATOR_ID, G_CALLBACK (ids_changed_cb), self); @@ -707,23 +708,34 @@ nm_device_modem_new (NMModem *modem) { NMDeviceModemCapabilities caps = NM_DEVICE_MODEM_CAPABILITY_NONE; NMDeviceModemCapabilities current_caps = NM_DEVICE_MODEM_CAPABILITY_NONE; + NMDevice *device; + const char *data_port; g_return_val_if_fail (NM_IS_MODEM (modem), NULL); /* Load capabilities */ nm_modem_get_capabilities (modem, &caps, ¤t_caps); - return g_object_new (NM_TYPE_DEVICE_MODEM, - NM_DEVICE_UDI, nm_modem_get_path (modem), - NM_DEVICE_IFACE, nm_modem_get_uid (modem), - NM_DEVICE_DRIVER, nm_modem_get_driver (modem), - NM_DEVICE_TYPE_DESC, "Broadband", - NM_DEVICE_DEVICE_TYPE, NM_DEVICE_TYPE_MODEM, - NM_DEVICE_RFKILL_TYPE, RFKILL_TYPE_WWAN, - NM_DEVICE_MODEM_MODEM, modem, - NM_DEVICE_MODEM_CAPABILITIES, caps, - NM_DEVICE_MODEM_CURRENT_CAPABILITIES, current_caps, - NULL); + device = (NMDevice *) g_object_new (NM_TYPE_DEVICE_MODEM, + NM_DEVICE_UDI, nm_modem_get_path (modem), + NM_DEVICE_IFACE, nm_modem_get_uid (modem), + NM_DEVICE_DRIVER, nm_modem_get_driver (modem), + NM_DEVICE_TYPE_DESC, "Broadband", + NM_DEVICE_DEVICE_TYPE, NM_DEVICE_TYPE_MODEM, + NM_DEVICE_RFKILL_TYPE, RFKILL_TYPE_WWAN, + NM_DEVICE_MODEM_MODEM, modem, + NM_DEVICE_MODEM_CAPABILITIES, caps, + NM_DEVICE_MODEM_CURRENT_CAPABILITIES, current_caps, + NULL); + + /* If the data port is known, set it as the IP interface immediately */ + data_port = nm_modem_get_data_port (modem); + if (data_port) { + nm_device_set_ip_iface (device, data_port); + nm_device_ipv6_sysctl_set (device, "disable_ipv6", "1"); + } + + return device; } static void @@ -731,41 +743,23 @@ dispose (GObject *object) { NMDeviceModemPrivate *priv = NM_DEVICE_MODEM_GET_PRIVATE ((NMDeviceModem *) object); - if (priv->modem) { + if (priv->modem) g_signal_handlers_disconnect_by_data (priv->modem, NM_DEVICE_MODEM (object)); - g_clear_object (&priv->modem); - } + g_clear_object (&priv->modem); G_OBJECT_CLASS (nm_device_modem_parent_class)->dispose (object); } -static const NMDBusInterfaceInfoExtended interface_info_device_modem = { - .parent = NM_DEFINE_GDBUS_INTERFACE_INFO_INIT ( - NM_DBUS_INTERFACE_DEVICE_MODEM, - .signals = NM_DEFINE_GDBUS_SIGNAL_INFOS ( - &nm_signal_info_property_changed_legacy, - ), - .properties = NM_DEFINE_GDBUS_PROPERTY_INFOS ( - NM_DEFINE_DBUS_PROPERTY_INFO_EXTENDED_READABLE_L ("ModemCapabilities", "u", NM_DEVICE_MODEM_CAPABILITIES), - NM_DEFINE_DBUS_PROPERTY_INFO_EXTENDED_READABLE_L ("CurrentCapabilities", "u", NM_DEVICE_MODEM_CURRENT_CAPABILITIES), - ), - ), - .legacy_property_changed = TRUE, -}; - static void -nm_device_modem_class_init (NMDeviceModemClass *klass) +nm_device_modem_class_init (NMDeviceModemClass *mclass) { - GObjectClass *object_class = G_OBJECT_CLASS (klass); - NMDBusObjectClass *dbus_object_class = NM_DBUS_OBJECT_CLASS (klass); - NMDeviceClass *device_class = NM_DEVICE_CLASS (klass); + GObjectClass *object_class = G_OBJECT_CLASS (mclass); + NMDeviceClass *device_class = NM_DEVICE_CLASS (mclass); object_class->dispose = dispose; object_class->get_property = get_property; object_class->set_property = set_property; - dbus_object_class->interface_infos = NM_DBUS_INTERFACE_INFOS (&interface_info_device_modem); - device_class->get_generic_capabilities = get_generic_capabilities; device_class->get_type_description = get_type_description; device_class->check_connection_compatible = check_connection_compatible; @@ -808,4 +802,8 @@ nm_device_modem_class_init (NMDeviceModemClass *klass) G_PARAM_STATIC_STRINGS); g_object_class_install_properties (object_class, _PROPERTY_ENUMS_LAST, obj_properties); + + nm_exported_object_class_add_interface (NM_EXPORTED_OBJECT_CLASS (mclass), + NMDBUS_TYPE_DEVICE_MODEM_SKELETON, + NULL); } diff --git a/src/devices/wwan/nm-modem-broadband.c b/src/devices/wwan/nm-modem-broadband.c index 9a3744db..dc0ce303 100644 --- a/src/devices/wwan/nm-modem-broadband.c +++ b/src/devices/wwan/nm-modem-broadband.c @@ -339,7 +339,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); + g_clear_pointer (&ctx->ip_types, (GDestroyNotify) g_array_unref); nm_clear_g_cancellable (&ctx->cancellable); g_clear_object (&ctx->connection); g_clear_object (&ctx->connect_properties); @@ -385,10 +385,9 @@ connect_ready (MMModemSimple *simple_iface, g_dbus_error_strip_remote_error (error); ctx->first_error = error; } else - g_clear_error (&error); + g_error_free (error); - if ( ctx->ip_type_tries == 0 - && g_error_matches (error, MM_CORE_ERROR, MM_CORE_ERROR_RETRY)) { + if (ctx->ip_type_tries == 0 && g_error_matches (error, MM_CORE_ERROR, MM_CORE_ERROR_RETRY)) { /* Try one more time */ ctx->ip_type_tries++; } else { @@ -411,20 +410,21 @@ connect_ready (MMModemSimple *simple_iface, if (self->_priv.ipv6_config) ip6_method = get_bearer_ip_method (self->_priv.ipv6_config); - if (!nm_modem_set_data_port (NM_MODEM (self), - NM_PLATFORM_GET, - mm_bearer_get_interface (self->_priv.bearer), - ip4_method, - ip6_method, - mm_bearer_get_ip_timeout (self->_priv.bearer), - &error)) { - _LOGW ("failed to connect modem: %s", error->message); - g_error_free (error); + if (ip4_method == NM_MODEM_IP_METHOD_UNKNOWN && + ip6_method == NM_MODEM_IP_METHOD_UNKNOWN) { + _LOGW ("failed to connect modem: invalid bearer IP configuration"); nm_modem_emit_prepare_result (NM_MODEM (self), FALSE, NM_DEVICE_STATE_REASON_CONFIG_FAILED); connect_context_clear (self); return; } + g_object_set (self, + NM_MODEM_DATA_PORT, mm_bearer_get_interface (self->_priv.bearer), + NM_MODEM_IP4_METHOD, ip4_method, + NM_MODEM_IP6_METHOD, ip6_method, + NM_MODEM_IP_TIMEOUT, mm_bearer_get_ip_timeout (self->_priv.bearer), + NULL); + ctx->step++; connect_context_step (self); } @@ -663,7 +663,7 @@ check_connection_compatible (NMModem *_self, NMConnection *connection) static gboolean complete_connection (NMModem *_self, NMConnection *connection, - NMConnection *const*existing_connections, + const GSList *existing_connections, GError **error) { NMModemBroadband *self = NM_MODEM_BROADBAND (_self); @@ -1409,34 +1409,35 @@ nm_modem_broadband_init (NMModemBroadband *self) NMModem * nm_modem_broadband_new (GObject *object, GError **error) { + NMModem *modem; MMObject *modem_object; MMModem *modem_iface; - const char *const*drivers; - gs_free char *driver = NULL; + gchar *drivers; g_return_val_if_fail (MM_IS_OBJECT (object), NULL); modem_object = MM_OBJECT (object); /* Ensure we have the 'Modem' interface and the primary port at least */ modem_iface = mm_object_peek_modem (modem_object); - g_return_val_if_fail (modem_iface, NULL); - g_return_val_if_fail (mm_modem_get_primary_port (modem_iface), NULL); + g_return_val_if_fail (!!modem_iface, NULL); + g_return_val_if_fail (!!mm_modem_get_primary_port (modem_iface), NULL); /* Build a single string with all drivers listed */ - drivers = mm_modem_get_drivers (modem_iface); - if (drivers) - driver = g_strjoinv (", ", (char **) drivers); - - return g_object_new (NM_TYPE_MODEM_BROADBAND, - NM_MODEM_PATH, mm_object_get_path (modem_object), - NM_MODEM_UID, mm_modem_get_primary_port (modem_iface), - NM_MODEM_CONTROL_PORT, mm_modem_get_primary_port (modem_iface), - NM_MODEM_IP_TYPES, mm_ip_family_to_nm (mm_modem_get_supported_ip_families (modem_iface)), - NM_MODEM_STATE, (int) mm_state_to_nm (mm_modem_get_state (modem_iface)), - NM_MODEM_DEVICE_ID, mm_modem_get_device_identifier (modem_iface), - NM_MODEM_BROADBAND_MODEM, modem_object, - NM_MODEM_DRIVER, driver, - NULL); + drivers = g_strjoinv (", ", (gchar **)mm_modem_get_drivers (modem_iface)); + + modem = g_object_new (NM_TYPE_MODEM_BROADBAND, + NM_MODEM_PATH, mm_object_get_path (modem_object), + NM_MODEM_UID, mm_modem_get_primary_port (modem_iface), + NM_MODEM_CONTROL_PORT, mm_modem_get_primary_port (modem_iface), + NM_MODEM_DATA_PORT, NULL, /* We don't know it until bearer created */ + NM_MODEM_IP_TYPES, mm_ip_family_to_nm (mm_modem_get_supported_ip_families (modem_iface)), + NM_MODEM_STATE, (int) mm_state_to_nm (mm_modem_get_state (modem_iface)), + NM_MODEM_DEVICE_ID, mm_modem_get_device_identifier (modem_iface), + NM_MODEM_BROADBAND_MODEM, modem_object, + NM_MODEM_DRIVER, drivers, + NULL); + g_free (drivers); + return modem; } static void diff --git a/src/devices/wwan/nm-modem-ofono.c b/src/devices/wwan/nm-modem-ofono.c index a1c6aef2..811c3afb 100644 --- a/src/devices/wwan/nm-modem-ofono.c +++ b/src/devices/wwan/nm-modem-ofono.c @@ -836,7 +836,6 @@ context_property_changed (GDBusProxy *proxy, guint32 address_network, gateway_network; guint32 ip4_route_table, ip4_route_metric; int ifindex; - GError *error = NULL; _LOGD ("PropertyChanged: %s", property); @@ -861,26 +860,27 @@ context_property_changed (GDBusProxy *proxy, _LOGW ("Settings 'Interface' missing"); goto out; } + if (!interface || !interface[0]) { + _LOGW ("Settings 'Interface'; empty"); + goto out; + } - _LOGD ("Interface: %s", interface); - if (!nm_modem_set_data_port (NM_MODEM (self), - NM_PLATFORM_GET, - interface, - NM_MODEM_IP_METHOD_STATIC, - NM_MODEM_IP_METHOD_UNKNOWN, - 0, - &error)) { - _LOGW ("failed to connect to modem: %s", error->message); - g_clear_error (&error); + ifindex = nm_platform_link_get_ifindex (NM_PLATFORM_GET, interface); + if (ifindex <= 0) { + _LOGW ("Interface \"%s\" not found", interface); goto out; } - ifindex = nm_modem_get_ip_ifindex (NM_MODEM (self)); - nm_assert (ifindex > 0); + _LOGD ("Interface: %s", interface); + g_object_set (self, + NM_MODEM_DATA_PORT, interface, + NM_MODEM_IP4_METHOD, NM_MODEM_IP_METHOD_STATIC, + NULL); /* TODO: verify handling of ip4_config; check other places it's used... */ g_clear_object (&priv->ip4_config); + priv->ip4_config = nm_ip4_config_new (nm_platform_get_multi_idx (NM_PLATFORM_GET), ifindex); diff --git a/src/devices/wwan/nm-modem.c b/src/devices/wwan/nm-modem.c index 61b7247e..010a2b60 100644 --- a/src/devices/wwan/nm-modem.c +++ b/src/devices/wwan/nm-modem.c @@ -44,10 +44,13 @@ NM_GOBJECT_PROPERTIES_DEFINE (NMModem, PROP_CONTROL_PORT, - PROP_IP_IFINDEX, + PROP_DATA_PORT, PROP_PATH, PROP_UID, PROP_DRIVER, + PROP_IP4_METHOD, + PROP_IP6_METHOD, + PROP_IP_TIMEOUT, PROP_STATE, PROP_DEVICE_ID, PROP_SIM_ID, @@ -76,12 +79,7 @@ typedef struct _NMModemPrivate { char *driver; char *control_port; char *data_port; - - /* TODO: ip_iface is solely used for nm_modem_owns_port(). - * We should rework the code that it's not necessary */ - char *ip_iface; - - int ip_ifindex; + char *ppp_iface; NMModemIPMethod ip4_method; NMModemIPMethod ip6_method; NMUtilsIPv6IfaceId iid; @@ -98,7 +96,7 @@ typedef struct _NMModemPrivate { guint32 secrets_tries; NMActRequestGetSecretsCallId *secrets_id; - guint mm_ip_timeout; + guint32 mm_ip_timeout; guint32 ip4_route_table; guint32 ip4_route_metric; @@ -155,10 +153,6 @@ _nmlog_prefix (char *prefix, NMModem *self) } G_STMT_END /*****************************************************************************/ - -static void _set_ip_ifindex (NMModem *self, int ifindex, const char *ifname); - -/*****************************************************************************/ /* State/enabled/connected */ static const char *state_table[] = { @@ -456,28 +450,20 @@ ppp_state_changed (NMPPPManager *ppp_manager, NMPPPStatus status, gpointer user_ } static void -ppp_ifindex_set (NMPPPManager *ppp_manager, - int ifindex, - const char *iface, - gpointer user_data) +set_data_port (NMModem *self, const char *new_data_port) { - NMModem *self = NM_MODEM (user_data); - - nm_assert (ifindex >= 0); - nm_assert (NM_MODEM_GET_PRIVATE (self)->ppp_manager == ppp_manager); + NMModemPrivate *priv = NM_MODEM_GET_PRIVATE (self); - if (ifindex <= 0 && iface) { - /* this might happen, if the ifname was already deleted - * and we failed to resolve ifindex. - * - * Forget about the name. */ - iface = NULL; + if (g_strcmp0 (priv->data_port, new_data_port) != 0) { + g_free (priv->data_port); + priv->data_port = g_strdup (new_data_port); + _notify (self, PROP_DATA_PORT); } - _set_ip_ifindex (self, ifindex, iface); } static void ppp_ip4_config (NMPPPManager *ppp_manager, + const char *iface, NMIP4Config *config, gpointer user_data) { @@ -489,6 +475,9 @@ ppp_ip4_config (NMPPPManager *ppp_manager, guint32 good_dns2 = htonl (0x04020202); /* GTE nameserver */ gboolean dns_workaround = FALSE; + /* Notify about the new data port to use */ + set_data_port (self, iface); + /* Work around a PPP bug (#1732) which causes many mobile broadband * providers to return 10.11.12.13 and 10.11.12.14 for the DNS servers. * Apparently fixed in ppp-2.4.5 but we've had some reports that this is @@ -530,12 +519,16 @@ ppp_ip4_config (NMPPPManager *ppp_manager, static void ppp_ip6_config (NMPPPManager *ppp_manager, + const char *iface, const NMUtilsIPv6IfaceId *iid, NMIP6Config *config, gpointer user_data) { NMModem *self = NM_MODEM (user_data); + /* Notify about the new data port to use */ + set_data_port (self, iface); + NM_MODEM_GET_PRIVATE (self)->iid = *iid; nm_modem_emit_ip6_config_result (self, config, NULL); @@ -564,18 +557,6 @@ port_speed_is_zero (const char *port) { struct termios options; nm_auto_close int fd = -1; - gs_free char *path = NULL; - - nm_assert (port); - - if (port[0] != '/') { - if ( !port[0] - || strchr (port, '/') - || NM_IN_STRSET (port, ".", "..")) - return FALSE; - path = g_build_path ("/sys/class/tty", port, NULL); - port = path; - } fd = open (port, O_RDWR | O_NONBLOCK | O_NOCTTY | O_CLOEXEC); if (fd < 0) @@ -617,12 +598,6 @@ ppp_stage3_ip_config_start (NMModem *self, return NM_ACT_STAGE_RETURN_FAILURE; } - if (!priv->data_port) { - _LOGE ("error starting PPP (no data port)"); - NM_SET_OUT (out_failure_reason, NM_DEVICE_STATE_REASON_PPP_START_FAILED); - return NM_ACT_STAGE_RETURN_FAILURE; - } - /* Check if ModemManager requested a specific IP timeout to be used. If 0 reported, * use the default one (30s) */ if (priv->mm_ip_timeout > 0) { @@ -654,7 +629,9 @@ ppp_stage3_ip_config_start (NMModem *self, ip_timeout, baud_override, &error)) { _LOGE ("error starting PPP: %s", error->message); g_error_free (error); + g_clear_object (&priv->ppp_manager); + NM_SET_OUT (out_failure_reason, NM_DEVICE_STATE_REASON_PPP_START_FAILED); return NM_ACT_STAGE_RETURN_FAILURE; } @@ -662,9 +639,6 @@ ppp_stage3_ip_config_start (NMModem *self, g_signal_connect (priv->ppp_manager, NM_PPP_MANAGER_SIGNAL_STATE_CHANGED, G_CALLBACK (ppp_state_changed), self); - g_signal_connect (priv->ppp_manager, NM_PPP_MANAGER_SIGNAL_IFINDEX_SET, - G_CALLBACK (ppp_ifindex_set), - self); g_signal_connect (priv->ppp_manager, NM_PPP_MANAGER_SIGNAL_IP4_CONFIG, G_CALLBACK (ppp_ip4_config), self); @@ -1091,20 +1065,12 @@ nm_modem_check_connection_compatible (NMModem *self, NMConnection *connection) gboolean nm_modem_complete_connection (NMModem *self, NMConnection *connection, - NMConnection *const*existing_connections, + const GSList *existing_connections, GError **error) { - NMModemClass *klass; - - klass = NM_MODEM_GET_CLASS (self); - if (!klass->complete_connection) { - g_set_error (error, NM_DEVICE_ERROR, NM_DEVICE_ERROR_INVALID_CONNECTION, - "Modem class %s had no complete_connection method", - G_OBJECT_TYPE_NAME (self)); - return FALSE; - } - - return klass->complete_connection (self, connection, existing_connections, error); + if (NM_MODEM_GET_CLASS (self)->complete_connection) + return NM_MODEM_GET_CLASS (self)->complete_connection (self, connection, existing_connections, error); + return FALSE; } /*****************************************************************************/ @@ -1129,10 +1095,7 @@ deactivate_cleanup (NMModem *self, NMDevice *device) priv->in_bytes = priv->out_bytes = 0; - if (priv->ppp_manager) { - g_signal_handlers_disconnect_by_data (priv->ppp_manager, self); - g_clear_object (&priv->ppp_manager); - } + g_clear_object (&priv->ppp_manager); if (device) { g_return_if_fail (NM_IS_DEVICE (device)); @@ -1151,12 +1114,11 @@ deactivate_cleanup (NMModem *self, NMDevice *device) } } } - - nm_clear_g_free (&priv->data_port); - priv->mm_ip_timeout = 0; priv->ip4_method = NM_MODEM_IP_METHOD_UNKNOWN; priv->ip6_method = NM_MODEM_IP_METHOD_UNKNOWN; - _set_ip_ifindex (self, -1, NULL); + + g_free (priv->ppp_iface); + priv->ppp_iface = NULL; } /*****************************************************************************/ @@ -1407,117 +1369,17 @@ nm_modem_get_control_port (NMModem *self) return NM_MODEM_GET_PRIVATE (self)->control_port; } -int -nm_modem_get_ip_ifindex (NMModem *self) -{ - NMModemPrivate *priv; - - g_return_val_if_fail (NM_IS_MODEM (self), 0); - - priv = NM_MODEM_GET_PRIVATE (self); - - /* internally we track an unset ip_ifindex as -1. - * For the caller of nm_modem_get_ip_ifindex(), this - * shall be zero too. */ - return priv->ip_ifindex != -1 ? priv->ip_ifindex : 0; -} - -static void -_set_ip_ifindex (NMModem *self, int ifindex, const char *ifname) -{ - NMModemPrivate *priv = NM_MODEM_GET_PRIVATE (self); - - nm_assert (ifindex >= -1); - nm_assert ((ifindex > 0) == !!ifname); - - if (!nm_streq0 (priv->ip_iface, ifname)) { - g_free (priv->ip_iface); - priv->ip_iface = g_strdup (ifname); - } - - if (priv->ip_ifindex != ifindex) { - priv->ip_ifindex = ifindex; - _notify (self, PROP_IP_IFINDEX); - } -} - -gboolean -nm_modem_set_data_port (NMModem *self, - NMPlatform *platform, - const char *data_port, - NMModemIPMethod ip4_method, - NMModemIPMethod ip6_method, - guint timeout, - GError **error) +const char * +nm_modem_get_data_port (NMModem *self) { - NMModemPrivate *priv; - gboolean is_ppp; - int ifindex = -1; - - g_return_val_if_fail (NM_IS_MODEM (self), FALSE); - g_return_val_if_fail (NM_IS_PLATFORM (platform), FALSE); - g_return_val_if_fail (!error || !*error, FALSE); - - priv = NM_MODEM_GET_PRIVATE (self); - - if ( priv->ppp_manager - || priv->data_port - || priv->ip_ifindex != -1) { - g_set_error_literal (error, NM_UTILS_ERROR, NM_UTILS_ERROR_UNKNOWN, - "cannot set data port in activated state"); - /* this really shouldn't happen. Assert. */ - g_return_val_if_reached (FALSE); - } - - if (!data_port) { - g_set_error_literal (error, NM_UTILS_ERROR, NM_UTILS_ERROR_UNKNOWN, - "missing data port"); - return FALSE; - } - - is_ppp = (ip4_method == NM_MODEM_IP_METHOD_PPP) - || (ip6_method == NM_MODEM_IP_METHOD_PPP); - if (is_ppp) { - if ( !NM_IN_SET (ip4_method, NM_MODEM_IP_METHOD_UNKNOWN, NM_MODEM_IP_METHOD_PPP) - || !NM_IN_SET (ip6_method, NM_MODEM_IP_METHOD_UNKNOWN, NM_MODEM_IP_METHOD_PPP)) { - g_set_error_literal (error, NM_UTILS_ERROR, NM_UTILS_ERROR_UNKNOWN, - "conflicting ip methods"); - return FALSE; - } - } else if ( !NM_IN_SET (ip4_method, NM_MODEM_IP_METHOD_UNKNOWN, NM_MODEM_IP_METHOD_STATIC, NM_MODEM_IP_METHOD_AUTO) - || !NM_IN_SET (ip6_method, NM_MODEM_IP_METHOD_UNKNOWN, NM_MODEM_IP_METHOD_STATIC, NM_MODEM_IP_METHOD_AUTO) - || ( ip4_method == NM_MODEM_IP_METHOD_UNKNOWN - && ip6_method == NM_MODEM_IP_METHOD_UNKNOWN)) { - g_set_error_literal (error, NM_UTILS_ERROR, NM_UTILS_ERROR_UNKNOWN, - "invalid ip methods"); - return FALSE; - } - - if (!is_ppp) { - ifindex = nm_platform_if_nametoindex (platform, data_port); - if (ifindex <= 0) { - g_set_error (error, NM_UTILS_ERROR, NM_UTILS_ERROR_UNKNOWN, - "cannot find network interface %s", data_port); - return FALSE; - } - if (!nm_platform_process_events_ensure_link (platform, ifindex, data_port)) { - g_set_error (error, NM_UTILS_ERROR, NM_UTILS_ERROR_UNKNOWN, - "cannot find network interface %s in platform cache", data_port); - return FALSE; - } - } + g_return_val_if_fail (NM_IS_MODEM (self), NULL); - priv->mm_ip_timeout = timeout; - priv->ip4_method = ip4_method; - priv->ip6_method = ip6_method; - if (is_ppp) { - priv->data_port = g_strdup (data_port); - _set_ip_ifindex (self, -1, NULL); - } else { - priv->data_port = NULL; - _set_ip_ifindex (self, ifindex, data_port); - } - return TRUE; + /* The ppp_iface takes precedence over the data interface when PPP is used, + * since data_iface is the TTY over which PPP is run, and that TTY can't + * do IP. The caller really wants the thing that's doing IP. + */ + return NM_MODEM_GET_PRIVATE (self)->ppp_iface ? + NM_MODEM_GET_PRIVATE (self)->ppp_iface : NM_MODEM_GET_PRIVATE (self)->data_port; } gboolean @@ -1530,10 +1392,15 @@ nm_modem_owns_port (NMModem *self, const char *iface) if (NM_MODEM_GET_CLASS (self)->owns_port) return NM_MODEM_GET_CLASS (self)->owns_port (self, iface); - return NM_IN_STRSET (iface, - priv->ip_iface, - priv->data_port, - priv->control_port); + /* Fall back to data/control ports */ + if (priv->ppp_iface && (strcmp (priv->ppp_iface, iface) == 0)) + return TRUE; + if (priv->data_port && (strcmp (priv->data_port, iface) == 0)) + return TRUE; + if (priv->control_port && (strcmp (priv->control_port, iface) == 0)) + return TRUE; + + return FALSE; } gboolean @@ -1633,8 +1500,7 @@ static void get_property (GObject *object, guint prop_id, GValue *value, GParamSpec *pspec) { - NMModem *self = NM_MODEM (object); - NMModemPrivate *priv = NM_MODEM_GET_PRIVATE (self); + NMModemPrivate *priv = NM_MODEM_GET_PRIVATE ((NMModem *) object); switch (prop_id) { case PROP_PATH: @@ -1646,12 +1512,21 @@ get_property (GObject *object, guint prop_id, case PROP_CONTROL_PORT: g_value_set_string (value, priv->control_port); break; - case PROP_IP_IFINDEX: - g_value_set_int (value, nm_modem_get_ip_ifindex (self)); + case PROP_DATA_PORT: + g_value_set_string (value, nm_modem_get_data_port (NM_MODEM (object))); break; case PROP_UID: g_value_set_string (value, priv->uid); break; + case PROP_IP4_METHOD: + g_value_set_uint (value, priv->ip4_method); + break; + case PROP_IP6_METHOD: + g_value_set_uint (value, priv->ip6_method); + break; + case PROP_IP_TIMEOUT: + g_value_set_uint (value, priv->mm_ip_timeout); + break; case PROP_STATE: g_value_set_int (value, priv->state); break; @@ -1694,10 +1569,23 @@ set_property (GObject *object, guint prop_id, /* construct-only */ priv->control_port = g_value_dup_string (value); break; + case PROP_DATA_PORT: + g_free (priv->data_port); + priv->data_port = g_value_dup_string (value); + break; case PROP_UID: /* construct-only */ priv->uid = g_value_dup_string (value); break; + case PROP_IP4_METHOD: + priv->ip4_method = g_value_get_uint (value); + break; + case PROP_IP6_METHOD: + priv->ip6_method = g_value_get_uint (value); + break; + case PROP_IP_TIMEOUT: + priv->mm_ip_timeout = g_value_get_uint (value); + break; case PROP_STATE: /* construct-only */ priv->state = g_value_get_int (value); @@ -1735,7 +1623,6 @@ nm_modem_init (NMModem *self) self->_priv = G_TYPE_INSTANCE_GET_PRIVATE (self, NM_TYPE_MODEM, NMModemPrivate); priv = self->_priv; - priv->ip_ifindex = -1; priv->ip4_route_table = RT_TABLE_MAIN; priv->ip4_route_metric = 700; priv->ip6_route_table = RT_TABLE_MAIN; @@ -1751,7 +1638,7 @@ constructed (GObject *object) priv = NM_MODEM_GET_PRIVATE (NM_MODEM (object)); - g_return_if_fail (priv->control_port); + g_return_if_fail (priv->data_port || priv->control_port); } /*****************************************************************************/ @@ -1776,7 +1663,6 @@ finalize (GObject *object) g_free (priv->driver); g_free (priv->control_port); g_free (priv->data_port); - g_free (priv->ip_iface); g_free (priv->device_id); g_free (priv->sim_id); g_free (priv->sim_operator_id); @@ -1825,11 +1711,33 @@ nm_modem_class_init (NMModemClass *klass) G_PARAM_READWRITE | G_PARAM_CONSTRUCT_ONLY | G_PARAM_STATIC_STRINGS); - obj_properties[PROP_IP_IFINDEX] = - g_param_spec_int (NM_MODEM_IP_IFINDEX, "", "", - 0, G_MAXINT, 0, - G_PARAM_READABLE | - G_PARAM_STATIC_STRINGS); + obj_properties[PROP_DATA_PORT] = + g_param_spec_string (NM_MODEM_DATA_PORT, "", "", + NULL, + G_PARAM_READWRITE | G_PARAM_CONSTRUCT | + G_PARAM_STATIC_STRINGS); + + obj_properties[PROP_IP4_METHOD] = + g_param_spec_uint (NM_MODEM_IP4_METHOD, "", "", + NM_MODEM_IP_METHOD_UNKNOWN, + NM_MODEM_IP_METHOD_AUTO, + NM_MODEM_IP_METHOD_UNKNOWN, + G_PARAM_READWRITE | G_PARAM_CONSTRUCT | + G_PARAM_STATIC_STRINGS); + + obj_properties[PROP_IP6_METHOD] = + g_param_spec_uint (NM_MODEM_IP6_METHOD, "", "", + NM_MODEM_IP_METHOD_UNKNOWN, + NM_MODEM_IP_METHOD_AUTO, + NM_MODEM_IP_METHOD_UNKNOWN, + G_PARAM_READWRITE | G_PARAM_CONSTRUCT | + G_PARAM_STATIC_STRINGS); + + obj_properties[PROP_IP_TIMEOUT] = + g_param_spec_uint (NM_MODEM_IP_TIMEOUT, "", "", + 0, 360, 20, + G_PARAM_READWRITE | + G_PARAM_STATIC_STRINGS); obj_properties[PROP_STATE] = g_param_spec_int (NM_MODEM_STATE, "", "", diff --git a/src/devices/wwan/nm-modem.h b/src/devices/wwan/nm-modem.h index 3e281c0c..9546e4a1 100644 --- a/src/devices/wwan/nm-modem.h +++ b/src/devices/wwan/nm-modem.h @@ -37,7 +37,10 @@ #define NM_MODEM_PATH "path" #define NM_MODEM_DRIVER "driver" #define NM_MODEM_CONTROL_PORT "control-port" -#define NM_MODEM_IP_IFINDEX "ip-ifindex" +#define NM_MODEM_DATA_PORT "data-port" +#define NM_MODEM_IP4_METHOD "ip4-method" +#define NM_MODEM_IP6_METHOD "ip6-method" +#define NM_MODEM_IP_TIMEOUT "ip-timeout" #define NM_MODEM_STATE "state" #define NM_MODEM_DEVICE_ID "device-id" #define NM_MODEM_SIM_ID "sim-id" @@ -126,7 +129,7 @@ typedef struct { gboolean (*complete_connection) (NMModem *modem, NMConnection *connection, - NMConnection *const*existing_connections, + const GSList *existing_connections, GError **error); NMActStageReturn (*act_stage1_prepare) (NMModem *modem, @@ -164,21 +167,13 @@ GType nm_modem_get_type (void); const char *nm_modem_get_path (NMModem *modem); const char *nm_modem_get_uid (NMModem *modem); const char *nm_modem_get_control_port (NMModem *modem); -int nm_modem_get_ip_ifindex (NMModem *modem); +const char *nm_modem_get_data_port (NMModem *modem); const char *nm_modem_get_driver (NMModem *modem); const char *nm_modem_get_device_id (NMModem *modem); const char *nm_modem_get_sim_id (NMModem *modem); const char *nm_modem_get_sim_operator_id (NMModem *modem); gboolean nm_modem_get_iid (NMModem *modem, NMUtilsIPv6IfaceId *out_iid); -gboolean nm_modem_set_data_port (NMModem *self, - NMPlatform *platform, - const char *data_port, - NMModemIPMethod ip4_method, - NMModemIPMethod ip6_method, - guint timeout, - GError **error); - gboolean nm_modem_owns_port (NMModem *modem, const char *iface); void nm_modem_get_capabilities (NMModem *self, @@ -189,7 +184,7 @@ gboolean nm_modem_check_connection_compatible (NMModem *self, NMConnection *conn gboolean nm_modem_complete_connection (NMModem *self, NMConnection *connection, - NMConnection *const*existing_connections, + const GSList *existing_connections, GError **error); void nm_modem_get_route_parameters (NMModem *self, diff --git a/src/devices/wwan/nm-wwan-factory.c b/src/devices/wwan/nm-wwan-factory.c index f0aae040..663102de 100644 --- a/src/devices/wwan/nm-wwan-factory.c +++ b/src/devices/wwan/nm-wwan-factory.c @@ -80,7 +80,7 @@ modem_added_cb (NMModemManager *manager, { NMWwanFactory *self = NM_WWAN_FACTORY (user_data); NMDevice *device; - const char *driver; + const char *driver, *port; /* Do nothing if the modem was consumed by some other plugin */ if (nm_device_factory_emit_component_added (NM_DEVICE_FACTORY (self), G_OBJECT (modem))) @@ -93,8 +93,10 @@ modem_added_cb (NMModemManager *manager, * by the Bluetooth code during the connection process. */ if (driver && strstr (driver, "bluetooth")) { - nm_log_info (LOGD_MB, "ignoring modem '%s' (no associated Bluetooth device)", - nm_modem_get_control_port (modem)); + port = nm_modem_get_data_port (modem); + if (!port) + port = nm_modem_get_control_port (modem); + nm_log_info (LOGD_MB, "ignoring modem '%s' (no associated Bluetooth device)", port); return; } diff --git a/src/dhcp/meson.build b/src/dhcp/meson.build deleted file mode 100644 index 289a16ca..00000000 --- a/src/dhcp/meson.build +++ /dev/null @@ -1,22 +0,0 @@ -name = 'nm-dhcp-helper' - -cflags = [ - '-DG_LOG_DOMAIN="@0@"'.format(name), - '-DNETWORKMANAGER_COMPILATION=NM_NETWORKMANAGER_COMPILATION_GLIB', - '-DNMRUNDIR="@0@"'.format(nm_pkgrundir), -] - -executable( - name, - name + '.c', - dependencies: nm_core_dep, - c_args: cflags, - link_args: ldflags_linker_script_binary, - link_depends: linker_script_binary, - install: true, - install_dir: nm_libexecdir -) - -if enable_tests - subdir('tests') -endif diff --git a/src/dhcp/nm-dhcp-client.c b/src/dhcp/nm-dhcp-client.c index 96c02653..ea3938d6 100644 --- a/src/dhcp/nm-dhcp-client.c +++ b/src/dhcp/nm-dhcp-client.c @@ -52,24 +52,23 @@ enum { static guint signals[LAST_SIGNAL] = { 0 }; NM_GOBJECT_PROPERTIES_DEFINE_BASE ( + PROP_MULTI_IDX, PROP_ADDR_FAMILY, - PROP_FLAGS, - PROP_HWADDR, PROP_IFACE, PROP_IFINDEX, - PROP_MULTI_IDX, - PROP_ROUTE_METRIC, + PROP_HWADDR, + PROP_UUID, PROP_ROUTE_TABLE, + PROP_ROUTE_METRIC, PROP_TIMEOUT, - PROP_UUID, ); typedef struct _NMDhcpClientPrivate { NMDedupMultiIndex *multi_idx; char * iface; - GBytes * hwaddr; + GByteArray * hwaddr; char * uuid; - GBytes * duid; + GByteArray * duid; GBytes * client_id; char * hostname; pid_t pid; @@ -139,7 +138,7 @@ nm_dhcp_client_get_uuid (NMDhcpClient *self) return NM_DHCP_CLIENT_GET_PRIVATE (self)->uuid; } -GBytes * +const GByteArray * nm_dhcp_client_get_duid (NMDhcpClient *self) { g_return_val_if_fail (NM_IS_DHCP_CLIENT (self), NULL); @@ -147,7 +146,7 @@ nm_dhcp_client_get_duid (NMDhcpClient *self) return NM_DHCP_CLIENT_GET_PRIVATE (self)->duid; } -GBytes * +const GByteArray * nm_dhcp_client_get_hw_addr (NMDhcpClient *self) { g_return_val_if_fail (NM_IS_DHCP_CLIENT (self), NULL); @@ -239,20 +238,26 @@ nm_dhcp_client_set_client_id_bin (NMDhcpClient *self, _set_client_id (self, b, TRUE); } -const char * -nm_dhcp_client_get_hostname (NMDhcpClient *self) +void +nm_dhcp_client_set_client_id_str (NMDhcpClient *self, + const char *dhcp_client_id) { - g_return_val_if_fail (NM_IS_DHCP_CLIENT (self), NULL); + g_return_if_fail (NM_IS_DHCP_CLIENT (self)); + g_return_if_fail (!dhcp_client_id || dhcp_client_id[0]); - return NM_DHCP_CLIENT_GET_PRIVATE (self)->hostname; + _set_client_id (self, + dhcp_client_id + ? nm_dhcp_utils_client_id_string_to_bytes (dhcp_client_id) + : NULL, + TRUE); } -gboolean -nm_dhcp_client_get_info_only (NMDhcpClient *self) +const char * +nm_dhcp_client_get_hostname (NMDhcpClient *self) { - g_return_val_if_fail (NM_IS_DHCP_CLIENT (self), FALSE); + g_return_val_if_fail (NM_IS_DHCP_CLIENT (self), NULL); - return NM_DHCP_CLIENT_GET_PRIVATE (self)->info_only; + return NM_DHCP_CLIENT_GET_PRIVATE (self)->hostname; } gboolean @@ -340,7 +345,7 @@ nm_dhcp_client_stop_pid (pid_t pid, const char *iface) } static void -stop (NMDhcpClient *self, gboolean release, GBytes *duid) +stop (NMDhcpClient *self, gboolean release, const GByteArray *duid) { NMDhcpClientPrivate *priv; @@ -354,6 +359,7 @@ stop (NMDhcpClient *self, gboolean release, GBytes *duid) nm_dhcp_client_stop_pid (priv->pid, priv->iface); } priv->pid = -1; + priv->info_only = FALSE; } void @@ -486,9 +492,10 @@ nm_dhcp_client_watch_child (NMDhcpClient *self, pid_t pid) gboolean nm_dhcp_client_start_ip4 (NMDhcpClient *self, - GBytes *client_id, + const char *dhcp_client_id, const char *dhcp_anycast_addr, const char *hostname, + gboolean use_fqdn, const char *last_ip4_address) { NMDhcpClientPrivate *priv; @@ -505,19 +512,19 @@ nm_dhcp_client_start_ip4 (NMDhcpClient *self, else _LOGI ("activation: beginning transaction (timeout in %u seconds)", (guint) priv->timeout); - nm_dhcp_client_set_client_id (self, client_id); + nm_dhcp_client_set_client_id_str (self, dhcp_client_id); g_clear_pointer (&priv->hostname, g_free); priv->hostname = g_strdup (hostname); + priv->use_fqdn = use_fqdn; return NM_DHCP_CLIENT_GET_CLASS (self)->ip4_start (self, dhcp_anycast_addr, last_ip4_address); } -static GBytes * +static GByteArray * generate_duid_from_machine_id (void) { - const int DUID_SIZE = 18; - guint8 *duid_buffer; + GByteArray *duid; GChecksum *sum; guint8 buffer[32]; /* SHA256 digest size */ gsize sumlen = sizeof (buffer); @@ -525,7 +532,6 @@ generate_duid_from_machine_id (void) uuid_t uuid; gs_free char *machine_id_s = NULL; gs_free char *str = NULL; - GBytes *duid; machine_id_s = nm_utils_machine_id_read (); if (nm_utils_machine_id_parse (machine_id_s, uuid)) { @@ -548,31 +554,36 @@ generate_duid_from_machine_id (void) * u16: type (DUID-UUID = 4) * u8[16]: UUID bytes */ - duid_buffer = g_malloc (DUID_SIZE); - - G_STATIC_ASSERT_EXPR (sizeof (duid_type) == 2); - memcpy (&duid_buffer[0], &duid_type, 2); + duid = g_byte_array_sized_new (18); + g_byte_array_append (duid, (guint8 *) &duid_type, sizeof (duid_type)); /* Since SHA256 is 256 bits, but UUID is 128 bits, we just take the first * 128 bits of the SHA256 as the DUID-UUID. */ - memcpy (&duid_buffer[2], buffer, 16); + g_byte_array_append (duid, buffer, 16); - duid = g_bytes_new_take (duid_buffer, DUID_SIZE); nm_log_dbg (LOGD_DHCP, "dhcp: generated DUID %s", (str = nm_dhcp_utils_duid_to_string (duid))); return duid; } -static GBytes * +static GByteArray * get_duid (NMDhcpClient *self) { - static GBytes *duid = NULL; + static GByteArray *duid = NULL; + GByteArray *copy = NULL; - if (G_UNLIKELY (!duid)) + if (G_UNLIKELY (duid == NULL)) { duid = generate_duid_from_machine_id (); + g_assert (duid); + } + + if (G_LIKELY (duid)) { + copy = g_byte_array_sized_new (duid->len); + g_byte_array_append (copy, duid->data, duid->len); + } - return g_bytes_ref (duid); + return copy; } gboolean @@ -580,6 +591,7 @@ nm_dhcp_client_start_ip6 (NMDhcpClient *self, const char *dhcp_anycast_addr, const struct in6_addr *ll_addr, const char *hostname, + gboolean info_only, NMSettingIP6ConfigPrivacy privacy, guint needed_prefixes) { @@ -604,6 +616,8 @@ nm_dhcp_client_start_ip6 (NMDhcpClient *self, g_clear_pointer (&priv->hostname, g_free); priv->hostname = g_strdup (hostname); + priv->info_only = info_only; + if (priv->timeout == NM_DHCP_TIMEOUT_INFINITY) _LOGI ("activation: beginning transaction (no timeout)"); else @@ -612,6 +626,7 @@ nm_dhcp_client_start_ip6 (NMDhcpClient *self, return NM_DHCP_CLIENT_GET_CLASS (self)->ip6_start (self, dhcp_anycast_addr, ll_addr, + info_only, privacy, priv->duid, needed_prefixes); @@ -796,8 +811,8 @@ nm_dhcp_client_handle_event (gpointer unused, old_state = priv->state; new_state = reason_to_state (self, priv->iface, reason); - _LOGD ("DHCP state '%s' -> '%s' (reason: '%s')", - state_to_string (old_state), state_to_string (new_state), reason); + _LOGD ("DHCP reason '%s' -> state '%s'", + reason, state_to_string (new_state)); if (new_state == NM_DHCP_STATE_BOUND) { GVariantIter iter; @@ -908,16 +923,8 @@ set_property (GObject *object, guint prop_id, const GValue *value, GParamSpec *pspec) { NMDhcpClientPrivate *priv = NM_DHCP_CLIENT_GET_PRIVATE ((NMDhcpClient *) object); - guint flags; switch (prop_id) { - case PROP_FLAGS: - /* construct-only */ - flags = g_value_get_uint (value); - nm_assert ((flags & ~((guint) (NM_DHCP_CLIENT_FLAGS_INFO_ONLY | NM_DHCP_CLIENT_FLAGS_USE_FQDN))) == 0); - priv->info_only = NM_FLAGS_HAS (flags, NM_DHCP_CLIENT_FLAGS_INFO_ONLY); - priv->use_fqdn = NM_FLAGS_HAS (flags, NM_DHCP_CLIENT_FLAGS_USE_FQDN); - break; case PROP_MULTI_IDX: /* construct-only */ priv->multi_idx = g_value_get_pointer (value); @@ -976,8 +983,6 @@ nm_dhcp_client_init (NMDhcpClient *self) priv = G_TYPE_INSTANCE_GET_PRIVATE (self, NM_TYPE_DHCP_CLIENT, NMDhcpClientPrivate); self->_priv = priv; - c_list_init (&self->dhcp_client_lst); - priv->pid = -1; } @@ -992,8 +997,6 @@ dispose (GObject *object) * the DHCP client. */ - nm_assert (c_list_is_empty (&self->dhcp_client_lst)); - watch_cleanup (self); timeout_cleanup (self); @@ -1001,8 +1004,16 @@ dispose (GObject *object) g_clear_pointer (&priv->hostname, g_free); g_clear_pointer (&priv->uuid, g_free); g_clear_pointer (&priv->client_id, g_bytes_unref); - g_clear_pointer (&priv->hwaddr, g_bytes_unref); - g_clear_pointer (&priv->duid, g_bytes_unref); + + if (priv->hwaddr) { + g_byte_array_free (priv->hwaddr, TRUE); + priv->hwaddr = NULL; + } + + if (priv->duid) { + g_byte_array_free (priv->duid, TRUE); + priv->duid = NULL; + } G_OBJECT_CLASS (nm_dhcp_client_parent_class)->dispose (object); @@ -1043,7 +1054,7 @@ nm_dhcp_client_class_init (NMDhcpClientClass *client_class) obj_properties[PROP_HWADDR] = g_param_spec_boxed (NM_DHCP_CLIENT_HWADDR, "", "", - G_TYPE_BYTES, + G_TYPE_BYTE_ARRAY, G_PARAM_READWRITE | G_PARAM_CONSTRUCT_ONLY | G_PARAM_STATIC_STRINGS); @@ -1077,12 +1088,6 @@ nm_dhcp_client_class_init (NMDhcpClientClass *client_class) G_PARAM_READWRITE | G_PARAM_CONSTRUCT_ONLY | G_PARAM_STATIC_STRINGS); - obj_properties[PROP_FLAGS] = - g_param_spec_uint (NM_DHCP_CLIENT_FLAGS, "", "", - 0, G_MAXUINT32, 0, - G_PARAM_WRITABLE | G_PARAM_CONSTRUCT_ONLY | - G_PARAM_STATIC_STRINGS); - g_object_class_install_properties (object_class, _PROPERTY_ENUMS_LAST, obj_properties); signals[SIGNAL_STATE_CHANGED] = diff --git a/src/dhcp/nm-dhcp-client.h b/src/dhcp/nm-dhcp-client.h index 0d92d743..2c634168 100644 --- a/src/dhcp/nm-dhcp-client.h +++ b/src/dhcp/nm-dhcp-client.h @@ -34,16 +34,15 @@ #define NM_IS_DHCP_CLIENT_CLASS(klass) (G_TYPE_CHECK_CLASS_TYPE ((klass), NM_TYPE_DHCP_CLIENT)) #define NM_DHCP_CLIENT_GET_CLASS(obj) (G_TYPE_INSTANCE_GET_CLASS ((obj), NM_TYPE_DHCP_CLIENT, NMDhcpClientClass)) -#define NM_DHCP_CLIENT_ADDR_FAMILY "addr-family" -#define NM_DHCP_CLIENT_FLAGS "flags" -#define NM_DHCP_CLIENT_HWADDR "hwaddr" -#define NM_DHCP_CLIENT_IFINDEX "ifindex" -#define NM_DHCP_CLIENT_INTERFACE "iface" -#define NM_DHCP_CLIENT_MULTI_IDX "multi-idx" -#define NM_DHCP_CLIENT_ROUTE_METRIC "route-metric" +#define NM_DHCP_CLIENT_INTERFACE "iface" +#define NM_DHCP_CLIENT_ADDR_FAMILY "addr-family" +#define NM_DHCP_CLIENT_IFINDEX "ifindex" +#define NM_DHCP_CLIENT_HWADDR "hwaddr" +#define NM_DHCP_CLIENT_UUID "uuid" #define NM_DHCP_CLIENT_ROUTE_TABLE "route-table" -#define NM_DHCP_CLIENT_TIMEOUT "timeout" -#define NM_DHCP_CLIENT_UUID "uuid" +#define NM_DHCP_CLIENT_ROUTE_METRIC "route-metric" +#define NM_DHCP_CLIENT_TIMEOUT "timeout" +#define NM_DHCP_CLIENT_MULTI_IDX "multi-idx" #define NM_DHCP_CLIENT_SIGNAL_STATE_CHANGED "state-changed" #define NM_DHCP_CLIENT_SIGNAL_PREFIX_DELEGATED "prefix-delegated" @@ -65,14 +64,8 @@ struct _NMDhcpClientPrivate; typedef struct { GObject parent; struct _NMDhcpClientPrivate *_priv; - CList dhcp_client_lst; } NMDhcpClient; -typedef enum { - NM_DHCP_CLIENT_FLAGS_INFO_ONLY = (1LL << 0), - NM_DHCP_CLIENT_FLAGS_USE_FQDN = (1LL << 1), -} NMDhcpClientFlags; - typedef struct { GObjectClass parent; @@ -85,13 +78,14 @@ typedef struct { gboolean (*ip6_start) (NMDhcpClient *self, const char *anycast_addr, const struct in6_addr *ll_addr, + gboolean info_only, NMSettingIP6ConfigPrivacy privacy, - GBytes *duid, + const GByteArray *duid, guint needed_prefixes); void (*stop) (NMDhcpClient *self, gboolean release, - GBytes *duid); + const GByteArray *duid); /** * get_duid: @@ -102,7 +96,7 @@ typedef struct { * representation of the DUID. If no DUID is found, %NULL should be * returned. */ - GBytes *(*get_duid) (NMDhcpClient *self); + GByteArray * (*get_duid) (NMDhcpClient *self); /* Signals */ void (*state_changed) (NMDhcpClient *self, @@ -125,9 +119,9 @@ int nm_dhcp_client_get_ifindex (NMDhcpClient *self); const char *nm_dhcp_client_get_uuid (NMDhcpClient *self); -GBytes *nm_dhcp_client_get_duid (NMDhcpClient *self); +const GByteArray *nm_dhcp_client_get_duid (NMDhcpClient *self); -GBytes *nm_dhcp_client_get_hw_addr (NMDhcpClient *self); +const GByteArray *nm_dhcp_client_get_hw_addr (NMDhcpClient *self); guint32 nm_dhcp_client_get_route_table (NMDhcpClient *self); @@ -139,20 +133,20 @@ GBytes *nm_dhcp_client_get_client_id (NMDhcpClient *self); const char *nm_dhcp_client_get_hostname (NMDhcpClient *self); -gboolean nm_dhcp_client_get_info_only (NMDhcpClient *self); - gboolean nm_dhcp_client_get_use_fqdn (NMDhcpClient *self); gboolean nm_dhcp_client_start_ip4 (NMDhcpClient *self, - GBytes *client_id, + const char *dhcp_client_id, const char *dhcp_anycast_addr, const char *hostname, + gboolean use_fqdn, const char *last_ip4_address); gboolean nm_dhcp_client_start_ip6 (NMDhcpClient *self, const char *dhcp_anycast_addr, const struct in6_addr *ll_addr, const char *hostname, + gboolean info_only, NMSettingIP6ConfigPrivacy privacy, guint needed_prefixes); @@ -185,6 +179,8 @@ void nm_dhcp_client_set_client_id_bin (NMDhcpClient *self, guint8 type, const guint8 *client_id, gsize len); +void nm_dhcp_client_set_client_id_str (NMDhcpClient *self, + const char *dhcp_client_id); /***************************************************************************** * Client data @@ -194,6 +190,13 @@ typedef struct { GType (*get_type)(void); const char *name; const char *(*get_path) (void); + GSList *(*get_lease_ip_configs) (struct _NMDedupMultiIndex *multi_idx, + int addr_family, + const char *iface, + int ifindex, + const char *uuid, + guint32 route_table, + guint32 route_metric); } NMDhcpClientFactory; extern const NMDhcpClientFactory _nm_dhcp_client_factory_dhcpcanon; diff --git a/src/dhcp/nm-dhcp-dhclient-utils.c b/src/dhcp/nm-dhcp-dhclient-utils.c index 52923310..4df90d76 100644 --- a/src/dhcp/nm-dhcp-dhclient-utils.c +++ b/src/dhcp/nm-dhcp-dhclient-utils.c @@ -125,7 +125,7 @@ add_ip4_config (GString *str, GBytes *client_id, const char *hostname, gboolean * as long as all the characters are printable. */ for (i = 1; (p[0] == 0) && i < l; i++) { - if (!g_ascii_isprint (p[i]) || p[i] == '\\' || p[i] == '"') + if (!g_ascii_isprint (p[i])) break; } @@ -138,9 +138,8 @@ add_ip4_config (GString *str, GBytes *client_id, const char *hostname, gboolean g_string_append_printf (str, "%02x", (guint8) p[i]); } } else { - /* Printable; just add to the line with type 0 */ + /* Printable; just add to the line minus the 'type' */ g_string_append_c (str, '"'); - g_string_append (str, "\\x00"); g_string_append_len (str, p + 1, l - 1); g_string_append_c (str, '"'); } @@ -178,60 +177,31 @@ read_client_id (const char *str) { gs_free char *s = NULL; char *p; - int i = 0, j = 0; nm_assert (!strncmp (str, CLIENTID_TAG, NM_STRLEN (CLIENTID_TAG))); - str += NM_STRLEN (CLIENTID_TAG); - if (!g_ascii_isspace (*str)) - return NULL; + str += NM_STRLEN (CLIENTID_TAG); while (g_ascii_isspace (*str)) str++; if (*str == '"') { - /* Parse string literal with escape sequences */ s = g_strdup (str + 1); p = strrchr (s, '"'); if (p) *p = '\0'; else return NULL; + } else + s = g_strdup (str); - if (!s[0]) - return NULL; - - while (s[i]) { - if ( s[i] == '\\' - && s[i + 1] == 'x' - && g_ascii_isxdigit (s[i + 2]) - && g_ascii_isxdigit (s[i + 3])) { - s[j++] = (g_ascii_xdigit_value (s[i + 2]) << 4) - + g_ascii_xdigit_value (s[i + 3]); - i += 4; - continue; - } - if ( s[i] == '\\' - && s[i + 1] >= '0' && s[i + 1] <= '7' - && s[1 + 2] >= '0' && s[i + 2] <= '7' - && s[1 + 3] >= '0' && s[i + 3] <= '7') { - s[j++] = ((s[i + 1] - '0') << 6) - + ((s[i + 2] - '0') << 3) - + ( s[i + 3] - '0'); - i += 4; - continue; - } - s[j++] = s[i++]; - } - return g_bytes_new_take (g_steal_pointer (&s), j); - } - - /* Otherwise, try to read a hexadecimal sequence */ - s = g_strdup (str); g_strchomp (s); if (s[strlen (s) - 1] == ';') s[strlen (s) - 1] = '\0'; - return nm_utils_hexstr2bin (s); + if (!s[0]) + return NULL; + + return nm_dhcp_utils_client_id_string_to_bytes (s); } GBytes * @@ -309,7 +279,6 @@ nm_dhcp_dhclient_create_config (const char *interface, g_return_val_if_fail (!anycast_addr || nm_utils_hwaddr_valid (anycast_addr, ETH_ALEN), NULL); g_return_val_if_fail (NM_IN_SET (addr_family, AF_INET, AF_INET6), NULL); - nm_assert (!out_new_client_id || !*out_new_client_id); new_contents = g_string_new (_("# Created by NetworkManager\n")); fqdn_opts = g_ptr_array_sized_new (5); @@ -363,8 +332,6 @@ nm_dhcp_dhclient_create_config (const char *interface, continue; /* Otherwise capture and return the existing client id */ - if (out_new_client_id) - g_clear_pointer (out_new_client_id, g_bytes_unref); NM_SET_OUT (out_new_client_id, read_client_id (p)); } @@ -477,20 +444,14 @@ nm_dhcp_dhclient_create_config (const char *interface, /* Roughly follow what dhclient's quotify_buf() and pretty_escape() functions do */ char * -nm_dhcp_dhclient_escape_duid (GBytes *duid) +nm_dhcp_dhclient_escape_duid (const GByteArray *duid) { char *escaped; - const guint8 *s, *s0; - gsize len; + const guint8 *s = duid->data; char *d; - g_return_val_if_fail (duid, NULL); - - s0 = g_bytes_get_data (duid, &len); - s = s0; - - d = escaped = g_malloc ((len * 4) + 1); - while (s < (s0 + len)) { + d = escaped = g_malloc0 ((duid->len * 4) + 1); + while (s < (duid->data + duid->len)) { if (!g_ascii_isprint (*s)) { *d++ = '\\'; *d++ = '0' + ((*s >> 6) & 0x7); @@ -504,7 +465,6 @@ nm_dhcp_dhclient_escape_duid (GBytes *duid) } else *d++ = *s++; } - *d++ = '\0'; return escaped; } @@ -516,7 +476,7 @@ isoctal (const guint8 *p) && p[2] >= '0' && p[2] <= '7'); } -GBytes * +GByteArray * nm_dhcp_dhclient_unescape_duid (const char *duid) { GByteArray *unescaped; @@ -547,7 +507,7 @@ nm_dhcp_dhclient_unescape_duid (const char *duid) g_byte_array_append (unescaped, &p[i], 1); } - return g_byte_array_free_to_bytes (unescaped); + return unescaped; error: g_byte_array_free (unescaped, TRUE); @@ -556,10 +516,10 @@ error: #define DUID_PREFIX "default-duid \"" -GBytes * +GByteArray * nm_dhcp_dhclient_read_duid (const char *leasefile, GError **error) { - GBytes *duid = NULL; + GByteArray *duid = NULL; char *contents; char **line, **split, *p, *e; @@ -643,3 +603,259 @@ nm_dhcp_dhclient_save_duid (const char *leasefile, g_string_free (s, TRUE); return success; } + +static void +add_lease_option (GHashTable *hash, char *line) +{ + char *spc; + size_t len; + + /* Find the space after "option" */ + spc = strchr (line, ' '); + if (!spc) + return; + + /* Find the option tag's data, which is after the second space */ + if (g_str_has_prefix (line, "option ")) { + while (g_ascii_isspace (*spc)) + spc++; + spc = strchr (spc + 1, ' '); + if (!spc) + return; + } + + /* Split the line at the space */ + *spc = '\0'; + spc++; + + /* Kill the ';' at the end of the line, if any */ + len = strlen (spc); + if (*(spc + len - 1) == ';') + *(spc + len - 1) = '\0'; + + /* Strip leading quote */ + while (g_ascii_isspace (*spc)) + spc++; + if (*spc == '"') + spc++; + + /* Strip trailing quote */ + len = strlen (spc); + if (len > 0 && spc[len - 1] == '"') + spc[len - 1] = '\0'; + + if (spc[0]) + g_hash_table_insert (hash, g_strdup (line), g_strdup (spc)); +} + +#define LEASE_INVALID G_MININT64 +static GTimeSpan +lease_validity_span (const char *str_expire, GDateTime *now) +{ + GDateTime *expire = NULL; + struct tm expire_tm; + GTimeSpan span; + + g_return_val_if_fail (now != NULL, LEASE_INVALID); + g_return_val_if_fail (str_expire != NULL, LEASE_INVALID); + + /* Skip initial number (day of week?) */ + if (!isdigit (*str_expire++)) + return LEASE_INVALID; + if (!isspace (*str_expire++)) + return LEASE_INVALID; + /* Read lease expiration (in UTC) */ + if (!strptime (str_expire, "%t%Y/%m/%d %H:%M:%S", &expire_tm)) + return LEASE_INVALID; + + expire = g_date_time_new_utc (expire_tm.tm_year + 1900, + expire_tm.tm_mon + 1, + expire_tm.tm_mday, + expire_tm.tm_hour, + expire_tm.tm_min, + expire_tm.tm_sec); + if (!expire) + return LEASE_INVALID; + + span = g_date_time_difference (expire, now); + g_date_time_unref (expire); + + /* GDateTime only supports a range of less then 10000 years, so span can + * not overflow or be equal to LEASE_INVALID */ + return span; +} + +/** + * nm_dhcp_dhclient_read_lease_ip_configs: + * @multi_idx: the multi index instance for the ip config object + * @addr_family: whether to read IPv4 or IPv6 leases + * @iface: the interface name to match leases with + * @ifindex: interface index of @iface + * @route_table: the route table for the default route. + * @route_metric: the route metric for the default route. + * @contents: the contents of a dhclient leasefile + * @now: the current UTC date/time; pass %NULL to automatically use current + * UTC time. Testcases may need a different value for 'now' + * + * Reads dhclient leases from @contents and parses them into either + * #NMIP4Config or #NMIP6Config objects depending on the value of @addr_family. + * + * Returns: a #GSList of #NMIP4Config objects (if @addr_family is %AF_INET) or a list of + * #NMIP6Config objects (if @addr_family is %AF_INET6) containing the lease data. + */ +GSList * +nm_dhcp_dhclient_read_lease_ip_configs (NMDedupMultiIndex *multi_idx, + int addr_family, + const char *iface, + int ifindex, + guint32 route_table, + guint32 route_metric, + const char *contents, + GDateTime *now) +{ + GSList *parsed = NULL, *iter, *leases = NULL; + char **line, **split = NULL; + GHashTable *hash = NULL; + gint32 now_monotonic_ts; + + g_return_val_if_fail (contents != NULL, NULL); + nm_assert (NM_IN_SET (addr_family, AF_INET, AF_INET6)); + + split = g_strsplit_set (contents, "\n\r", -1); + if (!split) + return NULL; + + for (line = split; line && *line; line++) { + *line = g_strstrip (*line); + + if (*line[0] == '#') { + /* Comment */ + } else if (!strcmp (*line, "}")) { + /* Lease ends */ + parsed = g_slist_append (parsed, hash); + hash = NULL; + } else if (!strcmp (*line, "lease {")) { + /* Beginning of a new lease */ + if (hash) { + /* Ignore malformed lease that doesn't end before new one starts */ + g_hash_table_destroy (hash); + } + + hash = g_hash_table_new_full (nm_str_hash, g_str_equal, g_free, g_free); + } else if (hash && strlen (*line)) + add_lease_option (hash, *line); + } + g_strfreev (split); + + /* Check if the last lease in the file was properly ended */ + if (hash) { + /* Ignore malformed lease that doesn't end before new one starts */ + g_hash_table_destroy (hash); + hash = NULL; + } + + if (now) + g_date_time_ref (now); + else + now = g_date_time_new_now_utc (); + now_monotonic_ts = nm_utils_get_monotonic_timestamp_s (); + + for (iter = parsed; iter; iter = g_slist_next (iter)) { + NMIP4Config *ip4; + NMPlatformIP4Address address; + const char *value; + GTimeSpan expiry; + guint32 tmp, gw = 0; + + hash = iter->data; + + /* Make sure this lease is for the interface we want */ + value = g_hash_table_lookup (hash, "interface"); + if (!value || strcmp (value, iface)) + continue; + + value = g_hash_table_lookup (hash, "expire"); + if (!value) + continue; + expiry = lease_validity_span (value, now); + if (expiry == LEASE_INVALID) + continue; + + /* scale expiry to seconds (and CLAMP into the range of guint32) */ + expiry = CLAMP (expiry / G_TIME_SPAN_SECOND, 0, NM_PLATFORM_LIFETIME_PERMANENT-1); + if (expiry <= 0) { + /* the address is already expired. Don't even add it. */ + continue; + } + + memset (&address, 0, sizeof (address)); + + /* IP4 address */ + value = g_hash_table_lookup (hash, "fixed-address"); + if (!value) + continue; + if (!inet_pton (AF_INET, value, &address.address)) + continue; + address.peer_address = address.address; + + /* Gateway */ + value = g_hash_table_lookup (hash, "option routers"); + if (!value) + continue; + if (!inet_pton (AF_INET, value, &gw)) + continue; + + /* Netmask */ + value = g_hash_table_lookup (hash, "option subnet-mask"); + if (value && inet_pton (AF_INET, value, &tmp)) + address.plen = nm_utils_ip4_netmask_to_prefix (tmp); + + /* Get default netmask for the IP according to appropriate class. */ + if (!address.plen) + address.plen = _nm_utils_ip4_get_default_prefix (address.address); + + address.timestamp = now_monotonic_ts; + address.lifetime = address.preferred = expiry; + address.addr_source = NM_IP_CONFIG_SOURCE_DHCP; + + ip4 = nm_ip4_config_new (multi_idx, ifindex); + nm_ip4_config_add_address (ip4, &address); + + { + const NMPlatformIP4Route r = { + .rt_source = NM_IP_CONFIG_SOURCE_DHCP, + .gateway = gw, + .table_coerced = nm_platform_route_table_coerce (route_table), + .metric = route_metric, + }; + + nm_ip4_config_add_route (ip4, &r, NULL); + } + + value = g_hash_table_lookup (hash, "option domain-name-servers"); + if (value) { + char **dns, **dns_iter; + + dns = g_strsplit_set (value, ",", -1); + for (dns_iter = dns; dns_iter && *dns_iter; dns_iter++) { + if (inet_pton (AF_INET, *dns_iter, &tmp)) + nm_ip4_config_add_nameserver (ip4, tmp); + } + if (dns) + g_strfreev (dns); + } + + value = g_hash_table_lookup (hash, "option domain-name"); + if (value && value[0]) + nm_ip4_config_add_domain (ip4, value); + + /* FIXME: static routes */ + + leases = g_slist_append (leases, ip4); + } + + g_date_time_unref (now); + g_slist_free_full (parsed, (GDestroyNotify) g_hash_table_destroy); + return leases; +} + diff --git a/src/dhcp/nm-dhcp-dhclient-utils.h b/src/dhcp/nm-dhcp-dhclient-utils.h index fab9196a..94de1963 100644 --- a/src/dhcp/nm-dhcp-dhclient-utils.h +++ b/src/dhcp/nm-dhcp-dhclient-utils.h @@ -33,16 +33,25 @@ char *nm_dhcp_dhclient_create_config (const char *interface, const char *orig_contents, GBytes **out_new_client_id); -char *nm_dhcp_dhclient_escape_duid (GBytes *duid); +char *nm_dhcp_dhclient_escape_duid (const GByteArray *duid); -GBytes *nm_dhcp_dhclient_unescape_duid (const char *duid); +GByteArray *nm_dhcp_dhclient_unescape_duid (const char *duid); -GBytes *nm_dhcp_dhclient_read_duid (const char *leasefile, GError **error); +GByteArray *nm_dhcp_dhclient_read_duid (const char *leasefile, GError **error); gboolean nm_dhcp_dhclient_save_duid (const char *leasefile, const char *escaped_duid, GError **error); +GSList *nm_dhcp_dhclient_read_lease_ip_configs (struct _NMDedupMultiIndex *multi_idx, + int addr_family, + const char *iface, + int ifindex, + guint32 route_table, + guint32 route_metric, + const char *contents, + GDateTime *now); + GBytes *nm_dhcp_dhclient_get_client_id_from_config_file (const char *path); #endif /* __NETWORKMANAGER_DHCP_DHCLIENT_UTILS_H__ */ diff --git a/src/dhcp/nm-dhcp-dhclient.c b/src/dhcp/nm-dhcp-dhclient.c index 738e9f91..74d920a8 100644 --- a/src/dhcp/nm-dhcp-dhclient.c +++ b/src/dhcp/nm-dhcp-dhclient.c @@ -158,6 +158,32 @@ get_dhclient_leasefile (int addr_family, return NULL; } +static GSList * +nm_dhcp_dhclient_get_lease_ip_configs (NMDedupMultiIndex *multi_idx, + int addr_family, + const char *iface, + int ifindex, + const char *uuid, + guint32 route_table, + guint32 route_metric) +{ + gs_free char *contents = NULL; + gs_free char *leasefile = NULL; + + leasefile = get_dhclient_leasefile (addr_family, iface, uuid, NULL); + if (!leasefile) + return NULL; + + if ( g_file_test (leasefile, G_FILE_TEST_EXISTS) + && g_file_get_contents (leasefile, &contents, NULL, NULL) + && contents + && contents[0]) { + return nm_dhcp_dhclient_read_lease_ip_configs (multi_idx, addr_family, iface, ifindex, + route_table, route_metric, contents, NULL); + } + return NULL; +} + static gboolean merge_dhclient_config (NMDhcpDhclient *self, int addr_family, @@ -312,7 +338,7 @@ create_dhclient_config (NMDhcpDhclient *self, static gboolean dhclient_start (NMDhcpClient *client, const char *mode_opt, - GBytes *duid, + const GByteArray *duid, gboolean release, pid_t *out_pid, int prefixes) @@ -413,19 +439,19 @@ dhclient_start (NMDhcpClient *client, while (prefixes--) g_ptr_array_add (argv, (gpointer) "-P"); } - g_ptr_array_add (argv, (gpointer) "-sf"); /* Set script file */ + g_ptr_array_add (argv, (gpointer) "-sf"); /* Set script file */ g_ptr_array_add (argv, (gpointer) nm_dhcp_helper_path); if (pid_file) { - g_ptr_array_add (argv, (gpointer) "-pf"); /* Set pid file */ + g_ptr_array_add (argv, (gpointer) "-pf"); /* Set pid file */ g_ptr_array_add (argv, (gpointer) pid_file); } - g_ptr_array_add (argv, (gpointer) "-lf"); /* Set lease file */ + g_ptr_array_add (argv, (gpointer) "-lf"); /* Set lease file */ g_ptr_array_add (argv, (gpointer) priv->lease_file); if (priv->conf_file) { - g_ptr_array_add (argv, (gpointer) "-cf"); /* Set interface config file */ + g_ptr_array_add (argv, (gpointer) "-cf"); /* Set interface config file */ g_ptr_array_add (argv, (gpointer) priv->conf_file); } @@ -492,10 +518,8 @@ ip4_start (NMDhcpClient *client, const char *dhcp_anycast_addr, const char *last priv->conf_file = create_dhclient_config (self, AF_INET, iface, uuid, client_id, dhcp_anycast_addr, hostname, timeout, use_fqdn, &new_client_id); if (priv->conf_file) { - if (new_client_id) { - nm_assert (!client_id); + if (new_client_id) nm_dhcp_client_set_client_id (client, new_client_id); - } success = dhclient_start (client, NULL, NULL, FALSE, NULL, 0); } else _LOGW ("error creating dhclient configuration file"); @@ -507,8 +531,9 @@ static gboolean ip6_start (NMDhcpClient *client, const char *dhcp_anycast_addr, const struct in6_addr *ll_addr, + gboolean info_only, NMSettingIP6ConfigPrivacy privacy, - GBytes *duid, + const GByteArray *duid, guint needed_prefixes) { NMDhcpDhclient *self = NM_DHCP_DHCLIENT (client); @@ -528,19 +553,16 @@ ip6_start (NMDhcpClient *client, return FALSE; } - return dhclient_start (client, - nm_dhcp_client_get_info_only (NM_DHCP_CLIENT (self)) - ? "-S" - : "-N", - duid, FALSE, NULL, needed_prefixes); + return dhclient_start (client, info_only ? "-S" : "-N", duid, FALSE, NULL, needed_prefixes); } static void -stop (NMDhcpClient *client, gboolean release, GBytes *duid) +stop (NMDhcpClient *client, gboolean release, const GByteArray *duid) { NMDhcpDhclient *self = NM_DHCP_DHCLIENT (client); NMDhcpDhclientPrivate *priv = NM_DHCP_DHCLIENT_GET_PRIVATE (self); + /* Chain up to parent */ NM_DHCP_CLIENT_CLASS (nm_dhcp_dhclient_parent_class)->stop (client, release, duid); if (priv->conf_file) @@ -581,12 +603,12 @@ state_changed (NMDhcpClient *client, nm_dhcp_client_set_client_id (client, client_id); } -static GBytes * +static GByteArray * get_duid (NMDhcpClient *client) { NMDhcpDhclient *self = NM_DHCP_DHCLIENT (client); NMDhcpDhclientPrivate *priv = NM_DHCP_DHCLIENT_GET_PRIVATE (self); - GBytes *duid = NULL; + GByteArray *duid = NULL; char *leasefile; GError *error = NULL; @@ -620,7 +642,7 @@ get_duid (NMDhcpClient *client) } /* return our DUID, otherwise let the parent class make a default DUID */ - return duid ?: NM_DHCP_CLIENT_CLASS (nm_dhcp_dhclient_parent_class)->get_duid (client); + return duid ? duid : NM_DHCP_CLIENT_CLASS (nm_dhcp_dhclient_parent_class)->get_duid (client); } /*****************************************************************************/ @@ -695,6 +717,7 @@ const NMDhcpClientFactory _nm_dhcp_client_factory_dhclient = { .name = "dhclient", .get_type = nm_dhcp_dhclient_get_type, .get_path = nm_dhcp_dhclient_get_path, + .get_lease_ip_configs = nm_dhcp_dhclient_get_lease_ip_configs, }; #endif /* WITH_DHCLIENT */ diff --git a/src/dhcp/nm-dhcp-dhcpcanon.c b/src/dhcp/nm-dhcp-dhcpcanon.c index 82b3db4f..d7ddd194 100644 --- a/src/dhcp/nm-dhcp-dhcpcanon.c +++ b/src/dhcp/nm-dhcp-dhcpcanon.c @@ -80,7 +80,7 @@ nm_dhcp_dhcpcanon_get_path (void) static gboolean dhcpcanon_start (NMDhcpClient *client, const char *mode_opt, - GBytes *duid, + const GByteArray *duid, gboolean release, pid_t *out_pid, int prefixes) @@ -118,16 +118,16 @@ dhcpcanon_start (NMDhcpClient *client, argv = g_ptr_array_new (); g_ptr_array_add (argv, (gpointer) dhcpcanon_path); - g_ptr_array_add (argv, (gpointer) "-sf"); /* Set script file */ + g_ptr_array_add (argv, (gpointer) "-sf"); /* Set script file */ g_ptr_array_add (argv, (gpointer) nm_dhcp_helper_path); if (pid_file) { - g_ptr_array_add (argv, (gpointer) "-pf"); /* Set pid file */ + g_ptr_array_add (argv, (gpointer) "-pf"); /* Set pid file */ g_ptr_array_add (argv, (gpointer) pid_file); } if (priv->conf_file) { - g_ptr_array_add (argv, (gpointer) "-cf"); /* Set interface config file */ + g_ptr_array_add (argv, (gpointer) "-cf"); /* Set interface config file */ g_ptr_array_add (argv, (gpointer) priv->conf_file); } @@ -179,8 +179,9 @@ static gboolean ip6_start (NMDhcpClient *client, const char *dhcp_anycast_addr, const struct in6_addr *ll_addr, + gboolean info_only, NMSettingIP6ConfigPrivacy privacy, - GBytes *duid, + const GByteArray *duid, guint needed_prefixes) { NMDhcpDhcpcanon *self = NM_DHCP_DHCPCANON (client); @@ -189,7 +190,7 @@ ip6_start (NMDhcpClient *client, return FALSE; } static void -stop (NMDhcpClient *client, gboolean release, GBytes *duid) +stop (NMDhcpClient *client, gboolean release, const GByteArray *duid) { NMDhcpDhcpcanon *self = NM_DHCP_DHCPCANON (client); NMDhcpDhcpcanonPrivate *priv = NM_DHCP_DHCPCANON_GET_PRIVATE (self); @@ -265,6 +266,7 @@ const NMDhcpClientFactory _nm_dhcp_client_factory_dhcpcanon = { .name = "dhcpcanon", .get_type = nm_dhcp_dhcpcanon_get_type, .get_path = nm_dhcp_dhcpcanon_get_path, + .get_lease_ip_configs = NULL, }; #endif /* WITH_DHCPCANON */ diff --git a/src/dhcp/nm-dhcp-dhcpcd.c b/src/dhcp/nm-dhcp-dhcpcd.c index c4bcb084..66a31acf 100644 --- a/src/dhcp/nm-dhcp-dhcpcd.c +++ b/src/dhcp/nm-dhcp-dhcpcd.c @@ -114,18 +114,18 @@ ip4_start (NMDhcpClient *client, const char *dhcp_anycast_addr, const char *last argv = g_ptr_array_new (); g_ptr_array_add (argv, (gpointer) dhcpcd_path); - g_ptr_array_add (argv, (gpointer) "-B"); /* Don't background on lease (disable fork()) */ + g_ptr_array_add (argv, (gpointer) "-B"); /* Don't background on lease (disable fork()) */ - g_ptr_array_add (argv, (gpointer) "-K"); /* Disable built-in carrier detection */ + g_ptr_array_add (argv, (gpointer) "-K"); /* Disable built-in carrier detection */ - g_ptr_array_add (argv, (gpointer) "-L"); /* Disable built-in IPv4LL */ + g_ptr_array_add (argv, (gpointer) "-L"); /* Disable built-in IPv4LL */ /* --noarp. Don't request or claim the address by ARP; this also disables IPv4LL. */ g_ptr_array_add (argv, (gpointer) "-A"); - g_ptr_array_add (argv, (gpointer) "-G"); /* Let NM handle routing */ + g_ptr_array_add (argv, (gpointer) "-G"); /* Let NM handle routing */ - g_ptr_array_add (argv, (gpointer) "-c"); /* Set script file */ + g_ptr_array_add (argv, (gpointer) "-c"); /* Set script file */ g_ptr_array_add (argv, (gpointer) nm_dhcp_helper_path); #ifdef DHCPCD_SUPPORTS_IPV6 @@ -177,8 +177,9 @@ static gboolean ip6_start (NMDhcpClient *client, const char *dhcp_anycast_addr, const struct in6_addr *ll_addr, + gboolean info_only, NMSettingIP6ConfigPrivacy privacy, - GBytes *duid, + const GByteArray *duid, guint needed_prefixes) { NMDhcpDhcpcd *self = NM_DHCP_DHCPCD (client); @@ -188,11 +189,12 @@ ip6_start (NMDhcpClient *client, } static void -stop (NMDhcpClient *client, gboolean release, GBytes *duid) +stop (NMDhcpClient *client, gboolean release, const GByteArray *duid) { NMDhcpDhcpcd *self = NM_DHCP_DHCPCD (client); NMDhcpDhcpcdPrivate *priv = NM_DHCP_DHCPCD_GET_PRIVATE (self); + /* Chain up to parent */ NM_DHCP_CLIENT_CLASS (nm_dhcp_dhcpcd_parent_class)->stop (client, release, duid); if (priv->pid_file) { @@ -251,6 +253,7 @@ const NMDhcpClientFactory _nm_dhcp_client_factory_dhcpcd = { .name = "dhcpcd", .get_type = nm_dhcp_dhcpcd_get_type, .get_path = nm_dhcp_dhcpcd_get_path, + .get_lease_ip_configs = NULL, }; #endif /* WITH_DHCPCD */ diff --git a/src/dhcp/nm-dhcp-helper.c b/src/dhcp/nm-dhcp-helper.c index 8ea55061..f50c5cec 100644 --- a/src/dhcp/nm-dhcp-helper.c +++ b/src/dhcp/nm-dhcp-helper.c @@ -134,6 +134,8 @@ main (int argc, char *argv[]) guint try_count = 0; gint64 time_end; + nm_g_type_init (); + /* FIXME: g_dbus_connection_new_for_address_sync() tries to connect to the socket in * non-blocking mode, which can easily fail with EAGAIN, causing the creation of the * socket to fail with "Could not connect: Resource temporarily unavailable". diff --git a/src/dhcp/nm-dhcp-listener.c b/src/dhcp/nm-dhcp-listener.c index d7d38e54..1cce5a1c 100644 --- a/src/dhcp/nm-dhcp-listener.c +++ b/src/dhcp/nm-dhcp-listener.c @@ -33,7 +33,7 @@ #include "nm-dhcp-client.h" #include "nm-dhcp-manager.h" #include "nm-core-internal.h" -#include "nm-dbus-manager.h" +#include "nm-bus-manager.h" #include "NetworkManagerUtils.h" #define PRIV_SOCK_PATH NMRUNDIR "/private-dhcp" @@ -60,7 +60,7 @@ const NMDhcpClientFactory *const _nm_dhcp_manager_factories[4] = { /*****************************************************************************/ typedef struct { - NMDBusManager * dbus_mgr; + NMBusManager * dbus_mgr; gulong new_conn_id; gulong dis_conn_id; GHashTable * connections; @@ -192,52 +192,70 @@ _method_call (GDBusConnection *connection, { NMDhcpListener *self = NM_DHCP_LISTENER (user_data); - if ( !nm_streq (interface_name, NM_DHCP_HELPER_SERVER_INTERFACE_NAME) - || !nm_streq (method_name, NM_DHCP_HELPER_SERVER_METHOD_NOTIFY)) { - g_dbus_method_invocation_return_error (invocation, - G_DBUS_ERROR, - G_DBUS_ERROR_UNKNOWN_METHOD, - "Unknown method %s", - method_name); - return; - } + if (!nm_streq0 (interface_name, NM_DHCP_HELPER_SERVER_INTERFACE_NAME)) + g_return_if_reached (); + if (!nm_streq0 (method_name, NM_DHCP_HELPER_SERVER_METHOD_NOTIFY)) + g_return_if_reached (); + if (!g_variant_is_of_type (parameters, G_VARIANT_TYPE ("(a{sv})"))) + g_return_if_reached (); _method_call_handle (self, parameters); + g_dbus_method_invocation_return_value (invocation, NULL); } -static GDBusInterfaceInfo *const interface_info = NM_DEFINE_GDBUS_INTERFACE_INFO ( - NM_DHCP_HELPER_SERVER_INTERFACE_NAME, - .methods = NM_DEFINE_GDBUS_METHOD_INFOS ( - NM_DEFINE_GDBUS_METHOD_INFO ( - NM_DHCP_HELPER_SERVER_METHOD_NOTIFY, - .in_args = NM_DEFINE_GDBUS_ARG_INFOS ( - NM_DEFINE_GDBUS_ARG_INFO ("data", "a{sv}"), - ), - ), - ), -); - static guint _dbus_connection_register_object (NMDhcpListener *self, GDBusConnection *connection, GError **error) { - static const GDBusInterfaceVTable interface_vtable = { + static GDBusArgInfo arg_info_notify_in = { + .ref_count = -1, + .name = "data", + .signature = "a{sv}", + .annotations = NULL, + }; + static GDBusArgInfo *arg_infos_notify[] = { + &arg_info_notify_in, + NULL, + }; + static GDBusMethodInfo method_info_notify = { + .ref_count = -1, + .name = NM_DHCP_HELPER_SERVER_METHOD_NOTIFY, + .in_args = arg_infos_notify, + .out_args = NULL, + .annotations = NULL, + }; + static GDBusMethodInfo *method_infos[] = { + &method_info_notify, + NULL, + }; + static GDBusInterfaceInfo interface_info = { + .ref_count = -1, + .name = NM_DHCP_HELPER_SERVER_INTERFACE_NAME, + .methods = method_infos, + .signals = NULL, + .properties = NULL, + .annotations = NULL, + }; + + static GDBusInterfaceVTable interface_vtable = { .method_call = _method_call, + .get_property = NULL, + .set_property = NULL, }; return g_dbus_connection_register_object (connection, NM_DHCP_HELPER_SERVER_OBJECT_PATH, - interface_info, - NM_UNCONST_PTR (GDBusInterfaceVTable, &interface_vtable), + &interface_info, + &interface_vtable, self, NULL, error); } static void -new_connection_cb (NMDBusManager *mgr, +new_connection_cb (NMBusManager *mgr, GDBusConnection *connection, GDBusObjectManager *manager, NMDhcpListener *self) @@ -260,7 +278,7 @@ new_connection_cb (NMDBusManager *mgr, } static void -dis_connection_cb (NMDBusManager *mgr, +dis_connection_cb (NMBusManager *mgr, GDBusConnection *connection, NMDhcpListener *self) { @@ -282,18 +300,18 @@ nm_dhcp_listener_init (NMDhcpListener *self) NMDhcpListenerPrivate *priv = NM_DHCP_LISTENER_GET_PRIVATE (self); /* Maps GDBusConnection :: signal-id */ - priv->connections = g_hash_table_new (nm_direct_hash, NULL); + priv->connections = g_hash_table_new (NULL, NULL); - priv->dbus_mgr = nm_dbus_manager_get (); + priv->dbus_mgr = nm_bus_manager_get (); /* Register the socket our DHCP clients will return lease info on */ - nm_dbus_manager_private_server_register (priv->dbus_mgr, PRIV_SOCK_PATH, PRIV_SOCK_TAG); + nm_bus_manager_private_server_register (priv->dbus_mgr, PRIV_SOCK_PATH, PRIV_SOCK_TAG); priv->new_conn_id = g_signal_connect (priv->dbus_mgr, - NM_DBUS_MANAGER_PRIVATE_CONNECTION_NEW "::" PRIV_SOCK_TAG, + NM_BUS_MANAGER_PRIVATE_CONNECTION_NEW "::" PRIV_SOCK_TAG, G_CALLBACK (new_connection_cb), self); priv->dis_conn_id = g_signal_connect (priv->dbus_mgr, - NM_DBUS_MANAGER_PRIVATE_CONNECTION_DISCONNECTED "::" PRIV_SOCK_TAG, + NM_BUS_MANAGER_PRIVATE_CONNECTION_DISCONNECTED "::" PRIV_SOCK_TAG, G_CALLBACK (dis_connection_cb), self); } diff --git a/src/dhcp/nm-dhcp-manager.c b/src/dhcp/nm-dhcp-manager.c index bf22872d..f5c7c84b 100644 --- a/src/dhcp/nm-dhcp-manager.c +++ b/src/dhcp/nm-dhcp-manager.c @@ -43,8 +43,8 @@ typedef struct { const NMDhcpClientFactory *client_factory; - char *default_hostname; - CList dhcp_client_lst_head; + GHashTable * clients; + char * default_hostname; } NMDhcpManagerPrivate; struct _NMDhcpManager { @@ -98,17 +98,21 @@ static NMDhcpClient * get_client_for_ifindex (NMDhcpManager *manager, int addr_family, int ifindex) { NMDhcpManagerPrivate *priv; - NMDhcpClient *client; + GHashTableIter iter; + gpointer value; g_return_val_if_fail (NM_IS_DHCP_MANAGER (manager), NULL); g_return_val_if_fail (ifindex > 0, NULL); priv = NM_DHCP_MANAGER_GET_PRIVATE (manager); - c_list_for_each_entry (client, &priv->dhcp_client_lst_head, dhcp_client_lst) { - if ( nm_dhcp_client_get_ifindex (client) == ifindex - && nm_dhcp_client_get_addr_family (client) == addr_family) - return client; + g_hash_table_iter_init (&iter, priv->clients); + while (g_hash_table_iter_next (&iter, NULL, &value)) { + NMDhcpClient *candidate = NM_DHCP_CLIENT (value); + + if ( nm_dhcp_client_get_ifindex (candidate) == ifindex + && nm_dhcp_client_get_addr_family (candidate) == addr_family) + return candidate; } return NULL; @@ -125,19 +129,13 @@ static void remove_client (NMDhcpManager *self, NMDhcpClient *client) { g_signal_handlers_disconnect_by_func (client, client_state_changed, self); - c_list_unlink (&client->dhcp_client_lst); /* Stopping the client is left up to the controlling device * explicitly since we may want to quit NetworkManager but not terminate * the DHCP client. */ -} -static void -remove_client_unref (NMDhcpManager *self, NMDhcpClient *client) -{ - remove_client (self, client); - g_object_unref (client); + g_hash_table_remove (NM_DHCP_MANAGER_GET_PRIVATE (self)->clients, client); } static void @@ -149,7 +147,7 @@ client_state_changed (NMDhcpClient *client, NMDhcpManager *self) { if (state >= NM_DHCP_STATE_TIMEOUT) - remove_client_unref (self, client); + remove_client (self, client); } static NMDhcpClient * @@ -158,12 +156,12 @@ client_start (NMDhcpManager *self, NMDedupMultiIndex *multi_idx, const char *iface, int ifindex, - GBytes *hwaddr, + const GByteArray *hwaddr, const char *uuid, guint32 route_table, guint32 route_metric, const struct in6_addr *ipv6_ll_addr, - GBytes *dhcp_client_id, + const char *dhcp_client_id, guint32 timeout, const char *dhcp_anycast_addr, const char *hostname, @@ -181,21 +179,23 @@ client_start (NMDhcpManager *self, g_return_val_if_fail (NM_IS_DHCP_MANAGER (self), NULL); g_return_val_if_fail (ifindex > 0, NULL); g_return_val_if_fail (uuid != NULL, NULL); - g_return_val_if_fail (!dhcp_client_id || g_bytes_get_size (dhcp_client_id) >= 2, NULL); priv = NM_DHCP_MANAGER_GET_PRIVATE (self); + /* Ensure we have a usable DHCP client */ if (!priv->client_factory) return NULL; /* Kill any old client instance */ client = get_client_for_ifindex (self, addr_family, ifindex); if (client) { + g_object_ref (client); remove_client (self, client); nm_dhcp_client_stop (client, FALSE); g_object_unref (client); } + /* And make a new one */ client = g_object_new (priv->client_factory->get_type (), NM_DHCP_CLIENT_MULTI_IDX, multi_idx, NM_DHCP_CLIENT_ADDR_FAMILY, addr_family, @@ -206,26 +206,21 @@ client_start (NMDhcpManager *self, NM_DHCP_CLIENT_ROUTE_TABLE, (guint) route_table, NM_DHCP_CLIENT_ROUTE_METRIC, (guint) route_metric, NM_DHCP_CLIENT_TIMEOUT, (guint) timeout, - NM_DHCP_CLIENT_FLAGS, (guint) (0 - | (hostname_use_fqdn ? NM_DHCP_CLIENT_FLAGS_USE_FQDN : 0) - | (info_only ? NM_DHCP_CLIENT_FLAGS_INFO_ONLY : 0) - ), NULL); - nm_assert (client && c_list_is_empty (&client->dhcp_client_lst)); - c_list_link_tail (&priv->dhcp_client_lst_head, &client->dhcp_client_lst); + g_hash_table_insert (NM_DHCP_MANAGER_GET_PRIVATE (self)->clients, client, g_object_ref (client)); g_signal_connect (client, NM_DHCP_CLIENT_SIGNAL_STATE_CHANGED, G_CALLBACK (client_state_changed), self); if (addr_family == AF_INET) - success = nm_dhcp_client_start_ip4 (client, dhcp_client_id, dhcp_anycast_addr, hostname, last_ip4_address); + success = nm_dhcp_client_start_ip4 (client, dhcp_client_id, dhcp_anycast_addr, hostname, hostname_use_fqdn, last_ip4_address); else - success = nm_dhcp_client_start_ip6 (client, dhcp_anycast_addr, ipv6_ll_addr, hostname, privacy, needed_prefixes); + success = nm_dhcp_client_start_ip6 (client, dhcp_anycast_addr, ipv6_ll_addr, hostname, info_only, privacy, needed_prefixes); if (!success) { - remove_client_unref (self, client); - return NULL; + remove_client (self, client); + client = NULL; } - return g_object_ref (client); + return client; } /* Caller owns a reference to the NMDhcpClient on return */ @@ -234,14 +229,14 @@ nm_dhcp_manager_start_ip4 (NMDhcpManager *self, NMDedupMultiIndex *multi_idx, const char *iface, int ifindex, - GBytes *hwaddr, + const GByteArray *hwaddr, const char *uuid, guint32 route_table, guint32 route_metric, gboolean send_hostname, const char *dhcp_hostname, const char *dhcp_fqdn, - GBytes *dhcp_client_id, + const char *dhcp_client_id, guint32 timeout, const char *dhcp_anycast_addr, const char *last_ip_address) @@ -290,7 +285,7 @@ nm_dhcp_manager_start_ip6 (NMDhcpManager *self, NMDedupMultiIndex *multi_idx, const char *iface, int ifindex, - GBytes *hwaddr, + const GByteArray *hwaddr, const struct in6_addr *ll_addr, const char *uuid, guint32 route_table, @@ -333,6 +328,31 @@ nm_dhcp_manager_set_default_hostname (NMDhcpManager *manager, const char *hostna priv->default_hostname = g_strdup (hostname); } +GSList * +nm_dhcp_manager_get_lease_ip_configs (NMDhcpManager *self, + NMDedupMultiIndex *multi_idx, + int addr_family, + const char *iface, + int ifindex, + const char *uuid, + guint32 route_table, + guint32 route_metric) +{ + NMDhcpManagerPrivate *priv; + + g_return_val_if_fail (NM_IS_DHCP_MANAGER (self), NULL); + g_return_val_if_fail (iface != NULL, NULL); + g_return_val_if_fail (ifindex >= -1, NULL); + g_return_val_if_fail (uuid != NULL, NULL); + g_return_val_if_fail (NM_IN_SET (addr_family, AF_INET, AF_INET6), NULL); + + priv = NM_DHCP_MANAGER_GET_PRIVATE (self); + if ( priv->client_factory + && priv->client_factory->get_lease_ip_configs) + return priv->client_factory->get_lease_ip_configs (multi_idx, addr_family, iface, ifindex, uuid, route_table, route_metric); + return NULL; +} + const char * nm_dhcp_manager_get_config (NMDhcpManager *self) { @@ -358,8 +378,6 @@ nm_dhcp_manager_init (NMDhcpManager *self) int i; const NMDhcpClientFactory *client_factory = NULL; - c_list_init (&priv->dhcp_client_lst_head); - for (i = 0; i < G_N_ELEMENTS (_nm_dhcp_manager_factories); i++) { const NMDhcpClientFactory *f = _nm_dhcp_manager_factories[i]; @@ -411,21 +429,38 @@ nm_dhcp_manager_init (NMDhcpManager *self) nm_log_info (LOGD_DHCP, "dhcp-init: Using DHCP client '%s'", client_factory->name); priv->client_factory = client_factory; + priv->clients = g_hash_table_new_full (g_direct_hash, g_direct_equal, + NULL, + (GDestroyNotify) g_object_unref); } static void dispose (GObject *object) { - NMDhcpManager *self = NM_DHCP_MANAGER (object); - NMDhcpManagerPrivate *priv = NM_DHCP_MANAGER_GET_PRIVATE (self); - NMDhcpClient *client, *client_safe; - - c_list_for_each_entry_safe (client, client_safe, &priv->dhcp_client_lst_head, dhcp_client_lst) - remove_client_unref (self, client); + NMDhcpManagerPrivate *priv = NM_DHCP_MANAGER_GET_PRIVATE ((NMDhcpManager *) object); + GList *values, *iter; + + if (priv->clients) { + values = g_hash_table_get_values (priv->clients); + for (iter = values; iter; iter = g_list_next (iter)) + remove_client (NM_DHCP_MANAGER (object), NM_DHCP_CLIENT (iter->data)); + g_list_free (values); + } G_OBJECT_CLASS (nm_dhcp_manager_parent_class)->dispose (object); +} + +static void +finalize (GObject *object) +{ + NMDhcpManagerPrivate *priv = NM_DHCP_MANAGER_GET_PRIVATE ((NMDhcpManager *) object); + + g_free (priv->default_hostname); + + if (priv->clients) + g_hash_table_destroy (priv->clients); - nm_clear_g_free (&priv->default_hostname); + G_OBJECT_CLASS (nm_dhcp_manager_parent_class)->finalize (object); } static void @@ -433,5 +468,6 @@ nm_dhcp_manager_class_init (NMDhcpManagerClass *manager_class) { GObjectClass *object_class = G_OBJECT_CLASS (manager_class); + object_class->finalize = finalize; object_class->dispose = dispose; } diff --git a/src/dhcp/nm-dhcp-manager.h b/src/dhcp/nm-dhcp-manager.h index f8a7e31d..078117ff 100644 --- a/src/dhcp/nm-dhcp-manager.h +++ b/src/dhcp/nm-dhcp-manager.h @@ -49,14 +49,14 @@ NMDhcpClient * nm_dhcp_manager_start_ip4 (NMDhcpManager *manager, struct _NMDedupMultiIndex *multi_idx, const char *iface, int ifindex, - GBytes *hwaddr, + const GByteArray *hwaddr, const char *uuid, guint32 route_table, guint32 route_metric, gboolean send_hostname, const char *dhcp_hostname, const char *dhcp_fqdn, - GBytes *dhcp_client_id, + const char *dhcp_client_id, guint32 timeout, const char *dhcp_anycast_addr, const char *last_ip_address); @@ -65,7 +65,7 @@ NMDhcpClient * nm_dhcp_manager_start_ip6 (NMDhcpManager *manager, struct _NMDedupMultiIndex *multi_idx, const char *iface, int ifindex, - GBytes *hwaddr, + const GByteArray *hwaddr, const struct in6_addr *ll_addr, const char *uuid, guint32 route_table, @@ -78,6 +78,15 @@ NMDhcpClient * nm_dhcp_manager_start_ip6 (NMDhcpManager *manager, NMSettingIP6ConfigPrivacy privacy, guint needed_prefixes); +GSList * nm_dhcp_manager_get_lease_ip_configs (NMDhcpManager *self, + struct _NMDedupMultiIndex *multi_idx, + int addr_family, + const char *iface, + int ifindex, + const char *uuid, + guint32 route_table, + guint32 route_metric); + /* For testing only */ extern const char* nm_dhcp_helper_path; diff --git a/src/dhcp/nm-dhcp-systemd.c b/src/dhcp/nm-dhcp-systemd.c index 4f37f069..f79b7cb1 100644 --- a/src/dhcp/nm-dhcp-systemd.c +++ b/src/dhcp/nm-dhcp-systemd.c @@ -29,7 +29,6 @@ #include <net/if_arp.h> #include "nm-utils/nm-dedup-multi.h" -#include "nm-utils/unaligned.h" #include "nm-utils.h" #include "nm-dhcp-utils.h" @@ -61,7 +60,8 @@ typedef struct { guint request_count; - bool privacy:1; + gboolean privacy; + gboolean info_only; } NMDhcpSystemdPrivate; struct _NMDhcpSystemd { @@ -451,6 +451,36 @@ get_leasefile_path (int addr_family, const char *iface, const char *uuid) iface); } +static GSList * +nm_dhcp_systemd_get_lease_ip_configs (NMDedupMultiIndex *multi_idx, + int addr_family, + const char *iface, + int ifindex, + const char *uuid, + guint32 route_table, + guint32 route_metric) +{ + GSList *leases = NULL; + gs_free char *path = NULL; + sd_dhcp_lease *lease = NULL; + NMIP4Config *ip4_config; + int r; + + if (addr_family != AF_INET) + return NULL; + + path = get_leasefile_path (addr_family, iface, uuid); + r = dhcp_lease_load (&lease, path); + if (r == 0 && lease) { + ip4_config = lease_to_ip4_config (multi_idx, iface, ifindex, lease, NULL, route_table, route_metric, FALSE, NULL); + if (ip4_config) + leases = g_slist_append (leases, ip4_config); + sd_dhcp_lease_unref (lease); + } + + return leases; +} + /*****************************************************************************/ static void @@ -554,16 +584,14 @@ dhcp_event_cb (sd_dhcp_client *client, int event, gpointer user_data) } static guint16 -get_arp_type (GBytes *hwaddr) +get_arp_type (const GByteArray *hwaddr) { - switch (g_bytes_get_size (hwaddr)) { - case ETH_ALEN: + if (hwaddr->len == ETH_ALEN) return ARPHRD_ETHER; - case INFINIBAND_ALEN: + else if (hwaddr->len == INFINIBAND_ALEN) return ARPHRD_INFINIBAND; - default: + else return ARPHRD_NONE; - } } static gboolean @@ -572,7 +600,7 @@ ip4_start (NMDhcpClient *client, const char *dhcp_anycast_addr, const char *last NMDhcpSystemd *self = NM_DHCP_SYSTEMD (client); NMDhcpSystemdPrivate *priv = NM_DHCP_SYSTEMD_GET_PRIVATE (self); const char *iface = nm_dhcp_client_get_iface (client); - GBytes *hwaddr; + const GByteArray *hwaddr; sd_dhcp_lease *lease = NULL; GBytes *override_client_id; const uint8_t *client_id = NULL; @@ -581,6 +609,7 @@ ip4_start (NMDhcpClient *client, const char *dhcp_anycast_addr, const char *last const char *hostname; int r, i; gboolean success = FALSE; + guint16 arp_type; g_assert (priv->client4 == NULL); g_assert (priv->client6 == NULL); @@ -604,14 +633,16 @@ ip4_start (NMDhcpClient *client, const char *dhcp_anycast_addr, const char *last hwaddr = nm_dhcp_client_get_hw_addr (client); if (hwaddr) { - const uint8_t *data; - gsize len; + arp_type= get_arp_type (hwaddr); + if (arp_type == ARPHRD_NONE) { + _LOGW ("failed to determine ARP type"); + goto error; + } - data = g_bytes_get_data (hwaddr, &len); r = sd_dhcp_client_set_mac (priv->client4, - data, - len, - get_arp_type (hwaddr)); + hwaddr->data, + hwaddr->len, + arp_type); if (r < 0) { _LOGW ("failed to set MAC address (%d)", r); goto error; @@ -630,6 +661,12 @@ ip4_start (NMDhcpClient *client, const char *dhcp_anycast_addr, const char *last goto error; } + r = sd_dhcp_client_set_request_broadcast (priv->client4, true); + if (r < 0) { + _LOGW ("failed to enable broadcast mode (%d)", r); + goto error; + } + dhcp_lease_load (&lease, priv->lease_file); if (last_ip4_address) @@ -817,7 +854,7 @@ bound6_handle (NMDhcpSystemd *self) lease, options, TRUE, - nm_dhcp_client_get_info_only (NM_DHCP_CLIENT (self)), + priv->info_only, &error); if (ip6_config) { @@ -863,29 +900,24 @@ static gboolean ip6_start (NMDhcpClient *client, const char *dhcp_anycast_addr, const struct in6_addr *ll_addr, + gboolean info_only, NMSettingIP6ConfigPrivacy privacy, - GBytes *duid, + const GByteArray *duid, guint needed_prefixes) { NMDhcpSystemd *self = NM_DHCP_SYSTEMD (client); NMDhcpSystemdPrivate *priv = NM_DHCP_SYSTEMD_GET_PRIVATE (self); const char *iface = nm_dhcp_client_get_iface (client); - GBytes *hwaddr; - const char *hostname; + const GByteArray *hwaddr; int r, i; - const guint8 *duid_arr; - gsize duid_len; g_assert (priv->client4 == NULL); g_assert (priv->client6 == NULL); g_return_val_if_fail (duid != NULL, FALSE); - duid_arr = g_bytes_get_data (duid, &duid_len); - if (!duid_arr || duid_len < 2) - g_return_val_if_reached (FALSE); - g_free (priv->lease_file); priv->lease_file = get_leasefile_path (AF_INET6, iface, nm_dhcp_client_get_uuid (client)); + priv->info_only = info_only; r = sd_dhcp6_client_new (&priv->client6); if (r < 0) { @@ -900,13 +932,16 @@ ip6_start (NMDhcpClient *client, _LOGT ("dhcp-client6: set %p", priv->client6); - if (nm_dhcp_client_get_info_only (client)) - sd_dhcp6_client_set_information_request (priv->client6, 1); + if (info_only) + sd_dhcp6_client_set_information_request (priv->client6, 1); + /* NM stores the entire DUID which includes the uint16 "type", while systemd + * wants the type passed separately from the following data. + */ r = sd_dhcp6_client_set_duid (priv->client6, - unaligned_read_be16 (&duid_arr[0]), - &duid_arr[2], - duid_len - 2); + ntohs (((const guint16 *) duid->data)[0]), + duid->data + 2, + duid->len - 2); if (r < 0) { _LOGW ("failed to set DUID (%d)", r); return FALSE; @@ -920,13 +955,9 @@ ip6_start (NMDhcpClient *client, hwaddr = nm_dhcp_client_get_hw_addr (client); if (hwaddr) { - const uint8_t *data; - gsize len; - - data = g_bytes_get_data (hwaddr, &len); r = sd_dhcp6_client_set_mac (priv->client6, - data, - len, + hwaddr->data, + hwaddr->len, get_arp_type (hwaddr)); if (r < 0) { _LOGW ("failed to set MAC address (%d)", r); @@ -958,13 +989,6 @@ ip6_start (NMDhcpClient *client, goto error; } - hostname = nm_dhcp_client_get_hostname (client); - r = sd_dhcp6_client_set_fqdn (priv->client6, hostname); - if (r < 0) { - _LOGW ("failed to set DHCP hostname to '%s' (%d)", hostname, r); - goto error; - } - r = sd_dhcp6_client_start (priv->client6); if (r < 0) { _LOGW ("failed to start client (%d)", r); @@ -982,14 +1006,12 @@ error: } static void -stop (NMDhcpClient *client, gboolean release, GBytes *duid) +stop (NMDhcpClient *client, gboolean release, const GByteArray *duid) { NMDhcpSystemd *self = NM_DHCP_SYSTEMD (client); NMDhcpSystemdPrivate *priv = NM_DHCP_SYSTEMD_GET_PRIVATE (self); int r = 0; - NM_DHCP_CLIENT_CLASS (nm_dhcp_systemd_parent_class)->stop (client, release, duid); - _LOGT ("dhcp-client%d: stop %p", priv->client4 ? '4' : '6', priv->client4 ? (gpointer) priv->client4 : (gpointer) priv->client6); @@ -1052,4 +1074,5 @@ const NMDhcpClientFactory _nm_dhcp_client_factory_internal = { .name = "internal", .get_type = nm_dhcp_systemd_get_type, .get_path = NULL, + .get_lease_ip_configs = nm_dhcp_systemd_get_lease_ip_configs, }; diff --git a/src/dhcp/nm-dhcp-utils.c b/src/dhcp/nm-dhcp-utils.c index 9185a135..50ca2abe 100644 --- a/src/dhcp/nm-dhcp-utils.c +++ b/src/dhcp/nm-dhcp-utils.c @@ -721,15 +721,11 @@ error: } char * -nm_dhcp_utils_duid_to_string (GBytes *duid) +nm_dhcp_utils_duid_to_string (const GByteArray *duid) { - gconstpointer data; - gsize len; - g_return_val_if_fail (duid != NULL, NULL); - data = g_bytes_get_data (duid, &len); - return _nm_utils_bin2str (data, len, FALSE); + return _nm_utils_bin2str (duid->data, duid->len, FALSE); } /** diff --git a/src/dhcp/nm-dhcp-utils.h b/src/dhcp/nm-dhcp-utils.h index 5c127bd1..32140f48 100644 --- a/src/dhcp/nm-dhcp-utils.h +++ b/src/dhcp/nm-dhcp-utils.h @@ -39,7 +39,7 @@ NMIP6Config *nm_dhcp_utils_ip6_config_from_options (struct _NMDedupMultiIndex *m NMPlatformIP6Address nm_dhcp_utils_ip6_prefix_from_options (GHashTable *options); -char *nm_dhcp_utils_duid_to_string (GBytes *duid); +char * nm_dhcp_utils_duid_to_string (const GByteArray *duid); GBytes * nm_dhcp_utils_client_id_string_to_bytes (const char *client_id); diff --git a/src/dhcp/tests/leases/basic.leases b/src/dhcp/tests/leases/basic.leases new file mode 100644 index 00000000..703d9247 --- /dev/null +++ b/src/dhcp/tests/leases/basic.leases @@ -0,0 +1,31 @@ +lease { + interface "wlan0"; + fixed-address 192.168.1.180; + option subnet-mask 255.255.255.0; + option routers 192.168.1.1; + option dhcp-lease-time 600; + option dhcp-message-type 5; + option domain-name-servers 192.168.1.1; + option dhcp-server-identifier 192.168.1.1; + option broadcast-address 192.168.1.255; + renew 5 2013/11/01 19:56:15; + rebind 5 2013/11/01 20:00:44; + expire 5 2013/11/01 20:01:59; +} +lease { + interface "wlan0"; + fixed-address 10.77.52.141; + option subnet-mask 255.0.0.0; + option dhcp-lease-time 1200; + option routers 10.77.52.254; + option dhcp-message-type 5; + option dhcp-server-identifier 10.77.52.254; + option domain-name-servers 8.8.8.8,8.8.4.4; + option dhcp-renewal-time 600; + option dhcp-rebinding-time 1050; + option domain-name "morriesguest.local"; + renew 5 2013/11/01 20:01:08; + rebind 5 2013/11/01 20:05:00; + expire 5 2013/11/01 20:06:15; +} + diff --git a/src/dhcp/tests/leases/malformed1.leases b/src/dhcp/tests/leases/malformed1.leases new file mode 100644 index 00000000..401d982a --- /dev/null +++ b/src/dhcp/tests/leases/malformed1.leases @@ -0,0 +1,15 @@ +# missing fixed-address option +lease { + interface "wlan0"; + option subnet-mask 255.255.255.0; + option routers 192.168.1.1; + option dhcp-lease-time 600; + option dhcp-message-type 5; + option domain-name-servers 192.168.1.1; + option dhcp-server-identifier 192.168.1.1; + option broadcast-address 192.168.1.255; + renew 5 2013/11/01 19:56:15; + rebind 5 2013/11/01 20:00:44; + expire 5 2013/11/01 20:01:59; +} + diff --git a/src/dhcp/tests/leases/malformed2.leases b/src/dhcp/tests/leases/malformed2.leases new file mode 100644 index 00000000..adf5f6de --- /dev/null +++ b/src/dhcp/tests/leases/malformed2.leases @@ -0,0 +1,15 @@ +# missing routers option +lease { + interface "wlan0"; + fixed-address 192.168.1.180; + option subnet-mask 255.255.255.0; + option dhcp-lease-time 600; + option dhcp-message-type 5; + option domain-name-servers 192.168.1.1; + option dhcp-server-identifier 192.168.1.1; + option broadcast-address 192.168.1.255; + renew 5 2013/11/01 19:56:15; + rebind 5 2013/11/01 20:00:44; + expire 5 2013/11/01 20:01:59; +} + diff --git a/src/dhcp/tests/leases/malformed3.leases b/src/dhcp/tests/leases/malformed3.leases new file mode 100644 index 00000000..a2afc8b6 --- /dev/null +++ b/src/dhcp/tests/leases/malformed3.leases @@ -0,0 +1,15 @@ +# missing expire time +lease { + interface "wlan0"; + fixed-address 192.168.1.180; + option subnet-mask 255.255.255.0; + option routers 192.168.1.1; + option dhcp-lease-time 600; + option dhcp-message-type 5; + option domain-name-servers 192.168.1.1; + option dhcp-server-identifier 192.168.1.1; + option broadcast-address 192.168.1.255; + renew 5 2013/11/01 19:56:15; + rebind 5 2013/11/01 20:00:44; +} + diff --git a/src/dhcp/tests/meson.build b/src/dhcp/tests/meson.build deleted file mode 100644 index 32badae8..00000000 --- a/src/dhcp/tests/meson.build +++ /dev/null @@ -1,19 +0,0 @@ -test_units = [ - 'test-dhcp-dhclient', - 'test-dhcp-utils' -] - -foreach test_unit: test_units - exe = executable( - test_unit, - test_unit + '.c', - dependencies: test_nm_dep, - c_args: '-DTESTDIR="@0@"'.format(meson.current_source_dir()) - ) - - test( - 'dhcp/' + test_unit, - test_script, - args: test_args + [exe.full_path()] - ) -endforeach diff --git a/src/dhcp/tests/test-dhcp-dhclient.c b/src/dhcp/tests/test-dhcp-dhclient.c index 25af51a1..f2e1f321 100644 --- a/src/dhcp/tests/test-dhcp-dhclient.c +++ b/src/dhcp/tests/test-dhcp-dhclient.c @@ -36,6 +36,12 @@ #include "nm-test-utils-core.h" +#define DEBUG 1 + +static const int IFINDEX = 5; +static const guint32 ROUTE_TABLE = RT_TABLE_MAIN; +static const guint32 ROUTE_METRIC = 100; + static void test_config (const char *orig, const char *expected, @@ -148,7 +154,7 @@ test_override_client_id (void) static const char *quote_client_id_expected = \ "# Created by NetworkManager\n" "\n" - "send dhcp-client-identifier \"\\x00abcd\"; # added by NetworkManager\n" + "send dhcp-client-identifier \"1234\"; # added by NetworkManager\n" "\n" "option rfc3442-classless-static-routes code 121 = array of unsigned integer 8;\n" "option ms-classless-static-routes code 249 = array of unsigned integer 8;\n" @@ -166,65 +172,7 @@ test_quote_client_id (void) { test_config (NULL, quote_client_id_expected, AF_INET, NULL, 0, FALSE, - "abcd", - NULL, - "eth0", - NULL); -} - -/*****************************************************************************/ - -static const char *quote_client_id_expected_2 = \ - "# Created by NetworkManager\n" - "\n" - "send dhcp-client-identifier 00:61:5c:62:63; # added by NetworkManager\n" - "\n" - "option rfc3442-classless-static-routes code 121 = array of unsigned integer 8;\n" - "option ms-classless-static-routes code 249 = array of unsigned integer 8;\n" - "option wpad code 252 = string;\n" - "\n" - "also request rfc3442-classless-static-routes;\n" - "also request ms-classless-static-routes;\n" - "also request static-routes;\n" - "also request wpad;\n" - "also request ntp-servers;\n" - "\n"; - -static void -test_quote_client_id_2 (void) -{ - test_config (NULL, quote_client_id_expected_2, - AF_INET, NULL, 0, FALSE, - "a\\bc", - NULL, - "eth0", - NULL); -} - -/*****************************************************************************/ - -static const char *hex_zero_client_id_expected = \ - "# Created by NetworkManager\n" - "\n" - "send dhcp-client-identifier 00:11:22:33; # added by NetworkManager\n" - "\n" - "option rfc3442-classless-static-routes code 121 = array of unsigned integer 8;\n" - "option ms-classless-static-routes code 249 = array of unsigned integer 8;\n" - "option wpad code 252 = string;\n" - "\n" - "also request rfc3442-classless-static-routes;\n" - "also request ms-classless-static-routes;\n" - "also request static-routes;\n" - "also request wpad;\n" - "also request ntp-servers;\n" - "\n"; - -static void -test_hex_zero_client_id (void) -{ - test_config (NULL, hex_zero_client_id_expected, - AF_INET, NULL, 0, FALSE, - "00:11:22:33", + "1234", NULL, "eth0", NULL); @@ -235,7 +183,7 @@ test_hex_zero_client_id (void) static const char *ascii_client_id_expected = \ "# Created by NetworkManager\n" "\n" - "send dhcp-client-identifier \"\\x00qb:cd:ef:12:34:56\"; # added by NetworkManager\n" + "send dhcp-client-identifier \"qb:cd:ef:12:34:56\"; # added by NetworkManager\n" "\n" "option rfc3442-classless-static-routes code 121 = array of unsigned integer 8;\n" "option ms-classless-static-routes code 249 = array of unsigned integer 8;\n" @@ -291,13 +239,13 @@ test_hex_single_client_id (void) /*****************************************************************************/ static const char *existing_hex_client_id_orig = \ - "send dhcp-client-identifier 10:30:04:20:7A:08;\n"; + "send dhcp-client-identifier 00:30:04:20:7A:08;\n"; static const char *existing_hex_client_id_expected = \ "# Created by NetworkManager\n" "# Merged from /path/to/dhclient.conf\n" "\n" - "send dhcp-client-identifier 10:30:04:20:7A:08;\n" + "send dhcp-client-identifier 00:30:04:20:7A:08;\n" "\n" "option rfc3442-classless-static-routes code 121 = array of unsigned integer 8;\n" "option ms-classless-static-routes code 249 = array of unsigned integer 8;\n" @@ -314,7 +262,7 @@ static void test_existing_hex_client_id (void) { gs_unref_bytes GBytes *new_client_id = NULL; - const guint8 bytes[] = { 0x10, 0x30, 0x04, 0x20, 0x7A, 0x08 }; + const guint8 bytes[] = { 0x00, 0x30, 0x04,0x20, 0x7A, 0x08 }; new_client_id = g_bytes_new (bytes, sizeof (bytes)); test_config (existing_hex_client_id_orig, existing_hex_client_id_expected, @@ -327,52 +275,16 @@ test_existing_hex_client_id (void) /*****************************************************************************/ -static const char *existing_escaped_client_id_orig = \ - "send dhcp-client-identifier \"\\044test\\xfe\";\n"; - -static const char *existing_escaped_client_id_expected = \ - "# Created by NetworkManager\n" - "# Merged from /path/to/dhclient.conf\n" - "\n" - "send dhcp-client-identifier \"\\044test\\xfe\";\n" - "\n" - "option rfc3442-classless-static-routes code 121 = array of unsigned integer 8;\n" - "option ms-classless-static-routes code 249 = array of unsigned integer 8;\n" - "option wpad code 252 = string;\n" - "\n" - "also request rfc3442-classless-static-routes;\n" - "also request ms-classless-static-routes;\n" - "also request static-routes;\n" - "also request wpad;\n" - "also request ntp-servers;\n" - "\n"; - -static void -test_existing_escaped_client_id (void) -{ - gs_unref_bytes GBytes *new_client_id = NULL; - - new_client_id = g_bytes_new ("$test\xfe", 6); - test_config (existing_escaped_client_id_orig, existing_escaped_client_id_expected, - AF_INET, NULL, 0, FALSE, - NULL, - new_client_id, - "eth0", - NULL); -} - -/*****************************************************************************/ - #define EACID "qb:cd:ef:12:34:56" static const char *existing_ascii_client_id_orig = \ - "send dhcp-client-identifier \"\\x00" EACID "\";\n"; + "send dhcp-client-identifier \"" EACID "\";\n"; static const char *existing_ascii_client_id_expected = \ "# Created by NetworkManager\n" "# Merged from /path/to/dhclient.conf\n" "\n" - "send dhcp-client-identifier \"\\x00" EACID "\";\n" + "send dhcp-client-identifier \"" EACID "\";\n" "\n" "option rfc3442-classless-static-routes code 121 = array of unsigned integer 8;\n" "option ms-classless-static-routes code 249 = array of unsigned integer 8;\n" @@ -673,26 +585,23 @@ test_existing_multiline_alsoreq (void) static void test_one_duid (const char *escaped, const guint8 *unescaped, guint len) { - GBytes *t; + GByteArray *t; char *w; - gsize t_len; - gconstpointer t_arr; t = nm_dhcp_dhclient_unescape_duid (escaped); g_assert (t); - t_arr = g_bytes_get_data (t, &t_len); - g_assert (t_arr); - g_assert_cmpint (t_len, ==, len); - g_assert_cmpint (memcmp (t_arr, unescaped, len), ==, 0); - g_bytes_unref (t); + g_assert_cmpint (t->len, ==, len); + g_assert_cmpint (memcmp (t->data, unescaped, len), ==, 0); + g_byte_array_free (t, TRUE); - t = g_bytes_new_static (unescaped, len); + t = g_byte_array_sized_new (len); + g_byte_array_append (t, unescaped, len); w = nm_dhcp_dhclient_escape_duid (t); g_assert (w); g_assert_cmpint (strlen (escaped), ==, strlen (w)); g_assert_cmpstr (escaped, ==, w); - g_bytes_unref (t); + g_byte_array_free (t, TRUE); g_free (w); } @@ -731,23 +640,22 @@ test_read_duid_from_leasefile (void) { const guint8 expected[] = { 0x00, 0x01, 0x00, 0x01, 0x18, 0x79, 0xa6, 0x13, 0x60, 0x67, 0x20, 0xec, 0x4c, 0x70 }; - gs_unref_bytes GBytes *duid = NULL; + GByteArray *duid; GError *error = NULL; - gconstpointer duid_arr; - gsize duid_len; duid = nm_dhcp_dhclient_read_duid (TESTDIR "/test-dhclient-duid.leases", &error); g_assert_no_error (error); g_assert (duid); - duid_arr = g_bytes_get_data (duid, &duid_len); - g_assert_cmpint (duid_len, ==, sizeof (expected)); - g_assert_cmpint (memcmp (duid_arr, expected, duid_len), ==, 0); + g_assert_cmpint (duid->len, ==, sizeof (expected)); + g_assert_cmpint (memcmp (duid->data, expected, duid->len), ==, 0); + + g_byte_array_free (duid, TRUE); } static void test_read_commented_duid_from_leasefile (void) { - GBytes *duid; + GByteArray *duid; GError *error = NULL; duid = nm_dhcp_dhclient_read_duid (TESTDIR "/test-dhclient-commented-duid.leases", &error); @@ -846,12 +754,12 @@ test_write_existing_commented_duid (void) static const char *interface1_orig = \ "interface \"eth0\" {\n" - "\talso request my-option;\n" - "\tinitial-delay 5;\n" + " also request my-option;\n" + " initial-delay 5;\n" "}\n" "interface \"eth1\" {\n" - "\talso request another-option;\n" - "\tinitial-delay 0;\n" + " also request another-option;\n" + " initial-delay 0;\n" "}\n" "\n" "also request yet-another-option;\n"; @@ -890,12 +798,12 @@ test_interface1 (void) static const char *interface2_orig = \ "interface eth0 {\n" - "\talso request my-option;\n" - "\tinitial-delay 5;\n" + " also request my-option;\n" + " initial-delay 5;\n" " }\n" "interface eth1 {\n" - "\tinitial-delay 0;\n" - "\trequest another-option;\n" + " initial-delay 0;\n" + " request another-option;\n" " } \n" "\n" "also request yet-another-option;\n"; @@ -936,12 +844,12 @@ test_config_req_intf (void) { static const char *const orig = \ "request subnet-mask, broadcast-address, routers,\n" - "\trfc3442-classless-static-routes,\n" - "\tinterface-mtu, host-name, domain-name, domain-search,\n" - "\tdomain-name-servers, nis-domain, nis-servers,\n" - "\tnds-context, nds-servers, nds-tree-name,\n" - "\tnetbios-name-servers, netbios-dd-server,\n" - "\tnetbios-node-type, netbios-scope, ntp-servers;\n" + " rfc3442-classless-static-routes,\n" + " interface-mtu, host-name, domain-name, domain-search,\n" + " domain-name-servers, nis-domain, nis-servers,\n" + " nds-context, nds-servers, nds-tree-name,\n" + " netbios-name-servers, netbios-dd-server,\n" + " netbios-node-type, netbios-scope, ntp-servers;\n" ""; static const char *const expected = \ "# Created by NetworkManager\n" @@ -987,6 +895,133 @@ test_config_req_intf (void) /*****************************************************************************/ +static void +test_read_lease_ip4_config_basic (void) +{ + nm_auto_unref_dedup_multi_index NMDedupMultiIndex *multi_idx = nm_dedup_multi_index_new (); + GError *error = NULL; + char *contents = NULL; + gboolean success; + const char *path = TESTDIR "/leases/basic.leases"; + GSList *leases; + GDateTime *now; + NMIP4Config *config; + const NMPlatformIP4Address *addr; + guint32 expected_addr; + + success = g_file_get_contents (path, &contents, NULL, &error); + g_assert_no_error (error); + g_assert (success); + + /* Date from before the least expiration */ + now = g_date_time_new_utc (2013, 11, 1, 19, 55, 32); + leases = nm_dhcp_dhclient_read_lease_ip_configs (multi_idx, AF_INET, "wlan0", IFINDEX, ROUTE_TABLE, ROUTE_METRIC, contents, now); + g_assert_cmpint (g_slist_length (leases), ==, 2); + + /* IP4Config #1 */ + config = g_slist_nth_data (leases, 0); + g_assert (NM_IS_IP4_CONFIG (config)); + + /* Address */ + g_assert_cmpint (nm_ip4_config_get_num_addresses (config), ==, 1); + expected_addr = nmtst_inet4_from_string ("192.168.1.180"); + addr = _nmtst_ip4_config_get_address (config, 0); + g_assert_cmpint (addr->address, ==, expected_addr); + g_assert_cmpint (addr->peer_address, ==, expected_addr); + g_assert_cmpint (addr->plen, ==, 24); + + /* Gateway */ + expected_addr = nmtst_inet4_from_string ("192.168.1.1"); + g_assert_cmpint (nmtst_ip4_config_get_gateway (config), ==, expected_addr); + + /* DNS */ + g_assert_cmpint (nm_ip4_config_get_num_nameservers (config), ==, 1); + expected_addr = nmtst_inet4_from_string ("192.168.1.1"); + g_assert_cmpint (nm_ip4_config_get_nameserver (config, 0), ==, expected_addr); + + g_assert_cmpint (nm_ip4_config_get_num_domains (config), ==, 0); + + /* IP4Config #2 */ + config = g_slist_nth_data (leases, 1); + g_assert (NM_IS_IP4_CONFIG (config)); + + /* Address */ + g_assert_cmpint (nm_ip4_config_get_num_addresses (config), ==, 1); + expected_addr = nmtst_inet4_from_string ("10.77.52.141"); + addr = _nmtst_ip4_config_get_address (config, 0); + g_assert_cmpint (addr->address, ==, expected_addr); + g_assert_cmpint (addr->peer_address, ==, expected_addr); + g_assert_cmpint (addr->plen, ==, 8); + + /* Gateway */ + expected_addr = nmtst_inet4_from_string ("10.77.52.254"); + g_assert_cmpint (nmtst_ip4_config_get_gateway (config), ==, expected_addr); + + /* DNS */ + g_assert_cmpint (nm_ip4_config_get_num_nameservers (config), ==, 2); + expected_addr = nmtst_inet4_from_string ("8.8.8.8"); + g_assert_cmpint (nm_ip4_config_get_nameserver (config, 0), ==, expected_addr); + expected_addr = nmtst_inet4_from_string ("8.8.4.4"); + g_assert_cmpint (nm_ip4_config_get_nameserver (config, 1), ==, expected_addr); + + /* Domains */ + g_assert_cmpint (nm_ip4_config_get_num_domains (config), ==, 1); + g_assert_cmpstr (nm_ip4_config_get_domain (config, 0), ==, "morriesguest.local"); + + g_slist_free_full (leases, g_object_unref); + g_date_time_unref (now); + g_free (contents); +} + +static void +test_read_lease_ip4_config_expired (void) +{ + nm_auto_unref_dedup_multi_index NMDedupMultiIndex *multi_idx = nm_dedup_multi_index_new (); + GError *error = NULL; + char *contents = NULL; + gboolean success; + const char *path = TESTDIR "/leases/basic.leases"; + GSList *leases; + GDateTime *now; + + success = g_file_get_contents (path, &contents, NULL, &error); + g_assert_no_error (error); + g_assert (success); + + /* Date from *after* the lease expiration */ + now = g_date_time_new_utc (2013, 12, 1, 19, 55, 32); + leases = nm_dhcp_dhclient_read_lease_ip_configs (multi_idx, AF_INET, "wlan0", IFINDEX, ROUTE_TABLE, ROUTE_METRIC, contents, now); + g_assert (leases == NULL); + + g_date_time_unref (now); + g_free (contents); +} + +static void +test_read_lease_ip4_config_expect_failure (gconstpointer user_data) +{ + nm_auto_unref_dedup_multi_index NMDedupMultiIndex *multi_idx = nm_dedup_multi_index_new (); + GError *error = NULL; + char *contents = NULL; + gboolean success; + GSList *leases; + GDateTime *now; + + success = g_file_get_contents ((const char *) user_data, &contents, NULL, &error); + g_assert_no_error (error); + g_assert (success); + + /* Date from before the least expiration */ + now = g_date_time_new_utc (2013, 11, 1, 1, 1, 1); + leases = nm_dhcp_dhclient_read_lease_ip_configs (multi_idx, AF_INET, "wlan0", IFINDEX, ROUTE_TABLE, ROUTE_METRIC, contents, now); + g_assert (leases == NULL); + + g_date_time_unref (now); + g_free (contents); +} + +/*****************************************************************************/ + NMTST_DEFINE (); int @@ -996,13 +1031,10 @@ main (int argc, char **argv) g_test_add_func ("/dhcp/dhclient/orig_missing", test_orig_missing); g_test_add_func ("/dhcp/dhclient/override_client_id", test_override_client_id); - g_test_add_func ("/dhcp/dhclient/quote_client_id/1", test_quote_client_id); - g_test_add_func ("/dhcp/dhclient/quote_client_id/2", test_quote_client_id_2); - g_test_add_func ("/dhcp/dhclient/hex_zero_client_id", test_hex_zero_client_id); + g_test_add_func ("/dhcp/dhclient/quote_client_id", test_quote_client_id); g_test_add_func ("/dhcp/dhclient/ascii_client_id", test_ascii_client_id); g_test_add_func ("/dhcp/dhclient/hex_single_client_id", test_hex_single_client_id); g_test_add_func ("/dhcp/dhclient/existing-hex-client-id", test_existing_hex_client_id); - g_test_add_func ("/dhcp/dhclient/existing-client-id", test_existing_escaped_client_id); g_test_add_func ("/dhcp/dhclient/existing-ascii-client-id", test_existing_ascii_client_id); g_test_add_func ("/dhcp/dhclient/fqdn", test_fqdn); g_test_add_func ("/dhcp/dhclient/fqdn_options_override", test_fqdn_options_override); @@ -1024,6 +1056,18 @@ main (int argc, char **argv) g_test_add_func ("/dhcp/dhclient/write_existing_duid", test_write_existing_duid); g_test_add_func ("/dhcp/dhclient/write_existing_commented_duid", test_write_existing_commented_duid); + g_test_add_func ("/dhcp/dhclient/leases/ip4-config/basic", test_read_lease_ip4_config_basic); + g_test_add_func ("/dhcp/dhclient/leases/ip4-config/expired", test_read_lease_ip4_config_expired); + g_test_add_data_func ("/dhcp/dhclient/leases/ip4-config/missing-address", + TESTDIR "/leases/malformed1.leases", + test_read_lease_ip4_config_expect_failure); + g_test_add_data_func ("/dhcp/dhclient/leases/ip4-config/missing-gateway", + TESTDIR "/leases/malformed2.leases", + test_read_lease_ip4_config_expect_failure); + g_test_add_data_func ("/dhcp/dhclient/leases/ip4-config/missing-expire", + TESTDIR "/leases/malformed3.leases", + test_read_lease_ip4_config_expect_failure); + return g_test_run (); } diff --git a/src/dhcp/tests/test-dhcp-utils.c b/src/dhcp/tests/test-dhcp-utils.c index 617a3c6c..72f31191 100644 --- a/src/dhcp/tests/test-dhcp-utils.c +++ b/src/dhcp/tests/test-dhcp-utils.c @@ -349,7 +349,8 @@ test_dhclient_invalid_classless_routes_1 (void) options = fill_table (generic_options, NULL); options = fill_table (data, options); - NMTST_EXPECT_NM_WARN ("*ignoring invalid classless static routes*"); + g_test_expect_message ("NetworkManager", G_LOG_LEVEL_MESSAGE, + "*ignoring invalid classless static routes*"); ip4_config = _ip4_config_from_options (1, "eth0", options, 0); g_test_assert_expected_messages (); @@ -379,7 +380,8 @@ test_dhcpcd_invalid_classless_routes_1 (void) options = fill_table (generic_options, NULL); options = fill_table (data, options); - NMTST_EXPECT_NM_WARN ("*ignoring invalid classless static routes*"); + g_test_expect_message ("NetworkManager", G_LOG_LEVEL_MESSAGE, + "*ignoring invalid classless static routes*"); ip4_config = _ip4_config_from_options (1, "eth0", options, 0); g_test_assert_expected_messages (); @@ -411,7 +413,8 @@ test_dhclient_invalid_classless_routes_2 (void) options = fill_table (generic_options, NULL); options = fill_table (data, options); - NMTST_EXPECT_NM_WARN ("*ignoring invalid classless static routes*"); + g_test_expect_message ("NetworkManager", G_LOG_LEVEL_MESSAGE, + "*ignoring invalid classless static routes*"); ip4_config = _ip4_config_from_options (1, "eth0", options, 0); g_test_assert_expected_messages (); @@ -443,7 +446,8 @@ test_dhcpcd_invalid_classless_routes_2 (void) options = fill_table (generic_options, NULL); options = fill_table (data, options); - NMTST_EXPECT_NM_WARN ("*ignoring invalid classless static routes*"); + g_test_expect_message ("NetworkManager", G_LOG_LEVEL_MESSAGE, + "*ignoring invalid classless static routes*"); ip4_config = _ip4_config_from_options (1, "eth0", options, 0); g_test_assert_expected_messages (); @@ -475,7 +479,8 @@ test_dhclient_invalid_classless_routes_3 (void) options = fill_table (generic_options, NULL); options = fill_table (data, options); - NMTST_EXPECT_NM_WARN ("*ignoring invalid classless static routes*"); + g_test_expect_message ("NetworkManager", G_LOG_LEVEL_MESSAGE, + "*ignoring invalid classless static routes*"); ip4_config = _ip4_config_from_options (1, "eth0", options, 0); g_test_assert_expected_messages (); @@ -502,7 +507,8 @@ test_dhcpcd_invalid_classless_routes_3 (void) options = fill_table (generic_options, NULL); options = fill_table (data, options); - NMTST_EXPECT_NM_WARN ("*DHCP provided invalid classless static route*"); + g_test_expect_message ("NetworkManager", G_LOG_LEVEL_MESSAGE, + "*DHCP provided invalid classless static route*"); ip4_config = _ip4_config_from_options (1, "eth0", options, 0); g_test_assert_expected_messages (); @@ -609,7 +615,8 @@ test_invalid_escaped_domain_searches (void) options = fill_table (generic_options, NULL); options = fill_table (data, options); - NMTST_EXPECT_NM_WARN ("*invalid domain search*"); + g_test_expect_message ("NetworkManager", G_LOG_LEVEL_MESSAGE, + "*invalid domain search*"); ip4_config = _ip4_config_from_options (1, "eth0", options, 0); g_test_assert_expected_messages (); diff --git a/src/dns/nm-dns-dnsmasq.c b/src/dns/nm-dns-dnsmasq.c index d0753078..e6436c79 100644 --- a/src/dns/nm-dns-dnsmasq.c +++ b/src/dns/nm-dns-dnsmasq.c @@ -35,7 +35,7 @@ #include "nm-utils.h" #include "nm-ip4-config.h" #include "nm-ip6-config.h" -#include "nm-dbus-manager.h" +#include "nm-bus-manager.h" #include "NetworkManagerUtils.h" #define PIDFILE NMRUNDIR "/dnsmasq.pid" @@ -76,41 +76,54 @@ G_DEFINE_TYPE (NMDnsDnsmasq, nm_dns_dnsmasq, NM_TYPE_DNS_PLUGIN) /*****************************************************************************/ static char ** -get_ip_rdns_domains (NMIPConfig *ip_config) +get_ip4_rdns_domains (NMIP4Config *ip4) { - int addr_family = nm_ip_config_get_addr_family (ip_config); char **strv; GPtrArray *domains = NULL; NMDedupMultiIter ipconf_iter; + const NMPlatformIP4Address *address; + const NMPlatformIP4Route *route; - nm_assert_addr_family (addr_family); + g_return_val_if_fail (ip4 != NULL, NULL); domains = g_ptr_array_sized_new (5); - if (addr_family == AF_INET) { - NMIP4Config *ip4 = (gpointer) ip_config; - const NMPlatformIP4Address *address; - const NMPlatformIP4Route *route; + nm_ip_config_iter_ip4_address_for_each (&ipconf_iter, ip4, &address) + nm_utils_get_reverse_dns_domains_ip4 (address->address, address->plen, domains); - nm_ip_config_iter_ip4_address_for_each (&ipconf_iter, ip4, &address) - nm_utils_get_reverse_dns_domains_ip4 (address->address, address->plen, domains); + nm_ip_config_iter_ip4_route_for_each (&ipconf_iter, ip4, &route) { + if (!NM_PLATFORM_IP_ROUTE_IS_DEFAULT (route)) + nm_utils_get_reverse_dns_domains_ip4 (route->network, route->plen, domains); + } - nm_ip_config_iter_ip4_route_for_each (&ipconf_iter, ip4, &route) { - if (!NM_PLATFORM_IP_ROUTE_IS_DEFAULT (route)) - nm_utils_get_reverse_dns_domains_ip4 (route->network, route->plen, domains); - } - } else { - NMIP6Config *ip6 = (gpointer) ip_config; - const NMPlatformIP6Address *address; - const NMPlatformIP6Route *route; + /* Terminating NULL so we can use g_strfreev() to free it */ + g_ptr_array_add (domains, NULL); - nm_ip_config_iter_ip6_address_for_each (&ipconf_iter, ip6, &address) - nm_utils_get_reverse_dns_domains_ip6 (&address->address, address->plen, domains); + /* Free the array and return NULL if the only element was the ending NULL */ + strv = (char **) g_ptr_array_free (domains, (domains->len == 1)); - nm_ip_config_iter_ip6_route_for_each (&ipconf_iter, ip6, &route) { - if (!NM_PLATFORM_IP_ROUTE_IS_DEFAULT (route)) - nm_utils_get_reverse_dns_domains_ip6 (&route->network, route->plen, domains); - } + return _nm_utils_strv_cleanup (strv, FALSE, FALSE, TRUE); +} + +static char ** +get_ip6_rdns_domains (NMIP6Config *ip6) +{ + char **strv; + GPtrArray *domains = NULL; + NMDedupMultiIter ipconf_iter; + const NMPlatformIP6Address *address; + const NMPlatformIP6Route *route; + + g_return_val_if_fail (ip6 != NULL, NULL); + + domains = g_ptr_array_sized_new (5); + + nm_ip_config_iter_ip6_address_for_each (&ipconf_iter, ip6, &address) + nm_utils_get_reverse_dns_domains_ip6 (&address->address, address->plen, domains); + + nm_ip_config_iter_ip6_route_for_each (&ipconf_iter, ip6, &route) { + if (!NM_PLATFORM_IP_ROUTE_IS_DEFAULT (route)) + nm_utils_get_reverse_dns_domains_ip6 (&route->network, route->plen, domains); } /* Terminating NULL so we can use g_strfreev() to free it */ @@ -142,43 +155,96 @@ add_dnsmasq_nameserver (NMDnsDnsmasq *self, g_variant_builder_close (servers); } -#define IP_ADDR_TO_STRING_BUFLEN (NM_UTILS_INET_ADDRSTRLEN + 1 + IFNAMSIZ) - -static const char * -ip_addr_to_string (int addr_family, gconstpointer addr, const char *iface, char *out_buf) +static gboolean +add_ip4_config (NMDnsDnsmasq *self, GVariantBuilder *servers, NMIP4Config *ip4, + const char *iface, gboolean split) { - int n_written; - char buf2[NM_UTILS_INET_ADDRSTRLEN]; - const char *separator; + char buf[INET_ADDRSTRLEN + 1 + IFNAMSIZ]; + char buf2[INET_ADDRSTRLEN]; + in_addr_t addr; + int nnameservers, i_nameserver, n, i; + gboolean added = FALSE; - nm_assert_addr_family (addr_family); - nm_assert (addr); - nm_assert (out_buf); + g_return_val_if_fail (iface, FALSE); + nnameservers = nm_ip4_config_get_num_nameservers (ip4); - if (addr_family == AF_INET) { - nm_utils_inet_ntop (addr_family, addr, buf2); - separator = "@"; - } else { - if (IN6_IS_ADDR_V4MAPPED (addr)) - nm_utils_inet4_ntop (((const struct in6_addr *) addr)->s6_addr32[3], buf2); - else - nm_utils_inet6_ntop (addr, buf2); - /* Need to scope link-local addresses with %<zone-id>. Before dnsmasq 2.58, - * only '@' was supported as delimiter. Since 2.58, '@' and '%' are - * supported. Due to a bug, since 2.73 only '%' works properly as "server" - * address. - */ - separator = IN6_IS_ADDR_LINKLOCAL (addr) ? "%" : "@"; + if (split) { + char **domains, **iter; + + if (nnameservers == 0) + return FALSE; + + for (i_nameserver = 0; i_nameserver < nnameservers; i_nameserver++) { + addr = nm_ip4_config_get_nameserver (ip4, i_nameserver); + g_snprintf (buf, sizeof (buf), "%s@%s", + nm_utils_inet4_ntop (addr, buf2), iface); + + /* searches are preferred over domains */ + n = nm_ip4_config_get_num_searches (ip4); + for (i = 0; i < n; i++) { + add_dnsmasq_nameserver (self, + servers, + buf, + nm_ip4_config_get_search (ip4, i)); + added = TRUE; + } + + if (n == 0) { + /* If not searches, use any domains */ + n = nm_ip4_config_get_num_domains (ip4); + for (i = 0; i < n; i++) { + add_dnsmasq_nameserver (self, + servers, + buf, + nm_ip4_config_get_domain (ip4, i)); + added = TRUE; + } + } + + /* Ensure reverse-DNS works by directing queries for in-addr.arpa + * domains to the split domain's nameserver. + */ + domains = get_ip4_rdns_domains (ip4); + if (domains) { + for (iter = domains; iter && *iter; iter++) + add_dnsmasq_nameserver (self, servers, buf, *iter); + g_strfreev (domains); + } + } + } + + /* If no searches or domains, just add the nameservers */ + if (!added) { + for (i = 0; i < nnameservers; i++) { + addr = nm_ip4_config_get_nameserver (ip4, i); + g_snprintf (buf, sizeof (buf), "%s@%s", + nm_utils_inet4_ntop (addr, buf2), iface); + add_dnsmasq_nameserver (self, servers, buf, NULL); + } } - n_written = g_snprintf (out_buf, - IP_ADDR_TO_STRING_BUFLEN, - "%s%s%s", - buf2, - iface ? separator : "", - iface ?: ""); - nm_assert (n_written < IP_ADDR_TO_STRING_BUFLEN); - return out_buf; + return TRUE; +} + +static char * +ip6_addr_to_string (const struct in6_addr *addr, const char *iface) +{ + char buf[NM_UTILS_INET_ADDRSTRLEN]; + + if (IN6_IS_ADDR_V4MAPPED (addr)) + nm_utils_inet4_ntop (addr->s6_addr32[3], buf); + else + nm_utils_inet6_ntop (addr, buf); + + /* Need to scope link-local addresses with %<zone-id>. Before dnsmasq 2.58, + * only '@' was supported as delimiter. Since 2.58, '@' and '%' are + * supported. Due to a bug, since 2.73 only '%' works properly as "server" + * address. + */ + return g_strdup_printf ("%s%c%s", + buf, + IN6_IS_ADDR_LINKLOCAL (addr) ? '%' : '@', + iface); } static void @@ -205,100 +271,103 @@ add_global_config (NMDnsDnsmasq *self, GVariantBuilder *dnsmasq_servers, const N } } -static void -add_ip_config (NMDnsDnsmasq *self, - GVariantBuilder *servers, - int ifindex, - NMIPConfig *ip_config, - gboolean split) +static gboolean +add_ip6_config (NMDnsDnsmasq *self, GVariantBuilder *servers, NMIP6Config *ip6, + const char *iface, gboolean split) { - int addr_family; - gconstpointer addr; + const struct in6_addr *addr; + char *buf = NULL; + int nnameservers, i_nameserver, n, i; gboolean added = FALSE; - guint nnameservers, i_nameserver, n, i; - char ip_addr_to_string_buf[IP_ADDR_TO_STRING_BUFLEN]; - char **domains, **iter; - gboolean iface_resolved = FALSE; - const char *iface = NULL, *domain; - addr_family = nm_ip_config_get_addr_family (ip_config); - g_return_if_fail (NM_IN_SET (addr_family, AF_INET, AF_INET6)); - - nm_assert (ifindex > 0); - nm_assert (ifindex == nm_ip_config_get_ifindex (ip_config)); - - nnameservers = nm_ip_config_get_num_nameservers (ip_config); + g_return_val_if_fail (iface, FALSE); + nnameservers = nm_ip6_config_get_num_nameservers (ip6); if (split) { - if (nnameservers == 0) - return; - - if (!iface_resolved) { - iface = nm_platform_link_get_name (NM_PLATFORM_GET, ifindex); - iface_resolved = TRUE; - } - - if (iface) { - for (i_nameserver = 0; i_nameserver < nnameservers; i_nameserver++) { - addr = nm_ip_config_get_nameserver (ip_config, i_nameserver); + char **domains, **iter; - ip_addr_to_string (addr_family, addr, iface, ip_addr_to_string_buf); + if (nnameservers == 0) + return FALSE; + + for (i_nameserver = 0; i_nameserver < nnameservers; i_nameserver++) { + addr = nm_ip6_config_get_nameserver (ip6, i_nameserver); + buf = ip6_addr_to_string (addr, iface); + + /* searches are preferred over domains */ + n = nm_ip6_config_get_num_searches (ip6); + for (i = 0; i < n; i++) { + add_dnsmasq_nameserver (self, + servers, + buf, + nm_ip6_config_get_search (ip6, i)); + added = TRUE; + } - /* searches are preferred over domains */ - n = nm_ip_config_get_num_searches (ip_config); + if (n == 0) { + /* If not searches, use any domains */ + n = nm_ip6_config_get_num_domains (ip6); for (i = 0; i < n; i++) { - domain = nm_utils_parse_dns_domain (nm_ip_config_get_search (ip_config, i), NULL); add_dnsmasq_nameserver (self, servers, - ip_addr_to_string_buf, - domain); + buf, + nm_ip6_config_get_domain (ip6, i)); added = TRUE; } + } - if (n == 0) { - /* If not searches, use any domains */ - n = nm_ip_config_get_num_domains (ip_config); - domain = nm_utils_parse_dns_domain (nm_ip_config_get_domain (ip_config, i), NULL); - for (i = 0; i < n; i++) { - add_dnsmasq_nameserver (self, - servers, - ip_addr_to_string_buf, - domain); - added = TRUE; - } - } - - /* Ensure reverse-DNS works by directing queries for in-addr4.arpa/ip6.arpa - * domains to the split domain's nameserver. - */ - domains = get_ip_rdns_domains (ip_config); - if (domains) { - for (iter = domains; *iter; iter++) - add_dnsmasq_nameserver (self, servers, ip_addr_to_string_buf, *iter); - g_strfreev (domains); - } + /* Ensure reverse-DNS works by directing queries for ip6.arpa + * domains to the split domain's nameserver. + */ + domains = get_ip6_rdns_domains (ip6); + if (domains) { + for (iter = domains; iter && *iter; iter++) + add_dnsmasq_nameserver (self, servers, buf, *iter); + g_strfreev (domains); } + + g_free (buf); } } /* If no searches or domains, just add the nameservers */ if (!added) { - if (!iface_resolved) - iface = nm_platform_link_get_name (NM_PLATFORM_GET, ifindex); - if (iface) { - for (i = 0; i < nnameservers; i++) { - addr = nm_ip_config_get_nameserver (ip_config, i); - ip_addr_to_string (addr_family, addr, iface, ip_addr_to_string_buf); - add_dnsmasq_nameserver (self, servers, ip_addr_to_string_buf, NULL); + for (i = 0; i < nnameservers; i++) { + addr = nm_ip6_config_get_nameserver (ip6, i); + buf = ip6_addr_to_string (addr, iface); + if (buf) { + add_dnsmasq_nameserver (self, servers, buf, NULL); + g_free (buf); } } } + + return TRUE; +} + +static gboolean +add_ip_config_data (NMDnsDnsmasq *self, GVariantBuilder *servers, const NMDnsIPConfigData *data) +{ + if (NM_IS_IP4_CONFIG (data->config)) { + return add_ip4_config (self, + servers, + (NMIP4Config *) data->config, + data->iface, + data->type == NM_DNS_IP_CONFIG_TYPE_VPN); + } else if (NM_IS_IP6_CONFIG (data->config)) { + return add_ip6_config (self, + servers, + (NMIP6Config *) data->config, + data->iface, + data->type == NM_DNS_IP_CONFIG_TYPE_VPN); + } else + g_return_val_if_reached (FALSE); } static void dnsmasq_update_done (GDBusProxy *proxy, GAsyncResult *res, gpointer user_data) { NMDnsDnsmasq *self; + NMDnsDnsmasqPrivate *priv; gs_free_error GError *error = NULL; gs_unref_variant GVariant *response = NULL; @@ -307,6 +376,7 @@ dnsmasq_update_done (GDBusProxy *proxy, GAsyncResult *res, gpointer user_data) return; self = NM_DNS_DNSMASQ (user_data); + priv = NM_DNS_DNSMASQ_GET_PRIVATE (self); if (!response) _LOGW ("dnsmasq update failed: %s", error->message); @@ -408,7 +478,7 @@ start_dnsmasq (NMDnsDnsmasq *self) const char *argv[15]; GPid pid = 0; guint idx = 0; - NMDBusManager *dbus_mgr; + NMBusManager *dbus_mgr; GDBusConnection *connection; if (priv->running) { @@ -460,10 +530,10 @@ start_dnsmasq (NMDnsDnsmasq *self) return; } - dbus_mgr = nm_dbus_manager_get (); + dbus_mgr = nm_bus_manager_get (); g_return_if_fail (dbus_mgr); - connection = nm_dbus_manager_get_connection (dbus_mgr); + connection = nm_bus_manager_get_connection (dbus_mgr); g_return_if_fail (connection); priv->dnsmasq_cancellable = g_cancellable_new (); @@ -480,16 +550,15 @@ start_dnsmasq (NMDnsDnsmasq *self) static gboolean update (NMDnsPlugin *plugin, + const GPtrArray *configs, const NMGlobalDnsConfig *global_config, - const CList *ip_config_lst_head, const char *hostname) { NMDnsDnsmasq *self = NM_DNS_DNSMASQ (plugin); NMDnsDnsmasqPrivate *priv = NM_DNS_DNSMASQ_GET_PRIVATE (self); GVariantBuilder servers; - int prio, first_prio = 0; - const NMDnsIPConfigData *ip_data; - gboolean is_first = TRUE; + guint i; + int prio, first_prio; start_dnsmasq (self); @@ -498,18 +567,15 @@ update (NMDnsPlugin *plugin, if (global_config) add_global_config (self, &servers, global_config); else { - c_list_for_each_entry (ip_data, ip_config_lst_head, ip_config_lst) { - prio = nm_ip_config_get_dns_priority (ip_data->ip_config); - if (is_first) { - is_first = FALSE; + for (i = 0; i < configs->len; i++) { + const NMDnsIPConfigData *data = configs->pdata[i]; + + prio = nm_ip_config_get_dns_priority (data->config); + if (i == 0) first_prio = prio; - } else if (first_prio < 0 && first_prio != prio) + else if (first_prio < 0 && first_prio != prio) break; - add_ip_config (self, - &servers, - ip_data->data->ifindex, - ip_data->ip_config, - ip_data->ip_config_type == NM_DNS_IP_CONFIG_TYPE_VPN); + add_ip_config_data (self, &servers, data); } } diff --git a/src/dns/nm-dns-manager.c b/src/dns/nm-dns-manager.c index 10a16e57..dc545470 100644 --- a/src/dns/nm-dns-manager.c +++ b/src/dns/nm-dns-manager.c @@ -46,7 +46,6 @@ #include "nm-ip6-config.h" #include "NetworkManagerUtils.h" #include "nm-config.h" -#include "nm-dbus-object.h" #include "devices/nm-device.h" #include "nm-manager.h" @@ -55,6 +54,8 @@ #include "nm-dns-systemd-resolved.h" #include "nm-dns-unbound.h" +#include "introspection/org.freedesktop.NetworkManager.DnsManager.h" + #define HASH_LEN 20 #ifndef RESOLVCONF_PATH @@ -69,24 +70,6 @@ #define PLUGIN_RATELIMIT_BURST 5 #define PLUGIN_RATELIMIT_DELAY 300 -/*****************************************************************************/ - -typedef enum { - SR_SUCCESS, - SR_NOTFOUND, - SR_ERROR -} SpawnResult; - -typedef struct { - GPtrArray *nameservers; - GPtrArray *searches; - GPtrArray *options; - const char *nis_domain; - GPtrArray *nis_servers; -} NMResolvConfData; - -/*****************************************************************************/ - enum { CONFIG_CHANGED, @@ -101,16 +84,44 @@ NM_GOBJECT_PROPERTIES_DEFINE (NMDnsManager, static guint signals[LAST_SIGNAL] = { 0 }; -typedef struct { - GHashTable *configs; - CList ip_config_lst_head; - GVariant *config_variant; +typedef enum { + SR_SUCCESS, + SR_NOTFOUND, + SR_ERROR +} SpawnResult; - NMDnsIPConfigData *best_ip_config_4; - NMDnsIPConfigData *best_ip_config_6; +NM_DEFINE_SINGLETON_GETTER (NMDnsManager, nm_dns_manager_get, NM_TYPE_DNS_MANAGER); - bool ip_config_lst_need_sort:1; +/*****************************************************************************/ +#define _NMLOG_PREFIX_NAME "dns-mgr" +#define _NMLOG_DOMAIN LOGD_DNS +#define _NMLOG(level, ...) \ + G_STMT_START { \ + const NMLogLevel __level = (level); \ + \ + if (nm_logging_enabled (__level, _NMLOG_DOMAIN)) { \ + char __prefix[20]; \ + const NMDnsManager *const __self = (self); \ + \ + _nm_log (__level, _NMLOG_DOMAIN, 0, NULL, NULL, \ + "%s%s: " _NM_UTILS_MACRO_FIRST (__VA_ARGS__), \ + _NMLOG_PREFIX_NAME, \ + ((!__self || __self == singleton_instance) \ + ? "" \ + : nm_sprintf_buf (__prefix, "[%p]", __self)) \ + _NM_UTILS_MACRO_REST (__VA_ARGS__)); \ + } \ + } G_STMT_END + +/*****************************************************************************/ + +typedef struct { + GPtrArray *configs; + GVariant *config_variant; + NMDnsIPConfigData *best_conf4, *best_conf6; + + bool need_sort:1; bool dns_touched:1; bool is_stopped:1; @@ -134,52 +145,20 @@ typedef struct { } NMDnsManagerPrivate; struct _NMDnsManager { - NMDBusObject parent; + NMExportedObject parent; NMDnsManagerPrivate _priv; }; struct _NMDnsManagerClass { - NMDBusObjectClass parent; + NMExportedObjectClass parent; }; -G_DEFINE_TYPE (NMDnsManager, nm_dns_manager, NM_TYPE_DBUS_OBJECT) +G_DEFINE_TYPE (NMDnsManager, nm_dns_manager, NM_TYPE_EXPORTED_OBJECT) #define NM_DNS_MANAGER_GET_PRIVATE(self) _NM_GET_PRIVATE(self, NMDnsManager, NM_IS_DNS_MANAGER) -NM_DEFINE_SINGLETON_GETTER (NMDnsManager, nm_dns_manager_get, NM_TYPE_DNS_MANAGER); - -/*****************************************************************************/ - -#define _NMLOG_PREFIX_NAME "dns-mgr" -#define _NMLOG_DOMAIN LOGD_DNS -#define _NMLOG(level, ...) \ - G_STMT_START { \ - const NMLogLevel __level = (level); \ - \ - if (nm_logging_enabled (__level, _NMLOG_DOMAIN)) { \ - char __prefix[20]; \ - const NMDnsManager *const __self = (self); \ - \ - _nm_log (__level, _NMLOG_DOMAIN, 0, NULL, NULL, \ - "%s%s: " _NM_UTILS_MACRO_FIRST (__VA_ARGS__), \ - _NMLOG_PREFIX_NAME, \ - ((!__self || __self == singleton_instance) \ - ? "" \ - : nm_sprintf_buf (__prefix, "[%p]", __self)) \ - _NM_UTILS_MACRO_REST (__VA_ARGS__)); \ - } \ - } G_STMT_END - -/*****************************************************************************/ - -static void _ip_config_dns_priority_changed (gpointer config, - GParamSpec *pspec, - NMDnsIPConfigData *ip_data); - -/*****************************************************************************/ - static gboolean -domain_is_valid (const char *domain, gboolean check_public_suffix) +domain_is_valid (const gchar *domain, gboolean check_public_suffix) { if (*domain == '\0') return FALSE; @@ -190,14 +169,16 @@ domain_is_valid (const char *domain, gboolean check_public_suffix) return TRUE; } -static gboolean -domain_is_routing (const char *domain) -{ - return domain[0] == '~'; -} - /*****************************************************************************/ +typedef struct { + GPtrArray *nameservers; + GPtrArray *searches; + GPtrArray *options; + const char *nis_domain; + GPtrArray *nis_servers; +} NMResolvConfData; + NM_UTILS_LOOKUP_STR_DEFINE_STATIC (_rc_manager_to_string, NMDnsManagerResolvConfManager, NM_UTILS_LOOKUP_DEFAULT_WARN (NULL), NM_UTILS_LOOKUP_STR_ITEM (NM_DNS_MANAGER_RESOLV_CONF_MAN_UNKNOWN, "unknown"), @@ -211,109 +192,44 @@ NM_UTILS_LOOKUP_STR_DEFINE_STATIC (_rc_manager_to_string, NMDnsManagerResolvConf NM_UTILS_LOOKUP_STR_DEFINE_STATIC (_config_type_to_string, NMDnsIPConfigType, NM_UTILS_LOOKUP_DEFAULT_WARN ("<unknown>"), - NM_UTILS_LOOKUP_STR_ITEM (NM_DNS_IP_CONFIG_TYPE_REMOVED, "removed"), NM_UTILS_LOOKUP_STR_ITEM (NM_DNS_IP_CONFIG_TYPE_DEFAULT, "default"), NM_UTILS_LOOKUP_STR_ITEM (NM_DNS_IP_CONFIG_TYPE_BEST_DEVICE, "best"), NM_UTILS_LOOKUP_STR_ITEM (NM_DNS_IP_CONFIG_TYPE_VPN, "vpn"), ); -/*****************************************************************************/ - -static void -_ASSERT_config_data (const NMDnsConfigData *data) -{ - nm_assert (data); - nm_assert (NM_IS_DNS_MANAGER (data->self)); - nm_assert (data->ifindex > 0); -} - -static void -_ASSERT_ip_config_data (const NMDnsIPConfigData *ip_data) -{ - nm_assert (ip_data); - _ASSERT_config_data (ip_data->data); - nm_assert (NM_IS_IP_CONFIG (ip_data->ip_config)); - nm_assert (c_list_contains (&ip_data->data->data_lst_head, &ip_data->data_lst)); - nm_assert (ip_data->data->ifindex == nm_ip_config_get_ifindex (ip_data->ip_config)); -} - static NMDnsIPConfigData * -_ip_config_data_new (NMDnsConfigData *data, - NMIPConfig *ip_config, - NMDnsIPConfigType ip_config_type) -{ - NMDnsIPConfigData *ip_data; - - _ASSERT_config_data (data); - nm_assert (NM_IS_IP_CONFIG (ip_config)); - nm_assert (ip_config_type != NM_DNS_IP_CONFIG_TYPE_REMOVED); - - ip_data = g_slice_new0 (NMDnsIPConfigData); - ip_data->data = data; - ip_data->ip_config = g_object_ref (ip_config); - ip_data->ip_config_type = ip_config_type; - c_list_link_tail (&data->data_lst_head, &ip_data->data_lst); - c_list_link_tail (&NM_DNS_MANAGER_GET_PRIVATE (data->self)->ip_config_lst_head, &ip_data->ip_config_lst); - - g_signal_connect (ip_config, - NM_IS_IP4_CONFIG (ip_config) - ? "notify::" NM_IP4_CONFIG_DNS_PRIORITY - : "notify::" NM_IP6_CONFIG_DNS_PRIORITY, - (GCallback) _ip_config_dns_priority_changed, ip_data); - - _ASSERT_ip_config_data (ip_data); - return ip_data; -} - -static void -_ip_config_data_free (NMDnsIPConfigData *ip_data) +ip_config_data_new (gpointer config, NMDnsIPConfigType type, const char *iface) { - _ASSERT_ip_config_data (ip_data); + NMDnsIPConfigData *data; - c_list_unlink_stale (&ip_data->data_lst); - c_list_unlink_stale (&ip_data->ip_config_lst); + data = g_slice_new0 (NMDnsIPConfigData); + data->config = g_object_ref (config); + data->iface = g_strdup (iface); + data->type = type; - g_signal_handlers_disconnect_by_func (ip_data->ip_config, - _ip_config_dns_priority_changed, - ip_data); - - g_object_unref (ip_data->ip_config); - g_slice_free (NMDnsIPConfigData, ip_data); -} - -static NMDnsIPConfigData * -_config_data_find_ip_config (NMDnsConfigData *data, - NMIPConfig *ip_config) -{ - NMDnsIPConfigData *ip_data; - - _ASSERT_config_data (data); - - c_list_for_each_entry (ip_data, &data->data_lst_head, data_lst) { - _ASSERT_ip_config_data (ip_data); - - if (ip_data->ip_config == ip_config) - return ip_data; - } - return NULL; + return data; } static void -_config_data_free (NMDnsConfigData *data) +ip_config_data_destroy (gpointer ptr) { - _ASSERT_config_data (data); + NMDnsIPConfigData *data = ptr; + + if (!data) + return; - nm_assert (c_list_is_empty (&data->data_lst_head)); - g_slice_free (NMDnsConfigData, data); + g_object_unref (data->config); + g_free (data->iface); + g_slice_free (NMDnsIPConfigData, data); } static gint -_ip_config_data_cmp (const NMDnsIPConfigData *a, const NMDnsIPConfigData *b) +ip_config_data_compare (const NMDnsIPConfigData *a, const NMDnsIPConfigData *b) { int a_prio, b_prio; - a_prio = nm_ip_config_get_dns_priority (a->ip_config); - b_prio = nm_ip_config_get_dns_priority (b->ip_config); + a_prio = nm_ip_config_get_dns_priority (a->config); + b_prio = nm_ip_config_get_dns_priority (b->config); /* Configurations with lower priority value first */ if (a_prio < b_prio) @@ -322,40 +238,24 @@ _ip_config_data_cmp (const NMDnsIPConfigData *a, const NMDnsIPConfigData *b) return 1; /* Sort also according to type */ - if (a->ip_config_type > b->ip_config_type) + if (a->type > b->type) return -1; - else if (a->ip_config_type < b->ip_config_type) + else if (a->type < b->type) return 1; return 0; } static gint -_ip_config_lst_cmp (const CList *a, - const CList *b, - const void *user_data) +ip_config_data_ptr_compare (gconstpointer a, gconstpointer b) { - return _ip_config_data_cmp (c_list_entry (a, NMDnsIPConfigData, ip_config_lst), - c_list_entry (b, NMDnsIPConfigData, ip_config_lst)); -} + const NMDnsIPConfigData *const *ptr_a = a, *const *ptr_b = b; -static CList * -_ip_config_lst_head (NMDnsManager *self) -{ - NMDnsManagerPrivate *priv = NM_DNS_MANAGER_GET_PRIVATE (self); - - if (priv->ip_config_lst_need_sort) { - priv->ip_config_lst_need_sort = FALSE; - c_list_sort (&priv->ip_config_lst_head, _ip_config_lst_cmp, NULL); - } - - return &priv->ip_config_lst_head; + return ip_config_data_compare (*ptr_a, *ptr_b); } -/*****************************************************************************/ - static void -add_string_item (GPtrArray *array, const char *str, gboolean dup) +add_string_item (GPtrArray *array, const char *str) { int i; @@ -371,7 +271,7 @@ add_string_item (GPtrArray *array, const char *str, gboolean dup) } /* No dupes, add the new item */ - g_ptr_array_add (array, dup ? g_strdup (str): (gpointer) str); + g_ptr_array_add (array, g_strdup (str)); } static void @@ -382,55 +282,24 @@ add_dns_option_item (GPtrArray *array, const char *str) } static void -add_dns_domains (GPtrArray *array, const NMIPConfig *ip_config, - gboolean include_routing, gboolean dup) -{ - guint num_domains, num_searches, i; - const char *str; - - num_domains = nm_ip_config_get_num_domains (ip_config); - num_searches = nm_ip_config_get_num_searches (ip_config); - - for (i = 0; i < num_searches; i++) { - str = nm_ip_config_get_search (ip_config, i); - if (!include_routing && domain_is_routing (str)) - continue; - if (!domain_is_valid (nm_utils_parse_dns_domain (str, NULL), FALSE)) - continue; - add_string_item (array, str, dup); - } - if (num_domains > 1 || !num_searches) { - for (i = 0; i < num_domains; i++) { - str = nm_ip_config_get_domain (ip_config, i); - if (!include_routing && domain_is_routing (str)) - continue; - if (!domain_is_valid (nm_utils_parse_dns_domain (str, NULL), FALSE)) - continue; - add_string_item (array, str, dup); - } - } -} - -static void merge_one_ip_config (NMResolvConfData *rc, - int ifindex, - const NMIPConfig *ip_config) + const NMIPConfig *config, + const char *iface) { int addr_family; - guint num, i; + guint num, num_domains, num_searches, i; char buf[NM_UTILS_INET_ADDRSTRLEN + 50]; + const char *str; - addr_family = nm_ip_config_get_addr_family (ip_config); + addr_family = nm_ip_config_get_addr_family (config); nm_assert_addr_family (addr_family); - nm_assert (ifindex > 0); - nm_assert (ifindex == nm_ip_config_get_ifindex (ip_config)); - num = nm_ip_config_get_num_nameservers (ip_config); + num = nm_ip_config_get_num_nameservers (config); for (i = 0; i < num; i++) { const NMIPAddr *addr; - addr = nm_ip_config_get_nameserver (ip_config, i); + addr = nm_ip_config_get_nameserver (config, i); if (addr_family == AF_INET) nm_utils_inet_ntop (addr_family, addr, buf); else if (IN6_IS_ADDR_V4MAPPED (addr)) @@ -438,42 +307,49 @@ merge_one_ip_config (NMResolvConfData *rc, else { nm_utils_inet6_ntop (&addr->addr6, buf); if (IN6_IS_ADDR_LINKLOCAL (addr)) { - const char *ifname; - - ifname = nm_platform_link_get_name (NM_PLATFORM_GET, ifindex); - if (ifname) { - g_strlcat (buf, "%", sizeof (buf)); - g_strlcat (buf, ifname, sizeof (buf)); - } + g_strlcat (buf, "%", sizeof (buf)); + g_strlcat (buf, iface, sizeof (buf)); } } - add_string_item (rc->nameservers, buf, TRUE); + add_string_item (rc->nameservers, buf); } - add_dns_domains (rc->searches, ip_config, FALSE, TRUE); + num_domains = nm_ip_config_get_num_domains (config); + num_searches = nm_ip_config_get_num_searches (config); + for (i = 0; i < num_searches; i++) { + str = nm_ip_config_get_search (config, i); + if (domain_is_valid (str, FALSE)) + add_string_item (rc->searches, str); + } + if (num_domains > 1 || !num_searches) { + for (i = 0; i < num_domains; i++) { + str = nm_ip_config_get_domain (config, i); + if (domain_is_valid (str, FALSE)) + add_string_item (rc->searches, str); + } + } - num = nm_ip_config_get_num_dns_options (ip_config); + num = nm_ip_config_get_num_dns_options (config); for (i = 0; i < num; i++) { add_dns_option_item (rc->options, - nm_ip_config_get_dns_option (ip_config, i)); + nm_ip_config_get_dns_option (config, i)); } if (addr_family == AF_INET) { - const NMIP4Config *ip4_config = (const NMIP4Config *) ip_config; + const NMIP4Config *config4 = (const NMIP4Config *) config; /* NIS stuff */ - num = nm_ip4_config_get_num_nis_servers (ip4_config); + num = nm_ip4_config_get_num_nis_servers (config4); for (i = 0; i < num; i++) { add_string_item (rc->nis_servers, - nm_utils_inet4_ntop (nm_ip4_config_get_nis_server (ip4_config, i), buf), - TRUE); + nm_utils_inet4_ntop (nm_ip4_config_get_nis_server (config4, i), buf)); } - if (nm_ip4_config_get_nis_domain (ip4_config)) { + if (nm_ip4_config_get_nis_domain (config4)) { /* FIXME: handle multiple domains */ if (!rc->nis_domain) - rc->nis_domain = nm_ip4_config_get_nis_domain (ip4_config); + rc->nis_domain = nm_ip4_config_get_nis_domain (config4); } } } @@ -502,59 +378,58 @@ run_netconfig (NMDnsManager *self, GError **error, gint *stdin_fd) } static void -netconfig_construct_str (NMDnsManager *self, GString *str, const char *key, const char *value) +write_to_netconfig (NMDnsManager *self, gint fd, const char *key, const char *value) { - if (value) { - _LOGD ("writing to netconfig: %s='%s'", key, value); - g_string_append_printf (str, "%s='%s'\n", key, value); - } -} + char *str; + int x; -static void -netconfig_construct_strv (NMDnsManager *self, GString *str, const char *key, const char *const*values) -{ - if (values) { - gs_free char *value = NULL; - - value = g_strjoinv (" ", (char **) values); - netconfig_construct_str (self, str, key, value); - } + str = g_strdup_printf ("%s='%s'\n", key, value); + _LOGD ("writing to netconfig: %s", str); + x = write (fd, str, strlen (str)); + g_free (str); } static SpawnResult dispatch_netconfig (NMDnsManager *self, - const char *const*searches, - const char *const*nameservers, + char **searches, + char **nameservers, const char *nis_domain, - const char *const*nis_servers, + char **nis_servers, GError **error) { + char *str; GPid pid; gint fd; int status; - gssize l; - nm_auto_free_gstring GString *str = NULL; pid = run_netconfig (self, error, &fd); if (pid <= 0) return SR_NOTFOUND; - str = g_string_new (""); - /* NM is writing already-merged DNS information to netconfig, so it * does not apply to a specific network interface. */ - netconfig_construct_str (self, str, "INTERFACE", "NetworkManager"); - netconfig_construct_strv (self, str, "DNSSEARCH", searches); - netconfig_construct_strv (self, str, "DNSSERVERS", nameservers); - netconfig_construct_str (self, str, "NISDOMAIN", nis_domain); - netconfig_construct_strv (self, str, "NISSERVERS", nis_servers); + write_to_netconfig (self, fd, "INTERFACE", "NetworkManager"); -again: - l = write (fd, str->str, str->len); - if (l == -1) { - if (errno == EINTR) - goto again; + if (searches) { + str = g_strjoinv (" ", searches); + write_to_netconfig (self, fd, "DNSSEARCH", str); + g_free (str); + } + + if (nameservers) { + str = g_strjoinv (" ", nameservers); + write_to_netconfig (self, fd, "DNSSERVERS", str); + g_free (str); + } + + if (nis_domain) + write_to_netconfig (self, fd, "NISDOMAIN", nis_domain); + + if (nis_servers) { + str = g_strjoinv (" ", nis_servers); + write_to_netconfig (self, fd, "NISSERVERS", str); + g_free (str); } nm_close (fd); @@ -868,7 +743,7 @@ update_resolv_conf (NMDnsManager *self, if (rc_manager == NM_DNS_MANAGER_RESOLV_CONF_MAN_FILE) { _LOGT ("update-resolv-conf: write internal file %s succeeded (rc-manager=%s)", - MY_RESOLV_CONF, _rc_manager_to_string (rc_manager)); + rc_path, _rc_manager_to_string (rc_manager)); return write_file_result; } @@ -942,21 +817,25 @@ update_resolv_conf (NMDnsManager *self, static void compute_hash (NMDnsManager *self, const NMGlobalDnsConfig *global, guint8 buffer[HASH_LEN]) { + NMDnsManagerPrivate *priv = NM_DNS_MANAGER_GET_PRIVATE (self); GChecksum *sum; gsize len = HASH_LEN; - NMDnsIPConfigData *ip_data; + guint i; sum = g_checksum_new (G_CHECKSUM_SHA1); - nm_assert (len == g_checksum_type_get_length (G_CHECKSUM_SHA1)); + g_assert (len == g_checksum_type_get_length (G_CHECKSUM_SHA1)); if (global) nm_global_dns_config_update_checksum (global, sum); else { - const CList *head; + for (i = 0; i < priv->configs->len; i++) { + NMDnsIPConfigData *data = priv->configs->pdata[i]; - head = _ip_config_lst_head (self); - c_list_for_each_entry (ip_data, head, ip_config_lst) - nm_ip_config_hash (ip_data->ip_config, sum, TRUE); + if (NM_IS_IP4_CONFIG (data->config)) + nm_ip4_config_hash ((NMIP4Config *) data->config, sum, TRUE); + else if (NM_IS_IP6_CONFIG (data->config)) + nm_ip6_config_hash ((NMIP6Config *) data->config, sum, TRUE); + } } g_checksum_get_digest (sum, buffer, &len); @@ -970,36 +849,27 @@ merge_global_dns_config (NMResolvConfData *rc, NMGlobalDnsConfig *global_conf) const char *const *searches; const char *const *options; const char *const *servers; - guint i; + gint i; if (!global_conf) return FALSE; searches = nm_global_dns_config_get_searches (global_conf); - if (searches) { - for (i = 0; searches[i]; i++) { - if (domain_is_routing (searches[i])) - continue; - if (!domain_is_valid (searches[i], FALSE)) - continue; - add_string_item (rc->searches, searches[i], TRUE); - } - } - options = nm_global_dns_config_get_options (global_conf); - if (options) { - for (i = 0; options[i]; i++) - add_string_item (rc->options, options[i], TRUE); + + for (i = 0; searches && searches[i]; i++) { + if (domain_is_valid (searches[i], FALSE)) + add_string_item (rc->searches, searches[i]); } - default_domain = nm_global_dns_config_lookup_domain (global_conf, "*"); - nm_assert (default_domain); + for (i = 0; options && options[i]; i++) + add_string_item (rc->options, options[i]); + default_domain = nm_global_dns_config_lookup_domain (global_conf, "*"); + g_assert (default_domain); servers = nm_global_dns_domain_get_servers (default_domain); - if (servers) { - for (i = 0; servers[i]; i++) - add_string_item (rc->nameservers, servers[i], TRUE); - } + for (i = 0; servers && servers[i]; i++) + add_string_item (rc->nameservers, servers[i]); return TRUE; } @@ -1039,16 +909,17 @@ _ptrarray_to_strv (GPtrArray *parray) } static void -_collect_resolv_conf_data (NMDnsManager *self, +_collect_resolv_conf_data (NMDnsManager *self, /* only for logging context, no other side-effects */ NMGlobalDnsConfig *global_config, + const GPtrArray *configs, + const char *hostname, char ***out_searches, char ***out_options, char ***out_nameservers, char ***out_nis_servers, const char **out_nis_domain) { - NMDnsManagerPrivate *priv; - guint i, num, len; + guint i, j, num, len; NMResolvConfData rc = { .nameservers = g_ptr_array_new (), .searches = g_ptr_array_new (), @@ -1057,44 +928,37 @@ _collect_resolv_conf_data (NMDnsManager *self, .nis_servers = g_ptr_array_new (), }; - priv = NM_DNS_MANAGER_GET_PRIVATE (self); - if (global_config) merge_global_dns_config (&rc, global_config); else { nm_auto_free_gstring GString *tmp_gstring = NULL; int prio, first_prio = 0; - const NMDnsIPConfigData *ip_data; - const CList *head; - gboolean is_first = TRUE; + NMDnsIPConfigData *current; - head = _ip_config_lst_head (self); - c_list_for_each_entry (ip_data, head, ip_config_lst) { + for (i = 0, j = 0; i < configs->len; i++) { gboolean skip = FALSE; - _ASSERT_ip_config_data (ip_data); + current = configs->pdata[i]; - prio = nm_ip_config_get_dns_priority (ip_data->ip_config); + prio = nm_ip_config_get_dns_priority (current->config); - if (is_first) { - is_first = FALSE; + if (i == 0) first_prio = prio; - } else if ( first_prio < 0 - && first_prio != prio) + else if (first_prio < 0 && first_prio != prio) skip = TRUE; - if (nm_ip_config_get_num_nameservers (ip_data->ip_config)) { - _LOGT ("config: %8d %-7s v%c %-5d %s: %s", + if (nm_ip_config_get_num_nameservers (current->config)) { + _LOGT ("config: %8d %-7s v%c %-16s %s: %s", prio, - _config_type_to_string (ip_data->ip_config_type), - nm_utils_addr_family_to_char (nm_ip_config_get_addr_family (ip_data->ip_config)), - ip_data->data->ifindex, + _config_type_to_string (current->type), + nm_utils_addr_family_to_char (nm_ip_config_get_addr_family (current->config)), + current->iface, skip ? "<SKIP>" : "", - get_nameserver_list (ip_data->ip_config, &tmp_gstring)); + get_nameserver_list (current->config, &tmp_gstring)); } if (!skip) - merge_one_ip_config (&rc, ip_data->data->ifindex, ip_data->ip_config); + merge_one_ip_config (&rc, current->config, current->iface); } } @@ -1105,16 +969,16 @@ _collect_resolv_conf_data (NMDnsManager *self, * (eg, "example.com"), then use the hostname itself as the search (since the user is * unlikely to want "com" as a search domain). */ - if (priv->hostname) { - const char *hostdomain = strchr (priv->hostname, '.'); + if (hostname) { + const char *hostdomain = strchr (hostname, '.'); if ( hostdomain - && !nm_utils_ipaddr_valid (AF_UNSPEC, priv->hostname)) { + && !nm_utils_ipaddr_valid (AF_UNSPEC, hostname)) { hostdomain++; if (domain_is_valid (hostdomain, TRUE)) - add_string_item (rc.searches, hostdomain, TRUE); - else if (domain_is_valid (priv->hostname, TRUE)) - add_string_item (rc.searches, priv->hostname, TRUE); + add_string_item (rc.searches, hostdomain); + else if (domain_is_valid (hostname, TRUE)) + add_string_item (rc.searches, hostname); } } @@ -1176,12 +1040,16 @@ update_dns (NMDnsManager *self, data = nm_config_get_data (priv->config); global_config = nm_config_data_get_global_dns_config (data); + if (priv->need_sort) { + g_ptr_array_sort (priv->configs, ip_config_data_ptr_compare); + priv->need_sort = FALSE; + } + /* Update hash with config we're applying */ compute_hash (self, global_config, priv->hash); - _collect_resolv_conf_data (self, global_config, - &searches, &options, &nameservers, - &nis_servers, &nis_domain); + _collect_resolv_conf_data (self, global_config, priv->configs, priv->hostname, + &searches, &options, &nameservers, &nis_servers, &nis_domain); /* Let any plugins do their thing first */ if (priv->plugin) { @@ -1199,8 +1067,8 @@ update_dns (NMDnsManager *self, _LOGD ("update-dns: updating plugin %s", plugin_name); if (!nm_dns_plugin_update (plugin, + priv->configs, global_config, - _ip_config_lst_head (self), priv->hostname)) { _LOGW ("update-dns: plugin %s update failed", plugin_name); @@ -1246,12 +1114,8 @@ update_dns (NMDnsManager *self, result = dispatch_resolvconf (self, searches, nameservers, options, error); break; case NM_DNS_MANAGER_RESOLV_CONF_MAN_NETCONFIG: - result = dispatch_netconfig (self, - (const char *const*) searches, - (const char *const*) nameservers, - nis_domain, - (const char *const*) nis_servers, - error); + result = dispatch_netconfig (self, searches, nameservers, nis_domain, + nis_servers, error); break; default: g_assert_not_reached (); @@ -1341,96 +1205,82 @@ plugin_child_quit (NMDnsPlugin *plugin, int exit_status, gpointer user_data) } static void -_ip_config_dns_priority_changed (gpointer config, - GParamSpec *pspec, - NMDnsIPConfigData *ip_data) +ip_config_dns_priority_changed (gpointer config, + GParamSpec *pspec, + NMDnsManager *self) { - _ASSERT_ip_config_data (ip_data); + NM_DNS_MANAGER_GET_PRIVATE (self)->need_sort = TRUE; +} - NM_DNS_MANAGER_GET_PRIVATE (ip_data->data->self)->ip_config_lst_need_sort = TRUE; +static void +forget_data (NMDnsManager *self, NMDnsIPConfigData *data) +{ + NMDnsManagerPrivate *priv = NM_DNS_MANAGER_GET_PRIVATE (self); + + if (data == priv->best_conf4) + priv->best_conf4 = NULL; + else if (data == priv->best_conf6) + priv->best_conf6 = NULL; + + g_signal_handlers_disconnect_by_func (data->config, ip_config_dns_priority_changed, self); } gboolean -nm_dns_manager_set_ip_config (NMDnsManager *self, - NMIPConfig *ip_config, - NMDnsIPConfigType ip_config_type) +nm_dns_manager_add_ip_config (NMDnsManager *self, + const char *iface, + gpointer config, + NMDnsIPConfigType cfg_type) { NMDnsManagerPrivate *priv; GError *error = NULL; - NMDnsIPConfigData *ip_data; - NMDnsConfigData *data; - int ifindex; - NMDnsIPConfigData **p_best; + NMDnsIPConfigData *data; + gboolean v4 = NM_IS_IP4_CONFIG (config); + guint i; g_return_val_if_fail (NM_IS_DNS_MANAGER (self), FALSE); - g_return_val_if_fail (NM_IS_IP_CONFIG (ip_config), FALSE); - - ifindex = nm_ip_config_get_ifindex (ip_config); - g_return_val_if_fail (ifindex > 0, FALSE); + g_return_val_if_fail (config, FALSE); + g_return_val_if_fail (iface && iface[0], FALSE); + nm_assert (NM_IS_IP_CONFIG (config)); priv = NM_DNS_MANAGER_GET_PRIVATE (self); - data = g_hash_table_lookup (priv->configs, GINT_TO_POINTER (ifindex)); - if (!data) - ip_data = NULL; - else - ip_data = _config_data_find_ip_config (data, ip_config); - - if (ip_config_type == NM_DNS_IP_CONFIG_TYPE_REMOVED) { - if (!ip_data) - return FALSE; - if (priv->best_ip_config_4 == ip_data) - priv->best_ip_config_4 = NULL; - if (priv->best_ip_config_6 == ip_data) - priv->best_ip_config_6 = NULL; - /* deleting a config doesn't invalidate the configs' sort order. */ - _ip_config_data_free (ip_data); - if (c_list_is_empty (&data->data_lst_head)) - g_hash_table_remove (priv->configs, GINT_TO_POINTER (ifindex)); - goto changed; - } - - if ( ip_data - && ip_data->ip_config_type == ip_config_type) { - /* nothing to do. */ - return FALSE; - } - - if (!data) { - data = g_slice_new0 (NMDnsConfigData); - data->ifindex = ifindex; - data->self = self; - c_list_init (&data->data_lst_head); - _ASSERT_config_data (data); - g_hash_table_insert (priv->configs, GINT_TO_POINTER (ifindex), data); + for (i = 0; i < priv->configs->len; i++) { + data = priv->configs->pdata[i]; + if (data->config == config) { + if ( nm_streq (data->iface, iface) + && data->type == cfg_type) + return FALSE; + else { + forget_data (self, data); + g_ptr_array_remove_index_fast (priv->configs, i); + break; + } + } } - if (!ip_data) - ip_data = _ip_config_data_new (data, ip_config, ip_config_type); - else - ip_data->ip_config_type = ip_config_type; - - priv->ip_config_lst_need_sort = TRUE; - - p_best = NM_IS_IP4_CONFIG (ip_config) - ? &priv->best_ip_config_4 - : &priv->best_ip_config_6; + data = ip_config_data_new (config, cfg_type, iface); + g_ptr_array_add (priv->configs, data); + g_signal_connect (config, + v4 ? + "notify::" NM_IP4_CONFIG_DNS_PRIORITY : + "notify::" NM_IP6_CONFIG_DNS_PRIORITY, + (GCallback) ip_config_dns_priority_changed, self); + priv->need_sort = TRUE; - if (ip_config_type == NM_DNS_IP_CONFIG_TYPE_BEST_DEVICE) { + if (cfg_type == NM_DNS_IP_CONFIG_TYPE_BEST_DEVICE) { /* Only one best-device per IP version is allowed */ - if (*p_best != ip_data) { - if (*p_best) - (*p_best)->ip_config_type = NM_DNS_IP_CONFIG_TYPE_DEFAULT; - *p_best = ip_data; + if (v4) { + if (priv->best_conf4) + priv->best_conf4->type = NM_DNS_IP_CONFIG_TYPE_DEFAULT; + priv->best_conf4 = data; + } else { + if (priv->best_conf6) + priv->best_conf6->type = NM_DNS_IP_CONFIG_TYPE_DEFAULT; + priv->best_conf6 = data; } - } else { - if (*p_best == ip_data) - *p_best = NULL; } -changed: - if ( !priv->updates_queue - && !update_dns (self, FALSE, &error)) { + if (!priv->updates_queue && !update_dns (self, FALSE, &error)) { _LOGW ("could not commit DNS changes: %s", error->message); g_clear_error (&error); } @@ -1438,6 +1288,38 @@ changed: return TRUE; } +gboolean +nm_dns_manager_remove_ip_config (NMDnsManager *self, gpointer config) +{ + NMDnsManagerPrivate *priv; + GError *error = NULL; + NMDnsIPConfigData *data; + guint i; + + g_return_val_if_fail (NM_IS_DNS_MANAGER (self), FALSE); + g_return_val_if_fail (config, FALSE); + nm_assert (NM_IS_IP_CONFIG (config)); + + priv = NM_DNS_MANAGER_GET_PRIVATE (self); + + for (i = 0; i < priv->configs->len; i++) { + data = priv->configs->pdata[i]; + + if (data->config == config) { + forget_data (self, data); + g_ptr_array_remove_index (priv->configs, i); + + if (!priv->updates_queue && !update_dns (self, FALSE, &error)) { + _LOGW ("could not commit DNS changes: %s", error->message); + g_clear_error (&error); + } + + return TRUE; + } + } + return FALSE; +} + void nm_dns_manager_set_initial_hostname (NMDnsManager *self, const char *hostname) @@ -1480,6 +1362,23 @@ nm_dns_manager_set_hostname (NMDnsManager *self, } } +gboolean +nm_dns_manager_get_resolv_conf_explicit (NMDnsManager *self) +{ + NMDnsManagerPrivate *priv; + + g_return_val_if_fail (NM_IS_DNS_MANAGER (self), FALSE); + + priv = NM_DNS_MANAGER_GET_PRIVATE (self); + + if ( NM_IN_SET (priv->rc_manager, NM_DNS_MANAGER_RESOLV_CONF_MAN_UNMANAGED, + NM_DNS_MANAGER_RESOLV_CONF_MAN_IMMUTABLE) + || priv->plugin) + return FALSE; + + return TRUE; +} + void nm_dns_manager_begin_updates (NMDnsManager *self, const char *func) { @@ -1510,6 +1409,11 @@ nm_dns_manager_end_updates (NMDnsManager *self, const char *func) priv = NM_DNS_MANAGER_GET_PRIVATE (self); g_return_if_fail (priv->updates_queue > 0); + if (priv->need_sort) { + g_ptr_array_sort (priv->configs, ip_config_data_ptr_compare); + priv->need_sort = FALSE; + } + compute_hash (self, nm_config_data_get_global_dns_config (nm_config_get_data (priv->config)), new); changed = (memcmp (new, priv->prev_hash, sizeof (new)) != 0) ? TRUE : FALSE; _LOGD ("(%s): DNS configuration %s", func, changed ? "changed" : "did not change"); @@ -1906,14 +1810,14 @@ _get_config_variant (NMDnsManager *self) NMGlobalDnsConfig *global_config; gs_free char *str = NULL; GVariantBuilder builder; - NMDnsIPConfigData *ip_data; - const CList *head; - gs_unref_ptrarray GPtrArray *array_domains = NULL; + NMConfigData *data; + guint i, j; if (priv->config_variant) return priv->config_variant; - global_config = nm_config_data_get_global_dns_config (nm_config_get_data (priv->config)); + data = nm_config_get_data (priv->config); + global_config = nm_config_data_get_global_dns_config (data); if (global_config) { priv->config_variant = _get_global_config_variant (global_config); _LOGT ("current configuration: %s", (str = g_variant_print (priv->config_variant, TRUE))); @@ -1922,26 +1826,25 @@ _get_config_variant (NMDnsManager *self) g_variant_builder_init (&builder, G_VARIANT_TYPE ("aa{sv}")); - head = _ip_config_lst_head (self); - c_list_for_each_entry (ip_data, head, ip_config_lst) { - const NMIPConfig *ip_config = ip_data->ip_config; + for (i = 0; i < priv->configs->len; i++) { + NMDnsIPConfigData *current = priv->configs->pdata[i]; + const NMIPConfig *config = current->config; GVariantBuilder entry_builder; GVariantBuilder strv_builder; - guint i, num; - const int addr_family = nm_ip_config_get_addr_family (ip_config); + guint num; + const int addr_family = nm_ip_config_get_addr_family (config); char buf[NM_UTILS_INET_ADDRSTRLEN]; const NMIPAddr *addr; - const char *ifname; - num = nm_ip_config_get_num_nameservers (ip_config); + num = nm_ip_config_get_num_nameservers (config); if (!num) continue; g_variant_builder_init (&entry_builder, G_VARIANT_TYPE ("a{sv}")); g_variant_builder_init (&strv_builder, G_VARIANT_TYPE ("as")); - for (i = 0; i < num; i++) { - addr = nm_ip_config_get_nameserver (ip_config, i); + for (j = 0; j < num; j++) { + addr = nm_ip_config_get_nameserver (config, j); g_variant_builder_add (&strv_builder, "s", nm_utils_inet_ntop (addr_family, addr, buf)); @@ -1951,47 +1854,36 @@ _get_config_variant (NMDnsManager *self) "nameservers", g_variant_builder_end (&strv_builder)); - - num = nm_ip_config_get_num_domains (ip_config); - num += nm_ip_config_get_num_searches (ip_config); + num = nm_ip_config_get_num_domains (config); if (num > 0) { - if (!array_domains) - array_domains = g_ptr_array_sized_new (num); - else - g_ptr_array_set_size (array_domains, 0); - - add_dns_domains (array_domains, ip_config, TRUE, FALSE); - if (array_domains->len) { - g_variant_builder_init (&strv_builder, G_VARIANT_TYPE ("as")); - for (i = 0; i < array_domains->len; i++) { - g_variant_builder_add (&strv_builder, - "s", - array_domains->pdata[i]); - } - g_variant_builder_add (&entry_builder, - "{sv}", - "domains", - g_variant_builder_end (&strv_builder)); + g_variant_builder_init (&strv_builder, G_VARIANT_TYPE ("as")); + for (j = 0; j < num; j++) { + g_variant_builder_add (&strv_builder, + "s", + nm_ip_config_get_domain (config, j)); } + g_variant_builder_add (&entry_builder, + "{sv}", + "domains", + g_variant_builder_end (&strv_builder)); } - ifname = nm_platform_link_get_name (NM_PLATFORM_GET, ip_data->data->ifindex); - if (ifname) { + if (current->iface) { g_variant_builder_add (&entry_builder, "{sv}", "interface", - g_variant_new_string (ifname)); + g_variant_new_string (current->iface)); } g_variant_builder_add (&entry_builder, "{sv}", "priority", - g_variant_new_int32 (nm_ip_config_get_dns_priority (ip_config))); + g_variant_new_int32 (nm_ip_config_get_dns_priority (config))); g_variant_builder_add (&entry_builder, "{sv}", "vpn", - g_variant_new_boolean (ip_data->ip_config_type == NM_DNS_IP_CONFIG_TYPE_VPN)); + g_variant_new_boolean (current->type == NM_DNS_IP_CONFIG_TYPE_VPN)); g_variant_builder_add (&builder, "a{sv}", &entry_builder); } @@ -2032,12 +1924,8 @@ nm_dns_manager_init (NMDnsManager *self) _LOGT ("creating..."); - c_list_init (&priv->ip_config_lst_head); - priv->config = g_object_ref (nm_config_get ()); - - priv->configs = g_hash_table_new_full (nm_direct_hash, NULL, - NULL, (GDestroyNotify) _config_data_free); + priv->configs = g_ptr_array_new_full (8, ip_config_data_destroy); /* Set the initial hash */ compute_hash (self, NULL, NM_DNS_MANAGER_GET_PRIVATE (self)->hash); @@ -2054,33 +1942,33 @@ dispose (GObject *object) { NMDnsManager *self = NM_DNS_MANAGER (object); NMDnsManagerPrivate *priv = NM_DNS_MANAGER_GET_PRIVATE (self); - NMDnsIPConfigData *ip_data, *ip_data_safe; + NMDnsIPConfigData *data; + guint i; _LOGT ("disposing"); if (!priv->is_stopped) nm_dns_manager_stop (self); - if (priv->config) - g_signal_handlers_disconnect_by_func (priv->config, config_changed_cb, self); - _clear_plugin (self); - priv->best_ip_config_4 = NULL; - priv->best_ip_config_6 = NULL; - - c_list_for_each_entry_safe (ip_data, ip_data_safe, &priv->ip_config_lst_head, ip_config_lst) - _ip_config_data_free (ip_data); + if (priv->config) { + g_signal_handlers_disconnect_by_func (priv->config, config_changed_cb, self); + g_clear_object (&priv->config); + } - g_clear_pointer (&priv->configs, g_hash_table_destroy); + if (priv->configs) { + for (i = 0; i < priv->configs->len; i++) { + data = priv->configs->pdata[i]; + forget_data (self, data); + } + g_ptr_array_free (priv->configs, TRUE); + priv->configs = NULL; + } nm_clear_g_source (&priv->plugin_ratelimit.timer); - g_clear_object (&priv->config); - G_OBJECT_CLASS (nm_dns_manager_parent_class)->dispose (object); - - g_clear_pointer (&priv->config_variant, g_variant_unref); } static void @@ -2095,30 +1983,18 @@ finalize (GObject *object) G_OBJECT_CLASS (nm_dns_manager_parent_class)->finalize (object); } -static const NMDBusInterfaceInfoExtended interface_info_dns_manager = { - .parent = NM_DEFINE_GDBUS_INTERFACE_INFO_INIT ( - NM_DBUS_INTERFACE_DNS_MANAGER, - .properties = NM_DEFINE_GDBUS_PROPERTY_INFOS ( - NM_DEFINE_DBUS_PROPERTY_INFO_EXTENDED_READABLE_L ("Mode", "s", NM_DNS_MANAGER_MODE), - NM_DEFINE_DBUS_PROPERTY_INFO_EXTENDED_READABLE_L ("RcManager", "s", NM_DNS_MANAGER_RC_MANAGER), - NM_DEFINE_DBUS_PROPERTY_INFO_EXTENDED_READABLE_L ("Configuration", "aa{sv}", NM_DNS_MANAGER_CONFIGURATION), - ), - ), -}; - static void nm_dns_manager_class_init (NMDnsManagerClass *klass) { GObjectClass *object_class = G_OBJECT_CLASS (klass); - NMDBusObjectClass *dbus_object_class = NM_DBUS_OBJECT_CLASS (klass); + NMExportedObjectClass *exported_object_class = NM_EXPORTED_OBJECT_CLASS (klass); object_class->dispose = dispose; object_class->finalize = finalize; object_class->get_property = get_property; - dbus_object_class->export_path = NM_DBUS_EXPORT_PATH_STATIC (NM_DBUS_PATH "/DnsManager"); - dbus_object_class->interface_infos = NM_DBUS_INTERFACE_INFOS (&interface_info_dns_manager); - dbus_object_class->export_on_construction = TRUE; + exported_object_class->export_path = NM_DBUS_PATH "/DnsManager"; + exported_object_class->export_on_construction = TRUE; obj_properties[PROP_MODE] = g_param_spec_string (NM_DNS_MANAGER_MODE, "", "", @@ -2148,4 +2024,9 @@ nm_dns_manager_class_init (NMDnsManagerClass *klass) 0, NULL, NULL, g_cclosure_marshal_VOID__VOID, G_TYPE_NONE, 0); + + nm_exported_object_class_add_interface (NM_EXPORTED_OBJECT_CLASS (klass), + NMDBUS_TYPE_DNS_MANAGER_SKELETON, + NULL); } + diff --git a/src/dns/nm-dns-manager.h b/src/dns/nm-dns-manager.h index 56889367..b38ea701 100644 --- a/src/dns/nm-dns-manager.h +++ b/src/dns/nm-dns-manager.h @@ -26,14 +26,11 @@ #include "nm-ip4-config.h" #include "nm-ip6-config.h" -#include "nm-setting-connection.h" typedef enum { - NM_DNS_IP_CONFIG_TYPE_REMOVED = -1, - NM_DNS_IP_CONFIG_TYPE_DEFAULT = 0, NM_DNS_IP_CONFIG_TYPE_BEST_DEVICE, - NM_DNS_IP_CONFIG_TYPE_VPN, + NM_DNS_IP_CONFIG_TYPE_VPN } NMDnsIPConfigType; enum { @@ -41,23 +38,12 @@ enum { NM_DNS_PRIORITY_DEFAULT_VPN = 50, }; -struct _NMDnsConfigData; -struct _NMDnsManager; - typedef struct { - struct _NMDnsConfigData *data; - NMIPConfig *ip_config; - CList data_lst; - CList ip_config_lst; - NMDnsIPConfigType ip_config_type; + gpointer config; + NMDnsIPConfigType type; + char *iface; } NMDnsIPConfigData; -typedef struct _NMDnsConfigData { - struct _NMDnsManager *self; - CList data_lst_head; - int ifindex; -} NMDnsConfigData; - #define NM_TYPE_DNS_MANAGER (nm_dns_manager_get_type ()) #define NM_DNS_MANAGER(o) (G_TYPE_CHECK_INSTANCE_CAST ((o), NM_TYPE_DNS_MANAGER, NMDnsManager)) #define NM_DNS_MANAGER_CLASS(k) (G_TYPE_CHECK_CLASS_CAST((k), NM_TYPE_DNS_MANAGER, NMDnsManagerClass)) @@ -84,9 +70,12 @@ NMDnsManager * nm_dns_manager_get (void); void nm_dns_manager_begin_updates (NMDnsManager *self, const char *func); void nm_dns_manager_end_updates (NMDnsManager *self, const char *func); -gboolean nm_dns_manager_set_ip_config (NMDnsManager *self, - NMIPConfig *ip_config, - NMDnsIPConfigType ip_config_type); +gboolean nm_dns_manager_add_ip_config (NMDnsManager *self, + const char *iface, + gpointer config, + NMDnsIPConfigType cfg_type); + +gboolean nm_dns_manager_remove_ip_config (NMDnsManager *self, gpointer config); void nm_dns_manager_set_initial_hostname (NMDnsManager *self, const char *hostname); @@ -123,6 +112,8 @@ typedef enum { NM_DNS_MANAGER_RESOLV_CONF_MAN_NETCONFIG, } NMDnsManagerResolvConfManager; +gboolean nm_dns_manager_get_resolv_conf_explicit (NMDnsManager *self); + void nm_dns_manager_stop (NMDnsManager *self); #endif /* __NETWORKMANAGER_DNS_MANAGER_H__ */ diff --git a/src/dns/nm-dns-plugin.c b/src/dns/nm-dns-plugin.c index d9400e3e..5805b7d8 100644 --- a/src/dns/nm-dns-plugin.c +++ b/src/dns/nm-dns-plugin.c @@ -77,15 +77,15 @@ G_DEFINE_TYPE_EXTENDED (NMDnsPlugin, nm_dns_plugin, G_TYPE_OBJECT, G_TYPE_FLAG_A gboolean nm_dns_plugin_update (NMDnsPlugin *self, + const GPtrArray *configs, const NMGlobalDnsConfig *global_config, - const CList *ip_config_lst_head, const char *hostname) { g_return_val_if_fail (NM_DNS_PLUGIN_GET_CLASS (self)->update != NULL, FALSE); return NM_DNS_PLUGIN_GET_CLASS (self)->update (self, + configs, global_config, - ip_config_lst_head, hostname); } diff --git a/src/dns/nm-dns-plugin.h b/src/dns/nm-dns-plugin.h index 80b77d95..996695c0 100644 --- a/src/dns/nm-dns-plugin.h +++ b/src/dns/nm-dns-plugin.h @@ -50,8 +50,8 @@ typedef struct { * configuration. */ gboolean (*update) (NMDnsPlugin *self, + const GPtrArray *configs, const NMGlobalDnsConfig *global_config, - const CList *ip_config_lst_head, const char *hostname); /* Subclasses should override and return TRUE if they start a local @@ -80,8 +80,8 @@ gboolean nm_dns_plugin_is_caching (NMDnsPlugin *self); const char *nm_dns_plugin_get_name (NMDnsPlugin *self); gboolean nm_dns_plugin_update (NMDnsPlugin *self, + const GPtrArray *configs, const NMGlobalDnsConfig *global_config, - const CList *ip_config_lst_head, const char *hostname); void nm_dns_plugin_stop (NMDnsPlugin *self); diff --git a/src/dns/nm-dns-systemd-resolved.c b/src/dns/nm-dns-systemd-resolved.c index 7da27e5f..6ab2ea18 100644 --- a/src/dns/nm-dns-systemd-resolved.c +++ b/src/dns/nm-dns-systemd-resolved.c @@ -31,15 +31,13 @@ #include <sys/stat.h> #include <linux/if.h> -#include "nm-utils/nm-c-list.h" #include "nm-core-internal.h" #include "platform/nm-platform.h" #include "nm-utils.h" #include "nm-ip4-config.h" #include "nm-ip6-config.h" -#include "nm-dbus-manager.h" +#include "nm-bus-manager.h" #include "nm-manager.h" -#include "nm-setting-connection.h" #include "devices/nm-device.h" #include "NetworkManagerUtils.h" @@ -50,23 +48,17 @@ typedef struct { int ifindex; - CList configs_lst_head; + GList *configs; } InterfaceConfig; -typedef struct { - CList request_queue_lst; - const char *operation; - GVariant *argument; -} RequestItem; - /*****************************************************************************/ typedef struct { GDBusProxy *resolve; GCancellable *init_cancellable; GCancellable *update_cancellable; - GCancellable *mdns_cancellable; - CList request_queue_lst_head; + GQueue dns_updates; + GQueue domain_updates; } NMDnsSystemdResolvedPrivate; struct _NMDnsSystemdResolved { @@ -90,36 +82,6 @@ G_DEFINE_TYPE (NMDnsSystemdResolved, nm_dns_systemd_resolved, NM_TYPE_DNS_PLUGIN /*****************************************************************************/ static void -_request_item_free (RequestItem *request_item) -{ - c_list_unlink_stale (&request_item->request_queue_lst); - g_variant_unref (request_item->argument); - g_slice_free (RequestItem, request_item); -} - -static void -_request_item_append (CList *request_queue_lst_head, - const char *operation, - GVariant *argument) -{ - RequestItem *request_item; - - request_item = g_slice_new (RequestItem); - request_item->operation = operation; - request_item->argument = g_variant_ref_sink (argument); - c_list_link_tail (request_queue_lst_head, &request_item->request_queue_lst); -} - -/*****************************************************************************/ - -static void -_interface_config_free (InterfaceConfig *config) -{ - nm_c_list_elem_free_all (&config->configs_lst_head, NULL); - g_slice_free (InterfaceConfig, config); -} - -static void call_done (GObject *source, GAsyncResult *r, gpointer user_data) { GVariant *v; @@ -127,58 +89,122 @@ call_done (GObject *source, GAsyncResult *r, gpointer user_data) NMDnsSystemdResolved *self = (NMDnsSystemdResolved *) user_data; v = g_dbus_proxy_call_finish (G_DBUS_PROXY (source), r, &error); - if (!v) { - if (g_error_matches (error, G_IO_ERROR, G_IO_ERROR_CANCELLED)) - return; + + if (g_error_matches (error, G_IO_ERROR, G_IO_ERROR_CANCELLED)) + return; + + if (error != NULL) { _LOGW ("Failed: %s\n", error->message); g_error_free (error); } } static void +add_interface_configuration (NMDnsSystemdResolved *self, + GArray *interfaces, + const NMDnsIPConfigData *data, + gboolean skip) +{ + int i; + InterfaceConfig *ic = NULL; + int ifindex; + + if (NM_IS_IP4_CONFIG (data->config)) + ifindex = nm_ip4_config_get_ifindex (data->config); + else if (NM_IS_IP6_CONFIG (data->config)) + ifindex = nm_ip6_config_get_ifindex (data->config); + else + g_return_if_reached (); + + for (i = 0; i < interfaces->len; i++) { + InterfaceConfig *tic = &g_array_index (interfaces, InterfaceConfig, i); + if (ifindex == tic->ifindex) { + ic = tic; + break; + } + } + + if (!ic) { + g_array_set_size (interfaces, interfaces->len + 1); + ic = &g_array_index (interfaces, InterfaceConfig, + interfaces->len - 1); + ic->ifindex = ifindex; + } + + if (!skip) + ic->configs = g_list_append (ic->configs, data->config); +} + +static void update_add_ip_config (NMDnsSystemdResolved *self, GVariantBuilder *dns, GVariantBuilder *domains, - NMIPConfig *config) + gpointer config) { int addr_family; gsize addr_size; guint i, n; - gboolean is_routing; - const char *domain; + gboolean route_only; + + if (NM_IS_IP4_CONFIG (config)) + addr_family = AF_INET; + else if (NM_IS_IP6_CONFIG (config)) + addr_family = AF_INET6; + else + g_return_if_reached (); - addr_family = nm_ip_config_get_addr_family (config); addr_size = nm_utils_addr_family_to_size (addr_family); - n = nm_ip_config_get_num_nameservers (config); + n = addr_family == AF_INET + ? nm_ip4_config_get_num_nameservers (config) + : nm_ip6_config_get_num_nameservers (config); for (i = 0 ; i < n; i++) { + in_addr_t ns4; + gconstpointer ns; + + if (addr_family == AF_INET) { + ns4 = nm_ip4_config_get_nameserver (config, i); + ns = &ns4; + } else + ns = nm_ip6_config_get_nameserver (config, i); + g_variant_builder_open (dns, G_VARIANT_TYPE ("(iay)")); g_variant_builder_add (dns, "i", addr_family); g_variant_builder_add_value (dns, g_variant_new_fixed_array (G_VARIANT_TYPE_BYTE, - nm_ip_config_get_nameserver (config, i), + ns, addr_size, 1)); g_variant_builder_close (dns); } - n = nm_ip_config_get_num_searches (config); + /* If this link is never the default (e.g. only used for resources on this + * network) add a routing domain. */ + route_only = addr_family == AF_INET + ? !nm_ip4_config_best_default_route_get (config) + : !nm_ip6_config_best_default_route_get (config); + + n = addr_family == AF_INET + ? nm_ip4_config_get_num_searches (config) + : nm_ip6_config_get_num_searches (config); if (n > 0) { for (i = 0; i < n; i++) { - domain = nm_utils_parse_dns_domain (nm_ip_config_get_search (config, i), - &is_routing); g_variant_builder_add (domains, "(sb)", - domain, - is_routing); + addr_family == AF_INET + ? nm_ip4_config_get_search (config, i) + : nm_ip6_config_get_search (config, i), + route_only); } } else { - n = nm_ip_config_get_num_domains (config); + n = addr_family == AF_INET + ? nm_ip4_config_get_num_domains (config) + : nm_ip6_config_get_num_domains (config); for (i = 0; i < n; i++) { - domain = nm_utils_parse_dns_domain (nm_ip_config_get_domain (config, i), - &is_routing); g_variant_builder_add (domains, "(sb)", - domain, - is_routing); + addr_family == AF_INET + ? nm_ip4_config_get_domain (config, i) + : nm_ip6_config_get_domain (config, i), + route_only); } } } @@ -187,13 +213,13 @@ static void free_pending_updates (NMDnsSystemdResolved *self) { NMDnsSystemdResolvedPrivate *priv = NM_DNS_SYSTEMD_RESOLVED_GET_PRIVATE (self); - RequestItem *request_item, *request_item_safe; + GVariant *v; - c_list_for_each_entry_safe (request_item, - request_item_safe, - &priv->request_queue_lst_head, - request_queue_lst) - _request_item_free (request_item); + while ((v = g_queue_pop_head (&priv->dns_updates)) != NULL) + g_variant_unref (v); + + while ((v = g_queue_pop_head (&priv->domain_updates)) != NULL) + g_variant_unref (v); } static void @@ -201,9 +227,7 @@ prepare_one_interface (NMDnsSystemdResolved *self, InterfaceConfig *ic) { NMDnsSystemdResolvedPrivate *priv = NM_DNS_SYSTEMD_RESOLVED_GET_PRIVATE (self); GVariantBuilder dns, domains; - NMCListElem *elem; - NMSettingConnectionMdns mdns = NM_SETTING_CONNECTION_MDNS_DEFAULT; - const char *mdns_arg = NULL; + GList *l; g_variant_builder_init (&dns, G_VARIANT_TYPE ("(ia(iay))")); g_variant_builder_add (&dns, "i", ic->ifindex); @@ -213,50 +237,23 @@ prepare_one_interface (NMDnsSystemdResolved *self, InterfaceConfig *ic) g_variant_builder_add (&domains, "i", ic->ifindex); g_variant_builder_open (&domains, G_VARIANT_TYPE ("a(sb)")); - c_list_for_each_entry (elem, &ic->configs_lst_head, lst) { - NMIPConfig *ip_config = elem->data; - - update_add_ip_config (self, &dns, &domains, ip_config); - - if (NM_IS_IP4_CONFIG (ip_config)) - mdns = NM_MAX (mdns, nm_ip4_config_mdns_get (NM_IP4_CONFIG (ip_config))); - } + for (l = ic->configs; l; l = l->next) + update_add_ip_config (self, &dns, &domains, l->data); g_variant_builder_close (&dns); g_variant_builder_close (&domains); - switch (mdns) { - case NM_SETTING_CONNECTION_MDNS_NO: - mdns_arg = "no"; - break; - case NM_SETTING_CONNECTION_MDNS_RESOLVE: - mdns_arg = "resolve"; - break; - case NM_SETTING_CONNECTION_MDNS_YES: - mdns_arg = "yes"; - break; - case NM_SETTING_CONNECTION_MDNS_DEFAULT: - mdns_arg = ""; - break; - } - nm_assert (mdns_arg); - - _request_item_append (&priv->request_queue_lst_head, - "SetLinkDNS", - g_variant_builder_end (&dns)); - _request_item_append (&priv->request_queue_lst_head, - "SetLinkDomains", - g_variant_builder_end (&domains)); - _request_item_append (&priv->request_queue_lst_head, - "SetLinkMulticastDNS", - g_variant_new ("(is)", ic->ifindex, mdns_arg ?: "")); + g_queue_push_tail (&priv->dns_updates, + g_variant_ref_sink (g_variant_builder_end (&dns))); + g_queue_push_tail (&priv->domain_updates, + g_variant_ref_sink (g_variant_builder_end (&domains))); } static void send_updates (NMDnsSystemdResolved *self) { NMDnsSystemdResolvedPrivate *priv = NM_DNS_SYSTEMD_RESOLVED_GET_PRIVATE (self); - RequestItem *request_item, *request_item_safe; + GVariant *v; nm_clear_g_cancellable (&priv->update_cancellable); @@ -265,81 +262,55 @@ send_updates (NMDnsSystemdResolved *self) priv->update_cancellable = g_cancellable_new (); - c_list_for_each_entry_safe (request_item, - request_item_safe, - &priv->request_queue_lst_head, - request_queue_lst) { - g_dbus_proxy_call (priv->resolve, - request_item->operation, - request_item->argument, + while ((v = g_queue_pop_head (&priv->dns_updates)) != NULL) { + g_dbus_proxy_call (priv->resolve, "SetLinkDNS", v, G_DBUS_CALL_FLAGS_NONE, - -1, - priv->update_cancellable, - call_done, - self); - _request_item_free (request_item); + -1, priv->update_cancellable, call_done, self); + g_variant_unref (v); + } + + while ((v = g_queue_pop_head (&priv->domain_updates)) != NULL) { + g_dbus_proxy_call (priv->resolve, "SetLinkDomains", v, + G_DBUS_CALL_FLAGS_NONE, + -1, priv->update_cancellable, call_done, self); + g_variant_unref (v); } } static gboolean update (NMDnsPlugin *plugin, + const GPtrArray *configs, const NMGlobalDnsConfig *global_config, - const CList *ip_config_lst_head, const char *hostname) { NMDnsSystemdResolved *self = NM_DNS_SYSTEMD_RESOLVED (plugin); - gs_unref_hashtable GHashTable *interfaces = NULL; - gs_free gpointer *interfaces_keys = NULL; - guint interfaces_len; + GArray *interfaces = g_array_new (TRUE, TRUE, sizeof (InterfaceConfig)); guint i; int prio, first_prio = 0; - NMDnsIPConfigData *ip_data; - gboolean is_first = TRUE; - - interfaces = g_hash_table_new_full (nm_direct_hash, NULL, - NULL, (GDestroyNotify) _interface_config_free); - c_list_for_each_entry (ip_data, ip_config_lst_head, ip_config_lst) { + for (i = 0; i < configs->len; i++) { + const NMDnsIPConfigData *data = configs->pdata[i]; gboolean skip = FALSE; - InterfaceConfig *ic = NULL; - int ifindex; - prio = nm_ip_config_get_dns_priority (ip_data->ip_config); - if (is_first) { - is_first = FALSE; + prio = nm_ip_config_get_dns_priority (data->config); + if (i == 0) first_prio = prio; - } else if (first_prio < 0 && first_prio != prio) + else if (first_prio < 0 && first_prio != prio) skip = TRUE; - - ifindex = ip_data->data->ifindex; - nm_assert (ifindex == nm_ip_config_get_ifindex (ip_data->ip_config)); - - ic = g_hash_table_lookup (interfaces, GINT_TO_POINTER (ifindex)); - if (!ic) { - ic = g_slice_new (InterfaceConfig); - ic->ifindex = ifindex; - c_list_init (&ic->configs_lst_head); - g_hash_table_insert (interfaces, GINT_TO_POINTER (ifindex), ic); - } - - if (!skip) { - c_list_link_tail (&ic->configs_lst_head, - &nm_c_list_elem_new_stale (ip_data->ip_config)->lst); - } + add_interface_configuration (self, interfaces, data, skip); } free_pending_updates (self); - interfaces_keys = nm_utils_hash_keys_to_array (interfaces, - nm_cmp_int2ptr_p_with_data, - NULL, - &interfaces_len); - for (i = 0; i < interfaces_len; i++) { - InterfaceConfig *ic = g_hash_table_lookup (interfaces, GINT_TO_POINTER (interfaces_keys[i])); + for (i = 0; i < interfaces->len; i++) { + InterfaceConfig *ic = &g_array_index (interfaces, InterfaceConfig, i); prepare_one_interface (self, ic); + g_list_free (ic->configs); } + g_array_free (interfaces, TRUE); + send_updates (self); return TRUE; @@ -392,15 +363,16 @@ static void nm_dns_systemd_resolved_init (NMDnsSystemdResolved *self) { NMDnsSystemdResolvedPrivate *priv = NM_DNS_SYSTEMD_RESOLVED_GET_PRIVATE (self); - NMDBusManager *dbus_mgr; + NMBusManager *dbus_mgr; GDBusConnection *connection; - c_list_init (&priv->request_queue_lst_head); + g_queue_init (&priv->dns_updates); + g_queue_init (&priv->domain_updates); - dbus_mgr = nm_dbus_manager_get (); + dbus_mgr = nm_bus_manager_get (); g_return_if_fail (dbus_mgr); - connection = nm_dbus_manager_get_connection (dbus_mgr); + connection = nm_bus_manager_get_connection (dbus_mgr); g_return_if_fail (connection); priv->init_cancellable = g_cancellable_new (); @@ -432,7 +404,6 @@ dispose (GObject *object) g_clear_object (&priv->resolve); nm_clear_g_cancellable (&priv->init_cancellable); nm_clear_g_cancellable (&priv->update_cancellable); - nm_clear_g_cancellable (&priv->mdns_cancellable); G_OBJECT_CLASS (nm_dns_systemd_resolved_parent_class)->dispose (object); } diff --git a/src/dns/nm-dns-unbound.c b/src/dns/nm-dns-unbound.c index e06128aa..0b80055f 100644 --- a/src/dns/nm-dns-unbound.c +++ b/src/dns/nm-dns-unbound.c @@ -39,8 +39,8 @@ G_DEFINE_TYPE (NMDnsUnbound, nm_dns_unbound, NM_TYPE_DNS_PLUGIN) static gboolean update (NMDnsPlugin *plugin, + const GPtrArray *configs, const NMGlobalDnsConfig *global_config, - const CList *ip_config_lst_head, const char *hostname) { char *argv[] = { DNSSEC_TRIGGER_SCRIPT, "--async", "--update", NULL }; diff --git a/src/dnsmasq/nm-dnsmasq-manager.c b/src/dnsmasq/nm-dnsmasq-manager.c index 041e75ea..323ef781 100644 --- a/src/dnsmasq/nm-dnsmasq-manager.c +++ b/src/dnsmasq/nm-dnsmasq-manager.c @@ -181,7 +181,7 @@ create_dm_cmd_line (const char *iface, nm_cmd_line_add_string (cmd, "--log-queries"); } - /* dnsmasq may read from its default config file location, which if that + /* dnsmasq may read from it's default config file location, which if that * location is a valid config file, it will combine with the options here * and cause undesirable side-effects. Like sending bogus IP addresses * as the gateway or whatever. So tell dnsmasq not to use any config file diff --git a/src/dnsmasq/tests/meson.build b/src/dnsmasq/tests/meson.build deleted file mode 100644 index 40f42f6f..00000000 --- a/src/dnsmasq/tests/meson.build +++ /dev/null @@ -1,14 +0,0 @@ -test_unit = 'test-dnsmasq-utils' - -exe = executable( - test_unit, - test_unit + '.c', - dependencies: test_nm_dep, - c_args: '-DTESTDIR="@0@"'.format(meson.source_root()) -) - -test( - 'dnsmasq/' + test_unit, - test_script, - args: test_args + [exe.full_path()] -) diff --git a/src/main.c b/src/main.c index bd8e26a5..d59da052 100644 --- a/src/main.c +++ b/src/main.c @@ -39,7 +39,7 @@ #include "NetworkManagerUtils.h" #include "nm-manager.h" #include "platform/nm-linux-platform.h" -#include "nm-dbus-manager.h" +#include "nm-bus-manager.h" #include "devices/nm-device.h" #include "dhcp/nm-dhcp-manager.h" #include "nm-config.h" @@ -48,7 +48,7 @@ #include "settings/nm-settings.h" #include "nm-auth-manager.h" #include "nm-core-internal.h" -#include "nm-dbus-object.h" +#include "nm-exported-object.h" #include "nm-connectivity.h" #include "dns/nm-dns-manager.h" #include "systemd/nm-sd.h" @@ -93,10 +93,8 @@ static void _init_nm_debug (NMConfig *config) { gs_free char *debug = NULL; - enum { - D_RLIMIT_CORE = (1 << 0), - D_FATAL_WARNINGS = (1 << 1), - }; + const guint D_RLIMIT_CORE = 1; + const guint D_FATAL_WARNINGS = 2; GDebugKey keys[] = { { "RLIMIT_CORE", D_RLIMIT_CORE }, { "fatal-warnings", D_FATAL_WARNINGS }, @@ -225,7 +223,6 @@ int main (int argc, char *argv[]) { gboolean success = FALSE; - NMManager *manager; NMConfig *config; GError *error = NULL; gboolean wrote_pidfile = FALSE; @@ -233,11 +230,13 @@ main (int argc, char *argv[]) NMConfigCmdLineOptions *config_cli; guint sd_id = 0; + nm_g_type_init (); + /* Known to cause a possible deadlock upon GDBus initialization: * https://bugzilla.gnome.org/show_bug.cgi?id=674885 */ g_type_ensure (G_TYPE_SOCKET); g_type_ensure (G_TYPE_DBUS_CONNECTION); - g_type_ensure (NM_TYPE_DBUS_MANAGER); + g_type_ensure (NM_TYPE_BUS_MANAGER); _nm_utils_is_manager_process = TRUE; @@ -395,18 +394,27 @@ main (int argc, char *argv[]) NM_CONFIG_KEYFILE_KEY_MAIN_AUTH_POLKIT, NM_CONFIG_DEFAULT_MAIN_AUTH_POLKIT_BOOL)); - manager = nm_manager_setup (); + nm_manager_setup (); - if (!nm_dbus_manager_start (nm_dbus_manager_get (), - nm_manager_dbus_set_property_handle, - manager)) - goto done; + if (!nm_bus_manager_get_connection (nm_bus_manager_get ())) { + nm_log_warn (LOGD_CORE, "Failed to connect to D-Bus; only private bus is available"); + } else { + /* Start our DBus service */ + if (!nm_bus_manager_start_service (nm_bus_manager_get ())) { + nm_log_err (LOGD_CORE, "failed to start the dbus service."); + goto done; + } + } + +#if WITH_CONCHECK + NM_UTILS_KEEP_ALIVE (nm_manager_get (), nm_connectivity_get (), "NMManager-depends-on-NMConnectivity"); +#endif nm_dispatcher_init (); - g_signal_connect (manager, NM_MANAGER_CONFIGURE_QUIT, G_CALLBACK (manager_configure_quit), config); + g_signal_connect (nm_manager_get (), NM_MANAGER_CONFIGURE_QUIT, G_CALLBACK (manager_configure_quit), config); - if (!nm_manager_start (manager, &error)) { + if (!nm_manager_start (nm_manager_get (), &error)) { nm_log_err (LOGD_CORE, "failed to initialize: %s", error->message); goto done; } @@ -440,14 +448,11 @@ done: * state here. We don't bother updating the state as devices * change during regular operation. If NM is killed with SIGKILL, * it misses to update the state. */ - nm_manager_write_device_state (manager); + nm_manager_write_device_state (nm_manager_get ()); - /* FIXME: we don't properly shut down on exit. That is a bug. - * NMDBusObject have an assertion that they get unexported before disposing. - * We need this workaround and disable the assertion during our leaky shutdown. */ - nm_dbus_object_set_quitting (); + nm_exported_object_class_set_quitting (); - nm_manager_stop (manager); + nm_manager_stop (nm_manager_get ()); nm_config_state_set (config, TRUE, TRUE); diff --git a/src/meson.build b/src/meson.build deleted file mode 100644 index 591c9c79..00000000 --- a/src/meson.build +++ /dev/null @@ -1,319 +0,0 @@ -src_inc = include_directories('.') - -install_data( - 'org.freedesktop.NetworkManager.conf', - install_dir: dbus_conf_dir -) - -subdir('systemd') - -core_plugins = [] - -nm_cflags = ['-DNETWORKMANAGER_COMPILATION=NM_NETWORKMANAGER_COMPILATION_DAEMON'] - -nm_dep = declare_dependency( - include_directories: src_inc, - dependencies: nm_core_dep, - compile_args: nm_cflags -) - -cflags = nm_cflags + [ - '-DPREFIX="@0@"'.format(nm_prefix), - '-DBINDIR="@0@"'.format(nm_bindir), - '-DDATADIR="@0@"'.format(nm_datadir), - '-DLIBEXECDIR="@0@"'.format(nm_libexecdir), - '-DLOCALSTATEDIR="@0@"'.format(nm_localstatedir), - '-DRUNSTATEDIR="@0@"'.format(nm_runstatedir), - '-DSBINDIR="@0@"'.format(nm_sbindir), - '-DSYSCONFDIR="@0@"'.format(nm_sysconfdir), - '-DRUNDIR="@0@"'.format(nm_pkgrundir), - '-DNMCONFDIR="@0@"'.format(nm_pkgconfdir), - '-DNMLOCALEDIR="@0@"'.format(nm_localedir), - '-DNMPLUGINDIR="@0@"'.format(nm_pkglibdir), - '-DNMRUNDIR="@0@"'.format(nm_pkgrundir), - '-DNMSTATEDIR="@0@"'.format(nm_pkgstatedir), - '-DNMLIBDIR="@0@"'.format(nm_pkglibdir) -] - -if enable_dhcpcanon - cflags += '-DDHCPCANON_PATH="@0@"'.format(dhcpcanon.path()) -endif - -if enable_dhclient - cflags += '-DDHCLIENT_PATH="@0@"'.format(dhclient.path()) -endif - -if enable_dhcpcd - cflags += '-DDHCPCD_PATH="@0@"'.format(dhcpcd.path()) -endif - -sources = files( - 'dhcp/nm-dhcp-client.c', - 'dhcp/nm-dhcp-manager.c', - 'dhcp/nm-dhcp-systemd.c', - 'dhcp/nm-dhcp-utils.c', - 'ndisc/nm-lndp-ndisc.c', - 'ndisc/nm-ndisc.c', - 'platform/nm-netlink.c', - 'platform/wifi/wifi-utils-nl80211.c', - 'platform/wifi/wifi-utils.c', - 'platform/nm-linux-platform.c', - 'platform/nm-platform.c', - 'platform/nm-platform-utils.c', - 'platform/nmp-netns.c', - 'platform/nmp-object.c', - 'main-utils.c', - 'NetworkManagerUtils.c', - 'nm-core-utils.c', - 'nm-dbus-object.c', - 'nm-dbus-utils.c', - 'nm-ip4-config.c', - 'nm-ip6-config.c', - 'nm-logging.c' -) - -deps = [ - libsystemd_dep, - libudev_dep, - nm_core_dep -] - -if enable_wext - sources += files('platform/wifi/wifi-utils-wext.c') -endif - -libnetwork_manager_base = static_library( - nm_name + 'Base', - sources: sources, - dependencies: deps, - c_args: cflags, - link_with: libnm_core -) - -sources = files( - 'devices/nm-acd-manager.c', - 'devices/nm-device-bond.c', - 'devices/nm-device-bridge.c', - 'devices/nm-device.c', - 'devices/nm-device-dummy.c', - 'devices/nm-device-ethernet.c', - 'devices/nm-device-ethernet-utils.c', - 'devices/nm-device-factory.c', - 'devices/nm-device-generic.c', - 'devices/nm-device-infiniband.c', - 'devices/nm-device-ip-tunnel.c', - 'devices/nm-device-macsec.c', - 'devices/nm-device-macvlan.c', - 'devices/nm-device-ppp.c', - 'devices/nm-device-tun.c', - 'devices/nm-device-veth.c', - 'devices/nm-device-vlan.c', - 'devices/nm-device-vxlan.c', - 'devices/nm-lldp-listener.c', - 'dhcp/nm-dhcp-dhclient.c', - 'dhcp/nm-dhcp-dhclient-utils.c', - 'dhcp/nm-dhcp-dhcpcanon.c', - 'dhcp/nm-dhcp-dhcpcd.c', - 'dhcp/nm-dhcp-listener.c', - 'dns/nm-dns-dnsmasq.c', - 'dns/nm-dns-manager.c', - 'dns/nm-dns-plugin.c', - 'dns/nm-dns-systemd-resolved.c', - 'dns/nm-dns-unbound.c', - 'dnsmasq/nm-dnsmasq-manager.c', - 'dnsmasq/nm-dnsmasq-utils.c', - 'ppp/nm-ppp-manager-call.c', - 'settings/plugins/keyfile/nms-keyfile-connection.c', - 'settings/plugins/keyfile/nms-keyfile-plugin.c', - 'settings/plugins/keyfile/nms-keyfile-reader.c', - 'settings/plugins/keyfile/nms-keyfile-utils.c', - 'settings/plugins/keyfile/nms-keyfile-writer.c', - 'settings/nm-agent-manager.c', - 'settings/nm-secret-agent.c', - 'settings/nm-settings.c', - 'settings/nm-settings-connection.c', - 'settings/nm-settings-plugin.c', - 'supplicant/nm-supplicant-config.c', - 'supplicant/nm-supplicant-interface.c', - 'supplicant/nm-supplicant-manager.c', - 'supplicant/nm-supplicant-settings-verify.c', - 'vpn/nm-vpn-connection.c', - 'vpn/nm-vpn-manager.c', - 'nm-active-connection.c', - 'nm-act-request.c', - 'nm-audit-manager.c', - 'nm-auth-manager.c', - 'nm-auth-subject.c', - 'nm-auth-utils.c', - 'nm-dbus-manager.c', - 'nm-checkpoint.c', - 'nm-checkpoint-manager.c', - 'nm-config.c', - 'nm-config-data.c', - 'nm-connectivity.c', - 'nm-dcb.c', - 'nm-dhcp4-config.c', - 'nm-dhcp6-config.c', - 'nm-dispatcher.c', - 'nm-firewall-manager.c', - 'nm-hostname-manager.c', - 'nm-manager.c', - 'nm-netns.c', - 'nm-pacrunner-manager.c', - 'nm-policy.c', - 'nm-proxy-config.c', - 'nm-rfkill-manager.c', - 'nm-session-monitor.c', - 'nm-sleep-monitor.c' -) - -deps = [ - dl_dep, - libndp_dep, - # FIXME: Some files use introspection/dbus* headers, so - # this dependency might be needed - #libnmdbus_dep, - libudev_dep, - nm_core_dep, - shared_n_acd_dep -] - -if enable_concheck - deps += libcurl_dep -endif - -if enable_libaudit - deps += libaudit_dep -endif - -if enable_libpsl - deps += libpsl_dep -endif - -if enable_selinux - deps += selinux_dep -endif - -if enable_session_tracking - deps += logind_dep -endif - -libnetwork_manager = static_library( - nm_name, - sources: sources, - dependencies: deps, - c_args: cflags, - link_with: [libnetwork_manager_base, libsystemd_nm] -) - -ldflags = ['-rdynamic'] - -# FIXME: this doesn't work and it depends on libtool -''' -src/NetworkManager.ver: src/libNetworkManager.la $(core_plugins) - $(AM_V_GEN) NM="$(NM)" "$(srcdir)/tools/create-exports-NetworkManager.sh" --called-from-make "$(srcdir)" - -src_NetworkManager_LDFLAGS = \ - -rdynamic \ - -Wl,--version-script="src/NetworkManager.ver" - -nm = find_program('gcc-nm', 'nm') -create_exports_networkmanager = join_paths(meson.source_root(), 'tools', 'create-exports-NetworkManager.sh') - -symbol_map_name = 'NetworkManager.ver' - -linker_script = custom_target( - symbol_map_name, - input: meson.source_root(), - output: symbol_map_name, - capture: true, - #command: ['NM=' + nm.path(), create_exports_networkmanager, '--called-from-make', '@INPUT@'] - command: [create_exports_networkmanager, '--called-from-make', '@INPUT@'] -) - -ldflags += '-Wl,--version-script,@0@'.format(linker_script) -''' - -network_manager = executable( - nm_name, - 'main.c', - dependencies: deps, - c_args: cflags, - link_with: libnetwork_manager, - link_args: ldflags, - #FIXME - #link_depends: linker_script, - install: true, - install_dir: nm_sbindir -) - -deps = [ - dl_dep, - libndp_dep, - libudev_dep, - nm_core_dep -] - -name = 'nm-iface-helper' - -executable( - name, - name + '.c', - dependencies: deps, - c_args: cflags, - link_with: [libnetwork_manager_base, libsystemd_nm], - link_args: ldflags_linker_script_binary, - link_depends: linker_script_binary, - install: true, - install_dir: nm_libexecdir -) - -if enable_tests - sources = files( - 'ndisc/nm-fake-ndisc.c', - 'platform/tests/test-common.c', - 'platform/nm-fake-platform.c' - ) - - deps = [ - libudev_dep, - nm_core_dep - ] - - test_cflags = ['-DNETWORKMANAGER_COMPILATION_TEST'] - if require_root_tests - test_cflags += ['-DREQUIRE_ROOT_TESTS=1'] - endif - - platform = (host_machine.system().contains('linux') ? 'linux' : 'fake') - test_cflags_platform = '-DSETUP=nm_' + platform + '_platform_setup' - - libnetwork_manager_test = static_library( - nm_name + 'Test', - sources: sources, - dependencies: deps, - c_args: cflags + test_cflags, - link_with: libnetwork_manager - ) - - test_nm_dep = declare_dependency( - dependencies: nm_dep, - compile_args: test_cflags, - link_with: libnetwork_manager_test - ) - - subdir('dnsmasq/tests') - subdir('ndisc/tests') - subdir('platform/tests') - subdir('supplicant/tests') - subdir('tests') -endif - -subdir('dhcp') - -if enable_ppp - subdir('ppp') -endif - -subdir('devices') -subdir('settings/plugins') diff --git a/src/ndisc/nm-lndp-ndisc.c b/src/ndisc/nm-lndp-ndisc.c index c0a0cd40..70200ed3 100644 --- a/src/ndisc/nm-lndp-ndisc.c +++ b/src/ndisc/nm-lndp-ndisc.c @@ -173,10 +173,10 @@ receive_ra (struct ndp *ndp, struct ndp_msg *msg, gpointer user_data) */ { const NMNDiscGateway gateway = { - .address = gateway_addr, - .timestamp = now, - .lifetime = ndp_msgra_router_lifetime (msgra), - .preference = _route_preference_coerce (ndp_msgra_route_preference (msgra)), + .address = gateway_addr, + .timestamp = now, + .lifetime = ndp_msgra_router_lifetime (msgra), + .preference = _route_preference_coerce (ndp_msgra_route_preference (msgra)), }; if (nm_ndisc_add_gateway (ndisc, &gateway)) @@ -195,16 +195,12 @@ receive_ra (struct ndp *ndp, struct ndp_msg *msg, gpointer user_data) continue; nm_utils_ip6_address_clear_host_address (&r_network, ndp_msg_opt_prefix (msg, offset), r_plen); - if ( IN6_IS_ADDR_UNSPECIFIED (&r_network) - || IN6_IS_ADDR_LINKLOCAL (&r_network)) - continue; - if (ndp_msg_opt_prefix_flag_on_link (msg, offset)) { - const NMNDiscRoute route = { - .network = r_network, - .plen = r_plen, - .timestamp = now, - .lifetime = ndp_msg_opt_prefix_valid_time (msg, offset), + NMNDiscRoute route = { + .network = r_network, + .plen = r_plen, + .timestamp = now, + .lifetime = ndp_msg_opt_prefix_valid_time (msg, offset), }; if (nm_ndisc_add_route (ndisc, &route)) @@ -215,10 +211,10 @@ receive_ra (struct ndp *ndp, struct ndp_msg *msg, gpointer user_data) if ( r_plen == 64 && ndp_msg_opt_prefix_flag_auto_addr_conf (msg, offset)) { NMNDiscAddress address = { - .address = r_network, - .timestamp = now, - .lifetime = ndp_msg_opt_prefix_valid_time (msg, offset), - .preferred = ndp_msg_opt_prefix_preferred_time (msg, offset), + .address = r_network, + .timestamp = now, + .lifetime = ndp_msg_opt_prefix_valid_time (msg, offset), + .preferred = ndp_msg_opt_prefix_preferred_time (msg, offset), }; if (address.preferred > address.lifetime) @@ -229,11 +225,11 @@ receive_ra (struct ndp *ndp, struct ndp_msg *msg, gpointer user_data) } ndp_msg_opt_for_each_offset(offset, msg, NDP_MSG_OPT_ROUTE) { NMNDiscRoute route = { - .gateway = gateway_addr, - .plen = ndp_msg_opt_route_prefix_len (msg, offset), - .timestamp = now, - .lifetime = ndp_msg_opt_route_lifetime (msg, offset), - .preference = _route_preference_coerce (ndp_msg_opt_route_preference (msg, offset)), + .gateway = gateway_addr, + .plen = ndp_msg_opt_route_prefix_len (msg, offset), + .timestamp = now, + .lifetime = ndp_msg_opt_route_lifetime (msg, offset), + .preference = _route_preference_coerce (ndp_msg_opt_route_preference (msg, offset)), }; if (route.plen == 0 || route.plen > 128) @@ -252,9 +248,9 @@ receive_ra (struct ndp *ndp, struct ndp_msg *msg, gpointer user_data) ndp_msg_opt_rdnss_for_each_addr (addr, addr_index, msg, offset) { NMNDiscDNSServer dns_server = { - .address = *addr, - .timestamp = now, - .lifetime = ndp_msg_opt_rdnss_lifetime (msg, offset), + .address = *addr, + .timestamp = now, + .lifetime = ndp_msg_opt_rdnss_lifetime (msg, offset), }; /* Pad the lifetime somewhat to give a bit of slack in cases @@ -274,9 +270,9 @@ receive_ra (struct ndp *ndp, struct ndp_msg *msg, gpointer user_data) ndp_msg_opt_dnssl_for_each_domain (domain, domain_index, msg, offset) { NMNDiscDNSDomain dns_domain = { - .domain = domain, - .timestamp = now, - .lifetime = ndp_msg_opt_rdnss_lifetime (msg, offset), + .domain = domain, + .timestamp = now, + .lifetime = ndp_msg_opt_rdnss_lifetime (msg, offset), }; /* Pad the lifetime somewhat to give a bit of slack in cases diff --git a/src/ndisc/nm-ndisc.c b/src/ndisc/nm-ndisc.c index ba61cb11..6b44a96c 100644 --- a/src/ndisc/nm-ndisc.c +++ b/src/ndisc/nm-ndisc.c @@ -89,7 +89,7 @@ NM_GOBJECT_PROPERTIES_DEFINE_BASE ( ); enum { - CONFIG_RECEIVED, + CONFIG_CHANGED, RA_TIMEOUT, LAST_SIGNAL }; @@ -235,7 +235,7 @@ static void _emit_config_change (NMNDisc *self, NMNDiscConfigMap changed) { _config_changed_log (self, changed); - g_signal_emit (self, signals[CONFIG_RECEIVED], 0, + g_signal_emit (self, signals[CONFIG_CHANGED], 0, _data_complete (&NM_NDISC_GET_PRIVATE (self)->rdata), (guint) changed); } @@ -349,11 +349,6 @@ nm_ndisc_add_address (NMNDisc *ndisc, const NMNDiscAddress *new) NMNDiscDataInternal *rdata = &priv->rdata; guint i; - nm_assert (new); - nm_assert (new->timestamp > 0 && new->timestamp < G_MAXINT32); - nm_assert (!IN6_IS_ADDR_UNSPECIFIED (&new->address)); - nm_assert (!IN6_IS_ADDR_LINKLOCAL (&new->address)); - for (i = 0; i < rdata->addresses->len; i++) { NMNDiscAddress *item = &g_array_index (rdata->addresses, NMNDiscAddress, i); @@ -797,7 +792,7 @@ nm_ndisc_start (NMNDisc *ndisc) } void -nm_ndisc_dad_failed (NMNDisc *ndisc, const struct in6_addr *address) +nm_ndisc_dad_failed (NMNDisc *ndisc, struct in6_addr *address) { NMNDiscDataInternal *rdata; guint i; @@ -892,23 +887,6 @@ get_expiry_time (guint32 timestamp, guint32 lifetime) : (_item->lifetime) / 2); \ }) -static const char * -_get_exp (char *buf, gsize buf_size, gint64 now_ns, gint32 expiry_time) -{ - int l; - - if (expiry_time == G_MAXINT32) - return "permanent"; - l = g_snprintf (buf, buf_size, - "%.4f", - ((double) ((expiry_time * NM_UTILS_NS_PER_SECOND) - now_ns)) / ((double) NM_UTILS_NS_PER_SECOND)); - nm_assert (l < buf_size); - return buf; -} - -#define get_exp(buf, now_ns, item) \ - _get_exp ((buf), G_N_ELEMENTS (buf), (now_ns), (get_expiry (item))) - static void _config_changed_log (NMNDisc *ndisc, NMNDiscConfigMap changed) { @@ -918,14 +896,10 @@ _config_changed_log (NMNDisc *ndisc, NMNDiscConfigMap changed) char changedstr[CONFIG_MAP_MAX_STR]; char addrstr[INET6_ADDRSTRLEN]; char str_pref[35]; - char str_exp[100]; - gint64 now_ns; if (!_LOGD_ENABLED ()) return; - now_ns = nm_utils_get_monotonic_timestamp_ns (); - priv = NM_NDISC_GET_PRIVATE (ndisc); rdata = &priv->rdata; @@ -936,38 +910,35 @@ _config_changed_log (NMNDisc *ndisc, NMNDiscConfigMap changed) NMNDiscGateway *gateway = &g_array_index (rdata->gateways, NMNDiscGateway, i); inet_ntop (AF_INET6, &gateway->address, addrstr, sizeof (addrstr)); - _LOGD (" gateway %s pref %s exp %s", addrstr, + _LOGD (" gateway %s pref %s exp %d", addrstr, nm_icmpv6_router_pref_to_string (gateway->preference, str_pref, sizeof (str_pref)), - get_exp (str_exp, now_ns, gateway)); + get_expiry (gateway)); } for (i = 0; i < rdata->addresses->len; i++) { - const NMNDiscAddress *address = &g_array_index (rdata->addresses, NMNDiscAddress, i); + NMNDiscAddress *address = &g_array_index (rdata->addresses, NMNDiscAddress, i); inet_ntop (AF_INET6, &address->address, addrstr, sizeof (addrstr)); - _LOGD (" address %s exp %s", addrstr, - get_exp (str_exp, now_ns, address)); + _LOGD (" address %s exp %d", addrstr, get_expiry (address)); } for (i = 0; i < rdata->routes->len; i++) { NMNDiscRoute *route = &g_array_index (rdata->routes, NMNDiscRoute, i); inet_ntop (AF_INET6, &route->network, addrstr, sizeof (addrstr)); - _LOGD (" route %s/%u via %s pref %s exp %s", addrstr, (guint) route->plen, + _LOGD (" route %s/%u via %s pref %s exp %d", addrstr, (guint) route->plen, nm_utils_inet6_ntop (&route->gateway, NULL), nm_icmpv6_router_pref_to_string (route->preference, str_pref, sizeof (str_pref)), - get_exp (str_exp, now_ns, route)); + get_expiry (route)); } for (i = 0; i < rdata->dns_servers->len; i++) { NMNDiscDNSServer *dns_server = &g_array_index (rdata->dns_servers, NMNDiscDNSServer, i); inet_ntop (AF_INET6, &dns_server->address, addrstr, sizeof (addrstr)); - _LOGD (" dns_server %s exp %s", addrstr, - get_exp (str_exp, now_ns, dns_server)); + _LOGD (" dns_server %s exp %d", addrstr, get_expiry (dns_server)); } for (i = 0; i < rdata->dns_domains->len; i++) { NMNDiscDNSDomain *dns_domain = &g_array_index (rdata->dns_domains, NMNDiscDNSDomain, i); - _LOGD (" dns_domain %s exp %s", dns_domain->domain, - get_exp (str_exp, now_ns, dns_domain)); + _LOGD (" dns_domain %s exp %d", dns_domain->domain, get_expiry (dns_domain)); } } @@ -1008,7 +979,7 @@ clean_addresses (NMNDisc *ndisc, gint32 now, NMNDiscConfigMap *changed, gint32 * rdata = &NM_NDISC_GET_PRIVATE (ndisc)->rdata; for (i = 0; i < rdata->addresses->len; ) { - const NMNDiscAddress *item = &g_array_index (rdata->addresses, NMNDiscAddress, i); + NMNDiscAddress *item = &g_array_index (rdata->addresses, NMNDiscAddress, i); if (item->lifetime != NM_NDISC_INFINITY) { gint32 expiry = get_expiry (item); @@ -1383,7 +1354,7 @@ nm_ndisc_class_init (NMNDiscClass *klass) G_PARAM_STATIC_STRINGS); g_object_class_install_properties (object_class, _PROPERTY_ENUMS_LAST, obj_properties); - signals[CONFIG_RECEIVED] = + signals[CONFIG_CHANGED] = g_signal_new (NM_NDISC_CONFIG_RECEIVED, G_OBJECT_CLASS_TYPE (klass), G_SIGNAL_RUN_FIRST, diff --git a/src/ndisc/nm-ndisc.h b/src/ndisc/nm-ndisc.h index 9a8a27d7..b66c2289 100644 --- a/src/ndisc/nm-ndisc.h +++ b/src/ndisc/nm-ndisc.h @@ -27,9 +27,6 @@ #include "nm-setting-ip6-config.h" #include "NetworkManagerUtils.h" -#include "platform/nm-platform.h" -#include "platform/nmp-object.h" - #define NM_TYPE_NDISC (nm_ndisc_get_type ()) #define NM_NDISC(obj) (G_TYPE_CHECK_INSTANCE_CAST ((obj), NM_TYPE_NDISC, NMNDisc)) #define NM_NDISC_CLASS(klass) (G_TYPE_CHECK_CLASS_CAST ((klass), NM_TYPE_NDISC, NMNDiscClass)) @@ -177,7 +174,7 @@ NMNDiscNodeType nm_ndisc_get_node_type (NMNDisc *self); gboolean nm_ndisc_set_iid (NMNDisc *ndisc, const NMUtilsIPv6IfaceId iid); void nm_ndisc_start (NMNDisc *ndisc); -void nm_ndisc_dad_failed (NMNDisc *ndisc, const struct in6_addr *address); +void nm_ndisc_dad_failed (NMNDisc *ndisc, struct in6_addr *address); void nm_ndisc_set_config (NMNDisc *ndisc, const GArray *addresses, const GArray *dns_servers, @@ -187,32 +184,4 @@ NMPlatform *nm_ndisc_get_platform (NMNDisc *self); NMPNetns *nm_ndisc_netns_get (NMNDisc *self); gboolean nm_ndisc_netns_push (NMNDisc *self, NMPNetns **netns); -static inline gboolean -nm_ndisc_dad_addr_is_fail_candidate_event (NMPlatformSignalChangeType change_type, - const NMPlatformIP6Address *addr) -{ - return !NM_FLAGS_HAS (addr->n_ifa_flags, IFA_F_TEMPORARY) - && ( (change_type == NM_PLATFORM_SIGNAL_CHANGED && addr->n_ifa_flags & IFA_F_DADFAILED) - || (change_type == NM_PLATFORM_SIGNAL_REMOVED && addr->n_ifa_flags & IFA_F_TENTATIVE)); -} - -static inline gboolean -nm_ndisc_dad_addr_is_fail_candidate (NMPlatform *platform, - const NMPObject *obj) -{ - const NMPlatformIP6Address *addr; - - addr = NMP_OBJECT_CAST_IP6_ADDRESS (nm_platform_lookup_obj (platform, - NMP_CACHE_ID_TYPE_OBJECT_TYPE, - obj)); - if ( addr - && ( NM_FLAGS_HAS (addr->n_ifa_flags, IFA_F_TEMPORARY) - || !NM_FLAGS_HAS (addr->n_ifa_flags, IFA_F_DADFAILED))) { - /* the address still/again exists and is not in DADFAILED state. Skip it. */ - return FALSE; - } - - return TRUE; -} - #endif /* __NETWORKMANAGER_NDISC_H__ */ diff --git a/src/ndisc/tests/meson.build b/src/ndisc/tests/meson.build deleted file mode 100644 index 2f479c2d..00000000 --- a/src/ndisc/tests/meson.build +++ /dev/null @@ -1,23 +0,0 @@ -test_unit = 'test-ndisc-fake' - -exe = executable( - test_unit, - test_unit + '.c', - dependencies: test_nm_dep, - c_args: test_cflags_platform -) - -test( - 'ndisc/' + test_unit, - test_script, - args: test_args + [exe.full_path()] -) - -test = 'test-ndisc-linux' - -exe = executable( - test, - test + '.c', - dependencies: test_nm_dep, - c_args: test_cflags_platform -) diff --git a/src/nm-act-request.c b/src/nm-act-request.c index 0ac20b85..dd73947d 100644 --- a/src/nm-act-request.c +++ b/src/nm-act-request.c @@ -28,7 +28,7 @@ #include <sys/wait.h> #include <unistd.h> -#include "c-list/src/c-list.h" +#include "nm-utils/c-list.h" #include "nm-setting-wireless-security.h" #include "nm-setting-8021x.h" @@ -242,6 +242,8 @@ _do_cancel_secrets (NMActRequest *self, NMActRequestGetSecretsCallId *call_id, g void nm_act_request_cancel_secrets (NMActRequest *self, NMActRequestGetSecretsCallId *call_id) { + NMActRequestPrivate *priv; + g_return_if_fail (call_id); if (self) { @@ -253,6 +255,8 @@ nm_act_request_cancel_secrets (NMActRequest *self, NMActRequestGetSecretsCallId self = call_id->self; } + priv = NM_ACT_REQUEST_GET_PRIVATE (self); + if (!c_list_is_linked (&call_id->call_ids_lst)) g_return_if_reached (); @@ -514,7 +518,7 @@ get_property (GObject *object, guint prop_id, || !NM_IN_SET (nm_active_connection_get_state (active), NM_ACTIVE_CONNECTION_STATE_ACTIVATED, NM_ACTIVE_CONNECTION_STATE_DEACTIVATING)) { - g_value_set_string (value, NULL); + g_value_set_string (value, "/"); return; } diff --git a/src/nm-active-connection.c b/src/nm-active-connection.c index c6d6645d..c3f92464 100644 --- a/src/nm-active-connection.c +++ b/src/nm-active-connection.c @@ -28,15 +28,14 @@ #include "settings/nm-settings-connection.h" #include "nm-simple-connection.h" #include "nm-auth-utils.h" -#include "nm-auth-manager.h" #include "nm-auth-subject.h" #include "NetworkManagerUtils.h" #include "nm-core-internal.h" -#define AUTH_CALL_ID_SHARED_WIFI_PERMISSION_FAILED ((NMAuthManagerCallId *) GINT_TO_POINTER (1)) +#include "introspection/org.freedesktop.NetworkManager.Connection.Active.h" typedef struct _NMActiveConnectionPrivate { - NMDBusTrackObjPath settings_connection; + NMSettingsConnection *settings_connection; NMConnection *applied_connection; char *specific_object; NMDevice *device; @@ -62,15 +61,11 @@ typedef struct _NMActiveConnectionPrivate { NMActiveConnection *parent; - struct { - NMAuthManagerCallId *call_id_network_control; - NMAuthManagerCallId *call_id_wifi_shared_permission; - - NMActiveConnectionAuthResultFunc result_func; - gpointer user_data1; - gpointer user_data2; - } auth; - + NMAuthChain *chain; + const char *wifi_shared_permission; + NMActiveConnectionAuthResultFunc result_func; + gpointer user_data1; + gpointer user_data2; } NMActiveConnectionPrivate; NM_GOBJECT_PROPERTIES_DEFINE (NMActiveConnection, @@ -110,19 +105,17 @@ enum { }; static guint signals[LAST_SIGNAL] = { 0 }; -G_DEFINE_ABSTRACT_TYPE (NMActiveConnection, nm_active_connection, NM_TYPE_DBUS_OBJECT) +G_DEFINE_ABSTRACT_TYPE (NMActiveConnection, nm_active_connection, NM_TYPE_EXPORTED_OBJECT) #define NM_ACTIVE_CONNECTION_GET_PRIVATE(self) _NM_GET_PRIVATE_PTR(self, NMActiveConnection, NM_IS_ACTIVE_CONNECTION) /*****************************************************************************/ -static const NMDBusInterfaceInfoExtended interface_info_active_connection; -static const GDBusSignalInfo signal_info_state_changed; - static void check_master_ready (NMActiveConnection *self); static void _device_cleanup (NMActiveConnection *self); -static void _settings_connection_flags_changed (NMSettingsConnection *settings_connection, - NMActiveConnection *self); +static void _settings_connection_notify_flags (NMSettingsConnection *settings_connection, + GParamSpec *param, + NMActiveConnection *self); static void _set_activation_type_managed (NMActiveConnection *self); /*****************************************************************************/ @@ -190,24 +183,40 @@ _settings_connection_updated (NMSettingsConnection *connection, } static void +_settings_connection_removed (NMSettingsConnection *connection, + gpointer user_data) +{ + NMActiveConnection *self = user_data; + + /* Our settings connection is about to drop off. The next active connection + * cleanup is going to tear us down (at least until we grow the capability to + * re-link; in that case we'd just clean the references to the old connection here). + * Let's remove ourselves from the bus so that we're not exposed with a dangling + * reference to the setting connection once it's gone. */ + if (nm_exported_object_is_exported (NM_EXPORTED_OBJECT (self))) + nm_exported_object_unexport (NM_EXPORTED_OBJECT (self)); +} + +static void _set_settings_connection (NMActiveConnection *self, NMSettingsConnection *connection) { NMActiveConnectionPrivate *priv = NM_ACTIVE_CONNECTION_GET_PRIVATE (self); - if (priv->settings_connection.obj == connection) + if (priv->settings_connection == connection) return; - - if (priv->settings_connection.obj) { - g_signal_handlers_disconnect_by_func (priv->settings_connection.obj, _settings_connection_updated, self); - g_signal_handlers_disconnect_by_func (priv->settings_connection.obj, _settings_connection_flags_changed, self); + if (priv->settings_connection) { + g_signal_handlers_disconnect_by_func (priv->settings_connection, _settings_connection_updated, self); + g_signal_handlers_disconnect_by_func (priv->settings_connection, _settings_connection_removed, self); + g_signal_handlers_disconnect_by_func (priv->settings_connection, _settings_connection_notify_flags, self); + g_clear_object (&priv->settings_connection); } if (connection) { + priv->settings_connection = g_object_ref (connection); g_signal_connect (connection, NM_SETTINGS_CONNECTION_UPDATED_INTERNAL, (GCallback) _settings_connection_updated, self); + g_signal_connect (connection, NM_SETTINGS_CONNECTION_REMOVED, (GCallback) _settings_connection_removed, self); if (nm_active_connection_get_activation_type (self) == NM_ACTIVATION_TYPE_EXTERNAL) - g_signal_connect (connection, NM_SETTINGS_CONNECTION_FLAGS_CHANGED, (GCallback) _settings_connection_flags_changed, self); + g_signal_connect (connection, "notify::"NM_SETTINGS_CONNECTION_FLAGS, (GCallback) _settings_connection_notify_flags, self); } - - nm_dbus_track_obj_path_set (&priv->settings_connection, connection, TRUE); } NMActiveConnectionState @@ -216,18 +225,6 @@ nm_active_connection_get_state (NMActiveConnection *self) return NM_ACTIVE_CONNECTION_GET_PRIVATE (self)->state; } -static void -emit_state_changed (NMActiveConnection *self, guint state, guint reason) -{ - nm_dbus_object_emit_signal (NM_DBUS_OBJECT (self), - &interface_info_active_connection, - &signal_info_state_changed, - "(uu)", - (guint32) state, - (guint32) reason); - g_signal_emit (self, signals[STATE_CHANGED], 0, state, reason); -} - void nm_active_connection_set_state (NMActiveConnection *self, NMActiveConnectionState new_state, @@ -258,14 +255,14 @@ nm_active_connection_set_state (NMActiveConnection *self, old_state = priv->state; priv->state = new_state; priv->state_set = TRUE; - emit_state_changed (self, new_state, reason); + g_signal_emit (self, signals[STATE_CHANGED], 0, (guint) new_state, (guint) reason); _notify (self, PROP_STATE); check_master_ready (self); if ( new_state == NM_ACTIVE_CONNECTION_STATE_ACTIVATED || old_state == NM_ACTIVE_CONNECTION_STATE_ACTIVATED) { - nm_settings_connection_update_timestamp (priv->settings_connection.obj, + nm_settings_connection_update_timestamp (priv->settings_connection, (guint64) time (NULL), TRUE); } @@ -361,7 +358,7 @@ nm_active_connection_get_settings_connection_id (NMActiveConnection *self) g_return_val_if_fail (NM_IS_ACTIVE_CONNECTION (self), NULL); - con = NM_ACTIVE_CONNECTION_GET_PRIVATE (self)->settings_connection.obj; + con = NM_ACTIVE_CONNECTION_GET_PRIVATE (self)->settings_connection; return con ? nm_connection_get_id (NM_CONNECTION (con)) : NULL; @@ -372,7 +369,7 @@ _nm_active_connection_get_settings_connection (NMActiveConnection *self) { g_return_val_if_fail (NM_IS_ACTIVE_CONNECTION (self), NULL); - return NM_ACTIVE_CONNECTION_GET_PRIVATE (self)->settings_connection.obj; + return NM_ACTIVE_CONNECTION_GET_PRIVATE (self)->settings_connection; } NMSettingsConnection * @@ -426,7 +423,10 @@ _set_applied_connection_take (NMActiveConnection *self, if (nm_setting_connection_get_master (s_con)) flags_val |= NM_ACTIVATION_STATE_FLAG_IS_SLAVE; - if (+_nm_connection_type_is_master (nm_setting_connection_get_connection_type (s_con))) + if (NM_IN_STRSET (nm_setting_connection_get_connection_type (s_con), + NM_SETTING_BOND_SETTING_NAME, + NM_SETTING_BRIDGE_SETTING_NAME, + NM_SETTING_TEAM_SETTING_NAME)) flags_val |= NM_ACTIVATION_STATE_FLAG_IS_MASTER; nm_active_connection_set_state_flags_full (self, @@ -446,7 +446,7 @@ nm_active_connection_set_settings_connection (NMActiveConnection *self, priv = NM_ACTIVE_CONNECTION_GET_PRIVATE (self); g_return_if_fail (NM_IS_SETTINGS_CONNECTION (connection)); - g_return_if_fail (!priv->settings_connection.obj); + g_return_if_fail (!priv->settings_connection); g_return_if_fail (!priv->applied_connection); /* Can't change connection after the ActiveConnection is exported over D-Bus. @@ -456,12 +456,12 @@ nm_active_connection_set_settings_connection (NMActiveConnection *self, * never changes (once it's set). That has effects for NMVpnConnection and * NMActivationRequest. * For example, we'd have to cancel all pending seret requests. */ - g_return_if_fail (!nm_dbus_object_is_exported (NM_DBUS_OBJECT (self))); + g_return_if_fail (!nm_exported_object_is_exported (NM_EXPORTED_OBJECT (self))); _set_settings_connection (self, connection); _set_applied_connection_take (self, - nm_simple_connection_new_clone (NM_CONNECTION (priv->settings_connection.obj))); + nm_simple_connection_new_clone (NM_CONNECTION (priv->settings_connection))); } gboolean @@ -473,9 +473,9 @@ nm_active_connection_has_unmodified_applied_connection (NMActiveConnection *self priv = NM_ACTIVE_CONNECTION_GET_PRIVATE (self); - g_return_val_if_fail (priv->settings_connection.obj, FALSE); + g_return_val_if_fail (priv->settings_connection, FALSE); - return nm_settings_connection_has_unmodified_applied_connection (priv->settings_connection.obj, + return nm_settings_connection_has_unmodified_applied_connection (priv->settings_connection, priv->applied_connection, compare_flags); } @@ -491,10 +491,10 @@ nm_active_connection_clear_secrets (NMActiveConnection *self) priv = NM_ACTIVE_CONNECTION_GET_PRIVATE (self); - if (nm_settings_connection_has_unmodified_applied_connection (priv->settings_connection.obj, + if (nm_settings_connection_has_unmodified_applied_connection (priv->settings_connection, priv->applied_connection, NM_SETTING_COMPARE_FLAG_NONE)) - nm_connection_clear_secrets ((NMConnection *) priv->settings_connection.obj); + nm_connection_clear_secrets ((NMConnection *) priv->settings_connection); nm_connection_clear_secrets (priv->applied_connection); } @@ -515,9 +515,9 @@ nm_active_connection_set_specific_object (NMActiveConnection *self, /* Nothing that calls this function should be using paths from D-Bus, * where NM uses "/" to mean NULL. */ - nm_assert (!nm_streq0 (specific_object, "/")); + g_assert (g_strcmp0 (specific_object, "/") != 0); - if (nm_streq0 (priv->specific_object, specific_object)) + if (g_strcmp0 (priv->specific_object, specific_object) == 0) return; g_free (priv->specific_object); @@ -815,7 +815,7 @@ nm_active_connection_set_master (NMActiveConnection *self, NMActiveConnection *m /* Master is write-once, and must be set before exporting the object */ g_return_if_fail (priv->master == NULL); - g_return_if_fail (!nm_dbus_object_is_exported (NM_DBUS_OBJECT (self))); + g_return_if_fail (!nm_exported_object_is_exported (NM_EXPORTED_OBJECT (self))); if (priv->device) { /* Note, the master ActiveConnection may not yet have a device */ g_return_if_fail (priv->device != nm_active_connection_get_device (master)); @@ -854,11 +854,11 @@ _set_activation_type (NMActiveConnection *self, priv->activation_type = activation_type; - if (priv->settings_connection.obj) { + if (priv->settings_connection) { if (activation_type == NM_ACTIVATION_TYPE_EXTERNAL) - g_signal_connect (priv->settings_connection.obj, NM_SETTINGS_CONNECTION_FLAGS_CHANGED, (GCallback) _settings_connection_flags_changed, self); + g_signal_connect (priv->settings_connection, "notify::"NM_SETTINGS_CONNECTION_FLAGS, (GCallback) _settings_connection_notify_flags, self); else - g_signal_handlers_disconnect_by_func (priv->settings_connection.obj, _settings_connection_flags_changed, self); + g_signal_handlers_disconnect_by_func (priv->settings_connection, _settings_connection_notify_flags, self); } } @@ -895,18 +895,19 @@ nm_active_connection_get_activation_reason (NMActiveConnection *self) /*****************************************************************************/ static void -_settings_connection_flags_changed (NMSettingsConnection *settings_connection, - NMActiveConnection *self) +_settings_connection_notify_flags (NMSettingsConnection *settings_connection, + GParamSpec *param, + NMActiveConnection *self) { GError *error = NULL; nm_assert (NM_IS_ACTIVE_CONNECTION (self)); nm_assert (NM_IS_SETTINGS_CONNECTION (settings_connection)); nm_assert (nm_active_connection_get_activation_type (self) == NM_ACTIVATION_TYPE_EXTERNAL); - nm_assert (NM_ACTIVE_CONNECTION_GET_PRIVATE (self)->settings_connection.obj == settings_connection); + nm_assert (NM_ACTIVE_CONNECTION_GET_PRIVATE (self)->settings_connection == settings_connection); if (NM_FLAGS_HAS (nm_settings_connection_get_flags (settings_connection), - NM_SETTINGS_CONNECTION_INT_FLAGS_NM_GENERATED)) + NM_SETTINGS_CONNECTION_FLAGS_NM_GENERATED)) return; _set_activation_type_managed (self); @@ -986,93 +987,62 @@ nm_active_connection_set_parent (NMActiveConnection *self, NMActiveConnection *p /*****************************************************************************/ static void -auth_cancel (NMActiveConnection *self) -{ - NMActiveConnectionPrivate *priv = NM_ACTIVE_CONNECTION_GET_PRIVATE (self); - - if (priv->auth.call_id_network_control) - nm_auth_manager_check_authorization_cancel (priv->auth.call_id_network_control); - if (priv->auth.call_id_wifi_shared_permission) { - if (priv->auth.call_id_wifi_shared_permission == AUTH_CALL_ID_SHARED_WIFI_PERMISSION_FAILED) - priv->auth.call_id_wifi_shared_permission = NULL; - else - nm_auth_manager_check_authorization_cancel (priv->auth.call_id_wifi_shared_permission); - } - priv->auth.result_func = NULL; - priv->auth.user_data1 = NULL; - priv->auth.user_data2 = NULL; -} - -static void -auth_complete (NMActiveConnection *self, gboolean result, const char *message) -{ - _nm_unused gs_unref_object NMActiveConnection *self_keep_alive = g_object_ref (self); - NMActiveConnectionPrivate *priv = NM_ACTIVE_CONNECTION_GET_PRIVATE (self); - - priv->auth.result_func (self, - result, - message, - priv->auth.user_data1, - priv->auth.user_data2); - auth_cancel (self); -} - -static void -auth_done (NMAuthManager *auth_mgr, - NMAuthManagerCallId *auth_call_id, - gboolean is_authorized, - gboolean is_challenge, +auth_done (NMAuthChain *chain, GError *error, + GDBusMethodInvocation *unused, gpointer user_data) - { NMActiveConnection *self = NM_ACTIVE_CONNECTION (user_data); NMActiveConnectionPrivate *priv = NM_ACTIVE_CONNECTION_GET_PRIVATE (self); NMAuthCallResult result; - nm_assert (auth_call_id); - nm_assert (priv->auth.result_func); + g_assert (priv->chain == chain); + g_assert (priv->result_func != NULL); - if (g_error_matches (error, G_IO_ERROR, G_IO_ERROR_CANCELLED)) { - if (auth_call_id == priv->auth.call_id_network_control) - priv->auth.call_id_network_control = NULL; - else { - nm_assert (auth_call_id == priv->auth.call_id_wifi_shared_permission); - priv->auth.call_id_wifi_shared_permission = NULL; - } - return; + /* Must stay alive over the callback */ + g_object_ref (self); + + if (error) { + priv->result_func (self, FALSE, error->message, priv->user_data1, priv->user_data2); + goto done; } - result = nm_auth_call_result_eval (is_authorized, is_challenge, error); + /* Caller has had a chance to obtain authorization, so we only need to + * check for 'yes' here. + */ + result = nm_auth_chain_get_result (chain, NM_AUTH_PERMISSION_NETWORK_CONTROL); + if (result != NM_AUTH_CALL_RESULT_YES) { + priv->result_func (self, + FALSE, + "Not authorized to control networking.", + priv->user_data1, + priv->user_data2); + goto done; + } - if (auth_call_id == priv->auth.call_id_network_control) { - priv->auth.call_id_network_control = NULL; + if (priv->wifi_shared_permission) { + result = nm_auth_chain_get_result (chain, priv->wifi_shared_permission); if (result != NM_AUTH_CALL_RESULT_YES) { - auth_complete (self, FALSE, "Not authorized to control networking."); - return; + priv->result_func (self, + FALSE, + "Not authorized to share connections via wifi.", + priv->user_data1, + priv->user_data2); + goto done; } - } else { - nm_assert (auth_call_id == priv->auth.call_id_wifi_shared_permission); - if (result != NM_AUTH_CALL_RESULT_YES) { - /* we don't fail right away. Instead, we mark that wifi-shared-permissions - * are missing. We prefer to report the failure about network-control. - * Below, we will wait longer for call_id_network_control (if it's still - * pending). */ - priv->auth.call_id_wifi_shared_permission = AUTH_CALL_ID_SHARED_WIFI_PERMISSION_FAILED; - } else - priv->auth.call_id_wifi_shared_permission = NULL; } - if (priv->auth.call_id_network_control) - return; + /* Otherwise authorized and available to activate */ + priv->result_func (self, TRUE, NULL, priv->user_data1, priv->user_data2); - if (priv->auth.call_id_wifi_shared_permission) { - if (priv->auth.call_id_wifi_shared_permission == AUTH_CALL_ID_SHARED_WIFI_PERMISSION_FAILED) - auth_complete (self, FALSE, "Not authorized to share connections via wifi."); - return; - } +done: + nm_auth_chain_unref (chain); + priv->chain = NULL; + priv->result_func = NULL; + priv->user_data1 = NULL; + priv->user_data2 = NULL; - auth_complete (self, TRUE, NULL); + g_object_unref (self); } /** @@ -1100,43 +1070,37 @@ nm_active_connection_authorize (NMActiveConnection *self, const char *wifi_permission = NULL; NMConnection *con; - g_return_if_fail (result_func); - g_return_if_fail (!priv->auth.call_id_network_control); - nm_assert (!priv->auth.call_id_wifi_shared_permission); + g_return_if_fail (result_func != NULL); + g_return_if_fail (priv->chain == NULL); if (initial_connection) { g_return_if_fail (NM_IS_CONNECTION (initial_connection)); - g_return_if_fail (!priv->settings_connection.obj); + g_return_if_fail (!priv->settings_connection); g_return_if_fail (!priv->applied_connection); con = initial_connection; } else { - g_return_if_fail (NM_IS_SETTINGS_CONNECTION (priv->settings_connection.obj)); + g_return_if_fail (NM_IS_SETTINGS_CONNECTION (priv->settings_connection)); g_return_if_fail (NM_IS_CONNECTION (priv->applied_connection)); con = priv->applied_connection; } - priv->auth.call_id_network_control = nm_auth_manager_check_authorization (nm_auth_manager_get (), - priv->subject, - NM_AUTH_PERMISSION_NETWORK_CONTROL, - TRUE, - auth_done, - self); + priv->chain = nm_auth_chain_new_subject (priv->subject, NULL, auth_done, self); + g_assert (priv->chain); + + /* Check that the subject is allowed to use networking at all */ + nm_auth_chain_add_call (priv->chain, NM_AUTH_PERMISSION_NETWORK_CONTROL, TRUE); /* Shared wifi connections require special permissions too */ wifi_permission = nm_utils_get_shared_wifi_permission (con); if (wifi_permission) { - priv->auth.call_id_wifi_shared_permission = nm_auth_manager_check_authorization (nm_auth_manager_get (), - priv->subject, - wifi_permission, - TRUE, - auth_done, - self); + priv->wifi_shared_permission = wifi_permission; + nm_auth_chain_add_call (priv->chain, wifi_permission, TRUE); } /* Wait for authorization */ - priv->auth.result_func = result_func; - priv->auth.user_data1 = user_data1; - priv->auth.user_data2 = user_data2; + priv->result_func = result_func; + priv->user_data1 = user_data1; + priv->user_data2 = user_data2; } /*****************************************************************************/ @@ -1198,40 +1162,31 @@ get_property (GObject *object, guint prop_id, GValue *value, GParamSpec *pspec) { NMActiveConnectionPrivate *priv = NM_ACTIVE_CONNECTION_GET_PRIVATE ((NMActiveConnection *) object); - char **strv; + GPtrArray *devices; NMDevice *master_device = NULL; switch (prop_id) { - - /* note that while priv->settings_connection.obj might not be set initially, - * it will be set before the object is exported on D-Bus. Hence, - * nobody is calling these property getters before the object is - * exported, at which point we will have a valid settings-connection. - * - * Therefore, intentionally not check whether priv->settings_connection.obj - * is set, to get an assertion failure if somebody tries to access the - * getters at the wrong time. */ case PROP_CONNECTION: - g_value_set_string (value, nm_dbus_track_obj_path_get (&priv->settings_connection)); + g_value_set_string (value, nm_connection_get_path (NM_CONNECTION (priv->settings_connection))); break; case PROP_ID: - g_value_set_string (value, nm_connection_get_id (NM_CONNECTION (priv->settings_connection.obj))); + g_value_set_string (value, nm_connection_get_id (NM_CONNECTION (priv->settings_connection))); break; case PROP_UUID: - g_value_set_string (value, nm_connection_get_uuid (NM_CONNECTION (priv->settings_connection.obj))); + g_value_set_string (value, nm_connection_get_uuid (NM_CONNECTION (priv->settings_connection))); break; case PROP_TYPE: - g_value_set_string (value, nm_connection_get_connection_type (NM_CONNECTION (priv->settings_connection.obj))); + g_value_set_string (value, nm_connection_get_connection_type (NM_CONNECTION (priv->settings_connection))); break; - case PROP_SPECIFIC_OBJECT: - g_value_set_string (value, priv->specific_object); + g_value_set_string (value, priv->specific_object ? priv->specific_object : "/"); break; case PROP_DEVICES: - strv = g_new0 (char *, 2); + devices = g_ptr_array_sized_new (2); if (priv->device && priv->state < NM_ACTIVE_CONNECTION_STATE_DEACTIVATED) - strv[0] = g_strdup (nm_dbus_object_get_path (NM_DBUS_OBJECT (priv->device))); - g_value_take_boxed (value, strv); + g_ptr_array_add (devices, g_strdup (nm_exported_object_get_path (NM_EXPORTED_OBJECT (priv->device)))); + g_ptr_array_add (devices, NULL); + g_value_take_boxed (value, (char **) g_ptr_array_free (devices, FALSE)); break; case PROP_STATE: if (priv->state_set) @@ -1251,19 +1206,19 @@ get_property (GObject *object, guint prop_id, break; case PROP_IP4_CONFIG: /* The IP and DHCP config properties may be overridden by a subclass */ - g_value_set_string (value, NULL); + g_value_set_string (value, "/"); break; case PROP_DHCP4_CONFIG: - g_value_set_string (value, NULL); + g_value_set_string (value, "/"); break; case PROP_DEFAULT6: g_value_set_boolean (value, priv->is_default6); break; case PROP_IP6_CONFIG: - g_value_set_string (value, NULL); + g_value_set_string (value, "/"); break; case PROP_DHCP6_CONFIG: - g_value_set_string (value, NULL); + g_value_set_string (value, "/"); break; case PROP_VPN: g_value_set_boolean (value, priv->vpn); @@ -1271,7 +1226,7 @@ get_property (GObject *object, guint prop_id, case PROP_MASTER: if (priv->master) master_device = nm_active_connection_get_device (priv->master); - nm_dbus_utils_g_value_set_object_path (value, master_device); + nm_utils_g_value_set_object_path (value, master_device); break; case PROP_INT_SUBJECT: g_value_set_object (value, priv->subject); @@ -1345,8 +1300,9 @@ set_property (GObject *object, guint prop_id, case PROP_SPECIFIC_OBJECT: /* construct-only */ tmp = g_value_get_string (value); - tmp = nm_utils_dbus_normalize_object_path (tmp); - priv->specific_object = g_strdup (tmp); + /* NM uses "/" to mean NULL */ + if (g_strcmp0 (tmp, "/") != 0) + priv->specific_object = g_strdup (tmp); break; case PROP_DEFAULT: priv->is_default = g_value_get_boolean (value); @@ -1376,10 +1332,6 @@ nm_active_connection_init (NMActiveConnection *self) priv = G_TYPE_INSTANCE_GET_PRIVATE (self, NM_TYPE_ACTIVE_CONNECTION, NMActiveConnectionPrivate); self->_priv = priv; - nm_dbus_track_obj_path_init (&priv->settings_connection, - G_OBJECT (self), - obj_properties[PROP_CONNECTION]); - c_list_init (&self->active_connections_lst); _LOGT ("creating"); @@ -1397,8 +1349,8 @@ constructed (GObject *object) G_OBJECT_CLASS (nm_active_connection_parent_class)->constructed (object); if ( !priv->applied_connection - && priv->settings_connection.obj) - priv->applied_connection = nm_simple_connection_new_clone (NM_CONNECTION (priv->settings_connection.obj)); + && priv->settings_connection) + priv->applied_connection = nm_simple_connection_new_clone (NM_CONNECTION (priv->settings_connection)); _LOGD ("constructed (%s, version-id %llu, type %s)", G_OBJECT_TYPE_NAME (self), @@ -1428,9 +1380,13 @@ dispose (GObject *object) _LOGD ("disposing"); - auth_cancel (self); + if (priv->chain) { + nm_auth_chain_unref (priv->chain); + priv->chain = NULL; + } - nm_clear_g_free (&priv->specific_object); + g_free (priv->specific_object); + priv->specific_object = NULL; _set_settings_connection (self, NULL); g_clear_object (&priv->applied_connection); @@ -1453,70 +1409,21 @@ dispose (GObject *object) } static void -finalize (GObject *object) -{ - NMActiveConnection *self = NM_ACTIVE_CONNECTION (object); - NMActiveConnectionPrivate *priv = NM_ACTIVE_CONNECTION_GET_PRIVATE (self); - - nm_dbus_track_obj_path_set (&priv->settings_connection, NULL, FALSE); - - G_OBJECT_CLASS (nm_active_connection_parent_class)->finalize (object); -} - -static const GDBusSignalInfo signal_info_state_changed = NM_DEFINE_GDBUS_SIGNAL_INFO_INIT ( - "StateChanged", - .args = NM_DEFINE_GDBUS_ARG_INFOS ( - NM_DEFINE_GDBUS_ARG_INFO ("state", "u"), - NM_DEFINE_GDBUS_ARG_INFO ("reason", "u"), - ), -); - -static const NMDBusInterfaceInfoExtended interface_info_active_connection = { - .parent = NM_DEFINE_GDBUS_INTERFACE_INFO_INIT ( - NM_DBUS_INTERFACE_ACTIVE_CONNECTION, - .signals = NM_DEFINE_GDBUS_SIGNAL_INFOS ( - &nm_signal_info_property_changed_legacy, - &signal_info_state_changed, - ), - .properties = NM_DEFINE_GDBUS_PROPERTY_INFOS ( - NM_DEFINE_DBUS_PROPERTY_INFO_EXTENDED_READABLE_L ("Connection", "o", NM_ACTIVE_CONNECTION_CONNECTION), - NM_DEFINE_DBUS_PROPERTY_INFO_EXTENDED_READABLE_L ("SpecificObject", "o", NM_ACTIVE_CONNECTION_SPECIFIC_OBJECT), - NM_DEFINE_DBUS_PROPERTY_INFO_EXTENDED_READABLE_L ("Id", "s", NM_ACTIVE_CONNECTION_ID), - NM_DEFINE_DBUS_PROPERTY_INFO_EXTENDED_READABLE_L ("Uuid", "s", NM_ACTIVE_CONNECTION_UUID), - NM_DEFINE_DBUS_PROPERTY_INFO_EXTENDED_READABLE_L ("Type", "s", NM_ACTIVE_CONNECTION_TYPE), - NM_DEFINE_DBUS_PROPERTY_INFO_EXTENDED_READABLE_L ("Devices", "ao", NM_ACTIVE_CONNECTION_DEVICES), - NM_DEFINE_DBUS_PROPERTY_INFO_EXTENDED_READABLE_L ("State", "u", NM_ACTIVE_CONNECTION_STATE), - NM_DEFINE_DBUS_PROPERTY_INFO_EXTENDED_READABLE_L ("StateFlags", "u", NM_ACTIVE_CONNECTION_STATE_FLAGS), - NM_DEFINE_DBUS_PROPERTY_INFO_EXTENDED_READABLE_L ("Default", "b", NM_ACTIVE_CONNECTION_DEFAULT), - NM_DEFINE_DBUS_PROPERTY_INFO_EXTENDED_READABLE_L ("Ip4Config", "o", NM_ACTIVE_CONNECTION_IP4_CONFIG), - NM_DEFINE_DBUS_PROPERTY_INFO_EXTENDED_READABLE_L ("Dhcp4Config", "o", NM_ACTIVE_CONNECTION_DHCP4_CONFIG), - NM_DEFINE_DBUS_PROPERTY_INFO_EXTENDED_READABLE_L ("Default6", "b", NM_ACTIVE_CONNECTION_DEFAULT6), - NM_DEFINE_DBUS_PROPERTY_INFO_EXTENDED_READABLE_L ("Ip6Config", "o", NM_ACTIVE_CONNECTION_IP6_CONFIG), - NM_DEFINE_DBUS_PROPERTY_INFO_EXTENDED_READABLE_L ("Dhcp6Config", "o", NM_ACTIVE_CONNECTION_DHCP6_CONFIG), - NM_DEFINE_DBUS_PROPERTY_INFO_EXTENDED_READABLE_L ("Vpn", "b", NM_ACTIVE_CONNECTION_VPN), - NM_DEFINE_DBUS_PROPERTY_INFO_EXTENDED_READABLE_L ("Master", "o", NM_ACTIVE_CONNECTION_MASTER), - ), - ), - .legacy_property_changed = TRUE, -}; - -static void nm_active_connection_class_init (NMActiveConnectionClass *ac_class) { GObjectClass *object_class = G_OBJECT_CLASS (ac_class); - NMDBusObjectClass *dbus_object_class = NM_DBUS_OBJECT_CLASS (ac_class); + NMExportedObjectClass *exported_object_class = NM_EXPORTED_OBJECT_CLASS (ac_class); g_type_class_add_private (ac_class, sizeof (NMActiveConnectionPrivate)); - dbus_object_class->export_path = NM_DBUS_EXPORT_PATH_NUMBERED (NM_DBUS_PATH"/ActiveConnection"); - dbus_object_class->interface_infos = NM_DBUS_INTERFACE_INFOS (&interface_info_active_connection); + exported_object_class->export_path = NM_EXPORT_PATH_NUMBERED (NM_DBUS_PATH"/ActiveConnection"); object_class->get_property = get_property; object_class->set_property = set_property; object_class->constructed = constructed; object_class->dispose = dispose; - object_class->finalize = finalize; + /* D-Bus exported properties */ obj_properties[PROP_CONNECTION] = g_param_spec_string (NM_ACTIVE_CONNECTION_CONNECTION, "", "", NULL, @@ -1701,4 +1608,9 @@ nm_active_connection_class_init (NMActiveConnectionClass *ac_class) G_SIGNAL_RUN_FIRST, 0, NULL, NULL, NULL, G_TYPE_NONE, 2, G_TYPE_UINT, G_TYPE_UINT); + + nm_exported_object_class_add_interface (NM_EXPORTED_OBJECT_CLASS (ac_class), + NMDBUS_TYPE_ACTIVE_CONNECTION_SKELETON, + NULL); } + diff --git a/src/nm-active-connection.h b/src/nm-active-connection.h index c3d08b64..9b6a49ef 100644 --- a/src/nm-active-connection.h +++ b/src/nm-active-connection.h @@ -21,9 +21,10 @@ #ifndef __NETWORKMANAGER_ACTIVE_CONNECTION_H__ #define __NETWORKMANAGER_ACTIVE_CONNECTION_H__ -#include "c-list/src/c-list.h" +#include "nm-exported-object.h" #include "nm-connection.h" -#include "nm-dbus-object.h" + +#include "nm-utils/c-list.h" #define NM_TYPE_ACTIVE_CONNECTION (nm_active_connection_get_type ()) #define NM_ACTIVE_CONNECTION(obj) (G_TYPE_CHECK_INSTANCE_CAST ((obj), NM_TYPE_ACTIVE_CONNECTION, NMActiveConnection)) @@ -71,7 +72,7 @@ struct _NMActiveConnectionPrivate; struct _NMActiveConnection { - NMDBusObject parent; + NMExportedObject parent; struct _NMActiveConnectionPrivate *_priv; /* active connection can be tracked in a list by NMManager. This is @@ -80,7 +81,7 @@ struct _NMActiveConnection { }; typedef struct { - NMDBusObjectClass parent; + NMExportedObjectClass parent; /* re-emits device state changes as a convenience for subclasses for * device states >= DISCONNECTED. diff --git a/src/nm-audit-manager.c b/src/nm-audit-manager.c index 45d068f9..2d75c0e7 100644 --- a/src/nm-audit-manager.c +++ b/src/nm-audit-manager.c @@ -123,7 +123,7 @@ build_message (GPtrArray *fields, AuditBackend backend) for (i = 0; i < fields->len; i++) { field = fields->pdata[i]; - if (!NM_FLAGS_ANY (field->backends, backend)) + if (!NM_FLAGS_HAS (field->backends, backend)) continue; if (first) diff --git a/src/nm-audit-manager.h b/src/nm-audit-manager.h index 59b8048f..56e26584 100644 --- a/src/nm-audit-manager.h +++ b/src/nm-audit-manager.h @@ -57,7 +57,6 @@ typedef struct _NMAuditManagerClass NMAuditManagerClass; #define NM_AUDIT_OP_CHECKPOINT_CREATE "checkpoint-create" #define NM_AUDIT_OP_CHECKPOINT_ROLLBACK "checkpoint-rollback" #define NM_AUDIT_OP_CHECKPOINT_DESTROY "checkpoint-destroy" -#define NM_AUDIT_OP_CHECKPOINT_ADJUST_ROLLBACK_TIMEOUT "checkpoint-adjust-rollback-timeout" GType nm_audit_manager_get_type (void); NMAuditManager *nm_audit_manager_get (void); diff --git a/src/nm-auth-manager.c b/src/nm-auth-manager.c index 199a2e40..003d9975 100644 --- a/src/nm-auth-manager.c +++ b/src/nm-auth-manager.c @@ -22,7 +22,6 @@ #include "nm-auth-manager.h" -#include "c-list/src/c-list.h" #include "nm-errors.h" #include "nm-core-internal.h" #include "NetworkManagerUtils.h" @@ -31,9 +30,6 @@ #define POLKIT_OBJECT_PATH "/org/freedesktop/PolicyKit1/Authority" #define POLKIT_INTERFACE "org.freedesktop.PolicyKit1.Authority" -#define CANCELLATION_ID_PREFIX "cancellation-id-" -#define CANCELLATION_TIMEOUT_MS 5000 - /*****************************************************************************/ NM_GOBJECT_PROPERTIES_DEFINE_BASE ( @@ -48,14 +44,13 @@ enum { static guint signals[LAST_SIGNAL] = {0}; typedef struct { - CList calls_lst_head; - GDBusProxy *proxy; + gboolean polkit_enabled; +#if WITH_POLKIT + guint call_id_counter; GCancellable *new_proxy_cancellable; - GCancellable *cancel_cancellable; - guint64 call_numid_counter; - bool polkit_enabled:1; - bool disposing:1; - bool shutting_down:1; + GSList *queued_calls; + GDBusProxy *proxy; +#endif } NMAuthManagerPrivate; struct _NMAuthManager { @@ -90,22 +85,6 @@ NM_DEFINE_SINGLETON_REGISTER (NMAuthManager); } \ } G_STMT_END -#define _NMLOG2(level, call_id, ...) \ - G_STMT_START { \ - if (nm_logging_enabled ((level), (_NMLOG_DOMAIN))) { \ - NMAuthManagerCallId *_call_id = (call_id); \ - char __prefix[30] = _NMLOG_PREFIX_NAME; \ - \ - if (_call_id->self != singleton_instance) \ - g_snprintf (__prefix, sizeof (__prefix), ""_NMLOG_PREFIX_NAME"[%p]", _call_id->self); \ - _nm_log ((level), (_NMLOG_DOMAIN), 0, NULL, NULL, \ - "%s: call[%"G_GUINT64_FORMAT"]: " _NM_UTILS_MACRO_FIRST(__VA_ARGS__), \ - __prefix, \ - _call_id->call_numid \ - _NM_UTILS_MACRO_REST(__VA_ARGS__)); \ - } \ - } G_STMT_END - /*****************************************************************************/ gboolean @@ -118,323 +97,251 @@ nm_auth_manager_get_polkit_enabled (NMAuthManager *self) /*****************************************************************************/ +#if WITH_POLKIT + typedef enum { POLKIT_CHECK_AUTHORIZATION_FLAGS_NONE = 0, POLKIT_CHECK_AUTHORIZATION_FLAGS_ALLOW_USER_INTERACTION = (1<<0), } PolkitCheckAuthorizationFlags; -typedef enum { - IDLE_REASON_AUTHORIZED, - IDLE_REASON_NO_DBUS, -} IdleReason; - -struct _NMAuthManagerCallId { - CList calls_lst; +typedef struct { + guint call_id; NMAuthManager *self; + GSimpleAsyncResult *simple; + gchar *cancellation_id; GVariant *dbus_parameters; - GCancellable *dbus_cancellable; - NMAuthManagerCheckAuthorizationCallback callback; - gpointer user_data; - guint64 call_numid; - guint idle_id; - IdleReason idle_reason:8; -}; - -#define cancellation_id_to_str_a(call_numid) \ - nm_sprintf_bufa (NM_STRLEN (CANCELLATION_ID_PREFIX) + 20, \ - CANCELLATION_ID_PREFIX"%"G_GUINT64_FORMAT, \ - (call_numid)) + GCancellable *cancellable; +} CheckAuthData; static void -_call_id_free (NMAuthManagerCallId *call_id) +_check_auth_data_free (CheckAuthData *data) { - c_list_unlink (&call_id->calls_lst); - nm_clear_g_source (&call_id->idle_id); - if (call_id->dbus_parameters) - g_variant_unref (g_steal_pointer (&call_id->dbus_parameters)); - - if (call_id->dbus_cancellable) { - /* we have a pending D-Bus call. We keep the call-id instance alive - * for _call_check_authorize_cb() */ - g_cancellable_cancel (call_id->dbus_cancellable); - return; - } - - g_object_unref (call_id->self); - g_slice_free (NMAuthManagerCallId, call_id); + if (data->dbus_parameters) + g_variant_unref (data->dbus_parameters); + g_object_unref (data->self); + g_object_unref (data->simple); + g_clear_object (&data->cancellable); + g_free (data->cancellation_id); + g_free (data); } static void -_call_id_invoke_callback (NMAuthManagerCallId *call_id, - gboolean is_authorized, - gboolean is_challenge, - GError *error) +_call_check_authorization_complete_with_error (CheckAuthData *data, + const char *error_message) { - c_list_unlink (&call_id->calls_lst); - - call_id->callback (call_id->self, - call_id, - is_authorized, - is_challenge, - error, - call_id->user_data); - _call_id_free (call_id); + NMAuthManager *self = data->self; + + _LOGD ("call[%u]: CheckAuthorization failed due to internal error: %s", data->call_id, error_message); + g_simple_async_result_set_error (data->simple, + NM_MANAGER_ERROR, + NM_MANAGER_ERROR_FAILED, + "Authorization check failed: %s", + error_message); + + g_simple_async_result_complete_in_idle (data->simple); + + _check_auth_data_free (data); } static void -cancel_check_authorization_cb (GObject *proxy, +cancel_check_authorization_cb (GDBusProxy *proxy, GAsyncResult *res, gpointer user_data) { - NMAuthManagerCallId *call_id = user_data; - gs_unref_variant GVariant *value = NULL; - gs_free_error GError *error= NULL; - - value = g_dbus_proxy_call_finish (G_DBUS_PROXY (proxy), res, &error); - if (g_error_matches (error, G_IO_ERROR, G_IO_ERROR_CANCELLED)) - _LOG2T (call_id, "cancel request was cancelled"); - else if (error) - _LOG2T (call_id, "cancel request failed: %s", error->message); - else - _LOG2T (call_id, "cancel request succeeded"); + NMAuthManager *self = user_data; + GVariant *value; + GError *error= NULL; + + value = g_dbus_proxy_call_finish (proxy, res, &error); + if (value == NULL) { + g_dbus_error_strip_remote_error (error); + _LOGD ("Error cancelling authorization check: %s", error->message); + g_error_free (error); + } else + g_variant_unref (value); - _call_id_free (call_id); + g_object_unref (self); } +typedef struct { + gboolean is_authorized; + gboolean is_challenge; +} CheckAuthorizationResult; + static void -_call_check_authorize_cb (GObject *proxy, - GAsyncResult *res, - gpointer user_data) +check_authorization_cb (GDBusProxy *proxy, + GAsyncResult *res, + gpointer user_data) { - NMAuthManagerCallId *call_id = user_data; - NMAuthManager *self; - NMAuthManagerPrivate *priv; - gs_unref_variant GVariant *value = NULL; - gs_free_error GError *error = NULL; - gboolean is_authorized = FALSE; - gboolean is_challenge = FALSE; - - /* we need to clear the cancelable, to signal for _call_id_free() that we - * are not in a pending call. - * - * Note how _call_id_free() kept call-id alive, even if the request was - * already cancelled. */ - g_clear_object (&call_id->dbus_cancellable); - - self = call_id->self; - priv = NM_AUTH_MANAGER_GET_PRIVATE (self); - - value = _nm_dbus_proxy_call_finish (G_DBUS_PROXY (proxy), res, G_VARIANT_TYPE ("((bba{ss}))"), &error); - if (g_error_matches (error, G_IO_ERROR, G_IO_ERROR_CANCELLED)) { - /* call_id was cancelled externally, but _call_id_free() kept call_id - * alive (and it has still the reference on @self. */ - - if (!priv->cancel_cancellable) { - /* we do a forced shutdown. There is no more time for cancelling... */ - _call_id_free (call_id); - - /* this shouldn't really happen, because: - * _call_check_authorize() only scheduled the D-Bus request at a time when - * cancel_cancellable was still set. It means, somebody called force-shutdown - * after call-id was schedule. - * force-shutdown should only be called after: - * - cancel all pending requests - * - give enough time to cancel the request and schedule a D-Bus call - * to CancelCheckAuthorization (below), before issuing force-shutdown. */ - g_return_if_reached (); - } + CheckAuthData *data = user_data; + NMAuthManager *self = data->self; + NMAuthManagerPrivate *priv = NM_AUTH_MANAGER_GET_PRIVATE (self); + GVariant *value; + GError *error = NULL; + + value = _nm_dbus_proxy_call_finish (proxy, res, G_VARIANT_TYPE ("((bba{ss}))"), &error); + if (value == NULL) { + if (data->cancellation_id != NULL && + ( g_error_matches (error, G_IO_ERROR, G_IO_ERROR_CANCELLED) + && !g_dbus_error_is_remote_error (error))) { + _LOGD ("call[%u]: CheckAuthorization cancelled", data->call_id); + g_dbus_proxy_call (priv->proxy, + "CancelCheckAuthorization", + g_variant_new ("(s)", data->cancellation_id), + G_DBUS_CALL_FLAGS_NONE, + -1, + NULL, /* GCancellable */ + (GAsyncReadyCallback) cancel_check_authorization_cb, + g_object_ref (self)); + } else + _LOGD ("call[%u]: CheckAuthorization failed: %s", data->call_id, error->message); + g_dbus_error_strip_remote_error (error); + g_simple_async_result_set_error (data->simple, + NM_MANAGER_ERROR, + NM_MANAGER_ERROR_FAILED, + "Authorization check failed: %s", + error->message); + g_error_free (error); + } else { + CheckAuthorizationResult *result; - g_dbus_proxy_call (priv->proxy, - "CancelCheckAuthorization", - g_variant_new ("(s)", - cancellation_id_to_str_a (call_id->call_numid)), - G_DBUS_CALL_FLAGS_NONE, - CANCELLATION_TIMEOUT_MS, - priv->cancel_cancellable, - cancel_check_authorization_cb, - call_id); - return; - } + result = g_new0 (CheckAuthorizationResult, 1); - if (!error) { g_variant_get (value, "((bb@a{ss}))", - &is_authorized, - &is_challenge, + &result->is_authorized, + &result->is_challenge, NULL); - _LOG2T (call_id, "completed: authorized=%d, challenge=%d", - is_authorized, is_challenge); - } else - _LOG2T (call_id, "completed: failed: %s", error->message); + g_variant_unref (value); + + _LOGD ("call[%u]: CheckAuthorization succeeded: (is_authorized=%d, is_challenge=%d)", data->call_id, result->is_authorized, result->is_challenge); + g_simple_async_result_set_op_res_gpointer (data->simple, result, g_free); + } + + g_simple_async_result_complete (data->simple); - _call_id_invoke_callback (call_id, is_authorized, is_challenge, error); + _check_auth_data_free (data); } static void -_call_check_authorize (NMAuthManagerCallId *call_id) +_call_check_authorization (CheckAuthData *data) { - NMAuthManager *self = call_id->self; - NMAuthManagerPrivate *priv = NM_AUTH_MANAGER_GET_PRIVATE (self); - - nm_assert (call_id->dbus_parameters); - nm_assert (g_variant_is_floating (call_id->dbus_parameters)); - nm_assert (!call_id->dbus_cancellable); - - call_id->dbus_cancellable = g_cancellable_new (); - - nm_assert (priv->cancel_cancellable); + NMAuthManagerPrivate *priv = NM_AUTH_MANAGER_GET_PRIVATE (data->self); g_dbus_proxy_call (priv->proxy, "CheckAuthorization", - g_steal_pointer (&call_id->dbus_parameters), + data->dbus_parameters, G_DBUS_CALL_FLAGS_NONE, G_MAXINT, /* no timeout */ - call_id->dbus_cancellable, - _call_check_authorize_cb, - call_id); + data->cancellable, + (GAsyncReadyCallback) check_authorization_cb, + data); + g_clear_object (&data->cancellable); + data->dbus_parameters = NULL; } -static gboolean -_call_on_idle (gpointer user_data) -{ - NMAuthManagerCallId *call_id = user_data; - gs_free_error GError *error = NULL; - gboolean is_authorized = FALSE; - gboolean is_challenge = FALSE; - const char *error_msg = NULL; - - call_id->idle_id = 0; - if (call_id->idle_reason == IDLE_REASON_AUTHORIZED) { - is_authorized = TRUE; - _LOG2T (call_id, "completed: authorized=%d, challenge=%d (simulated)", - is_authorized, is_challenge); - } else { - nm_assert (call_id->idle_reason == IDLE_REASON_NO_DBUS); - error_msg = "failure creating GDBusProxy for authorization request"; - _LOG2T (call_id, "completed: failed due to no D-Bus proxy"); - } - - if (error_msg) - g_set_error_literal (&error, NM_UTILS_ERROR, NM_UTILS_ERROR_UNKNOWN, error_msg); - _call_id_invoke_callback (call_id, is_authorized, is_challenge, error); - return G_SOURCE_REMOVE; -} - -/* - * @callback must never be invoked synchronously. - * - * @callback is always invoked exactly once, and never synchronously. - * You may cancel the invocation with nm_auth_manager_check_authorization_cancel(), - * but: you may only do so exactly once, and only before @callback is - * invoked. Even if you cancel the request, @callback will still be invoked - * (synchronously, during the _cancel() callback). - * - * The request keeps @self alive (it needs to do so, because when cancelling a - * request we might need to do an additional CancelCheckAuthorization call, for - * which @self must be live long enough). - */ -NMAuthManagerCallId * -nm_auth_manager_check_authorization (NMAuthManager *self, - NMAuthSubject *subject, - const char *action_id, - gboolean allow_user_interaction, - NMAuthManagerCheckAuthorizationCallback callback, - gpointer user_data) +void +nm_auth_manager_polkit_authority_check_authorization (NMAuthManager *self, + NMAuthSubject *subject, + const char *action_id, + gboolean allow_user_interaction, + GCancellable *cancellable, + GAsyncReadyCallback callback, + gpointer user_data) { NMAuthManagerPrivate *priv; - PolkitCheckAuthorizationFlags flags; char subject_buf[64]; GVariantBuilder builder; + PolkitCheckAuthorizationFlags flags; GVariant *subject_value; GVariant *details_value; - NMAuthManagerCallId *call_id; + CheckAuthData *data; - g_return_val_if_fail (NM_IS_AUTH_MANAGER (self), NULL); - g_return_val_if_fail (NM_IN_SET (nm_auth_subject_get_subject_type (subject), - NM_AUTH_SUBJECT_TYPE_INTERNAL, - NM_AUTH_SUBJECT_TYPE_UNIX_PROCESS), - NULL); - g_return_val_if_fail (action_id, NULL); + g_return_if_fail (NM_IS_AUTH_MANAGER (self)); + g_return_if_fail (NM_IS_AUTH_SUBJECT (subject)); + g_return_if_fail (nm_auth_subject_is_unix_process (subject)); + g_return_if_fail (action_id != NULL); + g_return_if_fail (cancellable == NULL || G_IS_CANCELLABLE (cancellable)); priv = NM_AUTH_MANAGER_GET_PRIVATE (self); - g_return_val_if_fail (!priv->disposing, NULL); - g_return_val_if_fail (!priv->shutting_down, NULL); + g_return_if_fail (priv->polkit_enabled); flags = allow_user_interaction ? POLKIT_CHECK_AUTHORIZATION_FLAGS_ALLOW_USER_INTERACTION : POLKIT_CHECK_AUTHORIZATION_FLAGS_NONE; - call_id = g_slice_new0 (NMAuthManagerCallId); - call_id->self = g_object_ref (self); - call_id->callback = callback; - call_id->user_data = user_data; - call_id->call_numid = ++priv->call_numid_counter; - c_list_link_tail (&priv->calls_lst_head, &call_id->calls_lst); - - if (!priv->polkit_enabled) { - _LOG2T (call_id, "CheckAuthorization(%s), subject=%s (succeeding due to polkit authorization disabled)", action_id, nm_auth_subject_to_string (subject, subject_buf, sizeof (subject_buf))); - call_id->idle_reason = IDLE_REASON_AUTHORIZED; - call_id->idle_id = g_idle_add (_call_on_idle, call_id); - } else if (nm_auth_subject_is_internal (subject)) { - _LOG2T (call_id, "CheckAuthorization(%s), subject=%s (succeeding for internal request)", action_id, nm_auth_subject_to_string (subject, subject_buf, sizeof (subject_buf))); - call_id->idle_reason = IDLE_REASON_AUTHORIZED; - call_id->idle_id = g_idle_add (_call_on_idle, call_id); - } else if (nm_auth_subject_get_unix_process_uid (subject) == 0) { - _LOG2T (call_id, "CheckAuthorization(%s), subject=%s (succeeding for root)", action_id, nm_auth_subject_to_string (subject, subject_buf, sizeof (subject_buf))); - call_id->idle_reason = IDLE_REASON_AUTHORIZED; - call_id->idle_id = g_idle_add (_call_on_idle, call_id); - } else if ( !priv->proxy - && !priv->new_proxy_cancellable) { - _LOG2T (call_id, "CheckAuthorization(%s), subject=%s (failing due to invalid DBUS proxy)", action_id, nm_auth_subject_to_string (subject, subject_buf, sizeof (subject_buf))); - call_id->idle_reason = IDLE_REASON_NO_DBUS; - call_id->idle_id = g_idle_add (_call_on_idle, call_id); - } else { - subject_value = nm_auth_subject_unix_process_to_polkit_gvariant (subject); - nm_assert (g_variant_is_floating (subject_value)); - - /* ((PolkitDetails *)NULL) */ - g_variant_builder_init (&builder, G_VARIANT_TYPE ("a{ss}")); - details_value = g_variant_builder_end (&builder); - - call_id->dbus_parameters = g_variant_new ("(@(sa{sv})s@a{ss}us)", - subject_value, - action_id, - details_value, - (guint32) flags, - cancellation_id_to_str_a (call_id->call_numid)); - if (!priv->proxy) { - _LOG2T (call_id, "CheckAuthorization(%s), subject=%s (wait for proxy)", action_id, nm_auth_subject_to_string (subject, subject_buf, sizeof (subject_buf))); - } else { - _LOG2T (call_id, "CheckAuthorization(%s), subject=%s", action_id, nm_auth_subject_to_string (subject, subject_buf, sizeof (subject_buf))); - _call_check_authorize (call_id); - } + subject_value = nm_auth_subject_unix_process_to_polkit_gvariant (subject); + nm_assert (g_variant_is_floating (subject_value)); + + /* ((PolkitDetails *)NULL) */ + g_variant_builder_init (&builder, G_VARIANT_TYPE ("a{ss}")); + details_value = g_variant_builder_end (&builder); + + data = g_new0 (CheckAuthData, 1); + data->call_id = ++priv->call_id_counter; + data->self = g_object_ref (self); + data->simple = g_simple_async_result_new (G_OBJECT (self), + callback, + user_data, + nm_auth_manager_polkit_authority_check_authorization); + if (cancellable != NULL) { + data->cancellation_id = g_strdup_printf ("cancellation-id-%u", data->call_id); + data->cancellable = g_object_ref (cancellable); } - return call_id; + data->dbus_parameters = g_variant_new ("(@(sa{sv})s@a{ss}us)", + subject_value, + action_id, + details_value, + (guint32) flags, + data->cancellation_id != NULL ? data->cancellation_id : ""); + + if (priv->new_proxy_cancellable) { + _LOGD ("call[%u]: CheckAuthorization(%s), subject=%s (wait for proxy)", data->call_id, action_id, nm_auth_subject_to_string (subject, subject_buf, sizeof (subject_buf))); + + priv->queued_calls = g_slist_prepend (priv->queued_calls, data); + } else if (!priv->proxy) { + _LOGD ("call[%u]: CheckAuthorization(%s), subject=%s (fails due to invalid DBUS proxy)", data->call_id, action_id, nm_auth_subject_to_string (subject, subject_buf, sizeof (subject_buf))); + + _call_check_authorization_complete_with_error (data, "invalid DBUS proxy"); + } else { + _LOGD ("call[%u]: CheckAuthorization(%s), subject=%s", data->call_id, action_id, nm_auth_subject_to_string (subject, subject_buf, sizeof (subject_buf))); + + _call_check_authorization (data); + } } -void -nm_auth_manager_check_authorization_cancel (NMAuthManagerCallId *call_id) +gboolean +nm_auth_manager_polkit_authority_check_authorization_finish (NMAuthManager *self, + GAsyncResult *res, + gboolean *out_is_authorized, + gboolean *out_is_challenge, + GError **error) { - NMAuthManager *self; - gs_free_error GError *error = NULL; - - g_return_if_fail (call_id); + gboolean success = FALSE; + gboolean is_authorized = FALSE; + gboolean is_challenge = FALSE; - self = call_id->self; + g_return_val_if_fail (NM_IS_AUTH_MANAGER (self), FALSE); + g_return_val_if_fail (G_IS_SIMPLE_ASYNC_RESULT (res), FALSE); + g_return_val_if_fail (error == NULL || *error == NULL, FALSE); - g_return_if_fail (NM_IS_AUTH_MANAGER (self)); - g_return_if_fail (!c_list_is_empty (&call_id->calls_lst)); + if (!g_simple_async_result_propagate_error (G_SIMPLE_ASYNC_RESULT (res), error)) { + CheckAuthorizationResult *result; - nm_assert (c_list_contains (&NM_AUTH_MANAGER_GET_PRIVATE (self)->calls_lst_head, &call_id->calls_lst)); + result = g_simple_async_result_get_op_res_gpointer (G_SIMPLE_ASYNC_RESULT (res)); + is_authorized = !!result->is_authorized; + is_challenge = !!result->is_challenge; + success = TRUE; + } + g_assert ((success && !error) || (!success || error)); - nm_utils_error_set_cancelled (&error, FALSE, "NMAuthManager"); - _LOG2T (call_id, "completed: failed due to call cancelled"); - _call_id_invoke_callback (call_id, - FALSE, - FALSE, - error); + if (out_is_authorized) + *out_is_authorized = is_authorized; + if (out_is_challenge) + *out_is_challenge = is_challenge; + return success; } /*****************************************************************************/ @@ -443,14 +350,14 @@ static void _emit_changed_signal (NMAuthManager *self) { _LOGD ("emit changed signal"); - g_signal_emit (self, signals[CHANGED_SIGNAL], 0); + g_signal_emit_by_name (self, NM_AUTH_MANAGER_SIGNAL_CHANGED); } static void _log_name_owner (NMAuthManager *self, char **out_name_owner) { NMAuthManagerPrivate *priv = NM_AUTH_MANAGER_GET_PRIVATE (self); - gs_free char *name_owner = NULL; + char *name_owner; name_owner = g_dbus_proxy_get_name_owner (priv->proxy); if (name_owner) @@ -458,7 +365,10 @@ _log_name_owner (NMAuthManager *self, char **out_name_owner) else _LOGD ("dbus name owner: none"); - NM_SET_OUT (out_name_owner, g_steal_pointer (&name_owner)); + if (out_name_owner) + *out_name_owner = name_owner; + else + g_free (name_owner); } static void @@ -467,16 +377,20 @@ _dbus_on_name_owner_notify_cb (GObject *object, gpointer user_data) { NMAuthManager *self = user_data; - gs_free char *name_owner = NULL; + NMAuthManagerPrivate *priv = NM_AUTH_MANAGER_GET_PRIVATE (self); + char *name_owner; - nm_assert (NM_AUTH_MANAGER_GET_PRIVATE (self)->proxy == (GDBusProxy *) object); + g_return_if_fail (priv->proxy == (void *) object); _log_name_owner (self, &name_owner); + if (!name_owner) { /* when the name disappears, we also want to raise a emit signal. * When it appears, we raise one already. */ _emit_changed_signal (self); } + + g_free (name_owner); } static void @@ -484,8 +398,9 @@ _dbus_on_changed_signal_cb (GDBusProxy *proxy, gpointer user_data) { NMAuthManager *self = user_data; + NMAuthManagerPrivate *priv = NM_AUTH_MANAGER_GET_PRIVATE (self); - nm_assert (NM_AUTH_MANAGER_GET_PRIVATE (self)->proxy == proxy); + g_return_if_fail (priv->proxy == proxy); _LOGD ("dbus signal: \"Changed\""); _emit_changed_signal (self); @@ -496,39 +411,49 @@ _dbus_new_proxy_cb (GObject *source_object, GAsyncResult *res, gpointer user_data) { - NMAuthManager *self; + NMAuthManager **p_self = user_data; + NMAuthManager *self = NULL; NMAuthManagerPrivate *priv; - gs_free GError *error = NULL; + GError *error = NULL; GDBusProxy *proxy; - NMAuthManagerCallId *call_id; + CheckAuthData *data; proxy = g_dbus_proxy_new_for_bus_finish (res, &error); - if (g_error_matches (error, G_IO_ERROR, G_IO_ERROR_CANCELLED)) + if (!*p_self) { + _LOGD ("_dbus_new_proxy_cb(): manager destroyed before callback finished. Abort"); + g_clear_object (&proxy); + g_clear_error (&error); + g_free (p_self); return; + } + self = *p_self; + g_object_remove_weak_pointer (G_OBJECT (self), (void **)p_self); + g_free (p_self); - self = user_data; priv = NM_AUTH_MANAGER_GET_PRIVATE (self); - priv->proxy = proxy; + g_return_if_fail (priv->new_proxy_cancellable); + g_return_if_fail (!priv->proxy); + g_clear_object (&priv->new_proxy_cancellable); + priv->queued_calls = g_slist_reverse (priv->queued_calls); + + priv->proxy = proxy; if (!priv->proxy) { - _LOGE ("could not create polkit proxy: %s", error->message); - -again: - c_list_for_each_entry (call_id, &priv->calls_lst_head, calls_lst) { - if (call_id->dbus_parameters) { - _LOG2T (call_id, "completed: failed due to no D-Bus proxy after startup"); - _call_id_invoke_callback (call_id, FALSE, FALSE, error); - goto again; - } + _LOGE ("could not get polkit proxy: %s", error->message); + g_clear_error (&error); + + while (priv->queued_calls) { + data = priv->queued_calls->data; + priv->queued_calls = g_slist_remove (priv->queued_calls, data); + + _call_check_authorization_complete_with_error (data, "error creating DBUS proxy"); } return; } - priv->cancel_cancellable = g_cancellable_new (); - g_signal_connect (priv->proxy, "notify::g-name-owner", G_CALLBACK (_dbus_on_name_owner_notify_cb), @@ -539,16 +464,17 @@ again: _log_name_owner (self, NULL); - c_list_for_each_entry (call_id, &priv->calls_lst_head, calls_lst) { - if (call_id->dbus_parameters) { - _LOG2T (call_id, "CheckAuthorization invoke now"); - _call_check_authorize (call_id); - } + while (priv->queued_calls) { + data = priv->queued_calls->data; + priv->queued_calls = g_slist_remove (priv->queued_calls, data); + _LOGD ("call[%u]: CheckAuthorization invoke now", data->call_id); + _call_check_authorization (data); } - _emit_changed_signal (self); } +#endif + /*****************************************************************************/ NMAuthManager * @@ -559,42 +485,23 @@ nm_auth_manager_get () return singleton_instance; } -void -nm_auth_manager_force_shutdown (NMAuthManager *self) -{ - NMAuthManagerPrivate *priv; - - g_return_if_fail (NM_IS_AUTH_MANAGER (self)); +/*****************************************************************************/ - priv = NM_AUTH_MANAGER_GET_PRIVATE (self); +static void +get_property (GObject *object, guint prop_id, GValue *value, GParamSpec *pspec) +{ + NMAuthManagerPrivate *priv = NM_AUTH_MANAGER_GET_PRIVATE ((NMAuthManager *) object); - /* while we have pending requests (NMAuthManagerCallId), the instance - * is kept alive. - * - * Even if the caller cancells all pending call-ids, we still need to keep - * a reference to self, in order to handle pending CancelCheckAuthorization - * requests. - * - * To do a corrdinated shutdown, do the following: - * - cancel all pending NMAuthManagerCallId requests. - * - ensure everybody unrefs the NMAuthManager instance. If by that, the instance - * gets destroyed, the shutdown already completed successfully. - * - Otherwise, the object is kept alive by pending CancelCheckAuthorization requests. - * wait a certain timeout (1 second) for all requests to complete (by watching - * for destruction of NMAuthManager). - * - if that doesn't happen within timeout, issue nm_auth_manager_force_shutdown() and - * wait longer. After that, soon the instance should be destroyed and you - * did a successful shutdown. - * - if the instance was still not destroyed within a short timeout, you leaked - * resources. You cannot properly shutdown. - */ - - priv->shutting_down = TRUE; - nm_clear_g_cancellable (&priv->cancel_cancellable); + switch (prop_id) { + case PROP_POLKIT_ENABLED: + g_value_set_boolean (value, priv->polkit_enabled); + 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) { @@ -616,9 +523,6 @@ set_property (GObject *object, guint prop_id, const GValue *value, GParamSpec *p static void nm_auth_manager_init (NMAuthManager *self) { - NMAuthManagerPrivate *priv = NM_AUTH_MANAGER_GET_PRIVATE (self); - - c_list_init (&priv->calls_lst_head); } static void @@ -629,10 +533,16 @@ constructed (GObject *object) G_OBJECT_CLASS (nm_auth_manager_parent_class)->constructed (object); +#if WITH_POLKIT _LOGD ("create auth-manager: polkit %s", priv->polkit_enabled ? "enabled" : "disabled"); if (priv->polkit_enabled) { + NMAuthManager **p_self; + priv->new_proxy_cancellable = g_cancellable_new (); + p_self = g_new (NMAuthManager *, 1); + *p_self = self; + g_object_add_weak_pointer (G_OBJECT (self), (void **) p_self); g_dbus_proxy_new_for_bus (G_BUS_TYPE_SYSTEM, G_DBUS_PROXY_FLAGS_DO_NOT_LOAD_PROPERTIES, NULL, @@ -641,8 +551,14 @@ constructed (GObject *object) POLKIT_INTERFACE, priv->new_proxy_cancellable, _dbus_new_proxy_cb, - self); + p_self); } +#else + if (priv->polkit_enabled) + _LOGW ("create auth-manager: polkit disabled at compile time. All authentication requests will fail"); + else + _LOGD ("create auth-manager: polkit disabled at compile time"); +#endif } NMAuthManager * @@ -669,21 +585,23 @@ static void dispose (GObject *object) { NMAuthManager* self = NM_AUTH_MANAGER (object); +#if WITH_POLKIT NMAuthManagerPrivate *priv = NM_AUTH_MANAGER_GET_PRIVATE (self); +#endif _LOGD ("dispose"); - nm_assert (c_list_is_empty (&priv->calls_lst_head)); - - priv->disposing = TRUE; +#if WITH_POLKIT + /* since we take a reference for each queued call, we don't expect to have any queued calls in dispose() */ + g_assert (!priv->queued_calls); nm_clear_g_cancellable (&priv->new_proxy_cancellable); - nm_clear_g_cancellable (&priv->cancel_cancellable); if (priv->proxy) { g_signal_handlers_disconnect_by_data (priv->proxy, self); g_clear_object (&priv->proxy); } +#endif G_OBJECT_CLASS (nm_auth_manager_parent_class)->dispose (object); } @@ -693,6 +611,7 @@ nm_auth_manager_class_init (NMAuthManagerClass *klass) { GObjectClass *object_class = G_OBJECT_CLASS (klass); + object_class->get_property = get_property; object_class->set_property = set_property; object_class->constructed = constructed; object_class->dispose = dispose; @@ -700,7 +619,7 @@ nm_auth_manager_class_init (NMAuthManagerClass *klass) obj_properties[PROP_POLKIT_ENABLED] = g_param_spec_boolean (NM_AUTH_MANAGER_POLKIT_ENABLED, "", "", FALSE, - G_PARAM_WRITABLE | + G_PARAM_READWRITE | G_PARAM_CONSTRUCT_ONLY | G_PARAM_STATIC_STRINGS); @@ -709,7 +628,11 @@ nm_auth_manager_class_init (NMAuthManagerClass *klass) signals[CHANGED_SIGNAL] = g_signal_new (NM_AUTH_MANAGER_SIGNAL_CHANGED, NM_TYPE_AUTH_MANAGER, G_SIGNAL_RUN_LAST, - 0, NULL, NULL, + 0, /* class offset */ + NULL, /* accumulator */ + NULL, /* accumulator data */ g_cclosure_marshal_VOID__VOID, - G_TYPE_NONE, 0); + G_TYPE_NONE, + 0); } + diff --git a/src/nm-auth-manager.h b/src/nm-auth-manager.h index fe7ee787..e66ef78c 100644 --- a/src/nm-auth-manager.h +++ b/src/nm-auth-manager.h @@ -23,31 +23,6 @@ #include "nm-auth-subject.h" -/*****************************************************************************/ - -typedef enum { - NM_AUTH_CALL_RESULT_UNKNOWN, - NM_AUTH_CALL_RESULT_YES, - NM_AUTH_CALL_RESULT_AUTH, - NM_AUTH_CALL_RESULT_NO, -} NMAuthCallResult; - -static inline NMAuthCallResult -nm_auth_call_result_eval (gboolean is_authorized, - gboolean is_challenge, - GError *error) -{ - if (error) - return NM_AUTH_CALL_RESULT_UNKNOWN; - if (is_authorized) - return NM_AUTH_CALL_RESULT_YES; - if (is_challenge) - return NM_AUTH_CALL_RESULT_AUTH; - return NM_AUTH_CALL_RESULT_NO; -} - -/*****************************************************************************/ - #define NM_TYPE_AUTH_MANAGER (nm_auth_manager_get_type ()) #define NM_AUTH_MANAGER(obj) (G_TYPE_CHECK_INSTANCE_CAST ((obj), NM_TYPE_AUTH_MANAGER, NMAuthManager)) #define NM_AUTH_MANAGER_CLASS(klass) (G_TYPE_CHECK_CLASS_CAST ((klass), NM_TYPE_AUTH_MANAGER, NMAuthManagerClass)) @@ -67,28 +42,23 @@ GType nm_auth_manager_get_type (void); NMAuthManager *nm_auth_manager_setup (gboolean polkit_enabled); NMAuthManager *nm_auth_manager_get (void); -void nm_auth_manager_force_shutdown (NMAuthManager *self); - gboolean nm_auth_manager_get_polkit_enabled (NMAuthManager *self); -/*****************************************************************************/ - -typedef struct _NMAuthManagerCallId NMAuthManagerCallId; - -typedef void (*NMAuthManagerCheckAuthorizationCallback) (NMAuthManager *self, - NMAuthManagerCallId *call_id, - gboolean is_authorized, - gboolean is_challenge, - GError *error, - gpointer user_data); - -NMAuthManagerCallId *nm_auth_manager_check_authorization (NMAuthManager *self, - NMAuthSubject *subject, - const char *action_id, - gboolean allow_user_interaction, - NMAuthManagerCheckAuthorizationCallback callback, - gpointer user_data); - -void nm_auth_manager_check_authorization_cancel (NMAuthManagerCallId *call_id); +#if WITH_POLKIT + +void nm_auth_manager_polkit_authority_check_authorization (NMAuthManager *self, + NMAuthSubject *subject, + const char *action_id, + gboolean allow_user_interaction, + GCancellable *cancellable, + GAsyncReadyCallback callback, + gpointer user_data); +gboolean nm_auth_manager_polkit_authority_check_authorization_finish (NMAuthManager *self, + GAsyncResult *res, + gboolean *out_is_authorized, + gboolean *out_is_challenge, + GError **error); + +#endif #endif /* NM_AUTH_MANAGER_H */ diff --git a/src/nm-auth-subject.c b/src/nm-auth-subject.c index 117a3815..0f40ff7c 100644 --- a/src/nm-auth-subject.c +++ b/src/nm-auth-subject.c @@ -33,7 +33,8 @@ #include <string.h> #include <stdlib.h> -#include "nm-dbus-manager.h" +#include "nm-bus-manager.h" +#include "NetworkManagerUtils.h" enum { PROP_0, @@ -92,15 +93,17 @@ nm_auth_subject_to_string (NMAuthSubject *self, char *buf, gsize buf_len) (unsigned long long) priv->unix_process.start_time); break; case NM_AUTH_SUBJECT_TYPE_INTERNAL: - g_strlcpy (buf, "internal", buf_len); + g_strlcat (buf, "internal", buf_len); break; default: - g_strlcpy (buf, "invalid", buf_len); + g_strlcat (buf, "invalid", buf_len); break; } return buf; } +#if WITH_POLKIT + /* returns a floating variant */ GVariant * nm_auth_subject_unix_process_to_polkit_gvariant (NMAuthSubject *self) @@ -122,6 +125,8 @@ nm_auth_subject_unix_process_to_polkit_gvariant (NMAuthSubject *self) return ret; } +#endif + NMAuthSubjectType nm_auth_subject_get_subject_type (NMAuthSubject *subject) { @@ -181,20 +186,20 @@ _new_unix_process (GDBusMethodInvocation *context, g_return_val_if_fail (context || (connection && message), NULL); if (context) { - success = nm_dbus_manager_get_caller_info (nm_dbus_manager_get (), - context, - &dbus_sender, - &uid, - &pid); - } else { - nm_assert (message); - success = nm_dbus_manager_get_caller_info_from_message (nm_dbus_manager_get (), - connection, - message, - &dbus_sender, - &uid, - &pid); - } + success = nm_bus_manager_get_caller_info (nm_bus_manager_get (), + context, + &dbus_sender, + &uid, + &pid); + } else if (message) { + success = nm_bus_manager_get_caller_info_from_message (nm_bus_manager_get (), + connection, + message, + &dbus_sender, + &uid, + &pid); + } else + g_assert_not_reached (); if (!success) return NULL; diff --git a/src/nm-auth-subject.h b/src/nm-auth-subject.h index a9921dbd..a0b6d14b 100644 --- a/src/nm-auth-subject.h +++ b/src/nm-auth-subject.h @@ -68,6 +68,10 @@ gulong nm_auth_subject_get_unix_process_uid (NMAuthSubject *subject); const char *nm_auth_subject_to_string (NMAuthSubject *self, char *buf, gsize buf_len); +#if WITH_POLKIT + GVariant * nm_auth_subject_unix_process_to_polkit_gvariant (NMAuthSubject *self); +#endif + #endif /* __NETWORKMANAGER_AUTH_SUBJECT_H__ */ diff --git a/src/nm-auth-utils.c b/src/nm-auth-utils.c index b41f6efa..f1aff430 100644 --- a/src/nm-auth-utils.c +++ b/src/nm-auth-utils.c @@ -24,83 +24,48 @@ #include <string.h> -#include "nm-utils/nm-c-list.h" - +#include "nm-utils/nm-hash-utils.h" #include "nm-setting-connection.h" #include "nm-auth-subject.h" #include "nm-auth-manager.h" #include "nm-session-monitor.h" -/*****************************************************************************/ - struct NMAuthChain { - GHashTable *data_hash; - - CList auth_call_lst_head; + guint32 refcount; + GSList *calls; + GHashTable *data; GDBusMethodInvocation *context; NMAuthSubject *subject; + GError *error; + + guint idle_id; + gboolean done; NMAuthChainResultFunc done_func; gpointer user_data; - - guint32 refcount; - - bool done:1; }; typedef struct { - CList auth_call_lst; NMAuthChain *chain; - NMAuthManagerCallId *call_id; + GCancellable *cancellable; char *permission; + guint call_idle_id; } AuthCall; -/*****************************************************************************/ - -static void -_ASSERT_call (AuthCall *call) -{ - nm_assert (call); - nm_assert (call->chain); - nm_assert (nm_c_list_contains_entry (&call->chain->auth_call_lst_head, call, auth_call_lst)); -} - -/*****************************************************************************/ - -static void -auth_call_free (AuthCall *call) -{ - if (call->call_id) - nm_auth_manager_check_authorization_cancel (call->call_id); - c_list_unlink_stale (&call->auth_call_lst); - g_free (call->permission); - g_slice_free (AuthCall, call); -} - -/*****************************************************************************/ - typedef struct { - - /* must be the first field. */ - const char *tag; - gpointer data; GDestroyNotify destroy; - char tag_data[]; } ChainData; static ChainData * -chain_data_new (const char *tag, gpointer data, GDestroyNotify destroy) +chain_data_new (gpointer data, GDestroyNotify destroy) { ChainData *tmp; - gsize l = strlen (tag); - tmp = g_malloc (sizeof (ChainData) + l + 1); - tmp->tag = &tmp->tag_data[0]; + tmp = g_slice_new (ChainData); tmp->data = data; tmp->destroy = destroy; - memcpy (&tmp->tag_data[0], tag, l + 1); return tmp; } @@ -111,7 +76,69 @@ chain_data_free (gpointer data) if (tmp->destroy) tmp->destroy (tmp->data); - g_free (tmp); + memset (tmp, 0, sizeof (ChainData)); + g_slice_free (ChainData, tmp); +} + +static gboolean +auth_chain_finish (gpointer user_data) +{ + NMAuthChain *self = user_data; + + self->idle_id = 0; + self->done = TRUE; + + /* Ensure we stay alive across the callback */ + self->refcount++; + self->done_func (self, self->error, self->context, self->user_data); + nm_auth_chain_unref (self); + return FALSE; +} + +/* Creates the NMAuthSubject automatically */ +NMAuthChain * +nm_auth_chain_new_context (GDBusMethodInvocation *context, + NMAuthChainResultFunc done_func, + gpointer user_data) +{ + NMAuthSubject *subject; + NMAuthChain *chain; + + g_return_val_if_fail (context != NULL, NULL); + + subject = nm_auth_subject_new_unix_process_from_context (context); + if (!subject) + return NULL; + + chain = nm_auth_chain_new_subject (subject, + context, + done_func, + user_data); + g_object_unref (subject); + return chain; +} + +/* Requires an NMAuthSubject */ +NMAuthChain * +nm_auth_chain_new_subject (NMAuthSubject *subject, + GDBusMethodInvocation *context, + NMAuthChainResultFunc done_func, + gpointer user_data) +{ + NMAuthChain *self; + + g_return_val_if_fail (NM_IS_AUTH_SUBJECT (subject), NULL); + g_return_val_if_fail (nm_auth_subject_is_unix_process (subject) || nm_auth_subject_is_internal (subject), NULL); + + self = g_slice_new0 (NMAuthChain); + self->refcount = 1; + self->data = g_hash_table_new_full (nm_str_hash, g_str_equal, g_free, chain_data_free); + self->done_func = done_func; + self->user_data = user_data; + self->context = context ? g_object_ref (context) : NULL; + self->subject = g_object_ref (subject); + + return self; } static gpointer @@ -119,17 +146,15 @@ _get_data (NMAuthChain *self, const char *tag) { ChainData *tmp; - if (!self->data_hash) - return NULL; - tmp = g_hash_table_lookup (self->data_hash, &tag); + tmp = g_hash_table_lookup (self->data, tag); return tmp ? tmp->data : NULL; } gpointer nm_auth_chain_get_data (NMAuthChain *self, const char *tag) { - g_return_val_if_fail (self, NULL); - g_return_val_if_fail (tag, NULL); + g_return_val_if_fail (self != NULL, NULL); + g_return_val_if_fail (tag != NULL, NULL); return _get_data (self, tag); } @@ -150,22 +175,19 @@ nm_auth_chain_steal_data (NMAuthChain *self, const char *tag) { ChainData *tmp; gpointer value = NULL; - - g_return_val_if_fail (self, NULL); - g_return_val_if_fail (tag, NULL); - - if (!self->data_hash) - return NULL; - - tmp = g_hash_table_lookup (self->data_hash, &tag); - if (!tmp) - return NULL; - - value = tmp->data; - - /* Make sure the destroy handler isn't called when freeing */ - tmp->destroy = NULL; - g_hash_table_remove (self->data_hash, tmp); + void *orig_key; + + g_return_val_if_fail (self != NULL, NULL); + g_return_val_if_fail (tag != NULL, NULL); + + if (g_hash_table_lookup_extended (self->data, tag, &orig_key, (gpointer)&tmp)) { + g_hash_table_steal (self->data, tag); + value = tmp->data; + /* Make sure the destroy handler isn't called when freeing */ + tmp->destroy = NULL; + chain_data_free (tmp); + g_free (orig_key); + } return value; } @@ -175,105 +197,165 @@ nm_auth_chain_set_data (NMAuthChain *self, gpointer data, GDestroyNotify data_destroy) { - g_return_if_fail (self); - g_return_if_fail (tag); - - if (data == NULL) { - if (self->data_hash) - g_hash_table_remove (self->data_hash, &tag); - } else { - if (!self->data_hash) { - self->data_hash = g_hash_table_new_full (nm_pstr_hash, nm_pstr_equal, - NULL, chain_data_free); - } - g_hash_table_add (self->data_hash, - chain_data_new (tag, data, data_destroy)); + g_return_if_fail (self != NULL); + g_return_if_fail (tag != NULL); + + if (data == NULL) + g_hash_table_remove (self->data, tag); + else { + g_hash_table_insert (self->data, + g_strdup (tag), + chain_data_new (data, data_destroy)); } } -/*****************************************************************************/ +gulong +nm_auth_chain_get_data_ulong (NMAuthChain *self, const char *tag) +{ + gulong *data; -NMAuthCallResult -nm_auth_chain_get_result (NMAuthChain *self, const char *permission) + g_return_val_if_fail (self != NULL, 0); + g_return_val_if_fail (tag != NULL, 0); + + data = _get_data (self, tag); + return data ? *data : 0ul; +} + +void +nm_auth_chain_set_data_ulong (NMAuthChain *self, + const char *tag, + gulong data) { - gpointer data; + gulong *ptr; - g_return_val_if_fail (self, NM_AUTH_CALL_RESULT_UNKNOWN); - g_return_val_if_fail (permission, NM_AUTH_CALL_RESULT_UNKNOWN); + g_return_if_fail (self != NULL); + g_return_if_fail (tag != NULL); - data = _get_data (self, permission); - return data ? GPOINTER_TO_UINT (data) : NM_AUTH_CALL_RESULT_UNKNOWN; + ptr = g_malloc (sizeof (*ptr)); + *ptr = data; + nm_auth_chain_set_data (self, tag, ptr, g_free); } NMAuthSubject * nm_auth_chain_get_subject (NMAuthChain *self) { - g_return_val_if_fail (self, NULL); + g_return_val_if_fail (self != NULL, NULL); return self->subject; } -/*****************************************************************************/ +NMAuthCallResult +nm_auth_chain_get_result (NMAuthChain *self, const char *permission) +{ + gpointer data; -static gboolean -auth_chain_finish (NMAuthChain *self) + g_return_val_if_fail (self != NULL, NM_AUTH_CALL_RESULT_UNKNOWN); + g_return_val_if_fail (permission != NULL, NM_AUTH_CALL_RESULT_UNKNOWN); + + data = _get_data (self, permission); + return data ? GPOINTER_TO_UINT (data) : NM_AUTH_CALL_RESULT_UNKNOWN; +} + +static AuthCall * +auth_call_new (NMAuthChain *chain, const char *permission) { - self->done = TRUE; + AuthCall *call; - /* Ensure we stay alive across the callback */ - nm_assert (self->refcount == 1); - self->refcount++; - self->done_func (self, NULL, self->context, self->user_data); - nm_assert (NM_IN_SET (self->refcount, 1, 2)); - nm_auth_chain_destroy (self); - return FALSE; + call = g_slice_new0 (AuthCall); + call->chain = chain; + call->permission = g_strdup (permission); + return call; } static void +auth_call_free (AuthCall *call) +{ + g_free (call->permission); + g_clear_object (&call->cancellable); + g_slice_free (AuthCall, call); +} + +static gboolean auth_call_complete (AuthCall *call) { NMAuthChain *self; - _ASSERT_call (call); + g_return_val_if_fail (call, G_SOURCE_REMOVE); self = call->chain; - nm_assert (!self->done); + g_return_val_if_fail (self, G_SOURCE_REMOVE); + g_return_val_if_fail (g_slist_find (self->calls, call), G_SOURCE_REMOVE); - auth_call_free (call); + self->calls = g_slist_remove (self->calls, call); - if (c_list_is_empty (&self->auth_call_lst_head)) { - /* we are on an idle-handler or a clean call-stack (non-reentrant). */ - auth_chain_finish (self); + if (!self->calls) { + g_assert (!self->idle_id && !self->done); + self->idle_id = g_idle_add (auth_chain_finish, self); } + auth_call_free (call); + return FALSE; } static void -pk_call_cb (NMAuthManager *auth_manager, - NMAuthManagerCallId *call_id, - gboolean is_authorized, - gboolean is_challenge, - GError *error, - gpointer user_data) +auth_call_cancel (gpointer user_data) { - AuthCall *call; - NMAuthCallResult call_result; + AuthCall *call = user_data; - if (g_error_matches (error, G_IO_ERROR, G_IO_ERROR_CANCELLED)) - return; - - call = user_data; - - nm_assert (call->call_id == call_id); + if (nm_clear_g_cancellable (&call->cancellable)) { + /* we don't free call immediately. Instead we cancel the async operation + * and set cancellable to NULL. pk_call_cb() will check for this and + * do the final cleanup. */ + } else { + g_source_remove (call->call_idle_id); + auth_call_free (call); + } +} - call->call_id = NULL; +#if WITH_POLKIT +static void +pk_call_cb (GObject *object, GAsyncResult *result, gpointer user_data) +{ + AuthCall *call = user_data; + GError *error = NULL; + gboolean is_authorized = FALSE, is_challenge = FALSE; + guint call_result = NM_AUTH_CALL_RESULT_UNKNOWN; + + nm_auth_manager_polkit_authority_check_authorization_finish (NM_AUTH_MANAGER (object), + result, + &is_authorized, + &is_challenge, + &error); + + /* If the call is already canceled do nothing */ + if (!call->cancellable) { + nm_log_dbg (LOGD_CORE, "callback already cancelled"); + g_clear_error (&error); + auth_call_free (call); + return; + } - call_result = nm_auth_call_result_eval (is_authorized, is_challenge, error); + if (error) { + /* Don't ruin the chain. Just leave the result unknown. */ + nm_log_warn (LOGD_CORE, "error requesting auth for %s: %s", + call->permission, error->message); + g_clear_error (&error); + } else { + if (is_authorized) { + /* Caller has the permission */ + call_result = NM_AUTH_CALL_RESULT_YES; + } else if (is_challenge) { + /* Caller could authenticate to get the permission */ + call_result = NM_AUTH_CALL_RESULT_AUTH; + } else + call_result = NM_AUTH_CALL_RESULT_NO; + } nm_auth_chain_set_data (call->chain, call->permission, GUINT_TO_POINTER (call_result), NULL); auth_call_complete (call); } +#endif void nm_auth_chain_add_call (NMAuthChain *self, @@ -283,109 +365,81 @@ nm_auth_chain_add_call (NMAuthChain *self, AuthCall *call; NMAuthManager *auth_manager = nm_auth_manager_get (); - g_return_if_fail (self); - g_return_if_fail (self->subject); - g_return_if_fail (!self->done); + g_return_if_fail (self != NULL); g_return_if_fail (permission && *permission); + g_return_if_fail (self->subject); g_return_if_fail (nm_auth_subject_is_unix_process (self->subject) || nm_auth_subject_is_internal (self->subject)); + g_return_if_fail (!self->idle_id && !self->done); - call = g_slice_new0 (AuthCall); - call->chain = self; - call->permission = g_strdup (permission); - c_list_link_tail (&self->auth_call_lst_head, &call->auth_call_lst); - call->call_id = nm_auth_manager_check_authorization (auth_manager, - self->subject, - permission, - allow_interaction, - pk_call_cb, - call); -} - -/*****************************************************************************/ + call = auth_call_new (self, permission); + self->calls = g_slist_append (self->calls, call); -/* Creates the NMAuthSubject automatically */ -NMAuthChain * -nm_auth_chain_new_context (GDBusMethodInvocation *context, - NMAuthChainResultFunc done_func, - gpointer user_data) -{ - NMAuthSubject *subject; - NMAuthChain *chain; - - g_return_val_if_fail (context, NULL); - - subject = nm_auth_subject_new_unix_process_from_context (context); - if (!subject) - return NULL; - - chain = nm_auth_chain_new_subject (subject, - context, - done_func, - user_data); - g_object_unref (subject); - return chain; -} - -/* Requires an NMAuthSubject */ -NMAuthChain * -nm_auth_chain_new_subject (NMAuthSubject *subject, - GDBusMethodInvocation *context, - NMAuthChainResultFunc done_func, - gpointer user_data) -{ - NMAuthChain *self; - - g_return_val_if_fail (NM_IS_AUTH_SUBJECT (subject), NULL); - nm_assert (nm_auth_subject_is_unix_process (subject) || nm_auth_subject_is_internal (subject)); - - self = g_slice_new0 (NMAuthChain); - c_list_init (&self->auth_call_lst_head); - self->refcount = 1; - self->done_func = done_func; - self->user_data = user_data; - self->context = context ? g_object_ref (context) : NULL; - self->subject = g_object_ref (subject); - return self; + if ( nm_auth_subject_is_internal (self->subject) + || nm_auth_subject_get_unix_process_uid (self->subject) == 0 + || !nm_auth_manager_get_polkit_enabled (auth_manager)) { + /* Root user or non-polkit always gets the permission */ + nm_auth_chain_set_data (self, permission, GUINT_TO_POINTER (NM_AUTH_CALL_RESULT_YES), NULL); + call->call_idle_id = g_idle_add ((GSourceFunc) auth_call_complete, call); + } else { + /* Non-root always gets authenticated when using polkit */ +#if WITH_POLKIT + call->cancellable = g_cancellable_new (); + nm_auth_manager_polkit_authority_check_authorization (auth_manager, + self->subject, + permission, + allow_interaction, + call->cancellable, + pk_call_cb, + call); +#else + if (!call->chain->error) { + call->chain->error = g_error_new_literal (NM_MANAGER_ERROR, + NM_MANAGER_ERROR_FAILED, + "Polkit support is disabled at compile time"); + } + call->call_idle_id = g_idle_add ((GSourceFunc) auth_call_complete, call); +#endif + } } /** - * nm_auth_chain_destroy: + * nm_auth_chain_unref: * @self: the auth-chain * - * Destroys the auth-chain. By destroying the auth-chain, you also cancel + * Unrefs the auth-chain. By unrefing the auth-chain, you also cancel * the receipt of the done-callback. IOW, the callback will not be invoked. * - * The only exception is, if may call nm_auth_chain_destroy() from inside + * The only exception is, if you call nm_auth_chain_unref() from inside * the callback. In this case, @self stays alive until the callback returns. - * - * Note that you might only destroy an auth-chain exactly once, and never - * after the callback was handled. */ void -nm_auth_chain_destroy (NMAuthChain *self) +nm_auth_chain_unref (NMAuthChain *self) { - AuthCall *call; - - g_return_if_fail (self); - g_return_if_fail (NM_IN_SET (self->refcount, 1, 2)); + g_return_if_fail (self != NULL); + g_return_if_fail (self->refcount > 0); - if (--self->refcount > 0) + self->refcount--; + if (self->refcount > 0) return; - nm_clear_g_object (&self->subject); - nm_clear_g_object (&self->context); + if (self->idle_id) + g_source_remove (self->idle_id); - while ((call = c_list_first_entry (&self->auth_call_lst_head, AuthCall, auth_call_lst))) - auth_call_free (call); + g_object_unref (self->subject); - nm_clear_pointer (&self->data_hash, g_hash_table_destroy); + if (self->context) + g_object_unref (self->context); + g_slist_free_full (self->calls, auth_call_cancel); + + g_clear_error (&self->error); + g_hash_table_destroy (self->data); + + memset (self, 0, sizeof (NMAuthChain)); g_slice_free (NMAuthChain, self); } -/****************************************************************************** - * utils - *****************************************************************************/ +/************ utils **************/ gboolean nm_auth_is_subject_in_acl (NMConnection *connection, @@ -396,7 +450,7 @@ nm_auth_is_subject_in_acl (NMConnection *connection, const char *user = NULL; gulong uid; - g_return_val_if_fail (connection, FALSE); + g_return_val_if_fail (connection != NULL, FALSE); g_return_val_if_fail (NM_IS_AUTH_SUBJECT (subject), FALSE); g_return_val_if_fail (nm_auth_subject_is_internal (subject) || nm_auth_subject_is_unix_process (subject), FALSE); @@ -410,8 +464,8 @@ nm_auth_is_subject_in_acl (NMConnection *connection, return TRUE; if (!nm_session_monitor_uid_to_user (uid, &user)) { - NM_SET_OUT (out_error_desc, - g_strdup_printf ("Could not determine username for uid %lu", uid)); + if (out_error_desc) + *out_error_desc = g_strdup_printf ("Could not determine username for uid %lu", uid); return FALSE; } @@ -425,31 +479,12 @@ nm_auth_is_subject_in_acl (NMConnection *connection, /* Match the username returned by the session check to a user in the ACL */ if (!nm_setting_connection_permissions_user_allowed (s_con, user)) { - NM_SET_OUT (out_error_desc, - g_strdup_printf ("uid %lu has no permission to perform this operation", uid)); + if (out_error_desc) + *out_error_desc = g_strdup_printf ("uid %lu has no permission to perform this operation", uid); return FALSE; } return TRUE; } -gboolean -nm_auth_is_subject_in_acl_set_error (NMConnection *connection, - NMAuthSubject *subject, - GQuark err_domain, - int err_code, - GError **error) -{ - char *error_desc = NULL; - - nm_assert (!error || !*error); - - if (nm_auth_is_subject_in_acl (connection, - subject, - error ? &error_desc : NULL)) - return TRUE; - g_set_error_literal (error, err_domain, err_code, error_desc); - g_free (error_desc); - return FALSE; -} diff --git a/src/nm-auth-utils.h b/src/nm-auth-utils.h index 5f9823b6..89ed79cc 100644 --- a/src/nm-auth-utils.h +++ b/src/nm-auth-utils.h @@ -23,10 +23,15 @@ #include "nm-connection.h" -#include "nm-auth-manager.h" - typedef struct NMAuthChain NMAuthChain; +typedef enum { + NM_AUTH_CALL_RESULT_UNKNOWN, + NM_AUTH_CALL_RESULT_YES, + NM_AUTH_CALL_RESULT_AUTH, + NM_AUTH_CALL_RESULT_NO, +} NMAuthCallResult; + typedef void (*NMAuthChainResultFunc) (NMAuthChain *chain, GError *error, GDBusMethodInvocation *context, @@ -50,6 +55,12 @@ void nm_auth_chain_set_data (NMAuthChain *chain, gpointer data, GDestroyNotify data_destroy); +void nm_auth_chain_set_data_ulong (NMAuthChain *chain, + const char *tag, + gulong data); + +gulong nm_auth_chain_get_data_ulong (NMAuthChain *chain, const char *tag); + NMAuthCallResult nm_auth_chain_get_result (NMAuthChain *chain, const char *permission); @@ -57,20 +68,14 @@ void nm_auth_chain_add_call (NMAuthChain *chain, const char *permission, gboolean allow_interaction); -void nm_auth_chain_destroy (NMAuthChain *chain); - -NMAuthSubject *nm_auth_chain_get_subject (NMAuthChain *self); +void nm_auth_chain_unref (NMAuthChain *chain); /* Caller must free returned error description */ gboolean nm_auth_is_subject_in_acl (NMConnection *connection, NMAuthSubject *subect, char **out_error_desc); -gboolean nm_auth_is_subject_in_acl_set_error (NMConnection *connection, - NMAuthSubject *subject, - GQuark err_domain, - int err_code, - GError **error); +NMAuthSubject *nm_auth_chain_get_subject (NMAuthChain *self); #endif /* __NETWORKMANAGER_MANAGER_AUTH_H__ */ diff --git a/src/nm-bus-manager.c b/src/nm-bus-manager.c new file mode 100644 index 00000000..f6b86e90 --- /dev/null +++ b/src/nm-bus-manager.c @@ -0,0 +1,1024 @@ +/* -*- Mode: C; tab-width: 4; indent-tabs-mode: t; c-basic-offset: 4 -*- */ +/* NetworkManager -- Network link manager + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation; either version 2 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License along + * with this program; if not, write to the Free Software Foundation, Inc., + * 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA. + * + * Copyright (C) 2006 - 2013 Red Hat, Inc. + * Copyright (C) 2006 - 2008 Novell, Inc. + */ + +#include "nm-default.h" + +#include "nm-bus-manager.h" + +#include <unistd.h> +#include <sys/stat.h> +#include <sys/types.h> +#include <errno.h> +#include <string.h> + +#include "nm-dbus-interface.h" +#include "nm-core-internal.h" +#include "nm-dbus-compat.h" +#include "nm-exported-object.h" +#include "NetworkManagerUtils.h" + +/* The base path for our GDBusObjectManagerServers. They do not contain + * "NetworkManager" because GDBusObjectManagerServer requires that all + * exported objects be *below* the base path, and eg the Manager object + * is the base path already. + */ +#define OBJECT_MANAGER_SERVER_BASE_PATH "/org/freedesktop" + +/*****************************************************************************/ + +enum { + DBUS_CONNECTION_CHANGED = 0, + PRIVATE_CONNECTION_NEW, + PRIVATE_CONNECTION_DISCONNECTED, + NUMBER_OF_SIGNALS, +}; + +static guint signals[NUMBER_OF_SIGNALS]; + +typedef struct { + GDBusConnection *connection; + GDBusObjectManagerServer *obj_manager; + gboolean started; + + GSList *private_servers; + + GDBusProxy *proxy; + + gulong bus_closed_id; + guint reconnect_id; +} NMBusManagerPrivate; + +struct _NMBusManager { + GObject parent; + NMBusManagerPrivate _priv; +}; + +struct _NMBusManagerClass { + GObjectClass parent; +}; + +G_DEFINE_TYPE(NMBusManager, nm_bus_manager, G_TYPE_OBJECT) + +#define NM_BUS_MANAGER_GET_PRIVATE(self) _NM_GET_PRIVATE (self, NMBusManager, NM_IS_BUS_MANAGER) + +/*****************************************************************************/ + +#define _NMLOG_DOMAIN LOGD_CORE +#define _NMLOG(level, ...) __NMLOG_DEFAULT (level, _NMLOG_DOMAIN, "bus-manager", __VA_ARGS__) + +/*****************************************************************************/ + +static gboolean nm_bus_manager_init_bus (NMBusManager *self); +static void nm_bus_manager_cleanup (NMBusManager *self); +static void start_reconnection_timeout (NMBusManager *self); + +/*****************************************************************************/ + +NM_DEFINE_SINGLETON_REGISTER (NMBusManager); + +NMBusManager * +nm_bus_manager_get (void) +{ + if (G_UNLIKELY (!singleton_instance)) { + nm_bus_manager_setup (g_object_new (NM_TYPE_BUS_MANAGER, NULL)); + if (!nm_bus_manager_init_bus (singleton_instance)) + start_reconnection_timeout (singleton_instance); + } + return singleton_instance; +} + +void +nm_bus_manager_setup (NMBusManager *instance) +{ + static char already_setup = FALSE; + + g_assert (NM_IS_BUS_MANAGER (instance)); + g_assert (!already_setup); + g_assert (!singleton_instance); + + already_setup = TRUE; + singleton_instance = instance; + nm_singleton_instance_register (); + _LOGD ("setup %s singleton (%p)", "NMBusManager", singleton_instance); +} + +/*****************************************************************************/ + +typedef struct { + const char *tag; + GQuark detail; + char *address; + GDBusServer *server; + + /* With peer bus connections, we'll get a new connection for each + * client. For each connection we create an ObjectManager for + * that connection to handle exporting our objects. This table + * maps GDBusObjectManager :: 'fake sender'. + * + * Note that even for connections that don't export any objects + * we'll still create GDBusObjectManager since that's where we store + * the pointer to the GDBusConnection. + */ + GHashTable *obj_managers; + + NMBusManager *manager; +} PrivateServer; + +typedef struct { + GDBusConnection *connection; + PrivateServer *server; + gboolean remote_peer_vanished; +} CloseConnectionInfo; + +static gboolean +close_connection_in_idle (gpointer user_data) +{ + CloseConnectionInfo *info = user_data; + PrivateServer *server = info->server; + GHashTableIter iter; + GDBusObjectManagerServer *manager; + + /* Emit this for the manager */ + g_signal_emit (server->manager, + signals[PRIVATE_CONNECTION_DISCONNECTED], + server->detail, + info->connection); + + /* FIXME: there's a bug (754730) in GLib for which the connection + * is marked as closed when the remote peer vanishes but its + * resources are not cleaned up. Work around it by explicitly + * closing the connection in that case. */ + if (info->remote_peer_vanished) + g_dbus_connection_close (info->connection, NULL, NULL, NULL); + + g_hash_table_iter_init (&iter, server->obj_managers); + while (g_hash_table_iter_next (&iter, (gpointer) &manager, NULL)) { + gs_unref_object GDBusConnection *connection = NULL; + + connection = g_dbus_object_manager_server_get_connection (manager); + if (connection == info->connection) { + g_hash_table_iter_remove (&iter); + break; + } + } + + g_object_unref (server->manager); + g_slice_free (CloseConnectionInfo, info); + + return G_SOURCE_REMOVE; +} + +static void +private_server_closed_connection (GDBusConnection *conn, + gboolean remote_peer_vanished, + GError *error, + gpointer user_data) +{ + PrivateServer *s = user_data; + CloseConnectionInfo *info; + + /* Clean up after the connection */ + _LOGD ("(%s) closed connection %p on private socket", s->tag, conn); + + info = g_slice_new0 (CloseConnectionInfo); + info->connection = conn; + info->server = s; + info->remote_peer_vanished = remote_peer_vanished; + + g_object_ref (s->manager); + + /* Delay the close of connection to ensure that D-Bus signals + * are handled */ + g_idle_add (close_connection_in_idle, info); +} + +static gboolean +private_server_new_connection (GDBusServer *server, + GDBusConnection *conn, + gpointer user_data) +{ + PrivateServer *s = user_data; + static guint32 counter = 0; + GDBusObjectManagerServer *manager; + char *sender; + + g_signal_connect (conn, "closed", G_CALLBACK (private_server_closed_connection), s); + + /* Fake a sender since private connections don't have one */ + sender = g_strdup_printf ("x:y:%d", counter++); + + manager = g_dbus_object_manager_server_new (OBJECT_MANAGER_SERVER_BASE_PATH); + g_dbus_object_manager_server_set_connection (manager, conn); + g_hash_table_insert (s->obj_managers, manager, sender); + + _LOGD ("(%s) accepted connection %p on private socket", s->tag, conn); + + /* Emit this for the manager. + * + * It is essential to do this from the "new-connection" signal handler, as + * at that point no messages from the connection are yet processed + * (which avoids races with registering objects). */ + g_signal_emit (s->manager, + signals[PRIVATE_CONNECTION_NEW], + s->detail, + conn, + manager); + return TRUE; +} + +static void +private_server_manager_destroy (GDBusObjectManagerServer *manager) +{ + GDBusConnection *connection = g_dbus_object_manager_server_get_connection (manager); + + if (!g_dbus_connection_is_closed (connection)) + g_dbus_connection_close (connection, NULL, NULL, NULL); + g_dbus_object_manager_server_set_connection (manager, NULL); + g_object_unref (manager); + g_object_unref (connection); +} + +static gboolean +private_server_authorize (GDBusAuthObserver *observer, + GIOStream *stream, + GCredentials *credentials, + gpointer user_data) +{ + return g_credentials_get_unix_user (credentials, NULL) == 0; +} + +static PrivateServer * +private_server_new (const char *path, + const char *tag, + NMBusManager *manager) +{ + PrivateServer *s; + GDBusAuthObserver *auth_observer; + GDBusServer *server; + GError *error = NULL; + char *address, *guid; + + unlink (path); + address = g_strdup_printf ("unix:path=%s", path); + + _LOGD ("(%s) creating private socket %s", tag, address); + + guid = g_dbus_generate_guid (); + auth_observer = g_dbus_auth_observer_new (); + g_signal_connect (auth_observer, "authorize-authenticated-peer", + G_CALLBACK (private_server_authorize), NULL); + server = g_dbus_server_new_sync (address, + G_DBUS_SERVER_FLAGS_NONE, + guid, + auth_observer, + NULL, &error); + g_free (guid); + g_object_unref (auth_observer); + + if (!server) { + _LOGW ("(%s) failed to set up private socket %s: %s", + tag, address, error->message); + g_error_free (error); + g_free (address); + return NULL; + } + + s = g_malloc0 (sizeof (*s)); + s->address = address; + s->server = server; + g_signal_connect (server, "new-connection", + G_CALLBACK (private_server_new_connection), s); + + s->obj_managers = g_hash_table_new_full (g_direct_hash, g_direct_equal, + (GDestroyNotify) private_server_manager_destroy, + g_free); + s->manager = manager; + s->detail = g_quark_from_string (tag); + s->tag = g_quark_to_string (s->detail); + + g_dbus_server_start (server); + + return s; +} + +static void +private_server_free (gpointer ptr) +{ + PrivateServer *s = ptr; + + unlink (s->address); + g_free (s->address); + g_hash_table_destroy (s->obj_managers); + + g_dbus_server_stop (s->server); + g_object_unref (s->server); + + memset (s, 0, sizeof (*s)); + g_free (s); +} + +void +nm_bus_manager_private_server_register (NMBusManager *self, + const char *path, + const char *tag) +{ + NMBusManagerPrivate *priv = NM_BUS_MANAGER_GET_PRIVATE (self); + PrivateServer *s; + GSList *iter; + + g_return_if_fail (self != NULL); + g_return_if_fail (path != NULL); + g_return_if_fail (tag != NULL); + + /* Only one instance per tag; but don't warn */ + for (iter = priv->private_servers; iter; iter = g_slist_next (iter)) { + s = iter->data; + if (g_strcmp0 (tag, s->tag) == 0) + return; + } + + s = private_server_new (path, tag, self); + if (s) + priv->private_servers = g_slist_append (priv->private_servers, s); +} + +static const char * +private_server_get_connection_owner (PrivateServer *s, GDBusConnection *connection) +{ + GHashTableIter iter; + GDBusObjectManagerServer *manager; + const char *owner; + + g_return_val_if_fail (s != NULL, NULL); + g_return_val_if_fail (connection != NULL, NULL); + + g_hash_table_iter_init (&iter, s->obj_managers); + while (g_hash_table_iter_next (&iter, (gpointer) &manager, (gpointer) &owner)) { + gs_unref_object GDBusConnection *c = NULL; + + c = g_dbus_object_manager_server_get_connection (manager); + if (c == connection) + return owner; + } + return NULL; +} + +static GDBusConnection * +private_server_get_connection_by_owner (PrivateServer *s, const char *owner) +{ + GHashTableIter iter; + GDBusObjectManagerServer *manager; + const char *priv_sender; + + g_hash_table_iter_init (&iter, s->obj_managers); + while (g_hash_table_iter_next (&iter, (gpointer) &manager, (gpointer) &priv_sender)) { + if (g_strcmp0 (owner, priv_sender) == 0) + return g_dbus_object_manager_server_get_connection (manager); + } + return NULL; +} + +/*****************************************************************************/ + +static gboolean +_bus_get_unix_pid (NMBusManager *self, + const char *sender, + gulong *out_pid, + GError **error) +{ + guint32 unix_pid = G_MAXUINT32; + gs_unref_variant GVariant *ret = NULL; + + ret = _nm_dbus_proxy_call_sync (NM_BUS_MANAGER_GET_PRIVATE (self)->proxy, + "GetConnectionUnixProcessID", + g_variant_new ("(s)", sender), + G_VARIANT_TYPE ("(u)"), + G_DBUS_CALL_FLAGS_NONE, 2000, + NULL, error); + if (!ret) + return FALSE; + + g_variant_get (ret, "(u)", &unix_pid); + + *out_pid = (gulong) unix_pid; + return TRUE; +} + +static gboolean +_bus_get_unix_user (NMBusManager *self, + const char *sender, + gulong *out_user, + GError **error) +{ + guint32 unix_uid = G_MAXUINT32; + gs_unref_variant GVariant *ret = NULL; + + ret = _nm_dbus_proxy_call_sync (NM_BUS_MANAGER_GET_PRIVATE (self)->proxy, + "GetConnectionUnixUser", + g_variant_new ("(s)", sender), + G_VARIANT_TYPE ("(u)"), + G_DBUS_CALL_FLAGS_NONE, 2000, + NULL, error); + if (!ret) + return FALSE; + + g_variant_get (ret, "(u)", &unix_uid); + + *out_user = (gulong) unix_uid; + return TRUE; +} + +/** + * _get_caller_info(): + * + * Given a GDBus method invocation, or a GDBusConnection + GDBusMessage, + * return the sender and the UID of the sender. + */ +static gboolean +_get_caller_info (NMBusManager *self, + GDBusMethodInvocation *context, + GDBusConnection *connection, + GDBusMessage *message, + char **out_sender, + gulong *out_uid, + gulong *out_pid) +{ + NMBusManagerPrivate *priv = NM_BUS_MANAGER_GET_PRIVATE (self); + const char *sender; + GSList *iter; + + if (context) { + connection = g_dbus_method_invocation_get_connection (context); + + /* only bus connections will have a sender */ + sender = g_dbus_method_invocation_get_sender (context); + } else { + g_assert (message); + sender = g_dbus_message_get_sender (message); + } + g_assert (connection); + + if (!sender) { + /* Might be a private connection, for which we fake a sender */ + for (iter = priv->private_servers; iter; iter = g_slist_next (iter)) { + PrivateServer *s = iter->data; + + sender = private_server_get_connection_owner (s, connection); + if (sender) { + if (out_uid) + *out_uid = 0; + if (out_sender) + *out_sender = g_strdup (sender); + if (out_pid) { + GCredentials *creds; + + creds = g_dbus_connection_get_peer_credentials (connection); + if (creds) { + pid_t pid; + + pid = g_credentials_get_unix_pid (creds, NULL); + if (pid == -1) + *out_pid = G_MAXULONG; + else + *out_pid = pid; + } else + *out_pid = G_MAXULONG; + } + return TRUE; + } + } + return FALSE; + } + + /* Bus connections always have a sender */ + g_assert (sender); + if (out_uid) { + if (!_bus_get_unix_user (self, sender, out_uid, NULL)) { + *out_uid = G_MAXULONG; + return FALSE; + } + } + + if (out_pid) { + if (!_bus_get_unix_pid (self, sender, out_pid, NULL)) { + *out_pid = G_MAXULONG; + return FALSE; + } + } + + if (out_sender) + *out_sender = g_strdup (sender); + + return TRUE; +} + +gboolean +nm_bus_manager_get_caller_info (NMBusManager *self, + GDBusMethodInvocation *context, + char **out_sender, + gulong *out_uid, + gulong *out_pid) +{ + return _get_caller_info (self, context, NULL, NULL, out_sender, out_uid, out_pid); +} + +gboolean +nm_bus_manager_get_caller_info_from_message (NMBusManager *self, + GDBusConnection *connection, + GDBusMessage *message, + char **out_sender, + gulong *out_uid, + gulong *out_pid) +{ + return _get_caller_info (self, NULL, connection, message, out_sender, out_uid, out_pid); +} + +/** + * nm_bus_manager_ensure_uid: + * + * @self: bus manager instance + * @context: D-Bus method invocation + * @uid: a user-id + * @error_domain: error domain to return on failure + * @error_code: error code to return on failure + * + * Retrieves the uid of the D-Bus method caller and + * checks that it matches @uid, unless @uid is G_MAXULONG. + * In case of failure the function returns FALSE and finishes + * handling the D-Bus method with an error. + * + * Returns: %TRUE if the check succeeded, %FALSE otherwise + */ +gboolean +nm_bus_manager_ensure_uid (NMBusManager *self, + GDBusMethodInvocation *context, + gulong uid, + GQuark error_domain, + int error_code) +{ + gulong caller_uid; + GError *error = NULL; + + g_return_val_if_fail (NM_IS_BUS_MANAGER (self), FALSE); + g_return_val_if_fail (G_IS_DBUS_METHOD_INVOCATION (context), FALSE); + + if (!nm_bus_manager_get_caller_info (self, context, NULL, &caller_uid, NULL)) { + error = g_error_new_literal (error_domain, + error_code, + "Unable to determine request UID."); + g_dbus_method_invocation_take_error (context, error); + return FALSE; + } + + if (uid != G_MAXULONG && caller_uid != uid) { + error = g_error_new_literal (error_domain, + error_code, + "Permission denied"); + g_dbus_method_invocation_take_error (context, error); + return FALSE; + } + + return TRUE; +} + +gboolean +nm_bus_manager_get_unix_user (NMBusManager *self, + const char *sender, + gulong *out_uid) +{ + NMBusManagerPrivate *priv = NM_BUS_MANAGER_GET_PRIVATE (self); + GSList *iter; + GError *error = NULL; + + g_return_val_if_fail (sender != NULL, FALSE); + g_return_val_if_fail (out_uid != NULL, FALSE); + + /* Check if it's a private connection sender, which we fake */ + for (iter = priv->private_servers; iter; iter = iter->next) { + gs_unref_object GDBusConnection *connection = NULL; + + connection = private_server_get_connection_by_owner (iter->data, sender); + if (connection) { + *out_uid = 0; + return TRUE; + } + } + + /* Otherwise, a bus connection */ + if (!_bus_get_unix_user (self, sender, out_uid, &error)) { + _LOGW ("failed to get unix user for dbus sender '%s': %s", + sender, error->message); + g_error_free (error); + return FALSE; + } + + return TRUE; +} + +/*****************************************************************************/ + +/* Only cleanup a specific dbus connection, not all our private data */ +static void +nm_bus_manager_cleanup (NMBusManager *self) +{ + NMBusManagerPrivate *priv = NM_BUS_MANAGER_GET_PRIVATE (self); + + g_clear_object (&priv->proxy); + + if (priv->connection) { + g_signal_handler_disconnect (priv->connection, priv->bus_closed_id); + priv->bus_closed_id = 0; + g_clear_object (&priv->connection); + } + + g_dbus_object_manager_server_set_connection (priv->obj_manager, NULL); + priv->started = FALSE; +} + +static gboolean +nm_bus_manager_reconnect (gpointer user_data) +{ + NMBusManager *self = NM_BUS_MANAGER (user_data); + NMBusManagerPrivate *priv = NM_BUS_MANAGER_GET_PRIVATE (self); + + g_assert (self != NULL); + + if (nm_bus_manager_init_bus (self)) { + if (nm_bus_manager_start_service (self)) { + _LOGI ("reconnected to the system bus"); + g_signal_emit (self, signals[DBUS_CONNECTION_CHANGED], + 0, priv->connection); + priv->reconnect_id = 0; + return FALSE; + } + } + + /* Try again */ + nm_bus_manager_cleanup (self); + return TRUE; +} + +static void +start_reconnection_timeout (NMBusManager *self) +{ + NMBusManagerPrivate *priv = NM_BUS_MANAGER_GET_PRIVATE (self); + + if (priv->reconnect_id) + g_source_remove (priv->reconnect_id); + + /* Schedule timeout for reconnection attempts */ + priv->reconnect_id = g_timeout_add_seconds (3, nm_bus_manager_reconnect, self); +} + +static void +closed_cb (GDBusConnection *connection, + gboolean remote_peer_vanished, + GError *error, + gpointer user_data) +{ + NMBusManager *self = NM_BUS_MANAGER (user_data); + + /* Clean up existing connection */ + _LOGW ("disconnected by the system bus"); + + nm_bus_manager_cleanup (self); + + g_signal_emit (G_OBJECT (self), signals[DBUS_CONNECTION_CHANGED], 0, NULL); + + start_reconnection_timeout (self); +} + +static gboolean +nm_bus_manager_init_bus (NMBusManager *self) +{ + NMBusManagerPrivate *priv = NM_BUS_MANAGER_GET_PRIVATE (self); + GError *error = NULL; + + if (priv->connection) { + _LOGW ("DBus Manager already has a valid connection"); + return FALSE; + } + + priv->connection = g_bus_get_sync (G_BUS_TYPE_SYSTEM, NULL, &error); + if (!priv->connection) { + /* Log with 'info' severity; there won't be a bus daemon in minimal + * environments (eg, initrd) where we only want to use the private + * socket. + */ + _LOGI ("could not connect to the system bus (%s); only the " + "private D-Bus socket will be available", + error->message); + g_error_free (error); + return FALSE; + } + + g_dbus_connection_set_exit_on_close (priv->connection, FALSE); + priv->bus_closed_id = g_signal_connect (priv->connection, "closed", + G_CALLBACK (closed_cb), self); + + priv->proxy = g_dbus_proxy_new_sync (priv->connection, + G_DBUS_PROXY_FLAGS_DO_NOT_LOAD_PROPERTIES | + G_DBUS_PROXY_FLAGS_DO_NOT_CONNECT_SIGNALS, + NULL, + DBUS_SERVICE_DBUS, + DBUS_PATH_DBUS, + DBUS_INTERFACE_DBUS, + NULL, &error); + if (!priv->proxy) { + g_clear_object (&priv->connection); + _LOGW ("could not create org.freedesktop.DBus proxy (%s); only the " + "private D-Bus socket will be available", + error->message); + g_error_free (error); + return FALSE; + } + + g_dbus_object_manager_server_set_connection (priv->obj_manager, priv->connection); + return TRUE; +} + +/* Register our service on the bus; shouldn't be called until + * all necessary message handlers have been registered, because + * when we register on the bus, clients may start to call. + */ +gboolean +nm_bus_manager_start_service (NMBusManager *self) +{ + NMBusManagerPrivate *priv; + gs_unref_variant GVariant *ret = NULL; + int result; + GError *err = NULL; + + g_return_val_if_fail (NM_IS_BUS_MANAGER (self), FALSE); + + priv = NM_BUS_MANAGER_GET_PRIVATE (self); + + if (priv->started) { + _LOGE ("service has already started"); + return FALSE; + } + + /* Pointless to request a name when we aren't connected to the bus */ + if (!priv->proxy) + return FALSE; + + ret = _nm_dbus_proxy_call_sync (priv->proxy, + "RequestName", + g_variant_new ("(su)", + NM_DBUS_SERVICE, + DBUS_NAME_FLAG_DO_NOT_QUEUE), + G_VARIANT_TYPE ("(u)"), + G_DBUS_CALL_FLAGS_NONE, -1, + NULL, &err); + if (!ret) { + _LOGE ("could not acquire the NetworkManager service: '%s'", err->message); + g_error_free (err); + return FALSE; + } + + g_variant_get (ret, "(u)", &result); + + if (result != DBUS_REQUEST_NAME_REPLY_PRIMARY_OWNER) { + _LOGE ("could not acquire the NetworkManager service as it is already taken"); + return FALSE; + } + + priv->started = TRUE; + return priv->started; +} + +GDBusConnection * +nm_bus_manager_get_connection (NMBusManager *self) +{ + g_return_val_if_fail (NM_IS_BUS_MANAGER (self), NULL); + + return NM_BUS_MANAGER_GET_PRIVATE (self)->connection; +} + +void +nm_bus_manager_register_object (NMBusManager *self, + GDBusObjectSkeleton *object) +{ + NMBusManagerPrivate *priv; + + g_return_if_fail (NM_IS_BUS_MANAGER (self)); + g_return_if_fail (NM_IS_EXPORTED_OBJECT (object)); + + priv = NM_BUS_MANAGER_GET_PRIVATE (self); + +#if NM_MORE_ASSERTS >= 1 +#if GLIB_CHECK_VERSION(2,34,0) + if (g_dbus_object_manager_server_is_exported (priv->obj_manager, object)) + g_return_if_reached (); +#endif +#endif + + g_dbus_object_manager_server_export (priv->obj_manager, object); +} + +GDBusObjectSkeleton * +nm_bus_manager_get_registered_object (NMBusManager *self, + const char *path) +{ + NMBusManagerPrivate *priv = NM_BUS_MANAGER_GET_PRIVATE (self); + + return G_DBUS_OBJECT_SKELETON (g_dbus_object_manager_get_object ((GDBusObjectManager *) priv->obj_manager, path)); +} + +void +nm_bus_manager_unregister_object (NMBusManager *self, + GDBusObjectSkeleton *object) +{ + NMBusManagerPrivate *priv; + gs_free char *path = NULL; + + g_return_if_fail (NM_IS_BUS_MANAGER (self)); + g_return_if_fail (NM_IS_EXPORTED_OBJECT (object)); + + priv = NM_BUS_MANAGER_GET_PRIVATE (self); + +#if NM_MORE_ASSERTS >= 1 +#if GLIB_CHECK_VERSION(2,34,0) + if (!g_dbus_object_manager_server_is_exported (priv->obj_manager, object)) + g_return_if_reached (); +#endif +#endif + + g_object_get (G_OBJECT (object), "g-object-path", &path, NULL); + g_return_if_fail (path != NULL); + + g_dbus_object_manager_server_unexport (priv->obj_manager, path); +} + +const char * +nm_bus_manager_connection_get_private_name (NMBusManager *self, + GDBusConnection *connection) +{ + NMBusManagerPrivate *priv; + GSList *iter; + const char *owner; + + g_return_val_if_fail (NM_IS_BUS_MANAGER (self), FALSE); + g_return_val_if_fail (G_IS_DBUS_CONNECTION (connection), FALSE); + + if (g_dbus_connection_get_unique_name (connection)) { + /* Shortcut. The connection is not a private connection. */ + return NULL; + } + + priv = NM_BUS_MANAGER_GET_PRIVATE (self); + for (iter = priv->private_servers; iter; iter = g_slist_next (iter)) { + PrivateServer *s = iter->data; + + if ((owner = private_server_get_connection_owner (s, connection))) + return owner; + } + g_return_val_if_reached (NULL); +} + +/** + * nm_bus_manager_new_proxy: + * @self: the #NMBusManager + * @connection: the GDBusConnection for which this connection should be created + * @proxy_type: the type of #GDBusProxy to create + * @name: any name on the message bus + * @path: name of the object instance to call methods on + * @iface: name of the interface to call methods on + * + * Creates a new proxy (of type @proxy_type) for a name on a given bus. Since + * the process which called the D-Bus method could be coming from a private + * connection or the system bus connection, different proxies must be created + * for each case. This function abstracts that. + * + * Returns: a #GDBusProxy capable of calling D-Bus methods of the calling process + */ +GDBusProxy * +nm_bus_manager_new_proxy (NMBusManager *self, + GDBusConnection *connection, + GType proxy_type, + const char *name, + const char *path, + const char *iface) +{ + const char *owner; + GDBusProxy *proxy; + GError *error = NULL; + + g_return_val_if_fail (g_type_is_a (proxy_type, G_TYPE_DBUS_PROXY), NULL); + g_return_val_if_fail (G_IS_DBUS_CONNECTION (connection), NULL); + + /* Might be a private connection, for which @name is fake */ + owner = nm_bus_manager_connection_get_private_name (self, connection); + if (owner) { + g_return_val_if_fail (!g_strcmp0 (owner, name), NULL); + name = NULL; + } + + proxy = g_initable_new (proxy_type, NULL, &error, + "g-connection", connection, + "g-flags", (G_DBUS_PROXY_FLAGS_DO_NOT_LOAD_PROPERTIES | + G_DBUS_PROXY_FLAGS_DO_NOT_CONNECT_SIGNALS), + "g-name", name, + "g-object-path", path, + "g-interface-name", iface, + NULL); + if (!proxy) { + _LOGW ("could not create proxy for %s on connection %s: %s", + iface, name, error->message); + g_error_free (error); + } + return proxy; +} + +/*****************************************************************************/ + +static void +nm_bus_manager_init (NMBusManager *self) +{ + NMBusManagerPrivate *priv = NM_BUS_MANAGER_GET_PRIVATE (self); + + priv->obj_manager = g_dbus_object_manager_server_new (OBJECT_MANAGER_SERVER_BASE_PATH); +} + +static void +dispose (GObject *object) +{ + NMBusManager *self = NM_BUS_MANAGER (object); + NMBusManagerPrivate *priv = NM_BUS_MANAGER_GET_PRIVATE (self); + GList *exported, *iter; + + g_slist_free_full (priv->private_servers, private_server_free); + priv->private_servers = NULL; + + nm_bus_manager_cleanup (self); + + if (priv->obj_manager) { + /* The ObjectManager owns the last reference to many exported + * objects, and when that reference is dropped the objects unregister + * themselves via nm_bus_manager_unregister_object(). By that time + * priv->obj_manager is already NULL and that prints warnings. Unregister + * them before clearing the ObjectManager instead. + */ + exported = g_dbus_object_manager_get_objects ((GDBusObjectManager *) priv->obj_manager); + for (iter = exported; iter; iter = iter->next) { + nm_bus_manager_unregister_object (self, iter->data); + g_object_unref (iter->data); + } + g_list_free (exported); + g_clear_object (&priv->obj_manager); + } + + nm_clear_g_source (&priv->reconnect_id); + + G_OBJECT_CLASS (nm_bus_manager_parent_class)->dispose (object); +} + +static void +nm_bus_manager_class_init (NMBusManagerClass *klass) +{ + GObjectClass *object_class = G_OBJECT_CLASS (klass); + + object_class->dispose = dispose; + + signals[DBUS_CONNECTION_CHANGED] = + g_signal_new (NM_BUS_MANAGER_DBUS_CONNECTION_CHANGED, + G_OBJECT_CLASS_TYPE (object_class), + G_SIGNAL_RUN_LAST, + 0, NULL, NULL, NULL, + G_TYPE_NONE, 1, G_TYPE_POINTER); + + signals[PRIVATE_CONNECTION_NEW] = + g_signal_new (NM_BUS_MANAGER_PRIVATE_CONNECTION_NEW, + G_OBJECT_CLASS_TYPE (object_class), + G_SIGNAL_RUN_LAST | G_SIGNAL_DETAILED, + 0, NULL, NULL, NULL, + G_TYPE_NONE, 2, G_TYPE_DBUS_CONNECTION, G_TYPE_DBUS_OBJECT_MANAGER_SERVER); + + signals[PRIVATE_CONNECTION_DISCONNECTED] = + g_signal_new (NM_BUS_MANAGER_PRIVATE_CONNECTION_DISCONNECTED, + G_OBJECT_CLASS_TYPE (object_class), + G_SIGNAL_RUN_LAST | G_SIGNAL_DETAILED, + 0, NULL, NULL, NULL, + G_TYPE_NONE, 1, G_TYPE_POINTER); +} + + + diff --git a/src/nm-bus-manager.h b/src/nm-bus-manager.h new file mode 100644 index 00000000..153f7cdc --- /dev/null +++ b/src/nm-bus-manager.h @@ -0,0 +1,93 @@ +/* -*- Mode: C; tab-width: 4; indent-tabs-mode: t; c-basic-offset: 4 -*- */ +/* NetworkManager -- Network link manager + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation; either version 2 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License along + * with this program; if not, write to the Free Software Foundation, Inc., + * 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA. + * + * Copyright (C) 2006 - 2008 Red Hat, Inc. + * Copyright (C) 2006 - 2008 Novell, Inc. + */ + +#ifndef __NM_BUS_MANAGER_H__ +#define __NM_BUS_MANAGER_H__ + +#define NM_TYPE_BUS_MANAGER (nm_bus_manager_get_type ()) +#define NM_BUS_MANAGER(o) (G_TYPE_CHECK_INSTANCE_CAST ((o), NM_TYPE_BUS_MANAGER, NMBusManager)) +#define NM_BUS_MANAGER_CLASS(k) (G_TYPE_CHECK_CLASS_CAST((k), NM_TYPE_BUS_MANAGER, NMBusManagerClass)) +#define NM_IS_BUS_MANAGER(o) (G_TYPE_CHECK_INSTANCE_TYPE ((o), NM_TYPE_BUS_MANAGER)) +#define NM_IS_BUS_MANAGER_CLASS(k) (G_TYPE_CHECK_CLASS_TYPE ((k), NM_TYPE_BUS_MANAGER)) +#define NM_BUS_MANAGER_GET_CLASS(o) (G_TYPE_INSTANCE_GET_CLASS ((o), NM_TYPE_BUS_MANAGER, NMBusManagerClass)) + +#define NM_BUS_MANAGER_DBUS_CONNECTION_CHANGED "dbus-connection-changed" +#define NM_BUS_MANAGER_PRIVATE_CONNECTION_NEW "private-connection-new" +#define NM_BUS_MANAGER_PRIVATE_CONNECTION_DISCONNECTED "private-connection-disconnected" + +typedef struct _NMBusManagerClass NMBusManagerClass; + +GType nm_bus_manager_get_type (void); + +NMBusManager * nm_bus_manager_get (void); +void nm_bus_manager_setup (NMBusManager *instance); + +gboolean nm_bus_manager_start_service (NMBusManager *self); + +GDBusConnection * nm_bus_manager_get_connection (NMBusManager *self); + +gboolean nm_bus_manager_get_caller_info (NMBusManager *self, + GDBusMethodInvocation *context, + char **out_sender, + gulong *out_uid, + gulong *out_pid); + +gboolean nm_bus_manager_ensure_uid (NMBusManager *self, + GDBusMethodInvocation *context, + gulong uid, + GQuark error_domain, + int error_code); + +const char *nm_bus_manager_connection_get_private_name (NMBusManager *self, + GDBusConnection *connection); + +gboolean nm_bus_manager_get_unix_user (NMBusManager *self, + const char *sender, + gulong *out_uid); + +gboolean nm_bus_manager_get_caller_info_from_message (NMBusManager *self, + GDBusConnection *connection, + GDBusMessage *message, + char **out_sender, + gulong *out_uid, + gulong *out_pid); + +void nm_bus_manager_register_object (NMBusManager *self, + GDBusObjectSkeleton *object); + +void nm_bus_manager_unregister_object (NMBusManager *self, + GDBusObjectSkeleton *object); + +GDBusObjectSkeleton *nm_bus_manager_get_registered_object (NMBusManager *self, + const char *path); + +void nm_bus_manager_private_server_register (NMBusManager *self, + const char *path, + const char *tag); + +GDBusProxy *nm_bus_manager_new_proxy (NMBusManager *self, + GDBusConnection *connection, + GType proxy_type, + const char *name, + const char *path, + const char *iface); + +#endif /* __NM_BUS_MANAGER_H__ */ diff --git a/src/nm-checkpoint-manager.c b/src/nm-checkpoint-manager.c index 8ba19db9..6da220c4 100644 --- a/src/nm-checkpoint-manager.c +++ b/src/nm-checkpoint-manager.c @@ -26,16 +26,16 @@ #include "nm-connection.h" #include "nm-core-utils.h" #include "devices/nm-device.h" +#include "nm-exported-object.h" #include "nm-manager.h" #include "nm-utils.h" -#include "c-list/src/c-list.h" /*****************************************************************************/ struct _NMCheckpointManager { NMManager *_manager; - GParamSpec *property_spec; - CList checkpoints_lst_head; + GHashTable *checkpoints; + guint rollback_timeout_id; }; #define GET_MANAGER(self) \ @@ -56,67 +56,80 @@ struct _NMCheckpointManager { /*****************************************************************************/ -static void -notify_checkpoints (NMCheckpointManager *self) { - g_object_notify_by_pspec ((GObject *) GET_MANAGER (self), - self->property_spec); -} +static void update_rollback_timeout (NMCheckpointManager *self); static void -destroy_checkpoint (NMCheckpointManager *self, NMCheckpoint *checkpoint, gboolean log_destroy) +checkpoint_destroy (gpointer checkpoint) { - nm_assert (NM_IS_CHECKPOINT (checkpoint)); - nm_assert (nm_dbus_object_is_exported (NM_DBUS_OBJECT (checkpoint))); - nm_assert (c_list_contains (&self->checkpoints_lst_head, &checkpoint->checkpoints_lst)); - - nm_checkpoint_set_timeout_callback (checkpoint, NULL, NULL); - - c_list_unlink (&checkpoint->checkpoints_lst); - - if (log_destroy) - nm_checkpoint_log_destroy (checkpoint); - - notify_checkpoints (self); - - nm_dbus_object_unexport (NM_DBUS_OBJECT (checkpoint)); - g_object_unref (checkpoint); + nm_exported_object_unexport (NM_EXPORTED_OBJECT (checkpoint)); + g_object_unref (G_OBJECT (checkpoint)); } -static GVariant * -rollback_checkpoint (NMCheckpointManager *self, NMCheckpoint *checkpoint) +static gboolean +rollback_timeout_cb (NMCheckpointManager *self) { + NMCheckpoint *checkpoint; + GHashTableIter iter; GVariant *result; - const CList *iter; + gint64 ts, now; + + now = nm_utils_get_monotonic_timestamp_ms (); + + g_hash_table_iter_init (&iter, self->checkpoints); + while (g_hash_table_iter_next (&iter, NULL, (gpointer *) &checkpoint)) { + ts = nm_checkpoint_get_rollback_ts (checkpoint); + if (ts && ts <= now) { + result = nm_checkpoint_rollback (checkpoint); + if (result) + g_variant_unref (result); + g_hash_table_iter_remove (&iter); + } + } - nm_assert (c_list_contains (&self->checkpoints_lst_head, &checkpoint->checkpoints_lst)); + self->rollback_timeout_id = 0; + update_rollback_timeout (self); - /* we destroy first all overlapping checkpoints that are younger/newer. */ - for (iter = checkpoint->checkpoints_lst.next; - iter != &self->checkpoints_lst_head; - ) { - NMCheckpoint *cp = c_list_entry (iter, NMCheckpoint, checkpoints_lst); + return G_SOURCE_REMOVE; +} - iter = iter->next; - if (nm_checkpoint_includes_devices_of (cp, checkpoint)) { - /* the younger checkpoint has overlapping devices and gets obsoleted. - * Destroy it. */ - destroy_checkpoint (self, cp, TRUE); - } +static void +update_rollback_timeout (NMCheckpointManager *self) +{ + NMCheckpoint *checkpoint; + GHashTableIter iter; + gint64 ts, delta, next = G_MAXINT64; + + g_hash_table_iter_init (&iter, self->checkpoints); + while (g_hash_table_iter_next (&iter, NULL, (gpointer *) &checkpoint)) { + ts = nm_checkpoint_get_rollback_ts (checkpoint); + if (ts && ts < next) + next = ts; } - result = nm_checkpoint_rollback (checkpoint); - destroy_checkpoint (self, checkpoint, FALSE); - return result; + nm_clear_g_source (&self->rollback_timeout_id); + + if (next != G_MAXINT64) { + delta = MAX (next - nm_utils_get_monotonic_timestamp_ms (), 0); + self->rollback_timeout_id = g_timeout_add (delta, + (GSourceFunc) rollback_timeout_cb, + self); + _LOGT ("update timeout: next check in %" G_GINT64_FORMAT " ms", delta); + } } -static void -rollback_timeout_cb (NMCheckpoint *checkpoint, - gpointer user_data) +static NMCheckpoint * +find_checkpoint_for_device (NMCheckpointManager *self, NMDevice *device) { - NMCheckpointManager *self = user_data; - gs_unref_variant GVariant *result = NULL; + GHashTableIter iter; + NMCheckpoint *checkpoint; - result = rollback_checkpoint (self, checkpoint); + g_hash_table_iter_init (&iter, self->checkpoints); + while (g_hash_table_iter_next (&iter, NULL, (gpointer *) &checkpoint)) { + if (nm_checkpoint_includes_device (checkpoint, device)) + return checkpoint; + } + + return NULL; } NMCheckpoint * @@ -128,200 +141,152 @@ nm_checkpoint_manager_create (NMCheckpointManager *self, { NMManager *manager; NMCheckpoint *checkpoint; + const char * const *path; gs_unref_ptrarray GPtrArray *devices = NULL; NMDevice *device; + const char *checkpoint_path; + gs_free const char **device_paths_free = NULL; + guint i; g_return_val_if_fail (self, FALSE); g_return_val_if_fail (!error || !*error, FALSE); manager = GET_MANAGER (self); - devices = g_ptr_array_new (); - if (!device_paths || !device_paths[0]) { - const CList *tmp_lst; - - nm_manager_for_each_device (manager, device, tmp_lst) { - /* FIXME: there is no strong reason to skip over unrealized devices. - * Also, NMCheckpoint anticipates to handle them (in parts). */ + const char *device_path; + const GSList *iter; + GPtrArray *paths; + + paths = g_ptr_array_new (); + for (iter = nm_manager_get_devices (manager); + iter; + iter = g_slist_next (iter)) { + device = NM_DEVICE (iter->data); if (!nm_device_is_real (device)) continue; - nm_assert (nm_dbus_object_get_path (NM_DBUS_OBJECT (device))); - g_ptr_array_add (devices, device); + device_path = nm_exported_object_get_path (NM_EXPORTED_OBJECT (device)); + if (device_path) + g_ptr_array_add (paths, (gpointer) device_path); } + g_ptr_array_add (paths, NULL); + device_paths_free = (const char **) g_ptr_array_free (paths, FALSE); + device_paths = (const char *const *) device_paths_free; } else if (NM_FLAGS_HAS (flags, NM_CHECKPOINT_CREATE_FLAG_DISCONNECT_NEW_DEVICES)) { g_set_error_literal (error, NM_MANAGER_ERROR, NM_MANAGER_ERROR_INVALID_ARGUMENTS, "the DISCONNECT_NEW_DEVICES flag can only be used with an empty device list"); return NULL; - } else { - for (; *device_paths; device_paths++) { - device = nm_manager_get_device_by_path (manager, *device_paths); - if (!device) { - g_set_error (error, NM_MANAGER_ERROR, NM_MANAGER_ERROR_UNKNOWN_DEVICE, - "device %s does not exist", *device_paths); - return NULL; - } - if (!nm_device_is_real (device)) { - g_set_error (error, NM_MANAGER_ERROR, NM_MANAGER_ERROR_UNKNOWN_DEVICE, - "device %s is not realized", *device_paths); - return NULL; - } - g_ptr_array_add (devices, device); - } } - if (!devices->len) { - g_set_error_literal (error, - NM_MANAGER_ERROR, - NM_MANAGER_ERROR_INVALID_ARGUMENTS, - "no device available"); - return NULL; + devices = g_ptr_array_new (); + for (path = device_paths; *path; path++) { + device = nm_manager_get_device_by_path (manager, *path); + if (!device) { + g_set_error (error, NM_MANAGER_ERROR, NM_MANAGER_ERROR_UNKNOWN_DEVICE, + "device %s does not exist", *path); + return NULL; + } + g_ptr_array_add (devices, device); } - if (NM_FLAGS_HAS (flags, NM_CHECKPOINT_CREATE_FLAG_DESTROY_ALL)) - nm_checkpoint_manager_destroy_all (self); - else if (!NM_FLAGS_HAS (flags, NM_CHECKPOINT_CREATE_FLAG_ALLOW_OVERLAPPING)) { - c_list_for_each_entry (checkpoint, &self->checkpoints_lst_head, checkpoints_lst) { - device = nm_checkpoint_includes_devices (checkpoint, (NMDevice *const*) devices->pdata, devices->len); - if (device) { + if (!NM_FLAGS_HAS (flags, NM_CHECKPOINT_CREATE_FLAG_DESTROY_ALL)) { + for (i = 0; i < devices->len; i++) { + device = devices->pdata[i]; + checkpoint = find_checkpoint_for_device (self, device); + if (checkpoint) { g_set_error (error, NM_MANAGER_ERROR, NM_MANAGER_ERROR_INVALID_ARGUMENTS, "device '%s' is already included in checkpoint %s", nm_device_get_iface (device), - nm_dbus_object_get_path (NM_DBUS_OBJECT (checkpoint))); + nm_exported_object_get_path (NM_EXPORTED_OBJECT (checkpoint))); return NULL; } } } - checkpoint = nm_checkpoint_new (manager, devices, rollback_timeout, flags); + checkpoint = nm_checkpoint_new (manager, devices, rollback_timeout, flags, error); + if (!checkpoint) + return NULL; + + if (NM_FLAGS_HAS (flags, NM_CHECKPOINT_CREATE_FLAG_DESTROY_ALL)) + g_hash_table_remove_all (self->checkpoints); + + nm_exported_object_export (NM_EXPORTED_OBJECT (checkpoint)); + checkpoint_path = nm_exported_object_get_path (NM_EXPORTED_OBJECT (checkpoint)); - nm_dbus_object_export (NM_DBUS_OBJECT (checkpoint)); + if (!nm_g_hash_table_insert (self->checkpoints, + (gpointer) checkpoint_path, + checkpoint)) + g_return_val_if_reached (NULL); + + update_rollback_timeout (self); - nm_checkpoint_set_timeout_callback (checkpoint, rollback_timeout_cb, self); - c_list_link_tail (&self->checkpoints_lst_head, &checkpoint->checkpoints_lst); - notify_checkpoints (self); return checkpoint; } -void -nm_checkpoint_manager_destroy_all (NMCheckpointManager *self) +gboolean +nm_checkpoint_manager_destroy_all (NMCheckpointManager *self, + GError **error) { - NMCheckpoint *checkpoint; + g_return_val_if_fail (self, FALSE); - g_return_if_fail (self); + g_hash_table_remove_all (self->checkpoints); - while ((checkpoint = c_list_first_entry (&self->checkpoints_lst_head, NMCheckpoint, checkpoints_lst))) - destroy_checkpoint (self, checkpoint, TRUE); + return TRUE; } gboolean nm_checkpoint_manager_destroy (NMCheckpointManager *self, - const char *path, + const char *checkpoint_path, GError **error) { - NMCheckpoint *checkpoint; + gboolean ret; g_return_val_if_fail (self, FALSE); - g_return_val_if_fail (path && path[0] == '/', FALSE); + g_return_val_if_fail (checkpoint_path && checkpoint_path[0] == '/', FALSE); g_return_val_if_fail (!error || !*error, FALSE); - if (!nm_streq (path, "/")) { - nm_checkpoint_manager_destroy_all (self); - return TRUE; - } - - checkpoint = nm_checkpoint_manager_lookup_by_path (self, path, error); - if (!checkpoint) - return FALSE; - - destroy_checkpoint (self, checkpoint, TRUE); - return TRUE; + if (!nm_streq (checkpoint_path, "/")) { + ret = g_hash_table_remove (self->checkpoints, checkpoint_path); + if (!ret) { + g_set_error (error, + NM_MANAGER_ERROR, + NM_MANAGER_ERROR_INVALID_ARGUMENTS, + "checkpoint %s does not exist", checkpoint_path); + } + return ret; + } else + return nm_checkpoint_manager_destroy_all (self, error); } gboolean nm_checkpoint_manager_rollback (NMCheckpointManager *self, - const char *path, + const char *checkpoint_path, GVariant **results, GError **error) { - NMCheckpoint *checkpoint; + NMCheckpoint *cp; g_return_val_if_fail (self, FALSE); - g_return_val_if_fail (path && path[0] == '/', FALSE); + g_return_val_if_fail (checkpoint_path && checkpoint_path[0] == '/', FALSE); g_return_val_if_fail (results, FALSE); g_return_val_if_fail (!error || !*error, FALSE); - checkpoint = nm_checkpoint_manager_lookup_by_path (self, path, error); - if (!checkpoint) + cp = g_hash_table_lookup (self->checkpoints, checkpoint_path); + if (!cp) { + g_set_error (error, NM_MANAGER_ERROR, NM_MANAGER_ERROR_FAILED, + "checkpoint %s does not exist", checkpoint_path); return FALSE; - - *results = rollback_checkpoint (self, checkpoint); - return TRUE; -} - -NMCheckpoint * -nm_checkpoint_manager_lookup_by_path (NMCheckpointManager *self, const char *path, GError **error) -{ - NMCheckpoint *checkpoint; - - g_return_val_if_fail (self, NULL); - - checkpoint = (NMCheckpoint *) nm_dbus_manager_lookup_object (nm_dbus_object_get_manager (NM_DBUS_OBJECT (GET_MANAGER (self))), - path); - if ( !checkpoint - || !NM_IS_CHECKPOINT (checkpoint)) { - g_set_error (error, NM_MANAGER_ERROR, NM_MANAGER_ERROR_INVALID_ARGUMENTS, - "checkpoint %s does not exist", path); - return NULL; } - nm_assert (c_list_contains (&self->checkpoints_lst_head, &checkpoint->checkpoints_lst)); - return checkpoint; -} - -const char ** -nm_checkpoint_manager_get_checkpoint_paths (NMCheckpointManager *self, guint *out_length) -{ - NMCheckpoint *checkpoint; - const char **strv; - guint num, i = 0; + *results = nm_checkpoint_rollback (cp); + g_hash_table_remove (self->checkpoints, checkpoint_path); - num = c_list_length (&self->checkpoints_lst_head); - NM_SET_OUT (out_length, num); - if (!num) - return NULL; - - strv = g_new (const char *, num + 1); - c_list_for_each_entry (checkpoint, &self->checkpoints_lst_head, checkpoints_lst) - strv[i++] = nm_dbus_object_get_path (NM_DBUS_OBJECT (checkpoint)); - nm_assert (i == num); - strv[i] = NULL; - return strv; -} - -gboolean -nm_checkpoint_manager_adjust_rollback_timeout (NMCheckpointManager *self, - const char *path, - guint32 add_timeout, - GError **error) -{ - NMCheckpoint *checkpoint; - - g_return_val_if_fail (self, FALSE); - g_return_val_if_fail (path && path[0] == '/', FALSE); - g_return_val_if_fail (!error || !*error, FALSE); - - checkpoint = nm_checkpoint_manager_lookup_by_path (self, path, error); - if (!checkpoint) - return FALSE; - - nm_checkpoint_adjust_rollback_timeout (checkpoint, add_timeout); return TRUE; } /*****************************************************************************/ NMCheckpointManager * -nm_checkpoint_manager_new (NMManager *manager, GParamSpec *spec) +nm_checkpoint_manager_new (NMManager *manager) { NMCheckpointManager *self; @@ -336,17 +301,20 @@ nm_checkpoint_manager_new (NMManager *manager, GParamSpec *spec) * of NMManager shall surpass the lifetime of the NMCheckpointManager * instance. */ self->_manager = manager; - self->property_spec = spec; - c_list_init (&self->checkpoints_lst_head); + self->checkpoints = g_hash_table_new_full (nm_str_hash, g_str_equal, + NULL, checkpoint_destroy); + return self; } void -nm_checkpoint_manager_free (NMCheckpointManager *self) +nm_checkpoint_manager_unref (NMCheckpointManager *self) { if (!self) return; - nm_checkpoint_manager_destroy_all (self); + nm_clear_g_source (&self->rollback_timeout_id); + g_hash_table_destroy (self->checkpoints); + g_slice_free (NMCheckpointManager, self); } diff --git a/src/nm-checkpoint-manager.h b/src/nm-checkpoint-manager.h index ca66ef16..30e49041 100644 --- a/src/nm-checkpoint-manager.h +++ b/src/nm-checkpoint-manager.h @@ -27,13 +27,8 @@ typedef struct _NMCheckpointManager NMCheckpointManager; -NMCheckpointManager *nm_checkpoint_manager_new (NMManager *manager, GParamSpec *spec); - -void nm_checkpoint_manager_free (NMCheckpointManager *self); - -NMCheckpoint *nm_checkpoint_manager_lookup_by_path (NMCheckpointManager *self, - const char *path, - GError **error); +NMCheckpointManager *nm_checkpoint_manager_new (NMManager *manager); +void nm_checkpoint_manager_unref (NMCheckpointManager *self); NMCheckpoint *nm_checkpoint_manager_create (NMCheckpointManager *self, const char *const*device_names, @@ -41,22 +36,15 @@ NMCheckpoint *nm_checkpoint_manager_create (NMCheckpointManager *self, NMCheckpointCreateFlags flags, GError **error); -void nm_checkpoint_manager_destroy_all (NMCheckpointManager *self); +gboolean nm_checkpoint_manager_destroy_all (NMCheckpointManager *self, + GError **error); gboolean nm_checkpoint_manager_destroy (NMCheckpointManager *self, - const char *path, + const char *checkpoint_path, GError **error); gboolean nm_checkpoint_manager_rollback (NMCheckpointManager *self, - const char *path, + const char *checkpoint_path, GVariant **results, GError **error); -gboolean nm_checkpoint_manager_adjust_rollback_timeout (NMCheckpointManager *self, - const char *path, - guint32 add_timeout, - GError **error); - -const char **nm_checkpoint_manager_get_checkpoint_paths (NMCheckpointManager *self, - guint *out_length); - #endif /* __NM_CHECKPOINT_MANAGER_H__ */ diff --git a/src/nm-checkpoint.c b/src/nm-checkpoint.c index a17f7eda..bc57d449 100644 --- a/src/nm-checkpoint.c +++ b/src/nm-checkpoint.c @@ -25,7 +25,6 @@ #include <string.h> #include "nm-active-connection.h" -#include "nm-act-request.h" #include "nm-auth-subject.h" #include "nm-core-utils.h" #include "nm-dbus-interface.h" @@ -35,6 +34,7 @@ #include "settings/nm-settings-connection.h" #include "nm-simple-connection.h" #include "nm-utils.h" +#include "introspection/org.freedesktop.NetworkManager.Checkpoint.h" /*****************************************************************************/ @@ -50,35 +50,36 @@ typedef struct { NMActivationReason activation_reason; } DeviceCheckpoint; -NM_GOBJECT_PROPERTIES_DEFINE (NMCheckpoint, +NM_GOBJECT_PROPERTIES_DEFINE_BASE ( PROP_DEVICES, PROP_CREATED, PROP_ROLLBACK_TIMEOUT, ); -struct _NMCheckpointPrivate { +typedef struct { /* properties */ GHashTable *devices; - gint64 created_at_ms; - guint32 rollback_timeout_s; - guint timeout_id; - /* private members */ + gint64 created; + guint32 rollback_timeout; /* private members */ NMManager *manager; + gint64 rollback_ts; NMCheckpointCreateFlags flags; GHashTable *connection_uuids; +} NMCheckpointPrivate; - NMCheckpointTimeoutCallback timeout_cb; - gpointer timeout_data; +struct _NMCheckpoint { + NMExportedObject parent; + NMCheckpointPrivate _priv; }; struct _NMCheckpointClass { - NMDBusObjectClass parent; + NMExportedObjectClass parent; }; -G_DEFINE_TYPE (NMCheckpoint, nm_checkpoint, NM_TYPE_DBUS_OBJECT) +G_DEFINE_TYPE (NMCheckpoint, nm_checkpoint, NM_TYPE_EXPORTED_OBJECT) -#define NM_CHECKPOINT_GET_PRIVATE(self) _NM_GET_PRIVATE_PTR (self, NMCheckpoint, NM_IS_CHECKPOINT) +#define NM_CHECKPOINT_GET_PRIVATE(self) _NM_GET_PRIVATE (self, NMCheckpoint, NM_IS_CHECKPOINT) /*****************************************************************************/ @@ -102,53 +103,20 @@ G_DEFINE_TYPE (NMCheckpoint, nm_checkpoint, NM_TYPE_DBUS_OBJECT) /*****************************************************************************/ -void -nm_checkpoint_log_destroy (NMCheckpoint *self) +guint64 +nm_checkpoint_get_rollback_ts (NMCheckpoint *self) { - _LOGI ("destroy %s", nm_dbus_object_get_path (NM_DBUS_OBJECT (self))); -} + g_return_val_if_fail (NM_IS_CHECKPOINT (self), 0); -void -nm_checkpoint_set_timeout_callback (NMCheckpoint *self, - NMCheckpointTimeoutCallback callback, - gpointer user_data) -{ - NMCheckpointPrivate *priv = NM_CHECKPOINT_GET_PRIVATE (self); - - /* in glib world, we would have a GSignal for this. But as there - * is only one subscriber, it's simpler to just set and unset(!) - * the callback this way. */ - priv->timeout_cb = callback; - priv->timeout_data = user_data; + return NM_CHECKPOINT_GET_PRIVATE (self)->rollback_ts; } -NMDevice * -nm_checkpoint_includes_devices (NMCheckpoint *self, NMDevice *const*devices, guint n_devices) +gboolean +nm_checkpoint_includes_device (NMCheckpoint *self, NMDevice *device) { NMCheckpointPrivate *priv = NM_CHECKPOINT_GET_PRIVATE (self); - guint i; - for (i = 0; i < n_devices; i++) { - if (g_hash_table_contains (priv->devices, devices[i])) - return devices[i]; - } - return NULL; -} - -NMDevice * -nm_checkpoint_includes_devices_of (NMCheckpoint *self, NMCheckpoint *cp_for_devices) -{ - NMCheckpointPrivate *priv = NM_CHECKPOINT_GET_PRIVATE (self); - NMCheckpointPrivate *priv2 = NM_CHECKPOINT_GET_PRIVATE (cp_for_devices); - GHashTableIter iter; - NMDevice *device; - - g_hash_table_iter_init (&iter, priv2->devices); - while (g_hash_table_iter_next (&iter, (gpointer *) &device, NULL)) { - if (g_hash_table_contains (priv->devices, device)) - return device; - } - return NULL; + return g_hash_table_contains (priv->devices, device); } static NMSettingsConnection * @@ -216,7 +184,7 @@ nm_checkpoint_rollback (NMCheckpoint *self) GError *local_error = NULL; GVariantBuilder builder; - _LOGI ("rollback of %s", nm_dbus_object_get_path (NM_DBUS_OBJECT (self))); + _LOGI ("rollback of %s", nm_exported_object_get_path ((NMExportedObject *) self)); g_variant_builder_init (&builder, G_VARIANT_TYPE ("a{su}")); /* Start rolling-back each device */ @@ -338,7 +306,7 @@ activate: &local_error)) { _LOGW ("rollback: reactivation of connection %s/%s failed: %s", nm_connection_get_id ((NMConnection *) connection), - nm_connection_get_uuid ((NMConnection *) connection), + nm_connection_get_uuid ((NMConnection * ) connection), local_error->message); g_clear_error (&local_error); result = NM_ROLLBACK_RESULT_ERR_FAILED; @@ -383,19 +351,21 @@ next_dev: } if (NM_FLAGS_HAS (priv->flags, NM_CHECKPOINT_CREATE_FLAG_DISCONNECT_NEW_DEVICES)) { - const CList *tmp_lst; + const GSList *list; NMDeviceState state; - - nm_manager_for_each_device (priv->manager, device, tmp_lst) { - if (g_hash_table_contains (priv->devices, device)) - continue; - state = nm_device_get_state (device); - if ( state > NM_DEVICE_STATE_DISCONNECTED - && state < NM_DEVICE_STATE_DEACTIVATING) { - _LOGD ("rollback: disconnecting new device %s", nm_device_get_iface (device)); - nm_device_state_changed (device, - NM_DEVICE_STATE_DEACTIVATING, - NM_DEVICE_STATE_REASON_USER_REQUESTED); + NMDevice *dev; + + for (list = nm_manager_get_devices (priv->manager); list ; list = g_slist_next (list)) { + dev = list->data; + if (!g_hash_table_contains (priv->devices, dev)) { + state = nm_device_get_state (dev); + if ( state > NM_DEVICE_STATE_DISCONNECTED + && state < NM_DEVICE_STATE_DEACTIVATING) { + _LOGD ("rollback: disconnecting new device %s", nm_device_get_iface (dev)); + nm_device_state_changed (dev, + NM_DEVICE_STATE_DEACTIVATING, + NM_DEVICE_STATE_REASON_USER_REQUESTED); + } } } @@ -405,7 +375,8 @@ next_dev: } static DeviceCheckpoint * -device_checkpoint_create (NMDevice *device) +device_checkpoint_create (NMDevice *device, + GError **error) { DeviceCheckpoint *dev_checkpoint; NMConnection *applied_connection; @@ -413,10 +384,7 @@ device_checkpoint_create (NMDevice *device) const char *path; NMActRequest *act_request; - nm_assert (NM_IS_DEVICE (device)); - nm_assert (nm_device_is_real (device)); - - path = nm_dbus_object_get_path (NM_DBUS_OBJECT (device)); + path = nm_exported_object_get_path (NM_EXPORTED_OBJECT (device)); dev_checkpoint = g_slice_new0 (DeviceCheckpoint); dev_checkpoint->device = g_object_ref (device); @@ -425,21 +393,25 @@ device_checkpoint_create (NMDevice *device) dev_checkpoint->realized = nm_device_is_real (device); if (nm_device_get_unmanaged_mask (device, NM_UNMANAGED_USER_EXPLICIT)) { - dev_checkpoint->unmanaged_explicit = !!nm_device_get_unmanaged_flags (device, - NM_UNMANAGED_USER_EXPLICIT); + dev_checkpoint->unmanaged_explicit = + !!nm_device_get_unmanaged_flags (device, NM_UNMANAGED_USER_EXPLICIT); } else dev_checkpoint->unmanaged_explicit = NM_UNMAN_FLAG_OP_FORGET; - act_request = nm_device_get_act_request (device); - if (act_request) { - settings_connection = nm_act_request_get_settings_connection (act_request); - applied_connection = nm_act_request_get_applied_connection (act_request); + applied_connection = nm_device_get_applied_connection (device); + if (applied_connection) { + dev_checkpoint->applied_connection = + nm_simple_connection_new_clone (applied_connection); - dev_checkpoint->applied_connection = nm_simple_connection_new_clone (applied_connection); + settings_connection = nm_device_get_settings_connection (device); + g_return_val_if_fail (settings_connection, NULL); dev_checkpoint->settings_connection = - nm_simple_connection_new_clone (NM_CONNECTION (settings_connection)); + nm_simple_connection_new_clone (NM_CONNECTION (settings_connection)); + + act_request = nm_device_get_act_request (device); + g_return_val_if_fail (act_request, NULL); dev_checkpoint->ac_version_id = - nm_active_connection_version_id_get (NM_ACTIVE_CONNECTION (act_request)); + nm_active_connection_version_id_get (NM_ACTIVE_CONNECTION (act_request)); dev_checkpoint->activation_reason = nm_active_connection_get_activation_reason (NM_ACTIVE_CONNECTION (act_request)); } @@ -460,57 +432,6 @@ device_checkpoint_destroy (gpointer data) g_slice_free (DeviceCheckpoint, dev_checkpoint); } -static gboolean -_timeout_cb (gpointer user_data) -{ - NMCheckpoint *self = user_data; - NMCheckpointPrivate *priv = NM_CHECKPOINT_GET_PRIVATE (self); - - priv->timeout_id = 0; - - if (priv->timeout_cb) - priv->timeout_cb (self, priv->timeout_data); - - /* beware, @self likely got destroyed! */ - return G_SOURCE_REMOVE; -} - -void -nm_checkpoint_adjust_rollback_timeout (NMCheckpoint *self, guint32 add_timeout) -{ - guint32 rollback_timeout_s; - gint64 now_ms, add_timeout_ms, rollback_timeout_ms; - - NMCheckpointPrivate *priv = NM_CHECKPOINT_GET_PRIVATE (self); - - nm_clear_g_source (&priv->timeout_id); - - if (add_timeout == 0) - rollback_timeout_s = 0; - else { - now_ms = nm_utils_get_monotonic_timestamp_ms (); - add_timeout_ms = ((gint64) add_timeout) * 1000; - rollback_timeout_ms = (now_ms - priv->created_at_ms) + add_timeout_ms; - - /* round to nearest integer second. Since NM_CHECKPOINT_ROLLBACK_TIMEOUT is - * in units seconds, it will be able to exactly express the timeout. */ - rollback_timeout_s = NM_MIN ((rollback_timeout_ms + 500) / 1000, (gint64) G_MAXUINT32); - - /* we expect the timeout to be positive, because add_timeout_ms is positive. - * We cannot accept a zero, because it means "infinity". */ - nm_assert (rollback_timeout_s > 0); - - priv->timeout_id = g_timeout_add (NM_MIN (add_timeout_ms, (gint64) G_MAXUINT32), - _timeout_cb, - self); - } - - if (rollback_timeout_s != priv->rollback_timeout_s) { - priv->rollback_timeout_s = rollback_timeout_s; - _notify (self, PROP_ROLLBACK_TIMEOUT); - } -} - /*****************************************************************************/ static void @@ -519,20 +440,22 @@ get_property (GObject *object, guint prop_id, { NMCheckpoint *self = NM_CHECKPOINT (object); NMCheckpointPrivate *priv = NM_CHECKPOINT_GET_PRIVATE (self); + gs_free_slist GSList *devices = NULL; + GHashTableIter iter; + NMDevice *device; switch (prop_id) { case PROP_DEVICES: - nm_dbus_utils_g_value_set_object_path_from_hash (value, - priv->devices, - FALSE); + g_hash_table_iter_init (&iter, priv->devices); + while (g_hash_table_iter_next (&iter, (gpointer *) &device, NULL)) + devices = g_slist_append (devices, device); + nm_utils_g_value_set_object_path_array (value, devices, NULL, NULL); break; case PROP_CREATED: - g_value_set_int64 (value, - nm_utils_monotonic_timestamp_as_boottime (priv->created_at_ms, - NM_UTILS_NS_PER_MSEC)); + g_value_set_int64 (value, priv->created); break; case PROP_ROLLBACK_TIMEOUT: - g_value_set_uint (value, priv->rollback_timeout_s); + g_value_set_uint (value, priv->rollback_timeout); break; default: G_OBJECT_WARN_INVALID_PROPERTY_ID (object, prop_id, pspec); @@ -545,47 +468,47 @@ get_property (GObject *object, guint prop_id, static void nm_checkpoint_init (NMCheckpoint *self) { - NMCheckpointPrivate *priv; - - priv = G_TYPE_INSTANCE_GET_PRIVATE (self, NM_TYPE_CHECKPOINT, NMCheckpointPrivate); - - self->_priv = priv; - - c_list_init (&self->checkpoints_lst); + NMCheckpointPrivate *priv = NM_CHECKPOINT_GET_PRIVATE (self); - priv->devices = g_hash_table_new_full (nm_direct_hash, NULL, + priv->devices = g_hash_table_new_full (g_direct_hash, g_direct_equal, NULL, device_checkpoint_destroy); } NMCheckpoint * -nm_checkpoint_new (NMManager *manager, GPtrArray *devices, guint32 rollback_timeout_s, - NMCheckpointCreateFlags flags) +nm_checkpoint_new (NMManager *manager, GPtrArray *devices, guint32 rollback_timeout, + NMCheckpointCreateFlags flags, GError **error) { NMCheckpoint *self; NMCheckpointPrivate *priv; NMSettingsConnection *const *con; - gint64 rollback_timeout_ms; + DeviceCheckpoint *dev_checkpoint; + NMDevice *device; guint i; g_return_val_if_fail (manager, NULL); g_return_val_if_fail (devices, NULL); - g_return_val_if_fail (devices->len > 0, NULL); + g_return_val_if_fail (!error || !*error, NULL); + + if (!devices->len) { + g_set_error_literal (error, + NM_MANAGER_ERROR, + NM_MANAGER_ERROR_INVALID_ARGUMENTS, + "no device available"); + return NULL; + } self = g_object_new (NM_TYPE_CHECKPOINT, NULL); priv = NM_CHECKPOINT_GET_PRIVATE (self); priv->manager = manager; - priv->rollback_timeout_s = rollback_timeout_s; - priv->created_at_ms = nm_utils_get_monotonic_timestamp_ms (); + priv->created = nm_utils_monotonic_timestamp_as_boottime (nm_utils_get_monotonic_timestamp_ms (), + NM_UTILS_NS_PER_MSEC); + priv->rollback_timeout = rollback_timeout; + priv->rollback_ts = rollback_timeout ? + (nm_utils_get_monotonic_timestamp_ms () + ((gint64) rollback_timeout * 1000)) : + 0; priv->flags = flags; - if (rollback_timeout_s != 0) { - rollback_timeout_ms = ((gint64) rollback_timeout_s) * 1000; - priv->timeout_id = g_timeout_add (NM_MIN (rollback_timeout_ms, (gint64) G_MAXUINT32), - _timeout_cb, - self); - } - if (NM_FLAGS_HAS (flags, NM_CHECKPOINT_CREATE_FLAG_DELETE_NEW_CONNECTIONS)) { priv->connection_uuids = g_hash_table_new_full (nm_str_hash, g_str_equal, g_free, NULL); for (con = nm_settings_get_connections (nm_settings_get (), NULL); *con; con++) { @@ -595,15 +518,13 @@ nm_checkpoint_new (NMManager *manager, GPtrArray *devices, guint32 rollback_time } for (i = 0; i < devices->len; i++) { - NMDevice *device = devices->pdata[i]; - - /* FIXME: as long as the check point instance exists, it won't let go - * of the device. That is a bug, for example, if you have a ethernet - * device that gets removed (rmmod), the checkpoint will reference - * a non-existing D-Bus path of a device. */ - g_hash_table_insert (priv->devices, - device, - device_checkpoint_create (device)); + device = (NMDevice *) devices->pdata[i]; + dev_checkpoint = device_checkpoint_create (device, error); + if (!dev_checkpoint) { + g_object_unref (self); + return NULL; + } + g_hash_table_insert (priv->devices, device, dev_checkpoint); } return self; @@ -615,41 +536,20 @@ dispose (GObject *object) NMCheckpoint *self = NM_CHECKPOINT (object); NMCheckpointPrivate *priv = NM_CHECKPOINT_GET_PRIVATE (self); - nm_assert (c_list_is_empty (&self->checkpoints_lst)); - g_clear_pointer (&priv->devices, g_hash_table_unref); g_clear_pointer (&priv->connection_uuids, g_hash_table_unref); - nm_clear_g_source (&priv->timeout_id); - G_OBJECT_CLASS (nm_checkpoint_parent_class)->dispose (object); } -static const NMDBusInterfaceInfoExtended interface_info_checkpoint = { - .parent = NM_DEFINE_GDBUS_INTERFACE_INFO_INIT ( - NM_DBUS_INTERFACE_CHECKPOINT, - .signals = NM_DEFINE_GDBUS_SIGNAL_INFOS ( - &nm_signal_info_property_changed_legacy, - ), - .properties = NM_DEFINE_GDBUS_PROPERTY_INFOS ( - NM_DEFINE_DBUS_PROPERTY_INFO_EXTENDED_READABLE_L ("Devices", "ao", NM_CHECKPOINT_DEVICES), - NM_DEFINE_DBUS_PROPERTY_INFO_EXTENDED_READABLE_L ("Created", "x", NM_CHECKPOINT_CREATED), - NM_DEFINE_DBUS_PROPERTY_INFO_EXTENDED_READABLE_L ("RollbackTimeout", "u", NM_CHECKPOINT_ROLLBACK_TIMEOUT), - ), - ), - .legacy_property_changed = TRUE, -}; - static void nm_checkpoint_class_init (NMCheckpointClass *checkpoint_class) { GObjectClass *object_class = G_OBJECT_CLASS (checkpoint_class); - NMDBusObjectClass *dbus_object_class = NM_DBUS_OBJECT_CLASS (checkpoint_class); + NMExportedObjectClass *exported_object_class = NM_EXPORTED_OBJECT_CLASS (checkpoint_class); - g_type_class_add_private (object_class, sizeof (NMCheckpointPrivate)); - - dbus_object_class->export_path = NM_DBUS_EXPORT_PATH_NUMBERED (NM_DBUS_PATH"/Checkpoint"); - dbus_object_class->interface_infos = NM_DBUS_INTERFACE_INFOS (&interface_info_checkpoint); + exported_object_class->export_path = NM_EXPORT_PATH_NUMBERED (NM_DBUS_PATH"/Checkpoint"); + exported_object_class->export_on_construction = FALSE; object_class->dispose = dispose; object_class->get_property = get_property; @@ -673,4 +573,8 @@ nm_checkpoint_class_init (NMCheckpointClass *checkpoint_class) G_PARAM_STATIC_STRINGS); g_object_class_install_properties (object_class, _PROPERTY_ENUMS_LAST, obj_properties); + + nm_exported_object_class_add_interface (NM_EXPORTED_OBJECT_CLASS (checkpoint_class), + NMDBUS_TYPE_CHECKPOINT_SKELETON, + NULL); } diff --git a/src/nm-checkpoint.h b/src/nm-checkpoint.h index c8598f38..fccf8af3 100644 --- a/src/nm-checkpoint.h +++ b/src/nm-checkpoint.h @@ -21,7 +21,7 @@ #ifndef __NETWORKMANAGER_CHECKPOINT_H__ #define __NETWORKMANAGER_CHECKPOINT_H__ -#include "nm-dbus-object.h" +#include "nm-exported-object.h" #include "nm-dbus-interface.h" #define NM_TYPE_CHECKPOINT (nm_checkpoint_get_type ()) @@ -35,35 +35,16 @@ #define NM_CHECKPOINT_CREATED "created" #define NM_CHECKPOINT_ROLLBACK_TIMEOUT "rollback-timeout" -typedef struct _NMCheckpointPrivate NMCheckpointPrivate; - -typedef struct { - NMDBusObject parent; - NMCheckpointPrivate *_priv; - CList checkpoints_lst; -} NMCheckpoint; - +typedef struct _NMCheckpoint NMCheckpoint; typedef struct _NMCheckpointClass NMCheckpointClass; GType nm_checkpoint_get_type (void); NMCheckpoint *nm_checkpoint_new (NMManager *manager, GPtrArray *devices, guint32 rollback_timeout, - NMCheckpointCreateFlags flags); - -typedef void (*NMCheckpointTimeoutCallback) (NMCheckpoint *self, - gpointer user_data); - -void nm_checkpoint_log_destroy (NMCheckpoint *self); - -void nm_checkpoint_set_timeout_callback (NMCheckpoint *self, - NMCheckpointTimeoutCallback callback, - gpointer user_data); + NMCheckpointCreateFlags flags, GError **error); +guint64 nm_checkpoint_get_rollback_ts (NMCheckpoint *checkpoint); +gboolean nm_checkpoint_includes_device (NMCheckpoint *checkpoint, NMDevice *device); GVariant *nm_checkpoint_rollback (NMCheckpoint *self); -void nm_checkpoint_adjust_rollback_timeout (NMCheckpoint *self, guint32 add_timeout); - -NMDevice *nm_checkpoint_includes_devices (NMCheckpoint *self, NMDevice *const*devices, guint n_devices); -NMDevice *nm_checkpoint_includes_devices_of (NMCheckpoint *self, NMCheckpoint *cp_for_devices); - #endif /* __NETWORKMANAGER_CHECKPOINT_H__ */ diff --git a/src/nm-config-data.c b/src/nm-config-data.c index 5f19eabe..00e5c635 100644 --- a/src/nm-config-data.c +++ b/src/nm-config-data.c @@ -54,7 +54,7 @@ struct _NMGlobalDnsConfig { char **searches; char **options; GHashTable *domains; - const char **domain_list; + char **domain_list; gboolean internal; }; @@ -238,7 +238,7 @@ nm_config_data_get_plugins (const NMConfigData *self, gboolean allow_default) if (!list && allow_default) { gs_unref_keyfile GKeyFile *kf = nm_config_create_keyfile (); - /* let keyfile split the default string according to its own escaping rules. */ + /* let keyfile split the default string according to it's own escaping rules. */ g_key_file_set_value (kf, NM_CONFIG_KEYFILE_GROUP_MAIN, "plugins", NM_CONFIG_DEFAULT_MAIN_PLUGINS); list = g_key_file_get_string_list (kf, NM_CONFIG_KEYFILE_GROUP_MAIN, "plugins", NULL, NULL); } @@ -705,53 +705,54 @@ nm_config_data_log (const NMConfigData *self, /*****************************************************************************/ -const char *const* -nm_global_dns_config_get_searches (const NMGlobalDnsConfig *dns_config) +const char *const * +nm_global_dns_config_get_searches (const NMGlobalDnsConfig *dns) { - g_return_val_if_fail (dns_config, NULL); + g_return_val_if_fail (dns, NULL); - return (const char *const*) dns_config->searches; + return (const char *const *) dns->searches; } const char *const * -nm_global_dns_config_get_options (const NMGlobalDnsConfig *dns_config) +nm_global_dns_config_get_options (const NMGlobalDnsConfig *dns) { - g_return_val_if_fail (dns_config, NULL); + g_return_val_if_fail (dns, NULL); - return (const char *const*) dns_config->options; + return (const char *const *) dns->options; } guint -nm_global_dns_config_get_num_domains (const NMGlobalDnsConfig *dns_config) +nm_global_dns_config_get_num_domains (const NMGlobalDnsConfig *dns) { - g_return_val_if_fail (dns_config, 0); + g_return_val_if_fail (dns, 0); + g_return_val_if_fail (dns->domains, 0); - return dns_config->domains ? g_hash_table_size (dns_config->domains) : 0; + return g_hash_table_size (dns->domains); } NMGlobalDnsDomain * -nm_global_dns_config_get_domain (const NMGlobalDnsConfig *dns_config, guint i) +nm_global_dns_config_get_domain (const NMGlobalDnsConfig *dns, guint i) { NMGlobalDnsDomain *domain; - g_return_val_if_fail (dns_config, NULL); - g_return_val_if_fail (dns_config->domains, NULL); - g_return_val_if_fail (i < g_hash_table_size (dns_config->domains), NULL); - - nm_assert (NM_PTRARRAY_LEN (dns_config->domain_list) == g_hash_table_size (dns_config->domains)); + g_return_val_if_fail (dns, NULL); + g_return_val_if_fail (dns->domains, NULL); + g_return_val_if_fail (dns->domain_list, NULL); + g_return_val_if_fail (i < g_strv_length (dns->domain_list), NULL); - domain = g_hash_table_lookup (dns_config->domains, dns_config->domain_list[i]); + domain = g_hash_table_lookup (dns->domains, dns->domain_list[i]); + g_return_val_if_fail (domain, NULL); - nm_assert (domain); return domain; } -NMGlobalDnsDomain *nm_global_dns_config_lookup_domain (const NMGlobalDnsConfig *dns_config, const char *name) +NMGlobalDnsDomain *nm_global_dns_config_lookup_domain (const NMGlobalDnsConfig *dns, const char *name) { - g_return_val_if_fail (dns_config, NULL); + g_return_val_if_fail (dns, NULL); + g_return_val_if_fail (dns->domains, NULL); g_return_val_if_fail (name, NULL); - return dns_config->domains ? g_hash_table_lookup (dns_config->domains, name) : NULL; + return g_hash_table_lookup (dns->domains, name); } const char * @@ -774,73 +775,55 @@ const char *const * nm_global_dns_domain_get_options (const NMGlobalDnsDomain *domain) { g_return_val_if_fail (domain, NULL); - return (const char *const *) domain->options; } gboolean -nm_global_dns_config_is_internal (const NMGlobalDnsConfig *dns_config) +nm_global_dns_config_is_internal (const NMGlobalDnsConfig *dns) { - return dns_config->internal; + return dns->internal; } gboolean -nm_global_dns_config_is_empty (const NMGlobalDnsConfig *dns_config) +nm_global_dns_config_is_empty (const NMGlobalDnsConfig *dns) { - g_return_val_if_fail (dns_config, TRUE); + g_return_val_if_fail (dns, TRUE); + g_return_val_if_fail (dns->domains, TRUE); - return !dns_config->searches - && !dns_config->options - && !dns_config->domain_list; + return (!dns->searches || g_strv_length (dns->searches) == 0) + && (!dns->options || g_strv_length (dns->options) == 0) + && g_hash_table_size (dns->domains) == 0; } void -nm_global_dns_config_update_checksum (const NMGlobalDnsConfig *dns_config, GChecksum *sum) +nm_global_dns_config_update_checksum (const NMGlobalDnsConfig *dns, GChecksum *sum) { NMGlobalDnsDomain *domain; - guint i, j; - guint8 v8; + GList *keys, *key; + guint i; - g_return_if_fail (dns_config); + g_return_if_fail (dns); + g_return_if_fail (dns->domains); g_return_if_fail (sum); - v8 = NM_HASH_COMBINE_BOOLS (guint8, - !dns_config->searches, - !dns_config->options, - !dns_config->domain_list); - g_checksum_update (sum, (guchar *) &v8, 1); - - if (dns_config->searches) { - for (i = 0; dns_config->searches[i]; i++) - g_checksum_update (sum, (guchar *) dns_config->searches[i], strlen (dns_config->searches[i]) + 1); - } - if (dns_config->options) { - for (i = 0; dns_config->options[i]; i++) - g_checksum_update (sum, (guchar *) dns_config->options[i], strlen (dns_config->options[i]) + 1); - } - - if (dns_config->domain_list) { - for (i = 0; dns_config->domain_list[i]; i++) { - domain = g_hash_table_lookup (dns_config->domains, dns_config->domain_list[i]); - nm_assert (domain); + for (i = 0; dns->searches && dns->searches[i]; i++) + g_checksum_update (sum, (guchar *) dns->searches[i], strlen (dns->searches[i])); + for (i = 0; dns->options && dns->options[i]; i++) + g_checksum_update (sum, (guchar *) dns->options[i], strlen (dns->options[i])); - v8 = NM_HASH_COMBINE_BOOLS (guint8, - !domain->servers, - !domain->options); - g_checksum_update (sum, (guchar *) &v8, 1); + keys = g_list_sort (g_hash_table_get_keys (dns->domains), (GCompareFunc) strcmp); + for (key = keys; key; key = g_list_next (key)) { - g_checksum_update (sum, (guchar *) domain->name, strlen (domain->name) + 1); + domain = g_hash_table_lookup (dns->domains, key->data); + g_assert (domain != NULL); + g_checksum_update (sum, (guchar *) domain->name, strlen (domain->name)); - if (domain->servers) { - for (j = 0; domain->servers[j]; j++) - g_checksum_update (sum, (guchar *) domain->servers[j], strlen (domain->servers[j]) + 1); - } - if (domain->options) { - for (j = 0; domain->options[j]; j++) - g_checksum_update (sum, (guchar *) domain->options[j], strlen (domain->options[j]) + 1); - } - } + for (i = 0; domain->servers && domain->servers[i]; i++) + g_checksum_update (sum, (guchar *) domain->servers[i], strlen (domain->servers[i])); + for (i = 0; domain->options && domain->options[i]; i++) + g_checksum_update (sum, (guchar *) domain->options[i], strlen (domain->options[i])); } + g_list_free (keys); } static void @@ -855,15 +838,14 @@ global_dns_domain_free (NMGlobalDnsDomain *domain) } void -nm_global_dns_config_free (NMGlobalDnsConfig *dns_config) -{ - if (dns_config) { - g_strfreev (dns_config->searches); - g_strfreev (dns_config->options); - g_free (dns_config->domain_list); - if (dns_config->domains) - g_hash_table_unref (dns_config->domains); - g_free (dns_config); +nm_global_dns_config_free (NMGlobalDnsConfig *conf) +{ + if (conf) { + g_strfreev (conf->searches); + g_strfreev (conf->options); + g_free (conf->domain_list); + g_hash_table_unref (conf->domains); + g_free (conf); } } @@ -876,22 +858,18 @@ nm_config_data_get_global_dns_config (const NMConfigData *self) } static void -global_dns_config_seal_domains (NMGlobalDnsConfig *dns_config) +global_dns_config_update_domain_list (NMGlobalDnsConfig *dns) { - nm_assert (dns_config); - nm_assert (dns_config->domains); - nm_assert (!dns_config->domain_list); + guint length; - if (g_hash_table_size (dns_config->domains) == 0) - nm_clear_pointer (&dns_config->domains, g_hash_table_unref); - else - dns_config->domain_list = nm_utils_strdict_get_keys (dns_config->domains, TRUE, NULL); + g_free (dns->domain_list); + dns->domain_list = (char **) g_hash_table_get_keys_as_array (dns->domains, &length); } static NMGlobalDnsConfig * load_global_dns (GKeyFile *keyfile, gboolean internal) { - NMGlobalDnsConfig *dns_config; + NMGlobalDnsConfig *conf; char *group, *domain_prefix; gs_strfreev char **groups = NULL; int g, i, j, domain_prefix_len; @@ -909,18 +887,13 @@ load_global_dns (GKeyFile *keyfile, gboolean internal) if (!nm_config_keyfile_has_global_dns_config (keyfile, internal)) return NULL; - dns_config = g_malloc0 (sizeof (NMGlobalDnsConfig)); - dns_config->domains = g_hash_table_new_full (nm_str_hash, g_str_equal, - g_free, (GDestroyNotify) global_dns_domain_free); + conf = g_malloc0 (sizeof (NMGlobalDnsConfig)); + conf->domains = g_hash_table_new_full (nm_str_hash, g_str_equal, + g_free, (GDestroyNotify) global_dns_domain_free); strv = g_key_file_get_string_list (keyfile, group, "searches", NULL, NULL); - if (strv) { - _nm_utils_strv_cleanup (strv, TRUE, TRUE, TRUE); - if (!strv[0]) - g_free (strv); - else - dns_config->searches = strv; - } + if (strv) + conf->searches = _nm_utils_strv_cleanup (strv, TRUE, TRUE, TRUE); strv = g_key_file_get_string_list (keyfile, group, "options", NULL, NULL); if (strv) { @@ -931,12 +904,8 @@ load_global_dns (GKeyFile *keyfile, gboolean internal) else g_free (strv[i]); } - if (j == 0) - g_free (strv); - else { - strv[j] = NULL; - dns_config->options = strv; - } + strv[j] = NULL; + conf->options = strv; } groups = g_key_file_get_groups (keyfile, NULL); @@ -959,23 +928,20 @@ load_global_dns (GKeyFile *keyfile, gboolean internal) else g_free (strv[i]); } - if (j == 0) - g_free (strv); - else { + if (j) { strv[j] = NULL; servers = strv; } + else + g_free (strv); } if (!servers) continue; strv = g_key_file_get_string_list (keyfile, groups[g], "options", NULL, NULL); - if (strv) { + if (strv) options = _nm_utils_strv_cleanup (strv, TRUE, TRUE, TRUE); - if (!options[0]) - nm_clear_g_free (&options); - } name = strdup (&groups[g][domain_prefix_len]); domain = g_malloc0 (sizeof (NMGlobalDnsDomain)); @@ -983,7 +949,7 @@ load_global_dns (GKeyFile *keyfile, gboolean internal) domain->servers = servers; domain->options = options; - g_hash_table_insert (dns_config->domains, strdup (name), domain); + g_hash_table_insert (conf->domains, strdup (name), domain); if (!strcmp (name, "*")) default_found = TRUE; @@ -992,61 +958,59 @@ load_global_dns (GKeyFile *keyfile, gboolean internal) if (!default_found) { nm_log_dbg (LOGD_CORE, "%s global DNS configuration is missing default domain, ignore it", internal ? "internal" : "user"); - nm_global_dns_config_free (dns_config); + nm_global_dns_config_free (conf); return NULL; } - dns_config->internal = internal; - global_dns_config_seal_domains (dns_config); - return dns_config; + conf->internal = internal; + global_dns_config_update_domain_list (conf); + return conf; } void -nm_global_dns_config_to_dbus (const NMGlobalDnsConfig *dns_config, GValue *value) +nm_global_dns_config_to_dbus (const NMGlobalDnsConfig *dns, GValue *value) { GVariantBuilder conf_builder, domains_builder, domain_builder; - guint i; + NMGlobalDnsDomain *domain; + GHashTableIter iter; g_variant_builder_init (&conf_builder, G_VARIANT_TYPE ("a{sv}")); - if (!dns_config) + if (!dns) goto out; - if (dns_config->searches) { + if (dns->searches) { g_variant_builder_add (&conf_builder, "{sv}", "searches", - g_variant_new_strv ((const char *const *) dns_config->searches, -1)); + g_variant_new_strv ((const char *const *) dns->searches, -1)); } - if (dns_config->options) { + if (dns->options) { g_variant_builder_add (&conf_builder, "{sv}", "options", - g_variant_new_strv ((const char *const *) dns_config->options, -1)); + g_variant_new_strv ((const char *const *) dns->options, -1)); } g_variant_builder_init (&domains_builder, G_VARIANT_TYPE ("a{sv}")); - if (dns_config->domain_list) { - for (i = 0; dns_config->domain_list[i]; i++) { - NMGlobalDnsDomain *domain; - - domain = g_hash_table_lookup (dns_config->domains, dns_config->domain_list[i]); - g_variant_builder_init (&domain_builder, G_VARIANT_TYPE ("a{sv}")); + g_hash_table_iter_init (&iter, dns->domains); + while (g_hash_table_iter_next (&iter, NULL, (gpointer *) &domain)) { - if (domain->servers) { - g_variant_builder_add (&domain_builder, "{sv}", "servers", - g_variant_new_strv ((const char *const *) domain->servers, -1)); - } - if (domain->options) { - g_variant_builder_add (&domain_builder, "{sv}", "options", - g_variant_new_strv ((const char *const *) domain->options, -1)); - } + g_variant_builder_init (&domain_builder, G_VARIANT_TYPE ("a{sv}")); - g_variant_builder_add (&domains_builder, "{sv}", domain->name, - g_variant_builder_end (&domain_builder)); + if (domain->servers) { + g_variant_builder_add (&domain_builder, "{sv}", "servers", + g_variant_new_strv ((const char *const *) domain->servers, -1)); + } + if (domain->options) { + g_variant_builder_add (&domain_builder, "{sv}", "options", + g_variant_new_strv ((const char *const *) domain->options, -1)); } + + g_variant_builder_add (&domains_builder, "{sv}", domain->name, + g_variant_builder_end (&domain_builder)); } + g_variant_builder_add (&conf_builder, "{sv}", "domains", g_variant_builder_end (&domains_builder)); - out: g_value_take_variant (value, g_variant_builder_end (&conf_builder)); } @@ -1080,20 +1044,15 @@ global_dns_domain_from_dbus (char *name, GVariant *variant) else g_free (strv[i]); } - if (j == 0) - g_free (strv); - else { + if (j) { strv[j] = NULL; - g_strfreev (domain->servers); domain->servers = strv; - } + } else + g_free (strv); } else if ( !g_strcmp0 (key, "options") && g_variant_is_of_type (val, G_VARIANT_TYPE ("as"))) { strv = g_variant_dup_strv (val, NULL); - g_strfreev (domain->options); domain->options = _nm_utils_strv_cleanup (strv, TRUE, TRUE, TRUE); - if (!domain->options[0]) - nm_clear_g_free (&domain->options); } g_variant_unref (val); @@ -1152,12 +1111,11 @@ nm_global_dns_config_from_dbus (const GValue *value, GError **error) else g_free (strv[i]); } - if (j == 0) - g_free (strv); - else { + + if (strv) strv[j] = NULL; - dns_config->options = strv; - } + + dns_config->options = strv; } else if ( !g_strcmp0 (key, "domains") && g_variant_is_of_type (val, G_VARIANT_TYPE ("a{sv}"))) { NMGlobalDnsDomain *domain; @@ -1187,7 +1145,7 @@ nm_global_dns_config_from_dbus (const GValue *value, GError **error) return NULL; } - global_dns_config_seal_domains (dns_config); + global_dns_config_update_domain_list (dns_config); return dns_config; } @@ -1238,8 +1196,6 @@ _match_section_infos_lookup (const MatchSectionInfo *match_section_infos, GKeyFile *keyfile, const char *property, NMDevice *device, - const NMPlatformLink *pllink, - const char *match_device_type, char **out_value) { if (!match_section_infos) @@ -1260,15 +1216,9 @@ _match_section_infos_lookup (const MatchSectionInfo *match_section_infos, if (!value && !match_section_infos->stop_match) continue; - if (match_section_infos->match_device.has) { - if (device) - match = nm_device_spec_match_list (device, match_section_infos->match_device.spec); - else if (pllink) - match = nm_match_spec_device_by_pllink (pllink, match_device_type, match_section_infos->match_device.spec, FALSE); - else - match = FALSE; - } else - match = TRUE; + match = TRUE; + if (match_section_infos->match_device.has) + match = device && nm_device_spec_match_list (device, match_section_infos->match_device.spec); if (match) { *out_value = value; @@ -1298,35 +1248,6 @@ nm_config_data_get_device_config (const NMConfigData *self, priv->keyfile, property, device, - NULL, - NULL, - &value); - NM_SET_OUT (has_match, !!connection_info); - return value; -} - -char * -nm_config_data_get_device_config_by_pllink (const NMConfigData *self, - const char *property, - const NMPlatformLink *pllink, - const char *match_device_type, - gboolean *has_match) -{ - const NMConfigDataPrivate *priv; - const MatchSectionInfo *connection_info; - char *value = NULL; - - g_return_val_if_fail (self, NULL); - g_return_val_if_fail (property && *property, NULL); - - priv = NM_CONFIG_DATA_GET_PRIVATE (self); - - connection_info = _match_section_infos_lookup (&priv->device_infos[0], - priv->keyfile, - property, - NULL, - pllink, - match_device_type, &value); NM_SET_OUT (has_match, !!connection_info); return value; @@ -1366,8 +1287,6 @@ nm_config_data_get_connection_default (const NMConfigData *self, priv->keyfile, property, device, - NULL, - NULL, &value); return value; } diff --git a/src/nm-config-data.h b/src/nm-config-data.h index a11b38b2..3092a87f 100644 --- a/src/nm-config-data.h +++ b/src/nm-config-data.h @@ -188,12 +188,6 @@ char *nm_config_data_get_device_config (const NMConfigData *self, NMDevice *device, gboolean *has_match); -char *nm_config_data_get_device_config_by_pllink (const NMConfigData *self, - const char *property, - const NMPlatformLink *pllink, - const char *match_device_type, - gboolean *has_match); - gboolean nm_config_data_get_device_config_boolean (const NMConfigData *self, const char *property, NMDevice *device, @@ -206,18 +200,18 @@ gboolean nm_config_data_is_intern_atomic_group (const NMConfigData *self, const GKeyFile *nm_config_data_clone_keyfile_intern (const NMConfigData *self); -const char *const *nm_global_dns_config_get_searches (const NMGlobalDnsConfig *dns_config); -const char *const *nm_global_dns_config_get_options (const NMGlobalDnsConfig *dns_config); -guint nm_global_dns_config_get_num_domains (const NMGlobalDnsConfig *dns_config); -NMGlobalDnsDomain *nm_global_dns_config_get_domain (const NMGlobalDnsConfig *dns_config, guint i); -NMGlobalDnsDomain *nm_global_dns_config_lookup_domain (const NMGlobalDnsConfig *dns_config, const char *name); +const char *const *nm_global_dns_config_get_searches (const NMGlobalDnsConfig *dns); +const char *const *nm_global_dns_config_get_options (const NMGlobalDnsConfig *dns); +guint nm_global_dns_config_get_num_domains (const NMGlobalDnsConfig *dns); +NMGlobalDnsDomain *nm_global_dns_config_get_domain (const NMGlobalDnsConfig *dns, guint i); +NMGlobalDnsDomain *nm_global_dns_config_lookup_domain (const NMGlobalDnsConfig *dns, const char *name); const char *nm_global_dns_domain_get_name (const NMGlobalDnsDomain *domain); const char *const *nm_global_dns_domain_get_servers (const NMGlobalDnsDomain *domain); const char *const *nm_global_dns_domain_get_options (const NMGlobalDnsDomain *domain); -gboolean nm_global_dns_config_is_internal (const NMGlobalDnsConfig *dns_config); -gboolean nm_global_dns_config_is_empty (const NMGlobalDnsConfig *dns_config); -void nm_global_dns_config_update_checksum (const NMGlobalDnsConfig *dns_config, GChecksum *sum); -void nm_global_dns_config_free (NMGlobalDnsConfig *dns_config); +gboolean nm_global_dns_config_is_internal (const NMGlobalDnsConfig *dns); +gboolean nm_global_dns_config_is_empty (const NMGlobalDnsConfig *dns); +void nm_global_dns_config_update_checksum (const NMGlobalDnsConfig *dns, GChecksum *sum); +void nm_global_dns_config_free (NMGlobalDnsConfig *conf); NMGlobalDnsConfig *nm_global_dns_config_from_dbus (const GValue *value, GError **error); void nm_global_dns_config_to_dbus (const NMGlobalDnsConfig *dns_config, GValue *value); diff --git a/src/nm-config.c b/src/nm-config.c index bef05fc7..29f0d517 100644 --- a/src/nm-config.c +++ b/src/nm-config.c @@ -553,7 +553,7 @@ nm_config_create_keyfile () /* this is an external variable, to make loading testable. Other then that, * no code is supposed to change this. */ -guint _nm_config_match_nm_version = NM_VERSION; +guint _nm_config_match_nm_version = NM_VERSION_CUR_STABLE; char *_nm_config_match_env = NULL; static gboolean @@ -615,7 +615,7 @@ _sort_groups_cmp (const char **pa, const char **pb, gpointer dummy) if (a_is_connection) { /* both are [connection.\+] entries. Reverse their order. * One of the sections might be literally [connection]. That section - * is special and its order will be fixed later. It doesn't actually + * is special and it's order will be fixed later. It doesn't actually * matter here how it compares with [connection.\+] sections. */ return pa > pb ? -1 : 1; } @@ -633,7 +633,7 @@ _sort_groups_cmp (const char **pa, const char **pb, gpointer dummy) if (a_is_device) { /* both are [device.\+] entries. Reverse their order. * One of the sections might be literally [device]. That section - * is special and its order will be fixed later. It doesn't actually + * is special and it's order will be fixed later. It doesn't actually * matter here how it compares with [device.\+] sections. */ return pa > pb ? -1 : 1; } @@ -1383,6 +1383,7 @@ intern_config_write (const char *filename, GKeyFile *keyfile; gs_strfreev char **groups = NULL; guint g, k; + gboolean has_intern = FALSE; gboolean success = FALSE; GError *local = NULL; @@ -1448,7 +1449,10 @@ intern_config_write (const char *filename, value_set = g_key_file_get_value (keyfile_intern, group, key, NULL); - if (is_intern || is_atomic) + if (is_intern) { + has_intern = TRUE; + g_key_file_set_value (keyfile, group, key, value_set); + } else if (is_atomic) g_key_file_set_value (keyfile, group, key, value_set); else { gs_free char *value_was = NULL; @@ -2113,7 +2117,7 @@ nm_config_device_state_load_all (void) if (!state) continue; - if (!g_hash_table_insert (states, GINT_TO_POINTER (ifindex), state)) + if (!nm_g_hash_table_insert (states, GINT_TO_POINTER (ifindex), state)) nm_assert_not_reached (); } g_dir_close (dir); @@ -2397,15 +2401,15 @@ _set_config_data (NMConfig *self, NMConfigData *new_data, NMConfigChangeFlags re } if (new_data) { - _LOGI ("signal: %s (%s)", + _LOGI ("config: signal %s (%s)", nm_config_change_flags_to_string (changes, NULL, 0), nm_config_data_get_config_description (new_data)); nm_config_data_log (new_data, "CONFIG: ", " ", NULL); priv->config_data = new_data; } else if (had_new_data) - _LOGI ("signal: %s (no changes from disk)", nm_config_change_flags_to_string (changes, NULL, 0)); + _LOGI ("config: signal %s (no changes from disk)", nm_config_change_flags_to_string (changes, NULL, 0)); else - _LOGI ("signal: %s", nm_config_change_flags_to_string (changes, NULL, 0)); + _LOGI ("config: signal %s", nm_config_change_flags_to_string (changes, NULL, 0)); g_signal_emit (self, signals[SIGNAL_CONFIG_CHANGED], 0, new_data ? new_data : old_data, changes, old_data); diff --git a/src/nm-config.h b/src/nm-config.h index 5d027ce0..42ab4682 100644 --- a/src/nm-config.h +++ b/src/nm-config.h @@ -57,6 +57,7 @@ #define NM_CONFIG_KEYFILE_GROUP_KEYFILE "keyfile" #define NM_CONFIG_KEYFILE_GROUP_IFUPDOWN "ifupdown" +#define NM_CONFIG_KEYFILE_GROUP_IFNET "ifnet" #define NM_CONFIG_KEYFILE_KEY_MAIN_AUTH_POLKIT "auth-polkit" #define NM_CONFIG_KEYFILE_KEY_MAIN_AUTOCONNECT_RETRIES_DEFAULT "autoconnect-retries-default" @@ -78,8 +79,6 @@ #define NM_CONFIG_KEYFILE_KEY_DEVICE_MANAGED "managed" #define NM_CONFIG_KEYFILE_KEY_DEVICE_IGNORE_CARRIER "ignore-carrier" #define NM_CONFIG_KEYFILE_KEY_DEVICE_SRIOV_NUM_VFS "sriov-num-vfs" -#define NM_CONFIG_KEYFILE_KEY_DEVICE_WIFI_BACKEND "wifi.backend" -#define NM_CONFIG_KEYFILE_KEY_DEVICE_WIFI_SCAN_RAND_MAC_ADDRESS "wifi.scan-rand-mac-address" #define NM_CONFIG_KEYFILE_KEY_DEVICE_CARRIER_WAIT_TIMEOUT "carrier-wait-timeout" #define NM_CONFIG_KEYFILE_KEYPREFIX_WAS ".was." diff --git a/src/nm-connectivity.c b/src/nm-connectivity.c index 389e72ad..8861f261 100644 --- a/src/nm-connectivity.c +++ b/src/nm-connectivity.c @@ -25,82 +25,22 @@ #include "nm-connectivity.h" #include <string.h> - -#if WITH_CONCHECK #include <curl/curl.h> -#endif -#include "c-list/src/c-list.h" #include "nm-config.h" #include "NetworkManagerUtils.h" -#define HEADER_STATUS_ONLINE "X-NetworkManager-Status: online\r\n" - /*****************************************************************************/ -NM_UTILS_LOOKUP_STR_DEFINE_STATIC (_state_to_string, int /*NMConnectivityState*/, - NM_UTILS_LOOKUP_DEFAULT_WARN ("???"), - NM_UTILS_LOOKUP_STR_ITEM (NM_CONNECTIVITY_UNKNOWN, "UNKNOWN"), - NM_UTILS_LOOKUP_STR_ITEM (NM_CONNECTIVITY_NONE, "NONE"), - NM_UTILS_LOOKUP_STR_ITEM (NM_CONNECTIVITY_LIMITED, "LIMITED"), - NM_UTILS_LOOKUP_STR_ITEM (NM_CONNECTIVITY_PORTAL, "PORTAL"), - NM_UTILS_LOOKUP_STR_ITEM (NM_CONNECTIVITY_FULL, "FULL"), - - NM_UTILS_LOOKUP_STR_ITEM (NM_CONNECTIVITY_ERROR, "ERROR"), - NM_UTILS_LOOKUP_STR_ITEM (NM_CONNECTIVITY_FAKE, "FAKE"), -); - -const char * -nm_connectivity_state_to_string (NMConnectivityState state) -{ - return _state_to_string (state); -} - -/*****************************************************************************/ - -struct _NMConnectivityCheckHandle { - CList handles_lst; - NMConnectivity *self; - NMConnectivityCheckCallback callback; - gpointer user_data; - - char *ifspec; - -#if WITH_CONCHECK - struct { - char *response; - - CURL *curl_ehandle; - struct curl_slist *request_headers; - - GString *recv_msg; - } concheck; -#endif - - guint timeout_id; -}; - -enum { - CONFIG_CHANGED, - - LAST_SIGNAL -}; - -static guint signals[LAST_SIGNAL] = { 0 }; - typedef struct { - CList handles_lst_head; char *uri; char *response; gboolean enabled; guint interval; NMConfig *config; -#if WITH_CONCHECK - struct { - CURLM *curl_mhandle; - guint curl_timer; - } concheck; -#endif + guint periodic_check_id; + CURLM *curl_mhandle; + guint curl_timer; } NMConnectivityPrivate; struct _NMConnectivity { @@ -118,6 +58,14 @@ G_DEFINE_TYPE (NMConnectivity, nm_connectivity, G_TYPE_OBJECT) NM_DEFINE_SINGLETON_GETTER (NMConnectivity, nm_connectivity_get, NM_TYPE_CONNECTIVITY); +enum { + PERIODIC_CHECK, + + LAST_SIGNAL +}; + +static guint signals[LAST_SIGNAL] = { 0 }; + /*****************************************************************************/ #define _NMLOG_DOMAIN LOGD_CONCHECK @@ -130,172 +78,116 @@ NM_DEFINE_SINGLETON_GETTER (NMConnectivity, nm_connectivity_get, NM_TYPE_CONNECT \ if (nm_logging_enabled (__level, _NMLOG2_DOMAIN)) { \ _nm_log (__level, _NMLOG2_DOMAIN, 0, \ - (cb_data->ifspec ? &cb_data->ifspec[3] : NULL), \ - NULL, \ - "connectivity: (%s) " \ - _NM_UTILS_MACRO_FIRST (__VA_ARGS__), \ - (cb_data->ifspec ? &cb_data->ifspec[3] : "") \ - _NM_UTILS_MACRO_REST (__VA_ARGS__)); \ + &cb_data->ifspec[3], NULL, \ + "connectivity: (%s) " \ + _NM_UTILS_MACRO_FIRST (__VA_ARGS__), \ + &cb_data->ifspec[3] \ + _NM_UTILS_MACRO_REST (__VA_ARGS__)); \ } \ } G_STMT_END /*****************************************************************************/ -static void -cb_data_invoke_callback (NMConnectivityCheckHandle *cb_data, - NMConnectivityState state, - GError *error, - const char *log_message) -{ - NMConnectivityCheckCallback callback; - - nm_assert (cb_data); - nm_assert (NM_IS_CONNECTIVITY (cb_data->self)); - - callback = cb_data->callback; - if (!callback) - return; - - cb_data->callback = NULL; - - nm_assert (log_message); +NM_UTILS_LOOKUP_STR_DEFINE (nm_connectivity_state_to_string, NMConnectivityState, + NM_UTILS_LOOKUP_DEFAULT_WARN ("???"), + NM_UTILS_LOOKUP_STR_ITEM (NM_CONNECTIVITY_UNKNOWN, "UNKNOWN"), + NM_UTILS_LOOKUP_STR_ITEM (NM_CONNECTIVITY_NONE, "NONE"), + NM_UTILS_LOOKUP_STR_ITEM (NM_CONNECTIVITY_LIMITED, "LIMITED"), + NM_UTILS_LOOKUP_STR_ITEM (NM_CONNECTIVITY_PORTAL, "PORTAL"), + NM_UTILS_LOOKUP_STR_ITEM (NM_CONNECTIVITY_FULL, "FULL"), +); - _LOG2D ("check completed: %s; %s", - nm_connectivity_state_to_string (state), - log_message); +/*****************************************************************************/ - callback (cb_data->self, - cb_data, - state, - error, - cb_data->user_data); -} +typedef struct { + GSimpleAsyncResult *simple; + char *response; + CURL *curl_ehandle; + size_t msg_size; + char *msg; + struct curl_slist *request_headers; + guint timeout_id; + char *ifspec; +} ConCheckCbData; static void -cb_data_free (NMConnectivityCheckHandle *cb_data, - NMConnectivityState state, - GError *error, - const char *log_message) +finish_cb_data (ConCheckCbData *cb_data, NMConnectivityState new_state) { - NMConnectivity *self; - - nm_assert (cb_data); - - self = cb_data->self; - - nm_assert (NM_IS_CONNECTIVITY (self)); - - c_list_unlink (&cb_data->handles_lst); - -#if WITH_CONCHECK - if (cb_data->concheck.curl_ehandle) { - NMConnectivityPrivate *priv; - - /* Contrary to what cURL manual claim it is *not* safe to remove - * the easy handle "at any moment"; specifically not from the - * write function. Thus here we just dissociate the cb_data from - * the easy handle and the easy handle will be cleaned up when the - * message goes to CURLMSG_DONE in curl_check_connectivity(). */ - curl_easy_setopt (cb_data->concheck.curl_ehandle, CURLOPT_WRITEFUNCTION, NULL); - curl_easy_setopt (cb_data->concheck.curl_ehandle, CURLOPT_WRITEDATA, NULL); - curl_easy_setopt (cb_data->concheck.curl_ehandle, CURLOPT_HEADERFUNCTION, NULL); - curl_easy_setopt (cb_data->concheck.curl_ehandle, CURLOPT_HEADERDATA, NULL); - curl_easy_setopt (cb_data->concheck.curl_ehandle, CURLOPT_PRIVATE, NULL); - curl_easy_setopt (cb_data->concheck.curl_ehandle, CURLOPT_HTTPHEADER, NULL); - - priv = NM_CONNECTIVITY_GET_PRIVATE (self); - - curl_multi_remove_handle (priv->concheck.curl_mhandle, cb_data->concheck.curl_ehandle); - curl_easy_cleanup (cb_data->concheck.curl_ehandle); - - curl_slist_free_all (cb_data->concheck.request_headers); - } -#endif - - nm_clear_g_source (&cb_data->timeout_id); - - cb_data_invoke_callback (cb_data, state, error, log_message); - -#if WITH_CONCHECK - g_free (cb_data->concheck.response); - if (cb_data->concheck.recv_msg) - g_string_free (cb_data->concheck.recv_msg, TRUE); -#endif + /* Contrary to what cURL manual claim it is *not* safe to remove + * the easy handle "at any moment"; specifically not from the + * write function. Thus here we just dissociate the cb_data from + * the easy handle and the easy handle will be cleaned up when the + * message goes to CURLMSG_DONE in curl_check_connectivity(). */ + curl_easy_setopt (cb_data->curl_ehandle, CURLOPT_PRIVATE, NULL); + + g_simple_async_result_set_op_res_gssize (cb_data->simple, new_state); + g_simple_async_result_complete (cb_data->simple); + g_object_unref (cb_data->simple); + curl_slist_free_all (cb_data->request_headers); + g_free (cb_data->response); + g_free (cb_data->msg); g_free (cb_data->ifspec); - g_slice_free (NMConnectivityCheckHandle, cb_data); -} - -/*****************************************************************************/ - -#if WITH_CONCHECK -static const char * -_check_handle_get_response (NMConnectivityCheckHandle *cb_data) -{ - return cb_data->concheck.response ?: NM_CONFIG_DEFAULT_CONNECTIVITY_RESPONSE; + g_source_remove (cb_data->timeout_id); + g_slice_free (ConCheckCbData, cb_data); } static void -curl_check_connectivity (CURLM *mhandle, int sockfd, int ev_bitmask) +curl_check_connectivity (CURLM *mhandle, CURLMcode ret) { - NMConnectivityCheckHandle *cb_data; + ConCheckCbData *cb_data; CURLMsg *msg; CURLcode eret; gint m_left; - long response_code; - CURLMcode ret; - int running_handles; - ret = curl_multi_socket_action (mhandle, sockfd, ev_bitmask, &running_handles); if (ret != CURLM_OK) - _LOGE ("connectivity check failed: %d", ret); + _LOGW ("connectivity check failed"); while ((msg = curl_multi_info_read (mhandle, &m_left))) { - if (msg->msg != CURLMSG_DONE) continue; /* Here we have completed a session. Check easy session result. */ eret = curl_easy_getinfo (msg->easy_handle, CURLINFO_PRIVATE, (char **) &cb_data); if (eret != CURLE_OK) { - _LOGE ("curl cannot extract cb_data for easy handle, skipping msg"); + _LOG2E ("curl cannot extract cb_data for easy handle %p, skipping msg", msg->easy_handle); continue; } - if (!cb_data->callback) { - /* callback was already invoked earlier. */ - cb_data_free (cb_data, NM_CONNECTIVITY_UNKNOWN, NULL, NULL); - } else if (msg->data.result != CURLE_OK) { - gs_free char *log_message = NULL; - - log_message = g_strdup_printf ("check failed with curl status %d", msg->data.result); - cb_data_free (cb_data, NM_CONNECTIVITY_LIMITED, NULL, - log_message); - } else if ( !((_check_handle_get_response (cb_data))[0]) - && (curl_easy_getinfo (msg->easy_handle, CURLINFO_RESPONSE_CODE, &response_code) == CURLE_OK) - && response_code == 204) { - /* If we got a 204 response code (no content) and we actually - * requested no content, report full connectivity. */ - cb_data_free (cb_data, NM_CONNECTIVITY_FULL, NULL, - "no content, as expected"); - } else { - /* If we get here, it means that easy_write_cb() didn't read enough - * bytes to be able to do a match, or that we were asking for no content - * (204 response code) and we actually got some. Either way, that is - * an indication of a captive portal */ - cb_data_free (cb_data, NM_CONNECTIVITY_PORTAL, NULL, - "unexpected short response"); + if (cb_data) { + /* If cb_data is still there this message hasn't been + * taken care of. Do so now. */ + if (msg->data.result == CURLE_OK) { + /* If we get here, it means that easy_write_cb() didn't read enough + * bytes to be able to do a match. */ + _LOG2I ("response shorter than expected '%s'; assuming captive portal.", + cb_data->response); + finish_cb_data (cb_data, NM_CONNECTIVITY_PORTAL); + } else { + _LOG2D ("check failed (%d)", msg->data.result); + finish_cb_data (cb_data, NM_CONNECTIVITY_LIMITED); + } } + + curl_multi_remove_handle (mhandle, msg->easy_handle); + curl_easy_cleanup (msg->easy_handle); } } static gboolean curl_timeout_cb (gpointer user_data) { - gs_unref_object NMConnectivity *self = g_object_ref (NM_CONNECTIVITY (user_data)); + NMConnectivity *self = NM_CONNECTIVITY (user_data); NMConnectivityPrivate *priv = NM_CONNECTIVITY_GET_PRIVATE (self); + CURLMcode ret; + int pending_conn; + + priv->curl_timer = 0; + + ret = curl_multi_socket_action (priv->curl_mhandle, CURL_SOCKET_TIMEOUT, 0, &pending_conn); + _LOGT ("timeout elapsed - multi_socket_action (%d conn remaining)", pending_conn); + + curl_check_connectivity (priv->curl_mhandle, ret); - priv->concheck.curl_timer = 0; - curl_check_connectivity (priv->concheck.curl_mhandle, CURL_SOCKET_TIMEOUT, 0); return G_SOURCE_REMOVE; } @@ -305,17 +197,21 @@ multi_timer_cb (CURLM *multi, long timeout_ms, void *userdata) NMConnectivity *self = NM_CONNECTIVITY (userdata); NMConnectivityPrivate *priv = NM_CONNECTIVITY_GET_PRIVATE (self); - nm_clear_g_source (&priv->concheck.curl_timer); + nm_clear_g_source (&priv->curl_timer); if (timeout_ms != -1) - priv->concheck.curl_timer = g_timeout_add (timeout_ms, curl_timeout_cb, self); + priv->curl_timer = g_timeout_add (timeout_ms, curl_timeout_cb, self); + return 0; } static gboolean -curl_socketevent_cb (GIOChannel *ch, GIOCondition condition, gpointer user_data) +curl_socketevent_cb (GIOChannel *ch, GIOCondition condition, gpointer data) { - gs_unref_object NMConnectivity *self = g_object_ref (NM_CONNECTIVITY (user_data)); + NMConnectivity *self = NM_CONNECTIVITY (data); NMConnectivityPrivate *priv = NM_CONNECTIVITY_GET_PRIVATE (self); + CURLMcode ret; + int pending_conn = 0; + gboolean bret = TRUE; int fd = g_io_channel_unix_get_fd (ch); int action = 0; @@ -323,11 +219,16 @@ curl_socketevent_cb (GIOChannel *ch, GIOCondition condition, gpointer user_data) action |= CURL_CSELECT_IN; if (condition & G_IO_OUT) action |= CURL_CSELECT_OUT; - if (condition & G_IO_ERR) - action |= CURL_CSELECT_ERR; - curl_check_connectivity (priv->concheck.curl_mhandle, fd, action); - return G_SOURCE_CONTINUE; + ret = curl_multi_socket_action (priv->curl_mhandle, fd, 0, &pending_conn); + + curl_check_connectivity (priv->curl_mhandle, ret); + + if (pending_conn == 0) { + nm_clear_g_source (&priv->curl_timer); + bret = FALSE; + } + return bret; } typedef struct { @@ -340,12 +241,11 @@ multi_socket_cb (CURL *e_handle, curl_socket_t s, int what, void *userdata, void { NMConnectivity *self = NM_CONNECTIVITY (userdata); NMConnectivityPrivate *priv = NM_CONNECTIVITY_GET_PRIVATE (self); - CurlSockData *fdp = socketp; + CurlSockData *fdp = (CurlSockData *) socketp; GIOCondition condition = 0; if (what == CURL_POLL_REMOVE) { if (fdp) { - curl_multi_assign (priv->concheck.curl_mhandle, s, NULL); nm_clear_g_source (&fdp->ev); g_io_channel_unref (fdp->ch); g_slice_free (CurlSockData, fdp); @@ -354,7 +254,6 @@ multi_socket_cb (CURL *e_handle, curl_socket_t s, int what, void *userdata, void if (!fdp) { fdp = g_slice_new0 (CurlSockData); fdp->ch = g_io_channel_unix_new (s); - curl_multi_assign (priv->concheck.curl_mhandle, s, fdp); } else nm_clear_g_source (&fdp->ev); @@ -362,26 +261,29 @@ multi_socket_cb (CURL *e_handle, curl_socket_t s, int what, void *userdata, void condition = G_IO_IN; else if (what == CURL_POLL_OUT) condition = G_IO_OUT; - else if (what == CURL_POLL_INOUT) + else if (condition == CURL_POLL_INOUT) condition = G_IO_IN | G_IO_OUT; if (condition) fdp->ev = g_io_add_watch (fdp->ch, condition, curl_socketevent_cb, self); + curl_multi_assign (priv->curl_mhandle, s, fdp); } return CURLM_OK; } +#define HEADER_STATUS_ONLINE "X-NetworkManager-Status: online\r\n" + static size_t easy_header_cb (char *buffer, size_t size, size_t nitems, void *userdata) { - NMConnectivityCheckHandle *cb_data = userdata; + ConCheckCbData *cb_data = userdata; size_t len = size * nitems; if ( len >= sizeof (HEADER_STATUS_ONLINE) - 1 && !g_ascii_strncasecmp (buffer, HEADER_STATUS_ONLINE, sizeof (HEADER_STATUS_ONLINE) - 1)) { - cb_data_invoke_callback (cb_data, NM_CONNECTIVITY_FULL, - NULL, "status header found"); + _LOG2D ("status header found, check successful"); + finish_cb_data (cb_data, NM_CONNECTIVITY_FULL); return 0; } @@ -391,26 +293,23 @@ easy_header_cb (char *buffer, size_t size, size_t nitems, void *userdata) static size_t easy_write_cb (void *buffer, size_t size, size_t nmemb, void *userdata) { - NMConnectivityCheckHandle *cb_data = userdata; + ConCheckCbData *cb_data = userdata; size_t len = size * nmemb; - const char *response = _check_handle_get_response (cb_data);; - - if (!cb_data->concheck.recv_msg) - cb_data->concheck.recv_msg = g_string_sized_new (len + 10); - g_string_append_len (cb_data->concheck.recv_msg, buffer, len); + cb_data->msg = g_realloc (cb_data->msg, cb_data->msg_size + len); + memcpy (cb_data->msg + cb_data->msg_size, buffer, len); + cb_data->msg_size += len; - if ( response - && cb_data->concheck.recv_msg->len >= strlen (response)) { + if (cb_data->msg_size >= strlen (cb_data->response)) { /* We already have enough data -- check response */ - if (g_str_has_prefix (cb_data->concheck.recv_msg->str, response)) { - cb_data_invoke_callback (cb_data, NM_CONNECTIVITY_FULL, NULL, - "expected response"); + if (g_str_has_prefix (cb_data->msg, cb_data->response)) { + _LOG2D ("check successful."); + finish_cb_data (cb_data, NM_CONNECTIVITY_FULL); } else { - cb_data_invoke_callback (cb_data, NM_CONNECTIVITY_PORTAL, NULL, - "unexpected response"); + _LOG2I ("response did not match expected response '%s'; assuming captive portal.", + cb_data->response); + finish_cb_data (cb_data, NM_CONNECTIVITY_PORTAL); } - return 0; } @@ -418,139 +317,105 @@ easy_write_cb (void *buffer, size_t size, size_t nmemb, void *userdata) } static gboolean -_timeout_cb (gpointer user_data) -{ - NMConnectivityCheckHandle *cb_data = user_data; - NMConnectivity *self; - - nm_assert (NM_IS_CONNECTIVITY (cb_data->self)); - - self = cb_data->self; - - nm_assert (c_list_contains (&NM_CONNECTIVITY_GET_PRIVATE (self)->handles_lst_head, &cb_data->handles_lst)); - - cb_data_free (cb_data, NM_CONNECTIVITY_LIMITED, NULL, "timeout"); - return G_SOURCE_REMOVE; -} -#endif - -static gboolean -_idle_cb (gpointer user_data) +timeout_cb (gpointer user_data) { - NMConnectivityCheckHandle *cb_data = user_data; - - nm_assert (NM_IS_CONNECTIVITY (cb_data->self)); - nm_assert (c_list_contains (&NM_CONNECTIVITY_GET_PRIVATE (cb_data->self)->handles_lst_head, &cb_data->handles_lst)); + ConCheckCbData *cb_data = user_data; + NMConnectivity *self = NM_CONNECTIVITY (g_async_result_get_source_object (G_ASYNC_RESULT (cb_data->simple))); + NMConnectivityPrivate *priv = NM_CONNECTIVITY_GET_PRIVATE (self); + CURL *ehandle = cb_data->curl_ehandle; - cb_data->timeout_id = 0; - if (!cb_data->ifspec) { - gs_free_error GError *error = NULL; + _LOG2I ("timed out"); + finish_cb_data (cb_data, NM_CONNECTIVITY_LIMITED); + curl_multi_remove_handle (priv->curl_mhandle, ehandle); + curl_easy_cleanup (ehandle); - /* the invocation was with an invalid ifname. It is a fail. */ - g_set_error (&error, NM_UTILS_ERROR, NM_UTILS_ERROR_INVALID_ARGUMENT, - "no interface specified for connectivity check"); - cb_data_free (cb_data, NM_CONNECTIVITY_ERROR, NULL, "missing interface"); - } else - cb_data_free (cb_data, NM_CONNECTIVITY_FAKE, NULL, "fake result"); return G_SOURCE_REMOVE; } -NMConnectivityCheckHandle * -nm_connectivity_check_start (NMConnectivity *self, - const char *iface, - NMConnectivityCheckCallback callback, - gpointer user_data) +void +nm_connectivity_check_async (NMConnectivity *self, + const char *iface, + GAsyncReadyCallback callback, + gpointer user_data) { NMConnectivityPrivate *priv; - NMConnectivityCheckHandle *cb_data; - - g_return_val_if_fail (NM_IS_CONNECTIVITY (self), NULL); - g_return_val_if_fail (!iface || iface[0], NULL); - g_return_val_if_fail (callback, NULL); + GSimpleAsyncResult *simple; + CURL *ehandle = NULL; + g_return_if_fail (NM_IS_CONNECTIVITY (self)); priv = NM_CONNECTIVITY_GET_PRIVATE (self); - cb_data = g_slice_new0 (NMConnectivityCheckHandle); - cb_data->self = self; - c_list_link_tail (&priv->handles_lst_head, &cb_data->handles_lst); - cb_data->callback = callback; - cb_data->user_data = user_data; + simple = g_simple_async_result_new (G_OBJECT (self), callback, user_data, + nm_connectivity_check_async); - if (iface) - cb_data->ifspec = g_strdup_printf ("if!%s", iface); + if (priv->enabled) + ehandle = curl_easy_init (); -#if WITH_CONCHECK - if (iface) { - CURL *ehandle; - - if ( priv->enabled - && (ehandle = curl_easy_init ())) { - - cb_data->concheck.response = g_strdup (priv->response); - cb_data->concheck.curl_ehandle = ehandle; - cb_data->concheck.request_headers = curl_slist_append (NULL, "Connection: close"); - curl_easy_setopt (ehandle, CURLOPT_URL, priv->uri); - curl_easy_setopt (ehandle, CURLOPT_WRITEFUNCTION, easy_write_cb); - curl_easy_setopt (ehandle, CURLOPT_WRITEDATA, cb_data); - curl_easy_setopt (ehandle, CURLOPT_HEADERFUNCTION, easy_header_cb); - curl_easy_setopt (ehandle, CURLOPT_HEADERDATA, cb_data); - curl_easy_setopt (ehandle, CURLOPT_PRIVATE, cb_data); - curl_easy_setopt (ehandle, CURLOPT_HTTPHEADER, cb_data->concheck.request_headers); - curl_easy_setopt (ehandle, CURLOPT_INTERFACE, cb_data->ifspec); - curl_multi_add_handle (priv->concheck.curl_mhandle, ehandle); - - cb_data->timeout_id = g_timeout_add_seconds (20, _timeout_cb, cb_data); - - _LOG2D ("start request to '%s'", priv->uri); - return cb_data; - } + if (ehandle) { + ConCheckCbData *cb_data = g_slice_new0 (ConCheckCbData); + + cb_data->curl_ehandle = ehandle; + cb_data->request_headers = curl_slist_append (NULL, "Connection: close"); + cb_data->ifspec = g_strdup_printf ("if!%s", iface); + cb_data->simple = simple; + if (priv->response) + cb_data->response = g_strdup (priv->response); + else + cb_data->response = g_strdup (NM_CONFIG_DEFAULT_CONNECTIVITY_RESPONSE); + + curl_easy_setopt (ehandle, CURLOPT_URL, priv->uri); + curl_easy_setopt (ehandle, CURLOPT_WRITEFUNCTION, easy_write_cb); + curl_easy_setopt (ehandle, CURLOPT_WRITEDATA, cb_data); + curl_easy_setopt (ehandle, CURLOPT_HEADERFUNCTION, easy_header_cb); + curl_easy_setopt (ehandle, CURLOPT_HEADERDATA, cb_data); + curl_easy_setopt (ehandle, CURLOPT_PRIVATE, cb_data); + curl_easy_setopt (ehandle, CURLOPT_HTTPHEADER, cb_data->request_headers); + curl_easy_setopt (ehandle, CURLOPT_INTERFACE, cb_data->ifspec); + curl_multi_add_handle (priv->curl_mhandle, ehandle); + + cb_data->timeout_id = g_timeout_add_seconds (30, timeout_cb, cb_data); + + _LOG2D ("sending request to '%s'", priv->uri); + return; + } else { + _LOGD ("(%s) faking request. Connectivity check disabled", iface); } -#endif - _LOG2D ("start fake request"); - cb_data->timeout_id = g_idle_add (_idle_cb, cb_data); - return cb_data; + g_simple_async_result_set_op_res_gssize (simple, NM_CONNECTIVITY_UNKNOWN); + g_simple_async_result_complete_in_idle (simple); + g_object_unref (simple); } -void -nm_connectivity_check_cancel (NMConnectivityCheckHandle *cb_data) +NMConnectivityState +nm_connectivity_check_finish (NMConnectivity *self, + GAsyncResult *result, + GError **error) { - NMConnectivity *self; - gs_free_error GError *error = NULL; - - g_return_if_fail (cb_data); - - self = cb_data->self; + GSimpleAsyncResult *simple; - g_return_if_fail (NM_IS_CONNECTIVITY (self)); - g_return_if_fail (!c_list_is_empty (&cb_data->handles_lst)); - g_return_if_fail (cb_data->callback); - - nm_assert (c_list_contains (&NM_CONNECTIVITY_GET_PRIVATE (self)->handles_lst_head, &cb_data->handles_lst)); - - nm_utils_error_set_cancelled (&error, FALSE, "NMConnectivity"); + g_return_val_if_fail (g_simple_async_result_is_valid (result, G_OBJECT (self), nm_connectivity_check_async), NM_CONNECTIVITY_UNKNOWN); - cb_data_free (cb_data, NM_CONNECTIVITY_ERROR, error, "cancelled"); + simple = G_SIMPLE_ASYNC_RESULT (result); + if (g_simple_async_result_propagate_error (simple, error)) + return NM_CONNECTIVITY_UNKNOWN; + return (NMConnectivityState) g_simple_async_result_get_op_res_gssize (simple); } -/*****************************************************************************/ - gboolean nm_connectivity_check_enabled (NMConnectivity *self) { - g_return_val_if_fail (NM_IS_CONNECTIVITY (self), FALSE); + NMConnectivityPrivate *priv = NM_CONNECTIVITY_GET_PRIVATE (self); - return NM_CONNECTIVITY_GET_PRIVATE (self)->enabled; + return priv->enabled; } /*****************************************************************************/ -guint -nm_connectivity_get_interval (NMConnectivity *self) +static gboolean +periodic_check (gpointer user_data) { - return nm_connectivity_check_enabled (self) - ? NM_CONNECTIVITY_GET_PRIVATE (self)->interval - : 0; + g_signal_emit (NM_CONNECTIVITY (user_data), signals[PERIODIC_CHECK], 0); + return G_SOURCE_CONTINUE; } static void @@ -590,22 +455,18 @@ update_config (NMConnectivity *self, NMConfigData *config_data) /* Set the interval. */ interval = nm_config_data_get_connectivity_interval (config_data); - interval = MIN (interval, (7 * 24 * 3600)); if (priv->interval != interval) { priv->interval = interval; changed = TRUE; } - enabled = FALSE; -#if WITH_CONCHECK + /* Set enabled flag. */ + enabled = nm_config_data_get_connectivity_enabled (config_data); /* connectivity checking also requires a valid URI, interval and * curl_mhandle */ - if ( priv->uri - && priv->interval - && priv->concheck.curl_mhandle) - enabled = nm_config_data_get_connectivity_enabled (config_data); -#endif - + if (!(priv->uri && priv->interval && priv->curl_mhandle)) { + enabled = FALSE; + } if (priv->enabled != enabled) { priv->enabled = enabled; changed = TRUE; @@ -613,7 +474,7 @@ update_config (NMConnectivity *self, NMConfigData *config_data) /* Set the response. */ response = nm_config_data_get_connectivity_response (config_data); - if (!nm_streq0 (response, priv->response)) { + if (g_strcmp0 (response, priv->response) != 0) { /* a response %NULL means, NM_CONFIG_DEFAULT_CONNECTIVITY_RESPONSE. Any other response * (including "") is accepted. */ g_free (priv->response); @@ -621,8 +482,11 @@ update_config (NMConnectivity *self, NMConfigData *config_data) changed = TRUE; } - if (changed) - g_signal_emit (self, signals[CONFIG_CHANGED], 0); + if (changed) { + nm_clear_g_source (&priv->periodic_check_id); + if (nm_connectivity_check_enabled (self)) + priv->periodic_check_id = g_timeout_add_seconds (priv->interval, periodic_check, self); + } } static void @@ -635,37 +499,34 @@ config_changed_cb (NMConfig *config, update_config (self, config_data); } -/*****************************************************************************/ - static void nm_connectivity_init (NMConnectivity *self) { NMConnectivityPrivate *priv = NM_CONNECTIVITY_GET_PRIVATE (self); + CURLcode retv; - c_list_init (&priv->handles_lst_head); + retv = curl_global_init (CURL_GLOBAL_ALL); + if (retv == CURLE_OK) + priv->curl_mhandle = curl_multi_init (); + + if (!priv->curl_mhandle) + _LOGE ("unable to init cURL, connectivity check will not work"); + else { + curl_multi_setopt (priv->curl_mhandle, CURLMOPT_SOCKETFUNCTION, multi_socket_cb); + curl_multi_setopt (priv->curl_mhandle, CURLMOPT_SOCKETDATA, self); + curl_multi_setopt (priv->curl_mhandle, CURLMOPT_TIMERFUNCTION, multi_timer_cb); + curl_multi_setopt (priv->curl_mhandle, CURLMOPT_TIMERDATA, self); + curl_multi_setopt (priv->curl_mhandle, CURLOPT_VERBOSE, 1); + } priv->config = g_object_ref (nm_config_get ()); + + update_config (self, nm_config_get_data (priv->config)); g_signal_connect (G_OBJECT (priv->config), NM_CONFIG_SIGNAL_CONFIG_CHANGED, G_CALLBACK (config_changed_cb), self); -#if WITH_CONCHECK - if (curl_global_init (CURL_GLOBAL_ALL) == CURLE_OK) - priv->concheck.curl_mhandle = curl_multi_init (); - - if (!priv->concheck.curl_mhandle) - _LOGE ("unable to init cURL, connectivity check will not work"); - else { - curl_multi_setopt (priv->concheck.curl_mhandle, CURLMOPT_SOCKETFUNCTION, multi_socket_cb); - curl_multi_setopt (priv->concheck.curl_mhandle, CURLMOPT_SOCKETDATA, self); - curl_multi_setopt (priv->concheck.curl_mhandle, CURLMOPT_TIMERFUNCTION, multi_timer_cb); - curl_multi_setopt (priv->concheck.curl_mhandle, CURLMOPT_TIMERDATA, self); - curl_multi_setopt (priv->concheck.curl_mhandle, CURLOPT_VERBOSE, 1); - } -#endif - - update_config (self, nm_config_get_data (priv->config)); } static void @@ -673,33 +534,19 @@ dispose (GObject *object) { NMConnectivity *self = NM_CONNECTIVITY (object); NMConnectivityPrivate *priv = NM_CONNECTIVITY_GET_PRIVATE (self); - NMConnectivityCheckHandle *cb_data; - GError *error = NULL; - -again: - c_list_for_each_entry (cb_data, &priv->handles_lst_head, handles_lst) { - if (!error) - nm_utils_error_set_cancelled (&error, TRUE, "NMConnectivity"); - cb_data_free (cb_data, NM_CONNECTIVITY_ERROR, error, "shutting down"); - goto again; - } - g_clear_error (&error); g_clear_pointer (&priv->uri, g_free); g_clear_pointer (&priv->response, g_free); -#if WITH_CONCHECK - nm_clear_g_source (&priv->concheck.curl_timer); - - curl_multi_cleanup (priv->concheck.curl_mhandle); - curl_global_cleanup (); -#endif - if (priv->config) { g_signal_handlers_disconnect_by_func (priv->config, config_changed_cb, self); g_clear_object (&priv->config); } + curl_multi_cleanup (priv->curl_mhandle); + curl_global_cleanup (); + nm_clear_g_source (&priv->periodic_check_id); + G_OBJECT_CLASS (nm_connectivity_parent_class)->dispose (object); } @@ -708,8 +555,8 @@ nm_connectivity_class_init (NMConnectivityClass *klass) { GObjectClass *object_class = G_OBJECT_CLASS (klass); - signals[CONFIG_CHANGED] = - g_signal_new (NM_CONNECTIVITY_CONFIG_CHANGED, + signals[PERIODIC_CHECK] = + g_signal_new (NM_CONNECTIVITY_PERIODIC_CHECK, G_OBJECT_CLASS_TYPE (object_class), G_SIGNAL_RUN_FIRST, 0, NULL, NULL, NULL, diff --git a/src/nm-connectivity.h b/src/nm-connectivity.h index df9295e0..d9a9f233 100644 --- a/src/nm-connectivity.h +++ b/src/nm-connectivity.h @@ -24,9 +24,6 @@ #include "nm-dbus-interface.h" -#define NM_CONNECTIVITY_ERROR ((NMConnectivityState) -1) -#define NM_CONNECTIVITY_FAKE ((NMConnectivityState) -2) - #define NM_TYPE_CONNECTIVITY (nm_connectivity_get_type ()) #define NM_CONNECTIVITY(obj) (G_TYPE_CHECK_INSTANCE_CAST ((obj), NM_TYPE_CONNECTIVITY, NMConnectivity)) #define NM_CONNECTIVITY_CLASS(klass) (G_TYPE_CHECK_CLASS_CAST ((klass), NM_TYPE_CONNECTIVITY, NMConnectivityClass)) @@ -34,7 +31,7 @@ #define NM_IS_CONNECTIVITY_CLASS(klass) (G_TYPE_CHECK_CLASS_TYPE ((klass), NM_TYPE_CONNECTIVITY)) #define NM_CONNECTIVITY_GET_CLASS(obj) (G_TYPE_INSTANCE_GET_CLASS ((obj), NM_TYPE_CONNECTIVITY, NMConnectivityClass)) -#define NM_CONNECTIVITY_CONFIG_CHANGED "config-changed" +#define NM_CONNECTIVITY_PERIODIC_CHECK "nm-connectivity-periodic-check" typedef struct _NMConnectivityClass NMConnectivityClass; @@ -44,23 +41,13 @@ NMConnectivity *nm_connectivity_get (void); const char *nm_connectivity_state_to_string (NMConnectivityState state); +void nm_connectivity_check_async (NMConnectivity *self, + const char *iface, + GAsyncReadyCallback callback, + gpointer user_data); +NMConnectivityState nm_connectivity_check_finish (NMConnectivity *self, + GAsyncResult *result, + GError **error); gboolean nm_connectivity_check_enabled (NMConnectivity *self); -guint nm_connectivity_get_interval (NMConnectivity *self); - -typedef struct _NMConnectivityCheckHandle NMConnectivityCheckHandle; - -typedef void (*NMConnectivityCheckCallback) (NMConnectivity *self, - NMConnectivityCheckHandle *handle, - NMConnectivityState state, - GError *error, - gpointer user_data); - -NMConnectivityCheckHandle *nm_connectivity_check_start (NMConnectivity *self, - const char *iface, - NMConnectivityCheckCallback callback, - gpointer user_data); - -void nm_connectivity_check_cancel (NMConnectivityCheckHandle *handle); - #endif /* __NETWORKMANAGER_CONNECTIVITY_H__ */ diff --git a/src/nm-core-utils.c b/src/nm-core-utils.c index b97be0b8..f6b33a14 100644 --- a/src/nm-core-utils.c +++ b/src/nm-core-utils.c @@ -452,6 +452,83 @@ nm_utils_modprobe (GError **error, gboolean suppress_error_logging, const char * return exit_status; } +/** + * nm_utils_get_start_time_for_pid: + * @pid: the process identifier + * @out_state: return the state character, like R, S, Z. See `man 5 proc`. + * @out_ppid: parent process id + * + * Originally copied from polkit source (src/polkit/polkitunixprocess.c) + * and adjusted. + * + * Returns: the timestamp when the process started (by parsing /proc/$PID/stat). + * If an error occurs (e.g. the process does not exist), 0 is returned. + * + * The returned start time counts since boot, in the unit HZ (with HZ usually being (1/100) seconds) + **/ +guint64 +nm_utils_get_start_time_for_pid (pid_t pid, char *out_state, pid_t *out_ppid) +{ + guint64 start_time; + char filename[256]; + gs_free gchar *contents = NULL; + size_t length; + gs_strfreev gchar **tokens = NULL; + guint num_tokens; + gchar *p; + char state = ' '; + gint64 ppid = 0; + + start_time = 0; + contents = NULL; + + g_return_val_if_fail (pid > 0, 0); + + nm_sprintf_buf (filename, "/proc/%"G_GUINT64_FORMAT"/stat", (guint64) pid); + + if (!g_file_get_contents (filename, &contents, &length, NULL)) + goto fail; + + /* start time is the token at index 19 after the '(process name)' entry - since only this + * field can contain the ')' character, search backwards for this to avoid malicious + * processes trying to fool us + */ + p = strrchr (contents, ')'); + if (p == NULL) + goto fail; + p += 2; /* skip ') ' */ + if (p - contents >= (int) length) + goto fail; + + state = p[0]; + + tokens = g_strsplit (p, " ", 0); + + num_tokens = g_strv_length (tokens); + + if (num_tokens < 20) + goto fail; + + if (out_ppid) { + ppid = _nm_utils_ascii_str_to_int64 (tokens[1], 10, 1, G_MAXINT, 0); + if (ppid == 0) + goto fail; + } + + start_time = _nm_utils_ascii_str_to_int64 (tokens[19], 10, 1, G_MAXINT64, 0); + if (start_time == 0) + goto fail; + + NM_SET_OUT (out_state, state); + NM_SET_OUT (out_ppid, ppid); + return start_time; + +fail: + NM_SET_OUT (out_state, ' '); + NM_SET_OUT (out_ppid, 0); + return 0; +} + /*****************************************************************************/ typedef struct { @@ -1169,8 +1246,8 @@ typedef struct { static gboolean match_device_s390_subchannels_parse (const char *s390_subchannels, guint32 *out_a, guint32 *out_b, guint32 *out_c) { - char buf[30 + 1]; - const int BUFSIZE = G_N_ELEMENTS (buf) - 1; + const int BUFSIZE = 30; + char buf[BUFSIZE + 1]; guint i = 0; char *pa = NULL, *pb = NULL, *pc = NULL; gint64 a, b, c; @@ -1800,6 +1877,110 @@ nm_utils_new_infiniband_name (char *name, const char *parent_name, int p_key) /*****************************************************************************/ +gboolean +nm_utils_resolve_conf_parse (int addr_family, + const char *rc_contents, + GArray *nameservers, + GPtrArray *dns_options) +{ + guint i; + gboolean changed = FALSE; + gs_free const char **lines = NULL; + gsize l; + + g_return_val_if_fail (rc_contents, FALSE); + g_return_val_if_fail (nameservers, FALSE); + g_return_val_if_fail ( ( addr_family == AF_INET + && g_array_get_element_size (nameservers) == sizeof (in_addr_t)) + || ( addr_family == AF_INET6 + && g_array_get_element_size (nameservers) == sizeof (struct in6_addr)), FALSE); + + lines = nm_utils_strsplit_set (rc_contents, "\r\n"); + if (!lines) + return FALSE; + +/* like glibc's MATCH() macro in resolv/res_init.c. */ +#define RC_MATCH(line, option, out_arg) \ + ({ \ + const char *const _line = (line); \ + gboolean _match = FALSE; \ + \ + if ( (strncmp (_line, option, NM_STRLEN (option)) == 0) \ + && (NM_IN_SET (_line[NM_STRLEN (option)], ' ', '\t'))) { \ + _match = TRUE;\ + (out_arg) = &_line[NM_STRLEN (option) + 1]; \ + } \ + _match; \ + }) + + for (l = 0; lines[l]; l++) { + const char *const line = lines[l]; + const char *s = NULL; + + if (RC_MATCH (line, "nameserver", s)) { + gs_free char *s_cpy = NULL; + NMIPAddr ns; + + s = nm_strstrip_avoid_copy (s, &s_cpy); + if (inet_pton (addr_family, s, &ns) != 1) + continue; + + if (addr_family == AF_INET) { + if (!ns.addr4) + continue; + for (i = 0; i < nameservers->len; i++) { + if (g_array_index (nameservers, guint32, i) == ns.addr4) + break; + } + } else { + if (IN6_IS_ADDR_UNSPECIFIED (&ns.addr6)) + continue; + for (i = 0; i < nameservers->len; i++) { + struct in6_addr *t = &g_array_index (nameservers, struct in6_addr, i); + + if (IN6_ARE_ADDR_EQUAL (t, &ns.addr6)) + break; + } + } + + if (i == nameservers->len) { + g_array_append_val (nameservers, ns); + changed = TRUE; + } + continue; + } + + if (RC_MATCH (line, "options", s)) { + if (!dns_options) + continue; + + s = nm_str_skip_leading_spaces (s); + if (s[0]) { + gs_free const char **tokens = NULL; + gsize i_tokens; + + tokens = nm_utils_strsplit_set (s, " \t"); + for (i_tokens = 0; tokens && tokens[i_tokens]; i_tokens++) { + gs_free char *t = g_strstrip (g_strdup (tokens[i_tokens])); + + if ( _nm_utils_dns_option_validate (t, NULL, NULL, + addr_family == AF_INET6, + _nm_utils_dns_option_descs) + && _nm_utils_dns_option_find_idx (dns_options, t) < 0) { + g_ptr_array_add (dns_options, g_steal_pointer (&t)); + changed = TRUE; + } + } + } + continue; + } + } + + return changed; +} + +/*****************************************************************************/ + /** * nm_utils_cmp_connection_by_autoconnect_priority: * @a: @@ -2157,13 +2338,7 @@ _log_connection_sort_names (LogConnectionSettingData *setting_data, GArray *sort } void -nm_utils_log_connection_diff (NMConnection *connection, - NMConnection *diff_base, - guint32 level, - guint64 domain, - const char *name, - const char *prefix, - const char *dbus_path) +nm_utils_log_connection_diff (NMConnection *connection, NMConnection *diff_base, guint32 level, guint64 domain, const char *name, const char *prefix) { GHashTable *connection_diff = NULL; GArray *sorted_hashes; @@ -2239,6 +2414,7 @@ nm_utils_log_connection_diff (NMConnection *connection, if (print_header) { GError *err_verify = NULL; + const char *path = nm_connection_get_path (connection); const char *t1, *t2; t1 = nm_connection_get_connection_type (connection); @@ -2248,12 +2424,12 @@ nm_utils_log_connection_diff (NMConnection *connection, prefix, name, connection, G_OBJECT_TYPE_NAME (connection), NM_PRINT_FMT_QUOTE_STRING (t1), diff_base, G_OBJECT_TYPE_NAME (diff_base), NM_PRINT_FMT_QUOTE_STRING (t2), - NM_PRINT_FMT_QUOTED (dbus_path, " [", dbus_path, "]", "")); + NM_PRINT_FMT_QUOTED (path, " [", path, "]", "")); } else { nm_log (level, domain, NULL, NULL, "%sconnection '%s' (%p/%s/%s%s%s):%s%s%s", prefix, name, connection, G_OBJECT_TYPE_NAME (connection), NM_PRINT_FMT_QUOTE_STRING (t1), - NM_PRINT_FMT_QUOTED (dbus_path, " [", dbus_path, "]", "")); + NM_PRINT_FMT_QUOTED (path, " [", path, "]", "")); } print_header = FALSE; @@ -2571,7 +2747,7 @@ _get_contents_error (GError **error, int errsv, const char *format, ...) /** * nm_utils_fd_get_contents: * @fd: open file descriptor to read. The fd will not be closed, - * but don't rely on its state afterwards. + * but don't rely on it's state afterwards. * @close_fd: if %TRUE, @fd will be closed by the function. * Passing %TRUE here might safe a syscall for dup(). * @max_length: allocate at most @max_length bytes. If the @@ -3573,8 +3749,7 @@ nm_utils_setpgid (gpointer unused G_GNUC_UNUSED) /** * nm_utils_g_value_set_strv: * @value: a #GValue, initialized to store a #G_TYPE_STRV - * @strings: a #GPtrArray of strings. %NULL values are not - * allowed. + * @strings: a #GPtrArray of strings * * Converts @strings to a #GStrv and stores it in @value. */ @@ -3582,13 +3757,11 @@ void nm_utils_g_value_set_strv (GValue *value, GPtrArray *strings) { char **strv; - guint i; + int i; strv = g_new (char *, strings->len + 1); - for (i = 0; i < strings->len; i++) { - nm_assert (strings->pdata[i]); + for (i = 0; i < strings->len; i++) strv[i] = g_strdup (strings->pdata[i]); - } strv[i] = NULL; g_value_take_boxed (value, strv); @@ -3718,11 +3891,12 @@ nm_utils_lifetime_rebase_relative_time_on_now (guint32 timestamp, return t; } -guint32 +gboolean nm_utils_lifetime_get (guint32 timestamp, guint32 lifetime, guint32 preferred, gint32 now, + guint32 *out_lifetime, guint32 *out_preferred) { guint32 t_lifetime, t_preferred; @@ -3730,39 +3904,38 @@ nm_utils_lifetime_get (guint32 timestamp, nm_assert (now >= 0); if (timestamp == 0 && lifetime == 0) { - /* We treat lifetime==0 && timestamp==0 addresses as permanent addresses to allow easy + /* We treat lifetime==0 && timestamp == 0 addresses as permanent addresses to allow easy * creation of such addresses (without requiring to set the lifetime fields to * NM_PLATFORM_LIFETIME_PERMANENT). The real lifetime==0 addresses (E.g. DHCP6 telling us * to drop an address will have timestamp set. */ - NM_SET_OUT (out_preferred, NM_PLATFORM_LIFETIME_PERMANENT); - g_return_val_if_fail (preferred == 0, NM_PLATFORM_LIFETIME_PERMANENT); - return NM_PLATFORM_LIFETIME_PERMANENT; - } + *out_lifetime = NM_PLATFORM_LIFETIME_PERMANENT; + *out_preferred = NM_PLATFORM_LIFETIME_PERMANENT; + g_return_val_if_fail (preferred == 0, TRUE); + } else { + if (now <= 0) + now = nm_utils_get_monotonic_timestamp_s (); + t_lifetime = nm_utils_lifetime_rebase_relative_time_on_now (timestamp, lifetime, now); + if (!t_lifetime) { + *out_lifetime = 0; + *out_preferred = 0; + return FALSE; + } + t_preferred = nm_utils_lifetime_rebase_relative_time_on_now (timestamp, preferred, now); - if (now <= 0) - now = nm_utils_get_monotonic_timestamp_s (); + *out_lifetime = t_lifetime; + *out_preferred = MIN (t_preferred, t_lifetime); - t_lifetime = nm_utils_lifetime_rebase_relative_time_on_now (timestamp, lifetime, now); - if (!t_lifetime) { - NM_SET_OUT (out_preferred, 0); - return 0; + /* Assert that non-permanent addresses have a (positive) @timestamp. nm_utils_lifetime_rebase_relative_time_on_now() + * treats addresses with timestamp 0 as *now*. Addresses passed to _address_get_lifetime() always + * should have a valid @timestamp, otherwise on every re-sync, their lifetime will be extended anew. + */ + g_return_val_if_fail ( timestamp != 0 + || ( lifetime == NM_PLATFORM_LIFETIME_PERMANENT + && preferred == NM_PLATFORM_LIFETIME_PERMANENT), TRUE); + g_return_val_if_fail (t_preferred <= t_lifetime, TRUE); } - - t_preferred = nm_utils_lifetime_rebase_relative_time_on_now (timestamp, preferred, now); - - NM_SET_OUT (out_preferred, MIN (t_preferred, t_lifetime)); - - /* Assert that non-permanent addresses have a (positive) @timestamp. nm_utils_lifetime_rebase_relative_time_on_now() - * treats addresses with timestamp 0 as *now*. Addresses passed to _address_get_lifetime() always - * should have a valid @timestamp, otherwise on every re-sync, their lifetime will be extended anew. - */ - g_return_val_if_fail ( timestamp != 0 - || ( lifetime == NM_PLATFORM_LIFETIME_PERMANENT - && preferred == NM_PLATFORM_LIFETIME_PERMANENT), t_lifetime); - g_return_val_if_fail (t_preferred <= t_lifetime, t_lifetime); - - return t_lifetime; + return TRUE; } const char * @@ -4156,21 +4329,6 @@ nm_utils_format_con_diff_for_audit (GHashTable *diff) return g_string_free (str, FALSE); } -const char * -nm_utils_parse_dns_domain (const char *domain, gboolean *is_routing) -{ - g_return_val_if_fail (domain, NULL); - g_return_val_if_fail (domain[0], NULL); - - if (domain[0] == '~') { - domain++; - NM_SET_OUT (is_routing, TRUE); - } else - NM_SET_OUT (is_routing, FALSE); - - return domain; -} - /*****************************************************************************/ NM_UTILS_ENUM2STR_DEFINE (nm_icmpv6_router_pref_to_string, NMIcmpv6RouterPref, diff --git a/src/nm-core-utils.h b/src/nm-core-utils.h index ec9e2947..cc784724 100644 --- a/src/nm-core-utils.h +++ b/src/nm-core-utils.h @@ -25,6 +25,8 @@ #include <stdio.h> #include <arpa/inet.h> +#include "nm-utils/nm-hash-utils.h" + #include "nm-connection.h" /*****************************************************************************/ @@ -178,6 +180,8 @@ nm_utils_ip_route_metric_penalize (int addr_family, guint32 metric, guint32 pena int nm_utils_modprobe (GError **error, gboolean suppress_error_loggin, const char *arg1, ...) G_GNUC_NULL_TERMINATED; +guint64 nm_utils_get_start_time_for_pid (pid_t pid, char *out_state, pid_t *out_ppid); + void nm_utils_kill_process_sync (pid_t pid, guint64 start_time, int sig, guint64 log_domain, const char *log_name, guint32 wait_before_kill_msec, guint32 sleep_duration_msec, guint32 max_wait_msec); @@ -227,14 +231,14 @@ gboolean nm_utils_connection_has_default_route (NMConnection *connection, char *nm_utils_new_vlan_name (const char *parent_iface, guint32 vlan_id); const char *nm_utils_new_infiniband_name (char *name, const char *parent_name, int p_key); +gboolean nm_utils_resolve_conf_parse (int addr_family, + const char *rc_contents, + GArray *nameservers, + GPtrArray *dns_options); + int nm_utils_cmp_connection_by_autoconnect_priority (NMConnection *a, NMConnection *b); -void nm_utils_log_connection_diff (NMConnection *connection, - NMConnection *diff_base, - guint32 level, guint64 domain, - const char *name, - const char *prefix, - const char *dbus_path); +void nm_utils_log_connection_diff (NMConnection *connection, NMConnection *diff_base, guint32 level, guint64 domain, const char *name, const char *prefix); gint64 nm_utils_get_monotonic_timestamp_ns (void); gint64 nm_utils_get_monotonic_timestamp_us (void); @@ -242,13 +246,6 @@ gint64 nm_utils_get_monotonic_timestamp_ms (void); gint32 nm_utils_get_monotonic_timestamp_s (void); gint64 nm_utils_monotonic_timestamp_as_boottime (gint64 timestamp, gint64 timestamp_ticks_per_ns); -static inline gint64 -nm_utils_get_monotonic_timestamp_ns_cached (gint64 *cache_now) -{ - return (*cache_now) - ?: (*cache_now = nm_utils_get_monotonic_timestamp_ns ()); -} - gboolean nm_utils_is_valid_path_component (const char *name); const char *NM_ASSERT_VALID_PATH_COMPONENT (const char *name); @@ -413,11 +410,12 @@ guint32 nm_utils_lifetime_rebase_relative_time_on_now (guint32 timestamp, guint32 duration, gint32 now); -guint32 nm_utils_lifetime_get (guint32 timestamp, - guint32 lifetime, - guint32 preferred, - gint32 now, - guint32 *out_preferred); +gboolean nm_utils_lifetime_get (guint32 timestamp, + guint32 lifetime, + guint32 preferred, + gint32 now, + guint32 *out_lifetime, + guint32 *out_preferred); gboolean nm_utils_ip4_address_is_link_local (in_addr_t addr); @@ -452,6 +450,4 @@ const char *nm_activation_type_to_string (NMActivationType activation_type); /*****************************************************************************/ -const char *nm_utils_parse_dns_domain (const char *domain, gboolean *is_routing); - #endif /* __NM_CORE_UTILS_H__ */ diff --git a/src/nm-dbus-manager.c b/src/nm-dbus-manager.c deleted file mode 100644 index 3e369129..00000000 --- a/src/nm-dbus-manager.c +++ /dev/null @@ -1,1626 +0,0 @@ -/* -*- Mode: C; tab-width: 4; indent-tabs-mode: t; c-basic-offset: 4 -*- */ -/* NetworkManager -- Network link manager - * - * This program is free software; you can redistribute it and/or modify - * it under the terms of the GNU General Public License as published by - * the Free Software Foundation; either version 2 of the License, or - * (at your option) any later version. - * - * This program is distributed in the hope that it will be useful, - * but WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the - * GNU General Public License for more details. - * - * You should have received a copy of the GNU General Public License along - * with this program; if not, write to the Free Software Foundation, Inc., - * 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA. - * - * Copyright (C) 2006 - 2013 Red Hat, Inc. - * Copyright (C) 2006 - 2008 Novell, Inc. - */ - -#include "nm-default.h" - -#include "nm-dbus-manager.h" - -#include <unistd.h> -#include <sys/stat.h> -#include <sys/types.h> -#include <errno.h> -#include <string.h> - -#include "c-list/src/c-list.h" -#include "nm-dbus-interface.h" -#include "nm-core-internal.h" -#include "nm-dbus-compat.h" -#include "nm-dbus-object.h" -#include "NetworkManagerUtils.h" - -/* The base path for our GDBusObjectManagerServers. They do not contain - * "NetworkManager" because GDBusObjectManagerServer requires that all - * exported objects be *below* the base path, and eg the Manager object - * is the base path already. - */ -#define OBJECT_MANAGER_SERVER_BASE_PATH "/org/freedesktop" - -/*****************************************************************************/ - -typedef struct { - GVariant *value; -} PropertyCacheData; - -typedef struct { - CList registration_lst; - NMDBusObject *obj; - NMDBusObjectClass *klass; - guint info_idx; - guint registration_id; - PropertyCacheData property_cache[]; -} RegistrationData; - -/* we require that @path is the first member of NMDBusManagerData - * because _objects_by_path_hash() requires that. */ -G_STATIC_ASSERT (G_STRUCT_OFFSET (struct _NMDBusObjectInternal, path) == 0); - -enum { - PRIVATE_CONNECTION_NEW, - PRIVATE_CONNECTION_DISCONNECTED, - - LAST_SIGNAL -}; - -static guint signals[LAST_SIGNAL]; - -typedef struct { - GHashTable *objects_by_path; - CList objects_lst_head; - - CList private_servers_lst_head; - - NMDBusManagerSetPropertyHandler set_property_handler; - gpointer set_property_handler_data; - - GDBusConnection *connection; - GDBusProxy *proxy; - guint objmgr_registration_id; -} NMDBusManagerPrivate; - -struct _NMDBusManager { - GObject parent; - NMDBusManagerPrivate _priv; -}; - -struct _NMDBusManagerClass { - GObjectClass parent; -}; - -G_DEFINE_TYPE(NMDBusManager, nm_dbus_manager, G_TYPE_OBJECT) - -#define NM_DBUS_MANAGER_GET_PRIVATE(self) _NM_GET_PRIVATE (self, NMDBusManager, NM_IS_DBUS_MANAGER) - -/*****************************************************************************/ - -#define _NMLOG_DOMAIN LOGD_CORE -#define _NMLOG(level, ...) __NMLOG_DEFAULT (level, _NMLOG_DOMAIN, "bus-manager", __VA_ARGS__) - -NM_DEFINE_SINGLETON_GETTER (NMDBusManager, nm_dbus_manager_get, NM_TYPE_DBUS_MANAGER); - -/*****************************************************************************/ - -static const GDBusInterfaceInfo interface_info_objmgr; -static const GDBusSignalInfo signal_info_objmgr_interfaces_added; -static const GDBusSignalInfo signal_info_objmgr_interfaces_removed; -static GVariantBuilder *_obj_collect_properties_all (NMDBusObject *obj, - GVariantBuilder *builder); - -/*****************************************************************************/ - -static guint -_objects_by_path_hash (gconstpointer user_data) -{ - const char *const*p_data = user_data; - - nm_assert (p_data); - nm_assert (*p_data); - nm_assert ((*p_data)[0] == '/'); - - return nm_hash_str (*p_data); -} - -static gboolean -_objects_by_path_equal (gconstpointer user_data_a, gconstpointer user_data_b) -{ - const char *const*p_data_a = user_data_a; - const char *const*p_data_b = user_data_b; - - nm_assert (p_data_a); - nm_assert (*p_data_a); - nm_assert ((*p_data_a)[0] == '/'); - nm_assert (p_data_b); - nm_assert (*p_data_b); - nm_assert ((*p_data_b)[0] == '/'); - - return nm_streq (*p_data_a, *p_data_b); -} - -/*****************************************************************************/ - -typedef struct { - CList private_servers_lst; - - const char *tag; - GQuark detail; - char *address; - GDBusServer *server; - - /* With peer bus connections, we'll get a new connection for each - * client. For each connection we create an ObjectManager for - * that connection to handle exporting our objects. - * - * Note that even for connections that don't export any objects - * we'll still create GDBusObjectManager since that's where we store - * the pointer to the GDBusConnection. - */ - CList object_mgr_lst_head; - - NMDBusManager *manager; -} PrivateServer; - -typedef struct { - CList object_mgr_lst; - GDBusObjectManagerServer *manager; - char *fake_sender; -} ObjectMgrData; - -typedef struct { - GDBusConnection *connection; - PrivateServer *server; - gboolean remote_peer_vanished; -} CloseConnectionInfo; - -/*****************************************************************************/ - -static void -_object_mgr_data_free (ObjectMgrData *obj_mgr_data) -{ - GDBusConnection *connection; - - c_list_unlink_stale (&obj_mgr_data->object_mgr_lst); - - connection = g_dbus_object_manager_server_get_connection (obj_mgr_data->manager); - if (!g_dbus_connection_is_closed (connection)) - g_dbus_connection_close (connection, NULL, NULL, NULL); - g_dbus_object_manager_server_set_connection (obj_mgr_data->manager, NULL); - g_object_unref (obj_mgr_data->manager); - g_object_unref (connection); - - g_free (obj_mgr_data->fake_sender); - - g_slice_free (ObjectMgrData, obj_mgr_data); -} - -/*****************************************************************************/ - -static gboolean -close_connection_in_idle (gpointer user_data) -{ - CloseConnectionInfo *info = user_data; - PrivateServer *server = info->server; - ObjectMgrData *obj_mgr_data, *obj_mgr_data_safe; - - /* Emit this for the manager */ - g_signal_emit (server->manager, - signals[PRIVATE_CONNECTION_DISCONNECTED], - server->detail, - info->connection); - - /* FIXME: there's a bug (754730) in GLib for which the connection - * is marked as closed when the remote peer vanishes but its - * resources are not cleaned up. Work around it by explicitly - * closing the connection in that case. */ - if (info->remote_peer_vanished) - g_dbus_connection_close (info->connection, NULL, NULL, NULL); - - c_list_for_each_entry_safe (obj_mgr_data, obj_mgr_data_safe, &server->object_mgr_lst_head, object_mgr_lst) { - gs_unref_object GDBusConnection *connection = NULL; - - connection = g_dbus_object_manager_server_get_connection (obj_mgr_data->manager); - if (connection == info->connection) { - _object_mgr_data_free (obj_mgr_data); - break; - } - } - - g_object_unref (server->manager); - g_slice_free (CloseConnectionInfo, info); - - return G_SOURCE_REMOVE; -} - -static void -private_server_closed_connection (GDBusConnection *conn, - gboolean remote_peer_vanished, - GError *error, - gpointer user_data) -{ - PrivateServer *s = user_data; - CloseConnectionInfo *info; - - /* Clean up after the connection */ - _LOGD ("(%s) closed connection %p on private socket", s->tag, conn); - - info = g_slice_new0 (CloseConnectionInfo); - info->connection = conn; - info->server = s; - info->remote_peer_vanished = remote_peer_vanished; - - g_object_ref (s->manager); - - /* Delay the close of connection to ensure that D-Bus signals - * are handled */ - g_idle_add (close_connection_in_idle, info); -} - -static gboolean -private_server_new_connection (GDBusServer *server, - GDBusConnection *conn, - gpointer user_data) -{ - PrivateServer *s = user_data; - ObjectMgrData *obj_mgr_data; - static guint32 counter = 0; - GDBusObjectManagerServer *manager; - char *sender; - - g_signal_connect (conn, "closed", G_CALLBACK (private_server_closed_connection), s); - - /* Fake a sender since private connections don't have one */ - sender = g_strdup_printf ("x:y:%d", counter++); - - manager = g_dbus_object_manager_server_new (OBJECT_MANAGER_SERVER_BASE_PATH); - g_dbus_object_manager_server_set_connection (manager, conn); - - obj_mgr_data = g_slice_new (ObjectMgrData); - obj_mgr_data->manager = manager; - obj_mgr_data->fake_sender = sender; - c_list_link_tail (&s->object_mgr_lst_head, &obj_mgr_data->object_mgr_lst); - - _LOGD ("(%s) accepted connection %p on private socket", s->tag, conn); - - /* Emit this for the manager. - * - * It is essential to do this from the "new-connection" signal handler, as - * at that point no messages from the connection are yet processed - * (which avoids races with registering objects). */ - g_signal_emit (s->manager, - signals[PRIVATE_CONNECTION_NEW], - s->detail, - conn, - manager); - return TRUE; -} - -static gboolean -private_server_authorize (GDBusAuthObserver *observer, - GIOStream *stream, - GCredentials *credentials, - gpointer user_data) -{ - return g_credentials_get_unix_user (credentials, NULL) == 0; -} - -static gboolean -private_server_allow_mechanism (GDBusAuthObserver *observer, - const char *mechanism, - gpointer user_data) -{ - return NM_IN_STRSET (mechanism, "EXTERNAL"); -} - -static void -private_server_free (gpointer ptr) -{ - PrivateServer *s = ptr; - ObjectMgrData *obj_mgr_data, *obj_mgr_data_safe; - - c_list_unlink_stale (&s->private_servers_lst); - - unlink (s->address); - g_free (s->address); - - c_list_for_each_entry_safe (obj_mgr_data, obj_mgr_data_safe, &s->object_mgr_lst_head, object_mgr_lst) - _object_mgr_data_free (obj_mgr_data); - - g_dbus_server_stop (s->server); - - g_signal_handlers_disconnect_by_func (s->server, G_CALLBACK (private_server_new_connection), s); - - g_object_unref (s->server); - - g_slice_free (PrivateServer, s); -} - -void -nm_dbus_manager_private_server_register (NMDBusManager *self, - const char *path, - const char *tag) -{ - NMDBusManagerPrivate *priv; - PrivateServer *s; - gs_unref_object GDBusAuthObserver *auth_observer = NULL; - GDBusServer *server; - GError *error = NULL; - gs_free char *address = NULL; - gs_free char *guid = NULL; - - g_return_if_fail (NM_IS_DBUS_MANAGER (self)); - g_return_if_fail (path); - g_return_if_fail (tag); - - priv = NM_DBUS_MANAGER_GET_PRIVATE (self); - - /* Only one instance per tag; but don't warn */ - c_list_for_each_entry (s, &priv->private_servers_lst_head, private_servers_lst) { - if (nm_streq0 (tag, s->tag)) - return; - } - - unlink (path); - address = g_strdup_printf ("unix:path=%s", path); - - _LOGD ("(%s) creating private socket %s", tag, address); - - guid = g_dbus_generate_guid (); - auth_observer = g_dbus_auth_observer_new (); - g_signal_connect (auth_observer, "authorize-authenticated-peer", - G_CALLBACK (private_server_authorize), NULL); - g_signal_connect (auth_observer, "allow-mechanism", - G_CALLBACK (private_server_allow_mechanism), NULL); - server = g_dbus_server_new_sync (address, - G_DBUS_SERVER_FLAGS_NONE, - guid, - auth_observer, - NULL, &error); - - if (!server) { - _LOGW ("(%s) failed to set up private socket %s: %s", - tag, address, error->message); - g_error_free (error); - return; - } - - s = g_slice_new0 (PrivateServer); - s->address = g_steal_pointer (&address); - s->server = server; - g_signal_connect (server, "new-connection", - G_CALLBACK (private_server_new_connection), s); - - c_list_init (&s->object_mgr_lst_head); - - s->manager = self; - s->detail = g_quark_from_string (tag); - s->tag = g_quark_to_string (s->detail); - - c_list_link_tail (&priv->private_servers_lst_head, &s->private_servers_lst); - - g_dbus_server_start (server); -} - -static const char * -private_server_get_connection_owner (PrivateServer *s, GDBusConnection *connection) -{ - ObjectMgrData *obj_mgr_data; - - nm_assert (s); - nm_assert (G_IS_DBUS_CONNECTION (connection)); - - c_list_for_each_entry (obj_mgr_data, &s->object_mgr_lst_head, object_mgr_lst) { - gs_unref_object GDBusConnection *c = NULL; - - c = g_dbus_object_manager_server_get_connection (obj_mgr_data->manager); - if (c == connection) - return obj_mgr_data->fake_sender; - } - return NULL; -} - -static GDBusConnection * -private_server_get_connection_by_owner (PrivateServer *s, const char *owner) -{ - ObjectMgrData *obj_mgr_data; - - nm_assert (s); - nm_assert (owner); - - c_list_for_each_entry (obj_mgr_data, &s->object_mgr_lst_head, object_mgr_lst) { - if (nm_streq (owner, obj_mgr_data->fake_sender)) - return g_dbus_object_manager_server_get_connection (obj_mgr_data->manager); - } - return NULL; -} - -/*****************************************************************************/ - -static gboolean -_bus_get_unix_pid (NMDBusManager *self, - const char *sender, - gulong *out_pid, - GError **error) -{ - guint32 unix_pid = G_MAXUINT32; - gs_unref_variant GVariant *ret = NULL; - - ret = _nm_dbus_proxy_call_sync (NM_DBUS_MANAGER_GET_PRIVATE (self)->proxy, - "GetConnectionUnixProcessID", - g_variant_new ("(s)", sender), - G_VARIANT_TYPE ("(u)"), - G_DBUS_CALL_FLAGS_NONE, 2000, - NULL, error); - if (!ret) - return FALSE; - - g_variant_get (ret, "(u)", &unix_pid); - - *out_pid = (gulong) unix_pid; - return TRUE; -} - -static gboolean -_bus_get_unix_user (NMDBusManager *self, - const char *sender, - gulong *out_user, - GError **error) -{ - guint32 unix_uid = G_MAXUINT32; - gs_unref_variant GVariant *ret = NULL; - - ret = _nm_dbus_proxy_call_sync (NM_DBUS_MANAGER_GET_PRIVATE (self)->proxy, - "GetConnectionUnixUser", - g_variant_new ("(s)", sender), - G_VARIANT_TYPE ("(u)"), - G_DBUS_CALL_FLAGS_NONE, 2000, - NULL, error); - if (!ret) - return FALSE; - - g_variant_get (ret, "(u)", &unix_uid); - - *out_user = (gulong) unix_uid; - return TRUE; -} - -/** - * _get_caller_info(): - * - * Given a GDBus method invocation, or a GDBusConnection + GDBusMessage, - * return the sender and the UID of the sender. - */ -static gboolean -_get_caller_info (NMDBusManager *self, - GDBusMethodInvocation *context, - GDBusConnection *connection, - GDBusMessage *message, - char **out_sender, - gulong *out_uid, - gulong *out_pid) -{ - NMDBusManagerPrivate *priv = NM_DBUS_MANAGER_GET_PRIVATE (self); - const char *sender; - - if (context) { - connection = g_dbus_method_invocation_get_connection (context); - - /* only bus connections will have a sender */ - sender = g_dbus_method_invocation_get_sender (context); - } else { - g_assert (message); - sender = g_dbus_message_get_sender (message); - } - g_assert (connection); - - if (!sender) { - PrivateServer *s; - - /* Might be a private connection, for which we fake a sender */ - c_list_for_each_entry (s, &priv->private_servers_lst_head, private_servers_lst) { - sender = private_server_get_connection_owner (s, connection); - if (sender) { - if (out_uid) - *out_uid = 0; - if (out_sender) - *out_sender = g_strdup (sender); - if (out_pid) { - GCredentials *creds; - - creds = g_dbus_connection_get_peer_credentials (connection); - if (creds) { - pid_t pid; - - pid = g_credentials_get_unix_pid (creds, NULL); - if (pid == -1) - *out_pid = G_MAXULONG; - else - *out_pid = pid; - } else - *out_pid = G_MAXULONG; - } - return TRUE; - } - } - return FALSE; - } - - /* Bus connections always have a sender */ - g_assert (sender); - if (out_uid) { - if (!_bus_get_unix_user (self, sender, out_uid, NULL)) { - *out_uid = G_MAXULONG; - return FALSE; - } - } - - if (out_pid) { - if (!_bus_get_unix_pid (self, sender, out_pid, NULL)) { - *out_pid = G_MAXULONG; - return FALSE; - } - } - - if (out_sender) - *out_sender = g_strdup (sender); - - return TRUE; -} - -gboolean -nm_dbus_manager_get_caller_info (NMDBusManager *self, - GDBusMethodInvocation *context, - char **out_sender, - gulong *out_uid, - gulong *out_pid) -{ - return _get_caller_info (self, context, NULL, NULL, out_sender, out_uid, out_pid); -} - -gboolean -nm_dbus_manager_get_caller_info_from_message (NMDBusManager *self, - GDBusConnection *connection, - GDBusMessage *message, - char **out_sender, - gulong *out_uid, - gulong *out_pid) -{ - return _get_caller_info (self, NULL, connection, message, out_sender, out_uid, out_pid); -} - -/** - * nm_dbus_manager_ensure_uid: - * - * @self: bus manager instance - * @context: D-Bus method invocation - * @uid: a user-id - * @error_domain: error domain to return on failure - * @error_code: error code to return on failure - * - * Retrieves the uid of the D-Bus method caller and - * checks that it matches @uid, unless @uid is G_MAXULONG. - * In case of failure the function returns FALSE and finishes - * handling the D-Bus method with an error. - * - * Returns: %TRUE if the check succeeded, %FALSE otherwise - */ -gboolean -nm_dbus_manager_ensure_uid (NMDBusManager *self, - GDBusMethodInvocation *context, - gulong uid, - GQuark error_domain, - int error_code) -{ - gulong caller_uid; - GError *error = NULL; - - g_return_val_if_fail (NM_IS_DBUS_MANAGER (self), FALSE); - g_return_val_if_fail (G_IS_DBUS_METHOD_INVOCATION (context), FALSE); - - if (!nm_dbus_manager_get_caller_info (self, context, NULL, &caller_uid, NULL)) { - error = g_error_new_literal (error_domain, - error_code, - "Unable to determine request UID."); - g_dbus_method_invocation_take_error (context, error); - return FALSE; - } - - if (uid != G_MAXULONG && caller_uid != uid) { - error = g_error_new_literal (error_domain, - error_code, - "Permission denied"); - g_dbus_method_invocation_take_error (context, error); - return FALSE; - } - - return TRUE; -} - -gboolean -nm_dbus_manager_get_unix_user (NMDBusManager *self, - const char *sender, - gulong *out_uid) -{ - NMDBusManagerPrivate *priv = NM_DBUS_MANAGER_GET_PRIVATE (self); - PrivateServer *s; - GError *error = NULL; - - g_return_val_if_fail (sender != NULL, FALSE); - g_return_val_if_fail (out_uid != NULL, FALSE); - - /* Check if it's a private connection sender, which we fake */ - c_list_for_each_entry (s, &priv->private_servers_lst_head, private_servers_lst) { - gs_unref_object GDBusConnection *connection = NULL; - - connection = private_server_get_connection_by_owner (s, sender); - if (connection) { - *out_uid = 0; - return TRUE; - } - } - - /* Otherwise, a bus connection */ - if (!_bus_get_unix_user (self, sender, out_uid, &error)) { - _LOGW ("failed to get unix user for dbus sender '%s': %s", - sender, error->message); - g_error_free (error); - return FALSE; - } - - return TRUE; -} - -/*****************************************************************************/ - -const char * -nm_dbus_manager_connection_get_private_name (NMDBusManager *self, - GDBusConnection *connection) -{ - NMDBusManagerPrivate *priv; - PrivateServer *s; - const char *owner; - - g_return_val_if_fail (NM_IS_DBUS_MANAGER (self), FALSE); - g_return_val_if_fail (G_IS_DBUS_CONNECTION (connection), FALSE); - - if (g_dbus_connection_get_unique_name (connection)) { - /* Shortcut. The connection is not a private connection. */ - return NULL; - } - - priv = NM_DBUS_MANAGER_GET_PRIVATE (self); - c_list_for_each_entry (s, &priv->private_servers_lst_head, private_servers_lst) { - if ((owner = private_server_get_connection_owner (s, connection))) - return owner; - } - g_return_val_if_reached (NULL); -} - -/** - * nm_dbus_manager_new_proxy: - * @self: the #NMDBusManager - * @connection: the GDBusConnection for which this connection should be created - * @proxy_type: the type of #GDBusProxy to create - * @name: any name on the message bus - * @path: name of the object instance to call methods on - * @iface: name of the interface to call methods on - * - * Creates a new proxy (of type @proxy_type) for a name on a given bus. Since - * the process which called the D-Bus method could be coming from a private - * connection or the system bus connection, different proxies must be created - * for each case. This function abstracts that. - * - * Returns: a #GDBusProxy capable of calling D-Bus methods of the calling process - */ -GDBusProxy * -nm_dbus_manager_new_proxy (NMDBusManager *self, - GDBusConnection *connection, - GType proxy_type, - const char *name, - const char *path, - const char *iface) -{ - const char *owner; - GDBusProxy *proxy; - GError *error = NULL; - - g_return_val_if_fail (g_type_is_a (proxy_type, G_TYPE_DBUS_PROXY), NULL); - g_return_val_if_fail (G_IS_DBUS_CONNECTION (connection), NULL); - - /* Might be a private connection, for which @name is fake */ - owner = nm_dbus_manager_connection_get_private_name (self, connection); - if (owner) { - g_return_val_if_fail (!g_strcmp0 (owner, name), NULL); - name = NULL; - } - - proxy = g_initable_new (proxy_type, NULL, &error, - "g-connection", connection, - "g-flags", (G_DBUS_PROXY_FLAGS_DO_NOT_LOAD_PROPERTIES | - G_DBUS_PROXY_FLAGS_DO_NOT_CONNECT_SIGNALS), - "g-name", name, - "g-object-path", path, - "g-interface-name", iface, - NULL); - if (!proxy) { - _LOGW ("could not create proxy for %s on connection %s: %s", - iface, name, error->message); - g_error_free (error); - } - return proxy; -} - -/*****************************************************************************/ - -GDBusConnection * -nm_dbus_manager_get_connection (NMDBusManager *self) -{ - g_return_val_if_fail (NM_IS_DBUS_MANAGER (self), NULL); - - return NM_DBUS_MANAGER_GET_PRIVATE (self)->connection; -} - -/*****************************************************************************/ - -static const NMDBusInterfaceInfoExtended * -_reg_data_get_interface_info (RegistrationData *reg_data) -{ - nm_assert (reg_data); - - return reg_data->klass->interface_infos[reg_data->info_idx]; -} - -/*****************************************************************************/ - -static void -dbus_vtable_method_call (GDBusConnection *connection, - const char *sender, - const char *object_path, - const char *interface_name, - const char *method_name, - GVariant *parameters, - GDBusMethodInvocation *invocation, - gpointer user_data) -{ - RegistrationData *reg_data = user_data; - NMDBusObject *obj = reg_data->obj; - const NMDBusInterfaceInfoExtended *interface_info = _reg_data_get_interface_info (reg_data); - const NMDBusMethodInfoExtended *method_info = NULL; - gboolean on_same_interface; - - on_same_interface = nm_streq (interface_info->parent.name, interface_name); - - /* handle property setter first... */ - if ( !on_same_interface - && nm_streq (interface_name, DBUS_INTERFACE_PROPERTIES) - && nm_streq (method_name, "Set")) { - NMDBusManager *self = nm_dbus_object_get_manager (obj); - NMDBusManagerPrivate *priv = NM_DBUS_MANAGER_GET_PRIVATE (self); - const NMDBusPropertyInfoExtended *property_info = NULL; - const char *property_interface; - const char *property_name; - gs_unref_variant GVariant *value = NULL; - - g_variant_get (parameters, "(&s&sv)", &property_interface, &property_name, &value); - - nm_assert (nm_streq (property_interface, interface_info->parent.name)); - - property_info = (const NMDBusPropertyInfoExtended *) nm_dbus_utils_interface_info_lookup_property (&interface_info->parent, - property_name, - NULL); - if ( !property_info - || !NM_FLAGS_HAS (property_info->parent.flags, G_DBUS_PROPERTY_INFO_FLAGS_WRITABLE)) - g_return_if_reached (); - - if (!priv->set_property_handler) { - g_dbus_method_invocation_return_error (invocation, - G_DBUS_ERROR, - G_DBUS_ERROR_AUTH_FAILED, - "Cannot authenticate setting property %s", - property_name); - return; - } - - priv->set_property_handler (obj, - interface_info, - property_info, - connection, - sender, - invocation, - value, - priv->set_property_handler_data); - return; - } - - if (on_same_interface) { - method_info = (const NMDBusMethodInfoExtended *) nm_dbus_utils_interface_info_lookup_method (&interface_info->parent, - method_name); - } - if (!method_info) { - g_dbus_method_invocation_return_error (invocation, - G_DBUS_ERROR, - G_DBUS_ERROR_UNKNOWN_METHOD, - "Unknown method %s", - method_name); - return; - } - - method_info->handle (reg_data->obj, - interface_info, - method_info, - connection, - sender, - invocation, - parameters); -} - -static GVariant * -_obj_get_property (RegistrationData *reg_data, - guint property_idx, - gboolean refetch) -{ - const NMDBusInterfaceInfoExtended *interface_info = _reg_data_get_interface_info (reg_data); - const NMDBusPropertyInfoExtended *property_info; - GVariant *value; - - property_info = (const NMDBusPropertyInfoExtended *) (interface_info->parent.properties[property_idx]); - - if (refetch) - nm_clear_g_variant (®_data->property_cache[property_idx].value); - else { - value = reg_data->property_cache[property_idx].value; - if (value) - goto out; - } - - value = nm_dbus_utils_get_property (G_OBJECT (reg_data->obj), - property_info->parent.signature, - property_info->property_name); - reg_data->property_cache[property_idx].value = value; -out: - return g_variant_ref (value); -} - -static GVariant * -dbus_vtable_get_property (GDBusConnection *connection, - const char *sender, - const char *object_path, - const char *interface_name, - const char *property_name, - GError **error, - gpointer user_data) -{ - RegistrationData *reg_data = user_data; - const NMDBusInterfaceInfoExtended *interface_info = _reg_data_get_interface_info (reg_data); - guint property_idx; - - if (!nm_dbus_utils_interface_info_lookup_property (&interface_info->parent, - property_name, - &property_idx)) - g_return_val_if_reached (NULL); - - return _obj_get_property (reg_data, property_idx, FALSE); -} - -static const GDBusInterfaceVTable dbus_vtable = { - .method_call = dbus_vtable_method_call, - .get_property = dbus_vtable_get_property, - - /* set_property is handled via method_call as well. We need to authenticate - * which requires an asynchronous handler. */ - .set_property = NULL, -}; - -static void -_obj_register (NMDBusManager *self, - NMDBusObject *obj) -{ - NMDBusManagerPrivate *priv = NM_DBUS_MANAGER_GET_PRIVATE (self); - guint i, k; - guint n_klasses; - GType gtype; - NMDBusObjectClass *klasses[10]; - const NMDBusInterfaceInfoExtended *const*prev_interface_infos = NULL; - GVariantBuilder builder; - - nm_assert (c_list_is_empty (&obj->internal.registration_lst_head)); - nm_assert (priv->connection); - - n_klasses = 0; - gtype = G_OBJECT_TYPE (obj); - while (gtype != NM_TYPE_DBUS_OBJECT) { - nm_assert (n_klasses < G_N_ELEMENTS (klasses)); - klasses[n_klasses++] = g_type_class_ref (gtype); - gtype = g_type_parent (gtype); - } - - for (k = n_klasses; k > 0; ) { - NMDBusObjectClass *klass = NM_DBUS_OBJECT_CLASS (klasses[--k]); - - if (!klass->interface_infos) - continue; - - if (prev_interface_infos == klass->interface_infos) { - /* derived classes inherrit the interface-infos from the parent class. - * For convenience, we allow the subclass to leave interface-infos untouched, - * but it means we must ignore the parent's interface, because we already - * handled it. - * - * Note that the loop goes from the parent classes to child classes */ - continue; - } - prev_interface_infos = klass->interface_infos; - - for (i = 0; klass->interface_infos[i]; i++) { - const NMDBusInterfaceInfoExtended *interface_info = klass->interface_infos[i]; - RegistrationData *reg_data; - gs_free_error GError *error = NULL; - guint registration_id; - guint prop_len = NM_PTRARRAY_LEN (interface_info->parent.properties); - - reg_data = g_malloc0 (sizeof (RegistrationData) + (sizeof (PropertyCacheData) * prop_len)); - - registration_id = g_dbus_connection_register_object (priv->connection, - obj->internal.path, - NM_UNCONST_PTR (GDBusInterfaceInfo, &interface_info->parent), - &dbus_vtable, - reg_data, - NULL, - &error); - if (!registration_id) { - _LOGE ("failure to register object %s: %s", obj->internal.path, error->message); - g_free (reg_data); - continue; - } - - reg_data->obj = obj; - reg_data->klass = g_type_class_ref (G_TYPE_FROM_CLASS (klass)); - reg_data->info_idx = i; - reg_data->registration_id = registration_id; - c_list_link_tail (&obj->internal.registration_lst_head, ®_data->registration_lst); - } - } - - for (k = 0; k < n_klasses; k++) - g_type_class_unref (klasses[k]); - - nm_assert (!c_list_is_empty (&obj->internal.registration_lst_head)); - - /* Currently the interfaces of an object do not changed and strictly depend on the object glib type. - * We don't need more flixibility, and it simplifies the code. Hence, now emit interface-added - * signal for the new object. - * - * Warning: note that if @obj's notify signal is currently blocked via g_object_freeze_notify(), - * we might emit properties with an inconsistent (internal) state. There is no easy solution, - * because we have to emit the signal now, and we don't know what the correct desired state - * of the properties is. - * Another problem is, upon unfreezing the signals, we immediately send PropertiesChanged - * notifications out. Which is a bit odd, as we just export the object. - * - * In general, it's ok to export an object with frozen signals. But you better make sure - * that all properties are in a self-consistent state when exporting the object. */ - g_dbus_connection_emit_signal (priv->connection, - NULL, - OBJECT_MANAGER_SERVER_BASE_PATH, - interface_info_objmgr.name, - signal_info_objmgr_interfaces_added.name, - g_variant_new ("(oa{sa{sv}})", - obj->internal.path, - _obj_collect_properties_all (obj, &builder)), - NULL); -} - -static void -_obj_unregister (NMDBusManager *self, - NMDBusObject *obj) -{ - NMDBusManagerPrivate *priv = NM_DBUS_MANAGER_GET_PRIVATE (self); - RegistrationData *reg_data; - GVariantBuilder builder; - - nm_assert (NM_IS_DBUS_OBJECT (obj)); - - if (!priv->connection) { - /* nothing to do for the moment. */ - nm_assert (c_list_is_empty (&obj->internal.registration_lst_head)); - return; - } - - nm_assert (!c_list_is_empty (&obj->internal.registration_lst_head)); - nm_assert (priv->objmgr_registration_id); - - g_variant_builder_init (&builder, G_VARIANT_TYPE ("as")); - - while ((reg_data = c_list_last_entry (&obj->internal.registration_lst_head, RegistrationData, registration_lst))) { - const NMDBusInterfaceInfoExtended *interface_info = _reg_data_get_interface_info (reg_data); - guint i; - - g_variant_builder_add (&builder, - "s", - interface_info->parent.name); - c_list_unlink_stale (®_data->registration_lst); - if (!g_dbus_connection_unregister_object (priv->connection, reg_data->registration_id)) - nm_assert_not_reached (); - - if (interface_info->parent.properties) { - for (i = 0; interface_info->parent.properties[i]; i++) - nm_clear_g_variant (®_data->property_cache[i].value); - } - - g_type_class_unref (reg_data->klass); - g_free (reg_data); - } - - g_dbus_connection_emit_signal (priv->connection, - NULL, - OBJECT_MANAGER_SERVER_BASE_PATH, - interface_info_objmgr.name, - signal_info_objmgr_interfaces_removed.name, - g_variant_new ("(oas)", - obj->internal.path, - &builder), - NULL); -} - -NMDBusObject * -nm_dbus_manager_lookup_object (NMDBusManager *self, const char *path) -{ - NMDBusManagerPrivate *priv; - gpointer ptr; - NMDBusObject *obj; - - g_return_val_if_fail (NM_IS_DBUS_MANAGER (self), NULL); - g_return_val_if_fail (path, NULL); - - priv = NM_DBUS_MANAGER_GET_PRIVATE (self); - - ptr = g_hash_table_lookup (priv->objects_by_path, &path); - if (!ptr) - return NULL; - - obj = (NMDBusObject *) (((char *) ptr) - G_STRUCT_OFFSET (NMDBusObject, internal)); - nm_assert (NM_IS_DBUS_OBJECT (obj)); - return obj; -} - -void -_nm_dbus_manager_obj_export (NMDBusObject *obj) -{ - NMDBusManager *self; - NMDBusManagerPrivate *priv; - - g_return_if_fail (NM_IS_DBUS_OBJECT (obj)); - g_return_if_fail (obj->internal.path); - g_return_if_fail (NM_IS_DBUS_MANAGER (obj->internal.bus_manager)); - g_return_if_fail (c_list_is_empty (&obj->internal.objects_lst)); - nm_assert (c_list_is_empty (&obj->internal.registration_lst_head)); - - self = obj->internal.bus_manager; - priv = NM_DBUS_MANAGER_GET_PRIVATE (self); - - if (!g_hash_table_add (priv->objects_by_path, &obj->internal)) - nm_assert_not_reached (); - c_list_link_tail (&priv->objects_lst_head, &obj->internal.objects_lst); - - if (priv->connection) - _obj_register (self, obj); -} - -void -_nm_dbus_manager_obj_unexport (NMDBusObject *obj) -{ - NMDBusManager *self; - NMDBusManagerPrivate *priv; - - g_return_if_fail (NM_IS_DBUS_OBJECT (obj)); - g_return_if_fail (obj->internal.path); - g_return_if_fail (NM_IS_DBUS_MANAGER (obj->internal.bus_manager)); - g_return_if_fail (!c_list_is_empty (&obj->internal.objects_lst)); - - self = obj->internal.bus_manager; - priv = NM_DBUS_MANAGER_GET_PRIVATE (self); - - nm_assert (&obj->internal == g_hash_table_lookup (priv->objects_by_path, &obj->internal)); - nm_assert (c_list_contains (&priv->objects_lst_head, &obj->internal.objects_lst)); - - _obj_unregister (self, obj); - - if (!g_hash_table_remove (priv->objects_by_path, &obj->internal)) - nm_assert_not_reached (); - c_list_unlink (&obj->internal.objects_lst); -} - -void -_nm_dbus_manager_obj_notify (NMDBusObject *obj, - guint n_pspecs, - const GParamSpec *const*pspecs) -{ - NMDBusManager *self; - NMDBusManagerPrivate *priv; - RegistrationData *reg_data; - guint i, p; - gboolean any_legacy_signals = FALSE; - gboolean any_legacy_properties = FALSE; - GVariantBuilder legacy_builder; - GVariant *device_statistics_args = NULL; - - nm_assert (NM_IS_DBUS_OBJECT (obj)); - nm_assert (obj->internal.path); - nm_assert (NM_IS_DBUS_MANAGER (obj->internal.bus_manager)); - nm_assert (!c_list_is_empty (&obj->internal.objects_lst)); - - c_list_for_each_entry (reg_data, &obj->internal.registration_lst_head, registration_lst) { - if (_reg_data_get_interface_info (reg_data)->legacy_property_changed) { - any_legacy_signals = TRUE; - break; - } - } - - self = obj->internal.bus_manager; - priv = NM_DBUS_MANAGER_GET_PRIVATE (self); - - /* do a naive search for the matching NMDBusPropertyInfoExtended infos. Since the number of - * (interaces x properties) is static and possibly small, this naive search is effectively - * O(1). We might wanna introduce some index to lookup the properties in question faster. - * - * The nice part of this implementation is however, that the order in which properties - * are added to the GVariant is strictly defined to be the order in which the D-Bus property-info - * is declared. Getting a defined ordering with some smart lookup would be hard. */ - c_list_for_each_entry (reg_data, &obj->internal.registration_lst_head, registration_lst) { - const NMDBusInterfaceInfoExtended *interface_info = _reg_data_get_interface_info (reg_data); - gboolean has_properties = FALSE; - GVariantBuilder builder; - GVariantBuilder invalidated_builder; - GVariant *args; - - if (!interface_info->parent.properties) - continue; - - for (i = 0; interface_info->parent.properties[i]; i++) { - const NMDBusPropertyInfoExtended *property_info = (const NMDBusPropertyInfoExtended *) interface_info->parent.properties[i]; - - for (p = 0; p < n_pspecs; p++) { - const GParamSpec *pspec = pspecs[p]; - gs_unref_variant GVariant *value = NULL; - - if (!nm_streq (property_info->property_name, pspec->name)) - continue; - - value = _obj_get_property (reg_data, i, TRUE); - - if ( property_info->include_in_legacy_property_changed - && any_legacy_signals) { - /* also track the value in the legacy_builder to emit legacy signals below. */ - if (!any_legacy_properties) { - any_legacy_properties = TRUE; - g_variant_builder_init (&legacy_builder, G_VARIANT_TYPE ("a{sv}")); - } - g_variant_builder_add (&legacy_builder, "{sv}", property_info->parent.name, value); - } - - if (!has_properties) { - has_properties = TRUE; - g_variant_builder_init (&builder, G_VARIANT_TYPE ("a{sv}")); - } - g_variant_builder_add (&builder, "{sv}", property_info->parent.name, value); - } - } - - if (!has_properties) - continue; - - args = g_variant_builder_end (&builder); - - if (G_UNLIKELY (interface_info == &nm_interface_info_device_statistics)) { - /* we treat the Device.Statistics signal special, because we need to - * emit a signal also for it (below). */ - nm_assert (!device_statistics_args); - device_statistics_args = g_variant_ref_sink (args); - } - - g_variant_builder_init (&invalidated_builder, G_VARIANT_TYPE ("as")); - g_dbus_connection_emit_signal (priv->connection, - NULL, - obj->internal.path, - "org.freedesktop.DBus.Properties", - "PropertiesChanged", - g_variant_new ("(s@a{sv}as)", - interface_info->parent.name, - args, - &invalidated_builder), - NULL); - } - - if (G_UNLIKELY (device_statistics_args)) { - /* this is a special interface: it has a legacy PropertiesChanged signal, - * however, contrary to other interfaces with ~regular~ legacy signals, - * we only notify about properties that actually belong to this interface. */ - g_dbus_connection_emit_signal (priv->connection, - NULL, - obj->internal.path, - nm_interface_info_device_statistics.parent.name, - "PropertiesChanged", - g_variant_new ("(@a{sv})", - device_statistics_args), - NULL); - g_variant_unref (device_statistics_args); - } - - if (any_legacy_properties) { - gs_unref_variant GVariant *args = NULL; - - /* The legacy PropertyChanged signal on the NetworkManager D-Bus interface is - * deprecated for the standard signal on org.freedesktop.DBus.Properties. However, - * for backward compatibility, we still need to emit it. - * - * Due to a bug in dbus-glib in NetworkManager <= 1.0, the signal would - * not only notify about properties that were actually on the corresponding - * D-Bus interface. Instead, it would notify about all relevant properties - * on all interfaces that had such a signal. - * - * For example, "HwAddress" gets emitted both on "fdo.NM.Device.Ethernet" - * and "fdo.NM.Device.Veth" for veth interfaces, although only the former - * actually has such a property. - * Also note that "fdo.NM.Device" interface has no legacy signal. All notifications - * about its properties are instead emitted on the interfaces of the subtypes. - * - * See bgo#770629 and commit bef26a2e69f51259095fa080221db73de09fd38d. - */ - args = g_variant_ref_sink (g_variant_new ("(a{sv})", - &legacy_builder)); - c_list_for_each_entry (reg_data, &obj->internal.registration_lst_head, registration_lst) { - const NMDBusInterfaceInfoExtended *interface_info = _reg_data_get_interface_info (reg_data); - - if (interface_info->legacy_property_changed) { - g_dbus_connection_emit_signal (priv->connection, - NULL, - obj->internal.path, - interface_info->parent.name, - "PropertiesChanged", - args, - NULL); - } - } - } -} - -void -_nm_dbus_manager_obj_emit_signal (NMDBusObject *obj, - const NMDBusInterfaceInfoExtended *interface_info, - const GDBusSignalInfo *signal_info, - GVariant *args) -{ - NMDBusManager *self; - NMDBusManagerPrivate *priv; - - g_return_if_fail (NM_IS_DBUS_OBJECT (obj)); - g_return_if_fail (obj->internal.path); - g_return_if_fail (NM_IS_DBUS_MANAGER (obj->internal.bus_manager)); - g_return_if_fail (!c_list_is_empty (&obj->internal.objects_lst)); - - self = obj->internal.bus_manager; - priv = NM_DBUS_MANAGER_GET_PRIVATE (self); - - if (!priv->connection) { - nm_g_variant_unref_floating (args); - return; - } - - g_dbus_connection_emit_signal (priv->connection, - NULL, - obj->internal.path, - interface_info->parent.name, - signal_info->name, - args, - NULL); -} - -/*****************************************************************************/ - -static GVariantBuilder * -_obj_collect_properties_per_interface (NMDBusObject *obj, - RegistrationData *reg_data, - GVariantBuilder *builder) -{ - const NMDBusInterfaceInfoExtended *interface_info = _reg_data_get_interface_info (reg_data); - guint i; - - g_variant_builder_init (builder, G_VARIANT_TYPE ("a{sv}")); - if (interface_info->parent.properties) { - for (i = 0; interface_info->parent.properties[i]; i++) { - const NMDBusPropertyInfoExtended *property_info = (const NMDBusPropertyInfoExtended *) interface_info->parent.properties[i]; - gs_unref_variant GVariant *variant = NULL; - - variant = _obj_get_property (reg_data, i, FALSE); - g_variant_builder_add (builder, - "{sv}", - property_info->parent.name, - variant); - } - } - return builder; -} - -static GVariantBuilder * -_obj_collect_properties_all (NMDBusObject *obj, - GVariantBuilder *builder) -{ - RegistrationData *reg_data; - - g_variant_builder_init (builder, G_VARIANT_TYPE ("a{sa{sv}}")); - - c_list_for_each_entry (reg_data, &obj->internal.registration_lst_head, registration_lst) { - GVariantBuilder properties_builder; - - g_variant_builder_add (builder, - "{sa{sv}}", - _reg_data_get_interface_info (reg_data)->parent.name, - _obj_collect_properties_per_interface (obj, - reg_data, - &properties_builder)); - } - - return builder; -} - -static void -dbus_vtable_objmgr_method_call (GDBusConnection *connection, - const char *sender, - const char *object_path, - const char *interface_name, - const char *method_name, - GVariant *parameters, - GDBusMethodInvocation *invocation, - gpointer user_data) -{ - NMDBusManager *self = user_data; - NMDBusManagerPrivate *priv = NM_DBUS_MANAGER_GET_PRIVATE (self); - GVariantBuilder array_builder; - NMDBusObject *obj; - - nm_assert (nm_streq0 (object_path, OBJECT_MANAGER_SERVER_BASE_PATH)); - - if ( !nm_streq (method_name, "GetManagedObjects") - || !nm_streq (interface_name, interface_info_objmgr.name)) { - g_dbus_method_invocation_return_error (invocation, - G_DBUS_ERROR, - G_DBUS_ERROR_UNKNOWN_METHOD, - "Unknown method %s - only GetManagedObjects() is supported", - method_name); - return; - } - - g_variant_builder_init (&array_builder, G_VARIANT_TYPE ("a{oa{sa{sv}}}")); - c_list_for_each_entry (obj, &priv->objects_lst_head, internal.objects_lst) { - GVariantBuilder interfaces_builder; - - /* note that we are called on an idle handler. Hence, all properties are - * supposed to be in a consistent state. That is true, if you always - * g_object_thaw_notify() before returning to the mainloop. Keeping - * signals frozen between while returning from the current call stack - * is anyway a very fragile thing, easy to get wrong. Don't do that. */ - g_variant_builder_add (&array_builder, - "{oa{sa{sv}}}", - obj->internal.path, - _obj_collect_properties_all (obj, - &interfaces_builder)); - } - g_dbus_method_invocation_return_value (invocation, - g_variant_new ("(a{oa{sa{sv}}})", - &array_builder)); -} - -static const GDBusInterfaceVTable dbus_vtable_objmgr = { - .method_call = dbus_vtable_objmgr_method_call -}; - -static const GDBusSignalInfo signal_info_objmgr_interfaces_added = NM_DEFINE_GDBUS_SIGNAL_INFO_INIT ( - "InterfacesAdded", - .args = NM_DEFINE_GDBUS_ARG_INFOS ( - NM_DEFINE_GDBUS_ARG_INFO ("object_path", "o"), - NM_DEFINE_GDBUS_ARG_INFO ("interfaces_and_properties", "a{sa{sv}}"), - ), -); - -static const GDBusSignalInfo signal_info_objmgr_interfaces_removed = NM_DEFINE_GDBUS_SIGNAL_INFO_INIT ( - "InterfacesRemoved", - .args = NM_DEFINE_GDBUS_ARG_INFOS ( - NM_DEFINE_GDBUS_ARG_INFO ("object_path", "o"), - NM_DEFINE_GDBUS_ARG_INFO ("interfaces", "as"), - ), -); - -static const GDBusInterfaceInfo interface_info_objmgr = NM_DEFINE_GDBUS_INTERFACE_INFO_INIT ( - "org.freedesktop.DBus.ObjectManager", - .methods = NM_DEFINE_GDBUS_METHOD_INFOS ( - NM_DEFINE_GDBUS_METHOD_INFO ( - "GetManagedObjects", - .out_args = NM_DEFINE_GDBUS_ARG_INFOS ( - NM_DEFINE_GDBUS_ARG_INFO ("object_paths_interfaces_and_properties", "a{oa{sa{sv}}}"), - ), - ), - ), - .signals = NM_DEFINE_GDBUS_SIGNAL_INFOS ( - &signal_info_objmgr_interfaces_added, - &signal_info_objmgr_interfaces_removed, - ), -); - -/*****************************************************************************/ - -gboolean -nm_dbus_manager_start (NMDBusManager *self, - NMDBusManagerSetPropertyHandler set_property_handler, - gpointer set_property_handler_data) -{ - NMDBusManagerPrivate *priv; - gs_free_error GError *error = NULL; - gs_unref_variant GVariant *ret = NULL; - gs_unref_object GDBusConnection *connection = NULL; - gs_unref_object GDBusProxy *proxy = NULL; - guint32 result; - guint registration_id; - NMDBusObject *obj; - - g_return_val_if_fail (NM_IS_DBUS_MANAGER (self), FALSE); - - priv = NM_DBUS_MANAGER_GET_PRIVATE (self); - - priv->set_property_handler = set_property_handler; - priv->set_property_handler_data = set_property_handler_data; - - g_return_val_if_fail (!priv->connection, FALSE); - - /* we will create the D-Bus connection and registering the name synchronously. - * The reason why that is necessary is because: - * (1) if we are unable to create a D-Bus connection, it means D-Bus is not - * available and we run in D-Bus less mode. We do not support creating - * a D-Bus connection later on. This disconnected mode is useful for initrd - * (well, currently not yet, but will be). - * (2) if we are able to create the connection and register the name, - * all is good and we run with D-Bus. Note that D-Bus disconnects - * from D-Bus are ignored. Essentially, we do not support restarting - * D-Bus. - * (3) if we are able to create the connection but registration fails, - * it means that something is borked. Quite possibly another NetworkManager - * instance is running. We need to exit right away. - * To appease (1) and (3), we cannot initalize synchronously, because we need - * to know right away whether another NetworkManager instance is running (3). - **/ - - connection = g_bus_get_sync (G_BUS_TYPE_SYSTEM, - NULL, - &error); - if (!connection) { - _LOGI ("cannot connect to D-Bus and proceed without (%s)", error->message); - return TRUE; - } - - g_dbus_connection_set_exit_on_close (connection, FALSE); - - proxy = g_dbus_proxy_new_sync (connection, - G_DBUS_PROXY_FLAGS_DO_NOT_LOAD_PROPERTIES - | G_DBUS_PROXY_FLAGS_DO_NOT_CONNECT_SIGNALS, - NULL, - DBUS_SERVICE_DBUS, - DBUS_PATH_DBUS, - DBUS_INTERFACE_DBUS, - NULL, - &error); - if (!proxy) { - _LOGE ("fatal failure to initialize D-Bus: %s", error->message); - return FALSE; - } - - ret = _nm_dbus_proxy_call_sync (proxy, - "RequestName", - g_variant_new ("(su)", - NM_DBUS_SERVICE, - DBUS_NAME_FLAG_DO_NOT_QUEUE), - G_VARIANT_TYPE ("(u)"), - G_DBUS_CALL_FLAGS_NONE, -1, - NULL, - &error); - if (!ret) { - _LOGE ("fatal failure to aquire D-Bus service \"%s"": %s", - NM_DBUS_SERVICE, error->message); - return FALSE; - } - - g_variant_get (ret, "(u)", &result); - if (result != DBUS_REQUEST_NAME_REPLY_PRIMARY_OWNER) { - _LOGE ("fatal failure to acquire D-Bus service \"%s\" (%u). Service already taken", - NM_DBUS_SERVICE, (guint) result); - return FALSE; - } - - registration_id = g_dbus_connection_register_object (connection, - OBJECT_MANAGER_SERVER_BASE_PATH, - NM_UNCONST_PTR (GDBusInterfaceInfo, &interface_info_objmgr), - &dbus_vtable_objmgr, - self, - NULL, - &error); - if (!registration_id) { - _LOGE ("failure to register object manager: %s", error->message); - return FALSE; - } - - priv->objmgr_registration_id = registration_id; - priv->connection = g_steal_pointer (&connection); - priv->proxy = g_steal_pointer (&proxy); - - _LOGI ("aquired D-Bus service \"%s\"", NM_DBUS_SERVICE); - - c_list_for_each_entry (obj, &priv->objects_lst_head, internal.objects_lst) - _obj_register (self, obj); - - return TRUE; -} - -/*****************************************************************************/ - -static void -nm_dbus_manager_init (NMDBusManager *self) -{ - NMDBusManagerPrivate *priv = NM_DBUS_MANAGER_GET_PRIVATE (self); - - c_list_init (&priv->private_servers_lst_head); - c_list_init (&priv->objects_lst_head); - priv->objects_by_path = g_hash_table_new ((GHashFunc) _objects_by_path_hash, (GEqualFunc) _objects_by_path_equal); -} - -static void -dispose (GObject *object) -{ - NMDBusManager *self = NM_DBUS_MANAGER (object); - NMDBusManagerPrivate *priv = NM_DBUS_MANAGER_GET_PRIVATE (self); - PrivateServer *s, *s_safe; - - /* All exported NMDBusObject instances keep the manager alive, so we don't - * expect any remaining objects. */ - nm_assert (!priv->objects_by_path || g_hash_table_size (priv->objects_by_path) == 0); - nm_assert (c_list_is_empty (&priv->objects_lst_head)); - - g_clear_pointer (&priv->objects_by_path, g_hash_table_destroy); - - c_list_for_each_entry_safe (s, s_safe, &priv->private_servers_lst_head, private_servers_lst) - private_server_free (s); - - if (priv->objmgr_registration_id) { - g_dbus_connection_unregister_object (priv->connection, - nm_steal_int (&priv->objmgr_registration_id)); - } - - g_clear_object (&priv->proxy); - g_clear_object (&priv->connection); - - G_OBJECT_CLASS (nm_dbus_manager_parent_class)->dispose (object); -} - -static void -nm_dbus_manager_class_init (NMDBusManagerClass *klass) -{ - GObjectClass *object_class = G_OBJECT_CLASS (klass); - - object_class->dispose = dispose; - - signals[PRIVATE_CONNECTION_NEW] = - g_signal_new (NM_DBUS_MANAGER_PRIVATE_CONNECTION_NEW, - G_OBJECT_CLASS_TYPE (object_class), - G_SIGNAL_RUN_LAST | G_SIGNAL_DETAILED, - 0, NULL, NULL, NULL, - G_TYPE_NONE, 2, G_TYPE_DBUS_CONNECTION, G_TYPE_DBUS_OBJECT_MANAGER_SERVER); - - signals[PRIVATE_CONNECTION_DISCONNECTED] = - g_signal_new (NM_DBUS_MANAGER_PRIVATE_CONNECTION_DISCONNECTED, - G_OBJECT_CLASS_TYPE (object_class), - G_SIGNAL_RUN_LAST | G_SIGNAL_DETAILED, - 0, NULL, NULL, NULL, - G_TYPE_NONE, 1, G_TYPE_POINTER); -} diff --git a/src/nm-dbus-manager.h b/src/nm-dbus-manager.h deleted file mode 100644 index 617f8a67..00000000 --- a/src/nm-dbus-manager.h +++ /dev/null @@ -1,107 +0,0 @@ -/* -*- Mode: C; tab-width: 4; indent-tabs-mode: t; c-basic-offset: 4 -*- */ -/* NetworkManager -- Network link manager - * - * This program is free software; you can redistribute it and/or modify - * it under the terms of the GNU General Public License as published by - * the Free Software Foundation; either version 2 of the License, or - * (at your option) any later version. - * - * This program is distributed in the hope that it will be useful, - * but WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the - * GNU General Public License for more details. - * - * You should have received a copy of the GNU General Public License along - * with this program; if not, write to the Free Software Foundation, Inc., - * 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA. - * - * Copyright (C) 2006 - 2008 Red Hat, Inc. - * Copyright (C) 2006 - 2008 Novell, Inc. - */ - -#ifndef __NM_DBUS_MANAGER_H__ -#define __NM_DBUS_MANAGER_H__ - -#include "nm-dbus-utils.h" - -#define NM_TYPE_DBUS_MANAGER (nm_dbus_manager_get_type ()) -#define NM_DBUS_MANAGER(o) (G_TYPE_CHECK_INSTANCE_CAST ((o), NM_TYPE_DBUS_MANAGER, NMDBusManager)) -#define NM_DBUS_MANAGER_CLASS(k) (G_TYPE_CHECK_CLASS_CAST((k), NM_TYPE_DBUS_MANAGER, NMDBusManagerClass)) -#define NM_IS_DBUS_MANAGER(o) (G_TYPE_CHECK_INSTANCE_TYPE ((o), NM_TYPE_DBUS_MANAGER)) -#define NM_IS_DBUS_MANAGER_CLASS(k) (G_TYPE_CHECK_CLASS_TYPE ((k), NM_TYPE_DBUS_MANAGER)) -#define NM_DBUS_MANAGER_GET_CLASS(o) (G_TYPE_INSTANCE_GET_CLASS ((o), NM_TYPE_DBUS_MANAGER, NMDBusManagerClass)) - -#define NM_DBUS_MANAGER_PRIVATE_CONNECTION_NEW "private-connection-new" -#define NM_DBUS_MANAGER_PRIVATE_CONNECTION_DISCONNECTED "private-connection-disconnected" - -typedef struct _NMDBusManagerClass NMDBusManagerClass; - -GType nm_dbus_manager_get_type (void); - -NMDBusManager *nm_dbus_manager_get (void); - -typedef void (*NMDBusManagerSetPropertyHandler) (NMDBusObject *obj, - const NMDBusInterfaceInfoExtended *interface_info, - const NMDBusPropertyInfoExtended *property_info, - GDBusConnection *connection, - const char *sender, - GDBusMethodInvocation *invocation, - GVariant *value, - gpointer user_data); - -gboolean nm_dbus_manager_start (NMDBusManager *self, - NMDBusManagerSetPropertyHandler handler, - gpointer handler_data); - -GDBusConnection *nm_dbus_manager_get_connection (NMDBusManager *self); - -NMDBusObject *nm_dbus_manager_lookup_object (NMDBusManager *self, const char *path); - -void _nm_dbus_manager_obj_export (NMDBusObject *obj); -void _nm_dbus_manager_obj_unexport (NMDBusObject *obj); -void _nm_dbus_manager_obj_notify (NMDBusObject *obj, - guint n_pspecs, - const GParamSpec *const*pspecs); -void _nm_dbus_manager_obj_emit_signal (NMDBusObject *obj, - const NMDBusInterfaceInfoExtended *interface_info, - const GDBusSignalInfo *signal_info, - GVariant *args); - -gboolean nm_dbus_manager_get_caller_info (NMDBusManager *self, - GDBusMethodInvocation *context, - char **out_sender, - gulong *out_uid, - gulong *out_pid); - -gboolean nm_dbus_manager_ensure_uid (NMDBusManager *self, - GDBusMethodInvocation *context, - gulong uid, - GQuark error_domain, - int error_code); - -const char *nm_dbus_manager_connection_get_private_name (NMDBusManager *self, - GDBusConnection *connection); - -gboolean nm_dbus_manager_get_unix_user (NMDBusManager *self, - const char *sender, - gulong *out_uid); - -gboolean nm_dbus_manager_get_caller_info_from_message (NMDBusManager *self, - GDBusConnection *connection, - GDBusMessage *message, - char **out_sender, - gulong *out_uid, - gulong *out_pid); - -void nm_dbus_manager_private_server_register (NMDBusManager *self, - const char *path, - const char *tag); - -GDBusProxy *nm_dbus_manager_new_proxy (NMDBusManager *self, - GDBusConnection *connection, - GType proxy_type, - const char *name, - const char *path, - const char *iface); - -#endif /* __NM_DBUS_MANAGER_H__ */ diff --git a/src/nm-dbus-object.c b/src/nm-dbus-object.c deleted file mode 100644 index 514fda49..00000000 --- a/src/nm-dbus-object.c +++ /dev/null @@ -1,320 +0,0 @@ -/* -*- Mode: C; tab-width: 4; indent-tabs-mode: t; c-basic-offset: 4 -*- */ -/* NetworkManager -- Network link manager - * - * This program is free software; you can redistribute it and/or modify - * it under the terms of the GNU General Public License as published by - * the Free Software Foundation; either version 2 of the License, or - * (at your option) any later version. - * - * This program is distributed in the hope that it will be useful, - * but WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the - * GNU General Public License for more details. - * - * You should have received a copy of the GNU General Public License along - * with this program; if not, write to the Free Software Foundation, Inc., - * 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA. - * - * Copyright 2018 Red Hat, Inc. - */ - -#include "nm-default.h" - -#include "nm-dbus-object.h" - -#include "nm-dbus-manager.h" - -/*****************************************************************************/ - -static gboolean quitting = FALSE; - -void -nm_dbus_object_set_quitting (void) -{ - nm_assert (!quitting); - quitting = TRUE; -} - -/*****************************************************************************/ - -enum { - EXPORTED_CHANGED, - - LAST_SIGNAL, -}; - -static guint signals[LAST_SIGNAL] = { 0 }; - -G_DEFINE_ABSTRACT_TYPE (NMDBusObject, nm_dbus_object, G_TYPE_OBJECT); - -/*****************************************************************************/ - -#define _NMLOG_DOMAIN LOGD_CORE -#define _NMLOG(level, ...) __NMLOG_DEFAULT_WITH_ADDR (level, _NMLOG_DOMAIN, "dbus-object", __VA_ARGS__) - -#define _NMLOG2_DOMAIN LOGD_DBUS_PROPS -#define _NMLOG2(level, ...) __NMLOG_DEFAULT_WITH_ADDR (level, _NMLOG2_DOMAIN, "properties-changed", __VA_ARGS__) - -/*****************************************************************************/ - -static void -_emit_exported_changed (NMDBusObject *self) -{ - g_signal_emit (self, signals[EXPORTED_CHANGED], 0); -} - -static char * -_create_export_path (NMDBusObjectClass *klass) -{ - nm_assert (NM_IS_DBUS_OBJECT_CLASS (klass)); - nm_assert (klass->export_path.path); - -#if NM_MORE_ASSERTS - { - const char *p; - - p = strchr (klass->export_path.path, '%'); - if (klass->export_path.int_counter) { - nm_assert (p); - nm_assert (p[1] == 'l'); - nm_assert (p[2] == 'l'); - nm_assert (p[3] == 'u'); - nm_assert (p[4] == '\0'); - } else - nm_assert (!p); - } -#endif - - if (klass->export_path.int_counter) { - NM_PRAGMA_WARNING_DISABLE("-Wformat-nonliteral") - return g_strdup_printf (klass->export_path.path, - ++(*klass->export_path.int_counter)); - NM_PRAGMA_WARNING_REENABLE - } - return g_strdup (klass->export_path.path); -} - -/** - * nm_dbus_object_export: - * @self: an #NMDBusObject - * - * Exports @self on all active and future D-Bus connections. - * - * The path to export @self on is taken from its #NMObjectClass's %export_path - * member. If the %export_path contains "%u", then it will be replaced with a - * monotonically increasing integer ID (with each distinct %export_path having - * its own counter). Otherwise, %export_path will be used literally (implying - * that @self must be a singleton). - * - * Returns: the path @self was exported under - */ -const char * -nm_dbus_object_export (NMDBusObject *self) -{ - static guint64 id_counter = 0; - - g_return_val_if_fail (NM_IS_DBUS_OBJECT (self), NULL); - - g_return_val_if_fail (!self->internal.path, self->internal.path); - - nm_assert (!self->internal.is_unexporting); - - self->internal.path = _create_export_path (NM_DBUS_OBJECT_GET_CLASS (self)); - - self->internal.export_version_id = ++id_counter; - - _LOGT ("export: \"%s\"", self->internal.path); - - _nm_dbus_manager_obj_export (self); - - _emit_exported_changed (self); - return self->internal.path; -} - -/** - * nm_dbus_object_unexport: - * @self: an #NMDBusObject - * - * Unexports @self on all active D-Bus connections (and prevents it from being - * auto-exported on future connections). - */ -void -nm_dbus_object_unexport (NMDBusObject *self) -{ - g_return_if_fail (NM_IS_DBUS_OBJECT (self)); - - g_return_if_fail (self->internal.path); - - _LOGT ("unexport: \"%s\"", self->internal.path); - - /* note that we emit the signal *before* actually unexporting the object. - * The reason is, that listeners want to use this signal to know that - * the object goes away, and clear their D-Bus path to this object. - * - * But this must happen before we actually unregister the object, so - * that we first emit a D-Bus signal that other objects no longer - * reference this object, before finally unregistering the object itself. - * - * The inconvenient part is, that at this point nm_dbus_object_get_path() - * still returns the path. So, the callee needs to handle that. Possibly - * by using "nm_dbus_object_get_path_still_exported()". */ - self->internal.is_unexporting = TRUE; - - _emit_exported_changed (self); - - _nm_dbus_manager_obj_unexport (self); - - g_clear_pointer (&self->internal.path, g_free); - self->internal.export_version_id = 0; - - self->internal.is_unexporting = FALSE; -} - -/*****************************************************************************/ - -void -_nm_dbus_object_clear_and_unexport (NMDBusObject **location) -{ - NMDBusObject *self; - - g_return_if_fail (location); - if (!*location) - return; - - self = g_steal_pointer (location); - - g_return_if_fail (NM_IS_DBUS_OBJECT (self)); - - if (self->internal.path) - nm_dbus_object_unexport (self); - - g_object_unref (self); -} - -/*****************************************************************************/ - -void -nm_dbus_object_emit_signal_variant (NMDBusObject *self, - const NMDBusInterfaceInfoExtended *interface_info, - const GDBusSignalInfo *signal_info, - GVariant *args) -{ - if (!self->internal.path) { - nm_g_variant_unref_floating (args); - return; - } - _nm_dbus_manager_obj_emit_signal (self, interface_info, signal_info, args); -} - -void -nm_dbus_object_emit_signal (NMDBusObject *self, - const NMDBusInterfaceInfoExtended *interface_info, - const GDBusSignalInfo *signal_info, - const char *format, - ...) -{ - va_list ap; - - nm_assert (NM_IS_DBUS_OBJECT (self)); - nm_assert (format); - - if (!self->internal.path) - return; - - va_start (ap, format); - _nm_dbus_manager_obj_emit_signal (self, - interface_info, - signal_info, - g_variant_new_va (format, NULL, &ap)); - va_end (ap); -} - -/*****************************************************************************/ - -static void -dispatch_properties_changed (GObject *object, - guint n_pspecs, - GParamSpec **pspecs) -{ - NMDBusObject *self = NM_DBUS_OBJECT (object); - - if (self->internal.path) - _nm_dbus_manager_obj_notify (self, n_pspecs, (const GParamSpec *const*) pspecs); - - G_OBJECT_CLASS (nm_dbus_object_parent_class)->dispatch_properties_changed (object, n_pspecs, pspecs); -} - -/*****************************************************************************/ - -static void -nm_dbus_object_init (NMDBusObject *self) -{ - c_list_init (&self->internal.objects_lst); - c_list_init (&self->internal.registration_lst_head); - self->internal.bus_manager = nm_g_object_ref (nm_dbus_manager_get ()); -} - -static void -constructed (GObject *object) -{ - NMDBusObjectClass *klass; - - G_OBJECT_CLASS (nm_dbus_object_parent_class)->constructed (object); - - klass = NM_DBUS_OBJECT_GET_CLASS (object); - - if (klass->export_on_construction) - nm_dbus_object_export ((NMDBusObject *) object); - - /* NMDBusObject types should be very careful when overwriting notify(). - * It is possible to do, but this is a reminder that it's probably not - * a good idea. - * - * It's not a good idea, because NMDBusObject uses dispatch_properties_changed() - * to emit signals about a bunch of property changes. So, we want to make - * use of g_object_freeze_notify() / g_object_thaw_notify() to combine multiple - * property changes in one signal on D-Bus. Note that notify() is not invoked - * while the signal is frozen, that means, whatever you do inside notify() - * will not make it into the same batch of PropertiesChanged signal. That is - * confusing, and probably not what you want. - * - * Simple solution: don't overwrite notify(). */ - nm_assert (!G_OBJECT_CLASS (klass)->notify); -} - -static void -dispose (GObject *object) -{ - NMDBusObject *self = NM_DBUS_OBJECT (object); - - /* Objects should have already been unexported by their owner, unless - * we are quitting, where many objects stick around until exit. - */ - if (self->internal.path) { - if (!quitting) - g_warn_if_reached (); - nm_dbus_object_unexport (self); - } - - G_OBJECT_CLASS (nm_dbus_object_parent_class)->dispose (object); - - g_clear_object (&self->internal.bus_manager); -} - -static void -nm_dbus_object_class_init (NMDBusObjectClass *klass) -{ - GObjectClass *object_class = G_OBJECT_CLASS (klass); - - object_class->constructed = constructed; - object_class->dispose = dispose; - object_class->dispatch_properties_changed = dispatch_properties_changed; - - signals[EXPORTED_CHANGED] = - g_signal_new (NM_DBUS_OBJECT_EXPORTED_CHANGED, - G_OBJECT_CLASS_TYPE (object_class), - G_SIGNAL_RUN_FIRST, - 0, NULL, NULL, - g_cclosure_marshal_VOID__VOID, - G_TYPE_NONE, 0); -} diff --git a/src/nm-dbus-object.h b/src/nm-dbus-object.h deleted file mode 100644 index 43613630..00000000 --- a/src/nm-dbus-object.h +++ /dev/null @@ -1,202 +0,0 @@ -/* -*- Mode: C; tab-width: 4; indent-tabs-mode: t; c-basic-offset: 4 -*- */ -/* NetworkManager -- Network link manager - * - * This program is free software; you can redistribute it and/or modify - * it under the terms of the GNU General Public License as published by - * the Free Software Foundation; either version 2 of the License, or - * (at your option) any later version. - * - * This program is distributed in the hope that it will be useful, - * but WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the - * GNU General Public License for more details. - * - * You should have received a copy of the GNU General Public License along - * with this program; if not, write to the Free Software Foundation, Inc., - * 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA. - * - * Copyright 2018 Red Hat, Inc. - */ - -#ifndef __NM_DBUS_OBJECT_H__ -#define __NM_DBUS_OBJECT_H__ - -/*****************************************************************************/ - -#include "c-list/src/c-list.h" -#include "nm-dbus-utils.h" - -/*****************************************************************************/ - -void nm_dbus_object_set_quitting (void); - -/*****************************************************************************/ - -typedef struct { - const char *path; - - /* if path is of type NM_DBUS_EXPORT_PATH_NUMBERED(), we need a - * per-class counter when generating a new numbered path. - * - * Each NMDBusObjectClass instance has a shallow clone of the NMDBusObjectClass parent - * instance in every derived type. Hence we cannot embed the counter there directly, - * because it must be shared, e.g. between NMDeviceBond and NMDeviceEthernet. - * Make int_counter a pointer to the actual counter that is used by ever sibling - * class. */ - long long unsigned *int_counter; -} NMDBusExportPath; - -#define NM_DBUS_EXPORT_PATH_STATIC(basepath) \ - ({ \ - ((NMDBusExportPath) { \ - .path = ""basepath"", \ - }); \ - }) - -#define NM_DBUS_EXPORT_PATH_NUMBERED(basepath) \ - ({ \ - static long long unsigned _int_counter = 0; \ - ((NMDBusExportPath) { \ - .path = ""basepath"/%llu", \ - .int_counter = &_int_counter, \ - }); \ - }) - -/*****************************************************************************/ - -/* "org.freedesktop.NetworkManager.Device.Statistics" is a special interface, - * because although it has a legacy PropertiesChanged signal, it only notifies - * about properties that actually exist on that interface. That is, because it - * was added with 1.4.0 release, and thus didn't have the broken behavior like - * other legacy interfaces. Those notify about *all* properties, even if they - * are not part of that D-Bus interface. See also "include_in_legacy_property_changed" - * and "legacy_property_changed". */ -extern const NMDBusInterfaceInfoExtended nm_interface_info_device_statistics; - -/*****************************************************************************/ - -#define NM_TYPE_DBUS_OBJECT (nm_dbus_object_get_type ()) -#define NM_DBUS_OBJECT(obj) (G_TYPE_CHECK_INSTANCE_CAST ((obj), NM_TYPE_DBUS_OBJECT, NMDBusObject)) -#define NM_DBUS_OBJECT_CLASS(klass) (G_TYPE_CHECK_CLASS_CAST ((klass), NM_TYPE_DBUS_OBJECT, NMDBusObjectClass)) -#define NM_IS_DBUS_OBJECT(obj) (G_TYPE_CHECK_INSTANCE_TYPE ((obj), NM_TYPE_DBUS_OBJECT)) -#define NM_IS_DBUS_OBJECT_CLASS(klass) (G_TYPE_CHECK_CLASS_TYPE ((klass), NM_TYPE_DBUS_OBJECT)) -#define NM_DBUS_OBJECT_GET_CLASS(obj) (G_TYPE_INSTANCE_GET_CLASS ((obj), NM_TYPE_DBUS_OBJECT, NMDBusObjectClass)) - -#define NM_DBUS_OBJECT_EXPORTED_CHANGED "exported-changed" - -/* NMDBusObject and NMDBusManager cooperate strongly. Hence, there is an - * internal data structure attached to the NMDBusObject accessible to both of them. */ -struct _NMDBusObjectInternal { - char *path; - NMDBusManager *bus_manager; - CList objects_lst; - CList registration_lst_head; - - /* we perform asynchronous operation on exported objects. For example, we receive - * a Set property call, and asynchronously validate the operation. We must make - * sure that when the authentication is complete, that we are still looking at - * the same (exported) object. In the meantime, the object could have been - * unexported, or even re-exported afterwards. If that happens, we want - * to fail the request. For that, we keep track of a version id. */ - guint64 export_version_id; - bool is_unexporting:1; -}; - -struct _NMDBusObject { - GObject parent; - struct _NMDBusObjectInternal internal; -}; - -#define NM_DEFINE_DBUS_INTERFACE_INFO(...) \ - ((NMDBusInterfaceInfo *) (&((const NMDBusInterfaceInfo) { \ - __VA_ARGS__ \ - }))) - -typedef struct { - GObjectClass parent; - - NMDBusExportPath export_path; - - const NMDBusInterfaceInfoExtended *const*interface_infos; - - bool export_on_construction; -} NMDBusObjectClass; - -GType nm_dbus_object_get_type (void); - -static inline NMDBusManager * -nm_dbus_object_get_manager (NMDBusObject *obj) -{ - nm_assert (NM_IS_DBUS_OBJECT (obj)); - - return obj->internal.bus_manager; -} - -static inline guint64 -nm_dbus_object_get_export_version_id (NMDBusObject *obj) -{ - nm_assert (NM_IS_DBUS_OBJECT (obj)); - - return obj->internal.export_version_id; -} - -/** - * nm_dbus_object_get_path: - * @self: an #NMDBusObject - * - * Gets @self's D-Bus path. - * - * Returns: @self's D-Bus path, or %NULL if @self is not exported. - */ -static inline const char * -nm_dbus_object_get_path (NMDBusObject *self) -{ - g_return_val_if_fail (NM_IS_DBUS_OBJECT (self), NULL); - - return self->internal.path; -} - -/** - * nm_dbus_object_is_exported: - * @self: an #NMDBusObject - * - * Checks if @self is exported - * - * Returns: %TRUE if @self is exported - */ -static inline gboolean -nm_dbus_object_is_exported (NMDBusObject *self) -{ - return !!nm_dbus_object_get_path (self); -} - -static inline const char * -nm_dbus_object_get_path_still_exported (NMDBusObject *self) -{ - g_return_val_if_fail (NM_IS_DBUS_OBJECT (self), NULL); - - /* like nm_dbus_object_get_path(), however, while unexporting - * (exported-changed signal), returns %NULL instead of the path. */ - return self->internal.is_unexporting - ? NULL - : self->internal.path; -} - -const char *nm_dbus_object_export (NMDBusObject *self); -void nm_dbus_object_unexport (NMDBusObject *self); - -void _nm_dbus_object_clear_and_unexport (NMDBusObject **location); -#define nm_dbus_object_clear_and_unexport(location) _nm_dbus_object_clear_and_unexport ((NMDBusObject **) (location)) - -void nm_dbus_object_emit_signal_variant (NMDBusObject *self, - const NMDBusInterfaceInfoExtended *interface_info, - const GDBusSignalInfo *signal_info, - GVariant *args); - -void nm_dbus_object_emit_signal (NMDBusObject *self, - const NMDBusInterfaceInfoExtended *interface_info, - const GDBusSignalInfo *signal_info, - const char *format, - ...); - -#endif /* __NM_DBUS_OBJECT_H__ */ diff --git a/src/nm-dbus-utils.c b/src/nm-dbus-utils.c deleted file mode 100644 index 8e7dd122..00000000 --- a/src/nm-dbus-utils.c +++ /dev/null @@ -1,312 +0,0 @@ -/* -*- Mode: C; tab-width: 4; indent-tabs-mode: t; c-basic-offset: 4 -*- */ -/* NetworkManager -- Network link manager - * - * This program is free software; you can redistribute it and/or modify - * it under the terms of the GNU General Public License as published by - * the Free Software Foundation; either version 2 of the License, or - * (at your option) any later version. - * - * This program is distributed in the hope that it will be useful, - * but WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the - * GNU General Public License for more details. - * - * You should have received a copy of the GNU General Public License along - * with this program; if not, write to the Free Software Foundation, Inc., - * 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA. - * - * Copyright 2018 Red Hat, Inc. - */ - -#include "nm-default.h" - -#include "nm-dbus-utils.h" - -#include "nm-dbus-object.h" - -/*****************************************************************************/ - -const GDBusSignalInfo nm_signal_info_property_changed_legacy = NM_DEFINE_GDBUS_SIGNAL_INFO_INIT ( - "PropertiesChanged", - .args = NM_DEFINE_GDBUS_ARG_INFOS ( - NM_DEFINE_GDBUS_ARG_INFO ("properties", "a{sv}"), - ), -); - -GDBusPropertyInfo * -nm_dbus_utils_interface_info_lookup_property (const GDBusInterfaceInfo *interface_info, - const char *property_name, - guint *property_idx) -{ - guint i; - - nm_assert (interface_info); - nm_assert (property_name); - - /* there is also g_dbus_interface_info_lookup_property(), however that makes use - * of a global cache. */ - if (interface_info->properties) { - for (i = 0; interface_info->properties[i]; i++) { - GDBusPropertyInfo *info = interface_info->properties[i]; - - if (nm_streq (info->name, property_name)) { - NM_SET_OUT (property_idx, i); - return info; - } - } - } - - return NULL; -} - -GDBusMethodInfo * -nm_dbus_utils_interface_info_lookup_method (const GDBusInterfaceInfo *interface_info, - const char *method_name) -{ - guint i; - - nm_assert (interface_info); - nm_assert (method_name); - - /* there is also g_dbus_interface_info_lookup_property(), however that makes use - * of a global cache. */ - if (interface_info->methods) { - for (i = 0; interface_info->methods[i]; i++) { - GDBusMethodInfo *info = interface_info->methods[i]; - - if (nm_streq (info->name, method_name)) - return info; - } - } - - return NULL; -} - -GVariant * -nm_dbus_utils_get_property (GObject *obj, - const char *signature, - const char *property_name) -{ - GParamSpec *pspec; - nm_auto_unset_gvalue GValue value = G_VALUE_INIT; - - nm_assert (G_IS_OBJECT (obj)); - nm_assert (g_variant_type_string_is_valid (signature)); - nm_assert (property_name && property_name[0]); - - pspec = g_object_class_find_property (G_OBJECT_GET_CLASS (obj), property_name); - if (!pspec) - g_return_val_if_reached (NULL); - - g_value_init (&value, pspec->value_type); - g_object_get_property (obj, property_name, &value); - /* returns never-floating variant */ - return g_dbus_gvalue_to_gvariant (&value, G_VARIANT_TYPE (signature)); -} - -/*****************************************************************************/ - -void -nm_dbus_utils_g_value_set_object_path (GValue *value, gpointer object) -{ - const char *path; - - g_return_if_fail (!object || NM_IS_DBUS_OBJECT (object)); - - if ( object - && (path = nm_dbus_object_get_path (object))) - g_value_set_string (value, path); - else - g_value_set_string (value, NULL); -} - -void -nm_dbus_utils_g_value_set_object_path_still_exported (GValue *value, gpointer object) -{ - const char *path; - - g_return_if_fail (!object || NM_IS_DBUS_OBJECT (object)); - - if ( object - && (path = nm_dbus_object_get_path_still_exported (object))) - g_value_set_string (value, path); - else - g_value_set_string (value, "/"); -} - -void -nm_dbus_utils_g_value_set_object_path_from_hash (GValue *value, - GHashTable *hash /* has keys of NMDBusObject type. */, - gboolean expect_all_exported) -{ - NMDBusObject *obj; - char **strv; - guint i, n; - GHashTableIter iter; - - nm_assert (value); - nm_assert (hash); - - n = g_hash_table_size (hash); - strv = g_new (char *, n + 1); - i = 0; - g_hash_table_iter_init (&iter, hash); - while (g_hash_table_iter_next (&iter, (gpointer *) &obj, NULL)) { - const char *path; - - path = nm_dbus_object_get_path (obj); - if (!path) { - nm_assert (!expect_all_exported); - continue; - } - strv[i++] = g_strdup (path); - } - nm_assert (i <= n); - strv[i] = NULL; - - /* sort the names, to give a well-defined, stable order. */ - nm_utils_strv_sort (strv, i); - - g_value_take_boxed (value, strv); -} - -const char ** -nm_dbus_utils_get_paths_for_clist (const CList *lst_head, - gssize lst_len, - guint member_offset, - gboolean expect_all_exported) -{ - const CList *iter; - const char **strv; - const char *path; - gsize i, n; - - nm_assert (lst_head); - - if (lst_len < 0) - n = c_list_length (lst_head); - else { - n = lst_len; - nm_assert (n == c_list_length (lst_head)); - } - - i = 0; - strv = g_new (const char *, n + 1); - c_list_for_each (iter, lst_head) { - NMDBusObject *obj = (NMDBusObject *) (((const char *) iter) - member_offset); - - path = nm_dbus_object_get_path (obj); - if (!path) { - nm_assert (expect_all_exported); - continue; - } - - nm_assert (i < n); - strv[i++] = path; - } - nm_assert (i <= n); - strv[i] = NULL; - - return strv; -} - -/*****************************************************************************/ - -void -nm_dbus_track_obj_path_init (NMDBusTrackObjPath *track, - GObject *target, - const GParamSpec *pspec) -{ - nm_assert (track); - nm_assert (G_IS_OBJECT (target)); - nm_assert (G_IS_PARAM_SPEC (pspec)); - - track->_obj = NULL; - track->_notify_target = target; - track->_notify_pspec = pspec; - track->_notify_signal_id = 0; - track->_visible = FALSE; -} - -void -nm_dbus_track_obj_path_deinit (NMDBusTrackObjPath *track) -{ - /* we allow deinit() to be called multiple times (e.g. from - * dispose(), which must be re-entrant). */ - nm_assert (track); - nm_assert (!track->_notify_target || G_IS_OBJECT (track->_notify_target)); - - nm_clear_g_signal_handler (track->obj, &track->_notify_signal_id); - track->_notify_target = NULL; - track->_notify_pspec = NULL; - track->_visible = FALSE; - nm_clear_g_object (&track->_obj); -} - -void -nm_dbus_track_obj_path_notify (const NMDBusTrackObjPath *track) -{ - nm_assert (track); - nm_assert (G_IS_OBJECT (track->_notify_target)); - nm_assert (G_IS_PARAM_SPEC (track->_notify_pspec)); - - g_object_notify_by_pspec (track->_notify_target, - (GParamSpec *) track->_notify_pspec); -} - -const char * -nm_dbus_track_obj_path_get (const NMDBusTrackObjPath *track) -{ - nm_assert (track); - nm_assert (G_IS_OBJECT (track->_notify_target)); - - return track->obj && track->visible - ? nm_dbus_object_get_path_still_exported (track->obj) - : NULL; -} - -static void -_track_obj_exported_changed (NMDBusObject *obj, - NMDBusTrackObjPath *track) -{ - nm_dbus_track_obj_path_notify (track); -} - -void -nm_dbus_track_obj_path_set (NMDBusTrackObjPath *track, - gpointer obj, - gboolean visible) -{ - gs_unref_object NMDBusObject *old_obj = NULL; - const char *old_path; - - nm_assert (track); - nm_assert (G_IS_OBJECT (track->_notify_target)); - - g_return_if_fail (!obj || NM_IS_DBUS_OBJECT (obj)); - - if ( track->obj == obj - && track->visible == !!visible) - return; - - old_path = nm_dbus_track_obj_path_get (track); - - track->_visible = visible; - - if (track->obj != obj) { - nm_clear_g_signal_handler (track->obj, &track->_notify_signal_id); - - old_obj = track->obj; - track->_obj = nm_g_object_ref (obj); - - if (obj) { - track->_notify_signal_id = g_signal_connect (obj, - NM_DBUS_OBJECT_EXPORTED_CHANGED, - G_CALLBACK (_track_obj_exported_changed), - track); - } - } - - if (!nm_streq0 (old_path, nm_dbus_track_obj_path_get (track))) - nm_dbus_track_obj_path_notify (track); -} diff --git a/src/nm-dbus-utils.h b/src/nm-dbus-utils.h deleted file mode 100644 index e7e930e9..00000000 --- a/src/nm-dbus-utils.h +++ /dev/null @@ -1,212 +0,0 @@ -/* -*- Mode: C; tab-width: 4; indent-tabs-mode: t; c-basic-offset: 4 -*- */ -/* NetworkManager -- Network link manager - * - * This program is free software; you can redistribute it and/or modify - * it under the terms of the GNU General Public License as published by - * the Free Software Foundation; either version 2 of the License, or - * (at your option) any later version. - * - * This program is distributed in the hope that it will be useful, - * but WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the - * GNU General Public License for more details. - * - * You should have received a copy of the GNU General Public License along - * with this program; if not, write to the Free Software Foundation, Inc., - * 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA. - * - * Copyright 2018 Red Hat, Inc. - */ - -#ifndef __NM_DBUS_UTILS_H__ -#define __NM_DBUS_UTILS_H__ - -/*****************************************************************************/ - -struct _NMDBusInterfaceInfoExtended; -struct _NMDBusMethodInfoExtended; - -struct _NMDBusPropertyInfoExtendedBase { - GDBusPropertyInfo _parent; - const char *property_name; - - /* Whether the properties needs to be notified on the legacy - * PropertyChanged signal. This is only to preserve API, new - * properties should not use this. */ - bool include_in_legacy_property_changed; -}; - -struct _NMDBusPropertyInfoExtendedReadWritable { - struct _NMDBusPropertyInfoExtendedBase _base; - - /* this is the polkit permission type for authenticating setting - * the property. */ - const char *permission; - - /* this is the audit operation type for writing the property. */ - const char *audit_op; -}; - -typedef struct { - union { - - GDBusPropertyInfo _parent; - struct _NMDBusPropertyInfoExtendedBase _base; - struct _NMDBusPropertyInfoExtendedReadWritable writable; - - /* duplicate the base structure in the union, so that the common fields - * are accessible directly in the parent struct. */ - struct { - GDBusPropertyInfo parent; - const char *property_name; - - /* Whether the properties needs to be notified on the legacy - * PropertyChanged signal. This is only to preserve API, new - * properties should not use this. */ - bool include_in_legacy_property_changed; - }; - }; -} NMDBusPropertyInfoExtended; - -G_STATIC_ASSERT (G_STRUCT_OFFSET (NMDBusPropertyInfoExtended, property_name) == G_STRUCT_OFFSET (struct _NMDBusPropertyInfoExtendedBase, property_name)); -G_STATIC_ASSERT (G_STRUCT_OFFSET (NMDBusPropertyInfoExtended, include_in_legacy_property_changed) == G_STRUCT_OFFSET (struct _NMDBusPropertyInfoExtendedBase, include_in_legacy_property_changed)); - -#define NM_DEFINE_DBUS_PROPERTY_INFO_EXTENDED_READABLE_FULL(m_name, m_signature, m_property_name, m_include_in_legacy_property_changed) \ - ((GDBusPropertyInfo *) &((const struct _NMDBusPropertyInfoExtendedBase) { \ - ._parent = { \ - .ref_count = -1, \ - .name = m_name, \ - .signature = m_signature, \ - .flags = G_DBUS_PROPERTY_INFO_FLAGS_READABLE, \ - }, \ - .property_name = m_property_name, \ - .include_in_legacy_property_changed = m_include_in_legacy_property_changed, \ - })) - -#define NM_DEFINE_DBUS_PROPERTY_INFO_EXTENDED_READABLE(m_name, m_signature, m_property_name) \ - NM_DEFINE_DBUS_PROPERTY_INFO_EXTENDED_READABLE_FULL (m_name, m_signature, m_property_name, FALSE) - -/* define a legacy property. Do not use for new code. */ -#define NM_DEFINE_DBUS_PROPERTY_INFO_EXTENDED_READABLE_L(m_name, m_signature, m_property_name) \ - NM_DEFINE_DBUS_PROPERTY_INFO_EXTENDED_READABLE_FULL (m_name, m_signature, m_property_name, TRUE) - -#define NM_DEFINE_DBUS_PROPERTY_INFO_EXTENDED_READWRITABLE_FULL(m_name, m_signature, m_property_name, m_permission, m_audit_op, m_include_in_legacy_property_changed) \ - ((GDBusPropertyInfo *) &((const struct _NMDBusPropertyInfoExtendedReadWritable) { \ - ._base = { \ - ._parent = { \ - .ref_count = -1, \ - .name = m_name, \ - .signature = m_signature, \ - .flags = G_DBUS_PROPERTY_INFO_FLAGS_READABLE | G_DBUS_PROPERTY_INFO_FLAGS_WRITABLE, \ - }, \ - .property_name = m_property_name, \ - .include_in_legacy_property_changed = m_include_in_legacy_property_changed, \ - }, \ - .permission = m_permission, \ - .audit_op = m_audit_op, \ - })) - -#define NM_DEFINE_DBUS_PROPERTY_INFO_EXTENDED_READWRITABLE(m_name, m_signature, m_property_name, m_permission, m_audit_op) \ - NM_DEFINE_DBUS_PROPERTY_INFO_EXTENDED_READWRITABLE_FULL (m_name, m_signature, m_property_name, m_permission, m_audit_op, FALSE) - -/* define a legacy property. Do not use for new code. */ -#define NM_DEFINE_DBUS_PROPERTY_INFO_EXTENDED_READWRITABLE_L(m_name, m_signature, m_property_name, m_permission, m_audit_op) \ - NM_DEFINE_DBUS_PROPERTY_INFO_EXTENDED_READWRITABLE_FULL (m_name, m_signature, m_property_name, m_permission, m_audit_op, TRUE) - -typedef struct _NMDBusMethodInfoExtended { - GDBusMethodInfo parent; - void (*handle) (NMDBusObject *obj, - const struct _NMDBusInterfaceInfoExtended *interface_info, - const struct _NMDBusMethodInfoExtended *method_info, - GDBusConnection *connection, - const char *sender, - GDBusMethodInvocation *invocation, - GVariant *parameters); -} NMDBusMethodInfoExtended; - -#define NM_DEFINE_DBUS_METHOD_INFO_EXTENDED(parent_, ...) \ - ((GDBusMethodInfo *) (&((const NMDBusMethodInfoExtended) { \ - .parent = parent_, \ - __VA_ARGS__ \ - }))) - -typedef struct _NMDBusInterfaceInfoExtended { - GDBusInterfaceInfo parent; - - /* Whether the interface has a legacy property changed signal (@nm_signal_info_property_changed_legacy). - * New interfaces should not use this. */ - bool legacy_property_changed:1; -} NMDBusInterfaceInfoExtended; - -extern const GDBusSignalInfo nm_signal_info_property_changed_legacy; - -#define NM_DBUS_INTERFACE_INFOS(...) \ - ({ \ - static const NMDBusInterfaceInfoExtended *const _interface_infos[] = { \ - __VA_ARGS__, \ - NULL, \ - }; \ - _interface_infos; \ - }); - -/*****************************************************************************/ - -GDBusPropertyInfo *nm_dbus_utils_interface_info_lookup_property (const GDBusInterfaceInfo *interface_info, - const char *property_name, - guint *property_idx); - -GDBusMethodInfo *nm_dbus_utils_interface_info_lookup_method (const GDBusInterfaceInfo *interface_info, - const char *method_name); - -GVariant *nm_dbus_utils_get_property (GObject *obj, - const char *signature, - const char *property_name); - -/*****************************************************************************/ - -struct CList; - -const char **nm_dbus_utils_get_paths_for_clist (const struct CList *lst_head, - gssize lst_len, - guint member_offset, - gboolean expect_all_exported); - -void nm_dbus_utils_g_value_set_object_path (GValue *value, gpointer object); - -void nm_dbus_utils_g_value_set_object_path_still_exported (GValue *value, gpointer object); - -void nm_dbus_utils_g_value_set_object_path_from_hash (GValue *value, - GHashTable *hash, - gboolean expect_all_exported); - -/*****************************************************************************/ - -typedef struct { - union { - gpointer const obj; - gpointer _obj; - }; - GObject *_notify_target; - const GParamSpec *_notify_pspec; - gulong _notify_signal_id; - union { - const bool visible; - bool _visible; - }; -} NMDBusTrackObjPath; - -void nm_dbus_track_obj_path_init (NMDBusTrackObjPath *track, - GObject *target, - const GParamSpec *pspec); - -void nm_dbus_track_obj_path_deinit (NMDBusTrackObjPath *track); - -void nm_dbus_track_obj_path_notify (const NMDBusTrackObjPath *track); - -const char *nm_dbus_track_obj_path_get (const NMDBusTrackObjPath *track); - -void nm_dbus_track_obj_path_set (NMDBusTrackObjPath *track, - gpointer obj, - gboolean visible); - -#endif /* __NM_DBUS_UTILS_H__ */ diff --git a/src/nm-dhcp4-config.c b/src/nm-dhcp4-config.c index 08becf3c..10f58bc6 100644 --- a/src/nm-dhcp4-config.c +++ b/src/nm-dhcp4-config.c @@ -26,7 +26,9 @@ #include "nm-dbus-interface.h" #include "nm-utils.h" -#include "nm-dbus-object.h" +#include "nm-exported-object.h" + +#include "introspection/org.freedesktop.NetworkManager.DHCP4Config.h" /*****************************************************************************/ @@ -39,15 +41,15 @@ typedef struct { } NMDhcp4ConfigPrivate; struct _NMDhcp4Config { - NMDBusObject parent; + NMExportedObject parent; NMDhcp4ConfigPrivate _priv; }; struct _NMDhcp4ConfigClass { - NMDBusObjectClass parent; + NMExportedObjectClass parent; }; -G_DEFINE_TYPE (NMDhcp4Config, nm_dhcp4_config, NM_TYPE_DBUS_OBJECT) +G_DEFINE_TYPE (NMDhcp4Config, nm_dhcp4_config, NM_TYPE_EXPORTED_OBJECT) #define NM_DHCP4_CONFIG_GET_PRIVATE(self) _NM_GET_PRIVATE (self, NMDhcp4Config, NM_IS_DHCP4_CONFIG) @@ -145,31 +147,17 @@ finalize (GObject *object) G_OBJECT_CLASS (nm_dhcp4_config_parent_class)->finalize (object); } -static const NMDBusInterfaceInfoExtended interface_info_dhcp4_config = { - .parent = NM_DEFINE_GDBUS_INTERFACE_INFO_INIT ( - NM_DBUS_INTERFACE_DHCP4_CONFIG, - .signals = NM_DEFINE_GDBUS_SIGNAL_INFOS ( - &nm_signal_info_property_changed_legacy, - ), - .properties = NM_DEFINE_GDBUS_PROPERTY_INFOS ( - NM_DEFINE_DBUS_PROPERTY_INFO_EXTENDED_READABLE_L ("Options", "a{sv}", NM_DHCP4_CONFIG_OPTIONS), - ), - ), - .legacy_property_changed = TRUE, -}; - static void nm_dhcp4_config_class_init (NMDhcp4ConfigClass *config_class) { GObjectClass *object_class = G_OBJECT_CLASS (config_class); - NMDBusObjectClass *dbus_object_class = NM_DBUS_OBJECT_CLASS (config_class); + NMExportedObjectClass *exported_object_class = NM_EXPORTED_OBJECT_CLASS (config_class); object_class->get_property = get_property; object_class->finalize = finalize; - dbus_object_class->export_path = NM_DBUS_EXPORT_PATH_NUMBERED (NM_DBUS_PATH"/DHCP4Config"); - dbus_object_class->interface_infos = NM_DBUS_INTERFACE_INFOS (&interface_info_dhcp4_config); - dbus_object_class->export_on_construction = TRUE; + exported_object_class->export_path = NM_EXPORT_PATH_NUMBERED (NM_DBUS_PATH"/DHCP4Config"); + exported_object_class->export_on_construction = TRUE; obj_properties[PROP_OPTIONS] = g_param_spec_variant (NM_DHCP4_CONFIG_OPTIONS, "", "", @@ -179,4 +167,8 @@ nm_dhcp4_config_class_init (NMDhcp4ConfigClass *config_class) G_PARAM_STATIC_STRINGS); g_object_class_install_properties (object_class, _PROPERTY_ENUMS_LAST, obj_properties); + + nm_exported_object_class_add_interface (NM_EXPORTED_OBJECT_CLASS (config_class), + NMDBUS_TYPE_DHCP4_CONFIG_SKELETON, + NULL); } diff --git a/src/nm-dhcp6-config.c b/src/nm-dhcp6-config.c index 5bb6c740..d51d77ef 100644 --- a/src/nm-dhcp6-config.c +++ b/src/nm-dhcp6-config.c @@ -26,7 +26,9 @@ #include "nm-dbus-interface.h" #include "nm-utils.h" -#include "nm-dbus-object.h" +#include "nm-exported-object.h" + +#include "introspection/org.freedesktop.NetworkManager.DHCP6Config.h" /*****************************************************************************/ @@ -39,15 +41,15 @@ typedef struct { } NMDhcp6ConfigPrivate; struct _NMDhcp6Config { - NMDBusObject parent; + NMExportedObject parent; NMDhcp6ConfigPrivate _priv; }; struct _NMDhcp6ConfigClass { - NMDBusObjectClass parent; + NMExportedObjectClass parent; }; -G_DEFINE_TYPE (NMDhcp6Config, nm_dhcp6_config, NM_TYPE_DBUS_OBJECT) +G_DEFINE_TYPE (NMDhcp6Config, nm_dhcp6_config, NM_TYPE_EXPORTED_OBJECT) #define NM_DHCP6_CONFIG_GET_PRIVATE(self) _NM_GET_PRIVATE (self, NMDhcp6Config, NM_IS_DHCP6_CONFIG) @@ -143,31 +145,17 @@ finalize (GObject *object) G_OBJECT_CLASS (nm_dhcp6_config_parent_class)->finalize (object); } -static const NMDBusInterfaceInfoExtended interface_info_dhcp6_config = { - .parent = NM_DEFINE_GDBUS_INTERFACE_INFO_INIT ( - NM_DBUS_INTERFACE_DHCP6_CONFIG, - .signals = NM_DEFINE_GDBUS_SIGNAL_INFOS ( - &nm_signal_info_property_changed_legacy, - ), - .properties = NM_DEFINE_GDBUS_PROPERTY_INFOS ( - NM_DEFINE_DBUS_PROPERTY_INFO_EXTENDED_READABLE_L ("Options", "a{sv}", NM_DHCP6_CONFIG_OPTIONS), - ), - ), - .legacy_property_changed = TRUE, -}; - static void nm_dhcp6_config_class_init (NMDhcp6ConfigClass *config_class) { GObjectClass *object_class = G_OBJECT_CLASS (config_class); - NMDBusObjectClass *dbus_object_class = NM_DBUS_OBJECT_CLASS (config_class); + NMExportedObjectClass *exported_object_class = NM_EXPORTED_OBJECT_CLASS (config_class); object_class->get_property = get_property; object_class->finalize = finalize; - dbus_object_class->export_path = NM_DBUS_EXPORT_PATH_NUMBERED (NM_DBUS_PATH"/DHCP6Config"); - dbus_object_class->interface_infos = NM_DBUS_INTERFACE_INFOS (&interface_info_dhcp6_config); - dbus_object_class->export_on_construction = TRUE; + exported_object_class->export_path = NM_EXPORT_PATH_NUMBERED (NM_DBUS_PATH"/DHCP6Config"); + exported_object_class->export_on_construction = TRUE; obj_properties[PROP_OPTIONS] = g_param_spec_variant (NM_DHCP6_CONFIG_OPTIONS, "", "", @@ -177,4 +165,8 @@ nm_dhcp6_config_class_init (NMDhcp6ConfigClass *config_class) G_PARAM_STATIC_STRINGS); g_object_class_install_properties (object_class, _PROPERTY_ENUMS_LAST, obj_properties); + + nm_exported_object_class_add_interface (NM_EXPORTED_OBJECT_CLASS (config_class), + NMDBUS_TYPE_DHCP6_CONFIG_SKELETON, + NULL); } diff --git a/src/nm-dispatcher.c b/src/nm-dispatcher.c index 235134c8..237afdef 100644 --- a/src/nm-dispatcher.c +++ b/src/nm-dispatcher.c @@ -284,10 +284,9 @@ fill_device_props (NMDevice *device, g_variant_new_uint32 (nm_device_get_device_type (device))); g_variant_builder_add (dev_builder, "{sv}", NMD_DEVICE_PROPS_STATE, g_variant_new_uint32 (nm_device_get_state (device))); - if (nm_dbus_object_is_exported (NM_DBUS_OBJECT (device))) { + if (nm_exported_object_is_exported (NM_EXPORTED_OBJECT (device))) g_variant_builder_add (dev_builder, "{sv}", NMD_DEVICE_PROPS_PATH, - g_variant_new_object_path (nm_dbus_object_get_path (NM_DBUS_OBJECT (device)))); - } + g_variant_new_object_path (nm_exported_object_get_path (NM_EXPORTED_OBJECT (device)))); proxy_config = nm_device_get_proxy_config (device); if (proxy_config) @@ -346,8 +345,8 @@ static void _ensure_requests (void) { if (G_UNLIKELY (requests == NULL)) { - requests = g_hash_table_new_full (nm_direct_hash, - NULL, + requests = g_hash_table_new_full (g_direct_hash, + g_direct_equal, NULL, (GDestroyNotify) dispatcher_info_free); } @@ -579,7 +578,7 @@ _dispatcher_call (NMDispatcherAction action, const char *connection_path; const char *filename; - connection_path = nm_dbus_object_get_path (NM_DBUS_OBJECT (settings_connection)); + connection_path = nm_connection_get_path (NM_CONNECTION (settings_connection)); if (connection_path) { g_variant_builder_add (&connection_props, "{sv}", NMD_CONNECTION_PROPS_PATH, @@ -631,7 +630,9 @@ _dispatcher_call (NMDispatcherAction action, if (!device_dhcp6_props) device_dhcp6_props = g_variant_ref_sink (g_variant_new_array (G_VARIANT_TYPE ("{sv}"), NULL, 0)); +#if WITH_CONCHECK connectivity_state_string = nm_connectivity_state_to_string (connectivity_state); +#endif /* Send the action to the dispatcher */ if (blocking) { diff --git a/src/nm-exported-object.c b/src/nm-exported-object.c new file mode 100644 index 00000000..94264caa --- /dev/null +++ b/src/nm-exported-object.c @@ -0,0 +1,1055 @@ +/* -*- Mode: C; tab-width: 4; indent-tabs-mode: t; c-basic-offset: 4 -*- */ +/* NetworkManager -- Network link manager + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation; either version 2 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License along + * with this program; if not, write to the Free Software Foundation, Inc., + * 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA. + * + * Copyright 2014-2016 Red Hat, Inc. + */ + +#include "nm-default.h" + +#include "nm-exported-object.h" + +#include <stdarg.h> +#include <string.h> + +#include "nm-bus-manager.h" + +#include "devices/nm-device.h" +#include "nm-active-connection.h" +#include "introspection/org.freedesktop.NetworkManager.Device.Statistics.h" + +#if NM_MORE_ASSERTS >= 2 +#define _ASSERT_NO_EARLY_EXPORT +#endif + +/*****************************************************************************/ + +static gboolean quitting = FALSE; + +/*****************************************************************************/ + +NM_GOBJECT_PROPERTIES_DEFINE (NMExportedObject, + PROP_PATH, +); + +typedef struct { + GDBusInterfaceSkeleton *interface; + guint property_changed_signal_id; + GHashTable *pending_notifies; +} InterfaceData; + +typedef struct _NMExportedObjectPrivate { + NMBusManager *bus_mgr; + char *path; + + InterfaceData *interfaces; + guint num_interfaces; + + guint notify_idle_id; + +#ifdef _ASSERT_NO_EARLY_EXPORT + bool _constructed:1; +#endif +} NMExportedObjectPrivate; + +G_DEFINE_ABSTRACT_TYPE (NMExportedObject, nm_exported_object, G_TYPE_DBUS_OBJECT_SKELETON); + +#define NM_EXPORTED_OBJECT_GET_PRIVATE(self) _NM_GET_PRIVATE_PTR (self, NMExportedObject, NM_IS_EXPORTED_OBJECT) + +/*****************************************************************************/ + +typedef struct { + GHashTable *properties; + GSList *skeleton_types; + GArray *methods; +} NMExportedObjectClassInfo; + +static NM_CACHED_QUARK_FCN ("NMExportedObjectClassInfo", nm_exported_object_class_info_quark) + +/*****************************************************************************/ + +#define _NMLOG_DOMAIN LOGD_CORE +#define _NMLOG(level, ...) __NMLOG_DEFAULT_WITH_ADDR (level, _NMLOG_DOMAIN, "exported-object", __VA_ARGS__) + +#define _NMLOG2_DOMAIN LOGD_DBUS_PROPS +#define _NMLOG2(level, ...) __NMLOG_DEFAULT_WITH_ADDR (level, _NMLOG2_DOMAIN, "properties-changed", __VA_ARGS__) + +/*****************************************************************************/ + +/* "AddConnectionUnsaved" -> "handle-add-connection-unsaved" */ +char * +nm_exported_object_skeletonify_method_name (const char *dbus_method_name) +{ + GString *out; + const char *p; + + out = g_string_new ("handle"); + for (p = dbus_method_name; *p; p++) { + if (g_ascii_isupper (*p) || p == dbus_method_name) { + g_string_append_c (out, '-'); + g_string_append_c (out, g_ascii_tolower (*p)); + } else + g_string_append_c (out, *p); + } + + return g_string_free (out, FALSE); +} + +/* "can-modify" -> "CanModify" */ +static char * +dbusify_name (const char *gobject_name) +{ + GString *out; + const char *p; + gboolean capitalize = TRUE; + + out = g_string_new (""); + for (p = gobject_name; *p; p++) { + if (capitalize) { + g_string_append_c (out, g_ascii_toupper (*p)); + capitalize = FALSE; + } else if (*p == '-') + capitalize = TRUE; + else + g_string_append_c (out, *p); + } + + return g_string_free (out, FALSE); +} + +/* "can_modify" -> "can-modify". Returns %NULL if @gobject_name contains no underscores */ +static char * +hyphenify_name (const char *gobject_name) +{ + char *hyphen_name, *p; + + if (!strchr (gobject_name, '_')) + return NULL; + + hyphen_name = g_strdup (gobject_name); + for (p = hyphen_name; *p; p++) { + if (*p == '_') + *p = '-'; + } + return hyphen_name; +} + +/* Called when an #NMExportedObject emits a signal that corresponds to a D-Bus + * signal, and re-emits that signal on the correct skeleton object as well. + */ +static gboolean +nm_exported_object_signal_hook (GSignalInvocationHint *ihint, + guint n_param_values, + const GValue *param_values, + gpointer data) +{ + NMExportedObject *self = g_value_get_object (¶m_values[0]); + NMExportedObjectPrivate *priv; + GSignalQuery *signal_info = data; + GDBusInterfaceSkeleton *interface = NULL; + GValue *dbus_param_values; + guint i; + + priv = NM_EXPORTED_OBJECT_GET_PRIVATE (self); + if (!priv->path) + return TRUE; + + for (i = 0; i < priv->num_interfaces; i++) { + InterfaceData *ifdata = &priv->interfaces[i]; + + if (g_type_is_a (G_OBJECT_TYPE (ifdata->interface), signal_info->itype)) { + interface = ifdata->interface; + break; + } + } + g_return_val_if_fail (interface != NULL, TRUE); + + dbus_param_values = g_newa (GValue, n_param_values); + memset (dbus_param_values, 0, sizeof (GValue) * n_param_values); + g_value_init (&dbus_param_values[0], G_OBJECT_TYPE (interface)); + g_value_set_object (&dbus_param_values[0], interface); + for (i = 1; i < n_param_values; i++) { + if (g_type_is_a (param_values[i].g_type, NM_TYPE_EXPORTED_OBJECT)) { + NMExportedObject *arg = g_value_get_object (¶m_values[i]); + + g_value_init (&dbus_param_values[i], G_TYPE_STRING); + if (arg && nm_exported_object_is_exported (arg)) + g_value_set_string (&dbus_param_values[i], nm_exported_object_get_path (arg)); + else + g_value_set_string (&dbus_param_values[i], "/"); + } else { + g_value_init (&dbus_param_values[i], param_values[i].g_type); + g_value_copy (¶m_values[i], &dbus_param_values[i]); + } + } + + g_signal_emitv (dbus_param_values, signal_info->signal_id, 0, NULL); + + for (i = 0; i < n_param_values; i++) + g_value_unset (&dbus_param_values[i]); + + return TRUE; +} + +/** + * nm_exported_object_class_add_interface: + * @object_class: an #NMExportedObjectClass + * @dbus_skeleton_type: the type of the #GDBusInterfaceSkeleton to add + * @...: method name / handler pairs, %NULL-terminated + * + * Adds @dbus_skeleton_type to the list of D-Bus interfaces implemented by + * @object_class. Instances of @object_class will automatically have a skeleton + * of that type created, which will be exported when you call + * nm_exported_object_export(). + * + * The skeleton's properties will be initialized from the #NMExportedObject's, + * and bidirectional bindings will be set up between them. When exported + * properties change, both the org.freedesktop.DBus.Properties.PropertiesChanged + * signal and the traditional NetworkManager PropertiesChanged signal will be + * emitted. + * + * When a signal is emitted on an #NMExportedObject that has the same name as a + * signal on @dbus_skeleton_type, it will automatically be emitted on the + * skeleton as well; #NMExportedObject arguments in the signal will be converted + * to D-Bus object paths in the skeleton signal. + * + * The arguments after @dbus_skeleton_type are pairs of D-Bus method names (in + * CamelCase), and the corresponding handlers for them (which must have the same + * prototype as the corresponding "handle-..." signal on @dbus_skeleton_type, + * except with no return value, and with the first argument being an object of + * @object_class's type, not of @dbus_skeleton_type). + * + * It is a programmer error if: + * - @object_class does not define a property of the same name and type as + * each of @dbus_skeleton_type's properties. + * - @object_class does not define a signal with the same name and arguments + * as each of @dbus_skeleton_type's signals. + * - the list of method names includes any names that do not correspond to + * "handle-" signals on @dbus_skeleton_type. + * - the list of method names does not include every method defined by + * @dbus_skeleton_type. + */ +void +nm_exported_object_class_add_interface (NMExportedObjectClass *object_class, + GType dbus_skeleton_type, + ...) +{ + NMExportedObjectClassInfo *classinfo; + NMExportedObjectDBusMethodImpl method; + va_list ap; + const char *method_name; + GCallback impl; + gs_free GType *interfaces = NULL; + guint n_interfaces; + guint n_signals, n_method_signals; + guint object_signal_id; + GSignalQuery query; + int i, s; + GObjectClass *dbus_object_class; + gs_free GParamSpec **dbus_properties = NULL; + GParamSpec *object_property; + guint n_dbus_properties; + + g_return_if_fail (NM_IS_EXPORTED_OBJECT_CLASS (object_class)); + g_return_if_fail (g_type_is_a (dbus_skeleton_type, G_TYPE_DBUS_INTERFACE_SKELETON)); + + classinfo = g_type_get_qdata (G_TYPE_FROM_CLASS (object_class), + nm_exported_object_class_info_quark ()); + if (!classinfo) { + classinfo = g_slice_new (NMExportedObjectClassInfo); + classinfo->skeleton_types = NULL; + classinfo->methods = g_array_new (FALSE, FALSE, sizeof (NMExportedObjectDBusMethodImpl)); + classinfo->properties = g_hash_table_new (nm_str_hash, g_str_equal); + g_type_set_qdata (G_TYPE_FROM_CLASS (object_class), + nm_exported_object_class_info_quark (), classinfo); + } + + classinfo->skeleton_types = g_slist_prepend (classinfo->skeleton_types, + GSIZE_TO_POINTER (dbus_skeleton_type)); + + /* Ensure @dbus_skeleton_type's class_init has run, so its signals/properties + * will be defined. + */ + dbus_object_class = g_type_class_ref (dbus_skeleton_type); + + /* Add method implementations from the varargs */ + va_start (ap, dbus_skeleton_type); + while ((method_name = va_arg (ap, const char *)) && (impl = va_arg (ap, GCallback))) { + method.dbus_skeleton_type = dbus_skeleton_type; + method.method_name = nm_exported_object_skeletonify_method_name (method_name); + g_assert (g_signal_lookup (method.method_name, dbus_skeleton_type) != 0); + method.impl = impl; + + g_array_append_val (classinfo->methods, method); + } + va_end (ap); + + /* Properties */ + dbus_properties = g_object_class_list_properties (dbus_object_class, &n_dbus_properties); + for (i = 0; i < n_dbus_properties; i++) { + char *hyphen_name; + + if (g_str_has_prefix (dbus_properties[i]->name, "g-")) + continue; + + object_property = g_object_class_find_property (G_OBJECT_CLASS (object_class), + dbus_properties[i]->name); + g_assert (object_property != NULL); + g_assert (object_property->value_type == dbus_properties[i]->value_type); + + g_assert (!g_hash_table_contains (classinfo->properties, dbus_properties[i]->name)); + g_hash_table_insert (classinfo->properties, + g_strdup (dbus_properties[i]->name), + dbusify_name (dbus_properties[i]->name)); + hyphen_name = hyphenify_name (dbus_properties[i]->name); + if (hyphen_name) { + g_assert (!g_hash_table_contains (classinfo->properties, hyphen_name)); + g_hash_table_insert (classinfo->properties, + hyphen_name, + dbusify_name (dbus_properties[i]->name)); + } + } + + /* Signals. Unlike g_object_class_list_properties(), g_signal_list_ids() is + * "shallow", so we need to query each implemented gdbus-generated interface + * separately. + */ + interfaces = g_type_interfaces (dbus_skeleton_type, &n_interfaces); + n_method_signals = 0; + for (i = 0; i < n_interfaces; i++) { + gs_free guint *dbus_signals = NULL; + + dbus_signals = g_signal_list_ids (interfaces[i], &n_signals); + for (s = 0; s < n_signals; s++) { + g_signal_query (dbus_signals[s], &query); + + /* PropertiesChanged is handled specially */ + if (!strcmp (query.signal_name, "properties-changed")) + continue; + + if (g_str_has_prefix (query.signal_name, "handle-")) { + n_method_signals++; + continue; + } + + object_signal_id = g_signal_lookup (query.signal_name, G_TYPE_FROM_CLASS (object_class)); + g_assert (object_signal_id != 0); + + g_signal_add_emission_hook (object_signal_id, 0, + nm_exported_object_signal_hook, + g_memdup (&query, sizeof (query)), + g_free); + } + } + + g_type_class_unref (dbus_object_class); +} + +/*****************************************************************************/ + +/* "meta-marshaller" that receives the skeleton "handle-foo" signal, replaces + * the skeleton object with an #NMExportedObject in the parameters, drops the + * user_data parameter, and adds a "TRUE" return value (indicating to gdbus that + * the signal was handled). + */ +static void +nm_exported_object_meta_marshal (GClosure *closure, GValue *return_value, + guint n_param_values, const GValue *param_values, + gpointer invocation_hint, gpointer marshal_data) +{ + GValue *local_param_values; + + local_param_values = g_new0 (GValue, n_param_values); + g_value_init (&local_param_values[0], G_TYPE_POINTER); + g_value_set_pointer (&local_param_values[0], closure->data); + memcpy (local_param_values + 1, param_values + 1, (n_param_values - 1) * sizeof (GValue)); + + g_cclosure_marshal_generic (closure, NULL, + n_param_values, local_param_values, + invocation_hint, + ((GCClosure *)closure)->callback); + g_value_set_boolean (return_value, TRUE); + + g_value_unset (&local_param_values[0]); + g_free (local_param_values); +} + +static NM_CACHED_QUARK_FCN ("skeleton-data", _skeleton_data_quark) + +typedef struct { + GBinding **prop_bindings; + gulong *method_signals; +} SkeletonData; + +GDBusInterfaceSkeleton * +nm_exported_object_skeleton_create (GType dbus_skeleton_type, + GObjectClass *object_class, + const NMExportedObjectDBusMethodImpl *methods, + guint methods_len, + GObject *target) +{ + GDBusInterfaceSkeleton *interface; + gs_free GParamSpec **properties = NULL; + SkeletonData *skeleton_data; + guint n_properties; + guint i, j; + + interface = G_DBUS_INTERFACE_SKELETON (g_object_new (dbus_skeleton_type, NULL)); + + skeleton_data = g_slice_new (SkeletonData); + + /* Bind properties */ + properties = g_object_class_list_properties (G_OBJECT_GET_CLASS (interface), &n_properties); + skeleton_data->prop_bindings = g_new (GBinding *, n_properties + 1); + for (i = 0, j = 0; i < n_properties; i++) { + GParamSpec *nm_property; + GBindingFlags flags; + GBinding *prop_binding; + + nm_property = g_object_class_find_property (object_class, properties[i]->name); + if (!nm_property) + continue; + + flags = G_BINDING_SYNC_CREATE; + if ( (nm_property->flags & G_PARAM_WRITABLE) + && !(nm_property->flags & G_PARAM_CONSTRUCT_ONLY)) + flags |= G_BINDING_BIDIRECTIONAL; + prop_binding = g_object_bind_property (target, properties[i]->name, + interface, properties[i]->name, + flags); + if (prop_binding) + skeleton_data->prop_bindings[j++] = prop_binding; + } + skeleton_data->prop_bindings[j++] = NULL; + + /* Bind methods */ + skeleton_data->method_signals = g_new (gulong, methods_len + 1); + for (i = 0, j = 0; i < methods_len; i++) { + const NMExportedObjectDBusMethodImpl *method = &methods[i]; + GClosure *closure; + gulong method_signal; + + /* ignore methods that are for a different skeleton-type. */ + if ( method->dbus_skeleton_type + && method->dbus_skeleton_type != dbus_skeleton_type) + continue; + + closure = g_cclosure_new_swap (method->impl, target, NULL); + g_closure_set_meta_marshal (closure, NULL, nm_exported_object_meta_marshal); + method_signal = g_signal_connect_closure (interface, method->method_name, closure, FALSE); + + if (method_signal != 0) + skeleton_data->method_signals[j++] = method_signal; + } + skeleton_data->method_signals[j++] = 0; + + g_object_set_qdata ((GObject *) interface, _skeleton_data_quark (), skeleton_data); + + return interface; +} + +static void +nm_exported_object_create_skeletons (NMExportedObject *self, + GType object_type) +{ + NMExportedObjectPrivate *priv; + GObjectClass *object_class; + NMExportedObjectClassInfo *classinfo; + GSList *iter; + const NMExportedObjectDBusMethodImpl *methods; + guint i, methods_len; + guint num_interfaces; + InterfaceData *interfaces; + + classinfo = g_type_get_qdata (object_type, nm_exported_object_class_info_quark ()); + if (!classinfo) + return; + + object_class = g_type_class_peek (object_type); + priv = NM_EXPORTED_OBJECT_GET_PRIVATE (self); + + methods = classinfo->methods->len ? &g_array_index (classinfo->methods, NMExportedObjectDBusMethodImpl, 0) : NULL; + methods_len = classinfo->methods->len; + + num_interfaces = g_slist_length (classinfo->skeleton_types); + g_return_if_fail (num_interfaces > 0); + + interfaces = g_slice_alloc (sizeof (InterfaceData) * (num_interfaces + priv->num_interfaces)); + + for (i = num_interfaces, iter = classinfo->skeleton_types; iter; iter = iter->next) { + InterfaceData *ifdata = &interfaces[--i]; + + ifdata->interface = nm_exported_object_skeleton_create (GPOINTER_TO_SIZE (iter->data), + object_class, + methods, + methods_len, + (GObject *) self); + g_dbus_object_skeleton_add_interface ((GDBusObjectSkeleton *) self, ifdata->interface); + + ifdata->property_changed_signal_id = g_signal_lookup ("properties-changed", G_OBJECT_TYPE (ifdata->interface)); + + ifdata->pending_notifies = g_hash_table_new_full (g_direct_hash, + g_direct_equal, + NULL, + (GDestroyNotify) g_variant_unref); + } + nm_assert (i == 0); + + /* The list of interfaces priv->interfaces is to be sorted from parent-class to derived-class. + * On the other hand, if one class defines multiple interfaces, the interfaces are sorted in + * the order of calls to nm_exported_object_class_add_interface(). */ + if (priv->num_interfaces > 0) { + memcpy (&interfaces[num_interfaces], priv->interfaces, sizeof (InterfaceData) * priv->num_interfaces); + g_slice_free1 (sizeof (InterfaceData) * priv->num_interfaces, priv->interfaces); + } + + priv->num_interfaces = num_interfaces + priv->num_interfaces; + priv->interfaces = interfaces; +} + +void +nm_exported_object_skeleton_release (GDBusInterfaceSkeleton *interface) +{ + SkeletonData *skeleton_data; + guint j; + + g_return_if_fail (G_IS_DBUS_INTERFACE_SKELETON (interface)); + + skeleton_data = g_object_steal_qdata ((GObject *) interface, _skeleton_data_quark ()); + + for (j = 0; skeleton_data->prop_bindings[j]; j++) + g_object_unref (skeleton_data->prop_bindings[j]); + for (j = 0; skeleton_data->method_signals[j]; j++) + g_signal_handler_disconnect (interface, skeleton_data->method_signals[j]); + + g_free (skeleton_data->prop_bindings); + g_free (skeleton_data->method_signals); + g_slice_free (SkeletonData, skeleton_data); + + g_object_unref (interface); +} + +static void +nm_exported_object_destroy_skeletons (NMExportedObject *self) +{ + NMExportedObjectPrivate *priv = NM_EXPORTED_OBJECT_GET_PRIVATE (self); + guint n; + + g_return_if_fail (priv->num_interfaces > 0); + nm_assert (priv->interfaces); + + n = priv->num_interfaces; + + while (priv->num_interfaces > 0) { + InterfaceData *ifdata = &priv->interfaces[--priv->num_interfaces]; + + g_dbus_object_skeleton_remove_interface ((GDBusObjectSkeleton *) self, ifdata->interface); + nm_exported_object_skeleton_release (ifdata->interface); + g_hash_table_destroy (ifdata->pending_notifies); + } + + g_slice_free1 (sizeof (InterfaceData) * n, priv->interfaces); + priv->interfaces = NULL; +} + +static char * +_create_export_path (NMExportedObjectClass *klass) +{ + const char *class_export_path, *p; + static GHashTable *prefix_counters; + guint64 *counter; + + class_export_path = klass->export_path; + + nm_assert (class_export_path); + + p = strchr (class_export_path, '%'); + if (p) { + if (G_UNLIKELY (!prefix_counters)) + prefix_counters = g_hash_table_new (nm_str_hash, g_str_equal); + + nm_assert (p[1] == 'l'); + nm_assert (p[2] == 'l'); + nm_assert (p[3] == 'u'); + nm_assert (p[4] == '\0'); + + counter = g_hash_table_lookup (prefix_counters, class_export_path); + if (!counter) { + counter = g_slice_new0 (guint64); + g_hash_table_insert (prefix_counters, (char *) class_export_path, counter); + } + + NM_PRAGMA_WARNING_DISABLE("-Wformat-nonliteral") + return g_strdup_printf (class_export_path, (unsigned long long) (++(*counter))); + NM_PRAGMA_WARNING_REENABLE + } + + return g_strdup (class_export_path); +} + +/** + * nm_exported_object_get_path: + * @self: an #NMExportedObject + * + * Gets @self's D-Bus path. + * + * Returns: @self's D-Bus path, or %NULL if @self is not exported. + */ +const char * +nm_exported_object_get_path (NMExportedObject *self) +{ + g_return_val_if_fail (NM_IS_EXPORTED_OBJECT (self), NULL); + + return NM_EXPORTED_OBJECT_GET_PRIVATE (self)->path; +} + +/** + * nm_exported_object_is_exported: + * @self: an #NMExportedObject + * + * Checks if @self is exported + * + * Returns: %TRUE if @self is exported + */ +gboolean +nm_exported_object_is_exported (NMExportedObject *self) +{ + g_return_val_if_fail (NM_IS_EXPORTED_OBJECT (self), FALSE); + + return NM_EXPORTED_OBJECT_GET_PRIVATE (self)->path != NULL; +} + +/** + * nm_exported_object_export: + * @self: an #NMExportedObject + * + * Exports @self on all active and future D-Bus connections. + * + * The path to export @self on is taken from its #NMObjectClass's %export_path + * member. If the %export_path contains "%u", then it will be replaced with a + * monotonically increasing integer ID (with each distinct %export_path having + * its own counter). Otherwise, %export_path will be used literally (implying + * that @self must be a singleton). + * + * Returns: the path @self was exported under + */ +const char * +nm_exported_object_export (NMExportedObject *self) +{ + NMExportedObjectPrivate *priv; + GType type; + + g_return_val_if_fail (NM_IS_EXPORTED_OBJECT (self), NULL); + priv = NM_EXPORTED_OBJECT_GET_PRIVATE (self); + + g_return_val_if_fail (!priv->path, priv->path); + g_return_val_if_fail (!priv->bus_mgr, priv->path); + +#ifdef _ASSERT_NO_EARLY_EXPORT + nm_assert (priv->_constructed); +#endif + + priv->bus_mgr = nm_bus_manager_get (); + if (!priv->bus_mgr) + g_return_val_if_reached (NULL); + g_object_add_weak_pointer ((GObject *) priv->bus_mgr, (gpointer *) &priv->bus_mgr); + + type = G_OBJECT_TYPE (self); + while (type != NM_TYPE_EXPORTED_OBJECT) { + nm_exported_object_create_skeletons (self, type); + type = g_type_parent (type); + } + + priv->path = _create_export_path (NM_EXPORTED_OBJECT_GET_CLASS (self)); + + _LOGT ("export: \"%s\"", priv->path); + g_dbus_object_skeleton_set_object_path (G_DBUS_OBJECT_SKELETON (self), priv->path); + + /* Important: priv->path and priv->interfaces must not change while + * the object is registered. */ + + nm_bus_manager_register_object (priv->bus_mgr, (GDBusObjectSkeleton *) self); + + _notify (self, PROP_PATH); + + return priv->path; +} + +/** + * nm_exported_object_unexport: + * @self: an #NMExportedObject + * + * Unexports @self on all active D-Bus connections (and prevents it from being + * auto-exported on future connections). + */ +void +nm_exported_object_unexport (NMExportedObject *self) +{ + NMExportedObjectPrivate *priv; + + g_return_if_fail (NM_IS_EXPORTED_OBJECT (self)); + priv = NM_EXPORTED_OBJECT_GET_PRIVATE (self); + + g_return_if_fail (priv->path); + + /* Important: priv->path and priv->interfaces must not change while + * the object is registered. */ + + _LOGT ("unexport: \"%s\"", priv->path); + + if (priv->bus_mgr) { + nm_bus_manager_unregister_object (priv->bus_mgr, (GDBusObjectSkeleton *) self); + g_object_remove_weak_pointer ((GObject *) priv->bus_mgr, (gpointer *) &priv->bus_mgr); + priv->bus_mgr = NULL; + } + + nm_exported_object_destroy_skeletons (self); + + g_dbus_object_skeleton_set_object_path ((GDBusObjectSkeleton *) self, NULL); + + g_clear_pointer (&priv->path, g_free); + + nm_clear_g_source (&priv->notify_idle_id); + + _notify (self, PROP_PATH); +} + +/*****************************************************************************/ + +void +_nm_exported_object_clear_and_unexport (NMExportedObject **location) +{ + NMExportedObject *self; + NMExportedObjectPrivate *priv; + + if (!location || !*location) + return; + + self = *location; + *location = NULL; + + g_return_if_fail (NM_IS_EXPORTED_OBJECT (self)); + + priv = NM_EXPORTED_OBJECT_GET_PRIVATE (self); + + if (priv->path) + nm_exported_object_unexport (self); + + g_object_unref (self); +} + +/*****************************************************************************/ + +GDBusInterfaceSkeleton * +nm_exported_object_get_interface_by_type (NMExportedObject *self, GType interface_type) +{ + NMExportedObjectPrivate *priv; + guint i; + + g_return_val_if_fail (NM_IS_EXPORTED_OBJECT (self), NULL); + + priv = NM_EXPORTED_OBJECT_GET_PRIVATE (self); + + g_return_val_if_fail (priv->path, NULL); + g_return_val_if_fail (priv->num_interfaces > 0, NULL); + + nm_assert (priv->interfaces); + + for (i = 0; i < priv->num_interfaces; i++) { + InterfaceData *ifdata = &priv->interfaces[i]; + + if (G_TYPE_CHECK_INSTANCE_TYPE (ifdata->interface, interface_type)) + return ifdata->interface; + } + return NULL; +} + +/*****************************************************************************/ + +void +nm_exported_object_class_set_quitting (void) +{ + quitting = TRUE; +} + +/*****************************************************************************/ + +typedef struct { + const char *property_name; + GVariant *variant; +} PendingNotifiesItem; + +static int +_sort_pending_notifies (gconstpointer a, gconstpointer b, gpointer user_data) +{ + return strcmp (((const PendingNotifiesItem *) a)->property_name, + ((const PendingNotifiesItem *) b)->property_name); +} + +static gboolean +idle_emit_properties_changed (gpointer self) +{ + NMExportedObjectPrivate *priv = NM_EXPORTED_OBJECT_GET_PRIVATE (NM_EXPORTED_OBJECT (self)); + guint k; + + priv->notify_idle_id = 0; + + for (k = 0; k < priv->num_interfaces; k++) { + InterfaceData *ifdata = &priv->interfaces[k]; + gs_unref_variant GVariant *variant = NULL; + PendingNotifiesItem *values; + GVariantBuilder notifies; + GHashTableIter hash_iter; + guint i, n; + + n = g_hash_table_size (ifdata->pending_notifies); + if (n == 0) + continue; + + nm_assert (ifdata->property_changed_signal_id); + + /* We use here alloca in a loop, something that is usually avoided. + * But the number of interfaces "priv->num_interfaces" is small (determined by + * the depth of the type inheritance) and the number of possible pending_notifies + * "n" is small (determined by the number of GObject properties). */ + values = g_alloca (sizeof (values[0]) * n); + + i = 0; + g_hash_table_iter_init (&hash_iter, ifdata->pending_notifies); + while (g_hash_table_iter_next (&hash_iter, (gpointer) &values[i].property_name, (gpointer) &values[i].variant)) + i++; + nm_assert (i == n); + + g_qsort_with_data (values, n, sizeof (values[0]), _sort_pending_notifies, NULL); + + g_variant_builder_init (¬ifies, G_VARIANT_TYPE_VARDICT); + for (i = 0; i < n; i++) + g_variant_builder_add (¬ifies, "{sv}", values[i].property_name, values[i].variant); + variant = g_variant_ref_sink (g_variant_builder_end (¬ifies)); + + + if (_LOG2D_ENABLED ()) { + gs_free char *notification = g_variant_print (variant, TRUE); + + _LOG2D ("type %s, iface %s: %s", + G_OBJECT_TYPE_NAME (self), G_OBJECT_TYPE_NAME (ifdata->interface), + notification); + } + + g_signal_emit (ifdata->interface, ifdata->property_changed_signal_id, 0, variant); + + g_hash_table_remove_all (ifdata->pending_notifies); + } + + return G_SOURCE_REMOVE; +} + +static void +nm_exported_object_notify (GObject *object, GParamSpec *pspec) +{ + NMExportedObject *self = (NMExportedObject *) object; + NMExportedObjectPrivate *priv = NM_EXPORTED_OBJECT_GET_PRIVATE (self); + NMExportedObjectClassInfo *classinfo; + GType type; + const char *dbus_property_name = NULL; + GValue value = G_VALUE_INIT; + GVariant *value_variant; + InterfaceData *ifdata = NULL; + const GVariantType *vtype; + guint i, j; + + /* Hook to emit deprecated "PropertiesChanged" signal on NetworkManager interfaces. + * This is to preserve deprecated D-Bus API, nowadays we use instead + * the "PropertiesChanged" signal of "org.freedesktop.DBus.Properties". */ + + if (priv->num_interfaces == 0) + return; + + for (type = G_OBJECT_TYPE (self); type; type = g_type_parent (type)) { + classinfo = g_type_get_qdata (type, nm_exported_object_class_info_quark ()); + if (!classinfo) + continue; + + dbus_property_name = g_hash_table_lookup (classinfo->properties, pspec->name); + if (dbus_property_name) + break; + } + if (!dbus_property_name) { + _LOG2T ("ignoring notification for prop %s on type %s", + pspec->name, G_OBJECT_TYPE_NAME (self)); + return; + } + + for (i = 0; i < priv->num_interfaces; i++) { + GDBusInterfaceInfo *iinfo; + + ifdata = &priv->interfaces[i]; + iinfo = g_dbus_interface_skeleton_get_info (ifdata->interface); + for (j = 0; iinfo->properties[j]; j++) { + if (nm_streq (iinfo->properties[j]->name, dbus_property_name)) { + vtype = G_VARIANT_TYPE (iinfo->properties[j]->signature); + goto vtype_found; + } + } + } + g_return_if_reached (); + +vtype_found: + g_value_init (&value, pspec->value_type); + g_object_get_property ((GObject *) self, pspec->name, &value); + value_variant = g_dbus_gvalue_to_gvariant (&value, vtype); + g_value_unset (&value); + + if ( ( NM_IS_DEVICE (self) + && !NMDBUS_IS_DEVICE_STATISTICS_SKELETON (ifdata->interface)) + || NM_IS_ACTIVE_CONNECTION (self)) { + /* This PropertiesChanged signal is nodaways deprecated in favor + * of "org.freedesktop.DBus.Properties"'s PropertiesChanged signal. + * This function solely exists to raise the NM version of PropertiesChanged. + * + * With types exported on D-Bus that are implemented as derived + * types in glib (NMDevice and NMActiveConnection), multiple types + * in the inheritance tree define a "PropertiesChanged" signal. + * + * In 1.0.0 and earlier, the signal was emitted once for every interface + * that had a "PropertiesChanged" signal. For example: + * - NMDeviceEthernet.HwAddress was emitted on "fdo.NM.Device.Ethernet" + * and "fdo.NM.Device.Veth" (if the device was of type NMDeviceVeth). + * - NMVpnConnection.VpnState was emitted on "fdo.NM.Connecion.Active" + * and "fdo.NM.VPN.Connection". + * + * NMDevice is special in that it didn't have a "PropertiesChanged" signal. + * Thus, a change to "NMDevice.StateReason" would be emitted on "fdo.NM.Device.Ethernet" + * and also on "fdo.NM.Device.Veth" (in case of a device of type NMDeviceVeth). + * + * The releases of 1.2.0 and 1.4.0 failed to realize above and broke this behavior. + * This special handling here is to bring back the 1.0.0 behavior. + * + * The Device.Statistics signal is special, because it was only added with 1.4.0 + * and didn't have above behavior. So let's save the overhead of emitting multiple + * deprecated signals for wrong interfaces. */ + for (i = 0, j = 0; i < priv->num_interfaces; i++) { + ifdata = &priv->interfaces[i]; + if ( ifdata->property_changed_signal_id + && !NMDBUS_IS_DEVICE_STATISTICS_SKELETON (ifdata->interface)) { + j++; + g_hash_table_insert (ifdata->pending_notifies, + (gpointer) dbus_property_name, + g_variant_ref (value_variant)); + } + } + nm_assert (j > 0); + g_variant_unref (value_variant); + } else if (ifdata->property_changed_signal_id) { + /* @dbus_property_name is inside classinfo and never freed, thus we don't clone it. + * Also, we do a pointer, not string comparison. */ + g_hash_table_insert (ifdata->pending_notifies, + (gpointer) dbus_property_name, + value_variant); + } else + g_variant_unref (value_variant); + + if (!priv->notify_idle_id) + priv->notify_idle_id = g_idle_add (idle_emit_properties_changed, self); +} + +/*****************************************************************************/ + +static void +get_property (GObject *object, guint prop_id, + GValue *value, GParamSpec *pspec) +{ + NMExportedObject *self = NM_EXPORTED_OBJECT (object); + NMExportedObjectPrivate *priv = NM_EXPORTED_OBJECT_GET_PRIVATE (self); + + switch (prop_id) { + case PROP_PATH: + g_value_set_string (value, priv->path); + break; + default: + G_OBJECT_WARN_INVALID_PROPERTY_ID (object, prop_id, pspec); + break; + } +} + +static void +nm_exported_object_init (NMExportedObject *self) +{ + NMExportedObjectPrivate *priv; + + priv = G_TYPE_INSTANCE_GET_PRIVATE (self, NM_TYPE_EXPORTED_OBJECT, NMExportedObjectPrivate); + self->_priv = priv; +} + +static void +constructed (GObject *object) +{ + NMExportedObjectClass *klass; + + G_OBJECT_CLASS (nm_exported_object_parent_class)->constructed (object); + +#ifdef _ASSERT_NO_EARLY_EXPORT + NM_EXPORTED_OBJECT_GET_PRIVATE (NM_EXPORTED_OBJECT (object))->_constructed = TRUE; +#endif + + klass = NM_EXPORTED_OBJECT_GET_CLASS (object); + + if (klass->export_on_construction) + nm_exported_object_export ((NMExportedObject *) object); +} + +static void +dispose (GObject *object) +{ + NMExportedObject *self = NM_EXPORTED_OBJECT (object); + NMExportedObjectPrivate *priv = NM_EXPORTED_OBJECT_GET_PRIVATE (self); + + /* Objects should have already been unexported by their owner, unless + * we are quitting, where many objects stick around until exit. + */ + if (!quitting) { + if (priv->path) { + g_warn_if_reached (); + nm_exported_object_unexport (self); + } + } else if (nm_clear_g_free (&priv->path)) + _notify (self, PROP_PATH); + + nm_clear_g_source (&priv->notify_idle_id); + + G_OBJECT_CLASS (nm_exported_object_parent_class)->dispose (object); +} + +static void +nm_exported_object_class_init (NMExportedObjectClass *klass) +{ + GObjectClass *object_class = G_OBJECT_CLASS (klass); + + g_type_class_add_private (object_class, sizeof (NMExportedObjectPrivate)); + + object_class->constructed = constructed; + object_class->notify = nm_exported_object_notify; + object_class->dispose = dispose; + object_class->get_property = get_property; + + obj_properties[PROP_PATH] = + g_param_spec_string (NM_EXPORTED_OBJECT_PATH, "", "", + NULL, + G_PARAM_READABLE | + G_PARAM_STATIC_STRINGS); + + g_object_class_install_properties (object_class, _PROPERTY_ENUMS_LAST, obj_properties); +} diff --git a/src/nm-exported-object.h b/src/nm-exported-object.h new file mode 100644 index 00000000..47559a20 --- /dev/null +++ b/src/nm-exported-object.h @@ -0,0 +1,85 @@ +/* -*- Mode: C; tab-width: 4; indent-tabs-mode: t; c-basic-offset: 4 -*- */ +/* NetworkManager -- Network link manager + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation; either version 2 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License along + * with this program; if not, write to the Free Software Foundation, Inc., + * 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA. + * + * Copyright 2014 Red Hat, Inc. + */ + +#ifndef NM_EXPORTED_OBJECT_H +#define NM_EXPORTED_OBJECT_H + +/*****************************************************************************/ + +#define NM_EXPORT_PATH_NUMBERED(basepath) ""basepath"/%llu" + +char *nm_exported_object_skeletonify_method_name (const char *dbus_method_name); + +typedef struct { + GType dbus_skeleton_type; + char *method_name; + GCallback impl; +} NMExportedObjectDBusMethodImpl; + +GDBusInterfaceSkeleton *nm_exported_object_skeleton_create (GType dbus_skeleton_type, + GObjectClass *object_class, + const NMExportedObjectDBusMethodImpl *methods, + guint methods_len, + GObject *target); +void nm_exported_object_skeleton_release (GDBusInterfaceSkeleton *interface); + +/*****************************************************************************/ + +#define NM_TYPE_EXPORTED_OBJECT (nm_exported_object_get_type ()) +#define NM_EXPORTED_OBJECT(obj) (G_TYPE_CHECK_INSTANCE_CAST ((obj), NM_TYPE_EXPORTED_OBJECT, NMExportedObject)) +#define NM_EXPORTED_OBJECT_CLASS(klass) (G_TYPE_CHECK_CLASS_CAST ((klass), NM_TYPE_EXPORTED_OBJECT, NMExportedObjectClass)) +#define NM_IS_EXPORTED_OBJECT(obj) (G_TYPE_CHECK_INSTANCE_TYPE ((obj), NM_TYPE_EXPORTED_OBJECT)) +#define NM_IS_EXPORTED_OBJECT_CLASS(klass) (G_TYPE_CHECK_CLASS_TYPE ((klass), NM_TYPE_EXPORTED_OBJECT)) +#define NM_EXPORTED_OBJECT_GET_CLASS(obj) (G_TYPE_INSTANCE_GET_CLASS ((obj), NM_TYPE_EXPORTED_OBJECT, NMExportedObjectClass)) + +#define NM_EXPORTED_OBJECT_PATH "path" + +struct _NMExportedObjectPrivate; + +struct _NMExportedObject { + GDBusObjectSkeleton parent; + struct _NMExportedObjectPrivate *_priv; +}; + +typedef struct { + GDBusObjectSkeletonClass parent; + + const char *export_path; + char export_on_construction; +} NMExportedObjectClass; + +GType nm_exported_object_get_type (void); + +void nm_exported_object_class_set_quitting (void); + +void nm_exported_object_class_add_interface (NMExportedObjectClass *object_class, + GType dbus_skeleton_type, + ...) G_GNUC_NULL_TERMINATED; + +const char *nm_exported_object_export (NMExportedObject *self); +const char *nm_exported_object_get_path (NMExportedObject *self); +gboolean nm_exported_object_is_exported (NMExportedObject *self); +void nm_exported_object_unexport (NMExportedObject *self); +GDBusInterfaceSkeleton *nm_exported_object_get_interface_by_type (NMExportedObject *self, GType interface_type); + +void _nm_exported_object_clear_and_unexport (NMExportedObject **location); +#define nm_exported_object_clear_and_unexport(location) _nm_exported_object_clear_and_unexport ((NMExportedObject **) (location)) + +#endif /* NM_EXPORTED_OBJECT_H */ diff --git a/src/nm-firewall-manager.c b/src/nm-firewall-manager.c index 134a46f7..216d5fc8 100644 --- a/src/nm-firewall-manager.c +++ b/src/nm-firewall-manager.c @@ -25,7 +25,7 @@ #include <string.h> #include "NetworkManagerUtils.h" -#include "c-list/src/c-list.h" +#include "nm-utils/c-list.h" /*****************************************************************************/ diff --git a/src/nm-iface-helper.c b/src/nm-iface-helper.c index 601c72ac..1493ef19 100644 --- a/src/nm-iface-helper.c +++ b/src/nm-iface-helper.c @@ -33,8 +33,6 @@ #include <signal.h> #include <linux/rtnetlink.h> -#include "nm-utils/nm-c-list.h" - #include "main-utils.h" #include "NetworkManagerUtils.h" #include "platform/nm-linux-platform.h" @@ -57,9 +55,6 @@ static struct { GMainLoop *main_loop; int ifindex; - - guint dad_failed_id; - CList dad_failed_lst_head; } gl/*obal*/ = { .ifindex = -1, }; @@ -125,7 +120,7 @@ dhcp4_state_changed (NMDhcpClient *client, g_assert (nm_ip4_config_get_ifindex (ip4_config) == gl.ifindex); existing = nm_ip4_config_capture (nm_platform_get_multi_idx (NM_PLATFORM_GET), - NM_PLATFORM_GET, gl.ifindex); + NM_PLATFORM_GET, gl.ifindex, FALSE); if (last_config) nm_ip4_config_subtract (existing, last_config, 0); @@ -171,7 +166,7 @@ ndisc_config_changed (NMNDisc *ndisc, const NMNDiscData *rdata, guint changed_in NMIP6Config *existing; existing = nm_ip6_config_capture (nm_platform_get_multi_idx (NM_PLATFORM_GET), - NM_PLATFORM_GET, gl.ifindex, global_opt.tempaddr); + NM_PLATFORM_GET, gl.ifindex, FALSE, global_opt.tempaddr); if (ndisc_config) nm_ip6_config_subtract (existing, ndisc_config, 0); else { @@ -321,58 +316,19 @@ do_early_setup (int *argc, char **argv[]) return TRUE; } -typedef struct { - NMPlatform *platform; - NMNDisc *ndisc; -} DadFailedHandleData; - -static gboolean -dad_failed_handle_idle (gpointer user_data) -{ - DadFailedHandleData *data = user_data; - NMCListElem *elem; - - while ((elem = c_list_first_entry (&gl.dad_failed_lst_head, NMCListElem, lst))) { - nm_auto_nmpobj const NMPObject *obj = elem->data; - - nm_c_list_elem_free (elem); - - if (nm_ndisc_dad_addr_is_fail_candidate (data->platform, obj)) { - nm_ndisc_dad_failed (data->ndisc, - &NMP_OBJECT_CAST_IP6_ADDRESS (obj)->address); - } - } - - gl.dad_failed_id = 0; - return G_SOURCE_REMOVE; -} - static void ip6_address_changed (NMPlatform *platform, int obj_type_i, int iface, - const NMPlatformIP6Address *addr, + NMPlatformIP6Address *addr, int change_type_i, NMNDisc *ndisc) { const NMPlatformSignalChangeType change_type = change_type_i; - DadFailedHandleData *data; - - if (!nm_ndisc_dad_addr_is_fail_candidate_event (change_type, addr)) - return; - - c_list_link_tail (&gl.dad_failed_lst_head, - &nm_c_list_elem_new_stale ((gpointer) nmp_object_ref (NMP_OBJECT_UP_CAST (addr)))->lst); - if (gl.dad_failed_id) - return; - - data = g_slice_new (DadFailedHandleData); - data->platform = platform; - data->ndisc = ndisc; - gl.dad_failed_id = g_idle_add_full (G_PRIORITY_DEFAULT_IDLE, - dad_failed_handle_idle, - data, - nm_g_slice_free_fcn (DadFailedHandleData)); + + if ( (change_type == NM_PLATFORM_SIGNAL_CHANGED && addr->n_ifa_flags & IFA_F_DADFAILED) + || (change_type == NM_PLATFORM_SIGNAL_REMOVED && addr->n_ifa_flags & IFA_F_TENTATIVE)) + nm_ndisc_dad_failed (ndisc, &addr->address); } int @@ -384,13 +340,14 @@ main (int argc, char *argv[]) gs_free char *pidfile = NULL; gs_unref_object NMDhcpClient *dhcp4_client = NULL; gs_unref_object NMNDisc *ndisc = NULL; - gs_unref_bytes GBytes *hwaddr = NULL; - gs_unref_bytes GBytes *client_id = NULL; + GByteArray *hwaddr = NULL; + size_t hwaddr_len = 0; + gconstpointer tmp; gs_free NMUtilsIPv6IfaceId *iid = NULL; guint sd_id; char sysctl_path_buf[NM_UTILS_SYSCTL_IP_CONF_PATH_BUFSIZE]; - c_list_init (&gl.dad_failed_lst_head); + nm_g_type_init (); setpgid (getpid (), getpid ()); @@ -474,7 +431,11 @@ main (int argc, char *argv[]) /* Set up platform interaction layer */ nm_linux_platform_setup (); - hwaddr = nm_platform_link_get_address_as_bytes (NM_PLATFORM_GET, gl.ifindex); + tmp = nm_platform_link_get_address (NM_PLATFORM_GET, gl.ifindex, &hwaddr_len); + if (tmp) { + hwaddr = g_byte_array_sized_new (hwaddr_len); + g_byte_array_append (hwaddr, tmp, hwaddr_len); + } if (global_opt.iid_str) { GBytes *bytes; @@ -488,16 +449,6 @@ main (int argc, char *argv[]) iid = g_bytes_unref_to_data (bytes, &ignored); } - if (global_opt.dhcp4_clientid) { - /* this string is just a plain hex-string. Unlike ipv4.dhcp-client-id, which - * is parsed via nm_dhcp_utils_client_id_string_to_bytes(). */ - client_id = nm_utils_hexstr2bin (global_opt.dhcp4_clientid); - if (!client_id || g_bytes_get_size (client_id) < 2) { - fprintf (stderr, _("(%s): Invalid DHCP client-id %s\n"), global_opt.ifname, global_opt.dhcp4_clientid); - return 1; - } - } - if (global_opt.dhcp4_address) { nm_platform_sysctl_set (NM_PLATFORM_GET, NMP_SYSCTL_PATHID_ABSOLUTE (nm_utils_sysctl_ip_conf_path (AF_INET, sysctl_path_buf, global_opt.ifname, "promote_secondaries")), "1"); @@ -512,7 +463,7 @@ main (int argc, char *argv[]) !!global_opt.dhcp4_hostname, global_opt.dhcp4_hostname, global_opt.dhcp4_fqdn, - client_id, + global_opt.dhcp4_clientid, NM_DHCP_TIMEOUT_DEFAULT, NULL, global_opt.dhcp4_address); @@ -572,8 +523,7 @@ main (int argc, char *argv[]) g_main_loop_run (gl.main_loop); - nm_clear_g_source (&gl.dad_failed_id); - nm_c_list_elem_free_all (&gl.dad_failed_lst_head, (GDestroyNotify) nmp_object_unref); + g_clear_pointer (&hwaddr, g_byte_array_unref); if (pidfile && wrote_pidfile) unlink (pidfile); @@ -597,7 +547,7 @@ const NMDhcpClientFactory *const _nm_dhcp_manager_factories[4] = { #include "nm-config.h" #include "devices/nm-device.h" #include "nm-active-connection.h" -#include "nm-dbus-manager.h" +#include "nm-bus-manager.h" void nm_main_config_reload (int signal) @@ -629,34 +579,21 @@ nm_config_get_configure_and_quit (NMConfig *config) return TRUE; } -NMDBusManager * -nm_dbus_manager_get (void) -{ - return NULL; -} - -void -_nm_dbus_manager_obj_export (NMDBusObject *obj) -{ -} - -void -_nm_dbus_manager_obj_unexport (NMDBusObject *obj) +NMBusManager * +nm_bus_manager_get (void) { + return GUINT_TO_POINTER (1); } void -_nm_dbus_manager_obj_notify (NMDBusObject *obj, - guint n_pspecs, - const GParamSpec *const*pspecs) +nm_bus_manager_register_object (NMBusManager *bus_manager, + GDBusObjectSkeleton *object) { } void -_nm_dbus_manager_obj_emit_signal (NMDBusObject *obj, - const NMDBusInterfaceInfoExtended *interface_info, - const GDBusSignalInfo *signal_info, - GVariant *args) +nm_bus_manager_unregister_object (NMBusManager *bus_manager, + GDBusObjectSkeleton *object) { } diff --git a/src/nm-ip4-config.c b/src/nm-ip4-config.c index 0a9591d2..15157739 100644 --- a/src/nm-ip4-config.c +++ b/src/nm-ip4-config.c @@ -36,7 +36,8 @@ #include "platform/nm-platform-utils.h" #include "NetworkManagerUtils.h" #include "nm-core-internal.h" -#include "nm-dbus-object.h" + +#include "introspection/org.freedesktop.NetworkManager.IP4Config.h" /*****************************************************************************/ @@ -292,7 +293,6 @@ typedef struct { int ifindex; NMIPConfigSource mtu_source; gint dns_priority; - NMSettingConnectionMdns mdns; GArray *nameservers; GPtrArray *domains; GPtrArray *searches; @@ -317,15 +317,15 @@ typedef struct { } NMIP4ConfigPrivate; struct _NMIP4Config { - NMDBusObject parent; + NMExportedObject parent; NMIP4ConfigPrivate _priv; }; struct _NMIP4ConfigClass { - NMDBusObjectClass parent; + NMExportedObjectClass parent; }; -G_DEFINE_TYPE (NMIP4Config, nm_ip4_config, NM_TYPE_DBUS_OBJECT) +G_DEFINE_TYPE (NMIP4Config, nm_ip4_config, NM_TYPE_EXPORTED_OBJECT) #define NM_IP4_CONFIG_GET_PRIVATE(self) _NM_GET_PRIVATE(self, NMIP4Config, NM_IS_IP4_CONFIG) @@ -582,24 +582,14 @@ sort_captured_addresses (const CList *lst_a, const CList *lst_b, gconstpointer u } NMIP4Config * -nm_ip4_config_clone (const NMIP4Config *self) -{ - NMIP4Config *copy; - - copy = nm_ip4_config_new (nm_ip4_config_get_multi_idx (self), -1); - nm_ip4_config_replace (copy, self, NULL); - - return copy; -} - -NMIP4Config * -nm_ip4_config_capture (NMDedupMultiIndex *multi_idx, NMPlatform *platform, int ifindex) +nm_ip4_config_capture (NMDedupMultiIndex *multi_idx, NMPlatform *platform, int ifindex, gboolean capture_resolv_conf) { NMIP4Config *self; NMIP4ConfigPrivate *priv; const NMDedupMultiHeadEntry *head_entry; NMDedupMultiIter iter; const NMPObject *plobj = NULL; + gboolean has_addresses = FALSE; nm_assert (ifindex > 0); @@ -631,6 +621,7 @@ nm_ip4_config_capture (NMDedupMultiIndex *multi_idx, NMPlatform *platform, int i nm_dedup_multi_head_entry_sort (head_entry, sort_captured_addresses, NULL); + has_addresses = TRUE; _notify_addresses (self); } @@ -642,6 +633,23 @@ nm_ip4_config_capture (NMDedupMultiIndex *multi_idx, NMPlatform *platform, int i nmp_cache_iter_for_each (&iter, head_entry, &plobj) _add_route (self, plobj, NULL, NULL); + /* If the interface has the default route, and has IPv4 addresses, capture + * nameservers from /etc/resolv.conf. + */ + if ( has_addresses + && priv->best_default_route + && capture_resolv_conf) { + gs_free char *rc_contents = NULL; + + if (g_file_get_contents (_PATH_RESCONF, &rc_contents, NULL, NULL)) { + if (nm_utils_resolve_conf_parse (AF_INET, + rc_contents, + priv->nameservers, + priv->dns_options)) + _notify (self, PROP_NAMESERVERS); + } + } + return self; } @@ -651,6 +659,7 @@ nm_ip4_config_add_dependent_routes (NMIP4Config *self, guint32 route_metric, GPtrArray **out_ip4_dev_route_blacklist) { + const NMIP4ConfigPrivate *priv; GPtrArray *ip4_dev_route_blacklist = NULL; const NMPlatformIP4Address *my_addr; const NMPlatformIP4Route *my_route; @@ -659,6 +668,8 @@ nm_ip4_config_add_dependent_routes (NMIP4Config *self, g_return_if_fail (NM_IS_IP4_CONFIG (self)); + priv = NM_IP4_CONFIG_GET_PRIVATE (self); + ifindex = nm_ip4_config_get_ifindex (self); g_return_if_fail (ifindex > 0); @@ -882,10 +893,10 @@ _nm_ip_config_merge_route_attributes (int addr_family, void nm_ip4_config_merge_setting (NMIP4Config *self, NMSettingIPConfig *setting, - NMSettingConnectionMdns mdns, guint32 route_table, guint32 route_metric) { + NMIP4ConfigPrivate *priv; guint naddresses, nroutes, nnameservers, nsearches; int i, priority; const char *gateway_str; @@ -896,6 +907,8 @@ nm_ip4_config_merge_setting (NMIP4Config *self, g_return_if_fail (NM_IS_SETTING_IP4_CONFIG (setting)); + priv = NM_IP4_CONFIG_GET_PRIVATE (self); + g_object_freeze_notify (G_OBJECT (self)); naddresses = nm_setting_ip_config_get_num_addresses (setting); @@ -933,7 +946,7 @@ nm_ip4_config_merge_setting (NMIP4Config *self, address.preferred = NM_PLATFORM_LIFETIME_PERMANENT; address.addr_source = NM_IP_CONFIG_SOURCE_USER; - label = nm_ip_address_get_attribute (s_addr, NM_IP_ADDRESS_ATTRIBUTE_LABEL); + label = nm_ip_address_get_attribute (s_addr, "label"); if (label) g_strlcpy (address.label, g_variant_get_string (label, NULL), sizeof (address.label)); @@ -999,8 +1012,6 @@ nm_ip4_config_merge_setting (NMIP4Config *self, if (priority) nm_ip4_config_set_dns_priority (self, priority); - nm_ip4_config_mdns_set (self, mdns); - g_object_thaw_notify (G_OBJECT (self)); } @@ -1047,7 +1058,7 @@ nm_ip4_config_create_setting (const NMIP4Config *self) s_addr = nm_ip_address_new_binary (AF_INET, &address->address, address->plen, NULL); if (*address->label) - nm_ip_address_set_attribute (s_addr, NM_IP_ADDRESS_ATTRIBUTE_LABEL, g_variant_new_string (address->label)); + nm_ip_address_set_attribute (s_addr, "label", g_variant_new_string (address->label)); nm_setting_ip_config_add_address (s_ip4, s_addr); nm_ip_address_unref (s_addr); @@ -1216,11 +1227,6 @@ nm_ip4_config_merge (NMIP4Config *dst, if (nm_ip4_config_get_dns_priority (src)) nm_ip4_config_set_dns_priority (dst, nm_ip4_config_get_dns_priority (src)); - /* mdns */ - nm_ip4_config_mdns_set (dst, - NM_MAX (nm_ip4_config_mdns_get (src), - nm_ip4_config_mdns_get (dst))); - g_object_thaw_notify (G_OBJECT (dst)); } @@ -1457,18 +1463,13 @@ nm_ip4_config_subtract (NMIP4Config *dst, if (nm_ip4_config_get_dns_priority (src) == nm_ip4_config_get_dns_priority (dst)) nm_ip4_config_set_dns_priority (dst, 0); - /* mdns */ - if (nm_ip4_config_mdns_get (src) == nm_ip4_config_mdns_get (dst)) - nm_ip4_config_mdns_set (dst, NM_SETTING_CONNECTION_MDNS_DEFAULT); - g_object_thaw_notify (G_OBJECT (dst)); } -static gboolean -_nm_ip4_config_intersect_helper (NMIP4Config *dst, - const NMIP4Config *src, - guint32 default_route_metric_penalty, - gboolean update_dst) +void +nm_ip4_config_intersect (NMIP4Config *dst, + const NMIP4Config *src, + guint32 default_route_metric_penalty) { NMIP4ConfigPrivate *dst_priv; const NMIP4ConfigPrivate *src_priv; @@ -1476,16 +1477,15 @@ _nm_ip4_config_intersect_helper (NMIP4Config *dst, const NMPlatformIP4Address *a; const NMPlatformIP4Route *r; const NMPObject *new_best_default_route; - gboolean changed, result = FALSE; + gboolean changed; - g_return_val_if_fail (src, FALSE); - g_return_val_if_fail (dst, FALSE); + g_return_if_fail (src); + g_return_if_fail (dst); dst_priv = NM_IP4_CONFIG_GET_PRIVATE (dst); src_priv = NM_IP4_CONFIG_GET_PRIVATE (src); - if (update_dst) - g_object_freeze_notify (G_OBJECT (dst)); + g_object_freeze_notify (G_OBJECT (dst)); /* addresses */ changed = FALSE; @@ -1495,18 +1495,13 @@ _nm_ip4_config_intersect_helper (NMIP4Config *dst, NMP_OBJECT_UP_CAST (a))) continue; - if (!update_dst) - return TRUE; - if (nm_dedup_multi_index_remove_entry (dst_priv->multi_idx, ipconf_iter.current) != 1) nm_assert_not_reached (); changed = TRUE; } - if (changed) { + if (changed) _notify_addresses (dst); - result = TRUE; - } /* ignore nameservers */ @@ -1538,9 +1533,6 @@ _nm_ip4_config_intersect_helper (NMIP4Config *dst, continue; } - if (!update_dst) - return TRUE; - if (nm_dedup_multi_index_remove_entry (dst_priv->multi_idx, ipconf_iter.current) != 1) nm_assert_not_reached (); @@ -1550,71 +1542,18 @@ _nm_ip4_config_intersect_helper (NMIP4Config *dst, nm_assert (changed); _notify (dst, PROP_GATEWAY); } - - if (changed) { + if (changed) _notify_routes (dst); - result = TRUE; - } /* ignore domains */ /* ignore dns searches */ /* ignore dns options */ /* ignore NIS */ /* ignore WINS */ - /* ignore mdns */ - if (update_dst) - g_object_thaw_notify (G_OBJECT (dst)); - return result; + g_object_thaw_notify (G_OBJECT (dst)); } -/** - * nm_ip4_config_intersect: - * @dst: a configuration to be updated - * @src: another configuration - * @default_route_metric_penalty: the default route metric penalty - * - * Computes the intersection between @src and @dst and updates @dst in place - * with the result. - */ -void -nm_ip4_config_intersect (NMIP4Config *dst, - const NMIP4Config *src, - guint32 default_route_metric_penalty) -{ - _nm_ip4_config_intersect_helper (dst, src, default_route_metric_penalty, TRUE); -} - -/** - * nm_ip4_config_intersect_alloc: - * @a: a configuration - * @b: another configuration - * @default_route_metric_penalty: the default route metric penalty - * - * Computes the intersection between @a and @b and returns the result in a newly - * allocated configuration. As a special case, if @a and @b are identical (with - * respect to the only properties considered - addresses and routes) the - * functions returns NULL so that one of existing configuration can be reused - * without allocation. - * - * Returns: the intersection between @a and @b, or %NULL if the result is equal - * to @a and @b. - */ -NMIP4Config * -nm_ip4_config_intersect_alloc (const NMIP4Config *a, - const NMIP4Config *b, - guint32 default_route_metric_penalty) -{ - NMIP4Config *a_copy; - - if (_nm_ip4_config_intersect_helper ((NMIP4Config *) a, b, - default_route_metric_penalty, FALSE)) { - a_copy = nm_ip4_config_clone (a); - _nm_ip4_config_intersect_helper (a_copy, b, default_route_metric_penalty, TRUE); - return a_copy; - } else - return NULL; -} /** * nm_ip4_config_replace: @@ -1840,8 +1779,6 @@ nm_ip4_config_replace (NMIP4Config *dst, const NMIP4Config *src, gboolean *relev has_relevant_changes = TRUE; } - dst_priv->mdns = src_priv->mdns; - /* DNS priority */ if (src_priv->dns_priority != dst_priv->dns_priority) { nm_ip4_config_set_dns_priority (dst, src_priv->dns_priority); @@ -1934,7 +1871,7 @@ nm_ip4_config_dump (const NMIP4Config *self, const char *detail) return; } - str = nm_dbus_object_get_path (NM_DBUS_OBJECT (self)); + str = nm_exported_object_get_path (NM_EXPORTED_OBJECT (self)); if (str) g_message (" path: %s", str); @@ -2519,21 +2456,6 @@ nm_ip4_config_get_dns_option (const NMIP4Config *self, guint i) /*****************************************************************************/ -NMSettingConnectionMdns -nm_ip4_config_mdns_get (const NMIP4Config *self) -{ - return NM_IP4_CONFIG_GET_PRIVATE (self)->mdns; -} - -void -nm_ip4_config_mdns_set (NMIP4Config *self, - NMSettingConnectionMdns mdns) -{ - NM_IP4_CONFIG_GET_PRIVATE (self)->mdns = mdns; -} - -/*****************************************************************************/ - void nm_ip4_config_set_dns_priority (NMIP4Config *self, gint priority) { @@ -2884,9 +2806,9 @@ nm_ip4_config_equal (const NMIP4Config *a, const NMIP4Config *b) { GChecksum *a_checksum = g_checksum_new (G_CHECKSUM_SHA1); GChecksum *b_checksum = g_checksum_new (G_CHECKSUM_SHA1); - guchar a_data[20], b_data[20]; - gsize a_len = sizeof (a_data); - gsize b_len = sizeof (b_data); + gsize a_len = g_checksum_type_get_length (G_CHECKSUM_SHA1); + gsize b_len = g_checksum_type_get_length (G_CHECKSUM_SHA1); + guchar a_data[a_len], b_data[b_len]; gboolean equal; if (a) @@ -2897,8 +2819,7 @@ nm_ip4_config_equal (const NMIP4Config *a, const NMIP4Config *b) g_checksum_get_digest (a_checksum, a_data, &a_len); g_checksum_get_digest (b_checksum, b_data, &b_len); - nm_assert (a_len == sizeof (a_data)); - nm_assert (b_len == sizeof (b_data)); + g_assert (a_len == b_len); equal = !memcmp (a_data, b_data, a_len); g_checksum_free (a_checksum); @@ -2968,7 +2889,7 @@ get_property (GObject *object, guint prop_id, if (*address->label) { g_variant_builder_add (&addr_builder, "{sv}", - NM_IP_ADDRESS_ATTRIBUTE_LABEL, + "label", g_variant_new_string (address->label)); } @@ -3144,7 +3065,6 @@ nm_ip4_config_init (NMIP4Config *self) nm_ip_config_dedup_multi_idx_type_init ((NMIPConfigDedupMultiIdxType *) &priv->idx_ip4_routes, NMP_OBJECT_TYPE_IP4_ROUTE); - priv->mdns = NM_SETTING_CONNECTION_MDNS_DEFAULT; priv->nameservers = g_array_new (FALSE, FALSE, sizeof (guint32)); priv->domains = g_ptr_array_new_with_free_func (g_free); priv->searches = g_ptr_array_new_with_free_func (g_free); @@ -3192,37 +3112,13 @@ finalize (GObject *object) nm_dedup_multi_index_unref (priv->multi_idx); } -static const NMDBusInterfaceInfoExtended interface_info_ip4_config = { - .parent = NM_DEFINE_GDBUS_INTERFACE_INFO_INIT ( - NM_DBUS_INTERFACE_IP4_CONFIG, - .signals = NM_DEFINE_GDBUS_SIGNAL_INFOS ( - &nm_signal_info_property_changed_legacy, - ), - .properties = NM_DEFINE_GDBUS_PROPERTY_INFOS ( - NM_DEFINE_DBUS_PROPERTY_INFO_EXTENDED_READABLE_L ("Addresses", "aau", NM_IP4_CONFIG_ADDRESSES), - NM_DEFINE_DBUS_PROPERTY_INFO_EXTENDED_READABLE_L ("AddressData", "aa{sv}", NM_IP4_CONFIG_ADDRESS_DATA), - NM_DEFINE_DBUS_PROPERTY_INFO_EXTENDED_READABLE_L ("Gateway", "s", NM_IP4_CONFIG_GATEWAY), - NM_DEFINE_DBUS_PROPERTY_INFO_EXTENDED_READABLE_L ("Routes", "aau", NM_IP4_CONFIG_ROUTES), - NM_DEFINE_DBUS_PROPERTY_INFO_EXTENDED_READABLE_L ("RouteData", "aa{sv}", NM_IP4_CONFIG_ROUTE_DATA), - NM_DEFINE_DBUS_PROPERTY_INFO_EXTENDED_READABLE_L ("Nameservers", "au", NM_IP4_CONFIG_NAMESERVERS), - NM_DEFINE_DBUS_PROPERTY_INFO_EXTENDED_READABLE_L ("Domains", "as", NM_IP4_CONFIG_DOMAINS), - NM_DEFINE_DBUS_PROPERTY_INFO_EXTENDED_READABLE_L ("Searches", "as", NM_IP4_CONFIG_SEARCHES), - NM_DEFINE_DBUS_PROPERTY_INFO_EXTENDED_READABLE_L ("DnsOptions", "as", NM_IP4_CONFIG_DNS_OPTIONS), - NM_DEFINE_DBUS_PROPERTY_INFO_EXTENDED_READABLE_L ("DnsPriority", "i", NM_IP4_CONFIG_DNS_PRIORITY), - NM_DEFINE_DBUS_PROPERTY_INFO_EXTENDED_READABLE_L ("WinsServers", "au", NM_IP4_CONFIG_WINS_SERVERS), - ), - ), - .legacy_property_changed = TRUE, -}; - static void nm_ip4_config_class_init (NMIP4ConfigClass *config_class) { GObjectClass *object_class = G_OBJECT_CLASS (config_class); - NMDBusObjectClass *dbus_object_class = NM_DBUS_OBJECT_CLASS (config_class); + NMExportedObjectClass *exported_object_class = NM_EXPORTED_OBJECT_CLASS (config_class); - dbus_object_class->export_path = NM_DBUS_EXPORT_PATH_NUMBERED (NM_DBUS_PATH"/IP4Config"); - dbus_object_class->interface_infos = NM_DBUS_INTERFACE_INFOS (&interface_info_ip4_config); + exported_object_class->export_path = NM_EXPORT_PATH_NUMBERED (NM_DBUS_PATH"/IP4Config"); object_class->get_property = get_property; object_class->set_property = set_property; @@ -3302,4 +3198,8 @@ nm_ip4_config_class_init (NMIP4ConfigClass *config_class) G_PARAM_STATIC_STRINGS); g_object_class_install_properties (object_class, _PROPERTY_ENUMS_LAST, obj_properties); + + nm_exported_object_class_add_interface (NM_EXPORTED_OBJECT_CLASS (config_class), + NMDBUS_TYPE_IP4_CONFIG_SKELETON, + NULL); } diff --git a/src/nm-ip4-config.h b/src/nm-ip4-config.h index 1c5222df..7c345d20 100644 --- a/src/nm-ip4-config.h +++ b/src/nm-ip4-config.h @@ -21,8 +21,7 @@ #ifndef __NETWORKMANAGER_IP4_CONFIG_H__ #define __NETWORKMANAGER_IP4_CONFIG_H__ -#include "nm-setting-connection.h" - +#include "nm-exported-object.h" #include "nm-setting-ip4-config.h" #include "nm-utils/nm-dedup-multi.h" @@ -155,12 +154,11 @@ GType nm_ip4_config_get_type (void); NMIP4Config * nm_ip4_config_new (NMDedupMultiIndex *multi_idx, int ifindex); -NMIP4Config *nm_ip4_config_clone (const NMIP4Config *self); int nm_ip4_config_get_ifindex (const NMIP4Config *self); NMDedupMultiIndex *nm_ip4_config_get_multi_idx (const NMIP4Config *self); -NMIP4Config *nm_ip4_config_capture (NMDedupMultiIndex *multi_idx, NMPlatform *platform, int ifindex); +NMIP4Config *nm_ip4_config_capture (NMDedupMultiIndex *multi_idx, NMPlatform *platform, int ifindex, gboolean capture_resolv_conf); void nm_ip4_config_add_dependent_routes (NMIP4Config *self, guint32 route_table, @@ -173,7 +171,6 @@ gboolean nm_ip4_config_commit (const NMIP4Config *self, void nm_ip4_config_merge_setting (NMIP4Config *self, NMSettingIPConfig *setting, - NMSettingConnectionMdns mdns, guint32 route_table, guint32 route_metric); NMSetting *nm_ip4_config_create_setting (const NMIP4Config *self); @@ -189,9 +186,6 @@ void nm_ip4_config_subtract (NMIP4Config *dst, void nm_ip4_config_intersect (NMIP4Config *dst, const NMIP4Config *src, guint32 default_route_metric_penalty); -NMIP4Config *nm_ip4_config_intersect_alloc (const NMIP4Config *a, - const NMIP4Config *b, - guint32 default_route_metric_penalty); gboolean nm_ip4_config_replace (NMIP4Config *dst, const NMIP4Config *src, gboolean *relevant_changes); void nm_ip4_config_dump (const NMIP4Config *self, const char *detail); @@ -200,10 +194,6 @@ const NMPObject *_nm_ip4_config_best_default_route_find (const NMIP4Config *self in_addr_t nmtst_ip4_config_get_gateway (NMIP4Config *config); -NMSettingConnectionMdns nm_ip4_config_mdns_get (const NMIP4Config *self); -void nm_ip4_config_mdns_set (NMIP4Config *self, - NMSettingConnectionMdns mdns); - const NMDedupMultiHeadEntry *nm_ip4_config_lookup_addresses (const NMIP4Config *self); void nm_ip4_config_reset_addresses (NMIP4Config *self); void nm_ip4_config_add_address (NMIP4Config *self, const NMPlatformIP4Address *address); @@ -228,13 +218,6 @@ const NMPlatformIP4Route *nm_ip4_config_get_direct_route_for_host (const NMIP4Co void nm_ip4_config_reset_nameservers (NMIP4Config *self); void nm_ip4_config_add_nameserver (NMIP4Config *self, guint32 nameserver); - -static inline void -_nm_ip4_config_add_nameserver (NMIP4Config *self, const guint32 *nameserver) -{ - nm_ip4_config_add_nameserver (self, *nameserver); -} - void nm_ip4_config_del_nameserver (NMIP4Config *self, guint i); guint nm_ip4_config_get_num_nameservers (const NMIP4Config *self); guint32 nm_ip4_config_get_nameserver (const NMIP4Config *self, guint i); @@ -355,7 +338,7 @@ nm_ip_config_get_addr_family (const NMIPConfig *config) g_return_val_if_reached (AF_UNSPEC); } -#define _NM_IP_CONFIG_DISPATCH(config, v4_func, v6_func, ...) \ +#define _NM_IP_CONFIG_DISPATCH(config, v4_func, v6_func, dflt, ...) \ G_STMT_START { \ gconstpointer _config = (config); \ \ @@ -367,217 +350,58 @@ nm_ip_config_get_addr_family (const NMIPConfig *config) } \ } G_STMT_END -#define _NM_IP_CONFIG_DISPATCH_VOID(config, v4_func, v6_func, ...) \ - G_STMT_START { \ - gconstpointer _config = (config); \ - \ - if (NM_IS_IP4_CONFIG (_config)) { \ - v4_func ((NMIP4Config *) _config, ##__VA_ARGS__); \ - } else { \ - nm_assert (NM_IS_IP6_CONFIG (_config)); \ - v6_func ((NMIP6Config *) _config, ##__VA_ARGS__); \ - } \ - } G_STMT_END - -static inline int -nm_ip_config_get_ifindex (const NMIPConfig *self) -{ - _NM_IP_CONFIG_DISPATCH (self, nm_ip4_config_get_ifindex, nm_ip6_config_get_ifindex); -} - -static inline void -nm_ip_config_hash (const NMIPConfig *self, GChecksum *sum, gboolean dns_only) -{ - _NM_IP_CONFIG_DISPATCH_VOID (self, nm_ip4_config_hash, nm_ip6_config_hash, sum, dns_only); -} - -static inline void -nm_ip_config_add_address (NMIPConfig *self, const NMPlatformIPAddress *address) -{ - _NM_IP_CONFIG_DISPATCH_VOID (self, nm_ip4_config_add_address, nm_ip6_config_add_address, (gconstpointer) address); -} - -static inline void -nm_ip_config_reset_addresses (NMIPConfig *self) -{ - _NM_IP_CONFIG_DISPATCH_VOID (self, nm_ip4_config_reset_addresses, nm_ip6_config_reset_addresses); -} - -static inline void -nm_ip_config_add_route (NMIPConfig *self, - const NMPlatformIPRoute *new, - const NMPObject **out_obj_new) -{ - _NM_IP_CONFIG_DISPATCH_VOID (self, nm_ip4_config_add_route, nm_ip6_config_add_route, (gpointer) new, out_obj_new); -} - -static inline void -nm_ip_config_reset_routes (NMIPConfig *self) -{ - _NM_IP_CONFIG_DISPATCH_VOID (self, nm_ip4_config_reset_routes, nm_ip6_config_reset_routes); -} - static inline int nm_ip_config_get_dns_priority (const NMIPConfig *self) { - _NM_IP_CONFIG_DISPATCH (self, nm_ip4_config_get_dns_priority, nm_ip6_config_get_dns_priority); -} - -static inline void -nm_ip_config_set_dns_priority (NMIPConfig *self, gint priority) -{ - _NM_IP_CONFIG_DISPATCH_VOID (self, nm_ip4_config_set_dns_priority, nm_ip6_config_set_dns_priority, priority); -} - -static inline void -nm_ip_config_add_nameserver (NMIPConfig *self, const NMIPAddr *ns) -{ - _NM_IP_CONFIG_DISPATCH_VOID (self, _nm_ip4_config_add_nameserver, nm_ip6_config_add_nameserver, (gconstpointer) ns); -} - -static inline void -nm_ip_config_reset_nameservers (const NMIPConfig *self) -{ - _NM_IP_CONFIG_DISPATCH_VOID (self, nm_ip4_config_reset_nameservers, nm_ip6_config_reset_nameservers); + _NM_IP_CONFIG_DISPATCH (self, nm_ip4_config_get_dns_priority, nm_ip6_config_get_dns_priority, 0); } static inline guint nm_ip_config_get_num_nameservers (const NMIPConfig *self) { - _NM_IP_CONFIG_DISPATCH (self, nm_ip4_config_get_num_nameservers, nm_ip6_config_get_num_nameservers); + _NM_IP_CONFIG_DISPATCH (self, nm_ip4_config_get_num_nameservers, nm_ip6_config_get_num_nameservers, 0); } static inline gconstpointer nm_ip_config_get_nameserver (const NMIPConfig *self, guint i) { - _NM_IP_CONFIG_DISPATCH (self, _nm_ip4_config_get_nameserver, nm_ip6_config_get_nameserver, i); + _NM_IP_CONFIG_DISPATCH (self, _nm_ip4_config_get_nameserver, nm_ip6_config_get_nameserver, 0, i); } static inline guint nm_ip_config_get_num_domains (const NMIPConfig *self) { - _NM_IP_CONFIG_DISPATCH (self, nm_ip4_config_get_num_domains, nm_ip6_config_get_num_domains); + _NM_IP_CONFIG_DISPATCH (self, nm_ip4_config_get_num_domains, nm_ip6_config_get_num_domains, 0); } static inline const char * nm_ip_config_get_domain (const NMIPConfig *self, guint i) { - _NM_IP_CONFIG_DISPATCH (self, nm_ip4_config_get_domain, nm_ip6_config_get_domain, i); -} - -static inline void -nm_ip_config_reset_searches (const NMIPConfig *self) -{ - _NM_IP_CONFIG_DISPATCH_VOID (self, nm_ip4_config_reset_searches, nm_ip6_config_reset_searches); -} - -static inline void -nm_ip_config_add_search (const NMIPConfig *self, const char *new) -{ - _NM_IP_CONFIG_DISPATCH_VOID (self, nm_ip4_config_add_search, nm_ip6_config_add_search, new); + _NM_IP_CONFIG_DISPATCH (self, nm_ip4_config_get_domain, nm_ip6_config_get_domain, NULL, i); } static inline guint nm_ip_config_get_num_searches (const NMIPConfig *self) { - _NM_IP_CONFIG_DISPATCH (self, nm_ip4_config_get_num_searches, nm_ip6_config_get_num_searches); + _NM_IP_CONFIG_DISPATCH (self, nm_ip4_config_get_num_searches, nm_ip6_config_get_num_searches, 0); } static inline const char * nm_ip_config_get_search (const NMIPConfig *self, guint i) { - _NM_IP_CONFIG_DISPATCH (self, nm_ip4_config_get_search, nm_ip6_config_get_search, i); + _NM_IP_CONFIG_DISPATCH (self, nm_ip4_config_get_search, nm_ip6_config_get_search, NULL, i); } static inline guint nm_ip_config_get_num_dns_options (const NMIPConfig *self) { - _NM_IP_CONFIG_DISPATCH (self, nm_ip4_config_get_num_dns_options, nm_ip6_config_get_num_dns_options); + _NM_IP_CONFIG_DISPATCH (self, nm_ip4_config_get_num_dns_options, nm_ip6_config_get_num_dns_options, 0); } static inline const char * nm_ip_config_get_dns_option (const NMIPConfig *self, guint i) { - _NM_IP_CONFIG_DISPATCH (self, nm_ip4_config_get_dns_option, nm_ip6_config_get_dns_option, i); -} - -#define _NM_IP_CONFIG_DISPATCH_SET_OP(_return, dst, src, v4_func, v6_func, ...) \ - G_STMT_START { \ - gpointer _dst = (dst); \ - gconstpointer _src = (src); \ - \ - if (NM_IS_IP4_CONFIG (_dst)) { \ - nm_assert (NM_IS_IP4_CONFIG (_src)); \ - _return v4_func ((NMIP4Config *) _dst, (const NMIP4Config *) _src, ##__VA_ARGS__); \ - } else { \ - nm_assert (NM_IS_IP6_CONFIG (_src)); \ - _return v6_func ((NMIP6Config *) _dst, (const NMIP6Config *) _src, ##__VA_ARGS__); \ - } \ - } G_STMT_END - -static inline void -nm_ip_config_intersect (NMIPConfig *dst, - const NMIPConfig *src, - guint32 default_route_metric_penalty) -{ - _NM_IP_CONFIG_DISPATCH_SET_OP (, dst, src, - nm_ip4_config_intersect, - nm_ip6_config_intersect, - default_route_metric_penalty); -} - -static inline void -nm_ip_config_subtract (NMIPConfig *dst, - const NMIPConfig *src, - guint32 default_route_metric_penalty) -{ - _NM_IP_CONFIG_DISPATCH_SET_OP (, dst, src, - nm_ip4_config_subtract, - nm_ip6_config_subtract, - default_route_metric_penalty); -} - -static inline void -nm_ip_config_merge (NMIPConfig *dst, - const NMIPConfig *src, - NMIPConfigMergeFlags merge_flags, - guint32 default_route_metric_penalty) -{ - _NM_IP_CONFIG_DISPATCH_SET_OP (, dst, src, - nm_ip4_config_merge, - nm_ip6_config_merge, - merge_flags, - default_route_metric_penalty); -} - -static inline gboolean -nm_ip_config_replace (NMIPConfig *dst, - const NMIPConfig *src, - gboolean *relevant_changes) -{ - _NM_IP_CONFIG_DISPATCH_SET_OP (return, dst, src, - nm_ip4_config_replace, - nm_ip6_config_replace, - relevant_changes); -} - -static inline NMIPConfig * -nm_ip_config_intersect_alloc (const NMIPConfig *a, - const NMIPConfig *b, - guint32 default_route_metric_penalty) -{ - if (NM_IS_IP4_CONFIG (a)) { - nm_assert (NM_IS_IP4_CONFIG (b)); - return (NMIPConfig *) nm_ip4_config_intersect_alloc ((const NMIP4Config *) a, - (const NMIP4Config *) b, - default_route_metric_penalty); - } else { - nm_assert (NM_IS_IP6_CONFIG (a)); - nm_assert (NM_IS_IP6_CONFIG (b)); - return (NMIPConfig *) nm_ip6_config_intersect_alloc ((const NMIP6Config *) a, - (const NMIP6Config *) b, - default_route_metric_penalty); - } + _NM_IP_CONFIG_DISPATCH (self, nm_ip4_config_get_dns_option, nm_ip6_config_get_dns_option, NULL, i); } #endif /* __NETWORKMANAGER_IP4_CONFIG_H__ */ diff --git a/src/nm-ip6-config.c b/src/nm-ip6-config.c index c76da995..ea3a2029 100644 --- a/src/nm-ip6-config.c +++ b/src/nm-ip6-config.c @@ -38,7 +38,8 @@ #include "NetworkManagerUtils.h" #include "nm-ip4-config.h" #include "ndisc/nm-ndisc.h" -#include "nm-dbus-object.h" + +#include "introspection/org.freedesktop.NetworkManager.IP6Config.h" /*****************************************************************************/ @@ -81,15 +82,15 @@ typedef struct { } NMIP6ConfigPrivate; struct _NMIP6Config { - NMDBusObject parent; + NMExportedObject parent; NMIP6ConfigPrivate _priv; }; struct _NMIP6ConfigClass { - NMDBusObjectClass parent; + NMExportedObjectClass parent; }; -G_DEFINE_TYPE (NMIP6Config, nm_ip6_config, NM_TYPE_DBUS_OBJECT) +G_DEFINE_TYPE (NMIP6Config, nm_ip6_config, NM_TYPE_EXPORTED_OBJECT) #define NM_IP6_CONFIG_GET_PRIVATE(self) _NM_GET_PRIVATE(self, NMIP6Config, NM_IS_IP6_CONFIG) @@ -365,24 +366,14 @@ _nmtst_ip6_config_addresses_sort (NMIP6Config *self) } NMIP6Config * -nm_ip6_config_clone (const NMIP6Config *self) -{ - NMIP6Config *copy; - - copy = nm_ip6_config_new (nm_ip6_config_get_multi_idx (self), -1); - nm_ip6_config_replace (copy, self, NULL); - - return copy; -} - -NMIP6Config * -nm_ip6_config_capture (NMDedupMultiIndex *multi_idx, NMPlatform *platform, int ifindex, NMSettingIP6ConfigPrivacy use_temporary) +nm_ip6_config_capture (NMDedupMultiIndex *multi_idx, NMPlatform *platform, int ifindex, gboolean capture_resolv_conf, NMSettingIP6ConfigPrivacy use_temporary) { NMIP6Config *self; NMIP6ConfigPrivate *priv; const NMDedupMultiHeadEntry *head_entry; NMDedupMultiIter iter; const NMPObject *plobj = NULL; + gboolean has_addresses = FALSE; nm_assert (ifindex > 0); @@ -408,6 +399,7 @@ nm_ip6_config_capture (NMDedupMultiIndex *multi_idx, NMPlatform *platform, int i NULL, NULL)) nm_assert_not_reached (); + has_addresses = TRUE; } head_entry = nm_ip6_config_lookup_addresses (self); nm_assert (head_entry); @@ -424,6 +416,23 @@ nm_ip6_config_capture (NMDedupMultiIndex *multi_idx, NMPlatform *platform, int i nmp_cache_iter_for_each (&iter, head_entry, &plobj) _add_route (self, plobj, NULL, NULL); + /* If the interface has the default route, and has IPv6 addresses, capture + * nameservers from /etc/resolv.conf. + */ + if ( has_addresses + && priv->best_default_route + && capture_resolv_conf) { + gs_free char *rc_contents = NULL; + + if (g_file_get_contents (_PATH_RESCONF, &rc_contents, NULL, NULL)) { + if (nm_utils_resolve_conf_parse (AF_INET6, + rc_contents, + priv->nameservers, + priv->dns_options)) + _notify (self, PROP_NAMESERVERS); + } + } + return self; } @@ -432,6 +441,7 @@ nm_ip6_config_add_dependent_routes (NMIP6Config *self, guint32 route_table, guint32 route_metric) { + const NMIP6ConfigPrivate *priv; const NMPlatformIP6Address *my_addr; const NMPlatformIP6Route *my_route; int ifindex; @@ -439,6 +449,8 @@ nm_ip6_config_add_dependent_routes (NMIP6Config *self, g_return_if_fail (NM_IS_IP6_CONFIG (self)); + priv = NM_IP6_CONFIG_GET_PRIVATE (self); + ifindex = nm_ip6_config_get_ifindex (self); g_return_if_fail (ifindex > 0); @@ -546,7 +558,7 @@ nm_ip6_config_commit (const NMIP6Config *self, ifindex, route_table_sync); - nm_platform_ip6_address_sync (platform, ifindex, addresses, FALSE); + nm_platform_ip6_address_sync (platform, ifindex, addresses, TRUE); if (!nm_platform_ip_route_sync (platform, AF_INET6, @@ -565,6 +577,7 @@ nm_ip6_config_merge_setting (NMIP6Config *self, guint32 route_table, guint32 route_metric) { + NMIP6ConfigPrivate *priv; guint naddresses, nroutes, nnameservers, nsearches; const char *gateway_str; struct in6_addr gateway_bin; @@ -575,6 +588,8 @@ nm_ip6_config_merge_setting (NMIP6Config *self, g_return_if_fail (NM_IS_SETTING_IP6_CONFIG (setting)); + priv = NM_IP6_CONFIG_GET_PRIVATE (self); + naddresses = nm_setting_ip_config_get_num_addresses (setting); nroutes = nm_setting_ip_config_get_num_routes (setting); nnameservers = nm_setting_ip_config_get_num_dns (setting); @@ -802,6 +817,8 @@ nm_ip6_config_merge (NMIP6Config *dst, NMIPConfigMergeFlags merge_flags, guint32 default_route_metric_penalty) { + NMIP6ConfigPrivate *dst_priv; + const NMIP6ConfigPrivate *src_priv; guint32 i; NMDedupMultiIter ipconf_iter; const NMPlatformIP6Address *address = NULL; @@ -809,6 +826,9 @@ nm_ip6_config_merge (NMIP6Config *dst, g_return_if_fail (src != NULL); g_return_if_fail (dst != NULL); + dst_priv = NM_IP6_CONFIG_GET_PRIVATE (dst); + src_priv = NM_IP6_CONFIG_GET_PRIVATE (src); + g_object_freeze_notify (G_OBJECT (dst)); /* addresses */ @@ -1050,28 +1070,26 @@ nm_ip6_config_subtract (NMIP6Config *dst, g_object_thaw_notify (G_OBJECT (dst)); } -static gboolean -_nm_ip6_config_intersect_helper (NMIP6Config *dst, - const NMIP6Config *src, - guint32 default_route_metric_penalty, - gboolean update_dst) +void +nm_ip6_config_intersect (NMIP6Config *dst, + const NMIP6Config *src, + guint32 default_route_metric_penalty) { NMIP6ConfigPrivate *dst_priv; const NMIP6ConfigPrivate *src_priv; NMDedupMultiIter ipconf_iter; const NMPlatformIP6Address *a; const NMPlatformIP6Route *r; - gboolean changed, result = FALSE; + gboolean changed; const NMPObject *new_best_default_route; - g_return_val_if_fail (src, FALSE); - g_return_val_if_fail (dst, FALSE); + g_return_if_fail (src); + g_return_if_fail (dst); dst_priv = NM_IP6_CONFIG_GET_PRIVATE (dst); src_priv = NM_IP6_CONFIG_GET_PRIVATE (src); - if (update_dst) - g_object_freeze_notify (G_OBJECT (dst)); + g_object_freeze_notify (G_OBJECT (dst)); /* addresses */ changed = FALSE; @@ -1081,18 +1099,13 @@ _nm_ip6_config_intersect_helper (NMIP6Config *dst, NMP_OBJECT_UP_CAST (a))) continue; - if (!update_dst) - return TRUE; - if (nm_dedup_multi_index_remove_entry (dst_priv->multi_idx, ipconf_iter.current) != 1) nm_assert_not_reached (); changed = TRUE; } - if (changed) { + if (changed) _notify_addresses (dst); - result = TRUE; - } /* ignore nameservers */ @@ -1124,9 +1137,6 @@ _nm_ip6_config_intersect_helper (NMIP6Config *dst, continue; } - if (!update_dst) - return TRUE; - if (nm_dedup_multi_index_remove_entry (dst_priv->multi_idx, ipconf_iter.current) != 1) nm_assert_not_reached (); @@ -1136,67 +1146,14 @@ _nm_ip6_config_intersect_helper (NMIP6Config *dst, nm_assert (changed); _notify (dst, PROP_GATEWAY); } - if (changed) { + if (changed) _notify_routes (dst); - result = TRUE; - } /* ignore domains */ /* ignore dns searches */ /* ignore dns options */ - if (update_dst) - g_object_thaw_notify (G_OBJECT (dst)); - - return result; -} - -/** - * nm_ip6_config_intersect: - * @dst: a configuration to be updated - * @src: another configuration - * @default_route_metric_penalty: the default route metric penalty - * - * Computes the intersection between @src and @dst and updates @dst in place - * with the result. - */ -void -nm_ip6_config_intersect (NMIP6Config *dst, - const NMIP6Config *src, - guint32 default_route_metric_penalty) -{ - _nm_ip6_config_intersect_helper (dst, src, default_route_metric_penalty, TRUE); -} - -/** - * nm_ip6_config_intersect_alloc: - * @a: a configuration - * @b: another configuration - * @default_route_metric_penalty: the default route metric penalty - * - * Computes the intersection between @a and @b and returns the result in a newly - * allocated configuration. As a special case, if @a and @b are identical (with - * respect to the only properties considered - addresses and routes) the - * functions returns NULL so that one of existing configuration can be reused - * without allocation. - * - * Returns: the intersection between @a and @b, or %NULL if the result is equal - * to @a and @b. - */ -NMIP6Config * -nm_ip6_config_intersect_alloc (const NMIP6Config *a, - const NMIP6Config *b, - guint32 default_route_metric_penalty) -{ - NMIP6Config *a_copy; - - if (_nm_ip6_config_intersect_helper ((NMIP6Config *) a, b, - default_route_metric_penalty, FALSE)) { - a_copy = nm_ip6_config_clone (a); - _nm_ip6_config_intersect_helper (a_copy, b, default_route_metric_penalty, TRUE); - return a_copy; - } else - return NULL; + g_object_thaw_notify (G_OBJECT (dst)); } /** @@ -1466,7 +1423,7 @@ nm_ip6_config_dump (const NMIP6Config *self, const char *detail) g_message ("--------- NMIP6Config %p (%s)", self, detail); - str = nm_dbus_object_get_path (NM_DBUS_OBJECT (self)); + str = nm_exported_object_get_path (NM_EXPORTED_OBJECT (self)); if (str) g_message (" path: %s", str); @@ -1672,43 +1629,22 @@ nm_ip6_config_lookup_address (const NMIP6Config *self, } const NMPlatformIP6Address * -nm_ip6_config_find_first_address (const NMIP6Config *self, - NMPlatformMatchFlags match_flag) +nm_ip6_config_get_address_first_nontentative (const NMIP6Config *self, gboolean linklocal) { + const NMIP6ConfigPrivate *priv; const NMPlatformIP6Address *addr; NMDedupMultiIter iter; g_return_val_if_fail (NM_IS_IP6_CONFIG (self), NULL); - nm_assert (!NM_FLAGS_ANY (match_flag, ~( NM_PLATFORM_MATCH_WITH_ADDRTYPE__ANY - | NM_PLATFORM_MATCH_WITH_ADDRSTATE__ANY))); + priv = NM_IP6_CONFIG_GET_PRIVATE (self); - nm_assert (NM_FLAGS_ANY (match_flag, NM_PLATFORM_MATCH_WITH_ADDRTYPE__ANY)); - nm_assert (NM_FLAGS_ANY (match_flag, NM_PLATFORM_MATCH_WITH_ADDRSTATE__ANY)); + linklocal = !!linklocal; nm_ip_config_iter_ip6_address_for_each (&iter, self, &addr) { - - if (IN6_IS_ADDR_LINKLOCAL (&addr->address)) { - if (!NM_FLAGS_HAS (match_flag, NM_PLATFORM_MATCH_WITH_ADDRTYPE_LINKLOCAL)) - continue; - } else { - if (!NM_FLAGS_HAS (match_flag, NM_PLATFORM_MATCH_WITH_ADDRTYPE_NORMAL)) - continue; - } - - if (NM_FLAGS_HAS (addr->n_ifa_flags, IFA_F_DADFAILED)) { - if (!NM_FLAGS_HAS (match_flag, NM_PLATFORM_MATCH_WITH_ADDRSTATE_DADFAILED)) - continue; - } else if ( NM_FLAGS_HAS (addr->n_ifa_flags, IFA_F_TENTATIVE) - && !NM_FLAGS_HAS (addr->n_ifa_flags, IFA_F_OPTIMISTIC)) { - if (!NM_FLAGS_HAS (match_flag, NM_PLATFORM_MATCH_WITH_ADDRSTATE_TENTATIVE)) - continue; - } else { - if (!NM_FLAGS_HAS (match_flag, NM_PLATFORM_MATCH_WITH_ADDRSTATE_NORMAL)) - continue; - } - - return addr; + if ( ((!!IN6_IS_ADDR_LINKLOCAL (&addr->address)) == linklocal) + && !(addr->n_ifa_flags & IFA_F_TENTATIVE)) + return addr; } return NULL; @@ -2467,9 +2403,9 @@ nm_ip6_config_equal (const NMIP6Config *a, const NMIP6Config *b) { GChecksum *a_checksum = g_checksum_new (G_CHECKSUM_SHA1); GChecksum *b_checksum = g_checksum_new (G_CHECKSUM_SHA1); - guchar a_data[20], b_data[20]; - gsize a_len = sizeof (a_data); - gsize b_len = sizeof (b_data); + gsize a_len = g_checksum_type_get_length (G_CHECKSUM_SHA1); + gsize b_len = g_checksum_type_get_length (G_CHECKSUM_SHA1); + guchar a_data[a_len], b_data[b_len]; gboolean equal; if (a) @@ -2480,8 +2416,7 @@ nm_ip6_config_equal (const NMIP6Config *a, const NMIP6Config *b) g_checksum_get_digest (a_checksum, a_data, &a_len); g_checksum_get_digest (b_checksum, b_data, &b_len); - nm_assert (a_len == sizeof (a_data)); - nm_assert (b_len == sizeof (b_data)); + g_assert (a_len == b_len); equal = !memcmp (a_data, b_data, a_len); g_checksum_free (a_checksum); @@ -2777,36 +2712,13 @@ finalize (GObject *object) nm_dedup_multi_index_unref (priv->multi_idx); } -static const NMDBusInterfaceInfoExtended interface_info_ip6_config = { - .parent = NM_DEFINE_GDBUS_INTERFACE_INFO_INIT ( - NM_DBUS_INTERFACE_IP6_CONFIG, - .signals = NM_DEFINE_GDBUS_SIGNAL_INFOS ( - &nm_signal_info_property_changed_legacy, - ), - .properties = NM_DEFINE_GDBUS_PROPERTY_INFOS ( - NM_DEFINE_DBUS_PROPERTY_INFO_EXTENDED_READABLE_L ("Addresses", "a(ayuay)", NM_IP6_CONFIG_ADDRESSES), - NM_DEFINE_DBUS_PROPERTY_INFO_EXTENDED_READABLE_L ("AddressData", "aa{sv}", NM_IP6_CONFIG_ADDRESS_DATA), - NM_DEFINE_DBUS_PROPERTY_INFO_EXTENDED_READABLE_L ("Gateway", "s", NM_IP6_CONFIG_GATEWAY), - NM_DEFINE_DBUS_PROPERTY_INFO_EXTENDED_READABLE_L ("Routes", "a(ayuayu)", NM_IP6_CONFIG_ROUTES), - NM_DEFINE_DBUS_PROPERTY_INFO_EXTENDED_READABLE_L ("RouteData", "aa{sv}", NM_IP6_CONFIG_ROUTE_DATA), - NM_DEFINE_DBUS_PROPERTY_INFO_EXTENDED_READABLE_L ("Nameservers", "aay", NM_IP6_CONFIG_NAMESERVERS), - NM_DEFINE_DBUS_PROPERTY_INFO_EXTENDED_READABLE_L ("Domains", "as", NM_IP6_CONFIG_DOMAINS), - NM_DEFINE_DBUS_PROPERTY_INFO_EXTENDED_READABLE_L ("Searches", "as", NM_IP6_CONFIG_SEARCHES), - NM_DEFINE_DBUS_PROPERTY_INFO_EXTENDED_READABLE_L ("DnsOptions", "as", NM_IP6_CONFIG_DNS_OPTIONS), - NM_DEFINE_DBUS_PROPERTY_INFO_EXTENDED_READABLE_L ("DnsPriority", "i", NM_IP6_CONFIG_DNS_PRIORITY), - ), - ), - .legacy_property_changed = TRUE, -}; - static void nm_ip6_config_class_init (NMIP6ConfigClass *config_class) { GObjectClass *object_class = G_OBJECT_CLASS (config_class); - NMDBusObjectClass *dbus_object_class = NM_DBUS_OBJECT_CLASS (config_class); + NMExportedObjectClass *exported_object_class = NM_EXPORTED_OBJECT_CLASS (config_class); - dbus_object_class->export_path = NM_DBUS_EXPORT_PATH_NUMBERED (NM_DBUS_PATH"/IP6Config"); - dbus_object_class->interface_infos = NM_DBUS_INTERFACE_INFOS (&interface_info_ip6_config); + exported_object_class->export_path = NM_EXPORT_PATH_NUMBERED (NM_DBUS_PATH"/IP6Config"); object_class->get_property = get_property; object_class->set_property = set_property; @@ -2880,4 +2792,8 @@ nm_ip6_config_class_init (NMIP6ConfigClass *config_class) G_PARAM_STATIC_STRINGS); g_object_class_install_properties (object_class, _PROPERTY_ENUMS_LAST, obj_properties); + + nm_exported_object_class_add_interface (NM_EXPORTED_OBJECT_CLASS (config_class), + NMDBUS_TYPE_IP6_CONFIG_SKELETON, + NULL); } diff --git a/src/nm-ip6-config.h b/src/nm-ip6-config.h index cd01ed02..2fb8b8a4 100644 --- a/src/nm-ip6-config.h +++ b/src/nm-ip6-config.h @@ -23,6 +23,7 @@ #include <netinet/in.h> +#include "nm-exported-object.h" #include "nm-setting-ip6-config.h" #include "nm-utils/nm-dedup-multi.h" @@ -100,13 +101,12 @@ GType nm_ip6_config_get_type (void); NMIP6Config * nm_ip6_config_new (struct _NMDedupMultiIndex *multi_idx, int ifindex); NMIP6Config * nm_ip6_config_new_cloned (const NMIP6Config *src); -NMIP6Config *nm_ip6_config_clone (const NMIP6Config *self); int nm_ip6_config_get_ifindex (const NMIP6Config *self); struct _NMDedupMultiIndex *nm_ip6_config_get_multi_idx (const NMIP6Config *self); NMIP6Config *nm_ip6_config_capture (struct _NMDedupMultiIndex *multi_idx, NMPlatform *platform, int ifindex, - NMSettingIP6ConfigPrivacy use_temporary); + gboolean capture_resolv_conf, NMSettingIP6ConfigPrivacy use_temporary); void nm_ip6_config_add_dependent_routes (NMIP6Config *self, guint32 route_table, @@ -133,9 +133,6 @@ void nm_ip6_config_subtract (NMIP6Config *dst, void nm_ip6_config_intersect (NMIP6Config *dst, const NMIP6Config *src, guint32 default_route_metric_penalty); -NMIP6Config *nm_ip6_config_intersect_alloc (const NMIP6Config *a, - const NMIP6Config *b, - guint32 default_route_metric_penalty); gboolean nm_ip6_config_replace (NMIP6Config *dst, const NMIP6Config *src, gboolean *relevant_changes); void nm_ip6_config_dump (const NMIP6Config *self, const char *detail); @@ -149,8 +146,7 @@ void _nmtst_ip6_config_del_address (NMIP6Config *self, guint i); guint nm_ip6_config_get_num_addresses (const NMIP6Config *self); const NMPlatformIP6Address *nm_ip6_config_get_first_address (const NMIP6Config *self); const NMPlatformIP6Address *_nmtst_ip6_config_get_address (const NMIP6Config *self, guint i); -const NMPlatformIP6Address *nm_ip6_config_find_first_address (const NMIP6Config *self, - NMPlatformMatchFlags match_flag); +const NMPlatformIP6Address *nm_ip6_config_get_address_first_nontentative (const NMIP6Config *self, gboolean linklocal); gboolean nm_ip6_config_address_exists (const NMIP6Config *self, const NMPlatformIP6Address *address); const NMPlatformIP6Address *nm_ip6_config_lookup_address (const NMIP6Config *self, const struct in6_addr *addr); diff --git a/src/nm-logging.c b/src/nm-logging.c index 11e05c31..f19f0de1 100644 --- a/src/nm-logging.c +++ b/src/nm-logging.c @@ -663,7 +663,7 @@ _nm_log_impl (const char *file, NMLogDomain dom = dom_all & _nm_logging_enabled_state[level]; for (diter = &global.domain_desc[0]; diter->name; diter++) { - if (!NM_FLAGS_ANY (dom_all, diter->num)) + if (!NM_FLAGS_HAS (dom_all, diter->num)) continue; /* construct a list of all domains (not only the enabled ones). @@ -681,7 +681,7 @@ _nm_log_impl (const char *file, g_string_append (s_domain_all, diter->name); } - if (NM_FLAGS_ANY (dom, diter->num)) { + if (NM_FLAGS_HAS (dom, diter->num)) { if (i_domain > 0) { /* SYSLOG_FACILITY is specified multiple times for each domain that is actually enabled. */ _iovec_set_format_a (iov++, _MAX_LEN (30, diter->name), "SYSLOG_FACILITY=%s", diter->name); @@ -768,9 +768,6 @@ nm_log_handler (const gchar *log_domain, break; } - if (global.debug_stderr) - g_printerr ("%s%s\n", global.prefix, message ?: ""); - switch (global.log_backend) { #if SYSTEMD_JOURNAL case LOG_BACKEND_JOURNAL: diff --git a/src/nm-logging.h b/src/nm-logging.h index 36ba6a5a..8fcbc8cc 100644 --- a/src/nm-logging.h +++ b/src/nm-logging.h @@ -83,16 +83,6 @@ typedef enum { /*< skip >*/ LOGD_IP = LOGD_IP4 | LOGD_IP6, } NMLogDomain; -static inline NMLogDomain -LOGD_IP_from_af (int addr_family) -{ - switch (addr_family) { - case AF_INET: return LOGD_IP4; - case AF_INET6: return LOGD_IP6; - } - g_return_val_if_reached (LOGD_NONE); -} - /* Log levels */ typedef enum { /*< skip >*/ LOGL_TRACE, @@ -133,7 +123,7 @@ typedef enum { /*< skip >*/ ""__VA_ARGS__); \ } G_STMT_END -/* nm_log() only evaluates its argument list after checking +/* nm_log() only evaluates it's argument list after checking * whether logging for the given level/domain is enabled. */ #define nm_log(level, domain, ifname, con_uuid, ...) \ G_STMT_START { \ diff --git a/src/nm-manager.c b/src/nm-manager.c index 1ccfad8e..f3bbebd0 100644 --- a/src/nm-manager.c +++ b/src/nm-manager.c @@ -30,7 +30,7 @@ #include <unistd.h> #include "nm-common-macros.h" -#include "nm-dbus-manager.h" +#include "nm-bus-manager.h" #include "vpn/nm-vpn-manager.h" #include "devices/nm-device.h" #include "devices/nm-device-generic.h" @@ -56,10 +56,12 @@ #include "nm-dbus-compat.h" #include "nm-checkpoint.h" #include "nm-checkpoint-manager.h" -#include "nm-dbus-object.h" #include "nm-dispatcher.h" #include "NetworkManagerUtils.h" +#include "introspection/org.freedesktop.NetworkManager.h" +#include "introspection/org.freedesktop.NetworkManager.Device.h" + /*****************************************************************************/ typedef struct { @@ -78,6 +80,8 @@ enum { INTERNAL_DEVICE_ADDED, DEVICE_REMOVED, INTERNAL_DEVICE_REMOVED, + STATE_CHANGED, + CHECK_PERMISSIONS, ACTIVE_CONNECTION_ADDED, ACTIVE_CONNECTION_REMOVED, CONFIGURE_QUIT, @@ -110,7 +114,6 @@ NM_GOBJECT_PROPERTIES_DEFINE (NMManager, PROP_METERED, PROP_GLOBAL_DNS_CONFIGURATION, PROP_ALL_DEVICES, - PROP_CHECKPOINTS, /* Not exported */ PROP_SLEEPING, @@ -128,14 +131,16 @@ typedef struct { NMActiveConnection *activating_connection; NMMetered metered; - CList devices_lst_head; - + GSList *devices; NMState state; NMConfig *config; - NMConnectivity *concheck_mgr; + NMConnectivityState connectivity_state; + NMPolicy *policy; + NMHostnameManager *hostname_manager; + NMBusManager *dbus_mgr; struct { GDBusConnection *connection; guint id; @@ -168,30 +173,26 @@ typedef struct { guint devices_inited_id; - NMConnectivityState connectivity_state; - bool startup:1; bool devices_inited:1; bool sleeping:1; bool net_enabled:1; - unsigned connectivity_check_enabled_last:2; - guint delete_volatile_connection_idle_id; CList delete_volatile_connection_lst_head; } NMManagerPrivate; struct _NMManager { - NMDBusObject parent; + NMExportedObject parent; NMManagerPrivate _priv; }; typedef struct { - NMDBusObjectClass parent; + NMExportedObjectClass parent; } NMManagerClass; -G_DEFINE_TYPE (NMManager, nm_manager, NM_TYPE_DBUS_OBJECT) +G_DEFINE_TYPE (NMManager, nm_manager, NM_TYPE_EXPORTED_OBJECT) #define NM_MANAGER_GET_PRIVATE(self) _NM_GET_PRIVATE(self, NMManager, NM_IS_MANAGER) @@ -268,20 +269,9 @@ NM_DEFINE_SINGLETON_INSTANCE (NMManager); /*****************************************************************************/ -static const NMDBusInterfaceInfoExtended interface_info_manager; -static const GDBusSignalInfo signal_info_check_permissions; -static const GDBusSignalInfo signal_info_state_changed; -static const GDBusSignalInfo signal_info_device_added; -static const GDBusSignalInfo signal_info_device_removed; - static gboolean add_device (NMManager *self, NMDevice *device, GError **error); -static void _emit_device_added_removed (NMManager *self, - NMDevice *device, - gboolean is_added); - static NMActiveConnection *_new_active_connection (NMManager *self, - gboolean is_vpn, NMConnection *connection, NMConnection *applied, const char *specific_object, @@ -329,8 +319,6 @@ static NMActiveConnection *active_connection_find_first (NMManager *self, const char *uuid, NMActiveConnectionState max_state); -static NMConnectivity *concheck_get_mgr (NMManager *self); - /*****************************************************************************/ static NM_CACHED_QUARK_FCN ("active-connection-add-and-activate", active_connection_add_and_activate_quark) @@ -339,73 +327,6 @@ static NM_CACHED_QUARK_FCN ("autoconnect-root", autoconnect_root_quark) /*****************************************************************************/ -static gboolean -_connection_is_vpn (NMConnection *connection) -{ - const char *type; - - type = nm_connection_get_connection_type (connection); - if (type) - return nm_streq (type, NM_SETTING_VPN_SETTING_NAME); - - /* we have an incomplete (invalid) connection at hand. That can only - * happen during AddAndActivate. Determine whether it's VPN type based - * on the existance of a [vpn] section. */ - return !!nm_connection_get_setting_vpn (connection); -} - -/*****************************************************************************/ - -static gboolean -concheck_enabled (NMManager *self, gboolean *out_changed) -{ - NMManagerPrivate *priv = NM_MANAGER_GET_PRIVATE (self); - guint check_enabled; - - check_enabled = nm_connectivity_check_enabled (concheck_get_mgr (self)) - ? 1 : 2; - if (priv->connectivity_check_enabled_last == check_enabled) - NM_SET_OUT (out_changed, FALSE); - else { - NM_SET_OUT (out_changed, TRUE); - priv->connectivity_check_enabled_last = check_enabled; - } - return check_enabled == 1; -} - -static void -concheck_config_changed_cb (NMConnectivity *connectivity, - NMManager *self) -{ - NMManagerPrivate *priv = NM_MANAGER_GET_PRIVATE (self); - NMDevice *device; - gboolean changed; - - concheck_enabled (self, &changed); - if (changed) - _notify (self, PROP_CONNECTIVITY_CHECK_ENABLED); - - c_list_for_each_entry (device, &priv->devices_lst_head, devices_lst) - nm_device_check_connectivity_update_interval (device); -} - -static NMConnectivity * -concheck_get_mgr (NMManager *self) -{ - NMManagerPrivate *priv = NM_MANAGER_GET_PRIVATE (self); - - if (G_UNLIKELY (!priv->concheck_mgr)) { - priv->concheck_mgr = g_object_ref (nm_connectivity_get ()); - g_signal_connect (priv->concheck_mgr, - NM_CONNECTIVITY_CONFIG_CHANGED, - G_CALLBACK (concheck_config_changed_cb), - self); - } - return priv->concheck_mgr; -} - -/*****************************************************************************/ - typedef struct { int ifindex; guint32 aspired_metric; @@ -514,10 +435,10 @@ _device_route_metric_get (NMManager *self, * hence we skip it. */ continue; } - if (!g_hash_table_add (priv->device_route_metrics, - _device_route_metric_data_new (device_state->ifindex, - device_state->route_metric_default_aspired, - device_state->route_metric_default_effective))) + if (!nm_g_hash_table_add (priv->device_route_metrics, + _device_route_metric_data_new (device_state->ifindex, + device_state->route_metric_default_aspired, + device_state->route_metric_default_effective))) nm_assert_not_reached (); } } @@ -610,7 +531,7 @@ again: _LOGT (LOGD_DEVICE, "default-route-metric: ifindex %d reserves metric %u (aspired %u)", data->ifindex, data->effective_metric, data->aspired_metric); - if (!g_hash_table_add (priv->device_route_metrics, data)) + if (!nm_g_hash_table_add (priv->device_route_metrics, data)) nm_assert_not_reached (); out: @@ -657,7 +578,7 @@ _delete_volatile_connection_do (NMManager *self, NMManagerPrivate *priv = NM_MANAGER_GET_PRIVATE (self); if (!NM_FLAGS_HAS (nm_settings_connection_get_flags (connection), - NM_SETTINGS_CONNECTION_INT_FLAGS_VOLATILE)) + NM_SETTINGS_CONNECTION_FLAGS_VOLATILE)) return; if (active_connection_find_first (self, connection, @@ -683,7 +604,7 @@ active_connection_remove (NMManager *self, NMActiveConnection *active) nm_assert (NM_IS_ACTIVE_CONNECTION (active)); nm_assert (c_list_contains (&priv->active_connections_lst_head, &active->active_connections_lst)); - notify = nm_dbus_object_is_exported (NM_DBUS_OBJECT (active)); + notify = nm_exported_object_is_exported (NM_EXPORTED_OBJECT (active)); c_list_unlink (&active->active_connections_lst); g_signal_emit (self, signals[ACTIVE_CONNECTION_REMOVED], 0, active); @@ -693,7 +614,7 @@ active_connection_remove (NMManager *self, NMActiveConnection *active) connection = nm_g_object_ref (nm_active_connection_get_settings_connection (active)); - nm_dbus_object_clear_and_unexport (&active); + nm_exported_object_clear_and_unexport (&active); if (connection) _delete_volatile_connection_do (self, connection); @@ -789,8 +710,8 @@ active_connection_add (NMManager *self, G_CALLBACK (active_connection_default_changed), self); - if (!nm_dbus_object_is_exported (NM_DBUS_OBJECT (active))) - nm_dbus_object_export (NM_DBUS_OBJECT (active)); + if (!nm_exported_object_is_exported (NM_EXPORTED_OBJECT (active))) + nm_exported_object_export (NM_EXPORTED_OBJECT (active)); g_signal_emit (self, signals[ACTIVE_CONNECTION_ADDED], 0, active); @@ -854,7 +775,7 @@ _get_activatable_connections_filter (NMSettings *settings, gpointer user_data) { if (NM_FLAGS_HAS (nm_settings_connection_get_flags (connection), - NM_SETTINGS_CONNECTION_INT_FLAGS_VOLATILE)) + NM_SETTINGS_CONNECTION_FLAGS_VOLATILE)) return FALSE; return !active_connection_find_first (user_data, connection, NULL, NM_ACTIVE_CONNECTION_STATE_DEACTIVATING); } @@ -872,20 +793,18 @@ nm_manager_get_activatable_connections (NMManager *manager, guint *out_len, gboo } static NMActiveConnection * -active_connection_get_by_path (NMManager *self, const char *path) +active_connection_get_by_path (NMManager *manager, const char *path) { - NMManagerPrivate *priv = NM_MANAGER_GET_PRIVATE (self); + NMManagerPrivate *priv = NM_MANAGER_GET_PRIVATE (manager); NMActiveConnection *ac; - ac = (NMActiveConnection *) nm_dbus_manager_lookup_object (nm_dbus_object_get_manager (NM_DBUS_OBJECT (self)), - path); - if ( !ac - || !NM_IS_ACTIVE_CONNECTION (ac) - || c_list_is_empty (&ac->active_connections_lst)) - return NULL; + nm_assert (path); - nm_assert (c_list_contains (&priv->active_connections_lst_head, &ac->active_connections_lst)); - return ac; + c_list_for_each_entry (ac, &priv->active_connections_lst_head, active_connections_lst) { + if (nm_streq0 (path, nm_exported_object_get_path (NM_EXPORTED_OBJECT (ac)))) + return ac; + } + return NULL; } /*****************************************************************************/ @@ -893,14 +812,8 @@ active_connection_get_by_path (NMManager *self, const char *path) static void _config_changed_cb (NMConfig *config, NMConfigData *config_data, NMConfigChangeFlags changes, NMConfigData *old_data, NMManager *self) { - g_object_freeze_notify (G_OBJECT (self)); - if (NM_FLAGS_HAS (changes, NM_CONFIG_CHANGE_GLOBAL_DNS_CONFIG)) _notify (self, PROP_GLOBAL_DNS_CONFIGURATION); - if ((!nm_config_data_get_connectivity_uri (config_data)) != (!nm_config_data_get_connectivity_uri (old_data))) - _notify (self, PROP_CONNECTIVITY_CHECK_AVAILABLE); - - g_object_thaw_notify (G_OBJECT (self)); } static void @@ -971,31 +884,28 @@ _reload_auth_cb (NMAuthChain *chain, g_dbus_method_invocation_return_value (context, NULL); out: - nm_auth_chain_destroy (chain); + nm_auth_chain_unref (chain); } static void -impl_manager_reload (NMDBusObject *obj, - const NMDBusInterfaceInfoExtended *interface_info, - const NMDBusMethodInfoExtended *method_info, - GDBusConnection *connection, - const char *sender, - GDBusMethodInvocation *invocation, - GVariant *parameters) -{ - NMManager *self = NM_MANAGER (obj); - NMManagerPrivate *priv = NM_MANAGER_GET_PRIVATE (self); +impl_manager_reload (NMManager *self, + GDBusMethodInvocation *context, + guint32 flags) +{ + NMManagerPrivate *priv; NMAuthChain *chain; - guint32 flags; + GError *error = NULL; - g_variant_get (parameters, "(u)", &flags); + g_return_if_fail (NM_IS_MANAGER (self)); - chain = nm_auth_chain_new_context (invocation, _reload_auth_cb, self); + priv = NM_MANAGER_GET_PRIVATE (self); + + chain = nm_auth_chain_new_context (context, _reload_auth_cb, self); if (!chain) { - g_dbus_method_invocation_return_error_literal (invocation, - NM_MANAGER_ERROR, - NM_MANAGER_ERROR_PERMISSION_DENIED, - "Unable to authenticate request"); + error = g_error_new_literal (NM_MANAGER_ERROR, + NM_MANAGER_ERROR_PERMISSION_DENIED, + "Unable to authenticate request"); + g_dbus_method_invocation_take_error (context, error); return; } @@ -1007,31 +917,27 @@ impl_manager_reload (NMDBusObject *obj, /*****************************************************************************/ NMDevice * -nm_manager_get_device_by_path (NMManager *self, const char *path) +nm_manager_get_device_by_path (NMManager *manager, const char *path) { - NMManagerPrivate *priv = NM_MANAGER_GET_PRIVATE (self); - NMDevice *device; - - g_return_val_if_fail (path, NULL); + GSList *iter; - device = (NMDevice *) nm_dbus_manager_lookup_object (nm_dbus_object_get_manager (NM_DBUS_OBJECT (self)), - path); - if ( !device - || !NM_IS_DEVICE (device) - || c_list_is_empty (&device->devices_lst)) - return NULL; + g_return_val_if_fail (path != NULL, NULL); - nm_assert (c_list_contains (&priv->devices_lst_head, &device->devices_lst)); - return device; + for (iter = NM_MANAGER_GET_PRIVATE (manager)->devices; iter; iter = iter->next) { + if (!strcmp (nm_exported_object_get_path (NM_EXPORTED_OBJECT (iter->data)), path)) + return NM_DEVICE (iter->data); + } + return NULL; } NMDevice * -nm_manager_get_device_by_ifindex (NMManager *self, int ifindex) +nm_manager_get_device_by_ifindex (NMManager *manager, int ifindex) { - NMManagerPrivate *priv = NM_MANAGER_GET_PRIVATE (self); - NMDevice *device; + GSList *iter; + + for (iter = NM_MANAGER_GET_PRIVATE (manager)->devices; iter; iter = iter->next) { + NMDevice *device = NM_DEVICE (iter->data); - c_list_for_each_entry (device, &priv->devices_lst_head, devices_lst) { if (nm_device_get_ifindex (device) == ifindex) return device; } @@ -1040,24 +946,19 @@ nm_manager_get_device_by_ifindex (NMManager *self, int ifindex) } static NMDevice * -find_device_by_permanent_hw_addr (NMManager *self, const char *hwaddr) +find_device_by_permanent_hw_addr (NMManager *manager, const char *hwaddr) { - NMManagerPrivate *priv = NM_MANAGER_GET_PRIVATE (self); - NMDevice *device; + GSList *iter; const char *device_addr; - guint8 hwaddr_bin[NM_UTILS_HWADDR_LEN_MAX]; - gsize hwaddr_len; g_return_val_if_fail (hwaddr != NULL, NULL); - if (!_nm_utils_hwaddr_aton (hwaddr, hwaddr_bin, sizeof (hwaddr_bin), &hwaddr_len)) - return NULL; - - c_list_for_each_entry (device, &priv->devices_lst_head, devices_lst) { - device_addr = nm_device_get_permanent_hw_address (device); - if ( device_addr - && nm_utils_hwaddr_matches (hwaddr_bin, hwaddr_len, device_addr, -1)) - return device; + if (nm_utils_hwaddr_valid (hwaddr, -1)) { + for (iter = NM_MANAGER_GET_PRIVATE (manager)->devices; iter; iter = iter->next) { + device_addr = nm_device_get_permanent_hw_address (NM_DEVICE (iter->data)); + if (device_addr && nm_utils_hwaddr_matches (hwaddr, -1, device_addr, -1)) + return NM_DEVICE (iter->data); + } } return NULL; } @@ -1065,15 +966,16 @@ find_device_by_permanent_hw_addr (NMManager *self, const char *hwaddr) static NMDevice * find_device_by_ip_iface (NMManager *self, const gchar *iface) { - NMManagerPrivate *priv = NM_MANAGER_GET_PRIVATE (self); - NMDevice *device; + GSList *iter; + + g_return_val_if_fail (iface != NULL, NULL); - g_return_val_if_fail (iface, NULL); + for (iter = NM_MANAGER_GET_PRIVATE (self)->devices; iter; iter = g_slist_next (iter)) { + NMDevice *candidate = iter->data; - c_list_for_each_entry (device, &priv->devices_lst_head, devices_lst) { - if ( nm_device_is_real (device) - && nm_streq0 (nm_device_get_ip_iface (device), iface)) - return device; + if ( nm_device_is_real (candidate) + && g_strcmp0 (nm_device_get_ip_iface (candidate), iface) == 0) + return candidate; } return NULL; } @@ -1101,11 +1003,12 @@ find_device_by_iface (NMManager *self, { NMManagerPrivate *priv = NM_MANAGER_GET_PRIVATE (self); NMDevice *fallback = NULL; - NMDevice *candidate; + GSList *iter; g_return_val_if_fail (iface != NULL, NULL); - c_list_for_each_entry (candidate, &priv->devices_lst_head, devices_lst) { + for (iter = priv->devices; iter; iter = iter->next) { + NMDevice *candidate = iter->data; if (strcmp (nm_device_get_iface (candidate), iface)) continue; @@ -1160,6 +1063,22 @@ _nm_state_to_string (NMState state) } } +static void +set_state (NMManager *self, NMState state) +{ + NMManagerPrivate *priv = NM_MANAGER_GET_PRIVATE (self); + + if (priv->state == state) + return; + + priv->state = state; + + _LOGI (LOGD_CORE, "NetworkManager state is now %s", _nm_state_to_string (state)); + + _notify (self, PROP_STATE); + g_signal_emit (self, signals[STATE_CHANGED], 0, priv->state); +} + static NMState find_best_device_state (NMManager *manager) { @@ -1230,38 +1149,26 @@ nm_manager_update_metered (NMManager *self) } static void -nm_manager_update_state (NMManager *self) +nm_manager_update_state (NMManager *manager) { NMManagerPrivate *priv; NMState new_state = NM_STATE_DISCONNECTED; - g_return_if_fail (NM_IS_MANAGER (self)); + g_return_if_fail (NM_IS_MANAGER (manager)); - priv = NM_MANAGER_GET_PRIVATE (self); + priv = NM_MANAGER_GET_PRIVATE (manager); - if (manager_sleeping (self)) + if (manager_sleeping (manager)) new_state = NM_STATE_ASLEEP; else - new_state = find_best_device_state (self); + new_state = find_best_device_state (manager); if ( new_state >= NM_STATE_CONNECTED_LOCAL && priv->connectivity_state == NM_CONNECTIVITY_FULL) { new_state = NM_STATE_CONNECTED_GLOBAL; } - if (priv->state == new_state) - return; - - priv->state = new_state; - - _LOGI (LOGD_CORE, "NetworkManager state is now %s", _nm_state_to_string (new_state)); - - _notify (self, PROP_STATE); - nm_dbus_object_emit_signal (NM_DBUS_OBJECT (self), - &interface_info_manager, - &signal_info_state_changed, - "(u)", - (guint32) priv->state); + set_state (manager, new_state); } static void @@ -1303,7 +1210,7 @@ static void check_if_startup_complete (NMManager *self) { NMManagerPrivate *priv = NM_MANAGER_GET_PRIVATE (self); - NMDevice *device; + GSList *iter; if (!priv->startup) return; @@ -1316,10 +1223,12 @@ check_if_startup_complete (NMManager *self) return; } - c_list_for_each_entry (device, &priv->devices_lst_head, devices_lst) { - if (nm_device_has_pending_action (device)) { + for (iter = priv->devices; iter; iter = iter->next) { + NMDevice *dev = iter->data; + + if (nm_device_has_pending_action (dev)) { _LOGD (LOGD_CORE, "check_if_startup_complete returns FALSE because of %s", - nm_device_get_iface (device)); + nm_device_get_iface (dev)); return; } } @@ -1331,8 +1240,8 @@ check_if_startup_complete (NMManager *self) /* we no longer care about these signals. Startup-complete only * happens once. */ g_signal_handlers_disconnect_by_func (priv->settings, G_CALLBACK (settings_startup_complete_changed), self); - c_list_for_each_entry (device, &priv->devices_lst_head, devices_lst) { - g_signal_handlers_disconnect_by_func (device, + for (iter = priv->devices; iter; iter = iter->next) { + g_signal_handlers_disconnect_by_func (iter->data, G_CALLBACK (device_has_pending_action_changed), self); } @@ -1364,18 +1273,18 @@ _parent_notify_changed (NMManager *self, NMDevice *device, gboolean device_removed) { - NMManagerPrivate *priv = NM_MANAGER_GET_PRIVATE (self); - NMDevice *candidate; + GSList *iter; nm_assert (NM_IS_DEVICE (device)); + nm_assert (NM_IS_MANAGER (self)); -again: - c_list_for_each_entry (candidate, &priv->devices_lst_head, devices_lst) { - if (nm_device_parent_notify_changed (candidate, device, device_removed)) { + for (iter = NM_MANAGER_GET_PRIVATE (self)->devices; iter; ) { + if (nm_device_parent_notify_changed (iter->data, device, device_removed)) { /* in the unlikely event that this changes anything, we start iterating * again, to be sure that the device list is up-to-date. */ - goto again; - } + iter = NM_MANAGER_GET_PRIVATE (self)->devices; + } else + iter = iter->next; } } @@ -1415,8 +1324,7 @@ remove_device (NMManager *self, g_signal_handlers_disconnect_matched (device, G_SIGNAL_MATCH_DATA, 0, 0, NULL, NULL, self); nm_settings_device_removed (priv->settings, device, quitting); - - c_list_unlink (&device->devices_lst); + priv->devices = g_slist_remove (priv->devices, device); _parent_notify_changed (self, device, TRUE); @@ -1434,7 +1342,8 @@ remove_device (NMManager *self, * Control that by passing @unconfigure_ip_config. */ nm_device_removed (device, unconfigure_ip_config); - _emit_device_added_removed (self, device, FALSE); + g_signal_emit (self, signals[DEVICE_REMOVED], 0, device); + _notify (self, PROP_DEVICES); } else { /* unrealize() does not release a slave device from master and * clear IP configurations, do it here */ @@ -1444,7 +1353,7 @@ remove_device (NMManager *self, g_signal_emit (self, signals[INTERNAL_DEVICE_REMOVED], 0, device); _notify (self, PROP_ALL_DEVICES); - nm_dbus_object_clear_and_unexport (&device); + nm_exported_object_clear_and_unexport (&device); check_if_startup_complete (self); } @@ -1473,7 +1382,7 @@ find_parent_device_for_connection (NMManager *self, NMConnection *connection, NM const char *parent_name = NULL; NMSettingsConnection *parent_connection; NMDevice *parent, *first_compatible = NULL; - NMDevice *candidate; + GSList *iter; g_return_val_if_fail (NM_IS_CONNECTION (connection), NULL); @@ -1506,7 +1415,9 @@ find_parent_device_for_connection (NMManager *self, NMConnection *connection, NM /* Check if the parent connection is currently activated or is comaptible * with some known device. */ - c_list_for_each_entry (candidate, &priv->devices_lst_head, devices_lst) { + for (iter = priv->devices; iter; iter = iter->next) { + NMDevice *candidate = iter->data; + /* Unmanaged devices are not compatible with any connection */ if (!nm_device_get_managed (candidate, FALSE)) continue; @@ -1622,15 +1533,18 @@ NMDevice * nm_manager_get_device (NMManager *self, const char *ifname, NMDeviceType device_type) { NMManagerPrivate *priv = NM_MANAGER_GET_PRIVATE (self); - NMDevice *device; + GSList *iter; + NMDevice *d; g_return_val_if_fail (ifname, NULL); g_return_val_if_fail (device_type != NM_DEVICE_TYPE_UNKNOWN, NULL); - c_list_for_each_entry (device, &priv->devices_lst_head, devices_lst) { - if ( nm_device_get_device_type (device) == device_type - && nm_streq0 (nm_device_get_iface (device), ifname)) - return device; + for (iter = priv->devices; iter; iter = iter->next) { + d = iter->data; + + if ( nm_device_get_device_type (d) == device_type + && nm_streq0 (nm_device_get_iface (d), ifname)) + return d; } return NULL; @@ -1666,9 +1580,9 @@ system_create_virtual_device (NMManager *self, NMConnection *connection) NMDeviceFactory *factory; gs_free NMSettingsConnection **connections = NULL; guint i; + GSList *iter; gs_free char *iface = NULL; NMDevice *device = NULL, *parent = NULL; - NMDevice *dev_candidate; GError *error = NULL; NMLogLevel log_level; @@ -1684,15 +1598,17 @@ system_create_virtual_device (NMManager *self, NMConnection *connection) } /* See if there's a device that is already compatible with this connection */ - c_list_for_each_entry (dev_candidate, &priv->devices_lst_head, devices_lst) { - if (nm_device_check_connection_compatible (dev_candidate, connection)) { - if (nm_device_is_real (dev_candidate)) { + for (iter = priv->devices; iter; iter = g_slist_next (iter)) { + NMDevice *candidate = iter->data; + + if (nm_device_check_connection_compatible (candidate, connection)) { + if (nm_device_is_real (candidate)) { _LOG3D (LOGD_DEVICE, connection, "already created virtual interface name %s", iface); return NULL; } - device = dev_candidate; + device = candidate; break; } } @@ -1888,7 +1804,7 @@ connection_flags_changed (NMSettings *settings, DeleteVolatileConnectionData *data; if (!NM_FLAGS_HAS (nm_settings_connection_get_flags (connection), - NM_SETTINGS_CONNECTION_INT_FLAGS_VOLATILE)) + NM_SETTINGS_CONNECTION_FLAGS_VOLATILE)) return; if (active_connection_find_first (self, connection, NULL, NM_ACTIVE_CONNECTION_STATE_DEACTIVATED)) { @@ -1913,10 +1829,10 @@ system_unmanaged_devices_changed_cb (NMSettings *settings, { NMManager *self = NM_MANAGER (user_data); NMManagerPrivate *priv = NM_MANAGER_GET_PRIVATE (self); - NMDevice *device; + const GSList *iter; - c_list_for_each_entry (device, &priv->devices_lst_head, devices_lst) - nm_device_set_unmanaged_by_user_settings (device); + for (iter = priv->devices; iter; iter = g_slist_next (iter)) + nm_device_set_unmanaged_by_user_settings (NM_DEVICE (iter->data)); } static void @@ -1962,7 +1878,7 @@ manager_update_radio_enabled (NMManager *self, gboolean enabled) { NMManagerPrivate *priv = NM_MANAGER_GET_PRIVATE (self); - NMDevice *device; + GSList *iter; /* Do nothing for radio types not yet implemented */ if (!rstate->prop) @@ -1975,7 +1891,9 @@ manager_update_radio_enabled (NMManager *self, return; /* enable/disable wireless devices as required */ - c_list_for_each_entry (device, &priv->devices_lst_head, devices_lst) { + for (iter = priv->devices; iter; iter = iter->next) { + NMDevice *device = NM_DEVICE (iter->data); + if (nm_device_get_rfkill_type (device) == rstate->rtype) { _LOG2D (LOGD_RFKILL, device, "rfkill: setting radio %s", enabled ? "enabled" : "disabled"); nm_device_set_enabled (device, enabled); @@ -2118,7 +2036,7 @@ device_auth_done_cb (NMAuthChain *chain, nm_auth_chain_get_data (chain, "user-data")); g_clear_error (&error); - nm_auth_chain_destroy (chain); + nm_auth_chain_unref (chain); } static void @@ -2134,6 +2052,7 @@ device_auth_request_cb (NMDevice *device, NMManagerPrivate *priv = NM_MANAGER_GET_PRIVATE (self); GError *error = NULL; NMAuthSubject *subject = NULL; + char *error_desc = NULL; NMAuthChain *chain; /* Validate the caller */ @@ -2146,13 +2065,15 @@ device_auth_request_cb (NMDevice *device, } /* Ensure the subject has permissions for this connection */ - if ( connection - && !nm_auth_is_subject_in_acl_set_error (connection, - subject, - NM_MANAGER_ERROR, - NM_MANAGER_ERROR_PERMISSION_DENIED, - &error)) + if (connection && !nm_auth_is_subject_in_acl (connection, + subject, + &error_desc)) { + error = g_error_new_literal (NM_MANAGER_ERROR, + NM_MANAGER_ERROR_PERMISSION_DENIED, + error_desc); + g_free (error_desc); goto done; + } /* Validate the request */ chain = nm_auth_chain_new_subject (subject, context, device_auth_done_cb, self); @@ -2349,8 +2270,8 @@ get_existing_connection (NMManager *self, } nm_settings_connection_set_flags (NM_SETTINGS_CONNECTION (added), - NM_SETTINGS_CONNECTION_INT_FLAGS_NM_GENERATED | - NM_SETTINGS_CONNECTION_INT_FLAGS_VOLATILE, + NM_SETTINGS_CONNECTION_FLAGS_NM_GENERATED | + NM_SETTINGS_CONNECTION_FLAGS_VOLATILE, TRUE); NM_SET_OUT (out_generated, TRUE); return added; @@ -2414,20 +2335,15 @@ recheck_assume_connection (NMManager *self, GError *error = NULL; subject = nm_auth_subject_new_internal (); - active = _new_active_connection (self, - FALSE, - NM_CONNECTION (connection), - NULL, - NULL, - device, - subject, + active = _new_active_connection (self, NM_CONNECTION (connection), NULL, NULL, + device, subject, generated ? NM_ACTIVATION_TYPE_EXTERNAL : NM_ACTIVATION_TYPE_ASSUME, NM_ACTIVATION_REASON_AUTOCONNECT, &error); if (!active) { _LOGW (LOGD_DEVICE, "assume: assumed connection %s failed to activate: %s", - nm_dbus_object_get_path (NM_DBUS_OBJECT (connection)), + nm_connection_get_path (NM_CONNECTION (connection)), error->message); g_error_free (error); @@ -2478,17 +2394,18 @@ device_ip_iface_changed (NMDevice *device, GParamSpec *pspec, NMManager *self) { - NMManagerPrivate *priv = NM_MANAGER_GET_PRIVATE (self); const char *ip_iface = nm_device_get_ip_iface (device); NMDeviceType device_type = nm_device_get_device_type (device); - NMDevice *candidate; + GSList *iter; /* Remove NMDevice objects that are actually child devices of others, * when the other device finally knows its IP interface name. For example, * remove the PPP interface that's a child of a WWAN device, since it's * not really a standalone NMDevice. */ - c_list_for_each_entry (candidate, &priv->devices_lst_head, devices_lst) { + for (iter = NM_MANAGER_GET_PRIVATE (self)->devices; iter; iter = iter->next) { + NMDevice *candidate = NM_DEVICE (iter->data); + if ( candidate != device && g_strcmp0 (nm_device_get_iface (candidate), ip_iface) == 0 && nm_device_get_device_type (candidate) == device_type @@ -2510,56 +2427,35 @@ device_iface_changed (NMDevice *device, retry_connections_for_parent_device (self, device); } -static void -_emit_device_added_removed (NMManager *self, - NMDevice *device, - gboolean is_added) -{ - nm_dbus_object_emit_signal (NM_DBUS_OBJECT (self), - &interface_info_manager, - is_added - ? &signal_info_device_added - : &signal_info_device_removed, - "(o)", - nm_dbus_object_get_path (NM_DBUS_OBJECT (device))); - g_signal_emit (self, - signals[is_added ? DEVICE_ADDED : DEVICE_REMOVED], - 0, - device); - _notify (self, PROP_DEVICES); -} static void device_realized (NMDevice *device, GParamSpec *pspec, NMManager *self) { - _emit_device_added_removed (self, device, nm_device_is_real (device)); + gboolean real = nm_device_is_real (device); + + /* Emit D-Bus signals */ + g_signal_emit (self, signals[real ? DEVICE_ADDED : DEVICE_REMOVED], 0, device); + _notify (self, PROP_DEVICES); } +#if WITH_CONCHECK static void device_connectivity_changed (NMDevice *device, + GParamSpec *pspec, NMManager *self) { NMManagerPrivate *priv = NM_MANAGER_GET_PRIVATE (self); NMConnectivityState best_state = NM_CONNECTIVITY_UNKNOWN; NMConnectivityState state; - NMDevice *dev; + const GSList *devices; - best_state = nm_device_get_connectivity_state (device); - if (best_state < NM_CONNECTIVITY_FULL) { - c_list_for_each_entry (dev, &priv->devices_lst_head, devices_lst) { - state = nm_device_get_connectivity_state (dev); - if (state <= best_state) - continue; + for (devices = priv->devices; devices; devices = devices->next) { + state = nm_device_get_connectivity_state (NM_DEVICE (devices->data)); + if (state > best_state) best_state = state; - if (best_state >= NM_CONNECTIVITY_FULL) { - /* it doesn't get better than this. */ - break; - } - } } - nm_assert (best_state <= NM_CONNECTIVITY_FULL); if (best_state != priv->connectivity_state) { priv->connectivity_state = best_state; @@ -2572,6 +2468,7 @@ device_connectivity_changed (NMDevice *device, nm_dispatcher_call_connectivity (priv->connectivity_state, NULL, NULL, NULL); } } +#endif static void _device_realize_finish (NMManager *self, @@ -2617,7 +2514,6 @@ add_device (NMManager *self, NMDevice *device, GError **error) GSList *iter, *remove = NULL; int ifindex; const char *dbus_path; - NMDevice *candidate; /* No duplicates */ ifindex = nm_device_get_ifindex (device); @@ -2634,20 +2530,18 @@ add_device (NMManager *self, NMDevice *device, GError **error) * FIXME: use parent/child device relationships instead of removing * the child NMDevice entirely */ - c_list_for_each_entry (candidate, &priv->devices_lst_head, devices_lst) { - if ( nm_device_is_real (candidate) - && (iface = nm_device_get_ip_iface (candidate)) - && nm_device_owns_iface (device, iface)) + for (iter = priv->devices; iter; iter = iter->next) { + NMDevice *candidate = iter->data; + + iface = nm_device_get_ip_iface (candidate); + if (nm_device_is_real (candidate) && nm_device_owns_iface (device, iface)) remove = g_slist_prepend (remove, candidate); } for (iter = remove; iter; iter = iter->next) remove_device (self, NM_DEVICE (iter->data), FALSE, FALSE); g_slist_free (remove); - g_object_ref (device); - - nm_assert (c_list_is_empty (&device->devices_lst)); - c_list_link_tail (&priv->devices_lst_head, &device->devices_lst); + priv->devices = g_slist_append (priv->devices, g_object_ref (device)); g_signal_connect (device, NM_DEVICE_STATE_CHANGED, G_CALLBACK (manager_device_state_changed), @@ -2681,9 +2575,11 @@ add_device (NMManager *self, NMDevice *device, GError **error) G_CALLBACK (device_realized), self); - g_signal_connect (device, NM_DEVICE_CONNECTIVITY_CHANGED, +#if WITH_CONCHECK + g_signal_connect (device, "notify::" NM_DEVICE_CONNECTIVITY, G_CALLBACK (device_connectivity_changed), self); +#endif if (priv->startup) { g_signal_connect (device, "notify::" NM_DEVICE_HAS_PENDING_ACTION, @@ -2712,7 +2608,7 @@ add_device (NMManager *self, NMDevice *device, GError **error) NM_UNMANAGED_SLEEPING, manager_sleeping (self)); - dbus_path = nm_dbus_object_export (NM_DBUS_OBJECT (device)); + dbus_path = nm_exported_object_export (NM_EXPORTED_OBJECT (device)); _LOG2I (LOGD_DEVICE, device, "new %s device (%s)", type_desc, dbus_path); nm_settings_device_added (priv->settings, device); @@ -2759,11 +2655,12 @@ factory_component_added_cb (NMDeviceFactory *factory, gpointer user_data) { NMManager *self = user_data; - NMManagerPrivate *priv = NM_MANAGER_GET_PRIVATE (self); - NMDevice *device; + GSList *iter; - c_list_for_each_entry (device, &priv->devices_lst_head, devices_lst) { - if (nm_device_notify_component_added (device, component)) + g_return_val_if_fail (self, FALSE); + + for (iter = NM_MANAGER_GET_PRIVATE (self)->devices; iter; iter = iter->next) { + if (nm_device_notify_component_added ((NMDevice *) iter->data, component)) return TRUE; } return FALSE; @@ -2793,10 +2690,9 @@ platform_link_added (NMManager *self, gboolean guess_assume, const NMConfigDeviceStateData *dev_state) { - NMManagerPrivate *priv = NM_MANAGER_GET_PRIVATE (self); NMDeviceFactory *factory; NMDevice *device = NULL; - NMDevice *candidate; + GSList *iter; g_return_if_fail (ifindex > 0); @@ -2804,7 +2700,8 @@ platform_link_added (NMManager *self, return; /* Let unrealized devices try to realize themselves with the link */ - c_list_for_each_entry (candidate, &priv->devices_lst_head, devices_lst) { + for (iter = NM_MANAGER_GET_PRIVATE (self)->devices; iter; iter = iter->next) { + NMDevice *candidate = iter->data; gboolean compatible = TRUE; gs_free_error GError *error = NULL; @@ -3031,12 +2928,12 @@ rfkill_manager_rfkill_changed_cb (NMRfkillManager *rfkill_mgr, nm_manager_rfkill_update (NM_MANAGER (user_data), rtype); } -const CList * +const GSList * nm_manager_get_devices (NMManager *manager) { g_return_val_if_fail (NM_IS_MANAGER (manager), NULL); - return &NM_MANAGER_GET_PRIVATE (manager)->devices_lst_head; + return NM_MANAGER_GET_PRIVATE (manager)->devices; } static NMDevice * @@ -3045,10 +2942,9 @@ nm_manager_get_best_device_for_connection (NMManager *self, gboolean for_user_request, GHashTable *unavailable_devices) { - NMManagerPrivate *priv = NM_MANAGER_GET_PRIVATE (self); + const GSList *devices, *iter; NMActiveConnection *ac; NMDevice *act_device; - NMDevice *device; NMDeviceCheckConAvailableFlags flags; ac = active_connection_find_first_by_connection (self, connection); @@ -3061,7 +2957,9 @@ nm_manager_get_best_device_for_connection (NMManager *self, flags = for_user_request ? NM_DEVICE_CHECK_CON_AVAILABLE_FOR_USER_REQUEST : NM_DEVICE_CHECK_CON_AVAILABLE_NONE; /* Pick the first device that's compatible with the connection. */ - c_list_for_each_entry (device, &priv->devices_lst_head, devices_lst) { + devices = nm_manager_get_devices (self); + for (iter = devices; iter; iter = g_slist_next (iter)) { + NMDevice *device = NM_DEVICE (iter->data); if (unavailable_devices && g_hash_table_contains (unavailable_devices, device)) continue; @@ -3074,100 +2972,67 @@ nm_manager_get_best_device_for_connection (NMManager *self, return NULL; } -static const char ** -_get_devices_paths (NMManager *self, - gboolean all_devices) +static void +_get_devices (NMManager *self, + GDBusMethodInvocation *context, + gboolean all_devices) { NMManagerPrivate *priv = NM_MANAGER_GET_PRIVATE (self); - const char **paths = NULL; + gs_free const char **paths = NULL; guint i; - NMDevice *device; + GSList *iter; - paths = g_new (const char *, c_list_length (&priv->devices_lst_head) + 1); + paths = g_new (const char *, g_slist_length (priv->devices) + 1); - i = 0; - c_list_for_each_entry (device, &priv->devices_lst_head, devices_lst) { + for (i = 0, iter = priv->devices; iter; iter = iter->next) { const char *path; - path = nm_dbus_object_get_path (NM_DBUS_OBJECT (device)); - if (!path) - continue; - - if ( !all_devices - && !nm_device_is_real (device)) - continue; - - paths[i++] = path; + path = nm_exported_object_get_path (NM_EXPORTED_OBJECT (iter->data)); + if ( path + && (all_devices || nm_device_is_real (iter->data))) + paths[i++] = path; } paths[i++] = NULL; - return paths; + g_dbus_method_invocation_return_value (context, + g_variant_new ("(^ao)", (char **) paths)); } static void -impl_manager_get_devices (NMDBusObject *obj, - const NMDBusInterfaceInfoExtended *interface_info, - const NMDBusMethodInfoExtended *method_info, - GDBusConnection *connection, - const char *sender, - GDBusMethodInvocation *invocation, - GVariant *parameters) -{ - NMManager *self = NM_MANAGER (obj); - gs_free const char **paths = NULL; - - paths = _get_devices_paths (self, FALSE); - g_dbus_method_invocation_return_value (invocation, - g_variant_new ("(^ao)", (char **) paths)); +impl_manager_get_devices (NMManager *self, + GDBusMethodInvocation *context) +{ + _get_devices (self, context, FALSE); } static void -impl_manager_get_all_devices (NMDBusObject *obj, - const NMDBusInterfaceInfoExtended *interface_info, - const NMDBusMethodInfoExtended *method_info, - GDBusConnection *connection, - const char *sender, - GDBusMethodInvocation *invocation, - GVariant *parameters) -{ - NMManager *self = NM_MANAGER (obj); - gs_free const char **paths = NULL; - - paths = _get_devices_paths (self, TRUE); - g_dbus_method_invocation_return_value (invocation, - g_variant_new ("(^ao)", (char **) paths)); +impl_manager_get_all_devices (NMManager *self, + GDBusMethodInvocation *context) +{ + _get_devices (self, context, TRUE); } static void -impl_manager_get_device_by_ip_iface (NMDBusObject *obj, - const NMDBusInterfaceInfoExtended *interface_info, - const NMDBusMethodInfoExtended *method_info, - GDBusConnection *connection, - const char *sender, - GDBusMethodInvocation *invocation, - GVariant *parameters) -{ - NMManager *self = NM_MANAGER (obj); +impl_manager_get_device_by_ip_iface (NMManager *self, + GDBusMethodInvocation *context, + const char *iface) +{ NMDevice *device; const char *path = NULL; - const char *iface; - - g_variant_get (parameters, "(&s)", &iface); device = find_device_by_ip_iface (self, iface); if (device) - path = nm_dbus_object_get_path (NM_DBUS_OBJECT (device)); + path = nm_exported_object_get_path (NM_EXPORTED_OBJECT (device)); - if (!path) { - g_dbus_method_invocation_return_error (invocation, + if (path == NULL) { + g_dbus_method_invocation_return_error (context, NM_MANAGER_ERROR, NM_MANAGER_ERROR_UNKNOWN_DEVICE, "No device found for the requested iface."); - return; + } else { + g_dbus_method_invocation_return_value (context, + g_variant_new ("(o)", path)); } - - g_dbus_method_invocation_return_value (invocation, - g_variant_new ("(o)", path)); } static gboolean @@ -3240,6 +3105,7 @@ find_master (NMManager *self, const char *master; NMDevice *master_device = NULL; NMSettingsConnection *master_connection = NULL; + GSList *iter; s_con = nm_connection_get_setting_connection (connection); g_assert (s_con); @@ -3268,10 +3134,10 @@ find_master (NMManager *self, /* Try master as a connection UUID */ master_connection = nm_settings_get_connection_by_uuid (priv->settings, master); if (master_connection) { - NMDevice *candidate; - /* Check if the master connection is activated on some device already */ - c_list_for_each_entry (candidate, &priv->devices_lst_head, devices_lst) { + for (iter = priv->devices; iter; iter = g_slist_next (iter)) { + NMDevice *candidate = NM_DEVICE (iter->data); + if (candidate == device) continue; @@ -3343,6 +3209,7 @@ ensure_master_active_connection (NMManager *self, NMManagerPrivate *priv = NM_MANAGER_GET_PRIVATE (self); NMActiveConnection *master_ac = NULL; NMDeviceState master_state; + GSList *iter; g_assert (connection); g_assert (master_connection || master_device); @@ -3419,10 +3286,12 @@ ensure_master_active_connection (NMManager *self, NM_MANAGER_ERROR_DEPENDENCY_FAILED, "Device unmanaged or not available for activation"); } else if (master_connection) { - NMDevice *candidate; + gboolean found_device = FALSE; /* Find a compatible device and activate it using this connection */ - c_list_for_each_entry (candidate, &priv->devices_lst_head, devices_lst) { + for (iter = priv->devices; iter; iter = g_slist_next (iter)) { + NMDevice *candidate = NM_DEVICE (iter->data); + if (candidate == device) { /* A device obviously can't be its own master */ continue; @@ -3431,6 +3300,7 @@ ensure_master_active_connection (NMManager *self, if (!nm_device_check_connection_available (candidate, NM_CONNECTION (master_connection), NM_DEVICE_CHECK_CON_AVAILABLE_FOR_USER_REQUEST, NULL)) continue; + found_device = TRUE; if (!nm_device_is_software (candidate)) { master_state = nm_device_get_state (candidate); if (nm_device_is_real (candidate) && master_state != NM_DEVICE_STATE_DISCONNECTED) @@ -3496,7 +3366,7 @@ find_slaves (NMManager *manager, s_con = nm_connection_get_setting_connection (NM_CONNECTION (connection)); g_return_val_if_fail (s_con, NULL); - devices = g_hash_table_new (nm_direct_hash, NULL); + devices = g_hash_table_new (g_direct_hash, g_direct_equal); /* Search through all connections, not only inactive ones, because * even if a slave was already active, it might be deactivated during @@ -3682,11 +3552,11 @@ _internal_activate_vpn (NMManager *self, NMActiveConnection *active, GError **er { nm_assert (NM_IS_VPN_CONNECTION (active)); - nm_dbus_object_export (NM_DBUS_OBJECT (active)); + nm_exported_object_export (NM_EXPORTED_OBJECT (active)); if (!nm_vpn_manager_activate_connection (NM_MANAGER_GET_PRIVATE (self)->vpn_manager, NM_VPN_CONNECTION (active), error)) { - nm_dbus_object_unexport (NM_DBUS_OBJECT (active)); + nm_exported_object_unexport (NM_EXPORTED_OBJECT (active)); return FALSE; } @@ -3781,6 +3651,7 @@ _internal_activate_device (NMManager *self, NMActiveConnection *active, GError * NMConnection *existing_connection = NULL; NMActiveConnection *master_ac = NULL; NMAuthSubject *subject; + char *error_desc = NULL; g_return_val_if_fail (NM_IS_MANAGER (self), FALSE); g_return_val_if_fail (NM_IS_ACTIVE_CONNECTION (active), FALSE); @@ -3788,14 +3659,14 @@ _internal_activate_device (NMManager *self, NMActiveConnection *active, GError * g_assert (NM_IS_VPN_CONNECTION (active) == FALSE); - device = nm_active_connection_get_device (active); - g_return_val_if_fail (device != NULL, FALSE); - connection = nm_active_connection_get_settings_connection (active); - nm_assert (connection); + g_assert (connection); applied = nm_active_connection_get_applied_connection (active); + device = nm_active_connection_get_device (active); + g_return_val_if_fail (device != NULL, FALSE); + /* If the device is active and its connection is not visible to the * user that's requesting this new activation, fail, since other users * should not be allowed to implicitly deactivate private connections @@ -3803,13 +3674,16 @@ _internal_activate_device (NMManager *self, NMActiveConnection *active, GError * */ existing_connection = nm_device_get_applied_connection (device); subject = nm_active_connection_get_subject (active); - if ( existing_connection - && !nm_auth_is_subject_in_acl_set_error (existing_connection, - subject, - NM_MANAGER_ERROR, - NM_MANAGER_ERROR_PERMISSION_DENIED, - error)) { - g_prefix_error (error, "Private connection already active on the device: "); + if (existing_connection && + !nm_auth_is_subject_in_acl (existing_connection, + subject, + &error_desc)) { + g_set_error (error, + NM_MANAGER_ERROR, + NM_MANAGER_ERROR_PERMISSION_DENIED, + "Private connection already active on the device: %s", + error_desc); + g_free (error_desc); return FALSE; } @@ -3821,9 +3695,6 @@ _internal_activate_device (NMManager *self, NMActiveConnection *active, GError * return FALSE; } - if (nm_active_connection_get_activation_type (active) == NM_ACTIVATION_TYPE_MANAGED) - nm_device_sys_iface_state_set (device, NM_DEVICE_SYS_IFACE_STATE_MANAGED); - /* Create any backing resources the device needs */ if (!nm_device_is_real (device)) { NMDevice *parent; @@ -3932,7 +3803,7 @@ _internal_activate_device (NMManager *self, NMActiveConnection *active, GError * _LOGD (LOGD_CORE, "Activation of '%s' depends on active connection %p %s", nm_settings_connection_get_id (connection), master_ac, - nm_dbus_object_get_path (NM_DBUS_OBJECT (master_ac)) ?: ""); + nm_exported_object_get_path (NM_EXPORTED_OBJECT (master_ac)) ?: ""); } /* Check slaves for master connection and possibly activate them */ @@ -4004,8 +3875,52 @@ _internal_activate_generic (NMManager *self, NMActiveConnection *active, GError } static NMActiveConnection * +_new_vpn_active_connection (NMManager *self, + NMSettingsConnection *settings_connection, + const char *specific_object, + NMAuthSubject *subject, + NMActivationReason activation_reason, + GError **error) +{ + NMManagerPrivate *priv = NM_MANAGER_GET_PRIVATE (self); + NMActiveConnection *parent = NULL; + NMDevice *device = NULL; + + g_return_val_if_fail (!settings_connection || NM_IS_SETTINGS_CONNECTION (settings_connection), NULL); + + if (specific_object) { + /* Find the specific connection the client requested we use */ + parent = active_connection_get_by_path (self, specific_object); + if (!parent) { + g_set_error_literal (error, NM_MANAGER_ERROR, NM_MANAGER_ERROR_CONNECTION_NOT_ACTIVE, + "Base connection for VPN connection not active."); + return NULL; + } + } else + parent = priv->primary_connection; + + if (!parent) { + g_set_error_literal (error, NM_MANAGER_ERROR, NM_MANAGER_ERROR_UNKNOWN_CONNECTION, + "Could not find source connection."); + return NULL; + } + + device = nm_active_connection_get_device (parent); + if (!device) { + g_set_error_literal (error, NM_MANAGER_ERROR, NM_MANAGER_ERROR_UNKNOWN_DEVICE, + "Source connection had no active device."); + return NULL; + } + + return (NMActiveConnection *) nm_vpn_connection_new (settings_connection, + device, + nm_exported_object_get_path (NM_EXPORTED_OBJECT (parent)), + activation_reason, + subject); +} + +static NMActiveConnection * _new_active_connection (NMManager *self, - gboolean is_vpn, NMConnection *connection, NMConnection *applied, const char *specific_object, @@ -4015,78 +3930,45 @@ _new_active_connection (NMManager *self, NMActivationReason activation_reason, GError **error) { - NMManagerPrivate *priv = NM_MANAGER_GET_PRIVATE (self); NMSettingsConnection *settings_connection = NULL; - NMDevice *parent_device; + NMActiveConnection *existing_ac; + gboolean is_vpn; g_return_val_if_fail (NM_IS_CONNECTION (connection), NULL); g_return_val_if_fail (NM_IS_AUTH_SUBJECT (subject), NULL); - nm_assert (is_vpn == _connection_is_vpn (connection)); - nm_assert (is_vpn || NM_IS_DEVICE (device)); - nm_assert (!nm_streq0 (specific_object, "/")); + /* Can't create new AC for already-active connection */ + existing_ac = active_connection_find_first_by_connection (self, connection); + if (NM_IS_VPN_CONNECTION (existing_ac)) { + g_set_error (error, NM_MANAGER_ERROR, NM_MANAGER_ERROR_CONNECTION_ALREADY_ACTIVE, + "Connection '%s' is already active", + nm_connection_get_id (connection)); + return NULL; + } + + /* Normalize the specific object */ + if (specific_object && g_strcmp0 (specific_object, "/") == 0) + specific_object = NULL; + + is_vpn = nm_connection_is_type (NM_CONNECTION (connection), NM_SETTING_VPN_SETTING_NAME); if (NM_IS_SETTINGS_CONNECTION (connection)) settings_connection = (NMSettingsConnection *) connection; if (is_vpn) { - NMActiveConnection *parent; - - /* FIXME: for VPN connections, we don't allow re-activating an - * already active connection. It's a bug, and should be fixed together - * when reworking VPN handling. */ - if (active_connection_find_first_by_connection (self, connection)) { - g_set_error (error, NM_MANAGER_ERROR, NM_MANAGER_ERROR_CONNECTION_ALREADY_ACTIVE, - "Connection '%s' is already active", - nm_connection_get_id (connection)); - return NULL; - } - - /* FIXME: apparently, activation here only works if @connection is - * a settings-connection. Which is not the case during AddAndActivatate. - * Probably, AddAndActivate is broken for VPN. */ if (activation_type != NM_ACTIVATION_TYPE_MANAGED) g_return_val_if_reached (NULL); - - g_return_val_if_fail (!settings_connection || NM_IS_SETTINGS_CONNECTION (settings_connection), NULL); - - if (specific_object) { - /* Find the specific connection the client requested we use */ - parent = active_connection_get_by_path (self, specific_object); - if (!parent) { - g_set_error_literal (error, NM_MANAGER_ERROR, NM_MANAGER_ERROR_CONNECTION_NOT_ACTIVE, - "Base connection for VPN connection not active."); - return NULL; - } - } else - parent = priv->primary_connection; - - if (!parent) { - g_set_error_literal (error, NM_MANAGER_ERROR, NM_MANAGER_ERROR_UNKNOWN_CONNECTION, - "Could not find source connection."); - return NULL; - } - - parent_device = nm_active_connection_get_device (parent); - if (!parent_device) { - g_set_error_literal (error, NM_MANAGER_ERROR, NM_MANAGER_ERROR_UNKNOWN_DEVICE, - "Source connection had no active device"); - return NULL; - } - - if (device && device != parent_device) { - g_set_error_literal (error, NM_MANAGER_ERROR, NM_MANAGER_ERROR_UNKNOWN_DEVICE, - "The device doesn't match the active connection."); - return NULL; - } - - return (NMActiveConnection *) nm_vpn_connection_new (settings_connection, - parent_device, - nm_dbus_object_get_path (NM_DBUS_OBJECT (parent)), - activation_reason, - subject); + return _new_vpn_active_connection (self, + settings_connection, + specific_object, + subject, + activation_reason, + error); } + if (device && (activation_type == NM_ACTIVATION_TYPE_MANAGED)) + nm_device_sys_iface_state_set (device, NM_DEVICE_SYS_IFACE_STATE_MANAGED); + return (NMActiveConnection *) nm_act_request_new (settings_connection, applied, specific_object, @@ -4111,16 +3993,14 @@ _internal_activation_auth_done (NMActiveConnection *active, priv->authorizing_connections = g_slist_remove (priv->authorizing_connections, active); - if (!success) - goto fail; - /* Don't continue with an internal activation if an equivalent active * connection already exists. Note that slave autoconnections always force a * reconnection. We also check this earlier, but there we may fail to * detect a duplicate if the existing active connection is undergoing * authorization in impl_manager_activate_connection(). */ - if ( nm_auth_subject_is_internal (nm_active_connection_get_subject (active)) + if ( success + && nm_auth_subject_is_internal (nm_active_connection_get_subject (active)) && nm_active_connection_get_activation_reason (active) != NM_ACTIVATION_REASON_AUTOCONNECT_SLAVES) { c_list_for_each_entry (ac, &priv->active_connections_lst_head, active_connections_lst) { if ( nm_active_connection_get_device (ac) == nm_active_connection_get_device (active) @@ -4133,15 +4013,17 @@ _internal_activation_auth_done (NMActiveConnection *active, NM_MANAGER_ERROR_CONNECTION_ALREADY_ACTIVE, "Connection '%s' is already active", nm_active_connection_get_settings_connection_id (active)); - goto fail; + success = FALSE; + break; } } } - if (_internal_activate_generic (self, active, &error)) - return; + if (success) { + if (_internal_activate_generic (self, active, &error)) + return; + } -fail: nm_assert (error_desc || error); nm_active_connection_set_state_fail (active, NM_ACTIVE_CONNECTION_STATE_REASON_UNKNOWN, @@ -4182,24 +4064,27 @@ nm_manager_activate_connection (NMManager *self, NMActivationReason activation_reason, GError **error) { - NMManagerPrivate *priv; + NMManagerPrivate *priv = NM_MANAGER_GET_PRIVATE (self); NMActiveConnection *active; + char *error_desc = NULL; GSList *iter; - g_return_val_if_fail (NM_IS_MANAGER (self), NULL); - g_return_val_if_fail (NM_IS_SETTINGS_CONNECTION (connection), NULL); - g_return_val_if_fail (NM_IS_DEVICE (device), NULL); - g_return_val_if_fail (!error || !*error, NULL); - nm_assert (!nm_streq0 (specific_object, "/")); - - priv = NM_MANAGER_GET_PRIVATE (self); + g_return_val_if_fail (self != NULL, NULL); + g_return_val_if_fail (connection != NULL, NULL); + g_return_val_if_fail (error != NULL, NULL); + g_return_val_if_fail (*error == NULL, NULL); - if (!nm_auth_is_subject_in_acl_set_error (NM_CONNECTION (connection), - subject, - NM_MANAGER_ERROR, - NM_MANAGER_ERROR_PERMISSION_DENIED, - error)) + /* Ensure the subject has permissions for this connection */ + if (!nm_auth_is_subject_in_acl (NM_CONNECTION (connection), + subject, + &error_desc)) { + g_set_error_literal (error, + NM_MANAGER_ERROR, + NM_MANAGER_ERROR_PERMISSION_DENIED, + error_desc); + g_free (error_desc); return NULL; + } /* Look for a active connection that's equivalent and is already pending authorization * and eventual activation. This is used to de-duplicate concurrent activations which would @@ -4210,7 +4095,7 @@ nm_manager_activate_connection (NMManager *self, active = iter->data; if ( connection == nm_active_connection_get_settings_connection (active) - && nm_streq0 (nm_active_connection_get_specific_object (active), specific_object) + && g_strcmp0 (nm_active_connection_get_specific_object (active), specific_object) == 0 && nm_active_connection_get_device (active) == device && nm_auth_subject_is_internal (nm_active_connection_get_subject (active)) && nm_auth_subject_is_internal (subject) @@ -4219,7 +4104,6 @@ nm_manager_activate_connection (NMManager *self, } active = _new_active_connection (self, - _connection_is_vpn (NM_CONNECTION (connection)), NM_CONNECTION (connection), applied, specific_object, @@ -4228,11 +4112,10 @@ nm_manager_activate_connection (NMManager *self, activation_type, activation_reason, error); - if (!active) - return NULL; - - priv->authorizing_connections = g_slist_prepend (priv->authorizing_connections, active); - nm_active_connection_authorize (active, NULL, _internal_activation_auth_done, self, NULL); + if (active) { + priv->authorizing_connections = g_slist_prepend (priv->authorizing_connections, active); + nm_active_connection_authorize (active, NULL, _internal_activation_auth_done, self, NULL); + } return active; } @@ -4241,12 +4124,9 @@ nm_manager_activate_connection (NMManager *self, * @self: the #NMManager * @context: the D-Bus context of the requestor * @connection: the partial or complete #NMConnection to be activated - * @device_path: the object path of the device to be activated, or NULL + * @device_path: the object path of the device to be activated, or "/" * @out_device: on successful reutrn, the #NMDevice to be activated with @connection - * The caller may pass in a device which shortcuts the lookup by path. - * In this case, the passed in device must have the matching @device_path - * already. - * @out_is_vpn: on successful return, %TRUE if @connection is a VPN connection + * @out_vpn: on successful return, %TRUE if @connection is a VPN connection * @error: location to store an error on failure * * Performs basic validation on an activation request, including ensuring that @@ -4262,16 +4142,17 @@ validate_activation_request (NMManager *self, NMConnection *connection, const char *device_path, NMDevice **out_device, - gboolean *out_is_vpn, + gboolean *out_vpn, GError **error) { NMDevice *device = NULL; - gboolean is_vpn = FALSE; - gs_unref_object NMAuthSubject *subject = NULL; + gboolean vpn = FALSE; + NMAuthSubject *subject = NULL; + char *error_desc = NULL; - nm_assert (NM_IS_CONNECTION (connection)); - nm_assert (out_device); - nm_assert (out_is_vpn); + g_assert (connection); + g_assert (out_device); + g_assert (out_vpn); /* Validate the caller */ subject = nm_auth_subject_new_unix_process_from_context (context); @@ -4283,80 +4164,76 @@ validate_activation_request (NMManager *self, return NULL; } - if (!nm_auth_is_subject_in_acl_set_error (connection, - subject, - NM_MANAGER_ERROR, - NM_MANAGER_ERROR_PERMISSION_DENIED, - error)) - return NULL; + /* Ensure the subject has permissions for this connection */ + if (!nm_auth_is_subject_in_acl (connection, + subject, + &error_desc)) { + g_set_error_literal (error, + NM_MANAGER_ERROR, + NM_MANAGER_ERROR_PERMISSION_DENIED, + error_desc); + g_free (error_desc); + goto error; + } + + /* Check whether it's a VPN or not */ + if ( nm_connection_get_setting_vpn (connection) + || nm_connection_is_type (connection, NM_SETTING_VPN_SETTING_NAME)) + vpn = TRUE; - is_vpn = _connection_is_vpn (connection); + /* Normalize device path */ + if (device_path && g_strcmp0 (device_path, "/") == 0) + device_path = NULL; - if (*out_device) { - device = *out_device; - nm_assert (NM_IS_DEVICE (device)); - nm_assert (device_path); - nm_assert (nm_streq0 (device_path, nm_dbus_object_get_path (NM_DBUS_OBJECT (device)))); - nm_assert (device == nm_manager_get_device_by_path (self, device_path)); - } else if (device_path) { + /* And validate it */ + if (device_path) { device = nm_manager_get_device_by_path (self, device_path); if (!device) { g_set_error_literal (error, NM_MANAGER_ERROR, NM_MANAGER_ERROR_UNKNOWN_DEVICE, "Device not found"); - return NULL; + goto error; } - } else if (!is_vpn) { + } else device = nm_manager_get_best_device_for_connection (self, connection, TRUE, NULL); - if (!device) { - gs_free char *iface = NULL; - - /* VPN and software-device connections don't need a device yet, - * but non-virtual connections do ... */ - if (!nm_connection_is_virtual (connection)) { - g_set_error_literal (error, - NM_MANAGER_ERROR, - NM_MANAGER_ERROR_UNKNOWN_DEVICE, - "No suitable device found for this connection."); - return NULL; - } - /* Look for an existing device with the connection's interface name */ - iface = nm_manager_get_connection_iface (self, connection, NULL, error); - if (!iface) - return NULL; + if (!device && !vpn) { + gs_free char *iface = NULL; - device = find_device_by_iface (self, iface, connection, NULL); - if (!device) { - g_set_error_literal (error, - NM_MANAGER_ERROR, - NM_MANAGER_ERROR_UNKNOWN_DEVICE, - "Failed to find a compatible device for this connection"); - return NULL; - } + /* VPN and software-device connections don't need a device yet, + * but non-virtual connections do ... */ + if (!nm_connection_is_virtual (connection)) { + g_set_error_literal (error, + NM_MANAGER_ERROR, + NM_MANAGER_ERROR_UNKNOWN_DEVICE, + "No suitable device found for this connection."); + goto error; } + + /* Look for an existing device with the connection's interface name */ + iface = nm_manager_get_connection_iface (self, connection, NULL, error); + if (!iface) + goto error; + + device = find_device_by_iface (self, iface, connection, NULL); } - if (is_vpn && device) { - /* VPN's are treated specially. Maybe the should accept a device as well, - * however, later on during activation, we don't handle the device. - * - * Maybe we should, and maybe it makes sense to specify a device - * when activating a VPN. But for now, just error out. */ + if ((!vpn || device_path) && !device) { g_set_error_literal (error, NM_MANAGER_ERROR, NM_MANAGER_ERROR_UNKNOWN_DEVICE, - "Cannot specify device when activating VPN"); - return NULL; + "Failed to find a compatible device for this connection"); + goto error; } - nm_assert ( ( is_vpn && !device) - || (!is_vpn && NM_IS_DEVICE (device))); - *out_device = device; - *out_is_vpn = is_vpn; - return g_steal_pointer (&subject); + *out_vpn = vpn; + return subject; + +error: + g_object_unref (subject); + return NULL; } /*****************************************************************************/ @@ -4378,27 +4255,24 @@ _activation_auth_done (NMActiveConnection *active, subject = nm_active_connection_get_subject (active); connection = nm_active_connection_get_settings_connection (active); - if (!success) { + if (success) { + if (_internal_activate_generic (self, active, &error)) { + nm_settings_connection_autoconnect_blocked_reason_set (connection, + NM_SETTINGS_AUTO_CONNECT_BLOCKED_REASON_USER_REQUEST, + FALSE); + g_dbus_method_invocation_return_value (context, + g_variant_new ("(o)", + nm_exported_object_get_path (NM_EXPORTED_OBJECT (active)))); + nm_audit_log_connection_op (NM_AUDIT_OP_CONN_ACTIVATE, connection, TRUE, NULL, + subject, NULL); + return; + } + } else { error = g_error_new_literal (NM_MANAGER_ERROR, NM_MANAGER_ERROR_PERMISSION_DENIED, error_desc); - goto fail; } - if (!_internal_activate_generic (self, active, &error)) - goto fail; - - nm_settings_connection_autoconnect_blocked_reason_set (connection, - NM_SETTINGS_AUTO_CONNECT_BLOCKED_REASON_USER_REQUEST, - FALSE); - g_dbus_method_invocation_return_value (context, - g_variant_new ("(o)", - nm_dbus_object_get_path (NM_DBUS_OBJECT (active)))); - nm_audit_log_connection_op (NM_AUDIT_OP_CONN_ACTIVATE, connection, TRUE, NULL, - subject, NULL); - return; - -fail: nm_audit_log_connection_op (NM_AUDIT_OP_CONN_ACTIVATE, connection, FALSE, NULL, subject, error->message); nm_active_connection_set_state_fail (active, @@ -4409,15 +4283,12 @@ fail: } static void -impl_manager_activate_connection (NMDBusObject *obj, - const NMDBusInterfaceInfoExtended *interface_info, - const NMDBusMethodInfoExtended *method_info, - GDBusConnection *dbus_connection, - const char *sender, - GDBusMethodInvocation *invocation, - GVariant *parameters) -{ - NMManager *self = NM_MANAGER (obj); +impl_manager_activate_connection (NMManager *self, + GDBusMethodInvocation *context, + const char *connection_path, + const char *device_path, + const char *specific_object_path) +{ NMManagerPrivate *priv = NM_MANAGER_GET_PRIVATE (self); gs_unref_object NMActiveConnection *active = NULL; gs_unref_object NMAuthSubject *subject = NULL; @@ -4425,15 +4296,14 @@ impl_manager_activate_connection (NMDBusObject *obj, NMDevice *device = NULL; gboolean is_vpn = FALSE; GError *error = NULL; - const char *connection_path; - const char *device_path; - const char *specific_object_path; - g_variant_get (parameters, "(&o&o&o)", &connection_path, &device_path, &specific_object_path); - - connection_path = nm_utils_dbus_normalize_object_path (connection_path); - specific_object_path = nm_utils_dbus_normalize_object_path (specific_object_path); - device_path = nm_utils_dbus_normalize_object_path (device_path); + /* Normalize object paths */ + if (g_strcmp0 (connection_path, "/") == 0) + connection_path = NULL; + if (g_strcmp0 (specific_object_path, "/") == 0) + specific_object_path = NULL; + if (g_strcmp0 (device_path, "/") == 0) + device_path = NULL; /* If the connection path is given and valid, that connection is activated. * Otherwise the "best" connection for the device is chosen and activated, @@ -4468,7 +4338,7 @@ impl_manager_activate_connection (NMDBusObject *obj, } subject = validate_activation_request (self, - invocation, + context, NM_CONNECTION (connection), device_path, &device, @@ -4478,7 +4348,6 @@ impl_manager_activate_connection (NMDBusObject *obj, goto error; active = _new_active_connection (self, - is_vpn, NM_CONNECTION (connection), NULL, specific_object_path, @@ -4497,7 +4366,7 @@ impl_manager_activate_connection (NMDBusObject *obj, NULL, _activation_auth_done, self, - invocation); + context); return; error: @@ -4505,7 +4374,7 @@ error: nm_audit_log_connection_op (NM_AUDIT_OP_CONN_ACTIVATE, connection, FALSE, NULL, subject, error->message); } - g_dbus_method_invocation_take_error (invocation, error); + g_dbus_method_invocation_take_error (context, error); } /*****************************************************************************/ @@ -4526,7 +4395,7 @@ activation_add_done (NMSettings *settings, AddAndActivateInfo *info = user_data; NMManager *self; gs_unref_object NMActiveConnection *active = NULL; - gs_free_error GError *local = NULL; + GError *local = NULL; self = info->manager; active = info->active; @@ -4545,8 +4414,8 @@ activation_add_done (NMSettings *settings, g_dbus_method_invocation_return_value ( context, g_variant_new ("(oo)", - nm_dbus_object_get_path (NM_DBUS_OBJECT (new_connection)), - nm_dbus_object_get_path (NM_DBUS_OBJECT (active)))); + nm_connection_get_path (NM_CONNECTION (new_connection)), + nm_exported_object_get_path (NM_EXPORTED_OBJECT (active)))); nm_audit_log_connection_op (NM_AUDIT_OP_CONN_ADD_ACTIVATE, nm_active_connection_get_settings_connection (active), TRUE, @@ -4559,7 +4428,6 @@ activation_add_done (NMSettings *settings, } nm_assert (error); - nm_active_connection_set_state_fail (active, NM_ACTIVE_CONNECTION_STATE_REASON_UNKNOWN, error->message); @@ -4572,6 +4440,7 @@ activation_add_done (NMSettings *settings, NULL, nm_active_connection_get_subject (active), error->message); + g_clear_error (&local); } static void @@ -4586,12 +4455,27 @@ _add_and_activate_auth_done (NMActiveConnection *active, GDBusMethodInvocation *context = user_data2; AddAndActivateInfo *info; GError *error = NULL; - gs_unref_object NMConnection *connection = NULL; - connection = g_object_steal_qdata (G_OBJECT (active), - active_connection_add_and_activate_quark ()); + if (success) { + NMConnection *connection; + + connection = g_object_steal_qdata (G_OBJECT (active), + active_connection_add_and_activate_quark ()); + + info = g_slice_new (AddAndActivateInfo); + info->manager = self; + info->active = g_object_ref (active); - if (!success) { + /* Basic sender auth checks performed; try to add the connection */ + nm_settings_add_connection_dbus (priv->settings, + connection, + FALSE, + context, + activation_add_done, + info); + g_object_unref (connection); + } else { + g_assert (error_desc); error = g_error_new_literal (NM_MANAGER_ERROR, NM_MANAGER_ERROR_PERMISSION_DENIED, error_desc); @@ -4602,50 +4486,32 @@ _add_and_activate_auth_done (NMActiveConnection *active, nm_active_connection_get_subject (active), error->message); g_dbus_method_invocation_take_error (context, error); - g_object_unref (active); - return; } - info = g_slice_new (AddAndActivateInfo); - info->manager = self; - - /* we pass on the reference to @active. */ - info->active = active; - - /* Basic sender auth checks performed; try to add the connection */ - nm_settings_add_connection_dbus (priv->settings, - connection, - FALSE, - context, - activation_add_done, - info); + g_object_unref (active); } static void -impl_manager_add_and_activate_connection (NMDBusObject *obj, - const NMDBusInterfaceInfoExtended *interface_info, - const NMDBusMethodInfoExtended *method_info, - GDBusConnection *dbus_connection, - const char *sender, - GDBusMethodInvocation *invocation, - GVariant *parameters) -{ - NMManager *self = NM_MANAGER (obj); +impl_manager_add_and_activate_connection (NMManager *self, + GDBusMethodInvocation *context, + GVariant *settings, + const char *device_path, + const char *specific_object_path) +{ NMManagerPrivate *priv = NM_MANAGER_GET_PRIVATE (self); - gs_unref_object NMConnection *connection = NULL; + NMConnection *connection = NULL; + GSList *all_connections = NULL; NMActiveConnection *active = NULL; - gs_unref_object NMAuthSubject *subject = NULL; + NMAuthSubject *subject = NULL; GError *error = NULL; NMDevice *device = NULL; - gboolean is_vpn = FALSE; - gs_unref_variant GVariant *settings = NULL; - const char *device_path; - const char *specific_object_path; + gboolean vpn = FALSE; - g_variant_get (parameters, "(@a{sa{sv}}&o&o)", &settings, &device_path, &specific_object_path); - - specific_object_path = nm_utils_dbus_normalize_object_path (specific_object_path); - device_path = nm_utils_dbus_normalize_object_path (device_path); + /* Normalize object paths */ + if (g_strcmp0 (specific_object_path, "/") == 0) + specific_object_path = NULL; + if (g_strcmp0 (device_path, "/") == 0) + device_path = NULL; /* Try to create a new connection with the given settings. * We allow empty settings for AddAndActivateConnection(). In that case, @@ -4659,16 +4525,29 @@ impl_manager_add_and_activate_connection (NMDBusObject *obj, _nm_connection_replace_settings (connection, settings, NM_SETTING_PARSE_FLAGS_STRICT, NULL); subject = validate_activation_request (self, - invocation, + context, connection, device_path, &device, - &is_vpn, + &vpn, &error); if (!subject) goto error; - if (is_vpn) { + { + gs_free NMSettingsConnection **connections = NULL; + guint i, len; + + connections = nm_settings_get_connections_clone (priv->settings, &len, + NULL, NULL, + nm_settings_connection_cmp_autoconnect_priority_p_with_data, NULL); + all_connections = NULL; + for (i = len; i > 0; ) { + i--; + all_connections = g_slist_prepend (all_connections, connections[i]); + } + } + if (vpn) { /* Try to fill the VPN's connection setting and name at least */ if (!nm_connection_get_setting_vpn (connection)) { error = g_error_new_literal (NM_CONNECTION_ERROR, @@ -4681,7 +4560,7 @@ impl_manager_add_and_activate_connection (NMDBusObject *obj, nm_utils_complete_generic (priv->platform, connection, NM_SETTING_VPN_SETTING_NAME, - (NMConnection *const*) nm_settings_get_connections (priv->settings, NULL), + all_connections, NULL, _("VPN connection"), NULL, @@ -4691,13 +4570,14 @@ impl_manager_add_and_activate_connection (NMDBusObject *obj, if (!nm_device_complete_connection (device, connection, specific_object_path, - (NMConnection *const*) nm_settings_get_connections (priv->settings, NULL), + all_connections, &error)) goto error; } + g_slist_free (all_connections); + all_connections = NULL; active = _new_active_connection (self, - is_vpn, connection, NULL, specific_object_path, @@ -4709,26 +4589,24 @@ impl_manager_add_and_activate_connection (NMDBusObject *obj, if (!active) goto error; - /* FIXME: nm_active_connection_authorize() already has two user-data pointers - * to piggyback additional data. Instead of attaching the third argument to - * @active's user-data, add a third paramter. - * Or alternatively, allocate a data structure to pass on additional data. - * Then we don't need two user-data pointers. */ g_object_set_qdata_full (G_OBJECT (active), active_connection_add_and_activate_quark (), connection, g_object_unref); - nm_active_connection_authorize (active, connection, _add_and_activate_auth_done, self, invocation); - - /* we passed the pointers on to the callback of authorize. */ - g_steal_pointer (&connection); - g_steal_pointer (&active); + nm_active_connection_authorize (active, connection, _add_and_activate_auth_done, self, context); + g_object_unref (subject); return; error: nm_audit_log_connection_op (NM_AUDIT_OP_CONN_ADD_ACTIVATE, NULL, FALSE, NULL, subject, error->message); - g_dbus_method_invocation_take_error (invocation, error); + g_clear_object (&connection); + g_slist_free (all_connections); + g_clear_object (&subject); + g_clear_object (&active); + + g_assert (error); + g_dbus_method_invocation_take_error (context, error); } /*****************************************************************************/ @@ -4824,28 +4702,21 @@ deactivate_net_auth_done_cb (NMAuthChain *chain, else g_dbus_method_invocation_return_value (context, NULL); - nm_auth_chain_destroy (chain); + nm_auth_chain_unref (chain); } static void -impl_manager_deactivate_connection (NMDBusObject *obj, - const NMDBusInterfaceInfoExtended *interface_info, - const NMDBusMethodInfoExtended *method_info, - GDBusConnection *dbus_connection, - const char *sender, - GDBusMethodInvocation *invocation, - GVariant *parameters) -{ - NMManager *self = NM_MANAGER (obj); +impl_manager_deactivate_connection (NMManager *self, + GDBusMethodInvocation *context, + const char *active_path) +{ NMManagerPrivate *priv = NM_MANAGER_GET_PRIVATE (self); NMActiveConnection *ac; NMSettingsConnection *connection = NULL; GError *error = NULL; NMAuthSubject *subject = NULL; NMAuthChain *chain; - const char *active_path; - - g_variant_get (parameters, "(&o)", &active_path); + char *error_desc = NULL; /* Find the connection by its object path */ ac = active_connection_get_by_path (self, active_path); @@ -4860,7 +4731,7 @@ impl_manager_deactivate_connection (NMDBusObject *obj, } /* Validate the caller */ - subject = nm_auth_subject_new_unix_process_from_context (invocation); + subject = nm_auth_subject_new_unix_process_from_context (context); if (!subject) { error = g_error_new_literal (NM_MANAGER_ERROR, NM_MANAGER_ERROR_PERMISSION_DENIED, @@ -4868,15 +4739,19 @@ impl_manager_deactivate_connection (NMDBusObject *obj, goto done; } - if (!nm_auth_is_subject_in_acl_set_error (NM_CONNECTION (connection), - subject, - NM_MANAGER_ERROR, - NM_MANAGER_ERROR_PERMISSION_DENIED, - &error)) + /* Ensure the subject has permissions for this connection */ + if (!nm_auth_is_subject_in_acl (NM_CONNECTION (connection), + subject, + &error_desc)) { + error = g_error_new_literal (NM_MANAGER_ERROR, + NM_MANAGER_ERROR_PERMISSION_DENIED, + error_desc); + g_free (error_desc); goto done; + } /* Validate the user request */ - chain = nm_auth_chain_new_subject (subject, invocation, deactivate_net_auth_done_cb, self); + chain = nm_auth_chain_new_subject (subject, context, deactivate_net_auth_done_cb, self); if (!chain) { error = g_error_new_literal (NM_MANAGER_ERROR, NM_MANAGER_ERROR_PERMISSION_DENIED, @@ -4894,7 +4769,7 @@ done: nm_audit_log_connection_op (NM_AUDIT_OP_CONN_DEACTIVATE, connection, FALSE, NULL, subject, error->message); } - g_dbus_method_invocation_take_error (invocation, error); + g_dbus_method_invocation_take_error (context, error); } g_clear_object (&subject); } @@ -5002,7 +4877,7 @@ do_sleep_wake (NMManager *self, gboolean sleeping_changed) { NMManagerPrivate *priv = NM_MANAGER_GET_PRIVATE (self); gboolean suspending, waking_from_suspend; - NMDevice *device; + GSList *iter; suspending = sleeping_changed && priv->sleeping; waking_from_suspend = sleeping_changed && !priv->sleeping; @@ -5013,7 +4888,9 @@ do_sleep_wake (NMManager *self, gboolean sleeping_changed) /* FIXME: are there still hardware devices that need to be disabled around * suspend/resume? */ - c_list_for_each_entry (device, &priv->devices_lst_head, devices_lst) { + for (iter = priv->devices; iter; iter = iter->next) { + NMDevice *device = iter->data; + /* FIXME: shouldn't we be unmanaging software devices if !suspending? */ if (nm_device_is_software (device)) continue; @@ -5041,7 +4918,9 @@ do_sleep_wake (NMManager *self, gboolean sleeping_changed) if (waking_from_suspend) { sleep_devices_clear (self); - c_list_for_each_entry (device, &priv->devices_lst_head, devices_lst) { + for (iter = priv->devices; iter; iter = iter->next) { + NMDevice *device = iter->data; + if (nm_device_is_software (device)) continue; @@ -5068,7 +4947,8 @@ do_sleep_wake (NMManager *self, gboolean sleeping_changed) nm_manager_rfkill_update (self, RFKILL_TYPE_UNKNOWN); /* Re-manage managed devices */ - c_list_for_each_entry (device, &priv->devices_lst_head, devices_lst) { + for (iter = priv->devices; iter; iter = iter->next) { + NMDevice *device = NM_DEVICE (iter->data); guint i; if (nm_device_is_software (device)) { @@ -5161,28 +5041,27 @@ sleep_auth_done_cb (NMAuthChain *chain, g_dbus_method_invocation_return_value (context, NULL); } - nm_auth_chain_destroy (chain); + nm_auth_chain_unref (chain); } #endif static void -impl_manager_sleep (NMDBusObject *obj, - const NMDBusInterfaceInfoExtended *interface_info, - const NMDBusMethodInfoExtended *method_info, - GDBusConnection *connection, - const char *sender, - GDBusMethodInvocation *invocation, - GVariant *parameters) -{ - NMManager *self = NM_MANAGER (obj); - NMManagerPrivate *priv = NM_MANAGER_GET_PRIVATE (self); +impl_manager_sleep (NMManager *self, + GDBusMethodInvocation *context, + gboolean do_sleep) +{ + NMManagerPrivate *priv; GError *error = NULL; gs_unref_object NMAuthSubject *subject = NULL; - gboolean do_sleep; +#if 0 + NMAuthChain *chain; + const char *error_desc = NULL; +#endif - g_variant_get (parameters, "(b)", &do_sleep); + g_return_if_fail (NM_IS_MANAGER (self)); - subject = nm_auth_subject_new_unix_process_from_context (invocation); + priv = NM_MANAGER_GET_PRIVATE (self); + subject = nm_auth_subject_new_unix_process_from_context (context); if (priv->sleeping == do_sleep) { error = g_error_new (NM_MANAGER_ERROR, @@ -5190,7 +5069,7 @@ impl_manager_sleep (NMDBusObject *obj, "Already %s", do_sleep ? "asleep" : "awake"); nm_audit_log_control_op (NM_AUDIT_OP_SLEEP_CONTROL, do_sleep ? "on" : "off", FALSE, subject, error->message); - g_dbus_method_invocation_take_error (invocation, error); + g_dbus_method_invocation_take_error (context, error); return; } @@ -5204,8 +5083,22 @@ impl_manager_sleep (NMDBusObject *obj, */ _internal_sleep (self, do_sleep); nm_audit_log_control_op (NM_AUDIT_OP_SLEEP_CONTROL, do_sleep ? "on" : "off", TRUE, subject, NULL); - g_dbus_method_invocation_return_value (invocation, NULL); + g_dbus_method_invocation_return_value (context, NULL); return; + +#if 0 + chain = nm_auth_chain_new (context, sleep_auth_done_cb, self, &error_desc); + if (chain) { + priv->auth_chains = g_slist_append (priv->auth_chains, chain); + nm_auth_chain_set_data (chain, "sleep", GUINT_TO_POINTER (do_sleep), NULL); + nm_auth_chain_add_call (chain, NM_AUTH_PERMISSION_SLEEP_WAKE, TRUE); + } else { + error = g_error_new_literal (NM_MANAGER_ERROR, + NM_MANAGER_ERROR_PERMISSION_DENIED, + error_desc); + g_dbus_method_invocation_take_error (context, error); + } +#endif } static void @@ -5281,25 +5174,21 @@ enable_net_done_cb (NMAuthChain *chain, g_dbus_method_invocation_take_error (context, ret_error); } - nm_auth_chain_destroy (chain); + nm_auth_chain_unref (chain); } static void -impl_manager_enable (NMDBusObject *obj, - const NMDBusInterfaceInfoExtended *interface_info, - const NMDBusMethodInfoExtended *method_info, - GDBusConnection *connection, - const char *sender, - GDBusMethodInvocation *invocation, - GVariant *parameters) -{ - NMManager *self = NM_MANAGER (obj); - NMManagerPrivate *priv = NM_MANAGER_GET_PRIVATE (self); +impl_manager_enable (NMManager *self, + GDBusMethodInvocation *context, + gboolean enable) +{ + NMManagerPrivate *priv; NMAuthChain *chain; GError *error = NULL; - gboolean enable; - g_variant_get (parameters, "(b)", &enable); + g_return_if_fail (NM_IS_MANAGER (self)); + + priv = NM_MANAGER_GET_PRIVATE (self); if (priv->net_enabled == enable) { error = g_error_new (NM_MANAGER_ERROR, @@ -5308,7 +5197,7 @@ impl_manager_enable (NMDBusObject *obj, goto done; } - chain = nm_auth_chain_new_context (invocation, enable_net_done_cb, self); + chain = nm_auth_chain_new_context (context, enable_net_done_cb, self); if (!chain) { error = g_error_new_literal (NM_MANAGER_ERROR, NM_MANAGER_ERROR_PERMISSION_DENIED, @@ -5322,7 +5211,7 @@ impl_manager_enable (NMDBusObject *obj, done: if (error) - g_dbus_method_invocation_take_error (invocation, error); + g_dbus_method_invocation_take_error (context, error); } /* Permissions */ @@ -5389,28 +5278,23 @@ get_permissions_done_cb (NMAuthChain *chain, g_variant_new ("(a{ss})", &results)); } - nm_auth_chain_destroy (chain); + nm_auth_chain_unref (chain); } static void -impl_manager_get_permissions (NMDBusObject *obj, - const NMDBusInterfaceInfoExtended *interface_info, - const NMDBusMethodInfoExtended *method_info, - GDBusConnection *connection, - const char *sender, - GDBusMethodInvocation *invocation, - GVariant *parameters) -{ - NMManager *self = NM_MANAGER (obj); +impl_manager_get_permissions (NMManager *self, + GDBusMethodInvocation *context) +{ NMManagerPrivate *priv = NM_MANAGER_GET_PRIVATE (self); NMAuthChain *chain; + GError *error = NULL; - chain = nm_auth_chain_new_context (invocation, get_permissions_done_cb, self); + chain = nm_auth_chain_new_context (context, get_permissions_done_cb, self); if (!chain) { - g_dbus_method_invocation_return_error_literal (invocation, - NM_MANAGER_ERROR, - NM_MANAGER_ERROR_PERMISSION_DENIED, - "Unable to authenticate request."); + error = g_error_new_literal (NM_MANAGER_ERROR, + NM_MANAGER_ERROR_PERMISSION_DENIED, + "Unable to authenticate request."); + g_dbus_method_invocation_take_error (context, error); return; } @@ -5434,123 +5318,83 @@ impl_manager_get_permissions (NMDBusObject *obj, } static void -impl_manager_state (NMDBusObject *obj, - const NMDBusInterfaceInfoExtended *interface_info, - const NMDBusMethodInfoExtended *method_info, - GDBusConnection *connection, - const char *sender, - GDBusMethodInvocation *invocation, - GVariant *parameters) +impl_manager_get_state (NMManager *self, + GDBusMethodInvocation *context) { - NMManager *self = NM_MANAGER (obj); - nm_manager_update_state (self); - g_dbus_method_invocation_return_value (invocation, + g_dbus_method_invocation_return_value (context, g_variant_new ("(u)", NM_MANAGER_GET_PRIVATE (self)->state)); } static void -impl_manager_set_logging (NMDBusObject *obj, - const NMDBusInterfaceInfoExtended *interface_info, - const NMDBusMethodInfoExtended *method_info, - GDBusConnection *connection, - const char *sender, - GDBusMethodInvocation *invocation, - GVariant *parameters) -{ - NMManager *self = NM_MANAGER (obj); +impl_manager_set_logging (NMManager *self, + GDBusMethodInvocation *context, + const char *level, + const char *domains) +{ GError *error = NULL; - const char *level; - const char *domains; /* The permission is already enforced by the D-Bus daemon, but we ensure * that the caller is still alive so that clients are forced to wait and * we'll be able to switch to polkit without breaking behavior. */ - if (!nm_dbus_manager_ensure_uid (nm_dbus_object_get_manager (NM_DBUS_OBJECT (self)), - invocation, - G_MAXULONG, - NM_MANAGER_ERROR, - NM_MANAGER_ERROR_PERMISSION_DENIED)) + if (!nm_bus_manager_ensure_uid (nm_bus_manager_get (), + context, + G_MAXULONG, + NM_MANAGER_ERROR, + NM_MANAGER_ERROR_PERMISSION_DENIED)) return; - g_variant_get (parameters, "(&s&s)", &level, &domains); - if (nm_logging_setup (level, domains, NULL, &error)) { _LOGI (LOGD_CORE, "logging: level '%s' domains '%s'", nm_logging_level_to_string (), nm_logging_domains_to_string ()); } if (error) - g_dbus_method_invocation_take_error (invocation, error); + g_dbus_method_invocation_take_error (context, error); else - g_dbus_method_invocation_return_value (invocation, NULL); + g_dbus_method_invocation_return_value (context, NULL); } static void -impl_manager_get_logging (NMDBusObject *obj, - const NMDBusInterfaceInfoExtended *interface_info, - const NMDBusMethodInfoExtended *method_info, - GDBusConnection *connection, - const char *sender, - GDBusMethodInvocation *invocation, - GVariant *parameters) -{ - g_dbus_method_invocation_return_value (invocation, +impl_manager_get_logging (NMManager *manager, + GDBusMethodInvocation *context) +{ + g_dbus_method_invocation_return_value (context, g_variant_new ("(ss)", nm_logging_level_to_string (), nm_logging_domains_to_string ())); } typedef struct { - NMManager *self; - GDBusMethodInvocation *context; guint remaining; + GDBusMethodInvocation *context; + NMConnectivityState state; } ConnectivityCheckData; static void -device_connectivity_done (NMDevice *device, - NMDeviceConnectivityHandle *handle, - NMConnectivityState state, - GError *error, - gpointer user_data) +device_connectivity_done (NMDevice *device, NMConnectivityState state, gpointer user_data) { ConnectivityCheckData *data = user_data; - NMManager *self; - NMManagerPrivate *priv; - - nm_assert (data); - nm_assert (data->remaining > 0); - nm_assert (NM_IS_MANAGER (data->self)); data->remaining--; - self = data->self; - priv = NM_MANAGER_GET_PRIVATE (self); + /* We check if the state is already FULL so that we can provide the + * response without waiting for slower devices that are not going to + * affect the overall state anyway. */ - if ( data->context - && ( data->remaining == 0 - || ( state == NM_CONNECTIVITY_FULL - && priv->connectivity_state == NM_CONNECTIVITY_FULL))) { - /* despite having a @handle and @state returned by the requests, we always - * return the current connectivity_state. That is, because the connectivity_state - * and the answer to the connectivity check shall agree. - * - * However, if one of the requests (early) returns full connectivity and agrees with - * the accumulated connectivity state, we no longer have to wait. The result is set. - * - * This also works well, because NMDevice first emits change signals to its own - * connectivity state, which is then taken into account for the accumulated global - * state. All this happens, before the callback is invoked. */ - g_dbus_method_invocation_return_value (g_steal_pointer (&data->context), - g_variant_new ("(u)", - (guint) priv->connectivity_state)); + if (data->state != NM_CONNECTIVITY_FULL) { + if (state > data->state) + data->state = state; + + if (data->state == NM_CONNECTIVITY_FULL || !data->remaining) { + g_dbus_method_invocation_return_value (data->context, + g_variant_new ("(u)", data->state)); + } } - if (data->remaining == 0) { - g_object_unref (self); + if (!data->remaining) g_slice_free (ConnectivityCheckData, data); - } } static void @@ -5564,7 +5408,7 @@ check_connectivity_auth_done_cb (NMAuthChain *chain, GError *error = NULL; NMAuthCallResult result; ConnectivityCheckData *data; - NMDevice *device; + const GSList *devices; priv->auth_chains = g_slist_remove (priv->auth_chains, chain); @@ -5580,59 +5424,39 @@ check_connectivity_auth_done_cb (NMAuthChain *chain, error = g_error_new_literal (NM_MANAGER_ERROR, NM_MANAGER_ERROR_PERMISSION_DENIED, "Not authorized to recheck connectivity"); - } - - if (error) { - g_dbus_method_invocation_take_error (context, error); - goto out; - } - - data = g_slice_new (ConnectivityCheckData); - data->self = g_object_ref (self); - data->context = context; - data->remaining = 0; + } else { + /* it's allowed */ + data = g_slice_new0 (ConnectivityCheckData); + data->context = context; - c_list_for_each_entry (device, &priv->devices_lst_head, devices_lst) { - if (nm_device_check_connectivity (device, - device_connectivity_done, - data)) + for (devices = priv->devices; devices; devices = devices->next) { data->remaining++; + nm_device_check_connectivity (NM_DEVICE (devices->data), + device_connectivity_done, + data); + } } - if (data->remaining == 0) { - /* call the handler at least once. */ - data->remaining = 1; - device_connectivity_done (NULL, - NULL, - NM_CONNECTIVITY_UNKNOWN, - NULL, - data); - /* @data got destroyed. */ - } - -out: - nm_auth_chain_destroy (chain); + if (error) + g_dbus_method_invocation_take_error (context, error); + nm_auth_chain_unref (chain); } static void -impl_manager_check_connectivity (NMDBusObject *obj, - const NMDBusInterfaceInfoExtended *interface_info, - const NMDBusMethodInfoExtended *method_info, - GDBusConnection *connection, - const char *sender, - GDBusMethodInvocation *invocation, - GVariant *parameters) -{ - NMManager *self = NM_MANAGER (obj); +impl_manager_check_connectivity (NMManager *self, + GDBusMethodInvocation *context) +{ NMManagerPrivate *priv = NM_MANAGER_GET_PRIVATE (self); NMAuthChain *chain; + GError *error = NULL; - chain = nm_auth_chain_new_context (invocation, check_connectivity_auth_done_cb, self); + /* Validate the request */ + chain = nm_auth_chain_new_context (context, check_connectivity_auth_done_cb, self); if (!chain) { - g_dbus_method_invocation_return_error_literal(invocation, - NM_MANAGER_ERROR, - NM_MANAGER_ERROR_PERMISSION_DENIED, - "Unable to authenticate request."); + error = g_error_new_literal (NM_MANAGER_ERROR, + NM_MANAGER_ERROR_PERMISSION_DENIED, + "Unable to authenticate request."); + g_dbus_method_invocation_take_error (context, error); return; } @@ -5649,14 +5473,15 @@ start_factory (NMDeviceFactory *factory, gpointer user_data) void nm_manager_write_device_state (NMManager *self) { + const GSList *devices; NMManagerPrivate *priv = NM_MANAGER_GET_PRIVATE (self); - NMDevice *device; gs_unref_hashtable GHashTable *seen_ifindexes = NULL; gint nm_owned; - seen_ifindexes = g_hash_table_new (nm_direct_hash, NULL); + seen_ifindexes = g_hash_table_new (NULL, NULL); - c_list_for_each_entry (device, &priv->devices_lst_head, devices_lst) { + for (devices = priv->devices; devices; devices = devices->next) { + NMDevice *device = NM_DEVICE (devices->data); int ifindex; gboolean managed; NMConfigDeviceStateManagedType managed_type; @@ -5797,10 +5622,10 @@ void nm_manager_stop (NMManager *self) { NMManagerPrivate *priv = NM_MANAGER_GET_PRIVATE (self); - NMDevice *device; - while ((device = c_list_first_entry (&priv->devices_lst_head, NMDevice, devices_lst))) - remove_device (self, device, TRUE, TRUE); + /* Remove all devices */ + while (priv->devices) + remove_device (self, NM_DEVICE (priv->devices->data), TRUE, TRUE); _active_connection_cleanup (self); @@ -5812,20 +5637,21 @@ handle_firmware_changed (gpointer user_data) { NMManager *self = NM_MANAGER (user_data); NMManagerPrivate *priv = NM_MANAGER_GET_PRIVATE (self); - NMDevice *device; + GSList *iter; priv->fw_changed_id = 0; /* Try to re-enable devices with missing firmware */ - c_list_for_each_entry (device, &priv->devices_lst_head, devices_lst) { - NMDeviceState state = nm_device_get_state (device); + for (iter = priv->devices; iter; iter = iter->next) { + NMDevice *candidate = NM_DEVICE (iter->data); + NMDeviceState state = nm_device_get_state (candidate); - if ( nm_device_get_firmware_missing (device) + if ( nm_device_get_firmware_missing (candidate) && (state == NM_DEVICE_STATE_UNAVAILABLE)) { - _LOG2I (LOGD_CORE, device, "firmware may now be available"); + _LOG2I (LOGD_CORE, candidate, "firmware may now be available"); /* Re-set unavailable state to try bringing the device up again */ - nm_device_state_changed (device, + nm_device_state_changed (candidate, NM_DEVICE_STATE_UNAVAILABLE, NM_DEVICE_STATE_REASON_NONE); } @@ -5944,133 +5770,318 @@ policy_activating_device_changed (GObject *object, GParamSpec *pspec, gpointer u } } -/*****************************************************************************/ +#define NM_PERM_DENIED_ERROR "org.freedesktop.NetworkManager.PermissionDenied" typedef struct { NMManager *self; - NMDBusObject *obj; - const NMDBusInterfaceInfoExtended *interface_info; - const NMDBusPropertyInfoExtended *property_info; - GVariant *value; - guint64 export_version_id; -} DBusSetPropertyHandle; + GDBusConnection *connection; + GDBusMessage *message; + NMAuthSubject *subject; + const char *permission; + const char *audit_op; + char *audit_prop_value; + GType interface_type; + const char *glib_propname; +} PropertyFilterData; -#define NM_PERM_DENIED_ERROR "org.freedesktop.NetworkManager.PermissionDenied" +static void +free_property_filter_data (PropertyFilterData *pfd) +{ + g_object_unref (pfd->self); + g_object_unref (pfd->connection); + g_object_unref (pfd->message); + g_clear_object (&pfd->subject); + g_free (pfd->audit_prop_value); + g_slice_free (PropertyFilterData, pfd); +} static void -_dbus_set_property_auth_cb (NMAuthChain *chain, - GError *error, - GDBusMethodInvocation *invocation, - gpointer user_data) +prop_set_auth_done_cb (NMAuthChain *chain, + GError *error, + GDBusMethodInvocation *context, /* NULL */ + gpointer user_data) { - DBusSetPropertyHandle *handle_data = user_data; - gs_unref_object NMDBusObject *obj = handle_data->obj; - const NMDBusInterfaceInfoExtended *interface_info = handle_data->interface_info; - const NMDBusPropertyInfoExtended *property_info = handle_data->property_info; - gs_unref_variant GVariant *value = handle_data->value; - guint64 export_version_id = handle_data->export_version_id; - gs_unref_object NMManager *self = handle_data->self; - NMManagerPrivate *priv = NM_MANAGER_GET_PRIVATE (self); + PropertyFilterData *pfd = user_data; + NMManagerPrivate *priv = NM_MANAGER_GET_PRIVATE (pfd->self); NMAuthCallResult result; - const char *error_name = NULL; - const char *error_message = NULL; - GValue gvalue; - - g_slice_free (DBusSetPropertyHandle, handle_data); + GDBusMessage *reply = NULL; + const char *error_message; + gs_unref_object NMExportedObject *object = NULL; + const NMGlobalDnsConfig *global_dns; + gs_unref_variant GVariant *value = NULL; + GVariant *args; priv->auth_chains = g_slist_remove (priv->auth_chains, chain); - result = nm_auth_chain_get_result (chain, property_info->writable.permission); + result = nm_auth_chain_get_result (chain, pfd->permission); + if (error || (result != NM_AUTH_CALL_RESULT_YES)) { + reply = g_dbus_message_new_method_error_literal (pfd->message, + NM_PERM_DENIED_ERROR, + (error_message = "Not authorized to perform this operation")); + if (error) + error_message = error->message; + goto done; + } - if ( error - || result != NM_AUTH_CALL_RESULT_YES) { - error_name = NM_PERM_DENIED_ERROR; - error_message = error ? error->message : "Not authorized to perform this operation"; - goto out; + object = NM_EXPORTED_OBJECT (nm_bus_manager_get_registered_object (priv->dbus_mgr, + g_dbus_message_get_path (pfd->message))); + if (!object) { + reply = g_dbus_message_new_method_error_literal (pfd->message, + "org.freedesktop.DBus.Error.UnknownObject", + (error_message = "Object doesn't exist.")); + goto done; } - if (export_version_id != nm_dbus_object_get_export_version_id (obj)) { - error_name = "org.freedesktop.DBus.Error.UnknownObject"; - error_message = "Object was deleted while authenticating"; - goto out; + /* do some extra type checking... */ + if (!nm_exported_object_get_interface_by_type (object, pfd->interface_type)) { + reply = g_dbus_message_new_method_error_literal (pfd->message, + "org.freedesktop.DBus.Error.InvalidArgs", + (error_message = "Object is of unexpected type.")); + goto done; } - /* Handle some properties specially *sigh* */ - if ( interface_info == &interface_info_manager - && nm_streq (property_info->property_name, NM_MANAGER_GLOBAL_DNS_CONFIGURATION)) { - const NMGlobalDnsConfig *global_dns; + args = g_dbus_message_get_body (pfd->message); + g_variant_get (args, "(&s&sv)", NULL, NULL, &value); + g_assert (pfd->glib_propname); + if (!strcmp (pfd->glib_propname, NM_MANAGER_GLOBAL_DNS_CONFIGURATION)) { + g_assert (g_variant_is_of_type (value, G_VARIANT_TYPE ("a{sv}"))); global_dns = nm_config_data_get_global_dns_config (nm_config_get_data (priv->config)); - if ( global_dns - && !nm_global_dns_config_is_internal (global_dns)) { - error_name = NM_PERM_DENIED_ERROR; - error_message = "Global DNS configuration already set via configuration file"; - goto out; + + if (global_dns && !nm_global_dns_config_is_internal (global_dns)) { + reply = g_dbus_message_new_method_error_literal (pfd->message, + NM_PERM_DENIED_ERROR, + (error_message = "Global DNS configuration already set via configuration file")); + goto done; } + /* ... but set the property on the @object itself. It would be correct to set the property + * on the skeleton interface, but as it is now, the result is the same. */ + g_object_set (object, pfd->glib_propname, value, NULL); + } else if (!strcmp (pfd->glib_propname, NM_DEVICE_STATISTICS_REFRESH_RATE_MS)) { + g_assert (g_variant_is_of_type (value, G_VARIANT_TYPE_UINT32)); + /* the same here */ + g_object_set (object, pfd->glib_propname, (guint) g_variant_get_uint32 (value), NULL); + } else { + g_assert (g_variant_is_of_type (value, G_VARIANT_TYPE_BOOLEAN)); + /* the same here */ + g_object_set (object, pfd->glib_propname, g_variant_get_boolean (value), NULL); } - g_dbus_gvariant_to_gvalue (value, &gvalue); - g_object_set_property (G_OBJECT (obj), property_info->property_name, &gvalue); - g_value_unset (&gvalue); + reply = g_dbus_message_new_method_reply (pfd->message); + g_dbus_message_set_body (reply, g_variant_new_tuple (NULL, 0)); + error_message = NULL; +done: + nm_audit_log_control_op (pfd->audit_op, pfd->audit_prop_value, !error_message, pfd->subject, error_message); -out: - nm_audit_log_control_op (property_info->writable.audit_op, - property_info->property_name, - !error_message, - nm_auth_chain_get_subject (chain), - error_message); - if (error_message) - g_dbus_method_invocation_return_dbus_error (invocation, error_name, error_message); - else - g_dbus_method_invocation_return_value (invocation, NULL); - nm_auth_chain_destroy (chain); + g_dbus_connection_send_message (pfd->connection, reply, + G_DBUS_SEND_MESSAGE_FLAGS_NONE, + NULL, NULL); + g_object_unref (reply); + nm_auth_chain_unref (chain); + + free_property_filter_data (pfd); } -void -nm_manager_dbus_set_property_handle (NMDBusObject *obj, - const NMDBusInterfaceInfoExtended *interface_info, - const NMDBusPropertyInfoExtended *property_info, - GDBusConnection *connection, - const char *sender, - GDBusMethodInvocation *invocation, - GVariant *value, - gpointer user_data) +static gboolean +do_set_property_check (gpointer user_data) { - NMManager *self = user_data; - NMManagerPrivate *priv = NM_MANAGER_GET_PRIVATE (self); + PropertyFilterData *pfd = user_data; + NMManagerPrivate *priv = NM_MANAGER_GET_PRIVATE (pfd->self); + GDBusMessage *reply = NULL; NMAuthChain *chain; const char *error_message = NULL; - gs_unref_object NMAuthSubject *subject = NULL; - DBusSetPropertyHandle *handle_data; - subject = nm_auth_subject_new_unix_process_from_context (invocation); - if (!subject) { - error_message = "Could not determine request UID"; - goto err; + pfd->subject = nm_auth_subject_new_unix_process_from_message (pfd->connection, pfd->message); + if (!pfd->subject) { + reply = g_dbus_message_new_method_error_literal (pfd->message, + NM_PERM_DENIED_ERROR, + (error_message = "Could not determine request UID.")); + goto out; } - handle_data = g_slice_new0 (DBusSetPropertyHandle); - handle_data->self = g_object_ref (self); - handle_data->obj = g_object_ref (obj); - handle_data->interface_info = interface_info; - handle_data->property_info = property_info; - handle_data->value = g_variant_ref (value); - handle_data->export_version_id = nm_dbus_object_get_export_version_id (obj); + /* Validate the user request */ + chain = nm_auth_chain_new_subject (pfd->subject, NULL, prop_set_auth_done_cb, pfd); + if (!chain) { + reply = g_dbus_message_new_method_error_literal (pfd->message, + NM_PERM_DENIED_ERROR, + (error_message = "Could not authenticate request.")); + goto out; + } - chain = nm_auth_chain_new_subject (subject, invocation, _dbus_set_property_auth_cb, handle_data); priv->auth_chains = g_slist_append (priv->auth_chains, chain); - nm_auth_chain_add_call (chain, property_info->writable.permission, TRUE); - return; + nm_auth_chain_add_call (chain, pfd->permission, TRUE); + +out: + if (reply) { + nm_audit_log_control_op (pfd->audit_op, pfd->audit_prop_value, FALSE, pfd->subject, error_message); + g_dbus_connection_send_message (pfd->connection, reply, + G_DBUS_SEND_MESSAGE_FLAGS_NONE, + NULL, NULL); + g_object_unref (reply); + free_property_filter_data (pfd); + } + + return FALSE; +} + +static GDBusMessage * +prop_filter (GDBusConnection *connection, + GDBusMessage *message, + gboolean incoming, + gpointer user_data) +{ + gs_unref_object NMManager *self = NULL; + GVariant *args; + const char *propiface = NULL; + const char *propname = NULL; + const char *glib_propname = NULL, *permission = NULL; + const char *audit_op = NULL; + GType interface_type = G_TYPE_INVALID; + PropertyFilterData *pfd; + const GVariantType *expected_type = G_VARIANT_TYPE_BOOLEAN; + gs_unref_variant GVariant *value = NULL; + + self = g_weak_ref_get (user_data); + if (!self) + return message; + + /* The sole purpose of this function is to validate property accesses on the + * NMManager object since gdbus doesn't give us this functionality. + */ + + /* Only filter org.freedesktop.DBus.Properties.Set calls */ + if ( !incoming + || g_dbus_message_get_message_type (message) != G_DBUS_MESSAGE_TYPE_METHOD_CALL + || g_strcmp0 (g_dbus_message_get_interface (message), DBUS_INTERFACE_PROPERTIES) != 0 + || g_strcmp0 (g_dbus_message_get_member (message), "Set") != 0) + return message; + + args = g_dbus_message_get_body (message); + if (!g_variant_is_of_type (args, G_VARIANT_TYPE ("(ssv)"))) + return message; + g_variant_get (args, "(&s&sv)", &propiface, &propname, &value); + + /* Only filter calls to filtered properties, on existing objects */ + if (!strcmp (propiface, NM_DBUS_INTERFACE)) { + if (!strcmp (propname, "WirelessEnabled")) { + glib_propname = NM_MANAGER_WIRELESS_ENABLED; + permission = NM_AUTH_PERMISSION_ENABLE_DISABLE_WIFI; + audit_op = NM_AUDIT_OP_RADIO_CONTROL; + } else if (!strcmp (propname, "WwanEnabled")) { + glib_propname = NM_MANAGER_WWAN_ENABLED; + permission = NM_AUTH_PERMISSION_ENABLE_DISABLE_WWAN; + audit_op = NM_AUDIT_OP_RADIO_CONTROL; + } else if (!strcmp (propname, "WimaxEnabled")) { + glib_propname = NM_MANAGER_WIMAX_ENABLED; + permission = NM_AUTH_PERMISSION_ENABLE_DISABLE_WIMAX; + audit_op = NM_AUDIT_OP_RADIO_CONTROL; + } else if (!strcmp (propname, "GlobalDnsConfiguration")) { + glib_propname = NM_MANAGER_GLOBAL_DNS_CONFIGURATION; + permission = NM_AUTH_PERMISSION_SETTINGS_MODIFY_GLOBAL_DNS; + audit_op = NM_AUDIT_OP_NET_CONTROL; + expected_type = G_VARIANT_TYPE ("a{sv}"); + } else if (!strcmp (propname, "ConnectivityCheckEnabled")) { + glib_propname = NM_MANAGER_CONNECTIVITY_CHECK_ENABLED; + permission = NM_AUTH_PERMISSION_ENABLE_DISABLE_CONNECTIVITY_CHECK; + audit_op = NM_AUDIT_OP_NET_CONTROL; + } else + return message; + interface_type = NMDBUS_TYPE_MANAGER_SKELETON; + } else if (!strcmp (propiface, NM_DBUS_INTERFACE_DEVICE)) { + if (!strcmp (propname, "Autoconnect")) { + glib_propname = NM_DEVICE_AUTOCONNECT; + permission = NM_AUTH_PERMISSION_NETWORK_CONTROL; + audit_op = NM_AUDIT_OP_DEVICE_AUTOCONNECT; + } else if (!strcmp (propname, "Managed")) { + glib_propname = NM_DEVICE_MANAGED; + permission = NM_AUTH_PERMISSION_NETWORK_CONTROL; + audit_op = NM_AUDIT_OP_DEVICE_MANAGED; + } else + return message; + interface_type = NMDBUS_TYPE_DEVICE_SKELETON; + } else if (!strcmp (propiface, NM_DBUS_INTERFACE_DEVICE_STATISTICS)) { + if (!strcmp (propname, "RefreshRateMs")) { + glib_propname = NM_DEVICE_STATISTICS_REFRESH_RATE_MS; + permission = NM_AUTH_PERMISSION_ENABLE_DISABLE_STATISTICS; + audit_op = NM_AUDIT_OP_STATISTICS; + expected_type = G_VARIANT_TYPE ("u"); + } else + return message; + interface_type = NMDBUS_TYPE_DEVICE_SKELETON; + } else + return message; + + if (!g_variant_is_of_type (value, expected_type)) + return message; + + /* This filter function is called from a gdbus worker thread which we can't + * make other D-Bus calls from. In particular, we cannot call + * org.freedesktop.DBus.GetConnectionUnixUser to find the remote UID. + */ + pfd = g_slice_new0 (PropertyFilterData); + pfd->self = self; + self = NULL; + pfd->connection = g_object_ref (connection); + pfd->message = message; + pfd->permission = permission; + pfd->interface_type = interface_type; + pfd->glib_propname = glib_propname; + pfd->audit_op = audit_op; + if (g_variant_is_of_type (value, G_VARIANT_TYPE_BOOLEAN)) { + pfd->audit_prop_value = g_strdup_printf ("%s:%d", pfd->glib_propname, + g_variant_get_boolean (value)); + } else + pfd->audit_prop_value = g_strdup (pfd->glib_propname); + + g_idle_add (do_set_property_check, pfd); + + return NULL; +} + +/*****************************************************************************/ + +static int +_set_prop_filter_free2 (gpointer user_data) +{ + g_slice_free (GWeakRef, user_data); + return G_SOURCE_REMOVE; +} + +static void +_set_prop_filter_free (gpointer user_data) +{ + g_weak_ref_clear (user_data); + + /* Delay the final deletion of the user_data. There is a race when + * calling g_dbus_connection_remove_filter() that the callback and user_data + * might have been copied and being executed after the destroy function + * runs (bgo #704568). + * This doesn't really fix the race, but it should work well enough. */ + g_timeout_add_seconds (2, _set_prop_filter_free2, user_data); +} + +static void +_set_prop_filter (NMManager *self, GDBusConnection *connection) +{ + NMManagerPrivate *priv = NM_MANAGER_GET_PRIVATE (self); + + nm_assert ((!priv->prop_filter.connection) == (!priv->prop_filter.id)); + + if (priv->prop_filter.connection == connection) + return; + + if (priv->prop_filter.connection) { + g_dbus_connection_remove_filter (priv->prop_filter.connection, priv->prop_filter.id); + priv->prop_filter.id = 0; + g_clear_object (&priv->prop_filter.connection); + } + if (connection) { + GWeakRef *wptr; -err: - nm_audit_log_control_op (property_info->writable.audit_op, - property_info->property_name, - FALSE, - invocation, - error_message); - g_dbus_method_invocation_return_error_literal (invocation, - G_DBUS_ERROR, - G_DBUS_ERROR_AUTH_FAILED, - error_message); + wptr = g_slice_new (GWeakRef); + g_weak_ref_init (wptr, self); + priv->prop_filter.id = g_dbus_connection_add_filter (connection, prop_filter, wptr, _set_prop_filter_free); + priv->prop_filter.connection = g_object_ref (connection); + } } /*****************************************************************************/ @@ -6081,7 +6092,7 @@ _checkpoint_mgr_get (NMManager *self, gboolean create_as_needed) NMManagerPrivate *priv = NM_MANAGER_GET_PRIVATE (self); if (G_UNLIKELY (!priv->checkpoint_mgr) && create_as_needed) - priv->checkpoint_mgr = nm_checkpoint_manager_new (self, obj_properties[PROP_CHECKPOINTS]); + priv->checkpoint_mgr = nm_checkpoint_manager_new (self); return priv->checkpoint_mgr; } @@ -6100,15 +6111,13 @@ checkpoint_auth_done_cb (NMAuthChain *chain, GVariant *variant = NULL; GError *error = NULL; const char *arg = NULL; - guint32 add_timeout; op = nm_auth_chain_get_data (chain, "audit-op"); priv->auth_chains = g_slist_remove (priv->auth_chains, chain); result = nm_auth_chain_get_result (chain, NM_AUTH_PERMISSION_CHECKPOINT_ROLLBACK); - if (NM_IN_STRSET (op, NM_AUDIT_OP_CHECKPOINT_DESTROY, - NM_AUDIT_OP_CHECKPOINT_ROLLBACK, - NM_AUDIT_OP_CHECKPOINT_ADJUST_ROLLBACK_TIMEOUT)) + if ( nm_streq0 (op, NM_AUDIT_OP_CHECKPOINT_DESTROY) + || nm_streq0 (op, NM_AUDIT_OP_CHECKPOINT_ROLLBACK)) arg = checkpoint_path = nm_auth_chain_get_data (chain, "checkpoint_path"); if (auth_error) { @@ -6132,7 +6141,7 @@ checkpoint_auth_done_cb (NMAuthChain *chain, (NMCheckpointCreateFlags) flags, &error); if (checkpoint) { - arg = nm_dbus_object_get_path (NM_DBUS_OBJECT (checkpoint)); + arg = nm_exported_object_get_path (NM_EXPORTED_OBJECT (checkpoint)); variant = g_variant_new ("(o)", arg); } } else if (nm_streq0 (op, NM_AUDIT_OP_CHECKPOINT_DESTROY)) { @@ -6141,10 +6150,6 @@ checkpoint_auth_done_cb (NMAuthChain *chain, } else if (nm_streq0 (op, NM_AUDIT_OP_CHECKPOINT_ROLLBACK)) { nm_checkpoint_manager_rollback (_checkpoint_mgr_get (self, TRUE), checkpoint_path, &variant, &error); - } else if (nm_streq0 (op, NM_AUDIT_OP_CHECKPOINT_ADJUST_ROLLBACK_TIMEOUT)) { - add_timeout = GPOINTER_TO_UINT (nm_auth_chain_get_data (chain, "add_timeout")); - nm_checkpoint_manager_adjust_rollback_timeout (_checkpoint_mgr_get (self, TRUE), - checkpoint_path, add_timeout, &error); } else g_return_if_reached (); } @@ -6157,71 +6162,63 @@ checkpoint_auth_done_cb (NMAuthChain *chain, else g_dbus_method_invocation_return_value (context, variant); - nm_auth_chain_destroy (chain); + + nm_auth_chain_unref (chain); } static void -impl_manager_checkpoint_create (NMDBusObject *obj, - const NMDBusInterfaceInfoExtended *interface_info, - const NMDBusMethodInfoExtended *method_info, - GDBusConnection *connection, - const char *sender, - GDBusMethodInvocation *invocation, - GVariant *parameters) -{ - NMManager *self = NM_MANAGER (obj); - NMManagerPrivate *priv = NM_MANAGER_GET_PRIVATE (self); +impl_manager_checkpoint_create (NMManager *self, + GDBusMethodInvocation *context, + const char *const *devices, + guint32 rollback_timeout, + guint32 flags) +{ + NMManagerPrivate *priv; NMAuthChain *chain; - char **devices; - guint32 rollback_timeout; - guint32 flags; + GError *error = NULL; G_STATIC_ASSERT_EXPR (sizeof (flags) <= sizeof (NMCheckpointCreateFlags)); + g_return_if_fail (NM_IS_MANAGER (self)); + priv = NM_MANAGER_GET_PRIVATE (self); - chain = nm_auth_chain_new_context (invocation, checkpoint_auth_done_cb, self); + chain = nm_auth_chain_new_context (context, checkpoint_auth_done_cb, self); if (!chain) { - g_dbus_method_invocation_return_error_literal (invocation, - NM_MANAGER_ERROR, - NM_MANAGER_ERROR_PERMISSION_DENIED, - "Unable to authenticate request."); + error = g_error_new_literal (NM_MANAGER_ERROR, + NM_MANAGER_ERROR_PERMISSION_DENIED, + "Unable to authenticate request."); + g_dbus_method_invocation_take_error (context, error); return; } - g_variant_get (parameters, "(^aouu)", &devices, &rollback_timeout, &flags); - priv->auth_chains = g_slist_append (priv->auth_chains, chain); nm_auth_chain_set_data (chain, "audit-op", NM_AUDIT_OP_CHECKPOINT_CREATE, NULL); - nm_auth_chain_set_data (chain, "devices", devices, (GDestroyNotify) g_strfreev); + nm_auth_chain_set_data (chain, "devices", g_strdupv ((char **) devices), (GDestroyNotify) g_strfreev); nm_auth_chain_set_data (chain, "flags", GUINT_TO_POINTER (flags), NULL); nm_auth_chain_set_data (chain, "timeout", GUINT_TO_POINTER (rollback_timeout), NULL); nm_auth_chain_add_call (chain, NM_AUTH_PERMISSION_CHECKPOINT_ROLLBACK, TRUE); } static void -impl_manager_checkpoint_destroy (NMDBusObject *obj, - const NMDBusInterfaceInfoExtended *interface_info, - const NMDBusMethodInfoExtended *method_info, - GDBusConnection *connection, - const char *sender, - GDBusMethodInvocation *invocation, - GVariant *parameters) -{ - NMManager *self = NM_MANAGER (obj); - NMManagerPrivate *priv = NM_MANAGER_GET_PRIVATE (self); +impl_manager_checkpoint_destroy (NMManager *self, + GDBusMethodInvocation *context, + const char *checkpoint_path) +{ + NMManagerPrivate *priv; + GError *error = NULL; NMAuthChain *chain; - const char *checkpoint_path; - chain = nm_auth_chain_new_context (invocation, checkpoint_auth_done_cb, self); + g_return_if_fail (NM_IS_MANAGER (self)); + priv = NM_MANAGER_GET_PRIVATE (self); + + chain = nm_auth_chain_new_context (context, checkpoint_auth_done_cb, self); if (!chain) { - g_dbus_method_invocation_return_error_literal (invocation, - NM_MANAGER_ERROR, - NM_MANAGER_ERROR_PERMISSION_DENIED, - "Unable to authenticate request."); + error = g_error_new_literal (NM_MANAGER_ERROR, + NM_MANAGER_ERROR_PERMISSION_DENIED, + "Unable to authenticate request."); + g_dbus_method_invocation_take_error (context, error); return; } - g_variant_get (parameters, "(&o)", &checkpoint_path); - priv->auth_chains = g_slist_append (priv->auth_chains, chain); nm_auth_chain_set_data (chain, "audit-op", NM_AUDIT_OP_CHECKPOINT_DESTROY, NULL); nm_auth_chain_set_data (chain, "checkpoint_path", g_strdup (checkpoint_path), g_free); @@ -6229,66 +6226,29 @@ impl_manager_checkpoint_destroy (NMDBusObject *obj, } static void -impl_manager_checkpoint_rollback (NMDBusObject *obj, - const NMDBusInterfaceInfoExtended *interface_info, - const NMDBusMethodInfoExtended *method_info, - GDBusConnection *connection, - const char *sender, - GDBusMethodInvocation *invocation, - GVariant *parameters) -{ - NMManager *self = NM_MANAGER (obj); - NMManagerPrivate *priv = NM_MANAGER_GET_PRIVATE (self); +impl_manager_checkpoint_rollback (NMManager *self, + GDBusMethodInvocation *context, + const char *checkpoint_path) +{ + NMManagerPrivate *priv; + GError *error = NULL; NMAuthChain *chain; - const char *checkpoint_path; - - chain = nm_auth_chain_new_context (invocation, checkpoint_auth_done_cb, self); - if (!chain) { - g_dbus_method_invocation_return_error_literal (invocation, - NM_MANAGER_ERROR, - NM_MANAGER_ERROR_PERMISSION_DENIED, - "Unable to authenticate request."); - return; - } - - g_variant_get (parameters, "(&o)", &checkpoint_path); - - priv->auth_chains = g_slist_append (priv->auth_chains, chain); - nm_auth_chain_set_data (chain, "audit-op", NM_AUDIT_OP_CHECKPOINT_ROLLBACK, NULL); - nm_auth_chain_set_data (chain, "checkpoint_path", g_strdup (checkpoint_path), g_free); - nm_auth_chain_add_call (chain, NM_AUTH_PERMISSION_CHECKPOINT_ROLLBACK, TRUE); -} -static void -impl_manager_checkpoint_adjust_rollback_timeout (NMDBusObject *obj, - const NMDBusInterfaceInfoExtended *interface_info, - const NMDBusMethodInfoExtended *method_info, - GDBusConnection *connection, - const char *sender, - GDBusMethodInvocation *invocation, - GVariant *parameters) -{ - NMManager *self = NM_MANAGER (obj); - NMManagerPrivate *priv = NM_MANAGER_GET_PRIVATE (self); - NMAuthChain *chain; - const char *checkpoint_path; - guint32 add_timeout; + g_return_if_fail (NM_IS_MANAGER (self)); + priv = NM_MANAGER_GET_PRIVATE (self); - chain = nm_auth_chain_new_context (invocation, checkpoint_auth_done_cb, self); + chain = nm_auth_chain_new_context (context, checkpoint_auth_done_cb, self); if (!chain) { - g_dbus_method_invocation_return_error_literal (invocation, - NM_MANAGER_ERROR, - NM_MANAGER_ERROR_PERMISSION_DENIED, - "Unable to authenticate request."); + error = g_error_new_literal (NM_MANAGER_ERROR, + NM_MANAGER_ERROR_PERMISSION_DENIED, + "Unable to authenticate request."); + g_dbus_method_invocation_take_error (context, error); return; } - g_variant_get (parameters, "(&ou)", &checkpoint_path, &add_timeout); - priv->auth_chains = g_slist_append (priv->auth_chains, chain); - nm_auth_chain_set_data (chain, "audit-op", NM_AUDIT_OP_CHECKPOINT_ADJUST_ROLLBACK_TIMEOUT, NULL); + nm_auth_chain_set_data (chain, "audit-op", NM_AUDIT_OP_CHECKPOINT_ROLLBACK, NULL); nm_auth_chain_set_data (chain, "checkpoint_path", g_strdup (checkpoint_path), g_free); - nm_auth_chain_set_data (chain, "add_timeout", GUINT_TO_POINTER (add_timeout), NULL); nm_auth_chain_add_call (chain, NM_AUTH_PERMISSION_CHECKPOINT_ROLLBACK, TRUE); } @@ -6298,10 +6258,7 @@ static void auth_mgr_changed (NMAuthManager *auth_manager, gpointer user_data) { /* Let clients know they should re-check their authorization */ - nm_dbus_object_emit_signal (user_data, - &interface_info_manager, - &signal_info_check_permissions, - "()"); + g_signal_emit (NM_MANAGER (user_data), signals[CHECK_PERMISSIONS], 0); } #define KERN_RFKILL_OP_CHANGE_ALL 3 @@ -6426,6 +6383,14 @@ periodic_update_active_connection_timestamps (gpointer user_data) return G_SOURCE_CONTINUE; } +static void +dbus_connection_changed_cb (NMBusManager *dbus_mgr, + GDBusConnection *connection, + gpointer user_data) +{ + _set_prop_filter (NM_MANAGER (user_data), connection); +} + /*****************************************************************************/ void @@ -6492,7 +6457,8 @@ nm_manager_setup (void) nm_singleton_instance_register (); _LOGD (LOGD_CORE, "setup %s singleton (%p)", "NMManager", singleton_instance); - nm_dbus_object_export (NM_DBUS_OBJECT (self)); + nm_exported_object_export ((NMExportedObject *) self); + return self; } @@ -6505,9 +6471,11 @@ constructed (GObject *object) G_OBJECT_CLASS (nm_manager_parent_class)->constructed (object); + _set_prop_filter (self, nm_bus_manager_get_connection (priv->dbus_mgr)); + priv->settings = nm_settings_new (); - nm_dbus_object_export (NM_DBUS_OBJECT (priv->settings)); + nm_exported_object_export (NM_EXPORTED_OBJECT (priv->settings)); g_signal_connect (priv->settings, "notify::" NM_SETTINGS_STARTUP_COMPLETE, G_CALLBACK (settings_startup_complete_changed), self); @@ -6575,7 +6543,6 @@ nm_manager_init (NMManager *self) GFile *file; c_list_init (&priv->link_cb_lst); - c_list_init (&priv->devices_lst_head); c_list_init (&priv->active_connections_lst_head); c_list_init (&priv->delete_volatile_connection_lst_head); @@ -6607,6 +6574,12 @@ nm_manager_init (NMManager *self) priv->state = NM_STATE_DISCONNECTED; priv->startup = TRUE; + priv->dbus_mgr = g_object_ref (nm_bus_manager_get ()); + g_signal_connect (priv->dbus_mgr, + NM_BUS_MANAGER_DBUS_CONNECTION_CHANGED, + G_CALLBACK (dbus_connection_changed_cb), + self); + /* sleep/wake handling */ priv->sleep_monitor = nm_sleep_monitor_new (); g_signal_connect (priv->sleep_monitor, NM_SLEEP_MONITOR_SLEEPING, @@ -6641,7 +6614,13 @@ nm_manager_init (NMManager *self) priv->timestamp_update_id = g_timeout_add_seconds (300, (GSourceFunc) periodic_update_active_connection_timestamps, self); priv->metered = NM_METERED_UNKNOWN; - priv->sleep_devices = g_hash_table_new (nm_direct_hash, NULL); + priv->sleep_devices = g_hash_table_new (g_direct_hash, g_direct_equal); +} + +static gboolean +device_is_real (GObject *device, gpointer user_data) +{ + return nm_device_is_real (NM_DEVICE (device)); } static void @@ -6656,6 +6635,7 @@ get_property (GObject *object, guint prop_id, const char *path; NMActiveConnection *ac; GPtrArray *ptrarr; + gboolean vbool; switch (prop_id) { case PROP_VERSION: @@ -6697,7 +6677,7 @@ get_property (GObject *object, guint prop_id, case PROP_ACTIVE_CONNECTIONS: ptrarr = g_ptr_array_new (); c_list_for_each_entry (ac, &priv->active_connections_lst_head, active_connections_lst) { - path = nm_dbus_object_get_path (NM_DBUS_OBJECT (ac)); + path = nm_exported_object_get_path (NM_EXPORTED_OBJECT (ac)); if (path) g_ptr_array_add (ptrarr, g_strdup (path)); } @@ -6712,10 +6692,15 @@ get_property (GObject *object, guint prop_id, g_value_set_boolean (value, nm_config_data_get_connectivity_uri (config_data) != NULL); break; case PROP_CONNECTIVITY_CHECK_ENABLED: - g_value_set_boolean (value, concheck_enabled (self, NULL)); +#if WITH_CONCHECK + vbool = nm_connectivity_check_enabled (nm_connectivity_get ()); +#else + vbool = FALSE; +#endif + g_value_set_boolean (value, vbool); break; case PROP_PRIMARY_CONNECTION: - nm_dbus_utils_g_value_set_object_path (value, priv->primary_connection); + nm_utils_g_value_set_object_path (value, priv->primary_connection); break; case PROP_PRIMARY_CONNECTION_TYPE: type = NULL; @@ -6729,15 +6714,13 @@ get_property (GObject *object, guint prop_id, g_value_set_string (value, type ? type : ""); break; case PROP_ACTIVATING_CONNECTION: - nm_dbus_utils_g_value_set_object_path (value, priv->activating_connection); + nm_utils_g_value_set_object_path (value, priv->activating_connection); break; case PROP_SLEEPING: g_value_set_boolean (value, priv->sleeping); break; case PROP_DEVICES: - g_value_take_boxed (value, - nm_utils_strv_make_deep_copied (_get_devices_paths (self, - FALSE))); + nm_utils_g_value_set_object_path_array (value, priv->devices, device_is_real, NULL); break; case PROP_METERED: g_value_set_uint (value, priv->metered); @@ -6748,16 +6731,7 @@ get_property (GObject *object, guint prop_id, nm_global_dns_config_to_dbus (dns_config, value); break; case PROP_ALL_DEVICES: - g_value_take_boxed (value, - nm_utils_strv_make_deep_copied (_get_devices_paths (self, - TRUE))); - break; - case PROP_CHECKPOINTS: - g_value_take_boxed (value, - priv->checkpoint_mgr - ? nm_utils_strv_make_deep_copied (nm_checkpoint_manager_get_checkpoint_paths (priv->checkpoint_mgr, - NULL)) - : NULL); + nm_utils_g_value_set_object_path_array (value, priv->devices, NULL, NULL); break; default: G_OBJECT_WARN_INVALID_PROPERTY_ID (object, prop_id, pspec); @@ -6824,6 +6798,11 @@ dispose (GObject *object) CList *iter, *iter_safe; NMActiveConnection *ac, *ac_safe; + nm_clear_g_source (&priv->delete_volatile_connection_idle_id); + _delete_volatile_connection_all (self, FALSE); + nm_assert (!priv->delete_volatile_connection_idle_id); + nm_assert (c_list_is_empty (&priv->delete_volatile_connection_lst_head)); + g_signal_handlers_disconnect_by_func (priv->platform, G_CALLBACK (platform_link_cb), self); @@ -6835,18 +6814,14 @@ dispose (GObject *object) g_slice_free (PlatformLinkCbData, data); } - g_slist_free_full (priv->auth_chains, (GDestroyNotify) nm_auth_chain_destroy); + g_slist_free_full (priv->auth_chains, (GDestroyNotify) nm_auth_chain_unref); priv->auth_chains = NULL; nm_clear_g_source (&priv->devices_inited_id); - g_clear_pointer (&priv->checkpoint_mgr, nm_checkpoint_manager_free); - - if (priv->concheck_mgr) { - g_signal_handlers_disconnect_by_func (priv->concheck_mgr, - G_CALLBACK (concheck_config_changed_cb), - self); - g_clear_object (&priv->concheck_mgr); + if (priv->checkpoint_mgr) { + nm_checkpoint_manager_destroy_all (priv->checkpoint_mgr, NULL); + g_clear_pointer (&priv->checkpoint_mgr, nm_checkpoint_manager_unref); } if (priv->auth_mgr) { @@ -6856,7 +6831,7 @@ dispose (GObject *object) g_clear_object (&priv->auth_mgr); } - nm_assert (c_list_is_empty (&priv->devices_lst_head)); + g_assert (priv->devices == NULL); nm_clear_g_source (&priv->ac_cleanup_id); @@ -6893,6 +6868,13 @@ dispose (GObject *object) g_clear_object (&priv->vpn_manager); + /* Unregister property filter */ + if (priv->dbus_mgr) { + g_signal_handlers_disconnect_by_func (priv->dbus_mgr, dbus_connection_changed_cb, self); + g_clear_object (&priv->dbus_mgr); + } + _set_prop_filter (self, NULL); + sleep_devices_clear (self); g_clear_pointer (&priv->sleep_devices, g_hash_table_unref); @@ -6915,11 +6897,6 @@ dispose (GObject *object) g_clear_object (&priv->rfkill_mgr); } - nm_clear_g_source (&priv->delete_volatile_connection_idle_id); - _delete_volatile_connection_all (self, FALSE); - nm_assert (!priv->delete_volatile_connection_idle_id); - nm_assert (c_list_is_empty (&priv->delete_volatile_connection_lst_head)); - nm_device_factory_manager_for_each_factory (_deinit_device_factory, self); nm_clear_g_source (&priv->timestamp_update_id); @@ -6941,274 +6918,22 @@ finalize (GObject *object) g_object_unref (priv->platform); } -static const GDBusSignalInfo signal_info_check_permissions = NM_DEFINE_GDBUS_SIGNAL_INFO_INIT ( - "CheckPermissions", -); - -static const GDBusSignalInfo signal_info_state_changed = NM_DEFINE_GDBUS_SIGNAL_INFO_INIT ( - "StateChanged", - .args = NM_DEFINE_GDBUS_ARG_INFOS ( - NM_DEFINE_GDBUS_ARG_INFO ("state", "u"), - ), -); - -static const GDBusSignalInfo signal_info_device_added = NM_DEFINE_GDBUS_SIGNAL_INFO_INIT ( - "DeviceAdded", - .args = NM_DEFINE_GDBUS_ARG_INFOS ( - NM_DEFINE_GDBUS_ARG_INFO ("device_path", "o"), - ), -); - -static const GDBusSignalInfo signal_info_device_removed = NM_DEFINE_GDBUS_SIGNAL_INFO_INIT ( - "DeviceRemoved", - .args = NM_DEFINE_GDBUS_ARG_INFOS ( - NM_DEFINE_GDBUS_ARG_INFO ("device_path", "o"), - ), -); - -static const NMDBusInterfaceInfoExtended interface_info_manager = { - .parent = NM_DEFINE_GDBUS_INTERFACE_INFO_INIT ( - NM_DBUS_INTERFACE, - .methods = NM_DEFINE_GDBUS_METHOD_INFOS ( - NM_DEFINE_DBUS_METHOD_INFO_EXTENDED ( - NM_DEFINE_GDBUS_METHOD_INFO_INIT ( - "Reload", - .in_args = NM_DEFINE_GDBUS_ARG_INFOS ( - NM_DEFINE_GDBUS_ARG_INFO ("flags", "u"), - ), - ), - .handle = impl_manager_reload, - ), - NM_DEFINE_DBUS_METHOD_INFO_EXTENDED ( - NM_DEFINE_GDBUS_METHOD_INFO_INIT ( - "GetDevices", - .out_args = NM_DEFINE_GDBUS_ARG_INFOS ( - NM_DEFINE_GDBUS_ARG_INFO ("devices", "ao"), - ), - ), - .handle = impl_manager_get_devices, - ), - NM_DEFINE_DBUS_METHOD_INFO_EXTENDED ( - NM_DEFINE_GDBUS_METHOD_INFO_INIT ( - "GetAllDevices", - .out_args = NM_DEFINE_GDBUS_ARG_INFOS ( - NM_DEFINE_GDBUS_ARG_INFO ("devices", "ao"), - ), - ), - .handle = impl_manager_get_all_devices, - ), - NM_DEFINE_DBUS_METHOD_INFO_EXTENDED ( - NM_DEFINE_GDBUS_METHOD_INFO_INIT ( - "GetDeviceByIpIface", - .in_args = NM_DEFINE_GDBUS_ARG_INFOS ( - NM_DEFINE_GDBUS_ARG_INFO ("iface", "s"), - ), - .out_args = NM_DEFINE_GDBUS_ARG_INFOS ( - NM_DEFINE_GDBUS_ARG_INFO ("device", "o"), - ), - ), - .handle = impl_manager_get_device_by_ip_iface, - ), - NM_DEFINE_DBUS_METHOD_INFO_EXTENDED ( - NM_DEFINE_GDBUS_METHOD_INFO_INIT ( - "ActivateConnection", - .in_args = NM_DEFINE_GDBUS_ARG_INFOS ( - NM_DEFINE_GDBUS_ARG_INFO ("connection", "o"), - NM_DEFINE_GDBUS_ARG_INFO ("device", "o"), - NM_DEFINE_GDBUS_ARG_INFO ("specific_object", "o"), - ), - .out_args = NM_DEFINE_GDBUS_ARG_INFOS ( - NM_DEFINE_GDBUS_ARG_INFO ("active_connection", "o"), - ), - ), - .handle = impl_manager_activate_connection, - ), - NM_DEFINE_DBUS_METHOD_INFO_EXTENDED ( - NM_DEFINE_GDBUS_METHOD_INFO_INIT ( - "AddAndActivateConnection", - .in_args = NM_DEFINE_GDBUS_ARG_INFOS ( - NM_DEFINE_GDBUS_ARG_INFO ("connection", "a{sa{sv}}"), - NM_DEFINE_GDBUS_ARG_INFO ("device", "o"), - NM_DEFINE_GDBUS_ARG_INFO ("specific_object", "o"), - ), - .out_args = NM_DEFINE_GDBUS_ARG_INFOS ( - NM_DEFINE_GDBUS_ARG_INFO ("path", "o"), - NM_DEFINE_GDBUS_ARG_INFO ("active_connection", "o"), - ), - ), - .handle = impl_manager_add_and_activate_connection, - ), - NM_DEFINE_DBUS_METHOD_INFO_EXTENDED ( - NM_DEFINE_GDBUS_METHOD_INFO_INIT ( - "DeactivateConnection", - .in_args = NM_DEFINE_GDBUS_ARG_INFOS ( - NM_DEFINE_GDBUS_ARG_INFO ("active_connection", "o"), - ), - ), - .handle = impl_manager_deactivate_connection, - ), - NM_DEFINE_DBUS_METHOD_INFO_EXTENDED ( - NM_DEFINE_GDBUS_METHOD_INFO_INIT ( - "Sleep", - .in_args = NM_DEFINE_GDBUS_ARG_INFOS ( - NM_DEFINE_GDBUS_ARG_INFO ("sleep", "b"), - ), - ), - .handle = impl_manager_sleep, - ), - NM_DEFINE_DBUS_METHOD_INFO_EXTENDED ( - NM_DEFINE_GDBUS_METHOD_INFO_INIT ( - "Enable", - .in_args = NM_DEFINE_GDBUS_ARG_INFOS ( - NM_DEFINE_GDBUS_ARG_INFO ("enable", "b"), - ), - ), - .handle = impl_manager_enable, - ), - NM_DEFINE_DBUS_METHOD_INFO_EXTENDED ( - NM_DEFINE_GDBUS_METHOD_INFO_INIT ( - "GetPermissions", - .out_args = NM_DEFINE_GDBUS_ARG_INFOS ( - NM_DEFINE_GDBUS_ARG_INFO ("permissions", "a{ss}"), - ), - ), - .handle = impl_manager_get_permissions, - ), - NM_DEFINE_DBUS_METHOD_INFO_EXTENDED ( - NM_DEFINE_GDBUS_METHOD_INFO_INIT ( - "SetLogging", - .in_args = NM_DEFINE_GDBUS_ARG_INFOS ( - NM_DEFINE_GDBUS_ARG_INFO ("level", "s"), - NM_DEFINE_GDBUS_ARG_INFO ("domains", "s"), - ), - ), - .handle = impl_manager_set_logging, - ), - NM_DEFINE_DBUS_METHOD_INFO_EXTENDED ( - NM_DEFINE_GDBUS_METHOD_INFO_INIT ( - "GetLogging", - .out_args = NM_DEFINE_GDBUS_ARG_INFOS ( - NM_DEFINE_GDBUS_ARG_INFO ("level", "s"), - NM_DEFINE_GDBUS_ARG_INFO ("domains", "s"), - ), - ), - .handle = impl_manager_get_logging, - ), - NM_DEFINE_DBUS_METHOD_INFO_EXTENDED ( - NM_DEFINE_GDBUS_METHOD_INFO_INIT ( - "CheckConnectivity", - .out_args = NM_DEFINE_GDBUS_ARG_INFOS ( - NM_DEFINE_GDBUS_ARG_INFO ("connectivity", "u"), - ), - ), - .handle = impl_manager_check_connectivity, - ), - NM_DEFINE_DBUS_METHOD_INFO_EXTENDED ( - NM_DEFINE_GDBUS_METHOD_INFO_INIT ( - "state", - .out_args = NM_DEFINE_GDBUS_ARG_INFOS ( - NM_DEFINE_GDBUS_ARG_INFO ("state", "u"), - ), - ), - .handle = impl_manager_state, - ), - NM_DEFINE_DBUS_METHOD_INFO_EXTENDED ( - NM_DEFINE_GDBUS_METHOD_INFO_INIT ( - "CheckpointCreate", - .in_args = NM_DEFINE_GDBUS_ARG_INFOS ( - NM_DEFINE_GDBUS_ARG_INFO ("devices", "ao"), - NM_DEFINE_GDBUS_ARG_INFO ("rollback_timeout", "u"), - NM_DEFINE_GDBUS_ARG_INFO ("flags", "u"), - ), - .out_args = NM_DEFINE_GDBUS_ARG_INFOS ( - NM_DEFINE_GDBUS_ARG_INFO ("checkpoint", "o"), - ), - ), - .handle = impl_manager_checkpoint_create, - ), - NM_DEFINE_DBUS_METHOD_INFO_EXTENDED ( - NM_DEFINE_GDBUS_METHOD_INFO_INIT ( - "CheckpointDestroy", - .in_args = NM_DEFINE_GDBUS_ARG_INFOS ( - NM_DEFINE_GDBUS_ARG_INFO ("checkpoint", "o"), - ), - ), - .handle = impl_manager_checkpoint_destroy, - ), - NM_DEFINE_DBUS_METHOD_INFO_EXTENDED ( - NM_DEFINE_GDBUS_METHOD_INFO_INIT ( - "CheckpointRollback", - .in_args = NM_DEFINE_GDBUS_ARG_INFOS ( - NM_DEFINE_GDBUS_ARG_INFO ("checkpoint", "o"), - ), - .out_args = NM_DEFINE_GDBUS_ARG_INFOS ( - NM_DEFINE_GDBUS_ARG_INFO ("result", "a{su}"), - ), - ), - .handle = impl_manager_checkpoint_rollback, - ), - NM_DEFINE_DBUS_METHOD_INFO_EXTENDED ( - NM_DEFINE_GDBUS_METHOD_INFO_INIT ( - "CheckpointAdjustRollbackTimeout", - .in_args = NM_DEFINE_GDBUS_ARG_INFOS ( - NM_DEFINE_GDBUS_ARG_INFO ("checkpoint", "o"), - NM_DEFINE_GDBUS_ARG_INFO ("add_timeout", "u"), - ), - ), - .handle = impl_manager_checkpoint_adjust_rollback_timeout, - ), - ), - .signals = NM_DEFINE_GDBUS_SIGNAL_INFOS ( - &nm_signal_info_property_changed_legacy, - &signal_info_check_permissions, - &signal_info_state_changed, - &signal_info_device_added, - &signal_info_device_removed, - ), - .properties = NM_DEFINE_GDBUS_PROPERTY_INFOS ( - NM_DEFINE_DBUS_PROPERTY_INFO_EXTENDED_READABLE_L ("Devices", "ao", NM_MANAGER_DEVICES), - NM_DEFINE_DBUS_PROPERTY_INFO_EXTENDED_READABLE_L ("AllDevices", "ao", NM_MANAGER_ALL_DEVICES), - NM_DEFINE_DBUS_PROPERTY_INFO_EXTENDED_READABLE_L ("Checkpoints", "ao", NM_MANAGER_CHECKPOINTS), - NM_DEFINE_DBUS_PROPERTY_INFO_EXTENDED_READABLE_L ("NetworkingEnabled", "b", NM_MANAGER_NETWORKING_ENABLED), - NM_DEFINE_DBUS_PROPERTY_INFO_EXTENDED_READWRITABLE_L ("WirelessEnabled", "b", NM_MANAGER_WIRELESS_ENABLED, NM_AUTH_PERMISSION_ENABLE_DISABLE_WIFI, NM_AUDIT_OP_RADIO_CONTROL), - NM_DEFINE_DBUS_PROPERTY_INFO_EXTENDED_READABLE_L ("WirelessHardwareEnabled", "b", NM_MANAGER_WIRELESS_HARDWARE_ENABLED), - NM_DEFINE_DBUS_PROPERTY_INFO_EXTENDED_READWRITABLE_L ("WwanEnabled", "b", NM_MANAGER_WWAN_ENABLED, NM_AUTH_PERMISSION_ENABLE_DISABLE_WWAN, NM_AUDIT_OP_RADIO_CONTROL), - NM_DEFINE_DBUS_PROPERTY_INFO_EXTENDED_READABLE_L ("WwanHardwareEnabled", "b", NM_MANAGER_WWAN_HARDWARE_ENABLED), - NM_DEFINE_DBUS_PROPERTY_INFO_EXTENDED_READWRITABLE_L ("WimaxEnabled", "b", NM_MANAGER_WIMAX_ENABLED, NM_AUTH_PERMISSION_ENABLE_DISABLE_WIMAX, NM_AUDIT_OP_RADIO_CONTROL), - NM_DEFINE_DBUS_PROPERTY_INFO_EXTENDED_READABLE_L ("WimaxHardwareEnabled", "b", NM_MANAGER_WIMAX_HARDWARE_ENABLED), - NM_DEFINE_DBUS_PROPERTY_INFO_EXTENDED_READABLE_L ("ActiveConnections", "ao", NM_MANAGER_ACTIVE_CONNECTIONS), - NM_DEFINE_DBUS_PROPERTY_INFO_EXTENDED_READABLE_L ("PrimaryConnection", "o", NM_MANAGER_PRIMARY_CONNECTION), - NM_DEFINE_DBUS_PROPERTY_INFO_EXTENDED_READABLE_L ("PrimartConnectionType", "s", NM_MANAGER_PRIMARY_CONNECTION_TYPE), - NM_DEFINE_DBUS_PROPERTY_INFO_EXTENDED_READABLE_L ("Metered", "u", NM_MANAGER_METERED), - NM_DEFINE_DBUS_PROPERTY_INFO_EXTENDED_READABLE_L ("ActivatingConnection", "o", NM_MANAGER_ACTIVATING_CONNECTION), - NM_DEFINE_DBUS_PROPERTY_INFO_EXTENDED_READABLE_L ("Startup", "b", NM_MANAGER_STARTUP), - NM_DEFINE_DBUS_PROPERTY_INFO_EXTENDED_READABLE_L ("Version", "s", NM_MANAGER_VERSION), - NM_DEFINE_DBUS_PROPERTY_INFO_EXTENDED_READABLE_L ("Capabilities", "u", NM_MANAGER_CAPABILITIES), - NM_DEFINE_DBUS_PROPERTY_INFO_EXTENDED_READABLE_L ("State", "u", NM_MANAGER_STATE), - NM_DEFINE_DBUS_PROPERTY_INFO_EXTENDED_READABLE_L ("Connectivity", "u", NM_MANAGER_CONNECTIVITY), - NM_DEFINE_DBUS_PROPERTY_INFO_EXTENDED_READABLE_L ("ConnectivityCheckAvailable", "b", NM_MANAGER_CONNECTIVITY_CHECK_AVAILABLE), - NM_DEFINE_DBUS_PROPERTY_INFO_EXTENDED_READWRITABLE_L ("ConnectivityCheckEnabled", "b", NM_MANAGER_CONNECTIVITY_CHECK_ENABLED, NM_AUTH_PERMISSION_ENABLE_DISABLE_CONNECTIVITY_CHECK, NM_AUDIT_OP_NET_CONTROL), - NM_DEFINE_DBUS_PROPERTY_INFO_EXTENDED_READWRITABLE_L ("GlobalDnsConfiguration", "a{sv}", NM_MANAGER_GLOBAL_DNS_CONFIGURATION, NM_AUTH_PERMISSION_SETTINGS_MODIFY_GLOBAL_DNS, NM_AUDIT_OP_NET_CONTROL), - ), - ), - .legacy_property_changed = TRUE, -}; - static void nm_manager_class_init (NMManagerClass *manager_class) { GObjectClass *object_class = G_OBJECT_CLASS (manager_class); - NMDBusObjectClass *dbus_object_class = NM_DBUS_OBJECT_CLASS (manager_class); + NMExportedObjectClass *exported_object_class = NM_EXPORTED_OBJECT_CLASS (manager_class); - dbus_object_class->export_path = NM_DBUS_EXPORT_PATH_STATIC (NM_DBUS_PATH); - dbus_object_class->interface_infos = NM_DBUS_INTERFACE_INFOS (&interface_info_manager); + exported_object_class->export_path = NM_DBUS_PATH; + /* virtual methods */ object_class->constructed = constructed; object_class->set_property = set_property; object_class->get_property = get_property; object_class->dispose = dispose; object_class->finalize = finalize; + /* properties */ obj_properties[PROP_VERSION] = g_param_spec_string (NM_MANAGER_VERSION, "", "", NULL, @@ -7216,11 +6941,11 @@ nm_manager_class_init (NMManagerClass *manager_class) G_PARAM_STATIC_STRINGS); obj_properties[PROP_CAPABILITIES] = - g_param_spec_variant (NM_MANAGER_CAPABILITIES, "", "", - G_VARIANT_TYPE ("au"), - NULL, - G_PARAM_READABLE | - G_PARAM_STATIC_STRINGS); + g_param_spec_variant (NM_MANAGER_CAPABILITIES, "", "", + G_VARIANT_TYPE ("au"), + NULL, + G_PARAM_READABLE | + G_PARAM_STATIC_STRINGS); obj_properties[PROP_STATE] = g_param_spec_uint (NM_MANAGER_STATE, "", "", @@ -7371,17 +7096,11 @@ nm_manager_class_init (NMManagerClass *manager_class) G_PARAM_READABLE | G_PARAM_STATIC_STRINGS); - obj_properties[PROP_CHECKPOINTS] = - g_param_spec_boxed (NM_MANAGER_CHECKPOINTS, "", "", - G_TYPE_STRV, - G_PARAM_READABLE | - G_PARAM_STATIC_STRINGS); - g_object_class_install_properties (object_class, _PROPERTY_ENUMS_LAST, obj_properties); /* signals */ - /* emitted only for realized devices */ + /* D-Bus exported; emitted only for realized devices */ signals[DEVICE_ADDED] = g_signal_new (NM_MANAGER_DEVICE_ADDED, G_OBJECT_CLASS_TYPE (object_class), @@ -7397,7 +7116,7 @@ nm_manager_class_init (NMManagerClass *manager_class) NULL, NULL, NULL, G_TYPE_NONE, 1, G_TYPE_OBJECT); - /* emitted only for realized devices when a device + /* D-Bus exported; emitted only for realized devices when a device * becomes unrealized or removed */ signals[DEVICE_REMOVED] = g_signal_new (NM_MANAGER_DEVICE_REMOVED, @@ -7414,6 +7133,20 @@ nm_manager_class_init (NMManagerClass *manager_class) NULL, NULL, NULL, G_TYPE_NONE, 1, G_TYPE_OBJECT); + signals[STATE_CHANGED] = + g_signal_new (NM_MANAGER_STATE_CHANGED, + G_OBJECT_CLASS_TYPE (object_class), + G_SIGNAL_RUN_FIRST, + 0, NULL, NULL, NULL, + G_TYPE_NONE, 1, G_TYPE_UINT); + + signals[CHECK_PERMISSIONS] = + g_signal_new (NM_MANAGER_CHECK_PERMISSIONS, + G_OBJECT_CLASS_TYPE (object_class), + G_SIGNAL_RUN_FIRST, + 0, NULL, NULL, NULL, + G_TYPE_NONE, 0); + signals[ACTIVE_CONNECTION_ADDED] = g_signal_new (NM_MANAGER_ACTIVE_CONNECTION_ADDED, G_OBJECT_CLASS_TYPE (object_class), @@ -7434,4 +7167,25 @@ nm_manager_class_init (NMManagerClass *manager_class) G_SIGNAL_RUN_FIRST, 0, NULL, NULL, NULL, G_TYPE_NONE, 0); + + nm_exported_object_class_add_interface (NM_EXPORTED_OBJECT_CLASS (manager_class), + NMDBUS_TYPE_MANAGER_SKELETON, + "Reload", impl_manager_reload, + "GetDevices", impl_manager_get_devices, + "GetAllDevices", impl_manager_get_all_devices, + "GetDeviceByIpIface", impl_manager_get_device_by_ip_iface, + "ActivateConnection", impl_manager_activate_connection, + "AddAndActivateConnection", impl_manager_add_and_activate_connection, + "DeactivateConnection", impl_manager_deactivate_connection, + "Sleep", impl_manager_sleep, + "Enable", impl_manager_enable, + "GetPermissions", impl_manager_get_permissions, + "SetLogging", impl_manager_set_logging, + "GetLogging", impl_manager_get_logging, + "CheckConnectivity", impl_manager_check_connectivity, + "state", impl_manager_get_state, + "CheckpointCreate", impl_manager_checkpoint_create, + "CheckpointDestroy", impl_manager_checkpoint_destroy, + "CheckpointRollback", impl_manager_checkpoint_rollback, + NULL); } diff --git a/src/nm-manager.h b/src/nm-manager.h index 54444532..da838532 100644 --- a/src/nm-manager.h +++ b/src/nm-manager.h @@ -22,9 +22,9 @@ #ifndef __NETWORKMANAGER_MANAGER_H__ #define __NETWORKMANAGER_MANAGER_H__ +#include "nm-exported-object.h" #include "settings/nm-settings-connection.h" -#include "c-list/src/c-list.h" -#include "nm-dbus-manager.h" +#include "nm-utils/c-list.h" #define NM_TYPE_MANAGER (nm_manager_get_type ()) #define NM_MANAGER(obj) (G_TYPE_CHECK_INSTANCE_CAST ((obj), NM_TYPE_MANAGER, NMManager)) @@ -55,16 +55,18 @@ #define NM_MANAGER_METERED "metered" #define NM_MANAGER_GLOBAL_DNS_CONFIGURATION "global-dns-configuration" #define NM_MANAGER_ALL_DEVICES "all-devices" -#define NM_MANAGER_CHECKPOINTS "checkpoints" /* Not exported */ #define NM_MANAGER_SLEEPING "sleeping" -/* Signals */ +/* signals */ +#define NM_MANAGER_CHECK_PERMISSIONS "check-permissions" #define NM_MANAGER_DEVICE_ADDED "device-added" #define NM_MANAGER_DEVICE_REMOVED "device-removed" +#define NM_MANAGER_STATE_CHANGED "state-changed" #define NM_MANAGER_USER_PERMISSIONS_CHANGED "user-permissions-changed" +/* Internal signals */ #define NM_MANAGER_ACTIVE_CONNECTION_ADDED "active-connection-added" #define NM_MANAGER_ACTIVE_CONNECTION_REMOVED "active-connection-removed" #define NM_MANAGER_CONFIGURE_QUIT "configure-quit" @@ -83,14 +85,13 @@ gboolean nm_manager_start (NMManager *manager, GError **error); void nm_manager_stop (NMManager *manager); NMState nm_manager_get_state (NMManager *manager); - const CList * nm_manager_get_active_connections (NMManager *manager); #define nm_manager_for_each_active_connection(manager, iter, tmp_list) \ for (tmp_list = nm_manager_get_active_connections (manager), \ iter = c_list_entry (tmp_list->next, NMActiveConnection, active_connections_lst); \ ({ \ - const gboolean _has_next = (&iter->active_connections_lst != tmp_list); \ + gboolean _has_next = (&iter->active_connections_lst != tmp_list); \ \ if (!_has_next) \ iter = NULL; \ @@ -106,19 +107,7 @@ void nm_manager_write_device_state (NMManager *manager); /* Device handling */ -const CList * nm_manager_get_devices (NMManager *manager); - -#define nm_manager_for_each_device(manager, iter, tmp_list) \ - for (tmp_list = nm_manager_get_devices (manager), \ - iter = c_list_entry (tmp_list->next, NMDevice, devices_lst); \ - ({ \ - const gboolean _has_next = (&iter->devices_lst != tmp_list); \ - \ - if (!_has_next) \ - iter = NULL; \ - _has_next; \ - }); \ - iter = c_list_entry (iter->devices_lst.next, NMDevice, devices_lst)) +const GSList * nm_manager_get_devices (NMManager *manager); NMDevice * nm_manager_get_device_by_ifindex (NMManager *manager, int ifindex); @@ -164,13 +153,4 @@ gboolean nm_manager_remove_device (NMManager *self, const char *ifname, NMDeviceType device_type); -void nm_manager_dbus_set_property_handle (NMDBusObject *obj, - const NMDBusInterfaceInfoExtended *interface_info, - const NMDBusPropertyInfoExtended *property_info, - GDBusConnection *connection, - const char *sender, - GDBusMethodInvocation *invocation, - GVariant *value, - gpointer user_data); - #endif /* __NETWORKMANAGER_MANAGER_H__ */ diff --git a/src/nm-netns.c b/src/nm-netns.c index 5952a490..96ab2b35 100644 --- a/src/nm-netns.c +++ b/src/nm-netns.c @@ -38,6 +38,7 @@ NM_GOBJECT_PROPERTIES_DEFINE_BASE ( typedef struct { NMPlatform *platform; NMPNetns *platform_netns; + bool log_with_ptr; } NMNetnsPrivate; struct _NMNetns { @@ -112,10 +113,13 @@ constructed (GObject *object) { NMNetns *self = NM_NETNS (object); NMNetnsPrivate *priv = NM_NETNS_GET_PRIVATE (self); + gboolean log_with_ptr; if (!priv->platform) g_return_if_reached (); + log_with_ptr = nm_platform_get_log_with_ptr (priv->platform); + priv->platform_netns = nm_platform_netns_get (priv->platform); G_OBJECT_CLASS (nm_netns_parent_class)->constructed (object); diff --git a/src/nm-pacrunner-manager.c b/src/nm-pacrunner-manager.c index caae8b20..36f517a2 100644 --- a/src/nm-pacrunner-manager.c +++ b/src/nm-pacrunner-manager.c @@ -27,7 +27,7 @@ #include "nm-proxy-config.h" #include "nm-ip4-config.h" #include "nm-ip6-config.h" -#include "c-list/src/c-list.h" +#include "nm-utils/c-list.h" #define PACRUNNER_DBUS_SERVICE "org.pacrunner" #define PACRUNNER_DBUS_INTERFACE "org.pacrunner.Manager" @@ -466,18 +466,19 @@ static void pacrunner_remove_done (GObject *source, GAsyncResult *res, gpointer user_data) { Config *config = user_data; + NMPacrunnerManager *self; gs_free_error GError *error = NULL; gs_unref_variant GVariant *ret = NULL; ret = g_dbus_proxy_call_finish (G_DBUS_PROXY (source), res, &error); - if (!ret) { - if (!g_error_matches (error, G_IO_ERROR, G_IO_ERROR_CANCELLED)) - goto out; - _LOG2D (config, "remove failed: %s", error->message); + if (!g_error_matches (error, G_IO_ERROR, G_IO_ERROR_CANCELLED)) goto out; - } - _LOG2D (config, "removed"); + self = NM_PACRUNNER_MANAGER (config->manager_maybe_dangling); + if (!ret) + _LOG2D (config, "remove failed: %s", error->message); + else + _LOG2D (config, "removed"); out: config_unref (config); diff --git a/src/nm-policy.c b/src/nm-policy.c index 55b6caf6..2bf25d50 100644 --- a/src/nm-policy.c +++ b/src/nm-policy.c @@ -337,7 +337,7 @@ device_ip6_prefix_delegated (NMDevice *device, /* Allocate a delegation delegation for new prefix. */ g_array_set_size (priv->ip6_prefix_delegations, i + 1); delegation = &g_array_index (priv->ip6_prefix_delegations, IP6PrefixDelegation, i); - delegation->subnets = g_hash_table_new (nm_direct_hash, NULL); + delegation->subnets = g_hash_table_new (NULL, NULL); delegation->next_subnet = 0; } @@ -385,8 +385,7 @@ get_best_ip_device (NMPolicy *self, gboolean fully_activated) { NMPolicyPrivate *priv = NM_POLICY_GET_PRIVATE (self); - const CList *tmp_lst; - NMDevice *device; + const GSList *iter; NMDevice *best_device; NMDevice *prev_device; guint32 best_metric = G_MAXUINT32; @@ -401,7 +400,8 @@ get_best_ip_device (NMPolicy *self, ? (fully_activated ? priv->default_device4 : priv->activating_device4) : (fully_activated ? priv->default_device6 : priv->activating_device6); - nm_manager_for_each_device (priv->manager, device, tmp_lst) { + for (iter = nm_manager_get_devices (priv->manager); iter; iter = iter->next) { + NMDevice *device = NM_DEVICE (iter->data); NMDeviceState state; const NMPObject *r; NMConnection *connection; @@ -418,7 +418,7 @@ get_best_ip_device (NMPolicy *self, r = nm_device_get_best_default_route (device, addr_family); if (r) { - /* NOTE: the best route might have rt_source NM_IP_CONFIG_SOURCE_VPN, + /* XXX: the best route might have rt_source NM_IP_CONFIG_SOURCE_VPN, * which means it was injected by a VPN, not added by device. * * In this case, is it really the best device? Why do we even need the best @@ -461,15 +461,15 @@ static gboolean all_devices_not_active (NMPolicy *self) { NMPolicyPrivate *priv = NM_POLICY_GET_PRIVATE (self); - const CList *tmp_lst; - NMDevice *device; + const GSList *iter = nm_manager_get_devices (priv->manager); - nm_manager_for_each_device (priv->manager, device, tmp_lst) { + while (iter != NULL) { NMDeviceState state; - state = nm_device_get_state (device); + state = nm_device_get_state (NM_DEVICE (iter->data)); if ( state <= NM_DEVICE_STATE_DISCONNECTED || state >= NM_DEVICE_STATE_DEACTIVATING) { + iter = g_slist_next (iter); continue; } return FALSE; @@ -1065,19 +1065,22 @@ update_ip_dns (NMPolicy *self, int addr_family) gpointer ip_config; const char *ip_iface = NULL; NMVpnConnection *vpn = NULL; + NMDnsIPConfigType dns_type = NM_DNS_IP_CONFIG_TYPE_BEST_DEVICE; nm_assert_addr_family (addr_family); ip_config = get_best_ip_config (self, addr_family, &ip_iface, NULL, NULL, &vpn); if (ip_config) { + if (vpn) + dns_type = NM_DNS_IP_CONFIG_TYPE_VPN; + /* Tell the DNS manager this config is preferred by re-adding it with * a different IP config type. */ - nm_dns_manager_set_ip_config (NM_POLICY_GET_PRIVATE (self)->dns_manager, + nm_dns_manager_add_ip_config (NM_POLICY_GET_PRIVATE (self)->dns_manager, + ip_iface, ip_config, - vpn - ? NM_DNS_IP_CONFIG_TYPE_VPN - : NM_DNS_IP_CONFIG_TYPE_BEST_DEVICE); + dns_type); } if (addr_family == AF_INET6) @@ -1192,7 +1195,7 @@ auto_activate_device (NMPolicy *self, gs_free NMSettingsConnection **connections = NULL; guint i, len; gs_free_error GError *error = NULL; - gs_unref_object NMAuthSubject *subject = NULL; + NMAuthSubject *subject; NMActiveConnection *ac; nm_assert (NM_IS_POLICY (self)); @@ -1269,11 +1272,13 @@ auto_activate_device (NMPolicy *self, * activation fails in early stages without changing device * state. */ - if (g_hash_table_add (priv->pending_active_connections, ac)) { + if (nm_g_hash_table_add (priv->pending_active_connections, ac)) { g_signal_connect (ac, NM_ACTIVE_CONNECTION_STATE_CHANGED, G_CALLBACK (pending_ac_state_changed), g_object_ref (self)); g_object_weak_ref (G_OBJECT (ac), (GWeakNotify) pending_ac_gone, self); } + + g_object_unref (subject); } static gboolean @@ -1357,7 +1362,7 @@ process_secondaries (NMPolicy *self, if (connected) { _LOGD (LOGD_DEVICE, "secondary connection '%s' succeeded; active path '%s'", nm_active_connection_get_settings_connection_id (active), - nm_dbus_object_get_path (NM_DBUS_OBJECT (active))); + nm_exported_object_get_path (NM_EXPORTED_OBJECT (active))); /* Secondary connection activated */ secondary_data->secondaries = g_slist_remove (secondary_data->secondaries, secondary_active); @@ -1373,7 +1378,7 @@ process_secondaries (NMPolicy *self, } else { _LOGD (LOGD_DEVICE, "secondary connection '%s' failed; active path '%s'", nm_active_connection_get_settings_connection_id (active), - nm_dbus_object_get_path (NM_DBUS_OBJECT (active))); + nm_exported_object_get_path (NM_EXPORTED_OBJECT (active))); /* Secondary connection failed -> do not watch other connections */ priv->pending_secondaries = g_slist_remove (priv->pending_secondaries, secondary_data); @@ -1669,7 +1674,7 @@ activate_secondary_connections (NMPolicy *self, ac = nm_manager_activate_connection (priv->manager, settings_con, NULL, - nm_dbus_object_get_path (NM_DBUS_OBJECT (req)), + nm_exported_object_get_path (NM_EXPORTED_OBJECT (req)), device, nm_active_connection_get_subject (NM_ACTIVE_CONNECTION (req)), NM_ACTIVATION_TYPE_MANAGED, @@ -1708,6 +1713,7 @@ device_state_changed (NMDevice *device, NMPolicy *self = _PRIV_TO_SELF (priv); NMActiveConnection *ac; NMSettingsConnection *connection = nm_device_get_settings_connection (device); + const char *ip_iface = nm_device_get_ip_iface (device); NMIP4Config *ip4_config; NMIP6Config *ip6_config; NMSettingConnection *s_con = NULL; @@ -1804,10 +1810,10 @@ device_state_changed (NMDevice *device, ip4_config = nm_device_get_ip4_config (device); if (ip4_config) - nm_dns_manager_set_ip_config (priv->dns_manager, NM_IP_CONFIG_CAST (ip4_config), NM_DNS_IP_CONFIG_TYPE_DEFAULT); + nm_dns_manager_add_ip_config (priv->dns_manager, ip_iface, ip4_config, NM_DNS_IP_CONFIG_TYPE_DEFAULT); ip6_config = nm_device_get_ip6_config (device); if (ip6_config) - nm_dns_manager_set_ip_config (priv->dns_manager, NM_IP_CONFIG_CAST (ip6_config), NM_DNS_IP_CONFIG_TYPE_DEFAULT); + nm_dns_manager_add_ip_config (priv->dns_manager, ip_iface, ip6_config, NM_DNS_IP_CONFIG_TYPE_DEFAULT); update_routing_and_dns (self, FALSE); @@ -1900,24 +1906,50 @@ device_state_changed (NMDevice *device, } static void -device_ip_config_changed (NMDevice *device, - NMIPConfig *new_config, - NMIPConfig *old_config, - gpointer user_data) +device_ip4_config_changed (NMDevice *device, + NMIP4Config *new_config, + NMIP4Config *old_config, + gpointer user_data) { NMPolicyPrivate *priv = user_data; NMPolicy *self = _PRIV_TO_SELF (priv); - int addr_family; + const char *ip_iface = nm_device_get_ip_iface (device); - nm_assert (new_config || old_config); - nm_assert (!new_config || NM_IS_IP_CONFIG (new_config)); - nm_assert (!old_config || NM_IS_IP_CONFIG (old_config)); + nm_dns_manager_begin_updates (priv->dns_manager, __func__); - if (new_config) { - addr_family = nm_ip_config_get_addr_family (new_config); - nm_assert (!old_config || addr_family == nm_ip_config_get_addr_family (old_config)); - } else - addr_family = nm_ip_config_get_addr_family (old_config); + /* We catch already all the IP events registering on the device state changes but + * the ones where the IP changes but the device state keep stable (i.e., activated): + * ignore IP config changes but when the device is in activated state. + * Prevents unecessary changes to DNS information. + */ + if (nm_device_get_state (device) == NM_DEVICE_STATE_ACTIVATED) { + if (old_config != new_config) { + if (old_config) + nm_dns_manager_remove_ip_config (priv->dns_manager, old_config); + if (new_config) + nm_dns_manager_add_ip_config (priv->dns_manager, ip_iface, new_config, NM_DNS_IP_CONFIG_TYPE_DEFAULT); + } + update_ip_dns (self, AF_INET); + update_ip4_routing (self, TRUE); + update_system_hostname (self, "ip4 conf"); + } else { + /* Old configs get removed immediately */ + if (old_config) + nm_dns_manager_remove_ip_config (priv->dns_manager, old_config); + } + + nm_dns_manager_end_updates (priv->dns_manager, __func__); +} + +static void +device_ip6_config_changed (NMDevice *device, + NMIP6Config *new_config, + NMIP6Config *old_config, + gpointer user_data) +{ + NMPolicyPrivate *priv = user_data; + NMPolicy *self = _PRIV_TO_SELF (priv); + const char *ip_iface = nm_device_get_ip_iface (device); nm_dns_manager_begin_updates (priv->dns_manager, __func__); @@ -1928,24 +1960,18 @@ device_ip_config_changed (NMDevice *device, */ if (nm_device_get_state (device) == NM_DEVICE_STATE_ACTIVATED) { if (old_config != new_config) { - if (new_config) - nm_dns_manager_set_ip_config (priv->dns_manager, new_config, NM_DNS_IP_CONFIG_TYPE_DEFAULT); if (old_config) - nm_dns_manager_set_ip_config (priv->dns_manager, old_config, NM_DNS_IP_CONFIG_TYPE_REMOVED); + nm_dns_manager_remove_ip_config (priv->dns_manager, old_config); + if (new_config) + nm_dns_manager_add_ip_config (priv->dns_manager, ip_iface, new_config, NM_DNS_IP_CONFIG_TYPE_DEFAULT); } - update_ip_dns (self, addr_family); - if (addr_family == AF_INET) - update_ip4_routing (self, TRUE); - else - update_ip6_routing (self, TRUE); - update_system_hostname (self, - addr_family == AF_INET - ? "ip4 conf" - : "ip6 conf"); + update_ip_dns (self, AF_INET6); + update_ip6_routing (self, TRUE); + update_system_hostname (self, "ip6 conf"); } else { /* Old configs get removed immediately */ if (old_config) - nm_dns_manager_set_ip_config (priv->dns_manager, old_config, NM_DNS_IP_CONFIG_TYPE_REMOVED); + nm_dns_manager_remove_ip_config (priv->dns_manager, old_config); } nm_dns_manager_end_updates (priv->dns_manager, __func__); @@ -1988,8 +2014,8 @@ devices_list_register (NMPolicy *self, NMDevice *device) /* Connect state-changed with _after, so that the handler is invoked after other handlers. */ g_signal_connect_after (device, NM_DEVICE_STATE_CHANGED, (GCallback) device_state_changed, priv); - g_signal_connect (device, NM_DEVICE_IP4_CONFIG_CHANGED, (GCallback) device_ip_config_changed, priv); - g_signal_connect (device, NM_DEVICE_IP6_CONFIG_CHANGED, (GCallback) device_ip_config_changed, priv); + g_signal_connect (device, NM_DEVICE_IP4_CONFIG_CHANGED, (GCallback) device_ip4_config_changed, priv); + g_signal_connect (device, NM_DEVICE_IP6_CONFIG_CHANGED, (GCallback) device_ip6_config_changed, priv); g_signal_connect (device, NM_DEVICE_IP6_PREFIX_DELEGATED, (GCallback) device_ip6_prefix_delegated, priv); g_signal_connect (device, NM_DEVICE_IP6_SUBNET_NEEDED, (GCallback) device_ip6_subnet_needed, priv); g_signal_connect (device, "notify::" NM_DEVICE_AUTOCONNECT, (GCallback) device_autoconnect_changed, priv); @@ -2006,7 +2032,7 @@ device_added (NMManager *manager, NMDevice *device, gpointer user_data) priv = NM_POLICY_GET_PRIVATE (self); - if (!g_hash_table_add (priv->devices, device)) + if (!nm_g_hash_table_add (priv->devices, device)) g_return_if_reached (); devices_list_register (self, device); @@ -2044,16 +2070,21 @@ vpn_connection_activated (NMPolicy *self, NMVpnConnection *vpn) NMPolicyPrivate *priv = NM_POLICY_GET_PRIVATE (self); NMIP4Config *ip4_config; NMIP6Config *ip6_config; + const char *ip_iface; nm_dns_manager_begin_updates (priv->dns_manager, __func__); + ip_iface = nm_vpn_connection_get_ip_iface (vpn, TRUE); + + /* Add the VPN connection's IP configs from DNS */ + ip4_config = nm_vpn_connection_get_ip4_config (vpn); if (ip4_config) - nm_dns_manager_set_ip_config (priv->dns_manager, NM_IP_CONFIG_CAST (ip4_config), NM_DNS_IP_CONFIG_TYPE_VPN); + nm_dns_manager_add_ip_config (priv->dns_manager, ip_iface, ip4_config, NM_DNS_IP_CONFIG_TYPE_VPN); ip6_config = nm_vpn_connection_get_ip6_config (vpn); if (ip6_config) - nm_dns_manager_set_ip_config (priv->dns_manager, NM_IP_CONFIG_CAST (ip6_config), NM_DNS_IP_CONFIG_TYPE_VPN); + nm_dns_manager_add_ip_config (priv->dns_manager, ip_iface, ip6_config, NM_DNS_IP_CONFIG_TYPE_VPN); update_routing_and_dns (self, TRUE); @@ -2070,12 +2101,16 @@ vpn_connection_deactivated (NMPolicy *self, NMVpnConnection *vpn) nm_dns_manager_begin_updates (priv->dns_manager, __func__); ip4_config = nm_vpn_connection_get_ip4_config (vpn); - if (ip4_config) - nm_dns_manager_set_ip_config (priv->dns_manager, NM_IP_CONFIG_CAST (ip4_config), NM_DNS_IP_CONFIG_TYPE_REMOVED); + if (ip4_config) { + /* Remove the VPN connection's IP4 config from DNS */ + nm_dns_manager_remove_ip_config (priv->dns_manager, ip4_config); + } ip6_config = nm_vpn_connection_get_ip6_config (vpn); - if (ip6_config) - nm_dns_manager_set_ip_config (priv->dns_manager, NM_IP_CONFIG_CAST (ip6_config), NM_DNS_IP_CONFIG_TYPE_REMOVED); + if (ip6_config) { + /* Remove the VPN connection's IP6 config from DNS */ + nm_dns_manager_remove_ip_config (priv->dns_manager, ip6_config); + } update_routing_and_dns (self, TRUE); @@ -2185,13 +2220,12 @@ schedule_activate_all_cb (gpointer user_data) { NMPolicy *self = user_data; NMPolicyPrivate *priv = NM_POLICY_GET_PRIVATE (self); - const CList *tmp_lst; - NMDevice *device; + const GSList *iter; priv->schedule_activate_all_id = 0; - nm_manager_for_each_device (priv->manager, device, tmp_lst) - schedule_activate_check (self, device); + for (iter = nm_manager_get_devices (priv->manager); iter; iter = g_slist_next (iter)) + schedule_activate_check (self, iter->data); return G_SOURCE_REMOVE; } @@ -2225,8 +2259,7 @@ firewall_state_changed (NMFirewallManager *manager, { NMPolicy *self = (NMPolicy *) user_data; NMPolicyPrivate *priv = NM_POLICY_GET_PRIVATE (self); - const CList *tmp_lst; - NMDevice *device; + const GSList *iter; if (initialized_now) { /* the firewall manager was initializing, but all requests @@ -2239,8 +2272,8 @@ firewall_state_changed (NMFirewallManager *manager, return; /* add interface of each device to correct zone */ - nm_manager_for_each_device (priv->manager, device, tmp_lst) - nm_device_update_firewall_zone (device); + for (iter = nm_manager_get_devices (priv->manager); iter; iter = g_slist_next (iter)) + nm_device_update_firewall_zone (iter->data); } static void @@ -2285,13 +2318,14 @@ connection_updated (NMSettings *settings, { NMPolicyPrivate *priv = user_data; NMPolicy *self = _PRIV_TO_SELF (priv); - const CList *tmp_lst; + const GSList *iter; NMDevice *device = NULL; - NMDevice *dev; if (by_user) { /* find device with given connection */ - nm_manager_for_each_device (priv->manager, dev, tmp_lst) { + for (iter = nm_manager_get_devices (priv->manager); iter; iter = g_slist_next (iter)) { + NMDevice *dev = NM_DEVICE (iter->data); + if (nm_device_get_settings_connection (dev) == connection) { device = dev; break; @@ -2319,9 +2353,10 @@ _deactivate_if_active (NMPolicy *self, NMSettingsConnection *connection) nm_assert (NM_IS_SETTINGS_CONNECTION (connection)); nm_manager_for_each_active_connection (priv->manager, ac, tmp_list) { + NMActiveConnectionState state = nm_active_connection_get_state (ac); if ( nm_active_connection_get_settings_connection (ac) == connection - && (nm_active_connection_get_state (ac) <= NM_ACTIVE_CONNECTION_STATE_ACTIVATED)) { + && (state <= NM_ACTIVE_CONNECTION_STATE_ACTIVATED)) { if (!nm_manager_deactivate_connection (priv->manager, ac, NM_DEVICE_STATE_REASON_CONNECTION_REMOVED, @@ -2356,7 +2391,7 @@ connection_flags_changed (NMSettings *settings, NMPolicy *self = _PRIV_TO_SELF (priv); if (NM_FLAGS_HAS (nm_settings_connection_get_flags (connection), - NM_SETTINGS_CONNECTION_INT_FLAGS_VISIBLE)) { + NM_SETTINGS_CONNECTION_FLAGS_VISIBLE)) { if (!nm_settings_connection_autoconnect_is_blocked (connection)) schedule_activate_all (self); } else @@ -2488,8 +2523,8 @@ nm_policy_init (NMPolicy *self) else /* default - full mode */ priv->hostname_mode = NM_POLICY_HOSTNAME_MODE_FULL; - priv->devices = g_hash_table_new (nm_direct_hash, NULL); - priv->pending_active_connections = g_hash_table_new (nm_direct_hash, NULL); + priv->devices = g_hash_table_new (NULL, NULL); + priv->pending_active_connections = g_hash_table_new (NULL, NULL); priv->ip6_prefix_delegations = g_array_new (FALSE, FALSE, sizeof (IP6PrefixDelegation)); g_array_set_clear_func (priv->ip6_prefix_delegations, clear_ip6_prefix_delegation); } diff --git a/src/nm-session-monitor.c b/src/nm-session-monitor.c index 13ccbd48..e7d1d742 100644 --- a/src/nm-session-monitor.c +++ b/src/nm-session-monitor.c @@ -261,7 +261,7 @@ ck_init (NMSessionMonitor *monitor) if (g_file_query_exists (file, NULL)) { if ((monitor->ck.monitor = g_file_monitor_file (file, G_FILE_MONITOR_NONE, NULL, &error))) { - monitor->ck.cache = g_hash_table_new_full (nm_direct_hash, NULL, NULL, g_free); + monitor->ck.cache = g_hash_table_new_full (g_direct_hash, g_direct_equal, NULL, g_free); g_signal_connect (monitor->ck.monitor, "changed", G_CALLBACK (ck_changed), diff --git a/src/nm-test-utils-core.h b/src/nm-test-utils-core.h index da24992e..58beadcd 100644 --- a/src/nm-test-utils-core.h +++ b/src/nm-test-utils-core.h @@ -30,14 +30,6 @@ /*****************************************************************************/ -#define NMTST_EXPECT_NM(level, msg) NMTST_EXPECT ("NetworkManager", level, msg) - -#define NMTST_EXPECT_NM_ERROR(msg) NMTST_EXPECT_NM (G_LOG_LEVEL_MESSAGE, "*<error> [*] "msg) -#define NMTST_EXPECT_NM_WARN(msg) NMTST_EXPECT_NM (G_LOG_LEVEL_MESSAGE, "*<warn> [*] "msg) -#define NMTST_EXPECT_NM_INFO(msg) NMTST_EXPECT_NM (G_LOG_LEVEL_INFO, "*<info> [*] "msg) -#define NMTST_EXPECT_NM_DEBUG(msg) NMTST_EXPECT_NM (G_LOG_LEVEL_DEBUG, "*<debug> [*] "msg) -#define NMTST_EXPECT_NM_TRACE(msg) NMTST_EXPECT_NM (G_LOG_LEVEL_DEBUG, "*<trace> [*] "msg) - static inline void nmtst_init_with_logging (int *argc, char ***argv, const char *log_level, const char *log_domains) { @@ -321,6 +313,18 @@ nmtst_ip4_config_new (int ifindex) return nm_ip4_config_new (multi_idx, ifindex); } +static inline NMIP4Config * +nmtst_ip4_config_clone (NMIP4Config *config) +{ + NMIP4Config *copy; + + g_assert (config); + copy = nm_ip4_config_new (nm_ip4_config_get_multi_idx (config), -1); + g_assert (copy); + nm_ip4_config_replace (copy, config, NULL); + return copy; +} + #endif @@ -336,6 +340,18 @@ nmtst_ip6_config_new (int ifindex) return nm_ip6_config_new (multi_idx, ifindex); } +static inline NMIP6Config * +nmtst_ip6_config_clone (NMIP6Config *config) +{ + NMIP6Config *copy; + + g_assert (config); + copy = nm_ip6_config_new (nm_ip6_config_get_multi_idx (config), -1); + g_assert (copy); + nm_ip6_config_replace (copy, config, NULL); + return copy; +} + #endif #endif /* __NM_TEST_UTILS_CORE_H__ */ diff --git a/src/nm-types.h b/src/nm-types.h index e1991c28..794b0a1c 100644 --- a/src/nm-types.h +++ b/src/nm-types.h @@ -21,23 +21,24 @@ #ifndef __NETWORKMANAGER_TYPES_H__ #define __NETWORKMANAGER_TYPES_H__ -#if !((NETWORKMANAGER_COMPILATION) & NM_NETWORKMANAGER_COMPILATION_WITH_DAEMON) -#error Cannot use this header. +#ifdef __NM_UTILS_PRIVATE_H__ +#error "nm-utils-private.h" must not be used outside of libnm-core/. Do you want "nm-core-internal.h"? #endif #define _NM_SD_MAX_CLIENT_ID_LEN (sizeof (guint32) + 128) /* core */ -typedef struct _NMDBusObject NMDBusObject; +typedef struct _NMExportedObject NMExportedObject; typedef struct _NMActiveConnection NMActiveConnection; typedef struct _NMAuditManager NMAuditManager; typedef struct _NMVpnConnection NMVpnConnection; typedef struct _NMActRequest NMActRequest; typedef struct _NMAuthSubject NMAuthSubject; -typedef struct _NMDBusManager NMDBusManager; +typedef struct _NMBusManager NMBusManager; typedef struct _NMConfig NMConfig; typedef struct _NMConfigData NMConfigData; -typedef struct _NMAcdManager NMAcdManager; +typedef struct _NMArpingManager NMArpingManager; +typedef struct _NMConnectionProvider NMConnectionProvider; typedef struct _NMConnectivity NMConnectivity; typedef struct _NMDevice NMDevice; typedef struct _NMDhcp4Config NMDhcp4Config; @@ -101,7 +102,6 @@ typedef enum { NM_IP_CONFIG_SOURCE_KERNEL, NM_IP_CONFIG_SOURCE_SHARED, NM_IP_CONFIG_SOURCE_IP4LL, - NM_IP_CONFIG_SOURCE_IP6LL, NM_IP_CONFIG_SOURCE_PPP, NM_IP_CONFIG_SOURCE_WWAN, NM_IP_CONFIG_SOURCE_VPN, @@ -164,6 +164,7 @@ typedef enum { NM_LINK_TYPE_OPENVSWITCH, NM_LINK_TYPE_PPP, NM_LINK_TYPE_SIT, + NM_LINK_TYPE_TAP, NM_LINK_TYPE_TUN, NM_LINK_TYPE_VETH, NM_LINK_TYPE_VLAN, @@ -197,7 +198,6 @@ typedef enum { NMP_OBJECT_TYPE_LNK_MACVLAN, NMP_OBJECT_TYPE_LNK_MACVTAP, NMP_OBJECT_TYPE_LNK_SIT, - NMP_OBJECT_TYPE_LNK_TUN, NMP_OBJECT_TYPE_LNK_VLAN, NMP_OBJECT_TYPE_LNK_VXLAN, @@ -238,6 +238,4 @@ typedef struct _NMSettingsConnection NMSettingsConnection; /* utils */ typedef struct _NMUtilsIPv6IfaceId NMUtilsIPv6IfaceId; -#define NM_SETTING_CONNECTION_MDNS_UNKNOWN ((NMSettingConnectionMdns) -42) - #endif /* NM_TYPES_H */ diff --git a/src/org.freedesktop.NetworkManager.conf b/src/org.freedesktop.NetworkManager.conf index fa74b280..6be1feb6 100644 --- a/src/org.freedesktop.NetworkManager.conf +++ b/src/org.freedesktop.NetworkManager.conf @@ -30,7 +30,7 @@ <allow send_destination="org.fedoraproject.FirewallD1"/> <!-- Allow the custom name for the dnsmasq instance spawned by NM - from the dns dnsmasq plugin to own its dbus name, and for + from the dns dnsmasq plugin to own it's dbus name, and for messages to be sent to it. --> <allow own="org.freedesktop.NetworkManager.dnsmasq"/> diff --git a/src/platform/nm-fake-platform.c b/src/platform/nm-fake-platform.c index 06dd7e13..be430152 100644 --- a/src/platform/nm-fake-platform.c +++ b/src/platform/nm-fake-platform.c @@ -938,6 +938,7 @@ wifi_find_frequency (NMPlatform *platform, int ifindex, const guint32 *freqs) static void wifi_indicate_addressing_running (NMPlatform *platform, int ifindex, gboolean running) { + ; } static guint32 diff --git a/src/platform/nm-linux-platform.c b/src/platform/nm-linux-platform.c index 0ed8fa06..e5961c7e 100644 --- a/src/platform/nm-linux-platform.c +++ b/src/platform/nm-linux-platform.c @@ -21,7 +21,6 @@ #include "nm-linux-platform.h" -#include <poll.h> #include <endian.h> #include <errno.h> #include <unistd.h> @@ -37,14 +36,14 @@ #include <linux/if_link.h> #include <linux/if_tun.h> #include <linux/if_tunnel.h> -#include <linux/ip6_tunnel.h> +#include <netlink/netlink.h> +#include <netlink/msg.h> #include <libudev.h> #include "nm-utils.h" #include "nm-core-internal.h" #include "nm-setting-vlan.h" -#include "nm-netlink.h" #include "nm-core-utils.h" #include "nmp-object.h" #include "nmp-netns.h" @@ -80,6 +79,10 @@ enum { #define VLAN_FLAG_MVRP 0x8 +/* nm-internal error codes for libnl. Make sure they don't overlap. */ +#define _NLE_NM_NOBUFS 500 +#define _NLE_MSG_TRUNC 501 + /*****************************************************************************/ #define IFQDISCSIZ 32 @@ -124,18 +127,6 @@ enum { #define IFLA_IPTUN_MAX (__IFLA_IPTUN_MAX - 1) #endif -#define IFLA_TUN_UNSPEC 0 -#define IFLA_TUN_OWNER 1 -#define IFLA_TUN_GROUP 2 -#define IFLA_TUN_TYPE 3 -#define IFLA_TUN_PI 4 -#define IFLA_TUN_VNET_HDR 5 -#define IFLA_TUN_PERSIST 6 -#define IFLA_TUN_MULTI_QUEUE 7 -#define IFLA_TUN_NUM_QUEUES 8 -#define IFLA_TUN_NUM_DISABLED_QUEUES 9 -#define __IFLA_TUN_MAX 10 -#define IFLA_TUN_MAX (__IFLA_TUN_MAX - 1) static const gboolean RTA_PREF_SUPPORTED_AT_COMPILETIME = (RTA_MAX >= 20 /* RTA_PREF */); @@ -292,7 +283,7 @@ typedef enum { #define FOR_EACH_DELAYED_ACTION(iflags, flags_all) \ for ((iflags) = (DelayedActionType) 0x1LL; (iflags) <= DELAYED_ACTION_TYPE_MAX; (iflags) <<= 1) \ - if (NM_FLAGS_ANY (flags_all, iflags)) + if (NM_FLAGS_HAS (flags_all, iflags)) typedef enum { /* Negative values are errors from kernel. Add dummy member to @@ -306,9 +297,13 @@ typedef enum { WAIT_FOR_NL_RESPONSE_RESULT_FAILED_POLL, WAIT_FOR_NL_RESPONSE_RESULT_FAILED_TIMEOUT, WAIT_FOR_NL_RESPONSE_RESULT_FAILED_DISPOSING, - WAIT_FOR_NL_RESPONSE_RESULT_FAILED_SETNS, } WaitForNlResponseResult; +typedef void (*WaitForNlResponseCallback) (NMPlatform *platform, + guint32 seq_number, + WaitForNlResponseResult seq_result, + gpointer user_data); + static void delayed_action_schedule (NMPlatform *platform, DelayedActionType action_type, gpointer user_data); static gboolean delayed_action_handle_all (NMPlatform *platform, gboolean read_netlink); static void do_request_link_no_delayed_actions (NMPlatform *platform, int ifindex, const char *name); @@ -333,9 +328,7 @@ wait_for_nl_response_to_plerr (WaitForNlResponseResult seq_result) } static const char * -wait_for_nl_response_to_string (WaitForNlResponseResult seq_result, - const char *errmsg, - char *buf, gsize buf_size) +wait_for_nl_response_to_string (WaitForNlResponseResult seq_result, char *buf, gsize buf_size) { char *buf0 = buf; @@ -350,13 +343,8 @@ wait_for_nl_response_to_string (WaitForNlResponseResult seq_result, nm_utils_strbuf_append_str (&buf, &buf_size, "failure"); break; default: - if (seq_result < 0) { - nm_utils_strbuf_append (&buf, &buf_size, "failure %d (%s%s%s)", - -((int) seq_result), - g_strerror (-((int) seq_result)), - errmsg ? " - " : "", - errmsg ?: ""); - } + if (seq_result < 0) + nm_utils_strbuf_append (&buf, &buf_size, "failure %d (%s)", -((int) seq_result), g_strerror (-((int) seq_result))); else nm_utils_strbuf_append (&buf, &buf_size, "internal failure %d", (int) seq_result); break; @@ -550,7 +538,8 @@ static const LinkDesc linktypes[] = { { NM_LINK_TYPE_OPENVSWITCH, "openvswitch", "openvswitch", NULL }, { NM_LINK_TYPE_PPP, "ppp", NULL, "ppp" }, { NM_LINK_TYPE_SIT, "sit", "sit", NULL }, - { NM_LINK_TYPE_TUN, "tun", "tun", NULL }, + { NM_LINK_TYPE_TAP, "tap", NULL, NULL }, + { NM_LINK_TYPE_TUN, "tun", NULL, NULL }, { NM_LINK_TYPE_VETH, "veth", "veth", NULL }, { NM_LINK_TYPE_VLAN, "vlan", "vlan", "vlan" }, { NM_LINK_TYPE_VXLAN, "vxlan", "vxlan", "vxlan" }, @@ -811,25 +800,36 @@ _linktype_get_type (NMPlatform *platform, && !NM_IN_SET (obj->link.type, NM_LINK_TYPE_UNKNOWN, NM_LINK_TYPE_NONE) && nm_streq (ifname, obj->link.name) && ( !kind - || nm_streq0 (kind, obj->link.kind))) { + || !g_strcmp0 (kind, obj->link.kind))) { nm_assert (obj->link.kind == g_intern_string (obj->link.kind)); *out_kind = obj->link.kind; return obj->link.type; } } - /* we intern kind to not require us to keep the pointer alive. Essentially - * leaking it in a global cache. That should be safe enough, because the - * kind comes only from kernel messages, which depend on the number of - * available drivers. So, there is not the danger that we leak uncontrolled - * many kinds. */ *out_kind = g_intern_string (kind); if (kind) { for (i = 0; i < G_N_ELEMENTS (linktypes); i++) { - if (nm_streq0 (kind, linktypes[i].rtnl_type)) { + if (g_strcmp0 (kind, linktypes[i].rtnl_type) == 0) return linktypes[i].nm_type; + } + + if (!strcmp (kind, "tun")) { + NMPlatformTunProperties props; + + if ( platform + && nm_platform_link_tun_get_properties (platform, ifindex, &props)) { + if (!g_strcmp0 (props.mode, "tap")) + return NM_LINK_TYPE_TAP; + if (!g_strcmp0 (props.mode, "tun")) + return NM_LINK_TYPE_TUN; } + + /* try guessing the type using the link flags instead... */ + if (flags & IFF_POINTOPOINT) + return NM_LINK_TYPE_TUN; + return NM_LINK_TYPE_TAP; } } @@ -951,6 +951,137 @@ _nl_addattr_l (struct nlmsghdr *n, return TRUE; } +static void +_nm_auto_nl_msg_cleanup (void *ptr) +{ + nlmsg_free (*((struct nl_msg **) ptr)); +} +#define nm_auto_nlmsg nm_auto(_nm_auto_nl_msg_cleanup) + +static const char * +_nl_nlmsghdr_to_str (const struct nlmsghdr *hdr, char *buf, gsize len) +{ + const char *b; + const char *s; + guint flags, flags_before; + const char *prefix; + + nm_utils_to_string_buffer_init (&buf, &len); + b = buf; + + switch (hdr->nlmsg_type) { + case RTM_NEWLINK: s = "RTM_NEWLINK"; break; + case RTM_DELLINK: s = "RTM_DELLINK"; break; + case RTM_NEWADDR: s = "RTM_NEWADDR"; break; + case RTM_DELADDR: s = "RTM_DELADDR"; break; + case RTM_NEWROUTE: s = "RTM_NEWROUTE"; break; + case RTM_DELROUTE: s = "RTM_DELROUTE"; break; + case RTM_NEWQDISC: s = "RTM_NEWQDISC"; break; + case RTM_DELQDISC: s = "RTM_DELQDISC"; break; + case RTM_NEWTFILTER: s = "RTM_NEWTFILTER"; break; + case RTM_DELTFILTER: s = "RTM_DELTFILTER"; break; + case NLMSG_NOOP: s = "NLMSG_NOOP"; break; + case NLMSG_ERROR: s = "NLMSG_ERROR"; break; + case NLMSG_DONE: s = "NLMSG_DONE"; break; + case NLMSG_OVERRUN: s = "NLMSG_OVERRUN"; break; + default: s = NULL; break; + } + + if (s) + nm_utils_strbuf_append_str (&buf, &len, s); + else + nm_utils_strbuf_append (&buf, &len, "(%u)", (unsigned) hdr->nlmsg_type); + + flags = hdr->nlmsg_flags; + + if (!flags) { + nm_utils_strbuf_append_str (&buf, &len, ", flags 0"); + goto flags_done; + } + +#define _F(f, n) \ + G_STMT_START { \ + if (NM_FLAGS_ALL (flags, f)) { \ + flags &= ~(f); \ + nm_utils_strbuf_append (&buf, &len, "%s%s", prefix, n); \ + if (!flags) \ + goto flags_done; \ + prefix = ","; \ + } \ + } G_STMT_END + + prefix = ", flags "; + flags_before = flags; + _F (NLM_F_REQUEST, "request"); + _F (NLM_F_MULTI, "multi"); + _F (NLM_F_ACK, "ack"); + _F (NLM_F_ECHO, "echo"); + _F (NLM_F_DUMP_INTR, "dump_intr"); + _F (0x20 /*NLM_F_DUMP_FILTERED*/, "dump_filtered"); + + if (flags_before != flags) + prefix = ";"; + + switch (hdr->nlmsg_type) { + case RTM_NEWLINK: + case RTM_NEWADDR: + case RTM_NEWROUTE: + case RTM_NEWQDISC: + case RTM_NEWTFILTER: + _F (NLM_F_REPLACE, "replace"); + _F (NLM_F_EXCL, "excl"); + _F (NLM_F_CREATE, "create"); + _F (NLM_F_APPEND, "append"); + break; + case RTM_GETLINK: + case RTM_GETADDR: + case RTM_GETROUTE: + case RTM_DELQDISC: + case RTM_DELTFILTER: + _F (NLM_F_DUMP, "dump"); + _F (NLM_F_ROOT, "root"); + _F (NLM_F_MATCH, "match"); + _F (NLM_F_ATOMIC, "atomic"); + break; + } + +#undef _F + + if (flags_before != flags) + prefix = ";"; + nm_utils_strbuf_append (&buf, &len, "%s0x%04x", prefix, flags); + +flags_done: + + nm_utils_strbuf_append (&buf, &len, ", seq %u", (unsigned) hdr->nlmsg_seq); + + return b; +} + +static int +_nl_nla_parse (struct nlattr *tb[], int maxtype, struct nlattr *head, int len, + const struct nla_policy *policy) +{ + return nla_parse (tb, maxtype, head, len, (struct nla_policy *) policy); +} +#define nla_parse(...) _nl_nla_parse(__VA_ARGS__) + +static int +_nl_nlmsg_parse (struct nlmsghdr *nlh, int hdrlen, struct nlattr *tb[], + int maxtype, const struct nla_policy *policy) +{ + return nlmsg_parse (nlh, hdrlen, tb, maxtype, (struct nla_policy *) policy); +} +#define nlmsg_parse(...) _nl_nlmsg_parse(__VA_ARGS__) + +static int +_nl_nla_parse_nested (struct nlattr *tb[], int maxtype, struct nlattr *nla, + const struct nla_policy *policy) +{ + return nla_parse_nested (tb, maxtype, nla, (struct nla_policy *) policy); +} +#define nla_parse_nested(...) _nl_nla_parse_nested(__VA_ARGS__) + /****************************************************************** * NMPObject/netlink functions ******************************************************************/ @@ -1161,7 +1292,6 @@ _parse_lnk_ip6tnl (const char *kind, struct nlattr *info_data) [IFLA_IPTUN_ENCAP_LIMIT] = { .type = NLA_U8 }, [IFLA_IPTUN_FLOWINFO] = { .type = NLA_U32 }, [IFLA_IPTUN_PROTO] = { .type = NLA_U8 }, - [IFLA_IPTUN_FLAGS] = { .type = NLA_U32 }, }; struct nlattr *tb[IFLA_IPTUN_MAX + 1]; int err; @@ -1196,8 +1326,6 @@ _parse_lnk_ip6tnl (const char *kind, struct nlattr *info_data) } if (tb[IFLA_IPTUN_PROTO]) props->proto = nla_get_u8 (tb[IFLA_IPTUN_PROTO]); - if (tb[IFLA_IPTUN_FLAGS]) - props->flags = nla_get_u32 (tb[IFLA_IPTUN_FLAGS]); return obj; } @@ -1377,60 +1505,6 @@ _parse_lnk_sit (const char *kind, struct nlattr *info_data) /*****************************************************************************/ -static NMPObject * -_parse_lnk_tun (const char *kind, struct nlattr *info_data) -{ - static const struct nla_policy policy[IFLA_TUN_MAX + 1] = { - [IFLA_TUN_OWNER] = { .type = NLA_U32 }, - [IFLA_TUN_GROUP] = { .type = NLA_U32 }, - [IFLA_TUN_TYPE] = { .type = NLA_U8 }, - [IFLA_TUN_PI] = { .type = NLA_U8 }, - [IFLA_TUN_VNET_HDR] = { .type = NLA_U8 }, - [IFLA_TUN_PERSIST] = { .type = NLA_U8 }, - [IFLA_TUN_MULTI_QUEUE] = { .type = NLA_U8 }, - [IFLA_TUN_NUM_QUEUES] = { .type = NLA_U32 }, - [IFLA_TUN_NUM_DISABLED_QUEUES] = { .type = NLA_U32 }, - }; - struct nlattr *tb[IFLA_TUN_MAX + 1]; - int err; - NMPObject *obj; - NMPlatformLnkTun *props; - - if (!info_data || !nm_streq0 (kind, "tun")) - return NULL; - - err = nla_parse_nested (tb, IFLA_TUN_MAX, info_data, policy); - if (err < 0) - return NULL; - - if (!tb[IFLA_TUN_TYPE]) { - /* we require at least a type. */ - return NULL; - } - - obj = nmp_object_new (NMP_OBJECT_TYPE_LNK_TUN, NULL); - props = &obj->lnk_tun; - - props->type = nla_get_u8 (tb[IFLA_TUN_TYPE]); - - props->pi = !!nla_get_u8_cond (tb, IFLA_TUN_PI, FALSE); - props->vnet_hdr = !!nla_get_u8_cond (tb, IFLA_TUN_VNET_HDR, FALSE); - props->multi_queue = !!nla_get_u8_cond (tb, IFLA_TUN_MULTI_QUEUE, FALSE); - props->persist = !!nla_get_u8_cond (tb, IFLA_TUN_PERSIST, FALSE); - - if (tb[IFLA_TUN_OWNER]) { - props->owner_valid = TRUE; - props->owner = nla_get_u32 (tb[IFLA_TUN_OWNER]); - } - if (tb[IFLA_TUN_GROUP]) { - props->group_valid = TRUE; - props->group = nla_get_u32 (tb[IFLA_TUN_GROUP]); - } - return obj; -} - -/*****************************************************************************/ - static gboolean _vlan_qos_mapping_from_nla (struct nlattr *nlattr, const NMVlanQosMapping **out_map, @@ -1862,9 +1936,6 @@ _new_from_nl_link (NMPlatform *platform, const NMPCache *cache, struct nlmsghdr case NM_LINK_TYPE_SIT: lnk_data = _parse_lnk_sit (nl_info_kind, nl_info_data); break; - case NM_LINK_TYPE_TUN: - lnk_data = _parse_lnk_tun (nl_info_kind, nl_info_data); - break; case NM_LINK_TYPE_VLAN: lnk_data = _parse_lnk_vlan (nl_info_kind, nl_info_data); break; @@ -2594,7 +2665,8 @@ _nl_msg_new_link (int nlmsg_type, nm_assert (NM_IN_SET (nlmsg_type, RTM_DELLINK, RTM_NEWLINK, RTM_GETLINK)); - msg = nlmsg_alloc_simple (nlmsg_type, nlmsg_flags); + if (!(msg = nlmsg_alloc_simple (nlmsg_type, nlmsg_flags))) + g_return_val_if_reached (NULL); if (nlmsg_append (msg, &ifi, sizeof (ifi), NLMSG_ALIGNTO) < 0) goto nla_put_failure; @@ -2636,6 +2708,8 @@ _nl_msg_new_address (int nlmsg_type, nm_assert (NM_IN_SET (nlmsg_type, RTM_NEWADDR, RTM_DELADDR)); msg = nlmsg_alloc_simple (nlmsg_type, nlmsg_flags); + if (!msg) + g_return_val_if_reached (NULL); if (scope == -1) { /* Allow having scope unset, and detect the scope (including IPv4 compatibility hack). */ @@ -2748,6 +2822,8 @@ _nl_msg_new_route (int nlmsg_type, nm_assert (NM_IN_SET (nlmsg_type, RTM_NEWROUTE, RTM_DELROUTE)); msg = nlmsg_alloc_simple (nlmsg_type, (int) nlmsgflags); + if (!msg) + g_return_val_if_reached (NULL); if (nlmsg_append (msg, &rtmsg, sizeof (rtmsg), NLMSG_ALIGNTO) < 0) goto nla_put_failure; @@ -2845,6 +2921,8 @@ _nl_msg_new_qdisc (int nlmsg_type, }; msg = nlmsg_alloc_simple (nlmsg_type, nlmsg_flags); + if (!msg) + return NULL; if (nlmsg_append (msg, &tcm, sizeof (tcm), NLMSG_ALIGNTO) < 0) goto nla_put_failure; @@ -2919,6 +2997,8 @@ _nl_msg_new_tfilter (int nlmsg_type, }; msg = nlmsg_alloc_simple (nlmsg_type, nlmsg_flags); + if (!msg) + return NULL; if (nlmsg_append (msg, &tcm, sizeof (tcm), NLMSG_ALIGNTO) < 0) goto nla_put_failure; @@ -2960,7 +3040,6 @@ typedef struct { DelayedActionWaitForNlResponseType response_type; gint64 timeout_abs_ns; WaitForNlResponseResult *out_seq_result; - char **out_errmsg; union { gint *out_refresh_all_in_progess; NMPObject **out_route_get; @@ -3421,7 +3500,7 @@ delayed_action_to_string_full (DelayedActionType action_type, gpointer user_data (timeout < 0 ? -timeout : timeout) % NM_UTILS_NS_PER_SECOND, (int) data->response_type, data->seq_result ? ", " : "", - data->seq_result ? wait_for_nl_response_to_string (data->seq_result, NULL, b, sizeof (b)) : ""); + data->seq_result ? wait_for_nl_response_to_string (data->seq_result, b, sizeof (b)) : ""); } else nm_utils_strbuf_append_str (&buf, &buf_size, " (any)"); break; @@ -3503,58 +3582,27 @@ delayed_action_wait_for_nl_response_complete (NMPlatform *platform, } static void -delayed_action_wait_for_nl_response_complete_check (NMPlatform *platform, - WaitForNlResponseResult force_result, - guint32 *out_next_seq_number, - gint64 *out_next_timeout_abs_ns, - gint64 *p_now_ns) +delayed_action_wait_for_nl_response_complete_all (NMPlatform *platform, + WaitForNlResponseResult fallback_result) { NMLinuxPlatformPrivate *priv = NM_LINUX_PLATFORM_GET_PRIVATE (platform); - guint i; - guint32 next_seq_number = 0; - gint64 next_timeout_abs_ns = 0; - gint now_ns = 0; - - for (i = 0; i < priv->delayed_action.list_wait_for_nl_response->len; ) { - const DelayedActionWaitForNlResponseData *data = &g_array_index (priv->delayed_action.list_wait_for_nl_response, DelayedActionWaitForNlResponseData, i); - - if (data->seq_result) - delayed_action_wait_for_nl_response_complete (platform, i, data->seq_result); - else if ( p_now_ns - && ((now_ns ?: (now_ns = nm_utils_get_monotonic_timestamp_ns ())) >= data->timeout_abs_ns)) { - /* the caller can optionally check for timeout by providing a p_now_ns argument. */ - delayed_action_wait_for_nl_response_complete (platform, i, WAIT_FOR_NL_RESPONSE_RESULT_FAILED_TIMEOUT); - } else if (force_result != WAIT_FOR_NL_RESPONSE_RESULT_UNKNOWN) - delayed_action_wait_for_nl_response_complete (platform, i, force_result); - else { - if ( next_seq_number == 0 - || next_timeout_abs_ns > data->timeout_abs_ns) { - next_seq_number = data->seq_number; - next_timeout_abs_ns = data->timeout_abs_ns; - } - i++; - } - } - if (force_result != WAIT_FOR_NL_RESPONSE_RESULT_UNKNOWN) { - nm_assert (!NM_FLAGS_HAS (priv->delayed_action.flags, DELAYED_ACTION_TYPE_WAIT_FOR_NL_RESPONSE)); - nm_assert (priv->delayed_action.list_wait_for_nl_response->len == 0); - } + if (NM_FLAGS_HAS (priv->delayed_action.flags, DELAYED_ACTION_TYPE_WAIT_FOR_NL_RESPONSE)) { + while (priv->delayed_action.list_wait_for_nl_response->len > 0) { + const DelayedActionWaitForNlResponseData *data; + guint idx = priv->delayed_action.list_wait_for_nl_response->len - 1; + WaitForNlResponseResult r; - NM_SET_OUT (out_next_seq_number, next_seq_number); - NM_SET_OUT (out_next_timeout_abs_ns, next_timeout_abs_ns); - NM_SET_OUT (p_now_ns, now_ns); -} + data = &g_array_index (priv->delayed_action.list_wait_for_nl_response, DelayedActionWaitForNlResponseData, idx); -static void -delayed_action_wait_for_nl_response_complete_all (NMPlatform *platform, - WaitForNlResponseResult fallback_result) -{ - delayed_action_wait_for_nl_response_complete_check (platform, - fallback_result, - NULL, - NULL, - NULL); + /* prefer the result that we already have. */ + r = data->seq_result ? : fallback_result; + + delayed_action_wait_for_nl_response_complete (platform, idx, r); + } + } + nm_assert (!NM_FLAGS_HAS (priv->delayed_action.flags, DELAYED_ACTION_TYPE_WAIT_FOR_NL_RESPONSE)); + nm_assert (priv->delayed_action.list_wait_for_nl_response->len == 0); } /*****************************************************************************/ @@ -3737,7 +3785,6 @@ static void delayed_action_schedule_WAIT_FOR_NL_RESPONSE (NMPlatform *platform, guint32 seq_number, WaitForNlResponseResult *out_seq_result, - char **out_errmsg, DelayedActionWaitForNlResponseType response_type, gpointer response_out_data) { @@ -3745,7 +3792,6 @@ delayed_action_schedule_WAIT_FOR_NL_RESPONSE (NMPlatform *platform, .seq_number = seq_number, .timeout_abs_ns = nm_utils_get_monotonic_timestamp_ns () + (200 * (NM_UTILS_NS_PER_SECOND / 1000)), .out_seq_result = out_seq_result, - .out_errmsg = out_errmsg, .response_type = response_type, .response.out_data = response_out_data, }; @@ -3930,46 +3976,40 @@ cache_on_change (NMPlatform *platform, && (obj_new && obj_new->_link.netlink.is_in_netlink) && (!obj_old || !obj_old->_link.netlink.is_in_netlink)) { - gboolean re_request_link = FALSE; - const NMPlatformLnkTun *lnk_tun; - - if ( !obj_new->_link.netlink.lnk - && NM_IN_SET (obj_new->link.type, NM_LINK_TYPE_GRE, - NM_LINK_TYPE_IP6TNL, - NM_LINK_TYPE_INFINIBAND, - NM_LINK_TYPE_MACVLAN, - NM_LINK_TYPE_MACVLAN, - NM_LINK_TYPE_SIT, - NM_LINK_TYPE_TUN, - NM_LINK_TYPE_VLAN, - NM_LINK_TYPE_VXLAN)) { + if (!obj_new->_link.netlink.lnk) { /* certain link-types also come with a IFLA_INFO_DATA/lnk_data. It may happen that * kernel didn't send this notification, thus when we first learn about a link * that lacks an lnk_data we re-request it again. * * For example https://bugzilla.redhat.com/show_bug.cgi?id=1284001 */ - re_request_link = TRUE; - } else if ( obj_new->link.type == NM_LINK_TYPE_TUN - && obj_new->_link.netlink.lnk - && (lnk_tun = &(obj_new->_link.netlink.lnk)->lnk_tun) - && !lnk_tun->persist - && lnk_tun->pi - && !lnk_tun->vnet_hdr - && !lnk_tun->multi_queue - && !lnk_tun->owner_valid - && !lnk_tun->group_valid) { - /* kernel has/had a know issue that the first notification for TUN device would - * be sent with invalid parameters. The message looks like that kind, so refetch - * it. */ - re_request_link = TRUE; - } else if ( obj_new->link.type == NM_LINK_TYPE_VETH - && obj_new->link.parent == 0) { + switch (obj_new->link.type) { + case NM_LINK_TYPE_GRE: + case NM_LINK_TYPE_IP6TNL: + case NM_LINK_TYPE_INFINIBAND: + case NM_LINK_TYPE_MACVLAN: + case NM_LINK_TYPE_MACVTAP: + case NM_LINK_TYPE_SIT: + case NM_LINK_TYPE_VLAN: + case NM_LINK_TYPE_VXLAN: + delayed_action_schedule (platform, + DELAYED_ACTION_TYPE_REFRESH_LINK, + GINT_TO_POINTER (obj_new->link.ifindex)); + break; + default: + break; + } + } + if ( obj_new->link.type == NM_LINK_TYPE_VETH + && obj_new->link.parent == 0) { /* the initial notification when adding a veth pair can lack the parent/IFLA_LINK * (https://bugzilla.redhat.com/show_bug.cgi?id=1285827). * Request it again. */ - re_request_link = TRUE; - } else if ( obj_new->link.type == NM_LINK_TYPE_ETHERNET - && obj_new->link.addr.len == 0) { + delayed_action_schedule (platform, + DELAYED_ACTION_TYPE_REFRESH_LINK, + GINT_TO_POINTER (obj_new->link.ifindex)); + } + if ( obj_new->link.type == NM_LINK_TYPE_ETHERNET + && obj_new->link.addr.len == 0) { /* Due to a kernel bug, we sometimes receive spurious NEWLINK * messages after a wifi interface has disappeared. Since the * link is not present anymore we can't determine its type and @@ -3977,9 +4017,6 @@ cache_on_change (NMPlatform *platform, * specified. Request the link again to check if it really * exists. https://bugzilla.redhat.com/show_bug.cgi?id=1302037 */ - re_request_link = TRUE; - } - if (re_request_link) { delayed_action_schedule (platform, DELAYED_ACTION_TYPE_REFRESH_LINK, GINT_TO_POINTER (obj_new->link.ifindex)); @@ -4030,10 +4067,8 @@ cache_on_change (NMPlatform *platform, static guint32 _nlh_seq_next_get (NMLinuxPlatformPrivate *priv) { - /* generate a new sequence number, but never return zero. - * Wrapping numbers are not a problem, because we don't rely - * on strictly increasing sequence numbers. */ - return (++priv->nlh_seq_next) ?: (++priv->nlh_seq_next); + /* generate a new sequence number, but skip zero. */ + return priv->nlh_seq_next++ ?: priv->nlh_seq_next++; } /** @@ -4044,13 +4079,12 @@ _nlh_seq_next_get (NMLinuxPlatformPrivate *priv) * @response_type: * @response_out_data: * - * Returns: 0 on success or a negative errno. + * Returns: 0 on success or a negative errno. Beware, it's an errno, not nlerror. */ static int _nl_send_nlmsghdr (NMPlatform *platform, struct nlmsghdr *nlhdr, WaitForNlResponseResult *out_seq_result, - char **out_errmsg, DelayedActionWaitForNlResponseType response_type, gpointer response_out_data) { @@ -4095,7 +4129,7 @@ again: } } - delayed_action_schedule_WAIT_FOR_NL_RESPONSE (platform, seq, out_seq_result, out_errmsg, + delayed_action_schedule_WAIT_FOR_NL_RESPONSE (platform, seq, out_seq_result, response_type, response_out_data); return 0; } @@ -4114,7 +4148,6 @@ static int _nl_send_nlmsg (NMPlatform *platform, struct nl_msg *nlmsg, WaitForNlResponseResult *out_seq_result, - char **out_errmsg, DelayedActionWaitForNlResponseType response_type, gpointer response_out_data) { @@ -4133,7 +4166,7 @@ _nl_send_nlmsg (NMPlatform *platform, return nle; } - delayed_action_schedule_WAIT_FOR_NL_RESPONSE (platform, seq, out_seq_result, out_errmsg, + delayed_action_schedule_WAIT_FOR_NL_RESPONSE (platform, seq, out_seq_result, response_type, response_out_data); return 0; } @@ -4171,7 +4204,7 @@ do_request_link_no_delayed_actions (NMPlatform *platform, int ifindex, const cha 0, 0); if (nlmsg) { - nle = _nl_send_nlmsg (platform, nlmsg, NULL, NULL, DELAYED_ACTION_RESPONSE_TYPE_VOID, NULL); + nle = _nl_send_nlmsg (platform, nlmsg, NULL, DELAYED_ACTION_RESPONSE_TYPE_VOID, NULL); if (nle < 0) { _LOGE ("do-request-link: %d %s: failed sending netlink request \"%s\" (%d)", ifindex, name ?: "", @@ -4230,6 +4263,8 @@ do_request_all_no_delayed_actions (NMPlatform *platform, DelayedActionType actio * because we need the sequence number. */ nlmsg = nlmsg_alloc_simple (klass->rtm_gettype, NLM_F_DUMP); + if (!nlmsg) + continue; if ( klass->obj_type == NMP_OBJECT_TYPE_QDISC || klass->obj_type == NMP_OBJECT_TYPE_TFILTER) { @@ -4246,7 +4281,7 @@ do_request_all_no_delayed_actions (NMPlatform *platform, DelayedActionType actio if (nle < 0) continue; - if (_nl_send_nlmsg (platform, nlmsg, NULL, NULL, DELAYED_ACTION_RESPONSE_TYPE_REFRESH_ALL_IN_PROGRESS, out_refresh_all_in_progess) < 0) { + if (_nl_send_nlmsg (platform, nlmsg, NULL, DELAYED_ACTION_RESPONSE_TYPE_REFRESH_ALL_IN_PROGRESS, out_refresh_all_in_progess) < 0) { nm_assert (*out_refresh_all_in_progess > 0); *out_refresh_all_in_progess -= 1; } @@ -4290,7 +4325,7 @@ event_seq_check_refresh_all (NMPlatform *platform, guint32 seq_number) } static void -event_seq_check (NMPlatform *platform, guint32 seq_number, WaitForNlResponseResult seq_result, const char *msg) +event_seq_check (NMPlatform *platform, guint32 seq_number, WaitForNlResponseResult seq_result) { NMLinuxPlatformPrivate *priv = NM_LINUX_PLATFORM_GET_PRIVATE (platform); DelayedActionWaitForNlResponseData *data; @@ -4309,13 +4344,11 @@ event_seq_check (NMPlatform *platform, guint32 seq_number, WaitForNlResponseResu /* We potentially receive many parts partial responses for the same sequence number. * Thus, we only remember the result, and collect it later. */ if (data->seq_result < 0) { - /* we already saw an error for this sequence number. + /* we already saw an error for this seqence number. * Preserve it. */ } else if ( seq_result != WAIT_FOR_NL_RESPONSE_RESULT_RESPONSE_UNKNOWN || data->seq_result == WAIT_FOR_NL_RESPONSE_RESULT_UNKNOWN) data->seq_result = seq_result; - if (data->out_errmsg && !*data->out_errmsg) - *data->out_errmsg = g_strdup (msg); return; } } @@ -4358,7 +4391,7 @@ event_valid_msg (NMPlatform *platform, struct nl_msg *msg, gboolean handle_event obj = nmp_object_new_from_nl (platform, cache, msg, id_only); if (!obj) { _LOGT ("event-notification: %s: ignore", - nl_nlmsghdr_to_str (msghdr, buf_nlmsghdr, sizeof (buf_nlmsghdr))); + _nl_nlmsghdr_to_str (msghdr, buf_nlmsghdr, sizeof (buf_nlmsghdr))); return; } @@ -4376,7 +4409,7 @@ event_valid_msg (NMPlatform *platform, struct nl_msg *msg, gboolean handle_event } _LOGT ("event-notification: %s%s: %s", - nl_nlmsghdr_to_str (msghdr, buf_nlmsghdr, sizeof (buf_nlmsghdr)), + _nl_nlmsghdr_to_str (msghdr, buf_nlmsghdr, sizeof (buf_nlmsghdr)), is_dump ? ", in-dump" : "", nmp_object_to_string (obj, id_only ? NMP_OBJECT_TO_STRING_ID : NMP_OBJECT_TO_STRING_PUBLIC, @@ -4514,14 +4547,13 @@ do_add_link_with_lookup (NMPlatform *platform, { const NMPObject *obj = NULL; WaitForNlResponseResult seq_result = WAIT_FOR_NL_RESPONSE_RESULT_UNKNOWN; - gs_free char *errmsg = NULL; int nle; char s_buf[256]; NMPCache *cache = nm_platform_get_cache (platform); event_handler_read_netlink (platform, FALSE); - nle = _nl_send_nlmsg (platform, nlmsg, &seq_result, &errmsg, DELAYED_ACTION_RESPONSE_TYPE_VOID, NULL); + nle = _nl_send_nlmsg (platform, nlmsg, &seq_result, DELAYED_ACTION_RESPONSE_TYPE_VOID, NULL); if (nle < 0) { _LOGE ("do-add-link[%s/%s]: failed sending netlink request \"%s\" (%d)", name, @@ -4541,7 +4573,7 @@ do_add_link_with_lookup (NMPlatform *platform, "do-add-link[%s/%s]: %s", name, nm_link_type_to_string (link_type), - wait_for_nl_response_to_string (seq_result, errmsg, s_buf, sizeof (s_buf))); + wait_for_nl_response_to_string (seq_result, s_buf, sizeof (s_buf))); if (out_link) { obj = nmp_cache_lookup_link_full (cache, 0, name, FALSE, link_type, NULL, NULL); @@ -4558,7 +4590,6 @@ do_add_addrroute (NMPlatform *platform, gboolean suppress_netlink_failure) { WaitForNlResponseResult seq_result = WAIT_FOR_NL_RESPONSE_RESULT_UNKNOWN; - gs_free char *errmsg = NULL; int nle; char s_buf[256]; @@ -4568,7 +4599,7 @@ do_add_addrroute (NMPlatform *platform, event_handler_read_netlink (platform, FALSE); - nle = _nl_send_nlmsg (platform, nlmsg, &seq_result, &errmsg, DELAYED_ACTION_RESPONSE_TYPE_VOID, NULL); + nle = _nl_send_nlmsg (platform, nlmsg, &seq_result, DELAYED_ACTION_RESPONSE_TYPE_VOID, NULL); if (nle < 0) { _LOGE ("do-add-%s[%s]: failure sending netlink request \"%s\" (%d)", NMP_OBJECT_GET_CLASS (obj_id)->obj_type_name, @@ -4589,7 +4620,7 @@ do_add_addrroute (NMPlatform *platform, "do-add-%s[%s]: %s", NMP_OBJECT_GET_CLASS (obj_id)->obj_type_name, nmp_object_to_string (obj_id, NMP_OBJECT_TO_STRING_ID, NULL, 0), - wait_for_nl_response_to_string (seq_result, errmsg, s_buf, sizeof (s_buf))); + wait_for_nl_response_to_string (seq_result, s_buf, sizeof (s_buf))); if (NMP_OBJECT_GET_TYPE (obj_id) == NMP_OBJECT_TYPE_IP6_ADDRESS) { /* In rare cases, the object is not yet ready as we received the ACK from @@ -4610,7 +4641,6 @@ static gboolean do_delete_object (NMPlatform *platform, const NMPObject *obj_id, struct nl_msg *nlmsg) { WaitForNlResponseResult seq_result = WAIT_FOR_NL_RESPONSE_RESULT_UNKNOWN; - gs_free char *errmsg = NULL; int nle; char s_buf[256]; gboolean success; @@ -4618,7 +4648,7 @@ do_delete_object (NMPlatform *platform, const NMPObject *obj_id, struct nl_msg * event_handler_read_netlink (platform, FALSE); - nle = _nl_send_nlmsg (platform, nlmsg, &seq_result, &errmsg, DELAYED_ACTION_RESPONSE_TYPE_VOID, NULL); + nle = _nl_send_nlmsg (platform, nlmsg, &seq_result, DELAYED_ACTION_RESPONSE_TYPE_VOID, NULL); if (nle < 0) { _LOGE ("do-delete-%s[%s]: failure sending netlink request \"%s\" (%d)", NMP_OBJECT_GET_CLASS (obj_id)->obj_type_name, @@ -4650,7 +4680,7 @@ do_delete_object (NMPlatform *platform, const NMPObject *obj_id, struct nl_msg * "do-delete-%s[%s]: %s%s", NMP_OBJECT_GET_CLASS (obj_id)->obj_type_name, nmp_object_to_string (obj_id, NMP_OBJECT_TO_STRING_ID, NULL, 0), - wait_for_nl_response_to_string (seq_result, errmsg, s_buf, sizeof (s_buf)), + wait_for_nl_response_to_string (seq_result, s_buf, sizeof (s_buf)), log_detail); if (NM_IN_SET (NMP_OBJECT_GET_TYPE (obj_id), @@ -4681,7 +4711,6 @@ do_change_link (NMPlatform *platform, nm_auto_pop_netns NMPNetns *netns = NULL; int nle; WaitForNlResponseResult seq_result = WAIT_FOR_NL_RESPONSE_RESULT_UNKNOWN; - gs_free char *errmsg = NULL; char s_buf[256]; NMPlatformError result = NM_PLATFORM_ERROR_SUCCESS; NMLogLevel log_level = LOGL_DEBUG; @@ -4697,7 +4726,7 @@ do_change_link (NMPlatform *platform, } retry: - nle = _nl_send_nlmsg (platform, nlmsg, &seq_result, &errmsg, DELAYED_ACTION_RESPONSE_TYPE_VOID, NULL); + nle = _nl_send_nlmsg (platform, nlmsg, &seq_result, DELAYED_ACTION_RESPONSE_TYPE_VOID, NULL); if (nle < 0) { log_level = LOGL_ERR; log_detail_free = g_strdup_printf (", failure sending netlink request: %s (%d)", @@ -4754,7 +4783,7 @@ out: "do-change-link[%d]: %s changing link: %s%s", ifindex, log_result, - wait_for_nl_response_to_string (seq_result, errmsg, s_buf, sizeof (s_buf)), + wait_for_nl_response_to_string (seq_result, s_buf, sizeof (s_buf)), log_detail); return result; } @@ -4831,12 +4860,6 @@ link_refresh (NMPlatform *platform, int ifindex) return !!nm_platform_link_get_obj (platform, ifindex, TRUE); } -static void -refresh_all (NMPlatform *platform, NMPObjectType obj_type) -{ - do_request_one_type (platform, obj_type); -} - static gboolean link_set_netns (NMPlatform *platform, int ifindex, @@ -5369,7 +5392,6 @@ link_ip6tnl_add (NMPlatform *platform, & IP6_FLOWINFO_TCLASS_MASK; NLA_PUT_U32 (nlmsg, IFLA_IPTUN_FLOWINFO, htonl (flowinfo)); NLA_PUT_U8 (nlmsg, IFLA_IPTUN_PROTO, props->proto); - NLA_PUT_U32 (nlmsg, IFLA_IPTUN_FLAGS, props->flags); nla_nest_end (nlmsg, data); nla_nest_end (nlmsg, info); @@ -5593,62 +5615,6 @@ nla_put_failure: } static gboolean -link_tun_add (NMPlatform *platform, - const char *name, - const NMPlatformLnkTun *props, - const NMPlatformLink **out_link, - int *out_fd) -{ - const NMPObject *obj; - struct ifreq ifr = { }; - nm_auto_close int fd = -1; - - nm_assert (NM_IN_SET (props->type, IFF_TAP, IFF_TUN)); - nm_assert (props->persist || out_fd); - - fd = open ("/dev/net/tun", O_RDWR | O_CLOEXEC); - if (fd < 0) - return FALSE; - - nm_utils_ifname_cpy (ifr.ifr_name, name); - ifr.ifr_flags = ((short) props->type) - | ((short) IFF_TUN_EXCL) - | (!props->pi ? (short) IFF_NO_PI : (short) 0) - | ( props->vnet_hdr ? (short) IFF_VNET_HDR : (short) 0) - | ( props->multi_queue ? (short) NM_IFF_MULTI_QUEUE : (short) 0); - if (ioctl (fd, TUNSETIFF, &ifr)) - return FALSE; - - if (props->owner_valid) { - if (ioctl (fd, TUNSETOWNER, (uid_t) props->owner)) - return FALSE; - } - - if (props->group_valid) { - if (ioctl (fd, TUNSETGROUP, (gid_t) props->group)) - return FALSE; - } - - if (props->persist) { - if (ioctl (fd, TUNSETPERSIST, 1)) - return FALSE; - } - - do_request_link (platform, 0, name); - obj = nmp_cache_lookup_link_full (nm_platform_get_cache (platform), - 0, name, FALSE, - NM_LINK_TYPE_TUN, - NULL, NULL); - - if (!obj) - return FALSE; - - NM_SET_OUT (out_link, &obj->link); - NM_SET_OUT (out_fd, nm_steal_fd (&fd)); - return TRUE; -} - -static gboolean link_vxlan_add (NMPlatform *platform, const char *name, const NMPlatformLnkVxlan *props, @@ -5888,6 +5854,64 @@ link_vlan_change (NMPlatform *platform, return do_change_link (platform, CHANGE_LINK_TYPE_UNSPEC, ifindex, nlmsg, NULL) == NM_PLATFORM_ERROR_SUCCESS; } +static int +tun_add (NMPlatform *platform, const char *name, gboolean tap, + gint64 owner, gint64 group, gboolean pi, gboolean vnet_hdr, + gboolean multi_queue, const NMPlatformLink **out_link) +{ + const NMPObject *obj; + struct ifreq ifr = { }; + int fd; + + fd = open ("/dev/net/tun", O_RDWR | O_CLOEXEC); + if (fd < 0) + return FALSE; + + nm_utils_ifname_cpy (ifr.ifr_name, name); + ifr.ifr_flags = tap ? IFF_TAP : IFF_TUN; + + if (!pi) + ifr.ifr_flags |= IFF_NO_PI; + if (vnet_hdr) + ifr.ifr_flags |= IFF_VNET_HDR; + if (multi_queue) + ifr.ifr_flags |= NM_IFF_MULTI_QUEUE; + + if (ioctl (fd, TUNSETIFF, &ifr)) { + nm_close (fd); + return FALSE; + } + + if (owner >= 0 && owner < G_MAXINT32) { + if (ioctl (fd, TUNSETOWNER, (uid_t) owner)) { + nm_close (fd); + return FALSE; + } + } + + if (group >= 0 && group < G_MAXINT32) { + if (ioctl (fd, TUNSETGROUP, (gid_t) group)) { + nm_close (fd); + return FALSE; + } + } + + if (ioctl (fd, TUNSETPERSIST, 1)) { + nm_close (fd); + return FALSE; + } + do_request_link (platform, 0, name); + obj = nmp_cache_lookup_link_full (nm_platform_get_cache (platform), + 0, name, FALSE, + tap ? NM_LINK_TYPE_TAP : NM_LINK_TYPE_TUN, + NULL, NULL); + if (out_link) + *out_link = obj ? &obj->link : NULL; + + nm_close (fd); + return !!obj; +} + static gboolean link_enslave (NMPlatform *platform, int master, int slave) { @@ -6429,7 +6453,7 @@ ip_route_get (NMPlatform *platform, } seq_result = WAIT_FOR_NL_RESPONSE_RESULT_UNKNOWN; - nle = _nl_send_nlmsghdr (platform, &req.n, &seq_result, NULL, DELAYED_ACTION_RESPONSE_TYPE_ROUTE_GET, &route); + nle = _nl_send_nlmsghdr (platform, &req.n, &seq_result, DELAYED_ACTION_RESPONSE_TYPE_ROUTE_GET, &route); if (nle < 0) { _LOGE ("get-route: failure sending netlink request \"%s\" (%d)", g_strerror (-nle), -nle); @@ -6468,7 +6492,6 @@ qdisc_add (NMPlatform *platform, const NMPlatformQdisc *qdisc) { WaitForNlResponseResult seq_result = WAIT_FOR_NL_RESPONSE_RESULT_UNKNOWN; - gs_free char *errmsg = NULL; int nle; char s_buf[256]; nm_auto_nlmsg struct nl_msg *msg = NULL; @@ -6477,7 +6500,7 @@ qdisc_add (NMPlatform *platform, event_handler_read_netlink (platform, FALSE); - nle = _nl_send_nlmsg (platform, msg, &seq_result, &errmsg, DELAYED_ACTION_RESPONSE_TYPE_VOID, NULL); + nle = _nl_send_nlmsg (platform, msg, &seq_result, DELAYED_ACTION_RESPONSE_TYPE_VOID, NULL); if (nle < 0) { _LOGE ("do-add-qdisc: failed sending netlink request \"%s\" (%d)", nl_geterror (nle), -nle); @@ -6492,7 +6515,7 @@ qdisc_add (NMPlatform *platform, ? LOGL_DEBUG : LOGL_WARN, "do-add-qdisc: %s", - wait_for_nl_response_to_string (seq_result, errmsg, s_buf, sizeof (s_buf))); + wait_for_nl_response_to_string (seq_result, s_buf, sizeof (s_buf))); if (seq_result == WAIT_FOR_NL_RESPONSE_RESULT_RESPONSE_OK) return NM_PLATFORM_ERROR_SUCCESS; @@ -6508,7 +6531,6 @@ tfilter_add (NMPlatform *platform, const NMPlatformTfilter *tfilter) { WaitForNlResponseResult seq_result = WAIT_FOR_NL_RESPONSE_RESULT_UNKNOWN; - gs_free char *errmsg = NULL; int nle; char s_buf[256]; nm_auto_nlmsg struct nl_msg *msg = NULL; @@ -6517,7 +6539,7 @@ tfilter_add (NMPlatform *platform, event_handler_read_netlink (platform, FALSE); - nle = _nl_send_nlmsg (platform, msg, &seq_result, &errmsg, DELAYED_ACTION_RESPONSE_TYPE_VOID, NULL); + nle = _nl_send_nlmsg (platform, msg, &seq_result, DELAYED_ACTION_RESPONSE_TYPE_VOID, NULL); if (nle < 0) { _LOGE ("do-add-tfilter: failed sending netlink request \"%s\" (%d)", nl_geterror (nle), -nle); @@ -6532,7 +6554,7 @@ tfilter_add (NMPlatform *platform, ? LOGL_DEBUG : LOGL_WARN, "do-add-tfilter: %s", - wait_for_nl_response_to_string (seq_result, errmsg, s_buf, sizeof (s_buf))); + wait_for_nl_response_to_string (seq_result, s_buf, sizeof (s_buf))); if (seq_result == WAIT_FOR_NL_RESPONSE_RESULT_RESPONSE_OK) return NM_PLATFORM_ERROR_SUCCESS; @@ -6563,12 +6585,15 @@ event_handler_recvmsgs (NMPlatform *platform, gboolean handle_events) { NMLinuxPlatformPrivate *priv = NM_LINUX_PLATFORM_GET_PRIVATE (platform); struct nl_sock *sk = priv->nlh; - int n; - int err = 0; - gboolean multipart = 0; - gboolean interrupted = FALSE; + int n, err = 0, multipart = 0, interrupted = 0; struct nlmsghdr *hdr; WaitForNlResponseResult seq_result; + + /* + nla is passed on to not only to nl_recv() but may also be passed + to a function pointer provided by the caller which may or may not + initialize the variable. Thomas Graf. + */ struct sockaddr_nl nla = {0}; nm_auto_free struct ucred *creds = NULL; nm_auto_free unsigned char *buf = NULL; @@ -6576,28 +6601,56 @@ event_handler_recvmsgs (NMPlatform *platform, gboolean handle_events) continue_reading: g_clear_pointer (&buf, free); g_clear_pointer (&creds, free); + errno = 0; n = nl_recv (sk, &nla, &buf, &creds); if (n <= 0) { - - if (n == -NLE_MSG_TRUNC) { - int buf_size; - - /* the message receive buffer was too small. We lost one message, which - * is unfortunate. Try to double the buffer size for the next time. */ - buf_size = nl_socket_get_msg_buf_size (sk); - if (buf_size < 512*1024) { - buf_size *= 2; - _LOGT ("netlink: recvmsg: increase message buffer size for recvmsg() to %d bytes", buf_size); - if (nl_socket_set_msg_buf_size (sk, buf_size) < 0) - nm_assert_not_reached (); - if (!handle_events) - goto continue_reading; - } + /* workaround libnl3 <= 3.2.15 returning danling pointers in case nl_recv() + * fails. Fixed by libnl3 69468517d0de1675d80f24661ff57a5dbac7275c. */ + buf = NULL; + creds = NULL; + } + + switch (n) { + case 0: + /* Work around a libnl bug fixed in 3.2.22 (375a6294) */ + if (errno == EAGAIN) { + /* EAGAIN is equal to EWOULDBLOCK. If it would not be, we'd have to + * workaround libnl3 mapping EWOULDBLOCK to -NLE_FAILURE. */ + G_STATIC_ASSERT (EAGAIN == EWOULDBLOCK); + n = -NLE_AGAIN; + } + break; + case -NLE_MSG_TRUNC: { + int buf_size; + + /* the message receive buffer was too small. We lost one message, which + * is unfortunate. Try to double the buffer size for the next time. */ + buf_size = nl_socket_get_msg_buf_size (sk); + if (buf_size < 512*1024) { + buf_size *= 2; + _LOGT ("netlink: recvmsg: increase message buffer size for recvmsg() to %d bytes", buf_size); + if (nl_socket_set_msg_buf_size (sk, buf_size) < 0) + nm_assert_not_reached (); + if (!handle_events) + goto continue_reading; } + n = -_NLE_MSG_TRUNC; + break; + } + case -NLE_NOMEM: + if (errno == ENOBUFS) { + /* we are very much interested in a overrun of the receive buffer. + * nl_recv() maps all kinds of errors to NLE_NOMEM, so check also + * for errno explicitly. And if so, hack our own return code to signal + * the overrun. */ + n = -_NLE_NM_NOBUFS; + } + break; + } + if (n <= 0) return n; - } hdr = (struct nlmsghdr *) buf; while (nlmsg_ok (hdr, n)) { @@ -6606,9 +6659,12 @@ continue_reading: gboolean process_valid_msg = FALSE; guint32 seq_number; char buf_nlmsghdr[400]; - const char *extack_msg = NULL; - msg = nlmsg_alloc_convert (hdr); + msg = nlmsg_convert (hdr); + if (!msg) { + err = -NLE_NOMEM; + goto out; + } nlmsg_set_proto (msg, NETLINK_ROUTE); nlmsg_set_src (msg, &nla); @@ -6623,13 +6679,13 @@ continue_reading: } _LOGt ("netlink: recvmsg: new message %s", - nl_nlmsghdr_to_str (hdr, buf_nlmsghdr, sizeof (buf_nlmsghdr))); + _nl_nlmsghdr_to_str (hdr, buf_nlmsghdr, sizeof (buf_nlmsghdr))); if (creds) nlmsg_set_creds (msg, creds); if (hdr->nlmsg_flags & NLM_F_MULTI) - multipart = TRUE; + multipart = 1; if (hdr->nlmsg_flags & NLM_F_DUMP_INTR) { /* @@ -6637,7 +6693,7 @@ continue_reading: * all messages until a NLMSG_DONE is * received and report the inconsistency. */ - interrupted = TRUE; + interrupted = 1; } /* Other side wishes to see an ack for this message */ @@ -6652,7 +6708,7 @@ continue_reading: * usually the end of a message and therefore we slip * out of the loop by default. the user may overrule * this action by skipping this packet. */ - multipart = FALSE; + multipart = 0; seq_result = WAIT_FOR_NL_RESPONSE_RESULT_RESPONSE_OK; } else if (hdr->nlmsg_type == NLMSG_NOOP) { /* Message to be ignored, the default action is to @@ -6679,28 +6735,10 @@ continue_reading: } else if (e->error) { int errsv = e->error > 0 ? e->error : -e->error; - if ( NM_FLAGS_HAS (hdr->nlmsg_flags, NLM_F_ACK_TLVS) - && hdr->nlmsg_len >= sizeof (*e) + e->msg.nlmsg_len) { - static const struct nla_policy policy[NLMSGERR_ATTR_MAX + 1] = { - [NLMSGERR_ATTR_MSG] = { .type = NLA_STRING }, - [NLMSGERR_ATTR_OFFS] = { .type = NLA_U32 }, - }; - struct nlattr *tb[NLMSGERR_ATTR_MAX + 1]; - struct nlattr *tlvs; - - tlvs = (struct nlattr *) ((char *) e + sizeof (*e) + e->msg.nlmsg_len - NLMSG_HDRLEN); - if (!nla_parse (tb, NLMSGERR_ATTR_MAX, tlvs, - hdr->nlmsg_len - sizeof (*e) - e->msg.nlmsg_len, policy)) { - if (tb[NLMSGERR_ATTR_MSG]) - extack_msg = nla_get_string (tb[NLMSGERR_ATTR_MSG]); - } - } - /* Error message reported back from kernel. */ - _LOGD ("netlink: recvmsg: error message from kernel: %s (%d)%s%s%s for request %d", + _LOGD ("netlink: recvmsg: error message from kernel: %s (%d) for request %d", strerror (errsv), errsv, - NM_PRINT_FMT_QUOTED (extack_msg, " \"", extack_msg, "\"", ""), nlmsg_hdr (msg)->nlmsg_seq); seq_result = -errsv; } else @@ -6729,7 +6767,7 @@ continue_reading: seq_result = WAIT_FOR_NL_RESPONSE_RESULT_RESPONSE_OK; } - event_seq_check (platform, seq_number, seq_result, extack_msg); + event_seq_check (platform, seq_number, seq_result); if (abort_parsing) goto stop; @@ -6749,9 +6787,9 @@ stop: * Repeat reading. */ goto continue_reading; } - +out: if (interrupted) - return -NLE_DUMP_INTR; + err = -NLE_DUMP_INTR; return err; } @@ -6762,50 +6800,46 @@ event_handler_read_netlink (NMPlatform *platform, gboolean wait_for_acks) { nm_auto_pop_netns NMPNetns *netns = NULL; NMLinuxPlatformPrivate *priv = NM_LINUX_PLATFORM_GET_PRIVATE (platform); - int r; + int r, nle; struct pollfd pfd; gboolean any = FALSE; + gint64 now_ns; int timeout_ms; + guint i; struct { guint32 seq_number; gint64 timeout_abs_ns; - gint64 now_ns; - } next; + } data_next; - if (!nm_platform_netns_push (platform, &netns)) { - delayed_action_wait_for_nl_response_complete_all (platform, - WAIT_FOR_NL_RESPONSE_RESULT_FAILED_SETNS); + if (!nm_platform_netns_push (platform, &netns)) return FALSE; - } - for (;;) { - for (;;) { - int nle; + while (TRUE) { + + while (TRUE) { nle = event_handler_recvmsgs (platform, TRUE); if (nle < 0) { switch (nle) { - case -EAGAIN: + case -NLE_AGAIN: goto after_read; case -NLE_DUMP_INTR: _LOGD ("netlink: read: uncritical failure to retrieve incoming events: %s (%d)", nl_geterror (nle), nle); break; - case -NLE_MSG_TRUNC: - case -ENOBUFS: + case -_NLE_MSG_TRUNC: + case -_NLE_NM_NOBUFS: _LOGI ("netlink: read: %s. Need to resynchronize platform cache", ({ const char *_reason = "unknown"; switch (nle) { - case -NLE_MSG_TRUNC: _reason = "message truncated"; break; - case -ENOBUFS: _reason = "too many netlink events"; break; + case -_NLE_MSG_TRUNC: _reason = "message truncated"; break; + case -_NLE_NM_NOBUFS: _reason = "too many netlink events"; break; } _reason; })); event_handler_recvmsgs (platform, FALSE); - delayed_action_wait_for_nl_response_complete_all (platform, - WAIT_FOR_NL_RESPONSE_RESULT_FAILED_RESYNC); - + delayed_action_wait_for_nl_response_complete_all (platform, WAIT_FOR_NL_RESPONSE_RESULT_FAILED_RESYNC); delayed_action_schedule (platform, DELAYED_ACTION_TYPE_REFRESH_ALL_LINKS | DELAYED_ACTION_TYPE_REFRESH_ALL_IP4_ADDRESSES | @@ -6829,23 +6863,39 @@ after_read: if (!NM_FLAGS_HAS (priv->delayed_action.flags, DELAYED_ACTION_TYPE_WAIT_FOR_NL_RESPONSE)) return any; - delayed_action_wait_for_nl_response_complete_check (platform, - WAIT_FOR_NL_RESPONSE_RESULT_UNKNOWN, - &next.seq_number, - &next.timeout_abs_ns, - &next.now_ns); + now_ns = 0; + data_next.seq_number = 0; + data_next.timeout_abs_ns = 0; + + for (i = 0; i < priv->delayed_action.list_wait_for_nl_response->len; ) { + DelayedActionWaitForNlResponseData *data = &g_array_index (priv->delayed_action.list_wait_for_nl_response, DelayedActionWaitForNlResponseData, i); + + if (data->seq_result) + delayed_action_wait_for_nl_response_complete (platform, i, data->seq_result); + else if ((now_ns ?: (now_ns = nm_utils_get_monotonic_timestamp_ns ())) > data->timeout_abs_ns) + delayed_action_wait_for_nl_response_complete (platform, i, WAIT_FOR_NL_RESPONSE_RESULT_FAILED_TIMEOUT); + else { + i++; + + if ( data_next.seq_number == 0 + || data_next.timeout_abs_ns > data->timeout_abs_ns) { + data_next.seq_number = data->seq_number; + data_next.timeout_abs_ns = data->timeout_abs_ns; + } + } + } if ( !wait_for_acks || !NM_FLAGS_HAS (priv->delayed_action.flags, DELAYED_ACTION_TYPE_WAIT_FOR_NL_RESPONSE)) return any; - nm_assert (next.seq_number); - nm_assert (next.now_ns > 0); - nm_assert (next.timeout_abs_ns > next.now_ns); + nm_assert (data_next.seq_number); + nm_assert (data_next.timeout_abs_ns > 0); + nm_assert (now_ns > 0); - _LOGT ("netlink: read: wait for ACK for sequence number %u...", next.seq_number); + _LOGT ("netlink: read: wait for ACK for sequence number %u...", data_next.seq_number); - timeout_ms = (next.timeout_abs_ns - next.now_ns) / (NM_UTILS_NS_PER_SECOND / 1000); + timeout_ms = (data_next.timeout_abs_ns - now_ns) / (NM_UTILS_NS_PER_SECOND / 1000); memset (&pfd, 0, sizeof (pfd)); pfd.fd = nl_socket_get_fd (priv->nlh); @@ -6856,7 +6906,6 @@ after_read: /* timeout and there is nothing to read. */ goto after_read; } - if (r < 0) { int errsv = errno; @@ -6998,10 +7047,11 @@ nm_linux_platform_init (NMLinuxPlatform *self) { NMLinuxPlatformPrivate *priv = NM_LINUX_PLATFORM_GET_PRIVATE (self); + priv->nlh_seq_next = 1; priv->delayed_action.list_master_connected = g_ptr_array_new (); priv->delayed_action.list_refresh_link = g_ptr_array_new (); priv->delayed_action.list_wait_for_nl_response = g_array_new (FALSE, TRUE, sizeof (DelayedActionWaitForNlResponseData)); - priv->wifi_data = g_hash_table_new_full (nm_direct_hash, NULL, NULL, (GDestroyNotify) wifi_utils_unref); + priv->wifi_data = g_hash_table_new_full (NULL, NULL, NULL, (GDestroyNotify) wifi_utils_deinit); } static void @@ -7047,10 +7097,6 @@ constructed (GObject *_object) nle = nl_socket_set_buffer_size (priv->nlh, 8*1024*1024, 0); g_assert (!nle); - nle = nl_socket_set_ext_ack (priv->nlh, TRUE); - if (nle) - _LOGD ("could not enable extended acks on netlink socket"); - /* explicitly set the msg buffer size and disable MSG_PEEK. * If we later encounter NLE_MSG_TRUNC, we will adjust the buffer size. */ nl_socket_disable_msg_peek (priv->nlh); @@ -7130,8 +7176,7 @@ dispose (GObject *object) _LOGD ("dispose"); - delayed_action_wait_for_nl_response_complete_all (platform, - WAIT_FOR_NL_RESPONSE_RESULT_FAILED_DISPOSING); + delayed_action_wait_for_nl_response_complete_all (platform, WAIT_FOR_NL_RESPONSE_RESULT_FAILED_DISPOSING); priv->delayed_action.flags = DELAYED_ACTION_TYPE_NONE; g_ptr_array_set_size (priv->delayed_action.list_master_connected, 0); @@ -7181,7 +7226,6 @@ nm_linux_platform_class_init (NMLinuxPlatformClass *klass) platform_class->link_add = link_add; platform_class->link_delete = link_delete; - platform_class->refresh_all = refresh_all; platform_class->link_refresh = link_refresh; platform_class->link_set_netns = link_set_netns; @@ -7220,6 +7264,8 @@ nm_linux_platform_class_init (NMLinuxPlatformClass *klass) platform_class->link_vlan_change = link_vlan_change; platform_class->link_vxlan_add = link_vxlan_add; + platform_class->tun_add = tun_add; + platform_class->infiniband_partition_add = infiniband_partition_add; platform_class->infiniband_partition_delete = infiniband_partition_delete; @@ -7244,7 +7290,6 @@ nm_linux_platform_class_init (NMLinuxPlatformClass *klass) platform_class->link_macvlan_add = link_macvlan_add; platform_class->link_ipip_add = link_ipip_add; platform_class->link_sit_add = link_sit_add; - platform_class->link_tun_add = link_tun_add; platform_class->object_delete = object_delete; platform_class->ip4_address_add = ip4_address_add; diff --git a/src/platform/nm-netlink.c b/src/platform/nm-netlink.c deleted file mode 100644 index 4cb19780..00000000 --- a/src/platform/nm-netlink.c +++ /dev/null @@ -1,1491 +0,0 @@ -/* -*- Mode: C; tab-width: 4; indent-tabs-mode: t; c-basic-offset: 4 -*- */ -/* nm-platform.c - Handle runtime kernel networking configuration - * - * This program is free software; you can redistribute it and/or modify - * it under the terms of the GNU General Public License as published by - * the Free Software Foundation; either version 2, or (at your option) - * any later version. - * - * This program is distributed in the hope that it will be useful, - * but WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the - * GNU General Public License for more details. - * - * You should have received a copy of the GNU General Public License along - * with this program; if not, write to the Free Software Foundation, Inc., - * 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA. - * - * Copyright (C) 2018 Red Hat, Inc. - */ - -#include "nm-default.h" - -#include "nm-netlink.h" - -#include <unistd.h> -#include <fcntl.h> - -/*****************************************************************************/ - -#ifndef SOL_NETLINK -#define SOL_NETLINK 270 -#endif - -/*****************************************************************************/ - -#define NL_SOCK_PASSCRED (1<<1) -#define NL_MSG_PEEK (1<<3) -#define NL_MSG_PEEK_EXPLICIT (1<<4) -#define NL_NO_AUTO_ACK (1<<5) - -#ifndef NETLINK_EXT_ACK -#define NETLINK_EXT_ACK 11 -#endif - -#define NL_MSG_CRED_PRESENT 1 - -struct nl_msg { - int nm_protocol; - int nm_flags; - struct sockaddr_nl nm_src; - struct sockaddr_nl nm_dst; - struct ucred nm_creds; - struct nlmsghdr * nm_nlh; - size_t nm_size; - int nm_refcnt; -}; - -struct nl_sock { - struct sockaddr_nl s_local; - struct sockaddr_nl s_peer; - int s_fd; - int s_proto; - unsigned int s_seq_next; - unsigned int s_seq_expect; - int s_flags; - size_t s_bufsize; -}; - -/*****************************************************************************/ - -NM_UTILS_LOOKUP_STR_DEFINE_STATIC (_geterror, int, - NM_UTILS_LOOKUP_DEFAULT (NULL), - NM_UTILS_LOOKUP_ITEM (NLE_UNSPEC, "NLE_UNSPEC"), - NM_UTILS_LOOKUP_ITEM (NLE_BUG, "NLE_BUG"), - NM_UTILS_LOOKUP_ITEM (NLE_NATIVE_ERRNO, "NLE_NATIVE_ERRNO"), - - NM_UTILS_LOOKUP_ITEM (NLE_ATTRSIZE, "NLE_ATTRSIZE"), - NM_UTILS_LOOKUP_ITEM (NLE_BAD_SOCK, "NLE_BAD_SOCK"), - NM_UTILS_LOOKUP_ITEM (NLE_DUMP_INTR, "NLE_DUMP_INTR"), - NM_UTILS_LOOKUP_ITEM (NLE_MSG_OVERFLOW, "NLE_MSG_OVERFLOW"), - NM_UTILS_LOOKUP_ITEM (NLE_MSG_TOOSHORT, "NLE_MSG_TOOSHORT"), - NM_UTILS_LOOKUP_ITEM (NLE_MSG_TRUNC, "NLE_MSG_TRUNC"), - NM_UTILS_LOOKUP_ITEM (NLE_SEQ_MISMATCH, "NLE_SEQ_MISMATCH"), -) - -const char * -nl_geterror (int err) -{ - const char *s; - - err = nl_errno (err); - - if (err >= _NLE_BASE) { - s = _geterror (err); - if (s) - return s; - } - return g_strerror (err); -} - -/*****************************************************************************/ - -NM_UTILS_ENUM2STR_DEFINE (nl_nlmsgtype2str, int, - NM_UTILS_ENUM2STR (NLMSG_NOOP, "NOOP"), - NM_UTILS_ENUM2STR (NLMSG_ERROR, "ERROR"), - NM_UTILS_ENUM2STR (NLMSG_DONE, "DONE"), - NM_UTILS_ENUM2STR (NLMSG_OVERRUN, "OVERRUN"), -); - -NM_UTILS_FLAGS2STR_DEFINE (nl_nlmsg_flags2str, int, - NM_UTILS_FLAGS2STR (NLM_F_REQUEST, "REQUEST"), - NM_UTILS_FLAGS2STR (NLM_F_MULTI, "MULTI"), - NM_UTILS_FLAGS2STR (NLM_F_ACK, "ACK"), - NM_UTILS_FLAGS2STR (NLM_F_ECHO, "ECHO"), - NM_UTILS_FLAGS2STR (NLM_F_ROOT, "ROOT"), - NM_UTILS_FLAGS2STR (NLM_F_MATCH, "MATCH"), - NM_UTILS_FLAGS2STR (NLM_F_ATOMIC, "ATOMIC"), - NM_UTILS_FLAGS2STR (NLM_F_REPLACE, "REPLACE"), - NM_UTILS_FLAGS2STR (NLM_F_EXCL, "EXCL"), - NM_UTILS_FLAGS2STR (NLM_F_CREATE, "CREATE"), - NM_UTILS_FLAGS2STR (NLM_F_APPEND, "APPEND"), -); - -/*****************************************************************************/ - -const char * -nl_nlmsghdr_to_str (const struct nlmsghdr *hdr, char *buf, gsize len) -{ - const char *b; - const char *s; - guint flags, flags_before; - const char *prefix; - - if (!nm_utils_to_string_buffer_init_null (hdr, &buf, &len)) - return buf; - - b = buf; - - switch (hdr->nlmsg_type) { - case RTM_NEWLINK: s = "RTM_NEWLINK"; break; - case RTM_DELLINK: s = "RTM_DELLINK"; break; - case RTM_NEWADDR: s = "RTM_NEWADDR"; break; - case RTM_DELADDR: s = "RTM_DELADDR"; break; - case RTM_NEWROUTE: s = "RTM_NEWROUTE"; break; - case RTM_DELROUTE: s = "RTM_DELROUTE"; break; - case RTM_NEWQDISC: s = "RTM_NEWQDISC"; break; - case RTM_DELQDISC: s = "RTM_DELQDISC"; break; - case RTM_NEWTFILTER: s = "RTM_NEWTFILTER"; break; - case RTM_DELTFILTER: s = "RTM_DELTFILTER"; break; - case NLMSG_NOOP: s = "NLMSG_NOOP"; break; - case NLMSG_ERROR: s = "NLMSG_ERROR"; break; - case NLMSG_DONE: s = "NLMSG_DONE"; break; - case NLMSG_OVERRUN: s = "NLMSG_OVERRUN"; break; - default: s = NULL; break; - } - - if (s) - nm_utils_strbuf_append_str (&buf, &len, s); - else - nm_utils_strbuf_append (&buf, &len, "(%u)", (unsigned) hdr->nlmsg_type); - - flags = hdr->nlmsg_flags; - - if (!flags) { - nm_utils_strbuf_append_str (&buf, &len, ", flags 0"); - goto flags_done; - } - -#define _F(f, n) \ - G_STMT_START { \ - if (NM_FLAGS_ALL (flags, f)) { \ - flags &= ~(f); \ - nm_utils_strbuf_append (&buf, &len, "%s%s", prefix, n); \ - if (!flags) \ - goto flags_done; \ - prefix = ","; \ - } \ - } G_STMT_END - - prefix = ", flags "; - flags_before = flags; - _F (NLM_F_REQUEST, "request"); - _F (NLM_F_MULTI, "multi"); - _F (NLM_F_ACK, "ack"); - _F (NLM_F_ECHO, "echo"); - _F (NLM_F_DUMP_INTR, "dump_intr"); - _F (0x20 /*NLM_F_DUMP_FILTERED*/, "dump_filtered"); - - if (flags_before != flags) - prefix = ";"; - - switch (hdr->nlmsg_type) { - case RTM_NEWLINK: - case RTM_NEWADDR: - case RTM_NEWROUTE: - case RTM_NEWQDISC: - case RTM_NEWTFILTER: - _F (NLM_F_REPLACE, "replace"); - _F (NLM_F_EXCL, "excl"); - _F (NLM_F_CREATE, "create"); - _F (NLM_F_APPEND, "append"); - break; - case RTM_GETLINK: - case RTM_GETADDR: - case RTM_GETROUTE: - case RTM_DELQDISC: - case RTM_DELTFILTER: - _F (NLM_F_DUMP, "dump"); - _F (NLM_F_ROOT, "root"); - _F (NLM_F_MATCH, "match"); - _F (NLM_F_ATOMIC, "atomic"); - break; - } - -#undef _F - - if (flags_before != flags) - prefix = ";"; - nm_utils_strbuf_append (&buf, &len, "%s0x%04x", prefix, flags); - -flags_done: - - nm_utils_strbuf_append (&buf, &len, ", seq %u", (unsigned) hdr->nlmsg_seq); - - return b; -} - -/*****************************************************************************/ - -struct nlmsghdr * -nlmsg_hdr (struct nl_msg *n) -{ - return n->nm_nlh; -} - -void * -nlmsg_reserve (struct nl_msg *n, size_t len, int pad) -{ - char *buf = (char *) n->nm_nlh; - size_t nlmsg_len = n->nm_nlh->nlmsg_len; - size_t tlen; - - if (len > n->nm_size) - return NULL; - - tlen = pad ? ((len + (pad - 1)) & ~(pad - 1)) : len; - - if ((tlen + nlmsg_len) > n->nm_size) - return NULL; - - buf += nlmsg_len; - n->nm_nlh->nlmsg_len += tlen; - - if (tlen > len) - memset(buf + len, 0, tlen - len); - - return buf; -} - -/*****************************************************************************/ - -static int - get_default_page_size (void) -{ - static int val = 0; - int v; - - if (G_UNLIKELY (val == 0)) { - v = getpagesize (); - g_assert (v > 0); - val = v; - } - return val; -} - -struct nlattr * -nla_reserve (struct nl_msg *msg, int attrtype, int attrlen) -{ - struct nlattr *nla; - int tlen; - - if (attrlen < 0) - return NULL; - - tlen = NLMSG_ALIGN(msg->nm_nlh->nlmsg_len) + nla_total_size(attrlen); - - if (tlen > msg->nm_size) - return NULL; - - nla = (struct nlattr *) nlmsg_tail(msg->nm_nlh); - nla->nla_type = attrtype; - nla->nla_len = nla_attr_size(attrlen); - - if (attrlen) - memset((unsigned char *) nla + nla->nla_len, 0, nla_padlen(attrlen)); - msg->nm_nlh->nlmsg_len = tlen; - - return nla; -} - -struct nl_msg * -nlmsg_alloc_size (size_t len) -{ - struct nl_msg *nm; - - if (len < sizeof (struct nlmsghdr)) - len = sizeof (struct nlmsghdr); - - nm = g_slice_new0 (struct nl_msg); - - nm->nm_refcnt = 1; - nm->nm_protocol = -1; - nm->nm_size = len; - nm->nm_nlh = g_malloc0 (len); - nm->nm_nlh->nlmsg_len = nlmsg_total_size (0); - return nm; -} - -/** - * Allocate a new netlink message with the default maximum payload size. - * - * Allocates a new netlink message without any further payload. The - * maximum payload size defaults to PAGESIZE or as otherwise specified - * with nlmsg_set_default_size(). - * - * @return Newly allocated netlink message or NULL. - */ -struct nl_msg * -nlmsg_alloc (void) -{ - return nlmsg_alloc_size (get_default_page_size ()); -} - -/** - * Allocate a new netlink message with maximum payload size specified. - */ -struct nl_msg * -nlmsg_alloc_inherit (struct nlmsghdr *hdr) -{ - struct nl_msg *nm; - - nm = nlmsg_alloc (); - if (hdr) { - struct nlmsghdr *new = nm->nm_nlh; - - new->nlmsg_type = hdr->nlmsg_type; - new->nlmsg_flags = hdr->nlmsg_flags; - new->nlmsg_seq = hdr->nlmsg_seq; - new->nlmsg_pid = hdr->nlmsg_pid; - } - - return nm; -} - -struct nl_msg * -nlmsg_alloc_convert (struct nlmsghdr *hdr) -{ - struct nl_msg *nm; - - nm = nlmsg_alloc_size (NLMSG_ALIGN (hdr->nlmsg_len)); - memcpy(nm->nm_nlh, hdr, hdr->nlmsg_len); - return nm; -} - -struct nl_msg * -nlmsg_alloc_simple (int nlmsgtype, int flags) -{ - struct nlmsghdr nlh = { - .nlmsg_type = nlmsgtype, - .nlmsg_flags = flags, - }; - - return nlmsg_alloc_inherit (&nlh); -} - -int -nlmsg_append (struct nl_msg *n, void *data, size_t len, int pad) -{ - void *tmp; - - tmp = nlmsg_reserve (n, len, pad); - if (tmp == NULL) - return -ENOMEM; - - memcpy(tmp, data, len); - return 0; -} - -int -nlmsg_parse (struct nlmsghdr *nlh, int hdrlen, struct nlattr *tb[], - int maxtype, const struct nla_policy *policy) -{ - if (!nlmsg_valid_hdr(nlh, hdrlen)) - return -NLE_MSG_TOOSHORT; - - return nla_parse (tb, maxtype, nlmsg_attrdata(nlh, hdrlen), - nlmsg_attrlen(nlh, hdrlen), policy); -} - -struct nlmsghdr * -nlmsg_put (struct nl_msg *n, uint32_t pid, uint32_t seq, - int type, int payload, int flags) -{ - struct nlmsghdr *nlh; - - if (n->nm_nlh->nlmsg_len < NLMSG_HDRLEN) - g_return_val_if_reached (NULL); - - nlh = (struct nlmsghdr *) n->nm_nlh; - nlh->nlmsg_type = type; - nlh->nlmsg_flags = flags; - nlh->nlmsg_pid = pid; - nlh->nlmsg_seq = seq; - - if (payload > 0 && - nlmsg_reserve(n, payload, NLMSG_ALIGNTO) == NULL) - return NULL; - - return nlh; -} - -uint64_t -nla_get_u64 (const struct nlattr *nla) -{ - uint64_t tmp = 0; - - if (nla && nla_len(nla) >= sizeof (tmp)) - memcpy(&tmp, nla_data(nla), sizeof (tmp)); - - return tmp; -} - -size_t -nla_strlcpy (char *dst, const struct nlattr *nla, size_t dstsize) -{ - size_t srclen = nla_len(nla); - const char *src = nla_data(nla); - - if (srclen > 0 && src[srclen - 1] == '\0') - srclen--; - - if (dstsize > 0) { - size_t len = (srclen >= dstsize) ? dstsize - 1 : srclen; - - memset(dst, 0, dstsize); - memcpy(dst, src, len); - } - - return srclen; -} - -int -nla_memcpy (void *dest, const struct nlattr *src, int count) -{ - int minlen; - - if (!src) - return 0; - - minlen = NM_MIN (count, (int) nla_len (src)); - memcpy(dest, nla_data(src), minlen); - - return minlen; -} - -int -nla_put (struct nl_msg *msg, int attrtype, int datalen, const void *data) -{ - struct nlattr *nla; - - nla = nla_reserve(msg, attrtype, datalen); - if (!nla) { - if (datalen < 0) - g_return_val_if_reached (-NLE_BUG); - - return -ENOMEM; - } - - if (datalen > 0) - memcpy (nla_data(nla), data, datalen); - - return 0; -} - -struct nlattr * -nla_find (const struct nlattr *head, int len, int attrtype) -{ - const struct nlattr *nla; - int rem; - - nla_for_each_attr (nla, head, len, rem) { - if (nla_type (nla) == attrtype) - return (struct nlattr*)nla; - } - - return NULL; -} - -void -nla_nest_cancel (struct nl_msg *msg, const struct nlattr *attr) -{ - ssize_t len; - - len = (char *) nlmsg_tail(msg->nm_nlh) - (char *) attr; - if (len < 0) - g_return_if_reached (); - else if (len > 0) { - msg->nm_nlh->nlmsg_len -= len; - memset(nlmsg_tail(msg->nm_nlh), 0, len); - } -} - -struct nlattr * -nla_nest_start (struct nl_msg *msg, int attrtype) -{ - struct nlattr *start = (struct nlattr *) nlmsg_tail(msg->nm_nlh); - - if (nla_put(msg, attrtype, 0, NULL) < 0) - return NULL; - - return start; -} - -static int -_nest_end (struct nl_msg *msg, struct nlattr *start, int keep_empty) -{ - size_t pad, len; - - len = (char *) nlmsg_tail(msg->nm_nlh) - (char *) start; - - if ( len > USHRT_MAX - || (!keep_empty && len == NLA_HDRLEN)) { - /* - * Max nlattr size exceeded or empty nested attribute, trim the - * attribute header again - */ - nla_nest_cancel(msg, start); - - /* Return error only if nlattr size was exceeded */ - return (len == NLA_HDRLEN) ? 0 : -NLE_ATTRSIZE; - } - - start->nla_len = len; - - pad = NLMSG_ALIGN(msg->nm_nlh->nlmsg_len) - msg->nm_nlh->nlmsg_len; - if (pad > 0) { - /* - * Data inside attribute does not end at a alignment boundry. - * Pad accordingly and accoun for the additional space in - * the message. nlmsg_reserve() may never fail in this situation, - * the allocate message buffer must be a multiple of NLMSG_ALIGNTO. - */ - if (!nlmsg_reserve(msg, pad, 0)) - g_return_val_if_reached (-NLE_BUG); - } - - return 0; -} - -int -nla_nest_end (struct nl_msg *msg, struct nlattr *start) -{ - return _nest_end (msg, start, 0); -} - -static const uint16_t nla_attr_minlen[NLA_TYPE_MAX+1] = { - [NLA_U8] = sizeof (uint8_t), - [NLA_U16] = sizeof (uint16_t), - [NLA_U32] = sizeof (uint32_t), - [NLA_U64] = sizeof (uint64_t), - [NLA_STRING] = 1, - [NLA_FLAG] = 0, -}; - -static int -validate_nla (const struct nlattr *nla, int maxtype, - const struct nla_policy *policy) -{ - const struct nla_policy *pt; - unsigned int minlen = 0; - int type = nla_type(nla); - - if (type < 0 || type > maxtype) - return 0; - - pt = &policy[type]; - - if (pt->type > NLA_TYPE_MAX) - g_return_val_if_reached (-NLE_BUG); - - if (pt->minlen) - minlen = pt->minlen; - else if (pt->type != NLA_UNSPEC) - minlen = nla_attr_minlen[pt->type]; - - if (nla_len(nla) < minlen) - return -NLE_UNSPEC; - - if (pt->maxlen && nla_len(nla) > pt->maxlen) - return -NLE_UNSPEC; - - if (pt->type == NLA_STRING) { - const char *data = nla_data(nla); - if (data[nla_len(nla) - 1] != '\0') - return -NLE_UNSPEC; - } - - return 0; -} - -int -nla_parse (struct nlattr *tb[], int maxtype, struct nlattr *head, int len, - const struct nla_policy *policy) -{ - struct nlattr *nla; - int rem, err; - - memset(tb, 0, sizeof (struct nlattr *) * (maxtype + 1)); - - nla_for_each_attr(nla, head, len, rem) { - int type = nla_type(nla); - - if (type > maxtype) - continue; - - if (policy) { - err = validate_nla(nla, maxtype, policy); - if (err < 0) - goto errout; - } - - tb[type] = nla; - } - - err = 0; -errout: - return err; -} - -/*****************************************************************************/ - -void nlmsg_free (struct nl_msg *msg) -{ - if (!msg) - return; - - if (msg->nm_refcnt < 1) - g_return_if_reached (); - - msg->nm_refcnt--; - - if (msg->nm_refcnt <= 0) { - g_free (msg->nm_nlh); - g_slice_free (struct nl_msg, msg); - } -} - -int -nlmsg_get_proto (struct nl_msg *msg) -{ - return msg->nm_protocol; -} - -void -nlmsg_set_proto (struct nl_msg *msg, int protocol) -{ - msg->nm_protocol = protocol; -} - -void -nlmsg_set_src (struct nl_msg *msg, struct sockaddr_nl *addr) -{ - memcpy (&msg->nm_src, addr, sizeof (*addr)); -} - -struct ucred * -nlmsg_get_creds (struct nl_msg *msg) -{ - if (msg->nm_flags & NL_MSG_CRED_PRESENT) - return &msg->nm_creds; - return NULL; -} - -void -nlmsg_set_creds (struct nl_msg *msg, struct ucred *creds) -{ - memcpy (&msg->nm_creds, creds, sizeof (*creds)); - msg->nm_flags |= NL_MSG_CRED_PRESENT; -} - -/*****************************************************************************/ - -void * -genlmsg_put (struct nl_msg *msg, uint32_t port, uint32_t seq, int family, - int hdrlen, int flags, uint8_t cmd, uint8_t version) -{ - struct nlmsghdr *nlh; - struct genlmsghdr hdr = { - .cmd = cmd, - .version = version, - }; - - nlh = nlmsg_put (msg, port, seq, family, GENL_HDRLEN + hdrlen, flags); - if (nlh == NULL) - return NULL; - - memcpy (nlmsg_data (nlh), &hdr, sizeof (hdr)); - - return (char *) nlmsg_data (nlh) + GENL_HDRLEN; -} - -void * -genlmsg_data (const struct genlmsghdr *gnlh) -{ - return ((unsigned char *) gnlh + GENL_HDRLEN); -} - -void * -genlmsg_user_hdr (const struct genlmsghdr *gnlh) -{ - return genlmsg_data (gnlh); -} - -struct genlmsghdr * -genlmsg_hdr (struct nlmsghdr *nlh) -{ - return nlmsg_data (nlh); -} - -void * -genlmsg_user_data (const struct genlmsghdr *gnlh, const int hdrlen) -{ - return (char *) genlmsg_user_hdr (gnlh) + NLMSG_ALIGN (hdrlen); -} - -struct nlattr * -genlmsg_attrdata (const struct genlmsghdr *gnlh, int hdrlen) -{ - return genlmsg_user_data (gnlh, hdrlen); -} - -int -genlmsg_len (const struct genlmsghdr *gnlh) -{ - const struct nlmsghdr *nlh; - - nlh = (const struct nlmsghdr *) ((const unsigned char *) gnlh - NLMSG_HDRLEN); - return (nlh->nlmsg_len - GENL_HDRLEN - NLMSG_HDRLEN); -} - -int -genlmsg_attrlen (const struct genlmsghdr *gnlh, int hdrlen) -{ - return genlmsg_len (gnlh) - NLMSG_ALIGN (hdrlen); -} - -int -genlmsg_valid_hdr (struct nlmsghdr *nlh, int hdrlen) -{ - struct genlmsghdr *ghdr; - - if (!nlmsg_valid_hdr (nlh, GENL_HDRLEN)) - return 0; - - ghdr = nlmsg_data (nlh); - if (genlmsg_len (ghdr) < NLMSG_ALIGN (hdrlen)) - return 0; - - return 1; -} - -int -genlmsg_parse (struct nlmsghdr *nlh, int hdrlen, struct nlattr *tb[], - int maxtype, const struct nla_policy *policy) -{ - struct genlmsghdr *ghdr; - - if (!genlmsg_valid_hdr (nlh, hdrlen)) - return -NLE_MSG_TOOSHORT; - - ghdr = nlmsg_data (nlh); - return nla_parse (tb, maxtype, genlmsg_attrdata (ghdr, hdrlen), - genlmsg_attrlen (ghdr, hdrlen), policy); -} - -static int -_genl_parse_getfamily (struct nl_msg *msg, void *arg) -{ - static const struct nla_policy ctrl_policy[CTRL_ATTR_MAX+1] = { - [CTRL_ATTR_FAMILY_ID] = { .type = NLA_U16 }, - [CTRL_ATTR_FAMILY_NAME] = { .type = NLA_STRING, - .maxlen = GENL_NAMSIZ }, - [CTRL_ATTR_VERSION] = { .type = NLA_U32 }, - [CTRL_ATTR_HDRSIZE] = { .type = NLA_U32 }, - [CTRL_ATTR_MAXATTR] = { .type = NLA_U32 }, - [CTRL_ATTR_OPS] = { .type = NLA_NESTED }, - [CTRL_ATTR_MCAST_GROUPS] = { .type = NLA_NESTED }, - }; - struct nlattr *tb[CTRL_ATTR_MAX+1]; - struct nlmsghdr *nlh = nlmsg_hdr (msg); - gint32 *response_data = arg; - - if (genlmsg_parse (nlh, 0, tb, CTRL_ATTR_MAX, ctrl_policy)) - return NL_SKIP; - - if (tb[CTRL_ATTR_FAMILY_ID]) - *response_data = nla_get_u16 (tb[CTRL_ATTR_FAMILY_ID]); - - return NL_STOP; -} - -int -genl_ctrl_resolve (struct nl_sock *sk, const char *name) -{ - nm_auto_nlmsg struct nl_msg *msg = NULL; - int result = -ENOMEM; - gint32 response_data = -1; - const struct nl_cb cb = { - .valid_cb = _genl_parse_getfamily, - .valid_arg = &response_data, - }; - - msg = nlmsg_alloc (); - - if (!genlmsg_put (msg, NL_AUTO_PORT, NL_AUTO_SEQ, GENL_ID_CTRL, - 0, 0, CTRL_CMD_GETFAMILY, 1)) - goto out; - - if (nla_put_string (msg, CTRL_ATTR_FAMILY_NAME, name) < 0) - goto out; - - result = nl_send_auto (sk, msg); - if (result < 0) - goto out; - - result = nl_recvmsgs (sk, &cb); - if (result < 0) - goto out; - - /* If search was successful, request may be ACKed after data */ - result = nl_wait_for_ack (sk, NULL); - if (result < 0) - goto out; - - if (response_data > 0) - result = response_data; - else - result = -ENOENT; - -out: - return result; -} - -/*****************************************************************************/ - -struct nl_sock * -nl_socket_alloc (void) -{ - struct nl_sock *sk; - - sk = g_slice_new0 (struct nl_sock); - - sk->s_fd = -1; - sk->s_local.nl_family = AF_NETLINK; - sk->s_peer.nl_family = AF_NETLINK; - sk->s_seq_expect = sk->s_seq_next = time(NULL); - - return sk; -} - -void -nl_socket_free (struct nl_sock *sk) -{ - if (!sk) - return; - - if (sk->s_fd >= 0) - nm_close (sk->s_fd); - g_slice_free (struct nl_sock, sk); -} - -int -nl_socket_get_fd (const struct nl_sock *sk) -{ - return sk->s_fd; -} - -uint32_t -nl_socket_get_local_port (const struct nl_sock *sk) -{ - return sk->s_local.nl_pid; -} - -size_t -nl_socket_get_msg_buf_size (struct nl_sock *sk) -{ - return sk->s_bufsize; -} - -int -nl_socket_set_passcred (struct nl_sock *sk, int state) -{ - int err; - - if (sk->s_fd == -1) - return -NLE_BAD_SOCK; - - err = setsockopt (sk->s_fd, SOL_SOCKET, SO_PASSCRED, - &state, sizeof (state)); - if (err < 0) - return -nl_syserr2nlerr (errno); - - if (state) - sk->s_flags |= NL_SOCK_PASSCRED; - else - sk->s_flags &= ~NL_SOCK_PASSCRED; - - return 0; -} - -int -nl_socket_set_msg_buf_size (struct nl_sock *sk, size_t bufsize) -{ - sk->s_bufsize = bufsize; - - return 0; -} - -struct sockaddr_nl * -nlmsg_get_dst (struct nl_msg *msg) -{ - return &msg->nm_dst; -} - -int -nl_socket_set_nonblocking (const struct nl_sock *sk) -{ - if (sk->s_fd == -1) - return -NLE_BAD_SOCK; - - if (fcntl(sk->s_fd, F_SETFL, O_NONBLOCK) < 0) - return -nl_syserr2nlerr (errno); - - return 0; -} - -int -nl_socket_set_buffer_size (struct nl_sock *sk, int rxbuf, int txbuf) -{ - int err; - - if (rxbuf <= 0) - rxbuf = 32768; - - if (txbuf <= 0) - txbuf = 32768; - - if (sk->s_fd == -1) - return -NLE_BAD_SOCK; - - err = setsockopt (sk->s_fd, SOL_SOCKET, SO_SNDBUF, - &txbuf, sizeof (txbuf)); - if (err < 0) { - return -nl_syserr2nlerr (errno); - } - - err = setsockopt (sk->s_fd, SOL_SOCKET, SO_RCVBUF, - &rxbuf, sizeof (rxbuf)); - if (err < 0) { - return -nl_syserr2nlerr (errno); - } - - return 0; -} - -int -nl_socket_add_memberships (struct nl_sock *sk, int group, ...) -{ - int err; - va_list ap; - - if (sk->s_fd == -1) - return -NLE_BAD_SOCK; - - va_start(ap, group); - - while (group != 0) { - if (group < 0) { - va_end(ap); - g_return_val_if_reached (-NLE_BUG); - } - - err = setsockopt (sk->s_fd, SOL_NETLINK, NETLINK_ADD_MEMBERSHIP, - &group, sizeof (group)); - if (err < 0) { - va_end(ap); - return -nl_syserr2nlerr (errno); - } - - group = va_arg(ap, int); - } - - va_end(ap); - - return 0; -} - -int -nl_socket_set_ext_ack (struct nl_sock *sk, gboolean enable) -{ - int err, val; - - if (sk->s_fd == -1) - return -NLE_BAD_SOCK; - - val = !!enable; - err = setsockopt (sk->s_fd, SOL_NETLINK, NETLINK_EXT_ACK, &val, sizeof (val)); - if (err < 0) - return -nl_syserr2nlerr (errno); - - return 0; -} - -void nl_socket_disable_msg_peek (struct nl_sock *sk) -{ - sk->s_flags |= NL_MSG_PEEK_EXPLICIT; - sk->s_flags &= ~NL_MSG_PEEK; -} - -int -nl_connect (struct nl_sock *sk, int protocol) -{ - int err; - socklen_t addrlen; - struct sockaddr_nl local = { 0 }; - - if (sk->s_fd != -1) - return -NLE_BAD_SOCK; - - sk->s_fd = socket (AF_NETLINK, SOCK_RAW | SOCK_CLOEXEC, protocol); - if (sk->s_fd < 0) { - err = -nl_syserr2nlerr (errno); - goto errout; - } - - err = nl_socket_set_buffer_size(sk, 0, 0); - if (err < 0) - goto errout; - - nm_assert (sk->s_local.nl_pid == 0); - - err = bind (sk->s_fd, (struct sockaddr*) &sk->s_local, - sizeof (sk->s_local)); - if (err != 0) { - err = -nl_syserr2nlerr (errno); - goto errout; - } - - addrlen = sizeof (local); - err = getsockname (sk->s_fd, (struct sockaddr *) &local, - &addrlen); - if (err < 0) { - err = -nl_syserr2nlerr (errno); - goto errout; - } - - if (addrlen != sizeof (local)) { - err = -NLE_UNSPEC; - goto errout; - } - - if (local.nl_family != AF_NETLINK) { - err = -NLE_UNSPEC; - goto errout; - } - - sk->s_local = local; - sk->s_proto = protocol; - - return 0; - -errout: - if (sk->s_fd != -1) { - close(sk->s_fd); - sk->s_fd = -1; - } - return err; -} - -/*****************************************************************************/ - -static void -_cb_init (struct nl_cb *dst, const struct nl_cb *src) -{ - nm_assert (dst); - - if (src) - *dst = *src; - else - memset (dst, 0, sizeof (*dst)); -} - -static int ack_wait_handler(struct nl_msg *msg, void *arg) -{ - return NL_STOP; -} - -int -nl_wait_for_ack (struct nl_sock *sk, - const struct nl_cb *cb) -{ - struct nl_cb cb2; - - _cb_init (&cb2, cb); - cb2.ack_cb = ack_wait_handler; - return nl_recvmsgs (sk, &cb2); -} - -#define NL_CB_CALL(cb, type, msg) \ -do { \ - const struct nl_cb *_cb = (cb); \ - \ - if (_cb->type##_cb) { \ - err = _cb->type##_cb ((msg), _cb->type##_arg); \ - switch (err) { \ - case NL_OK: \ - err = 0; \ - break; \ - case NL_SKIP: \ - goto skip; \ - case NL_STOP: \ - goto stop; \ - default: \ - goto out; \ - } \ - } \ -} while (0) - -int -nl_recvmsgs (struct nl_sock *sk, const struct nl_cb *cb) -{ - int n, err = 0, multipart = 0, interrupted = 0, nrecv = 0; - gs_free unsigned char *buf = NULL; - struct nlmsghdr *hdr; - struct sockaddr_nl nla = { 0 }; - gs_free struct ucred *creds = NULL; - -continue_reading: - n = nl_recv (sk, &nla, &buf, &creds); - if (n <= 0) - return n; - - hdr = (struct nlmsghdr *) buf; - while (nlmsg_ok (hdr, n)) { - nm_auto_nlmsg struct nl_msg *msg = NULL; - - msg = nlmsg_alloc_convert (hdr); - - nlmsg_set_proto (msg, sk->s_proto); - nlmsg_set_src (msg, &nla); - if (creds) - nlmsg_set_creds (msg, creds); - - nrecv++; - - /* Only do sequence checking if auto-ack mode is enabled */ - if (!(sk->s_flags & NL_NO_AUTO_ACK)) { - if (hdr->nlmsg_seq != sk->s_seq_expect) { - err = -NLE_SEQ_MISMATCH; - goto out; - } - } - - if (hdr->nlmsg_type == NLMSG_DONE || - hdr->nlmsg_type == NLMSG_ERROR || - hdr->nlmsg_type == NLMSG_NOOP || - hdr->nlmsg_type == NLMSG_OVERRUN) { - /* We can't check for !NLM_F_MULTI since some netlink - * users in the kernel are broken. */ - sk->s_seq_expect++; - } - - if (hdr->nlmsg_flags & NLM_F_MULTI) - multipart = 1; - - if (hdr->nlmsg_flags & NLM_F_DUMP_INTR) { - /* - * We have to continue reading to clear - * all messages until a NLMSG_DONE is - * received and report the inconsistency. - */ - interrupted = 1; - } - - /* messages terminates a multipart message, this is - * usually the end of a message and therefore we slip - * out of the loop by default. the user may overrule - * this action by skipping this packet. */ - if (hdr->nlmsg_type == NLMSG_DONE) { - multipart = 0; - NL_CB_CALL(cb, finish, msg); - } - - /* Message to be ignored, the default action is to - * skip this message if no callback is specified. The - * user may overrule this action by returning - * NL_PROCEED. */ - else if (hdr->nlmsg_type == NLMSG_NOOP) - goto skip; - - /* Data got lost, report back to user. The default action is to - * quit parsing. The user may overrule this action by retuning - * NL_SKIP or NL_PROCEED (dangerous) */ - else if (hdr->nlmsg_type == NLMSG_OVERRUN) { - err = -NLE_MSG_OVERFLOW; - goto out; - } - - /* Message carries a nlmsgerr */ - else if (hdr->nlmsg_type == NLMSG_ERROR) { - struct nlmsgerr *e = nlmsg_data(hdr); - - if (hdr->nlmsg_len < nlmsg_size(sizeof (*e))) { - /* Truncated error message, the default action - * is to stop parsing. The user may overrule - * this action by returning NL_SKIP or - * NL_PROCEED (dangerous) */ - err = -NLE_MSG_TRUNC; - goto out; - } - if (e->error) { - /* Error message reported back from kernel. */ - if (cb->err_cb) { - err = cb->err_cb (&nla, e, - cb->err_arg); - if (err < 0) - goto out; - else if (err == NL_SKIP) - goto skip; - else if (err == NL_STOP) { - err = -e->error; - goto out; - } - } else { - err = -e->error; - goto out; - } - } else - NL_CB_CALL(cb, ack, msg); - } else { - /* Valid message (not checking for MULTIPART bit to - * get along with broken kernels. NL_SKIP has no - * effect on this. */ - NL_CB_CALL(cb, valid, msg); - } -skip: - err = 0; - hdr = nlmsg_next(hdr, &n); - } - - if (multipart) { - /* Multipart message not yet complete, continue reading */ - nm_clear_g_free (&creds); - nm_clear_g_free (&buf); - - goto continue_reading; - } - -stop: - err = 0; - -out: - if (interrupted) - err = -NLE_DUMP_INTR; - - return err ?: nrecv; -} - -int -nl_sendmsg (struct nl_sock *sk, struct nl_msg *msg, struct msghdr *hdr) -{ - int ret; - - if (sk->s_fd < 0) - return -NLE_BAD_SOCK; - - nlmsg_set_src (msg, &sk->s_local); - - ret = sendmsg(sk->s_fd, hdr, 0); - if (ret < 0) - return -nl_syserr2nlerr (errno); - - return ret; -} - -int -nl_send_iovec (struct nl_sock *sk, struct nl_msg *msg, struct iovec *iov, unsigned iovlen) -{ - struct sockaddr_nl *dst; - struct ucred *creds; - struct msghdr hdr = { - .msg_name = (void *) &sk->s_peer, - .msg_namelen = sizeof (struct sockaddr_nl), - .msg_iov = iov, - .msg_iovlen = iovlen, - }; - char buf[CMSG_SPACE(sizeof (struct ucred))]; - - /* Overwrite destination if specified in the message itself, defaults - * to the peer address of the socket. - */ - dst = nlmsg_get_dst(msg); - if (dst->nl_family == AF_NETLINK) - hdr.msg_name = dst; - - /* Add credentials if present. */ - creds = nlmsg_get_creds(msg); - if (creds != NULL) { - struct cmsghdr *cmsg; - - hdr.msg_control = buf; - hdr.msg_controllen = sizeof (buf); - - cmsg = CMSG_FIRSTHDR(&hdr); - cmsg->cmsg_level = SOL_SOCKET; - cmsg->cmsg_type = SCM_CREDENTIALS; - cmsg->cmsg_len = CMSG_LEN(sizeof (struct ucred)); - memcpy(CMSG_DATA(cmsg), creds, sizeof (struct ucred)); - } - - return nl_sendmsg(sk, msg, &hdr); -} - -void -nl_complete_msg (struct nl_sock *sk, struct nl_msg *msg) -{ - struct nlmsghdr *nlh; - - nlh = nlmsg_hdr(msg); - if (nlh->nlmsg_pid == NL_AUTO_PORT) - nlh->nlmsg_pid = nl_socket_get_local_port(sk); - - if (nlh->nlmsg_seq == NL_AUTO_SEQ) - nlh->nlmsg_seq = sk->s_seq_next++; - - if (msg->nm_protocol == -1) - msg->nm_protocol = sk->s_proto; - - nlh->nlmsg_flags |= NLM_F_REQUEST; - - if (!(sk->s_flags & NL_NO_AUTO_ACK)) - nlh->nlmsg_flags |= NLM_F_ACK; -} - -int -nl_send (struct nl_sock *sk, struct nl_msg *msg) -{ - struct iovec iov = { - .iov_base = (void *) nlmsg_hdr(msg), - .iov_len = nlmsg_hdr(msg)->nlmsg_len, - }; - - return nl_send_iovec(sk, msg, &iov, 1); -} - -int nl_send_auto(struct nl_sock *sk, struct nl_msg *msg) -{ - nl_complete_msg(sk, msg); - - return nl_send(sk, msg); -} - -int -nl_recv (struct nl_sock *sk, struct sockaddr_nl *nla, - unsigned char **buf, struct ucred **creds) -{ - ssize_t n; - int flags = 0; - static int page_size = 0; - struct iovec iov; - struct msghdr msg = { - .msg_name = (void *) nla, - .msg_namelen = sizeof (struct sockaddr_nl), - .msg_iov = &iov, - .msg_iovlen = 1, - }; - gs_free struct ucred* tmpcreds = NULL; - int retval; - - nm_assert (nla); - nm_assert (buf && !*buf); - nm_assert (!creds || !*creds); - - if ( (sk->s_flags & NL_MSG_PEEK) - || ( !(sk->s_flags & NL_MSG_PEEK_EXPLICIT) - && sk->s_bufsize == 0)) - flags |= MSG_PEEK | MSG_TRUNC; - - if (page_size == 0) - page_size = getpagesize() * 4; - - iov.iov_len = sk->s_bufsize ? : page_size; - iov.iov_base = g_malloc (iov.iov_len); - - if ( creds - && (sk->s_flags & NL_SOCK_PASSCRED)) { - msg.msg_controllen = CMSG_SPACE (sizeof (struct ucred)); - msg.msg_control = g_malloc (msg.msg_controllen); - } - -retry: - n = recvmsg(sk->s_fd, &msg, flags); - if (!n) { - retval = 0; - goto abort; - } - - if (n < 0) { - if (errno == EINTR) - goto retry; - - retval = -nl_syserr2nlerr (errno); - goto abort; - } - - if (msg.msg_flags & MSG_CTRUNC) { - if (msg.msg_controllen == 0) { - retval = -NLE_MSG_TRUNC; - goto abort; - } - - msg.msg_controllen *= 2; - msg.msg_control = g_realloc (msg.msg_control, msg.msg_controllen); - goto retry; - } - - if ( iov.iov_len < n - || (msg.msg_flags & MSG_TRUNC)) { - /* respond with error to an incomplete message */ - if (flags == 0) { - retval = -NLE_MSG_TRUNC; - goto abort; - } - - /* Provided buffer is not long enough, enlarge it - * to size of n (which should be total length of the message) - * and try again. */ - iov.iov_base = g_realloc (iov.iov_base, n); - iov.iov_len = n; - flags = 0; - goto retry; - } - - if (flags != 0) { - /* Buffer is big enough, do the actual reading */ - flags = 0; - goto retry; - } - - if (msg.msg_namelen != sizeof (struct sockaddr_nl)) { - retval = -NLE_UNSPEC; - goto abort; - } - - if (creds && (sk->s_flags & NL_SOCK_PASSCRED)) { - struct cmsghdr *cmsg; - - for (cmsg = CMSG_FIRSTHDR(&msg); cmsg; cmsg = CMSG_NXTHDR(&msg, cmsg)) { - if (cmsg->cmsg_level != SOL_SOCKET) - continue; - if (cmsg->cmsg_type != SCM_CREDENTIALS) - continue; - tmpcreds = g_memdup (CMSG_DATA(cmsg), sizeof (*tmpcreds)); - break; - } - } - - retval = n; - -abort: - g_free (msg.msg_control); - - if (retval <= 0) { - g_free (iov.iov_base); - return retval; - } - - *buf = iov.iov_base; - NM_SET_OUT (creds, g_steal_pointer (&tmpcreds)); - return retval; -} diff --git a/src/platform/nm-netlink.h b/src/platform/nm-netlink.h deleted file mode 100644 index c0dc09c4..00000000 --- a/src/platform/nm-netlink.h +++ /dev/null @@ -1,511 +0,0 @@ -/* -*- Mode: C; tab-width: 4; indent-tabs-mode: t; c-basic-offset: 4 -*- */ -/* nm-platform.c - Handle runtime kernel networking configuration - * - * This program is free software; you can redistribute it and/or modify - * it under the terms of the GNU General Public License as published by - * the Free Software Foundation; either version 2, or (at your option) - * any later version. - * - * This program is distributed in the hope that it will be useful, - * but WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the - * GNU General Public License for more details. - * - * You should have received a copy of the GNU General Public License along - * with this program; if not, write to the Free Software Foundation, Inc., - * 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA. - * - * Copyright (C) 2018 Red Hat, Inc. - */ - -#ifndef __NM_NETLINK_H__ -#define __NM_NETLINK_H__ - -#include <linux/netlink.h> -#include <linux/rtnetlink.h> -#include <linux/genetlink.h> - -/*****************************************************************************/ -#define _NLE_BASE 100000 -#define NLE_UNSPEC (_NLE_BASE + 0) -#define NLE_BUG (_NLE_BASE + 1) -#define NLE_NATIVE_ERRNO (_NLE_BASE + 2) -#define NLE_SEQ_MISMATCH (_NLE_BASE + 3) -#define NLE_MSG_TRUNC (_NLE_BASE + 4) -#define NLE_MSG_TOOSHORT (_NLE_BASE + 5) -#define NLE_DUMP_INTR (_NLE_BASE + 6) -#define NLE_ATTRSIZE (_NLE_BASE + 7) -#define NLE_BAD_SOCK (_NLE_BASE + 8) -#define NLE_NOADDR (_NLE_BASE + 9) -#define NLE_MSG_OVERFLOW (_NLE_BASE + 10) - -#define _NLE_BASE_END (_NLE_BASE + 11) - -#define NLMSGERR_ATTR_UNUSED 0 -#define NLMSGERR_ATTR_MSG 1 -#define NLMSGERR_ATTR_OFFS 2 -#define NLMSGERR_ATTR_COOKIE 3 -#define NLMSGERR_ATTR_MAX 3 - -#ifndef NLM_F_ACK_TLVS -#define NLM_F_ACK_TLVS 0x200 -#endif - -static inline int -nl_errno (int err) -{ - /* the error codes from our netlink implementation are plain errno - * extended with our own error in a particular range starting from - * _NLE_BASE. - * - * However, often we encode errors as negative values. This function - * normalizes the error and returns its positive value. */ - return err >= 0 - ? err - : ((err == G_MININT) ? NLE_BUG : -errno); -} - -static inline int -nl_syserr2nlerr (int err) -{ - if (err == G_MININT) - return NLE_NATIVE_ERRNO; - if (err < 0) - err = -err; - return (err >= _NLE_BASE && err < _NLE_BASE_END) - ? NLE_NATIVE_ERRNO - : err; -} - -const char *nl_geterror (int err); - -/*****************************************************************************/ - -/* Basic attribute data types */ -enum { - NLA_UNSPEC, /* Unspecified type, binary data chunk */ - NLA_U8, /* 8 bit integer */ - NLA_U16, /* 16 bit integer */ - NLA_U32, /* 32 bit integer */ - NLA_U64, /* 64 bit integer */ - NLA_STRING, /* NUL terminated character string */ - NLA_FLAG, /* Flag */ - NLA_MSECS, /* Micro seconds (64bit) */ - NLA_NESTED, /* Nested attributes */ - NLA_NESTED_COMPAT, - NLA_NUL_STRING, - NLA_BINARY, - NLA_S8, - NLA_S16, - NLA_S32, - NLA_S64, - __NLA_TYPE_MAX, -}; - -#define NLA_TYPE_MAX (__NLA_TYPE_MAX - 1) - -struct nl_msg; - -/*****************************************************************************/ - -const char *nl_nlmsgtype2str (int type, char *buf, size_t size); - -const char *nl_nlmsg_flags2str (int flags, char *buf, size_t len); - -const char *nl_nlmsghdr_to_str (const struct nlmsghdr *hdr, char *buf, gsize len); - -/*****************************************************************************/ - -struct nla_policy { - /* Type of attribute or NLA_UNSPEC */ - uint16_t type; - - /* Minimal length of payload required */ - uint16_t minlen; - - /* Maximal length of payload allowed */ - uint16_t maxlen; -}; - -/*****************************************************************************/ - -static inline int -nla_attr_size(int payload) -{ - nm_assert (payload >= 0); - - return NLA_HDRLEN + payload; -} - -static inline int -nla_total_size (int payload) -{ - return NLA_ALIGN (nla_attr_size (payload)); -} - -static inline int -nla_padlen (int payload) -{ - return nla_total_size(payload) - nla_attr_size(payload); -} - -struct nlattr *nla_reserve (struct nl_msg *msg, int attrtype, int attrlen); - -static inline int -nla_len (const struct nlattr *nla) -{ - return nla->nla_len - NLA_HDRLEN; -} - -static inline int -nla_type (const struct nlattr *nla) -{ - return nla->nla_type & NLA_TYPE_MASK; -} - -static inline void * -nla_data (const struct nlattr *nla) -{ - nm_assert (nla); - return (char *) nla + NLA_HDRLEN; -} - -static inline uint8_t -nla_get_u8 (const struct nlattr *nla) -{ - return *(const uint8_t *) nla_data (nla); -} - -static inline uint8_t -nla_get_u8_cond (/*const*/ struct nlattr *const*tb, int attr, uint8_t default_val) -{ - nm_assert (tb); - nm_assert (attr >= 0); - - return tb[attr] ? nla_get_u8 (tb[attr]) : default_val; -} - -static inline uint16_t -nla_get_u16 (const struct nlattr *nla) -{ - return *(const uint16_t *) nla_data (nla); -} - -static inline uint32_t -nla_get_u32(const struct nlattr *nla) -{ - return *(const uint32_t *) nla_data (nla); -} - -uint64_t nla_get_u64 (const struct nlattr *nla); - -static inline char * -nla_get_string (const struct nlattr *nla) -{ - return (char *) nla_data (nla); -} - -size_t nla_strlcpy (char *dst, const struct nlattr *nla, size_t dstsize); - -int nla_memcpy (void *dest, const struct nlattr *src, int count); - -int nla_put (struct nl_msg *msg, int attrtype, int datalen, const void *data); - -static inline int -nla_put_string (struct nl_msg *msg, int attrtype, const char *str) -{ - return nla_put(msg, attrtype, strlen(str) + 1, str); -} - -#define NLA_PUT(msg, attrtype, attrlen, data) \ - do { \ - if (nla_put(msg, attrtype, attrlen, data) < 0) \ - goto nla_put_failure; \ - } while(0) - -#define NLA_PUT_TYPE(msg, type, attrtype, value) \ - do { \ - type __tmp = value; \ - NLA_PUT(msg, attrtype, sizeof(type), &__tmp); \ - } while(0) - -#define NLA_PUT_U8(msg, attrtype, value) \ - NLA_PUT_TYPE(msg, uint8_t, attrtype, value) - -#define NLA_PUT_U16(msg, attrtype, value) \ - NLA_PUT_TYPE(msg, uint16_t, attrtype, value) - -#define NLA_PUT_U32(msg, attrtype, value) \ - NLA_PUT_TYPE(msg, uint32_t, attrtype, value) - -#define NLA_PUT_U64(msg, attrtype, value) \ - NLA_PUT_TYPE(msg, uint64_t, attrtype, value) - -#define NLA_PUT_STRING(msg, attrtype, value) \ - NLA_PUT(msg, attrtype, (int) strlen(value) + 1, value) - -struct nlattr *nla_find (const struct nlattr *head, int len, int attrtype); - -static inline int -nla_ok (const struct nlattr *nla, int remaining) -{ - return remaining >= sizeof(*nla) && - nla->nla_len >= sizeof(*nla) && - nla->nla_len <= remaining; -} - -static inline struct nlattr * -nla_next(const struct nlattr *nla, int *remaining) -{ - int totlen = NLA_ALIGN(nla->nla_len); - - *remaining -= totlen; - return (struct nlattr *) ((char *) nla + totlen); -} - -#define nla_for_each_attr(pos, head, len, rem) \ - for (pos = head, rem = len; \ - nla_ok(pos, rem); \ - pos = nla_next(pos, &(rem))) - -#define nla_for_each_nested(pos, nla, rem) \ - for (pos = (struct nlattr *) nla_data(nla), rem = nla_len(nla); \ - nla_ok(pos, rem); \ - pos = nla_next(pos, &(rem))) - -void nla_nest_cancel (struct nl_msg *msg, const struct nlattr *attr); -struct nlattr *nla_nest_start (struct nl_msg *msg, int attrtype); -int nla_nest_end (struct nl_msg *msg, struct nlattr *start); - -int nla_parse (struct nlattr *tb[], int maxtype, struct nlattr *head, int len, - const struct nla_policy *policy); - -static inline int -nla_parse_nested (struct nlattr *tb[], int maxtype, struct nlattr *nla, - const struct nla_policy *policy) -{ - return nla_parse (tb, maxtype, nla_data(nla), nla_len(nla), policy); -} - -/*****************************************************************************/ - -struct nl_msg *nlmsg_alloc (void); - -struct nl_msg *nlmsg_alloc_size (size_t max); - -struct nl_msg *nlmsg_alloc_inherit (struct nlmsghdr *hdr); - -struct nl_msg *nlmsg_alloc_convert (struct nlmsghdr *hdr); - -struct nl_msg *nlmsg_alloc_simple (int nlmsgtype, int flags); - -void *nlmsg_reserve (struct nl_msg *n, size_t len, int pad); - -int nlmsg_append (struct nl_msg *n, void *data, size_t len, int pad); - -void nlmsg_free (struct nl_msg *msg); - -static inline int -nlmsg_size (int payload) -{ - nm_assert (payload >= 0 && payload < G_MAXINT - NLMSG_HDRLEN - 4); - return NLMSG_HDRLEN + payload; -} - -static inline int -nlmsg_total_size (int payload) -{ - return NLMSG_ALIGN (nlmsg_size (payload)); -} - -static inline int -nlmsg_ok (const struct nlmsghdr *nlh, int remaining) -{ - return (remaining >= (int)sizeof(struct nlmsghdr) && - nlh->nlmsg_len >= sizeof(struct nlmsghdr) && - nlh->nlmsg_len <= remaining); -} - -static inline struct nlmsghdr * -nlmsg_next (struct nlmsghdr *nlh, int *remaining) -{ - int totlen = NLMSG_ALIGN(nlh->nlmsg_len); - - *remaining -= totlen; - - return (struct nlmsghdr *) ((unsigned char *) nlh + totlen); -} - -int nlmsg_get_proto (struct nl_msg *msg); -void nlmsg_set_proto (struct nl_msg *msg, int protocol); - -void nlmsg_set_src (struct nl_msg *msg, struct sockaddr_nl *addr); - -struct ucred *nlmsg_get_creds (struct nl_msg *msg); -void nlmsg_set_creds (struct nl_msg *msg, struct ucred *creds); - -static inline void -_nm_auto_nl_msg_cleanup (struct nl_msg **ptr) -{ - nlmsg_free (*ptr); -} -#define nm_auto_nlmsg nm_auto(_nm_auto_nl_msg_cleanup) - -static inline void * -nlmsg_data (const struct nlmsghdr *nlh) -{ - return (unsigned char *) nlh + NLMSG_HDRLEN; -} - -static inline void * -nlmsg_tail (const struct nlmsghdr *nlh) -{ - return (unsigned char *) nlh + NLMSG_ALIGN(nlh->nlmsg_len); -} - -struct nlmsghdr *nlmsg_hdr (struct nl_msg *n); - -static inline int -nlmsg_valid_hdr(const struct nlmsghdr *nlh, int hdrlen) -{ - if (nlh->nlmsg_len < nlmsg_size (hdrlen)) - return 0; - - return 1; -} - -static inline int -nlmsg_datalen (const struct nlmsghdr *nlh) -{ - return nlh->nlmsg_len - NLMSG_HDRLEN; -} - -static inline int -nlmsg_attrlen (const struct nlmsghdr *nlh, int hdrlen) -{ - return NM_MAX ((int) (nlmsg_datalen (nlh) - NLMSG_ALIGN (hdrlen)), 0); -} - -static inline struct nlattr * -nlmsg_attrdata (const struct nlmsghdr *nlh, int hdrlen) -{ - unsigned char *data = nlmsg_data(nlh); - return (struct nlattr *) (data + NLMSG_ALIGN(hdrlen)); -} - -static inline struct nlattr * -nlmsg_find_attr (struct nlmsghdr *nlh, int hdrlen, int attrtype) -{ - return nla_find (nlmsg_attrdata (nlh, hdrlen), - nlmsg_attrlen (nlh, hdrlen), - attrtype); -} - -int nlmsg_parse (struct nlmsghdr *nlh, int hdrlen, struct nlattr *tb[], - int maxtype, const struct nla_policy *policy); - -struct nlmsghdr *nlmsg_put (struct nl_msg *n, uint32_t pid, uint32_t seq, - int type, int payload, int flags); - -/*****************************************************************************/ - -#define NL_AUTO_PORT 0 -#define NL_AUTO_SEQ 0 - -struct nl_sock; - -struct nl_sock *nl_socket_alloc (void); - -void nl_socket_free (struct nl_sock *sk); - -int nl_socket_get_fd (const struct nl_sock *sk); - -struct sockaddr_nl *nlmsg_get_dst (struct nl_msg *msg); - -size_t nl_socket_get_msg_buf_size (struct nl_sock *sk); -int nl_socket_set_msg_buf_size (struct nl_sock *sk, size_t bufsize); - -int nl_socket_set_buffer_size (struct nl_sock *sk, int rxbuf, int txbuf); - -int nl_socket_set_passcred (struct nl_sock *sk, int state); - -int nl_socket_set_nonblocking (const struct nl_sock *sk); - -void nl_socket_disable_msg_peek (struct nl_sock *sk); - -uint32_t nl_socket_get_local_port (const struct nl_sock *sk); - -int nl_socket_add_memberships (struct nl_sock *sk, int group, ...); - -int nl_connect (struct nl_sock *sk, int protocol); - -int nl_recv (struct nl_sock *sk, struct sockaddr_nl *nla, - unsigned char **buf, struct ucred **creds); - -int nl_send (struct nl_sock *sk, struct nl_msg *msg); - -int nl_send_auto (struct nl_sock *sk, struct nl_msg *msg); - -/*****************************************************************************/ - -enum nl_cb_action { - /* Proceed with wathever would come next */ - NL_OK, - /* Skip this message */ - NL_SKIP, - /* Stop parsing altogether and discard remaining messages */ - NL_STOP, -}; - -typedef int (*nl_recvmsg_msg_cb_t) (struct nl_msg *msg, void *arg); - -typedef int (*nl_recvmsg_err_cb_t) (struct sockaddr_nl *nla, - struct nlmsgerr *nlerr, void *arg); - -struct nl_cb { - nl_recvmsg_msg_cb_t valid_cb; - void * valid_arg; - - nl_recvmsg_msg_cb_t finish_cb; - void * finish_arg; - - nl_recvmsg_msg_cb_t ack_cb; - void * ack_arg; - - nl_recvmsg_err_cb_t err_cb; - void * err_arg; -}; - -int nl_sendmsg (struct nl_sock *sk, struct nl_msg *msg, struct msghdr *hdr); - -int nl_send_iovec (struct nl_sock *sk, struct nl_msg *msg, struct iovec *iov, unsigned iovlen); - -void nl_complete_msg (struct nl_sock *sk, struct nl_msg *msg); - -int nl_recvmsgs (struct nl_sock *sk, const struct nl_cb *cb); - -int nl_wait_for_ack (struct nl_sock *sk, - const struct nl_cb *cb); - -int nl_socket_set_ext_ack (struct nl_sock *sk, gboolean enable); - -/*****************************************************************************/ - -void *genlmsg_put (struct nl_msg *msg, uint32_t port, uint32_t seq, int family, - int hdrlen, int flags, uint8_t cmd, uint8_t version); -void *genlmsg_data (const struct genlmsghdr *gnlh); -void *genlmsg_user_hdr (const struct genlmsghdr *gnlh); -struct genlmsghdr *genlmsg_hdr (struct nlmsghdr *nlh); -void *genlmsg_user_data (const struct genlmsghdr *gnlh, const int hdrlen); -struct nlattr *genlmsg_attrdata (const struct genlmsghdr *gnlh, int hdrlen); -int genlmsg_len (const struct genlmsghdr *gnlh); -int genlmsg_attrlen (const struct genlmsghdr *gnlh, int hdrlen); -int genlmsg_valid_hdr (struct nlmsghdr *nlh, int hdrlen); -int genlmsg_parse (struct nlmsghdr *nlh, int hdrlen, struct nlattr *tb[], - int maxtype, const struct nla_policy *policy); - -int genl_ctrl_resolve (struct nl_sock *sk, const char *name); - -/*****************************************************************************/ - -#endif /* __NM_NETLINK_H__ */ diff --git a/src/platform/nm-platform-utils.c b/src/platform/nm-platform-utils.c index 114bf4b3..b664e8a9 100644 --- a/src/platform/nm-platform-utils.c +++ b/src/platform/nm-platform-utils.c @@ -589,8 +589,6 @@ nmp_utils_ip_config_source_coerce_to_rtprot (NMIPConfigSource source) switch (source) { case NM_IP_CONFIG_SOURCE_KERNEL: return RTPROT_KERNEL; - case NM_IP_CONFIG_SOURCE_IP6LL: - return RTPROT_KERNEL; case NM_IP_CONFIG_SOURCE_DHCP: return RTPROT_DHCP; case NM_IP_CONFIG_SOURCE_NDISC: @@ -658,7 +656,6 @@ nmp_utils_ip_config_source_to_string (NMIPConfigSource source, char *buf, gsize case NM_IP_CONFIG_SOURCE_KERNEL: s = "kernel"; break; case NM_IP_CONFIG_SOURCE_SHARED: s = "shared"; break; case NM_IP_CONFIG_SOURCE_IP4LL: s = "ipv4ll"; break; - case NM_IP_CONFIG_SOURCE_IP6LL: s = "ipv6ll"; break; case NM_IP_CONFIG_SOURCE_PPP: s = "ppp"; break; case NM_IP_CONFIG_SOURCE_WWAN: s = "wwan"; break; case NM_IP_CONFIG_SOURCE_VPN: s = "vpn"; break; diff --git a/src/platform/nm-platform.c b/src/platform/nm-platform.c index 84d862d2..c7ed90e3 100644 --- a/src/platform/nm-platform.c +++ b/src/platform/nm-platform.c @@ -353,45 +353,6 @@ nm_platform_process_events (NMPlatform *self) klass->process_events (self); } -const NMPlatformLink * -nm_platform_process_events_ensure_link (NMPlatform *self, - int ifindex, - const char *ifname) -{ - const NMPObject *obj; - gboolean refreshed = FALSE; - - g_return_val_if_fail (NM_IS_PLATFORM (self), NULL); - - if (ifindex <= 0 && !ifname) - return NULL; - - /* we look into the cache, whether a link for given ifindex/ifname - * exits. If not, we poll the netlink socket, maybe the event - * with the link is waiting. - * - * Then we try again to find the object. - * - * If the link is already cached the first time, we avoid polling - * the netlink socket. */ -again: - obj = nmp_cache_lookup_link_full (nm_platform_get_cache (self), - ifindex, - ifname, - FALSE, /* also invisible. We don't care here whether udev is ready */ - NM_LINK_TYPE_NONE, - NULL, NULL); - if (obj) - return NMP_OBJECT_CAST_LINK (obj); - if (!refreshed) { - refreshed = TRUE; - nm_platform_process_events (self); - goto again; - } - - return NULL; -} - /*****************************************************************************/ /** @@ -636,11 +597,11 @@ nm_platform_link_get_all (NMPlatform *self, gboolean sort_by_name) * further by moving children/slaves to the end. */ g_ptr_array_sort_with_data (links, _link_get_all_presort, GINT_TO_POINTER (sort_by_name)); - unseen = g_hash_table_new (nm_direct_hash, NULL); + unseen = g_hash_table_new (g_direct_hash, g_direct_equal); for (i = 0; i < links->len; i++) { item = NMP_OBJECT_CAST_LINK (links->pdata[i]); nm_assert (item->ifindex > 0); - if (!g_hash_table_insert (unseen, GINT_TO_POINTER (item->ifindex), NULL)) + if (!nm_g_hash_table_insert (unseen, GINT_TO_POINTER (item->ifindex), NULL)) nm_assert_not_reached (); } @@ -1157,21 +1118,6 @@ nm_platform_link_supports_slaves (NMPlatform *self, int ifindex) } /** - * nm_platform_refresh_all: - * @self: platform instance - * @obj_type: The object type to request. - * - * Resync and re-request all objects from kernel of a certain @obj_type. - */ -void -nm_platform_refresh_all (NMPlatform *self, NMPObjectType obj_type) -{ - _CHECK_SELF_VOID (self, klass); - - klass->refresh_all (self, obj_type); -} - -/** * nm_platform_link_refresh: * @self: platform instance * @ifindex: Interface index @@ -1379,26 +1325,30 @@ gconstpointer nm_platform_link_get_address (NMPlatform *self, int ifindex, size_t *length) { const NMPlatformLink *pllink; + gconstpointer a = NULL; + guint8 l = 0; _CHECK_SELF (self, klass, NULL); + if (length) + *length = 0; + g_return_val_if_fail (ifindex > 0, NULL); pllink = nm_platform_link_get (self, ifindex); - - if ( !pllink - || pllink->addr.len <= 0) { - NM_SET_OUT (length, 0); - return NULL; - } - - if (pllink->addr.len > NM_UTILS_HWADDR_LEN_MAX) { - NM_SET_OUT (length, 0); - g_return_val_if_reached (NULL); + if (pllink && pllink->addr.len > 0) { + if (pllink->addr.len > NM_UTILS_HWADDR_LEN_MAX) { + if (length) + *length = 0; + g_return_val_if_reached (NULL); + } + a = pllink->addr.data; + l = pllink->addr.len; } - NM_SET_OUT (length, pllink->addr.len); - return pllink->addr.data; + if (length) + *length = l; + return a; } /** @@ -1894,12 +1844,6 @@ nm_platform_link_get_lnk_sit (NMPlatform *self, int ifindex, const NMPlatformLin return _link_get_lnk (self, ifindex, NM_LINK_TYPE_SIT, out_link); } -const NMPlatformLnkTun * -nm_platform_link_get_lnk_tun (NMPlatform *self, int ifindex, const NMPlatformLink **out_link) -{ - return _link_get_lnk (self, ifindex, NM_LINK_TYPE_TUN, out_link); -} - const NMPlatformLnkVlan * nm_platform_link_get_lnk_vlan (NMPlatform *self, int ifindex, const NMPlatformLink **out_link) { @@ -2046,43 +1990,33 @@ nm_platform_link_vxlan_add (NMPlatform *self, * @vnet_hdr: whether to set the IFF_VNET_HDR flag * @multi_queue: whether to set the IFF_MULTI_QUEUE flag * @out_link: on success, the link object - * @out_fd: (allow-none): if give, return the file descriptor for the - * created device. Note that when creating a non-persistent device, - * this argument is mandatory, otherwise it makes no sense - * to create such an interface. - * The caller is responsible for closing this file descriptor. * * Create a TUN or TAP interface. */ NMPlatformError nm_platform_link_tun_add (NMPlatform *self, const char *name, - const NMPlatformLnkTun *props, - const NMPlatformLink **out_link, - int *out_fd) + gboolean tap, + gint64 owner, + gint64 group, + gboolean pi, + gboolean vnet_hdr, + gboolean multi_queue, + const NMPlatformLink **out_link) { - char b[255]; NMPlatformError plerr; _CHECK_SELF (self, klass, NM_PLATFORM_ERROR_BUG); g_return_val_if_fail (name, NM_PLATFORM_ERROR_BUG); - g_return_val_if_fail (props, NM_PLATFORM_ERROR_BUG); - g_return_val_if_fail (NM_IN_SET (props->type, IFF_TUN, IFF_TAP), NM_PLATFORM_ERROR_BUG); - - /* creating a non-persistant device requires that the caller handles - * the file descriptor. */ - g_return_val_if_fail (props->persist || out_fd, NM_PLATFORM_ERROR_BUG); - NM_SET_OUT (out_fd, -1); - - plerr = _link_add_check_existing (self, name, NM_LINK_TYPE_TUN, out_link); + plerr = _link_add_check_existing (self, name, tap ? NM_LINK_TYPE_TAP : NM_LINK_TYPE_TUN, out_link); if (plerr != NM_PLATFORM_ERROR_SUCCESS) return plerr; - _LOGD ("link: adding tun '%s' %s", - name, nm_platform_lnk_tun_to_string (props, b, sizeof (b))); - if (!klass->link_tun_add (self, name, props, out_link, out_fd)) + _LOGD ("link: adding %s '%s' owner %" G_GINT64_FORMAT " group %" G_GINT64_FORMAT, + tap ? "tap" : "tun", name, owner, group); + if (!klass->tun_add (self, name, tap, owner, group, pi, vnet_hdr, multi_queue, out_link)) return NM_PLATFORM_ERROR_UNSPECIFIED; return NM_PLATFORM_ERROR_SUCCESS; } @@ -2686,100 +2620,44 @@ nm_platform_link_veth_get_properties (NMPlatform *self, int ifindex, int *out_pe return TRUE; } -/** - * nm_platform_link_tun_get_properties: - * @self: the #NMPlatform instance - * @ifindex: the ifindex to look up - * @out_properties: (out): (allow-none): return the read properties - * - * Only recent versions of kernel export tun properties via netlink. - * So, if that's the case, then we have the NMPlatformLnkTun instance - * in the platform cache ready to return. Otherwise, this function - * falls back reading sysctl to obtain the tun properties. That - * is racy, because querying sysctl means that the object might - * be already removed from cache (while NM didn't yet process the - * netlink message). - * - * Hence, to lookup the tun properties, you always need to use this - * function, and use it with care knowing that it might obtain its - * data by reading sysctl. Note that we don't want to add this workaround - * to the platform cache itself, because the cache should (mainly) - * contain data from netlink. To access the sysctl side channel, the - * user needs to do explicitly. - * - * Returns: #TRUE, if the properties could be read. */ gboolean -nm_platform_link_tun_get_properties (NMPlatform *self, - int ifindex, - NMPlatformLnkTun *out_properties) +nm_platform_link_tun_get_properties (NMPlatform *self, int ifindex, NMPlatformTunProperties *props) { - const NMPObject *plobj; - const NMPObject *pllnk; + nm_auto_close int dirfd = -1; char ifname[IFNAMSIZ]; - gint64 owner; - gint64 group; gint64 flags; - + gboolean success = TRUE; _CHECK_SELF (self, klass, FALSE); g_return_val_if_fail (ifindex > 0, FALSE); + g_return_val_if_fail (props, FALSE); - /* we consider also invisible links (those that are not yet in udev). */ - plobj = nm_platform_link_get_obj (self, ifindex, FALSE); - if (!plobj) - return FALSE; - if (NMP_OBJECT_CAST_LINK (plobj)->type != NM_LINK_TYPE_TUN) - return FALSE; - - pllnk = plobj->_link.netlink.lnk; - if (pllnk) { - nm_assert (NMP_OBJECT_GET_TYPE (pllnk) == NMP_OBJECT_TYPE_LNK_TUN); - nm_assert (NMP_OBJECT_GET_CLASS (pllnk)->lnk_link_type == NM_LINK_TYPE_TUN); + memset (props, 0, sizeof (*props)); + props->owner = -1; + props->group = -1; - /* recent kernels expose tun properties via netlink and thus we have them - * in the platform cache. */ - NM_SET_OUT (out_properties, pllnk->lnk_tun); - return TRUE; - } - - /* fallback to reading sysctl. */ - { - nm_auto_close int dirfd = -1; + dirfd = nm_platform_sysctl_open_netdir (self, ifindex, ifname); + if (dirfd < 0) + return FALSE; - dirfd = nm_platform_sysctl_open_netdir (self, ifindex, ifname); - if (dirfd < 0) - return FALSE; + props->owner = nm_platform_sysctl_get_int_checked (self, NMP_SYSCTL_PATHID_NETDIR (dirfd, ifname, "owner"), 10, -1, G_MAXINT64, -1); + if (errno) + success = FALSE; - owner = nm_platform_sysctl_get_int_checked (self, NMP_SYSCTL_PATHID_NETDIR (dirfd, ifname, "owner"), 10, -1, G_MAXUINT32, -2); - if (owner == -2) - return FALSE; + props->group = nm_platform_sysctl_get_int_checked (self, NMP_SYSCTL_PATHID_NETDIR (dirfd, ifname, "group"), 10, -1, G_MAXINT64, -1); + if (errno) + success = FALSE; - group = nm_platform_sysctl_get_int_checked (self, NMP_SYSCTL_PATHID_NETDIR (dirfd, ifname, "group"), 10, -1, G_MAXUINT32, -2); - if (group == -2) - return FALSE; - - flags = nm_platform_sysctl_get_int_checked (self, NMP_SYSCTL_PATHID_NETDIR (dirfd, ifname, "tun_flags"), 16, 0, G_MAXINT64, -1); - if (flags == -1) - return FALSE; - } + flags = nm_platform_sysctl_get_int_checked (self, NMP_SYSCTL_PATHID_NETDIR (dirfd, ifname, "tun_flags"), 16, 0, G_MAXINT64, -1); + if (flags >= 0) { + props->mode = ((flags & (IFF_TUN | IFF_TAP)) == IFF_TUN) ? "tun" : "tap"; + props->no_pi = !!(flags & IFF_NO_PI); + props->vnet_hdr = !!(flags & IFF_VNET_HDR); + props->multi_queue = !!(flags & NM_IFF_MULTI_QUEUE); + } else + success = FALSE; - if (out_properties) { - memset (out_properties, 0, sizeof (*out_properties)); - if (owner != -1) { - out_properties->owner_valid = TRUE; - out_properties->owner = owner; - } - if (group != -1) { - out_properties->group_valid = TRUE; - out_properties->group = group; - } - out_properties->type = (flags & TUN_TYPE_MASK); - out_properties->pi = !(flags & IFF_NO_PI); - out_properties->vnet_hdr = !!(flags & IFF_VNET_HDR); - out_properties->multi_queue = !!(flags & NM_IFF_MULTI_QUEUE); - out_properties->persist = !!(flags & IFF_PERSIST); - } - return TRUE; + return success; } gboolean @@ -3054,7 +2932,7 @@ nm_platform_lookup_predicate_routes_main_skip_rtprot_kernel (const NMPObject *ob * @user_data: user data for @predicate * * Returns the result of lookup in a GPtrArray. The result array contains - * references objects from the cache, its destroy function will unref them. + * references objects from the cache, it's destroy function will unref them. * * The user must unref the GPtrArray, which will also unref the NMPObject * elements. @@ -3233,68 +3111,24 @@ nm_platform_ip6_address_get (NMPlatform *self, int ifindex, struct in6_addr addr } static gboolean -_addr_array_clean_expired (int addr_family, int ifindex, GPtrArray *array, guint32 now, GHashTable **idx) +array_contains_ip6_address (const GPtrArray *addresses, const NMPlatformIP6Address *address, gint32 now) { + guint len = addresses ? addresses->len : 0; guint i; - gboolean any_addrs = FALSE; - - nm_assert_addr_family (addr_family); - nm_assert (ifindex > 0); - nm_assert (now > 0); - if (!array) - return FALSE; - - /* remove all addresses that are already expired. */ - for (i = 0; i < array->len; i++) { - const NMPlatformIPAddress *a = NMP_OBJECT_CAST_IP_ADDRESS (array->pdata[i]); - -#if NM_MORE_ASSERTS > 10 - nm_assert (a); - nm_assert (a->ifindex == ifindex); - { - const NMPObject *o = NMP_OBJECT_UP_CAST (a); - guint j; - - nm_assert (NMP_OBJECT_GET_CLASS (o)->addr_family == addr_family); - for (j = i + 1; j < array->len; j++) { - const NMPObject *o2 = array->pdata[j]; - - nm_assert (NMP_OBJECT_GET_TYPE (o) == NMP_OBJECT_GET_TYPE (o2)); - nm_assert (!nmp_object_id_equal (o, o2)); - } - } -#endif - - if ( addr_family == AF_INET6 - && NM_FLAGS_HAS (a->n_ifa_flags, IFA_F_TEMPORARY)) { - /* temporary addresses are never added explicitly by NetworkManager but - * kernel adds them via mngtempaddr flag. - * - * We drop them from this list. */ - goto clear_and_next; - } + for (i = 0; i < len; i++) { + NMPlatformIP6Address *candidate = NMP_OBJECT_CAST_IP6_ADDRESS (addresses->pdata[i]); - if (!nm_utils_lifetime_get (a->timestamp, a->lifetime, a->preferred, - now, NULL)) - goto clear_and_next; + if (IN6_ARE_ADDR_EQUAL (&candidate->address, &address->address) && candidate->plen == address->plen) { + guint32 lifetime, preferred; - if (idx) { - if (G_UNLIKELY (!*idx)) { - *idx = g_hash_table_new ((GHashFunc) nmp_object_id_hash, - (GEqualFunc) nmp_object_id_equal); - } - if (!g_hash_table_add (*idx, (gpointer) NMP_OBJECT_UP_CAST (a))) - nm_assert_not_reached (); + if (nm_utils_lifetime_get (candidate->timestamp, candidate->lifetime, candidate->preferred, + now, &lifetime, &preferred)) + return TRUE; } - any_addrs = TRUE; - continue; - -clear_and_next: - nmp_object_unref (g_steal_pointer (&array->pdata[i])); } - return any_addrs; + return FALSE; } static gboolean @@ -3345,7 +3179,7 @@ ip4_addr_subnets_build_index (const GPtrArray *addresses, nm_assert (addresses && addresses->len); - subnets = g_hash_table_new (nm_direct_hash, NULL); + subnets = g_hash_table_new (NULL, NULL); /* Build a hash table of all addresses per subnet */ for (i = 0; i < addresses->len; i++) { @@ -3478,8 +3312,39 @@ nm_platform_ip4_address_sync (NMPlatform *self, _CHECK_SELF (self, klass, FALSE); - if (!_addr_array_clean_expired (AF_INET, ifindex, known_addresses, now, &known_addresses_idx)) - known_addresses = NULL; + if (known_addresses) { + /* remove all addresses that are already expired. */ + for (i = 0; i < known_addresses->len; i++) { + const NMPObject *o; + + o = known_addresses->pdata[i]; + nm_assert (o); + + known_address = NMP_OBJECT_CAST_IP4_ADDRESS (known_addresses->pdata[i]); + + if (!nm_utils_lifetime_get (known_address->timestamp, known_address->lifetime, known_address->preferred, + now, &lifetime, &preferred)) + goto delete_and_next; + + if (G_UNLIKELY (!known_addresses_idx)) { + known_addresses_idx = g_hash_table_new ((GHashFunc) nmp_object_id_hash, + (GEqualFunc) nmp_object_id_equal); + } + if (!nm_g_hash_table_insert (known_addresses_idx, (gpointer) o, (gpointer) o)) { + /* duplicate? Keep only the first instance. */ + goto delete_and_next; + } + + continue; +delete_and_next: + nmp_object_unref (o); + known_addresses->pdata[i] = NULL; + } + + if ( !known_addresses_idx + || g_hash_table_size (known_addresses_idx) == 0) + known_addresses = NULL; + } plat_addresses = nm_platform_lookup_clone (self, nmp_lookup_init_object (&lookup, @@ -3576,9 +3441,8 @@ nm_platform_ip4_address_sync (NMPlatform *self, known_address = NMP_OBJECT_CAST_IP4_ADDRESS (o); - lifetime = nm_utils_lifetime_get (known_address->timestamp, known_address->lifetime, known_address->preferred, - now, &preferred); - if (!lifetime) + if (!nm_utils_lifetime_get (known_address->timestamp, known_address->lifetime, known_address->preferred, + now, &lifetime, &preferred)) goto delete_and_next2; if (!nm_platform_ip4_address_add (self, ifindex, known_address->address, known_address->plen, @@ -3600,15 +3464,9 @@ delete_and_next2: * nm_platform_ip6_address_sync: * @self: platform instance * @ifindex: Interface index - * @known_addresses: List of addresses. The list will be modified and only - * addresses that were successfully added will be kept in the list. - * That means, expired addresses and addresses that could not be added - * will be dropped. - * Hence, the input argument @known_addresses is also an output argument - * telling which addresses were succesfully added. - * Addresses are removed by unrefing the instance via nmp_object_unref() - * and leaving a NULL tombstone. - * @full_sync: Also remove link-local and temporary addresses. + * @known_addresses: List of IPv6 addresses, as NMPObject. The list + * is not modified. + * @keep_link_local: Don't remove link-local address * * A convenience function to synchronize addresses for a specific interface * with the least possible disturbance. It simply removes addresses that are @@ -3619,117 +3477,32 @@ delete_and_next2: gboolean nm_platform_ip6_address_sync (NMPlatform *self, int ifindex, - GPtrArray *known_addresses, - gboolean full_sync) + const GPtrArray *known_addresses, + gboolean keep_link_local) { gs_unref_ptrarray GPtrArray *plat_addresses = NULL; + NMPlatformIP6Address *address; gint32 now = nm_utils_get_monotonic_timestamp_s (); - guint i_plat, i_know; - gs_unref_hashtable GHashTable *known_addresses_idx = NULL; + guint i; NMPLookup lookup; guint32 ifa_flags; - if (!_addr_array_clean_expired (AF_INET6, ifindex, known_addresses, now, &known_addresses_idx)) - known_addresses = NULL; - - /* @plat_addresses is in decreasing priority order (highest priority addresses first), contrary to - * @known_addresses which is in increasing priority order (lowest priority addresses first). */ + /* Delete unknown addresses */ plat_addresses = nm_platform_lookup_clone (self, nmp_lookup_init_object (&lookup, NMP_OBJECT_TYPE_IP6_ADDRESS, ifindex), NULL, NULL); - if (plat_addresses) { - guint known_addresses_len; - - known_addresses_len = known_addresses ? known_addresses->len : 0; - - /* First, compare every address whether it is still a "known address", that is, whether - * to keep it or to delete it. - * - * If we don't find a matching valid address in @known_addresses, we will delete - * plat_addr. - * - * Certain addresses, like temporary addresses, are ignored by this function - * if not run with full_sync. These addresses are usually not managed by NetworkManager - * directly, or at least, they are not managed via nm_platform_ip6_address_sync(). - * Only in full_sync mode, we really want to get rid of them (usually, when we take - * the interface down). - * - * Note that we mark handled addresses by setting it to %NULL in @plat_addresses array. */ - for (i_plat = 0; i_plat < plat_addresses->len; i_plat++) { - const NMPObject *plat_obj = plat_addresses->pdata[i_plat]; - const NMPObject *know_obj; - const NMPlatformIP6Address *plat_addr = NMP_OBJECT_CAST_IP6_ADDRESS (plat_obj); - - if (NM_FLAGS_HAS (plat_addr->n_ifa_flags, IFA_F_TEMPORARY)) { - if (!full_sync) { - /* just mark as handled, without actually deleting the address. */ - goto clear_and_next; - } - } else if (known_addresses_idx) { - know_obj = g_hash_table_lookup (known_addresses_idx, plat_obj); - if ( know_obj - && plat_addr->plen == NMP_OBJECT_CAST_IP6_ADDRESS (know_obj)->plen) { - /* technically, plen is not part of the ID for IPv6 addresses and thus - * @plat_addr is essentially the same address as @know_addr (regrading - * its identity, not its other attributes). - * However, we cannot modify an existing addresses' plen without - * removing and readding it. Thus, only keep plat_addr, if the plen - * matches. - * - * keep this one, and continue */ - continue; - } - } - - nm_platform_ip6_address_delete (self, ifindex, plat_addr->address, plat_addr->plen); -clear_and_next: - nmp_object_unref (g_steal_pointer (&plat_addresses->pdata[i_plat])); - } + for (i = 0; i < plat_addresses->len; i++) { + address = NMP_OBJECT_CAST_IP6_ADDRESS (plat_addresses->pdata[i]); - /* Next, we must preserve the priority of the routes. That is, source address - * selection will choose addresses in the order as they are reported by kernel. - * Note that the order in @plat_addresses of the remaining matches is highest - * priority first. - * We need to compare this to the order in @known_addresses (which has lowest - * priority first). - * - * If we find a first discrepancy, we need to delete all remaining addresses - * from that point on, because below we must re-add all the addresses in the - * right order to get their priority right. */ - i_plat = plat_addresses->len; - i_know = 0; - while (i_plat > 0) { - const NMPlatformIP6Address *plat_addr = NMP_OBJECT_CAST_IP6_ADDRESS (plat_addresses->pdata[--i_plat]); - - if (!plat_addr) + /* Leave link local address management to the kernel */ + if (keep_link_local && IN6_IS_ADDR_LINKLOCAL (&address->address)) continue; - for (; i_know < known_addresses_len; i_know++) { - const NMPlatformIP6Address *know_addr = NMP_OBJECT_CAST_IP6_ADDRESS (known_addresses->pdata[i_know]); - - if (!know_addr) - continue; - - if (IN6_ARE_ADDR_EQUAL (&plat_addr->address, &know_addr->address)) { - /* we have a match. Mark address as handled. */ - i_know++; - goto next_plat; - } - - /* all remainging addresses need to be removed as well, so that we can - * re-add them in the correct order. Signal that, by setting @i_know - * so that the next @i_plat iteration, we won't enter the loop and - * delete the address right away */ - i_know = known_addresses_len; - break; - } - - nm_platform_ip6_address_delete (self, ifindex, plat_addr->address, plat_addr->plen); -next_plat: - ; + if (!array_contains_ip6_address (known_addresses, address, now)) + nm_platform_ip6_address_delete (self, ifindex, address->address, address->plen); } } @@ -3740,18 +3513,19 @@ next_plat: ? IFA_F_NOPREFIXROUTE : 0; - /* Add missing addresses. New addresses are added by kernel with top - * priority. - */ - for (i_know = 0; i_know < known_addresses->len; i_know++) { - const NMPlatformIP6Address *known_address = NMP_OBJECT_CAST_IP6_ADDRESS (known_addresses->pdata[i_know]); + /* Add missing addresses */ + for (i = 0; i < known_addresses->len; i++) { + const NMPlatformIP6Address *known_address = NMP_OBJECT_CAST_IP6_ADDRESS (known_addresses->pdata[i]); guint32 lifetime, preferred; - if (!known_address) + if (NM_FLAGS_HAS (known_address->n_ifa_flags, IFA_F_TEMPORARY)) { + /* Kernel manages these */ continue; + } - lifetime = nm_utils_lifetime_get (known_address->timestamp, known_address->lifetime, known_address->preferred, - now, &preferred); + if (!nm_utils_lifetime_get (known_address->timestamp, known_address->lifetime, known_address->preferred, + now, &lifetime, &preferred)) + continue; if (!nm_platform_ip6_address_add (self, ifindex, known_address->address, known_address->plen, known_address->peer_address, @@ -3779,7 +3553,7 @@ nm_platform_ip_address_flush (NMPlatform *self, if (NM_IN_SET (addr_family, AF_UNSPEC, AF_INET)) success &= nm_platform_ip4_address_sync (self, ifindex, NULL); if (NM_IN_SET (addr_family, AF_UNSPEC, AF_INET6)) - success &= nm_platform_ip6_address_sync (self, ifindex, NULL, TRUE); + success &= nm_platform_ip6_address_sync (self, ifindex, NULL, FALSE); return success; } @@ -3918,8 +3692,7 @@ nm_platform_ip_route_sync (NMPlatform *self, for (i_type = 0; routes && i_type < 2; i_type++) { for (i = 0; i < routes->len; i++) { - NMPlatformError plerr, plerr2; - gboolean gateway_route_added = FALSE; + NMPlatformError plerr; conf_o = routes->pdata[i]; @@ -3939,7 +3712,7 @@ nm_platform_ip_route_sync (NMPlatform *self, routes_idx = g_hash_table_new ((GHashFunc) nmp_object_id_hash, (GEqualFunc) nmp_object_id_equal); } - if (!g_hash_table_insert (routes_idx, (gpointer) conf_o, (gpointer) conf_o)) { + if (!nm_g_hash_table_insert (routes_idx, (gpointer) conf_o, (gpointer) conf_o)) { _LOGD ("route-sync: skip adding duplicate route %s", nmp_object_to_string (conf_o, NMP_OBJECT_TO_STRING_PUBLIC, sbuf1, sizeof (sbuf1))); continue; @@ -3965,7 +3738,6 @@ nm_platform_ip_route_sync (NMPlatform *self, } } -sync_route_add: plerr = nm_platform_ip_route_add (self, NMP_NLM_FLAG_APPEND | NMP_NLM_FLAG_SUPPRESS_NETLINK_FAILURE, @@ -3990,11 +3762,6 @@ sync_route_add: nmp_object_to_string (plat_entry->obj, NMP_OBJECT_TO_STRING_PUBLIC, sbuf2, sizeof (sbuf2))); } } - } else if (NMP_OBJECT_CAST_IP_ROUTE (conf_o)->rt_source < NM_IP_CONFIG_SOURCE_USER) { - _LOGD ("route-sync: ignore failure to add IPv%c route: %s: %s", - vt->is_ip4 ? '4' : '6', - nmp_object_to_string (conf_o, NMP_OBJECT_TO_STRING_PUBLIC, sbuf1, sizeof (sbuf1)), - nm_platform_error_to_string (plerr, sbuf_err, sizeof (sbuf_err))); } else if ( -((int) plerr) == EINVAL && out_temporary_not_available && _err_inval_due_to_ipv6_tentative_pref_src (self, conf_o)) { @@ -4004,66 +3771,25 @@ sync_route_add: if (!*out_temporary_not_available) *out_temporary_not_available = g_ptr_array_new_full (0, (GDestroyNotify) nmp_object_unref); g_ptr_array_add (*out_temporary_not_available, (gpointer) nmp_object_ref (conf_o)); - } else if ( !gateway_route_added - && ( ( -((int) plerr) == ENETUNREACH - && vt->is_ip4 - && !!NMP_OBJECT_CAST_IP4_ROUTE (conf_o)->gateway) - || ( -((int) plerr) == EHOSTUNREACH - && !vt->is_ip4 - && !IN6_IS_ADDR_UNSPECIFIED (&NMP_OBJECT_CAST_IP6_ROUTE (conf_o)->gateway)))) { - NMPObject oo; - - if (vt->is_ip4) { - const NMPlatformIP4Route *r = NMP_OBJECT_CAST_IP4_ROUTE (conf_o); - - nmp_object_stackinit (&oo, - NMP_OBJECT_TYPE_IP4_ROUTE, - &((NMPlatformIP4Route) { - .network = r->gateway, - .plen = 32, - .metric = r->metric, - .rt_source = r->rt_source, - .table_coerced = r->table_coerced, - })); - } else { - const NMPlatformIP6Route *r = NMP_OBJECT_CAST_IP6_ROUTE (conf_o); - - nmp_object_stackinit (&oo, - NMP_OBJECT_TYPE_IP6_ROUTE, - &((NMPlatformIP6Route) { - .network = r->gateway, - .plen = 128, - .metric = r->metric, - .rt_source = r->rt_source, - .table_coerced = r->table_coerced, - })); - } - - _LOGD ("route-sync: failure to add IPv%c route: %s: %s; try adding direct route to gateway %s", + } else if (NMP_OBJECT_CAST_IP_ROUTE (conf_o)->rt_source < NM_IP_CONFIG_SOURCE_USER) { + _LOGD ("route-sync: ignore failure to add IPv%c route: %s: %s", vt->is_ip4 ? '4' : '6', nmp_object_to_string (conf_o, NMP_OBJECT_TO_STRING_PUBLIC, sbuf1, sizeof (sbuf1)), - nm_platform_error_to_string (plerr, sbuf_err, sizeof (sbuf_err)), - nmp_object_to_string (&oo, NMP_OBJECT_TO_STRING_PUBLIC, sbuf2, sizeof (sbuf2))); - - plerr2 = nm_platform_ip_route_add (self, - NMP_NLM_FLAG_APPEND - | NMP_NLM_FLAG_SUPPRESS_NETLINK_FAILURE, - &oo); - - if (plerr2 != NM_PLATFORM_ERROR_SUCCESS) { - _LOGD ("route-sync: failure to add gateway IPv%c route: %s: %s", - vt->is_ip4 ? '4' : '6', - nmp_object_to_string (conf_o, NMP_OBJECT_TO_STRING_PUBLIC, sbuf1, sizeof (sbuf1)), - nm_platform_error_to_string (plerr, sbuf_err, sizeof (sbuf_err))); - } - - gateway_route_added = TRUE; - goto sync_route_add; + nm_platform_error_to_string (plerr, sbuf_err, sizeof (sbuf_err))); } else { - _LOGW ("route-sync: failure to add IPv%c route: %s: %s", + const char *reason = ""; + + if ( -((int) plerr) == ENETUNREACH + && ( vt->is_ip4 + ? !!NMP_OBJECT_CAST_IP4_ROUTE (conf_o)->gateway + : !IN6_IS_ADDR_UNSPECIFIED (&NMP_OBJECT_CAST_IP6_ROUTE (conf_o)->gateway))) + reason = "; is the gateway directly reachable?"; + + _LOGW ("route-sync: failure to add IPv%c route: %s: %s%s", vt->is_ip4 ? '4' : '6', nmp_object_to_string (conf_o, NMP_OBJECT_TO_STRING_PUBLIC, sbuf1, sizeof (sbuf1)), - nm_platform_error_to_string (plerr, sbuf_err, sizeof (sbuf_err))); + nm_platform_error_to_string (plerr, sbuf_err, sizeof (sbuf_err)), + reason); success = FALSE; } } @@ -4987,7 +4713,6 @@ nm_platform_lnk_ip6tnl_to_string (const NMPlatformLnkIp6Tnl *lnk, char *buf, gsi "%s" /* encap limit */ "%s" /* flow label */ "%s" /* proto */ - " flags 0x%x" "", nm_sprintf_buf (str_remote, " remote %s", nm_utils_inet6_ntop (&lnk->remote, str_remote1)), nm_sprintf_buf (str_local, " local %s", nm_utils_inet6_ntop (&lnk->local, str_local1)), @@ -4996,8 +4721,7 @@ nm_platform_lnk_ip6tnl_to_string (const NMPlatformLnkIp6Tnl *lnk, char *buf, gsi lnk->tclass == 1 ? " tclass inherit" : nm_sprintf_buf (str_tclass, " tclass 0x%x", lnk->tclass), nm_sprintf_buf (str_encap, " encap-limit %u", lnk->encap_limit), nm_sprintf_buf (str_flow, " flow-label 0x05%x", lnk->flow_label), - nm_sprintf_buf (str_proto, " proto %u", lnk->proto), - (guint) lnk->flags); + nm_sprintf_buf (str_proto, " proto %u", lnk->proto)); return buf; } @@ -5118,43 +4842,6 @@ nm_platform_lnk_sit_to_string (const NMPlatformLnkSit *lnk, char *buf, gsize len } const char * -nm_platform_lnk_tun_to_string (const NMPlatformLnkTun *lnk, char *buf, gsize len) -{ - char str_owner[50]; - char str_group[50]; - char str_type[50]; - const char *type; - - if (!nm_utils_to_string_buffer_init_null (lnk, &buf, &len)) - return buf; - - if (lnk->type == IFF_TUN) - type = "tun"; - else if (lnk->type == IFF_TAP) - type = "tap"; - else - type = nm_sprintf_buf (str_type, "tun type %u", (guint) lnk->type); - - g_snprintf (buf, len, - "%s" /* type */ - "%s" /* pi */ - "%s" /* vnet_hdr */ - "%s" /* multi_queue */ - "%s" /* persist */ - "%s" /* owner */ - "%s" /* group */ - "", - type, - lnk->pi ? " pi" : "", - lnk->vnet_hdr ? " vnet_hdr" : "", - lnk->multi_queue ? " multi_queue" : "", - lnk->persist ? " persist" : "", - lnk->owner_valid ? nm_sprintf_buf (str_owner, " owner %u", (guint) lnk->owner) : "", - lnk->group_valid ? nm_sprintf_buf (str_group, " group %u", (guint) lnk->group) : ""); - return buf; -} - -const char * nm_platform_lnk_vlan_to_string (const NMPlatformLnkVlan *lnk, char *buf, gsize len) { char *b; @@ -5356,10 +5043,10 @@ NM_UTILS_FLAGS2STR_DEFINE (nm_platform_addr_flags2str, unsigned, NM_UTILS_FLAGS2STR (IFA_F_OPTIMISTIC, "optimistic"), NM_UTILS_FLAGS2STR (IFA_F_HOMEADDRESS, "homeaddress"), NM_UTILS_FLAGS2STR (IFA_F_DEPRECATED, "deprecated"), + NM_UTILS_FLAGS2STR (IFA_F_TENTATIVE, "tentative"), NM_UTILS_FLAGS2STR (IFA_F_PERMANENT, "permanent"), NM_UTILS_FLAGS2STR (IFA_F_MANAGETEMPADDR, "mngtmpaddr"), NM_UTILS_FLAGS2STR (IFA_F_NOPREFIXROUTE, "noprefixroute"), - NM_UTILS_FLAGS2STR (IFA_F_TENTATIVE, "tentative"), ); NM_UTILS_ENUM2STR_DEFINE (nm_platform_route_scope2str, int, @@ -5850,8 +5537,7 @@ nm_platform_lnk_ip6tnl_hash_update (const NMPlatformLnkIp6Tnl *obj, NMHashState obj->tclass, obj->encap_limit, obj->proto, - obj->flow_label, - obj->flags); + obj->flow_label); } int @@ -5866,7 +5552,6 @@ nm_platform_lnk_ip6tnl_cmp (const NMPlatformLnkIp6Tnl *a, const NMPlatformLnkIp6 NM_CMP_FIELD (a, b, encap_limit); NM_CMP_FIELD (a, b, flow_label); NM_CMP_FIELD (a, b, proto); - NM_CMP_FIELD (a, b, flags); return 0; } @@ -5985,38 +5670,6 @@ nm_platform_lnk_sit_cmp (const NMPlatformLnkSit *a, const NMPlatformLnkSit *b) } void -nm_platform_lnk_tun_hash_update (const NMPlatformLnkTun *obj, NMHashState *h) -{ - nm_hash_update_vals (h, - obj->type, - obj->owner, - obj->group, - NM_HASH_COMBINE_BOOLS (guint8, - obj->owner_valid, - obj->group_valid, - obj->pi, - obj->vnet_hdr, - obj->multi_queue, - obj->persist)); -} - -int -nm_platform_lnk_tun_cmp (const NMPlatformLnkTun *a, const NMPlatformLnkTun *b) -{ - NM_CMP_SELF (a, b); - NM_CMP_FIELD (a, b, type); - NM_CMP_FIELD (a, b, owner); - NM_CMP_FIELD (a, b, group); - NM_CMP_FIELD_BOOL (a, b, owner_valid); - NM_CMP_FIELD_BOOL (a, b, group_valid); - NM_CMP_FIELD_BOOL (a, b, pi); - NM_CMP_FIELD_BOOL (a, b, vnet_hdr); - NM_CMP_FIELD_BOOL (a, b, multi_queue); - NM_CMP_FIELD_BOOL (a, b, persist); - return 0; -} - -void nm_platform_lnk_vlan_hash_update (const NMPlatformLnkVlan *obj, NMHashState *h) { nm_hash_update_vals (h, @@ -6607,13 +6260,14 @@ nm_platform_cache_update_emit_signal (NMPlatform *self, const NMPObject *o; const NMPClass *klass; - nm_assert (NM_IN_SET ((NMPlatformSignalChangeType) cache_op, NM_PLATFORM_SIGNAL_NONE, - NM_PLATFORM_SIGNAL_ADDED, - NM_PLATFORM_SIGNAL_CHANGED, - NM_PLATFORM_SIGNAL_REMOVED)); + nm_assert (NM_IN_SET ((NMPlatformSignalChangeType) cache_op, (NMPlatformSignalChangeType) NMP_CACHE_OPS_UNCHANGED, NM_PLATFORM_SIGNAL_ADDED, NM_PLATFORM_SIGNAL_CHANGED, NM_PLATFORM_SIGNAL_REMOVED)); ASSERT_nmp_cache_ops (nm_platform_get_cache (self), cache_op, obj_old, obj_new); + nm_assert (NM_IN_SET (nm_platform_netns_get (self), + NULL, + nmp_netns_get_current ())); + NMTST_ASSERT_PLATFORM_NETNS_CURRENT (self); switch (cache_op) { diff --git a/src/platform/nm-platform.h b/src/platform/nm-platform.h index e6cef63b..f6bf02bf 100644 --- a/src/platform/nm-platform.h +++ b/src/platform/nm-platform.h @@ -25,7 +25,6 @@ #include <linux/if.h> #include <linux/if_addr.h> #include <linux/if_link.h> -#include <linux/ip6_tunnel.h> #include "nm-dbus-interface.h" #include "nm-core-types-internal.h" @@ -33,7 +32,6 @@ #include "nm-core-utils.h" #include "nm-setting-vlan.h" #include "nm-setting-wired.h" -#include "nm-setting-ip-tunnel.h" #define NM_TYPE_PLATFORM (nm_platform_get_type ()) #define NM_PLATFORM(obj) (G_TYPE_CHECK_INSTANCE_CAST ((obj), NM_TYPE_PLATFORM, NMPlatform)) @@ -171,34 +169,6 @@ typedef enum { /*< skip >*/ NM_PLATFORM_ERROR_CANT_SET_MTU, } NMPlatformError; -typedef enum { - - /* match-flags are strictly inclusive. That means, - * by default nothing is matched, but if you enable a particular - * flag, a candidate that matches passes the check. - * - * In other words: adding more flags can only extend the result - * set of matching objects. - * - * Also, the flags form partitions. Like, an address can be either of - * ADDRTYPE_NORMAL or ADDRTYPE_LINKLOCAL, but never both. Same for - * the ADDRSTATE match types. - */ - NM_PLATFORM_MATCH_WITH_NONE = 0, - - NM_PLATFORM_MATCH_WITH_ADDRTYPE_NORMAL = (1LL << 0), - NM_PLATFORM_MATCH_WITH_ADDRTYPE_LINKLOCAL = (1LL << 1), - NM_PLATFORM_MATCH_WITH_ADDRTYPE__ANY = NM_PLATFORM_MATCH_WITH_ADDRTYPE_NORMAL - | NM_PLATFORM_MATCH_WITH_ADDRTYPE_LINKLOCAL, - - NM_PLATFORM_MATCH_WITH_ADDRSTATE_NORMAL = (1LL << 2), - NM_PLATFORM_MATCH_WITH_ADDRSTATE_TENTATIVE = (1LL << 3), - NM_PLATFORM_MATCH_WITH_ADDRSTATE_DADFAILED = (1LL << 4), - NM_PLATFORM_MATCH_WITH_ADDRSTATE__ANY = NM_PLATFORM_MATCH_WITH_ADDRSTATE_NORMAL - | NM_PLATFORM_MATCH_WITH_ADDRSTATE_TENTATIVE - | NM_PLATFORM_MATCH_WITH_ADDRSTATE_DADFAILED, -} NMPlatformMatchFlags; - #define NM_PLATFORM_LINK_OTHER_NETNS (-1) #define __NMPlatformObject_COMMON \ @@ -284,8 +254,6 @@ struct _NMPlatformObject { __NMPlatformObject_COMMON; }; -#define NM_PLATFORM_IP_ADDRESS_CAST(address) \ - NM_CONSTCAST (NMPlatformIPAddress, (address), NMPlatformIPXAddress, NMPlatformIP4Address, NMPlatformIP6Address) #define __NMPlatformIPAddress_COMMON \ __NMPlatformObject_COMMON; \ @@ -434,7 +402,7 @@ typedef union { * do not exist from the point-of-view of platform users. * Such a route is not alive, according to nmp_object_is_alive(). * - * NOTE: currently we ignore all flags except RTM_F_CLONED + * XXX: currently we ignore all flags except RTM_F_CLONED * and RTNH_F_ONLINK for IPv4. * We also may not properly consider the flags as part of the ID * in route-cmp. */ \ @@ -636,7 +604,6 @@ typedef struct { guint8 encap_limit; guint8 proto; guint flow_label; - guint32 flags; } NMPlatformLnkIp6Tnl; typedef struct { @@ -684,21 +651,6 @@ typedef struct { } NMPlatformLnkSit; typedef struct { - guint32 owner; - guint32 group; - - guint8 type; - - bool owner_valid:1; - bool group_valid:1; - - bool pi:1; - bool vnet_hdr:1; - bool multi_queue:1; - bool persist:1; -} NMPlatformLnkTun; - -typedef struct { /* rtnl_link_vlan_get_id(), IFLA_VLAN_ID */ guint16 id; NMVlanFlags flags; @@ -725,6 +677,15 @@ typedef struct { bool l3miss:1; } NMPlatformLnkVxlan; +typedef struct { + gint64 owner; + gint64 group; + const char *mode; + bool no_pi:1; + bool vnet_hdr:1; + bool multi_queue:1; +} NMPlatformTunProperties; + typedef enum { NM_PLATFORM_LINK_DUPLEX_UNKNOWN, NM_PLATFORM_LINK_DUPLEX_HALF, @@ -753,8 +714,6 @@ typedef struct { gboolean (*sysctl_set) (NMPlatform *, const char *pathid, int dirfd, const char *path, const char *value); char * (*sysctl_get) (NMPlatform *, const char *pathid, int dirfd, const char *path); - void (*refresh_all) (NMPlatform *self, NMPObjectType obj_type); - gboolean (*link_add) (NMPlatform *, const char *name, NMLinkType type, @@ -850,15 +809,12 @@ typedef struct { const NMPlatformLnkSit *props, const NMPlatformLink **out_link); - gboolean (*link_tun_add) (NMPlatform *platform, - const char *name, - const NMPlatformLnkTun *props, - const NMPlatformLink **out_link, - int *out_fd); - gboolean (*infiniband_partition_add) (NMPlatform *, int parent, int p_key, const NMPlatformLink **out_link); gboolean (*infiniband_partition_delete) (NMPlatform *, int parent, int p_key); + gboolean (*tun_add) (NMPlatform *platform, const char *name, gboolean tap, gint64 owner, gint64 group, gboolean pi, + gboolean vnet_hdr, gboolean multi_queue, const NMPlatformLink **out_link); + gboolean (*wifi_get_capabilities) (NMPlatform *, int ifindex, NMDeviceWifiCapabilities *caps); gboolean (*wifi_get_bssid) (NMPlatform *, int ifindex, guint8 *bssid); GByteArray *(*wifi_get_ssid) (NMPlatform *, int ifindex); @@ -1072,8 +1028,6 @@ gboolean nm_platform_sysctl_set_ip6_hop_limit_safe (NMPlatform *self, const char const char *nm_platform_if_indextoname (NMPlatform *self, int ifindex, char *out_ifname/* of size IFNAMSIZ */); int nm_platform_if_nametoindex (NMPlatform *self, const char *ifname); -void nm_platform_refresh_all (NMPlatform *self, NMPObjectType obj_type); - const NMPObject *nm_platform_link_get_obj (NMPlatform *self, int ifindex, gboolean visible_only); @@ -1117,21 +1071,7 @@ gboolean nm_platform_link_is_connected (NMPlatform *self, int ifindex); gboolean nm_platform_link_uses_arp (NMPlatform *self, int ifindex); guint32 nm_platform_link_get_mtu (NMPlatform *self, int ifindex); gboolean nm_platform_link_get_user_ipv6ll_enabled (NMPlatform *self, int ifindex); - gconstpointer nm_platform_link_get_address (NMPlatform *self, int ifindex, size_t *length); - -static inline GBytes * -nm_platform_link_get_address_as_bytes (NMPlatform *self, int ifindex) -{ - gconstpointer p; - gsize l; - - p = nm_platform_link_get_address (self, ifindex, &l); - return p - ? g_bytes_new (p, l) - : NULL; -} - int nm_platform_link_get_master (NMPlatform *self, int slave); gboolean nm_platform_link_can_assume (NMPlatform *self, int ifindex); @@ -1143,10 +1083,6 @@ const char *nm_platform_link_get_type_name (NMPlatform *self, int ifindex); gboolean nm_platform_link_refresh (NMPlatform *self, int ifindex); void nm_platform_process_events (NMPlatform *self); -const NMPlatformLink *nm_platform_process_events_ensure_link (NMPlatform *self, - int ifindex, - const char *ifname); - gboolean nm_platform_link_set_up (NMPlatform *self, int ifindex, gboolean *out_no_firmware); gboolean nm_platform_link_set_down (NMPlatform *self, int ifindex); gboolean nm_platform_link_set_arp (NMPlatform *self, int ifindex); @@ -1196,7 +1132,6 @@ const NMPlatformLnkMacsec *nm_platform_link_get_lnk_macsec (NMPlatform *self, in const NMPlatformLnkMacvlan *nm_platform_link_get_lnk_macvlan (NMPlatform *self, int ifindex, const NMPlatformLink **out_link); const NMPlatformLnkMacvtap *nm_platform_link_get_lnk_macvtap (NMPlatform *self, int ifindex, const NMPlatformLink **out_link); const NMPlatformLnkSit *nm_platform_link_get_lnk_sit (NMPlatform *self, int ifindex, const NMPlatformLink **out_link); -const NMPlatformLnkTun *nm_platform_link_get_lnk_tun (NMPlatform *self, int ifindex, const NMPlatformLink **out_link); const NMPlatformLnkVlan *nm_platform_link_get_lnk_vlan (NMPlatform *self, int ifindex, const NMPlatformLink **out_link); const NMPlatformLnkVxlan *nm_platform_link_get_lnk_vxlan (NMPlatform *self, int ifindex, const NMPlatformLink **out_link); @@ -1224,6 +1159,16 @@ NMPlatformError nm_platform_link_vxlan_add (NMPlatform *self, const NMPlatformLnkVxlan *props, const NMPlatformLink **out_link); +NMPlatformError nm_platform_link_tun_add (NMPlatform *self, + const char *name, + gboolean tap, + gint64 owner, + gint64 group, + gboolean pi, + gboolean vnet_hdr, + gboolean multi_queue, + const NMPlatformLink **out_link); + NMPlatformError nm_platform_link_infiniband_add (NMPlatform *self, int parent, int p_key, @@ -1234,9 +1179,7 @@ NMPlatformError nm_platform_link_infiniband_delete (NMPlatform *self, gboolean nm_platform_link_infiniband_get_properties (NMPlatform *self, int ifindex, int *parent, int *p_key, const char **mode); gboolean nm_platform_link_veth_get_properties (NMPlatform *self, int ifindex, int *out_peer_ifindex); -gboolean nm_platform_link_tun_get_properties (NMPlatform *self, - int ifindex, - NMPlatformLnkTun *out_properties); +gboolean nm_platform_link_tun_get_properties (NMPlatform *self, int ifindex, NMPlatformTunProperties *properties); gboolean nm_platform_wifi_get_capabilities (NMPlatform *self, int ifindex, NMDeviceWifiCapabilities *caps); gboolean nm_platform_wifi_get_bssid (NMPlatform *self, int ifindex, guint8 *bssid); @@ -1284,11 +1227,6 @@ NMPlatformError nm_platform_link_sit_add (NMPlatform *self, const char *name, const NMPlatformLnkSit *props, const NMPlatformLink **out_link); -NMPlatformError nm_platform_link_tun_add (NMPlatform *self, - const char *name, - const NMPlatformLnkTun *props, - const NMPlatformLink **out_link, - int *out_fd); const NMPlatformIP6Address *nm_platform_ip6_address_get (NMPlatform *self, int ifindex, struct in6_addr address); @@ -1313,8 +1251,8 @@ gboolean nm_platform_ip6_address_add (NMPlatform *self, guint32 flags); gboolean nm_platform_ip4_address_delete (NMPlatform *self, int ifindex, in_addr_t address, guint8 plen, in_addr_t peer_address); gboolean nm_platform_ip6_address_delete (NMPlatform *self, int ifindex, struct in6_addr address, guint8 plen); -gboolean nm_platform_ip4_address_sync (NMPlatform *self, int ifindex, GPtrArray *known_addresses); -gboolean nm_platform_ip6_address_sync (NMPlatform *self, int ifindex, GPtrArray *known_addresses, gboolean full_sync); +gboolean nm_platform_ip4_address_sync (NMPlatform *self, int ifindex, GPtrArray *known_addresse); +gboolean nm_platform_ip6_address_sync (NMPlatform *self, int ifindex, const GPtrArray *known_addresses, gboolean keep_link_local); gboolean nm_platform_ip_address_flush (NMPlatform *self, int addr_family, int ifindex); @@ -1372,7 +1310,6 @@ const char *nm_platform_lnk_ipip_to_string (const NMPlatformLnkIpIp *lnk, char * const char *nm_platform_lnk_macsec_to_string (const NMPlatformLnkMacsec *lnk, char *buf, gsize len); const char *nm_platform_lnk_macvlan_to_string (const NMPlatformLnkMacvlan *lnk, char *buf, gsize len); const char *nm_platform_lnk_sit_to_string (const NMPlatformLnkSit *lnk, char *buf, gsize len); -const char *nm_platform_lnk_tun_to_string (const NMPlatformLnkTun *lnk, char *buf, gsize len); const char *nm_platform_lnk_vlan_to_string (const NMPlatformLnkVlan *lnk, char *buf, gsize len); const char *nm_platform_lnk_vxlan_to_string (const NMPlatformLnkVxlan *lnk, char *buf, gsize len); const char *nm_platform_ip4_address_to_string (const NMPlatformIP4Address *address, char *buf, gsize len); @@ -1396,7 +1333,6 @@ int nm_platform_lnk_ipip_cmp (const NMPlatformLnkIpIp *a, const NMPlatformLnkIpI int nm_platform_lnk_macsec_cmp (const NMPlatformLnkMacsec *a, const NMPlatformLnkMacsec *b); int nm_platform_lnk_macvlan_cmp (const NMPlatformLnkMacvlan *a, const NMPlatformLnkMacvlan *b); int nm_platform_lnk_sit_cmp (const NMPlatformLnkSit *a, const NMPlatformLnkSit *b); -int nm_platform_lnk_tun_cmp (const NMPlatformLnkTun *a, const NMPlatformLnkTun *b); int nm_platform_lnk_vlan_cmp (const NMPlatformLnkVlan *a, const NMPlatformLnkVlan *b); int nm_platform_lnk_vxlan_cmp (const NMPlatformLnkVxlan *a, const NMPlatformLnkVxlan *b); int nm_platform_ip4_address_cmp (const NMPlatformIP4Address *a, const NMPlatformIP4Address *b); @@ -1432,7 +1368,6 @@ void nm_platform_lnk_ipip_hash_update (const NMPlatformLnkIpIp *obj, NMHashState void nm_platform_lnk_macsec_hash_update (const NMPlatformLnkMacsec *obj, NMHashState *h); void nm_platform_lnk_macvlan_hash_update (const NMPlatformLnkMacvlan *obj, NMHashState *h); void nm_platform_lnk_sit_hash_update (const NMPlatformLnkSit *obj, NMHashState *h); -void nm_platform_lnk_tun_hash_update (const NMPlatformLnkTun *obj, NMHashState *h); void nm_platform_lnk_vlan_hash_update (const NMPlatformLnkVlan *obj, NMHashState *h); void nm_platform_lnk_vxlan_hash_update (const NMPlatformLnkVxlan *obj, NMHashState *h); diff --git a/src/platform/nmp-netns.c b/src/platform/nmp-netns.c index f1092fe9..d8561aef 100644 --- a/src/platform/nmp-netns.c +++ b/src/platform/nmp-netns.c @@ -200,8 +200,8 @@ _stack_current_ns_types (NMPNetns *netns, int ns_types) } for (i = 0; i < G_N_ELEMENTS (ns_types_check); i++) { - if ( NM_FLAGS_ANY (ns_types, ns_types_check[i]) - && NM_FLAGS_ANY (info->ns_types, ns_types_check[i])) { + if ( NM_FLAGS_HAS (ns_types, ns_types_check[i]) + && NM_FLAGS_HAS (info->ns_types, ns_types_check[i])) { res = NM_FLAGS_SET (res, ns_types_check[i]); ns_types = NM_FLAGS_UNSET (ns_types, ns_types_check[i]); } diff --git a/src/platform/nmp-object.c b/src/platform/nmp-object.c index 29bb999b..1a9b9325 100644 --- a/src/platform/nmp-object.c +++ b/src/platform/nmp-object.c @@ -325,7 +325,7 @@ _vlan_xgress_qos_mappings_cmp (guint n_map, static void _vlan_xgress_qos_mappings_cpy (guint *dst_n_map, - NMVlanQosMapping **dst_map, + const NMVlanQosMapping **dst_map, guint src_n_map, const NMVlanQosMapping *src_map) { @@ -388,7 +388,7 @@ _nmp_object_fixup_link_udev_fields (NMPObject **obj_new, NMPObject *obj_orig, gb /* The link contains internal fields that are combined by * properties from netlink and udev. Update those properties */ - /* When a link is not in netlink, its udev fields don't matter. */ + /* When a link is not in netlink, it's udev fields don't matter. */ if (obj->_link.netlink.is_in_netlink) { driver = _link_get_driver (obj->_link.udev.device, obj->link.kind, @@ -532,7 +532,7 @@ _nmp_object_stackinit_from_type (NMPObject *obj, NMPObjectType obj_type) } const NMPObject * -nmp_object_stackinit (NMPObject *obj, NMPObjectType obj_type, gconstpointer plobj) +nmp_object_stackinit (NMPObject *obj, NMPObjectType obj_type, const NMPlatformObject *plobj) { const NMPClass *klass = nmp_class_from_type (obj_type); @@ -865,6 +865,12 @@ _vt_cmd_obj_cmp_lnk_vlan (const NMPObject *obj1, const NMPObject *obj2) return c; } +gboolean +nmp_object_equal (const NMPObject *obj1, const NMPObject *obj2) +{ + return nmp_object_cmp (obj1, obj2) == 0; +} + /* @src is a const object, which is not entirely correct for link types, where * we increase the ref count for src->_link.udev.device. * Hence, nmp_object_copy() can violate the const promise of @src. @@ -916,11 +922,11 @@ _vt_cmd_obj_copy_lnk_vlan (NMPObject *dst, const NMPObject *src) { dst->lnk_vlan = src->lnk_vlan; _vlan_xgress_qos_mappings_cpy (&dst->_lnk_vlan.n_ingress_qos_map, - NM_UNCONST_PPTR (NMVlanQosMapping, &dst->_lnk_vlan.ingress_qos_map), + &dst->_lnk_vlan.ingress_qos_map, src->_lnk_vlan.n_ingress_qos_map, src->_lnk_vlan.ingress_qos_map); _vlan_xgress_qos_mappings_cpy (&dst->_lnk_vlan.n_egress_qos_map, - NM_UNCONST_PPTR (NMVlanQosMapping, &dst->_lnk_vlan.egress_qos_map), + &dst->_lnk_vlan.egress_qos_map, src->_lnk_vlan.n_egress_qos_map, src->_lnk_vlan.egress_qos_map); } @@ -1082,7 +1088,7 @@ nmp_object_id_hash (const NMPObject *obj) NMHashState h; if (!obj) - return nm_hash_static (914932607u); + return 0; nm_hash_init (&h, 914932607u); nmp_object_id_hash_update (obj, &h); @@ -1526,6 +1532,8 @@ const NMPLookup * nmp_lookup_init_obj_type (NMPLookup *lookup, NMPObjectType obj_type) { + NMPObject *o; + nm_assert (lookup); switch (obj_type) { @@ -1536,7 +1544,7 @@ nmp_lookup_init_obj_type (NMPLookup *lookup, case NMP_OBJECT_TYPE_IP6_ROUTE: case NMP_OBJECT_TYPE_QDISC: case NMP_OBJECT_TYPE_TFILTER: - _nmp_object_stackinit_from_type (&lookup->selector_obj, obj_type); + o = _nmp_object_stackinit_from_type (&lookup->selector_obj, obj_type); lookup->cache_id_type = NMP_CACHE_ID_TYPE_OBJECT_TYPE; return _L (lookup); default: @@ -1768,54 +1776,6 @@ nmp_cache_lookup_link_full (const NMPCache *cache, /*****************************************************************************/ -static NMDedupMultiIdxMode -_obj_get_add_mode (const NMPObject *obj) -{ - /* new objects are usually appended to the list. Except for - * addresses, which are prepended during `ip address add`. - * - * Actually, for routes it is more complicated, because depending on - * `ip route append`, `ip route replace`, `ip route prepend`, the object - * will be added at the tail, at the front, or even replace an element - * in the list. However, that is handled separately by nmp_cache_update_netlink_route() - * and of no concern here. */ - if (NM_IN_SET (NMP_OBJECT_GET_TYPE (obj), - NMP_OBJECT_TYPE_IP4_ADDRESS, - NMP_OBJECT_TYPE_IP6_ADDRESS)) - return NM_DEDUP_MULTI_IDX_MODE_PREPEND; - return NM_DEDUP_MULTI_IDX_MODE_APPEND; -} - -static void -_idxcache_update_order_for_dump (NMPCache *cache, - const NMDedupMultiEntry *entry) -{ - const NMPClass *klass; - const guint8 *i_idx_type; - const NMDedupMultiEntry *entry2; - - nm_dedup_multi_entry_reorder (entry, NULL, TRUE); - - klass = NMP_OBJECT_GET_CLASS (entry->obj); - for (i_idx_type = klass->supported_cache_ids; *i_idx_type; i_idx_type++) { - NMPCacheIdType id_type = *i_idx_type; - - if (id_type == NMP_CACHE_ID_TYPE_OBJECT_TYPE) - continue; - - entry2 = nm_dedup_multi_index_lookup_obj (cache->multi_idx, - _idx_type_get (cache, id_type), - entry->obj); - if (!entry2) - continue; - - nm_assert (entry2 != entry); - nm_assert (entry2->obj == entry->obj); - - nm_dedup_multi_entry_reorder (entry2, NULL, TRUE); - } -} - static void _idxcache_update_other_cache_ids (NMPCache *cache, NMPCacheIdType cache_id_type, @@ -1875,7 +1835,7 @@ _idxcache_update_other_cache_ids (NMPCache *cache, obj_new, is_dump ? NM_DEDUP_MULTI_IDX_MODE_APPEND_FORCE - : _obj_get_add_mode (obj_new), + : NM_DEDUP_MULTI_IDX_MODE_APPEND, is_dump ? NULL : entry_order, @@ -1953,7 +1913,7 @@ _idxcache_update (NMPCache *cache, obj_new, is_dump ? NM_DEDUP_MULTI_IDX_MODE_APPEND_FORCE - : _obj_get_add_mode (obj_new), + : NM_DEDUP_MULTI_IDX_MODE_APPEND, NULL, entry_old ?: NM_DEDUP_MULTI_ENTRY_MISSING, NULL, @@ -2210,8 +2170,6 @@ nmp_cache_update_netlink (NMPCache *cache, } if (nmp_object_equal (obj_old, obj_hand_over)) { - if (is_dump) - _idxcache_update_order_for_dump (cache, entry_old); nm_dedup_multi_entry_set_dirty (entry_old, FALSE); NM_SET_OUT (out_obj_new, nmp_object_ref (obj_old)); return NMP_CACHE_OPS_UNCHANGED; @@ -2285,8 +2243,6 @@ nmp_cache_update_netlink_route (NMPCache *cache, } if (nmp_object_equal (entry_old->obj, obj_hand_over)) { - if (is_dump) - _idxcache_update_order_for_dump (cache, entry_old); nm_dedup_multi_entry_set_dirty (entry_old, FALSE); goto update_done; } @@ -2310,8 +2266,9 @@ update_done: * properly find @obj_replaced. */ resync_required = FALSE; entry_replace = NULL; - if (is_dump) + if (is_dump) { goto out; + } if (!entry_new) { if ( NM_FLAGS_HAS (nlmsgflags, NLM_F_REPLACE) @@ -2326,8 +2283,6 @@ update_done: goto out; } - /* FIXME: for routes, we only maintain the order correctly for the BY_WEAK_ID - * index. For all other indexes their order becomes messed up. */ entry_cur = _lookup_entry_with_idx_type (cache, NMP_CACHE_ID_TYPE_ROUTES_BY_WEAK_ID, entry_new->obj); @@ -2780,17 +2735,6 @@ const NMPClass _nmp_classes[NMP_OBJECT_TYPE_MAX] = { .cmd_plobj_hash_update = (void (*) (const NMPlatformObject *obj, NMHashState *h)) nm_platform_lnk_sit_hash_update, .cmd_plobj_cmp = (int (*) (const NMPlatformObject *obj1, const NMPlatformObject *obj2)) nm_platform_lnk_sit_cmp, }, - [NMP_OBJECT_TYPE_LNK_TUN - 1] = { - .parent = DEDUP_MULTI_OBJ_CLASS_INIT(), - .obj_type = NMP_OBJECT_TYPE_LNK_TUN, - .sizeof_data = sizeof (NMPObjectLnkTun), - .sizeof_public = sizeof (NMPlatformLnkTun), - .obj_type_name = "tun", - .lnk_link_type = NM_LINK_TYPE_TUN, - .cmd_plobj_to_string = (const char *(*) (const NMPlatformObject *obj, char *buf, gsize len)) nm_platform_lnk_tun_to_string, - .cmd_plobj_hash_update = (void (*) (const NMPlatformObject *obj, NMHashState *h)) nm_platform_lnk_tun_hash_update, - .cmd_plobj_cmp = (int (*) (const NMPlatformObject *obj1, const NMPlatformObject *obj2)) nm_platform_lnk_tun_cmp, - }, [NMP_OBJECT_TYPE_LNK_VLAN - 1] = { .parent = DEDUP_MULTI_OBJ_CLASS_INIT(), .obj_type = NMP_OBJECT_TYPE_LNK_VLAN, diff --git a/src/platform/nmp-object.h b/src/platform/nmp-object.h index f473f462..e17b17b0 100644 --- a/src/platform/nmp-object.h +++ b/src/platform/nmp-object.h @@ -88,7 +88,7 @@ typedef enum { /*< skip >*/ /* Consider all the destination fields of a route, that is, the ID without the ifindex * and gateway (meaning: network/plen,metric). * The reason for this is that `ip route change` can replace an existing route - * and modify its ifindex/gateway. Effectively, that means it deletes an existing + * and modify it's ifindex/gateway. Effectively, that means it deletes an existing * route and adds a different one (as the ID of the route changes). However, it only * sends one RTM_NEWADDR notification without notifying about the deletion. We detect * that by having this index to contain overlapping routes which require special @@ -197,10 +197,6 @@ typedef struct { } NMPObjectLnkSit; typedef struct { - NMPlatformLnkTun _public; -} NMPObjectLnkTun; - -typedef struct { NMPlatformLnkVlan _public; guint n_ingress_qos_map; @@ -269,9 +265,6 @@ struct _NMPObject { NMPlatformLnkSit lnk_sit; NMPObjectLnkSit _lnk_sit; - NMPlatformLnkTun lnk_tun; - NMPObjectLnkTun _lnk_tun; - NMPlatformLnkVlan lnk_vlan; NMPObjectLnkVlan _lnk_vlan; @@ -467,8 +460,6 @@ nmp_object_ref (const NMPObject *obj) static inline void nmp_object_unref (const NMPObject *obj) { - nm_assert (!obj || NMP_OBJECT_IS_VALID (obj)); - nm_dedup_multi_obj_unref ((const NMDedupMultiObj *) obj); } @@ -490,7 +481,7 @@ nmp_object_unref (const NMPObject *obj) NMPObject *nmp_object_new (NMPObjectType obj_type, const NMPlatformObject *plob); NMPObject *nmp_object_new_link (int ifindex); -const NMPObject *nmp_object_stackinit (NMPObject *obj, NMPObjectType obj_type, gconstpointer plobj); +const NMPObject *nmp_object_stackinit (NMPObject *obj, NMPObjectType obj_type, const NMPlatformObject *plobj); static inline NMPObject * nmp_object_stackinit_obj (NMPObject *obj, const NMPObject *src) @@ -508,13 +499,7 @@ const NMPObject *nmp_object_stackinit_id_ip6_address (NMPObject *obj, int ifinde const char *nmp_object_to_string (const NMPObject *obj, NMPObjectToStringMode to_string_mode, char *buf, gsize buf_size); void nmp_object_hash_update (const NMPObject *obj, NMHashState *h); int nmp_object_cmp (const NMPObject *obj1, const NMPObject *obj2); - -static inline gboolean -nmp_object_equal (const NMPObject *obj1, const NMPObject *obj2) -{ - return nmp_object_cmp (obj1, obj2) == 0; -} - +gboolean nmp_object_equal (const NMPObject *obj1, const NMPObject *obj2); void nmp_object_copy (NMPObject *dst, const NMPObject *src, gboolean id_only); NMPObject *nmp_object_clone (const NMPObject *obj, gboolean id_only); @@ -739,16 +724,6 @@ const NMDedupMultiEntry *nm_platform_lookup_entry (NMPlatform *platform, NMPCacheIdType cache_id_type, const NMPObject *obj); -static inline const NMPObject * -nm_platform_lookup_obj (NMPlatform *platform, - NMPCacheIdType cache_id_type, - const NMPObject *obj) -{ - return nm_dedup_multi_entry_get_obj (nm_platform_lookup_entry (platform, - cache_id_type, - obj)); -} - static inline const NMDedupMultiHeadEntry * nm_platform_lookup_obj_type (NMPlatform *platform, NMPObjectType obj_type) diff --git a/src/platform/tests/meson.build b/src/platform/tests/meson.build deleted file mode 100644 index 0571efac..00000000 --- a/src/platform/tests/meson.build +++ /dev/null @@ -1,37 +0,0 @@ -test_units = [ - ['test-link-fake', 'test-link.c', 60], - ['test-link-linux', 'test-link.c', 60], - ['test-address-fake', 'test-address.c'], - ['test-address-linux', 'test-address.c'], - ['test-general', 'test-general.c'], - ['test-nmp-object', 'test-nmp-object.c'], - ['test-route-fake', 'test-route.c'], - ['test-route-linux', 'test-route.c'], - ['test-cleanup-fake', 'test-cleanup.c'], - ['test-cleanup-linux', 'test-cleanup.c'], -] - -foreach test_unit: test_units - exe = executable( - 'platform-' + test_unit[0], - test_unit[1], - dependencies: test_nm_dep, - c_args: test_cflags_platform - ) - - test( - 'platform/' + test_unit[0], - test_script, - timeout: test_unit.length() > 2 ? test_unit[2] : 30, - args: test_args + [exe.full_path()] - ) -endforeach - -test = 'monitor' - -executable( - test, - test + '.c', - dependencies: test_nm_dep, - c_args: test_cflags_platform -) diff --git a/src/platform/tests/monitor.c b/src/platform/tests/monitor.c index f0e3e6cf..e1220052 100644 --- a/src/platform/tests/monitor.c +++ b/src/platform/tests/monitor.c @@ -1,5 +1,6 @@ /* -*- Mode: C; tab-width: 4; indent-tabs-mode: t; c-basic-offset: 4 -*- */ -/* +/* NetworkManager audit support + * * This program is free software; you can redistribute it and/or modify * it under the terms of the GNU General Public License as published by * the Free Software Foundation; either version 2 of the License, or diff --git a/src/platform/tests/test-address.c b/src/platform/tests/test-address.c index ddef8853..93851ff7 100644 --- a/src/platform/tests/test-address.c +++ b/src/platform/tests/test-address.c @@ -1,5 +1,6 @@ /* -*- Mode: C; tab-width: 4; indent-tabs-mode: t; c-basic-offset: 4 -*- */ -/* +/* NetworkManager audit support + * * This program is free software; you can redistribute it and/or modify * it under the terms of the GNU General Public License as published by * the Free Software Foundation; either version 2 of the License, or @@ -148,7 +149,7 @@ test_ip6_address_general (void) /* Add address again (aka update) */ nmtstp_ip6_address_add (NULL, EX, ifindex, addr, IP6_PLEN, in6addr_any, lifetime, preferred, flags); - accept_signals (address_changed, 0, 2); + accept_signals (address_changed, 0, 1); /* Test address listing */ addresses = nmtstp_platform_ip6_address_get_all (NM_PLATFORM_GET, ifindex); diff --git a/src/platform/tests/test-cleanup.c b/src/platform/tests/test-cleanup.c index a213b31f..937cd12c 100644 --- a/src/platform/tests/test-cleanup.c +++ b/src/platform/tests/test-cleanup.c @@ -1,5 +1,6 @@ /* -*- Mode: C; tab-width: 4; indent-tabs-mode: t; c-basic-offset: 4 -*- */ -/* +/* NetworkManager audit support + * * This program is free software; you can redistribute it and/or modify * it under the terms of the GNU General Public License as published by * the Free Software Foundation; either version 2 of the License, or diff --git a/src/platform/tests/test-common.c b/src/platform/tests/test-common.c index 7885c083..d56e681e 100644 --- a/src/platform/tests/test-common.c +++ b/src/platform/tests/test-common.c @@ -1,5 +1,6 @@ /* -*- Mode: C; tab-width: 4; indent-tabs-mode: t; c-basic-offset: 4 -*- */ -/* +/* NetworkManager audit support + * * This program is free software; you can redistribute it and/or modify * it under the terms of the GNU General Public License as published by * the Free Software Foundation; either version 2 of the License, or @@ -23,7 +24,6 @@ #include <sched.h> #include <sys/wait.h> #include <fcntl.h> -#include <linux/if_tun.h> #include "test-common.h" @@ -628,10 +628,7 @@ nmtstp_wait_for_signal_until (NMPlatform *platform, gint64 until_ms) const NMPlatformLink * nmtstp_wait_for_link (NMPlatform *platform, const char *ifname, NMLinkType expected_link_type, gint64 timeout_ms) { - return nmtstp_wait_for_link_until (platform, ifname, expected_link_type, - timeout_ms - ? nm_utils_get_monotonic_timestamp_ms () + timeout_ms - : 0); + return nmtstp_wait_for_link_until (platform, ifname, expected_link_type, nm_utils_get_monotonic_timestamp_ms () + timeout_ms); } const NMPlatformLink * @@ -639,7 +636,6 @@ nmtstp_wait_for_link_until (NMPlatform *platform, const char *ifname, NMLinkType { const NMPlatformLink *plink; gint64 now; - gboolean waited_once = FALSE; _init_platform (&platform, FALSE); @@ -651,24 +647,29 @@ nmtstp_wait_for_link_until (NMPlatform *platform, const char *ifname, NMLinkType && (expected_link_type == NM_LINK_TYPE_NONE || plink->type == expected_link_type)) return plink; - if (until_ms == 0) { - /* don't wait, don't even poll the socket. */ - return NULL; - } - - if ( waited_once - && until_ms < now) { - /* timeout reached (+ we already waited for a signal at least once). */ + if (until_ms < now) return NULL; - } - waited_once = TRUE; - /* regardless of whether timeout is already reached, we poll the netlink - * socket a bit. */ nmtstp_wait_for_signal (platform, until_ms - now); } } +const NMPlatformLink * +nmtstp_assert_wait_for_link (NMPlatform *platform, const char *ifname, NMLinkType expected_link_type, guint timeout_ms) +{ + return nmtstp_assert_wait_for_link_until (platform, ifname, expected_link_type, nm_utils_get_monotonic_timestamp_ms () + timeout_ms); +} + +const NMPlatformLink * +nmtstp_assert_wait_for_link_until (NMPlatform *platform, const char *ifname, NMLinkType expected_link_type, gint64 until_ms) +{ + const NMPlatformLink *plink; + + plink = nmtstp_wait_for_link_until (platform, ifname, expected_link_type, until_ms); + g_assert (plink); + return plink; +} + /*****************************************************************************/ int @@ -1283,10 +1284,6 @@ nmtstp_link_ip6tnl_add (NMPlatform *platform, const NMPlatformLink *pllink = NULL; gboolean success; char buffer[INET6_ADDRSTRLEN]; - char encap[20]; - char tclass[20]; - gboolean encap_ignore; - gboolean tclass_inherit; g_assert (nm_utils_is_valid_iface_name (name, NULL)); @@ -1312,18 +1309,15 @@ nmtstp_link_ip6tnl_add (NMPlatform *platform, g_assert_not_reached (); } - encap_ignore = NM_FLAGS_HAS (lnk->flags, IP6_TNL_F_IGN_ENCAP_LIMIT); - tclass_inherit = NM_FLAGS_HAS (lnk->flags, IP6_TNL_F_USE_ORIG_TCLASS); - - success = !nmtstp_run_command ("ip -6 tunnel add %s mode %s %s local %s remote %s ttl %u tclass %s encaplimit %s flowlabel %x", + success = !nmtstp_run_command ("ip -6 tunnel add %s mode %s %s local %s remote %s ttl %u tclass %02x encaplimit %u flowlabel %x", name, mode, dev, nm_utils_inet6_ntop (&lnk->local, NULL), nm_utils_inet6_ntop (&lnk->remote, buffer), lnk->ttl, - tclass_inherit ? "inherit" : nm_sprintf_buf (tclass, "%02x", lnk->tclass), - encap_ignore ? "none" : nm_sprintf_buf (encap, "%u", lnk->encap_limit), + lnk->tclass, + lnk->encap_limit, lnk->flow_label); if (success) pllink = nmtstp_assert_wait_for_link (platform, name, NM_LINK_TYPE_IP6TNL, 100); @@ -1469,70 +1463,6 @@ nmtstp_link_sit_add (NMPlatform *platform, } const NMPlatformLink * -nmtstp_link_tun_add (NMPlatform *platform, - gboolean external_command, - const char *name, - const NMPlatformLnkTun *lnk, - int *out_fd) -{ - const NMPlatformLink *pllink = NULL; - NMPlatformError plerr; - int err; - - g_assert (nm_utils_is_valid_iface_name (name, NULL)); - g_assert (lnk); - g_assert (NM_IN_SET (lnk->type, IFF_TUN, IFF_TAP)); - g_assert (!out_fd || *out_fd == -1); - - if (!lnk->persist) { - /* ip tuntap does not support non-persistent devices. - * - * Add this device only via NMPlatform. */ - if (external_command == -1) - external_command = FALSE; - } - - external_command = nmtstp_run_command_check_external (external_command); - - _init_platform (&platform, external_command); - - if (external_command) { - g_assert (lnk->persist); - - err = nmtstp_run_command ("ip tuntap add" - " mode %s" - "%s" /* user */ - "%s" /* group */ - "%s" /* pi */ - "%s" /* vnet_hdr */ - "%s" /* multi_queue */ - " name %s", - lnk->type == IFF_TUN ? "tun" : "tap", - lnk->owner_valid ? nm_sprintf_bufa (100, " user %u", (guint) lnk->owner) : "", - lnk->group_valid ? nm_sprintf_bufa (100, " group %u", (guint) lnk->group) : "", - lnk->pi ? " pi" : "", - lnk->vnet_hdr ? " vnet_hdr" : "", - lnk->multi_queue ? " multi_queue" : "", - name); - /* Older versions of iproute2 don't support adding devices. - * On failure, fallback to using platform code. */ - if (err == 0) - pllink = nmtstp_assert_wait_for_link (platform, name, NM_LINK_TYPE_TUN, 100); - else - g_error ("failure to add tun/tap device via ip-route"); - } else { - g_assert (lnk->persist || out_fd); - plerr = nm_platform_link_tun_add (platform, name, lnk, &pllink, out_fd); - g_assert_cmpint (plerr, ==, NM_PLATFORM_ERROR_SUCCESS); - } - - g_assert (pllink); - g_assert_cmpint (pllink->type, ==, NM_LINK_TYPE_TUN); - g_assert_cmpstr (pllink->name, ==, name); - return pllink; -} - -const NMPlatformLink * nmtstp_link_vxlan_add (NMPlatform *platform, gboolean external_command, const char *name, diff --git a/src/platform/tests/test-common.h b/src/platform/tests/test-common.h index bd02b0d7..fb406a3f 100644 --- a/src/platform/tests/test-common.h +++ b/src/platform/tests/test-common.h @@ -1,21 +1,3 @@ -/* - * This program is free software; you can redistribute it and/or modify - * it under the terms of the GNU General Public License as published by - * the Free Software Foundation; either version 2 of the License, or - * (at your option) any later version. - * - * This program is distributed in the hope that it will be useful, - * but WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the - * GNU General Public License for more details. - * - * You should have received a copy of the GNU General Public License along - * with this program; if not, write to the Free Software Foundation, Inc., - * 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA. - * - * Copyright 2016 - 2017 Red Hat, Inc. - */ - #include <stdlib.h> #include <unistd.h> #include <syslog.h> @@ -129,11 +111,8 @@ const NMPlatformLink *nmtstp_wait_for_link_until (NMPlatform *platform, const ch g_assert_not_reached (); \ } G_STMT_END -#define nmtstp_assert_wait_for_link(platform, ifname, expected_link_type, timeout_ms) \ - nmtst_assert_nonnull (nmtstp_wait_for_link (platform, ifname, expected_link_type, timeout_ms)) - -#define nmtstp_assert_wait_for_link_until(platform, ifname, expected_link_type, until_ms) \ - nmtst_assert_nonnull (nmtstp_wait_for_link_until (platform, ifname, expected_link_type, until_ms)) +const NMPlatformLink *nmtstp_assert_wait_for_link (NMPlatform *platform, const char *ifname, NMLinkType expected_link_type, guint timeout_ms); +const NMPlatformLink *nmtstp_assert_wait_for_link_until (NMPlatform *platform, const char *ifname, NMLinkType expected_link_type, gint64 until_ms); /*****************************************************************************/ @@ -310,11 +289,6 @@ const NMPlatformLink *nmtstp_link_sit_add (NMPlatform *platform, gboolean external_command, const char *name, const NMPlatformLnkSit *lnk); -const NMPlatformLink *nmtstp_link_tun_add (NMPlatform *platform, - gboolean external_command, - const char *name, - const NMPlatformLnkTun *lnk, - int *out_fd); const NMPlatformLink *nmtstp_link_vxlan_add (NMPlatform *platform, gboolean external_command, const char *name, diff --git a/src/platform/tests/test-link.c b/src/platform/tests/test-link.c index dcd600ee..ef78cc24 100644 --- a/src/platform/tests/test-link.c +++ b/src/platform/tests/test-link.c @@ -1,5 +1,6 @@ /* -*- Mode: C; tab-width: 4; indent-tabs-mode: t; c-basic-offset: 4 -*- */ -/* +/* NetworkManager audit support + * * This program is free software; you can redistribute it and/or modify * it under the terms of the GNU General Public License as published by * the Free Software Foundation; either version 2 of the License, or @@ -23,7 +24,6 @@ #include <sys/mount.h> #include <sys/stat.h> #include <sys/types.h> -#include <linux/if_tun.h> #include "platform/nmp-object.h" #include "platform/nmp-netns.h" @@ -698,8 +698,6 @@ test_software_detect (gconstpointer user_data) const NMPObject *lnk; guint i_step; const gboolean ext = test_data->external_command; - NMPlatformLnkTun lnk_tun; - nm_auto_close int tun_fd = -1; nmtstp_run_command_check ("ip link add %s type dummy", PARENT_NAME); ifindex_parent = nmtstp_assert_wait_for_link (NM_PLATFORM_GET, PARENT_NAME, NM_LINK_TYPE_DUMMY, 100)->ifindex; @@ -763,27 +761,13 @@ test_software_detect (gconstpointer user_data) gracefully_skip = nm_utils_modprobe (NULL, TRUE, "ip6_tunnel", NULL) != 0; } - switch (test_data->test_mode) { - case 0: - lnk_ip6tnl.local = *nmtst_inet6_from_string ("fd01::15"); - lnk_ip6tnl.remote = *nmtst_inet6_from_string ("fd01::16"); - lnk_ip6tnl.parent_ifindex = ifindex_parent; - lnk_ip6tnl.tclass = 20; - lnk_ip6tnl.encap_limit = 6; - lnk_ip6tnl.flow_label = 1337; - lnk_ip6tnl.proto = IPPROTO_IPV6; - break; - case 1: - lnk_ip6tnl.local = *nmtst_inet6_from_string ("fd01::17"); - lnk_ip6tnl.remote = *nmtst_inet6_from_string ("fd01::18"); - lnk_ip6tnl.parent_ifindex = ifindex_parent; - lnk_ip6tnl.tclass = 0; - lnk_ip6tnl.encap_limit = 0; - lnk_ip6tnl.flow_label = 1338; - lnk_ip6tnl.proto = IPPROTO_IPV6; - lnk_ip6tnl.flags = IP6_TNL_F_IGN_ENCAP_LIMIT | IP6_TNL_F_USE_ORIG_TCLASS; - break; - } + lnk_ip6tnl.local = *nmtst_inet6_from_string ("fd01::15"); + lnk_ip6tnl.remote = *nmtst_inet6_from_string ("fd01::16"); + lnk_ip6tnl.parent_ifindex = ifindex_parent; + lnk_ip6tnl.tclass = 20; + lnk_ip6tnl.encap_limit = 6; + lnk_ip6tnl.flow_label = 1337; + lnk_ip6tnl.proto = IPPROTO_IPV6; if (!nmtstp_link_ip6tnl_add (NULL, ext, DEVICE_NAME, &lnk_ip6tnl)) { if (gracefully_skip) { @@ -895,38 +879,6 @@ test_software_detect (gconstpointer user_data) g_assert (nmtstp_link_vxlan_add (NULL, ext, DEVICE_NAME, &lnk_vxlan)); break; } - case NM_LINK_TYPE_TUN: { - gboolean owner_valid = nmtst_get_rand_bool (); - gboolean group_valid = nmtst_get_rand_bool (); - - switch (test_data->test_mode) { - case 0: - lnk_tun = (NMPlatformLnkTun) { - .type = nmtst_get_rand_bool () ? IFF_TUN : IFF_TAP, - .owner = owner_valid ? getuid () : 0, - .owner_valid = owner_valid, - .group = group_valid ? getgid () : 0, - .group_valid = group_valid, - .pi = nmtst_get_rand_bool (), - .vnet_hdr = nmtst_get_rand_bool (), - .multi_queue = nmtst_get_rand_bool (), - - /* if we add the device via iproute2 (external), we can only - * create persistent devices. */ - .persist = (ext == 1) ? TRUE : nmtst_get_rand_bool (), - }; - break; - default: - g_assert_not_reached (); - break; - } - - g_assert (nmtstp_link_tun_add (NULL, ext, DEVICE_NAME, &lnk_tun, - (!lnk_tun.persist || nmtst_get_rand_bool ()) - ? &tun_fd - : NULL)); - break; - } default: g_assert_not_reached (); } @@ -957,13 +909,7 @@ test_software_detect (gconstpointer user_data) lnk = nm_platform_link_get_lnk (NM_PLATFORM_GET, ifindex, test_data->link_type, &plink); g_assert (plink); g_assert_cmpint (plink->ifindex, ==, ifindex); - - if ( !lnk - && test_data->link_type == NM_LINK_TYPE_TUN) { - /* this is ok. Kernel apparently does not support tun properties via netlink. We - * fetch them from sysfs below. */ - } else - g_assert (lnk); + g_assert (lnk); switch (test_data->link_type) { case NM_LINK_TYPE_GRE: { @@ -985,31 +931,15 @@ test_software_detect (gconstpointer user_data) case NM_LINK_TYPE_IP6TNL: { const NMPlatformLnkIp6Tnl *plnk = &lnk->lnk_ip6tnl; - switch (test_data->test_mode) { - case 0: - g_assert (plnk == nm_platform_link_get_lnk_ip6tnl (NM_PLATFORM_GET, ifindex, NULL)); - g_assert_cmpint (plnk->parent_ifindex, ==, ifindex_parent); - nmtst_assert_ip6_address (&plnk->local, "fd01::15"); - nmtst_assert_ip6_address (&plnk->remote, "fd01::16"); - g_assert_cmpint (plnk->ttl, ==, 0); - g_assert_cmpint (plnk->tclass, ==, 20); - g_assert_cmpint (plnk->encap_limit, ==, 6); - g_assert_cmpint (plnk->flow_label, ==, 1337); - g_assert_cmpint (plnk->proto, ==, IPPROTO_IPV6); - break; - case 1: - g_assert (plnk == nm_platform_link_get_lnk_ip6tnl (NM_PLATFORM_GET, ifindex, NULL)); - g_assert_cmpint (plnk->parent_ifindex, ==, ifindex_parent); - nmtst_assert_ip6_address (&plnk->local, "fd01::17"); - nmtst_assert_ip6_address (&plnk->remote, "fd01::18"); - g_assert_cmpint (plnk->ttl, ==, 0); - g_assert_cmpint (plnk->flow_label, ==, 1338); - g_assert_cmpint (plnk->proto, ==, IPPROTO_IPV6); - g_assert_cmpint (plnk->flags & 0xFFFF, /* ignore kernel internal flags */ - ==, - IP6_TNL_F_IGN_ENCAP_LIMIT | IP6_TNL_F_USE_ORIG_TCLASS); - break; - } + g_assert (plnk == nm_platform_link_get_lnk_ip6tnl (NM_PLATFORM_GET, ifindex, NULL)); + g_assert_cmpint (plnk->parent_ifindex, ==, ifindex_parent); + nmtst_assert_ip6_address (&plnk->local, "fd01::15"); + nmtst_assert_ip6_address (&plnk->remote, "fd01::16"); + g_assert_cmpint (plnk->ttl, ==, 0); + g_assert_cmpint (plnk->tclass, ==, 20); + g_assert_cmpint (plnk->encap_limit, ==, 6); + g_assert_cmpint (plnk->flow_label, ==, 1337); + g_assert_cmpint (plnk->proto, ==, IPPROTO_IPV6); break; } case NM_LINK_TYPE_IPIP: { @@ -1052,27 +982,6 @@ test_software_detect (gconstpointer user_data) g_assert_cmpint (plnk->path_mtu_discovery, ==, FALSE); break; } - case NM_LINK_TYPE_TUN: { - const NMPlatformLnkTun *plnk; - NMPlatformLnkTun lnk_tun2; - - g_assert ((lnk ? &lnk->lnk_tun : NULL) == nm_platform_link_get_lnk_tun (NM_PLATFORM_GET, ifindex, NULL)); - - /* kernel might not expose tun options via netlink. Either way, try - * to read them (either from platform cache, or fallback to sysfs). - * See also: rh#1547213. */ - if (!nm_platform_link_tun_get_properties (NM_PLATFORM_GET, - ifindex, - &lnk_tun2)) - g_assert_not_reached (); - - plnk = lnk ? &lnk->lnk_tun : &lnk_tun2; - if (lnk) - g_assert (memcmp (plnk, &lnk_tun2, sizeof (NMPlatformLnkTun)) == 0); - - g_assert (nm_platform_lnk_tun_cmp (plnk, &lnk_tun) == 0); - break; - } case NM_LINK_TYPE_VLAN: { const NMPlatformLnkVlan *plnk = &lnk->lnk_vlan; @@ -2339,7 +2248,7 @@ test_netns_push (gpointer fixture, gconstpointer test_data) p = pl_base; for (j = nstack; j >= 1; ) { j--; - if (NM_FLAGS_ANY (stack[j].ns_types, ns_type)) { + if (NM_FLAGS_HAS (stack[j].ns_types, ns_type)) { p = stack[j].pl; break; } @@ -2637,13 +2546,11 @@ _nmtstp_setup_tests (void) g_test_add_func ("/link/external", test_external); test_software_detect_add ("/link/software/detect/gre", NM_LINK_TYPE_GRE, 0); - test_software_detect_add ("/link/software/detect/ip6tnl/0", NM_LINK_TYPE_IP6TNL, 0); - test_software_detect_add ("/link/software/detect/ip6tnl/1", NM_LINK_TYPE_IP6TNL, 1); + test_software_detect_add ("/link/software/detect/ip6tnl", NM_LINK_TYPE_IP6TNL, 0); test_software_detect_add ("/link/software/detect/ipip", NM_LINK_TYPE_IPIP, 0); test_software_detect_add ("/link/software/detect/macvlan", NM_LINK_TYPE_MACVLAN, 0); test_software_detect_add ("/link/software/detect/macvtap", NM_LINK_TYPE_MACVTAP, 0); test_software_detect_add ("/link/software/detect/sit", NM_LINK_TYPE_SIT, 0); - test_software_detect_add ("/link/software/detect/tun", NM_LINK_TYPE_TUN, 0); test_software_detect_add ("/link/software/detect/vlan", NM_LINK_TYPE_VLAN, 0); test_software_detect_add ("/link/software/detect/vxlan/0", NM_LINK_TYPE_VXLAN, 0); test_software_detect_add ("/link/software/detect/vxlan/1", NM_LINK_TYPE_VXLAN, 1); diff --git a/src/platform/tests/test-nmp-object.c b/src/platform/tests/test-nmp-object.c index 047d7a85..3228de83 100644 --- a/src/platform/tests/test-nmp-object.c +++ b/src/platform/tests/test-nmp-object.c @@ -54,20 +54,27 @@ test_obj_base (void) gs_unref_object GCancellable *obj_cancellable = g_cancellable_new (); nm_auto_nmpobj NMPObject *obj_link = nmp_object_new_link (10); - g_assert (&g->g_type_instance == (void *) &o->_class); - g_assert (&g->g_type_instance.g_class == (void *) &o->_class); +#define STATIC_ASSERT(cond) \ + G_STMT_START { \ + G_STATIC_ASSERT (cond); \ + G_STATIC_ASSERT_EXPR (cond); \ + g_assert (cond); \ + } G_STMT_END - g_assert (sizeof (o->parent.parent) == sizeof (GTypeInstance)); + STATIC_ASSERT (&g->g_type_instance == (void *) &o->_class); + STATIC_ASSERT (&g->g_type_instance.g_class == (void *) &o->_class); - g_assert (&c->parent == (void *) c); - g_assert (&c->parent.parent.g_type_class == (void *) c); - g_assert (&c->parent.parent.g_type == (void *) c); - g_assert (&c->parent.parent.g_type == &k->g_type); + STATIC_ASSERT (sizeof (o->parent.parent) == sizeof (GTypeInstance)); - g_assert (sizeof (c->parent.parent) == sizeof (GTypeClass)); + STATIC_ASSERT (&c->parent == (void *) c); + STATIC_ASSERT (&c->parent.parent.g_type_class == (void *) c); + STATIC_ASSERT (&c->parent.parent.g_type == (void *) c); + STATIC_ASSERT (&c->parent.parent.g_type == &k->g_type); - g_assert (&o->parent == (void *) o); - g_assert (&o->parent.klass == (void *) &o->_class); + STATIC_ASSERT (sizeof (c->parent.parent) == sizeof (GTypeClass)); + + STATIC_ASSERT (&o->parent == (void *) o); + STATIC_ASSERT (&o->parent.klass == (void *) &o->_class); obj = (NMObjBaseInst *) obj_cancellable; g_assert (!NMP_CLASS_IS_VALID ((NMPClass *) obj->klass)); diff --git a/src/platform/tests/test-route.c b/src/platform/tests/test-route.c index 85b14b57..13648f16 100644 --- a/src/platform/tests/test-route.c +++ b/src/platform/tests/test-route.c @@ -1,5 +1,6 @@ /* -*- Mode: C; tab-width: 4; indent-tabs-mode: t; c-basic-offset: 4 -*- */ -/* +/* NetworkManager audit support + * * This program is free software; you can redistribute it and/or modify * it under the terms of the GNU General Public License as published by * the Free Software Foundation; either version 2 of the License, or diff --git a/src/platform/wifi/wifi-utils-nl80211.c b/src/platform/wifi/wifi-utils-nl80211.c index db187a1f..a5f25b02 100644 --- a/src/platform/wifi/wifi-utils-nl80211.c +++ b/src/platform/wifi/wifi-utils-nl80211.c @@ -22,17 +22,17 @@ #include "nm-default.h" -#include "wifi-utils-nl80211.h" - #include <errno.h> #include <string.h> #include <sys/ioctl.h> #include <net/ethernet.h> #include <unistd.h> +#include <netlink/netlink.h> +#include <netlink/msg.h> #include <linux/nl80211.h> -#include "platform/nm-netlink.h" #include "wifi-utils-private.h" +#include "wifi-utils-nl80211.h" #include "platform/nm-platform.h" #include "platform/nm-platform-utils.h" #include "nm-utils.h" @@ -46,14 +46,223 @@ _NM_UTILS_MACRO_REST(__VA_ARGS__)); \ } G_STMT_END +/*****************************************************************************/ + +static int +_nl_nla_parse (struct nlattr *tb[], int maxtype, struct nlattr *head, int len, + const struct nla_policy *policy) +{ + return nla_parse (tb, maxtype, head, len, (struct nla_policy *) policy); +} +#define nla_parse(...) _nl_nla_parse(__VA_ARGS__) + +static int +_nl_nla_parse_nested (struct nlattr *tb[], int maxtype, struct nlattr *nla, + const struct nla_policy *policy) +{ + return nla_parse_nested (tb, maxtype, nla, (struct nla_policy *) policy); +} +#define nla_parse_nested(...) _nl_nla_parse_nested(__VA_ARGS__) + +/***************************************************************************** + * Copied from libnl3/genl: + *****************************************************************************/ + +static void * +genlmsg_put (struct nl_msg *msg, uint32_t port, uint32_t seq, int family, + int hdrlen, int flags, uint8_t cmd, uint8_t version) +{ + struct nlmsghdr *nlh; + struct genlmsghdr hdr = { + .cmd = cmd, + .version = version, + }; + + nlh = nlmsg_put (msg, port, seq, family, GENL_HDRLEN + hdrlen, flags); + if (nlh == NULL) + return NULL; + + memcpy (nlmsg_data (nlh), &hdr, sizeof (hdr)); + + return (char *) nlmsg_data (nlh) + GENL_HDRLEN; +} + +static void * +genlmsg_data (const struct genlmsghdr *gnlh) +{ + return ((unsigned char *) gnlh + GENL_HDRLEN); +} + +static void * +genlmsg_user_hdr (const struct genlmsghdr *gnlh) +{ + return genlmsg_data (gnlh); +} + +static struct genlmsghdr * +genlmsg_hdr (struct nlmsghdr *nlh) +{ + return nlmsg_data (nlh); +} + +static void * +genlmsg_user_data (const struct genlmsghdr *gnlh, const int hdrlen) +{ + return (char *) genlmsg_user_hdr (gnlh) + NLMSG_ALIGN (hdrlen); +} + +static struct nlattr * +genlmsg_attrdata (const struct genlmsghdr *gnlh, int hdrlen) +{ + return genlmsg_user_data (gnlh, hdrlen); +} + +static int +genlmsg_len (const struct genlmsghdr *gnlh) +{ + const struct nlmsghdr *nlh; + + nlh = (const struct nlmsghdr *) ((const unsigned char *) gnlh - NLMSG_HDRLEN); + return (nlh->nlmsg_len - GENL_HDRLEN - NLMSG_HDRLEN); +} + +static int +genlmsg_attrlen (const struct genlmsghdr *gnlh, int hdrlen) +{ + return genlmsg_len (gnlh) - NLMSG_ALIGN (hdrlen); +} + +static int +genlmsg_valid_hdr (struct nlmsghdr *nlh, int hdrlen) +{ + struct genlmsghdr *ghdr; + + if (!nlmsg_valid_hdr (nlh, GENL_HDRLEN)) + return 0; + + ghdr = nlmsg_data (nlh); + if (genlmsg_len (ghdr) < NLMSG_ALIGN (hdrlen)) + return 0; + + return 1; +} + +static int +genlmsg_parse (struct nlmsghdr *nlh, int hdrlen, struct nlattr *tb[], + int maxtype, const struct nla_policy *policy) +{ + struct genlmsghdr *ghdr; + + if (!genlmsg_valid_hdr (nlh, hdrlen)) + return -NLE_MSG_TOOSHORT; + + ghdr = nlmsg_data (nlh); + return nla_parse (tb, maxtype, genlmsg_attrdata (ghdr, hdrlen), + genlmsg_attrlen (ghdr, hdrlen), policy); +} + +/***************************************************************************** + * Reimplementation of libnl3/genl functions: + *****************************************************************************/ + +static int +probe_response (struct nl_msg *msg, void *arg) +{ + static const struct nla_policy ctrl_policy[CTRL_ATTR_MAX+1] = { + [CTRL_ATTR_FAMILY_ID] = { .type = NLA_U16 }, + [CTRL_ATTR_FAMILY_NAME] = { .type = NLA_STRING, + .maxlen = GENL_NAMSIZ }, + [CTRL_ATTR_VERSION] = { .type = NLA_U32 }, + [CTRL_ATTR_HDRSIZE] = { .type = NLA_U32 }, + [CTRL_ATTR_MAXATTR] = { .type = NLA_U32 }, + [CTRL_ATTR_OPS] = { .type = NLA_NESTED }, + [CTRL_ATTR_MCAST_GROUPS] = { .type = NLA_NESTED }, + }; + struct nlattr *tb[CTRL_ATTR_MAX+1]; + struct nlmsghdr *nlh = nlmsg_hdr (msg); + gint32 *response_data = arg; + + if (genlmsg_parse (nlh, 0, tb, CTRL_ATTR_MAX, ctrl_policy)) + return NL_SKIP; + + if (tb[CTRL_ATTR_FAMILY_ID]) + *response_data = nla_get_u16 (tb[CTRL_ATTR_FAMILY_ID]); + + return NL_STOP; +} + +static int +genl_ctrl_resolve (struct nl_sock *sk, const char *name) +{ + struct nl_msg *msg; + struct nl_cb *cb, *orig; + int rc; + int result = -NLE_OBJ_NOTFOUND; + gint32 response_data = -1; + + if (!(orig = nl_socket_get_cb (sk))) + goto out; + + cb = nl_cb_clone (orig); + nl_cb_put (orig); + if (!cb) + goto out; + + msg = nlmsg_alloc (); + if (!msg) + goto out_cb_free; + + if (!genlmsg_put (msg, NL_AUTO_PORT, NL_AUTO_SEQ, GENL_ID_CTRL, + 0, 0, CTRL_CMD_GETFAMILY, 1)) + goto out_msg_free; + + if (nla_put_string (msg, CTRL_ATTR_FAMILY_NAME, name) < 0) + goto out_msg_free; + + rc = nl_cb_set (cb, NL_CB_VALID, NL_CB_CUSTOM, probe_response, &response_data); + if (rc < 0) + goto out_msg_free; + + rc = nl_send_auto_complete (sk, msg); + if (rc < 0) + goto out_msg_free; + + rc = nl_recvmsgs (sk, cb); + if (rc < 0) + goto out_msg_free; + + /* If search was successful, request may be ACKed after data */ + rc = nl_wait_for_ack (sk); + if (rc < 0) + goto out_msg_free; + + if (response_data > 0) + result = response_data; + +out_msg_free: + nlmsg_free (msg); +out_cb_free: + nl_cb_put (cb); +out: + if (result >= 0) + _LOGD (LOGD_WIFI, "genl_ctrl_resolve: resolved \"%s\" as 0x%x", name, result); + else + _LOGE (LOGD_WIFI, "genl_ctrl_resolve: failed resolve \"%s\"", name); + return result; +} + +/***************************************************************************** + * </libn-genl-3> + *****************************************************************************/ + typedef struct { WifiData parent; struct nl_sock *nl_sock; - guint32 *freqs; int id; + struct nl_cb *nl_cb; + guint32 *freqs; int num_freqs; int phy; - bool can_wowlan:1; } WifiDataNl80211; static int @@ -83,16 +292,19 @@ error_handler (struct sockaddr_nl *nla, struct nlmsgerr *err, void *arg) static struct nl_msg * _nl80211_alloc_msg (int id, int ifindex, int phy, guint32 cmd, guint32 flags) { - nm_auto_nlmsg struct nl_msg *msg = NULL; + struct nl_msg *msg; msg = nlmsg_alloc (); - genlmsg_put (msg, 0, 0, id, 0, flags, cmd, 0); - NLA_PUT_U32 (msg, NL80211_ATTR_IFINDEX, ifindex); - if (phy != -1) - NLA_PUT_U32 (msg, NL80211_ATTR_WIPHY, phy); - return g_steal_pointer (&msg); + if (msg) { + genlmsg_put (msg, 0, 0, id, 0, flags, cmd, 0); + NLA_PUT_U32 (msg, NL80211_ATTR_IFINDEX, ifindex); + if (phy != -1) + NLA_PUT_U32 (msg, NL80211_ATTR_WIPHY, phy); + } + return msg; -nla_put_failure: + nla_put_failure: + nlmsg_free (msg); return NULL; } @@ -102,37 +314,42 @@ nl80211_alloc_msg (WifiDataNl80211 *nl80211, guint32 cmd, guint32 flags) return _nl80211_alloc_msg (nl80211->id, nl80211->parent.ifindex, nl80211->phy, cmd, flags); } +/* NOTE: this function consumes 'msg' */ static int _nl80211_send_and_recv (struct nl_sock *nl_sock, + struct nl_cb *nl_cb, struct nl_msg *msg, int (*valid_handler) (struct nl_msg *, void *), void *valid_data) { - int err; - int done = 0; - const struct nl_cb cb = { - .err_cb = error_handler, - .err_arg = &done, - .finish_cb = finish_handler, - .finish_arg = &done, - .ack_cb = ack_handler, - .ack_arg = &done, - .valid_cb = valid_handler, - .valid_arg = valid_data, - }; + struct nl_cb *cb; + int err, done; g_return_val_if_fail (msg != NULL, -ENOMEM); - err = nl_send_auto (nl_sock, msg); + cb = nl_cb_clone (nl_cb); + if (!cb) { + err = -ENOMEM; + goto out; + } + + err = nl_send_auto_complete (nl_sock, msg); if (err < 0) - return err; + goto out; + + done = 0; + nl_cb_err (cb, NL_CB_CUSTOM, error_handler, &done); + nl_cb_set (cb, NL_CB_FINISH, NL_CB_CUSTOM, finish_handler, &done); + nl_cb_set (cb, NL_CB_ACK, NL_CB_CUSTOM, ack_handler, &done); + if (valid_handler) + nl_cb_set (cb, NL_CB_VALID, NL_CB_CUSTOM, valid_handler, valid_data); /* Loop until one of our NL callbacks says we're done; on success * done will be 1, on error it will be < 0. */ while (!done) { - err = nl_recvmsgs (nl_sock, &cb); - if (err < 0 && err != -EAGAIN) { + err = nl_recvmsgs (nl_sock, cb); + if (err && err != -NLE_AGAIN) { /* Kernel scan list can change while we are dumping it, as new scan * results from H/W can arrive. BSS info is assured to be consistent * and we don't need consistent view of whole scan list. Hence do @@ -147,9 +364,12 @@ _nl80211_send_and_recv (struct nl_sock *nl_sock, break; } } - - if (err >= 0 && done < 0) + if (err == 0 && done < 0) err = done; + + out: + nl_cb_put (cb); + nlmsg_free (msg); return err; } @@ -159,7 +379,7 @@ nl80211_send_and_recv (WifiDataNl80211 *nl80211, int (*valid_handler) (struct nl_msg *, void *), void *valid_data) { - return _nl80211_send_and_recv (nl80211->nl_sock, msg, + return _nl80211_send_and_recv (nl80211->nl_sock, nl80211->nl_cb, msg, valid_handler, valid_data); } @@ -170,6 +390,8 @@ wifi_nl80211_deinit (WifiData *parent) if (nl80211->nl_sock) nl_socket_free (nl80211->nl_sock); + if (nl80211->nl_cb) + nl_cb_put (nl80211->nl_cb); g_free (nl80211->freqs); } @@ -213,12 +435,12 @@ wifi_nl80211_get_mode (WifiData *data) struct nl80211_iface_info iface_info = { .mode = NM_802_11_MODE_UNKNOWN, }; - nm_auto_nlmsg struct nl_msg *msg = NULL; + struct nl_msg *msg; msg = nl80211_alloc_msg (nl80211, NL80211_CMD_GET_INTERFACE, 0); if (nl80211_send_and_recv (nl80211, msg, nl80211_iface_info_handler, - &iface_info) < 0) + &iface_info) < 0) return NM_802_11_MODE_UNKNOWN; return iface_info.mode; @@ -228,7 +450,7 @@ static gboolean wifi_nl80211_set_mode (WifiData *data, const NM80211Mode mode) { WifiDataNl80211 *nl80211 = (WifiDataNl80211 *) data; - nm_auto_nlmsg struct nl_msg *msg = NULL; + struct nl_msg *msg; int err; msg = nl80211_alloc_msg (nl80211, NL80211_CMD_SET_INTERFACE, 0); @@ -248,7 +470,7 @@ wifi_nl80211_set_mode (WifiData *data, const NM80211Mode mode) } err = nl80211_send_and_recv (nl80211, msg, NULL, NULL); - return err >= 0; + return err ? FALSE : TRUE; nla_put_failure: nlmsg_free (msg); @@ -259,14 +481,14 @@ static gboolean wifi_nl80211_set_powersave (WifiData *data, guint32 powersave) { WifiDataNl80211 *nl80211 = (WifiDataNl80211 *) data; - nm_auto_nlmsg struct nl_msg *msg = NULL; + struct nl_msg *msg; int err; msg = nl80211_alloc_msg (nl80211, NL80211_CMD_SET_POWER_SAVE, 0); NLA_PUT_U32 (msg, NL80211_ATTR_PS_STATE, powersave == 1 ? NL80211_PS_ENABLED : NL80211_PS_DISABLED); err = nl80211_send_and_recv (nl80211, msg, NULL, NULL); - return err >= 0; + return err ? FALSE : TRUE; nla_put_failure: nlmsg_free (msg); @@ -296,7 +518,7 @@ struct nl80211_bss_info { gboolean valid; }; -#define WLAN_EID_SSID 0 +#define WLAN_EID_SSID 0 static void find_ssid (guint8 *ies, guint32 ies_len, @@ -396,7 +618,7 @@ static void nl80211_get_bss_info (WifiDataNl80211 *nl80211, struct nl80211_bss_info *bss_info) { - nm_auto_nlmsg struct nl_msg *msg = NULL; + struct nl_msg *msg; memset (bss_info, 0, sizeof (*bss_info)); @@ -520,7 +742,7 @@ static void nl80211_get_ap_info (WifiDataNl80211 *nl80211, struct nl80211_station_info *sta_info) { - nm_auto_nlmsg struct nl_msg *msg = NULL; + struct nl_msg *msg; struct nl80211_bss_info bss_info; memset (sta_info, 0, sizeof (*sta_info)); @@ -568,38 +790,35 @@ wifi_nl80211_get_qual (WifiData *data) return sta_info.signal; } +#if HAVE_NL80211_CRITICAL_PROTOCOL_CMDS static gboolean wifi_nl80211_indicate_addressing_running (WifiData *data, gboolean running) { WifiDataNl80211 *nl80211 = (WifiDataNl80211 *) data; - nm_auto_nlmsg struct nl_msg *msg = NULL; + struct nl_msg *msg; int err; msg = nl80211_alloc_msg (nl80211, - running - ? 98 /* NL80211_CMD_CRIT_PROTOCOL_START */ - : 99 /* NL80211_CMD_CRIT_PROTOCOL_STOP */, + running ? NL80211_CMD_CRIT_PROTOCOL_START : + NL80211_CMD_CRIT_PROTOCOL_STOP, 0); /* Despite the DHCP name, we're using this for any type of IP addressing, * DHCPv4, DHCPv6, and IPv6 SLAAC. */ - NLA_PUT_U16 (msg, - 179 /* NL80211_ATTR_CRIT_PROT_ID */, - 1 /* NL80211_CRIT_PROTO_DHCP */); + NLA_PUT_U16 (msg, NL80211_ATTR_CRIT_PROT_ID, NL80211_CRIT_PROTO_DHCP); if (running) { /* Give DHCP 5 seconds to complete */ - NLA_PUT_U16 (msg, - 180 /* NL80211_ATTR_MAX_CRIT_PROT_DURATION */, - 5000); + NLA_PUT_U16 (msg, NL80211_ATTR_MAX_CRIT_PROT_DURATION, 5000); } err = nl80211_send_and_recv (nl80211, msg, NULL, NULL); - return err >= 0; + return err ? FALSE : TRUE; nla_put_failure: nlmsg_free (msg); return FALSE; } +#endif struct nl80211_wowlan_info { gboolean enabled; @@ -628,14 +847,12 @@ static gboolean wifi_nl80211_get_wowlan (WifiData *data) { WifiDataNl80211 *nl80211 = (WifiDataNl80211 *) data; - nm_auto_nlmsg struct nl_msg *msg = NULL; + struct nl_msg *msg; struct nl80211_wowlan_info info; - if (!nl80211->can_wowlan) - return FALSE; - msg = nl80211_alloc_msg (nl80211, NL80211_CMD_GET_WOWLAN, 0); nl80211_send_and_recv (nl80211, msg, nl80211_wowlan_handler, &info); + return info.enabled; } @@ -845,22 +1062,8 @@ static int nl80211_wiphy_info_handler (struct nl_msg *msg, void *arg) WifiData * wifi_nl80211_init (int ifindex) { - static const WifiDataClass klass = { - .struct_size = sizeof (WifiDataNl80211), - .get_mode = wifi_nl80211_get_mode, - .set_mode = wifi_nl80211_set_mode, - .set_powersave = wifi_nl80211_set_powersave, - .get_freq = wifi_nl80211_get_freq, - .find_freq = wifi_nl80211_find_freq, - .get_bssid = wifi_nl80211_get_bssid, - .get_rate = wifi_nl80211_get_rate, - .get_qual = wifi_nl80211_get_qual, - .get_wowlan = wifi_nl80211_get_wowlan, - .indicate_addressing_running = wifi_nl80211_indicate_addressing_running, - .deinit = wifi_nl80211_deinit, - }; WifiDataNl80211 *nl80211; - nm_auto_nlmsg struct nl_msg *msg = NULL; + struct nl_msg *msg; struct nl80211_device_info device_info = {}; char ifname[IFNAMSIZ]; @@ -870,7 +1073,19 @@ wifi_nl80211_init (int ifindex) nm_sprintf_buf (ifname, "if %d", ifindex); } - nl80211 = wifi_data_new (&klass, ifindex); + nl80211 = wifi_data_new (ifindex, sizeof (*nl80211)); + nl80211->parent.get_mode = wifi_nl80211_get_mode; + nl80211->parent.set_mode = wifi_nl80211_set_mode; + nl80211->parent.set_powersave = wifi_nl80211_set_powersave; + nl80211->parent.get_freq = wifi_nl80211_get_freq; + nl80211->parent.find_freq = wifi_nl80211_find_freq; + nl80211->parent.get_bssid = wifi_nl80211_get_bssid; + nl80211->parent.get_rate = wifi_nl80211_get_rate; + nl80211->parent.get_qual = wifi_nl80211_get_qual; +#if HAVE_NL80211_CRITICAL_PROTOCOL_CMDS + nl80211->parent.indicate_addressing_running = wifi_nl80211_indicate_addressing_running; +#endif + nl80211->parent.deinit = wifi_nl80211_deinit; nl80211->nl_sock = nl_socket_alloc (); if (nl80211->nl_sock == NULL) @@ -880,10 +1095,12 @@ wifi_nl80211_init (int ifindex) goto error; nl80211->id = genl_ctrl_resolve (nl80211->nl_sock, "nl80211"); - if (nl80211->id < 0) { - _LOGD (LOGD_WIFI, "genl_ctrl_resolve: failed to resolve \"nl80211\""); + if (nl80211->id < 0) + goto error; + + nl80211->nl_cb = nl_cb_alloc (NL_CB_DEFAULT); + if (nl80211->nl_cb == NULL) goto error; - } nl80211->phy = -1; @@ -936,15 +1153,18 @@ wifi_nl80211_init (int ifindex) nl80211->freqs = device_info.freqs; nl80211->num_freqs = device_info.num_freqs; nl80211->parent.caps = device_info.caps; - nl80211->can_wowlan = device_info.can_wowlan; + + if (device_info.can_wowlan) + nl80211->parent.get_wowlan = wifi_nl80211_get_wowlan; _LOGI (LOGD_PLATFORM | LOGD_WIFI, "(%s): using nl80211 for WiFi device control", ifname); + return (WifiData *) nl80211; error: - wifi_utils_unref ((WifiData *) nl80211); + wifi_utils_deinit ((WifiData *) nl80211); return NULL; } diff --git a/src/platform/wifi/wifi-utils-private.h b/src/platform/wifi/wifi-utils-private.h index 59386514..11a0f060 100644 --- a/src/platform/wifi/wifi-utils-private.h +++ b/src/platform/wifi/wifi-utils-private.h @@ -24,8 +24,9 @@ #include "nm-dbus-interface.h" #include "wifi-utils.h" -typedef struct { - gsize struct_size; +struct WifiData { + int ifindex; + NMDeviceWifiCapabilities caps; NM80211Mode (*get_mode) (WifiData *data); @@ -65,14 +66,9 @@ typedef struct { gboolean (*set_mesh_ssid) (WifiData *data, const guint8 *ssid, gsize len); gboolean (*indicate_addressing_running) (WifiData *data, gboolean running); -} WifiDataClass; - -struct WifiData { - const WifiDataClass *klass; - int ifindex; - NMDeviceWifiCapabilities caps; }; -gpointer wifi_data_new (const WifiDataClass *klass, int ifindex); +gpointer wifi_data_new (int ifindex, gsize len); +void wifi_data_free (WifiData *data); #endif /* __WIFI_UTILS_PRIVATE_H__ */ diff --git a/src/platform/wifi/wifi-utils-wext.c b/src/platform/wifi/wifi-utils-wext.c index c8744f79..c4d3c999 100644 --- a/src/platform/wifi/wifi-utils-wext.c +++ b/src/platform/wifi/wifi-utils-wext.c @@ -21,14 +21,17 @@ #include "nm-default.h" -#include "wifi-utils-wext.h" - #include <errno.h> #include <string.h> #include <sys/ioctl.h> #include <net/ethernet.h> #include <unistd.h> +#include "wifi-utils-private.h" +#include "wifi-utils-wext.h" +#include "nm-utils.h" +#include "platform/nm-platform-utils.h" + /* Hacks necessary to #include wireless.h; yay for WEXT */ #ifndef __user #define __user @@ -38,10 +41,6 @@ #include <sys/socket.h> #include <linux/wireless.h> -#include "wifi-utils-private.h" -#include "nm-utils.h" -#include "platform/nm-platform-utils.h" - typedef struct { WifiData parent; int fd; @@ -629,21 +628,6 @@ wext_get_caps (WifiDataWext *wext, const char *ifname, struct iw_range *range) WifiData * wifi_wext_init (int ifindex, gboolean check_scan) { - static const WifiDataClass klass = { - .struct_size = sizeof (WifiDataWext), - .get_mode = wifi_wext_get_mode, - .set_mode = wifi_wext_set_mode, - .set_powersave = wifi_wext_set_powersave, - .get_freq = wifi_wext_get_freq, - .find_freq = wifi_wext_find_freq, - .get_bssid = wifi_wext_get_bssid, - .get_rate = wifi_wext_get_rate, - .get_qual = wifi_wext_get_qual, - .deinit = wifi_wext_deinit, - .get_mesh_channel = wifi_wext_get_mesh_channel, - .set_mesh_channel = wifi_wext_set_mesh_channel, - .set_mesh_ssid = wifi_wext_set_mesh_ssid, - }; WifiDataWext *wext; struct iw_range range; guint32 response_len = 0; @@ -658,7 +642,19 @@ wifi_wext_init (int ifindex, gboolean check_scan) return NULL; } - wext = wifi_data_new (&klass, ifindex); + wext = wifi_data_new (ifindex, sizeof (*wext)); + wext->parent.get_mode = wifi_wext_get_mode; + wext->parent.set_mode = wifi_wext_set_mode; + wext->parent.set_powersave = wifi_wext_set_powersave; + wext->parent.get_freq = wifi_wext_get_freq; + wext->parent.find_freq = wifi_wext_find_freq; + wext->parent.get_bssid = wifi_wext_get_bssid; + wext->parent.get_rate = wifi_wext_get_rate; + wext->parent.get_qual = wifi_wext_get_qual; + wext->parent.deinit = wifi_wext_deinit; + wext->parent.get_mesh_channel = wifi_wext_get_mesh_channel; + wext->parent.set_mesh_channel = wifi_wext_set_mesh_channel; + wext->parent.set_mesh_ssid = wifi_wext_set_mesh_ssid; wext->fd = socket (PF_INET, SOCK_DGRAM | SOCK_CLOEXEC, 0); if (wext->fd < 0) @@ -734,7 +730,7 @@ wifi_wext_init (int ifindex, gboolean check_scan) return (WifiData *) wext; error: - wifi_utils_unref ((WifiData *) wext); + wifi_utils_deinit ((WifiData *) wext); return NULL; } diff --git a/src/platform/wifi/wifi-utils.c b/src/platform/wifi/wifi-utils.c index 8818dc9d..d0052121 100644 --- a/src/platform/wifi/wifi-utils.c +++ b/src/platform/wifi/wifi-utils.c @@ -38,19 +38,22 @@ #include "platform/nm-platform-utils.h" gpointer -wifi_data_new (const WifiDataClass *klass, int ifindex) +wifi_data_new (int ifindex, gsize len) { WifiData *data; - nm_assert (klass); - nm_assert (klass->struct_size > sizeof (WifiData)); - - data = g_malloc0 (klass->struct_size); - data->klass = klass; + data = g_malloc0 (len); data->ifindex = ifindex; return data; } +void +wifi_data_free (WifiData *data) +{ + memset (data, 0, sizeof (*data)); + g_free (data); +} + /*****************************************************************************/ WifiData * @@ -82,14 +85,14 @@ wifi_utils_get_caps (WifiData *data) { g_return_val_if_fail (data != NULL, NM_WIFI_DEVICE_CAP_NONE); - return data->caps; + return data->caps; } NM80211Mode wifi_utils_get_mode (WifiData *data) { g_return_val_if_fail (data != NULL, NM_802_11_MODE_UNKNOWN); - return data->klass->get_mode (data); + return data->get_mode (data); } gboolean @@ -101,7 +104,7 @@ wifi_utils_set_mode (WifiData *data, const NM80211Mode mode) || (mode == NM_802_11_MODE_ADHOC), FALSE); /* nl80211 probably doesn't need this */ - return data->klass->set_mode ? data->klass->set_mode (data, mode) : TRUE; + return data->set_mode ? data->set_mode (data, mode) : TRUE; } gboolean @@ -109,14 +112,14 @@ wifi_utils_set_powersave (WifiData *data, guint32 powersave) { g_return_val_if_fail (data != NULL, FALSE); - return data->klass->set_powersave ? data->klass->set_powersave (data, powersave) : TRUE; + return data->set_powersave ? data->set_powersave (data, powersave) : TRUE; } guint32 wifi_utils_get_freq (WifiData *data) { g_return_val_if_fail (data != NULL, 0); - return data->klass->get_freq (data); + return data->get_freq (data); } guint32 @@ -124,7 +127,7 @@ wifi_utils_find_freq (WifiData *data, const guint32 *freqs) { g_return_val_if_fail (data != NULL, 0); g_return_val_if_fail (freqs != NULL, 0); - return data->klass->find_freq (data, freqs); + return data->find_freq (data, freqs); } gboolean @@ -134,40 +137,38 @@ wifi_utils_get_bssid (WifiData *data, guint8 *out_bssid) g_return_val_if_fail (out_bssid != NULL, FALSE); memset (out_bssid, 0, ETH_ALEN); - return data->klass->get_bssid (data, out_bssid); + return data->get_bssid (data, out_bssid); } guint32 wifi_utils_get_rate (WifiData *data) { g_return_val_if_fail (data != NULL, 0); - return data->klass->get_rate (data); + return data->get_rate (data); } int wifi_utils_get_qual (WifiData *data) { g_return_val_if_fail (data != NULL, 0); - return data->klass->get_qual (data); + return data->get_qual (data); } gboolean wifi_utils_get_wowlan (WifiData *data) { g_return_val_if_fail (data != NULL, 0); - - if (!data->klass->get_wowlan) + if (!data->get_wowlan) return FALSE; - return data->klass->get_wowlan (data); + return data->get_wowlan (data); } void -wifi_utils_unref (WifiData *data) +wifi_utils_deinit (WifiData *data) { g_return_if_fail (data != NULL); - - data->klass->deinit (data); - g_free (data); + data->deinit (data); + wifi_data_free (data); } gboolean @@ -190,8 +191,8 @@ guint32 wifi_utils_get_mesh_channel (WifiData *data) { g_return_val_if_fail (data != NULL, FALSE); - g_return_val_if_fail (data->klass->get_mesh_channel != NULL, FALSE); - return data->klass->get_mesh_channel (data); + g_return_val_if_fail (data->get_mesh_channel != NULL, FALSE); + return data->get_mesh_channel (data); } gboolean @@ -199,24 +200,24 @@ wifi_utils_set_mesh_channel (WifiData *data, guint32 channel) { g_return_val_if_fail (data != NULL, FALSE); g_return_val_if_fail (channel <= 13, FALSE); - g_return_val_if_fail (data->klass->set_mesh_channel != NULL, FALSE); - return data->klass->set_mesh_channel (data, channel); + g_return_val_if_fail (data->set_mesh_channel != NULL, FALSE); + return data->set_mesh_channel (data, channel); } gboolean wifi_utils_set_mesh_ssid (WifiData *data, const guint8 *ssid, gsize len) { g_return_val_if_fail (data != NULL, FALSE); - g_return_val_if_fail (data->klass->set_mesh_ssid != NULL, FALSE); - return data->klass->set_mesh_ssid (data, ssid, len); + g_return_val_if_fail (data->set_mesh_ssid != NULL, FALSE); + return data->set_mesh_ssid (data, ssid, len); } gboolean wifi_utils_indicate_addressing_running (WifiData *data, gboolean running) { g_return_val_if_fail (data != NULL, FALSE); - if (data->klass->indicate_addressing_running) - return data->klass->indicate_addressing_running (data, running); + if (data->indicate_addressing_running) + return data->indicate_addressing_running (data, running); return FALSE; } diff --git a/src/platform/wifi/wifi-utils.h b/src/platform/wifi/wifi-utils.h index 2633e965..705717b0 100644 --- a/src/platform/wifi/wifi-utils.h +++ b/src/platform/wifi/wifi-utils.h @@ -34,7 +34,7 @@ WifiData *wifi_utils_init (int ifindex, gboolean check_scan); int wifi_utils_get_ifindex (WifiData *data); -void wifi_utils_unref (WifiData *data); +void wifi_utils_deinit (WifiData *data); NMDeviceWifiCapabilities wifi_utils_get_caps (WifiData *data); diff --git a/src/ppp/meson.build b/src/ppp/meson.build deleted file mode 100644 index 20edb9d0..00000000 --- a/src/ppp/meson.build +++ /dev/null @@ -1,41 +0,0 @@ -name = 'nm-pppd-plugin' - -deps = [ - dl_dep, - nm_core_dep -] - -nm_pppd_plugin = shared_module( - name, - name_prefix: '', - sources: name + '.c', - include_directories: src_inc, - dependencies: deps, - c_args: [ - '-DG_LOG_DOMAIN="@0@"'.format(name), - '-DNETWORKMANAGER_COMPILATION=NM_NETWORKMANAGER_COMPILATION_GLIB', - ], - install: true, - install_dir: pppd_plugin_dir -) - -name = 'nm-ppp-plugin' - -deps = [ - nm_dep -] - -linker_script = join_paths(meson.current_source_dir(), 'nm-ppp-plugin.ver') - -core_plugins += shared_module( - name, - sources: 'nm-ppp-manager.c', - dependencies: deps, - c_args: '-DPPPD_PLUGIN_DIR="@0@"'.format(pppd_plugin_dir), - link_args: [ - '-Wl,--version-script,@0@'.format(linker_script), - ], - link_depends: linker_script, - install: true, - install_dir: nm_pkglibdir -) diff --git a/src/ppp/nm-ppp-manager-call.c b/src/ppp/nm-ppp-manager-call.c index ed70f687..ad3307a9 100644 --- a/src/ppp/nm-ppp-manager-call.c +++ b/src/ppp/nm-ppp-manager-call.c @@ -44,9 +44,11 @@ nm_ppp_manager_create (const char *iface, GError **error) GError *error_local = NULL; NMPPPOps *ops; struct stat st; + int errsv; if (G_UNLIKELY (!ppp_ops)) { if (stat (PPP_PLUGIN_PATH, &st) != 0) { + errsv = errno; g_set_error_literal (error, NM_MANAGER_ERROR, NM_MANAGER_ERROR_MISSING_PLUGIN, "the PPP plugin " PPP_PLUGIN_PATH " is not installed"); diff --git a/src/ppp/nm-ppp-manager.c b/src/ppp/nm-ppp-manager.c index 7d1eb408..743f80a2 100644 --- a/src/ppp/nm-ppp-manager.c +++ b/src/ppp/nm-ppp-manager.c @@ -50,12 +50,13 @@ #include "nm-act-request.h" #include "nm-ip4-config.h" #include "nm-ip6-config.h" -#include "nm-dbus-object.h" #include "nm-pppd-plugin.h" #include "nm-ppp-plugin-api.h" #include "nm-ppp-status.h" +#include "introspection/org.freedesktop.NetworkManager.PPP.h" + #define NM_PPPD_PLUGIN PPPD_PLUGIN_DIR "/nm-pppd-plugin.so" static NM_CACHED_QUARK_FCN ("ppp-manager-secret-tries", ppp_manager_secret_tries_quark) @@ -75,7 +76,6 @@ GType nm_ppp_manager_get_type (void); enum { STATE_CHANGED, - IFINDEX_SET, IP4_CONFIG, IP6_CONFIG, STATS, @@ -93,8 +93,6 @@ typedef struct { GPid pid; char *parent_iface; - char *ip_iface; - int ifindex; NMActRequest *act_req; GDBusMethodInvocation *pending_secrets_context; @@ -105,6 +103,7 @@ typedef struct { guint ppp_timeout_handler; /* Monitoring */ + char *ip_iface; int monitor_fd; guint monitor_id; @@ -115,17 +114,17 @@ typedef struct { } NMPPPManagerPrivate; struct _NMPPPManager { - NMDBusObject parent; + NMExportedObject parent; NMPPPManagerPrivate _priv; }; typedef struct { - NMDBusObjectClass parent; + NMExportedObjectClass parent; } NMPPPManagerClass; -G_DEFINE_TYPE (NMPPPManager, nm_ppp_manager, NM_TYPE_DBUS_OBJECT) +G_DEFINE_TYPE (NMPPPManager, nm_ppp_manager, NM_TYPE_EXPORTED_OBJECT) -#define NM_PPP_MANAGER_GET_PRIVATE(self) _NM_GET_PRIVATE (self, NMPPPManager, NM_IS_PPP_MANAGER, NMDBusObject) +#define NM_PPP_MANAGER_GET_PRIVATE(self) _NM_GET_PRIVATE (self, NMPPPManager, NM_IS_PPP_MANAGER) /*****************************************************************************/ @@ -175,28 +174,24 @@ monitor_cb (gpointer user_data) { NMPPPManager *manager = NM_PPP_MANAGER (user_data); NMPPPManagerPrivate *priv = NM_PPP_MANAGER_GET_PRIVATE (manager); - const char *ifname; + struct ifreq req; + struct ppp_stats stats; - ifname = nm_platform_link_get_name (NM_PLATFORM_GET, priv->ifindex); + memset (&req, 0, sizeof (req)); + memset (&stats, 0, sizeof (stats)); + req.ifr_data = (caddr_t) &stats; - if (ifname) { - struct ppp_stats stats = { }; - struct ifreq req = { - .ifr_data = (caddr_t) &stats, - }; - - nm_utils_ifname_cpy (req.ifr_name, ifname); - if (ioctl (priv->monitor_fd, SIOCGPPPSTATS, &req) < 0) { - if (errno != ENODEV) - _LOGW ("could not read ppp stats: %s", strerror (errno)); - } else { - g_signal_emit (manager, signals[STATS], 0, - (guint) stats.p.ppp_ibytes, - (guint) stats.p.ppp_obytes); - } + strncpy (req.ifr_name, priv->ip_iface, sizeof (req.ifr_name)); + if (ioctl (priv->monitor_fd, SIOCGPPPSTATS, &req) < 0) { + if (errno != ENODEV) + _LOGW ("could not read ppp stats: %s", strerror (errno)); + } else { + g_signal_emit (manager, signals[STATS], 0, + (guint) stats.p.ppp_ibytes, + (guint) stats.p.ppp_obytes); } - return G_SOURCE_CONTINUE; + return TRUE; } static void @@ -331,27 +326,20 @@ ppp_secrets_cb (NMActRequest *req, * against libnm just to parse this. So instead, let's just send what * it needs. */ - g_dbus_method_invocation_return_value (priv->pending_secrets_context, - g_variant_new ("(ss)", - username ?: "", - password ?: "")); + g_dbus_method_invocation_return_value ( + priv->pending_secrets_context, + g_variant_new ("(ss)", username ? username : "", password ? password : "")); -out: + out: priv->pending_secrets_context = NULL; priv->secrets_id = NULL; priv->secrets_setting_name = NULL; } static void -impl_ppp_manager_need_secrets (NMDBusObject *obj, - const NMDBusInterfaceInfoExtended *interface_info, - const NMDBusMethodInfoExtended *method_info, - GDBusConnection *connection, - const char *sender, - GDBusMethodInvocation *invocation, - GVariant *parameters) +impl_ppp_manager_need_secrets (NMPPPManager *manager, + GDBusMethodInvocation *context) { - NMPPPManager *manager = NM_PPP_MANAGER (obj); NMPPPManagerPrivate *priv = NM_PPP_MANAGER_GET_PRIVATE (manager); NMConnection *applied_connection; const char *username = NULL; @@ -370,7 +358,7 @@ impl_ppp_manager_need_secrets (NMDBusObject *obj, /* Use existing secrets from the connection */ if (extract_details_from_connection (applied_connection, NULL, &username, &password, &error)) { /* Send existing secrets to the PPP plugin */ - priv->pending_secrets_context = invocation; + priv->pending_secrets_context = context; ppp_secrets_cb (priv->act_req, priv->secrets_id, NULL, NULL, manager); } else { _LOGW ("%s", error->message); @@ -395,85 +383,39 @@ impl_ppp_manager_need_secrets (NMDBusObject *obj, ppp_secrets_cb, manager); g_object_set_qdata (G_OBJECT (applied_connection), ppp_manager_secret_tries_quark (), GUINT_TO_POINTER (++tries)); - priv->pending_secrets_context = invocation; + priv->pending_secrets_context = context; if (hints) g_ptr_array_free (hints, TRUE); } static void -impl_ppp_manager_set_state (NMDBusObject *obj, - const NMDBusInterfaceInfoExtended *interface_info, - const NMDBusMethodInfoExtended *method_info, - GDBusConnection *connection, - const char *sender, - GDBusMethodInvocation *invocation, - GVariant *parameters) +impl_ppp_manager_set_state (NMPPPManager *manager, + GDBusMethodInvocation *context, + guint32 state) { - NMPPPManager *manager = NM_PPP_MANAGER (obj); - guint32 state; - - g_variant_get (parameters, "(u)", &state); g_signal_emit (manager, signals[STATE_CHANGED], 0, (guint) state); - g_dbus_method_invocation_return_value (invocation, NULL); -} -static void -impl_ppp_manager_set_ifindex (NMDBusObject *obj, - const NMDBusInterfaceInfoExtended *interface_info, - const NMDBusMethodInfoExtended *method_info, - GDBusConnection *connection, - const char *sender, - GDBusMethodInvocation *invocation, - GVariant *parameters) -{ - NMPPPManager *manager = NM_PPP_MANAGER (obj); - NMPPPManagerPrivate *priv = NM_PPP_MANAGER_GET_PRIVATE (manager); - const NMPlatformLink *plink = NULL; - nm_auto_nmpobj const NMPObject *obj_keep_alive = NULL; - gint32 ifindex; - - g_variant_get (parameters, "(i)", &ifindex); - - _LOGD ("set-ifindex %d", (int) ifindex); - - if (priv->ifindex >= 0) { - _LOGW ("can't change the ifindex from %d to %d", priv->ifindex, (int) ifindex); - return; - } - - if (ifindex > 0) { - plink = nm_platform_link_get (NM_PLATFORM_GET, ifindex); - if (!plink) { - nm_platform_process_events (NM_PLATFORM_GET); - plink = nm_platform_link_get (NM_PLATFORM_GET, ifindex); - } - } - - if (!plink) { - _LOGW ("unknown interface with ifindex %d", ifindex); - ifindex = 0; - } - - priv->ifindex = ifindex; - - obj_keep_alive = nmp_object_ref (NMP_OBJECT_UP_CAST (plink)); - - g_signal_emit (manager, signals[IFINDEX_SET], 0, ifindex, plink->name); - g_dbus_method_invocation_return_value (invocation, NULL); + g_dbus_method_invocation_return_value (context, NULL); } static gboolean set_ip_config_common (NMPPPManager *self, GVariant *config_dict, + const char *iface_prop, guint32 *out_mtu) { NMPPPManagerPrivate *priv = NM_PPP_MANAGER_GET_PRIVATE (self); NMConnection *applied_connection; NMSettingPpp *s_ppp; + const char *iface; - if (priv->ifindex <= 0) + if (!g_variant_lookup (config_dict, iface_prop, "&s", &iface)) { + _LOGE ("no interface received!"); return FALSE; + } + if (priv->ip_iface == NULL) + priv->ip_iface = g_strdup (iface); /* Got successful IP config; obviously the secrets worked */ applied_connection = nm_act_request_get_applied_connection (priv->act_req); @@ -490,32 +432,29 @@ set_ip_config_common (NMPPPManager *self, } static void -impl_ppp_manager_set_ip4_config (NMDBusObject *obj, - const NMDBusInterfaceInfoExtended *interface_info, - const NMDBusMethodInfoExtended *method_info, - GDBusConnection *connection, - const char *sender, - GDBusMethodInvocation *invocation, - GVariant *parameters) +impl_ppp_manager_set_ip4_config (NMPPPManager *manager, + GDBusMethodInvocation *context, + GVariant *config_dict) { - NMPPPManager *manager = NM_PPP_MANAGER (obj); NMPPPManagerPrivate *priv = NM_PPP_MANAGER_GET_PRIVATE (manager); gs_unref_object NMIP4Config *config = NULL; NMPlatformIP4Address address; guint32 u32, mtu; GVariantIter *iter; - gs_unref_variant GVariant *config_dict = NULL; + int ifindex; _LOGI ("(IPv4 Config Get) reply received."); - g_variant_get (parameters, "(@a{sv})", &config_dict); - nm_clear_g_source (&priv->ppp_timeout_handler); - if (!set_ip_config_common (manager, config_dict, &mtu)) + if (!set_ip_config_common (manager, config_dict, NM_PPP_IP4_CONFIG_INTERFACE, &mtu)) goto out; - config = nm_ip4_config_new (nm_platform_get_multi_idx (NM_PLATFORM_GET), priv->ifindex); + ifindex = nm_platform_link_get_ifindex (NM_PLATFORM_GET, priv->ip_iface); + if (ifindex <= 0) + goto out; + + config = nm_ip4_config_new (nm_platform_get_multi_idx (NM_PLATFORM_GET), ifindex); if (mtu) nm_ip4_config_set_mtu (config, mtu, NM_IP_CONFIG_SOURCE_PPP); @@ -528,7 +467,7 @@ impl_ppp_manager_set_ip4_config (NMDBusObject *obj, if (g_variant_lookup (config_dict, NM_PPP_IP4_CONFIG_GATEWAY, "u", &u32)) { const NMPlatformIP4Route r = { - .ifindex = priv->ifindex, + .ifindex = ifindex, .rt_source = NM_IP_CONFIG_SOURCE_PPP, .gateway = u32, .table_coerced = nm_platform_route_table_coerce (priv->ip4_route_table), @@ -564,10 +503,10 @@ impl_ppp_manager_set_ip4_config (NMDBusObject *obj, } /* Push the IP4 config up to the device */ - g_signal_emit (manager, signals[IP4_CONFIG], 0, config); + g_signal_emit (manager, signals[IP4_CONFIG], 0, priv->ip_iface, config); out: - g_dbus_method_invocation_return_value (invocation, NULL); + g_dbus_method_invocation_return_value (context, NULL); } /* Converts the named Interface Identifier item to an IPv6 LL address and @@ -600,40 +539,37 @@ iid_value_to_ll6_addr (GVariant *dict, } static void -impl_ppp_manager_set_ip6_config (NMDBusObject *obj, - const NMDBusInterfaceInfoExtended *interface_info, - const NMDBusMethodInfoExtended *method_info, - GDBusConnection *connection, - const char *sender, - GDBusMethodInvocation *invocation, - GVariant *parameters) +impl_ppp_manager_set_ip6_config (NMPPPManager *manager, + GDBusMethodInvocation *context, + GVariant *config_dict) { - NMPPPManager *manager = NM_PPP_MANAGER (obj); NMPPPManagerPrivate *priv = NM_PPP_MANAGER_GET_PRIVATE (manager); gs_unref_object NMIP6Config *config = NULL; NMPlatformIP6Address addr; struct in6_addr a; NMUtilsIPv6IfaceId iid = NM_UTILS_IPV6_IFACE_ID_INIT; gboolean has_peer = FALSE; - gs_unref_variant GVariant *config_dict = NULL; + int ifindex; _LOGI ("(IPv6 Config Get) reply received."); - g_variant_get (parameters, "(@a{sv})", &config_dict); - nm_clear_g_source (&priv->ppp_timeout_handler); - if (!set_ip_config_common (manager, config_dict, NULL)) + if (!set_ip_config_common (manager, config_dict, NM_PPP_IP6_CONFIG_INTERFACE, NULL)) goto out; - config = nm_ip6_config_new (nm_platform_get_multi_idx (NM_PLATFORM_GET), priv->ifindex); + ifindex = nm_platform_link_get_ifindex (NM_PLATFORM_GET, priv->ip_iface); + if (ifindex <= 0) + goto out; + + config = nm_ip6_config_new (nm_platform_get_multi_idx (NM_PLATFORM_GET), ifindex); memset (&addr, 0, sizeof (addr)); addr.plen = 64; if (iid_value_to_ll6_addr (config_dict, NM_PPP_IP6_CONFIG_PEER_IID, &a, NULL)) { const NMPlatformIP6Route r = { - .ifindex = priv->ifindex, + .ifindex = ifindex, .rt_source = NM_IP_CONFIG_SOURCE_PPP, .gateway = a, .table_coerced = nm_platform_route_table_coerce (priv->ip6_route_table), @@ -651,12 +587,12 @@ impl_ppp_manager_set_ip6_config (NMDBusObject *obj, nm_ip6_config_add_address (config, &addr); /* Push the IPv6 config and interface identifier up to the device */ - g_signal_emit (manager, signals[IP6_CONFIG], 0, &iid, config); + g_signal_emit (manager, signals[IP6_CONFIG], 0, priv->ip_iface, &iid, config); } else _LOGE ("invalid IPv6 address received!"); out: - g_dbus_method_invocation_return_value (invocation, NULL); + g_dbus_method_invocation_return_value (context, NULL); } /*****************************************************************************/ @@ -963,7 +899,7 @@ create_pppd_cmd_line (NMPPPManager *self, nm_cmd_line_add_int (cmd, 0); nm_cmd_line_add_string (cmd, "ipparam"); - nm_cmd_line_add_string (cmd, nm_dbus_object_get_path (NM_DBUS_OBJECT (self))); + nm_cmd_line_add_string (cmd, nm_exported_object_get_path (NM_EXPORTED_OBJECT (self))); nm_cmd_line_add_string (cmd, "plugin"); nm_cmd_line_add_string (cmd, NM_PPPD_PLUGIN); @@ -1042,7 +978,7 @@ _ppp_manager_start (NMPPPManager *manager, return FALSE; #endif - nm_dbus_object_export (NM_DBUS_OBJECT (manager)); + nm_exported_object_export (NM_EXPORTED_OBJECT (manager)); priv->pid = 0; @@ -1116,7 +1052,7 @@ out: nm_cmd_line_destroy (ppp_cmd); if (priv->pid <= 0) - nm_dbus_object_unexport (NM_DBUS_OBJECT (manager)); + nm_exported_object_unexport (NM_EXPORTED_OBJECT (manager)); return priv->pid > 0; } @@ -1220,7 +1156,7 @@ _ppp_manager_stop_async (NMPPPManager *manager, NMPPPManagerPrivate *priv = NM_PPP_MANAGER_GET_PRIVATE (manager); StopContext *ctx; - nm_dbus_object_unexport (NM_DBUS_OBJECT (manager)); + nm_exported_object_unexport (NM_EXPORTED_OBJECT (manager)); ctx = g_slice_new0 (StopContext); ctx->manager = g_object_ref (manager); @@ -1257,10 +1193,10 @@ _ppp_manager_stop_async (NMPPPManager *manager, static void _ppp_manager_stop_sync (NMPPPManager *manager) { - NMDBusObject *dbus = NM_DBUS_OBJECT (manager); + NMExportedObject *exported = NM_EXPORTED_OBJECT (manager); - if (nm_dbus_object_is_exported (dbus)) - nm_dbus_object_unexport (dbus); + if (nm_exported_object_is_exported (exported)) + nm_exported_object_unexport (exported); _ppp_cleanup (manager); _ppp_kill (manager); @@ -1308,7 +1244,6 @@ nm_ppp_manager_init (NMPPPManager *manager) { NMPPPManagerPrivate *priv = NM_PPP_MANAGER_GET_PRIVATE (manager); - priv->ifindex = -1; priv->monitor_fd = -1; priv->ip4_route_table = RT_TABLE_MAIN; priv->ip4_route_metric = 460; @@ -1330,11 +1265,11 @@ static void dispose (GObject *object) { NMPPPManager *self = (NMPPPManager *) object; - NMDBusObject *dbus = NM_DBUS_OBJECT (self); + NMExportedObject *exported = NM_EXPORTED_OBJECT (self); NMPPPManagerPrivate *priv = NM_PPP_MANAGER_GET_PRIVATE (self); - if (nm_dbus_object_is_exported (dbus)) - nm_dbus_object_unexport (dbus); + if (nm_exported_object_is_exported (exported)) + nm_exported_object_unexport (exported); _ppp_cleanup (self); _ppp_kill (self); @@ -1349,78 +1284,24 @@ finalize (GObject *object) { NMPPPManagerPrivate *priv = NM_PPP_MANAGER_GET_PRIVATE ((NMPPPManager *) object); + g_free (priv->ip_iface); g_free (priv->parent_iface); G_OBJECT_CLASS (nm_ppp_manager_parent_class)->finalize (object); } -static const NMDBusInterfaceInfoExtended interface_info_ppp = { - .parent = NM_DEFINE_GDBUS_INTERFACE_INFO_INIT ( - NM_DBUS_INTERFACE_PPP, - .methods = NM_DEFINE_GDBUS_METHOD_INFOS ( - NM_DEFINE_DBUS_METHOD_INFO_EXTENDED ( - NM_DEFINE_GDBUS_METHOD_INFO_INIT ( - "NeedSecrets", - .out_args = NM_DEFINE_GDBUS_ARG_INFOS ( - NM_DEFINE_GDBUS_ARG_INFO ("username", "s"), - NM_DEFINE_GDBUS_ARG_INFO ("password", "s"), - ), - ), - .handle = impl_ppp_manager_need_secrets, - ), - NM_DEFINE_DBUS_METHOD_INFO_EXTENDED ( - NM_DEFINE_GDBUS_METHOD_INFO_INIT ( - "SetIp4Config", - .in_args = NM_DEFINE_GDBUS_ARG_INFOS ( - NM_DEFINE_GDBUS_ARG_INFO ("config", "a{sv}"), - ), - ), - .handle = impl_ppp_manager_set_ip4_config, - ), - NM_DEFINE_DBUS_METHOD_INFO_EXTENDED ( - NM_DEFINE_GDBUS_METHOD_INFO_INIT ( - "SetIp6Config", - .in_args = NM_DEFINE_GDBUS_ARG_INFOS ( - NM_DEFINE_GDBUS_ARG_INFO ("config", "a{sv}"), - ), - ), - .handle = impl_ppp_manager_set_ip6_config, - ), - NM_DEFINE_DBUS_METHOD_INFO_EXTENDED ( - NM_DEFINE_GDBUS_METHOD_INFO_INIT ( - "SetState", - .in_args = NM_DEFINE_GDBUS_ARG_INFOS ( - NM_DEFINE_GDBUS_ARG_INFO ("state", "u"), - ), - ), - .handle = impl_ppp_manager_set_state, - ), - NM_DEFINE_DBUS_METHOD_INFO_EXTENDED ( - NM_DEFINE_GDBUS_METHOD_INFO_INIT ( - "SetIfindex", - .in_args = NM_DEFINE_GDBUS_ARG_INFOS ( - NM_DEFINE_GDBUS_ARG_INFO ("ifindex", "i"), - ), - ), - .handle = impl_ppp_manager_set_ifindex, - ), - ), - ), -}; - static void nm_ppp_manager_class_init (NMPPPManagerClass *manager_class) { GObjectClass *object_class = G_OBJECT_CLASS (manager_class); - NMDBusObjectClass *dbus_object_class = NM_DBUS_OBJECT_CLASS (manager_class); + NMExportedObjectClass *exported_object_class = NM_EXPORTED_OBJECT_CLASS (manager_class); object_class->dispose = dispose; object_class->finalize = finalize; object_class->get_property = get_property; object_class->set_property = set_property; - dbus_object_class->export_path = NM_DBUS_EXPORT_PATH_NUMBERED (NM_DBUS_PATH"/PPP"); - dbus_object_class->interface_infos = NM_DBUS_INTERFACE_INFOS (&interface_info_ppp); + exported_object_class->export_path = NM_EXPORT_PATH_NUMBERED (NM_DBUS_PATH"/PPP"); obj_properties[PROP_PARENT_IFACE] = g_param_spec_string (NM_PPP_MANAGER_PARENT_IFACE, "", "", @@ -1439,23 +1320,14 @@ nm_ppp_manager_class_init (NMPPPManagerClass *manager_class) G_TYPE_NONE, 1, G_TYPE_UINT); - signals[IFINDEX_SET] = - g_signal_new (NM_PPP_MANAGER_SIGNAL_IFINDEX_SET, - G_OBJECT_CLASS_TYPE (object_class), - G_SIGNAL_RUN_FIRST, - 0, - NULL, NULL, NULL, - G_TYPE_NONE, 2, - G_TYPE_INT, - G_TYPE_STRING); - signals[IP4_CONFIG] = g_signal_new (NM_PPP_MANAGER_SIGNAL_IP4_CONFIG, G_OBJECT_CLASS_TYPE (object_class), G_SIGNAL_RUN_FIRST, 0, NULL, NULL, NULL, - G_TYPE_NONE, 1, + G_TYPE_NONE, 2, + G_TYPE_STRING, G_TYPE_OBJECT); signals[IP6_CONFIG] = @@ -1464,9 +1336,7 @@ nm_ppp_manager_class_init (NMPPPManagerClass *manager_class) G_SIGNAL_RUN_FIRST, 0, NULL, NULL, NULL, - G_TYPE_NONE, 2, - G_TYPE_POINTER, - G_TYPE_OBJECT); + G_TYPE_NONE, 3, G_TYPE_STRING, G_TYPE_POINTER, G_TYPE_OBJECT); signals[STATS] = g_signal_new (NM_PPP_MANAGER_SIGNAL_STATS, @@ -1477,6 +1347,14 @@ nm_ppp_manager_class_init (NMPPPManagerClass *manager_class) G_TYPE_NONE, 2, G_TYPE_UINT /*guint32 in_bytes*/, G_TYPE_UINT /*guint32 out_bytes*/); + + nm_exported_object_class_add_interface (NM_EXPORTED_OBJECT_CLASS (manager_class), + NMDBUS_TYPE_PPP_MANAGER_SKELETON, + "NeedSecrets", impl_ppp_manager_need_secrets, + "SetIp4Config", impl_ppp_manager_set_ip4_config, + "SetIp6Config", impl_ppp_manager_set_ip6_config, + "SetState", impl_ppp_manager_set_state, + NULL); } NMPPPOps ppp_ops = { diff --git a/src/ppp/nm-ppp-manager.h b/src/ppp/nm-ppp-manager.h index 5457726e..35fb1b60 100644 --- a/src/ppp/nm-ppp-manager.h +++ b/src/ppp/nm-ppp-manager.h @@ -25,7 +25,6 @@ #define NM_PPP_MANAGER_PARENT_IFACE "parent-iface" #define NM_PPP_MANAGER_SIGNAL_STATE_CHANGED "state-changed" -#define NM_PPP_MANAGER_SIGNAL_IFINDEX_SET "ifindex-set" #define NM_PPP_MANAGER_SIGNAL_IP4_CONFIG "ip4-config" #define NM_PPP_MANAGER_SIGNAL_IP6_CONFIG "ip6-config" #define NM_PPP_MANAGER_SIGNAL_STATS "stats" diff --git a/src/ppp/nm-pppd-plugin.c b/src/ppp/nm-pppd-plugin.c index 989f7433..0ac8f907 100644 --- a/src/ppp/nm-pppd-plugin.c +++ b/src/ppp/nm-pppd-plugin.c @@ -28,7 +28,6 @@ #include <pppd/ipcp.h> #include <sys/socket.h> #include <netinet/in.h> -#include <net/if.h> #include <arpa/inet.h> #include <dlfcn.h> @@ -37,9 +36,7 @@ #include <pppd/ipv6cp.h> #include "nm-default.h" - #include "nm-dbus-interface.h" - #include "nm-pppd-plugin.h" #include "nm-ppp-status.h" @@ -53,9 +50,7 @@ static void nm_phasechange (void *data, int arg) { NMPPPStatus ppp_status = NM_PPP_STATUS_UNKNOWN; - char new_name[IF_NAMESIZE]; char *ppp_phase; - int index; g_return_if_fail (G_IS_DBUS_PROXY (proxy)); @@ -131,25 +126,6 @@ nm_phasechange (void *data, int arg) NULL, NULL, NULL); } - - if (ppp_status == PHASE_RUNNING) { - index = if_nametoindex (ifname); - /* Make a sync call to ensure that when the call - * terminates the interface already has its final - * name. */ - g_dbus_proxy_call_sync (proxy, - "SetIfindex", - g_variant_new ("(i)", index), - G_DBUS_CALL_FLAGS_NONE, - 25000, - NULL, NULL); - /* Update the name in pppd if NM changed it */ - if ( if_indextoname (index, new_name) - && !nm_streq0 (ifname, new_name)) { - g_message ("nm-ppp-plugin: interface name changed from '%s' to '%s'", ifname, new_name); - strncpy (ifname, new_name, IF_NAMESIZE); - } - } } static void @@ -172,9 +148,6 @@ nm_ip_up (void *data, int arg) g_variant_builder_init (&builder, G_VARIANT_TYPE_VARDICT); - /* Keep sending the interface name to be backwards compatible - * with older versions of NM during a package upgrade, where - * NM is not restarted and the pppd plugin was not loaded. */ g_variant_builder_add (&builder, "{sv}", NM_PPP_IP4_CONFIG_INTERFACE, g_variant_new_string (ifname)); @@ -269,9 +242,6 @@ nm_ip6_up (void *data, int arg) g_message ("nm-ppp-plugin: (%s): ip6-up event", __func__); g_variant_builder_init (&builder, G_VARIANT_TYPE_VARDICT); - /* Keep sending the interface name to be backwards compatible - * with older versions of NM during a package upgrade, where - * NM is not restarted and the pppd plugin was not loaded. */ g_variant_builder_add (&builder, "{sv}", NM_PPP_IP6_CONFIG_INTERFACE, g_variant_new_string (ifname)); @@ -391,6 +361,8 @@ plugin_init (void) GDBusConnection *bus; GError *err = NULL; + nm_g_type_init (); + g_message ("nm-ppp-plugin: (%s): initializing", __func__); bus = g_bus_get_sync (G_BUS_TYPE_SYSTEM, NULL, &err); diff --git a/src/settings/nm-agent-manager.c b/src/settings/nm-agent-manager.c index 453136e4..a68db47e 100644 --- a/src/settings/nm-agent-manager.c +++ b/src/settings/nm-agent-manager.c @@ -31,12 +31,14 @@ #include "nm-auth-utils.h" #include "nm-setting-vpn.h" #include "nm-auth-manager.h" -#include "nm-dbus-manager.h" +#include "nm-bus-manager.h" #include "nm-session-monitor.h" #include "nm-simple-connection.h" #include "NetworkManagerUtils.h" #include "nm-core-internal.h" -#include "c-list/src/c-list.h" +#include "nm-utils/c-list.h" + +#include "introspection/org.freedesktop.NetworkManager.AgentManager.h" /*****************************************************************************/ @@ -65,15 +67,15 @@ typedef struct { } NMAgentManagerPrivate; struct _NMAgentManager { - NMDBusObject parent; + NMExportedObject parent; NMAgentManagerPrivate _priv; }; struct _NMAgentManagerClass { - NMDBusObjectClass parent; + NMExportedObjectClass parent; }; -G_DEFINE_TYPE (NMAgentManager, nm_agent_manager, NM_TYPE_DBUS_OBJECT) +G_DEFINE_TYPE (NMAgentManager, nm_agent_manager, NM_TYPE_EXPORTED_OBJECT) #define NM_AGENT_MANAGER_GET_PRIVATE(self) _NM_GET_PRIVATE (self, NMAgentManager, NM_IS_AGENT_MANAGER) @@ -360,7 +362,7 @@ agent_register_permissions_done (NMAuthChain *chain, request_add_agent (c_list_entry (iter, Request, lst_request), agent); } - nm_auth_chain_destroy (chain); + nm_auth_chain_unref (chain); } static NMSecretAgent * @@ -390,10 +392,10 @@ agent_disconnected_cb (NMSecretAgent *agent, gpointer user_data) } static void -agent_manager_register_with_capabilities (NMAgentManager *self, - GDBusMethodInvocation *context, - const char *identifier, - guint32 capabilities) +impl_agent_manager_register_with_capabilities (NMAgentManager *self, + GDBusMethodInvocation *context, + const char *identifier, + guint32 capabilities) { NMAgentManagerPrivate *priv = NM_AGENT_MANAGER_GET_PRIVATE (self); NMAuthSubject *subject; @@ -458,56 +460,45 @@ done: } static void -impl_agent_manager_register (NMDBusObject *obj, - const NMDBusInterfaceInfoExtended *interface_info, - const NMDBusMethodInfoExtended *method_info, - GDBusConnection *connection, - const char *sender, - GDBusMethodInvocation *invocation, - GVariant *parameters) +impl_agent_manager_register (NMAgentManager *self, + GDBusMethodInvocation *context, + const char *identifier) { - const char *identifier; - - g_variant_get (parameters, "(&s)", &identifier); - agent_manager_register_with_capabilities (NM_AGENT_MANAGER (obj), invocation, identifier, 0); + impl_agent_manager_register_with_capabilities (self, context, identifier, 0); } static void -impl_agent_manager_register_with_capabilities (NMDBusObject *obj, - const NMDBusInterfaceInfoExtended *interface_info, - const NMDBusMethodInfoExtended *method_info, - GDBusConnection *connection, - const char *sender, - GDBusMethodInvocation *invocation, - GVariant *parameters) +impl_agent_manager_unregister (NMAgentManager *self, + GDBusMethodInvocation *context) { - const char *identifier; - guint32 capabilities; - - g_variant_get (parameters, "(&su)", &identifier, &capabilities); - agent_manager_register_with_capabilities (NM_AGENT_MANAGER (obj), invocation, identifier, capabilities); -} + GError *error = NULL; + char *sender = NULL; -static void -impl_agent_manager_unregister (NMDBusObject *obj, - const NMDBusInterfaceInfoExtended *interface_info, - const NMDBusMethodInfoExtended *method_info, - GDBusConnection *connection, - const char *sender, - GDBusMethodInvocation *invocation, - GVariant *parameters) -{ - NMAgentManager *self = NM_AGENT_MANAGER (obj); + if (!nm_bus_manager_get_caller_info (nm_bus_manager_get (), + context, + &sender, + NULL, + NULL)) { + error = g_error_new_literal (NM_AGENT_MANAGER_ERROR, + NM_AGENT_MANAGER_ERROR_PERMISSION_DENIED, + "Unable to determine request sender."); + goto done; + } + /* Found the agent, unregister and remove it */ if (!remove_agent (self, sender)) { - g_dbus_method_invocation_return_error_literal (invocation, - NM_AGENT_MANAGER_ERROR, - NM_AGENT_MANAGER_ERROR_NOT_REGISTERED, - "Caller is not registered as an Agent"); - return; + error = g_error_new_literal (NM_AGENT_MANAGER_ERROR, + NM_AGENT_MANAGER_ERROR_NOT_REGISTERED, + "Caller is not registered as an Agent"); + goto done; } - g_dbus_method_invocation_return_value (invocation, NULL); + g_dbus_method_invocation_return_value (context, NULL); + +done: + if (error) + g_dbus_method_invocation_take_error (context, error); + g_free (sender); } /*****************************************************************************/ @@ -539,7 +530,7 @@ request_free (Request *req) g_object_unref (req->con.connection); g_free (req->con.path); if (req->con.chain) - nm_auth_chain_destroy (req->con.chain); + nm_auth_chain_unref (req->con.chain); if (req->request_type == REQUEST_TYPE_CON_GET) { g_free (req->con.get.setting_name); g_strfreev (req->con.get.hints); @@ -810,7 +801,7 @@ request_remove_agent (Request *req, NMSecretAgent *agent) case REQUEST_TYPE_CON_DEL: if (req->con.chain) { /* This cancels the pending authorization requests. */ - nm_auth_chain_destroy (req->con.chain); + nm_auth_chain_unref (req->con.chain); req->con.chain = NULL; } break; @@ -1047,7 +1038,7 @@ _con_get_request_start_validated (NMAuthChain *chain, _con_get_request_start_proceed (req, req->con.current_has_modify); } - nm_auth_chain_destroy (chain); + nm_auth_chain_unref (chain); } static void @@ -1541,7 +1532,7 @@ agent_permissions_changed_done (NMAuthChain *chain, nm_secret_agent_add_permission (agent, NM_AUTH_PERMISSION_WIFI_SHARE_PROTECTED, share_protected); nm_secret_agent_add_permission (agent, NM_AUTH_PERMISSION_WIFI_SHARE_OPEN, share_open); - nm_auth_chain_destroy (chain); + nm_auth_chain_unref (chain); } static void @@ -1595,7 +1586,7 @@ constructed (GObject *object) priv->auth_mgr = g_object_ref (nm_auth_manager_get ()); priv->session_monitor = g_object_ref (nm_session_monitor_get ()); - nm_dbus_object_export (NM_DBUS_OBJECT (object)); + nm_exported_object_export (NM_EXPORTED_OBJECT (object)); g_signal_connect (priv->auth_mgr, NM_AUTH_MANAGER_SIGNAL_CHANGED, @@ -1616,7 +1607,7 @@ cancel_more: goto cancel_more; } - g_slist_free_full (priv->chains, (GDestroyNotify) nm_auth_chain_destroy); + g_slist_free_full (priv->chains, (GDestroyNotify) nm_auth_chain_unref); priv->chains = NULL; if (priv->agents) { @@ -1631,64 +1622,20 @@ cancel_more: g_clear_object (&priv->auth_mgr); } - nm_dbus_object_unexport (NM_DBUS_OBJECT (object)); + nm_exported_object_unexport (NM_EXPORTED_OBJECT (object)); g_clear_object (&priv->session_monitor); G_OBJECT_CLASS (nm_agent_manager_parent_class)->dispose (object); } -static const NMDBusInterfaceInfoExtended interface_info_agent_manager = { - .parent = NM_DEFINE_GDBUS_INTERFACE_INFO_INIT ( - NM_DBUS_INTERFACE_AGENT_MANAGER, - .methods = NM_DEFINE_GDBUS_METHOD_INFOS ( - NM_DEFINE_DBUS_METHOD_INFO_EXTENDED ( - NM_DEFINE_GDBUS_METHOD_INFO_INIT ( - "Register", - .in_args = NM_DEFINE_GDBUS_ARG_INFOS ( - NM_DEFINE_GDBUS_ARG_INFO ("identifier", "s"), - ), - ), - .handle = impl_agent_manager_register, - ), - NM_DEFINE_DBUS_METHOD_INFO_EXTENDED ( - NM_DEFINE_GDBUS_METHOD_INFO_INIT ( - "RegisterWithCapabilities", - .in_args = NM_DEFINE_GDBUS_ARG_INFOS ( - NM_DEFINE_GDBUS_ARG_INFO ("identifier", "s"), - NM_DEFINE_GDBUS_ARG_INFO ("capabilities", "u"), - ), - ), - .handle = impl_agent_manager_register_with_capabilities, - ), - NM_DEFINE_DBUS_METHOD_INFO_EXTENDED ( - NM_DEFINE_GDBUS_METHOD_INFO_INIT ( - "RegisterWithCapabilities", - .in_args = NM_DEFINE_GDBUS_ARG_INFOS ( - NM_DEFINE_GDBUS_ARG_INFO ("identifier", "s"), - NM_DEFINE_GDBUS_ARG_INFO ("capabilities", "u"), - ), - ), - .handle = impl_agent_manager_register_with_capabilities, - ), - NM_DEFINE_DBUS_METHOD_INFO_EXTENDED ( - NM_DEFINE_GDBUS_METHOD_INFO_INIT ( - "Unregister", - ), - .handle = impl_agent_manager_unregister, - ), - ), - ), -}; - static void nm_agent_manager_class_init (NMAgentManagerClass *agent_manager_class) { GObjectClass *object_class = G_OBJECT_CLASS (agent_manager_class); - NMDBusObjectClass *dbus_object_class = NM_DBUS_OBJECT_CLASS (agent_manager_class); + NMExportedObjectClass *exported_object_class = NM_EXPORTED_OBJECT_CLASS (agent_manager_class); - dbus_object_class->export_path = NM_DBUS_EXPORT_PATH_STATIC (NM_DBUS_PATH_AGENT_MANAGER); - dbus_object_class->interface_infos = NM_DBUS_INTERFACE_INFOS (&interface_info_agent_manager); + exported_object_class->export_path = NM_DBUS_PATH_AGENT_MANAGER; object_class->constructed = constructed; object_class->dispose = dispose; @@ -1702,4 +1649,11 @@ nm_agent_manager_class_init (NMAgentManagerClass *agent_manager_class) g_cclosure_marshal_VOID__OBJECT, G_TYPE_NONE, 1, G_TYPE_OBJECT); + + nm_exported_object_class_add_interface (NM_EXPORTED_OBJECT_CLASS (agent_manager_class), + NMDBUS_TYPE_AGENT_MANAGER_SKELETON, + "Register", impl_agent_manager_register, + "RegisterWithCapabilities", impl_agent_manager_register_with_capabilities, + "Unregister", impl_agent_manager_unregister, + NULL); } diff --git a/src/settings/nm-agent-manager.h b/src/settings/nm-agent-manager.h index 8c27f26b..f6845818 100644 --- a/src/settings/nm-agent-manager.h +++ b/src/settings/nm-agent-manager.h @@ -23,7 +23,7 @@ #include "nm-connection.h" -#include "nm-dbus-object.h" +#include "nm-exported-object.h" #include "nm-secret-agent.h" #define NM_TYPE_AGENT_MANAGER (nm_agent_manager_get_type ()) diff --git a/src/settings/nm-secret-agent.c b/src/settings/nm-secret-agent.c index af6d7017..192e9877 100644 --- a/src/settings/nm-secret-agent.c +++ b/src/settings/nm-secret-agent.c @@ -26,12 +26,13 @@ #include <pwd.h> #include "nm-dbus-interface.h" -#include "nm-dbus-manager.h" -#include "nm-core-internal.h" +#include "nm-bus-manager.h" #include "nm-auth-subject.h" #include "nm-simple-connection.h" #include "NetworkManagerUtils.h" -#include "c-list/src/c-list.h" +#include "nm-utils/c-list.h" + +#include "introspection/org.freedesktop.NetworkManager.SecretAgent.h" /*****************************************************************************/ @@ -50,8 +51,8 @@ typedef struct { char *dbus_owner; NMSecretAgentCapabilities capabilities; GSList *permissions; - GDBusProxy *proxy; - NMDBusManager *bus_mgr; + NMDBusSecretAgent *proxy; + NMBusManager *bus_mgr; GDBusConnection *connection; CList requests; gulong on_disconnected_id; @@ -299,7 +300,7 @@ nm_secret_agent_add_permission (NMSecretAgent *agent, * @permission: The name of the permission to check for * * Returns whether or not the agent has the given permission. - * + * * Returns: %TRUE if the agent has the given permission, %FALSE if it does not * or if the permission was not previous recorded with * nm_secret_agent_add_permission(). @@ -335,17 +336,11 @@ get_callback (GObject *proxy, if (request_check_return (r)) { NMSecretAgentPrivate *priv = NM_SECRET_AGENT_GET_PRIVATE (r->agent); gs_free_error GError *error = NULL; - gs_unref_variant GVariant *ret = NULL; gs_unref_variant GVariant *secrets = NULL; - ret = _nm_dbus_proxy_call_finish (priv->proxy, result, G_VARIANT_TYPE ("(a{sa{sv}})"), &error); - if (!ret) + nmdbus_secret_agent_call_get_secrets_finish (priv->proxy, &secrets, result, &error); + if (error) g_dbus_error_strip_remote_error (error); - else { - g_variant_get (ret, - "(@a{sa{sv}})", - &secrets); - } r->callback (r->agent, r, secrets, error, r->callback_data); } @@ -363,6 +358,7 @@ nm_secret_agent_get_secrets (NMSecretAgent *self, gpointer callback_data) { NMSecretAgentPrivate *priv; + static const char *no_hints[] = { NULL }; GVariant *dict; NMSecretAgentCallId *r; @@ -383,20 +379,16 @@ nm_secret_agent_get_secrets (NMSecretAgent *self, r = request_new (self, "GetSecrets", path, setting_name, callback, callback_data); r->is_get_secrets = TRUE; - g_dbus_proxy_call (priv->proxy, - "GetSecrets", - g_variant_new ("(@a{sa{sv}}os^asu)", - dict, - path, - setting_name, - hints ?: NM_PTRARRAY_EMPTY (const char *), - (guint32) flags), - G_DBUS_CALL_FLAGS_NONE, - 120000, - r->cancellable, - get_callback, - r); - + /* Increase the timeout only for this call */ + g_dbus_proxy_set_default_timeout (G_DBUS_PROXY (priv->proxy), 120000); + nmdbus_secret_agent_call_get_secrets (priv->proxy, + dict, + path, + setting_name, + hints ? hints : no_hints, + flags, + r->cancellable, + get_callback, r); g_dbus_proxy_set_default_timeout (G_DBUS_PROXY (priv->proxy), -1); return r; @@ -407,16 +399,17 @@ nm_secret_agent_get_secrets (NMSecretAgent *self, static void cancel_done (GObject *proxy, GAsyncResult *result, gpointer user_data) { - gs_free char *description = user_data; - gs_free_error GError *error = NULL; - gs_unref_variant GVariant *ret = NULL; + char *description = user_data; + GError *error = NULL; - ret = _nm_dbus_proxy_call_finish (G_DBUS_PROXY (proxy), result, G_VARIANT_TYPE ("()"), &error); - if (!ret) { + if (!nmdbus_secret_agent_call_cancel_get_secrets_finish (NMDBUS_SECRET_AGENT (proxy), result, &error)) { nm_log_dbg (LOGD_AGENTS, "%s%s%s: agent failed to cancel secrets: %s", NM_PRINT_FMT_QUOTED (description, "(", description, ")", "???"), error->message); + g_clear_error (&error); } + + g_free (description); } static void @@ -433,16 +426,11 @@ do_cancel_secrets (NMSecretAgent *self, NMSecretAgentCallId *r, gboolean disposi if ( r->is_get_secrets && priv->proxy) { /* for GetSecrets call, we must cancel the request. */ - g_dbus_proxy_call (G_DBUS_PROXY (priv->proxy), - "CancelGetSecrets", - g_variant_new ("(os)", - r->path, - r->setting_name), - G_DBUS_CALL_FLAGS_NONE, - -1, - NULL, - cancel_done, - g_strdup (nm_secret_agent_get_description (self))); + nmdbus_secret_agent_call_cancel_get_secrets (priv->proxy, + r->path, r->setting_name, + NULL, + cancel_done, + g_strdup (nm_secret_agent_get_description (self))); } cancellable = r->cancellable; @@ -506,11 +494,11 @@ agent_save_cb (GObject *proxy, NMSecretAgentCallId *r = user_data; if (request_check_return (r)) { + NMSecretAgentPrivate *priv = NM_SECRET_AGENT_GET_PRIVATE (r->agent); gs_free_error GError *error = NULL; - gs_unref_variant GVariant *ret = NULL; - ret = _nm_dbus_proxy_call_finish (G_DBUS_PROXY (proxy), result, G_VARIANT_TYPE ("()"), &error); - if (!ret) + nmdbus_secret_agent_call_save_secrets_finish (priv->proxy, result, &error); + if (error) g_dbus_error_strip_remote_error (error); r->callback (r->agent, r, NULL, error, r->callback_data); } @@ -539,16 +527,11 @@ nm_secret_agent_save_secrets (NMSecretAgent *self, dict = nm_connection_to_dbus (connection, NM_CONNECTION_SERIALIZE_ALL); r = request_new (self, "SaveSecrets", path, NULL, callback, callback_data); - g_dbus_proxy_call (priv->proxy, - "SaveSecrets", - g_variant_new ("(@a{sa{sv}}o)", - dict, - path), - G_DBUS_CALL_FLAGS_NONE, - -1, - NULL, /* cancelling the request does *not* cancel the D-Bus call. */ - agent_save_cb, - r); + nmdbus_secret_agent_call_save_secrets (priv->proxy, + dict, + path, + NULL, /* cancelling the request does *not* cancel the D-Bus call. */ + agent_save_cb, r); return r; } @@ -563,11 +546,11 @@ agent_delete_cb (GObject *proxy, NMSecretAgentCallId *r = user_data; if (request_check_return (r)) { + NMSecretAgentPrivate *priv = NM_SECRET_AGENT_GET_PRIVATE (r->agent); gs_free_error GError *error = NULL; - gs_unref_variant GVariant *ret = NULL; - ret = _nm_dbus_proxy_call_finish (G_DBUS_PROXY (proxy), result, G_VARIANT_TYPE ("()"), &error); - if (!ret) + nmdbus_secret_agent_call_delete_secrets_finish (priv->proxy, result, &error); + if (error) g_dbus_error_strip_remote_error (error); r->callback (r->agent, r, NULL, error, r->callback_data); } @@ -596,16 +579,12 @@ nm_secret_agent_delete_secrets (NMSecretAgent *self, dict = nm_connection_to_dbus (connection, NM_CONNECTION_SERIALIZE_NO_SECRETS); r = request_new (self, "DeleteSecrets", path, NULL, callback, callback_data); - g_dbus_proxy_call (priv->proxy, - "DeleteSecrets", - g_variant_new ("(@a{sa{sv}}o)", - dict, - path), - G_DBUS_CALL_FLAGS_NONE, - -1, - NULL, /* cancelling the request does *not* cancel the D-Bus call. */ - agent_delete_cb, - r); + nmdbus_secret_agent_call_delete_secrets (priv->proxy, + dict, + path, + NULL, /* cancelling the request does *not* cancel the D-Bus call. */ + agent_delete_cb, r); + return r; } @@ -631,7 +610,7 @@ _on_disconnected_cleanup (NMSecretAgentPrivate *priv) } static void -_on_disconnected_private_connection (NMDBusManager *mgr, +_on_disconnected_private_connection (NMBusManager *mgr, GDBusConnection *connection, NMSecretAgent *self) { @@ -687,6 +666,7 @@ nm_secret_agent_new (GDBusMethodInvocation *context, NMSecretAgentPrivate *priv; const char *dbus_owner; struct passwd *pw; + GDBusProxy *proxy; char *owner_username = NULL; char *description = NULL; char buf_subject[64]; @@ -715,9 +695,9 @@ nm_secret_agent_new (GDBusMethodInvocation *context, priv = NM_SECRET_AGENT_GET_PRIVATE (self); - priv->bus_mgr = g_object_ref (nm_dbus_manager_get ()); + priv->bus_mgr = g_object_ref (nm_bus_manager_get ()); priv->connection = g_object_ref (connection); - priv->connection_is_private = !!nm_dbus_manager_connection_get_private_name (priv->bus_mgr, connection); + priv->connection_is_private = !!nm_bus_manager_connection_get_private_name (priv->bus_mgr, connection); _LOGt ("constructed: %s, owner=%s%s%s (%s), private-connection=%d, unique-name=%s%s%s, capabilities=%s", (description = _create_description (dbus_owner, identifier, uid)), @@ -734,18 +714,20 @@ nm_secret_agent_new (GDBusMethodInvocation *context, priv->capabilities = capabilities; priv->subject = g_object_ref (subject); - priv->proxy = nm_dbus_manager_new_proxy (priv->bus_mgr, - priv->connection, - G_TYPE_DBUS_PROXY, - priv->dbus_owner, - NM_DBUS_PATH_SECRET_AGENT, - NM_DBUS_INTERFACE_SECRET_AGENT); + proxy = nm_bus_manager_new_proxy (priv->bus_mgr, + priv->connection, + NMDBUS_TYPE_SECRET_AGENT_PROXY, + priv->dbus_owner, + NM_DBUS_PATH_SECRET_AGENT, + NM_DBUS_INTERFACE_SECRET_AGENT); + g_assert (proxy); + priv->proxy = NMDBUS_SECRET_AGENT (proxy); /* we cannot subscribe to notify::g-name-owner because that doesn't work * for unique names and it doesn't work for private connections. */ if (priv->connection_is_private) { priv->on_disconnected_id = g_signal_connect (priv->bus_mgr, - NM_DBUS_MANAGER_PRIVATE_CONNECTION_DISCONNECTED, + NM_BUS_MANAGER_PRIVATE_CONNECTION_DISCONNECTED, G_CALLBACK (_on_disconnected_private_connection), self); } else { diff --git a/src/settings/nm-settings-connection.c b/src/settings/nm-settings-connection.c index 0b998372..58626372 100644 --- a/src/settings/nm-settings-connection.c +++ b/src/settings/nm-settings-connection.c @@ -25,14 +25,13 @@ #include <string.h> -#include "c-list/src/c-list.h" +#include "nm-utils/c-list.h" #include "nm-common-macros.h" #include "nm-config.h" #include "nm-config-data.h" #include "nm-dbus-interface.h" #include "nm-session-monitor.h" -#include "nm-auth-manager.h" #include "nm-auth-utils.h" #include "nm-auth-subject.h" #include "nm-agent-manager.h" @@ -40,6 +39,8 @@ #include "nm-core-internal.h" #include "nm-audit-manager.h" +#include "introspection/org.freedesktop.NetworkManager.Settings.Connection.h" + #define SETTINGS_TIMESTAMPS_FILE NMSTATEDIR "/timestamps" #define SETTINGS_SEEN_BSSIDS_FILE NMSTATEDIR "/seen-bssids" @@ -59,9 +60,9 @@ NM_GOBJECT_PROPERTIES_DEFINE (NMSettingsConnection, ); enum { + UPDATED, REMOVED, UPDATED_INTERNAL, - FLAGS_CHANGED, LAST_SIGNAL }; @@ -73,7 +74,7 @@ typedef struct _NMSettingsConnectionPrivate { NMSessionMonitor *session_monitor; gulong session_changed_id; - NMSettingsConnectionIntFlags flags:5; + NMSettingsConnectionFlags flags:5; bool removed:1; bool ready:1; @@ -82,8 +83,7 @@ typedef struct _NMSettingsConnectionPrivate { NMSettingsAutoconnectBlockedReason autoconnect_blocked_reason:4; - /* List of pending authentication requests */ - CList auth_lst_head; + GSList *pending_auths; /* List of pending authentication requests */ CList call_ids_lst_head; /* in-progress secrets requests */ @@ -115,7 +115,7 @@ typedef struct _NMSettingsConnectionPrivate { } NMSettingsConnectionPrivate; -G_DEFINE_TYPE_WITH_CODE (NMSettingsConnection, nm_settings_connection, NM_TYPE_DBUS_OBJECT, +G_DEFINE_TYPE_WITH_CODE (NMSettingsConnection, nm_settings_connection, NM_TYPE_EXPORTED_OBJECT, G_IMPLEMENT_INTERFACE (NM_TYPE_CONNECTION, nm_settings_connection_connection_interface_init) ) @@ -146,9 +146,12 @@ G_DEFINE_TYPE_WITH_CODE (NMSettingsConnection, nm_settings_connection, NM_TYPE_D /*****************************************************************************/ -static const GDBusSignalInfo signal_info_updated; -static const GDBusSignalInfo signal_info_removed; -static const NMDBusInterfaceInfoExtended interface_info_settings_connection; +static void +_emit_updated (NMSettingsConnection *self, gboolean by_user) +{ + g_signal_emit (self, signals[UPDATED], 0); + g_signal_emit (self, signals[UPDATED_INTERNAL], 0, by_user); +} /*****************************************************************************/ @@ -317,7 +320,7 @@ static void set_visible (NMSettingsConnection *self, gboolean new_visible) { nm_settings_connection_set_flags (self, - NM_SETTINGS_CONNECTION_INT_FLAGS_VISIBLE, + NM_SETTINGS_CONNECTION_FLAGS_VISIBLE, new_visible); } @@ -387,7 +390,7 @@ nm_settings_connection_check_permission (NMSettingsConnection *self, priv = NM_SETTINGS_CONNECTION_GET_PRIVATE (self); if (!NM_FLAGS_HAS (nm_settings_connection_get_flags (self), - NM_SETTINGS_CONNECTION_INT_FLAGS_VISIBLE)) + NM_SETTINGS_CONNECTION_FLAGS_VISIBLE)) return FALSE; s_con = nm_connection_get_setting_connection (NM_CONNECTION (self)); @@ -487,30 +490,30 @@ secrets_cleared_cb (NMSettingsConnection *self) static void set_persist_mode (NMSettingsConnection *self, NMSettingsConnectionPersistMode persist_mode) { - NMSettingsConnectionIntFlags flags = NM_SETTINGS_CONNECTION_INT_FLAGS_NONE; - const NMSettingsConnectionIntFlags ALL = NM_SETTINGS_CONNECTION_INT_FLAGS_UNSAVED - | NM_SETTINGS_CONNECTION_INT_FLAGS_NM_GENERATED - | NM_SETTINGS_CONNECTION_INT_FLAGS_VOLATILE; + NMSettingsConnectionFlags flags = NM_SETTINGS_CONNECTION_FLAGS_NONE; + const NMSettingsConnectionFlags ALL = NM_SETTINGS_CONNECTION_FLAGS_UNSAVED + | NM_SETTINGS_CONNECTION_FLAGS_NM_GENERATED + | NM_SETTINGS_CONNECTION_FLAGS_VOLATILE; switch (persist_mode) { case NM_SETTINGS_CONNECTION_PERSIST_MODE_DISK: - flags = NM_SETTINGS_CONNECTION_INT_FLAGS_NONE; + flags = NM_SETTINGS_CONNECTION_FLAGS_NONE; break; case NM_SETTINGS_CONNECTION_PERSIST_MODE_IN_MEMORY: case NM_SETTINGS_CONNECTION_PERSIST_MODE_IN_MEMORY_DETACHED: case NM_SETTINGS_CONNECTION_PERSIST_MODE_IN_MEMORY_ONLY: - flags = NM_SETTINGS_CONNECTION_INT_FLAGS_UNSAVED; + flags = NM_SETTINGS_CONNECTION_FLAGS_UNSAVED; break; case NM_SETTINGS_CONNECTION_PERSIST_MODE_VOLATILE_DETACHED: case NM_SETTINGS_CONNECTION_PERSIST_MODE_VOLATILE_ONLY: - flags = NM_SETTINGS_CONNECTION_INT_FLAGS_UNSAVED | - NM_SETTINGS_CONNECTION_INT_FLAGS_VOLATILE; + flags = NM_SETTINGS_CONNECTION_FLAGS_UNSAVED | + NM_SETTINGS_CONNECTION_FLAGS_VOLATILE; break; case NM_SETTINGS_CONNECTION_PERSIST_MODE_UNSAVED: /* only set the connection as unsaved, but preserve the nm-generated * and volatile flag. */ nm_settings_connection_set_flags (self, - NM_SETTINGS_CONNECTION_INT_FLAGS_UNSAVED, + NM_SETTINGS_CONNECTION_FLAGS_UNSAVED, TRUE); return; case NM_SETTINGS_CONNECTION_PERSIST_MODE_KEEP: @@ -523,16 +526,6 @@ set_persist_mode (NMSettingsConnection *self, NMSettingsConnectionPersistMode pe } static void -_emit_updated (NMSettingsConnection *self, gboolean by_user) -{ - nm_dbus_object_emit_signal (NM_DBUS_OBJECT (self), - &interface_info_settings_connection, - &signal_info_updated, - "()"); - g_signal_emit (self, signals[UPDATED_INTERNAL], 0, by_user); -} - -static void connection_changed_cb (NMSettingsConnection *self, gpointer unused) { set_persist_mode (self, NM_SETTINGS_CONNECTION_PERSIST_MODE_UNSAVED); @@ -578,13 +571,17 @@ _update_prepare (NMSettingsConnection *self, NMConnection *new_connection, GError **error) { + NMSettingsConnectionPrivate *priv; + g_return_val_if_fail (NM_IS_SETTINGS_CONNECTION (self), FALSE); g_return_val_if_fail (NM_IS_CONNECTION (new_connection), FALSE); + priv = NM_SETTINGS_CONNECTION_GET_PRIVATE (self); + if (!nm_connection_normalize (new_connection, NULL, NULL, error)) return FALSE; - if ( nm_dbus_object_get_path (NM_DBUS_OBJECT (self)) + if ( nm_connection_get_path (NM_CONNECTION (self)) && g_strcmp0 (nm_settings_connection_get_uuid (self), nm_connection_get_uuid (new_connection)) != 0) { /* Updating the UUID is not allowed once the path is exported. */ g_set_error (error, NM_SETTINGS_ERROR, NM_SETTINGS_ERROR_FAILED, @@ -664,10 +661,8 @@ nm_settings_connection_update (NMSettingsConnection *self, NM_SETTING_COMPARE_FLAG_EXACT)) { gs_unref_object NMConnection *simple = NULL; - if (log_diff_name) { - nm_utils_log_connection_diff (replace_connection, NM_CONNECTION (self), LOGL_DEBUG, LOGD_CORE, log_diff_name, "++ ", - nm_dbus_object_get_path (NM_DBUS_OBJECT (self))); - } + if (log_diff_name) + nm_utils_log_connection_diff (replace_connection, NM_CONNECTION (self), LOGL_DEBUG, LOGD_CORE, log_diff_name, "++ "); /* Make a copy of agent-owned secrets because they won't be present in * the connection returned by plugins, as plugins return only what was @@ -684,7 +679,7 @@ nm_settings_connection_update (NMSettingsConnection *self, } nm_settings_connection_set_flags (self, - NM_SETTINGS_CONNECTION_INT_FLAGS_NM_GENERATED | NM_SETTINGS_CONNECTION_INT_FLAGS_VOLATILE, + NM_SETTINGS_CONNECTION_FLAGS_NM_GENERATED | NM_SETTINGS_CONNECTION_FLAGS_VOLATILE, FALSE); if (replaced) { @@ -803,7 +798,7 @@ nm_settings_connection_delete (NMSettingsConnection *self, for_agents = nm_simple_connection_new_clone (NM_CONNECTION (self)); nm_connection_clear_secrets (for_agents); nm_agent_manager_delete_secrets (priv->agent_mgr, - nm_dbus_object_get_path (NM_DBUS_OBJECT (self)), + nm_connection_get_path (NM_CONNECTION (self)), for_agents); g_object_unref (for_agents); @@ -1300,7 +1295,7 @@ nm_settings_connection_get_secrets (NMSettingsConnection *self, priv->last_secret_agent_version_id = nm_agent_manager_get_agent_version_id (priv->agent_mgr); call_id_a = nm_agent_manager_get_secrets (priv->agent_mgr, - nm_dbus_object_get_path (NM_DBUS_OBJECT (self)), + nm_connection_get_path (NM_CONNECTION (self)), NM_CONNECTION (self), subject, existing_secrets, @@ -1364,7 +1359,7 @@ nm_settings_connection_cancel_secrets (NMSettingsConnection *self, _get_secrets_cancel (self, call_id, FALSE); } -/*****************************************************************************/ +/**** User authorization **************************************/ typedef void (*AuthCallback) (NMSettingsConnection *self, GDBusMethodInvocation *context, @@ -1372,61 +1367,46 @@ typedef void (*AuthCallback) (NMSettingsConnection *self, GError *error, gpointer data); -typedef struct { - CList auth_lst; - NMAuthManagerCallId *call_id; - NMSettingsConnection *self; - AuthCallback callback; - gpointer callback_data; - GDBusMethodInvocation *invocation; - NMAuthSubject *subject; -} AuthData; - static void -pk_auth_cb (NMAuthManager *auth_manager, - NMAuthManagerCallId *auth_call_id, - gboolean is_authorized, - gboolean is_challenge, - GError *auth_error, +pk_auth_cb (NMAuthChain *chain, + GError *chain_error, + GDBusMethodInvocation *context, gpointer user_data) { - AuthData *auth_data = user_data; - NMSettingsConnection *self; - gs_free_error GError *error = NULL; - - nm_assert (auth_data); - nm_assert (NM_IS_SETTINGS_CONNECTION (auth_data->self)); - - self = auth_data->self; + NMSettingsConnection *self = NM_SETTINGS_CONNECTION (user_data); + NMSettingsConnectionPrivate *priv = NM_SETTINGS_CONNECTION_GET_PRIVATE (self); + GError *error = NULL; + NMAuthCallResult result; + const char *perm; + AuthCallback callback; + gpointer callback_data; + NMAuthSubject *subject; - auth_data->call_id = NULL; + priv->pending_auths = g_slist_remove (priv->pending_auths, chain); - c_list_unlink (&auth_data->auth_lst); + perm = nm_auth_chain_get_data (chain, "perm"); + g_assert (perm); + result = nm_auth_chain_get_result (chain, perm); - if (g_error_matches (auth_error, G_IO_ERROR, G_IO_ERROR_CANCELLED)) { - error = g_error_new (NM_SETTINGS_ERROR, - NM_SETTINGS_ERROR_FAILED, - "Error checking authorization: connection was deleted"); - } else if (auth_error) { + /* If our NMSettingsConnection is already gone, do nothing */ + if (chain_error) { error = g_error_new (NM_SETTINGS_ERROR, NM_SETTINGS_ERROR_FAILED, "Error checking authorization: %s", - auth_error->message); - } else if (nm_auth_call_result_eval (is_authorized, is_challenge, auth_error) != NM_AUTH_CALL_RESULT_YES) { + chain_error->message ? chain_error->message : "(unknown)"); + } else if (result != NM_AUTH_CALL_RESULT_YES) { error = g_error_new_literal (NM_SETTINGS_ERROR, NM_SETTINGS_ERROR_PERMISSION_DENIED, - "Insufficient privileges"); + "Insufficient privileges."); } - auth_data->callback (self, - auth_data->invocation, - auth_data->subject, - error, - auth_data->callback_data); + callback = nm_auth_chain_get_data (chain, "callback"); + callback_data = nm_auth_chain_get_data (chain, "callback-data"); + subject = nm_auth_chain_get_data (chain, "subject"); + callback (self, context, subject, error, callback_data); - g_object_unref (auth_data->invocation); - g_object_unref (auth_data->subject); - g_slice_free (AuthData, auth_data); + g_clear_error (&error); + nm_auth_chain_unref (chain); } /** @@ -1454,52 +1434,59 @@ _new_auth_subject (GDBusMethodInvocation *context, GError **error) return subject; } -/* may either invoke callback synchronously or asynchronously. */ static void auth_start (NMSettingsConnection *self, - GDBusMethodInvocation *invocation, + GDBusMethodInvocation *context, NMAuthSubject *subject, const char *check_permission, AuthCallback callback, gpointer callback_data) { NMSettingsConnectionPrivate *priv = NM_SETTINGS_CONNECTION_GET_PRIVATE (self); - AuthData *auth_data; + NMAuthChain *chain; GError *error = NULL; + char *error_desc = NULL; - nm_assert (nm_dbus_object_is_exported (NM_DBUS_OBJECT (self))); - nm_assert (G_IS_DBUS_METHOD_INVOCATION (invocation)); - nm_assert (NM_IS_AUTH_SUBJECT (subject)); + g_return_if_fail (context != NULL); + g_return_if_fail (NM_IS_AUTH_SUBJECT (subject)); - if (!nm_auth_is_subject_in_acl_set_error (NM_CONNECTION (self), - subject, - NM_SETTINGS_ERROR, - NM_SETTINGS_ERROR_PERMISSION_DENIED, - &error)) { - callback (self, invocation, subject, error, callback_data); + /* Ensure the caller can view this connection */ + if (!nm_auth_is_subject_in_acl (NM_CONNECTION (self), + subject, + &error_desc)) { + error = g_error_new_literal (NM_SETTINGS_ERROR, + NM_SETTINGS_ERROR_PERMISSION_DENIED, + error_desc); + g_free (error_desc); + + callback (self, context, subject, error, callback_data); g_clear_error (&error); return; } if (!check_permission) { /* Don't need polkit auth, automatic success */ - callback (self, invocation, subject, NULL, callback_data); + callback (self, context, subject, NULL, callback_data); + return; + } + + chain = nm_auth_chain_new_subject (subject, context, pk_auth_cb, self); + if (!chain) { + g_set_error_literal (&error, + NM_SETTINGS_ERROR, + NM_SETTINGS_ERROR_PERMISSION_DENIED, + "Unable to authenticate the request."); + callback (self, context, subject, error, callback_data); + g_clear_error (&error); return; } - auth_data = g_slice_new (AuthData); - auth_data->self = self; - auth_data->callback = callback; - auth_data->callback_data = callback_data; - auth_data->invocation = g_object_ref (invocation); - auth_data->subject = g_object_ref (subject); - c_list_link_tail (&priv->auth_lst_head, &auth_data->auth_lst); - auth_data->call_id = nm_auth_manager_check_authorization (nm_auth_manager_get (), - subject, - check_permission, - TRUE, - pk_auth_cb, - auth_data); + priv->pending_auths = g_slist_append (priv->pending_auths, chain); + nm_auth_chain_set_data (chain, "perm", (gpointer) check_permission, NULL); + nm_auth_chain_set_data (chain, "callback", callback, NULL); + nm_auth_chain_set_data (chain, "callback-data", callback_data, NULL); + nm_auth_chain_set_data (chain, "subject", g_object_ref (subject), g_object_unref); + nm_auth_chain_add_call (chain, check_permission, TRUE); } /**** DBus method handlers ************************************/ @@ -1536,7 +1523,7 @@ check_writable (NMConnection *self, GError **error) } static void -get_settings_auth_cb (NMSettingsConnection *self, +get_settings_auth_cb (NMSettingsConnection *self, GDBusMethodInvocation *context, NMAuthSubject *subject, GError *error, @@ -1590,25 +1577,18 @@ get_settings_auth_cb (NMSettingsConnection *self, } static void -impl_settings_connection_get_settings (NMDBusObject *obj, - const NMDBusInterfaceInfoExtended *interface_info, - const NMDBusMethodInfoExtended *method_info, - GDBusConnection *connection, - const char *sender, - GDBusMethodInvocation *invocation, - GVariant *parameters) -{ - NMSettingsConnection *self = NM_SETTINGS_CONNECTION (obj); - gs_unref_object NMAuthSubject *subject = NULL; +impl_settings_connection_get_settings (NMSettingsConnection *self, + GDBusMethodInvocation *context) +{ + NMAuthSubject *subject; GError *error = NULL; - subject = _new_auth_subject (invocation, &error); - if (!subject) { - g_dbus_method_invocation_take_error (invocation, error); - return; - } - - auth_start (self, invocation, subject, NULL, get_settings_auth_cb, NULL); + subject = _new_auth_subject (context, &error); + if (subject) { + auth_start (self, context, subject, NULL, get_settings_auth_cb, NULL); + g_object_unref (subject); + } else + g_dbus_method_invocation_take_error (context, error); } typedef struct { @@ -1802,7 +1782,7 @@ update_auth_cb (NMSettingsConnection *self, secrets_filter_cb, GUINT_TO_POINTER (NM_SETTING_SECRET_FLAG_AGENT_OWNED)); nm_agent_manager_save_secrets (info->agent_mgr, - nm_dbus_object_get_path (NM_DBUS_OBJECT (self)), + nm_connection_get_path (NM_CONNECTION (self)), for_agent, info->subject); } @@ -1850,6 +1830,7 @@ settings_connection_update (NMSettingsConnection *self, GError *error = NULL; UpdateInfo *info; const char *permission; + char *error_desc = NULL; /* If the connection is read-only, that has to be changed at the source of * the problem (ex a system settings plugin that can't write connections out) @@ -1886,12 +1867,15 @@ settings_connection_update (NMSettingsConnection *self, * that's sending the update request. You can't make a connection * invisible to yourself. */ - if (!nm_auth_is_subject_in_acl_set_error (tmp ? tmp : NM_CONNECTION (self), - subject, - NM_SETTINGS_ERROR, - NM_SETTINGS_ERROR_PERMISSION_DENIED, - &error)) + if (!nm_auth_is_subject_in_acl (tmp ? tmp : NM_CONNECTION (self), + subject, + &error_desc)) { + error = g_error_new_literal (NM_SETTINGS_ERROR, + NM_SETTINGS_ERROR_PERMISSION_DENIED, + error_desc); + g_free (error_desc); goto error; + } info = g_slice_new0 (UpdateInfo); info->is_update2 = is_update2; @@ -1917,87 +1901,54 @@ error: } static void -impl_settings_connection_update (NMDBusObject *obj, - const NMDBusInterfaceInfoExtended *interface_info, - const NMDBusMethodInfoExtended *method_info, - GDBusConnection *connection, - const char *sender, - GDBusMethodInvocation *invocation, - GVariant *parameters) +impl_settings_connection_update (NMSettingsConnection *self, + GDBusMethodInvocation *context, + GVariant *new_settings) { - NMSettingsConnection *self = NM_SETTINGS_CONNECTION (obj); - gs_unref_variant GVariant *settings = NULL; - - g_variant_get (parameters, "(@a{sa{sv}})", &settings); - settings_connection_update (self, FALSE, invocation, settings, NM_SETTINGS_UPDATE2_FLAG_TO_DISK); + settings_connection_update (self, FALSE, context, new_settings, NM_SETTINGS_UPDATE2_FLAG_TO_DISK); } static void -impl_settings_connection_update_unsaved (NMDBusObject *obj, - const NMDBusInterfaceInfoExtended *interface_info, - const NMDBusMethodInfoExtended *method_info, - GDBusConnection *connection, - const char *sender, - GDBusMethodInvocation *invocation, - GVariant *parameters) +impl_settings_connection_update_unsaved (NMSettingsConnection *self, + GDBusMethodInvocation *context, + GVariant *new_settings) { - NMSettingsConnection *self = NM_SETTINGS_CONNECTION (obj); - gs_unref_variant GVariant *settings = NULL; - - g_variant_get (parameters, "(@a{sa{sv}})", &settings); - settings_connection_update (self, FALSE, invocation, settings, NM_SETTINGS_UPDATE2_FLAG_IN_MEMORY); + settings_connection_update (self, FALSE, context, new_settings, NM_SETTINGS_UPDATE2_FLAG_IN_MEMORY); } static void -impl_settings_connection_save (NMDBusObject *obj, - const NMDBusInterfaceInfoExtended *interface_info, - const NMDBusMethodInfoExtended *method_info, - GDBusConnection *connection, - const char *sender, - GDBusMethodInvocation *invocation, - GVariant *parameters) +impl_settings_connection_save (NMSettingsConnection *self, + GDBusMethodInvocation *context) { - NMSettingsConnection *self = NM_SETTINGS_CONNECTION (obj); - - settings_connection_update (self, FALSE, invocation, NULL, NM_SETTINGS_UPDATE2_FLAG_TO_DISK); + settings_connection_update (self, FALSE, context, NULL, NM_SETTINGS_UPDATE2_FLAG_TO_DISK); } static void -impl_settings_connection_update2 (NMDBusObject *obj, - const NMDBusInterfaceInfoExtended *interface_info, - const NMDBusMethodInfoExtended *method_info, - GDBusConnection *connection, - const char *sender, - GDBusMethodInvocation *invocation, - GVariant *parameters) -{ - NMSettingsConnection *self = NM_SETTINGS_CONNECTION (obj); - gs_unref_variant GVariant *settings = NULL; - gs_unref_variant GVariant *args = NULL; - guint32 flags_u; +impl_settings_connection_update2 (NMSettingsConnection *self, + GDBusMethodInvocation *context, + GVariant *settings, + guint32 flags_u, + GVariant *args) +{ GError *error = NULL; GVariantIter iter; const char *args_name; - NMSettingsUpdate2Flags flags; + const NMSettingsUpdate2Flags flags = (NMSettingsUpdate2Flags) flags_u; const NMSettingsUpdate2Flags ALL_PERSIST_MODES = NM_SETTINGS_UPDATE2_FLAG_TO_DISK | NM_SETTINGS_UPDATE2_FLAG_IN_MEMORY | NM_SETTINGS_UPDATE2_FLAG_IN_MEMORY_DETACHED | NM_SETTINGS_UPDATE2_FLAG_IN_MEMORY_ONLY; - g_variant_get (parameters, "(@a{sa{sv}}u@a{sv})", &settings, &flags_u, &args); - if (NM_FLAGS_ANY (flags_u, ~((guint32) (ALL_PERSIST_MODES | NM_SETTINGS_UPDATE2_FLAG_VOLATILE | NM_SETTINGS_UPDATE2_FLAG_BLOCK_AUTOCONNECT)))) { error = g_error_new_literal (NM_SETTINGS_ERROR, NM_SETTINGS_ERROR_INVALID_ARGUMENTS, "Unknown flags"); - g_dbus_method_invocation_take_error (invocation, error); + g_dbus_method_invocation_take_error (context, error); return; } - flags = (NMSettingsUpdate2Flags) flags_u; - if ( ( NM_FLAGS_ANY (flags, ALL_PERSIST_MODES) && !nm_utils_is_power_of_two (flags & ALL_PERSIST_MODES)) || ( NM_FLAGS_HAS (flags, NM_SETTINGS_UPDATE2_FLAG_VOLATILE) @@ -2006,7 +1957,7 @@ impl_settings_connection_update2 (NMDBusObject *obj, error = g_error_new_literal (NM_SETTINGS_ERROR, NM_SETTINGS_ERROR_INVALID_ARGUMENTS, "Conflicting flags"); - g_dbus_method_invocation_take_error (invocation, error); + g_dbus_method_invocation_take_error (context, error); return; } @@ -2014,7 +1965,7 @@ impl_settings_connection_update2 (NMDBusObject *obj, error = g_error_new_literal (NM_SETTINGS_ERROR, NM_SETTINGS_ERROR_INVALID_ARGUMENTS, "args is of invalid type"); - g_dbus_method_invocation_take_error (invocation, error); + g_dbus_method_invocation_take_error (context, error); return; } @@ -2023,13 +1974,13 @@ impl_settings_connection_update2 (NMDBusObject *obj, error = g_error_new (NM_SETTINGS_ERROR, NM_SETTINGS_ERROR_INVALID_ARGUMENTS, "Unsupported argument '%s'", args_name); - g_dbus_method_invocation_take_error (invocation, error); + g_dbus_method_invocation_take_error (context, error); return; } settings_connection_update (self, TRUE, - invocation, + context, settings, flags); } @@ -2074,7 +2025,7 @@ get_modify_permission_basic (NMSettingsConnection *self) * request affects more than just the caller, require 'modify.system'. */ s_con = nm_connection_get_setting_connection (NM_CONNECTION (self)); - nm_assert (s_con); + g_assert (s_con); if (nm_setting_connection_get_num_permissions (s_con) == 1) return NM_AUTH_PERMISSION_SETTINGS_MODIFY_OWN; @@ -2082,30 +2033,26 @@ get_modify_permission_basic (NMSettingsConnection *self) } static void -impl_settings_connection_delete (NMDBusObject *obj, - const NMDBusInterfaceInfoExtended *interface_info, - const NMDBusMethodInfoExtended *method_info, - GDBusConnection *connection, - const char *sender, - GDBusMethodInvocation *invocation, - GVariant *parameters) -{ - NMSettingsConnection *self = NM_SETTINGS_CONNECTION (obj); - gs_unref_object NMAuthSubject *subject = NULL; +impl_settings_connection_delete (NMSettingsConnection *self, + GDBusMethodInvocation *context) +{ + NMAuthSubject *subject = NULL; GError *error = NULL; if (!check_writable (NM_CONNECTION (self), &error)) - goto err; + goto out_err; - subject = _new_auth_subject (invocation, &error); - if (!subject) - goto err; + subject = _new_auth_subject (context, &error); + if (subject) { + auth_start (self, context, subject, get_modify_permission_basic (self), delete_auth_cb, NULL); + g_object_unref (subject); + } else + goto out_err; - auth_start (self, invocation, subject, get_modify_permission_basic (self), delete_auth_cb, NULL); return; -err: +out_err: nm_audit_log_connection_op (NM_AUDIT_OP_CONN_DELETE, self, FALSE, NULL, subject, error->message); - g_dbus_method_invocation_take_error (invocation, error); + g_dbus_method_invocation_take_error (context, error); } /*****************************************************************************/ @@ -2164,33 +2111,24 @@ dbus_get_secrets_auth_cb (NMSettingsConnection *self, } static void -impl_settings_connection_get_secrets (NMDBusObject *obj, - const NMDBusInterfaceInfoExtended *interface_info, - const NMDBusMethodInfoExtended *method_info, - GDBusConnection *connection, - const char *sender, - GDBusMethodInvocation *invocation, - GVariant *parameters) -{ - NMSettingsConnection *self = NM_SETTINGS_CONNECTION (obj); - gs_unref_object NMAuthSubject *subject = NULL; +impl_settings_connection_get_secrets (NMSettingsConnection *self, + GDBusMethodInvocation *context, + const gchar *setting_name) +{ + NMAuthSubject *subject; GError *error = NULL; - const char *setting_name; - - subject = _new_auth_subject (invocation, &error); - if (!subject) { - g_dbus_method_invocation_take_error (invocation, error); - return; - } - - g_variant_get (parameters, "(&s)", &setting_name); - auth_start (self, - invocation, - subject, - get_modify_permission_basic (self), - dbus_get_secrets_auth_cb, - g_strdup (setting_name)); + subject = _new_auth_subject (context, &error); + if (subject) { + auth_start (self, + context, + subject, + get_modify_permission_basic (self), + dbus_get_secrets_auth_cb, + g_strdup (setting_name)); + g_object_unref (subject); + } else + g_dbus_method_invocation_take_error (context, error); } static void @@ -2219,7 +2157,7 @@ dbus_clear_secrets_auth_cb (NMSettingsConnection *self, /* Tell agents to remove secrets for this connection */ nm_agent_manager_delete_secrets (priv->agent_mgr, - nm_dbus_object_get_path (NM_DBUS_OBJECT (self)), + nm_connection_get_path (NM_CONNECTION (self)), NM_CONNECTION (self)); nm_settings_connection_update (self, @@ -2239,31 +2177,26 @@ dbus_clear_secrets_auth_cb (NMSettingsConnection *self, } static void -impl_settings_connection_clear_secrets (NMDBusObject *obj, - const NMDBusInterfaceInfoExtended *interface_info, - const NMDBusMethodInfoExtended *method_info, - GDBusConnection *connection, - const char *sender, - GDBusMethodInvocation *invocation, - GVariant *parameters) -{ - NMSettingsConnection *self = NM_SETTINGS_CONNECTION (obj); - gs_unref_object NMAuthSubject *subject = NULL; +impl_settings_connection_clear_secrets (NMSettingsConnection *self, + GDBusMethodInvocation *context) +{ + NMAuthSubject *subject; GError *error = NULL; - subject = _new_auth_subject (invocation, &error); - if (!subject) { + subject = _new_auth_subject (context, &error); + if (subject) { + auth_start (self, + context, + subject, + get_modify_permission_basic (self), + dbus_clear_secrets_auth_cb, + NULL); + g_object_unref (subject); + } else { nm_audit_log_connection_op (NM_AUDIT_OP_CONN_CLEAR_SECRETS, self, FALSE, NULL, NULL, error->message); - g_dbus_method_invocation_take_error (invocation, error); - return; + g_dbus_method_invocation_take_error (context, error); } - auth_start (self, - invocation, - subject, - get_modify_permission_basic (self), - dbus_clear_secrets_auth_cb, - NULL); } /*****************************************************************************/ @@ -2283,64 +2216,55 @@ void nm_settings_connection_signal_remove (NMSettingsConnection *self) { NMSettingsConnectionPrivate *priv = NM_SETTINGS_CONNECTION_GET_PRIVATE (self); - AuthData *auth_data; if (priv->removed) return; priv->removed = TRUE; - - while ((auth_data = c_list_first_entry (&priv->auth_lst_head, AuthData, auth_lst))) - nm_auth_manager_check_authorization_cancel (auth_data->call_id); - - nm_dbus_object_emit_signal (NM_DBUS_OBJECT (self), - &interface_info_settings_connection, - &signal_info_removed, - "()"); - g_signal_emit (self, signals[REMOVED], 0); + g_signal_emit_by_name (self, NM_SETTINGS_CONNECTION_REMOVED); } gboolean nm_settings_connection_get_unsaved (NMSettingsConnection *self) { - return NM_FLAGS_HAS (nm_settings_connection_get_flags (self), NM_SETTINGS_CONNECTION_INT_FLAGS_UNSAVED); + return NM_FLAGS_HAS (nm_settings_connection_get_flags (self), NM_SETTINGS_CONNECTION_FLAGS_UNSAVED); } /*****************************************************************************/ -NM_UTILS_FLAGS2STR_DEFINE_STATIC (_settings_connection_flags_to_string, NMSettingsConnectionIntFlags, - NM_UTILS_FLAGS2STR (NM_SETTINGS_CONNECTION_INT_FLAGS_NONE, "none"), - NM_UTILS_FLAGS2STR (NM_SETTINGS_CONNECTION_INT_FLAGS_UNSAVED, "unsaved"), - NM_UTILS_FLAGS2STR (NM_SETTINGS_CONNECTION_INT_FLAGS_NM_GENERATED, "nm-generated"), - NM_UTILS_FLAGS2STR (NM_SETTINGS_CONNECTION_INT_FLAGS_VOLATILE, "volatile"), - NM_UTILS_FLAGS2STR (NM_SETTINGS_CONNECTION_INT_FLAGS_VISIBLE, "visible"), +NM_UTILS_FLAGS2STR_DEFINE_STATIC (_settings_connection_flags_to_string, NMSettingsConnectionFlags, + NM_UTILS_FLAGS2STR (NM_SETTINGS_CONNECTION_FLAGS_NONE, "none"), + NM_UTILS_FLAGS2STR (NM_SETTINGS_CONNECTION_FLAGS_UNSAVED, "unsaved"), + NM_UTILS_FLAGS2STR (NM_SETTINGS_CONNECTION_FLAGS_NM_GENERATED, "nm-generated"), + NM_UTILS_FLAGS2STR (NM_SETTINGS_CONNECTION_FLAGS_VOLATILE, "volatile"), + NM_UTILS_FLAGS2STR (NM_SETTINGS_CONNECTION_FLAGS_VISIBLE, "visible"), ); -NMSettingsConnectionIntFlags +NMSettingsConnectionFlags nm_settings_connection_get_flags (NMSettingsConnection *self) { - g_return_val_if_fail (NM_IS_SETTINGS_CONNECTION (self), NM_SETTINGS_CONNECTION_INT_FLAGS_NONE); + g_return_val_if_fail (NM_IS_SETTINGS_CONNECTION (self), NM_SETTINGS_CONNECTION_FLAGS_NONE); return NM_SETTINGS_CONNECTION_GET_PRIVATE (self)->flags; } -NMSettingsConnectionIntFlags -nm_settings_connection_set_flags (NMSettingsConnection *self, NMSettingsConnectionIntFlags flags, gboolean set) +NMSettingsConnectionFlags +nm_settings_connection_set_flags (NMSettingsConnection *self, NMSettingsConnectionFlags flags, gboolean set) { return nm_settings_connection_set_flags_full (self, flags, - set ? flags : NM_SETTINGS_CONNECTION_INT_FLAGS_NONE); + set ? flags : NM_SETTINGS_CONNECTION_FLAGS_NONE); } -NMSettingsConnectionIntFlags +NMSettingsConnectionFlags nm_settings_connection_set_flags_full (NMSettingsConnection *self, - NMSettingsConnectionIntFlags mask, - NMSettingsConnectionIntFlags value) + NMSettingsConnectionFlags mask, + NMSettingsConnectionFlags value) { NMSettingsConnectionPrivate *priv; - NMSettingsConnectionIntFlags old_flags; + NMSettingsConnectionFlags old_flags; - g_return_val_if_fail (NM_IS_SETTINGS_CONNECTION (self), NM_SETTINGS_CONNECTION_INT_FLAGS_NONE); - nm_assert (mask && !NM_FLAGS_ANY (mask, ~NM_SETTINGS_CONNECTION_INT_FLAGS_ALL)); + g_return_val_if_fail (NM_IS_SETTINGS_CONNECTION (self), NM_SETTINGS_CONNECTION_FLAGS_NONE); + nm_assert (mask && !NM_FLAGS_ANY (mask, ~NM_SETTINGS_CONNECTION_FLAGS_ALL)); nm_assert (!NM_FLAGS_ANY (value, ~mask)); priv = NM_SETTINGS_CONNECTION_GET_PRIVATE (self); @@ -2349,7 +2273,6 @@ nm_settings_connection_set_flags_full (NMSettingsConnection *self, old_flags = priv->flags; if (old_flags != value) { - gboolean notify_unsaved = FALSE; char buf1[255], buf2[255]; _LOGT ("update settings-connection flags to %s (was %s)", @@ -2357,17 +2280,9 @@ nm_settings_connection_set_flags_full (NMSettingsConnection *self, _settings_connection_flags_to_string (priv->flags, buf2, sizeof (buf2))); priv->flags = value; nm_assert (priv->flags == value); - - if (NM_FLAGS_HAS (old_flags, NM_SETTINGS_CONNECTION_INT_FLAGS_UNSAVED) != NM_FLAGS_HAS (value, NM_SETTINGS_CONNECTION_INT_FLAGS_UNSAVED)) { - g_object_freeze_notify (G_OBJECT (self)); - _notify (self, PROP_UNSAVED); - notify_unsaved = TRUE; - } _notify (self, PROP_FLAGS); - if (notify_unsaved) - g_object_thaw_notify (G_OBJECT (self)); - - g_signal_emit (self, signals[FLAGS_CHANGED], 0); + if (NM_FLAGS_HAS (old_flags, NM_SETTINGS_CONNECTION_FLAGS_UNSAVED) != NM_FLAGS_HAS (value, NM_SETTINGS_CONNECTION_FLAGS_UNSAVED)) + _notify (self, PROP_UNSAVED); } return old_flags; } @@ -2788,7 +2703,7 @@ _autoconnect_retries_set (NMSettingsConnection *self, if (retries) priv->autoconnect_retries_blocked_until = 0; else { - /* NOTE: the blocked time must be identical for all connections, otherwise + /* XXX: the blocked time must be identical for all connections, otherwise * the tracking of resetting the retry count in NMPolicy needs adjustment * in _connection_autoconnect_retries_set() (as it would need to re-evaluate * the next-timeout everytime a connection gets blocked). */ @@ -2883,7 +2798,7 @@ gboolean nm_settings_connection_autoconnect_is_blocked (NMSettingsConnection *self) { NMSettingsConnectionPrivate *priv; - NMSettingsConnectionIntFlags flags; + NMSettingsConnectionFlags flags; g_return_val_if_fail (NM_IS_SETTINGS_CONNECTION (self), TRUE); @@ -2895,9 +2810,9 @@ nm_settings_connection_autoconnect_is_blocked (NMSettingsConnection *self) return TRUE; flags = priv->flags; - if (NM_FLAGS_HAS (flags, NM_SETTINGS_CONNECTION_INT_FLAGS_VOLATILE)) + if (NM_FLAGS_HAS (flags, NM_SETTINGS_CONNECTION_FLAGS_VOLATILE)) return TRUE; - if (!NM_FLAGS_HAS (flags, NM_SETTINGS_CONNECTION_INT_FLAGS_VISIBLE)) + if (!NM_FLAGS_HAS (flags, NM_SETTINGS_CONNECTION_FLAGS_VISIBLE)) return TRUE; return FALSE; @@ -2985,11 +2900,8 @@ nm_settings_connection_init (NMSettingsConnection *self) priv = G_TYPE_INSTANCE_GET_PRIVATE (self, NM_TYPE_SETTINGS_CONNECTION, NMSettingsConnectionPrivate); self->_priv = priv; - c_list_init (&self->_connections_lst); - priv->ready = TRUE; c_list_init (&priv->call_ids_lst_head); - c_list_init (&priv->auth_lst_head); priv->session_monitor = g_object_ref (nm_session_monitor_get ()); priv->session_changed_id = g_signal_connect (priv->session_monitor, @@ -3025,9 +2937,6 @@ dispose (GObject *object) _LOGD ("disposing"); - nm_assert (c_list_is_empty (&self->_connections_lst)); - nm_assert (c_list_is_empty (&priv->auth_lst_head)); - /* Cancel in-progress secrets requests */ if (priv->agent_mgr) { c_list_for_each_entry_safe (call_id, call_id_safe, &priv->call_ids_lst_head, call_ids_lst) @@ -3045,7 +2954,11 @@ dispose (GObject *object) g_clear_object (&priv->system_secrets); g_clear_object (&priv->agent_secrets); - g_clear_pointer (&priv->seen_bssids, g_hash_table_destroy); + /* Cancel PolicyKit requests */ + g_slist_free_full (priv->pending_auths, (GDestroyNotify) nm_auth_chain_unref); + priv->pending_auths = NULL; + + g_clear_pointer (&priv->seen_bssids, (GDestroyNotify) g_hash_table_destroy); set_visible (self, FALSE); @@ -3073,8 +2986,7 @@ get_property (GObject *object, guint prop_id, g_value_set_boolean (value, nm_settings_connection_get_ready (self)); break; case PROP_FLAGS: - g_value_set_uint (value, - nm_settings_connection_get_flags (self) & NM_SETTINGS_CONNECTION_INT_FLAGS_EXPORTED_MASK); + g_value_set_uint (value, nm_settings_connection_get_flags (self)); break; case PROP_FILENAME: g_value_set_string (value, nm_settings_connection_get_filename (self)); @@ -3102,120 +3014,22 @@ set_property (GObject *object, guint prop_id, } } -static const GDBusSignalInfo signal_info_updated = NM_DEFINE_GDBUS_SIGNAL_INFO_INIT ( - "Updated", -); - -static const GDBusSignalInfo signal_info_removed = NM_DEFINE_GDBUS_SIGNAL_INFO_INIT ( - "Removed", -); - -static const NMDBusInterfaceInfoExtended interface_info_settings_connection = { - .parent = NM_DEFINE_GDBUS_INTERFACE_INFO_INIT ( - NM_DBUS_INTERFACE_SETTINGS_CONNECTION, - .methods = NM_DEFINE_GDBUS_METHOD_INFOS ( - NM_DEFINE_DBUS_METHOD_INFO_EXTENDED ( - NM_DEFINE_GDBUS_METHOD_INFO_INIT ( - "Update", - .in_args = NM_DEFINE_GDBUS_ARG_INFOS ( - NM_DEFINE_GDBUS_ARG_INFO ("properties", "a{sa{sv}}"), - ), - ), - .handle = impl_settings_connection_update, - ), - NM_DEFINE_DBUS_METHOD_INFO_EXTENDED ( - NM_DEFINE_GDBUS_METHOD_INFO_INIT ( - "UpdateUnsaved", - .in_args = NM_DEFINE_GDBUS_ARG_INFOS ( - NM_DEFINE_GDBUS_ARG_INFO ("properties", "a{sa{sv}}"), - ), - ), - .handle = impl_settings_connection_update_unsaved, - ), - NM_DEFINE_DBUS_METHOD_INFO_EXTENDED ( - NM_DEFINE_GDBUS_METHOD_INFO_INIT ( - "Delete", - ), - .handle = impl_settings_connection_delete, - ), - NM_DEFINE_DBUS_METHOD_INFO_EXTENDED ( - NM_DEFINE_GDBUS_METHOD_INFO_INIT ( - "GetSettings", - .out_args = NM_DEFINE_GDBUS_ARG_INFOS ( - NM_DEFINE_GDBUS_ARG_INFO ("settings", "a{sa{sv}}"), - ), - ), - .handle = impl_settings_connection_get_settings, - ), - NM_DEFINE_DBUS_METHOD_INFO_EXTENDED ( - NM_DEFINE_GDBUS_METHOD_INFO_INIT ( - "GetSecrets", - .in_args = NM_DEFINE_GDBUS_ARG_INFOS ( - NM_DEFINE_GDBUS_ARG_INFO ("setting_name", "s"), - ), - .out_args = NM_DEFINE_GDBUS_ARG_INFOS ( - NM_DEFINE_GDBUS_ARG_INFO ("secrets", "a{sa{sv}}"), - ), - ), - .handle = impl_settings_connection_get_secrets, - ), - NM_DEFINE_DBUS_METHOD_INFO_EXTENDED ( - NM_DEFINE_GDBUS_METHOD_INFO_INIT ( - "ClearSecrets", - ), - .handle = impl_settings_connection_clear_secrets, - ), - NM_DEFINE_DBUS_METHOD_INFO_EXTENDED ( - NM_DEFINE_GDBUS_METHOD_INFO_INIT ( - "Save", - ), - .handle = impl_settings_connection_save, - ), - NM_DEFINE_DBUS_METHOD_INFO_EXTENDED ( - NM_DEFINE_GDBUS_METHOD_INFO_INIT ( - "Update2", - .in_args = NM_DEFINE_GDBUS_ARG_INFOS ( - NM_DEFINE_GDBUS_ARG_INFO ("settings", "a{sa{sv}}"), - NM_DEFINE_GDBUS_ARG_INFO ("flags", "u"), - NM_DEFINE_GDBUS_ARG_INFO ("args", "a{sv}"), - ), - .out_args = NM_DEFINE_GDBUS_ARG_INFOS ( - NM_DEFINE_GDBUS_ARG_INFO ("result", "a{sv}"), - ), - ), - .handle = impl_settings_connection_update2, - ), - ), - .signals = NM_DEFINE_GDBUS_SIGNAL_INFOS ( - &nm_signal_info_property_changed_legacy, - &signal_info_updated, - &signal_info_removed, - ), - .properties = NM_DEFINE_GDBUS_PROPERTY_INFOS ( - NM_DEFINE_DBUS_PROPERTY_INFO_EXTENDED_READABLE_L ("Unsaved", "b", NM_SETTINGS_CONNECTION_UNSAVED), - NM_DEFINE_DBUS_PROPERTY_INFO_EXTENDED_READABLE ("Flags", "u", NM_SETTINGS_CONNECTION_FLAGS), - ), - ), - .legacy_property_changed = TRUE, -}; - static void -nm_settings_connection_class_init (NMSettingsConnectionClass *klass) +nm_settings_connection_class_init (NMSettingsConnectionClass *class) { - GObjectClass *object_class = G_OBJECT_CLASS (klass); - NMDBusObjectClass *dbus_object_class = NM_DBUS_OBJECT_CLASS (klass); + GObjectClass *object_class = G_OBJECT_CLASS (class); + NMExportedObjectClass *exported_object_class = NM_EXPORTED_OBJECT_CLASS (class); - g_type_class_add_private (klass, sizeof (NMSettingsConnectionPrivate)); + g_type_class_add_private (class, sizeof (NMSettingsConnectionPrivate)); - dbus_object_class->export_path = NM_DBUS_EXPORT_PATH_NUMBERED (NM_DBUS_PATH_SETTINGS); - dbus_object_class->interface_infos = NM_DBUS_INTERFACE_INFOS (&interface_info_settings_connection); + exported_object_class->export_path = NM_EXPORT_PATH_NUMBERED (NM_DBUS_PATH_SETTINGS); object_class->constructed = constructed; object_class->dispose = dispose; object_class->get_property = get_property; object_class->set_property = set_property; - klass->supports_secrets = supports_secrets; + class->supports_secrets = supports_secrets; obj_properties[PROP_UNSAVED] = g_param_spec_boolean (NM_SETTINGS_CONNECTION_UNSAVED, "", "", @@ -3231,7 +3045,9 @@ nm_settings_connection_class_init (NMSettingsConnectionClass *klass) obj_properties[PROP_FLAGS] = g_param_spec_uint (NM_SETTINGS_CONNECTION_FLAGS, "", "", - 0, G_MAXUINT32, 0, + NM_SETTINGS_CONNECTION_FLAGS_NONE, + NM_SETTINGS_CONNECTION_FLAGS_ALL, + NM_SETTINGS_CONNECTION_FLAGS_NONE, G_PARAM_READABLE | G_PARAM_STATIC_STRINGS); @@ -3244,10 +3060,20 @@ nm_settings_connection_class_init (NMSettingsConnectionClass *klass) g_object_class_install_properties (object_class, _PROPERTY_ENUMS_LAST, obj_properties); + + signals[UPDATED] = + g_signal_new (NM_SETTINGS_CONNECTION_UPDATED, + G_TYPE_FROM_CLASS (class), + G_SIGNAL_RUN_FIRST, + 0, + NULL, NULL, + g_cclosure_marshal_VOID__VOID, + G_TYPE_NONE, 0); + /* internal signal, with an argument (gboolean by_user). */ signals[UPDATED_INTERNAL] = g_signal_new (NM_SETTINGS_CONNECTION_UPDATED_INTERNAL, - G_TYPE_FROM_CLASS (klass), + G_TYPE_FROM_CLASS (class), G_SIGNAL_RUN_FIRST, 0, NULL, NULL, g_cclosure_marshal_VOID__BOOLEAN, @@ -3255,20 +3081,24 @@ nm_settings_connection_class_init (NMSettingsConnectionClass *klass) signals[REMOVED] = g_signal_new (NM_SETTINGS_CONNECTION_REMOVED, - G_TYPE_FROM_CLASS (klass), + G_TYPE_FROM_CLASS (class), G_SIGNAL_RUN_FIRST, 0, NULL, NULL, g_cclosure_marshal_VOID__VOID, G_TYPE_NONE, 0); - signals[FLAGS_CHANGED] = - g_signal_new (NM_SETTINGS_CONNECTION_FLAGS_CHANGED, - G_TYPE_FROM_CLASS (klass), - G_SIGNAL_RUN_FIRST, - 0, NULL, NULL, - g_cclosure_marshal_VOID__VOID, - G_TYPE_NONE, 0); + nm_exported_object_class_add_interface (NM_EXPORTED_OBJECT_CLASS (class), + NMDBUS_TYPE_SETTINGS_CONNECTION_SKELETON, + "Update", impl_settings_connection_update, + "UpdateUnsaved", impl_settings_connection_update_unsaved, + "Delete", impl_settings_connection_delete, + "GetSettings", impl_settings_connection_get_settings, + "GetSecrets", impl_settings_connection_get_secrets, + "ClearSecrets", impl_settings_connection_clear_secrets, + "Save", impl_settings_connection_save, + "Update2", impl_settings_connection_update2, + NULL); } static void diff --git a/src/settings/nm-settings-connection.h b/src/settings/nm-settings-connection.h index 58901699..29ec05dd 100644 --- a/src/settings/nm-settings-connection.h +++ b/src/settings/nm-settings-connection.h @@ -24,7 +24,7 @@ #include <net/ethernet.h> -#include "nm-dbus-object.h" +#include "nm-exported-object.h" #include "nm-connection.h" #define NM_TYPE_SETTINGS_CONNECTION (nm_settings_connection_get_type ()) @@ -34,11 +34,14 @@ #define NM_IS_SETTINGS_CONNECTION_CLASS(klass) (G_TYPE_CHECK_CLASS_TYPE ((klass), NM_TYPE_SETTINGS_CONNECTION)) #define NM_SETTINGS_CONNECTION_GET_CLASS(obj) (G_TYPE_INSTANCE_GET_CLASS ((obj), NM_TYPE_SETTINGS_CONNECTION, NMSettingsConnectionClass)) +/* Signals */ +#define NM_SETTINGS_CONNECTION_UPDATED "updated" #define NM_SETTINGS_CONNECTION_REMOVED "removed" #define NM_SETTINGS_CONNECTION_GET_SECRETS "get-secrets" #define NM_SETTINGS_CONNECTION_CANCEL_SECRETS "cancel-secrets" + +/* Internal signals */ #define NM_SETTINGS_CONNECTION_UPDATED_INTERNAL "updated-internal" -#define NM_SETTINGS_CONNECTION_FLAGS_CHANGED "flags-changed" /* Properties */ #define NM_SETTINGS_CONNECTION_UNSAVED "unsaved" @@ -50,45 +53,32 @@ /** - * NMSettingsConnectionIntFlags: - * @NM_SETTINGS_CONNECTION_INT_FLAGS_NONE: no flag set - * @NM_SETTINGS_CONNECTION_INT_FLAGS_UNSAVED: the connection is not saved to disk. - * See also #NM_SETTINGS_CONNECTION_FLAG_UNSAVED. - * @NM_SETTINGS_CONNECTION_INT_FLAGS_NM_GENERATED: A connection is "nm-generated" if + * NMSettingsConnectionFlags: + * @NM_SETTINGS_CONNECTION_FLAGS_NONE: no flag set + * @NM_SETTINGS_CONNECTION_FLAGS_UNSAVED: the connection is not saved to disk + * @NM_SETTINGS_CONNECTION_FLAGS_NM_GENERATED: A connection is "nm-generated" if * it was generated by NetworkManger. If the connection gets modified or saved * by the user, the flag gets cleared. A nm-generated is implicitly unsaved. - * See also #NM_SETTINGS_CONNECTION_FLAG_NM_GENERATED. - * @NM_SETTINGS_CONNECTION_INT_FLAGS_VOLATILE: The connection will be deleted + * @NM_SETTINGS_CONNECTION_FLAGS_VOLATILE: The connection will be deleted * when it disconnects. That is for in-memory connections (unsaved), which are * currently active but cleanup on disconnect. - * See also #NM_SETTINGS_CONNECTION_FLAG_VOLATILE. - * @NM_SETTINGS_CONNECTION_INT_FLAGS_VISIBLE: The connection is visible - * @NM_SETTINGS_CONNECTION_INT_FLAGS_EXPORTED_MASK: the entire enum is - * internal, however, parts of it is public API as #NMSettingsConnectionFlags. - * This mask, are the public flags. - * @NM_SETTINGS_CONNECTION_INT_FLAGS_ALL: special mask, for all known flags + * @NM_SETTINGS_CONNECTION_FLAGS_VISIBLE: The connection is visible + * @NM_SETTINGS_CONNECTION_FLAGS_ALL: special mask, for all known flags * * #NMSettingsConnection flags. **/ typedef enum { - NM_SETTINGS_CONNECTION_INT_FLAGS_NONE = 0, - - NM_SETTINGS_CONNECTION_INT_FLAGS_UNSAVED = NM_SETTINGS_CONNECTION_FLAG_UNSAVED, - NM_SETTINGS_CONNECTION_INT_FLAGS_NM_GENERATED = NM_SETTINGS_CONNECTION_FLAG_NM_GENERATED, - NM_SETTINGS_CONNECTION_INT_FLAGS_VOLATILE = NM_SETTINGS_CONNECTION_FLAG_VOLATILE, - - NM_SETTINGS_CONNECTION_INT_FLAGS_VISIBLE = (1LL << 3), + NM_SETTINGS_CONNECTION_FLAGS_NONE = 0, - __NM_SETTINGS_CONNECTION_INT_FLAGS_LAST, + NM_SETTINGS_CONNECTION_FLAGS_UNSAVED = (1LL << 0), + NM_SETTINGS_CONNECTION_FLAGS_NM_GENERATED = (1LL << 1), + NM_SETTINGS_CONNECTION_FLAGS_VOLATILE = (1LL << 2), - NM_SETTINGS_CONNECTION_INT_FLAGS_EXPORTED_MASK = 0 - | NM_SETTINGS_CONNECTION_INT_FLAGS_UNSAVED - | NM_SETTINGS_CONNECTION_INT_FLAGS_NM_GENERATED - | NM_SETTINGS_CONNECTION_INT_FLAGS_VOLATILE - | 0, + NM_SETTINGS_CONNECTION_FLAGS_VISIBLE = (1LL << 3), - NM_SETTINGS_CONNECTION_INT_FLAGS_ALL = ((__NM_SETTINGS_CONNECTION_INT_FLAGS_LAST - 1) << 1) - 1, -} NMSettingsConnectionIntFlags; + __NM_SETTINGS_CONNECTION_FLAGS_LAST, + NM_SETTINGS_CONNECTION_FLAGS_ALL = ((__NM_SETTINGS_CONNECTION_FLAGS_LAST - 1) << 1) - 1, +} NMSettingsConnectionFlags; typedef enum { NM_SETTINGS_CONNECTION_COMMIT_REASON_NONE = 0, @@ -116,13 +106,12 @@ typedef struct _NMSettingsConnectionClass NMSettingsConnectionClass; struct _NMSettingsConnectionPrivate; struct _NMSettingsConnection { - NMDBusObject parent; + NMExportedObject parent; struct _NMSettingsConnectionPrivate *_priv; - CList _connections_lst; }; struct _NMSettingsConnectionClass { - NMDBusObjectClass parent; + NMExportedObjectClass parent; gboolean (*commit_changes) (NMSettingsConnection *self, NMConnection *new_connection, @@ -210,9 +199,9 @@ void nm_settings_connection_signal_remove (NMSettingsConnection *self); gboolean nm_settings_connection_get_unsaved (NMSettingsConnection *self); -NMSettingsConnectionIntFlags nm_settings_connection_get_flags (NMSettingsConnection *self); -NMSettingsConnectionIntFlags nm_settings_connection_set_flags (NMSettingsConnection *self, NMSettingsConnectionIntFlags flags, gboolean set); -NMSettingsConnectionIntFlags nm_settings_connection_set_flags_full (NMSettingsConnection *self, NMSettingsConnectionIntFlags mask, NMSettingsConnectionIntFlags value); +NMSettingsConnectionFlags nm_settings_connection_get_flags (NMSettingsConnection *self); +NMSettingsConnectionFlags nm_settings_connection_set_flags (NMSettingsConnection *self, NMSettingsConnectionFlags flags, gboolean set); +NMSettingsConnectionFlags nm_settings_connection_set_flags_full (NMSettingsConnection *self, NMSettingsConnectionFlags mask, NMSettingsConnectionFlags value); int nm_settings_connection_cmp_timestamp (NMSettingsConnection *ac, NMSettingsConnection *ab); int nm_settings_connection_cmp_timestamp_p_with_data (gconstpointer pa, gconstpointer pb, gpointer user_data); diff --git a/src/settings/nm-settings.c b/src/settings/nm-settings.c index 2c6b7101..8e3fc582 100644 --- a/src/settings/nm-settings.c +++ b/src/settings/nm-settings.c @@ -62,12 +62,10 @@ #include "nm-utils.h" #include "nm-core-internal.h" -#include "nm-utils/nm-c-list.h" -#include "nm-dbus-object.h" #include "devices/nm-device-ethernet.h" #include "nm-settings-connection.h" #include "nm-settings-plugin.h" -#include "nm-dbus-manager.h" +#include "nm-bus-manager.h" #include "nm-auth-utils.h" #include "nm-auth-subject.h" #include "nm-session-monitor.h" @@ -79,6 +77,8 @@ #include "nm-dispatcher.h" #include "nm-hostname-manager.h" +#include "introspection/org.freedesktop.NetworkManager.Settings.h" + /*****************************************************************************/ #define EXPORT(sym) void * __export_##sym = &sym; @@ -107,6 +107,7 @@ enum { CONNECTION_UPDATED, CONNECTION_REMOVED, CONNECTION_FLAGS_CHANGED, + NEW_CONNECTION, /* exported, not used internally */ LAST_SIGNAL }; @@ -120,33 +121,29 @@ typedef struct { GSList *auths; GSList *plugins; - - CList connections_lst_head; - + gboolean connections_loaded; + GHashTable *connections; NMSettingsConnection **connections_cached_list; GSList *unmanaged_specs; GSList *unrecognized_specs; - NMHostnameManager *hostname_manager; - - guint connections_len; + gboolean started; + gboolean startup_complete; - bool started:1; - bool startup_complete:1; - bool connections_loaded:1; + NMHostnameManager *hostname_manager; } NMSettingsPrivate; struct _NMSettings { - NMDBusObject parent; + NMExportedObject parent; NMSettingsPrivate _priv; }; struct _NMSettingsClass { - NMDBusObjectClass parent; + NMExportedObjectClass parent; }; -G_DEFINE_TYPE (NMSettings, nm_settings, NM_TYPE_DBUS_OBJECT); +G_DEFINE_TYPE (NMSettings, nm_settings, NM_TYPE_EXPORTED_OBJECT); #define NM_SETTINGS_GET_PRIVATE(self) _NM_GET_PRIVATE (self, NMSettings, NM_IS_SETTINGS) @@ -157,10 +154,6 @@ G_DEFINE_TYPE (NMSettings, nm_settings, NM_TYPE_DBUS_OBJECT); /*****************************************************************************/ -static const NMDBusInterfaceInfoExtended interface_info_settings; -static const GDBusSignalInfo signal_info_new_connection; -static const GDBusSignalInfo signal_info_connection_removed; - static void claim_connection (NMSettings *self, NMSettingsConnection *connection); @@ -171,29 +164,27 @@ static void connection_ready_changed (NMSettingsConnection *conn, GParamSpec *pspec, gpointer user_data); -static void default_wired_clear_tag (NMSettings *self, - NMDevice *device, - NMSettingsConnection *connection, - gboolean add_to_no_auto_default); - /*****************************************************************************/ static void check_startup_complete (NMSettings *self) { NMSettingsPrivate *priv = NM_SETTINGS_GET_PRIVATE (self); + GHashTableIter iter; NMSettingsConnection *conn; if (priv->startup_complete) return; - c_list_for_each_entry (conn, &priv->connections_lst_head, _connections_lst) { + g_hash_table_iter_init (&iter, priv->connections); + while (g_hash_table_iter_next (&iter, NULL, (gpointer *) &conn)) { if (!nm_settings_connection_get_ready (conn)) return; } /* the connection_ready_changed signal handler is no longer needed. */ - c_list_for_each_entry (conn, &priv->connections_lst_head, _connections_lst) + g_hash_table_iter_init (&iter, priv->connections); + while (g_hash_table_iter_next (&iter, NULL, (gpointer *) &conn)) g_signal_handlers_disconnect_by_func (conn, G_CALLBACK (connection_ready_changed), self); priv->startup_complete = TRUE; @@ -256,25 +247,43 @@ load_connections (NMSettings *self) unrecognized_specs_changed (NULL, self); } +void +nm_settings_for_each_connection (NMSettings *self, + NMSettingsForEachFunc for_each_func, + gpointer user_data) +{ + NMSettingsPrivate *priv; + GHashTableIter iter; + gpointer data; + + g_return_if_fail (NM_IS_SETTINGS (self)); + g_return_if_fail (for_each_func != NULL); + + priv = NM_SETTINGS_GET_PRIVATE (self); + + g_hash_table_iter_init (&iter, priv->connections); + while (g_hash_table_iter_next (&iter, NULL, &data)) + for_each_func (self, NM_SETTINGS_CONNECTION (data), user_data); +} + static void -impl_settings_list_connections (NMDBusObject *obj, - const NMDBusInterfaceInfoExtended *interface_info, - const NMDBusMethodInfoExtended *method_info, - GDBusConnection *dbus_connection, - const char *sender, - GDBusMethodInvocation *invocation, - GVariant *parameters) +impl_settings_list_connections (NMSettings *self, + GDBusMethodInvocation *context) { - NMSettings *self = NM_SETTINGS (obj); NMSettingsPrivate *priv = NM_SETTINGS_GET_PRIVATE (self); - gs_free const char **strv = NULL; - - strv = nm_dbus_utils_get_paths_for_clist (&priv->connections_lst_head, - priv->connections_len, - G_STRUCT_OFFSET (NMSettingsConnection, _connections_lst), - TRUE); - g_dbus_method_invocation_return_value (invocation, - g_variant_new ("(^ao)", strv)); + GPtrArray *connections; + GHashTableIter iter; + gpointer key; + + connections = g_ptr_array_sized_new (g_hash_table_size (priv->connections) + 1); + g_hash_table_iter_init (&iter, priv->connections); + while (g_hash_table_iter_next (&iter, &key, NULL)) + g_ptr_array_add (connections, key); + g_ptr_array_add (connections, NULL); + + g_dbus_method_invocation_return_value (context, + g_variant_new ("(^ao)", connections->pdata)); + g_ptr_array_unref (connections); } NMSettingsConnection * @@ -282,14 +291,16 @@ nm_settings_get_connection_by_uuid (NMSettings *self, const char *uuid) { NMSettingsPrivate *priv; NMSettingsConnection *candidate; + GHashTableIter iter; g_return_val_if_fail (NM_IS_SETTINGS (self), NULL); g_return_val_if_fail (uuid != NULL, NULL); priv = NM_SETTINGS_GET_PRIVATE (self); - c_list_for_each_entry (candidate, &priv->connections_lst_head, _connections_lst) { - if (nm_streq (uuid, nm_settings_connection_get_uuid (candidate))) + g_hash_table_iter_init (&iter, priv->connections); + while (g_hash_table_iter_next (&iter, NULL, (gpointer) &candidate)) { + if (g_strcmp0 (uuid, nm_settings_connection_get_uuid (candidate)) == 0) return candidate; } @@ -297,21 +308,14 @@ nm_settings_get_connection_by_uuid (NMSettings *self, const char *uuid) } static void -impl_settings_get_connection_by_uuid (NMDBusObject *obj, - const NMDBusInterfaceInfoExtended *interface_info, - const NMDBusMethodInfoExtended *method_info, - GDBusConnection *dbus_connection, - const char *sender, - GDBusMethodInvocation *invocation, - GVariant *parameters) +impl_settings_get_connection_by_uuid (NMSettings *self, + GDBusMethodInvocation *context, + const char *uuid) { - NMSettings *self = NM_SETTINGS (obj); NMSettingsConnection *connection = NULL; - gs_unref_object NMAuthSubject *subject = NULL; + NMAuthSubject *subject = NULL; GError *error = NULL; - const char *uuid; - - g_variant_get (parameters, "(&s)", &uuid); + char *error_desc = NULL; connection = nm_settings_get_connection_by_uuid (self, uuid); if (!connection) { @@ -321,7 +325,7 @@ impl_settings_get_connection_by_uuid (NMDBusObject *obj, goto error; } - subject = nm_auth_subject_new_unix_process_from_context (invocation); + subject = nm_auth_subject_new_unix_process_from_context (context); if (!subject) { error = g_error_new_literal (NM_SETTINGS_ERROR, NM_SETTINGS_ERROR_PERMISSION_DENIED, @@ -329,40 +333,26 @@ impl_settings_get_connection_by_uuid (NMDBusObject *obj, goto error; } - if (!nm_auth_is_subject_in_acl_set_error (NM_CONNECTION (connection), - subject, - NM_SETTINGS_ERROR, - NM_SETTINGS_ERROR_PERMISSION_DENIED, - &error)) + if (!nm_auth_is_subject_in_acl (NM_CONNECTION (connection), + subject, + &error_desc)) { + error = g_error_new_literal (NM_SETTINGS_ERROR, + NM_SETTINGS_ERROR_PERMISSION_DENIED, + error_desc); + g_free (error_desc); goto error; + } - g_dbus_method_invocation_return_value (invocation, - g_variant_new ("(o)", - nm_dbus_object_get_path (NM_DBUS_OBJECT (connection)))); + g_clear_object (&subject); + g_dbus_method_invocation_return_value ( + context, + g_variant_new ("(o)", nm_connection_get_path (NM_CONNECTION (connection)))); return; error: - g_dbus_method_invocation_take_error (invocation, error); -} - -static void -_clear_connections_cached_list (NMSettingsPrivate *priv) -{ - if (!priv->connections_cached_list) - return; - - nm_assert (priv->connections_len == NM_PTRARRAY_LEN (priv->connections_cached_list)); - -#if NM_MORE_ASSERTS - /* set the pointer to a bogus value. This makes it more apparent - * if somebody has a reference to the cached list and still uses - * it. That is a bug, this code just tries to make it blow up - * more eagerly. */ - memset (priv->connections_cached_list, - 0xdeaddead, - sizeof (NMSettingsConnection *) * (priv->connections_len + 1)); -#endif - nm_clear_g_free (&priv->connections_cached_list); + g_assert (error); + g_dbus_method_invocation_take_error (context, error); + g_clear_object (&subject); } /** @@ -380,33 +370,37 @@ _clear_connections_cached_list (NMSettingsPrivate *priv) NMSettingsConnection *const* nm_settings_get_connections (NMSettings *self, guint *out_len) { + GHashTableIter iter; NMSettingsPrivate *priv; + guint l, i; NMSettingsConnection **v; NMSettingsConnection *con; - guint i; g_return_val_if_fail (NM_IS_SETTINGS (self), NULL); priv = NM_SETTINGS_GET_PRIVATE (self); - nm_assert (priv->connections_len == c_list_length (&priv->connections_lst_head)); + if (G_LIKELY (priv->connections_cached_list)) { + NM_SET_OUT (out_len, g_hash_table_size (priv->connections)); + return priv->connections_cached_list; + } - if (G_UNLIKELY (!priv->connections_cached_list)) { - v = g_new (NMSettingsConnection *, priv->connections_len + 1); + l = g_hash_table_size (priv->connections); - i = 0; - c_list_for_each_entry (con, &priv->connections_lst_head, _connections_lst) { - nm_assert (i < priv->connections_len); - v[i++] = con; - } - nm_assert (i == priv->connections_len); - v[i] = NULL; + v = g_new (NMSettingsConnection *, (gsize) l + 1); - priv->connections_cached_list = v; + i = 0; + g_hash_table_iter_init (&iter, priv->connections); + while (g_hash_table_iter_next (&iter, NULL, (gpointer *) &con)) { + nm_assert (i < l); + v[i++] = con; } + nm_assert (i == l); + v[i] = NULL; - NM_SET_OUT (out_len, priv->connections_len); - return priv->connections_cached_list; + NM_SET_OUT (out_len, l); + priv->connections_cached_list = v; + return v; } /** @@ -473,41 +467,28 @@ NMSettingsConnection * nm_settings_get_connection_by_path (NMSettings *self, const char *path) { NMSettingsPrivate *priv; - NMSettingsConnection *connection; g_return_val_if_fail (NM_IS_SETTINGS (self), NULL); - g_return_val_if_fail (path, NULL); + g_return_val_if_fail (path != NULL, NULL); priv = NM_SETTINGS_GET_PRIVATE (self); - connection = (NMSettingsConnection *) nm_dbus_manager_lookup_object (nm_dbus_object_get_manager (NM_DBUS_OBJECT (self)), - path); - if ( !connection - || !NM_IS_SETTINGS_CONNECTION (connection)) - return NULL; - - nm_assert (c_list_contains (&priv->connections_lst_head, &connection->_connections_lst)); - return connection; + return (NMSettingsConnection *) g_hash_table_lookup (priv->connections, path); } gboolean nm_settings_has_connection (NMSettings *self, NMSettingsConnection *connection) { - NMSettingsConnection *candidate = NULL; - const char *path; - - g_return_val_if_fail (NM_IS_SETTINGS (self), FALSE); - g_return_val_if_fail (NM_IS_SETTINGS_CONNECTION (connection), FALSE); + NMSettingsPrivate *priv = NM_SETTINGS_GET_PRIVATE (self); + GHashTableIter iter; + gpointer data; - path = nm_dbus_object_get_path (NM_DBUS_OBJECT (connection)); - if (path) - candidate = nm_settings_get_connection_by_path (self, path); + g_hash_table_iter_init (&iter, priv->connections); + while (g_hash_table_iter_next (&iter, NULL, &data)) + if (data == connection) + return TRUE; - nm_assert (!candidate || candidate == connection); - nm_assert (!!candidate == nm_c_list_contains_entry (&NM_SETTINGS_GET_PRIVATE (self)->connections_lst_head, - connection, - _connections_lst)); - return !!candidate; + return FALSE; } const GSList * @@ -519,7 +500,7 @@ nm_settings_get_unmanaged_specs (NMSettings *self) } static NMSettingsPlugin * -get_plugin (NMSettings *self, NMSettingsPluginCapabilities capability) +get_plugin (NMSettings *self, guint32 capability) { NMSettingsPrivate *priv = NM_SETTINGS_GET_PRIVATE (self); GSList *iter; @@ -696,8 +677,8 @@ load_plugins (NMSettings *self, const char **plugins, GError **error) continue; } - if (NM_IN_STRSET (pname, "ifcfg-suse", "ifnet")) { - _LOGW ("skipping deprecated plugin %s", pname); + if (!strcmp (pname, "ifcfg-suse")) { + _LOGW ("skipping deprecated plugin ifcfg-suse"); continue; } @@ -825,6 +806,7 @@ connection_updated (NMSettingsConnection *connection, gboolean by_user, gpointer static void connection_flags_changed (NMSettingsConnection *connection, + GParamSpec *pspec, gpointer user_data) { g_signal_emit (NM_SETTINGS (user_data), @@ -838,20 +820,11 @@ connection_removed (NMSettingsConnection *connection, gpointer user_data) { NMSettings *self = NM_SETTINGS (user_data); NMSettingsPrivate *priv = NM_SETTINGS_GET_PRIVATE (self); - NMDevice *device; + const char *cpath = nm_connection_get_path (NM_CONNECTION (connection)); - g_return_if_fail (NM_IS_SETTINGS_CONNECTION (connection)); - g_return_if_fail (!c_list_is_empty (&connection->_connections_lst)); - nm_assert (c_list_contains (&priv->connections_lst_head, &connection->_connections_lst)); - - /* When the default wired connection is removed (either deleted or saved to - * a new persistent connection by a plugin), write the MAC address of the - * wired device to the config file and don't create a new default wired - * connection for that device again. - */ - device = g_object_get_qdata (G_OBJECT (connection), _default_wired_device_quark ()); - if (device) - default_wired_clear_tag (self, device, connection, TRUE); + if (!g_hash_table_lookup (priv->connections, cpath)) + g_return_if_reached (); + g_object_ref (connection); /* Disconnect signal handlers, as plugins might still keep references * to the connection (and thus the signal handlers would still be live) @@ -863,30 +836,23 @@ connection_removed (NMSettingsConnection *connection, gpointer user_data) g_signal_handlers_disconnect_by_func (connection, G_CALLBACK (connection_flags_changed), self); if (!priv->startup_complete) g_signal_handlers_disconnect_by_func (connection, G_CALLBACK (connection_ready_changed), self); + g_object_unref (self); /* Forget about the connection internally */ - _clear_connections_cached_list (priv); - priv->connections_len--; - c_list_unlink (&connection->_connections_lst); - - if (priv->connections_loaded) { - _notify (self, PROP_CONNECTIONS); + g_hash_table_remove (priv->connections, (gpointer) cpath); + g_clear_pointer (&priv->connections_cached_list, g_free); - nm_dbus_object_emit_signal (NM_DBUS_OBJECT (self), - &interface_info_settings, - &signal_info_connection_removed, - "(o)", - nm_dbus_object_get_path (NM_DBUS_OBJECT (connection))); - } + /* Notify D-Bus */ + g_signal_emit (self, signals[CONNECTION_REMOVED], 0, connection); - nm_dbus_object_unexport (NM_DBUS_OBJECT (connection)); + /* Re-emit for listeners like NMPolicy */ + _notify (self, PROP_CONNECTIONS); + if (nm_exported_object_is_exported (NM_EXPORTED_OBJECT (connection))) + nm_exported_object_unexport (NM_EXPORTED_OBJECT (connection)); - if (priv->connections_loaded) - g_signal_emit (self, signals[CONNECTION_REMOVED], 0, connection); + check_startup_complete (self); g_object_unref (connection); - - check_startup_complete (self); } #define NM_DBUS_SERVICE_OPENCONNECT "org.freedesktop.NetworkManager.openconnect" @@ -934,16 +900,19 @@ claim_connection (NMSettings *self, NMSettingsConnection *connection) { NMSettingsPrivate *priv = NM_SETTINGS_GET_PRIVATE (self); GError *error = NULL; + GHashTableIter iter; + gpointer data; const char *path; NMSettingsConnection *existing; g_return_if_fail (NM_IS_SETTINGS_CONNECTION (connection)); - g_return_if_fail (!nm_dbus_object_is_exported (NM_DBUS_OBJECT (connection))); + g_return_if_fail (nm_connection_get_path (NM_CONNECTION (connection)) == NULL); - /* prevent duplicates */ - if (!c_list_is_empty (&connection->_connections_lst)) { - nm_assert (c_list_contains (&priv->connections_lst_head, &connection->_connections_lst)); - return; + g_hash_table_iter_init (&iter, priv->connections); + while (g_hash_table_iter_next (&iter, NULL, &data)) { + /* prevent duplicates */ + if (data == connection) + return; } if (!nm_connection_normalize (NM_CONNECTION (connection), NULL, NULL, &error)) { @@ -975,19 +944,20 @@ claim_connection (NMSettings *self, NMSettingsConnection *connection) /* Read seen-bssids from look-aside file and put it into the connection's data */ nm_settings_connection_read_and_fill_seen_bssids (connection); - /* Ensure its initial visibility is up-to-date */ + /* Ensure it's initial visibility is up-to-date */ nm_settings_connection_recheck_visibility (connection); /* Evil openconnect migration hack */ openconnect_migrate_hack (NM_CONNECTION (connection)); + g_object_ref (self); /* This one unexports the connection, it needs to run late to give the active * connection a chance to deal with its reference to this settings connection. */ g_signal_connect_after (connection, NM_SETTINGS_CONNECTION_REMOVED, G_CALLBACK (connection_removed), self); g_signal_connect (connection, NM_SETTINGS_CONNECTION_UPDATED_INTERNAL, G_CALLBACK (connection_updated), self); - g_signal_connect (connection, NM_SETTINGS_CONNECTION_FLAGS_CHANGED, + g_signal_connect (connection, "notify::" NM_SETTINGS_CONNECTION_FLAGS, G_CALLBACK (connection_flags_changed), self); if (!priv->startup_complete) { @@ -996,29 +966,28 @@ claim_connection (NMSettings *self, NMSettingsConnection *connection) self); } - _clear_connections_cached_list (priv); + /* Export the connection over D-Bus */ + g_warn_if_fail (nm_connection_get_path (NM_CONNECTION (connection)) == NULL); + path = nm_exported_object_export (NM_EXPORTED_OBJECT (connection)); + nm_connection_set_path (NM_CONNECTION (connection), path); - g_object_ref (connection); - priv->connections_len++; - c_list_link_tail (&priv->connections_lst_head, &connection->_connections_lst); - - path = nm_dbus_object_export (NM_DBUS_OBJECT (connection)); + g_hash_table_insert (priv->connections, + (gpointer) nm_connection_get_path (NM_CONNECTION (connection)), + g_object_ref (connection)); + g_clear_pointer (&priv->connections_cached_list, g_free); - nm_utils_log_connection_diff (NM_CONNECTION (connection), NULL, LOGL_DEBUG, LOGD_CORE, "new connection", "++ ", - path); + nm_utils_log_connection_diff (NM_CONNECTION (connection), NULL, LOGL_DEBUG, LOGD_CORE, "new connection", "++ "); /* Only emit the individual connection-added signal after connections * have been initially loaded. */ if (priv->connections_loaded) { - nm_dbus_object_emit_signal (NM_DBUS_OBJECT (self), - &interface_info_settings, - &signal_info_new_connection, - "(o)", - nm_dbus_object_get_path (NM_DBUS_OBJECT (connection))); - + /* Internal added signal */ g_signal_emit (self, signals[CONNECTION_ADDED], 0, connection); _notify (self, PROP_CONNECTIONS); + + /* Exported D-Bus signal */ + g_signal_emit (self, signals[NEW_CONNECTION], 0, connection); } nm_settings_connection_added (connection); @@ -1066,14 +1035,14 @@ nm_settings_add_connection (NMSettings *self, NMSettingsPrivate *priv = NM_SETTINGS_GET_PRIVATE (self); GSList *iter; NMSettingsConnection *added = NULL; - NMSettingsConnection *candidate = NULL; - const char *uuid; - - uuid = nm_connection_get_uuid (connection); + GHashTableIter citer; + NMConnection *candidate = NULL; /* Make sure a connection with this UUID doesn't already exist */ - c_list_for_each_entry (candidate, &priv->connections_lst_head, _connections_lst) { - if (nm_streq0 (uuid, nm_connection_get_uuid (NM_CONNECTION (candidate)))) { + g_hash_table_iter_init (&citer, priv->connections); + while (g_hash_table_iter_next (&citer, NULL, (gpointer *) &candidate)) { + if (g_strcmp0 (nm_connection_get_uuid (connection), + nm_connection_get_uuid (candidate)) == 0) { g_set_error_literal (error, NM_SETTINGS_ERROR, NM_SETTINGS_ERROR_UUID_EXISTS, @@ -1130,7 +1099,7 @@ send_agent_owned_secrets (NMSettings *self, NMAuthSubject *subject) { NMSettingsPrivate *priv = NM_SETTINGS_GET_PRIVATE (self); - gs_unref_object NMConnection *for_agent = NULL; + NMConnection *for_agent; /* Dupe the connection so we can clear out non-agent-owned secrets, * as agent-owned secrets are the only ones we send back to be saved. @@ -1141,9 +1110,10 @@ send_agent_owned_secrets (NMSettings *self, secrets_filter_cb, GUINT_TO_POINTER (NM_SETTING_SECRET_FLAG_AGENT_OWNED)); nm_agent_manager_save_secrets (priv->agent_mgr, - nm_dbus_object_get_path (NM_DBUS_OBJECT (connection)), + nm_connection_get_path (NM_CONNECTION (connection)), for_agent, subject); + g_object_unref (for_agent); } static void @@ -1200,7 +1170,7 @@ pk_add_cb (NMAuthChain *chain, send_agent_owned_secrets (self, added, subject); g_clear_error (&error); - nm_auth_chain_destroy (chain); + nm_auth_chain_unref (chain); } /* FIXME: remove if/when kernel supports adhoc wpa */ @@ -1248,6 +1218,7 @@ nm_settings_add_connection_dbus (NMSettings *self, NMAuthSubject *subject = NULL; NMAuthChain *chain; GError *error = NULL, *tmp_error = NULL; + char *error_desc = NULL; const char *perm; g_return_if_fail (connection != NULL); @@ -1290,12 +1261,18 @@ nm_settings_add_connection_dbus (NMSettings *self, goto done; } - if (!nm_auth_is_subject_in_acl_set_error (connection, - subject, - NM_SETTINGS_ERROR, - NM_SETTINGS_ERROR_PERMISSION_DENIED, - &error)) + /* Ensure the caller's username exists in the connection's permissions, + * or that the permissions is empty (ie, visible by everyone). + */ + if (!nm_auth_is_subject_in_acl (connection, + subject, + &error_desc)) { + error = g_error_new_literal (NM_SETTINGS_ERROR, + NM_SETTINGS_ERROR_PERMISSION_DENIED, + error_desc); + g_free (error_desc); goto done; + } /* If the caller is the only user in the connection's permissions, then * we use the 'modify.own' permission instead of 'modify.system'. If the @@ -1335,30 +1312,30 @@ done: } static void -settings_add_connection_add_cb (NMSettings *self, - NMSettingsConnection *connection, - GError *error, - GDBusMethodInvocation *context, - NMAuthSubject *subject, - gpointer user_data) +impl_settings_add_connection_add_cb (NMSettings *self, + NMSettingsConnection *connection, + GError *error, + GDBusMethodInvocation *context, + NMAuthSubject *subject, + gpointer user_data) { if (error) { g_dbus_method_invocation_return_gerror (context, error); nm_audit_log_connection_op (NM_AUDIT_OP_CONN_ADD, NULL, FALSE, NULL, subject, error->message); } else { - g_dbus_method_invocation_return_value (context, - g_variant_new ("(o)", - nm_dbus_object_get_path (NM_DBUS_OBJECT (connection)))); + g_dbus_method_invocation_return_value ( + context, + g_variant_new ("(o)", nm_connection_get_path (NM_CONNECTION (connection)))); nm_audit_log_connection_op (NM_AUDIT_OP_CONN_ADD, connection, TRUE, NULL, subject, NULL); } } static void -settings_add_connection_helper (NMSettings *self, - GDBusMethodInvocation *context, - GVariant *settings, - gboolean save_to_disk) +impl_settings_add_connection_helper (NMSettings *self, + GDBusMethodInvocation *context, + GVariant *settings, + gboolean save_to_disk) { gs_unref_object NMConnection *connection = NULL; GError *error = NULL; @@ -1378,111 +1355,77 @@ settings_add_connection_helper (NMSettings *self, connection, save_to_disk, context, - settings_add_connection_add_cb, + impl_settings_add_connection_add_cb, NULL); } static void -impl_settings_add_connection (NMDBusObject *obj, - const NMDBusInterfaceInfoExtended *interface_info, - const NMDBusMethodInfoExtended *method_info, - GDBusConnection *connection, - const char *sender, - GDBusMethodInvocation *invocation, - GVariant *parameters) +impl_settings_add_connection (NMSettings *self, + GDBusMethodInvocation *context, + GVariant *settings) { - NMSettings *self = NM_SETTINGS (obj); - gs_unref_variant GVariant *settings = NULL; - - g_variant_get (parameters, "(@a{sa{sv}})", &settings); - settings_add_connection_helper (self, invocation, settings, TRUE); + impl_settings_add_connection_helper (self, context, settings, TRUE); } static void -impl_settings_add_connection_unsaved (NMDBusObject *obj, - const NMDBusInterfaceInfoExtended *interface_info, - const NMDBusMethodInfoExtended *method_info, - GDBusConnection *connection, - const char *sender, - GDBusMethodInvocation *invocation, - GVariant *parameters) +impl_settings_add_connection_unsaved (NMSettings *self, + GDBusMethodInvocation *context, + GVariant *settings) { - NMSettings *self = NM_SETTINGS (obj); - gs_unref_variant GVariant *settings = NULL; - - g_variant_get (parameters, "(@a{sa{sv}})", &settings); - settings_add_connection_helper (self, invocation, settings, FALSE); + impl_settings_add_connection_helper (self, context, settings, FALSE); } static void -impl_settings_load_connections (NMDBusObject *obj, - const NMDBusInterfaceInfoExtended *interface_info, - const NMDBusMethodInfoExtended *method_info, - GDBusConnection *connection, - const char *sender, - GDBusMethodInvocation *invocation, - GVariant *parameters) +impl_settings_load_connections (NMSettings *self, + GDBusMethodInvocation *context, + char **filenames) { - NMSettings *self = NM_SETTINGS (obj); NMSettingsPrivate *priv = NM_SETTINGS_GET_PRIVATE (self); - gs_unref_ptrarray GPtrArray *failures = NULL; + GPtrArray *failures; GSList *iter; - guint i; - gs_free const char **filenames = NULL; - - g_variant_get (parameters, "(^a&s)", &filenames); + int i; /* The permission is already enforced by the D-Bus daemon, but we ensure * that the caller is still alive so that clients are forced to wait and * we'll be able to switch to polkit without breaking behavior. */ - if (!nm_dbus_manager_ensure_uid (nm_dbus_object_get_manager (obj), - invocation, - G_MAXULONG, - NM_SETTINGS_ERROR, - NM_SETTINGS_ERROR_PERMISSION_DENIED)) + if (!nm_bus_manager_ensure_uid (nm_bus_manager_get (), + context, + G_MAXULONG, + NM_SETTINGS_ERROR, + NM_SETTINGS_ERROR_PERMISSION_DENIED)) return; - if (filenames) { - for (i = 0; filenames[i]; i++) { - for (iter = priv->plugins; iter; iter = g_slist_next (iter)) { - NMSettingsPlugin *plugin = NM_SETTINGS_PLUGIN (iter->data); + failures = g_ptr_array_new (); - if (nm_settings_plugin_load_connection (plugin, filenames[i])) - break; - } + for (i = 0; filenames[i]; i++) { + for (iter = priv->plugins; iter; iter = g_slist_next (iter)) { + NMSettingsPlugin *plugin = NM_SETTINGS_PLUGIN (iter->data); - if (!iter) { - if (!g_path_is_absolute (filenames[i])) - _LOGW ("connection filename '%s' is not an absolute path", filenames[i]); - if (!failures) - failures = g_ptr_array_new (); - g_ptr_array_add (failures, (char *) filenames[i]); - } + if (nm_settings_plugin_load_connection (plugin, filenames[i])) + break; } - } - if (failures) - g_ptr_array_add (failures, NULL); + if (!iter) { + if (!g_path_is_absolute (filenames[i])) + _LOGW ("connection filename '%s' is not an absolute path", filenames[i]); + g_ptr_array_add (failures, (char *) filenames[i]); + } + } - g_dbus_method_invocation_return_value (invocation, - g_variant_new ("(b^as)", - (gboolean) (!!failures), - failures - ? (const char **) failures->pdata - : NM_PTRARRAY_EMPTY (const char *))); + g_ptr_array_add (failures, NULL); + g_dbus_method_invocation_return_value ( + context, + g_variant_new ("(b^as)", + failures->len == 1, + failures->pdata)); + g_ptr_array_unref (failures); } static void -impl_settings_reload_connections (NMDBusObject *obj, - const NMDBusInterfaceInfoExtended *interface_info, - const NMDBusMethodInfoExtended *method_info, - GDBusConnection *connection, - const char *sender, - GDBusMethodInvocation *invocation, - GVariant *parameters) +impl_settings_reload_connections (NMSettings *self, + GDBusMethodInvocation *context) { - NMSettings *self = NM_SETTINGS (obj); NMSettingsPrivate *priv = NM_SETTINGS_GET_PRIVATE (self); GSList *iter; @@ -1490,11 +1433,11 @@ impl_settings_reload_connections (NMDBusObject *obj, * that the caller is still alive so that clients are forced to wait and * we'll be able to switch to polkit without breaking behavior. */ - if (!nm_dbus_manager_ensure_uid (nm_dbus_object_get_manager (obj), - invocation, - G_MAXULONG, - NM_SETTINGS_ERROR, - NM_SETTINGS_ERROR_PERMISSION_DENIED)) + if (!nm_bus_manager_ensure_uid (nm_bus_manager_get (), + context, + G_MAXULONG, + NM_SETTINGS_ERROR, + NM_SETTINGS_ERROR_PERMISSION_DENIED)) return; for (iter = priv->plugins; iter; iter = g_slist_next (iter)) { @@ -1503,7 +1446,7 @@ impl_settings_reload_connections (NMDBusObject *obj, nm_settings_plugin_reload_connections (plugin); } - g_dbus_method_invocation_return_value (invocation, g_variant_new ("(b)", TRUE)); + g_dbus_method_invocation_return_value (context, g_variant_new ("(b)", TRUE)); } /*****************************************************************************/ @@ -1551,46 +1494,41 @@ pk_hostname_cb (NMAuthChain *chain, else g_dbus_method_invocation_return_value (context, NULL); - nm_auth_chain_destroy (chain); + nm_auth_chain_unref (chain); } static void -impl_settings_save_hostname (NMDBusObject *obj, - const NMDBusInterfaceInfoExtended *interface_info, - const NMDBusMethodInfoExtended *method_info, - GDBusConnection *connection, - const char *sender, - GDBusMethodInvocation *invocation, - GVariant *parameters) +impl_settings_save_hostname (NMSettings *self, + GDBusMethodInvocation *context, + const char *hostname) { - NMSettings *self = NM_SETTINGS (obj); NMSettingsPrivate *priv = NM_SETTINGS_GET_PRIVATE (self); NMAuthChain *chain; - const char *hostname; - - g_variant_get (parameters, "(&s)", &hostname); + GError *error = NULL; /* Minimal validation of the hostname */ if (!nm_hostname_manager_validate_hostname (hostname)) { - g_dbus_method_invocation_return_error_literal (invocation, - NM_SETTINGS_ERROR, - NM_SETTINGS_ERROR_INVALID_HOSTNAME, - "The hostname was too long or contained invalid characters."); - return; + error = g_error_new_literal (NM_SETTINGS_ERROR, + NM_SETTINGS_ERROR_INVALID_HOSTNAME, + "The hostname was too long or contained invalid characters."); + goto done; } - chain = nm_auth_chain_new_context (invocation, pk_hostname_cb, self); + chain = nm_auth_chain_new_context (context, pk_hostname_cb, self); if (!chain) { - g_dbus_method_invocation_return_error_literal (invocation, - NM_SETTINGS_ERROR, - NM_SETTINGS_ERROR_PERMISSION_DENIED, - "Unable to authenticate the request."); - return; + error = g_error_new_literal (NM_SETTINGS_ERROR, + NM_SETTINGS_ERROR_PERMISSION_DENIED, + "Unable to authenticate the request."); + goto done; } priv->auths = g_slist_append (priv->auths, chain); nm_auth_chain_add_call (chain, NM_AUTH_PERMISSION_SETTINGS_MODIFY_HOSTNAME, TRUE); nm_auth_chain_set_data (chain, "hostname", g_strdup (hostname), g_free); + +done: + if (error) + g_dbus_method_invocation_take_error (context, error); } /*****************************************************************************/ @@ -1599,24 +1537,27 @@ static gboolean have_connection_for_device (NMSettings *self, NMDevice *device) { NMSettingsPrivate *priv = NM_SETTINGS_GET_PRIVATE (self); + GHashTableIter iter; + gpointer data; NMSettingConnection *s_con; NMSettingWired *s_wired; const char *setting_hwaddr; const char *perm_hw_addr; - NMSettingsConnection *connection; g_return_val_if_fail (NM_IS_SETTINGS (self), FALSE); perm_hw_addr = nm_device_get_permanent_hw_address (device); /* Find a wired connection locked to the given MAC address, if any */ - c_list_for_each_entry (connection, &priv->connections_lst_head, _connections_lst) { + g_hash_table_iter_init (&iter, priv->connections); + while (g_hash_table_iter_next (&iter, NULL, &data)) { + NMConnection *connection = NM_CONNECTION (data); const char *ctype, *iface; - if (!nm_device_check_connection_compatible (device, NM_CONNECTION (connection))) + if (!nm_device_check_connection_compatible (device, connection)) continue; - s_con = nm_connection_get_setting_connection (NM_CONNECTION (connection)); + s_con = nm_connection_get_setting_connection (connection); iface = nm_setting_connection_get_interface_name (s_con); if (iface && strcmp (iface, nm_device_get_iface (device)) != 0) @@ -1627,7 +1568,7 @@ have_connection_for_device (NMSettings *self, NMDevice *device) && strcmp (ctype, NM_SETTING_PPPOE_SETTING_NAME)) continue; - s_wired = nm_connection_get_setting_wired (NM_CONNECTION (connection)); + s_wired = nm_connection_get_setting_wired (connection); if (!s_wired && !strcmp (ctype, NM_SETTING_PPPOE_SETTING_NAME)) { /* No wired setting; therefore the PPPoE connection applies to any device */ @@ -1655,6 +1596,26 @@ have_connection_for_device (NMSettings *self, NMDevice *device) return FALSE; } +static void default_wired_clear_tag (NMSettings *self, + NMDevice *device, + NMSettingsConnection *connection, + gboolean add_to_no_auto_default); + +static void +default_wired_connection_removed_cb (NMSettingsConnection *connection, NMSettings *self) +{ + NMDevice *device; + + /* When the default wired connection is removed (either deleted or saved to + * a new persistent connection by a plugin), write the MAC address of the + * wired device to the config file and don't create a new default wired + * connection for that device again. + */ + device = g_object_get_qdata (G_OBJECT (connection), _default_wired_device_quark ()); + if (device) + default_wired_clear_tag (self, device, connection, TRUE); +} + static void default_wired_connection_updated_by_user_cb (NMSettingsConnection *connection, gboolean by_user, NMSettings *self) { @@ -1687,6 +1648,7 @@ default_wired_clear_tag (NMSettings *self, g_object_set_qdata (G_OBJECT (connection), _default_wired_device_quark (), NULL); g_object_set_qdata (G_OBJECT (device), _default_wired_connection_quark (), NULL); + g_signal_handlers_disconnect_by_func (connection, G_CALLBACK (default_wired_connection_removed_cb), self); g_signal_handlers_disconnect_by_func (connection, G_CALLBACK (default_wired_connection_updated_by_user_cb), self); if (add_to_no_auto_default) @@ -1738,6 +1700,8 @@ device_realized (NMDevice *device, GParamSpec *pspec, NMSettings *self) g_signal_connect (added, NM_SETTINGS_CONNECTION_UPDATED_INTERNAL, G_CALLBACK (default_wired_connection_updated_by_user_cb), self); + g_signal_connect (added, NM_SETTINGS_CONNECTION_REMOVED, + G_CALLBACK (default_wired_connection_removed_cb), self); _LOGI ("(%s): created default wired connection '%s'", nm_device_get_iface (device), @@ -1810,8 +1774,10 @@ nm_settings_start (NMSettings *self, GError **error) /* Load the plugins; fail if a plugin is not found. */ plugins = nm_config_data_get_plugins (nm_config_get_data_orig (priv->config), TRUE); - if (!load_plugins (self, (const char **) plugins, error)) + if (!load_plugins (self, (const char **) plugins, error)) { + g_object_unref (self); return FALSE; + } load_connections (self); check_startup_complete (self); @@ -1836,19 +1802,18 @@ get_property (GObject *object, guint prop_id, NMSettings *self = NM_SETTINGS (object); NMSettingsPrivate *priv = NM_SETTINGS_GET_PRIVATE (self); const GSList *specs, *iter; - guint i; - char **strvs; - const char **strv; + GHashTableIter citer; + GPtrArray *array; + const char *path; switch (prop_id) { case PROP_UNMANAGED_SPECS: + array = g_ptr_array_new (); specs = nm_settings_get_unmanaged_specs (self); - strvs = g_new (char *, g_slist_length ((GSList *) specs) + 1); - i = 0; - for (iter = specs; iter; iter = iter->next) - strvs[i++] = g_strdup (iter->data); - strvs[i] = NULL; - g_value_take_boxed (value, strvs); + for (iter = specs; iter; iter = g_slist_next (iter)) + g_ptr_array_add (array, g_strdup (iter->data)); + g_ptr_array_add (array, NULL); + g_value_take_boxed (value, (char **) g_ptr_array_free (array, FALSE)); break; case PROP_HOSTNAME: g_value_set_string (value, @@ -1860,14 +1825,12 @@ get_property (GObject *object, guint prop_id, g_value_set_boolean (value, !!get_plugin (self, NM_SETTINGS_PLUGIN_CAP_MODIFY_CONNECTIONS)); break; case PROP_CONNECTIONS: - if (priv->connections_loaded) { - strv = nm_dbus_utils_get_paths_for_clist (&priv->connections_lst_head, - priv->connections_len, - G_STRUCT_OFFSET (NMSettingsConnection, _connections_lst), - TRUE); - g_value_take_boxed (value, nm_utils_strv_make_deep_copied (strv)); - } else - g_value_set_boxed (value, NULL); + array = g_ptr_array_sized_new (g_hash_table_size (priv->connections) + 1); + g_hash_table_iter_init (&citer, priv->connections); + while (g_hash_table_iter_next (&citer, (gpointer) &path, NULL)) + g_ptr_array_add (array, g_strdup (path)); + g_ptr_array_add (array, NULL); + g_value_take_boxed (value, (char **) g_ptr_array_free (array, FALSE)); break; case PROP_STARTUP_COMPLETE: g_value_set_boolean (value, nm_settings_get_startup_complete (self)); @@ -1885,7 +1848,7 @@ nm_settings_init (NMSettings *self) { NMSettingsPrivate *priv = NM_SETTINGS_GET_PRIVATE (self); - c_list_init (&priv->connections_lst_head); + priv->connections = g_hash_table_new_full (nm_str_hash, g_str_equal, NULL, g_object_unref); priv->agent_mgr = g_object_ref (nm_agent_manager_get ()); priv->config = g_object_ref (nm_config_get ()); @@ -1903,9 +1866,11 @@ dispose (GObject *object) NMSettings *self = NM_SETTINGS (object); NMSettingsPrivate *priv = NM_SETTINGS_GET_PRIVATE (self); - g_slist_free_full (priv->auths, (GDestroyNotify) nm_auth_chain_destroy); + g_slist_free_full (priv->auths, (GDestroyNotify) nm_auth_chain_unref); priv->auths = NULL; + g_object_unref (priv->agent_mgr); + if (priv->hostname_manager) { g_signal_handlers_disconnect_by_func (priv->hostname_manager, G_CALLBACK (_hostname_changed_cb), @@ -1922,139 +1887,26 @@ finalize (GObject *object) NMSettings *self = NM_SETTINGS (object); NMSettingsPrivate *priv = NM_SETTINGS_GET_PRIVATE (self); - _clear_connections_cached_list (priv); - - nm_assert (c_list_is_empty (&priv->connections_lst_head)); + g_hash_table_destroy (priv->connections); + g_clear_pointer (&priv->connections_cached_list, g_free); g_slist_free_full (priv->unmanaged_specs, g_free); g_slist_free_full (priv->unrecognized_specs, g_free); g_slist_free_full (priv->plugins, g_object_unref); - g_clear_object (&priv->agent_mgr); - g_clear_object (&priv->config); G_OBJECT_CLASS (nm_settings_parent_class)->finalize (object); } -static const GDBusSignalInfo signal_info_new_connection = NM_DEFINE_GDBUS_SIGNAL_INFO_INIT ( - "NewConnection", - .args = NM_DEFINE_GDBUS_ARG_INFOS ( - NM_DEFINE_GDBUS_ARG_INFO ("connection", "o"), - ), -); - -static const GDBusSignalInfo signal_info_connection_removed = NM_DEFINE_GDBUS_SIGNAL_INFO_INIT ( - "ConnectionRemoved", - .args = NM_DEFINE_GDBUS_ARG_INFOS ( - NM_DEFINE_GDBUS_ARG_INFO ("connection", "o"), - ), -); - -static const NMDBusInterfaceInfoExtended interface_info_settings = { - .parent = NM_DEFINE_GDBUS_INTERFACE_INFO_INIT ( - NM_DBUS_INTERFACE_SETTINGS, - .methods = NM_DEFINE_GDBUS_METHOD_INFOS ( - NM_DEFINE_DBUS_METHOD_INFO_EXTENDED ( - NM_DEFINE_GDBUS_METHOD_INFO_INIT ( - "ListConnections", - .out_args = NM_DEFINE_GDBUS_ARG_INFOS ( - NM_DEFINE_GDBUS_ARG_INFO ("connections", "ao"), - ), - ), - .handle = impl_settings_list_connections, - ), - NM_DEFINE_DBUS_METHOD_INFO_EXTENDED ( - NM_DEFINE_GDBUS_METHOD_INFO_INIT ( - "GetConnectionByUuid", - .in_args = NM_DEFINE_GDBUS_ARG_INFOS ( - NM_DEFINE_GDBUS_ARG_INFO ("uuid", "s"), - ), - .out_args = NM_DEFINE_GDBUS_ARG_INFOS ( - NM_DEFINE_GDBUS_ARG_INFO ("connection", "o"), - ), - ), - .handle = impl_settings_get_connection_by_uuid, - ), - NM_DEFINE_DBUS_METHOD_INFO_EXTENDED ( - NM_DEFINE_GDBUS_METHOD_INFO_INIT ( - "AddConnection", - .in_args = NM_DEFINE_GDBUS_ARG_INFOS ( - NM_DEFINE_GDBUS_ARG_INFO ("connection", "a{sa{sv}}"), - ), - .out_args = NM_DEFINE_GDBUS_ARG_INFOS ( - NM_DEFINE_GDBUS_ARG_INFO ("path", "o"), - ), - ), - .handle = impl_settings_add_connection, - ), - NM_DEFINE_DBUS_METHOD_INFO_EXTENDED ( - NM_DEFINE_GDBUS_METHOD_INFO_INIT ( - "AddConnectionUnsaved", - .in_args = NM_DEFINE_GDBUS_ARG_INFOS ( - NM_DEFINE_GDBUS_ARG_INFO ("connection", "a{sa{sv}}"), - ), - .out_args = NM_DEFINE_GDBUS_ARG_INFOS ( - NM_DEFINE_GDBUS_ARG_INFO ("path", "o"), - ), - ), - .handle = impl_settings_add_connection_unsaved, - ), - NM_DEFINE_DBUS_METHOD_INFO_EXTENDED ( - NM_DEFINE_GDBUS_METHOD_INFO_INIT ( - "LoadConnections", - .in_args = NM_DEFINE_GDBUS_ARG_INFOS ( - NM_DEFINE_GDBUS_ARG_INFO ("filenames", "as"), - ), - .out_args = NM_DEFINE_GDBUS_ARG_INFOS ( - NM_DEFINE_GDBUS_ARG_INFO ("status", "b"), - NM_DEFINE_GDBUS_ARG_INFO ("failures", "as"), - ), - ), - .handle = impl_settings_load_connections, - ), - NM_DEFINE_DBUS_METHOD_INFO_EXTENDED ( - NM_DEFINE_GDBUS_METHOD_INFO_INIT ( - "ReloadConnections", - .out_args = NM_DEFINE_GDBUS_ARG_INFOS ( - NM_DEFINE_GDBUS_ARG_INFO ("status", "b"), - ), - ), - .handle = impl_settings_reload_connections, - ), - NM_DEFINE_DBUS_METHOD_INFO_EXTENDED ( - NM_DEFINE_GDBUS_METHOD_INFO_INIT ( - "SaveHostname", - .in_args = NM_DEFINE_GDBUS_ARG_INFOS ( - NM_DEFINE_GDBUS_ARG_INFO ("hostname", "s"), - ), - ), - .handle = impl_settings_save_hostname, - ), - ), - .signals = NM_DEFINE_GDBUS_SIGNAL_INFOS ( - &nm_signal_info_property_changed_legacy, - &signal_info_new_connection, - &signal_info_connection_removed, - ), - .properties = NM_DEFINE_GDBUS_PROPERTY_INFOS ( - NM_DEFINE_DBUS_PROPERTY_INFO_EXTENDED_READABLE_L ("Connections", "ao", NM_SETTINGS_CONNECTIONS), - NM_DEFINE_DBUS_PROPERTY_INFO_EXTENDED_READABLE_L ("Hostname", "s", NM_SETTINGS_HOSTNAME), - NM_DEFINE_DBUS_PROPERTY_INFO_EXTENDED_READABLE_L ("CanModify", "b", NM_SETTINGS_CAN_MODIFY), - ), - ), - .legacy_property_changed = TRUE, -}; - static void nm_settings_class_init (NMSettingsClass *class) { GObjectClass *object_class = G_OBJECT_CLASS (class); - NMDBusObjectClass *dbus_object_class = NM_DBUS_OBJECT_CLASS (class); + NMExportedObjectClass *exported_object_class = NM_EXPORTED_OBJECT_CLASS (class); - dbus_object_class->export_path = NM_DBUS_EXPORT_PATH_STATIC (NM_DBUS_PATH_SETTINGS); - dbus_object_class->interface_infos = NM_DBUS_INTERFACE_INFOS (&interface_info_settings); + exported_object_class->export_path = NM_DBUS_PATH_SETTINGS; object_class->get_property = get_property; object_class->dispose = dispose; @@ -2123,4 +1975,23 @@ nm_settings_class_init (NMSettingsClass *class) 0, NULL, NULL, g_cclosure_marshal_VOID__OBJECT, G_TYPE_NONE, 1, NM_TYPE_SETTINGS_CONNECTION); + + signals[NEW_CONNECTION] = + g_signal_new ("new-connection", + G_OBJECT_CLASS_TYPE (object_class), + G_SIGNAL_RUN_FIRST, 0, NULL, NULL, + g_cclosure_marshal_VOID__OBJECT, + G_TYPE_NONE, 1, NM_TYPE_SETTINGS_CONNECTION); + + nm_exported_object_class_add_interface (NM_EXPORTED_OBJECT_CLASS (class), + NMDBUS_TYPE_SETTINGS_SKELETON, + "ListConnections", impl_settings_list_connections, + "GetConnectionByUuid", impl_settings_get_connection_by_uuid, + "AddConnection", impl_settings_add_connection, + "AddConnectionUnsaved", impl_settings_add_connection_unsaved, + "LoadConnections", impl_settings_load_connections, + "ReloadConnections", impl_settings_reload_connections, + "SaveHostname", impl_settings_save_hostname, + NULL); } + diff --git a/src/settings/nm-settings.h b/src/settings/nm-settings.h index 7d56f7b4..0ecffb70 100644 --- a/src/settings/nm-settings.h +++ b/src/settings/nm-settings.h @@ -28,6 +28,8 @@ #include "nm-connection.h" +#include "nm-exported-object.h" + #define NM_TYPE_SETTINGS (nm_settings_get_type ()) #define NM_SETTINGS(obj) (G_TYPE_CHECK_INSTANCE_CAST ((obj), NM_TYPE_SETTINGS, NMSettings)) #define NM_SETTINGS_CLASS(klass) (G_TYPE_CHECK_CLASS_CAST ((klass), NM_TYPE_SETTINGS, NMSettingsClass)) @@ -70,6 +72,14 @@ NMSettings *nm_settings_get (void); NMSettings *nm_settings_new (void); gboolean nm_settings_start (NMSettings *self, GError **error); +typedef void (*NMSettingsForEachFunc) (NMSettings *settings, + NMSettingsConnection *connection, + gpointer user_data); + +void nm_settings_for_each_connection (NMSettings *settings, + NMSettingsForEachFunc for_each_func, + gpointer user_data); + typedef void (*NMSettingsAddCallback) (NMSettings *settings, NMSettingsConnection *connection, GError *error, diff --git a/src/settings/plugins/ibft/meson.build b/src/settings/plugins/ibft/meson.build deleted file mode 100644 index da9f5566..00000000 --- a/src/settings/plugins/ibft/meson.build +++ /dev/null @@ -1,48 +0,0 @@ -name = 'nm-settings-plugin-ibft' - -cflags = [ - '-DSBINDIR="@0@"'.format(nm_sbindir), - '-DSYSCONFDIR="@0@"'.format(nm_sysconfdir) -] - -libnms_ibft_core = static_library( - 'nms-ibft-core', - 'nms-ibft-reader.c', - dependencies: nm_dep, - c_args: cflags -) - -sources = files( - 'nms-ibft-connection.c', - 'nms-ibft-plugin.c' -) - -libnm_settings_plugin_ibft = shared_module( - name, - sources: sources, - dependencies: nm_dep, - c_args: cflags, - link_with: libnms_ibft_core, - link_args: ldflags_linker_script_settings, - link_depends: linker_script_settings, - install: true, - install_dir: nm_pkglibdir -) - -core_plugins += libnm_settings_plugin_ibft - -# FIXME: check_so_symbols replacement -''' -run_target( - 'check-local-symbols-settings-ibft', - command: [check_so_symbols, libnm_settings_plugin_ibft.full_path()], - depends: libnm_settings_plugin_ibft -) - -check-local-symbols-settings-ibft: src/settings/plugins/ibft/libnm-settings-plugin-ibft.la - $(call check_so_symbols,$(builddir)/src/settings/plugins/ibft/.libs/libnm-settings-plugin-ibft.so) -''' - -if enable_tests - subdir('tests') -endif diff --git a/src/settings/plugins/ibft/tests/meson.build b/src/settings/plugins/ibft/tests/meson.build deleted file mode 100644 index 7a9445dd..00000000 --- a/src/settings/plugins/ibft/tests/meson.build +++ /dev/null @@ -1,22 +0,0 @@ -test_unit = 'test-ibft' - -test_ibft_dir = meson.current_source_dir() - -cflags = [ - '-DTEST_IBFT_DIR="@0@"'.format(test_ibft_dir), - '-DTEST_SCRATCH_DIR="@0@"'.format(test_ibft_dir) -] - -exe = executable( - test_unit, - test_unit + '.c', - dependencies: test_nm_dep, - c_args: cflags, - link_with: libnms_ibft_core -) - -test( - 'ibft/' + test_unit, - test_script, - args: test_args + [exe.full_path()] -) diff --git a/src/settings/plugins/ibft/tests/test-ibft.c b/src/settings/plugins/ibft/tests/test-ibft.c index fd2ec61b..72d1a7db 100644 --- a/src/settings/plugins/ibft/tests/test-ibft.c +++ b/src/settings/plugins/ibft/tests/test-ibft.c @@ -181,7 +181,7 @@ test_read_ibft_malformed (gconstpointer user_data) g_assert (g_file_test (iscsiadm_path, G_FILE_TEST_EXISTS)); - NMTST_EXPECT_NM_WARN ("*malformed iscsiadm record*"); + g_test_expect_message ("NetworkManager", G_LOG_LEVEL_MESSAGE, "*malformed iscsiadm record*"); success = nms_ibft_reader_load_blocks (iscsiadm_path, &blocks, &error); g_assert_no_error (error); diff --git a/src/settings/plugins/ifcfg-rh/meson.build b/src/settings/plugins/ifcfg-rh/meson.build deleted file mode 100644 index fdf308be..00000000 --- a/src/settings/plugins/ifcfg-rh/meson.build +++ /dev/null @@ -1,77 +0,0 @@ -install_data( - 'nm-ifcfg-rh.conf', - install_dir: dbus_conf_dir -) - -cflags = [ - '-DSBINDIR="@0@"'.format(nm_sbindir), - '-DSYSCONFDIR="@0@"'.format(nm_sysconfdir) -] - -name = 'nmdbus-ifcfg-rh' - -dbus_sources = gnome.gdbus_codegen( - name, - 'nm-ifcfg-rh.xml', - interface_prefix: 'com.redhat', - namespace: 'NMDBus' -) - -libnmdbus_ifcfg_rh = static_library( - name, - sources: dbus_sources, - dependencies: glib_dep, - c_args: cflags -) - -sources = files( - 'nm-inotify-helper.c', - 'nms-ifcfg-rh-reader.c', - 'nms-ifcfg-rh-utils.c', - 'nms-ifcfg-rh-writer.c', - 'shvar.c' -) - -deps = [ - crypto_dep, - nm_dep -] - -libnms_ifcfg_rh_core = static_library( - 'nms-ifcfg-rh-core', - sources: sources, - dependencies: deps, - c_args: cflags -) - -sources = [dbus_sources] + files('nms-ifcfg-rh-connection.c') - -libnm_settings_plugin_ifcfg_rh = shared_module( - 'nm-settings-plugin-ifcfg-rh', - sources: sources, - dependencies: deps, - c_args: cflags, - link_with: [libnms_ifcfg_rh_core], - link_args: ldflags_linker_script_settings, - link_depends: linker_script_settings, - install: true, - install_dir: nm_pkglibdir -) - -core_plugins += libnm_settings_plugin_ifcfg_rh - -# FIXME: check_so_symbols replacement -''' -run_target( - 'check-local-symbols-settings-ifcfg-rh', - command: [check_so_symbols, libnm_settings_plugin_ifcfg_rh.full_path()], - depends: libnm_settings_plugin_ifcfg_rh -) - -check-local-symbols-settings-ifcfg-rh: src/settings/plugins/ifcfg-rh/libnm-settings-plugin-ifcfg-rh.la - $(call check_so_symbols,$(builddir)/src/settings/plugins/ifcfg-rh/.libs/libnm-settings-plugin-ifcfg-rh.so) -''' - -if enable_tests - subdir('tests') -endif diff --git a/src/settings/plugins/ifcfg-rh/nm-inotify-helper.c b/src/settings/plugins/ifcfg-rh/nm-inotify-helper.c index 2863df64..97417db9 100644 --- a/src/settings/plugins/ifcfg-rh/nm-inotify-helper.c +++ b/src/settings/plugins/ifcfg-rh/nm-inotify-helper.c @@ -172,7 +172,7 @@ nm_inotify_helper_init (NMInotifyHelper *self) { NMInotifyHelperPrivate *priv = NM_INOTIFY_HELPER_GET_PRIVATE (self); - priv->wd_refs = g_hash_table_new (nm_direct_hash, NULL); + priv->wd_refs = g_hash_table_new (g_direct_hash, g_direct_equal); } static void diff --git a/src/settings/plugins/ifcfg-rh/nms-ifcfg-rh-plugin.c b/src/settings/plugins/ifcfg-rh/nms-ifcfg-rh-plugin.c index c7207297..0743fc9f 100644 --- a/src/settings/plugins/ifcfg-rh/nms-ifcfg-rh-plugin.c +++ b/src/settings/plugins/ifcfg-rh/nms-ifcfg-rh-plugin.c @@ -37,6 +37,7 @@ #include "settings/nm-settings-plugin.h" #include "nm-config.h" #include "NetworkManagerUtils.h" +#include "nm-exported-object.h" #include "nms-ifcfg-rh-connection.h" #include "nms-ifcfg-rh-common.h" @@ -45,10 +46,10 @@ #include "nms-ifcfg-rh-utils.h" #include "shvar.h" -#define IFCFGRH1_BUS_NAME "com.redhat.ifcfgrh1" -#define IFCFGRH1_OBJECT_PATH "/com/redhat/ifcfgrh1" -#define IFCFGRH1_IFACE1_NAME "com.redhat.ifcfgrh1" -#define IFCFGRH1_IFACE1_METHOD_GET_IFCFG_DETAILS "GetIfcfgDetails" +#include "settings/plugins/ifcfg-rh/nmdbus-ifcfg-rh.h" + +#define IFCFGRH1_DBUS_SERVICE_NAME "com.redhat.ifcfgrh1" +#define IFCFGRH1_DBUS_OBJECT_PATH "/com/redhat/ifcfgrh1" /*****************************************************************************/ @@ -57,9 +58,9 @@ typedef struct { struct { GDBusConnection *connection; + GDBusInterfaceSkeleton *interface; GCancellable *cancellable; gulong signal_id; - guint regist_id; } dbus; GHashTable *connections; /* uuid::connection */ @@ -326,21 +327,21 @@ update_connection (SettingsPluginIfcfg *self, if (new_unmanaged || new_unrecognized) { if (!old_unmanaged && !old_unrecognized) { - /* ref connection first, because we put it into priv->connections below. - * Emitting signal-removed might otherwise delete it. */ g_object_ref (connection_by_uuid); - /* Unexport the connection by telling the settings service it's * been removed. */ nm_settings_connection_signal_remove (NM_SETTINGS_CONNECTION (connection_by_uuid)); + /* Remove the path so that claim_connection() doesn't complain later when + * interface gets managed and connection is re-added. */ + nm_connection_set_path (NM_CONNECTION (connection_by_uuid), NULL); /* signal_remove() will end up removing the connection from our hash, * so add it back now. */ g_hash_table_insert (priv->connections, g_strdup (nm_connection_get_uuid (NM_CONNECTION (connection_by_uuid))), - connection_by_uuid /* we took reference above and pass it on */); + connection_by_uuid); } } else { if (old_unmanaged /* && !new_unmanaged */) { @@ -372,9 +373,7 @@ update_connection (SettingsPluginIfcfg *self, _LOGI ("add connection "NM_IFCFG_CONNECTION_LOG_FMT, NM_IFCFG_CONNECTION_LOG_ARG (connection_new)); else _LOGI ("new connection "NM_IFCFG_CONNECTION_LOG_FMT, NM_IFCFG_CONNECTION_LOG_ARG (connection_new)); - g_hash_table_insert (priv->connections, - g_strdup (uuid), - connection_new /* take reference */); + g_hash_table_insert (priv->connections, g_strdup (uuid), connection_new); g_signal_connect (connection_new, NM_SETTINGS_CONNECTION_REMOVED, G_CALLBACK (connection_removed_cb), @@ -517,7 +516,7 @@ read_connections (SettingsPluginIfcfg *plugin) return; } - alive_connections = g_hash_table_new (nm_direct_hash, NULL); + alive_connections = g_hash_table_new (NULL, NULL); filenames = g_ptr_array_new_with_free_func (g_free); while ((item = g_dir_read_name (dir))) { @@ -750,7 +749,7 @@ impl_ifcfgrh_get_ifcfg_details (SettingsPluginIfcfg *plugin, return; } - path = nm_dbus_object_get_path (NM_DBUS_OBJECT (connection)); + path = nm_connection_get_path (NM_CONNECTION (connection)); if (!path) { g_dbus_method_invocation_return_error (context, NM_SETTINGS_ERROR, @@ -769,15 +768,15 @@ static void _dbus_clear (SettingsPluginIfcfg *self) { SettingsPluginIfcfgPrivate *priv = SETTINGS_PLUGIN_IFCFG_GET_PRIVATE (self); - guint id; nm_clear_g_signal_handler (priv->dbus.connection, &priv->dbus.signal_id); nm_clear_g_cancellable (&priv->dbus.cancellable); - if ((id = nm_steal_int (&priv->dbus.regist_id))) { - if (!g_dbus_connection_unregister_object (priv->dbus.connection, id)) - _LOGW ("dbus: unexpected failure to unregister object"); + if (priv->dbus.interface) { + g_dbus_interface_skeleton_unexport (priv->dbus.interface); + nm_exported_object_skeleton_release (priv->dbus.interface); + priv->dbus.interface = NULL; } g_clear_object (&priv->dbus.connection); @@ -789,56 +788,13 @@ _dbus_connection_closed (GDBusConnection *connection, GError *error, gpointer user_data) { - _LOGW ("dbus: %s bus closed", IFCFGRH1_BUS_NAME); + _LOGW ("dbus: %s bus closed", IFCFGRH1_DBUS_SERVICE_NAME); _dbus_clear (SETTINGS_PLUGIN_IFCFG (user_data)); /* Retry or recover? */ } static void -_method_call (GDBusConnection *connection, - const char *sender, - const char *object_path, - const char *interface_name, - const char *method_name, - GVariant *parameters, - GDBusMethodInvocation *invocation, - gpointer user_data) -{ - SettingsPluginIfcfg *self = SETTINGS_PLUGIN_IFCFG (user_data); - const char *ifcfg; - - if ( !nm_streq (interface_name, IFCFGRH1_IFACE1_NAME) - || !nm_streq (method_name, IFCFGRH1_IFACE1_METHOD_GET_IFCFG_DETAILS)) { - g_dbus_method_invocation_return_error (invocation, - G_DBUS_ERROR, - G_DBUS_ERROR_UNKNOWN_METHOD, - "Unknown method %s", - method_name); - return; - } - - g_variant_get (parameters, "(&s)", &ifcfg); - impl_ifcfgrh_get_ifcfg_details (self, invocation, ifcfg); -} - -static GDBusInterfaceInfo *const interface_info = NM_DEFINE_GDBUS_INTERFACE_INFO ( - IFCFGRH1_BUS_NAME, - .methods = NM_DEFINE_GDBUS_METHOD_INFOS ( - NM_DEFINE_GDBUS_METHOD_INFO ( - IFCFGRH1_IFACE1_METHOD_GET_IFCFG_DETAILS, - .in_args = NM_DEFINE_GDBUS_ARG_INFOS ( - NM_DEFINE_GDBUS_ARG_INFO ("ifcfg", "s"), - ), - .out_args = NM_DEFINE_GDBUS_ARG_INFOS ( - NM_DEFINE_GDBUS_ARG_INFO ("uuid", "s"), - NM_DEFINE_GDBUS_ARG_INFO ("path", "o"), - ), - ), - ), -); - -static void _dbus_request_name_done (GObject *source_object, GAsyncResult *res, gpointer user_data) @@ -874,27 +830,36 @@ _dbus_request_name_done (GObject *source_object, } { - static const GDBusInterfaceVTable interface_vtable = { - .method_call = _method_call, + GType skeleton_type = NMDBUS_TYPE_IFCFGRH1_SKELETON; + gs_free char *method_name_get_ifcfg_details = NULL; + NMExportedObjectDBusMethodImpl methods[] = { + { + .method_name = (method_name_get_ifcfg_details = nm_exported_object_skeletonify_method_name ("GetIfcfgDetails")), + .impl = G_CALLBACK (impl_ifcfgrh_get_ifcfg_details), + }, }; - priv->dbus.regist_id = g_dbus_connection_register_object (connection, - IFCFGRH1_OBJECT_PATH, - interface_info, - NM_UNCONST_PTR (GDBusInterfaceVTable, &interface_vtable), - self, - NULL, - &error); - if (!priv->dbus.regist_id) { - _LOGW ("dbus: couldn't register D-Bus service: %s", error->message); + priv->dbus.interface = nm_exported_object_skeleton_create (skeleton_type, + g_type_class_peek (SETTINGS_TYPE_PLUGIN_IFCFG), + methods, + G_N_ELEMENTS (methods), + (GObject *) self); + + if (!g_dbus_interface_skeleton_export (priv->dbus.interface, + priv->dbus.connection, + IFCFGRH1_DBUS_OBJECT_PATH, + &error)) { + nm_exported_object_skeleton_release (priv->dbus.interface); + priv->dbus.interface = NULL; + _LOGW ("dbus: failed exporting interface: %s", error->message); _dbus_clear (self); return; } } _LOGD ("dbus: aquired D-Bus service %s and exported %s object", - IFCFGRH1_BUS_NAME, - IFCFGRH1_OBJECT_PATH); + IFCFGRH1_DBUS_SERVICE_NAME, + IFCFGRH1_DBUS_OBJECT_PATH); } static void @@ -935,7 +900,7 @@ _dbus_create_done (GObject *source_object, DBUS_INTERFACE_DBUS, "RequestName", g_variant_new ("(su)", - IFCFGRH1_BUS_NAME, + IFCFGRH1_DBUS_SERVICE_NAME, DBUS_NAME_FLAG_DO_NOT_QUEUE), G_VARIANT_TYPE ("(u)"), G_DBUS_CALL_FLAGS_NONE, @@ -952,7 +917,7 @@ _dbus_setup (SettingsPluginIfcfg *self) gs_free char *address = NULL; gs_free_error GError *error = NULL; - _dbus_clear (self); + g_return_if_fail (!priv->dbus.connection); address = g_dbus_address_get_for_bus_sync (G_BUS_TYPE_SYSTEM, NULL, &error); if (address == NULL) { @@ -978,22 +943,17 @@ config_changed_cb (NMConfig *config, NMConfigData *old_data, SettingsPluginIfcfg *self) { - SettingsPluginIfcfgPrivate *priv; - /* If the dbus connection for some reason is borked the D-Bus service * won't be offered. * * On SIGHUP and SIGUSR1 try to re-connect to D-Bus. So in the unlikely * event that the D-Bus conneciton is broken, that allows for recovery * without need for restarting NetworkManager. */ - if (!NM_FLAGS_ANY (changes, NM_CONFIG_CHANGE_CAUSE_SIGHUP - | NM_CONFIG_CHANGE_CAUSE_SIGUSR1)) - return; - - priv = SETTINGS_PLUGIN_IFCFG_GET_PRIVATE (self); - if ( !priv->dbus.connection - && !priv->dbus.cancellable) - _dbus_setup (self); + if (NM_FLAGS_ANY (changes, NM_CONFIG_CHANGE_CAUSE_SIGHUP + | NM_CONFIG_CHANGE_CAUSE_SIGUSR1)) { + if (!SETTINGS_PLUGIN_IFCFG_GET_PRIVATE (self)->dbus.connection) + _dbus_setup (self); + } } /*****************************************************************************/ diff --git a/src/settings/plugins/ifcfg-rh/nms-ifcfg-rh-reader.c b/src/settings/plugins/ifcfg-rh/nms-ifcfg-rh-reader.c index 6ef3f660..c91cd253 100644 --- a/src/settings/plugins/ifcfg-rh/nms-ifcfg-rh-reader.c +++ b/src/settings/plugins/ifcfg-rh/nms-ifcfg-rh-reader.c @@ -181,7 +181,7 @@ make_connection_setting (const char *file, const char *v; gs_free char *stable_id = NULL; const char *const *iter; - int vint64, i_val; + int vint64; ifcfg_name = utils_get_ifcfg_name (file, TRUE); if (!ifcfg_name) @@ -338,13 +338,6 @@ make_connection_setting (const char *file, vint64 = svGetValueInt64 (ifcfg, "AUTH_RETRIES", 10, -1, G_MAXINT32, -1); g_object_set (s_con, NM_SETTING_CONNECTION_AUTH_RETRIES, (gint) vint64, NULL); - i_val = NM_SETTING_CONNECTION_MDNS_DEFAULT; - if (!svGetValueEnum (ifcfg, "MDNS", - nm_setting_connection_mdns_get_type (), - &i_val, NULL)) - PARSE_WARNING ("invalid MDNS setting"); - g_object_set (s_con, NM_SETTING_CONNECTION_MDNS, i_val, NULL); - return NM_SETTING (s_con); } @@ -934,7 +927,7 @@ next: : "")); break; case PARSE_LINE_TYPE_FLAG: - /* NOTE: the flag (for "onlink") only allows to explictly set "TRUE". + /* XXX: the flag (for "onlink") only allows to explictly set "TRUE". * There is no way to express an explicit "FALSE" setting * of this attribute, hence, the file format cannot encode * that configuration. */ @@ -1345,7 +1338,29 @@ make_ip4_setting (shvarFile *ifcfg, } else if (!g_ascii_strcasecmp (v, "autoip")) { method = NM_SETTING_IP4_CONFIG_METHOD_LINK_LOCAL; } else if (!g_ascii_strcasecmp (v, "shared")) { - method = NM_SETTING_IP4_CONFIG_METHOD_SHARED; + int idx; + + g_object_set (s_ip4, + NM_SETTING_IP_CONFIG_METHOD, NM_SETTING_IP4_CONFIG_METHOD_SHARED, + NM_SETTING_IP_CONFIG_NEVER_DEFAULT, never_default, + NULL); + /* 1 IP address is allowed for shared connections. Read it. */ + if (is_any_ip4_address_defined (ifcfg, &idx)) { + guint32 gw; + NMIPAddress *addr = NULL; + + if (!read_full_ip4_address (ifcfg, idx, NULL, &addr, NULL, error)) + return NULL; + if (!read_ip4_address (ifcfg, "GATEWAY", NULL, &gw, error)) + return NULL; + (void) nm_setting_ip_config_add_address (s_ip4, addr); + nm_ip_address_unref (addr); + if (never_default) + PARSE_WARNING ("GATEWAY will be ignored when DEFROUTE is disabled"); + gateway = g_strdup (nm_utils_inet4_ntop (gw, inet_buf)); + g_object_set (s_ip4, NM_SETTING_IP_CONFIG_GATEWAY, gateway, NULL); + } + return g_steal_pointer (&s_ip4); } else { g_set_error (error, NM_SETTINGS_ERROR, NM_SETTINGS_ERROR_INVALID_CONNECTION, "Unknown BOOTPROTO '%s'", v); @@ -1372,7 +1387,7 @@ make_ip4_setting (shvarFile *ifcfg, NM_SETTING_IP_CONFIG_ROUTE_TABLE, (guint) route_table, NULL); - if (nm_streq (method, NM_SETTING_IP4_CONFIG_METHOD_DISABLED)) + if (strcmp (method, NM_SETTING_IP4_CONFIG_METHOD_DISABLED) == 0) return g_steal_pointer (&s_ip4); /* Handle DHCP settings */ @@ -1449,47 +1464,39 @@ make_ip4_setting (shvarFile *ifcfg, if (gateway && never_default) PARSE_WARNING ("GATEWAY will be ignored when DEFROUTE is disabled"); - /* We used to skip saving a lot of unused properties for the ipv4 shared method. - * We want now to persist them but... unfortunately loading DNS or DOMAIN options - * would cause a fail in the ipv4 verify() function. As we don't want any regression - * in the unlikely event that someone has a working ifcfg file for an IPv4 shared ip - * connection with a crafted "DNS" entry... don't load it. So we will avoid failing - * the connection) */ - if (!nm_streq (method, NM_SETTING_IP4_CONFIG_METHOD_SHARED)) { - /* DNS servers - * Pick up just IPv4 addresses (IPv6 addresses are taken by make_ip6_setting()) - */ - for (i = 1; i <= 10; i++) { - char tag[256]; - - numbered_tag (tag, "DNS", i); - nm_clear_g_free (&value); - v = svGetValueStr (ifcfg, tag, &value); - if (v) { - if (nm_utils_ipaddr_valid (AF_INET, v)) { - if (!nm_setting_ip_config_add_dns (s_ip4, v)) - PARSE_WARNING ("duplicate DNS server %s", tag); - } else if (nm_utils_ipaddr_valid (AF_INET6, v)) { - /* Ignore IPv6 addresses */ - } else { - PARSE_WARNING ("invalid DNS server address %s", v); - return NULL; - } - } - } + /* DNS servers + * Pick up just IPv4 addresses (IPv6 addresses are taken by make_ip6_setting()) + */ + for (i = 1; i <= 10; i++) { + char tag[256]; - /* DNS searches */ + numbered_tag (tag, "DNS", i); nm_clear_g_free (&value); - v = svGetValueStr (ifcfg, "DOMAIN", &value); + v = svGetValueStr (ifcfg, tag, &value); if (v) { - gs_free const char **searches = NULL; + if (nm_utils_ipaddr_valid (AF_INET, v)) { + if (!nm_setting_ip_config_add_dns (s_ip4, v)) + PARSE_WARNING ("duplicate DNS server %s", tag); + } else if (nm_utils_ipaddr_valid (AF_INET6, v)) { + /* Ignore IPv6 addresses */ + } else { + PARSE_WARNING ("invalid DNS server address %s", v); + return NULL; + } + } + } - searches = nm_utils_strsplit_set (v, " "); - if (searches) { - for (item = searches; *item; item++) { - if (!nm_setting_ip_config_add_dns_search (s_ip4, *item)) - PARSE_WARNING ("duplicate DNS domain '%s'", *item); - } + /* DNS searches */ + nm_clear_g_free (&value); + v = svGetValueStr (ifcfg, "DOMAIN", &value); + if (v) { + gs_free const char **searches = NULL; + + searches = nm_utils_strsplit_set (v, " "); + if (searches) { + for (item = searches; *item; item++) { + if (!nm_setting_ip_config_add_dns_search (s_ip4, *item)) + PARSE_WARNING ("duplicate DNS domain '%s'", *item); } } } @@ -1538,8 +1545,7 @@ make_ip4_setting (shvarFile *ifcfg, } /* Legacy value NM used for a while but is incorrect (rh #459370) */ - if ( !nm_streq (method, NM_SETTING_IP4_CONFIG_METHOD_SHARED) - && !nm_setting_ip_config_get_num_dns_searches (s_ip4)) { + if (!nm_setting_ip_config_get_num_dns_searches (s_ip4)) { nm_clear_g_free (&value); v = svGetValueStr (ifcfg, "SEARCH", &value); if (v) { @@ -1555,14 +1561,10 @@ make_ip4_setting (shvarFile *ifcfg, } } - timeout = svGetValueInt64 (ifcfg, "ACD_TIMEOUT", 10, -1, NM_SETTING_IP_CONFIG_DAD_TIMEOUT_MAX, -2); - if (timeout == -2) { - timeout = svGetValueInt64 (ifcfg, "ARPING_WAIT", 10, -1, - NM_SETTING_IP_CONFIG_DAD_TIMEOUT_MAX / 1000, -1); - if (timeout > 0) - timeout *= 1000; - } - g_object_set (s_ip4, NM_SETTING_IP_CONFIG_DAD_TIMEOUT, (gint) timeout, NULL); + timeout = svGetValueInt64 (ifcfg, "ARPING_WAIT", 10, -1, + NM_SETTING_IP_CONFIG_DAD_TIMEOUT_MAX / 1000, -1); + g_object_set (s_ip4, NM_SETTING_IP_CONFIG_DAD_TIMEOUT, + (gint) (timeout <= 0 ? timeout : timeout * 1000), NULL); return g_steal_pointer (&s_ip4); } @@ -1640,7 +1642,7 @@ read_aliases (NMSettingIPConfig *s_ip4, gboolean read_defroute, const char *file read_defroute ? &gateway : NULL, &err); if (ok) { - nm_ip_address_set_attribute (addr, NM_IP_ADDRESS_ATTRIBUTE_LABEL, g_variant_new_string (device)); + nm_ip_address_set_attribute (addr, "label", g_variant_new_string (device)); if (!nm_setting_ip_config_add_address (s_ip4, addr)) PARSE_WARNING ("duplicate IP4 address in alias file %s", item); if (nm_streq0 (nm_setting_ip_config_get_method (s_ip4), NM_SETTING_IP4_CONFIG_METHOD_DISABLED)) @@ -1999,15 +2001,11 @@ make_tc_setting (shvarFile *ifcfg) break; qdisc = nm_utils_tc_qdisc_from_str (value, &local); - if (!qdisc) { - PARSE_WARNING ("ignoring bad tc qdisc: '%s': %s", value, local->message); - continue; - } + if (!qdisc) + PARSE_WARNING ("ignoring bad qdisc: '%s': %s", value, local->message); if (!nm_setting_tc_config_add_qdisc (s_tc, qdisc)) - PARSE_WARNING ("duplicate tc qdisc"); - - nm_tc_qdisc_unref (qdisc); + PARSE_WARNING ("duplicate qdisc"); } for (i = 1;; i++) { @@ -2021,15 +2019,11 @@ make_tc_setting (shvarFile *ifcfg) break; tfilter = nm_utils_tc_tfilter_from_str (value, &local); - if (!tfilter) { - PARSE_WARNING ("ignoring bad tc filter: '%s': %s", value, local->message); - continue; - } + if (!tfilter) + PARSE_WARNING ("ignoring bad tfilter: '%s': %s", value, local->message); if (!nm_setting_tc_config_add_tfilter (s_tc, tfilter)) - PARSE_WARNING ("duplicate tc filter"); - - nm_tc_tfilter_unref (tfilter); + PARSE_WARNING ("duplicate filter"); } if ( nm_setting_tc_config_get_num_qdiscs (s_tc) > 0 @@ -3558,13 +3552,6 @@ make_wpa_setting (shvarFile *ifcfg, return NULL; g_object_set (wsec, NM_SETTING_WIRELESS_SECURITY_PMF, i_val, NULL); - i_val = NM_SETTING_WIRELESS_SECURITY_FILS_DEFAULT; - if (!svGetValueEnum (ifcfg, "FILS", - nm_setting_wireless_security_fils_get_type (), - &i_val, error)) - return NULL; - g_object_set (wsec, NM_SETTING_WIRELESS_SECURITY_FILS, i_val, NULL); - nm_clear_g_free (&value); v = svGetValueStr (ifcfg, "SECURITYMODE", &value); if (NM_IN_STRSET (v, NULL, "open")) @@ -5334,8 +5321,6 @@ connection_from_file_full (const char *filename, g_return_val_if_fail (filename != NULL, NULL); g_return_val_if_fail (out_unhandled && !*out_unhandled, NULL); - NM_SET_OUT (out_ignore_error, FALSE); - /* Non-NULL only for unit tests; normally use /etc/sysconfig/network */ if (!network_file) network_file = SYSCONFDIR "/sysconfig/network"; @@ -5356,7 +5341,6 @@ connection_from_file_full (const char *filename, if (!svGetValueBoolean (parsed, "NM_CONTROLLED", TRUE)) { connection = create_unhandled_connection (filename, parsed, "unmanaged", out_unhandled); if (!connection) { - NM_SET_OUT (out_ignore_error, TRUE); g_set_error (error, NM_SETTINGS_ERROR, NM_SETTINGS_ERROR_FAILED, "NM_CONTROLLED was false but device was not uniquely identified; device will be managed"); } @@ -5366,7 +5350,8 @@ connection_from_file_full (const char *filename, /* iBFT is handled by the iBFT settings plugin */ bootproto = svGetValueStr_cp (parsed, "BOOTPROTO"); if (bootproto && !g_ascii_strcasecmp (bootproto, "ibft")) { - NM_SET_OUT (out_ignore_error, TRUE); + if (out_ignore_error) + *out_ignore_error = TRUE; g_set_error (error, NM_SETTINGS_ERROR, NM_SETTINGS_ERROR_INVALID_CONNECTION, "Ignoring iBFT configuration"); g_free (bootproto); @@ -5412,7 +5397,8 @@ connection_from_file_full (const char *filename, char *device; if ((tmp = svGetValueStr_cp (parsed, "IPV6TUNNELIPV4"))) { - NM_SET_OUT (out_ignore_error, TRUE); + if (out_ignore_error) + *out_ignore_error = TRUE; g_set_error (error, NM_SETTINGS_ERROR, NM_SETTINGS_ERROR_INVALID_CONNECTION, "Ignoring unsupported connection due to IPV6TUNNELIPV4"); return NULL; @@ -5426,7 +5412,8 @@ connection_from_file_full (const char *filename, } if (!strcmp (device, "lo")) { - NM_SET_OUT (out_ignore_error, TRUE); + if (out_ignore_error) + *out_ignore_error = TRUE; g_set_error (error, NM_SETTINGS_ERROR, NM_SETTINGS_ERROR_INVALID_CONNECTION, "Ignoring loopback device config."); g_free (device); @@ -5473,7 +5460,8 @@ connection_from_file_full (const char *filename, memcpy (p_path, IFUP_PATH_PREFIX, NM_STRLEN (IFUP_PATH_PREFIX)); if (access (p_path, X_OK) == 0) { /* for all other types, this is not something we want to handle. */ - NM_SET_OUT (out_ignore_error, TRUE); + if (out_ignore_error) + *out_ignore_error = TRUE; g_set_error (error, NM_SETTINGS_ERROR, NM_SETTINGS_ERROR_INVALID_CONNECTION, "Ignore script for unknown device type which has a matching %s script", p_path); diff --git a/src/settings/plugins/ifcfg-rh/nms-ifcfg-rh-writer.c b/src/settings/plugins/ifcfg-rh/nms-ifcfg-rh-writer.c index 8584772e..e9dd08b7 100644 --- a/src/settings/plugins/ifcfg-rh/nms-ifcfg-rh-writer.c +++ b/src/settings/plugins/ifcfg-rh/nms-ifcfg-rh-writer.c @@ -148,7 +148,16 @@ write_secrets (shvarFile *ifcfg, /* we purge all existing secrets. */ svUnsetAll (keyfile, SV_KEY_TYPE_ANY); - secrets_keys = nm_utils_strdict_get_keys (secrets, TRUE, &secrets_keys_n); + /* sort the keys. */ + secrets_keys = (const char **) g_hash_table_get_keys_as_array (secrets, &secrets_keys_n); + if (secrets_keys_n > 1) { + g_qsort_with_data (secrets_keys, + secrets_keys_n, + sizeof (const char *), + nm_strcmp_p_with_data, + NULL); + } + for (i = 0; i < secrets_keys_n; i++) { const char *k = secrets_keys[i]; const char *v = g_hash_table_lookup (secrets, k); @@ -785,13 +794,6 @@ write_wireless_security_setting (NMConnection *connection, nm_setting_wireless_security_get_pmf (s_wsec)); } - if (nm_setting_wireless_security_get_fils (s_wsec) == NM_SETTING_WIRELESS_SECURITY_FILS_DEFAULT) - svUnsetValue (ifcfg, "FILS"); - else { - svSetValueEnum (ifcfg, "FILS", nm_setting_wireless_security_fils_get_type (), - nm_setting_wireless_security_get_fils (s_wsec)); - } - return TRUE; } @@ -897,16 +899,14 @@ write_wireless_setting (NMConnection *connection, } mode = nm_setting_wireless_get_mode (s_wireless); - if (!mode) - svUnsetValue(ifcfg, "MODE"); - else if (nm_streq (mode, NM_SETTING_WIRELESS_MODE_INFRA)) + if (!mode || !strcmp (mode, "infrastructure")) { svSetValueStr (ifcfg, "MODE", "Managed"); - else if (nm_streq (mode, NM_SETTING_WIRELESS_MODE_ADHOC)) { + } else if (!strcmp (mode, "adhoc")) { svSetValueStr (ifcfg, "MODE", "Ad-Hoc"); adhoc = TRUE; - } else if (nm_streq (mode, NM_SETTING_WIRELESS_MODE_AP)) + } else if (!strcmp (mode, "ap")) { svSetValueStr (ifcfg, "MODE", "Ap"); - else { + } else { g_set_error (error, NM_SETTINGS_ERROR, NM_SETTINGS_ERROR_FAILED, "Invalid mode '%s' in '%s' setting", mode, NM_SETTING_WIRELESS_SETTING_NAME); @@ -1728,7 +1728,6 @@ write_connection_setting (NMSettingConnection *s_con, shvarFile *ifcfg) GString *str; const char *master, *master_iface = NULL, *type; gint vint; - NMSettingConnectionMdns mdns; guint32 vuint32; const char *tmp; @@ -1750,7 +1749,9 @@ write_connection_setting (NMSettingConnection *s_con, shvarFile *ifcfg) /* Only save the value for master connections */ type = nm_setting_connection_get_connection_type (s_con); - if (_nm_connection_type_is_master (type)) { + if ( !g_strcmp0 (type, NM_SETTING_BOND_SETTING_NAME) + || !g_strcmp0 (type, NM_SETTING_TEAM_SETTING_NAME) + || !g_strcmp0 (type, NM_SETTING_BRIDGE_SETTING_NAME)) { NMSettingConnectionAutoconnectSlaves autoconnect_slaves; autoconnect_slaves = nm_setting_connection_get_autoconnect_slaves (s_con); svSetValueStr (ifcfg, "AUTOCONNECT_SLAVES", @@ -1887,13 +1888,6 @@ write_connection_setting (NMSettingConnection *s_con, shvarFile *ifcfg) vint = nm_setting_connection_get_auth_retries (s_con); svSetValueInt64_cond (ifcfg, "AUTH_RETRIES", vint >= 0, vint); - - mdns = nm_setting_connection_get_mdns (s_con); - if (mdns != NM_SETTING_CONNECTION_MDNS_DEFAULT) { - svSetValueEnum (ifcfg, "MDNS", nm_setting_connection_mdns_get_type (), - mdns); - } else - svUnsetValue (ifcfg, "MDNS"); } static char * @@ -2287,7 +2281,7 @@ write_ip4_setting (NMConnection *connection, if (i > 0) { GVariant *label; - label = nm_ip_address_get_attribute (addr, NM_IP_ADDRESS_ATTRIBUTE_LABEL); + label = nm_ip_address_get_attribute (addr, "label"); if (label) continue; } @@ -2417,15 +2411,12 @@ write_ip4_setting (NMConnection *connection, NM_SET_OUT (out_route_content, write_route_file (s_ip4)); timeout = nm_setting_ip_config_get_dad_timeout (s_ip4); - if (timeout < 0) { - svUnsetValue (ifcfg, "ACD_TIMEOUT"); + if (timeout < 0) svUnsetValue (ifcfg, "ARPING_WAIT"); - } else if (timeout == 0) { - svSetValueStr (ifcfg, "ACD_TIMEOUT", "0"); + else if (timeout == 0) svSetValueStr (ifcfg, "ARPING_WAIT", "0"); - } else { - svSetValueInt64 (ifcfg, "ACD_TIMEOUT", timeout); - /* Round the value up to next integer for initscripts */ + else { + /* Round the value up to next integer */ svSetValueInt64 (ifcfg, "ARPING_WAIT", (timeout - 1) / 1000 + 1); } @@ -2493,7 +2484,7 @@ write_ip4_aliases (NMConnection *connection, const char *base_ifcfg_path) addr = nm_setting_ip_config_get_address (s_ip4, i); - label_var = nm_ip_address_get_attribute (addr, NM_IP_ADDRESS_ATTRIBUTE_LABEL); + label_var = nm_ip_address_get_attribute (addr, "label"); if (!label_var) continue; label = g_variant_get_string (label_var, NULL); @@ -2996,7 +2987,7 @@ do_write_to_disk (NMConnection *connection, { /* From here on, we persist data to disk. Before, it was all in-memory * only. But we loaded the ifcfg files from disk, and managled our - * new settings (in-memory). */ + * new settings (in-momory). */ if (!svWriteFile (ifcfg, 0644, error)) return FALSE; @@ -3147,10 +3138,10 @@ nms_ifcfg_rh_writer_write_connection (NMConnection *connection, * does not yet allow to inject the configuration. */ if (out_reread || out_reread_same) { if (!do_write_reread (connection, - svFileGetName (ifcfg), - out_reread, - out_reread_same, - &local)) { + svFileGetName (ifcfg), + out_reread, + out_reread_same, + &local)) { _LOGW ("write: failure to re-read connection \"%s\": %s", svFileGetName (ifcfg), local->message); g_clear_error (&local); @@ -3197,3 +3188,4 @@ nms_ifcfg_rh_writer_can_write_connection (NMConnection *connection, GError **err NM_PRINT_FMT_QUOTE_STRING (type)); return FALSE; } + diff --git a/src/settings/plugins/ifcfg-rh/shvar.c b/src/settings/plugins/ifcfg-rh/shvar.c index 9120b870..2b64f3fc 100644 --- a/src/settings/plugins/ifcfg-rh/shvar.c +++ b/src/settings/plugins/ifcfg-rh/shvar.c @@ -39,7 +39,7 @@ #include "nm-core-internal.h" #include "nm-core-utils.h" #include "nm-utils/nm-enum-utils.h" -#include "c-list/src/c-list.h" +#include "nm-utils/c-list.h" /*****************************************************************************/ @@ -1278,7 +1278,7 @@ svSetValueEnum (shvarFile *s, const char *key, GType gtype, int value) { gs_free char *v = NULL; - v = _nm_utils_enum_to_str_full (gtype, value, " ", NULL); + v = _nm_utils_enum_to_str_full (gtype, value, " "); return svSetValueStr (s, key, v); } diff --git a/src/settings/plugins/ifcfg-rh/tests/meson.build b/src/settings/plugins/ifcfg-rh/tests/meson.build deleted file mode 100644 index 3596b642..00000000 --- a/src/settings/plugins/ifcfg-rh/tests/meson.build +++ /dev/null @@ -1,22 +0,0 @@ -test_unit = 'test-ifcfg-rh' - -test_ifcfg_dir = meson.current_source_dir() - -cflags = [ - '-DTEST_IFCFG_DIR="@0@"'.format(test_ifcfg_dir), - '-DTEST_SCRATCH_DIR="@0@"'.format(test_ifcfg_dir) -] - -exe = executable( - test_unit, - test_unit + '.c', - dependencies: test_nm_dep, - c_args: cflags, - link_with: libnms_ifcfg_rh_core -) - -test( - 'ifcfg-rh/' + test_unit, - test_script, - args: test_args + [exe.full_path()] -) diff --git a/src/settings/plugins/ifcfg-rh/tests/network-scripts/ifcfg-Test_Write_WiFi_Hidden.cexpected b/src/settings/plugins/ifcfg-rh/tests/network-scripts/ifcfg-Test_Write_WiFi_Hidden.cexpected index cf325f35..026993b8 100644 --- a/src/settings/plugins/ifcfg-rh/tests/network-scripts/ifcfg-Test_Write_WiFi_Hidden.cexpected +++ b/src/settings/plugins/ifcfg-rh/tests/network-scripts/ifcfg-Test_Write_WiFi_Hidden.cexpected @@ -1,4 +1,5 @@ ESSID="Test SSID" +MODE=Managed SSID_HIDDEN=yes MAC_ADDRESS_RANDOMIZATION=default TYPE=Wireless diff --git a/src/settings/plugins/ifcfg-rh/tests/network-scripts/ifcfg-Test_Write_Wired_Static_Routes.cexpected b/src/settings/plugins/ifcfg-rh/tests/network-scripts/ifcfg-Test_Write_Wired_Static_Routes.cexpected index cd8fc96f..c0e47c48 100644 --- a/src/settings/plugins/ifcfg-rh/tests/network-scripts/ifcfg-Test_Write_Wired_Static_Routes.cexpected +++ b/src/settings/plugins/ifcfg-rh/tests/network-scripts/ifcfg-Test_Write_Wired_Static_Routes.cexpected @@ -14,8 +14,6 @@ DNS2=4.2.2.2 DOMAIN="foobar.com lab.foobar.com" DEFROUTE=yes IPV4_FAILURE_FATAL=no -ACD_TIMEOUT=400 -ARPING_WAIT=1 IPV6INIT=no NAME="Test Write Wired Static Routes" UUID=${UUID} diff --git a/src/settings/plugins/ifcfg-rh/tests/network-scripts/ifcfg-test-tc b/src/settings/plugins/ifcfg-rh/tests/network-scripts/ifcfg-test-tc deleted file mode 100644 index d0a3c254..00000000 --- a/src/settings/plugins/ifcfg-rh/tests/network-scripts/ifcfg-test-tc +++ /dev/null @@ -1,16 +0,0 @@ -TYPE=Ethernet -DEVICE=eth0 -HWADDR=00:11:22:33:44:55 -BOOTPROTO=none -ONBOOT=yes -DNS1=4.2.2.1 -DNS2=4.2.2.2 -IPADDR=192.168.1.5 -PREFIX=24 -NETMASK=255.255.255.0 -GATEWAY=192.168.1.1 -IPV6INIT=no -QDISC1="root fq_codel" -FILTER1="parent 1234: matchall action simple sdata Hello" -NAME=ethernet-tc -UUID=a42c8d4e-11a2-4144-92d2-5cbce8c6b2c4 diff --git a/src/settings/plugins/ifcfg-rh/tests/network-scripts/ifcfg-test-tc-write.cexpected b/src/settings/plugins/ifcfg-rh/tests/network-scripts/ifcfg-test-tc-write.cexpected deleted file mode 100644 index a67ca598..00000000 --- a/src/settings/plugins/ifcfg-rh/tests/network-scripts/ifcfg-test-tc-write.cexpected +++ /dev/null @@ -1,16 +0,0 @@ -TYPE=Ethernet -PROXY_METHOD=none -BROWSER_ONLY=no -QDISC1="parent 2468:2 pfifo_fast" -FILTER1="parent 1234: matchall action simple sdata Hello" -BOOTPROTO=none -IPADDR=1.1.1.3 -PREFIX=24 -GATEWAY=1.1.1.1 -DEFROUTE=yes -IPV4_FAILURE_FATAL=no -IPV6INIT=no -NAME="Test Write TC config" -UUID=${UUID} -DEVICE=eth0 -ONBOOT=yes diff --git a/src/settings/plugins/ifcfg-rh/tests/network-scripts/ifcfg-test-wired-ipv4-manual-1 b/src/settings/plugins/ifcfg-rh/tests/network-scripts/ifcfg-test-wired-ipv4-manual-1 index db09afdb..1bc3d524 100644 --- a/src/settings/plugins/ifcfg-rh/tests/network-scripts/ifcfg-test-wired-ipv4-manual-1 +++ b/src/settings/plugins/ifcfg-rh/tests/network-scripts/ifcfg-test-wired-ipv4-manual-1 @@ -10,5 +10,3 @@ PREFIX1=16 IPADDR2=3.3.3.3 PREFIX2=8 GATEWAY=1.1.1.1 -ACD_TIMEOUT=2000 -ARPING_WAIT=1 diff --git a/src/settings/plugins/ifcfg-rh/tests/network-scripts/ifcfg-test-wired-ipv4-manual-2 b/src/settings/plugins/ifcfg-rh/tests/network-scripts/ifcfg-test-wired-ipv4-manual-2 index 6972e279..d7273e36 100644 --- a/src/settings/plugins/ifcfg-rh/tests/network-scripts/ifcfg-test-wired-ipv4-manual-2 +++ b/src/settings/plugins/ifcfg-rh/tests/network-scripts/ifcfg-test-wired-ipv4-manual-2 @@ -9,5 +9,3 @@ IPADDR2=9.8.7.6 PREFIX2=16 IPADDR3=3.3.3.3 PREFIX3=8 -ACD_TIMEOUT=2000 -ARPING_WAIT=1 diff --git a/src/settings/plugins/ifcfg-rh/tests/network-scripts/ifcfg-test-wired-ipv4-manual-3 b/src/settings/plugins/ifcfg-rh/tests/network-scripts/ifcfg-test-wired-ipv4-manual-3 index d9065994..f2457bd2 100644 --- a/src/settings/plugins/ifcfg-rh/tests/network-scripts/ifcfg-test-wired-ipv4-manual-3 +++ b/src/settings/plugins/ifcfg-rh/tests/network-scripts/ifcfg-test-wired-ipv4-manual-3 @@ -9,5 +9,3 @@ IPADDR3=9.8.7.6 PREFIX3=16 IPADDR4=3.3.3.3 PREFIX4=8 -ACD_TIMEOUT=2000 -ARPING_WAIT=1 diff --git a/src/settings/plugins/ifcfg-rh/tests/network-scripts/ifcfg-test-wired-ipv4-manual-4 b/src/settings/plugins/ifcfg-rh/tests/network-scripts/ifcfg-test-wired-ipv4-manual-4 index 935267f7..e6b77141 100644 --- a/src/settings/plugins/ifcfg-rh/tests/network-scripts/ifcfg-test-wired-ipv4-manual-4 +++ b/src/settings/plugins/ifcfg-rh/tests/network-scripts/ifcfg-test-wired-ipv4-manual-4 @@ -9,5 +9,3 @@ IPADDR1=9.8.7.6 PREFIX1=16 IPADDR2=3.3.3.3 PREFIX2=8 -ACD_TIMEOUT=2000 -ARPING_WAIT=1 diff --git a/src/settings/plugins/ifcfg-rh/tests/test-ifcfg-rh.c b/src/settings/plugins/ifcfg-rh/tests/test-ifcfg-rh.c index 57bd96e9..6bf27556 100644 --- a/src/settings/plugins/ifcfg-rh/tests/test-ifcfg-rh.c +++ b/src/settings/plugins/ifcfg-rh/tests/test-ifcfg-rh.c @@ -24,7 +24,6 @@ #include <stdarg.h> #include <unistd.h> #include <string.h> -#include <linux/pkt_sched.h> #include <netinet/in.h> #include <arpa/inet.h> #include <sys/socket.h> @@ -606,7 +605,8 @@ test_read_miscellaneous_variables (void) int mac_blacklist_num, i; guint64 expected_timestamp = 0; - NMTST_EXPECT_NM_WARN ("*invalid MAC in HWADDR_BLACKLIST 'XX:aa:invalid'*"); + g_test_expect_message ("NetworkManager", G_LOG_LEVEL_MESSAGE, + "*invalid MAC in HWADDR_BLACKLIST 'XX:aa:invalid'*"); connection = _connection_from_file (TEST_IFCFG_DIR"/network-scripts/ifcfg-test-misc-variables", NULL, TYPE_ETHERNET, NULL); g_test_assert_expected_messages (); @@ -859,7 +859,8 @@ test_read_wired_static_no_prefix (gconstpointer user_data) file = g_strdup_printf (TEST_IFCFG_DIR "/network-scripts/ifcfg-test-wired-static-no-prefix-%u", expected_prefix); expected_id = g_strdup_printf ("System test-wired-static-no-prefix-%u", expected_prefix); - NMTST_EXPECT_NM_WARN ("*missing PREFIX, assuming*"); + g_test_expect_message ("NetworkManager", G_LOG_LEVEL_MESSAGE, + "*missing PREFIX, assuming*"); connection = _connection_from_file (file, NULL, TYPE_ETHERNET, NULL); g_test_assert_expected_messages (); @@ -1080,7 +1081,8 @@ test_read_wired_global_gateway_ignore (void) NMSettingIPConfig *s_ip4; char *unmanaged = NULL; - NMTST_EXPECT_NM_WARN ("*ignoring GATEWAY (/etc/sysconfig/network) for * because the connection has no static addresses"); + g_test_expect_message ("NetworkManager", G_LOG_LEVEL_MESSAGE, + "*ignoring GATEWAY (/etc/sysconfig/network) for * because the connection has no static addresses"); connection = _connection_from_file (TEST_IFCFG_DIR"/network-scripts/ifcfg-test-wired-global-gateway-ignore", TEST_IFCFG_DIR"/network-scripts/network-test-wired-global-gateway-ignore", TYPE_ETHERNET, &unmanaged); @@ -1474,7 +1476,6 @@ test_read_wired_ipv4_manual (gconstpointer data) s_ip4 = nm_connection_get_setting_ip4_config (connection); g_assert (s_ip4); g_assert_cmpstr (nm_setting_ip_config_get_method (s_ip4), ==, NM_SETTING_IP4_CONFIG_METHOD_MANUAL); - g_assert_cmpint (nm_setting_ip_config_get_dad_timeout (s_ip4), ==, 2000); /* IP addresses */ g_assert_cmpint (nm_setting_ip_config_get_num_addresses (s_ip4), ==, 3); @@ -1512,7 +1513,8 @@ test_read_wired_ipv6_manual (void) NMIPAddress *ip6_addr; NMIPRoute *ip6_route; - NMTST_EXPECT_NM_WARN ("*ignoring manual default route*"); + g_test_expect_message ("NetworkManager", G_LOG_LEVEL_MESSAGE, + "*ignoring manual default route*"); connection = _connection_from_file (TEST_IFCFG_DIR"/network-scripts/ifcfg-test-wired-ipv6-manual", NULL, TYPE_ETHERNET, &unmanaged); g_test_assert_expected_messages (); @@ -1895,7 +1897,8 @@ test_read_write_802_1X_subj_matches (void) gs_unref_object NMConnection *reread = NULL; NMSetting8021x *s_8021x; - NMTST_EXPECT_NM_WARN ("*missing IEEE_8021X_CA_CERT*peap*"); + g_test_expect_message ("NetworkManager", G_LOG_LEVEL_MESSAGE, + "*missing IEEE_8021X_CA_CERT*peap*"); connection = _connection_from_file (TEST_IFCFG_DIR"/network-scripts/ifcfg-test-wired-802-1X-subj-matches", NULL, TYPE_ETHERNET, NULL); g_test_assert_expected_messages (); @@ -1916,14 +1919,16 @@ test_read_write_802_1X_subj_matches (void) g_assert_cmpstr (nm_setting_802_1x_get_phase2_altsubject_match (s_8021x, 0), ==, "x.yourdomain.tld"); g_assert_cmpstr (nm_setting_802_1x_get_phase2_altsubject_match (s_8021x, 1), ==, "y.yourdomain.tld"); - NMTST_EXPECT_NM_WARN ("*missing IEEE_8021X_CA_CERT for EAP method 'peap'; this is insecure!"); + g_test_expect_message ("NetworkManager", G_LOG_LEVEL_MESSAGE, + "*missing IEEE_8021X_CA_CERT for EAP method 'peap'; this is insecure!"); _writer_new_connec_exp (connection, TEST_SCRATCH_DIR "/network-scripts/", TEST_IFCFG_DIR "/network-scripts/ifcfg-System_test-wired-802-1X-subj-matches.cexpected", &testfile); g_test_assert_expected_messages (); - NMTST_EXPECT_NM_WARN ("*missing IEEE_8021X_CA_CERT for EAP method 'peap'; this is insecure!"); + g_test_expect_message ("NetworkManager", G_LOG_LEVEL_MESSAGE, + "*missing IEEE_8021X_CA_CERT for EAP method 'peap'; this is insecure!"); reread = _connection_from_file (testfile, NULL, TYPE_ETHERNET, NULL); g_test_assert_expected_messages (); @@ -2074,7 +2079,7 @@ test_read_wired_aliases_good (gconstpointer test_data) g_assert (j < expected_num_addresses); g_assert_cmpint (nm_ip_address_get_prefix (ip4_addr), ==, 24); - label = nm_ip_address_get_attribute (ip4_addr, NM_IP_ADDRESS_ATTRIBUTE_LABEL); + label = nm_ip_address_get_attribute (ip4_addr, "label"); if (expected_label[j]) g_assert_cmpstr (g_variant_get_string (label, NULL), ==, expected_label[j]); else @@ -2126,7 +2131,7 @@ test_read_wired_aliases_bad (const char *base, const char *expected_id) g_assert (ip4_addr != NULL); g_assert_cmpstr (nm_ip_address_get_address (ip4_addr), ==, "192.168.1.5"); g_assert_cmpint (nm_ip_address_get_prefix (ip4_addr), ==, 24); - g_assert (nm_ip_address_get_attribute (ip4_addr, NM_IP_ADDRESS_ATTRIBUTE_LABEL) == NULL); + g_assert (nm_ip_address_get_attribute (ip4_addr, "label") == NULL); /* Gateway */ g_assert_cmpstr (nm_setting_ip_config_get_gateway (s_ip4), ==, "192.168.1.1"); @@ -2137,14 +2142,16 @@ test_read_wired_aliases_bad (const char *base, const char *expected_id) static void test_read_wired_aliases_bad_1 (void) { - NMTST_EXPECT_NM_WARN ("*aliasem1:1*has no DEVICE*"); + g_test_expect_message ("NetworkManager", G_LOG_LEVEL_MESSAGE, + "*aliasem1:1*has no DEVICE*"); test_read_wired_aliases_bad (TEST_IFCFG_DIR "/network-scripts/ifcfg-aliasem1", "System aliasem1"); } static void test_read_wired_aliases_bad_2 (void) { - NMTST_EXPECT_NM_WARN ("*aliasem2:1*has invalid DEVICE*"); + g_test_expect_message ("NetworkManager", G_LOG_LEVEL_MESSAGE, + "*aliasem2:1*has invalid DEVICE*"); test_read_wired_aliases_bad (TEST_IFCFG_DIR "/network-scripts/ifcfg-aliasem2", "System aliasem2"); } @@ -3515,6 +3522,7 @@ test_write_wifi_hidden (void) g_object_set (s_wifi, NM_SETTING_WIRELESS_SSID, ssid, + NM_SETTING_WIRELESS_MODE, "infrastructure", NM_SETTING_WIRELESS_HIDDEN, TRUE, NULL); @@ -4766,7 +4774,6 @@ test_write_wired_static_routes (void) g_object_set (s_ip4, NM_SETTING_IP_CONFIG_METHOD, NM_SETTING_IP4_CONFIG_METHOD_MANUAL, NM_SETTING_IP_CONFIG_GATEWAY, "1.1.1.1", - NM_SETTING_IP_CONFIG_DAD_TIMEOUT, 400, NULL); addr = nm_ip_address_new (AF_INET, "1.1.1.3", 24, &error); @@ -5134,7 +5141,7 @@ test_write_wired_aliases (void) addr = nm_ip_address_new (AF_INET, ip[i], 24, &error); g_assert_no_error (error); if (label[i]) - nm_ip_address_set_attribute (addr, NM_IP_ADDRESS_ATTRIBUTE_LABEL, g_variant_new_string (label[i])); + nm_ip_address_set_attribute (addr, "label", g_variant_new_string (label[i])); nm_setting_ip_config_add_address (s_ip4, addr); nm_ip_address_unref (addr); } @@ -5193,9 +5200,9 @@ test_write_wired_aliases (void) else { g_assert_cmpint (nm_ip_address_get_prefix (addr), ==, 24); if (label[j]) - g_assert_cmpstr (g_variant_get_string (nm_ip_address_get_attribute (addr, NM_IP_ADDRESS_ATTRIBUTE_LABEL), NULL), ==, label[j]); + g_assert_cmpstr (g_variant_get_string (nm_ip_address_get_attribute (addr, "label"), NULL), ==, label[j]); else - g_assert (nm_ip_address_get_attribute (addr, NM_IP_ADDRESS_ATTRIBUTE_LABEL) == NULL); + g_assert (nm_ip_address_get_attribute (addr, "label") == NULL); ip[j] = NULL; } } @@ -6278,9 +6285,7 @@ test_write_wifi_wpa_eap_tls (void) s_wsec = (NMSettingWirelessSecurity *) nm_setting_wireless_security_new (); nm_connection_add_setting (connection, NM_SETTING (s_wsec)); - g_object_set (s_wsec, NM_SETTING_WIRELESS_SECURITY_KEY_MGMT, "wpa-eap", - NM_SETTING_WIRELESS_SECURITY_FILS, (int) NM_SETTING_WIRELESS_SECURITY_FILS_REQUIRED, - NULL); + g_object_set (s_wsec, NM_SETTING_WIRELESS_SECURITY_KEY_MGMT, "wpa-eap", NULL); nm_setting_wireless_security_add_proto (s_wsec, "wpa"); nm_setting_wireless_security_add_pairwise (s_wsec, "tkip"); nm_setting_wireless_security_add_group (s_wsec, "tkip"); @@ -7028,7 +7033,7 @@ test_write_wired_ctc_dhcp (void) TEST_SCRATCH_DIR "/network-scripts/", &testfile); - /* Ensure the CTCPROT item gets written out as its own option */ + /* Ensure the CTCPROT item gets written out as it's own option */ ifcfg = _svOpenFile (testfile); _svGetValue_check (ifcfg, "CTCPROT", "0"); @@ -7708,7 +7713,8 @@ test_read_vlan_reorder_hdr_1 (void) NMConnection *connection; NMSettingVlan *s_vlan; - NMTST_EXPECT_NM_WARN ("*REORDER_HDR key is deprecated, use VLAN_FLAGS*"); + g_test_expect_message ("NetworkManager", G_LOG_LEVEL_MESSAGE, + "*REORDER_HDR key is deprecated, use VLAN_FLAGS*"); connection = _connection_from_file (TEST_IFCFG_DIR"/network-scripts/ifcfg-test-vlan-reorder-hdr-1", NULL, TYPE_ETHERNET, NULL); g_test_assert_expected_messages (); @@ -8502,7 +8508,8 @@ test_read_dcb_bad_booleans (void) { gs_free_error GError *error = NULL; - NMTST_EXPECT_NM_WARN ("*invalid DCB_PG_STRICT value*not all 0s and 1s*"); + g_test_expect_message ("NetworkManager", G_LOG_LEVEL_MESSAGE, + "*invalid DCB_PG_STRICT value*not all 0s and 1s*"); _connection_from_file_fail (TEST_IFCFG_DIR "/network-scripts/ifcfg-test-dcb-bad-booleans", NULL, TYPE_ETHERNET, &error); g_test_assert_expected_messages (); @@ -8516,7 +8523,8 @@ test_read_dcb_short_booleans (void) { gs_free_error GError *error = NULL; - NMTST_EXPECT_NM_WARN ("*DCB_PG_STRICT value*8 characters*"); + g_test_expect_message ("NetworkManager", G_LOG_LEVEL_MESSAGE, + "*DCB_PG_STRICT value*8 characters*"); _connection_from_file_fail (TEST_IFCFG_DIR "/network-scripts/ifcfg-test-dcb-short-booleans", NULL, TYPE_ETHERNET, &error); g_test_assert_expected_messages (); @@ -8530,7 +8538,8 @@ test_read_dcb_bad_uints (void) { gs_free_error GError *error = NULL; - NMTST_EXPECT_NM_WARN ("*invalid DCB_PG_UP2TC value*not 0 - 7*"); + g_test_expect_message ("NetworkManager", G_LOG_LEVEL_MESSAGE, + "*invalid DCB_PG_UP2TC value*not 0 - 7*"); _connection_from_file_fail (TEST_IFCFG_DIR "/network-scripts/ifcfg-test-dcb-bad-uints", NULL, TYPE_ETHERNET, &error); g_test_assert_expected_messages (); @@ -8544,7 +8553,8 @@ test_read_dcb_short_uints (void) { gs_free_error GError *error = NULL; - NMTST_EXPECT_NM_WARN ("*DCB_PG_UP2TC value*8 characters*"); + g_test_expect_message ("NetworkManager", G_LOG_LEVEL_MESSAGE, + "*DCB_PG_UP2TC value*8 characters*"); _connection_from_file_fail (TEST_IFCFG_DIR "/network-scripts/ifcfg-test-dcb-short-uints", NULL, TYPE_ETHERNET, &error); g_test_assert_expected_messages (); @@ -8558,7 +8568,8 @@ test_read_dcb_bad_percent (void) { gs_free_error GError *error = NULL; - NMTST_EXPECT_NM_WARN ("*invalid DCB_PG_PCT percentage value*"); + g_test_expect_message ("NetworkManager", G_LOG_LEVEL_MESSAGE, + "*invalid DCB_PG_PCT percentage value*"); _connection_from_file_fail (TEST_IFCFG_DIR "/network-scripts/ifcfg-test-dcb-bad-percent", NULL, TYPE_ETHERNET, &error); g_test_assert_expected_messages (); @@ -8572,7 +8583,8 @@ test_read_dcb_short_percent (void) { gs_free_error GError *error = NULL; - NMTST_EXPECT_NM_WARN ("*invalid DCB_PG_PCT percentage list value*"); + g_test_expect_message ("NetworkManager", G_LOG_LEVEL_MESSAGE, + "*invalid DCB_PG_PCT percentage list value*"); _connection_from_file_fail (TEST_IFCFG_DIR "/network-scripts/ifcfg-test-dcb-short-percent", NULL, TYPE_ETHERNET, &error); g_test_assert_expected_messages (); @@ -8586,7 +8598,8 @@ test_read_dcb_pgpct_not_100 (void) { gs_free_error GError *error = NULL; - NMTST_EXPECT_NM_WARN ("*DCB_PG_PCT percentages do not equal 100*"); + g_test_expect_message ("NetworkManager", G_LOG_LEVEL_MESSAGE, + "*DCB_PG_PCT percentages do not equal 100*"); _connection_from_file_fail (TEST_IFCFG_DIR "/network-scripts/ifcfg-test-dcb-pgpct-not-100", NULL, TYPE_ETHERNET, &error); g_test_assert_expected_messages (); @@ -8707,7 +8720,7 @@ test_read_team_master_invalid (gconstpointer user_data) NMSettingConnection *s_con; NMSettingTeam *s_team; - NMTST_EXPECT_NM_WARN ("*ignoring invalid team configuration*"); + g_test_expect_message ("NetworkManager", G_LOG_LEVEL_MESSAGE, "*ignoring invalid team configuration*"); connection = _connection_from_file (PATH_NAME, NULL, TYPE_ETHERNET, NULL); g_test_assert_expected_messages (); @@ -9632,125 +9645,6 @@ test_utils_ignore (void) do_test_utils_ignored ("ignored-augtmp", "ifcfg-FooBar" AUGTMP_TAG, TRUE); } -static void -test_tc_read (void) -{ - NMConnection *connection; - NMSettingTCConfig *s_tc; - NMTCQdisc *qdisc; - NMTCTfilter *filter; - char *str; - - connection = _connection_from_file (TEST_IFCFG_DIR "/network-scripts/ifcfg-test-tc", - NULL, TYPE_ETHERNET,NULL); - - g_assert_cmpstr (nm_connection_get_interface_name (connection), ==, "eth0"); - - s_tc = nm_connection_get_setting_tc_config (connection); - g_assert (s_tc); - - g_assert_cmpint (nm_setting_tc_config_get_num_qdiscs (s_tc), ==, 1); - qdisc = nm_setting_tc_config_get_qdisc (s_tc, 0); - g_assert (qdisc); - g_assert_cmpint (nm_tc_qdisc_get_parent (qdisc), ==, TC_H_ROOT); - g_assert_cmpint (nm_tc_qdisc_get_handle (qdisc), ==, TC_H_UNSPEC); - g_assert_cmpstr (nm_tc_qdisc_get_kind (qdisc), ==, "fq_codel"); - - g_assert_cmpint (nm_setting_tc_config_get_num_tfilters (s_tc), ==, 1); - filter = nm_setting_tc_config_get_tfilter (s_tc, 0); - g_assert (filter); - str = nm_utils_tc_tfilter_to_str (filter, NULL); - g_assert_cmpstr (str, ==, "parent 1234: matchall action simple sdata Hello"); - g_free (str); - - g_object_unref (connection); -} - -static void -test_tc_write (void) -{ - nmtst_auto_unlinkfile char *testfile = NULL; - gs_unref_object NMConnection *connection = NULL; - gs_unref_object NMConnection *reread = NULL; - NMSettingConnection *s_con; - NMSettingIPConfig *s_ip4; - NMSettingIPConfig *s_ip6; - NMSettingWired *s_wired; - NMSettingTCConfig *s_tc; - NMTCQdisc *qdisc; - NMTCTfilter *tfilter; - NMIPAddress *addr; - GError *error = NULL; - - connection = nm_simple_connection_new (); - - /* Connection setting */ - s_con = (NMSettingConnection *) nm_setting_connection_new (); - nm_connection_add_setting (connection, NM_SETTING (s_con)); - - g_object_set (s_con, - NM_SETTING_CONNECTION_ID, "Test Write TC config", - NM_SETTING_CONNECTION_UUID, nm_utils_uuid_generate_a (), - NM_SETTING_CONNECTION_AUTOCONNECT, TRUE, - NM_SETTING_CONNECTION_INTERFACE_NAME, "eth0", - NM_SETTING_CONNECTION_TYPE, NM_SETTING_WIRED_SETTING_NAME, - NULL); - - /* Wired setting */ - s_wired = (NMSettingWired *) nm_setting_wired_new (); - nm_connection_add_setting (connection, NM_SETTING (s_wired)); - - /* IP4 setting */ - s_ip4 = (NMSettingIPConfig *) nm_setting_ip4_config_new (); - nm_connection_add_setting (connection, NM_SETTING (s_ip4)); - - g_object_set (s_ip4, - NM_SETTING_IP_CONFIG_METHOD, NM_SETTING_IP4_CONFIG_METHOD_MANUAL, - NM_SETTING_IP_CONFIG_GATEWAY, "1.1.1.1", - NM_SETTING_IP_CONFIG_MAY_FAIL, TRUE, - NULL); - - addr = nm_ip_address_new (AF_INET, "1.1.1.3", 24, &error); - g_assert_no_error (error); - nm_setting_ip_config_add_address (s_ip4, addr); - nm_ip_address_unref (addr); - - /* IP6 setting */ - s_ip6 = (NMSettingIPConfig *) nm_setting_ip6_config_new (); - nm_connection_add_setting (connection, NM_SETTING (s_ip6)); - - g_object_set (s_ip6, - NM_SETTING_IP_CONFIG_METHOD, NM_SETTING_IP6_CONFIG_METHOD_IGNORE, - NULL); - - /* TC setting */ - s_tc = (NMSettingTCConfig *) nm_setting_tc_config_new (); - nm_connection_add_setting (connection, NM_SETTING (s_tc)); - - qdisc = nm_tc_qdisc_new ("pfifo_fast", TC_H_MAKE (0x2468 << 16, 0x2), &error); - g_assert_no_error (error); - nm_setting_tc_config_add_qdisc (s_tc, qdisc); - nm_tc_qdisc_unref (qdisc); - - tfilter = nm_utils_tc_tfilter_from_str ("parent 1234: matchall action simple sdata Hello", &error); - g_assert_no_error (error); - nm_setting_tc_config_add_tfilter (s_tc, tfilter); - nm_tc_tfilter_unref (tfilter); - - nm_connection_add_setting (connection, nm_setting_proxy_new ()); - - nmtst_assert_connection_verifies_without_normalization (connection); - - _writer_new_connec_exp (connection, - TEST_SCRATCH_DIR "/network-scripts/", - TEST_IFCFG_DIR "/network-scripts/ifcfg-test-tc-write.cexpected", - &testfile); - - reread = _connection_from_file (testfile, NULL, TYPE_BOND, NULL); - - nmtst_assert_connection_equals (connection, TRUE, reread, FALSE); -} - /*****************************************************************************/ #define TPATH "/settings/plugins/ifcfg-rh/" @@ -10033,8 +9927,5 @@ int main (int argc, char **argv) g_test_add_func (TPATH "utils/path", test_utils_path); g_test_add_func (TPATH "utils/ignore", test_utils_ignore); - g_test_add_func (TPATH "tc/read", test_tc_read); - g_test_add_func (TPATH "tc/write", test_tc_write); - return g_test_run (); } diff --git a/src/settings/plugins/ifnet/nms-ifnet-connection-parser.c b/src/settings/plugins/ifnet/nms-ifnet-connection-parser.c new file mode 100644 index 00000000..ed0a757f --- /dev/null +++ b/src/settings/plugins/ifnet/nms-ifnet-connection-parser.c @@ -0,0 +1,2912 @@ +/* -*- Mode: C; tab-width: 4; indent-tabs-mode: t; c-basic-offset: 4 -*- */ +/* + * Mu Qiao <qiaomuf@gmail.com> + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation; either version 2 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License along + * with this program; if not, write to the Free Software Foundation, Inc., + * 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA. + * + * Copyright (C) 1999-2010 Gentoo Foundation, Inc. + */ + +#include "nm-default.h" + +#include "nms-ifnet-connection-parser.h" + +#include <string.h> +#include <arpa/inet.h> +#include <stdlib.h> +#include <errno.h> + +#include "settings/nm-settings-plugin.h" +#include "nm-core-internal.h" +#include "NetworkManagerUtils.h" +#include "nm-meta-setting.h" + +#include "nms-ifnet-net-utils.h" +#include "nms-ifnet-wpa-parser.h" +#include "nms-ifnet-connection.h" + +static char * +connection_id_from_ifnet_name (const char *conn_name) +{ + int name_len = strlen (conn_name); + + /* Convert a hex-encoded conn_name (only used for wifi SSIDs) to human-readable one */ + if ((name_len > 2) && (g_str_has_prefix (conn_name, "0x"))) { + GBytes *bytes = nm_utils_hexstr2bin (conn_name); + char *buf; + + if (bytes) { + buf = g_strndup (g_bytes_get_data (bytes, NULL), g_bytes_get_size (bytes)); + g_bytes_unref (bytes); + return buf; + } + } + + return g_strdup (conn_name); +} + +static gboolean eap_simple_reader (const char *eap_method, + const char *ssid, + NMSetting8021x *s_8021x, + gboolean phase2, + const char *basepath, + GError **error); + +static gboolean eap_tls_reader (const char *eap_method, + const char *ssid, + NMSetting8021x *s_8021x, + gboolean phase2, + const char *basepath, + GError **error); + +static gboolean eap_peap_reader (const char *eap_method, + const char *ssid, + NMSetting8021x *s_8021x, + gboolean phase2, + const char *basepath, + GError **error); + +static gboolean eap_ttls_reader (const char *eap_method, + const char *ssid, + NMSetting8021x *s_8021x, + gboolean phase2, + const char *basepath, + GError **error); + +typedef struct { + const char *method; + gboolean (*reader) (const char *eap_method, + const char *ssid, + NMSetting8021x *s_8021x, + gboolean phase2, + const char *basepath, + GError **error); + gboolean wifi_phase2_only; +} EAPReader; + +static EAPReader eap_readers[] = { + {"md5", eap_simple_reader, TRUE}, + {"pwd", eap_simple_reader, TRUE}, + {"pap", eap_simple_reader, TRUE}, + {"chap", eap_simple_reader, TRUE}, + {"mschap", eap_simple_reader, TRUE}, + {"mschapv2", eap_simple_reader, TRUE}, + {"leap", eap_simple_reader, TRUE}, + {"tls", eap_tls_reader, FALSE}, + {"peap", eap_peap_reader, FALSE}, + {"ttls", eap_ttls_reader, FALSE}, + {NULL, NULL} +}; + +/* reading identity and password */ +static gboolean +eap_simple_reader (const char *eap_method, + const char *ssid, + NMSetting8021x *s_8021x, + gboolean phase2, + const char *basepath, + GError **error) +{ + const char *value; + + /* identity */ + value = wpa_get_value (ssid, "identity"); + if (!value) { + g_set_error (error, NM_SETTINGS_ERROR, NM_SETTINGS_ERROR_INVALID_CONNECTION, + "Missing IEEE_8021X_IDENTITY for EAP method '%s'.", + eap_method); + return FALSE; + } + g_object_set (s_8021x, NM_SETTING_802_1X_IDENTITY, value, NULL); + + /* password */ + value = wpa_get_value (ssid, "password"); + if (!value) { + g_set_error (error, NM_SETTINGS_ERROR, NM_SETTINGS_ERROR_INVALID_CONNECTION, + "Missing IEEE_8021X_PASSWORD for EAP method '%s'.", + eap_method); + return FALSE; + } + + g_object_set (s_8021x, NM_SETTING_802_1X_PASSWORD, value, NULL); + + return TRUE; +} + +static char * +get_cert (const char *ssid, const char *key, const char *basepath) +{ + const char *orig; + + /* If it's a relative path, convert to absolute using 'basepath' */ + orig = wpa_get_value (ssid, key); + if (g_path_is_absolute (orig)) + return g_strdup (orig); + return g_strdup_printf ("%s/%s", basepath, orig); +} + +static gboolean +eap_tls_reader (const char *eap_method, + const char *ssid, + NMSetting8021x *s_8021x, + gboolean phase2, + const char *basepath, + GError **error) +{ + const char *value; + char *ca_cert = NULL; + char *client_cert = NULL; + char *privkey = NULL; + const char *privkey_password = NULL; + gboolean success = FALSE; + NMSetting8021xCKFormat privkey_format = NM_SETTING_802_1X_CK_FORMAT_UNKNOWN; + + /* identity */ + value = wpa_get_value (ssid, "identity"); + if (!value) { + g_set_error (error, NM_SETTINGS_ERROR, NM_SETTINGS_ERROR_INVALID_CONNECTION, + "Missing IEEE_8021X_IDENTITY for EAP method '%s'.", + eap_method); + return FALSE; + } + g_object_set (s_8021x, NM_SETTING_802_1X_IDENTITY, value, NULL); + + /* ca cert */ + ca_cert = get_cert (ssid, phase2 ? "ca_cert2" : "ca_cert", basepath); + if (ca_cert) { + if (phase2) { + if (!nm_setting_802_1x_set_phase2_ca_cert (s_8021x, + ca_cert, + NM_SETTING_802_1X_CK_SCHEME_PATH, + NULL, error)) + goto done; + } else { + if (!nm_setting_802_1x_set_ca_cert (s_8021x, + ca_cert, + NM_SETTING_802_1X_CK_SCHEME_PATH, + NULL, error)) + goto done; + } + } else { + nm_log_warn (LOGD_SETTINGS, " missing %s for EAP method '%s'; this is insecure!", + phase2 ? "IEEE_8021X_INNER_CA_CERT" : + "IEEE_8021X_CA_CERT", eap_method); + } + + /* Private key password */ + privkey_password = wpa_get_value (ssid, + phase2 ? "private_key2_passwd" : + "private_key_passwd"); + + if (!privkey_password) { + g_set_error (error, NM_SETTINGS_ERROR, NM_SETTINGS_ERROR_INVALID_CONNECTION, + "Missing %s for EAP method '%s'.", + phase2 ? "IEEE_8021X_INNER_PRIVATE_KEY_PASSWORD" : + "IEEE_8021X_PRIVATE_KEY_PASSWORD", eap_method); + goto done; + } + + /* The private key itself */ + privkey = get_cert (ssid, phase2 ? "private_key2" : "private_key", basepath); + if (!privkey) { + g_set_error (error, NM_SETTINGS_ERROR, NM_SETTINGS_ERROR_INVALID_CONNECTION, + "Missing %s for EAP method '%s'.", + phase2 ? "IEEE_8021X_INNER_PRIVATE_KEY" : + "IEEE_8021X_PRIVATE_KEY", eap_method); + goto done; + } + + if (phase2) { + if (!nm_setting_802_1x_set_phase2_private_key (s_8021x, + privkey, + privkey_password, + NM_SETTING_802_1X_CK_SCHEME_PATH, + &privkey_format, + error)) + goto done; + } else { + if (!nm_setting_802_1x_set_private_key (s_8021x, + privkey, + privkey_password, + NM_SETTING_802_1X_CK_SCHEME_PATH, + &privkey_format, error)) + goto done; + } + + /* Only set the client certificate if the private key is not PKCS#12 format, + * as NM (due to supplicant restrictions) requires. If the key was PKCS#12, + * then nm_setting_802_1x_set_private_key() already set the client certificate + * to the same value as the private key. + */ + if (privkey_format == NM_SETTING_802_1X_CK_FORMAT_RAW_KEY + || privkey_format == NM_SETTING_802_1X_CK_FORMAT_X509) { + client_cert = get_cert (ssid, phase2 ? "client_cert2" : "client_cert", basepath); + if (!client_cert) { + g_set_error (error, NM_SETTINGS_ERROR, NM_SETTINGS_ERROR_INVALID_CONNECTION, + "Missing %s for EAP method '%s'.", + phase2 ? "IEEE_8021X_INNER_CLIENT_CERT" : + "IEEE_8021X_CLIENT_CERT", eap_method); + goto done; + } + + if (phase2) { + if (!nm_setting_802_1x_set_phase2_client_cert (s_8021x, + client_cert, + NM_SETTING_802_1X_CK_SCHEME_PATH, + NULL, + error)) + goto done; + } else { + if (!nm_setting_802_1x_set_client_cert (s_8021x, + client_cert, + NM_SETTING_802_1X_CK_SCHEME_PATH, + NULL, error)) + goto done; + } + } + + success = TRUE; + +done: + g_free (ca_cert); + g_free (client_cert); + g_free (privkey); + return success; +} + +static gboolean +eap_peap_reader (const char *eap_method, + const char *ssid, + NMSetting8021x *s_8021x, + gboolean phase2, + const char *basepath, + GError **error) +{ + char *ca_cert = NULL; + const char *inner_auth = NULL; + const char *peapver = NULL; + char **list = NULL, **iter, *lower; + gboolean success = FALSE; + + ca_cert = get_cert (ssid, "ca_cert", basepath); + if (ca_cert) { + if (!nm_setting_802_1x_set_ca_cert (s_8021x, + ca_cert, + NM_SETTING_802_1X_CK_SCHEME_PATH, + NULL, error)) + goto done; + } else { + nm_log_warn (LOGD_SETTINGS, " missing IEEE_8021X_CA_CERT for EAP method '%s'; this is insecure!", + eap_method); + } + + peapver = wpa_get_value (ssid, "phase1"); + /* peap version, default is automatic */ + if (peapver && strstr (peapver, "peapver")) { + if (strstr (peapver, "peapver=0")) + g_object_set (s_8021x, NM_SETTING_802_1X_PHASE1_PEAPVER, + "0", NULL); + else if (strstr (peapver, "peapver=1")) + g_object_set (s_8021x, NM_SETTING_802_1X_PHASE1_PEAPVER, + "1", NULL); + else { + g_set_error (error, NM_SETTINGS_ERROR, NM_SETTINGS_ERROR_INVALID_CONNECTION, + "Unknown IEEE_8021X_PEAP_VERSION value '%s'", + peapver); + goto done; + } + } + + /* peaplabel */ + if (peapver && strstr (peapver, "peaplabel=1")) + g_object_set (s_8021x, NM_SETTING_802_1X_PHASE1_PEAPLABEL, "1", + NULL); + + inner_auth = wpa_get_value (ssid, "phase2"); + if (!inner_auth) { + g_set_error (error, NM_SETTINGS_ERROR, NM_SETTINGS_ERROR_INVALID_CONNECTION, + "Missing IEEE_8021X_INNER_AUTH_METHODS."); + goto done; + } + /* Handle options for the inner auth method */ + list = g_strsplit (inner_auth, " ", 0); + for (iter = list; iter && *iter; iter++) { + gchar *pos = NULL; + + if (!strlen (*iter)) + continue; + + if (!(pos = strstr (*iter, "MSCHAPV2")) + || !(pos = strstr (*iter, "MD5")) + || !(pos = strstr (*iter, "GTC"))) { + if (!eap_simple_reader (pos, ssid, s_8021x, TRUE, basepath, error)) + goto done; + } else if (!(pos = strstr (*iter, "TLS"))) { + if (!eap_tls_reader (pos, ssid, s_8021x, TRUE, basepath, error)) + goto done; + } else { + g_set_error (error, NM_SETTINGS_ERROR, NM_SETTINGS_ERROR_INVALID_CONNECTION, + "Unknown IEEE_8021X_INNER_AUTH_METHOD '%s'.", + *iter); + goto done; + } + + pos = strchr (*iter, '='); + if (pos && *pos) { + pos++; + lower = g_ascii_strdown (pos, -1); + g_object_set (s_8021x, NM_SETTING_802_1X_PHASE2_AUTH, lower, + NULL); + g_free (lower); + } else { + g_set_error (error, NM_SETTINGS_ERROR, NM_SETTINGS_ERROR_INVALID_CONNECTION, + "No IEEE_8021X_INNER_AUTH_METHOD."); + goto done; + } + break; + } + + if (!nm_setting_802_1x_get_phase2_auth (s_8021x)) { + g_set_error (error, NM_SETTINGS_ERROR, NM_SETTINGS_ERROR_INVALID_CONNECTION, + "No valid IEEE_8021X_INNER_AUTH_METHODS found."); + goto done; + } + + success = TRUE; + +done: + g_free (ca_cert); + if (list) + g_strfreev (list); + return success; +} + +static gboolean +eap_ttls_reader (const char *eap_method, + const char *ssid, + NMSetting8021x *s_8021x, + gboolean phase2, + const char *basepath, + GError **error) +{ + gboolean success = FALSE; + const char *anon_ident = NULL; + char *ca_cert = NULL; + const char *tmp; + char **list = NULL, **iter, *inner_auth = NULL; + + /* ca cert */ + ca_cert = get_cert (ssid, "ca_cert", basepath); + if (ca_cert) { + if (!nm_setting_802_1x_set_ca_cert (s_8021x, + ca_cert, + NM_SETTING_802_1X_CK_SCHEME_PATH, + NULL, error)) + goto done; + } else { + nm_log_warn (LOGD_SETTINGS, " missing IEEE_8021X_CA_CERT for EAP method '%s'; this is insecure!", + eap_method); + } + + /* anonymous indentity for tls */ + anon_ident = wpa_get_value (ssid, "anonymous_identity"); + if (anon_ident && strlen (anon_ident)) + g_object_set (s_8021x, NM_SETTING_802_1X_ANONYMOUS_IDENTITY, + anon_ident, NULL); + + tmp = wpa_get_value (ssid, "phase2"); + if (!tmp) { + g_set_error (error, NM_SETTINGS_ERROR, NM_SETTINGS_ERROR_INVALID_CONNECTION, + "Missing IEEE_8021X_INNER_AUTH_METHODS."); + goto done; + } + + /* Handle options for the inner auth method */ + inner_auth = g_ascii_strdown (tmp, -1); + list = g_strsplit (inner_auth, " ", 0); + for (iter = list; iter && *iter; iter++) { + gchar *pos = NULL; + + if (!strlen (*iter)) + continue; + if ((pos = strstr (*iter, "mschapv2")) != NULL + || (pos = strstr (*iter, "mschap")) != NULL + || (pos = strstr (*iter, "pap")) != NULL + || (pos = strstr (*iter, "chap")) != NULL) { + if (!eap_simple_reader (pos, ssid, s_8021x, TRUE, basepath, error)) + goto done; + g_object_set (s_8021x, NM_SETTING_802_1X_PHASE2_AUTH, + pos, NULL); + } else if ((pos = strstr (*iter, "tls")) != NULL) { + if (!eap_tls_reader (pos, ssid, s_8021x, TRUE, basepath, error)) + goto done; + g_object_set (s_8021x, NM_SETTING_802_1X_PHASE2_AUTHEAP, + "tls", NULL); + } else if ((pos = strstr (*iter, "mschapv2")) != NULL + || (pos = strstr (*iter, "md5")) != NULL) { + if (!eap_simple_reader (pos, ssid, s_8021x, TRUE, basepath, error)) { + nm_log_warn (LOGD_SETTINGS, "SIMPLE ERROR"); + goto done; + } + g_object_set (s_8021x, NM_SETTING_802_1X_PHASE2_AUTHEAP, + pos, NULL); + } else { + g_set_error (error, NM_SETTINGS_ERROR, NM_SETTINGS_ERROR_INVALID_CONNECTION, + "Unknown IEEE_8021X_INNER_AUTH_METHOD '%s'.", + *iter); + goto done; + } + break; + } + + success = TRUE; +done: + g_free (ca_cert); + if (list) + g_strfreev (list); + g_free (inner_auth); + return success; +} + +/* type is already decided by net_parser, this function is just used to + * doing tansformation*/ +static const gchar * +guess_connection_type (const char *conn_name) +{ + const gchar *type = ifnet_get_data (conn_name, "type"); + const gchar *ret_type = NULL; + + if (!g_strcmp0 (type, "ppp")) + ret_type = NM_SETTING_PPPOE_SETTING_NAME; + + if (!g_strcmp0 (type, "wireless")) + ret_type = NM_SETTING_WIRELESS_SETTING_NAME; + + if (!ret_type) + ret_type = NM_SETTING_WIRED_SETTING_NAME; + + nm_log_info (LOGD_SETTINGS, "guessed connection type (%s) = %s", conn_name, ret_type); + return ret_type; +} + +/* Reading mac address for setting connection option. + * Unmanaged device mac address is required by NetworkManager*/ +static gboolean +read_mac_address (const char *conn_name, const char **mac, GError **error) +{ + const char *value = ifnet_get_data (conn_name, "mac"); + + if (!value || !strlen (value)) + return TRUE; + + if (!nm_utils_hwaddr_valid (value, ETH_ALEN)) { + g_set_error (error, NM_SETTINGS_ERROR, NM_SETTINGS_ERROR_INVALID_CONNECTION, + "The MAC address '%s' was invalid.", value); + return FALSE; + } + + *mac = value; + return TRUE; +} + +static gboolean +make_wired_connection_setting (NMConnection *connection, + const char *conn_name, + GError **error) +{ + const char *mac = NULL; + NMSettingWired *s_wired = NULL; + const char *value = NULL; + + s_wired = NM_SETTING_WIRED (nm_setting_wired_new ()); + + /* mtu_xxx */ + value = ifnet_get_data (conn_name, "mtu"); + if (value) { + long int mtu; + + errno = 0; + mtu = strtol (value, NULL, 10); + if (errno || mtu < 0 || mtu > 65535) { + nm_log_warn (LOGD_SETTINGS, " invalid MTU '%s' for %s", value, conn_name); + } else + g_object_set (s_wired, NM_SETTING_WIRED_MTU, + (guint32) mtu, NULL); + } + + if (!read_mac_address (conn_name, &mac, error)) { + g_object_unref (s_wired); + return FALSE; + } + + if (mac) + g_object_set (s_wired, NM_SETTING_WIRED_MAC_ADDRESS, mac, NULL); + nm_connection_add_setting (connection, NM_SETTING (s_wired)); + + return TRUE; +} + +/* add NM_SETTING_IP_CONFIG_DHCP_HOSTNAME, + * NM_SETTING_IP_CONFIG_DHCP_CLIENT_ID in future*/ +static gboolean +make_ip4_setting (NMConnection *connection, + const char *conn_name, + GError **error) +{ + + NMSettingIPConfig *ip4_setting = + NM_SETTING_IP_CONFIG (nm_setting_ip4_config_new ()); + const char *value, *method = NULL; + gboolean is_static_block = is_static_ip4 (conn_name); + ip_block *iblock = NULL; + + /* set dhcp options (dhcp_xxx) */ + value = ifnet_get_data (conn_name, "dhcp"); + g_object_set (ip4_setting, NM_SETTING_IP_CONFIG_IGNORE_AUTO_DNS, value + && strstr (value, "nodns") ? TRUE : FALSE, + NM_SETTING_IP_CONFIG_IGNORE_AUTO_ROUTES, value + && strstr (value, "nogateway") ? TRUE : FALSE, NULL); + + if (!is_static_block) { + method = ifnet_get_data (conn_name, "config"); + if (!method){ + g_set_error (error, NM_SETTINGS_ERROR, NM_SETTINGS_ERROR_INVALID_CONNECTION, + "Unknown config for %s", conn_name); + g_object_unref (ip4_setting); + return FALSE; + } + if (strstr (method, "dhcp")) + g_object_set (ip4_setting, + NM_SETTING_IP_CONFIG_METHOD, + NM_SETTING_IP4_CONFIG_METHOD_AUTO, + NM_SETTING_IP_CONFIG_NEVER_DEFAULT, FALSE, NULL); + else if (strstr (method, "autoip")) { + g_object_set (ip4_setting, + NM_SETTING_IP_CONFIG_METHOD, + NM_SETTING_IP4_CONFIG_METHOD_LINK_LOCAL, + NM_SETTING_IP_CONFIG_NEVER_DEFAULT, FALSE, NULL); + nm_connection_add_setting (connection, NM_SETTING (ip4_setting)); + return TRUE; + } else if (strstr (method, "shared")) { + g_object_set (ip4_setting, + NM_SETTING_IP_CONFIG_METHOD, + NM_SETTING_IP4_CONFIG_METHOD_SHARED, + NM_SETTING_IP_CONFIG_NEVER_DEFAULT, FALSE, NULL); + nm_connection_add_setting (connection, NM_SETTING (ip4_setting)); + return TRUE; + } else { + g_set_error (error, NM_SETTINGS_ERROR, NM_SETTINGS_ERROR_INVALID_CONNECTION, + "Unknown config for %s", conn_name); + g_object_unref (ip4_setting); + return FALSE; + } + nm_log_info (LOGD_SETTINGS, "Using %s method for %s", method, conn_name); + }else { + iblock = convert_ip4_config_block (conn_name); + if (!iblock) { + g_set_error (error, NM_SETTINGS_ERROR, NM_SETTINGS_ERROR_INVALID_CONNECTION, + "Ifnet plugin: can't aquire ip configuration for %s", + conn_name); + g_object_unref (ip4_setting); + return FALSE; + } + /************** add all ip settings to the connection**********/ + while (iblock) { + ip_block *current_iblock; + NMIPAddress *ip4_addr; + GError *local = NULL; + + ip4_addr = nm_ip_address_new (AF_INET, iblock->ip, iblock->prefix, &local); + if (iblock->next_hop) + g_object_set (ip4_setting, + NM_SETTING_IP_CONFIG_IGNORE_AUTO_ROUTES, + TRUE, NULL); + + if (ip4_addr) { + if (!nm_setting_ip_config_add_address (ip4_setting, ip4_addr)) + nm_log_warn (LOGD_SETTINGS, "ignoring duplicate IP4 address"); + nm_ip_address_unref (ip4_addr); + } else { + nm_log_warn (LOGD_SETTINGS, " ignoring invalid address entry: %s", local->message); + g_clear_error (&local); + } + + current_iblock = iblock; + iblock = iblock->next; + destroy_ip_block (current_iblock); + + } + g_object_set (ip4_setting, + NM_SETTING_IP_CONFIG_METHOD, NM_SETTING_IP4_CONFIG_METHOD_MANUAL, + NM_SETTING_IP_CONFIG_NEVER_DEFAULT, !has_default_ip4_route (conn_name), + NULL); + } + + /* add dhcp hostname and client id */ + if (!is_static_block && strstr (method, "dhcp")) { + gchar *dhcp_hostname, *client_id; + + get_dhcp_hostname_and_client_id (&dhcp_hostname, &client_id); + if (dhcp_hostname) { + g_object_set (ip4_setting, + NM_SETTING_IP_CONFIG_DHCP_HOSTNAME, + dhcp_hostname, NULL); + nm_log_info (LOGD_SETTINGS, "DHCP hostname: %s", dhcp_hostname); + g_free (dhcp_hostname); + } + if (client_id) { + g_object_set (ip4_setting, + NM_SETTING_IP4_CONFIG_DHCP_CLIENT_ID, + client_id, NULL); + nm_log_info (LOGD_SETTINGS, "DHCP client id: %s", client_id); + g_free (client_id); + } + } + + /* add all IPv4 dns servers, IPv6 servers will be ignored */ + set_ip4_dns_servers (ip4_setting, conn_name); + + /* DNS searches */ + value = ifnet_get_data (conn_name, "dns_search"); + if (value) { + gs_free char *stripped = g_strdup (value); + char **searches = NULL; + + strip_string (stripped, '"'); + + searches = g_strsplit (stripped, " ", 0); + if (searches) { + char **item; + + for (item = searches; *item; item++) { + if (strlen (*item)) { + if (!nm_setting_ip_config_add_dns_search (ip4_setting, *item)) + nm_log_warn (LOGD_SETTINGS, " duplicate DNS domain '%s'", *item); + } + } + g_strfreev (searches); + } + } + + /* static routes */ + iblock = convert_ip4_routes_block (conn_name); + while (iblock) { + ip_block *current_iblock = iblock; + const char *metric_str; + char *stripped; + gint64 metric; + NMIPRoute *route; + GError *local = NULL; + + if ((metric_str = ifnet_get_data (conn_name, "metric")) != NULL) { + metric = _nm_utils_ascii_str_to_int64 (metric_str, 10, 0, G_MAXUINT32, -1); + } else { + metric_str = ifnet_get_global_data ("metric"); + if (metric_str) { + stripped = g_strdup (metric_str); + strip_string (stripped, '"'); + metric = _nm_utils_ascii_str_to_int64 (metric_str, 10, 0, G_MAXUINT32, -1); + g_free (stripped); + } else + metric = -1; + } + + route = nm_ip_route_new (AF_INET, iblock->ip, iblock->prefix, iblock->next_hop, metric, &local); + if (route) { + if (nm_setting_ip_config_add_route (ip4_setting, route)) + nm_log_info (LOGD_SETTINGS, "new IP4 route:%s\n", iblock->ip); + else + nm_log_warn (LOGD_SETTINGS, "duplicate IP4 route"); + nm_ip_route_unref (route); + } else { + nm_log_warn (LOGD_SETTINGS, " ignoring invalid route entry: %s", local->message); + g_clear_error (&local); + } + + current_iblock = iblock; + iblock = iblock->next; + destroy_ip_block (current_iblock); + } + + /* Finally add setting to connection */ + nm_connection_add_setting (connection, NM_SETTING (ip4_setting)); + + return TRUE; +} + +static gboolean +make_ip6_setting (NMConnection *connection, + const char *conn_name, + GError **error) +{ + NMSettingIPConfig *s_ip6 = NULL; + gboolean is_static_block = is_static_ip6 (conn_name); + + // used to disable IPv6 + gboolean ipv6_enabled = FALSE; + gchar *method = NM_SETTING_IP6_CONFIG_METHOD_MANUAL; + const char *value; + ip_block *iblock; + gboolean never_default = !has_default_ip6_route (conn_name); + + s_ip6 = (NMSettingIPConfig *) nm_setting_ip6_config_new (); + + value = ifnet_get_data (conn_name, "enable_ipv6"); + if (value && is_true (value)) + ipv6_enabled = TRUE; + + //FIXME Handle other methods that NM supports in future + // Currently only Manual and DHCP are supported + if (!ipv6_enabled) { + g_object_set (s_ip6, + NM_SETTING_IP_CONFIG_METHOD, + NM_SETTING_IP6_CONFIG_METHOD_IGNORE, NULL); + goto done; + } else if (!is_static_block) { + // config_eth* contains "dhcp6" + method = NM_SETTING_IP6_CONFIG_METHOD_AUTO; + never_default = FALSE; + } + // else if (!has_ip6_address(conn_name)) + // doesn't have "dhcp6" && doesn't have any ipv6 address + // method = NM_SETTING_IP6_CONFIG_METHOD_LINK_LOCAL; + else + // doesn't have "dhcp6" && has at least one ipv6 address + method = NM_SETTING_IP6_CONFIG_METHOD_MANUAL; + nm_log_info (LOGD_SETTINGS, "IPv6 for %s enabled, using %s", conn_name, method); + + g_object_set (s_ip6, + NM_SETTING_IP_CONFIG_METHOD, method, + NM_SETTING_IP_CONFIG_IGNORE_AUTO_DNS, FALSE, + NM_SETTING_IP_CONFIG_IGNORE_AUTO_ROUTES, FALSE, + NM_SETTING_IP_CONFIG_NEVER_DEFAULT, never_default, NULL); + + /* Make manual settings */ + if (!strcmp (method, NM_SETTING_IP6_CONFIG_METHOD_MANUAL)) { + ip_block *current_iblock; + + iblock = convert_ip6_config_block (conn_name); + if (!iblock) { + g_set_error (error, NM_SETTINGS_ERROR, NM_SETTINGS_ERROR_INVALID_CONNECTION, + "Ifnet plugin: can't aquire ip6 configuration for %s", + conn_name); + goto error; + } + /* add all IPv6 addresses */ + while (iblock) { + NMIPAddress *ip6_addr; + GError *local = NULL; + + ip6_addr = nm_ip_address_new (AF_INET6, iblock->ip, iblock->prefix, &local); + if (ip6_addr) { + if (nm_setting_ip_config_add_address (s_ip6, ip6_addr)) { + nm_log_info (LOGD_SETTINGS, "ipv6 addresses count: %d", + nm_setting_ip_config_get_num_addresses (s_ip6)); + } else { + nm_log_warn (LOGD_SETTINGS, "ignoring duplicate IP6 address"); + } + nm_ip_address_unref (ip6_addr); + } else { + nm_log_warn (LOGD_SETTINGS, " ignoring invalid address entry: %s", local->message); + g_clear_error (&local); + } + + current_iblock = iblock; + iblock = iblock->next; + destroy_ip_block (current_iblock); + } + + } else if (!strcmp (method, NM_SETTING_IP6_CONFIG_METHOD_AUTO)) { + /* - autoconf or DHCPv6 stuff goes here */ + } + // DNS Servers, set NM_SETTING_IP_CONFIG_IGNORE_AUTO_DNS TRUE here + set_ip6_dns_servers (s_ip6, conn_name); + + /* DNS searches ('DOMAIN' key) are read by make_ip4_setting() and included in NMSettingIPConfig */ + + // Add routes + iblock = convert_ip6_routes_block (conn_name); + if (iblock) + g_object_set (s_ip6, NM_SETTING_IP_CONFIG_IGNORE_AUTO_ROUTES, + TRUE, NULL); + /* Add all IPv6 routes */ + while (iblock) { + ip_block *current_iblock = iblock; + const char *metric_str; + char *stripped; + gint64 metric; + NMIPRoute *route; + GError *local = NULL; + + /* metric is not per routes configuration right now + * global metric is also supported (metric="x") */ + if ((metric_str = ifnet_get_data (conn_name, "metric")) != NULL) + metric = _nm_utils_ascii_str_to_int64 (metric_str, 10, 0, G_MAXUINT32, -1); + else { + metric_str = ifnet_get_global_data ("metric"); + if (metric_str) { + stripped = g_strdup (metric_str); + strip_string (stripped, '"'); + metric = _nm_utils_ascii_str_to_int64 (metric_str, 10, 0, G_MAXUINT32, -1); + g_free (stripped); + } else + metric = 1; + } + + route = nm_ip_route_new (AF_INET6, iblock->ip, iblock->prefix, iblock->next_hop, metric, &local); + if (route) { + if (nm_setting_ip_config_add_route (s_ip6, route)) + nm_log_info (LOGD_SETTINGS, " new IP6 route"); + else + nm_log_warn (LOGD_SETTINGS, " duplicate IP6 route"); + nm_ip_route_unref (route); + } else { + nm_log_warn (LOGD_SETTINGS, " ignoring invalid route entry: %s", local->message); + g_clear_error (&local); + } + + current_iblock = iblock; + iblock = iblock->next; + destroy_ip_block (current_iblock); + } + +done: + nm_connection_add_setting (connection, NM_SETTING (s_ip6)); + return TRUE; + +error: + g_object_unref (s_ip6); + nm_log_warn (LOGD_SETTINGS, " Ignore IPv6 for %s", conn_name); + return FALSE; +} + +static NMSetting * +make_wireless_connection_setting (const char *conn_name, + NMSetting8021x **s_8021x, + GError **error) +{ + const char *mac = NULL; + NMSettingWireless *wireless_setting = NULL; + gboolean adhoc = FALSE; + const char *value; + const char *type; + + /* PPP over WIFI is not supported yet */ + g_return_val_if_fail (conn_name != NULL + && strcmp (ifnet_get_data (conn_name, "type"), + "ppp") != 0, NULL); + type = ifnet_get_data (conn_name, "type"); + if (strcmp (type, "ppp") == 0) { + nm_log_warn (LOGD_SETTINGS, "PPP over WIFI is not supported yet"); + return NULL; + } + + wireless_setting = NM_SETTING_WIRELESS (nm_setting_wireless_new ()); + if (read_mac_address (conn_name, &mac, error)) { + if (mac) { + g_object_set (wireless_setting, + NM_SETTING_WIRELESS_MAC_ADDRESS, mac, + NULL); + } + } else { + g_object_unref (wireless_setting); + return NULL; + } + + /* handle ssid (hex and ascii) */ + if (conn_name) { + GBytes *bytes; + gsize ssid_len = 0, value_len = strlen (conn_name); + + ssid_len = value_len; + if ((value_len > 2) && (g_str_has_prefix (conn_name, "0x"))) { + /* Hex representation */ + if (value_len % 2) { + g_set_error (error, NM_SETTINGS_ERROR, NM_SETTINGS_ERROR_INVALID_CONNECTION, + "Invalid SSID '%s' size (looks like hex but length not multiple of 2)", + conn_name); + goto error; + } + + bytes = nm_utils_hexstr2bin (conn_name); + if (!bytes) { + g_set_error (error, NM_SETTINGS_ERROR, NM_SETTINGS_ERROR_INVALID_CONNECTION, + "Invalid SSID '%s' (looks like hex SSID but isn't)", + conn_name); + goto error; + } + } else + bytes = g_bytes_new (conn_name, value_len); + + ssid_len = g_bytes_get_size (bytes); + if (ssid_len > 32 || ssid_len == 0) { + g_set_error (error, NM_SETTINGS_ERROR, NM_SETTINGS_ERROR_INVALID_CONNECTION, + "Invalid SSID '%s' (size %zu not between 1 and 32 inclusive)", + conn_name, ssid_len); + goto error; + } + + g_object_set (wireless_setting, NM_SETTING_WIRELESS_SSID, bytes, NULL); + g_bytes_unref (bytes); + } else { + g_set_error (error, NM_SETTINGS_ERROR, NM_SETTINGS_ERROR_INVALID_CONNECTION, + "Missing SSID"); + goto error; + } + + /* mode=0: infrastructure + * mode=1: adhoc */ + value = wpa_get_value (conn_name, "mode"); + if (value) + adhoc = strcmp (value, "1") == 0 ? TRUE : FALSE; + + if (exist_ssid (conn_name)) { + const char *mode = adhoc ? "adhoc" : "infrastructure"; + + g_object_set (wireless_setting, NM_SETTING_WIRELESS_MODE, mode, + NULL); + nm_log_info (LOGD_SETTINGS, "Using mode: %s", mode); + } + + /* BSSID setting */ + value = wpa_get_value (conn_name, "bssid"); + if (value) { + if (!nm_utils_hwaddr_valid (value, ETH_ALEN)) { + g_set_error (error, NM_SETTINGS_ERROR, NM_SETTINGS_ERROR_INVALID_CONNECTION, + "Invalid BSSID '%s'", value); + goto error; + } + + g_object_set (wireless_setting, NM_SETTING_WIRELESS_BSSID, + value, NULL); + + } + + /* mtu_ssid="xx" */ + value = ifnet_get_data (conn_name, "mtu"); + if (value) { + long int mtu; + + errno = 0; + mtu = strtol (value, NULL, 10); + if (errno || mtu < 0 || mtu > 50000) { + nm_log_warn (LOGD_SETTINGS, " invalid MTU '%s' for %s", value, conn_name); + } else + g_object_set (wireless_setting, NM_SETTING_WIRELESS_MTU, + (guint32) mtu, NULL); + + } + + nm_log_info (LOGD_SETTINGS, "wireless_setting added for %s", conn_name); + return NM_SETTING (wireless_setting); +error: + if (wireless_setting) + g_object_unref (wireless_setting); + return NULL; + +} + +static NMSettingWirelessSecurity * +make_leap_setting (const char *ssid, GError **error) +{ + NMSettingWirelessSecurity *wsec; + const char *value; + + wsec = + NM_SETTING_WIRELESS_SECURITY (nm_setting_wireless_security_new ()); + + value = wpa_get_value (ssid, "password"); + if (value && strlen (value)) + g_object_set (wsec, NM_SETTING_WIRELESS_SECURITY_LEAP_PASSWORD, + value, NULL); + + value = wpa_get_value (ssid, "identity"); + if (!value || !strlen (value)) { + g_set_error (error, NM_SETTINGS_ERROR, NM_SETTINGS_ERROR_INVALID_CONNECTION, + "Missing LEAP identity"); + goto error; + } + g_object_set (wsec, NM_SETTING_WIRELESS_SECURITY_LEAP_USERNAME, value, + NULL); + + g_object_set (wsec, + NM_SETTING_WIRELESS_SECURITY_KEY_MGMT, "ieee8021x", + NM_SETTING_WIRELESS_SECURITY_AUTH_ALG, "leap", NULL); + + return wsec; +error: + if (wsec) + g_object_unref (wsec); + return NULL; +} + +static gboolean +add_one_wep_key (const char *ssid, + const char *key, + int key_idx, + NMSettingWirelessSecurity *s_wsec, + GError **error) +{ + const char *value; + char *converted = NULL; + gboolean success = FALSE; + + g_return_val_if_fail (ssid != NULL, FALSE); + g_return_val_if_fail (key != NULL, FALSE); + g_return_val_if_fail (key_idx >= 0 && key_idx <= 3, FALSE); + g_return_val_if_fail (s_wsec != NULL, FALSE); + + value = wpa_get_value (ssid, key); + if (!value) + return TRUE; + + /* Validate keys */ + if (strlen (value) == 10 || strlen (value) == 26) { + /* Hexadecimal WEP key */ + if (!is_hex (value)) { + g_set_error (error, NM_SETTINGS_ERROR, NM_SETTINGS_ERROR_INVALID_CONNECTION, + "Invalid hexadecimal WEP key."); + goto out; + } + converted = g_strdup (value); + } else if (value[0] == '"' + && (strlen (value) == 7 || strlen (value) == 15)) { + /* ASCII passphrase */ + char *tmp = g_strdup (value); + char *p = strip_string (tmp, '"'); + + if (!is_ascii (p)) { + g_set_error (error, NM_SETTINGS_ERROR, NM_SETTINGS_ERROR_INVALID_CONNECTION, + "Invalid ASCII WEP passphrase."); + g_free (tmp); + goto out; + + } + + converted = nm_utils_bin2hexstr (tmp, strlen (tmp), -1); + g_free (tmp); + } else { + g_set_error (error, NM_SETTINGS_ERROR, NM_SETTINGS_ERROR_INVALID_CONNECTION, + "Invalid WEP key length. Key: %s", value); + goto out; + } + + if (converted) { + nm_setting_wireless_security_set_wep_key (s_wsec, key_idx, converted); + g_free (converted); + success = TRUE; + } + +out: + return success; +} + +static gboolean +add_wep_keys (const char *ssid, + NMSettingWirelessSecurity *s_wsec, + GError **error) +{ + if (!add_one_wep_key (ssid, "wep_key0", 0, s_wsec, error)) + return FALSE; + if (!add_one_wep_key (ssid, "wep_key1", 1, s_wsec, error)) + return FALSE; + if (!add_one_wep_key (ssid, "wep_key2", 2, s_wsec, error)) + return FALSE; + if (!add_one_wep_key (ssid, "wep_key3", 3, s_wsec, error)) + return FALSE; + return TRUE; + +} + +static NMSettingWirelessSecurity * +make_wep_setting (const char *ssid, GError **error) +{ + const char *auth_alg, *value; + int default_key_idx = 0; + NMSettingWirelessSecurity *s_wireless_sec; + + s_wireless_sec = + NM_SETTING_WIRELESS_SECURITY (nm_setting_wireless_security_new ()); + g_object_set (s_wireless_sec, NM_SETTING_WIRELESS_SECURITY_KEY_MGMT, + "none", NULL); + + /* default key index */ + value = wpa_get_value (ssid, "wep_tx_keyidx"); + if (value) { + default_key_idx = atoi (value); + if (default_key_idx >= 0 && default_key_idx <= 3) { + g_object_set (s_wireless_sec, + NM_SETTING_WIRELESS_SECURITY_WEP_TX_KEYIDX, + default_key_idx, NULL); + nm_log_info (LOGD_SETTINGS, "Default key index: %d", default_key_idx); + } else { + g_set_error (error, NM_SETTINGS_ERROR, NM_SETTINGS_ERROR_INVALID_CONNECTION, + "Invalid default WEP key '%s'", value); + goto error; + } + } + + if (!add_wep_keys (ssid, s_wireless_sec, error)) + goto error; + + /* If there's a default key, ensure that key exists */ + if ((default_key_idx == 1) + && !nm_setting_wireless_security_get_wep_key (s_wireless_sec, 1)) { + g_set_error (error, NM_SETTINGS_ERROR, NM_SETTINGS_ERROR_INVALID_CONNECTION, + "Default WEP key index was 2, but no valid KEY2 exists."); + goto error; + } else if ((default_key_idx == 2) + && !nm_setting_wireless_security_get_wep_key (s_wireless_sec, + 2)) { + g_set_error (error, NM_SETTINGS_ERROR, NM_SETTINGS_ERROR_INVALID_CONNECTION, + "Default WEP key index was 3, but no valid KEY3 exists."); + goto error; + } else if ((default_key_idx == 3) + && !nm_setting_wireless_security_get_wep_key (s_wireless_sec, + 3)) { + g_set_error (error, NM_SETTINGS_ERROR, NM_SETTINGS_ERROR_INVALID_CONNECTION, + "Default WEP key index was 4, but no valid KEY4 exists."); + goto error; + } + + /* authentication algorithms */ + auth_alg = wpa_get_value (ssid, "auth_alg"); + if (auth_alg) { + if (strcmp (auth_alg, "OPEN") == 0) { + g_object_set (s_wireless_sec, + NM_SETTING_WIRELESS_SECURITY_AUTH_ALG, + "open", NULL); + nm_log_info (LOGD_SETTINGS, "WEP: Use open system authentication"); + } else if (strcmp (auth_alg, "SHARED") == 0) { + g_object_set (s_wireless_sec, + NM_SETTING_WIRELESS_SECURITY_AUTH_ALG, + "shared", NULL); + nm_log_info (LOGD_SETTINGS, "WEP: Use shared system authentication"); + } else { + g_set_error (error, NM_SETTINGS_ERROR, NM_SETTINGS_ERROR_INVALID_CONNECTION, + "Invalid WEP authentication algorithm '%s'", + auth_alg); + goto error; + } + + } + + if (!nm_setting_wireless_security_get_wep_key (s_wireless_sec, 0) + && !nm_setting_wireless_security_get_wep_key (s_wireless_sec, 1) + && !nm_setting_wireless_security_get_wep_key (s_wireless_sec, 2) + && !nm_setting_wireless_security_get_wep_key (s_wireless_sec, 3) + && !nm_setting_wireless_security_get_wep_tx_keyidx (s_wireless_sec)) { + if (auth_alg && !strcmp (auth_alg, "shared")) { + g_set_error (error, NM_SETTINGS_ERROR, NM_SETTINGS_ERROR_INVALID_CONNECTION, + "WEP Shared Key authentication is invalid for " + "unencrypted connections."); + goto error; + } + /* Unencrypted */ + g_object_unref (s_wireless_sec); + s_wireless_sec = NULL; + } + return s_wireless_sec; + +error: + if (s_wireless_sec) + g_object_unref (s_wireless_sec); + return NULL; +} + +static char * +parse_wpa_psk (const char *psk, GError **error) +{ + char *hashed = NULL; + gboolean quoted = FALSE; + + if (!psk) { + g_set_error (error, NM_SETTINGS_ERROR, NM_SETTINGS_ERROR_INVALID_CONNECTION, + "Missing WPA_PSK for WPA-PSK key management"); + return NULL; + } + + /* Passphrase must be between 10 and 66 characters in length because WPA + * hex keys are exactly 64 characters (no quoting), and WPA passphrases + * are between 8 and 63 characters (inclusive), plus optional quoting if + * the passphrase contains spaces. + */ + + if (psk[0] == '"' && psk[strlen (psk) - 1] == '"') + quoted = TRUE; + if (!quoted && (strlen (psk) == 64)) { + /* Verify the hex PSK; 64 digits */ + if (!is_hex (psk)) { + g_set_error (error, NM_SETTINGS_ERROR, NM_SETTINGS_ERROR_INVALID_CONNECTION, + "Invalid WPA_PSK (contains non-hexadecimal characters)"); + goto out; + } + hashed = g_strdup (psk); + } else { + char *stripped = g_strdup (psk); + + strip_string (stripped, '"'); + + /* Length check */ + if (strlen (stripped) < 8 || strlen (stripped) > 63) { + g_set_error (error, NM_SETTINGS_ERROR, NM_SETTINGS_ERROR_INVALID_CONNECTION, + "Invalid WPA_PSK (passphrases must be between " + "8 and 63 characters long (inclusive))"); + g_free (stripped); + goto out; + } + + hashed = g_strdup (stripped); + g_free (stripped); + } + + if (!hashed) { + g_set_error (error, NM_SETTINGS_ERROR, NM_SETTINGS_ERROR_INVALID_CONNECTION, + "Invalid WPA_PSK (doesn't look like a passphrase or hex key)"); + goto out; + } + +out: + return hashed; +} + +static gboolean +fill_wpa_ciphers (const char *ssid, + NMSettingWirelessSecurity *wsec, + gboolean group, + gboolean adhoc) +{ + const char *value; + char **list = NULL, **iter; + int i = 0; + + value = wpa_get_value (ssid, group ? "group" : "pairwise"); + if (!value) + return TRUE; + + list = g_strsplit_set (value, " ", 0); + for (iter = list; iter && *iter; iter++, i++) { + /* Ad-Hoc configurations cannot have pairwise ciphers, and can only + * have one group cipher. Ignore any additional group ciphers and + * any pairwise ciphers specified. + */ + if (adhoc) { + if (group && (i > 0)) { + nm_log_warn (LOGD_SETTINGS, " ignoring group cipher '%s' (only one group cipher allowed in Ad-Hoc mode)", + *iter); + continue; + } else if (!group) { + nm_log_warn (LOGD_SETTINGS, " ignoring pairwise cipher '%s' (pairwise not used in Ad-Hoc mode)", + *iter); + continue; + } + } + + if (!strcmp (*iter, "CCMP")) { + if (group) + nm_setting_wireless_security_add_group (wsec, + "ccmp"); + else + nm_setting_wireless_security_add_pairwise (wsec, + "ccmp"); + } else if (!strcmp (*iter, "TKIP")) { + if (group) + nm_setting_wireless_security_add_group (wsec, + "tkip"); + else + nm_setting_wireless_security_add_pairwise (wsec, + "tkip"); + } else if (group && !strcmp (*iter, "WEP104")) + nm_setting_wireless_security_add_group (wsec, "wep104"); + else if (group && !strcmp (*iter, "WEP40")) + nm_setting_wireless_security_add_group (wsec, "wep40"); + else { + nm_log_warn (LOGD_SETTINGS, " ignoring invalid %s cipher '%s'", + group ? "CIPHER_GROUP" : "CIPHER_PAIRWISE", + *iter); + } + } + + if (list) + g_strfreev (list); + return TRUE; +} + +static NMSetting8021x * +fill_8021x (const char *ssid, + const char *key_mgmt, + gboolean wifi, + const char *basepath, + GError **error) +{ + NMSetting8021x *s_8021x; + const char *value; + char **list, **iter; + + value = wpa_get_value (ssid, "eap"); + if (!value) { + g_set_error (error, NM_SETTINGS_ERROR, NM_SETTINGS_ERROR_INVALID_CONNECTION, + "Missing IEEE_8021X_EAP_METHODS for key management '%s'", + key_mgmt); + return NULL; + } + + list = g_strsplit (value, " ", 0); + + s_8021x = (NMSetting8021x *) nm_setting_802_1x_new (); + /* Validate and handle each EAP method */ + for (iter = list; iter && *iter; iter++) { + EAPReader *eap = &eap_readers[0]; + gboolean found = FALSE; + char *lower = NULL; + + lower = g_ascii_strdown (*iter, -1); + while (eap->method) { + if (strcmp (eap->method, lower)) + goto next; + + /* Some EAP methods don't provide keying material, thus they + * cannot be used with WiFi unless they are an inner method + * used with TTLS or PEAP or whatever. + */ + if (wifi && eap->wifi_phase2_only) { + nm_log_warn (LOGD_SETTINGS, " ignored invalid IEEE_8021X_EAP_METHOD '%s'; not allowed for wifi.", + lower); + goto next; + } + + /* Parse EAP method specific options */ + if (!(*eap->reader) (lower, ssid, s_8021x, FALSE, basepath, error)) { + g_free (lower); + goto error; + } + nm_setting_802_1x_add_eap_method (s_8021x, lower); + found = TRUE; + break; + + next: + eap++; + } + + if (!found) { + nm_log_warn (LOGD_SETTINGS, " ignored unknown IEEE_8021X_EAP_METHOD '%s'.", lower); + } + g_free (lower); + } + g_strfreev (list); + + if (nm_setting_802_1x_get_num_eap_methods (s_8021x) == 0) { + g_set_error (error, NM_SETTINGS_ERROR, NM_SETTINGS_ERROR_INVALID_CONNECTION, + "No valid EAP methods found in IEEE_8021X_EAP_METHODS."); + goto error; + } + + return s_8021x; + +error: + g_object_unref (s_8021x); + return NULL; +} + +static NMSettingWirelessSecurity * +make_wpa_setting (const char *ssid, + const char *basepath, + NMSetting8021x **s_8021x, + GError **error) +{ + NMSettingWirelessSecurity *wsec; + const char *value; + char *lower; + gboolean adhoc = FALSE; + + if (!exist_ssid (ssid)) { + g_set_error (error, NM_SETTINGS_ERROR, NM_SETTINGS_ERROR_INVALID_CONNECTION, + "No security info found for ssid: %s", ssid); + return NULL; + } + + wsec = NM_SETTING_WIRELESS_SECURITY (nm_setting_wireless_security_new ()); + + /* mode=1: adhoc + * mode=0: infrastructure */ + value = wpa_get_value (ssid, "mode"); + if (value) + adhoc = strcmp (value, "1") == 0 ? TRUE : FALSE; + + /* Pairwise and Group ciphers */ + fill_wpa_ciphers (ssid, wsec, FALSE, adhoc); + fill_wpa_ciphers (ssid, wsec, TRUE, adhoc); + + /* WPA and/or RSN */ + if (adhoc) { + /* Ad-Hoc mode only supports WPA proto for now */ + nm_setting_wireless_security_add_proto (wsec, "wpa"); + } else { + nm_setting_wireless_security_add_proto (wsec, "wpa"); + nm_setting_wireless_security_add_proto (wsec, "rsn"); + + } + + value = wpa_get_value (ssid, "key_mgmt"); + if (!strcmp (value, "WPA-PSK")) { + char *psk = parse_wpa_psk (wpa_get_value (ssid, "psk"), error); + + if (!psk) + goto error; + g_object_set (wsec, NM_SETTING_WIRELESS_SECURITY_PSK, psk, + NULL); + g_free (psk); + + if (adhoc) + g_object_set (wsec, + NM_SETTING_WIRELESS_SECURITY_KEY_MGMT, + "wpa-none", NULL); + else + g_object_set (wsec, + NM_SETTING_WIRELESS_SECURITY_KEY_MGMT, + "wpa-psk", NULL); + } else if (!strcmp (value, "WPA-EAP") || !strcmp (value, "IEEE8021X")) { + if (adhoc) { + g_set_error (error, NM_SETTINGS_ERROR, NM_SETTINGS_ERROR_INVALID_CONNECTION, + "Ad-Hoc mode cannot be used with KEY_MGMT type '%s'", + value); + goto error; + } + *s_8021x = fill_8021x (ssid, value, TRUE, basepath, error); + if (!*s_8021x) + goto error; + + lower = g_ascii_strdown (value, -1); + g_object_set (wsec, NM_SETTING_WIRELESS_SECURITY_KEY_MGMT, + lower, NULL); + g_free (lower); + } else { + g_set_error (error, NM_SETTINGS_ERROR, NM_SETTINGS_ERROR_INVALID_CONNECTION, + "Unknown wireless KEY_MGMT type '%s'", value); + goto error; + } + return wsec; +error: + if (wsec) + g_object_unref (wsec); + return NULL; +} + +static NMSettingWirelessSecurity * +make_wireless_security_setting (const char *conn_name, + const char *basepath, + NMSetting8021x **s_8021x, + GError ** error) +{ + NMSettingWirelessSecurity *wsec = NULL; + const char *ssid; + gboolean adhoc = FALSE; + const char *value; + + g_return_val_if_fail (conn_name != NULL + && strcmp (ifnet_get_data (conn_name, "type"), + "ppp") != 0, NULL); + nm_log_info (LOGD_SETTINGS, "updating wireless security settings (%s).", conn_name); + + ssid = conn_name; + value = wpa_get_value (ssid, "mode"); + if (value) + adhoc = strcmp (value, "1") == 0 ? TRUE : FALSE; + + value = wpa_get_value (ssid, "key_mgmt"); + if (!adhoc && g_strcmp0 (value, "IEEE8021X") == 0) { + value = wpa_get_value (ssid, "eap"); + if (value && strcasecmp (value, "LEAP") == 0) { + wsec = make_leap_setting (ssid, error); + if (wsec == NULL) + goto error; + } + } else if (g_strcmp0 (value, "WPA-PSK") == 0 || g_strcmp0 (value, "WPA-EAP") == 0) { + wsec = make_wpa_setting (ssid, basepath, s_8021x, error); + if (wsec == NULL) + goto error; + } + if (!wsec) { + wsec = make_wep_setting (ssid, error); + if (wsec == NULL) + goto error; + } + return wsec; + +error: + g_set_error (error, NM_SETTINGS_ERROR, NM_SETTINGS_ERROR_INVALID_CONNECTION, + "Can't handle security information for ssid: %s", + conn_name); + return NULL; +} + +/* Currently only support username and password */ +static gboolean +make_pppoe_connection_setting (NMConnection *connection, + const char *conn_name, + GError **error) +{ + NMSettingPppoe *s_pppoe; + NMSettingPpp *s_ppp; + const char *value; + + s_pppoe = NM_SETTING_PPPOE (nm_setting_pppoe_new ()); + + /* username */ + value = ifnet_get_data (conn_name, "username"); + if (!value) { + g_set_error (error, NM_SETTINGS_ERROR, NM_SETTINGS_ERROR_INVALID_CONNECTION, + "ppp requires at lease a username"); + return FALSE; + } + g_object_set (s_pppoe, NM_SETTING_PPPOE_USERNAME, value, NULL); + + /* password */ + value = ifnet_get_data (conn_name, "password"); + if (!value) { + value = ""; + } + + g_object_set (s_pppoe, NM_SETTING_PPPOE_PASSWORD, value, NULL); + nm_connection_add_setting (connection, NM_SETTING (s_pppoe)); + + /* PPP setting */ + s_ppp = (NMSettingPpp *) nm_setting_ppp_new (); + nm_connection_add_setting (connection, NM_SETTING (s_ppp)); + + return TRUE; +} + +NMConnection * +ifnet_update_connection_from_config_block (const char *conn_name, + const char *basepath, + GError **error) +{ + const gchar *type = NULL; + NMConnection *connection = NULL; + NMSettingConnection *setting = NULL; + NMSetting8021x *s_8021x = NULL; + NMSettingWirelessSecurity *wsec = NULL; + gboolean auto_conn = TRUE; + const char *value = NULL; + gchar *id, *uuid; + gboolean success = FALSE; + + connection = nm_simple_connection_new (); + setting = nm_connection_get_setting_connection (connection); + if (!setting) { + setting = NM_SETTING_CONNECTION (nm_setting_connection_new ()); + g_assert (setting); + nm_connection_add_setting (connection, NM_SETTING (setting)); + } + + type = guess_connection_type (conn_name); + value = ifnet_get_data (conn_name, "auto"); + if (value && !strcmp (value, "false")) + auto_conn = FALSE; + + /* Try to read UUID from the ifnet block, otherwise generate UUID from + * the connection ID. + */ + id = connection_id_from_ifnet_name (conn_name); + uuid = g_strdup (ifnet_get_data (conn_name, "uuid")); + if (!uuid) + uuid = nm_utils_uuid_generate_from_string (id, -1, NM_UTILS_UUID_TYPE_LEGACY, NULL); + + g_object_set (setting, + NM_SETTING_CONNECTION_TYPE, type, + NM_SETTING_CONNECTION_ID, id, + NM_SETTING_CONNECTION_UUID, uuid, + NM_SETTING_CONNECTION_INTERFACE_NAME, conn_name, + NM_SETTING_CONNECTION_READ_ONLY, FALSE, + NM_SETTING_CONNECTION_AUTOCONNECT, auto_conn, + NULL); + nm_log_info (LOGD_SETTINGS, "name:%s, id:%s, uuid: %s", conn_name, id, uuid); + g_free (id); + g_free (uuid); + + if (!strcmp (NM_SETTING_WIRED_SETTING_NAME, type) + || !strcmp (NM_SETTING_PPPOE_SETTING_NAME, type)) { + /* wired setting */ + if (!make_wired_connection_setting (connection, conn_name, error)) + goto error; + + /* pppoe setting */ + if (!strcmp (NM_SETTING_PPPOE_SETTING_NAME, type)) { + if (!make_pppoe_connection_setting (connection, conn_name, error)) + goto error; + } + } else if (!strcmp (NM_SETTING_WIRELESS_SETTING_NAME, type)) { + /* wireless setting */ + NMSetting *wireless_setting; + + wireless_setting = make_wireless_connection_setting (conn_name, &s_8021x, error); + if (!wireless_setting) + goto error; + nm_connection_add_setting (connection, wireless_setting); + + /* wireless security setting */ + if (wpa_get_value (conn_name, "ssid")) { + wsec = make_wireless_security_setting (conn_name, basepath, &s_8021x, error); + if (!wsec) + goto error; + nm_connection_add_setting (connection, NM_SETTING (wsec)); + if (s_8021x) + nm_connection_add_setting (connection, NM_SETTING (s_8021x)); + } + } else + goto error; + + /* IPv4 setting */ + if (!make_ip4_setting (connection, conn_name, error)) + goto error; + + /* IPv6 setting */ + if (!make_ip6_setting (connection, conn_name, error)) + goto error; + + if (nm_connection_verify (connection, error)) { + nm_log_info (LOGD_SETTINGS, "Connection verified %s:%d", conn_name, success); + } else { + goto error; + } + + return connection; +error: + g_object_unref (connection); + return NULL; +} + +typedef struct Setting8021xSchemeVtable { + const NMSetting8021xSchemeVtable *vtable; + const char *ifnet_key; +} Setting8021xSchemeVtable; + +static const Setting8021xSchemeVtable setting_8021x_scheme_vtable[] = { + [NM_SETTING_802_1X_SCHEME_TYPE_CA_CERT] = { + .vtable = &nm_setting_8021x_scheme_vtable[NM_SETTING_802_1X_SCHEME_TYPE_CA_CERT], + .ifnet_key = "ca_cert", + }, + [NM_SETTING_802_1X_SCHEME_TYPE_PHASE2_CA_CERT] = { + .vtable = &nm_setting_8021x_scheme_vtable[NM_SETTING_802_1X_SCHEME_TYPE_PHASE2_CA_CERT], + .ifnet_key = "ca_cert2", + }, + [NM_SETTING_802_1X_SCHEME_TYPE_CLIENT_CERT] = { + .vtable = &nm_setting_8021x_scheme_vtable[NM_SETTING_802_1X_SCHEME_TYPE_CLIENT_CERT], + .ifnet_key = "client_cert", + }, + [NM_SETTING_802_1X_SCHEME_TYPE_PHASE2_CLIENT_CERT] = { + .vtable = &nm_setting_8021x_scheme_vtable[NM_SETTING_802_1X_SCHEME_TYPE_PHASE2_CLIENT_CERT], + .ifnet_key = "client_cert2", + }, + [NM_SETTING_802_1X_SCHEME_TYPE_PRIVATE_KEY] = { + .vtable = &nm_setting_8021x_scheme_vtable[NM_SETTING_802_1X_SCHEME_TYPE_PRIVATE_KEY], + .ifnet_key = "private_key", + }, + [NM_SETTING_802_1X_SCHEME_TYPE_PHASE2_PRIVATE_KEY] = { + .vtable = &nm_setting_8021x_scheme_vtable[NM_SETTING_802_1X_SCHEME_TYPE_PHASE2_PRIVATE_KEY], + .ifnet_key = "private_key2", + }, +}; + +static gboolean +write_object (NMSetting8021x *s_8021x, + const char *conn_name, + GBytes *override_data, + const Setting8021xSchemeVtable *objtype, + GError **error) +{ + NMSetting8021xCKScheme scheme; + const char *path = NULL; + GBytes *blob = NULL; + + g_return_val_if_fail (conn_name != NULL, FALSE); + g_return_val_if_fail (objtype != NULL, FALSE); + if (override_data) + /* if given explicit data to save, always use that instead of asking + * the setting what to do. + */ + blob = override_data; + else { + scheme = (*(objtype->vtable->scheme_func)) (s_8021x); + switch (scheme) { + case NM_SETTING_802_1X_CK_SCHEME_BLOB: + blob = (*(objtype->vtable->blob_func)) (s_8021x); + break; + case NM_SETTING_802_1X_CK_SCHEME_PATH: + path = (*(objtype->vtable->path_func)) (s_8021x); + break; + default: + break; + } + } + + /* If the object path was specified, prefer that over any raw cert data that + * may have been sent. + */ + if (path) { + wpa_set_data (conn_name, (gchar *) objtype->ifnet_key, + (gchar *) path); + return TRUE; + } + + /* does not support writing encryption data now */ + if (blob) + nm_log_warn (LOGD_SETTINGS, " Currently we do not support cert writing."); + + return TRUE; +} + +static gboolean +write_8021x_certs (NMSetting8021x *s_8021x, + gboolean phase2, + const char *conn_name, + GError **error) +{ + char *password = NULL; + const Setting8021xSchemeVtable *otype = NULL; + gboolean is_pkcs12 = FALSE, success = FALSE; + GBytes *blob = NULL; + GBytes *enc_key = NULL; + gchar *generated_pw = NULL; + + /* CA certificate */ + otype = phase2 + ? &setting_8021x_scheme_vtable[NM_SETTING_802_1X_SCHEME_TYPE_PHASE2_CA_CERT] + : &setting_8021x_scheme_vtable[NM_SETTING_802_1X_SCHEME_TYPE_CA_CERT]; + + if (!write_object (s_8021x, conn_name, NULL, otype, error)) + return FALSE; + + /* Private key */ + if (phase2) { + if (nm_setting_802_1x_get_phase2_private_key_scheme (s_8021x) != + NM_SETTING_802_1X_CK_SCHEME_UNKNOWN) { + if (nm_setting_802_1x_get_phase2_private_key_format + (s_8021x) == NM_SETTING_802_1X_CK_FORMAT_PKCS12) + is_pkcs12 = TRUE; + } + password = (char *) + nm_setting_802_1x_get_phase2_private_key_password (s_8021x); + } else { + if (nm_setting_802_1x_get_private_key_scheme (s_8021x) != + NM_SETTING_802_1X_CK_SCHEME_UNKNOWN) { + if (nm_setting_802_1x_get_private_key_format (s_8021x) + == NM_SETTING_802_1X_CK_FORMAT_PKCS12) + is_pkcs12 = TRUE; + } + password = (char *) + nm_setting_802_1x_get_private_key_password (s_8021x); + } + + otype = phase2 + ? &setting_8021x_scheme_vtable[NM_SETTING_802_1X_SCHEME_TYPE_PHASE2_PRIVATE_KEY] + : &setting_8021x_scheme_vtable[NM_SETTING_802_1X_SCHEME_TYPE_PRIVATE_KEY]; + + if ((*(otype->vtable->scheme_func)) (s_8021x) == + NM_SETTING_802_1X_CK_SCHEME_BLOB) + blob = (*(otype->vtable->blob_func)) (s_8021x); + + /* Only do the private key re-encrypt dance if we got the raw key data, which + * by definition will be unencrypted. If we're given a direct path to the + * private key file, it'll be encrypted, so we don't need to re-encrypt. + */ + if (blob && !is_pkcs12) { + GByteArray *tmp_enc_key; + + /* Encrypt the unencrypted private key with the fake password */ + tmp_enc_key = + nm_utils_rsa_key_encrypt (g_bytes_get_data (blob, NULL), g_bytes_get_size (blob), + password, &generated_pw, error); + if (!tmp_enc_key) + goto out; + + enc_key = g_byte_array_free_to_bytes (tmp_enc_key); + + if (generated_pw) + password = generated_pw; + } + + /* Save the private key */ + if (!write_object + (s_8021x, conn_name, enc_key ? enc_key : blob, otype, error)) + goto out; + + if (phase2) + wpa_set_data (conn_name, "private_key2_passwd", password); + else + wpa_set_data (conn_name, "private_key_passwd", password); + + /* Client certificate */ + if (is_pkcs12) { + wpa_set_data (conn_name, + phase2 ? "client_cert2" : "client_cert", NULL); + } else { + otype = phase2 + ? &setting_8021x_scheme_vtable[NM_SETTING_802_1X_SCHEME_TYPE_PHASE2_CLIENT_CERT] + : &setting_8021x_scheme_vtable[NM_SETTING_802_1X_SCHEME_TYPE_CLIENT_CERT]; + + /* Save the client certificate */ + if (!write_object (s_8021x, conn_name, NULL, otype, error)) + goto out; + } + + success = TRUE; +out: + if (generated_pw) { + memset (generated_pw, 0, strlen (generated_pw)); + g_free (generated_pw); + } + if (enc_key) { + memset ((gpointer) g_bytes_get_data (enc_key, NULL), 0, g_bytes_get_size (enc_key)); + g_bytes_unref (enc_key); + } + return success; +} + +static gboolean +write_8021x_setting (NMConnection *connection, + const char *conn_name, + gboolean wired, + GError **error) +{ + NMSetting8021x *s_8021x; + const char *value; + char *tmp = NULL; + gboolean success = FALSE; + GString *phase2_auth; + GString *phase1; + + s_8021x = nm_connection_get_setting_802_1x (connection); + if (!s_8021x) { + return TRUE; + } + + nm_log_info (LOGD_SETTINGS, "Adding 8021x setting for %s", conn_name); + + /* If wired, write KEY_MGMT */ + if (wired) + wpa_set_data (conn_name, "key_mgmt", "IEEE8021X"); + + /* EAP method */ + if (nm_setting_802_1x_get_num_eap_methods (s_8021x)) { + value = nm_setting_802_1x_get_eap_method (s_8021x, 0); + if (value) + tmp = g_ascii_strup (value, -1); + } + wpa_set_data (conn_name, "eap", tmp ? tmp : NULL); + g_free (tmp); + + wpa_set_data (conn_name, "identity", + (gchar *) nm_setting_802_1x_get_identity (s_8021x)); + + wpa_set_data (conn_name, "anonymous_identity", (gchar *) + nm_setting_802_1x_get_anonymous_identity (s_8021x)); + + wpa_set_data (conn_name, "password", + (gchar *) nm_setting_802_1x_get_password (s_8021x)); + + phase1 = g_string_new (NULL); + + /* PEAP version */ + wpa_set_data (conn_name, "phase1", NULL); + value = nm_setting_802_1x_get_phase1_peapver (s_8021x); + if (value && (!strcmp (value, "0") || !strcmp (value, "1"))) + g_string_append_printf (phase1, "peapver=%s ", value); + + /* PEAP label */ + value = nm_setting_802_1x_get_phase1_peaplabel (s_8021x); + if (value && !strcmp (value, "1")) + g_string_append_printf (phase1, "peaplabel=%s ", value); + if (phase1->len) { + tmp = g_strstrip (g_strdup (phase1->str)); + wpa_set_data (conn_name, "phase1", tmp); + g_free (tmp); + } + + /* Phase2 auth methods */ + wpa_set_data (conn_name, "phase2", NULL); + phase2_auth = g_string_new (NULL); + + value = nm_setting_802_1x_get_phase2_auth (s_8021x); + if (value) { + tmp = g_ascii_strup (value, -1); + g_string_append_printf (phase2_auth, "auth=%s ", tmp); + g_free (tmp); + } + + /* Phase2 auth heap */ + value = nm_setting_802_1x_get_phase2_autheap (s_8021x); + if (value) { + tmp = g_ascii_strup (value, -1); + g_string_append_printf (phase2_auth, "autheap=%s ", tmp); + g_free (tmp); + } + tmp = g_strstrip (g_strdup (phase2_auth->str)); + wpa_set_data (conn_name, "phase2", phase2_auth->len ? tmp : NULL); + g_free (tmp); + + g_string_free (phase2_auth, TRUE); + g_string_free (phase1, TRUE); + + success = write_8021x_certs (s_8021x, FALSE, conn_name, error); + if (success) { + /* phase2/inner certs */ + success = write_8021x_certs (s_8021x, TRUE, conn_name, error); + } + + return success; +} + +static gboolean +write_wireless_security_setting (NMConnection * connection, + gchar * conn_name, + gboolean adhoc, + gboolean * no_8021x, GError ** error) +{ + NMSettingWirelessSecurity *s_wsec; + const char *key_mgmt, *auth_alg, *key, *cipher, *psk; + gboolean wep = FALSE, wpa = FALSE; + char *tmp; + guint32 i, num; + GString *str; + + s_wsec = nm_connection_get_setting_wireless_security (connection); + if (!s_wsec) { + g_set_error (error, NM_SETTINGS_ERROR, NM_SETTINGS_ERROR_INVALID_CONNECTION, + "Missing '%s' setting", + NM_SETTING_WIRELESS_SECURITY_SETTING_NAME); + return FALSE; + } + + key_mgmt = nm_setting_wireless_security_get_key_mgmt (s_wsec); + g_assert (key_mgmt); + + auth_alg = nm_setting_wireless_security_get_auth_alg (s_wsec); + + if (!strcmp (key_mgmt, "none")) { + wpa_set_data (conn_name, "key_mgmt", "NONE"); + wep = TRUE; + *no_8021x = TRUE; + } else if (!strcmp (key_mgmt, "wpa-none") + || !strcmp (key_mgmt, "wpa-psk")) { + wpa_set_data (conn_name, "key_mgmt", "WPA-PSK"); + wpa = TRUE; + *no_8021x = TRUE; + } else if (!strcmp (key_mgmt, "ieee8021x")) { + wpa_set_data (conn_name, "key_mgmt", "IEEE8021X"); + } else if (!strcmp (key_mgmt, "wpa-eap")) { + wpa_set_data (conn_name, "key_mgmt", "WPA-EAP"); + wpa = TRUE; + } else + nm_log_warn (LOGD_SETTINGS, "Unknown key_mgmt: %s", key_mgmt); + + if (auth_alg) { + if (!strcmp (auth_alg, "shared")) + wpa_set_data (conn_name, "auth_alg", "SHARED"); + else if (!strcmp (auth_alg, "open")) + wpa_set_data (conn_name, "auth_alg", "OPEN"); + else if (!strcmp (auth_alg, "leap")) { + wpa_set_data (conn_name, "auth_alg", "LEAP"); + wpa_set_data (conn_name, "eap", "LEAP"); + wpa_set_data (conn_name, "identity", (gchar *) + nm_setting_wireless_security_get_leap_username + (s_wsec)); + wpa_set_data (conn_name, "password", (gchar *) + nm_setting_wireless_security_get_leap_password + (s_wsec)); + *no_8021x = TRUE; + } + } else + wpa_set_data (conn_name, "auth_alg", NULL); + + /* Default WEP TX key index */ + if (wep) { + tmp = + g_strdup_printf ("%d", + nm_setting_wireless_security_get_wep_tx_keyidx + (s_wsec)); + wpa_set_data (conn_name, "wep_tx_keyidx", tmp); + g_free (tmp); + } else + wpa_set_data (conn_name, "wep_tx_keyidx", NULL); + + /* WEP keys */ + for (i = 0; i < 4; i++) { + int length; + + key = nm_setting_wireless_security_get_wep_key (s_wsec, i); + if (!key) + continue; + tmp = g_strdup_printf ("wep_key%d", i); + length = strlen (key); + if (length == 10 || length == 26 || length == 58) + wpa_set_data (conn_name, tmp, (gchar *) key); + else { + gchar *tmp_key = g_strdup_printf ("\"%s\"", key); + + wpa_set_data (conn_name, tmp, tmp_key); + g_free (tmp_key); + } + g_free (tmp); + } + + /* WPA Pairwise ciphers */ + wpa_set_data (conn_name, "pairwise", NULL); + str = g_string_new (NULL); + num = nm_setting_wireless_security_get_num_pairwise (s_wsec); + for (i = 0; i < num; i++) { + if (i > 0) + g_string_append_c (str, ' '); + cipher = nm_setting_wireless_security_get_pairwise (s_wsec, i); + tmp = g_ascii_strup (cipher, -1); + g_string_append (str, tmp); + g_free (tmp); + } + if (strlen (str->str)) + wpa_set_data (conn_name, "pairwise", str->str); + g_string_free (str, TRUE); + + /* WPA Group ciphers */ + wpa_set_data (conn_name, "group", NULL); + str = g_string_new (NULL); + num = nm_setting_wireless_security_get_num_groups (s_wsec); + for (i = 0; i < num; i++) { + if (i > 0) + g_string_append_c (str, ' '); + cipher = nm_setting_wireless_security_get_group (s_wsec, i); + tmp = g_ascii_strup (cipher, -1); + g_string_append (str, tmp); + g_free (tmp); + } + if (strlen (str->str)) + wpa_set_data (conn_name, "group", str->str); + g_string_free (str, TRUE); + + /* WPA Passphrase */ + if (wpa) { + GString *quoted = NULL; + + psk = nm_setting_wireless_security_get_psk (s_wsec); + if (psk && (strlen (psk) != 64)) { + quoted = g_string_sized_new (strlen (psk) + 2); + g_string_append_c (quoted, '"'); + g_string_append (quoted, psk); + g_string_append_c (quoted, '"'); + } + /* psk will be lost here if we don't check it for NULL */ + if (psk) + wpa_set_data (conn_name, "psk", + quoted ? quoted->str : (gchar *) psk); + if (quoted) + g_string_free (quoted, TRUE); + } else + wpa_set_data (conn_name, "psk", NULL); + + return TRUE; +} + +/* remove old ssid and add new one*/ +static void +update_wireless_ssid (NMConnection *connection, + const char *conn_name, + const char *ssid, + gboolean hex) +{ + if(strcmp (conn_name, ssid)){ + ifnet_delete_network (conn_name); + wpa_delete_security (conn_name); + } + + ifnet_add_network (ssid, "wireless"); + wpa_add_security (ssid); +} + +static gboolean +write_wireless_setting (NMConnection *connection, + const char *conn_name, + gboolean *no_8021x, + const char **out_new_name, + GError **error) +{ + NMSettingWireless *s_wireless; + GBytes *ssid; + const guint8 *ssid_data; + gsize ssid_len; + const char *mac, *bssid, *mode; + char buf[33]; + guint32 mtu, i; + gboolean adhoc = FALSE, hex_ssid = FALSE; + gchar *ssid_str, *tmp; + + s_wireless = nm_connection_get_setting_wireless (connection); + if (!s_wireless) { + g_set_error (error, NM_SETTINGS_ERROR, NM_SETTINGS_ERROR_INVALID_CONNECTION, + "Missing '%s' setting", + NM_SETTING_WIRELESS_SETTING_NAME); + return FALSE; + } + + ssid = nm_setting_wireless_get_ssid (s_wireless); + if (!ssid) { + g_set_error (error, NM_SETTINGS_ERROR, NM_SETTINGS_ERROR_INVALID_CONNECTION, + "Missing SSID in '%s' setting", + NM_SETTING_WIRELESS_SETTING_NAME); + return FALSE; + } + ssid_data = g_bytes_get_data (ssid, &ssid_len); + if (!ssid_len || ssid_len > 32) { + g_set_error (error, NM_SETTINGS_ERROR, NM_SETTINGS_ERROR_INVALID_CONNECTION, + "Invalid SSID in '%s' setting", + NM_SETTING_WIRELESS_SETTING_NAME); + return FALSE; + } + + /* If the SSID contains any non-alnum characters, we need to use + * the hex notation of the SSID instead. (Because openrc doesn't + * support these characters, see bug #356337) + */ + for (i = 0; i < ssid_len; i++) { + if (!g_ascii_isalnum (ssid_data[i])) { + hex_ssid = TRUE; + break; + } + } + + if (hex_ssid) { + GString *str; + + /* Hex SSIDs don't get quoted */ + str = g_string_sized_new (ssid_len * 2 + 3); + g_string_append (str, "0x"); + for (i = 0; i < ssid_len; i++) + g_string_append_printf (str, "%02X", ssid_data[i]); + update_wireless_ssid (connection, conn_name, str->str, hex_ssid); + ssid_str = g_string_free (str, FALSE); + } else { + /* Printable SSIDs get quoted */ + memset (buf, 0, sizeof (buf)); + memcpy (buf, ssid_data, ssid_len); + g_strstrip (buf); + update_wireless_ssid (connection, conn_name, buf, hex_ssid); + ssid_str = g_strdup (buf); + } + + ifnet_set_data (ssid_str, "mac", NULL); + mac = nm_setting_wireless_get_mac_address (s_wireless); + if (mac) + ifnet_set_data (ssid_str, "mac", mac); + + ifnet_set_data (ssid_str, "mtu", NULL); + mtu = nm_setting_wireless_get_mtu (s_wireless); + if (mtu) { + tmp = g_strdup_printf ("%u", mtu); + ifnet_set_data (ssid_str, "mtu", tmp); + g_free (tmp); + } + + ifnet_set_data (ssid_str, "mode", NULL); + mode = nm_setting_wireless_get_mode (s_wireless); + if (!mode || !strcmp (mode, "infrastructure")) { + wpa_set_data (ssid_str, "mode", "0"); + } else if (!strcmp (mode, "adhoc")) { + wpa_set_data (ssid_str, "mode", "1"); + adhoc = TRUE; + } else { + nm_log_warn (LOGD_SETTINGS, "Invalid mode '%s' in '%s' setting", + mode, NM_SETTING_WIRELESS_SETTING_NAME); + return FALSE; + } + + wpa_set_data (ssid_str, "bssid", NULL); + bssid = nm_setting_wireless_get_bssid (s_wireless); + if (bssid) + wpa_set_data (ssid_str, "bssid", bssid); + + if (nm_connection_get_setting_wireless_security (connection)) { + if (!write_wireless_security_setting + (connection, ssid_str, adhoc, no_8021x, error)) + return FALSE; + } else + wpa_delete_security (ssid_str); + + if (out_new_name) + *out_new_name = ifnet_get_data (ssid_str, "name"); + g_free (ssid_str); + return TRUE; +} + +static gboolean +write_wired_setting (NMConnection *connection, + const char *conn_name, + GError **error) +{ + NMSettingWired *s_wired; + const char *mac; + char *tmp; + guint32 mtu; + + s_wired = nm_connection_get_setting_wired (connection); + if (!s_wired) { + g_set_error (error, NM_SETTINGS_ERROR, NM_SETTINGS_ERROR_INVALID_CONNECTION, + "Missing '%s' setting", + NM_SETTING_WIRED_SETTING_NAME); + return FALSE; + } + + ifnet_set_data (conn_name, "mac", NULL); + mac = nm_setting_wired_get_mac_address (s_wired); + if (mac) + ifnet_set_data (conn_name, "mac", mac); + + ifnet_set_data (conn_name, "mtu", NULL); + mtu = nm_setting_wired_get_mtu (s_wired); + if (mtu) { + tmp = g_strdup_printf ("%u", mtu); + ifnet_set_data (conn_name, "mtu", tmp); + g_free (tmp); + } + //FIXME may add connection type in future + //ifnet_set_data (conn_name, "TYPE", TYPE_ETHERNET); + + return TRUE; +} + +static gboolean +write_ip4_setting (NMConnection *connection, const char *conn_name, GError **error) +{ + NMSettingIPConfig *s_ip4; + const char *value; + guint32 i, num; + GString *searches; + GString *ips; + GString *routes; + GString *dns; + gboolean success = FALSE; + + s_ip4 = nm_connection_get_setting_ip4_config (connection); + if (!s_ip4) { + g_set_error (error, NM_SETTINGS_ERROR, NM_SETTINGS_ERROR_INVALID_CONNECTION, + "Missing '%s' setting", + NM_SETTING_IP4_CONFIG_SETTING_NAME); + return FALSE; + } + routes = g_string_new (NULL); + + value = nm_setting_ip_config_get_method (s_ip4); + g_assert (value); + if (!strcmp (value, NM_SETTING_IP4_CONFIG_METHOD_MANUAL)) { + + num = nm_setting_ip_config_get_num_addresses (s_ip4); + ips = g_string_new (NULL); + /* IPv4 addresses */ + for (i = 0; i < num; i++) { + NMIPAddress *addr; + + addr = nm_setting_ip_config_get_address (s_ip4, i); + + g_string_append_printf (ips, "\"%s/%u", + nm_ip_address_get_address (addr), + nm_ip_address_get_prefix (addr)); + + /* only the first gateway will be written */ + if (i == 0 && nm_setting_ip_config_get_gateway (s_ip4)) { + g_string_append_printf (routes, + "\"default via %s\" ", + nm_setting_ip_config_get_gateway (s_ip4)); + } + } + ifnet_set_data (conn_name, "config", ips->str); + g_string_free (ips, TRUE); + } else if (!strcmp (value, NM_SETTING_IP4_CONFIG_METHOD_SHARED)) + ifnet_set_data (conn_name, "config", "shared"); + else if (!strcmp (value, NM_SETTING_IP4_CONFIG_METHOD_LINK_LOCAL)) + ifnet_set_data (conn_name, "config", "autoip"); + else + ifnet_set_data (conn_name, "config", "dhcp"); + + /* DNS Servers */ + num = nm_setting_ip_config_get_num_dns (s_ip4); + if (num > 0) { + dns = g_string_new (NULL); + for (i = 0; i < num; i++) { + const char *ip; + + ip = nm_setting_ip_config_get_dns (s_ip4, i); + g_string_append_printf (dns, " %s", ip); + } + ifnet_set_data (conn_name, "dns_servers", dns->str); + g_string_free (dns, TRUE); + } else + ifnet_set_data (conn_name, "dns_servers", NULL); + + /* DNS Searches */ + num = nm_setting_ip_config_get_num_dns_searches (s_ip4); + if (num > 0) { + searches = g_string_new (NULL); + for (i = 0; i < num; i++) { + if (i > 0) + g_string_append_c (searches, ' '); + g_string_append (searches, + nm_setting_ip_config_get_dns_search + (s_ip4, i)); + } + ifnet_set_data (conn_name, "dns_search", searches->str); + g_string_free (searches, TRUE); + } else + ifnet_set_data (conn_name, "dns_search", NULL); + /* FIXME Will be implemented when configuration supports it + if (!strcmp(value, NM_SETTING_IP4_CONFIG_METHOD_AUTO)) { + value = nm_setting_ip_config_get_dhcp_hostname(s_ip4); + if (value) + ifnet_set_data(conn_name, "DHCP_HOSTNAME", value, + FALSE); + + value = nm_setting_ip_config_get_dhcp_client_id(s_ip4); + if (value) + ifnet_set_data(conn_name, "DHCP_CLIENT_ID", value, + FALSE); + } + */ + + /* Static routes */ + num = nm_setting_ip_config_get_num_routes (s_ip4); + if (num > 0) { + for (i = 0; i < num; i++) { + NMIPRoute *route; + const char *next_hop; + + route = nm_setting_ip_config_get_route (s_ip4, i); + + next_hop = nm_ip_route_get_next_hop (route); + if (!next_hop) + next_hop = "0.0.0.0"; + + g_string_append_printf (routes, "\"%s/%u via %s\" ", + nm_ip_route_get_dest (route), + nm_ip_route_get_prefix (route), + next_hop); + } + } + if (routes->len > 0) + ifnet_set_data (conn_name, "routes", routes->str); + else + ifnet_set_data (conn_name, "routes", NULL); + g_string_free (routes, TRUE); + + success = TRUE; + + return success; +} + +static void +write_route6_file (NMSettingIPConfig *s_ip6, const char *conn_name) +{ + NMIPRoute *route; + const char *next_hop; + guint32 i, num; + GString *routes_string; + const char *old_routes; + + g_return_if_fail (s_ip6 != NULL); + num = nm_setting_ip_config_get_num_routes (s_ip6); + if (num == 0) + return; + + old_routes = ifnet_get_data (conn_name, "routes"); + routes_string = g_string_new (old_routes); + if (old_routes) + g_string_append (routes_string, "\" "); + for (i = 0; i < num; i++) { + route = nm_setting_ip_config_get_route (s_ip6, i); + + next_hop = nm_ip_route_get_next_hop (route); + if (!next_hop) + next_hop = "::"; + + g_string_append_printf (routes_string, "\"%s/%u via %s\" ", + nm_ip_route_get_dest (route), + nm_ip_route_get_prefix (route), + next_hop); + } + if (num > 0) + ifnet_set_data (conn_name, "routes", routes_string->str); + g_string_free (routes_string, TRUE); +} + +static gboolean +write_ip6_setting (NMConnection *connection, const char *conn_name, GError **error) +{ + NMSettingIPConfig *s_ip6; + const char *value; + guint32 i, num; + GString *searches; + NMIPAddress *addr; + + s_ip6 = nm_connection_get_setting_ip6_config (connection); + if (!s_ip6) { + g_set_error (error, NM_SETTINGS_ERROR, NM_SETTINGS_ERROR_INVALID_CONNECTION, + "Missing '%s' setting", + NM_SETTING_IP6_CONFIG_SETTING_NAME); + return FALSE; + } + + value = nm_setting_ip_config_get_method (s_ip6); + g_assert (value); + if (!strcmp (value, NM_SETTING_IP6_CONFIG_METHOD_IGNORE)) { + ifnet_set_data (conn_name, "enable_ipv6", "false"); + return TRUE; + } else if (!strcmp (value, NM_SETTING_IP6_CONFIG_METHOD_MANUAL)) { + /* nothing to do now */ + } else { + // if (!strcmp(value, NM_SETTING_IP6_CONFIG_METHOD_AUTO)) { + const char *config = ifnet_get_data (conn_name, "config"); + gchar *tmp; + + if (!config) + tmp = g_strdup_printf ("dhcp6"); + else + tmp = g_strdup_printf ("%s\" \"dhcp6\"", config); + ifnet_set_data (conn_name, "config", tmp); + g_free (tmp); + } + /* else if (!strcmp(value, NM_SETTING_IP6_CONFIG_METHOD_MANUAL)) { + } else if (!strcmp(value, NM_SETTING_IP6_CONFIG_METHOD_LINK_LOCAL)) { + } else if (!strcmp(value, NM_SETTING_IP6_CONFIG_METHOD_SHARED)) { + } */ + + /* Remember to set IPv6 enabled */ + ifnet_set_data (conn_name, "enable_ipv6", "true"); + + if (!strcmp (value, NM_SETTING_IP6_CONFIG_METHOD_MANUAL)) { + const char *config = ifnet_get_data (conn_name, "config"); + gchar *tmp; + GString *ip_str; + + if (!config) + config = ""; + num = nm_setting_ip_config_get_num_addresses (s_ip6); + + /* IPv6 addresses */ + ip_str = g_string_new (NULL); + for (i = 0; i < num; i++) { + addr = nm_setting_ip_config_get_address (s_ip6, i); + + g_string_append_printf (ip_str, "\"%s/%u\"", + nm_ip_address_get_address (addr), + nm_ip_address_get_prefix (addr)); + } + tmp = g_strdup_printf ("%s\" %s", config, ip_str->str); + ifnet_set_data (conn_name, "config", tmp); + g_free (tmp); + g_string_free (ip_str, TRUE); + } + + /* DNS Servers */ + num = nm_setting_ip_config_get_num_dns (s_ip6); + if (num > 0) { + const char *dns_servers = ifnet_get_data (conn_name, "dns_servers"); + gchar *tmp; + GString *dns_string = g_string_new (NULL); + const char *dns; + + if (!dns_servers) + dns_servers = ""; + for (i = 0; i < num; i++) { + dns = nm_setting_ip_config_get_dns (s_ip6, i); + + if (!strstr (dns_servers, dns)) + g_string_append_printf (dns_string, "%s ", dns); + } + tmp = g_strdup_printf ("%s %s", dns_servers, dns_string->str); + ifnet_set_data (conn_name, "dns_servers", tmp); + g_free (tmp); + g_string_free (dns_string, TRUE); + + } else + /* DNS Searches */ + num = nm_setting_ip_config_get_num_dns_searches (s_ip6); + if (num > 0) { + const char *ip4_domains; + + ip4_domains = ifnet_get_data (conn_name, "dns_search"); + if (!ip4_domains) + ip4_domains = ""; + searches = g_string_new (ip4_domains); + for (i = 0; i < num; i++) { + const gchar *search = NULL; + + search = + nm_setting_ip_config_get_dns_search (s_ip6, i); + if (search && !strstr (searches->str, search)) { + if (searches->len > 0) + g_string_append_c (searches, ' '); + g_string_append (searches, search); + } + } + ifnet_set_data (conn_name, "dns_search", searches->str); + g_string_free (searches, TRUE); + } + + write_route6_file (s_ip6, conn_name); + return TRUE; +} + +static gboolean +write_pppoe_setting (const char *conn_name, NMSettingPppoe * s_pppoe) +{ + const gchar *value; + + value = nm_setting_pppoe_get_username (s_pppoe); + if (!value) { + return FALSE; + } + ifnet_set_data (conn_name, "username", (gchar *) value); + + value = nm_setting_pppoe_get_password (s_pppoe); + /* password could be NULL here */ + if (value) { + ifnet_set_data (conn_name, "password", (gchar *) value); + } + return TRUE; +} + +gboolean +ifnet_update_parsers_by_connection (NMConnection *connection, + const char *conn_name, + const char *config_file, + const char *wpa_file, + gchar **out_new_name, + gchar **out_backup, + GError **error) +{ + NMSettingConnection *s_con; + NMSettingIPConfig *s_ip6; + gboolean success = FALSE; + const char *type; + gboolean no_8021x = FALSE; + gboolean wired = FALSE, pppoe = TRUE; + const char *new_name = NULL; + + if (!ifnet_can_write_connection (connection, error)) + return FALSE; + + s_con = nm_connection_get_setting_connection (connection); + g_assert (s_con); + + type = nm_setting_connection_get_connection_type (s_con); + if (!type) { + g_set_error (error, NM_SETTINGS_ERROR, NM_SETTINGS_ERROR_INVALID_CONNECTION, + "Missing connection type!"); + goto out; + } + + if (!strcmp (type, NM_SETTING_WIRED_SETTING_NAME)) { + /* Writing wired setting */ + if (!write_wired_setting (connection, conn_name, error)) + goto out; + wired = TRUE; + no_8021x = TRUE; + } else if (!strcmp (type, NM_SETTING_WIRELESS_SETTING_NAME)) { + /* Writing wireless setting */ + if (!write_wireless_setting (connection, conn_name, &no_8021x, &new_name, error)) + goto out; + } else if (!strcmp (type, NM_SETTING_PPPOE_SETTING_NAME)) { + NMSettingPppoe *s_pppoe; + + /* Writing pppoe setting */ + s_pppoe = nm_connection_get_setting_pppoe (connection); + if (!write_pppoe_setting (conn_name, s_pppoe)) + goto out; + pppoe = TRUE; + wired = TRUE; + no_8021x = TRUE; + } else { + g_set_error (error, NM_SETTINGS_ERROR, NM_SETTINGS_ERROR_NOT_SUPPORTED, + "Can't write connection type '%s'", type); + goto out; + } + + /* connection name may have been updated; use it when writing out + * the rest of the settings. + */ + if (new_name) + conn_name = new_name; + + //FIXME wired connection doesn't support 8021x now + if (!no_8021x) { + if (!write_8021x_setting (connection, conn_name, wired, error)) + goto out; + } + + /* IPv4 Setting */ + if (!write_ip4_setting (connection, conn_name, error)) + goto out; + + s_ip6 = nm_connection_get_setting_ip6_config (connection); + if (s_ip6) { + /* IPv6 Setting */ + if (!write_ip6_setting (connection, conn_name, error)) + goto out; + } + + /* Connection Setting */ + ifnet_set_data (conn_name, "auto", + nm_setting_connection_get_autoconnect (s_con) ? "true" : "false"); + ifnet_set_data (conn_name, "uuid", nm_connection_get_uuid (connection)); + + /* Write changes to disk */ + success = ifnet_flush_to_file (config_file, out_backup); + if (success) + wpa_flush_to_file (wpa_file); + + if (out_new_name) + *out_new_name = g_strdup (conn_name); + +out: + return success; +} + +gboolean +ifnet_delete_connection_in_parsers (const char *conn_name, + const char *config_file, + const char *wpa_file, + gchar **out_backup) +{ + gboolean result = FALSE; + + ifnet_delete_network (conn_name); + result = ifnet_flush_to_file (config_file, out_backup); + if (result) { + /* connection may not have security information + * so simply ignore the return value*/ + wpa_delete_security (conn_name); + wpa_flush_to_file (wpa_file); + } + + return result; +} + +static void +check_unsupported_secrets (NMSetting *setting, + const char *key, + const GValue *value, + GParamFlags flags, + gpointer user_data) +{ + gboolean *unsupported_secret = user_data; + + if (flags & NM_SETTING_PARAM_SECRET) { + NMSettingSecretFlags secret_flags = NM_SETTING_SECRET_FLAG_NONE; + + if (!nm_setting_get_secret_flags (setting, key, &secret_flags, NULL)) + g_return_if_reached (); + if (secret_flags != NM_SETTING_SECRET_FLAG_NONE) + *unsupported_secret = TRUE; + } +} + +gboolean +ifnet_can_write_connection (NMConnection *connection, GError **error) +{ + NMSettingConnection *s_con; + gboolean has_unsupported_secrets = FALSE; + + s_con = nm_connection_get_setting_connection (connection); + g_assert (s_con); + + /* If the connection is not available for all users, ignore + * it as this plugin only deals with System Connections */ + if (nm_setting_connection_get_num_permissions (s_con)) { + g_set_error_literal (error, NM_SETTINGS_ERROR, NM_SETTINGS_ERROR_NOT_SUPPORTED, + "The ifnet plugin does not support non-system-wide connections."); + return FALSE; + } + + /* Only support wired, wifi, and PPPoE */ + if ( !nm_connection_is_type (connection, NM_SETTING_WIRED_SETTING_NAME) + && !nm_connection_is_type (connection, NM_SETTING_WIRELESS_SETTING_NAME) + && !nm_connection_is_type (connection, NM_SETTING_PPPOE_SETTING_NAME)) { + g_set_error (error, NM_SETTINGS_ERROR, NM_SETTINGS_ERROR_NOT_SUPPORTED, + "The ifnet plugin cannot write the connection '%s' (type '%s')", + nm_connection_get_id (connection), + nm_setting_connection_get_connection_type (s_con)); + return FALSE; + } + + /* If the connection has flagged secrets, ignore + * it as this plugin does not deal with user agent service */ + nm_connection_for_each_setting_value (connection, + check_unsupported_secrets, + &has_unsupported_secrets); + if (has_unsupported_secrets) { + g_set_error_literal (error, NM_SETTINGS_ERROR, NM_SETTINGS_ERROR_NOT_SUPPORTED, + "The ifnet plugin only supports persistent system secrets."); + return FALSE; + } + + return TRUE; +} + +/* get the available wired name(eth*). */ +static gchar * +get_wired_name (void) +{ + int i = 0; + + for (; i < 256; i++) { + gchar *conn_name = g_strdup_printf ("eth%d", i); + + if (!ifnet_has_network (conn_name)) { + return conn_name; + } else + g_free (conn_name); + } + return NULL; +} + +/* get the available pppoe name(ppp*). */ +static gchar * +get_ppp_name (void) +{ + int i = 0; + + for (; i < 256; i++) { + gchar *conn_name = g_strdup_printf ("ppp%d", i); + + if (!ifnet_has_network (conn_name)) { + return conn_name; + } else + g_free (conn_name); + } + return NULL; +} + +/* get wireless ssid */ +static gchar * +get_wireless_name (NMConnection * connection) +{ + NMSettingWireless *s_wireless; + GBytes *ssid; + const guint8 *ssid_data; + gsize ssid_len; + gboolean hex_ssid = FALSE; + gchar *result = NULL; + char buf[33]; + int i = 0; + + s_wireless = nm_connection_get_setting_wireless (connection); + if (!s_wireless) + return NULL; + + ssid = nm_setting_wireless_get_ssid (s_wireless); + ssid_data = g_bytes_get_data (ssid, &ssid_len); + if (!ssid_len || ssid_len > 32) { + return NULL; + } + + for (i = 0; i < ssid_len; i++) { + if (!g_ascii_isprint (ssid_data[i])) { + hex_ssid = TRUE; + break; + } + } + + if (hex_ssid) { + GString *str; + + str = g_string_sized_new (ssid_len * 2 + 3); + g_string_append (str, "0x"); + for (i = 0; i < ssid_len; i++) + g_string_append_printf (str, "%02X", ssid_data[i]); + result = g_strdup (str->str); + g_string_free (str, TRUE); + } else { + memset (buf, 0, sizeof (buf)); + memcpy (buf, ssid_data, ssid_len); + result = g_strdup_printf ("%s", buf); + g_strstrip (result); + } + + return result; +} + +gboolean +ifnet_add_new_connection (NMConnection *connection, + const char *config_file, + const char *wpa_file, + gchar **out_new_name, + gchar **out_backup, + GError **error) +{ + NMSettingConnection *s_con; + gboolean success = FALSE; + const char *type; + gchar *new_type, *new_name = NULL; + + if (!ifnet_can_write_connection (connection, error)) + return FALSE; + + s_con = nm_connection_get_setting_connection (connection); + g_assert (s_con); + type = nm_setting_connection_get_connection_type (s_con); + g_assert (type); + + nm_log_info (LOGD_SETTINGS, "Adding %s connection", type); + + /* get name and type + * Wireless type: wireless + * Wired type: wired + * PPPoE type: ppp*/ + if (!strcmp (type, NM_SETTING_WIRED_SETTING_NAME)) { + new_name = get_wired_name (); + if (!new_name) + goto out; + new_type = "wired"; + } else if (!strcmp (type, NM_SETTING_WIRELESS_SETTING_NAME)) { + new_name = get_wireless_name (connection); + new_type = "wireless"; + } else if (!strcmp (type, NM_SETTING_PPPOE_SETTING_NAME)) { + new_name = get_ppp_name (); + if (!new_name) + goto out; + new_type = "ppp"; + } else { + g_set_error (error, NM_SETTINGS_ERROR, NM_SETTINGS_ERROR_NOT_SUPPORTED, + "Can't write connection type '%s'", type); + goto out; + } + + if (ifnet_add_network (new_name, new_type)) { + success = ifnet_update_parsers_by_connection (connection, + new_name, + config_file, + wpa_file, + NULL, + out_backup, + error); + } + + nm_log_info (LOGD_SETTINGS, "Added new connection: %s, result: %s", + new_name, success ? "success" : "fail"); + +out: + if (!success || !out_new_name) + g_free (new_name); + else if (out_new_name) + *out_new_name = new_name; + return success; +} + diff --git a/src/settings/plugins/ifnet/nms-ifnet-connection-parser.h b/src/settings/plugins/ifnet/nms-ifnet-connection-parser.h new file mode 100644 index 00000000..51bc34b9 --- /dev/null +++ b/src/settings/plugins/ifnet/nms-ifnet-connection-parser.h @@ -0,0 +1,55 @@ +/* -*- Mode: C; tab-width: 4; indent-tabs-mode: t; c-basic-offset: 4 -*- */ +/* + * Mu Qiao <qiaomuf@gmail.com> + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation; either version 2 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License along + * with this program; if not, write to the Free Software Foundation, Inc., + * 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA. + * + * Copyright (C) 1999-2010 Gentoo Foundation, Inc. + */ + +#ifndef _CONNECTION_PARSER_H +#define _CONNECTION_PARSER_H + +#include "nm-connection.h" + +#include "nms-ifnet-net-parser.h" + +gboolean ifnet_can_write_connection (NMConnection *connection, GError **error); + +NMConnection *ifnet_update_connection_from_config_block (const char *conn_name, + const char *basepath, + GError **error); + +/* nm_conn_name is used to update nm_ifnet_connection's priv data */ +gboolean ifnet_update_parsers_by_connection (NMConnection *connection, + const char *conn_name, + const char *config_file, + const char *wpa_file, + gchar **out_new_name, + gchar **out_backup, + GError **error); + +gboolean ifnet_delete_connection_in_parsers (const char *conn_name, + const char *config_file, + const char *wpa_file, + gchar **out_backup); + +gboolean ifnet_add_new_connection (NMConnection *connection, + const char *config_file, + const char *wpa_file, + gchar **out_new_name, + gchar **out_backup, + GError ** error); +#endif diff --git a/src/settings/plugins/ifnet/nms-ifnet-connection.c b/src/settings/plugins/ifnet/nms-ifnet-connection.c new file mode 100644 index 00000000..ce0b3f2b --- /dev/null +++ b/src/settings/plugins/ifnet/nms-ifnet-connection.c @@ -0,0 +1,233 @@ +/* -*- Mode: C; tab-width: 4; indent-tabs-mode: t; c-basic-offset: 4 -*- */ +/* + * Mu Qiao <qiaomuf@gmail.com> + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation; either version 2 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License along + * with this program; if not, write to the Free Software Foundation, Inc., + * 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA. + * + * Copyright (C) 1999-2010 Gentoo Foundation, Inc. + */ + +#include "nm-default.h" + +#include "nms-ifnet-connection.h" + +#include <string.h> +#include <glib/gstdio.h> + +#include "nm-dbus-interface.h" +#include "nm-utils.h" +#include "nm-setting-wireless-security.h" +#include "settings/nm-settings-connection.h" +#include "settings/nm-settings-plugin.h" + +#include "nms-ifnet-connection-parser.h" +#include "nms-ifnet-net-parser.h" +#include "nms-ifnet-net-utils.h" +#include "nms-ifnet-wpa-parser.h" +#include "nms-ifnet-plugin.h" + +/*****************************************************************************/ + +enum { + IFNET_SETUP_MONITORS, + IFNET_CANCEL_MONITORS, + IFNET_LAST_SIGNAL +}; + +static guint signals[IFNET_LAST_SIGNAL] = { 0 }; + +typedef struct { + gchar *conn_name; + NMSettingsPlugin *config; +} NMIfnetConnectionPrivate; + +struct _NMIfnetConnection { + NMSettingsConnection parent; + NMIfnetConnectionPrivate _priv; +}; + +struct _NMIfnetConnectionClass { + NMSettingsConnectionClass parent; +}; + +G_DEFINE_TYPE (NMIfnetConnection, nm_ifnet_connection, NM_TYPE_SETTINGS_CONNECTION) + +#define NM_IFNET_CONNECTION_GET_PRIVATE(self) _NM_GET_PRIVATE (self, NMIfnetConnection, NM_IS_IFNET_CONNECTION) + +/*****************************************************************************/ + +const char * +nm_ifnet_connection_get_conn_name (NMIfnetConnection *connection) +{ + return NM_IFNET_CONNECTION_GET_PRIVATE (connection)->conn_name; +} + +static gboolean +commit_changes (NMSettingsConnection *connection, + NMConnection *new_connection, + NMSettingsConnectionCommitReason commit_reason, + NMConnection **out_reread_connection, + char **out_logmsg_change, + GError **error) +{ + NMIfnetConnectionPrivate *priv = NM_IFNET_CONNECTION_GET_PRIVATE ((NMIfnetConnection *) connection); + char *new_name = NULL; + gboolean success = FALSE; + gboolean added = FALSE; + + nm_assert (out_reread_connection && !*out_reread_connection); + nm_assert (!out_logmsg_change || !*out_logmsg_change); + + g_signal_emit (connection, signals[IFNET_CANCEL_MONITORS], 0); + + if (priv->conn_name) { + success = ifnet_update_parsers_by_connection (new_connection, + priv->conn_name, + CONF_NET_FILE, + WPA_SUPPLICANT_CONF, + &new_name, + NULL, + error); + } else { + added = TRUE; + success = ifnet_add_new_connection (new_connection, + CONF_NET_FILE, + WPA_SUPPLICANT_CONF, + &new_name, + NULL, + error); + } + + g_assert (!!success == (new_name != NULL)); + if (success) { + g_free (priv->conn_name); + priv->conn_name = new_name; + } + + reload_parsers (); + + g_signal_emit (connection, signals[IFNET_SETUP_MONITORS], 0); + + if (success) { + NM_SET_OUT (out_logmsg_change, + g_strdup_printf ("ifcfg-rh: %s %s", + added ? "persist" : "updated", + new_name)); + } + return success; +} + +static gboolean +delete (NMSettingsConnection *connection, + GError **error) +{ + NMIfnetConnectionPrivate *priv = NM_IFNET_CONNECTION_GET_PRIVATE ((NMIfnetConnection *) connection); + + /* Only connections which exist in /etc/conf.d/net will have a conn_name */ + if (priv->conn_name) { + g_signal_emit (connection, signals[IFNET_CANCEL_MONITORS], 0); + + if (!ifnet_delete_connection_in_parsers (priv->conn_name, CONF_NET_FILE, WPA_SUPPLICANT_CONF, NULL)) { + nm_log_warn (LOGD_SETTINGS, "Failed to delete %s", priv->conn_name); + reload_parsers (); + /* let's not return an error. */ + } + + g_signal_emit (connection, signals[IFNET_SETUP_MONITORS], 0); + } + + return TRUE; +} + +/*****************************************************************************/ + +static void +nm_ifnet_connection_init (NMIfnetConnection * connection) +{ +} + +NMIfnetConnection * +nm_ifnet_connection_new (NMConnection *source, const char *conn_name) +{ + NMConnection *tmp; + GObject *object; + GError *error = NULL; + gboolean update_unsaved = TRUE; + + g_return_val_if_fail (source || conn_name, NULL); + + if (source) + tmp = g_object_ref (source); + else { + tmp = ifnet_update_connection_from_config_block (conn_name, NULL, &error); + if (!tmp) { + nm_log_warn (LOGD_SETTINGS, "Could not read connection '%s': %s", + conn_name, error->message); + g_error_free (error); + return NULL; + } + + /* If we just read the connection from disk, it's clearly not Unsaved */ + update_unsaved = FALSE; + } + + object = (GObject *) g_object_new (NM_TYPE_IFNET_CONNECTION, NULL); + + NM_IFNET_CONNECTION_GET_PRIVATE ((NMIfnetConnection *) object)->conn_name = g_strdup (conn_name); + if (!nm_settings_connection_update (NM_SETTINGS_CONNECTION (object), + tmp, + update_unsaved + ? NM_SETTINGS_CONNECTION_PERSIST_MODE_UNSAVED + : NM_SETTINGS_CONNECTION_PERSIST_MODE_KEEP_SAVED, + NM_SETTINGS_CONNECTION_COMMIT_REASON_NONE, + NULL, + NULL)) { + g_object_unref (object); + return NULL; + } + g_object_unref (tmp); + + return NM_IFNET_CONNECTION (object); +} + +static void +finalize (GObject * object) +{ + g_free (NM_IFNET_CONNECTION_GET_PRIVATE ((NMIfnetConnection *) object)->conn_name); + G_OBJECT_CLASS (nm_ifnet_connection_parent_class)->finalize (object); +} + +static void +nm_ifnet_connection_class_init (NMIfnetConnectionClass * ifnet_connection_class) +{ + GObjectClass *object_class = G_OBJECT_CLASS (ifnet_connection_class); + NMSettingsConnectionClass *settings_class = NM_SETTINGS_CONNECTION_CLASS (ifnet_connection_class); + + object_class->finalize = finalize; + + settings_class->delete = delete; + settings_class->commit_changes = commit_changes; + + signals[IFNET_SETUP_MONITORS] = + g_signal_new ("ifnet_setup_monitors", + G_OBJECT_CLASS_TYPE (object_class), G_SIGNAL_RUN_LAST, + 0, NULL, NULL, g_cclosure_marshal_VOID__VOID, + G_TYPE_NONE, 0); + signals[IFNET_CANCEL_MONITORS] = + g_signal_new ("ifnet_cancel_monitors", + G_OBJECT_CLASS_TYPE (object_class), G_SIGNAL_RUN_LAST, + 0, NULL, NULL, g_cclosure_marshal_VOID__VOID, + G_TYPE_NONE, 0); +} diff --git a/src/settings/plugins/ifnet/nms-ifnet-connection.h b/src/settings/plugins/ifnet/nms-ifnet-connection.h new file mode 100644 index 00000000..1bc06644 --- /dev/null +++ b/src/settings/plugins/ifnet/nms-ifnet-connection.h @@ -0,0 +1,46 @@ +/* -*- Mode: C; tab-width: 4; indent-tabs-mode: t; c-basic-offset: 4 -*- */ +/* + * Mu Qiao <qiaomuf@gmail.com> + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation; either version 2 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License along + * with this program; if not, write to the Free Software Foundation, Inc., + * 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA. + * + * Copyright (C) 1999-2010 Gentoo Foundation, Inc. + */ + +#ifndef __NETWORKMANAGER_IFNET_CONNECTION_H__ +#define __NETWORKMANAGER_IFNET_CONNECTION_H__ + +#include "settings/nm-settings-connection.h" + +#include "nms-ifnet-net-parser.h" + +#define NM_TYPE_IFNET_CONNECTION (nm_ifnet_connection_get_type ()) +#define NM_IFNET_CONNECTION(obj) (G_TYPE_CHECK_INSTANCE_CAST ((obj), NM_TYPE_IFNET_CONNECTION, NMIfnetConnection)) +#define NM_IFNET_CONNECTION_CLASS(klass) (G_TYPE_CHECK_CLASS_CAST ((klass), NM_TYPE_IFNET_CONNECTION, NMIfnetConnectionClass)) +#define NM_IS_IFNET_CONNECTION(obj) (G_TYPE_CHECK_INSTANCE_TYPE ((obj), NM_TYPE_IFNET_CONNECTION)) +#define NM_IS_IFNET_CONNECTION_CLASS(klass) (G_TYPE_CHECK_CLASS_TYPE ((klass), NM_TYPE_IFNET_CONNECTION)) +#define NM_IFNET_CONNECTION_GET_CLASS(obj) (G_TYPE_INSTANCE_GET_CLASS ((obj), NM_TYPE_IFNET_CONNECTION, NMIfnetConnectionClass)) + +typedef struct _NMIfnetConnection NMIfnetConnection; +typedef struct _NMIfnetConnectionClass NMIfnetConnectionClass; + +GType nm_ifnet_connection_get_type (void); + +NMIfnetConnection *nm_ifnet_connection_new (NMConnection *source, + const char *conn_name); + +const char *nm_ifnet_connection_get_conn_name (NMIfnetConnection *connection); + +#endif /* __NETWORKMANAGER_IFNET_CONNECTION_H__ */ diff --git a/src/settings/plugins/ifnet/nms-ifnet-net-parser.c b/src/settings/plugins/ifnet/nms-ifnet-net-parser.c new file mode 100644 index 00000000..d3e47219 --- /dev/null +++ b/src/settings/plugins/ifnet/nms-ifnet-net-parser.c @@ -0,0 +1,734 @@ +/* -*- Mode: C; tab-width: 4; indent-tabs-mode: t; c-basic-offset: 4 -*- */ +/* + * Mu Qiao <qiaomuf@gmail.com> + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation; either version 2 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License along + * with this program; if not, write to the Free Software Foundation, Inc., + * 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA. + * + * Copyright (C) 1999-2010 Gentoo Foundation, Inc. + */ + +#include "nm-default.h" + +#include "nms-ifnet-net-parser.h" + +#include <string.h> +#include <stdio.h> +#include <sys/ioctl.h> +#include <unistd.h> + +#include "settings/nm-settings-plugin.h" +#include "platform/nm-platform.h" + +#include "nms-ifnet-plugin.h" +#include "nms-ifnet-net-utils.h" + +/* Save all the connection information */ +static GHashTable *conn_table; + +/* Save global settings which are used for writing*/ +static GHashTable *global_settings_table; + +/* Save functions */ +static GList *functions_list; + +/* Used to decide whether to write changes to file*/ +static gboolean net_parser_data_changed = FALSE; + +static GHashTable * +add_new_connection_config (const gchar * type, const gchar * name) +{ + GHashTable *new_conn; + gchar *new_name; + + if (!name) + return NULL; + + /* Return existing connection */ + if ((new_conn = g_hash_table_lookup (conn_table, name)) != NULL) + return new_conn; + new_conn = g_hash_table_new (nm_str_hash, g_str_equal); + new_name = g_strdup (name); + g_hash_table_insert (new_conn, g_strdup ("name"), new_name); + g_hash_table_insert (new_conn, g_strdup ("type"), g_strdup (type)); + g_hash_table_insert (conn_table, new_name, new_conn); + return new_conn; +} + +gboolean +ifnet_add_network (const char *name, const char *type) +{ + if (ifnet_has_network (name)) + return TRUE; + if (add_new_connection_config (type, name)) { + nm_log_info (LOGD_SETTINGS, "Adding network for %s", name); + net_parser_data_changed = TRUE; + return TRUE; + } + return FALSE; +} + +gboolean +ifnet_has_network (const char *conn_name) +{ + return g_hash_table_lookup (conn_table, conn_name) != NULL; +} + +static GHashTable * +get_connection_config (const char *name) +{ + return g_hash_table_lookup (conn_table, name); +} + +/* Ignored name won't be treated as wireless ssid */ +static gchar *ignore_name[] = { + "vlan", "bond", "atm", "ath", "ippp", "vpn", "tap", "tun", "1", + "br", "nas", "6to4", "timeout", "kvm", "force", NULL +}; + +static gboolean +ignore_connection_name (const char *name) +{ + gboolean result = FALSE; + guint i = 0; + + /* check ignore_name list */ + while (ignore_name[i] != NULL) { + if (g_ascii_strncasecmp + (name, ignore_name[i], strlen (ignore_name[i])) == 0) { + return TRUE; + } + i++; + } + /* Ignore mac address based configuration */ + if (strlen (name) == 12 && is_hex (name)) + result = TRUE; + return result; +} + +static gboolean +is_global_setting (char *key) +{ + static gchar *global_settings[] = { "wpa_supplicant_", NULL }; + int i; + + for (i = 0; global_settings[i] != NULL; i++) { + if (strstr (key, global_settings[i])) + return 1; + } + return 0; +} + +/* Parse a complete line */ +/* Connection type is determined here */ +static void +init_block_by_line (gchar * buf) +{ + gchar **key_value; + gchar *pos; + gchar *data; + gchar *tmp; + GHashTable *conn; + + key_value = g_strsplit (buf, "=", 2); + if (g_strv_length (key_value) != 2) { + nm_log_warn (LOGD_SETTINGS, "Can't handle this line: %s\n", buf); + g_strfreev (key_value); + return; + } + pos = g_strrstr (key_value[0], "_"); + if (pos == NULL || is_global_setting (key_value[0])) { + /* global data */ + data = g_strdup (key_value[1]); + tmp = strip_string (data, '"'); + strip_string (tmp, '\''); + nm_log_info (LOGD_SETTINGS, "global:%s-%s\n", key_value[0], tmp); + g_hash_table_insert (global_settings_table, g_strdup (key_value[0]), g_strdup (tmp)); + g_strfreev (key_value); + g_free (data); + return; + } + *pos++ = '\0'; + if ((conn = get_connection_config (pos)) == NULL) { + if (g_ascii_strncasecmp (pos, "eth", 3) == 0 + && strlen (pos) == 4) + /* wired connection */ + conn = add_new_connection_config ("wired", pos); + else if (g_ascii_strncasecmp (pos, "ppp", 3) == 0 + && strlen (pos) == 4) + /* pppoe connection */ + conn = add_new_connection_config ("ppp", pos); + else if (ignore_connection_name (pos)) { + /* ignored connection */ + conn = add_new_connection_config ("ignore", pos); + } else { + int ifindex = nm_platform_link_get_ifindex (NM_PLATFORM_GET, pos); + + if (ifindex && nm_platform_link_get_type (NM_PLATFORM_GET, ifindex) != NM_LINK_TYPE_WIFI) + /* wired connection */ + conn = add_new_connection_config ("wired", pos); + else + /* wireless connection */ + conn = add_new_connection_config ("wireless", pos); + } + } + data = g_strdup (key_value[1]); + tmp = strip_string (data, '"'); + strip_string (tmp, '\''); + if (conn) + g_hash_table_insert (conn, strip_string (g_strdup (key_value[0]), ' '), + g_strdup (tmp)); + g_free (data); + g_strfreev (key_value); +} + +static void +destroy_connection_config (GHashTable * conn) +{ + gpointer key, value; + GHashTableIter iter; + + g_hash_table_iter_init (&iter, conn); + while (g_hash_table_iter_next (&iter, &key, &value)) { + g_free (key); + g_free (value); + } + + g_hash_table_destroy (conn); +} + +static void +strip_function (GIOChannel * channel, gchar * line) +{ + + int counter = 0; + gchar *p, *tmp; + gboolean begin = FALSE; + GString *function_str = g_string_new (line); + + g_string_append (function_str, "\n"); + while (1) { + p = line; + while (*p != '\0') { + if (*p == '{') { + counter++; + begin = TRUE; + } else if (*p == '}') + counter--; + p++; + } + if (begin && counter == 0) { + g_free (line); + goto done; + } + while (1) { + g_free (line); + if (g_io_channel_read_line + (channel, &line, NULL, NULL, + NULL) == G_IO_STATUS_EOF) + goto done; + g_string_append (function_str, line); + tmp = g_strdup (line); + g_strstrip (tmp); + if (tmp[0] != '#' && tmp[0] != '\0') { + g_free (tmp); + break; + } else + g_free (tmp); + } + } +done: + functions_list = + g_list_append (functions_list, g_strdup (function_str->str)); + g_string_free (function_str, TRUE); +} + +static gboolean +is_function (gchar * line) +{ + static gchar *func_names[] = + { "preup", "predown", "postup", "postdown", "failup", "faildown", + NULL, + }; + int i; + + for (i = 0; func_names[i]; i++) { + if (g_str_has_prefix (line, func_names[i])) { + nm_log_info (LOGD_SETTINGS, "Ignoring function: %s", func_names[i]); + return TRUE; + } + } + return FALSE; +} + +static void +append_line (GString *buf, gchar* line) +{ + gchar *pos = NULL; + + if ((pos = strchr (line, '#')) != NULL) + *pos = '\0'; + g_strstrip (line); + + if (line[0] != '\0') + g_string_append_printf (buf, " %s", line); + g_free (line); +} + +gboolean +ifnet_init (gchar * config_file) +{ + GIOChannel *channel = NULL; + gchar *line; + + /* Handle multiple lines with brackets */ + gboolean complete = TRUE; + + gboolean openrc_style = TRUE; + + /* line buffer */ + GString *buf; + + net_parser_data_changed = FALSE; + + conn_table = g_hash_table_new (nm_str_hash, g_str_equal); + global_settings_table = g_hash_table_new (nm_str_hash, g_str_equal); + functions_list = NULL; + + if (g_file_test (config_file, G_FILE_TEST_IS_REGULAR)) + channel = g_io_channel_new_file (config_file, "r", NULL); + if (channel == NULL) { + nm_log_warn (LOGD_SETTINGS, "Can't open %s", config_file); + return FALSE; + } + + buf = g_string_new (NULL); + while (g_io_channel_read_line + (channel, &line, NULL, NULL, NULL) != G_IO_STATUS_EOF) { + g_strstrip (line); + /* convert multiple lines to a complete line and + * pass it to init_block_by_line() */ + if (is_function (line)) { + strip_function (channel, line); + continue; + } + + // New openrc style, bash arrays are not allowed. We only care about '"' + if (openrc_style && line[0] != '#' && line[0] != '\0' + && !strchr (line, '(') && !strchr (line, ')')) { + gchar *tmp = line; + + while ((tmp = strchr (tmp, '"')) != NULL) { + complete = !complete; + ++tmp; + } + + append_line (buf, line); + // Add "(separator) for routes. It will be easier for later parsing + if (strstr (buf->str, "via")) + g_string_append_printf (buf, "\""); + + if (!complete) + continue; + + strip_string (buf->str, '"'); + + init_block_by_line (buf->str); + g_string_free (buf, TRUE); + buf = g_string_new (NULL); + } + // Old bash arrays for baselayout-1, to be deleted + else if (line[0] != '#' && line[0] != '\0') { + if (!complete) { + complete = + g_strrstr (line, + ")") == NULL ? FALSE : TRUE; + + append_line (buf, line); + if (!complete) { + openrc_style = FALSE; + continue; + } + else { + openrc_style = TRUE; + } + } else { + complete = + (g_strrstr (line, "(") != NULL + && g_strrstr (line, ")") != NULL) + || g_strrstr (line, "(") == NULL; + + append_line (buf, line); + if (!complete) + { + openrc_style = FALSE; + continue; + } else { + openrc_style = TRUE; + } + } + init_block_by_line (buf->str); + g_string_free (buf, TRUE); + buf = g_string_new (NULL); + } else + /* Blank line or comment line */ + g_free (line); + } + + g_string_free (buf, TRUE); + g_io_channel_shutdown (channel, FALSE, NULL); + g_io_channel_unref (channel); + return TRUE; +} + +const char * +ifnet_get_data (const char *conn_name, const char *key) +{ + GHashTable *conn; + + g_return_val_if_fail (conn_name && key, NULL); + + conn = g_hash_table_lookup (conn_table, conn_name); + + if (conn) + return g_hash_table_lookup (conn, key); + return NULL; +} + +/* format ip values for comparison */ +static gchar* +format_ip_for_comparison (const gchar * value) +{ + gchar **ipset; + guint length, i; + GString *formated_string = g_string_new (NULL); + gchar *formatted = NULL; + + ipset = g_strsplit (value, "\"", 0); + length = g_strv_length (ipset); + + for (i = 0; i < length; i++) + { + strip_string (ipset[i], ' '); + if (ipset[i][0] != '\0') + g_string_append_printf (formated_string, + "%s ", ipset[i]); + } + formatted = g_strdup (formated_string->str); + formatted[formated_string->len - 1] = '\0'; + + g_string_free (formated_string, TRUE); + g_strfreev (ipset); + + return formatted; +} + +void +ifnet_set_data (const char *conn_name, const char *key, const char *value) +{ + gpointer old_key = NULL, old_value = NULL; + GHashTable *conn = g_hash_table_lookup (conn_table, conn_name); + gchar * stripped = NULL; + + if (!conn) { + nm_log_warn (LOGD_SETTINGS, "%s does not exist!", conn_name); + return; + } + if (value){ + stripped = g_strdup (value); + strip_string (stripped, '"'); + } + /* Remove existing key value pair */ + if (g_hash_table_lookup_extended (conn, key, &old_key, &old_value)) { + + /* This ugly hack is due to baselayout compatibility. We have to + * deal with different ip format. So sometimes we have the same ips + * but different strings. + */ + if (stripped && + (!strcmp (key, "config") + || !strcmp (key, "routes") + || !strcmp (key, "pppd") + || !strcmp (key, "chat"))) + { + gchar *old_ips = format_ip_for_comparison (old_value); + gchar *new_ips = format_ip_for_comparison (value); + if(!strcmp (old_ips, new_ips)) + { + g_free (stripped); + g_free (old_ips); + g_free (new_ips); + return; + } + g_free (old_ips); + g_free (new_ips); + } + + if (stripped && !strcmp (old_value, stripped)) { + g_free (stripped); + return; + } + g_hash_table_remove (conn, old_key); + g_free (old_key); + g_free (old_value); + } else if (!value) + return; + if (stripped) + g_hash_table_insert (conn, g_strdup (key), stripped); + net_parser_data_changed = TRUE; +} + +// Remember to free return value +const char * +ifnet_get_global_data (const gchar * key) +{ + return g_hash_table_lookup (global_settings_table, key); +} + +// Return names of legal connections +GList * +ifnet_get_connection_names (void) +{ + GList *names = g_hash_table_get_keys (conn_table); + GList *iter, *result = NULL; + + for (iter = names; iter; iter = iter->next) { + if (!ignore_connection_name (iter->data)) + result = g_list_prepend (result, iter->data); + } + + g_list_free (names); + return g_list_reverse (result); +} + +/* format IP and route for writing */ +static void +format_ips (gchar * value, gchar ** out_line, gchar * key, gchar * name) +{ + gchar **ipset; + guint length, i; + GString *formated_string = g_string_new (NULL); + + strip_string (value, '('); + strip_string (value, ')'); + strip_string (value, '"'); + ipset = g_strsplit (value, "\"", 0); + length = g_strv_length (ipset); + + //only one line + if (length < 2) { + *out_line = + g_strdup_printf ("%s_%s=\"%s\"\n", key, name, value); + goto done; + } + // Multiple lines + g_string_append_printf (formated_string, "%s_%s=\"\n", key, name); + for (i = 0; i < length; i++) + { + strip_string (ipset[i], ' '); + if (ipset[i][0] != '\0') + g_string_append_printf (formated_string, + "%s\n", ipset[i]); + } + g_string_append (formated_string, "\"\n"); + *out_line = g_strdup (formated_string->str); +done: + g_string_free (formated_string, TRUE); + g_strfreev (ipset); +} + +gboolean +ifnet_flush_to_file (const char *config_file, gchar **out_backup) +{ + GIOChannel *channel; + GError *error = NULL; + gpointer key, value, name, network; + GHashTableIter iter, iter_network; + GList *list_iter; + gchar *out_line = NULL; + gsize bytes_written; + gboolean result = FALSE; + gchar *backup; + + if (!net_parser_data_changed) + return TRUE; + if (!conn_table || !global_settings_table) + return FALSE; + + backup = backup_file (config_file); + + channel = g_io_channel_new_file (config_file, "w", NULL); + if (!channel) { + nm_log_warn (LOGD_SETTINGS, "Can't open file %s for writing", config_file); + g_free (backup); + return FALSE; + } + g_hash_table_iter_init (&iter, global_settings_table); + nm_log_info (LOGD_SETTINGS, "Writing to %s", config_file); + g_io_channel_write_chars (channel, + "#Generated by NetworkManager\n" + "###### Global Configuration ######\n", + -1, &bytes_written, &error); + if (error) + goto done; + + /* Writing global data */ + while (g_hash_table_iter_next (&iter, &key, &value)) { + out_line = + g_strdup_printf ("%s=\"%s\"\n", (gchar *) key, (gchar *) value); + g_io_channel_write_chars (channel, out_line, -1, + &bytes_written, &error); + if (bytes_written == 0 || error) + goto done; + g_free (out_line); + } + + /* Writing connection data */ + g_io_channel_write_chars (channel, + "\n###### Connection Configuration ######\n", + -1, &bytes_written, &error); + if (error) + goto done; + + g_hash_table_iter_init (&iter, conn_table); + while (g_hash_table_iter_next (&iter, &name, &network)) { + g_hash_table_iter_init (&iter_network, (GHashTable *) network); + g_io_channel_write_chars (channel, + "#----------------------------------\n", + -1, &bytes_written, &error); + if (error) + goto done; + + while (g_hash_table_iter_next (&iter_network, &key, &value)) { + if (!g_str_has_prefix ((gchar *) key, "name") + && !g_str_has_prefix ((gchar *) key, "type")) { + /* These keys contain brackets */ + if (strcmp + ((gchar *) key, + "config") == 0 + || strcmp ((gchar *) key, + "routes") == 0 + || strcmp ((gchar *) key, + "pppd") == 0 + || strcmp ((gchar *) key, "chat") == 0) + format_ips (value, &out_line, (gchar *) + key, (gchar *) + name); + else + out_line = + g_strdup_printf + ("%s_%s=\"%s\"\n", + (gchar *) key, + (gchar *) name, (gchar *) value); + g_io_channel_write_chars (channel, out_line, -1, &bytes_written, &error); + if (bytes_written == 0 || error) + goto done; + g_free (out_line); + } + } + } + + /* Writing reserved functions */ + if (functions_list) { + g_io_channel_write_chars (channel, + "\n###### Reserved Functions ######\n", + -1, &bytes_written, &error); + if (error) + goto done; + + /* Writing functions */ + for (list_iter = functions_list; list_iter; + list_iter = g_list_next (list_iter)) { + out_line = + g_strdup_printf ("%s\n", (gchar *) list_iter->data); + g_io_channel_write_chars (channel, out_line, -1, + &bytes_written, &error); + if (bytes_written == 0 || error) + goto done; + g_free (out_line); + } + } + + g_io_channel_flush (channel, &error); + if (error) + goto done; + result = TRUE; + net_parser_data_changed = FALSE; + +done: + if (error) { + nm_log_warn (LOGD_SETTINGS, "Error writing the configuration file: %s", error->message); + g_error_free (error); + } + + if (result && out_backup) + *out_backup = backup; + else + g_free (backup); + + g_io_channel_shutdown (channel, FALSE, NULL); + g_io_channel_unref (channel); + return result; +} + +gboolean +ifnet_delete_network (const char *conn_name) +{ + GHashTable *network = NULL; + + g_return_val_if_fail (conn_table != NULL && conn_name != NULL, FALSE); + nm_log_info (LOGD_SETTINGS, "Deleting network for %s", conn_name); + network = g_hash_table_lookup (conn_table, conn_name); + if (!network) + return FALSE; + g_hash_table_remove (conn_table, conn_name); + destroy_connection_config (network); + net_parser_data_changed = TRUE; + return TRUE; +} + +void +ifnet_destroy (void) +{ + GHashTableIter iter; + gpointer key; + gpointer value; + GList *list_iter; + + /* Destroy connection setting */ + if (conn_table) { + g_hash_table_iter_init (&iter, conn_table); + while (g_hash_table_iter_next (&iter, &key, &value)) { + destroy_connection_config ((GHashTable *) + value); + } + g_hash_table_destroy (conn_table); + conn_table = NULL; + } + + /* Destroy global data */ + if (global_settings_table) { + g_hash_table_iter_init (&iter, global_settings_table); + while (g_hash_table_iter_next (&iter, &key, &value)) { + g_free (key); + g_free (value); + } + g_hash_table_destroy (global_settings_table); + global_settings_table = NULL; + } + for (list_iter = functions_list; list_iter; + list_iter = g_list_next (list_iter)) + g_free (list_iter->data); + g_list_free (functions_list); +} diff --git a/src/settings/plugins/ifnet/nms-ifnet-net-parser.h b/src/settings/plugins/ifnet/nms-ifnet-net-parser.h new file mode 100644 index 00000000..31fc9ead --- /dev/null +++ b/src/settings/plugins/ifnet/nms-ifnet-net-parser.h @@ -0,0 +1,42 @@ +/* -*- Mode: C; tab-width: 4; indent-tabs-mode: t; c-basic-offset: 4 -*- */ +/* + * Mu Qiao <qiaomuf@gmail.com> + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation; either version 2 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License along + * with this program; if not, write to the Free Software Foundation, Inc., + * 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA. + * + * Copyright (C) 1999-2010 Gentoo Foundation, Inc. + */ + +#ifndef _NET_PARSER_H +#define _NET_PARSER_H + +#define CONF_NET_FILE SYSCONFDIR "/conf.d/net" + +gboolean ifnet_init (gchar * config_file); +void ifnet_destroy (void); + +/* Reader functions */ +GList *ifnet_get_connection_names (void); +const char *ifnet_get_data (const char *conn_name, const char *key); +const char *ifnet_get_global_data (const char *key); +gboolean ifnet_has_network (const char *conn_name); + +/* Writer functions */ +gboolean ifnet_flush_to_file (const char *config_file, gchar **out_backup); +void ifnet_set_data (const char *conn_name, const char *key, const char *value); +gboolean ifnet_add_network (const char *name, const char *type); +gboolean ifnet_delete_network (const char *conn_name); + +#endif diff --git a/src/settings/plugins/ifnet/nms-ifnet-net-utils.c b/src/settings/plugins/ifnet/nms-ifnet-net-utils.c new file mode 100644 index 00000000..6531a238 --- /dev/null +++ b/src/settings/plugins/ifnet/nms-ifnet-net-utils.c @@ -0,0 +1,830 @@ +/* -*- Mode: C; tab-width: 4; indent-tabs-mode: t; c-basic-offset: 4 -*- */ +/* + * Mu Qiao <qiaomuf@gmail.com> + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation; either version 2 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License along + * with this program; if not, write to the Free Software Foundation, Inc., + * 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA. + * + * Copyright (C) 1999-2010 Gentoo Foundation, Inc. + */ + +#include "nm-default.h" + +#include "nms-ifnet-net-utils.h" + +#include <stdlib.h> +#include <stdio.h> +#include <string.h> +#include <errno.h> + +#include "nm-utils.h" +#include "NetworkManagerUtils.h" +#include "settings/nm-settings-plugin.h" +#include "nm-config.h" +#include "dhcp/nm-dhcp-manager.h" + +#include "nms-ifnet-wpa-parser.h" +#include "nms-ifnet-net-parser.h" + +/* emit heading and tailing blank space, tab, character t */ +gchar * +strip_string (gchar * str, gchar t) +{ + gchar *ret = str; + gint length = 0; + guint i = 0; + + while (ret[i] != '\0' + && (ret[i] == '\t' || ret[i] == ' ' || ret[i] == t)) { + length++; + i++; + } + i = 0; + while (ret[i + length] != '\0') { + ret[i] = ret[i + length]; + i++; + } + ret[i] = '\0'; + length = strlen (ret); + while ((length - 1) >= 0 + && (ret[length - 1] == ' ' || ret[length - 1] == '\n' + || ret[length - 1] == '\t' || ret[length - 1] == t)) + length--; + ret[length] = '\0'; + return ret; +} + +gboolean +is_hex (const char *value) +{ + const char *p = value; + + if (!p) + return FALSE; + while (*p) { + if (!g_ascii_isxdigit (*p++)) + return FALSE; + } + return TRUE; +} + +gboolean +is_ascii (const char *value) +{ + const char *p = value; + + while (*p) { + if (!g_ascii_isprint (*p++)) + return FALSE; + } + return TRUE; + +} + +gboolean +is_true (const char *str) +{ + if (!g_ascii_strcasecmp (str, "yes") + || !g_ascii_strcasecmp (str, "true")) + return TRUE; + return FALSE; +} + +static char * +find_default_gateway_str (char *str) +{ + char *tmp; + + if ((tmp = strstr (str, "default via ")) != NULL) { + return tmp + strlen ("default via "); + } else if ((tmp = strstr (str, "default gw ")) != NULL) { + return tmp + strlen ("default gw "); + } + return NULL; +} + +static char * +find_gateway_str (char *str) +{ + char *tmp; + + if ((tmp = strstr (str, "via ")) != NULL) { + return tmp + strlen ("via "); + } else if ((tmp = strstr (str, "gw ")) != NULL) { + return tmp + strlen ("gw "); + } + return NULL; +} + +gboolean +reload_parsers (void) +{ + ifnet_destroy (); + wpa_parser_destroy (); + if (!ifnet_init (CONF_NET_FILE)) + return FALSE; + wpa_parser_init (WPA_SUPPLICANT_CONF); + return TRUE; +} + +gboolean +is_static_ip4 (const char *conn_name) +{ + const char *data = ifnet_get_data (conn_name, "config"); + const char *dhcp6; + + if (!data) + return FALSE; + if (!strcmp (data, "shared")) + return FALSE; + if (!strcmp (data, "autoip")) + return FALSE; + dhcp6 = strstr (data, "dhcp6"); + if (dhcp6) { + gchar *dhcp4; + + if (strstr (data, "dhcp ")) + return FALSE; + dhcp4 = strstr (data, "dhcp"); + if (!dhcp4) + return TRUE; + if (dhcp4[4] == '\0') + return FALSE; + return TRUE; + } + return strstr (data, "dhcp") == NULL ? TRUE : FALSE; +} + +gboolean +is_static_ip6 (const char *conn_name) +{ + const char *data = ifnet_get_data (conn_name, "config"); + + if (!data) + return TRUE; + return strstr (data, "dhcp6") == NULL ? TRUE : FALSE; +} + +gboolean +is_ip4_address (const char *in_address) +{ + const char *pattern = + "\\d{1,3}\\.\\d{1,3}\\.\\d{1,3}\\.((\\{\\d{1,3}\\.\\.\\d{1,3}\\})|\\d{1,3})$"; + gchar *address = g_strdup (in_address); + gboolean result = FALSE; + gchar *tmp; + GRegex *regex = g_regex_new (pattern, 0, 0, NULL); + GMatchInfo *match_info = NULL; + + if (!address) + goto done; + g_strstrip (address); + if ((tmp = strstr (address, "/")) != NULL) + *tmp = '\0'; + if ((tmp = strstr (address, " ")) != NULL) + *tmp = '\0'; + g_regex_match (regex, address, 0, &match_info); + result = g_match_info_matches (match_info); +done: + if (match_info) + g_match_info_free (match_info); + g_regex_unref (regex); + g_free (address); + return result; +} + +gboolean +is_ip6_address (const char *in_address) +{ + struct in6_addr tmp_ip6_addr; + gchar *tmp, *address; + gboolean result = FALSE; + + if (!in_address) + return FALSE; + address = g_strdup (in_address); + g_strstrip (address); + if ((tmp = strchr (address, '/')) != NULL) + *tmp = '\0'; + if (inet_pton (AF_INET6, address, &tmp_ip6_addr)) + result = TRUE; + g_free (address); + return result; + +} + +// 'c' is only used for openrc style +static gchar ** +split_addresses_by_char (const gchar *addresses, const gchar *c) +{ + gchar **ipset; + + if (addresses == NULL) + return NULL; + + if (strchr (addresses, '(') != NULL) { // old baselayout style + gchar *tmp = g_strdup (addresses); + strip_string (tmp, '('); + strip_string (tmp, ')'); + strip_string (tmp, '"'); + strip_string (tmp, '\''); + ipset = g_strsplit (tmp, "\" \"", 0); + g_free(tmp); + } else { // openrc style + if (strstr (addresses, "netmask")) + // There is only one ip address if "netmask" is specified. + // '\n' is not used in config so there will be only one split. + ipset = g_strsplit (addresses, "\n", 0); + else + ipset = g_strsplit (addresses, c, 0); + } + + return ipset; +} + +static gchar ** +split_addresses (const gchar* addresses) +{ + // " " is only used by openrc style + return split_addresses_by_char (addresses, " "); +} + +static gchar ** +split_routes (const gchar* routes) +{ + // "\"" is only used by openrc style + return split_addresses_by_char (routes, "\""); +} + +gboolean +has_ip6_address (const char *conn_name) +{ + gchar **ipset; + guint length; + guint i; + + g_return_val_if_fail (conn_name != NULL, FALSE); + ipset = split_addresses (ifnet_get_data (conn_name, "config")); + length = ipset ? g_strv_length (ipset) : 0; + for (i = 0; i < length; i++) { + if (!is_ip6_address (ipset[i])) + continue; + else { + g_strfreev (ipset); + return TRUE; + } + + } + g_strfreev (ipset); + return FALSE; +} + +gboolean +has_default_route (const char *conn_name, gboolean (*check_fn) (const char *)) +{ + char *routes = NULL, *end, *tmp; + gboolean success = FALSE; + + g_return_val_if_fail (conn_name != NULL, FALSE); + + routes = g_strdup (ifnet_get_data (conn_name, "routes")); + if (!routes) + return FALSE; + tmp = find_default_gateway_str (routes); + if (tmp) { + g_strstrip (tmp); + if ((end = strstr (tmp, "\"")) != NULL) + *end = '\0'; + if (check_fn (tmp)) + success = TRUE; + } + + g_free (routes); + return success; +} + +static ip_block * +create_ip4_block (gchar * ip) +{ + ip_block *iblock = g_slice_new0 (ip_block); + guint32 tmp_ip4_addr; + int i; + guint length; + gchar **ip_mask; + + /* prefix format */ + if (strstr (ip, "/")) { + gchar *prefix; + + ip_mask = g_strsplit (ip, "/", 0); + length = g_strv_length (ip_mask); + if (!nm_utils_ipaddr_valid (AF_INET, ip_mask[0])) + goto error; + iblock->ip = g_strdup (ip_mask[0]); + prefix = ip_mask[1]; + i = 0; + while (i < length && g_ascii_isdigit (prefix[i])) + i++; + prefix[i] = '\0'; + iblock->prefix = (guint32) atoi (ip_mask[1]); + } else if (strstr (ip, "netmask")) { + ip_mask = g_strsplit (ip, " ", 0); + length = g_strv_length (ip_mask); + if (!nm_utils_ipaddr_valid (AF_INET, ip_mask[0])) + goto error; + iblock->ip = g_strdup (ip_mask[0]); + i = 0; + while (i < length && !strstr (ip_mask[++i], "netmask")) ; + while (i < length && ip_mask[++i][0] == '\0') ; + if (i >= length) + goto error; + if (!inet_pton (AF_INET, ip_mask[i], &tmp_ip4_addr)) + goto error; + iblock->prefix = nm_utils_ip4_netmask_to_prefix (tmp_ip4_addr); + } else { + g_slice_free (ip_block, iblock); + if (!is_ip6_address (ip) && !strstr (ip, "dhcp")) + nm_log_warn (LOGD_SETTINGS, "Can't handle ipv4 address: %s, missing netmask or prefix", ip); + return NULL; + } + if (iblock->prefix == 0 || iblock->prefix > 32) { + nm_log_warn (LOGD_SETTINGS, "Can't handle ipv4 address: %s, invalid prefix", ip); + goto error; + } + g_strfreev (ip_mask); + return iblock; +error: + if (!is_ip6_address (ip)) + nm_log_warn (LOGD_SETTINGS, "Can't handle IPv4 address: %s", ip); + g_strfreev (ip_mask); + g_free (iblock->ip); + g_slice_free (ip_block, iblock); + return NULL; +} + +static ip_block * +create_ip_block (gchar * ip) +{ + ip_block *iblock = g_slice_new0 (ip_block); + gchar *dup_ip = g_strdup (ip); + gchar *prefix = NULL; + + if ((prefix = strstr (dup_ip, "/")) != NULL) { + *prefix = '\0'; + prefix++; + } + if (!nm_utils_ipaddr_valid (AF_INET6, dup_ip)) + goto error; + iblock->ip = dup_ip; + if (prefix) { + errno = 0; + iblock->prefix = strtol (prefix, NULL, 10); + if (errno || iblock->prefix <= 0 || iblock->prefix > 128) { + goto error; + } + } else + iblock->prefix = 64; + return iblock; +error: + if (!is_ip4_address (ip)) + nm_log_warn (LOGD_SETTINGS, "Can't handle IPv6 address: %s", ip); + g_slice_free (ip_block, iblock); + g_free (dup_ip); + return NULL; +} + +static char * +get_ip4_gateway (gchar * gateway) +{ + gchar *tmp, *split; + + if (!gateway) + return NULL; + tmp = find_gateway_str (gateway); + if (!tmp) { + nm_log_warn (LOGD_SETTINGS, "Couldn't obtain gateway in \"%s\"", gateway); + return NULL; + } + tmp = g_strdup (tmp); + strip_string (tmp, ' '); + strip_string (tmp, '"'); + + // Only one gateway is selected + if ((split = strstr (tmp, "\"")) != NULL) + *split = '\0'; + + if (!nm_utils_ipaddr_valid (AF_INET, tmp)) + goto error; + return tmp; +error: + if (!is_ip6_address (tmp)) + nm_log_warn (LOGD_SETTINGS, "Can't handle IPv4 gateway: %s", tmp); + g_free (tmp); + return NULL; +} + +static char * +get_ip6_next_hop (gchar * next_hop) +{ + gchar *tmp; + + if (!next_hop) + return NULL; + tmp = find_gateway_str (next_hop); + if (!tmp) { + nm_log_warn (LOGD_SETTINGS, "Couldn't obtain next_hop in \"%s\"", next_hop); + return NULL; + } + tmp = g_strdup (tmp); + strip_string (tmp, ' '); + strip_string (tmp, '"'); + g_strstrip (tmp); + if (!nm_utils_ipaddr_valid (AF_INET6, tmp)) + goto error; + return tmp; +error: + if (!is_ip4_address (tmp)) + nm_log_warn (LOGD_SETTINGS, "Can't handle IPv6 next_hop: %s", tmp); + g_free (tmp); + + return NULL; +} + +ip_block * +convert_ip4_config_block (const char *conn_name) +{ + gchar **ipset; + guint length; + guint i; + gchar *ip; + char *def_gateway = NULL; + const char *routes; + ip_block *start = NULL, *current = NULL, *iblock = NULL; + + g_return_val_if_fail (conn_name != NULL, NULL); + + ipset = split_addresses (ifnet_get_data (conn_name, "config")); + length = ipset ? g_strv_length (ipset) : 0; + + routes = ifnet_get_data (conn_name, "routes"); + if (routes) + def_gateway = get_ip4_gateway (strstr (routes, "default")); + + for (i = 0; i < length; i++) { + ip = ipset[i]; + ip = strip_string (ip, '"'); + iblock = create_ip4_block (ip); + if (iblock == NULL) + continue; + if (!iblock->next_hop && def_gateway != NULL) + iblock->next_hop = g_strdup (def_gateway); + if (start == NULL) + start = current = iblock; + else { + current->next = iblock; + current = iblock; + } + } + g_strfreev (ipset); + g_free (def_gateway); + return start; +} + +ip_block * +convert_ip6_config_block (const char *conn_name) +{ + gchar **ipset; + guint length; + guint i; + gchar *ip; + ip_block *start = NULL, *current = NULL, *iblock = NULL; + + g_return_val_if_fail (conn_name != NULL, NULL); + ipset = split_addresses (ifnet_get_data (conn_name, "config")); + length = ipset ? g_strv_length (ipset) : 0; + for (i = 0; i < length; i++) { + ip = ipset[i]; + ip = strip_string (ip, '"'); + iblock = create_ip_block (ip); + if (iblock == NULL) + continue; + if (start == NULL) + start = current = iblock; + else { + current->next = iblock; + current = iblock; + } + } + g_strfreev (ipset); + return start; +} + +ip_block * +convert_ip4_routes_block (const char *conn_name) +{ + gchar **ipset; + guint length; + guint i; + gchar *ip; + ip_block *start = NULL, *current = NULL, *iblock = NULL; + + g_return_val_if_fail (conn_name != NULL, NULL); + + ipset = split_routes (ifnet_get_data (conn_name, "routes")); + length = ipset ? g_strv_length (ipset) : 0; + for (i = 0; i < length; i++) { + ip = ipset[i]; + if (find_default_gateway_str (ip) || strstr (ip, "::") + || !find_gateway_str (ip)) + continue; + ip = strip_string (ip, '"'); + iblock = create_ip4_block (ip); + if (iblock == NULL) + continue; + iblock->next_hop = get_ip4_gateway (ip); + if (start == NULL) + start = current = iblock; + else { + current->next = iblock; + current = iblock; + } + } + g_strfreev (ipset); + return start; +} + +ip_block * +convert_ip6_routes_block (const char *conn_name) +{ + gchar **ipset; + guint length; + guint i; + gchar *ip, *tmp_addr; + ip_block *start = NULL, *current = NULL, *iblock = NULL; + + g_return_val_if_fail (conn_name != NULL, NULL); + ipset = split_routes (ifnet_get_data (conn_name, "routes")); + length = ipset ? g_strv_length (ipset) : 0; + for (i = 0; i < length; i++) { + ip = ipset[i]; + ip = strip_string (ip, '"'); + if (ip[0] == '\0') + continue; + if ((tmp_addr = find_default_gateway_str (ip)) != NULL) { + if (!is_ip6_address (tmp_addr)) + continue; + else { + iblock = g_slice_new0 (ip_block); + iblock->ip = g_strdup ("::"); + iblock->prefix = 128; + } + } else + iblock = create_ip_block (ip); + if (iblock == NULL) + continue; + iblock->next_hop = get_ip6_next_hop (ip); + if (iblock->next_hop == NULL) { + destroy_ip_block (iblock); + continue; + } + if (start == NULL) + start = current = iblock; + else { + current->next = iblock; + current = iblock; + } + } + g_strfreev (ipset); + return start; +} + +void +destroy_ip_block (ip_block * iblock) +{ + g_free (iblock->ip); + g_free (iblock->next_hop); + g_slice_free (ip_block, iblock); +} + +void +set_ip4_dns_servers (NMSettingIPConfig *s_ip4, const char *conn_name) +{ + const char *dns_servers; + gchar **server_list, *stripped; + guint length, i; + guint32 tmp_ip4_addr; + + dns_servers = ifnet_get_data (conn_name, "dns_servers"); + if (!dns_servers) + return; + stripped = g_strdup (dns_servers); + strip_string (stripped, '"'); + server_list = g_strsplit (stripped, " ", 0); + g_free (stripped); + + length = g_strv_length (server_list); + if (length) + g_object_set (s_ip4, NM_SETTING_IP_CONFIG_IGNORE_AUTO_DNS, + TRUE, NULL); + for (i = 0; i < length; i++) { + g_strstrip (server_list[i]); + if (server_list[i][0] == '\0') + continue; + if (!inet_pton (AF_INET, server_list[i], &tmp_ip4_addr)) { + if (!is_ip6_address (server_list[i])) + nm_log_warn (LOGD_SETTINGS, "ignored dns: %s\n", server_list[i]); + continue; + } + if (!nm_setting_ip_config_add_dns (s_ip4, server_list[i])) + nm_log_warn (LOGD_SETTINGS, "warning: duplicate DNS server %s", server_list[i]); + } + g_strfreev (server_list); +} + +void +set_ip6_dns_servers (NMSettingIPConfig *s_ip6, const char *conn_name) +{ + const char *dns_servers; + gchar **server_list, *stripped; + guint length, i; + struct in6_addr tmp_ip6_addr; + + dns_servers = ifnet_get_data (conn_name, "dns_servers"); + if (!dns_servers) + return; + + stripped = g_strdup (dns_servers); + strip_string (stripped, '"'); + server_list = g_strsplit (stripped, " ", 0); + g_free (stripped); + + length = g_strv_length (server_list); + if (length) + g_object_set (s_ip6, NM_SETTING_IP_CONFIG_IGNORE_AUTO_DNS, + TRUE, NULL); + for (i = 0; i < length; i++) { + g_strstrip (server_list[i]); + if (server_list[i][0] == '\0') + continue; + if (!inet_pton (AF_INET6, server_list[i], &tmp_ip6_addr)) { + if (is_ip6_address (server_list[i])) + nm_log_warn (LOGD_SETTINGS, "ignored dns: %s\n", server_list[i]); + continue; + } + if (!nm_setting_ip_config_add_dns (s_ip6, server_list[i])) + nm_log_warn (LOGD_SETTINGS, "warning: duplicate DNS server %s", server_list[i]); + } + g_strfreev (server_list); +} + +gboolean +is_managed (const char *conn_name) +{ + gchar *config; + + g_return_val_if_fail (conn_name != NULL, FALSE); + config = (gchar *) ifnet_get_data (conn_name, "managed"); + if (!config) + return TRUE; + if (strcmp (config, "false") == 0) + return FALSE; + return TRUE; +} + +static char * +_has_prefix_impl (char *str, const char *prefix, gsize prefix_len) +{ + if (!g_str_has_prefix (str, prefix)) + return NULL; + str += prefix_len; + if (!g_ascii_isspace (str[0])) + return NULL; + do { + str++; + } while (g_ascii_isspace (str[0])); + return str; +} +#define _has_prefix(STR, PREFIX) _has_prefix_impl (STR, PREFIX, NM_STRLEN (PREFIX)) + +void +get_dhcp_hostname_and_client_id (char **hostname, char **client_id) +{ + const char *dhcp_client; + const gchar *dhcpcd_conf = SYSCONFDIR "/dhcpcd.conf"; + const gchar *dhclient_conf = SYSCONFDIR "/dhcp/dhclient.conf"; + gchar *line = NULL, *tmp = NULL, *contents = NULL, *tmp1; + gchar **all_lines; + guint line_num, i; + gboolean use_dhclient = FALSE; + + *hostname = NULL; + *client_id = NULL; + dhcp_client = nm_dhcp_manager_get_config (nm_dhcp_manager_get ()); + if (dhcp_client) { + if (!strcmp (dhcp_client, "dhclient")) { + g_file_get_contents (dhclient_conf, &contents, NULL, + NULL); + use_dhclient = TRUE; + } else if (!strcmp (dhcp_client, "dhcpcd")) { + g_file_get_contents (dhcpcd_conf, &contents, NULL, + NULL); + } + } else { + if (g_file_test (dhclient_conf, G_FILE_TEST_IS_REGULAR)) { + g_file_get_contents (dhclient_conf, &contents, NULL, + NULL); + use_dhclient = TRUE; + } else if (g_file_test (dhcpcd_conf, G_FILE_TEST_IS_REGULAR)) { + g_file_get_contents (dhcpcd_conf, &contents, NULL, + NULL); + } + } + if (!contents) + return; + all_lines = g_strsplit (contents, "\n", 0); + line_num = g_strv_length (all_lines); + for (i = 0; i < line_num; i++) { + line = all_lines[i]; + g_strstrip (line); + if (line[0] == '#' || line[0] == '\0') + continue; + if (!use_dhclient) { + // dhcpcd.conf + if ((tmp = _has_prefix (line, "hostname"))) { + if (tmp[0] != '\0') { + g_free (*hostname); + *hostname = g_strdup (tmp); + } else + nm_log_info (LOGD_SETTINGS, "dhcpcd hostname not defined, ignoring"); + } else if ((tmp = _has_prefix (line, "clientid"))) { + if (tmp[0] != '\0') { + g_free (*client_id); + *client_id = g_strdup (tmp); + } else + nm_log_info (LOGD_SETTINGS, "dhcpcd clientid not defined, ignoring"); + } + } else { + // dhclient.conf + if ((tmp1 = _has_prefix (line, "send"))) { + if ((tmp = _has_prefix (tmp1, "host-name"))) { + strip_string (tmp, ';'); + strip_string (tmp, '"'); + if (tmp[0] != '\0') { + g_free (*hostname); + *hostname = g_strdup (tmp); + } else + nm_log_info (LOGD_SETTINGS, "dhclient hostname not defined, ignoring"); + } else if ((tmp = _has_prefix (tmp1, "dhcp-client-identifier"))) { + strip_string (tmp, ';'); + if (tmp[0] != '\0') { + g_free (*client_id); + *client_id = g_strdup (tmp); + } else + nm_log_info (LOGD_SETTINGS, "dhclient clientid not defined, ignoring"); + } + } + } + } + g_strfreev (all_lines); + g_free (contents); +} + +gchar *backup_file (const gchar* target) +{ + GFile *source, *backup; + gchar* backup_path; + GError *error = NULL; + + source = g_file_new_for_path (target); + + if (!g_file_query_exists (source, NULL)) { + g_object_unref (source); + return NULL; + } + + backup_path = g_strdup_printf ("%s.bak", target); + backup = g_file_new_for_path (backup_path); + + if (!g_file_copy (source, backup, G_FILE_COPY_OVERWRITE, NULL, NULL, NULL, &error)) { + nm_log_warn (LOGD_SETTINGS, "Backup failed: %s", error->message); + g_free (backup_path); + backup_path = NULL; + g_error_free (error); + } + + g_object_unref (source); + g_object_unref (backup); + + return backup_path; +} diff --git a/src/settings/plugins/ifnet/nms-ifnet-net-utils.h b/src/settings/plugins/ifnet/nms-ifnet-net-utils.h new file mode 100644 index 00000000..cc273aa7 --- /dev/null +++ b/src/settings/plugins/ifnet/nms-ifnet-net-utils.h @@ -0,0 +1,71 @@ +/* -*- Mode: C; tab-width: 4; indent-tabs-mode: t; c-basic-offset: 4 -*- */ +/* + * Mu Qiao <qiaomuf@gmail.com> + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation; either version 2 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License along + * with this program; if not, write to the Free Software Foundation, Inc., + * 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA. + * + * Copyright (C) 1999-2010 Gentoo Foundation, Inc. + */ + +#ifndef _IFNET_UTILS_H +#define _IFNET_UTILS_H + +#define IFNET_PLUGIN_NAME "SettingsPlugin-Ifnet" + +#include <arpa/inet.h> + +#include "nm-setting-ip6-config.h" +#include "nm-setting-ip4-config.h" + +#include "nms-ifnet-net-parser.h" + +#define has_default_ip4_route(conn_name) has_default_route((conn_name), &is_ip4_address) +#define has_default_ip6_route(conn_name) has_default_route((conn_name), &is_ip6_address) + +typedef struct _ip_block { + char *ip; + guint32 prefix; + char *next_hop; + struct _ip_block *next; +} ip_block; + +gboolean is_static_ip4 (const char *conn_name); +gboolean is_static_ip6 (const char *conn_name); +gboolean is_ip4_address (const char *in_address); +gboolean is_ip6_address (const char *in_address); +gboolean has_ip6_address (const char *conn_name); +gboolean has_default_route (const char *conn_name, gboolean (*check_fn) (const char *)); +gboolean reload_parsers (void); + +ip_block *convert_ip4_config_block (const char *conn_name); +ip_block *convert_ip6_config_block (const char *conn_name); +ip_block *convert_ip4_routes_block (const char *conn_name); +ip_block *convert_ip6_routes_block (const char *conn_name); +void destroy_ip_block (ip_block * iblock); + +void set_ip4_dns_servers (NMSettingIPConfig * s_ip4, const char *conn_name); +void set_ip6_dns_servers (NMSettingIPConfig * s_ip6, const char *conn_name); + +gchar *strip_string (gchar *str, gchar t); +gboolean is_managed (const char *conn_name); + +gboolean is_hex (const char *value); +gboolean is_ascii (const char *value); +gboolean is_true (const char *str); + +void get_dhcp_hostname_and_client_id (char **hostname, char **client_id); + +gchar *backup_file (const gchar* target); +#endif diff --git a/src/settings/plugins/ifnet/nms-ifnet-plugin.c b/src/settings/plugins/ifnet/nms-ifnet-plugin.c new file mode 100644 index 00000000..8332358f --- /dev/null +++ b/src/settings/plugins/ifnet/nms-ifnet-plugin.c @@ -0,0 +1,524 @@ +/* -*- Mode: C; tab-width: 4; indent-tabs-mode: t; c-basic-offset: 4 -*- */ +/* NetworkManager system settings service (ifnet) + * + * Mu Qiao <qiaomuf@gmail.com> + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation; either version 2 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License along + * with this program; if not, write to the Free Software Foundation, Inc., + * 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA. + * + * Copyright (C) 1999-2010 Gentoo Foundation, Inc. + */ + +#include "nm-default.h" + +#include "nms-ifnet-plugin.h" + +#include <string.h> +#include <gmodule.h> + +#include "nm-utils.h" +#include "nm-setting-connection.h" +#include "nm-dbus-interface.h" +#include "settings/nm-settings-plugin.h" +#include "nm-config.h" +#include "NetworkManagerUtils.h" + +#include "nms-ifnet-connection.h" +#include "nms-ifnet-net-utils.h" +#include "nms-ifnet-net-parser.h" +#include "nms-ifnet-wpa-parser.h" +#include "nms-ifnet-connection-parser.h" + +#define IFNET_PLUGIN_NAME_PRINT "ifnet" +#define IFNET_PLUGIN_INFO "(C) 1999-2010 Gentoo Foundation, Inc. To report bugs please use bugs.gentoo.org with [networkmanager] or [qiaomuf] prefix." +#define IFNET_MANAGE_WELL_KNOWN_DEFAULT TRUE + +/*****************************************************************************/ + +typedef void (*FileChangedFn) (gpointer user_data); + +typedef struct { + FileChangedFn callback; + gpointer user_data; +} FileMonitorInfo; + +/*****************************************************************************/ + +typedef struct { + GHashTable *connections; /* uuid::connection */ + gboolean unmanaged_well_known; + + GFileMonitor *net_monitor; + GFileMonitor *wpa_monitor; +} SettingsPluginIfnetPrivate; + +struct _SettingsPluginIfnet { + GObject parent; + SettingsPluginIfnetPrivate _priv; +}; + +struct _SettingsPluginIfnetClass { + GObjectClass parent; +}; + +static void settings_plugin_interface_init (NMSettingsPluginInterface *plugin_iface); + +G_DEFINE_TYPE_EXTENDED (SettingsPluginIfnet, settings_plugin_ifnet, G_TYPE_OBJECT, 0, + G_IMPLEMENT_INTERFACE (NM_TYPE_SETTINGS_PLUGIN, + settings_plugin_interface_init)) + +#define SETTINGS_PLUGIN_IFNET_GET_PRIVATE(self) _NM_GET_PRIVATE (self, SettingsPluginIfnet, SETTINGS_IS_PLUGIN_IFNET) + +/*****************************************************************************/ + +static SettingsPluginIfnet *settings_plugin_ifnet_get (void); + +NM_DEFINE_SINGLETON_GETTER (SettingsPluginIfnet, settings_plugin_ifnet_get, SETTINGS_TYPE_PLUGIN_IFNET); + +/*****************************************************************************/ + +static void reload_connections (NMSettingsPlugin *config); + +/*****************************************************************************/ + +static gboolean +is_managed_plugin (void) +{ + return nm_config_data_get_value_boolean (NM_CONFIG_GET_DATA_ORIG, + NM_CONFIG_KEYFILE_GROUP_IFNET, NM_CONFIG_KEYFILE_KEY_IFNET_MANAGED, + IFNET_MANAGE_WELL_KNOWN_DEFAULT); +} + +static void +file_changed (GFileMonitor * monitor, + GFile * file, + GFile * other_file, + GFileMonitorEvent event_type, gpointer user_data) +{ + FileMonitorInfo *info; + + switch (event_type) { + case G_FILE_MONITOR_EVENT_CHANGES_DONE_HINT: + info = (FileMonitorInfo *) user_data; + info->callback (info->user_data); + break; + default: + break; + } +} + +static GFileMonitor * +monitor_file_changes (const char *filename, + FileChangedFn callback, gpointer user_data) +{ + GFile *file; + GFileMonitor *monitor; + FileMonitorInfo *info; + GError **error = NULL; + + if (!g_file_test (filename, G_FILE_TEST_IS_REGULAR)) + return NULL; + file = g_file_new_for_path (filename); + monitor = g_file_monitor_file (file, G_FILE_MONITOR_NONE, NULL, error); + g_object_unref (file); + + if (monitor) { + info = g_new0 (FileMonitorInfo, 1); + info->callback = callback; + info->user_data = user_data; + g_object_weak_ref (G_OBJECT (monitor), (GWeakNotify) g_free, + info); + g_signal_connect (monitor, "changed", G_CALLBACK (file_changed), + info); + } else { + nm_log_warn (LOGD_SETTINGS, "Monitoring %s failed, error: %s", filename, + error == NULL ? "nothing" : (*error)->message); + } + + return monitor; +} + +static void +setup_monitors (NMIfnetConnection *connection, gpointer user_data) +{ + SettingsPluginIfnet *self = SETTINGS_PLUGIN_IFNET (user_data); + SettingsPluginIfnetPrivate *priv = SETTINGS_PLUGIN_IFNET_GET_PRIVATE (self); + + if (!nm_config_get_monitor_connection_files (nm_config_get ())) + return; + + if (priv->net_monitor || priv->wpa_monitor) + return; + + priv->net_monitor = monitor_file_changes (CONF_NET_FILE, + (FileChangedFn) reload_connections, + user_data); + priv->wpa_monitor = monitor_file_changes (WPA_SUPPLICANT_CONF, + (FileChangedFn) reload_connections, + user_data); +} + +static void +cancel_monitors (NMIfnetConnection *connection, gpointer user_data) +{ + SettingsPluginIfnet *self = SETTINGS_PLUGIN_IFNET (user_data); + SettingsPluginIfnetPrivate *priv = SETTINGS_PLUGIN_IFNET_GET_PRIVATE (self); + + if (priv->net_monitor) { + g_file_monitor_cancel (priv->net_monitor); + g_clear_object (&priv->net_monitor); + } + if (priv->wpa_monitor) { + g_file_monitor_cancel (priv->wpa_monitor); + g_clear_object (&priv->wpa_monitor); + } +} + +static void +connection_removed_cb (NMSettingsConnection *obj, gpointer user_data) +{ + g_hash_table_remove (SETTINGS_PLUGIN_IFNET_GET_PRIVATE ((SettingsPluginIfnet *) user_data)->connections, + nm_connection_get_uuid (NM_CONNECTION (obj))); +} + +static void +track_new_connection (SettingsPluginIfnet *self, NMIfnetConnection *connection) +{ + g_hash_table_insert (SETTINGS_PLUGIN_IFNET_GET_PRIVATE (self)->connections, + g_strdup (nm_connection_get_uuid (NM_CONNECTION (connection))), + g_object_ref (connection)); + g_signal_connect (connection, NM_SETTINGS_CONNECTION_REMOVED, + G_CALLBACK (connection_removed_cb), + self); +} + +static void +reload_connections (NMSettingsPlugin *config) +{ + SettingsPluginIfnet *self = SETTINGS_PLUGIN_IFNET (config); + SettingsPluginIfnetPrivate *priv = SETTINGS_PLUGIN_IFNET_GET_PRIVATE (self); + GList *conn_names = NULL, *n_iter = NULL; + gboolean auto_refresh; + GError *error = NULL; + + /* save names for removing unused connections */ + GHashTable *new_connections = NULL; + GHashTableIter iter; + const char *uuid; + NMSettingsConnection *candidate; + + if (priv->unmanaged_well_known) + return; + + if (!reload_parsers ()) + return; + + nm_log_info (LOGD_SETTINGS, "Loading connections"); + + auto_refresh = nm_config_data_get_value_boolean (NM_CONFIG_GET_DATA_ORIG, + NM_CONFIG_KEYFILE_GROUP_IFNET, NM_CONFIG_KEYFILE_KEY_IFNET_AUTO_REFRESH, + FALSE); + + new_connections = g_hash_table_new_full (nm_str_hash, g_str_equal, NULL, g_object_unref); + + /* Reread on-disk data and refresh in-memory connections from it */ + conn_names = ifnet_get_connection_names (); + for (n_iter = conn_names; n_iter; n_iter = g_list_next (n_iter)) { + NMIfnetConnection *new; + NMIfnetConnection *old; + const char *conn_name = n_iter->data; + + /* read the new connection */ + new = nm_ifnet_connection_new (NULL, conn_name); + if (!new) + continue; + + g_signal_connect (G_OBJECT (new), "ifnet_setup_monitors", + G_CALLBACK (setup_monitors), config); + g_signal_connect (G_OBJECT (new), "ifnet_cancel_monitors", + G_CALLBACK (cancel_monitors), config); + + old = g_hash_table_lookup (priv->connections, + nm_connection_get_uuid (NM_CONNECTION (new))); + if (old && new) { + if (auto_refresh) { + /* If connection has changed, remove the old one and add the + * new one to force a disconnect/reconnect with new settings + */ + if (!nm_connection_compare (NM_CONNECTION (old), + NM_CONNECTION (new), + NM_SETTING_COMPARE_FLAG_IGNORE_AGENT_OWNED_SECRETS | + NM_SETTING_COMPARE_FLAG_IGNORE_NOT_SAVED_SECRETS)) { + nm_log_info (LOGD_SETTINGS, "Auto refreshing %s", conn_name); + + nm_settings_connection_signal_remove (NM_SETTINGS_CONNECTION (old)); + track_new_connection (self, new); + if (is_managed_plugin () && is_managed (conn_name)) + g_signal_emit_by_name (self, NM_SETTINGS_PLUGIN_CONNECTION_ADDED, new); + } + } else { + /* Update existing connection with new settings */ + if (!nm_settings_connection_update (NM_SETTINGS_CONNECTION (old), + NM_CONNECTION (new), + NM_SETTINGS_CONNECTION_PERSIST_MODE_KEEP_SAVED, + NM_SETTINGS_CONNECTION_COMMIT_REASON_NONE, + "ifnet-update", + &error)) { + /* Shouldn't ever get here as 'new' was verified by the reader already + * and the UUID did not change. */ + g_assert_not_reached (); + } + g_assert_no_error (error); + nm_log_info (LOGD_SETTINGS, "Connection %s updated", + nm_connection_get_id (NM_CONNECTION (new))); + } + g_signal_emit_by_name (self, NM_SETTINGS_PLUGIN_UNMANAGED_SPECS_CHANGED); + } else if (new) { + track_new_connection (self, new); + if (is_managed_plugin () && is_managed (conn_name)) + g_signal_emit_by_name (self, NM_SETTINGS_PLUGIN_CONNECTION_ADDED, new); + } + + /* Track all valid connections so we can remove deleted ones later */ + g_hash_table_insert (new_connections, + (gpointer) nm_connection_get_uuid (NM_CONNECTION (new)), + new); + } + + /* remove deleted/unused connections */ + g_hash_table_iter_init (&iter, priv->connections); + while (g_hash_table_iter_next (&iter, (gpointer) &uuid, (gpointer) &candidate)) { + /* only saved connections (which have a conn_name) get removed; unsaved + * ones obviously don't exist in /etc/conf.d/net yet and shouldn't get + * blown away by net file changes. + */ + if ( nm_ifnet_connection_get_conn_name (NM_IFNET_CONNECTION (candidate)) + && !g_hash_table_lookup (new_connections, uuid)) { + nm_settings_connection_signal_remove (candidate); + g_hash_table_iter_remove (&iter); + } + } + g_hash_table_destroy (new_connections); + g_list_free (conn_names); +} + +static NMSettingsConnection * +add_connection (NMSettingsPlugin *config, + NMConnection *source, + gboolean save_to_disk, + GError **error) +{ + SettingsPluginIfnetPrivate *priv = SETTINGS_PLUGIN_IFNET_GET_PRIVATE ((SettingsPluginIfnet *) config); + NMIfnetConnection *new = NULL; + + /* Ensure we reject attempts to add the connection long before we're + * asked to write it to disk. + */ + if (!ifnet_can_write_connection (source, error)) + goto out; + + if (save_to_disk) { + if (!ifnet_add_new_connection (source, CONF_NET_FILE, WPA_SUPPLICANT_CONF, NULL, NULL, error)) + goto out; + reload_connections (config); + new = g_hash_table_lookup (priv->connections, nm_connection_get_uuid (source)); + } else { + new = nm_ifnet_connection_new (source, NULL); + if (new) { + track_new_connection (SETTINGS_PLUGIN_IFNET (config), new); + /* track_new_connection refs 'new' */ + g_object_unref (new); + } + } + +out: + if (!new && error && !*error) { + g_set_error_literal (error, NM_SETTINGS_ERROR, NM_SETTINGS_ERROR_FAILED, + "The ifnet plugin cannot add the connection (unknown error)."); + } + return (NMSettingsConnection *) new; +} + +static void +check_unmanaged (gpointer key, gpointer data, gpointer user_data) +{ + NMIfnetConnection *connection = NM_IFNET_CONNECTION (data); + GSList **list = (GSList **) user_data; + const char *mac, *conn_name; + char *unmanaged_spec; + GSList *iter; + + conn_name = nm_ifnet_connection_get_conn_name (connection); + + if (!conn_name || is_managed (conn_name)) + return; + + nm_log_info (LOGD_SETTINGS, "Checking unmanaged: %s", conn_name); + mac = ifnet_get_data (conn_name, "mac"); + if (mac) + unmanaged_spec = g_strdup_printf ("mac:%s", mac); + else + unmanaged_spec = g_strdup_printf ("interface-name:%s", conn_name); + + /* Just return if the unmanaged spec is already in the list */ + for (iter = *list; iter; iter = g_slist_next (iter)) { + if (g_str_equal (iter->data, unmanaged_spec)) { + g_free (unmanaged_spec); + return; + } + } + + nm_log_info (LOGD_SETTINGS, "Add unmanaged: %s", unmanaged_spec); + *list = g_slist_prepend (*list, unmanaged_spec); +} + +static GSList * +get_unmanaged_specs (NMSettingsPlugin * config) +{ + SettingsPluginIfnetPrivate *priv = SETTINGS_PLUGIN_IFNET_GET_PRIVATE ((SettingsPluginIfnet *) config); + GSList *list = NULL; + + nm_log_info (LOGD_SETTINGS, "getting unmanaged specs..."); + g_hash_table_foreach (priv->connections, check_unmanaged, &list); + return list; +} + +static GSList * +get_connections (NMSettingsPlugin *config) +{ + SettingsPluginIfnetPrivate *priv = SETTINGS_PLUGIN_IFNET_GET_PRIVATE ((SettingsPluginIfnet *) config); + GSList *connections = NULL; + GHashTableIter iter; + NMIfnetConnection *connection; + + nm_log_info (LOGD_SETTINGS, "(%p) ... get_connections.", config); + + g_hash_table_iter_init (&iter, priv->connections); + while (g_hash_table_iter_next (&iter, NULL, (gpointer) &connection)) { + const char *conn_name = nm_ifnet_connection_get_conn_name (connection); + + if (!conn_name || (!priv->unmanaged_well_known && is_managed (conn_name))) + connections = g_slist_prepend (connections, connection); + } + nm_log_info (LOGD_SETTINGS, "(%p) connections count: %d", + config, g_slist_length (connections)); + return connections; +} + +/*****************************************************************************/ + +static void +get_property (GObject * object, guint prop_id, GValue * value, + GParamSpec * pspec) +{ + switch (prop_id) { + case NM_SETTINGS_PLUGIN_PROP_NAME: + g_value_set_string (value, IFNET_PLUGIN_NAME_PRINT); + break; + case NM_SETTINGS_PLUGIN_PROP_INFO: + g_value_set_string (value, IFNET_PLUGIN_INFO); + break; + case NM_SETTINGS_PLUGIN_PROP_CAPABILITIES: + g_value_set_uint (value, + NM_SETTINGS_PLUGIN_CAP_MODIFY_CONNECTIONS); + break; + default: + G_OBJECT_WARN_INVALID_PROPERTY_ID (object, prop_id, pspec); + break; + } +} + +/*****************************************************************************/ + +static void +init (NMSettingsPlugin *config) +{ + SettingsPluginIfnet *self = SETTINGS_PLUGIN_IFNET (config); + SettingsPluginIfnetPrivate *priv = SETTINGS_PLUGIN_IFNET_GET_PRIVATE (self); + + nm_log_info (LOGD_SETTINGS, "Initializing!"); + + priv->connections = g_hash_table_new_full (nm_str_hash, g_str_equal, g_free, g_object_unref); + priv->unmanaged_well_known = !is_managed_plugin (); + nm_log_info (LOGD_SETTINGS, "management mode: %s", + priv->unmanaged_well_known ? "unmanaged" : "managed"); + + setup_monitors (NULL, config); + reload_connections (config); + + nm_log_info (LOGD_SETTINGS, "Initialzation complete!"); +} + +/*****************************************************************************/ + +static void +settings_plugin_ifnet_init (SettingsPluginIfnet * plugin) +{ +} + +static void +dispose (GObject * object) +{ + SettingsPluginIfnet *plugin = SETTINGS_PLUGIN_IFNET (object); + SettingsPluginIfnetPrivate *priv = SETTINGS_PLUGIN_IFNET_GET_PRIVATE ((SettingsPluginIfnet *) plugin); + + cancel_monitors (NULL, object); + if (priv->connections) { + g_hash_table_destroy (priv->connections); + priv->connections = NULL; + } + + ifnet_destroy (); + wpa_parser_destroy (); + G_OBJECT_CLASS (settings_plugin_ifnet_parent_class)->dispose (object); +} + +static void +settings_plugin_ifnet_class_init (SettingsPluginIfnetClass * req_class) +{ + GObjectClass *object_class = G_OBJECT_CLASS (req_class); + + object_class->dispose = dispose; + object_class->get_property = get_property; + + g_object_class_override_property (object_class, + NM_SETTINGS_PLUGIN_PROP_NAME, + NM_SETTINGS_PLUGIN_NAME); + + g_object_class_override_property (object_class, + NM_SETTINGS_PLUGIN_PROP_INFO, + NM_SETTINGS_PLUGIN_INFO); + + g_object_class_override_property (object_class, + NM_SETTINGS_PLUGIN_PROP_CAPABILITIES, + NM_SETTINGS_PLUGIN_CAPABILITIES); +} + +static void +settings_plugin_interface_init (NMSettingsPluginInterface *plugin_iface) +{ + plugin_iface->init = init; + plugin_iface->get_connections = get_connections; + plugin_iface->get_unmanaged_specs = get_unmanaged_specs; + plugin_iface->add_connection = add_connection; + plugin_iface->reload_connections = reload_connections; +} + +/*****************************************************************************/ + +G_MODULE_EXPORT GObject * +nm_settings_plugin_factory (void) +{ + return G_OBJECT (g_object_ref (settings_plugin_ifnet_get ())); +} diff --git a/src/settings/plugins/ifnet/nms-ifnet-plugin.h b/src/settings/plugins/ifnet/nms-ifnet-plugin.h new file mode 100644 index 00000000..f006e7e4 --- /dev/null +++ b/src/settings/plugins/ifnet/nms-ifnet-plugin.h @@ -0,0 +1,38 @@ +/* -*- Mode: C; tab-width: 4; indent-tabs-mode: t; c-basic-offset: 4 -*- */ +/* NetworkManager system settings service (ifnet) + * + * Mu Qiao <qiaomuf@gmail.com> + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation; either version 2 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License along + * with this program; if not, write to the Free Software Foundation, Inc., + * 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA. + * + * Copyright (C) 1999-2010 Gentoo Foundation, Inc. + */ + +#ifndef _PLUGIN_H_ +#define _PLUGIN_H_ + +#define SETTINGS_TYPE_PLUGIN_IFNET (settings_plugin_ifnet_get_type ()) +#define SETTINGS_PLUGIN_IFNET(obj) (G_TYPE_CHECK_INSTANCE_CAST ((obj), SETTINGS_TYPE_PLUGIN_IFNET, SettingsPluginIfnet)) +#define SETTINGS_PLUGIN_IFNET_CLASS(klass) (G_TYPE_CHECK_CLASS_CAST ((klass), SETTINGS_TYPE_PLUGIN_IFNET, SettingsPluginIfnetClass)) +#define SETTINGS_IS_PLUGIN_IFNET(obj) (G_TYPE_CHECK_INSTANCE_TYPE ((obj), SETTINGS_TYPE_PLUGIN_IFNET)) +#define SETTINGS_IS_PLUGIN_IFNET_CLASS(klass) (G_TYPE_CHECK_CLASS_TYPE ((klass), SETTINGS_TYPE_PLUGIN_IFNET)) +#define SETTINGS_PLUGIN_IFNET_GET_CLASS(obj) (G_TYPE_INSTANCE_GET_CLASS ((obj), SETTINGS_TYPE_PLUGIN_IFNET, SettingsPluginIfnetClass)) + +typedef struct _SettingsPluginIfnet SettingsPluginIfnet; +typedef struct _SettingsPluginIfnetClass SettingsPluginIfnetClass; + +GType settings_plugin_ifnet_get_type (void); + +#endif diff --git a/src/settings/plugins/ifnet/nms-ifnet-wpa-parser.c b/src/settings/plugins/ifnet/nms-ifnet-wpa-parser.c new file mode 100644 index 00000000..2b62e886 --- /dev/null +++ b/src/settings/plugins/ifnet/nms-ifnet-wpa-parser.c @@ -0,0 +1,584 @@ +/* -*- Mode: C; tab-width: 4; indent-tabs-mode: t; c-basic-offset: 4 -*- */ +/* + * Mu Qiao <qiaomuf@gmail.com> + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation; either version 2 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License along + * with this program; if not, write to the Free Software Foundation, Inc., + * 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA. + * + * Copyright (C) 1999-2010 Gentoo Foundation, Inc. + */ + +#include "nm-default.h" + +#include "nms-ifnet-wpa-parser.h" + +#include <string.h> +#include <stdlib.h> + +#include "nm-utils/nm-hash-utils.h" +#include "settings/nm-settings-plugin.h" + +#include "nms-ifnet-net-parser.h" +#include "nms-ifnet-net-utils.h" + +/* Security information */ +static GHashTable *wsec_table = NULL; + +/* Global information used for writing */ +static GHashTable *wsec_global_table = NULL; + +static gboolean wpa_parser_data_changed = FALSE; + +static long +wpa_get_long (GHashTable *table, const char *key) +{ + return atol (g_hash_table_lookup (table, key)); +} + +static void +destroy_security (GHashTable * network) +{ + gpointer key, value; + GHashTableIter iter; + + g_return_if_fail (network); + g_hash_table_iter_init (&iter, network); + while (g_hash_table_iter_next (&iter, &key, &value)) { + g_free (key); + g_free (value); + } + + g_hash_table_destroy (network); +} + +static GHashTable * +add_security (GHashTable *security) +{ + GHashTable *oldsecurity; + const char *ssid, *value; + char *ssid_key; + gboolean is_hex_ssid; + + /* Every security information should have a ssid */ + ssid = g_hash_table_lookup (security, "ssid"); + if (!ssid) { + destroy_security (security); + return NULL; + } + + /* Hex format begins with " */ + is_hex_ssid = (ssid[0] != '"'); + if ((value = g_hash_table_lookup (security, "disabled")) != NULL) { + if (strcmp (value, "1") == 0) { + destroy_security (security); + return NULL; + } + } + + /* Default priority is 1 */ + if (g_hash_table_lookup (security, "priority") == NULL) + g_hash_table_insert (security, g_strdup ("priority"), + g_strdup ("1")); + + oldsecurity = g_hash_table_lookup (wsec_table, ssid); + /* Security with lower priority will be ignored */ + if (oldsecurity != NULL) { + if (wpa_get_long (oldsecurity, "priority") >= + wpa_get_long (security, "priority")) { + destroy_security (security); + return NULL; + } else { + g_hash_table_remove (wsec_table, ssid); + destroy_security (oldsecurity); + } + } + + /* format ssid */ + ssid_key = + is_hex_ssid ? g_strdup_printf ("0x%s", + ssid) : + strip_string (g_strdup (ssid), '"'); + g_hash_table_insert (wsec_table, ssid_key, security); + return security; +} + +static void +add_key_value (GHashTable * network, gchar * line) +{ + gpointer orig_key, orig_value; + gchar **key_value; + + if (g_str_has_prefix (line, "network={")) + line += 9; + strip_string (line, '{'); + strip_string (line, '}'); + if (line[0] == '\0') + return; + key_value = g_strsplit (line, "=", 2); + if (g_strv_length (key_value) != 2) { + g_strfreev (key_value); + return; + } + g_strstrip (key_value[0]); + g_strstrip (key_value[1]); + + /* Reserve quotes for psk, wep_key, ssid + * Quotes will determine whether they are hex format */ + if (strcmp (key_value[0], "psk") != 0 + && !g_str_has_prefix (key_value[0], "wep_key") + && strcmp (key_value[0], "ssid") != 0) + strip_string (key_value[1], '"'); + + /* This sucks */ + if (g_hash_table_lookup_extended (network, key_value[0], &orig_key, &orig_value)) { + g_hash_table_remove (network, orig_key); + g_free (orig_key); + g_free (orig_value); + } + + g_hash_table_insert (network, g_strdup (key_value[0]), + g_strdup (key_value[1])); + g_strfreev (key_value); +} + +static void +add_one_wep_key (GHashTable * table, int key_num, gchar * one_wep_key) +{ + if (one_wep_key[0] == 's') { + //asc key + g_hash_table_insert (table, + g_strdup_printf ("wep_key%d", key_num - 1), + g_strdup_printf ("\"%s\"", + one_wep_key + 2)); + } else { + gchar buf[30]; + int i = 0, j = 0; + + //hex key + while (one_wep_key[i] != '\0') { + if (one_wep_key[i] != '-') + buf[j++] = one_wep_key[i]; + i++; + } + buf[j] = '\0'; + g_hash_table_insert (table, + g_strdup_printf ("wep_key%d", key_num - 1), + g_strdup (buf)); + + } +} + +/* Reading wep security information from /etc/conf.d/net. + * This should not be used in future, use wpa_supplicant instead. */ +static void +add_keys_from_net (void) +{ + GList *names = ifnet_get_connection_names (); + GList *iter = names; + gchar *wep_keys = "(\\[([1-4])\\]\\s+(s:\\w{5}|s:\\w{13}|" + "([\\da-fA-F]{4}\\-){2}[\\da-fA-F]{2}|" + "([\\da-fA-F]{4}\\-){6}[\\da-fA-F]{2})\\s+)"; + gchar *key_method = + "\\s+key\\s+\\[([1-4])\\]\\s+enc\\s+(open|restricted)"; + GRegex *regex_keys = g_regex_new (wep_keys, 0, 0, NULL); + GRegex *regex_method = g_regex_new (key_method, 0, 0, NULL); + GMatchInfo *keys_info; + GMatchInfo *method_info; + + while (iter) { + gchar *conn_name = iter->data; + GHashTable *table; + const char *key_str; + + if ((key_str = ifnet_get_data (conn_name, "key")) == NULL) { + iter = g_list_next (iter); + continue; + } + + wpa_add_security (conn_name); + table = _get_hash_table (conn_name); + /* Give lowest priority */ + wpa_set_data (conn_name, "priority", "0"); + g_regex_match (regex_keys, key_str, 0, &keys_info); + /* add wep keys */ + while (g_match_info_matches (keys_info)) { + gchar *key_num = g_match_info_fetch (keys_info, 2); + gchar *one_wep_key = g_match_info_fetch (keys_info, 3); + + add_one_wep_key (table, atoi (key_num), one_wep_key); + g_free (key_num); + g_free (one_wep_key); + g_match_info_next (keys_info, NULL); + } + g_match_info_free (keys_info); + + g_regex_match (regex_method, key_str, 0, &method_info); + /* set default key index and auth alg */ + if (g_match_info_matches (method_info)) { + gchar *default_idx = + g_match_info_fetch (method_info, 1); + gchar *method = g_match_info_fetch (method_info, 2); + + default_idx[0]--; + g_hash_table_insert (table, g_strdup ("wep_tx_keyidx"), + default_idx); + g_hash_table_insert (table, g_strdup ("auth_alg"), + g_ascii_strup (method, -1)); + } + g_match_info_free (method_info); + add_security (table); + iter = g_list_next (iter); + } + g_list_free (names); + g_regex_unref (regex_keys); + g_regex_unref (regex_method); +} + +static void +add_global_data (gchar * line) +{ + gchar **key_value; + + g_strstrip (line); + key_value = g_strsplit (line, "=", 2); + if (g_strv_length (key_value) != 2) { + nm_log_warn (LOGD_SETTINGS, "Can't handle this line: %s\n", line); + g_strfreev (key_value); + return; + } + g_hash_table_insert (wsec_global_table, + g_strdup (g_strstrip (key_value[0])), + g_strdup (g_strstrip (key_value[1]))); + g_strfreev (key_value); +} + +void +wpa_parser_init (const char *wpa_supplicant_conf) +{ + GIOChannel *channel = NULL; + gchar *line; + gboolean complete = FALSE; + + wpa_parser_data_changed = FALSE; + wsec_table = g_hash_table_new (nm_str_hash, g_str_equal); + wsec_global_table = g_hash_table_new (nm_str_hash, g_str_equal); + + if (g_file_test (wpa_supplicant_conf, G_FILE_TEST_IS_REGULAR)) + channel = + g_io_channel_new_file (wpa_supplicant_conf, "r", NULL); + if (channel == NULL) { + nm_log_warn (LOGD_SETTINGS, "Can't open %s for wireless security", + wpa_supplicant_conf); + return; + } + + while (g_io_channel_read_line (channel, &line, NULL, NULL, NULL) + != G_IO_STATUS_EOF) { + g_strstrip (line); + if (line[0] != '#' && line[0] != '\0') { + if (strstr (line, "network={") == NULL) { + add_global_data (line); + g_free (line); + continue; + } else { + GHashTable *network = + g_hash_table_new (nm_str_hash, g_str_equal); + + do { + gchar *quote_start, *quote_end = NULL, *comment; + + if (line[0] == '#' || line[0] == '\0') { + g_free (line); + continue; + } + /* ignore inline comments unless inside + a double-quoted string */ + if ((quote_start = strchr (line, '"')) != NULL) + quote_end = strrchr (quote_start + 1, '"'); + if ((comment = strchr ((quote_end != NULL) ? + quote_end : line, '#')) != NULL) + *comment = '\0'; + if (strstr (line, "}") != NULL) + complete = TRUE; + add_key_value (network, line); + g_free (line); + } while (complete == FALSE + && + g_io_channel_read_line + (channel, &line, NULL, + NULL, NULL) != G_IO_STATUS_EOF); + add_security (network); + //EOF in inner loop + if (complete == FALSE) { + g_free (line); + break; + } + complete = FALSE; + } + } else + g_free (line); + } + + g_io_channel_shutdown (channel, FALSE, NULL); + g_io_channel_unref (channel); + + add_keys_from_net (); +} + +const char * +wpa_get_value (const char *ssid, const char *key) +{ + GHashTable *target = g_hash_table_lookup (wsec_table, ssid); + + if (target) + return g_hash_table_lookup (target, key); + return NULL; +} + +gboolean +exist_ssid (const char *ssid) +{ + return g_hash_table_lookup (wsec_table, ssid) != NULL; +} + +GHashTable * +_get_hash_table (const char *ssid) +{ + return g_hash_table_lookup (wsec_table, ssid); +} + +static gchar *quoted_keys[] = + { "identity", "cert", "private", "phase", "password", NULL }; + +/* tell whether the key needs quotes when writing is performed */ +static gboolean +need_quote (gchar * key) +{ + int i = 0; + + while (quoted_keys[i] != NULL) { + if (strstr (key, quoted_keys[i])) + return TRUE; + i++; + } + return FALSE; +} + +gboolean +wpa_flush_to_file (const char *config_file) +{ + GIOChannel *channel; + GError *error = NULL; + gpointer key, value, ssid, security; + GHashTableIter iter, iter_security; + gchar *out_line; + gsize bytes_written; + gboolean result = FALSE; + + if (!wpa_parser_data_changed) + return TRUE; + if (!wsec_table || !wsec_global_table) + return FALSE; + + backup_file (config_file); + + channel = g_io_channel_new_file (config_file, "w", NULL); + if (!channel) { + nm_log_warn (LOGD_SETTINGS, "Can't open file %s for writing", config_file); + return FALSE; + } + g_hash_table_iter_init (&iter, wsec_global_table); + nm_log_info (LOGD_SETTINGS, "Writing to %s", config_file); + g_io_channel_write_chars (channel, + "#Generated by NetworkManager\n" + "###### Global Configuration ######\n", + -1, &bytes_written, &error); + if (error) + goto done; + + /* Writing global information */ + while (g_hash_table_iter_next (&iter, &key, &value)) { + out_line = + g_strdup_printf ("%s=%s\n", (gchar *) key, (gchar *) value); + g_io_channel_write_chars (channel, out_line, -1, &bytes_written, + &error); + if (bytes_written == 0 || error) + break; + g_free (out_line); + } + if (error) + goto done; + g_io_channel_write_chars (channel, + "\n###### Security Configuration ######\n", + -1, &bytes_written, &error); + if (error) + goto done; + + g_hash_table_iter_init (&iter, wsec_table); + /* Writing security */ + while (g_hash_table_iter_next (&iter, &ssid, &security)) { + g_hash_table_iter_init (&iter_security, + (GHashTable *) security); + g_io_channel_write_chars (channel, "network={\n", -1, + &bytes_written, &error); + if (error) + goto done; + while (g_hash_table_iter_next (&iter_security, &key, &value)) { + out_line = + g_strdup_printf (need_quote ((gchar *) key) ? + "\t%s=\"%s\"\n" : "\t%s=%s\n", + (gchar *) key, (gchar *) value); + g_io_channel_write_chars (channel, out_line, -1, + &bytes_written, &error); + if (bytes_written == 0 || error) + goto done; + g_free (out_line); + } + g_io_channel_write_chars (channel, "}\n\n", -1, &bytes_written, &error); + + } + g_io_channel_flush (channel, &error); + if (error) + goto done; + + wpa_parser_data_changed = FALSE; + result = TRUE; +done: + if (error) { + nm_log_warn (LOGD_SETTINGS, "Error writing WPA configuration: %s", error->message); + g_error_free (error); + } + g_io_channel_shutdown (channel, FALSE, NULL); + g_io_channel_unref (channel); + return result; +} + +/* If value is NULL, this method will delete old key value pair */ +void +wpa_set_data (const char *ssid, const char *key, const char *value) +{ + gpointer old_key = NULL, old_value = NULL; + GHashTable *security = g_hash_table_lookup (wsec_table, ssid); + gchar * stripped = NULL; + + g_return_if_fail (security != NULL); + + if (value){ + stripped = g_strdup(value); + if (strcmp (key, "ssid") != 0 && strcmp (key, "psk") != 0 + && !g_str_has_prefix (key, "wep_key")) + strip_string (stripped, '"'); + } + + /* Remove old key value pairs */ + if (g_hash_table_lookup_extended + (security, key, &old_key, &old_value)) { + if (stripped && !strcmp(old_value, stripped)){ + g_free (stripped); + return; + } + g_hash_table_remove (security, old_key); + g_free (old_key); + g_free (old_value); + } else if (!value) + return; + + /* Add new key value */ + if (stripped) + g_hash_table_insert (security, g_strdup (key), stripped); + wpa_parser_data_changed = TRUE; +} + +gboolean +wpa_has_security (const char *ssid) +{ + return g_hash_table_lookup (wsec_table, ssid) != NULL; +} + +gboolean +wpa_add_security (const char *ssid) +{ + if (wpa_has_security (ssid)) + return TRUE; + else { + GHashTable *security = + g_hash_table_new (nm_str_hash, g_str_equal); + gchar *ssid_i; + + nm_log_info (LOGD_SETTINGS, "Adding security for %s", ssid); + if (g_str_has_prefix (ssid, "0x")) { + /* hex ssid */ + ssid_i = g_strdup (ssid + 2); + } else { + /* ascii ssid requires quotes */ + ssid_i = g_strdup_printf ("\"%s\"", ssid); + } + g_hash_table_insert (security, strdup ("ssid"), ssid_i); + g_hash_table_insert (security, strdup ("priority"), + strdup ("1")); + g_hash_table_insert (wsec_table, g_strdup (ssid), security); + wpa_parser_data_changed = TRUE; + return TRUE; + } +} + +gboolean +wpa_delete_security (const char *ssid) +{ + gpointer old_key, old_value; + + g_return_val_if_fail (wsec_table != NULL && ssid != NULL, FALSE); + nm_log_info (LOGD_SETTINGS, "Deleting security for %s", ssid); + if (!g_hash_table_lookup_extended + (wsec_table, ssid, &old_key, &old_value)) + return FALSE; + g_hash_table_remove (wsec_table, old_key); + g_free (old_key); + destroy_security ((GHashTable *) old_value); + wpa_parser_data_changed = TRUE; + return TRUE; + +} + +void +wpa_parser_destroy (void) +{ + GHashTableIter iter; + gpointer key; + gpointer value; + + /* Destroy security */ + if (wsec_table) { + g_hash_table_iter_init (&iter, wsec_table); + while (g_hash_table_iter_next (&iter, &key, &value)) { + destroy_security ((GHashTable *) value); + g_free (key); + } + + g_hash_table_destroy (wsec_table); + wsec_table = NULL; + } + + /* Destroy global data */ + if (wsec_global_table) { + g_hash_table_iter_init (&iter, wsec_global_table); + while (g_hash_table_iter_next (&iter, &key, &value)) { + g_free (key); + g_free (value); + } + + g_hash_table_destroy (wsec_global_table); + wsec_global_table = NULL; + } +} diff --git a/src/settings/plugins/ifnet/nms-ifnet-wpa-parser.h b/src/settings/plugins/ifnet/nms-ifnet-wpa-parser.h new file mode 100644 index 00000000..d096f468 --- /dev/null +++ b/src/settings/plugins/ifnet/nms-ifnet-wpa-parser.h @@ -0,0 +1,41 @@ +/* -*- Mode: C; tab-width: 4; indent-tabs-mode: t; c-basic-offset: 4 -*- */ +/* + * Mu Qiao <qiaomuf@gmail.com> + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation; either version 2 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License along + * with this program; if not, write to the Free Software Foundation, Inc., + * 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA. + * + * Copyright (C) 1999-2010 Gentoo Foundation, Inc. + */ + +#ifndef _WPA_PARSER_H +#define _WPA_PARSER_H + +#define WPA_SUPPLICANT_CONF SYSCONFDIR "/wpa_supplicant/wpa_supplicant.conf" + +void wpa_parser_init (const char *wpa_supplicant_conf); +void wpa_parser_destroy (void); + +/* reader functions */ +const char *wpa_get_value (const char *ssid, const char *key); +gboolean exist_ssid (const char *ssid); +GHashTable *_get_hash_table (const char *ssid); +gboolean wpa_has_security (const char *ssid); + +/* writer functions */ +gboolean wpa_flush_to_file (const char *config_file); +void wpa_set_data (const char *ssid, const char *key, const char *value); +gboolean wpa_add_security (const char *ssid); +gboolean wpa_delete_security (const char *ssid); +#endif diff --git a/src/settings/plugins/ifnet/tests/net b/src/settings/plugins/ifnet/tests/net new file mode 100644 index 00000000..a5ac9ca2 --- /dev/null +++ b/src/settings/plugins/ifnet/tests/net @@ -0,0 +1,158 @@ +# This blank configuration will automatically use DHCP for any net.* +# scripts in /etc/init.d. To create a more complete configuration, +# please review /etc/conf.d/net.example and save your configuration +# in /etc/conf.d/net (this file :]!). + +modules="!wpa_supplicant" + +config_eth0=( +"202.117.16.121 netmask 255.255.255.0 brd 202.117.16.255" +"192.168.4.121/24" +"dhcp6" +) +routes_eth0=( "default via 202.117.16.1" + "192.168.4.0/24 via 192.168.4.1") +dns_servers_eth0="202.117.0.20 202.117.0.21" +dns_search_eth0="p12.edu.cn p13.edu.cn" + +config_eth1=( + "dhcp" +) +enable_ipv6_eth1="true" +routes_eth1=( "default via 202.117.16.1" ) +dns_servers_eth1="202.117.0.20 202.117.0.21" +config_eth2=( +"202.117.16.1211 netmask 255.255.255.0 brd 202.117.16.255" +"192.168.4.121/24" +"4321:0:1:2:3:4:567:89ab/64" +) +routes_eth2=("default via 4321:0:1:2:3:4:567:89ab") +enable_ipv6_eth2="true" +config_eth3=("nufjlsjlll") +managed_eth4="false" +routes_eth4=("default via 4321:0:1:2:3:4:567:89ab") +config_eth5=("dhcp") + +config_eth7=( "dhcp" ) +auto_eth7="true" + +# missing config_eth8 +auto_eth8="true" + +#new openrc style +config_eth9="202.117.16.10/24 202.117.17.10/24" +routes_eth9="default via 202.117.16.1 +10.0.0.0/8 via 192.168.0.1 +" +config_eth10="202.117.16.2 netmask 255.255.255.0" +routes_eth10="10.0.0.0/8 via 192.168.0.1" + +config_myxjtu2=("202.117.16.121/24 brd 202.117.16.255") +routes_myxjtu2=("default via 202.117.16.1") +dns_servers_myxjtu2="202.117.0.20 202.117.0.21" +#key_myxjtu2="[1] s:xjtud key [1] enc restricted" +#key_eth6="[1] aaaa-4444-3d [2] s:xjtudlc key [1] enc open" + + +username_ppp0='user' +password_ppp0='password' + +config_qiaomuf=("dhcp") + +config_1xtest=("dhcp") + +config_0xab3ace=("dhcp") + +modules=( "iproute2" ) + config_kvm0=( "null" ) + config_kvm1=( "null" ) + + tuntap_kvm0="tap" + tuntap_kvm1="tap" + tunctl_kvm0="-u user" + tunctl_kvm1="-u user" + +bridge_br0="eth0 kvm0 kvm1" +config_br0=( "192.168.1.10/24" ) + brctl_br0=( "setfd 0") + dhcp_eth1="nosendhost nontp -I" + +predown() { + # The default in the script is to test for NFS root and disallow + # downing interfaces in that case. Note that if you specify a + # predown() function you will override that logic. Here it is, in + # case you still want it... + if is_net_fs /; then + eerror "root filesystem is network mounted -- can't stop ${IFACE}" + return 1 + fi + + # Remember to return 0 on success + return 0 +} + +postup() { + # This function could be used, for example, to register with a + # dynamic DNS service. Another possibility would be to + # send/receive mail once the interface is brought up. + + # Here is an example that allows the use of iproute rules + # which have been configured using the rules_eth0 variable. + #rules_eth0=" \ + # 'from 24.80.102.112/32 to 192.168.1.0/24 table localnet priority 100' \ + # 'from 216.113.223.51/32 to 192.168.1.0/24 table localnet priority 100' \ + #" + eval set -- \$rules_${IFVAR} + if [ $# != 0 ]; then + einfo "Adding IP policy routing rules" + eindent + # Ensure that the kernel supports policy routing + if ! ip rule list | grep -q "^"; then + eerror "You need to enable IP Policy Routing (CONFIG_IP_MULTIPLE_TABLES)" + eerror "in your kernel to use ip rules" + else + for x; do + ebegin "${x}" + ip rule add ${x} + eend $? + done + fi + eoutdent + # Flush the cache + ip route flush cache dev "${IFACE}" + fi + +} + +postdown() { + # Enable Wake-On-LAN for every interface except for lo + # Probably a good idea to set ifdown="no" in /etc/conf.d/net + # as well ;) + [ "${IFACE}" != "lo" ] && ethtool -s "${IFACE}" wol g + + Automatically erase any ip rules created in the example postup above + if interface_exists "${IFACE}"; then + # Remove any rules for this interface + local rule + ip rule list | grep " iif ${IFACE}[ ]*" | { + while read rule; do + rule="${rule#*:}" + ip rule del ${rule} + done + } + # Flush the route cache + ip route flush cache dev "${IFACE}" + fi + + # Return 0 always + return 0 +} + +failup() { + # This function is mostly here for completeness... I haven't + # thought of anything nifty to do with it yet ;-) +} + +faildown() +{} + diff --git a/src/settings/plugins/ifnet/tests/net.all b/src/settings/plugins/ifnet/tests/net.all new file mode 100644 index 00000000..285a4cdf --- /dev/null +++ b/src/settings/plugins/ifnet/tests/net.all @@ -0,0 +1,864 @@ +############################################################################## +# QUICK-START +# +# The quickest start is if you want to use DHCP. +# In that case, everything should work out of the box, no configuration +# necessary, though the startup script will warn you that you haven't +# specified anything. + +# WARNING :- some examples have a mixture of IPv4 (ie 192.168.0.1) and IPv6 +# (ie 4321:0:1:2:3:4:567:89ab) internet addresses. They only work if you have +# the relevant kernel option enabled. So if you don't have an IPv6 enabled +# kernel then remove the IPv6 address from your config. + +# If you want to use a static address or use DHCP explicitly, jump +# down to the section labelled INTERFACE HANDLERS. +# +# If you want to do anything more fancy, you should take the time to +# read through the rest of this file. + +############################################################################## +# MODULES +# +# We now support modular networking scripts which means we can easily +# add support for new interface types and modules while keeping +# compatability with existing ones. +# +# Modules load by default if the package they need is installed. If +# you specify a module here that doesn't have it's package installed +# then you get an error stating which package you need to install. +# Ideally, you only use the modules setting when you have two or more +# packages installed that supply the same service. +# +# In other words, you probably should DO NOTHING HERE... + +# Prefer ifconfig over iproute2 +modules=( "ifconfig" ) + +# You can also specify other modules for an interface +# In this case we prefer udhcpc over dhcpcd +modules_eth0=( "udhcpc" ) + +# You can also specify which modules not to use - for example you may be +# using a supplicant or linux-wlan-ng to control wireless configuration but +# you still want to configure network settings per ESSID associated with. +modules=( "!iwconfig" "!wpa_supplicant" ) +# IMPORTANT: If you need the above, please disable modules in that order + + +############################################################################## +# INTERFACE HANDLERS +# +# We provide two interface handlers presently: ifconfig and iproute2. +# You need one of these to do any kind of network configuration. +# For ifconfig support, emerge sys-apps/net-tools +# For iproute2 support, emerge sys-apps/iproute2 + +# If you don't specify an interface then we prefer iproute2 if it's installed +# To prefer ifconfig over iproute2 +modules=( "ifconfig" ) + +# For a static configuration, use something like this +# (They all do exactly the same thing btw) +config_eth0=( "192.168.0.2/24" ) +config_eth0=( "192.168.0.2 netmask 255.255.255.0" ) + +# We can also specify a broadcast +config_eth0=( "192.168.0.2/24 brd 192.168.0.255" ) +config_eth0=( "192.168.0.2 netmask 255.255.255.0 broadcast 192.168.0.255" ) + +# If you need more than one address, you can use something like this +# NOTE: ifconfig creates an aliased device for each extra IPv4 address +# (eth0:1, eth0:2, etc) +# iproute2 does not do this as there is no need to +config_eth0=( + "192.168.0.2/24" + "192.168.0.3/24" + "192.168.0.4/24" +) +# Or you can use sequence expressions +config_eth0=( "192.168.0.{2..4}/24" ) +# which does the same as above. Be careful though as if you use this and +# fallbacks, you have to ensure that both end up with the same number of +# values otherwise your fallback won't work correctly. + +# You can also use IPv6 addresses +# (you should always specify a prefix length with IPv6 here) +config_eth0=( + "192.168.0.2/24" + "4321:0:1:2:3:4:567:89ab/64" + "4321:0:1:2:3:4:567:89ac/64" +) + +# If you wish to keep existing addresses + routing and the interface is up, +# you can specify a noop (no operation). If the interface is down or there +# are no addresses assigned, then we move onto the next step (default dhcp) +# This is useful when configuring your interface with a kernel command line +# or similar +config_eth0=( "noop" "192.168.0.2/24" ) + +# If you don't want ANY address (only useful when calling for advanced stuff) +config_eth0=( "null" ) + +# Here's how to do routing if you need it +routes_eth0=( + "default via 192.168.0.1" # IPv4 default route + "10.0.0.0/8 via 192.168.0.1" # IPv4 subnet route + "::/0" # IPv6 unicast +) + +# If a specified module fails (like dhcp - see below), you can specify a +# fallback like so +fallback_eth0=( "192.168.0.2 netmask 255.255.255.0" ) +fallback_route_eth0=( "default via 192.168.0.1" ) + +# NOTE: fallback entry must match the entry location in config_eth0 +# As such you can only have one fallback route. + +# Some users may need to alter the MTU - here's how +mtu_eth0="1500" + +# Each module described below can set a default base metric, lower is +# preferred over higher. This is so we can prefer a wired route over a +# wireless route automaticaly. You can override this by setting +metric_eth0="100" +# or on a global basis +metric="100" +# The only downside of the global setting is that you have to ensure that +# there are no conflicting routes yourself. For users with large routing +# tables you may have to set a global metric as the due to a simple read of +# the routing table taking over a minute at a time. + +############################################################################## +# OPTIONAL MODULES + +# INTERFACE RENAMING +# There is no consistent device renaming scheme for Linux. +# The preferred way of naming devices is via the kernel module directly or +# by using udev (http://www.reactivated.net/udevrules.php) + +# If you are unable to write udev rules, then we do provide a way of renaming +# the interface based on it's MAC address, but it is not optimal. +# Here is how to rename an interface whose MAC address is 00:11:22:33:44:55 +# to foo1 +rename_001122334455="foo1" + +# You can also do this based on current device name - although this is not +# recommended. Here we rename eth1 to foo2. +rename_eth1="foo2" + +#----------------------------------------------------------------------------- +# WIRELESS (802.11 support) +# Wireless can be provided by iwconfig or wpa_supplicant + +# iwconfig +# emerge net-wireless/wireless-tools +# Wireless options are held in /etc/conf.d/wireless - but could be here too +# Consult the sample file /etc/conf.d/wireless.example for instructions +# iwconfig is the default + +# wpa_supplicant +# emerge net-wireless/wpa-supplicant +# Wireless options are held in /etc/wpa_supplicant.conf +# Consult the sample file /etc/wpa_supplicant.conf.example for instructions +# To choose wpa_supplicant over iwconfig +modules=( "wpa_supplicant" ) +# To configure wpa_supplicant +wpa_supplicant_eth0="-Dwext" # For generic wireless +wpa_supplicant_ath0="-Dmadwifi" # For Atheros based cards +# Consult wpa_supplicant for more drivers +# By default don't wait for wpa_suppliant to associate and authenticate. +# If you would like to, so can specify how long in seconds +associate_timeout_eth0=60 +# A value of 0 means wait forever. + +# GENERIC WIRELESS OPTIONS +# PLEASE READ THE INSTRUCTIONS IN /etc/conf.d/wireless.example FOR +# HOW TO USE THIS ESSID VARIABLE +# You can also override any settings found here per ESSID - which is very +# handy if you use different networks a lot +config_ESSID=( "dhcp" ) +dhcpcd_ESSID="-t 5" + +# Setting name/domain server causes /etc/resolv.conf to be overwritten +# Note that if DHCP is used, and you want this to take precedence then + set dhcp_ESSID="nodns" +dns_servers_ESSID=( "192.168.0.1" "192.168.0.2" ) +dns_domain_ESSID="some.domain" +dns_search_ESSID="search.this.domain search.that.domain" +# Please check the man page for resolv.conf for more information +# as domain and search are mutually exclusive. + +# You can also override any settings found here per MAC address of the AP +# in case you use Access Points with the same ESSID but need different +# networking configs. Below is an example - of course you use the same +# method with other variables +mac_config_001122334455=( "dhcp" ) +mac_dhcpcd_001122334455="-t 10" +mac_dns_servers_001122334455=( "192.168.0.1" "192.168.0.2" ) + +# When an interface has been associated with an Access Point, a global +# variable called ESSID is set to the Access Point's ESSID for use in the +# pre/post user functions below (although it's not available in preup as you +# won't have associated then) + +# If you're using anything else to configure wireless on your interface AND +# you have installed any of the above packages, you need to disable them +modules=( "!iwconfig" "!wpa_supplicant" ) + +#----------------------------------------------------------------------------- +# DHCP +# DHCP can be provided by dhclient, dhcpcd, pump or udhcpc. +# +# dhclient: emerge net-misc/dhcp +# dhcpcd: emerge net-misc/dhcpcd +# pump: emerge net-misc/pump +# udhcpc: emerge net-misc/udhcp + +# If you have more than one DHCP client installed, you need to specify which +# one to use - otherwise we default to dhcpcd if available. +modules=( "dhclient" ) # to select dhclient over dhcpcd +# +# Notes: +# - All clients send the current hostname to the DHCP server by default +# - dhcpcd does not daemonize when the lease time is infinite +# - udhcp-0.9.3-r3 and earlier do not support getting NTP servers +# - pump does not support getting NIS servers +# - DHCP tends to erase any existing device information - so add +# static addresses after dhcp if you need them +# - dhclient and udhcpc can set other resolv.conf options such as "option" +# and "sortlist"- see the System module for more details + +# Regardless of which DHCP client you prefer, you configure them the +# same way using one of following depending on which interface modules +# you're using. +config_eth0=( "dhcp" ) + +# For passing custom options to dhcpcd use something like the following. This +# example reduces the timeout for retrieving an address from 60 seconds (the +# default) to 10 seconds. +dhcpcd_eth0="-t 10" + +# dhclient, udhcpc and pump don't have many runtime options +# You can pass options to them in a similar manner to dhcpcd though +dhclient_eth0="..." +udhcpc_eth0="..." +pump_eth0="..." + +# GENERIC DHCP OPTIONS +# Set generic DHCP options like so +dhcp_eth0="release nodns nontp nonis nogateway nosendhost" + +# This tells the dhcp client to release it's lease when it stops, not to +# overwrite dns, ntp and nis settings, not to set a default route and not to +# send the current hostname to the dhcp server and when it starts. +# You can use any combination of the above options - the default is not to +# use any of them. + +#----------------------------------------------------------------------------- +# For APIPA support, emerge net-misc/iputils or net-analyzer/arping + +# APIPA is a module that tries to find a free address in the range +# 169.254.0.0-169.254.255.255 by arping a random address in that range on the +# interface. If no reply is found then we assign that address to the interface + +# This is only useful for LANs where there is no DHCP server and you don't +# connect directly to the internet. +config_eth0=( "dhcp" ) +fallback_eth0=( "apipa" ) + +#----------------------------------------------------------------------------- +# ARPING Gateway configuration +# and +# Automatic Private IP Addressing (APIPA) +# For arpingnet / apipa support, emerge net-misc/iputils or net-analyzer/arping +# +# This is a module that tries to find a gateway IP. If it exists then we use +# that gateways configuration for our own. For the configuration variables +# simply ensure that each octet is zero padded and the dots are removed. +# Below is an example. +# +gateways_eth0="192.168.0.1 10.0.0.1" +config_192168000001=( "192.168.0.2/24" ) +routes_192168000001=( "default via 192.168.0.1" ) +dns_servers_192168000001=( "192.168.0.1" ) +config_010000000001=( "10.0.0.254/8" ) +routes_010000000001=( "default via 10.0.0.1" ) +dns_servers_010000000001=( "10.0.0.1" ) + +# We can also specify a specific MAC address for each gateway if different +# networks have the same gateway. +gateways_eth0="192.168.0.1,00:11:22:AA:BB:CC 10.0.0.1,33:44:55:DD:EE:FF" +config_192168000001_001122AABBCC=( "192.168.0.2/24" ) +routes_192168000001_001122AABBCC=( "default via 192.168.0.1" ) +dns_servers_192168000001_001122AABBCC=( "192.168.0.1" ) +config_010000000001_334455DDEEFF=( "10.0.0.254/8" ) +routes_010000000001_334455DDEEFF=( "default via 10.0.0.1" ) +dns_servers_010000000001_334455DDEEFF=( "10.0.0.1" ) + +# If we don't find any gateways (or there are none configured) then we try and +# use APIPA to find a free address in the range 169.254.0.0-169.254.255.255 +# by arping a random address in that range on the interface. If no reply is +# found then we assign that address to the interface. + +# This is only useful for LANs where there is no DHCP server. +config_eth0=( "arping" ) + +# or if no DHCP server can be found +config_eth0=( "dhcp" ) +fallback_eth0=( "arping" ) + +# NOTE: We default to sleeping for 1 second the first time we attempt an +# arping to give the interface time to settle on the LAN. This appears to +# be a good default for most instances, but if not you can alter it here. +arping_sleep=5 +arping_sleep_lan=7 + +# NOTE: We default to waiting 3 seconds to get an arping response. You can +# change the default wait like so. +arping_wait=3 +arping_wait_lan=2 + +#----------------------------------------------------------------------------- +# VLAN (802.1q support) +# For VLAN support, emerge net-misc/vconfig + +# Specify the VLAN numbers for the interface like so +# Please ensure your VLAN IDs are NOT zero-padded +vlans_eth0="1 2" + +# You may not want to assign an IP to the physical interface, but we still +# need it up. +config_eth0=( "null" ) + +# You can also configure the VLAN - see for vconfig man page for more details +vconfig_eth0=( "set_name_type VLAN_PLUS_VID_NO_PAD" ) +vconfig_vlan1=( "set_flag 1" "set_egress_map 2 6" ) +config_vlan1=( "172.16.3.1 netmask 255.255.254.0" ) +config_vlan2=( "172.16.2.1 netmask 255.255.254.0" ) + +# NOTE: Vlans can be configured with a . in their interface names +# When configuring vlans with this name type, you need to replace . with a _ +config_eth0.1=( "dhcp" ) - does not work +config_eth0_1=( "dhcp" ) - does work + +# NOTE: Vlans are controlled by their physical interface and not per vlan +# This means you do not need to create init scripts in /etc/init.d for each +# vlan, you must need to create one for the physical interface. +# If you wish to control the configuration of each vlan through a separate +# script, or wish to rename the vlan interface to something that vconfig +# cannot then you need to do this. +vlan_start_eth0="no" + +# If you do the above then you may want to depend on eth0 like so + RC_NEED_vlan1="net.eth0" +# NOTE: depend functions only work in /etc/conf.d/net +# and not in profile configs such as /etc/conf.d/net.foo + +#----------------------------------------------------------------------------- +# Bonding +# For link bonding/trunking emerge net-misc/ifenslave + +# To bond interfaces together +slaves_bond0="eth0 eth1 eth2" +config_bond0=( "null" ) # You may not want to assign an IP to the bond + +# If any of the slaves require extra configuration - for example wireless or +# ppp devices - we need to depend function on the bonded interfaces +RC_NEED_bond0="net.eth0 net.eth1" + + +#----------------------------------------------------------------------------- +# Classical IP over ATM +# For CLIP support emerge net-dialup/linux-atm + +# Ensure that you have /etc/atmsigd.conf setup correctly +# Now setup each clip interface like so +clip_atm0=( "peer_ip [if.]vpi.vci [opts]" ... ) +# where "peer_ip" is the IP address of a PVC peer (in case of an ATM connection +# with your ISP, your only peer is usually the ISP gateway closest to you), +# "if" is the number of the ATM interface which will carry the PVC, "vpi.vci" +# is the ATM VC address, and "opts" may optionally specify VC parameters like +# qos, pcr, and the like (see "atmarp -s" for further reference). Please also +# note quoting: it is meant to distinguish the VCs you want to create. You may, +# in example, create an atm0 interface to more peers, like this: +clip_atm0=( "1.1.1.254 0.8.35" "1.1.1.253 1.8.35" ) + +# By default, the PVC will use the LLC/SNAP encapsulation. If you rather need a +# null encapsulation (aka "VC mode"), please add the keyword "null" to opts. + + +#----------------------------------------------------------------------------- +# PPP +# For PPP support, emerge net-dialup/ppp +# PPP is used for most dialup connections, including ADSL. +# The older ADSL module is documented below, but you are encouraged to try +# this module first. +# +# You need to create the PPP net script yourself. Make it like so +#ln -s net.lo /etc/init.d/net.ppp0 +# +# We have to instruct ppp0 to actually use ppp +config_ppp0=( "ppp" ) +# +# Each PPP interface requires an interface to use as a "Link" +link_ppp0="/dev/ttyS0" # Most PPP links will use a serial port +link_ppp0="eth0" # PPPoE requires an ethernet interface +link_ppp0="[itf.]vpi.vci" # PPPoA requires the ATM VC's address +link_ppp0="/dev/null" # ISDN links should have this +link_ppp0="pty 'your_link_command'" # PPP links over ssh, rsh, etc +# +# Here you should specify what pppd plugins you want to use +# Available plugins are: pppoe, pppoa, capi, dhcpc, minconn, radius, +# radattr, radrealms and winbind +plugins_ppp0=( + "pppoe" # Required plugin for PPPoE + "pppoa vc-encaps" # Required plugin for PPPoA with an option + "capi" # Required plugin for ISDN +) +# +# PPP requires at least a username. You can optionally set a password here too +# If you don't, then it will use the password specified in /etc/ppp/*-secrets +# against the specified username +username_ppp0='user' +password_ppp0='password' +# NOTE: You can set a blank password like so +password_ppp0= +# +# The PPP daemon has many options you can specify - although there are many +# and may seem daunting, it is recommended that you read the pppd man page +# before enabling any of them +pppd_ppp0=( + "maxfail 0" # WARNING: It's not recommended you use this + # if you don't specify maxfail then we assume 0 + "updetach" # If not set, "/etc/init.d/net.ppp0 start" will return + # immediately, without waiting the link to come up + # for the first time. + # Do not use it for dial-on-demand links! + "debug" # Enables syslog debugging + "noauth" # Do not require the peer to authenticate itself + "defaultroute" # Make this PPP interface the default route + "usepeerdns" # Use the DNS settings provided by PPP + +# On demand options + "demand" # Enable dial on demand + "idle 30" # Link goes down after 30 seconds of inactivity + "10.112.112.112:10.112.112.113" # Phony IP addresses + "ipcp-accept-remote" # Accept the peers idea of remote address + "ipcp-accept-local" # Accept the peers idea of local address + "holdoff 3" # Wait 3 seconds after link dies before re-starting + +# Dead peer detection + "lcp-echo-interval 15" # Send a LCP echo every 15 seconds + "lcp-echo-failure 3" # Make peer dead after 3 consective + # echo-requests + +# Compression options - use these to completely disable compression +# noaccomp noccp nobsdcomp nodeflate nopcomp novj novjccomp + +# Dial-up settings + "lock" # Lock serial port + "115200" # Set the serial port baud rate + "modem crtscts" # Enable hardware flow control + "192.168.0.1:192.168.0.2" # Local and remote IP addresses +) +# +# Dial-up PPP users need to specify at least one telephone number +phone_number_ppp0=( "12345689" ) # Maximum 2 phone numbers are supported +# They will also need a chat script - here's a good one +chat_ppp0=( +# 'ABORT' 'BUSY' +# 'ABORT' 'ERROR' +# 'ABORT' 'NO ANSWER' +# 'ABORT' 'NO CARRIER' +# 'ABORT' 'NO DIALTONE' +# 'ABORT' 'Invalid Login' +# 'ABORT' 'Login incorrect' +# 'TIMEOUT' '5' +# '' 'ATZ' +# 'OK' 'AT' # Put your modem initialization string here +# 'OK' 'ATDT\T' +# 'TIMEOUT' '60' +# 'CONNECT' '' +# 'TIMEOUT' '5' +# '~--' '' +) + +# If the link require extra configuration - for example wireless or +# RFC 268 bridge - we need to depend on the bridge so they get +# configured correctly. +RC_NEED_ppp0="net.nas0" + +#WARNING: if MTU of the PPP interface is less than 1500 and you use this +#machine as a router, you should add the following rule to your firewall +# +#iptables -I FORWARD 1 -p tcp --tcp-flags SYN,RST SYN -j TCPMSS --clamp-mss-to-pmtu + +#----------------------------------------------------------------------------- +# ADSL +# For ADSL support, emerge net-dialup/rp-pppoe +# WARNING: This ADSL module is being deprecated in favour of the PPP module +# above. +# You should make the following settings and also put your +# username/password information in /etc/ppp/pap-secrets + +# Configure the interface to use ADSL +config_eth0=( "adsl" ) + +# You probably won't need to edit /etc/ppp/pppoe.conf if you set this +adsl_user_eth0="my-adsl-username" + +#----------------------------------------------------------------------------- +# ISDN +# For ISDN support, emerge net-dialup/isdn4k-utils +# You should make the following settings and also put your +# username/password information in /etc/ppp/pap-secrets + +# Configure the interface to use ISDN +config_ippp0=( "dhcp" ) +# It's important to specify dhcp if you need it! +config_ippp0=( "192.168.0.1/24" ) +# Otherwise, you can use a static IP + +# NOTE: The interface name must be either ippp or isdn followed by a number + +# You may need this option to set the default route +ipppd_eth0="defaultroute" + +#----------------------------------------------------------------------------- +# MAC changer +# To set a specific MAC address +mac_eth0="00:11:22:33:44:55" + +# For changing MAC addresses using the below, emerge net-analyzer/macchanger +# - to randomize the last 3 bytes only +mac_eth0="random-ending" +# - to randomize between the same physical type of connection (e.g. fibre, +# copper, wireless) , all vendors +mac_eth0="random-samekind" +# - to randomize between any physical type of connection (e.g. fibre, copper, +# wireless) , all vendors +mac_eth0="random-anykind" +# - full randomization - WARNING: some MAC addresses generated by this may NOT +# act as expected +mac_eth0="random-full" +# custom - passes all parameters directly to net-analyzer/macchanger +mac_eth0="some custom set of parameters" + +# You can also set other options based on the MAC address of your network card +# Handy if you use different docking stations with laptops +config_001122334455=( "dhcp" ) + +#----------------------------------------------------------------------------- +# TUN/TAP +# For TUN/TAP support emerge net-misc/openvpn or sys-apps/usermode-utilities +# +# You must specify if we're a tun or tap device. Then you can give it any +# name you like - such as vpn +tuntap_vpn="tun" +config_vpn=( "192.168.0.1/24") + +# Or stick wit the generic names - like tap0 +tuntap_tap0="tap" +config_tap0=( "192.168.0.1/24") + +# For passing custom options to tunctl use something like the following. This +# example sets the owner to adm +tunctl_tun1="-u adm" +# When using openvpn, there are no options + +#----------------------------------------------------------------------------- +# Bridging (802.1d) +# For bridging support emerge net-misc/bridge-utils + +# To add ports to bridge br0 +bridge_br0="eth0 eth1" +# or dynamically add them when the interface comes up +bridge_add_eth0="br0" +bridge_add_eth1="br0" + +# You need to configure the ports to null values so dhcp does not get started +config_eth0=( "null" ) +config_eth1=( "null" ) + +# Finally give the bridge an address - dhcp or a static IP +config_br0=( "dhcp" ) # may not work when adding ports dynamically +config_br0=( "192.168.0.1/24" ) + +# If any of the ports require extra configuration - for example wireless or +# ppp devices - we need to depend on them like so. +RC_NEED_br0="net.eth0 net.eth1" + +# Below is an example of configuring the bridge +# Consult "man brctl" for more details +brctl_br0=( "setfd 0" "sethello 0" "stp off" ) + +#----------------------------------------------------------------------------- +# RFC 2684 Bridge Support +# For RFC 2684 bridge support emerge net-misc/br2684ctl + +# Interface names have to be of the form nas0, nas1, nas2, etc. +# You have to specify a VPI and VCI for the interface like so +br2684ctl_nas0="-a 0.38" # UK VPI and VCI + +# You may want to configure the encapsulation method as well by adding the -e +# option to the command above (may need to be before the -a command) +# -e 0 # LLC (default) +# -e 1 # VC mux + +# Then you can configure the interface as normal +config_nas0=( "192.168.0.1/24" ) + +#----------------------------------------------------------------------------- +# Tunnelling +# WARNING: For tunnelling it is highly recommended that you +# emerge sys-apps/iproute2 +# +# For GRE tunnels +iptunnel_vpn0="mode gre remote 207.170.82.1 key 0xffffffff ttl 255" + +# For IPIP tunnels +iptunnel_vpn0="mode ipip remote 207.170.82.2 ttl 255" + +# To configure the interface +config_vpn0=( "192.168.0.2 pointopoint 192.168.1.2" ) # ifconfig style +config_vpn0=( "192.168.0.2 peer 192.168.1.1" ) # iproute2 style + +# 6to4 Tunnels allow IPv6 to work over IPv4 addresses, provided you +# have a non-private address configured on an interface. + link_6to4="eth0" # Interface to base it's addresses on + config_6to4=( "ip6to4" ) +# You may want to depend on eth0 like so +RC_NEED_6to4="net.eth0" +# To ensure that eth0 is configured before 6to4. Of course, the tunnel could be +# any name and this also works for any configured interface. +# NOTE: If you're not using iproute2 then your 6to4 tunnel has to be called +# sit0 - otherwise use a different name like 6to4 in the example above. + + +#----------------------------------------------------------------------------- +# System +# For configuring system specifics such as domain, dns, ntp and nis servers +# It's rare that you would need todo this, but you can anyway. +# This is most benefit to wireless users who don't use DHCP so they can change +# their configs based on ESSID. See wireless.example for more details + +# To use dns settings such as these, dns_servers_eth0 must be set! +# If you omit the _eth0 suffix, then it applies to all interfaces unless +# overridden by the interface suffix. +dns_domain_eth0="your.domain" +dns_servers_eth0="192.168.0.2 192.168.0.3" +dns_search_eth0="this.domain that.domain" +dns_options_eth0=( "timeout 1" "rotate" ) +dns_sortlist_eth0="130.155.160.0/255.255.240.0 130.155.0.0" +# See the man page for resolv.conf for details about the options and sortlist +# directives + +ntp_servers_eth0="192.168.0.2 192.168.0.3" + +nis_domain_eth0="domain" +nis_servers_eth0="192.168.0.2 192.168.0.3" + +# NOTE: Setting any of these will stamp on the files in question. So if you +# don't specify dns_servers but you do specify dns_domain then no nameservers +# will be listed in /etc/resolv.conf even if there were any there to start +# with. +# If this is an issue for you then maybe you should look into a resolv.conf +# manager like resolvconf-gentoo to manage this file for you. All packages +# that baselayout supports use resolvconf-gentoo if installed. + +#----------------------------------------------------------------------------- +# Cable in/out detection +# Sometimes the cable is in, others it's out. Obviously you don't want to +# restart net.eth0 every time when you plug it in either. +# +# netplug is a package that detects this and requires no extra configuration +# on your part. +# emerge sys-apps/netplug +# or +# emerge sys-apps/ifplugd +# and you're done :) + +# By default we don't wait for netplug/ifplugd to configure the interface. +# If you would like it to wait so that other services now that network is up +# then you can specify a timeout here. +plug_timeout="10" +# A value of 0 means wait forever. + +# If you don't want to use netplug on a specific interface but you have it +# installed, you can disable it for that interface via the modules statement +modules_eth0=( "!netplug" ) +# You can do the same for ifplugd +# +# You can disable them both with the generic plug +modules_eth0=( "!plug" ) + +# To use specific ifplugd options, fex specifying wireless mode +ifplugd_eth0="--api-mode=wlan" +# man ifplugd for more options + +############################################################################## +# ADVANCED CONFIGURATION +# +# Four functions can be defined which will be called surrounding the +# start/stop operations. The functions are called with the interface +# name first so that one function can control multiple adapters. An extra two +# functions can be defined when an interface fails to start or stop. +# +# The return values for the preup and predown functions should be 0 +# (success) to indicate that configuration or deconfiguration of the +# interface can continue. If preup returns a non-zero value, then +# interface configuration will be aborted. If predown returns a +# non-zero value, then the interface will not be allowed to continue +# deconfiguration. +# +# The return values for the postup, postdown, failup and faildown functions are +# ignored since there's nothing to do if they indicate failure. +# +# ${IFACE} is set to the interface being brought up/down +# ${IFVAR} is ${IFACE} converted to variable name bash allows + +#preup() { +# # Test for link on the interface prior to bringing it up. This +# # only works on some network adapters and requires the mii-diag +# # package to be installed. +# if mii-tool "${IFACE}" 2> /dev/null | grep -q 'no link'; then +# ewarn "No link on ${IFACE}, aborting configuration" +# return 1 +# fi +# +# # Test for link on the interface prior to bringing it up. This +# # only works on some network adapters and requires the ethtool +# # package to be installed. +# if ethtool "${IFACE}" | grep -q 'Link detected: no'; then +# ewarn "No link on ${IFACE}, aborting configuration" +# return 1 +# fi +# +# +# # Remember to return 0 on success +# return 0 +#} + +#predown() { +# # The default in the script is to test for NFS root and disallow +# # downing interfaces in that case. Note that if you specify a +# # predown() function you will override that logic. Here it is, in +# # case you still want it... +# if is_net_fs /; then +# eerror "root filesystem is network mounted -- can't stop ${IFACE}" +# return 1 +# fi +# +# # Remember to return 0 on success +# return 0 +#} + +#postup() { +# # This function could be used, for example, to register with a +# # dynamic DNS service. Another possibility would be to +# # send/receive mail once the interface is brought up. + +# # Here is an example that allows the use of iproute rules +# # which have been configured using the rules_eth0 variable. +# #rules_eth0=( +# # "from 24.80.102.112/32 to 192.168.1.0/24 table localnet priority 100" +# # "from 216.113.223.51/32 to 192.168.1.0/24 table localnet priority 100" +# #) +# local x="rules_${IFVAR}[@]" +# local -a rules=( "${!x}" ) +# if [[ -n ${rules} ]] ; then +# einfo "Adding IP policy routing rules" +# eindent +# # Ensure that the kernel supports policy routing +# if ! ip rule list | grep -q "^" ; then +# eerror "You need to enable IP Policy Routing (CONFIG_IP_MULTIPLE_TABLES)" +# eerror "in your kernel to use ip rules" +# else +# for x in "${rules[@]}" ; do +# ebegin "${x}" +# ip rule add ${x} dev "${IFACE}" +# eend $? +# done +# fi +# eoutdent +# # Flush the cache +# ip route flush cache dev "${IFACE}" +# fi + +#} + +#postdown() { +# # Enable Wake-On-LAN for every interface except for lo +# # Probably a good idea to set RC_DOWN_INTERFACE="no" in /etc/conf.d/rc +# # as well ;) +# [[ ${IFACE} != "lo" ]] && ethtool -s "${IFACE}" wol g + +# Automatically erase any ip rules created in the example postup above +# if interface_exists "${IFACE}" ; then +# # Remove any rules for this interface +# local rule +# ip rule list | grep " iif ${IFACE}[ ]*" | { +# while read rule ; do +# rule="${rule#*:}" +# ip rule del ${rule} +# done +# } +# # Flush the route cache +# ip route flush cache dev "${IFACE}" +# fi + +# # Return 0 always +# return 0 +#} + +#failup() { +# # This function is mostly here for completeness... I haven't +# # thought of anything nifty to do with it yet ;-) +#} + +#faildown() { +# # This function is mostly here for completeness... I haven't +# # thought of anything nifty to do with it yet ;-) +#} + +############################################################################## +# FORCING MODULES +# The Big Fat Warning :- If you use module forcing do not complain to us or +# file bugs about it not working! +# +# Loading modules is a slow affair - we have to check each one for the following +# 1) Code sanity +# 2) Has the required package been emerged? +# 3) Has it modified anything? +# 4) Have all the dependant modules been loaded? + +# Then we have to strip out the conflicting modules based on user preference +# and default configuration and sort them into the correct order. +# Finally we check the end result for dependencies. + +# This, of course, takes valuable CPU time so we provide module forcing as a +# means to speed things up. We still do *some* checking but not much. + +# It is essential that you force modules in the correct order and supply all +# the modules you need. You must always supply an interface module - we +# supply ifconfig or iproute2. + +# The Big Fat Warning :- If you use module forcing do not complain to us or +# file bugs about it not working! + +# Now that we've warned you twice, here's how to do it +modules_force=( "ifconfig" ) +modules_force=( "iproute2" "dhcpcd" ) + +# We can also apply this to a specific interface +modules_force_eth1=( "iproute2" ) + +# The below will not work +modules_force=( "dhcpcd" ) +# No interface (ifconfig/iproute2) +modules_force=( "ifconfig" "essidnet" "iwconfig" ) +# Although it will not crash, essidnet will not work as it has to come after +# iwconfig +modules_force=( "iproute2" "ifconfig" ) +# The interface will be setup twice which will cause problems diff --git a/src/settings/plugins/ifnet/tests/nm-system-settings.conf b/src/settings/plugins/ifnet/tests/nm-system-settings.conf new file mode 100644 index 00000000..39bc87b8 --- /dev/null +++ b/src/settings/plugins/ifnet/tests/nm-system-settings.conf @@ -0,0 +1,5 @@ +[main] +plugins=ifnet,keyfile + +[ifnet] +managed=false diff --git a/src/settings/plugins/ifnet/tests/test-ifnet.c b/src/settings/plugins/ifnet/tests/test-ifnet.c new file mode 100644 index 00000000..68f2b928 --- /dev/null +++ b/src/settings/plugins/ifnet/tests/test-ifnet.c @@ -0,0 +1,396 @@ +/* -*- Mode: C; tab-width: 4; indent-tabs-mode: t; c-basic-offset: 4 -*- */ +/* NetworkManager system settings service (ifnet) + * + * Mu Qiao <qiaomuf@gmail.com> + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation; either version 2 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License along + * with this program; if not, write to the Free Software Foundation, Inc., + * 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA. + * + * Copyright (C) 1999-2010 Gentoo Foundation, Inc. + */ + +#include "nm-default.h" + +#include <stdio.h> +#include <string.h> +#include <arpa/inet.h> +#include <stdlib.h> +#include <unistd.h> + +#include "nm-utils.h" + +#include "platform/nm-linux-platform.h" +#include "dhcp/nm-dhcp-manager.h" + +#include "settings/plugins/ifnet/nms-ifnet-net-parser.h" +#include "settings/plugins/ifnet/nms-ifnet-net-utils.h" +#include "settings/plugins/ifnet/nms-ifnet-wpa-parser.h" +#include "settings/plugins/ifnet/nms-ifnet-connection-parser.h" + +#include "nm-test-utils-core.h" + +/* Fake config handling; the values it returns don't matter, so this + * is easier than forcing it to read our own config file, etc. + */ +NMDhcpManager * +nm_dhcp_manager_get (void) +{ + return NULL; +} + +const char * +nm_dhcp_manager_get_config (NMDhcpManager *dhcp_manager) +{ + return "dhclient"; +} + +static void +test_getdata (void) +{ + g_assert (ifnet_get_data ("eth1", "config") && + strcmp (ifnet_get_data ("eth1", "config"), "( \"dhcp\" )") == 0); + g_assert (ifnet_get_data ("ppp0", "username") && + strcmp (ifnet_get_data ("ppp0", "username"), "user") == 0); + g_assert (ifnet_get_data ("ppp0", "password") && + strcmp (ifnet_get_data ("ppp0", "password"), "password") == 0); + g_assert (ifnet_get_global_data ("modules") && + strcmp ("!wpa_supplicant", ifnet_get_global_data ("modules")) == 0); +} + +static void +test_is_static (void) +{ + g_assert (!is_static_ip4 ("eth1")); + g_assert (is_static_ip4 ("eth0")); + g_assert (!is_static_ip6 ("eth0")); +} + +static void +test_has_default_route (void) +{ + g_assert (has_default_ip4_route ("eth0")); + g_assert (has_default_ip6_route ("eth4")); + g_assert (!has_default_ip4_route ("eth5") && + !has_default_ip6_route ("eth5")); +} + +static void +test_has_ip6_address (void) +{ + g_assert (has_ip6_address ("eth2")); + g_assert (!has_ip6_address ("eth0")); +} + +static void +test_is_ip4_address (void) +{ + gchar *address1 = "192.168.4.232/24"; + gchar *address2 = "192.168.100.{1..254}/24"; + gchar *address3 = "192.168.4.2555/24"; + + g_assert (is_ip4_address (address1)); + g_assert (is_ip4_address (address2)); + g_assert (!is_ip4_address (address3)); +} + +static void +test_is_ip6_address (void) +{ + gchar *address1 = "4321:0:1:2:3:4:567:89ac/24"; + + g_assert (is_ip6_address (address1)); +} + +static void +check_ip_block (ip_block * iblock, gchar * ip, guint32 prefix, gchar * gateway) +{ + g_assert_cmpstr (ip, ==, iblock->ip); + g_assert (prefix == iblock->prefix); + g_assert_cmpstr (gateway, ==, iblock->next_hop); +} + +static void +test_convert_ipv4_config_block (void) +{ + ip_block *iblock = convert_ip4_config_block ("eth0"); + ip_block *tmp = iblock; + + g_assert (iblock != NULL); + check_ip_block (iblock, "202.117.16.121", 24, "202.117.16.1"); + iblock = iblock->next; + destroy_ip_block (tmp); + g_assert (iblock != NULL); + check_ip_block (iblock, "192.168.4.121", 24, "202.117.16.1"); + destroy_ip_block (iblock); + + g_test_expect_message ("NetworkManager", G_LOG_LEVEL_MESSAGE, + "*Can't handle IPv4 address*202.117.16.1211*"); + iblock = convert_ip4_config_block ("eth2"); + g_test_assert_expected_messages (); + g_assert (iblock != NULL && iblock->next == NULL); + check_ip_block (iblock, "192.168.4.121", 24, NULL); + destroy_ip_block (iblock); + + g_test_expect_message ("NetworkManager", G_LOG_LEVEL_MESSAGE, + "*missing netmask or prefix*"); + iblock = convert_ip4_config_block ("eth3"); + g_assert (iblock == NULL); +} + +static void +test_convert_ipv4_routes_block (void) +{ + ip_block *iblock = convert_ip4_routes_block ("eth0"); + ip_block *tmp = iblock; + + g_assert (iblock != NULL); + check_ip_block (iblock, "192.168.4.0", 24, "192.168.4.1"); + iblock = iblock->next; + destroy_ip_block (tmp); + g_assert (iblock == NULL); + + iblock = convert_ip4_routes_block ("eth9"); + tmp = iblock; + + g_assert (iblock != NULL); + check_ip_block (iblock, "10.0.0.0", 8, "192.168.0.1"); + iblock = iblock->next; + destroy_ip_block (tmp); + g_assert (iblock == NULL); +} + +static void +test_wpa_parser (void) +{ + const char *value; + + g_assert (exist_ssid ("example")); + + g_assert (exist_ssid ("static-wep-test")); + value = wpa_get_value ("static-wep-test", "key_mgmt"); + g_assert_cmpstr (value, ==, "NONE"); + value = wpa_get_value ("static-wep-test", "wep_key0"); + g_assert_cmpstr (value, ==, "\"abcde\""); + + g_assert (exist_ssid ("leap-example")); + + value = wpa_get_value ("test-with-hash-in-psk", "psk"); + g_assert_cmpstr (value, ==, "\"xjtudlc3731###asdfasdfasdf\""); +} + +static void +test_strip_string (void) +{ + gchar *str = "( \"default via 202.117.16.1\" )"; + gchar *result = g_strdup (str); + gchar *result_b = result; + + result = strip_string (result, '('); + result = strip_string (result, ')'); + result = strip_string (result, '"'); + g_assert_cmpstr (result, ==, "default via 202.117.16.1"); + g_free (result_b); +} + +static void +test_is_unmanaged (void) +{ + g_assert (is_managed ("eth0")); + g_assert (!is_managed ("eth4")); +} + +static void +test_new_connection (void) +{ + GError *error = NULL; + NMConnection *connection; + + g_test_expect_message ("NetworkManager", G_LOG_LEVEL_MESSAGE, + "*Can't handle IPv4 address*202.117.16.1211*"); + g_test_expect_message ("NetworkManager", G_LOG_LEVEL_MESSAGE, + "*Can't handle IPv6 address*202.117.16.1211*"); + connection = ifnet_update_connection_from_config_block ("eth2", NULL, &error); + g_test_assert_expected_messages (); + g_assert (connection != NULL); + g_object_unref (connection); + + connection = ifnet_update_connection_from_config_block ("qiaomuf", NULL, &error); + g_assert (connection != NULL); + g_object_unref (connection); + + connection = ifnet_update_connection_from_config_block ("myxjtu2", NULL, &error); + g_assert (connection != NULL); + g_object_unref (connection); + + connection = ifnet_update_connection_from_config_block ("eth9", NULL, &error); + g_assert (connection != NULL); + g_object_unref (connection); + + connection = ifnet_update_connection_from_config_block ("eth10", NULL, &error); + g_assert (connection != NULL); + g_object_unref (connection); +} + +static void +kill_backup (char **path) +{ + if (*path) { + unlink (*path); + g_free (*path); + *path = NULL; + } +} + +#define NET_GEN_NAME "net.generate" +#define SUP_GEN_NAME "wpa_supplicant.conf.generate" + +static void +test_update_connection (void) +{ + GError *error = NULL; + NMConnection *connection; + gboolean success; + char *backup = NULL; + char *basepath = TEST_IFNET_DIR; + + connection = ifnet_update_connection_from_config_block ("eth0", basepath, &error); + g_assert (connection != NULL); + + success = ifnet_update_parsers_by_connection (connection, "eth0", + NET_GEN_NAME, + SUP_GEN_NAME, + NULL, + &backup, + &error); + kill_backup (&backup); + g_assert (success); + g_object_unref (connection); + + connection = ifnet_update_connection_from_config_block ("0xab3ace", basepath, &error); + g_assert (connection != NULL); + + success = ifnet_update_parsers_by_connection (connection, "0xab3ace", + NET_GEN_NAME, + SUP_GEN_NAME, + NULL, + &backup, + &error); + kill_backup (&backup); + g_assert (success); + g_object_unref (connection); + + unlink (NET_GEN_NAME); + unlink (SUP_GEN_NAME); +} + +static void +test_add_connection (void) +{ + NMConnection *connection; + char *backup = NULL; + const char *basepath = TEST_IFNET_DIR; + + connection = ifnet_update_connection_from_config_block ("eth0", basepath, NULL); + g_assert (ifnet_add_new_connection (connection, NET_GEN_NAME, SUP_GEN_NAME, NULL, &backup, NULL)); + kill_backup (&backup); + g_object_unref (connection); + + g_test_expect_message ("NetworkManager", G_LOG_LEVEL_MESSAGE, + "*Can't handle ipv4 address: brd, missing netmask or prefix*"); + g_test_expect_message ("NetworkManager", G_LOG_LEVEL_MESSAGE, + "*Can't handle ipv4 address: 202.117.16.255, missing netmask or prefix*"); + connection = ifnet_update_connection_from_config_block ("myxjtu2", basepath, NULL); + g_test_assert_expected_messages (); + g_assert (ifnet_add_new_connection (connection, NET_GEN_NAME, SUP_GEN_NAME, NULL, &backup, NULL)); + kill_backup (&backup); + g_object_unref (connection); + + unlink (NET_GEN_NAME); + unlink (SUP_GEN_NAME); +} + +static void +test_delete_connection (void) +{ + GError *error = NULL; + NMConnection *connection; + char *backup = NULL; + + connection = ifnet_update_connection_from_config_block ("eth7", NULL, &error); + g_assert (connection != NULL); + g_assert (ifnet_delete_connection_in_parsers ("eth7", NET_GEN_NAME, SUP_GEN_NAME, &backup)); + kill_backup (&backup); + g_object_unref (connection); + + connection = ifnet_update_connection_from_config_block ("qiaomuf", NULL, &error); + g_assert (connection != NULL); + g_assert (ifnet_delete_connection_in_parsers ("qiaomuf", NET_GEN_NAME, SUP_GEN_NAME, &backup)); + kill_backup (&backup); + g_object_unref (connection); + + unlink (NET_GEN_NAME); + unlink (SUP_GEN_NAME); +} + +static void +test_missing_config (void) +{ + gs_free_error GError *error = NULL; + NMConnection *connection; + + connection = ifnet_update_connection_from_config_block ("eth8", NULL, &error); + g_assert_error (error, NM_SETTINGS_ERROR, NM_SETTINGS_ERROR_INVALID_CONNECTION); + g_assert (connection == NULL && error != NULL); +} + +NMTST_DEFINE (); + +#define TPATH "/settings/plugins/ifnet/" + +int +main (int argc, char **argv) +{ + int ret; + + nm_linux_platform_setup (); + + nmtst_init_assert_logging (&argc, &argv, "WARN", "DEFAULT"); + + ifnet_init (TEST_IFNET_DIR "/net"); + wpa_parser_init (TEST_IFNET_DIR "/wpa_supplicant.conf"); + + g_test_add_func (TPATH "strip-string", test_strip_string); + g_test_add_func (TPATH "is-static", test_is_static); + g_test_add_func (TPATH "has-ip6-address", test_has_ip6_address); + g_test_add_func (TPATH "has-default-route", test_has_default_route); + g_test_add_func (TPATH "get-data", test_getdata); + g_test_add_func (TPATH "is-ip4-address", test_is_ip4_address); + g_test_add_func (TPATH "is-ip6-address", test_is_ip6_address); + g_test_add_func (TPATH "convert-ip4-config", test_convert_ipv4_config_block); + g_test_add_func (TPATH "convert-ip4-routes", test_convert_ipv4_routes_block); + g_test_add_func (TPATH "is-unmanaged", test_is_unmanaged); + g_test_add_func (TPATH "wpa-parser", test_wpa_parser); + g_test_add_func (TPATH "new-connection", test_new_connection); + g_test_add_func (TPATH "update-connection", test_update_connection); + g_test_add_func (TPATH "add-connection", test_add_connection); + g_test_add_func (TPATH "delete-connection", test_delete_connection); + g_test_add_func (TPATH "missing-config", test_missing_config); + + ret = g_test_run (); + + ifnet_destroy (); + wpa_parser_destroy (); + + return ret; +} diff --git a/src/settings/plugins/ifnet/tests/test_ca_cert.pem b/src/settings/plugins/ifnet/tests/test_ca_cert.pem new file mode 100644 index 00000000..ef1be20d --- /dev/null +++ b/src/settings/plugins/ifnet/tests/test_ca_cert.pem @@ -0,0 +1,27 @@ +-----BEGIN CERTIFICATE----- +MIIEjzCCA3egAwIBAgIJAOvnZPt59yIZMA0GCSqGSIb3DQEBBQUAMIGLMQswCQYD +VQQGEwJVUzESMBAGA1UECBMJQmVya3NoaXJlMRAwDgYDVQQHEwdOZXdidXJ5MRcw +FQYDVQQKEw5NeSBDb21wYW55IEx0ZDEQMA4GA1UECxMHVGVzdGluZzENMAsGA1UE +AxMEdGVzdDEcMBoGCSqGSIb3DQEJARYNdGVzdEB0ZXN0LmNvbTAeFw0wOTAzMTAx +NTEyMTRaFw0xOTAzMDgxNTEyMTRaMIGLMQswCQYDVQQGEwJVUzESMBAGA1UECBMJ +QmVya3NoaXJlMRAwDgYDVQQHEwdOZXdidXJ5MRcwFQYDVQQKEw5NeSBDb21wYW55 +IEx0ZDEQMA4GA1UECxMHVGVzdGluZzENMAsGA1UEAxMEdGVzdDEcMBoGCSqGSIb3 +DQEJARYNdGVzdEB0ZXN0LmNvbTCCASIwDQYJKoZIhvcNAQEBBQADggEPADCCAQoC +ggEBAKot9j+/+CX1/gZLgJHIXCRgCItKLGnf7qGbgqB9T2ACBqR0jllKWwDKrcWU +xjXNIc+GF9Wnv+lX6G0Okn4Zt3/uRNobL+2b/yOF7M3Td3/9W873zdkQQX930YZc +Rr8uxdRPP5bxiCgtcw632y21sSEbG9mjccAUnV/0jdvfmMNj0i8gN6E0fMBiJ9S3 +FkxX/KFvt9JWE9CtoyL7ki7UIDq+6vj7Gd5N0B3dOa1y+rRHZzKlJPcSXQSEYUS4 +HmKDwiKSVahft8c4tDn7KPi0vex91hlgZVd3usL2E/Vq7o5D9FAZ5kZY0AdFXwdm +J4lO4Mj7ac7GE4vNERNcXVIX59sCAwEAAaOB8zCB8DAdBgNVHQ4EFgQUuDU3Mr7P +T3n1e3Sy8hBauoDFahAwgcAGA1UdIwSBuDCBtYAUuDU3Mr7PT3n1e3Sy8hBauoDF +ahChgZGkgY4wgYsxCzAJBgNVBAYTAlVTMRIwEAYDVQQIEwlCZXJrc2hpcmUxEDAO +BgNVBAcTB05ld2J1cnkxFzAVBgNVBAoTDk15IENvbXBhbnkgTHRkMRAwDgYDVQQL +EwdUZXN0aW5nMQ0wCwYDVQQDEwR0ZXN0MRwwGgYJKoZIhvcNAQkBFg10ZXN0QHRl +c3QuY29tggkA6+dk+3n3IhkwDAYDVR0TBAUwAwEB/zANBgkqhkiG9w0BAQUFAAOC +AQEAVRG4aALIvCXCiKfe7K+iJxjBVRDFPEf7JWA9LGgbFOn6pNvbxonrR+0BETdc +JV1ET4ct2xsE7QNFIkp9GKRC+6J32zCo8qtLCD5+v436r8TUG2/t2JRMkb9I2XVT +p7RJoot6M0Ltf8KNQUPYh756xmKZ4USfQUwc58MOSDGY8VWEXJOYij9Pf0e0c52t +qiCEjXH7uXiS8Pgq9TYm7AkWSOrglYhSa83x0f8mtT8Q15nBESIHZ6o8FAS2bBgn +B0BkrKRjtBUkuJG3vTox+bYINh2Gxi1JZHWSV1tN5z3hd4VFcKqanW5OgQwToBqp +3nniskIjbH0xjgZf/nVMyLnjxg== +-----END CERTIFICATE----- diff --git a/src/settings/plugins/ifnet/tests/wpa_supplicant.conf b/src/settings/plugins/ifnet/tests/wpa_supplicant.conf new file mode 100644 index 00000000..917d495d --- /dev/null +++ b/src/settings/plugins/ifnet/tests/wpa_supplicant.conf @@ -0,0 +1,70 @@ +# Only WPA-PSK is used. Any valid cipher combination is accepted. +network={ + ssid="example" + proto=WPA + key_mgmt=WPA-PSK + pairwise=CCMP TKIP + group=CCMP TKIP WEP104 WEP40 + psk=06b4be19da289f475aa46a33cb793029d4ab3db7a23ee92382eb0106c72ac7bb + priority=2 +} + +# LEAP with dynamic WEP keys +network={ + ssid="leap-example" + key_mgmt=IEEE8021X + eap=LEAP + identity="user" + password="foobar" +} + +# Shared WEP key connection (no WPA, no IEEE 802.1X) +network={ + ssid="static-wep-test" + key_mgmt=NONE + wep_key0="abcde" + wep_key1=0102030405 + wep_key2="1234567890123" + wep_tx_keyidx=0 + priority=5 +} + +# Wildcard match for SSID (plaintext APs only). This example select any +# open AP regardless of its SSID. +network={ + key_mgmt=NONE +} + +network={ + ssid="myxjtu2" + scan_ssid=1 + key_mgmt=WPA-PSK + psk="xjtudlc3731" + disabled=0 + key_mgmt=NONE + wep_key0="12345" + wep_key1=1234567890 + wep_key2="zxcvb" + wep_tx_keyidx=1 + auth_alg=OPEN + mode=1 +} + +network={ + ssid=ab3ace + key_mgmt=WPA-EAP + eap=TTLS + identity="user@example.com" + anonymous_identity="anonymous@example.com" + password="foobar" + ca_cert="test_ca_cert.pem" + phase2="auth=CHAP" + priority=20 +} + +network={ + ssid="test-with-hash-in-psk" + key_mgmt=WPA-PSK + psk="xjtudlc3731###asdfasdfasdf" +} + diff --git a/src/settings/plugins/ifupdown/meson.build b/src/settings/plugins/ifupdown/meson.build deleted file mode 100644 index 87b5bea2..00000000 --- a/src/settings/plugins/ifupdown/meson.build +++ /dev/null @@ -1,53 +0,0 @@ -sources = files( - 'nms-ifupdown-interface-parser.c', - 'nms-ifupdown-parser.c' -) - -deps = [ - libudev_dep, - nm_dep -] - -cflags = '-DSYSCONFDIR="@0@"'.format(nm_sysconfdir) - -libnms_ifupdown_core = static_library( - 'nms-ifupdown-core', - sources: sources, - dependencies: deps, - c_args: cflags -) - -sources = files( - 'nms-ifupdown-connection.c', - 'nms-ifupdown-plugin.c' -) - -libnm_settings_plugin_ifupdown = shared_module( - 'nm-settings-plugin-ifupdown', - sources: sources, - dependencies: deps, - c_args: cflags, - link_with: libnms_ifupdown_core, - link_args: ldflags_linker_script_settings, - link_depends: linker_script_settings, - install: true, - install_dir: nm_pkglibdir -) - -core_plugins += libnm_settings_plugin_ifupdown - -# FIXME: check_so_symbols replacement -''' -run_target( - 'check-local-symbols-settings-ifupdown', - command: [check_so_symbols, libnm_settings_plugin_ifupdown.full_path()], - depends: libnm_settings_plugin_ifupdown -) - -check-local-symbols-settings-ifupdown: src/settings/plugins/ifupdown/libnm-settings-plugin-ifupdown.la - $(call check_so_symbols,$(builddir)/src/settings/plugins/ifupdown/.libs/libnm-settings-plugin-ifupdown.so) -''' - -if enable_tests - subdir('tests') -endif diff --git a/src/settings/plugins/ifupdown/nms-ifupdown-interface-parser.c b/src/settings/plugins/ifupdown/nms-ifupdown-interface-parser.c index 014998a6..8421afc2 100644 --- a/src/settings/plugins/ifupdown/nms-ifupdown-interface-parser.c +++ b/src/settings/plugins/ifupdown/nms-ifupdown-interface-parser.c @@ -129,8 +129,8 @@ _recursive_ifparser (const char *eni_file, int quiet) while (!feof(inp)) { - char *token[128]; /* 255 chars can only be split into 127 tokens */ - char value[255]; /* large enough to join previously split tokens */ + char *token[128]; /* 255 chars can only be split into 127 tokens */ + char value[255]; /* large enough to join previously split tokens */ char *safeptr; int toknum; int len = 0; @@ -169,7 +169,7 @@ _recursive_ifparser (const char *eni_file, int quiet) continue; } -#define SPACES " \t" +#define SPACES " \t" /* tokenize input; */ for (toknum = 0, token[toknum] = strtok_r(line, SPACES, &safeptr); token[toknum] != NULL; diff --git a/src/settings/plugins/ifupdown/tests/meson.build b/src/settings/plugins/ifupdown/tests/meson.build deleted file mode 100644 index 7f210034..00000000 --- a/src/settings/plugins/ifupdown/tests/meson.build +++ /dev/null @@ -1,17 +0,0 @@ -test_unit = 'test-ifupdown' - -cflags = '-DTEST_ENI_DIR="@0@"'.format(meson.current_source_dir()) - -exe = executable( - test_unit, - test_unit + '.c', - dependencies: test_nm_dep, - c_args: cflags, - link_with: libnms_ifupdown_core -) - -test( - 'ifupdown/' + test_unit, - test_script, - args: test_args + [exe.full_path()] -) diff --git a/src/settings/plugins/ifupdown/tests/test-ifupdown.c b/src/settings/plugins/ifupdown/tests/test-ifupdown.c index 56515438..d037b8a6 100644 --- a/src/settings/plugins/ifupdown/tests/test-ifupdown.c +++ b/src/settings/plugins/ifupdown/tests/test-ifupdown.c @@ -168,7 +168,7 @@ dump_blocks (void) for (n = ifparser_getfirst (); n != NULL; n = n->next) { if_data *m; - // each block start with its type & name + // each block start with its type & name // (single quotes used to show typ & name baoundaries) g_print("'%s' '%s'\n", n->type, n->name); diff --git a/src/settings/plugins/keyfile/nms-keyfile-plugin.c b/src/settings/plugins/keyfile/nms-keyfile-plugin.c index df2c05b7..e6299d1e 100644 --- a/src/settings/plugins/keyfile/nms-keyfile-plugin.c +++ b/src/settings/plugins/keyfile/nms-keyfile-plugin.c @@ -436,7 +436,7 @@ read_connections (NMSettingsPlugin *config) return; } - alive_connections = g_hash_table_new (nm_direct_hash, NULL); + alive_connections = g_hash_table_new (NULL, NULL); filenames = g_ptr_array_new_with_free_func (g_free); while ((item = g_dir_read_name (dir))) { diff --git a/src/settings/plugins/keyfile/tests/keyfiles/Test_Wired_Connection b/src/settings/plugins/keyfile/tests/keyfiles/Test_Wired_Connection index 1e62f4b3..5cb4d726 100644 --- a/src/settings/plugins/keyfile/tests/keyfiles/Test_Wired_Connection +++ b/src/settings/plugins/keyfile/tests/keyfiles/Test_Wired_Connection @@ -15,7 +15,7 @@ mtu=1400 [ipv4] method=manual -dns=4.2.2.1;bogus;4.2.2.2; +dns=4.2.2.1;4.2.2.2; addresses1=192.168.0.5;24;192.168.0.1; addresses2=1.2.3.4;16;1.2.1.1; address=2.3.4.5/24,2.3.4.6 @@ -26,21 +26,15 @@ routes1=1.2.3.0/24,2.3.4.8,99 route=5.6.7.8/32 routes2=1.1.1.2/12, routes3=1.1.1.3/13,, -routes7=1.1.1.7/17,0.0.0.0 routes4=1.1.1.4/14,2.2.2.4 -address30=1.2.3.130/24 routes5=1.1.1.5/15,2.2.2.5, routes6=1.1.1.6/16,2.2.2.6,0 +routes7=1.1.1.7/17,0.0.0.0 routes8=1.1.1.8/18,0.0.0.0, routes9=1.1.1.9/19,0.0.0.0,0 -route10=1.1.1.10/21,,0 routes10=1.1.1.10/20,,0 routes11=1.1.1.11/21,,21 routes11_options=cwnd=10,lock-cwnd=true,mtu=1430,src=7.7.7.7 -address30=1.2.3.30/24 -addresses30=1.2.3.30/25 -addresses31=1.2.3.31/25 -address31=1.2.3.31/24 ignore-auto-routes=false ignore-auto-dns=false diff --git a/src/settings/plugins/keyfile/tests/meson.build b/src/settings/plugins/keyfile/tests/meson.build deleted file mode 100644 index 54b4ee0d..00000000 --- a/src/settings/plugins/keyfile/tests/meson.build +++ /dev/null @@ -1,21 +0,0 @@ -test_unit = 'test-keyfile' - -test_keyfiles_dir = join_paths(meson.current_source_dir(), 'keyfiles') - -cflags = [ - '-DTEST_KEYFILES_DIR="@0@"'.format(test_keyfiles_dir), - '-DTEST_SCRATCH_DIR="@0@"'.format(test_keyfiles_dir) -] - -exe = executable( - test_unit, - test_unit + '.c', - dependencies: test_nm_dep, - c_args: cflags -) - -test( - 'keyfile/' + test_unit, - test_script, - args: test_args + [exe.full_path()] -) diff --git a/src/settings/plugins/keyfile/tests/test-keyfile.c b/src/settings/plugins/keyfile/tests/test-keyfile.c index b46475e8..f27efddd 100644 --- a/src/settings/plugins/keyfile/tests/test-keyfile.c +++ b/src/settings/plugins/keyfile/tests/test-keyfile.c @@ -231,21 +231,34 @@ test_read_valid_wired_connection (void) char expected_mac_address[ETH_ALEN] = { 0x00, 0x11, 0x22, 0x33, 0x44, 0x55 }; gboolean success; - NMTST_EXPECT_NM_INFO ("*ipv4.addresses:*semicolon at the end*addresses1*"); - NMTST_EXPECT_NM_INFO ("*ipv4.addresses:*semicolon at the end*addresses2*"); - NMTST_EXPECT_NM_WARN ("*missing prefix length*address4*"); - NMTST_EXPECT_NM_WARN ("*missing prefix length*address5*"); - NMTST_EXPECT_NM_WARN ("*ipv4.dns: ignoring invalid DNS server IPv4 address 'bogus'*"); - NMTST_EXPECT_NM_INFO ("*ipv4.routes*semicolon at the end*routes2*"); - NMTST_EXPECT_NM_INFO ("*ipv4.routes*semicolon at the end*routes3*"); - NMTST_EXPECT_NM_INFO ("*ipv4.routes*semicolon at the end*routes5*"); - NMTST_EXPECT_NM_INFO ("*ipv4.routes*semicolon at the end*routes8*"); - NMTST_EXPECT_NM_WARN ("*missing prefix length*address4*"); - NMTST_EXPECT_NM_INFO ("*ipv6.address*semicolon at the end*address5*"); - NMTST_EXPECT_NM_WARN ("*missing prefix length*address5*"); - NMTST_EXPECT_NM_INFO ("*ipv6.address*semicolon at the end*address7*"); - NMTST_EXPECT_NM_INFO ("*ipv6.routes*semicolon at the end*routes1*"); - NMTST_EXPECT_NM_INFO ("*ipv6.route*semicolon at the end*route6*"); + g_test_expect_message ("NetworkManager", G_LOG_LEVEL_INFO, + "*ipv4.addresses:*semicolon at the end*addresses1*"); + g_test_expect_message ("NetworkManager", G_LOG_LEVEL_INFO, + "*ipv4.addresses:*semicolon at the end*addresses2*"); + g_test_expect_message ("NetworkManager", G_LOG_LEVEL_MESSAGE, + "*missing prefix length*address4*"); + g_test_expect_message ("NetworkManager", G_LOG_LEVEL_MESSAGE, + "*missing prefix length*address5*"); + g_test_expect_message ("NetworkManager", G_LOG_LEVEL_INFO, + "*ipv4.routes*semicolon at the end*routes2*"); + g_test_expect_message ("NetworkManager", G_LOG_LEVEL_INFO, + "*ipv4.routes*semicolon at the end*routes3*"); + g_test_expect_message ("NetworkManager", G_LOG_LEVEL_INFO, + "*ipv4.routes*semicolon at the end*routes5*"); + g_test_expect_message ("NetworkManager", G_LOG_LEVEL_INFO, + "*ipv4.routes*semicolon at the end*routes8*"); + g_test_expect_message ("NetworkManager", G_LOG_LEVEL_MESSAGE, + "*missing prefix length*address4*"); + g_test_expect_message ("NetworkManager", G_LOG_LEVEL_INFO, + "*ipv6.address*semicolon at the end*address5*"); + g_test_expect_message ("NetworkManager", G_LOG_LEVEL_MESSAGE, + "*missing prefix length*address5*"); + g_test_expect_message ("NetworkManager", G_LOG_LEVEL_INFO, + "*ipv6.address*semicolon at the end*address7*"); + g_test_expect_message ("NetworkManager", G_LOG_LEVEL_INFO, + "*ipv6.routes*semicolon at the end*routes1*"); + g_test_expect_message ("NetworkManager", G_LOG_LEVEL_INFO, + "*ipv6.route*semicolon at the end*route6*"); connection = nms_keyfile_reader_from_file (TEST_KEYFILES_DIR "/Test_Wired_Connection", &error); g_assert_no_error (error); g_test_assert_expected_messages (); @@ -281,23 +294,19 @@ test_read_valid_wired_connection (void) g_assert_cmpstr (nm_setting_ip_config_get_dns (s_ip4, 1), ==, "4.2.2.2"); /* IPv4 addresses */ - g_assert_cmpint (nm_setting_ip_config_get_num_addresses (s_ip4), ==, 10); + g_assert_cmpint (nm_setting_ip_config_get_num_addresses (s_ip4), ==, 6); check_ip_address (s_ip4, 0, "2.3.4.5", 24); check_ip_address (s_ip4, 1, "192.168.0.5", 24); check_ip_address (s_ip4, 2, "1.2.3.4", 16); check_ip_address (s_ip4, 3, "3.4.5.6", 16); check_ip_address (s_ip4, 4, "4.5.6.7", 24); check_ip_address (s_ip4, 5, "5.6.7.8", 24); - check_ip_address (s_ip4, 6, "1.2.3.30", 24); - check_ip_address (s_ip4, 7, "1.2.3.30", 25); - check_ip_address (s_ip4, 8, "1.2.3.31", 24); - check_ip_address (s_ip4, 9, "1.2.3.31", 25); /* IPv4 gateway */ g_assert_cmpstr (nm_setting_ip_config_get_gateway (s_ip4), ==, "2.3.4.6"); /* IPv4 routes */ - g_assert_cmpint (nm_setting_ip_config_get_num_routes (s_ip4), ==, 13); + g_assert_cmpint (nm_setting_ip_config_get_num_routes (s_ip4), ==, 12); check_ip_route (s_ip4, 0, "5.6.7.8", 32, NULL, -1); check_ip_route (s_ip4, 1, "1.2.3.0", 24, "2.3.4.8", 99); check_ip_route (s_ip4, 2, "1.1.1.2", 12, NULL, -1); @@ -308,12 +317,11 @@ test_read_valid_wired_connection (void) check_ip_route (s_ip4, 7, "1.1.1.7", 17, NULL, -1); check_ip_route (s_ip4, 8, "1.1.1.8", 18, NULL, -1); check_ip_route (s_ip4, 9, "1.1.1.9", 19, NULL, 0); - check_ip_route (s_ip4, 10, "1.1.1.10", 21, NULL, 0); - check_ip_route (s_ip4, 11, "1.1.1.10", 20, NULL, 0); - check_ip_route (s_ip4, 12, "1.1.1.11", 21, NULL, 21); + check_ip_route (s_ip4, 10, "1.1.1.10", 20, NULL, 0); + check_ip_route (s_ip4, 11, "1.1.1.11", 21, NULL, 21); /* Route attributes */ - route = nm_setting_ip_config_get_route (s_ip4, 12); + route = nm_setting_ip_config_get_route (s_ip4, 11); g_assert (route); nmtst_assert_route_attribute_uint32 (route, NM_IP_ROUTE_ATTRIBUTE_CWND, 10); @@ -641,9 +649,12 @@ test_read_wired_mac_case (void) char expected_mac_address[ETH_ALEN] = { 0x00, 0x11, 0xaa, 0xbb, 0xcc, 0x55 }; gboolean success; - NMTST_EXPECT_NM_INFO ("*ipv4.addresses*semicolon at the end*addresses1*"); - NMTST_EXPECT_NM_INFO ("*ipv4.addresses*semicolon at the end*addresses2*"); - NMTST_EXPECT_NM_INFO ("*ipv6.routes*semicolon at the end*routes1*"); + g_test_expect_message ("NetworkManager", G_LOG_LEVEL_INFO, + "*ipv4.addresses*semicolon at the end*addresses1*"); + g_test_expect_message ("NetworkManager", G_LOG_LEVEL_INFO, + "*ipv4.addresses*semicolon at the end*addresses2*"); + g_test_expect_message ("NetworkManager", G_LOG_LEVEL_INFO, + "*ipv6.routes*semicolon at the end*routes1*"); connection = nms_keyfile_reader_from_file (TEST_KEYFILES_DIR "/Test_Wired_Connection_MAC_Case", NULL); g_test_assert_expected_messages (); g_assert (connection); @@ -1404,8 +1415,10 @@ test_read_wired_8021x_tls_blob_connection (void) gboolean success; GBytes *blob; - NMTST_EXPECT_NM_WARN ("keyfile: 802-1x.client-cert: certificate or key file '/CASA/dcbw/Desktop/certinfra/client.pem' does not exist*"); - NMTST_EXPECT_NM_WARN ("keyfile: 802-1x.private-key: certificate or key file '/CASA/dcbw/Desktop/certinfra/client.pem' does not exist*"); + g_test_expect_message ("NetworkManager", G_LOG_LEVEL_MESSAGE, + "*<warn> * keyfile: 802-1x.client-cert: certificate or key file '/CASA/dcbw/Desktop/certinfra/client.pem' does not exist*"); + g_test_expect_message ("NetworkManager", G_LOG_LEVEL_MESSAGE, + "*<warn> * keyfile: 802-1x.private-key: certificate or key file '/CASA/dcbw/Desktop/certinfra/client.pem' does not exist*"); connection = nms_keyfile_reader_from_file (TEST_KEYFILES_DIR "/Test_Wired_TLS_Blob", &error); g_assert_no_error (error); g_assert (connection); @@ -1434,7 +1447,8 @@ test_read_wired_8021x_tls_blob_connection (void) g_assert_cmpint (nm_setting_802_1x_get_ca_cert_scheme (s_8021x), ==, NM_SETTING_802_1X_CK_SCHEME_BLOB); /* Make sure it's not a path, since it's a blob */ - NMTST_EXPECT_LIBNM_CRITICAL (NMTST_G_RETURN_MSG (scheme == NM_SETTING_802_1X_CK_SCHEME_PATH)); + g_test_expect_message ("libnm", G_LOG_LEVEL_CRITICAL, + NMTST_G_RETURN_MSG (scheme == NM_SETTING_802_1X_CK_SCHEME_PATH)); tmp = nm_setting_802_1x_get_ca_cert_path (s_8021x); g_test_assert_expected_messages (); g_assert (tmp == NULL); @@ -1462,7 +1476,8 @@ test_read_wired_8021x_tls_bad_path_connection (void) char *tmp2; gboolean success; - NMTST_EXPECT_NM_WARN ("*does not exist*"); + g_test_expect_message ("NetworkManager", G_LOG_LEVEL_MESSAGE, + "*does not exist*"); connection = nms_keyfile_reader_from_file (TEST_KEYFILES_DIR "/Test_Wired_TLS_Path_Missing", &error); g_test_assert_expected_messages (); g_assert_no_error (error); @@ -1515,9 +1530,12 @@ test_read_wired_8021x_tls_old_connection (void) const char *tmp; gboolean success; - NMTST_EXPECT_NM_WARN ("keyfile: 802-1x.ca-cert: certificate or key file '/CASA/dcbw/Desktop/certinfra/CA/eaptest_ca_cert.pem' does not exist*"); - NMTST_EXPECT_NM_WARN ("keyfile: 802-1x.client-cert: certificate or key file '/CASA/dcbw/Desktop/certinfra/client.pem' does not exist*"); - NMTST_EXPECT_NM_WARN ("keyfile: 802-1x.private-key: certificate or key file '/CASA/dcbw/Desktop/certinfra/client.pem' does not exist*"); + g_test_expect_message ("NetworkManager", G_LOG_LEVEL_MESSAGE, + "*<warn> * keyfile: 802-1x.ca-cert: certificate or key file '/CASA/dcbw/Desktop/certinfra/CA/eaptest_ca_cert.pem' does not exist*"); + g_test_expect_message ("NetworkManager", G_LOG_LEVEL_MESSAGE, + "*<warn> * keyfile: 802-1x.client-cert: certificate or key file '/CASA/dcbw/Desktop/certinfra/client.pem' does not exist*"); + g_test_expect_message ("NetworkManager", G_LOG_LEVEL_MESSAGE, + "*<warn> * keyfile: 802-1x.private-key: certificate or key file '/CASA/dcbw/Desktop/certinfra/client.pem' does not exist*"); connection = nms_keyfile_reader_from_file (TEST_KEYFILES_DIR "/Test_Wired_TLS_Old", &error); g_assert_no_error (error); g_assert (connection); diff --git a/src/settings/plugins/meson.build b/src/settings/plugins/meson.build deleted file mode 100644 index a1aa7823..00000000 --- a/src/settings/plugins/meson.build +++ /dev/null @@ -1,15 +0,0 @@ -if enable_ibft - subdir('ibft') -endif - -if enable_ifcfg_rh - subdir('ifcfg-rh') -endif - -if enable_ifupdown - subdir('ifupdown') -endif - -if enable_tests - subdir('keyfile/tests') -endif diff --git a/src/supplicant/nm-supplicant-config.c b/src/supplicant/nm-supplicant-config.c index 14f5cac8..16e7851a 100644 --- a/src/supplicant/nm-supplicant-config.c +++ b/src/supplicant/nm-supplicant-config.c @@ -47,8 +47,6 @@ typedef struct { guint32 ap_scan; gboolean fast_required; gboolean dispose_has_run; - gboolean support_pmf; - gboolean support_fils; } NMSupplicantConfigPrivate; struct _NMSupplicantConfig { @@ -67,18 +65,9 @@ G_DEFINE_TYPE (NMSupplicantConfig, nm_supplicant_config, G_TYPE_OBJECT) /*****************************************************************************/ NMSupplicantConfig * -nm_supplicant_config_new (gboolean support_pmf, gboolean support_fils) +nm_supplicant_config_new (void) { - NMSupplicantConfigPrivate *priv; - NMSupplicantConfig *self; - - self = g_object_new (NM_TYPE_SUPPLICANT_CONFIG, NULL); - priv = NM_SUPPLICANT_CONFIG_GET_PRIVATE (self); - - priv->support_pmf = support_pmf; - priv->support_fils = support_fils; - - return self; + return g_object_new (NM_TYPE_SUPPLICANT_CONFIG, NULL); } static void @@ -380,6 +369,7 @@ nm_supplicant_config_add_setting_macsec (NMSupplicantConfig * self, NMSettingMacsec * setting, GError **error) { + NMSupplicantConfigPrivate *priv; gs_unref_bytes GBytes *bytes = NULL; const char *value; char buf[32]; @@ -389,6 +379,8 @@ nm_supplicant_config_add_setting_macsec (NMSupplicantConfig * self, g_return_val_if_fail (setting != NULL, FALSE); g_return_val_if_fail (!error || !*error, FALSE); + priv = NM_SUPPLICANT_CONFIG_GET_PRIVATE (self); + if (!nm_supplicant_config_add_option (self, "macsec_policy", "1", -1, NULL, error)) return FALSE; @@ -744,10 +736,8 @@ nm_supplicant_config_add_setting_wireless_security (NMSupplicantConfig *self, const char *con_uuid, guint32 mtu, NMSettingWirelessSecurityPmf pmf, - NMSettingWirelessSecurityFils fils, GError **error) { - NMSupplicantConfigPrivate *priv = NM_SUPPLICANT_CONFIG_GET_PRIVATE (self); const char *key_mgmt, *key_mgmt_conf, *auth_alg; const char *psk; @@ -756,37 +746,18 @@ nm_supplicant_config_add_setting_wireless_security (NMSupplicantConfig *self, g_return_val_if_fail (con_uuid != NULL, FALSE); g_return_val_if_fail (!error || !*error, FALSE); - /* Check if we actually support FILS */ - if (!priv->support_fils) { - if (fils == NM_SETTING_WIRELESS_SECURITY_FILS_REQUIRED) { - g_set_error_literal (error, NM_SUPPLICANT_ERROR, NM_SUPPLICANT_ERROR_CONFIG, - "Supplicant does not support FILS"); - return FALSE; - } else if (fils == NM_SETTING_WIRELESS_SECURITY_FILS_OPTIONAL) - fils = NM_SETTING_WIRELESS_SECURITY_FILS_DISABLE; - } - key_mgmt = key_mgmt_conf = nm_setting_wireless_security_get_key_mgmt (setting); - if (nm_streq (key_mgmt, "wpa-psk")) { - if (priv->support_pmf) + if (pmf == NM_SETTING_WIRELESS_SECURITY_PMF_OPTIONAL) { + if (nm_streq (key_mgmt_conf, "wpa-psk")) key_mgmt_conf = "wpa-psk wpa-psk-sha256"; - } else if (nm_streq (key_mgmt, "wpa-eap")) { - switch (fils) { - case NM_SETTING_WIRELESS_SECURITY_FILS_OPTIONAL: - key_mgmt_conf = priv->support_pmf - ? "wpa-eap wpa-eap-sha256 fils-sha256 fils-sha384" - : "wpa-eap fils-sha256 fils-sha384"; - break; - case NM_SETTING_WIRELESS_SECURITY_FILS_REQUIRED: - key_mgmt_conf = "fils-sha256 fils-sha384"; - break; - default: - if (priv->support_pmf) - key_mgmt_conf = "wpa-eap wpa-eap-sha256"; - break; - } + else if (nm_streq (key_mgmt_conf, "wpa-eap")) + key_mgmt_conf = "wpa-eap wpa-eap-sha256"; + } else if (pmf == NM_SETTING_WIRELESS_SECURITY_PMF_REQUIRED) { + if (nm_streq (key_mgmt_conf, "wpa-psk")) + key_mgmt_conf = "wpa-psk-sha256"; + else if (nm_streq (key_mgmt_conf, "wpa-eap")) + key_mgmt_conf = "wpa-eap-sha256"; } - if (!add_string_val (self, key_mgmt_conf, "key_mgmt", TRUE, NULL, error)) return FALSE; @@ -832,20 +803,6 @@ nm_supplicant_config_add_setting_wireless_security (NMSupplicantConfig *self, } } - /* Don't try to enable PMF on non-WPA networks */ - if (!NM_IN_STRSET (key_mgmt, "wpa-eap", "wpa-psk")) - pmf = NM_SETTING_WIRELESS_SECURITY_PMF_DISABLE; - - /* Check if we actually support PMF */ - if (!priv->support_pmf) { - if (pmf == NM_SETTING_WIRELESS_SECURITY_PMF_REQUIRED) { - g_set_error_literal (error, NM_SUPPLICANT_ERROR, NM_SUPPLICANT_ERROR_CONFIG, - "Supplicant does not support PMF"); - return FALSE; - } else if (pmf == NM_SETTING_WIRELESS_SECURITY_PMF_OPTIONAL) - pmf = NM_SETTING_WIRELESS_SECURITY_PMF_DISABLE; - } - /* Only WPA-specific things when using WPA */ if ( !strcmp (key_mgmt, "wpa-none") || !strcmp (key_mgmt, "wpa-psk") diff --git a/src/supplicant/nm-supplicant-config.h b/src/supplicant/nm-supplicant-config.h index f6c845a3..d90d82b8 100644 --- a/src/supplicant/nm-supplicant-config.h +++ b/src/supplicant/nm-supplicant-config.h @@ -40,7 +40,7 @@ typedef struct _NMSupplicantConfigClass NMSupplicantConfigClass; GType nm_supplicant_config_get_type (void); -NMSupplicantConfig *nm_supplicant_config_new (gboolean support_pmf, gboolean support_fils); +NMSupplicantConfig *nm_supplicant_config_new (void); guint32 nm_supplicant_config_get_ap_scan (NMSupplicantConfig *self); @@ -65,7 +65,6 @@ gboolean nm_supplicant_config_add_setting_wireless_security (NMSupplicantConfig const char *con_uuid, guint32 mtu, NMSettingWirelessSecurityPmf pmf, - NMSettingWirelessSecurityFils fils, GError **error); gboolean nm_supplicant_config_add_no_security (NMSupplicantConfig *self, diff --git a/src/supplicant/nm-supplicant-interface.c b/src/supplicant/nm-supplicant-interface.c index 3511b151..44f887cb 100644 --- a/src/supplicant/nm-supplicant-interface.c +++ b/src/supplicant/nm-supplicant-interface.c @@ -93,7 +93,6 @@ NM_GOBJECT_PROPERTIES_DEFINE (NMSupplicantInterface, PROP_FAST_SUPPORT, PROP_AP_SUPPORT, PROP_PMF_SUPPORT, - PROP_FILS_SUPPORT, ); typedef struct { @@ -103,7 +102,6 @@ typedef struct { NMSupplicantFeature fast_support; NMSupplicantFeature ap_support; /* Lightweight AP mode support */ NMSupplicantFeature pmf_support; - NMSupplicantFeature fils_support; guint32 max_scan_ssids; guint32 ready_count; @@ -567,12 +565,6 @@ nm_supplicant_interface_get_pmf_support (NMSupplicantInterface *self) return NM_SUPPLICANT_INTERFACE_GET_PRIVATE (self)->pmf_support; } -NMSupplicantFeature -nm_supplicant_interface_get_fils_support (NMSupplicantInterface *self) -{ - return NM_SUPPLICANT_INTERFACE_GET_PRIVATE (self)->fils_support; -} - void nm_supplicant_interface_set_ap_support (NMSupplicantInterface *self, NMSupplicantFeature ap_support) @@ -604,15 +596,6 @@ nm_supplicant_interface_set_pmf_support (NMSupplicantInterface *self, priv->pmf_support = pmf_support; } -void -nm_supplicant_interface_set_fils_support (NMSupplicantInterface *self, - NMSupplicantFeature fils_support) -{ - NMSupplicantInterfacePrivate *priv = NM_SUPPLICANT_INTERFACE_GET_PRIVATE (self); - - priv->fils_support = fils_support; -} - /*****************************************************************************/ static void @@ -1074,8 +1057,9 @@ props_changed_cb (GDBusProxy *proxy, } if (g_variant_lookup (changed_properties, "CurrentBSS", "&o", &s)) { - s = nm_utils_dbus_normalize_object_path (s); - if (!nm_streq0 (s, priv->current_bss)) { + if (strcmp (s, "/") == 0) + s = NULL; + if (g_strcmp0 (s, priv->current_bss) != 0) { g_free (priv->current_bss); priv->current_bss = g_strdup (s); _notify (self, PROP_CURRENT_BSS); @@ -1214,6 +1198,7 @@ static void interface_get_cb (GDBusProxy *proxy, GAsyncResult *result, gpointer user_data) { NMSupplicantInterface *self; + NMSupplicantInterfacePrivate *priv; gs_unref_variant GVariant *variant = NULL; gs_free_error GError *error = NULL; const char *path; @@ -1225,6 +1210,7 @@ interface_get_cb (GDBusProxy *proxy, GAsyncResult *result, gpointer user_data) return; self = NM_SUPPLICANT_INTERFACE (user_data); + priv = NM_SUPPLICANT_INTERFACE_GET_PRIVATE (self); if (variant) { g_variant_get (variant, "(&o)", &path); @@ -1914,10 +1900,6 @@ set_property (GObject *object, /* construct-only */ priv->pmf_support = g_value_get_int (value); break; - case PROP_FILS_SUPPORT: - /* construct-only */ - priv->fils_support = g_value_get_int (value); - break; default: G_OBJECT_WARN_INVALID_PROPERTY_ID (object, prop_id, pspec); break; @@ -1938,8 +1920,7 @@ nm_supplicant_interface_new (const char *ifname, NMSupplicantDriver driver, NMSupplicantFeature fast_support, NMSupplicantFeature ap_support, - NMSupplicantFeature pmf_support, - NMSupplicantFeature fils_support) + NMSupplicantFeature pmf_support) { g_return_val_if_fail (ifname != NULL, NULL); @@ -1949,7 +1930,6 @@ nm_supplicant_interface_new (const char *ifname, NM_SUPPLICANT_INTERFACE_FAST_SUPPORT, (int) fast_support, NM_SUPPLICANT_INTERFACE_AP_SUPPORT, (int) ap_support, NM_SUPPLICANT_INTERFACE_PMF_SUPPORT, (int) pmf_support, - NM_SUPPLICANT_INTERFACE_FILS_SUPPORT, (int) fils_support, NULL); } @@ -1984,7 +1964,7 @@ dispose (GObject *object) nm_clear_g_cancellable (&priv->other_cancellable); g_clear_object (&priv->wpas_proxy); - g_clear_pointer (&priv->bss_proxies, g_hash_table_destroy); + g_clear_pointer (&priv->bss_proxies, (GDestroyNotify) g_hash_table_destroy); g_clear_pointer (&priv->net_path, g_free); g_clear_pointer (&priv->dev, g_free); @@ -2049,14 +2029,6 @@ nm_supplicant_interface_class_init (NMSupplicantInterfaceClass *klass) G_PARAM_WRITABLE | G_PARAM_CONSTRUCT_ONLY | G_PARAM_STATIC_STRINGS); - obj_properties[PROP_FILS_SUPPORT] = - g_param_spec_int (NM_SUPPLICANT_INTERFACE_FILS_SUPPORT, "", "", - NM_SUPPLICANT_FEATURE_UNKNOWN, - NM_SUPPLICANT_FEATURE_YES, - NM_SUPPLICANT_FEATURE_UNKNOWN, - G_PARAM_WRITABLE | - G_PARAM_CONSTRUCT_ONLY | - G_PARAM_STATIC_STRINGS); g_object_class_install_properties (object_class, _PROPERTY_ENUMS_LAST, obj_properties); diff --git a/src/supplicant/nm-supplicant-interface.h b/src/supplicant/nm-supplicant-interface.h index f32ad8dd..567cf96f 100644 --- a/src/supplicant/nm-supplicant-interface.h +++ b/src/supplicant/nm-supplicant-interface.h @@ -61,7 +61,6 @@ typedef enum { #define NM_SUPPLICANT_INTERFACE_FAST_SUPPORT "fast-support" #define NM_SUPPLICANT_INTERFACE_AP_SUPPORT "ap-support" #define NM_SUPPLICANT_INTERFACE_PMF_SUPPORT "pmf-support" -#define NM_SUPPLICANT_INTERFACE_FILS_SUPPORT "fils-support" /* Signals */ #define NM_SUPPLICANT_INTERFACE_STATE "state" @@ -80,8 +79,7 @@ NMSupplicantInterface * nm_supplicant_interface_new (const char *ifname, NMSupplicantDriver driver, NMSupplicantFeature fast_support, NMSupplicantFeature ap_support, - NMSupplicantFeature pmf_support, - NMSupplicantFeature fils_support); + NMSupplicantFeature pmf_support); void nm_supplicant_interface_set_supplicant_available (NMSupplicantInterface *self, gboolean available); @@ -125,7 +123,6 @@ gboolean nm_supplicant_interface_credentials_reply (NMSupplicantInterface *self, NMSupplicantFeature nm_supplicant_interface_get_ap_support (NMSupplicantInterface *self); NMSupplicantFeature nm_supplicant_interface_get_pmf_support (NMSupplicantInterface *self); -NMSupplicantFeature nm_supplicant_interface_get_fils_support (NMSupplicantInterface *self); void nm_supplicant_interface_set_ap_support (NMSupplicantInterface *self, NMSupplicantFeature apmode); @@ -136,9 +133,6 @@ void nm_supplicant_interface_set_fast_support (NMSupplicantInterface *self, void nm_supplicant_interface_set_pmf_support (NMSupplicantInterface *self, NMSupplicantFeature pmf_support); -void nm_supplicant_interface_set_fils_support (NMSupplicantInterface *self, - NMSupplicantFeature fils_support); - void nm_supplicant_interface_enroll_wps (NMSupplicantInterface *self, const char *const type, const char *bssid, diff --git a/src/supplicant/nm-supplicant-manager.c b/src/supplicant/nm-supplicant-manager.c index 5ab96f88..0f2eb63a 100644 --- a/src/supplicant/nm-supplicant-manager.c +++ b/src/supplicant/nm-supplicant-manager.c @@ -40,7 +40,6 @@ typedef struct { NMSupplicantFeature fast_support; NMSupplicantFeature ap_support; NMSupplicantFeature pmf_support; - NMSupplicantFeature fils_support; guint die_count_reset_id; guint die_count; } NMSupplicantManagerPrivate; @@ -162,8 +161,7 @@ nm_supplicant_manager_create_interface (NMSupplicantManager *self, driver, priv->fast_support, priv->ap_support, - priv->pmf_support, - priv->fils_support); + priv->pmf_support); priv->ifaces = g_slist_prepend (priv->ifaces, iface); g_object_add_toggle_ref ((GObject *) iface, _sup_iface_last_ref, self); @@ -198,7 +196,6 @@ update_capabilities (NMSupplicantManager *self) */ priv->ap_support = NM_SUPPLICANT_FEATURE_UNKNOWN; priv->pmf_support = NM_SUPPLICANT_FEATURE_UNKNOWN; - priv->fils_support = NM_SUPPLICANT_FEATURE_UNKNOWN; value = g_dbus_proxy_get_cached_property (priv->proxy, "Capabilities"); if (value) { @@ -206,25 +203,21 @@ update_capabilities (NMSupplicantManager *self) array = g_variant_get_strv (value, NULL); priv->ap_support = NM_SUPPLICANT_FEATURE_NO; priv->pmf_support = NM_SUPPLICANT_FEATURE_NO; - priv->fils_support = NM_SUPPLICANT_FEATURE_NO; if (array) { if (g_strv_contains (array, "ap")) priv->ap_support = NM_SUPPLICANT_FEATURE_YES; if (g_strv_contains (array, "pmf")) priv->pmf_support = NM_SUPPLICANT_FEATURE_YES; - if (g_strv_contains (array, "fils")) - priv->fils_support = NM_SUPPLICANT_FEATURE_YES; g_free (array); } } g_variant_unref (value); } - /* Tell all interfaces about results of the AP/PMF/FILS check */ + /* Tell all interfaces about results of the AP/PMF check */ for (ifaces = priv->ifaces; ifaces; ifaces = ifaces->next) { nm_supplicant_interface_set_ap_support (ifaces->data, priv->ap_support); nm_supplicant_interface_set_pmf_support (ifaces->data, priv->pmf_support); - nm_supplicant_interface_set_fils_support (ifaces->data, priv->fils_support); } _LOGD ("AP mode is %ssupported", @@ -233,9 +226,6 @@ update_capabilities (NMSupplicantManager *self) _LOGD ("PMF is %ssupported", (priv->pmf_support == NM_SUPPLICANT_FEATURE_YES) ? "" : (priv->pmf_support == NM_SUPPLICANT_FEATURE_NO) ? "not " : "possibly "); - _LOGD ("FILS is %ssupported", - (priv->fils_support == NM_SUPPLICANT_FEATURE_YES) ? "" : - (priv->fils_support == NM_SUPPLICANT_FEATURE_NO) ? "not " : "possibly "); /* EAP-FAST */ priv->fast_support = NM_SUPPLICANT_FEATURE_NO; @@ -359,7 +349,6 @@ name_owner_cb (GDBusProxy *proxy, GParamSpec *pspec, gpointer user_data) priv->ap_support = NM_SUPPLICANT_FEATURE_UNKNOWN; priv->fast_support = NM_SUPPLICANT_FEATURE_UNKNOWN; priv->pmf_support = NM_SUPPLICANT_FEATURE_UNKNOWN; - priv->fils_support = NM_SUPPLICANT_FEATURE_UNKNOWN; set_running (self, FALSE); } diff --git a/src/supplicant/nm-supplicant-settings-verify.c b/src/supplicant/nm-supplicant-settings-verify.c index 5198d75f..14daf693 100644 --- a/src/supplicant/nm-supplicant-settings-verify.c +++ b/src/supplicant/nm-supplicant-settings-verify.c @@ -73,7 +73,6 @@ const char * group_allowed[] = { "CCMP", "TKIP", "WEP104", "WEP40", NULL }; const char * proto_allowed[] = { "WPA", "RSN", NULL }; const char * key_mgmt_allowed[] = { "WPA-PSK", "WPA-PSK-SHA256", "WPA-EAP", "WPA-EAP-SHA256", - "FILS-SHA256", "FILS-SHA384", "IEEE8021X", "WPA-NONE", "NONE", NULL }; const char * auth_alg_allowed[] = { "OPEN", "SHARED", "LEAP", NULL }; @@ -222,10 +221,10 @@ validate_type_keyword (const struct Opt * opt, const char * value, const guint32 len) { - char **allowed; - gchar **candidates = NULL; - char **candidate; - gboolean found = FALSE; + char ** allowed; + gchar ** candidates = NULL; + char ** candidate; + gboolean found = FALSE; g_return_val_if_fail (opt != NULL, FALSE); g_return_val_if_fail (value != NULL, FALSE); diff --git a/src/supplicant/nm-supplicant-types.h b/src/supplicant/nm-supplicant-types.h index 747cf152..f75827ec 100644 --- a/src/supplicant/nm-supplicant-types.h +++ b/src/supplicant/nm-supplicant-types.h @@ -21,9 +21,9 @@ #ifndef __NETWORKMANAGER_SUPPLICANT_TYPES_H__ #define __NETWORKMANAGER_SUPPLICANT_TYPES_H__ -#define WPAS_DBUS_SERVICE "fi.w1.wpa_supplicant1" -#define WPAS_DBUS_PATH "/fi/w1/wpa_supplicant1" -#define WPAS_DBUS_INTERFACE "fi.w1.wpa_supplicant1" +#define WPAS_DBUS_SERVICE "fi.w1.wpa_supplicant1" +#define WPAS_DBUS_PATH "/fi/w1/wpa_supplicant1" +#define WPAS_DBUS_INTERFACE "fi.w1.wpa_supplicant1" typedef struct _NMSupplicantManager NMSupplicantManager; typedef struct _NMSupplicantInterface NMSupplicantInterface; diff --git a/src/supplicant/tests/meson.build b/src/supplicant/tests/meson.build deleted file mode 100644 index e6a86b20..00000000 --- a/src/supplicant/tests/meson.build +++ /dev/null @@ -1,14 +0,0 @@ -test_unit = 'test-supplicant-config' - -exe = executable( - test_unit, - test_unit + '.c', - dependencies: test_nm_dep, - c_args: '-DTEST_CERT_DIR="@0@"'.format(join_paths(meson.current_source_dir(), 'certs')) -) - -test( - 'supplicant/' + test_unit, - test_script, - args: test_args + [exe.full_path()] -) diff --git a/src/supplicant/tests/test-supplicant-config.c b/src/supplicant/tests/test-supplicant-config.c index 60ca5258..4b4a4935 100644 --- a/src/supplicant/tests/test-supplicant-config.c +++ b/src/supplicant/tests/test-supplicant-config.c @@ -95,11 +95,7 @@ validate_opt (const char *detail, } static GVariant * -build_supplicant_config (NMConnection *connection, - guint mtu, - guint fixed_freq, - gboolean support_pmf, - gboolean support_fils) +build_supplicant_config (NMConnection *connection, guint mtu, guint fixed_freq) { gs_unref_object NMSupplicantConfig *config = NULL; gs_free_error GError *error = NULL; @@ -108,7 +104,7 @@ build_supplicant_config (NMConnection *connection, NMSetting8021x *s_8021x; gboolean success; - config = nm_supplicant_config_new (support_pmf, support_fils); + config = nm_supplicant_config_new (); s_wifi = nm_connection_get_setting_wireless (connection); g_assert (s_wifi); @@ -122,7 +118,6 @@ build_supplicant_config (NMConnection *connection, s_wsec = nm_connection_get_setting_wireless_security (connection); if (s_wsec) { NMSettingWirelessSecurityPmf pmf = nm_setting_wireless_security_get_pmf (s_wsec); - NMSettingWirelessSecurityFils fils = nm_setting_wireless_security_get_fils (s_wsec); s_8021x = nm_connection_get_setting_802_1x (connection); success = nm_supplicant_config_add_setting_wireless_security (config, s_wsec, @@ -130,7 +125,6 @@ build_supplicant_config (NMConnection *connection, nm_connection_get_uuid (connection), mtu, pmf, - fils, &error); } else { success = nm_supplicant_config_add_no_security (config, &error); @@ -146,6 +140,7 @@ build_supplicant_config (NMConnection *connection, return nm_supplicant_config_to_variant (config); } +#define EXPECT(msg) g_test_expect_message ("NetworkManager", G_LOG_LEVEL_INFO, msg) static NMConnection * new_basic_connection (const char *id, @@ -204,12 +199,12 @@ test_wifi_open (void) g_assert_no_error (error); g_assert (success); - NMTST_EXPECT_NM_INFO ("Config: added 'ssid' value 'Test SSID'*"); - NMTST_EXPECT_NM_INFO ("Config: added 'scan_ssid' value '1'*"); - NMTST_EXPECT_NM_INFO ("Config: added 'bssid' value '11:22:33:44:55:66'*"); - NMTST_EXPECT_NM_INFO ("Config: added 'freq_list' value *"); - NMTST_EXPECT_NM_INFO ("Config: added 'key_mgmt' value 'NONE'"); - config_dict = build_supplicant_config (connection, 1500, 0, TRUE, TRUE); + EXPECT ("*added 'ssid' value 'Test SSID'*"); + EXPECT ("*added 'scan_ssid' value '1'*"); + EXPECT ("*added 'bssid' value '11:22:33:44:55:66'*"); + EXPECT ("*added 'freq_list' value *"); + EXPECT ("*added 'key_mgmt' value 'NONE'"); + config_dict = build_supplicant_config (connection, 1500, 0); g_test_assert_expected_messages (); g_assert (config_dict); @@ -254,19 +249,19 @@ test_wifi_wep_key (const char *detail, g_assert_no_error (error); g_assert (success); - NMTST_EXPECT_NM_INFO ("Config: added 'ssid' value 'Test SSID'*"); - NMTST_EXPECT_NM_INFO ("Config: added 'scan_ssid' value '1'*"); + EXPECT ("*added 'ssid' value 'Test SSID'*"); + EXPECT ("*added 'scan_ssid' value '1'*"); if (test_bssid) - NMTST_EXPECT_NM_INFO ("Config: added 'bssid' value '11:22:33:44:55:66'*"); + EXPECT ("*added 'bssid' value '11:22:33:44:55:66'*"); - NMTST_EXPECT_NM_INFO ("Config: added 'freq_list' value *"); - NMTST_EXPECT_NM_INFO ("Config: added 'key_mgmt' value 'NONE'"); - NMTST_EXPECT_NM_INFO ("Config: added 'wep_key0' value *"); - NMTST_EXPECT_NM_INFO ("Config: added 'wep_tx_keyidx' value '0'"); + EXPECT ("*added 'freq_list' value *"); + EXPECT ("*added 'key_mgmt' value 'NONE'"); + EXPECT ("*added 'wep_key0' value *"); + EXPECT ("*added 'wep_tx_keyidx' value '0'"); if (!test_bssid) - NMTST_EXPECT_NM_INFO ("Config: added 'bgscan' value 'simple:30:-80:86400'*"); + EXPECT ("*added 'bgscan' value 'simple:30:-80:86400'*"); - config_dict = build_supplicant_config (connection, 1500, 0, TRUE, TRUE); + config_dict = build_supplicant_config (connection, 1500, 0); g_test_assert_expected_messages (); g_assert (config_dict); @@ -313,8 +308,7 @@ test_wifi_wpa_psk (const char *detail, OptType key_type, const char *key_data, const unsigned char *expected, - size_t expected_size, - NMSettingWirelessSecurityPmf pmf) + size_t expected_size) { gs_unref_object NMConnection *connection = NULL; gs_unref_variant GVariant *config_dict = NULL; @@ -334,7 +328,7 @@ test_wifi_wpa_psk (const char *detail, g_object_set (s_wsec, NM_SETTING_WIRELESS_SECURITY_KEY_MGMT, "wpa-psk", NM_SETTING_WIRELESS_SECURITY_PSK, key_data, - NM_SETTING_WIRELESS_SECURITY_PMF, (int) pmf, + NM_SETTING_WIRELESS_SECURITY_PMF, (int) NM_SETTING_WIRELESS_SECURITY_PMF_OPTIONAL, NULL); nm_setting_wireless_security_add_proto (s_wsec, "wpa"); nm_setting_wireless_security_add_proto (s_wsec, "rsn"); @@ -347,26 +341,17 @@ test_wifi_wpa_psk (const char *detail, g_assert_no_error (error); g_assert (success); - NMTST_EXPECT_NM_INFO ("Config: added 'ssid' value 'Test SSID'*"); - NMTST_EXPECT_NM_INFO ("Config: added 'scan_ssid' value '1'*"); - NMTST_EXPECT_NM_INFO ("Config: added 'bssid' value '11:22:33:44:55:66'*"); - NMTST_EXPECT_NM_INFO ("Config: added 'freq_list' value *"); - NMTST_EXPECT_NM_INFO ("Config: added 'key_mgmt' value 'WPA-PSK WPA-PSK-SHA256'"); - NMTST_EXPECT_NM_INFO ("Config: added 'psk' value *"); - NMTST_EXPECT_NM_INFO ("Config: added 'proto' value 'WPA RSN'"); - NMTST_EXPECT_NM_INFO ("Config: added 'pairwise' value 'TKIP CCMP'"); - NMTST_EXPECT_NM_INFO ("Config: added 'group' value 'TKIP CCMP'"); - switch (pmf) { - case NM_SETTING_WIRELESS_SECURITY_PMF_OPTIONAL: - NMTST_EXPECT_NM_INFO ("Config: added 'ieee80211w' value '1'"); - break; - case NM_SETTING_WIRELESS_SECURITY_PMF_REQUIRED: - NMTST_EXPECT_NM_INFO ("Config: added 'ieee80211w' value '2'"); - break; - default: - break; - } - config_dict = build_supplicant_config (connection, 1500, 0, TRUE, TRUE); + EXPECT ("*added 'ssid' value 'Test SSID'*"); + EXPECT ("*added 'scan_ssid' value '1'*"); + EXPECT ("*added 'bssid' value '11:22:33:44:55:66'*"); + EXPECT ("*added 'freq_list' value *"); + EXPECT ("*added 'key_mgmt' value 'WPA-PSK WPA-PSK-SHA256'"); + EXPECT ("*added 'psk' value *"); + EXPECT ("*added 'proto' value 'WPA RSN'"); + EXPECT ("*added 'pairwise' value 'TKIP CCMP'"); + EXPECT ("*added 'group' value 'TKIP CCMP'"); + EXPECT ("*added 'ieee80211w' value '1'"); + config_dict = build_supplicant_config (connection, 1500, 0); g_test_assert_expected_messages (); g_assert (config_dict); @@ -396,16 +381,12 @@ test_wifi_wpa_psk_types (void) 0x6c, 0x2f, 0x11, 0x60, 0x5a, 0x16, 0x08, 0x93 }; const char *key2 = "r34lly l33t wp4 p4ssphr4s3 for t3st1ng"; - test_wifi_wpa_psk ("wifi-wpa-psk-hex", TYPE_BYTES, key1, key1_expected, - sizeof (key1_expected), NM_SETTING_WIRELESS_SECURITY_PMF_OPTIONAL); - test_wifi_wpa_psk ("wifi-wep-psk-passphrase", TYPE_STRING, key2, - (gconstpointer) key2, strlen (key2), NM_SETTING_WIRELESS_SECURITY_PMF_REQUIRED); - test_wifi_wpa_psk ("pmf-disabled", TYPE_STRING, key2, - (gconstpointer) key2, strlen (key2), NM_SETTING_WIRELESS_SECURITY_PMF_DISABLE); + test_wifi_wpa_psk ("wifi-wpa-psk-hex", TYPE_BYTES, key1, key1_expected, sizeof (key1_expected)); + test_wifi_wpa_psk ("wifi-wep-psk-passphrase", TYPE_STRING, key2, (gconstpointer) key2, strlen (key2)); } static NMConnection * -generate_wifi_eap_connection (const char *id, GBytes *ssid, const char *bssid_str, NMSettingWirelessSecurityFils fils) +generate_wifi_eap_connection (const char *id, GBytes *ssid, const char *bssid_str) { NMConnection *connection = NULL; NMSettingWirelessSecurity *s_wsec; @@ -420,7 +401,6 @@ generate_wifi_eap_connection (const char *id, GBytes *ssid, const char *bssid_st nm_connection_add_setting (connection, NM_SETTING (s_wsec)); g_object_set (s_wsec, NM_SETTING_WIRELESS_SECURITY_KEY_MGMT, "wpa-eap", - NM_SETTING_WIRELESS_SECURITY_FILS, (int) fils, NULL); nm_setting_wireless_security_add_proto (s_wsec, "wpa"); nm_setting_wireless_security_add_proto (s_wsec, "rsn"); @@ -454,22 +434,22 @@ test_wifi_eap_locked_bssid (void) const char *bssid_str = "11:22:33:44:55:66"; guint32 mtu = 1100; - connection = generate_wifi_eap_connection ("Test Wifi EAP-TLS Locked", ssid, bssid_str, NM_SETTING_WIRELESS_SECURITY_FILS_OPTIONAL); - - NMTST_EXPECT_NM_INFO ("Config: added 'ssid' value 'Test SSID'*"); - NMTST_EXPECT_NM_INFO ("Config: added 'scan_ssid' value '1'*"); - NMTST_EXPECT_NM_INFO ("Config: added 'bssid' value '11:22:33:44:55:66'*"); - NMTST_EXPECT_NM_INFO ("Config: added 'freq_list' value *"); - NMTST_EXPECT_NM_INFO ("Config: added 'key_mgmt' value 'WPA-EAP'"); - NMTST_EXPECT_NM_INFO ("Config: added 'proto' value 'WPA RSN'"); - NMTST_EXPECT_NM_INFO ("Config: added 'pairwise' value 'TKIP CCMP'"); - NMTST_EXPECT_NM_INFO ("Config: added 'group' value 'TKIP CCMP'"); - NMTST_EXPECT_NM_INFO ("Config: added 'eap' value 'TLS'"); - NMTST_EXPECT_NM_INFO ("Config: added 'fragment_size' value '1086'"); - NMTST_EXPECT_NM_INFO ("Config: added 'ca_cert' value '*/test-ca-cert.pem'"); - NMTST_EXPECT_NM_INFO ("Config: added 'private_key' value '*/test-cert.p12'"); - NMTST_EXPECT_NM_INFO ("Config: added 'proactive_key_caching' value '1'"); - config_dict = build_supplicant_config (connection, mtu, 0, FALSE, FALSE); + connection = generate_wifi_eap_connection ("Test Wifi EAP-TLS Locked", ssid, bssid_str); + + EXPECT ("*added 'ssid' value 'Test SSID'*"); + EXPECT ("*added 'scan_ssid' value '1'*"); + EXPECT ("*added 'bssid' value '11:22:33:44:55:66'*"); + EXPECT ("*added 'freq_list' value *"); + EXPECT ("*added 'key_mgmt' value 'WPA-EAP'"); + EXPECT ("*added 'proto' value 'WPA RSN'"); + EXPECT ("*added 'pairwise' value 'TKIP CCMP'"); + EXPECT ("*added 'group' value 'TKIP CCMP'"); + EXPECT ("*Config: added 'eap' value 'TLS'"); + EXPECT ("*Config: added 'fragment_size' value '1086'"); + EXPECT ("* Config: added 'ca_cert' value '*/test-ca-cert.pem'"); + EXPECT ("* Config: added 'private_key' value '*/test-cert.p12'"); + EXPECT ("*Config: added 'proactive_key_caching' value '1'"); + config_dict = build_supplicant_config (connection, mtu, 0); g_test_assert_expected_messages (); g_assert (config_dict); @@ -495,69 +475,28 @@ test_wifi_eap_unlocked_bssid (void) gs_unref_bytes GBytes *bgscan = g_bytes_new (bgscan_data, strlen (bgscan_data)); guint32 mtu = 1100; - connection = generate_wifi_eap_connection ("Test Wifi EAP-TLS Unlocked", ssid, NULL, NM_SETTING_WIRELESS_SECURITY_FILS_REQUIRED); - - NMTST_EXPECT_NM_INFO ("Config: added 'ssid' value 'Test SSID'*"); - NMTST_EXPECT_NM_INFO ("Config: added 'scan_ssid' value '1'*"); - NMTST_EXPECT_NM_INFO ("Config: added 'freq_list' value *"); - NMTST_EXPECT_NM_INFO ("Config: added 'key_mgmt' value 'FILS-SHA256 FILS-SHA384'"); - NMTST_EXPECT_NM_INFO ("Config: added 'proto' value 'WPA RSN'"); - NMTST_EXPECT_NM_INFO ("Config: added 'pairwise' value 'TKIP CCMP'"); - NMTST_EXPECT_NM_INFO ("Config: added 'group' value 'TKIP CCMP'"); - NMTST_EXPECT_NM_INFO ("Config: added 'eap' value 'TLS'"); - NMTST_EXPECT_NM_INFO ("Config: added 'fragment_size' value '1086'"); - NMTST_EXPECT_NM_INFO ("Config: added 'ca_cert' value '*/test-ca-cert.pem'"); - NMTST_EXPECT_NM_INFO ("Config: added 'private_key' value '*/test-cert.p12'"); - NMTST_EXPECT_NM_INFO ("Config: added 'proactive_key_caching' value '1'"); - NMTST_EXPECT_NM_INFO ("Config: added 'bgscan' value 'simple:30:-65:300'"); - config_dict = build_supplicant_config (connection, mtu, 0, FALSE, TRUE); - g_test_assert_expected_messages (); - g_assert (config_dict); - - validate_opt ("wifi-eap", config_dict, "scan_ssid", TYPE_INT, GINT_TO_POINTER (1)); - validate_opt ("wifi-eap", config_dict, "ssid", TYPE_BYTES, ssid); - validate_opt ("wifi-eap", config_dict, "key_mgmt", TYPE_KEYWORD, "FILS-SHA256 FILS-SHA384"); - validate_opt ("wifi-eap", config_dict, "eap", TYPE_KEYWORD, "TLS"); - validate_opt ("wifi-eap", config_dict, "proto", TYPE_KEYWORD, "WPA RSN"); - validate_opt ("wifi-eap", config_dict, "pairwise", TYPE_KEYWORD, "TKIP CCMP"); - validate_opt ("wifi-eap", config_dict, "group", TYPE_KEYWORD, "TKIP CCMP"); - validate_opt ("wifi-eap", config_dict, "fragment_size", TYPE_INT, GINT_TO_POINTER(mtu-14)); - validate_opt ("wifi-eap", config_dict, "bgscan", TYPE_BYTES, bgscan); -} - -static void -test_wifi_eap_fils_disabled (void) -{ - gs_unref_object NMConnection *connection = NULL; - gs_unref_variant GVariant *config_dict = NULL; - const unsigned char ssid_data[] = { 0x54, 0x65, 0x73, 0x74, 0x20, 0x53, 0x53, 0x49, 0x44 }; - gs_unref_bytes GBytes *ssid = g_bytes_new (ssid_data, sizeof (ssid_data)); - const char *bgscan_data = "simple:30:-65:300"; - gs_unref_bytes GBytes *bgscan = g_bytes_new (bgscan_data, strlen (bgscan_data)); - guint32 mtu = 1100; - - connection = generate_wifi_eap_connection ("Test Wifi FILS disabled", ssid, NULL, NM_SETTING_WIRELESS_SECURITY_FILS_DISABLE); - - NMTST_EXPECT_NM_INFO ("Config: added 'ssid' value 'Test SSID'*"); - NMTST_EXPECT_NM_INFO ("Config: added 'scan_ssid' value '1'*"); - NMTST_EXPECT_NM_INFO ("Config: added 'freq_list' value *"); - NMTST_EXPECT_NM_INFO ("Config: added 'key_mgmt' value 'WPA-EAP WPA-EAP-SHA256'"); - NMTST_EXPECT_NM_INFO ("Config: added 'proto' value 'WPA RSN'"); - NMTST_EXPECT_NM_INFO ("Config: added 'pairwise' value 'TKIP CCMP'"); - NMTST_EXPECT_NM_INFO ("Config: added 'group' value 'TKIP CCMP'"); - NMTST_EXPECT_NM_INFO ("Config: added 'eap' value 'TLS'"); - NMTST_EXPECT_NM_INFO ("Config: added 'fragment_size' value '1086'"); - NMTST_EXPECT_NM_INFO ("Config: added 'ca_cert' value '*/test-ca-cert.pem'"); - NMTST_EXPECT_NM_INFO ("Config: added 'private_key' value '*/test-cert.p12'"); - NMTST_EXPECT_NM_INFO ("Config: added 'proactive_key_caching' value '1'"); - NMTST_EXPECT_NM_INFO ("Config: added 'bgscan' value 'simple:30:-65:300'"); - config_dict = build_supplicant_config (connection, mtu, 0, TRUE, TRUE); + connection = generate_wifi_eap_connection ("Test Wifi EAP-TLS Unlocked", ssid, NULL); + + EXPECT ("*added 'ssid' value 'Test SSID'*"); + EXPECT ("*added 'scan_ssid' value '1'*"); + EXPECT ("*added 'freq_list' value *"); + EXPECT ("*added 'key_mgmt' value 'WPA-EAP'"); + EXPECT ("*added 'proto' value 'WPA RSN'"); + EXPECT ("*added 'pairwise' value 'TKIP CCMP'"); + EXPECT ("*added 'group' value 'TKIP CCMP'"); + EXPECT ("*Config: added 'eap' value 'TLS'"); + EXPECT ("*Config: added 'fragment_size' value '1086'"); + EXPECT ("* Config: added 'ca_cert' value '*/test-ca-cert.pem'"); + EXPECT ("* Config: added 'private_key' value '*/test-cert.p12'"); + EXPECT ("*Config: added 'proactive_key_caching' value '1'"); + EXPECT ("*Config: added 'bgscan' value 'simple:30:-65:300'"); + config_dict = build_supplicant_config (connection, mtu, 0); g_test_assert_expected_messages (); g_assert (config_dict); validate_opt ("wifi-eap", config_dict, "scan_ssid", TYPE_INT, GINT_TO_POINTER (1)); validate_opt ("wifi-eap", config_dict, "ssid", TYPE_BYTES, ssid); - validate_opt ("wifi-eap", config_dict, "key_mgmt", TYPE_KEYWORD, "WPA-EAP WPA-EAP-SHA256"); + validate_opt ("wifi-eap", config_dict, "key_mgmt", TYPE_KEYWORD, "WPA-EAP"); validate_opt ("wifi-eap", config_dict, "eap", TYPE_KEYWORD, "TLS"); validate_opt ("wifi-eap", config_dict, "proto", TYPE_KEYWORD, "WPA RSN"); validate_opt ("wifi-eap", config_dict, "pairwise", TYPE_KEYWORD, "TKIP CCMP"); @@ -577,7 +516,6 @@ int main (int argc, char **argv) g_test_add_func ("/supplicant-config/wifi-wpa-psk-types", test_wifi_wpa_psk_types); g_test_add_func ("/supplicant-config/wifi-eap/locked-bssid", test_wifi_eap_locked_bssid); g_test_add_func ("/supplicant-config/wifi-eap/unlocked-bssid", test_wifi_eap_unlocked_bssid); - g_test_add_func ("/supplicant-config/wifi-eap/fils-disabled", test_wifi_eap_fils_disabled); return g_test_run (); } diff --git a/src/systemd/meson.build b/src/systemd/meson.build deleted file mode 100644 index fe3d88d3..00000000 --- a/src/systemd/meson.build +++ /dev/null @@ -1,70 +0,0 @@ -sources = files( - 'sd-adapt/nm-sd-adapt.c', - 'src/basic/alloc-util.c', - 'src/basic/escape.c', - 'src/basic/ether-addr-util.c', - 'src/basic/extract-word.c', - 'src/basic/fd-util.c', - 'src/basic/fileio.c', - 'src/basic/fs-util.c', - 'src/basic/hash-funcs.c', - 'src/basic/hashmap.c', - 'src/basic/hexdecoct.c', - 'src/basic/hostname-util.c', - 'src/basic/in-addr-util.c', - 'src/basic/io-util.c', - 'src/basic/mempool.c', - 'src/basic/parse-util.c', - 'src/basic/path-util.c', - 'src/basic/prioq.c', - 'src/basic/process-util.c', - 'src/basic/random-util.c', - 'src/basic/socket-util.c', - 'src/basic/string-table.c', - 'src/basic/string-util.c', - 'src/basic/strv.c', - 'src/basic/time-util.c', - 'src/basic/utf8.c', - 'src/basic/util.c', - 'src/libsystemd-network/arp-util.c', - 'src/libsystemd-network/dhcp-identifier.c', - 'src/libsystemd-network/dhcp-network.c', - 'src/libsystemd-network/dhcp-option.c', - 'src/libsystemd-network/dhcp-packet.c', - 'src/libsystemd-network/dhcp6-network.c', - 'src/libsystemd-network/dhcp6-option.c', - 'src/libsystemd-network/lldp-neighbor.c', - 'src/libsystemd-network/lldp-network.c', - 'src/libsystemd-network/network-internal.c', - 'src/libsystemd-network/sd-dhcp-client.c', - 'src/libsystemd-network/sd-dhcp-lease.c', - 'src/libsystemd-network/sd-dhcp6-client.c', - 'src/libsystemd-network/sd-dhcp6-lease.c', - 'src/libsystemd-network/sd-ipv4acd.c', - 'src/libsystemd-network/sd-ipv4ll.c', - 'src/libsystemd-network/sd-lldp.c', - 'src/libsystemd/sd-event/sd-event.c', - 'src/libsystemd/sd-id128/id128-util.c', - 'src/libsystemd/sd-id128/sd-id128.c', - 'src/shared/dns-domain.c', - 'nm-sd.c' -) - -incs = [ - src_inc, - include_directories( - 'sd-adapt', - 'src/basic', - 'src/libsystemd-network', - 'src/shared', - 'src/systemd' - ) -] - -libsystemd_nm = static_library( - 'systemd-nm', - sources: sources, - include_directories: incs, - dependencies: nm_core_dep, - c_args: '-DNETWORKMANAGER_COMPILATION=NM_NETWORKMANAGER_COMPILATION_SYSTEMD' -) diff --git a/src/systemd/sd-adapt/device-nodes.h b/src/systemd/sd-adapt/device-nodes.h deleted file mode 100644 index 637892c2..00000000 --- a/src/systemd/sd-adapt/device-nodes.h +++ /dev/null @@ -1,3 +0,0 @@ -#pragma once - -/* dummy header */ diff --git a/src/systemd/sd-adapt/errno-list.h b/src/systemd/sd-adapt/errno-list.h deleted file mode 100644 index 637892c2..00000000 --- a/src/systemd/sd-adapt/errno-list.h +++ /dev/null @@ -1,3 +0,0 @@ -#pragma once - -/* dummy header */ diff --git a/src/systemd/sd-adapt/locale-util.h b/src/systemd/sd-adapt/locale-util.h deleted file mode 100644 index 637892c2..00000000 --- a/src/systemd/sd-adapt/locale-util.h +++ /dev/null @@ -1,3 +0,0 @@ -#pragma once - -/* dummy header */ diff --git a/src/systemd/sd-adapt/memfd-util.h b/src/systemd/sd-adapt/memfd-util.h deleted file mode 100644 index 637892c2..00000000 --- a/src/systemd/sd-adapt/memfd-util.h +++ /dev/null @@ -1,3 +0,0 @@ -#pragma once - -/* dummy header */ diff --git a/src/systemd/sd-adapt/nm-sd-adapt.h b/src/systemd/sd-adapt/nm-sd-adapt.h index 3a4125a0..0d291e26 100644 --- a/src/systemd/sd-adapt/nm-sd-adapt.h +++ b/src/systemd/sd-adapt/nm-sd-adapt.h @@ -26,16 +26,12 @@ #include <sys/resource.h> #include <time.h> +#define noreturn G_GNUC_NORETURN + #ifndef CLOCK_BOOTTIME #define CLOCK_BOOTTIME 7 #endif -#if defined(HAVE_DECL_REALLOCARRAY) && HAVE_DECL_REALLOCARRAY == 1 -#define HAVE_REALLOCARRAY 1 -#else -#define HAVE_REALLOCARRAY 0 -#endif - #if defined(HAVE_DECL_EXPLICIT_BZERO) && HAVE_DECL_EXPLICIT_BZERO == 1 #define HAVE_EXPLICIT_BZERO 1 #else @@ -109,7 +105,7 @@ G_STMT_START { \ * itself. *****************************************************************************/ -#if (NETWORKMANAGER_COMPILATION) & NM_NETWORKMANAGER_COMPILATION_WITH_SYSTEMD +#if (NETWORKMANAGER_COMPILATION) == NM_NETWORKMANAGER_COMPILATION_SYSTEMD #include <netinet/in.h> #include <string.h> @@ -142,15 +138,6 @@ G_STMT_START { \ # endif #endif -static inline pid_t -raw_getpid (void) { -#if defined(__alpha__) - return (pid_t) syscall (__NR_getxpid); -#else - return (pid_t) syscall (__NR_getpid); -#endif -} - /*****************************************************************************/ /* work around missing uchar.h */ @@ -159,6 +146,8 @@ typedef guint32 char32_t; /*****************************************************************************/ +#define PID_TO_PTR(p) ((void*) ((uintptr_t) p)) + static inline int sd_notify (int unset_environment, const char *state) { @@ -197,7 +186,7 @@ static inline pid_t gettid(void) { return (pid_t) syscall(SYS_gettid); } -#endif /* (NETWORKMANAGER_COMPILATION) & NM_NETWORKMANAGER_COMPILATION_WITH_SYSTEMD */ +#endif /* (NETWORKMANAGER_COMPILATION) == NM_NETWORKMANAGER_COMPILATION_SYSTEMD */ #endif /* NM_SD_ADAPT_H */ diff --git a/src/systemd/sd-adapt/procfs-util.h b/src/systemd/sd-adapt/procfs-util.h deleted file mode 100644 index 637892c2..00000000 --- a/src/systemd/sd-adapt/procfs-util.h +++ /dev/null @@ -1,3 +0,0 @@ -#pragma once - -/* dummy header */ diff --git a/src/systemd/sd-adapt/terminal-util.h b/src/systemd/sd-adapt/terminal-util.h deleted file mode 100644 index 637892c2..00000000 --- a/src/systemd/sd-adapt/terminal-util.h +++ /dev/null @@ -1,3 +0,0 @@ -#pragma once - -/* dummy header */ diff --git a/src/systemd/src/basic/alloc-util.c b/src/systemd/src/basic/alloc-util.c index 1a058d2f..97588312 100644 --- a/src/systemd/src/basic/alloc-util.c +++ b/src/systemd/src/basic/alloc-util.c @@ -1,4 +1,3 @@ -/* SPDX-License-Identifier: LGPL-2.1+ */ /*** This file is part of systemd. @@ -40,7 +39,7 @@ void* memdup(const void *p, size_t l) { return ret; } -void* memdup_suffix0(const void *p, size_t l) { +void* memdup_suffix0(const void*p, size_t l) { void *ret; assert(l == 0 || p); diff --git a/src/systemd/src/basic/alloc-util.h b/src/systemd/src/basic/alloc-util.h index b1e0edbb..0a89691b 100644 --- a/src/systemd/src/basic/alloc-util.h +++ b/src/systemd/src/basic/alloc-util.h @@ -1,4 +1,3 @@ -/* SPDX-License-Identifier: LGPL-2.1+ */ #pragma once /*** @@ -55,7 +54,7 @@ static inline void *mfree(void *memory) { }) void* memdup(const void *p, size_t l) _alloc_(2); -void* memdup_suffix0(const void *p, size_t l) _alloc_(2); +void* memdup_suffix0(const void*p, size_t l) _alloc_(2); static inline void freep(void *p) { free(*(void**) p); @@ -74,14 +73,12 @@ _malloc_ _alloc_(1, 2) static inline void *malloc_multiply(size_t size, size_t return malloc(size * need); } -#if !HAVE_REALLOCARRAY -_alloc_(2, 3) static inline void *reallocarray(void *p, size_t need, size_t size) { +_alloc_(2, 3) static inline void *realloc_multiply(void *p, size_t size, size_t need) { if (size_multiply_overflow(size, need)) return NULL; return realloc(p, size * need); } -#endif _alloc_(2, 3) static inline void *memdup_multiply(const void *p, size_t size, size_t need) { if (size_multiply_overflow(size, need)) @@ -130,12 +127,3 @@ void* greedy_realloc0(void **p, size_t *allocated, size_t need, size_t size); _new_ = alloca_align(_size_, (align)); \ (void*)memset(_new_, 0, _size_); \ }) - -/* Takes inspiration from Rusts's Option::take() method: reads and returns a pointer, but at the same time resets it to - * NULL. See: https://doc.rust-lang.org/std/option/enum.Option.html#method.take */ -#define TAKE_PTR(ptr) \ - ({ \ - typeof(ptr) _ptr_ = (ptr); \ - (ptr) = NULL; \ - _ptr_; \ - }) diff --git a/src/systemd/src/basic/async.h b/src/systemd/src/basic/async.h index 01c975bb..9bd13ff6 100644 --- a/src/systemd/src/basic/async.h +++ b/src/systemd/src/basic/async.h @@ -1,4 +1,3 @@ -/* SPDX-License-Identifier: LGPL-2.1+ */ #pragma once /*** @@ -22,5 +21,5 @@ int asynchronous_job(void* (*func)(void *p), void *arg); -int asynchronous_sync(pid_t *ret_pid); +int asynchronous_sync(void); int asynchronous_close(int fd); diff --git a/src/systemd/src/basic/escape.c b/src/systemd/src/basic/escape.c index fac618dd..27a20702 100644 --- a/src/systemd/src/basic/escape.c +++ b/src/systemd/src/basic/escape.c @@ -1,4 +1,3 @@ -/* SPDX-License-Identifier: LGPL-2.1+ */ /*** This file is part of systemd. diff --git a/src/systemd/src/basic/escape.h b/src/systemd/src/basic/escape.h index cd5c49fa..e62347af 100644 --- a/src/systemd/src/basic/escape.h +++ b/src/systemd/src/basic/escape.h @@ -1,4 +1,3 @@ -/* SPDX-License-Identifier: LGPL-2.1+ */ #pragma once /*** diff --git a/src/systemd/src/basic/ether-addr-util.c b/src/systemd/src/basic/ether-addr-util.c index 93922a28..a793219c 100644 --- a/src/systemd/src/basic/ether-addr-util.c +++ b/src/systemd/src/basic/ether-addr-util.c @@ -1,4 +1,3 @@ -/* SPDX-License-Identifier: LGPL-2.1+ */ /*** This file is part of systemd. @@ -20,7 +19,6 @@ #include "nm-sd-adapt.h" -#include <errno.h> #include <net/ethernet.h> #include <stdio.h> #include <sys/types.h> @@ -74,7 +72,7 @@ int ether_addr_from_string(const char *s, struct ether_addr *ret, size_t *offset if (s[pos] == '\0') \ break; \ hexoff = strchr(hex, s[pos]); \ - if (!hexoff) \ + if (hexoff == NULL) \ break; \ assert(hexoff >= hex); \ x = hexoff - hex; \ @@ -102,7 +100,7 @@ int ether_addr_from_string(const char *s, struct ether_addr *ret, size_t *offset sep = s[strspn(s, hex)]; if (sep == '\n') return -EINVAL; - if (!strchr(":.-", sep)) + if (strchr(":.-", sep) == NULL) return -EINVAL; if (sep == '.') { diff --git a/src/systemd/src/basic/ether-addr-util.h b/src/systemd/src/basic/ether-addr-util.h index 08d05a13..74e125a9 100644 --- a/src/systemd/src/basic/ether-addr-util.h +++ b/src/systemd/src/basic/ether-addr-util.h @@ -1,4 +1,3 @@ -/* SPDX-License-Identifier: LGPL-2.1+ */ #pragma once /*** diff --git a/src/systemd/src/basic/extract-word.c b/src/systemd/src/basic/extract-word.c index e52c376b..69d8c48d 100644 --- a/src/systemd/src/basic/extract-word.c +++ b/src/systemd/src/basic/extract-word.c @@ -1,4 +1,3 @@ -/* SPDX-License-Identifier: LGPL-2.1+ */ /*** This file is part of systemd. @@ -196,7 +195,8 @@ finish: finish_force_next: s[sz] = 0; - *ret = TAKE_PTR(s); + *ret = s; + s = NULL; return 1; } diff --git a/src/systemd/src/basic/extract-word.h b/src/systemd/src/basic/extract-word.h index 300c51bb..04746c6d 100644 --- a/src/systemd/src/basic/extract-word.h +++ b/src/systemd/src/basic/extract-word.h @@ -1,4 +1,3 @@ -/* SPDX-License-Identifier: LGPL-2.1+ */ #pragma once /*** diff --git a/src/systemd/src/basic/fd-util.c b/src/systemd/src/basic/fd-util.c index ff480f51..1c327d83 100644 --- a/src/systemd/src/basic/fd-util.c +++ b/src/systemd/src/basic/fd-util.c @@ -1,4 +1,3 @@ -/* SPDX-License-Identifier: LGPL-2.1+ */ /*** This file is part of systemd. @@ -29,10 +28,8 @@ #include "dirent-util.h" #include "fd-util.h" -#include "fileio.h" #include "fs-util.h" #include "macro.h" -#include "memfd-util.h" #include "missing.h" #include "parse-util.h" #include "path-util.h" @@ -194,6 +191,12 @@ int fd_cloexec(int fd, bool cloexec) { } #if 0 /* NM_IGNORED */ +void stdio_unset_cloexec(void) { + fd_cloexec(STDIN_FILENO, false); + fd_cloexec(STDOUT_FILENO, false); + fd_cloexec(STDERR_FILENO, false); +} + _pure_ static bool fd_in_set(int fd, const int fdset[], unsigned n_fdset) { unsigned i; @@ -224,21 +227,20 @@ int close_all_fds(const int except[], unsigned n_except) { assert_se(getrlimit(RLIMIT_NOFILE, &rl) >= 0); for (fd = 3; fd < (int) rl.rlim_max; fd ++) { - int q; if (fd_in_set(fd, except, n_except)) continue; - q = close_nointr(fd); - if (q < 0 && q != -EBADF && r >= 0) - r = q; + if (close_nointr(fd) < 0) + if (errno != EBADF && r == 0) + r = -errno; } return r; } FOREACH_DIRENT(de, d, return -errno) { - int fd = -1, q; + int fd = -1; if (safe_atoi(de->d_name, &fd) < 0) /* Let's better ignore this, just in case */ @@ -253,9 +255,11 @@ int close_all_fds(const int except[], unsigned n_except) { if (fd_in_set(fd, except, n_except)) continue; - q = close_nointr(fd); - if (q < 0 && q != -EBADF && r >= 0) /* Valgrind has its own FD and doesn't want to have it closed */ - r = q; + if (close_nointr(fd) < 0) { + /* Valgrind has its own FD and doesn't want to have it closed */ + if (errno != EBADF && r == 0) + r = -errno; + } } return r; @@ -365,384 +369,15 @@ bool fdname_is_valid(const char *s) { } int fd_get_path(int fd, char **ret) { - _cleanup_close_ int dir = -1; - char fdname[DECIMAL_STR_MAX(int)]; + char procfs_path[strlen("/proc/self/fd/") + DECIMAL_STR_MAX(int)]; int r; - dir = open("/proc/self/fd/", O_CLOEXEC | O_DIRECTORY | O_PATH); - if (dir < 0) - /* /proc is not available or not set up properly, we're most likely - * in some chroot environment. */ - return errno == ENOENT ? -EOPNOTSUPP : -errno; + xsprintf(procfs_path, "/proc/self/fd/%i", fd); - xsprintf(fdname, "%i", fd); + r = readlink_malloc(procfs_path, ret); - r = readlinkat_malloc(dir, fdname, ret); - if (r == -ENOENT) - /* If the file doesn't exist the fd is invalid */ + if (r == -ENOENT) /* If the file doesn't exist the fd is invalid */ return -EBADF; return r; } - -#if 0 /* NM_IGNORED */ -int move_fd(int from, int to, int cloexec) { - int r; - - /* Move fd 'from' to 'to', make sure FD_CLOEXEC remains equal if requested, and release the old fd. If - * 'cloexec' is passed as -1, the original FD_CLOEXEC is inherited for the new fd. If it is 0, it is turned - * off, if it is > 0 it is turned on. */ - - if (from < 0) - return -EBADF; - if (to < 0) - return -EBADF; - - if (from == to) { - - if (cloexec >= 0) { - r = fd_cloexec(to, cloexec); - if (r < 0) - return r; - } - - return to; - } - - if (cloexec < 0) { - int fl; - - fl = fcntl(from, F_GETFD, 0); - if (fl < 0) - return -errno; - - cloexec = !!(fl & FD_CLOEXEC); - } - - r = dup3(from, to, cloexec ? O_CLOEXEC : 0); - if (r < 0) - return -errno; - - assert(r == to); - - safe_close(from); - - return to; -} - -int acquire_data_fd(const void *data, size_t size, unsigned flags) { - - _cleanup_close_pair_ int pipefds[2] = { -1, -1 }; - char pattern[] = "/dev/shm/data-fd-XXXXXX"; - _cleanup_close_ int fd = -1; - int isz = 0, r; - ssize_t n; - off_t f; - - assert(data || size == 0); - - /* Acquire a read-only file descriptor that when read from returns the specified data. This is much more - * complex than I wish it was. But here's why: - * - * a) First we try to use memfds. They are the best option, as we can seal them nicely to make them - * read-only. Unfortunately they require kernel 3.17, and – at the time of writing – we still support 3.14. - * - * b) Then, we try classic pipes. They are the second best options, as we can close the writing side, retaining - * a nicely read-only fd in the reading side. However, they are by default quite small, and unprivileged - * clients can only bump their size to a system-wide limit, which might be quite low. - * - * c) Then, we try an O_TMPFILE file in /dev/shm (that dir is the only suitable one known to exist from - * earliest boot on). To make it read-only we open the fd a second time with O_RDONLY via - * /proc/self/<fd>. Unfortunately O_TMPFILE is not available on older kernels on tmpfs. - * - * d) Finally, we try creating a regular file in /dev/shm, which we then delete. - * - * It sucks a bit that depending on the situation we return very different objects here, but that's Linux I - * figure. */ - - if (size == 0 && ((flags & ACQUIRE_NO_DEV_NULL) == 0)) { - /* As a special case, return /dev/null if we have been called for an empty data block */ - r = open("/dev/null", O_RDONLY|O_CLOEXEC|O_NOCTTY); - if (r < 0) - return -errno; - - return r; - } - - if ((flags & ACQUIRE_NO_MEMFD) == 0) { - fd = memfd_new("data-fd"); - if (fd < 0) - goto try_pipe; - - n = write(fd, data, size); - if (n < 0) - return -errno; - if ((size_t) n != size) - return -EIO; - - f = lseek(fd, 0, SEEK_SET); - if (f != 0) - return -errno; - - r = memfd_set_sealed(fd); - if (r < 0) - return r; - - return TAKE_FD(fd); - } - -try_pipe: - if ((flags & ACQUIRE_NO_PIPE) == 0) { - if (pipe2(pipefds, O_CLOEXEC|O_NONBLOCK) < 0) - return -errno; - - isz = fcntl(pipefds[1], F_GETPIPE_SZ, 0); - if (isz < 0) - return -errno; - - if ((size_t) isz < size) { - isz = (int) size; - if (isz < 0 || (size_t) isz != size) - return -E2BIG; - - /* Try to bump the pipe size */ - (void) fcntl(pipefds[1], F_SETPIPE_SZ, isz); - - /* See if that worked */ - isz = fcntl(pipefds[1], F_GETPIPE_SZ, 0); - if (isz < 0) - return -errno; - - if ((size_t) isz < size) - goto try_dev_shm; - } - - n = write(pipefds[1], data, size); - if (n < 0) - return -errno; - if ((size_t) n != size) - return -EIO; - - (void) fd_nonblock(pipefds[0], false); - - return TAKE_FD(pipefds[0]); - } - -try_dev_shm: - if ((flags & ACQUIRE_NO_TMPFILE) == 0) { - fd = open("/dev/shm", O_RDWR|O_TMPFILE|O_CLOEXEC, 0500); - if (fd < 0) - goto try_dev_shm_without_o_tmpfile; - - n = write(fd, data, size); - if (n < 0) - return -errno; - if ((size_t) n != size) - return -EIO; - - /* Let's reopen the thing, in order to get an O_RDONLY fd for the original O_RDWR one */ - return fd_reopen(fd, O_RDONLY|O_CLOEXEC); - } - -try_dev_shm_without_o_tmpfile: - if ((flags & ACQUIRE_NO_REGULAR) == 0) { - fd = mkostemp_safe(pattern); - if (fd < 0) - return fd; - - n = write(fd, data, size); - if (n < 0) { - r = -errno; - goto unlink_and_return; - } - if ((size_t) n != size) { - r = -EIO; - goto unlink_and_return; - } - - /* Let's reopen the thing, in order to get an O_RDONLY fd for the original O_RDWR one */ - r = open(pattern, O_RDONLY|O_CLOEXEC); - if (r < 0) - r = -errno; - - unlink_and_return: - (void) unlink(pattern); - return r; - } - - return -EOPNOTSUPP; -} -#endif /* NM_IGNORED */ - -int fd_move_above_stdio(int fd) { - int flags, copy; - PROTECT_ERRNO; - - /* Moves the specified file descriptor if possible out of the range [0…2], i.e. the range of - * stdin/stdout/stderr. If it can't be moved outside of this range the original file descriptor is - * returned. This call is supposed to be used for long-lasting file descriptors we allocate in our code that - * might get loaded into foreign code, and where we want ensure our fds are unlikely used accidentally as - * stdin/stdout/stderr of unrelated code. - * - * Note that this doesn't fix any real bugs, it just makes it less likely that our code will be affected by - * buggy code from others that mindlessly invokes 'fprintf(stderr, …' or similar in places where stderr has - * been closed before. - * - * This function is written in a "best-effort" and "least-impact" style. This means whenever we encounter an - * error we simply return the original file descriptor, and we do not touch errno. */ - - if (fd < 0 || fd > 2) - return fd; - - flags = fcntl(fd, F_GETFD, 0); - if (flags < 0) - return fd; - - if (flags & FD_CLOEXEC) - copy = fcntl(fd, F_DUPFD_CLOEXEC, 3); - else - copy = fcntl(fd, F_DUPFD, 3); - if (copy < 0) - return fd; - - assert(copy > 2); - - (void) close(fd); - return copy; -} - -#if 0 /* NM_IGNORED */ -int rearrange_stdio(int original_input_fd, int original_output_fd, int original_error_fd) { - - int fd[3] = { /* Put together an array of fds we work on */ - original_input_fd, - original_output_fd, - original_error_fd - }; - - int r, i, - null_fd = -1, /* if we open /dev/null, we store the fd to it here */ - copy_fd[3] = { -1, -1, -1 }; /* This contains all fds we duplicate here temporarily, and hence need to close at the end */ - bool null_readable, null_writable; - - /* Sets up stdin, stdout, stderr with the three file descriptors passed in. If any of the descriptors is - * specified as -1 it will be connected with /dev/null instead. If any of the file descriptors is passed as - * itself (e.g. stdin as STDIN_FILENO) it is left unmodified, but the O_CLOEXEC bit is turned off should it be - * on. - * - * Note that if any of the passed file descriptors are > 2 they will be closed — both on success and on - * failure! Thus, callers should assume that when this function returns the input fds are invalidated. - * - * Note that when this function fails stdin/stdout/stderr might remain half set up! - * - * O_CLOEXEC is turned off for all three file descriptors (which is how it should be for - * stdin/stdout/stderr). */ - - null_readable = original_input_fd < 0; - null_writable = original_output_fd < 0 || original_error_fd < 0; - - /* First step, open /dev/null once, if we need it */ - if (null_readable || null_writable) { - - /* Let's open this with O_CLOEXEC first, and convert it to non-O_CLOEXEC when we move the fd to the final position. */ - null_fd = open("/dev/null", (null_readable && null_writable ? O_RDWR : - null_readable ? O_RDONLY : O_WRONLY) | O_CLOEXEC); - if (null_fd < 0) { - r = -errno; - goto finish; - } - - /* If this fd is in the 0…2 range, let's move it out of it */ - if (null_fd < 3) { - int copy; - - copy = fcntl(null_fd, F_DUPFD_CLOEXEC, 3); /* Duplicate this with O_CLOEXEC set */ - if (copy < 0) { - r = -errno; - goto finish; - } - - safe_close(null_fd); - null_fd = copy; - } - } - - /* Let's assemble fd[] with the fds to install in place of stdin/stdout/stderr */ - for (i = 0; i < 3; i++) { - - if (fd[i] < 0) - fd[i] = null_fd; /* A negative parameter means: connect this one to /dev/null */ - else if (fd[i] != i && fd[i] < 3) { - /* This fd is in the 0…2 territory, but not at its intended place, move it out of there, so that we can work there. */ - copy_fd[i] = fcntl(fd[i], F_DUPFD_CLOEXEC, 3); /* Duplicate this with O_CLOEXEC set */ - if (copy_fd[i] < 0) { - r = -errno; - goto finish; - } - - fd[i] = copy_fd[i]; - } - } - - /* At this point we now have the fds to use in fd[], and they are all above the stdio range, so that we - * have freedom to move them around. If the fds already were at the right places then the specific fds are - * -1. Let's now move them to the right places. This is the point of no return. */ - for (i = 0; i < 3; i++) { - - if (fd[i] == i) { - - /* fd is already in place, but let's make sure O_CLOEXEC is off */ - r = fd_cloexec(i, false); - if (r < 0) - goto finish; - - } else { - assert(fd[i] > 2); - - if (dup2(fd[i], i) < 0) { /* Turns off O_CLOEXEC on the new fd. */ - r = -errno; - goto finish; - } - } - } - - r = 0; - -finish: - /* Close the original fds, but only if they were outside of the stdio range. Also, properly check for the same - * fd passed in multiple times. */ - safe_close_above_stdio(original_input_fd); - if (original_output_fd != original_input_fd) - safe_close_above_stdio(original_output_fd); - if (original_error_fd != original_input_fd && original_error_fd != original_output_fd) - safe_close_above_stdio(original_error_fd); - - /* Close the copies we moved > 2 */ - for (i = 0; i < 3; i++) - safe_close(copy_fd[i]); - - /* Close our null fd, if it's > 2 */ - safe_close_above_stdio(null_fd); - - return r; -} - -int fd_reopen(int fd, int flags) { - char procfs_path[STRLEN("/proc/self/fd/") + DECIMAL_STR_MAX(int)]; - int new_fd; - - /* Reopens the specified fd with new flags. This is useful for convert an O_PATH fd into a regular one, or to - * turn O_RDWR fds into O_RDONLY fds. - * - * This doesn't work on sockets (since they cannot be open()ed, ever). - * - * This implicitly resets the file read index to 0. */ - - xsprintf(procfs_path, "/proc/self/fd/%i", fd); - new_fd = open(procfs_path, flags); - if (new_fd < 0) - return -errno; - - return new_fd; -} -#endif /* NM_IGNORED */ diff --git a/src/systemd/src/basic/fd-util.h b/src/systemd/src/basic/fd-util.h index 163b096b..34b98d4a 100644 --- a/src/systemd/src/basic/fd-util.h +++ b/src/systemd/src/basic/fd-util.h @@ -1,4 +1,3 @@ -/* SPDX-License-Identifier: LGPL-2.1+ */ #pragma once /*** @@ -35,13 +34,6 @@ int close_nointr(int fd); int safe_close(int fd); void safe_close_pair(int p[]); -static inline int safe_close_above_stdio(int fd) { - if (fd < 3) /* Don't close stdin/stdout/stderr, but still invalidate the fd by returning -1 */ - return -1; - - return safe_close(fd); -} - void close_many(const int fds[], unsigned n_fd); int fclose_nointr(FILE *f); @@ -71,6 +63,7 @@ DEFINE_TRIVIAL_CLEANUP_FUNC(DIR*, closedir); int fd_nonblock(int fd, bool nonblock); int fd_cloexec(int fd, bool cloexec); +void stdio_unset_cloexec(void); int close_all_fds(const int except[], unsigned n_except); @@ -82,36 +75,6 @@ bool fdname_is_valid(const char *s); int fd_get_path(int fd, char **ret); -int move_fd(int from, int to, int cloexec); - -enum { - ACQUIRE_NO_DEV_NULL = 1 << 0, - ACQUIRE_NO_MEMFD = 1 << 1, - ACQUIRE_NO_PIPE = 1 << 2, - ACQUIRE_NO_TMPFILE = 1 << 3, - ACQUIRE_NO_REGULAR = 1 << 4, -}; - -int acquire_data_fd(const void *data, size_t size, unsigned flags); - /* Hint: ENETUNREACH happens if we try to connect to "non-existing" special IP addresses, such as ::5 */ #define ERRNO_IS_DISCONNECT(r) \ IN_SET(r, ENOTCONN, ECONNRESET, ECONNREFUSED, ECONNABORTED, EPIPE, ENETUNREACH) - -int fd_move_above_stdio(int fd); - -int rearrange_stdio(int original_input_fd, int original_output_fd, int original_error_fd); - -static inline int make_null_stdio(void) { - return rearrange_stdio(-1, -1, -1); -} - -/* Like TAKE_PTR() but for file descriptors, resetting them to -1 */ -#define TAKE_FD(fd) \ - ({ \ - int _fd_ = (fd); \ - (fd) = -1; \ - _fd_; \ - }) - -int fd_reopen(int fd, int flags); diff --git a/src/systemd/src/basic/fileio.c b/src/systemd/src/basic/fileio.c index c7b4b241..51d1c052 100644 --- a/src/systemd/src/basic/fileio.c +++ b/src/systemd/src/basic/fileio.c @@ -1,4 +1,3 @@ -/* SPDX-License-Identifier: LGPL-2.1+ */ /*** This file is part of systemd. @@ -25,10 +24,8 @@ #include <limits.h> #include <stdarg.h> #include <stdint.h> -#include <stdio_ext.h> #include <stdlib.h> #include <string.h> -#include <sys/mman.h> #include <sys/stat.h> #include <sys/types.h> #include <unistd.h> @@ -65,30 +62,12 @@ int write_string_stream_ts( WriteStringFileFlags flags, struct timespec *ts) { - bool needs_nl; - assert(f); assert(line); - if (ferror(f)) - return -EIO; - - needs_nl = !(flags & WRITE_STRING_FILE_AVOID_NEWLINE) && !endswith(line, "\n"); - - if (needs_nl && (flags & WRITE_STRING_FILE_DISABLE_BUFFER)) { - /* If STDIO buffering was disabled, then let's append the newline character to the string itself, so - * that the write goes out in one go, instead of two */ - - line = strjoina(line, "\n"); - needs_nl = false; - } - - if (fputs(line, f) == EOF) - return -errno; - - if (needs_nl) - if (fputc('\n', f) == EOF) - return -errno; + fputs(line, f); + if (!(flags & WRITE_STRING_FILE_AVOID_NEWLINE) && !endswith(line, "\n")) + fputc('\n', f); if (ts) { struct timespec twice[2] = {*ts, *ts}; @@ -120,7 +99,6 @@ static int write_string_file_atomic( if (r < 0) return r; - (void) __fsetlocking(f, FSETLOCKING_BYCALLER); (void) fchmod_umask(fileno(f), 0644); r = write_string_stream_ts(f, line, flags, ts); @@ -163,7 +141,7 @@ int write_string_file_ts( return r; } else - assert(!ts); + assert(ts == NULL); if (flags & WRITE_STRING_FILE_CREATE) { f = fopen(fn, "we"); @@ -190,11 +168,6 @@ int write_string_file_ts( } } - (void) __fsetlocking(f, FSETLOCKING_BYCALLER); - - if (flags & WRITE_STRING_FILE_DISABLE_BUFFER) - setvbuf(f, NULL, _IONBF, 0); - r = write_string_stream_ts(f, line, flags, ts); if (r < 0) goto fail; @@ -228,11 +201,10 @@ int read_one_line_file(const char *fn, char **line) { if (!f) return -errno; - (void) __fsetlocking(f, FSETLOCKING_BYCALLER); - r = read_line(f, LONG_LINE_MAX, line); return r < 0 ? r : 0; } +#endif /* NM_IGNORED */ int verify_file(const char *fn, const char *blob, bool accept_extra_nl) { _cleanup_fclose_ FILE *f = NULL; @@ -255,8 +227,6 @@ int verify_file(const char *fn, const char *blob, bool accept_extra_nl) { if (!f) return -errno; - (void) __fsetlocking(f, FSETLOCKING_BYCALLER); - /* We try to read one byte more than we need, so that we know whether we hit eof */ errno = 0; k = fread(buf, 1, l + accept_extra_nl + 1, f); @@ -272,7 +242,6 @@ int verify_file(const char *fn, const char *blob, bool accept_extra_nl) { return 1; } -#endif /* NM_IGNORED */ int read_full_stream(FILE *f, char **contents, size_t *size) { size_t n, l; @@ -334,7 +303,8 @@ int read_full_stream(FILE *f, char **contents, size_t *size) { } buf[l] = 0; - *contents = TAKE_PTR(buf); + *contents = buf; + buf = NULL; /* do not free */ if (size) *size = l; @@ -352,8 +322,6 @@ int read_full_file(const char *fn, char **contents, size_t *size) { if (!f) return -errno; - (void) __fsetlocking(f, FSETLOCKING_BYCALLER); - return read_full_stream(f, contents, size); } @@ -366,11 +334,11 @@ static int parse_env_file_internal( void *userdata, int *n_pushed) { + _cleanup_free_ char *contents = NULL, *key = NULL; size_t key_alloc = 0, n_key = 0, value_alloc = 0, n_value = 0, last_value_whitespace = (size_t) -1, last_key_whitespace = (size_t) -1; - _cleanup_free_ char *contents = NULL, *key = NULL, *value = NULL; - unsigned line = 1; - char *p; + char *p, *value = NULL; int r; + unsigned line = 1; enum { PRE_KEY, @@ -407,8 +375,10 @@ static int parse_env_file_internal( state = KEY; last_key_whitespace = (size_t) -1; - if (!GREEDY_REALLOC(key, key_alloc, n_key+2)) - return -ENOMEM; + if (!GREEDY_REALLOC(key, key_alloc, n_key+2)) { + r = -ENOMEM; + goto fail; + } key[n_key++] = c; } @@ -428,8 +398,10 @@ static int parse_env_file_internal( else if (last_key_whitespace == (size_t) -1) last_key_whitespace = n_key; - if (!GREEDY_REALLOC(key, key_alloc, n_key+2)) - return -ENOMEM; + if (!GREEDY_REALLOC(key, key_alloc, n_key+2)) { + r = -ENOMEM; + goto fail; + } key[n_key++] = c; } @@ -451,7 +423,7 @@ static int parse_env_file_internal( r = push(fname, line, key, value, userdata, n_pushed); if (r < 0) - return r; + goto fail; n_key = 0; value = NULL; @@ -466,8 +438,10 @@ static int parse_env_file_internal( else if (!strchr(WHITESPACE, c)) { state = VALUE; - if (!GREEDY_REALLOC(value, value_alloc, n_value+2)) - return -ENOMEM; + if (!GREEDY_REALLOC(value, value_alloc, n_value+2)) { + r = -ENOMEM; + goto fail; + } value[n_value++] = c; } @@ -494,7 +468,7 @@ static int parse_env_file_internal( r = push(fname, line, key, value, userdata, n_pushed); if (r < 0) - return r; + goto fail; n_key = 0; value = NULL; @@ -509,8 +483,10 @@ static int parse_env_file_internal( else if (last_value_whitespace == (size_t) -1) last_value_whitespace = n_value; - if (!GREEDY_REALLOC(value, value_alloc, n_value+2)) - return -ENOMEM; + if (!GREEDY_REALLOC(value, value_alloc, n_value+2)) { + r = -ENOMEM; + goto fail; + } value[n_value++] = c; } @@ -522,8 +498,10 @@ static int parse_env_file_internal( if (!strchr(newline, c)) { /* Escaped newlines we eat up entirely */ - if (!GREEDY_REALLOC(value, value_alloc, n_value+2)) - return -ENOMEM; + if (!GREEDY_REALLOC(value, value_alloc, n_value+2)) { + r = -ENOMEM; + goto fail; + } value[n_value++] = c; } @@ -535,8 +513,10 @@ static int parse_env_file_internal( else if (c == '\\') state = SINGLE_QUOTE_VALUE_ESCAPE; else { - if (!GREEDY_REALLOC(value, value_alloc, n_value+2)) - return -ENOMEM; + if (!GREEDY_REALLOC(value, value_alloc, n_value+2)) { + r = -ENOMEM; + goto fail; + } value[n_value++] = c; } @@ -547,8 +527,10 @@ static int parse_env_file_internal( state = SINGLE_QUOTE_VALUE; if (!strchr(newline, c)) { - if (!GREEDY_REALLOC(value, value_alloc, n_value+2)) - return -ENOMEM; + if (!GREEDY_REALLOC(value, value_alloc, n_value+2)) { + r = -ENOMEM; + goto fail; + } value[n_value++] = c; } @@ -560,8 +542,10 @@ static int parse_env_file_internal( else if (c == '\\') state = DOUBLE_QUOTE_VALUE_ESCAPE; else { - if (!GREEDY_REALLOC(value, value_alloc, n_value+2)) - return -ENOMEM; + if (!GREEDY_REALLOC(value, value_alloc, n_value+2)) { + r = -ENOMEM; + goto fail; + } value[n_value++] = c; } @@ -572,8 +556,10 @@ static int parse_env_file_internal( state = DOUBLE_QUOTE_VALUE; if (!strchr(newline, c)) { - if (!GREEDY_REALLOC(value, value_alloc, n_value+2)) - return -ENOMEM; + if (!GREEDY_REALLOC(value, value_alloc, n_value+2)) { + r = -ENOMEM; + goto fail; + } value[n_value++] = c; } @@ -618,12 +604,14 @@ static int parse_env_file_internal( r = push(fname, line, key, value, userdata, n_pushed); if (r < 0) - return r; - - value = NULL; + goto fail; } return 0; + +fail: + free(value); + return r; } static int check_utf8ness_and_warn( @@ -891,8 +879,7 @@ int write_env_file(const char *fname, char **l) { if (r < 0) return r; - (void) __fsetlocking(f, FSETLOCKING_BYCALLER); - (void) fchmod_umask(fileno(f), 0644); + fchmod_umask(fileno(f), 0644); STRV_FOREACH(i, l) write_env_var(f, *i); @@ -910,16 +897,14 @@ int write_env_file(const char *fname, char **l) { } int executable_is_script(const char *path, char **interpreter) { + int r; _cleanup_free_ char *line = NULL; - size_t len; + int len; char *ans; - int r; assert(path); r = read_one_line_file(path, &line); - if (r == -ENOBUFS) /* First line overly long? if so, then it's not a script */ - return 0; if (r < 0) return r; @@ -1162,7 +1147,6 @@ int fflush_and_check(FILE *f) { return 0; } -#if 0 /* NM_IGNORED */ int fflush_sync_and_check(FILE *f) { int r; @@ -1175,13 +1159,8 @@ int fflush_sync_and_check(FILE *f) { if (fsync(fileno(f)) < 0) return -errno; - r = fsync_directory_of_file(fileno(f)); - if (r < 0) - return r; - return 0; } -#endif /* NM_IGNORED */ /* This is much like mkostemp() but is subject to umask(). */ int mkostemp_safe(char *pattern) { @@ -1218,7 +1197,8 @@ int tempfn_xxxxxx(const char *p, const char *extra, char **ret) { if (!filename_is_valid(fn)) return -EINVAL; - extra = strempty(extra); + if (extra == NULL) + extra = ""; t = new(char, strlen(p) + 2 + strlen(extra) + 6 + 1); if (!t) @@ -1252,7 +1232,8 @@ int tempfn_random(const char *p, const char *extra, char **ret) { if (!filename_is_valid(fn)) return -EINVAL; - extra = strempty(extra); + if (!extra) + extra = ""; t = new(char, strlen(p) + 2 + strlen(extra) + 16 + 1); if (!t) @@ -1292,7 +1273,8 @@ int tempfn_random_child(const char *p, const char *extra, char **ret) { return r; } - extra = strempty(extra); + if (!extra) + extra = ""; t = new(char, strlen(p) + 3 + strlen(extra) + 16 + 1); if (!t) @@ -1444,7 +1426,8 @@ int open_tmpfile_linkable(const char *target, int flags, char **ret_path) { if (fd < 0) return -errno; - *ret_path = TAKE_PTR(tmp); + *ret_path = tmp; + tmp = NULL; return fd; } @@ -1484,7 +1467,7 @@ int link_tmpfile(int fd, const char *path, const char *target) { if (rename_noreplace(AT_FDCWD, path, AT_FDCWD, target) < 0) return -errno; } else { - char proc_fd_path[STRLEN("/proc/self/fd/") + DECIMAL_STR_MAX(fd) + 1]; + char proc_fd_path[strlen("/proc/self/fd/") + DECIMAL_STR_MAX(fd) + 1]; xsprintf(proc_fd_path, "/proc/self/fd/%i", fd); @@ -1530,7 +1513,8 @@ int read_nul_string(FILE *f, char **ret) { return -ENOMEM; } - *ret = TAKE_PTR(x); + *ret = x; + x = NULL; return 0; } @@ -1554,7 +1538,9 @@ int mkdtemp_malloc(const char *template, char **ret) { return 0; } -DEFINE_TRIVIAL_CLEANUP_FUNC(FILE*, funlockfile); +static inline void funlockfilep(FILE **f) { + funlockfile(*f); +} int read_line(FILE *f, size_t limit, char **ret) { _cleanup_free_ char *buffer = NULL; @@ -1581,7 +1567,7 @@ int read_line(FILE *f, size_t limit, char **ret) { } { - _unused_ _cleanup_(funlockfilep) FILE *flocked = f; + _cleanup_(funlockfilep) FILE *flocked = f; flockfile(f); for (;;) { diff --git a/src/systemd/src/basic/fileio.h b/src/systemd/src/basic/fileio.h index da5d5c66..eba05be2 100644 --- a/src/systemd/src/basic/fileio.h +++ b/src/systemd/src/basic/fileio.h @@ -1,4 +1,3 @@ -/* SPDX-License-Identifier: LGPL-2.1+ */ #pragma once /*** @@ -30,17 +29,11 @@ #include "time-util.h" typedef enum { - WRITE_STRING_FILE_CREATE = 1<<0, - WRITE_STRING_FILE_ATOMIC = 1<<1, - WRITE_STRING_FILE_AVOID_NEWLINE = 1<<2, + WRITE_STRING_FILE_CREATE = 1<<0, + WRITE_STRING_FILE_ATOMIC = 1<<1, + WRITE_STRING_FILE_AVOID_NEWLINE = 1<<2, WRITE_STRING_FILE_VERIFY_ON_FAILURE = 1<<3, - WRITE_STRING_FILE_SYNC = 1<<4, - WRITE_STRING_FILE_DISABLE_BUFFER = 1<<5, - - /* And before you wonder, why write_string_file_atomic_label_ts() is a separate function instead of just one - more flag here: it's about linking: we don't want to pull -lselinux into all users of write_string_file() - and friends. */ - + WRITE_STRING_FILE_SYNC = 1<<4, } WriteStringFileFlags; int write_string_stream_ts(FILE *f, const char *line, WriteStringFileFlags flags, struct timespec *ts); diff --git a/src/systemd/src/basic/fs-util.c b/src/systemd/src/basic/fs-util.c index ffd9996a..ff4ad5ab 100644 --- a/src/systemd/src/basic/fs-util.c +++ b/src/systemd/src/basic/fs-util.c @@ -1,4 +1,3 @@ -/* SPDX-License-Identifier: LGPL-2.1+ */ /*** This file is part of systemd. @@ -41,7 +40,6 @@ #include "mkdir.h" #include "parse-util.h" #include "path-util.h" -#include "process-util.h" #include "stat-util.h" #include "stdio-util.h" #include "string-util.h" @@ -109,6 +107,7 @@ int rmdir_parents(const char *path, const char *stop) { return 0; } + int rename_noreplace(int olddirfd, const char *oldpath, int newdirfd, const char *newpath) { struct stat buf; int ret; @@ -230,6 +229,49 @@ int readlink_and_make_absolute(const char *p, char **r) { return 0; } +int readlink_and_canonicalize(const char *p, const char *root, char **ret) { + char *t, *s; + int r; + + assert(p); + assert(ret); + + r = readlink_and_make_absolute(p, &t); + if (r < 0) + return r; + + r = chase_symlinks(t, root, 0, &s); + if (r < 0) + /* If we can't follow up, then let's return the original string, slightly cleaned up. */ + *ret = path_kill_slashes(t); + else { + *ret = s; + free(t); + } + + return 0; +} + +int readlink_and_make_absolute_root(const char *root, const char *path, char **ret) { + _cleanup_free_ char *target = NULL, *t = NULL; + const char *full; + int r; + + full = prefix_roota(root, path); + r = readlink_malloc(full, &target); + if (r < 0) + return r; + + t = file_in_same_dir(path, target); + if (!t) + return -ENOMEM; + + *ret = t; + t = NULL; + + return 0; +} + int chmod_and_chown(const char *path, mode_t mode, uid_t uid, gid_t gid) { assert(path); @@ -280,60 +322,43 @@ int fd_warn_permissions(const char *path, int fd) { } int touch_file(const char *path, bool parents, usec_t stamp, uid_t uid, gid_t gid, mode_t mode) { - char fdpath[STRLEN("/proc/self/fd/") + DECIMAL_STR_MAX(int)]; - _cleanup_close_ int fd = -1; - int r, ret = 0; + _cleanup_close_ int fd; + int r; assert(path); - /* Note that touch_file() does not follow symlinks: if invoked on an existing symlink, then it is the symlink - * itself which is updated, not its target - * - * Returns the first error we encounter, but tries to apply as much as possible. */ - if (parents) - (void) mkdir_parents(path, 0755); - - /* Initially, we try to open the node with O_PATH, so that we get a reference to the node. This is useful in - * case the path refers to an existing device or socket node, as we can open it successfully in all cases, and - * won't trigger any driver magic or so. */ - fd = open(path, O_PATH|O_CLOEXEC|O_NOFOLLOW); - if (fd < 0) { - if (errno != ENOENT) - return -errno; + mkdir_parents(path, 0755); + + fd = open(path, O_WRONLY|O_CREAT|O_CLOEXEC|O_NOCTTY, + IN_SET(mode, 0, MODE_INVALID) ? 0644 : mode); + if (fd < 0) + return -errno; - /* if the node doesn't exist yet, we create it, but with O_EXCL, so that we only create a regular file - * here, and nothing else */ - fd = open(path, O_WRONLY|O_CREAT|O_EXCL|O_CLOEXEC, IN_SET(mode, 0, MODE_INVALID) ? 0644 : mode); - if (fd < 0) + if (mode != MODE_INVALID) { + r = fchmod(fd, mode); + if (r < 0) return -errno; } - /* Let's make a path from the fd, and operate on that. With this logic, we can adjust the access mode, - * ownership and time of the file node in all cases, even if the fd refers to an O_PATH object — which is - * something fchown(), fchmod(), futimensat() don't allow. */ - xsprintf(fdpath, "/proc/self/fd/%i", fd); - - if (mode != MODE_INVALID) - if (chmod(fdpath, mode) < 0) - ret = -errno; - - if (uid_is_valid(uid) || gid_is_valid(gid)) - if (chown(fdpath, uid, gid) < 0 && ret >= 0) - ret = -errno; + if (uid != UID_INVALID || gid != GID_INVALID) { + r = fchown(fd, uid, gid); + if (r < 0) + return -errno; + } if (stamp != USEC_INFINITY) { struct timespec ts[2]; timespec_store(&ts[0], stamp); ts[1] = ts[0]; - r = utimensat(AT_FDCWD, fdpath, ts, 0); + r = futimens(fd, ts); } else - r = utimensat(AT_FDCWD, fdpath, NULL, 0); - if (r < 0 && ret >= 0) + r = futimens(fd, NULL); + if (r < 0) return -errno; - return ret; + return 0; } int touch(const char *path) { @@ -465,8 +490,10 @@ int get_files_in_directory(const char *path, char ***list) { n++; } - if (list) - *list = TAKE_PTR(l); + if (list) { + *list = l; + l = NULL; /* avoid freeing */ + } return n; } @@ -489,7 +516,7 @@ static int getenv_tmp_dir(const char **ret_path) { r = -ENOTDIR; goto next; } - if (!path_is_normalized(e)) { + if (!path_is_safe(e)) { r = -EPERM; goto next; } @@ -559,19 +586,8 @@ int tmp_dir(const char **ret) { return tmp_dir_internal("/tmp", ret); } -int unlink_or_warn(const char *filename) { - if (unlink(filename) < 0 && errno != ENOENT) - /* If the file doesn't exist and the fs simply was read-only (in which - * case unlink() returns EROFS even if the file doesn't exist), don't - * complain */ - if (errno != EROFS || access(filename, F_OK) >= 0) - return log_error_errno(errno, "Failed to remove \"%s\": %m", filename); - - return 0; -} - int inotify_add_watch_fd(int fd, int what, uint32_t mask) { - char path[STRLEN("/proc/self/fd/") + DECIMAL_STR_MAX(int) + 1]; + char path[strlen("/proc/self/fd/") + DECIMAL_STR_MAX(int) + 1]; int r; /* This is like inotify_add_watch(), except that the file to watch is not referenced by a path, but by an fd */ @@ -584,39 +600,16 @@ int inotify_add_watch_fd(int fd, int what, uint32_t mask) { return r; } -static bool noop_root(const char *root) { - return isempty(root) || path_equal(root, "/"); -} - -static bool safe_transition(const struct stat *a, const struct stat *b) { - /* Returns true if the transition from a to b is safe, i.e. that we never transition from unprivileged to - * privileged files or directories. Why bother? So that unprivileged code can't symlink to privileged files - * making us believe we read something safe even though it isn't safe in the specific context we open it in. */ - - if (a->st_uid == 0) /* Transitioning from privileged to unprivileged is always fine */ - return true; - - return a->st_uid == b->st_uid; /* Otherwise we need to stay within the same UID */ -} - int chase_symlinks(const char *path, const char *original_root, unsigned flags, char **ret) { _cleanup_free_ char *buffer = NULL, *done = NULL, *root = NULL; _cleanup_close_ int fd = -1; unsigned max_follow = 32; /* how many symlinks to follow before giving up and returning ELOOP */ - struct stat previous_stat; bool exists = true; char *todo; int r; assert(path); - /* Either the file may be missing, or we return an fd to the final object, but both make no sense */ - if ((flags & (CHASE_NONEXISTENT|CHASE_OPEN)) == (CHASE_NONEXISTENT|CHASE_OPEN)) - return -EINVAL; - - if (isempty(path)) - return -EINVAL; - /* This is a lot like canonicalize_file_name(), but takes an additional "root" parameter, that allows following * symlinks relative to a root directory, instead of the root of the host. * @@ -635,35 +628,18 @@ int chase_symlinks(const char *path, const char *original_root, unsigned flags, * Suggested usage: whenever you want to canonicalize a path, use this function. Pass the absolute path you got * as-is: fully qualified and relative to your host's root. Optionally, specify the root parameter to tell this * function what to do when encountering a symlink with an absolute path as directory: prefix it by the - * specified path. */ - - /* A root directory of "/" or "" is identical to none */ - if (noop_root(original_root)) - original_root = NULL; - - if (!original_root && !ret && (flags & (CHASE_NONEXISTENT|CHASE_NO_AUTOFS|CHASE_SAFE|CHASE_OPEN)) == CHASE_OPEN) { - /* Shortcut the CHASE_OPEN case if the caller isn't interested in the actual path and has no root set - * and doesn't care about any of the other special features we provide either. */ - r = open(path, O_PATH|O_CLOEXEC); - if (r < 0) - return -errno; - - return r; - } + * specified path. + * + * Note: there's also chase_symlinks_prefix() (see below), which as first step prefixes the passed path by the + * passed root. */ if (original_root) { r = path_make_absolute_cwd(original_root, &root); if (r < 0) return r; - if (flags & CHASE_PREFIX_ROOT) { - - /* We don't support relative paths in combination with a root directory */ - if (!path_is_absolute(path)) - return -EINVAL; - + if (flags & CHASE_PREFIX_ROOT) path = prefix_roota(root, path); - } } r = path_make_absolute_cwd(path, &buffer); @@ -674,11 +650,6 @@ int chase_symlinks(const char *path, const char *original_root, unsigned flags, if (fd < 0) return -errno; - if (flags & CHASE_SAFE) { - if (fstat(fd, &previous_stat) < 0) - return -errno; - } - todo = buffer; for (;;) { _cleanup_free_ char *first = NULL; @@ -697,20 +668,9 @@ int chase_symlinks(const char *path, const char *original_root, unsigned flags, todo += m; - /* Empty? Then we reached the end. */ - if (isempty(first)) - break; - /* Just a single slash? Then we reached the end. */ - if (path_equal(first, "/")) { - /* Preserve the trailing slash */ - - if (flags & CHASE_TRAIL_SLASH) - if (!strextend(&done, "/", NULL)) - return -ENOMEM; - + if (isempty(first) || path_equal(first, "/")) break; - } /* Just a dot? Then let's eat this up. */ if (path_equal(first, "/.")) @@ -719,7 +679,7 @@ int chase_symlinks(const char *path, const char *original_root, unsigned flags, /* Two dots? Then chop off the last bit of what we already found out. */ if (path_equal(first, "/..")) { _cleanup_free_ char *parent = NULL; - _cleanup_close_ int fd_parent = -1; + int fd_parent = -1; /* If we already are at the top, then going up will not change anything. This is in-line with * how the kernel handles this. */ @@ -742,18 +702,8 @@ int chase_symlinks(const char *path, const char *original_root, unsigned flags, if (fd_parent < 0) return -errno; - if (flags & CHASE_SAFE) { - if (fstat(fd_parent, &st) < 0) - return -errno; - - if (!safe_transition(&previous_stat, &st)) - return -EPERM; - - previous_stat = st; - } - safe_close(fd); - fd = TAKE_FD(fd_parent); + fd = fd_parent; continue; } @@ -764,16 +714,12 @@ int chase_symlinks(const char *path, const char *original_root, unsigned flags, if (errno == ENOENT && (flags & CHASE_NONEXISTENT) && - (isempty(todo) || path_is_normalized(todo))) { + (isempty(todo) || path_is_safe(todo))) { /* If CHASE_NONEXISTENT is set, and the path does not exist, then that's OK, return * what we got so far. But don't allow this if the remaining path contains "../ or "./" * or something else weird. */ - /* If done is "/", as first also contains slash at the head, then remove this redundant slash. */ - if (streq_ptr(done, "/")) - *done = '\0'; - if (!strextend(&done, first, todo, NULL)) return -ENOMEM; @@ -786,14 +732,8 @@ int chase_symlinks(const char *path, const char *original_root, unsigned flags, if (fstat(child, &st) < 0) return -errno; - if ((flags & CHASE_SAFE) && - !safe_transition(&previous_stat, &st)) - return -EPERM; - - previous_stat = st; - if ((flags & CHASE_NO_AUTOFS) && - fd_is_fs_type(child, AUTOFS_SUPER_MAGIC) > 0) + fd_check_fstype(child, AUTOFS_SUPER_MAGIC) > 0) return -EREMOTE; if (S_ISLNK(st.st_mode)) { @@ -822,16 +762,6 @@ int chase_symlinks(const char *path, const char *original_root, unsigned flags, if (fd < 0) return -errno; - if (flags & CHASE_SAFE) { - if (fstat(fd, &st) < 0) - return -errno; - - if (!safe_transition(&previous_stat, &st)) - return -EPERM; - - previous_stat = st; - } - free(done); /* Note that we do not revalidate the root, we take it as is. */ @@ -843,11 +773,12 @@ int chase_symlinks(const char *path, const char *original_root, unsigned flags, return -ENOMEM; } - /* Prefix what's left to do with what we just read, and start the loop again, but - * remain in the current directory. */ - joined = strjoin(destination, todo); - } else - joined = strjoin("/", destination, todo); + } + + /* Prefix what's left to do with what we just read, and start the loop again, + * but remain in the current directory. */ + + joined = strjoin("/", destination, todo); if (!joined) return -ENOMEM; @@ -858,20 +789,18 @@ int chase_symlinks(const char *path, const char *original_root, unsigned flags, } /* If this is not a symlink, then let's just add the name we read to what we already verified. */ - if (!done) - done = TAKE_PTR(first); - else { - /* If done is "/", as first also contains slash at the head, then remove this redundant slash. */ - if (streq(done, "/")) - *done = '\0'; - + if (!done) { + done = first; + first = NULL; + } else { if (!strextend(&done, first, NULL)) return -ENOMEM; } /* And iterate again, but go one directory further down. */ safe_close(fd); - fd = TAKE_FD(child); + fd = child; + child = -1; } if (!done) { @@ -881,221 +810,11 @@ int chase_symlinks(const char *path, const char *original_root, unsigned flags, return -ENOMEM; } - if (ret) - *ret = TAKE_PTR(done); - - if (flags & CHASE_OPEN) { - /* Return the O_PATH fd we currently are looking to the caller. It can translate it to a proper fd by - * opening /proc/self/fd/xyz. */ - - assert(fd >= 0); - return TAKE_FD(fd); + if (ret) { + *ret = done; + done = NULL; } return exists; } - -int chase_symlinks_and_open( - const char *path, - const char *root, - unsigned chase_flags, - int open_flags, - char **ret_path) { - - _cleanup_close_ int path_fd = -1; - _cleanup_free_ char *p = NULL; - int r; - - if (chase_flags & CHASE_NONEXISTENT) - return -EINVAL; - - if (noop_root(root) && !ret_path && (chase_flags & (CHASE_NO_AUTOFS|CHASE_SAFE)) == 0) { - /* Shortcut this call if none of the special features of this call are requested */ - r = open(path, open_flags); - if (r < 0) - return -errno; - - return r; - } - - path_fd = chase_symlinks(path, root, chase_flags|CHASE_OPEN, ret_path ? &p : NULL); - if (path_fd < 0) - return path_fd; - - r = fd_reopen(path_fd, open_flags); - if (r < 0) - return r; - - if (ret_path) - *ret_path = TAKE_PTR(p); - - return r; -} - -int chase_symlinks_and_opendir( - const char *path, - const char *root, - unsigned chase_flags, - char **ret_path, - DIR **ret_dir) { - - char procfs_path[STRLEN("/proc/self/fd/") + DECIMAL_STR_MAX(int)]; - _cleanup_close_ int path_fd = -1; - _cleanup_free_ char *p = NULL; - DIR *d; - - if (!ret_dir) - return -EINVAL; - if (chase_flags & CHASE_NONEXISTENT) - return -EINVAL; - - if (noop_root(root) && !ret_path && (chase_flags & (CHASE_NO_AUTOFS|CHASE_SAFE)) == 0) { - /* Shortcut this call if none of the special features of this call are requested */ - d = opendir(path); - if (!d) - return -errno; - - *ret_dir = d; - return 0; - } - - path_fd = chase_symlinks(path, root, chase_flags|CHASE_OPEN, ret_path ? &p : NULL); - if (path_fd < 0) - return path_fd; - - xsprintf(procfs_path, "/proc/self/fd/%i", path_fd); - d = opendir(procfs_path); - if (!d) - return -errno; - - if (ret_path) - *ret_path = TAKE_PTR(p); - - *ret_dir = d; - return 0; -} - -int access_fd(int fd, int mode) { - char p[STRLEN("/proc/self/fd/") + DECIMAL_STR_MAX(fd) + 1]; - int r; - - /* Like access() but operates on an already open fd */ - - xsprintf(p, "/proc/self/fd/%i", fd); - r = access(p, mode); - if (r < 0) - return -errno; - - return r; -} - -int unlinkat_deallocate(int fd, const char *name, int flags) { - _cleanup_close_ int truncate_fd = -1; - struct stat st; - off_t l, bs; - - /* Operates like unlinkat() but also deallocates the file contents if it is a regular file and there's no other - * link to it. This is useful to ensure that other processes that might have the file open for reading won't be - * able to keep the data pinned on disk forever. This call is particular useful whenever we execute clean-up - * jobs ("vacuuming"), where we want to make sure the data is really gone and the disk space released and - * returned to the free pool. - * - * Deallocation is preferably done by FALLOC_FL_PUNCH_HOLE|FALLOC_FL_KEEP_SIZE (👊) if supported, which means - * the file won't change size. That's a good thing since we shouldn't needlessly trigger SIGBUS in other - * programs that have mmap()ed the file. (The assumption here is that changing file contents to all zeroes - * underneath those programs is the better choice than simply triggering SIGBUS in them which truncation does.) - * However if hole punching is not implemented in the kernel or file system we'll fall back to normal file - * truncation (🔪), as our goal of deallocating the data space trumps our goal of being nice to readers (💐). - * - * Note that we attempt deallocation, but failure to succeed with that is not considered fatal, as long as the - * primary job – to delete the file – is accomplished. */ - - if ((flags & AT_REMOVEDIR) == 0) { - truncate_fd = openat(fd, name, O_WRONLY|O_CLOEXEC|O_NOCTTY|O_NOFOLLOW|O_NONBLOCK); - if (truncate_fd < 0) { - - /* If this failed because the file doesn't exist propagate the error right-away. Also, - * AT_REMOVEDIR wasn't set, and we tried to open the file for writing, which means EISDIR is - * returned when this is a directory but we are not supposed to delete those, hence propagate - * the error right-away too. */ - if (IN_SET(errno, ENOENT, EISDIR)) - return -errno; - - if (errno != ELOOP) /* don't complain if this is a symlink */ - log_debug_errno(errno, "Failed to open file '%s' for deallocation, ignoring: %m", name); - } - } - - if (unlinkat(fd, name, flags) < 0) - return -errno; - - if (truncate_fd < 0) /* Don't have a file handle, can't do more ☹️ */ - return 0; - - if (fstat(truncate_fd, &st) < 0) { - log_debug_errno(errno, "Failed to stat file '%s' for deallocation, ignoring.", name); - return 0; - } - - if (!S_ISREG(st.st_mode) || st.st_blocks == 0 || st.st_nlink > 0) - return 0; - - /* If this is a regular file, it actually took up space on disk and there are no other links it's time to - * punch-hole/truncate this to release the disk space. */ - - bs = MAX(st.st_blksize, 512); - l = DIV_ROUND_UP(st.st_size, bs) * bs; /* Round up to next block size */ - - if (fallocate(truncate_fd, FALLOC_FL_PUNCH_HOLE|FALLOC_FL_KEEP_SIZE, 0, l) >= 0) - return 0; /* Successfully punched a hole! 😊 */ - - /* Fall back to truncation */ - if (ftruncate(truncate_fd, 0) < 0) { - log_debug_errno(errno, "Failed to truncate file to 0, ignoring: %m"); - return 0; - } - - return 0; -} - -int fsync_directory_of_file(int fd) { - _cleanup_free_ char *path = NULL, *dn = NULL; - _cleanup_close_ int dfd = -1; - int r; - - r = fd_verify_regular(fd); - if (r < 0) - return r; - - r = fd_get_path(fd, &path); - if (r < 0) { - log_debug("Failed to query /proc/self/fd/%d%s: %m", - fd, - r == -EOPNOTSUPP ? ", ignoring" : ""); - - if (r == -EOPNOTSUPP) - /* If /proc is not available, we're most likely running in some - * chroot environment, and syncing the directory is not very - * important in that case. Let's just silently do nothing. */ - return 0; - - return r; - } - - if (!path_is_absolute(path)) - return -EINVAL; - - dn = dirname_malloc(path); - if (!dn) - return -ENOMEM; - - dfd = open(dn, O_RDONLY|O_CLOEXEC|O_DIRECTORY); - if (dfd < 0) - return -errno; - - if (fsync(dfd) < 0) - return -errno; - - return 0; -} #endif /* NM_IGNORED */ diff --git a/src/systemd/src/basic/fs-util.h b/src/systemd/src/basic/fs-util.h index 2225b7e7..d3342d5c 100644 --- a/src/systemd/src/basic/fs-util.h +++ b/src/systemd/src/basic/fs-util.h @@ -1,4 +1,3 @@ -/* SPDX-License-Identifier: LGPL-2.1+ */ #pragma once /*** @@ -20,7 +19,6 @@ along with systemd; If not, see <http://www.gnu.org/licenses/>. ***/ -#include <dirent.h> #include <fcntl.h> #include <limits.h> #include <stdbool.h> @@ -30,7 +28,6 @@ #include <unistd.h> #include "time-util.h" -#include "util.h" int unlink_noerrno(const char *path); @@ -42,6 +39,8 @@ int readlinkat_malloc(int fd, const char *p, char **ret); int readlink_malloc(const char *p, char **r); int readlink_value(const char *p, char **ret); int readlink_and_make_absolute(const char *p, char **r); +int readlink_and_canonicalize(const char *p, const char *root, char **r); +int readlink_and_make_absolute_root(const char *root, const char *path, char **ret); int chmod_and_chown(const char *path, mode_t mode, uid_t uid, gid_t gid); @@ -65,8 +64,6 @@ int get_files_in_directory(const char *path, char ***list); int tmp_dir(const char **ret); int var_tmp_dir(const char **ret); -int unlink_or_warn(const char *filename); - #define INOTIFY_EVENT_MAX (sizeof(struct inotify_event) + NAME_MAX + 1) #define FOREACH_INOTIFY_EVENT(e, buffer, sz) \ @@ -82,35 +79,22 @@ union inotify_event_buffer { int inotify_add_watch_fd(int fd, int what, uint32_t mask); enum { - CHASE_PREFIX_ROOT = 1U << 0, /* If set, the specified path will be prefixed by the specified root before beginning the iteration */ - CHASE_NONEXISTENT = 1U << 1, /* If set, it's OK if the path doesn't actually exist. */ - CHASE_NO_AUTOFS = 1U << 2, /* If set, return -EREMOTE if autofs mount point found */ - CHASE_SAFE = 1U << 3, /* If set, return EPERM if we ever traverse from unprivileged to privileged files or directories */ - CHASE_OPEN = 1U << 4, /* If set, return an O_PATH object to the final component */ - CHASE_TRAIL_SLASH = 1U << 5, /* If set, any trailing slash will be preserved */ + CHASE_PREFIX_ROOT = 1, /* If set, the specified path will be prefixed by the specified root before beginning the iteration */ + CHASE_NONEXISTENT = 2, /* If set, it's OK if the path doesn't actually exist. */ + CHASE_NO_AUTOFS = 4, /* If set, return -EREMOTE if autofs mount point found */ }; int chase_symlinks(const char *path_with_prefix, const char *root, unsigned flags, char **ret); -int chase_symlinks_and_open(const char *path, const char *root, unsigned chase_flags, int open_flags, char **ret_path); -int chase_symlinks_and_opendir(const char *path, const char *root, unsigned chase_flags, char **ret_path, DIR **ret_dir); - /* Useful for usage with _cleanup_(), removes a directory and frees the pointer */ static inline void rmdir_and_free(char *p) { - PROTECT_ERRNO; (void) rmdir(p); free(p); } DEFINE_TRIVIAL_CLEANUP_FUNC(char*, rmdir_and_free); static inline void unlink_and_free(char *p) { - (void) unlink_noerrno(p); + (void) unlink(p); free(p); } DEFINE_TRIVIAL_CLEANUP_FUNC(char*, unlink_and_free); - -int access_fd(int fd, int mode); - -int unlinkat_deallocate(int fd, const char *name, int flags); - -int fsync_directory_of_file(int fd); diff --git a/src/systemd/src/basic/hash-funcs.c b/src/systemd/src/basic/hash-funcs.c index 234565ed..4a29f43c 100644 --- a/src/systemd/src/basic/hash-funcs.c +++ b/src/systemd/src/basic/hash-funcs.c @@ -1,4 +1,3 @@ -/* SPDX-License-Identifier: LGPL-2.1+ */ /*** This file is part of systemd. @@ -21,16 +20,12 @@ #include "nm-sd-adapt.h" -#include <string.h> - #include "hash-funcs.h" -#include "path-util.h" void string_hash_func(const void *p, struct siphash *state) { siphash24_compress(p, strlen(p) + 1, state); } -#if 0 /* NM_IGNORED */ int string_compare_func(const void *a, const void *b) { return strcmp(a, b); } @@ -40,56 +35,6 @@ const struct hash_ops string_hash_ops = { .compare = string_compare_func }; - -void path_hash_func(const void *p, struct siphash *state) { - const char *q = p; - size_t n; - - assert(q); - assert(state); - - /* Calculates a hash for a path in a way this duplicate inner slashes don't make a differences, and also - * whether there's a trailing slash or not. This fits well with the semantics of path_compare(), which does - * similar checks and also doesn't care for trailing slashes. Note that relative and absolute paths (i.e. those - * which begin in a slash or not) will hash differently though. */ - - n = strspn(q, "/"); - if (n > 0) { /* Eat up initial slashes, and add one "/" to the hash for all of them */ - siphash24_compress(q, 1, state); - q += n; - } - - for (;;) { - /* Determine length of next component */ - n = strcspn(q, "/"); - if (n == 0) /* Reached the end? */ - break; - - /* Add this component to the hash and skip over it */ - siphash24_compress(q, n, state); - q += n; - - /* How many slashes follow this component? */ - n = strspn(q, "/"); - if (q[n] == 0) /* Is this a trailing slash? If so, we are at the end, and don't care about the slashes anymore */ - break; - - /* We are not add the end yet. Hash exactly one slash for all of the ones we just encountered. */ - siphash24_compress(q, 1, state); - q += n; - } -} - -int path_compare_func(const void *a, const void *b) { - return path_compare(a, b); -} - -const struct hash_ops path_hash_ops = { - .hash = path_hash_func, - .compare = path_compare_func -}; -#endif /* NM_IGNORED */ - void trivial_hash_func(const void *p, struct siphash *state) { siphash24_compress(&p, sizeof(p), state); } @@ -119,7 +64,6 @@ const struct hash_ops uint64_hash_ops = { .compare = uint64_compare_func }; -#if 0 /* NM_IGNORED */ #if SIZEOF_DEV_T != 8 void devt_hash_func(const void *p, struct siphash *state) { siphash24_compress(p, sizeof(dev_t), state); @@ -137,4 +81,3 @@ const struct hash_ops devt_hash_ops = { .compare = devt_compare_func }; #endif -#endif /* NM_IGNORED */ diff --git a/src/systemd/src/basic/hash-funcs.h b/src/systemd/src/basic/hash-funcs.h index 945b4c25..299189d1 100644 --- a/src/systemd/src/basic/hash-funcs.h +++ b/src/systemd/src/basic/hash-funcs.h @@ -1,4 +1,3 @@ -/* SPDX-License-Identifier: LGPL-2.1+ */ #pragma once /*** @@ -36,28 +35,29 @@ void string_hash_func(const void *p, struct siphash *state); int string_compare_func(const void *a, const void *b) _pure_; extern const struct hash_ops string_hash_ops; -void path_hash_func(const void *p, struct siphash *state); -int path_compare_func(const void *a, const void *b) _pure_; -extern const struct hash_ops path_hash_ops; - -/* This will compare the passed pointers directly, and will not dereference them. This is hence not useful for strings - * or suchlike. */ +/* This will compare the passed pointers directly, and will not + * dereference them. This is hence not useful for strings or + * suchlike. */ void trivial_hash_func(const void *p, struct siphash *state); int trivial_compare_func(const void *a, const void *b) _const_; extern const struct hash_ops trivial_hash_ops; -/* 32bit values we can always just embed in the pointer itself, but in order to support 32bit archs we need store 64bit - * values indirectly, since they don't fit in a pointer. */ +/* 32bit values we can always just embed in the pointer itself, but + * in order to support 32bit archs we need store 64bit values + * indirectly, since they don't fit in a pointer. */ void uint64_hash_func(const void *p, struct siphash *state); int uint64_compare_func(const void *a, const void *b) _pure_; extern const struct hash_ops uint64_hash_ops; -/* On some archs dev_t is 32bit, and on others 64bit. And sometimes it's 64bit on 32bit archs, and sometimes 32bit on - * 64bit archs. Yuck! */ +/* On some archs dev_t is 32bit, and on others 64bit. And sometimes + * it's 64bit on 32bit archs, and sometimes 32bit on 64bit archs. Yuck! */ #if SIZEOF_DEV_T != 8 void devt_hash_func(const void *p, struct siphash *state) _pure_; int devt_compare_func(const void *a, const void *b) _pure_; -extern const struct hash_ops devt_hash_ops; +extern const struct hash_ops devt_hash_ops = { + .hash = devt_hash_func, + .compare = devt_compare_func +}; #else #define devt_hash_func uint64_hash_func #define devt_compare_func uint64_compare_func diff --git a/src/systemd/src/basic/hashmap.c b/src/systemd/src/basic/hashmap.c index a76ec8e8..c95d4991 100644 --- a/src/systemd/src/basic/hashmap.c +++ b/src/systemd/src/basic/hashmap.c @@ -1,4 +1,3 @@ -/* SPDX-License-Identifier: LGPL-2.1+ */ /*** This file is part of systemd. @@ -28,14 +27,12 @@ #include "alloc-util.h" #include "hashmap.h" -#include "fileio.h" #include "macro.h" #include "mempool.h" #include "process-util.h" #include "random-util.h" #include "set.h" #include "siphash24.h" -#include "string-util.h" #include "strv.h" #include "util.h" @@ -231,8 +228,6 @@ struct HashmapBase { unsigned n_direct_entries:3; /* Number of entries in direct storage. * Only valid if !has_indirect. */ bool from_pool:1; /* whether was allocated from mempool */ - bool dirty:1; /* whether dirtied since last iterated_cache_get() */ - bool cached:1; /* whether this hashmap is being cached */ HASHMAP_DEBUG_FIELDS /* optional hashmap_debug_info */ }; @@ -252,17 +247,6 @@ struct Set { struct HashmapBase b; }; -typedef struct CacheMem { - const void **ptr; - size_t n_populated, n_allocated; - bool active:1; -} CacheMem; - -struct IteratedCache { - HashmapBase *hashmap; - CacheMem keys, values; -}; - DEFINE_MEMPOOL(hashmap_pool, Hashmap, 8); DEFINE_MEMPOOL(ordered_hashmap_pool, OrderedHashmap, 8); /* No need for a separate Set pool */ @@ -296,28 +280,6 @@ static const struct hashmap_type_info hashmap_type_info[_HASHMAP_TYPE_MAX] = { }, }; -#ifdef VALGRIND -__attribute__((destructor)) static void cleanup_pools(void) { - _cleanup_free_ char *t = NULL; - int r; - - /* Be nice to valgrind */ - - /* The pool is only allocated by the main thread, but the memory can - * be passed to other threads. Let's clean up if we are the main thread - * and no other threads are live. */ - if (!is_main_thread()) - return; - - r = get_proc_field("/proc/self/status", "Threads", WHITESPACE, &t); - if (r < 0 || !streq(t, "1")) - return; - - mempool_drop(&hashmap_pool); - mempool_drop(&ordered_hashmap_pool); -} -#endif - static unsigned n_buckets(HashmapBase *h) { return h->has_indirect ? h->indirect.n_buckets : hashmap_type_info[h->type].n_direct_buckets; @@ -366,11 +328,6 @@ static unsigned base_bucket_hash(HashmapBase *h, const void *p) { } #define bucket_hash(h, p) base_bucket_hash(HASHMAP_BASE(h), p) -static inline void base_set_dirty(HashmapBase *h) { - h->dirty = true; -} -#define hashmap_set_dirty(h) base_set_dirty(HASHMAP_BASE(h)) - static void get_hash_key(uint8_t hash_key[HASH_KEY_SIZE], bool reuse_is_ok) { static uint8_t current[HASH_KEY_SIZE]; static bool current_initialized = false; @@ -588,7 +545,6 @@ static void base_remove_entry(HashmapBase *h, unsigned idx) { bucket_mark_free(h, prev); n_entries_dec(h); - base_set_dirty(h); } #define remove_entry(h, idx) base_remove_entry(HASHMAP_BASE(h), idx) @@ -758,25 +714,6 @@ bool set_iterate(Set *s, Iterator *i, void **value) { (idx != IDX_NIL); \ (idx) = hashmap_iterate_entry((h), &(i))) -IteratedCache *internal_hashmap_iterated_cache_new(HashmapBase *h) { - IteratedCache *cache; - - assert(h); - assert(!h->cached); - - if (h->cached) - return NULL; - - cache = new0(IteratedCache, 1); - if (!cache) - return NULL; - - cache->hashmap = h; - h->cached = true; - - return cache; -} - static void reset_direct_storage(HashmapBase *h) { const struct hashmap_type_info *hi = &hashmap_type_info[h->type]; void *p; @@ -937,8 +874,6 @@ void internal_hashmap_clear(HashmapBase *h) { OrderedHashmap *lh = (OrderedHashmap*) h; lh->iterate_list_head = lh->iterate_list_tail = IDX_NIL; } - - base_set_dirty(h); } void internal_hashmap_clear_free(HashmapBase *h) { @@ -1083,8 +1018,6 @@ static int hashmap_base_put_boldly(HashmapBase *h, unsigned idx, h->debug.max_entries = MAX(h->debug.max_entries, n_entries(h)); #endif - base_set_dirty(h); - return 1; } #define hashmap_put_boldly(h, idx, swap, may_resize) \ @@ -1321,8 +1254,6 @@ int hashmap_replace(Hashmap *h, const void *key, void *value) { #endif e->b.key = key; e->value = value; - hashmap_set_dirty(h); - return 0; } @@ -1345,8 +1276,6 @@ int hashmap_update(Hashmap *h, const void *key, void *value) { e = plain_bucket_at(h, idx); e->value = value; - hashmap_set_dirty(h); - return 0; } @@ -1899,95 +1828,3 @@ int set_put_strsplit(Set *s, const char *v, const char *separators, ExtractFlags return r; } } - -/* expand the cachemem if needed, return true if newly (re)activated. */ -static int cachemem_maintain(CacheMem *mem, unsigned size) { - assert(mem); - - if (!GREEDY_REALLOC(mem->ptr, mem->n_allocated, size)) { - if (size > 0) - return -ENOMEM; - } - - if (!mem->active) { - mem->active = true; - return true; - } - - return false; -} - -int iterated_cache_get(IteratedCache *cache, const void ***res_keys, const void ***res_values, unsigned *res_n_entries) { - bool sync_keys = false, sync_values = false; - unsigned size; - int r; - - assert(cache); - assert(cache->hashmap); - - size = n_entries(cache->hashmap); - - if (res_keys) { - r = cachemem_maintain(&cache->keys, size); - if (r < 0) - return r; - - sync_keys = r; - } else - cache->keys.active = false; - - if (res_values) { - r = cachemem_maintain(&cache->values, size); - if (r < 0) - return r; - - sync_values = r; - } else - cache->values.active = false; - - if (cache->hashmap->dirty) { - if (cache->keys.active) - sync_keys = true; - if (cache->values.active) - sync_values = true; - - cache->hashmap->dirty = false; - } - - if (sync_keys || sync_values) { - unsigned i, idx; - Iterator iter; - - i = 0; - HASHMAP_FOREACH_IDX(idx, cache->hashmap, iter) { - struct hashmap_base_entry *e; - - e = bucket_at(cache->hashmap, idx); - - if (sync_keys) - cache->keys.ptr[i] = e->key; - if (sync_values) - cache->values.ptr[i] = entry_value(cache->hashmap, e); - i++; - } - } - - if (res_keys) - *res_keys = cache->keys.ptr; - if (res_values) - *res_values = cache->values.ptr; - if (res_n_entries) - *res_n_entries = size; - - return 0; -} - -IteratedCache *iterated_cache_free(IteratedCache *cache) { - if (cache) { - free(cache->keys.ptr); - free(cache->values.ptr); - free(cache); - } - - return NULL; -} diff --git a/src/systemd/src/basic/hashmap.h b/src/systemd/src/basic/hashmap.h index b6749103..c1089652 100644 --- a/src/systemd/src/basic/hashmap.h +++ b/src/systemd/src/basic/hashmap.h @@ -1,4 +1,3 @@ -/* SPDX-License-Identifier: LGPL-2.1+ */ #pragma once /*** @@ -53,8 +52,6 @@ typedef struct Hashmap Hashmap; /* Maps keys to values */ typedef struct OrderedHashmap OrderedHashmap; /* Like Hashmap, but also remembers entry insertion order */ typedef struct Set Set; /* Stores just keys */ -typedef struct IteratedCache IteratedCache; /* Caches the iterated order of one of the above */ - /* Ideally the Iterator would be an opaque struct, but it is instantiated * by hashmap users, so the definition has to be here. Do not use its fields * directly. */ @@ -128,9 +125,6 @@ static inline OrderedHashmap *ordered_hashmap_free_free_free(OrderedHashmap *h) return (void*)hashmap_free_free_free(PLAIN_HASHMAP(h)); } -IteratedCache *iterated_cache_free(IteratedCache *cache); -int iterated_cache_get(IteratedCache *cache, const void ***res_keys, const void ***res_values, unsigned *res_n_entries); - HashmapBase *internal_hashmap_copy(HashmapBase *h); static inline Hashmap *hashmap_copy(Hashmap *h) { return (Hashmap*) internal_hashmap_copy(HASHMAP_BASE(h)); @@ -144,14 +138,6 @@ int internal_ordered_hashmap_ensure_allocated(OrderedHashmap **h, const struct h #define hashmap_ensure_allocated(h, ops) internal_hashmap_ensure_allocated(h, ops HASHMAP_DEBUG_SRC_ARGS) #define ordered_hashmap_ensure_allocated(h, ops) internal_ordered_hashmap_ensure_allocated(h, ops HASHMAP_DEBUG_SRC_ARGS) -IteratedCache *internal_hashmap_iterated_cache_new(HashmapBase *h); -static inline IteratedCache *hashmap_iterated_cache_new(Hashmap *h) { - return (IteratedCache*) internal_hashmap_iterated_cache_new(HASHMAP_BASE(h)); -} -static inline IteratedCache *ordered_hashmap_iterated_cache_new(OrderedHashmap *h) { - return (IteratedCache*) internal_hashmap_iterated_cache_new(HASHMAP_BASE(h)); -} - int hashmap_put(Hashmap *h, const void *key, void *value); static inline int ordered_hashmap_put(OrderedHashmap *h, const void *key, void *value) { return hashmap_put(PLAIN_HASHMAP(h), key, value); @@ -342,29 +328,6 @@ static inline void *ordered_hashmap_first(OrderedHashmap *h) { return internal_hashmap_first(HASHMAP_BASE(h)); } -#define hashmap_clear_with_destructor(_s, _f) \ - ({ \ - void *_item; \ - while ((_item = hashmap_steal_first(_s))) \ - _f(_item); \ - }) -#define hashmap_free_with_destructor(_s, _f) \ - ({ \ - hashmap_clear_with_destructor(_s, _f); \ - hashmap_free(_s); \ - }) -#define ordered_hashmap_clear_with_destructor(_s, _f) \ - ({ \ - void *_item; \ - while ((_item = ordered_hashmap_steal_first(_s))) \ - _f(_item); \ - }) -#define ordered_hashmap_free_with_destructor(_s, _f) \ - ({ \ - ordered_hashmap_clear_with_destructor(_s, _f); \ - ordered_hashmap_free(_s); \ - }) - /* no hashmap_next */ void *ordered_hashmap_next(OrderedHashmap *h, const void *key); @@ -407,7 +370,3 @@ DEFINE_TRIVIAL_CLEANUP_FUNC(OrderedHashmap*, ordered_hashmap_free_free_free); #define _cleanup_ordered_hashmap_free_ _cleanup_(ordered_hashmap_freep) #define _cleanup_ordered_hashmap_free_free_ _cleanup_(ordered_hashmap_free_freep) #define _cleanup_ordered_hashmap_free_free_free_ _cleanup_(ordered_hashmap_free_free_freep) - -DEFINE_TRIVIAL_CLEANUP_FUNC(IteratedCache*, iterated_cache_free); - -#define _cleanup_iterated_cache_free_ _cleanup_(iterated_cache_freep) diff --git a/src/systemd/src/basic/hexdecoct.c b/src/systemd/src/basic/hexdecoct.c index e8e82b5f..e0ae83c1 100644 --- a/src/systemd/src/basic/hexdecoct.c +++ b/src/systemd/src/basic/hexdecoct.c @@ -1,4 +1,3 @@ -/* SPDX-License-Identifier: LGPL-2.1+ */ /*** This file is part of systemd. @@ -99,10 +98,7 @@ int unhexmem(const char *p, size_t l, void **mem, size_t *len) { assert(mem); assert(len); - assert(p || l == 0); - - if (l == (size_t) -1) - l = strlen(p); + assert(p); if (l % 2 != 0) return -EINVAL; @@ -134,7 +130,6 @@ int unhexmem(const char *p, size_t l, void **mem, size_t *len) { return 0; } -#if 0 /* NM_IGNORED */ /* https://tools.ietf.org/html/rfc4648#section-6 * Notice that base32hex differs from base32 in the alphabet it uses. * The distinction is that the base32hex representation preserves the @@ -167,8 +162,6 @@ char *base32hexmem(const void *p, size_t l, bool padding) { const uint8_t *x; size_t len; - assert(p || l == 0); - if (padding) /* five input bytes makes eight output bytes, padding is added so we must round up */ len = 8 * (l + 4) / 5; @@ -278,12 +271,7 @@ int unbase32hexmem(const char *p, size_t l, bool padding, void **mem, size_t *_l size_t len; unsigned pad = 0; - assert(p || l == 0); - assert(mem); - assert(_len); - - if (l == (size_t) -1) - l = strlen(p); + assert(p); /* padding ensures any base32hex input has input divisible by 8 */ if (padding && l % 8 != 0) @@ -533,9 +521,6 @@ ssize_t base64mem(const void *p, size_t l, char **out) { char *r, *z; const uint8_t *x; - assert(p || l == 0); - assert(out); - /* three input bytes makes four output bytes, padding is added so we must round up */ z = r = malloc(4 * (l + 2) / 3 + 1); if (!r) @@ -571,11 +556,10 @@ ssize_t base64mem(const void *p, size_t l, char **out) { return z - r; } -static int base64_append_width( - char **prefix, int plen, - const char *sep, int indent, - const void *p, size_t l, - int width) { +static int base64_append_width(char **prefix, int plen, + const char *sep, int indent, + const void *p, size_t l, + int width) { _cleanup_free_ char *x = NULL; char *t, *s; @@ -586,7 +570,7 @@ static int base64_append_width( if (len <= 0) return len; - lines = DIV_ROUND_UP(len, width); + lines = (len + width - 1) / width; slen = strlen_ptr(sep); t = realloc(*prefix, plen + 1 + slen + (indent + width + 1) * lines); @@ -614,148 +598,118 @@ static int base64_append_width( return 0; } -int base64_append( - char **prefix, int plen, - const void *p, size_t l, - int indent, int width) { - +int base64_append(char **prefix, int plen, + const void *p, size_t l, + int indent, int width) { if (plen > width / 2 || plen + indent > width) /* leave indent on the left, keep last column free */ return base64_append_width(prefix, plen, "\n", indent, p, l, width - indent - 1); else /* leave plen on the left, keep last column free */ return base64_append_width(prefix, plen, NULL, plen, p, l, width - plen - 1); -} - -static int unbase64_next(const char **p, size_t *l) { - int ret; - - assert(p); - assert(l); - - /* Find the next non-whitespace character, and decode it. If we find padding, we return it as INT_MAX. We - * greedily skip all preceeding and all following whitespace. */ - - for (;;) { - if (*l == 0) - return -EPIPE; - - if (!strchr(WHITESPACE, **p)) - break; - - /* Skip leading whitespace */ - (*p)++, (*l)--; - } - - if (**p == '=') - ret = INT_MAX; /* return padding as INT_MAX */ - else { - ret = unbase64char(**p); - if (ret < 0) - return ret; - } +}; - for (;;) { - (*p)++, (*l)--; - if (*l == 0) - break; - if (!strchr(WHITESPACE, **p)) - break; - - /* Skip following whitespace */ - } - - return ret; -} - -int unbase64mem(const char *p, size_t l, void **ret, size_t *ret_size) { - _cleanup_free_ uint8_t *buf = NULL; - const char *x; +int unbase64mem(const char *p, size_t l, void **mem, size_t *_len) { + _cleanup_free_ uint8_t *r = NULL; + int a, b, c, d; uint8_t *z; + const char *x; size_t len; - assert(p || l == 0); - assert(ret); - assert(ret_size); + assert(p); - if (l == (size_t) -1) - l = strlen(p); + /* padding ensures any base63 input has input divisible by 4 */ + if (l % 4 != 0) + return -EINVAL; - /* A group of four input bytes needs three output bytes, in case of padding we need to add two or three extra - bytes. Note that this calculation is an upper boundary, as we ignore whitespace while decoding */ - len = (l / 4) * 3 + (l % 4 != 0 ? (l % 4) - 1 : 0); + /* strip the padding */ + if (l > 0 && p[l - 1] == '=') + l--; + if (l > 0 && p[l - 1] == '=') + l--; - buf = malloc(len + 1); - if (!buf) - return -ENOMEM; + /* a group of four input bytes needs three output bytes, in case of + padding we need to add two or three extra bytes */ + len = (l / 4) * 3 + (l % 4 ? (l % 4) - 1 : 0); - for (x = p, z = buf;;) { - int a, b, c, d; /* a == 00XXXXXX; b == 00YYYYYY; c == 00ZZZZZZ; d == 00WWWWWW */ + z = r = malloc(len + 1); + if (!r) + return -ENOMEM; - a = unbase64_next(&x, &l); - if (a == -EPIPE) /* End of string */ - break; + for (x = p; x < p + (l / 4) * 4; x += 4) { + /* a == 00XXXXXX; b == 00YYYYYY; c == 00ZZZZZZ; d == 00WWWWWW */ + a = unbase64char(x[0]); if (a < 0) - return a; - if (a == INT_MAX) /* Padding is not allowed at the beginning of a 4ch block */ return -EINVAL; - b = unbase64_next(&x, &l); + b = unbase64char(x[1]); if (b < 0) - return b; - if (b == INT_MAX) /* Padding is not allowed at the second character of a 4ch block either */ return -EINVAL; - c = unbase64_next(&x, &l); + c = unbase64char(x[2]); if (c < 0) - return c; + return -EINVAL; - d = unbase64_next(&x, &l); + d = unbase64char(x[3]); if (d < 0) - return d; + return -EINVAL; - if (c == INT_MAX) { /* Padding at the third character */ + *(z++) = (uint8_t) a << 2 | (uint8_t) b >> 4; /* XXXXXXYY */ + *(z++) = (uint8_t) b << 4 | (uint8_t) c >> 2; /* YYYYZZZZ */ + *(z++) = (uint8_t) c << 6 | (uint8_t) d; /* ZZWWWWWW */ + } - if (d != INT_MAX) /* If the third character is padding, the fourth must be too */ - return -EINVAL; + switch (l % 4) { + case 3: + a = unbase64char(x[0]); + if (a < 0) + return -EINVAL; - /* b == 00YY0000 */ - if (b & 15) - return -EINVAL; + b = unbase64char(x[1]); + if (b < 0) + return -EINVAL; - if (l > 0) /* Trailing rubbish? */ - return -ENAMETOOLONG; + c = unbase64char(x[2]); + if (c < 0) + return -EINVAL; - *(z++) = (uint8_t) a << 2 | (uint8_t) (b >> 4); /* XXXXXXYY */ - break; - } + /* c == 00ZZZZ00 */ + if (c & 3) + return -EINVAL; - if (d == INT_MAX) { - /* c == 00ZZZZ00 */ - if (c & 3) - return -EINVAL; + *(z++) = (uint8_t) a << 2 | (uint8_t) b >> 4; /* XXXXXXYY */ + *(z++) = (uint8_t) b << 4 | (uint8_t) c >> 2; /* YYYYZZZZ */ - if (l > 0) /* Trailing rubbish? */ - return -ENAMETOOLONG; + break; + case 2: + a = unbase64char(x[0]); + if (a < 0) + return -EINVAL; - *(z++) = (uint8_t) a << 2 | (uint8_t) b >> 4; /* XXXXXXYY */ - *(z++) = (uint8_t) b << 4 | (uint8_t) c >> 2; /* YYYYZZZZ */ - break; - } + b = unbase64char(x[1]); + if (b < 0) + return -EINVAL; - *(z++) = (uint8_t) a << 2 | (uint8_t) b >> 4; /* XXXXXXYY */ - *(z++) = (uint8_t) b << 4 | (uint8_t) c >> 2; /* YYYYZZZZ */ - *(z++) = (uint8_t) c << 6 | (uint8_t) d; /* ZZWWWWWW */ + /* b == 00YY0000 */ + if (b & 15) + return -EINVAL; + + *(z++) = (uint8_t) a << 2 | (uint8_t) (b >> 4); /* XXXXXXYY */ + + break; + case 0: + + break; + default: + return -EINVAL; } *z = 0; - if (ret_size) - *ret_size = (size_t) (z - buf); - - *ret = buf; - buf = NULL; + *mem = r; + r = NULL; + *_len = len; return 0; } @@ -764,10 +718,7 @@ void hexdump(FILE *f, const void *p, size_t s) { const uint8_t *b = p; unsigned n = 0; - assert(b || s == 0); - - if (!f) - f = stdout; + assert(s == 0 || b); while (s > 0) { size_t i; @@ -805,4 +756,3 @@ void hexdump(FILE *f, const void *p, size_t s) { s -= 16; } } -#endif /* NM_IGNORED */ diff --git a/src/systemd/src/basic/hexdecoct.h b/src/systemd/src/basic/hexdecoct.h index 08d0a522..1ba2f69e 100644 --- a/src/systemd/src/basic/hexdecoct.h +++ b/src/systemd/src/basic/hexdecoct.h @@ -1,4 +1,3 @@ -/* SPDX-License-Identifier: LGPL-2.1+ */ #pragma once /*** diff --git a/src/systemd/src/basic/hostname-util.c b/src/systemd/src/basic/hostname-util.c index 66b80727..be6e9e58 100644 --- a/src/systemd/src/basic/hostname-util.c +++ b/src/systemd/src/basic/hostname-util.c @@ -1,4 +1,3 @@ -/* SPDX-License-Identifier: LGPL-2.1+ */ /*** This file is part of systemd. @@ -27,15 +26,12 @@ #include <sys/utsname.h> #include <unistd.h> -#include "alloc-util.h" -#include "def.h" #include "fd-util.h" #include "fileio.h" #include "hostname-util.h" #include "macro.h" #include "string-util.h" -#if 0 /* NM_IGNORED */ bool hostname_is_set(void) { struct utsname u; @@ -51,6 +47,7 @@ bool hostname_is_set(void) { return true; } +#if 0 /* NM_IGNORED */ char* gethostname_malloc(void) { struct utsname u; @@ -226,88 +223,36 @@ int sethostname_idempotent(const char *s) { return 1; } -int shorten_overlong(const char *s, char **ret) { - char *h, *p; - - /* Shorten an overlong name to HOST_NAME_MAX or to the first dot, - * whatever comes earlier. */ - - assert(s); - - h = strdup(s); - if (!h) - return -ENOMEM; - - if (hostname_is_valid(h, false)) { - *ret = h; - return 0; - } - - p = strchr(h, '.'); - if (p) - *p = 0; - - strshorten(h, HOST_NAME_MAX); - - if (!hostname_is_valid(h, false)) { - free(h); - return -EDOM; - } - - *ret = h; - return 1; -} - -int read_etc_hostname_stream(FILE *f, char **ret) { - int r; - - assert(f); - assert(ret); - - for (;;) { - _cleanup_free_ char *line = NULL; - char *p; - - r = read_line(f, LONG_LINE_MAX, &line); - if (r < 0) - return r; - if (r == 0) /* EOF without any hostname? the file is empty, let's treat that exactly like no file at all: ENOENT */ - return -ENOENT; - - p = strstrip(line); - - /* File may have empty lines or comments, ignore them */ - if (!IN_SET(*p, '\0', '#')) { - char *copy; - - hostname_cleanup(p); /* normalize the hostname */ - - if (!hostname_is_valid(p, true)) /* check that the hostname we return is valid */ - return -EBADMSG; - - copy = strdup(p); - if (!copy) - return -ENOMEM; - - *ret = copy; - return 0; - } - } -} - -int read_etc_hostname(const char *path, char **ret) { +int read_hostname_config(const char *path, char **hostname) { _cleanup_fclose_ FILE *f = NULL; + char l[LINE_MAX]; + char *name = NULL; - assert(ret); - - if (!path) - path = "/etc/hostname"; + assert(path); + assert(hostname); f = fopen(path, "re"); if (!f) return -errno; - return read_etc_hostname_stream(f, ret); + /* may have comments, ignore them */ + FOREACH_LINE(l, f, return -errno) { + truncate_nl(l); + if (!IN_SET(l[0], '\0', '#')) { + /* found line with value */ + name = hostname_cleanup(l); + name = strdup(name); + if (!name) + return -ENOMEM; + break; + } + } + if (!name) + /* no non-empty line found */ + return -ENOENT; + + *hostname = name; + return 0; } #endif /* NM_IGNORED */ diff --git a/src/systemd/src/basic/hostname-util.h b/src/systemd/src/basic/hostname-util.h index edae52e3..7af4e6c7 100644 --- a/src/systemd/src/basic/hostname-util.h +++ b/src/systemd/src/basic/hostname-util.h @@ -1,4 +1,3 @@ -/* SPDX-License-Identifier: LGPL-2.1+ */ #pragma once /*** @@ -21,7 +20,6 @@ ***/ #include <stdbool.h> -#include <stdio.h> #include "macro.h" @@ -40,7 +38,4 @@ bool is_gateway_hostname(const char *hostname); int sethostname_idempotent(const char *s); -int shorten_overlong(const char *s, char **ret); - -int read_etc_hostname_stream(FILE *f, char **ret); -int read_etc_hostname(const char *path, char **ret); +int read_hostname_config(const char *path, char **hostname); diff --git a/src/systemd/src/basic/in-addr-util.c b/src/systemd/src/basic/in-addr-util.c index b2b68089..2a02d90b 100644 --- a/src/systemd/src/basic/in-addr-util.c +++ b/src/systemd/src/basic/in-addr-util.c @@ -1,4 +1,3 @@ -/* SPDX-License-Identifier: LGPL-2.1+ */ /*** This file is part of systemd. @@ -333,7 +332,6 @@ int in_addr_from_string_auto(const char *s, int *ret_family, union in_addr_union return -EINVAL; } -#if 0 /* NM_IGNORED */ int in_addr_ifindex_from_string_auto(const char *s, int *family, union in_addr_union *ret, int *ifindex) { const char *suffix; int r, ifi = 0; @@ -374,7 +372,6 @@ int in_addr_ifindex_from_string_auto(const char *s, int *family, union in_addr_u return r; } -#endif /* NM_IGNORED */ unsigned char in4_addr_netmask_to_prefixlen(const struct in_addr *addr) { assert(addr); diff --git a/src/systemd/src/basic/in-addr-util.h b/src/systemd/src/basic/in-addr-util.h index acaae6d2..59f8eb7e 100644 --- a/src/systemd/src/basic/in-addr-util.h +++ b/src/systemd/src/basic/in-addr-util.h @@ -1,4 +1,3 @@ -/* SPDX-License-Identifier: LGPL-2.1+ */ #pragma once /*** diff --git a/src/systemd/src/basic/io-util.c b/src/systemd/src/basic/io-util.c index 0f10ad7f..61b667f0 100644 --- a/src/systemd/src/basic/io-util.c +++ b/src/systemd/src/basic/io-util.c @@ -1,4 +1,3 @@ -/* SPDX-License-Identifier: LGPL-2.1+ */ /*** This file is part of systemd. @@ -35,7 +34,6 @@ int flush_fd(int fd) { .fd = fd, .events = POLLIN, }; - int count = 0; /* Read from the specified file descriptor, until POLLIN is not set anymore, throwing away everything * read. Note that some file descriptors (notable IP sockets) will trigger POLLIN even when no data can be read @@ -55,7 +53,7 @@ int flush_fd(int fd) { return -errno; } else if (r == 0) - return count; + return 0; l = read(fd, buf, sizeof(buf)); if (l < 0) { @@ -64,13 +62,11 @@ int flush_fd(int fd) { continue; if (errno == EAGAIN) - return count; + return 0; return -errno; } else if (l == 0) - return count; - - count += (int) l; + return 0; } } @@ -139,7 +135,7 @@ int loop_write(int fd, const void *buf, size_t nbytes, bool do_poll) { assert(fd >= 0); assert(buf); - if (_unlikely_(nbytes > (size_t) SSIZE_MAX)) + if (nbytes > (size_t) SSIZE_MAX) return -EINVAL; do { @@ -205,6 +201,7 @@ int fd_wait_for_event(int fd, int event, usec_t t) { r = ppoll(&pollfd, 1, t == USEC_INFINITY ? NULL : timespec_store(&ts, t), NULL); if (r < 0) return -errno; + if (r == 0) return 0; diff --git a/src/systemd/src/basic/io-util.h b/src/systemd/src/basic/io-util.h index d81610ad..d9b69add 100644 --- a/src/systemd/src/basic/io-util.h +++ b/src/systemd/src/basic/io-util.h @@ -1,4 +1,3 @@ -/* SPDX-License-Identifier: LGPL-2.1+ */ #pragma once /*** diff --git a/src/systemd/src/basic/list.h b/src/systemd/src/basic/list.h index 7006c3e2..c3771a17 100644 --- a/src/systemd/src/basic/list.h +++ b/src/systemd/src/basic/list.h @@ -1,4 +1,3 @@ -/* SPDX-License-Identifier: LGPL-2.1+ */ #pragma once /*** @@ -183,6 +182,3 @@ for ((i) = (p)->name##_next ? (p)->name##_next : (head); \ (i) != (p); \ (i) = (i)->name##_next ? (i)->name##_next : (head)) - -#define LIST_IS_EMPTY(head) \ - (!(head)) diff --git a/src/systemd/src/basic/log.h b/src/systemd/src/basic/log.h index b0e963b0..67fda3f9 100644 --- a/src/systemd/src/basic/log.h +++ b/src/systemd/src/basic/log.h @@ -1,4 +1,3 @@ -/* SPDX-License-Identifier: LGPL-2.1+ */ #pragma once /*** @@ -20,16 +19,18 @@ along with systemd; If not, see <http://www.gnu.org/licenses/>. ***/ +#include <errno.h> #include <stdarg.h> #include <stdbool.h> #include <stdlib.h> +#include <sys/signalfd.h> +#include <sys/socket.h> #include <syslog.h> -#include "macro.h" +#include "sd-id128.h" -/* Some structures we reference but don't want to pull in headers for */ -struct iovec; -struct signalfd_siginfo; +#include "macro.h" +#include "process-util.h" typedef enum LogRealm { LOG_REALM_SYSTEMD, @@ -50,6 +51,7 @@ typedef enum LogTarget{ LOG_TARGET_SYSLOG, LOG_TARGET_SYSLOG_OR_KMSG, LOG_TARGET_AUTO, /* console if stderr is tty, JOURNAL_OR_KMSG otherwise */ + LOG_TARGET_SAFE, /* console if stderr is tty, KMSG otherwise */ LOG_TARGET_NULL, _LOG_TARGET_MAX, _LOG_TARGET_INVALID = -1 @@ -96,6 +98,11 @@ int log_open(void); void log_close(void); void log_forget_fds(void); +void log_close_syslog(void); +void log_close_journal(void); +void log_close_kmsg(void); +void log_close_console(void); + void log_parse_environment_realm(LogRealm realm); #define log_parse_environment() \ log_parse_environment_realm(LOG_REALM) @@ -149,6 +156,19 @@ int log_object_internal( const char *extra, const char *format, ...) _printf_(10,11); +int log_object_internalv( + int level, + int error, + const char *file, + int line, + const char *func, + const char *object_field, + const char *object, + const char *extra_field, + const char *extra, + const char *format, + va_list ap) _printf_(10,0); + int log_struct_internal( int level, int error, @@ -165,8 +185,8 @@ int log_oom_internal( int log_format_iovec( struct iovec *iovec, - size_t iovec_len, - size_t *n, + unsigned iovec_len, + unsigned *n, bool newline_separator, int error, const char *format, @@ -178,7 +198,7 @@ int log_struct_iovec_internal( const char *file, int line, const char *func, - const struct iovec *input_iovec, + const struct iovec input_iovec[], size_t n_input_iovec); /* This modifies the buffer passed! */ @@ -191,7 +211,7 @@ int log_dump_internal( char *buffer); /* Logging for various assertions */ -_noreturn_ void log_assert_failed_realm( +noreturn void log_assert_failed_realm( LogRealm realm, const char *text, const char *file, @@ -200,7 +220,7 @@ _noreturn_ void log_assert_failed_realm( #define log_assert_failed(text, ...) \ log_assert_failed_realm(LOG_REALM, (text), __VA_ARGS__) -_noreturn_ void log_assert_failed_unreachable_realm( +noreturn void log_assert_failed_unreachable_realm( LogRealm realm, const char *text, const char *file, @@ -225,9 +245,9 @@ void log_assert_failed_return_realm( /* Logging with level */ #define log_full_errno_realm(realm, level, error, ...) \ ({ \ - int _level = (level), _e = (error), _realm = (realm); \ - (log_get_max_level_realm(_realm) >= LOG_PRI(_level)) \ - ? log_internal_realm(LOG_REALM_PLUS_LEVEL(_realm, _level), _e, \ + int _level = (level), _e = (error); \ + (log_get_max_level_realm((realm)) >= LOG_PRI(_level)) \ + ? log_internal_realm(LOG_REALM_PLUS_LEVEL((realm), _level), _e, \ __FILE__, __LINE__, __func__, __VA_ARGS__) \ : -abs(_e); \ }) @@ -237,15 +257,13 @@ void log_assert_failed_return_realm( #define log_full(level, ...) log_full_errno((level), 0, __VA_ARGS__) -int log_emergency_level(void); - /* Normal logging */ #define log_debug(...) log_full(LOG_DEBUG, __VA_ARGS__) #define log_info(...) log_full(LOG_INFO, __VA_ARGS__) #define log_notice(...) log_full(LOG_NOTICE, __VA_ARGS__) #define log_warning(...) log_full(LOG_WARNING, __VA_ARGS__) #define log_error(...) log_full(LOG_ERR, __VA_ARGS__) -#define log_emergency(...) log_full(log_emergency_level(), __VA_ARGS__) +#define log_emergency(...) log_full(getpid_cached() == 1 ? LOG_EMERG : LOG_ERR, __VA_ARGS__) /* Logging triggered by an errno-like error */ #define log_debug_errno(error, ...) log_full_errno(LOG_DEBUG, error, __VA_ARGS__) @@ -253,7 +271,7 @@ int log_emergency_level(void); #define log_notice_errno(error, ...) log_full_errno(LOG_NOTICE, error, __VA_ARGS__) #define log_warning_errno(error, ...) log_full_errno(LOG_WARNING, error, __VA_ARGS__) #define log_error_errno(error, ...) log_full_errno(LOG_ERR, error, __VA_ARGS__) -#define log_emergency_errno(error, ...) log_full_errno(log_emergency_level(), error, __VA_ARGS__) +#define log_emergency_errno(error, ...) log_full_errno(getpid_cached() == 1 ? LOG_EMERG : LOG_ERR, error, __VA_ARGS__) #ifdef LOG_TRACE # define log_trace(...) log_debug(__VA_ARGS__) @@ -289,20 +307,10 @@ LogTarget log_target_from_string(const char *s) _pure_; void log_received_signal(int level, const struct signalfd_siginfo *si); -/* If turned on, any requests for a log target involving "syslog" will be implicitly upgraded to the equivalent journal target */ void log_set_upgrade_syslog_to_journal(bool b); - -/* If turned on, and log_open() is called, we'll not use STDERR_FILENO for logging ever, but rather open /dev/console */ void log_set_always_reopen_console(bool b); - -/* If turned on, we'll open the log stream implicitly if needed on each individual log call. This is normally not - * desired as we want to reuse our logging streams. It is useful however */ void log_set_open_when_needed(bool b); -/* If turned on, then we'll never use IPC-based logging, i.e. never log to syslog or the journal. We'll only log to - * stderr, the console or kmsg */ -void log_set_prohibit_ipc(bool b); - int log_syntax_internal( const char *unit, int level, @@ -314,16 +322,6 @@ int log_syntax_internal( const char *func, const char *format, ...) _printf_(9, 10); -int log_syntax_invalid_utf8_internal( - const char *unit, - int level, - const char *config_file, - unsigned config_line, - const char *file, - int line, - const char *func, - const char *rvalue); - #define log_syntax(unit, level, config_file, config_line, error, ...) \ ({ \ int _level = (level), _e = (error); \ @@ -335,9 +333,10 @@ int log_syntax_invalid_utf8_internal( #define log_syntax_invalid_utf8(unit, level, config_file, config_line, rvalue) \ ({ \ int _level = (level); \ - (log_get_max_level() >= LOG_PRI(_level)) \ - ? log_syntax_invalid_utf8_internal(unit, _level, config_file, config_line, __FILE__, __LINE__, __func__, rvalue) \ - : -EINVAL; \ + if (log_get_max_level() >= LOG_PRI(_level)) { \ + _cleanup_free_ char *_p = NULL; \ + _p = utf8_escape_invalid(rvalue); \ + log_syntax_internal(unit, _level, config_file, config_line, 0, __FILE__, __LINE__, __func__, \ + "String is not UTF-8 clean, ignoring assignment: %s", strna(_p)); \ + } \ }) - -#define DEBUG_LOGGING _unlikely_(log_get_max_level() >= LOG_DEBUG) diff --git a/src/systemd/src/basic/macro.h b/src/systemd/src/basic/macro.h index 025a5db7..afcde459 100644 --- a/src/systemd/src/basic/macro.h +++ b/src/systemd/src/basic/macro.h @@ -1,4 +1,3 @@ -/* SPDX-License-Identifier: LGPL-2.1+ */ #pragma once /*** @@ -48,31 +47,6 @@ #define _weakref_(x) __attribute__((weakref(#x))) #define _alignas_(x) __attribute__((aligned(__alignof(x)))) #define _cleanup_(x) __attribute__((cleanup(x))) -#if __GNUC__ >= 7 -#define _fallthrough_ __attribute__((fallthrough)) -#else -#define _fallthrough_ -#endif -/* Define C11 noreturn without <stdnoreturn.h> and even on older gcc - * compiler versions */ -#ifndef _noreturn_ -#if __STDC_VERSION__ >= 201112L -#define _noreturn_ _Noreturn -#else -#define _noreturn_ __attribute__((noreturn)) -#endif -#endif - -#if !defined(HAS_FEATURE_MEMORY_SANITIZER) -# if defined(__has_feature) -# if __has_feature(memory_sanitizer) -# define HAS_FEATURE_MEMORY_SANITIZER 1 -# endif -# endif -# if !defined(HAS_FEATURE_MEMORY_SANITIZER) -# define HAS_FEATURE_MEMORY_SANITIZER 0 -# endif -#endif #if (defined (__GNUC__) && (__GNUC__ > 4 || (__GNUC__ == 4 && __GNUC_MINOR__ >= 6))) || defined (__clang__) /* Temporarily disable some warnings */ @@ -168,25 +142,11 @@ static inline unsigned long ALIGN_POWER2(unsigned long u) { return 1UL << (sizeof(u) * 8 - __builtin_clzl(u - 1UL)); } -#ifndef __COVERITY__ -# define VOID_0 ((void)0) -#else -# define VOID_0 ((void*)0) -#endif - #define ELEMENTSOF(x) \ __extension__ (__builtin_choose_expr( \ !__builtin_types_compatible_p(typeof(x), typeof(&*(x))), \ sizeof(x)/sizeof((x)[0]), \ - VOID_0)) - -/* - * STRLEN - return the length of a string literal, minus the trailing NUL byte. - * Contrary to strlen(), this is a constant expression. - * @x: a string literal. - */ -#define STRLEN(x) (sizeof(""x"") - 1) - + (void)0)) /* * container_of - cast a member of a structure out to the containing structure * @ptr: the pointer to the member. @@ -216,7 +176,7 @@ static inline unsigned long ALIGN_POWER2(unsigned long u) { __builtin_constant_p(_B) && \ __builtin_types_compatible_p(typeof(_A), typeof(_B)), \ ((_A) > (_B)) ? (_A) : (_B), \ - VOID_0)) + (void)0)) /* takes two types and returns the size of the larger one */ #define MAXSIZE(A, B) (sizeof(union _packed_ { typeof(A) a; typeof(B) b; })) @@ -443,10 +403,21 @@ static inline unsigned long ALIGN_POWER2(unsigned long u) { #endif #endif +/* Define C11 noreturn without <stdnoreturn.h> and even on older gcc + * compiler versions */ +#ifndef noreturn +#if defined(__STDC_VERSION__) && __STDC_VERSION__ >= 201112L +#define noreturn _Noreturn +#else +#define noreturn __attribute__((noreturn)) +#endif +#endif + #define DEFINE_TRIVIAL_CLEANUP_FUNC(type, func) \ static inline void func##p(type *p) { \ if (*p) \ func(*p); \ - } + } \ + struct __useless_struct_to_allow_trailing_semicolon__ #include "log.h" diff --git a/src/systemd/src/basic/mempool.c b/src/systemd/src/basic/mempool.c index 43ae59c9..c1635964 100644 --- a/src/systemd/src/basic/mempool.c +++ b/src/systemd/src/basic/mempool.c @@ -1,4 +1,3 @@ -/* SPDX-License-Identifier: LGPL-2.1+ */ /*** This file is part of systemd. diff --git a/src/systemd/src/basic/mempool.h b/src/systemd/src/basic/mempool.h index c9235c83..0618b8dd 100644 --- a/src/systemd/src/basic/mempool.h +++ b/src/systemd/src/basic/mempool.h @@ -1,4 +1,3 @@ -/* SPDX-License-Identifier: LGPL-2.1+ */ #pragma once /*** diff --git a/src/systemd/src/basic/parse-util.c b/src/systemd/src/basic/parse-util.c index 44fae932..6d978e93 100644 --- a/src/systemd/src/basic/parse-util.c +++ b/src/systemd/src/basic/parse-util.c @@ -1,4 +1,3 @@ -/* SPDX-License-Identifier: LGPL-2.1+ */ /*** This file is part of systemd. @@ -28,9 +27,7 @@ #include <string.h> #include "alloc-util.h" -#include "errno-list.h" #include "extract-word.h" -#include "locale-util.h" #include "macro.h" #include "parse-util.h" #include "process-util.h" @@ -71,6 +68,7 @@ int parse_pid(const char *s, pid_t* ret_pid) { *ret_pid = pid; return 0; } +#endif /* NM_IGNORED */ int parse_mode(const char *s, mode_t *ret) { char *x; @@ -87,7 +85,7 @@ int parse_mode(const char *s, mode_t *ret) { l = strtol(s, &x, 8); if (errno > 0) return -errno; - if (!x || x == s || *x != 0) + if (!x || x == s || *x) return -EINVAL; if (l < 0 || l > 07777) return -ERANGE; @@ -237,6 +235,7 @@ int parse_size(const char *t, uint64_t base, uint64_t *size) { return 0; } +#if 0 /* NM_IGNORED */ int parse_range(const char *t, unsigned *lower, unsigned *upper) { _cleanup_free_ char *word = NULL; unsigned l, u; @@ -273,64 +272,7 @@ int parse_range(const char *t, unsigned *lower, unsigned *upper) { *upper = u; return 0; } - -int parse_errno(const char *t) { - int r, e; - - assert(t); - - r = errno_from_name(t); - if (r > 0) - return r; - - r = safe_atoi(t, &e); - if (r < 0) - return r; - - /* 0 is also allowed here */ - if (!errno_is_valid(e) && e != 0) - return -ERANGE; - - return e; -} - -int parse_syscall_and_errno(const char *in, char **name, int *error) { - _cleanup_free_ char *n = NULL; - char *p; - int e = -1; - - assert(in); - assert(name); - assert(error); - - /* - * This parse "syscall:errno" like "uname:EILSEQ", "@sync:255". - * If errno is omitted, then error is set to -1. - * Empty syscall name is not allowed. - * Here, we do not check that the syscall name is valid or not. - */ - - p = strchr(in, ':'); - if (p) { - e = parse_errno(p + 1); - if (e < 0) - return e; - - n = strndup(in, p - in); - } else - n = strdup(in); - - if (!n) - return -ENOMEM; - - if (isempty(n)) - return -EINVAL; - - *error = e; - *name = TAKE_PTR(n); - - return 0; -} +#endif /* NM_IGNORED */ char *format_bytes(char *buf, size_t l, uint64_t t) { unsigned i; @@ -372,15 +314,13 @@ finish: return buf; } -#endif /* NM_IGNORED */ -int safe_atou_full(const char *s, unsigned base, unsigned *ret_u) { +int safe_atou(const char *s, unsigned *ret_u) { char *x = NULL; unsigned long l; assert(s); assert(ret_u); - assert(base <= 16); /* strtoul() is happy to parse negative values, and silently * converts them to unsigned values without generating an @@ -393,10 +333,10 @@ int safe_atou_full(const char *s, unsigned base, unsigned *ret_u) { s += strspn(s, WHITESPACE); errno = 0; - l = strtoul(s, &x, base); + l = strtoul(s, &x, 0); if (errno > 0) return -errno; - if (!x || x == s || *x != 0) + if (!x || x == s || *x) return -EINVAL; if (s[0] == '-') return -ERANGE; @@ -418,7 +358,7 @@ int safe_atoi(const char *s, int *ret_i) { l = strtol(s, &x, 0); if (errno > 0) return -errno; - if (!x || x == s || *x != 0) + if (!x || x == s || *x) return -EINVAL; if ((long) (int) l != l) return -ERANGE; @@ -440,7 +380,7 @@ int safe_atollu(const char *s, long long unsigned *ret_llu) { l = strtoull(s, &x, 0); if (errno > 0) return -errno; - if (!x || x == s || *x != 0) + if (!x || x == s || *x) return -EINVAL; if (*s == '-') return -ERANGE; @@ -460,7 +400,7 @@ int safe_atolli(const char *s, long long int *ret_lli) { l = strtoll(s, &x, 0); if (errno > 0) return -errno; - if (!x || x == s || *x != 0) + if (!x || x == s || *x) return -EINVAL; *ret_lli = l; @@ -480,7 +420,7 @@ int safe_atou8(const char *s, uint8_t *ret) { l = strtoul(s, &x, 0); if (errno > 0) return -errno; - if (!x || x == s || *x != 0) + if (!x || x == s || *x) return -EINVAL; if (s[0] == '-') return -ERANGE; @@ -491,21 +431,20 @@ int safe_atou8(const char *s, uint8_t *ret) { return 0; } -int safe_atou16_full(const char *s, unsigned base, uint16_t *ret) { +int safe_atou16(const char *s, uint16_t *ret) { char *x = NULL; unsigned long l; assert(s); assert(ret); - assert(base <= 16); s += strspn(s, WHITESPACE); errno = 0; - l = strtoul(s, &x, base); + l = strtoul(s, &x, 0); if (errno > 0) return -errno; - if (!x || x == s || *x != 0) + if (!x || x == s || *x) return -EINVAL; if (s[0] == '-') return -ERANGE; @@ -527,7 +466,7 @@ int safe_atoi16(const char *s, int16_t *ret) { l = strtol(s, &x, 0); if (errno > 0) return -errno; - if (!x || x == s || *x != 0) + if (!x || x == s || *x) return -EINVAL; if ((long) (int16_t) l != l) return -ERANGE; @@ -536,11 +475,10 @@ int safe_atoi16(const char *s, int16_t *ret) { return 0; } -#if 0 /* NM_IGNORED */ int safe_atod(const char *s, double *ret_d) { - _cleanup_(freelocalep) locale_t loc = (locale_t) 0; char *x = NULL; double d = 0; + locale_t loc; assert(s); assert(ret_d); @@ -551,11 +489,16 @@ int safe_atod(const char *s, double *ret_d) { errno = 0; d = strtod_l(s, &x, loc); - if (errno > 0) + if (errno > 0) { + freelocale(loc); return -errno; - if (!x || x == s || *x != 0) + } + if (!x || x == s || *x) { + freelocale(loc); return -EINVAL; + } + freelocale(loc); *ret_d = (double) d; return 0; } @@ -598,20 +541,19 @@ int parse_fractional_part_u(const char **p, size_t digits, unsigned *res) { int parse_percent_unbounded(const char *p) { const char *pc, *n; - int r, v; + unsigned v; + int r; pc = endswith(p, "%"); if (!pc) return -EINVAL; n = strndupa(p, pc - p); - r = safe_atoi(n, &v); + r = safe_atou(n, &v); if (r < 0) return r; - if (v < 0) - return -ERANGE; - return v; + return (int) v; } int parse_percent(const char *p) { @@ -624,6 +566,7 @@ int parse_percent(const char *p) { return v; } +#if 0 /* NM_IGNORED */ int parse_nice(const char *p, int *ret) { int n, r; diff --git a/src/systemd/src/basic/parse-util.h b/src/systemd/src/basic/parse-util.h index 1605cc4f..dc09782c 100644 --- a/src/systemd/src/basic/parse-util.h +++ b/src/systemd/src/basic/parse-util.h @@ -1,4 +1,3 @@ -/* SPDX-License-Identifier: LGPL-2.1+ */ #pragma once /*** @@ -38,34 +37,18 @@ int parse_ifindex(const char *s, int *ret); int parse_size(const char *t, uint64_t base, uint64_t *size); int parse_range(const char *t, unsigned *lower, unsigned *upper); -int parse_errno(const char *t); -int parse_syscall_and_errno(const char *in, char **name, int *error); #define FORMAT_BYTES_MAX 8 char *format_bytes(char *buf, size_t l, uint64_t t); -int safe_atou_full(const char *s, unsigned base, unsigned *ret_u); - -static inline int safe_atou(const char *s, unsigned *ret_u) { - return safe_atou_full(s, 0, ret_u); -} - +int safe_atou(const char *s, unsigned *ret_u); int safe_atoi(const char *s, int *ret_i); int safe_atollu(const char *s, unsigned long long *ret_u); int safe_atolli(const char *s, long long int *ret_i); int safe_atou8(const char *s, uint8_t *ret); -int safe_atou16_full(const char *s, unsigned base, uint16_t *ret); - -static inline int safe_atou16(const char *s, uint16_t *ret) { - return safe_atou16_full(s, 0, ret); -} - -static inline int safe_atoux16(const char *s, uint16_t *ret) { - return safe_atou16_full(s, 16, ret); -} - +int safe_atou16(const char *s, uint16_t *ret); int safe_atoi16(const char *s, int16_t *ret); static inline int safe_atou32(const char *s, uint32_t *ret_u) { diff --git a/src/systemd/src/basic/path-util.c b/src/systemd/src/basic/path-util.c index 23827c19..1bdcc653 100644 --- a/src/systemd/src/basic/path-util.c +++ b/src/systemd/src/basic/path-util.c @@ -1,4 +1,3 @@ -/* SPDX-License-Identifier: LGPL-2.1+ */ /*** This file is part of systemd. @@ -84,36 +83,14 @@ char *path_make_absolute(const char *p, const char *prefix) { /* Makes every item in the list an absolute path by prepending * the prefix, if specified and necessary */ - if (path_is_absolute(p) || isempty(prefix)) + if (path_is_absolute(p) || !prefix) return strdup(p); - if (endswith(prefix, "/")) - return strjoin(prefix, p); - else - return strjoin(prefix, "/", p); -} - -int safe_getcwd(char **ret) { - char *cwd; - - cwd = get_current_dir_name(); - if (!cwd) - return negative_errno(); - - /* Let's make sure the directory is really absolute, to protect us from the logic behind - * CVE-2018-1000001 */ - if (cwd[0] != '/') { - free(cwd); - return -ENOMEDIUM; - } - - *ret = cwd; - return 0; + return strjoin(prefix, "/", p); } int path_make_absolute_cwd(const char *p, char **ret) { char *c; - int r; assert(p); assert(ret); @@ -126,14 +103,11 @@ int path_make_absolute_cwd(const char *p, char **ret) { else { _cleanup_free_ char *cwd = NULL; - r = safe_getcwd(&cwd); - if (r < 0) - return r; + cwd = get_current_dir_name(); + if (!cwd) + return negative_errno(); - if (endswith(cwd, "/")) - c = strjoin(cwd, p); - else - c = strjoin(cwd, "/", p); + c = strjoin(cwd, "/", p); } if (!c) return -ENOMEM; @@ -251,8 +225,8 @@ int path_strv_make_absolute_cwd(char **l) { if (r < 0) return r; - path_kill_slashes(t); - free_and_replace(*s, t); + free(*s); + *s = t; } return 0; @@ -293,7 +267,8 @@ char **path_strv_resolve(char **l, const char *root) { r = chase_symlinks(t, root, 0, &u); if (r == -ENOENT) { if (root) { - u = TAKE_PTR(orig); + u = orig; + orig = NULL; free(t); } else u = t; @@ -567,7 +542,7 @@ bool paths_check_timestamp(const char* const* paths, usec_t *timestamp, bool upd assert(timestamp); - if (!paths) + if (paths == NULL) return false; STRV_FOREACH(i, paths) { @@ -731,37 +706,6 @@ char* dirname_malloc(const char *path) { return dir2; } - -const char *last_path_component(const char *path) { - /* Finds the last component of the path, preserving the - * optional trailing slash that signifies a directory. - * a/b/c → c - * a/b/c/ → c/ - * / → / - * // → / - * /foo/a → a - * /foo/a/ → a/ - * This is different than basename, which returns "" when - * a trailing slash is present. - */ - - unsigned l, k; - - l = k = strlen(path); - if (l == 0) /* special case — an empty string */ - return path; - - while (k > 0 && path[k-1] == '/') - k--; - - if (k == 0) /* the root directory */ - return path + l - 1; - - while (k > 0 && path[k-1] != '/') - k--; - - return path + k; -} #endif /* NM_IGNORED */ bool filename_is_valid(const char *p) { @@ -784,7 +728,7 @@ bool filename_is_valid(const char *p) { } #if 0 /* NM_IGNORED */ -bool path_is_normalized(const char *p) { +bool path_is_safe(const char *p) { if (isempty(p)) return false; @@ -798,6 +742,7 @@ bool path_is_normalized(const char *p) { if (strlen(p)+1 > PATH_MAX) return false; + /* The following two checks are not really dangerous, but hey, they still are confusing */ if (startswith(p, "./") || endswith(p, "/.") || strstr(p, "/./")) return false; @@ -913,9 +858,7 @@ int systemd_installation_has_version(const char *root, unsigned minimal_version) * for Gentoo which does a merge without making /lib a symlink. */ "lib/systemd/libsystemd-shared-*.so\0" - "lib64/systemd/libsystemd-shared-*.so\0" - "usr/lib/systemd/libsystemd-shared-*.so\0" - "usr/lib64/systemd/libsystemd-shared-*.so\0") { + "usr/lib/systemd/libsystemd-shared-*.so\0") { _cleanup_strv_free_ char **names = NULL; _cleanup_free_ char *path = NULL; diff --git a/src/systemd/src/basic/path-util.h b/src/systemd/src/basic/path-util.h index 8848abe9..399ed5f9 100644 --- a/src/systemd/src/basic/path-util.h +++ b/src/systemd/src/basic/path-util.h @@ -1,4 +1,3 @@ -/* SPDX-License-Identifier: LGPL-2.1+ */ #pragma once /*** @@ -29,14 +28,8 @@ #include "time-util.h" #if 0 /* NM_IGNORED */ -#if HAVE_SPLIT_BIN -# define PATH_SBIN_BIN(x) x "sbin:" x "bin" -#else -# define PATH_SBIN_BIN(x) x "bin" -#endif - -#define DEFAULT_PATH_NORMAL PATH_SBIN_BIN("/usr/local/") ":" PATH_SBIN_BIN("/usr/") -#define DEFAULT_PATH_SPLIT_USR DEFAULT_PATH_NORMAL ":" PATH_SBIN_BIN("/") +#define DEFAULT_PATH_NORMAL "/usr/local/sbin:/usr/local/bin:/usr/sbin:/usr/bin" +#define DEFAULT_PATH_SPLIT_USR DEFAULT_PATH_NORMAL ":/sbin:/bin" #if HAVE_SPLIT_USR # define DEFAULT_PATH DEFAULT_PATH_SPLIT_USR @@ -49,7 +42,6 @@ bool is_path(const char *p) _pure_; int path_split_and_make_absolute(const char *p, char ***ret); bool path_is_absolute(const char *p) _pure_; char* path_make_absolute(const char *p, const char *prefix); -int safe_getcwd(char **ret); int path_make_absolute_cwd(const char *p, char **ret); int path_make_relative(const char *from_dir, const char *to_path, char **_r); char* path_kill_slashes(char *path); @@ -139,10 +131,9 @@ char *prefix_root(const char *root, const char *path); int parse_path_argument_and_warn(const char *path, bool suppress_root, char **arg); char* dirname_malloc(const char *path); -const char *last_path_component(const char *path); bool filename_is_valid(const char *p) _pure_; -bool path_is_normalized(const char *p) _pure_; +bool path_is_safe(const char *p) _pure_; char *file_in_same_dir(const char *path, const char *filename); diff --git a/src/systemd/src/basic/prioq.c b/src/systemd/src/basic/prioq.c index 1e81bc71..64ad638e 100644 --- a/src/systemd/src/basic/prioq.c +++ b/src/systemd/src/basic/prioq.c @@ -1,4 +1,3 @@ -/* SPDX-License-Identifier: LGPL-2.1+ */ /*** This file is part of systemd. @@ -175,7 +174,7 @@ int prioq_put(Prioq *q, void *data, unsigned *idx) { struct prioq_item *j; n = MAX((q->n_items+1) * 2, 16u); - j = reallocarray(q->items, n, sizeof(struct prioq_item)); + j = realloc(q->items, sizeof(struct prioq_item) * n); if (!j) return -ENOMEM; diff --git a/src/systemd/src/basic/prioq.h b/src/systemd/src/basic/prioq.h index a222955d..113c73d0 100644 --- a/src/systemd/src/basic/prioq.h +++ b/src/systemd/src/basic/prioq.h @@ -1,4 +1,3 @@ -/* SPDX-License-Identifier: LGPL-2.1+ */ #pragma once /*** diff --git a/src/systemd/src/basic/process-util.c b/src/systemd/src/basic/process-util.c index 4128ac54..272030d1 100644 --- a/src/systemd/src/basic/process-util.c +++ b/src/systemd/src/basic/process-util.c @@ -1,4 +1,3 @@ -/* SPDX-License-Identifier: LGPL-2.1+ */ /*** This file is part of systemd. @@ -28,7 +27,6 @@ #include <signal.h> #include <stdbool.h> #include <stdio.h> -#include <stdio_ext.h> #include <stdlib.h> #include <string.h> #include <sys/mman.h> @@ -60,7 +58,6 @@ #include "stat-util.h" #include "string-table.h" #include "string-util.h" -#include "terminal-util.h" #include "user-util.h" #include "util.h" @@ -137,8 +134,6 @@ int get_process_cmdline(pid_t pid, size_t max_length, bool comm_fallback, char * return -errno; } - (void) __fsetlocking(f, FSETLOCKING_BYCALLER); - if (max_length == 1) { /* If there's only room for one byte, return the empty string */ @@ -302,17 +297,10 @@ int rename_process(const char name[]) { if (isempty(name)) return -EINVAL; /* let's not confuse users unnecessarily with an empty name */ - if (!is_main_thread()) - return -EPERM; /* Let's not allow setting the process name from other threads than the main one, as we - * cache things without locking, and we make assumptions that PR_SET_NAME sets the - * process name that isn't correct on any other threads */ - l = strlen(name); - /* First step, change the comm field. The main thread's comm is identical to the process comm. This means we - * can use PR_SET_NAME, which sets the thread name for the calling thread. */ - if (prctl(PR_SET_NAME, name) < 0) - log_debug_errno(errno, "PR_SET_NAME failed: %m"); + /* First step, change the comm field. */ + (void) prctl(PR_SET_NAME, name); if (l > 15) /* Linux process names can be 15 chars at max */ truncated = true; @@ -403,61 +391,35 @@ use_saved_argv: } int is_kernel_thread(pid_t pid) { - _cleanup_free_ char *line = NULL; - unsigned long long flags; - size_t l, i; const char *p; - char *q; - int r; + size_t count; + char c; + bool eof; + FILE *f; if (IN_SET(pid, 0, 1) || pid == getpid_cached()) /* pid 1, and we ourselves certainly aren't a kernel thread */ return 0; - if (!pid_is_valid(pid)) - return -EINVAL; - p = procfs_file_alloca(pid, "stat"); - r = read_one_line_file(p, &line); - if (r == -ENOENT) - return -ESRCH; - if (r < 0) - return r; + assert(pid > 1); - /* Skip past the comm field */ - q = strrchr(line, ')'); - if (!q) - return -EINVAL; - q++; - - /* Skip 6 fields to reach the flags field */ - for (i = 0; i < 6; i++) { - l = strspn(q, WHITESPACE); - if (l < 1) - return -EINVAL; - q += l; - - l = strcspn(q, WHITESPACE); - if (l < 1) - return -EINVAL; - q += l; + p = procfs_file_alloca(pid, "cmdline"); + f = fopen(p, "re"); + if (!f) { + if (errno == ENOENT) + return -ESRCH; + return -errno; } - /* Skip preceeding whitespace */ - l = strspn(q, WHITESPACE); - if (l < 1) - return -EINVAL; - q += l; + count = fread(&c, 1, 1, f); + eof = feof(f); + fclose(f); - /* Truncate the rest */ - l = strcspn(q, WHITESPACE); - if (l < 1) - return -EINVAL; - q[l] = 0; + /* Kernel threads have an empty cmdline */ - r = safe_atollu(q, &flags); - if (r < 0) - return r; + if (count <= 0) + return eof ? 1 : -errno; - return !!(flags & PF_KTHREAD); + return 0; } int get_process_capeff(pid_t pid, char **capeff) { @@ -529,8 +491,6 @@ static int get_process_id(pid_t pid, const char *field, uid_t *uid) { return -errno; } - (void) __fsetlocking(f, FSETLOCKING_BYCALLER); - FOREACH_LINE(line, f, return -errno) { char *l; @@ -609,8 +569,6 @@ int get_process_environ(pid_t pid, char **env) { return -errno; } - (void) __fsetlocking(f, FSETLOCKING_BYCALLER); - while ((c = fgetc(f)) != EOF) { if (!GREEDY_REALLOC(outcome, allocated, sz + 5)) return -ENOMEM; @@ -628,7 +586,8 @@ int get_process_environ(pid_t pid, char **env) { } else outcome[sz] = '\0'; - *env = TAKE_PTR(outcome); + *env = outcome; + outcome = NULL; return 0; } @@ -715,104 +674,32 @@ int wait_for_terminate(pid_t pid, siginfo_t *status) { * A warning is emitted if the process terminates abnormally, * and also if it returns non-zero unless check_exit_code is true. */ -int wait_for_terminate_and_check(const char *name, pid_t pid, WaitFlags flags) { - _cleanup_free_ char *buffer = NULL; +int wait_for_terminate_and_warn(const char *name, pid_t pid, bool check_exit_code) { + int r; siginfo_t status; - int r, prio; + assert(name); assert(pid > 1); - if (!name) { - r = get_process_comm(pid, &buffer); - if (r < 0) - log_debug_errno(r, "Failed to acquire process name of " PID_FMT ", ignoring: %m", pid); - else - name = buffer; - } - - prio = flags & WAIT_LOG_ABNORMAL ? LOG_ERR : LOG_DEBUG; - r = wait_for_terminate(pid, &status); if (r < 0) - return log_full_errno(prio, r, "Failed to wait for %s: %m", strna(name)); + return log_warning_errno(r, "Failed to wait for %s: %m", name); if (status.si_code == CLD_EXITED) { - if (status.si_status != EXIT_SUCCESS) - log_full(flags & WAIT_LOG_NON_ZERO_EXIT_STATUS ? LOG_ERR : LOG_DEBUG, - "%s failed with exit status %i.", strna(name), status.si_status); + if (status.si_status != 0) + log_full(check_exit_code ? LOG_WARNING : LOG_DEBUG, + "%s failed with error code %i.", name, status.si_status); else log_debug("%s succeeded.", name); return status.si_status; - } else if (IN_SET(status.si_code, CLD_KILLED, CLD_DUMPED)) { - log_full(prio, "%s terminated by signal %s.", strna(name), signal_to_string(status.si_status)); + log_warning("%s terminated by signal %s.", name, signal_to_string(status.si_status)); return -EPROTO; } - log_full(prio, "%s failed due to unknown reason.", strna(name)); - return -EPROTO; -} - -/* - * Return values: - * < 0 : wait_for_terminate_with_timeout() failed to get the state of the - * process, the process timed out, the process was terminated by a - * signal, or failed for an unknown reason. - * >=0 : The process terminated normally with no failures. - * - * Success is indicated by a return value of zero, a timeout is indicated - * by ETIMEDOUT, and all other child failure states are indicated by error - * is indicated by a non-zero value. - */ -int wait_for_terminate_with_timeout(pid_t pid, usec_t timeout) { - sigset_t mask; - int r; - usec_t until; - - assert_se(sigemptyset(&mask) == 0); - assert_se(sigaddset(&mask, SIGCHLD) == 0); - - /* Drop into a sigtimewait-based timeout. Waiting for the - * pid to exit. */ - until = now(CLOCK_MONOTONIC) + timeout; - for (;;) { - usec_t n; - siginfo_t status = {}; - struct timespec ts; - - n = now(CLOCK_MONOTONIC); - if (n >= until) - break; - - r = sigtimedwait(&mask, NULL, timespec_store(&ts, until - n)) < 0 ? -errno : 0; - /* Assuming we woke due to the child exiting. */ - if (waitid(P_PID, pid, &status, WEXITED|WNOHANG) == 0) { - if (status.si_pid == pid) { - /* This is the correct child.*/ - if (status.si_code == CLD_EXITED) - return (status.si_status == 0) ? 0 : -EPROTO; - else - return -EPROTO; - } - } - /* Not the child, check for errors and proceed appropriately */ - if (r < 0) { - switch (r) { - case -EAGAIN: - /* Timed out, child is likely hung. */ - return -ETIMEDOUT; - case -EINTR: - /* Received a different signal and should retry */ - continue; - default: - /* Return any unexpected errors */ - return r; - } - } - } - + log_warning("%s failed due to unknown reason.", name); return -EPROTO; } @@ -824,8 +711,6 @@ void sigkill_wait(pid_t pid) { } void sigkill_waitp(pid_t *pid) { - PROTECT_ERRNO; - if (!pid) return; if (*pid <= 1) @@ -834,13 +719,6 @@ void sigkill_waitp(pid_t *pid) { sigkill_wait(*pid); } -void sigterm_wait(pid_t pid) { - assert(pid > 1); - - if (kill_and_sigcont(pid, SIGTERM) > 0) - (void) wait_for_terminate(pid, NULL); -} - int kill_and_sigcont(pid_t pid, int sig) { int r; @@ -854,33 +732,17 @@ int kill_and_sigcont(pid_t pid, int sig) { return r; } -int getenv_for_pid(pid_t pid, const char *field, char **ret) { +int getenv_for_pid(pid_t pid, const char *field, char **_value) { _cleanup_fclose_ FILE *f = NULL; char *value = NULL; + int r; bool done = false; - const char *path; size_t l; + const char *path; assert(pid >= 0); assert(field); - assert(ret); - - if (pid == 0 || pid == getpid_cached()) { - const char *e; - - e = getenv(field); - if (!e) { - *ret = NULL; - return 0; - } - - value = strdup(e); - if (!value) - return -ENOMEM; - - *ret = value; - return 1; - } + assert(_value); path = procfs_file_alloca(pid, "environ"); @@ -888,13 +750,11 @@ int getenv_for_pid(pid_t pid, const char *field, char **ret) { if (!f) { if (errno == ENOENT) return -ESRCH; - return -errno; } - (void) __fsetlocking(f, FSETLOCKING_BYCALLER); - l = strlen(field); + r = 0; do { char line[LINE_MAX]; @@ -919,14 +779,14 @@ int getenv_for_pid(pid_t pid, const char *field, char **ret) { if (!value) return -ENOMEM; - *ret = value; - return 1; + r = 1; + break; } } while (!done); - *ret = NULL; - return 0; + *_value = value; + return r; } bool pid_is_unwaited(pid_t pid) { @@ -993,7 +853,7 @@ bool is_main_thread(void) { } #if 0 /* NM_IGNORED */ -_noreturn_ void freeze(void) { +noreturn void freeze(void) { log_close(); @@ -1002,17 +862,6 @@ _noreturn_ void freeze(void) { sync(); - /* Let's not freeze right away, but keep reaping zombies. */ - for (;;) { - int r; - siginfo_t si = {}; - - r = waitid(P_ALL, 0, &si, WEXITED); - if (r < 0 && errno != EINTR) - break; - } - - /* waitid() failed with an unexpected error, things are really borked. Freeze now! */ for (;;) pause(); } @@ -1161,7 +1010,7 @@ int ioprio_parse_priority(const char *s, int *ret) { static pid_t cached_pid = CACHED_PID_UNSET; -void reset_cached_pid(void) { +static void reset_cached_pid(void) { /* Invoked in the child after a fork(), i.e. at the first moment the PID changed */ cached_pid = CACHED_PID_UNSET; } @@ -1173,7 +1022,6 @@ extern int __register_atfork(void (*prepare) (void), void (*parent) (void), void extern void* __dso_handle __attribute__ ((__weak__)); pid_t getpid_cached(void) { - static bool installed = false; pid_t current_value; /* getpid_cached() is much like getpid(), but caches the value in local memory, to avoid having to invoke a @@ -1192,20 +1040,12 @@ pid_t getpid_cached(void) { case CACHED_PID_UNSET: { /* Not initialized yet, then do so now */ pid_t new_pid; - new_pid = raw_getpid(); - - if (!installed) { - /* __register_atfork() either returns 0 or -ENOMEM, in its glibc implementation. Since it's - * only half-documented (glibc doesn't document it but LSB does — though only superficially) - * we'll check for errors only in the most generic fashion possible. */ - - if (__register_atfork(NULL, NULL, reset_cached_pid, __dso_handle) != 0) { - /* OOM? Let's try again later */ - cached_pid = CACHED_PID_UNSET; - return new_pid; - } + new_pid = getpid(); - installed = true; + if (__register_atfork(NULL, NULL, reset_cached_pid, __dso_handle) != 0) { + /* OOM? Let's try again later */ + cached_pid = CACHED_PID_UNSET; + return new_pid; } cached_pid = new_pid; @@ -1213,7 +1053,7 @@ pid_t getpid_cached(void) { } case CACHED_PID_BUSY: /* Somebody else is currently initializing */ - return raw_getpid(); + return getpid(); default: /* Properly initialized */ return current_value; @@ -1221,252 +1061,6 @@ pid_t getpid_cached(void) { } #if 0 /* NM_IGNORED */ -int must_be_root(void) { - - if (geteuid() == 0) - return 0; - - log_error("Need to be root."); - return -EPERM; -} - -int safe_fork_full( - const char *name, - const int except_fds[], - size_t n_except_fds, - ForkFlags flags, - pid_t *ret_pid) { - - pid_t original_pid, pid; - sigset_t saved_ss, ss; - bool block_signals = false; - int prio, r; - - /* A wrapper around fork(), that does a couple of important initializations in addition to mere forking. Always - * returns the child's PID in *ret_pid. Returns == 0 in the child, and > 0 in the parent. */ - - prio = flags & FORK_LOG ? LOG_ERR : LOG_DEBUG; - - original_pid = getpid_cached(); - - if (flags & (FORK_RESET_SIGNALS|FORK_DEATHSIG)) { - - /* We temporarily block all signals, so that the new child has them blocked initially. This way, we can - * be sure that SIGTERMs are not lost we might send to the child. */ - - if (sigfillset(&ss) < 0) - return log_full_errno(prio, errno, "Failed to reset signal set: %m"); - - block_signals = true; - - } else if (flags & FORK_WAIT) { - - /* Let's block SIGCHLD at least, so that we can safely watch for the child process */ - - if (sigemptyset(&ss) < 0) - return log_full_errno(prio, errno, "Failed to clear signal set: %m"); - - if (sigaddset(&ss, SIGCHLD) < 0) - return log_full_errno(prio, errno, "Failed to add SIGCHLD to signal set: %m"); - - block_signals = true; - } - - if (block_signals) - if (sigprocmask(SIG_SETMASK, &ss, &saved_ss) < 0) - return log_full_errno(prio, errno, "Failed to set signal mask: %m"); - - if (flags & FORK_NEW_MOUNTNS) - pid = raw_clone(SIGCHLD|CLONE_NEWNS); - else - pid = fork(); - if (pid < 0) { - r = -errno; - - if (block_signals) /* undo what we did above */ - (void) sigprocmask(SIG_SETMASK, &saved_ss, NULL); - - return log_full_errno(prio, r, "Failed to fork: %m"); - } - if (pid > 0) { - /* We are in the parent process */ - - log_debug("Successfully forked off '%s' as PID " PID_FMT ".", strna(name), pid); - - if (flags & FORK_WAIT) { - r = wait_for_terminate_and_check(name, pid, (flags & FORK_LOG ? WAIT_LOG : 0)); - if (r < 0) - return r; - if (r != EXIT_SUCCESS) /* exit status > 0 should be treated as failure, too */ - return -EPROTO; - } - - if (block_signals) /* undo what we did above */ - (void) sigprocmask(SIG_SETMASK, &saved_ss, NULL); - - if (ret_pid) - *ret_pid = pid; - - return 1; - } - - /* We are in the child process */ - - if (flags & FORK_REOPEN_LOG) { - /* Close the logs if requested, before we log anything. And make sure we reopen it if needed. */ - log_close(); - log_set_open_when_needed(true); - } - - if (name) { - r = rename_process(name); - if (r < 0) - log_full_errno(flags & FORK_LOG ? LOG_WARNING : LOG_DEBUG, - r, "Failed to rename process, ignoring: %m"); - } - - if (flags & FORK_DEATHSIG) - if (prctl(PR_SET_PDEATHSIG, SIGTERM) < 0) { - log_full_errno(prio, errno, "Failed to set death signal: %m"); - _exit(EXIT_FAILURE); - } - - if (flags & FORK_RESET_SIGNALS) { - r = reset_all_signal_handlers(); - if (r < 0) { - log_full_errno(prio, r, "Failed to reset signal handlers: %m"); - _exit(EXIT_FAILURE); - } - - /* This implicitly undoes the signal mask stuff we did before the fork()ing above */ - r = reset_signal_mask(); - if (r < 0) { - log_full_errno(prio, r, "Failed to reset signal mask: %m"); - _exit(EXIT_FAILURE); - } - } else if (block_signals) { /* undo what we did above */ - if (sigprocmask(SIG_SETMASK, &saved_ss, NULL) < 0) { - log_full_errno(prio, errno, "Failed to restore signal mask: %m"); - _exit(EXIT_FAILURE); - } - } - - if (flags & FORK_DEATHSIG) { - pid_t ppid; - /* Let's see if the parent PID is still the one we started from? If not, then the parent - * already died by the time we set PR_SET_PDEATHSIG, hence let's emulate the effect */ - - ppid = getppid(); - if (ppid == 0) - /* Parent is in a differn't PID namespace. */; - else if (ppid != original_pid) { - log_debug("Parent died early, raising SIGTERM."); - (void) raise(SIGTERM); - _exit(EXIT_FAILURE); - } - } - - if (flags & FORK_CLOSE_ALL_FDS) { - /* Close the logs here in case it got reopened above, as close_all_fds() would close them for us */ - log_close(); - - r = close_all_fds(except_fds, n_except_fds); - if (r < 0) { - log_full_errno(prio, r, "Failed to close all file descriptors: %m"); - _exit(EXIT_FAILURE); - } - } - - /* When we were asked to reopen the logs, do so again now */ - if (flags & FORK_REOPEN_LOG) { - log_open(); - log_set_open_when_needed(false); - } - - if (flags & FORK_NULL_STDIO) { - r = make_null_stdio(); - if (r < 0) { - log_full_errno(prio, r, "Failed to connect stdin/stdout to /dev/null: %m"); - _exit(EXIT_FAILURE); - } - } - - if (ret_pid) - *ret_pid = getpid_cached(); - - return 0; -} - -int fork_agent(const char *name, const int except[], unsigned n_except, pid_t *ret_pid, const char *path, ...) { - bool stdout_is_tty, stderr_is_tty; - unsigned n, i; - va_list ap; - char **l; - int r; - - assert(path); - - /* Spawns a temporary TTY agent, making sure it goes away when we go away */ - - r = safe_fork_full(name, except, n_except, FORK_RESET_SIGNALS|FORK_DEATHSIG|FORK_CLOSE_ALL_FDS, ret_pid); - if (r < 0) - return r; - if (r > 0) - return 0; - - /* In the child: */ - - stdout_is_tty = isatty(STDOUT_FILENO); - stderr_is_tty = isatty(STDERR_FILENO); - - if (!stdout_is_tty || !stderr_is_tty) { - int fd; - - /* Detach from stdout/stderr. and reopen - * /dev/tty for them. This is important to - * ensure that when systemctl is started via - * popen() or a similar call that expects to - * read EOF we actually do generate EOF and - * not delay this indefinitely by because we - * keep an unused copy of stdin around. */ - fd = open("/dev/tty", O_WRONLY); - if (fd < 0) { - log_error_errno(errno, "Failed to open /dev/tty: %m"); - _exit(EXIT_FAILURE); - } - - if (!stdout_is_tty && dup2(fd, STDOUT_FILENO) < 0) { - log_error_errno(errno, "Failed to dup2 /dev/tty: %m"); - _exit(EXIT_FAILURE); - } - - if (!stderr_is_tty && dup2(fd, STDERR_FILENO) < 0) { - log_error_errno(errno, "Failed to dup2 /dev/tty: %m"); - _exit(EXIT_FAILURE); - } - - safe_close_above_stdio(fd); - } - - /* Count arguments */ - va_start(ap, path); - for (n = 0; va_arg(ap, char*); n++) - ; - va_end(ap); - - /* Allocate strv */ - l = alloca(sizeof(char *) * (n + 1)); - - /* Fill in arguments */ - va_start(ap, path); - for (i = 0; i <= n; i++) - l[i] = va_arg(ap, char*); - va_end(ap); - - execv(path, l); - _exit(EXIT_FAILURE); -} - static const char *const ioprio_class_table[] = { [IOPRIO_CLASS_NONE] = "none", [IOPRIO_CLASS_RT] = "realtime", @@ -1474,7 +1068,7 @@ static const char *const ioprio_class_table[] = { [IOPRIO_CLASS_IDLE] = "idle" }; -DEFINE_STRING_TABLE_LOOKUP_WITH_FALLBACK(ioprio_class, int, IOPRIO_N_CLASSES); +DEFINE_STRING_TABLE_LOOKUP_WITH_FALLBACK(ioprio_class, int, INT_MAX); static const char *const sigchld_code_table[] = { [CLD_EXITED] = "exited", diff --git a/src/systemd/src/basic/process-util.h b/src/systemd/src/basic/process-util.h index 3525c2d6..e1bd2c5b 100644 --- a/src/systemd/src/basic/process-util.h +++ b/src/systemd/src/basic/process-util.h @@ -1,4 +1,3 @@ -/* SPDX-License-Identifier: LGPL-2.1+ */ #pragma once /*** @@ -21,7 +20,6 @@ ***/ #include <alloca.h> -#include <errno.h> #include <sched.h> #include <signal.h> #include <stdbool.h> @@ -34,7 +32,6 @@ #include "format-util.h" #include "ioprio.h" #include "macro.h" -#include "time-util.h" #define procfs_file_alloca(pid, field) \ ({ \ @@ -43,7 +40,7 @@ if (_pid_ == 0) { \ _r_ = ("/proc/self/" field); \ } else { \ - _r_ = alloca(STRLEN("/proc/") + DECIMAL_STR_MAX(pid_t) + 1 + sizeof(field)); \ + _r_ = alloca(strlen("/proc/") + DECIMAL_STR_MAX(pid_t) + 1 + sizeof(field)); \ sprintf((char*) _r_, "/proc/"PID_FMT"/" field, _pid_); \ } \ _r_; \ @@ -62,21 +59,10 @@ int get_process_environ(pid_t pid, char **environ); int get_process_ppid(pid_t pid, pid_t *ppid); int wait_for_terminate(pid_t pid, siginfo_t *status); - -typedef enum WaitFlags { - WAIT_LOG_ABNORMAL = 1U << 0, - WAIT_LOG_NON_ZERO_EXIT_STATUS = 1U << 1, - - /* A shortcut for requesting the most complete logging */ - WAIT_LOG = WAIT_LOG_ABNORMAL|WAIT_LOG_NON_ZERO_EXIT_STATUS, -} WaitFlags; - -int wait_for_terminate_and_check(const char *name, pid_t pid, WaitFlags flags); -int wait_for_terminate_with_timeout(pid_t pid, usec_t timeout); +int wait_for_terminate_and_warn(const char *name, pid_t pid, bool check_exit_code); void sigkill_wait(pid_t pid); void sigkill_waitp(pid_t *pid); -void sigterm_wait(pid_t pid); int kill_and_sigcont(pid_t pid, int sig); @@ -91,7 +77,7 @@ int pid_from_same_root_fs(pid_t pid); bool is_main_thread(void); -_noreturn_ void freeze(void); +noreturn void freeze(void); bool oom_score_adjust_is_valid(int oa); @@ -117,13 +103,8 @@ int sigchld_code_from_string(const char *s) _pure_; int sched_policy_to_string_alloc(int i, char **s); int sched_policy_from_string(const char *s); -static inline pid_t PTR_TO_PID(const void *p) { - return (pid_t) ((uintptr_t) p); -} - -static inline void* PID_TO_PTR(pid_t pid) { - return (void*) ((uintptr_t) pid); -} +#define PTR_TO_PID(p) ((pid_t) ((uintptr_t) p)) +#define PID_TO_PTR(p) ((void*) ((uintptr_t) p)) void valgrind_summary_hack(void); @@ -153,56 +134,8 @@ static inline bool ioprio_priority_is_valid(int i) { static inline bool pid_is_valid(pid_t p) { return p > 0; } - -static inline int sched_policy_to_string_alloc_with_check(int n, char **s) { - if (!sched_policy_is_valid(n)) - return -EINVAL; - - return sched_policy_to_string_alloc(n, s); -} #endif /* NM_IGNORED */ int ioprio_parse_priority(const char *s, int *ret); pid_t getpid_cached(void); -void reset_cached_pid(void); - -int must_be_root(void); - -typedef enum ForkFlags { - FORK_RESET_SIGNALS = 1U << 0, - FORK_CLOSE_ALL_FDS = 1U << 1, - FORK_DEATHSIG = 1U << 2, - FORK_NULL_STDIO = 1U << 3, - FORK_REOPEN_LOG = 1U << 4, - FORK_LOG = 1U << 5, - FORK_WAIT = 1U << 6, - FORK_NEW_MOUNTNS = 1U << 7, -} ForkFlags; - -int safe_fork_full(const char *name, const int except_fds[], size_t n_except_fds, ForkFlags flags, pid_t *ret_pid); - -static inline int safe_fork(const char *name, ForkFlags flags, pid_t *ret_pid) { - return safe_fork_full(name, NULL, 0, flags, ret_pid); -} - -int fork_agent(const char *name, const int except[], unsigned n_except, pid_t *pid, const char *path, ...); - -#if SIZEOF_PID_T == 4 -/* The highest possibly (theoretic) pid_t value on this architecture. */ -#define PID_T_MAX ((pid_t) INT32_MAX) -/* The maximum number of concurrent processes Linux allows on this architecture, as well as the highest valid PID value - * the kernel will potentially assign. This reflects a value compiled into the kernel (PID_MAX_LIMIT), and sets the - * upper boundary on what may be written to the /proc/sys/kernel/pid_max sysctl (but do note that the sysctl is off by - * 1, since PID 0 can never exist and there can hence only be one process less than the limit would suggest). Since - * these values are documented in proc(5) we feel quite confident that they are stable enough for the near future at - * least to define them here too. */ -#define TASKS_MAX 4194303U -#elif SIZEOF_PID_T == 2 -#define PID_T_MAX ((pid_t) INT16_MAX) -#define TASKS_MAX 32767U -#else -#error "Unknown pid_t size" -#endif - -assert_cc(TASKS_MAX <= (unsigned long) PID_T_MAX) diff --git a/src/systemd/src/basic/random-util.c b/src/systemd/src/basic/random-util.c index 29ee3b45..3b6ddb7d 100644 --- a/src/systemd/src/basic/random-util.c +++ b/src/systemd/src/basic/random-util.c @@ -1,4 +1,3 @@ -/* SPDX-License-Identifier: LGPL-2.1+ */ /*** This file is part of systemd. @@ -23,12 +22,11 @@ #include <elf.h> #include <errno.h> #include <fcntl.h> -#include <linux/random.h> #include <stdbool.h> -#include <stdint.h> #include <stdlib.h> -#include <string.h> #include <sys/time.h> +#include <linux/random.h> +#include <stdint.h> #if HAVE_SYS_AUXV_H # include <sys/auxv.h> diff --git a/src/systemd/src/basic/random-util.h b/src/systemd/src/basic/random-util.h index dd870151..804e225f 100644 --- a/src/systemd/src/basic/random-util.h +++ b/src/systemd/src/basic/random-util.h @@ -1,4 +1,3 @@ -/* SPDX-License-Identifier: LGPL-2.1+ */ #pragma once /*** diff --git a/src/systemd/src/basic/refcnt.h b/src/systemd/src/basic/refcnt.h index ae2e446d..1d77a644 100644 --- a/src/systemd/src/basic/refcnt.h +++ b/src/systemd/src/basic/refcnt.h @@ -1,4 +1,3 @@ -/* SPDX-License-Identifier: LGPL-2.1+ */ #pragma once /*** diff --git a/src/systemd/src/basic/set.h b/src/systemd/src/basic/set.h index 156ab4b0..12d0fda1 100644 --- a/src/systemd/src/basic/set.h +++ b/src/systemd/src/basic/set.h @@ -1,4 +1,3 @@ -/* SPDX-License-Identifier: LGPL-2.1+ */ #pragma once /*** @@ -108,18 +107,6 @@ static inline void *set_steal_first(Set *s) { return internal_hashmap_steal_first(HASHMAP_BASE(s)); } -#define set_clear_with_destructor(_s, _f) \ - ({ \ - void *_item; \ - while ((_item = set_steal_first(_s))) \ - _f(_item); \ - }) -#define set_free_with_destructor(_s, _f) \ - ({ \ - set_clear_with_destructor(_s, _f); \ - set_free(_s); \ - }) - /* no set_steal_first_key */ /* no set_first_key */ diff --git a/src/systemd/src/basic/signal-util.h b/src/systemd/src/basic/signal-util.h index f6c3396e..dfd6eb56 100644 --- a/src/systemd/src/basic/signal-util.h +++ b/src/systemd/src/basic/signal-util.h @@ -1,4 +1,3 @@ -/* SPDX-License-Identifier: LGPL-2.1+ */ #pragma once /*** @@ -45,20 +44,13 @@ static inline void block_signals_reset(sigset_t *ss) { assert_se(sigprocmask(SIG_SETMASK, ss, NULL) >= 0); } -#define BLOCK_SIGNALS(...) \ - _cleanup_(block_signals_reset) _unused_ sigset_t _saved_sigset = ({ \ - sigset_t _t; \ - assert_se(sigprocmask_many(SIG_BLOCK, &_t, __VA_ARGS__, -1) >= 0); \ - _t; \ +#define BLOCK_SIGNALS(...) \ + _cleanup_(block_signals_reset) _unused_ sigset_t _saved_sigset = ({ \ + sigset_t t; \ + assert_se(sigprocmask_many(SIG_BLOCK, &t, __VA_ARGS__, -1) >= 0); \ + t; \ }) static inline bool SIGNAL_VALID(int signo) { return signo > 0 && signo < _NSIG; } - -static inline const char* signal_to_string_with_check(int n) { - if (!SIGNAL_VALID(n)) - return NULL; - - return signal_to_string(n); -} diff --git a/src/systemd/src/basic/socket-util.c b/src/systemd/src/basic/socket-util.c index 8ae68b6f..798ab16e 100644 --- a/src/systemd/src/basic/socket-util.c +++ b/src/systemd/src/basic/socket-util.c @@ -1,4 +1,3 @@ -/* SPDX-License-Identifier: LGPL-2.1+ */ /*** This file is part of systemd. @@ -43,7 +42,6 @@ #include "missing.h" #include "parse-util.h" #include "path-util.h" -#include "process-util.h" #include "socket-util.h" #include "string-table.h" #include "string-util.h" @@ -54,24 +52,14 @@ #if 0 /* NM_IGNORED */ #if ENABLE_IDN -# define IDN_FLAGS NI_IDN +# define IDN_FLAGS (NI_IDN|NI_IDN_USE_STD3_ASCII_RULES) #else # define IDN_FLAGS 0 #endif -static const char* const socket_address_type_table[] = { - [SOCK_STREAM] = "Stream", - [SOCK_DGRAM] = "Datagram", - [SOCK_RAW] = "Raw", - [SOCK_RDM] = "ReliableDatagram", - [SOCK_SEQPACKET] = "SequentialPacket", - [SOCK_DCCP] = "DatagramCongestionControl", -}; - -DEFINE_STRING_TABLE_LOOKUP(socket_address_type, int); - int socket_address_parse(SocketAddress *a, const char *s) { char *e, *n; + unsigned u; int r; assert(a); @@ -81,8 +69,6 @@ int socket_address_parse(SocketAddress *a, const char *s) { a->type = SOCK_STREAM; if (*s == '[') { - uint16_t port; - /* IPv6 in [x:.....:z]:p notation */ e = strchr(s+1, ']'); @@ -100,12 +86,15 @@ int socket_address_parse(SocketAddress *a, const char *s) { return -EINVAL; e++; - r = parse_ip_port(e, &port); + r = safe_atou(e, &u); if (r < 0) return r; + if (u <= 0 || u > 0xFFFF) + return -EINVAL; + a->sockaddr.in6.sin6_family = AF_INET6; - a->sockaddr.in6.sin6_port = htobe16(port); + a->sockaddr.in6.sin6_port = htobe16((uint16_t)u); a->size = sizeof(struct sockaddr_in6); } else if (*s == '/') { @@ -135,14 +124,13 @@ int socket_address_parse(SocketAddress *a, const char *s) { } else if (startswith(s, "vsock:")) { /* AF_VSOCK socket in vsock:cid:port notation */ - const char *cid_start = s + STRLEN("vsock:"); - unsigned port; + const char *cid_start = s + strlen("vsock:"); e = strchr(cid_start, ':'); if (!e) return -EINVAL; - r = safe_atou(e+1, &port); + r = safe_atou(e+1, &u); if (r < 0) return r; @@ -155,18 +143,19 @@ int socket_address_parse(SocketAddress *a, const char *s) { a->sockaddr.vm.svm_cid = VMADDR_CID_ANY; a->sockaddr.vm.svm_family = AF_VSOCK; - a->sockaddr.vm.svm_port = port; + a->sockaddr.vm.svm_port = u; a->size = sizeof(struct sockaddr_vm); } else { - uint16_t port; - e = strchr(s, ':'); if (e) { - r = parse_ip_port(e + 1, &port); + r = safe_atou(e+1, &u); if (r < 0) return r; + if (u <= 0 || u > 0xFFFF) + return -EINVAL; + n = strndupa(s, e-s); /* IPv4 in w.x.y.z:p notation? */ @@ -177,7 +166,7 @@ int socket_address_parse(SocketAddress *a, const char *s) { if (r > 0) { /* Gotcha, it's a traditional IPv4 address */ a->sockaddr.in.sin_family = AF_INET; - a->sockaddr.in.sin_port = htobe16(port); + a->sockaddr.in.sin_port = htobe16((uint16_t)u); a->size = sizeof(struct sockaddr_in); } else { unsigned idx; @@ -191,7 +180,7 @@ int socket_address_parse(SocketAddress *a, const char *s) { return -EINVAL; a->sockaddr.in6.sin6_family = AF_INET6; - a->sockaddr.in6.sin6_port = htobe16(port); + a->sockaddr.in6.sin6_port = htobe16((uint16_t)u); a->sockaddr.in6.sin6_scope_id = idx; a->sockaddr.in6.sin6_addr = in6addr_any; a->size = sizeof(struct sockaddr_in6); @@ -199,18 +188,21 @@ int socket_address_parse(SocketAddress *a, const char *s) { } else { /* Just a port */ - r = parse_ip_port(s, &port); + r = safe_atou(s, &u); if (r < 0) return r; + if (u <= 0 || u > 0xFFFF) + return -EINVAL; + if (socket_ipv6_is_supported()) { a->sockaddr.in6.sin6_family = AF_INET6; - a->sockaddr.in6.sin6_port = htobe16(port); + a->sockaddr.in6.sin6_port = htobe16((uint16_t)u); a->sockaddr.in6.sin6_addr = in6addr_any; a->size = sizeof(struct sockaddr_in6); } else { a->sockaddr.in.sin_family = AF_INET; - a->sockaddr.in.sin_port = htobe16(port); + a->sockaddr.in.sin_port = htobe16((uint16_t)u); a->sockaddr.in.sin_addr.s_addr = INADDR_ANY; a->size = sizeof(struct sockaddr_in); } @@ -538,25 +530,22 @@ bool socket_address_matches_fd(const SocketAddress *a, int fd) { return socket_address_equal(a, &b); } -int sockaddr_port(const struct sockaddr *_sa, unsigned *ret_port) { +int sockaddr_port(const struct sockaddr *_sa, unsigned *port) { union sockaddr_union *sa = (union sockaddr_union*) _sa; - /* Note, this returns the port as 'unsigned' rather than 'uint16_t', as AF_VSOCK knows larger ports */ - assert(sa); switch (sa->sa.sa_family) { - case AF_INET: - *ret_port = be16toh(sa->in.sin_port); + *port = be16toh(sa->in.sin_port); return 0; case AF_INET6: - *ret_port = be16toh(sa->in6.sin6_port); + *port = be16toh(sa->in6.sin6_port); return 0; case AF_VSOCK: - *ret_port = sa->vm.svm_port; + *port = sa->vm.svm_port; return 0; default: @@ -761,6 +750,19 @@ int socknameinfo_pretty(union sockaddr_union *sa, socklen_t salen, char **_ret) return 0; } +int getnameinfo_pretty(int fd, char **ret) { + union sockaddr_union sa; + socklen_t salen = sizeof(sa); + + assert(fd >= 0); + assert(ret); + + if (getsockname(fd, &sa.sa, &salen) < 0) + return -errno; + + return socknameinfo_pretty(&sa, salen, ret); +} + int socket_address_unlink(SocketAddress *a) { assert(a); @@ -807,18 +809,6 @@ static const char* const socket_address_bind_ipv6_only_table[_SOCKET_ADDRESS_BIN DEFINE_STRING_TABLE_LOOKUP(socket_address_bind_ipv6_only, SocketAddressBindIPv6Only); -SocketAddressBindIPv6Only parse_socket_address_bind_ipv6_only_or_bool(const char *n) { - int r; - - r = parse_boolean(n); - if (r > 0) - return SOCKET_ADDRESS_IPV6_ONLY; - if (r == 0) - return SOCKET_ADDRESS_BOTH; - - return socket_address_bind_ipv6_only_from_string(n); -} - bool sockaddr_equal(const union sockaddr_union *a, const union sockaddr_union *b) { assert(a); assert(b); @@ -953,77 +943,56 @@ int getpeercred(int fd, struct ucred *ucred) { if (n != sizeof(struct ucred)) return -EIO; - /* Check if the data is actually useful and not suppressed due to namespacing issues */ - if (!pid_is_valid(u.pid)) + /* Check if the data is actually useful and not suppressed due + * to namespacing issues */ + if (u.pid <= 0) + return -ENODATA; + if (u.uid == UID_INVALID) + return -ENODATA; + if (u.gid == GID_INVALID) return -ENODATA; - - /* Note that we don't check UID/GID here, as namespace translation works differently there: instead of - * receiving in "invalid" user/group we get the overflow UID/GID. */ *ucred = u; return 0; } int getpeersec(int fd, char **ret) { - _cleanup_free_ char *s = NULL; socklen_t n = 64; + char *s; + int r; assert(fd >= 0); assert(ret); - for (;;) { - s = new0(char, n+1); - if (!s) - return -ENOMEM; + s = new0(char, n); + if (!s) + return -ENOMEM; - if (getsockopt(fd, SOL_SOCKET, SO_PEERSEC, s, &n) >= 0) - break; + r = getsockopt(fd, SOL_SOCKET, SO_PEERSEC, s, &n); + if (r < 0) { + free(s); if (errno != ERANGE) return -errno; - s = mfree(s); - } - - if (isempty(s)) - return -EOPNOTSUPP; - - *ret = TAKE_PTR(s); - - return 0; -} - -int getpeergroups(int fd, gid_t **ret) { - socklen_t n = sizeof(gid_t) * 64; - _cleanup_free_ gid_t *d = NULL; - - assert(fd >= 0); - assert(ret); - - for (;;) { - d = malloc(n); - if (!d) + s = new0(char, n); + if (!s) return -ENOMEM; - if (getsockopt(fd, SOL_SOCKET, SO_PEERGROUPS, d, &n) >= 0) - break; - - if (errno != ERANGE) + r = getsockopt(fd, SOL_SOCKET, SO_PEERSEC, s, &n); + if (r < 0) { + free(s); return -errno; - - d = mfree(d); + } } - assert_se(n % sizeof(gid_t) == 0); - n /= sizeof(gid_t); - - if ((socklen_t) (int) n != n) - return -E2BIG; - - *ret = d; - d = NULL; + if (isempty(s)) { + free(s); + return -EOPNOTSUPP; + } - return (int) n; + *ret = s; + return 0; } int send_one_fd_sa( diff --git a/src/systemd/src/basic/socket-util.h b/src/systemd/src/basic/socket-util.h index ac957a76..d7e2d85f 100644 --- a/src/systemd/src/basic/socket-util.h +++ b/src/systemd/src/basic/socket-util.h @@ -1,4 +1,3 @@ -/* SPDX-License-Identifier: LGPL-2.1+ */ #pragma once /*** @@ -36,28 +35,18 @@ #include "util.h" union sockaddr_union { - /* The minimal, abstract version */ struct sockaddr sa; - - /* The libc provided version that allocates "enough room" for every protocol */ - struct sockaddr_storage storage; - - /* Protoctol-specific implementations */ struct sockaddr_in in; struct sockaddr_in6 in6; struct sockaddr_un un; struct sockaddr_nl nl; + struct sockaddr_storage storage; struct sockaddr_ll ll; #if 0 /* NM_IGNORED */ struct sockaddr_vm vm; #endif /* NM_IGNORED */ - /* Ensure there is enough space to store Infiniband addresses */ uint8_t ll_buffer[offsetof(struct sockaddr_ll, sll_addr) + CONST_MAX(ETH_ALEN, INFINIBAND_ALEN)]; - - /* Ensure there is enough space after the AF_UNIX sun_path for one more NUL byte, just to be sure that the path - * component is always followed by at least one NUL byte. */ - uint8_t un_buffer[sizeof(struct sockaddr_un) + 1]; }; typedef struct SocketAddress { @@ -84,9 +73,6 @@ typedef enum SocketAddressBindIPv6Only { #define socket_address_family(a) ((a)->sockaddr.sa.sa_family) -const char* socket_address_type_to_string(int t) _const_; -int socket_address_type_from_string(const char *s) _pure_; - int socket_address_parse(SocketAddress *a, const char *s); int socket_address_parse_and_warn(SocketAddress *a, const char *s); int socket_address_parse_netlink(SocketAddress *a, const char *s); @@ -128,10 +114,10 @@ int getpeername_pretty(int fd, bool include_port, char **ret); int getsockname_pretty(int fd, char **ret); int socknameinfo_pretty(union sockaddr_union *sa, socklen_t salen, char **_ret); +int getnameinfo_pretty(int fd, char **ret); const char* socket_address_bind_ipv6_only_to_string(SocketAddressBindIPv6Only b) _const_; SocketAddressBindIPv6Only socket_address_bind_ipv6_only_from_string(const char *s) _pure_; -SocketAddressBindIPv6Only parse_socket_address_bind_ipv6_only_or_bool(const char *s); int netlink_family_to_string_alloc(int b, char **s); int netlink_family_from_string(const char *s) _pure_; @@ -149,7 +135,6 @@ bool address_label_valid(const char *p); int getpeercred(int fd, struct ucred *ucred); int getpeersec(int fd, char **ret); -int getpeergroups(int fd, gid_t **ret); int send_one_fd_sa(int transport_fd, int fd, diff --git a/src/systemd/src/basic/sparse-endian.h b/src/systemd/src/basic/sparse-endian.h index 5e59de54..a3573b84 100644 --- a/src/systemd/src/basic/sparse-endian.h +++ b/src/systemd/src/basic/sparse-endian.h @@ -1,6 +1,4 @@ -/* SPDX-License-Identifier: MIT - * - * Copyright (c) 2012 Josh Triplett <josh@joshtriplett.org> +/* Copyright (c) 2012 Josh Triplett <josh@joshtriplett.org> * * Permission is hereby granted, free of charge, to any person obtaining a copy * of this software and associated documentation files (the "Software"), to diff --git a/src/systemd/src/basic/stdio-util.h b/src/systemd/src/basic/stdio-util.h index d3fed365..bd1144b4 100644 --- a/src/systemd/src/basic/stdio-util.h +++ b/src/systemd/src/basic/stdio-util.h @@ -1,4 +1,3 @@ -/* SPDX-License-Identifier: LGPL-2.1+ */ #pragma once /*** @@ -27,11 +26,9 @@ #include "macro.h" -#define snprintf_ok(buf, len, fmt, ...) \ - ((size_t) snprintf(buf, len, fmt, __VA_ARGS__) < (len)) - #define xsprintf(buf, fmt, ...) \ - assert_message_se(snprintf_ok(buf, ELEMENTSOF(buf), fmt, __VA_ARGS__), "xsprintf: " #buf "[] must be big enough") + assert_message_se((size_t) snprintf(buf, ELEMENTSOF(buf), fmt, __VA_ARGS__) < ELEMENTSOF(buf), "xsprintf: " #buf "[] must be big enough") + #define VA_FORMAT_ADVANCE(format, ap) \ do { \ diff --git a/src/systemd/src/basic/string-table.c b/src/systemd/src/basic/string-table.c index 8ec3b266..df26d5fb 100644 --- a/src/systemd/src/basic/string-table.c +++ b/src/systemd/src/basic/string-table.c @@ -1,4 +1,3 @@ -/* SPDX-License-Identifier: LGPL-2.1+ */ /*** This file is part of systemd. diff --git a/src/systemd/src/basic/string-table.h b/src/systemd/src/basic/string-table.h index e78a6dbd..369610ef 100644 --- a/src/systemd/src/basic/string-table.h +++ b/src/systemd/src/basic/string-table.h @@ -1,4 +1,3 @@ -/* SPDX-License-Identifier: LGPL-2.1+ */ #pragma once @@ -93,11 +92,13 @@ ssize_t string_table_lookup(const char * const *table, size_t len, const char *k #define _DEFINE_STRING_TABLE_LOOKUP(name,type,scope) \ _DEFINE_STRING_TABLE_LOOKUP_TO_STRING(name,type,scope) \ - _DEFINE_STRING_TABLE_LOOKUP_FROM_STRING(name,type,scope) + _DEFINE_STRING_TABLE_LOOKUP_FROM_STRING(name,type,scope) \ + struct __useless_struct_to_allow_trailing_semicolon__ #define _DEFINE_STRING_TABLE_LOOKUP_WITH_BOOLEAN(name,type,yes,scope) \ _DEFINE_STRING_TABLE_LOOKUP_TO_STRING(name,type,scope) \ - _DEFINE_STRING_TABLE_LOOKUP_FROM_STRING_WITH_BOOLEAN(name,type,yes,scope) + _DEFINE_STRING_TABLE_LOOKUP_FROM_STRING_WITH_BOOLEAN(name,type,yes,scope) \ + struct __useless_struct_to_allow_trailing_semicolon__ #define DEFINE_STRING_TABLE_LOOKUP(name,type) _DEFINE_STRING_TABLE_LOOKUP(name,type,) #define DEFINE_PRIVATE_STRING_TABLE_LOOKUP(name,type) _DEFINE_STRING_TABLE_LOOKUP(name,type,static) @@ -109,7 +110,8 @@ ssize_t string_table_lookup(const char * const *table, size_t len, const char *k /* For string conversions where numbers are also acceptable */ #define DEFINE_STRING_TABLE_LOOKUP_WITH_FALLBACK(name,type,max) \ _DEFINE_STRING_TABLE_LOOKUP_TO_STRING_FALLBACK(name,type,max,) \ - _DEFINE_STRING_TABLE_LOOKUP_FROM_STRING_FALLBACK(name,type,max,) + _DEFINE_STRING_TABLE_LOOKUP_FROM_STRING_FALLBACK(name,type,max,) \ + struct __useless_struct_to_allow_trailing_semicolon__ #define DEFINE_PRIVATE_STRING_TABLE_LOOKUP_TO_STRING_FALLBACK(name,type,max) \ _DEFINE_STRING_TABLE_LOOKUP_TO_STRING_FALLBACK(name,type,max,static) diff --git a/src/systemd/src/basic/string-util.c b/src/systemd/src/basic/string-util.c index a8e595db..047eb162 100644 --- a/src/systemd/src/basic/string-util.c +++ b/src/systemd/src/basic/string-util.c @@ -1,4 +1,3 @@ -/* SPDX-License-Identifier: LGPL-2.1+ */ /*** This file is part of systemd. @@ -24,7 +23,6 @@ #include <stdarg.h> #include <stdint.h> #include <stdio.h> -#include <stdio_ext.h> #include <stdlib.h> #include <string.h> @@ -32,7 +30,6 @@ #include "gunicode.h" #include "macro.h" #include "string-util.h" -#include "terminal-util.h" #include "utf8.h" #include "util.h" @@ -223,7 +220,6 @@ char *strappend(const char *s, const char *suffix) { return strnappend(s, suffix, strlen_ptr(suffix)); } -#if 0 /* NM_IGNORED */ char *strjoin_real(const char *x, ...) { va_list ap; size_t l; @@ -284,9 +280,6 @@ char *strjoin_real(const char *x, ...) { char *strstrip(char *s) { char *e; - if (!s) - return NULL; - /* Drops trailing whitespace. Modifies the string in * place. Returns pointer to first non-space character */ @@ -304,13 +297,7 @@ char *strstrip(char *s) { char *delete_chars(char *s, const char *bad) { char *f, *t; - /* Drops all specified bad characters, regardless where in the string */ - - if (!s) - return NULL; - - if (!bad) - bad = WHITESPACE; + /* Drops all whitespace, regardless where in the string */ for (f = s, t = s; *f; f++) { if (strchr(bad, *f)) @@ -324,27 +311,6 @@ char *delete_chars(char *s, const char *bad) { return s; } -char *delete_trailing_chars(char *s, const char *bad) { - char *p, *c = s; - - /* Drops all specified bad characters, at the end of the string */ - - if (!s) - return NULL; - - if (!bad) - bad = WHITESPACE; - - for (p = s; *p; p++) - if (!strchr(bad, *p)) - c = p + 1; - - *c = 0; - - return s; -} -#endif /* NM_IGNORED */ - char *truncate_nl(char *s) { assert(s); @@ -509,10 +475,6 @@ char *ellipsize_mem(const char *s, size_t old_length, size_t new_length, unsigne assert(s); assert(percent <= 100); - - if (new_length == (size_t) -1) - return strndup(s, old_length); - assert(new_length >= 3); /* if no multibyte characters use ascii_ellipsize_mem for speed */ @@ -580,10 +542,6 @@ char *ellipsize_mem(const char *s, size_t old_length, size_t new_length, unsigne } char *ellipsize(const char *s, size_t length, unsigned percent) { - - if (length == (size_t) -1) - return strdup(s); - return ellipsize_mem(s, strlen(s), length, percent); } #endif /* NM_IGNORED */ @@ -611,26 +569,26 @@ char* strshorten(char *s, size_t l) { } char *strreplace(const char *text, const char *old_string, const char *new_string) { - size_t l, old_len, new_len, allocated = 0; - char *t, *ret = NULL; const char *f; + char *t, *r; + size_t l, old_len, new_len; + assert(text); assert(old_string); assert(new_string); - if (!text) - return NULL; - old_len = strlen(old_string); new_len = strlen(new_string); l = strlen(text); - if (!GREEDY_REALLOC(ret, allocated, l+1)) + r = new(char, l+1); + if (!r) return NULL; f = text; - t = ret; + t = r; while (*f) { + char *a; size_t d, nl; if (!startswith(f, old_string)) { @@ -638,34 +596,28 @@ char *strreplace(const char *text, const char *old_string, const char *new_strin continue; } - d = t - ret; + d = t - r; nl = l - old_len + new_len; - - if (!GREEDY_REALLOC(ret, allocated, nl + 1)) - return mfree(ret); + a = realloc(r, nl + 1); + if (!a) + goto oom; l = nl; - t = ret + d; + r = a; + t = r + d; t = stpcpy(t, new_string); f += old_len; } *t = 0; - return ret; -} - -static void advance_offsets(ssize_t diff, size_t offsets[2], size_t shift[2], size_t size) { - if (!offsets) - return; + return r; - if ((size_t) diff < offsets[0]) - shift[0] += size; - if ((size_t) diff < offsets[1]) - shift[1] += size; +oom: + return mfree(r); } -char *strip_tab_ansi(char **ibuf, size_t *_isz, size_t highlight[2]) { +char *strip_tab_ansi(char **ibuf, size_t *_isz) { const char *i, *begin = NULL; enum { STATE_OTHER, @@ -673,7 +625,7 @@ char *strip_tab_ansi(char **ibuf, size_t *_isz, size_t highlight[2]) { STATE_BRACKET } state = STATE_OTHER; char *obuf = NULL; - size_t osz = 0, isz, shift[2] = {}; + size_t osz = 0, isz; FILE *f; assert(ibuf); @@ -687,10 +639,10 @@ char *strip_tab_ansi(char **ibuf, size_t *_isz, size_t highlight[2]) { if (!f) return NULL; - /* Note we turn off internal locking on f for performance reasons. It's safe to do so since we created f here - * and it doesn't leave our scope. */ - - (void) __fsetlocking(f, FSETLOCKING_BYCALLER); + /* Note we use the _unlocked() stdio variants on f for performance + * reasons. It's safe to do so since we created f here and it + * doesn't leave our scope. + */ for (i = *ibuf; i < *ibuf + isz + 1; i++) { @@ -701,26 +653,22 @@ char *strip_tab_ansi(char **ibuf, size_t *_isz, size_t highlight[2]) { break; else if (*i == '\x1B') state = STATE_ESCAPE; - else if (*i == '\t') { - fputs(" ", f); - advance_offsets(i - *ibuf, highlight, shift, 7); - } else - fputc(*i, f); - + else if (*i == '\t') + fputs_unlocked(" ", f); + else + fputc_unlocked(*i, f); break; case STATE_ESCAPE: if (i >= *ibuf + isz) { /* EOT */ - fputc('\x1B', f); - advance_offsets(i - *ibuf, highlight, shift, 1); + fputc_unlocked('\x1B', f); break; } else if (*i == '[') { state = STATE_BRACKET; begin = i + 1; } else { - fputc('\x1B', f); - fputc(*i, f); - advance_offsets(i - *ibuf, highlight, shift, 1); + fputc_unlocked('\x1B', f); + fputc_unlocked(*i, f); state = STATE_OTHER; } @@ -730,9 +678,8 @@ char *strip_tab_ansi(char **ibuf, size_t *_isz, size_t highlight[2]) { if (i >= *ibuf + isz || /* EOT */ (!(*i >= '0' && *i <= '9') && !IN_SET(*i, ';', 'm'))) { - fputc('\x1B', f); - fputc('[', f); - advance_offsets(i - *ibuf, highlight, shift, 2); + fputc_unlocked('\x1B', f); + fputc_unlocked('[', f); state = STATE_OTHER; i = begin-1; } else if (*i == 'm') @@ -754,29 +701,19 @@ char *strip_tab_ansi(char **ibuf, size_t *_isz, size_t highlight[2]) { if (_isz) *_isz = osz; - if (highlight) { - highlight[0] += shift[0]; - highlight[1] += shift[1]; - } - return obuf; } -#if 0 /* NM_IGNORED */ -char *strextend_with_separator(char **x, const char *separator, ...) { - bool need_separator; - size_t f, l, l_separator; - char *r, *p; +char *strextend(char **x, ...) { va_list ap; + size_t f, l; + char *r, *p; assert(x); l = f = strlen_ptr(*x); - need_separator = !isempty(*x); - l_separator = strlen_ptr(separator); - - va_start(ap, separator); + va_start(ap, x); for (;;) { const char *t; size_t n; @@ -786,29 +723,22 @@ char *strextend_with_separator(char **x, const char *separator, ...) { break; n = strlen(t); - - if (need_separator) - n += l_separator; - if (n > ((size_t) -1) - l) { va_end(ap); return NULL; } l += n; - need_separator = true; } va_end(ap); - need_separator = !isempty(*x); - r = realloc(*x, l+1); if (!r) return NULL; p = r + f; - va_start(ap, separator); + va_start(ap, x); for (;;) { const char *t; @@ -816,23 +746,15 @@ char *strextend_with_separator(char **x, const char *separator, ...) { if (!t) break; - if (need_separator && separator) - p = stpcpy(p, separator); - p = stpcpy(p, t); - - need_separator = true; } va_end(ap); - assert(p == r + l); - *p = 0; *x = r; return r + l; } -#endif /* NM_IGNORED */ char *strrep(const char *s, unsigned n) { size_t l; diff --git a/src/systemd/src/basic/string-util.h b/src/systemd/src/basic/string-util.h index 08eda4fc..4c94b182 100644 --- a/src/systemd/src/basic/string-util.h +++ b/src/systemd/src/basic/string-util.h @@ -1,4 +1,3 @@ -/* SPDX-License-Identifier: LGPL-2.1+ */ #pragma once /*** @@ -52,15 +51,15 @@ static inline bool streq_ptr(const char *a, const char *b) { } static inline const char* strempty(const char *s) { - return s ?: ""; + return s ? s : ""; } static inline const char* strnull(const char *s) { - return s ?: "(null)"; + return s ? s : "(null)"; } static inline const char *strna(const char *s) { - return s ?: "n/a"; + return s ? s : "n/a"; } static inline bool isempty(const char *p) { @@ -134,20 +133,8 @@ char *strjoin_real(const char *x, ...) _sentinel_; char *strstrip(char *s); char *delete_chars(char *s, const char *bad); -char *delete_trailing_chars(char *s, const char *bad); char *truncate_nl(char *s); -static inline char *skip_leading_chars(const char *s, const char *bad) { - - if (!s) - return NULL; - - if (!bad) - bad = WHITESPACE; - - return (char*) s + strspn(s, bad); -} - char ascii_tolower(char x); char *ascii_strlower(char *s); char *ascii_strlower_n(char *s, size_t n); @@ -177,11 +164,9 @@ char* strshorten(char *s, size_t l); char *strreplace(const char *text, const char *old_string, const char *new_string); -char *strip_tab_ansi(char **ibuf, size_t *_isz, size_t highlight[2]); - -char *strextend_with_separator(char **x, const char *separator, ...) _sentinel_; +char *strip_tab_ansi(char **p, size_t *l); -#define strextend(x, ...) strextend_with_separator(x, NULL, __VA_ARGS__) +char *strextend(char **x, ...) _sentinel_; char *strrep(const char *s, unsigned n); diff --git a/src/systemd/src/basic/strv.c b/src/systemd/src/basic/strv.c index dee5bbd7..08bcff6e 100644 --- a/src/systemd/src/basic/strv.c +++ b/src/systemd/src/basic/strv.c @@ -1,4 +1,3 @@ -/* SPDX-License-Identifier: LGPL-2.1+ */ /*** This file is part of systemd. @@ -216,7 +215,7 @@ int strv_extend_strv(char ***a, char **b, bool filter_duplicates) { p = strv_length(*a); q = strv_length(b); - t = reallocarray(*a, p + q + 1, sizeof(char *)); + t = realloc(*a, sizeof(char*) * (p + q + 1)); if (!t) return -ENOMEM; @@ -344,7 +343,8 @@ int strv_split_extract(char ***t, const char *s, const char *separators, Extract if (!GREEDY_REALLOC(l, allocated, n + 2)) return -ENOMEM; - l[n++] = TAKE_PTR(word); + l[n++] = word; + word = NULL; l[n] = NULL; } @@ -355,7 +355,8 @@ int strv_split_extract(char ***t, const char *s, const char *separators, Extract return -ENOMEM; } - *t = TAKE_PTR(l); + *t = l; + l = NULL; return (int) n; } @@ -395,6 +396,42 @@ char *strv_join(char **l, const char *separator) { return r; } +char *strv_join_quoted(char **l) { + char *buf = NULL; + char **s; + size_t allocated = 0, len = 0; + + STRV_FOREACH(s, l) { + /* assuming here that escaped string cannot be more + * than twice as long, and reserving space for the + * separator and quotes. + */ + _cleanup_free_ char *esc = NULL; + size_t needed; + + if (!GREEDY_REALLOC(buf, allocated, + len + strlen(*s) * 2 + 3)) + goto oom; + + esc = cescape(*s); + if (!esc) + goto oom; + + needed = snprintf(buf + len, allocated - len, "%s\"%s\"", + len > 0 ? " " : "", esc); + assert(needed < allocated - len); + len += needed; + } + + if (!buf) + buf = malloc0(1); + + return buf; + + oom: + return mfree(buf); +} + int strv_push(char ***l, char *value) { char **c; unsigned n, m; @@ -409,7 +446,7 @@ int strv_push(char ***l, char *value) { if (m < n) return -ENOMEM; - c = reallocarray(*l, m, sizeof(char*)); + c = realloc_multiply(*l, sizeof(char*), m); if (!c) return -ENOMEM; @@ -434,7 +471,7 @@ int strv_push_pair(char ***l, char *a, char *b) { if (m < n) return -ENOMEM; - c = reallocarray(*l, m, sizeof(char*)); + c = realloc_multiply(*l, sizeof(char*), m); if (!c) return -ENOMEM; @@ -448,7 +485,7 @@ int strv_push_pair(char ***l, char *a, char *b) { return 0; } -int strv_insert(char ***l, unsigned position, char *value) { +int strv_push_prepend(char ***l, char *value) { char **c; unsigned n, m, i; @@ -456,7 +493,6 @@ int strv_insert(char ***l, unsigned position, char *value) { return 0; n = strv_length(*l); - position = MIN(position, n); /* increase and check for overflow */ m = n + 2; @@ -467,12 +503,10 @@ int strv_insert(char ***l, unsigned position, char *value) { if (!c) return -ENOMEM; - for (i = 0; i < position; i++) - c[i] = (*l)[i]; - c[position] = value; - for (i = position; i < n; i++) + for (i = 0; i < n; i++) c[i+1] = (*l)[i]; + c[0] = value; c[n+1] = NULL; free(*l); @@ -548,7 +582,7 @@ int strv_extend_front(char ***l, const char *value) { if (!v) return -ENOMEM; - c = reallocarray(*l, m, sizeof(char*)); + c = realloc_multiply(*l, sizeof(char*), m); if (!c) { free(v); return -ENOMEM; @@ -863,7 +897,7 @@ int strv_extend_n(char ***l, const char *value, size_t n) { k = strv_length(*l); - nl = reallocarray(*l, k + n + 1, sizeof(char *)); + nl = realloc(*l, sizeof(char*) * (k + n + 1)); if (!nl) return -ENOMEM; diff --git a/src/systemd/src/basic/strv.h b/src/systemd/src/basic/strv.h index f169ac5d..385ad177 100644 --- a/src/systemd/src/basic/strv.h +++ b/src/systemd/src/basic/strv.h @@ -1,4 +1,3 @@ -/* SPDX-License-Identifier: LGPL-2.1+ */ #pragma once /*** @@ -54,12 +53,7 @@ int strv_extendf(char ***l, const char *format, ...) _printf_(2,0); int strv_extend_front(char ***l, const char *value); int strv_push(char ***l, char *value); int strv_push_pair(char ***l, char *a, char *b); -int strv_insert(char ***l, unsigned position, char *value); - -static inline int strv_push_prepend(char ***l, char *value) { - return strv_insert(l, 0, value); -} - +int strv_push_prepend(char ***l, char *value); int strv_consume(char ***l, char *value); int strv_consume_pair(char ***l, char *a, char *b); int strv_consume_prepend(char ***l, char *value); @@ -91,6 +85,7 @@ char **strv_split_newlines(const char *s); int strv_split_extract(char ***t, const char *s, const char *separators, ExtractFlags flags); char *strv_join(char **l, const char *separator); +char *strv_join_quoted(char **l); char **strv_parse_nulstr(const char *s, size_t l); char **strv_split_nulstr(const char *s); @@ -179,18 +174,9 @@ static inline bool strv_fnmatch_or_empty(char* const* patterns, const char *s, i } char ***strv_free_free(char ***l); -DEFINE_TRIVIAL_CLEANUP_FUNC(char***, strv_free_free); char **strv_skip(char **l, size_t n); int strv_extend_n(char ***l, const char *value, size_t n); int fputstrv(FILE *f, char **l, const char *separator, bool *space); - -#define strv_free_and_replace(a, b) \ - ({ \ - strv_free(a); \ - (a) = (b); \ - (b) = NULL; \ - 0; \ - }) diff --git a/src/systemd/src/basic/time-util.c b/src/systemd/src/basic/time-util.c index 95fbbd91..7f1c3f7c 100644 --- a/src/systemd/src/basic/time-util.c +++ b/src/systemd/src/basic/time-util.c @@ -1,4 +1,3 @@ -/* SPDX-License-Identifier: LGPL-2.1+ */ /*** This file is part of systemd. @@ -40,7 +39,6 @@ #include "macro.h" #include "parse-util.h" #include "path-util.h" -#include "process-util.h" #include "string-util.h" #include "strv.h" #include "time-util.h" @@ -893,24 +891,28 @@ int parse_timestamp(const char *t, usec_t *usec) { char *last_space, *tz = NULL; ParseTimestampResult *shared, tmp; int r; + pid_t pid; last_space = strrchr(t, ' '); if (last_space != NULL && timezone_is_valid(last_space + 1)) tz = last_space + 1; - if (!tz || endswith_no_case(t, " UTC")) + if (tz == NULL || endswith_no_case(t, " UTC")) return parse_timestamp_impl(t, usec, false); shared = mmap(NULL, sizeof *shared, PROT_READ|PROT_WRITE, MAP_SHARED|MAP_ANONYMOUS, -1, 0); if (shared == MAP_FAILED) return negative_errno(); - r = safe_fork("(sd-timestamp)", FORK_RESET_SIGNALS|FORK_CLOSE_ALL_FDS|FORK_DEATHSIG|FORK_WAIT, NULL); - if (r < 0) { + pid = fork(); + + if (pid == -1) { + int fork_errno = errno; (void) munmap(shared, sizeof *shared); - return r; + return -fork_errno; } - if (r == 0) { + + if (pid == 0) { bool with_tz = true; if (setenv("TZ", tz, 1) != 0) { @@ -933,6 +935,12 @@ int parse_timestamp(const char *t, usec_t *usec) { _exit(EXIT_SUCCESS); } + r = wait_for_terminate(pid, NULL); + if (r < 0) { + (void) munmap(shared, sizeof *shared); + return r; + } + tmp = *shared; if (munmap(shared, sizeof *shared) != 0) return negative_errno(); @@ -1379,7 +1387,8 @@ bool clock_supported(clockid_t clock) { if (!clock_boottime_supported()) return false; - _fallthrough_; + /* fall through */ + default: /* For everything else, check properly */ return clock_gettime(clock, &ts) >= 0; @@ -1454,10 +1463,4 @@ usec_t usec_shift_clock(usec_t x, clockid_t from, clockid_t to) { /* x lies in the past */ return usec_sub_unsigned(b, usec_sub_unsigned(a, x)); } - -bool in_utc_timezone(void) { - tzset(); - - return timezone == 0 && daylight == 0; -} #endif /* NM_IGNORED */ diff --git a/src/systemd/src/basic/time-util.h b/src/systemd/src/basic/time-util.h index a8c5a837..73f7e400 100644 --- a/src/systemd/src/basic/time-util.h +++ b/src/systemd/src/basic/time-util.h @@ -1,4 +1,3 @@ -/* SPDX-License-Identifier: LGPL-2.1+ */ #pragma once /*** @@ -100,12 +99,12 @@ triple_timestamp* triple_timestamp_from_realtime(triple_timestamp *ts, usec_t u) #define TRIPLE_TIMESTAMP_HAS_CLOCK(clock) \ IN_SET(clock, CLOCK_REALTIME, CLOCK_REALTIME_ALARM, CLOCK_MONOTONIC, CLOCK_BOOTTIME, CLOCK_BOOTTIME_ALARM) -static inline bool dual_timestamp_is_set(const dual_timestamp *ts) { +static inline bool dual_timestamp_is_set(dual_timestamp *ts) { return ((ts->realtime > 0 && ts->realtime != USEC_INFINITY) || (ts->monotonic > 0 && ts->monotonic != USEC_INFINITY)); } -static inline bool triple_timestamp_is_set(const triple_timestamp *ts) { +static inline bool triple_timestamp_is_set(triple_timestamp *ts) { return ((ts->realtime > 0 && ts->realtime != USEC_INFINITY) || (ts->monotonic > 0 && ts->monotonic != USEC_INFINITY) || (ts->boottime > 0 && ts->boottime != USEC_INFINITY)); @@ -156,8 +155,6 @@ struct tm *localtime_or_gmtime_r(const time_t *t, struct tm *tm, bool utc); unsigned long usec_to_jiffies(usec_t usec); -bool in_utc_timezone(void); - static inline usec_t usec_add(usec_t a, usec_t b) { usec_t c; diff --git a/src/systemd/src/basic/umask-util.h b/src/systemd/src/basic/umask-util.h index 638b37d7..359d87d2 100644 --- a/src/systemd/src/basic/umask-util.h +++ b/src/systemd/src/basic/umask-util.h @@ -1,4 +1,3 @@ -/* SPDX-License-Identifier: LGPL-2.1+ */ #pragma once /*** diff --git a/src/systemd/src/basic/utf8.c b/src/systemd/src/basic/utf8.c index c88eef38..ff281e43 100644 --- a/src/systemd/src/basic/utf8.c +++ b/src/systemd/src/basic/utf8.c @@ -1,4 +1,3 @@ -/* SPDX-License-Identifier: LGPL-2.1+ */ /*** This file is part of systemd. @@ -410,22 +409,3 @@ int utf8_encoded_valid_unichar(const char *str) { return len; } - -size_t utf8_n_codepoints(const char *str) { - size_t n = 0; - - /* Returns the number of UTF-8 codepoints in this string, or (size_t) -1 if the string is not valid UTF-8. */ - - while (*str != 0) { - int k; - - k = utf8_encoded_valid_unichar(str); - if (k < 0) - return (size_t) -1; - - str += k; - n++; - } - - return n; -} diff --git a/src/systemd/src/basic/utf8.h b/src/systemd/src/basic/utf8.h index c5243c24..322dac20 100644 --- a/src/systemd/src/basic/utf8.h +++ b/src/systemd/src/basic/utf8.h @@ -1,4 +1,3 @@ -/* SPDX-License-Identifier: LGPL-2.1+ */ #pragma once /*** @@ -61,5 +60,3 @@ static inline bool utf16_is_trailing_surrogate(char16_t c) { static inline char32_t utf16_surrogate_pair_to_unichar(char16_t lead, char16_t trail) { return ((lead - 0xd800) << 10) + (trail - 0xdc00) + 0x10000; } - -size_t utf8_n_codepoints(const char *str); diff --git a/src/systemd/src/basic/util.c b/src/systemd/src/basic/util.c index d8c9e82d..c8a22d68 100644 --- a/src/systemd/src/basic/util.c +++ b/src/systemd/src/basic/util.c @@ -1,4 +1,3 @@ -/* SPDX-License-Identifier: LGPL-2.1+ */ /*** This file is part of systemd. @@ -41,7 +40,6 @@ #include "build.h" #include "cgroup-util.h" #include "def.h" -#include "device-nodes.h" #include "dirent-util.h" #include "fd-util.h" #include "fileio.h" @@ -54,7 +52,6 @@ #include "parse-util.h" #include "path-util.h" #include "process-util.h" -#include "procfs-util.h" #include "set.h" #include "signal-util.h" #include "stat-util.h" @@ -64,7 +61,6 @@ #include "umask-util.h" #include "user-util.h" #include "util.h" -#include "virt.h" #if 0 /* NM_IGNORED */ int saved_argc = 0; @@ -112,7 +108,7 @@ int socket_from_display(const char *display, char **path) { k = strspn(display+1, "0123456789"); - f = new(char, STRLEN("/tmp/.X11-unix/X") + k + 1); + f = new(char, strlen("/tmp/.X11-unix/X") + k + 1); if (!f) return -ENOMEM; @@ -125,6 +121,66 @@ int socket_from_display(const char *display, char **path) { return 0; } +int block_get_whole_disk(dev_t d, dev_t *ret) { + char *p, *s; + int r; + unsigned n, m; + + assert(ret); + + /* If it has a queue this is good enough for us */ + if (asprintf(&p, "/sys/dev/block/%u:%u/queue", major(d), minor(d)) < 0) + return -ENOMEM; + + r = access(p, F_OK); + free(p); + + if (r >= 0) { + *ret = d; + return 0; + } + + /* If it is a partition find the originating device */ + if (asprintf(&p, "/sys/dev/block/%u:%u/partition", major(d), minor(d)) < 0) + return -ENOMEM; + + r = access(p, F_OK); + free(p); + + if (r < 0) + return -ENOENT; + + /* Get parent dev_t */ + if (asprintf(&p, "/sys/dev/block/%u:%u/../dev", major(d), minor(d)) < 0) + return -ENOMEM; + + r = read_one_line_file(p, &s); + free(p); + + if (r < 0) + return r; + + r = sscanf(s, "%u:%u", &m, &n); + free(s); + + if (r != 2) + return -EINVAL; + + /* Only return this if it is really good enough for us. */ + if (asprintf(&p, "/sys/dev/block/%u:%u/queue", m, n) < 0) + return -ENOMEM; + + r = access(p, F_OK); + free(p); + + if (r >= 0) { + *ret = makedev(m, n); + return 0; + } + + return -ENOENT; +} + bool kexec_loaded(void) { _cleanup_free_ char *s = NULL; @@ -152,6 +208,112 @@ int prot_from_flags(int flags) { } } +int fork_agent(pid_t *pid, const int except[], unsigned n_except, const char *path, ...) { + bool stdout_is_tty, stderr_is_tty; + pid_t parent_pid, agent_pid; + sigset_t ss, saved_ss; + unsigned n, i; + va_list ap; + char **l; + + assert(pid); + assert(path); + + /* Spawns a temporary TTY agent, making sure it goes away when + * we go away */ + + parent_pid = getpid_cached(); + + /* First we temporarily block all signals, so that the new + * child has them blocked initially. This way, we can be sure + * that SIGTERMs are not lost we might send to the agent. */ + assert_se(sigfillset(&ss) >= 0); + assert_se(sigprocmask(SIG_SETMASK, &ss, &saved_ss) >= 0); + + agent_pid = fork(); + if (agent_pid < 0) { + assert_se(sigprocmask(SIG_SETMASK, &saved_ss, NULL) >= 0); + return -errno; + } + + if (agent_pid != 0) { + assert_se(sigprocmask(SIG_SETMASK, &saved_ss, NULL) >= 0); + *pid = agent_pid; + return 0; + } + + /* In the child: + * + * Make sure the agent goes away when the parent dies */ + if (prctl(PR_SET_PDEATHSIG, SIGTERM) < 0) + _exit(EXIT_FAILURE); + + /* Make sure we actually can kill the agent, if we need to, in + * case somebody invoked us from a shell script that trapped + * SIGTERM or so... */ + (void) reset_all_signal_handlers(); + (void) reset_signal_mask(); + + /* Check whether our parent died before we were able + * to set the death signal and unblock the signals */ + if (getppid() != parent_pid) + _exit(EXIT_SUCCESS); + + /* Don't leak fds to the agent */ + close_all_fds(except, n_except); + + stdout_is_tty = isatty(STDOUT_FILENO); + stderr_is_tty = isatty(STDERR_FILENO); + + if (!stdout_is_tty || !stderr_is_tty) { + int fd; + + /* Detach from stdout/stderr. and reopen + * /dev/tty for them. This is important to + * ensure that when systemctl is started via + * popen() or a similar call that expects to + * read EOF we actually do generate EOF and + * not delay this indefinitely by because we + * keep an unused copy of stdin around. */ + fd = open("/dev/tty", O_WRONLY); + if (fd < 0) { + log_error_errno(errno, "Failed to open /dev/tty: %m"); + _exit(EXIT_FAILURE); + } + + if (!stdout_is_tty && dup2(fd, STDOUT_FILENO) < 0) { + log_error_errno(errno, "Failed to dup2 /dev/tty: %m"); + _exit(EXIT_FAILURE); + } + + if (!stderr_is_tty && dup2(fd, STDERR_FILENO) < 0) { + log_error_errno(errno, "Failed to dup2 /dev/tty: %m"); + _exit(EXIT_FAILURE); + } + + if (fd > STDERR_FILENO) + close(fd); + } + + /* Count arguments */ + va_start(ap, path); + for (n = 0; va_arg(ap, char*); n++) + ; + va_end(ap); + + /* Allocate strv */ + l = alloca(sizeof(char *) * (n + 1)); + + /* Fill in arguments */ + va_start(ap, path); + for (i = 0; i <= n; i++) + l[i] = va_arg(ap, char*); + va_end(ap); + + execv(path, l); + _exit(EXIT_FAILURE); +} + bool in_initrd(void) { struct statfs s; @@ -186,13 +348,11 @@ void *xbsearch_r(const void *key, const void *base, size_t nmemb, size_t size, const void *p; int comparison; - assert(!size_multiply_overflow(nmemb, size)); - l = 0; u = nmemb; while (l < u) { idx = (l + u) / 2; - p = (const uint8_t*) base + idx * size; + p = (const char *) base + idx * size; comparison = compar(key, p, arg); if (comparison < 0) u = idx; @@ -481,22 +641,31 @@ uint64_t physical_memory_scale(uint64_t v, uint64_t max) { uint64_t system_tasks_max(void) { +#if SIZEOF_PID_T == 4 +#define TASKS_MAX ((uint64_t) (INT32_MAX-1)) +#elif SIZEOF_PID_T == 2 +#define TASKS_MAX ((uint64_t) (INT16_MAX-1)) +#else +#error "Unknown pid_t size" +#endif + + _cleanup_free_ char *value = NULL, *root = NULL; uint64_t a = TASKS_MAX, b = TASKS_MAX; - _cleanup_free_ char *root = NULL; /* Determine the maximum number of tasks that may run on this system. We check three sources to determine this * limit: * - * a) the maximum tasks value the kernel allows on this architecture + * a) the maximum value for the pid_t type * b) the cgroups pids_max attribute for the system - * c) the kernel's configured maximum PID value + * c) the kernel's configure maximum PID value * * And then pick the smallest of the three */ - (void) procfs_tasks_get_limit(&a); + if (read_one_line_file("/proc/sys/kernel/pid_max", &value) >= 0) + (void) safe_atou64(value, &a); if (cg_get_root_path(&root) >= 0) { - _cleanup_free_ char *value = NULL; + value = mfree(value); if (cg_get_attribute("pids", root, "pids.max", &value) >= 0) (void) safe_atou64(value, &b); @@ -525,83 +694,162 @@ uint64_t system_tasks_max_scale(uint64_t v, uint64_t max) { return m / max; } +int update_reboot_parameter_and_warn(const char *param) { + int r; + + if (isempty(param)) { + if (unlink("/run/systemd/reboot-param") < 0) { + if (errno == ENOENT) + return 0; + + return log_warning_errno(errno, "Failed to unlink reboot parameter file: %m"); + } + + return 0; + } + + RUN_WITH_UMASK(0022) { + r = write_string_file("/run/systemd/reboot-param", param, WRITE_STRING_FILE_CREATE); + if (r < 0) + return log_warning_errno(r, "Failed to write reboot parameter file: %m"); + } + + return 0; +} + int version(void) { puts(PACKAGE_STRING "\n" SYSTEMD_FEATURES); return 0; } -/* This is a direct translation of str_verscmp from boot.c */ -static bool is_digit(int c) { - return c >= '0' && c <= '9'; -} +int get_block_device(const char *path, dev_t *dev) { + struct stat st; + struct statfs sfs; -static int c_order(int c) { - if (c == 0 || is_digit(c)) - return 0; + assert(path); + assert(dev); - if ((c >= 'a') && (c <= 'z')) - return c; + /* Get's the block device directly backing a file system. If + * the block device is encrypted, returns the device mapper + * block device. */ - return c + 0x10000; -} + if (lstat(path, &st)) + return -errno; + + if (major(st.st_dev) != 0) { + *dev = st.st_dev; + return 1; + } -int str_verscmp(const char *s1, const char *s2) { - const char *os1, *os2; + if (statfs(path, &sfs) < 0) + return -errno; - assert(s1); - assert(s2); + if (F_TYPE_EQUAL(sfs.f_type, BTRFS_SUPER_MAGIC)) + return btrfs_get_block_device(path, dev); - os1 = s1; - os2 = s2; + return 0; +} - while (*s1 || *s2) { - int first; +int get_block_device_harder(const char *path, dev_t *dev) { + _cleanup_closedir_ DIR *d = NULL; + _cleanup_free_ char *p = NULL, *t = NULL; + struct dirent *de, *found = NULL; + const char *q; + unsigned maj, min; + dev_t dt; + int r; - while ((*s1 && !is_digit(*s1)) || (*s2 && !is_digit(*s2))) { - int order; + assert(path); + assert(dev); - order = c_order(*s1) - c_order(*s2); - if (order != 0) - return order; - s1++; - s2++; - } + /* Gets the backing block device for a file system, and + * handles LUKS encrypted file systems, looking for its + * immediate parent, if there is one. */ - while (*s1 == '0') - s1++; - while (*s2 == '0') - s2++; - - first = 0; - while (is_digit(*s1) && is_digit(*s2)) { - if (first == 0) - first = *s1 - *s2; - s1++; - s2++; - } + r = get_block_device(path, &dt); + if (r <= 0) + return r; + + if (asprintf(&p, "/sys/dev/block/%u:%u/slaves", major(dt), minor(dt)) < 0) + return -ENOMEM; - if (is_digit(*s1)) - return 1; - if (is_digit(*s2)) - return -1; + d = opendir(p); + if (!d) { + if (errno == ENOENT) + goto fallback; - if (first != 0) - return first; + return -errno; } - return strcmp(os1, os2); -} + FOREACH_DIRENT_ALL(de, d, return -errno) { -/* Turn off core dumps but only if we're running outside of a container. */ -void disable_coredumps(void) { - int r; + if (dot_or_dot_dot(de->d_name)) + continue; - if (detect_container() > 0) - return; + if (!IN_SET(de->d_type, DT_LNK, DT_UNKNOWN)) + continue; - r = write_string_file("/proc/sys/kernel/core_pattern", "|/bin/false", 0); + if (found) { + _cleanup_free_ char *u = NULL, *v = NULL, *a = NULL, *b = NULL; + + /* We found a device backed by multiple other devices. We don't really support automatic + * discovery on such setups, with the exception of dm-verity partitions. In this case there are + * two backing devices: the data partition and the hash partition. We are fine with such + * setups, however, only if both partitions are on the same physical device. Hence, let's + * verify this. */ + + u = strjoin(p, "/", de->d_name, "/../dev"); + if (!u) + return -ENOMEM; + + v = strjoin(p, "/", found->d_name, "/../dev"); + if (!v) + return -ENOMEM; + + r = read_one_line_file(u, &a); + if (r < 0) { + log_debug_errno(r, "Failed to read %s: %m", u); + goto fallback; + } + + r = read_one_line_file(v, &b); + if (r < 0) { + log_debug_errno(r, "Failed to read %s: %m", v); + goto fallback; + } + + /* Check if the parent device is the same. If not, then the two backing devices are on + * different physical devices, and we don't support that. */ + if (!streq(a, b)) + goto fallback; + } + + found = de; + } + + if (!found) + goto fallback; + + q = strjoina(p, "/", found->d_name, "/dev"); + + r = read_one_line_file(q, &t); + if (r == -ENOENT) + goto fallback; if (r < 0) - log_debug_errno(r, "Failed to turn off coredumps, ignoring: %m"); + return r; + + if (sscanf(t, "%u:%u", &maj, &min) != 2) + return -EINVAL; + + if (maj == 0) + goto fallback; + + *dev = makedev(maj, min); + return 1; + +fallback: + *dev = dt; + return 1; } #endif /* NM_IGNORED */ diff --git a/src/systemd/src/basic/util.h b/src/systemd/src/basic/util.h index 19e9eae1..b31dfd1c 100644 --- a/src/systemd/src/basic/util.h +++ b/src/systemd/src/basic/util.h @@ -1,4 +1,3 @@ -/* SPDX-License-Identifier: LGPL-2.1+ */ #pragma once /*** @@ -71,6 +70,8 @@ bool plymouth_running(void); bool display_is_local(const char *display) _pure_; int socket_from_display(const char *display, char **path); +int block_get_whole_disk(dev_t d, dev_t *ret); + #define NULSTR_FOREACH(i, l) \ for ((i) = (l); (i) && *(i); (i) = strchr((i), 0)+1) @@ -84,6 +85,8 @@ bool kexec_loaded(void); int prot_from_flags(int flags) _const_; +int fork_agent(pid_t *pid, const int except[], unsigned n_except, const char *path, ...); + bool in_initrd(void); void in_initrd_force(bool value); @@ -92,19 +95,6 @@ void *xbsearch_r(const void *key, const void *base, size_t nmemb, size_t size, void *arg); /** - * Normal bsearch requires base to be nonnull. Here were require - * that only if nmemb > 0. - */ -static inline void* bsearch_safe(const void *key, const void *base, - size_t nmemb, size_t size, comparison_fn_t compar) { - if (nmemb <= 0) - return NULL; - - assert(base); - return bsearch(key, base, nmemb, size, compar); -} - -/** * Normal qsort requires base to be nonnull. Here were require * that only if nmemb > 0. */ @@ -199,8 +189,9 @@ uint64_t physical_memory_scale(uint64_t v, uint64_t max); uint64_t system_tasks_max(void); uint64_t system_tasks_max_scale(uint64_t v, uint64_t max); -int version(void); +int update_reboot_parameter_and_warn(const char *param); -int str_verscmp(const char *s1, const char *s2); +int version(void); -void disable_coredumps(void); +int get_block_device(const char *path, dev_t *dev); +int get_block_device_harder(const char *path, dev_t *dev); diff --git a/src/systemd/src/libsystemd-network/arp-util.c b/src/systemd/src/libsystemd-network/arp-util.c index 9b721ee6..69bd3e75 100644 --- a/src/systemd/src/libsystemd-network/arp-util.c +++ b/src/systemd/src/libsystemd-network/arp-util.c @@ -1,4 +1,3 @@ -/* SPDX-License-Identifier: LGPL-2.1+ */ /*** This file is part of systemd. @@ -26,7 +25,6 @@ #include "arp-util.h" #include "fd-util.h" -#include "unaligned.h" #include "util.h" int arp_network_bind_raw_socket(int ifindex, be32_t address, const struct ether_addr *eth_mac) { @@ -51,12 +49,12 @@ int arp_network_bind_raw_socket(int ifindex, be32_t address, const struct ether_ BPF_JUMP(BPF_JMP + BPF_JEQ + BPF_K, ARPOP_REPLY, 1, 0), /* protocol == reply ? */ BPF_STMT(BPF_RET + BPF_K, 0), /* ignore */ /* Sender Hardware Address must be different from our own */ - BPF_STMT(BPF_LD + BPF_IMM, unaligned_read_be32(ð_mac->ether_addr_octet[0])),/* A <- 4 bytes of client's MAC */ + BPF_STMT(BPF_LD + BPF_IMM, htobe32(*((uint32_t *) eth_mac))), /* A <- 4 bytes of client's MAC */ BPF_STMT(BPF_MISC + BPF_TAX, 0), /* X <- A */ BPF_STMT(BPF_LD + BPF_W + BPF_ABS, offsetof(struct ether_arp, arp_sha)), /* A <- 4 bytes of SHA */ BPF_STMT(BPF_ALU + BPF_XOR + BPF_X, 0), /* A xor X */ BPF_JUMP(BPF_JMP + BPF_JEQ + BPF_K, 0, 0, 6), /* A == 0 ? */ - BPF_STMT(BPF_LD + BPF_IMM, unaligned_read_be16(ð_mac->ether_addr_octet[4])),/* A <- remainder of client's MAC */ + BPF_STMT(BPF_LD + BPF_IMM, htobe16(*((uint16_t *) (((char *) eth_mac) + 4)))), /* A <- remainder of client's MAC */ BPF_STMT(BPF_MISC + BPF_TAX, 0), /* X <- A */ BPF_STMT(BPF_LD + BPF_H + BPF_ABS, offsetof(struct ether_arp, arp_sha) + 4), /* A <- remainder of SHA */ BPF_STMT(BPF_ALU + BPF_XOR + BPF_X, 0), /* A xor X */ @@ -105,7 +103,10 @@ int arp_network_bind_raw_socket(int ifindex, be32_t address, const struct ether_ if (r < 0) return -errno; - return TAKE_FD(s); + r = s; + s = -1; + + return r; } static int arp_send_packet(int fd, int ifindex, diff --git a/src/systemd/src/libsystemd-network/arp-util.h b/src/systemd/src/libsystemd-network/arp-util.h index decfce3f..3ef56b00 100644 --- a/src/systemd/src/libsystemd-network/arp-util.h +++ b/src/systemd/src/libsystemd-network/arp-util.h @@ -1,4 +1,3 @@ -/* SPDX-License-Identifier: LGPL-2.1+ */ #pragma once /*** diff --git a/src/systemd/src/libsystemd-network/dhcp-identifier.c b/src/systemd/src/libsystemd-network/dhcp-identifier.c index df4d8afb..c1fa8763 100644 --- a/src/systemd/src/libsystemd-network/dhcp-identifier.c +++ b/src/systemd/src/libsystemd-network/dhcp-identifier.c @@ -1,4 +1,3 @@ -/* SPDX-License-Identifier: LGPL-2.1+ */ /*** This file is part of systemd. diff --git a/src/systemd/src/libsystemd-network/dhcp-identifier.h b/src/systemd/src/libsystemd-network/dhcp-identifier.h index 0ccee7a7..1cc0f9fb 100644 --- a/src/systemd/src/libsystemd-network/dhcp-identifier.h +++ b/src/systemd/src/libsystemd-network/dhcp-identifier.h @@ -1,4 +1,3 @@ -/* SPDX-License-Identifier: LGPL-2.1+ */ #pragma once /*** diff --git a/src/systemd/src/libsystemd-network/dhcp-internal.h b/src/systemd/src/libsystemd-network/dhcp-internal.h index a5352695..3fdf02da 100644 --- a/src/systemd/src/libsystemd-network/dhcp-internal.h +++ b/src/systemd/src/libsystemd-network/dhcp-internal.h @@ -1,4 +1,3 @@ -/* SPDX-License-Identifier: LGPL-2.1+ */ #pragma once /*** diff --git a/src/systemd/src/libsystemd-network/dhcp-lease-internal.h b/src/systemd/src/libsystemd-network/dhcp-lease-internal.h index 65c182f4..7847ce07 100644 --- a/src/systemd/src/libsystemd-network/dhcp-lease-internal.h +++ b/src/systemd/src/libsystemd-network/dhcp-lease-internal.h @@ -1,4 +1,3 @@ -/* SPDX-License-Identifier: LGPL-2.1+ */ #pragma once /*** @@ -34,8 +33,6 @@ struct sd_dhcp_route { struct in_addr dst_addr; struct in_addr gw_addr; unsigned char dst_prefixlen; - - uint8_t option; }; struct sd_dhcp_raw_option { diff --git a/src/systemd/src/libsystemd-network/dhcp-network.c b/src/systemd/src/libsystemd-network/dhcp-network.c index d9067ffb..f01b2cfe 100644 --- a/src/systemd/src/libsystemd-network/dhcp-network.c +++ b/src/systemd/src/libsystemd-network/dhcp-network.c @@ -1,4 +1,3 @@ -/* SPDX-License-Identifier: LGPL-2.1+ */ /*** This file is part of systemd. @@ -34,7 +33,6 @@ #include "dhcp-internal.h" #include "fd-util.h" #include "socket-util.h" -#include "unaligned.h" static int _bind_raw_socket(int ifindex, union sockaddr_union *link, uint32_t xid, const uint8_t *mac_addr, @@ -73,13 +71,13 @@ static int _bind_raw_socket(int ifindex, union sockaddr_union *link, BPF_STMT(BPF_LD + BPF_W + BPF_ABS, offsetof(DHCPPacket, dhcp.xid)), /* A <- client identifier */ BPF_JUMP(BPF_JMP + BPF_JEQ + BPF_K, xid, 1, 0), /* client identifier == xid ? */ BPF_STMT(BPF_RET + BPF_K, 0), /* ignore */ - BPF_STMT(BPF_LD + BPF_IMM, unaligned_read_be32(ð_mac->ether_addr_octet[0])), /* A <- 4 bytes of client's MAC */ + BPF_STMT(BPF_LD + BPF_IMM, htobe32(*((unsigned int *) eth_mac))), /* A <- 4 bytes of client's MAC */ BPF_STMT(BPF_MISC + BPF_TAX, 0), /* X <- A */ BPF_STMT(BPF_LD + BPF_W + BPF_ABS, offsetof(DHCPPacket, dhcp.chaddr)), /* A <- 4 bytes of MAC from dhcp.chaddr */ BPF_STMT(BPF_ALU + BPF_XOR + BPF_X, 0), /* A xor X */ BPF_JUMP(BPF_JMP + BPF_JEQ + BPF_K, 0, 1, 0), /* A == 0 ? */ BPF_STMT(BPF_RET + BPF_K, 0), /* ignore */ - BPF_STMT(BPF_LD + BPF_IMM, unaligned_read_be16(ð_mac->ether_addr_octet[4])), /* A <- remainder of client's MAC */ + BPF_STMT(BPF_LD + BPF_IMM, htobe16(*((unsigned short *) (((char *) eth_mac) + 4)))), /* A <- remainder of client's MAC */ BPF_STMT(BPF_MISC + BPF_TAX, 0), /* X <- A */ BPF_STMT(BPF_LD + BPF_H + BPF_ABS, offsetof(DHCPPacket, dhcp.chaddr) + 4), /* A <- remainder of MAC from dhcp.chaddr */ BPF_STMT(BPF_ALU + BPF_XOR + BPF_X, 0), /* A xor X */ @@ -125,7 +123,10 @@ static int _bind_raw_socket(int ifindex, union sockaddr_union *link, if (r < 0) return -errno; - return TAKE_FD(s); + r = s; + s = -1; + + return r; } int dhcp_network_bind_raw_socket(int ifindex, union sockaddr_union *link, @@ -210,7 +211,10 @@ int dhcp_network_bind_udp_socket(int ifindex, be32_t address, uint16_t port) { if (r < 0) return -errno; - return TAKE_FD(s); + r = s; + s = -1; + + return r; } int dhcp_network_send_raw_socket(int s, const union sockaddr_union *link, diff --git a/src/systemd/src/libsystemd-network/dhcp-option.c b/src/systemd/src/libsystemd-network/dhcp-option.c index 08ed8a9f..e003e088 100644 --- a/src/systemd/src/libsystemd-network/dhcp-option.c +++ b/src/systemd/src/libsystemd-network/dhcp-option.c @@ -1,4 +1,3 @@ -/* SPDX-License-Identifier: LGPL-2.1+ */ /*** This file is part of systemd. @@ -193,7 +192,9 @@ static int parse_options(const uint8_t options[], size_t buflen, uint8_t *overlo if (!ascii_is_valid(string)) return -EINVAL; - free_and_replace(*error_message, string); + free(*error_message); + *error_message = string; + string = NULL; } break; @@ -255,8 +256,10 @@ int dhcp_option_parse(DHCPMessage *message, size_t len, dhcp_option_callback_t c if (message_type == 0) return -ENOMSG; - if (_error_message && IN_SET(message_type, DHCP_NAK, DHCP_DECLINE)) - *_error_message = TAKE_PTR(error_message); + if (_error_message && IN_SET(message_type, DHCP_NAK, DHCP_DECLINE)) { + *_error_message = error_message; + error_message = NULL; + } return message_type; } diff --git a/src/systemd/src/libsystemd-network/dhcp-packet.c b/src/systemd/src/libsystemd-network/dhcp-packet.c index 6d8f01f2..1bb1bfcf 100644 --- a/src/systemd/src/libsystemd-network/dhcp-packet.c +++ b/src/systemd/src/libsystemd-network/dhcp-packet.c @@ -1,4 +1,3 @@ -/* SPDX-License-Identifier: LGPL-2.1+ */ /*** This file is part of systemd. diff --git a/src/systemd/src/libsystemd-network/dhcp-protocol.h b/src/systemd/src/libsystemd-network/dhcp-protocol.h index 73a9f75e..5cf7abbf 100644 --- a/src/systemd/src/libsystemd-network/dhcp-protocol.h +++ b/src/systemd/src/libsystemd-network/dhcp-protocol.h @@ -1,4 +1,3 @@ -/* SPDX-License-Identifier: LGPL-2.1+ */ #pragma once /*** diff --git a/src/systemd/src/libsystemd-network/dhcp6-internal.h b/src/systemd/src/libsystemd-network/dhcp6-internal.h index 13844a86..945c3b97 100644 --- a/src/systemd/src/libsystemd-network/dhcp6-internal.h +++ b/src/systemd/src/libsystemd-network/dhcp6-internal.h @@ -1,4 +1,3 @@ -/* SPDX-License-Identifier: LGPL-2.1+ */ #pragma once /*** @@ -29,65 +28,25 @@ #include "macro.h" #include "sparse-endian.h" -/* Common option header */ -typedef struct DHCP6Option { - be16_t code; - be16_t len; - uint8_t data[]; -} _packed_ DHCP6Option; - -/* Address option */ -struct iaaddr { - struct in6_addr address; - be32_t lifetime_preferred; - be32_t lifetime_valid; -} _packed_; - -/* Prefix Delegation Prefix option */ -struct iapdprefix { - be32_t lifetime_preferred; - be32_t lifetime_valid; - uint8_t prefixlen; - struct in6_addr address; -} _packed_; - typedef struct DHCP6Address DHCP6Address; struct DHCP6Address { LIST_FIELDS(DHCP6Address, addresses); - union { - struct iaaddr iaaddr; - struct iapdprefix iapdprefix; - }; + struct { + struct in6_addr address; + be32_t lifetime_preferred; + be32_t lifetime_valid; + } iaaddr _packed_; }; -/* Non-temporary Address option */ -struct ia_na { - be32_t id; - be32_t lifetime_t1; - be32_t lifetime_t2; -} _packed_; - -/* Prefix Delegation option */ -struct ia_pd { - be32_t id; - be32_t lifetime_t1; - be32_t lifetime_t2; -} _packed_; - -/* Temporary Address option */ -struct ia_ta { - be32_t id; -} _packed_; - struct DHCP6IA { uint16_t type; - union { - struct ia_na ia_na; - struct ia_pd ia_pd; - struct ia_ta ia_ta; - }; + struct { + be32_t id; + be32_t lifetime_t1; + be32_t lifetime_t2; + } _packed_; sd_event_source *timeout_t1; sd_event_source *timeout_t2; @@ -102,12 +61,10 @@ typedef struct DHCP6IA DHCP6IA; int dhcp6_option_append(uint8_t **buf, size_t *buflen, uint16_t code, size_t optlen, const void *optval); int dhcp6_option_append_ia(uint8_t **buf, size_t *buflen, DHCP6IA *ia); -int dhcp6_option_append_pd(uint8_t *buf, size_t len, DHCP6IA *pd); -int dhcp6_option_append_fqdn(uint8_t **buf, size_t *buflen, const char *fqdn); int dhcp6_option_parse(uint8_t **buf, size_t *buflen, uint16_t *optcode, size_t *optlen, uint8_t **optvalue); -int dhcp6_option_parse_status(DHCP6Option *option); -int dhcp6_option_parse_ia(DHCP6Option *iaoption, DHCP6IA *ia); +int dhcp6_option_parse_ia(uint8_t **buf, size_t *buflen, uint16_t iatype, + DHCP6IA *ia); int dhcp6_option_parse_ip6addrs(uint8_t *optval, uint16_t optlen, struct in6_addr **addrs, size_t count, size_t *allocated); diff --git a/src/systemd/src/libsystemd-network/dhcp6-lease-internal.h b/src/systemd/src/libsystemd-network/dhcp6-lease-internal.h index 45e0e824..14e708ef 100644 --- a/src/systemd/src/libsystemd-network/dhcp6-lease-internal.h +++ b/src/systemd/src/libsystemd-network/dhcp6-lease-internal.h @@ -1,4 +1,3 @@ -/* SPDX-License-Identifier: LGPL-2.1+ */ #pragma once /*** @@ -36,10 +35,8 @@ struct sd_dhcp6_lease { bool rapid_commit; DHCP6IA ia; - DHCP6IA pd; DHCP6Address *addr_iter; - DHCP6Address *prefix_iter; struct in6_addr *dns; size_t dns_count; diff --git a/src/systemd/src/libsystemd-network/dhcp6-network.c b/src/systemd/src/libsystemd-network/dhcp6-network.c index 85231084..e4883019 100644 --- a/src/systemd/src/libsystemd-network/dhcp6-network.c +++ b/src/systemd/src/libsystemd-network/dhcp6-network.c @@ -1,4 +1,3 @@ -/* SPDX-License-Identifier: LGPL-2.1+ */ /*** This file is part of systemd. @@ -69,7 +68,9 @@ int dhcp6_network_bind_udp_socket(int index, struct in6_addr *local_address) { if (r < 0) return -errno; - return TAKE_FD(s); + r = s; + s = -1; + return r; } int dhcp6_network_send_udp_socket(int s, struct in6_addr *server_address, diff --git a/src/systemd/src/libsystemd-network/dhcp6-option.c b/src/systemd/src/libsystemd-network/dhcp6-option.c index d449a9c7..3a77e34d 100644 --- a/src/systemd/src/libsystemd-network/dhcp6-option.c +++ b/src/systemd/src/libsystemd-network/dhcp6-option.c @@ -1,4 +1,3 @@ -/* SPDX-License-Identifier: LGPL-2.1+ */ /*** This file is part of systemd. @@ -28,7 +27,6 @@ #include "alloc-util.h" #include "dhcp6-internal.h" -#include "dhcp6-lease-internal.h" #include "dhcp6-protocol.h" #include "dns-domain.h" #include "sparse-endian.h" @@ -36,27 +34,14 @@ #include "unaligned.h" #include "util.h" -typedef struct DHCP6StatusOption { - struct DHCP6Option option; - be16_t status; - char msg[]; -} _packed_ DHCP6StatusOption; +#define DHCP6_OPTION_IA_NA_LEN 12 +#define DHCP6_OPTION_IA_TA_LEN 4 -typedef struct DHCP6AddressOption { - struct DHCP6Option option; - struct iaaddr iaaddr; - uint8_t options[]; -} _packed_ DHCP6AddressOption; - -typedef struct DHCP6PDPrefixOption { - struct DHCP6Option option; - struct iapdprefix iapdprefix; - uint8_t options[]; -} _packed_ DHCP6PDPrefixOption; - -#define DHCP6_OPTION_IA_NA_LEN (sizeof(struct ia_na)) -#define DHCP6_OPTION_IA_PD_LEN (sizeof(struct ia_pd)) -#define DHCP6_OPTION_IA_TA_LEN (sizeof(struct ia_ta)) +typedef struct DHCP6Option { + be16_t code; + be16_t len; + uint8_t data[]; +} _packed_ DHCP6Option; static int option_append_hdr(uint8_t **buf, size_t *buflen, uint16_t optcode, size_t optlen) { @@ -99,7 +84,7 @@ int dhcp6_option_append(uint8_t **buf, size_t *buflen, uint16_t code, int dhcp6_option_append_ia(uint8_t **buf, size_t *buflen, DHCP6IA *ia) { uint16_t len; uint8_t *ia_hdr; - size_t iaid_offset, ia_buflen, ia_addrlen = 0; + size_t ia_buflen, ia_addrlen = 0; DHCP6Address *addr; int r; @@ -108,12 +93,10 @@ int dhcp6_option_append_ia(uint8_t **buf, size_t *buflen, DHCP6IA *ia) { switch (ia->type) { case SD_DHCP6_OPTION_IA_NA: len = DHCP6_OPTION_IA_NA_LEN; - iaid_offset = offsetof(DHCP6IA, ia_na); break; case SD_DHCP6_OPTION_IA_TA: len = DHCP6_OPTION_IA_TA_LEN; - iaid_offset = offsetof(DHCP6IA, ia_ta); break; default: @@ -129,7 +112,7 @@ int dhcp6_option_append_ia(uint8_t **buf, size_t *buflen, DHCP6IA *ia) { *buf += sizeof(DHCP6Option); *buflen -= sizeof(DHCP6Option); - memcpy(*buf, (char*) ia + iaid_offset, len); + memcpy(*buf, &ia->id, len); *buf += len; *buflen -= len; @@ -155,69 +138,6 @@ int dhcp6_option_append_ia(uint8_t **buf, size_t *buflen, DHCP6IA *ia) { return 0; } -int dhcp6_option_append_fqdn(uint8_t **buf, size_t *buflen, const char *fqdn) { - uint8_t buffer[1 + DNS_WIRE_FOMAT_HOSTNAME_MAX]; - int r; - - assert_return(buf && *buf && buflen && fqdn, -EINVAL); - - buffer[0] = DHCP6_FQDN_FLAG_S; /* Request server to perform AAAA RR DNS updates */ - - /* Store domain name after flags field */ - r = dns_name_to_wire_format(fqdn, buffer + 1, sizeof(buffer) - 1, false); - if (r <= 0) - return r; - - /* - * According to RFC 4704, chapter 4.2 only add terminating zero-length - * label in case a FQDN is provided. Since dns_name_to_wire_format - * always adds terminating zero-length label remove if only a hostname - * is provided. - */ - if (dns_name_is_single_label(fqdn)) - r--; - - r = dhcp6_option_append(buf, buflen, SD_DHCP6_OPTION_FQDN, 1 + r, buffer); - - return r; -} - -int dhcp6_option_append_pd(uint8_t *buf, size_t len, DHCP6IA *pd) { - DHCP6Option *option = (DHCP6Option *)buf; - size_t i = sizeof(*option) + sizeof(pd->ia_pd); - DHCP6Address *prefix; - - assert_return(buf, -EINVAL); - assert_return(pd, -EINVAL); - assert_return(pd->type == SD_DHCP6_OPTION_IA_PD, -EINVAL); - - if (len < i) - return -ENOBUFS; - - option->code = htobe16(SD_DHCP6_OPTION_IA_PD); - - memcpy(&option->data, &pd->ia_pd, sizeof(pd->ia_pd)); - - LIST_FOREACH(addresses, prefix, pd->addresses) { - DHCP6PDPrefixOption *prefix_opt; - - if (len < i + sizeof(*prefix_opt)) - return -ENOBUFS; - - prefix_opt = (DHCP6PDPrefixOption *)&buf[i]; - prefix_opt->option.code = htobe16(SD_DHCP6_OPTION_IA_PD_PREFIX); - prefix_opt->option.len = htobe16(sizeof(prefix_opt->iapdprefix)); - - memcpy(&prefix_opt->iapdprefix, &prefix->iapdprefix, - sizeof(struct iapdprefix)); - - i += sizeof(*prefix_opt); - } - - option->len = htobe16(i - sizeof(*option)); - - return i; -} static int option_parse_hdr(uint8_t **buf, size_t *buflen, uint16_t *optcode, size_t *optlen) { DHCP6Option *option = (DHCP6Option*) *buf; @@ -264,147 +184,35 @@ int dhcp6_option_parse(uint8_t **buf, size_t *buflen, uint16_t *optcode, return 0; } -int dhcp6_option_parse_status(DHCP6Option *option) { - DHCP6StatusOption *statusopt = (DHCP6StatusOption *)option; - - if (be16toh(option->len) + sizeof(DHCP6Option) < sizeof(*statusopt)) - return -ENOBUFS; - - return be16toh(statusopt->status); -} - -static int dhcp6_option_parse_address(DHCP6Option *option, DHCP6IA *ia, - uint32_t *lifetime_valid) { - DHCP6AddressOption *addr_option = (DHCP6AddressOption *)option; - DHCP6Address *addr; - uint32_t lt_valid, lt_pref; - int r; - - if (be16toh(option->len) + sizeof(DHCP6Option) < sizeof(*addr_option)) - return -ENOBUFS; - - lt_valid = be32toh(addr_option->iaaddr.lifetime_valid); - lt_pref = be32toh(addr_option->iaaddr.lifetime_preferred); - - if (lt_valid == 0 || lt_pref > lt_valid) { - log_dhcp6_client(client, "Valid lifetime of an IA address is zero or preferred lifetime %d > valid lifetime %d", - lt_pref, lt_valid); - - return 0; - } - - if (be16toh(option->len) + sizeof(DHCP6Option) > sizeof(*addr_option)) { - r = dhcp6_option_parse_status((DHCP6Option *)addr_option->options); - if (r != 0) - return r < 0 ? r: 0; - } - - addr = new0(DHCP6Address, 1); - if (!addr) - return -ENOMEM; - - LIST_INIT(addresses, addr); - memcpy(&addr->iaaddr, option->data, sizeof(addr->iaaddr)); - - LIST_PREPEND(addresses, ia->addresses, addr); - - *lifetime_valid = be32toh(addr->iaaddr.lifetime_valid); - - return 0; -} - -static int dhcp6_option_parse_pdprefix(DHCP6Option *option, DHCP6IA *ia, - uint32_t *lifetime_valid) { - DHCP6PDPrefixOption *pdprefix_option = (DHCP6PDPrefixOption *)option; - DHCP6Address *prefix; - uint32_t lt_valid, lt_pref; +int dhcp6_option_parse_ia(uint8_t **buf, size_t *buflen, uint16_t iatype, + DHCP6IA *ia) { int r; - - if (be16toh(option->len) + sizeof(DHCP6Option) < sizeof(*pdprefix_option)) - return -ENOBUFS; - - lt_valid = be32toh(pdprefix_option->iapdprefix.lifetime_valid); - lt_pref = be32toh(pdprefix_option->iapdprefix.lifetime_preferred); - - if (lt_valid == 0 || lt_pref > lt_valid) { - log_dhcp6_client(client, "Valid lifetieme of a PD prefix is zero or preferred lifetime %d > valid lifetime %d", - lt_pref, lt_valid); - - return 0; - } - - if (be16toh(option->len) + sizeof(DHCP6Option) > sizeof(*pdprefix_option)) { - r = dhcp6_option_parse_status((DHCP6Option *)pdprefix_option->options); - if (r != 0) - return r < 0 ? r: 0; - } - - prefix = new0(DHCP6Address, 1); - if (!prefix) - return -ENOMEM; - - LIST_INIT(addresses, prefix); - memcpy(&prefix->iapdprefix, option->data, sizeof(prefix->iapdprefix)); - - LIST_PREPEND(addresses, ia->addresses, prefix); - - *lifetime_valid = be32toh(prefix->iapdprefix.lifetime_valid); - - return 0; -} - -int dhcp6_option_parse_ia(DHCP6Option *iaoption, DHCP6IA *ia) { - uint16_t iatype, optlen; - size_t i, len; - int r = 0, status; - uint16_t opt; + uint16_t opt, status; + size_t optlen; size_t iaaddr_offset; - uint32_t lt_t1, lt_t2, lt_valid = 0, lt_min = UINT32_MAX; + DHCP6Address *addr; + uint32_t lt_t1, lt_t2, lt_valid, lt_pref, lt_min = ~0; assert_return(ia, -EINVAL); assert_return(!ia->addresses, -EINVAL); - iatype = be16toh(iaoption->code); - len = be16toh(iaoption->len); - switch (iatype) { case SD_DHCP6_OPTION_IA_NA: - if (len < DHCP6_OPTION_IA_NA_LEN) { + if (*buflen < DHCP6_OPTION_IA_NA_LEN + sizeof(DHCP6Option) + + sizeof(addr->iaaddr)) { r = -ENOBUFS; goto error; } iaaddr_offset = DHCP6_OPTION_IA_NA_LEN; - memcpy(&ia->ia_na, iaoption->data, sizeof(ia->ia_na)); - - lt_t1 = be32toh(ia->ia_na.lifetime_t1); - lt_t2 = be32toh(ia->ia_na.lifetime_t2); - - if (lt_t1 && lt_t2 && lt_t1 > lt_t2) { - log_dhcp6_client(client, "IA NA T1 %ds > T2 %ds", - lt_t1, lt_t2); - r = -EINVAL; - goto error; - } - - break; + memcpy(&ia->id, *buf, iaaddr_offset); - case SD_DHCP6_OPTION_IA_PD: - - if (len < sizeof(ia->ia_pd)) { - r = -ENOBUFS; - goto error; - } - - iaaddr_offset = sizeof(ia->ia_pd); - memcpy(&ia->ia_pd, iaoption->data, sizeof(ia->ia_pd)); - - lt_t1 = be32toh(ia->ia_pd.lifetime_t1); - lt_t2 = be32toh(ia->ia_pd.lifetime_t2); + lt_t1 = be32toh(ia->lifetime_t1); + lt_t2 = be32toh(ia->lifetime_t2); if (lt_t1 && lt_t2 && lt_t1 > lt_t2) { - log_dhcp6_client(client, "IA PD T1 %ds > T2 %ds", + log_dhcp6_client(client, "IA T1 %ds > T2 %ds", lt_t1, lt_t2); r = -EINVAL; goto error; @@ -413,13 +221,17 @@ int dhcp6_option_parse_ia(DHCP6Option *iaoption, DHCP6IA *ia) { break; case SD_DHCP6_OPTION_IA_TA: - if (len < DHCP6_OPTION_IA_TA_LEN) { + if (*buflen < DHCP6_OPTION_IA_TA_LEN + sizeof(DHCP6Option) + + sizeof(addr->iaaddr)) { r = -ENOBUFS; goto error; } iaaddr_offset = DHCP6_OPTION_IA_TA_LEN; - memcpy(&ia->ia_ta.id, iaoption->data, sizeof(ia->ia_ta)); + memcpy(&ia->id, *buf, iaaddr_offset); + + ia->lifetime_t1 = 0; + ia->lifetime_t2 = 0; break; @@ -429,63 +241,48 @@ int dhcp6_option_parse_ia(DHCP6Option *iaoption, DHCP6IA *ia) { } ia->type = iatype; - i = iaaddr_offset; - while (i < len) { - DHCP6Option *option = (DHCP6Option *)&iaoption->data[i]; - - if (len < i + sizeof(*option) || len < i + sizeof(*option) + be16toh(option->len)) { - r = -ENOBUFS; - goto error; - } + *buflen -= iaaddr_offset; + *buf += iaaddr_offset; - opt = be16toh(option->code); - optlen = be16toh(option->len); + while ((r = option_parse_hdr(buf, buflen, &opt, &optlen)) >= 0) { switch (opt) { case SD_DHCP6_OPTION_IAADDR: - if (!IN_SET(ia->type, SD_DHCP6_OPTION_IA_NA, SD_DHCP6_OPTION_IA_TA)) { - log_dhcp6_client(client, "IA Address option not in IA NA or TA option"); - r = -EINVAL; + addr = new0(DHCP6Address, 1); + if (!addr) { + r = -ENOMEM; goto error; } - r = dhcp6_option_parse_address(option, ia, <_valid); - if (r < 0) - goto error; - - if (lt_valid < lt_min) - lt_min = lt_valid; + LIST_INIT(addresses, addr); - break; + memcpy(&addr->iaaddr, *buf, sizeof(addr->iaaddr)); - case SD_DHCP6_OPTION_IA_PD_PREFIX: + lt_valid = be32toh(addr->iaaddr.lifetime_valid); + lt_pref = be32toh(addr->iaaddr.lifetime_valid); - if (!IN_SET(ia->type, SD_DHCP6_OPTION_IA_PD)) { - log_dhcp6_client(client, "IA PD Prefix option not in IA PD option"); - r = -EINVAL; - goto error; + if (!lt_valid || lt_pref > lt_valid) { + log_dhcp6_client(client, "IA preferred %ds > valid %ds", + lt_pref, lt_valid); + free(addr); + } else { + LIST_PREPEND(addresses, ia->addresses, addr); + if (lt_valid < lt_min) + lt_min = lt_valid; } - r = dhcp6_option_parse_pdprefix(option, ia, <_valid); - if (r < 0) - goto error; - - if (lt_valid < lt_min) - lt_min = lt_valid; - break; case SD_DHCP6_OPTION_STATUS_CODE: + if (optlen < sizeof(status)) + break; - status = dhcp6_option_parse_status(option); + status = (*buf)[0] << 8 | (*buf)[1]; if (status) { log_dhcp6_client(client, "IA status %d", status); - - dhcp6_lease_free_ia(ia); - r = -EINVAL; goto error; } @@ -497,41 +294,30 @@ int dhcp6_option_parse_ia(DHCP6Option *iaoption, DHCP6IA *ia) { break; } - i += sizeof(*option) + optlen; + *buflen -= optlen; + *buf += optlen; } - switch(iatype) { - case SD_DHCP6_OPTION_IA_NA: - if (!ia->ia_na.lifetime_t1 && !ia->ia_na.lifetime_t2) { - lt_t1 = lt_min / 2; - lt_t2 = lt_min / 10 * 8; - ia->ia_na.lifetime_t1 = htobe32(lt_t1); - ia->ia_na.lifetime_t2 = htobe32(lt_t2); - - log_dhcp6_client(client, "Computed IA NA T1 %ds and T2 %ds as both were zero", - lt_t1, lt_t2); - } - - break; - - case SD_DHCP6_OPTION_IA_PD: - if (!ia->ia_pd.lifetime_t1 && !ia->ia_pd.lifetime_t2) { - lt_t1 = lt_min / 2; - lt_t2 = lt_min / 10 * 8; - ia->ia_pd.lifetime_t1 = htobe32(lt_t1); - ia->ia_pd.lifetime_t2 = htobe32(lt_t2); + if (r == -ENOMSG) + r = 0; - log_dhcp6_client(client, "Computed IA PD T1 %ds and T2 %ds as both were zero", - lt_t1, lt_t2); - } + if (!ia->lifetime_t1 && !ia->lifetime_t2) { + lt_t1 = lt_min / 2; + lt_t2 = lt_min / 10 * 8; + ia->lifetime_t1 = htobe32(lt_t1); + ia->lifetime_t2 = htobe32(lt_t2); - break; - - default: - break; + log_dhcp6_client(client, "Computed IA T1 %ds and T2 %ds as both were zero", + lt_t1, lt_t2); } + if (*buflen) + r = -ENOMSG; + error: + *buf += *buflen; + *buflen = 0; + return r; } @@ -619,7 +405,8 @@ int dhcp6_option_parse_domainname(const uint8_t *optval, uint16_t optlen, char * idx++; } - *str_arr = TAKE_PTR(names); + *str_arr = names; + names = NULL; return idx; diff --git a/src/systemd/src/libsystemd-network/dhcp6-protocol.h b/src/systemd/src/libsystemd-network/dhcp6-protocol.h index 5f7e809b..2487c470 100644 --- a/src/systemd/src/libsystemd-network/dhcp6-protocol.h +++ b/src/systemd/src/libsystemd-network/dhcp6-protocol.h @@ -1,4 +1,3 @@ -/* SPDX-License-Identifier: LGPL-2.1+ */ #pragma once /*** @@ -34,7 +33,6 @@ struct DHCP6Message { } _packed_; be32_t transaction_id; }; - uint8_t options[]; } _packed_; typedef struct DHCP6Message DHCP6Message; @@ -106,9 +104,3 @@ enum { DHCP6_STATUS_USE_MULTICAST = 5, _DHCP6_STATUS_MAX = 6, }; - -enum { - DHCP6_FQDN_FLAG_S = (1 << 0), - DHCP6_FQDN_FLAG_O = (1 << 1), - DHCP6_FQDN_FLAG_N = (1 << 2), -}; diff --git a/src/systemd/src/libsystemd-network/lldp-internal.h b/src/systemd/src/libsystemd-network/lldp-internal.h index 2673aa1c..becc162f 100644 --- a/src/systemd/src/libsystemd-network/lldp-internal.h +++ b/src/systemd/src/libsystemd-network/lldp-internal.h @@ -1,4 +1,3 @@ -/* SPDX-License-Identifier: LGPL-2.1+ */ #pragma once /*** diff --git a/src/systemd/src/libsystemd-network/lldp-neighbor.c b/src/systemd/src/libsystemd-network/lldp-neighbor.c index cffbfb98..c560a864 100644 --- a/src/systemd/src/libsystemd-network/lldp-neighbor.c +++ b/src/systemd/src/libsystemd-network/lldp-neighbor.c @@ -1,4 +1,3 @@ -/* SPDX-License-Identifier: LGPL-2.1+ */ /*** This file is part of systemd. diff --git a/src/systemd/src/libsystemd-network/lldp-neighbor.h b/src/systemd/src/libsystemd-network/lldp-neighbor.h index 76d4c0c7..c1a7606d 100644 --- a/src/systemd/src/libsystemd-network/lldp-neighbor.h +++ b/src/systemd/src/libsystemd-network/lldp-neighbor.h @@ -1,4 +1,3 @@ -/* SPDX-License-Identifier: LGPL-2.1+ */ #pragma once /*** diff --git a/src/systemd/src/libsystemd-network/lldp-network.c b/src/systemd/src/libsystemd-network/lldp-network.c index b8a10d54..4466a050 100644 --- a/src/systemd/src/libsystemd-network/lldp-network.c +++ b/src/systemd/src/libsystemd-network/lldp-network.c @@ -1,4 +1,3 @@ -/* SPDX-License-Identifier: LGPL-2.1+ */ /*** This file is part of systemd. @@ -94,5 +93,8 @@ int lldp_network_bind_raw_socket(int ifindex) { if (r < 0) return -errno; - return TAKE_FD(fd); + r = fd; + fd = -1; + + return r; } diff --git a/src/systemd/src/libsystemd-network/lldp-network.h b/src/systemd/src/libsystemd-network/lldp-network.h index c0f8cbe1..c4cf8c79 100644 --- a/src/systemd/src/libsystemd-network/lldp-network.h +++ b/src/systemd/src/libsystemd-network/lldp-network.h @@ -1,4 +1,3 @@ -/* SPDX-License-Identifier: LGPL-2.1+ */ #pragma once /*** diff --git a/src/systemd/src/libsystemd-network/network-internal.c b/src/systemd/src/libsystemd-network/network-internal.c index a8a5658b..de37b9f0 100644 --- a/src/systemd/src/libsystemd-network/network-internal.c +++ b/src/systemd/src/libsystemd-network/network-internal.c @@ -1,4 +1,3 @@ -/* SPDX-License-Identifier: LGPL-2.1+ */ /*** This file is part of systemd. @@ -24,7 +23,6 @@ #include <linux/if.h> #include <netinet/ether.h> -#include "sd-id128.h" #include "sd-ndisc.h" #include "alloc-util.h" @@ -120,8 +118,7 @@ bool net_match_config(const struct ether_addr *match_mac, char * const *match_names, Condition *match_host, Condition *match_virt, - Condition *match_kernel_cmdline, - Condition *match_kernel_version, + Condition *match_kernel, Condition *match_arch, const struct ether_addr *dev_mac, const char *dev_path, @@ -136,10 +133,7 @@ bool net_match_config(const struct ether_addr *match_mac, if (match_virt && condition_test(match_virt) <= 0) return false; - if (match_kernel_cmdline && condition_test(match_kernel_cmdline) <= 0) - return false; - - if (match_kernel_version && condition_test(match_kernel_version) <= 0) + if (match_kernel && condition_test(match_kernel) <= 0) return false; if (match_arch && condition_test(match_arch) <= 0) @@ -279,9 +273,10 @@ int config_parse_ifalias(const char *unit, } free(*s); - if (*n) - *s = TAKE_PTR(n); - else + if (*n) { + *s = n; + n = NULL; + } else *s = NULL; return 0; @@ -427,7 +422,7 @@ int deserialize_in_addrs(struct in_addr **ret, const char *string) { if (r == 0) break; - new_addresses = reallocarray(addresses, size + 1, sizeof(struct in_addr)); + new_addresses = realloc(addresses, (size + 1) * sizeof(struct in_addr)); if (!new_addresses) return -ENOMEM; else @@ -440,7 +435,8 @@ int deserialize_in_addrs(struct in_addr **ret, const char *string) { size++; } - *ret = TAKE_PTR(addresses); + *ret = addresses; + addresses = NULL; return size; } @@ -480,7 +476,7 @@ int deserialize_in6_addrs(struct in6_addr **ret, const char *string) { if (r == 0) break; - new_addresses = reallocarray(addresses, size + 1, sizeof(struct in6_addr)); + new_addresses = realloc(addresses, (size + 1) * sizeof(struct in6_addr)); if (!new_addresses) return -ENOMEM; else @@ -493,7 +489,8 @@ int deserialize_in6_addrs(struct in6_addr **ret, const char *string) { size++; } - *ret = TAKE_PTR(addresses); + *ret = addresses; + addresses = NULL; return size; } @@ -586,7 +583,8 @@ int deserialize_dhcp_routes(struct sd_dhcp_route **ret, size_t *ret_size, size_t *ret_size = size; *ret_allocated = allocated; - *ret = TAKE_PTR(routes); + *ret = routes; + routes = NULL; return 0; } diff --git a/src/systemd/src/libsystemd-network/network-internal.h b/src/systemd/src/libsystemd-network/network-internal.h index 4e69f1a5..4666f174 100644 --- a/src/systemd/src/libsystemd-network/network-internal.h +++ b/src/systemd/src/libsystemd-network/network-internal.h @@ -1,4 +1,3 @@ -/* SPDX-License-Identifier: LGPL-2.1+ */ #pragma once /*** @@ -37,8 +36,7 @@ bool net_match_config(const struct ether_addr *match_mac, char * const *match_name, Condition *match_host, Condition *match_virt, - Condition *match_kernel_cmdline, - Condition *match_kernel_version, + Condition *match_kernel, Condition *match_arch, const struct ether_addr *dev_mac, const char *dev_path, diff --git a/src/systemd/src/libsystemd-network/sd-dhcp-client.c b/src/systemd/src/libsystemd-network/sd-dhcp-client.c index b93b7334..5eab0050 100644 --- a/src/systemd/src/libsystemd-network/sd-dhcp-client.c +++ b/src/systemd/src/libsystemd-network/sd-dhcp-client.c @@ -1,4 +1,3 @@ -/* SPDX-License-Identifier: LGPL-2.1+ */ /*** This file is part of systemd. @@ -358,10 +357,9 @@ int sd_dhcp_client_set_client_id( * without further modification. Otherwise, if duid_type is supported, DUID * is set based on that type. Otherwise, an error is returned. */ -static int dhcp_client_set_iaid_duid( +int sd_dhcp_client_set_iaid_duid( sd_dhcp_client *client, uint32_t iaid, - bool append_iaid, uint16_t duid_type, const void *duid, size_t duid_len) { @@ -382,17 +380,15 @@ static int dhcp_client_set_iaid_duid( zero(client->client_id); client->client_id.type = 255; - if (append_iaid) { - /* If IAID is not configured, generate it. */ - if (iaid == 0) { - r = dhcp_identifier_set_iaid(client->ifindex, client->mac_addr, - client->mac_addr_len, - &client->client_id.ns.iaid); - if (r < 0) - return r; - } else - client->client_id.ns.iaid = htobe32(iaid); - } + /* If IAID is not configured, generate it. */ + if (iaid == 0) { + r = dhcp_identifier_set_iaid(client->ifindex, client->mac_addr, + client->mac_addr_len, + &client->client_id.ns.iaid); + if (r < 0) + return r; + } else + client->client_id.ns.iaid = htobe32(iaid); if (duid != NULL) { client->client_id.ns.duid.type = htobe16(duid_type); @@ -406,7 +402,7 @@ static int dhcp_client_set_iaid_duid( return -EOPNOTSUPP; client->client_id_len = sizeof(client->client_id.type) + len + - (append_iaid ? sizeof(client->client_id.ns.iaid) : 0); + sizeof(client->client_id.ns.iaid); if (!IN_SET(client->state, DHCP_STATE_INIT, DHCP_STATE_STOPPED)) { log_dhcp_client(client, "Configured IAID+DUID, restarting."); @@ -416,23 +412,6 @@ static int dhcp_client_set_iaid_duid( return 0; } - -int sd_dhcp_client_set_iaid_duid( - sd_dhcp_client *client, - uint32_t iaid, - uint16_t duid_type, - const void *duid, - size_t duid_len) { - return dhcp_client_set_iaid_duid(client, iaid, true, duid_type, duid, duid_len); -} - -int sd_dhcp_client_set_duid( - sd_dhcp_client *client, - uint16_t duid_type, - const void *duid, - size_t duid_len) { - return dhcp_client_set_iaid_duid(client, 0, false, duid_type, duid, duid_len); -} #endif /* NM_IGNORED */ int sd_dhcp_client_set_hostname( @@ -441,9 +420,9 @@ int sd_dhcp_client_set_hostname( assert_return(client, -EINVAL); - /* Make sure hostnames qualify as DNS and as Linux hostnames */ + /* Refuse hostnames that neither qualify as DNS nor as Linux hosntames */ if (hostname && - !(hostname_is_valid(hostname, false) && dns_name_is_valid(hostname) > 0)) + !(hostname_is_valid(hostname, false) || dns_name_is_valid(hostname) > 0)) return -EINVAL; return free_and_strdup(&client->hostname, hostname); @@ -854,6 +833,7 @@ static int client_send_request(sd_dhcp_client *client) { client’s IP address. */ + /* fall through */ case DHCP_STATE_REBINDING: /* ’server identifier’ MUST NOT be filled in, ’requested IP address’ option MUST NOT be filled in, ’ciaddr’ MUST be filled in with @@ -1285,9 +1265,9 @@ static int client_handle_offer(sd_dhcp_client *client, DHCPMessage *offer, size_ if (!lease->have_subnet_mask) { r = dhcp_lease_set_default_subnet_mask(lease); if (r < 0) { - log_dhcp_client(client, - "received lease lacks subnet mask, " - "and a fallback one cannot be generated, ignoring"); + log_dhcp_client(client, "received lease lacks subnet " + "mask, and a fallback one can not be " + "generated, ignoring"); return -ENOMSG; } } @@ -1356,9 +1336,9 @@ static int client_handle_ack(sd_dhcp_client *client, DHCPMessage *ack, size_t le if (lease->subnet_mask == INADDR_ANY) { r = dhcp_lease_set_default_subnet_mask(lease); if (r < 0) { - log_dhcp_client(client, - "received lease lacks subnet mask, " - "and a fallback one cannot be generated, ignoring"); + log_dhcp_client(client, "received lease lacks subnet " + "mask, and a fallback one can not be " + "generated, ignoring"); return -ENOMSG; } } diff --git a/src/systemd/src/libsystemd-network/sd-dhcp-lease.c b/src/systemd/src/libsystemd-network/sd-dhcp-lease.c index c272a61e..c00190b5 100644 --- a/src/systemd/src/libsystemd-network/sd-dhcp-lease.c +++ b/src/systemd/src/libsystemd-network/sd-dhcp-lease.c @@ -1,4 +1,3 @@ -/* SPDX-License-Identifier: LGPL-2.1+ */ /*** This file is part of systemd. @@ -24,7 +23,6 @@ #include <arpa/inet.h> #include <errno.h> #include <stdio.h> -#include <stdio_ext.h> #include <stdlib.h> #include <string.h> @@ -396,7 +394,9 @@ static int lease_parse_domain(const uint8_t *option, size_t len, char **ret) { if (dns_name_is_root(normalized)) return -EINVAL; - free_and_replace(*ret, normalized); + free(*ret); + *ret = normalized; + normalized = NULL; return 0; } @@ -473,7 +473,6 @@ static int lease_parse_routes( struct sd_dhcp_route *route = *routes + *routes_size; int r; - route->option = SD_DHCP_OPTION_STATIC_ROUTE; r = in4_addr_default_prefixlen((struct in_addr*) option, &route->dst_prefixlen); if (r < 0) { log_debug("Failed to determine destination prefix length from class based IP, ignoring"); @@ -517,7 +516,6 @@ static int lease_parse_classless_routes( return -ENOMEM; route = *routes + *routes_size; - route->option = SD_DHCP_OPTION_CLASSLESS_STATIC_ROUTE; dst_octets = (*option == 0 ? 0 : ((*option - 1) / 8) + 1); route->dst_prefixlen = *option; @@ -687,7 +685,9 @@ int dhcp_lease_parse_options(uint8_t code, uint8_t len, const void *option, void return 0; } - free_and_replace(lease->timezone, tz); + free(lease->timezone); + lease->timezone = tz; + tz = NULL; break; } @@ -809,7 +809,8 @@ int dhcp_lease_parse_search_domains(const uint8_t *option, size_t len, char ***d pos = next_chunk; } - *domains = TAKE_PTR(names); + *domains = names; + names = NULL; return cnt; } @@ -880,8 +881,7 @@ int dhcp_lease_save(sd_dhcp_lease *lease, const char *lease_file) { if (r < 0) goto fail; - (void) __fsetlocking(f, FSETLOCKING_BYCALLER); - (void) fchmod(fileno(f), 0644); + fchmod(fileno(f), 0644); fprintf(f, "# This is private data. Do not parse.\n"); @@ -928,16 +928,16 @@ int dhcp_lease_save(sd_dhcp_lease *lease, const char *lease_file) { r = sd_dhcp_lease_get_dns(lease, &addresses); if (r > 0) { - fputs("DNS=", f); + fputs_unlocked("DNS=", f); serialize_in_addrs(f, addresses, r); - fputs("\n", f); + fputs_unlocked("\n", f); } r = sd_dhcp_lease_get_ntp(lease, &addresses); if (r > 0) { - fputs("NTP=", f); + fputs_unlocked("NTP=", f); serialize_in_addrs(f, addresses, r); - fputs("\n", f); + fputs_unlocked("\n", f); } r = sd_dhcp_lease_get_domainname(lease, &string); @@ -946,9 +946,9 @@ int dhcp_lease_save(sd_dhcp_lease *lease, const char *lease_file) { r = sd_dhcp_lease_get_search_domains(lease, &search_domains); if (r > 0) { - fputs("DOMAIN_SEARCH_LIST=", f); + fputs_unlocked("DOMAIN_SEARCH_LIST=", f); fputstrv(f, search_domains, NULL, NULL); - fputs("\n", f); + fputs_unlocked("\n", f); } r = sd_dhcp_lease_get_hostname(lease, &string); @@ -992,7 +992,7 @@ int dhcp_lease_save(sd_dhcp_lease *lease, const char *lease_file) { } LIST_FOREACH(options, option, lease->private_options) { - char key[STRLEN("OPTION_000")+1]; + char key[strlen("OPTION_000")+1]; xsprintf(key, "OPTION_%" PRIu8, option->tag); r = serialize_dhcp_option(f, key, option->data, option->length); diff --git a/src/systemd/src/libsystemd-network/sd-dhcp6-client.c b/src/systemd/src/libsystemd-network/sd-dhcp6-client.c index f22daa3c..f512b65b 100644 --- a/src/systemd/src/libsystemd-network/sd-dhcp6-client.c +++ b/src/systemd/src/libsystemd-network/sd-dhcp6-client.c @@ -1,4 +1,3 @@ -/* SPDX-License-Identifier: LGPL-2.1+ */ /*** This file is part of systemd. @@ -32,9 +31,7 @@ #include "dhcp6-internal.h" #include "dhcp6-lease-internal.h" #include "dhcp6-protocol.h" -#include "dns-domain.h" #include "fd-util.h" -#include "hostname-util.h" #include "in-addr-util.h" #include "network-internal.h" #include "random-util.h" @@ -56,8 +53,6 @@ struct sd_dhcp6_client { size_t mac_addr_len; uint16_t arp_type; DHCP6IA ia_na; - DHCP6IA ia_pd; - bool prefix_delegation; be32_t transaction_id; usec_t transaction_start; struct sd_dhcp6_lease *lease; @@ -66,7 +61,6 @@ struct sd_dhcp6_client { be16_t *req_opts; size_t req_opts_allocated; size_t req_opts_len; - char *fqdn; sd_event_source *receive_message; usec_t retransmit_time; uint8_t retransmit_count; @@ -235,27 +229,12 @@ int sd_dhcp6_client_set_iaid(sd_dhcp6_client *client, uint32_t iaid) { assert_return(client, -EINVAL); assert_return(IN_SET(client->state, DHCP6_STATE_STOPPED), -EBUSY); - client->ia_na.ia_na.id = htobe32(iaid); - client->ia_pd.ia_pd.id = htobe32(iaid); + client->ia_na.id = htobe32(iaid); return 0; } #endif /* NM_IGNORED */ -int sd_dhcp6_client_set_fqdn( - sd_dhcp6_client *client, - const char *fqdn) { - - assert_return(client, -EINVAL); - - /* Make sure FQDN qualifies as DNS and as Linux hostname */ - if (fqdn && - !(hostname_is_valid(fqdn, false) && dns_name_is_valid(fqdn) > 0)) - return -EINVAL; - - return free_and_strdup(&client->fqdn, fqdn); -} - int sd_dhcp6_client_set_information_request(sd_dhcp6_client *client, int enabled) { assert_return(client, -EINVAL); assert_return(IN_SET(client->state, DHCP6_STATE_STOPPED), -EBUSY); @@ -286,7 +265,6 @@ int sd_dhcp6_client_set_request_option(sd_dhcp6_client *client, uint16_t option) case SD_DHCP6_OPTION_DOMAIN_LIST: case SD_DHCP6_OPTION_SNTP_SERVERS: case SD_DHCP6_OPTION_NTP_SERVER: - case SD_DHCP6_OPTION_RAPID_COMMIT: break; default: @@ -306,14 +284,6 @@ int sd_dhcp6_client_set_request_option(sd_dhcp6_client *client, uint16_t option) return 0; } -int sd_dhcp6_client_set_prefix_delegation(sd_dhcp6_client *client, bool delegation) { - assert_return(client, -EINVAL); - - client->prefix_delegation = delegation; - - return 0; -} - int sd_dhcp6_client_get_lease(sd_dhcp6_client *client, sd_dhcp6_lease **ret) { assert_return(client, -EINVAL); @@ -352,6 +322,8 @@ static int client_reset(sd_dhcp6_client *client) { client->receive_message = sd_event_source_unref(client->receive_message); + client->fd = safe_close(client->fd); + client->transaction_id = 0; client->transaction_start = 0; @@ -421,21 +393,6 @@ static int client_send_message(sd_dhcp6_client *client, usec_t time_now) { if (r < 0) return r; - if (client->fqdn) { - r = dhcp6_option_append_fqdn(&opt, &optlen, client->fqdn); - if (r < 0) - return r; - } - - if (client->prefix_delegation) { - r = dhcp6_option_append_pd(opt, optlen, &client->ia_pd); - if (r < 0) - return r; - - opt += r; - optlen -= r; - } - break; case DHCP6_STATE_REQUEST: @@ -456,21 +413,6 @@ static int client_send_message(sd_dhcp6_client *client, usec_t time_now) { if (r < 0) return r; - if (client->fqdn) { - r = dhcp6_option_append_fqdn(&opt, &optlen, client->fqdn); - if (r < 0) - return r; - } - - if (client->prefix_delegation) { - r = dhcp6_option_append_pd(opt, optlen, &client->lease->pd); - if (r < 0) - return r; - - opt += r; - optlen -= r; - } - break; case DHCP6_STATE_REBIND: @@ -480,21 +422,6 @@ static int client_send_message(sd_dhcp6_client *client, usec_t time_now) { if (r < 0) return r; - if (client->fqdn) { - r = dhcp6_option_append_fqdn(&opt, &optlen, client->fqdn); - if (r < 0) - return r; - } - - if (client->prefix_delegation) { - r = dhcp6_option_append_pd(opt, optlen, &client->lease->pd); - if (r < 0) - return r; - - opt += r; - optlen -= r; - } - break; case DHCP6_STATE_STOPPED: @@ -508,7 +435,7 @@ static int client_send_message(sd_dhcp6_client *client, usec_t time_now) { if (r < 0) return r; - assert(client->duid_len); + assert (client->duid_len); r = dhcp6_option_append(&opt, &optlen, SD_DHCP6_OPTION_CLIENTID, client->duid_len, &client->duid); if (r < 0) @@ -750,20 +677,16 @@ error: static int client_ensure_iaid(sd_dhcp6_client *client) { int r; - be32_t iaid; assert(client); - if (client->ia_na.ia_na.id) + if (client->ia_na.id) return 0; - r = dhcp_identifier_set_iaid(client->ifindex, client->mac_addr, client->mac_addr_len, &iaid); + r = dhcp_identifier_set_iaid(client->ifindex, client->mac_addr, client->mac_addr_len, &client->ia_na.id); if (r < 0) return r; - client->ia_na.ia_na.id = iaid; - client->ia_pd.ia_pd.id = iaid; - return 0; } @@ -772,33 +695,23 @@ static int client_parse_message( DHCP6Message *message, size_t len, sd_dhcp6_lease *lease) { - size_t pos = 0; int r; + uint8_t *optval, *option, *id = NULL; + uint16_t optcode, status; + size_t optlen, id_len; bool clientid = false; - uint32_t lt_t1 = ~0, lt_t2 = ~0; + be32_t iaid_lease; assert(client); assert(message); assert(len >= sizeof(DHCP6Message)); assert(lease); + option = (uint8_t *)message + sizeof(DHCP6Message); len -= sizeof(DHCP6Message); - while (pos < len) { - DHCP6Option *option = (DHCP6Option *)&message->options[pos]; - uint16_t optcode, optlen; - int status; - uint8_t *optval; - be32_t iaid_lease; - - if (len < offsetof(DHCP6Option, data) || - len < offsetof(DHCP6Option, data) + be16toh(option->len)) - return -ENOBUFS; - - optcode = be16toh(option->code); - optlen = be16toh(option->len); - optval = option->data; - + while ((r = dhcp6_option_parse(&option, &len, &optcode, &optlen, + &optval)) >= 0) { switch (optcode) { case SD_DHCP6_OPTION_CLIENTID: if (clientid) { @@ -819,8 +732,8 @@ static int client_parse_message( break; case SD_DHCP6_OPTION_SERVERID: - r = dhcp6_lease_get_serverid(lease, NULL, NULL); - if (r >= 0) { + r = dhcp6_lease_get_serverid(lease, &id, &id_len); + if (r >= 0 && id) { log_dhcp6_client(client, "%s contains multiple serverids", dhcp6_message_type_to_string(message->type)); return -EINVAL; @@ -836,21 +749,21 @@ static int client_parse_message( if (optlen != 1) return -EINVAL; - r = dhcp6_lease_set_preference(lease, optval[0]); + r = dhcp6_lease_set_preference(lease, *optval); if (r < 0) return r; break; case SD_DHCP6_OPTION_STATUS_CODE: - status = dhcp6_option_parse_status(option); + if (optlen < 2) + return -EINVAL; + + status = optval[0] << 8 | optval[1]; if (status) { log_dhcp6_client(client, "%s Status %s", dhcp6_message_type_to_string(message->type), dhcp6_message_status_to_string(status)); - dhcp6_lease_free_ia(&lease->ia); - dhcp6_lease_free_ia(&lease->pd); - return -EINVAL; } @@ -863,35 +776,8 @@ static int client_parse_message( break; } - r = dhcp6_option_parse_ia(option, &lease->ia); - if (r < 0 && r != -ENOMSG) - return r; - - r = dhcp6_lease_get_iaid(lease, &iaid_lease); - if (r < 0) - return r; - - if (client->ia_na.ia_na.id != iaid_lease) { - log_dhcp6_client(client, "%s has wrong IAID for IA NA", - dhcp6_message_type_to_string(message->type)); - return -EINVAL; - } - - if (lease->ia.addresses) { - lt_t1 = MIN(lt_t1, be32toh(lease->ia.ia_na.lifetime_t1)); - lt_t2 = MIN(lt_t2, be32toh(lease->ia.ia_na.lifetime_t1)); - } - - break; - - case SD_DHCP6_OPTION_IA_PD: - if (client->state == DHCP6_STATE_INFORMATION_REQUEST) { - log_dhcp6_client(client, "Information request ignoring IA PD option"); - - break; - } - - r = dhcp6_option_parse_ia(option, &lease->pd); + r = dhcp6_option_parse_ia(&optval, &optlen, optcode, + &lease->ia); if (r < 0 && r != -ENOMSG) return r; @@ -899,17 +785,12 @@ static int client_parse_message( if (r < 0) return r; - if (client->ia_pd.ia_pd.id != iaid_lease) { - log_dhcp6_client(client, "%s has wrong IAID for IA PD", + if (client->ia_na.id != iaid_lease) { + log_dhcp6_client(client, "%s has wrong IAID", dhcp6_message_type_to_string(message->type)); return -EINVAL; } - if (lease->pd.addresses) { - lt_t1 = MIN(lt_t1, be32toh(lease->pd.ia_pd.lifetime_t1)); - lt_t2 = MIN(lt_t2, be32toh(lease->pd.ia_pd.lifetime_t2)); - } - break; case SD_DHCP6_OPTION_RAPID_COMMIT: @@ -948,36 +829,25 @@ static int client_parse_message( break; } - pos += sizeof(*option) + optlen; } - if (!clientid) { + if (r == -ENOMSG) + r = 0; + + if (r < 0 || !clientid) { log_dhcp6_client(client, "%s has incomplete options", dhcp6_message_type_to_string(message->type)); return -EINVAL; } if (client->state != DHCP6_STATE_INFORMATION_REQUEST) { - r = dhcp6_lease_get_serverid(lease, NULL, NULL); - if (r < 0) { + r = dhcp6_lease_get_serverid(lease, &id, &id_len); + if (r < 0) log_dhcp6_client(client, "%s has no server id", dhcp6_message_type_to_string(message->type)); - return -EINVAL; - } - - } else { - if (lease->ia.addresses) { - lease->ia.ia_na.lifetime_t1 = htobe32(lt_t1); - lease->ia.ia_na.lifetime_t2 = htobe32(lt_t2); - } - - if (lease->pd.addresses) { - lease->pd.ia_pd.lifetime_t1 = htobe32(lt_t1); - lease->pd.ia_pd.lifetime_t2 = htobe32(lt_t2); - } } - return 0; + return r; } static int client_receive_reply(sd_dhcp6_client *client, DHCP6Message *reply, size_t len) { @@ -1133,7 +1003,7 @@ static int client_receive_message( break; } - _fallthrough_; /* for Soliciation Rapid Commit option check */ + /* fall through */ /* for Soliciation Rapid Commit option check */ case DHCP6_STATE_REQUEST: case DHCP6_STATE_RENEW: case DHCP6_STATE_REBIND: @@ -1190,24 +1060,6 @@ static int client_start(sd_dhcp6_client *client, enum DHCP6State state) { if (r < 0) return r; - if (!client->receive_message) { - r = sd_event_add_io(client->event, &client->receive_message, - client->fd, EPOLLIN, client_receive_message, - client); - if (r < 0) - goto error; - - r = sd_event_source_set_priority(client->receive_message, - client->event_priority); - if (r < 0) - goto error; - - r = sd_event_source_set_description(client->receive_message, - "dhcp6-receive-message"); - if (r < 0) - goto error; - } - switch (state) { case DHCP6_STATE_STOPPED: if (client->state == DHCP6_STATE_INFORMATION_REQUEST) { @@ -1216,7 +1068,7 @@ static int client_start(sd_dhcp6_client *client, enum DHCP6State state) { return 0; } - _fallthrough_; + /* fall through */ case DHCP6_STATE_SOLICITATION: client->state = DHCP6_STATE_SOLICITATION; @@ -1233,17 +1085,17 @@ static int client_start(sd_dhcp6_client *client, enum DHCP6State state) { case DHCP6_STATE_BOUND: - if (client->lease->ia.ia_na.lifetime_t1 == 0xffffffff || - client->lease->ia.ia_na.lifetime_t2 == 0xffffffff) { + if (client->lease->ia.lifetime_t1 == 0xffffffff || + client->lease->ia.lifetime_t2 == 0xffffffff) { log_dhcp6_client(client, "Infinite T1 0x%08x or T2 0x%08x", - be32toh(client->lease->ia.ia_na.lifetime_t1), - be32toh(client->lease->ia.ia_na.lifetime_t2)); + be32toh(client->lease->ia.lifetime_t1), + be32toh(client->lease->ia.lifetime_t2)); return 0; } - timeout = client_timeout_compute_random(be32toh(client->lease->ia.ia_na.lifetime_t1) * USEC_PER_SEC); + timeout = client_timeout_compute_random(be32toh(client->lease->ia.lifetime_t1) * USEC_PER_SEC); log_dhcp6_client(client, "T1 expires in %s", format_timespan(time_string, FORMAT_TIMESPAN_MAX, timeout, USEC_PER_SEC)); @@ -1254,18 +1106,18 @@ static int client_start(sd_dhcp6_client *client, enum DHCP6State state) { 10 * USEC_PER_SEC, client_timeout_t1, client); if (r < 0) - goto error; + return r; r = sd_event_source_set_priority(client->lease->ia.timeout_t1, client->event_priority); if (r < 0) - goto error; + return r; r = sd_event_source_set_description(client->lease->ia.timeout_t1, "dhcp6-t1-timeout"); if (r < 0) - goto error; + return r; - timeout = client_timeout_compute_random(be32toh(client->lease->ia.ia_na.lifetime_t2) * USEC_PER_SEC); + timeout = client_timeout_compute_random(be32toh(client->lease->ia.lifetime_t2) * USEC_PER_SEC); log_dhcp6_client(client, "T2 expires in %s", format_timespan(time_string, FORMAT_TIMESPAN_MAX, timeout, USEC_PER_SEC)); @@ -1276,16 +1128,16 @@ static int client_start(sd_dhcp6_client *client, enum DHCP6State state) { 10 * USEC_PER_SEC, client_timeout_t2, client); if (r < 0) - goto error; + return r; r = sd_event_source_set_priority(client->lease->ia.timeout_t2, client->event_priority); if (r < 0) - goto error; + return r; r = sd_event_source_set_description(client->lease->ia.timeout_t2, "dhcp6-t2-timeout"); if (r < 0) - goto error; + return r; client->state = state; @@ -1299,22 +1151,18 @@ static int client_start(sd_dhcp6_client *client, enum DHCP6State state) { clock_boottime_or_monotonic(), 0, 0, client_timeout_resend, client); if (r < 0) - goto error; + return r; r = sd_event_source_set_priority(client->timeout_resend, client->event_priority); if (r < 0) - goto error; + return r; r = sd_event_source_set_description(client->timeout_resend, "dhcp6-resend-timeout"); if (r < 0) - goto error; + return r; return 0; - - error: - client_reset(client); - return r; } int sd_dhcp6_client_stop(sd_dhcp6_client *client) { @@ -1322,8 +1170,6 @@ int sd_dhcp6_client_stop(sd_dhcp6_client *client) { client_stop(client, SD_DHCP6_CLIENT_EVENT_STOP); - client->fd = safe_close(client->fd); - return 0; } @@ -1357,19 +1203,33 @@ int sd_dhcp6_client_start(sd_dhcp6_client *client) { if (r < 0) return r; - if (client->fd < 0) { - r = dhcp6_network_bind_udp_socket(client->ifindex, &client->local_address); - if (r < 0) { - _cleanup_free_ char *p = NULL; - - (void) in_addr_to_string(AF_INET6, (const union in_addr_union*) &client->local_address, &p); - return log_dhcp6_client_errno(client, r, - "Failed to bind to UDP socket at address %s: %m", strna(p)); - } + r = dhcp6_network_bind_udp_socket(client->ifindex, &client->local_address); + if (r < 0) { + _cleanup_free_ char *p = NULL; - client->fd = r; + (void) in_addr_to_string(AF_INET6, (const union in_addr_union*) &client->local_address, &p); + return log_dhcp6_client_errno(client, r, + "Failed to bind to UDP socket at address %s: %m", strna(p)); } + client->fd = r; + + r = sd_event_add_io(client->event, &client->receive_message, + client->fd, EPOLLIN, client_receive_message, + client); + if (r < 0) + goto error; + + r = sd_event_source_set_priority(client->receive_message, + client->event_priority); + if (r < 0) + goto error; + + r = sd_event_source_set_description(client->receive_message, + "dhcp6-receive-message"); + if (r < 0) + goto error; + if (client->information_request) state = DHCP6_STATE_INFORMATION_REQUEST; @@ -1378,6 +1238,10 @@ int sd_dhcp6_client_start(sd_dhcp6_client *client) { "Managed"); return client_start(client, state); + +error: + client_reset(client); + return r; } int sd_dhcp6_client_attach_event(sd_dhcp6_client *client, sd_event *event, int64_t priority) { @@ -1437,12 +1301,9 @@ sd_dhcp6_client *sd_dhcp6_client_unref(sd_dhcp6_client *client) { client_reset(client); - client->fd = safe_close(client->fd); - sd_dhcp6_client_detach_event(client); free(client->req_opts); - free(client->fqdn); return mfree(client); } @@ -1458,7 +1319,6 @@ int sd_dhcp6_client_new(sd_dhcp6_client **ret) { client->n_ref = 1; client->ia_na.type = SD_DHCP6_OPTION_IA_NA; - client->ia_pd.type = SD_DHCP6_OPTION_IA_PD; client->ifindex = -1; client->fd = -1; diff --git a/src/systemd/src/libsystemd-network/sd-dhcp6-lease.c b/src/systemd/src/libsystemd-network/sd-dhcp6-lease.c index 00b9fdf0..63a813aa 100644 --- a/src/systemd/src/libsystemd-network/sd-dhcp6-lease.c +++ b/src/systemd/src/libsystemd-network/sd-dhcp6-lease.c @@ -1,4 +1,3 @@ -/* SPDX-License-Identifier: LGPL-2.1+ */ /*** This file is part of systemd. @@ -51,7 +50,7 @@ int dhcp6_lease_ia_rebind_expire(const DHCP6IA *ia, uint32_t *expire) { valid = t; } - t = be32toh(ia->ia_na.lifetime_t2); + t = be32toh(ia->lifetime_t2); if (t > valid) return -EINVAL; @@ -97,14 +96,11 @@ int dhcp6_lease_set_serverid(sd_dhcp6_lease *lease, const uint8_t *id, int dhcp6_lease_get_serverid(sd_dhcp6_lease *lease, uint8_t **id, size_t *len) { assert_return(lease, -EINVAL); + assert_return(id, -EINVAL); + assert_return(len, -EINVAL); - if (!lease->serverid) - return -ENOMSG; - - if (id) - *id = lease->serverid; - if (len) - *len = lease->serverid_len; + *id = lease->serverid; + *len = lease->serverid_len; return 0; } @@ -149,7 +145,7 @@ int dhcp6_lease_get_iaid(sd_dhcp6_lease *lease, be32_t *iaid) { assert_return(lease, -EINVAL); assert_return(iaid, -EINVAL); - *iaid = lease->ia.ia_na.id; + *iaid = lease->ia.id; return 0; } @@ -181,37 +177,6 @@ void sd_dhcp6_lease_reset_address_iter(sd_dhcp6_lease *lease) { lease->addr_iter = lease->ia.addresses; } -int sd_dhcp6_lease_get_pd(sd_dhcp6_lease *lease, struct in6_addr *prefix, - uint8_t *prefix_len, - uint32_t *lifetime_preferred, - uint32_t *lifetime_valid) { - assert_return(lease, -EINVAL); - assert_return(prefix, -EINVAL); - assert_return(prefix_len, -EINVAL); - assert_return(lifetime_preferred, -EINVAL); - assert_return(lifetime_valid, -EINVAL); - - if (!lease->prefix_iter) - return -ENOMSG; - - memcpy(prefix, &lease->prefix_iter->iapdprefix.address, - sizeof(struct in6_addr)); - *prefix_len = lease->prefix_iter->iapdprefix.prefixlen; - *lifetime_preferred = - be32toh(lease->prefix_iter->iapdprefix.lifetime_preferred); - *lifetime_valid = - be32toh(lease->prefix_iter->iapdprefix.lifetime_valid); - - lease->prefix_iter = lease->prefix_iter->addresses_next; - - return 0; -} - -void sd_dhcp6_lease_reset_pd_prefix_iter(sd_dhcp6_lease *lease) { - if (lease) - lease->prefix_iter = lease->pd.addresses; -} - int dhcp6_lease_set_dns(sd_dhcp6_lease *lease, uint8_t *optval, size_t optlen) { int r; @@ -418,7 +383,6 @@ sd_dhcp6_lease *sd_dhcp6_lease_unref(sd_dhcp6_lease *lease) { free(lease->serverid); dhcp6_lease_free_ia(&lease->ia); - dhcp6_lease_free_ia(&lease->pd); free(lease->dns); diff --git a/src/systemd/src/libsystemd-network/sd-ipv4acd.c b/src/systemd/src/libsystemd-network/sd-ipv4acd.c index 08f46dd2..694384b5 100644 --- a/src/systemd/src/libsystemd-network/sd-ipv4acd.c +++ b/src/systemd/src/libsystemd-network/sd-ipv4acd.c @@ -1,4 +1,3 @@ -/* SPDX-License-Identifier: LGPL-2.1+ */ /*** This file is part of systemd. @@ -290,7 +289,8 @@ static int ipv4acd_on_timeout(sd_event_source *s, uint64_t usec, void *userdata) break; } - _fallthrough_; + /* fall through */ + case IPV4ACD_STATE_WAITING_ANNOUNCE: /* Send announcement packet */ r = arp_send_announcement(acd->fd, acd->ifindex, acd->address, &acd->mac_addr); diff --git a/src/systemd/src/libsystemd-network/sd-ipv4ll.c b/src/systemd/src/libsystemd-network/sd-ipv4ll.c index f1e7b404..47fc141c 100644 --- a/src/systemd/src/libsystemd-network/sd-ipv4ll.c +++ b/src/systemd/src/libsystemd-network/sd-ipv4ll.c @@ -1,4 +1,3 @@ -/* SPDX-License-Identifier: LGPL-2.1+ */ /*** This file is part of systemd. @@ -27,7 +26,6 @@ #include <stdlib.h> #include <string.h> -#include "sd-id128.h" #include "sd-ipv4acd.h" #include "sd-ipv4ll.h" diff --git a/src/systemd/src/libsystemd-network/sd-lldp.c b/src/systemd/src/libsystemd-network/sd-lldp.c index 20956041..31e24486 100644 --- a/src/systemd/src/libsystemd-network/sd-lldp.c +++ b/src/systemd/src/libsystemd-network/sd-lldp.c @@ -1,4 +1,3 @@ -/* SPDX-License-Identifier: LGPL-2.1+ */ /*** This file is part of systemd. diff --git a/src/systemd/src/libsystemd/sd-event/sd-event.c b/src/systemd/src/libsystemd/sd-event/sd-event.c index 4fb8ed7f..9dfe6847 100644 --- a/src/systemd/src/libsystemd/sd-event/sd-event.c +++ b/src/systemd/src/libsystemd/sd-event/sd-event.c @@ -1,4 +1,3 @@ -/* SPDX-License-Identifier: LGPL-2.1+ */ /*** This file is part of systemd. @@ -124,7 +123,6 @@ struct sd_event_source { uint32_t events; uint32_t revents; bool registered:1; - bool owned:1; } io; struct { sd_event_time_handler_t callback; @@ -243,14 +241,8 @@ struct sd_event { unsigned delays[sizeof(usec_t) * 8]; }; -static thread_local sd_event *default_event = NULL; - static void source_disconnect(sd_event_source *s); -static sd_event *event_resolve(sd_event *e) { - return e == SD_EVENT_DEFAULT ? default_event : e; -} - static int pending_prioq_compare(const void *a, const void *b) { const sd_event_source *x = a, *y = b; @@ -459,8 +451,6 @@ _public_ int sd_event_new(sd_event** ret) { goto fail; } - e->epoll_fd = fd_move_above_stdio(e->epoll_fd); - if (secure_getenv("SD_EVENT_PROFILE_DELAYS")) { log_debug("Event loop profiling enabled. Logarithmic histogram of event loop iterations in the range 2^0 ... 2^63 us will be logged every 5s."); e->profile_delays = true; @@ -699,7 +689,7 @@ static int event_make_signal_data( return 0; } - d->fd = fd_move_above_stdio(r); + d->fd = r; ev.events = EPOLLIN; ev.data.ptr = d; @@ -894,10 +884,6 @@ static void source_free(sd_event_source *s) { assert(s); source_disconnect(s); - - if (s->type == SOURCE_IO && s->io.owned) - safe_close(s->io.fd); - free(s->description); free(s); } @@ -982,7 +968,6 @@ _public_ int sd_event_add_io( int r; assert_return(e, -EINVAL); - assert_return(e = event_resolve(e), -ENOPKG); assert_return(fd >= 0, -EBADF); assert_return(!(events & ~(EPOLLIN|EPOLLOUT|EPOLLRDHUP|EPOLLPRI|EPOLLERR|EPOLLHUP|EPOLLET)), -EINVAL); assert_return(callback, -EINVAL); @@ -1049,8 +1034,6 @@ static int event_setup_timer_fd( if (fd < 0) return -errno; - fd = fd_move_above_stdio(fd); - ev.events = EPOLLIN; ev.data.ptr = d; @@ -1085,7 +1068,6 @@ _public_ int sd_event_add_time( int r; assert_return(e, -EINVAL); - assert_return(e = event_resolve(e), -ENOPKG); assert_return(accuracy != (uint64_t) -1, -EINVAL); assert_return(e->state != SD_EVENT_FINISHED, -ESTALE); assert_return(!event_pid_changed(e), -ECHILD); @@ -1168,7 +1150,6 @@ _public_ int sd_event_add_signal( int r; assert_return(e, -EINVAL); - assert_return(e = event_resolve(e), -ENOPKG); assert_return(SIGNAL_VALID(sig), -EINVAL); assert_return(e->state != SD_EVENT_FINISHED, -ESTALE); assert_return(!event_pid_changed(e), -ECHILD); @@ -1229,7 +1210,6 @@ _public_ int sd_event_add_child( int r; assert_return(e, -EINVAL); - assert_return(e = event_resolve(e), -ENOPKG); assert_return(pid > 1, -EINVAL); assert_return(!(options & ~(WEXITED|WSTOPPED|WCONTINUED)), -EINVAL); assert_return(options != 0, -EINVAL); @@ -1287,7 +1267,6 @@ _public_ int sd_event_add_defer( int r; assert_return(e, -EINVAL); - assert_return(e = event_resolve(e), -ENOPKG); assert_return(callback, -EINVAL); assert_return(e->state != SD_EVENT_FINISHED, -ESTALE); assert_return(!event_pid_changed(e), -ECHILD); @@ -1322,7 +1301,6 @@ _public_ int sd_event_add_post( int r; assert_return(e, -EINVAL); - assert_return(e = event_resolve(e), -ENOPKG); assert_return(callback, -EINVAL); assert_return(e->state != SD_EVENT_FINISHED, -ESTALE); assert_return(!event_pid_changed(e), -ECHILD); @@ -1361,7 +1339,6 @@ _public_ int sd_event_add_exit( int r; assert_return(e, -EINVAL); - assert_return(e = event_resolve(e), -ENOPKG); assert_return(callback, -EINVAL); assert_return(e->state != SD_EVENT_FINISHED, -ESTALE); assert_return(!event_pid_changed(e), -ECHILD); @@ -1507,21 +1484,6 @@ _public_ int sd_event_source_set_io_fd(sd_event_source *s, int fd) { return 0; } -_public_ int sd_event_source_get_io_fd_own(sd_event_source *s) { - assert_return(s, -EINVAL); - assert_return(s->type == SOURCE_IO, -EDOM); - - return s->io.owned; -} - -_public_ int sd_event_source_set_io_fd_own(sd_event_source *s, int own) { - assert_return(s, -EINVAL); - assert_return(s->type == SOURCE_IO, -EDOM); - - s->io.owned = own; - return 0; -} - _public_ int sd_event_source_get_io_events(sd_event_source *s, uint32_t* events) { assert_return(s, -EINVAL); assert_return(events, -EINVAL); @@ -2490,7 +2452,6 @@ _public_ int sd_event_prepare(sd_event *e) { int r; assert_return(e, -EINVAL); - assert_return(e = event_resolve(e), -ENOPKG); assert_return(!event_pid_changed(e), -ECHILD); assert_return(e->state != SD_EVENT_FINISHED, -ESTALE); assert_return(e->state == SD_EVENT_INITIAL, -EBUSY); @@ -2548,7 +2509,6 @@ _public_ int sd_event_wait(sd_event *e, uint64_t timeout) { int r, m, i; assert_return(e, -EINVAL); - assert_return(e = event_resolve(e), -ENOPKG); assert_return(!event_pid_changed(e), -ECHILD); assert_return(e->state != SD_EVENT_FINISHED, -ESTALE); assert_return(e->state == SD_EVENT_ARMED, -EBUSY); @@ -2655,7 +2615,6 @@ _public_ int sd_event_dispatch(sd_event *e) { int r; assert_return(e, -EINVAL); - assert_return(e = event_resolve(e), -ENOPKG); assert_return(!event_pid_changed(e), -ECHILD); assert_return(e->state != SD_EVENT_FINISHED, -ESTALE); assert_return(e->state == SD_EVENT_PENDING, -EBUSY); @@ -2697,7 +2656,6 @@ _public_ int sd_event_run(sd_event *e, uint64_t timeout) { int r; assert_return(e, -EINVAL); - assert_return(e = event_resolve(e), -ENOPKG); assert_return(!event_pid_changed(e), -ECHILD); assert_return(e->state != SD_EVENT_FINISHED, -ESTALE); assert_return(e->state == SD_EVENT_INITIAL, -EBUSY); @@ -2742,7 +2700,6 @@ _public_ int sd_event_loop(sd_event *e) { int r; assert_return(e, -EINVAL); - assert_return(e = event_resolve(e), -ENOPKG); assert_return(!event_pid_changed(e), -ECHILD); assert_return(e->state == SD_EVENT_INITIAL, -EBUSY); @@ -2764,7 +2721,6 @@ finish: _public_ int sd_event_get_fd(sd_event *e) { assert_return(e, -EINVAL); - assert_return(e = event_resolve(e), -ENOPKG); assert_return(!event_pid_changed(e), -ECHILD); return e->epoll_fd; @@ -2772,7 +2728,6 @@ _public_ int sd_event_get_fd(sd_event *e) { _public_ int sd_event_get_state(sd_event *e) { assert_return(e, -EINVAL); - assert_return(e = event_resolve(e), -ENOPKG); assert_return(!event_pid_changed(e), -ECHILD); return e->state; @@ -2780,7 +2735,6 @@ _public_ int sd_event_get_state(sd_event *e) { _public_ int sd_event_get_exit_code(sd_event *e, int *code) { assert_return(e, -EINVAL); - assert_return(e = event_resolve(e), -ENOPKG); assert_return(code, -EINVAL); assert_return(!event_pid_changed(e), -ECHILD); @@ -2793,7 +2747,6 @@ _public_ int sd_event_get_exit_code(sd_event *e, int *code) { _public_ int sd_event_exit(sd_event *e, int code) { assert_return(e, -EINVAL); - assert_return(e = event_resolve(e), -ENOPKG); assert_return(e->state != SD_EVENT_FINISHED, -ESTALE); assert_return(!event_pid_changed(e), -ECHILD); @@ -2805,7 +2758,6 @@ _public_ int sd_event_exit(sd_event *e, int code) { _public_ int sd_event_now(sd_event *e, clockid_t clock, uint64_t *usec) { assert_return(e, -EINVAL); - assert_return(e = event_resolve(e), -ENOPKG); assert_return(usec, -EINVAL); assert_return(!event_pid_changed(e), -ECHILD); @@ -2830,6 +2782,8 @@ _public_ int sd_event_now(sd_event *e, clockid_t clock, uint64_t *usec) { } _public_ int sd_event_default(sd_event **ret) { + + static thread_local sd_event *default_event = NULL; sd_event *e = NULL; int r; @@ -2856,7 +2810,6 @@ _public_ int sd_event_default(sd_event **ret) { #if 0 /* NM_IGNORED */ _public_ int sd_event_get_tid(sd_event *e, pid_t *tid) { assert_return(e, -EINVAL); - assert_return(e = event_resolve(e), -ENOPKG); assert_return(tid, -EINVAL); assert_return(!event_pid_changed(e), -ECHILD); @@ -2872,7 +2825,6 @@ _public_ int sd_event_set_watchdog(sd_event *e, int b) { int r; assert_return(e, -EINVAL); - assert_return(e = event_resolve(e), -ENOPKG); assert_return(!event_pid_changed(e), -ECHILD); if (e->watchdog == !!b) @@ -2923,7 +2875,6 @@ fail: _public_ int sd_event_get_watchdog(sd_event *e) { assert_return(e, -EINVAL); - assert_return(e = event_resolve(e), -ENOPKG); assert_return(!event_pid_changed(e), -ECHILD); return e->watchdog; @@ -2931,7 +2882,6 @@ _public_ int sd_event_get_watchdog(sd_event *e) { _public_ int sd_event_get_iteration(sd_event *e, uint64_t *ret) { assert_return(e, -EINVAL); - assert_return(e = event_resolve(e), -ENOPKG); assert_return(!event_pid_changed(e), -ECHILD); *ret = e->iteration; diff --git a/src/systemd/src/libsystemd/sd-id128/id128-util.c b/src/systemd/src/libsystemd/sd-id128/id128-util.c index f1033346..19277021 100644 --- a/src/systemd/src/libsystemd/sd-id128/id128-util.c +++ b/src/systemd/src/libsystemd/sd-id128/id128-util.c @@ -1,4 +1,3 @@ -/* SPDX-License-Identifier: LGPL-2.1+ */ /*** This file is part of systemd. @@ -20,12 +19,10 @@ #include "nm-sd-adapt.h" -#include <errno.h> #include <fcntl.h> #include <unistd.h> #include "fd-util.h" -#include "fs-util.h" #include "hexdecoct.h" #include "id128-util.h" #include "io-util.h" @@ -123,7 +120,7 @@ int id128_read_fd(int fd, Id128Format f, sd_id128_t *ret) { if (buffer[32] != '\n') return -EINVAL; - _fallthrough_; + /* fall through */ case 32: /* plain UUID without trailing newline */ if (f == ID128_UUID) return -EINVAL; @@ -135,7 +132,7 @@ int id128_read_fd(int fd, Id128Format f, sd_id128_t *ret) { if (buffer[36] != '\n') return -EINVAL; - _fallthrough_; + /* fall through */ case 36: /* RFC UUID without trailing newline */ if (f == ID128_PLAIN) return -EINVAL; @@ -186,13 +183,9 @@ int id128_write_fd(int fd, Id128Format f, sd_id128_t id, bool do_sync) { if (do_sync) { if (fsync(fd) < 0) return -errno; - - r = fsync_directory_of_file(fd); - if (r < 0) - return r; } - return 0; + return r; } int id128_write(const char *p, Id128Format f, sd_id128_t id, bool do_sync) { diff --git a/src/systemd/src/libsystemd/sd-id128/id128-util.h b/src/systemd/src/libsystemd/sd-id128/id128-util.h index 9f3340e5..6b3855ac 100644 --- a/src/systemd/src/libsystemd/sd-id128/id128-util.h +++ b/src/systemd/src/libsystemd/sd-id128/id128-util.h @@ -1,4 +1,3 @@ -/* SPDX-License-Identifier: LGPL-2.1+ */ #pragma once /*** diff --git a/src/systemd/src/libsystemd/sd-id128/sd-id128.c b/src/systemd/src/libsystemd/sd-id128/sd-id128.c index e5bd447a..052110d5 100644 --- a/src/systemd/src/libsystemd/sd-id128/sd-id128.c +++ b/src/systemd/src/libsystemd/sd-id128/sd-id128.c @@ -1,4 +1,3 @@ -/* SPDX-License-Identifier: LGPL-2.1+ */ /*** This file is part of systemd. diff --git a/src/systemd/src/shared/dns-domain.c b/src/systemd/src/shared/dns-domain.c index cfc1f3b3..c313a033 100644 --- a/src/systemd/src/shared/dns-domain.c +++ b/src/systemd/src/shared/dns-domain.c @@ -1,4 +1,3 @@ -/* SPDX-License-Identifier: LGPL-2.1+ */ /*** This file is part of systemd. @@ -302,7 +301,8 @@ int dns_label_escape_new(const char *p, size_t l, char **ret) { if (r < 0) return r; - *ret = TAKE_PTR(s); + *ret = s; + s = NULL; return r; } @@ -609,7 +609,8 @@ int dns_name_endswith(const char *name, const char *suffix) { /* Not the same, let's jump back, and try with the next label again */ s = suffix; - n = TAKE_PTR(saved_n); + n = saved_n; + saved_n = NULL; } } } @@ -700,26 +701,23 @@ int dns_name_change_suffix(const char *name, const char *old_suffix, const char } int dns_name_between(const char *a, const char *b, const char *c) { + int n; + /* Determine if b is strictly greater than a and strictly smaller than c. We consider the order of names to be circular, so that if a is strictly greater than c, we consider b to be between them if it is either greater than a or smaller than c. This is how the canonical DNS name order used in NSEC records work. */ - if (dns_name_compare_func(a, c) < 0) - /* - a and c are properly ordered: - a<---b--->c - */ + n = dns_name_compare_func(a, c); + if (n == 0) + return -EINVAL; + else if (n < 0) + /* a<---b--->c */ return dns_name_compare_func(a, b) < 0 && dns_name_compare_func(b, c) < 0; else - /* - a and c are equal or 'reversed': - <--b--c a-----> - or: - <-----c a--b--> - */ + /* <--b--c a--b--> */ return dns_name_compare_func(b, c) < 0 || dns_name_compare_func(a, b) < 0; } @@ -971,12 +969,6 @@ bool dns_srv_type_is_valid(const char *name) { return c == 2; /* exactly two labels */ } -bool dnssd_srv_type_is_valid(const char *name) { - return dns_srv_type_is_valid(name) && - ((dns_name_endswith(name, "_tcp") > 0) || - (dns_name_endswith(name, "_udp") > 0)); /* Specific to DNS-SD. RFC 6763, Section 7 */ -} - bool dns_service_name_is_valid(const char *name) { size_t l; diff --git a/src/systemd/src/shared/dns-domain.h b/src/systemd/src/shared/dns-domain.h index 3ebd4018..d1a99be7 100644 --- a/src/systemd/src/shared/dns-domain.h +++ b/src/systemd/src/shared/dns-domain.h @@ -1,4 +1,3 @@ -/* SPDX-License-Identifier: LGPL-2.1+ */ #pragma once /*** @@ -98,7 +97,6 @@ bool dns_name_is_single_label(const char *name); int dns_name_to_wire_format(const char *domain, uint8_t *buffer, size_t len, bool canonical); bool dns_srv_type_is_valid(const char *name); -bool dnssd_srv_type_is_valid(const char *name); bool dns_service_name_is_valid(const char *name); int dns_service_join(const char *name, const char *type, const char *domain, char **ret); diff --git a/src/systemd/src/systemd/_sd-common.h b/src/systemd/src/systemd/_sd-common.h index b4400e7b..97c39438 100644 --- a/src/systemd/src/systemd/_sd-common.h +++ b/src/systemd/src/systemd/_sd-common.h @@ -1,4 +1,3 @@ -/* SPDX-License-Identifier: LGPL-2.1+ */ #ifndef foosdcommonhfoo #define foosdcommonhfoo diff --git a/src/systemd/src/systemd/sd-dhcp-client.h b/src/systemd/src/systemd/sd-dhcp-client.h index 789cc501..5e46d8d0 100644 --- a/src/systemd/src/systemd/sd-dhcp-client.h +++ b/src/systemd/src/systemd/sd-dhcp-client.h @@ -1,4 +1,3 @@ -/* SPDX-License-Identifier: LGPL-2.1+ */ #ifndef foosddhcpclienthfoo #define foosddhcpclienthfoo @@ -132,11 +131,6 @@ int sd_dhcp_client_set_iaid_duid( uint16_t duid_type, const void *duid, size_t duid_len); -int sd_dhcp_client_set_duid( - sd_dhcp_client *client, - uint16_t duid_type, - const void *duid, - size_t duid_len); int sd_dhcp_client_get_client_id( sd_dhcp_client *client, uint8_t *type, diff --git a/src/systemd/src/systemd/sd-dhcp-lease.h b/src/systemd/src/systemd/sd-dhcp-lease.h index 3cc7fcab..7ab99ccc 100644 --- a/src/systemd/src/systemd/sd-dhcp-lease.h +++ b/src/systemd/src/systemd/sd-dhcp-lease.h @@ -1,4 +1,3 @@ -/* SPDX-License-Identifier: LGPL-2.1+ */ #ifndef foosddhcpleasehfoo #define foosddhcpleasehfoo diff --git a/src/systemd/src/systemd/sd-dhcp6-client.h b/src/systemd/src/systemd/sd-dhcp6-client.h index cadb32a0..7819f0d2 100644 --- a/src/systemd/src/systemd/sd-dhcp6-client.h +++ b/src/systemd/src/systemd/sd-dhcp6-client.h @@ -1,4 +1,3 @@ -/* SPDX-License-Identifier: LGPL-2.1+ */ #ifndef foosddhcp6clienthfoo #define foosddhcp6clienthfoo @@ -23,7 +22,6 @@ #include <inttypes.h> #include <net/ethernet.h> -#include <stdbool.h> #include <sys/types.h> #include "sd-dhcp6-lease.h" @@ -65,15 +63,11 @@ enum { SD_DHCP6_OPTION_DNS_SERVERS = 23, /* RFC 3646 */ SD_DHCP6_OPTION_DOMAIN_LIST = 24, /* RFC 3646 */ - SD_DHCP6_OPTION_IA_PD = 25, /* RFC 3633, prefix delegation */ - SD_DHCP6_OPTION_IA_PD_PREFIX = 26, /* RFC 3633, prefix delegation */ SD_DHCP6_OPTION_SNTP_SERVERS = 31, /* RFC 4075, deprecated */ /* option code 35 is unassigned */ - SD_DHCP6_OPTION_FQDN = 39, /* RFC 4704 */ - SD_DHCP6_OPTION_NTP_SERVER = 56, /* RFC 5908 */ /* option codes 89-142 are unassigned */ @@ -107,9 +101,6 @@ int sd_dhcp6_client_set_duid( int sd_dhcp6_client_set_iaid( sd_dhcp6_client *client, uint32_t iaid); -int sd_dhcp6_client_set_fqdn( - sd_dhcp6_client *client, - const char *fqdn); int sd_dhcp6_client_set_information_request( sd_dhcp6_client *client, int enabled); @@ -119,8 +110,6 @@ int sd_dhcp6_client_get_information_request( int sd_dhcp6_client_set_request_option( sd_dhcp6_client *client, uint16_t option); -int sd_dhcp6_client_set_prefix_delegation(sd_dhcp6_client *client, - bool delegation); int sd_dhcp6_client_get_lease( sd_dhcp6_client *client, diff --git a/src/systemd/src/systemd/sd-dhcp6-lease.h b/src/systemd/src/systemd/sd-dhcp6-lease.h index 22a5f8ce..184fbb8e 100644 --- a/src/systemd/src/systemd/sd-dhcp6-lease.h +++ b/src/systemd/src/systemd/sd-dhcp6-lease.h @@ -1,4 +1,3 @@ -/* SPDX-License-Identifier: LGPL-2.1+ */ #ifndef foosddhcp6leasehfoo #define foosddhcp6leasehfoo @@ -36,11 +35,6 @@ int sd_dhcp6_lease_get_address(sd_dhcp6_lease *lease, struct in6_addr *addr, uint32_t *lifetime_preferred, uint32_t *lifetime_valid); -void sd_dhcp6_lease_reset_pd_prefix_iter(sd_dhcp6_lease *lease); -int sd_dhcp6_lease_get_pd(sd_dhcp6_lease *lease, struct in6_addr *prefix, - uint8_t *prefix_len, - uint32_t *lifetime_preferred, - uint32_t *lifetime_valid); int sd_dhcp6_lease_get_dns(sd_dhcp6_lease *lease, struct in6_addr **addrs); int sd_dhcp6_lease_get_domains(sd_dhcp6_lease *lease, char ***domains); diff --git a/src/systemd/src/systemd/sd-event.h b/src/systemd/src/systemd/sd-event.h index ec4b7bcf..f8cb8956 100644 --- a/src/systemd/src/systemd/sd-event.h +++ b/src/systemd/src/systemd/sd-event.h @@ -1,4 +1,3 @@ -/* SPDX-License-Identifier: LGPL-2.1+ */ #ifndef foosdeventhfoo #define foosdeventhfoo @@ -26,7 +25,6 @@ #include <sys/epoll.h> #include <sys/signalfd.h> #include <sys/types.h> -#include <time.h> #include "_sd-common.h" @@ -41,8 +39,6 @@ _SD_BEGIN_DECLARATIONS; -#define SD_EVENT_DEFAULT ((sd_event *) 1) - typedef struct sd_event sd_event; typedef struct sd_event_source sd_event_source; @@ -127,8 +123,6 @@ int sd_event_source_get_enabled(sd_event_source *s, int *enabled); int sd_event_source_set_enabled(sd_event_source *s, int enabled); int sd_event_source_get_io_fd(sd_event_source *s); int sd_event_source_set_io_fd(sd_event_source *s, int fd); -int sd_event_source_get_io_fd_own(sd_event_source *s); -int sd_event_source_set_io_fd_own(sd_event_source *s, int own); int sd_event_source_get_io_events(sd_event_source *s, uint32_t* events); int sd_event_source_set_io_events(sd_event_source *s, uint32_t events); int sd_event_source_get_io_revents(sd_event_source *s, uint32_t* revents); diff --git a/src/systemd/src/systemd/sd-id128.h b/src/systemd/src/systemd/sd-id128.h index 67fc5956..9b38969b 100644 --- a/src/systemd/src/systemd/sd-id128.h +++ b/src/systemd/src/systemd/sd-id128.h @@ -1,4 +1,3 @@ -/* SPDX-License-Identifier: LGPL-2.1+ */ #ifndef foosdid128hfoo #define foosdid128hfoo diff --git a/src/systemd/src/systemd/sd-ipv4acd.h b/src/systemd/src/systemd/sd-ipv4acd.h index 677ae3b2..16d99983 100644 --- a/src/systemd/src/systemd/sd-ipv4acd.h +++ b/src/systemd/src/systemd/sd-ipv4acd.h @@ -1,4 +1,3 @@ -/* SPDX-License-Identifier: LGPL-2.1+ */ #ifndef foosdipv4acdfoo #define foosdipv4acdfoo diff --git a/src/systemd/src/systemd/sd-ipv4ll.h b/src/systemd/src/systemd/sd-ipv4ll.h index c330b0ae..5ba92083 100644 --- a/src/systemd/src/systemd/sd-ipv4ll.h +++ b/src/systemd/src/systemd/sd-ipv4ll.h @@ -1,4 +1,3 @@ -/* SPDX-License-Identifier: LGPL-2.1+ */ #ifndef foosdipv4llfoo #define foosdipv4llfoo diff --git a/src/systemd/src/systemd/sd-lldp.h b/src/systemd/src/systemd/sd-lldp.h index 0a76fa63..3f35eebe 100644 --- a/src/systemd/src/systemd/sd-lldp.h +++ b/src/systemd/src/systemd/sd-lldp.h @@ -1,4 +1,3 @@ -/* SPDX-License-Identifier: LGPL-2.1+ */ #ifndef foosdlldphfoo #define foosdlldphfoo diff --git a/src/systemd/src/systemd/sd-ndisc.h b/src/systemd/src/systemd/sd-ndisc.h index 15211450..9f7d4ef7 100644 --- a/src/systemd/src/systemd/sd-ndisc.h +++ b/src/systemd/src/systemd/sd-ndisc.h @@ -1,4 +1,3 @@ -/* SPDX-License-Identifier: LGPL-2.1+ */ #ifndef foosdndiscfoo #define foosdndiscfoo diff --git a/src/tests/config/meson.build b/src/tests/config/meson.build deleted file mode 100644 index fb40d9a9..00000000 --- a/src/tests/config/meson.build +++ /dev/null @@ -1,26 +0,0 @@ -test_unit = 'test-config' - -sources = files( - 'nm-test-device.c', - 'test-config.c' -) - -test_config_dir = meson.current_source_dir() - -cflags = [ - '-DSRCDIR="@0@"'.format(test_config_dir), - '-DBUILDDIR="@0@"'.format(test_config_dir) -] - -exe = executable( - test_unit, - sources, - dependencies: test_nm_dep, - c_args: cflags -) - -test( - 'config/' + test_unit, - test_script, - args: test_args + [exe.full_path()] -) diff --git a/src/tests/config/nm-test-device.c b/src/tests/config/nm-test-device.c index 49631583..3ec866f5 100644 --- a/src/tests/config/nm-test-device.c +++ b/src/tests/config/nm-test-device.c @@ -57,7 +57,7 @@ nm_test_device_init (NMTestDevice *self) } /* We jump over NMDevice's construct/destruct methods, which require NMPlatform - * and NMSettings to be initialized. + * and NMConnectionProvider to be initialized. */ static void constructed (GObject *object) diff --git a/src/tests/config/test-config.c b/src/tests/config/test-config.c index 50215756..89b22a9f 100644 --- a/src/tests/config/test-config.c +++ b/src/tests/config/test-config.c @@ -25,7 +25,7 @@ #include "nm-config.h" #include "nm-test-device.h" #include "platform/nm-fake-platform.h" -#include "nm-dbus-manager.h" +#include "nm-bus-manager.h" #include "nm-connectivity.h" #include "nm-test-utils-core.h" @@ -254,7 +254,7 @@ test_config_global_dns (void) NMConfig *config; const NMGlobalDnsConfig *dns; NMGlobalDnsDomain *domain; - const char *const*strv; + const char *const *strv; config = setup_config (NULL, SRCDIR "/NetworkManager.conf", "", NULL, "/no/such/dir", "", NULL); @@ -318,10 +318,10 @@ test_config_global_dns (void) g_object_unref (config); } +#if WITH_CONCHECK static void test_config_connectivity_check (void) { -#if WITH_CONCHECK const char *CONFIG_INTERN = BUILDDIR"/test-connectivity-check-intern.conf"; NMConfig *config; NMConnectivity *connectivity; @@ -334,14 +334,14 @@ test_config_connectivity_check (void) g_assert (nm_connectivity_check_enabled (connectivity)); /* disable connectivity checking */ - NMTST_EXPECT_NM_INFO ("config: signal: *"); + g_test_expect_message ("NetworkManager", G_LOG_LEVEL_INFO, "*config: signal *"); nm_config_set_connectivity_check_enabled (config, FALSE); g_test_assert_expected_messages (); g_assert (!nm_connectivity_check_enabled (connectivity)); /* re-enable connectivity checking */ - NMTST_EXPECT_NM_INFO ("config: signal: *"); + g_test_expect_message ("NetworkManager", G_LOG_LEVEL_INFO, "*config: signal *"); nm_config_set_connectivity_check_enabled (config, TRUE); g_test_assert_expected_messages (); @@ -351,10 +351,8 @@ test_config_connectivity_check (void) g_object_unref (config); g_assert (remove (CONFIG_INTERN) == 0); -#else - g_test_skip ("concheck disabled"); -#endif } +#endif static void test_config_no_auto_default (void) @@ -388,7 +386,7 @@ test_config_no_auto_default (void) g_assert (!nm_config_get_no_auto_default_for_device (config, dev3)); g_assert (nm_config_get_no_auto_default_for_device (config, dev4)); - NMTST_EXPECT_NM_INFO ("config: signal: NO_AUTO_DEFAULT,no-auto-default *"); + g_test_expect_message ("NetworkManager", G_LOG_LEVEL_INFO, "*config: signal NO_AUTO_DEFAULT,no-auto-default *"); nm_config_set_no_auto_default_for_device (config, dev3); g_test_assert_expected_messages (); @@ -599,9 +597,9 @@ _set_values_user (NMConfig *config, config_data_before = g_object_ref (nm_config_get_data (config)); if (expected_changes != NM_CONFIG_CHANGE_NONE) - NMTST_EXPECT_NM_INFO ("config: signal: *"); + g_test_expect_message ("NetworkManager", G_LOG_LEVEL_INFO, "*config: signal *"); else - NMTST_EXPECT_NM_INFO ("config: signal: SIGHUP (no changes from disk)*"); + g_test_expect_message ("NetworkManager", G_LOG_LEVEL_INFO, "*config: signal SIGHUP (no changes from disk)*"); nm_config_reload (config, NM_CONFIG_CHANGE_CAUSE_SIGHUP); @@ -643,7 +641,7 @@ _set_values_intern (NMConfig *config, &config_changed_data); if (expected_changes != NM_CONFIG_CHANGE_NONE) - NMTST_EXPECT_NM_INFO ("config: signal: *"); + g_test_expect_message ("NetworkManager", G_LOG_LEVEL_INFO, "*config: signal *"); nm_config_set_values (config, keyfile_intern, TRUE, FALSE); @@ -906,15 +904,15 @@ test_config_signal (void) &expected); expected = NM_CONFIG_CHANGE_CAUSE_SIGUSR1; - NMTST_EXPECT_NM_INFO ("config: signal: SIGUSR1"); + g_test_expect_message ("NetworkManager", G_LOG_LEVEL_INFO, "*config: signal SIGUSR1"); nm_config_reload (config, expected); expected = NM_CONFIG_CHANGE_CAUSE_SIGUSR2; - NMTST_EXPECT_NM_INFO ("config: signal: SIGUSR2"); + g_test_expect_message ("NetworkManager", G_LOG_LEVEL_INFO, "*config: signal SIGUSR2"); nm_config_reload (config, expected); expected = NM_CONFIG_CHANGE_CAUSE_SIGHUP; - NMTST_EXPECT_NM_INFO ("config: signal: SIGHUP (no changes from disk)*"); + g_test_expect_message ("NetworkManager", G_LOG_LEVEL_INFO, "*config: signal SIGHUP (no changes from disk)*"); nm_config_reload (config, expected); @@ -927,7 +925,7 @@ test_config_signal (void) G_CALLBACK (_test_signal_config_changed_cb2), &expected); expected = NM_CONFIG_CHANGE_CAUSE_SIGUSR2; - NMTST_EXPECT_NM_INFO ("config: signal: SIGUSR2"); + g_test_expect_message ("NetworkManager", G_LOG_LEVEL_INFO, "*config: signal SIGUSR2"); nm_config_reload (config, NM_CONFIG_CHANGE_CAUSE_SIGUSR2); g_signal_handlers_disconnect_by_func (config, _test_signal_config_changed_cb2, &expected); @@ -1039,6 +1037,13 @@ main (int argc, char **argv) { nmtst_init_assert_logging (&argc, &argv, "INFO", "DEFAULT"); + /* Initialize the DBus manager singleton explicitly, because it is accessed by + * the class initializer of NMDevice (used by the NMTestDevice stub). + * This way, we skip calling nm_bus_manager_init_bus() which would + * either fail and/or cause unexpected actions in the test. + * */ + nm_bus_manager_setup (g_object_new (NM_TYPE_BUS_MANAGER, NULL)); + nm_fake_platform_setup (); g_test_add_func ("/config/simple", test_config_simple); @@ -1050,7 +1055,9 @@ main (int argc, char **argv) g_test_add_func ("/config/set-values", test_config_set_values); g_test_add_func ("/config/global-dns", test_config_global_dns); +#if WITH_CONCHECK g_test_add_func ("/config/connectivity-check", test_config_connectivity_check); +#endif g_test_add_func ("/config/signal", test_config_signal); diff --git a/src/tests/meson.build b/src/tests/meson.build deleted file mode 100644 index 386ede87..00000000 --- a/src/tests/meson.build +++ /dev/null @@ -1,47 +0,0 @@ -subdir('config') - -test_units = [ - 'test-general', - 'test-general-with-expect', - 'test-ip4-config', - 'test-ip6-config', - 'test-dcb', - 'test-wired-defname', - 'test-utils' -] - -foreach test_unit: test_units - exe = executable( - test_unit, - test_unit + '.c', - dependencies: test_nm_dep - ) - - test( - 'src/' + test_unit, - test_script, - args: test_args + [exe.full_path()] - ) -endforeach - -test_unit = 'test-systemd' - -cflags = [ - '-DNETWORKMANAGER_COMPILATION_TEST', - '-DNETWORKMANAGER_COMPILATION=NM_NETWORKMANAGER_COMPILATION_SYSTEMD', -] - -exe = executable( - test_unit, - [test_unit + '.c'] + shared_siphash, - include_directories: src_inc, - dependencies: nm_core_dep, - c_args: cflags, - link_with: libsystemd_nm -) - -test( - 'src/' + test_unit, - test_script, - args: test_args + [exe.full_path()] -) diff --git a/src/tests/test-general-with-expect.c b/src/tests/test-general-with-expect.c index f67c332b..2911d84d 100644 --- a/src/tests/test-general-with-expect.c +++ b/src/tests/test-general-with-expect.c @@ -167,7 +167,7 @@ test_nm_utils_kill_child_spawn (char **argv, gboolean do_not_reap_child) } static pid_t -do_test_nm_utils_kill_child_create_and_join_pgroup (void) +test_nm_utils_kill_child_create_and_join_pgroup (void) { int err, tmp = 0; int pipefd[2]; @@ -177,7 +177,10 @@ do_test_nm_utils_kill_child_create_and_join_pgroup (void) g_assert (err == 0); pgid = fork(); - g_assert (pgid >= 0); + if (pgid < 0) { + g_assert_not_reached (); + return pgid; + } if (pgid == 0) { /* child process... */ @@ -203,6 +206,7 @@ do_test_nm_utils_kill_child_create_and_join_pgroup (void) err = setpgid (0, pgid); g_assert (err == 0); + do { err = waitpid (pgid, &tmp, 0); } while (err == -1 && errno == EINTR); @@ -215,8 +219,9 @@ do_test_nm_utils_kill_child_create_and_join_pgroup (void) #define TEST_TOKEN "nm_test_kill_child_process" static void -do_test_nm_utils_kill_child (void) +test_nm_utils_kill_child (void) { + int err; GLogLevelFlags fatal_mask; char *argv_watchdog[] = { "bash", @@ -250,6 +255,7 @@ do_test_nm_utils_kill_child (void) "trap \"while true; do :; done\" TERM; while true; do :; done; #" TEST_TOKEN, NULL, }; + pid_t gpid; pid_t pid1a_1, pid1a_2, pid1a_3, pid2a, pid3a, pid4a; pid_t pid1s_1, pid1s_2, pid1s_3, pid2s, pid3s, pid4s; @@ -257,6 +263,8 @@ do_test_nm_utils_kill_child (void) const int expected_signal_TERM = SIGTERM; const int expected_signal_KILL = SIGKILL; + gpid = test_nm_utils_kill_child_create_and_join_pgroup (); + test_nm_utils_kill_child_spawn (argv_watchdog, FALSE); pid1s_1 = test_nm_utils_kill_child_spawn (argv1, TRUE); @@ -276,122 +284,90 @@ do_test_nm_utils_kill_child (void) /* give processes time to start (and potentially block signals) ... */ g_usleep (G_USEC_PER_SEC / 10); + fatal_mask = g_log_set_always_fatal (G_LOG_FATAL_MASK); - NMTST_EXPECT_NM_DEBUG ("kill child process 'test-s-1-1' (*): waiting up to 3000 milliseconds for process to terminate normally after sending SIGTERM (15)..."); - NMTST_EXPECT_NM_DEBUG ("kill child process 'test-s-1-1' (*): after sending SIGTERM (15), process * exited by signal 15 (* usec elapsed)"); + g_test_expect_message ("NetworkManager", G_LOG_LEVEL_DEBUG, "*kill child process 'test-s-1-1' (*): waiting up to 3000 milliseconds for process to terminate normally after sending SIGTERM (15)..."); + g_test_expect_message ("NetworkManager", G_LOG_LEVEL_DEBUG, "*kill child process 'test-s-1-1' (*): after sending SIGTERM (15), process * exited by signal 15 (* usec elapsed)"); test_nm_utils_kill_child_sync_do ("test-s-1-1", pid1s_1, SIGTERM, 3000, TRUE, &expected_signal_TERM); - NMTST_EXPECT_NM_DEBUG ("kill child process 'test-s-1-2' (*): waiting for process to terminate after sending SIGKILL (9)..."); - NMTST_EXPECT_NM_DEBUG ("kill child process 'test-s-1-2' (*): after sending SIGKILL (9), process * exited by signal 9 (* usec elapsed)"); + g_test_expect_message ("NetworkManager", G_LOG_LEVEL_DEBUG, "*kill child process 'test-s-1-2' (*): waiting for process to terminate after sending SIGKILL (9)..."); + g_test_expect_message ("NetworkManager", G_LOG_LEVEL_DEBUG, "*kill child process 'test-s-1-2' (*): after sending SIGKILL (9), process * exited by signal 9 (* usec elapsed)"); test_nm_utils_kill_child_sync_do ("test-s-1-2", pid1s_2, SIGKILL, 1000 / 2, TRUE, &expected_signal_KILL); - NMTST_EXPECT_NM_DEBUG ("kill child process 'test-s-1-3' (*): waiting up to 1 milliseconds for process to terminate normally after sending no signal (0)..."); - NMTST_EXPECT_NM_DEBUG ("kill child process 'test-s-1-3' (*): sending SIGKILL..."); - NMTST_EXPECT_NM_DEBUG ("kill child process 'test-s-1-3' (*): after sending no signal (0) and SIGKILL, process * exited by signal 9 (* usec elapsed)"); + g_test_expect_message ("NetworkManager", G_LOG_LEVEL_DEBUG, "*kill child process 'test-s-1-3' (*): waiting up to 1 milliseconds for process to terminate normally after sending no signal (0)..."); + g_test_expect_message ("NetworkManager", G_LOG_LEVEL_DEBUG, "*kill child process 'test-s-1-3' (*): sending SIGKILL..."); + g_test_expect_message ("NetworkManager", G_LOG_LEVEL_DEBUG, "*kill child process 'test-s-1-3' (*): after sending no signal (0) and SIGKILL, process * exited by signal 9 (* usec elapsed)"); test_nm_utils_kill_child_sync_do ("test-s-1-3", pid1s_3, 0, 1, TRUE, &expected_signal_KILL); - NMTST_EXPECT_NM_DEBUG ("kill child process 'test-s-2' (*): process * already terminated normally with status 47"); + g_test_expect_message ("NetworkManager", G_LOG_LEVEL_DEBUG, "*kill child process 'test-s-2' (*): process * already terminated normally with status 47"); test_nm_utils_kill_child_sync_do ("test-s-2", pid2s, SIGTERM, 3000, TRUE, &expected_exit_47); /* send invalid signal. */ - NMTST_EXPECT_NM_ERROR ("kill child process 'test-s-3-0' (*): failed to send Unexpected signal: Invalid argument (22)"); + g_test_expect_message ("NetworkManager", G_LOG_LEVEL_MESSAGE, "*kill child process 'test-s-3-0' (*): failed to send Unexpected signal: Invalid argument (22)"); test_nm_utils_kill_child_sync_do ("test-s-3-0", pid3s, -1, 0, FALSE, NULL); /* really kill pid3s */ - NMTST_EXPECT_NM_DEBUG ("kill child process 'test-s-3-1' (*): waiting up to 3000 milliseconds for process to terminate normally after sending SIGTERM (15)..."); - NMTST_EXPECT_NM_DEBUG ("kill child process 'test-s-3-1' (*): after sending SIGTERM (15), process * exited normally with status 47 (* usec elapsed)"); + g_test_expect_message ("NetworkManager", G_LOG_LEVEL_DEBUG, "*kill child process 'test-s-3-1' (*): waiting up to 3000 milliseconds for process to terminate normally after sending SIGTERM (15)..."); + g_test_expect_message ("NetworkManager", G_LOG_LEVEL_DEBUG, "*kill child process 'test-s-3-1' (*): after sending SIGTERM (15), process * exited normally with status 47 (* usec elapsed)"); test_nm_utils_kill_child_sync_do ("test-s-3-1", pid3s, SIGTERM, 3000, TRUE, &expected_exit_47); /* pid3s should not be a valid process, hence the call should fail. Note, that there * is a race here. */ - NMTST_EXPECT_NM_ERROR ("kill child process 'test-s-3-2' (*): failed due to unexpected return value -1 by waitpid (No child processes, 10) after sending no signal (0)"); + g_test_expect_message ("NetworkManager", G_LOG_LEVEL_MESSAGE, "*kill child process 'test-s-3-2' (*): failed due to unexpected return value -1 by waitpid (No child processes, 10) after sending no signal (0)"); test_nm_utils_kill_child_sync_do ("test-s-3-2", pid3s, 0, 0, FALSE, NULL); - NMTST_EXPECT_NM_DEBUG ("kill child process 'test-s-4' (*): waiting up to 1 milliseconds for process to terminate normally after sending SIGTERM (15)..."); - NMTST_EXPECT_NM_DEBUG ("kill child process 'test-s-4' (*): sending SIGKILL..."); - NMTST_EXPECT_NM_DEBUG ("kill child process 'test-s-4' (*): after sending SIGTERM (15) and SIGKILL, process * exited by signal 9 (* usec elapsed)"); + g_test_expect_message ("NetworkManager", G_LOG_LEVEL_DEBUG, "*kill child process 'test-s-4' (*): waiting up to 1 milliseconds for process to terminate normally after sending SIGTERM (15)..."); + g_test_expect_message ("NetworkManager", G_LOG_LEVEL_DEBUG, "*kill child process 'test-s-4' (*): sending SIGKILL..."); + g_test_expect_message ("NetworkManager", G_LOG_LEVEL_DEBUG, "*kill child process 'test-s-4' (*): after sending SIGTERM (15) and SIGKILL, process * exited by signal 9 (* usec elapsed)"); test_nm_utils_kill_child_sync_do ("test-s-4", pid4s, SIGTERM, 1, TRUE, &expected_signal_KILL); - NMTST_EXPECT_NM_DEBUG ("kill child process 'test-a-1-1' (*): wait for process to terminate after sending SIGTERM (15) (send SIGKILL in 3000 milliseconds)..."); - NMTST_EXPECT_NM_DEBUG ("kill child process 'test-a-1-1' (*): terminated by signal 15 (* usec elapsed)"); + g_test_expect_message ("NetworkManager", G_LOG_LEVEL_DEBUG, "*kill child process 'test-a-1-1' (*): wait for process to terminate after sending SIGTERM (15) (send SIGKILL in 3000 milliseconds)..."); + g_test_expect_message ("NetworkManager", G_LOG_LEVEL_DEBUG, "*kill child process 'test-a-1-1' (*): terminated by signal 15 (* usec elapsed)"); test_nm_utils_kill_child_async_do ("test-a-1-1", pid1a_1, SIGTERM, 3000, TRUE, &expected_signal_TERM); - NMTST_EXPECT_NM_DEBUG ("kill child process 'test-a-1-2' (*): wait for process to terminate after sending SIGKILL (9)..."); - NMTST_EXPECT_NM_DEBUG ("kill child process 'test-a-1-2' (*): terminated by signal 9 (* usec elapsed)"); + g_test_expect_message ("NetworkManager", G_LOG_LEVEL_DEBUG, "*kill child process 'test-a-1-2' (*): wait for process to terminate after sending SIGKILL (9)..."); + g_test_expect_message ("NetworkManager", G_LOG_LEVEL_DEBUG, "*kill child process 'test-a-1-2' (*): terminated by signal 9 (* usec elapsed)"); test_nm_utils_kill_child_async_do ("test-a-1-2", pid1a_2, SIGKILL, 1000 / 2, TRUE, &expected_signal_KILL); - NMTST_EXPECT_NM_DEBUG ("kill child process 'test-a-1-3' (*): wait for process to terminate after sending no signal (0) (send SIGKILL in 1 milliseconds)..."); - NMTST_EXPECT_NM_DEBUG ("kill child process 'test-a-1-3' (*): process not terminated after * usec. Sending SIGKILL signal"); - NMTST_EXPECT_NM_DEBUG ("kill child process 'test-a-1-3' (*): terminated by signal 9 (* usec elapsed)"); + g_test_expect_message ("NetworkManager", G_LOG_LEVEL_DEBUG, "*kill child process 'test-a-1-3' (*): wait for process to terminate after sending no signal (0) (send SIGKILL in 1 milliseconds)..."); + g_test_expect_message ("NetworkManager", G_LOG_LEVEL_DEBUG, "*kill child process 'test-a-1-3' (*): process not terminated after * usec. Sending SIGKILL signal"); + g_test_expect_message ("NetworkManager", G_LOG_LEVEL_DEBUG, "*kill child process 'test-a-1-3' (*): terminated by signal 9 (* usec elapsed)"); test_nm_utils_kill_child_async_do ("test-a-1-3", pid1a_3, 0, 1, TRUE, &expected_signal_KILL); - NMTST_EXPECT_NM_DEBUG ("kill child process 'test-a-2' (*): process * already terminated normally with status 47"); - NMTST_EXPECT_NM_DEBUG ("kill child process 'test-a-2' (*): invoke callback: terminated normally with status 47"); + g_test_expect_message ("NetworkManager", G_LOG_LEVEL_DEBUG, "*kill child process 'test-a-2' (*): process * already terminated normally with status 47"); + g_test_expect_message ("NetworkManager", G_LOG_LEVEL_DEBUG, "*kill child process 'test-a-2' (*): invoke callback: terminated normally with status 47"); test_nm_utils_kill_child_async_do ("test-a-2", pid2a, SIGTERM, 3000, TRUE, &expected_exit_47); - NMTST_EXPECT_NM_ERROR ("kill child process 'test-a-3-0' (*): unexpected error sending Unexpected signal: Invalid argument (22)"); - NMTST_EXPECT_NM_DEBUG ("kill child process 'test-a-3-0' (*): invoke callback: killing child failed"); + g_test_expect_message ("NetworkManager", G_LOG_LEVEL_MESSAGE, "*kill child process 'test-a-3-0' (*): unexpected error sending Unexpected signal: Invalid argument (22)"); + g_test_expect_message ("NetworkManager", G_LOG_LEVEL_DEBUG, "*kill child process 'test-a-3-0' (*): invoke callback: killing child failed"); /* coverity[negative_returns] */ test_nm_utils_kill_child_async_do ("test-a-3-0", pid3a, -1, 1000 / 2, FALSE, NULL); - NMTST_EXPECT_NM_DEBUG ("kill child process 'test-a-3-1' (*): wait for process to terminate after sending SIGTERM (15) (send SIGKILL in 3000 milliseconds)..."); - NMTST_EXPECT_NM_DEBUG ("kill child process 'test-a-3-1' (*): terminated normally with status 47 (* usec elapsed)"); + g_test_expect_message ("NetworkManager", G_LOG_LEVEL_DEBUG, "*kill child process 'test-a-3-1' (*): wait for process to terminate after sending SIGTERM (15) (send SIGKILL in 3000 milliseconds)..."); + g_test_expect_message ("NetworkManager", G_LOG_LEVEL_DEBUG, "*kill child process 'test-a-3-1' (*): terminated normally with status 47 (* usec elapsed)"); test_nm_utils_kill_child_async_do ("test-a-3-1", pid3a, SIGTERM, 3000, TRUE, &expected_exit_47); /* pid3a should not be a valid process, hence the call should fail. Note, that there * is a race here. */ - NMTST_EXPECT_NM_ERROR ("kill child process 'test-a-3-2' (*): failed due to unexpected return value -1 by waitpid (No child processes, 10) after sending no signal (0)"); - NMTST_EXPECT_NM_DEBUG ("kill child process 'test-a-3-2' (*): invoke callback: killing child failed"); + g_test_expect_message ("NetworkManager", G_LOG_LEVEL_MESSAGE, "*kill child process 'test-a-3-2' (*): failed due to unexpected return value -1 by waitpid (No child processes, 10) after sending no signal (0)"); + g_test_expect_message ("NetworkManager", G_LOG_LEVEL_DEBUG, "*kill child process 'test-a-3-2' (*): invoke callback: killing child failed"); test_nm_utils_kill_child_async_do ("test-a-3-2", pid3a, 0, 0, FALSE, NULL); - NMTST_EXPECT_NM_DEBUG ("kill child process 'test-a-4' (*): wait for process to terminate after sending SIGTERM (15) (send SIGKILL in 1 milliseconds)..."); - NMTST_EXPECT_NM_DEBUG ("kill child process 'test-a-4' (*): process not terminated after * usec. Sending SIGKILL signal"); - NMTST_EXPECT_NM_DEBUG ("kill child process 'test-a-4' (*): terminated by signal 9 (* usec elapsed)"); + g_test_expect_message ("NetworkManager", G_LOG_LEVEL_DEBUG, "*kill child process 'test-a-4' (*): wait for process to terminate after sending SIGTERM (15) (send SIGKILL in 1 milliseconds)..."); + g_test_expect_message ("NetworkManager", G_LOG_LEVEL_DEBUG, "*kill child process 'test-a-4' (*): process not terminated after * usec. Sending SIGKILL signal"); + g_test_expect_message ("NetworkManager", G_LOG_LEVEL_DEBUG, "*kill child process 'test-a-4' (*): terminated by signal 9 (* usec elapsed)"); test_nm_utils_kill_child_async_do ("test-a-4", pid4a, SIGTERM, 1, TRUE, &expected_signal_KILL); - g_log_set_always_fatal (fatal_mask); - - g_test_assert_expected_messages (); -} - -static void -test_nm_utils_kill_child (void) -{ - int err; - int exit_status; - pid_t gpid; - pid_t child_pid; - - /* the tests spawns several processes, we want to clean them up - * by sending a SIGKILL to the process group. - * - * The current process might be a session leader, which prevents it from - * creating a new process group. Hence, first fork and let the child - * create a new process group, run the tests, and kill all pending - * processes. */ - child_pid = fork (); - g_assert (child_pid >= 0); - - if (child_pid == 0) { - gpid = do_test_nm_utils_kill_child_create_and_join_pgroup (); - - do_test_nm_utils_kill_child (); - - err = setpgid (0, 0); - g_assert (err == 0); + err = setpgid (0, 0); + g_assert (err == 0); - kill (-gpid, SIGKILL); + kill (-gpid, SIGKILL); - exit (0); - }; + g_log_set_always_fatal (fatal_mask); - do { - err = waitpid (child_pid, &exit_status, 0); - } while (err == -1 && errno == EINTR); - g_assert (err == child_pid); - g_assert (WIFEXITED (exit_status) && WEXITSTATUS(exit_status) == 0); + g_test_assert_expected_messages (); } /*****************************************************************************/ @@ -456,7 +432,7 @@ test_nm_utils_array_remove_at_indexes (void) idx = g_array_new (FALSE, FALSE, sizeof (guint)); array = g_array_new (FALSE, FALSE, sizeof (gssize)); - unique = g_hash_table_new (nm_direct_hash, NULL); + unique = g_hash_table_new (NULL, NULL); for (i_len = 1; i_len < 20; i_len++) { for (i_idx_len = 1; i_idx_len <= i_len; i_idx_len++) { for (i_rnd = 0; i_rnd < 20; i_rnd++) { diff --git a/src/tests/test-general.c b/src/tests/test-general.c index 38eaf25e..bfa2ea73 100644 --- a/src/tests/test-general.c +++ b/src/tests/test-general.c @@ -232,13 +232,13 @@ test_nm_utils_log_connection_diff (void) connection = nm_simple_connection_new (); nm_connection_add_setting (connection, nm_setting_connection_new ()); - nm_utils_log_connection_diff (connection, NULL, LOGL_DEBUG, LOGD_CORE, "test1", ">>> ", NULL); + nm_utils_log_connection_diff (connection, NULL, LOGL_DEBUG, LOGD_CORE, "test1", ">>> "); nm_connection_add_setting (connection, nm_setting_wired_new ()); - nm_utils_log_connection_diff (connection, NULL, LOGL_DEBUG, LOGD_CORE, "test2", ">>> ", NULL); + nm_utils_log_connection_diff (connection, NULL, LOGL_DEBUG, LOGD_CORE, "test2", ">>> "); connection2 = nm_simple_connection_new_clone (connection); - nm_utils_log_connection_diff (connection, connection2, LOGL_DEBUG, LOGD_CORE, "test3", ">>> ", NULL); + nm_utils_log_connection_diff (connection, connection2, LOGL_DEBUG, LOGD_CORE, "test3", ">>> "); g_object_set (nm_connection_get_setting_connection (connection), NM_SETTING_CONNECTION_ID, "id", @@ -248,24 +248,24 @@ test_nm_utils_log_connection_diff (void) NM_SETTING_CONNECTION_ID, "id2", NM_SETTING_CONNECTION_MASTER, "master2", NULL); - nm_utils_log_connection_diff (connection, connection2, LOGL_DEBUG, LOGD_CORE, "test4", ">>> ", NULL); + nm_utils_log_connection_diff (connection, connection2, LOGL_DEBUG, LOGD_CORE, "test4", ">>> "); nm_connection_add_setting (connection, nm_setting_802_1x_new ()); - nm_utils_log_connection_diff (connection, connection2, LOGL_DEBUG, LOGD_CORE, "test5", ">>> ", NULL); + nm_utils_log_connection_diff (connection, connection2, LOGL_DEBUG, LOGD_CORE, "test5", ">>> "); g_object_set (nm_connection_get_setting_802_1x (connection), NM_SETTING_802_1X_PASSWORD, "id2", NM_SETTING_802_1X_PASSWORD_FLAGS, NM_SETTING_SECRET_FLAG_NOT_SAVED, NULL); - nm_utils_log_connection_diff (connection, NULL, LOGL_DEBUG, LOGD_CORE, "test6", ">>> ", NULL); - nm_utils_log_connection_diff (connection, connection2, LOGL_DEBUG, LOGD_CORE, "test7", ">>> ", NULL); - nm_utils_log_connection_diff (connection2, connection, LOGL_DEBUG, LOGD_CORE, "test8", ">>> ", NULL); + nm_utils_log_connection_diff (connection, NULL, LOGL_DEBUG, LOGD_CORE, "test6", ">>> "); + nm_utils_log_connection_diff (connection, connection2, LOGL_DEBUG, LOGD_CORE, "test7", ">>> "); + nm_utils_log_connection_diff (connection2, connection, LOGL_DEBUG, LOGD_CORE, "test8", ">>> "); g_clear_object (&connection); g_clear_object (&connection2); connection = nmtst_create_minimal_connection ("id-vpn-1", NULL, NM_SETTING_VPN_SETTING_NAME, NULL); - nm_utils_log_connection_diff (connection, NULL, LOGL_DEBUG, LOGD_CORE, "test-vpn-1", ">>> ", NULL); + nm_utils_log_connection_diff (connection, NULL, LOGL_DEBUG, LOGD_CORE, "test-vpn-1", ">>> "); g_clear_object (&connection); } @@ -1460,11 +1460,6 @@ test_nm_utils_strbuf_append (void) static void test_duplicate_decl_specifier (void) { - /* We're intentionally assigning values to static arrays v_const - * and v_result without using it afterwards just so that valgrind - * doesn't complain about the leak. */ - NM_PRAGMA_WARNING_DISABLE("-Wunused-but-set-variable") - /* have some static variables, so that the result is certainly not optimized out. */ static const int v_const[1] = { 1 }; static int v_result[1] = { }; @@ -1482,8 +1477,6 @@ test_duplicate_decl_specifier (void) }) v_result[0] = TEST_MAX (v_const[0], nmtst_get_rand_int () % 5) + v2; - - NM_PRAGMA_WARNING_REENABLE } static void diff --git a/src/tests/test-ip6-config.c b/src/tests/test-ip6-config.c index 816a816f..bcbeee3e 100644 --- a/src/tests/test-ip6-config.c +++ b/src/tests/test-ip6-config.c @@ -246,10 +246,8 @@ test_nm_ip6_config_addresses_sort_check (NMIP6Config *config, NMSettingIP6Config int *idx = g_new (int, addr_count); nm_ip6_config_set_privacy (config, use_tempaddr); - copy = nm_ip6_config_clone (config); - g_assert (copy); - copy2 = nm_ip6_config_clone (config); - g_assert (copy2); + copy = nmtst_ip6_config_clone (config); + copy2 = nmtst_ip6_config_clone (config); /* initialize the array of indeces, and keep shuffling them for every @repeat iteration. */ for (i = 0; i < addr_count; i++) @@ -298,9 +296,9 @@ test_nm_ip6_config_addresses_sort (void) ADDR_ADD("2607:f0d0:1002:51::4", NULL, 64, 0, NM_IP_CONFIG_SOURCE_USER, 0, 0, 0, 0); ADDR_ADD("2607:f0d0:1002:51::5", NULL, 64, 0, NM_IP_CONFIG_SOURCE_USER, 0, 0, 0, 0); ADDR_ADD("2607:f0d0:1002:51::6", NULL, 64, 0, NM_IP_CONFIG_SOURCE_NDISC, 0, 0, 0, IFA_F_MANAGETEMPADDR); - ADDR_ADD("2607:f0d0:1002:51::3", NULL, 64, 0, NM_IP_CONFIG_SOURCE_USER, 0, 0, 0, IFA_F_TEMPORARY); - ADDR_ADD("2607:f0d0:1002:51::8", NULL, 64, 0, NM_IP_CONFIG_SOURCE_USER, 0, 0, 0, IFA_F_TEMPORARY); - ADDR_ADD("2607:f0d0:1002:51::0", NULL, 64, 0, NM_IP_CONFIG_SOURCE_KERNEL, 0, 0, 0, IFA_F_TEMPORARY); + ADDR_ADD("2607:f0d0:1002:51::3", NULL, 64, 0, NM_IP_CONFIG_SOURCE_USER, 0, 0, 0, IFA_F_SECONDARY); + ADDR_ADD("2607:f0d0:1002:51::8", NULL, 64, 0, NM_IP_CONFIG_SOURCE_USER, 0, 0, 0, IFA_F_SECONDARY); + ADDR_ADD("2607:f0d0:1002:51::0", NULL, 64, 0, NM_IP_CONFIG_SOURCE_KERNEL, 0, 0, 0, IFA_F_SECONDARY); ADDR_ADD("fec0::1", NULL, 128, 0, NM_IP_CONFIG_SOURCE_KERNEL, 0, 0, 0, 0); ADDR_ADD("fe80::208:74ff:feda:625c", NULL, 128, 0, NM_IP_CONFIG_SOURCE_KERNEL, 0, 0, 0, 0); ADDR_ADD("fe80::208:74ff:feda:625d", NULL, 128, 0, NM_IP_CONFIG_SOURCE_KERNEL, 0, 0, 0, 0); @@ -311,11 +309,11 @@ test_nm_ip6_config_addresses_sort (void) test_nm_ip6_config_addresses_sort_check (config, NM_SETTING_IP6_CONFIG_PRIVACY_PREFER_PUBLIC_ADDR, 8); nm_ip6_config_reset_addresses (config); - ADDR_ADD("2607:f0d0:1002:51::3", NULL, 64, 0, NM_IP_CONFIG_SOURCE_USER, 0, 0, 0, IFA_F_TEMPORARY); + ADDR_ADD("2607:f0d0:1002:51::3", NULL, 64, 0, NM_IP_CONFIG_SOURCE_USER, 0, 0, 0, IFA_F_SECONDARY); ADDR_ADD("2607:f0d0:1002:51::4", NULL, 64, 0, NM_IP_CONFIG_SOURCE_USER, 0, 0, 0, 0); ADDR_ADD("2607:f0d0:1002:51::5", NULL, 64, 0, NM_IP_CONFIG_SOURCE_USER, 0, 0, 0, 0); - ADDR_ADD("2607:f0d0:1002:51::8", NULL, 64, 0, NM_IP_CONFIG_SOURCE_USER, 0, 0, 0, IFA_F_TEMPORARY); - ADDR_ADD("2607:f0d0:1002:51::0", NULL, 64, 0, NM_IP_CONFIG_SOURCE_KERNEL, 0, 0, 0, IFA_F_TEMPORARY); + ADDR_ADD("2607:f0d0:1002:51::8", NULL, 64, 0, NM_IP_CONFIG_SOURCE_USER, 0, 0, 0, IFA_F_SECONDARY); + ADDR_ADD("2607:f0d0:1002:51::0", NULL, 64, 0, NM_IP_CONFIG_SOURCE_KERNEL, 0, 0, 0, IFA_F_SECONDARY); ADDR_ADD("2607:f0d0:1002:51::6", NULL, 64, 0, NM_IP_CONFIG_SOURCE_NDISC, 0, 0, 0, IFA_F_MANAGETEMPADDR); ADDR_ADD("fec0::1", NULL, 128, 0, NM_IP_CONFIG_SOURCE_KERNEL, 0, 0, 0, 0); ADDR_ADD("fe80::208:74ff:feda:625c", NULL, 128, 0, NM_IP_CONFIG_SOURCE_KERNEL, 0, 0, 0, 0); diff --git a/src/tests/test-resolvconf-capture.c b/src/tests/test-resolvconf-capture.c new file mode 100644 index 00000000..2c34ff74 --- /dev/null +++ b/src/tests/test-resolvconf-capture.c @@ -0,0 +1,298 @@ +/* -*- Mode: C; tab-width: 4; indent-tabs-mode: t; c-basic-offset: 4 -*- */ +/* + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation; either version 2, or (at your option) + * any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License along + * with this program; if not, write to the Free Software Foundation, Inc., + * 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA. + * + * Copyright (C) 2013 Red Hat, Inc. + * + */ + +#include "nm-default.h" + +#include <string.h> +#include <arpa/inet.h> + +#include "NetworkManagerUtils.h" +#include "nm-ip4-config.h" +#include "nm-ip6-config.h" +#include "platform/nm-platform.h" + +#include "nm-test-utils-core.h" + +static void +test_capture_empty (void) +{ + GArray *ns4 = g_array_new (FALSE, FALSE, sizeof (guint32)); + GArray *ns6 = g_array_new (FALSE, FALSE, sizeof (struct in6_addr)); + + g_assert (!nm_utils_resolve_conf_parse (AF_INET, "", ns4, NULL)); + g_assert_cmpint (ns4->len, ==, 0); + + g_assert (!nm_utils_resolve_conf_parse (AF_INET6, "", ns6, NULL)); + g_assert_cmpint (ns6->len, ==, 0); + + g_array_free (ns4, TRUE); + g_array_free (ns6, TRUE); +} + +#define assert_dns4_entry(a, i, s) \ + g_assert_cmpint ((g_array_index ((a), guint32, (i))), ==, nmtst_inet4_from_string (s)); + +#define assert_dns6_entry(a, i, s) \ + g_assert (IN6_ARE_ADDR_EQUAL (&g_array_index ((a), struct in6_addr, (i)), nmtst_inet6_from_string (s))) + +#define assert_dns_option(a, i, s) \ + g_assert_cmpstr ((a)->pdata[(i)], ==, (s)); + +static void +test_capture_basic4 (void) +{ + GArray *ns4 = g_array_new (FALSE, FALSE, sizeof (guint32)); + const char *rc = +"# neato resolv.conf\r\n" +"domain foobar.com\r\n" +"search foobar.com\r\n" +"nameserver 4.2.2.1\r\n" +"nameserver 4.2.2.2\r\n"; + + g_assert (nm_utils_resolve_conf_parse (AF_INET, rc, ns4, NULL)); + g_assert_cmpint (ns4->len, ==, 2); + assert_dns4_entry (ns4, 0, "4.2.2.1"); + assert_dns4_entry (ns4, 1, "4.2.2.2"); + + g_array_free (ns4, TRUE); +} + +static void +test_capture_dup4 (void) +{ + GArray *ns4 = g_array_new (FALSE, FALSE, sizeof (guint32)); + const char *rc = +"# neato resolv.conf\r\n" +"domain foobar.com\r\n" +"search foobar.com\r\n" +"nameserver 4.2.2.1\r\n" +"nameserver 4.2.2.1\r\n" +"nameserver 4.2.2.2\r\n"; + + /* Check that duplicates are ignored */ + g_assert (nm_utils_resolve_conf_parse (AF_INET, rc, ns4, NULL)); + g_assert_cmpint (ns4->len, ==, 2); + assert_dns4_entry (ns4, 0, "4.2.2.1"); + assert_dns4_entry (ns4, 1, "4.2.2.2"); + + g_array_free (ns4, TRUE); +} + +static void +test_capture_basic6 (void) +{ + GArray *ns6 = g_array_new (FALSE, FALSE, sizeof (struct in6_addr)); + const char *rc = +"# neato resolv.conf\r\n" +"domain foobar.com\r\n" +"search foobar.com\r\n" +"nameserver 2001:4860:4860::8888\r\n" +"nameserver 2001:4860:4860::8844\r\n"; + + g_assert (nm_utils_resolve_conf_parse (AF_INET6, rc, ns6, NULL)); + g_assert_cmpint (ns6->len, ==, 2); + assert_dns6_entry (ns6, 0, "2001:4860:4860::8888"); + assert_dns6_entry (ns6, 1, "2001:4860:4860::8844"); + + g_array_free (ns6, TRUE); +} + +static void +test_capture_dup6 (void) +{ + GArray *ns6 = g_array_new (FALSE, FALSE, sizeof (struct in6_addr)); + const char *rc = +"# neato resolv.conf\r\n" +"domain foobar.com\r\n" +"search foobar.com\r\n" +"nameserver 2001:4860:4860::8888\r\n" +"nameserver 2001:4860:4860::8888\r\n" +"nameserver 2001:4860:4860::8844\r\n"; + + /* Check that duplicates are ignored */ + g_assert (nm_utils_resolve_conf_parse (AF_INET6, rc, ns6, NULL)); + g_assert_cmpint (ns6->len, ==, 2); + assert_dns6_entry (ns6, 0, "2001:4860:4860::8888"); + assert_dns6_entry (ns6, 1, "2001:4860:4860::8844"); + + g_array_free (ns6, TRUE); +} + +static void +test_capture_addr4_with_6 (void) +{ + GArray *ns4 = g_array_new (FALSE, FALSE, sizeof (guint32)); + const char *rc = +"# neato resolv.conf\r\n" +"domain foobar.com\r\n" +"search foobar.com\r\n" +"nameserver 4.2.2.1\r\n" +"nameserver 4.2.2.2\r\n" +"nameserver 2001:4860:4860::8888\r\n"; + + g_assert (nm_utils_resolve_conf_parse (AF_INET, rc, ns4, NULL)); + g_assert_cmpint (ns4->len, ==, 2); + assert_dns4_entry (ns4, 0, "4.2.2.1"); + assert_dns4_entry (ns4, 1, "4.2.2.2"); + + g_array_free (ns4, TRUE); +} + +static void +test_capture_addr6_with_4 (void) +{ + GArray *ns6 = g_array_new (FALSE, FALSE, sizeof (struct in6_addr)); + const char *rc = +"# neato resolv.conf\r\n" +"domain foobar.com\r\n" +"search foobar.com\r\n" +"nameserver 4.2.2.1\r\n" +"nameserver 2001:4860:4860::8888\r\n" +"nameserver 2001:4860:4860::8844\r\n"; + + g_assert (nm_utils_resolve_conf_parse (AF_INET6, rc, ns6, NULL)); + g_assert_cmpint (ns6->len, ==, 2); + assert_dns6_entry (ns6, 0, "2001:4860:4860::8888"); + assert_dns6_entry (ns6, 1, "2001:4860:4860::8844"); + + g_array_free (ns6, TRUE); +} + +static void +test_capture_format (void) +{ + GArray *ns4 = g_array_new (FALSE, FALSE, sizeof (guint32)); + const char *rc = +" nameserver 4.2.2.1\r\n" /* bad */ +"nameserver4.2.2.1\r\n" /* bad */ +"nameserver 4.2.2.3\r" /* good */ +"nameserver\t\t4.2.2.4\r\n" /* good */ +"nameserver 4.2.2.5\t\t\r\n" /* good */ +"nameserver 4.2.2.6 \r\n"; /* good */ + + g_assert (nm_utils_resolve_conf_parse (AF_INET, rc, ns4, NULL)); + g_assert_cmpint (ns4->len, ==, 4); + assert_dns4_entry (ns4, 0, "4.2.2.3"); + assert_dns4_entry (ns4, 1, "4.2.2.4"); + assert_dns4_entry (ns4, 2, "4.2.2.5"); + assert_dns4_entry (ns4, 3, "4.2.2.6"); + + g_array_free (ns4, TRUE); +} + +static void +test_capture_dns_options (void) +{ + GArray *ns4 = g_array_new (FALSE, FALSE, sizeof (guint32)); + GPtrArray *dns_options = g_ptr_array_new_with_free_func (g_free); + const char *rc = +"nameserver 4.2.2.1\r\n" +"options debug rotate timeout:5 \r\n" +"options edns0\r\n"; + + g_assert (nm_utils_resolve_conf_parse (AF_INET, rc, ns4, dns_options)); + g_assert_cmpint (dns_options->len, ==, 4); + assert_dns_option (dns_options, 0, "debug"); + assert_dns_option (dns_options, 1, "rotate"); + assert_dns_option (dns_options, 2, "timeout:5"); + assert_dns_option (dns_options, 3, "edns0"); + + g_array_free (ns4, TRUE); + g_ptr_array_free (dns_options, TRUE); +} + +static void +test_capture_dns_options_dup (void) +{ + GArray *ns4 = g_array_new (FALSE, FALSE, sizeof (guint32)); + GPtrArray *dns_options = g_ptr_array_new_with_free_func (g_free); + const char *rc = +"options debug rotate timeout:3\r\n" +"options edns0 debug\r\n" +"options timeout:5\r\n"; + + g_assert (nm_utils_resolve_conf_parse (AF_INET, rc, ns4, dns_options)); + g_assert_cmpint (dns_options->len, ==, 4); + assert_dns_option (dns_options, 0, "debug"); + assert_dns_option (dns_options, 1, "rotate"); + assert_dns_option (dns_options, 2, "timeout:3"); + assert_dns_option (dns_options, 3, "edns0"); + + g_array_free (ns4, TRUE); + g_ptr_array_free (dns_options, TRUE); +} + +static void +test_capture_dns_options_valid4 (void) +{ + GArray *ns4 = g_array_new (FALSE, FALSE, sizeof (guint32)); + GPtrArray *dns_options = g_ptr_array_new_with_free_func (g_free); + const char *rc = +"options debug: rotate:yes edns0 foobar : inet6\r\n"; + + g_assert (nm_utils_resolve_conf_parse (AF_INET, rc, ns4, dns_options)); + g_assert_cmpint (dns_options->len, ==, 1); + assert_dns_option (dns_options, 0, "edns0"); + + g_array_free (ns4, TRUE); + g_ptr_array_free (dns_options, TRUE); +} + +static void +test_capture_dns_options_valid6 (void) +{ + GArray *ns6 = g_array_new (FALSE, FALSE, sizeof (struct in6_addr)); + GPtrArray *dns_options = g_ptr_array_new_with_free_func (g_free); + const char *rc = +"options inet6 debug foobar rotate:\r\n"; + + g_assert (nm_utils_resolve_conf_parse (AF_INET6, rc, ns6, dns_options)); + g_assert_cmpint (dns_options->len, ==, 2); + assert_dns_option (dns_options, 0, "inet6"); + assert_dns_option (dns_options, 1, "debug"); + + g_array_free (ns6, TRUE); + g_ptr_array_free (dns_options, TRUE); +} +/*****************************************************************************/ + +NMTST_DEFINE (); + +int +main (int argc, char **argv) +{ + nmtst_init_assert_logging (&argc, &argv, "INFO", "DEFAULT"); + + g_test_add_func ("/resolvconf-capture/empty", test_capture_empty); + g_test_add_func ("/resolvconf-capture/basic4", test_capture_basic4); + g_test_add_func ("/resolvconf-capture/dup4", test_capture_dup4); + g_test_add_func ("/resolvconf-capture/basic6", test_capture_basic6); + g_test_add_func ("/resolvconf-capture/dup6", test_capture_dup6); + g_test_add_func ("/resolvconf-capture/addr4-with-6", test_capture_addr4_with_6); + g_test_add_func ("/resolvconf-capture/addr6-with-4", test_capture_addr6_with_4); + g_test_add_func ("/resolvconf-capture/format", test_capture_format); + g_test_add_func ("/resolvconf-capture/dns-options", test_capture_dns_options); + g_test_add_func ("/resolvconf-capture/dns-options-dup", test_capture_dns_options_dup); + g_test_add_func ("/resolvconf-capture/dns-options-valid4", test_capture_dns_options_valid4); + g_test_add_func ("/resolvconf-capture/dns-options-valid6", test_capture_dns_options_valid6); + + return g_test_run (); +} + diff --git a/src/vpn/nm-vpn-connection.c b/src/vpn/nm-vpn-connection.c index 436fc68b..12ee0059 100644 --- a/src/vpn/nm-vpn-connection.c +++ b/src/vpn/nm-vpn-connection.c @@ -51,6 +51,8 @@ #include "nm-vpn-manager.h" #include "dns/nm-dns-manager.h" +#include "introspection/org.freedesktop.NetworkManager.VPN.Connection.h" + typedef enum { /* Only system secrets */ SECRETS_REQ_SYSTEM = 0, @@ -80,6 +82,7 @@ typedef enum { } VpnState; enum { + VPN_STATE_CHANGED, INTERNAL_STATE_CHANGED, INTERNAL_RETRY_AFTER_FAILURE, @@ -156,6 +159,19 @@ struct _NMVpnConnection { struct _NMVpnConnectionClass { NMActiveConnectionClass parent; + + /* Signals */ + void (*vpn_state_changed) (NMVpnConnection *self, + NMVpnConnectionState new_state, + NMActiveConnectionStateReason reason); + + /* not exported over D-Bus */ + void (*internal_state_changed) (NMVpnConnection *self, + NMVpnConnectionState new_state, + NMVpnConnectionState old_state, + NMActiveConnectionStateReason reason); + + void (*internal_failed_retry) (NMVpnConnection *self); }; G_DEFINE_TYPE (NMVpnConnection, nm_vpn_connection, NM_TYPE_ACTIVE_CONNECTION) @@ -164,9 +180,6 @@ G_DEFINE_TYPE (NMVpnConnection, nm_vpn_connection, NM_TYPE_ACTIVE_CONNECTION) /*****************************************************************************/ -static const NMDBusInterfaceInfoExtended interface_info_vpn_connection; -static const GDBusSignalInfo signal_info_vpn_state_changed; - static NMSettingsConnection *_get_settings_connection (NMVpnConnection *self, gboolean allow_missing); @@ -498,12 +511,7 @@ _set_vpn_state (NMVpnConnection *self, old_external_state = _state_to_nm_vpn_state (old_vpn_state); new_external_state = _state_to_nm_vpn_state (priv->vpn_state); if (new_external_state != old_external_state) { - nm_dbus_object_emit_signal (NM_DBUS_OBJECT (self), - &interface_info_vpn_connection, - &signal_info_vpn_state_changed, - "(uu)", - (guint32) new_external_state, - (guint32) reason); + g_signal_emit (self, signals[VPN_STATE_CHANGED], 0, new_external_state, reason); g_signal_emit (self, signals[INTERNAL_STATE_CHANGED], 0, new_external_state, old_external_state, @@ -855,7 +863,6 @@ nm_vpn_connection_new (NMSettingsConnection *settings_connection, { g_return_val_if_fail (!settings_connection || NM_IS_SETTINGS_CONNECTION (settings_connection), NULL); g_return_val_if_fail (NM_IS_DEVICE (parent_device), NULL); - g_return_val_if_fail (specific_object, NULL); return (NMVpnConnection *) g_object_new (NM_TYPE_VPN_CONNECTION, NM_ACTIVE_CONNECTION_INT_SETTINGS_CONNECTION, settings_connection, @@ -1171,8 +1178,8 @@ _cleanup_failed_config (NMVpnConnection *self) { NMVpnConnectionPrivate *priv = NM_VPN_CONNECTION_GET_PRIVATE (self); - nm_dbus_object_clear_and_unexport (&priv->ip4_config); - nm_dbus_object_clear_and_unexport (&priv->ip6_config); + nm_exported_object_clear_and_unexport (&priv->ip4_config); + nm_exported_object_clear_and_unexport (&priv->ip6_config); _LOGW ("VPN connection: did not receive valid IP config information"); _set_vpn_state (self, STATE_FAILED, NM_ACTIVE_CONNECTION_STATE_REASON_IP_CONFIG_INVALID, FALSE); @@ -1389,12 +1396,12 @@ nm_vpn_connection_config_get (NMVpnConnection *self, GVariant *dict) priv->has_ip4 = FALSE; if (g_variant_lookup (dict, NM_VPN_PLUGIN_CONFIG_HAS_IP4, "b", &b)) priv->has_ip4 = b; - nm_dbus_object_clear_and_unexport (&priv->ip4_config); + nm_exported_object_clear_and_unexport (&priv->ip4_config); priv->has_ip6 = FALSE; if (g_variant_lookup (dict, NM_VPN_PLUGIN_CONFIG_HAS_IP6, "b", &b)) priv->has_ip6 = b; - nm_dbus_object_clear_and_unexport (&priv->ip6_config); + nm_exported_object_clear_and_unexport (&priv->ip6_config); nm_vpn_connection_config_maybe_complete (self, TRUE); } @@ -1455,7 +1462,6 @@ nm_vpn_connection_ip4_config_get (NMVpnConnection *self, GVariant *dict) NMPlatformIP4Address address; guint32 u32, route_metric; NMSettingIPConfig *s_ip; - NMSettingConnection *s_con; guint32 route_table; NMIP4Config *config; GVariantIter *iter; @@ -1560,7 +1566,6 @@ nm_vpn_connection_ip4_config_get (NMVpnConnection *self, GVariant *dict) route_table = get_route_table (self, AF_INET, TRUE); route_metric = nm_vpn_connection_get_ip4_route_metric (self); s_ip = nm_connection_get_setting_ip4_config (_get_applied_connection (self)); - s_con = nm_connection_get_setting_connection (_get_applied_connection (self)); if (nm_setting_ip_config_get_ignore_auto_routes (s_ip)) { /* ignore VPN routes */ @@ -1618,7 +1623,6 @@ nm_vpn_connection_ip4_config_get (NMVpnConnection *self, GVariant *dict) /* Merge in user overrides from the NMConnection's IPv4 setting */ nm_ip4_config_merge_setting (config, s_ip, - nm_setting_connection_get_mdns (s_con), route_table, route_metric); @@ -1648,7 +1652,7 @@ nm_vpn_connection_ip4_config_get (NMVpnConnection *self, GVariant *dict) g_object_unref (config); } else { priv->ip4_config = config; - nm_dbus_object_export (NM_DBUS_OBJECT (config)); + nm_exported_object_export (NM_EXPORTED_OBJECT (config)); g_object_notify ((GObject *) self, NM_ACTIVE_CONNECTION_IP4_CONFIG); } @@ -1837,7 +1841,7 @@ next: g_object_unref (config); } else { priv->ip6_config = config; - nm_dbus_object_export (NM_DBUS_OBJECT (config)); + nm_exported_object_export (NM_EXPORTED_OBJECT (config)); g_object_notify ((GObject *) self, NM_ACTIVE_CONNECTION_IP6_CONFIG); } @@ -2324,7 +2328,7 @@ nm_vpn_connection_activate (NMVpnConnection *self, if (nm_vpn_plugin_info_supports_multiple (plugin_info)) { const char *path; - path = nm_dbus_object_get_path (NM_DBUS_OBJECT (self)); + path = nm_exported_object_get_path (NM_EXPORTED_OBJECT (self)); if (path) path = strrchr (path, '/'); g_return_if_fail (path); @@ -2547,6 +2551,7 @@ static void plugin_new_secrets_cb (GDBusProxy *proxy, GAsyncResult *result, gpointer user_data) { NMVpnConnection *self; + NMVpnConnectionPrivate *priv; gs_unref_variant GVariant *reply = NULL; gs_free_error GError *error = NULL; @@ -2555,6 +2560,7 @@ plugin_new_secrets_cb (GDBusProxy *proxy, GAsyncResult *result, gpointer user_da return; self = NM_VPN_CONNECTION (user_data); + priv = NM_VPN_CONNECTION_GET_PRIVATE (self); if (error) { g_dbus_error_strip_remote_error (error); @@ -2774,8 +2780,8 @@ dispose (GObject *object) nm_clear_g_cancellable (&priv->cancellable); g_clear_object (&priv->proxy_config); - nm_dbus_object_clear_and_unexport (&priv->ip4_config); - nm_dbus_object_clear_and_unexport (&priv->ip6_config); + nm_exported_object_clear_and_unexport (&priv->ip4_config); + nm_exported_object_clear_and_unexport (&priv->ip6_config); g_clear_object (&priv->proxy); g_clear_object (&priv->plugin_info); @@ -2825,14 +2831,14 @@ get_property (GObject *object, guint prop_id, g_value_set_string (value, priv->banner ? priv->banner : ""); break; case PROP_IP4_CONFIG: - nm_dbus_utils_g_value_set_object_path (value, ip_config_valid (priv->vpn_state) ? priv->ip4_config : NULL); + nm_utils_g_value_set_object_path (value, ip_config_valid (priv->vpn_state) ? priv->ip4_config : NULL); break; case PROP_IP6_CONFIG: - nm_dbus_utils_g_value_set_object_path (value, ip_config_valid (priv->vpn_state) ? priv->ip6_config : NULL); + nm_utils_g_value_set_object_path (value, ip_config_valid (priv->vpn_state) ? priv->ip6_config : NULL); break; case PROP_MASTER: parent_dev = nm_active_connection_get_device (NM_ACTIVE_CONNECTION (object)); - nm_dbus_utils_g_value_set_object_path (value, parent_dev); + nm_utils_g_value_set_object_path (value, parent_dev); break; default: G_OBJECT_WARN_INVALID_PROPERTY_ID (object, prop_id, pspec); @@ -2840,42 +2846,16 @@ get_property (GObject *object, guint prop_id, } } -static const GDBusSignalInfo signal_info_vpn_state_changed = NM_DEFINE_GDBUS_SIGNAL_INFO_INIT ( - "VpnStateChanged", - .args = NM_DEFINE_GDBUS_ARG_INFOS ( - NM_DEFINE_GDBUS_ARG_INFO ("state", "u"), - NM_DEFINE_GDBUS_ARG_INFO ("reason", "u"), - ), -); - -static const NMDBusInterfaceInfoExtended interface_info_vpn_connection = { - .parent = NM_DEFINE_GDBUS_INTERFACE_INFO_INIT ( - NM_DBUS_INTERFACE_VPN_CONNECTION, - .signals = NM_DEFINE_GDBUS_SIGNAL_INFOS ( - &nm_signal_info_property_changed_legacy, - &signal_info_vpn_state_changed, - ), - .properties = NM_DEFINE_GDBUS_PROPERTY_INFOS ( - NM_DEFINE_DBUS_PROPERTY_INFO_EXTENDED_READABLE_L ("VpnState", "u", NM_VPN_CONNECTION_VPN_STATE), - NM_DEFINE_DBUS_PROPERTY_INFO_EXTENDED_READABLE_L ("Banner", "s", NM_VPN_CONNECTION_BANNER), - ), - ), - .legacy_property_changed = TRUE, -}; - static void nm_vpn_connection_class_init (NMVpnConnectionClass *connection_class) { GObjectClass *object_class = G_OBJECT_CLASS (connection_class); NMActiveConnectionClass *active_class = NM_ACTIVE_CONNECTION_CLASS (connection_class); - NMDBusObjectClass *dbus_object_class = NM_DBUS_OBJECT_CLASS (connection_class); - - dbus_object_class->interface_infos = NM_DBUS_INTERFACE_INFOS (&interface_info_vpn_connection); + /* virtual methods */ object_class->get_property = get_property; object_class->dispose = dispose; object_class->finalize = finalize; - active_class->device_state_changed = device_state_changed; active_class->device_changed = device_changed; @@ -2902,6 +2882,13 @@ nm_vpn_connection_class_init (NMVpnConnectionClass *connection_class) g_object_class_override_property (object_class, PROP_IP6_CONFIG, NM_ACTIVE_CONNECTION_IP6_CONFIG); + signals[VPN_STATE_CHANGED] = + g_signal_new ("vpn-state-changed", + G_OBJECT_CLASS_TYPE (object_class), + G_SIGNAL_RUN_FIRST, + 0, NULL, NULL, NULL, + G_TYPE_NONE, 2, G_TYPE_UINT, G_TYPE_UINT); + signals[INTERNAL_STATE_CHANGED] = g_signal_new (NM_VPN_CONNECTION_INTERNAL_STATE_CHANGED, G_OBJECT_CLASS_TYPE (object_class), @@ -2915,4 +2902,8 @@ nm_vpn_connection_class_init (NMVpnConnectionClass *connection_class) G_SIGNAL_RUN_FIRST, 0, NULL, NULL, NULL, G_TYPE_NONE, 0); + + nm_exported_object_class_add_interface (NM_EXPORTED_OBJECT_CLASS (connection_class), + NMDBUS_TYPE_VPN_CONNECTION_SKELETON, + NULL); } diff --git a/src/vpn/nm-vpn-connection.h b/src/vpn/nm-vpn-connection.h index 3046634d..b287c334 100644 --- a/src/vpn/nm-vpn-connection.h +++ b/src/vpn/nm-vpn-connection.h @@ -42,6 +42,7 @@ #define NM_VPN_CONNECTION_BANNER "banner" /* Signals */ +/* not exported: includes old reason code */ #define NM_VPN_CONNECTION_INTERNAL_STATE_CHANGED "internal-state-changed" #define NM_VPN_CONNECTION_INTERNAL_RETRY_AFTER_FAILURE "internal-retry-after-failure" |