diff options
Diffstat (limited to 'src')
94 files changed, 4354 insertions, 2582 deletions
diff --git a/src/NetworkManagerUtils.c b/src/NetworkManagerUtils.c index 596c5bb3..89bd357f 100644 --- a/src/NetworkManagerUtils.c +++ b/src/NetworkManagerUtils.c @@ -773,6 +773,10 @@ check_possible_match (NMConnection *orig, * @connections: a (optionally pre-sorted) list of connections from which to * find a matching connection to @original based on "inferrable" properties * @original: the #NMConnection to find a match for from @connections + * @indicated: whether the match is already hinted/indicated. That is the + * case when we found the connection in the state file from a previous run. + * In this case, we perform a relexed check, as we have a good hint + * that the connection actually matches. * @device_has_carrier: pass %TRUE if the device that generated @original has * a carrier, %FALSE if not * @match_filter_func: a function to check whether each connection from @connections @@ -792,6 +796,7 @@ check_possible_match (NMConnection *orig, NMConnection * nm_utils_match_connection (NMConnection *const*connections, NMConnection *original, + gboolean indicated, gboolean device_has_carrier, gint64 default_v4_metric, gint64 default_v6_metric, @@ -812,7 +817,24 @@ nm_utils_match_connection (NMConnection *const*connections, continue; } - if (!nm_connection_diff (original, candidate, NM_SETTING_COMPARE_FLAG_INFERRABLE, &diffs)) { + if (indicated) { + NMSettingConnection *s_orig, *s_cand; + + s_orig = nm_connection_get_setting_connection (original); + s_cand = nm_connection_get_setting_connection (candidate); + + /* It is indicated that this connection matches. Assume we have + * a match, but check for particular differences that let us + * reject the candidate. */ + if (!nm_streq0 (nm_setting_connection_get_connection_type (s_orig), + nm_setting_connection_get_connection_type (s_cand))) + continue; + if (!nm_streq0 (nm_setting_connection_get_slave_type (s_orig), + nm_setting_connection_get_slave_type (s_cand))) + continue; + + /* this is good enough for a match */ + } else if (!nm_connection_diff (original, candidate, NM_SETTING_COMPARE_FLAG_INFERRABLE, &diffs)) { if (!best_match) { best_match = check_possible_match (original, candidate, diffs, device_has_carrier, default_v4_metric, default_v6_metric); diff --git a/src/NetworkManagerUtils.h b/src/NetworkManagerUtils.h index c20f2439..e5f28b27 100644 --- a/src/NetworkManagerUtils.h +++ b/src/NetworkManagerUtils.h @@ -41,6 +41,7 @@ typedef gboolean (NMUtilsMatchFilterFunc) (NMConnection *connection, gpointer us NMConnection *nm_utils_match_connection (NMConnection *const*connections, NMConnection *original, + gboolean indicated, gboolean device_has_carrier, gint64 default_v4_metric, gint64 default_v6_metric, diff --git a/src/devices/bluetooth/nm-bluez-device.c b/src/devices/bluetooth/nm-bluez-device.c index 182527d9..bd3cf18a 100644 --- a/src/devices/bluetooth/nm-bluez-device.c +++ b/src/devices/bluetooth/nm-bluez-device.c @@ -1185,7 +1185,8 @@ dispose (GObject *object) if (priv->pan_connection) { /* 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_settings_connection_get_nm_generated (NM_SETTINGS_CONNECTION (priv->pan_connection))) + if (NM_FLAGS_HAS (nm_settings_connection_get_flags (NM_SETTINGS_CONNECTION (priv->pan_connection)), + 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-bluez5-manager.c b/src/devices/bluetooth/nm-bluez5-manager.c index 8c93f2a5..de3f4072 100644 --- a/src/devices/bluetooth/nm-bluez5-manager.c +++ b/src/devices/bluetooth/nm-bluez5-manager.c @@ -158,7 +158,7 @@ static void _network_server_free (NMBluez5Manager *self, NetworkServer *network_server) { _network_server_unregister (self, network_server); - c_list_unlink (&network_server->lst_ns); + c_list_unlink_stale (&network_server->lst_ns); g_free (network_server->path); g_free (network_server->addr); g_slice_free (NetworkServer, network_server); diff --git a/src/devices/nm-device-ethernet.c b/src/devices/nm-device-ethernet.c index 7807100f..3ca86e06 100644 --- a/src/devices/nm-device-ethernet.c +++ b/src/devices/nm-device-ethernet.c @@ -104,7 +104,7 @@ typedef struct _NMDeviceEthernetPrivate { char * s390_nettype; GHashTable * s390_options; - NMActRequestGetSecretsCallId wired_secrets_id; + NMActRequestGetSecretsCallId *wired_secrets_id; /* PPPoE */ NMPPPManager *ppp_manager; @@ -416,7 +416,7 @@ supplicant_interface_release (NMDeviceEthernet *self) static void wired_secrets_cb (NMActRequest *req, - NMActRequestGetSecretsCallId call_id, + NMActRequestGetSecretsCallId *call_id, NMSettingsConnection *connection, GError *error, gpointer user_data) diff --git a/src/devices/nm-device-macsec.c b/src/devices/nm-device-macsec.c index 95587278..5ef8f938 100644 --- a/src/devices/nm-device-macsec.c +++ b/src/devices/nm-device-macsec.c @@ -71,7 +71,7 @@ typedef struct { gulong parent_state_id; Supplicant supplicant; guint supplicant_timeout_id; - NMActRequestGetSecretsCallId macsec_secrets_id; + NMActRequestGetSecretsCallId *macsec_secrets_id; } NMDeviceMacsecPrivate; struct _NMDeviceMacsec { @@ -276,7 +276,7 @@ supplicant_iface_assoc_cb (NMSupplicantInterface *iface, static void macsec_secrets_cb (NMActRequest *req, - NMActRequestGetSecretsCallId call_id, + NMActRequestGetSecretsCallId *call_id, NMSettingsConnection *connection, GError *error, gpointer user_data) diff --git a/src/devices/nm-device-vlan.c b/src/devices/nm-device-vlan.c index e30dae74..81512335 100644 --- a/src/devices/nm-device-vlan.c +++ b/src/devices/nm-device-vlan.c @@ -66,7 +66,7 @@ struct _NMDeviceVlanClass { G_DEFINE_TYPE (NMDeviceVlan, nm_device_vlan, NM_TYPE_DEVICE) -#define NM_DEVICE_VLAN_GET_PRIVATE(self) _NM_GET_PRIVATE (self, NMDeviceVlan, NM_IS_DEVICE_VLAN) +#define NM_DEVICE_VLAN_GET_PRIVATE(self) _NM_GET_PRIVATE (self, NMDeviceVlan, NM_IS_DEVICE_VLAN, NMDevice) /*****************************************************************************/ @@ -418,7 +418,7 @@ complete_connection (NMDevice *device, static void update_connection (NMDevice *device, NMConnection *connection) { - NMDeviceVlanPrivate *priv = NM_DEVICE_VLAN_GET_PRIVATE ((NMDeviceVlan *) device); + NMDeviceVlanPrivate *priv = NM_DEVICE_VLAN_GET_PRIVATE (device); NMSettingVlan *s_vlan = nm_connection_get_setting_vlan (connection); int ifindex = nm_device_get_ifindex (device); const char *setting_parent, *new_parent; @@ -558,7 +558,7 @@ static void get_property (GObject *object, guint prop_id, GValue *value, GParamSpec *pspec) { - NMDeviceVlanPrivate *priv = NM_DEVICE_VLAN_GET_PRIVATE ((NMDeviceVlan *) object); + NMDeviceVlanPrivate *priv = NM_DEVICE_VLAN_GET_PRIVATE (object); switch (prop_id) { case PROP_VLAN_ID: diff --git a/src/devices/nm-device.c b/src/devices/nm-device.c index 6a1a10f4..afc81dcd 100644 --- a/src/devices/nm-device.c +++ b/src/devices/nm-device.c @@ -35,6 +35,7 @@ #include <fcntl.h> #include <linux/if_addr.h> #include <linux/rtnetlink.h> +#include <linux/pkt_sched.h> #include "nm-utils/nm-dedup-multi.h" @@ -328,7 +329,7 @@ typedef struct _NMDevicePrivate { guint32 v4_route_table; guint32 v6_route_table; - /* when carrier goes away, we give a grace period of CARRIER_WAIT_TIME_MS + /* when carrier goes away, we give a grace period of _get_carrier_wait_ms() * until taking action. * * When changing MTU, the device might take longer then that. So, whenever @@ -351,8 +352,8 @@ typedef struct _NMDevicePrivate { NMDeviceSysIfaceState sys_iface_state:2; - bool v4_route_table_initalized:1; - bool v6_route_table_initalized:1; + bool v4_route_table_initialized:1; + bool v6_route_table_initialized:1; NMDeviceAutoconnectBlockedFlags autoconnect_blocked_flags:4; @@ -530,6 +531,7 @@ 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); static const char *_activation_func_to_string (ActivationHandleFunc func); static void activation_source_handle_cb (NMDevice *self, int addr_family); @@ -582,7 +584,7 @@ nm_device_state_to_str (NMDeviceState state) return queued_state_to_string (state) + NM_STRLEN (NM_PENDING_ACTIONPREFIX_QUEUED_STATE_CHANGE); } -NM_UTILS_LOOKUP_STR_DEFINE_STATIC (_reason_to_string, NMDeviceStateReason, +NM_UTILS_LOOKUP_STR_DEFINE (nm_device_state_reason_to_str, NMDeviceStateReason, NM_UTILS_LOOKUP_DEFAULT (NULL), NM_UTILS_LOOKUP_STR_ITEM (NM_DEVICE_STATE_REASON_UNKNOWN, "unknown"), NM_UTILS_LOOKUP_STR_ITEM (NM_DEVICE_STATE_REASON_NONE, "none"), @@ -651,7 +653,7 @@ NM_UTILS_LOOKUP_STR_DEFINE_STATIC (_reason_to_string, NMDeviceStateReason, ); #define reason_to_string(reason) \ - NM_UTILS_LOOKUP_STR (_reason_to_string, reason) + NM_UTILS_LOOKUP_STR (nm_device_state_reason_to_str, reason) /*****************************************************************************/ @@ -1163,9 +1165,9 @@ nm_device_get_ip_iface (NMDevice *self) } int -nm_device_get_ip_ifindex (NMDevice *self) +nm_device_get_ip_ifindex (const NMDevice *self) { - NMDevicePrivate *priv; + const NMDevicePrivate *priv; g_return_val_if_fail (self != NULL, 0); @@ -1485,7 +1487,7 @@ _stats_set_refresh_rate (NMDevice *self, guint refresh_rate_ms) if (!refresh_rate_ms) return; - /* trigger an inital refresh of the data whenever the refresh-rate changes. + /* trigger an initial refresh of the data whenever the refresh-rate changes. * As we process the result in an idle handler with device_link_changed(), * we don't get the result right away. */ ifindex = nm_device_get_ip_ifindex (self); @@ -1787,10 +1789,10 @@ nm_device_get_route_table (NMDevice *self, /* the route table setting affects how we sync routes. We shall * not change it while the device is active, hence, cache it. */ if (addr_family == AF_INET) { - if (priv->v4_route_table_initalized) + if (priv->v4_route_table_initialized) return priv->v4_route_table ?: (fallback_main ? RT_TABLE_MAIN : 0); } else { - if (priv->v6_route_table_initalized) + if (priv->v6_route_table_initialized) return priv->v6_route_table ?: (fallback_main ? RT_TABLE_MAIN : 0); } @@ -1820,10 +1822,10 @@ nm_device_get_route_table (NMDevice *self, } if (addr_family == AF_INET) { - priv->v4_route_table_initalized = TRUE; + priv->v4_route_table_initialized = TRUE; priv->v4_route_table = route_table; } else { - priv->v6_route_table_initalized = TRUE; + priv->v6_route_table_initialized = TRUE; priv->v6_route_table = route_table; } @@ -2260,7 +2262,7 @@ nm_device_master_release_one_slave (NMDevice *self, NMDevice *slave, gboolean co * Transfers ownership from slave_priv->master. */ self_free = self; - c_list_unlink_init (&info->lst_slave); + c_list_unlink (&info->lst_slave); slave_priv->master = NULL; g_signal_handler_disconnect (slave, info->watch_id); @@ -2464,8 +2466,6 @@ carrier_changed (NMDevice *self, gboolean carrier) } } -#define LINK_DISCONNECT_DELAY 4 - static gboolean carrier_disconnected_action_cb (gpointer user_data) { @@ -2522,10 +2522,13 @@ nm_device_set_carrier (NMDevice *self, gboolean carrier) _LOGD (LOGD_DEVICE, "carrier: link disconnected"); carrier_changed (self, FALSE); } else { - priv->carrier_defer_id = g_timeout_add_seconds (LINK_DISCONNECT_DELAY, - carrier_disconnected_action_cb, self); - _LOGD (LOGD_DEVICE, "carrier: link disconnected (deferring action for %d seconds) (id=%u)", - LINK_DISCONNECT_DELAY, priv->carrier_defer_id); + gint64 now_ms, until_ms; + + now_ms = nm_utils_get_monotonic_timestamp_ms (); + until_ms = NM_MAX (now_ms + _get_carrier_wait_ms (self), priv->carrier_wait_until_ms); + priv->carrier_defer_id = g_timeout_add (until_ms - now_ms, carrier_disconnected_action_cb, self); + _LOGD (LOGD_DEVICE, "carrier: link disconnected (deferring action for %ld milli seconds) (id=%u)", + (long) (until_ms - now_ms), priv->carrier_defer_id); } } } @@ -2828,6 +2831,9 @@ device_ip_link_changed (NMDevice *self) if (!pllink) return G_SOURCE_REMOVE; + if (priv->ifindex <= 0 && pllink->mtu) + _set_mtu (self, pllink->mtu); + _stats_update_counters_from_pllink (self, pllink); if (_ip_iface_update (self, pllink->name)) @@ -2910,9 +2916,9 @@ _v4_has_shadowed_routes_detect (NMDevice *self) platform = nm_device_get_platform (self); head_entry = nm_platform_lookup (platform, - nmp_lookup_init_addrroute (&lookup, - NMP_OBJECT_TYPE_IP4_ROUTE, - ifindex)); + nmp_lookup_init_object (&lookup, + NMP_OBJECT_TYPE_IP4_ROUTE, + ifindex)); if (!head_entry) return FALSE; @@ -4080,6 +4086,7 @@ nm_device_slave_notify_release (NMDevice *self, NMDeviceStateReason reason) break; case NM_DEVICE_STATE_REASON_USER_REQUESTED: new_state = NM_DEVICE_STATE_DEACTIVATING; + reason = NM_DEVICE_STATE_REASON_DEPENDENCY_FAILED; master_status = "deactivated by user request"; break; default: @@ -5213,6 +5220,88 @@ lldp_init (NMDevice *self, gboolean restart) } } +static gboolean +tc_commit (NMDevice *self) +{ + NMConnection *connection = NULL; + gs_unref_ptrarray GPtrArray *qdiscs = NULL; + gs_unref_ptrarray GPtrArray *tfilters = NULL; + NMSettingTCConfig *s_tc = NULL; + int ip_ifindex; + guint nqdiscs, ntfilters; + int i; + + connection = nm_device_get_applied_connection (self); + if (connection) + s_tc = nm_connection_get_setting_tc_config (connection); + + ip_ifindex = nm_device_get_ip_ifindex (self); + if (!ip_ifindex) + return s_tc == NULL; + + if (s_tc) { + nqdiscs = nm_setting_tc_config_get_num_qdiscs (s_tc); + qdiscs = g_ptr_array_new_full (nqdiscs, (GDestroyNotify) nmp_object_unref); + + for (i = 0; i < nqdiscs; i++) { + NMTCQdisc *s_qdisc = nm_setting_tc_config_get_qdisc (s_tc, i); + NMPObject *q = nmp_object_new (NMP_OBJECT_TYPE_QDISC, NULL); + NMPlatformQdisc *qdisc = NMP_OBJECT_CAST_QDISC (q); + + qdisc->ifindex = ip_ifindex; + qdisc->kind = nm_tc_qdisc_get_kind (s_qdisc); + qdisc->addr_family = AF_UNSPEC; + qdisc->handle = nm_tc_qdisc_get_handle (s_qdisc); + qdisc->parent = nm_tc_qdisc_get_parent (s_qdisc); + qdisc->info = 0; + + g_ptr_array_add (qdiscs, q); + } + + ntfilters = nm_setting_tc_config_get_num_tfilters (s_tc); + tfilters = g_ptr_array_new_full (ntfilters, (GDestroyNotify) nmp_object_unref); + + for (i = 0; i < ntfilters; i++) { + NMTCTfilter *s_tfilter = nm_setting_tc_config_get_tfilter (s_tc, i); + NMTCAction *action; + NMPObject *q = nmp_object_new (NMP_OBJECT_TYPE_TFILTER, NULL); + NMPlatformTfilter *tfilter = NMP_OBJECT_CAST_TFILTER (q); + + tfilter->ifindex = ip_ifindex; + tfilter->kind = nm_tc_tfilter_get_kind (s_tfilter); + tfilter->addr_family = AF_UNSPEC; + tfilter->handle = nm_tc_tfilter_get_handle (s_tfilter); + tfilter->parent = nm_tc_tfilter_get_parent (s_tfilter); + tfilter->info = TC_H_MAKE (0, htons (ETH_P_ALL)); + + action = nm_tc_tfilter_get_action (s_tfilter); + if (action) { + tfilter->action.kind = nm_tc_action_get_kind (action); + if (strcmp (tfilter->action.kind, "simple") == 0) { + GVariant *sdata; + + sdata = nm_tc_action_get_attribute (action, "sdata"); + if (sdata && g_variant_is_of_type (sdata, G_VARIANT_TYPE_BYTESTRING)) { + g_strlcpy (tfilter->action.simple.sdata, + g_variant_get_bytestring (sdata), + sizeof (tfilter->action.simple.sdata)); + } + } + } + + g_ptr_array_add (tfilters, q); + } + } + + if (!nm_platform_qdisc_sync (nm_device_get_platform (self), ip_ifindex, qdiscs)) + return FALSE; + + if (!nm_platform_tfilter_sync (nm_device_get_platform (self), ip_ifindex, tfilters)) + return FALSE; + + return TRUE; +} + /* * activate_stage2_device_config * @@ -5234,6 +5323,11 @@ activate_stage2_device_config (NMDevice *self) if (!nm_device_sys_iface_state_is_external_or_assume (self)) { NMDeviceStateReason failure_reason = NM_DEVICE_STATE_REASON_NONE; + if (!tc_commit (self)) { + _LOGW (LOGD_IP6, "failed applying traffic control rules"); + nm_device_state_changed (self, NM_DEVICE_STATE_FAILED, NM_DEVICE_STATE_REASON_CONFIG_FAILED); + } + if (!nm_device_bring_up (self, FALSE, &no_firmware)) { if (no_firmware) nm_device_state_changed (self, NM_DEVICE_STATE_FAILED, NM_DEVICE_STATE_REASON_FIRMWARE_MISSING); @@ -5811,6 +5905,9 @@ ip4_config_merge_and_apply (NMDevice *self, GSList *iter; gs_unref_ptrarray GPtrArray *ip4_dev_route_blacklist = NULL; + 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) { @@ -6474,6 +6571,9 @@ ip6_config_merge_and_apply (NMDevice *self, 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) { @@ -7001,7 +7101,7 @@ nm_device_copy_ip6_dns_config (NMDevice *self, NMDevice *from_device) { NMDevicePrivate *priv = NM_DEVICE_GET_PRIVATE (self); NMIP6Config *from_config = NULL; - int i; + guint i, len; if (priv->ac_ip6_config) { nm_ip6_config_reset_nameservers (priv->ac_ip6_config); @@ -7014,14 +7114,16 @@ nm_device_copy_ip6_dns_config (NMDevice *self, NMDevice *from_device) if (!from_config) return; - for (i = 0; i < nm_ip6_config_get_num_nameservers (from_config); i++) { + len = nm_ip6_config_get_num_nameservers (from_config); + for (i = 0; i < len; i++) { nm_ip6_config_add_nameserver (priv->ac_ip6_config, nm_ip6_config_get_nameserver (from_config, i)); } - for (i = 0; i < nm_ip6_config_get_num_searches (from_config); i++) { + len = nm_ip6_config_get_num_searches (from_config); + for (i = 0; i < len; i++) { nm_ip6_config_add_search (priv->ac_ip6_config, - nm_ip6_config_get_search (from_config, i)); + nm_ip6_config_get_search (from_config, i)); } if (!ip6_config_merge_and_apply (self, TRUE)) @@ -7105,11 +7207,11 @@ check_and_add_ipv6ll_addr (NMDevice *self) if (priv->nm_ipv6ll == FALSE) return; - if (priv->ip6_config) { + if (priv->ext_ip6_config_captured) { NMDedupMultiIter ipconf_iter; const NMPlatformIP6Address *addr; - nm_ip_config_iter_ip6_address_for_each (&ipconf_iter, priv->ip6_config, &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 */ @@ -8376,7 +8478,7 @@ nm_device_activate_schedule_ip6_config_timeout (NMDevice *self) } static gboolean -share_init (NMDevice *self) +share_init (NMDevice *self, GError **error) { char *modules[] = { "ip_tables", "iptable_nat", "nf_nat_ftp", "nf_nat_irc", "nf_nat_sip", "nf_nat_tftp", "nf_nat_pptp", "nf_nat_h323", @@ -8384,17 +8486,23 @@ share_init (NMDevice *self) char **iter; int errsv; - if (!nm_platform_sysctl_set (nm_device_get_platform (self), NMP_SYSCTL_PATHID_ABSOLUTE ("/proc/sys/net/ipv4/ip_forward"), "1")) { + if (nm_platform_sysctl_get_int32 (nm_device_get_platform (self), NMP_SYSCTL_PATHID_ABSOLUTE ("/proc/sys/net/ipv4/ip_forward"), -1) == 1) { + /* nothing to do. */ + } else if (!nm_platform_sysctl_set (nm_device_get_platform (self), NMP_SYSCTL_PATHID_ABSOLUTE ("/proc/sys/net/ipv4/ip_forward"), "1")) { errsv = errno; - nm_log_err (LOGD_SHARING, "share: error enabling IPv4 forwarding: (%d) %s", - errsv, strerror (errsv)); + _LOGD (LOGD_SHARING, "share: error enabling IPv4 forwarding: (%d) %s", + errsv, g_strerror (errsv)); + g_set_error (error, NM_UTILS_ERROR, NM_UTILS_ERROR_UNKNOWN, + "cannot set ipv4/ip_forward: %s", g_strerror (errsv)); return FALSE; } - if (!nm_platform_sysctl_set (nm_device_get_platform (self), NMP_SYSCTL_PATHID_ABSOLUTE ("/proc/sys/net/ipv4/ip_dynaddr"), "1")) { + if (nm_platform_sysctl_get_int32 (nm_device_get_platform (self), NMP_SYSCTL_PATHID_ABSOLUTE ("/proc/sys/net/ipv4/ip_dynaddr"), -1) == 1) { + /* nothing to do. */ + } else if (!nm_platform_sysctl_set (nm_device_get_platform (self), NMP_SYSCTL_PATHID_ABSOLUTE ("/proc/sys/net/ipv4/ip_dynaddr"), "1")) { errsv = errno; - nm_log_err (LOGD_SHARING, "share: error enabling dynamic addresses: (%d) %s", - errsv, strerror (errsv)); + _LOGD (LOGD_SHARING, "share: error enabling dynamic addresses: (%d) %s", + errsv, strerror (errsv)); } for (iter = modules; *iter; iter++) @@ -8411,41 +8519,45 @@ share_init (NMDevice *self) } G_STMT_END static gboolean -start_sharing (NMDevice *self, NMIP4Config *config) +start_sharing (NMDevice *self, NMIP4Config *config, GError **error) { NMDevicePrivate *priv = NM_DEVICE_GET_PRIVATE (self); NMActRequest *req; - GError *error = NULL; - char str_addr[INET_ADDRSTRLEN + 1]; - char str_mask[INET_ADDRSTRLEN + 1]; + char str_addr[INET_ADDRSTRLEN]; + char str_mask[INET_ADDRSTRLEN]; guint32 netmask, network; const NMPlatformIP4Address *ip4_addr = NULL; const char *ip_iface; + GError *local = NULL; - g_return_val_if_fail (config != NULL, FALSE); + g_return_val_if_fail (config, FALSE); ip_iface = nm_device_get_ip_iface (self); - if (!ip_iface) + if (!ip_iface) { + g_set_error (error, NM_UTILS_ERROR, NM_UTILS_ERROR_UNKNOWN, + "device has no ip interface"); return FALSE; + } ip4_addr = nm_ip4_config_get_first_address (config); - if (!ip4_addr || !ip4_addr->address) - return FALSE; - - netmask = _nm_utils_ip4_prefix_to_netmask (ip4_addr->plen); - if (!inet_ntop (AF_INET, &netmask, str_mask, sizeof (str_mask))) - return FALSE; - - network = ip4_addr->address & netmask; - if (!inet_ntop (AF_INET, &network, str_addr, sizeof (str_addr))) + if (!ip4_addr || !ip4_addr->address) { + g_set_error (error, NM_UTILS_ERROR, NM_UTILS_ERROR_UNKNOWN, + "could not determine IPv4 address"); return FALSE; + } - if (!share_init (self)) + if (!share_init (self, error)) return FALSE; req = nm_device_get_act_request (self); g_assert (req); + netmask = _nm_utils_ip4_prefix_to_netmask (ip4_addr->plen); + nm_utils_inet4_ntop (netmask, str_mask); + + network = ip4_addr->address & netmask; + nm_utils_inet4_ntop (network, str_addr); + add_share_rule (req, "nat", "POSTROUTING --source %s/%s ! --destination %s/%s --jump MASQUERADE", str_addr, str_mask, str_addr, str_mask); add_share_rule (req, "filter", "FORWARD --destination %s/%s --out-interface %s --match state --state ESTABLISHED,RELATED --jump ACCEPT", str_addr, str_mask, ip_iface); add_share_rule (req, "filter", "FORWARD --source %s/%s --in-interface %s --jump ACCEPT", str_addr, str_mask, ip_iface); @@ -8459,10 +8571,10 @@ start_sharing (NMDevice *self, NMIP4Config *config) nm_act_request_set_shared (req, TRUE); - if (!nm_dnsmasq_manager_start (priv->dnsmasq_manager, config, &error)) { - _LOGE (LOGD_SHARING, "share: (%s) failed to start dnsmasq: %s", - ip_iface, error->message); - g_error_free (error); + if (!nm_dnsmasq_manager_start (priv->dnsmasq_manager, config, &local)) { + g_set_error (error, NM_UTILS_ERROR, NM_UTILS_ERROR_UNKNOWN, + "could not start dnsmasq due to %s", local->message); + g_error_free (local); nm_act_request_set_shared (req, FALSE); return FALSE; } @@ -8564,8 +8676,10 @@ activate_stage5_ip4_config_result (NMDevice *self) method = nm_utils_get_ip_config_method (connection, NM_TYPE_SETTING_IP4_CONFIG); if (strcmp (method, NM_SETTING_IP4_CONFIG_METHOD_SHARED) == 0) { - if (!start_sharing (self, priv->ip4_config)) { - _LOGW (LOGD_SHARING, "Activation: Stage 5 of 5 (IPv4 Commit) start sharing failed."); + gs_free_error GError *error = NULL; + + 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; } @@ -9441,6 +9555,9 @@ reapply_cb (NMDevice *self, return; } + if (nm_device_sys_iface_state_is_external (self)) + nm_device_sys_iface_state_set (self, NM_DEVICE_SYS_IFACE_STATE_MANAGED); + if (!check_and_reapply_connection (self, connection ? : (NMConnection *) nm_device_get_settings_connection (self), version_id, @@ -10144,7 +10261,8 @@ nm_device_set_ip4_config (NMDevice *self, if ( nm_device_sys_iface_state_is_external (self) && (settings_connection = nm_device_get_settings_connection (self)) - && nm_settings_connection_get_nm_generated (settings_connection) + && 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_ip4; @@ -10315,7 +10433,8 @@ nm_device_set_ip6_config (NMDevice *self, if ( nm_device_sys_iface_state_is_external (self) && (settings_connection = nm_device_get_settings_connection (self)) - && nm_settings_connection_get_nm_generated (settings_connection) + && 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; @@ -10670,6 +10789,18 @@ nm_device_is_up (NMDevice *self) return ifindex > 0 ? nm_platform_link_is_up (nm_device_get_platform (self), ifindex) : TRUE; } +static gint64 +_get_carrier_wait_ms (NMDevice *self) +{ + gs_free char *value = NULL; + + value = nm_config_data_get_device_config (NM_CONFIG_GET_DATA, + NM_CONFIG_KEYFILE_KEY_DEVICE_CARRIER_WAIT_TIMEOUT, + self, + NULL); + return _nm_utils_ascii_str_to_int64 (value, 10, 0, G_MAXINT32, CARRIER_WAIT_TIME_MS); +} + gboolean nm_device_bring_up (NMDevice *self, gboolean block, gboolean *no_firmware) { @@ -10744,7 +10875,7 @@ nm_device_bring_up (NMDevice *self, gboolean block, gboolean *no_firmware) nm_device_add_pending_action (self, NM_PENDING_ACTION_CARRIER_WAIT, FALSE); now_ms = nm_utils_get_monotonic_timestamp_ms (); - until_ms = NM_MAX (now_ms + CARRIER_WAIT_TIME_MS, priv->carrier_wait_until_ms); + until_ms = NM_MAX (now_ms + _get_carrier_wait_ms (self), priv->carrier_wait_until_ms); priv->carrier_wait_id = g_timeout_add (until_ms - now_ms, carrier_wait_timeout, self); } @@ -12378,8 +12509,8 @@ _cleanup_generic_post (NMDevice *self, CleanupType cleanup_type) priv->v4_commit_first_time = TRUE; priv->v6_commit_first_time = TRUE; - priv->v4_route_table_initalized = FALSE; - priv->v6_route_table_initalized = FALSE; + priv->v4_route_table_initialized = FALSE; + priv->v6_route_table_initialized = FALSE; priv->default_route_metric_penalty_ip4_has = FALSE; priv->default_route_metric_penalty_ip6_has = FALSE; @@ -12418,7 +12549,7 @@ _cleanup_generic_post (NMDevice *self, CleanupType cleanup_type) nm_assert (priv->needs_ip6_subnet == FALSE); if (priv->act_request) { - nm_active_connection_set_default (NM_ACTIVE_CONNECTION (priv->act_request), FALSE); + 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, &priv->master_ready_id); @@ -12493,6 +12624,8 @@ nm_device_cleanup (NMDevice *self, NMDeviceStateReason reason, CleanupType clean nm_platform_ip_route_flush (platform, AF_UNSPEC, ifindex); nm_platform_ip_address_flush (platform, AF_UNSPEC, ifindex); + nm_platform_tfilter_sync (platform, ifindex, NULL); + nm_platform_qdisc_sync (platform, ifindex, NULL); } } @@ -13344,7 +13477,7 @@ nm_device_update_hw_address (NMDevice *self) && !nm_device_is_activating (self))) { /* when we get a hw_addr the first time or while the device * is not activated (with no explict hw address set), always - * update our inital hw-address as well. */ + * update our initial hw-address as well. */ nm_device_update_initial_hw_address (self); } return TRUE; diff --git a/src/devices/nm-device.h b/src/devices/nm-device.h index bd8104b4..810a613d 100644 --- a/src/devices/nm-device.h +++ b/src/devices/nm-device.h @@ -438,7 +438,7 @@ int nm_device_get_ifindex (NMDevice *dev); gboolean nm_device_is_software (NMDevice *dev); gboolean nm_device_is_real (NMDevice *dev); const char * nm_device_get_ip_iface (NMDevice *dev); -int nm_device_get_ip_ifindex (NMDevice *dev); +int nm_device_get_ip_ifindex (const NMDevice *dev); const char * nm_device_get_driver (NMDevice *dev); const char * nm_device_get_driver_version (NMDevice *dev); const char * nm_device_get_type_desc (NMDevice *dev); @@ -794,5 +794,6 @@ struct _NMBtVTableNetworkServer { }; const char *nm_device_state_to_str (NMDeviceState state); +const char *nm_device_state_reason_to_str (NMDeviceStateReason reason); #endif /* __NETWORKMANAGER_DEVICE_H__ */ diff --git a/src/devices/tests/test-lldp.c b/src/devices/tests/test-lldp.c index 1e600cdf..c3c4f0d2 100644 --- a/src/devices/tests/test-lldp.c +++ b/src/devices/tests/test-lldp.c @@ -366,7 +366,7 @@ _test_recv_fixture_setup (TestRecvFixture *fixture, gconstpointer user_data) g_assert (s >= 0); ifr.ifr_flags |= IFF_UP; g_assert (ioctl (s, SIOCSIFFLAGS, &ifr) >= 0); - close (s); + nm_close (s); link = nmtstp_assert_wait_for_link (NM_PLATFORM_GET, TEST_IFNAME, NM_LINK_TYPE_TAP, 100); fixture->ifindex = link->ifindex; diff --git a/src/devices/wifi/nm-device-wifi.c b/src/devices/wifi/nm-device-wifi.c index 5e92f47b..bf021095 100644 --- a/src/devices/wifi/nm-device-wifi.c +++ b/src/devices/wifi/nm-device-wifi.c @@ -107,7 +107,7 @@ typedef struct { NM80211Mode mode; - NMActRequestGetSecretsCallId wifi_secrets_id; + NMActRequestGetSecretsCallId *wifi_secrets_id; guint periodic_source_id; guint link_timeout_id; @@ -1428,8 +1428,8 @@ build_hidden_probe_list (NMDeviceWifi *self) connections = nm_settings_get_connections_clone (nm_device_get_settings ((NMDevice *) self), &len, - hidden_filter_func, - NULL); + hidden_filter_func, NULL, + NULL, NULL); if (!connections[0]) return NULL; @@ -1786,7 +1786,7 @@ cleanup_supplicant_failures (NMDeviceWifi *self) static void wifi_secrets_cb (NMActRequest *req, - NMActRequestGetSecretsCallId call_id, + NMActRequestGetSecretsCallId *call_id, NMSettingsConnection *connection, GError *error, gpointer user_data) diff --git a/src/devices/wwan/nm-modem.c b/src/devices/wwan/nm-modem.c index 77495b62..1c32791f 100644 --- a/src/devices/wwan/nm-modem.c +++ b/src/devices/wwan/nm-modem.c @@ -94,7 +94,7 @@ typedef struct _NMModemPrivate { NMActRequest *act_request; guint32 secrets_tries; - NMActRequestGetSecretsCallId secrets_id; + NMActRequestGetSecretsCallId *secrets_id; guint32 mm_ip_timeout; @@ -880,7 +880,7 @@ cancel_get_secrets (NMModem *self) static void modem_secrets_cb (NMActRequest *req, - NMActRequestGetSecretsCallId call_id, + NMActRequestGetSecretsCallId *call_id, NMSettingsConnection *connection, GError *error, gpointer user_data) diff --git a/src/dns/nm-dns-dnsmasq.c b/src/dns/nm-dns-dnsmasq.c index 3ec1fd2d..e6436c79 100644 --- a/src/dns/nm-dns-dnsmasq.c +++ b/src/dns/nm-dns-dnsmasq.c @@ -568,12 +568,14 @@ update (NMDnsPlugin *plugin, add_global_config (self, &servers, global_config); else { for (i = 0; i < configs->len; i++) { - prio = nm_dns_ip_config_data_get_dns_priority (configs->pdata[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) break; - add_ip_config_data (self, &servers, configs->pdata[i]); + add_ip_config_data (self, &servers, data); } } diff --git a/src/dns/nm-dns-manager.c b/src/dns/nm-dns-manager.c index d5392b7d..973abc1c 100644 --- a/src/dns/nm-dns-manager.c +++ b/src/dns/nm-dns-manager.c @@ -197,19 +197,6 @@ NM_UTILS_LOOKUP_STR_DEFINE_STATIC (_config_type_to_string, NMDnsIPConfigType, NM_UTILS_LOOKUP_STR_ITEM (NM_DNS_IP_CONFIG_TYPE_VPN, "vpn"), ); -int -nm_dns_ip_config_data_get_dns_priority (const NMDnsIPConfigData *config) -{ - g_return_val_if_fail (config, 0); - - if (NM_IS_IP4_CONFIG (config->config)) - return nm_ip4_config_get_dns_priority (config->config); - else if (NM_IS_IP6_CONFIG (config->config)) - return nm_ip6_config_get_dns_priority (config->config); - else - g_return_val_if_reached (0); -} - static NMDnsIPConfigData * ip_config_data_new (gpointer config, NMDnsIPConfigType type, const char *iface) { @@ -241,8 +228,8 @@ ip_config_data_compare (const NMDnsIPConfigData *a, const NMDnsIPConfigData *b) { int a_prio, b_prio; - a_prio = nm_dns_ip_config_data_get_dns_priority (a); - b_prio = nm_dns_ip_config_data_get_dns_priority (b); + 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) @@ -288,135 +275,83 @@ add_string_item (GPtrArray *array, const char *str) } static void -add_dns_option_item (GPtrArray *array, const char *str, gboolean ipv6) +add_dns_option_item (GPtrArray *array, const char *str) { if (_nm_utils_dns_option_find_idx (array, str) < 0) g_ptr_array_add (array, g_strdup (str)); } static void -merge_one_ip4_config (NMResolvConfData *rc, NMIP4Config *src) +merge_one_ip_config (NMResolvConfData *rc, + const NMIPConfig *config, + const char *iface) { - guint32 num, num_domains, num_searches, i; - - num = nm_ip4_config_get_num_nameservers (src); - for (i = 0; i < num; i++) { - add_string_item (rc->nameservers, - nm_utils_inet4_ntop (nm_ip4_config_get_nameserver (src, i), NULL)); - } - - num_domains = nm_ip4_config_get_num_domains (src); - num_searches = nm_ip4_config_get_num_searches (src); - - for (i = 0; i < num_searches; i++) { - const char *search; - - search = nm_ip4_config_get_search (src, i); - if (!domain_is_valid (search, FALSE)) - continue; - add_string_item (rc->searches, search); - } - - if (num_domains > 1 || !num_searches) { - for (i = 0; i < num_domains; i++) { - const char *domain; - - domain = nm_ip4_config_get_domain (src, i); - if (!domain_is_valid (domain, FALSE)) - continue; - add_string_item (rc->searches, domain); - } - } - - num = nm_ip4_config_get_num_dns_options (src); - for (i = 0; i < num; i++) { - const char *option; - - option = nm_ip4_config_get_dns_option (src, i); - add_dns_option_item (rc->options, option, FALSE); - } - - /* NIS stuff */ - num = nm_ip4_config_get_num_nis_servers (src); - for (i = 0; i < num; i++) { - add_string_item (rc->nis_servers, - nm_utils_inet4_ntop (nm_ip4_config_get_nis_server (src, i), NULL)); - } + int addr_family; + guint num, num_domains, num_searches, i; + char buf[NM_UTILS_INET_ADDRSTRLEN + 50]; + const char *str; - if (nm_ip4_config_get_nis_domain (src)) { - /* FIXME: handle multiple domains */ - if (!rc->nis_domain) - rc->nis_domain = nm_ip4_config_get_nis_domain (src); - } -} + addr_family = nm_ip_config_get_addr_family (config); -static void -merge_one_ip6_config (NMResolvConfData *rc, NMIP6Config *src, const char *iface) -{ - guint32 num, num_domains, num_searches, i; + nm_assert_addr_family (addr_family); - num = nm_ip6_config_get_num_nameservers (src); + num = nm_ip_config_get_num_nameservers (config); for (i = 0; i < num; i++) { - const struct in6_addr *addr; - char buf[NM_UTILS_INET_ADDRSTRLEN + 50]; - - addr = nm_ip6_config_get_nameserver (src, i); + const NMIPAddr *addr; - /* inet_ntop is probably supposed to do this for us, but it doesn't */ - if (IN6_IS_ADDR_V4MAPPED (addr)) - nm_utils_inet4_ntop (addr->s6_addr32[3], buf); + 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)) + nm_utils_inet4_ntop (addr->addr6.s6_addr32[3], buf); else { - nm_utils_inet6_ntop (addr, buf); + nm_utils_inet6_ntop (&addr->addr6, buf); if (IN6_IS_ADDR_LINKLOCAL (addr)) { g_strlcat (buf, "%", sizeof (buf)); g_strlcat (buf, iface, sizeof (buf)); } } + add_string_item (rc->nameservers, buf); } - num_domains = nm_ip6_config_get_num_domains (src); - num_searches = nm_ip6_config_get_num_searches (src); - + 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++) { - const char *search; - - search = nm_ip6_config_get_search (src, i); - if (!domain_is_valid (search, FALSE)) - continue; - add_string_item (rc->searches, search); + 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++) { - const char *domain; - - domain = nm_ip6_config_get_domain (src, i); - if (!domain_is_valid (domain, FALSE)) - continue; - add_string_item (rc->searches, domain); + str = nm_ip_config_get_domain (config, i); + if (domain_is_valid (str, FALSE)) + add_string_item (rc->searches, str); } } - num = nm_ip6_config_get_num_dns_options (src); + num = nm_ip_config_get_num_dns_options (config); for (i = 0; i < num; i++) { - const char *option; - - option = nm_ip6_config_get_dns_option (src, i); - add_dns_option_item (rc->options, option, TRUE); + add_dns_option_item (rc->options, + nm_ip_config_get_dns_option (config, i)); } -} -static void -merge_one_ip_config_data (NMResolvConfData *rc, - NMDnsIPConfigData *data) -{ - if (NM_IS_IP4_CONFIG (data->config)) - merge_one_ip4_config (rc, (NMIP4Config *) data->config); - else if (NM_IS_IP6_CONFIG (data->config)) - merge_one_ip6_config (rc, (NMIP6Config *) data->config, data->iface); - else - g_return_if_reached (); + if (addr_family == AF_INET) { + const NMIP4Config *config4 = (const NMIP4Config *) config; + + /* NIS stuff */ + 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 (config4, i), buf)); + } + + 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 (config4); + } + } } static GPid @@ -940,39 +875,27 @@ merge_global_dns_config (NMResolvConfData *rc, NMGlobalDnsConfig *global_conf) } static const char * -get_nameserver_list (void *config, GString **str) +get_nameserver_list (const NMIPConfig *config, GString **str) { - NMIP4Config *ip4; - NMIP6Config *ip6; guint num, i; - - nm_assert (str); + char buf[NM_UTILS_INET_ADDRSTRLEN]; + int addr_family; if (*str) g_string_truncate (*str, 0); else *str = g_string_sized_new (64); - if (NM_IS_IP4_CONFIG (config)) { - ip4 = (NMIP4Config *) config; - num = nm_ip4_config_get_num_nameservers (ip4); - for (i = 0; i < num; i++) { - g_string_append (*str, - nm_utils_inet4_ntop (nm_ip4_config_get_nameserver (ip4, i), - NULL)); - g_string_append_c (*str, ' '); - } - } else if (NM_IS_IP6_CONFIG (config)) { - ip6 = (NMIP6Config *) config; - num = nm_ip6_config_get_num_nameservers (ip6); - for (i = 0; i < num; i++) { - g_string_append (*str, - nm_utils_inet6_ntop (nm_ip6_config_get_nameserver (ip6, i), - NULL)); + addr_family = nm_ip_config_get_addr_family (config); + num = nm_ip_config_get_num_nameservers (config); + for (i = 0; i < num; i++) { + nm_utils_inet_ntop (addr_family, + nm_ip_config_get_nameserver (config, i), + buf); + if (i > 0) g_string_append_c (*str, ' '); - } - } else - g_return_val_if_reached (NULL); + g_string_append (*str, buf); + } return (*str)->str; } @@ -1011,34 +934,31 @@ _collect_resolv_conf_data (NMDnsManager *self, /* only for logging context, no o nm_auto_free_gstring GString *tmp_gstring = NULL; int prio, first_prio = 0; NMDnsIPConfigData *current; - gboolean v4; for (i = 0, j = 0; i < configs->len; i++) { gboolean skip = FALSE; current = configs->pdata[i]; - prio = nm_dns_ip_config_data_get_dns_priority (current); + prio = nm_ip_config_get_dns_priority (current->config); if (i == 0) first_prio = prio; else if (first_prio < 0 && first_prio != prio) skip = TRUE; - v4 = NM_IS_IP4_CONFIG (current->config); - if ( ( v4 && nm_ip4_config_get_num_nameservers ((NMIP4Config *) current->config)) - || (!v4 && nm_ip6_config_get_num_nameservers ((NMIP6Config *) current->config))) { + if (nm_ip_config_get_num_nameservers (current->config)) { _LOGT ("config: %8d %-7s v%c %-16s %s: %s", prio, _config_type_to_string (current->type), - v4 ? '4' : '6', + nm_utils_addr_family_to_char (nm_ip_config_get_addr_family (current->config)), current->iface, skip ? "<SKIP>" : "", get_nameserver_list (current->config, &tmp_gstring)); } if (!skip) - merge_one_ip_config_data (&rc, current); + merge_one_ip_config (&rc, current->config, current->iface); } } @@ -1305,7 +1225,7 @@ forget_data (NMDnsManager *self, NMDnsIPConfigData *data) g_signal_handlers_disconnect_by_func (data->config, ip_config_dns_priority_changed, self); } -static gboolean +gboolean nm_dns_manager_add_ip_config (NMDnsManager *self, const char *iface, gpointer config, @@ -1320,6 +1240,7 @@ nm_dns_manager_add_ip_config (NMDnsManager *self, g_return_val_if_fail (NM_IS_DNS_MANAGER (self), 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); @@ -1368,24 +1289,6 @@ nm_dns_manager_add_ip_config (NMDnsManager *self, } gboolean -nm_dns_manager_add_ip4_config (NMDnsManager *self, - const char *iface, - NMIP4Config *config, - NMDnsIPConfigType cfg_type) -{ - return nm_dns_manager_add_ip_config (self, iface, config, cfg_type); -} - -gboolean -nm_dns_manager_add_ip6_config (NMDnsManager *self, - const char *iface, - NMIP6Config *config, - NMDnsIPConfigType cfg_type) -{ - return nm_dns_manager_add_ip_config (self, iface, config, cfg_type); -} - -static gboolean nm_dns_manager_remove_ip_config (NMDnsManager *self, gpointer config) { NMDnsManagerPrivate *priv; @@ -1395,6 +1298,7 @@ nm_dns_manager_remove_ip_config (NMDnsManager *self, gpointer config) 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); @@ -1416,18 +1320,6 @@ nm_dns_manager_remove_ip_config (NMDnsManager *self, gpointer config) return FALSE; } -gboolean -nm_dns_manager_remove_ip4_config (NMDnsManager *self, NMIP4Config *config) -{ - return nm_dns_manager_remove_ip_config (self, config); -} - -gboolean -nm_dns_manager_remove_ip6_config (NMDnsManager *self, NMIP6Config *config) -{ - return nm_dns_manager_remove_ip_config (self, config); -} - void nm_dns_manager_set_initial_hostname (NMDnsManager *self, const char *hostname) @@ -1643,6 +1535,11 @@ static gboolean _resolvconf_resolved_managed (void) { static const char *const RESOLVED_PATHS[] = { + "../run/systemd/resolve/stub-resolv.conf", + "../run/systemd/resolve/resolv.conf", + "../lib/systemd/resolv.conf", + "../usr/lib/systemd/resolv.conf", + "/run/systemd/resolve/stub-resolv.conf", "/run/systemd/resolve/resolv.conf", "/lib/systemd/resolv.conf", "/usr/lib/systemd/resolv.conf", @@ -1697,7 +1594,10 @@ _resolvconf_resolved_managed (void) /* see if resolv.conf resolves to one of the candidate * paths (or whether it is hard-linked). */ for (i = 0; i < G_N_ELEMENTS (RESOLVED_PATHS); i++) { - if ( stat (RESOLVED_PATHS[i], &st_test) == 0 + const char *p = RESOLVED_PATHS[i]; + + if ( p[0] == '/' + && stat (p, &st_test) == 0 && st.st_dev == st_test.st_dev && st.st_ino == st_test.st_ino) return TRUE; @@ -1926,92 +1826,46 @@ _get_config_variant (NMDnsManager *self) 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; - gboolean v4 = NM_IS_IP4_CONFIG (current->config); - gint priority; + guint num; + const int addr_family = nm_ip_config_get_addr_family (config); + char buf[NM_UTILS_INET_ADDRSTRLEN]; + const NMIPAddr *addr; - if (v4) { - NMIP4Config *config = NM_IP4_CONFIG (current->config); - guint num = nm_ip4_config_get_num_nameservers (config); - guint32 ns; - - if (!num) - continue; - - g_variant_builder_init (&entry_builder, G_VARIANT_TYPE ("a{sv}")); - - /* Add nameservers */ - g_variant_builder_init (&strv_builder, G_VARIANT_TYPE ("as")); - for (j = 0; j < num; j++) { - ns = nm_ip4_config_get_nameserver (config, j); - g_variant_builder_add (&strv_builder, - "s", - nm_utils_inet4_ntop (ns, NULL)); - } - g_variant_builder_add (&entry_builder, - "{sv}", - "nameservers", - g_variant_builder_end (&strv_builder)); - - /* Add domains */ - num = nm_ip4_config_get_num_domains (config); - if (num > 0) { - g_variant_builder_init (&strv_builder, G_VARIANT_TYPE ("as")); - for (j = 0; j < num; j++) { - g_variant_builder_add (&strv_builder, - "s", - nm_ip4_config_get_domain (config, j)); - } - g_variant_builder_add (&entry_builder, - "{sv}", - "domains", - g_variant_builder_end (&strv_builder)); - } - - priority = nm_ip4_config_get_dns_priority (config); - } else { - NMIP6Config *config = NM_IP6_CONFIG (current->config); - guint num = nm_ip6_config_get_num_nameservers (config); - const struct in6_addr *ns; + num = nm_ip_config_get_num_nameservers (config); + if (!num) + continue; - if (!num) - continue; + g_variant_builder_init (&entry_builder, G_VARIANT_TYPE ("a{sv}")); - g_variant_builder_init (&entry_builder, G_VARIANT_TYPE ("a{sv}")); + g_variant_builder_init (&strv_builder, G_VARIANT_TYPE ("as")); + 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)); + } + g_variant_builder_add (&entry_builder, + "{sv}", + "nameservers", + g_variant_builder_end (&strv_builder)); - /* Add nameservers */ + num = nm_ip_config_get_num_domains (config); + if (num > 0) { g_variant_builder_init (&strv_builder, G_VARIANT_TYPE ("as")); for (j = 0; j < num; j++) { - ns = nm_ip6_config_get_nameserver (config, j); g_variant_builder_add (&strv_builder, "s", - nm_utils_inet6_ntop (ns, NULL)); + nm_ip_config_get_domain (config, j)); } g_variant_builder_add (&entry_builder, "{sv}", - "nameservers", + "domains", g_variant_builder_end (&strv_builder)); - - /* Add domains */ - num = nm_ip6_config_get_num_domains (config); - if (num > 0) { - g_variant_builder_init (&strv_builder, G_VARIANT_TYPE ("as")); - for (j = 0; j < num; j++) { - g_variant_builder_add (&strv_builder, - "s", - nm_ip6_config_get_domain (config, j)); - } - g_variant_builder_add (&entry_builder, - "{sv}", - "domains", - g_variant_builder_end (&strv_builder)); - } - - priority = nm_ip6_config_get_dns_priority (config); } - /* Add device */ if (current->iface) { g_variant_builder_add (&entry_builder, "{sv}", @@ -2019,13 +1873,11 @@ _get_config_variant (NMDnsManager *self) g_variant_new_string (current->iface)); } - /* Add priority */ g_variant_builder_add (&entry_builder, "{sv}", "priority", - g_variant_new_int32 (priority)); + g_variant_new_int32 (nm_ip_config_get_dns_priority (config))); - /* Add VPN */ g_variant_builder_add (&entry_builder, "{sv}", "vpn", diff --git a/src/dns/nm-dns-manager.h b/src/dns/nm-dns-manager.h index ee835927..b38ea701 100644 --- a/src/dns/nm-dns-manager.h +++ b/src/dns/nm-dns-manager.h @@ -44,8 +44,6 @@ typedef struct { char *iface; } NMDnsIPConfigData; -int nm_dns_ip_config_data_get_dns_priority (const NMDnsIPConfigData *config); - #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)) @@ -72,19 +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_add_ip4_config (NMDnsManager *self, - const char *iface, - NMIP4Config *config, - NMDnsIPConfigType cfg_type); - -gboolean nm_dns_manager_remove_ip4_config (NMDnsManager *self, NMIP4Config *config); - -gboolean nm_dns_manager_add_ip6_config (NMDnsManager *self, - const char *iface, - NMIP6Config *config, - NMDnsIPConfigType cfg_type); +gboolean nm_dns_manager_add_ip_config (NMDnsManager *self, + const char *iface, + gpointer config, + NMDnsIPConfigType cfg_type); -gboolean nm_dns_manager_remove_ip6_config (NMDnsManager *self, NMIP6Config *config); +gboolean nm_dns_manager_remove_ip_config (NMDnsManager *self, gpointer config); void nm_dns_manager_set_initial_hostname (NMDnsManager *self, const char *hostname); diff --git a/src/dns/nm-dns-systemd-resolved.c b/src/dns/nm-dns-systemd-resolved.c index 315f2c4d..6ab2ea18 100644 --- a/src/dns/nm-dns-systemd-resolved.c +++ b/src/dns/nm-dns-systemd-resolved.c @@ -289,14 +289,15 @@ update (NMDnsPlugin *plugin, int prio, first_prio = 0; for (i = 0; i < configs->len; i++) { + const NMDnsIPConfigData *data = configs->pdata[i]; gboolean skip = FALSE; - prio = nm_dns_ip_config_data_get_dns_priority (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) skip = TRUE; - add_interface_configuration (self, interfaces, configs->pdata[i], skip); + add_interface_configuration (self, interfaces, data, skip); } free_pending_updates (self); diff --git a/src/main-utils.c b/src/main-utils.c index c84f1e4c..0f790536 100644 --- a/src/main-utils.c +++ b/src/main-utils.c @@ -106,7 +106,7 @@ nm_main_utils_write_pidfile (const char *pidfile) else success = TRUE; - if (close (fd)) + if (nm_close (fd)) fprintf (stderr, _("Closing %s failed: %s\n"), pidfile, strerror (errno)); return success; diff --git a/src/nm-act-request.c b/src/nm-act-request.c index 6d8bb065..87070794 100644 --- a/src/nm-act-request.c +++ b/src/nm-act-request.c @@ -28,6 +28,8 @@ #include <sys/wait.h> #include <unistd.h> +#include "nm-utils/c-list.h" + #include "nm-setting-wireless-security.h" #include "nm-setting-8021x.h" #include "devices/nm-device.h" @@ -41,7 +43,7 @@ typedef struct { } ShareRule; typedef struct { - GSList *secrets_calls; + CList call_ids_lst_head; gboolean shared; GSList *share_rules; } NMActRequestPrivate; @@ -90,64 +92,52 @@ nm_act_request_get_applied_connection (NMActRequest *req) /*****************************************************************************/ struct _NMActRequestGetSecretsCallId { + CList call_ids_lst; NMActRequest *self; NMActRequestSecretsFunc callback; gpointer callback_data; - NMSettingsConnectionCallId call_id; + NMSettingsConnectionCallId *call_id; bool has_ref; }; -typedef struct _NMActRequestGetSecretsCallId GetSecretsInfo; - -static GetSecretsInfo * -_get_secrets_info_new (NMActRequest *self, gboolean ref_self, NMActRequestSecretsFunc callback, gpointer callback_data) -{ - GetSecretsInfo *info; - - info = g_slice_new0 (GetSecretsInfo); - info->has_ref = ref_self; - info->self = ref_self ? g_object_ref (self) : self; - info->callback = callback; - info->callback_data = callback_data; - - return info; -} - static void -_get_secrets_info_free (GetSecretsInfo *info) +_get_secrets_call_id_free (NMActRequestGetSecretsCallId *call_id) { - if (info->has_ref) - g_object_unref (info->self); - g_slice_free (GetSecretsInfo, info); + nm_assert (call_id); + nm_assert (!c_list_is_linked (&call_id->call_ids_lst)); + + if (call_id->has_ref) + g_object_unref (call_id->self); + g_slice_free (NMActRequestGetSecretsCallId, call_id); } static void get_secrets_cb (NMSettingsConnection *connection, - NMSettingsConnectionCallId call_id_s, + NMSettingsConnectionCallId *call_id_s, const char *agent_username, const char *setting_name, GError *error, gpointer user_data) { - GetSecretsInfo *info = user_data; + NMActRequestGetSecretsCallId *call_id = user_data; NMActRequestPrivate *priv; - g_return_if_fail (info && info->call_id == call_id_s); - g_return_if_fail (NM_IS_ACT_REQUEST (info->self)); + g_return_if_fail (call_id && call_id->call_id == call_id_s); + g_return_if_fail (NM_IS_ACT_REQUEST (call_id->self)); if (g_error_matches (error, G_IO_ERROR, G_IO_ERROR_CANCELLED)) return; - priv = NM_ACT_REQUEST_GET_PRIVATE (info->self); + priv = NM_ACT_REQUEST_GET_PRIVATE (call_id->self); - g_return_if_fail (g_slist_find (priv->secrets_calls, info)); + nm_assert (c_list_contains (&priv->call_ids_lst_head, &call_id->call_ids_lst)); - priv->secrets_calls = g_slist_remove (priv->secrets_calls, info); + c_list_unlink (&call_id->call_ids_lst); - if (info->callback) - info->callback (info->self, info, connection, error, info->callback_data); + if (call_id->callback) + call_id->callback (call_id->self, call_id, connection, error, call_id->callback_data); - _get_secrets_info_free (info); + _get_secrets_call_id_free (call_id); } /** @@ -171,7 +161,7 @@ get_secrets_cb (NMSettingsConnection *connection, * * Returns: a call-id. */ -NMActRequestGetSecretsCallId +NMActRequestGetSecretsCallId * nm_act_request_get_secrets (NMActRequest *self, gboolean ref_self, const char *setting_name, @@ -181,8 +171,8 @@ nm_act_request_get_secrets (NMActRequest *self, gpointer callback_data) { NMActRequestPrivate *priv; - GetSecretsInfo *info; - NMSettingsConnectionCallId call_id_s; + NMActRequestGetSecretsCallId *call_id; + NMSettingsConnectionCallId *call_id_s; NMSettingsConnection *settings_connection; NMConnection *applied_connection; const char *hints[2] = { hint, NULL }; @@ -194,9 +184,12 @@ nm_act_request_get_secrets (NMActRequest *self, settings_connection = nm_act_request_get_settings_connection (self); applied_connection = nm_act_request_get_applied_connection (self); - info = _get_secrets_info_new (self, ref_self, callback, callback_data); - - priv->secrets_calls = g_slist_append (priv->secrets_calls, info); + call_id = g_slice_new0 (NMActRequestGetSecretsCallId); + call_id->has_ref = ref_self; + call_id->self = ref_self ? g_object_ref (self) : self; + call_id->callback = callback; + call_id->callback_data = callback_data; + c_list_link_tail (&priv->call_ids_lst_head, &call_id->call_ids_lst); if (nm_active_connection_get_user_requested (NM_ACTIVE_CONNECTION (self))) flags |= NM_SECRET_AGENT_GET_SECRETS_FLAG_USER_REQUESTED; @@ -208,32 +201,32 @@ nm_act_request_get_secrets (NMActRequest *self, flags, hints, get_secrets_cb, - info); - info->call_id = call_id_s; + call_id); + call_id->call_id = call_id_s; g_return_val_if_fail (call_id_s, NULL); - return info; + return call_id; } static void -_do_cancel_secrets (NMActRequest *self, GetSecretsInfo *info, gboolean is_disposing) +_do_cancel_secrets (NMActRequest *self, NMActRequestGetSecretsCallId *call_id, gboolean is_disposing) { NMActRequestPrivate *priv = NM_ACT_REQUEST_GET_PRIVATE (self); - nm_assert (info && info->self == self); - nm_assert (g_slist_find (priv->secrets_calls, info)); + nm_assert (call_id && call_id->self == self); + nm_assert (c_list_contains (&priv->call_ids_lst_head, &call_id->call_ids_lst)); - priv->secrets_calls = g_slist_remove (priv->secrets_calls, info); + c_list_unlink (&call_id->call_ids_lst); - nm_settings_connection_cancel_secrets (nm_act_request_get_settings_connection (self), info->call_id); + nm_settings_connection_cancel_secrets (nm_act_request_get_settings_connection (self), call_id->call_id); - if (info->callback) { + if (call_id->callback) { gs_free_error GError *error = NULL; nm_utils_error_set_cancelled (&error, is_disposing, "NMActRequest"); - info->callback (self, info, NULL, error, info->callback_data); + call_id->callback (self, call_id, NULL, error, call_id->callback_data); } - _get_secrets_info_free (info); + _get_secrets_call_id_free (call_id); } /** @@ -247,7 +240,7 @@ _do_cancel_secrets (NMActRequest *self, GetSecretsInfo *info, gboolean is_dispos * synchronously. */ void -nm_act_request_cancel_secrets (NMActRequest *self, NMActRequestGetSecretsCallId call_id) +nm_act_request_cancel_secrets (NMActRequest *self, NMActRequestGetSecretsCallId *call_id) { NMActRequestPrivate *priv; @@ -264,7 +257,7 @@ nm_act_request_cancel_secrets (NMActRequest *self, NMActRequestGetSecretsCallId priv = NM_ACT_REQUEST_GET_PRIVATE (self); - if (!g_slist_find (priv->secrets_calls, call_id)) + if (!c_list_is_linked (&call_id->call_ids_lst)) g_return_if_reached (); _do_cancel_secrets (self, call_id, FALSE); @@ -461,10 +454,8 @@ device_state_changed (NMActiveConnection *active, } if ( ac_state == NM_ACTIVE_CONNECTION_STATE_DEACTIVATED - || ac_state == NM_ACTIVE_CONNECTION_STATE_UNKNOWN) { - nm_active_connection_set_default (active, FALSE); - nm_active_connection_set_default6 (active, FALSE); - } + || ac_state == NM_ACTIVE_CONNECTION_STATE_UNKNOWN) + nm_active_connection_set_default (active, AF_UNSPEC, FALSE); nm_active_connection_set_state (active, ac_state, ac_state_reason); } @@ -537,6 +528,9 @@ get_property (GObject *object, guint prop_id, static void nm_act_request_init (NMActRequest *req) { + NMActRequestPrivate *priv = NM_ACT_REQUEST_GET_PRIVATE (req); + + c_list_init (&priv->call_ids_lst_head); } /** @@ -582,10 +576,11 @@ dispose (GObject *object) { NMActRequest *self = NM_ACT_REQUEST (object); NMActRequestPrivate *priv = NM_ACT_REQUEST_GET_PRIVATE (self); + NMActRequestGetSecretsCallId *call_id, *call_id_safe; /* Kill any in-progress secrets requests */ - while (priv->secrets_calls) - _do_cancel_secrets (self, priv->secrets_calls->data, TRUE); + c_list_for_each_entry_safe (call_id, call_id_safe, &priv->call_ids_lst_head, call_ids_lst) + _do_cancel_secrets (self, call_id, TRUE); /* Clear any share rules */ if (priv->share_rules) { diff --git a/src/nm-act-request.h b/src/nm-act-request.h index b8549404..5d1c9dfd 100644 --- a/src/nm-act-request.h +++ b/src/nm-act-request.h @@ -32,7 +32,7 @@ #define NM_ACT_REQUEST_GET_CLASS(obj) (G_TYPE_INSTANCE_GET_CLASS ((obj), NM_TYPE_ACT_REQUEST, NMActRequestClass)) struct _NMActRequestGetSecretsCallId; -typedef struct _NMActRequestGetSecretsCallId *NMActRequestGetSecretsCallId; +typedef struct _NMActRequestGetSecretsCallId NMActRequestGetSecretsCallId; GType nm_act_request_get_type (void); @@ -58,20 +58,20 @@ void nm_act_request_add_share_rule (NMActRequest *req, /* Secrets handling */ typedef void (*NMActRequestSecretsFunc) (NMActRequest *req, - NMActRequestGetSecretsCallId call_id, + NMActRequestGetSecretsCallId *call_id, NMSettingsConnection *connection, GError *error, gpointer user_data); -NMActRequestGetSecretsCallId nm_act_request_get_secrets (NMActRequest *req, - gboolean take_ref, - const char *setting_name, - NMSecretAgentGetSecretsFlags flags, - const char *hint, - NMActRequestSecretsFunc callback, - gpointer callback_data); +NMActRequestGetSecretsCallId *nm_act_request_get_secrets (NMActRequest *req, + gboolean take_ref, + const char *setting_name, + NMSecretAgentGetSecretsFlags flags, + const char *hint, + NMActRequestSecretsFunc callback, + gpointer callback_data); -void nm_act_request_cancel_secrets (NMActRequest *req, NMActRequestGetSecretsCallId call_id); +void nm_act_request_cancel_secrets (NMActRequest *req, NMActRequestGetSecretsCallId *call_id); void nm_act_request_clear_secrets (NMActRequest *self); #endif /* __NM_ACT_REQUEST_H__ */ diff --git a/src/nm-active-connection.c b/src/nm-active-connection.c index 002f11f7..2286a74b 100644 --- a/src/nm-active-connection.c +++ b/src/nm-active-connection.c @@ -494,53 +494,46 @@ nm_active_connection_set_specific_object (NMActiveConnection *self, } void -nm_active_connection_set_default (NMActiveConnection *self, gboolean is_default) +nm_active_connection_set_default (NMActiveConnection *self, + int addr_family, + gboolean is_default) { NMActiveConnectionPrivate *priv; g_return_if_fail (NM_IS_ACTIVE_CONNECTION (self)); + nm_assert (NM_IN_SET (addr_family, AF_UNSPEC, AF_INET, AF_INET6)); is_default = !!is_default; priv = NM_ACTIVE_CONNECTION_GET_PRIVATE (self); - if (priv->is_default == is_default) - return; - - priv->is_default = is_default; - _notify (self, PROP_DEFAULT); + if (NM_IN_SET (addr_family, AF_UNSPEC, AF_INET)) { + if (priv->is_default != is_default) { + priv->is_default = is_default; + _notify (self, PROP_DEFAULT); + } + } + if (NM_IN_SET (addr_family, AF_UNSPEC, AF_INET6)) { + if (priv->is_default6 != is_default) { + priv->is_default6 = is_default; + _notify (self, PROP_DEFAULT6); + } + } } gboolean -nm_active_connection_get_default (NMActiveConnection *self) -{ - g_return_val_if_fail (NM_IS_ACTIVE_CONNECTION (self), FALSE); - - return NM_ACTIVE_CONNECTION_GET_PRIVATE (self)->is_default; -} - -void -nm_active_connection_set_default6 (NMActiveConnection *self, gboolean is_default6) +nm_active_connection_get_default (NMActiveConnection *self, int addr_family) { NMActiveConnectionPrivate *priv; - g_return_if_fail (NM_IS_ACTIVE_CONNECTION (self)); - - is_default6 = !!is_default6; - - priv = NM_ACTIVE_CONNECTION_GET_PRIVATE (self); - if (priv->is_default6 == is_default6) - return; - - priv->is_default6 = is_default6; - _notify (self, PROP_DEFAULT6); -} - -gboolean -nm_active_connection_get_default6 (NMActiveConnection *self) -{ g_return_val_if_fail (NM_IS_ACTIVE_CONNECTION (self), FALSE); + nm_assert (NM_IN_SET (addr_family, AF_UNSPEC, AF_INET, AF_INET6)); - return NM_ACTIVE_CONNECTION_GET_PRIVATE (self)->is_default6; + priv = NM_ACTIVE_CONNECTION_GET_PRIVATE (self); + switch (addr_family) { + case AF_INET: return priv->is_default; + case AF_INET6: return priv->is_default6; + default: return priv->is_default || priv->is_default6; + } } NMAuthSubject * @@ -873,7 +866,8 @@ _settings_connection_notify_flags (NMSettingsConnection *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 == settings_connection); - if (nm_settings_connection_get_nm_generated (settings_connection)) + if (NM_FLAGS_HAS (nm_settings_connection_get_flags (settings_connection), + NM_SETTINGS_CONNECTION_FLAGS_NM_GENERATED)) return; _set_activation_type_managed (self); @@ -1263,10 +1257,10 @@ set_property (GObject *object, guint prop_id, priv->specific_object = g_strdup (tmp); break; case PROP_DEFAULT: - priv->is_default = !!g_value_get_boolean (value); + priv->is_default = g_value_get_boolean (value); break; case PROP_DEFAULT6: - priv->is_default6 = !!g_value_get_boolean (value); + priv->is_default6 = g_value_get_boolean (value); break; case PROP_VPN: priv->vpn = g_value_get_boolean (value); @@ -1289,6 +1283,8 @@ nm_active_connection_init (NMActiveConnection *self) priv = G_TYPE_INSTANCE_GET_PRIVATE (self, NM_TYPE_ACTIVE_CONNECTION, NMActiveConnectionPrivate); self->_priv = priv; + c_list_init (&self->active_connections_lst); + _LOGT ("creating"); priv->activation_type = NM_ACTIVATION_TYPE_MANAGED; @@ -1331,6 +1327,8 @@ dispose (GObject *object) NMActiveConnection *self = NM_ACTIVE_CONNECTION (object); NMActiveConnectionPrivate *priv = NM_ACTIVE_CONNECTION_GET_PRIVATE (self); + nm_assert (!c_list_is_linked (&self->active_connections_lst)); + _LOGD ("disposing"); if (priv->chain) { diff --git a/src/nm-active-connection.h b/src/nm-active-connection.h index 5562b42f..5ede2b04 100644 --- a/src/nm-active-connection.h +++ b/src/nm-active-connection.h @@ -24,6 +24,8 @@ #include "nm-exported-object.h" #include "nm-connection.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)) #define NM_ACTIVE_CONNECTION_CLASS(klass) (G_TYPE_CHECK_CLASS_CAST ((klass), NM_TYPE_ACTIVE_CONNECTION, NMActiveConnectionClass)) @@ -71,6 +73,10 @@ struct _NMActiveConnectionPrivate; struct _NMActiveConnection { NMExportedObject parent; struct _NMActiveConnectionPrivate *_priv; + + /* active connection can be tracked in a list by NMManager. This is + * the list node. */ + CList active_connections_lst; }; typedef struct { @@ -131,14 +137,10 @@ void nm_active_connection_set_specific_object (NMActiveConnection *self const char *specific_object); void nm_active_connection_set_default (NMActiveConnection *self, + int addr_family, gboolean is_default); -gboolean nm_active_connection_get_default (NMActiveConnection *self); - -void nm_active_connection_set_default6 (NMActiveConnection *self, - gboolean is_default6); - -gboolean nm_active_connection_get_default6 (NMActiveConnection *self); +gboolean nm_active_connection_get_default (NMActiveConnection *self, int addr_family); NMActiveConnectionState nm_active_connection_get_state (NMActiveConnection *self); diff --git a/src/nm-checkpoint.c b/src/nm-checkpoint.c index c3a2e743..d606dee3 100644 --- a/src/nm-checkpoint.c +++ b/src/nm-checkpoint.c @@ -125,10 +125,10 @@ find_settings_connection (NMCheckpoint *self, gboolean *need_activation) { NMCheckpointPrivate *priv = NM_CHECKPOINT_GET_PRIVATE (self); - const GSList *active_connections, *iter; - NMActiveConnection *active = NULL; + NMActiveConnection *active; NMSettingsConnection *connection; const char *uuid, *ac_uuid; + const CList *tmp_clist; *need_activation = FALSE; *need_update = FALSE; @@ -149,9 +149,7 @@ find_settings_connection (NMCheckpoint *self, } /* ... is active, ... */ - active_connections = nm_manager_get_active_connections (priv->manager); - for (iter = active_connections; iter; iter = g_slist_next (iter)) { - active = iter->data; + nm_manager_for_each_active_connection (priv->manager, active, tmp_clist) { ac_uuid = nm_settings_connection_get_uuid (nm_active_connection_get_settings_connection (active)); if (nm_streq (uuid, ac_uuid)) { _LOGT ("rollback: connection %s is active", uuid); @@ -159,7 +157,7 @@ find_settings_connection (NMCheckpoint *self, } } - if (!iter) { + if (!active) { _LOGT ("rollback: connection %s is not active", uuid); *need_activation = TRUE; return connection; @@ -256,12 +254,12 @@ activate: if (need_update) { _LOGD ("rollback: updating connection %s", nm_settings_connection_get_uuid (connection)); - nm_connection_replace_settings_from_connection (NM_CONNECTION (connection), - dev_checkpoint->settings_connection); - nm_settings_connection_commit_changes (connection, - NULL, - NM_SETTINGS_CONNECTION_COMMIT_REASON_NONE, - NULL); + nm_settings_connection_update (connection, + dev_checkpoint->settings_connection, + NM_SETTINGS_CONNECTION_PERSIST_MODE_DISK, + NM_SETTINGS_CONNECTION_COMMIT_REASON_NONE, + "checkpoint-rollback", + NULL); } } else { /* The connection was deleted, recreate it */ @@ -335,7 +333,9 @@ next_dev: guint i; g_return_val_if_fail (priv->connection_uuids, NULL); - list = nm_settings_get_connections_sorted (nm_settings_get (), NULL); + list = nm_settings_get_connections_clone (nm_settings_get (), NULL, + NULL, NULL, + nm_settings_connection_cmp_autoconnect_priority_p_with_data, NULL); for (i = 0; list[i]; i++) { con = list[i]; diff --git a/src/nm-config-data.c b/src/nm-config-data.c index 5b06e00a..00e5c635 100644 --- a/src/nm-config-data.c +++ b/src/nm-config-data.c @@ -95,6 +95,8 @@ typedef struct { guint interval; } connectivity; + int autoconnect_retries_default; + struct { char **arr; GSList *specs; @@ -275,6 +277,14 @@ nm_config_data_get_connectivity_response (const NMConfigData *self) return NM_CONFIG_DATA_GET_PRIVATE (self)->connectivity.response; } +int +nm_config_data_get_autoconnect_retries_default (const NMConfigData *self) +{ + g_return_val_if_fail (self, FALSE); + + return NM_CONFIG_DATA_GET_PRIVATE (self)->autoconnect_retries_default; +} + const char *const* nm_config_data_get_no_auto_default (const NMConfigData *self) { @@ -1527,7 +1537,7 @@ constructed (GObject *object) { NMConfigData *self = NM_CONFIG_DATA (object); NMConfigDataPrivate *priv = NM_CONFIG_DATA_GET_PRIVATE (self); - char *interval; + char *str; priv->keyfile = _merge_keyfiles (priv->keyfile_user, priv->keyfile_intern); @@ -1538,13 +1548,15 @@ constructed (GObject *object) priv->connectivity.uri = nm_strstrip (g_key_file_get_string (priv->keyfile, NM_CONFIG_KEYFILE_GROUP_CONNECTIVITY, "uri", NULL)); priv->connectivity.response = g_key_file_get_string (priv->keyfile, NM_CONFIG_KEYFILE_GROUP_CONNECTIVITY, "response", NULL); + str = nm_config_keyfile_get_value (priv->keyfile, NM_CONFIG_KEYFILE_GROUP_MAIN, NM_CONFIG_KEYFILE_KEY_MAIN_AUTOCONNECT_RETRIES_DEFAULT, NM_CONFIG_GET_VALUE_NONE); + priv->autoconnect_retries_default = _nm_utils_ascii_str_to_int64 (str, 10, 0, G_MAXINT32, 4); + g_free (str); + /* On missing config value, fallback to 300. On invalid value, disable connectivity checking by setting * the interval to zero. */ - interval = g_key_file_get_string (priv->keyfile, NM_CONFIG_KEYFILE_GROUP_CONNECTIVITY, "interval", NULL); - priv->connectivity.interval = interval - ? _nm_utils_ascii_str_to_int64 (interval, 10, 0, G_MAXUINT, 0) - : NM_CONFIG_DEFAULT_CONNECTIVITY_INTERVAL; - g_free (interval); + str = g_key_file_get_string (priv->keyfile, NM_CONFIG_KEYFILE_GROUP_CONNECTIVITY, "interval", NULL); + priv->connectivity.interval = _nm_utils_ascii_str_to_int64 (str, 10, 0, G_MAXUINT, NM_CONFIG_DEFAULT_CONNECTIVITY_INTERVAL); + g_free (str); priv->dns_mode = nm_strstrip (g_key_file_get_string (priv->keyfile, NM_CONFIG_KEYFILE_GROUP_MAIN, "dns", NULL)); priv->rc_manager = nm_strstrip (g_key_file_get_string (priv->keyfile, NM_CONFIG_KEYFILE_GROUP_MAIN, "rc-manager", NULL)); diff --git a/src/nm-config-data.h b/src/nm-config-data.h index 3efe4259..3092a87f 100644 --- a/src/nm-config-data.h +++ b/src/nm-config-data.h @@ -165,6 +165,8 @@ const char *nm_config_data_get_connectivity_uri (const NMConfigData *config_data guint nm_config_data_get_connectivity_interval (const NMConfigData *config_data); const char *nm_config_data_get_connectivity_response (const NMConfigData *config_data); +int nm_config_data_get_autoconnect_retries_default (const NMConfigData *config_data); + const char *const*nm_config_data_get_no_auto_default (const NMConfigData *config_data); gboolean nm_config_data_get_no_auto_default_for_device (const NMConfigData *self, NMDevice *device); diff --git a/src/nm-config.h b/src/nm-config.h index 47e92988..8bdd5002 100644 --- a/src/nm-config.h +++ b/src/nm-config.h @@ -60,6 +60,7 @@ #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" #define NM_CONFIG_KEYFILE_KEY_MAIN_DHCP "dhcp" #define NM_CONFIG_KEYFILE_KEY_MAIN_DEBUG "debug" #define NM_CONFIG_KEYFILE_KEY_MAIN_HOSTNAME_MODE "hostname-mode" @@ -78,6 +79,7 @@ #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_CARRIER_WAIT_TIMEOUT "carrier-wait-timeout" #define NM_CONFIG_KEYFILE_KEYPREFIX_WAS ".was." #define NM_CONFIG_KEYFILE_KEYPREFIX_SET ".set." diff --git a/src/nm-core-utils.c b/src/nm-core-utils.c index a8ff3513..40a0c352 100644 --- a/src/nm-core-utils.c +++ b/src/nm-core-utils.c @@ -2835,13 +2835,13 @@ nm_utils_fd_get_contents (int fd, if (fd_keeper >= 0) fd2 = nm_steal_fd (&fd_keeper); else { - fd2 = dup (fd); + fd2 = fcntl (fd, F_DUPFD_CLOEXEC, 0); if (fd2 < 0) return _get_contents_error (error, 0, "error during dup"); } if (!(f = fdopen (fd2, "r"))) { - close (fd2); + nm_close (fd2); return _get_contents_error (error, 0, "failure during fdopen"); } @@ -4119,7 +4119,7 @@ nm_utils_file_set_contents (const gchar *filename, if (errsv == EINTR) continue; - close (fd); + nm_close (fd); unlink (tmp_name); g_set_error (error, @@ -4148,7 +4148,7 @@ nm_utils_file_set_contents (const gchar *filename, && fsync (fd) != 0) { errsv = errno; - close (fd); + nm_close (fd); unlink (tmp_name); g_set_error (error, @@ -4160,7 +4160,7 @@ nm_utils_file_set_contents (const gchar *filename, return FALSE; } - close (fd); + nm_close (fd); if (rename (tmp_name, filename)) { errsv = errno; diff --git a/src/nm-firewall-manager.c b/src/nm-firewall-manager.c index b9878592..216d5fc8 100644 --- a/src/nm-firewall-manager.c +++ b/src/nm-firewall-manager.c @@ -186,7 +186,7 @@ _cb_info_create (NMFirewallManager *self, static void _cb_info_free (CBInfo *info) { - c_list_unlink (&info->lst); + c_list_unlink_stale (&info->lst); if (info->mode != CB_INFO_MODE_IDLE) { if (info->dbus.arg) g_variant_unref (info->dbus.arg); @@ -213,7 +213,7 @@ _cb_info_complete_normal (CBInfo *info, GError *error) nm_assert (c_list_contains (&priv->pending_calls, &info->lst)); - c_list_unlink_init (&info->lst); + c_list_unlink (&info->lst); _cb_info_callback (info, error); _cb_info_free (info); @@ -428,7 +428,7 @@ nm_firewall_manager_cancel_call (NMFirewallManagerCallId call) nm_assert (c_list_contains (&priv->pending_calls, &info->lst)); - c_list_unlink_init (&info->lst); + c_list_unlink (&info->lst); nm_utils_error_set_cancelled (&error, FALSE, "NMFirewallManager"); @@ -527,7 +527,7 @@ again: _handle_dbus_start (self, info); } else { _LOGD (info, "complete: fake success"); - c_list_unlink_init (&info->lst); + c_list_unlink (&info->lst); _cb_info_callback (info, NULL); _cb_info_free (info); goto again; diff --git a/src/nm-ip4-config.c b/src/nm-ip4-config.c index e2f99e24..15157739 100644 --- a/src/nm-ip4-config.c +++ b/src/nm-ip4-config.c @@ -15,7 +15,7 @@ * with this program; if not, write to the Free Software Foundation, Inc., * 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA. * - * Copyright (C) 2005 - 2014 Red Hat, Inc. + * Copyright (C) 2005 - 2017 Red Hat, Inc. * Copyright (C) 2006 - 2008 Novell, Inc. */ @@ -600,9 +600,9 @@ nm_ip4_config_capture (NMDedupMultiIndex *multi_idx, NMPlatform *platform, int i self = nm_ip4_config_new (multi_idx, ifindex); priv = NM_IP4_CONFIG_GET_PRIVATE (self); - head_entry = nm_platform_lookup_addrroute (platform, - NMP_OBJECT_TYPE_IP4_ADDRESS, - ifindex); + head_entry = nm_platform_lookup_object (platform, + NMP_OBJECT_TYPE_IP4_ADDRESS, + ifindex); if (head_entry) { nmp_cache_iter_for_each (&iter, head_entry, &plobj) { if (!_nm_ip_config_add_obj (priv->multi_idx, @@ -625,9 +625,9 @@ nm_ip4_config_capture (NMDedupMultiIndex *multi_idx, NMPlatform *platform, int i _notify_addresses (self); } - head_entry = nm_platform_lookup_addrroute (platform, - NMP_OBJECT_TYPE_IP4_ROUTE, - ifindex); + head_entry = nm_platform_lookup_object (platform, + NMP_OBJECT_TYPE_IP4_ROUTE, + ifindex); /* Extract gateway from default route */ nmp_cache_iter_for_each (&iter, head_entry, &plobj) @@ -806,44 +806,87 @@ nm_ip4_config_commit (const NMIP4Config *self, return success; } -static void -merge_route_attributes (NMIPRoute *s_route, - NMPlatformIP4Route *r, - guint32 route_table) +void +_nm_ip_config_merge_route_attributes (int addr_family, + NMIPRoute *s_route, + NMPlatformIPRoute *r, + guint32 route_table) { GVariant *variant; - guint32 u32; - in_addr_t addr; - -#define GET_ATTR(name, field, variant_type, type) \ - variant = nm_ip_route_get_attribute (s_route, name); \ - if (variant && g_variant_is_of_type (variant, G_VARIANT_TYPE_ ## variant_type)) \ - r->field = g_variant_get_ ## type (variant); - - variant = nm_ip_route_get_attribute (s_route, NM_IP_ROUTE_ATTRIBUTE_TABLE); - u32 = variant && g_variant_is_of_type (variant, G_VARIANT_TYPE_UINT32) - ? g_variant_get_uint32 (variant) - : 0; - r->table_coerced = nm_platform_route_table_coerce (u32 ?: (route_table ?: RT_TABLE_MAIN)); - - GET_ATTR (NM_IP_ROUTE_ATTRIBUTE_TOS, tos, BYTE, byte); - GET_ATTR (NM_IP_ROUTE_ATTRIBUTE_WINDOW, window, UINT32, uint32); - GET_ATTR (NM_IP_ROUTE_ATTRIBUTE_CWND, cwnd, UINT32, uint32); - GET_ATTR (NM_IP_ROUTE_ATTRIBUTE_INITCWND, initcwnd, UINT32, uint32); - GET_ATTR (NM_IP_ROUTE_ATTRIBUTE_INITRWND, initrwnd, UINT32, uint32); - GET_ATTR (NM_IP_ROUTE_ATTRIBUTE_MTU, mtu, UINT32, uint32); - GET_ATTR (NM_IP_ROUTE_ATTRIBUTE_LOCK_WINDOW, lock_window, BOOLEAN, boolean); - GET_ATTR (NM_IP_ROUTE_ATTRIBUTE_LOCK_CWND, lock_cwnd, BOOLEAN, boolean); - GET_ATTR (NM_IP_ROUTE_ATTRIBUTE_LOCK_INITCWND, lock_initcwnd, BOOLEAN, boolean); - GET_ATTR (NM_IP_ROUTE_ATTRIBUTE_LOCK_INITRWND, lock_initrwnd, BOOLEAN, boolean); - GET_ATTR (NM_IP_ROUTE_ATTRIBUTE_LOCK_MTU, lock_mtu, BOOLEAN, boolean); + guint32 table; + NMIPAddr addr; + NMPlatformIP4Route *r4 = (NMPlatformIP4Route *) r; + NMPlatformIP6Route *r6 = (NMPlatformIP6Route *) r; + gboolean onlink; + + nm_assert (s_route); + nm_assert_addr_family (addr_family); + nm_assert (r); + +#define GET_ATTR(name, dst, variant_type, type, dflt) \ + G_STMT_START { \ + GVariant *_variant = nm_ip_route_get_attribute (s_route, ""name""); \ + \ + if ( _variant \ + && g_variant_is_of_type (_variant, G_VARIANT_TYPE_ ## variant_type)) \ + (dst) = g_variant_get_ ## type (_variant); \ + else \ + (dst) = (dflt); \ + } G_STMT_END + + GET_ATTR (NM_IP_ROUTE_ATTRIBUTE_TABLE, table, UINT32, uint32, 0); + r->table_coerced = nm_platform_route_table_coerce (table ?: (route_table ?: RT_TABLE_MAIN)); + + if (addr_family == AF_INET) { + GET_ATTR (NM_IP_ROUTE_ATTRIBUTE_TOS, r4->tos, BYTE, byte, 0); + GET_ATTR (NM_IP_ROUTE_ATTRIBUTE_ONLINK, onlink, BOOLEAN, boolean, FALSE); + } else + onlink = FALSE; + + r->r_rtm_flags = 0; + if (onlink) + r->r_rtm_flags = RTNH_F_ONLINK; + + GET_ATTR (NM_IP_ROUTE_ATTRIBUTE_WINDOW, r->window, UINT32, uint32, 0); + GET_ATTR (NM_IP_ROUTE_ATTRIBUTE_CWND, r->cwnd, UINT32, uint32, 0); + GET_ATTR (NM_IP_ROUTE_ATTRIBUTE_INITCWND, r->initcwnd, UINT32, uint32, 0); + GET_ATTR (NM_IP_ROUTE_ATTRIBUTE_INITRWND, r->initrwnd, UINT32, uint32, 0); + GET_ATTR (NM_IP_ROUTE_ATTRIBUTE_MTU, r->mtu, UINT32, uint32, 0); + GET_ATTR (NM_IP_ROUTE_ATTRIBUTE_LOCK_WINDOW, r->lock_window, BOOLEAN, boolean, FALSE); + GET_ATTR (NM_IP_ROUTE_ATTRIBUTE_LOCK_CWND, r->lock_cwnd, BOOLEAN, boolean, FALSE); + GET_ATTR (NM_IP_ROUTE_ATTRIBUTE_LOCK_INITCWND, r->lock_initcwnd, BOOLEAN, boolean, FALSE); + GET_ATTR (NM_IP_ROUTE_ATTRIBUTE_LOCK_INITRWND, r->lock_initrwnd, BOOLEAN, boolean, FALSE); + GET_ATTR (NM_IP_ROUTE_ATTRIBUTE_LOCK_MTU, r->lock_mtu, BOOLEAN, boolean, FALSE); if ( (variant = nm_ip_route_get_attribute (s_route, NM_IP_ROUTE_ATTRIBUTE_SRC)) && g_variant_is_of_type (variant, G_VARIANT_TYPE_STRING)) { - if (inet_pton (AF_INET, g_variant_get_string (variant, NULL), &addr) == 1) - r->pref_src = addr; + if (inet_pton (addr_family, g_variant_get_string (variant, NULL), &addr) == 1) { + if (addr_family == AF_INET) + r4->pref_src = addr.addr4; + else + r6->pref_src = addr.addr6; + } } + if ( addr_family == AF_INET6 + && (variant = nm_ip_route_get_attribute (s_route, NM_IP_ROUTE_ATTRIBUTE_FROM)) + && g_variant_is_of_type (variant, G_VARIANT_TYPE_STRING)) { + gs_free char *string = NULL; + guint8 plen = 128; + char *sep; + + string = g_variant_dup_string (variant, NULL); + sep = strchr (string, '/'); + if (sep) { + *sep = 0; + plen = _nm_utils_ascii_str_to_int64 (sep + 1, 10, 1, 128, 255); + } + if ( plen <= 128 + && inet_pton (AF_INET6, string, &addr) == 1) { + r6->src = addr.addr6; + r6->src_plen = plen; + } + } #undef GET_ATTR } @@ -911,8 +954,6 @@ nm_ip4_config_merge_setting (NMIP4Config *self, } /* Routes */ - if (nm_setting_ip_config_get_ignore_auto_routes (setting)) - nm_ip4_config_reset_routes (self); for (i = 0; i < nroutes; i++) { NMIPRoute *s_route = nm_setting_ip_config_get_route (setting, i); NMPlatformIP4Route route; @@ -939,7 +980,10 @@ nm_ip4_config_merge_setting (NMIP4Config *self, route.network = nm_utils_ip4_address_clear_host_address (route.network, route.plen); - merge_route_attributes (s_route, &route, route_table); + _nm_ip_config_merge_route_attributes (AF_INET, + s_route, + NM_PLATFORM_IP_ROUTE_CAST (&route), + route_table); _add_route (self, NULL, &route, NULL); } @@ -2216,6 +2260,14 @@ nm_ip4_config_get_nameserver (const NMIP4Config *self, guint i) return g_array_index (priv->nameservers, guint32, i); } +const in_addr_t * +_nm_ip4_config_get_nameserver (const NMIP4Config *self, guint i) +{ + const NMIP4ConfigPrivate *priv = NM_IP4_CONFIG_GET_PRIVATE (self); + + return &g_array_index (priv->nameservers, guint32, i); +} + /*****************************************************************************/ void diff --git a/src/nm-ip4-config.h b/src/nm-ip4-config.h index 978471df..7c345d20 100644 --- a/src/nm-ip4-config.h +++ b/src/nm-ip4-config.h @@ -113,6 +113,11 @@ const NMDedupMultiEntry *_nm_ip_config_lookup_ip_route (const NMDedupMultiIndex const NMPObject *needle, NMPlatformIPRouteCmpType cmp_type); +void _nm_ip_config_merge_route_attributes (int addr_family, + NMIPRoute *s_route, + NMPlatformIPRoute *r, + guint32 route_table); + /*****************************************************************************/ #define NM_TYPE_IP4_CONFIG (nm_ip4_config_get_type ()) @@ -216,6 +221,7 @@ void nm_ip4_config_add_nameserver (NMIP4Config *self, guint32 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); +const in_addr_t *_nm_ip4_config_get_nameserver (const NMIP4Config *self, guint i); void nm_ip4_config_reset_domains (NMIP4Config *self); void nm_ip4_config_add_domain (NMIP4Config *self, const char *domain); @@ -267,4 +273,135 @@ gboolean nm_ip4_config_nmpobj_remove (NMIP4Config *self, void nm_ip4_config_hash (const NMIP4Config *self, GChecksum *sum, gboolean dns_only); gboolean nm_ip4_config_equal (const NMIP4Config *a, const NMIP4Config *b); +/*****************************************************************************/ + +#include "nm-ip6-config.h" + +static inline gboolean +NM_IS_IP_CONFIG (gconstpointer config) +{ + return NM_IS_IP4_CONFIG (config) || NM_IS_IP6_CONFIG (config); +} + +#if _NM_CC_SUPPORT_GENERIC +/* _NM_IS_IP_CONFIG() is a bit unusual. If _Generic() is supported, + * it checks whether @config is either NM_IS_IP4_CONFIG() or NM_IS_IP6_CONFIG(), + * depending on the pointer type of @config. + * + * For example, with _Generic() support, the following assertions would fail: + * NMIP6Config *ptr = (NMIP6Config *) nm_ip4_config_new(...); + * g_assert (_NM_IS_IP_CONFIG (ptr, ptr)); + * but the following would pass: + * NMIP4Config *ptr = nm_ip4_config_new(...); + * g_assert (_NM_IS_IP_CONFIG (ptr, ptr)); + */ +#define _NM_IS_IP_CONFIG(typeexpr, config) \ + ({ \ + const void *const _config = (config); \ + _Generic ((typeexpr), \ + const void *const: (NM_IS_IP4_CONFIG (_config) || NM_IS_IP6_CONFIG (_config)), \ + const void * : (NM_IS_IP4_CONFIG (_config) || NM_IS_IP6_CONFIG (_config)), \ + void *const: (NM_IS_IP4_CONFIG (_config) || NM_IS_IP6_CONFIG (_config)), \ + void * : (NM_IS_IP4_CONFIG (_config) || NM_IS_IP6_CONFIG (_config)), \ + const NMIPConfig *const: (NM_IS_IP4_CONFIG (_config) || NM_IS_IP6_CONFIG (_config)), \ + const NMIPConfig * : (NM_IS_IP4_CONFIG (_config) || NM_IS_IP6_CONFIG (_config)), \ + NMIPConfig *const: (NM_IS_IP4_CONFIG (_config) || NM_IS_IP6_CONFIG (_config)), \ + NMIPConfig * : (NM_IS_IP4_CONFIG (_config) || NM_IS_IP6_CONFIG (_config)), \ + const NMIP4Config *const: (NM_IS_IP4_CONFIG (_config)), \ + const NMIP4Config * : (NM_IS_IP4_CONFIG (_config)), \ + NMIP4Config *const: (NM_IS_IP4_CONFIG (_config)), \ + NMIP4Config * : (NM_IS_IP4_CONFIG (_config)), \ + const NMIP6Config *const: (NM_IS_IP6_CONFIG (_config)), \ + const NMIP6Config * : (NM_IS_IP6_CONFIG (_config)), \ + NMIP6Config *const: (NM_IS_IP6_CONFIG (_config)), \ + NMIP6Config * : (NM_IS_IP6_CONFIG (_config))); \ + }) +#else +#define _NM_IS_IP_CONFIG(typeexpr, config) NM_IS_IP_CONFIG(config) +#endif + +#define NM_IP_CONFIG_CAST(config) \ + ({ \ + const void *const _configx = (config); \ + \ + nm_assert (!_configx || _NM_IS_IP_CONFIG ((config), _configx)); \ + NM_CONSTCAST_FULL (NMIPConfig, (config), _configx, NMIP4Config, NMIP6Config); \ + }) + +static inline int +nm_ip_config_get_addr_family (const NMIPConfig *config) +{ + if (NM_IS_IP4_CONFIG (config)) + return AF_INET; + if (NM_IS_IP6_CONFIG (config)) + return AF_INET6; + g_return_val_if_reached (AF_UNSPEC); +} + +#define _NM_IP_CONFIG_DISPATCH(config, v4_func, v6_func, dflt, ...) \ + G_STMT_START { \ + gconstpointer _config = (config); \ + \ + if (NM_IS_IP4_CONFIG (_config)) { \ + return v4_func ((NMIP4Config *) _config, ##__VA_ARGS__); \ + } else { \ + nm_assert (NM_IS_IP6_CONFIG (_config)); \ + return v6_func ((NMIP6Config *) _config, ##__VA_ARGS__); \ + } \ + } G_STMT_END + +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, 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, 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, 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, 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, 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, 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, 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, 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, NULL, i); +} + #endif /* __NETWORKMANAGER_IP4_CONFIG_H__ */ diff --git a/src/nm-ip6-config.c b/src/nm-ip6-config.c index 3f0bbfe7..ea3a2029 100644 --- a/src/nm-ip6-config.c +++ b/src/nm-ip6-config.c @@ -15,7 +15,7 @@ * with this program; if not, write to the Free Software Foundation, Inc., * 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA. * - * Copyright (C) 2005 - 2013 Red Hat, Inc. + * Copyright (C) 2005 - 2017 Red Hat, Inc. * Copyright (C) 2006 - 2008 Novell, Inc. */ @@ -384,9 +384,9 @@ nm_ip6_config_capture (NMDedupMultiIndex *multi_idx, NMPlatform *platform, int i self = nm_ip6_config_new (multi_idx, ifindex); priv = NM_IP6_CONFIG_GET_PRIVATE (self); - head_entry = nm_platform_lookup_addrroute (platform, - NMP_OBJECT_TYPE_IP6_ADDRESS, - ifindex); + head_entry = nm_platform_lookup_object (platform, + NMP_OBJECT_TYPE_IP6_ADDRESS, + ifindex); if (head_entry) { nmp_cache_iter_for_each (&iter, head_entry, &plobj) { if (!_nm_ip_config_add_obj (priv->multi_idx, @@ -409,9 +409,9 @@ nm_ip6_config_capture (NMDedupMultiIndex *multi_idx, NMPlatform *platform, int i _notify_addresses (self); } - head_entry = nm_platform_lookup_addrroute (platform, - NMP_OBJECT_TYPE_IP6_ROUTE, - ifindex); + head_entry = nm_platform_lookup_object (platform, + NMP_OBJECT_TYPE_IP6_ROUTE, + ifindex); nmp_cache_iter_for_each (&iter, head_entry, &plobj) _add_route (self, plobj, NULL, NULL); @@ -571,65 +571,6 @@ nm_ip6_config_commit (const NMIP6Config *self, return success; } -static void -merge_route_attributes (NMIPRoute *s_route, - NMPlatformIP6Route *r, - guint32 route_table) -{ - GVariant *variant; - guint32 u32; - struct in6_addr addr; - -#define GET_ATTR(name, field, variant_type, type) \ - variant = nm_ip_route_get_attribute (s_route, name); \ - if (variant && g_variant_is_of_type (variant, G_VARIANT_TYPE_ ## variant_type)) \ - r->field = g_variant_get_ ## type (variant); - - variant = nm_ip_route_get_attribute (s_route, NM_IP_ROUTE_ATTRIBUTE_TABLE); - u32 = variant && g_variant_is_of_type (variant, G_VARIANT_TYPE_UINT32) - ? g_variant_get_uint32 (variant) - : 0; - r->table_coerced = nm_platform_route_table_coerce (u32 ?: (route_table ?: RT_TABLE_MAIN)); - - GET_ATTR (NM_IP_ROUTE_ATTRIBUTE_WINDOW, window, UINT32, uint32); - GET_ATTR (NM_IP_ROUTE_ATTRIBUTE_CWND, cwnd, UINT32, uint32); - GET_ATTR (NM_IP_ROUTE_ATTRIBUTE_INITCWND, initcwnd, UINT32, uint32); - GET_ATTR (NM_IP_ROUTE_ATTRIBUTE_INITRWND, initrwnd, UINT32, uint32); - GET_ATTR (NM_IP_ROUTE_ATTRIBUTE_MTU, mtu, UINT32, uint32); - GET_ATTR (NM_IP_ROUTE_ATTRIBUTE_LOCK_WINDOW, lock_window, BOOLEAN, boolean); - GET_ATTR (NM_IP_ROUTE_ATTRIBUTE_LOCK_CWND, lock_cwnd, BOOLEAN, boolean); - GET_ATTR (NM_IP_ROUTE_ATTRIBUTE_LOCK_INITCWND, lock_initcwnd, BOOLEAN, boolean); - GET_ATTR (NM_IP_ROUTE_ATTRIBUTE_LOCK_INITRWND, lock_initrwnd, BOOLEAN, boolean); - GET_ATTR (NM_IP_ROUTE_ATTRIBUTE_LOCK_MTU, lock_mtu, BOOLEAN, boolean); - - - if ( (variant = nm_ip_route_get_attribute (s_route, NM_IP_ROUTE_ATTRIBUTE_SRC)) - && g_variant_is_of_type (variant, G_VARIANT_TYPE_STRING)) { - if (inet_pton (AF_INET6, g_variant_get_string (variant, NULL), &addr) == 1) - r->pref_src = addr; - } - - if ( (variant = nm_ip_route_get_attribute (s_route, NM_IP_ROUTE_ATTRIBUTE_FROM)) - && g_variant_is_of_type (variant, G_VARIANT_TYPE_STRING)) { - gs_free char *string = NULL; - guint8 plen = 128; - char *sep; - - string = g_variant_dup_string (variant, NULL); - sep = strchr (string, '/'); - if (sep) { - *sep = 0; - plen = _nm_utils_ascii_str_to_int64 (sep + 1, 10, 1, 128, 255); - } - if ( plen <= 128 - && inet_pton (AF_INET6, string, &addr) == 1) { - r->src = addr; - r->src_plen = plen; - } - } -#undef GET_ATTR -} - void nm_ip6_config_merge_setting (NMIP6Config *self, NMSettingIPConfig *setting, @@ -688,8 +629,6 @@ nm_ip6_config_merge_setting (NMIP6Config *self, } /* Routes */ - if (nm_setting_ip_config_get_ignore_auto_routes (setting)) - nm_ip6_config_reset_routes (self); for (i = 0; i < nroutes; i++) { NMIPRoute *s_route = nm_setting_ip_config_get_route (setting, i); NMPlatformIP6Route route; @@ -716,7 +655,10 @@ nm_ip6_config_merge_setting (NMIP6Config *self, nm_utils_ip6_address_clear_host_address (&route.network, &route.network, route.plen); - merge_route_attributes (s_route, &route, route_table); + _nm_ip_config_merge_route_attributes (AF_INET, + s_route, + NM_PLATFORM_IP_ROUTE_CAST (&route), + route_table); _add_route (self, NULL, &route, NULL); } diff --git a/src/nm-manager.c b/src/nm-manager.c index 2766e86a..7f1b9a9d 100644 --- a/src/nm-manager.c +++ b/src/nm-manager.c @@ -62,41 +62,7 @@ #include "introspection/org.freedesktop.NetworkManager.h" #include "introspection/org.freedesktop.NetworkManager.Device.h" -static gboolean add_device (NMManager *self, NMDevice *device, GError **error); - -static NMActiveConnection *_new_active_connection (NMManager *self, - NMConnection *connection, - NMConnection *applied, - const char *specific_object, - NMDevice *device, - NMAuthSubject *subject, - NMActivationType activation_type, - GError **error); - -static void policy_activating_device_changed (GObject *object, GParamSpec *pspec, gpointer user_data); - -static gboolean find_master (NMManager *self, - NMConnection *connection, - NMDevice *device, - NMSettingsConnection **out_master_connection, - NMDevice **out_master_device, - NMActiveConnection **out_master_ac, - GError **error); - -static void nm_manager_update_state (NMManager *manager); - -static void connection_changed (NMManager *self, NMConnection *connection); -static void device_sleep_cb (NMDevice *device, - GParamSpec *pspec, - NMManager *self); - -static void settings_startup_complete_changed (NMSettings *settings, - GParamSpec *pspec, - NMManager *self); - -static void retry_connections_for_parent_device (NMManager *self, NMDevice *device); - -static NM_CACHED_QUARK_FCN ("active-connection-add-and-activate", active_connection_add_and_activate_quark) +/*****************************************************************************/ typedef struct { gboolean user_enabled; @@ -109,12 +75,56 @@ typedef struct { const char *hw_prop; } RadioState; +enum { + DEVICE_ADDED, + INTERNAL_DEVICE_ADDED, + DEVICE_REMOVED, + INTERNAL_DEVICE_REMOVED, + STATE_CHANGED, + CHECK_PERMISSIONS, + ACTIVE_CONNECTION_ADDED, + ACTIVE_CONNECTION_REMOVED, + CONFIGURE_QUIT, + + LAST_SIGNAL +}; + +static guint signals[LAST_SIGNAL] = { 0 }; + +NM_GOBJECT_PROPERTIES_DEFINE (NMManager, + PROP_VERSION, + PROP_CAPABILITIES, + PROP_STATE, + PROP_STARTUP, + PROP_NETWORKING_ENABLED, + PROP_WIRELESS_ENABLED, + PROP_WIRELESS_HARDWARE_ENABLED, + PROP_WWAN_ENABLED, + PROP_WWAN_HARDWARE_ENABLED, + PROP_WIMAX_ENABLED, + PROP_WIMAX_HARDWARE_ENABLED, + PROP_ACTIVE_CONNECTIONS, + PROP_CONNECTIVITY, + PROP_CONNECTIVITY_CHECK_AVAILABLE, + PROP_CONNECTIVITY_CHECK_ENABLED, + PROP_PRIMARY_CONNECTION, + PROP_PRIMARY_CONNECTION_TYPE, + PROP_ACTIVATING_CONNECTION, + PROP_DEVICES, + PROP_METERED, + PROP_GLOBAL_DNS_CONFIGURATION, + PROP_ALL_DEVICES, + + /* Not exported */ + PROP_SLEEPING, +); + typedef struct { NMPlatform *platform; GArray *capabilities; - GSList *active_connections; + CList active_connections_lst_head; GSList *authorizing_connections; guint ac_cleanup_id; NMActiveConnection *primary_connection; @@ -166,6 +176,9 @@ typedef struct { bool sleeping:1; bool net_enabled:1; + + guint delete_volatile_connection_idle_id; + CList delete_volatile_connection_lst_head; } NMManagerPrivate; struct _NMManager { @@ -181,49 +194,7 @@ G_DEFINE_TYPE (NMManager, nm_manager, NM_TYPE_EXPORTED_OBJECT) #define NM_MANAGER_GET_PRIVATE(self) _NM_GET_PRIVATE(self, NMManager, NM_IS_MANAGER) -enum { - DEVICE_ADDED, - INTERNAL_DEVICE_ADDED, - DEVICE_REMOVED, - INTERNAL_DEVICE_REMOVED, - STATE_CHANGED, - CHECK_PERMISSIONS, - ACTIVE_CONNECTION_ADDED, - ACTIVE_CONNECTION_REMOVED, - CONFIGURE_QUIT, - - LAST_SIGNAL -}; - -static guint signals[LAST_SIGNAL] = { 0 }; - -NM_GOBJECT_PROPERTIES_DEFINE (NMManager, - PROP_VERSION, - PROP_CAPABILITIES, - PROP_STATE, - PROP_STARTUP, - PROP_NETWORKING_ENABLED, - PROP_WIRELESS_ENABLED, - PROP_WIRELESS_HARDWARE_ENABLED, - PROP_WWAN_ENABLED, - PROP_WWAN_HARDWARE_ENABLED, - PROP_WIMAX_ENABLED, - PROP_WIMAX_HARDWARE_ENABLED, - PROP_ACTIVE_CONNECTIONS, - PROP_CONNECTIVITY, - PROP_CONNECTIVITY_CHECK_AVAILABLE, - PROP_CONNECTIVITY_CHECK_ENABLED, - PROP_PRIMARY_CONNECTION, - PROP_PRIMARY_CONNECTION_TYPE, - PROP_ACTIVATING_CONNECTION, - PROP_DEVICES, - PROP_METERED, - PROP_GLOBAL_DNS_CONFIGURATION, - PROP_ALL_DEVICES, - - /* Not exported */ - PROP_SLEEPING, -); +/*****************************************************************************/ NM_DEFINE_SINGLETON_INSTANCE (NMManager); @@ -296,7 +267,39 @@ NM_DEFINE_SINGLETON_INSTANCE (NMManager); /*****************************************************************************/ -static NM_CACHED_QUARK_FCN ("autoconnect-root", autoconnect_root_quark) +static gboolean add_device (NMManager *self, NMDevice *device, GError **error); + +static NMActiveConnection *_new_active_connection (NMManager *self, + NMConnection *connection, + NMConnection *applied, + const char *specific_object, + NMDevice *device, + NMAuthSubject *subject, + NMActivationType activation_type, + GError **error); + +static void policy_activating_device_changed (GObject *object, GParamSpec *pspec, gpointer user_data); + +static gboolean find_master (NMManager *self, + NMConnection *connection, + NMDevice *device, + NMSettingsConnection **out_master_connection, + NMDevice **out_master_device, + NMActiveConnection **out_master_ac, + GError **error); + +static void nm_manager_update_state (NMManager *manager); + +static void connection_changed (NMManager *self, NMConnection *connection); +static void device_sleep_cb (NMDevice *device, + GParamSpec *pspec, + NMManager *self); + +static void settings_startup_complete_changed (NMSettings *settings, + GParamSpec *pspec, + NMManager *self); + +static void retry_connections_for_parent_device (NMManager *self, NMDevice *device); static void active_connection_state_changed (NMActiveConnection *active, GParamSpec *pspec, @@ -308,44 +311,68 @@ static void active_connection_parent_active (NMActiveConnection *active, NMActiveConnection *parent_ac, NMManager *self); +static NMActiveConnection *active_connection_find_first (NMManager *self, + NMSettingsConnection *settings_connection, + const char *uuid, + NMActiveConnectionState max_state); + +/*****************************************************************************/ + +static NM_CACHED_QUARK_FCN ("active-connection-add-and-activate", active_connection_add_and_activate_quark) + +static NM_CACHED_QUARK_FCN ("autoconnect-root", autoconnect_root_quark) + +/*****************************************************************************/ + +static void +_delete_volatile_connection_do (NMManager *self, + NMSettingsConnection *connection) +{ + NMManagerPrivate *priv = NM_MANAGER_GET_PRIVATE (self); + + if (!NM_FLAGS_HAS (nm_settings_connection_get_flags (connection), + NM_SETTINGS_CONNECTION_FLAGS_VOLATILE)) + return; + if (active_connection_find_first (self, + connection, + NULL, + NM_ACTIVE_CONNECTION_STATE_DEACTIVATED)) + return; + if (!nm_settings_has_connection (priv->settings, connection)) + return; + + _LOGD (LOGD_DEVICE, "volatile connection disconnected. Deleting connection '%s' (%s)", + nm_settings_connection_get_id (connection), nm_settings_connection_get_uuid (connection)); + nm_settings_connection_delete (connection, NULL); +} + /* Returns: whether to notify D-Bus of the removal or not */ static gboolean active_connection_remove (NMManager *self, NMActiveConnection *active) { NMManagerPrivate *priv = NM_MANAGER_GET_PRIVATE (self); - gboolean notify = nm_exported_object_is_exported (NM_EXPORTED_OBJECT (active)); - GSList *found; - - /* FIXME: switch to a GList for faster removal */ - found = g_slist_find (priv->active_connections, active); - if (found) { - NMSettingsConnection *connection; - - priv->active_connections = g_slist_remove (priv->active_connections, active); - g_signal_emit (self, signals[ACTIVE_CONNECTION_REMOVED], 0, active); - g_signal_handlers_disconnect_by_func (active, active_connection_state_changed, self); - g_signal_handlers_disconnect_by_func (active, active_connection_default_changed, self); - g_signal_handlers_disconnect_by_func (active, active_connection_parent_active, self); - - if ( (connection = nm_active_connection_get_settings_connection (active)) - && nm_settings_connection_get_volatile (connection)) - g_object_ref (connection); - else - connection = NULL; + gs_unref_object NMSettingsConnection *connection = NULL; + gboolean notify; - nm_exported_object_clear_and_unexport (&active); + nm_assert (NM_IS_ACTIVE_CONNECTION (active)); + nm_assert (c_list_contains (&priv->active_connections_lst_head, &active->active_connections_lst)); - if (connection) { - if (nm_settings_has_connection (priv->settings, connection)) { - _LOGD (LOGD_DEVICE, "assumed connection disconnected. Deleting generated connection '%s' (%s)", - nm_settings_connection_get_id (connection), nm_settings_connection_get_uuid (connection)); - nm_settings_connection_delete (connection, NULL); - } - g_object_unref (connection); - } - } + 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); + g_signal_handlers_disconnect_by_func (active, active_connection_state_changed, self); + g_signal_handlers_disconnect_by_func (active, active_connection_default_changed, self); + g_signal_handlers_disconnect_by_func (active, active_connection_parent_active, self); + + connection = nm_g_object_ref (nm_active_connection_get_settings_connection (active)); + + nm_exported_object_clear_and_unexport (&active); - return found && notify; + if (connection) + _delete_volatile_connection_do (self, connection); + + return notify; } static gboolean @@ -353,16 +380,12 @@ _active_connection_cleanup (gpointer user_data) { NMManager *self = NM_MANAGER (user_data); NMManagerPrivate *priv = NM_MANAGER_GET_PRIVATE (self); - GSList *iter; + NMActiveConnection *ac, *ac_safe; priv->ac_cleanup_id = 0; g_object_freeze_notify (G_OBJECT (self)); - iter = priv->active_connections; - while (iter) { - NMActiveConnection *ac = iter->data; - - iter = iter->next; + c_list_for_each_entry_safe (ac, ac_safe, &priv->active_connections_lst_head, active_connections_lst) { if (nm_active_connection_get_state (ac) == NM_ACTIVE_CONNECTION_STATE_DEACTIVATED) { if (active_connection_remove (self, ac)) _notify (self, PROP_ACTIVE_CONNECTIONS); @@ -420,10 +443,11 @@ active_connection_add (NMManager *self, NMActiveConnection *active) { NMManagerPrivate *priv = NM_MANAGER_GET_PRIVATE (self); - g_return_if_fail (g_slist_find (priv->active_connections, active) == FALSE); + nm_assert (NM_IS_ACTIVE_CONNECTION (active)); + nm_assert (!c_list_is_linked (&active->active_connections_lst)); - priv->active_connections = g_slist_prepend (priv->active_connections, - g_object_ref (active)); + c_list_link_front (&priv->active_connections_lst_head, &active->active_connections_lst); + g_object_ref (active); g_signal_connect (active, "notify::" NM_ACTIVE_CONNECTION_STATE, @@ -445,10 +469,10 @@ active_connection_add (NMManager *self, NMActiveConnection *active) _notify (self, PROP_ACTIVE_CONNECTIONS); } -const GSList * +const CList * nm_manager_get_active_connections (NMManager *manager) { - return NM_MANAGER_GET_PRIVATE (manager)->active_connections; + return &NM_MANAGER_GET_PRIVATE (manager)->active_connections_lst_head; } static NMActiveConnection * @@ -457,16 +481,12 @@ active_connection_find_first (NMManager *self, const char *uuid, NMActiveConnectionState max_state) { - NMManagerPrivate *priv; - GSList *iter; - - g_return_val_if_fail (NM_IS_MANAGER (self), NULL); - g_return_val_if_fail (!settings_connection || NM_IS_SETTINGS_CONNECTION (settings_connection), NULL); + NMManagerPrivate *priv = NM_MANAGER_GET_PRIVATE (self); + NMActiveConnection *ac; - priv = NM_MANAGER_GET_PRIVATE (self); + nm_assert (!settings_connection || NM_IS_SETTINGS_CONNECTION (settings_connection)); - for (iter = priv->active_connections; iter; iter = iter->next) { - NMActiveConnection *ac = iter->data; + c_list_for_each_entry (ac, &priv->active_connections_lst_head, active_connections_lst) { NMSettingsConnection *con; con = nm_active_connection_get_settings_connection (ac); @@ -505,47 +525,35 @@ _get_activatable_connections_filter (NMSettings *settings, NMSettingsConnection *connection, gpointer user_data) { - if (nm_settings_connection_get_volatile (connection)) + if (NM_FLAGS_HAS (nm_settings_connection_get_flags (connection), + NM_SETTINGS_CONNECTION_FLAGS_VOLATILE)) return FALSE; return !active_connection_find_first (user_data, connection, NULL, NM_ACTIVE_CONNECTION_STATE_DEACTIVATING); } -/* Filter out connections that are already active. - * nm_settings_get_connections_sorted() returns sorted list. We need to preserve the - * order so that we didn't change auto-activation order (recent timestamps - * are first). - * Caller is responsible for freeing the returned list with g_slist_free(). - */ NMSettingsConnection ** nm_manager_get_activatable_connections (NMManager *manager, guint *out_len, gboolean sort) { NMManagerPrivate *priv = NM_MANAGER_GET_PRIVATE (manager); - NMSettingsConnection **connections; - guint len; - connections = nm_settings_get_connections_clone (priv->settings, &len, - _get_activatable_connections_filter, - manager); - if (sort && len > 1) - g_qsort_with_data (connections, len, sizeof (connections[0]), nm_settings_connection_cmp_autoconnect_priority_p_with_data, NULL); - NM_SET_OUT (out_len, len); - return connections; + return nm_settings_get_connections_clone (priv->settings, out_len, + _get_activatable_connections_filter, + manager, + sort ? nm_settings_connection_cmp_autoconnect_priority_p_with_data : NULL, + NULL); } static NMActiveConnection * active_connection_get_by_path (NMManager *manager, const char *path) { NMManagerPrivate *priv = NM_MANAGER_GET_PRIVATE (manager); - GSList *iter; - - g_return_val_if_fail (manager != NULL, NULL); - g_return_val_if_fail (path != NULL, NULL); + NMActiveConnection *ac; - for (iter = priv->active_connections; iter; iter = g_slist_next (iter)) { - NMActiveConnection *candidate = iter->data; + nm_assert (path); - if (g_strcmp0 (path, nm_exported_object_get_path (NM_EXPORTED_OBJECT (candidate))) == 0) - return candidate; + 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; } @@ -827,16 +835,14 @@ find_best_device_state (NMManager *manager) { NMManagerPrivate *priv = NM_MANAGER_GET_PRIVATE (manager); NMState best_state = NM_STATE_DISCONNECTED; - GSList *iter; + NMActiveConnection *ac; - for (iter = priv->active_connections; iter; iter = iter->next) { - NMActiveConnection *ac = NM_ACTIVE_CONNECTION (iter->data); + c_list_for_each_entry (ac, &priv->active_connections_lst_head, active_connections_lst) { NMActiveConnectionState ac_state = nm_active_connection_get_state (ac); switch (ac_state) { case NM_ACTIVE_CONNECTION_STATE_ACTIVATED: - if ( nm_active_connection_get_default (ac) - || nm_active_connection_get_default6 (ac)) { + if (nm_active_connection_get_default (ac, AF_UNSPEC)) { if (priv->connectivity_state == NM_CONNECTIVITY_FULL) return NM_STATE_CONNECTED_GLOBAL; @@ -1391,7 +1397,9 @@ system_create_virtual_device (NMManager *self, NMConnection *connection) } /* Create backing resources if the device has any autoconnect connections */ - connections = nm_settings_get_connections_sorted (priv->settings, NULL); + connections = nm_settings_get_connections_clone (priv->settings, NULL, + NULL, NULL, + nm_settings_connection_cmp_autoconnect_priority_p_with_data, NULL); for (i = 0; connections[i]; i++) { NMConnection *candidate = NM_CONNECTION (connections[i]); NMSettingConnection *s_con; @@ -1435,7 +1443,9 @@ retry_connections_for_parent_device (NMManager *self, NMDevice *device) g_return_if_fail (device); - connections = nm_settings_get_connections_sorted (priv->settings, NULL); + connections = nm_settings_get_connections_clone (priv->settings, NULL, + NULL, NULL, + nm_settings_connection_cmp_autoconnect_priority_p_with_data, NULL); for (i = 0; connections[i]; i++) { NMConnection *candidate = NM_CONNECTION (connections[i]); gs_free_error GError *error = NULL; @@ -1491,6 +1501,74 @@ connection_updated_cb (NMSettings *settings, connection_changed (self, connection); } +/*****************************************************************************/ + +typedef struct { + CList delete_volatile_connection_lst; + NMSettingsConnection *connection; +} DeleteVolatileConnectionData; + +static void +_delete_volatile_connection_all (NMManager *self, gboolean do_delete) +{ + NMManagerPrivate *priv = NM_MANAGER_GET_PRIVATE (self); + CList *lst; + DeleteVolatileConnectionData *data; + + while ((lst = c_list_first (&priv->delete_volatile_connection_lst_head))) { + gs_unref_object NMSettingsConnection *connection = NULL; + + data = c_list_entry (lst, + DeleteVolatileConnectionData, + delete_volatile_connection_lst); + connection = data->connection; + c_list_unlink_stale (&data->delete_volatile_connection_lst); + g_slice_free (DeleteVolatileConnectionData, data); + + if (do_delete) + _delete_volatile_connection_do (self, connection); + } +} + +static gboolean +_delete_volatile_connection_cb (gpointer user_data) +{ + NMManager *self = user_data; + NMManagerPrivate *priv = NM_MANAGER_GET_PRIVATE (self); + + priv->delete_volatile_connection_idle_id = 0; + _delete_volatile_connection_all (self, TRUE); + return G_SOURCE_REMOVE; +} + +static void +connection_flags_changed (NMSettings *settings, + NMSettingsConnection *connection, + gpointer user_data) +{ + NMManager *self = user_data; + NMManagerPrivate *priv = NM_MANAGER_GET_PRIVATE (self); + DeleteVolatileConnectionData *data; + + if (!NM_FLAGS_HAS (nm_settings_connection_get_flags (connection), + NM_SETTINGS_CONNECTION_FLAGS_VOLATILE)) + return; + + if (active_connection_find_first (self, connection, NULL, NM_ACTIVE_CONNECTION_STATE_DEACTIVATED)) { + /* the connection still have an active-connection. It will be purged + * when the active connection(s) get(s) removed. */ + return; + } + + data = g_slice_new (DeleteVolatileConnectionData); + data->connection = g_object_ref (connection); + c_list_link_tail (&priv->delete_volatile_connection_lst_head, &data->delete_volatile_connection_lst); + if (!priv->delete_volatile_connection_idle_id) + priv->delete_volatile_connection_idle_id = g_idle_add (_delete_volatile_connection_cb, self); +} + +/*****************************************************************************/ + static void system_unmanaged_devices_changed_cb (NMSettings *settings, GParamSpec *pspec, @@ -1860,6 +1938,7 @@ get_existing_connection (NMManager *self, matched = NM_SETTINGS_CONNECTION (nm_utils_match_connection (connections, connection, + TRUE, nm_device_has_carrier (device), nm_device_get_route_metric (device, AF_INET), nm_device_get_route_metric (device, AF_INET6), @@ -1889,6 +1968,7 @@ get_existing_connection (NMManager *self, matched = NM_SETTINGS_CONNECTION (nm_utils_match_connection ((NMConnection *const*) connections, connection, + FALSE, nm_device_has_carrier (device), nm_device_get_route_metric (device, AF_INET), nm_device_get_route_metric (device, AF_INET6), @@ -2476,7 +2556,7 @@ _platform_link_cb_idle (PlatformLinkCbData *data) NMManagerPrivate *priv = NM_MANAGER_GET_PRIVATE (self); const NMPlatformLink *plink; - c_list_unlink (&data->lst); + c_list_unlink_stale (&data->lst); g_slice_free (PlatformLinkCbData, data); plink = nm_platform_link_get (priv->platform, ifindex); @@ -3021,7 +3101,9 @@ find_slaves (NMManager *manager, * even if a slave was already active, it might be deactivated during * master reactivation. */ - all_connections = nm_settings_get_connections_sorted (priv->settings, &n_all_connections); + all_connections = nm_settings_get_connections_clone (priv->settings, &n_all_connections, + NULL, NULL, + nm_settings_connection_cmp_autoconnect_priority_p_with_data, NULL); for (i = 0; i < n_all_connections; i++) { NMSettingsConnection *master_connection = NULL; NMDevice *master_device = NULL, *slave_device; @@ -3627,11 +3709,11 @@ _internal_activation_auth_done (NMActiveConnection *active, gpointer user_data1, gpointer user_data2) { + _nm_unused gs_unref_object NMActiveConnection *active_to_free = active; NMManager *self = user_data1; NMManagerPrivate *priv = NM_MANAGER_GET_PRIVATE (self); - NMActiveConnection *candidate; - GError *error = NULL; - GSList *iter; + NMActiveConnection *ac; + gs_free_error GError *error = NULL; priv->authorizing_connections = g_slist_remove (priv->authorizing_connections, active); @@ -3640,12 +3722,12 @@ _internal_activation_auth_done (NMActiveConnection *active, * detect a duplicate if the existing active connection is undergoing * authorization in impl_manager_activate_connection(). */ - if (success && nm_auth_subject_is_internal (nm_active_connection_get_subject (active))) { - for (iter = priv->active_connections; iter; iter = iter->next) { - candidate = iter->data; - if ( nm_active_connection_get_device (candidate) == nm_active_connection_get_device (active) - && nm_active_connection_get_settings_connection (candidate) == nm_active_connection_get_settings_connection (active) - && NM_IN_SET (nm_active_connection_get_state (candidate), + if ( success + && nm_auth_subject_is_internal (nm_active_connection_get_subject (active))) { + 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) + && nm_active_connection_get_settings_connection (ac) == nm_active_connection_get_settings_connection (active) + && NM_IN_SET (nm_active_connection_get_state (ac), NM_ACTIVE_CONNECTION_STATE_ACTIVATING, NM_ACTIVE_CONNECTION_STATE_ACTIVATED)) { g_set_error (&error, @@ -3660,16 +3742,12 @@ _internal_activation_auth_done (NMActiveConnection *active, } if (success) { - if (_internal_activate_generic (self, active, &error)) { - g_object_unref (active); + if (_internal_activate_generic (self, active, &error)) return; - } } - g_assert (error_desc || error); + nm_assert (error_desc || error); _internal_activation_failed (self, active, error_desc ? error_desc : error->message); - g_object_unref (active); - g_clear_error (&error); } /** @@ -3894,6 +3972,9 @@ _activation_auth_done (NMActiveConnection *active, 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)))); @@ -4037,10 +4118,12 @@ activation_add_done (NMSettings *settings, nm_active_connection_set_settings_connection (active, new_connection); if (_internal_activate_generic (self, active, &local)) { - nm_settings_connection_commit_changes (new_connection, - NULL, - NM_SETTINGS_CONNECTION_COMMIT_REASON_USER_ACTION | NM_SETTINGS_CONNECTION_COMMIT_REASON_ID_CHANGED, - NULL); + nm_settings_connection_update (new_connection, + NULL, + NM_SETTINGS_CONNECTION_PERSIST_MODE_DISK, + NM_SETTINGS_CONNECTION_COMMIT_REASON_USER_ACTION | NM_SETTINGS_CONNECTION_COMMIT_REASON_ID_CHANGED, + "add-and-activate", + NULL); g_dbus_method_invocation_return_value ( context, g_variant_new ("(oo)", @@ -4166,7 +4249,9 @@ impl_manager_add_and_activate_connection (NMManager *self, gs_free NMSettingsConnection **connections = NULL; guint i, len; - connections = nm_settings_get_connections_sorted (priv->settings, &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--; @@ -4508,7 +4593,7 @@ do_sleep_wake (NMManager *self, gboolean sleeping_changed) waking_from_suspend = sleeping_changed && !priv->sleeping; if (manager_sleeping (self)) { - _LOGI (LOGD_SUSPEND, "%s...", suspending ? "sleeping" : "disabling"); + _LOGD (LOGD_SUSPEND, "sleep: %s...", suspending ? "sleeping" : "disabling"); /* FIXME: are there still hardware devices that need to be disabled around * suspend/resume? @@ -4539,7 +4624,7 @@ do_sleep_wake (NMManager *self, gboolean sleeping_changed) } } } else { - _LOGI (LOGD_SUSPEND, "%s...", waking_from_suspend ? "waking up" : "re-enabling"); + _LOGD (LOGD_SUSPEND, "sleep: %s...", waking_from_suspend ? "waking up" : "re-enabling"); if (waking_from_suspend) { sleep_devices_clear (self); @@ -4596,7 +4681,6 @@ do_sleep_wake (NMManager *self, gboolean sleeping_changed) enabled ? "enabling" : "disabling", rstate->desc, rstate->hw_enabled, rstate->sw_enabled, rstate->user_enabled); } - if (nm_device_get_rfkill_type (device) == rstate->rtype) nm_device_set_enabled (device, enabled); } @@ -4620,7 +4704,7 @@ _internal_sleep (NMManager *self, gboolean do_sleep) if (priv->sleeping == do_sleep) return; - _LOGI (LOGD_SUSPEND, "%s requested (sleeping: %s enabled: %s)", + _LOGI (LOGD_SUSPEND, "sleep: %s requested (sleeping: %s enabled: %s)", do_sleep ? "sleep" : "wake", priv->sleeping ? "yes" : "no", priv->net_enabled ? "yes" : "no"); @@ -4732,7 +4816,7 @@ sleeping_cb (NMSleepMonitor *monitor, gboolean is_about_to_suspend, gpointer use { NMManager *self = user_data; - _LOGD (LOGD_SUSPEND, "Received %s signal", is_about_to_suspend ? "sleeping" : "resuming"); + _LOGT (LOGD_SUSPEND, "sleep: received %s signal", is_about_to_suspend ? "sleeping" : "resuming"); _internal_sleep (self, is_about_to_suspend); } @@ -5225,7 +5309,9 @@ nm_manager_start (NMManager *self, GError **error) * connection-added signals thus devices have to be created manually. */ _LOGD (LOGD_CORE, "creating virtual devices..."); - connections = nm_settings_get_connections_sorted (priv->settings, NULL); + connections = nm_settings_get_connections_clone (priv->settings, NULL, + NULL, NULL, + nm_settings_connection_cmp_autoconnect_priority_p_with_data, NULL); for (i = 0; connections[i]; i++) connection_changed (self, NM_CONNECTION (connections[i])); @@ -5908,7 +5994,7 @@ rfkill_change (NMManager *self, const char *desc, RfKillType rtype, gboolean ena if (fcntl (fd, F_SETFL, O_NONBLOCK) < 0) { _LOGW (LOGD_RFKILL, "rfkill: (%s): failed to set killswitch device for " "non-blocking operation", desc); - close (fd); + nm_close (fd); return; } @@ -5938,7 +6024,7 @@ rfkill_change (NMManager *self, const char *desc, RfKillType rtype, gboolean ena _LOGW (LOGD_RFKILL, "rfkill: (%s): failed to change WiFi killswitch state", desc); } - close (fd); + nm_close (fd); } static void @@ -5989,19 +6075,15 @@ periodic_update_active_connection_timestamps (gpointer user_data) { NMManager *manager = NM_MANAGER (user_data); NMManagerPrivate *priv = NM_MANAGER_GET_PRIVATE (manager); - GSList *iter; - - for (iter = priv->active_connections; iter; iter = g_slist_next (iter)) { - NMActiveConnection *ac = iter->data; - NMSettingsConnection *connection; + NMActiveConnection *ac; + c_list_for_each_entry (ac, &priv->active_connections_lst_head, active_connections_lst) { if (nm_active_connection_get_state (ac) == NM_ACTIVE_CONNECTION_STATE_ACTIVATED) { - connection = nm_active_connection_get_settings_connection (ac); - nm_settings_connection_update_timestamp (connection, (guint64) time (NULL), FALSE); + nm_settings_connection_update_timestamp (nm_active_connection_get_settings_connection (ac), + (guint64) time (NULL), FALSE); } } - - return TRUE; + return G_SOURCE_CONTINUE; } static void @@ -6106,6 +6188,7 @@ constructed (GObject *object) G_CALLBACK (connection_added_cb), self); g_signal_connect (priv->settings, NM_SETTINGS_SIGNAL_CONNECTION_UPDATED, G_CALLBACK (connection_updated_cb), self); + g_signal_connect (priv->settings, NM_SETTINGS_SIGNAL_CONNECTION_FLAGS_CHANGED, G_CALLBACK (connection_flags_changed), self); priv->hostname_manager = g_object_ref (nm_hostname_manager_get ()); g_signal_connect (priv->hostname_manager, "notify::" NM_HOSTNAME_MANAGER_HOSTNAME, @@ -6163,6 +6246,8 @@ nm_manager_init (NMManager *self) GFile *file; c_list_init (&priv->link_cb_lst); + c_list_init (&priv->active_connections_lst_head); + c_list_init (&priv->delete_volatile_connection_lst_head); priv->platform = g_object_ref (NM_PLATFORM_GET); @@ -6250,7 +6335,10 @@ get_property (GObject *object, guint prop_id, NMConfigData *config_data; const NMGlobalDnsConfig *dns_config; const char *type; - NMConnectivity *connectivity; + const char *path; + NMActiveConnection *ac; + GPtrArray *ptrarr; + gboolean vbool; switch (prop_id) { case PROP_VERSION: @@ -6290,7 +6378,14 @@ get_property (GObject *object, guint prop_id, g_value_set_boolean (value, FALSE); break; case PROP_ACTIVE_CONNECTIONS: - nm_utils_g_value_set_object_path_array (value, priv->active_connections, NULL, NULL); + ptrarr = g_ptr_array_new (); + c_list_for_each_entry (ac, &priv->active_connections_lst_head, active_connections_lst) { + path = nm_exported_object_get_path (NM_EXPORTED_OBJECT (ac)); + if (path) + g_ptr_array_add (ptrarr, g_strdup (path)); + } + g_ptr_array_add (ptrarr, NULL); + g_value_take_boxed (value, g_ptr_array_free (ptrarr, FALSE)); break; case PROP_CONNECTIVITY: g_value_set_uint (value, priv->connectivity_state); @@ -6300,8 +6395,12 @@ 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: - connectivity = nm_connectivity_get (); - g_value_set_boolean (value, nm_connectivity_check_enabled (connectivity)); +#if WITH_CONCHECK + vbool = nm_connectivity_check_enabled (nm_connectivity_get ()); +#else + vbool = FALSE; +#endif + g_value_set_boolean (value, FALSE); break; case PROP_PRIMARY_CONNECTION: nm_utils_g_value_set_object_path (value, priv->primary_connection); @@ -6400,6 +6499,12 @@ dispose (GObject *object) NMManager *self = NM_MANAGER (object); NMManagerPrivate *priv = NM_MANAGER_GET_PRIVATE (self); 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), @@ -6408,7 +6513,7 @@ dispose (GObject *object) PlatformLinkCbData *data = c_list_entry (iter, PlatformLinkCbData, lst); g_source_remove (data->idle_id); - c_list_unlink (iter); + c_list_unlink_stale (iter); g_slice_free (PlatformLinkCbData, data); } @@ -6433,9 +6538,9 @@ dispose (GObject *object) nm_clear_g_source (&priv->ac_cleanup_id); - while (priv->active_connections) - active_connection_remove (self, NM_ACTIVE_CONNECTION (priv->active_connections->data)); - g_clear_pointer (&priv->active_connections, g_slist_free); + c_list_for_each_entry_safe (ac, ac_safe, &priv->active_connections_lst_head, active_connections_lst) + active_connection_remove (self, ac); + nm_assert (c_list_is_empty (&priv->active_connections_lst_head)); g_clear_object (&priv->primary_connection); g_clear_object (&priv->activating_connection); @@ -6455,6 +6560,7 @@ dispose (GObject *object) g_signal_handlers_disconnect_by_func (priv->settings, system_unmanaged_devices_changed_cb, self); g_signal_handlers_disconnect_by_func (priv->settings, connection_added_cb, self); g_signal_handlers_disconnect_by_func (priv->settings, connection_updated_cb, self); + g_signal_handlers_disconnect_by_func (priv->settings, connection_flags_changed, self); g_clear_object (&priv->settings); } diff --git a/src/nm-manager.h b/src/nm-manager.h index 418c5ea9..2d463c71 100644 --- a/src/nm-manager.h +++ b/src/nm-manager.h @@ -24,6 +24,7 @@ #include "nm-exported-object.h" #include "settings/nm-settings-connection.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)) @@ -84,7 +85,19 @@ gboolean nm_manager_start (NMManager *manager, GError **error); void nm_manager_stop (NMManager *manager); NMState nm_manager_get_state (NMManager *manager); -const GSList *nm_manager_get_active_connections (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); \ + ({ \ + gboolean _has_next = (&iter->active_connections_lst != tmp_list); \ + \ + if (!_has_next) \ + iter = NULL; \ + _has_next; \ + }); \ + iter = c_list_entry (iter->active_connections_lst.next, NMActiveConnection, active_connections_lst)) NMSettingsConnection **nm_manager_get_activatable_connections (NMManager *manager, guint *out_len, diff --git a/src/nm-pacrunner-manager.c b/src/nm-pacrunner-manager.c index 08e10e40..36f517a2 100644 --- a/src/nm-pacrunner-manager.c +++ b/src/nm-pacrunner-manager.c @@ -128,7 +128,7 @@ config_unref (Config *config) if (config->refcount == 1) { g_variant_unref (config->args); g_free (config->path); - c_list_unlink (&config->lst); + c_list_unlink_stale (&config->lst); g_slice_free (Config, config); } else config->refcount--; @@ -524,7 +524,7 @@ nm_pacrunner_manager_remove (NMPacrunnerManager *self, NMPacrunnerCallId *call_i } } - c_list_unlink_init (&config->lst); + c_list_unlink (&config->lst); config_unref (config); } @@ -570,7 +570,7 @@ dispose (GObject *object) CList *iter, *safe; c_list_for_each_safe (iter, safe, &priv->configs) { - c_list_unlink_init (iter); + c_list_unlink (iter); config_unref (c_list_entry (iter, Config, lst)); } diff --git a/src/nm-policy.c b/src/nm-policy.c index e56fce0b..8dfb0ab0 100644 --- a/src/nm-policy.c +++ b/src/nm-policy.c @@ -44,6 +44,7 @@ #include "nm-manager.h" #include "settings/nm-settings.h" #include "settings/nm-settings-connection.h" +#include "settings/nm-agent-manager.h" #include "nm-dhcp4-config.h" #include "nm-dhcp6-config.h" #include "nm-config.h" @@ -65,7 +66,9 @@ typedef struct { NMManager *manager; NMNetns *netns; NMFirewallManager *firewall_manager; - GSList *pending_activation_checks; + CList pending_activation_checks; + + NMAgentManager *agent_mgr; GHashTable *devices; GHashTable *pending_active_connections; @@ -312,8 +315,9 @@ device_ip6_prefix_delegated (NMDevice *device, NMPolicyPrivate *priv = user_data; NMPolicy *self = _PRIV_TO_SELF (priv); IP6PrefixDelegation *delegation = NULL; - const GSList *connections, *iter; guint i; + const CList *tmp_list; + NMActiveConnection *ac; _LOGI (LOGD_IP6, "ipv6-pd: received a prefix %s/%d from %s", nm_utils_inet6_ntop (&prefix->address, NULL), @@ -344,10 +348,10 @@ device_ip6_prefix_delegated (NMDevice *device, * so traversing it from the beginning makes it likely for newly * activated connections that have no subnet assigned to be served * first. That is a simple yet fair policy, which is good. */ - connections = nm_manager_get_active_connections (priv->manager); - for (iter = connections; iter; iter = g_slist_next (iter)) { - NMDevice *to_device = nm_active_connection_get_device (iter->data); + nm_manager_for_each_active_connection (priv->manager, ac, tmp_list) { + NMDevice *to_device; + to_device = nm_active_connection_get_device (ac); if (nm_device_needs_ip6_subnet (to_device)) ip6_subnet_from_delegation (delegation, to_device); } @@ -818,25 +822,25 @@ update_system_hostname (NMPolicy *self, const char *msg) static void update_default_ac (NMPolicy *self, - NMActiveConnection *best, - void (*set_active_func)(NMActiveConnection*, gboolean)) + int addr_family, + NMActiveConnection *best) { NMPolicyPrivate *priv = NM_POLICY_GET_PRIVATE (self); - const GSList *connections, *iter; + const CList *tmp_list; + NMActiveConnection *ac; /* Clear the 'default[6]' flag on all active connections that aren't the new * default active connection. We'll set the new default after; this ensures * we don't ever have two marked 'default[6]' simultaneously. */ - connections = nm_manager_get_active_connections (priv->manager); - for (iter = connections; iter; iter = g_slist_next (iter)) { - if (NM_ACTIVE_CONNECTION (iter->data) != best) - set_active_func (NM_ACTIVE_CONNECTION (iter->data), FALSE); + nm_manager_for_each_active_connection (priv->manager, ac, tmp_list) { + if (ac != best) + nm_active_connection_set_default (ac, addr_family, FALSE); } /* Mark new default active connection */ if (best) - set_active_func (best, TRUE); + nm_active_connection_set_default (best, addr_family, TRUE); } static gpointer @@ -850,19 +854,19 @@ get_best_ip_config (NMPolicy *self, NMPolicyPrivate *priv = NM_POLICY_GET_PRIVATE (self); NMDevice *device; gpointer conf; - const GSList *iter; + const CList *tmp_list; + NMActiveConnection *ac; nm_assert (NM_IN_SET (addr_family, AF_INET, AF_INET6)); - for (iter = nm_manager_get_active_connections (priv->manager); iter; iter = iter->next) { - NMActiveConnection *active = NM_ACTIVE_CONNECTION (iter->data); + nm_manager_for_each_active_connection (priv->manager, ac, tmp_list) { NMVpnConnection *candidate; NMVpnConnectionState vpn_state; - if (!NM_IS_VPN_CONNECTION (active)) + if (!NM_IS_VPN_CONNECTION (ac)) continue; - candidate = NM_VPN_CONNECTION (active); + candidate = NM_VPN_CONNECTION (ac); vpn_state = nm_vpn_connection_get_vpn_state (candidate); if (vpn_state != NM_VPN_CONNECTION_STATE_ACTIVATED) @@ -887,7 +891,7 @@ get_best_ip_config (NMPolicy *self, * best metric. */ NM_SET_OUT (out_device, NULL); NM_SET_OUT (out_vpn, candidate); - NM_SET_OUT (out_ac, active); + NM_SET_OUT (out_ac, ac); NM_SET_OUT (out_ip_iface, nm_vpn_connection_get_ip_iface (candidate, TRUE)); return conf; } @@ -919,26 +923,6 @@ get_best_ip_config (NMPolicy *self, } static void -update_ip4_dns (NMPolicy *self, NMDnsManager *dns_mgr) -{ - NMIP4Config *ip4_config; - const char *ip_iface = NULL; - NMVpnConnection *vpn = NULL; - NMDnsIPConfigType dns_type = NM_DNS_IP_CONFIG_TYPE_BEST_DEVICE; - - ip4_config = get_best_ip_config (self, AF_INET, &ip_iface, NULL, NULL, &vpn); - if (ip4_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_add_ip4_config (dns_mgr, ip_iface, ip4_config, dns_type); - } -} - -static void update_ip4_routing (NMPolicy *self, gboolean force_update) { NMPolicyPrivate *priv = NM_POLICY_GET_PRIVATE (self); @@ -946,6 +930,8 @@ update_ip4_routing (NMPolicy *self, gboolean force_update) NMVpnConnection *vpn = NULL; NMActiveConnection *best_ac = NULL; const char *ip_iface = NULL; + const CList *tmp_list; + NMActiveConnection *ac; /* Note that we might have an IPv4 VPN tunneled over an IPv6-only device, * so we can get (vpn != NULL && best == NULL). @@ -965,23 +951,18 @@ update_ip4_routing (NMPolicy *self, gboolean force_update) return; if (best) { - const GSList *connections, *iter; - - connections = nm_manager_get_active_connections (priv->manager); - for (iter = connections; iter; iter = g_slist_next (iter)) { - NMActiveConnection *active = iter->data; - - if ( NM_IS_VPN_CONNECTION (active) - && nm_vpn_connection_get_ip4_config (NM_VPN_CONNECTION (active)) - && !nm_active_connection_get_device (active)) - nm_active_connection_set_device (active, best); + nm_manager_for_each_active_connection (priv->manager, ac, tmp_list) { + if ( NM_IS_VPN_CONNECTION (ac) + && nm_vpn_connection_get_ip4_config (NM_VPN_CONNECTION (ac)) + && !nm_active_connection_get_device (ac)) + nm_active_connection_set_device (ac, best); } } if (vpn) best = nm_active_connection_get_device (NM_ACTIVE_CONNECTION (vpn)); - update_default_ac (self, best_ac, nm_active_connection_set_default); + update_default_ac (self, AF_INET, best_ac); if (!nm_g_object_ref_set (&priv->default_device4, best)) return; @@ -997,50 +978,28 @@ static void update_ip6_dns_delegation (NMPolicy *self) { NMPolicyPrivate *priv = NM_POLICY_GET_PRIVATE (self); - const GSList *connections, *iter; - - connections = nm_manager_get_active_connections (priv->manager); - for (iter = connections; iter; iter = g_slist_next (iter)) { - NMDevice *device = nm_active_connection_get_device (iter->data); + NMDevice *device; + NMActiveConnection *ac; + const CList *tmp_list; + nm_manager_for_each_active_connection (priv->manager, ac, tmp_list) { + device = nm_active_connection_get_device (ac); if (device && nm_device_needs_ip6_subnet (device)) nm_device_copy_ip6_dns_config (device, priv->default_device6); } } static void -update_ip6_dns (NMPolicy *self, NMDnsManager *dns_mgr) -{ - NMIP6Config *ip6_config; - const char *ip_iface = NULL; - NMVpnConnection *vpn = NULL; - NMDnsIPConfigType dns_type = NM_DNS_IP_CONFIG_TYPE_BEST_DEVICE; - - ip6_config = get_best_ip_config (self, AF_INET6, &ip_iface, NULL, NULL, &vpn); - if (ip6_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_add_ip6_config (dns_mgr, ip_iface, ip6_config, dns_type); - } - - update_ip6_dns_delegation (self); -} - -static void update_ip6_prefix_delegation (NMPolicy *self) { NMPolicyPrivate *priv = NM_POLICY_GET_PRIVATE (self); - const GSList *connections, *iter; + NMDevice *device; + NMActiveConnection *ac; + const CList *tmp_list; /* There's new default IPv6 connection, try to get a prefix for everyone. */ - connections = nm_manager_get_active_connections (priv->manager); - for (iter = connections; iter; iter = g_slist_next (iter)) { - NMDevice *device = nm_active_connection_get_device (iter->data); - + nm_manager_for_each_active_connection (priv->manager, ac, tmp_list) { + device = nm_active_connection_get_device (ac); if (device && nm_device_needs_ip6_subnet (device)) ip6_subnet_from_device (self, priv->default_device6, device); } @@ -1054,6 +1013,8 @@ update_ip6_routing (NMPolicy *self, gboolean force_update) NMVpnConnection *vpn = NULL; NMActiveConnection *best_ac = NULL; const char *ip_iface = NULL; + NMActiveConnection *ac; + const CList *tmp_list; /* Note that we might have an IPv6 VPN tunneled over an IPv4-only device, * so we can get (vpn != NULL && best == NULL). @@ -1073,23 +1034,18 @@ update_ip6_routing (NMPolicy *self, gboolean force_update) return; if (best) { - const GSList *connections, *iter; - - connections = nm_manager_get_active_connections (priv->manager); - for (iter = connections; iter; iter = g_slist_next (iter)) { - NMActiveConnection *active = iter->data; - - if ( NM_IS_VPN_CONNECTION (active) - && nm_vpn_connection_get_ip6_config (NM_VPN_CONNECTION (active)) - && !nm_active_connection_get_device (active)) - nm_active_connection_set_device (active, best); + nm_manager_for_each_active_connection (priv->manager, ac, tmp_list) { + if ( NM_IS_VPN_CONNECTION (ac) + && nm_vpn_connection_get_ip6_config (NM_VPN_CONNECTION (ac)) + && !nm_active_connection_get_device (ac)) + nm_active_connection_set_device (ac, best); } } if (vpn) best = nm_active_connection_get_device (NM_ACTIVE_CONNECTION (vpn)); - update_default_ac (self, best_ac, nm_active_connection_set_default6); + update_default_ac (self, AF_INET6, best_ac); if (!nm_g_object_ref_set (&priv->default_device6, best)) return; @@ -1104,14 +1060,42 @@ update_ip6_routing (NMPolicy *self, gboolean force_update) } static void +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_add_ip_config (NM_POLICY_GET_PRIVATE (self)->dns_manager, + ip_iface, + ip_config, + dns_type); + } + + if (addr_family == AF_INET6) + update_ip6_dns_delegation (self); +} + +static void update_routing_and_dns (NMPolicy *self, gboolean force_update) { NMPolicyPrivate *priv = NM_POLICY_GET_PRIVATE (self); nm_dns_manager_begin_updates (priv->dns_manager, __func__); - update_ip4_dns (self, priv->dns_manager); - update_ip6_dns (self, priv->dns_manager); + update_ip_dns (self, AF_INET); + update_ip_dns (self, AF_INET6); update_ip4_routing (self, force_update); update_ip6_routing (self, force_update); @@ -1146,6 +1130,7 @@ check_activating_devices (NMPolicy *self) } typedef struct { + CList pending_lst; NMPolicy *policy; NMDevice *device; guint autoactivate_id; @@ -1154,14 +1139,10 @@ typedef struct { static void activate_data_free (ActivateData *data) { - NMPolicyPrivate *priv = NM_POLICY_GET_PRIVATE (data->policy); - nm_device_remove_pending_action (data->device, NM_PENDING_ACTION_AUTOACTIVATE, TRUE); - priv->pending_activation_checks = g_slist_remove (priv->pending_activation_checks, data); - + c_list_unlink_stale (&data->pending_lst); nm_clear_g_source (&data->autoactivate_id); g_object_unref (data->device); - g_slice_free (ActivateData, data); } @@ -1192,7 +1173,7 @@ pending_ac_state_changed (NMActiveConnection *ac, guint state, guint reason, NMP * loop. */ con = nm_active_connection_get_settings_connection (ac); - nm_settings_connection_autoconnect_blocked_reason_set (con, NM_SETTINGS_AUTO_CONNECT_BLOCKED_REASON_FAILED); + nm_settings_connection_autoconnect_blocked_reason_set (con, NM_SETTINGS_AUTO_CONNECT_BLOCKED_REASON_FAILED, TRUE); schedule_activate_check (self, nm_active_connection_get_device (ac)); /* Cleanup */ @@ -1213,7 +1194,7 @@ auto_activate_device (NMPolicy *self, gs_free char *specific_object = NULL; gs_free NMSettingsConnection **connections = NULL; guint i, len; - GError *error = NULL; + gs_free_error GError *error = NULL; NMAuthSubject *subject; NMActiveConnection *ac; @@ -1243,9 +1224,7 @@ auto_activate_device (NMPolicy *self, NMSettingConnection *s_con; const char *permission; - if ( !nm_settings_connection_is_visible (candidate) - || nm_settings_connection_autoconnect_retries_get (candidate) == 0 - || nm_settings_connection_autoconnect_blocked_reason_get (candidate) != NM_SETTINGS_AUTO_CONNECT_BLOCKED_REASON_NONE) + if (nm_settings_connection_autoconnect_is_blocked (candidate)) continue; s_con = nm_connection_get_setting_connection (NM_CONNECTION (candidate)); @@ -1278,13 +1257,12 @@ auto_activate_device (NMPolicy *self, NM_ACTIVATION_TYPE_MANAGED, &error); if (!ac) { - _LOGI (LOGD_DEVICE, "connection '%s' auto-activation failed: (%d) %s", + _LOGI (LOGD_DEVICE, "connection '%s' auto-activation failed: %s", nm_settings_connection_get_id (best_connection), - error->code, error->message); - g_error_free (error); nm_settings_connection_autoconnect_blocked_reason_set (best_connection, - NM_SETTINGS_AUTO_CONNECT_BLOCKED_REASON_FAILED); + NM_SETTINGS_AUTO_CONNECT_BLOCKED_REASON_FAILED, + TRUE); schedule_activate_check (self, device); return; } @@ -1318,13 +1296,14 @@ auto_activate_device_cb (gpointer user_data) } static ActivateData * -find_pending_activation (GSList *list, NMDevice *device) +find_pending_activation (NMPolicy *self, NMDevice *device) { - GSList *iter; + NMPolicyPrivate *priv = NM_POLICY_GET_PRIVATE (self); + ActivateData *data; - for (iter = list; iter; iter = g_slist_next (iter)) { - if (((ActivateData *) iter->data)->device == device) - return iter->data; + c_list_for_each_entry (data, &priv->pending_activation_checks, pending_lst) { + if (data->device == device) + return data; } return NULL; } @@ -1422,48 +1401,56 @@ hostname_changed (NMHostnameManager *hostname_manager, GParamSpec *pspec, gpoint update_system_hostname (self, "hostname changed"); } -static void -reset_autoconnect_all (NMPolicy *self, NMDevice *device) +static gboolean +reset_autoconnect_all (NMPolicy *self, + NMDevice *device, /* if present, only reset connections compatible with @device */ + gboolean only_no_secrets) { NMPolicyPrivate *priv = NM_POLICY_GET_PRIVATE (self); - gs_free NMSettingsConnection **connections = NULL; + NMSettingsConnection *const*connections = NULL; guint i; + gboolean changed; - if (device) { - _LOGD (LOGD_DEVICE, "re-enabling autoconnect for all connections on %s", - nm_device_get_iface (device)); - } else - _LOGD (LOGD_DEVICE, "re-enabling autoconnect for all connections"); + _LOGD (LOGD_DEVICE, "re-enabling autoconnect for all connections%s%s%s", + device ? " on " : "", + device ? nm_device_get_iface (device) : "", + only_no_secrets ? " (only clear no-secrets flag)" : ""); - connections = nm_settings_get_connections_sorted (priv->settings, NULL); + connections = nm_settings_get_connections (priv->settings, NULL); for (i = 0; connections[i]; i++) { NMSettingsConnection *connection = connections[i]; - if (!device || nm_device_check_connection_compatible (device, NM_CONNECTION (connection))) { - nm_settings_connection_autoconnect_retries_reset (connection); - nm_settings_connection_autoconnect_blocked_reason_set (connection, NM_SETTINGS_AUTO_CONNECT_BLOCKED_REASON_NONE); - } - } -} - -static void -reset_autoconnect_for_failed_secrets (NMPolicy *self) -{ - NMPolicyPrivate *priv = NM_POLICY_GET_PRIVATE (self); - gs_free NMSettingsConnection **connections = NULL; - guint i; - - _LOGD (LOGD_DEVICE, "re-enabling autoconnect for all connections with failed secrets"); - - connections = nm_settings_get_connections_sorted (priv->settings, NULL); - for (i = 0; connections[i]; i++) { - NMSettingsConnection *connection = connections[i]; + if ( device + && !nm_device_check_connection_compatible (device, NM_CONNECTION (connection))) + continue; - if (nm_settings_connection_autoconnect_blocked_reason_get (connection) == NM_SETTINGS_AUTO_CONNECT_BLOCKED_REASON_NO_SECRETS) { + if (only_no_secrets) { + /* we only reset the no-secrets blocked flag. */ + if (nm_settings_connection_autoconnect_blocked_reason_set (connection, + NM_SETTINGS_AUTO_CONNECT_BLOCKED_REASON_NO_SECRETS, + FALSE)) { + /* maybe the connection is still blocked afterwards for other reasons + * and in the larger picture nothing changed. But it's too complicated + * to find out exactly. Just assume, something changed to be sure. */ + if (!nm_settings_connection_autoconnect_is_blocked (connection)) + changed = TRUE; + } + } else { + /* we reset the tries-count and any blocked-reason */ + if (nm_settings_connection_autoconnect_retries_get (connection) == 0) + changed = TRUE; nm_settings_connection_autoconnect_retries_reset (connection); - nm_settings_connection_autoconnect_blocked_reason_set (connection, NM_SETTINGS_AUTO_CONNECT_BLOCKED_REASON_NONE); + + if (nm_settings_connection_autoconnect_blocked_reason_set (connection, + NM_SETTINGS_AUTO_CONNECT_BLOCKED_REASON_ALL + & ~NM_SETTINGS_AUTO_CONNECT_BLOCKED_REASON_USER_REQUEST, + FALSE)) { + if (!nm_settings_connection_autoconnect_is_blocked (connection)) + changed = TRUE; + } } } + return changed; } static void @@ -1478,7 +1465,7 @@ sleeping_changed (NMManager *manager, GParamSpec *pspec, gpointer user_data) /* Reset retries on all connections so they'll checked on wakeup */ if (sleeping || !enabled) - reset_autoconnect_all (self, NULL); + reset_autoconnect_all (self, NULL, FALSE); } static void @@ -1486,7 +1473,8 @@ schedule_activate_check (NMPolicy *self, NMDevice *device) { NMPolicyPrivate *priv = NM_POLICY_GET_PRIVATE (self); ActivateData *data; - const GSList *active_connections, *iter; + NMActiveConnection *ac; + const CList *tmp_list; if (nm_manager_get_state (priv->manager) == NM_STATE_ASLEEP) return; @@ -1494,12 +1482,11 @@ schedule_activate_check (NMPolicy *self, NMDevice *device) if (!nm_device_autoconnect_allowed (device)) return; - if (find_pending_activation (priv->pending_activation_checks, device)) + if (find_pending_activation (self, device)) return; - active_connections = nm_manager_get_active_connections (priv->manager); - for (iter = active_connections; iter; iter = iter->next) { - if (nm_active_connection_get_device (NM_ACTIVE_CONNECTION (iter->data)) == device) + nm_manager_for_each_active_connection (priv->manager, ac, tmp_list) { + if (nm_active_connection_get_device (ac) == device) return; } @@ -1509,18 +1496,7 @@ schedule_activate_check (NMPolicy *self, NMDevice *device) data->policy = self; data->device = g_object_ref (device); data->autoactivate_id = g_idle_add (auto_activate_device_cb, data); - priv->pending_activation_checks = g_slist_append (priv->pending_activation_checks, data); -} - -static void -clear_pending_activate_check (NMPolicy *self, NMDevice *device) -{ - NMPolicyPrivate *priv = NM_POLICY_GET_PRIVATE (self); - ActivateData *data; - - data = find_pending_activation (priv->pending_activation_checks, device); - if (data && data->autoactivate_id) - activate_data_free (data); + c_list_link_tail (&priv->pending_activation_checks, &data->pending_lst); } static gboolean @@ -1528,7 +1504,7 @@ reset_connections_retries (gpointer user_data) { NMPolicy *self = (NMPolicy *) user_data; NMPolicyPrivate *priv = NM_POLICY_GET_PRIVATE (self); - gs_free NMSettingsConnection **connections = NULL; + NMSettingsConnection *const*connections = NULL; guint i; gint32 con_stamp, min_stamp, now; gboolean changed = FALSE; @@ -1537,11 +1513,11 @@ reset_connections_retries (gpointer user_data) min_stamp = 0; now = nm_utils_get_monotonic_timestamp_s (); - connections = nm_settings_get_connections_sorted (priv->settings, NULL); + connections = nm_settings_get_connections (priv->settings, NULL); for (i = 0; connections[i]; i++) { NMSettingsConnection *connection = connections[i]; - con_stamp = nm_settings_connection_autoconnect_blocked_until_get (connection); + con_stamp = nm_settings_connection_autoconnect_retries_blocked_until (connection); if (con_stamp == 0) continue; @@ -1564,6 +1540,29 @@ reset_connections_retries (gpointer user_data) } static void +_connection_autoconnect_retries_set (NMPolicy *self, + NMSettingsConnection *connection, + int tries) +{ + NMPolicyPrivate *priv = NM_POLICY_GET_PRIVATE (self); + + nm_assert (NM_IS_SETTINGS_CONNECTION (connection)); + nm_assert (tries >= 0); + + nm_settings_connection_autoconnect_retries_set (connection, tries); + + if (tries == 0) { + /* Schedule a handler to reset retries count */ + if (!priv->reset_retries_id) { + gint32 retry_time = nm_settings_connection_autoconnect_retries_blocked_until (connection); + + g_warn_if_fail (retry_time != 0); + priv->reset_retries_id = g_timeout_add_seconds (MAX (0, retry_time - nm_utils_get_monotonic_timestamp_s ()), reset_connections_retries, self); + } + } +} + +static void activate_slave_connections (NMPolicy *self, NMDevice *device) { NMPolicyPrivate *priv = NM_POLICY_GET_PRIVATE (self); @@ -1571,7 +1570,8 @@ activate_slave_connections (NMPolicy *self, NMDevice *device) guint i; NMActRequest *req; gboolean internal_activation = FALSE; - gs_free NMSettingsConnection **connections = NULL; + NMSettingsConnection *const*connections; + gboolean changed; master_device = nm_device_get_iface (device); g_assert (master_device); @@ -1595,38 +1595,37 @@ activate_slave_connections (NMPolicy *self, NMDevice *device) internal_activation = subject && nm_auth_subject_is_internal (subject); } - connections = nm_settings_get_connections_sorted (priv->settings, NULL); + changed = FALSE; + connections = nm_settings_get_connections (priv->settings, NULL); for (i = 0; connections[i]; i++) { - NMConnection *slave; + NMSettingsConnection *connection = connections[i]; NMSettingConnection *s_slave_con; const char *slave_master; - slave = NM_CONNECTION (connections[i]); - - s_slave_con = nm_connection_get_setting_connection (slave); - g_assert (s_slave_con); + s_slave_con = nm_connection_get_setting_connection (NM_CONNECTION (connection)); slave_master = nm_setting_connection_get_master (s_slave_con); if (!slave_master) continue; + if (!NM_IN_STRSET (slave_master, master_device, + master_uuid_applied, + master_uuid_settings)) + continue; - if ( nm_streq0 (slave_master, master_device) - || nm_streq0 (slave_master, master_uuid_applied) - || nm_streq0 (slave_master, master_uuid_settings)) { - NMSettingsConnection *settings = NM_SETTINGS_CONNECTION (slave); - NMSettingsAutoconnectBlockedReason reason; - - if (!internal_activation) - nm_settings_connection_autoconnect_retries_reset (settings); - - reason = nm_settings_connection_autoconnect_blocked_reason_get (settings); - if (reason == NM_SETTINGS_AUTO_CONNECT_BLOCKED_REASON_FAILED) { - reason = NM_SETTINGS_AUTO_CONNECT_BLOCKED_REASON_NONE; - nm_settings_connection_autoconnect_blocked_reason_set (settings, reason); - } + if (!internal_activation) { + if (nm_settings_connection_autoconnect_retries_get (connection) == 0) + changed = TRUE; + nm_settings_connection_autoconnect_retries_reset (connection); + } + if (nm_settings_connection_autoconnect_blocked_reason_set (connection, + NM_SETTINGS_AUTO_CONNECT_BLOCKED_REASON_FAILED, + FALSE)) { + if (!nm_settings_connection_autoconnect_is_blocked (connection)) + changed = TRUE; } } - schedule_activate_all (self); + if (changed) + schedule_activate_all (self); } static gboolean @@ -1711,9 +1710,7 @@ device_state_changed (NMDevice *device, NMPolicyPrivate *priv = user_data; 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; @@ -1734,7 +1731,8 @@ device_state_changed (NMDevice *device, */ if (connection) { nm_settings_connection_autoconnect_blocked_reason_set (connection, - NM_SETTINGS_AUTO_CONNECT_BLOCKED_REASON_FAILED); + NM_SETTINGS_AUTO_CONNECT_BLOCKED_REASON_FAILED, + TRUE); } break; default: @@ -1749,36 +1747,40 @@ device_state_changed (NMDevice *device, if ( connection && old_state >= NM_DEVICE_STATE_PREPARE && old_state <= NM_DEVICE_STATE_ACTIVATED) { + gboolean block_no_secrets = FALSE; int tries; + guint64 con_v; - tries = nm_settings_connection_autoconnect_retries_get (connection); if (nm_device_state_reason_check (reason) == NM_DEVICE_STATE_REASON_NO_SECRETS) { + /* we want to block the connection from auto-connect if it failed due to no-secrets. + * However, if a secret-agent registered, since the connection made the last + * secret-request, we do not block it. The new secret-agent might not yet + * been consulted, and it may be able to provide the secrets. + * + * We detect this by using a version-id of the agent-manager, which increments + * whenever new agents register. */ + con_v = nm_settings_connection_get_last_secret_agent_version_id (connection); + if ( con_v == 0 + || con_v != nm_agent_manager_get_agent_version_id (priv->agent_mgr)) + block_no_secrets = TRUE; + } + + if (block_no_secrets) { _LOGD (LOGD_DEVICE, "connection '%s' now blocked from autoconnect due to no secrets", nm_settings_connection_get_id (connection)); - - nm_settings_connection_autoconnect_blocked_reason_set (connection, NM_SETTINGS_AUTO_CONNECT_BLOCKED_REASON_NO_SECRETS); - } else if (tries != 0) { + nm_settings_connection_autoconnect_blocked_reason_set (connection, NM_SETTINGS_AUTO_CONNECT_BLOCKED_REASON_NO_SECRETS, TRUE); + } else { + tries = nm_settings_connection_autoconnect_retries_get (connection); if (tries > 0) { _LOGD (LOGD_DEVICE, "connection '%s' failed to autoconnect; %d tries left", - nm_settings_connection_get_id (connection), tries); - nm_settings_connection_autoconnect_retries_set (connection, --tries); - } else { + nm_settings_connection_get_id (connection), tries - 1); + _connection_autoconnect_retries_set (self, connection, tries - 1); + } else if (tries != 0) { _LOGD (LOGD_DEVICE, "connection '%s' failed to autoconnect; infinite tries left", nm_settings_connection_get_id (connection)); } } - if (nm_settings_connection_autoconnect_retries_get (connection) == 0) { - _LOGI (LOGD_DEVICE, "disabling autoconnect for connection '%s'.", - nm_settings_connection_get_id (connection)); - /* Schedule a handler to reset retries count */ - if (!priv->reset_retries_id) { - gint32 retry_time = nm_settings_connection_autoconnect_blocked_until_get (connection); - - g_warn_if_fail (retry_time != 0); - priv->reset_retries_id = g_timeout_add_seconds (MAX (0, retry_time - nm_utils_get_monotonic_timestamp_s ()), reset_connections_retries, self); - } - } nm_connection_clear_secrets (NM_CONNECTION (connection)); } break; @@ -1800,10 +1802,10 @@ device_state_changed (NMDevice *device, ip4_config = nm_device_get_ip4_config (device); if (ip4_config) - nm_dns_manager_add_ip4_config (priv->dns_manager, ip_iface, 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_add_ip6_config (priv->dns_manager, ip_iface, 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); @@ -1815,13 +1817,25 @@ device_state_changed (NMDevice *device, update_routing_and_dns (self, FALSE); break; case NM_DEVICE_STATE_DEACTIVATING: - if (nm_device_state_reason_check (reason) == NM_DEVICE_STATE_REASON_USER_REQUESTED) { - if (connection) { - /* The connection was deactivated, so block just this connection */ - _LOGD (LOGD_DEVICE, "blocking autoconnect of connection '%s' by user request", - nm_settings_connection_get_id (connection)); - nm_settings_connection_autoconnect_blocked_reason_set (connection, - NM_SETTINGS_AUTO_CONNECT_BLOCKED_REASON_USER_REQUEST); + if (connection) { + NMSettingsAutoconnectBlockedReason blocked_reason = NM_SETTINGS_AUTO_CONNECT_BLOCKED_REASON_NONE; + + switch (nm_device_state_reason_check (reason)) { + case NM_DEVICE_STATE_REASON_USER_REQUESTED: + blocked_reason = NM_SETTINGS_AUTO_CONNECT_BLOCKED_REASON_USER_REQUEST; + break; + case NM_DEVICE_STATE_REASON_DEPENDENCY_FAILED: + blocked_reason = NM_SETTINGS_AUTO_CONNECT_BLOCKED_REASON_FAILED; + break; + default: + break; + } + if (blocked_reason != NM_SETTINGS_AUTO_CONNECT_BLOCKED_REASON_NONE) { + _LOGD (LOGD_DEVICE, "blocking autoconnect of connection '%s': %s", + nm_settings_connection_get_id (connection), + NM_UTILS_LOOKUP_STR (nm_device_state_reason_to_str, + nm_device_state_reason_check (reason))); + nm_settings_connection_autoconnect_blocked_reason_set (connection, blocked_reason, TRUE); } } ip6_remove_device_prefix_delegations (self, device); @@ -1832,7 +1846,7 @@ device_state_changed (NMDevice *device, */ if ( nm_device_state_reason_check (reason) == NM_DEVICE_STATE_REASON_CARRIER && old_state == NM_DEVICE_STATE_UNAVAILABLE) - reset_autoconnect_all (self, device); + reset_autoconnect_all (self, device, FALSE); if (old_state > NM_DEVICE_STATE_DISCONNECTED) update_routing_and_dns (self, FALSE); @@ -1858,7 +1872,7 @@ device_state_changed (NMDevice *device, case NM_DEVICE_STATE_IP_CONFIG: /* We must have secrets if we got here. */ if (connection) - nm_settings_connection_autoconnect_blocked_reason_set (connection, NM_SETTINGS_AUTO_CONNECT_BLOCKED_REASON_NONE); + nm_settings_connection_autoconnect_blocked_reason_set (connection, NM_SETTINGS_AUTO_CONNECT_BLOCKED_REASON_ALL, FALSE); break; case NM_DEVICE_STATE_SECONDARIES: if (connection) @@ -1903,17 +1917,17 @@ device_ip4_config_changed (NMDevice *device, if (nm_device_get_state (device) == NM_DEVICE_STATE_ACTIVATED) { if (old_config != new_config) { if (old_config) - nm_dns_manager_remove_ip4_config (priv->dns_manager, old_config); + nm_dns_manager_remove_ip_config (priv->dns_manager, old_config); if (new_config) - nm_dns_manager_add_ip4_config (priv->dns_manager, ip_iface, new_config, NM_DNS_IP_CONFIG_TYPE_DEFAULT); + nm_dns_manager_add_ip_config (priv->dns_manager, ip_iface, new_config, NM_DNS_IP_CONFIG_TYPE_DEFAULT); } - update_ip4_dns (self, priv->dns_manager); + 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_ip4_config (priv->dns_manager, old_config); + nm_dns_manager_remove_ip_config (priv->dns_manager, old_config); } nm_dns_manager_end_updates (priv->dns_manager, __func__); @@ -1939,17 +1953,17 @@ device_ip6_config_changed (NMDevice *device, if (nm_device_get_state (device) == NM_DEVICE_STATE_ACTIVATED) { if (old_config != new_config) { if (old_config) - nm_dns_manager_remove_ip6_config (priv->dns_manager, old_config); + nm_dns_manager_remove_ip_config (priv->dns_manager, old_config); if (new_config) - nm_dns_manager_add_ip6_config (priv->dns_manager, ip_iface, new_config, NM_DNS_IP_CONFIG_TYPE_DEFAULT); + nm_dns_manager_add_ip_config (priv->dns_manager, ip_iface, new_config, NM_DNS_IP_CONFIG_TYPE_DEFAULT); } - update_ip6_dns (self, priv->dns_manager); + 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_remove_ip6_config (priv->dns_manager, old_config); + nm_dns_manager_remove_ip_config (priv->dns_manager, old_config); } nm_dns_manager_end_updates (priv->dns_manager, __func__); @@ -2021,13 +2035,16 @@ device_removed (NMManager *manager, NMDevice *device, gpointer user_data) { NMPolicyPrivate *priv = user_data; NMPolicy *self = _PRIV_TO_SELF (priv); + ActivateData *data; /* XXX is this needed? The delegations are cleaned up * on transition to deactivated too. */ ip6_remove_device_prefix_delegations (self, device); /* Clear any idle callbacks for this device */ - clear_pending_activate_check (self, device); + data = find_pending_activation (self, device); + if (data && data->autoactivate_id) + activate_data_free (data); if (g_hash_table_remove (priv->devices, device)) devices_list_unregister (self, device); @@ -2055,11 +2072,11 @@ vpn_connection_activated (NMPolicy *self, NMVpnConnection *vpn) ip4_config = nm_vpn_connection_get_ip4_config (vpn); if (ip4_config) - nm_dns_manager_add_ip4_config (priv->dns_manager, ip_iface, 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_add_ip6_config (priv->dns_manager, ip_iface, 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); @@ -2078,13 +2095,13 @@ vpn_connection_deactivated (NMPolicy *self, NMVpnConnection *vpn) ip4_config = nm_vpn_connection_get_ip4_config (vpn); if (ip4_config) { /* Remove the VPN connection's IP4 config from DNS */ - nm_dns_manager_remove_ip4_config (priv->dns_manager, ip4_config); + nm_dns_manager_remove_ip_config (priv->dns_manager, ip4_config); } ip6_config = nm_vpn_connection_get_ip6_config (vpn); if (ip6_config) { /* Remove the VPN connection's IP6 config from DNS */ - nm_dns_manager_remove_ip6_config (priv->dns_manager, ip6_config); + nm_dns_manager_remove_ip_config (priv->dns_manager, ip6_config); } update_routing_and_dns (self, TRUE); @@ -2317,19 +2334,21 @@ connection_updated (NMSettings *settings, } static void -_deactivate_if_active (NMManager *manager, NMSettingsConnection *connection) +_deactivate_if_active (NMPolicy *self, NMSettingsConnection *connection) { - const GSList *active, *iter; + NMPolicyPrivate *priv = NM_POLICY_GET_PRIVATE (self); + NMActiveConnection *ac; + const CList *tmp_list; + GError *error = NULL; + + nm_assert (NM_IS_SETTINGS_CONNECTION (connection)); - active = nm_manager_get_active_connections (manager); - for (iter = active; iter; iter = g_slist_next (iter)) { - NMActiveConnection *ac = iter->data; + nm_manager_for_each_active_connection (priv->manager, ac, tmp_list) { NMActiveConnectionState state = nm_active_connection_get_state (ac); - GError *error = NULL; - if (nm_active_connection_get_settings_connection (ac) == connection && - (state <= NM_ACTIVE_CONNECTION_STATE_ACTIVATED)) { - if (!nm_manager_deactivate_connection (manager, + if ( nm_active_connection_get_settings_connection (ac) == connection + && (state <= NM_ACTIVE_CONNECTION_STATE_ACTIVATED)) { + if (!nm_manager_deactivate_connection (priv->manager, ac, NM_DEVICE_STATE_REASON_CONNECTION_REMOVED, &error)) { @@ -2349,22 +2368,25 @@ connection_removed (NMSettings *settings, gpointer user_data) { NMPolicyPrivate *priv = user_data; + NMPolicy *self = _PRIV_TO_SELF (priv); - _deactivate_if_active (priv->manager, connection); + _deactivate_if_active (self, connection); } static void -connection_visibility_changed (NMSettings *settings, - NMSettingsConnection *connection, - gpointer user_data) +connection_flags_changed (NMSettings *settings, + NMSettingsConnection *connection, + gpointer user_data) { NMPolicyPrivate *priv = user_data; NMPolicy *self = _PRIV_TO_SELF (priv); - if (nm_settings_connection_is_visible (connection)) - schedule_activate_all (self); - else - _deactivate_if_active (priv->manager, connection); + if (NM_FLAGS_HAS (nm_settings_connection_get_flags (connection), + NM_SETTINGS_CONNECTION_FLAGS_VISIBLE)) { + if (!nm_settings_connection_autoconnect_is_blocked (connection)) + schedule_activate_all (self); + } else + _deactivate_if_active (self, connection); } static void @@ -2372,15 +2394,14 @@ secret_agent_registered (NMSettings *settings, NMSecretAgent *agent, gpointer user_data) { - NMPolicyPrivate *priv = user_data; - NMPolicy *self = _PRIV_TO_SELF (priv); + NMPolicy *self = NM_POLICY (user_data); /* The registered secret agent may provide some missing secrets. Thus we * reset retries count here and schedule activation, so that the * connections failed due to missing secrets may re-try auto-connection. */ - reset_autoconnect_for_failed_secrets (self); - schedule_activate_all (self); + if (reset_autoconnect_all (self, NULL, TRUE)) + schedule_activate_all (self); } NMDevice * @@ -2476,6 +2497,8 @@ nm_policy_init (NMPolicy *self) NMPolicyPrivate *priv = NM_POLICY_GET_PRIVATE (self); const char *hostname_mode; + c_list_init (&priv->pending_activation_checks); + priv->netns = g_object_ref (nm_netns_get ()); priv->hostname_manager = g_object_ref (nm_hostname_manager_get ()); @@ -2516,6 +2539,8 @@ constructed (GObject *object) _LOGT (LOGD_DNS, "hostname-original: set to %s%s%s", NM_PRINT_FMT_QUOTE_STRING (priv->orig_hostname)); + priv->agent_mgr = g_object_ref (nm_agent_manager_get ()); + priv->firewall_manager = g_object_ref (nm_firewall_manager_get ()); g_signal_connect (priv->firewall_manager, NM_FIREWALL_MANAGER_STATE_CHANGED, G_CALLBACK (firewall_state_changed), self); @@ -2536,11 +2561,12 @@ constructed (GObject *object) g_signal_connect (priv->manager, NM_MANAGER_ACTIVE_CONNECTION_ADDED, (GCallback) active_connection_added, priv); g_signal_connect (priv->manager, NM_MANAGER_ACTIVE_CONNECTION_REMOVED, (GCallback) active_connection_removed, priv); - g_signal_connect (priv->settings, NM_SETTINGS_SIGNAL_CONNECTION_ADDED, (GCallback) connection_added, priv); - g_signal_connect (priv->settings, NM_SETTINGS_SIGNAL_CONNECTION_UPDATED, (GCallback) connection_updated, priv); - g_signal_connect (priv->settings, NM_SETTINGS_SIGNAL_CONNECTION_REMOVED, (GCallback) connection_removed, priv); - g_signal_connect (priv->settings, NM_SETTINGS_SIGNAL_CONNECTION_VISIBILITY_CHANGED, (GCallback) connection_visibility_changed, priv); - g_signal_connect (priv->settings, NM_SETTINGS_SIGNAL_AGENT_REGISTERED, (GCallback) secret_agent_registered, priv); + g_signal_connect (priv->settings, NM_SETTINGS_SIGNAL_CONNECTION_ADDED, (GCallback) connection_added, priv); + g_signal_connect (priv->settings, NM_SETTINGS_SIGNAL_CONNECTION_UPDATED, (GCallback) connection_updated, priv); + g_signal_connect (priv->settings, NM_SETTINGS_SIGNAL_CONNECTION_REMOVED, (GCallback) connection_removed, priv); + g_signal_connect (priv->settings, NM_SETTINGS_SIGNAL_CONNECTION_FLAGS_CHANGED, (GCallback) connection_flags_changed, priv); + + g_signal_connect (priv->agent_mgr, NM_AGENT_MANAGER_AGENT_REGISTERED, G_CALLBACK (secret_agent_registered), self); G_OBJECT_CLASS (nm_policy_parent_class)->constructed (object); @@ -2564,9 +2590,9 @@ dispose (GObject *object) { NMPolicy *self = NM_POLICY (object); NMPolicyPrivate *priv = NM_POLICY_GET_PRIVATE (self); - const GSList *connections; GHashTableIter h_iter; NMDevice *device; + ActivateData *data, *data_safe; nm_clear_g_cancellable (&priv->lookup.cancellable); g_clear_object (&priv->lookup.addr); @@ -2578,8 +2604,8 @@ dispose (GObject *object) nm_clear_g_object (&priv->activating_device6); g_clear_pointer (&priv->pending_active_connections, g_hash_table_unref); - while (priv->pending_activation_checks) - activate_data_free (priv->pending_activation_checks->data); + c_list_for_each_entry_safe (data, data_safe, &priv->pending_activation_checks, pending_lst) + activate_data_free (data); g_slist_free_full (priv->pending_secondaries, (GDestroyNotify) pending_secondary_data_free); priv->pending_secondaries = NULL; @@ -2589,6 +2615,11 @@ dispose (GObject *object) g_clear_object (&priv->firewall_manager); } + if (priv->agent_mgr) { + g_signal_handlers_disconnect_by_func (priv->agent_mgr, secret_agent_registered, self); + g_clear_object (&priv->agent_mgr); + } + if (priv->dns_manager) { nm_clear_g_signal_handler (priv->dns_manager, &priv->config_changed_id); g_clear_object (&priv->dns_manager); @@ -2604,8 +2635,7 @@ dispose (GObject *object) * will have called active_connection_removed() and thus we don't need * to clean anything up. Assert that this is TRUE. */ - connections = nm_manager_get_active_connections (priv->manager); - g_assert (connections == NULL); + nm_assert (c_list_is_empty (nm_manager_get_active_connections (priv->manager))); nm_clear_g_source (&priv->reset_retries_id); nm_clear_g_source (&priv->schedule_activate_all_id); diff --git a/src/nm-sleep-monitor.c b/src/nm-sleep-monitor.c index 037db11b..7a373874 100644 --- a/src/nm-sleep-monitor.c +++ b/src/nm-sleep-monitor.c @@ -134,7 +134,7 @@ drop_inhibitor (NMSleepMonitor *self, gboolean force) if (self->inhibit_fd >= 0) { _LOGD ("inhibit: dropping sleep inhibitor %d", self->inhibit_fd); - close (self->inhibit_fd); + nm_close (self->inhibit_fd); self->inhibit_fd = -1; } diff --git a/src/nm-types.h b/src/nm-types.h index e01c48b0..cc657397 100644 --- a/src/nm-types.h +++ b/src/nm-types.h @@ -15,7 +15,7 @@ * with this program; if not, write to the Free Software Foundation, Inc., * 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA. * - * Copyright (C) 2012 Red Hat, Inc. + * Copyright (C) 2012 - 2017 Red Hat, Inc. */ #ifndef __NETWORKMANAGER_TYPES_H__ @@ -42,6 +42,7 @@ typedef struct _NMDevice NMDevice; typedef struct _NMDhcp4Config NMDhcp4Config; typedef struct _NMDhcp6Config NMDhcp6Config; typedef struct _NMProxyConfig NMProxyConfig; +typedef struct _NMIPConfig NMIPConfig; typedef struct _NMIP4Config NMIP4Config; typedef struct _NMIP6Config NMIP6Config; typedef struct _NMManager NMManager; @@ -176,6 +177,10 @@ typedef enum { NMP_OBJECT_TYPE_IP4_ROUTE, NMP_OBJECT_TYPE_IP6_ROUTE, + NMP_OBJECT_TYPE_QDISC, + + NMP_OBJECT_TYPE_TFILTER, + NMP_OBJECT_TYPE_LNK_GRE, NMP_OBJECT_TYPE_LNK_INFINIBAND, NMP_OBJECT_TYPE_LNK_IP6TNL, diff --git a/src/platform/nm-fake-platform.c b/src/platform/nm-fake-platform.c index c199c5ed..be430152 100644 --- a/src/platform/nm-fake-platform.c +++ b/src/platform/nm-fake-platform.c @@ -15,7 +15,7 @@ * with this program; if not, write to the Free Software Foundation, Inc., * 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA. * - * Copyright (C) 2012–2013 Red Hat, Inc. + * Copyright (C) 2012–2017 Red Hat, Inc. */ #include "nm-default.h" @@ -1056,11 +1056,11 @@ ipx_address_delete (NMPlatform *platform, peer_addr_i = peer_addr ? *((guint32 *) peer_addr) : 0; nmp_cache_iter_for_each (&iter, - nm_platform_lookup_addrroute (platform, - addr_family == AF_INET - ? NMP_OBJECT_TYPE_IP4_ADDRESS - : NMP_OBJECT_TYPE_IP6_ADDRESS, - 0), + nm_platform_lookup_object (platform, + addr_family == AF_INET + ? NMP_OBJECT_TYPE_IP4_ADDRESS + : NMP_OBJECT_TYPE_IP6_ADDRESS, + 0), &o) { const NMPObject *obj_old = NULL; @@ -1144,9 +1144,9 @@ ipx_route_delete (NMPlatform *platform, } nmp_cache_iter_for_each (&iter, - nm_platform_lookup_addrroute (platform, - obj_type, - ifindex), + nm_platform_lookup_object (platform, + obj_type, + ifindex), &o) { const NMPObject *obj_old = NULL; @@ -1190,7 +1190,7 @@ ipx_route_delete (NMPlatform *platform, } static gboolean -ip_route_delete (NMPlatform *platform, const NMPObject *obj) +object_delete (NMPlatform *platform, const NMPObject *obj) { g_assert (NM_IS_FAKE_PLATFORM (platform)); g_assert (NM_IN_SET (NMP_OBJECT_GET_TYPE (obj), NMP_OBJECT_TYPE_IP4_ROUTE, @@ -1254,9 +1254,9 @@ ip_route_add (NMPlatform *platform, gboolean has_route_to_gw = FALSE; nmp_cache_iter_for_each (&iter, - nm_platform_lookup_addrroute (platform, - NMP_OBJECT_GET_TYPE (obj), - 0), + nm_platform_lookup_object (platform, + NMP_OBJECT_GET_TYPE (obj), + 0), &o) { if (addr_family == AF_INET) { const NMPlatformIP4Route *item = NMP_OBJECT_CAST_IP4_ROUTE (o); @@ -1462,5 +1462,5 @@ nm_fake_platform_class_init (NMFakePlatformClass *klass) platform_class->ip6_address_delete = ip6_address_delete; platform_class->ip_route_add = ip_route_add; - platform_class->ip_route_delete = ip_route_delete; + platform_class->object_delete = object_delete; } diff --git a/src/platform/nm-linux-platform.c b/src/platform/nm-linux-platform.c index c4c93ed3..10d1a6ef 100644 --- a/src/platform/nm-linux-platform.c +++ b/src/platform/nm-linux-platform.c @@ -15,7 +15,7 @@ * with this program; if not, write to the Free Software Foundation, Inc., * 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA. * - * Copyright (C) 2012-2015 Red Hat, Inc. + * Copyright (C) 2012 - 2017 Red Hat, Inc. */ #include "nm-default.h" @@ -54,6 +54,29 @@ #include "nm-utils/unaligned.h" #include "nm-utils/nm-udev-utils.h" +/*****************************************************************************/ + +/* re-implement <linux/tc_act/tc_defact.h> to build against kernel + * headers that lack this. */ + +#include <linux/pkt_cls.h> + +struct tc_defact { + tc_gen; +}; + +enum { + TCA_DEF_UNSPEC, + TCA_DEF_TM, + TCA_DEF_PARMS, + TCA_DEF_DATA, + TCA_DEF_PAD, + __TCA_DEF_MAX +}; +#define TCA_DEF_MAX (__TCA_DEF_MAX - 1) + +/*****************************************************************************/ + #define VLAN_FLAG_MVRP 0x8 /* nm-internal error codes for libnl. Make sure they don't overlap. */ @@ -227,27 +250,33 @@ enum { DELAYED_ACTION_IDX_REFRESH_ALL_IP6_ADDRESSES, DELAYED_ACTION_IDX_REFRESH_ALL_IP4_ROUTES, DELAYED_ACTION_IDX_REFRESH_ALL_IP6_ROUTES, + DELAYED_ACTION_IDX_REFRESH_ALL_QDISCS, + DELAYED_ACTION_IDX_REFRESH_ALL_TFILTERS, _DELAYED_ACTION_IDX_REFRESH_ALL_NUM, }; typedef enum { DELAYED_ACTION_TYPE_NONE = 0, - DELAYED_ACTION_TYPE_REFRESH_ALL_LINKS = (1LL << DELAYED_ACTION_IDX_REFRESH_ALL_LINKS), - DELAYED_ACTION_TYPE_REFRESH_ALL_IP4_ADDRESSES = (1LL << DELAYED_ACTION_IDX_REFRESH_ALL_IP4_ADDRESSES), - DELAYED_ACTION_TYPE_REFRESH_ALL_IP6_ADDRESSES = (1LL << DELAYED_ACTION_IDX_REFRESH_ALL_IP6_ADDRESSES), - DELAYED_ACTION_TYPE_REFRESH_ALL_IP4_ROUTES = (1LL << DELAYED_ACTION_IDX_REFRESH_ALL_IP4_ROUTES), - DELAYED_ACTION_TYPE_REFRESH_ALL_IP6_ROUTES = (1LL << DELAYED_ACTION_IDX_REFRESH_ALL_IP6_ROUTES), - DELAYED_ACTION_TYPE_REFRESH_LINK = (1LL << 5), - DELAYED_ACTION_TYPE_MASTER_CONNECTED = (1LL << 6), - DELAYED_ACTION_TYPE_READ_NETLINK = (1LL << 7), - DELAYED_ACTION_TYPE_WAIT_FOR_NL_RESPONSE = (1LL << 8), + DELAYED_ACTION_TYPE_REFRESH_ALL_LINKS = (1LL << /* 0 */ DELAYED_ACTION_IDX_REFRESH_ALL_LINKS), + DELAYED_ACTION_TYPE_REFRESH_ALL_IP4_ADDRESSES = (1LL << /* 1 */ DELAYED_ACTION_IDX_REFRESH_ALL_IP4_ADDRESSES), + DELAYED_ACTION_TYPE_REFRESH_ALL_IP6_ADDRESSES = (1LL << /* 2 */ DELAYED_ACTION_IDX_REFRESH_ALL_IP6_ADDRESSES), + DELAYED_ACTION_TYPE_REFRESH_ALL_IP4_ROUTES = (1LL << /* 3 */ DELAYED_ACTION_IDX_REFRESH_ALL_IP4_ROUTES), + DELAYED_ACTION_TYPE_REFRESH_ALL_IP6_ROUTES = (1LL << /* 4 */ DELAYED_ACTION_IDX_REFRESH_ALL_IP6_ROUTES), + DELAYED_ACTION_TYPE_REFRESH_ALL_QDISCS = (1LL << /* 5 */ DELAYED_ACTION_IDX_REFRESH_ALL_QDISCS), + DELAYED_ACTION_TYPE_REFRESH_ALL_TFILTERS = (1LL << /* 6 */ DELAYED_ACTION_IDX_REFRESH_ALL_TFILTERS), + DELAYED_ACTION_TYPE_REFRESH_LINK = (1LL << 7), + DELAYED_ACTION_TYPE_MASTER_CONNECTED = (1LL << 11), + DELAYED_ACTION_TYPE_READ_NETLINK = (1LL << 12), + DELAYED_ACTION_TYPE_WAIT_FOR_NL_RESPONSE = (1LL << 13), __DELAYED_ACTION_TYPE_MAX, DELAYED_ACTION_TYPE_REFRESH_ALL = DELAYED_ACTION_TYPE_REFRESH_ALL_LINKS | DELAYED_ACTION_TYPE_REFRESH_ALL_IP4_ADDRESSES | DELAYED_ACTION_TYPE_REFRESH_ALL_IP6_ADDRESSES | DELAYED_ACTION_TYPE_REFRESH_ALL_IP4_ROUTES | - DELAYED_ACTION_TYPE_REFRESH_ALL_IP6_ROUTES, + DELAYED_ACTION_TYPE_REFRESH_ALL_IP6_ROUTES | + DELAYED_ACTION_TYPE_REFRESH_ALL_QDISCS | + DELAYED_ACTION_TYPE_REFRESH_ALL_TFILTERS, DELAYED_ACTION_TYPE_MAX = __DELAYED_ACTION_TYPE_MAX -1, } DelayedActionType; @@ -941,17 +970,25 @@ _nl_nlmsghdr_to_str (const struct nlmsghdr *hdr, char *buf, gsize len) b = buf; switch (hdr->nlmsg_type) { - case RTM_NEWLINK: s = "NEWLINK"; break; - case RTM_DELLINK: s = "DELLINK"; break; - case RTM_NEWADDR: s = "NEWADDR"; break; - case RTM_DELADDR: s = "DELADDR"; break; - case RTM_NEWROUTE: s = "NEWROUTE"; break; - case RTM_DELROUTE: s = "DELROUTE"; break; - default: s = NULL; break; + 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 (&buf, &len, "RTM_%s", s); + nm_utils_strbuf_append_str (&buf, &len, s); else nm_utils_strbuf_append (&buf, &len, "(%u)", (unsigned) hdr->nlmsg_type); @@ -989,6 +1026,8 @@ _nl_nlmsghdr_to_str (const struct nlmsghdr *hdr, char *buf, gsize len) 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"); @@ -997,6 +1036,8 @@ _nl_nlmsghdr_to_str (const struct nlmsghdr *hdr, char *buf, gsize len) 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"); @@ -2291,17 +2332,7 @@ _new_from_nl_route (struct nlmsghdr *nlh, gboolean id_only) obj->ip6_route.rt_pref = nla_get_u8 (tb[RTA_PREF]); } - if (NM_FLAGS_HAS (rtm->rtm_flags, RTM_F_CLONED)) { - /* we must not straight way reject cloned routes, because we might have cached - * a non-cloned route. If we now receive an update of the route with the route - * being cloned, we must still return the object, so that we can remove the old - * one from the cache. - * - * This happens, because this route is not nmp_object_is_alive(). - * */ - obj->ip_route.rt_cloned = TRUE; - } - + obj->ip_route.r_rtm_flags = rtm->rtm_flags; obj->ip_route.rt_source = nmp_utils_ip_config_source_from_rtprot (rtm->rtm_protocol); obj_result = obj; @@ -2310,6 +2341,74 @@ errout: return obj_result; } +static NMPObject * +_new_from_nl_qdisc (struct nlmsghdr *nlh, gboolean id_only) +{ + NMPObject *obj = NULL; + const struct tcmsg *tcm; + struct nlattr *tb[TCA_MAX + 1]; + int err; + static const struct nla_policy policy[TCA_MAX + 1] = { + [TCA_KIND] = { .type = NLA_STRING }, + }; + + if (!nlmsg_valid_hdr (nlh, sizeof (*tcm))) + return NULL; + tcm = nlmsg_data (nlh); + + err = nlmsg_parse (nlh, sizeof (*tcm), tb, TCA_MAX, policy); + if (err < 0) + return NULL; + + if (!tb[TCA_KIND]) + return NULL; + + obj = nmp_object_new (NMP_OBJECT_TYPE_QDISC, NULL); + + obj->qdisc.kind = g_intern_string (nla_get_string (tb[TCA_KIND])); + obj->qdisc.ifindex = tcm->tcm_ifindex; + obj->qdisc.addr_family = tcm->tcm_family; + obj->qdisc.handle = tcm->tcm_handle; + obj->qdisc.parent = tcm->tcm_parent; + obj->qdisc.info = tcm->tcm_info; + + return obj; +} + +static NMPObject * +_new_from_nl_tfilter (struct nlmsghdr *nlh, gboolean id_only) +{ + NMPObject *obj = NULL; + const struct tcmsg *tcm; + struct nlattr *tb[TCA_MAX + 1]; + int err; + static const struct nla_policy policy[TCA_MAX + 1] = { + [TCA_KIND] = { .type = NLA_STRING }, + }; + + if (!nlmsg_valid_hdr (nlh, sizeof (*tcm))) + return NULL; + tcm = nlmsg_data (nlh); + + err = nlmsg_parse (nlh, sizeof (*tcm), tb, TCA_MAX, policy); + if (err < 0) + return NULL; + + if (!tb[TCA_KIND]) + return NULL; + + obj = nmp_object_new (NMP_OBJECT_TYPE_TFILTER, NULL); + + obj->tfilter.kind = g_intern_string (nla_get_string (tb[TCA_KIND])); + obj->tfilter.ifindex = tcm->tcm_ifindex; + obj->tfilter.addr_family = tcm->tcm_family; + obj->tfilter.handle = tcm->tcm_handle; + obj->tfilter.parent = tcm->tcm_parent; + obj->tfilter.info = tcm->tcm_info; + + return obj; +} + /** * nmp_object_new_from_nl: * @platform: (allow-none): for creating certain objects, the constructor wants to check @@ -2346,6 +2445,14 @@ nmp_object_new_from_nl (NMPlatform *platform, const NMPCache *cache, struct nl_m case RTM_DELROUTE: case RTM_GETROUTE: return _new_from_nl_route (msghdr, id_only); + case RTM_NEWQDISC: + case RTM_DELQDISC: + case RTM_GETQDISC: + return _new_from_nl_qdisc (msghdr, id_only); + case RTM_NEWTFILTER: + case RTM_DELTFILTER: + case RTM_GETTFILTER: + return _new_from_nl_tfilter (msghdr, id_only); default: return NULL; } @@ -2700,7 +2807,9 @@ _nl_msg_new_route (int nlmsg_type, ? nm_platform_route_scope_inv (obj->ip4_route.scope_inv) : RT_SCOPE_NOWHERE, .rtm_type = RTN_UNICAST, - .rtm_flags = 0, + .rtm_flags = obj->ip_route.r_rtm_flags & (is_v4 + ? (unsigned) (RTNH_F_ONLINK) + : (unsigned) 0), .rtm_dst_len = obj->ip_route.plen, .rtm_src_len = is_v4 ? 0 @@ -2797,6 +2906,124 @@ nla_put_failure: g_return_val_if_reached (NULL); } +static struct nl_msg * +_nl_msg_new_qdisc (int nlmsg_type, + int nlmsg_flags, + const NMPlatformQdisc *qdisc) +{ + struct nl_msg *msg; + struct tcmsg tcm = { + .tcm_family = qdisc->addr_family, + .tcm_ifindex = qdisc->ifindex, + .tcm_handle = qdisc->handle, + .tcm_parent = qdisc->parent, + .tcm_info = qdisc->info, + }; + + 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; + + NLA_PUT_STRING (msg, TCA_KIND, qdisc->kind); + + return msg; +nla_put_failure: + nlmsg_free (msg); + g_return_val_if_reached (NULL); +} + +static gboolean +_add_action_simple (struct nl_msg *msg, + const NMPlatformActionSimple *simple) +{ + struct nlattr *act_options; + struct tc_defact sel = { 0, }; + + if (!(act_options = nla_nest_start (msg, TCA_ACT_OPTIONS))) + goto nla_put_failure; + + NLA_PUT (msg, TCA_DEF_PARMS, sizeof (sel), &sel); + NLA_PUT (msg, TCA_DEF_DATA, sizeof (simple->sdata), simple->sdata); + + nla_nest_end (msg, act_options); + + return TRUE; + +nla_put_failure: + return FALSE; +} + +static gboolean +_add_action (struct nl_msg *msg, + const NMPlatformAction *action) +{ + struct nlattr *prio; + + nm_assert (action || action->kind); + + if (!(prio = nla_nest_start (msg, 1 /* priority */))) + goto nla_put_failure; + + NLA_PUT_STRING (msg, TCA_ACT_KIND, action->kind); + + if (nm_streq (action->kind, NM_PLATFORM_ACTION_KIND_SIMPLE)) + _add_action_simple (msg, &action->simple); + + nla_nest_end (msg, prio); + + return TRUE; + +nla_put_failure: + return FALSE; +} + +static struct nl_msg * +_nl_msg_new_tfilter (int nlmsg_type, + int nlmsg_flags, + const NMPlatformTfilter *tfilter) +{ + struct nl_msg *msg; + struct nlattr *tc_options; + struct nlattr *act_tab; + struct tcmsg tcm = { + .tcm_family = tfilter->addr_family, + .tcm_ifindex = tfilter->ifindex, + .tcm_handle = tfilter->handle, + .tcm_parent = tfilter->parent, + .tcm_info = tfilter->info, + }; + + 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; + + NLA_PUT_STRING (msg, TCA_KIND, tfilter->kind); + + if (!(tc_options = nla_nest_start (msg, TCA_OPTIONS))) + goto nla_put_failure; + + if (!(act_tab = nla_nest_start (msg, TCA_OPTIONS))) // 3 TCA_ACT_KIND TCA_ACT_KIND + goto nla_put_failure; + + if (tfilter->action.kind) + _add_action (msg, &tfilter->action); + + nla_nest_end (msg, tc_options); + + nla_nest_end (msg, act_tab); + + return msg; +nla_put_failure: + nlmsg_free (msg); + g_return_val_if_reached (NULL); +} + /****************************************************************** * NMPlatform types and functions ******************************************************************/ @@ -2867,7 +3094,7 @@ struct _NMLinuxPlatformClass { G_DEFINE_TYPE (NMLinuxPlatform, nm_linux_platform, NM_TYPE_PLATFORM) -#define NM_LINUX_PLATFORM_GET_PRIVATE(self) _NM_GET_PRIVATE_VOID(self, NMLinuxPlatform, NM_IS_LINUX_PLATFORM) +#define NM_LINUX_PLATFORM_GET_PRIVATE(self) _NM_GET_PRIVATE (self, NMLinuxPlatform, NM_IS_LINUX_PLATFORM, NMPlatform) NMPlatform * nm_linux_platform_new (gboolean log_with_ptr, gboolean netns_support) @@ -3198,6 +3425,8 @@ _NM_UTILS_LOOKUP_DEFINE (static, delayed_action_refresh_from_object_type, NMPObj NM_UTILS_LOOKUP_ITEM (NMP_OBJECT_TYPE_IP6_ADDRESS, DELAYED_ACTION_TYPE_REFRESH_ALL_IP6_ADDRESSES), NM_UTILS_LOOKUP_ITEM (NMP_OBJECT_TYPE_IP4_ROUTE, DELAYED_ACTION_TYPE_REFRESH_ALL_IP4_ROUTES), NM_UTILS_LOOKUP_ITEM (NMP_OBJECT_TYPE_IP6_ROUTE, DELAYED_ACTION_TYPE_REFRESH_ALL_IP6_ROUTES), + NM_UTILS_LOOKUP_ITEM (NMP_OBJECT_TYPE_QDISC, DELAYED_ACTION_TYPE_REFRESH_ALL_QDISCS), + NM_UTILS_LOOKUP_ITEM (NMP_OBJECT_TYPE_TFILTER, DELAYED_ACTION_TYPE_REFRESH_ALL_TFILTERS), NM_UTILS_LOOKUP_ITEM_IGNORE_OTHER (), ); @@ -3208,6 +3437,8 @@ _NM_UTILS_LOOKUP_DEFINE (static, delayed_action_refresh_to_object_type, DelayedA NM_UTILS_LOOKUP_ITEM (DELAYED_ACTION_TYPE_REFRESH_ALL_IP6_ADDRESSES, NMP_OBJECT_TYPE_IP6_ADDRESS), NM_UTILS_LOOKUP_ITEM (DELAYED_ACTION_TYPE_REFRESH_ALL_IP4_ROUTES, NMP_OBJECT_TYPE_IP4_ROUTE), NM_UTILS_LOOKUP_ITEM (DELAYED_ACTION_TYPE_REFRESH_ALL_IP6_ROUTES, NMP_OBJECT_TYPE_IP6_ROUTE), + NM_UTILS_LOOKUP_ITEM (DELAYED_ACTION_TYPE_REFRESH_ALL_QDISCS, NMP_OBJECT_TYPE_QDISC), + NM_UTILS_LOOKUP_ITEM (DELAYED_ACTION_TYPE_REFRESH_ALL_TFILTERS, NMP_OBJECT_TYPE_TFILTER), NM_UTILS_LOOKUP_ITEM_IGNORE_OTHER (), ); @@ -3218,6 +3449,8 @@ _NM_UTILS_LOOKUP_DEFINE (static, delayed_action_refresh_all_to_idx, DelayedActio NM_UTILS_LOOKUP_ITEM (DELAYED_ACTION_TYPE_REFRESH_ALL_IP6_ADDRESSES, DELAYED_ACTION_IDX_REFRESH_ALL_IP6_ADDRESSES), NM_UTILS_LOOKUP_ITEM (DELAYED_ACTION_TYPE_REFRESH_ALL_IP4_ROUTES, DELAYED_ACTION_IDX_REFRESH_ALL_IP4_ROUTES), NM_UTILS_LOOKUP_ITEM (DELAYED_ACTION_TYPE_REFRESH_ALL_IP6_ROUTES, DELAYED_ACTION_IDX_REFRESH_ALL_IP6_ROUTES), + NM_UTILS_LOOKUP_ITEM (DELAYED_ACTION_TYPE_REFRESH_ALL_QDISCS, DELAYED_ACTION_IDX_REFRESH_ALL_QDISCS), + NM_UTILS_LOOKUP_ITEM (DELAYED_ACTION_TYPE_REFRESH_ALL_TFILTERS, DELAYED_ACTION_IDX_REFRESH_ALL_TFILTERS), NM_UTILS_LOOKUP_ITEM_IGNORE_OTHER (), ); @@ -3228,6 +3461,8 @@ NM_UTILS_LOOKUP_STR_DEFINE_STATIC (delayed_action_to_string, DelayedActionType, NM_UTILS_LOOKUP_STR_ITEM (DELAYED_ACTION_TYPE_REFRESH_ALL_IP6_ADDRESSES, "refresh-all-ip6-addresses"), NM_UTILS_LOOKUP_STR_ITEM (DELAYED_ACTION_TYPE_REFRESH_ALL_IP4_ROUTES, "refresh-all-ip4-routes"), NM_UTILS_LOOKUP_STR_ITEM (DELAYED_ACTION_TYPE_REFRESH_ALL_IP6_ROUTES, "refresh-all-ip6-routes"), + NM_UTILS_LOOKUP_STR_ITEM (DELAYED_ACTION_TYPE_REFRESH_ALL_QDISCS, "refresh-all-qdiscs"), + NM_UTILS_LOOKUP_STR_ITEM (DELAYED_ACTION_TYPE_REFRESH_ALL_TFILTERS, "refresh-all-tfilters"), NM_UTILS_LOOKUP_STR_ITEM (DELAYED_ACTION_TYPE_REFRESH_LINK, "refresh-link"), NM_UTILS_LOOKUP_STR_ITEM (DELAYED_ACTION_TYPE_MASTER_CONNECTED, "master-connected"), NM_UTILS_LOOKUP_STR_ITEM (DELAYED_ACTION_TYPE_READ_NETLINK, "read-netlink"), @@ -3665,7 +3900,7 @@ cache_on_change (NMPlatform *platform, { int ifindex = 0; - /* if we remove a link (from netlink), we must refresh the addresses and routes */ + /* if we remove a link (from netlink), we must refresh the addresses, routes, qdiscs and tfilters */ if ( cache_op == NMP_CACHE_OPS_REMOVED && obj_old /* <-- nonsensical, make coverity happy */) ifindex = obj_old->link.ifindex; @@ -3680,7 +3915,9 @@ cache_on_change (NMPlatform *platform, DELAYED_ACTION_TYPE_REFRESH_ALL_IP4_ADDRESSES | DELAYED_ACTION_TYPE_REFRESH_ALL_IP6_ADDRESSES | DELAYED_ACTION_TYPE_REFRESH_ALL_IP4_ROUTES | - DELAYED_ACTION_TYPE_REFRESH_ALL_IP6_ROUTES, + DELAYED_ACTION_TYPE_REFRESH_ALL_IP6_ROUTES | + DELAYED_ACTION_TYPE_REFRESH_ALL_QDISCS | + DELAYED_ACTION_TYPE_REFRESH_ALL_TFILTERS, NULL); } } @@ -4003,9 +4240,6 @@ do_request_all_no_delayed_actions (NMPlatform *platform, DelayedActionType actio NMPObjectType obj_type = delayed_action_refresh_to_object_type (iflags); const NMPClass *klass = nmp_class_from_type (obj_type); nm_auto_nlmsg struct nl_msg *nlmsg = NULL; - struct rtgenmsg gmsg = { - .rtgen_family = klass->addr_family, - }; int nle; gint *out_refresh_all_in_progess; @@ -4032,7 +4266,18 @@ do_request_all_no_delayed_actions (NMPlatform *platform, DelayedActionType actio if (!nlmsg) continue; - nle = nlmsg_append (nlmsg, &gmsg, sizeof (gmsg), NLMSG_ALIGNTO); + if ( klass->obj_type == NMP_OBJECT_TYPE_QDISC + || klass->obj_type == NMP_OBJECT_TYPE_TFILTER) { + struct tcmsg tcmsg = { + .tcm_family = AF_UNSPEC, + }; + nle = nlmsg_append (nlmsg, &tcmsg, sizeof (tcmsg), NLMSG_ALIGNTO); + } else { + struct rtgenmsg gmsg = { + .rtgen_family = klass->addr_family, + }; + nle = nlmsg_append (nlmsg, &gmsg, sizeof (gmsg), NLMSG_ALIGNTO); + } if (nle < 0) continue; @@ -4154,6 +4399,8 @@ event_valid_msg (NMPlatform *platform, struct nl_msg *msg, gboolean handle_event case RTM_NEWADDR: case RTM_NEWLINK: case RTM_NEWROUTE: + case RTM_NEWQDISC: + case RTM_NEWTFILTER: is_dump = delayed_action_refresh_all_in_progress (platform, delayed_action_refresh_from_object_type (NMP_OBJECT_GET_TYPE (obj))); break; @@ -4177,6 +4424,8 @@ event_valid_msg (NMPlatform *platform, struct nl_msg *msg, gboolean handle_event case RTM_NEWLINK: case RTM_NEWADDR: case RTM_GETLINK: + case RTM_NEWQDISC: + case RTM_NEWTFILTER: cache_op = nmp_cache_update_netlink (cache, obj, is_dump, &obj_old, &obj_new); if (cache_op != NMP_CACHE_OPS_UNCHANGED) { cache_on_change (platform, cache_op, obj_old, obj_new); @@ -4189,7 +4438,7 @@ event_valid_msg (NMPlatform *platform, struct nl_msg *msg, gboolean handle_event gboolean resync_required = FALSE; gboolean only_dirty = FALSE; - if (obj->ip_route.rt_cloned) { + if (NM_FLAGS_HAS (obj->ip_route.r_rtm_flags, RTM_F_CLONED)) { /* a cloned route might be a response for RTM_GETROUTE. Check, whether it is. */ nm_assert (!nmp_object_is_alive (obj)); priv = NM_LINUX_PLATFORM_GET_PRIVATE (platform); @@ -4270,13 +4519,14 @@ event_valid_msg (NMPlatform *platform, struct nl_msg *msg, gboolean handle_event case RTM_DELLINK: case RTM_DELADDR: case RTM_DELROUTE: + case RTM_DELQDISC: + case RTM_DELTFILTER: cache_op = nmp_cache_remove_netlink (cache, obj, &obj_old, &obj_new); if (cache_op != NMP_CACHE_OPS_UNCHANGED) { cache_on_change (platform, cache_op, obj_old, obj_new); nm_platform_cache_update_emit_signal (platform, cache_op, obj_old, obj_new); } break; - default: break; } @@ -5652,7 +5902,7 @@ tun_add (NMPlatform *platform, const char *name, gboolean tap, if (out_link) *out_link = obj ? &obj->link : NULL; - close (fd); + nm_close (fd); return !!obj; } @@ -5886,15 +6136,15 @@ link_can_assume (NMPlatform *platform, int ifindex) if (link->link.master > 0) return TRUE; - nmp_lookup_init_addrroute (&lookup, - NMP_OBJECT_TYPE_IP4_ADDRESS, - ifindex); + nmp_lookup_init_object (&lookup, + NMP_OBJECT_TYPE_IP4_ADDRESS, + ifindex); if (nmp_cache_lookup (cache, &lookup)) return TRUE; - nmp_lookup_init_addrroute (&lookup, - NMP_OBJECT_TYPE_IP6_ADDRESS, - ifindex); + nmp_lookup_init_object (&lookup, + NMP_OBJECT_TYPE_IP6_ADDRESS, + ifindex); nmp_cache_iter_for_each (&iter, nmp_cache_lookup (cache, &lookup), &o) { @@ -6120,19 +6370,30 @@ ip_route_add (NMPlatform *platform, } static gboolean -ip_route_delete (NMPlatform *platform, - const NMPObject *obj) +object_delete (NMPlatform *platform, + const NMPObject *obj) { nm_auto_nmpobj const NMPObject *obj_keep_alive = NULL; nm_auto_nlmsg struct nl_msg *nlmsg = NULL; - nm_assert (NM_IN_SET (NMP_OBJECT_GET_TYPE (obj), NMP_OBJECT_TYPE_IP4_ROUTE, - NMP_OBJECT_TYPE_IP6_ROUTE)); - if (!NMP_OBJECT_IS_STACKINIT (obj)) obj_keep_alive = nmp_object_ref (obj); - nlmsg = _nl_msg_new_route (RTM_DELROUTE, 0, obj); + switch (NMP_OBJECT_GET_TYPE (obj)) { + case NMP_OBJECT_TYPE_IP4_ROUTE: + case NMP_OBJECT_TYPE_IP6_ROUTE: + nlmsg = _nl_msg_new_route (RTM_DELROUTE, 0, obj); + break; + case NMP_OBJECT_TYPE_QDISC: + nlmsg = _nl_msg_new_qdisc (RTM_DELQDISC, 0, NMP_OBJECT_CAST_QDISC (obj)); + break; + case NMP_OBJECT_TYPE_TFILTER: + nlmsg = _nl_msg_new_tfilter (RTM_DELTFILTER, 0, NMP_OBJECT_CAST_TFILTER (obj)); + break; + default: + break; + } + if (!nlmsg) g_return_val_if_reached (FALSE); return do_delete_object (platform, obj, nlmsg); @@ -6219,6 +6480,84 @@ ip_route_get (NMPlatform *platform, /*****************************************************************************/ +static NMPlatformError +qdisc_add (NMPlatform *platform, + NMPNlmFlags flags, + const NMPlatformQdisc *qdisc) +{ + WaitForNlResponseResult seq_result = WAIT_FOR_NL_RESPONSE_RESULT_UNKNOWN; + int nle; + char s_buf[256]; + nm_auto_nlmsg struct nl_msg *msg = NULL; + + msg = _nl_msg_new_qdisc (RTM_NEWQDISC, flags, qdisc); + + event_handler_read_netlink (platform, FALSE); + + 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); + return NM_PLATFORM_ERROR_NETLINK; + } + + delayed_action_handle_all (platform, FALSE); + + nm_assert (seq_result); + + _NMLOG (seq_result == WAIT_FOR_NL_RESPONSE_RESULT_RESPONSE_OK + ? LOGL_DEBUG + : LOGL_WARN, + "do-add-qdisc: %s", + 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; + + return NM_PLATFORM_ERROR_UNSPECIFIED; +} + +/*****************************************************************************/ + +static NMPlatformError +tfilter_add (NMPlatform *platform, + NMPNlmFlags flags, + const NMPlatformTfilter *tfilter) +{ + WaitForNlResponseResult seq_result = WAIT_FOR_NL_RESPONSE_RESULT_UNKNOWN; + int nle; + char s_buf[256]; + nm_auto_nlmsg struct nl_msg *msg = NULL; + + msg = _nl_msg_new_tfilter (RTM_NEWTFILTER, flags, tfilter); + + event_handler_read_netlink (platform, FALSE); + + 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); + return NM_PLATFORM_ERROR_NETLINK; + } + + delayed_action_handle_all (platform, FALSE); + + nm_assert (seq_result); + + _NMLOG (seq_result == WAIT_FOR_NL_RESPONSE_RESULT_RESPONSE_OK + ? LOGL_DEBUG + : LOGL_WARN, + "do-add-tfilter: %s", + 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; + + return NM_PLATFORM_ERROR_UNSPECIFIED; +} + +/*****************************************************************************/ + #define EVENT_CONDITIONS ((GIOCondition) (G_IO_IN | G_IO_PRI)) #define ERROR_CONDITIONS ((GIOCondition) (G_IO_ERR | G_IO_NVAL)) #define DISCONNECT_CONDITIONS ((GIOCondition) (G_IO_HUP)) @@ -6500,7 +6839,9 @@ event_handler_read_netlink (NMPlatform *platform, gboolean wait_for_acks) DELAYED_ACTION_TYPE_REFRESH_ALL_IP4_ADDRESSES | DELAYED_ACTION_TYPE_REFRESH_ALL_IP6_ADDRESSES | DELAYED_ACTION_TYPE_REFRESH_ALL_IP4_ROUTES | - DELAYED_ACTION_TYPE_REFRESH_ALL_IP6_ROUTES, + DELAYED_ACTION_TYPE_REFRESH_ALL_IP6_ROUTES | + DELAYED_ACTION_TYPE_REFRESH_ALL_QDISCS | + DELAYED_ACTION_TYPE_REFRESH_ALL_TFILTERS, NULL); break; default: @@ -6760,13 +7101,13 @@ constructed (GObject *_object) RTNLGRP_LINK, RTNLGRP_IPV4_IFADDR, RTNLGRP_IPV6_IFADDR, RTNLGRP_IPV4_ROUTE, RTNLGRP_IPV6_ROUTE, + RTNLGRP_TC, 0); g_assert (!nle); _LOGD ("Netlink socket for events established: port=%u, fd=%d", nl_socket_get_local_port (priv->nlh), nl_socket_get_fd (priv->nlh)); priv->event_channel = g_io_channel_unix_new (nl_socket_get_fd (priv->nlh)); g_io_channel_set_encoding (priv->event_channel, NULL, NULL); - g_io_channel_set_close_on_unref (priv->event_channel, TRUE); channel_flags = g_io_channel_get_flags (priv->event_channel); status = g_io_channel_set_flags (priv->event_channel, @@ -6785,7 +7126,9 @@ constructed (GObject *_object) DELAYED_ACTION_TYPE_REFRESH_ALL_IP4_ADDRESSES | DELAYED_ACTION_TYPE_REFRESH_ALL_IP6_ADDRESSES | DELAYED_ACTION_TYPE_REFRESH_ALL_IP4_ROUTES | - DELAYED_ACTION_TYPE_REFRESH_ALL_IP6_ROUTES, + DELAYED_ACTION_TYPE_REFRESH_ALL_IP6_ROUTES | + DELAYED_ACTION_TYPE_REFRESH_ALL_QDISCS | + DELAYED_ACTION_TYPE_REFRESH_ALL_TFILTERS, NULL); delayed_action_handle_all (platform, FALSE); @@ -6942,15 +7285,18 @@ nm_linux_platform_class_init (NMLinuxPlatformClass *klass) platform_class->link_ipip_add = link_ipip_add; platform_class->link_sit_add = link_sit_add; + platform_class->object_delete = object_delete; platform_class->ip4_address_add = ip4_address_add; platform_class->ip6_address_add = ip6_address_add; platform_class->ip4_address_delete = ip4_address_delete; platform_class->ip6_address_delete = ip6_address_delete; platform_class->ip_route_add = ip_route_add; - platform_class->ip_route_delete = ip_route_delete; platform_class->ip_route_get = ip_route_get; + platform_class->qdisc_add = qdisc_add; + platform_class->tfilter_add = tfilter_add; + platform_class->check_kernel_support = check_kernel_support; platform_class->process_events = process_events; diff --git a/src/platform/nm-platform.c b/src/platform/nm-platform.c index ffc4b395..2ca379e4 100644 --- a/src/platform/nm-platform.c +++ b/src/platform/nm-platform.c @@ -15,7 +15,7 @@ * with this program; if not, write to the Free Software Foundation, Inc., * 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA. * - * Copyright (C) 2012 Red Hat, Inc. + * Copyright (C) 2012 - 2017 Red Hat, Inc. */ #include "nm-default.h" @@ -508,6 +508,7 @@ nm_platform_sysctl_get_int_checked (NMPlatform *self, const char *pathid, int di { char *value = NULL; gint32 ret; + int errsv; _CHECK_SELF (self, klass, fallback); @@ -522,7 +523,9 @@ nm_platform_sysctl_get_int_checked (NMPlatform *self, const char *pathid, int di } ret = _nm_utils_ascii_str_to_int64 (value, base, min, max, fallback); + errsv = errno; g_free (value); + errno = errsv; return ret; } @@ -3343,9 +3346,9 @@ delete_and_next: } plat_addresses = nm_platform_lookup_clone (self, - nmp_lookup_init_addrroute (&lookup, - NMP_OBJECT_TYPE_IP4_ADDRESS, - ifindex), + nmp_lookup_init_object (&lookup, + NMP_OBJECT_TYPE_IP4_ADDRESS, + ifindex), NULL, NULL); if (plat_addresses) plat_subnets = ip4_addr_subnets_build_index (plat_addresses, TRUE, TRUE); @@ -3485,9 +3488,9 @@ nm_platform_ip6_address_sync (NMPlatform *self, /* Delete unknown addresses */ plat_addresses = nm_platform_lookup_clone (self, - nmp_lookup_init_addrroute (&lookup, - NMP_OBJECT_TYPE_IP6_ADDRESS, - ifindex), + nmp_lookup_init_object (&lookup, + NMP_OBJECT_TYPE_IP6_ADDRESS, + ifindex), NULL, NULL); if (plat_addresses) { for (i = 0; i < plat_addresses->len; i++) { @@ -3608,11 +3611,11 @@ nm_platform_ip_route_get_prune_list (NMPlatform *self, NM_IP_ROUTE_TABLE_SYNC_MODE_FULL, NM_IP_ROUTE_TABLE_SYNC_MODE_ALL)); - nmp_lookup_init_addrroute (&lookup, - addr_family == AF_INET - ? NMP_OBJECT_TYPE_IP4_ROUTE - : NMP_OBJECT_TYPE_IP6_ROUTE, - ifindex); + nmp_lookup_init_object (&lookup, + addr_family == AF_INET + ? NMP_OBJECT_TYPE_IP4_ROUTE + : NMP_OBJECT_TYPE_IP6_ROUTE, + ifindex); head_entry = nm_platform_lookup (self, &lookup); if (!head_entry) return NULL; @@ -3729,7 +3732,7 @@ nm_platform_ip_route_sync (NMPlatform *self, /* we need to replace the existing route with a (slightly) differnt * one. Delete it first. */ - if (!nm_platform_ip_route_delete (self, plat_o)) { + if (!nm_platform_object_delete (self, plat_o)) { /* ignore error. */ } } @@ -3810,7 +3813,7 @@ nm_platform_ip_route_sync (NMPlatform *self, prune_o)) continue; - if (!nm_platform_ip_route_delete (self, prune_o)) { + if (!nm_platform_object_delete (self, prune_o)) { /* ignore error... */ } } @@ -3988,20 +3991,22 @@ nm_platform_ip6_route_add (NMPlatform *self, } gboolean -nm_platform_ip_route_delete (NMPlatform *self, - const NMPObject *obj) +nm_platform_object_delete (NMPlatform *self, + const NMPObject *obj) { _CHECK_SELF (self, klass, FALSE); if (!NM_IN_SET (NMP_OBJECT_GET_TYPE (obj), NMP_OBJECT_TYPE_IP4_ROUTE, - NMP_OBJECT_TYPE_IP6_ROUTE)) + NMP_OBJECT_TYPE_IP6_ROUTE, + NMP_OBJECT_TYPE_QDISC, + NMP_OBJECT_TYPE_TFILTER)) g_return_val_if_reached (FALSE); - _LOGD ("route: delete IPv%c route %s", - NMP_OBJECT_GET_TYPE (obj) == NMP_OBJECT_TYPE_IP4_ROUTE ? '4' : '6', + _LOGD ("%s: delete %s", + NMP_OBJECT_GET_CLASS (obj)->obj_type_name, nmp_object_to_string (obj, NMP_OBJECT_TO_STRING_PUBLIC, NULL, 0)); - return klass->ip_route_delete (self, obj); + return klass->object_delete (self, obj); } /*****************************************************************************/ @@ -4112,7 +4117,7 @@ again: _LOGT ("ip4-dev-route: delete %s", nmp_object_to_string (p_obj, NMP_OBJECT_TO_STRING_PUBLIC, NULL, 0)); - nm_platform_ip_route_delete (self, p_obj); + nm_platform_object_delete (self, p_obj); goto again; } @@ -4329,6 +4334,138 @@ nm_platform_ip4_dev_route_blacklist_set (NMPlatform *self, /*****************************************************************************/ +NMPlatformError +nm_platform_qdisc_add (NMPlatform *self, + NMPNlmFlags flags, + const NMPlatformQdisc *qdisc) +{ + _CHECK_SELF (self, klass, NM_PLATFORM_ERROR_BUG); + + _LOGD ("adding or updating a qdisc: %s", nm_platform_qdisc_to_string (qdisc, NULL, 0)); + return klass->qdisc_add (self, flags, qdisc); +} + +gboolean +nm_platform_qdisc_sync (NMPlatform *self, + int ifindex, + GPtrArray *known_qdiscs) +{ + gs_unref_ptrarray GPtrArray *plat_qdiscs = NULL; + NMPLookup lookup; + guint i; + gboolean success = TRUE; + gs_unref_hashtable GHashTable *known_qdiscs_idx = NULL; + + nm_assert (NM_IS_PLATFORM (self)); + nm_assert (ifindex > 0); + + known_qdiscs_idx = g_hash_table_new ((GHashFunc) nmp_object_id_hash, + (GEqualFunc) nmp_object_id_equal); + + if (known_qdiscs) { + for (i = 0; i < known_qdiscs->len; i++) { + const NMPObject *q = g_ptr_array_index (known_qdiscs, i); + + g_hash_table_insert (known_qdiscs_idx, (gpointer) q, (gpointer) q); + } + } + + plat_qdiscs = nm_platform_lookup_clone (self, + nmp_lookup_init_object (&lookup, + NMP_OBJECT_TYPE_QDISC, + ifindex), + NULL, NULL); + + + if (plat_qdiscs) { + for (i = 0; i < plat_qdiscs->len; i++) { + const NMPObject *q = g_ptr_array_index (plat_qdiscs, i); + + if (!g_hash_table_lookup (known_qdiscs_idx, q)) + success &= nm_platform_object_delete (self, q); + } + } + + if (known_qdiscs) { + for (i = 0; i < known_qdiscs->len; i++) { + const NMPObject *q = g_ptr_array_index (known_qdiscs, i); + + success &= (nm_platform_qdisc_add (self, NMP_NLM_FLAG_ADD, + NMP_OBJECT_CAST_QDISC (q)) == NM_PLATFORM_ERROR_SUCCESS); + } + } + + return success; +} + +/*****************************************************************************/ + +NMPlatformError +nm_platform_tfilter_add (NMPlatform *self, + NMPNlmFlags flags, + const NMPlatformTfilter *tfilter) +{ + _CHECK_SELF (self, klass, NM_PLATFORM_ERROR_BUG); + + _LOGD ("adding or updating a tfilter: %s", nm_platform_tfilter_to_string (tfilter, NULL, 0)); + return klass->tfilter_add (self, flags, tfilter); +} + +gboolean +nm_platform_tfilter_sync (NMPlatform *self, + int ifindex, + GPtrArray *known_tfilters) +{ + gs_unref_ptrarray GPtrArray *plat_tfilters = NULL; + NMPLookup lookup; + guint i; + gboolean success = TRUE; + gs_unref_hashtable GHashTable *known_tfilters_idx = NULL; + + nm_assert (NM_IS_PLATFORM (self)); + nm_assert (ifindex > 0); + + known_tfilters_idx = g_hash_table_new ((GHashFunc) nmp_object_id_hash, + (GEqualFunc) nmp_object_id_equal); + + if (known_tfilters) { + for (i = 0; i < known_tfilters->len; i++) { + const NMPObject *q = g_ptr_array_index (known_tfilters, i); + + g_hash_table_insert (known_tfilters_idx, (gpointer) q, (gpointer) q); + } + } + + plat_tfilters = nm_platform_lookup_clone (self, + nmp_lookup_init_object (&lookup, + NMP_OBJECT_TYPE_TFILTER, + ifindex), + NULL, NULL); + + + if (plat_tfilters) { + for (i = 0; i < plat_tfilters->len; i++) { + const NMPObject *q = g_ptr_array_index (plat_tfilters, i); + + if (!g_hash_table_lookup (known_tfilters_idx, q)) + success &= nm_platform_object_delete (self, q); + } + } + + if (known_tfilters) { + for (i = 0; i < known_tfilters->len; i++) { + const NMPObject *q = g_ptr_array_index (known_tfilters, i); + + success &= (nm_platform_tfilter_add (self, NMP_NLM_FLAG_ADD, + NMP_OBJECT_CAST_TFILTER (q)) == NM_PLATFORM_ERROR_SUCCESS); + } + } + + return success; +} + +/*****************************************************************************/ + const char * nm_platform_vlan_qos_mapping_to_string (const char *name, const NMVlanQosMapping *map, @@ -4976,6 +5113,40 @@ nm_platform_ip6_address_to_string (const NMPlatformIP6Address *address, char *bu return buf; } +NM_UTILS_FLAGS2STR_DEFINE_STATIC (_rtm_flags_to_string, unsigned, + NM_UTILS_FLAGS2STR (RTNH_F_DEAD, "dead"), + NM_UTILS_FLAGS2STR (RTNH_F_PERVASIVE, "pervasive"), + NM_UTILS_FLAGS2STR (RTNH_F_ONLINK, "onlink"), + NM_UTILS_FLAGS2STR (8 /*RTNH_F_OFFLOAD*/, "offload"), + NM_UTILS_FLAGS2STR (16 /*RTNH_F_LINKDOWN*/, "linkdown"), + NM_UTILS_FLAGS2STR (32 /*RTNH_F_UNRESOLVED*/, "unresolved"), + + NM_UTILS_FLAGS2STR (RTM_F_NOTIFY, "notify"), + NM_UTILS_FLAGS2STR (RTM_F_CLONED, "cloned"), + NM_UTILS_FLAGS2STR (RTM_F_EQUALIZE, "equalize"), + NM_UTILS_FLAGS2STR (RTM_F_PREFIX, "prefix"), + NM_UTILS_FLAGS2STR (0x1000 /*RTM_F_LOOKUP_TABLE*/, "lookup-table"), + NM_UTILS_FLAGS2STR (0x2000 /*RTM_F_FIB_MATCH*/, "fib-match"), +); + +#define _RTM_FLAGS_TO_STRING_MAXLEN 200 + +static const char * +_rtm_flags_to_string_full (char *buf, gsize buf_size, unsigned rtm_flags) +{ + const char *buf0 = buf; + + nm_assert (buf_size >= _RTM_FLAGS_TO_STRING_MAXLEN); + + if (!rtm_flags) + return ""; + + nm_utils_strbuf_append_str (&buf, &buf_size, " rtm_flags "); + _rtm_flags_to_string (rtm_flags, buf, buf_size); + nm_assert (strlen (buf) < buf_size); + return buf0; +} + /** * nm_platform_ip4_route_to_string: * @route: pointer to NMPlatformIP4Route route structure @@ -4997,6 +5168,7 @@ nm_platform_ip4_route_to_string (const NMPlatformIP4Route *route, char *buf, gsi char str_table[30]; char str_scope[30], s_source[50]; char str_tos[32], str_window[32], str_cwnd[32], str_initcwnd[32], str_initrwnd[32], str_mtu[32]; + char str_rtm_flags[_RTM_FLAGS_TO_STRING_MAXLEN]; if (!nm_utils_to_string_buffer_init_null (route, &buf, &len)) return buf; @@ -5015,7 +5187,7 @@ nm_platform_ip4_route_to_string (const NMPlatformIP4Route *route, char *buf, gsi " metric %"G_GUINT32_FORMAT " mss %"G_GUINT32_FORMAT " rt-src %s" /* protocol */ - "%s" /* cloned */ + "%s" /* rtm_flags */ "%s%s" /* scope */ "%s%s" /* pref-src */ "%s" /* tos */ @@ -5033,7 +5205,7 @@ nm_platform_ip4_route_to_string (const NMPlatformIP4Route *route, char *buf, gsi route->metric, route->mss, nmp_utils_ip_config_source_to_string (route->rt_source, s_source, sizeof (s_source)), - route->rt_cloned ? " cloned" : "", + _rtm_flags_to_string_full (str_rtm_flags, sizeof (str_rtm_flags), route->r_rtm_flags), route->scope_inv ? " scope " : "", route->scope_inv ? (nm_platform_route_scope2str (nm_platform_route_scope_inv (route->scope_inv), str_scope, sizeof (str_scope))) : "", route->pref_src ? " pref-src " : "", @@ -5069,6 +5241,7 @@ nm_platform_ip6_route_to_string (const NMPlatformIP6Route *route, char *buf, gsi char str_pref2[30]; char str_dev[TO_STRING_DEV_BUF_SIZE], s_source[50]; char str_window[32], str_cwnd[32], str_initcwnd[32], str_initrwnd[32], str_mtu[32]; + char str_rtm_flags[_RTM_FLAGS_TO_STRING_MAXLEN]; if (!nm_utils_to_string_buffer_init_null (route, &buf, &len)) return buf; @@ -5092,7 +5265,7 @@ nm_platform_ip6_route_to_string (const NMPlatformIP6Route *route, char *buf, gsi " mss %"G_GUINT32_FORMAT " rt-src %s" /* protocol */ "%s" /* source */ - "%s" /* cloned */ + "%s" /* rtm_flags */ "%s%s" /* pref-src */ "%s" /* window */ "%s" /* cwnd */ @@ -5112,7 +5285,7 @@ nm_platform_ip6_route_to_string (const NMPlatformIP6Route *route, char *buf, gsi route->src_plen || !IN6_IS_ADDR_UNSPECIFIED (&route->src) ? nm_sprintf_buf (s_src_all, " src %s/%u", nm_utils_inet6_ntop (&route->src, s_src), (unsigned) route->src_plen) : "", - route->rt_cloned ? " cloned" : "", + _rtm_flags_to_string_full (str_rtm_flags, sizeof (str_rtm_flags), route->r_rtm_flags), s_pref_src[0] ? " pref-src " : "", s_pref_src[0] ? s_pref_src : "", route->window || route->lock_window ? nm_sprintf_buf (str_window, " window %s%"G_GUINT32_FORMAT, route->lock_window ? "lock " : "", route->window) : "", @@ -5125,6 +5298,129 @@ nm_platform_ip6_route_to_string (const NMPlatformIP6Route *route, char *buf, gsi return buf; } +const char * +nm_platform_qdisc_to_string (const NMPlatformQdisc *qdisc, char *buf, gsize len) +{ + char str_dev[TO_STRING_DEV_BUF_SIZE]; + + if (!nm_utils_to_string_buffer_init_null (qdisc, &buf, &len)) + return buf; + + g_snprintf (buf, len, "%s%s family %d handle %x parent %x info %x", + qdisc->kind, + _to_string_dev (NULL, qdisc->ifindex, str_dev, sizeof (str_dev)), + qdisc->addr_family, + qdisc->handle, + qdisc->parent, + qdisc->info); + + return buf; +} + +void +nm_platform_qdisc_hash_update (const NMPlatformQdisc *obj, NMHashState *h) +{ + nm_hash_update_str (h, obj->kind); + nm_hash_update_vals (h, + obj->ifindex, + obj->addr_family, + obj->handle, + obj->parent, + obj->info); +} + +int +nm_platform_qdisc_cmp (const NMPlatformQdisc *a, const NMPlatformQdisc *b) +{ + NM_CMP_SELF (a, b); + NM_CMP_FIELD (a, b, ifindex); + NM_CMP_FIELD (a, b, parent); + NM_CMP_FIELD_STR_INTERNED (a, b, kind); + NM_CMP_FIELD (a, b, addr_family); + NM_CMP_FIELD (a, b, handle); + NM_CMP_FIELD (a, b, info); + + return 0; +} + +const char * +nm_platform_tfilter_to_string (const NMPlatformTfilter *tfilter, char *buf, gsize len) +{ + char str_dev[TO_STRING_DEV_BUF_SIZE]; + char act_buf[300]; + char *p; + gsize l; + + if (!nm_utils_to_string_buffer_init_null (tfilter, &buf, &len)) + return buf; + + if (tfilter->action.kind) { + p = act_buf; + l = sizeof (act_buf); + + nm_utils_strbuf_append (&p, &l, " \"%s\"", tfilter->action.kind); + if (nm_streq (tfilter->action.kind, NM_PLATFORM_ACTION_KIND_SIMPLE)) { + gs_free char *t = NULL; + + nm_utils_strbuf_append (&p, &l, + " (\"%s\")", + nm_utils_str_utf8safe_escape (tfilter->action.kind, + NM_UTILS_STR_UTF8_SAFE_FLAG_ESCAPE_CTRL + | NM_UTILS_STR_UTF8_SAFE_FLAG_ESCAPE_NON_ASCII, + &t)); + } + } else + act_buf[0] = '\0'; + + g_snprintf (buf, len, "%s%s family %d handle %x parent %x info %x%s", + tfilter->kind, + _to_string_dev (NULL, tfilter->ifindex, str_dev, sizeof (str_dev)), + tfilter->addr_family, + tfilter->handle, + tfilter->parent, + tfilter->info, + act_buf); + + return buf; +} + +void +nm_platform_tfilter_hash_update (const NMPlatformTfilter *obj, NMHashState *h) +{ + nm_hash_update_str (h, obj->kind); + nm_hash_update_vals (h, + obj->ifindex, + obj->addr_family, + obj->handle, + obj->parent, + obj->info); + nm_hash_update_str (h, obj->action.kind); + if (obj->action.kind) { + if (nm_streq (obj->action.kind, NM_PLATFORM_ACTION_KIND_SIMPLE)) + nm_hash_update_str (h, obj->action.simple.sdata); + } +} + +int +nm_platform_tfilter_cmp (const NMPlatformTfilter *a, const NMPlatformTfilter *b) +{ + NM_CMP_SELF (a, b); + NM_CMP_FIELD (a, b, ifindex); + NM_CMP_FIELD (a, b, parent); + NM_CMP_FIELD_STR_INTERNED (a, b, kind); + NM_CMP_FIELD (a, b, addr_family); + NM_CMP_FIELD (a, b, handle); + NM_CMP_FIELD (a, b, info); + + NM_CMP_FIELD_STR_INTERNED (a, b, action.kind); + if (a->action.kind) { + if (nm_streq (a->action.kind, NM_PLATFORM_ACTION_KIND_SIMPLE)) + NM_CMP_FIELD_STR (a, b, action.simple.sdata); + } + + return 0; +} + void nm_platform_link_hash_update (const NMPlatformLink *obj, NMHashState *h) { @@ -5538,6 +5834,7 @@ nm_platform_ip4_route_hash_update (const NMPlatformIP4Route *obj, NMPlatformIPRo obj->initcwnd, obj->initrwnd, obj->mtu, + obj->r_rtm_flags & RTNH_F_ONLINK, NM_HASH_COMBINE_BOOLS (guint8, obj->lock_window, obj->lock_cwnd, @@ -5563,8 +5860,8 @@ nm_platform_ip4_route_hash_update (const NMPlatformIP4Route *obj, NMPlatformIPRo obj->initcwnd, obj->initrwnd, obj->mtu, + obj->r_rtm_flags & (RTM_F_CLONED | RTNH_F_ONLINK), NM_HASH_COMBINE_BOOLS (guint8, - obj->rt_cloned, obj->lock_window, obj->lock_cwnd, obj->lock_initcwnd, @@ -5589,8 +5886,8 @@ nm_platform_ip4_route_hash_update (const NMPlatformIP4Route *obj, NMPlatformIPRo obj->initcwnd, obj->initrwnd, obj->mtu, + obj->r_rtm_flags, NM_HASH_COMBINE_BOOLS (guint8, - obj->rt_cloned, obj->lock_window, obj->lock_cwnd, obj->lock_initcwnd, @@ -5627,6 +5924,8 @@ nm_platform_ip4_route_cmp (const NMPlatformIP4Route *a, const NMPlatformIP4Route NM_CMP_FIELD (a, b, initcwnd); NM_CMP_FIELD (a, b, initrwnd); NM_CMP_FIELD (a, b, mtu); + NM_CMP_DIRECT (a->r_rtm_flags & RTNH_F_ONLINK, + b->r_rtm_flags & RTNH_F_ONLINK); NM_CMP_FIELD_UNSAFE (a, b, lock_window); NM_CMP_FIELD_UNSAFE (a, b, lock_cwnd); NM_CMP_FIELD_UNSAFE (a, b, lock_initcwnd); @@ -5660,7 +5959,11 @@ nm_platform_ip4_route_cmp (const NMPlatformIP4Route *a, const NMPlatformIP4Route } NM_CMP_FIELD (a, b, mss); NM_CMP_FIELD (a, b, pref_src); - NM_CMP_FIELD_UNSAFE (a, b, rt_cloned); + if (cmp_type == NM_PLATFORM_IP_ROUTE_CMP_TYPE_SEMANTICALLY) { + NM_CMP_DIRECT (a->r_rtm_flags & (RTM_F_CLONED | RTNH_F_ONLINK), + b->r_rtm_flags & (RTM_F_CLONED | RTNH_F_ONLINK)); + } else + NM_CMP_FIELD (a, b, r_rtm_flags); NM_CMP_FIELD (a, b, tos); NM_CMP_FIELD_UNSAFE (a, b, lock_window); NM_CMP_FIELD_UNSAFE (a, b, lock_cwnd); @@ -5717,8 +6020,8 @@ nm_platform_ip6_route_hash_update (const NMPlatformIP6Route *obj, NMPlatformIPRo obj->src_plen, nmp_utils_ip_config_source_round_trip_rtprot (obj->rt_source), obj->mss, + obj->r_rtm_flags & RTM_F_CLONED, NM_HASH_COMBINE_BOOLS (guint8, - obj->rt_cloned, obj->lock_window, obj->lock_cwnd, obj->lock_initcwnd, @@ -5744,8 +6047,8 @@ nm_platform_ip6_route_hash_update (const NMPlatformIP6Route *obj, NMPlatformIPRo obj->src_plen, obj->rt_source, obj->mss, + obj->r_rtm_flags, NM_HASH_COMBINE_BOOLS (guint8, - obj->rt_cloned, obj->lock_window, obj->lock_cwnd, obj->lock_initcwnd, @@ -5810,7 +6113,11 @@ nm_platform_ip6_route_cmp (const NMPlatformIP6Route *a, const NMPlatformIP6Route NM_CMP_FIELD (a, b, rt_source); } NM_CMP_FIELD (a, b, mss); - NM_CMP_FIELD_UNSAFE (a, b, rt_cloned); + if (cmp_type == NM_PLATFORM_IP_ROUTE_CMP_TYPE_SEMANTICALLY) { + NM_CMP_DIRECT (a->r_rtm_flags & RTM_F_CLONED, + b->r_rtm_flags & RTM_F_CLONED); + } else + NM_CMP_FIELD (a, b, r_rtm_flags); NM_CMP_FIELD_UNSAFE (a, b, lock_window); NM_CMP_FIELD_UNSAFE (a, b, lock_cwnd); NM_CMP_FIELD_UNSAFE (a, b, lock_initcwnd); @@ -5927,6 +6234,18 @@ log_ip6_route (NMPlatform *self, NMPObjectType obj_type, int ifindex, NMPlatform _LOGD ("signal: route 6 %7s: %s", nm_platform_signal_change_type_to_string (change_type), nm_platform_ip6_route_to_string (route, NULL, 0)); } +static void +log_qdisc (NMPlatform *self, NMPObjectType obj_type, int ifindex, NMPlatformQdisc *qdisc, NMPlatformSignalChangeType change_type, gpointer user_data) +{ + _LOGD ("signal: qdisc %7s: %s", nm_platform_signal_change_type_to_string (change_type), nm_platform_qdisc_to_string (qdisc, NULL, 0)); +} + +static void +log_tfilter (NMPlatform *self, NMPObjectType obj_type, int ifindex, NMPlatformTfilter *tfilter, NMPlatformSignalChangeType change_type, gpointer user_data) +{ + _LOGD ("signal: tfilter %7s: %s", nm_platform_signal_change_type_to_string (change_type), nm_platform_tfilter_to_string (tfilter, NULL, 0)); +} + /*****************************************************************************/ void @@ -6200,4 +6519,6 @@ nm_platform_class_init (NMPlatformClass *platform_class) SIGNAL (NM_PLATFORM_SIGNAL_ID_IP6_ADDRESS, NM_PLATFORM_SIGNAL_IP6_ADDRESS_CHANGED, log_ip6_address); SIGNAL (NM_PLATFORM_SIGNAL_ID_IP4_ROUTE, NM_PLATFORM_SIGNAL_IP4_ROUTE_CHANGED, log_ip4_route); SIGNAL (NM_PLATFORM_SIGNAL_ID_IP6_ROUTE, NM_PLATFORM_SIGNAL_IP6_ROUTE_CHANGED, log_ip6_route); + SIGNAL (NM_PLATFORM_SIGNAL_ID_QDISC, NM_PLATFORM_SIGNAL_QDISC_CHANGED, log_qdisc); + SIGNAL (NM_PLATFORM_SIGNAL_ID_TFILTER, NM_PLATFORM_SIGNAL_TFILTER_CHANGED, log_tfilter); } diff --git a/src/platform/nm-platform.h b/src/platform/nm-platform.h index d155c109..f6bf02bf 100644 --- a/src/platform/nm-platform.h +++ b/src/platform/nm-platform.h @@ -15,7 +15,7 @@ * with this program; if not, write to the Free Software Foundation, Inc., * 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA. * - * Copyright (C) 2009 - 2010 Red Hat, Inc. + * Copyright (C) 2009 - 2017 Red Hat, Inc. */ #ifndef __NETWORKMANAGER_PLATFORM_H__ @@ -236,6 +236,8 @@ typedef enum { /*< skip >*/ NM_PLATFORM_SIGNAL_ID_IP6_ADDRESS, NM_PLATFORM_SIGNAL_ID_IP4_ROUTE, NM_PLATFORM_SIGNAL_ID_IP6_ROUTE, + NM_PLATFORM_SIGNAL_ID_QDISC, + NM_PLATFORM_SIGNAL_ID_TFILTER, _NM_PLATFORM_SIGNAL_ID_LAST, } NMPlatformSignalIdType; @@ -375,13 +377,6 @@ typedef union { \ guint8 plen; \ \ - /* the route has rtm_flags set to RTM_F_CLONED. Such a route - * is hidden by platform and does not exist from the point-of-view - * of platform users. This flag is internal to track those hidden - * routes. Such a route is not alive, according to nmp_object_is_alive(). */ \ - bool rt_cloned:1; \ - \ - \ /* RTA_METRICS: * * For IPv4 routes, these properties are part of their @@ -401,6 +396,18 @@ typedef union { bool lock_initrwnd:1; \ bool lock_mtu:1; \ \ + /* rtnh_flags + * + * Routes with rtm_flags RTM_F_CLONED are hidden by platform and + * do not exist from the point-of-view of platform users. + * Such a route is not alive, according to nmp_object_is_alive(). + * + * 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. */ \ + unsigned r_rtm_flags; \ + \ /* RTA_METRICS.RTAX_ADVMSS (iproute2: advmss) */ \ guint32 mss; \ \ @@ -441,23 +448,11 @@ typedef struct { }; } NMPlatformIPRoute; -#if _NM_CC_SUPPORT_GENERIC -#define NM_PLATFORM_IP_ROUTE_IS_DEFAULT(route) \ - (_Generic ((route), \ - const NMPlatformIPRoute *: ((const NMPlatformIPRoute *) (route))->plen, \ - NMPlatformIPRoute *: ((const NMPlatformIPRoute *) (route))->plen, \ - const NMPlatformIPXRoute *: ((const NMPlatformIPRoute *) (route))->plen, \ - NMPlatformIPXRoute *: ((const NMPlatformIPRoute *) (route))->plen, \ - const NMPlatformIP4Route *: ((const NMPlatformIPRoute *) (route))->plen, \ - NMPlatformIP4Route *: ((const NMPlatformIPRoute *) (route))->plen, \ - const NMPlatformIP6Route *: ((const NMPlatformIPRoute *) (route))->plen, \ - NMPlatformIP6Route *: ((const NMPlatformIPRoute *) (route))->plen, \ - const void *: ((const NMPlatformIPRoute *) (route))->plen, \ - void *: ((const NMPlatformIPRoute *) (route))->plen) == 0) -#else +#define NM_PLATFORM_IP_ROUTE_CAST(route) \ + NM_CONSTCAST (NMPlatformIPRoute, (route), NMPlatformIPXRoute, NMPlatformIP4Route, NMPlatformIP6Route) + #define NM_PLATFORM_IP_ROUTE_IS_DEFAULT(route) \ - ( ((const NMPlatformIPRoute *) (route))->plen <= 0 ) -#endif + (NM_PLATFORM_IP_ROUTE_CAST (route)->plen <= 0) struct _NMPlatformIP4Route { __NMPlatformIPRoute_COMMON; @@ -534,6 +529,37 @@ typedef union { #undef __NMPlatformIPRoute_COMMON +typedef struct { + __NMPlatformObject_COMMON; + const char *kind; + int addr_family; + guint32 handle; + guint32 parent; + guint32 info; +} NMPlatformQdisc; + +typedef struct { + char sdata[32]; +} NMPlatformActionSimple; + +typedef struct { + const char *kind; + union { + NMPlatformActionSimple simple; + }; +} NMPlatformAction; + +#define NM_PLATFORM_ACTION_KIND_SIMPLE "simple" + +typedef struct { + __NMPlatformObject_COMMON; + const char *kind; + int addr_family; + guint32 handle; + guint32 parent; + guint32 info; + NMPlatformAction action; +} NMPlatformTfilter; #undef __NMPlatformObject_COMMON @@ -805,6 +831,8 @@ typedef struct { gboolean (*mesh_set_channel) (NMPlatform *, int ifindex, guint32 channel); gboolean (*mesh_set_ssid) (NMPlatform *, int ifindex, const guint8 *ssid, gsize len); + gboolean (*object_delete) (NMPlatform *, const NMPObject *obj); + gboolean (*ip4_address_add) (NMPlatform *, int ifindex, in_addr_t address, @@ -829,14 +857,20 @@ typedef struct { NMPNlmFlags flags, int addr_family, const NMPlatformIPRoute *route); - gboolean (*ip_route_delete) (NMPlatform *, const NMPObject *obj); - NMPlatformError (*ip_route_get) (NMPlatform *self, int addr_family, gconstpointer address, int oif_ifindex, NMPObject **out_route); + NMPlatformError (*qdisc_add) (NMPlatform *self, + NMPNlmFlags flags, + const NMPlatformQdisc *qdisc); + + NMPlatformError (*tfilter_add) (NMPlatform *self, + NMPNlmFlags flags, + const NMPlatformTfilter *tfilter); + NMPlatformKernelSupportFlags (*check_kernel_support) (NMPlatform * self, NMPlatformKernelSupportFlags request_flags); } NMPlatformClass; @@ -857,6 +891,8 @@ typedef struct { #define NM_PLATFORM_SIGNAL_IP6_ADDRESS_CHANGED "ip6-address-changed" #define NM_PLATFORM_SIGNAL_IP4_ROUTE_CHANGED "ip4-route-changed" #define NM_PLATFORM_SIGNAL_IP6_ROUTE_CHANGED "ip6-route-changed" +#define NM_PLATFORM_SIGNAL_QDISC_CHANGED "qdisc-changed" +#define NM_PLATFORM_SIGNAL_TFILTER_CHANGED "tfilter-changed" const char *nm_platform_signal_change_type_to_string (NMPlatformSignalChangeType change_type); @@ -1194,6 +1230,8 @@ NMPlatformError nm_platform_link_sit_add (NMPlatform *self, const NMPlatformIP6Address *nm_platform_ip6_address_get (NMPlatform *self, int ifindex, struct in6_addr address); +gboolean nm_platform_object_delete (NMPlatform *self, const NMPObject *route); + gboolean nm_platform_ip4_address_add (NMPlatform *self, int ifindex, in_addr_t address, @@ -1228,8 +1266,6 @@ NMPlatformError nm_platform_ip_route_add (NMPlatform *self, NMPlatformError nm_platform_ip4_route_add (NMPlatform *self, NMPNlmFlags flags, const NMPlatformIP4Route *route); NMPlatformError nm_platform_ip6_route_add (NMPlatform *self, NMPNlmFlags flags, const NMPlatformIP6Route *route); -gboolean nm_platform_ip_route_delete (NMPlatform *self, const NMPObject *route); - GPtrArray *nm_platform_ip_route_get_prune_list (NMPlatform *self, int addr_family, int ifindex, @@ -1252,6 +1288,20 @@ NMPlatformError nm_platform_ip_route_get (NMPlatform *self, int oif_ifindex, NMPObject **out_route); +NMPlatformError nm_platform_qdisc_add (NMPlatform *self, + NMPNlmFlags flags, + const NMPlatformQdisc *qdisc); +gboolean nm_platform_qdisc_sync (NMPlatform *self, + int ifindex, + GPtrArray *known_qdiscs); + +NMPlatformError nm_platform_tfilter_add (NMPlatform *self, + NMPNlmFlags flags, + const NMPlatformTfilter *tfilter); +gboolean nm_platform_tfilter_sync (NMPlatform *self, + int ifindex, + GPtrArray *known_tfilters); + const char *nm_platform_link_to_string (const NMPlatformLink *link, char *buf, gsize len); const char *nm_platform_lnk_gre_to_string (const NMPlatformLnkGre *lnk, char *buf, gsize len); const char *nm_platform_lnk_infiniband_to_string (const NMPlatformLnkInfiniband *lnk, char *buf, gsize len); @@ -1266,6 +1316,8 @@ const char *nm_platform_ip4_address_to_string (const NMPlatformIP4Address *addre const char *nm_platform_ip6_address_to_string (const NMPlatformIP6Address *address, char *buf, gsize len); const char *nm_platform_ip4_route_to_string (const NMPlatformIP4Route *route, char *buf, gsize len); const char *nm_platform_ip6_route_to_string (const NMPlatformIP6Route *route, char *buf, gsize len); +const char *nm_platform_qdisc_to_string (const NMPlatformQdisc *qdisc, char *buf, gsize len); +const char *nm_platform_tfilter_to_string (const NMPlatformTfilter *tfilter, char *buf, gsize len); const char *nm_platform_vlan_qos_mapping_to_string (const char *name, const NMVlanQosMapping *map, @@ -1301,6 +1353,9 @@ nm_platform_ip6_route_cmp_full (const NMPlatformIP6Route *a, const NMPlatformIP6 return nm_platform_ip6_route_cmp (a, b, NM_PLATFORM_IP_ROUTE_CMP_TYPE_FULL); } +int nm_platform_qdisc_cmp (const NMPlatformQdisc *a, const NMPlatformQdisc *b); +int nm_platform_tfilter_cmp (const NMPlatformTfilter *a, const NMPlatformTfilter *b); + void nm_platform_link_hash_update (const NMPlatformLink *obj, NMHashState *h); void nm_platform_ip4_address_hash_update (const NMPlatformIP4Address *obj, NMHashState *h); void nm_platform_ip6_address_hash_update (const NMPlatformIP6Address *obj, NMHashState *h); @@ -1316,6 +1371,9 @@ void nm_platform_lnk_sit_hash_update (const NMPlatformLnkSit *obj, NMHashState * void nm_platform_lnk_vlan_hash_update (const NMPlatformLnkVlan *obj, NMHashState *h); void nm_platform_lnk_vxlan_hash_update (const NMPlatformLnkVxlan *obj, NMHashState *h); +void nm_platform_qdisc_hash_update (const NMPlatformQdisc *obj, NMHashState *h); +void nm_platform_tfilter_hash_update (const NMPlatformTfilter *obj, NMHashState *h); + NMPlatformKernelSupportFlags nm_platform_check_kernel_support (NMPlatform *self, NMPlatformKernelSupportFlags request_flags); diff --git a/src/platform/nmp-netns.c b/src/platform/nmp-netns.c index 34215828..bc305f01 100644 --- a/src/platform/nmp-netns.c +++ b/src/platform/nmp-netns.c @@ -290,6 +290,7 @@ _netns_new (GError **error) g_set_error (error, NM_UTILS_ERROR, NM_UTILS_ERROR_UNKNOWN, "Failed opening netns: %s", g_strerror (errsv)); + errno = errsv; return NULL; } @@ -300,6 +301,7 @@ _netns_new (GError **error) "Failed opening mntns: %s", g_strerror (errsv)); nm_close (fd_net); + errno = errsv; return NULL; } @@ -479,6 +481,7 @@ nmp_netns_new (void) if (!_stack_peek ()) { /* there are no netns instances. We cannot create a new one * (because after unshare we couldn't return to the original one). */ + errno = ENOTSUP; return NULL; } @@ -508,6 +511,7 @@ nmp_netns_new (void) self = _netns_new (&error); if (!self) { + errsv = errno; _LOGE (NULL, "failed to create netns after unshare: %s", error->message); g_clear_error (&error); goto err_out; @@ -518,6 +522,7 @@ nmp_netns_new (void) return self; err_out: _netns_switch_pop (NULL, _CLONE_NS_ALL); + errno = errsv; return NULL; } diff --git a/src/platform/nmp-object.c b/src/platform/nmp-object.c index a8600705..1a9b9325 100644 --- a/src/platform/nmp-object.c +++ b/src/platform/nmp-object.c @@ -15,7 +15,7 @@ * with this program; if not, write to the Free Software Foundation, Inc., * 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA. * - * Copyright (C) 2015 Red Hat, Inc. + * Copyright (C) 2015 - 2017 Red Hat, Inc. */ #include "nm-default.h" @@ -186,11 +186,13 @@ _idx_obj_part (const DedupMultiIdxType *idx_type, } return 1; - case NMP_CACHE_ID_TYPE_ADDRROUTE_BY_IFINDEX: + case NMP_CACHE_ID_TYPE_OBJECT_BY_IFINDEX: if ( !NM_IN_SET (NMP_OBJECT_GET_TYPE (obj_a), NMP_OBJECT_TYPE_IP4_ADDRESS, NMP_OBJECT_TYPE_IP6_ADDRESS, NMP_OBJECT_TYPE_IP4_ROUTE, - NMP_OBJECT_TYPE_IP6_ROUTE) + NMP_OBJECT_TYPE_IP6_ROUTE, + NMP_OBJECT_TYPE_QDISC, + NMP_OBJECT_TYPE_TFILTER) || !nmp_object_is_visible (obj_a)) { if (h) nm_hash_update_val (h, obj_a); @@ -737,6 +739,8 @@ _vt_cmd_plobj_to_string_id (ip4_address, NMPlatformIP4Address, "%d: %s/%d%s%s", obj->peer_address != obj->address ? "," : "", obj->peer_address != obj->address ? nm_utils_inet4_ntop (nm_utils_ip4_address_clear_host_address (obj->peer_address, obj->plen), buf2) : ""); _vt_cmd_plobj_to_string_id (ip6_address, NMPlatformIP6Address, "%d: %s", obj->ifindex, nm_utils_inet6_ntop (&obj->address, buf1)); +_vt_cmd_plobj_to_string_id (qdisc, NMPlatformQdisc, "%d: %d", obj->ifindex, obj->parent); +_vt_cmd_plobj_to_string_id (tfilter, NMPlatformTfilter, "%d: %d", obj->ifindex, obj->parent); void nmp_object_hash_update (const NMPObject *obj, NMHashState *h) @@ -1035,6 +1039,14 @@ _vt_cmd_plobj_id_cmp (ip6_address, NMPlatformIP6Address, /* for IPv6 addresses, the prefix length is not part of the primary identifier. */ NM_CMP_FIELD_IN6ADDR (obj1, obj2, address); ) +_vt_cmd_plobj_id_cmp (qdisc, NMPlatformQdisc, + NM_CMP_FIELD (obj1, obj2, ifindex); + NM_CMP_FIELD (obj1, obj2, parent); +) +_vt_cmd_plobj_id_cmp (tfilter, NMPlatformTfilter, + NM_CMP_FIELD (obj1, obj2, ifindex); + NM_CMP_FIELD (obj1, obj2, handle); +) static int _vt_cmd_plobj_id_cmp_ip4_route (const NMPlatformObject *obj1, const NMPlatformObject *obj2) @@ -1113,6 +1125,16 @@ _vt_cmd_plobj_id_hash_update (ip4_route, NMPlatformIP4Route, { _vt_cmd_plobj_id_hash_update (ip6_route, NMPlatformIP6Route, { nm_platform_ip6_route_hash_update (obj, NM_PLATFORM_IP_ROUTE_CMP_TYPE_ID, h); }) +_vt_cmd_plobj_id_hash_update (qdisc, NMPlatformQdisc, { + nm_hash_update_vals (h, + obj->ifindex, + obj->parent); +}) +_vt_cmd_plobj_id_hash_update (tfilter, NMPlatformTfilter, { + nm_hash_update_vals (h, + obj->ifindex, + obj->handle); +}) static inline void _vt_cmd_plobj_hash_update_ip4_route (const NMPlatformObject *obj, NMHashState *h) @@ -1170,7 +1192,20 @@ _vt_cmd_obj_is_alive_ipx_route (const NMPObject *obj) * Instead we create a dead object, and nmp_cache_update_netlink() * will remove the old version of the update. **/ - return obj->object.ifindex > 0 && !obj->ip_route.rt_cloned; + return obj->object.ifindex > 0 + && !NM_FLAGS_HAS (obj->ip_route.r_rtm_flags, RTM_F_CLONED); +} + +static gboolean +_vt_cmd_obj_is_alive_qdisc (const NMPObject *obj) +{ + return obj->object.ifindex > 0; +} + +static gboolean +_vt_cmd_obj_is_alive_tfilter (const NMPObject *obj) +{ + return obj->object.ifindex > 0; } gboolean @@ -1202,6 +1237,12 @@ _vt_cmd_obj_is_visible_link (const NMPObject *obj) /*****************************************************************************/ +static const guint8 _supported_cache_ids_object[] = { + NMP_CACHE_ID_TYPE_OBJECT_TYPE, + NMP_CACHE_ID_TYPE_OBJECT_BY_IFINDEX, + 0, +}; + static const guint8 _supported_cache_ids_link[] = { NMP_CACHE_ID_TYPE_OBJECT_TYPE, NMP_CACHE_ID_TYPE_LINK_BY_IFNAME, @@ -1210,13 +1251,13 @@ static const guint8 _supported_cache_ids_link[] = { static const guint8 _supported_cache_ids_ipx_address[] = { NMP_CACHE_ID_TYPE_OBJECT_TYPE, - NMP_CACHE_ID_TYPE_ADDRROUTE_BY_IFINDEX, + NMP_CACHE_ID_TYPE_OBJECT_BY_IFINDEX, 0, }; static const guint8 _supported_cache_ids_ipx_route[] = { NMP_CACHE_ID_TYPE_OBJECT_TYPE, - NMP_CACHE_ID_TYPE_ADDRROUTE_BY_IFINDEX, + NMP_CACHE_ID_TYPE_OBJECT_BY_IFINDEX, NMP_CACHE_ID_TYPE_DEFAULT_ROUTES, NMP_CACHE_ID_TYPE_ROUTES_BY_WEAK_ID, 0, @@ -1501,6 +1542,8 @@ nmp_lookup_init_obj_type (NMPLookup *lookup, case NMP_OBJECT_TYPE_IP6_ADDRESS: case NMP_OBJECT_TYPE_IP4_ROUTE: case NMP_OBJECT_TYPE_IP6_ROUTE: + case NMP_OBJECT_TYPE_QDISC: + case NMP_OBJECT_TYPE_TFILTER: o = _nmp_object_stackinit_from_type (&lookup->selector_obj, obj_type); lookup->cache_id_type = NMP_CACHE_ID_TYPE_OBJECT_TYPE; return _L (lookup); @@ -1528,9 +1571,9 @@ nmp_lookup_init_link_by_ifname (NMPLookup *lookup, } const NMPLookup * -nmp_lookup_init_addrroute (NMPLookup *lookup, - NMPObjectType obj_type, - int ifindex) +nmp_lookup_init_object (NMPLookup *lookup, + NMPObjectType obj_type, + int ifindex) { NMPObject *o; @@ -1538,7 +1581,9 @@ nmp_lookup_init_addrroute (NMPLookup *lookup, nm_assert (NM_IN_SET (obj_type, NMP_OBJECT_TYPE_IP4_ADDRESS, NMP_OBJECT_TYPE_IP6_ADDRESS, NMP_OBJECT_TYPE_IP4_ROUTE, - NMP_OBJECT_TYPE_IP6_ROUTE)); + NMP_OBJECT_TYPE_IP6_ROUTE, + NMP_OBJECT_TYPE_QDISC, + NMP_OBJECT_TYPE_TFILTER)); if (ifindex <= 0) { return nmp_lookup_init_obj_type (lookup, @@ -1547,7 +1592,7 @@ nmp_lookup_init_addrroute (NMPLookup *lookup, o = _nmp_object_stackinit_from_type (&lookup->selector_obj, obj_type); o->object.ifindex = ifindex; - lookup->cache_id_type = NMP_CACHE_ID_TYPE_ADDRROUTE_BY_IFINDEX; + lookup->cache_id_type = NMP_CACHE_ID_TYPE_OBJECT_BY_IFINDEX; return _L (lookup); } @@ -2566,6 +2611,42 @@ const NMPClass _nmp_classes[NMP_OBJECT_TYPE_MAX] = { .cmd_plobj_hash_update = _vt_cmd_plobj_hash_update_ip6_route, .cmd_plobj_cmp = (int (*) (const NMPlatformObject *obj1, const NMPlatformObject *obj2)) nm_platform_ip6_route_cmp_full, }, + [NMP_OBJECT_TYPE_QDISC - 1] = { + .parent = DEDUP_MULTI_OBJ_CLASS_INIT(), + .obj_type = NMP_OBJECT_TYPE_QDISC, + .sizeof_data = sizeof (NMPObjectQdisc), + .sizeof_public = sizeof (NMPlatformQdisc), + .obj_type_name = "qdisc", + .rtm_gettype = RTM_GETQDISC, + .signal_type_id = NM_PLATFORM_SIGNAL_ID_QDISC, + .signal_type = NM_PLATFORM_SIGNAL_QDISC_CHANGED, + .supported_cache_ids = _supported_cache_ids_object, + .cmd_obj_is_alive = _vt_cmd_obj_is_alive_qdisc, + .cmd_plobj_id_cmp = _vt_cmd_plobj_id_cmp_qdisc, + .cmd_plobj_id_hash_update = _vt_cmd_plobj_id_hash_update_qdisc, + .cmd_plobj_to_string_id = _vt_cmd_plobj_to_string_id_qdisc, + .cmd_plobj_to_string = (const char *(*) (const NMPlatformObject *obj, char *buf, gsize len)) nm_platform_qdisc_to_string, + .cmd_plobj_hash_update = (void (*) (const NMPlatformObject *obj, NMHashState *h)) nm_platform_qdisc_hash_update, + .cmd_plobj_cmp = (int (*) (const NMPlatformObject *obj1, const NMPlatformObject *obj2)) nm_platform_qdisc_cmp, + }, + [NMP_OBJECT_TYPE_TFILTER - 1] = { + .parent = DEDUP_MULTI_OBJ_CLASS_INIT(), + .obj_type = NMP_OBJECT_TYPE_TFILTER, + .sizeof_data = sizeof (NMPObjectTfilter), + .sizeof_public = sizeof (NMPlatformTfilter), + .obj_type_name = "tfilter", + .rtm_gettype = RTM_GETTFILTER, + .signal_type_id = NM_PLATFORM_SIGNAL_ID_TFILTER, + .signal_type = NM_PLATFORM_SIGNAL_TFILTER_CHANGED, + .supported_cache_ids = _supported_cache_ids_object, + .cmd_obj_is_alive = _vt_cmd_obj_is_alive_tfilter, + .cmd_plobj_id_cmp = _vt_cmd_plobj_id_cmp_tfilter, + .cmd_plobj_id_hash_update = _vt_cmd_plobj_id_hash_update_tfilter, + .cmd_plobj_to_string_id = _vt_cmd_plobj_to_string_id_tfilter, + .cmd_plobj_to_string = (const char *(*) (const NMPlatformObject *obj, char *buf, gsize len)) nm_platform_tfilter_to_string, + .cmd_plobj_hash_update = (void (*) (const NMPlatformObject *obj, NMHashState *h)) nm_platform_tfilter_hash_update, + .cmd_plobj_cmp = (int (*) (const NMPlatformObject *obj1, const NMPlatformObject *obj2)) nm_platform_tfilter_cmp, + }, [NMP_OBJECT_TYPE_LNK_GRE - 1] = { .parent = DEDUP_MULTI_OBJ_CLASS_INIT(), .obj_type = NMP_OBJECT_TYPE_LNK_GRE, diff --git a/src/platform/nmp-object.h b/src/platform/nmp-object.h index 41fd08cb..e3862f2d 100644 --- a/src/platform/nmp-object.h +++ b/src/platform/nmp-object.h @@ -15,7 +15,7 @@ * with this program; if not, write to the Free Software Foundation, Inc., * 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA. * - * Copyright (C) 2015 Red Hat, Inc. + * Copyright (C) 2015 - 2017 Red Hat, Inc. */ #ifndef __NMP_OBJECT_H__ @@ -35,8 +35,8 @@ typedef enum { /*< skip >*/ typedef enum { /*< skip >*/ NMP_CACHE_OPS_UNCHANGED = NM_PLATFORM_SIGNAL_NONE, - NMP_CACHE_OPS_UPDATED = NM_PLATFORM_SIGNAL_CHANGED, NMP_CACHE_OPS_ADDED = NM_PLATFORM_SIGNAL_ADDED, + NMP_CACHE_OPS_UPDATED = NM_PLATFORM_SIGNAL_CHANGED, NMP_CACHE_OPS_REMOVED = NM_PLATFORM_SIGNAL_REMOVED, } NMPCacheOpsType; @@ -48,12 +48,12 @@ typedef enum { /*< skip >*/ * but only route objects can be indexed by NMP_CACHE_ID_TYPE_ROUTES_VISIBLE_NO_DEFAULT. * * Of one index type, there can be multiple indexes or not. - * For example, of the index type NMP_CACHE_ID_TYPE_ADDRROUTE_BY_IFINDEX there + * For example, of the index type NMP_CACHE_ID_TYPE_OBJECT_BY_IFINDEX there * are multiple instances (for different route/addresses, v4/v6, per-ifindex). * * But one object, can only be indexed by one particular index of a * type. For example, a certain address instance is only indexed by - * the index NMP_CACHE_ID_TYPE_ADDRROUTE_BY_IFINDEX with + * the index NMP_CACHE_ID_TYPE_OBJECT_BY_IFINDEX with * matching v4/v6 and ifindex -- or maybe not at all if it isn't visible. * */ typedef enum { /*< skip >*/ @@ -82,8 +82,8 @@ typedef enum { /*< skip >*/ * separate for IPv4 and IPv6. */ NMP_CACHE_ID_TYPE_DEFAULT_ROUTES, - /* all the addresses/routes (by object-type) for an ifindex. */ - NMP_CACHE_ID_TYPE_ADDRROUTE_BY_IFINDEX, + /* all the objects that have an ifindex (by object-type) for an ifindex. */ + NMP_CACHE_ID_TYPE_OBJECT_BY_IFINDEX, /* Consider all the destination fields of a route, that is, the ID without the ifindex * and gateway (meaning: network/plen,metric). @@ -225,6 +225,14 @@ typedef struct { NMPlatformIP6Route _public; } NMPObjectIP6Route; +typedef struct { + NMPlatformQdisc _public; +} NMPObjectQdisc; + +typedef struct { + NMPlatformTfilter _public; +} NMPObjectTfilter; + struct _NMPObject { union { NMDedupMultiObj parent; @@ -276,6 +284,11 @@ struct _NMPObject { NMPlatformIP6Route ip6_route; NMPObjectIP4Route _ip4_route; NMPObjectIP6Route _ip6_route; + + NMPlatformQdisc qdisc; + NMPObjectQdisc _qdisc; + NMPlatformTfilter tfilter; + NMPObjectTfilter _tfilter; }; }; @@ -341,7 +354,7 @@ NMP_OBJECT_GET_TYPE (const NMPObject *obj) typeof (obj) _obj = (obj); \ \ nm_assert (!_obj || NMP_OBJECT_GET_TYPE ((const NMPObject *) _obj) == NMP_OBJECT_TYPE_LINK); \ - _obj ? &_NM_CONSTCAST (NMPObject, _obj)->link : NULL; \ + _obj ? &NM_CONSTCAST (NMPObject, _obj)->link : NULL; \ }) #define NMP_OBJECT_CAST_IP_ADDRESS(obj) \ @@ -349,7 +362,7 @@ NMP_OBJECT_GET_TYPE (const NMPObject *obj) typeof (obj) _obj = (obj); \ \ nm_assert (!_obj || NM_IN_SET (NMP_OBJECT_GET_TYPE (_obj), NMP_OBJECT_TYPE_IP4_ADDRESS, NMP_OBJECT_TYPE_IP6_ADDRESS)); \ - _obj ? &_NM_CONSTCAST (NMPObject, _obj)->ip_address : NULL; \ + _obj ? &NM_CONSTCAST (NMPObject, _obj)->ip_address : NULL; \ }) #define NMP_OBJECT_CAST_IPX_ADDRESS(obj) \ @@ -357,7 +370,7 @@ NMP_OBJECT_GET_TYPE (const NMPObject *obj) typeof (obj) _obj = (obj); \ \ nm_assert (!_obj || NM_IN_SET (NMP_OBJECT_GET_TYPE (_obj), NMP_OBJECT_TYPE_IP4_ADDRESS, NMP_OBJECT_TYPE_IP6_ADDRESS)); \ - _obj ? &_NM_CONSTCAST (NMPObject, _obj)->ipx_address : NULL; \ + _obj ? &NM_CONSTCAST (NMPObject, _obj)->ipx_address : NULL; \ }) #define NMP_OBJECT_CAST_IP4_ADDRESS(obj) \ @@ -365,7 +378,7 @@ NMP_OBJECT_GET_TYPE (const NMPObject *obj) typeof (obj) _obj = (obj); \ \ nm_assert (!_obj || NMP_OBJECT_GET_TYPE ((const NMPObject *) _obj) == NMP_OBJECT_TYPE_IP4_ADDRESS); \ - _obj ? &_NM_CONSTCAST (NMPObject, _obj)->ip4_address : NULL; \ + _obj ? &NM_CONSTCAST (NMPObject, _obj)->ip4_address : NULL; \ }) #define NMP_OBJECT_CAST_IP6_ADDRESS(obj) \ @@ -373,7 +386,7 @@ NMP_OBJECT_GET_TYPE (const NMPObject *obj) typeof (obj) _obj = (obj); \ \ nm_assert (!_obj || NMP_OBJECT_GET_TYPE ((const NMPObject *) _obj) == NMP_OBJECT_TYPE_IP6_ADDRESS); \ - _obj ? &_NM_CONSTCAST (NMPObject, _obj)->ip6_address : NULL; \ + _obj ? &NM_CONSTCAST (NMPObject, _obj)->ip6_address : NULL; \ }) #define NMP_OBJECT_CAST_IPX_ROUTE(obj) \ @@ -381,7 +394,7 @@ NMP_OBJECT_GET_TYPE (const NMPObject *obj) typeof (obj) _obj = (obj); \ \ nm_assert (!_obj || NM_IN_SET (NMP_OBJECT_GET_TYPE (_obj), NMP_OBJECT_TYPE_IP4_ROUTE, NMP_OBJECT_TYPE_IP6_ROUTE)); \ - _obj ? &_NM_CONSTCAST (NMPObject, _obj)->ipx_route : NULL; \ + _obj ? &NM_CONSTCAST (NMPObject, _obj)->ipx_route : NULL; \ }) #define NMP_OBJECT_CAST_IP_ROUTE(obj) \ @@ -389,7 +402,7 @@ NMP_OBJECT_GET_TYPE (const NMPObject *obj) typeof (obj) _obj = (obj); \ \ nm_assert (!_obj || NM_IN_SET (NMP_OBJECT_GET_TYPE (_obj), NMP_OBJECT_TYPE_IP4_ROUTE, NMP_OBJECT_TYPE_IP6_ROUTE)); \ - _obj ? &_NM_CONSTCAST (NMPObject, _obj)->ip_route : NULL; \ + _obj ? &NM_CONSTCAST (NMPObject, _obj)->ip_route : NULL; \ }) #define NMP_OBJECT_CAST_IP4_ROUTE(obj) \ @@ -397,7 +410,7 @@ NMP_OBJECT_GET_TYPE (const NMPObject *obj) typeof (obj) _obj = (obj); \ \ nm_assert (!_obj || NMP_OBJECT_GET_TYPE ((const NMPObject *) _obj) == NMP_OBJECT_TYPE_IP4_ROUTE); \ - _obj ? &_NM_CONSTCAST (NMPObject, _obj)->ip4_route : NULL; \ + _obj ? &NM_CONSTCAST (NMPObject, _obj)->ip4_route : NULL; \ }) #define NMP_OBJECT_CAST_IP6_ROUTE(obj) \ @@ -405,7 +418,23 @@ NMP_OBJECT_GET_TYPE (const NMPObject *obj) typeof (obj) _obj = (obj); \ \ nm_assert (!_obj || NMP_OBJECT_GET_TYPE ((const NMPObject *) _obj) == NMP_OBJECT_TYPE_IP6_ROUTE); \ - _obj ? &_NM_CONSTCAST (NMPObject, _obj)->ip6_route : NULL; \ + _obj ? &NM_CONSTCAST (NMPObject, _obj)->ip6_route : NULL; \ + }) + +#define NMP_OBJECT_CAST_QDISC(obj) \ + ({ \ + typeof (obj) _obj = (obj); \ + \ + nm_assert (!_obj || NMP_OBJECT_GET_TYPE ((const NMPObject *) _obj) == NMP_OBJECT_TYPE_QDISC); \ + _obj ? &NM_CONSTCAST (NMPObject, _obj)->qdisc : NULL; \ + }) + +#define NMP_OBJECT_CAST_TFILTER(obj) \ + ({ \ + typeof (obj) _obj = (obj); \ + \ + nm_assert (!_obj || NMP_OBJECT_GET_TYPE ((const NMPObject *) _obj) == NMP_OBJECT_TYPE_TFILTER); \ + _obj ? &NM_CONSTCAST (NMPObject, _obj)->tfilter : NULL; \ }) const NMPClass *nmp_class_from_type (NMPObjectType obj_type); @@ -536,9 +565,9 @@ const NMPLookup *nmp_lookup_init_obj_type (NMPLookup *lookup, NMPObjectType obj_type); const NMPLookup *nmp_lookup_init_link_by_ifname (NMPLookup *lookup, const char *ifname); -const NMPLookup *nmp_lookup_init_addrroute (NMPLookup *lookup, - NMPObjectType obj_type, - int ifindex); +const NMPLookup *nmp_lookup_init_object (NMPLookup *lookup, + NMPObjectType obj_type, + int ifindex); const NMPLookup *nmp_lookup_init_route_default (NMPLookup *lookup, NMPObjectType obj_type); const NMPLookup *nmp_lookup_init_route_by_weak_id (NMPLookup *lookup, @@ -717,26 +746,26 @@ nm_platform_lookup_link_by_ifname (NMPlatform *platform, } static inline const NMDedupMultiHeadEntry * -nm_platform_lookup_addrroute (NMPlatform *platform, - NMPObjectType obj_type, - int ifindex) +nm_platform_lookup_object (NMPlatform *platform, + NMPObjectType obj_type, + int ifindex) { NMPLookup lookup; - nmp_lookup_init_addrroute (&lookup, obj_type, ifindex); + nmp_lookup_init_object (&lookup, obj_type, ifindex); return nm_platform_lookup (platform, &lookup); } static inline GPtrArray * -nm_platform_lookup_addrroute_clone (NMPlatform *platform, - NMPObjectType obj_type, - int ifindex, - NMPObjectPredicateFunc predicate, - gpointer user_data) +nm_platform_lookup_object_clone (NMPlatform *platform, + NMPObjectType obj_type, + int ifindex, + NMPObjectPredicateFunc predicate, + gpointer user_data) { NMPLookup lookup; - nmp_lookup_init_addrroute (&lookup, obj_type, ifindex); + nmp_lookup_init_object (&lookup, obj_type, ifindex); return nm_platform_lookup_clone (platform, &lookup, predicate, user_data); } diff --git a/src/platform/tests/test-common.c b/src/platform/tests/test-common.c index 18076712..9a12f8f9 100644 --- a/src/platform/tests/test-common.c +++ b/src/platform/tests/test-common.c @@ -15,7 +15,7 @@ * with this program; if not, write to the Free Software Foundation, Inc., * 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA. * - * Copyright 2016 Red Hat, Inc. + * Copyright 2016 - 2017 Red Hat, Inc. */ #include "nm-default.h" @@ -78,9 +78,9 @@ _ipx_address_get_all (NMPlatform *self, int ifindex, NMPObjectType obj_type) g_assert (NM_IS_PLATFORM (self)); g_assert (ifindex > 0); g_assert (NM_IN_SET (obj_type, NMP_OBJECT_TYPE_IP4_ADDRESS, NMP_OBJECT_TYPE_IP6_ADDRESS)); - nmp_lookup_init_addrroute (&lookup, - obj_type, - ifindex); + nmp_lookup_init_object (&lookup, + obj_type, + ifindex); return nmp_cache_lookup_to_array (nm_platform_lookup (self, &lookup), obj_type, FALSE /*addresses are always visible. */); @@ -108,9 +108,9 @@ nmtstp_platform_ip4_route_delete (NMPlatform *platform, int ifindex, in_addr_t n nm_platform_process_events (platform); nm_dedup_multi_iter_for_each (&iter, - nm_platform_lookup_addrroute (platform, - NMP_OBJECT_TYPE_IP4_ROUTE, - ifindex)) { + nm_platform_lookup_object (platform, + NMP_OBJECT_TYPE_IP4_ROUTE, + ifindex)) { const NMPlatformIP4Route *r = NMP_OBJECT_CAST_IP4_ROUTE (iter.current->obj); if ( r->ifindex != ifindex @@ -120,7 +120,7 @@ nmtstp_platform_ip4_route_delete (NMPlatform *platform, int ifindex, in_addr_t n continue; } - return nm_platform_ip_route_delete (platform, NMP_OBJECT_UP_CAST (r)); + return nm_platform_object_delete (platform, NMP_OBJECT_UP_CAST (r)); } return TRUE; @@ -134,9 +134,9 @@ nmtstp_platform_ip6_route_delete (NMPlatform *platform, int ifindex, struct in6_ nm_platform_process_events (platform); nm_dedup_multi_iter_for_each (&iter, - nm_platform_lookup_addrroute (platform, - NMP_OBJECT_TYPE_IP6_ROUTE, - ifindex)) { + nm_platform_lookup_object (platform, + NMP_OBJECT_TYPE_IP6_ROUTE, + ifindex)) { const NMPlatformIP6Route *r = NMP_OBJECT_CAST_IP6_ROUTE (iter.current->obj); if ( r->ifindex != ifindex @@ -146,7 +146,7 @@ nmtstp_platform_ip6_route_delete (NMPlatform *platform, int ifindex, struct in6_ continue; } - return nm_platform_ip_route_delete (platform, NMP_OBJECT_UP_CAST (r)); + return nm_platform_object_delete (platform, NMP_OBJECT_UP_CAST (r)); } return TRUE; @@ -1703,8 +1703,8 @@ nmtstp_namespace_create (int unshare_flags, GError **error) errsv = errno; g_set_error (error, NM_UTILS_ERROR, NM_UTILS_ERROR_UNKNOWN, "pipe() failed with %d (%s)", errsv, strerror (errsv)); - close (pipefd_c2p[0]); - close (pipefd_c2p[1]); + nm_close (pipefd_c2p[0]); + nm_close (pipefd_c2p[1]); return FALSE; } @@ -1713,18 +1713,18 @@ nmtstp_namespace_create (int unshare_flags, GError **error) errsv = errno; g_set_error (error, NM_UTILS_ERROR, NM_UTILS_ERROR_UNKNOWN, "fork() failed with %d (%s)", errsv, strerror (errsv)); - close (pipefd_c2p[0]); - close (pipefd_c2p[1]); - close (pipefd_p2c[0]); - close (pipefd_p2c[1]); + nm_close (pipefd_c2p[0]); + nm_close (pipefd_c2p[1]); + nm_close (pipefd_p2c[0]); + nm_close (pipefd_p2c[1]); return FALSE; } if (pid == 0) { char read_buf[1]; - close (pipefd_c2p[0]); /* close read-end */ - close (pipefd_p2c[1]); /* close write-end */ + nm_close (pipefd_c2p[0]); /* close read-end */ + nm_close (pipefd_p2c[1]); /* close write-end */ if (unshare (unshare_flags) != 0) { errsv = errno; @@ -1742,7 +1742,7 @@ nmtstp_namespace_create (int unshare_flags, GError **error) if (errsv == 0) errsv = -2; } - close (pipefd_c2p[1]); + nm_close (pipefd_c2p[1]); /* wait until parent process terminates (or kills us). */ if (errsv == 0) { @@ -1750,19 +1750,19 @@ nmtstp_namespace_create (int unshare_flags, GError **error) r = read (pipefd_p2c[0], read_buf, sizeof (read_buf)); } while (r < 0 && errno == EINTR); } - close (pipefd_p2c[0]); + nm_close (pipefd_p2c[0]); _exit (0); } - close (pipefd_c2p[1]); /* close write-end */ - close (pipefd_p2c[0]); /* close read-end */ + nm_close (pipefd_c2p[1]); /* close write-end */ + nm_close (pipefd_p2c[0]); /* close read-end */ /* sync with child process. */ do { r = read (pipefd_c2p[0], &errsv, sizeof (errsv)); } while (r < 0 && errno == EINTR); - close (pipefd_c2p[0]); + nm_close (pipefd_c2p[0]); if ( r != sizeof (errsv) || errsv != 0) { @@ -1775,7 +1775,7 @@ nmtstp_namespace_create (int unshare_flags, GError **error) g_set_error (error, NM_UTILS_ERROR, NM_UTILS_ERROR_UNKNOWN, "child process signaled failure %d (%s)", errsv, strerror (errsv)); } - close (pipefd_p2c[1]); + nm_close (pipefd_p2c[1]); kill (pid, SIGKILL); do { pid2 = waitpid (pid, &status, 0); @@ -1809,7 +1809,7 @@ nmtstp_namespace_handle_release (NMTstpNamespaceHandle *ns_handle) g_return_if_fail (ns_handle->pid > 0); - close (ns_handle->pipe_fd); + nm_close (ns_handle->pipe_fd); ns_handle->pipe_fd = 0; kill (ns_handle->pid, SIGKILL); diff --git a/src/platform/tests/test-common.h b/src/platform/tests/test-common.h index 4010aa2f..fb406a3f 100644 --- a/src/platform/tests/test-common.h +++ b/src/platform/tests/test-common.h @@ -227,22 +227,22 @@ static inline GPtrArray * nmtstp_ip4_route_get_all (NMPlatform *platform, int ifindex) { - return nm_platform_lookup_addrroute_clone (platform, - NMP_OBJECT_TYPE_IP4_ROUTE, - ifindex, - nm_platform_lookup_predicate_routes_main_skip_rtprot_kernel, - NULL); + return nm_platform_lookup_object_clone (platform, + NMP_OBJECT_TYPE_IP4_ROUTE, + ifindex, + nm_platform_lookup_predicate_routes_main_skip_rtprot_kernel, + NULL); } static inline GPtrArray * nmtstp_ip6_route_get_all (NMPlatform *platform, int ifindex) { - return nm_platform_lookup_addrroute_clone (platform, - NMP_OBJECT_TYPE_IP6_ROUTE, - ifindex, - nm_platform_lookup_predicate_routes_main_skip_rtprot_kernel, - NULL); + return nm_platform_lookup_object_clone (platform, + NMP_OBJECT_TYPE_IP6_ROUTE, + ifindex, + nm_platform_lookup_predicate_routes_main_skip_rtprot_kernel, + NULL); } /*****************************************************************************/ diff --git a/src/platform/tests/test-link.c b/src/platform/tests/test-link.c index 9c72371c..d3a10bd6 100644 --- a/src/platform/tests/test-link.c +++ b/src/platform/tests/test-link.c @@ -1916,6 +1916,7 @@ _test_netns_check_skip (void) static int support = -1; static int support_errsv = 0; NMPNetns *netns; + gs_unref_object NMPNetns *netns2 = NULL; netns = nmp_netns_get_current (); if (!netns) { @@ -1931,10 +1932,20 @@ _test_netns_check_skip (void) support_errsv = errno; } if (!support) { - _LOGD ("setns() failed with \"%s\". This indicates missing support (valgrind?)", g_strerror (support_errsv)); - g_test_skip ("No netns support (setns failed)"); + _LOGD ("setns() failed with \"%s\". This indicates missing support (valgrind?)", g_strerror (support_errsv)); + g_test_skip ("No netns support (setns failed)"); return TRUE; } + + netns2 = nmp_netns_new (); + if (!netns2) { + /* skip tests for https://bugzilla.gnome.org/show_bug.cgi?id=790214 */ + g_assert_cmpint (errno, ==, EINVAL); + g_test_skip ("No netns support to create another netns"); + return TRUE; + } + nmp_netns_pop (netns2); + return FALSE; } diff --git a/src/platform/tests/test-nmp-object.c b/src/platform/tests/test-nmp-object.c index a02388d2..3228de83 100644 --- a/src/platform/tests/test-nmp-object.c +++ b/src/platform/tests/test-nmp-object.c @@ -15,12 +15,13 @@ * with this program; if not, write to the Free Software Foundation, Inc., * 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA. * - * Copyright (C) 2015 Red Hat, Inc. + * Copyright (C) 2015 - 2017 Red Hat, Inc. */ #include "nm-default.h" #include <libudev.h> +#include <linux/pkt_sched.h> #include "platform/nmp-object.h" #include "nm-utils/nm-udev-utils.h" @@ -454,6 +455,93 @@ test_cache_link (void) nmp_cache_free (cache); } +const char noqueue[] = "noqueue"; +const char fq_codel[] = "fq_codel"; +const char ingress[] = "ingress"; + +static const NMPlatformQdisc pl_qdisc_1a = { + .ifindex = 1, + .kind = noqueue, + .addr_family = AF_UNSPEC, + .handle = 0, + .parent = TC_H_ROOT, + .info = 0, +}; + +static const NMPlatformQdisc pl_qdisc_1b = { + .ifindex = 1, + .kind = fq_codel, + .addr_family = AF_UNSPEC, + .handle = 0, + .parent = TC_H_ROOT, + .info = 0, +}; + +static const NMPlatformQdisc pl_qdisc_1c = { + .ifindex = 1, + .kind = ingress, + .addr_family = AF_UNSPEC, + .handle = TC_H_MAKE(TC_H_INGRESS, 0), + .parent = TC_H_INGRESS, + .info = 0, +}; + +static const NMPlatformQdisc pl_qdisc_2 = { + .ifindex = 2, + .kind = fq_codel, + .addr_family = AF_UNSPEC, + .handle = 0, + .parent = TC_H_ROOT, + .info = 0, +}; + +static void +test_cache_qdisc (void) +{ + NMPCache *cache; + nm_auto_unref_dedup_multi_index NMDedupMultiIndex *multi_idx = NULL; + NMPLookup lookup; + const NMDedupMultiHeadEntry *head_entry; + nm_auto_nmpobj NMPObject *obj1a = nmp_object_new (NMP_OBJECT_TYPE_QDISC, (NMPlatformObject *) &pl_qdisc_1a); + nm_auto_nmpobj NMPObject *obj1b = nmp_object_new (NMP_OBJECT_TYPE_QDISC, (NMPlatformObject *) &pl_qdisc_1b); + nm_auto_nmpobj NMPObject *obj1c = nmp_object_new (NMP_OBJECT_TYPE_QDISC, (NMPlatformObject *) &pl_qdisc_1c); + nm_auto_nmpobj NMPObject *obj2 = nmp_object_new (NMP_OBJECT_TYPE_QDISC, (NMPlatformObject *) &pl_qdisc_2); + + multi_idx = nm_dedup_multi_index_new (); + cache = nmp_cache_new (multi_idx, nmtst_get_rand_int () % 2); + + g_assert (nmp_cache_lookup_obj (cache, obj1a) == NULL); + + g_assert (nmp_cache_update_netlink (cache, obj1a, FALSE, NULL, NULL) == NMP_CACHE_OPS_ADDED); + g_assert (nmp_cache_lookup_obj (cache, obj1a) == obj1a); + g_assert (nmp_cache_lookup_obj (cache, obj1b) == obj1a); + g_assert (nmp_cache_lookup_obj (cache, obj2) == NULL); + + g_assert (nmp_cache_update_netlink (cache, obj1b, FALSE, NULL, NULL) == NMP_CACHE_OPS_UPDATED); + g_assert (nmp_cache_lookup_obj (cache, obj1a) == obj1b); + g_assert (nmp_cache_lookup_obj (cache, obj1b) == obj1b); + g_assert (nmp_cache_lookup_obj (cache, obj2) == NULL); + + g_assert (nmp_cache_update_netlink (cache, obj1c, FALSE, NULL, NULL) == NMP_CACHE_OPS_ADDED); + g_assert (nmp_cache_lookup_obj (cache, obj1a) == obj1b); + g_assert (nmp_cache_lookup_obj (cache, obj1b) == obj1b); + g_assert (nmp_cache_lookup_obj (cache, obj1c) == obj1c); + g_assert (nmp_cache_lookup_obj (cache, obj2) == NULL); + + g_assert (nmp_cache_update_netlink (cache, obj2, FALSE, NULL, NULL) == NMP_CACHE_OPS_ADDED); + g_assert (nmp_cache_lookup_obj (cache, obj1a) == obj1b); + g_assert (nmp_cache_lookup_obj (cache, obj1b) == obj1b); + g_assert (nmp_cache_lookup_obj (cache, obj2) == obj2); + + head_entry = nmp_cache_lookup (cache, + nmp_lookup_init_object (&lookup, + NMP_OBJECT_TYPE_QDISC, + 1)); + g_assert (head_entry->len == 2); + + nmp_cache_free (cache); +} + /*****************************************************************************/ NMTST_DEFINE (); @@ -500,6 +588,7 @@ main (int argc, char **argv) g_test_add_func ("/nmp-object/obj-base", test_obj_base); g_test_add_func ("/nmp-object/cache_link", test_cache_link); + g_test_add_func ("/nmp-object/cache_qdisc", test_cache_qdisc); result = g_test_run (); diff --git a/src/platform/tests/test-route.c b/src/platform/tests/test-route.c index 2c00fada..fe97db07 100644 --- a/src/platform/tests/test-route.c +++ b/src/platform/tests/test-route.c @@ -15,7 +15,7 @@ * with this program; if not, write to the Free Software Foundation, Inc., * 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA. * - * Copyright 2016 Red Hat, Inc. + * Copyright 2016 - 2017 Red Hat, Inc. */ #include "nm-default.h" @@ -31,6 +31,42 @@ #define EX NMTSTP_ENV1_EX static void +_wait_for_ipv4_addr_device_route (NMPlatform *platform, + gint64 timeout_ms, + int ifindex, + in_addr_t addr, + guint8 plen) +{ + /* Wait that the addresses gets a device-route. After adding a address, + * the device route is not added immediately. It takes a moment... */ + + addr = nm_utils_ip4_address_clear_host_address (addr, plen); + NMTST_WAIT_ASSERT (400, { + NMDedupMultiIter iter; + NMPLookup lookup; + const NMPObject *o; + + nmp_cache_iter_for_each (&iter, + nm_platform_lookup (platform, + nmp_lookup_init_object (&lookup, + NMP_OBJECT_TYPE_IP4_ROUTE, + ifindex)), + &o) { + const NMPlatformIP4Route *r = NMP_OBJECT_CAST_IP4_ROUTE (o); + + if ( r->plen == plen + && addr == nm_utils_ip4_address_clear_host_address (r->network, plen) + && r->metric == 0 + && r->scope_inv == nm_platform_route_scope_inv (RT_SCOPE_LINK) + && r->rt_source == NM_IP_CONFIG_SOURCE_RTPROT_KERNEL) + return; + } + nmtstp_assert_wait_for_signal (platform, + (nmtst_wait_end_us - g_get_monotonic_time ()) / 1000); + }); +} + +static void _wait_for_ipv6_addr_non_tentative (NMPlatform *platform, gint64 timeout_ms, int ifindex, @@ -44,7 +80,7 @@ _wait_for_ipv6_addr_non_tentative (NMPlatform *platform, * small amount of time, which prevents the immediate addition of the route * with RTA_PREFSRC */ - NMTST_WAIT_ASSERT (400, { + NMTST_WAIT_ASSERT (timeout_ms, { gboolean should_wait = FALSE; const NMPlatformIP6Address *plt_addr; @@ -63,7 +99,6 @@ _wait_for_ipv6_addr_non_tentative (NMPlatform *platform, }); } - static void ip4_route_callback (NMPlatform *platform, int obj_type_i, int ifindex, const NMPlatformIP4Route *received, int change_type_i, SignalData *data) { @@ -417,7 +452,7 @@ test_ip_route_get (void) g_assert (!NMP_OBJECT_IS_STACKINIT (route)); g_assert (route->parent._ref_count == 1); r = NMP_OBJECT_CAST_IP4_ROUTE (route); - g_assert (r->rt_cloned); + g_assert (NM_FLAGS_HAS (r->r_rtm_flags, RTM_F_CLONED)); g_assert (r->ifindex == ifindex); g_assert (r->network == a); g_assert (r->plen == 32); @@ -448,63 +483,114 @@ test_ip4_zero_gateway (void) } static void -test_ip4_route_options (void) +test_ip4_route_options (gconstpointer test_data) { - int ifindex = nm_platform_link_get_ifindex (NM_PLATFORM_GET, DEVICE_NAME); - NMPlatformIP4Route route = { }; - in_addr_t network; - GPtrArray *routes; - NMPlatformIP4Route rts[1]; + const int TEST_IDX = GPOINTER_TO_INT (test_data); + const int IFINDEX = nm_platform_link_get_ifindex (NM_PLATFORM_GET, DEVICE_NAME); + gs_unref_ptrarray GPtrArray *routes = NULL; +#define RTS_MAX 3 + NMPlatformIP4Route rts_add[RTS_MAX] = { }; + NMPlatformIP4Route rts_cmp[RTS_MAX] = { }; + NMPlatformIP4Address addr[1] = { }; + guint i; + guint rts_n = 0; + guint addr_n = 0; - inet_pton (AF_INET, "172.16.1.0", &network); + switch (TEST_IDX) { + case 1: + rts_add[rts_n++] = ((NMPlatformIP4Route) { + .ifindex = IFINDEX, + .rt_source = NM_IP_CONFIG_SOURCE_USER, + .network = nmtst_inet4_from_string ("172.16.1.0"), + .plen = 24, + .metric = 20, + .tos = 0x28, + .window = 10000, + .cwnd = 16, + .initcwnd = 30, + .initrwnd = 50, + .mtu = 1350, + .lock_cwnd = TRUE, + }); + break; + case 2: + addr[addr_n++] = ((NMPlatformIP4Address) { + .ifindex = IFINDEX, + .address = nmtst_inet4_from_string ("172.16.1.5"), + .peer_address = nmtst_inet4_from_string ("172.16.1.5"), + .plen = 24, + .lifetime = NM_PLATFORM_LIFETIME_PERMANENT, + .preferred = NM_PLATFORM_LIFETIME_PERMANENT, + .n_ifa_flags = 0, + }); + rts_add[rts_n++] = ((NMPlatformIP4Route) { + .ifindex = IFINDEX, + .rt_source = NM_IP_CONFIG_SOURCE_USER, + .network = nmtst_inet4_from_string ("172.17.1.0"), + .gateway = nmtst_inet4_from_string ("172.16.1.1"), + .plen = 24, + .metric = 20, + }); + rts_add[rts_n++] = ((NMPlatformIP4Route) { + .ifindex = IFINDEX, + .rt_source = NM_IP_CONFIG_SOURCE_USER, + .network = nmtst_inet4_from_string ("172.19.1.0"), + .gateway = nmtst_inet4_from_string ("172.18.1.1"), + .r_rtm_flags = RTNH_F_ONLINK, + .plen = 24, + .metric = 20, + }); + break; + default: + g_assert_not_reached (); + break; + } + g_assert (rts_n <= G_N_ELEMENTS (rts_add)); + g_assert (addr_n <= G_N_ELEMENTS (addr)); - route.ifindex = ifindex; - route.rt_source = NM_IP_CONFIG_SOURCE_USER; - route.network = network; - route.plen = 24; - route.metric = 20; - route.tos = 0x28; - route.window = 10000; - route.cwnd = 16; - route.initcwnd = 30; - route.initrwnd = 50; - route.mtu = 1350; - route.lock_cwnd = TRUE; + for (i = 0; i < addr_n; i++) { + const NMPlatformIP4Address *a = &addr[i]; + + g_assert (a->ifindex == IFINDEX); + g_assert (nm_platform_ip4_address_add (NM_PLATFORM_GET, + a->ifindex, + a->address, + a->plen, + a->peer_address, + a->lifetime, + a->preferred, + a->n_ifa_flags, + a->label)); + if (a->peer_address == a->address) + _wait_for_ipv4_addr_device_route (NM_PLATFORM_GET, 200, a->ifindex, a->address, a->plen); + } - g_assert (nm_platform_ip4_route_add (NM_PLATFORM_GET, NMP_NLM_FLAG_REPLACE, &route) == NM_PLATFORM_ERROR_SUCCESS); + for (i = 0; i < rts_n; i++) + g_assert (nm_platform_ip4_route_add (NM_PLATFORM_GET, NMP_NLM_FLAG_REPLACE, &rts_add[i]) == NM_PLATFORM_ERROR_SUCCESS); - /* Test route listing */ - routes = nmtstp_ip4_route_get_all (NM_PLATFORM_GET, ifindex); - memset (rts, 0, sizeof (rts)); - rts[0].rt_source = nmp_utils_ip_config_source_round_trip_rtprot (NM_IP_CONFIG_SOURCE_USER); - rts[0].scope_inv = nm_platform_route_scope_inv (RT_SCOPE_LINK); - rts[0].network = network; - rts[0].plen = 24; - rts[0].ifindex = ifindex; - rts[0].metric = 20; - rts[0].tos = 0x28; - rts[0].window = 10000; - rts[0].cwnd = 16; - rts[0].initcwnd = 30; - rts[0].initrwnd = 50; - rts[0].mtu = 1350; - rts[0].lock_cwnd = TRUE; - g_assert_cmpint (routes->len, ==, 1); - nmtst_platform_ip4_routes_equal_aptr ((const NMPObject *const*) routes->pdata, rts, routes->len, TRUE); + for (i = 0; i < rts_n; i++) { + rts_cmp[i] = rts_add[i]; + nm_platform_ip_route_normalize (AF_INET, NM_PLATFORM_IP_ROUTE_CAST (&rts_cmp[i])); + } - /* Remove route */ - g_assert (nm_platform_ip_route_delete (NM_PLATFORM_GET, routes->pdata[0])); + routes = nmtstp_ip4_route_get_all (NM_PLATFORM_GET, IFINDEX); + g_assert_cmpint (routes->len, ==, rts_n); + nmtst_platform_ip4_routes_equal_aptr ((const NMPObject *const*) routes->pdata, rts_cmp, routes->len, TRUE); - g_ptr_array_unref (routes); + for (i = 0; i < rts_n; i++) { + g_assert (nmtstp_platform_ip4_route_delete (NM_PLATFORM_GET, IFINDEX, + rts_add[i].network, rts_add[i].plen, + rts_add[i].metric)); + } +#undef RTS_MAX } - static void test_ip6_route_options (gconstpointer test_data) { const int TEST_IDX = GPOINTER_TO_INT (test_data); const int IFINDEX = nm_platform_link_get_ifindex (NM_PLATFORM_GET, DEVICE_NAME); - GPtrArray *routes; + gs_unref_ptrarray GPtrArray *routes = NULL; #define RTS_MAX 3 NMPlatformIP6Route rts_add[RTS_MAX] = { }; NMPlatformIP6Route rts_cmp[RTS_MAX] = { }; @@ -582,6 +668,8 @@ test_ip6_route_options (gconstpointer test_data) default: g_assert_not_reached (); } + g_assert (rts_n <= G_N_ELEMENTS (rts_add)); + g_assert (addr_n <= G_N_ELEMENTS (addr)); for (i = 0; i < addr_n; i++) { g_assert (addr[i].ifindex == IFINDEX); @@ -595,28 +683,19 @@ test_ip6_route_options (gconstpointer test_data) addr[i].preferred, addr[i].n_ifa_flags)); } - _wait_for_ipv6_addr_non_tentative (NM_PLATFORM_GET, 400, IFINDEX, addr_n, addr_in6); for (i = 0; i < rts_n; i++) g_assert (nm_platform_ip6_route_add (NM_PLATFORM_GET, NMP_NLM_FLAG_REPLACE, &rts_add[i]) == NM_PLATFORM_ERROR_SUCCESS); - routes = nmtstp_ip6_route_get_all (NM_PLATFORM_GET, IFINDEX); - switch (TEST_IDX) { - case 1: - case 2: - case 3: - for (i = 0; i < rts_n; i++) { - rts_cmp[i] = rts_add[i]; - rts_cmp[i].rt_source = nmp_utils_ip_config_source_round_trip_rtprot (NM_IP_CONFIG_SOURCE_USER); - } - break; - default: - g_assert_not_reached (); + for (i = 0; i < rts_n; i++) { + rts_cmp[i] = rts_add[i]; + nm_platform_ip_route_normalize (AF_INET6, NM_PLATFORM_IP_ROUTE_CAST (&rts_cmp[i])); } + + routes = nmtstp_ip6_route_get_all (NM_PLATFORM_GET, IFINDEX); g_assert_cmpint (routes->len, ==, rts_n); nmtst_platform_ip6_routes_equal_aptr ((const NMPObject *const*) routes->pdata, rts_cmp, routes->len, TRUE); - g_ptr_array_unref (routes); for (i = 0; i < rts_n; i++) { g_assert (nmtstp_platform_ip6_route_delete (NM_PLATFORM_GET, IFINDEX, @@ -631,6 +710,7 @@ test_ip6_route_options (gconstpointer test_data) rts_add[i].network, rts_add[i].plen); } +#undef RTS_MAX } /*****************************************************************************/ @@ -714,7 +794,7 @@ again_find_idx: order_len--; r->ifindex = iface_data[idx].ifindex; - g_assert (nm_platform_ip_route_delete (platform, &o)); + g_assert (nm_platform_object_delete (platform, &o)); } head_entry = nm_platform_lookup (platform, @@ -771,7 +851,9 @@ _nmtstp_setup_tests (void) add_test_func ("/route/ip4", test_ip4_route); add_test_func ("/route/ip6", test_ip6_route); add_test_func ("/route/ip4_metric0", test_ip4_route_metric0); - add_test_func ("/route/ip4_options", test_ip4_route_options); + add_test_func_data ("/route/ip4_options/1", test_ip4_route_options, GINT_TO_POINTER (1)); + if (nmtstp_is_root_test ()) + add_test_func_data ("/route/ip4_options/2", test_ip4_route_options, GINT_TO_POINTER (2)); add_test_func_data ("/route/ip6_options/1", test_ip6_route_options, GINT_TO_POINTER (1)); add_test_func_data ("/route/ip6_options/2", test_ip6_route_options, GINT_TO_POINTER (2)); add_test_func_data ("/route/ip6_options/3", test_ip6_route_options, GINT_TO_POINTER (3)); diff --git a/src/ppp/nm-ppp-manager.c b/src/ppp/nm-ppp-manager.c index 3ef3f3dc..7dd6a9b9 100644 --- a/src/ppp/nm-ppp-manager.c +++ b/src/ppp/nm-ppp-manager.c @@ -96,7 +96,7 @@ typedef struct { NMActRequest *act_req; GDBusMethodInvocation *pending_secrets_context; - NMActRequestGetSecretsCallId secrets_id; + NMActRequestGetSecretsCallId *secrets_id; const char *secrets_setting_name; guint ppp_watch_id; @@ -287,7 +287,7 @@ extract_details_from_connection (NMConnection *connection, static void ppp_secrets_cb (NMActRequest *req, - NMActRequestGetSecretsCallId call_id, + NMActRequestGetSecretsCallId *call_id, NMSettingsConnection *settings_connection, /* unused (we pass NULL here) */ GError *error, gpointer user_data) diff --git a/src/settings/nm-agent-manager.c b/src/settings/nm-agent-manager.c index bcd17843..a68db47e 100644 --- a/src/settings/nm-agent-manager.c +++ b/src/settings/nm-agent-manager.c @@ -62,6 +62,8 @@ typedef struct { GHashTable *agents; CList requests; + + guint64 agent_version_id; } NMAgentManagerPrivate; struct _NMAgentManager { @@ -137,6 +139,16 @@ static gboolean _con_get_try_complete_early (Request *req); /*****************************************************************************/ +guint64 +nm_agent_manager_get_agent_version_id (NMAgentManager *self) +{ + g_return_val_if_fail (NM_IS_AGENT_MANAGER (self), 0); + + return NM_AGENT_MANAGER_GET_PRIVATE (self)->agent_version_id; +} + +/*****************************************************************************/ + typedef enum { REQUEST_TYPE_INVALID, REQUEST_TYPE_CON_GET, @@ -170,7 +182,7 @@ struct _NMAgentManagerCallId { /* Current agent being asked for secrets */ NMSecretAgent *current; - NMSecretAgentCallId current_call_id; + NMSecretAgentCallId *current_call_id; /* Stores the sorted list of NMSecretAgents which will be asked for secrets */ GSList *pending; @@ -336,6 +348,7 @@ agent_register_permissions_done (NMAuthChain *chain, if (result == NM_AUTH_CALL_RESULT_YES) nm_secret_agent_add_permission (agent, NM_AUTH_PERMISSION_WIFI_SHARE_OPEN, TRUE); + priv->agent_version_id += 1; sender = nm_secret_agent_get_dbus_owner (agent); g_hash_table_insert (priv->agents, g_strdup (sender), agent); _LOGD (agent, "agent registered"); @@ -609,7 +622,7 @@ req_complete (Request *req, nm_assert (c_list_contains (&NM_AGENT_MANAGER_GET_PRIVATE (self)->requests, &req->lst_request)); - c_list_unlink_init (&req->lst_request); + c_list_unlink (&req->lst_request); req_complete_release (req, secrets, agent_dbus_owner, agent_username, error); } @@ -832,7 +845,7 @@ out: static void _con_get_request_done (NMSecretAgent *agent, - NMSecretAgentCallId call_id, + NMSecretAgentCallId *call_id, GVariant *secrets, GError *error, gpointer user_data) @@ -1213,7 +1226,7 @@ nm_agent_manager_get_secrets (NMAgentManager *self, GVariant *existing_secrets, const char *setting_name, NMSecretAgentGetSecretsFlags flags, - const char **hints, + const char *const*hints, NMAgentSecretsResultFunc callback, gpointer callback_data) { @@ -1267,7 +1280,7 @@ nm_agent_manager_cancel_secrets (NMAgentManager *self, nm_assert (c_list_contains (&NM_AGENT_MANAGER_GET_PRIVATE (self)->requests, &request_id->lst_request)); - c_list_unlink_init (&request_id->lst_request); + c_list_unlink (&request_id->lst_request); req_complete_cancel (request_id, FALSE); } @@ -1276,7 +1289,7 @@ nm_agent_manager_cancel_secrets (NMAgentManager *self, static void _con_save_request_done (NMSecretAgent *agent, - NMSecretAgentCallId call_id, + NMSecretAgentCallId *call_id, GVariant *secrets, GError *error, gpointer user_data) @@ -1362,7 +1375,7 @@ nm_agent_manager_save_secrets (NMAgentManager *self, static void _con_del_request_done (NMSecretAgent *agent, - NMSecretAgentCallId call_id, + NMSecretAgentCallId *call_id, GVariant *secrets, GError *error, gpointer user_data) @@ -1558,6 +1571,7 @@ nm_agent_manager_init (NMAgentManager *self) { NMAgentManagerPrivate *priv = NM_AGENT_MANAGER_GET_PRIVATE (self); + priv->agent_version_id = 1; c_list_init (&priv->requests); priv->agents = g_hash_table_new_full (nm_str_hash, g_str_equal, g_free, g_object_unref); } @@ -1588,7 +1602,7 @@ dispose (GObject *object) cancel_more: c_list_for_each (iter, &priv->requests) { - c_list_unlink_init (iter); + c_list_unlink (iter); req_complete_cancel (c_list_entry (iter, Request, lst_request), TRUE); goto cancel_more; } @@ -1627,7 +1641,7 @@ nm_agent_manager_class_init (NMAgentManagerClass *agent_manager_class) object_class->dispose = dispose; signals[AGENT_REGISTERED] = - g_signal_new ("agent-registered", + g_signal_new (NM_AGENT_MANAGER_AGENT_REGISTERED, G_OBJECT_CLASS_TYPE (object_class), G_SIGNAL_RUN_FIRST, 0, diff --git a/src/settings/nm-agent-manager.h b/src/settings/nm-agent-manager.h index 7f812693..f6845818 100644 --- a/src/settings/nm-agent-manager.h +++ b/src/settings/nm-agent-manager.h @@ -33,6 +33,8 @@ #define NM_IS_AGENT_MANAGER_CLASS(klass) (G_TYPE_CHECK_CLASS_TYPE ((klass), NM_TYPE_AGENT_MANAGER)) #define NM_AGENT_MANAGER_GET_CLASS(obj) (G_TYPE_INSTANCE_GET_CLASS ((obj), NM_TYPE_AGENT_MANAGER, NMAgentManagerClass)) +#define NM_AGENT_MANAGER_AGENT_REGISTERED "agent-registered" + typedef struct _NMAgentManagerCallId *NMAgentManagerCallId; typedef struct _NMAgentManagerClass NMAgentManagerClass; @@ -41,6 +43,8 @@ GType nm_agent_manager_get_type (void); NMAgentManager *nm_agent_manager_get (void); +guint64 nm_agent_manager_get_agent_version_id (NMAgentManager *self); + /* If no agent fulfilled the secrets request, agent_dbus_owner will be NULL */ typedef void (*NMAgentSecretsResultFunc) (NMAgentManager *manager, NMAgentManagerCallId call_id, @@ -60,7 +64,7 @@ NMAgentManagerCallId nm_agent_manager_get_secrets (NMAgentManager *manager, GVariant *existing_secrets, const char *setting_name, NMSecretAgentGetSecretsFlags flags, - const char **hints, + const char *const*hints, NMAgentSecretsResultFunc callback, gpointer callback_data); diff --git a/src/settings/nm-secret-agent.c b/src/settings/nm-secret-agent.c index 5fe4dd17..192e9877 100644 --- a/src/settings/nm-secret-agent.c +++ b/src/settings/nm-secret-agent.c @@ -50,16 +50,13 @@ typedef struct { char *owner_username; char *dbus_owner; NMSecretAgentCapabilities capabilities; - GSList *permissions; - NMDBusSecretAgent *proxy; NMBusManager *bus_mgr; GDBusConnection *connection; - gboolean connection_is_private; - gulong on_disconnected_id; - CList requests; + gulong on_disconnected_id; + bool connection_is_private:1; } NMSecretAgentPrivate; struct _NMSecretAgent { @@ -99,6 +96,13 @@ G_DEFINE_TYPE (NMSecretAgent, nm_secret_agent, G_TYPE_OBJECT) /*****************************************************************************/ +NM_UTILS_FLAGS2STR_DEFINE_STATIC (_capabilities_to_string, NMSecretAgentCapabilities, + NM_UTILS_FLAGS2STR (NM_SECRET_AGENT_CAPABILITY_NONE, "none"), + NM_UTILS_FLAGS2STR (NM_SECRET_AGENT_CAPABILITY_VPN_HINTS, "vpn-hints"), +); + +/*****************************************************************************/ + struct _NMSecretAgentCallId { CList lst; NMSecretAgent *agent; @@ -111,9 +115,7 @@ struct _NMSecretAgentCallId { gpointer callback_data; }; -typedef struct _NMSecretAgentCallId Request; - -static Request * +static NMSecretAgentCallId * request_new (NMSecretAgent *self, const char *dbus_command, /* this must be a static string. */ const char *path, @@ -121,9 +123,9 @@ request_new (NMSecretAgent *self, NMSecretAgentCallback callback, gpointer callback_data) { - Request *r; + NMSecretAgentCallId *r; - r = g_slice_new0 (Request); + r = g_slice_new0 (NMSecretAgentCallId); r->agent = self; r->path = g_strdup (path); r->setting_name = g_strdup (setting_name); @@ -139,21 +141,21 @@ request_new (NMSecretAgent *self, #define request_new(self,dbus_command,path,setting_name,callback,callback_data) request_new(self,""dbus_command"",path,setting_name,callback,callback_data) static void -request_free (Request *r) +request_free (NMSecretAgentCallId *r) { NMSecretAgent *self = r->agent; _LOGt ("request "LOG_REQ_FMT": destroyed", LOG_REQ_ARG (r)); - c_list_unlink (&r->lst); + c_list_unlink_stale (&r->lst); g_free (r->path); g_free (r->setting_name); if (r->cancellable) g_object_unref (r->cancellable); - g_slice_free (Request, r); + g_slice_free (NMSecretAgentCallId, r); } static gboolean -request_check_return (Request *r) +request_check_return (NMSecretAgentCallId *r) { if (!r->cancellable) return FALSE; @@ -163,7 +165,7 @@ request_check_return (Request *r) nm_assert (c_list_contains (&NM_SECRET_AGENT_GET_PRIVATE (r->agent)->requests, &r->lst)); - c_list_unlink_init (&r->lst); + c_list_unlink (&r->lst); return TRUE; } @@ -329,7 +331,7 @@ get_callback (GObject *proxy, GAsyncResult *result, gpointer user_data) { - Request *r = user_data; + NMSecretAgentCallId *r = user_data; if (request_check_return (r)) { NMSecretAgentPrivate *priv = NM_SECRET_AGENT_GET_PRIVATE (r->agent); @@ -345,7 +347,7 @@ get_callback (GObject *proxy, request_free (r); } -NMSecretAgentCallId +NMSecretAgentCallId * nm_secret_agent_get_secrets (NMSecretAgent *self, const char *path, NMConnection *connection, @@ -358,7 +360,7 @@ nm_secret_agent_get_secrets (NMSecretAgent *self, NMSecretAgentPrivate *priv; static const char *no_hints[] = { NULL }; GVariant *dict; - Request *r; + NMSecretAgentCallId *r; g_return_val_if_fail (NM_IS_SECRET_AGENT (self), NULL); g_return_val_if_fail (NM_IS_CONNECTION (connection), NULL); @@ -411,7 +413,7 @@ cancel_done (GObject *proxy, GAsyncResult *result, gpointer user_data) } static void -do_cancel_secrets (NMSecretAgent *self, Request *r, gboolean disposing) +do_cancel_secrets (NMSecretAgent *self, NMSecretAgentCallId *r, gboolean disposing) { NMSecretAgentPrivate *priv = NM_SECRET_AGENT_GET_PRIVATE (self); GCancellable *cancellable; @@ -467,9 +469,9 @@ do_cancel_secrets (NMSecretAgent *self, Request *r, gboolean disposing) * callback before nm_secret_agent_cancel_secrets() returns. */ void -nm_secret_agent_cancel_secrets (NMSecretAgent *self, NMSecretAgentCallId call_id) +nm_secret_agent_cancel_secrets (NMSecretAgent *self, NMSecretAgentCallId *call_id) { - Request *r = call_id; + NMSecretAgentCallId *r = call_id; g_return_if_fail (NM_IS_SECRET_AGENT (self)); g_return_if_fail (r); @@ -477,7 +479,7 @@ nm_secret_agent_cancel_secrets (NMSecretAgent *self, NMSecretAgentCallId call_id nm_assert (c_list_contains (&NM_SECRET_AGENT_GET_PRIVATE (self)->requests, &r->lst)); - c_list_unlink_init (&r->lst); + c_list_unlink (&r->lst); do_cancel_secrets (self, r, FALSE); } @@ -489,7 +491,7 @@ agent_save_cb (GObject *proxy, GAsyncResult *result, gpointer user_data) { - Request *r = user_data; + NMSecretAgentCallId *r = user_data; if (request_check_return (r)) { NMSecretAgentPrivate *priv = NM_SECRET_AGENT_GET_PRIVATE (r->agent); @@ -504,7 +506,7 @@ agent_save_cb (GObject *proxy, request_free (r); } -NMSecretAgentCallId +NMSecretAgentCallId * nm_secret_agent_save_secrets (NMSecretAgent *self, const char *path, NMConnection *connection, @@ -513,7 +515,7 @@ nm_secret_agent_save_secrets (NMSecretAgent *self, { NMSecretAgentPrivate *priv; GVariant *dict; - Request *r; + NMSecretAgentCallId *r; g_return_val_if_fail (NM_IS_SECRET_AGENT (self), NULL); g_return_val_if_fail (NM_IS_CONNECTION (connection), NULL); @@ -541,7 +543,7 @@ agent_delete_cb (GObject *proxy, GAsyncResult *result, gpointer user_data) { - Request *r = user_data; + NMSecretAgentCallId *r = user_data; if (request_check_return (r)) { NMSecretAgentPrivate *priv = NM_SECRET_AGENT_GET_PRIVATE (r->agent); @@ -556,7 +558,7 @@ agent_delete_cb (GObject *proxy, request_free (r); } -NMSecretAgentCallId +NMSecretAgentCallId * nm_secret_agent_delete_secrets (NMSecretAgent *self, const char *path, NMConnection *connection, @@ -565,7 +567,7 @@ nm_secret_agent_delete_secrets (NMSecretAgent *self, { NMSecretAgentPrivate *priv; GVariant *dict; - Request *r; + NMSecretAgentCallId *r; g_return_val_if_fail (NM_IS_SECRET_AGENT (self), NULL); g_return_val_if_fail (NM_IS_CONNECTION (connection), NULL); @@ -668,6 +670,7 @@ nm_secret_agent_new (GDBusMethodInvocation *context, char *owner_username = NULL; char *description = NULL; char buf_subject[64]; + char buf_caps[150]; gulong uid; GDBusConnection *connection; @@ -696,12 +699,13 @@ nm_secret_agent_new (GDBusMethodInvocation *context, priv->connection = g_object_ref (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", + _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)), NM_PRINT_FMT_QUOTE_STRING (owner_username), nm_auth_subject_to_string (subject, buf_subject, sizeof (buf_subject)), priv->connection_is_private, - NM_PRINT_FMT_QUOTE_STRING (g_dbus_connection_get_unique_name (priv->connection))); + NM_PRINT_FMT_QUOTE_STRING (g_dbus_connection_get_unique_name (priv->connection)), + _capabilities_to_string (capabilities, buf_caps, sizeof (buf_caps))); priv->identifier = g_strdup (identifier); priv->owner_username = owner_username; @@ -759,8 +763,8 @@ dispose (GObject *object) again: c_list_for_each (iter, &priv->requests) { - c_list_unlink_init (iter); - do_cancel_secrets (self, c_list_entry (iter, Request, lst), TRUE); + c_list_unlink (iter); + do_cancel_secrets (self, c_list_entry (iter, NMSecretAgentCallId, lst), TRUE); goto again; } diff --git a/src/settings/nm-secret-agent.h b/src/settings/nm-secret-agent.h index 54c5b398..64b103aa 100644 --- a/src/settings/nm-secret-agent.h +++ b/src/settings/nm-secret-agent.h @@ -33,8 +33,7 @@ #define NM_SECRET_AGENT_DISCONNECTED "disconnected" typedef struct _NMSecretAgentClass NMSecretAgentClass; - -typedef struct _NMSecretAgentCallId *NMSecretAgentCallId; +typedef struct _NMSecretAgentCallId NMSecretAgentCallId; GType nm_secret_agent_get_type (void); @@ -67,12 +66,12 @@ gboolean nm_secret_agent_has_permission (NMSecretAgent *agent, const char *permission); typedef void (*NMSecretAgentCallback) (NMSecretAgent *agent, - NMSecretAgentCallId call_id, + NMSecretAgentCallId *call_id, GVariant *new_secrets, /* NULL for save & delete */ GError *error, gpointer user_data); -NMSecretAgentCallId nm_secret_agent_get_secrets (NMSecretAgent *agent, +NMSecretAgentCallId *nm_secret_agent_get_secrets (NMSecretAgent *agent, const char *path, NMConnection *connection, const char *setting_name, @@ -82,18 +81,18 @@ NMSecretAgentCallId nm_secret_agent_get_secrets (NMSecretAgent *agent, gpointer callback_data); void nm_secret_agent_cancel_secrets (NMSecretAgent *agent, - NMSecretAgentCallId call_id); - -NMSecretAgentCallId nm_secret_agent_save_secrets (NMSecretAgent *agent, - const char *path, - NMConnection *connection, - NMSecretAgentCallback callback, - gpointer callback_data); - -NMSecretAgentCallId nm_secret_agent_delete_secrets (NMSecretAgent *agent, - const char *path, - NMConnection *connection, - NMSecretAgentCallback callback, - gpointer callback_data); + NMSecretAgentCallId *call_id); + +NMSecretAgentCallId *nm_secret_agent_save_secrets (NMSecretAgent *agent, + const char *path, + NMConnection *connection, + NMSecretAgentCallback callback, + gpointer callback_data); + +NMSecretAgentCallId *nm_secret_agent_delete_secrets (NMSecretAgent *agent, + const char *path, + NMConnection *connection, + NMSecretAgentCallback callback, + gpointer callback_data); #endif /* __NETWORKMANAGER_SECRET_AGENT_H__ */ diff --git a/src/settings/nm-settings-connection.c b/src/settings/nm-settings-connection.c index ed69115c..b6e89404 100644 --- a/src/settings/nm-settings-connection.c +++ b/src/settings/nm-settings-connection.c @@ -25,6 +25,8 @@ #include <string.h> +#include "nm-utils/c-list.h" + #include "nm-common-macros.h" #include "nm-config.h" #include "nm-config-data.h" @@ -42,9 +44,8 @@ #define SETTINGS_TIMESTAMPS_FILE NMSTATEDIR "/timestamps" #define SETTINGS_SEEN_BSSIDS_FILE NMSTATEDIR "/seen-bssids" -#define AUTOCONNECT_RETRIES_UNSET -2 -#define AUTOCONNECT_RETRIES_FOREVER -1 -#define AUTOCONNECT_RETRIES_DEFAULT 4 +#define AUTOCONNECT_RETRIES_UNSET -2 +#define AUTOCONNECT_RETRIES_FOREVER -1 #define AUTOCONNECT_RESET_RETRIES_TIMER 300 /*****************************************************************************/ @@ -52,7 +53,6 @@ static void nm_settings_connection_connection_interface_init (NMConnectionInterface *iface); NM_GOBJECT_PROPERTIES_DEFINE (NMSettingsConnection, - PROP_VISIBLE, PROP_UNSAVED, PROP_READY, PROP_FLAGS, @@ -74,21 +74,18 @@ typedef struct _NMSettingsConnectionPrivate { NMSessionMonitor *session_monitor; gulong session_changed_id; - NMSettingsConnectionFlags flags; + NMSettingsConnectionFlags flags:5; bool removed:1; bool ready:1; - /* Is this connection visible by some session? */ - bool visible:1; - bool timestamp_set:1; - NMSettingsAutoconnectBlockedReason autoconnect_blocked_reason:3; + NMSettingsAutoconnectBlockedReason autoconnect_blocked_reason:4; GSList *pending_auths; /* List of pending authentication requests */ - GSList *get_secret_requests; /* in-progress secrets requests */ + CList call_ids_lst_head; /* in-progress secrets requests */ /* Caches secrets from on-disk connections; were they not cached any * call to nm_connection_clear_secrets() wipes them out and we'd have @@ -105,13 +102,17 @@ typedef struct _NMSettingsConnectionPrivate { */ NMConnection *agent_secrets; - guint64 timestamp; /* Up-to-date timestamp of connection use */ + char *filename; + GHashTable *seen_bssids; /* Up-to-date BSSIDs that's been seen for the connection */ + guint64 timestamp; /* Up-to-date timestamp of connection use */ + + guint64 last_secret_agent_version_id; + int autoconnect_retries; - gint32 autoconnect_blocked_until; + gint32 autoconnect_retries_blocked_until; - char *filename; } NMSettingsConnectionPrivate; G_DEFINE_TYPE_WITH_CODE (NMSettingsConnection, nm_settings_connection, NM_TYPE_EXPORTED_OBJECT, @@ -170,6 +171,16 @@ nm_settings_connection_has_unmodified_applied_connection (NMSettingsConnection * /*****************************************************************************/ +guint64 +nm_settings_connection_get_last_secret_agent_version_id (NMSettingsConnection *self) +{ + g_return_val_if_fail (NM_IS_SETTINGS_CONNECTION (self), 0); + + return NM_SETTINGS_CONNECTION_GET_PRIVATE (self)->last_secret_agent_version_id; +} + +/*****************************************************************************/ + /* Return TRUE to keep, FALSE to drop */ typedef gboolean (*ForEachSecretFunc) (NMSettingSecretFlags flags, gpointer user_data); @@ -308,20 +319,9 @@ find_secret (NMConnection *self, static void set_visible (NMSettingsConnection *self, gboolean new_visible) { - NMSettingsConnectionPrivate *priv = NM_SETTINGS_CONNECTION_GET_PRIVATE (self); - - if (new_visible == priv->visible) - return; - priv->visible = new_visible; - _notify (self, PROP_VISIBLE); -} - -gboolean -nm_settings_connection_is_visible (NMSettingsConnection *self) -{ - g_return_val_if_fail (NM_IS_SETTINGS_CONNECTION (self), FALSE); - - return NM_SETTINGS_CONNECTION_GET_PRIVATE (self)->visible; + nm_settings_connection_set_flags (self, + NM_SETTINGS_CONNECTION_FLAGS_VISIBLE, + new_visible); } void @@ -389,7 +389,8 @@ nm_settings_connection_check_permission (NMSettingsConnection *self, priv = NM_SETTINGS_CONNECTION_GET_PRIVATE (self); - if (priv->visible == FALSE) + if (!NM_FLAGS_HAS (nm_settings_connection_get_flags (self), + NM_SETTINGS_CONNECTION_FLAGS_VISIBLE)) return FALSE; s_con = nm_connection_get_setting_connection (NM_CONNECTION (self)); @@ -487,33 +488,87 @@ secrets_cleared_cb (NMSettingsConnection *self) } static void -set_unsaved (NMSettingsConnection *self, gboolean now_unsaved) +set_persist_mode (NMSettingsConnection *self, NMSettingsConnectionPersistMode persist_mode) { - NMSettingsConnectionFlags flags = nm_settings_connection_get_flags (self); + 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; - if (NM_FLAGS_HAS (flags, NM_SETTINGS_CONNECTION_FLAGS_UNSAVED) != !!now_unsaved) { - if (now_unsaved) - flags |= NM_SETTINGS_CONNECTION_FLAGS_UNSAVED; - else { - flags &= ~(NM_SETTINGS_CONNECTION_FLAGS_UNSAVED | - NM_SETTINGS_CONNECTION_FLAGS_NM_GENERATED | - NM_SETTINGS_CONNECTION_FLAGS_VOLATILE); - } - nm_settings_connection_set_flags_all (self, flags); + switch (persist_mode) { + case NM_SETTINGS_CONNECTION_PERSIST_MODE_DISK: + 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_FLAGS_UNSAVED; + break; + case NM_SETTINGS_CONNECTION_PERSIST_MODE_VOLATILE_DETACHED: + case NM_SETTINGS_CONNECTION_PERSIST_MODE_VOLATILE_ONLY: + 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_FLAGS_UNSAVED, + TRUE); + return; + case NM_SETTINGS_CONNECTION_PERSIST_MODE_KEEP: + /* Nothing to do */ + return; } + + nm_settings_connection_set_flags_full (self, ALL, flags); } static void connection_changed_cb (NMSettingsConnection *self, gpointer unused) { - set_unsaved (self, TRUE); + set_persist_mode (self, NM_SETTINGS_CONNECTION_PERSIST_MODE_UNSAVED); _emit_updated (self, FALSE); } -gboolean -nm_settings_connection_replace_settings_prepare (NMSettingsConnection *self, - NMConnection *new_connection, - GError **error) +static gboolean +_delete (NMSettingsConnection *self, GError **error) +{ + NMSettingsConnectionClass *klass; + GError *local = NULL; + const char *filename; + + nm_assert (NM_IS_SETTINGS_CONNECTION (self)); + + klass = NM_SETTINGS_CONNECTION_GET_CLASS (self); + if (!klass->delete) { + g_set_error (&local, + NM_SETTINGS_ERROR, + NM_SETTINGS_ERROR_FAILED, + "delete not supported"); + goto fail; + } + if (!klass->delete (self, + &local)) + goto fail; + + filename = nm_settings_connection_get_filename (self); + if (filename) { + _LOGD ("delete: success deleting connection (\"%s\")", filename); + nm_settings_connection_set_filename (self, NULL); + } else + _LOGT ("delete: success deleting connection (no-file)"); + return TRUE; +fail: + _LOGD ("delete: failure deleting connection: %s", local->message); + g_propagate_error (error, local); + return FALSE; +} + +static gboolean +_update_prepare (NMSettingsConnection *self, + NMConnection *new_connection, + GError **error) { NMSettingsConnectionPrivate *priv; @@ -538,173 +593,136 @@ nm_settings_connection_replace_settings_prepare (NMSettingsConnection *self, } gboolean -nm_settings_connection_replace_settings_full (NMSettingsConnection *self, - NMConnection *new_connection, - gboolean prepare_new_connection, - gboolean update_unsaved, - const char *log_diff_name, - GError **error) +nm_settings_connection_update (NMSettingsConnection *self, + NMConnection *new_connection, + NMSettingsConnectionPersistMode persist_mode, + NMSettingsConnectionCommitReason commit_reason, + const char *log_diff_name, + GError **error) { NMSettingsConnectionPrivate *priv; + NMSettingsConnectionClass *klass = NULL; + gs_unref_object NMConnection *reread_connection = NULL; + NMConnection *replace_connection; + gboolean replaced = FALSE; + gs_free char *logmsg_change = NULL; + GError *local = NULL; 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 ( prepare_new_connection - && !nm_settings_connection_replace_settings_prepare (self, - new_connection, - error)) - return FALSE; + if (persist_mode == NM_SETTINGS_CONNECTION_PERSIST_MODE_DISK) { + klass = NM_SETTINGS_CONNECTION_GET_CLASS (self); + if (!klass->commit_changes) { + g_set_error (&local, + NM_SETTINGS_ERROR, + NM_SETTINGS_ERROR_FAILED, + "writing settings not supported"); + goto out; + } + } - /* Do nothing if there's nothing to update */ - if (nm_connection_compare (NM_CONNECTION (self), - new_connection, - NM_SETTING_COMPARE_FLAG_EXACT)) { - return TRUE; + if ( new_connection + && !_update_prepare (self, + new_connection, + &local)) + goto out; + + if (persist_mode == NM_SETTINGS_CONNECTION_PERSIST_MODE_DISK) { + if (!klass->commit_changes (self, + new_connection ?: NM_CONNECTION (self), + commit_reason, + &reread_connection, + &logmsg_change, + &local)) + goto out; + + if ( reread_connection + && !_update_prepare (self, + reread_connection, + &local)) + goto out; } + replace_connection = reread_connection ?: new_connection; + /* Disconnect the changed signal to ensure we don't set Unsaved when * it's not required. */ g_signal_handlers_block_by_func (self, G_CALLBACK (connection_changed_cb), NULL); - if (log_diff_name) - nm_utils_log_connection_diff (new_connection, NM_CONNECTION (self), LOGL_DEBUG, LOGD_CORE, log_diff_name, "++ "); + /* Do nothing if there's nothing to update */ + if ( replace_connection + && !nm_connection_compare (NM_CONNECTION (self), + replace_connection, + NM_SETTING_COMPARE_FLAG_EXACT)) { + if (log_diff_name) + nm_utils_log_connection_diff (replace_connection, NM_CONNECTION (self), LOGL_DEBUG, LOGD_CORE, log_diff_name, "++ "); - nm_connection_replace_settings_from_connection (NM_CONNECTION (self), new_connection); + nm_connection_replace_settings_from_connection (NM_CONNECTION (self), replace_connection); - _LOGD ("replace settings from connection %p (%s)", new_connection, nm_connection_get_id (NM_CONNECTION (self))); + replaced = TRUE; + } nm_settings_connection_set_flags (self, NM_SETTINGS_CONNECTION_FLAGS_NM_GENERATED | NM_SETTINGS_CONNECTION_FLAGS_VOLATILE, FALSE); - /* Cache the just-updated system secrets in case something calls - * nm_connection_clear_secrets() and clears them. - */ - update_system_secrets_cache (self); + if (replaced) { + /* Cache the just-updated system secrets in case something calls + * nm_connection_clear_secrets() and clears them. + */ + update_system_secrets_cache (self); - /* Add agent and always-ask secrets back; they won't necessarily be - * in the replacement connection data if it was eg reread from disk. - */ - if (priv->agent_secrets) { - GVariant *dict; + /* Add agent and always-ask secrets back; they won't necessarily be + * in the replacement connection data if it was eg reread from disk. + */ + if (priv->agent_secrets) { + GVariant *dict; - dict = nm_connection_to_dbus (priv->agent_secrets, NM_CONNECTION_SERIALIZE_ONLY_SECRETS); - if (dict) { - (void) nm_connection_update_secrets (NM_CONNECTION (self), NULL, dict, NULL); - g_variant_unref (dict); + dict = nm_connection_to_dbus (priv->agent_secrets, NM_CONNECTION_SERIALIZE_ONLY_SECRETS); + if (dict) { + (void) nm_connection_update_secrets (NM_CONNECTION (self), NULL, dict, NULL); + g_variant_unref (dict); + } } } nm_settings_connection_recheck_visibility (self); - /* Manually emit changed signal since we disconnected the handler, but - * only update Unsaved if the caller wanted us to. - */ - if (update_unsaved) - set_unsaved (self, TRUE); + if ( replaced + && persist_mode == NM_SETTINGS_CONNECTION_PERSIST_MODE_KEEP) + set_persist_mode (self, NM_SETTINGS_CONNECTION_PERSIST_MODE_UNSAVED); + else + set_persist_mode (self, persist_mode); + + if (NM_IN_SET (persist_mode, NM_SETTINGS_CONNECTION_PERSIST_MODE_IN_MEMORY_ONLY, + NM_SETTINGS_CONNECTION_PERSIST_MODE_VOLATILE_ONLY)) + _delete (self, NULL); + else if (NM_IN_SET (persist_mode, NM_SETTINGS_CONNECTION_PERSIST_MODE_IN_MEMORY_DETACHED, + NM_SETTINGS_CONNECTION_PERSIST_MODE_VOLATILE_DETACHED)) + nm_settings_connection_set_filename (self, NULL); g_signal_handlers_unblock_by_func (self, G_CALLBACK (connection_changed_cb), NULL); _emit_updated (self, TRUE); - return TRUE; -} - -/* Update the settings of this connection to match that of 'new_connection', - * taking care to make a private copy of secrets. - */ -gboolean -nm_settings_connection_replace_settings (NMSettingsConnection *self, - NMConnection *new_connection, - gboolean update_unsaved, - const char *log_diff_name, - GError **error) -{ - return nm_settings_connection_replace_settings_full (self, - new_connection, - TRUE, - update_unsaved, - log_diff_name, - error); -} - -gboolean -nm_settings_connection_commit_changes (NMSettingsConnection *self, - NMConnection *new_connection, - NMSettingsConnectionCommitReason commit_reason, - GError **error) -{ - NMSettingsConnectionClass *klass; - gs_free_error GError *local = NULL; - gs_unref_object NMConnection *reread_connection = NULL; - gs_free char *logmsg_change = NULL; - - g_return_val_if_fail (NM_IS_SETTINGS_CONNECTION (self), FALSE); - - klass = NM_SETTINGS_CONNECTION_GET_CLASS (self); - if (!klass->commit_changes) { - _LOGW ("write: setting plugin %s does not support to write connection", - G_OBJECT_TYPE_NAME (self)); - g_set_error (error, - NM_SETTINGS_ERROR, - NM_SETTINGS_ERROR_FAILED, - "writing settings not supported"); - return FALSE; - } - - if ( new_connection - && !nm_settings_connection_replace_settings_prepare (self, - new_connection, - &local)) { - _LOGW ("write: failed to prepare connection for writing: %s", - local->message); - g_propagate_error (error, g_steal_pointer (&local)); - return FALSE; - } - - if (!klass->commit_changes (self, - new_connection, - commit_reason, - &reread_connection, - &logmsg_change, - &local)) { - _LOGW ("write: failure to write setting: %s", - local->message); - g_propagate_error (error, g_steal_pointer (&local)); +out: + if (local) { + _LOGI ("write: failure to update connection: %s", local->message); + g_propagate_error (error, local); return FALSE; } - if (reread_connection || new_connection) { - if (!nm_settings_connection_replace_settings_full (self, - reread_connection ?: new_connection, - !reread_connection, - FALSE, - new_connection - ? "update-during-write" - : "replace-and-commit-disk", - &local)) { - /* this can't really happen, because at this point replace-settings - * is no longer supposed to fail. It's a bug. */ - _LOGE ("write: replacing setting failed: %s", - local->message); - g_propagate_error (error, g_steal_pointer (&local)); - g_return_val_if_reached (FALSE); - } + if (persist_mode == NM_SETTINGS_CONNECTION_PERSIST_MODE_DISK) { + if (reread_connection) + _LOGI ("write: successfully updated (%s), connection was modified in the process", logmsg_change); + else if (new_connection) + _LOGI ("write: successfully updated (%s)", logmsg_change); + else + _LOGI ("write: successfully commited (%s)", logmsg_change); } - - set_unsaved (self, FALSE); - - if (reread_connection) - _LOGI ("write: successfully updated (%s), connection was modified in the process", logmsg_change); - else if (new_connection) - _LOGI ("write: successfully updated (%s)", logmsg_change); - else - _LOGI ("write: successfully commited (%s)", logmsg_change); - return TRUE; } @@ -749,25 +767,14 @@ nm_settings_connection_delete (NMSettingsConnection *self, GError **error) { gs_unref_object NMSettingsConnection *self_keep_alive = NULL; - NMSettingsConnectionClass *klass; NMSettingsConnectionPrivate *priv = NM_SETTINGS_CONNECTION_GET_PRIVATE (self); NMConnection *for_agents; g_return_val_if_fail (NM_IS_SETTINGS_CONNECTION (self), FALSE); - klass = NM_SETTINGS_CONNECTION_GET_CLASS (self); - self_keep_alive = g_object_ref (self); - if (!klass->delete) { - g_set_error (error, - NM_SETTINGS_ERROR, - NM_SETTINGS_ERROR_FAILED, - "delete not supported"); - return FALSE; - } - if (!klass->delete (self, - error)) + if (!_delete (self, error)) return FALSE; set_visible (self, FALSE); @@ -795,18 +802,19 @@ nm_settings_connection_delete (NMSettingsConnection *self, typedef enum { - GET_SECRETS_INFO_TYPE_REQ, - GET_SECRETS_INFO_TYPE_IDLE, -} GetSecretsInfoType; + CALL_ID_TYPE_REQ, + CALL_ID_TYPE_IDLE, +} CallIdType; struct _NMSettingsConnectionCallId { NMSettingsConnection *self; + CList call_ids_lst; gboolean had_applied_connection; NMConnection *applied_connection; NMSettingsConnectionSecretsFunc callback; gpointer callback_data; - GetSecretsInfoType type; + CallIdType type; union { struct { NMAgentManagerCallId id; @@ -818,59 +826,36 @@ struct _NMSettingsConnectionCallId { } t; }; -typedef struct _NMSettingsConnectionCallId GetSecretsInfo; - -static GetSecretsInfo * -_get_secrets_info_new (NMSettingsConnection *self, - NMConnection *applied_connection, - NMSettingsConnectionSecretsFunc callback, - gpointer callback_data) -{ - GetSecretsInfo *info; - - info = g_slice_new0 (GetSecretsInfo); - - info->self = self; - if (applied_connection) { - info->had_applied_connection = TRUE; - info->applied_connection = applied_connection; - g_object_add_weak_pointer (G_OBJECT (applied_connection), (gpointer *) &info->applied_connection); - } - info->callback = callback; - info->callback_data = callback_data; - - return info; -} - static void -_get_secrets_info_callback (GetSecretsInfo *info, +_get_secrets_info_callback (NMSettingsConnectionCallId *call_id, const char *agent_username, const char *setting_name, GError *error) { - if (info->callback) { - info->callback (info->self, - info, - agent_username, - setting_name, - error, - info->callback_data); + if (call_id->callback) { + call_id->callback (call_id->self, + call_id, + agent_username, + setting_name, + error, + call_id->callback_data); } } static void -_get_secrets_info_free (GetSecretsInfo *info) +_get_secrets_info_free (NMSettingsConnectionCallId *call_id) { - g_return_if_fail (info && info->self); + g_return_if_fail (call_id && call_id->self); + nm_assert (!c_list_is_linked (&call_id->call_ids_lst)); - if (info->applied_connection) - g_object_remove_weak_pointer (G_OBJECT (info->applied_connection), (gpointer *) &info->applied_connection); + if (call_id->applied_connection) + g_object_remove_weak_pointer (G_OBJECT (call_id->applied_connection), (gpointer *) &call_id->applied_connection); - if (info->type == GET_SECRETS_INFO_TYPE_IDLE) - g_clear_error (&info->t.idle.error); + if (call_id->type == CALL_ID_TYPE_IDLE) + g_clear_error (&call_id->t.idle.error); - memset (info, 0, sizeof (*info)); - g_slice_free (GetSecretsInfo, info); + memset (call_id, 0, sizeof (*call_id)); + g_slice_free (NMSettingsConnectionCallId, call_id); } static gboolean @@ -907,7 +892,7 @@ secret_is_system_owned (NMSettingSecretFlags flags, static void get_cmp_flags (NMSettingsConnection *self, /* only needed for logging */ - GetSecretsInfo *info, /* only needed for logging */ + NMSettingsConnectionCallId *call_id, /* only needed for logging */ NMConnection *connection, const char *agent_dbus_owner, gboolean agent_has_modify, @@ -930,7 +915,7 @@ get_cmp_flags (NMSettingsConnection *self, /* only needed for logging */ if (is_self) { _LOGD ("(%s:%p) secrets returned from agent %s", setting_name, - info, + call_id, agent_dbus_owner); } @@ -949,7 +934,7 @@ get_cmp_flags (NMSettingsConnection *self, /* only needed for logging */ if (is_self) { _LOGD ("(%s:%p) interaction forbidden but agent %s returned system secrets", setting_name, - info, + call_id, agent_dbus_owner); } @@ -961,7 +946,7 @@ get_cmp_flags (NMSettingsConnection *self, /* only needed for logging */ if (is_self) { _LOGD ("(%s:%p) agent failed to authenticate but provided system secrets", setting_name, - info); + call_id); } cmp_flags->required |= NM_SETTING_SECRET_FLAG_AGENT_OWNED; @@ -971,7 +956,7 @@ get_cmp_flags (NMSettingsConnection *self, /* only needed for logging */ if (is_self) { _LOGD ("(%s:%p) existing secrets returned", setting_name, - info); + call_id); } } @@ -1004,10 +989,12 @@ nm_settings_connection_new_secrets (NMSettingsConnection *self, update_system_secrets_cache (self); update_agent_secrets_cache (self, NULL); - nm_settings_connection_commit_changes (self, - NULL, - NM_SETTINGS_CONNECTION_COMMIT_REASON_NONE, - NULL); + nm_settings_connection_update (self, + NULL, + NM_SETTINGS_CONNECTION_PERSIST_MODE_DISK, + NM_SETTINGS_CONNECTION_COMMIT_REASON_NONE, + "new-secrets", + NULL); return TRUE; } @@ -1023,7 +1010,7 @@ get_secrets_done_cb (NMAgentManager *manager, GError *error, gpointer user_data) { - GetSecretsInfo *info = user_data; + NMSettingsConnectionCallId *call_id = user_data; NMSettingsConnection *self; NMSettingsConnectionPrivate *priv; NMConnection *applied_connection; @@ -1035,36 +1022,36 @@ get_secrets_done_cb (NMAgentManager *manager, if (g_error_matches (error, G_IO_ERROR, G_IO_ERROR_CANCELLED)) return; - self = info->self; + self = call_id->self; g_return_if_fail (NM_IS_SETTINGS_CONNECTION (self)); priv = NM_SETTINGS_CONNECTION_GET_PRIVATE (self); - g_return_if_fail (g_slist_find (priv->get_secret_requests, info)); + nm_assert (c_list_contains (&priv->call_ids_lst_head, &call_id->call_ids_lst)); - priv->get_secret_requests = g_slist_remove (priv->get_secret_requests, info); + c_list_unlink (&call_id->call_ids_lst); if (error) { _LOGD ("(%s:%p) secrets request error: %s", - setting_name, info, error->message); + setting_name, call_id, error->message); - _get_secrets_info_callback (info, NULL, setting_name, error); + _get_secrets_info_callback (call_id, NULL, setting_name, error); goto out; } - if ( info->had_applied_connection - && !info->applied_connection) { + if ( call_id->had_applied_connection + && !call_id->applied_connection) { g_set_error_literal (&local, NM_CONNECTION_ERROR, NM_CONNECTION_ERROR_SETTING_NOT_FOUND, "Applied connection deleted since requesting secrets"); - _get_secrets_info_callback (info, NULL, setting_name, local); + _get_secrets_info_callback (call_id, NULL, setting_name, local); goto out; } - if ( info->had_applied_connection - && !nm_settings_connection_has_unmodified_applied_connection (self, info->applied_connection, NM_SETTING_COMPARE_FLAG_NONE)) { + if ( call_id->had_applied_connection + && !nm_settings_connection_has_unmodified_applied_connection (self, call_id->applied_connection, NM_SETTING_COMPARE_FLAG_NONE)) { g_set_error_literal (&local, NM_SETTINGS_ERROR, NM_SETTINGS_ERROR_FAILED, "The connection was modified since activation"); - _get_secrets_info_callback (info, NULL, setting_name, local); + _get_secrets_info_callback (call_id, NULL, setting_name, local); goto out; } @@ -1072,12 +1059,12 @@ get_secrets_done_cb (NMAgentManager *manager, g_set_error (&local, NM_CONNECTION_ERROR, NM_CONNECTION_ERROR_SETTING_NOT_FOUND, "Connection didn't have requested setting '%s'.", setting_name); - _get_secrets_info_callback (info, NULL, setting_name, local); + _get_secrets_info_callback (call_id, NULL, setting_name, local); goto out; } get_cmp_flags (self, - info, + call_id, NM_CONNECTION (self), agent_dbus_owner, agent_has_modify, @@ -1089,7 +1076,7 @@ get_secrets_done_cb (NMAgentManager *manager, _LOGD ("(%s:%p) secrets request completed", setting_name, - info); + call_id); dict = nm_connection_to_dbus (priv->system_secrets, NM_CONNECTION_SERIALIZE_ONLY_SECRETS); @@ -1119,36 +1106,38 @@ get_secrets_done_cb (NMAgentManager *manager, if (agent_had_system) { _LOGD ("(%s:%p) saving new secrets to backing storage", setting_name, - info); - - nm_settings_connection_commit_changes (self, - NULL, - NM_SETTINGS_CONNECTION_COMMIT_REASON_NONE, - NULL); + call_id); + + nm_settings_connection_update (self, + NULL, + NM_SETTINGS_CONNECTION_PERSIST_MODE_DISK, + NM_SETTINGS_CONNECTION_COMMIT_REASON_NONE, + "get-new-secrets", + NULL); } else { _LOGD ("(%s:%p) new agent secrets processed", setting_name, - info); + call_id); } } else { _LOGD ("(%s:%p) failed to update with agent secrets: %s", setting_name, - info, + call_id, local->message); } g_variant_unref (filtered_secrets); } else { _LOGD ("(%s:%p) failed to update with existing secrets: %s", setting_name, - info, + call_id, local->message); } - applied_connection = info->applied_connection; + applied_connection = call_id->applied_connection; if (applied_connection) { get_cmp_flags (self, - info, + call_id, applied_connection, agent_dbus_owner, agent_has_modify, @@ -1169,31 +1158,31 @@ get_secrets_done_cb (NMAgentManager *manager, } } - _get_secrets_info_callback (info, agent_username, setting_name, local); + _get_secrets_info_callback (call_id, agent_username, setting_name, local); g_clear_error (&local); if (dict) g_variant_unref (dict); out: - _get_secrets_info_free (info); + _get_secrets_info_free (call_id); } static gboolean -get_secrets_idle_cb (GetSecretsInfo *info) +get_secrets_idle_cb (NMSettingsConnectionCallId *call_id) { NMSettingsConnectionPrivate *priv; - g_return_val_if_fail (info && NM_IS_SETTINGS_CONNECTION (info->self), G_SOURCE_REMOVE); + g_return_val_if_fail (call_id && NM_IS_SETTINGS_CONNECTION (call_id->self), G_SOURCE_REMOVE); - priv = NM_SETTINGS_CONNECTION_GET_PRIVATE (info->self); + priv = NM_SETTINGS_CONNECTION_GET_PRIVATE (call_id->self); - g_return_val_if_fail (g_slist_find (priv->get_secret_requests, info), G_SOURCE_REMOVE); + nm_assert (c_list_contains (&priv->call_ids_lst_head, &call_id->call_ids_lst)); - priv->get_secret_requests = g_slist_remove (priv->get_secret_requests, info); + c_list_unlink (&call_id->call_ids_lst); - _get_secrets_info_callback (info, NULL, NULL, info->t.idle.error); + _get_secrets_info_callback (call_id, NULL, NULL, call_id->t.idle.error); - _get_secrets_info_free (info); + _get_secrets_info_free (call_id); return G_SOURCE_REMOVE; } @@ -1222,13 +1211,13 @@ get_secrets_idle_cb (GetSecretsInfo *info) * * Returns: a call ID which may be used to cancel the ongoing secrets request. **/ -NMSettingsConnectionCallId +NMSettingsConnectionCallId * nm_settings_connection_get_secrets (NMSettingsConnection *self, NMConnection *applied_connection, NMAuthSubject *subject, const char *setting_name, NMSecretAgentGetSecretsFlags flags, - const char **hints, + const char *const*hints, NMSettingsConnectionSecretsFunc callback, gpointer callback_data) { @@ -1236,7 +1225,7 @@ nm_settings_connection_get_secrets (NMSettingsConnection *self, GVariant *existing_secrets; NMAgentManagerCallId call_id_a; gs_free char *joined_hints = NULL; - GetSecretsInfo *info; + NMSettingsConnectionCallId *call_id; GError *local = NULL; g_return_val_if_fail (NM_IS_SETTINGS_CONNECTION (self), NULL); @@ -1244,12 +1233,16 @@ nm_settings_connection_get_secrets (NMSettingsConnection *self, || ( NM_IS_CONNECTION (applied_connection) && (((NMConnection *) self) != applied_connection)), NULL); - info = _get_secrets_info_new (self, - applied_connection, - callback, - callback_data); - - priv->get_secret_requests = g_slist_append (priv->get_secret_requests, info); + call_id = g_slice_new0 (NMSettingsConnectionCallId); + call_id->self = self; + if (applied_connection) { + call_id->had_applied_connection = TRUE; + call_id->applied_connection = applied_connection; + g_object_add_weak_pointer (G_OBJECT (applied_connection), (gpointer *) &call_id->applied_connection); + } + call_id->callback = callback; + call_id->callback_data = callback_data; + c_list_link_tail (&priv->call_ids_lst_head, &call_id->call_ids_lst); /* Use priv->secrets to work around the fact that nm_connection_clear_secrets() * will clear secrets on this object's settings. @@ -1278,6 +1271,14 @@ nm_settings_connection_get_secrets (NMSettingsConnection *self, existing_secrets = nm_connection_to_dbus (priv->system_secrets, NM_CONNECTION_SERIALIZE_ONLY_SECRETS); if (existing_secrets) g_variant_ref_sink (existing_secrets); + + /* we remember the current version-id of the secret-agents. The version-id is strictly increasing, + * as new agents register the number. We know hence, that this request was made against a certain + * set of secret-agents. + * If after making this request a new secret-agent registeres, the version-id increases. + * Then we know that the this request probably did not yet include the latest secret-agent. */ + 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_connection_get_path (NM_CONNECTION (self)), NM_CONNECTION (self), @@ -1287,7 +1288,7 @@ nm_settings_connection_get_secrets (NMSettingsConnection *self, flags, hints, get_secrets_done_cb, - info); + call_id); g_assert (call_id_a); if (existing_secrets) g_variant_unref (existing_secrets); @@ -1299,45 +1300,44 @@ nm_settings_connection_get_secrets (NMSettingsConnection *self, (hints && hints[0]) ? (joined_hints = g_strjoinv (",", (char **) hints)) : "(none)"); if (call_id_a) { - info->type = GET_SECRETS_INFO_TYPE_REQ; - info->t.req.id = call_id_a; + call_id->type = CALL_ID_TYPE_REQ; + call_id->t.req.id = call_id_a; } else { schedule_dummy: - info->type = GET_SECRETS_INFO_TYPE_IDLE; - g_propagate_error (&info->t.idle.error, local); - info->t.idle.id = g_idle_add ((GSourceFunc) get_secrets_idle_cb, info); + call_id->type = CALL_ID_TYPE_IDLE; + g_propagate_error (&call_id->t.idle.error, local); + call_id->t.idle.id = g_idle_add ((GSourceFunc) get_secrets_idle_cb, call_id); } - return info; + return call_id; } static void _get_secrets_cancel (NMSettingsConnection *self, - GetSecretsInfo *info, + NMSettingsConnectionCallId *call_id, gboolean is_disposing) { NMSettingsConnectionPrivate *priv = NM_SETTINGS_CONNECTION_GET_PRIVATE (self); gs_free_error GError *error = NULL; - if (!g_slist_find (priv->get_secret_requests, info)) - g_return_if_reached (); + nm_assert (c_list_contains (&priv->call_ids_lst_head, &call_id->call_ids_lst)); - priv->get_secret_requests = g_slist_remove (priv->get_secret_requests, info); + c_list_unlink (&call_id->call_ids_lst); - if (info->type == GET_SECRETS_INFO_TYPE_REQ) - nm_agent_manager_cancel_secrets (priv->agent_mgr, info->t.req.id); + if (call_id->type == CALL_ID_TYPE_REQ) + nm_agent_manager_cancel_secrets (priv->agent_mgr, call_id->t.req.id); else - g_source_remove (info->t.idle.id); + g_source_remove (call_id->t.idle.id); nm_utils_error_set_cancelled (&error, is_disposing, "NMSettingsConnection"); - _get_secrets_info_callback (info, NULL, NULL, error); + _get_secrets_info_callback (call_id, NULL, NULL, error); - _get_secrets_info_free (info); + _get_secrets_info_free (call_id); } void nm_settings_connection_cancel_secrets (NMSettingsConnection *self, - NMSettingsConnectionCallId call_id) + NMSettingsConnectionCallId *call_id) { _LOGD ("(%p) secrets canceled", call_id); @@ -1581,8 +1581,9 @@ typedef struct { NMAgentManager *agent_mgr; NMAuthSubject *subject; NMConnection *new_settings; - gboolean save_to_disk; + NMSettingsUpdate2Flags flags; char *audit_args; + bool is_update2:1; } UpdateInfo; static void @@ -1646,7 +1647,13 @@ update_complete (NMSettingsConnection *self, { if (error) g_dbus_method_invocation_return_gerror (info->context, error); - else + else if (info->is_update2) { + GVariantBuilder result; + + g_variant_builder_init (&result, G_VARIANT_TYPE ("a{sv}")); + g_dbus_method_invocation_return_value (info->context, + g_variant_new ("(@a{sv})", g_variant_builder_end (&result))); + } else g_dbus_method_invocation_return_value (info->context, NULL); nm_audit_log_connection_op (NM_AUDIT_OP_CONN_UPDATE, self, !error, info->audit_args, @@ -1656,8 +1663,7 @@ update_complete (NMSettingsConnection *self, g_clear_object (&info->agent_mgr); g_clear_object (&info->new_settings); g_free (info->audit_args); - memset (info, 0, sizeof (*info)); - g_free (info); + g_slice_free (UpdateInfo, info); } static void @@ -1670,6 +1676,8 @@ update_auth_cb (NMSettingsConnection *self, UpdateInfo *info = data; NMSettingsConnectionCommitReason commit_reason; gs_free_error GError *local = NULL; + NMSettingsConnectionPersistMode persist_mode; + const char *log_diff_name; if (error) { update_complete (self, info, error); @@ -1690,7 +1698,9 @@ update_auth_cb (NMSettingsConnection *self, */ update_agent_secrets_cache (self, info->new_settings); } + } + if (info->new_settings) { if (nm_audit_manager_audit_enabled (nm_audit_manager_get ())) { gs_unref_hashtable GHashTable *diff = NULL; gboolean same; @@ -1704,36 +1714,47 @@ update_auth_cb (NMSettingsConnection *self, } } - if (!info->save_to_disk) { - if (info->new_settings) { - nm_settings_connection_replace_settings (self, - info->new_settings, - TRUE, - "replace-unsaved", - &local); - } - goto out; - } - - if (info->new_settings) { - if (!nm_settings_connection_replace_settings_prepare (self, - info->new_settings, - &local)) - goto out; - } - commit_reason = NM_SETTINGS_CONNECTION_COMMIT_REASON_USER_ACTION; if ( info->new_settings && !nm_streq0 (nm_connection_get_id (NM_CONNECTION (self)), nm_connection_get_id (info->new_settings))) commit_reason |= NM_SETTINGS_CONNECTION_COMMIT_REASON_ID_CHANGED; - nm_settings_connection_commit_changes (self, - info->new_settings, - commit_reason, - &local); + if (NM_FLAGS_HAS (info->flags, NM_SETTINGS_UPDATE2_FLAG_TO_DISK)) + persist_mode = NM_SETTINGS_CONNECTION_PERSIST_MODE_DISK; + else if (NM_FLAGS_HAS (info->flags, NM_SETTINGS_UPDATE2_FLAG_IN_MEMORY)) + persist_mode = NM_SETTINGS_CONNECTION_PERSIST_MODE_IN_MEMORY; + else if (NM_FLAGS_HAS (info->flags, NM_SETTINGS_UPDATE2_FLAG_IN_MEMORY_DETACHED)) { + persist_mode = NM_FLAGS_HAS (info->flags, NM_SETTINGS_UPDATE2_FLAG_VOLATILE) + ? NM_SETTINGS_CONNECTION_PERSIST_MODE_VOLATILE_DETACHED + : NM_SETTINGS_CONNECTION_PERSIST_MODE_IN_MEMORY_DETACHED; + } else if (NM_FLAGS_HAS (info->flags, NM_SETTINGS_UPDATE2_FLAG_IN_MEMORY_ONLY)) { + persist_mode = NM_FLAGS_HAS (info->flags, NM_SETTINGS_UPDATE2_FLAG_VOLATILE) + ? NM_SETTINGS_CONNECTION_PERSIST_MODE_VOLATILE_ONLY + : NM_SETTINGS_CONNECTION_PERSIST_MODE_IN_MEMORY_ONLY; + } else + persist_mode = NM_SETTINGS_CONNECTION_PERSIST_MODE_KEEP; + + if ( persist_mode == NM_SETTINGS_CONNECTION_PERSIST_MODE_DISK + || ( persist_mode == NM_SETTINGS_CONNECTION_PERSIST_MODE_KEEP + && !nm_settings_connection_get_unsaved (self))) + log_diff_name = info->new_settings ? "update-settings" : "write-out-to-disk"; + else + log_diff_name = info->new_settings ? "update-unsaved" : "make-unsaved"; + + if (NM_FLAGS_HAS (info->flags, NM_SETTINGS_UPDATE2_FLAG_BLOCK_AUTOCONNECT)) { + nm_settings_connection_autoconnect_blocked_reason_set (self, + NM_SETTINGS_AUTO_CONNECT_BLOCKED_REASON_USER_REQUEST, + TRUE); + } + + nm_settings_connection_update (self, + info->new_settings, + persist_mode, + commit_reason, + log_diff_name, + &local); -out: if (!local) { gs_unref_object NMConnection *for_agent = NULL; @@ -1782,10 +1803,11 @@ get_update_modify_permission (NMConnection *old, NMConnection *new) } static void -settings_connection_update_helper (NMSettingsConnection *self, - GDBusMethodInvocation *context, - GVariant *new_settings, - gboolean save_to_disk) +settings_connection_update (NMSettingsConnection *self, + gboolean is_update2, + GDBusMethodInvocation *context, + GVariant *new_settings, + NMSettingsUpdate2Flags flags) { NMSettingsConnectionPrivate *priv = NM_SETTINGS_CONNECTION_GET_PRIVATE (self); NMAuthSubject *subject = NULL; @@ -1795,8 +1817,6 @@ settings_connection_update_helper (NMSettingsConnection *self, const char *permission; char *error_desc = NULL; - g_assert (new_settings != NULL || save_to_disk == TRUE); - /* 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) * instead of over D-Bus. @@ -1806,12 +1826,22 @@ settings_connection_update_helper (NMSettingsConnection *self, /* Check if the settings are valid first */ if (new_settings) { - tmp = _nm_simple_connection_new_from_dbus (new_settings, - NM_SETTING_PARSE_FLAGS_STRICT - | NM_SETTING_PARSE_FLAGS_NORMALIZE, - &error); - if (!tmp) + if (!g_variant_is_of_type (new_settings, NM_VARIANT_TYPE_CONNECTION)) { + g_set_error_literal (&error, + NM_SETTINGS_ERROR, + NM_SETTINGS_ERROR_INVALID_ARGUMENTS, + "settings is of invalid type"); goto error; + } + + if (g_variant_n_children (new_settings) > 0) { + tmp = _nm_simple_connection_new_from_dbus (new_settings, + NM_SETTING_PARSE_FLAGS_STRICT + | NM_SETTING_PARSE_FLAGS_NORMALIZE, + &error); + if (!tmp) + goto error; + } } subject = _new_auth_subject (context, &error); @@ -1832,11 +1862,12 @@ settings_connection_update_helper (NMSettingsConnection *self, goto error; } - info = g_malloc0 (sizeof (*info)); + info = g_slice_new0 (UpdateInfo); + info->is_update2 = is_update2; info->context = context; info->agent_mgr = g_object_ref (priv->agent_mgr); info->subject = subject; - info->save_to_disk = save_to_disk; + info->flags = flags; info->new_settings = tmp; permission = get_update_modify_permission (NM_CONNECTION (self), @@ -1859,7 +1890,7 @@ impl_settings_connection_update (NMSettingsConnection *self, GDBusMethodInvocation *context, GVariant *new_settings) { - settings_connection_update_helper (self, context, new_settings, TRUE); + settings_connection_update (self, FALSE, context, new_settings, NM_SETTINGS_UPDATE2_FLAG_TO_DISK); } static void @@ -1867,14 +1898,76 @@ impl_settings_connection_update_unsaved (NMSettingsConnection *self, GDBusMethodInvocation *context, GVariant *new_settings) { - settings_connection_update_helper (self, context, new_settings, FALSE); + settings_connection_update (self, FALSE, context, new_settings, NM_SETTINGS_UPDATE2_FLAG_IN_MEMORY); } static void impl_settings_connection_save (NMSettingsConnection *self, GDBusMethodInvocation *context) { - settings_connection_update_helper (self, context, NULL, TRUE); + settings_connection_update (self, FALSE, context, NULL, NM_SETTINGS_UPDATE2_FLAG_TO_DISK); +} + +static void +impl_settings_connection_update2 (NMSettingsConnection *self, + GDBusMethodInvocation *context, + GVariant *settings, + guint32 flags_u, + GVariant *args) +{ + GError *error = NULL; + GVariantIter iter; + const char *args_name; + 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; + + 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 (context, error); + return; + } + + 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) + && !NM_FLAGS_ANY (flags, NM_SETTINGS_UPDATE2_FLAG_IN_MEMORY_DETACHED | + NM_SETTINGS_UPDATE2_FLAG_IN_MEMORY_ONLY))) { + error = g_error_new_literal (NM_SETTINGS_ERROR, + NM_SETTINGS_ERROR_INVALID_ARGUMENTS, + "Conflicting flags"); + g_dbus_method_invocation_take_error (context, error); + return; + } + + if (!g_variant_is_of_type (args, G_VARIANT_TYPE ("a{sv}"))) { + error = g_error_new_literal (NM_SETTINGS_ERROR, + NM_SETTINGS_ERROR_INVALID_ARGUMENTS, + "args is of invalid type"); + g_dbus_method_invocation_take_error (context, error); + return; + } + + g_variant_iter_init (&iter, args); + while (g_variant_iter_next (&iter, "{&sv}", &args_name, NULL)) { + error = g_error_new (NM_SETTINGS_ERROR, + NM_SETTINGS_ERROR_INVALID_ARGUMENTS, + "Unsupported argument '%s'", args_name); + g_dbus_method_invocation_take_error (context, error); + return; + } + + settings_connection_update (self, + TRUE, + context, + settings, + flags); } static void @@ -1951,7 +2044,7 @@ out_err: static void dbus_get_agent_secrets_cb (NMSettingsConnection *self, - NMSettingsConnectionCallId call_id, + NMSettingsConnectionCallId *call_id, const char *agent_username, const char *setting_name, GError *error, @@ -2052,10 +2145,12 @@ dbus_clear_secrets_auth_cb (NMSettingsConnection *self, nm_connection_get_path (NM_CONNECTION (self)), NM_CONNECTION (self)); - nm_settings_connection_commit_changes (self, - NULL, - NM_SETTINGS_CONNECTION_COMMIT_REASON_NONE, - &local); + nm_settings_connection_update (self, + NULL, + NM_SETTINGS_CONNECTION_PERSIST_MODE_DISK, + NM_SETTINGS_CONNECTION_COMMIT_REASON_NONE, + "clear-secrets", + &local); nm_audit_log_connection_op (NM_AUDIT_OP_CONN_CLEAR_SECRETS, self, !local, NULL, subject, local ? local->message : NULL); @@ -2112,6 +2207,14 @@ nm_settings_connection_get_unsaved (NMSettingsConnection *self) /*****************************************************************************/ +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"), +); + NMSettingsConnectionFlags nm_settings_connection_get_flags (NMSettingsConnection *self) { @@ -2123,35 +2226,38 @@ nm_settings_connection_get_flags (NMSettingsConnection *self) NMSettingsConnectionFlags nm_settings_connection_set_flags (NMSettingsConnection *self, NMSettingsConnectionFlags flags, gboolean set) { - NMSettingsConnectionFlags new_flags; - - g_return_val_if_fail (NM_IS_SETTINGS_CONNECTION (self), NM_SETTINGS_CONNECTION_FLAGS_NONE); - g_return_val_if_fail ((flags & ~NM_SETTINGS_CONNECTION_FLAGS_ALL) == 0, NM_SETTINGS_CONNECTION_FLAGS_NONE); - - new_flags = NM_SETTINGS_CONNECTION_GET_PRIVATE (self)->flags; - if (set) - new_flags |= flags; - else - new_flags &= ~flags; - return nm_settings_connection_set_flags_all (self, new_flags); + return nm_settings_connection_set_flags_full (self, + flags, + set ? flags : NM_SETTINGS_CONNECTION_FLAGS_NONE); } NMSettingsConnectionFlags -nm_settings_connection_set_flags_all (NMSettingsConnection *self, NMSettingsConnectionFlags flags) +nm_settings_connection_set_flags_full (NMSettingsConnection *self, + NMSettingsConnectionFlags mask, + NMSettingsConnectionFlags value) { NMSettingsConnectionPrivate *priv; NMSettingsConnectionFlags old_flags; g_return_val_if_fail (NM_IS_SETTINGS_CONNECTION (self), NM_SETTINGS_CONNECTION_FLAGS_NONE); - g_return_val_if_fail ((flags & ~NM_SETTINGS_CONNECTION_FLAGS_ALL) == 0, 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); + value = (priv->flags & ~mask) | value; + old_flags = priv->flags; - if (old_flags != flags) { - _LOGT ("update settings-connection flags to 0x%x (was 0x%x)", (guint) flags, (guint) priv->flags); - priv->flags = flags; + if (old_flags != value) { + char buf1[255], buf2[255]; + + _LOGT ("update settings-connection flags to %s (was %s)", + _settings_connection_flags_to_string (value, buf1, sizeof (buf1)), + _settings_connection_flags_to_string (priv->flags, buf2, sizeof (buf2))); + priv->flags = value; + nm_assert (priv->flags == value); _notify (self, PROP_FLAGS); - if (NM_FLAGS_HAS (old_flags, NM_SETTINGS_CONNECTION_FLAGS_UNSAVED) != NM_FLAGS_HAS (flags, NM_SETTINGS_CONNECTION_FLAGS_UNSAVED)) + 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; @@ -2533,6 +2639,54 @@ nm_settings_connection_read_and_fill_seen_bssids (NMSettingsConnection *self) /*****************************************************************************/ +static int +_autoconnect_retries_initial (NMSettingsConnection *self) +{ + NMSettingConnection *s_con; + int retries = -1; + + s_con = nm_connection_get_setting_connection ((NMConnection *) self); + if (s_con) + retries = nm_setting_connection_get_autoconnect_retries (s_con); + + /* -1 means 'default' */ + if (retries == -1) + retries = nm_config_data_get_autoconnect_retries_default (NM_CONFIG_GET_DATA); + + /* 0 means 'forever', which is translated to a retry count of -1 */ + if (retries == 0) + retries = AUTOCONNECT_RETRIES_FOREVER; + + nm_assert (retries == AUTOCONNECT_RETRIES_FOREVER || retries >= 0); + return retries; +} + +static void +_autoconnect_retries_set (NMSettingsConnection *self, + int retries, + gboolean is_reset) +{ + NMSettingsConnectionPrivate *priv = NM_SETTINGS_CONNECTION_GET_PRIVATE (self); + + g_return_if_fail (retries == AUTOCONNECT_RETRIES_FOREVER || retries >= 0); + + if (priv->autoconnect_retries != retries) { + _LOGT ("autoconnect: retries set %d%s", retries, + is_reset ? " (reset)" : ""); + priv->autoconnect_retries = retries; + } + + if (retries) + priv->autoconnect_retries_blocked_until = 0; + else { + /* 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). */ + priv->autoconnect_retries_blocked_until = nm_utils_get_monotonic_timestamp_s () + AUTOCONNECT_RESET_RETRIES_TIMER; + } +} + /** * nm_settings_connection_autoconnect_retries_get: * @self: the settings connection @@ -2547,30 +2701,10 @@ nm_settings_connection_autoconnect_retries_get (NMSettingsConnection *self) NMSettingsConnectionPrivate *priv = NM_SETTINGS_CONNECTION_GET_PRIVATE (self); if (G_UNLIKELY (priv->autoconnect_retries == AUTOCONNECT_RETRIES_UNSET)) { - NMSettingConnection *s_con; - int retries = -1; - - s_con = nm_connection_get_setting_connection ((NMConnection *) self); - if (s_con) - retries = nm_setting_connection_get_autoconnect_retries (s_con); - - /* -1 means 'default' */ - if (retries == -1) { - retries = nm_config_data_get_value_int64 (NM_CONFIG_GET_DATA, - NM_CONFIG_KEYFILE_GROUP_MAIN, - "autoconnect-retries-default", - 10, 0, G_MAXINT32, - AUTOCONNECT_RETRIES_DEFAULT); - } - - /* 0 means 'forever', which is translated to a retry count of -1 */ - if (retries == 0) - retries = AUTOCONNECT_RETRIES_FOREVER; - - _LOGT ("autoconnect-retries: init %d", retries); - priv->autoconnect_retries = retries; + _autoconnect_retries_set (self, + _autoconnect_retries_initial (self), + TRUE); } - return priv->autoconnect_retries; } @@ -2578,86 +2712,90 @@ void nm_settings_connection_autoconnect_retries_set (NMSettingsConnection *self, int retries) { - NMSettingsConnectionPrivate *priv; - g_return_if_fail (NM_IS_SETTINGS_CONNECTION (self)); - nm_assert (retries == AUTOCONNECT_RETRIES_UNSET || retries >= 0); - - priv = NM_SETTINGS_CONNECTION_GET_PRIVATE (self); + g_return_if_fail (retries >= 0); - if (priv->autoconnect_retries != retries) { - _LOGT ("autoconnect-retries: set %d", retries); - priv->autoconnect_retries = retries; - } - if (retries) - priv->autoconnect_blocked_until = 0; - else - priv->autoconnect_blocked_until = nm_utils_get_monotonic_timestamp_s () + AUTOCONNECT_RESET_RETRIES_TIMER; + _autoconnect_retries_set (self, retries, FALSE); } void nm_settings_connection_autoconnect_retries_reset (NMSettingsConnection *self) { - nm_settings_connection_autoconnect_retries_set (self, AUTOCONNECT_RETRIES_UNSET); + g_return_if_fail (NM_IS_SETTINGS_CONNECTION (self)); + + _autoconnect_retries_set (self, + _autoconnect_retries_initial (self), + TRUE); } gint32 -nm_settings_connection_autoconnect_blocked_until_get (NMSettingsConnection *self) +nm_settings_connection_autoconnect_retries_blocked_until (NMSettingsConnection *self) { - return NM_SETTINGS_CONNECTION_GET_PRIVATE (self)->autoconnect_blocked_until; + return NM_SETTINGS_CONNECTION_GET_PRIVATE (self)->autoconnect_retries_blocked_until; } +NM_UTILS_FLAGS2STR_DEFINE_STATIC (_autoconnect_blocked_reason_to_string, NMSettingsAutoconnectBlockedReason, + NM_UTILS_FLAGS2STR (NM_SETTINGS_AUTO_CONNECT_BLOCKED_REASON_NONE, "none"), + NM_UTILS_FLAGS2STR (NM_SETTINGS_AUTO_CONNECT_BLOCKED_REASON_USER_REQUEST, "user-request"), + NM_UTILS_FLAGS2STR (NM_SETTINGS_AUTO_CONNECT_BLOCKED_REASON_FAILED, "failed"), + NM_UTILS_FLAGS2STR (NM_SETTINGS_AUTO_CONNECT_BLOCKED_REASON_NO_SECRETS, "no-secrets"), +); + NMSettingsAutoconnectBlockedReason -nm_settings_connection_autoconnect_blocked_reason_get (NMSettingsConnection *self) +nm_settings_connection_autoconnect_blocked_reason_get (NMSettingsConnection *self, NMSettingsAutoconnectBlockedReason mask) { - return NM_SETTINGS_CONNECTION_GET_PRIVATE (self)->autoconnect_blocked_reason; + return NM_SETTINGS_CONNECTION_GET_PRIVATE (self)->autoconnect_blocked_reason & (mask ?: NM_SETTINGS_AUTO_CONNECT_BLOCKED_REASON_ALL); } -void -nm_settings_connection_autoconnect_blocked_reason_set (NMSettingsConnection *self, - NMSettingsAutoconnectBlockedReason reason) +gboolean +nm_settings_connection_autoconnect_blocked_reason_set_full (NMSettingsConnection *self, + NMSettingsAutoconnectBlockedReason mask, + NMSettingsAutoconnectBlockedReason value) { - g_return_if_fail (NM_IN_SET (reason, - NM_SETTINGS_AUTO_CONNECT_BLOCKED_REASON_NONE, - NM_SETTINGS_AUTO_CONNECT_BLOCKED_REASON_USER_REQUEST, - NM_SETTINGS_AUTO_CONNECT_BLOCKED_REASON_FAILED, - NM_SETTINGS_AUTO_CONNECT_BLOCKED_REASON_NO_SECRETS)); - NM_SETTINGS_CONNECTION_GET_PRIVATE (self)->autoconnect_blocked_reason = reason; -} + NMSettingsAutoconnectBlockedReason v; + NMSettingsConnectionPrivate *priv = NM_SETTINGS_CONNECTION_GET_PRIVATE (self); + char buf[100]; -/*****************************************************************************/ + nm_assert (mask); + nm_assert (!NM_FLAGS_ANY (value, ~mask)); -/** - * nm_settings_connection_get_nm_generated: - * @self: an #NMSettingsConnection - * - * Gets the "nm-generated" flag on @self. - * - * A connection is "nm-generated" if it was generated by - * nm_device_generate_connection() and has not been modified or - * saved by the user since then. - */ -gboolean -nm_settings_connection_get_nm_generated (NMSettingsConnection *self) -{ - return NM_FLAGS_HAS (nm_settings_connection_get_flags (self), NM_SETTINGS_CONNECTION_FLAGS_NM_GENERATED); + v = priv->autoconnect_blocked_reason; + v = (v & ~mask) | (value & mask); + + if (priv->autoconnect_blocked_reason == v) + return FALSE; + + _LOGT ("autoconnect: blocked reason: %s", _autoconnect_blocked_reason_to_string (v, buf, sizeof (buf))); + priv->autoconnect_blocked_reason = v; + return TRUE; } -/** - * nm_settings_connection_get_volatile: - * @self: an #NMSettingsConnection - * - * Gets the "volatile" flag on @self. - * - * The connection is marked as volatile and will be removed when - * it disconnects. - */ gboolean -nm_settings_connection_get_volatile (NMSettingsConnection *self) +nm_settings_connection_autoconnect_is_blocked (NMSettingsConnection *self) { - return NM_FLAGS_HAS (nm_settings_connection_get_flags (self), NM_SETTINGS_CONNECTION_FLAGS_VOLATILE); + NMSettingsConnectionPrivate *priv; + NMSettingsConnectionFlags flags; + + g_return_val_if_fail (NM_IS_SETTINGS_CONNECTION (self), TRUE); + + priv = NM_SETTINGS_CONNECTION_GET_PRIVATE (self); + + if (priv->autoconnect_blocked_reason != NM_SETTINGS_AUTO_CONNECT_BLOCKED_REASON_NONE) + return TRUE; + if (priv->autoconnect_retries == 0) + return TRUE; + + flags = priv->flags; + if (NM_FLAGS_HAS (flags, NM_SETTINGS_CONNECTION_FLAGS_VOLATILE)) + return TRUE; + if (!NM_FLAGS_HAS (flags, NM_SETTINGS_CONNECTION_FLAGS_VISIBLE)) + return TRUE; + + return FALSE; } +/*****************************************************************************/ + gboolean nm_settings_connection_get_ready (NMSettingsConnection *self) { @@ -2738,8 +2876,8 @@ nm_settings_connection_init (NMSettingsConnection *self) priv = G_TYPE_INSTANCE_GET_PRIVATE (self, NM_TYPE_SETTINGS_CONNECTION, NMSettingsConnectionPrivate); self->_priv = priv; - priv->visible = FALSE; priv->ready = TRUE; + c_list_init (&priv->call_ids_lst_head); priv->session_monitor = g_object_ref (nm_session_monitor_get ()); priv->session_changed_id = g_signal_connect (priv->session_monitor, @@ -2771,17 +2909,14 @@ dispose (GObject *object) { NMSettingsConnection *self = NM_SETTINGS_CONNECTION (object); NMSettingsConnectionPrivate *priv = NM_SETTINGS_CONNECTION_GET_PRIVATE (self); + NMSettingsConnectionCallId *call_id, *call_id_safe; _LOGD ("disposing"); /* Cancel in-progress secrets requests */ if (priv->agent_mgr) { - while (priv->get_secret_requests) { - GetSecretsInfo *info = priv->get_secret_requests->data; - - _get_secrets_cancel (self, info, TRUE); - g_return_if_fail (!priv->get_secret_requests || (info != priv->get_secret_requests->data)); - } + c_list_for_each_entry_safe (call_id, call_id_safe, &priv->call_ids_lst_head, call_ids_lst) + _get_secrets_cancel (self, call_id, TRUE); } /* Disconnect handlers. @@ -2818,12 +2953,8 @@ get_property (GObject *object, guint prop_id, GValue *value, GParamSpec *pspec) { NMSettingsConnection *self = NM_SETTINGS_CONNECTION (object); - NMSettingsConnectionPrivate *priv = NM_SETTINGS_CONNECTION_GET_PRIVATE (self); switch (prop_id) { - case PROP_VISIBLE: - g_value_set_boolean (value, priv->visible); - break; case PROP_UNSAVED: g_value_set_boolean (value, nm_settings_connection_get_unsaved (self)); break; @@ -2876,12 +3007,6 @@ nm_settings_connection_class_init (NMSettingsConnectionClass *class) class->supports_secrets = supports_secrets; - obj_properties[PROP_VISIBLE] = - g_param_spec_boolean (NM_SETTINGS_CONNECTION_VISIBLE, "", "", - FALSE, - G_PARAM_READABLE | - G_PARAM_STATIC_STRINGS); - obj_properties[PROP_UNSAVED] = g_param_spec_boolean (NM_SETTINGS_CONNECTION_UNSAVED, "", "", FALSE, @@ -2948,6 +3073,7 @@ nm_settings_connection_class_init (NMSettingsConnectionClass *class) "GetSecrets", impl_settings_connection_get_secrets, "ClearSecrets", impl_settings_connection_clear_secrets, "Save", impl_settings_connection_save, + "Update2", impl_settings_connection_update2, NULL); } diff --git a/src/settings/nm-settings-connection.h b/src/settings/nm-settings-connection.h index faacd949..fc8ad1de 100644 --- a/src/settings/nm-settings-connection.h +++ b/src/settings/nm-settings-connection.h @@ -44,8 +44,9 @@ #define NM_SETTINGS_CONNECTION_UPDATED_INTERNAL "updated-internal" /* Properties */ -#define NM_SETTINGS_CONNECTION_VISIBLE "visible" #define NM_SETTINGS_CONNECTION_UNSAVED "unsaved" + +/* Internal properties */ #define NM_SETTINGS_CONNECTION_READY "ready" #define NM_SETTINGS_CONNECTION_FLAGS "flags" #define NM_SETTINGS_CONNECTION_FILENAME "filename" @@ -61,22 +62,25 @@ * @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. + * @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_FLAGS_NONE = 0x00, - NM_SETTINGS_CONNECTION_FLAGS_UNSAVED = 0x01, - NM_SETTINGS_CONNECTION_FLAGS_NM_GENERATED = 0x02, - NM_SETTINGS_CONNECTION_FLAGS_VOLATILE = 0x04, +typedef enum { + NM_SETTINGS_CONNECTION_FLAGS_NONE = 0, + + 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_FLAGS_VISIBLE = (1LL << 3), __NM_SETTINGS_CONNECTION_FLAGS_LAST, NM_SETTINGS_CONNECTION_FLAGS_ALL = ((__NM_SETTINGS_CONNECTION_FLAGS_LAST - 1) << 1) - 1, } NMSettingsConnectionFlags; -typedef enum { /*< skip >*/ +typedef enum { NM_SETTINGS_CONNECTION_COMMIT_REASON_NONE = 0, NM_SETTINGS_CONNECTION_COMMIT_REASON_USER_ACTION = (1LL << 0), NM_SETTINGS_CONNECTION_COMMIT_REASON_ID_CHANGED = (1LL << 1), @@ -84,13 +88,18 @@ typedef enum { /*< skip >*/ typedef enum { NM_SETTINGS_AUTO_CONNECT_BLOCKED_REASON_NONE = 0, - NM_SETTINGS_AUTO_CONNECT_BLOCKED_REASON_USER_REQUEST = 1, - NM_SETTINGS_AUTO_CONNECT_BLOCKED_REASON_FAILED = 2, - NM_SETTINGS_AUTO_CONNECT_BLOCKED_REASON_NO_SECRETS = 3, + + NM_SETTINGS_AUTO_CONNECT_BLOCKED_REASON_USER_REQUEST = (1LL << 0), + NM_SETTINGS_AUTO_CONNECT_BLOCKED_REASON_FAILED = (1LL << 1), + NM_SETTINGS_AUTO_CONNECT_BLOCKED_REASON_NO_SECRETS = (1LL << 2), + + NM_SETTINGS_AUTO_CONNECT_BLOCKED_REASON_ALL = ( NM_SETTINGS_AUTO_CONNECT_BLOCKED_REASON_USER_REQUEST + | NM_SETTINGS_AUTO_CONNECT_BLOCKED_REASON_FAILED + | NM_SETTINGS_AUTO_CONNECT_BLOCKED_REASON_NO_SECRETS), } NMSettingsAutoconnectBlockedReason; struct _NMSettingsConnectionCallId; -typedef struct _NMSettingsConnectionCallId *NMSettingsConnectionCallId; +typedef struct _NMSettingsConnectionCallId NMSettingsConnectionCallId; typedef struct _NMSettingsConnectionClass NMSettingsConnectionClass; @@ -120,37 +129,39 @@ struct _NMSettingsConnectionClass { GType nm_settings_connection_get_type (void); +guint64 nm_settings_connection_get_last_secret_agent_version_id (NMSettingsConnection *self); + gboolean nm_settings_connection_has_unmodified_applied_connection (NMSettingsConnection *self, NMConnection *applied_connection, NMSettingCompareFlags compare_flage); -gboolean nm_settings_connection_commit_changes (NMSettingsConnection *self, - NMConnection *new_connection, - NMSettingsConnectionCommitReason commit_reason, - GError **error); - -gboolean nm_settings_connection_replace_settings_prepare (NMSettingsConnection *self, - NMConnection *new_connection, - GError **error); - -gboolean nm_settings_connection_replace_settings (NMSettingsConnection *self, - NMConnection *new_connection, - gboolean update_unsaved, - const char *log_diff_name, - GError **error); - -gboolean nm_settings_connection_replace_settings_full (NMSettingsConnection *self, - NMConnection *new_connection, - gboolean prepare_new_connection, - gboolean update_unsaved, - const char *log_diff_name, - GError **error); +typedef enum { + NM_SETTINGS_CONNECTION_PERSIST_MODE_KEEP, + NM_SETTINGS_CONNECTION_PERSIST_MODE_DISK, + + /* unsaved, only sets the unsaved flag, but it doesn't touch + * the NM_GENERATED nor VOLATILE flag. */ + NM_SETTINGS_CONNECTION_PERSIST_MODE_UNSAVED, + + NM_SETTINGS_CONNECTION_PERSIST_MODE_IN_MEMORY, + NM_SETTINGS_CONNECTION_PERSIST_MODE_IN_MEMORY_DETACHED, + NM_SETTINGS_CONNECTION_PERSIST_MODE_IN_MEMORY_ONLY, + NM_SETTINGS_CONNECTION_PERSIST_MODE_VOLATILE_DETACHED, + NM_SETTINGS_CONNECTION_PERSIST_MODE_VOLATILE_ONLY, +} NMSettingsConnectionPersistMode; + +gboolean nm_settings_connection_update (NMSettingsConnection *self, + NMConnection *new_connection, + NMSettingsConnectionPersistMode persist_mode, + NMSettingsConnectionCommitReason commit_reason, + const char *log_diff_name, + GError **error); gboolean nm_settings_connection_delete (NMSettingsConnection *self, GError **error); typedef void (*NMSettingsConnectionSecretsFunc) (NMSettingsConnection *self, - NMSettingsConnectionCallId call_id, + NMSettingsConnectionCallId *call_id, const char *agent_username, const char *setting_name, GError *error, @@ -162,19 +173,17 @@ gboolean nm_settings_connection_new_secrets (NMSettingsConnection *self, GVariant *secrets, GError **error); -NMSettingsConnectionCallId nm_settings_connection_get_secrets (NMSettingsConnection *self, - NMConnection *applied_connection, - NMAuthSubject *subject, - const char *setting_name, - NMSecretAgentGetSecretsFlags flags, - const char **hints, - NMSettingsConnectionSecretsFunc callback, - gpointer callback_data); +NMSettingsConnectionCallId *nm_settings_connection_get_secrets (NMSettingsConnection *self, + NMConnection *applied_connection, + NMAuthSubject *subject, + const char *setting_name, + NMSecretAgentGetSecretsFlags flags, + const char *const*hints, + NMSettingsConnectionSecretsFunc callback, + gpointer callback_data); void nm_settings_connection_cancel_secrets (NMSettingsConnection *self, - NMSettingsConnectionCallId call_id); - -gboolean nm_settings_connection_is_visible (NMSettingsConnection *self); + NMSettingsConnectionCallId *call_id); void nm_settings_connection_recheck_visibility (NMSettingsConnection *self); @@ -187,7 +196,7 @@ gboolean nm_settings_connection_get_unsaved (NMSettingsConnection *self); 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_all (NMSettingsConnection *self, NMSettingsConnectionFlags flags); +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); @@ -218,14 +227,23 @@ void nm_settings_connection_autoconnect_retries_set (NMSettingsConnection *self, int retries); void nm_settings_connection_autoconnect_retries_reset (NMSettingsConnection *self); -gint32 nm_settings_connection_autoconnect_blocked_until_get (NMSettingsConnection *self); +gint32 nm_settings_connection_autoconnect_retries_blocked_until (NMSettingsConnection *self); -NMSettingsAutoconnectBlockedReason nm_settings_connection_autoconnect_blocked_reason_get (NMSettingsConnection *self); -void nm_settings_connection_autoconnect_blocked_reason_set (NMSettingsConnection *self, - NMSettingsAutoconnectBlockedReason reason); +NMSettingsAutoconnectBlockedReason nm_settings_connection_autoconnect_blocked_reason_get (NMSettingsConnection *self, + NMSettingsAutoconnectBlockedReason mask); +gboolean nm_settings_connection_autoconnect_blocked_reason_set_full (NMSettingsConnection *self, + NMSettingsAutoconnectBlockedReason mask, + NMSettingsAutoconnectBlockedReason value); + +static inline gboolean +nm_settings_connection_autoconnect_blocked_reason_set (NMSettingsConnection *self, + NMSettingsAutoconnectBlockedReason mask, + gboolean set) +{ + return nm_settings_connection_autoconnect_blocked_reason_set_full (self, mask, set ? mask : NM_SETTINGS_AUTO_CONNECT_BLOCKED_REASON_NONE); +} -gboolean nm_settings_connection_get_nm_generated (NMSettingsConnection *self); -gboolean nm_settings_connection_get_volatile (NMSettingsConnection *self); +gboolean nm_settings_connection_autoconnect_is_blocked (NMSettingsConnection *self); gboolean nm_settings_connection_get_ready (NMSettingsConnection *self); void nm_settings_connection_set_ready (NMSettingsConnection *self, diff --git a/src/settings/nm-settings.c b/src/settings/nm-settings.c index e2b467a2..21fdf9e0 100644 --- a/src/settings/nm-settings.c +++ b/src/settings/nm-settings.c @@ -75,7 +75,6 @@ #include "nm-audit-manager.h" #include "NetworkManagerUtils.h" #include "nm-dispatcher.h" -#include "nm-inotify-helper.h" #include "nm-hostname-manager.h" #include "introspection/org.freedesktop.NetworkManager.Settings.h" @@ -84,13 +83,8 @@ #define EXPORT(sym) void * __export_##sym = &sym; -EXPORT(nm_inotify_helper_get_type) -EXPORT(nm_inotify_helper_get) -EXPORT(nm_inotify_helper_add_watch) -EXPORT(nm_inotify_helper_remove_watch) - EXPORT(nm_settings_connection_get_type) -EXPORT(nm_settings_connection_replace_settings) +EXPORT(nm_settings_connection_update) /*****************************************************************************/ @@ -127,8 +121,7 @@ enum { CONNECTION_ADDED, CONNECTION_UPDATED, CONNECTION_REMOVED, - CONNECTION_VISIBILITY_CHANGED, - AGENT_REGISTERED, + CONNECTION_FLAGS_CHANGED, NEW_CONNECTION, /* exported, not used internally */ LAST_SIGNAL }; @@ -431,6 +424,9 @@ nm_settings_get_connections (NMSettings *self, guint *out_len) * @out_len: (allow-none): optional output argument * @func: caller-supplied function for filtering connections * @func_data: caller-supplied data passed to @func + * @sort_compare_func: (allow-none): optional function pointer for + * sorting the returned list. + * @sort_data: user data for @sort_compare_func. * * Returns: (transfer container) (element-type NMSettingsConnection): * an NULL terminated array of #NMSettingsConnection objects that were @@ -443,7 +439,9 @@ NMSettingsConnection ** nm_settings_get_connections_clone (NMSettings *self, guint *out_len, NMSettingsConnectionFilterFunc func, - gpointer func_data) + gpointer func_data, + GCompareDataFunc sort_compare_func, + gpointer sort_data) { NMSettingsConnection *const*list_cached; NMSettingsConnection **list; @@ -471,31 +469,15 @@ nm_settings_get_connections_clone (NMSettings *self, } else memcpy (list, list_cached, sizeof (list[0]) * ((gsize) len + 1)); + if ( len > 1 + && sort_compare_func) { + g_qsort_with_data (list, len, sizeof (NMSettingsConnection *), + sort_compare_func, sort_data); + } NM_SET_OUT (out_len, len); return list; } -/* Returns a list of NMSettingsConnections. - * The list is sorted in the order suitable for auto-connecting, i.e. - * first go connections with autoconnect=yes and most recent timestamp. - * Caller must free the list with g_free(), but not the list items. - */ -NMSettingsConnection ** -nm_settings_get_connections_sorted (NMSettings *self, guint *out_len) -{ - NMSettingsConnection **connections; - guint len; - - g_return_val_if_fail (NM_IS_SETTINGS (self), NULL); - - connections = nm_settings_get_connections_clone (self, &len, NULL, NULL); - if (len > 1) - g_qsort_with_data (connections, len, sizeof (NMSettingsConnection *), nm_settings_connection_cmp_autoconnect_priority_p_with_data, NULL); - - NM_SET_OUT (out_len, len); - return connections; -} - NMSettingsConnection * nm_settings_get_connection_by_path (NMSettings *self, const char *path) { @@ -838,13 +820,12 @@ connection_updated (NMSettingsConnection *connection, gboolean by_user, gpointer } static void -connection_visibility_changed (NMSettingsConnection *connection, - GParamSpec *pspec, - gpointer user_data) +connection_flags_changed (NMSettingsConnection *connection, + GParamSpec *pspec, + gpointer user_data) { - /* Re-emit for listeners like NMPolicy */ g_signal_emit (NM_SETTINGS (user_data), - signals[CONNECTION_VISIBILITY_CHANGED], + signals[CONNECTION_FLAGS_CHANGED], 0, connection); } @@ -867,7 +848,7 @@ connection_removed (NMSettingsConnection *connection, gpointer user_data) g_signal_handlers_disconnect_by_func (connection, G_CALLBACK (connection_removed), self); g_signal_handlers_disconnect_by_func (connection, G_CALLBACK (connection_updated), self); - g_signal_handlers_disconnect_by_func (connection, G_CALLBACK (connection_visibility_changed), self); + 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); @@ -889,18 +870,6 @@ connection_removed (NMSettingsConnection *connection, gpointer user_data) g_object_unref (connection); } -static void -secret_agent_registered (NMAgentManager *agent_mgr, - NMSecretAgent *agent, - gpointer user_data) -{ - /* Re-emit for listeners like NMPolicy */ - g_signal_emit (NM_SETTINGS (user_data), - signals[AGENT_REGISTERED], - 0, - agent); -} - #define NM_DBUS_SERVICE_OPENCONNECT "org.freedesktop.NetworkManager.openconnect" #define NM_OPENCONNECT_KEY_GATEWAY "gateway" #define NM_OPENCONNECT_KEY_COOKIE "cookie" @@ -1003,8 +972,8 @@ claim_connection (NMSettings *self, NMSettingsConnection *connection) G_CALLBACK (connection_removed), self); g_signal_connect (connection, NM_SETTINGS_CONNECTION_UPDATED_INTERNAL, G_CALLBACK (connection_updated), self); - g_signal_connect (connection, "notify::" NM_SETTINGS_CONNECTION_VISIBLE, - G_CALLBACK (connection_visibility_changed), + g_signal_connect (connection, "notify::" NM_SETTINGS_CONNECTION_FLAGS, + G_CALLBACK (connection_flags_changed), self); if (!priv->startup_complete) { g_signal_connect (connection, "notify::" NM_SETTINGS_CONNECTION_READY, @@ -1037,6 +1006,25 @@ claim_connection (NMSettings *self, NMSettingsConnection *connection) } } +static gboolean +secrets_filter_cb (NMSetting *setting, + const char *secret, + NMSettingSecretFlags flags, + gpointer user_data) +{ + NMSettingSecretFlags filter_flags = GPOINTER_TO_UINT (user_data); + + /* Returns TRUE to remove the secret */ + + /* Can't use bitops with SECRET_FLAG_NONE so handle that specifically */ + if ( (flags == NM_SETTING_SECRET_FLAG_NONE) + && (filter_flags == NM_SETTING_SECRET_FLAG_NONE)) + return FALSE; + + /* Otherwise if the secret has at least one of the desired flags keep it */ + return (flags & filter_flags) ? FALSE : TRUE; +} + /** * nm_settings_add_connection: * @self: the #NMSettings object @@ -1087,9 +1075,22 @@ nm_settings_add_connection (NMSettings *self, for (iter = priv->plugins; iter; iter = g_slist_next (iter)) { NMSettingsPlugin *plugin = NM_SETTINGS_PLUGIN (iter->data); GError *add_error = NULL; + gs_unref_object NMConnection *simple = NULL; + gs_unref_variant GVariant *secrets = NULL; + + /* 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 + * reread from the file. */ + simple = nm_simple_connection_new_clone (connection); + nm_connection_clear_secrets_with_flags (simple, + secrets_filter_cb, + GUINT_TO_POINTER (NM_SETTING_SECRET_FLAG_AGENT_OWNED)); + secrets = nm_connection_to_dbus (simple, NM_CONNECTION_SERIALIZE_ONLY_SECRETS); added = nm_settings_plugin_add_connection (plugin, connection, save_to_disk, &add_error); if (added) { + if (secrets) + nm_connection_update_secrets (NM_CONNECTION (added), NULL, secrets, NULL); claim_connection (self, added); return added; } @@ -1105,25 +1106,6 @@ nm_settings_add_connection (NMSettings *self, return NULL; } -static gboolean -secrets_filter_cb (NMSetting *setting, - const char *secret, - NMSettingSecretFlags flags, - gpointer user_data) -{ - NMSettingSecretFlags filter_flags = GPOINTER_TO_UINT (user_data); - - /* Returns TRUE to remove the secret */ - - /* Can't use bitops with SECRET_FLAG_NONE so handle that specifically */ - if ( (flags == NM_SETTING_SECRET_FLAG_NONE) - && (filter_flags == NM_SETTING_SECRET_FLAG_NONE)) - return FALSE; - - /* Otherwise if the secret has at least one of the desired flags keep it */ - return (flags & filter_flags) ? FALSE : TRUE; -} - static void send_agent_owned_secrets (NMSettings *self, NMSettingsConnection *connection, @@ -1886,16 +1868,8 @@ nm_settings_init (NMSettings *self) priv->connections = g_hash_table_new_full (nm_str_hash, g_str_equal, NULL, g_object_unref); - /* Hold a reference to the agent manager so it stays alive; the only - * other holders are NMSettingsConnection objects which are often - * transient, and we don't want the agent manager to get destroyed and - * recreated often. - */ priv->agent_mgr = g_object_ref (nm_agent_manager_get ()); - priv->config = g_object_ref (nm_config_get ()); - - g_signal_connect (priv->agent_mgr, "agent-registered", G_CALLBACK (secret_agent_registered), self); } NMSettings * @@ -2012,23 +1986,14 @@ nm_settings_class_init (NMSettingsClass *class) g_cclosure_marshal_VOID__OBJECT, G_TYPE_NONE, 1, NM_TYPE_SETTINGS_CONNECTION); - signals[CONNECTION_VISIBILITY_CHANGED] = - g_signal_new (NM_SETTINGS_SIGNAL_CONNECTION_VISIBILITY_CHANGED, + signals[CONNECTION_FLAGS_CHANGED] = + g_signal_new (NM_SETTINGS_SIGNAL_CONNECTION_FLAGS_CHANGED, 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); - signals[AGENT_REGISTERED] = - g_signal_new (NM_SETTINGS_SIGNAL_AGENT_REGISTERED, - G_OBJECT_CLASS_TYPE (object_class), - G_SIGNAL_RUN_FIRST, - 0, NULL, NULL, - g_cclosure_marshal_VOID__OBJECT, - G_TYPE_NONE, 1, NM_TYPE_SECRET_AGENT); - - signals[NEW_CONNECTION] = g_signal_new ("new-connection", G_OBJECT_CLASS_TYPE (object_class), diff --git a/src/settings/nm-settings.h b/src/settings/nm-settings.h index eede76b0..0ecffb70 100644 --- a/src/settings/nm-settings.h +++ b/src/settings/nm-settings.h @@ -46,8 +46,7 @@ #define NM_SETTINGS_SIGNAL_CONNECTION_ADDED "connection-added" #define NM_SETTINGS_SIGNAL_CONNECTION_UPDATED "connection-updated" #define NM_SETTINGS_SIGNAL_CONNECTION_REMOVED "connection-removed" -#define NM_SETTINGS_SIGNAL_CONNECTION_VISIBILITY_CHANGED "connection-visibility-changed" -#define NM_SETTINGS_SIGNAL_AGENT_REGISTERED "agent-registered" +#define NM_SETTINGS_SIGNAL_CONNECTION_FLAGS_CHANGED "connection-flags-changed" /** * NMConnectionFilterFunc: @@ -100,10 +99,9 @@ NMSettingsConnection *const* nm_settings_get_connections (NMSettings *settings, NMSettingsConnection **nm_settings_get_connections_clone (NMSettings *self, guint *out_len, NMSettingsConnectionFilterFunc func, - gpointer func_data); - -NMSettingsConnection **nm_settings_get_connections_sorted (NMSettings *self, - guint *out_len); + gpointer func_data, + GCompareDataFunc sort_compare_func, + gpointer sort_data); NMSettingsConnection *nm_settings_add_connection (NMSettings *settings, NMConnection *connection, diff --git a/src/settings/plugins/ibft/nms-ibft-connection.c b/src/settings/plugins/ibft/nms-ibft-connection.c index 834ba834..2a7c5f4a 100644 --- a/src/settings/plugins/ibft/nms-ibft-connection.c +++ b/src/settings/plugins/ibft/nms-ibft-connection.c @@ -60,11 +60,12 @@ nms_ibft_connection_new (const GPtrArray *block, GError **error) object = g_object_new (NMS_TYPE_IBFT_CONNECTION, NULL); /* Update settings with what was read from iscsiadm */ - if (!nm_settings_connection_replace_settings (NM_SETTINGS_CONNECTION (object), - source, - FALSE, - NULL, - error)) + if (!nm_settings_connection_update (NM_SETTINGS_CONNECTION (object), + source, + NM_SETTINGS_CONNECTION_PERSIST_MODE_KEEP, + NM_SETTINGS_CONNECTION_COMMIT_REASON_NONE, + NULL, + error)) g_clear_object (&object); return (NMSIbftConnection *) object; diff --git a/src/settings/plugins/ibft/nms-ibft-plugin.c b/src/settings/plugins/ibft/nms-ibft-plugin.c index 9b1f5ccd..ea4d1524 100644 --- a/src/settings/plugins/ibft/nms-ibft-plugin.c +++ b/src/settings/plugins/ibft/nms-ibft-plugin.c @@ -202,5 +202,5 @@ settings_plugin_interface_init (NMSettingsPluginInterface *plugin_iface) G_MODULE_EXPORT GObject * nm_settings_plugin_factory (void) { - return g_object_ref (nms_ibft_plugin_get ()); + return G_OBJECT (g_object_ref (nms_ibft_plugin_get ())); } diff --git a/src/settings/nm-inotify-helper.c b/src/settings/plugins/ifcfg-rh/nm-inotify-helper.c index 4c65b02d..4c65b02d 100644 --- a/src/settings/nm-inotify-helper.c +++ b/src/settings/plugins/ifcfg-rh/nm-inotify-helper.c diff --git a/src/settings/nm-inotify-helper.h b/src/settings/plugins/ifcfg-rh/nm-inotify-helper.h index 2715f3ee..b887ae37 100644 --- a/src/settings/nm-inotify-helper.h +++ b/src/settings/plugins/ifcfg-rh/nm-inotify-helper.h @@ -43,4 +43,17 @@ int nm_inotify_helper_add_watch (NMInotifyHelper *helper, const char *path); void nm_inotify_helper_remove_watch (NMInotifyHelper *helper, int wd); +static inline gboolean +nm_inotify_helper_clear_watch (NMInotifyHelper *helper, int *wd) +{ + int x; + + if (wd && ((x = *wd) >= 0)) { + *wd = -1; + nm_inotify_helper_remove_watch (helper, x); + return TRUE; + } + return FALSE; +} + #endif /* __NM_INOTIFY_HELPER_H__ */ diff --git a/src/settings/plugins/ifcfg-rh/nms-ifcfg-rh-connection.c b/src/settings/plugins/ifcfg-rh/nms-ifcfg-rh-connection.c index 4c1d02ae..3cf5c978 100644 --- a/src/settings/plugins/ifcfg-rh/nms-ifcfg-rh-connection.c +++ b/src/settings/plugins/ifcfg-rh/nms-ifcfg-rh-connection.c @@ -36,13 +36,13 @@ #include "nm-setting-wireless-security.h" #include "nm-setting-8021x.h" #include "platform/nm-platform.h" -#include "settings/nm-inotify-helper.h" #include "nm-config.h" #include "nms-ifcfg-rh-common.h" #include "nms-ifcfg-rh-reader.h" #include "nms-ifcfg-rh-writer.h" #include "nms-ifcfg-rh-utils.h" +#include "nm-inotify-helper.h" /*****************************************************************************/ @@ -96,14 +96,6 @@ G_DEFINE_TYPE (NMIfcfgConnection, nm_ifcfg_connection, NM_TYPE_SETTINGS_CONNECTI /*****************************************************************************/ -static NMInotifyHelper * -_get_inotify_helper (NMIfcfgConnectionPrivate *priv) -{ - if (!priv->inotify_helper) - priv->inotify_helper = g_object_ref (nm_inotify_helper_get ()); - return priv->inotify_helper; -} - static gboolean devtimeout_ready (gpointer user_data) { @@ -225,37 +217,17 @@ static void path_watch_stop (NMIfcfgConnection *self) { NMIfcfgConnectionPrivate *priv = NM_IFCFG_CONNECTION_GET_PRIVATE (self); - NMInotifyHelper *ih; - - ih = _get_inotify_helper (priv); - - nm_clear_g_signal_handler (ih, &priv->ih_event_id); - - if (priv->file_wd >= 0) { - nm_inotify_helper_remove_watch (ih, priv->file_wd); - priv->file_wd = -1; - } - g_free (priv->keyfile); - priv->keyfile = NULL; - if (priv->keyfile_wd >= 0) { - nm_inotify_helper_remove_watch (ih, priv->keyfile_wd); - priv->keyfile_wd = -1; - } + nm_clear_g_signal_handler (priv->inotify_helper, &priv->ih_event_id); - g_free (priv->routefile); - priv->routefile = NULL; - if (priv->routefile_wd >= 0) { - nm_inotify_helper_remove_watch (ih, priv->routefile_wd); - priv->routefile_wd = -1; - } + nm_inotify_helper_clear_watch (priv->inotify_helper, &priv->file_wd); + nm_inotify_helper_clear_watch (priv->inotify_helper, &priv->keyfile_wd); + nm_inotify_helper_clear_watch (priv->inotify_helper, &priv->routefile_wd); + nm_inotify_helper_clear_watch (priv->inotify_helper, &priv->route6file_wd); - g_free (priv->route6file); - priv->route6file = NULL; - if (priv->route6file_wd >= 0) { - nm_inotify_helper_remove_watch (ih, priv->route6file_wd); - priv->route6file_wd = -1; - } + nm_clear_g_free (&priv->keyfile); + nm_clear_g_free (&priv->routefile); + nm_clear_g_free (&priv->route6file); } static void @@ -280,7 +252,9 @@ filename_changed (GObject *object, if (nm_config_get_monitor_connection_files (nm_config_get ())) { NMInotifyHelper *ih; - ih = _get_inotify_helper (priv); + if (!priv->inotify_helper) + priv->inotify_helper = g_object_ref (nm_inotify_helper_get ()); + ih = priv->inotify_helper; priv->ih_event_id = g_signal_connect (ih, "event", G_CALLBACK (files_changed_cb), self); priv->file_wd = nm_inotify_helper_add_watch (ih, ifcfg_path); @@ -324,7 +298,7 @@ commit_changes (NMSettingsConnection *connection, nm_assert (!out_logmsg_change || !*out_logmsg_change); filename = nm_settings_connection_get_filename (connection); - if (!nms_ifcfg_rh_writer_write_connection (new_connection ?: NM_CONNECTION (connection), + if (!nms_ifcfg_rh_writer_write_connection (new_connection, IFCFG_DIR, filename, &ifcfg_path, @@ -415,6 +389,13 @@ set_property (GObject *object, guint prop_id, static void nm_ifcfg_connection_init (NMIfcfgConnection *connection) { + NMIfcfgConnectionPrivate *priv = NM_IFCFG_CONNECTION_GET_PRIVATE (connection); + + priv->file_wd = -1; + priv->keyfile_wd = -1; + priv->routefile_wd = -1; + priv->route6file_wd = -1; + g_signal_connect (connection, "notify::" NM_SETTINGS_CONNECTION_FILENAME, G_CALLBACK (filename_changed), NULL); } @@ -429,18 +410,12 @@ nm_ifcfg_connection_new (NMConnection *source, NMConnection *tmp; char *unhandled_spec = NULL; const char *unmanaged_spec = NULL, *unrecognized_spec = NULL; - gboolean update_unsaved = TRUE; g_assert (source || full_path); if (out_ignore_error) *out_ignore_error = FALSE; - if (full_path) { - /* The connection already is on the disk */ - update_unsaved = FALSE; - } - /* If we're given a connection already, prefer that instead of re-reading */ if (source) tmp = g_object_ref (source); @@ -464,11 +439,14 @@ nm_ifcfg_connection_new (NMConnection *source, NM_IFCFG_CONNECTION_UNRECOGNIZED_SPEC, unrecognized_spec, NULL); /* Update our settings with what was read from the file */ - if (nm_settings_connection_replace_settings (NM_SETTINGS_CONNECTION (object), - tmp, - update_unsaved, - NULL, - error)) + if (nm_settings_connection_update (NM_SETTINGS_CONNECTION (object), + tmp, + full_path + ? NM_SETTINGS_CONNECTION_PERSIST_MODE_KEEP /* connection is already on disk */ + : NM_SETTINGS_CONNECTION_PERSIST_MODE_UNSAVED, + NM_SETTINGS_CONNECTION_COMMIT_REASON_NONE, + NULL, + error)) nm_ifcfg_connection_check_devtimeout (NM_IFCFG_CONNECTION (object)); else g_clear_object (&object); 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 da0920ef..04e74bbd 100644 --- a/src/settings/plugins/ifcfg-rh/nms-ifcfg-rh-plugin.c +++ b/src/settings/plugins/ifcfg-rh/nms-ifcfg-rh-plugin.c @@ -313,11 +313,12 @@ update_connection (SettingsPluginIfcfg *self, NM_IFCFG_CONNECTION_UNRECOGNIZED_SPEC, new_unrecognized, NULL); - if (!nm_settings_connection_replace_settings (NM_SETTINGS_CONNECTION (connection_by_uuid), - NM_CONNECTION (connection_new), - FALSE, /* don't set Unsaved */ - "ifcfg-update", - &local)) { + if (!nm_settings_connection_update (NM_SETTINGS_CONNECTION (connection_by_uuid), + NM_CONNECTION (connection_new), + NM_SETTINGS_CONNECTION_PERSIST_MODE_KEEP, + NM_SETTINGS_CONNECTION_COMMIT_REASON_NONE, + "ifcfg-update", + &local)) { /* Shouldn't ever get here as 'connection_new' was verified by the reader already * and the UUID did not change. */ g_assert_not_reached (); @@ -1079,5 +1080,5 @@ settings_plugin_interface_init (NMSettingsPluginInterface *plugin_iface) G_MODULE_EXPORT GObject * nm_settings_plugin_factory (void) { - return g_object_ref (settings_plugin_ifcfg_get ()); + return G_OBJECT (g_object_ref (settings_plugin_ifcfg_get ())); } 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 66add713..b9900eec 100644 --- a/src/settings/plugins/ifcfg-rh/nms-ifcfg-rh-reader.c +++ b/src/settings/plugins/ifcfg-rh/nms-ifcfg-rh-reader.c @@ -15,7 +15,7 @@ * with this program; if not, write to the Free Software Foundation, Inc., * 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA. * - * Copyright 2008 - 2015 Red Hat, Inc. + * Copyright 2008 - 2017 Red Hat, Inc. */ #include "nm-default.h" @@ -77,18 +77,6 @@ /*****************************************************************************/ -static gboolean -get_uint (const char *str, guint32 *value) -{ - gint64 tmp; - - tmp = _nm_utils_ascii_str_to_int64 (str, 0, 0, G_MAXUINT32, -1); - if (tmp == -1) - return FALSE; - *value = tmp; - return TRUE; -} - static void check_if_bond_slave (shvarFile *ifcfg, NMSettingConnection *s_con) @@ -512,13 +500,13 @@ typedef struct { bool int_base_16:1; - /* the type, one of PARSE_LINE_TYPE_* */ - char type; - /* whether the command line option was found, and @v is * initialized. */ bool has:1; + /* the type, one of PARSE_LINE_TYPE_* */ + char type; + union { guint8 uint8; guint32 uint32; @@ -541,6 +529,7 @@ enum { PARSE_LINE_ATTR_ROUTE_SRC, PARSE_LINE_ATTR_ROUTE_FROM, PARSE_LINE_ATTR_ROUTE_TOS, + PARSE_LINE_ATTR_ROUTE_ONLINK, PARSE_LINE_ATTR_ROUTE_WINDOW, PARSE_LINE_ATTR_ROUTE_CWND, PARSE_LINE_ATTR_ROUTE_INITCWND, @@ -562,6 +551,7 @@ enum { #define PARSE_LINE_TYPE_ADDR 'a' #define PARSE_LINE_TYPE_ADDR_WITH_PREFIX 'p' #define PARSE_LINE_TYPE_IFNAME 'i' +#define PARSE_LINE_TYPE_FLAG 'f' /** * parse_route_line: @@ -601,42 +591,45 @@ parse_route_line (const char *line, char buf1[256]; char buf2[256]; ParseLineInfo infos[] = { - [PARSE_LINE_ATTR_ROUTE_TABLE] = { .key = NM_IP_ROUTE_ATTRIBUTE_TABLE, - .type = PARSE_LINE_TYPE_UINT32, }, - [PARSE_LINE_ATTR_ROUTE_SRC] = { .key = NM_IP_ROUTE_ATTRIBUTE_SRC, - .type = PARSE_LINE_TYPE_ADDR, }, - [PARSE_LINE_ATTR_ROUTE_FROM] = { .key = NM_IP_ROUTE_ATTRIBUTE_FROM, - .type = PARSE_LINE_TYPE_ADDR_WITH_PREFIX, - .disabled = (addr_family != AF_INET6), }, - [PARSE_LINE_ATTR_ROUTE_TOS] = { .key = NM_IP_ROUTE_ATTRIBUTE_TOS, - .type = PARSE_LINE_TYPE_UINT8, - .int_base_16 = TRUE, - .ignore = (addr_family != AF_INET), }, - [PARSE_LINE_ATTR_ROUTE_WINDOW] = { .key = NM_IP_ROUTE_ATTRIBUTE_WINDOW, - .type = PARSE_LINE_TYPE_UINT32_WITH_LOCK, }, - [PARSE_LINE_ATTR_ROUTE_CWND] = { .key = NM_IP_ROUTE_ATTRIBUTE_CWND, - .type = PARSE_LINE_TYPE_UINT32_WITH_LOCK, }, - [PARSE_LINE_ATTR_ROUTE_INITCWND] = { .key = NM_IP_ROUTE_ATTRIBUTE_INITCWND, - .type = PARSE_LINE_TYPE_UINT32_WITH_LOCK, }, - [PARSE_LINE_ATTR_ROUTE_INITRWND] = { .key = NM_IP_ROUTE_ATTRIBUTE_INITRWND, - .type = PARSE_LINE_TYPE_UINT32_WITH_LOCK, }, - [PARSE_LINE_ATTR_ROUTE_MTU] = { .key = NM_IP_ROUTE_ATTRIBUTE_MTU, - .type = PARSE_LINE_TYPE_UINT32_WITH_LOCK, }, - - [PARSE_LINE_ATTR_ROUTE_TO] = { .key = "to", - .type = PARSE_LINE_TYPE_ADDR_WITH_PREFIX, - .disabled = (options_route != NULL), }, - [PARSE_LINE_ATTR_ROUTE_VIA] = { .key = "via", - .type = PARSE_LINE_TYPE_ADDR, - .disabled = (options_route != NULL), }, - [PARSE_LINE_ATTR_ROUTE_METRIC] = { .key = "metric", - .type = PARSE_LINE_TYPE_UINT32, - .disabled = (options_route != NULL), }, - - [PARSE_LINE_ATTR_ROUTE_DEV] = { .key = "dev", - .type = PARSE_LINE_TYPE_IFNAME, - .ignore = TRUE, - .disabled = (options_route != NULL), }, + [PARSE_LINE_ATTR_ROUTE_TABLE] = { .key = NM_IP_ROUTE_ATTRIBUTE_TABLE, + .type = PARSE_LINE_TYPE_UINT32, }, + [PARSE_LINE_ATTR_ROUTE_SRC] = { .key = NM_IP_ROUTE_ATTRIBUTE_SRC, + .type = PARSE_LINE_TYPE_ADDR, }, + [PARSE_LINE_ATTR_ROUTE_FROM] = { .key = NM_IP_ROUTE_ATTRIBUTE_FROM, + .type = PARSE_LINE_TYPE_ADDR_WITH_PREFIX, + .disabled = (addr_family != AF_INET6), }, + [PARSE_LINE_ATTR_ROUTE_TOS] = { .key = NM_IP_ROUTE_ATTRIBUTE_TOS, + .type = PARSE_LINE_TYPE_UINT8, + .int_base_16 = TRUE, + .ignore = (addr_family != AF_INET), }, + [PARSE_LINE_ATTR_ROUTE_ONLINK] = { .key = NM_IP_ROUTE_ATTRIBUTE_ONLINK, + .type = PARSE_LINE_TYPE_FLAG, + .ignore = (addr_family != AF_INET), }, + [PARSE_LINE_ATTR_ROUTE_WINDOW] = { .key = NM_IP_ROUTE_ATTRIBUTE_WINDOW, + .type = PARSE_LINE_TYPE_UINT32_WITH_LOCK, }, + [PARSE_LINE_ATTR_ROUTE_CWND] = { .key = NM_IP_ROUTE_ATTRIBUTE_CWND, + .type = PARSE_LINE_TYPE_UINT32_WITH_LOCK, }, + [PARSE_LINE_ATTR_ROUTE_INITCWND] = { .key = NM_IP_ROUTE_ATTRIBUTE_INITCWND, + .type = PARSE_LINE_TYPE_UINT32_WITH_LOCK, }, + [PARSE_LINE_ATTR_ROUTE_INITRWND] = { .key = NM_IP_ROUTE_ATTRIBUTE_INITRWND, + .type = PARSE_LINE_TYPE_UINT32_WITH_LOCK, }, + [PARSE_LINE_ATTR_ROUTE_MTU] = { .key = NM_IP_ROUTE_ATTRIBUTE_MTU, + .type = PARSE_LINE_TYPE_UINT32_WITH_LOCK, }, + + [PARSE_LINE_ATTR_ROUTE_TO] = { .key = "to", + .type = PARSE_LINE_TYPE_ADDR_WITH_PREFIX, + .disabled = (options_route != NULL), }, + [PARSE_LINE_ATTR_ROUTE_VIA] = { .key = "via", + .type = PARSE_LINE_TYPE_ADDR, + .disabled = (options_route != NULL), }, + [PARSE_LINE_ATTR_ROUTE_METRIC] = { .key = "metric", + .type = PARSE_LINE_TYPE_UINT32, + .disabled = (options_route != NULL), }, + + [PARSE_LINE_ATTR_ROUTE_DEV] = { .key = "dev", + .type = PARSE_LINE_TYPE_IFNAME, + .ignore = TRUE, + .disabled = (options_route != NULL), }, }; nm_assert (line); @@ -705,6 +698,9 @@ parse_route_line (const char *line, case PARSE_LINE_TYPE_IFNAME: i_words++; goto parse_line_type_ifname; + case PARSE_LINE_TYPE_FLAG: + i_words++; + goto next; default: nm_assert_not_reached (); } @@ -913,6 +909,15 @@ next: ? nm_sprintf_buf (buf2, "/%u", (unsigned) info->v.addr.plen) : "")); break; + case PARSE_LINE_TYPE_FLAG: + /* 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. */ + nm_ip_route_set_attribute (route, + info->key, + g_variant_new_boolean (TRUE)); + break; default: nm_assert_not_reached (); break; @@ -1141,7 +1146,7 @@ error: } static NMSetting * -make_user_setting (shvarFile *ifcfg, GError **error) +make_user_setting (shvarFile *ifcfg) { gboolean has_user_data = FALSE; gs_unref_object NMSettingUser *s_user = NULL; @@ -1189,7 +1194,7 @@ make_user_setting (shvarFile *ifcfg, GError **error) } static NMSetting * -make_proxy_setting (shvarFile *ifcfg, GError **error) +make_proxy_setting (shvarFile *ifcfg) { NMSettingProxy *s_proxy = NULL; gs_free char *value = NULL; @@ -1239,7 +1244,7 @@ make_proxy_setting (shvarFile *ifcfg, GError **error) static NMSetting * make_ip4_setting (shvarFile *ifcfg, - const char *network_file, + shvarFile *network_ifcfg, gboolean routes_read, gboolean *out_has_defroute, GError **error) @@ -1255,7 +1260,6 @@ make_ip4_setting (shvarFile *ifcfg, int i; guint32 a; gboolean has_key; - shvarFile *network_ifcfg; shvarFile *route_ifcfg; gboolean never_default; gint64 timeout; @@ -1282,7 +1286,6 @@ make_ip4_setting (shvarFile *ifcfg, } /* Then check if GATEWAYDEV; it's global and overrides DEFROUTE */ - network_ifcfg = svOpenFile (network_file, NULL); if (network_ifcfg) { gs_free char *gatewaydev_value = NULL; const char *gatewaydev; @@ -1299,7 +1302,6 @@ make_ip4_setting (shvarFile *ifcfg, never_default = !!strcmp (v, gatewaydev); nm_clear_g_free (&value); - svCloseFile (network_ifcfg); } v = svGetValueStr (ifcfg, "BOOTPROTO", &value); @@ -1424,12 +1426,10 @@ make_ip4_setting (shvarFile *ifcfg, /* Gateway */ if (!gateway) { - network_ifcfg = svOpenFile (network_file, NULL); if (network_ifcfg) { gboolean read_success; read_success = read_ip4_address (network_ifcfg, "GATEWAY", &has_key, &a, error); - svCloseFile (network_ifcfg); if (!read_success) return NULL; if (has_key) { @@ -1665,16 +1665,15 @@ read_aliases (NMSettingIPConfig *s_ip4, gboolean read_defroute, const char *file static NMSetting * make_ip6_setting (shvarFile *ifcfg, - const char *network_file, + shvarFile *network_ifcfg, gboolean routes_read, GError **error) { NMSettingIPConfig *s_ip6 = NULL; + const char *v; char *value = NULL; char *str_value; char *route6_path = NULL; - gs_free char *dns_options_free = NULL; - const char *dns_options = NULL; gboolean ipv6init, ipv6forwarding, dhcp6 = FALSE; char *method = NM_SETTING_IP6_CONFIG_METHOD_MANUAL; char *ipv6addr, *ipv6addr_secondaries; @@ -1684,7 +1683,6 @@ make_ip6_setting (shvarFile *ifcfg, int i_val; GError *local = NULL; gint priority; - shvarFile *network_ifcfg; gboolean never_default = FALSE; gboolean ip6_privacy = FALSE, ip6_privacy_prefer_public_ip; NMSettingIP6ConfigPrivacy ip6_privacy_val; @@ -1703,7 +1701,6 @@ make_ip6_setting (shvarFile *ifcfg, * they are global and override IPV6_DEFROUTE * When both are set, the device specified in IPV6_DEFAULTGW takes preference. */ - network_ifcfg = svOpenFile (network_file, NULL); if (network_ifcfg) { char *ipv6_defaultgw, *ipv6_defaultdev; char *default_dev = NULL; @@ -1712,7 +1709,6 @@ make_ip6_setting (shvarFile *ifcfg, value = svGetValueStr_cp (ifcfg, "DEVICE"); ipv6_defaultgw = svGetValueStr_cp (network_ifcfg, "IPV6_DEFAULTGW"); ipv6_defaultdev = svGetValueStr_cp (network_ifcfg, "IPV6_DEFAULTDEV"); - dns_options = svGetValue (network_ifcfg, "RES_OPTIONS", &dns_options_free); if (ipv6_defaultgw) { default_dev = strchr (ipv6_defaultgw, '%'); @@ -1731,7 +1727,6 @@ make_ip6_setting (shvarFile *ifcfg, g_free (ipv6_defaultgw); g_free (ipv6_defaultdev); g_free (value); - svCloseFile (network_ifcfg); } /* Find out method property */ @@ -1739,11 +1734,8 @@ make_ip6_setting (shvarFile *ifcfg, str_value = svGetValueStr_cp (ifcfg, "IPV6INIT"); ipv6init = svGetValueBoolean (ifcfg, "IPV6INIT", FALSE); if (!str_value) { - network_ifcfg = svOpenFile (network_file, NULL); - if (network_ifcfg) { + if (network_ifcfg) ipv6init = svGetValueBoolean (network_ifcfg, "IPV6INIT", FALSE); - svCloseFile (network_ifcfg); - } } g_free (str_value); @@ -1865,11 +1857,8 @@ make_ip6_setting (shvarFile *ifcfg, value = svGetValueStr_cp (ifcfg, "IPV6_DEFAULTGW"); if (!value) { /* If no gateway in the ifcfg, try global /etc/sysconfig/network instead */ - network_ifcfg = svOpenFile (network_file, NULL); - if (network_ifcfg) { + if (network_ifcfg) value = svGetValueStr_cp (network_ifcfg, "IPV6_DEFAULTGW"); - svCloseFile (network_ifcfg); - } } if (value) { char *ptr; @@ -1930,8 +1919,6 @@ make_ip6_setting (shvarFile *ifcfg, g_free (value); } - /* DNS searches ('DOMAIN' key) are read by make_ip4_setting() and included in NMSettingIPConfig */ - if (!routes_read) { /* NOP */ } else { @@ -1942,9 +1929,24 @@ make_ip6_setting (shvarFile *ifcfg, g_free (route6_path); } + /* DNS searches */ + nm_clear_g_free (&value); + v = svGetValueStr (ifcfg, "IPV6_DOMAIN", &value); + if (v) { + gs_free const char **searches = NULL; + + searches = nm_utils_strsplit_set (v, " "); + if (searches) { + for (iter = searches; *iter; iter++) { + if (!nm_setting_ip_config_add_dns_search (s_ip6, *iter)) + PARSE_WARNING ("duplicate DNS domain '%s'", *iter); + } + } + } + /* DNS options */ - parse_dns_options (s_ip6, svGetValue (ifcfg, "RES_OPTIONS", &value)); - parse_dns_options (s_ip6, dns_options); + nm_clear_g_free (&value); + parse_dns_options (s_ip6, svGetValue (ifcfg, "IPV6_RES_OPTIONS", &value)); g_free (value); /* DNS priority */ @@ -1962,6 +1964,59 @@ error: return NULL; } +static NMSetting * +make_tc_setting (shvarFile *ifcfg) +{ + NMSettingTCConfig *s_tc = NULL; + char tag[256]; + int i; + + s_tc = (NMSettingTCConfig *) nm_setting_tc_config_new (); + + for (i = 1;; i++) { + NMTCQdisc *qdisc = NULL; + gs_free char *value_to_free = NULL; + const char *value = NULL; + GError *local = NULL; + + value = svGetValueStr (ifcfg, numbered_tag (tag, "QDISC", i), &value_to_free); + if (!value) + break; + + qdisc = nm_utils_tc_qdisc_from_str (value, &local); + 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 qdisc"); + } + + for (i = 1;; i++) { + NMTCTfilter *tfilter = NULL; + gs_free char *value_to_free = NULL; + const char *value = NULL; + GError *local = NULL; + + value = svGetValueStr (ifcfg, numbered_tag (tag, "FILTER", i), &value_to_free); + if (!value) + break; + + tfilter = nm_utils_tc_tfilter_from_str (value, &local); + 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 filter"); + } + + if ( nm_setting_tc_config_get_num_qdiscs (s_tc) > 0 + || nm_setting_tc_config_get_num_tfilters (s_tc) > 0) + return NM_SETTING (s_tc); + + g_object_unref (s_tc); + return NULL; +} + typedef struct { const char *enable_key; const char *advertise_key; @@ -2195,7 +2250,6 @@ read_dcb_percent_array (shvarFile *ifcfg, static gboolean make_dcb_setting (shvarFile *ifcfg, - const char *network_file, NMSetting **out_setting, GError **error) { @@ -2350,54 +2404,39 @@ add_one_wep_key (shvarFile *ifcfg, NMSettingWirelessSecurity *s_wsec, GError **error) { - char *key = NULL; - char *value = NULL; - gboolean success = FALSE; + gs_free char *value_free = NULL; + const char *value; + const char *key = NULL; g_return_val_if_fail (ifcfg != NULL, FALSE); g_return_val_if_fail (shvar_key != NULL, FALSE); g_return_val_if_fail (key_idx <= 3, FALSE); g_return_val_if_fail (s_wsec != NULL, FALSE); - value = svGetValueStr_cp (ifcfg, shvar_key); + value = svGetValueStr (ifcfg, shvar_key, &value_free); if (!value) return TRUE; /* Validate keys */ if (passphrase) { - if (strlen (value) && strlen (value) < 64) { - key = g_strdup (value); - g_object_set (G_OBJECT (s_wsec), - NM_SETTING_WIRELESS_SECURITY_WEP_KEY_TYPE, - NM_WEP_KEY_TYPE_PASSPHRASE, - NULL); - } + if (value[0] && strlen (value) < 64) + key = value; } else { - if (strlen (value) == 10 || strlen (value) == 26) { + if (NM_IN_SET (strlen (value), 10, 26)) { /* Hexadecimal WEP key */ - char *p = value; - - while (*p) { - if (!g_ascii_isxdigit (*p)) { - g_set_error (error, NM_SETTINGS_ERROR, NM_SETTINGS_ERROR_INVALID_CONNECTION, - "Invalid hexadecimal WEP key."); - goto out; - } - p++; + if (NM_STRCHAR_ANY (value, ch, !g_ascii_isxdigit (ch))) { + g_set_error (error, NM_SETTINGS_ERROR, NM_SETTINGS_ERROR_INVALID_CONNECTION, + "Invalid hexadecimal WEP key."); + return FALSE; } - key = g_strdup (value); + key = value; } else if ( !strncmp (value, "s:", 2) - && (strlen (value) == 7 || strlen (value) == 15)) { + && NM_IN_SET (strlen (value), 7, 15)) { /* ASCII key */ - char *p = value + 2; - - while (*p) { - if (!g_ascii_isprint ((int) (*p))) { - g_set_error (error, NM_SETTINGS_ERROR, NM_SETTINGS_ERROR_INVALID_CONNECTION, - "Invalid ASCII WEP key."); - goto out; - } - p++; + if (NM_STRCHAR_ANY (value + 2, ch, !g_ascii_isprint (ch))) { + g_set_error (error, NM_SETTINGS_ERROR, NM_SETTINGS_ERROR_INVALID_CONNECTION, + "Invalid ASCII WEP key."); + return FALSE; } /* Remove 's:' prefix. @@ -2406,51 +2445,50 @@ add_one_wep_key (shvarFile *ifcfg, * before passing to wpa_supplicant, this prevents two unnecessary conversions. And mainly, * ASCII WEP key doesn't change to HEX WEP key in UI, which could confuse users. */ - key = g_strdup (value + 2); + key = value + 2; } } - if (key) { - nm_setting_wireless_security_set_wep_key (s_wsec, key_idx, key); - g_free (key); - success = TRUE; - } else { + if (!key) { g_set_error (error, NM_SETTINGS_ERROR, NM_SETTINGS_ERROR_INVALID_CONNECTION, "Invalid WEP key length."); + return FALSE; } -out: - g_free (value); - return success; + nm_setting_wireless_security_set_wep_key (s_wsec, key_idx, key); + return TRUE; } static gboolean read_wep_keys (shvarFile *ifcfg, + NMWepKeyType key_type, guint8 def_idx, NMSettingWirelessSecurity *s_wsec, GError **error) { - /* Try hex/ascii keys first */ - if (!add_one_wep_key (ifcfg, "KEY1", 0, FALSE, s_wsec, error)) - return FALSE; - if (!add_one_wep_key (ifcfg, "KEY2", 1, FALSE, s_wsec, error)) - return FALSE; - if (!add_one_wep_key (ifcfg, "KEY3", 2, FALSE, s_wsec, error)) - return FALSE; - if (!add_one_wep_key (ifcfg, "KEY4", 3, FALSE, s_wsec, error)) - return FALSE; - if (!add_one_wep_key (ifcfg, "KEY", def_idx, FALSE, s_wsec, error)) - return FALSE; + if (key_type != NM_WEP_KEY_TYPE_PASSPHRASE) { + if (!add_one_wep_key (ifcfg, "KEY1", 0, FALSE, s_wsec, error)) + return FALSE; + if (!add_one_wep_key (ifcfg, "KEY2", 1, FALSE, s_wsec, error)) + return FALSE; + if (!add_one_wep_key (ifcfg, "KEY3", 2, FALSE, s_wsec, error)) + return FALSE; + if (!add_one_wep_key (ifcfg, "KEY4", 3, FALSE, s_wsec, error)) + return FALSE; + if (!add_one_wep_key (ifcfg, "KEY", def_idx, FALSE, s_wsec, error)) + return FALSE; + } - /* And then passphrases */ - if (!add_one_wep_key (ifcfg, "KEY_PASSPHRASE1", 0, TRUE, s_wsec, error)) - return FALSE; - if (!add_one_wep_key (ifcfg, "KEY_PASSPHRASE2", 1, TRUE, s_wsec, error)) - return FALSE; - if (!add_one_wep_key (ifcfg, "KEY_PASSPHRASE3", 2, TRUE, s_wsec, error)) - return FALSE; - if (!add_one_wep_key (ifcfg, "KEY_PASSPHRASE4", 3, TRUE, s_wsec, error)) - return FALSE; + if (key_type != NM_WEP_KEY_TYPE_KEY) { + if (!add_one_wep_key (ifcfg, "KEY_PASSPHRASE1", 0, TRUE, s_wsec, error)) + return FALSE; + if (!add_one_wep_key (ifcfg, "KEY_PASSPHRASE2", 1, TRUE, s_wsec, error)) + return FALSE; + if (!add_one_wep_key (ifcfg, "KEY_PASSPHRASE3", 2, TRUE, s_wsec, error)) + return FALSE; + if (!add_one_wep_key (ifcfg, "KEY_PASSPHRASE4", 3, TRUE, s_wsec, error)) + return FALSE; + } return TRUE; } @@ -2515,19 +2553,40 @@ make_wep_setting (shvarFile *ifcfg, /* Read keys in the ifcfg file if they are system-owned */ if (key_flags == NM_SETTING_SECRET_FLAG_NONE) { - if (!read_wep_keys (ifcfg, default_key_idx, s_wsec, error)) + NMWepKeyType key_type; + const char *v; + gs_free char *to_free = NULL; + + v = svGetValueStr (ifcfg, "KEY_TYPE", &to_free); + if (!v) + key_type = NM_WEP_KEY_TYPE_UNKNOWN; + else if (nm_streq (v, "key")) + key_type = NM_WEP_KEY_TYPE_KEY; + else if (nm_streq (v, "passphrase")) + key_type = NM_WEP_KEY_TYPE_PASSPHRASE; + else { + g_set_error (error, NM_SETTINGS_ERROR, NM_SETTINGS_ERROR_INVALID_CONNECTION, + "Invalid KEY_TYPE value '%s'", v); + return FALSE; + } + + if (!read_wep_keys (ifcfg, key_type, default_key_idx, s_wsec, error)) return NULL; /* Try to get keys from the "shadow" key file */ keys_ifcfg = utils_get_keys_ifcfg (file, FALSE); if (keys_ifcfg) { - if (!read_wep_keys (keys_ifcfg, default_key_idx, s_wsec, error)) { + if (!read_wep_keys (keys_ifcfg, key_type, default_key_idx, s_wsec, error)) { svCloseFile (keys_ifcfg); return NULL; } svCloseFile (keys_ifcfg); g_assert (error == NULL || *error == NULL); } + + g_object_set (G_OBJECT (s_wsec), + NM_SETTING_WIRELESS_SECURITY_WEP_KEY_TYPE, key_type, + NULL); } value = svGetValueStr_cp (ifcfg, "SECURITYMODE"); @@ -3577,25 +3636,25 @@ make_wireless_security_setting (shvarFile *ifcfg, return NULL; /* unencrypted */ } -static char ** +static const char ** transform_hwaddr_blacklist (const char *blacklist) { - char **strv, **iter; - int shift = 0; - - strv = _nm_utils_strsplit_set (blacklist, " \t", 0); - for (iter = strv; iter && *iter; iter++) { - if (shift) { - *(iter - shift) = *iter; - *iter = NULL; - } - if (!nm_utils_hwaddr_valid (*(iter - shift), ETH_ALEN)) { - PARSE_WARNING ("invalid MAC in HWADDR_BLACKLIST '%s'", *(iter - shift)); - g_free (*(iter - shift)); - *(iter - shift) = NULL; - shift++; + const char **strv; + gsize i, j; + + strv = nm_utils_strsplit_set (blacklist, " \t"); + if (!strv) + return NULL; + for (i = 0, j = 0; strv[j]; j++) { + const char *s = strv[j]; + + if (!nm_utils_hwaddr_valid (s, ETH_ALEN)) { + PARSE_WARNING ("invalid MAC in HWADDR_BLACKLIST '%s'", s); + continue; } + strv[i++] = s; } + strv[i] = NULL; return strv; } @@ -3630,13 +3689,12 @@ make_wireless_setting (shvarFile *ifcfg, g_object_set (s_wireless, NM_SETTING_WIRELESS_GENERATE_MAC_ADDRESS_MASK, value, NULL); g_free (value); - value = svGetValueStr_cp (ifcfg, "HWADDR_BLACKLIST"); - if (value) { - char **strv; + cvalue = svGetValueStr (ifcfg, "HWADDR_BLACKLIST", &value); + if (cvalue) { + gs_free const char **strv = NULL; - strv = transform_hwaddr_blacklist (value); + strv = transform_hwaddr_blacklist (cvalue); g_object_set (s_wireless, NM_SETTING_WIRELESS_MAC_ADDRESS_BLACKLIST, strv, NULL); - g_strfreev (strv); g_free (value); } @@ -4096,6 +4154,7 @@ make_wired_setting (shvarFile *ifcfg, GError **error) { gs_unref_object NMSettingWired *s_wired = NULL; + const char *cvalue; gs_free char *value = NULL; char *nettype; @@ -4204,11 +4263,11 @@ make_wired_setting (shvarFile *ifcfg, NULL); nm_clear_g_free (&value); - value = svGetValueStr_cp (ifcfg, "HWADDR_BLACKLIST"); - if (value) { - gs_strfreev char **strv = NULL; + cvalue = svGetValueStr (ifcfg, "HWADDR_BLACKLIST", &value); + if (cvalue) { + gs_free const char **strv = NULL; - strv = transform_hwaddr_blacklist (value); + strv = transform_hwaddr_blacklist (cvalue); g_object_set (s_wired, NM_SETTING_WIRED_MAC_ADDRESS_BLACKLIST, strv, NULL); nm_clear_g_free (&value); } @@ -4633,66 +4692,114 @@ team_connection_from_ifcfg (const char *file, return connection; } +typedef enum { + BRIDGE_OPT_TYPE_MAIN, + BRIDGE_OPT_TYPE_OPTION, + BRIDGE_OPT_TYPE_PORT_MAIN, + BRIDGE_OPT_TYPE_PORT_OPTION, +} BridgeOptType; + typedef void (*BridgeOptFunc) (NMSetting *setting, gboolean stp, const char *key, - const char *value); + const char *value, + BridgeOptType opt_type); static void handle_bridge_option (NMSetting *setting, gboolean stp, const char *key, - const char *value) + const char *value, + BridgeOptType opt_type) { - guint32 u = 0; + static const struct { + const char *key; + const char *property_name; + BridgeOptType opt_type; + gboolean only_with_stp; + gboolean extended_bool; + } m/*etadata*/[] = { + { "DELAY", NM_SETTING_BRIDGE_FORWARD_DELAY, BRIDGE_OPT_TYPE_MAIN, .only_with_stp = TRUE }, + { "priority", NM_SETTING_BRIDGE_PRIORITY, BRIDGE_OPT_TYPE_OPTION, .only_with_stp = TRUE }, + { "hello_time", NM_SETTING_BRIDGE_HELLO_TIME, BRIDGE_OPT_TYPE_OPTION, .only_with_stp = TRUE }, + { "max_age", NM_SETTING_BRIDGE_MAX_AGE, BRIDGE_OPT_TYPE_OPTION, .only_with_stp = TRUE }, + { "ageing_time", NM_SETTING_BRIDGE_AGEING_TIME, BRIDGE_OPT_TYPE_OPTION }, + { "multicast_snooping", NM_SETTING_BRIDGE_MULTICAST_SNOOPING, BRIDGE_OPT_TYPE_OPTION }, + { "group_fwd_mask", NM_SETTING_BRIDGE_GROUP_FORWARD_MASK, BRIDGE_OPT_TYPE_OPTION }, + { "priority", NM_SETTING_BRIDGE_PORT_PRIORITY, BRIDGE_OPT_TYPE_PORT_OPTION }, + { "path_cost", NM_SETTING_BRIDGE_PORT_PATH_COST, BRIDGE_OPT_TYPE_PORT_OPTION }, + { "hairpin_mode", NM_SETTING_BRIDGE_PORT_HAIRPIN_MODE, BRIDGE_OPT_TYPE_PORT_OPTION, .extended_bool = TRUE, }, + }; + const char *error_message = NULL; + int i; + gint64 v; - if (!strcmp (key, "priority")) { - if (stp == FALSE) - PARSE_WARNING ("'priority' invalid when STP is disabled"); - else if (get_uint (value, &u)) - g_object_set (setting, NM_SETTING_BRIDGE_PRIORITY, u, NULL); - else - PARSE_WARNING ("invalid priority value '%s'", value); - } else if (!strcmp (key, "hello_time")) { - if (stp == FALSE) - PARSE_WARNING ("'hello_time' invalid when STP is disabled"); - else if (get_uint (value, &u)) - g_object_set (setting, NM_SETTING_BRIDGE_HELLO_TIME, u, NULL); - else - PARSE_WARNING ("invalid hello_time value '%s'", value); - } else if (!strcmp (key, "max_age")) { - if (stp == FALSE) - PARSE_WARNING ("'max_age' invalid when STP is disabled"); - else if (get_uint (value, &u)) - g_object_set (setting, NM_SETTING_BRIDGE_MAX_AGE, u, NULL); - else - PARSE_WARNING ("invalid max_age value '%s'", value); - } else if (!strcmp (key, "ageing_time")) { - if (get_uint (value, &u)) - g_object_set (setting, NM_SETTING_BRIDGE_AGEING_TIME, u, NULL); - else - PARSE_WARNING ("invalid ageing_time value '%s'", value); - } else if (!strcmp (key, "multicast_snooping")) { - if (get_uint (value, &u)) - g_object_set (setting, NM_SETTING_BRIDGE_MULTICAST_SNOOPING, - (gboolean) u, NULL); - else - PARSE_WARNING ("invalid multicast_snooping value '%s'", value); - } else if (!strcmp (key, "group_fwd_mask")) { - if (get_uint (value, &u) && u <= 0xFFFF && !NM_FLAGS_ANY (u, 7)) - g_object_set (setting, NM_SETTING_BRIDGE_GROUP_FORWARD_MASK, - (gboolean) u, NULL); - else - PARSE_WARNING ("invalid group_fwd_mask value '%s'", value); - } else - PARSE_WARNING ("unhandled bridge option '%s'", key); + for (i = 0; i < G_N_ELEMENTS (m); i++) { + GParamSpec *param_spec; + + if (opt_type != m[i].opt_type) + continue; + if (!nm_streq (key, m[i].key)) + continue; + if (m[i].only_with_stp && !stp) { + PARSE_WARNING ("'%s' invalid when STP is disabled", key); + return; + } + + param_spec = g_object_class_find_property (G_OBJECT_GET_CLASS (setting), m[i].property_name); + switch (param_spec->value_type) { + case G_TYPE_BOOLEAN: + if (m[i].extended_bool) { + if (!strcasecmp (value, "on") || !strcasecmp (value, "yes") || !strcmp (value, "1")) + v = TRUE; + else if (!strcasecmp (value, "off") || !strcasecmp (value, "no")) + v = FALSE; + else { + error_message = "is not a boolean"; + goto warn; + } + } else { + v = _nm_utils_ascii_str_to_int64 (value, 10, 0, 1, -1); + if (v == -1) { + error_message = g_strerror (errno); + goto warn; + } + } + if (!nm_g_object_set_property_boolean (G_OBJECT (setting), m[i].property_name, v, NULL)) { + error_message = "number is out of range"; + goto warn; + } + return; + case G_TYPE_UINT: + v = _nm_utils_ascii_str_to_int64 (value, 10, 0, G_MAXUINT, -1); + if (v == -1) { + error_message = g_strerror (errno); + goto warn; + } + if (!nm_g_object_set_property_uint (G_OBJECT (setting), m[i].property_name, v, NULL)) { + error_message = "number is out of range"; + goto warn; + } + return; + default: + nm_assert_not_reached (); + continue; + } + +warn: + PARSE_WARNING ("invalid %s value '%s': %s", key, value, error_message); + return; + } + + PARSE_WARNING ("unhandled bridge option '%s'", key); } static void handle_bridging_opts (NMSetting *setting, gboolean stp, const char *value, - BridgeOptFunc func) + BridgeOptFunc func, + BridgeOptType opt_type) { gs_free const char **items = NULL; const char *const *iter; @@ -4707,7 +4814,7 @@ handle_bridging_opts (NMSetting *setting, key = *keys; val = *(keys + 1); if (val && key[0] && val[0]) - func (setting, stp, key, val); + func (setting, stp, key, val, opt_type); } } } @@ -4717,30 +4824,29 @@ make_bridge_setting (shvarFile *ifcfg, const char *file, GError **error) { - NMSettingBridge *s_bridge; - char *value; - guint32 u; + gs_unref_object NMSettingBridge *s_bridge = NULL; + gs_free char *value_to_free = NULL; + const char *value; gboolean stp = FALSE; gboolean stp_set = FALSE; - value = svGetValueStr_cp (ifcfg, "DEVICE"); + value = svGetValueStr (ifcfg, "DEVICE", &value_to_free); if (!value) { g_set_error (error, NM_SETTINGS_ERROR, NM_SETTINGS_ERROR_INVALID_CONNECTION, "mandatory DEVICE keyword missing"); return NULL; } - g_free (value); + nm_clear_g_free (&value_to_free); s_bridge = NM_SETTING_BRIDGE (nm_setting_bridge_new ()); - value = svGetValueStr_cp (ifcfg, "MACADDR"); + value = svGetValueStr (ifcfg, "BRIDGE_MACADDR", &value_to_free); if (value) { - value = g_strstrip (value); g_object_set (s_bridge, NM_SETTING_BRIDGE_MAC_ADDRESS, value, NULL); - g_free (value); + nm_clear_g_free (&value_to_free); } - value = svGetValueStr_cp (ifcfg, "STP"); + value = svGetValueStr (ifcfg, "STP", &value_to_free); if (value) { if (!strcasecmp (value, "on") || !strcasecmp (value, "yes")) { g_object_set (s_bridge, NM_SETTING_BRIDGE_STP, TRUE, NULL); @@ -4751,7 +4857,7 @@ make_bridge_setting (shvarFile *ifcfg, stp_set = TRUE; } else PARSE_WARNING ("invalid STP value '%s'", value); - g_free (value); + nm_clear_g_free (&value_to_free); } if (!stp_set) { @@ -4759,25 +4865,19 @@ make_bridge_setting (shvarFile *ifcfg, g_object_set (s_bridge, NM_SETTING_BRIDGE_STP, FALSE, NULL); } - value = svGetValueStr_cp (ifcfg, "DELAY"); + value = svGetValueStr (ifcfg, "DELAY", &value_to_free); if (value) { - if (stp) { - if (get_uint (value, &u)) - g_object_set (s_bridge, NM_SETTING_BRIDGE_FORWARD_DELAY, u, NULL); - else - PARSE_WARNING ("invalid forward delay value '%s'", value); - } else - PARSE_WARNING ("DELAY invalid when STP is disabled"); - g_free (value); + handle_bridge_option (NM_SETTING (s_bridge), stp, "DELAY", value, BRIDGE_OPT_TYPE_MAIN); + nm_clear_g_free (&value_to_free); } - value = svGetValueStr_cp (ifcfg, "BRIDGING_OPTS"); + value = svGetValueStr (ifcfg, "BRIDGING_OPTS", &value_to_free); if (value) { - handle_bridging_opts (NM_SETTING (s_bridge), stp, value, handle_bridge_option); - g_free (value); + handle_bridging_opts (NM_SETTING (s_bridge), stp, value, handle_bridge_option, BRIDGE_OPT_TYPE_OPTION); + nm_clear_g_free (&value_to_free); } - return (NMSetting *) s_bridge; + return (NMSetting *) g_steal_pointer (&s_bridge); } static NMConnection * @@ -4788,6 +4888,8 @@ bridge_connection_from_ifcfg (const char *file, NMConnection *connection = NULL; NMSetting *con_setting = NULL; NMSetting *bridge_setting = NULL; + NMSetting *wired_setting = NULL; + NMSetting8021x *s_8021x = NULL; g_return_val_if_fail (file != NULL, NULL); g_return_val_if_fail (ifcfg != NULL, NULL); @@ -4810,57 +4912,40 @@ bridge_connection_from_ifcfg (const char *file, } nm_connection_add_setting (connection, bridge_setting); - return connection; -} + wired_setting = make_wired_setting (ifcfg, file, &s_8021x, error); + if (!wired_setting) { + g_object_unref (connection); + return NULL; + } + nm_connection_add_setting (connection, wired_setting); -static void -handle_bridge_port_option (NMSetting *setting, - gboolean stp, - const char *key, - const char *value) -{ - guint32 u = 0; + if (s_8021x) + nm_connection_add_setting (connection, NM_SETTING (s_8021x)); - if (!strcmp (key, "priority")) { - if (get_uint (value, &u)) - g_object_set (setting, NM_SETTING_BRIDGE_PORT_PRIORITY, u, NULL); - else - PARSE_WARNING ("invalid priority value '%s'", value); - } else if (!strcmp (key, "path_cost")) { - if (get_uint (value, &u)) - g_object_set (setting, NM_SETTING_BRIDGE_PORT_PATH_COST, u, NULL); - else - PARSE_WARNING ("invalid path_cost value '%s'", value); - } else if (!strcmp (key, "hairpin_mode")) { - if (!strcasecmp (value, "on") || !strcasecmp (value, "yes") || !strcmp (value, "1")) - g_object_set (setting, NM_SETTING_BRIDGE_PORT_HAIRPIN_MODE, TRUE, NULL); - else if (!strcasecmp (value, "off") || !strcasecmp (value, "no")) - g_object_set (setting, NM_SETTING_BRIDGE_PORT_HAIRPIN_MODE, FALSE, NULL); - else - PARSE_WARNING ("invalid hairpin_mode value '%s'", value); - } else - PARSE_WARNING ("unhandled bridge port option '%s'", key); + return connection; } static NMSetting * make_bridge_port_setting (shvarFile *ifcfg) { NMSetting *s_port = NULL; - char *value; + gs_free char *value_to_free = NULL; + const char *value; g_return_val_if_fail (ifcfg != NULL, FALSE); - value = svGetValueStr_cp (ifcfg, "BRIDGE_UUID"); + value = svGetValueStr (ifcfg, "BRIDGE_UUID", &value_to_free); if (!value) - value = svGetValueStr_cp (ifcfg, "BRIDGE"); + value = svGetValueStr (ifcfg, "BRIDGE", &value_to_free); if (value) { - g_free (value); + nm_clear_g_free (&value_to_free); s_port = nm_setting_bridge_port_new (); - value = svGetValueStr_cp (ifcfg, "BRIDGING_OPTS"); - if (value) - handle_bridging_opts (s_port, FALSE, value, handle_bridge_port_option); - g_free (value); + value = svGetValueStr (ifcfg, "BRIDGING_OPTS", &value_to_free); + if (value) { + handle_bridging_opts (s_port, FALSE, value, handle_bridge_option, BRIDGE_OPT_TYPE_PORT_OPTION); + nm_clear_g_free (&value_to_free); + } } return s_port; @@ -5206,10 +5291,11 @@ connection_from_file_full (const char *filename, gboolean *out_ignore_error) { nm_auto_shvar_file_close shvarFile *parsed = NULL; + nm_auto_shvar_file_close shvarFile *network_ifcfg = NULL; gs_unref_object NMConnection *connection = NULL; gs_free char *type = NULL; char *devtype, *bootproto; - NMSetting *s_ip4, *s_ip6, *s_proxy, *s_port, *s_dcb = NULL, *s_user; + NMSetting *s_ip4, *s_ip6, *s_tc, *s_proxy, *s_port, *s_dcb = NULL, *s_user; const char *ifcfg_name = NULL; gboolean has_ip4_defroute = FALSE; gboolean has_complex_routes_v4; @@ -5233,6 +5319,8 @@ connection_from_file_full (const char *filename, if (!parsed) return NULL; + network_ifcfg = svOpenFile (network_file, NULL); + if (!svGetValueBoolean (parsed, "NM_CONTROLLED", TRUE)) { connection = create_unhandled_connection (filename, parsed, "unmanaged", out_unhandled); if (!connection) { @@ -5442,7 +5530,7 @@ connection_from_file_full (const char *filename, } s_ip6 = make_ip6_setting (parsed, - network_file, + network_ifcfg, !has_complex_routes_v4 && !has_complex_routes_v6, error); if (!s_ip6) @@ -5451,7 +5539,7 @@ connection_from_file_full (const char *filename, nm_connection_add_setting (connection, s_ip6); s_ip4 = make_ip4_setting (parsed, - network_file, + network_ifcfg, !has_complex_routes_v4 && !has_complex_routes_v6, &has_ip4_defroute, error); @@ -5464,17 +5552,21 @@ connection_from_file_full (const char *filename, nm_connection_add_setting (connection, s_ip4); } - /* There is only one DOMAIN variable and it is read and put to IPv4 config - * But if IPv4 is disabled or the config fails for some reason, we read - * DOMAIN and put the values into IPv6 config instead. + s_tc = make_tc_setting (parsed); + if (s_tc) + nm_connection_add_setting (connection, s_tc); + + /* For backwards compatibility, if IPv4 is disabled or the + * config fails for some reason, we read DOMAIN and put the + * values into IPv6 config instead of IPv4. */ check_dns_search_domains (parsed, s_ip4, s_ip6); - s_proxy = make_proxy_setting (parsed, error); + s_proxy = make_proxy_setting (parsed); if (s_proxy) nm_connection_add_setting (connection, s_proxy); - s_user = make_user_setting (parsed, error); + s_user = make_user_setting (parsed); if (s_user) nm_connection_add_setting (connection, s_user); @@ -5488,7 +5580,7 @@ connection_from_file_full (const char *filename, if (s_port) nm_connection_add_setting (connection, s_port); - if (!make_dcb_setting (parsed, network_file, &s_dcb, error)) + if (!make_dcb_setting (parsed, &s_dcb, error)) return NULL; if (s_dcb) nm_connection_add_setting (connection, s_dcb); diff --git a/src/settings/plugins/ifcfg-rh/nms-ifcfg-rh-utils.c b/src/settings/plugins/ifcfg-rh/nms-ifcfg-rh-utils.c index 6434ad7d..862e640e 100644 --- a/src/settings/plugins/ifcfg-rh/nms-ifcfg-rh-utils.c +++ b/src/settings/plugins/ifcfg-rh/nms-ifcfg-rh-utils.c @@ -15,7 +15,7 @@ * with this program; if not, write to the Free Software Foundation, Inc., * 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA. * - * (C) Copyright 2008 - 2012 Red Hat, Inc. + * (C) Copyright 2008 - 2017 Red Hat, Inc. */ #include "nm-default.h" @@ -243,12 +243,6 @@ utils_get_route_ifcfg (const char *parent, gboolean should_create) return utils_get_extra_ifcfg (parent, ROUTE_TAG, should_create); } -shvarFile * -utils_get_route6_ifcfg (const char *parent, gboolean should_create) -{ - return utils_get_extra_ifcfg (parent, ROUTE6_TAG, should_create); -} - /* Finds out if route file has new or older format * Returns TRUE - new syntax (ADDRESS<n>=a.b.c.d ...), error opening file or empty * FALSE - older syntax, i.e. argument to 'ip route add' (1.2.3.0/24 via 11.22.33.44) diff --git a/src/settings/plugins/ifcfg-rh/nms-ifcfg-rh-utils.h b/src/settings/plugins/ifcfg-rh/nms-ifcfg-rh-utils.h index e7abf4d8..3756af7c 100644 --- a/src/settings/plugins/ifcfg-rh/nms-ifcfg-rh-utils.h +++ b/src/settings/plugins/ifcfg-rh/nms-ifcfg-rh-utils.h @@ -15,7 +15,7 @@ * with this program; if not, write to the Free Software Foundation, Inc., * 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA. * - * (C) Copyright 2008 - 2012 Red Hat, Inc. + * (C) Copyright 2008 - 2017 Red Hat, Inc. */ #ifndef _UTILS_H_ @@ -45,7 +45,6 @@ char *utils_get_route6_path (const char *parent); shvarFile *utils_get_extra_ifcfg (const char *parent, const char *tag, gboolean should_create); shvarFile *utils_get_keys_ifcfg (const char *parent, gboolean should_create); shvarFile *utils_get_route_ifcfg (const char *parent, gboolean should_create); -shvarFile *utils_get_route6_ifcfg (const char *parent, gboolean should_create); gboolean utils_has_route_file_new_syntax (const char *filename); gboolean utils_has_complex_routes (const char *filename, int addr_family); 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 5c8de7d1..5cb8ee98 100644 --- a/src/settings/plugins/ifcfg-rh/nms-ifcfg-rh-writer.c +++ b/src/settings/plugins/ifcfg-rh/nms-ifcfg-rh-writer.c @@ -150,7 +150,7 @@ write_secrets (shvarFile *ifcfg, /* sort the keys. */ secrets_keys = (const char **) g_hash_table_get_keys_as_array (secrets, &secrets_keys_n); - if (secrets_keys) { + if (secrets_keys_n > 1) { g_qsort_with_data (secrets_keys, secrets_keys_n, sizeof (const char *), @@ -662,12 +662,26 @@ write_wireless_security_setting (NMConnection *connection, /* And write the new ones out */ if (wep) { + NMWepKeyType key_type; + const char *key_type_str = NULL; + /* Default WEP TX key index */ svSetValueInt64 (ifcfg, "DEFAULTKEY", nm_setting_wireless_security_get_wep_tx_keyidx(s_wsec) + 1); - for (i = 0; i < 4; i++) { - NMWepKeyType key_type; + key_type = nm_setting_wireless_security_get_wep_key_type (s_wsec); + switch (key_type) { + case NM_WEP_KEY_TYPE_KEY: + key_type_str = "key"; + break; + case NM_WEP_KEY_TYPE_PASSPHRASE: + key_type_str = "passphrase"; + break; + case NM_WEP_KEY_TYPE_UNKNOWN: + break; + } + svSetValue (ifcfg, "KEY_TYPE", key_type_str); + for (i = 0; i < 4; i++) { key = nm_setting_wireless_security_get_wep_key (s_wsec, i); if (key) { gs_free char *ascii_key = NULL; @@ -678,7 +692,6 @@ write_wireless_security_setting (NMConnection *connection, * are some passphrases that are indistinguishable from WEP hex * keys. */ - key_type = nm_setting_wireless_security_get_wep_key_type (s_wsec); if (key_type == NM_WEP_KEY_TYPE_UNKNOWN) { if (nm_utils_wep_key_valid (key, NM_WEP_KEY_TYPE_KEY)) key_type = NM_WEP_KEY_TYPE_KEY; @@ -1309,25 +1322,19 @@ write_bond_setting (NMConnection *connection, shvarFile *ifcfg, gboolean *wired, svUnsetValue (ifcfg, "BONDING_OPTS"); num_opts = nm_setting_bond_get_num_options (s_bond); - if (num_opts > 0) { - GString *str = g_string_sized_new (64); - - for (i = 0; i < nm_setting_bond_get_num_options (s_bond); i++) { - const char *key, *value; - - if (!nm_setting_bond_get_option (s_bond, i, &key, &value)) - continue; + if (num_opts) { + nm_auto_free_gstring GString *str = NULL; + const char *name, *value; + str = g_string_sized_new (64); + for (i = 0; i < num_opts; i++) { if (str->len) g_string_append_c (str, ' '); - - g_string_append_printf (str, "%s=%s", key, value); + nm_setting_bond_get_option (s_bond, i, &name, &value); + g_string_append_printf (str, "%s=%s", name, value); } - if (str->len) - svSetValueStr (ifcfg, "BONDING_OPTS", str->str); - - g_string_free (str, TRUE); + svSetValueStr (ifcfg, "BONDING_OPTS", str->str); } svSetValueStr (ifcfg, "TYPE", TYPE_BOND); @@ -1414,7 +1421,7 @@ write_bridge_setting (NMConnection *connection, shvarFile *ifcfg, gboolean *wire svUnsetValue (ifcfg, "DELAY"); mac = nm_setting_bridge_get_mac_address (s_bridge); - svSetValueStr (ifcfg, "MACADDR", mac); + svSetValueStr (ifcfg, "BRIDGE_MACADDR", mac); /* Bridge options */ opts = g_string_sized_new (32); @@ -1928,8 +1935,11 @@ get_route_attributes_string (NMIPRoute *route, int family) g_string_append_printf (str, "%s 0x%02x", names[i], (unsigned) g_variant_get_byte (attr)); } else if (nm_streq (names[i], NM_IP_ROUTE_ATTRIBUTE_TABLE)) { g_string_append_printf (str, "%s %u", names[i], (unsigned) g_variant_get_uint32 (attr)); - } else if ( nm_streq (names[i], NM_IP_ROUTE_ATTRIBUTE_SRC) - || nm_streq (names[i], NM_IP_ROUTE_ATTRIBUTE_FROM)) { + } else if (nm_streq (names[i], NM_IP_ROUTE_ATTRIBUTE_ONLINK)) { + if (g_variant_get_boolean (attr)) + g_string_append (str, "onlink"); + } else if (NM_IN_STRSET (names[i], NM_IP_ROUTE_ATTRIBUTE_SRC, + NM_IP_ROUTE_ATTRIBUTE_FROM)) { char *arg = nm_streq (names[i], NM_IP_ROUTE_ATTRIBUTE_SRC) ? "src" : "from"; g_string_append_printf (str, "%s %s", arg, g_variant_get_string (attr, NULL)); @@ -2116,6 +2126,73 @@ write_user_setting (NMConnection *connection, shvarFile *ifcfg, GError **error) } static gboolean +write_tc_setting (NMConnection *connection, shvarFile *ifcfg, GError **error) +{ + NMSettingTCConfig *s_tc; + guint i, num, n; + char tag[64]; + + svUnsetAll (ifcfg, SV_KEY_TYPE_TC); + + s_tc = nm_connection_get_setting_tc_config (connection); + if (!s_tc) + return TRUE; + + num = nm_setting_tc_config_get_num_qdiscs (s_tc); + for (n = 1, i = 0; i < num; i++) { + NMTCQdisc *qdisc; + gs_free char *str = NULL; + + qdisc = nm_setting_tc_config_get_qdisc (s_tc, i); + str = nm_utils_tc_qdisc_to_str (qdisc, error); + if (!str) + return FALSE; + + svSetValueStr (ifcfg, numbered_tag (tag, "QDISC", n), str); + n++; + } + + + num = nm_setting_tc_config_get_num_tfilters (s_tc); + for (n = 1, i = 0; i < num; i++) { + NMTCTfilter *tfilter; + gs_free char *str = NULL; + + tfilter = nm_setting_tc_config_get_tfilter (s_tc, i); + str = nm_utils_tc_tfilter_to_str (tfilter, error); + if (!str) + return FALSE; + + svSetValueStr (ifcfg, numbered_tag (tag, "FILTER", n), str); + n++; + } + + return TRUE; +} + +static void +write_res_options (shvarFile *ifcfg, NMSettingIPConfig *s_ip, const char *var) +{ + nm_auto_free_gstring GString *value = NULL; + guint i, num_options; + + if (!nm_setting_ip_config_has_dns_options (s_ip)) { + svUnsetValue (ifcfg, var); + return; + } + + value = g_string_new (NULL); + num_options = nm_setting_ip_config_get_num_dns_options (s_ip); + for (i = 0; i < num_options; i++) { + if (i > 0) + g_string_append_c (value, ' '); + g_string_append (value, nm_setting_ip_config_get_dns_option (s_ip, i)); + } + + svSetValue (ifcfg, var, value->str); +} + +static gboolean write_ip4_setting (NMConnection *connection, shvarFile *ifcfg, shvarFile **out_route_content_svformat, @@ -2146,6 +2223,7 @@ write_ip4_setting (NMConnection *connection, * Some IPv4 setting related options are not cleared, * for no strong reason. */ svUnsetValue (ifcfg, "BOOTPROTO"); + svUnsetValue (ifcfg, "RES_OPTIONS"); svUnsetAll (ifcfg, SV_KEY_TYPE_IP4_ADDRESS); return TRUE; } @@ -2342,6 +2420,8 @@ write_ip4_setting (NMConnection *connection, else svUnsetValue (ifcfg, "IPV4_DNS_PRIORITY"); + write_res_options (ifcfg, s_ip4, "RES_OPTIONS"); + return TRUE; } @@ -2483,6 +2563,7 @@ write_ip6_setting (NMConnection *connection, svUnsetValue (ifcfg, "IPV6_FAILURE_FATAL"); svUnsetValue (ifcfg, "IPV6_ROUTE_METRIC"); svUnsetValue (ifcfg, "IPV6_ADDR_GEN_MODE"); + svUnsetValue (ifcfg, "IPV6_RES_OPTIONS"); return TRUE; } @@ -2557,21 +2638,20 @@ write_ip6_setting (NMConnection *connection, } } - /* Write out DNS domains - 'DOMAIN' key is shared for both IPv4 and IPv6 domains */ + /* Write out DNS domains */ num = nm_setting_ip_config_get_num_dns_searches (s_ip6); if (num > 0) { - gs_free char *ip4_domains = NULL; nm_auto_free_gstring GString *searches = NULL; - searches = g_string_new (svGetValueStr (ifcfg, "DOMAIN", &ip4_domains)); + searches = g_string_new (NULL); for (i = 0; i < num; i++) { if (searches->len > 0) g_string_append_c (searches, ' '); g_string_append (searches, nm_setting_ip_config_get_dns_search (s_ip6, i)); } - svSetValueStr (ifcfg, "DOMAIN", searches->str); - } - + svSetValueStr (ifcfg, "IPV6_DOMAIN", searches->str); + } else + svUnsetValue (ifcfg, "IPV6_DOMAIN"); /* handle IPV6_DEFROUTE */ /* IPV6_DEFROUTE has the opposite meaning from 'never-default' */ @@ -2638,66 +2718,9 @@ write_ip6_setting (NMConnection *connection, else svUnsetValue (ifcfg, "IPV6_DNS_PRIORITY"); - NM_SET_OUT (out_route6_content, write_route_file (s_ip6)); + write_res_options (ifcfg, s_ip6, "IPV6_RES_OPTIONS"); - return TRUE; -} - -static void -add_dns_option (GPtrArray *array, const char *option) -{ - if (_nm_utils_dns_option_find_idx (array, option) < 0) - g_ptr_array_add (array, (gpointer) option); -} - -static gboolean -write_res_options (NMConnection *connection, shvarFile *ifcfg, GError **error) -{ - NMSettingIPConfig *s_ip6; - NMSettingIPConfig *s_ip4; - const char *method; - int i, num_options; - gs_unref_ptrarray GPtrArray *array = NULL; - GString *value; - - s_ip4 = nm_connection_get_setting_ip4_config (connection); - - if (!s_ip4) { - /* slave-type: clear res-options */ - svUnsetValue (ifcfg, "RES_OPTIONS"); - return TRUE; - } - - array = g_ptr_array_new (); - - method = nm_setting_ip_config_get_method (s_ip4); - if (g_strcmp0 (method, NM_SETTING_IP4_CONFIG_METHOD_DISABLED)) { - num_options = nm_setting_ip_config_get_num_dns_options (s_ip4); - for (i = 0; i < num_options; i++) - add_dns_option (array, nm_setting_ip_config_get_dns_option (s_ip4, i)); - } - - s_ip6 = nm_connection_get_setting_ip6_config (connection); - method = nm_setting_ip_config_get_method (s_ip6); - if (g_strcmp0 (method, NM_SETTING_IP6_CONFIG_METHOD_IGNORE)) { - num_options = nm_setting_ip_config_get_num_dns_options (s_ip6); - for (i = 0; i < num_options; i++) - add_dns_option (array, nm_setting_ip_config_get_dns_option (s_ip6, i)); - } - - if ( array->len > 0 - || nm_setting_ip_config_has_dns_options (s_ip4) - || nm_setting_ip_config_has_dns_options (s_ip6)) { - value = g_string_new (NULL); - for (i = 0; i < array->len; i++) { - if (i > 0) - g_string_append_c (value, ' '); - g_string_append (value, array->pdata[i]); - } - svSetValue (ifcfg, "RES_OPTIONS", value->str); - g_string_free (value, TRUE); - } else - svUnsetValue (ifcfg, "RES_OPTIONS"); + NM_SET_OUT (out_route6_content, write_route_file (s_ip6)); return TRUE; } @@ -2882,6 +2905,9 @@ do_write_construct (NMConnection *connection, if (!write_user_setting (connection, ifcfg, error)) return FALSE; + if (!write_tc_setting (connection, ifcfg, error)) + return FALSE; + svUnsetValue (ifcfg, "DHCP_HOSTNAME"); svUnsetValue (ifcfg, "DHCP_FQDN"); @@ -2930,9 +2956,6 @@ do_write_construct (NMConnection *connection, error)) return FALSE; - if (!write_res_options (connection, ifcfg, error)) - return FALSE; - write_connection_setting (s_con, ifcfg); NM_SET_OUT (out_ifcfg, g_steal_pointer (&ifcfg)); diff --git a/src/settings/plugins/ifcfg-rh/shvar.c b/src/settings/plugins/ifcfg-rh/shvar.c index df03bf65..2b64f3fc 100644 --- a/src/settings/plugins/ifcfg-rh/shvar.c +++ b/src/settings/plugins/ifcfg-rh/shvar.c @@ -776,7 +776,7 @@ line_free (shvarLine *line) ASSERT_shvarLine (line); g_free (line->line); g_free (line->key_with_prefix); - c_list_unlink (&line->lst); + c_list_unlink_stale (&line->lst); g_slice_free (shvarLine, line); } @@ -1171,6 +1171,11 @@ svUnsetAll (shvarFile *s, SvKeyType match_key_type) if (g_str_has_prefix (line->key, "NM_USER_")) goto do_clear; } + if (NM_FLAGS_HAS (match_key_type, SV_KEY_TYPE_TC)) { + if ( IS_NUMBERED_TAG (line->key, "QDISC") + || IS_NUMBERED_TAG (line->key, "FILTER")) + goto do_clear; + } continue; do_clear: @@ -1318,7 +1323,7 @@ svWriteFile (shvarFile *s, int mode, GError **error) return FALSE; } - tmpfd = dup (s->fd); + tmpfd = fcntl (s->fd, F_DUPFD_CLOEXEC, 0); if (tmpfd == -1) { int errsv = errno; @@ -1373,7 +1378,8 @@ svCloseFile (shvarFile *s) g_return_if_fail (s != NULL); - nm_close (s->fd); + if (s->fd >= 0) + nm_close (s->fd); g_free (s->fileName); c_list_for_each_safe (current, safe, &s->lst_head) line_free (c_list_entry (current, shvarLine, lst)); diff --git a/src/settings/plugins/ifcfg-rh/shvar.h b/src/settings/plugins/ifcfg-rh/shvar.h index c48bbfd3..dbc4d950 100644 --- a/src/settings/plugins/ifcfg-rh/shvar.h +++ b/src/settings/plugins/ifcfg-rh/shvar.h @@ -90,7 +90,8 @@ typedef enum { SV_KEY_TYPE_ANY = (1LL << 0), SV_KEY_TYPE_ROUTE_SVFORMAT = (1LL << 1), SV_KEY_TYPE_IP4_ADDRESS = (1LL << 2), - SV_KEY_TYPE_USER = (1LL << 3), + SV_KEY_TYPE_TC = (1LL << 3), + SV_KEY_TYPE_USER = (1LL << 4), } SvKeyType; gboolean svUnsetAll (shvarFile *s, SvKeyType match_key_type); diff --git a/src/settings/plugins/ifcfg-rh/tests/network-scripts/ifcfg-Test_Write_Bond_Main.cexpected b/src/settings/plugins/ifcfg-rh/tests/network-scripts/ifcfg-Test_Write_Bond_Main.cexpected index 854d2490..5d81dfef 100644 --- a/src/settings/plugins/ifcfg-rh/tests/network-scripts/ifcfg-Test_Write_Bond_Main.cexpected +++ b/src/settings/plugins/ifcfg-rh/tests/network-scripts/ifcfg-Test_Write_Bond_Main.cexpected @@ -1,4 +1,4 @@ -BONDING_OPTS=mode=balance-rr +BONDING_OPTS="downdelay=5 miimon=100 mode=balance-rr updelay=10" TYPE=Bond BONDING_MASTER=yes PROXY_METHOD=none diff --git a/src/settings/plugins/ifcfg-rh/tests/network-scripts/ifcfg-Test_Write_Team_Infiniband_Port.cexpected b/src/settings/plugins/ifcfg-rh/tests/network-scripts/ifcfg-Test_Write_Team_Infiniband_Port.cexpected index 460278e1..2df1fbb3 100644 --- a/src/settings/plugins/ifcfg-rh/tests/network-scripts/ifcfg-Test_Write_Team_Infiniband_Port.cexpected +++ b/src/settings/plugins/ifcfg-rh/tests/network-scripts/ifcfg-Test_Write_Team_Infiniband_Port.cexpected @@ -1,6 +1,6 @@ CONNECTED_MODE=no TYPE=InfiniBand -TEAM_PORT_CONFIG="{ \"inf1\": { \"prio\": -10, \"sticky\": true } }" +TEAM_PORT_CONFIG="{\"inf1\": {\"prio\": -10, \"sticky\": true}}" NAME="Test Write Team Infiniband Port" UUID=${UUID} DEVICE=inf1 diff --git a/src/settings/plugins/ifcfg-rh/tests/network-scripts/ifcfg-Test_Write_Team_Port.cexpected b/src/settings/plugins/ifcfg-rh/tests/network-scripts/ifcfg-Test_Write_Team_Port.cexpected index 0b1deb80..ff55cefe 100644 --- a/src/settings/plugins/ifcfg-rh/tests/network-scripts/ifcfg-Test_Write_Team_Port.cexpected +++ b/src/settings/plugins/ifcfg-rh/tests/network-scripts/ifcfg-Test_Write_Team_Port.cexpected @@ -1,4 +1,4 @@ -TEAM_PORT_CONFIG="{ \"p4p1\": { \"prio\": -10, \"sticky\": true } }" +TEAM_PORT_CONFIG="{\"p4p1\": {\"prio\": -10, \"sticky\": true}}" NAME="Test Write Team Port" UUID=${UUID} ONBOOT=yes 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 new file mode 100644 index 00000000..c0e47c48 --- /dev/null +++ b/src/settings/plugins/ifcfg-rh/tests/network-scripts/ifcfg-Test_Write_Wired_Static_Routes.cexpected @@ -0,0 +1,20 @@ +HWADDR=31:33:33:37:BE:CD +MTU=1492 +TYPE=Ethernet +PROXY_METHOD=none +BROWSER_ONLY=no +BOOTPROTO=none +IPADDR=1.1.1.3 +PREFIX=24 +IPADDR1=1.1.1.5 +PREFIX1=24 +GATEWAY=1.1.1.1 +DNS1=4.2.2.1 +DNS2=4.2.2.2 +DOMAIN="foobar.com lab.foobar.com" +DEFROUTE=yes +IPV4_FAILURE_FATAL=no +IPV6INIT=no +NAME="Test Write Wired Static Routes" +UUID=${UUID} +ONBOOT=yes diff --git a/src/settings/plugins/ifcfg-rh/tests/network-scripts/ifcfg-test-dns-options b/src/settings/plugins/ifcfg-rh/tests/network-scripts/ifcfg-test-dns-options index 62e301e3..cea2471a 100644 --- a/src/settings/plugins/ifcfg-rh/tests/network-scripts/ifcfg-test-dns-options +++ b/src/settings/plugins/ifcfg-rh/tests/network-scripts/ifcfg-test-dns-options @@ -8,7 +8,8 @@ NM_CONTROLLED=yes PEERDNS=yes DNS1=10.2.0.4 DOMAIN="lorem.com ipsum.org dolor.edu" -RES_OPTIONS="ndots:3 single-request-reopen inet6" +RES_OPTIONS="ndots:3 single-request-reopen" +IPV6_RES_OPTIONS="inet6" IPV6INIT=yes IPV6_AUTOCONF=no IPV6ADDR="1001:abba::1234/56" diff --git a/src/settings/plugins/ifcfg-rh/tests/network-scripts/ifcfg-test-team-master-1 b/src/settings/plugins/ifcfg-rh/tests/network-scripts/ifcfg-test-team-master-1 index 7edc736a..209447b8 100644 --- a/src/settings/plugins/ifcfg-rh/tests/network-scripts/ifcfg-test-team-master-1 +++ b/src/settings/plugins/ifcfg-rh/tests/network-scripts/ifcfg-test-team-master-1 @@ -2,5 +2,5 @@ DEVICE=team0 ONBOOT=no DEVICETYPE=Team BOOTPROTO=dhcp -TEAM_CONFIG="{ \"device\": \"team0\", \"link_watch\": { \"name\": \"ethtool\" } }" +TEAM_CONFIG="{\"device\": \"team0\", \"link_watch\": {\"name\": \"ethtool\"}}" diff --git a/src/settings/plugins/ifcfg-rh/tests/network-scripts/ifcfg-test-team-master-2 b/src/settings/plugins/ifcfg-rh/tests/network-scripts/ifcfg-test-team-master-2 index d01e37c5..26e448cc 100644 --- a/src/settings/plugins/ifcfg-rh/tests/network-scripts/ifcfg-test-team-master-2 +++ b/src/settings/plugins/ifcfg-rh/tests/network-scripts/ifcfg-test-team-master-2 @@ -1,5 +1,5 @@ DEVICE=team0 ONBOOT=no BOOTPROTO=dhcp -TEAM_CONFIG="{ \"device\": \"team0\", \"link_watch\": { \"name\": \"ethtool\" } }" +TEAM_CONFIG="{\"device\": \"team0\", \"link_watch\": {\"name\": \"ethtool\"}}" diff --git a/src/settings/plugins/ifcfg-rh/tests/network-scripts/ifcfg-test-team-port-1 b/src/settings/plugins/ifcfg-rh/tests/network-scripts/ifcfg-test-team-port-1 index 966bec67..80355c26 100644 --- a/src/settings/plugins/ifcfg-rh/tests/network-scripts/ifcfg-test-team-port-1 +++ b/src/settings/plugins/ifcfg-rh/tests/network-scripts/ifcfg-test-team-port-1 @@ -1,5 +1,5 @@ TYPE=Ethernet -TEAM_PORT_CONFIG="{ \"p4p1\": { \"prio\": -10, \"sticky\": true } }" +TEAM_PORT_CONFIG="{\"p4p1\": {\"prio\": -10, \"sticky\": true}}" DEVICE=p4p1 TEAM_MASTER=team0 DEVICETYPE=TeamPort diff --git a/src/settings/plugins/ifcfg-rh/tests/network-scripts/ifcfg-test-team-port-2 b/src/settings/plugins/ifcfg-rh/tests/network-scripts/ifcfg-test-team-port-2 index 992510ee..4284737a 100644 --- a/src/settings/plugins/ifcfg-rh/tests/network-scripts/ifcfg-test-team-port-2 +++ b/src/settings/plugins/ifcfg-rh/tests/network-scripts/ifcfg-test-team-port-2 @@ -1,4 +1,4 @@ TYPE=Ethernet -TEAM_PORT_CONFIG="{ \"p4p1\": { \"prio\": -10, \"sticky\": true } }" +TEAM_PORT_CONFIG="{\"p4p1\": {\"prio\": -10, \"sticky\": true}}" DEVICE=p4p1 TEAM_MASTER=team0 diff --git a/src/settings/plugins/ifcfg-rh/tests/network-scripts/ifcfg-test-wired-ipv6-only b/src/settings/plugins/ifcfg-rh/tests/network-scripts/ifcfg-test-wired-ipv6-only index 59ec32e5..94189064 100644 --- a/src/settings/plugins/ifcfg-rh/tests/network-scripts/ifcfg-test-wired-ipv6-only +++ b/src/settings/plugins/ifcfg-rh/tests/network-scripts/ifcfg-test-wired-ipv6-only @@ -7,7 +7,7 @@ USERCTL=yes NM_CONTROLLED=yes PEERDNS=yes DNS1=1:2:3:4::a -DOMAIN="lorem.com ipsum.org dolor.edu" +IPV6_DOMAIN="lorem.com ipsum.org dolor.edu" IPV6INIT=yes IPV6_AUTOCONF=no IPV6ADDR="1001:abba::1234/56" diff --git a/src/settings/plugins/ifcfg-rh/tests/network-scripts/ifcfg-test-wired-static b/src/settings/plugins/ifcfg-rh/tests/network-scripts/ifcfg-test-wired-static index 6d49c01c..34acf9fe 100644 --- a/src/settings/plugins/ifcfg-rh/tests/network-scripts/ifcfg-test-wired-static +++ b/src/settings/plugins/ifcfg-rh/tests/network-scripts/ifcfg-test-wired-static @@ -19,3 +19,4 @@ IPV6ADDR_SECONDARIES="dead:beaf::2/56" DNS3=1:2:3:4::a DNS4=1:2:3:4::b RES_OPTIONS= +IPV6_RES_OPTIONS= diff --git a/src/settings/plugins/ifcfg-rh/tests/network-scripts/route-test-wired-static-routes b/src/settings/plugins/ifcfg-rh/tests/network-scripts/route-test-wired-static-routes index 10a63b67..8d6aaac2 100644 --- a/src/settings/plugins/ifcfg-rh/tests/network-scripts/route-test-wired-static-routes +++ b/src/settings/plugins/ifcfg-rh/tests/network-scripts/route-test-wired-static-routes @@ -7,3 +7,9 @@ NETMASK1=255.255.255.255 GATEWAY1=192.168.1.7 METRIC1=3 OPTIONS1="mtu lock 9000 cwnd 12 src 1.1.1.1 tos 0x28 window 30000 initcwnd lock 13 initrwnd 14" + +ADDRESS2=44.55.66.78 +NETMASK2=255.255.255.255 +GATEWAY2=192.168.1.8 +METRIC2=3 +OPTIONS2="mtu lock 9000 cwnd 12 src 1.1.1.1 tos 0x28 onlink window 30000 initcwnd lock 13 initrwnd 14" 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 5044a2d7..6bf27556 100644 --- a/src/settings/plugins/ifcfg-rh/tests/test-ifcfg-rh.c +++ b/src/settings/plugins/ifcfg-rh/tests/test-ifcfg-rh.c @@ -1318,7 +1318,7 @@ test_read_wired_static_routes (void) g_assert_cmpstr (nm_setting_ip_config_get_method (s_ip4), ==, NM_SETTING_IP4_CONFIG_METHOD_MANUAL); /* Routes */ - g_assert_cmpint (nm_setting_ip_config_get_num_routes (s_ip4), ==, 2); + g_assert_cmpint (nm_setting_ip_config_get_num_routes (s_ip4), ==, 3); ip4_route = nm_setting_ip_config_get_route (s_ip4, 0); g_assert (ip4_route); @@ -1343,6 +1343,23 @@ test_read_wired_static_routes (void) nmtst_assert_route_attribute_boolean (ip4_route, NM_IP_ROUTE_ATTRIBUTE_LOCK_INITCWND, TRUE); nmtst_assert_route_attribute_string (ip4_route, NM_IP_ROUTE_ATTRIBUTE_SRC, "1.1.1.1"); + ip4_route = nm_setting_ip_config_get_route (s_ip4, 2); + g_assert (ip4_route); + g_assert_cmpstr (nm_ip_route_get_dest (ip4_route), ==, "44.55.66.78"); + g_assert_cmpint (nm_ip_route_get_prefix (ip4_route), ==, 32); + g_assert_cmpstr (nm_ip_route_get_next_hop (ip4_route), ==, "192.168.1.8"); + g_assert_cmpint (nm_ip_route_get_metric (ip4_route), ==, 3); + nmtst_assert_route_attribute_byte (ip4_route, NM_IP_ROUTE_ATTRIBUTE_TOS, 0x28); + nmtst_assert_route_attribute_uint32 (ip4_route, NM_IP_ROUTE_ATTRIBUTE_WINDOW, 30000); + nmtst_assert_route_attribute_uint32 (ip4_route, NM_IP_ROUTE_ATTRIBUTE_CWND, 12); + nmtst_assert_route_attribute_uint32 (ip4_route, NM_IP_ROUTE_ATTRIBUTE_INITCWND, 13); + nmtst_assert_route_attribute_uint32 (ip4_route, NM_IP_ROUTE_ATTRIBUTE_INITRWND, 14); + nmtst_assert_route_attribute_uint32 (ip4_route, NM_IP_ROUTE_ATTRIBUTE_MTU, 9000); + nmtst_assert_route_attribute_boolean (ip4_route, NM_IP_ROUTE_ATTRIBUTE_LOCK_MTU, TRUE); + nmtst_assert_route_attribute_boolean (ip4_route, NM_IP_ROUTE_ATTRIBUTE_LOCK_INITCWND, TRUE); + nmtst_assert_route_attribute_string (ip4_route, NM_IP_ROUTE_ATTRIBUTE_SRC, "1.1.1.1"); + nmtst_assert_route_attribute_boolean (ip4_route, NM_IP_ROUTE_ATTRIBUTE_ONLINK, TRUE); + g_object_unref (connection); } @@ -2145,8 +2162,9 @@ test_read_dns_options (void) NMSettingIPConfig *s_ip4, *s_ip6; char *unmanaged = NULL; const char *option; - const char *options[] = { "ndots:3", "single-request-reopen", "inet6" }; - guint32 i, options_len = sizeof (options) / sizeof (options[0]); + const char *options4[] = { "ndots:3", "single-request-reopen" }; + const char *options6[] = { "inet6" }; + guint32 i, num; connection = _connection_from_file (TEST_IFCFG_DIR "/network-scripts/ifcfg-test-dns-options", NULL, TYPE_ETHERNET, &unmanaged); @@ -2158,18 +2176,20 @@ test_read_dns_options (void) s_ip6 = nm_connection_get_setting_ip6_config (connection); g_assert (s_ip6); - i = nm_setting_ip_config_get_num_dns_options (s_ip4); - g_assert_cmpint (i, ==, options_len); - - i = nm_setting_ip_config_get_num_dns_options (s_ip6); - g_assert_cmpint (i, ==, options_len); + num = nm_setting_ip_config_get_num_dns_options (s_ip4); + g_assert_cmpint (num, ==, G_N_ELEMENTS (options4)); - for (i = 0; i < options_len; i++) { + for (i = 0; i < num; i++) { option = nm_setting_ip_config_get_dns_option (s_ip4, i); - g_assert_cmpstr (options[i], ==, option); + g_assert_cmpstr (options4[i], ==, option); + } + + num = nm_setting_ip_config_get_num_dns_options (s_ip6); + g_assert_cmpint (num, ==, G_N_ELEMENTS (options6)); + for (i = 0; i < num; i++) { option = nm_setting_ip_config_get_dns_option (s_ip6, i); - g_assert_cmpstr (options[i], ==, option); + g_assert_cmpstr (options6[i], ==, option); } g_object_unref (connection); @@ -2280,6 +2300,8 @@ test_write_dns_options (void) nm_setting_ip_config_add_address (s_ip4, addr); nm_ip_address_unref (addr); + nm_setting_ip_config_add_dns_option (s_ip4, "debug"); + /* IP6 setting */ s_ip6 = (NMSettingIPConfig *) nm_setting_ip6_config_new (); nm_connection_add_setting (connection, NM_SETTING (s_ip6)); @@ -2295,26 +2317,16 @@ test_write_dns_options (void) nm_setting_ip_config_add_address (s_ip6, addr6); nm_ip_address_unref (addr6); - nm_setting_ip_config_add_dns_option (s_ip4, "debug"); nm_setting_ip_config_add_dns_option (s_ip6, "timeout:3"); nmtst_assert_connection_verifies (connection); - _writer_new_connection_FIXME (connection, - TEST_SCRATCH_DIR "/network-scripts/", - &testfile); + _writer_new_connection (connection, + TEST_SCRATCH_DIR "/network-scripts/", + &testfile); reread = _connection_from_file (testfile, NULL, TYPE_ETHERNET, NULL); - /* RES_OPTIONS is copied to both IPv4 and IPv6 settings */ - nm_setting_ip_config_clear_dns_options (s_ip4, TRUE); - nm_setting_ip_config_add_dns_option (s_ip4, "debug"); - nm_setting_ip_config_add_dns_option (s_ip4, "timeout:3"); - - nm_setting_ip_config_clear_dns_options (s_ip6, TRUE); - nm_setting_ip_config_add_dns_option (s_ip6, "debug"); - nm_setting_ip_config_add_dns_option (s_ip6, "timeout:3"); - nmtst_assert_connection_equals (connection, TRUE, reread, FALSE); } @@ -2674,7 +2686,7 @@ test_read_wifi_wep_passphrase (void) g_assert (s_wsec); g_assert_cmpstr (nm_setting_wireless_security_get_key_mgmt (s_wsec), ==, "none"); g_assert_cmpint (nm_setting_wireless_security_get_wep_tx_keyidx (s_wsec), ==, 0); - g_assert_cmpint (nm_setting_wireless_security_get_wep_key_type (s_wsec), ==, NM_WEP_KEY_TYPE_PASSPHRASE); + g_assert_cmpint (nm_setting_wireless_security_get_wep_key_type (s_wsec), ==, NM_WEP_KEY_TYPE_UNKNOWN); g_assert_cmpstr (nm_setting_wireless_security_get_wep_key (s_wsec, 0), ==, "foobar222blahblah"); g_assert (!nm_setting_wireless_security_get_wep_key (s_wsec, 1)); g_assert (!nm_setting_wireless_security_get_wep_key (s_wsec, 2)); @@ -4175,23 +4187,15 @@ test_write_wired_static (void) nmtst_assert_connection_verifies (connection); - _writer_new_connection_FIXME (connection, - TEST_SCRATCH_DIR "/network-scripts/", - &testfile); + _writer_new_connection (connection, + TEST_SCRATCH_DIR "/network-scripts/", + &testfile); route6file = utils_get_route6_path (testfile); reread = _connection_from_file (testfile, NULL, TYPE_ETHERNET, NULL); - /* FIXME: currently DNS domains from IPv6 setting are stored in 'DOMAIN' key in ifcfg-file - * However after re-reading they are dropped into IPv4 setting. - * So, in order to comparison succeeded, move DNS domains back to IPv6 setting. - */ reread_s_ip4 = nm_connection_get_setting_ip4_config (reread); reread_s_ip6 = nm_connection_get_setting_ip6_config (reread); - nm_setting_ip_config_add_dns_search (reread_s_ip6, nm_setting_ip_config_get_dns_search (reread_s_ip4, 2)); - nm_setting_ip_config_add_dns_search (reread_s_ip6, nm_setting_ip_config_get_dns_search (reread_s_ip4, 3)); - nm_setting_ip_config_remove_dns_search (reread_s_ip4, 3); - nm_setting_ip_config_remove_dns_search (reread_s_ip4, 2); g_assert_cmpint (nm_setting_ip_config_get_route_metric (reread_s_ip4), ==, 204); g_assert_cmpint (nm_setting_ip_config_get_route_metric (reread_s_ip6), ==, 206); @@ -4329,17 +4333,8 @@ test_write_wired_static_with_generic (void) route6file = utils_get_route6_path (testfile); reread = _connection_from_file (testfile, NULL, TYPE_ETHERNET, NULL); - - /* FIXME: currently DNS domains from IPv6 setting are stored in 'DOMAIN' key in ifcfg-file - * However after re-reading they are dropped into IPv4 setting. - * So, in order to comparison succeeded, move DNS domains back to IPv6 setting. - */ reread_s_ip4 = nm_connection_get_setting_ip4_config (reread); reread_s_ip6 = nm_connection_get_setting_ip6_config (reread); - nm_setting_ip_config_add_dns_search (reread_s_ip6, nm_setting_ip_config_get_dns_search (reread_s_ip4, 2)); - nm_setting_ip_config_add_dns_search (reread_s_ip6, nm_setting_ip_config_get_dns_search (reread_s_ip4, 3)); - nm_setting_ip_config_remove_dns_search (reread_s_ip4, 3); - nm_setting_ip_config_remove_dns_search (reread_s_ip4, 2); g_assert_cmpint (nm_setting_ip_config_get_route_metric (reread_s_ip4), ==, 204); g_assert_cmpint (nm_setting_ip_config_get_route_metric (reread_s_ip6), ==, 206); @@ -4748,6 +4743,7 @@ test_write_wired_static_routes (void) NMIPAddress *addr; NMIPRoute *route; GError *error = NULL; + gboolean reread_same = FALSE; connection = nm_simple_connection_new (); @@ -4792,11 +4788,15 @@ test_write_wired_static_routes (void) /* Write out routes */ route = nm_ip_route_new (AF_INET, "1.2.3.0", 24, "222.173.190.239", 0, &error); + nm_ip_route_set_attribute (route, NM_IP_ROUTE_ATTRIBUTE_WINDOW, g_variant_new_uint32 (3455)); + nm_ip_route_set_attribute (route, NM_IP_ROUTE_ATTRIBUTE_ONLINK, g_variant_new_boolean (TRUE)); g_assert_no_error (error); nm_setting_ip_config_add_route (s_ip4, route); nm_ip_route_unref (route); route = nm_ip_route_new (AF_INET, "3.2.1.0", 24, "202.254.186.190", 77, &error); + nm_ip_route_set_attribute (route, NM_IP_ROUTE_ATTRIBUTE_WINDOW, g_variant_new_uint32 (30000)); + nm_ip_route_set_attribute (route, NM_IP_ROUTE_ATTRIBUTE_ONLINK, g_variant_new_boolean (FALSE)); g_assert_no_error (error); nm_setting_ip_config_add_route (s_ip4, route); nm_ip_route_unref (route); @@ -4818,15 +4818,28 @@ test_write_wired_static_routes (void) nmtst_assert_connection_verifies (connection); - _writer_new_connection (connection, - TEST_SCRATCH_DIR "/network-scripts/", - &testfile); + _writer_new_connection_reread (connection, + TEST_SCRATCH_DIR "/network-scripts/", + &testfile, + TEST_IFCFG_DIR "/network-scripts/ifcfg-Test_Write_Wired_Static_Routes.cexpected", + &reread, + &reread_same); + /* ifcfg does not support setting onlink=0. It gets lost during write+re-read. + * Assert that it's missing, and patch it to check whether the rest of the + * connection equals. */ + g_assert (!reread_same); + nmtst_assert_connection_verifies_without_normalization (reread); + s_ip4 = nm_connection_get_setting_ip4_config (reread); + g_assert (s_ip4); + g_assert_cmpint (nm_setting_ip_config_get_num_routes (s_ip4), ==, 2); + route = nm_setting_ip_config_get_route (s_ip4, 1); + g_assert (route); + g_assert (!nm_ip_route_get_attribute (route, NM_IP_ROUTE_ATTRIBUTE_ONLINK)); + nm_ip_route_set_attribute (route, NM_IP_ROUTE_ATTRIBUTE_ONLINK, g_variant_new_boolean (FALSE)); - reread = _connection_from_file (testfile, NULL, TYPE_ETHERNET, NULL); + nmtst_assert_connection_equals (connection, TRUE, reread, FALSE); routefile = utils_get_route_path (testfile); - - nmtst_assert_connection_equals (connection, TRUE, reread, FALSE); } static void @@ -5728,6 +5741,7 @@ test_write_wifi_wep_40_ascii (void) g_object_set (s_wsec, NM_SETTING_WIRELESS_SECURITY_KEY_MGMT, "none", NM_SETTING_WIRELESS_SECURITY_WEP_TX_KEYIDX, 2, + NM_SETTING_WIRELESS_SECURITY_WEP_KEY_TYPE, NM_WEP_KEY_TYPE_KEY, NM_SETTING_WIRELESS_SECURITY_AUTH_ALG, "shared", NULL); nm_setting_wireless_security_set_wep_key (s_wsec, 0, "lorem"); @@ -5815,6 +5829,7 @@ test_write_wifi_wep_104_ascii (void) g_object_set (s_wsec, NM_SETTING_WIRELESS_SECURITY_KEY_MGMT, "none", NM_SETTING_WIRELESS_SECURITY_WEP_TX_KEYIDX, 0, + NM_SETTING_WIRELESS_SECURITY_WEP_KEY_TYPE, NM_WEP_KEY_TYPE_UNKNOWN, NM_SETTING_WIRELESS_SECURITY_AUTH_ALG, "open", NULL); nm_setting_wireless_security_set_wep_key (s_wsec, 0, "LoremIpsumSit"); @@ -7368,6 +7383,7 @@ test_read_bridge_main (void) { NMConnection *connection; NMSettingBridge *s_bridge; + NMSettingWired *s_wired; const char *mac; char expected_mac_address[ETH_ALEN] = { 0x00, 0x16, 0x41, 0x11, 0x22, 0x33 }; @@ -7390,7 +7406,9 @@ test_read_bridge_main (void) g_assert (!nm_setting_bridge_get_multicast_snooping (s_bridge)); /* MAC address */ - mac = nm_setting_bridge_get_mac_address (s_bridge); + s_wired = nm_connection_get_setting_wired (connection); + g_assert (s_wired); + mac = nm_setting_wired_get_cloned_mac_address (s_wired); g_assert (mac); g_assert (nm_utils_hwaddr_matches (mac, -1, expected_mac_address, ETH_ALEN)); @@ -7405,8 +7423,8 @@ test_write_bridge_main (void) gs_unref_object NMConnection *reread = NULL; NMSettingConnection *s_con; NMSettingBridge *s_bridge; - NMSettingIPConfig *s_ip4; - NMSettingIPConfig *s_ip6; + NMSettingIPConfig *s_ip4, *s_ip6; + NMSettingWired *s_wired; NMIPAddress *addr; static const char *mac = "31:33:33:37:be:cd"; GError *error = NULL; @@ -7458,6 +7476,10 @@ test_write_bridge_main (void) NM_SETTING_IP_CONFIG_METHOD, NM_SETTING_IP6_CONFIG_METHOD_IGNORE, NULL); + /* Wired setting */ + s_wired = (NMSettingWired *) nm_setting_wired_new (); + nm_connection_add_setting (connection, NM_SETTING (s_wired)); + nm_connection_add_setting (connection, nm_setting_proxy_new ()); nmtst_assert_connection_verifies_without_normalization (connection); @@ -8023,6 +8045,10 @@ test_write_bond_main (void) s_bond = (NMSettingBond *) nm_setting_bond_new (); nm_connection_add_setting (connection, NM_SETTING (s_bond)); + nm_setting_bond_add_option (s_bond, NM_SETTING_BOND_OPTION_DOWNDELAY, "5"); + nm_setting_bond_add_option (s_bond, NM_SETTING_BOND_OPTION_UPDELAY, "10"); + nm_setting_bond_add_option (s_bond, NM_SETTING_BOND_OPTION_MIIMON, "100"); + /* IP4 setting */ s_ip4 = (NMSettingIPConfig *) nm_setting_ip4_config_new (); nm_connection_add_setting (connection, NM_SETTING (s_ip4)); @@ -8669,7 +8695,7 @@ test_read_team_master (gconstpointer user_data) NMConnection *connection; NMSettingConnection *s_con; NMSettingTeam *s_team; - const char *expected_config = "{ \"device\": \"team0\", \"link_watch\": { \"name\": \"ethtool\" } }"; + const char *expected_config = "{\"device\": \"team0\", \"link_watch\": {\"name\": \"ethtool\"}}"; connection = _connection_from_file (PATH_NAME, NULL, TYPE_ETHERNET, NULL); @@ -8722,7 +8748,7 @@ test_write_team_master (void) NMSettingWired *s_wired; NMSettingIPConfig *s_ip4; NMSettingIPConfig *s_ip6; - const char *expected_config = "{ \"device\": \"team0\", \"link_watch\": { \"name\": \"ethtool\" } }"; + const char *expected_config = "{\"device\": \"team0\", \"link_watch\": {\"name\": \"ethtool\"}}"; shvarFile *f; connection = nm_simple_connection_new (); @@ -8791,7 +8817,7 @@ test_read_team_port (gconstpointer user_data) NMConnection *connection; NMSettingConnection *s_con; NMSettingTeamPort *s_team_port; - const char *expected_config = "{ \"p4p1\": { \"prio\": -10, \"sticky\": true } }"; + const char *expected_config = "{\"p4p1\": {\"prio\": -10, \"sticky\": true}}"; connection = _connection_from_file (PATH_NAME, NULL, TYPE_ETHERNET, NULL); @@ -8816,7 +8842,7 @@ test_write_team_port (void) NMSettingConnection *s_con; NMSettingTeamPort *s_team_port; NMSettingWired *s_wired; - const char *expected_config = "{ \"p4p1\": { \"prio\": -10, \"sticky\": true } }"; + const char *expected_config = "{\"p4p1\": {\"prio\": -10, \"sticky\": true}}"; shvarFile *f; connection = nm_simple_connection_new (); @@ -8871,7 +8897,7 @@ test_write_team_infiniband_port (void) NMSettingConnection *s_con; NMSettingTeamPort *s_team_port; NMSettingInfiniband *s_inf; - const char *expected_config = "{ \"inf1\": { \"prio\": -10, \"sticky\": true } }"; + const char *expected_config = "{\"inf1\": {\"prio\": -10, \"sticky\": true}}"; shvarFile *f; connection = nm_simple_connection_new (); @@ -9232,7 +9258,9 @@ test_svUnescape (void) V0 ("Bob outside LAN", NULL), V1 ("x", "x"), V1 ("'{ \"device\": \"team0\", \"link_watch\": { \"name\": \"ethtool\" } }'", - "{ \"device\": \"team0\", \"link_watch\": { \"name\": \"ethtool\" } }"), + "{ \"device\": \"team0\", \"link_watch\": { \"name\": \"ethtool\" } }"), + V1 ("'{\"device\": \"team0\", \"link_watch\": {\"name\": \"ethtool\"}}'", + "{\"device\": \"team0\", \"link_watch\": {\"name\": \"ethtool\"}}"), V1 ("x\"\"b", "xb"), V1 ("x\"c\"b", "xcb"), V1 ("\"c\"b", "cb"), diff --git a/src/settings/plugins/ifnet/nms-ifnet-connection.c b/src/settings/plugins/ifnet/nms-ifnet-connection.c index 5dbb124c..e7cd19cd 100644 --- a/src/settings/plugins/ifnet/nms-ifnet-connection.c +++ b/src/settings/plugins/ifnet/nms-ifnet-connection.c @@ -93,7 +93,7 @@ commit_changes (NMSettingsConnection *connection, g_signal_emit (connection, signals[IFNET_CANCEL_MONITORS], 0); if (priv->conn_name) { - success = ifnet_update_parsers_by_connection (NM_CONNECTION (connection), + success = ifnet_update_parsers_by_connection (new_connection, priv->conn_name, CONF_NET_FILE, WPA_SUPPLICANT_CONF, @@ -102,7 +102,7 @@ commit_changes (NMSettingsConnection *connection, error); } else { added = TRUE; - success = ifnet_add_new_connection (NM_CONNECTION (connection), + success = ifnet_add_new_connection (new_connection, CONF_NET_FILE, WPA_SUPPLICANT_CONF, &new_name, @@ -186,11 +186,14 @@ nm_ifnet_connection_new (NMConnection *source, const char *conn_name) 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_replace_settings (NM_SETTINGS_CONNECTION (object), - tmp, - update_unsaved, - NULL, - NULL)) { + if (!nm_settings_connection_update (NM_SETTINGS_CONNECTION (object), + tmp, + update_unsaved + ? NM_SETTINGS_CONNECTION_PERSIST_MODE_UNSAVED + : NM_SETTINGS_CONNECTION_PERSIST_MODE_KEEP, + NM_SETTINGS_CONNECTION_COMMIT_REASON_NONE, + NULL, + NULL)) { g_object_unref (object); return NULL; } diff --git a/src/settings/plugins/ifnet/nms-ifnet-plugin.c b/src/settings/plugins/ifnet/nms-ifnet-plugin.c index 998b04b4..38d23f30 100644 --- a/src/settings/plugins/ifnet/nms-ifnet-plugin.c +++ b/src/settings/plugins/ifnet/nms-ifnet-plugin.c @@ -269,11 +269,12 @@ reload_connections (NMSettingsPlugin *config) } } else { /* Update existing connection with new settings */ - if (!nm_settings_connection_replace_settings (NM_SETTINGS_CONNECTION (old), - NM_CONNECTION (new), - FALSE, /* don't set Unsaved */ - "ifnet-update", - &error)) { + if (!nm_settings_connection_update (NM_SETTINGS_CONNECTION (old), + NM_CONNECTION (new), + NM_SETTINGS_CONNECTION_PERSIST_MODE_KEEP, + 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 (); @@ -519,5 +520,5 @@ settings_plugin_interface_init (NMSettingsPluginInterface *plugin_iface) G_MODULE_EXPORT GObject * nm_settings_plugin_factory (void) { - return g_object_ref (settings_plugin_ifnet_get ()); + return G_OBJECT (g_object_ref (settings_plugin_ifnet_get ())); } diff --git a/src/settings/plugins/ifupdown/nms-ifupdown-plugin.c b/src/settings/plugins/ifupdown/nms-ifupdown-plugin.c index 0928772a..bfad9d15 100644 --- a/src/settings/plugins/ifupdown/nms-ifupdown-plugin.c +++ b/src/settings/plugins/ifupdown/nms-ifupdown-plugin.c @@ -139,10 +139,12 @@ bind_device_to_connection (SettingsPluginIfupdown *self, g_object_set (s_wifi, NM_SETTING_WIRELESS_MAC_ADDRESS, address, NULL); } - nm_settings_connection_commit_changes (NM_SETTINGS_CONNECTION (exported), - NULL, - NM_SETTINGS_CONNECTION_COMMIT_REASON_NONE, - NULL); + nm_settings_connection_update (NM_SETTINGS_CONNECTION (exported), + NULL, + NM_SETTINGS_CONNECTION_PERSIST_MODE_DISK, + NM_SETTINGS_CONNECTION_COMMIT_REASON_NONE, + "ifupdown-new", + NULL); } static void @@ -539,6 +541,6 @@ settings_plugin_interface_init (NMSettingsPluginInterface *plugin_iface) G_MODULE_EXPORT GObject * nm_settings_plugin_factory (void) { - return g_object_ref (settings_plugin_ifupdown_get ()); + return G_OBJECT (g_object_ref (settings_plugin_ifupdown_get ())); } diff --git a/src/settings/plugins/keyfile/nms-keyfile-connection.c b/src/settings/plugins/keyfile/nms-keyfile-connection.c index 300aa9f7..5a6d8a76 100644 --- a/src/settings/plugins/keyfile/nms-keyfile-connection.c +++ b/src/settings/plugins/keyfile/nms-keyfile-connection.c @@ -65,7 +65,7 @@ commit_changes (NMSettingsConnection *connection, nm_assert (out_reread_connection && !*out_reread_connection); nm_assert (!out_logmsg_change || !*out_logmsg_change); - if (!nms_keyfile_writer_connection (new_connection ?: NM_CONNECTION (connection), + if (!nms_keyfile_writer_connection (new_connection, nm_settings_connection_get_filename (connection), NM_FLAGS_ALL (commit_reason, NM_SETTINGS_CONNECTION_COMMIT_REASON_USER_ACTION | NM_SETTINGS_CONNECTION_COMMIT_REASON_ID_CHANGED), @@ -159,11 +159,14 @@ nms_keyfile_connection_new (NMConnection *source, NULL); /* Update our settings with what was read from the file */ - if (!nm_settings_connection_replace_settings (NM_SETTINGS_CONNECTION (object), - tmp, - update_unsaved, - NULL, - error)) { + if (!nm_settings_connection_update (NM_SETTINGS_CONNECTION (object), + tmp, + update_unsaved + ? NM_SETTINGS_CONNECTION_PERSIST_MODE_UNSAVED + : NM_SETTINGS_CONNECTION_PERSIST_MODE_KEEP, + NM_SETTINGS_CONNECTION_COMMIT_REASON_NONE, + NULL, + error)) { g_object_unref (object); object = NULL; } diff --git a/src/settings/plugins/keyfile/nms-keyfile-plugin.c b/src/settings/plugins/keyfile/nms-keyfile-plugin.c index ee4db320..bc64b3ca 100644 --- a/src/settings/plugins/keyfile/nms-keyfile-plugin.c +++ b/src/settings/plugins/keyfile/nms-keyfile-plugin.c @@ -258,11 +258,12 @@ update_connection (NMSKeyfilePlugin *self, else _LOGI ("update and persist "NMS_KEYFILE_CONNECTION_LOG_FMT, NMS_KEYFILE_CONNECTION_LOG_ARG (connection_new)); - if (!nm_settings_connection_replace_settings (NM_SETTINGS_CONNECTION (connection_by_uuid), - NM_CONNECTION (connection_new), - FALSE, /* don't set Unsaved */ - "keyfile-update", - &local)) { + if (!nm_settings_connection_update (NM_SETTINGS_CONNECTION (connection_by_uuid), + NM_CONNECTION (connection_new), + NM_SETTINGS_CONNECTION_PERSIST_MODE_KEEP, + NM_SETTINGS_CONNECTION_COMMIT_REASON_NONE, + "keyfile-update", + &local)) { /* Shouldn't ever get here as 'connection_new' was verified by the reader already * and the UUID did not change. */ g_assert_not_reached (); diff --git a/src/settings/plugins/keyfile/tests/keyfiles/Test_TC_Config b/src/settings/plugins/keyfile/tests/keyfiles/Test_TC_Config new file mode 100644 index 00000000..14280eef --- /dev/null +++ b/src/settings/plugins/keyfile/tests/keyfiles/Test_TC_Config @@ -0,0 +1,11 @@ + +[connection] +id=Test TC Config +uuid=32a51666-95ea-1337-b371-dcf5e54b1001 +type=802-3-ethernet + +[tc] +qdisc.root=handle 1234 fq_codel +qdisc.ffff:fff1=ingress +tfilter.1234:=matchall action drop +tfilter.ffff:=matchall action simple sdata Hello diff --git a/src/settings/plugins/keyfile/tests/test-keyfile.c b/src/settings/plugins/keyfile/tests/test-keyfile.c index 2584a722..f27efddd 100644 --- a/src/settings/plugins/keyfile/tests/test-keyfile.c +++ b/src/settings/plugins/keyfile/tests/test-keyfile.c @@ -15,7 +15,7 @@ * with this program; if not, write to the Free Software Foundation, Inc., * 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA. * - * Copyright (C) 2008 - 2014 Red Hat, Inc. + * Copyright (C) 2008 - 2017 Red Hat, Inc. */ #include "nm-default.h" @@ -27,6 +27,7 @@ #include <netinet/in.h> #include <arpa/inet.h> #include <sys/socket.h> +#include <linux/pkt_sched.h> #include "nm-core-internal.h" @@ -2624,6 +2625,125 @@ test_write_flags_property (void) /*****************************************************************************/ static void +test_read_tc_config (void) +{ + gs_unref_object NMConnection *connection = NULL; + NMSettingTCConfig *s_tc; + NMTCQdisc *qdisc1, *qdisc2; + NMTCAction *action1, *action2; + NMTCTfilter *tfilter1, *tfilter2; + gs_free_error GError *error = NULL; + gboolean success; + + connection = nms_keyfile_reader_from_file (TEST_KEYFILES_DIR "/Test_TC_Config", NULL); + g_assert (connection); + success = nm_connection_verify (connection, &error); + g_assert_no_error (error); + g_assert (success); + + s_tc = nm_connection_get_setting_tc_config (connection); + g_assert (s_tc); + + g_assert (nm_setting_tc_config_get_num_qdiscs (s_tc) == 2); + + qdisc1 = nm_setting_tc_config_get_qdisc (s_tc, 0); + g_assert (qdisc1); + g_assert (g_strcmp0 (nm_tc_qdisc_get_kind (qdisc1), "fq_codel") == 0); + g_assert (nm_tc_qdisc_get_handle (qdisc1) == TC_H_MAKE (0x1234 << 16, 0x0000)); + g_assert (nm_tc_qdisc_get_parent (qdisc1) == TC_H_ROOT); + + qdisc2 = nm_setting_tc_config_get_qdisc (s_tc, 1); + g_assert (qdisc2); + g_assert (g_strcmp0 (nm_tc_qdisc_get_kind (qdisc2), "ingress") == 0); + g_assert (nm_tc_qdisc_get_handle (qdisc2) == TC_H_MAKE (TC_H_INGRESS, 0)); + g_assert (nm_tc_qdisc_get_parent (qdisc2) == TC_H_INGRESS); + + g_assert (nm_setting_tc_config_get_num_tfilters (s_tc) == 2); + + tfilter1 = nm_setting_tc_config_get_tfilter (s_tc, 0); + g_assert (tfilter1); + g_assert (g_strcmp0 (nm_tc_tfilter_get_kind (tfilter1), "matchall") == 0); + g_assert (nm_tc_tfilter_get_handle (tfilter1) == TC_H_UNSPEC); + g_assert (nm_tc_tfilter_get_parent (tfilter1) == TC_H_MAKE (0x1234 << 16, 0x0000)); + + action1 = nm_tc_tfilter_get_action (tfilter1); + g_assert (action1); + g_assert (g_strcmp0 (nm_tc_action_get_kind (action1), "drop") == 0); + + tfilter2 = nm_setting_tc_config_get_tfilter (s_tc, 1); + g_assert (tfilter2); + g_assert (g_strcmp0 (nm_tc_tfilter_get_kind (tfilter2), "matchall") == 0); + g_assert (nm_tc_tfilter_get_handle (tfilter2) == TC_H_UNSPEC); + g_assert (nm_tc_tfilter_get_parent (tfilter2) == TC_H_MAKE (TC_H_INGRESS, 0)); + + action2 = nm_tc_tfilter_get_action (tfilter2); + g_assert (action2); + g_assert (g_strcmp0 (nm_tc_action_get_kind (action2), "simple") == 0); + g_assert (g_strcmp0 (g_variant_get_bytestring (nm_tc_action_get_attribute (action2, "sdata")), + "Hello") == 0); +} + +static void +test_write_tc_config (void) +{ + gs_unref_object NMConnection *connection = NULL; + NMSetting *s_tc; + NMTCQdisc *qdisc1, *qdisc2; + NMTCTfilter *tfilter1, *tfilter2; + NMTCAction *action; + GError *error = NULL; + + connection = nmtst_create_minimal_connection ("Test TC", + NULL, + NM_SETTING_WIRED_SETTING_NAME, + NULL); + s_tc = nm_setting_tc_config_new (); + + qdisc1 = nm_tc_qdisc_new ("fq_codel", TC_H_ROOT, &error); + nmtst_assert_success (qdisc1, error); + nm_tc_qdisc_set_handle (qdisc1, TC_H_MAKE (0x1234 << 16, 0x0000)); + nm_setting_tc_config_add_qdisc (NM_SETTING_TC_CONFIG (s_tc), qdisc1); + + qdisc2 = nm_tc_qdisc_new ("ingress", TC_H_INGRESS, &error); + nmtst_assert_success (qdisc2, error); + nm_tc_qdisc_set_handle (qdisc2, TC_H_MAKE (TC_H_INGRESS, 0)); + nm_setting_tc_config_add_qdisc (NM_SETTING_TC_CONFIG (s_tc), qdisc2); + + tfilter1 = nm_tc_tfilter_new ("matchall", + TC_H_MAKE (0x1234 << 16, 0x0000), + &error); + nmtst_assert_success (tfilter1, error); + action = nm_tc_action_new ("drop", &error); + nmtst_assert_success (action, error); + nm_tc_tfilter_set_action (tfilter1, action); + nm_tc_action_unref (action); + nm_setting_tc_config_add_tfilter (NM_SETTING_TC_CONFIG (s_tc), tfilter1); + nm_tc_tfilter_unref (tfilter1); + + tfilter2 = nm_tc_tfilter_new ("matchall", + TC_H_MAKE (TC_H_INGRESS, 0), + &error); + nmtst_assert_success (tfilter2, error); + action = nm_tc_action_new ("simple", &error); + nmtst_assert_success (action, error); + nm_tc_action_set_attribute (action, "sdata", g_variant_new_bytestring ("Hello")); + nm_tc_tfilter_set_action (tfilter2, action); + nm_tc_action_unref (action); + nm_setting_tc_config_add_tfilter (NM_SETTING_TC_CONFIG (s_tc), tfilter2); + nm_tc_tfilter_unref (tfilter2); + + nm_connection_add_setting (connection, s_tc); + + nmtst_connection_normalize (connection); + write_test_connection_and_reread (connection, FALSE); + + nm_tc_qdisc_unref (qdisc1); + nm_tc_qdisc_unref (qdisc2); +} + +/*****************************************************************************/ + +static void _escape_filename (const char *filename, gboolean would_be_ignored) { gs_free char *esc = NULL; @@ -2748,6 +2868,9 @@ int main (int argc, char **argv) g_test_add_func ("/keyfile/test_read_flags_property", test_read_flags_property); g_test_add_func ("/keyfile/test_write_flags_property", test_write_flags_property); + g_test_add_func ("/keyfile/test_read_tc_config", test_read_tc_config); + g_test_add_func ("/keyfile/test_write_tc_config", test_write_tc_config); + g_test_add_func ("/keyfile/test_nm_keyfile_plugin_utils_escape_filename", test_nm_keyfile_plugin_utils_escape_filename); return g_test_run (); diff --git a/src/tests/config/test-config.c b/src/tests/config/test-config.c index 80e17d01..89b22a9f 100644 --- a/src/tests/config/test-config.c +++ b/src/tests/config/test-config.c @@ -318,6 +318,7 @@ test_config_global_dns (void) g_object_unref (config); } +#if WITH_CONCHECK static void test_config_connectivity_check (void) { @@ -351,6 +352,7 @@ test_config_connectivity_check (void) g_assert (remove (CONFIG_INTERN) == 0); } +#endif static void test_config_no_auto_default (void) @@ -368,7 +370,7 @@ test_config_no_auto_default (void) g_assert_cmpint (nwrote, ==, 18); nwrote = write (fd, "44:44:44:44:44:44\n", 18); g_assert_cmpint (nwrote, ==, 18); - close (fd); + nm_close (fd); config = setup_config (NULL, SRCDIR "/NetworkManager.conf", "", NULL, "/no/such/dir", "", "--no-auto-default", state_file, @@ -1053,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/test-general-with-expect.c b/src/tests/test-general-with-expect.c index c5d26163..2911d84d 100644 --- a/src/tests/test-general-with-expect.c +++ b/src/tests/test-general-with-expect.c @@ -184,7 +184,7 @@ test_nm_utils_kill_child_create_and_join_pgroup (void) if (pgid == 0) { /* child process... */ - close (pipefd[0]); + nm_close (pipefd[0]); err = setpgid (0, 0); g_assert (err == 0); @@ -192,16 +192,16 @@ test_nm_utils_kill_child_create_and_join_pgroup (void) err = write (pipefd[1], &tmp, sizeof (tmp)); g_assert (err == sizeof (tmp)); - close (pipefd[1]); + nm_close (pipefd[1]); exit (0); } - close (pipefd[1]); + nm_close (pipefd[1]); err = read (pipefd[0], &tmp, sizeof (tmp)); g_assert (err == sizeof (tmp)); - close (pipefd[0]); + nm_close (pipefd[0]); err = setpgid (0, pgid); g_assert (err == 0); diff --git a/src/tests/test-general.c b/src/tests/test-general.c index d36a26ef..bfa2ea73 100644 --- a/src/tests/test-general.c +++ b/src/tests/test-general.c @@ -359,7 +359,7 @@ _match_connection (GSList *connections, } list[i] = NULL; - return nm_utils_match_connection (list, original, device_has_carrier, default_v4_metric, default_v6_metric, NULL, NULL); + return nm_utils_match_connection (list, original, FALSE, device_has_carrier, default_v4_metric, default_v6_metric, NULL, NULL); } static void diff --git a/src/tests/test-ip4-config.c b/src/tests/test-ip4-config.c index 649b443f..4c3c344e 100644 --- a/src/tests/test-ip4-config.c +++ b/src/tests/test-ip4-config.c @@ -38,6 +38,8 @@ build_test_config (void) /* Build up the config to subtract */ config = nmtst_ip4_config_new (1); + nm_assert (NM_IP_CONFIG_CAST (config)); + addr = *nmtst_platform_ip4_address ("192.168.1.10", "1.2.3.4", 24); nm_ip4_config_add_address (config, &addr); diff --git a/src/vpn/nm-vpn-connection.c b/src/vpn/nm-vpn-connection.c index 2436ea33..6c600c46 100644 --- a/src/vpn/nm-vpn-connection.c +++ b/src/vpn/nm-vpn-connection.c @@ -103,7 +103,7 @@ typedef struct { gboolean service_can_persist; gboolean connection_can_persist; - NMSettingsConnectionCallId secrets_id; + NMSettingsConnectionCallId *secrets_id; SecretsReq secrets_idx; char *username; @@ -185,13 +185,13 @@ static NMSettingsConnection *_get_settings_connection (NMVpnConnection *self, static void get_secrets (NMVpnConnection *self, SecretsReq secrets_idx, - const char **hints); + const char *const*hints); static guint32 get_route_table (NMVpnConnection *self, int addr_family, gboolean fallback_main); static void plugin_interactive_secrets_required (NMVpnConnection *self, const char *message, - const char **secrets); + const char *const*secrets); static void _set_vpn_state (NMVpnConnection *self, VpnState vpn_state, @@ -1007,8 +1007,8 @@ print_vpn_config (NMVpnConnection *self) if (priv->ip4_internal_gw) _LOGI ("Data: Internal Gateway: %s", nm_utils_inet4_ntop (priv->ip4_internal_gw, NULL)); - _LOGI ("Data: Internal Address: %s", nm_utils_inet4_ntop (address4->address, NULL)); - _LOGI ("Data: Internal Prefix: %d", address4->plen); + _LOGI ("Data: Internal Address: %s", address4 ? nm_utils_inet4_ntop (address4->address, NULL) : "??"); + _LOGI ("Data: Internal Prefix: %d", address4 ? (int) address4->plen : -1); _LOGI ("Data: Internal Point-to-Point Address: %s", nm_utils_inet4_ntop (address4->peer_address, NULL)); nm_ip_config_iter_ip4_route_for_each (&ipconf_iter, priv->ip4_config, &route) { @@ -1563,9 +1563,12 @@ 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)); - if ( g_variant_lookup (dict, NM_VPN_PLUGIN_IP4_CONFIG_PRESERVE_ROUTES, "b", &b) - && b) { + if (nm_setting_ip_config_get_ignore_auto_routes (s_ip)) { + /* ignore VPN routes */ + } else if ( g_variant_lookup (dict, NM_VPN_PLUGIN_IP4_CONFIG_PRESERVE_ROUTES, "b", &b) + && b) { if (priv->ip4_config) { NMDedupMultiIter ipconf_iter; const NMPlatformIP4Route *route; @@ -1616,7 +1619,6 @@ nm_vpn_connection_ip4_config_get (NMVpnConnection *self, GVariant *dict) never_default = b; /* Merge in user overrides from the NMConnection's IPv4 setting */ - s_ip = nm_connection_get_setting_ip4_config (_get_applied_connection (self)); nm_ip4_config_merge_setting (config, s_ip, route_table, @@ -1756,9 +1758,12 @@ nm_vpn_connection_ip6_config_get (NMVpnConnection *self, GVariant *dict) route_table = get_route_table (self, AF_INET6, TRUE); route_metric = nm_vpn_connection_get_ip6_route_metric (self); + s_ip = nm_connection_get_setting_ip6_config (_get_applied_connection (self)); - if ( g_variant_lookup (dict, NM_VPN_PLUGIN_IP6_CONFIG_PRESERVE_ROUTES, "b", &b) - && b) { + if (nm_setting_ip_config_get_ignore_auto_routes (s_ip)) { + /* Ignore VPN routes */ + } else if ( g_variant_lookup (dict, NM_VPN_PLUGIN_IP6_CONFIG_PRESERVE_ROUTES, "b", &b) + && b) { if (priv->ip6_config) { NMDedupMultiIter ipconf_iter; const NMPlatformIP6Route *route; @@ -1806,7 +1811,6 @@ next: never_default = b; /* Merge in user overrides from the NMConnection's IPv6 setting */ - s_ip = nm_connection_get_setting_ip6_config (_get_applied_connection (self)); nm_ip6_config_merge_setting (config, s_ip, route_table, @@ -2043,7 +2047,7 @@ state_changed_cb (GDBusProxy *proxy, static void secrets_required_cb (GDBusProxy *proxy, const char *message, - const char **secrets, + const char *const*secrets, gpointer user_data) { NMVpnConnection *self = NM_VPN_CONNECTION (user_data); @@ -2567,7 +2571,7 @@ plugin_new_secrets_cb (GDBusProxy *proxy, GAsyncResult *result, gpointer user_da static void get_secrets_cb (NMSettingsConnection *connection, - NMSettingsConnectionCallId call_id, + NMSettingsConnectionCallId *call_id, const char *agent_username, const char *setting_name, GError *error, @@ -2634,7 +2638,7 @@ get_secrets_cb (NMSettingsConnection *connection, static void get_secrets (NMVpnConnection *self, SecretsReq secrets_idx, - const char **hints) + const char *const*hints) { NMVpnConnectionPrivate *priv = NM_VPN_CONNECTION_GET_PRIVATE (self); NMSecretAgentGetSecretsFlags flags = NM_SECRET_AGENT_GET_SECRETS_FLAG_NONE; @@ -2679,12 +2683,13 @@ get_secrets (NMVpnConnection *self, static void plugin_interactive_secrets_required (NMVpnConnection *self, const char *message, - const char **secrets) + const char *const*secrets) { NMVpnConnectionPrivate *priv = NM_VPN_CONNECTION_GET_PRIVATE (self); - guint32 secrets_len = secrets ? g_strv_length ((char **) secrets) : 0; - char **hints; - guint32 i; + const gsize secrets_len = NM_PTRARRAY_LEN (secrets); + gsize i; + gs_free const char **hints = NULL; + gs_free char *message_hint = NULL; _LOGI ("VPN plugin: requested secrets; state %s (%d)", vpn_state_to_string (priv->vpn_state), priv->vpn_state); @@ -2696,14 +2701,17 @@ plugin_interactive_secrets_required (NMVpnConnection *self, _set_vpn_state (self, STATE_NEED_AUTH, NM_ACTIVE_CONNECTION_STATE_REASON_NONE, FALSE); /* Copy hints and add message to the end */ - hints = g_malloc0 (sizeof (char *) * (secrets_len + 2)); + hints = g_new (const char *, secrets_len + 2); for (i = 0; i < secrets_len; i++) - hints[i] = g_strdup (secrets[i]); - if (message) - hints[i] = g_strdup_printf ("x-vpn-message:%s", message); + hints[i] = secrets[i]; + if (message) { + message_hint = g_strdup_printf ("x-vpn-message:%s", message); + hints[i++] = message_hint; + } + hints[i] = NULL; + nm_assert (i < secrets_len + 2); - get_secrets (self, SECRETS_REQ_INTERACTIVE, (const char **) hints); - g_strfreev (hints); + get_secrets (self, SECRETS_REQ_INTERACTIVE, hints); } /*****************************************************************************/ |