diff options
| author | Sebastien Bacher <seb128@ubuntu.com> | 2019-03-12 15:13:33 +0100 |
|---|---|---|
| committer | Sebastien Bacher <seb128@ubuntu.com> | 2019-03-12 15:13:33 +0100 |
| commit | dd428301eb6f02542015121d7b08d9997f137e50 (patch) | |
| tree | 5530189f63510287d65268fc36025bdbc9414c00 /src | |
| parent | bbae86d3d2997a853ca0365e8eb7a3ca7489ee09 (diff) | |
New upstream version 1.15.91
Diffstat (limited to 'src')
212 files changed, 7704 insertions, 3068 deletions
diff --git a/src/NetworkManagerUtils.c b/src/NetworkManagerUtils.c index fc0c5b8d..71bfbf7c 100644 --- a/src/NetworkManagerUtils.c +++ b/src/NetworkManagerUtils.c @@ -212,10 +212,7 @@ nm_utils_connection_has_default_route (NMConnection *connection, if (!connection) goto out; - if (addr_family == AF_INET) - s_ip = nm_connection_get_setting_ip4_config (connection); - else - s_ip = nm_connection_get_setting_ip6_config (connection); + s_ip = nm_connection_get_setting_ip_config (connection, addr_family); if (!s_ip) goto out; if (nm_setting_ip_config_get_never_default (s_ip)) { @@ -377,40 +374,36 @@ check_ip6_method (NMConnection *orig, static int route_compare (NMIPRoute *route1, NMIPRoute *route2, gint64 default_metric) { - gint64 r, metric1, metric2; + NMIPAddr a1; + NMIPAddr a2; + guint64 m1; + guint64 m2; int family; guint plen; - NMIPAddr a1 = { 0 }, a2 = { 0 }; family = nm_ip_route_get_family (route1); - r = family - nm_ip_route_get_family (route2); - if (r) - return r > 0 ? 1 : -1; + NM_CMP_DIRECT (family, nm_ip_route_get_family (route2)); + + nm_assert_addr_family (family); plen = nm_ip_route_get_prefix (route1); - r = plen - nm_ip_route_get_prefix (route2); - if (r) - return r > 0 ? 1 : -1; - - metric1 = nm_ip_route_get_metric (route1) == -1 ? default_metric : nm_ip_route_get_metric (route1); - metric2 = nm_ip_route_get_metric (route2) == -1 ? default_metric : nm_ip_route_get_metric (route2); - - r = metric1 - metric2; - if (r) - return r > 0 ? 1 : -1; - - r = g_strcmp0 (nm_ip_route_get_next_hop (route1), nm_ip_route_get_next_hop (route2)); - if (r) - return r; - - /* NMIPRoute validates family and dest. inet_pton() is not expected to fail. */ - inet_pton (family, nm_ip_route_get_dest (route1), &a1); - inet_pton (family, nm_ip_route_get_dest (route2), &a2); - nm_utils_ipx_address_clear_host_address (family, &a1, &a1, plen); - nm_utils_ipx_address_clear_host_address (family, &a2, &a2, plen); - r = memcmp (&a1, &a2, sizeof (a1)); - if (r) - return r; + NM_CMP_DIRECT (plen, nm_ip_route_get_prefix (route2)); + + m1 = nm_ip_route_get_metric (route1); + m2 = nm_ip_route_get_metric (route2); + NM_CMP_DIRECT (m1 == -1 ? default_metric : m1, + m2 == -1 ? default_metric : m2); + + NM_CMP_DIRECT_STRCMP0 (nm_ip_route_get_next_hop (route1), + nm_ip_route_get_next_hop (route2)); + + if (!inet_pton (family, nm_ip_route_get_dest (route1), &a1)) + nm_assert_not_reached (); + if (!inet_pton (family, nm_ip_route_get_dest (route2), &a2)) + nm_assert_not_reached (); + nm_utils_ipx_address_clear_host_address (family, &a1, NULL, plen); + nm_utils_ipx_address_clear_host_address (family, &a2, NULL, plen); + NM_CMP_DIRECT_MEMCMP (&a1, &a2, nm_utils_addr_family_to_size (family)); return 0; } diff --git a/src/devices/adsl/nm-atm-manager.c b/src/devices/adsl/nm-atm-manager.c index 0ff4603d..dddb8342 100644 --- a/src/devices/adsl/nm-atm-manager.c +++ b/src/devices/adsl/nm-atm-manager.c @@ -20,7 +20,6 @@ #include "nm-default.h" -#include <string.h> #include <gmodule.h> #include <libudev.h> diff --git a/src/devices/adsl/nm-device-adsl.c b/src/devices/adsl/nm-device-adsl.c index ddc03ce3..b3b87dc7 100644 --- a/src/devices/adsl/nm-device-adsl.c +++ b/src/devices/adsl/nm-device-adsl.c @@ -25,13 +25,12 @@ #include <sys/socket.h> #include <linux/atmdev.h> #include <linux/atmbr2684.h> -#include <errno.h> #include <sys/ioctl.h> #include <sys/types.h> #include <unistd.h> #include <stdlib.h> -#include <string.h> +#include "nm-ip4-config.h" #include "devices/nm-device-private.h" #include "platform/nm-platform.h" #include "ppp/nm-ppp-manager-call.h" @@ -371,8 +370,8 @@ br2684_create_iface (NMDeviceAdsl *self, priv->nas_update_id = g_timeout_add (100, nas_update_cb, self); return NM_ACT_STAGE_RETURN_POSTPONE; } - if (errno != EEXIST) { - errsv = errno; + errsv = errno; + if (errsv != EEXIST) { _LOGW (LOGD_ADSL, "failed to create br2684 interface (%d)", errsv); break; } @@ -449,9 +448,8 @@ ppp_ip4_config (NMPPPManager *ppp_manager, NMDevice *device = NM_DEVICE (user_data); /* Ignore PPP IP4 events that come in after initial configuration */ - if (nm_device_activate_ip4_state_in_conf (device)) { - nm_device_activate_schedule_ip4_config_result (device, config); - } + if (nm_device_activate_ip4_state_in_conf (device)) + nm_device_activate_schedule_ip_config_result (device, AF_INET, NM_IP_CONFIG_CAST (config)); } static NMActStageReturn @@ -520,6 +518,18 @@ act_stage3_ip4_config_start (NMDevice *device, return NM_ACT_STAGE_RETURN_POSTPONE; } +static NMActStageReturn +act_stage3_ip_config_start (NMDevice *device, + int addr_family, + gpointer *out_config, + NMDeviceStateReason *out_failure_reason) +{ + if (addr_family == AF_INET) + return act_stage3_ip4_config_start (device, (NMIP4Config **) out_config, out_failure_reason); + + return NM_DEVICE_CLASS (nm_device_adsl_parent_class)->act_stage3_ip_config_start (device, addr_family, out_config, out_failure_reason); +} + static void adsl_cleanup (NMDeviceAdsl *self) { @@ -689,7 +699,7 @@ nm_device_adsl_class_init (NMDeviceAdslClass *klass) device_class->complete_connection = complete_connection; device_class->act_stage2_config = act_stage2_config; - device_class->act_stage3_ip4_config_start = act_stage3_ip4_config_start; + device_class->act_stage3_ip_config_start = act_stage3_ip_config_start; device_class->deactivate = deactivate; obj_properties[PROP_ATM_INDEX] = diff --git a/src/devices/bluetooth/nm-bluez-device.c b/src/devices/bluetooth/nm-bluez-device.c index 8e2a96b7..377ee478 100644 --- a/src/devices/bluetooth/nm-bluez-device.c +++ b/src/devices/bluetooth/nm-bluez-device.c @@ -23,8 +23,6 @@ #include "nm-bluez-device.h" -#include <string.h> - #include "nm-core-internal.h" #include "nm-bt-error.h" #include "nm-bluez-common.h" diff --git a/src/devices/bluetooth/nm-bluez-manager.c b/src/devices/bluetooth/nm-bluez-manager.c index 711f2e57..dc85a8b2 100644 --- a/src/devices/bluetooth/nm-bluez-manager.c +++ b/src/devices/bluetooth/nm-bluez-manager.c @@ -21,7 +21,6 @@ #include "nm-default.h" #include <signal.h> -#include <string.h> #include <stdlib.h> #include <gmodule.h> diff --git a/src/devices/bluetooth/nm-bluez4-adapter.c b/src/devices/bluetooth/nm-bluez4-adapter.c index c8ef7a27..3a456deb 100644 --- a/src/devices/bluetooth/nm-bluez4-adapter.c +++ b/src/devices/bluetooth/nm-bluez4-adapter.c @@ -22,8 +22,6 @@ #include "nm-bluez4-adapter.h" -#include <string.h> - #include "nm-dbus-interface.h" #include "nm-bluez-device.h" #include "nm-bluez-common.h" diff --git a/src/devices/bluetooth/nm-bluez4-manager.c b/src/devices/bluetooth/nm-bluez4-manager.c index 1fe02f18..82d995be 100644 --- a/src/devices/bluetooth/nm-bluez4-manager.c +++ b/src/devices/bluetooth/nm-bluez4-manager.c @@ -24,7 +24,6 @@ #include "nm-bluez4-manager.h" #include <signal.h> -#include <string.h> #include <stdlib.h> #include "nm-bluez4-adapter.h" diff --git a/src/devices/bluetooth/nm-bluez5-dun.c b/src/devices/bluetooth/nm-bluez5-dun.c index 32f8da65..ff3a0da9 100644 --- a/src/devices/bluetooth/nm-bluez5-dun.c +++ b/src/devices/bluetooth/nm-bluez5-dun.c @@ -27,7 +27,6 @@ #include <net/ethernet.h> #include <sys/ioctl.h> #include <unistd.h> -#include <errno.h> #include <fcntl.h> #include "nm-bluez5-dun.h" @@ -57,6 +56,7 @@ dun_connect (NMBluez5DunContext *context) char tty[100]; const int ttylen = sizeof (tty) - 1; GError *error = NULL; + int errsv; struct rfcomm_dev_req req = { .flags = (1 << RFCOMM_REUSE_DLC) | (1 << RFCOMM_RELEASE_ONHUP), @@ -66,10 +66,10 @@ dun_connect (NMBluez5DunContext *context) context->rfcomm_fd = socket (AF_BLUETOOTH, SOCK_STREAM | SOCK_CLOEXEC, BTPROTO_RFCOMM); if (context->rfcomm_fd < 0) { - int errsv = errno; + errsv = errno; error = g_error_new (NM_BT_ERROR, NM_BT_ERROR_DUN_CONNECT_FAILED, "Failed to create RFCOMM socket: (%d) %s", - errsv, strerror (errsv)); + errsv, nm_strerror_native (errsv)); goto done; } @@ -78,20 +78,20 @@ dun_connect (NMBluez5DunContext *context) sa.rc_channel = 0; memcpy (&sa.rc_bdaddr, &context->src, ETH_ALEN); if (bind (context->rfcomm_fd, (struct sockaddr *) &sa, sizeof(sa))) { - int errsv = errno; + errsv = errno; error = g_error_new (NM_BT_ERROR, NM_BT_ERROR_DUN_CONNECT_FAILED, "Failed to bind socket: (%d) %s", - errsv, strerror (errsv)); + errsv, nm_strerror_native (errsv)); goto done; } sa.rc_channel = context->rfcomm_channel; memcpy (&sa.rc_bdaddr, &context->dst, ETH_ALEN); if (connect (context->rfcomm_fd, (struct sockaddr *) &sa, sizeof (sa)) ) { - int errsv = errno; + errsv = errno; error = g_error_new (NM_BT_ERROR, NM_BT_ERROR_DUN_CONNECT_FAILED, "Failed to connect to remote device: (%d) %s", - errsv, strerror (errsv)); + errsv, nm_strerror_native (errsv)); goto done; } @@ -103,10 +103,10 @@ dun_connect (NMBluez5DunContext *context) memcpy (&req.dst, &context->dst, ETH_ALEN); devid = ioctl (context->rfcomm_fd, RFCOMMCREATEDEV, &req); if (devid < 0) { - int errsv = errno; + errsv = errno; error = g_error_new (NM_BT_ERROR, NM_BT_ERROR_DUN_CONNECT_FAILED, "Failed to create rfcomm device: (%d) %s", - errsv, strerror (errsv)); + errsv, nm_strerror_native (errsv)); goto done; } context->rfcomm_id = devid; @@ -250,7 +250,8 @@ sdp_connect_watch (GIOChannel *channel, GIOCondition condition, gpointer user_da sdp_list_t *search, *attrs; uuid_t svclass; uint16_t attr; - int fd, err, fd_err = 0; + int fd, fd_err = 0; + int err; socklen_t len = sizeof (fd_err); GError *error = NULL; @@ -258,19 +259,19 @@ sdp_connect_watch (GIOChannel *channel, GIOCondition condition, gpointer user_da fd = g_io_channel_unix_get_fd (channel); if (getsockopt (fd, SOL_SOCKET, SO_ERROR, &fd_err, &len) < 0) { - nm_log_dbg (LOGD_BT, "(%s -> %s): getsockopt error=%d", - context->src_str, context->dst_str, errno); err = errno; + nm_log_dbg (LOGD_BT, "(%s -> %s): getsockopt error=%d", + context->src_str, context->dst_str, err); } else { + err = fd_err; nm_log_dbg (LOGD_BT, "(%s -> %s): SO_ERROR error=%d", context->src_str, context->dst_str, fd_err); - err = fd_err; } if (err != 0) { error = g_error_new (NM_BT_ERROR, NM_BT_ERROR_DUN_CONNECT_FAILED, "Error on Service Discovery socket: (%d) %s", - err, strerror (err)); + err, nm_strerror_native (err)); goto done; } @@ -297,7 +298,7 @@ sdp_connect_watch (GIOChannel *channel, GIOCondition condition, gpointer user_da error = g_error_new (NM_BT_ERROR, NM_BT_ERROR_DUN_CONNECT_FAILED, "Error starting Service Discovery: (%d) %s", - err, strerror (err)); + err, nm_strerror_native (err)); } sdp_list_free (attrs, NULL); @@ -358,7 +359,7 @@ nm_bluez5_dun_connect (NMBluez5DunContext *context, error = g_error_new (NM_BT_ERROR, NM_BT_ERROR_DUN_CONNECT_FAILED, "Failed to connect to the SDP server: (%d) %s", - err, strerror (err)); + err, nm_strerror_native (err)); /* FIXME: don't invoke the callback synchronously. */ context->callback (context, NULL, error, context->user_data); return; diff --git a/src/devices/bluetooth/nm-bluez5-manager.c b/src/devices/bluetooth/nm-bluez5-manager.c index e984212b..be15d824 100644 --- a/src/devices/bluetooth/nm-bluez5-manager.c +++ b/src/devices/bluetooth/nm-bluez5-manager.c @@ -25,7 +25,6 @@ #include "nm-bluez5-manager.h" #include <signal.h> -#include <string.h> #include <stdlib.h> #include "nm-core-internal.h" diff --git a/src/devices/bluetooth/nm-device-bt.c b/src/devices/bluetooth/nm-device-bt.c index 68209d8a..e79251ce 100644 --- a/src/devices/bluetooth/nm-device-bt.c +++ b/src/devices/bluetooth/nm-device-bt.c @@ -23,7 +23,6 @@ #include "nm-device-bt.h" #include <stdio.h> -#include <string.h> #include "nm-bluez-common.h" #include "nm-bluez-device.h" @@ -39,6 +38,7 @@ #include "settings/nm-settings-connection.h" #include "nm-utils.h" #include "nm-bt-error.h" +#include "nm-ip4-config.h" #include "platform/nm-platform.h" #include "devices/wwan/nm-modem-manager.h" @@ -398,9 +398,9 @@ ppp_failed (NMModem *modem, case NM_DEVICE_STATE_SECONDARIES: case NM_DEVICE_STATE_ACTIVATED: if (nm_device_activate_ip4_state_in_conf (device)) - nm_device_activate_schedule_ip4_config_timeout (device); + nm_device_activate_schedule_ip_config_timeout (device, AF_INET); else if (nm_device_activate_ip6_state_in_conf (device)) - nm_device_activate_schedule_ip6_config_timeout (device); + nm_device_activate_schedule_ip_config_timeout (device, AF_INET6); else if (nm_device_activate_ip4_state_done (device)) { nm_device_ip_method_failed (device, AF_INET, @@ -542,7 +542,7 @@ modem_ip4_config_result (NMModem *modem, AF_INET, NM_DEVICE_STATE_REASON_IP_CONFIG_UNAVAILABLE); } else - nm_device_activate_schedule_ip4_config_result (device, config); + nm_device_activate_schedule_ip_config_result (device, AF_INET, NM_IP_CONFIG_CAST (config)); } static void @@ -899,33 +899,29 @@ act_stage2_config (NMDevice *device, NMDeviceStateReason *out_failure_reason) } static NMActStageReturn -act_stage3_ip4_config_start (NMDevice *device, - NMIP4Config **out_config, - NMDeviceStateReason *out_failure_reason) +act_stage3_ip_config_start (NMDevice *device, + int addr_family, + gpointer *out_config, + NMDeviceStateReason *out_failure_reason) { NMDeviceBtPrivate *priv = NM_DEVICE_BT_GET_PRIVATE ((NMDeviceBt *) device); + nm_assert_addr_family (addr_family); + if (priv->bt_type == NM_BT_CAPABILITY_DUN) { - return nm_modem_stage3_ip4_config_start (priv->modem, - device, - NM_DEVICE_CLASS (nm_device_bt_parent_class), - out_failure_reason); + if (addr_family == AF_INET) { + return nm_modem_stage3_ip4_config_start (priv->modem, + device, + NM_DEVICE_CLASS (nm_device_bt_parent_class), + out_failure_reason); + } else { + return nm_modem_stage3_ip6_config_start (priv->modem, + device, + out_failure_reason); + } } - return NM_DEVICE_CLASS (nm_device_bt_parent_class)->act_stage3_ip4_config_start (device, out_config, out_failure_reason); -} - -static NMActStageReturn -act_stage3_ip6_config_start (NMDevice *device, - NMIP6Config **out_config, - NMDeviceStateReason *out_failure_reason) -{ - NMDeviceBtPrivate *priv = NM_DEVICE_BT_GET_PRIVATE ((NMDeviceBt *) device); - - if (priv->bt_type == NM_BT_CAPABILITY_DUN) - return nm_modem_stage3_ip6_config_start (priv->modem, device, out_failure_reason); - - return NM_DEVICE_CLASS (nm_device_bt_parent_class)->act_stage3_ip6_config_start (device, out_config, out_failure_reason); + return NM_DEVICE_CLASS (nm_device_bt_parent_class)->act_stage3_ip_config_start (device, addr_family, out_config, out_failure_reason); } static void @@ -1204,8 +1200,7 @@ nm_device_bt_class_init (NMDeviceBtClass *klass) device_class->can_auto_connect = can_auto_connect; device_class->deactivate = deactivate; device_class->act_stage2_config = act_stage2_config; - device_class->act_stage3_ip4_config_start = act_stage3_ip4_config_start; - device_class->act_stage3_ip6_config_start = act_stage3_ip6_config_start; + device_class->act_stage3_ip_config_start = act_stage3_ip_config_start; device_class->check_connection_compatible = check_connection_compatible; device_class->check_connection_available = check_connection_available; device_class->complete_connection = complete_connection; diff --git a/src/devices/nm-acd-manager.c b/src/devices/nm-acd-manager.c index a0a175be..a8f7a63a 100644 --- a/src/devices/nm-acd-manager.c +++ b/src/devices/nm-acd-manager.c @@ -99,7 +99,7 @@ static const char * acd_error_to_string (int error) { if (error < 0) - return g_strerror (-error); + return nm_strerror_native (-error); switch (error) { case _N_ACD_E_SUCCESS: diff --git a/src/devices/nm-device-bond.c b/src/devices/nm-device-bond.c index 78cba9bb..6dabdfe8 100644 --- a/src/devices/nm-device-bond.c +++ b/src/devices/nm-device-bond.c @@ -22,7 +22,6 @@ #include "nm-device-bond.h" -#include <errno.h> #include <stdlib.h> #include "NetworkManagerUtils.h" diff --git a/src/devices/nm-device-dummy.c b/src/devices/nm-device-dummy.c index eb90456a..47a45342 100644 --- a/src/devices/nm-device-dummy.c +++ b/src/devices/nm-device-dummy.c @@ -17,7 +17,6 @@ #include "nm-device-dummy.h" #include <stdlib.h> -#include <string.h> #include <sys/types.h> #include "nm-act-request.h" diff --git a/src/devices/nm-device-ethernet.c b/src/devices/nm-device-ethernet.c index 3b6fb35b..24c99f76 100644 --- a/src/devices/nm-device-ethernet.c +++ b/src/devices/nm-device-ethernet.c @@ -24,10 +24,8 @@ #include "nm-device-ethernet.h" #include <netinet/in.h> -#include <string.h> #include <stdlib.h> #include <unistd.h> -#include <errno.h> #include <libudev.h> #include "nm-device-private.h" @@ -984,9 +982,8 @@ ppp_ip4_config (NMPPPManager *ppp_manager, NMDevice *device = NM_DEVICE (user_data); /* Ignore PPP IP4 events that come in after initial configuration */ - if (nm_device_activate_ip4_state_in_conf (device)) { - nm_device_activate_schedule_ip4_config_result (device, config); - } + if (nm_device_activate_ip4_state_in_conf (device)) + nm_device_activate_schedule_ip_config_result (device, AF_INET, NM_IP_CONFIG_CAST (config)); } static NMActStageReturn @@ -1317,22 +1314,25 @@ act_stage2_config (NMDevice *device, NMDeviceStateReason *out_failure_reason) } static NMActStageReturn -act_stage3_ip4_config_start (NMDevice *device, - NMIP4Config **out_config, - NMDeviceStateReason *out_failure_reason) +act_stage3_ip_config_start (NMDevice *device, + int addr_family, + gpointer *out_config, + NMDeviceStateReason *out_failure_reason) { NMSettingConnection *s_con; const char *connection_type; - s_con = nm_device_get_applied_setting (device, NM_TYPE_SETTING_CONNECTION); + if (addr_family == AF_INET) { + s_con = nm_device_get_applied_setting (device, NM_TYPE_SETTING_CONNECTION); - g_return_val_if_fail (s_con, NM_ACT_STAGE_RETURN_FAILURE); + g_return_val_if_fail (s_con, NM_ACT_STAGE_RETURN_FAILURE); - connection_type = nm_setting_connection_get_connection_type (s_con); - if (!strcmp (connection_type, NM_SETTING_PPPOE_SETTING_NAME)) - return pppoe_stage3_ip4_config_start (NM_DEVICE_ETHERNET (device), out_failure_reason); + connection_type = nm_setting_connection_get_connection_type (s_con); + if (!strcmp (connection_type, NM_SETTING_PPPOE_SETTING_NAME)) + return pppoe_stage3_ip4_config_start (NM_DEVICE_ETHERNET (device), out_failure_reason); + } - return NM_DEVICE_CLASS (nm_device_ethernet_parent_class)->act_stage3_ip4_config_start (device, out_config, out_failure_reason); + return NM_DEVICE_CLASS (nm_device_ethernet_parent_class)->act_stage3_ip_config_start (device, addr_family, out_config, out_failure_reason); } static guint32 @@ -1794,7 +1794,7 @@ nm_device_ethernet_class_init (NMDeviceEthernetClass *klass) device_class->act_stage1_prepare = act_stage1_prepare; device_class->act_stage2_config = act_stage2_config; - device_class->act_stage3_ip4_config_start = act_stage3_ip4_config_start; + device_class->act_stage3_ip_config_start = act_stage3_ip_config_start; device_class->get_configured_mtu = get_configured_mtu; device_class->deactivate = deactivate; device_class->get_s390_subchannels = get_s390_subchannels; diff --git a/src/devices/nm-device-factory.c b/src/devices/nm-device-factory.c index a11ead6e..30aca038 100644 --- a/src/devices/nm-device-factory.c +++ b/src/devices/nm-device-factory.c @@ -24,8 +24,6 @@ #include <sys/types.h> #include <sys/stat.h> -#include <errno.h> -#include <string.h> #include <gmodule.h> #include "platform/nm-platform.h" diff --git a/src/devices/nm-device-ip-tunnel.c b/src/devices/nm-device-ip-tunnel.c index ca5f9c3f..96275947 100644 --- a/src/devices/nm-device-ip-tunnel.c +++ b/src/devices/nm-device-ip-tunnel.c @@ -22,7 +22,6 @@ #include "nm-device-ip-tunnel.h" -#include <string.h> #include <netinet/in.h> #include <linux/if.h> #include <linux/ip.h> @@ -149,9 +148,13 @@ update_properties_from_ifindex (NMDevice *device, int ifindex) NMDeviceIPTunnel *self = NM_DEVICE_IP_TUNNEL (device); NMDeviceIPTunnelPrivate *priv = NM_DEVICE_IP_TUNNEL_GET_PRIVATE (self); int parent_ifindex = 0; - in_addr_t local4 = 0, remote4 = 0; - struct in6_addr local6 = { 0 }, remote6 = { 0 }; - guint8 ttl = 0, tos = 0, encap_limit = 0; + in_addr_t local4 = 0; + in_addr_t remote4 = 0; + struct in6_addr local6 = IN6ADDR_ANY_INIT; + struct in6_addr remote6 = IN6ADDR_ANY_INIT; + guint8 ttl = 0; + guint8 tos = 0; + guint8 encap_limit = 0; gboolean pmtud = FALSE; guint32 flow_label = 0; NMIPTunnelFlags flags = NM_IP_TUNNEL_FLAG_NONE; diff --git a/src/devices/nm-device-macvlan.c b/src/devices/nm-device-macvlan.c index bb629713..aa2a0ac0 100644 --- a/src/devices/nm-device-macvlan.c +++ b/src/devices/nm-device-macvlan.c @@ -22,7 +22,6 @@ #include "nm-device-macvlan.h" -#include <string.h> #include <linux/if_link.h> #include "nm-device-private.h" diff --git a/src/devices/nm-device-ppp.c b/src/devices/nm-device-ppp.c index 2f565d4b..3c310146 100644 --- a/src/devices/nm-device-ppp.c +++ b/src/devices/nm-device-ppp.c @@ -16,6 +16,7 @@ #include "nm-device-ppp.h" +#include "nm-ip4-config.h" #include "nm-act-request.h" #include "nm-device-factory.h" #include "nm-device-private.h" @@ -106,7 +107,7 @@ ppp_ip4_config (NMPPPManager *ppp_manager, if (nm_device_get_state (device) == NM_DEVICE_STATE_IP_CONFIG) { if (nm_device_activate_ip4_state_in_conf (device)) { - nm_device_activate_schedule_ip4_config_result (device, config); + nm_device_activate_schedule_ip_config_result (device, AF_INET, NM_IP_CONFIG_CAST (config)); return; } } else { @@ -172,23 +173,31 @@ act_stage2_config (NMDevice *device, NMDeviceStateReason *out_failure_reason) } static NMActStageReturn -act_stage3_ip4_config_start (NMDevice *device, - NMIP4Config **out_config, - NMDeviceStateReason *out_failure_reason) +act_stage3_ip_config_start (NMDevice *device, + int addr_family, + gpointer *out_config, + NMDeviceStateReason *out_failure_reason) { - NMDevicePpp *self = NM_DEVICE_PPP (device); - NMDevicePppPrivate *priv = NM_DEVICE_PPP_GET_PRIVATE (self); + if (addr_family == AF_INET) { + NMDevicePpp *self = NM_DEVICE_PPP (device); + NMDevicePppPrivate *priv = NM_DEVICE_PPP_GET_PRIVATE (self); + + if (priv->ip4_config) { + if (out_config) + *out_config = g_steal_pointer (&priv->ip4_config); + else + g_clear_object (&priv->ip4_config); + return NM_ACT_STAGE_RETURN_SUCCESS; + } - if (priv->ip4_config) { - if (out_config) - *out_config = g_steal_pointer (&priv->ip4_config); - else - g_clear_object (&priv->ip4_config); - return NM_ACT_STAGE_RETURN_SUCCESS; + /* Wait IPCP termination */ + return NM_ACT_STAGE_RETURN_POSTPONE; } - /* Wait IPCP termination */ - return NM_ACT_STAGE_RETURN_POSTPONE; + return NM_DEVICE_CLASS (nm_device_ppp_parent_class)->act_stage3_ip_config_start (device, + addr_family, + out_config, + out_failure_reason); } static gboolean @@ -270,7 +279,7 @@ nm_device_ppp_class_init (NMDevicePppClass *klass) device_class->link_types = NM_DEVICE_DEFINE_LINK_TYPES (NM_LINK_TYPE_PPP); device_class->act_stage2_config = act_stage2_config; - device_class->act_stage3_ip4_config_start = act_stage3_ip4_config_start; + device_class->act_stage3_ip_config_start = act_stage3_ip_config_start; device_class->create_and_realize = create_and_realize; device_class->deactivate = deactivate; device_class->get_generic_capabilities = get_generic_capabilities; diff --git a/src/devices/nm-device-private.h b/src/devices/nm-device-private.h index 6c0f473d..6e2372ab 100644 --- a/src/devices/nm-device-private.h +++ b/src/devices/nm-device-private.h @@ -26,6 +26,14 @@ /* This file should only be used by subclasses of NMDevice */ +typedef enum { + NM_DEVICE_IP_STATE_NONE, + NM_DEVICE_IP_STATE_WAIT, + NM_DEVICE_IP_STATE_CONF, + NM_DEVICE_IP_STATE_DONE, + NM_DEVICE_IP_STATE_FAIL, +} NMDeviceIPState; + enum NMActStageReturn { NM_ACT_STAGE_RETURN_FAILURE = 0, /* Hard failure of activation */ NM_ACT_STAGE_RETURN_SUCCESS, /* Activation stage done */ @@ -75,19 +83,51 @@ void nm_device_set_firmware_missing (NMDevice *self, gboolean missing); void nm_device_activate_schedule_stage1_device_prepare (NMDevice *device); void nm_device_activate_schedule_stage2_device_config (NMDevice *device); -void nm_device_activate_schedule_ip4_config_result(NMDevice *device, NMIP4Config *config); -void nm_device_activate_schedule_ip4_config_timeout (NMDevice *device); - -void nm_device_activate_schedule_ip6_config_result (NMDevice *device); -void nm_device_activate_schedule_ip6_config_timeout (NMDevice *device); - -gboolean nm_device_activate_ip4_state_in_conf (NMDevice *device); -gboolean nm_device_activate_ip4_state_in_wait (NMDevice *device); -gboolean nm_device_activate_ip4_state_done (NMDevice *device); - -gboolean nm_device_activate_ip6_state_in_conf (NMDevice *device); -gboolean nm_device_activate_ip6_state_in_wait (NMDevice *device); -gboolean nm_device_activate_ip6_state_done (NMDevice *device); +void nm_device_activate_schedule_ip_config_result (NMDevice *device, + int addr_family, + NMIPConfig *config); + +void nm_device_activate_schedule_ip_config_timeout (NMDevice *device, + int addr_family); + +NMDeviceIPState nm_device_activate_get_ip_state (NMDevice *self, + int addr_family); + +static inline gboolean +nm_device_activate_ip4_state_in_conf (NMDevice *self) +{ + return nm_device_activate_get_ip_state (self, AF_INET) == NM_DEVICE_IP_STATE_CONF; +} + +static inline gboolean +nm_device_activate_ip4_state_in_wait (NMDevice *self) +{ + return nm_device_activate_get_ip_state (self, AF_INET) == NM_DEVICE_IP_STATE_WAIT; +} + +static inline gboolean +nm_device_activate_ip4_state_done (NMDevice *self) +{ + return nm_device_activate_get_ip_state (self, AF_INET) == NM_DEVICE_IP_STATE_DONE; +} + +static inline gboolean +nm_device_activate_ip6_state_in_conf (NMDevice *self) +{ + return nm_device_activate_get_ip_state (self, AF_INET6) == NM_DEVICE_IP_STATE_CONF; +} + +static inline gboolean +nm_device_activate_ip6_state_in_wait (NMDevice *self) +{ + return nm_device_activate_get_ip_state (self, AF_INET6) == NM_DEVICE_IP_STATE_WAIT; +} + +static inline gboolean +nm_device_activate_ip6_state_done (NMDevice *self) +{ + return nm_device_activate_get_ip_state (self, AF_INET6) == NM_DEVICE_IP_STATE_DONE; +} void nm_device_set_dhcp_anycast_address (NMDevice *device, const char *addr); @@ -106,8 +146,9 @@ void nm_device_queue_recheck_available (NMDevice *device, NMDeviceStateReason available_reason, NMDeviceStateReason unavailable_reason); -void nm_device_set_wwan_ip4_config (NMDevice *device, NMIP4Config *config); -void nm_device_set_wwan_ip6_config (NMDevice *device, NMIP6Config *config); +void nm_device_set_dev2_ip_config (NMDevice *device, + int addr_family, + NMIPConfig *config); gboolean nm_device_hw_addr_is_explict (NMDevice *device); @@ -118,6 +159,12 @@ gboolean nm_device_sysctl_ip_conf_set (NMDevice *self, const char *property, const char *value); +NMIP4Config *nm_device_ip4_config_new (NMDevice *self); + +NMIP6Config *nm_device_ip6_config_new (NMDevice *self); + +NMIPConfig *nm_device_ip_config_new (NMDevice *self, int addr_family); + /*****************************************************************************/ gint64 nm_device_get_configured_mtu_from_connection_default (NMDevice *self, diff --git a/src/devices/nm-device-tun.c b/src/devices/nm-device-tun.c index 3fe3dfd4..90360c9e 100644 --- a/src/devices/nm-device-tun.c +++ b/src/devices/nm-device-tun.c @@ -23,7 +23,6 @@ #include "nm-device-tun.h" #include <stdlib.h> -#include <string.h> #include <sys/types.h> #include <linux/if_tun.h> diff --git a/src/devices/nm-device-veth.c b/src/devices/nm-device-veth.c index 6f90758c..d7a59bae 100644 --- a/src/devices/nm-device-veth.c +++ b/src/devices/nm-device-veth.c @@ -20,9 +20,7 @@ #include "nm-default.h" -#include <errno.h> #include <stdlib.h> -#include <string.h> #include "nm-device-veth.h" #include "nm-device-private.h" diff --git a/src/devices/nm-device-vxlan.c b/src/devices/nm-device-vxlan.c index 50730320..fc73c099 100644 --- a/src/devices/nm-device-vxlan.c +++ b/src/devices/nm-device-vxlan.c @@ -22,8 +22,6 @@ #include "nm-device-vxlan.h" -#include <string.h> - #include "nm-device-private.h" #include "nm-manager.h" #include "platform/nm-platform.h" diff --git a/src/devices/nm-device-wireguard.c b/src/devices/nm-device-wireguard.c index 62ec0274..a9eb1ab4 100644 --- a/src/devices/nm-device-wireguard.c +++ b/src/devices/nm-device-wireguard.c @@ -21,24 +21,128 @@ #include "nm-device-wireguard.h" +#include "nm-setting-wireguard.h" +#include "nm-core-internal.h" +#include "nm-utils/nm-secret-utils.h" #include "nm-device-private.h" #include "platform/nm-platform.h" +#include "platform/nmp-object.h" #include "nm-device-factory.h" +#include "nm-active-connection.h" +#include "nm-act-request.h" +#include "dns/nm-dns-manager.h" #include "nm-device-logging.h" _LOG_DECLARE_SELF(NMDeviceWireGuard); /*****************************************************************************/ +/* TODO: activate profile with peer preshared-key-flags=2. On first activation, the secret is + * requested (good). Enter it and connect. Reactivate the profile, now there is no password + * prompt, as the secret is cached (good??). */ + +/* TODO: unlike for other VPNs, we don't inject a direct route to the peers. That means, + * you might get a routing sceneraio where the peer (VPN server) is reachable via the VPN. + * How we handle adding routes to external gateway for other peers, has severe issues + * as well. We may use policy-routing like wg-quick does. See also disussions at + * https://www.wireguard.com/netns/#improving-the-classic-solutions */ + +/* TODO: honor the TTL of DNS to determine when to retry resolving endpoints. */ + +/* TODO: when we get multiple IP addresses when resolving a peer endpoint. We currently + * just take the first from GAI. We should only accept AAAA/IPv6 if we also have a suitable + * IPv6 address. The problem is, that we have to recheck that when IP addressing on other + * interfaces changes. This makes it almost too cumbersome to implement. */ + +/*****************************************************************************/ + +G_STATIC_ASSERT (NM_WIREGUARD_PUBLIC_KEY_LEN == NMP_WIREGUARD_PUBLIC_KEY_LEN); +G_STATIC_ASSERT (NM_WIREGUARD_SYMMETRIC_KEY_LEN == NMP_WIREGUARD_SYMMETRIC_KEY_LEN); + +/*****************************************************************************/ + +#define LINK_CONFIG_RATE_LIMIT_NSEC (50 * NM_UTILS_NS_PER_MSEC) + +/* a special @next_try_at_nsec timestamp indicating that we should try again as soon as possible. */ +#define NEXT_TRY_AT_NSEC_ASAP ((gint64) G_MAXINT64) + +/* a special @next_try_at_nsec timestamp that is + * - positive (indicating resolve-checks are enabled) + * - already in the past (we use the absolute timestamp of 1nsec for that). */ +#define NEXT_TRY_AT_NSEC_PAST ((gint64) 1) + +/* like %NEXT_TRY_AT_NSEC_ASAP, but used for indicating to retry ASAP for a @retry_in_msec value. + * That is a relative time duraction, contrary to @next_try_at_nsec which is an absolute + * timestamp. */ +#define RETRY_IN_MSEC_ASAP ((gint64) G_MAXINT64) + +#define RETRY_IN_MSEC_MAX ((gint64) (30 * 60 * 1000)) + +typedef enum { + LINK_CONFIG_MODE_FULL, + LINK_CONFIG_MODE_REAPPLY, + LINK_CONFIG_MODE_ASSUME, + LINK_CONFIG_MODE_ENDPOINTS, +} LinkConfigMode; + +typedef struct { + GCancellable *cancellable; + + NMSockAddrUnion sockaddr; + + /* the timestamp (in nm_utils_get_monotonic_timestamp_ns() scale) when we want + * to retry resolving the endpoint (again). + * + * It may be set to %NEXT_TRY_AT_NSEC_ASAP to indicate to re-resolve as soon as possible. + * + * A @sockaddr is either fixed or it has + * - @cancellable set to indicate an ongoing request + * - @next_try_at_nsec set to a positive value, indicating when + * we ought to retry. */ + gint64 next_try_at_nsec; + + guint resolv_fail_count; +} PeerEndpointResolveData; + +typedef struct { + NMWireGuardPeer *peer; + + NMDeviceWireGuard *self; + + CList lst_peers; + + PeerEndpointResolveData ep_resolv; + + /* dirty flag used during _peers_update_all(). */ + bool dirty_update_all:1; +} PeerData; + NM_GOBJECT_PROPERTIES_DEFINE (NMDeviceWireGuard, PROP_PUBLIC_KEY, PROP_LISTEN_PORT, PROP_FWMARK, ); +typedef struct { + + NMDnsManager *dns_manager; + + NMPlatformLnkWireGuard lnk_curr; + NMActRequestGetSecretsCallId *secrets_call_id; + + CList lst_peers_head; + GHashTable *peers; + + gint64 resolve_next_try_at; + guint resolve_next_try_id; + + gint64 link_config_last_at; + guint link_config_delayed_id; +} NMDeviceWireGuardPrivate; + struct _NMDeviceWireGuard { NMDevice parent; - NMPlatformLnkWireGuard props; + NMDeviceWireGuardPrivate _priv; }; struct _NMDeviceWireGuardClass { @@ -47,25 +151,710 @@ struct _NMDeviceWireGuardClass { G_DEFINE_TYPE (NMDeviceWireGuard, nm_device_wireguard, NM_TYPE_DEVICE) -/******************************************************************/ +#define NM_DEVICE_WIREGUARD_GET_PRIVATE(self) _NM_GET_PRIVATE (self, NMDeviceWireGuard, NM_IS_DEVICE_WIREGUARD, NMDevice) + +/*****************************************************************************/ + +static void _peers_resolve_start (NMDeviceWireGuard *self, + PeerData *peer_data); + +static void _peers_resolve_retry_reschedule (NMDeviceWireGuard *self, + gint64 new_next_try_at_nsec); + +static gboolean link_config_delayed_resolver_cb (gpointer user_data); + +static gboolean link_config_delayed_ratelimit_cb (gpointer user_data); + +/*****************************************************************************/ + +NM_UTILS_LOOKUP_STR_DEFINE_STATIC (_link_config_mode_to_string, LinkConfigMode, + NM_UTILS_LOOKUP_DEFAULT_NM_ASSERT (NULL), + NM_UTILS_LOOKUP_ITEM (LINK_CONFIG_MODE_FULL, "full"), + NM_UTILS_LOOKUP_ITEM (LINK_CONFIG_MODE_REAPPLY, "reapply"), + NM_UTILS_LOOKUP_ITEM (LINK_CONFIG_MODE_ASSUME, "assume"), + NM_UTILS_LOOKUP_ITEM (LINK_CONFIG_MODE_ENDPOINTS, "endpoints"), +); + +/*****************************************************************************/ + +static gboolean +_peer_data_equal (gconstpointer ptr_a, gconstpointer ptr_b) +{ + const PeerData *peer_data_a = ptr_a; + const PeerData *peer_data_b = ptr_b; + + return nm_streq (nm_wireguard_peer_get_public_key (peer_data_a->peer), + nm_wireguard_peer_get_public_key (peer_data_b->peer)); +} + +static guint +_peer_data_hash (gconstpointer ptr) +{ + const PeerData *peer_data = ptr; + + return nm_hash_str (nm_wireguard_peer_get_public_key (peer_data->peer)); +} + +static PeerData * +_peers_find (NMDeviceWireGuardPrivate *priv, + NMWireGuardPeer *peer) +{ + nm_assert (peer); + + G_STATIC_ASSERT_EXPR (G_STRUCT_OFFSET (PeerData, peer) == 0); + + return g_hash_table_lookup (priv->peers, &peer); +} + +static void +_peers_remove (NMDeviceWireGuardPrivate *priv, + PeerData *peer_data) +{ + nm_assert (peer_data); + nm_assert (g_hash_table_lookup (priv->peers, peer_data) == peer_data); + + if (!g_hash_table_remove (priv->peers, peer_data)) + nm_assert_not_reached (); + + c_list_unlink_stale (&peer_data->lst_peers); + nm_wireguard_peer_unref (peer_data->peer); + nm_clear_g_cancellable (&peer_data->ep_resolv.cancellable); + g_slice_free (PeerData, peer_data); + + if (c_list_is_empty (&peer_data->lst_peers)) { + nm_clear_g_source (&priv->resolve_next_try_id); + nm_clear_g_source (&priv->link_config_delayed_id); + } +} + +static PeerData * +_peers_add (NMDeviceWireGuard *self, + NMWireGuardPeer *peer) +{ + NMDeviceWireGuardPrivate *priv = NM_DEVICE_WIREGUARD_GET_PRIVATE (self); + PeerData *peer_data; + + nm_assert (peer); + nm_assert (nm_wireguard_peer_is_sealed (peer)); + nm_assert (!_peers_find (priv, peer)); + + peer_data = g_slice_new (PeerData); + *peer_data = (PeerData) { + .self = self, + .peer = nm_wireguard_peer_ref (peer), + .ep_resolv = { + .sockaddr = NM_SOCK_ADDR_UNION_INIT_UNSPEC, + }, + }; + + c_list_link_tail (&priv->lst_peers_head, &peer_data->lst_peers); + if (!nm_g_hash_table_add (priv->peers, peer_data)) + nm_assert_not_reached (); + return peer_data; +} + +static gboolean +_peers_resolve_retry_timeout (gpointer user_data) +{ + NMDeviceWireGuard *self = user_data; + NMDeviceWireGuardPrivate *priv = NM_DEVICE_WIREGUARD_GET_PRIVATE (self); + PeerData *peer_data; + gint64 now; + gint64 next; + + priv->resolve_next_try_id = 0; + + _LOGT (LOGD_DEVICE, "wireguard-peers: rechecking peer endpoints..."); + + now = nm_utils_get_monotonic_timestamp_ns (); + next = G_MAXINT64; + c_list_for_each_entry (peer_data, &priv->lst_peers_head, lst_peers) { + if (peer_data->ep_resolv.next_try_at_nsec <= 0) + continue; + + if (peer_data->ep_resolv.cancellable) { + /* we are currently resolving a name. We don't need the global + * watchdog to guard this peer. No need to adjust @next for + * this one, when the currently ongoing resolving completes, we + * may reschedule. Skip. */ + continue; + } + + if ( peer_data->ep_resolv.next_try_at_nsec == NEXT_TRY_AT_NSEC_ASAP + || now >= peer_data->ep_resolv.next_try_at_nsec) { + _peers_resolve_start (self, peer_data); + /* same here. Now we are resolving. We don't need the global + * watchdog. Skip w.r.t. finding @next. */ + continue; + } + + if (next > peer_data->ep_resolv.next_try_at_nsec) + next = peer_data->ep_resolv.next_try_at_nsec; + } + if (next < G_MAXINT64) + _peers_resolve_retry_reschedule (self, next); + + return G_SOURCE_REMOVE; +} + +static void +_peers_resolve_retry_reschedule (NMDeviceWireGuard *self, + gint64 new_next_try_at_nsec) +{ + NMDeviceWireGuardPrivate *priv = NM_DEVICE_WIREGUARD_GET_PRIVATE (self); + guint32 interval_ms; + gint64 now; + + nm_assert (new_next_try_at_nsec > 0); + nm_assert (new_next_try_at_nsec != NEXT_TRY_AT_NSEC_ASAP); + + if ( priv->resolve_next_try_id + && priv->resolve_next_try_at <= new_next_try_at_nsec) { + /* we already have an earlier timeout scheduled (possibly for + * another peer that expires sooner). Don't reschedule now. + * Even if the scheduled timeout expires too early, we will + * compute the right next-timeout and reschedule then. */ + return; + } + + now = nm_utils_get_monotonic_timestamp_ns (); + + /* schedule at most one day ahead. No problem if we expire earlier + * than expected. Also, rate-limit to 500 msec. */ + interval_ms = NM_CLAMP ((new_next_try_at_nsec - now) / NM_UTILS_NS_PER_MSEC, + (gint64) 500, + (gint64) (24*60*60*1000)); + + _LOGT (LOGD_DEVICE, "wireguard-peers: schedule rechecking peer endpoints in %u msec", + interval_ms); + + nm_clear_g_source (&priv->resolve_next_try_id); + priv->resolve_next_try_at = new_next_try_at_nsec; + priv->resolve_next_try_id = g_timeout_add (interval_ms, + _peers_resolve_retry_timeout, + self); +} + +static void +_peers_resolve_retry_reschedule_for_peer (NMDeviceWireGuard *self, + PeerData *peer_data, + gint64 retry_in_msec) +{ + nm_assert (retry_in_msec >= 0); + + if (retry_in_msec == RETRY_IN_MSEC_ASAP) { + _peers_resolve_start (self, peer_data); + return; + } + + peer_data->ep_resolv.next_try_at_nsec = nm_utils_get_monotonic_timestamp_ns () + + (retry_in_msec * NM_UTILS_NS_PER_MSEC); + _peers_resolve_retry_reschedule (self, peer_data->ep_resolv.next_try_at_nsec); +} + +static gint64 +_peers_retry_in_msec (PeerData *peer_data, + gboolean after_failure) +{ + if (peer_data->ep_resolv.next_try_at_nsec == NEXT_TRY_AT_NSEC_ASAP) { + peer_data->ep_resolv.resolv_fail_count = 0; + return RETRY_IN_MSEC_ASAP; + } + + if (after_failure) { + if (peer_data->ep_resolv.resolv_fail_count < G_MAXUINT) + peer_data->ep_resolv.resolv_fail_count++; + } else + peer_data->ep_resolv.resolv_fail_count = 0; + + if (!after_failure) + return RETRY_IN_MSEC_MAX; -static GVariant * -get_public_key_as_variant (const NMDeviceWireGuard *self) + if (peer_data->ep_resolv.resolv_fail_count > 20) + return RETRY_IN_MSEC_MAX; + + /* double the retry-time, starting with one second. */ + return NM_MIN (RETRY_IN_MSEC_MAX, + (1u << peer_data->ep_resolv.resolv_fail_count) * 500); +} + +static void +_peers_resolve_cb (GObject *source_object, + GAsyncResult *res, + gpointer user_data) +{ + NMDeviceWireGuard *self; + PeerData *peer_data; + gs_free_error GError *resolv_error = NULL; + GList *list; + gboolean changed = FALSE; + NMSockAddrUnion sockaddr; + gint64 retry_in_msec; + char s_sockaddr[100]; + char s_retry[100]; + + list = g_resolver_lookup_by_name_finish (G_RESOLVER (source_object), res, &resolv_error); + + if (nm_utils_error_is_cancelled (resolv_error, FALSE)) + return; + + peer_data = user_data; + self = peer_data->self; + + g_clear_object (&peer_data->ep_resolv.cancellable); + + nm_assert ((!resolv_error) != (!list)); + +#define _retry_in_msec_to_string(retry_in_msec, s_retry) \ + ({ \ + gint64 _retry_in_msec = (retry_in_msec); \ + \ + _retry_in_msec == RETRY_IN_MSEC_ASAP \ + ? "right away" \ + : nm_sprintf_buf (s_retry, "in %"G_GINT64_FORMAT" msec", _retry_in_msec); \ + }) + + if ( resolv_error + && !g_error_matches (resolv_error, G_RESOLVER_ERROR, G_RESOLVER_ERROR_NOT_FOUND)) { + retry_in_msec = _peers_retry_in_msec (peer_data, TRUE); + + _LOGT (LOGD_DEVICE, "wireguard-peer[%s]: failure to resolve endpoint \"%s\": %s (retry %s)", + nm_wireguard_peer_get_public_key (peer_data->peer), + nm_wireguard_peer_get_endpoint (peer_data->peer), + resolv_error->message, + _retry_in_msec_to_string (retry_in_msec, s_retry)); + + _peers_resolve_retry_reschedule_for_peer (self, peer_data, retry_in_msec); + return; + } + + sockaddr = (NMSockAddrUnion) NM_SOCK_ADDR_UNION_INIT_UNSPEC; + + if (!resolv_error) { + GList *iter; + + for (iter = list; iter; iter = iter->next) { + GInetAddress *a = iter->data; + GSocketFamily f = g_inet_address_get_family (a); + + if (f == G_SOCKET_FAMILY_IPV4) { + nm_assert (g_inet_address_get_native_size (a) == sizeof (struct in_addr)); + sockaddr.in = (struct sockaddr_in) { + .sin_family = AF_INET, + .sin_port = htons (nm_sock_addr_endpoint_get_port (_nm_wireguard_peer_get_endpoint (peer_data->peer))), + }; + memcpy (&sockaddr.in.sin_addr, g_inet_address_to_bytes (a), sizeof (struct in_addr)); + break; + } + if (f == G_SOCKET_FAMILY_IPV6) { + nm_assert (g_inet_address_get_native_size (a) == sizeof (struct in6_addr)); + sockaddr.in6 = (struct sockaddr_in6) { + .sin6_family = AF_INET6, + .sin6_port = htons (nm_sock_addr_endpoint_get_port (_nm_wireguard_peer_get_endpoint (peer_data->peer))), + .sin6_scope_id = 0, + .sin6_flowinfo = 0, + }; + memcpy (&sockaddr.in6.sin6_addr, g_inet_address_to_bytes (a), sizeof (struct in6_addr)); + break; + } + } + + g_list_free_full (list, g_object_unref); + } + + if (sockaddr.sa.sa_family == AF_UNSPEC) { + /* we failed to resolve the name. There is no need to reset the previous + * sockaddr. Either it was already AF_UNSPEC, or we had a good name + * from resolving before. In that case, we don't want to throw away + * a possibly good IP address, since WireGuard supports automatic roaming + * anyway. Either the IP address is still good (and we would wrongly + * reject it), or it isn't -- in which case it does not hurt much. */ + } else { + if (nm_sock_addr_union_cmp (&peer_data->ep_resolv.sockaddr, &sockaddr) != 0) + changed = TRUE; + peer_data->ep_resolv.sockaddr = sockaddr; + } + + if ( resolv_error + || peer_data->ep_resolv.sockaddr.sa.sa_family == AF_UNSPEC) { + /* while it technically did not fail, something is probably odd. Retry frequently to + * resolve the name, like we would do for normal failures. */ + retry_in_msec = _peers_retry_in_msec (peer_data, TRUE); + _LOGT (LOGD_DEVICE, "wireguard-peer[%s]: no %sresults for endpoint \"%s\" (retry %s)", + nm_wireguard_peer_get_public_key (peer_data->peer), + resolv_error ? "" : "suitable ", + nm_wireguard_peer_get_endpoint (peer_data->peer), + _retry_in_msec_to_string (retry_in_msec, s_retry)); + } else { + retry_in_msec = _peers_retry_in_msec (peer_data, FALSE); + _LOGT (LOGD_DEVICE, "wireguard-peer[%s]: endpoint \"%s\" resolved to %s (retry %s)", + nm_wireguard_peer_get_public_key (peer_data->peer), + nm_wireguard_peer_get_endpoint (peer_data->peer), + nm_sock_addr_union_to_string (&peer_data->ep_resolv.sockaddr, s_sockaddr, sizeof (s_sockaddr)), + _retry_in_msec_to_string (retry_in_msec, s_retry)); + } + + _peers_resolve_retry_reschedule_for_peer (self, peer_data, retry_in_msec); + + if (changed) { + NMDeviceWireGuardPrivate *priv = NM_DEVICE_WIREGUARD_GET_PRIVATE (self); + + /* schedule the job in the background, to give multiple resolve events time + * to complete. */ + nm_clear_g_source (&priv->link_config_delayed_id); + priv->link_config_delayed_id = g_idle_add_full (G_PRIORITY_DEFAULT_IDLE + 1, + link_config_delayed_resolver_cb, + self, + NULL); + } +} + +static void +_peers_resolve_start (NMDeviceWireGuard *self, + PeerData *peer_data) +{ + gs_unref_object GResolver *resolver = NULL; + const char *host; + + resolver = g_resolver_get_default (); + + nm_assert (!peer_data->ep_resolv.cancellable); + + peer_data->ep_resolv.cancellable = g_cancellable_new (); + + /* set a special next-try timestamp. It is positive, and indicates + * that we are in the process of trying. + * This timestamp however already lies in the past, but that is correct, + * because we are currently in the process of trying. We will determine + * a next-try timestamp once the try completes. */ + peer_data->ep_resolv.next_try_at_nsec = NEXT_TRY_AT_NSEC_PAST; + + host = nm_sock_addr_endpoint_get_host (_nm_wireguard_peer_get_endpoint (peer_data->peer)); + + g_resolver_lookup_by_name_async (resolver, + host, + peer_data->ep_resolv.cancellable, + _peers_resolve_cb, + peer_data); + + _LOGT (LOGD_DEVICE, "wireguard-peer[%s]: resolving name \"%s\" for endpoint \"%s\"...", + nm_wireguard_peer_get_public_key (peer_data->peer), + host, + nm_wireguard_peer_get_endpoint (peer_data->peer)); +} + +static void +_peers_resolve_reresolve_all (NMDeviceWireGuard *self) +{ + NMDeviceWireGuardPrivate *priv = NM_DEVICE_WIREGUARD_GET_PRIVATE (self); + PeerData *peer_data; + + c_list_for_each_entry (peer_data, &priv->lst_peers_head, lst_peers) { + if (peer_data->ep_resolv.cancellable) { + /* remember to retry when the currently ongoing request completes. */ + peer_data->ep_resolv.next_try_at_nsec = NEXT_TRY_AT_NSEC_ASAP; + } else if (peer_data->ep_resolv.next_try_at_nsec <= 0) { + /* this peer does not require resolving the name. Skip it. */ + } else { + /* we have a next-try scheduled. Restart right away. */ + peer_data->ep_resolv.resolv_fail_count = 0; + _peers_resolve_start (self, peer_data); + } + } +} + +static gboolean +_peers_update (NMDeviceWireGuard *self, + PeerData *peer_data, + NMWireGuardPeer *peer, + gboolean force_update) +{ + nm_auto_unref_wgpeer NMWireGuardPeer *old_peer = NULL; + NMSockAddrEndpoint *old_endpoint; + NMSockAddrEndpoint *endpoint; + gboolean endpoint_changed = FALSE; + gboolean changed; + NMSockAddrUnion sockaddr; + gboolean sockaddr_fixed; + char sockaddr_sbuf[100]; + + nm_assert (peer); + nm_assert (nm_wireguard_peer_is_sealed (peer)); + + if ( peer == peer_data->peer + && !force_update) + return FALSE; + + changed = (nm_wireguard_peer_cmp (peer, + peer_data->peer, + NM_SETTING_COMPARE_FLAG_EXACT) != 0); + + old_peer = peer_data->peer; + peer_data->peer = nm_wireguard_peer_ref (peer); + + old_endpoint = old_peer ? _nm_wireguard_peer_get_endpoint (old_peer) : NULL; + endpoint = peer ? _nm_wireguard_peer_get_endpoint (peer) : NULL; + + endpoint_changed = ( endpoint != old_endpoint + && ( !old_endpoint + || !endpoint + || !nm_streq (nm_sock_addr_endpoint_get_endpoint (old_endpoint), + nm_sock_addr_endpoint_get_endpoint (endpoint)))); + + if ( !force_update + && !endpoint_changed) { + /* nothing to do. */ + return changed; + } + + sockaddr = (NMSockAddrUnion) NM_SOCK_ADDR_UNION_INIT_UNSPEC; + sockaddr_fixed = TRUE; + if ( endpoint + && nm_sock_addr_endpoint_get_host (endpoint)) { + if (!nm_sock_addr_endpoint_get_fixed_sockaddr (endpoint, &sockaddr)) { + /* we have an endpoint, but it's not a static IP address. We need to resolve + * the names. */ + sockaddr_fixed = FALSE; + } + } + + if (nm_sock_addr_union_cmp (&peer_data->ep_resolv.sockaddr, &sockaddr) != 0) + changed = TRUE; + + nm_clear_g_cancellable (&peer_data->ep_resolv.cancellable); + + peer_data->ep_resolv = (PeerEndpointResolveData) { + .sockaddr = sockaddr, + .resolv_fail_count = 0, + .cancellable = NULL, + .next_try_at_nsec = 0, + }; + + if (!endpoint) { + _LOGT (LOGD_DEVICE, "wireguard-peer[%s]: no endpoint configured", + nm_wireguard_peer_get_public_key (peer_data->peer)); + } else if (!nm_sock_addr_endpoint_get_host (endpoint)) { + _LOGT (LOGD_DEVICE, "wireguard-peer[%s]: invalid endpoint \"%s\"", + nm_wireguard_peer_get_public_key (peer_data->peer), + nm_sock_addr_endpoint_get_endpoint (endpoint)); + } else if (sockaddr_fixed) { + _LOGT (LOGD_DEVICE, "wireguard-peer[%s]: fixed endpoint \"%s\" (%s)", + nm_wireguard_peer_get_public_key (peer_data->peer), + nm_sock_addr_endpoint_get_endpoint (endpoint), + nm_sock_addr_union_to_string (&peer_data->ep_resolv.sockaddr, sockaddr_sbuf, sizeof (sockaddr_sbuf))); + } else + _peers_resolve_start (self, peer_data); + + return changed; +} + +static void +_peers_remove_all (NMDeviceWireGuardPrivate *priv) { - return g_variant_new_fixed_array (G_VARIANT_TYPE_BYTE, - self->props.public_key, sizeof (self->props.public_key), 1); + PeerData *peer_data; + + while ((peer_data = c_list_first_entry (&priv->lst_peers_head, PeerData, lst_peers))) + _peers_remove (priv, peer_data); } static void +_peers_update_all (NMDeviceWireGuard *self, + NMSettingWireGuard *s_wg, + gboolean *out_peers_removed) +{ + NMDeviceWireGuardPrivate *priv = NM_DEVICE_WIREGUARD_GET_PRIVATE (self); + PeerData *peer_data_safe; + PeerData *peer_data; + guint i, n; + gboolean peers_removed = FALSE; + + c_list_for_each_entry (peer_data, &priv->lst_peers_head, lst_peers) + peer_data->dirty_update_all = TRUE; + + n = nm_setting_wireguard_get_peers_len (s_wg); + for (i = 0; i < n; i++) { + NMWireGuardPeer *peer = nm_setting_wireguard_get_peer (s_wg, i); + gboolean added = FALSE; + + peer_data = _peers_find (priv, peer); + if (!peer_data) { + peer_data = _peers_add (self, peer); + added = TRUE; + } + _peers_update (self, peer_data, peer, added); + peer_data->dirty_update_all = FALSE; + } + + c_list_for_each_entry_safe (peer_data, peer_data_safe, &priv->lst_peers_head, lst_peers) { + if (peer_data->dirty_update_all) { + _peers_remove (priv, peer_data); + peers_removed = TRUE; + } + } + + NM_SET_OUT (out_peers_removed, peers_removed); +} + +static void +_peers_get_platform_list (NMDeviceWireGuardPrivate *priv, + LinkConfigMode config_mode, + NMPWireGuardPeer **out_peers, + NMPlatformWireGuardChangePeerFlags **out_peer_flags, + guint *out_len, + GArray **out_allowed_ips_data) +{ + gs_free NMPWireGuardPeer *plpeers = NULL; + gs_free NMPlatformWireGuardChangePeerFlags *plpeer_flags = NULL; + gs_unref_array GArray *allowed_ips = NULL; + PeerData *peer_data; + guint i_good; + guint n_aip; + guint i_aip; + guint len; + guint i; + + nm_assert (out_peers && !*out_peers); + nm_assert (out_peer_flags && !*out_peer_flags); + nm_assert (out_len && *out_len == 0); + nm_assert (out_allowed_ips_data && !*out_allowed_ips_data); + + len = g_hash_table_size (priv->peers); + + nm_assert (len == c_list_length (&priv->lst_peers_head)); + + if (len == 0) + return; + + plpeers = g_new0 (NMPWireGuardPeer, len); + plpeer_flags = g_new0 (NMPlatformWireGuardChangePeerFlags, len); + + i_good = 0; + c_list_for_each_entry (peer_data, &priv->lst_peers_head, lst_peers) { + NMPlatformWireGuardChangePeerFlags *plf = &plpeer_flags[i_good]; + NMPWireGuardPeer *plp = &plpeers[i_good]; + NMSettingSecretFlags psk_secret_flags; + + if (!nm_utils_base64secret_decode (nm_wireguard_peer_get_public_key (peer_data->peer), + sizeof (plp->public_key), + plp->public_key)) + continue; + + *plf = NM_PLATFORM_WIREGUARD_CHANGE_PEER_FLAG_NONE; + + plp->persistent_keepalive_interval = nm_wireguard_peer_get_persistent_keepalive (peer_data->peer); + if (NM_IN_SET (config_mode, LINK_CONFIG_MODE_FULL, + LINK_CONFIG_MODE_REAPPLY)) + *plf |= NM_PLATFORM_WIREGUARD_CHANGE_PEER_FLAG_HAS_KEEPALIVE_INTERVAL; + + /* if the peer has an endpoint but it is not yet resolved (not ready), + * we still configure it and leave the endpoint unspecified. Later, + * when we can resolve the endpoint, we will update. */ + plp->endpoint = peer_data->ep_resolv.sockaddr; + if (plp->endpoint.sa.sa_family == AF_UNSPEC) { + /* we don't actually ever clear endpoints, if we don't have better information. */ + } else + *plf |= NM_PLATFORM_WIREGUARD_CHANGE_PEER_FLAG_HAS_ENDPOINT; + + if (NM_IN_SET (config_mode, LINK_CONFIG_MODE_FULL, + LINK_CONFIG_MODE_REAPPLY)) { + psk_secret_flags = nm_wireguard_peer_get_preshared_key_flags (peer_data->peer); + if (!NM_FLAGS_HAS (psk_secret_flags, NM_SETTING_SECRET_FLAG_NOT_REQUIRED)) { + if ( !nm_utils_base64secret_decode (nm_wireguard_peer_get_preshared_key (peer_data->peer), + sizeof (plp->preshared_key), + plp->preshared_key) + && config_mode == LINK_CONFIG_MODE_FULL) + goto skip; + } + *plf |= NM_PLATFORM_WIREGUARD_CHANGE_PEER_FLAG_HAS_PRESHARED_KEY; + } + + if ( NM_IN_SET (config_mode, LINK_CONFIG_MODE_FULL, + LINK_CONFIG_MODE_REAPPLY) + && ((n_aip = nm_wireguard_peer_get_allowed_ips_len (peer_data->peer)) > 0)) { + if (!allowed_ips) + allowed_ips = g_array_new (FALSE, FALSE, sizeof (NMPWireGuardAllowedIP)); + + *plf |= NM_PLATFORM_WIREGUARD_CHANGE_PEER_FLAG_HAS_ALLOWEDIPS + | NM_PLATFORM_WIREGUARD_CHANGE_PEER_FLAG_REPLACE_ALLOWEDIPS; + + plp->_construct_idx_start = allowed_ips->len; + for (i_aip = 0; i_aip < n_aip; i_aip++) { + const char *aip; + NMIPAddr addrbin = { }; + int addr_family; + gboolean valid; + int prefix; + + aip = nm_wireguard_peer_get_allowed_ip (peer_data->peer, i_aip, &valid); + if ( !valid + || !nm_utils_parse_inaddr_prefix_bin (AF_UNSPEC, + aip, + &addr_family, + &addrbin, + &prefix)) { + /* the address is really not expected to be invalid, because then + * the connection would not verify. Anyway, silently skip it. */ + continue; + } + + if (prefix == -1) + prefix = addr_family == AF_INET ? 32 : 128; + + g_array_append_val (allowed_ips, + ((NMPWireGuardAllowedIP) { + .family = addr_family, + .mask = prefix, + .addr = addrbin, + })); + } + plp->_construct_idx_end = allowed_ips->len; + } + + i_good++; + continue; + +skip: + memset (plp, 0, sizeof (*plp)); + } + + if (i_good == 0) + return; + + for (i = 0; i < i_good; i++) { + NMPWireGuardPeer *plp = &plpeers[i]; + guint l; + + if (plp->_construct_idx_end == 0) { + nm_assert (plp->_construct_idx_start == 0); + plp->allowed_ips = NULL; + plp->allowed_ips_len = 0; + } else { + nm_assert (plp->_construct_idx_start < plp->_construct_idx_end); + l = plp->_construct_idx_end - plp->_construct_idx_start; + plp->allowed_ips = &g_array_index (allowed_ips, NMPWireGuardAllowedIP, plp->_construct_idx_start); + plp->allowed_ips_len = l; + } + } + *out_peers = g_steal_pointer (&plpeers); + *out_peer_flags = g_steal_pointer (&plpeer_flags);; + *out_len = i_good; + *out_allowed_ips_data = g_steal_pointer (&allowed_ips); +} + +/*****************************************************************************/ + +static void update_properties (NMDevice *device) { NMDeviceWireGuard *self; + NMDeviceWireGuardPrivate *priv; const NMPlatformLink *plink; const NMPlatformLnkWireGuard *props = NULL; int ifindex; g_return_if_fail (NM_IS_DEVICE_WIREGUARD (device)); self = NM_DEVICE_WIREGUARD (device); + priv = NM_DEVICE_WIREGUARD_GET_PRIVATE (self); ifindex = nm_device_get_ifindex (device); props = nm_platform_link_get_lnk_wireguard (nm_device_get_platform (device), ifindex, &plink); @@ -78,16 +867,16 @@ update_properties (NMDevice *device) #define CHECK_PROPERTY_CHANGED(field, prop) \ G_STMT_START { \ - if (self->props.field != props->field) { \ - self->props.field = props->field; \ + if (priv->lnk_curr.field != props->field) { \ + priv->lnk_curr.field = props->field; \ _notify (self, prop); \ } \ } G_STMT_END #define CHECK_PROPERTY_CHANGED_ARRAY(field, prop) \ G_STMT_START { \ - if (memcmp (&self->props.field, &props->field, sizeof (props->field)) != 0) { \ - memcpy (&self->props.field, &props->field, sizeof (props->field)); \ + if (memcmp (&priv->lnk_curr.field, &props->field, sizeof (priv->lnk_curr.field)) != 0) { \ + memcpy (&priv->lnk_curr.field, &props->field, sizeof (priv->lnk_curr.field)); \ _notify (self, prop); \ } \ } G_STMT_END @@ -107,24 +896,655 @@ link_changed (NMDevice *device, update_properties (device); } +static NMDeviceCapabilities +get_generic_capabilities (NMDevice *dev) +{ + return NM_DEVICE_CAP_IS_SOFTWARE; +} + +/*****************************************************************************/ + +static gboolean +create_and_realize (NMDevice *device, + NMConnection *connection, + NMDevice *parent, + const NMPlatformLink **out_plink, + GError **error) +{ + const char *iface = nm_device_get_iface (device); + int r; + + g_return_val_if_fail (iface, FALSE); + + r = nm_platform_link_wireguard_add (nm_device_get_platform (device), iface, out_plink); + if (r < 0) { + g_set_error (error, NM_DEVICE_ERROR, NM_DEVICE_ERROR_CREATION_FAILED, + "Failed to create WireGuard interface '%s' for '%s': %s", + iface, + nm_connection_get_id (connection), + nm_strerror (r)); + return FALSE; + } + + return TRUE; +} + +/*****************************************************************************/ + +static void +_secrets_cancel (NMDeviceWireGuard *self) +{ + NMDeviceWireGuardPrivate *priv = NM_DEVICE_WIREGUARD_GET_PRIVATE (self); + + if (priv->secrets_call_id) + nm_act_request_cancel_secrets (NULL, priv->secrets_call_id); + nm_assert (!priv->secrets_call_id); +} + +static void +_secrets_cb (NMActRequest *req, + NMActRequestGetSecretsCallId *call_id, + NMSettingsConnection *connection, + GError *error, + gpointer user_data) +{ + NMDeviceWireGuard *self = NM_DEVICE_WIREGUARD (user_data); + NMDevice *device = NM_DEVICE (self); + NMDeviceWireGuardPrivate *priv; + + g_return_if_fail (NM_IS_DEVICE_WIREGUARD (self)); + g_return_if_fail (NM_IS_ACT_REQUEST (req)); + + priv = NM_DEVICE_WIREGUARD_GET_PRIVATE (self); + + g_return_if_fail (priv->secrets_call_id == call_id); + + priv->secrets_call_id = NULL; + + if (g_error_matches (error, G_IO_ERROR, G_IO_ERROR_CANCELLED)) + return; + + g_return_if_fail (req == nm_device_get_act_request (device)); + g_return_if_fail (nm_device_get_state (device) == NM_DEVICE_STATE_NEED_AUTH); + g_return_if_fail (nm_act_request_get_settings_connection (req) == connection); + + if (error) { + _LOGW (LOGD_ETHER, "%s", error->message); + nm_device_state_changed (device, + NM_DEVICE_STATE_FAILED, + NM_DEVICE_STATE_REASON_NO_SECRETS); + } else + nm_device_activate_schedule_stage1_device_prepare (device); +} + +static void +_secrets_get_secrets (NMDeviceWireGuard *self, + const char *setting_name, + NMSecretAgentGetSecretsFlags flags, + const char *const*hints) +{ + NMDeviceWireGuardPrivate *priv = NM_DEVICE_WIREGUARD_GET_PRIVATE (self); + NMActRequest *req; + + _secrets_cancel (self); + + req = nm_device_get_act_request (NM_DEVICE (self)); + g_return_if_fail (NM_IS_ACT_REQUEST (req)); + + priv->secrets_call_id = nm_act_request_get_secrets (req, + TRUE, + setting_name, + flags, + hints, + _secrets_cb, + self); + g_return_if_fail (priv->secrets_call_id); +} + +static NMActStageReturn +_secrets_handle_auth_or_fail (NMDeviceWireGuard *self, + NMActRequest *req, + gboolean new_secrets) +{ + NMConnection *applied_connection; + const char *setting_name; + gs_unref_ptrarray GPtrArray *hints = NULL; + + if (!nm_device_auth_retries_try_next (NM_DEVICE (self))) + return NM_ACT_STAGE_RETURN_FAILURE; + + nm_device_state_changed (NM_DEVICE (self), NM_DEVICE_STATE_NEED_AUTH, NM_DEVICE_STATE_REASON_NONE); + + nm_active_connection_clear_secrets (NM_ACTIVE_CONNECTION (req)); + + applied_connection = nm_act_request_get_applied_connection (req); + setting_name = nm_connection_need_secrets (applied_connection, &hints); + if (!setting_name) { + _LOGI (LOGD_DEVICE, "Cleared secrets, but setting didn't need any secrets."); + return NM_ACT_STAGE_RETURN_FAILURE; + } + + if (hints) + g_ptr_array_add (hints, NULL); + + _secrets_get_secrets (self, + setting_name, + NM_SECRET_AGENT_GET_SECRETS_FLAG_ALLOW_INTERACTION + | (new_secrets ? NM_SECRET_AGENT_GET_SECRETS_FLAG_REQUEST_NEW : 0), + ( hints + ? (const char *const*) hints->pdata + : NULL)); + return NM_ACT_STAGE_RETURN_POSTPONE; +} + +/*****************************************************************************/ + +static void +_dns_config_changed (NMDnsManager *dns_manager, NMDeviceWireGuard *self) +{ + /* when the DNS configuration changes, we re-resolve the peer addresses. + * + * Possibly, we should also do that when the default-route changes, but it's + * hard to figure out when that happens. */ + _peers_resolve_reresolve_all (self); +} + +/*****************************************************************************/ + +static NMActStageReturn +link_config (NMDeviceWireGuard *self, + const char *reason, + LinkConfigMode config_mode, + NMDeviceStateReason *out_failure_reason) +{ + NMDeviceWireGuardPrivate *priv = NM_DEVICE_WIREGUARD_GET_PRIVATE (self); + nm_auto_bzero_secret_ptr NMSecretPtr wg_lnk_clear_private_key = NM_SECRET_PTR_INIT (); + NMSettingWireGuard *s_wg; + NMConnection *connection; + NMActStageReturn ret; + gs_unref_array GArray *allowed_ips_data = NULL; + NMPlatformLnkWireGuard wg_lnk; + gs_free NMPWireGuardPeer *plpeers = NULL; + gs_free NMPlatformWireGuardChangePeerFlags *plpeer_flags = NULL; + guint plpeers_len = 0; + const char *setting_name; + gboolean peers_removed; + NMPlatformWireGuardChangeFlags wg_change_flags; + int ifindex; + int r; + + NM_SET_OUT (out_failure_reason, NM_DEVICE_STATE_REASON_NONE); + + connection = nm_device_get_applied_connection (NM_DEVICE (self)); + s_wg = NM_SETTING_WIREGUARD (nm_connection_get_setting (connection, NM_TYPE_SETTING_WIREGUARD)); + g_return_val_if_fail (s_wg, NM_ACT_STAGE_RETURN_FAILURE); + + priv->link_config_last_at = nm_utils_get_monotonic_timestamp_ns (); + + _LOGT (LOGD_DEVICE, "wireguard link config (%s, %s)...", + reason, _link_config_mode_to_string (config_mode)); + + if (!priv->dns_manager) { + priv->dns_manager = g_object_ref (nm_dns_manager_get ()); + g_signal_connect (priv->dns_manager, NM_DNS_MANAGER_CONFIG_CHANGED, G_CALLBACK (_dns_config_changed), self); + } + + if ( NM_IN_SET (config_mode, LINK_CONFIG_MODE_FULL) + && (setting_name = nm_connection_need_secrets (connection, NULL))) { + NMActRequest *req = nm_device_get_act_request (NM_DEVICE (self)); + + _LOGD (LOGD_DEVICE, + "Activation: connection '%s' has security, but secrets are required.", + nm_connection_get_id (connection)); + + ret = _secrets_handle_auth_or_fail (self, req, FALSE); + if (ret != NM_ACT_STAGE_RETURN_SUCCESS) { + if (ret != NM_ACT_STAGE_RETURN_POSTPONE) { + nm_assert (ret == NM_ACT_STAGE_RETURN_FAILURE); + NM_SET_OUT (out_failure_reason, NM_DEVICE_STATE_REASON_NO_SECRETS); + } + return ret; + } + } + + ifindex = nm_device_get_ip_ifindex (NM_DEVICE (self)); + if (ifindex <= 0) { + NM_SET_OUT (out_failure_reason, NM_DEVICE_STATE_REASON_CONFIG_FAILED); + return NM_ACT_STAGE_RETURN_FAILURE; + } + + _peers_update_all (self, s_wg, &peers_removed); + + wg_lnk = (NMPlatformLnkWireGuard) { }; -/******************************************************************/ + wg_change_flags = NM_PLATFORM_WIREGUARD_CHANGE_FLAG_NONE; + + if ( NM_IN_SET (config_mode, LINK_CONFIG_MODE_FULL) + || ( NM_IN_SET (config_mode, LINK_CONFIG_MODE_REAPPLY) + && peers_removed)) + wg_change_flags |= NM_PLATFORM_WIREGUARD_CHANGE_FLAG_REPLACE_PEERS; + + if (NM_IN_SET (config_mode, LINK_CONFIG_MODE_FULL, + LINK_CONFIG_MODE_REAPPLY)) { + + wg_lnk.listen_port = nm_setting_wireguard_get_listen_port (s_wg), + wg_change_flags |= NM_PLATFORM_WIREGUARD_CHANGE_FLAG_HAS_LISTEN_PORT; + + wg_lnk.fwmark = nm_setting_wireguard_get_fwmark (s_wg), + wg_change_flags |= NM_PLATFORM_WIREGUARD_CHANGE_FLAG_HAS_FWMARK; + + if (nm_utils_base64secret_decode (nm_setting_wireguard_get_private_key (s_wg), + sizeof (wg_lnk.private_key), + wg_lnk.private_key)) { + wg_lnk_clear_private_key = NM_SECRET_PTR_ARRAY (wg_lnk.private_key); + wg_change_flags |= NM_PLATFORM_WIREGUARD_CHANGE_FLAG_HAS_PRIVATE_KEY; + } else { + if (NM_IN_SET (config_mode, LINK_CONFIG_MODE_FULL)) { + _LOGD (LOGD_DEVICE, "the provided private-key is invalid"); + NM_SET_OUT (out_failure_reason, NM_DEVICE_STATE_REASON_NO_SECRETS); + return NM_ACT_STAGE_RETURN_FAILURE; + } + } + } + + _peers_get_platform_list (priv, + config_mode, + &plpeers, + &plpeer_flags, + &plpeers_len, + &allowed_ips_data); + + r = nm_platform_link_wireguard_change (nm_device_get_platform (NM_DEVICE (self)), + ifindex, + &wg_lnk, + plpeers, + plpeer_flags, + plpeers_len, + wg_change_flags); + + nm_explicit_bzero (plpeers, sizeof (plpeers) * plpeers_len); + + if (r < 0) { + NM_SET_OUT (out_failure_reason, NM_DEVICE_STATE_REASON_CONFIG_FAILED); + return NM_ACT_STAGE_RETURN_FAILURE; + } + + return NM_ACT_STAGE_RETURN_SUCCESS; +} + +static void +link_config_delayed (NMDeviceWireGuard *self, + const char *reason) +{ + NMDeviceWireGuardPrivate *priv = NM_DEVICE_WIREGUARD_GET_PRIVATE (self); + gint64 now; + + priv->link_config_delayed_id = 0; + + if (priv->link_config_last_at != 0) { + now = nm_utils_get_monotonic_timestamp_ns (); + if (now < priv->link_config_last_at + LINK_CONFIG_RATE_LIMIT_NSEC) { + /* we ratelimit calls to link_config(), because we call this whenever a resolver + * completes. */ + _LOGT (LOGD_DEVICE, "wireguard link config (%s) (postponed)", reason); + priv->link_config_delayed_id = g_timeout_add (NM_MAX ((priv->link_config_last_at + LINK_CONFIG_RATE_LIMIT_NSEC - now) / NM_UTILS_NS_PER_MSEC, + (gint64) 1), + link_config_delayed_ratelimit_cb, + self); + return; + } + } + + link_config (self, reason, LINK_CONFIG_MODE_ENDPOINTS, NULL); +} + +static gboolean +link_config_delayed_ratelimit_cb (gpointer user_data) +{ + link_config_delayed (user_data, "after-ratelimiting"); + return G_SOURCE_REMOVE; +} + +static gboolean +link_config_delayed_resolver_cb (gpointer user_data) +{ + link_config_delayed (user_data, "resolver-update"); + return G_SOURCE_REMOVE; +} + +static NMActStageReturn +act_stage2_config (NMDevice *device, + NMDeviceStateReason *out_failure_reason) +{ + NMDeviceSysIfaceState sys_iface_state; + NMDeviceStateReason failure_reason; + NMActStageReturn ret; + + sys_iface_state = nm_device_sys_iface_state_get (device); + + if (sys_iface_state == NM_DEVICE_SYS_IFACE_STATE_EXTERNAL) { + NM_SET_OUT (out_failure_reason, NM_DEVICE_STATE_REASON_NONE); + return NM_ACT_STAGE_RETURN_SUCCESS; + } + + ret = link_config (NM_DEVICE_WIREGUARD (device), + "configure", + (sys_iface_state == NM_DEVICE_SYS_IFACE_STATE_ASSUME) + ? LINK_CONFIG_MODE_ASSUME + : LINK_CONFIG_MODE_FULL, + &failure_reason); + + if (sys_iface_state == NM_DEVICE_SYS_IFACE_STATE_ASSUME) { + /* this never fails. */ + NM_SET_OUT (out_failure_reason, NM_DEVICE_STATE_REASON_NONE); + return NM_ACT_STAGE_RETURN_SUCCESS; + } + + if (ret != NM_ACT_STAGE_RETURN_FAILURE) { + NM_SET_OUT (out_failure_reason, NM_DEVICE_STATE_REASON_NONE); + return ret; + } + + nm_device_state_changed (device, + NM_DEVICE_STATE_FAILED, + failure_reason); + NM_SET_OUT (out_failure_reason, failure_reason); + return NM_ACT_STAGE_RETURN_FAILURE; +} + +static NMIPConfig * +_get_dev2_ip_config (NMDeviceWireGuard *self, + int addr_family) +{ + gs_unref_object NMIPConfig *ip_config = NULL; + NMConnection *connection; + NMSettingWireGuard *s_wg; + guint n_peers; + guint i; + int ip_ifindex; + guint32 route_metric; + guint32 route_table_coerced; + + connection = nm_device_get_applied_connection (NM_DEVICE (self)); + + s_wg = NM_SETTING_WIREGUARD (nm_connection_get_setting (connection, NM_TYPE_SETTING_WIREGUARD)); + + /* Differences to `wg-quick`. + * + * `wg-quick` supports the "Table" setting with 3 modes: + * + * a1) "off": this is what we do with "peer-routes" disabled. + * + * a2) an explicit routing table. This is our behavior with "peer-routes" on. In this case + * we honor the "ipv4.route-table" and "ipv6.route-table" settings. One difference is that + * `wg-quick` would resolve table names from /etc/iproute2/rt_tables. Our connection profiles + * only contain table numbers, so that conversion from name to table must have happened + * before already. + * + * a3) "auto" (the default). In this case, `wg-quick` would only add the route to the + * main table, if the AllowedIP range is not yet reachable on the link. With "peer-routes" + * enabled, we don't check for that and always add the routes to the main-table + * (with 'ipv4.route-table' and 'ipv6.route-table' set to zero or RT_TABLE_MAIN (254)). + * + * Also, in "auto" mode, `wg-quick` would add special handling for /0 routes and pick + * an empty table to configure policy routing to avoid routing loops. This handling + * of routing-loops via policy routing is not yet done, and requires a separate solution + * from constructing the peer-routes here. + */ + if (!nm_setting_wireguard_get_peer_routes (s_wg)) + return NULL; + + ip_ifindex = nm_device_get_ip_ifindex (NM_DEVICE (self)); + + if (ip_ifindex <= 0) + return NULL; + + route_metric = nm_device_get_route_metric (NM_DEVICE (self), addr_family); + + route_table_coerced = nm_platform_route_table_coerce (nm_device_get_route_table (NM_DEVICE (self), addr_family, TRUE)); + + n_peers = nm_setting_wireguard_get_peers_len (s_wg); + for (i = 0; i < n_peers; i++) { + NMWireGuardPeer *peer = nm_setting_wireguard_get_peer (s_wg, i); + guint n_aips; + guint j; + + n_aips = nm_wireguard_peer_get_allowed_ips_len (peer); + for (j = 0; j < n_aips; j++) { + NMPlatformIPXRoute rt; + NMIPAddr addrbin; + const char *aip; + gboolean valid; + int prefix; + + aip = nm_wireguard_peer_get_allowed_ip (peer, j, &valid); + + if ( !valid + || !nm_utils_parse_inaddr_prefix_bin (addr_family, + aip, + NULL, + &addrbin, + &prefix)) + continue; + + if (prefix < 0) + prefix = (addr_family == AF_INET) ? 32 : 128; + + if (!ip_config) + ip_config = nm_device_ip_config_new (NM_DEVICE (self), addr_family); + + nm_utils_ipx_address_clear_host_address (addr_family, &addrbin, NULL, prefix); + + if (addr_family == AF_INET) { + rt.r4 = (NMPlatformIP4Route) { + .network = addrbin.addr4, + .plen = prefix, + .ifindex = ip_ifindex, + .rt_source = NM_IP_CONFIG_SOURCE_USER, + .table_coerced = route_table_coerced, + .metric = route_metric, + }; + } else { + rt.r6 = (NMPlatformIP6Route) { + .network = addrbin.addr6, + .plen = prefix, + .ifindex = ip_ifindex, + .rt_source = NM_IP_CONFIG_SOURCE_USER, + .table_coerced = route_table_coerced, + .metric = route_metric, + }; + } + + nm_ip_config_add_route (ip_config, &rt.rx, NULL); + } + } + + return g_steal_pointer (&ip_config); +} + +static NMActStageReturn +act_stage3_ip_config_start (NMDevice *device, + int addr_family, + gpointer *out_config, + NMDeviceStateReason *out_failure_reason) +{ + gs_unref_object NMIPConfig *ip_config = NULL; + + ip_config = _get_dev2_ip_config (NM_DEVICE_WIREGUARD (device), addr_family); + + nm_device_set_dev2_ip_config (device, addr_family, ip_config); + + return NM_DEVICE_CLASS (nm_device_wireguard_parent_class)->act_stage3_ip_config_start (device, addr_family, out_config, out_failure_reason); +} + +static guint32 +get_configured_mtu (NMDevice *device, NMDeviceMtuSource *out_source) +{ + /* When "MTU" for `wg-quick up` is unset, it calls `ip route get` for + * each configured endpoint, to determine the suitable MTU how to reach + * each endpoint. + * For `wg-quick` this works very well, because whenever the script runs it + * determines the best setting at that point in time. It's simply not concerned + * with what happens later (and it's not around anyway). + * + * NetworkManager sticks around, so the right MTU would need to be re-determined + * whenever anything relevant changes. Which basically means, to re-evaluate whenever + * something related to addresses or routing changes (which happens all the time). + * + * The correct MTU indeed depends on the MTU setting of other interfaces (or routes). + * But it's still odd, that activating/deactivating a seemingly unrelated interface + * would trigger an MTU change. It's odd to explain/document and odd to implemented + * -- despite this being the reality. + * + * For now, only support configuring an explicit MTU, or leave the setting untouched. + * The same limitation also applies to other "ip-tunnel" types, where we could use + * similar smarts for autodetecting the MTU. + */ + return nm_device_get_configured_mtu_from_connection (device, + NM_TYPE_SETTING_WIREGUARD, + out_source); +} + +static void +device_state_changed (NMDevice *device, + NMDeviceState new_state, + NMDeviceState old_state, + NMDeviceStateReason reason) +{ + NMDeviceWireGuardPrivate *priv; + + if (new_state <= NM_DEVICE_STATE_ACTIVATED) + return; + + priv = NM_DEVICE_WIREGUARD_GET_PRIVATE (device); + + _peers_remove_all (priv); + _secrets_cancel (NM_DEVICE_WIREGUARD (device)); +} + +/*****************************************************************************/ + +static gboolean +can_reapply_change (NMDevice *device, + const char *setting_name, + NMSetting *s_old, + NMSetting *s_new, + GHashTable *diffs, + GError **error) +{ + if (nm_streq (setting_name, NM_SETTING_WIREGUARD_SETTING_NAME)) { + /* Most, but not all WireGuard settings can be reapplied. Whitelist. + * + * MTU cannot be reapplied. */ + return nm_device_hash_check_invalid_keys (diffs, + NM_SETTING_WIREGUARD_SETTING_NAME, + error, + NM_SETTING_WIREGUARD_FWMARK, + NM_SETTING_WIREGUARD_LISTEN_PORT, + NM_SETTING_WIREGUARD_PEERS, + NM_SETTING_WIREGUARD_PEER_ROUTES, + NM_SETTING_WIREGUARD_PRIVATE_KEY, + NM_SETTING_WIREGUARD_PRIVATE_KEY_FLAGS); + } + + return NM_DEVICE_CLASS (nm_device_wireguard_parent_class)->can_reapply_change (device, + setting_name, + s_old, + s_new, + diffs, + error); +} + +static void +reapply_connection (NMDevice *device, + NMConnection *con_old, + NMConnection *con_new) +{ + NMDeviceWireGuard *self = NM_DEVICE_WIREGUARD (device); + gs_unref_object NMIPConfig *ip4_config = NULL; + gs_unref_object NMIPConfig *ip6_config = NULL; + + ip4_config = _get_dev2_ip_config (self, AF_INET); + ip6_config = _get_dev2_ip_config (self, AF_INET6); + + nm_device_set_dev2_ip_config (device, AF_INET, ip4_config); + nm_device_set_dev2_ip_config (device, AF_INET6, ip6_config); + + NM_DEVICE_CLASS (nm_device_wireguard_parent_class)->reapply_connection (device, + con_old, + con_new); + + link_config (NM_DEVICE_WIREGUARD (device), + "reapply", + LINK_CONFIG_MODE_REAPPLY, + NULL); +} + +/*****************************************************************************/ + +static void +update_connection (NMDevice *device, NMConnection *connection) +{ + NMDeviceWireGuardPrivate *priv = NM_DEVICE_WIREGUARD_GET_PRIVATE (device); + NMSettingWireGuard *s_wg = NM_SETTING_WIREGUARD (nm_connection_get_setting (connection, NM_TYPE_SETTING_WIREGUARD)); + const NMPObject *obj_wg; + const NMPObjectLnkWireGuard *olnk_wg; + guint i; + + if (!s_wg) { + s_wg = NM_SETTING_WIREGUARD (nm_setting_wireguard_new ()); + nm_connection_add_setting (connection, NM_SETTING (s_wg)); + } + + g_object_set (s_wg, + NM_SETTING_WIREGUARD_FWMARK, + (guint) priv->lnk_curr.fwmark, + NM_SETTING_WIREGUARD_LISTEN_PORT, + (guint) priv->lnk_curr.listen_port, + NULL); + + obj_wg = NMP_OBJECT_UP_CAST (nm_platform_link_get_lnk_wireguard (nm_device_get_platform (device), + nm_device_get_ip_ifindex (device), + NULL)); + if (!obj_wg) + return; + + olnk_wg = &obj_wg->_lnk_wireguard; + + for (i = 0; i < olnk_wg->peers_len; i++) { + nm_auto_unref_wgpeer NMWireGuardPeer *peer = NULL; + const NMPWireGuardPeer *ppeer = &olnk_wg->peers[i]; + + peer = nm_wireguard_peer_new (); + + _nm_wireguard_peer_set_public_key_bin (peer, ppeer->public_key); + + nm_setting_wireguard_append_peer (s_wg, peer); + } +} + +/*****************************************************************************/ static void get_property (GObject *object, guint prop_id, GValue *value, GParamSpec *pspec) { NMDeviceWireGuard *self = NM_DEVICE_WIREGUARD (object); + NMDeviceWireGuardPrivate *priv = NM_DEVICE_WIREGUARD_GET_PRIVATE (self); switch (prop_id) { case PROP_PUBLIC_KEY: - g_value_take_variant (value, get_public_key_as_variant (self)); + g_value_take_variant (value, + g_variant_new_fixed_array (G_VARIANT_TYPE_BYTE, + priv->lnk_curr.public_key, + sizeof (priv->lnk_curr.public_key), + 1)); break; case PROP_LISTEN_PORT: - g_value_set_uint (value, self->props.listen_port); + g_value_set_uint (value, priv->lnk_curr.listen_port); break; case PROP_FWMARK: - g_value_set_uint (value, self->props.fwmark); + g_value_set_uint (value, priv->lnk_curr.fwmark); break; default: G_OBJECT_WARN_INVALID_PROPERTY_ID (object, prop_id, pspec); @@ -132,9 +1552,44 @@ get_property (GObject *object, guint prop_id, } } +/*****************************************************************************/ + static void nm_device_wireguard_init (NMDeviceWireGuard *self) { + NMDeviceWireGuardPrivate *priv = NM_DEVICE_WIREGUARD_GET_PRIVATE (self); + + c_list_init (&priv->lst_peers_head); + priv->peers = g_hash_table_new (_peer_data_hash, _peer_data_equal); +} + +static void +dispose (GObject *object) +{ + NMDeviceWireGuard *self = NM_DEVICE_WIREGUARD (object); + NMDeviceWireGuardPrivate *priv = NM_DEVICE_WIREGUARD_GET_PRIVATE (self); + + _secrets_cancel (self); + + _peers_remove_all (priv); + + G_OBJECT_CLASS (nm_device_wireguard_parent_class)->dispose (object); +} + +static void +finalize (GObject *object) +{ + NMDeviceWireGuard *self = NM_DEVICE_WIREGUARD (object); + NMDeviceWireGuardPrivate *priv = NM_DEVICE_WIREGUARD_GET_PRIVATE (self); + + nm_explicit_bzero (priv->lnk_curr.private_key, sizeof (priv->lnk_curr.private_key)); + + if (priv->dns_manager) { + g_signal_handlers_disconnect_by_func (priv->dns_manager, _dns_config_changed, self); + g_object_unref (priv->dns_manager); + } + + G_OBJECT_CLASS (nm_device_wireguard_parent_class)->finalize (object); } static const NMDBusInterfaceInfoExtended interface_info_device_wireguard = { @@ -156,13 +1611,26 @@ nm_device_wireguard_class_init (NMDeviceWireGuardClass *klass) NMDeviceClass *device_class = NM_DEVICE_CLASS (klass); object_class->get_property = get_property; + object_class->dispose = dispose; + object_class->finalize = finalize; dbus_object_class->interface_infos = NM_DBUS_INTERFACE_INFOS (&interface_info_device_wireguard); - device_class->connection_type_supported = NULL; + device_class->connection_type_supported = NM_SETTING_WIREGUARD_SETTING_NAME; + device_class->connection_type_check_compatible = NM_SETTING_WIREGUARD_SETTING_NAME; device_class->link_types = NM_DEVICE_DEFINE_LINK_TYPES (NM_LINK_TYPE_WIREGUARD); + device_class->state_changed = device_state_changed; + device_class->create_and_realize = create_and_realize; + device_class->act_stage2_config = act_stage2_config; + device_class->act_stage2_config_also_for_external_or_assume = TRUE; + device_class->act_stage3_ip_config_start = act_stage3_ip_config_start; + device_class->get_generic_capabilities = get_generic_capabilities; device_class->link_changed = link_changed; + device_class->update_connection = update_connection; + device_class->can_reapply_change = can_reapply_change; + device_class->reapply_connection = reapply_connection; + device_class->get_configured_mtu = get_configured_mtu; obj_properties[PROP_PUBLIC_KEY] = g_param_spec_variant (NM_DEVICE_WIREGUARD_PUBLIC_KEY, @@ -207,6 +1675,7 @@ create_device (NMDeviceFactory *factory, } NM_DEVICE_FACTORY_DEFINE_INTERNAL (WIREGUARD, WireGuard, wireguard, - NM_DEVICE_FACTORY_DECLARE_LINK_TYPES (NM_LINK_TYPE_WIREGUARD), + NM_DEVICE_FACTORY_DECLARE_LINK_TYPES (NM_LINK_TYPE_WIREGUARD) + NM_DEVICE_FACTORY_DECLARE_SETTING_TYPES (NM_SETTING_WIREGUARD_SETTING_NAME), factory_class->create_device = create_device; ) diff --git a/src/devices/nm-device-wpan.c b/src/devices/nm-device-wpan.c index c2fa7f4e..cdfd1f70 100644 --- a/src/devices/nm-device-wpan.c +++ b/src/devices/nm-device-wpan.c @@ -23,7 +23,6 @@ #include "nm-device-wpan.h" #include <stdlib.h> -#include <string.h> #include <sys/types.h> #include <linux/if.h> diff --git a/src/devices/nm-device.c b/src/devices/nm-device.c index 9ded911c..7514fa78 100644 --- a/src/devices/nm-device.c +++ b/src/devices/nm-device.c @@ -24,9 +24,7 @@ #include "nm-device.h" #include <netinet/in.h> -#include <string.h> #include <unistd.h> -#include <errno.h> #include <sys/ioctl.h> #include <signal.h> #include <sys/types.h> @@ -115,14 +113,6 @@ typedef enum { CLEANUP_TYPE_DECONFIGURE, } CleanupType; -typedef enum { - IP_NONE = 0, - IP_WAIT, - IP_CONF, - IP_DONE, - IP_FAIL -} IpState; - typedef struct { CList lst_slave; NMDevice *slave; @@ -397,6 +387,8 @@ typedef struct _NMDevicePrivate { bool ndisc_started:1; bool device_link_changed_down:1; + bool concheck_rp_filter_checked:1; + /* Generic DHCP stuff */ char * dhcp_anycast_address; @@ -416,11 +408,8 @@ typedef struct _NMDevicePrivate { NMIPConfig *ip_config_x[2]; }; - union { - const IpState ip4_state; - IpState ip4_state_; - }; - AppliedConfig dev_ip4_config; /* Config from DHCP, PPP, LLv4, etc */ + /* Config from DHCP, PPP, LLv4, etc */ + AppliedConfig dev_ip_config_4; /* config from the setting */ union { @@ -449,13 +438,14 @@ typedef struct _NMDevicePrivate { GSList *vpn_configs_x[2]; }; - /* WWAN configuration */ + /* Extra device configuration, injected by the subclass of NMDevice. + * This is used for example by NMDeviceModem for WWAN configuration. */ union { struct { - AppliedConfig wwan_ip_config_6; - AppliedConfig wwan_ip_config_4; + AppliedConfig dev2_ip_config_6; + AppliedConfig dev2_ip_config_4; }; - AppliedConfig wwan_ip_config_x[2]; + AppliedConfig dev2_ip_config_x[2]; }; /* DHCPv4 tracking */ @@ -500,9 +490,16 @@ typedef struct _NMDevicePrivate { } acd; union { - const IpState ip6_state; - IpState ip6_state_; + struct { + const NMDeviceIPState ip_state_6; + const NMDeviceIPState ip_state_4; + }; + union { + const NMDeviceIPState ip_state_x[2]; + NMDeviceIPState ip_state_x_[2]; + }; }; + AppliedConfig ac_ip6_config; /* config from IPv6 autoconfiguration */ NMIP6Config * ext_ip6_config_captured; /* Configuration captured from platform. */ NMIP6Config * dad6_ip6_config; @@ -648,6 +645,22 @@ static void concheck_update_state (NMDevice *self, NMConnectivityState state, gboolean is_periodic); +static void activate_stage4_ip_config_timeout_4 (NMDevice *self); +static void activate_stage4_ip_config_timeout_6 (NMDevice *self); + +static void (*const activate_stage4_ip_config_timeout_x[2]) (NMDevice *self) = { + activate_stage4_ip_config_timeout_6, + activate_stage4_ip_config_timeout_4, +}; + +static void activate_stage5_ip_config_result_4 (NMDevice *self); +static void activate_stage5_ip_config_result_6 (NMDevice *self); + +static void (*const activate_stage5_ip_config_result_x[2]) (NMDevice *self) = { + activate_stage5_ip_config_result_6, + activate_stage5_ip_config_result_4, +}; + /*****************************************************************************/ NM_UTILS_LOOKUP_STR_DEFINE_STATIC (queued_state_to_string, NMDeviceState, @@ -742,6 +755,7 @@ NM_UTILS_LOOKUP_STR_DEFINE (nm_device_state_reason_to_str, NMDeviceStateReason, NM_UTILS_LOOKUP_STR_ITEM (NM_DEVICE_STATE_REASON_IP_ADDRESS_DUPLICATE, "ip-address-duplicate"), NM_UTILS_LOOKUP_STR_ITEM (NM_DEVICE_STATE_REASON_IP_METHOD_UNSUPPORTED, "ip-method-unsupported"), NM_UTILS_LOOKUP_STR_ITEM (NM_DEVICE_STATE_REASON_SRIOV_CONFIGURATION_FAILED, "sriov-configuration-failed"), + NM_UTILS_LOOKUP_STR_ITEM (NM_DEVICE_STATE_REASON_PEER_NOT_FOUND, "peer-not-found"), ); #define reason_to_string_a(reason) NM_UTILS_LOOKUP_STR_A (nm_device_state_reason_to_str, reason) @@ -870,28 +884,28 @@ concheck_get_mgr (NMDevice *self) return priv->concheck_mgr; } -static NMIP4Config * -_ip4_config_new (NMDevice *self) +NMIP4Config * +nm_device_ip4_config_new (NMDevice *self) { return nm_ip4_config_new (nm_device_get_multi_index (self), nm_device_get_ip_ifindex (self)); } -static NMIP6Config * -_ip6_config_new (NMDevice *self) +NMIP6Config * +nm_device_ip6_config_new (NMDevice *self) { return nm_ip6_config_new (nm_device_get_multi_index (self), nm_device_get_ip_ifindex (self)); } -static NMIPConfig * -_ip_config_new (NMDevice *self, int addr_family) +NMIPConfig * +nm_device_ip_config_new (NMDevice *self, int addr_family) { nm_assert_addr_family (addr_family); return addr_family == AF_INET - ? (gpointer) _ip4_config_new (self) - : (gpointer) _ip6_config_new (self); + ? (gpointer) nm_device_ip4_config_new (self) + : (gpointer) nm_device_ip6_config_new (self); } static void @@ -904,6 +918,12 @@ applied_config_clear (AppliedConfig *config) static void applied_config_init (AppliedConfig *config, gpointer ip_config) { + nm_assert ( !ip_config + || (!config->orig && !config->current) + || nm_ip_config_get_addr_family (ip_config) == nm_ip_config_get_addr_family (config->orig ?: config->current)); + nm_assert ( !ip_config + || NM_IS_IP_CONFIG (ip_config, AF_UNSPEC)); + nm_g_object_ref (ip_config); applied_config_clear (config); config->orig = ip_config; @@ -912,7 +932,7 @@ applied_config_init (AppliedConfig *config, gpointer ip_config) static void applied_config_init_new (AppliedConfig *config, NMDevice *self, int addr_family) { - gs_unref_object NMIPConfig *c = _ip_config_new (self, addr_family); + gs_unref_object NMIPConfig *c = nm_device_ip_config_new (self, addr_family); applied_config_init (config, c); } @@ -1274,7 +1294,7 @@ _get_stable_id (NMDevice *self, uuid = nm_connection_get_uuid (connection); /* the cloned-mac-address may be generated based on the stable-id. - * Thus, at this point, we can only use the permanant MAC address + * Thus, at this point, we can only use the permanent MAC address * as seed. */ hwaddr = nm_device_get_permanent_hw_address_full (self, TRUE, &hwaddr_is_fake); @@ -1315,44 +1335,42 @@ _get_stable_id (NMDevice *self, /*****************************************************************************/ -NM_UTILS_LOOKUP_STR_DEFINE_STATIC (_ip_state_to_string, IpState, +NM_UTILS_LOOKUP_STR_DEFINE_STATIC (_ip_state_to_string, NMDeviceIPState, NM_UTILS_LOOKUP_DEFAULT_WARN ("unknown"), - NM_UTILS_LOOKUP_STR_ITEM (IP_NONE, "none"), - NM_UTILS_LOOKUP_STR_ITEM (IP_WAIT, "wait"), - NM_UTILS_LOOKUP_STR_ITEM (IP_CONF, "conf"), - NM_UTILS_LOOKUP_STR_ITEM (IP_DONE, "done"), - NM_UTILS_LOOKUP_STR_ITEM (IP_FAIL, "fail"), + NM_UTILS_LOOKUP_STR_ITEM (NM_DEVICE_IP_STATE_NONE, "none"), + NM_UTILS_LOOKUP_STR_ITEM (NM_DEVICE_IP_STATE_WAIT, "wait"), + NM_UTILS_LOOKUP_STR_ITEM (NM_DEVICE_IP_STATE_CONF, "conf"), + NM_UTILS_LOOKUP_STR_ITEM (NM_DEVICE_IP_STATE_DONE, "done"), + NM_UTILS_LOOKUP_STR_ITEM (NM_DEVICE_IP_STATE_FAIL, "fail"), ); static void -_set_ip_state (NMDevice *self, int addr_family, IpState new_state) +_set_ip_state (NMDevice *self, int addr_family, NMDeviceIPState new_state) { - IpState *p; NMDevicePrivate *priv = NM_DEVICE_GET_PRIVATE (self); + const gboolean IS_IPv4 = (addr_family == AF_INET); nm_assert_addr_family (addr_family); - p = (addr_family == AF_INET) - ? &priv->ip4_state_ - : &priv->ip6_state_; + if (priv->ip_state_x[IS_IPv4] == new_state) + return; - if (*p != new_state) { - _LOGT (LOGD_DEVICE, "ip%c-state: set to %d (%s)", - nm_utils_addr_family_to_char (addr_family), - (int) new_state, - _ip_state_to_string (new_state)); - *p = new_state; + _LOGT (LOGD_DEVICE, "ip%c-state: set to %d (%s)", + nm_utils_addr_family_to_char (addr_family), + (int) new_state, + _ip_state_to_string (new_state)); - if (new_state == IP_DONE) { - /* we only set the IPx_READY flag once we reach IP_DONE state. We don't - * ever clear it, even if we later enter IP_FAIL state. - * - * This is not documented/guaranteed behavior, but seems to make sense for now. */ - _active_connection_set_state_flags (self, - addr_family == AF_INET - ? NM_ACTIVATION_STATE_FLAG_IP4_READY - : NM_ACTIVATION_STATE_FLAG_IP6_READY); - } + priv->ip_state_x_[IS_IPv4] = new_state; + + if (new_state == NM_DEVICE_IP_STATE_DONE) { + /* we only set the IPx_READY flag once we reach NM_DEVICE_IP_STATE_DONE state. We don't + * ever clear it, even if we later enter NM_DEVICE_IP_STATE_FAIL state. + * + * This is not documented/guaranteed behavior, but seems to make sense for now. */ + _active_connection_set_state_flags (self, + addr_family == AF_INET + ? NM_ACTIVATION_STATE_FLAG_IP4_READY + : NM_ACTIVATION_STATE_FLAG_IP6_READY); } } @@ -2041,9 +2059,14 @@ nm_device_get_route_metric_default (NMDeviceType device_type) */ switch (device_type) { - /* 50 is also used for VPN plugins (NM_VPN_ROUTE_METRIC_DEFAULT) */ + + /* 50 is also used for VPN plugins (NM_VPN_ROUTE_METRIC_DEFAULT). + * + * Note that returning 50 from this function means that this device-type is + * in some aspects a VPN. */ case NM_DEVICE_TYPE_WIREGUARD: - return 50; + return NM_VPN_ROUTE_METRIC_DEFAULT; + case NM_DEVICE_TYPE_ETHERNET: case NM_DEVICE_TYPE_VETH: return 100; @@ -2091,6 +2114,7 @@ nm_device_get_route_metric_default (NMDeviceType device_type) return 800; case NM_DEVICE_TYPE_WPAN: return 850; + case NM_DEVICE_TYPE_WIFI_P2P: case NM_DEVICE_TYPE_GENERIC: return 950; case NM_DEVICE_TYPE_UNKNOWN: @@ -2146,9 +2170,7 @@ nm_device_get_route_metric (NMDevice *self, connection = nm_device_get_applied_connection (self); if (connection) { - s_ip = addr_family == AF_INET - ? nm_connection_get_setting_ip4_config (connection) - : nm_connection_get_setting_ip6_config (connection); + s_ip = nm_connection_get_setting_ip_config (connection, addr_family); /* Slave interfaces don't have IP settings, but we may get here when * external changes are made or when noticing IP changes when starting @@ -2253,11 +2275,7 @@ nm_device_get_route_table (NMDevice *self, connection = nm_device_get_applied_connection (self); if (connection) { - if (addr_family == AF_INET) - s_ip = nm_connection_get_setting_ip4_config (connection); - else - s_ip = nm_connection_get_setting_ip6_config (connection); - + s_ip = nm_connection_get_setting_ip_config (connection, addr_family); if (s_ip) route_table = nm_setting_ip_config_get_route_table (s_ip); @@ -3041,6 +3059,7 @@ concheck_start (NMDevice *self, static guint64 seq_counter = 0; NMDevicePrivate *priv; NMDeviceConnectivityHandle *handle; + const char *ifname; g_return_val_if_fail (NM_IS_DEVICE (self), NULL); @@ -3063,6 +3082,39 @@ concheck_start (NMDevice *self, (long long unsigned) handle->seq, is_periodic ? ", periodic-check" : ""); + if ( addr_family == AF_INET + && !priv->concheck_rp_filter_checked) { + + if ((ifname = nm_device_get_ip_iface_from_platform (self))) { + int val, val_all; + + val = nm_platform_sysctl_ip_conf_get_int_checked (nm_device_get_platform (self), + AF_INET, + ifname, + "rp_filter", + 10, 0, 2, 3); + if (val < 2) { + val_all = nm_platform_sysctl_ip_conf_get_int_checked (nm_device_get_platform (self), + AF_INET, + "all", + "rp_filter", + 10, 0, 2, val); + if (val_all > val) { + val = val_all; + ifname = "all"; + } + } + + if (val == 1) { + _LOGW (LOGD_CONCHECK, "connectivity: \"/proc/sys/net/ipv4/conf/%s/rp_filter\" is set to \"1\". " + "This might break connectivity checking for IPv4 on this device", ifname); + } + } + + /* we only check once per device. It's a warning after all. */ + priv->concheck_rp_filter_checked = TRUE; + } + handle->c_handle = nm_connectivity_check_start (concheck_get_mgr (self), handle->addr_family, nm_device_get_ip_ifindex (self), @@ -3160,6 +3212,7 @@ find_slave_info (NMDevice *self, NMDevice *slave) static gboolean nm_device_master_enslave_slave (NMDevice *self, NMDevice *slave, NMConnection *connection) { + NMDevicePrivate *priv; SlaveInfo *info; gboolean success = FALSE; gboolean configure; @@ -3168,6 +3221,7 @@ nm_device_master_enslave_slave (NMDevice *self, NMDevice *slave, NMConnection *c g_return_val_if_fail (slave != NULL, FALSE); g_return_val_if_fail (NM_DEVICE_GET_CLASS (self)->enslave_slave != NULL, FALSE); + priv = NM_DEVICE_GET_PRIVATE (self); info = find_slave_info (self, slave); if (!info) return FALSE; @@ -3190,15 +3244,20 @@ nm_device_master_enslave_slave (NMDevice *self, NMDevice *slave, NMConnection *c */ nm_device_update_hw_address (self); + /* Send ARP announcements if did not yet and have addresses. */ + if ( priv->ip_state_4 == NM_DEVICE_IP_STATE_DONE + && !priv->acd.announcing) + nm_device_arp_announce (self); + /* Restart IP configuration if we're waiting for slaves. Do this * after updating the hardware address as IP config may need the * new address. */ if (success) { - if (NM_DEVICE_GET_PRIVATE (self)->ip4_state == IP_WAIT) + if (priv->ip_state_4 == NM_DEVICE_IP_STATE_WAIT) nm_device_activate_stage3_ip4_start (self); - if (NM_DEVICE_GET_PRIVATE (self)->ip6_state == IP_WAIT) + if (priv->ip_state_6 == NM_DEVICE_IP_STATE_WAIT) nm_device_activate_stage3_ip6_start (self); } @@ -3821,11 +3880,13 @@ device_link_changed (NMDevice *self) if (priv->up && (!was_up || seen_down)) { /* the link was down and just came up. That happens for example, while changing MTU. * We must restore IP configuration. */ - if (priv->ip4_state == IP_DONE) { + if (priv->ip_state_4 == NM_DEVICE_IP_STATE_DONE) { if (!ip_config_merge_and_apply (self, AF_INET, TRUE)) _LOGW (LOGD_IP4, "failed applying IP4 config after link comes up again"); } - if (priv->ip6_state == IP_DONE) { + + priv->linklocal6_dad_counter = 0; + if (priv->ip_state_6 == NM_DEVICE_IP_STATE_DONE) { if (!ip_config_merge_and_apply (self, AF_INET6, TRUE)) _LOGW (LOGD_IP6, "failed applying IP6 config after link comes up again"); } @@ -4323,8 +4384,7 @@ realize_start_setup (NMDevice *self, * NetworkManager might down the interface or remove the 127.0.0.1 address. */ nm_device_set_unmanaged_flags (self, NM_UNMANAGED_BY_TYPE, - is_loopback (self) - || NM_IS_DEVICE_WIREGUARD (self)); + is_loopback (self)); nm_device_set_unmanaged_by_user_udev (self); nm_device_set_unmanaged_by_user_conf (self); @@ -4848,21 +4908,11 @@ static gboolean get_ip_config_may_fail (NMDevice *self, int addr_family) { NMConnection *connection; - NMSettingIPConfig *s_ip = NULL; + NMSettingIPConfig *s_ip; connection = nm_device_get_applied_connection (self); - /* Fail the connection if the failed IP method is required to complete */ - switch (addr_family) { - case AF_INET: - s_ip = nm_connection_get_setting_ip4_config (connection); - break; - case AF_INET6: - s_ip = nm_connection_get_setting_ip6_config (connection); - break; - default: - nm_assert_not_reached (); - } + s_ip = nm_connection_get_setting_ip_config (connection, addr_family); return !s_ip || nm_setting_ip_config_get_may_fail (s_ip); } @@ -4906,22 +4956,22 @@ check_ip_state (NMDevice *self, gboolean may_fail, gboolean full_state_update) NM_SETTING_IP6_CONFIG_METHOD_IGNORE)) ip6_ignore = TRUE; - if ( priv->ip4_state == IP_DONE - && priv->ip6_state == IP_DONE) { + if ( priv->ip_state_4 == NM_DEVICE_IP_STATE_DONE + && priv->ip_state_6 == NM_DEVICE_IP_STATE_DONE) { /* Both method completed (or disabled), proceed with activation */ nm_device_state_changed (self, NM_DEVICE_STATE_IP_CHECK, NM_DEVICE_STATE_REASON_NONE); return; } - if ( (priv->ip4_state == IP_FAIL || (ip4_disabled && priv->ip4_state == IP_DONE)) - && (priv->ip6_state == IP_FAIL || (ip6_ignore && priv->ip6_state == IP_DONE))) { + if ( (priv->ip_state_4 == NM_DEVICE_IP_STATE_FAIL || (ip4_disabled && priv->ip_state_4 == NM_DEVICE_IP_STATE_DONE)) + && (priv->ip_state_6 == NM_DEVICE_IP_STATE_FAIL || (ip6_ignore && priv->ip_state_6 == NM_DEVICE_IP_STATE_DONE))) { /* Either both methods failed, or only one failed and the other is * disabled */ if (nm_device_sys_iface_state_is_external_or_assume (self)) { /* We have assumed configuration, but couldn't redo it. No problem, * move to check state. */ - _set_ip_state (self, AF_INET, IP_DONE); - _set_ip_state (self, AF_INET6, IP_DONE); + _set_ip_state (self, AF_INET, NM_DEVICE_IP_STATE_DONE); + _set_ip_state (self, AF_INET6, NM_DEVICE_IP_STATE_DONE); state = NM_DEVICE_STATE_IP_CHECK; } else if ( may_fail && get_ip_config_may_fail (self, AF_INET) @@ -4944,14 +4994,14 @@ check_ip_state (NMDevice *self, gboolean may_fail, gboolean full_state_update) } /* If a method is still pending but required, wait */ - if (priv->ip4_state != IP_DONE && !get_ip_config_may_fail (self, AF_INET)) + if (priv->ip_state_4 != NM_DEVICE_IP_STATE_DONE && !get_ip_config_may_fail (self, AF_INET)) return; - if (priv->ip6_state != IP_DONE && !get_ip_config_may_fail (self, AF_INET6)) + if (priv->ip_state_6 != NM_DEVICE_IP_STATE_DONE && !get_ip_config_may_fail (self, AF_INET6)) return; /* If at least a method has completed, proceed with activation */ - if ( (priv->ip4_state == IP_DONE && !ip4_disabled) - || (priv->ip6_state == IP_DONE && !ip6_ignore)) { + if ( (priv->ip_state_4 == NM_DEVICE_IP_STATE_DONE && !ip4_disabled) + || (priv->ip_state_6 == NM_DEVICE_IP_STATE_DONE && !ip6_ignore)) { if (full_state_update) nm_device_state_changed (self, NM_DEVICE_STATE_IP_CHECK, NM_DEVICE_STATE_REASON_NONE); return; @@ -5642,7 +5692,6 @@ check_connection_compatible (NMDevice *self, NMConnection *connection, GError ** NMDeviceClass *klass; const char *const *patterns; NMSettingMatch *s_match; - guint num_patterns; klass = NM_DEVICE_GET_CLASS (self); if (klass->connection_type_check_compatible) { @@ -5683,6 +5732,8 @@ check_connection_compatible (NMDevice *self, NMConnection *connection, GError ** s_match = (NMSettingMatch *) nm_connection_get_setting (connection, NM_TYPE_SETTING_MATCH); if (s_match) { + guint num_patterns = 0; + patterns = nm_setting_match_get_interface_names (s_match, &num_patterns); if (!nm_wildcard_match_check (device_iface, patterns, num_patterns)) { nm_utils_error_set_literal (error, NM_UTILS_ERROR_CONNECTION_AVAILABLE_TEMPORARY, @@ -6267,8 +6318,8 @@ activate_stage1_device_prepare (NMDevice *self) NMDevicePrivate *priv = NM_DEVICE_GET_PRIVATE (self); NMActStageReturn ret = NM_ACT_STAGE_RETURN_SUCCESS; - _set_ip_state (self, AF_INET, IP_NONE); - _set_ip_state (self, AF_INET6, IP_NONE); + _set_ip_state (self, AF_INET, NM_DEVICE_IP_STATE_NONE); + _set_ip_state (self, AF_INET6, NM_DEVICE_IP_STATE_NONE); /* Notify the new ActiveConnection along with the state change */ nm_dbus_track_obj_path_set (&priv->act_request, @@ -6445,23 +6496,25 @@ static void activate_stage2_device_config (NMDevice *self) { NMDevicePrivate *priv = NM_DEVICE_GET_PRIVATE (self); + NMDeviceClass *klass; NMActStageReturn ret; gboolean no_firmware = FALSE; CList *iter; nm_device_state_changed (self, NM_DEVICE_STATE_CONFIG, NM_DEVICE_STATE_REASON_NONE); - /* Assumed connections were already set up outside NetworkManager */ - if (!nm_device_sys_iface_state_is_external_or_assume (self)) { - NMDeviceStateReason failure_reason = NM_DEVICE_STATE_REASON_NONE; - + if (!nm_device_sys_iface_state_is_external_or_assume (self)) _ethtool_state_set (self); + if (!nm_device_sys_iface_state_is_external_or_assume (self)) { if (!tc_commit (self)) { _LOGW (LOGD_IP6, "failed applying traffic control rules"); nm_device_state_changed (self, NM_DEVICE_STATE_FAILED, NM_DEVICE_STATE_REASON_CONFIG_FAILED); + return; } + } + if (!nm_device_sys_iface_state_is_external_or_assume (self)) { if (!nm_device_bring_up (self, FALSE, &no_firmware)) { if (no_firmware) nm_device_state_changed (self, NM_DEVICE_STATE_FAILED, NM_DEVICE_STATE_REASON_FIRMWARE_MISSING); @@ -6469,15 +6522,21 @@ activate_stage2_device_config (NMDevice *self) nm_device_state_changed (self, NM_DEVICE_STATE_FAILED, NM_DEVICE_STATE_REASON_CONFIG_FAILED); return; } + } + + klass = NM_DEVICE_GET_CLASS (self); + if ( klass->act_stage2_config_also_for_external_or_assume + || !nm_device_sys_iface_state_is_external_or_assume (self)) { + NMDeviceStateReason failure_reason = NM_DEVICE_STATE_REASON_NONE; - ret = NM_DEVICE_GET_CLASS (self)->act_stage2_config (self, &failure_reason); + ret = klass->act_stage2_config (self, &failure_reason); if (ret == NM_ACT_STAGE_RETURN_POSTPONE) return; - else if (ret == NM_ACT_STAGE_RETURN_FAILURE) { + if (ret != NM_ACT_STAGE_RETURN_SUCCESS) { + nm_assert (ret == NM_ACT_STAGE_RETURN_FAILURE); nm_device_state_changed (self, NM_DEVICE_STATE_FAILED, failure_reason); return; } - g_assert (ret == NM_ACT_STAGE_RETURN_SUCCESS); } /* If we have slaves that aren't yet enslaved, do that now */ @@ -6494,6 +6553,7 @@ activate_stage2_device_config (NMDevice *self) } lldp_init (self, TRUE); + nm_device_activate_schedule_stage3_ip_config_start (self); } @@ -6555,7 +6615,7 @@ nm_device_ip_method_failed (NMDevice *self, g_return_if_fail (NM_IS_DEVICE (self)); g_return_if_fail (NM_IN_SET (addr_family, AF_INET, AF_INET6)); - _set_ip_state (self, addr_family, IP_FAIL); + _set_ip_state (self, addr_family, NM_DEVICE_IP_STATE_FAIL); if (get_ip_config_may_fail (self, addr_family)) check_ip_state (self, FALSE, (nm_device_get_state (self) == NM_DEVICE_STATE_IP_CONFIG)); @@ -6606,7 +6666,6 @@ ipv4_manual_method_apply (NMDevice *self, NMIP4Config **configs, gboolean succes { NMConnection *connection; const char *method; - NMIP4Config *empty; connection = nm_device_get_applied_connection (self); nm_assert (connection); @@ -6621,12 +6680,10 @@ ipv4_manual_method_apply (NMDevice *self, NMIP4Config **configs, gboolean succes return; } - if (nm_streq (method, NM_SETTING_IP4_CONFIG_METHOD_MANUAL)) { - empty = _ip4_config_new (self); - nm_device_activate_schedule_ip4_config_result (self, empty); - g_object_unref (empty); - } else { - if (NM_DEVICE_GET_PRIVATE (self)->ip4_state != IP_DONE) + if (nm_streq (method, NM_SETTING_IP4_CONFIG_METHOD_MANUAL)) + nm_device_activate_schedule_ip_config_result (self, AF_INET, NULL); + else { + if (NM_DEVICE_GET_PRIVATE (self)->ip_state_4 != NM_DEVICE_IP_STATE_DONE) ip_config_merge_and_apply (self, AF_INET, TRUE); } } @@ -6781,7 +6838,7 @@ ipv4ll_get_ip4_config (NMDevice *self, guint32 lla) NMPlatformIP4Address address; NMPlatformIP4Route route; - config = _ip4_config_new (self); + config = nm_device_ip4_config_new (self); g_assert (config); memset (&address, 0, sizeof (address)); @@ -6841,11 +6898,11 @@ nm_device_handle_ipv4ll_event (sd_ipv4ll *ll, int event, void *data) return; } - if (priv->ip4_state == IP_CONF) { + if (priv->ip_state_4 == NM_DEVICE_IP_STATE_CONF) { nm_clear_g_source (&priv->ipv4ll_timeout); - nm_device_activate_schedule_ip4_config_result (self, config); - } else if (priv->ip4_state == IP_DONE) { - applied_config_init (&priv->dev_ip4_config, config); + nm_device_activate_schedule_ip_config_result (self, AF_INET, NM_IP_CONFIG_CAST (config)); + } else if (priv->ip_state_4 == NM_DEVICE_IP_STATE_DONE) { + applied_config_init (&priv->dev_ip_config_4, config); if (!ip_config_merge_and_apply (self, AF_INET, TRUE)) { _LOGE (LOGD_AUTOIP4, "failed to update IP4 config for autoip change."); nm_device_ip_method_failed (self, AF_INET, NM_DEVICE_STATE_REASON_AUTOIP_FAILED); @@ -6872,8 +6929,8 @@ ipv4ll_timeout_cb (gpointer user_data) priv->ipv4ll_timeout = 0; ipv4ll_cleanup (self); - if (priv->ip4_state == IP_CONF) - nm_device_activate_schedule_ip4_config_timeout (self); + if (priv->ip_state_4 == NM_DEVICE_IP_STATE_CONF) + nm_device_activate_schedule_ip_config_timeout (self, AF_INET); } return FALSE; @@ -6956,7 +7013,7 @@ ensure_con_ip_config (NMDevice *self, int addr_family) if (!connection) return; - con_ip_config = _ip_config_new (self, addr_family); + con_ip_config = nm_device_ip_config_new (self, addr_family); if (IS_IPv4) { nm_ip4_config_merge_setting (NM_IP4_CONFIG (con_ip_config), @@ -7038,10 +7095,9 @@ ip_config_merge_and_apply (NMDevice *self, /* Apply ignore-auto-routes and ignore-auto-dns settings */ if (connection) { - NMSettingIPConfig *s_ip = IS_IPv4 - ? nm_connection_get_setting_ip4_config (connection) - : nm_connection_get_setting_ip6_config (connection); + NMSettingIPConfig *s_ip; + s_ip = nm_connection_get_setting_ip_config (connection, addr_family); if (s_ip) { ignore_auto_routes = nm_setting_ip_config_get_ignore_auto_routes (s_ip); ignore_auto_dns = nm_setting_ip_config_get_ignore_auto_dns (s_ip); @@ -7060,7 +7116,7 @@ ip_config_merge_and_apply (NMDevice *self, } } - composite = _ip_config_new (self, addr_family); + composite = nm_device_ip_config_new (self, addr_family); if (!IS_IPv4) { nm_ip6_config_set_privacy (NM_IP6_CONFIG (composite), @@ -7112,7 +7168,7 @@ ip_config_merge_and_apply (NMDevice *self, /* Merge all the IP configs into the composite config */ if (IS_IPv4) { - config = applied_config_get_current (&priv->dev_ip4_config); + config = applied_config_get_current (&priv->dev_ip_config_4); if (config) { nm_ip4_config_merge (NM_IP4_CONFIG (composite), NM_IP4_CONFIG (config), (ignore_auto_routes ? NM_IP_CONFIG_MERGE_NO_ROUTES : 0) @@ -7153,7 +7209,7 @@ ip_config_merge_and_apply (NMDevice *self, /* Merge WWAN config *last* to ensure modem-given settings overwrite * any external stuff set by pppd or other scripts. */ - config = applied_config_get_current (&priv->wwan_ip_config_x[IS_IPv4]); + config = applied_config_get_current (&priv->dev2_ip_config_x[IS_IPv4]); if (config) { nm_ip_config_merge (composite, config, (ignore_auto_routes ? NM_IP_CONFIG_MERGE_NO_ROUTES : 0) @@ -7234,7 +7290,7 @@ dhcp4_lease_change (NMDevice *self, NMIP4Config *config) g_return_val_if_fail (config, FALSE); - applied_config_init (&priv->dev_ip4_config, config); + applied_config_init (&priv->dev_ip_config_4, config); if (!ip_config_merge_and_apply (self, AF_INET, TRUE)) { _LOGW (LOGD_DHCP4, "failed to update IPv4 config for DHCP change."); @@ -7273,13 +7329,13 @@ dhcp4_fail (NMDevice *self, NMDhcpState dhcp_state) NMDevicePrivate *priv = NM_DEVICE_GET_PRIVATE (self); _LOGD (LOGD_DHCP4, "DHCPv4 failed (ip_state %s, was_active %d)", - _ip_state_to_string (priv->ip4_state), + _ip_state_to_string (priv->ip_state_4), priv->dhcp4.was_active); /* Keep client running if there are static addresses configured * on the interface. */ - if ( priv->ip4_state == IP_DONE + if ( priv->ip_state_4 == NM_DEVICE_IP_STATE_DONE && priv->con_ip_config_4 && nm_ip4_config_get_num_addresses (priv->con_ip_config_4) > 0) goto clear_config; @@ -7291,9 +7347,9 @@ dhcp4_fail (NMDevice *self, NMDhcpState dhcp_state) * not active before. */ if ( dhcp_state == NM_DHCP_STATE_TERMINATED - || (!priv->dhcp4.was_active && priv->ip4_state == IP_CONF)) { + || (!priv->dhcp4.was_active && priv->ip_state_4 == NM_DEVICE_IP_STATE_CONF)) { dhcp4_cleanup (self, CLEANUP_TYPE_DECONFIGURE, FALSE); - nm_device_activate_schedule_ip4_config_timeout (self); + nm_device_activate_schedule_ip_config_timeout (self, AF_INET); return; } @@ -7325,7 +7381,7 @@ static void dhcp4_dad_cb (NMDevice *self, NMIP4Config **configs, gboolean success) { if (success) - nm_device_activate_schedule_ip4_config_result (self, configs[1]); + nm_device_activate_schedule_ip_config_result (self, AF_INET, NM_IP_CONFIG_CAST (configs[1])); else { nm_device_ip_method_failed (self, AF_INET, NM_DEVICE_STATE_REASON_IP_ADDRESS_DUPLICATE); @@ -7363,8 +7419,8 @@ dhcp4_state_changed (NMDhcpClient *client, /* After some failures, we have been able to renew the lease: * update the ip state */ - if (priv->ip4_state == IP_FAIL) - _set_ip_state (self, AF_INET, IP_CONF); + if (priv->ip_state_4 == NM_DEVICE_IP_STATE_FAIL) + _set_ip_state (self, AF_INET, NM_DEVICE_IP_STATE_CONF); g_free (priv->dhcp4.pac_url); priv->dhcp4.pac_url = g_strdup (g_hash_table_lookup (options, "wpad")); @@ -7376,11 +7432,11 @@ dhcp4_state_changed (NMDhcpClient *client, nm_dhcp4_config_set_options (priv->dhcp4.config, options); _notify (self, PROP_DHCP4_CONFIG); - if (priv->ip4_state == IP_CONF) { + if (priv->ip_state_4 == NM_DEVICE_IP_STATE_CONF) { connection = nm_device_get_applied_connection (self); g_assert (connection); - manual = _ip4_config_new (self); + manual = nm_device_ip4_config_new (self); nm_ip4_config_merge_setting (manual, nm_connection_get_setting_ip4_config (connection), NM_SETTING_CONNECTION_MDNS_DEFAULT, @@ -7393,7 +7449,7 @@ dhcp4_state_changed (NMDhcpClient *client, configs[1] = g_object_ref (ip4_config); ipv4_dad_start (self, configs, dhcp4_dad_cb); - } else if (priv->ip4_state == IP_DONE) { + } else if (priv->ip_state_4 == NM_DEVICE_IP_STATE_DONE) { if (dhcp4_lease_change (self, ip4_config)) nm_device_update_metered (self); else @@ -7405,7 +7461,7 @@ dhcp4_state_changed (NMDhcpClient *client, break; case NM_DHCP_STATE_EXPIRE: /* Ignore expiry before we even have a lease (NAK, old lease, etc) */ - if (priv->ip4_state == IP_CONF) + if (priv->ip_state_4 == NM_DEVICE_IP_STATE_CONF) break; /* fall through */ case NM_DHCP_STATE_DONE: @@ -7431,10 +7487,7 @@ get_dhcp_timeout (NMDevice *self, int addr_family) connection = nm_device_get_applied_connection (self); - if (addr_family == AF_INET) - s_ip = nm_connection_get_setting_ip4_config (connection); - else - s_ip = nm_connection_get_setting_ip6_config (connection); + s_ip = nm_connection_get_setting_ip_config (connection, addr_family); timeout = nm_setting_ip_config_get_dhcp_timeout (s_ip); if (timeout) @@ -7721,7 +7774,7 @@ shared4_new_config (NMDevice *self, NMConnection *connection) is_generated = TRUE; } - config = _ip4_config_new (self); + config = nm_device_ip4_config_new (self); nm_ip4_config_add_address (config, &address); if (is_generated) { /* Remove the address lock when the object gets disposed */ @@ -7735,25 +7788,21 @@ shared4_new_config (NMDevice *self, NMConnection *connection) /*****************************************************************************/ static gboolean -connection_ip4_method_requires_carrier (NMConnection *connection, - gboolean *out_ip4_enabled) +connection_ip_method_requires_carrier (NMConnection *connection, + int addr_family, + gboolean *out_ip_enabled) { const char *method; - method = nm_utils_get_ip_config_method (connection, AF_INET); - NM_SET_OUT (out_ip4_enabled, !nm_streq (method, NM_SETTING_IP4_CONFIG_METHOD_DISABLED)); - return NM_IN_STRSET (method, NM_SETTING_IP4_CONFIG_METHOD_AUTO, - NM_SETTING_IP4_CONFIG_METHOD_LINK_LOCAL); -} + method = nm_utils_get_ip_config_method (connection, addr_family); -static gboolean -connection_ip6_method_requires_carrier (NMConnection *connection, - gboolean *out_ip6_enabled) -{ - const char *method; + if (addr_family == AF_INET) { + NM_SET_OUT (out_ip_enabled, !nm_streq (method, NM_SETTING_IP4_CONFIG_METHOD_DISABLED)); + return NM_IN_STRSET (method, NM_SETTING_IP4_CONFIG_METHOD_AUTO, + NM_SETTING_IP4_CONFIG_METHOD_LINK_LOCAL); + } - method = nm_utils_get_ip_config_method (connection, AF_INET6); - NM_SET_OUT (out_ip6_enabled, !nm_streq (method, NM_SETTING_IP6_CONFIG_METHOD_IGNORE)); + NM_SET_OUT (out_ip_enabled, !nm_streq (method, NM_SETTING_IP6_CONFIG_METHOD_IGNORE)); return NM_IN_STRSET (method, NM_SETTING_IP6_CONFIG_METHOD_AUTO, NM_SETTING_IP6_CONFIG_METHOD_DHCP, NM_SETTING_IP6_CONFIG_METHOD_SHARED, @@ -7774,7 +7823,7 @@ connection_requires_carrier (NMConnection *connection) if (nm_setting_connection_get_master (s_con)) return FALSE; - ip4_carrier_wanted = connection_ip4_method_requires_carrier (connection, &ip4_used); + ip4_carrier_wanted = connection_ip_method_requires_carrier (connection, AF_INET, &ip4_used); if (ip4_carrier_wanted) { /* If IPv4 wants a carrier and cannot fail, the whole connection * requires a carrier regardless of the IPv6 method. @@ -7784,7 +7833,7 @@ connection_requires_carrier (NMConnection *connection) return TRUE; } - ip6_carrier_wanted = connection_ip6_method_requires_carrier (connection, &ip6_used); + ip6_carrier_wanted = connection_ip_method_requires_carrier (connection, AF_INET6, &ip6_used); if (ip6_carrier_wanted) { /* If IPv6 wants a carrier and cannot fail, the whole connection * requires a carrier regardless of the IPv4 method. @@ -7825,108 +7874,6 @@ have_any_ready_slaves (NMDevice *self) return FALSE; } -static gboolean -ip4_requires_slaves (NMDevice *self) -{ - const char *method; - - method = nm_device_get_effective_ip_config_method (self, AF_INET); - return nm_streq (method, NM_SETTING_IP4_CONFIG_METHOD_AUTO); -} - -static NMActStageReturn -act_stage3_ip4_config_start (NMDevice *self, - NMIP4Config **out_config, - NMDeviceStateReason *out_failure_reason) -{ - NMDevicePrivate *priv = NM_DEVICE_GET_PRIVATE (self); - NMConnection *connection; - NMActStageReturn ret = NM_ACT_STAGE_RETURN_FAILURE; - const char *method; - - connection = nm_device_get_applied_connection (self); - g_return_val_if_fail (connection, NM_ACT_STAGE_RETURN_FAILURE); - - if ( connection_ip4_method_requires_carrier (connection, NULL) - && nm_device_is_master (self) - && !priv->carrier) { - _LOGI (LOGD_IP4 | LOGD_DEVICE, - "IPv4 config waiting until carrier is on"); - return NM_ACT_STAGE_RETURN_IP_WAIT; - } - - if (nm_device_is_master (self) && ip4_requires_slaves (self)) { - /* If the master has no ready slaves, and depends on slaves for - * a successful IPv4 attempt, then postpone IPv4 addressing. - */ - if (!have_any_ready_slaves (self)) { - _LOGI (LOGD_DEVICE | LOGD_IP4, - "IPv4 config waiting until slaves are ready"); - return NM_ACT_STAGE_RETURN_IP_WAIT; - } - } - - method = nm_device_get_effective_ip_config_method (self, AF_INET); - _LOGD (LOGD_IP4 | LOGD_DEVICE, "IPv4 config method is %s", method); - - if (NM_IN_STRSET (method, - NM_SETTING_IP4_CONFIG_METHOD_AUTO, - NM_SETTING_IP4_CONFIG_METHOD_MANUAL)) { - NMSettingIPConfig *s_ip4; - NMIP4Config **configs, *config; - guint num_addresses; - - s_ip4 = nm_connection_get_setting_ip4_config (connection); - g_return_val_if_fail (s_ip4, NM_ACT_STAGE_RETURN_FAILURE); - num_addresses = nm_setting_ip_config_get_num_addresses (s_ip4); - - if (nm_streq (method, NM_SETTING_IP4_CONFIG_METHOD_AUTO)) { - ret = dhcp4_start (self); - if (ret == NM_ACT_STAGE_RETURN_FAILURE) { - NM_SET_OUT (out_failure_reason, NM_DEVICE_STATE_REASON_DHCP_START_FAILED); - return ret; - } - } else { - g_return_val_if_fail (num_addresses != 0, NM_ACT_STAGE_RETURN_FAILURE); - ret = NM_ACT_STAGE_RETURN_POSTPONE; - } - - if (num_addresses) { - config = _ip4_config_new (self); - nm_ip4_config_merge_setting (config, - nm_connection_get_setting_ip4_config (connection), - NM_SETTING_CONNECTION_MDNS_DEFAULT, - NM_SETTING_CONNECTION_LLMNR_DEFAULT, - nm_device_get_route_table (self, AF_INET, TRUE), - nm_device_get_route_metric (self, AF_INET)); - configs = g_new0 (NMIP4Config *, 2); - configs[0] = config; - ipv4_dad_start (self, configs, ipv4_manual_method_apply); - } - } else if (nm_streq (method, NM_SETTING_IP4_CONFIG_METHOD_LINK_LOCAL)) { - ret = ipv4ll_start (self); - if (ret == NM_ACT_STAGE_RETURN_FAILURE) - NM_SET_OUT (out_failure_reason, NM_DEVICE_STATE_REASON_AUTOIP_START_FAILED); - } else if (nm_streq (method, NM_SETTING_IP4_CONFIG_METHOD_SHARED)) { - if (out_config) { - *out_config = shared4_new_config (self, connection); - if (*out_config) { - priv->dnsmasq_manager = nm_dnsmasq_manager_new (nm_device_get_ip_iface (self)); - ret = NM_ACT_STAGE_RETURN_SUCCESS; - } else { - NM_SET_OUT (out_failure_reason, NM_DEVICE_STATE_REASON_IP_CONFIG_UNAVAILABLE); - ret = NM_ACT_STAGE_RETURN_FAILURE; - } - } else - g_return_val_if_reached (NM_ACT_STAGE_RETURN_FAILURE); - } else if (nm_streq (method, NM_SETTING_IP4_CONFIG_METHOD_DISABLED)) - ret = NM_ACT_STAGE_RETURN_SUCCESS; - else - _LOGW (LOGD_IP4, "unhandled IPv4 config method '%s'; will fail", method); - - return ret; -} - /*****************************************************************************/ /* DHCPv6 stuff */ @@ -8015,7 +7962,7 @@ dhcp6_fail (NMDevice *self, NMDhcpState dhcp_state) gboolean is_dhcp_managed; _LOGD (LOGD_DHCP6, "DHCPv6 failed (ip_state %s, was_active %d)", - _ip_state_to_string (priv->ip6_state), + _ip_state_to_string (priv->ip_state_6), priv->dhcp6.was_active); is_dhcp_managed = (priv->dhcp6.mode == NM_NDISC_DHCP_LEVEL_MANAGED); @@ -8024,7 +7971,7 @@ dhcp6_fail (NMDevice *self, NMDhcpState dhcp_state) /* Keep client running if there are static addresses configured * on the interface. */ - if ( priv->ip6_state == IP_DONE + if ( priv->ip_state_6 == NM_DEVICE_IP_STATE_DONE && priv->con_ip_config_6 && nm_ip6_config_get_num_addresses (priv->con_ip_config_6)) goto clear_config; @@ -8036,9 +7983,9 @@ dhcp6_fail (NMDevice *self, NMDhcpState dhcp_state) * not active before. */ if ( dhcp_state == NM_DHCP_STATE_TERMINATED - || (!priv->dhcp6.was_active && priv->ip6_state == IP_CONF)) { + || (!priv->dhcp6.was_active && priv->ip_state_6 == NM_DEVICE_IP_STATE_CONF)) { dhcp6_cleanup (self, CLEANUP_TYPE_DECONFIGURE, FALSE); - nm_device_activate_schedule_ip6_config_timeout (self); + nm_device_activate_schedule_ip_config_timeout (self, AF_INET6); return; } @@ -8058,8 +8005,8 @@ dhcp6_fail (NMDevice *self, NMDhcpState dhcp_state) } else { /* not a hard failure; just live with the RA info */ dhcp6_cleanup (self, CLEANUP_TYPE_DECONFIGURE, FALSE); - if (priv->ip6_state == IP_CONF) - nm_device_activate_schedule_ip6_config_result (self); + if (priv->ip_state_6 == NM_DEVICE_IP_STATE_CONF) + nm_device_activate_schedule_ip_config_result (self, AF_INET6, NULL); } return; @@ -8118,16 +8065,16 @@ dhcp6_state_changed (NMDhcpClient *client, /* After long time we have been able to renew the lease: * update the ip state */ - if (priv->ip6_state == IP_FAIL) - _set_ip_state (self, AF_INET6, IP_CONF); + if (priv->ip_state_6 == NM_DEVICE_IP_STATE_FAIL) + _set_ip_state (self, AF_INET6, NM_DEVICE_IP_STATE_CONF); - if (priv->ip6_state == IP_CONF) { + if (priv->ip_state_6 == NM_DEVICE_IP_STATE_CONF) { if (!applied_config_get_current (&priv->dhcp6.ip6_config)) { nm_device_ip_method_failed (self, AF_INET6, NM_DEVICE_STATE_REASON_DHCP_FAILED); break; } - nm_device_activate_schedule_ip6_config_result (self); - } else if (priv->ip6_state == IP_DONE) + nm_device_activate_schedule_ip_config_result (self, AF_INET6, NULL); + } else if (priv->ip_state_6 == NM_DEVICE_IP_STATE_DONE) if (!dhcp6_lease_change (self)) dhcp6_fail (self, state); break; @@ -8137,13 +8084,13 @@ dhcp6_state_changed (NMDhcpClient *client, else { /* not a hard failure; just live with the RA info */ dhcp6_cleanup (self, CLEANUP_TYPE_DECONFIGURE, FALSE); - if (priv->ip6_state == IP_CONF) - nm_device_activate_schedule_ip6_config_result (self); + if (priv->ip_state_6 == NM_DEVICE_IP_STATE_CONF) + nm_device_activate_schedule_ip_config_result (self, AF_INET6, NULL); } break; case NM_DHCP_STATE_EXPIRE: /* Ignore expiry before we even have a lease (NAK, old lease, etc) */ - if (priv->ip6_state != IP_CONF) + if (priv->ip_state_6 != NM_DEVICE_IP_STATE_CONF) dhcp6_fail (self, state); break; case NM_DHCP_STATE_TERMINATED: @@ -8350,7 +8297,7 @@ dhcp6_get_duid (NMDevice *self, NMConnection *connection, GBytes *hwaddr, gboole /* preferably, we would salt the checksum differently for each @duid type. We missed * to do that initially, so most types use the DEFAULT_SALT. * - * Implemenations that are added later, should use a distinct salt instead, + * Implementations that are added later, should use a distinct salt instead, * like "stable-ll"/"stable-llt" with ARPHRD_INFINIBAND below. */ const guint32 DEFAULT_SALT = 670531087u; nm_auto_free_checksum GChecksum *sum = NULL; @@ -8719,7 +8666,7 @@ linklocal6_failed (NMDevice *self) NMDevicePrivate *priv = NM_DEVICE_GET_PRIVATE (self); nm_clear_g_source (&priv->linklocal6_timeout_id); - nm_device_activate_schedule_ip6_config_timeout (self); + nm_device_activate_schedule_ip_config_timeout (self, AF_INET6); } static gboolean @@ -8767,10 +8714,10 @@ linklocal6_check_complete (NMDevice *self) else if (nm_streq (method, NM_SETTING_IP6_CONFIG_METHOD_DHCP)) { if (!dhcp6_start_with_link_ready (self, connection)) { /* Time out IPv6 instead of failing the entire activation */ - nm_device_activate_schedule_ip6_config_timeout (self); + nm_device_activate_schedule_ip_config_timeout (self, AF_INET6); } } else if (nm_streq (method, NM_SETTING_IP6_CONFIG_METHOD_LINK_LOCAL)) - nm_device_activate_schedule_ip6_config_result (self); + nm_device_activate_schedule_ip_config_result (self, AF_INET6, NULL); else g_return_if_fail (FALSE); } @@ -8927,6 +8874,10 @@ nm_device_get_configured_mtu_from_connection (NMDevice *self, if (setting) mtu = nm_setting_ip_tunnel_get_mtu (NM_SETTING_IP_TUNNEL (setting)); global_property_name = NM_CON_DEFAULT ("ip-tunnel.mtu"); + } else if (setting_type == NM_TYPE_SETTING_WIREGUARD) { + if (setting) + mtu = nm_setting_wireguard_get_mtu (NM_SETTING_WIREGUARD (setting)); + global_property_name = NM_CON_DEFAULT ("wireguard.mtu"); } else g_return_val_if_reached (0); @@ -9282,7 +9233,7 @@ ndisc_config_changed (NMNDisc *ndisc, const NMNDiscData *rdata, guint changed_in } } - nm_device_activate_schedule_ip6_config_result (self); + nm_device_activate_schedule_ip_config_result (self, AF_INET6, NULL); } static void @@ -9296,7 +9247,7 @@ ndisc_ra_timeout (NMNDisc *ndisc, NMDevice *self) */ _LOGD (LOGD_IP6, "timed out waiting for IPv6 router advertisement"); - if (priv->ip6_state == IP_CONF) { + if (priv->ip_state_6 == NM_DEVICE_IP_STATE_CONF) { /* If RA is our only source of addressing information and we don't * ever receive one, then time out IPv6. But if there is other * IPv6 configuration, like manual IPv6 addresses or external IPv6 @@ -9309,9 +9260,9 @@ ndisc_ra_timeout (NMNDisc *ndisc, NMDevice *self) && nm_ip6_config_find_first_address (priv->ip_config_6, NM_PLATFORM_MATCH_WITH_ADDRTYPE_NORMAL | NM_PLATFORM_MATCH_WITH_ADDRSTATE__ANY)) - nm_device_activate_schedule_ip6_config_result (self); + nm_device_activate_schedule_ip_config_result (self, AF_INET6, NULL); else - nm_device_activate_schedule_ip6_config_timeout (self); + nm_device_activate_schedule_ip_config_timeout (self, AF_INET6); } } @@ -9348,7 +9299,7 @@ addrconf6_start_with_link_ready (NMDevice *self) case NM_NDISC_NODE_TYPE_ROUTER: /* We're the router. */ nm_device_sysctl_ip_conf_set (self, AF_INET6, "forwarding", "1"); - nm_device_activate_schedule_ip6_config_result (self); + nm_device_activate_schedule_ip_config_result (self, AF_INET6, NULL); priv->needs_ip6_subnet = TRUE; g_signal_emit (self, signals[IP6_SUBNET_NEEDED], 0); break; @@ -9515,7 +9466,7 @@ restore_ip6_properties (NMDevice *self) } } -static inline void +static void set_disable_ipv6 (NMDevice *self, const char *value) { /* We only touch disable_ipv6 when NM is not managing the IPv6LL address */ @@ -9523,7 +9474,7 @@ set_disable_ipv6 (NMDevice *self, const char *value) nm_device_sysctl_ip_conf_set (self, AF_INET6, "disable_ipv6", value); } -static inline void +static void set_nm_ipv6ll (NMDevice *self, gboolean enable) { NMDevicePrivate *priv = NM_DEVICE_GET_PRIVATE (self); @@ -9541,7 +9492,7 @@ set_nm_ipv6ll (NMDevice *self, gboolean enable) _LOGD (LOGD_IP6, "will %s userland IPv6LL", detail); r = nm_platform_link_set_user_ipv6ll_enabled (nm_device_get_platform (self), ifindex, enable); if (r < 0) { - _NMLOG ( NM_IN_SET (r, -NME_PL_NOT_FOUND + _NMLOG ( NM_IN_SET (r, -NME_PL_NOT_FOUND, -NME_PL_OPNOTSUPP) ? LOGL_DEBUG : LOGL_WARN, @@ -9632,11 +9583,14 @@ _ip6_privacy_get (NMDevice *self) /*****************************************************************************/ static gboolean -ip6_requires_slaves (NMDevice *self) +ip_requires_slaves (NMDevice *self, int addr_family) { const char *method; - method = nm_device_get_effective_ip_config_method (self, AF_INET6); + method = nm_device_get_effective_ip_config_method (self, addr_family); + + if (addr_family == AF_INET) + return nm_streq (method, NM_SETTING_IP4_CONFIG_METHOD_AUTO); /* SLAAC, DHCP, and Link-Local depend on connectivity (and thus slaves) * to complete addressing. SLAAC and DHCP need a peer to provide a prefix. @@ -9646,128 +9600,202 @@ ip6_requires_slaves (NMDevice *self) } static NMActStageReturn -act_stage3_ip6_config_start (NMDevice *self, - NMIP6Config **out_config, - NMDeviceStateReason *out_failure_reason) +act_stage3_ip_config_start (NMDevice *self, + int addr_family, + gpointer *out_config, + NMDeviceStateReason *out_failure_reason) { + const gboolean IS_IPv4 = (addr_family == AF_INET); NMDevicePrivate *priv = NM_DEVICE_GET_PRIVATE (self); - NMActStageReturn ret = NM_ACT_STAGE_RETURN_FAILURE; NMConnection *connection; + NMActStageReturn ret = NM_ACT_STAGE_RETURN_FAILURE; const char *method; - NMSettingIP6ConfigPrivacy ip6_privacy = NM_SETTING_IP6_CONFIG_PRIVACY_UNKNOWN; - const char *ip6_privacy_str = "0"; + + nm_assert_addr_family (addr_family); connection = nm_device_get_applied_connection (self); + g_return_val_if_fail (connection, NM_ACT_STAGE_RETURN_FAILURE); - if ( connection_ip6_method_requires_carrier (connection, NULL) + if ( connection_ip_method_requires_carrier (connection, addr_family, NULL) && nm_device_is_master (self) && !priv->carrier) { - _LOGI (LOGD_IP6 | LOGD_DEVICE, - "IPv6 config waiting until carrier is on"); + _LOGI (LOGD_IP | LOGD_DEVICE, + "IPv%c config waiting until carrier is on", + nm_utils_addr_family_to_char (addr_family)); return NM_ACT_STAGE_RETURN_IP_WAIT; } - if (nm_device_is_master (self) && ip6_requires_slaves (self)) { + if ( nm_device_is_master (self) + && ip_requires_slaves (self, addr_family)) { /* If the master has no ready slaves, and depends on slaves for - * a successful IPv6 attempt, then postpone IPv6 addressing. + * a successful IP configuration attempt, then postpone IP addressing. */ if (!have_any_ready_slaves (self)) { - _LOGI (LOGD_DEVICE | LOGD_IP6, - "IPv6 config waiting until slaves are ready"); + _LOGI (LOGD_DEVICE | LOGD_IP, + "IPv%c config waiting until slaves are ready", + nm_utils_addr_family_to_char (addr_family)); return NM_ACT_STAGE_RETURN_IP_WAIT; } } - priv->dhcp6.mode = NM_NDISC_DHCP_LEVEL_NONE; - method = nm_device_get_effective_ip_config_method (self, AF_INET6); - if (nm_streq (method, NM_SETTING_IP6_CONFIG_METHOD_IGNORE)) { - if ( !priv->master - && !nm_device_sys_iface_state_is_external (self)) { - gboolean ipv6ll_handle_old = priv->ipv6ll_handle; + if (!IS_IPv4) + priv->dhcp6.mode = NM_NDISC_DHCP_LEVEL_NONE; - /* When activating an IPv6 'ignore' connection we need to revert back - * to kernel IPv6LL, but the kernel won't actually assign an address - * to the interface until disable_ipv6 is bounced. - */ - set_nm_ipv6ll (self, FALSE); - if (ipv6ll_handle_old) - nm_device_sysctl_ip_conf_set (self, AF_INET6, "disable_ipv6", "1"); - restore_ip6_properties (self); + method = nm_device_get_effective_ip_config_method (self, addr_family); + + _LOGD (LOGD_IP | LOGD_DEVICE, "IPv%c config method is %s", + nm_utils_addr_family_to_char (addr_family), method); + + if (IS_IPv4) { + if (NM_IN_STRSET (method, + NM_SETTING_IP4_CONFIG_METHOD_AUTO, + NM_SETTING_IP4_CONFIG_METHOD_MANUAL)) { + NMSettingIPConfig *s_ip4; + NMIP4Config **configs, *config; + guint num_addresses; + + s_ip4 = nm_connection_get_setting_ip4_config (connection); + g_return_val_if_fail (s_ip4, NM_ACT_STAGE_RETURN_FAILURE); + num_addresses = nm_setting_ip_config_get_num_addresses (s_ip4); + + if (nm_streq (method, NM_SETTING_IP4_CONFIG_METHOD_AUTO)) { + ret = dhcp4_start (self); + if (ret == NM_ACT_STAGE_RETURN_FAILURE) { + NM_SET_OUT (out_failure_reason, NM_DEVICE_STATE_REASON_DHCP_START_FAILED); + return ret; + } + } else { + g_return_val_if_fail (num_addresses != 0, NM_ACT_STAGE_RETURN_FAILURE); + ret = NM_ACT_STAGE_RETURN_POSTPONE; + } + + if (num_addresses) { + config = nm_device_ip4_config_new (self); + nm_ip4_config_merge_setting (config, + nm_connection_get_setting_ip4_config (connection), + NM_SETTING_CONNECTION_MDNS_DEFAULT, + NM_SETTING_CONNECTION_LLMNR_DEFAULT, + nm_device_get_route_table (self, AF_INET, TRUE), + nm_device_get_route_metric (self, AF_INET)); + configs = g_new0 (NMIP4Config *, 2); + configs[0] = config; + ipv4_dad_start (self, configs, ipv4_manual_method_apply); + } + } else if (nm_streq (method, NM_SETTING_IP4_CONFIG_METHOD_LINK_LOCAL)) { + ret = ipv4ll_start (self); + if (ret == NM_ACT_STAGE_RETURN_FAILURE) + NM_SET_OUT (out_failure_reason, NM_DEVICE_STATE_REASON_AUTOIP_START_FAILED); + } else if (nm_streq (method, NM_SETTING_IP4_CONFIG_METHOD_SHARED)) { + if (out_config) { + *out_config = shared4_new_config (self, connection); + if (*out_config) { + priv->dnsmasq_manager = nm_dnsmasq_manager_new (nm_device_get_ip_iface (self)); + ret = NM_ACT_STAGE_RETURN_SUCCESS; + } else { + NM_SET_OUT (out_failure_reason, NM_DEVICE_STATE_REASON_IP_CONFIG_UNAVAILABLE); + ret = NM_ACT_STAGE_RETURN_FAILURE; + } + } else + g_return_val_if_reached (NM_ACT_STAGE_RETURN_FAILURE); + } else if (nm_streq (method, NM_SETTING_IP4_CONFIG_METHOD_DISABLED)) + ret = NM_ACT_STAGE_RETURN_SUCCESS; + else + _LOGW (LOGD_IP4, "unhandled IPv4 config method '%s'; will fail", method); + + return ret; + } else { + NMSettingIP6ConfigPrivacy ip6_privacy = NM_SETTING_IP6_CONFIG_PRIVACY_UNKNOWN; + const char *ip6_privacy_str = "0"; + + if (nm_streq (method, NM_SETTING_IP6_CONFIG_METHOD_IGNORE)) { + if ( !priv->master + && !nm_device_sys_iface_state_is_external (self)) { + gboolean ipv6ll_handle_old = priv->ipv6ll_handle; + + /* When activating an IPv6 'ignore' connection we need to revert back + * to kernel IPv6LL, but the kernel won't actually assign an address + * to the interface until disable_ipv6 is bounced. + */ + set_nm_ipv6ll (self, FALSE); + if (ipv6ll_handle_old) + nm_device_sysctl_ip_conf_set (self, AF_INET6, "disable_ipv6", "1"); + restore_ip6_properties (self); + } + return NM_ACT_STAGE_RETURN_IP_DONE; } - return NM_ACT_STAGE_RETURN_IP_DONE; - } - /* Ensure the MTU makes sense. If it was below 1280 the kernel would not - * expose any ipv6 sysctls or allow presence of any addresses on the interface, - * including LL, which * would make it impossible to autoconfigure MTU to a - * correct value. */ - _commit_mtu (self, priv->ip_config_4); + /* Ensure the MTU makes sense. If it was below 1280 the kernel would not + * expose any ipv6 sysctls or allow presence of any addresses on the interface, + * including LL, which * would make it impossible to autoconfigure MTU to a + * correct value. */ + _commit_mtu (self, priv->ip_config_4); - /* Any method past this point requires an IPv6LL address. Use NM-controlled - * IPv6LL if this is not an assumed connection, since assumed connections - * will already have IPv6 set up. - */ - if (!nm_device_sys_iface_state_is_external_or_assume (self)) - set_nm_ipv6ll (self, TRUE); + /* Any method past this point requires an IPv6LL address. Use NM-controlled + * IPv6LL if this is not an assumed connection, since assumed connections + * will already have IPv6 set up. + */ + if (!nm_device_sys_iface_state_is_external_or_assume (self)) + set_nm_ipv6ll (self, TRUE); - /* Re-enable IPv6 on the interface */ - set_disable_ipv6 (self, "0"); + /* Re-enable IPv6 on the interface */ + set_disable_ipv6 (self, "0"); - /* Synchronize external IPv6 configuration with kernel, since - * linklocal6_start() uses the information there to determine if we can - * proceed with the selected method (SLAAC, DHCP, link-local). - */ - nm_platform_process_events (nm_device_get_platform (self)); - g_clear_object (&priv->ext_ip6_config_captured); - priv->ext_ip6_config_captured = nm_ip6_config_capture (nm_device_get_multi_index (self), - nm_device_get_platform (self), - nm_device_get_ip_ifindex (self), - NM_SETTING_IP6_CONFIG_PRIVACY_UNKNOWN); + /* Synchronize external IPv6 configuration with kernel, since + * linklocal6_start() uses the information there to determine if we can + * proceed with the selected method (SLAAC, DHCP, link-local). + */ + nm_platform_process_events (nm_device_get_platform (self)); + g_clear_object (&priv->ext_ip6_config_captured); + priv->ext_ip6_config_captured = nm_ip6_config_capture (nm_device_get_multi_index (self), + nm_device_get_platform (self), + nm_device_get_ip_ifindex (self), + NM_SETTING_IP6_CONFIG_PRIVACY_UNKNOWN); - ip6_privacy = _ip6_privacy_get (self); + ip6_privacy = _ip6_privacy_get (self); - if (NM_IN_STRSET (method, NM_SETTING_IP6_CONFIG_METHOD_AUTO, - NM_SETTING_IP6_CONFIG_METHOD_SHARED)) { - if (!addrconf6_start (self, ip6_privacy)) { - /* IPv6 might be disabled; allow IPv4 to proceed */ - ret = NM_ACT_STAGE_RETURN_IP_FAIL; - } else - ret = NM_ACT_STAGE_RETURN_POSTPONE; - } else if (nm_streq (method, NM_SETTING_IP6_CONFIG_METHOD_LINK_LOCAL)) { - ret = linklocal6_start (self) - ? NM_ACT_STAGE_RETURN_SUCCESS - : NM_ACT_STAGE_RETURN_POSTPONE; - } else if (nm_streq (method, NM_SETTING_IP6_CONFIG_METHOD_DHCP)) { - priv->dhcp6.mode = NM_NDISC_DHCP_LEVEL_MANAGED; - if (!dhcp6_start (self, TRUE)) { - /* IPv6 might be disabled; allow IPv4 to proceed */ - ret = NM_ACT_STAGE_RETURN_IP_FAIL; - } else - ret = NM_ACT_STAGE_RETURN_POSTPONE; - } else if (nm_streq (method, NM_SETTING_IP6_CONFIG_METHOD_MANUAL)) - ret = NM_ACT_STAGE_RETURN_SUCCESS; - else - _LOGW (LOGD_IP6, "unhandled IPv6 config method '%s'; will fail", method); - - if ( ret != NM_ACT_STAGE_RETURN_FAILURE - && !nm_device_sys_iface_state_is_external_or_assume (self)) { - switch (ip6_privacy) { - case NM_SETTING_IP6_CONFIG_PRIVACY_UNKNOWN: - case NM_SETTING_IP6_CONFIG_PRIVACY_DISABLED: - ip6_privacy_str = "0"; - break; - case NM_SETTING_IP6_CONFIG_PRIVACY_PREFER_PUBLIC_ADDR: - ip6_privacy_str = "1"; - break; - case NM_SETTING_IP6_CONFIG_PRIVACY_PREFER_TEMP_ADDR: - ip6_privacy_str = "2"; - break; + if (NM_IN_STRSET (method, NM_SETTING_IP6_CONFIG_METHOD_AUTO, + NM_SETTING_IP6_CONFIG_METHOD_SHARED)) { + if (!addrconf6_start (self, ip6_privacy)) { + /* IPv6 might be disabled; allow IPv4 to proceed */ + ret = NM_ACT_STAGE_RETURN_IP_FAIL; + } else + ret = NM_ACT_STAGE_RETURN_POSTPONE; + } else if (nm_streq (method, NM_SETTING_IP6_CONFIG_METHOD_LINK_LOCAL)) { + ret = linklocal6_start (self) + ? NM_ACT_STAGE_RETURN_SUCCESS + : NM_ACT_STAGE_RETURN_POSTPONE; + } else if (nm_streq (method, NM_SETTING_IP6_CONFIG_METHOD_DHCP)) { + priv->dhcp6.mode = NM_NDISC_DHCP_LEVEL_MANAGED; + if (!dhcp6_start (self, TRUE)) { + /* IPv6 might be disabled; allow IPv4 to proceed */ + ret = NM_ACT_STAGE_RETURN_IP_FAIL; + } else + ret = NM_ACT_STAGE_RETURN_POSTPONE; + } else if (nm_streq (method, NM_SETTING_IP6_CONFIG_METHOD_MANUAL)) + ret = NM_ACT_STAGE_RETURN_SUCCESS; + else + _LOGW (LOGD_IP6, "unhandled IPv6 config method '%s'; will fail", method); + + if ( ret != NM_ACT_STAGE_RETURN_FAILURE + && !nm_device_sys_iface_state_is_external_or_assume (self)) { + switch (ip6_privacy) { + case NM_SETTING_IP6_CONFIG_PRIVACY_UNKNOWN: + case NM_SETTING_IP6_CONFIG_PRIVACY_DISABLED: + ip6_privacy_str = "0"; + break; + case NM_SETTING_IP6_CONFIG_PRIVACY_PREFER_PUBLIC_ADDR: + ip6_privacy_str = "1"; + break; + case NM_SETTING_IP6_CONFIG_PRIVACY_PREFER_TEMP_ADDR: + ip6_privacy_str = "2"; + break; + } + nm_device_sysctl_ip_conf_set (self, AF_INET6, "use_tempaddr", ip6_privacy_str); } - nm_device_sysctl_ip_conf_set (self, AF_INET6, "use_tempaddr", ip6_privacy_str); - } - return ret; + return ret; + } } /** @@ -9782,35 +9810,32 @@ nm_device_activate_stage3_ip4_start (NMDevice *self) NMDevicePrivate *priv = NM_DEVICE_GET_PRIVATE (self); NMActStageReturn ret; NMDeviceStateReason failure_reason = NM_DEVICE_STATE_REASON_NONE; - NMIP4Config *ip4_config = NULL; + gs_unref_object NMIP4Config *ip4_config = NULL; - g_assert (priv->ip4_state == IP_WAIT); + g_assert (priv->ip_state_4 == NM_DEVICE_IP_STATE_WAIT); if (nm_device_sys_iface_state_is_external (self)) { - _set_ip_state (self, AF_INET, IP_DONE); + _set_ip_state (self, AF_INET, NM_DEVICE_IP_STATE_DONE); check_ip_state (self, FALSE, TRUE); return TRUE; } - _set_ip_state (self, AF_INET, IP_CONF); - ret = NM_DEVICE_GET_CLASS (self)->act_stage3_ip4_config_start (self, &ip4_config, &failure_reason); - if (ret == NM_ACT_STAGE_RETURN_SUCCESS) { - if (!ip4_config) - ip4_config = _ip4_config_new (self); - nm_device_activate_schedule_ip4_config_result (self, ip4_config); - g_object_unref (ip4_config); - } else if (ret == NM_ACT_STAGE_RETURN_IP_DONE) { - _set_ip_state (self, AF_INET, IP_DONE); + _set_ip_state (self, AF_INET, NM_DEVICE_IP_STATE_CONF); + ret = NM_DEVICE_GET_CLASS (self)->act_stage3_ip_config_start (self, AF_INET, (gpointer *) &ip4_config, &failure_reason); + if (ret == NM_ACT_STAGE_RETURN_SUCCESS) + nm_device_activate_schedule_ip_config_result (self, AF_INET, NM_IP_CONFIG_CAST (ip4_config)); + else if (ret == NM_ACT_STAGE_RETURN_IP_DONE) { + _set_ip_state (self, AF_INET, NM_DEVICE_IP_STATE_DONE); check_ip_state (self, FALSE, TRUE); } else if (ret == NM_ACT_STAGE_RETURN_FAILURE) { nm_device_state_changed (self, NM_DEVICE_STATE_FAILED, failure_reason); return FALSE; } else if (ret == NM_ACT_STAGE_RETURN_IP_FAIL) { /* Activation not wanted */ - _set_ip_state (self, AF_INET, IP_FAIL); + _set_ip_state (self, AF_INET, NM_DEVICE_IP_STATE_FAIL); } else if (ret == NM_ACT_STAGE_RETURN_IP_WAIT) { /* Wait for something to try IP config again */ - _set_ip_state (self, AF_INET, IP_WAIT); + _set_ip_state (self, AF_INET, NM_DEVICE_IP_STATE_WAIT); } else g_assert (ret == NM_ACT_STAGE_RETURN_POSTPONE); @@ -9831,37 +9856,37 @@ nm_device_activate_stage3_ip6_start (NMDevice *self) NMDeviceStateReason failure_reason = NM_DEVICE_STATE_REASON_NONE; NMIP6Config *ip6_config = NULL; - g_assert (priv->ip6_state == IP_WAIT); + g_assert (priv->ip_state_6 == NM_DEVICE_IP_STATE_WAIT); if (nm_device_sys_iface_state_is_external (self)) { - _set_ip_state (self, AF_INET6, IP_DONE); + _set_ip_state (self, AF_INET6, NM_DEVICE_IP_STATE_DONE); check_ip_state (self, FALSE, TRUE); return TRUE; } - _set_ip_state (self, AF_INET6, IP_CONF); - ret = NM_DEVICE_GET_CLASS (self)->act_stage3_ip6_config_start (self, &ip6_config, &failure_reason); + _set_ip_state (self, AF_INET6, NM_DEVICE_IP_STATE_CONF); + ret = NM_DEVICE_GET_CLASS (self)->act_stage3_ip_config_start (self, AF_INET6, (gpointer *) &ip6_config, &failure_reason); if (ret == NM_ACT_STAGE_RETURN_SUCCESS) { if (!ip6_config) - ip6_config = _ip6_config_new (self); + ip6_config = nm_device_ip6_config_new (self); /* Here we get a static IPv6 config, like for Shared where it's * autogenerated or from modems where it comes from ModemManager. */ nm_assert (!applied_config_get_current (&priv->ac_ip6_config)); applied_config_init (&priv->ac_ip6_config, ip6_config); - nm_device_activate_schedule_ip6_config_result (self); + nm_device_activate_schedule_ip_config_result (self, AF_INET6, NULL); } else if (ret == NM_ACT_STAGE_RETURN_IP_DONE) { - _set_ip_state (self, AF_INET6, IP_DONE); + _set_ip_state (self, AF_INET6, NM_DEVICE_IP_STATE_DONE); check_ip_state (self, FALSE, TRUE); } else if (ret == NM_ACT_STAGE_RETURN_FAILURE) { nm_device_state_changed (self, NM_DEVICE_STATE_FAILED, failure_reason); return FALSE; } else if (ret == NM_ACT_STAGE_RETURN_IP_FAIL) { /* Activation not wanted */ - _set_ip_state (self, AF_INET6, IP_FAIL); + _set_ip_state (self, AF_INET6, NM_DEVICE_IP_STATE_FAIL); } else if (ret == NM_ACT_STAGE_RETURN_IP_WAIT) { /* Wait for something to try IP config again */ - _set_ip_state (self, AF_INET6, IP_WAIT); + _set_ip_state (self, AF_INET6, NM_DEVICE_IP_STATE_WAIT); } else g_assert (ret == NM_ACT_STAGE_RETURN_POSTPONE); @@ -9879,8 +9904,8 @@ activate_stage3_ip_config_start (NMDevice *self) { int ifindex; - _set_ip_state (self, AF_INET, IP_WAIT); - _set_ip_state (self, AF_INET6, IP_WAIT); + _set_ip_state (self, AF_INET, NM_DEVICE_IP_STATE_WAIT); + _set_ip_state (self, AF_INET6, NM_DEVICE_IP_STATE_WAIT); _active_connection_set_state_flags (self, NM_ACTIVATION_STATE_FLAG_LAYER2_READY); @@ -9935,7 +9960,7 @@ fw_change_zone_cb (NMFirewallManager *firewall_manager, break; case FIREWALL_STATE_WAIT_IP_CONFIG: priv->fw_state = FIREWALL_STATE_INITIALIZED; - if (priv->ip4_state == IP_DONE || priv->ip6_state == IP_DONE) + if (priv->ip_state_4 == NM_DEVICE_IP_STATE_DONE || priv->ip_state_6 == NM_DEVICE_IP_STATE_DONE) nm_device_start_ip_check (self); break; case FIREWALL_STATE_INITIALIZED: @@ -10012,15 +10037,21 @@ nm_device_activate_schedule_stage3_ip_config_start (NMDevice *self) } static NMActStageReturn -act_stage4_ip4_config_timeout (NMDevice *self, NMDeviceStateReason *out_failure_reason) +act_stage4_ip_config_timeout (NMDevice *self, + int addr_family, + NMDeviceStateReason *out_failure_reason) { - if (!get_ip_config_may_fail (self, AF_INET)) { + nm_assert_addr_family (addr_family); + + if (!get_ip_config_may_fail (self, addr_family)) { NM_SET_OUT (out_failure_reason, NM_DEVICE_STATE_REASON_IP_CONFIG_UNAVAILABLE); return NM_ACT_STAGE_RETURN_FAILURE; } + return NM_ACT_STAGE_RETURN_SUCCESS; } + /* * nm_device_activate_stage4_ip4_config_timeout * @@ -10028,12 +10059,12 @@ act_stage4_ip4_config_timeout (NMDevice *self, NMDeviceStateReason *out_failure_ * */ static void -activate_stage4_ip4_config_timeout (NMDevice *self) +activate_stage4_ip_config_timeout_4 (NMDevice *self) { NMActStageReturn ret = NM_ACT_STAGE_RETURN_FAILURE; NMDeviceStateReason failure_reason = NM_DEVICE_STATE_REASON_NONE; - ret = NM_DEVICE_GET_CLASS (self)->act_stage4_ip4_config_timeout (self, &failure_reason); + ret = NM_DEVICE_GET_CLASS (self)->act_stage4_ip_config_timeout (self, AF_INET6, &failure_reason); if (ret == NM_ACT_STAGE_RETURN_POSTPONE) return; else if (ret == NM_ACT_STAGE_RETURN_FAILURE) { @@ -10042,54 +10073,35 @@ activate_stage4_ip4_config_timeout (NMDevice *self) } g_assert (ret == NM_ACT_STAGE_RETURN_SUCCESS); - _set_ip_state (self, AF_INET, IP_FAIL); + _set_ip_state (self, AF_INET, NM_DEVICE_IP_STATE_FAIL); check_ip_state (self, FALSE, TRUE); } -/* - * nm_device_activate_schedule_ip4_config_timeout - * - * Deal with a timeout of the IPv4 configuration - * - */ void -nm_device_activate_schedule_ip4_config_timeout (NMDevice *self) +nm_device_activate_schedule_ip_config_timeout (NMDevice *self, + int addr_family) { NMDevicePrivate *priv; + const gboolean IS_IPv4 = (addr_family == AF_INET); g_return_if_fail (NM_IS_DEVICE (self)); + g_return_if_fail (NM_IN_SET (addr_family, AF_INET, AF_INET6)); priv = NM_DEVICE_GET_PRIVATE (self); - g_return_if_fail (priv->act_request.obj); - activation_source_schedule (self, activate_stage4_ip4_config_timeout, AF_INET); -} - -static NMActStageReturn -act_stage4_ip6_config_timeout (NMDevice *self, NMDeviceStateReason *out_failure_reason) -{ - if (!get_ip_config_may_fail (self, AF_INET6)) { - NM_SET_OUT (out_failure_reason, NM_DEVICE_STATE_REASON_IP_CONFIG_UNAVAILABLE); - return NM_ACT_STAGE_RETURN_FAILURE; - } + g_return_if_fail (priv->act_request.obj); - return NM_ACT_STAGE_RETURN_SUCCESS; + activation_source_schedule (self, activate_stage4_ip_config_timeout_x[IS_IPv4], addr_family); } -/* - * activate_stage4_ip6_config_timeout - * - * Time out on retrieving the IPv6 config. - * - */ static void -activate_stage4_ip6_config_timeout (NMDevice *self) +activate_stage4_ip_config_timeout_6 (NMDevice *self) { NMActStageReturn ret = NM_ACT_STAGE_RETURN_FAILURE; NMDeviceStateReason failure_reason = NM_DEVICE_STATE_REASON_NONE; - ret = NM_DEVICE_GET_CLASS (self)->act_stage4_ip6_config_timeout (self, &failure_reason); + ret = NM_DEVICE_GET_CLASS (self)->act_stage4_ip_config_timeout (self, AF_INET6, &failure_reason); if (ret == NM_ACT_STAGE_RETURN_POSTPONE) return; if (ret == NM_ACT_STAGE_RETURN_FAILURE) { @@ -10098,30 +10110,11 @@ activate_stage4_ip6_config_timeout (NMDevice *self) } g_assert (ret == NM_ACT_STAGE_RETURN_SUCCESS); - _set_ip_state (self, AF_INET6, IP_FAIL); + _set_ip_state (self, AF_INET6, NM_DEVICE_IP_STATE_FAIL); check_ip_state (self, FALSE, TRUE); } -/* - * nm_device_activate_schedule_ip6_config_timeout - * - * Deal with a timeout of the IPv6 configuration - * - */ -void -nm_device_activate_schedule_ip6_config_timeout (NMDevice *self) -{ - NMDevicePrivate *priv; - - g_return_if_fail (NM_IS_DEVICE (self)); - - priv = NM_DEVICE_GET_PRIVATE (self); - g_return_if_fail (priv->act_request.obj); - - activation_source_schedule (self, activate_stage4_ip6_config_timeout, AF_INET6); -} - static gboolean share_init (NMDevice *self, GError **error) { @@ -10136,9 +10129,9 @@ share_init (NMDevice *self, GError **error) } else if (!nm_platform_sysctl_set (nm_device_get_platform (self), NMP_SYSCTL_PATHID_ABSOLUTE ("/proc/sys/net/ipv4/ip_forward"), "1")) { errsv = errno; _LOGD (LOGD_SHARING, "share: error enabling IPv4 forwarding: (%d) %s", - errsv, g_strerror (errsv)); + errsv, nm_strerror_native (errsv)); g_set_error (error, NM_UTILS_ERROR, NM_UTILS_ERROR_UNKNOWN, - "cannot set ipv4/ip_forward: %s", g_strerror (errsv)); + "cannot set ipv4/ip_forward: %s", nm_strerror_native (errsv)); return FALSE; } @@ -10147,7 +10140,7 @@ share_init (NMDevice *self, GError **error) } else if (!nm_platform_sysctl_set (nm_device_get_platform (self), NMP_SYSCTL_PATHID_ABSOLUTE ("/proc/sys/net/ipv4/ip_dynaddr"), "1")) { errsv = errno; _LOGD (LOGD_SHARING, "share: error enabling dynamic addresses: (%d) %s", - errsv, strerror (errsv)); + errsv, nm_strerror_native (errsv)); } for (iter = modules; *iter; iter++) @@ -10321,12 +10314,13 @@ nm_device_arp_announce (NMDevice *self) } static void -activate_stage5_ip4_config_result (NMDevice *self) +activate_stage5_ip_config_result_4 (NMDevice *self) { NMDevicePrivate *priv = NM_DEVICE_GET_PRIVATE (self); NMActRequest *req; const char *method; int ip_ifindex; + gboolean do_announce = FALSE; req = nm_device_get_act_request (self); g_assert (req); @@ -10369,45 +10363,77 @@ activate_stage5_ip4_config_result (NMDevice *self) NULL, NULL, NULL); } - nm_device_arp_announce (self); + /* Send ARP announcements */ + + if (nm_device_is_master (self)) { + CList *iter; + SlaveInfo *info; + + /* Skip announcement if there are no device enslaved, for two reasons: + * 1) the master has a temporary MAC address until the first slave comes + * 2) announcements are going to be dropped anyway without slaves + */ + do_announce = FALSE; + + c_list_for_each (iter, &priv->slaves) { + info = c_list_entry (iter, SlaveInfo, lst_slave); + if (info->slave_is_enslaved) { + do_announce = TRUE; + break; + } + } + } else + do_announce = TRUE; + + if (do_announce) + nm_device_arp_announce (self); + nm_device_remove_pending_action (self, NM_PENDING_ACTION_DHCP4, FALSE); /* Enter the IP_CHECK state if this is the first method to complete */ - _set_ip_state (self, AF_INET, IP_DONE); + _set_ip_state (self, AF_INET, NM_DEVICE_IP_STATE_DONE); check_ip_state (self, FALSE, TRUE); } void -nm_device_activate_schedule_ip4_config_result (NMDevice *self, NMIP4Config *config) +nm_device_activate_schedule_ip_config_result (NMDevice *self, + int addr_family, + NMIPConfig *config) { NMDevicePrivate *priv; + const gboolean IS_IPv4 = (addr_family == AF_INET); g_return_if_fail (NM_IS_DEVICE (self)); + g_return_if_fail (NM_IN_SET (addr_family, AF_INET, AF_INET6)); + g_return_if_fail ( !config + || ( addr_family == AF_INET + && nm_ip_config_get_addr_family (config) == AF_INET)); + priv = NM_DEVICE_GET_PRIVATE (self); - applied_config_init (&priv->dev_ip4_config, config); - activation_source_schedule (self, activate_stage5_ip4_config_result, AF_INET); -} + if (IS_IPv4) { + applied_config_init (&priv->dev_ip_config_4, config); + } else { + /* If IP had previously failed, move it back to NM_DEVICE_IP_STATE_CONF since we + * clearly now have configuration. + */ + if (priv->ip_state_6 == NM_DEVICE_IP_STATE_FAIL) + _set_ip_state (self, AF_INET6, NM_DEVICE_IP_STATE_CONF); + } -gboolean -nm_device_activate_ip4_state_in_conf (NMDevice *self) -{ - g_return_val_if_fail (self != NULL, FALSE); - return NM_DEVICE_GET_PRIVATE (self)->ip4_state == IP_CONF; + activation_source_schedule (self, activate_stage5_ip_config_result_x[IS_IPv4], addr_family); } -gboolean -nm_device_activate_ip4_state_in_wait (NMDevice *self) +NMDeviceIPState +nm_device_activate_get_ip_state (NMDevice *self, + int addr_family) { - g_return_val_if_fail (self != NULL, FALSE); - return NM_DEVICE_GET_PRIVATE (self)->ip4_state == IP_WAIT; -} + const gboolean IS_IPv4 = (addr_family == AF_INET); -gboolean -nm_device_activate_ip4_state_done (NMDevice *self) -{ - g_return_val_if_fail (self != NULL, FALSE); - return NM_DEVICE_GET_PRIVATE (self)->ip4_state == IP_DONE; + g_return_val_if_fail (NM_IS_DEVICE (self), NM_DEVICE_IP_STATE_NONE); + g_return_val_if_fail (NM_IN_SET (addr_family, AF_INET, AF_INET6), NM_DEVICE_IP_STATE_NONE); + + return NM_DEVICE_GET_PRIVATE (self)->ip_state_x[IS_IPv4]; } static void @@ -10430,7 +10456,7 @@ dad6_add_pending_address (NMDevice *self, nm_platform_ip6_address_to_string (pl_addr, NULL, 0)); if (!*dad6_config) - *dad6_config = _ip6_config_new (self); + *dad6_config = nm_device_ip6_config_new (self); nm_ip6_config_add_address (*dad6_config, pl_addr); } @@ -10447,7 +10473,7 @@ dad6_get_pending_addresses (NMDevice *self) NMIP6Config *confs[] = { (NMIP6Config *) applied_config_get_current (&priv->ac_ip6_config), (NMIP6Config *) applied_config_get_current (&priv->dhcp6.ip6_config), priv->con_ip_config_6, - (NMIP6Config *) applied_config_get_current (&priv->wwan_ip_config_6) }; + (NMIP6Config *) applied_config_get_current (&priv->dev2_ip_config_6) }; const NMPlatformIP6Address *addr; NMIP6Config *dad6_config = NULL; NMDedupMultiIter ipconf_iter; @@ -10488,7 +10514,7 @@ dad6_get_pending_addresses (NMDevice *self) } static void -activate_stage5_ip6_config_commit (NMDevice *self) +activate_stage5_ip_config_result_6 (NMDevice *self) { NMDevicePrivate *priv = NM_DEVICE_GET_PRIVATE (self); NMActRequest *req; @@ -10511,7 +10537,7 @@ activate_stage5_ip6_config_commit (NMDevice *self) if (ip_config_merge_and_apply (self, AF_INET6, TRUE)) { if ( priv->dhcp6.mode != NM_NDISC_DHCP_LEVEL_NONE - && priv->ip6_state == IP_CONF) { + && priv->ip_state_6 == NM_DEVICE_IP_STATE_CONF) { if (applied_config_get_current (&priv->dhcp6.ip6_config)) { /* If IPv6 wasn't the first IP to complete, and DHCP was used, * then ensure dispatcher scripts get the DHCP lease information. @@ -10533,13 +10559,13 @@ activate_stage5_ip6_config_commit (NMDevice *self) if (nm_streq (method, NM_SETTING_IP6_CONFIG_METHOD_SHARED)) { if (!nm_platform_sysctl_set (nm_device_get_platform (self), NMP_SYSCTL_PATHID_ABSOLUTE ("/proc/sys/net/ipv6/conf/all/forwarding"), "1")) { errsv = errno; - _LOGE (LOGD_SHARING, "share: error enabling IPv6 forwarding: (%d) %s", errsv, strerror (errsv)); + _LOGE (LOGD_SHARING, "share: error enabling IPv6 forwarding: (%d) %s", errsv, nm_strerror_native (errsv)); nm_device_ip_method_failed (self, AF_INET6, NM_DEVICE_STATE_REASON_SHARED_START_FAILED); } } /* Check if we have to wait for DAD */ - if (priv->ip6_state == IP_CONF && !priv->dad6_ip6_config) { + if (priv->ip_state_6 == NM_DEVICE_IP_STATE_CONF && !priv->dad6_ip6_config) { if (!priv->carrier && priv->ignore_carrier && get_ip_config_may_fail (self, AF_INET6)) _LOGI (LOGD_DEVICE | LOGD_IP6, "IPv6 DAD: carrier missing and ignored, not delaying activation"); else @@ -10548,7 +10574,7 @@ activate_stage5_ip6_config_commit (NMDevice *self) if (priv->dad6_ip6_config) { _LOGD (LOGD_DEVICE | LOGD_IP6, "IPv6 DAD: awaiting termination"); } else { - _set_ip_state (self, AF_INET6, IP_DONE); + _set_ip_state (self, AF_INET6, NM_DEVICE_IP_STATE_DONE); check_ip_state (self, FALSE, TRUE); } } @@ -10558,43 +10584,6 @@ activate_stage5_ip6_config_commit (NMDevice *self) } } -void -nm_device_activate_schedule_ip6_config_result (NMDevice *self) -{ - NMDevicePrivate *priv = NM_DEVICE_GET_PRIVATE (self); - - g_return_if_fail (NM_IS_DEVICE (self)); - - /* If IP had previously failed, move it back to IP_CONF since we - * clearly now have configuration. - */ - if (priv->ip6_state == IP_FAIL) - _set_ip_state (self, AF_INET6, IP_CONF); - - activation_source_schedule (self, activate_stage5_ip6_config_commit, AF_INET6); -} - -gboolean -nm_device_activate_ip6_state_in_conf (NMDevice *self) -{ - g_return_val_if_fail (self != NULL, FALSE); - return NM_DEVICE_GET_PRIVATE (self)->ip6_state == IP_CONF; -} - -gboolean -nm_device_activate_ip6_state_in_wait (NMDevice *self) -{ - g_return_val_if_fail (self != NULL, FALSE); - return NM_DEVICE_GET_PRIVATE (self)->ip6_state == IP_WAIT; -} - -gboolean -nm_device_activate_ip6_state_done (NMDevice *self) -{ - g_return_val_if_fail (self != NULL, FALSE); - return NM_DEVICE_GET_PRIVATE (self)->ip6_state == IP_DONE; -} - /*****************************************************************************/ static void @@ -10760,7 +10749,7 @@ _cleanup_ip_pre (NMDevice *self, int addr_family, CleanupType cleanup_type) NMDevicePrivate *priv = NM_DEVICE_GET_PRIVATE (self); const gboolean IS_IPv4 = (addr_family == AF_INET); - _set_ip_state (self, addr_family, IP_NONE); + _set_ip_state (self, addr_family, NM_DEVICE_IP_STATE_NONE); if (nm_clear_g_source (&priv->queued_ip_config_id_x[IS_IPv4])) { _LOGD (LOGD_DEVICE, "clearing queued IP%c config change", @@ -10862,12 +10851,12 @@ nm_device_reactivate_ip4_config (NMDevice *self, g_return_if_fail (NM_IS_DEVICE (self)); priv = NM_DEVICE_GET_PRIVATE (self); - if (priv->ip4_state != IP_NONE) { + if (priv->ip_state_4 != NM_DEVICE_IP_STATE_NONE) { g_clear_object (&priv->con_ip_config_4); g_clear_object (&priv->ext_ip_config_4); - g_clear_object (&priv->dev_ip4_config.current); - g_clear_object (&priv->wwan_ip_config_4.current); - priv->con_ip_config_4 = _ip4_config_new (self); + g_clear_object (&priv->dev_ip_config_4.current); + g_clear_object (&priv->dev2_ip_config_4.current); + priv->con_ip_config_4 = nm_device_ip4_config_new (self); nm_ip4_config_merge_setting (priv->con_ip_config_4, s_ip4_new, _get_mdns (self), @@ -10884,7 +10873,7 @@ nm_device_reactivate_ip4_config (NMDevice *self, if (!nm_streq0 (method_old, method_new)) { _cleanup_ip_pre (self, AF_INET, CLEANUP_TYPE_DECONFIGURE); - _set_ip_state (self, AF_INET, IP_WAIT); + _set_ip_state (self, AF_INET, NM_DEVICE_IP_STATE_WAIT); if (!nm_device_activate_stage3_ip4_start (self)) _LOGW (LOGD_IP4, "Failed to apply IPv4 configuration"); return; @@ -10903,12 +10892,12 @@ nm_device_reactivate_ip4_config (NMDevice *self, metric_new = nm_setting_ip_config_get_route_metric (s_ip4_new); if (metric_old != metric_new) { - if (priv->dev_ip4_config.orig) { - nm_ip4_config_update_routes_metric ((NMIP4Config *) priv->dev_ip4_config.orig, + if (priv->dev_ip_config_4.orig) { + nm_ip4_config_update_routes_metric ((NMIP4Config *) priv->dev_ip_config_4.orig, nm_device_get_route_metric (self, AF_INET)); } - if (priv->wwan_ip_config_4.orig) { - nm_ip4_config_update_routes_metric ((NMIP4Config *) priv->wwan_ip_config_4.orig, + if (priv->dev2_ip_config_4.orig) { + nm_ip4_config_update_routes_metric ((NMIP4Config *) priv->dev2_ip_config_4.orig, nm_device_get_route_metric (self, AF_INET)); } if (priv->dhcp4.client) { @@ -10934,16 +10923,16 @@ nm_device_reactivate_ip6_config (NMDevice *self, g_return_if_fail (NM_IS_DEVICE (self)); priv = NM_DEVICE_GET_PRIVATE (self); - if (priv->ip6_state != IP_NONE) { + if (priv->ip_state_6 != NM_DEVICE_IP_STATE_NONE) { g_clear_object (&priv->con_ip_config_6); g_clear_object (&priv->ext_ip_config_6); g_clear_object (&priv->ac_ip6_config.current); g_clear_object (&priv->dhcp6.ip6_config.current); - g_clear_object (&priv->wwan_ip_config_6.current); + g_clear_object (&priv->dev2_ip_config_6.current); if ( priv->ipv6ll_handle && !IN6_IS_ADDR_UNSPECIFIED (&priv->ipv6ll_addr)) priv->ipv6ll_has = TRUE; - priv->con_ip_config_6 = _ip6_config_new (self); + priv->con_ip_config_6 = nm_device_ip6_config_new (self); nm_ip6_config_merge_setting (priv->con_ip_config_6, s_ip6_new, nm_device_get_route_table (self, AF_INET6, TRUE), @@ -10958,7 +10947,7 @@ nm_device_reactivate_ip6_config (NMDevice *self, if (!nm_streq0 (method_old, method_new)) { _cleanup_ip_pre (self, AF_INET6, CLEANUP_TYPE_DECONFIGURE); - _set_ip_state (self, AF_INET6, IP_WAIT); + _set_ip_state (self, AF_INET6, NM_DEVICE_IP_STATE_WAIT); if (!nm_device_activate_stage3_ip6_start (self)) _LOGW (LOGD_IP6, "Failed to apply IPv6 configuration"); return; @@ -10980,8 +10969,8 @@ nm_device_reactivate_ip6_config (NMDevice *self, nm_ip6_config_update_routes_metric ((NMIP6Config *) priv->dhcp6.ip6_config.orig, nm_device_get_route_metric (self, AF_INET6)); } - if (priv->wwan_ip_config_6.orig) { - nm_ip6_config_update_routes_metric ((NMIP6Config *) priv->wwan_ip_config_6.orig, + if (priv->dev2_ip_config_6.orig) { + nm_ip6_config_update_routes_metric ((NMIP6Config *) priv->dev2_ip_config_6.orig, nm_device_get_route_metric (self, AF_INET6)); } if (priv->dhcp6.client) { @@ -11091,7 +11080,6 @@ can_reapply_change (NMDevice *self, const char *setting_name, static void reapply_connection (NMDevice *self, NMConnection *con_old, NMConnection *con_new) { - } /* check_and_reapply_connection: @@ -11490,7 +11478,7 @@ _rt6_temporary_not_available_timeout (gpointer user_data) NMDevicePrivate *priv = NM_DEVICE_GET_PRIVATE (self); priv->rt6_temporary_not_available_id = 0; - nm_device_activate_schedule_ip6_config_result (self); + nm_device_activate_schedule_ip_config_result (self, AF_INET6, NULL); return G_SOURCE_REMOVE; } @@ -12074,7 +12062,7 @@ nm_device_set_ip_config (NMDevice *self, nm_dbus_object_get_path (NM_DBUS_OBJECT (old_config))); if (IS_IPv4) { /* Device config is invalid if combined config is invalid */ - applied_config_clear (&priv->dev_ip4_config); + applied_config_clear (&priv->dev_ip_config_4); } else priv->needs_ip6_subnet = FALSE; } @@ -12175,13 +12163,25 @@ nm_device_replace_vpn4_config (NMDevice *self, NMIP4Config *old, NMIP4Config *co } void -nm_device_set_wwan_ip4_config (NMDevice *self, NMIP4Config *config) +nm_device_set_dev2_ip_config (NMDevice *self, + int addr_family, + NMIPConfig *config) { - NMDevicePrivate *priv = NM_DEVICE_GET_PRIVATE (self); + NMDevicePrivate *priv; + const gboolean IS_IPv4 = (addr_family == AF_INET); - applied_config_init (&priv->wwan_ip_config_4, config); - if (!ip_config_merge_and_apply (self, AF_INET, TRUE)) - _LOGW (LOGD_IP4, "failed to set WWAN IPv4 configuration"); + g_return_if_fail (NM_IS_DEVICE (self)); + g_return_if_fail (NM_IN_SET (addr_family, AF_INET, AF_INET6)); + g_return_if_fail ( !config + || nm_ip_config_get_addr_family (config) == addr_family); + + priv = NM_DEVICE_GET_PRIVATE (self); + + applied_config_init (&priv->dev2_ip_config_x[IS_IPv4], config); + if (!ip_config_merge_and_apply (self, addr_family, TRUE)) { + _LOGW (LOGD_IP, "failed to set extra device IPv%c configuration", + nm_utils_addr_family_to_char (addr_family)); + } } void @@ -12202,16 +12202,6 @@ nm_device_replace_vpn6_config (NMDevice *self, NMIP6Config *old, NMIP6Config *co _LOGW (LOGD_IP6, "failed to set VPN routes for device"); } -void -nm_device_set_wwan_ip6_config (NMDevice *self, NMIP6Config *config) -{ - NMDevicePrivate *priv = NM_DEVICE_GET_PRIVATE (self); - - applied_config_init (&priv->wwan_ip_config_6, config); - if (!ip_config_merge_and_apply (self, AF_INET6, TRUE)) - _LOGW (LOGD_IP6, "failed to set WWAN IPv6 configuration"); -} - NMDhcp6Config * nm_device_get_dhcp6_config (NMDevice *self) { @@ -12446,7 +12436,7 @@ nm_device_start_ip_check (NMDevice *self) g_return_if_fail (!priv->gw_ping.watch); g_return_if_fail (!priv->gw_ping.timeout); g_return_if_fail (!priv->gw_ping.pid); - g_return_if_fail (priv->ip4_state == IP_DONE || priv->ip6_state == IP_DONE); + g_return_if_fail (priv->ip_state_4 == NM_DEVICE_IP_STATE_DONE || priv->ip_state_6 == NM_DEVICE_IP_STATE_DONE); connection = nm_device_get_applied_connection (self); g_assert (connection); @@ -12459,14 +12449,14 @@ nm_device_start_ip_check (NMDevice *self) if (timeout) { const NMPObject *gw; - if (priv->ip_config_4 && priv->ip4_state == IP_DONE) { + if (priv->ip_config_4 && priv->ip_state_4 == NM_DEVICE_IP_STATE_DONE) { gw = nm_ip4_config_best_default_route_get (priv->ip_config_4); if (gw) { nm_utils_inet4_ntop (NMP_OBJECT_CAST_IP4_ROUTE (gw)->gateway, buf); ping_binary = nm_utils_find_helper ("ping", "/usr/bin/ping", NULL); log_domain = LOGD_IP4; } - } else if (priv->ip_config_6 && priv->ip6_state == IP_DONE) { + } else if (priv->ip_config_6 && priv->ip_state_6 == NM_DEVICE_IP_STATE_DONE) { gw = nm_ip6_config_best_default_route_get (priv->ip_config_6); if (gw) { nm_utils_inet6_ntop (&NMP_OBJECT_CAST_IP6_ROUTE (gw)->gateway, buf); @@ -12606,11 +12596,11 @@ nm_device_bring_up (NMDevice *self, gboolean block, gboolean *no_firmware) _update_ip4_address (self); /* when the link comes up, we must restore IP configuration if necessary. */ - if (priv->ip4_state == IP_DONE) { + if (priv->ip_state_4 == NM_DEVICE_IP_STATE_DONE) { if (!ip_config_merge_and_apply (self, AF_INET, TRUE)) _LOGW (LOGD_IP4, "failed applying IP4 config after bringing link up"); } - if (priv->ip6_state == IP_DONE) { + if (priv->ip_state_6 == NM_DEVICE_IP_STATE_DONE) { if (!ip_config_merge_and_apply (self, AF_INET6, TRUE)) _LOGW (LOGD_IP6, "failed applying IP6 config after bringing link up"); } @@ -12679,6 +12669,7 @@ nm_device_get_firmware_missing (NMDevice *self) static void intersect_ext_config (NMDevice *self, AppliedConfig *config, + gboolean intersect_addresses, gboolean intersect_routes) { NMDevicePrivate *priv = NM_DEVICE_GET_PRIVATE (self); @@ -12695,11 +12686,16 @@ intersect_ext_config (NMDevice *self, ? (NMIPConfig *) priv->ext_ip_config_4 : (NMIPConfig *) priv->ext_ip_config_6; - if (config->current) - nm_ip_config_intersect (config->current, ext, intersect_routes, penalty); - else { + if (config->current) { + nm_ip_config_intersect (config->current, + ext, + intersect_addresses, + intersect_routes, + penalty); + } else { config->current = nm_ip_config_intersect_alloc (config->orig, ext, + intersect_addresses, intersect_routes, penalty); } @@ -12735,15 +12731,16 @@ update_ext_ip_config (NMDevice *self, int addr_family, gboolean intersect_config * by the user. */ if (priv->con_ip_config_4) { nm_ip4_config_intersect (priv->con_ip_config_4, priv->ext_ip_config_4, + TRUE, is_up, default_route_metric_penalty_get (self, AF_INET)); } - intersect_ext_config (self, &priv->dev_ip4_config, is_up); - intersect_ext_config (self, &priv->wwan_ip_config_4, is_up); + intersect_ext_config (self, &priv->dev_ip_config_4, TRUE, is_up); + intersect_ext_config (self, &priv->dev2_ip_config_4, TRUE, is_up); for (iter = priv->vpn_configs_4; iter; iter = iter->next) - nm_ip4_config_intersect (iter->data, priv->ext_ip_config_4, is_up, 0); + nm_ip4_config_intersect (iter->data, priv->ext_ip_config_4, TRUE, is_up, 0); } /* Remove parts from ext_ip_config_4 to only contain the information that @@ -12753,14 +12750,14 @@ update_ext_ip_config (NMDevice *self, int addr_family, gboolean intersect_config nm_ip4_config_subtract (priv->ext_ip_config_4, priv->con_ip_config_4, default_route_metric_penalty_get (self, AF_INET)); } - if (applied_config_get_current (&priv->dev_ip4_config)) { + if (applied_config_get_current (&priv->dev_ip_config_4)) { nm_ip_config_subtract ((NMIPConfig *) priv->ext_ip_config_4, - applied_config_get_current (&priv->dev_ip4_config), + applied_config_get_current (&priv->dev_ip_config_4), default_route_metric_penalty_get (self, AF_INET)); } - if (applied_config_get_current (&priv->wwan_ip_config_4)) { + if (applied_config_get_current (&priv->dev2_ip_config_4)) { nm_ip_config_subtract ((NMIPConfig *) priv->ext_ip_config_4, - applied_config_get_current (&priv->wwan_ip_config_4), + applied_config_get_current (&priv->dev2_ip_config_4), default_route_metric_penalty_get (self, AF_INET)); } for (iter = priv->vpn_configs_4; iter; iter = iter->next) @@ -12788,15 +12785,16 @@ update_ext_ip_config (NMDevice *self, int addr_family, gboolean intersect_config if (priv->con_ip_config_6) { nm_ip6_config_intersect (priv->con_ip_config_6, priv->ext_ip_config_6, is_up, + is_up, default_route_metric_penalty_get (self, AF_INET6)); } - intersect_ext_config (self, &priv->ac_ip6_config, is_up); - intersect_ext_config (self, &priv->dhcp6.ip6_config, is_up); - intersect_ext_config (self, &priv->wwan_ip_config_6, is_up); + intersect_ext_config (self, &priv->ac_ip6_config, is_up, is_up); + intersect_ext_config (self, &priv->dhcp6.ip6_config, is_up, is_up); + intersect_ext_config (self, &priv->dev2_ip_config_6, is_up, is_up); for (iter = priv->vpn_configs_6; iter; iter = iter->next) - nm_ip6_config_intersect (iter->data, priv->ext_ip_config_6, is_up, 0); + nm_ip6_config_intersect (iter->data, priv->ext_ip_config_6, is_up, is_up, 0); if ( priv->ipv6ll_has && !nm_ip6_config_lookup_address (priv->ext_ip_config_6, &priv->ipv6ll_addr)) @@ -12820,9 +12818,9 @@ update_ext_ip_config (NMDevice *self, int addr_family, gboolean intersect_config applied_config_get_current (&priv->dhcp6.ip6_config), default_route_metric_penalty_get (self, AF_INET6)); } - if (applied_config_get_current (&priv->wwan_ip_config_6)) { + if (applied_config_get_current (&priv->dev2_ip_config_6)) { nm_ip_config_subtract ((NMIPConfig *) priv->ext_ip_config_6, - applied_config_get_current (&priv->wwan_ip_config_6), + applied_config_get_current (&priv->dev2_ip_config_6), default_route_metric_penalty_get (self, AF_INET6)); } for (iter = priv->vpn_configs_6; iter; iter = iter->next) @@ -12886,9 +12884,7 @@ queued_ip_config_change (NMDevice *self, int addr_family) * update in such case. */ if (activation_source_is_scheduled (self, - IS_IPv4 - ? activate_stage5_ip4_config_result - : activate_stage5_ip6_config_commit, + activate_stage5_ip_config_result_x[IS_IPv4], addr_family)) return G_SOURCE_CONTINUE; @@ -12906,6 +12902,7 @@ queued_ip_config_change (NMDevice *self, int addr_family) if (!IS_IPv4) { NMPlatform *platform; GSList *dad6_failed_addrs, *iter; + const NMPlatformLink *pllink; dad6_failed_addrs = g_steal_pointer (&priv->dad6_failed_addrs); @@ -12914,7 +12911,8 @@ queued_ip_config_change (NMDevice *self, int addr_family) && priv->ifindex > 0 && !nm_device_sys_iface_state_is_external (self) && (platform = nm_device_get_platform (self)) - && nm_platform_link_get (platform, priv->ifindex)) { + && (pllink = nm_platform_link_get (platform, priv->ifindex)) + && (pllink->n_ifi_flags & IFF_UP)) { gboolean need_ipv6ll = FALSE; NMNDiscConfigMap ndisc_config_changed = NM_NDISC_CONFIG_NONE; @@ -12957,17 +12955,17 @@ queued_ip_config_change (NMDevice *self, int addr_family) if (!IS_IPv4) { /* Check if DAD is still pending */ - if ( priv->ip6_state == IP_CONF + if ( priv->ip_state_6 == NM_DEVICE_IP_STATE_CONF && priv->dad6_ip6_config && priv->ext_ip6_config_captured && !nm_ip6_config_has_any_dad_pending (priv->ext_ip6_config_captured, priv->dad6_ip6_config)) { _LOGD (LOGD_DEVICE | LOGD_IP6, "IPv6 DAD terminated"); g_clear_object (&priv->dad6_ip6_config); - _set_ip_state (self, addr_family, IP_DONE); + _set_ip_state (self, addr_family, NM_DEVICE_IP_STATE_DONE); check_ip_state (self, FALSE, TRUE); if (priv->rt6_temporary_not_available) - nm_device_activate_schedule_ip6_config_result (self); + nm_device_activate_schedule_ip_config_result (self, AF_INET6, NULL); } } @@ -13639,7 +13637,7 @@ nm_device_update_metered (NMDevice *self) /* Try to guess a value using the metered flag in IP configuration */ if (value == NM_METERED_INVALID) { if ( priv->ip_config_4 - && priv->ip4_state == IP_DONE + && priv->ip_state_4 == NM_DEVICE_IP_STATE_DONE && nm_ip4_config_get_metered (priv->ip_config_4)) value = NM_METERED_GUESS_YES; } @@ -14240,15 +14238,15 @@ _cleanup_generic_post (NMDevice *self, CleanupType cleanup_type) nm_device_set_ip_config (self, AF_INET6, NULL, TRUE, NULL); g_clear_object (&priv->proxy_config); g_clear_object (&priv->con_ip_config_4); - applied_config_clear (&priv->dev_ip4_config); - applied_config_clear (&priv->wwan_ip_config_4); + applied_config_clear (&priv->dev_ip_config_4); + applied_config_clear (&priv->dev2_ip_config_4); g_clear_object (&priv->ext_ip_config_4); g_clear_object (&priv->ip_config_4); g_clear_object (&priv->con_ip_config_6); applied_config_clear (&priv->ac_ip6_config); g_clear_object (&priv->ext_ip_config_6); g_clear_object (&priv->ext_ip6_config_captured); - applied_config_clear (&priv->wwan_ip_config_6); + applied_config_clear (&priv->dev2_ip_config_6); g_clear_object (&priv->ip_config_6); g_clear_object (&priv->dad6_ip6_config); priv->ipv6ll_has = FALSE; @@ -14485,7 +14483,7 @@ nm_device_spawn_iface_helper (NMDevice *self) NMSettingIPConfig *s_ip4; s_ip4 = nm_connection_get_setting_ip4_config (connection); - g_assert (s_ip4); + nm_assert (s_ip4); g_ptr_array_add (argv, g_strdup ("--priority4")); g_ptr_array_add (argv, g_strdup_printf ("%u", nm_device_get_route_metric (self, AF_INET))); @@ -14503,11 +14501,11 @@ nm_device_spawn_iface_helper (NMDevice *self) if (client_id) { g_ptr_array_add (argv, g_strdup ("--dhcp4-clientid")); g_ptr_array_add (argv, - _nm_utils_bin2hexstr_full (g_bytes_get_data (client_id, NULL), - g_bytes_get_size (client_id), - ':', - FALSE, - NULL)); + nm_utils_bin2hexstr_full (g_bytes_get_data (client_id, NULL), + g_bytes_get_size (client_id), + ':', + FALSE, + NULL)); } hostname = nm_dhcp_client_get_hostname (priv->dhcp4.client); @@ -14545,11 +14543,11 @@ nm_device_spawn_iface_helper (NMDevice *self) if (nm_device_get_ip_iface_identifier (self, &iid, FALSE)) { g_ptr_array_add (argv, g_strdup ("--iid")); g_ptr_array_add (argv, - _nm_utils_bin2hexstr_full (iid.id_u8, - sizeof (NMUtilsIPv6IfaceId), - ':', - FALSE, - NULL)); + nm_utils_bin2hexstr_full (iid.id_u8, + sizeof (NMUtilsIPv6IfaceId), + ':', + FALSE, + NULL)); } g_ptr_array_add (argv, g_strdup ("--addr-gen-mode")); @@ -15995,10 +15993,10 @@ _activation_func_to_string (ActivationHandleFunc func) FUNC_TO_STRING_CHECK_AND_RETURN (func, activate_stage1_device_prepare); FUNC_TO_STRING_CHECK_AND_RETURN (func, activate_stage2_device_config); FUNC_TO_STRING_CHECK_AND_RETURN (func, activate_stage3_ip_config_start); - FUNC_TO_STRING_CHECK_AND_RETURN (func, activate_stage4_ip4_config_timeout); - FUNC_TO_STRING_CHECK_AND_RETURN (func, activate_stage4_ip6_config_timeout); - FUNC_TO_STRING_CHECK_AND_RETURN (func, activate_stage5_ip4_config_result); - FUNC_TO_STRING_CHECK_AND_RETURN (func, activate_stage5_ip6_config_commit); + FUNC_TO_STRING_CHECK_AND_RETURN (func, activate_stage4_ip_config_timeout_4); + FUNC_TO_STRING_CHECK_AND_RETURN (func, activate_stage4_ip_config_timeout_6); + FUNC_TO_STRING_CHECK_AND_RETURN (func, activate_stage5_ip_config_result_4); + FUNC_TO_STRING_CHECK_AND_RETURN (func, activate_stage5_ip_config_result_6); g_return_val_if_reached ("unknown"); } @@ -16346,6 +16344,8 @@ set_property (GObject *object, guint prop_id, /* construct-only */ nm_assert (priv->type == NM_DEVICE_TYPE_UNKNOWN); priv->type = g_value_get_uint (value); + nm_assert (priv->type > NM_DEVICE_TYPE_UNKNOWN); + nm_assert (priv->type <= NM_DEVICE_TYPE_WIFI_P2P); break; case PROP_LINK_TYPE: /* construct-only */ @@ -16694,10 +16694,8 @@ nm_device_class_init (NMDeviceClass *klass) klass->is_available = is_available; klass->act_stage1_prepare = act_stage1_prepare; klass->act_stage2_config = act_stage2_config; - klass->act_stage3_ip4_config_start = act_stage3_ip4_config_start; - klass->act_stage3_ip6_config_start = act_stage3_ip6_config_start; - klass->act_stage4_ip4_config_timeout = act_stage4_ip4_config_timeout; - klass->act_stage4_ip6_config_timeout = act_stage4_ip6_config_timeout; + klass->act_stage3_ip_config_start = act_stage3_ip_config_start; + klass->act_stage4_ip_config_timeout = act_stage4_ip_config_timeout; klass->get_type_description = get_type_description; klass->can_auto_connect = can_auto_connect; diff --git a/src/devices/nm-device.h b/src/devices/nm-device.h index c2e3c474..45c9dda0 100644 --- a/src/devices/nm-device.h +++ b/src/devices/nm-device.h @@ -183,13 +183,13 @@ typedef enum { /*< skip >*/ _NM_DEVICE_CHECK_CON_AVAILABLE_FOR_USER_REQUEST_IGNORE_AP = (1L << 2), /* a device can be marked as unmanaged for various reasons. Some of these reasons - * are authorative, others not. Non-authoritative reasons can be overruled by + * are authoritative, others not. Non-authoritative reasons can be overruled by * `nmcli device set $DEVICE managed yes`. Also, for an explicit user activation * request we may want to consider the device as managed. This flag makes devices * that are unmanaged appear available. */ _NM_DEVICE_CHECK_CON_AVAILABLE_FOR_USER_REQUEST_OVERRULE_UNMANAGED = (1L << 3), - /* a collection of flags, that are commonly set for an explict user-request. */ + /* a collection of flags, that are commonly set for an explicit user-request. */ NM_DEVICE_CHECK_CON_AVAILABLE_FOR_USER_REQUEST = _NM_DEVICE_CHECK_CON_AVAILABLE_FOR_USER_REQUEST | _NM_DEVICE_CHECK_CON_AVAILABLE_FOR_USER_REQUEST_WAITING_CARRIER | _NM_DEVICE_CHECK_CON_AVAILABLE_FOR_USER_REQUEST_IGNORE_AP @@ -369,16 +369,13 @@ typedef struct _NMDeviceClass { NMDeviceStateReason *out_failure_reason); NMActStageReturn (* act_stage2_config) (NMDevice *self, NMDeviceStateReason *out_failure_reason); - NMActStageReturn (* act_stage3_ip4_config_start) (NMDevice *self, - NMIP4Config **out_config, - NMDeviceStateReason *out_failure_reason); - NMActStageReturn (* act_stage3_ip6_config_start) (NMDevice *self, - NMIP6Config **out_config, - NMDeviceStateReason *out_failure_reason); - NMActStageReturn (* act_stage4_ip4_config_timeout) (NMDevice *self, - NMDeviceStateReason *out_failure_reason); - NMActStageReturn (* act_stage4_ip6_config_timeout) (NMDevice *self, - NMDeviceStateReason *out_failure_reason); + NMActStageReturn (* act_stage3_ip_config_start) (NMDevice *self, + int addr_family, + gpointer *out_config, + NMDeviceStateReason *out_failure_reason); + NMActStageReturn (* act_stage4_ip_config_timeout) (NMDevice *self, + int addr_family, + NMDeviceStateReason *out_failure_reason); void (* ip4_config_pre_commit) (NMDevice *self, NMIP4Config *config); @@ -456,6 +453,11 @@ typedef struct _NMDeviceClass { guint32 (* get_dhcp_timeout) (NMDevice *self, int addr_family); + + /* Controls, whether to call act_stage2_config() callback also for assuming + * a device or for external activations. In this case, act_stage2_config() must + * take care not to touch the device's configuration. */ + bool act_stage2_config_also_for_external_or_assume:1; } NMDeviceClass; typedef void (*NMDeviceAuthRequestFunc) (NMDevice *device, diff --git a/src/devices/nm-lldp-listener.c b/src/devices/nm-lldp-listener.c index ae180637..cb3b5907 100644 --- a/src/devices/nm-lldp-listener.c +++ b/src/devices/nm-lldp-listener.c @@ -23,7 +23,6 @@ #include "nm-lldp-listener.h" #include <net/ethernet.h> -#include <errno.h> #include "platform/nm-platform.h" #include "nm-utils.h" @@ -384,7 +383,7 @@ lldp_neighbor_new (sd_lldp_neighbor *neighbor_sd, GError **error) &chassis_id, &chassis_id_len); if (r < 0) { g_set_error (error, NM_UTILS_ERROR, NM_UTILS_ERROR_UNKNOWN, - "failed reading chassis-id: %s", g_strerror (-r)); + "failed reading chassis-id: %s", nm_strerror_native (-r)); return NULL; } if (chassis_id_len < 1) { @@ -397,7 +396,7 @@ lldp_neighbor_new (sd_lldp_neighbor *neighbor_sd, GError **error) &port_id, &port_id_len); if (r < 0) { g_set_error (error, NM_UTILS_ERROR, NM_UTILS_ERROR_UNKNOWN, - "failed reading port-id: %s", g_strerror (-r)); + "failed reading port-id: %s", nm_strerror_native (-r)); return NULL; } if (port_id_len < 1) { @@ -413,7 +412,7 @@ lldp_neighbor_new (sd_lldp_neighbor *neighbor_sd, GError **error) r = sd_lldp_neighbor_get_destination_address (neighbor_sd, &neigh->destination_address); if (r < 0) { g_set_error (error, NM_UTILS_ERROR, NM_UTILS_ERROR_UNKNOWN, - "failed getting destination address: %s", g_strerror (-r)); + "failed getting destination address: %s", nm_strerror_native (-r)); goto out; } @@ -464,7 +463,7 @@ lldp_neighbor_new (sd_lldp_neighbor *neighbor_sd, GError **error) r = sd_lldp_neighbor_tlv_rewind (neighbor_sd); if (r < 0) { g_set_error (error, NM_UTILS_ERROR, NM_UTILS_ERROR_UNKNOWN, - "failed reading tlv (rewind): %s", g_strerror (-r)); + "failed reading tlv (rewind): %s", nm_strerror_native (-r)); goto out; } do { @@ -476,7 +475,7 @@ lldp_neighbor_new (sd_lldp_neighbor *neighbor_sd, GError **error) if (r == -ENXIO) continue; g_set_error (error, NM_UTILS_ERROR, NM_UTILS_ERROR_UNKNOWN, - "failed reading tlv: %s", g_strerror (-r)); + "failed reading tlv: %s", nm_strerror_native (-r)); goto out; } diff --git a/src/devices/ovs/nm-device-ovs-bridge.c b/src/devices/ovs/nm-device-ovs-bridge.c index eff355a3..be707e7a 100644 --- a/src/devices/ovs/nm-device-ovs-bridge.c +++ b/src/devices/ovs/nm-device-ovs-bridge.c @@ -77,17 +77,10 @@ get_generic_capabilities (NMDevice *device) } static NMActStageReturn -act_stage3_ip4_config_start (NMDevice *device, - NMIP4Config **out_config, - NMDeviceStateReason *out_failure_reason) -{ - return NM_ACT_STAGE_RETURN_IP_FAIL; -} - -static NMActStageReturn -act_stage3_ip6_config_start (NMDevice *device, - NMIP6Config **out_config, - NMDeviceStateReason *out_failure_reason) +act_stage3_ip_config_start (NMDevice *device, + int addr_family, + gpointer *out_config, + NMDeviceStateReason *out_failure_reason) { return NM_ACT_STAGE_RETURN_IP_FAIL; } @@ -146,8 +139,7 @@ nm_device_ovs_bridge_class_init (NMDeviceOvsBridgeClass *klass) device_class->create_and_realize = create_and_realize; device_class->unrealize = unrealize; device_class->get_generic_capabilities = get_generic_capabilities; - device_class->act_stage3_ip4_config_start = act_stage3_ip4_config_start; - device_class->act_stage3_ip6_config_start = act_stage3_ip6_config_start; + device_class->act_stage3_ip_config_start = act_stage3_ip_config_start; device_class->enslave_slave = enslave_slave; device_class->release_slave = release_slave; } diff --git a/src/devices/ovs/nm-device-ovs-interface.c b/src/devices/ovs/nm-device-ovs-interface.c index 960b8f35..e3d3f9ee 100644 --- a/src/devices/ovs/nm-device-ovs-interface.c +++ b/src/devices/ovs/nm-device-ovs-interface.c @@ -131,39 +131,22 @@ _is_internal_interface (NMDevice *device) } static NMActStageReturn -act_stage3_ip4_config_start (NMDevice *device, - NMIP4Config **out_config, - NMDeviceStateReason *out_failure_reason) +act_stage3_ip_config_start (NMDevice *device, + int addr_family, + gpointer *out_config, + NMDeviceStateReason *out_failure_reason) { NMDeviceOvsInterfacePrivate *priv = NM_DEVICE_OVS_INTERFACE_GET_PRIVATE (device); if (!_is_internal_interface (device)) return NM_ACT_STAGE_RETURN_IP_FAIL; - if (!nm_device_get_ip_ifindex (device)) { + if (nm_device_get_ip_ifindex (device) <= 0) { priv->waiting_for_interface = TRUE; return NM_ACT_STAGE_RETURN_POSTPONE; } - return NM_DEVICE_CLASS (nm_device_ovs_interface_parent_class)->act_stage3_ip4_config_start (device, out_config, out_failure_reason); -} - -static NMActStageReturn -act_stage3_ip6_config_start (NMDevice *device, - NMIP6Config **out_config, - NMDeviceStateReason *out_failure_reason) -{ - NMDeviceOvsInterfacePrivate *priv = NM_DEVICE_OVS_INTERFACE_GET_PRIVATE (device); - - if (!_is_internal_interface (device)) - return NM_ACT_STAGE_RETURN_IP_FAIL; - - if (!nm_device_get_ip_ifindex (device)) { - priv->waiting_for_interface = TRUE; - return NM_ACT_STAGE_RETURN_POSTPONE; - } - - return NM_DEVICE_CLASS (nm_device_ovs_interface_parent_class)->act_stage3_ip6_config_start (device, out_config, out_failure_reason); + return NM_DEVICE_CLASS (nm_device_ovs_interface_parent_class)->act_stage3_ip_config_start (device, addr_family, out_config, out_failure_reason); } static gboolean @@ -207,7 +190,6 @@ nm_device_ovs_interface_class_init (NMDeviceOvsInterfaceClass *klass) device_class->is_available = is_available; device_class->check_connection_compatible = check_connection_compatible; device_class->link_changed = link_changed; - device_class->act_stage3_ip4_config_start = act_stage3_ip4_config_start; - device_class->act_stage3_ip6_config_start = act_stage3_ip6_config_start; + device_class->act_stage3_ip_config_start = act_stage3_ip_config_start; device_class->can_unmanaged_external_down = can_unmanaged_external_down; } diff --git a/src/devices/ovs/nm-device-ovs-port.c b/src/devices/ovs/nm-device-ovs-port.c index 1f9afbab..b96eba68 100644 --- a/src/devices/ovs/nm-device-ovs-port.c +++ b/src/devices/ovs/nm-device-ovs-port.c @@ -71,17 +71,10 @@ get_generic_capabilities (NMDevice *device) } static NMActStageReturn -act_stage3_ip4_config_start (NMDevice *device, - NMIP4Config **out_config, - NMDeviceStateReason *out_failure_reason) -{ - return NM_ACT_STAGE_RETURN_IP_FAIL; -} - -static NMActStageReturn -act_stage3_ip6_config_start (NMDevice *device, - NMIP6Config **out_config, - NMDeviceStateReason *out_failure_reason) +act_stage3_ip_config_start (NMDevice *device, + int addr_family, + gpointer *out_config, + NMDeviceStateReason *out_failure_reason) { return NM_ACT_STAGE_RETURN_IP_FAIL; } @@ -186,8 +179,7 @@ nm_device_ovs_port_class_init (NMDeviceOvsPortClass *klass) device_class->get_type_description = get_type_description; device_class->create_and_realize = create_and_realize; device_class->get_generic_capabilities = get_generic_capabilities; - device_class->act_stage3_ip4_config_start = act_stage3_ip4_config_start; - device_class->act_stage3_ip6_config_start = act_stage3_ip6_config_start; + device_class->act_stage3_ip_config_start = act_stage3_ip_config_start; device_class->enslave_slave = enslave_slave; device_class->release_slave = release_slave; } diff --git a/src/devices/ovs/nm-ovsdb.c b/src/devices/ovs/nm-ovsdb.c index 48f6b4f3..9d73c3ac 100644 --- a/src/devices/ovs/nm-ovsdb.c +++ b/src/devices/ovs/nm-ovsdb.c @@ -21,7 +21,6 @@ #include "nm-ovsdb.h" -#include <string.h> #include <gmodule.h> #include <gio/gunixsocketaddress.h> @@ -349,14 +348,14 @@ _insert_interface (json_t *params, NMConnection *interface) if (s_ovs_iface) type = nm_setting_ovs_interface_get_interface_type (s_ovs_iface); - json_array_append (options, json_string ("map")); + json_array_append_new (options, json_string ("map")); s_ovs_patch = nm_connection_get_setting_ovs_patch (interface); if (s_ovs_patch) { - json_array_append (options, json_pack ("[[s, s]]", + json_array_append_new (options, json_pack ("[[s, s]]", "peer", nm_setting_ovs_patch_get_peer (s_ovs_patch))); } else { - json_array_append (options, json_array ()); + json_array_append_new (options, json_array ()); } json_array_append_new (params, @@ -504,12 +503,15 @@ _add_interface (NMOvsdb *self, json_t *params, OpenvswitchBridge *ovs_bridge = NULL; OpenvswitchPort *ovs_port = NULL; OpenvswitchInterface *ovs_interface = NULL; + nm_auto_decref_json json_t *bridges = NULL; + nm_auto_decref_json json_t *new_bridges = NULL; + nm_auto_decref_json json_t *ports = NULL; + nm_auto_decref_json json_t *new_ports = NULL; + nm_auto_decref_json json_t *interfaces = NULL; + nm_auto_decref_json json_t *new_interfaces = NULL; + gboolean has_interface = FALSE; int pi; int ii; - json_t *bridges, *new_bridges; - json_t *ports, *new_ports; - json_t *interfaces, *new_interfaces; - gboolean has_interface = FALSE; bridges = json_array (); ports = json_array (); @@ -585,14 +587,6 @@ _add_interface (NMOvsdb *self, json_t *params, _insert_interface (params, interface); json_array_append_new (new_interfaces, json_pack ("[s, s]", "named-uuid", "rowInterface")); } - - json_decref (interfaces); - json_decref (ports); - json_decref (bridges); - - json_decref (new_interfaces); - json_decref (new_ports); - json_decref (new_bridges); } /** @@ -612,14 +606,13 @@ _delete_interface (NMOvsdb *self, json_t *params, const char *ifname) OpenvswitchBridge *ovs_bridge; OpenvswitchPort *ovs_port; OpenvswitchInterface *ovs_interface; - int pi; - int ii; - json_t *bridges, *new_bridges; - json_t *ports, *new_ports; - json_t *interfaces, *new_interfaces; + nm_auto_decref_json json_t *bridges = NULL; + nm_auto_decref_json json_t *new_bridges = NULL; gboolean bridges_changed; gboolean ports_changed; gboolean interfaces_changed; + int pi; + int ii; bridges = json_array (); new_bridges = json_array (); @@ -627,20 +620,26 @@ _delete_interface (NMOvsdb *self, json_t *params, const char *ifname) g_hash_table_iter_init (&iter, priv->bridges); while (g_hash_table_iter_next (&iter, (gpointer) &bridge_uuid, (gpointer) &ovs_bridge)) { - json_array_append_new (bridges, json_pack ("[s,s]", "uuid", bridge_uuid)); + nm_auto_decref_json json_t *ports = NULL; + nm_auto_decref_json json_t *new_ports = NULL; ports = json_array (); new_ports = json_array (); ports_changed = FALSE; + json_array_append_new (bridges, json_pack ("[s,s]", "uuid", bridge_uuid)); + for (pi = 0; pi < ovs_bridge->ports->len; pi++) { + nm_auto_decref_json json_t *interfaces = NULL; + nm_auto_decref_json json_t *new_interfaces = NULL; + + interfaces = json_array (); + new_interfaces = json_array (); port_uuid = g_ptr_array_index (ovs_bridge->ports, pi); ovs_port = g_hash_table_lookup (priv->ports, port_uuid); json_array_append_new (ports, json_pack ("[s,s]", "uuid", port_uuid)); - interfaces = json_array (); - new_interfaces = json_array (); interfaces_changed = FALSE; for (ii = 0; ii < ovs_port->interfaces->len; ii++) { @@ -667,9 +666,6 @@ _delete_interface (NMOvsdb *self, json_t *params, const char *ifname) } json_array_append_new (new_ports, json_pack ("[s,s]", "uuid", port_uuid)); } - - json_decref (interfaces); - json_decref (new_interfaces); } if (json_array_size (new_ports) == 0) { @@ -681,9 +677,6 @@ _delete_interface (NMOvsdb *self, json_t *params, const char *ifname) } json_array_append_new (new_bridges, json_pack ("[s,s]", "uuid", bridge_uuid)); } - - json_decref (ports); - json_decref (new_ports); } if (bridges_changed) { @@ -708,7 +701,7 @@ ovsdb_next_command (NMOvsdb *self) NMOvsdbPrivate *priv = NM_OVSDB_GET_PRIVATE (self); OvsdbMethodCall *call = NULL; char *cmd; - json_t *msg = NULL; + nm_auto_decref_json json_t *msg = NULL; json_t *params; if (!priv->conn) @@ -764,7 +757,6 @@ ovsdb_next_command (NMOvsdb *self) cmd = json_dumps (msg, 0); g_string_append (priv->output, cmd); - json_decref (msg); free (cmd); ovsdb_write (self); @@ -1041,7 +1033,7 @@ static void ovsdb_got_echo (NMOvsdb *self, json_int_t id, json_t *data) { NMOvsdbPrivate *priv = NM_OVSDB_GET_PRIVATE (self); - json_t *msg; + nm_auto_decref_json json_t *msg = NULL; char *reply; gboolean output_was_empty; @@ -1050,7 +1042,6 @@ ovsdb_got_echo (NMOvsdb *self, json_int_t id, json_t *data) msg = json_pack ("{s:I, s:O}", "id", id, "result", data); reply = json_dumps (msg, 0); g_string_append (priv->output, reply); - json_decref (msg); free (reply); if (output_was_empty) @@ -1300,6 +1291,9 @@ ovsdb_disconnect (NMOvsdb *self, gboolean is_disposing) gpointer user_data; gs_free_error GError *error = NULL; + if (!priv->client) + return; + _LOGD ("disconnecting from ovsdb"); nm_utils_error_set_cancelled (&error, is_disposing, "NMOvsdb"); @@ -1317,6 +1311,7 @@ ovsdb_disconnect (NMOvsdb *self, gboolean is_disposing) g_clear_object (&priv->client); g_clear_object (&priv->conn); g_clear_pointer (&priv->db_uuid, g_free); + nm_clear_g_cancellable (&priv->cancellable); } static void @@ -1535,11 +1530,14 @@ dispose (GObject *object) ovsdb_disconnect (self, TRUE); - g_string_free (priv->input, TRUE); - priv->input = NULL; - g_string_free (priv->output, TRUE); - priv->output = NULL; - + if (priv->input) { + g_string_free (priv->input, TRUE); + priv->input = NULL; + } + if (priv->output) { + g_string_free (priv->output, TRUE); + priv->output = NULL; + } if (priv->calls) { g_array_free (priv->calls, TRUE); priv->calls = NULL; @@ -1549,9 +1547,6 @@ dispose (GObject *object) g_clear_pointer (&priv->ports, g_hash_table_destroy); g_clear_pointer (&priv->interfaces, g_hash_table_destroy); - g_cancellable_cancel (priv->cancellable); - g_clear_object (&priv->cancellable); - G_OBJECT_CLASS (nm_ovsdb_parent_class)->dispose (object); } diff --git a/src/devices/team/nm-team-factory.c b/src/devices/team/nm-team-factory.c index d062429f..f18b943d 100644 --- a/src/devices/team/nm-team-factory.c +++ b/src/devices/team/nm-team-factory.c @@ -20,7 +20,6 @@ #include "nm-default.h" -#include <string.h> #include <gmodule.h> #include "nm-manager.h" diff --git a/src/devices/tests/meson.build b/src/devices/tests/meson.build index 11f35a05..4702c656 100644 --- a/src/devices/tests/meson.build +++ b/src/devices/tests/meson.build @@ -14,5 +14,6 @@ foreach test_unit: test_units 'devices/' + test_unit, test_script, args: test_args + [exe.full_path()], + timeout: default_test_timeout, ) endforeach diff --git a/src/devices/wifi/meson.build b/src/devices/wifi/meson.build index dd2be540..4dfbe4c8 100644 --- a/src/devices/wifi/meson.build +++ b/src/devices/wifi/meson.build @@ -1,13 +1,15 @@ common_sources = files( 'nm-wifi-ap.c', + 'nm-wifi-p2p-peer.c', 'nm-wifi-utils.c', ) sources = common_sources + files( - 'nm-wifi-factory.c', - 'nm-wifi-common.c', - 'nm-device-wifi.c', 'nm-device-olpc-mesh.c', + 'nm-device-wifi-p2p.c', + 'nm-device-wifi.c', + 'nm-wifi-common.c', + 'nm-wifi-factory.c', ) if enable_iwd diff --git a/src/devices/wifi/nm-device-iwd.c b/src/devices/wifi/nm-device-iwd.c index 71b8d151..dcc161d2 100644 --- a/src/devices/wifi/nm-device-iwd.c +++ b/src/devices/wifi/nm-device-iwd.c @@ -22,8 +22,6 @@ #include "nm-device-iwd.h" -#include <string.h> - #include "nm-common-macros.h" #include "devices/nm-device.h" #include "devices/nm-device-private.h" @@ -1132,7 +1130,7 @@ _nm_device_iwd_request_scan (NMDeviceIwd *self, NM_DEVICE_AUTH_REQUEST, invocation, NULL, - NM_AUTH_PERMISSION_NETWORK_CONTROL, + NM_AUTH_PERMISSION_WIFI_SCAN, TRUE, dbus_request_scan_cb, options ? g_variant_ref (options) : NULL); @@ -1380,7 +1378,7 @@ wifi_secrets_get_one (NMDeviceIwd *self, TRUE, setting_name, flags, - setting_key, + NM_MAKE_STRV (setting_key), wifi_secrets_cb, nm_utils_user_data_pack (self, invocation)); } @@ -1549,11 +1547,11 @@ error: * DBus interface has appeared already. If so proceed to call Start or * StartOpen on that interface. */ -static void act_check_interface (NMDeviceIwd *self) +static void +act_check_interface (NMDeviceIwd *self) { NMDeviceIwdPrivate *priv = NM_DEVICE_IWD_GET_PRIVATE (self); NMDevice *device = NM_DEVICE (self); - gs_free_error GError *error = NULL; NMSettingWireless *s_wireless; NMSettingWirelessSecurity *s_wireless_sec; GDBusProxy *proxy = NULL; @@ -1894,7 +1892,7 @@ act_stage2_config (NMDevice *device, NMDeviceStateReason *out_failure_reason) TRUE, NM_SETTING_WIRELESS_SECURITY_SETTING_NAME, NM_SECRET_AGENT_GET_SECRETS_FLAG_ALLOW_INTERACTION, - "psk", + NM_MAKE_STRV (NM_SETTING_WIRELESS_SECURITY_PSK), act_psk_cb, self); nm_device_state_changed (device, NM_DEVICE_STATE_NEED_AUTH, NM_DEVICE_STATE_REASON_NONE); @@ -2335,7 +2333,7 @@ powered_changed (NMDeviceIwd *self, gboolean new_powered) value = g_dbus_proxy_get_cached_property (priv->dbus_device_proxy, "State"); if (value) { g_variant_unref (value); - interface = g_object_ref (priv->dbus_device_proxy); + interface = g_object_ref (G_DBUS_INTERFACE (priv->dbus_device_proxy)); } else { _LOGE (LOGD_WIFI, "Interface %s not found on obj %s", NM_IWD_STATION_INTERFACE, @@ -2401,7 +2399,7 @@ nm_device_iwd_set_dbus_object (NMDeviceIwd *self, GDBusObject *object) gboolean powered; NMDeviceWifiCapabilities capabilities; - if (!nm_g_object_ref_set ((GObject **) &priv->dbus_obj, (GObject *) object)) + if (!nm_g_object_ref_set (&priv->dbus_obj, object)) return; if (priv->dbus_device_proxy) { diff --git a/src/devices/wifi/nm-device-olpc-mesh.c b/src/devices/wifi/nm-device-olpc-mesh.c index 193779a7..1172a613 100644 --- a/src/devices/wifi/nm-device-olpc-mesh.c +++ b/src/devices/wifi/nm-device-olpc-mesh.c @@ -29,13 +29,11 @@ #include "nm-device-olpc-mesh.h" #include <netinet/in.h> -#include <string.h> #include <sys/stat.h> #include <sys/wait.h> #include <signal.h> #include <unistd.h> #include <sys/ioctl.h> -#include <errno.h> #include "devices/nm-device.h" #include "nm-device-wifi.h" diff --git a/src/devices/wifi/nm-device-wifi-p2p.c b/src/devices/wifi/nm-device-wifi-p2p.c new file mode 100644 index 00000000..8381ebc7 --- /dev/null +++ b/src/devices/wifi/nm-device-wifi-p2p.c @@ -0,0 +1,1316 @@ +/* NetworkManager -- Wi-Fi P2P Device + * + * This library is free software; you can redistribute it and/or + * modify it under the terms of the GNU Lesser General Public + * License as published by the Free Software Foundation; either + * version 2 of the License, or (at your option) any later version. + * + * This library is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + * Lesser General Public License for more details. + * + * You should have received a copy of the GNU Lesser General Public + * License along with this library; if not, write to the + * Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor, + * Boston, MA 02110-1301 USA. + * + * (C) Copyright 2018 Red Hat, Inc. + */ + +#include "nm-default.h" + +#include "nm-device-wifi-p2p.h" + +#include <sys/socket.h> + +#include "supplicant/nm-supplicant-manager.h" +#include "supplicant/nm-supplicant-interface.h" + +#include "nm-manager.h" +#include "nm-utils.h" +#include "nm-wifi-p2p-peer.h" +#include "NetworkManagerUtils.h" +#include "devices/nm-device-private.h" +#include "settings/nm-settings.h" +#include "nm-setting-wifi-p2p.h" +#include "nm-act-request.h" +#include "nm-ip4-config.h" +#include "platform/nm-platform.h" +#include "nm-manager.h" +#include "nm-core-internal.h" +#include "platform/nmp-object.h" + +#include "devices/nm-device-logging.h" +_LOG_DECLARE_SELF(NMDeviceWifiP2P); + +/*****************************************************************************/ + +NM_GOBJECT_PROPERTIES_DEFINE (NMDeviceWifiP2P, + PROP_PEERS, +); + +typedef struct { + NMSupplicantManager *sup_mgr; + + /* NOTE: In theory management and group ifaces could be identical. However, + * in practice, this cannot happen currently as NMDeviceWifiP2P is only + * created for existing non-P2P interfaces. + * (i.e. a single standalone P2P interface is not supported at this point) + */ + NMSupplicantInterface *mgmt_iface; + NMSupplicantInterface *group_iface; + + CList peers_lst_head; + + guint sup_timeout_id; + guint peer_dump_id; + guint peer_missing_id; + + bool is_waiting_for_supplicant:1; +} NMDeviceWifiP2PPrivate; + +struct _NMDeviceWifiP2P { + NMDevice parent; + NMDeviceWifiP2PPrivate _priv; +}; + +struct _NMDeviceWifiP2PClass { + NMDeviceClass parent; +}; + +G_DEFINE_TYPE (NMDeviceWifiP2P, nm_device_wifi_p2p, NM_TYPE_DEVICE) + +#define NM_DEVICE_WIFI_P2P_GET_PRIVATE(self) _NM_GET_PRIVATE (self, NMDeviceWifiP2P, NM_IS_DEVICE_WIFI_P2P, NMDevice) + +/*****************************************************************************/ + +static const NMDBusInterfaceInfoExtended interface_info_device_wifi_p2p; +static const GDBusSignalInfo nm_signal_info_wifi_p2p_peer_added; +static const GDBusSignalInfo nm_signal_info_wifi_p2p_peer_removed; + +static void supplicant_group_interface_release (NMDeviceWifiP2P *self); +static void supplicant_interfaces_release (NMDeviceWifiP2P *self, gboolean set_is_waiting); + +/*****************************************************************************/ + +static void +_peer_dump (NMDeviceWifiP2P *self, + NMLogLevel log_level, + const NMWifiP2PPeer *peer, + const char *prefix, + gint32 now_s) +{ + char buf[1024]; + + _NMLOG (log_level, LOGD_WIFI_SCAN, "wifi-peer: %-7s %s", + prefix, + nm_wifi_p2p_peer_to_string (peer, buf, sizeof (buf), now_s)); +} + +static gboolean +peer_list_dump (gpointer user_data) +{ + NMDeviceWifiP2P *self = NM_DEVICE_WIFI_P2P (user_data); + NMDeviceWifiP2PPrivate *priv = NM_DEVICE_WIFI_P2P_GET_PRIVATE (self); + + priv->peer_dump_id = 0; + + if (_LOGD_ENABLED (LOGD_WIFI_SCAN)) { + NMWifiP2PPeer *peer; + gint32 now_s = nm_utils_get_monotonic_timestamp_s (); + + _LOGD (LOGD_WIFI_SCAN, "P2P Peers: [now:%u]", now_s); + c_list_for_each_entry (peer, &priv->peers_lst_head, peers_lst) + _peer_dump (self, LOGL_DEBUG, peer, "dump", now_s); + } + return G_SOURCE_REMOVE; +} + +static void +schedule_peer_list_dump (NMDeviceWifiP2P *self) +{ + NMDeviceWifiP2PPrivate *priv = NM_DEVICE_WIFI_P2P_GET_PRIVATE (self); + + if ( !priv->peer_dump_id + && _LOGD_ENABLED (LOGD_WIFI_SCAN)) + priv->peer_dump_id = g_timeout_add_seconds (1, peer_list_dump, self); +} + +/*****************************************************************************/ + +static void +_set_is_waiting_for_supplicant (NMDeviceWifiP2P *self, gboolean is_waiting) +{ + NMDeviceWifiP2PPrivate *priv = NM_DEVICE_WIFI_P2P_GET_PRIVATE (self); + + if (priv->is_waiting_for_supplicant == (!!is_waiting)) + return; + + priv->is_waiting_for_supplicant = is_waiting; + + if (is_waiting) + nm_device_add_pending_action (NM_DEVICE (self), NM_PENDING_ACTION_WAITING_FOR_SUPPLICANT, TRUE); + else + nm_device_remove_pending_action (NM_DEVICE (self), NM_PENDING_ACTION_WAITING_FOR_SUPPLICANT, TRUE); +} + +/*****************************************************************************/ + +static gboolean +check_connection_peer_joined (NMDeviceWifiP2P *device) +{ + NMDeviceWifiP2PPrivate *priv = NM_DEVICE_WIFI_P2P_GET_PRIVATE (device); + NMConnection *conn = nm_device_get_applied_connection (NM_DEVICE (device)); + NMWifiP2PPeer *peer; + const char* group; + const char * const * groups; + + if (!conn || !priv->group_iface) + return FALSE; + + /* Comparing the object path found on the group_iface with the peers + * found on the mgmt_iface is legal. */ + group = nm_supplicant_interface_get_p2p_group_path (priv->group_iface); + if (!group) + return FALSE; + + /* NOTE: We currently only support connections to a specific peer */ + peer = nm_wifi_p2p_peers_find_first_compatible (&priv->peers_lst_head, conn); + if (!peer) + return FALSE; + + groups = nm_wifi_p2p_peer_get_groups (peer); + if ( !groups + || !g_strv_contains (groups, group)) + return FALSE; + + return TRUE; +} + +static gboolean +disconnect_on_connection_peer_missing_cb (gpointer user_data) +{ + NMDevice *device = NM_DEVICE (user_data); + NMDeviceWifiP2P *self = NM_DEVICE_WIFI_P2P (device); + NMDeviceWifiP2PPrivate *priv = NM_DEVICE_WIFI_P2P_GET_PRIVATE (self); + + _LOGW (LOGD_WIFI, "Peer requested in connection is missing for too long, failing connection."); + + priv->peer_missing_id = 0; + + nm_device_state_changed (device, + NM_DEVICE_STATE_FAILED, + NM_DEVICE_STATE_REASON_PEER_NOT_FOUND); + return FALSE; +} + +static void +update_disconnect_on_connection_peer_missing (NMDeviceWifiP2P *self) +{ + NMDeviceWifiP2PPrivate *priv = NM_DEVICE_WIFI_P2P_GET_PRIVATE (self); + NMDeviceState state; + + state = nm_device_get_state (NM_DEVICE (self)); + if ( state < NM_DEVICE_STATE_IP_CONFIG + || state > NM_DEVICE_STATE_ACTIVATED) { + nm_clear_g_source (&priv->peer_missing_id); + return; + } + + if (check_connection_peer_joined (self)) { + if (nm_clear_g_source (&priv->peer_missing_id)) + _LOGD (LOGD_WIFI, "Peer requested in connection is joined, removing timeout"); + return; + } + + if (priv->peer_missing_id == 0) { + _LOGD (LOGD_WIFI, "Peer requested in connection is missing, adding timeout"); + priv->peer_missing_id = g_timeout_add_seconds (5, disconnect_on_connection_peer_missing_cb, self); + } +} + +static gboolean +is_available (NMDevice *device, NMDeviceCheckDevAvailableFlags flags) +{ + NMDeviceWifiP2P *self = NM_DEVICE_WIFI_P2P (device); + NMDeviceWifiP2PPrivate *priv = NM_DEVICE_WIFI_P2P_GET_PRIVATE (self); + NMSupplicantInterfaceState supplicant_state; + + if (!priv->mgmt_iface) + return FALSE; + + supplicant_state = nm_supplicant_interface_get_state (priv->mgmt_iface); + if ( supplicant_state < NM_SUPPLICANT_INTERFACE_STATE_READY + || supplicant_state > NM_SUPPLICANT_INTERFACE_STATE_COMPLETED) + return FALSE; + + return TRUE; +} + +static gboolean +check_connection_compatible (NMDevice *device, NMConnection *connection, GError **error) +{ + if (!NM_DEVICE_CLASS (nm_device_wifi_p2p_parent_class)->check_connection_compatible (device, connection, error)) + return FALSE; + + /* TODO: Allow limitting the interface using the HW-address? */ + + /* We don't need to check anything else here. The P2P device will only + * exists if we are able to establish a P2P connection, and there should + * be no further restrictions necessary. + */ + + return TRUE; +} + +static gboolean +complete_connection (NMDevice *device, + NMConnection *connection, + const char *specific_object, + NMConnection *const*existing_connections, + GError **error) +{ + NMDeviceWifiP2P *self = NM_DEVICE_WIFI_P2P (device); + gs_free char *setting_name = NULL; + NMSettingWifiP2P *s_wifi_p2p; + NMWifiP2PPeer *peer; + const char *setting_peer; + + s_wifi_p2p = NM_SETTING_WIFI_P2P (nm_connection_get_setting (connection, NM_TYPE_SETTING_WIFI_P2P)); + + if (!specific_object) { + /* If not given a specific object, we need at minimum a peer address */ + if (!s_wifi_p2p) { + g_set_error (error, + NM_DEVICE_ERROR, + NM_DEVICE_ERROR_INVALID_CONNECTION, + "A '%s' setting is required if no Peer path was given", + NM_SETTING_WIFI_P2P_SETTING_NAME); + return FALSE; + } + + setting_peer = nm_setting_wifi_p2p_get_peer (s_wifi_p2p); + if (!setting_peer) { + g_set_error (error, + NM_DEVICE_ERROR, + NM_DEVICE_ERROR_INVALID_CONNECTION, + "A '%s' setting with a valid Peer is required if no Peer path was given", + NM_SETTING_WIFI_P2P_SETTING_NAME); + return FALSE; + } + + } else { + peer = nm_wifi_p2p_peer_lookup_for_device (NM_DEVICE (self), specific_object); + if (!peer) { + g_set_error (error, + NM_DEVICE_ERROR, + NM_DEVICE_ERROR_SPECIFIC_OBJECT_NOT_FOUND, + "The P2P peer %s is unknown", + specific_object); + return FALSE; + } + + setting_peer = nm_wifi_p2p_peer_get_address (peer); + g_return_val_if_fail (setting_peer, FALSE); + } + + /* Add a Wi-Fi P2P setting if one doesn't exist yet */ + if (!s_wifi_p2p) { + s_wifi_p2p = NM_SETTING_WIFI_P2P (nm_setting_wifi_p2p_new ()); + nm_connection_add_setting (connection, NM_SETTING (s_wifi_p2p)); + } + + g_object_set (G_OBJECT (s_wifi_p2p), NM_SETTING_WIFI_P2P_PEER, setting_peer, NULL); + + setting_name = g_strdup_printf ("Wi-Fi P2P Peer %s", setting_peer); + nm_utils_complete_generic (nm_device_get_platform (device), + connection, + NM_SETTING_WIFI_P2P_SETTING_NAME, + existing_connections, + setting_name, + setting_name, + NULL, + TRUE); + + return TRUE; +} + +/* + * supplicant_find_timeout_cb + * + * Called when the supplicant has been unable to find the peer we want to connect to. + */ +static gboolean +supplicant_find_timeout_cb (gpointer user_data) +{ + NMDevice *device = NM_DEVICE (user_data); + NMDeviceWifiP2P *self = NM_DEVICE_WIFI_P2P (user_data); + NMDeviceWifiP2PPrivate *priv = NM_DEVICE_WIFI_P2P_GET_PRIVATE (self); + + priv->sup_timeout_id = 0; + + nm_supplicant_interface_p2p_cancel_connect (priv->mgmt_iface); + + if (nm_device_is_activating (device)) { + _LOGW (LOGD_DEVICE | LOGD_WIFI, + "Activation: (wifi-p2p) could not find peer, failing activation"); + nm_device_state_changed (device, NM_DEVICE_STATE_FAILED, + NM_DEVICE_STATE_REASON_PEER_NOT_FOUND); + } + + return G_SOURCE_REMOVE; +} + +static NMActStageReturn +act_stage1_prepare (NMDevice *device, NMDeviceStateReason *out_failure_reason) +{ + NMDeviceWifiP2P *self = NM_DEVICE_WIFI_P2P (device); + NMDeviceWifiP2PPrivate *priv = NM_DEVICE_WIFI_P2P_GET_PRIVATE (self); + NMActStageReturn ret; + NMActRequest *req; + NMConnection *connection; + NMSettingWifiP2P *s_wifi_p2p; + NMWifiP2PPeer *peer; + + nm_clear_g_source (&priv->sup_timeout_id); + + ret = NM_DEVICE_CLASS (nm_device_wifi_p2p_parent_class)->act_stage1_prepare (device, out_failure_reason); + if (ret != NM_ACT_STAGE_RETURN_SUCCESS) + return ret; + + if (!priv->mgmt_iface) { + NM_SET_OUT (out_failure_reason, NM_DEVICE_STATE_REASON_SUPPLICANT_FAILED); + return NM_ACT_STAGE_RETURN_FAILURE; + } + + req = nm_device_get_act_request (NM_DEVICE (self)); + g_return_val_if_fail (req, NM_ACT_STAGE_RETURN_FAILURE); + + connection = nm_act_request_get_applied_connection (req); + g_return_val_if_fail (connection, NM_ACT_STAGE_RETURN_FAILURE); + + s_wifi_p2p = NM_SETTING_WIFI_P2P (nm_connection_get_setting (connection, NM_TYPE_SETTING_WIFI_P2P)); + g_return_val_if_fail (s_wifi_p2p, NM_ACT_STAGE_RETURN_FAILURE); + + peer = nm_wifi_p2p_peers_find_first_compatible (&priv->peers_lst_head, connection); + if (!peer) { + /* Set up a timeout on the find attempt and run a find for the same period of time */ + priv->sup_timeout_id = g_timeout_add_seconds (10, + supplicant_find_timeout_cb, + self); + + nm_supplicant_interface_p2p_start_find (priv->mgmt_iface, 10); + + return NM_ACT_STAGE_RETURN_POSTPONE; + } + + return NM_ACT_STAGE_RETURN_SUCCESS; +} + +static void +cleanup_p2p_connect_attempt (NMDeviceWifiP2P *self, gboolean disconnect) +{ + NMDeviceWifiP2PPrivate *priv = NM_DEVICE_WIFI_P2P_GET_PRIVATE (self); + + nm_clear_g_source (&priv->sup_timeout_id); + nm_clear_g_source (&priv->peer_missing_id); + + if (priv->mgmt_iface) + nm_supplicant_interface_p2p_cancel_connect (priv->mgmt_iface); + + if (disconnect && priv->group_iface) + nm_supplicant_interface_p2p_disconnect (priv->group_iface); +} + +/* + * supplicant_connection_timeout_cb + * + * Called when the supplicant has been unable to connect to a peer + * within a specified period of time. + */ +static gboolean +supplicant_connection_timeout_cb (gpointer user_data) +{ + NMDevice *device = NM_DEVICE (user_data); + NMDeviceWifiP2P *self = NM_DEVICE_WIFI_P2P (user_data); + NMDeviceWifiP2PPrivate *priv = NM_DEVICE_WIFI_P2P_GET_PRIVATE (self); + + priv->sup_timeout_id = 0; + + nm_supplicant_interface_p2p_cancel_connect (priv->mgmt_iface); + + if (nm_device_is_activating (device)) { + _LOGW (LOGD_DEVICE | LOGD_WIFI, + "Activation: (wifi-p2p) connecting took too long, failing activation"); + nm_device_state_changed (device, NM_DEVICE_STATE_FAILED, + NM_DEVICE_STATE_REASON_SUPPLICANT_TIMEOUT); + } + + return G_SOURCE_REMOVE; +} + +static NMActStageReturn +act_stage2_config (NMDevice *device, NMDeviceStateReason *out_failure_reason) +{ + NMDeviceWifiP2P *self = NM_DEVICE_WIFI_P2P (device); + NMDeviceWifiP2PPrivate *priv = NM_DEVICE_WIFI_P2P_GET_PRIVATE (self); + NMConnection *connection; + NMSettingWifiP2P *s_wifi_p2p; + NMWifiP2PPeer *peer; + GBytes *wfd_ies; + + nm_clear_g_source (&priv->sup_timeout_id); + + if (!priv->mgmt_iface) { + NM_SET_OUT (out_failure_reason, NM_DEVICE_STATE_REASON_SUPPLICANT_FAILED); + return NM_ACT_STAGE_RETURN_FAILURE; + } + + connection = nm_device_get_applied_connection (device); + g_return_val_if_fail (connection, NM_ACT_STAGE_RETURN_FAILURE); + + nm_assert (NM_IS_SETTING_WIFI_P2P (nm_connection_get_setting (connection, NM_TYPE_SETTING_WIFI_P2P))); + + /* The prepare stage ensures that the peer has been found */ + peer = nm_wifi_p2p_peers_find_first_compatible (&priv->peers_lst_head, connection); + if (!peer) { + NM_SET_OUT (out_failure_reason, NM_DEVICE_STATE_REASON_PEER_NOT_FOUND); + return NM_ACT_STAGE_RETURN_FAILURE; + } + + /* Set the WFD IEs before trying to establish the connection. */ + s_wifi_p2p = NM_SETTING_WIFI_P2P (nm_connection_get_setting (connection, NM_TYPE_SETTING_WIFI_P2P)); + wfd_ies = nm_setting_wifi_p2p_get_wfd_ies (s_wifi_p2p); + nm_supplicant_manager_set_wfd_ies (priv->sup_mgr, wfd_ies); + + /* TODO: Grab secrets if we don't have them yet! */ + + /* TODO: Fix "pbc" being hardcoded here! */ + nm_supplicant_interface_p2p_connect (priv->mgmt_iface, + nm_wifi_p2p_peer_get_supplicant_path (peer), + "pbc", NULL); + + /* Set up a timeout on the connect attempt */ + priv->sup_timeout_id = g_timeout_add_seconds (45, + supplicant_connection_timeout_cb, + self); + + /* We'll get stage3 started when the P2P group has been started */ + return NM_ACT_STAGE_RETURN_POSTPONE; +} + +/*****************************************************************************/ + +static void +emit_signal_p2p_peer_add_remove (NMDeviceWifiP2P *device, + NMWifiP2PPeer *peer, + gboolean is_added /* or else is_removed */) +{ + nm_dbus_object_emit_signal (NM_DBUS_OBJECT (device), + &interface_info_device_wifi_p2p, + is_added + ? &nm_signal_info_wifi_p2p_peer_added + : &nm_signal_info_wifi_p2p_peer_removed, + "(o)", + nm_dbus_object_get_path (NM_DBUS_OBJECT (peer))); +} + +static void +peer_add_remove (NMDeviceWifiP2P *self, + gboolean is_adding, /* or else removing */ + NMWifiP2PPeer *peer, + gboolean recheck_available_connections) +{ + NMDevice *device = NM_DEVICE (self); + NMDeviceWifiP2PPrivate *priv = NM_DEVICE_WIFI_P2P_GET_PRIVATE (self); + + if (is_adding) { + g_object_ref (peer); + peer->wifi_device = device; + c_list_link_tail (&priv->peers_lst_head, &peer->peers_lst); + nm_dbus_object_export (NM_DBUS_OBJECT (peer)); + _peer_dump (self, LOGL_DEBUG, peer, "added", 0); + + emit_signal_p2p_peer_add_remove (self, peer, TRUE); + } else { + peer->wifi_device = NULL; + c_list_unlink (&peer->peers_lst); + _peer_dump (self, LOGL_DEBUG, peer, "removed", 0); + } + + _notify (self, PROP_PEERS); + + if (!is_adding) { + emit_signal_p2p_peer_add_remove (self, peer, FALSE); + nm_dbus_object_clear_and_unexport (&peer); + } + + if (is_adding) { + /* If we are in prepare state, then we are currently runnign a find + * to search for the requested peer. */ + if (nm_device_get_state (device) == NM_DEVICE_STATE_PREPARE) { + NMConnection *connection; + + connection = nm_device_get_applied_connection (device); + g_assert (connection); + + peer = nm_wifi_p2p_peers_find_first_compatible (&priv->peers_lst_head, connection); + if (peer) { + /* A peer for the connection was found, cancel the timeout and go to configure state. */ + nm_clear_g_source (&priv->sup_timeout_id); + nm_device_activate_schedule_stage2_device_config (device); + } + } + + /* TODO: We may want to re-check auto-activation here, otherwise it will never work. */ + } + + update_disconnect_on_connection_peer_missing (self); +} + +static void +remove_all_peers (NMDeviceWifiP2P *self) +{ + NMDeviceWifiP2PPrivate *priv = NM_DEVICE_WIFI_P2P_GET_PRIVATE (self); + NMWifiP2PPeer *peer; + + if (c_list_is_empty (&priv->peers_lst_head)) + return; + + while ((peer = c_list_first_entry (&priv->peers_lst_head, NMWifiP2PPeer, peers_lst))) + peer_add_remove (self, FALSE, peer, FALSE); + + nm_device_recheck_available_connections (NM_DEVICE (self)); +} + +/*****************************************************************************/ + + +static NMActStageReturn +act_stage3_ip_config_start (NMDevice *device, + int addr_family, + gpointer *out_config, + NMDeviceStateReason *out_failure_reason) +{ + gboolean indicate_addressing_running; + NMConnection *connection; + const char *method; + + connection = nm_device_get_applied_connection (device); + + method = nm_utils_get_ip_config_method (connection, addr_family); + + if (addr_family == AF_INET) + indicate_addressing_running = NM_IN_STRSET (method, NM_SETTING_IP4_CONFIG_METHOD_AUTO); + else { + indicate_addressing_running = NM_IN_STRSET (method, NM_SETTING_IP6_CONFIG_METHOD_AUTO, + NM_SETTING_IP6_CONFIG_METHOD_DHCP); + } + + if (indicate_addressing_running) + nm_platform_wifi_indicate_addressing_running (nm_device_get_platform (device), nm_device_get_ip_ifindex (device), TRUE); + + return NM_DEVICE_CLASS (nm_device_wifi_p2p_parent_class)->act_stage3_ip_config_start (device, addr_family, out_config, out_failure_reason); +} + +static void +deactivate (NMDevice *device) +{ + NMDeviceWifiP2P *self = NM_DEVICE_WIFI_P2P (device); + int ifindex = nm_device_get_ip_ifindex (device); + + cleanup_p2p_connect_attempt (self, TRUE); + + /* Clear any critical protocol notification in the Wi-Fi stack */ + if (ifindex > 0) + nm_platform_wifi_indicate_addressing_running (nm_device_get_platform (device), ifindex, FALSE); +} + +static guint32 +get_configured_mtu (NMDevice *device, NMDeviceMtuSource *out_source) +{ + *out_source = NM_DEVICE_MTU_SOURCE_NONE; + return 0; +} + +static const char * +get_auto_ip_config_method (NMDevice *device, int addr_family) +{ + NMDeviceWifiP2P *self = NM_DEVICE_WIFI_P2P (device); + NMDeviceWifiP2PPrivate *priv = NM_DEVICE_WIFI_P2P_GET_PRIVATE (self); + + /* Override the AUTO method to mean shared if we are group owner. */ + if ( priv->group_iface + && nm_supplicant_interface_get_p2p_group_owner (priv->group_iface)) { + if (addr_family == AF_INET) + return NM_SETTING_IP4_CONFIG_METHOD_SHARED; + + if (addr_family == AF_INET6) + return NM_SETTING_IP6_CONFIG_METHOD_SHARED; + } + + return NULL; +} + +static gboolean +unmanaged_on_quit (NMDevice *self) +{ + return TRUE; +} + +static void +supplicant_iface_state_cb (NMSupplicantInterface *iface, + int new_state_i, + int old_state_i, + int disconnect_reason, + gpointer user_data) +{ + NMDeviceWifiP2P *self = NM_DEVICE_WIFI_P2P (user_data); + NMDevice *device = NM_DEVICE (self); + NMSupplicantInterfaceState new_state = new_state_i; + NMSupplicantInterfaceState old_state = old_state_i; + + if (new_state == old_state) + return; + + _LOGI (LOGD_DEVICE | LOGD_WIFI, + "supplicant management interface state: %s -> %s", + nm_supplicant_interface_state_to_string (old_state), + nm_supplicant_interface_state_to_string (new_state)); + + switch (new_state) { + case NM_SUPPLICANT_INTERFACE_STATE_READY: + _LOGD (LOGD_WIFI, "supplicant ready"); + nm_device_queue_recheck_available (device, + NM_DEVICE_STATE_REASON_SUPPLICANT_AVAILABLE, + NM_DEVICE_STATE_REASON_SUPPLICANT_FAILED); + + if (old_state < NM_SUPPLICANT_INTERFACE_STATE_READY) + _set_is_waiting_for_supplicant (self, FALSE); + break; + case NM_SUPPLICANT_INTERFACE_STATE_DOWN: + supplicant_interfaces_release (self, TRUE); + nm_device_queue_recheck_available (device, + NM_DEVICE_STATE_REASON_SUPPLICANT_AVAILABLE, + NM_DEVICE_STATE_REASON_SUPPLICANT_FAILED); + break; + default: + break; + } +} + +static void +supplicant_iface_peer_updated_cb (NMSupplicantInterface *iface, + const char *object_path, + GVariant *properties, + NMDeviceWifiP2P *self) +{ + NMDeviceWifiP2PPrivate *priv; + NMWifiP2PPeer *found_peer; + + g_return_if_fail (self != NULL); + g_return_if_fail (object_path != NULL); + + priv = NM_DEVICE_WIFI_P2P_GET_PRIVATE (self); + + found_peer = nm_wifi_p2p_peers_find_by_supplicant_path (&priv->peers_lst_head, object_path); + if (found_peer) { + if (!nm_wifi_p2p_peer_update_from_properties (found_peer, object_path, properties)) + return; + + update_disconnect_on_connection_peer_missing (self); + _peer_dump (self, LOGL_DEBUG, found_peer, "updated", 0); + } else { + gs_unref_object NMWifiP2PPeer *peer = NULL; + + peer = nm_wifi_p2p_peer_new_from_properties (object_path, properties); + if (!peer) { + _LOGD (LOGD_WIFI, "invalid P2P peer properties received for %s", object_path); + return; + } + + peer_add_remove (self, TRUE, peer, TRUE); + } + + schedule_peer_list_dump (self); +} + +static void +supplicant_iface_peer_removed_cb (NMSupplicantInterface *iface, + const char *object_path, + NMDeviceWifiP2P *self) +{ + NMDeviceWifiP2PPrivate *priv; + NMWifiP2PPeer *peer; + + g_return_if_fail (self != NULL); + g_return_if_fail (object_path != NULL); + + priv = NM_DEVICE_WIFI_P2P_GET_PRIVATE (self); + peer = nm_wifi_p2p_peers_find_by_supplicant_path (&priv->peers_lst_head, object_path); + if (!peer) + return; + + peer_add_remove (self, FALSE, peer, TRUE); + schedule_peer_list_dump (self); +} + +static void +check_group_iface_ready (NMDeviceWifiP2P *self) +{ + NMDeviceWifiP2PPrivate *priv = NM_DEVICE_WIFI_P2P_GET_PRIVATE (self);; + + if (!priv->group_iface) + return; + + if (nm_supplicant_interface_get_state (priv->group_iface) < NM_SUPPLICANT_INTERFACE_STATE_READY) + return; + + if (!nm_supplicant_interface_get_p2p_group_joined (priv->group_iface)) + return; + + nm_clear_g_source (&priv->sup_timeout_id); + update_disconnect_on_connection_peer_missing (self); + + nm_device_activate_schedule_stage3_ip_config_start (NM_DEVICE (self)); +} + +static void +supplicant_group_iface_state_cb (NMSupplicantInterface *iface, + int new_state_i, + int old_state_i, + int disconnect_reason, + gpointer user_data) +{ + NMDeviceWifiP2P *self = NM_DEVICE_WIFI_P2P (user_data); + NMDeviceWifiP2PPrivate *priv = NM_DEVICE_WIFI_P2P_GET_PRIVATE (self); + NMDevice *device = NM_DEVICE (self); + NMSupplicantInterfaceState new_state = new_state_i; + NMSupplicantInterfaceState old_state = old_state_i; + + if (new_state == old_state) + return; + + _LOGI (LOGD_DEVICE | LOGD_WIFI, + "P2P Group supplicant interface state: %s -> %s", + nm_supplicant_interface_state_to_string (old_state), + nm_supplicant_interface_state_to_string (new_state)); + + switch (new_state) { + case NM_SUPPLICANT_INTERFACE_STATE_READY: + _LOGD (LOGD_WIFI, "P2P Group supplicant ready"); + + if (!nm_device_set_ip_iface (device, nm_supplicant_interface_get_ifname (priv->group_iface))) { + nm_device_state_changed (device, + NM_DEVICE_STATE_FAILED, + NM_DEVICE_STATE_REASON_SUPPLICANT_FAILED); + break; + } + + if (old_state < NM_SUPPLICANT_INTERFACE_STATE_READY) + _set_is_waiting_for_supplicant (self, FALSE); + + check_group_iface_ready (self); + break; + case NM_SUPPLICANT_INTERFACE_STATE_DOWN: + supplicant_group_interface_release (self); + + nm_device_state_changed (device, + NM_DEVICE_STATE_DISCONNECTED, + NM_DEVICE_STATE_REASON_SUPPLICANT_DISCONNECT); + break; + default: + break; + } +} + +static void +supplicant_group_iface_group_finished_cb (NMSupplicantInterface *iface, + void *user_data) +{ + NMDeviceWifiP2P *self = NM_DEVICE_WIFI_P2P (user_data); + + supplicant_group_interface_release (self); + + nm_device_state_changed (NM_DEVICE (self), + NM_DEVICE_STATE_DISCONNECTED, + NM_DEVICE_STATE_REASON_SUPPLICANT_DISCONNECT); +} + +static void +supplicant_iface_group_joined_updated_cb (NMSupplicantInterface *iface, + GParamSpec *pspec, + void *user_data) +{ + NMDeviceWifiP2P *self = NM_DEVICE_WIFI_P2P (user_data); + + check_group_iface_ready (self); +} + +static void +supplicant_iface_group_started_cb (NMSupplicantInterface *iface, + NMSupplicantInterface *group_iface, + NMDeviceWifiP2P *self) +{ + NMDeviceWifiP2PPrivate *priv; + + g_return_if_fail (self != NULL); + + if (!nm_device_is_activating (NM_DEVICE (self))) { + _LOGW (LOGD_DEVICE | LOGD_WIFI, "P2P: WPA supplicant notified a group start but we are not trying to connect! Ignoring the event."); + return; + } + + priv = NM_DEVICE_WIFI_P2P_GET_PRIVATE (self); + + supplicant_group_interface_release (self); + priv->group_iface = g_object_ref (group_iface); + + /* We need to wait for the interface to be ready and the group + * information to be resolved. */ + g_signal_connect (priv->group_iface, + "notify::" NM_SUPPLICANT_INTERFACE_P2P_GROUP_JOINED, + G_CALLBACK (supplicant_iface_group_joined_updated_cb), + self); + + g_signal_connect (priv->group_iface, + NM_SUPPLICANT_INTERFACE_STATE, + G_CALLBACK (supplicant_group_iface_state_cb), + self); + + g_signal_connect (priv->group_iface, NM_SUPPLICANT_INTERFACE_GROUP_FINISHED, + G_CALLBACK (supplicant_group_iface_group_finished_cb), + self); + + if (nm_supplicant_interface_get_state (priv->group_iface) < NM_SUPPLICANT_INTERFACE_STATE_READY) + _set_is_waiting_for_supplicant (self, TRUE); + + check_group_iface_ready (self); +} + +static void +supplicant_group_interface_release (NMDeviceWifiP2P *self) +{ + NMDeviceWifiP2PPrivate *priv = NM_DEVICE_WIFI_P2P_GET_PRIVATE (self); + + if (!priv->group_iface) + return; + + g_signal_handlers_disconnect_by_data (priv->group_iface, self); + + nm_supplicant_interface_p2p_disconnect (priv->group_iface); + + g_clear_object (&priv->group_iface); +} + +static void +supplicant_interfaces_release (NMDeviceWifiP2P *self, gboolean set_is_waiting) +{ + NMDeviceWifiP2PPrivate *priv = NM_DEVICE_WIFI_P2P_GET_PRIVATE (self); + + nm_clear_g_source (&priv->peer_dump_id); + + remove_all_peers (self); + + if (priv->mgmt_iface) { + _LOGD (LOGD_DEVICE | LOGD_WIFI, "P2P: Releasing WPA supplicant interface."); + nm_supplicant_manager_set_wfd_ies (priv->sup_mgr, NULL); + g_signal_handlers_disconnect_by_data (priv->mgmt_iface, self); + g_clear_object (&priv->mgmt_iface); + nm_clear_g_source (&priv->sup_timeout_id); + } + + supplicant_group_interface_release (self); + + if (set_is_waiting) + _set_is_waiting_for_supplicant (self, TRUE); +} + +static void +device_state_changed (NMDevice *device, + NMDeviceState new_state, + NMDeviceState old_state, + NMDeviceStateReason reason) +{ + NMDeviceWifiP2P *self = NM_DEVICE_WIFI_P2P (device); + NMDeviceWifiP2PPrivate *priv = NM_DEVICE_WIFI_P2P_GET_PRIVATE (self); + + update_disconnect_on_connection_peer_missing (self); + + if (new_state <= NM_DEVICE_STATE_UNAVAILABLE) { + /* Clean up the supplicant interface because in these states the + * device cannot be used. + * Do not clean up for the UNMANAGED to UNAVAILABLE transition which + * will happen during initialization. + */ + if (priv->mgmt_iface && old_state > new_state) + supplicant_interfaces_release (self, TRUE); + + /* TODO: More cleanup needed? */ + } + + switch (new_state) { + case NM_DEVICE_STATE_UNMANAGED: + break; + case NM_DEVICE_STATE_UNAVAILABLE: + if ( !priv->mgmt_iface + || nm_supplicant_interface_get_state (priv->mgmt_iface) < NM_SUPPLICANT_INTERFACE_STATE_READY) + _set_is_waiting_for_supplicant (self, TRUE); + + break; + case NM_DEVICE_STATE_NEED_AUTH: + /* Disconnect? */ + break; + case NM_DEVICE_STATE_IP_CHECK: + /* Clear any critical protocol notification in the wifi stack */ + nm_platform_wifi_indicate_addressing_running (nm_device_get_platform (device), nm_device_get_ip_ifindex (device), FALSE); + break; + case NM_DEVICE_STATE_ACTIVATED: + //activation_success_handler (device); + break; + case NM_DEVICE_STATE_FAILED: + /* Clear any critical protocol notification in the wifi stack. + * At this point the IP device may have been removed already. */ + nm_supplicant_manager_set_wfd_ies (priv->sup_mgr, NULL); + if (nm_device_get_ip_ifindex (device) > 0) + nm_platform_wifi_indicate_addressing_running (nm_device_get_platform (device), nm_device_get_ip_ifindex (device), FALSE); + break; + case NM_DEVICE_STATE_DISCONNECTED: + nm_supplicant_manager_set_wfd_ies (priv->sup_mgr, NULL); + break; + default: + break; + } +} + +static void +impl_device_wifi_p2p_start_find (NMDBusObject *obj, + const NMDBusInterfaceInfoExtended *interface_info, + const NMDBusMethodInfoExtended *method_info, + GDBusConnection *connection, + const char *sender, + GDBusMethodInvocation *invocation, + GVariant *parameters) +{ + NMDeviceWifiP2P *self = NM_DEVICE_WIFI_P2P (obj); + NMDeviceWifiP2PPrivate *priv = NM_DEVICE_WIFI_P2P_GET_PRIVATE (self); + gs_unref_variant GVariant *options = NULL; + const char *opts_key; + GVariant *opts_val; + GVariantIter iter; + gint32 timeout = 30; + + g_variant_get (parameters, "(@a{sv})", &options); + + g_variant_iter_init (&iter, options); + while (g_variant_iter_next (&iter, "{&sv}", &opts_key, &opts_val)) { + _nm_unused gs_unref_variant GVariant *opts_val_free = opts_val; + + if (nm_streq (opts_key, "timeout")) { + if (!g_variant_is_of_type (opts_val, G_VARIANT_TYPE_INT32)) { + g_dbus_method_invocation_return_error_literal (invocation, + NM_DEVICE_ERROR, + NM_DEVICE_ERROR_INVALID_ARGUMENT, + "\"timeout\" must be an integer \"i\""); + return; + } + + timeout = g_variant_get_int32 (opts_val); + if (timeout <= 0 || timeout > 600) { + g_dbus_method_invocation_return_error_literal (invocation, + NM_DEVICE_ERROR, + NM_DEVICE_ERROR_NOT_ALLOWED, + "The timeout for a find operation needs to be in the range of 1-600s."); + return; + } + + continue; + } + + g_dbus_method_invocation_return_error (invocation, + NM_DEVICE_ERROR, + NM_DEVICE_ERROR_INVALID_ARGUMENT, + "Unsupported options key \"%s\"", + opts_key); + return; + } + + if (!priv->mgmt_iface) { + g_dbus_method_invocation_return_error_literal (invocation, + NM_DEVICE_ERROR, + NM_DEVICE_ERROR_NOT_ACTIVE, + "WPA Supplicant management interface is currently unavailable."); + return; + } + + nm_supplicant_interface_p2p_start_find (priv->mgmt_iface, timeout); + + g_dbus_method_invocation_return_value (invocation, NULL); +} + +static void +impl_device_wifi_p2p_stop_find (NMDBusObject *obj, + const NMDBusInterfaceInfoExtended *interface_info, + const NMDBusMethodInfoExtended *method_info, + GDBusConnection *connection, + const char *sender, + GDBusMethodInvocation *invocation, + GVariant *parameters) +{ + NMDeviceWifiP2P *self = NM_DEVICE_WIFI_P2P (obj); + NMDeviceWifiP2PPrivate *priv = NM_DEVICE_WIFI_P2P_GET_PRIVATE (self); + + if (!priv->mgmt_iface) { + g_dbus_method_invocation_return_error_literal (invocation, + NM_DEVICE_ERROR, + NM_DEVICE_ERROR_NOT_ACTIVE, + "WPA Supplicant management interface is currently unavailable."); + return; + } + + nm_supplicant_interface_p2p_stop_find (priv->mgmt_iface); + + g_dbus_method_invocation_return_value (invocation, NULL); +} + +/*****************************************************************************/ + +NMSupplicantInterface * +nm_device_wifi_p2p_get_mgmt_iface (NMDeviceWifiP2P *self) +{ + g_return_val_if_fail (NM_IS_DEVICE_WIFI_P2P (self), NULL); + + return NM_DEVICE_WIFI_P2P_GET_PRIVATE (self)->mgmt_iface; +} + +void +nm_device_wifi_p2p_set_mgmt_iface (NMDeviceWifiP2P *self, + NMSupplicantInterface *iface) +{ + NMDeviceWifiP2PPrivate *priv; + + g_return_if_fail (NM_IS_DEVICE_WIFI_P2P (self)); + g_return_if_fail (!iface || NM_IS_SUPPLICANT_INTERFACE (iface)); + + priv = NM_DEVICE_WIFI_P2P_GET_PRIVATE (self); + + if (priv->mgmt_iface == iface) + goto done; + + supplicant_interfaces_release (self, FALSE); + + if (!iface) + goto done; + + _LOGD (LOGD_DEVICE | LOGD_WIFI, "P2P: WPA supplicant management interface changed to %s.", + nm_supplicant_interface_get_object_path (iface)); + + priv->mgmt_iface = g_object_ref (iface); + + g_signal_connect (priv->mgmt_iface, NM_SUPPLICANT_INTERFACE_STATE, + G_CALLBACK (supplicant_iface_state_cb), + self); + g_signal_connect (priv->mgmt_iface, NM_SUPPLICANT_INTERFACE_PEER_UPDATED, + G_CALLBACK (supplicant_iface_peer_updated_cb), + self); + g_signal_connect (priv->mgmt_iface, NM_SUPPLICANT_INTERFACE_PEER_REMOVED, + G_CALLBACK (supplicant_iface_peer_removed_cb), + self); + g_signal_connect (priv->mgmt_iface, NM_SUPPLICANT_INTERFACE_GROUP_STARTED, + G_CALLBACK (supplicant_iface_group_started_cb), + self); +done: + nm_device_queue_recheck_available (NM_DEVICE (self), + NM_DEVICE_STATE_REASON_SUPPLICANT_AVAILABLE, + NM_DEVICE_STATE_REASON_SUPPLICANT_FAILED); + _set_is_waiting_for_supplicant (self, + !priv->mgmt_iface + || ( nm_supplicant_interface_get_state (priv->mgmt_iface) + < NM_SUPPLICANT_INTERFACE_STATE_READY)); +} + +void +nm_device_wifi_p2p_remove (NMDeviceWifiP2P* self) +{ + g_signal_emit_by_name (self, NM_DEVICE_REMOVED); +} + +/*****************************************************************************/ + +static const char * +get_type_description (NMDevice *device) +{ + return "wifi-p2p"; +} + +/*****************************************************************************/ + +static const GDBusSignalInfo nm_signal_info_wifi_p2p_peer_added = NM_DEFINE_GDBUS_SIGNAL_INFO_INIT ( + "PeerAdded", + .args = NM_DEFINE_GDBUS_ARG_INFOS ( + NM_DEFINE_GDBUS_ARG_INFO ("peer", "o"), + ), +); + +static const GDBusSignalInfo nm_signal_info_wifi_p2p_peer_removed = NM_DEFINE_GDBUS_SIGNAL_INFO_INIT ( + "PeerRemoved", + .args = NM_DEFINE_GDBUS_ARG_INFOS ( + NM_DEFINE_GDBUS_ARG_INFO ("peer", "o"), + ), +); + +static const NMDBusInterfaceInfoExtended interface_info_device_wifi_p2p = { + .parent = NM_DEFINE_GDBUS_INTERFACE_INFO_INIT ( + NM_DBUS_INTERFACE_DEVICE_WIFI_P2P, + .methods = NM_DEFINE_GDBUS_METHOD_INFOS ( + NM_DEFINE_DBUS_METHOD_INFO_EXTENDED ( + NM_DEFINE_GDBUS_METHOD_INFO_INIT ( + "StartFind", + .in_args = NM_DEFINE_GDBUS_ARG_INFOS ( + NM_DEFINE_GDBUS_ARG_INFO ("options", "a{sv}"), + ), + ), + .handle = impl_device_wifi_p2p_start_find, + ), + NM_DEFINE_DBUS_METHOD_INFO_EXTENDED ( + NM_DEFINE_GDBUS_METHOD_INFO_INIT ( + "StopFind", + ), + .handle = impl_device_wifi_p2p_stop_find, + ), + ), + .signals = NM_DEFINE_GDBUS_SIGNAL_INFOS ( + &nm_signal_info_wifi_p2p_peer_added, + &nm_signal_info_wifi_p2p_peer_removed, + ), + .properties = NM_DEFINE_GDBUS_PROPERTY_INFOS ( + NM_DEFINE_DBUS_PROPERTY_INFO_EXTENDED_READABLE ("HwAddress", "s", NM_DEVICE_HW_ADDRESS), + NM_DEFINE_DBUS_PROPERTY_INFO_EXTENDED_READABLE ("Peers", "ao", NM_DEVICE_WIFI_P2P_PEERS), + ), + ), + .legacy_property_changed = FALSE, +}; + +/*****************************************************************************/ + +static void +get_property (GObject *object, guint prop_id, + GValue *value, GParamSpec *pspec) +{ + NMDeviceWifiP2P *self = NM_DEVICE_WIFI_P2P (object); + NMDeviceWifiP2PPrivate *priv = NM_DEVICE_WIFI_P2P_GET_PRIVATE (self); + const char **list; + + switch (prop_id) { + case PROP_PEERS: + list = nm_wifi_p2p_peers_get_paths (&priv->peers_lst_head); + g_value_take_boxed (value, nm_utils_strv_make_deep_copied (list)); + break; + default: + G_OBJECT_WARN_INVALID_PROPERTY_ID (object, prop_id, pspec); + break; + } +} + +/*****************************************************************************/ + +static void +nm_device_wifi_p2p_init (NMDeviceWifiP2P * self) +{ + NMDeviceWifiP2PPrivate *priv = NM_DEVICE_WIFI_P2P_GET_PRIVATE (self); + + c_list_init (&priv->peers_lst_head); + + priv->sup_mgr = g_object_ref (nm_supplicant_manager_get ()); +} + +static void +constructed (GObject *object) +{ + NMDeviceWifiP2P *self = NM_DEVICE_WIFI_P2P (object); + + G_OBJECT_CLASS (nm_device_wifi_p2p_parent_class)->constructed (object); + + _set_is_waiting_for_supplicant (self, TRUE); +} + +NMDeviceWifiP2P * +nm_device_wifi_p2p_new (const char *iface) +{ + return g_object_new (NM_TYPE_DEVICE_WIFI_P2P, + NM_DEVICE_IFACE, iface, + NM_DEVICE_TYPE_DESC, "802.11 Wi-Fi P2P", + NM_DEVICE_DEVICE_TYPE, NM_DEVICE_TYPE_WIFI_P2P, + NM_DEVICE_LINK_TYPE, NM_LINK_TYPE_WIFI, + NM_DEVICE_RFKILL_TYPE, RFKILL_TYPE_WLAN, + NULL); +} + +static void +dispose (GObject *object) +{ + NMDeviceWifiP2P *self = NM_DEVICE_WIFI_P2P (object); + NMDeviceWifiP2PPrivate *priv = NM_DEVICE_WIFI_P2P_GET_PRIVATE (object); + + g_clear_object (&priv->sup_mgr); + + supplicant_interfaces_release (self, FALSE); + + G_OBJECT_CLASS (nm_device_wifi_p2p_parent_class)->dispose (object); +} + +static void +finalize (GObject *object) +{ + NMDeviceWifiP2P *peer = NM_DEVICE_WIFI_P2P (object); + NMDeviceWifiP2PPrivate *priv = NM_DEVICE_WIFI_P2P_GET_PRIVATE (peer); + + nm_assert (c_list_is_empty (&priv->peers_lst_head)); + + G_OBJECT_CLASS (nm_device_wifi_p2p_parent_class)->finalize (object); +} + +static void +nm_device_wifi_p2p_class_init (NMDeviceWifiP2PClass *klass) +{ + GObjectClass *object_class = G_OBJECT_CLASS (klass); + NMDBusObjectClass *dbus_object_class = NM_DBUS_OBJECT_CLASS (klass); + NMDeviceClass *device_class = NM_DEVICE_CLASS (klass); + + object_class->constructed = constructed; + object_class->get_property = get_property; + object_class->dispose = dispose; + object_class->finalize = finalize; + + dbus_object_class->interface_infos = NM_DBUS_INTERFACE_INFOS (&interface_info_device_wifi_p2p); + + device_class->connection_type_supported = NM_SETTING_WIFI_P2P_SETTING_NAME; + device_class->connection_type_check_compatible = NM_SETTING_WIFI_P2P_SETTING_NAME; + device_class->link_types = NM_DEVICE_DEFINE_LINK_TYPES (NM_LINK_TYPE_WIFI_P2P); + device_class->get_type_description = get_type_description; + + /* Do we need compatibility checking or is the default good enough? */ + device_class->is_available = is_available; + device_class->check_connection_compatible = check_connection_compatible; + device_class->complete_connection = complete_connection; + + device_class->act_stage1_prepare = act_stage1_prepare; + device_class->act_stage2_config = act_stage2_config; + device_class->get_configured_mtu = get_configured_mtu; + device_class->get_auto_ip_config_method = get_auto_ip_config_method; + device_class->act_stage3_ip_config_start = act_stage3_ip_config_start; + + device_class->deactivate = deactivate; + device_class->unmanaged_on_quit = unmanaged_on_quit; + + device_class->state_changed = device_state_changed; + + obj_properties[PROP_PEERS] = + g_param_spec_boxed (NM_DEVICE_WIFI_P2P_PEERS, "", "", + G_TYPE_STRV, + G_PARAM_READABLE | + G_PARAM_STATIC_STRINGS); + + g_object_class_install_properties (object_class, _PROPERTY_ENUMS_LAST, obj_properties); +} diff --git a/src/devices/wifi/nm-device-wifi-p2p.h b/src/devices/wifi/nm-device-wifi-p2p.h new file mode 100644 index 00000000..a13eef15 --- /dev/null +++ b/src/devices/wifi/nm-device-wifi-p2p.h @@ -0,0 +1,50 @@ +/* NetworkManager -- Wi-Fi P2P Device + * + * This library is free software; you can redistribute it and/or + * modify it under the terms of the GNU Lesser General Public + * License as published by the Free Software Foundation; either + * version 2 of the License, or (at your option) any later version. + * + * This library is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + * Lesser General Public License for more details. + * + * You should have received a copy of the GNU Lesser General Public + * License along with this library; if not, write to the + * Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor, + * Boston, MA 02110-1301 USA. + * + * (C) Copyright 2018 Red Hat, Inc. + */ + +#ifndef __NM_DEVICE_WIFI_P2P_H__ +#define __NM_DEVICE_WIFI_P2P_H__ + +#include "devices/nm-device.h" +#include "supplicant/nm-supplicant-interface.h" + +#define NM_TYPE_DEVICE_WIFI_P2P (nm_device_wifi_p2p_get_type ()) +#define NM_DEVICE_WIFI_P2P(obj) (G_TYPE_CHECK_INSTANCE_CAST ((obj), NM_TYPE_DEVICE_WIFI_P2P, NMDeviceWifiP2P)) +#define NM_DEVICE_WIFI_P2P_CLASS(klass) (G_TYPE_CHECK_CLASS_CAST ((klass), NM_TYPE_DEVICE_WIFI_P2P, NMDeviceWifiP2PClass)) +#define NM_IS_DEVICE_WIFI_P2P(obj) (G_TYPE_CHECK_INSTANCE_TYPE ((obj), NM_TYPE_DEVICE_WIFI_P2P)) +#define NM_IS_DEVICE_WIFI_P2P_CLASS(klass) (G_TYPE_CHECK_CLASS_TYPE ((klass), NM_TYPE_DEVICE_WIFI_P2P)) +#define NM_DEVICE_WIFI_P2P_GET_CLASS(obj) (G_TYPE_INSTANCE_GET_CLASS ((obj), NM_TYPE_DEVICE_WIFI_P2P, NMDeviceWifiP2PClass)) + +#define NM_DEVICE_WIFI_P2P_PEERS "peers" +#define NM_DEVICE_WIFI_P2P_GROUPS "groups" + +typedef struct _NMDeviceWifiP2P NMDeviceWifiP2P; +typedef struct _NMDeviceWifiP2PClass NMDeviceWifiP2PClass; + +GType nm_device_wifi_p2p_get_type (void); + +NMDeviceWifiP2P *nm_device_wifi_p2p_new (const char *iface); + +NMSupplicantInterface * nm_device_wifi_p2p_get_mgmt_iface (NMDeviceWifiP2P *self); +void nm_device_wifi_p2p_set_mgmt_iface (NMDeviceWifiP2P *self, + NMSupplicantInterface *iface); + +void nm_device_wifi_p2p_remove (NMDeviceWifiP2P *self); + +#endif /* __NM_DEVICE_WIFI_P2P_H__ */ diff --git a/src/devices/wifi/nm-device-wifi.c b/src/devices/wifi/nm-device-wifi.c index e0be38c3..d33d4307 100644 --- a/src/devices/wifi/nm-device-wifi.c +++ b/src/devices/wifi/nm-device-wifi.c @@ -24,10 +24,9 @@ #include "nm-device-wifi.h" #include <netinet/in.h> -#include <string.h> #include <unistd.h> -#include <errno.h> +#include "nm-device-wifi-p2p.h" #include "nm-wifi-ap.h" #include "nm-common-macros.h" #include "devices/nm-device.h" @@ -79,6 +78,7 @@ NM_GOBJECT_PROPERTIES_DEFINE (NMDeviceWifi, enum { SCANNING_PROHIBITED, + P2P_DEVICE_CREATED, LAST_SIGNAL }; @@ -124,6 +124,8 @@ typedef struct { guint wps_timeout_id; NMSettingWirelessWakeOnWLan wowlan_restore; + + NMDeviceWifiP2P *p2p_device; } NMDeviceWifiPrivate; struct _NMDeviceWifi @@ -186,6 +188,10 @@ static void supplicant_iface_notify_current_bss (NMSupplicantInterface *iface, GParamSpec *pspec, NMDeviceWifi *self); +static void supplicant_iface_notify_p2p_available (NMSupplicantInterface *iface, + GParamSpec *pspec, + NMDeviceWifi *self); + static void request_wireless_scan (NMDeviceWifi *self, gboolean periodic, gboolean force_if_scanning, @@ -198,6 +204,8 @@ static void ap_add_remove (NMDeviceWifi *self, static void _hw_addr_set_scanning (NMDeviceWifi *self, gboolean do_reset); +static void recheck_p2p_availability (NMDeviceWifi *self); + /*****************************************************************************/ static void @@ -291,6 +299,10 @@ supplicant_interface_acquire (NMDeviceWifi *self) "notify::" NM_SUPPLICANT_INTERFACE_CURRENT_BSS, G_CALLBACK (supplicant_iface_notify_current_bss), self); + g_signal_connect (priv->sup_iface, + "notify::" NM_SUPPLICANT_INTERFACE_P2P_AVAILABLE, + G_CALLBACK (supplicant_iface_notify_p2p_available), + self); _notify_scanning (self); @@ -347,6 +359,11 @@ supplicant_interface_release (NMDeviceWifi *self) g_clear_object (&priv->sup_iface); } + if (priv->p2p_device) { + /* Signal to P2P device to also release its reference */ + nm_device_wifi_p2p_set_mgmt_iface (priv->p2p_device, NULL); + } + _notify_scanning (self); } @@ -1185,7 +1202,7 @@ _nm_device_wifi_request_scan (NMDeviceWifi *self, NM_DEVICE_AUTH_REQUEST, invocation, NULL, - NM_AUTH_PERMISSION_NETWORK_CONTROL, + NM_AUTH_PERMISSION_WIFI_SCAN, TRUE, dbus_request_scan_cb, options ? g_variant_ref (options) : NULL); @@ -2028,6 +2045,10 @@ supplicant_iface_state_cb (NMSupplicantInterface *iface, && new_state <= NM_SUPPLICANT_INTERFACE_STATE_COMPLETED) priv->ssid_found = TRUE; + if ( old_state < NM_SUPPLICANT_INTERFACE_STATE_READY + && new_state >= NM_SUPPLICANT_INTERFACE_STATE_READY) + recheck_p2p_availability (self); + switch (new_state) { case NM_SUPPLICANT_INTERFACE_STATE_READY: _LOGD (LOGD_WIFI, "supplicant ready"); @@ -2204,6 +2225,67 @@ supplicant_iface_notify_current_bss (NMSupplicantInterface *iface, } } +/* We bind the existence of the P2P device to a wifi device that is being + * managed by NetworkManager and is capable of P2P operation. + * Note that some care must be taken here, because we don't want to re-create + * the device every time the supplicant interface is destroyed (e.g. due to + * a suspend/resume cycle). + * Therefore, this function will be called when a change in the P2P capability + * is detected and the supplicant interface has been initialised. + */ +static void +recheck_p2p_availability (NMDeviceWifi *self) +{ + NMDeviceWifiPrivate *priv = NM_DEVICE_WIFI_GET_PRIVATE (self); + gboolean p2p_available; + + g_object_get (priv->sup_iface, + NM_SUPPLICANT_INTERFACE_P2P_AVAILABLE, &p2p_available, + NULL); + + if (p2p_available && !priv->p2p_device) { + gs_free char *iface_name = NULL; + + /* Create a P2P device. "p2p-dev-" is the same prefix as chosen by + * wpa_supplicant internally. + */ + iface_name = g_strconcat ("p2p-dev-", nm_device_get_iface (NM_DEVICE (self)), NULL); + + priv->p2p_device = nm_device_wifi_p2p_new (iface_name); + + nm_device_wifi_p2p_set_mgmt_iface (priv->p2p_device, priv->sup_iface); + + g_signal_emit (self, signals[P2P_DEVICE_CREATED], 0, priv->p2p_device); + g_object_add_weak_pointer (G_OBJECT (priv->p2p_device), (gpointer*) &priv->p2p_device); + g_object_unref (priv->p2p_device); + return; + } + + if (p2p_available && priv->p2p_device) { + nm_device_wifi_p2p_set_mgmt_iface (priv->p2p_device, priv->sup_iface); + return; + } + + if (!p2p_available && priv->p2p_device) { + /* Destroy the P2P device. */ + g_object_remove_weak_pointer (G_OBJECT (priv->p2p_device), (gpointer*) &priv->p2p_device); + nm_device_wifi_p2p_remove (g_steal_pointer (&priv->p2p_device)); + return; + } +} + +static void +supplicant_iface_notify_p2p_available (NMSupplicantInterface *iface, + GParamSpec *pspec, + NMDeviceWifi *self) +{ + /* Do not update when the interface is still initializing. */ + if (nm_supplicant_interface_get_state (iface) < NM_SUPPLICANT_INTERFACE_STATE_READY) + return; + + recheck_p2p_availability (self); +} + static gboolean handle_auth_or_fail (NMDeviceWifi *self, NMActRequest *req, @@ -2792,52 +2874,29 @@ out: } static NMActStageReturn -act_stage3_ip4_config_start (NMDevice *device, - NMIP4Config **out_config, - NMDeviceStateReason *out_failure_reason) +act_stage3_ip_config_start (NMDevice *device, + int addr_family, + gpointer *out_config, + NMDeviceStateReason *out_failure_reason) { + gboolean indicate_addressing_running; NMConnection *connection; - NMSettingIPConfig *s_ip4; - const char *method = NM_SETTING_IP4_CONFIG_METHOD_AUTO; + const char *method; connection = nm_device_get_applied_connection (device); - g_return_val_if_fail (connection, NM_ACT_STAGE_RETURN_FAILURE); - - s_ip4 = nm_connection_get_setting_ip4_config (connection); - if (s_ip4) - method = nm_setting_ip_config_get_method (s_ip4); - - /* Indicate that a critical protocol is about to start */ - if (strcmp (method, NM_SETTING_IP4_CONFIG_METHOD_AUTO) == 0) - nm_platform_wifi_indicate_addressing_running (nm_device_get_platform (device), nm_device_get_ifindex (device), TRUE); - - return NM_DEVICE_CLASS (nm_device_wifi_parent_class)->act_stage3_ip4_config_start (device, out_config, out_failure_reason); -} - -static NMActStageReturn -act_stage3_ip6_config_start (NMDevice *device, - NMIP6Config **out_config, - NMDeviceStateReason *out_failure_reason) -{ - NMConnection *connection; - NMSettingIPConfig *s_ip6; - const char *method = NM_SETTING_IP6_CONFIG_METHOD_AUTO; - - connection = nm_device_get_applied_connection (device); - - g_return_val_if_fail (connection, NM_ACT_STAGE_RETURN_FAILURE); - - s_ip6 = nm_connection_get_setting_ip6_config (connection); - if (s_ip6) - method = nm_setting_ip_config_get_method (s_ip6); + method = nm_utils_get_ip_config_method (connection, addr_family); + if (addr_family == AF_INET) + indicate_addressing_running = NM_IN_STRSET (method, NM_SETTING_IP4_CONFIG_METHOD_AUTO); + else { + indicate_addressing_running = NM_IN_STRSET (method, NM_SETTING_IP6_CONFIG_METHOD_AUTO, + NM_SETTING_IP6_CONFIG_METHOD_DHCP); + } - /* Indicate that a critical protocol is about to start */ - if (strcmp (method, NM_SETTING_IP6_CONFIG_METHOD_AUTO) == 0 || - strcmp (method, NM_SETTING_IP6_CONFIG_METHOD_DHCP) == 0) - nm_platform_wifi_indicate_addressing_running (nm_device_get_platform (device), nm_device_get_ifindex (device), TRUE); + if (indicate_addressing_running) + nm_platform_wifi_indicate_addressing_running (nm_device_get_platform (device), nm_device_get_ip_ifindex (device), TRUE); - return NM_DEVICE_CLASS (nm_device_wifi_parent_class)->act_stage3_ip6_config_start (device, out_config, out_failure_reason); + return NM_DEVICE_CLASS (nm_device_wifi_parent_class)->act_stage3_ip_config_start (device, addr_family, out_config, out_failure_reason); } static guint32 @@ -2872,19 +2931,27 @@ is_static_wep (NMConnection *connection) } static NMActStageReturn -handle_ip_config_timeout (NMDeviceWifi *self, - NMConnection *connection, - gboolean may_fail, - gboolean *chain_up, - NMDeviceStateReason *out_failure_reason) +act_stage4_ip_config_timeout (NMDevice *device, + int addr_family, + NMDeviceStateReason *out_failure_reason) { - NMActStageReturn ret = NM_ACT_STAGE_RETURN_FAILURE; + NMDeviceWifi *self = NM_DEVICE_WIFI (device); + NMDeviceWifiPrivate *priv = NM_DEVICE_WIFI_GET_PRIVATE (self); + NMConnection *connection; + NMSettingIPConfig *s_ip; + gboolean may_fail; - g_return_val_if_fail (connection != NULL, NM_ACT_STAGE_RETURN_FAILURE); + connection = nm_device_get_applied_connection (device); + s_ip = nm_connection_get_setting_ip4_config (connection); + may_fail = nm_setting_ip_config_get_may_fail (s_ip); - if (NM_DEVICE_WIFI_GET_PRIVATE (self)->mode == NM_802_11_MODE_AP) { - *chain_up = TRUE; - return NM_ACT_STAGE_RETURN_FAILURE; + if (priv->mode == NM_802_11_MODE_AP) + goto call_parent; + + if ( may_fail + && !is_static_wep (connection)) { + /* Not static WEP or failure allowed; let superclass handle it */ + goto call_parent; } /* If IP configuration times out and it's a static WEP connection, that @@ -2893,71 +2960,23 @@ handle_ip_config_timeout (NMDeviceWifi *self, * to wait for DHCP to fail to figure it out. For all other Wi-Fi security * types (open, WPA, 802.1x, etc) if the secrets/certs were wrong the * connection would have failed before IP configuration. - */ - if (!may_fail && is_static_wep (connection)) { - /* Activation failed, we must have bad encryption key */ - _LOGW (LOGD_DEVICE | LOGD_WIFI, - "Activation: (wifi) could not get IP configuration for connection '%s'.", - nm_connection_get_id (connection)); + * + * Activation failed, we must have bad encryption key */ + _LOGW (LOGD_DEVICE | LOGD_WIFI, + "Activation: (wifi) could not get IP configuration for connection '%s'.", + nm_connection_get_id (connection)); - if (handle_auth_or_fail (self, NULL, TRUE)) { - _LOGI (LOGD_DEVICE | LOGD_WIFI, - "Activation: (wifi) asking for new secrets"); - ret = NM_ACT_STAGE_RETURN_POSTPONE; - } else { - NM_SET_OUT (out_failure_reason, NM_DEVICE_STATE_REASON_NO_SECRETS); - ret = NM_ACT_STAGE_RETURN_FAILURE; - } - } else { - /* Not static WEP or failure allowed; let superclass handle it */ - *chain_up = TRUE; + if (!handle_auth_or_fail (self, NULL, TRUE)) { + NM_SET_OUT (out_failure_reason, NM_DEVICE_STATE_REASON_NO_SECRETS); + return NM_ACT_STAGE_RETURN_FAILURE; } - return ret; -} - -static NMActStageReturn -act_stage4_ip4_config_timeout (NMDevice *device, NMDeviceStateReason *out_failure_reason) -{ - NMConnection *connection; - NMSettingIPConfig *s_ip4; - gboolean may_fail = FALSE, chain_up = FALSE; - NMActStageReturn ret; - - connection = nm_device_get_applied_connection (device); - - g_return_val_if_fail (connection, NM_ACT_STAGE_RETURN_FAILURE); - - s_ip4 = nm_connection_get_setting_ip4_config (connection); - may_fail = nm_setting_ip_config_get_may_fail (s_ip4); - - ret = handle_ip_config_timeout (NM_DEVICE_WIFI (device), connection, may_fail, &chain_up, out_failure_reason); - if (chain_up) - ret = NM_DEVICE_CLASS (nm_device_wifi_parent_class)->act_stage4_ip4_config_timeout (device, out_failure_reason); - - return ret; -} - -static NMActStageReturn -act_stage4_ip6_config_timeout (NMDevice *device, NMDeviceStateReason *out_failure_reason) -{ - NMConnection *connection; - NMSettingIPConfig *s_ip6; - gboolean may_fail = FALSE, chain_up = FALSE; - NMActStageReturn ret; - - connection = nm_device_get_applied_connection (device); - - g_return_val_if_fail (connection, NM_ACT_STAGE_RETURN_FAILURE); - - s_ip6 = nm_connection_get_setting_ip6_config (connection); - may_fail = nm_setting_ip_config_get_may_fail (s_ip6); - - ret = handle_ip_config_timeout (NM_DEVICE_WIFI (device), connection, may_fail, &chain_up, out_failure_reason); - if (chain_up) - ret = NM_DEVICE_CLASS (nm_device_wifi_parent_class)->act_stage4_ip6_config_timeout (device, out_failure_reason); + _LOGI (LOGD_DEVICE | LOGD_WIFI, + "Activation: (wifi) asking for new secrets"); + return NM_ACT_STAGE_RETURN_POSTPONE; - return ret; +call_parent: + return NM_DEVICE_CLASS (nm_device_wifi_parent_class)->act_stage4_ip_config_timeout (device, addr_family, out_failure_reason); } static void @@ -3314,6 +3333,12 @@ dispose (GObject *object) remove_all_aps (self); + if (priv->p2p_device) { + /* Destroy the P2P device. */ + g_object_remove_weak_pointer (G_OBJECT (priv->p2p_device), (gpointer*) &priv->p2p_device); + nm_device_wifi_p2p_remove (g_steal_pointer (&priv->p2p_device)); + } + G_OBJECT_CLASS (nm_device_wifi_parent_class)->dispose (object); } @@ -3359,10 +3384,8 @@ nm_device_wifi_class_init (NMDeviceWifiClass *klass) device_class->act_stage1_prepare = act_stage1_prepare; device_class->act_stage2_config = act_stage2_config; device_class->get_configured_mtu = get_configured_mtu; - device_class->act_stage3_ip4_config_start = act_stage3_ip4_config_start; - device_class->act_stage3_ip6_config_start = act_stage3_ip6_config_start; - device_class->act_stage4_ip4_config_timeout = act_stage4_ip4_config_timeout; - device_class->act_stage4_ip6_config_timeout = act_stage4_ip6_config_timeout; + device_class->act_stage3_ip_config_start = act_stage3_ip_config_start; + device_class->act_stage4_ip_config_timeout = act_stage4_ip_config_timeout; device_class->deactivate = deactivate; device_class->deactivate_reset_hw_addr = deactivate_reset_hw_addr; device_class->unmanaged_on_quit = unmanaged_on_quit; @@ -3426,4 +3449,12 @@ nm_device_wifi_class_init (NMDeviceWifiClass *klass) G_STRUCT_OFFSET (NMDeviceWifiClass, scanning_prohibited), NULL, NULL, NULL, G_TYPE_BOOLEAN, 1, G_TYPE_BOOLEAN); + + signals[P2P_DEVICE_CREATED] = + g_signal_new (NM_DEVICE_WIFI_P2P_DEVICE_CREATED, + G_OBJECT_CLASS_TYPE (object_class), + G_SIGNAL_RUN_LAST, + 0, NULL, NULL, + g_cclosure_marshal_VOID__OBJECT, + G_TYPE_NONE, 1, NM_TYPE_DEVICE); } diff --git a/src/devices/wifi/nm-device-wifi.h b/src/devices/wifi/nm-device-wifi.h index 1c555f5f..116ad11e 100644 --- a/src/devices/wifi/nm-device-wifi.h +++ b/src/devices/wifi/nm-device-wifi.h @@ -40,6 +40,7 @@ #define NM_DEVICE_WIFI_LAST_SCAN "last-scan" #define NM_DEVICE_WIFI_SCANNING_PROHIBITED "scanning-prohibited" +#define NM_DEVICE_WIFI_P2P_DEVICE_CREATED "p2p-device-created" typedef struct _NMDeviceWifi NMDeviceWifi; typedef struct _NMDeviceWifiClass NMDeviceWifiClass; diff --git a/src/devices/wifi/nm-iwd-manager.c b/src/devices/wifi/nm-iwd-manager.c index 736a1a23..d668f0d8 100644 --- a/src/devices/wifi/nm-iwd-manager.c +++ b/src/devices/wifi/nm-iwd-manager.c @@ -22,7 +22,6 @@ #include "nm-iwd-manager.h" -#include <string.h> #include <net/if.h> #include "nm-logging.h" @@ -137,6 +136,7 @@ agent_dbus_method_cb (GDBusConnection *connection, int ifindex; NMDevice *device; gs_free char *name_owner = NULL; + int errsv; /* Be paranoid and check the sender address */ name_owner = g_dbus_object_manager_client_get_name_owner (G_DBUS_OBJECT_MANAGER_CLIENT (priv->object_manager)); @@ -172,8 +172,9 @@ agent_dbus_method_cb (GDBusConnection *connection, ifindex = if_nametoindex (ifname); if (!ifindex) { + errsv = errno; _LOGD ("agent-request: if_nametoindex failed for Name %s for Device at %s: %i", - ifname, device_path, errno); + ifname, device_path, errsv); goto return_error; } @@ -339,6 +340,7 @@ set_device_dbus_object (NMIwdManager *self, GDBusProxy *proxy, const char *ifname; int ifindex; NMDevice *device; + int errsv; ifname = get_property_string_or_null (proxy, "Name"); if (!ifname) { @@ -350,8 +352,9 @@ set_device_dbus_object (NMIwdManager *self, GDBusProxy *proxy, ifindex = if_nametoindex (ifname); if (!ifindex) { + errsv = errno; _LOGE ("if_nametoindex failed for Name %s for Device at %s: %i", - ifname, g_dbus_proxy_get_object_path (proxy), errno); + ifname, g_dbus_proxy_get_object_path (proxy), errsv); return; } diff --git a/src/devices/wifi/nm-wifi-ap.c b/src/devices/wifi/nm-wifi-ap.c index e5573383..87daff59 100644 --- a/src/devices/wifi/nm-wifi-ap.c +++ b/src/devices/wifi/nm-wifi-ap.c @@ -23,7 +23,6 @@ #include "nm-wifi-ap.h" -#include <string.h> #include <stdlib.h> #include "nm-setting-wireless.h" @@ -425,6 +424,8 @@ security_from_vardict (GVariant *security) g_strv_contains (array, "wpa-fils-sha256") || g_strv_contains (array, "wpa-fils-sha384")) flags |= NM_802_11_AP_SEC_KEY_MGMT_802_1X; + if (g_strv_contains (array, "sae")) + flags |= NM_802_11_AP_SEC_KEY_MGMT_SAE; g_free (array); } @@ -1390,7 +1391,8 @@ nm_wifi_ap_class_init (NMWifiAPClass *ap_class) | NM_802_11_AP_SEC_GROUP_TKIP \ | NM_802_11_AP_SEC_GROUP_CCMP \ | NM_802_11_AP_SEC_KEY_MGMT_PSK \ - | NM_802_11_AP_SEC_KEY_MGMT_802_1X ) + | NM_802_11_AP_SEC_KEY_MGMT_802_1X \ + | NM_802_11_AP_SEC_KEY_MGMT_SAE ) GObjectClass *object_class = G_OBJECT_CLASS (ap_class); NMDBusObjectClass *dbus_object_class = NM_DBUS_OBJECT_CLASS (ap_class); diff --git a/src/devices/wifi/nm-wifi-factory.c b/src/devices/wifi/nm-wifi-factory.c index 4e9d1ecb..9a89bbe9 100644 --- a/src/devices/wifi/nm-wifi-factory.c +++ b/src/devices/wifi/nm-wifi-factory.c @@ -26,6 +26,7 @@ #include "nm-setting-wireless.h" #include "nm-setting-olpc-mesh.h" #include "nm-device-wifi.h" +#include "nm-device-wifi-p2p.h" #include "nm-device-olpc-mesh.h" #include "nm-device-iwd.h" #include "settings/nm-settings-connection.h" @@ -68,6 +69,18 @@ nm_device_factory_create (GError **error) /*****************************************************************************/ +static void +p2p_device_created (NMDeviceWifi *device, + NMDeviceWifiP2P *p2p_device, + NMDeviceFactory *self) +{ + nm_log_info (LOGD_PLATFORM | LOGD_WIFI, + "Wi-Fi P2P device controlled by interface %s created", + nm_device_get_iface (NM_DEVICE (device))); + + g_signal_emit_by_name (self, NM_DEVICE_FACTORY_DEVICE_ADDED, p2p_device); +} + static NMDevice * create_device (NMDeviceFactory *factory, const char *iface, @@ -98,6 +111,7 @@ create_device (NMDeviceFactory *factory, NM_PRINT_FMT_QUOTE_STRING (backend), WITH_IWD ? " (iwd support enabled)" : ""); if (!backend || !strcasecmp (backend, "wpa_supplicant")) { + NMDevice *device; NMDeviceWifiCapabilities capabilities; NM80211Mode mode; @@ -120,7 +134,14 @@ create_device (NMDeviceFactory *factory, return NULL; } - return nm_device_wifi_new (iface, capabilities); + device = nm_device_wifi_new (iface, capabilities); + + g_signal_connect_object (device, NM_DEVICE_WIFI_P2P_DEVICE_CREATED, + G_CALLBACK (p2p_device_created), + factory, + 0); + + return device; } #if WITH_IWD else if (!strcasecmp (backend, "iwd")) diff --git a/src/devices/wifi/nm-wifi-p2p-peer.c b/src/devices/wifi/nm-wifi-p2p-peer.c new file mode 100644 index 00000000..4b524623 --- /dev/null +++ b/src/devices/wifi/nm-wifi-p2p-peer.c @@ -0,0 +1,796 @@ +/* NetworkManager -- Wi-Fi P2P Peer + * + * This library is free software; you can redistribute it and/or + * modify it under the terms of the GNU Lesser General Public + * License as published by the Free Software Foundation; either + * version 2 of the License, or (at your option) any later version. + * + * This library is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + * Lesser General Public License for more details. + * + * You should have received a copy of the GNU Lesser General Public + * License along with this library; if not, write to the + * Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor, + * Boston, MA 02110-1301 USA. + * + * Copyright (C) 2018 Red Hat, Inc. + */ + +#include "nm-default.h" + +#include "nm-wifi-p2p-peer.h" + +#include <stdlib.h> + +#include "nm-setting-wireless.h" + +#include "nm-wifi-utils.h" +#include "NetworkManagerUtils.h" +#include "nm-utils.h" +#include "nm-core-internal.h" +#include "platform/nm-platform.h" +#include "devices/nm-device.h" +#include "nm-dbus-manager.h" + +/*****************************************************************************/ + +NM_GOBJECT_PROPERTIES_DEFINE (NMWifiP2PPeer, + PROP_NAME, + PROP_MANUFACTURER, + PROP_MODEL, + PROP_MODEL_NUMBER, + PROP_SERIAL, + PROP_WFD_IES, + PROP_GROUPS, + PROP_HW_ADDRESS, + PROP_STRENGTH, + PROP_LAST_SEEN, + PROP_FLAGS, +); + +struct _NMWifiP2PPeerPrivate { + char *supplicant_path; /* D-Bus object path of this Peer from wpa_supplicant */ + + /* Scanned or cached values */ + char * name; + char * manufacturer; + char * model; + char * model_number; + char * serial; + + char * address; + + GBytes * wfd_ies; + char ** groups; + + guint8 strength; + + NM80211ApFlags flags; /* General flags */ + + /* Non-scanned attributes */ + gint32 last_seen; /* Timestamp when the Peer was seen lastly (obtained via nm_utils_get_monotonic_timestamp_s()) */ +}; + +typedef struct _NMWifiP2PPeerPrivate NMWifiP2PPeerPrivate; + +struct _NMWifiP2PPeerClass { + NMDBusObjectClass parent; +}; + +G_DEFINE_TYPE (NMWifiP2PPeer, nm_wifi_p2p_peer, NM_TYPE_DBUS_OBJECT) + +#define NM_WIFI_P2P_PEER_GET_PRIVATE(self) _NM_GET_PRIVATE_PTR(self, NMWifiP2PPeer, NM_IS_WIFI_P2P_PEER) + +/*****************************************************************************/ + +const char ** +nm_wifi_p2p_peers_get_paths (const CList *peers_lst_head) +{ + NMWifiP2PPeer *peer; + const char **list; + const char *path; + gsize i, n; + + n = c_list_length (peers_lst_head); + list = g_new (const char *, n + 1); + + i = 0; + if (n > 0) { + c_list_for_each_entry (peer, peers_lst_head, peers_lst) { + nm_assert (i < n); + path = nm_dbus_object_get_path (NM_DBUS_OBJECT (peer)); + nm_assert (path); + + list[i++] = path; + } + nm_assert (i <= n); + } + list[i] = NULL; + return list; +} + +NMWifiP2PPeer * +nm_wifi_p2p_peers_find_first_compatible (const CList *peers_lst_head, + NMConnection *connection) +{ + NMWifiP2PPeer *peer; + + g_return_val_if_fail (connection, NULL); + + c_list_for_each_entry (peer, peers_lst_head, peers_lst) { + if (nm_wifi_p2p_peer_check_compatible (peer, connection)) + return peer; + } + return NULL; +} + +NMWifiP2PPeer * +nm_wifi_p2p_peers_find_by_supplicant_path (const CList *peers_lst_head, const char *path) +{ + NMWifiP2PPeer *peer; + + g_return_val_if_fail (path != NULL, NULL); + + c_list_for_each_entry (peer, peers_lst_head, peers_lst) { + if (nm_streq0 (path, nm_wifi_p2p_peer_get_supplicant_path (peer))) + return peer; + } + return NULL; +} + +/*****************************************************************************/ + +NMWifiP2PPeer * +nm_wifi_p2p_peer_lookup_for_device (NMDevice *device, const char *exported_path) +{ + NMWifiP2PPeer *peer; + + g_return_val_if_fail (NM_IS_DEVICE (device), NULL); + + peer = (NMWifiP2PPeer *) nm_dbus_manager_lookup_object (nm_dbus_object_get_manager (NM_DBUS_OBJECT (device)), + exported_path); + if ( !peer + || !NM_IS_WIFI_P2P_PEER (peer) + || peer->wifi_device != device) + return NULL; + + return peer; +} + +/*****************************************************************************/ + +const char * +nm_wifi_p2p_peer_get_supplicant_path (NMWifiP2PPeer *peer) +{ + g_return_val_if_fail (NM_IS_WIFI_P2P_PEER (peer), NULL); + + return NM_WIFI_P2P_PEER_GET_PRIVATE (peer)->supplicant_path; +} + +const char * +nm_wifi_p2p_peer_get_name (const NMWifiP2PPeer *peer) +{ + g_return_val_if_fail (NM_IS_WIFI_P2P_PEER (peer), NULL); + + return NM_WIFI_P2P_PEER_GET_PRIVATE (peer)->name; +} + +gboolean +nm_wifi_p2p_peer_set_name (NMWifiP2PPeer *peer, const char *name) +{ + NMWifiP2PPeerPrivate *priv = NM_WIFI_P2P_PEER_GET_PRIVATE (peer); + g_return_val_if_fail (NM_IS_WIFI_P2P_PEER (peer), FALSE); + + if (g_strcmp0 (name, priv->name) == 0) + return FALSE; + + g_clear_pointer (&priv->name, g_free); + if (name) + priv->name = g_strdup (name); + + _notify (peer, PROP_NAME); + return TRUE; +} + +const char * +nm_wifi_p2p_peer_get_manufacturer (const NMWifiP2PPeer *peer) +{ + g_return_val_if_fail (NM_IS_WIFI_P2P_PEER (peer), NULL); + + return NM_WIFI_P2P_PEER_GET_PRIVATE (peer)->manufacturer; +} + +gboolean +nm_wifi_p2p_peer_set_manufacturer (NMWifiP2PPeer *peer, const char *manufacturer) +{ + NMWifiP2PPeerPrivate *priv = NM_WIFI_P2P_PEER_GET_PRIVATE (peer); + g_return_val_if_fail (NM_IS_WIFI_P2P_PEER (peer), FALSE); + + if (g_strcmp0 (manufacturer, priv->manufacturer) == 0) + return FALSE; + + g_clear_pointer (&priv->manufacturer, g_free); + if (manufacturer) + priv->manufacturer = g_strdup (manufacturer); + + _notify (peer, PROP_MANUFACTURER); + return TRUE; +} + +const char * +nm_wifi_p2p_peer_get_model (const NMWifiP2PPeer *peer) +{ + g_return_val_if_fail (NM_IS_WIFI_P2P_PEER (peer), NULL); + + return NM_WIFI_P2P_PEER_GET_PRIVATE (peer)->model; +} + +gboolean +nm_wifi_p2p_peer_set_model (NMWifiP2PPeer *peer, const char *model) +{ + NMWifiP2PPeerPrivate *priv = NM_WIFI_P2P_PEER_GET_PRIVATE (peer); + g_return_val_if_fail (NM_IS_WIFI_P2P_PEER (peer), FALSE); + + if (g_strcmp0 (model, priv->model) == 0) + return FALSE; + + g_clear_pointer (&priv->model, g_free); + if (model) + priv->model = g_strdup (model); + + _notify (peer, PROP_MODEL); + return TRUE; +} + +const char * +nm_wifi_p2p_peer_get_model_number (const NMWifiP2PPeer *peer) +{ + g_return_val_if_fail (NM_IS_WIFI_P2P_PEER (peer), NULL); + + return NM_WIFI_P2P_PEER_GET_PRIVATE (peer)->model_number; +} + +gboolean +nm_wifi_p2p_peer_set_model_number (NMWifiP2PPeer *peer, const char *model_number) +{ + NMWifiP2PPeerPrivate *priv = NM_WIFI_P2P_PEER_GET_PRIVATE (peer); + g_return_val_if_fail (NM_IS_WIFI_P2P_PEER (peer), FALSE); + + if (g_strcmp0 (model_number, priv->model_number) == 0) + return FALSE; + + g_clear_pointer (&priv->model_number, g_free); + if (model_number) + priv->model_number = g_strdup (model_number); + + _notify (peer, PROP_MODEL_NUMBER); + return TRUE; +} + +const char * +nm_wifi_p2p_peer_get_serial (const NMWifiP2PPeer *peer) +{ + g_return_val_if_fail (NM_IS_WIFI_P2P_PEER (peer), NULL); + + return NM_WIFI_P2P_PEER_GET_PRIVATE (peer)->serial; +} + +gboolean +nm_wifi_p2p_peer_set_serial (NMWifiP2PPeer *peer, const char *serial) +{ + NMWifiP2PPeerPrivate *priv = NM_WIFI_P2P_PEER_GET_PRIVATE (peer); + g_return_val_if_fail (NM_IS_WIFI_P2P_PEER (peer), FALSE); + + if (g_strcmp0 (serial, priv->serial) == 0) + return FALSE; + + g_clear_pointer (&priv->serial, g_free); + if (serial) + priv->serial = g_strdup (serial); + + _notify (peer, PROP_SERIAL); + return TRUE; +} + +GBytes * +nm_wifi_p2p_peer_get_wfd_ies (const NMWifiP2PPeer *peer) +{ + g_return_val_if_fail (NM_IS_WIFI_P2P_PEER (peer), NULL); + + return NM_WIFI_P2P_PEER_GET_PRIVATE (peer)->wfd_ies; +} + +gboolean +nm_wifi_p2p_peer_set_wfd_ies (NMWifiP2PPeer *peer, GBytes *wfd_ies) +{ + NMWifiP2PPeerPrivate *priv; + + g_return_val_if_fail (NM_IS_WIFI_P2P_PEER (peer), FALSE); + + priv = NM_WIFI_P2P_PEER_GET_PRIVATE (peer); + + if (nm_gbytes_equal0 (priv->wfd_ies, wfd_ies)) + return FALSE; + + g_bytes_unref (priv->wfd_ies); + priv->wfd_ies = wfd_ies ? g_bytes_ref (wfd_ies) : NULL; + + _notify (peer, PROP_WFD_IES); + return TRUE; +} + +const char *const* +nm_wifi_p2p_peer_get_groups (const NMWifiP2PPeer *peer) +{ + g_return_val_if_fail (NM_IS_WIFI_P2P_PEER (peer), NULL); + + return (const char * const*) NM_WIFI_P2P_PEER_GET_PRIVATE (peer)->groups; +} + +static gboolean +nm_wifi_p2p_peer_set_groups (NMWifiP2PPeer *peer, const char** groups) +{ + NMWifiP2PPeerPrivate *priv; + + g_return_val_if_fail (NM_IS_WIFI_P2P_PEER (peer), FALSE); + g_return_val_if_fail (groups != NULL, FALSE); + + priv = NM_WIFI_P2P_PEER_GET_PRIVATE (peer); + + if (_nm_utils_strv_equal (priv->groups, (char **) groups)) + return FALSE; + + g_strfreev (priv->groups); + priv->groups = g_strdupv ((char**) groups); + + _notify (peer, PROP_GROUPS); + return TRUE; +} + +const char * +nm_wifi_p2p_peer_get_address (const NMWifiP2PPeer *peer) +{ + g_return_val_if_fail (NM_IS_WIFI_P2P_PEER (peer), NULL); + + return NM_WIFI_P2P_PEER_GET_PRIVATE (peer)->address; +} + +static gboolean +nm_wifi_p2p_peer_set_address_bin (NMWifiP2PPeer *peer, const guint8 addr[static ETH_ALEN]) +{ + NMWifiP2PPeerPrivate *priv = NM_WIFI_P2P_PEER_GET_PRIVATE (peer); + + if ( priv->address + && nm_utils_hwaddr_matches (addr, ETH_ALEN, priv->address, -1)) + return FALSE; + + g_free (priv->address); + priv->address = nm_utils_hwaddr_ntoa (addr, ETH_ALEN); + _notify (peer, PROP_HW_ADDRESS); + return TRUE; +} + +gboolean +nm_wifi_p2p_peer_set_address (NMWifiP2PPeer *peer, const char *addr) +{ + guint8 addr_buf[ETH_ALEN]; + + g_return_val_if_fail (NM_IS_WIFI_P2P_PEER (peer), FALSE); + + if ( !addr + || !nm_utils_hwaddr_aton (addr, addr_buf, sizeof (addr_buf))) + g_return_val_if_reached (FALSE); + + return nm_wifi_p2p_peer_set_address_bin (peer, addr_buf); +} + +gint8 +nm_wifi_p2p_peer_get_strength (NMWifiP2PPeer *peer) +{ + g_return_val_if_fail (NM_IS_WIFI_P2P_PEER (peer), 0); + + return NM_WIFI_P2P_PEER_GET_PRIVATE (peer)->strength; +} + +gboolean +nm_wifi_p2p_peer_set_strength (NMWifiP2PPeer *peer, const gint8 strength) +{ + NMWifiP2PPeerPrivate *priv; + + g_return_val_if_fail (NM_IS_WIFI_P2P_PEER (peer), FALSE); + + priv = NM_WIFI_P2P_PEER_GET_PRIVATE (peer); + + if (priv->strength != strength) { + priv->strength = strength; + _notify (peer, PROP_STRENGTH); + return TRUE; + } + return FALSE; +} + +NM80211ApFlags +nm_wifi_p2p_peer_get_flags (const NMWifiP2PPeer *peer) +{ + g_return_val_if_fail (NM_IS_WIFI_P2P_PEER (peer), NM_802_11_AP_FLAGS_NONE); + + return NM_WIFI_P2P_PEER_GET_PRIVATE (peer)->flags; +} + +static gboolean +nm_wifi_p2p_peer_set_last_seen (NMWifiP2PPeer *peer, gint32 last_seen) +{ + NMWifiP2PPeerPrivate *priv; + + g_return_val_if_fail (NM_IS_WIFI_P2P_PEER (peer), FALSE); + + priv = NM_WIFI_P2P_PEER_GET_PRIVATE (peer); + + if (priv->last_seen != last_seen) { + priv->last_seen = last_seen; + _notify (peer, PROP_LAST_SEEN); + return TRUE; + } + return FALSE; +} + + +/*****************************************************************************/ + +gboolean +nm_wifi_p2p_peer_update_from_properties (NMWifiP2PPeer *peer, + const char *supplicant_path, + GVariant *properties) +{ + NMWifiP2PPeerPrivate *priv; + const guint8 *bytes; + GVariant *v; + gsize len; + const char *s; + const char **sv; + gint32 i32; + gboolean changed = FALSE; + + g_return_val_if_fail (NM_IS_WIFI_P2P_PEER (peer), FALSE); + g_return_val_if_fail (properties, FALSE); + + priv = NM_WIFI_P2P_PEER_GET_PRIVATE (peer); + + g_object_freeze_notify (G_OBJECT (peer)); + + if (g_variant_lookup (properties, "level", "i", &i32)) + changed |= nm_wifi_p2p_peer_set_strength (peer, nm_wifi_utils_level_to_quality (i32)); + + if (g_variant_lookup (properties, "DeviceName", "&s", &s)) + changed |= nm_wifi_p2p_peer_set_name (peer, s); + + if (g_variant_lookup (properties, "Manufacturer", "&s", &s)) + changed |= nm_wifi_p2p_peer_set_manufacturer (peer, s); + + if (g_variant_lookup (properties, "Model", "&s", &s)) + changed |= nm_wifi_p2p_peer_set_model (peer, s); + + if (g_variant_lookup (properties, "ModelNumber", "&s", &s)) + changed |= nm_wifi_p2p_peer_set_model_number (peer, s); + + if (g_variant_lookup (properties, "Serial", "&s", &s)) + changed |= nm_wifi_p2p_peer_set_serial (peer, s); + + v = g_variant_lookup_value (properties, "DeviceAddress", G_VARIANT_TYPE_BYTESTRING); + if (v) { + bytes = g_variant_get_fixed_array (v, &len, 1); + if ( len == ETH_ALEN + && memcmp (bytes, nm_ip_addr_zero.addr_eth, ETH_ALEN) != 0 + && memcmp (bytes, (char[ETH_ALEN]) { 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF }, ETH_ALEN) != 0) + changed |= nm_wifi_p2p_peer_set_address_bin (peer, bytes); + g_variant_unref (v); + } + + /* The IEs property contains the WFD R1 subelements */ + v = g_variant_lookup_value (properties, "IEs", G_VARIANT_TYPE_BYTESTRING); + if (v) { + gs_unref_bytes GBytes *b = NULL; + + bytes = g_variant_get_fixed_array (v, &len, 1); + b = g_bytes_new (bytes, len); + changed |= nm_wifi_p2p_peer_set_wfd_ies (peer, b); + g_variant_unref (v); + } + + v = g_variant_lookup_value (properties, "Groups", G_VARIANT_TYPE_OBJECT_PATH_ARRAY); + if (v) { + sv = g_variant_get_objv (v, NULL); + changed |= nm_wifi_p2p_peer_set_groups (peer, sv); + g_free (sv); + } + + /*if (max_rate) + changed |= nm_wifi_p2p_peer_set_max_bitrate (peer, max_rate / 1000);*/ + + if (!priv->supplicant_path) { + priv->supplicant_path = g_strdup (supplicant_path); + changed = TRUE; + } + + changed |= nm_wifi_p2p_peer_set_last_seen (peer, nm_utils_get_monotonic_timestamp_s ()); + + g_object_thaw_notify (G_OBJECT (peer)); + + return changed; +} + +const char * +nm_wifi_p2p_peer_to_string (const NMWifiP2PPeer *self, + char *str_buf, + gsize buf_len, + gint32 now_s) +{ + const NMWifiP2PPeerPrivate *priv; + const char *supplicant_id = "-"; + const char* export_path; + + g_return_val_if_fail (NM_IS_WIFI_P2P_PEER (self), NULL); + + priv = NM_WIFI_P2P_PEER_GET_PRIVATE (self); + + if (priv->supplicant_path) + supplicant_id = strrchr (priv->supplicant_path, '/') ?: supplicant_id; + + export_path = nm_dbus_object_get_path (NM_DBUS_OBJECT (self)); + if (export_path) + export_path = strrchr (export_path, '/') ?: export_path; + else + export_path = "/"; + + g_snprintf (str_buf, buf_len, + "%17s [n:%s, m:%s, mod:%s, mod_num:%s, ser:%s] %3us sup:%s [nm:%s]", + priv->address ?: "(none)", + priv->name, + priv->manufacturer, + priv->model, + priv->model_number, + priv->serial, + priv->last_seen > 0 ? ((now_s > 0 ? now_s : nm_utils_get_monotonic_timestamp_s ()) - priv->last_seen) : -1, + supplicant_id, + export_path); + + return str_buf; +} + +gboolean +nm_wifi_p2p_peer_check_compatible (NMWifiP2PPeer *self, + NMConnection *connection) +{ + NMWifiP2PPeerPrivate *priv; + NMSettingWifiP2P *s_wifi_p2p; + const char *hwaddr; + + g_return_val_if_fail (NM_IS_WIFI_P2P_PEER (self), FALSE); + g_return_val_if_fail (NM_IS_CONNECTION (connection), FALSE); + + priv = NM_WIFI_P2P_PEER_GET_PRIVATE (self); + + s_wifi_p2p = NM_SETTING_WIFI_P2P (nm_connection_get_setting (connection, NM_TYPE_SETTING_WIFI_P2P)); + if (s_wifi_p2p == NULL) + return FALSE; + + hwaddr = nm_setting_wifi_p2p_get_peer (s_wifi_p2p); + if ( hwaddr + && ( !priv->address + || !nm_utils_hwaddr_matches (hwaddr, -1, priv->address, -1))) + return FALSE; + + return TRUE; +} + +/*****************************************************************************/ + +static void +get_property (GObject *object, guint prop_id, + GValue *value, GParamSpec *pspec) +{ + NMWifiP2PPeer *self = NM_WIFI_P2P_PEER (object); + NMWifiP2PPeerPrivate *priv = NM_WIFI_P2P_PEER_GET_PRIVATE (self); + + switch (prop_id) { + case PROP_FLAGS: + g_value_set_uint (value, priv->flags); + break; + case PROP_NAME: + g_value_set_string (value, priv->name); + break; + case PROP_MANUFACTURER: + g_value_set_string (value, priv->manufacturer); + break; + case PROP_MODEL: + g_value_set_string (value, priv->model); + break; + case PROP_MODEL_NUMBER: + g_value_set_string (value, priv->model_number); + break; + case PROP_SERIAL: + g_value_set_string (value, priv->serial); + break; + case PROP_WFD_IES: + g_value_take_variant (value, nm_utils_gbytes_to_variant_ay (priv->wfd_ies)); + break; + case PROP_GROUPS: + g_value_set_variant (value, + g_variant_new_strv ( (const char*const*) priv->groups + ?: NM_PTRARRAY_EMPTY (const char *), + -1)); + break; + case PROP_HW_ADDRESS: + g_value_set_string (value, priv->address); + break; + case PROP_STRENGTH: + g_value_set_uchar (value, priv->strength); + break; + case PROP_LAST_SEEN: + g_value_set_int (value, + priv->last_seen > 0 + ? (int) nm_utils_monotonic_timestamp_as_boottime (priv->last_seen, NM_UTILS_NS_PER_SECOND) + : -1); + break; + default: + G_OBJECT_WARN_INVALID_PROPERTY_ID (object, prop_id, pspec); + break; + } +} + +/*****************************************************************************/ + +static void +nm_wifi_p2p_peer_init (NMWifiP2PPeer *self) +{ + NMWifiP2PPeerPrivate *priv; + + priv = G_TYPE_INSTANCE_GET_PRIVATE (self, NM_TYPE_WIFI_P2P_PEER, NMWifiP2PPeerPrivate); + + self->_priv = priv; + + c_list_init (&self->peers_lst); + + priv->flags = NM_802_11_AP_FLAGS_NONE; + priv->last_seen = -1; +} + +NMWifiP2PPeer * +nm_wifi_p2p_peer_new_from_properties (const char *supplicant_path, GVariant *properties) +{ + NMWifiP2PPeer *peer; + + g_return_val_if_fail (supplicant_path != NULL, NULL); + g_return_val_if_fail (properties != NULL, NULL); + + peer = (NMWifiP2PPeer *) g_object_new (NM_TYPE_WIFI_P2P_PEER, NULL); + nm_wifi_p2p_peer_update_from_properties (peer, supplicant_path, properties); + + /* ignore peers with invalid or missing address */ + if (!nm_wifi_p2p_peer_get_address (peer)) { + g_object_unref (peer); + return NULL; + } + + return peer; +} + +static void +finalize (GObject *object) +{ + NMWifiP2PPeer *self = NM_WIFI_P2P_PEER (object); + NMWifiP2PPeerPrivate *priv = NM_WIFI_P2P_PEER_GET_PRIVATE (self); + + nm_assert (!self->wifi_device); + nm_assert (c_list_is_empty (&self->peers_lst)); + + g_free (priv->supplicant_path); + g_free (priv->name); + g_free (priv->manufacturer); + g_free (priv->model); + g_free (priv->model_number); + g_free (priv->serial); + g_free (priv->address); + g_bytes_unref (priv->wfd_ies); + g_strfreev (priv->groups); + + G_OBJECT_CLASS (nm_wifi_p2p_peer_parent_class)->finalize (object); +} + +static const NMDBusInterfaceInfoExtended interface_info_p2p_peer = { + .parent = NM_DEFINE_GDBUS_INTERFACE_INFO_INIT ( + NM_DBUS_INTERFACE_WIFI_P2P_PEER, + .properties = NM_DEFINE_GDBUS_PROPERTY_INFOS ( + NM_DEFINE_DBUS_PROPERTY_INFO_EXTENDED_READABLE ("Flags", "u", NM_WIFI_P2P_PEER_FLAGS), + NM_DEFINE_DBUS_PROPERTY_INFO_EXTENDED_READABLE ("Name", "s", NM_WIFI_P2P_PEER_NAME), + NM_DEFINE_DBUS_PROPERTY_INFO_EXTENDED_READABLE ("Manufacturer", "s", NM_WIFI_P2P_PEER_MANUFACTURER), + NM_DEFINE_DBUS_PROPERTY_INFO_EXTENDED_READABLE ("Model", "s", NM_WIFI_P2P_PEER_MODEL), + NM_DEFINE_DBUS_PROPERTY_INFO_EXTENDED_READABLE ("ModelNumber", "s", NM_WIFI_P2P_PEER_MODEL_NUMBER), + NM_DEFINE_DBUS_PROPERTY_INFO_EXTENDED_READABLE ("Serial", "s", NM_WIFI_P2P_PEER_SERIAL), + NM_DEFINE_DBUS_PROPERTY_INFO_EXTENDED_READABLE ("WfdIEs", "ay", NM_WIFI_P2P_PEER_WFD_IES), + NM_DEFINE_DBUS_PROPERTY_INFO_EXTENDED_READABLE ("Groups", "as", NM_WIFI_P2P_PEER_GROUPS), + NM_DEFINE_DBUS_PROPERTY_INFO_EXTENDED_READABLE ("HwAddress", "s", NM_WIFI_P2P_PEER_HW_ADDRESS), + NM_DEFINE_DBUS_PROPERTY_INFO_EXTENDED_READABLE ("Strength", "y", NM_WIFI_P2P_PEER_STRENGTH), + NM_DEFINE_DBUS_PROPERTY_INFO_EXTENDED_READABLE ("LastSeen", "i", NM_WIFI_P2P_PEER_LAST_SEEN), + ), + ), + .legacy_property_changed = FALSE, +}; + +static void +nm_wifi_p2p_peer_class_init (NMWifiP2PPeerClass *klass) +{ + GObjectClass *object_class = G_OBJECT_CLASS (klass); + NMDBusObjectClass *dbus_object_class = NM_DBUS_OBJECT_CLASS (klass); + + g_type_class_add_private (object_class, sizeof (NMWifiP2PPeerPrivate)); + + dbus_object_class->export_path = NM_DBUS_EXPORT_PATH_NUMBERED (NM_DBUS_PATH_WIFI_P2P_PEER); + dbus_object_class->interface_infos = NM_DBUS_INTERFACE_INFOS (&interface_info_p2p_peer); + + object_class->get_property = get_property; + object_class->finalize = finalize; + + obj_properties[PROP_FLAGS] = + g_param_spec_uint (NM_WIFI_P2P_PEER_FLAGS, "", "", + NM_802_11_AP_FLAGS_NONE, + NM_802_11_AP_FLAGS_PRIVACY, + NM_802_11_AP_FLAGS_NONE, + G_PARAM_READABLE | G_PARAM_STATIC_STRINGS); + + obj_properties[PROP_NAME] = + g_param_spec_string (NM_WIFI_P2P_PEER_NAME, "", "", + NULL, + G_PARAM_READABLE | G_PARAM_STATIC_STRINGS); + + obj_properties[PROP_MANUFACTURER] = + g_param_spec_string (NM_WIFI_P2P_PEER_MANUFACTURER, "", "", + NULL, + G_PARAM_READABLE | G_PARAM_STATIC_STRINGS); + + obj_properties[PROP_MODEL] = + g_param_spec_string (NM_WIFI_P2P_PEER_MODEL, "", "", + NULL, + G_PARAM_READABLE | G_PARAM_STATIC_STRINGS); + + obj_properties[PROP_MODEL_NUMBER] = + g_param_spec_string (NM_WIFI_P2P_PEER_MODEL_NUMBER, "", "", + NULL, + G_PARAM_READABLE | G_PARAM_STATIC_STRINGS); + + obj_properties[PROP_SERIAL] = + g_param_spec_string (NM_WIFI_P2P_PEER_SERIAL, "", "", + NULL, + G_PARAM_READABLE | G_PARAM_STATIC_STRINGS); + + obj_properties[PROP_WFD_IES] = + g_param_spec_variant (NM_WIFI_P2P_PEER_WFD_IES, "", "", + G_VARIANT_TYPE ("ay"), + NULL, + G_PARAM_READABLE | G_PARAM_STATIC_STRINGS); + + obj_properties[PROP_GROUPS] = + g_param_spec_variant (NM_WIFI_P2P_PEER_GROUPS, "", "", + G_VARIANT_TYPE ("as"), + NULL, + G_PARAM_READABLE | G_PARAM_STATIC_STRINGS); + + obj_properties[PROP_HW_ADDRESS] = + g_param_spec_string (NM_WIFI_P2P_PEER_HW_ADDRESS, "", "", + NULL, + G_PARAM_READABLE | G_PARAM_STATIC_STRINGS); + + obj_properties[PROP_STRENGTH] = + g_param_spec_uchar (NM_WIFI_P2P_PEER_STRENGTH, "", "", + 0, G_MAXINT8, 0, + G_PARAM_READABLE | G_PARAM_STATIC_STRINGS); + + obj_properties[PROP_LAST_SEEN] = + g_param_spec_int (NM_WIFI_P2P_PEER_LAST_SEEN, "", "", + -1, G_MAXINT, -1, + G_PARAM_READABLE | G_PARAM_STATIC_STRINGS); + + g_object_class_install_properties (object_class, _PROPERTY_ENUMS_LAST, obj_properties); +} diff --git a/src/devices/wifi/nm-wifi-p2p-peer.h b/src/devices/wifi/nm-wifi-p2p-peer.h new file mode 100644 index 00000000..d6ff7abc --- /dev/null +++ b/src/devices/wifi/nm-wifi-p2p-peer.h @@ -0,0 +1,114 @@ +/* NetworkManager -- Wi-Fi P2P Peer + * + * This library is free software; you can redistribute it and/or + * modify it under the terms of the GNU Lesser General Public + * License as published by the Free Software Foundation; either + * version 2 of the License, or (at your option) any later version. + * + * This library is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + * Lesser General Public License for more details. + * + * You should have received a copy of the GNU Lesser General Public + * License along with this library; if not, write to the + * Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor, + * Boston, MA 02110-1301 USA. + * + * Copyright (C) 2018 Red Hat, Inc. + */ + +#ifndef __NM_WIFI_P2P_PEER_H__ +#define __NM_WIFI_P2P_PEER_H__ + +#include "nm-dbus-object.h" +#include "nm-dbus-interface.h" +#include "nm-connection.h" + +#define NM_TYPE_WIFI_P2P_PEER (nm_wifi_p2p_peer_get_type ()) +#define NM_WIFI_P2P_PEER(obj) (G_TYPE_CHECK_INSTANCE_CAST ((obj), NM_TYPE_WIFI_P2P_PEER, NMWifiP2PPeer)) +#define NM_WIFI_P2P_PEER_CLASS(klass) (G_TYPE_CHECK_CLASS_CAST ((klass), NM_TYPE_WIFI_P2P_PEER, NMWifiP2PPeerClass)) +#define NM_IS_WIFI_P2P_PEER(obj) (G_TYPE_CHECK_INSTANCE_TYPE ((obj), NM_TYPE_WIFI_P2P_PEER)) +#define NM_IS_WIFI_P2P_PEER_CLASS(klass) (G_TYPE_CHECK_CLASS_TYPE ((klass), NM_TYPE_WIFI_P2P_PEER)) +#define NM_WIFI_P2P_PEER_GET_CLASS(obj) (G_TYPE_INSTANCE_GET_CLASS ((obj), NM_TYPE_WIFI_P2P_PEER, NMWifiP2PPeerClass)) + +#define NM_WIFI_P2P_PEER_FLAGS "flags" +#define NM_WIFI_P2P_PEER_NAME "name" +#define NM_WIFI_P2P_PEER_MANUFACTURER "manufacturer" +#define NM_WIFI_P2P_PEER_MODEL "model" +#define NM_WIFI_P2P_PEER_MODEL_NUMBER "model-number" +#define NM_WIFI_P2P_PEER_SERIAL "serial" +#define NM_WIFI_P2P_PEER_WFD_IES "wfd-ies" +#define NM_WIFI_P2P_PEER_GROUPS "groups" +#define NM_WIFI_P2P_PEER_HW_ADDRESS "hw-address" +#define NM_WIFI_P2P_PEER_STRENGTH "strength" +#define NM_WIFI_P2P_PEER_LAST_SEEN "last-seen" + +typedef struct { + NMDBusObject parent; + NMDevice *wifi_device; + CList peers_lst; + struct _NMWifiP2PPeerPrivate *_priv; +} NMWifiP2PPeer; + +typedef struct _NMWifiP2PPeerClass NMWifiP2PPeerClass; + +GType nm_wifi_p2p_peer_get_type (void); + +NMWifiP2PPeer * nm_wifi_p2p_peer_new_from_properties (const char *supplicant_path, + GVariant *properties); + +gboolean nm_wifi_p2p_peer_update_from_properties (NMWifiP2PPeer *peer, + const char *supplicant_path, + GVariant *properties); + +gboolean nm_wifi_p2p_peer_check_compatible (NMWifiP2PPeer *self, + NMConnection *connection); + +const char * nm_wifi_p2p_peer_get_supplicant_path (NMWifiP2PPeer *peer); + +const char * nm_wifi_p2p_peer_get_name (const NMWifiP2PPeer *peer); +gboolean nm_wifi_p2p_peer_set_name (NMWifiP2PPeer *peer, + const char *name); +const char * nm_wifi_p2p_peer_get_manufacturer (const NMWifiP2PPeer *peer); +gboolean nm_wifi_p2p_peer_set_manufacturer (NMWifiP2PPeer *peer, + const char *manufacturer); +const char * nm_wifi_p2p_peer_get_model (const NMWifiP2PPeer *peer); +gboolean nm_wifi_p2p_peer_set_model (NMWifiP2PPeer *peer, + const char *model); +const char * nm_wifi_p2p_peer_get_model_number (const NMWifiP2PPeer *peer); +gboolean nm_wifi_p2p_peer_set_model_number (NMWifiP2PPeer *peer, + const char *number); +const char * nm_wifi_p2p_peer_get_serial (const NMWifiP2PPeer *peer); +gboolean nm_wifi_p2p_peer_set_serial (NMWifiP2PPeer *peer, + const char *serial); + +GBytes * nm_wifi_p2p_peer_get_wfd_ies (const NMWifiP2PPeer *peer); +gboolean nm_wifi_p2p_peer_set_wfd_ies (NMWifiP2PPeer *peer, + GBytes *bytes); + +const char *const*nm_wifi_p2p_peer_get_groups (const NMWifiP2PPeer *peer); + +const char * nm_wifi_p2p_peer_get_address (const NMWifiP2PPeer *peer); +gboolean nm_wifi_p2p_peer_set_address (NMWifiP2PPeer *peer, + const char *addr); +gint8 nm_wifi_p2p_peer_get_strength (NMWifiP2PPeer *peer); +gboolean nm_wifi_p2p_peer_set_strength (NMWifiP2PPeer *peer, + gint8 strength); +NM80211ApFlags nm_wifi_p2p_peer_get_flags (const NMWifiP2PPeer *self); + +const char *nm_wifi_p2p_peer_to_string (const NMWifiP2PPeer *self, + char *str_buf, + gsize buf_len, + gint32 now_s); + +const char **nm_wifi_p2p_peers_get_paths (const CList *peers_lst_head); + +NMWifiP2PPeer *nm_wifi_p2p_peers_find_first_compatible (const CList *peers_lst_head, + NMConnection *connection); + +NMWifiP2PPeer *nm_wifi_p2p_peers_find_by_supplicant_path (const CList *peers_lst_head, const char *path); + +NMWifiP2PPeer *nm_wifi_p2p_peer_lookup_for_device (NMDevice *device, const char *exported_path); + +#endif /* __NM_WIFI_P2P_PEER_H__ */ diff --git a/src/devices/wifi/nm-wifi-utils.c b/src/devices/wifi/nm-wifi-utils.c index 0f7836be..c6e8b3e0 100644 --- a/src/devices/wifi/nm-wifi-utils.c +++ b/src/devices/wifi/nm-wifi-utils.c @@ -22,7 +22,6 @@ #include "nm-wifi-utils.h" -#include <string.h> #include <stdlib.h> #include "nm-utils.h" @@ -739,6 +738,12 @@ nm_wifi_utils_complete_connection (GBytes *ap_ssid, * setting. Since there's so much configuration required for it, there's * no way it can be automatically completed. */ + } else if ( (key_mgmt && !strcmp (key_mgmt, "sae")) + || (ap_rsn_flags & NM_802_11_AP_SEC_KEY_MGMT_SAE)) { + g_object_set (s_wsec, + NM_SETTING_WIRELESS_SECURITY_KEY_MGMT, "sae", + NM_SETTING_WIRELESS_SECURITY_AUTH_ALG, "open", + NULL); } else if ( (key_mgmt && !strcmp (key_mgmt, "wpa-psk")) || (ap_wpa_flags & NM_802_11_AP_SEC_KEY_MGMT_PSK) || (ap_rsn_flags & NM_802_11_AP_SEC_KEY_MGMT_PSK)) { diff --git a/src/devices/wifi/tests/meson.build b/src/devices/wifi/tests/meson.build index ee60f349..895853c4 100644 --- a/src/devices/wifi/tests/meson.build +++ b/src/devices/wifi/tests/meson.build @@ -10,4 +10,5 @@ test( 'devices/wifi/' + test_unit, test_script, args: test_args + [exe.full_path()], + timeout: default_test_timeout, ) diff --git a/src/devices/wifi/tests/test-general.c b/src/devices/wifi/tests/test-general.c index f752bbfc..e0899837 100644 --- a/src/devices/wifi/tests/test-general.c +++ b/src/devices/wifi/tests/test-general.c @@ -20,10 +20,7 @@ #include "nm-default.h" -#include <string.h> - #include "devices/wifi/nm-wifi-utils.h" - #include "nm-core-internal.h" #include "nm-test-utils-core.h" diff --git a/src/devices/wwan/nm-device-modem.c b/src/devices/wwan/nm-device-modem.c index bd9ee3bb..1e316280 100644 --- a/src/devices/wwan/nm-device-modem.c +++ b/src/devices/wwan/nm-device-modem.c @@ -22,9 +22,8 @@ #include "nm-device-modem.h" -#include <string.h> - #include "nm-modem.h" +#include "nm-ip4-config.h" #include "devices/nm-device-private.h" #include "nm-rfkill-manager.h" #include "settings/nm-settings-connection.h" @@ -85,9 +84,9 @@ ppp_failed (NMModem *modem, case NM_DEVICE_STATE_SECONDARIES: case NM_DEVICE_STATE_ACTIVATED: if (nm_device_activate_ip4_state_in_conf (device)) - nm_device_activate_schedule_ip4_config_timeout (device); + nm_device_activate_schedule_ip_config_timeout (device, AF_INET); else if (nm_device_activate_ip6_state_in_conf (device)) - nm_device_activate_schedule_ip6_config_timeout (device); + nm_device_activate_schedule_ip_config_timeout (device, AF_INET6); else if (nm_device_activate_ip4_state_done (device)) { nm_device_ip_method_failed (device, AF_INET, @@ -213,8 +212,8 @@ modem_ip4_config_result (NMModem *modem, AF_INET, NM_DEVICE_STATE_REASON_IP_CONFIG_UNAVAILABLE); } else { - nm_device_set_wwan_ip4_config (device, config); - nm_device_activate_schedule_ip4_config_result (device, NULL); + nm_device_set_dev2_ip_config (device, AF_INET, NM_IP_CONFIG_CAST (config)); + nm_device_activate_schedule_ip_config_result (device, AF_INET, NULL); } } @@ -229,7 +228,7 @@ modem_ip6_config_result (NMModem *modem, NMDevice *device = NM_DEVICE (self); NMActStageReturn ret; NMDeviceStateReason failure_reason = NM_DEVICE_STATE_REASON_NONE; - NMIP6Config *ignored = NULL; + gs_unref_object NMIP6Config *ignored = NULL; gboolean got_config = !!config; g_return_if_fail (nm_device_activate_ip6_state_in_conf (device) == TRUE); @@ -247,11 +246,11 @@ modem_ip6_config_result (NMModem *modem, nm_device_sysctl_ip_conf_set (device, AF_INET6, "disable_ipv6", "0"); if (config) - nm_device_set_wwan_ip6_config (device, config); + nm_device_set_dev2_ip_config (device, AF_INET6, NM_IP_CONFIG_CAST (config)); if (do_slaac == FALSE) { if (got_config) - nm_device_activate_schedule_ip6_config_result (device); + nm_device_activate_schedule_ip_config_result (device, AF_INET6, NULL); else { _LOGW (LOGD_MB | LOGD_IP6, "retrieving IPv6 configuration failed: SLAAC not requested and no addresses"); nm_device_ip_method_failed (device, @@ -262,15 +261,17 @@ modem_ip6_config_result (NMModem *modem, } /* Start SLAAC now that we have a link-local address from the modem */ - ret = NM_DEVICE_CLASS (nm_device_modem_parent_class)->act_stage3_ip6_config_start (device, &ignored, &failure_reason); - g_assert (ignored == NULL); + ret = NM_DEVICE_CLASS (nm_device_modem_parent_class)->act_stage3_ip_config_start (device, AF_INET6, (gpointer *) &ignored, &failure_reason); + + nm_assert (ignored == NULL); + switch (ret) { case NM_ACT_STAGE_RETURN_FAILURE: nm_device_ip_method_failed (device, AF_INET6, failure_reason); break; case NM_ACT_STAGE_RETURN_IP_FAIL: /* all done */ - nm_device_activate_schedule_ip6_config_result (device); + nm_device_activate_schedule_ip_config_result (device, AF_INET6, NULL); break; case NM_ACT_STAGE_RETURN_POSTPONE: /* let SLAAC run */ @@ -279,7 +280,7 @@ modem_ip6_config_result (NMModem *modem, /* Should never get here since we've assured that the IPv6 method * will either be "auto" or "ignored" when starting IPv6 configuration. */ - g_assert_not_reached (); + nm_assert_not_reached (); } } @@ -570,14 +571,25 @@ act_stage2_config (NMDevice *device, NMDeviceStateReason *out_failure_reason) } static NMActStageReturn -act_stage3_ip4_config_start (NMDevice *device, - NMIP4Config **out_config, - NMDeviceStateReason *out_failure_reason) +act_stage3_ip_config_start (NMDevice *device, + int addr_family, + gpointer *out_config, + NMDeviceStateReason *out_failure_reason) { - return nm_modem_stage3_ip4_config_start (NM_DEVICE_MODEM_GET_PRIVATE ((NMDeviceModem *) device)->modem, - device, - NM_DEVICE_CLASS (nm_device_modem_parent_class), - out_failure_reason); + NMDeviceModemPrivate *priv = NM_DEVICE_MODEM_GET_PRIVATE (device); + + nm_assert_addr_family (addr_family); + + if (addr_family == AF_INET) { + return nm_modem_stage3_ip4_config_start (priv->modem, + device, + NM_DEVICE_CLASS (nm_device_modem_parent_class), + out_failure_reason); + } else { + return nm_modem_stage3_ip6_config_start (priv->modem, + device, + out_failure_reason); + } } static void @@ -586,16 +598,6 @@ ip4_config_pre_commit (NMDevice *device, NMIP4Config *config) nm_modem_ip4_pre_commit (NM_DEVICE_MODEM_GET_PRIVATE ((NMDeviceModem *) device)->modem, device, config); } -static NMActStageReturn -act_stage3_ip6_config_start (NMDevice *device, - NMIP6Config **out_config, - NMDeviceStateReason *out_failure_reason) -{ - return nm_modem_stage3_ip6_config_start (NM_DEVICE_MODEM_GET_PRIVATE ((NMDeviceModem *) device)->modem, - device, - out_failure_reason); -} - static gboolean get_ip_iface_identifier (NMDevice *device, NMUtilsIPv6IfaceId *out_iid) { @@ -825,8 +827,7 @@ nm_device_modem_class_init (NMDeviceModemClass *klass) device_class->deactivate = deactivate; device_class->act_stage1_prepare = act_stage1_prepare; device_class->act_stage2_config = act_stage2_config; - device_class->act_stage3_ip4_config_start = act_stage3_ip4_config_start; - device_class->act_stage3_ip6_config_start = act_stage3_ip6_config_start; + device_class->act_stage3_ip_config_start = act_stage3_ip_config_start; device_class->ip4_config_pre_commit = ip4_config_pre_commit; device_class->get_enabled = get_enabled; device_class->set_enabled = set_enabled; diff --git a/src/devices/wwan/nm-modem-broadband.c b/src/devices/wwan/nm-modem-broadband.c index 82e9e2f1..1cb549b0 100644 --- a/src/devices/wwan/nm-modem-broadband.c +++ b/src/devices/wwan/nm-modem-broadband.c @@ -22,7 +22,6 @@ #include "nm-modem-broadband.h" -#include <string.h> #include <arpa/inet.h> #include <libmm-glib.h> @@ -254,16 +253,21 @@ get_bearer_ip_method (MMBearerIpConfig *config) static MMSimpleConnectProperties * create_cdma_connect_properties (NMConnection *connection) { - NMSettingCdma *setting; MMSimpleConnectProperties *properties; - const char *str; - setting = nm_connection_get_setting_cdma (connection); properties = mm_simple_connect_properties_new (); - str = nm_setting_cdma_get_number (setting); - if (str) - mm_simple_connect_properties_set_number (properties, str); +#if !MM_CHECK_VERSION (1, 9, 1) + { + NMSettingCdma *setting; + const char *str; + + setting = nm_connection_get_setting_cdma (connection); + str = nm_setting_cdma_get_number (setting); + if (str) + mm_simple_connect_properties_set_number (properties, str); + } +#endif return properties; } diff --git a/src/devices/wwan/nm-modem-manager.c b/src/devices/wwan/nm-modem-manager.c index dfc102f3..fac14d69 100644 --- a/src/devices/wwan/nm-modem-manager.c +++ b/src/devices/wwan/nm-modem-manager.c @@ -24,7 +24,6 @@ #include "nm-modem-manager.h" -#include <string.h> #include <libmm-glib.h> #if HAVE_LIBSYSTEMD diff --git a/src/devices/wwan/nm-modem-ofono.c b/src/devices/wwan/nm-modem-ofono.c index 8efe0253..78d9a9f0 100644 --- a/src/devices/wwan/nm-modem-ofono.c +++ b/src/devices/wwan/nm-modem-ofono.c @@ -22,8 +22,6 @@ #include "nm-modem-ofono.h" -#include <string.h> - #include "nm-core-internal.h" #include "devices/nm-device-private.h" #include "nm-modem.h" @@ -214,7 +212,6 @@ disconnect (NMModem *modem, NMModemOfonoPrivate *priv = NM_MODEM_OFONO_GET_PRIVATE (self); DisconnectContext *ctx; NMModemState state = nm_modem_get_state (NM_MODEM (self)); - gs_free_error GError *error = NULL; _LOGD ("warn: %s modem_state: %s", warn ? "TRUE" : "FALSE", @@ -654,7 +651,7 @@ handle_connman_iface (NMModemOfono *self, gboolean found) OFONO_DBUS_INTERFACE_CONNECTION_MANAGER, priv->connman_proxy_cancellable, _connman_proxy_new_cb, - NULL); + self); } } diff --git a/src/devices/wwan/nm-modem.c b/src/devices/wwan/nm-modem.c index 11ada549..2217f2a2 100644 --- a/src/devices/wwan/nm-modem.c +++ b/src/devices/wwan/nm-modem.c @@ -24,7 +24,6 @@ #include "nm-modem.h" #include <fcntl.h> -#include <string.h> #include <termios.h> #include <linux/rtnetlink.h> @@ -729,7 +728,7 @@ nm_modem_stage3_ip4_config_start (NMModem *self, break; case NM_MODEM_IP_METHOD_AUTO: _LOGD ("MODEM_IP_METHOD_AUTO"); - ret = device_class->act_stage3_ip4_config_start (device, NULL, out_failure_reason); + ret = device_class->act_stage3_ip_config_start (device, AF_INET, NULL, out_failure_reason); break; default: _LOGI ("IPv4 configuration disabled"); @@ -948,7 +947,7 @@ nm_modem_get_secrets (NMModem *self, FALSE, setting_name, flags, - hint, + NM_MAKE_STRV (hint), modem_secrets_cb, self); g_return_if_fail (priv->secrets_id); @@ -986,8 +985,7 @@ nm_modem_act_stage1_prepare (NMModem *self, setting_name = nm_connection_need_secrets (connection, &hints); if (!setting_name) { - /* Ready to connect */ - g_assert (!hints); + nm_assert (!hints); return NM_MODEM_GET_CLASS (self)->act_stage1_prepare (self, connection, out_failure_reason); } @@ -995,11 +993,14 @@ nm_modem_act_stage1_prepare (NMModem *self, if (priv->secrets_tries++) flags |= NM_SECRET_AGENT_GET_SECRETS_FLAG_REQUEST_NEW; + if (hints) + g_ptr_array_add (hints, NULL); + priv->secrets_id = nm_act_request_get_secrets (req, FALSE, setting_name, flags, - hints ? g_ptr_array_index (hints, 0) : NULL, + hints ? (const char *const*) hints->pdata : NULL, modem_secrets_cb, self); g_return_val_if_fail (priv->secrets_id, NM_ACT_STAGE_RETURN_FAILURE); diff --git a/src/devices/wwan/nm-wwan-factory.c b/src/devices/wwan/nm-wwan-factory.c index a561b58a..c9ee27ff 100644 --- a/src/devices/wwan/nm-wwan-factory.c +++ b/src/devices/wwan/nm-wwan-factory.c @@ -20,7 +20,6 @@ #include "nm-default.h" -#include <string.h> #include <gmodule.h> #include "devices/nm-device-factory.h" diff --git a/src/dhcp/nm-dhcp-client.c b/src/dhcp/nm-dhcp-client.c index 7ed7a686..a4fccce0 100644 --- a/src/dhcp/nm-dhcp-client.c +++ b/src/dhcp/nm-dhcp-client.c @@ -21,10 +21,8 @@ #include "nm-dhcp-client.h" -#include <string.h> #include <sys/types.h> #include <sys/wait.h> -#include <errno.h> #include <unistd.h> #include <stdio.h> #include <stdlib.h> @@ -627,7 +625,7 @@ out: int errsv = errno; nm_log_dbg (LOGD_DHCP, "dhcp: could not remove pid file \"%s\": %s (%d)", - pid_file, g_strerror (errsv), errsv); + pid_file, nm_strerror_native (errsv), errsv); } } diff --git a/src/dhcp/nm-dhcp-dhclient-utils.c b/src/dhcp/nm-dhcp-dhclient-utils.c index d6da3f5c..cbd706fa 100644 --- a/src/dhcp/nm-dhcp-dhclient-utils.c +++ b/src/dhcp/nm-dhcp-dhclient-utils.c @@ -21,7 +21,6 @@ #include "nm-dhcp-dhclient-utils.h" -#include <string.h> #include <ctype.h> #include <arpa/inet.h> #include <net/if.h> @@ -495,7 +494,7 @@ nm_dhcp_dhclient_escape_duid (GBytes *duid) return escaped; } -static inline gboolean +static gboolean isoctal (const guint8 *p) { return ( p[0] >= '0' && p[0] <= '3' diff --git a/src/dhcp/nm-dhcp-dhclient.c b/src/dhcp/nm-dhcp-dhclient.c index 0146c8b4..af702cb4 100644 --- a/src/dhcp/nm-dhcp-dhclient.c +++ b/src/dhcp/nm-dhcp-dhclient.c @@ -29,9 +29,7 @@ #if WITH_DHCLIENT -#include <string.h> #include <stdlib.h> -#include <errno.h> #include <unistd.h> #include <stdio.h> #include <netinet/in.h> @@ -593,17 +591,19 @@ stop (NMDhcpClient *client, gboolean release) { NMDhcpDhclient *self = NM_DHCP_DHCLIENT (client); NMDhcpDhclientPrivate *priv = NM_DHCP_DHCLIENT_GET_PRIVATE (self); + int errsv; NM_DHCP_CLIENT_CLASS (nm_dhcp_dhclient_parent_class)->stop (client, release); if (priv->conf_file) - if (remove (priv->conf_file) == -1) - _LOGD ("could not remove dhcp config file \"%s\": %d (%s)", priv->conf_file, errno, g_strerror (errno)); + if (remove (priv->conf_file) == -1) { + errsv = errno; + _LOGD ("could not remove dhcp config file \"%s\": %d (%s)", priv->conf_file, errsv, nm_strerror_native (errsv)); + } if (priv->pid_file) { if (remove (priv->pid_file) == -1) { - int errsv = errno; - - _LOGD ("could not remove dhcp pid file \"%s\": %s (%d)", priv->pid_file, g_strerror (errsv), errsv); + errsv = errno; + _LOGD ("could not remove dhcp pid file \"%s\": %s (%d)", priv->pid_file, nm_strerror_native (errsv), errsv); } nm_clear_g_free (&priv->pid_file); } diff --git a/src/dhcp/nm-dhcp-dhcpcanon.c b/src/dhcp/nm-dhcp-dhcpcanon.c index 0f033e22..868cc9dd 100644 --- a/src/dhcp/nm-dhcp-dhcpcanon.c +++ b/src/dhcp/nm-dhcp-dhcpcanon.c @@ -22,9 +22,7 @@ #if WITH_DHCPCANON -#include <string.h> #include <stdlib.h> -#include <errno.h> #include <unistd.h> #include "nm-utils.h" @@ -205,12 +203,15 @@ stop (NMDhcpClient *client, gboolean release) { NMDhcpDhcpcanon *self = NM_DHCP_DHCPCANON (client); NMDhcpDhcpcanonPrivate *priv = NM_DHCP_DHCPCANON_GET_PRIVATE (self); + int errsv; NM_DHCP_CLIENT_CLASS (nm_dhcp_dhcpcanon_parent_class)->stop (client, release); if (priv->pid_file) { - if (remove (priv->pid_file) == -1) - _LOGD ("could not remove dhcp pid file \"%s\": %d (%s)", priv->pid_file, errno, g_strerror (errno)); + if (remove (priv->pid_file) == -1) { + errsv = errno; + _LOGD ("could not remove dhcp pid file \"%s\": %d (%s)", priv->pid_file, errsv, nm_strerror_native (errsv)); + } g_free (priv->pid_file); priv->pid_file = NULL; } diff --git a/src/dhcp/nm-dhcp-dhcpcd.c b/src/dhcp/nm-dhcp-dhcpcd.c index e2a1354f..2a7482b1 100644 --- a/src/dhcp/nm-dhcp-dhcpcd.c +++ b/src/dhcp/nm-dhcp-dhcpcd.c @@ -24,9 +24,7 @@ #if WITH_DHCPCD -#include <string.h> #include <stdlib.h> -#include <errno.h> #include <unistd.h> #include <stdio.h> #include <netinet/in.h> @@ -199,12 +197,15 @@ stop (NMDhcpClient *client, gboolean release) { NMDhcpDhcpcd *self = NM_DHCP_DHCPCD (client); NMDhcpDhcpcdPrivate *priv = NM_DHCP_DHCPCD_GET_PRIVATE (self); + int errsv; NM_DHCP_CLIENT_CLASS (nm_dhcp_dhcpcd_parent_class)->stop (client, release); if (priv->pid_file) { - if (remove (priv->pid_file) == -1) - _LOGD ("could not remove dhcp pid file \"%s\": %d (%s)", priv->pid_file, errno, g_strerror (errno)); + if (remove (priv->pid_file) == -1) { + errsv = errno; + _LOGD ("could not remove dhcp pid file \"%s\": %d (%s)", priv->pid_file, errsv, nm_strerror_native (errsv)); + } } /* FIXME: implement release... */ diff --git a/src/dhcp/nm-dhcp-helper.c b/src/dhcp/nm-dhcp-helper.c index 83cc4600..8f753a61 100644 --- a/src/dhcp/nm-dhcp-helper.c +++ b/src/dhcp/nm-dhcp-helper.c @@ -22,7 +22,6 @@ #include <unistd.h> #include <stdlib.h> -#include <string.h> #include <signal.h> #include "nm-utils/nm-vpn-plugin-macros.h" diff --git a/src/dhcp/nm-dhcp-listener.c b/src/dhcp/nm-dhcp-listener.c index 1770ead3..049c4e55 100644 --- a/src/dhcp/nm-dhcp-listener.c +++ b/src/dhcp/nm-dhcp-listener.c @@ -24,9 +24,7 @@ #include <sys/socket.h> #include <sys/wait.h> #include <signal.h> -#include <string.h> #include <stdlib.h> -#include <errno.h> #include <unistd.h> #include "nm-dhcp-helper-api.h" diff --git a/src/dhcp/nm-dhcp-manager.c b/src/dhcp/nm-dhcp-manager.c index c13c3043..7063c82c 100644 --- a/src/dhcp/nm-dhcp-manager.c +++ b/src/dhcp/nm-dhcp-manager.c @@ -27,9 +27,7 @@ #include <sys/socket.h> #include <sys/wait.h> #include <signal.h> -#include <string.h> #include <stdlib.h> -#include <errno.h> #include <unistd.h> #include <fcntl.h> #include <stdio.h> diff --git a/src/dhcp/nm-dhcp-systemd.c b/src/dhcp/nm-dhcp-systemd.c index bcbe916f..70ed8715 100644 --- a/src/dhcp/nm-dhcp-systemd.c +++ b/src/dhcp/nm-dhcp-systemd.c @@ -18,9 +18,7 @@ #include "nm-default.h" -#include <string.h> #include <stdlib.h> -#include <errno.h> #include <unistd.h> #include <stdio.h> #include <netinet/in.h> @@ -269,28 +267,35 @@ lease_to_ip4_config (NMDedupMultiIndex *multi_idx, gint64 ts_time = time (NULL); struct in_addr a_address; struct in_addr a_netmask; - struct in_addr a_router; + const struct in_addr *a_router; guint32 a_plen; guint32 a_lifetime; g_return_val_if_fail (lease != NULL, NULL); - ip4_config = nm_ip4_config_new (multi_idx, ifindex); - - options = out_options ? create_options_dict () : NULL; - if (sd_dhcp_lease_get_address (lease, &a_address) < 0) { nm_utils_error_set_literal (error, NM_UTILS_ERROR_UNKNOWN, "could not get address from lease"); return NULL; } - nm_utils_inet4_ntop (a_address.s_addr, addr_str); - LOG_LEASE (LOGD_DHCP4, "address %s", addr_str); - add_option (options, dhcp4_requests, DHCP_OPTION_IP_ADDRESS, addr_str); if (sd_dhcp_lease_get_netmask (lease, &a_netmask) < 0) { nm_utils_error_set_literal (error, NM_UTILS_ERROR_UNKNOWN, "could not get netmask from lease"); return NULL; } + + if (sd_dhcp_lease_get_lifetime (lease, &a_lifetime) < 0) { + nm_utils_error_set_literal (error, NM_UTILS_ERROR_UNKNOWN, "could not get lifetime from lease"); + return NULL; + } + + ip4_config = nm_ip4_config_new (multi_idx, ifindex); + + options = out_options ? create_options_dict () : NULL; + + nm_utils_inet4_ntop (a_address.s_addr, addr_str); + LOG_LEASE (LOGD_DHCP4, "address %s", addr_str); + add_option (options, dhcp4_requests, DHCP_OPTION_IP_ADDRESS, addr_str); + a_plen = nm_utils_ip4_netmask_to_prefix (a_netmask.s_addr); LOG_LEASE (LOGD_DHCP4, "plen %u", (guint) a_plen); add_option (options, @@ -298,10 +303,6 @@ lease_to_ip4_config (NMDedupMultiIndex *multi_idx, SD_DHCP_OPTION_SUBNET_MASK, nm_utils_inet4_ntop (a_netmask.s_addr, addr_str)); - if (sd_dhcp_lease_get_lifetime (lease, &a_lifetime) < 0) { - nm_utils_error_set_literal (error, NM_UTILS_ERROR_UNKNOWN, "could not get lifetime from lease"); - return NULL; - } LOG_LEASE (LOGD_DHCP4, "expires in %u seconds (at %lld)", (guint) a_lifetime, (long long) (ts_time + a_lifetime)); @@ -325,41 +326,44 @@ lease_to_ip4_config (NMDedupMultiIndex *multi_idx, if (num > 0) { nm_gstring_prepare (&str); for (i = 0; i < num; i++) { - if (addr_list[i].s_addr) { - nm_ip4_config_add_nameserver (ip4_config, addr_list[i].s_addr); - s = nm_utils_inet4_ntop (addr_list[i].s_addr, addr_str); - LOG_LEASE (LOGD_DHCP4, "nameserver '%s'", s); - g_string_append_printf (str, "%s%s", str->len ? " " : "", s); + nm_utils_inet4_ntop (addr_list[i].s_addr, addr_str); + g_string_append (nm_gstring_add_space_delimiter (str), addr_str); + + if ( addr_list[i].s_addr == 0 + || nm_ip4_addr_is_localhost (addr_list[i].s_addr)) { + /* Skip localhost addresses, like also networkd does. + * See https://github.com/systemd/systemd/issues/4524. */ + continue; } + nm_ip4_config_add_nameserver (ip4_config, addr_list[i].s_addr); } - if (str->len) - add_option (options, dhcp4_requests, SD_DHCP_OPTION_DOMAIN_NAME_SERVER, str->str); + LOG_LEASE (LOGD_DHCP4, "nameserver '%s'", str->str); + add_option (options, dhcp4_requests, SD_DHCP_OPTION_DOMAIN_NAME_SERVER, str->str); } num = sd_dhcp_lease_get_search_domains (lease, (char ***) &search_domains); if (num > 0) { nm_gstring_prepare (&str); for (i = 0; i < num; i++) { + g_string_append (nm_gstring_add_space_delimiter (str), search_domains[i]); nm_ip4_config_add_search (ip4_config, search_domains[i]); - g_string_append_printf (str, "%s%s", str->len ? " " : "", search_domains[i]); - LOG_LEASE (LOGD_DHCP4, "domain search '%s'", search_domains[i]); } + LOG_LEASE (LOGD_DHCP4, "domain search '%s'", str->str); add_option (options, dhcp4_requests, SD_DHCP_OPTION_DOMAIN_SEARCH_LIST, str->str); } - if ( sd_dhcp_lease_get_domainname (lease, &s) >= 0 - && s) { + if (sd_dhcp_lease_get_domainname (lease, &s) >= 0) { gs_strfreev char **domains = NULL; char **d; + LOG_LEASE (LOGD_DHCP4, "domain name '%s'", s); + add_option (options, dhcp4_requests, SD_DHCP_OPTION_DOMAIN_NAME, s); + /* Multiple domains sometimes stuffed into option 15 "Domain Name". * As systemd escapes such characters, split them at \\032. */ domains = g_strsplit (s, "\\032", 0); - for (d = domains; *d; d++) { - LOG_LEASE (LOGD_DHCP4, "domain name '%s'", *d); + for (d = domains; *d; d++) nm_ip4_config_add_domain (ip4_config, *d); - } - add_option (options, dhcp4_requests, SD_DHCP_OPTION_DOMAIN_NAME, s); } if (sd_dhcp_lease_get_hostname (lease, &s) >= 0) { @@ -479,45 +483,66 @@ lease_to_ip4_config (NMDedupMultiIndex *multi_idx, add_option (options, dhcp4_requests, SD_DHCP_OPTION_STATIC_ROUTE, str_static->str); } - /* FIXME: internal client only supports returing the first router. */ - if (sd_dhcp_lease_get_router (lease, &a_router) >= 0) { - s = nm_utils_inet4_ntop (a_router.s_addr, addr_str); - LOG_LEASE (LOGD_DHCP4, "gateway %s", s); - add_option (options, dhcp4_requests, SD_DHCP_OPTION_ROUTER, s); - - /* If the DHCP server returns both a Classless Static Routes option and a - * Router option, the DHCP client MUST ignore the Router option [RFC 3442]. - * - * Be more lenient and ignore the Router option only if Classless Static - * Routes contain a default gateway (as other DHCP backends do). - */ - if (!has_router_from_classless) { + num = sd_dhcp_lease_get_router (lease, &a_router); + if (num > 0) { + guint32 default_route_metric = route_metric; + + nm_gstring_prepare (&str); + for (i = 0; i < num; i++) { + guint32 m; + + s = nm_utils_inet4_ntop (a_router[i].s_addr, addr_str); + g_string_append (nm_gstring_add_space_delimiter (str), s); + + if (a_router[i].s_addr == 0) { + /* silently skip 0.0.0.0 */ + continue; + } + + if (has_router_from_classless) { + /* If the DHCP server returns both a Classless Static Routes option and a + * Router option, the DHCP client MUST ignore the Router option [RFC 3442]. + * + * Be more lenient and ignore the Router option only if Classless Static + * Routes contain a default gateway (as other DHCP backends do). + */ + continue; + } + + /* if there are multiple default routes, we add them with differing + * metrics. */ + m = default_route_metric; + if (default_route_metric < G_MAXUINT32) + default_route_metric++; + nm_ip4_config_add_route (ip4_config, &((const NMPlatformIP4Route) { .rt_source = NM_IP_CONFIG_SOURCE_DHCP, - .gateway = a_router.s_addr, + .gateway = a_router[i].s_addr, .table_coerced = nm_platform_route_table_coerce (route_table), - .metric = route_metric, + .metric = m, }), NULL); } + LOG_LEASE (LOGD_DHCP4, "router %s", str->str); + add_option (options, dhcp4_requests, SD_DHCP_OPTION_ROUTER, str->str); } if ( sd_dhcp_lease_get_mtu (lease, &mtu) >= 0 && mtu) { - nm_ip4_config_set_mtu (ip4_config, mtu, NM_IP_CONFIG_SOURCE_DHCP); - add_option_u64 (options, dhcp4_requests, SD_DHCP_OPTION_INTERFACE_MTU, mtu); LOG_LEASE (LOGD_DHCP4, "mtu %u", mtu); + add_option_u64 (options, dhcp4_requests, SD_DHCP_OPTION_INTERFACE_MTU, mtu); + nm_ip4_config_set_mtu (ip4_config, mtu, NM_IP_CONFIG_SOURCE_DHCP); } num = sd_dhcp_lease_get_ntp (lease, &addr_list); if (num > 0) { nm_gstring_prepare (&str); for (i = 0; i < num; i++) { - s = nm_utils_inet4_ntop (addr_list[i].s_addr, addr_str); - LOG_LEASE (LOGD_DHCP4, "ntp server '%s'", s); - g_string_append_printf (str, "%s%s", str->len ? " " : "", s); + nm_utils_inet4_ntop (addr_list[i].s_addr, addr_str); + g_string_append (nm_gstring_add_space_delimiter (str), addr_str); } + LOG_LEASE (LOGD_DHCP4, "ntp server '%s'", str->str); add_option (options, dhcp4_requests, SD_DHCP_OPTION_NTP_SERVER, str->str); } @@ -826,6 +851,7 @@ lease_to_ip6_config (NMDedupMultiIndex *multi_idx, sd_dhcp6_lease_reset_address_iter (lease); nm_gstring_prepare (&str); while (sd_dhcp6_lease_get_address (lease, &tmp_addr, &lft_pref, &lft_valid) >= 0) { + char sbuf[400]; const NMPlatformIP6Address address = { .plen = 128, .address = tmp_addr, @@ -838,15 +864,12 @@ lease_to_ip6_config (NMDedupMultiIndex *multi_idx, nm_ip6_config_add_address (ip6_config, &address); nm_utils_inet6_ntop (&tmp_addr, addr_str); - if (str->len) - g_string_append_c (str, ' '); - g_string_append (str, addr_str); + g_string_append (nm_gstring_add_space_delimiter (str), addr_str); LOG_LEASE (LOGD_DHCP6, "address %s", - nm_platform_ip6_address_to_string (&address, NULL, 0)); + nm_platform_ip6_address_to_string (&address, sbuf, sizeof (sbuf))); }; - if (str->len) add_option (options, dhcp6_requests, DHCP6_OPTION_IP_ADDRESS, str->str); @@ -863,13 +886,11 @@ lease_to_ip6_config (NMDedupMultiIndex *multi_idx, if (num > 0) { nm_gstring_prepare (&str); for (i = 0; i < num; i++) { - nm_ip6_config_add_nameserver (ip6_config, &dns[i]); nm_utils_inet6_ntop (&dns[i], addr_str); - if (str->len) - g_string_append_c (str, ' '); - g_string_append (str, addr_str); - LOG_LEASE (LOGD_DHCP6, "nameserver %s", addr_str); + g_string_append (nm_gstring_add_space_delimiter (str), addr_str); + nm_ip6_config_add_nameserver (ip6_config, &dns[i]); } + LOG_LEASE (LOGD_DHCP6, "nameserver %s", str->str); add_option (options, dhcp6_requests, SD_DHCP6_OPTION_DNS_SERVERS, str->str); } @@ -877,10 +898,10 @@ lease_to_ip6_config (NMDedupMultiIndex *multi_idx, if (num > 0) { nm_gstring_prepare (&str); for (i = 0; i < num; i++) { + g_string_append (nm_gstring_add_space_delimiter (str), domains[i]); nm_ip6_config_add_search (ip6_config, domains[i]); - g_string_append_printf (str, "%s%s", str->len ? " " : "", domains[i]); - LOG_LEASE (LOGD_DHCP6, "domain name '%s'", domains[i]); } + LOG_LEASE (LOGD_DHCP6, "domain name '%s'", str->str); add_option (options, dhcp6_requests, SD_DHCP6_OPTION_DOMAIN_LIST, str->str); } diff --git a/src/dhcp/nm-dhcp-utils.c b/src/dhcp/nm-dhcp-utils.c index 768f9fd7..5227eea7 100644 --- a/src/dhcp/nm-dhcp-utils.c +++ b/src/dhcp/nm-dhcp-utils.c @@ -19,8 +19,6 @@ #include "nm-default.h" -#include <string.h> -#include <errno.h> #include <unistd.h> #include <arpa/inet.h> @@ -546,7 +544,7 @@ nm_dhcp_utils_ip4_config_from_options (NMDedupMultiIndex *multi_idx, errno = 0; int_mtu = strtol (str, NULL, 10); - if ((errno == EINVAL) || (errno == ERANGE)) + if (NM_IN_SET (errno, EINVAL, ERANGE)) goto error; if (int_mtu > 576) @@ -732,7 +730,7 @@ nm_dhcp_utils_duid_to_string (GBytes *duid) g_return_val_if_fail (duid, NULL); data = g_bytes_get_data (duid, &len); - return _nm_utils_bin2hexstr_full (data, len, ':', FALSE, NULL); + return nm_utils_bin2hexstr_full (data, len, ':', FALSE, NULL); } /** diff --git a/src/dhcp/tests/meson.build b/src/dhcp/tests/meson.build index d2de4dc4..43b33951 100644 --- a/src/dhcp/tests/meson.build +++ b/src/dhcp/tests/meson.build @@ -14,5 +14,6 @@ foreach test_unit: test_units 'dhcp/' + test_unit, test_script, args: test_args + [exe.full_path()], + timeout: default_test_timeout, ) endforeach diff --git a/src/dhcp/tests/test-dhcp-dhclient.c b/src/dhcp/tests/test-dhcp-dhclient.c index ab1f5551..55d712b0 100644 --- a/src/dhcp/tests/test-dhcp-dhclient.c +++ b/src/dhcp/tests/test-dhcp-dhclient.c @@ -20,7 +20,6 @@ #include "nm-default.h" -#include <string.h> #include <unistd.h> #include <arpa/inet.h> #include <linux/rtnetlink.h> @@ -803,7 +802,7 @@ test_write_duid (void) static void test_write_existing_duid (void) { - const guint8 duid[] = { 000, 001, 000, 001, 023, 'o', 023, 'n', 000, '\"', 0372, 0214, 0326, 0302 }; + const guint8 duid[] = { 000, 001, 000, 001, 023, 'o', 023, 'n', 000, '"', 0372, 0214, 0326, 0302 }; const char *original_contents = "default-duid \"\\000\\001\\000\\001\\027X\\350X\\000#\\025\\010~\\254\";\n"; const char *expected_contents = "default-duid \"\\000\\001\\000\\001\\023o\\023n\\000\\\"\\372\\214\\326\\302\";\n"; GError *error = NULL; @@ -825,7 +824,7 @@ test_write_existing_duid (void) g_assert_cmpstr (expected_contents, ==, contents); } -static const guint8 DUID_BIN[] = { 000, 001, 000, 001, 023, 'o', 023, 'n', 000, '\"', 0372, 0214, 0326, 0302 }; +static const guint8 DUID_BIN[] = { 000, 001, 000, 001, 023, 'o', 023, 'n', 000, '"', 0372, 0214, 0326, 0302 }; #define DUID "\\000\\001\\000\\001\\023o\\023n\\000\\\"\\372\\214\\326\\302" static void diff --git a/src/dhcp/tests/test-dhcp-utils.c b/src/dhcp/tests/test-dhcp-utils.c index 617a3c6c..240d868c 100644 --- a/src/dhcp/tests/test-dhcp-utils.c +++ b/src/dhcp/tests/test-dhcp-utils.c @@ -21,7 +21,6 @@ #include <netinet/in.h> #include <arpa/inet.h> -#include <string.h> #include <linux/rtnetlink.h> #include "nm-utils/nm-dedup-multi.h" diff --git a/src/dns/nm-dns-manager.c b/src/dns/nm-dns-manager.c index 2a30a540..c7c561c4 100644 --- a/src/dns/nm-dns-manager.c +++ b/src/dns/nm-dns-manager.c @@ -23,7 +23,6 @@ #include "nm-default.h" -#include <errno.h> #include <fcntl.h> #include <resolv.h> #include <stdlib.h> @@ -536,6 +535,7 @@ dispatch_netconfig (NMDnsManager *self, { GPid pid; int fd; + int errsv; int status; gssize l; nm_auto_free_gstring GString *str = NULL; @@ -566,11 +566,10 @@ again: /* Wait until the process exits */ if (!nm_utils_kill_child_sync (pid, 0, LOGD_DNS, "netconfig", &status, 1000, 0)) { - int errsv = errno; - + errsv = errno; g_set_error (error, NM_MANAGER_ERROR, NM_MANAGER_ERROR_FAILED, "Error waiting for netconfig to exit: %s", - strerror (errsv)); + nm_strerror_native (errsv)); return SR_ERROR; } if (!WIFEXITED (status) || WEXITSTATUS (status) != EXIT_SUCCESS) { @@ -678,7 +677,7 @@ write_resolv_conf_contents (FILE *f, NM_MANAGER_ERROR, NM_MANAGER_ERROR_FAILED, "Could not write " _PATH_RESCONF ": %s", - g_strerror (errsv)); + nm_strerror_native (errsv)); errno = errsv; return FALSE; } @@ -709,7 +708,8 @@ dispatch_resolvconf (NMDnsManager *self, gs_free char *cmd = NULL; FILE *f; gboolean success = FALSE; - int errnosv, err; + int errsv; + int err; char *argv[] = { RESOLVCONF_PATH, "-d", "NetworkManager", NULL }; int status; @@ -743,12 +743,13 @@ dispatch_resolvconf (NMDnsManager *self, cmd = g_strconcat (RESOLVCONF_PATH, " -a ", "NetworkManager", NULL); if ((f = popen (cmd, "w")) == NULL) { + errsv = errno; g_set_error (error, NM_MANAGER_ERROR, NM_MANAGER_ERROR_FAILED, "Could not write to %s: %s", RESOLVCONF_PATH, - g_strerror (errno)); + nm_strerror_native (errsv)); return SR_ERROR; } @@ -759,10 +760,10 @@ dispatch_resolvconf (NMDnsManager *self, error); err = pclose (f); if (err < 0) { - errnosv = errno; + errsv = errno; g_clear_error (error); - g_set_error (error, G_IO_ERROR, g_io_error_from_errno (errnosv), - "Failed to close pipe to resolvconf: %d", errnosv); + g_set_error (error, G_IO_ERROR, g_io_error_from_errno (errsv), + "Failed to close pipe to resolvconf: %d", errsv); return SR_ERROR; } else if (err > 0) { _LOGW ("resolvconf failed with status %d", err); @@ -886,9 +887,9 @@ update_resolv_conf (NMDnsManager *self, NM_MANAGER_ERROR_FAILED, "Could not open %s: %s", MY_RESOLV_CONF_TMP, - g_strerror (errsv)); + nm_strerror_native (errsv)); _LOGT ("update-resolv-conf: open temporary file %s failed (%s)", - MY_RESOLV_CONF_TMP, g_strerror (errsv)); + MY_RESOLV_CONF_TMP, nm_strerror_native (errsv)); return SR_ERROR; } @@ -896,7 +897,7 @@ update_resolv_conf (NMDnsManager *self, if (!success) { errsv = errno; _LOGT ("update-resolv-conf: write temporary file %s failed (%s)", - MY_RESOLV_CONF_TMP, g_strerror (errsv)); + MY_RESOLV_CONF_TMP, nm_strerror_native (errsv)); } if (fclose (f) < 0) { @@ -910,9 +911,9 @@ update_resolv_conf (NMDnsManager *self, NM_MANAGER_ERROR_FAILED, "Could not close %s: %s", MY_RESOLV_CONF_TMP, - g_strerror (errsv)); + nm_strerror_native (errsv)); _LOGT ("update-resolv-conf: close temporary file %s failed (%s)", - MY_RESOLV_CONF_TMP, g_strerror (errsv)); + MY_RESOLV_CONF_TMP, nm_strerror_native (errsv)); } return SR_ERROR; } else if (!success) @@ -925,9 +926,9 @@ update_resolv_conf (NMDnsManager *self, NM_MANAGER_ERROR_FAILED, "Could not replace %s: %s", MY_RESOLV_CONF, - g_strerror (errno)); + nm_strerror_native (errsv)); _LOGT ("update-resolv-conf: failed to rename temporary file %s to %s (%s)", - MY_RESOLV_CONF_TMP, MY_RESOLV_CONF, g_strerror (errsv)); + MY_RESOLV_CONF_TMP, MY_RESOLV_CONF, nm_strerror_native (errsv)); return SR_ERROR; } @@ -962,10 +963,10 @@ update_resolv_conf (NMDnsManager *self, NM_MANAGER_ERROR_FAILED, "Could not unlink %s: %s", RESOLV_CONF_TMP, - g_strerror (errsv)); + nm_strerror_native (errsv)); _LOGT ("update-resolv-conf: write internal file %s succeeded " "but canot delete temporary file %s: %s", - MY_RESOLV_CONF, RESOLV_CONF_TMP, g_strerror (errsv)); + MY_RESOLV_CONF, RESOLV_CONF_TMP, nm_strerror_native (errsv)); return SR_ERROR; } @@ -977,10 +978,10 @@ update_resolv_conf (NMDnsManager *self, "Could not create symlink %s pointing to %s: %s", RESOLV_CONF_TMP, MY_RESOLV_CONF, - g_strerror (errsv)); + nm_strerror_native (errsv)); _LOGT ("update-resolv-conf: write internal file %s succeeded " "but failed to symlink %s: %s", - MY_RESOLV_CONF, RESOLV_CONF_TMP, g_strerror (errsv)); + MY_RESOLV_CONF, RESOLV_CONF_TMP, nm_strerror_native (errsv)); return SR_ERROR; } @@ -992,10 +993,10 @@ update_resolv_conf (NMDnsManager *self, "Could not rename %s to %s: %s", RESOLV_CONF_TMP, _PATH_RESCONF, - g_strerror (errsv)); + nm_strerror_native (errsv)); _LOGT ("update-resolv-conf: write internal file %s succeeded " "but failed to rename temporary symlink %s to %s: %s", - MY_RESOLV_CONF, RESOLV_CONF_TMP, _PATH_RESCONF, g_strerror (errsv)); + MY_RESOLV_CONF, RESOLV_CONF_TMP, _PATH_RESCONF, nm_strerror_native (errsv)); return SR_ERROR; } diff --git a/src/dns/nm-dns-plugin.c b/src/dns/nm-dns-plugin.c index 48f04b00..ce814186 100644 --- a/src/dns/nm-dns-plugin.c +++ b/src/dns/nm-dns-plugin.c @@ -21,7 +21,6 @@ #include "nm-dns-plugin.h" -#include <string.h> #include <stdlib.h> #include <unistd.h> #include <sys/types.h> diff --git a/src/dnsmasq/nm-dnsmasq-manager.c b/src/dnsmasq/nm-dnsmasq-manager.c index 1afc6e0d..43bc66fc 100644 --- a/src/dnsmasq/nm-dnsmasq-manager.c +++ b/src/dnsmasq/nm-dnsmasq-manager.c @@ -25,7 +25,6 @@ #include <sys/types.h> #include <sys/wait.h> #include <signal.h> -#include <string.h> #include <unistd.h> #include <arpa/inet.h> #include <stdlib.h> diff --git a/src/dnsmasq/nm-dnsmasq-utils.c b/src/dnsmasq/nm-dnsmasq-utils.c index 382b3aeb..ec5545d3 100644 --- a/src/dnsmasq/nm-dnsmasq-utils.c +++ b/src/dnsmasq/nm-dnsmasq-utils.c @@ -20,7 +20,6 @@ #include "nm-default.h" -#include <string.h> #include <arpa/inet.h> #include "nm-dnsmasq-utils.h" diff --git a/src/initrd/nm-initrd-generator.c b/src/initrd/nm-initrd-generator.c index 70f23e17..b84543c4 100644 --- a/src/initrd/nm-initrd-generator.c +++ b/src/initrd/nm-initrd-generator.c @@ -92,6 +92,7 @@ main (int argc, char *argv[]) }; GOptionContext *option_context; GError *error = NULL; + int errsv; option_context = g_option_context_new ("-- [ip=...] [rd.route=...] [bridge=...] [bond=...] [team=...] [vlan=...] " "[bootdev=...] [nameserver=...] [rd.peerdns=...] [rd.bootif=...] [BOOTIF=...] ... "); @@ -121,7 +122,8 @@ main (int argc, char *argv[]) g_clear_pointer (&connections_dir, g_free); if (connections_dir && g_mkdir_with_parents (connections_dir, 0755) != 0) { - _LOGW (LOGD_CORE, "%s: %s", connections_dir, strerror (errno)); + errsv = errno; + _LOGW (LOGD_CORE, "%s: %s", connections_dir, nm_strerror_native (errsv)); return 1; } diff --git a/src/initrd/nm-initrd-generator.h b/src/initrd/nm-initrd-generator.h index 1fa858fc..dab6fb64 100644 --- a/src/initrd/nm-initrd-generator.h +++ b/src/initrd/nm-initrd-generator.h @@ -1,18 +1,19 @@ /* NetworkManager initrd configuration generator * - * This program is free software; you can redistribute it and/or modify - * it under the terms of the GNU General Public License as published by - * the Free Software Foundation; either version 2 of the License, or - * (at your option) any later version. + * This library is free software; you can redistribute it and/or + * modify it under the terms of the GNU Lesser General Public + * License as published by the Free Software Foundation; either + * version 2 of the License, or (at your option) any later version. * - * This program is distributed in the hope that it will be useful, + * This library is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the - * GNU General Public License for more details. + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + * Lesser General Public License for more details. * - * You should have received a copy of the GNU General Public License along - * with this program; if not, write to the Free Software Foundation, Inc., - * 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA. + * You should have received a copy of the GNU Lesser General Public + * License along with this library; if not, write to the + * Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor, + * Boston, MA 02110-1301 USA. * * Copyright (C) 2014, 2018 Red Hat, Inc. */ diff --git a/src/initrd/nmi-cmdline-reader.c b/src/initrd/nmi-cmdline-reader.c index e812b086..b9c75c1b 100644 --- a/src/initrd/nmi-cmdline-reader.c +++ b/src/initrd/nmi-cmdline-reader.c @@ -19,12 +19,10 @@ */ #include "nm-default.h" -#include "nm-core-internal.h" +#include "nm-core-internal.h" #include "nm-initrd-generator.h" -#include <string.h> - /*****************************************************************************/ #define _NMLOG(level, domain, ...) \ @@ -518,8 +516,8 @@ parse_rd_route (GHashTable *connections, char *argument) const char *gateway; const char *interface; int family = AF_UNSPEC; - NMIPAddr net_addr = { 0, }; - NMIPAddr gateway_addr = { 0, }; + NMIPAddr net_addr = { }; + NMIPAddr gateway_addr = { }; int net_prefix = -1; NMIPRoute *route; NMSettingIPConfig *s_ip; diff --git a/src/initrd/nmi-ibft-reader.c b/src/initrd/nmi-ibft-reader.c index c9275467..efac5307 100644 --- a/src/initrd/nmi-ibft-reader.c +++ b/src/initrd/nmi-ibft-reader.c @@ -1,18 +1,19 @@ /* NetworkManager initrd configuration generator * - * This program is free software; you can redistribute it and/or modify - * it under the terms of the GNU General Public License as published by - * the Free Software Foundation; either version 2 of the License, or - * (at your option) any later version. + * This library is free software; you can redistribute it and/or + * modify it under the terms of the GNU Lesser General Public + * License as published by the Free Software Foundation; either + * version 2 of the License, or (at your option) any later version. * - * This program is distributed in the hope that it will be useful, + * This library is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the - * GNU General Public License for more details. + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + * Lesser General Public License for more details. * - * You should have received a copy of the GNU General Public License along - * with this program; if not, write to the Free Software Foundation, Inc., - * 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA. + * You should have received a copy of the GNU Lesser General Public + * License along with this library; if not, write to the + * Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor, + * Boston, MA 02110-1301 USA. * * Copyright 2014 - 2018 Red Hat, Inc. */ @@ -22,13 +23,11 @@ #include "nm-initrd-generator.h" #include <stdlib.h> -#include <string.h> #include <sys/types.h> #include <sys/socket.h> #include <arpa/inet.h> #include <sys/wait.h> #include <sys/inotify.h> -#include <errno.h> #include <sys/ioctl.h> #include <unistd.h> diff --git a/src/initrd/tests/test-cmdline-reader.c b/src/initrd/tests/test-cmdline-reader.c index 95084e92..1a87505a 100644 --- a/src/initrd/tests/test-cmdline-reader.c +++ b/src/initrd/tests/test-cmdline-reader.c @@ -23,7 +23,6 @@ #include <stdio.h> #include <stdarg.h> #include <unistd.h> -#include <string.h> #include <netinet/ether.h> #include <netinet/in.h> #include <arpa/inet.h> diff --git a/src/initrd/tests/test-ibft-reader.c b/src/initrd/tests/test-ibft-reader.c index 340b3896..64362d18 100644 --- a/src/initrd/tests/test-ibft-reader.c +++ b/src/initrd/tests/test-ibft-reader.c @@ -1,18 +1,19 @@ /* NetworkManager initrd configuration generator * - * This program is free software; you can redistribute it and/or modify - * it under the terms of the GNU General Public License as published by - * the Free Software Foundation; either version 2 of the License, or - * (at your option) any later version. + * This library is free software; you can redistribute it and/or + * modify it under the terms of the GNU Lesser General Public + * License as published by the Free Software Foundation; either + * version 2 of the License, or (at your option) any later version. * - * This program is distributed in the hope that it will be useful, + * This library is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the - * GNU General Public License for more details. + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + * Lesser General Public License for more details. * - * You should have received a copy of the GNU General Public License along - * with this program; if not, write to the Free Software Foundation, Inc., - * 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA. + * You should have received a copy of the GNU Lesser General Public + * License along with this library; if not, write to the + * Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor, + * Boston, MA 02110-1301 USA. * * Copyright 2014 - 2018 Red Hat, Inc. */ @@ -22,7 +23,6 @@ #include <stdio.h> #include <stdarg.h> #include <unistd.h> -#include <string.h> #include <netinet/ether.h> #include <netinet/in.h> #include <arpa/inet.h> diff --git a/src/main-utils.c b/src/main-utils.c index a597ede7..f3a2edf5 100644 --- a/src/main-utils.c +++ b/src/main-utils.c @@ -22,7 +22,6 @@ #include "nm-default.h" #include <stdio.h> -#include <errno.h> #include <fcntl.h> #include <stdlib.h> #include <unistd.h> @@ -93,21 +92,26 @@ nm_main_utils_write_pidfile (const char *pidfile) { char pid[16]; int fd; + int errsv; gboolean success = FALSE; if ((fd = open (pidfile, O_CREAT | O_WRONLY | O_TRUNC | O_CLOEXEC, 00644)) < 0) { - fprintf (stderr, _("Opening %s failed: %s\n"), pidfile, strerror (errno)); + errsv = errno; + fprintf (stderr, _("Opening %s failed: %s\n"), pidfile, nm_strerror_native (errsv)); return FALSE; } g_snprintf (pid, sizeof (pid), "%d", getpid ()); - if (write (fd, pid, strlen (pid)) < 0) - fprintf (stderr, _("Writing to %s failed: %s\n"), pidfile, strerror (errno)); - else + if (write (fd, pid, strlen (pid)) < 0) { + errsv = errno; + fprintf (stderr, _("Writing to %s failed: %s\n"), pidfile, nm_strerror_native (errsv)); + } else success = TRUE; - if (nm_close (fd)) - fprintf (stderr, _("Closing %s failed: %s\n"), pidfile, strerror (errno)); + if (nm_close (fd)) { + errsv = errno; + fprintf (stderr, _("Closing %s failed: %s\n"), pidfile, nm_strerror_native (errsv)); + } return success; } @@ -126,13 +130,13 @@ nm_main_utils_ensure_statedir () && parent[1] != '\0' && g_mkdir_with_parents (parent, 0755) != 0) { errsv = errno; - fprintf (stderr, "Cannot create parents for '%s': %s", NMSTATEDIR, g_strerror (errsv)); + fprintf (stderr, "Cannot create parents for '%s': %s", NMSTATEDIR, nm_strerror_native (errsv)); exit (1); } /* Ensure state directory exists */ if (g_mkdir_with_parents (NMSTATEDIR, 0700) != 0) { errsv = errno; - fprintf (stderr, "Cannot create '%s': %s", NMSTATEDIR, g_strerror (errsv)); + fprintf (stderr, "Cannot create '%s': %s", NMSTATEDIR, nm_strerror_native (errsv)); exit (1); } } @@ -145,7 +149,7 @@ nm_main_utils_ensure_rundir () /* Setup runtime directory */ if (g_mkdir_with_parents (NMRUNDIR, 0755) != 0) { errsv = errno; - fprintf (stderr, _("Cannot create '%s': %s"), NMRUNDIR, g_strerror (errsv)); + fprintf (stderr, _("Cannot create '%s': %s"), NMRUNDIR, nm_strerror_native (errsv)); exit (1); } @@ -156,7 +160,7 @@ nm_main_utils_ensure_rundir () if (g_mkdir (NM_CONFIG_DEVICE_STATE_DIR, 0755) != 0) { errsv = errno; if (errsv != EEXIST) { - fprintf (stderr, _("Cannot create '%s': %s"), NM_CONFIG_DEVICE_STATE_DIR, g_strerror (errsv)); + fprintf (stderr, _("Cannot create '%s': %s"), NM_CONFIG_DEVICE_STATE_DIR, nm_strerror_native (errsv)); exit (1); } } diff --git a/src/main.c b/src/main.c index 36356a7a..9f979cf4 100644 --- a/src/main.c +++ b/src/main.c @@ -23,15 +23,12 @@ #include <getopt.h> #include <locale.h> -#include <errno.h> #include <stdlib.h> #include <signal.h> -#include <pthread.h> #include <unistd.h> #include <fcntl.h> #include <sys/stat.h> #include <sys/types.h> -#include <string.h> #include <sys/resource.h> #include "main-utils.h" @@ -233,6 +230,7 @@ main (int argc, char *argv[]) guint sd_id = 0; GError *error_invalid_logging_config = NULL; const char *const *warnings; + int errsv; /* Known to cause a possible deadlock upon GDBus initialization: * https://bugzilla.gnome.org/show_bug.cgi?id=674885 */ @@ -334,12 +332,10 @@ main (int argc, char *argv[]) if (global_opt.become_daemon && !nm_config_get_is_debug (config)) { if (daemon (0, 0) < 0) { - int saved_errno; - - saved_errno = errno; + errsv = errno; fprintf (stderr, _("Could not daemonize: %s [error %u]\n"), - g_strerror (saved_errno), - saved_errno); + nm_strerror_native (errsv), + errsv); exit (1); } wrote_pidfile = nm_main_utils_write_pidfile (global_opt.pidfile); @@ -355,7 +351,7 @@ main (int argc, char *argv[]) NM_CONFIG_KEYFILE_GROUP_LOGGING, NM_CONFIG_KEYFILE_KEY_LOGGING_BACKEND, NM_CONFIG_GET_VALUE_STRIP | NM_CONFIG_GET_VALUE_NO_EMPTY); - nm_logging_syslog_openlog (v, nm_config_get_is_debug (config)); + nm_logging_init (v, nm_config_get_is_debug (config)); } nm_log_info (LOGD_CORE, "NetworkManager (version " NM_DIST_VERSION ") is starting... (%s)", diff --git a/src/meson.build b/src/meson.build index ff2276e3..06a0dc57 100644 --- a/src/meson.build +++ b/src/meson.build @@ -45,8 +45,6 @@ sources = files( 'nm-logging.c', ) -sources += shared_files_time_utils - deps = [ libsystemd_dep, libudev_dep, diff --git a/src/ndisc/nm-fake-ndisc.c b/src/ndisc/nm-fake-ndisc.c index 6e9a72c6..f4719231 100644 --- a/src/ndisc/nm-fake-ndisc.c +++ b/src/ndisc/nm-fake-ndisc.c @@ -22,7 +22,6 @@ #include "nm-fake-ndisc.h" -#include <string.h> #include <arpa/inet.h> #include "nm-ndisc-private.h" diff --git a/src/ndisc/nm-lndp-ndisc.c b/src/ndisc/nm-lndp-ndisc.c index 53548050..2dd7e7d8 100644 --- a/src/ndisc/nm-lndp-ndisc.c +++ b/src/ndisc/nm-lndp-ndisc.c @@ -22,7 +22,6 @@ #include "nm-lndp-ndisc.h" -#include <string.h> #include <arpa/inet.h> #include <netinet/icmp6.h> /* stdarg.h included because of a bug in ndp.h */ @@ -73,7 +72,6 @@ send_rs (NMNDisc *ndisc, GError **error) errsv = ndp_msg_new (&msg, NDP_MSG_RS); if (errsv) { - errsv = errsv > 0 ? errsv : -errsv; g_set_error_literal (error, NM_UTILS_ERROR, NM_UTILS_ERROR_UNKNOWN, "cannot create router solicitation"); return FALSE; @@ -83,10 +81,10 @@ send_rs (NMNDisc *ndisc, GError **error) errsv = ndp_msg_send (priv->ndp, msg); ndp_msg_destroy (msg); if (errsv) { - errsv = errsv > 0 ? errsv : -errsv; + errsv = nm_errno_native (errsv); g_set_error (error, NM_UTILS_ERROR, NM_UTILS_ERROR_UNKNOWN, "%s (%d)", - g_strerror (errsv), errsv); + nm_strerror_native (errsv), errsv); return FALSE; } @@ -361,7 +359,6 @@ send_ra (NMNDisc *ndisc, GError **error) errsv = ndp_msg_new (&msg, NDP_MSG_RA); if (errsv) { - errsv = errsv > 0 ? errsv : -errsv; g_set_error_literal (error, NM_UTILS_ERROR, NM_UTILS_ERROR_UNKNOWN, "cannot create a router advertisement"); return FALSE; @@ -469,10 +466,10 @@ send_ra (NMNDisc *ndisc, GError **error) ndp_msg_destroy (msg); if (errsv) { - errsv = errsv > 0 ? errsv : -errsv; + errsv = nm_errno_native (errsv); g_set_error (error, NM_UTILS_ERROR, NM_UTILS_ERROR_UNKNOWN, "%s (%d)", - g_strerror (errsv), errsv); + nm_strerror_native (errsv), errsv); return FALSE; } @@ -536,7 +533,7 @@ start (NMNDisc *ndisc) /*****************************************************************************/ -static inline int +static int ipv6_sysctl_get (NMPlatform *platform, const char *ifname, const char *property, int min, int max, int defval) { return nm_platform_sysctl_ip_conf_get_int_checked (platform, @@ -600,10 +597,10 @@ nm_lndp_ndisc_new (NMPlatform *platform, errsv = ndp_open (&priv->ndp); if (errsv != 0) { - errsv = errsv > 0 ? errsv : -errsv; + errsv = nm_errno_native (errsv); g_set_error (error, NM_UTILS_ERROR, NM_UTILS_ERROR_UNKNOWN, "failure creating libndp socket: %s (%d)", - g_strerror (errsv), errsv); + nm_strerror_native (errsv), errsv); g_object_unref (ndisc); return NULL; } diff --git a/src/ndisc/nm-ndisc.c b/src/ndisc/nm-ndisc.c index 2da08c5f..dd535630 100644 --- a/src/ndisc/nm-ndisc.c +++ b/src/ndisc/nm-ndisc.c @@ -24,7 +24,6 @@ #include <stdlib.h> #include <arpa/inet.h> -#include <string.h> #include "nm-setting-ip6-config.h" @@ -442,7 +441,7 @@ nm_ndisc_add_address (NMNDisc *ndisc, if (from_ra) { /* RFC4862 5.5.3.d, we find an existing address with the same prefix. - * (note that all prefixes at this point have implicity length /64). */ + * (note that all prefixes at this point have implicitly length /64). */ if (memcmp (&item->address, &new->address, 8) == 0) { existing = item; break; diff --git a/src/ndisc/tests/meson.build b/src/ndisc/tests/meson.build index 0395e406..99cf664e 100644 --- a/src/ndisc/tests/meson.build +++ b/src/ndisc/tests/meson.build @@ -10,6 +10,7 @@ test( 'ndisc/' + test_unit, test_script, args: test_args + [exe.full_path()], + timeout: default_test_timeout, ) test = 'test-ndisc-linux' diff --git a/src/ndisc/tests/test-ndisc-fake.c b/src/ndisc/tests/test-ndisc-fake.c index 268f3b49..d2291d44 100644 --- a/src/ndisc/tests/test-ndisc-fake.c +++ b/src/ndisc/tests/test-ndisc-fake.c @@ -20,7 +20,6 @@ #include "nm-default.h" -#include <string.h> #include <syslog.h> #include "ndisc/nm-ndisc.h" diff --git a/src/ndisc/tests/test-ndisc-linux.c b/src/ndisc/tests/test-ndisc-linux.c index 2764b6c0..d47c0018 100644 --- a/src/ndisc/tests/test-ndisc-linux.c +++ b/src/ndisc/tests/test-ndisc-linux.c @@ -20,7 +20,6 @@ #include "nm-default.h" -#include <string.h> #include <syslog.h> #include "ndisc/nm-ndisc.h" diff --git a/src/nm-act-request.c b/src/nm-act-request.c index cd816964..a79167f2 100644 --- a/src/nm-act-request.c +++ b/src/nm-act-request.c @@ -23,7 +23,6 @@ #include "nm-act-request.h" -#include <string.h> #include <stdlib.h> #include <sys/wait.h> #include <unistd.h> @@ -166,7 +165,7 @@ nm_act_request_get_secrets (NMActRequest *self, gboolean ref_self, const char *setting_name, NMSecretAgentGetSecretsFlags flags, - const char *hint, + const char *const*hints, NMActRequestSecretsFunc callback, gpointer callback_data) { @@ -175,7 +174,6 @@ nm_act_request_get_secrets (NMActRequest *self, NMSettingsConnectionCallId *call_id_s; NMSettingsConnection *settings_connection; NMConnection *applied_connection; - const char *hints[2] = { hint, NULL }; g_return_val_if_fail (NM_IS_ACT_REQUEST (self), NULL); diff --git a/src/nm-act-request.h b/src/nm-act-request.h index af2b7490..e16e1ecf 100644 --- a/src/nm-act-request.h +++ b/src/nm-act-request.h @@ -69,7 +69,7 @@ NMActRequestGetSecretsCallId *nm_act_request_get_secrets (NMActRequest *req, gboolean take_ref, const char *setting_name, NMSecretAgentGetSecretsFlags flags, - const char *hint, + const char *const*hints, NMActRequestSecretsFunc callback, gpointer callback_data); diff --git a/src/nm-audit-manager.c b/src/nm-audit-manager.c index 64d9bf4a..9f868508 100644 --- a/src/nm-audit-manager.c +++ b/src/nm-audit-manager.c @@ -22,8 +22,6 @@ #include "nm-audit-manager.h" -#include <errno.h> -#include <string.h> #if HAVE_LIBAUDIT #include <libaudit.h> #endif @@ -337,15 +335,17 @@ init_auditd (NMAuditManager *self) { NMAuditManagerPrivate *priv = NM_AUDIT_MANAGER_GET_PRIVATE (self); NMConfigData *data = nm_config_get_data (priv->config); + int errsv; if (nm_config_data_get_value_boolean (data, NM_CONFIG_KEYFILE_GROUP_LOGGING, NM_CONFIG_KEYFILE_KEY_LOGGING_AUDIT, NM_CONFIG_DEFAULT_LOGGING_AUDIT_BOOL)) { if (priv->auditd_fd < 0) { priv->auditd_fd = audit_open (); - if (priv->auditd_fd < 0) - _LOGE (LOGD_CORE, "failed to open auditd socket: %s", strerror (errno)); - else + if (priv->auditd_fd < 0) { + errsv = errno; + _LOGE (LOGD_CORE, "failed to open auditd socket: %s", nm_strerror_native (errsv)); + } else _LOGD (LOGD_CORE, "socket created"); } } else { diff --git a/src/nm-auth-subject.c b/src/nm-auth-subject.c index 9ed65e2d..dff331a8 100644 --- a/src/nm-auth-subject.c +++ b/src/nm-auth-subject.c @@ -30,7 +30,6 @@ #include "nm-auth-subject.h" -#include <string.h> #include <stdlib.h> #include "nm-dbus-manager.h" diff --git a/src/nm-auth-utils.c b/src/nm-auth-utils.c index 0c4a4bac..146f6883 100644 --- a/src/nm-auth-utils.c +++ b/src/nm-auth-utils.c @@ -22,10 +22,7 @@ #include "nm-auth-utils.h" -#include <string.h> - #include "nm-utils/nm-c-list.h" - #include "nm-setting-connection.h" #include "nm-auth-subject.h" #include "nm-auth-manager.h" diff --git a/src/nm-checkpoint.c b/src/nm-checkpoint.c index 5489ed49..9b1622ec 100644 --- a/src/nm-checkpoint.c +++ b/src/nm-checkpoint.c @@ -22,8 +22,6 @@ #include "nm-checkpoint.h" -#include <string.h> - #include "nm-active-connection.h" #include "nm-act-request.h" #include "nm-auth-subject.h" diff --git a/src/nm-config-data.c b/src/nm-config-data.c index 8ef91516..608b7e58 100644 --- a/src/nm-config-data.c +++ b/src/nm-config-data.c @@ -23,8 +23,6 @@ #include "nm-config-data.h" -#include <string.h> - #include "nm-config.h" #include "devices/nm-device.h" #include "nm-core-internal.h" @@ -218,7 +216,6 @@ nm_config_data_get_value_int64 (const NMConfigData *self, const char *group, con str = nm_config_keyfile_get_value (NM_CONFIG_DATA_GET_PRIVATE (self)->keyfile, group, key, NM_CONFIG_GET_VALUE_NONE); val = _nm_utils_ascii_str_to_int64 (str, base, min, max, fallback); if (str) { - /* preserve errno from the parsing. */ errsv = errno; g_free (str); errno = errsv; diff --git a/src/nm-config.c b/src/nm-config.c index d028be67..3e82bdec 100644 --- a/src/nm-config.c +++ b/src/nm-config.c @@ -23,7 +23,6 @@ #include "nm-config.h" -#include <string.h> #include <stdio.h> #include "nm-utils.h" diff --git a/src/nm-connectivity.c b/src/nm-connectivity.c index 5f0567e9..b72413d2 100644 --- a/src/nm-connectivity.c +++ b/src/nm-connectivity.c @@ -24,8 +24,6 @@ #include "nm-connectivity.h" -#include <string.h> - #if WITH_CONCHECK #include <curl/curl.h> #endif @@ -92,7 +90,7 @@ struct _NMConnectivityCheckHandle { struct curl_slist *request_headers; struct curl_slist *hosts; - GString *recv_msg; + gsize response_good_cnt; guint curl_timer; int ch_ifindex; @@ -271,8 +269,6 @@ cb_data_complete (NMConnectivityCheckHandle *cb_data, #if WITH_CONCHECK _con_config_unref (cb_data->concheck.con_config); - if (cb_data->concheck.recv_msg) - g_string_free (cb_data->concheck.recv_msg, TRUE); #endif g_free (cb_data->ifspec); if (cb_data->completed_log_message_free) @@ -342,6 +338,7 @@ _con_curl_check_connectivity (CURLM *mhandle, int sockfd, int ev_bitmask) } while ((msg = curl_multi_info_read (mhandle, &m_left))) { + const char *response; if (msg->msg != CURLMSG_DONE) continue; @@ -370,25 +367,44 @@ _con_curl_check_connectivity (CURLM *mhandle, int sockfd, int ev_bitmask) g_strdup_printf ("check failed: (%d) %s", msg->data.result, curl_easy_strerror (msg->data.result))); - } else if ( !((_con_config_get_response (cb_data->concheck.con_config))[0]) - && (curl_easy_getinfo (msg->easy_handle, CURLINFO_RESPONSE_CODE, &response_code) == CURLE_OK) - && response_code == 204) { - /* If we got a 204 response code (no content) and we actually - * requested no content, report full connectivity. */ - cb_data_queue_completed (cb_data, - NM_CONNECTIVITY_FULL, - "no content, as expected", - NULL); - } else { - /* If we get here, it means that easy_write_cb() didn't read enough - * bytes to be able to do a match, or that we were asking for no content - * (204 response code) and we actually got some. Either way, that is - * an indication of a captive portal */ - cb_data_queue_completed (cb_data, - NM_CONNECTIVITY_PORTAL, - "unexpected short response", - NULL); + continue; + } + + response = _con_config_get_response (cb_data->concheck.con_config); + + if ( response[0] == '\0' + && (curl_easy_getinfo (msg->easy_handle, CURLINFO_RESPONSE_CODE, &response_code) == CURLE_OK)) { + + if (response_code == 204) { + /* We expected an empty response, and we got a 204 response code (no content). + * We may or may not have received any content (we would ignore it). + * Anyway, the response_code 204 means we are good. */ + cb_data_queue_completed (cb_data, + NM_CONNECTIVITY_FULL, + "no content, as expected", + NULL); + continue; + } + + if ( response_code == 200 + && cb_data->concheck.response_good_cnt == 0) { + /* we expected no response, and indeed we got an empty reply (with status code 200) */ + cb_data_queue_completed (cb_data, + NM_CONNECTIVITY_FULL, + "empty response, as expected", + NULL); + continue; + } } + + /* If we get here, it means that easy_write_cb() didn't read enough + * bytes to be able to do a match, or that we were asking for no content + * (204 response code) and we actually got some. Either way, that is + * an indication of a captive portal */ + cb_data_queue_completed (cb_data, + NM_CONNECTIVITY_PORTAL, + "unexpected short response", + NULL); } /* if we return a failure, we don't know what went wrong. It's likely serious, because @@ -540,6 +556,8 @@ easy_write_cb (void *buffer, size_t size, size_t nmemb, void *userdata) { NMConnectivityCheckHandle *cb_data = userdata; size_t len = size * nmemb; + size_t response_len; + size_t check_len; const char *response; if (cb_data->completed_state != NM_CONNECTIVITY_UNKNOWN) { @@ -547,26 +565,68 @@ easy_write_cb (void *buffer, size_t size, size_t nmemb, void *userdata) return 0; } - if (!cb_data->concheck.recv_msg) - cb_data->concheck.recv_msg = g_string_sized_new (len + 10); - - g_string_append_len (cb_data->concheck.recv_msg, buffer, len); + if (len == 0) { + /* no data. That can happen, it's fine. */ + return len; + } response = _con_config_get_response (cb_data->concheck.con_config);; - if ( response - && cb_data->concheck.recv_msg->len >= strlen (response)) { - /* We already have enough data -- check response */ - if (g_str_has_prefix (cb_data->concheck.recv_msg->str, response)) { - cb_data_queue_completed (cb_data, - NM_CONNECTIVITY_FULL, - "expected response", - NULL); - } else { + + if (response[0] == '\0') { + /* no response expected. We are however graceful and accept any + * extra response that we might receive. We determine the empty + * response based on the status code 204. + * + * Continue receiving... */ + cb_data->concheck.response_good_cnt += len; + + if (cb_data->concheck.response_good_cnt > (gsize) (100 * 1024)) { + /* we expect an empty response. We accept either + * 1) status code 204 and any response + * 2) status code 200 and an empty response. + * + * Here, we want to continue receiving data, to see whether we have + * case 1). Arguably, the server shouldn't send us 204 with a non-empty + * response, but we accept that also with a non-empty response, so + * keep receiving. + * + * However, if we get an excessive amount of data, we put a stop on it + * and fail. */ cb_data_queue_completed (cb_data, NM_CONNECTIVITY_PORTAL, - "unexpected response", + "unexpected non-empty response", NULL); + return 0; } + + return len; + } + + nm_assert (cb_data->concheck.response_good_cnt < strlen (response)); + + response_len = strlen (response); + + check_len = NM_MIN (len, + response_len - cb_data->concheck.response_good_cnt); + + if (strncmp (&response[cb_data->concheck.response_good_cnt], + buffer, + check_len) != 0) { + cb_data_queue_completed (cb_data, + NM_CONNECTIVITY_PORTAL, + "unexpected response", + NULL); + return 0; + } + + cb_data->concheck.response_good_cnt += len; + + if (cb_data->concheck.response_good_cnt >= response_len) { + /* We already have enough data, and it matched. */ + cb_data_queue_completed (cb_data, + NM_CONNECTIVITY_FULL, + "expected response", + NULL); return 0; } @@ -1041,8 +1101,8 @@ nm_connectivity_init (NMConnectivity *self) #if WITH_CONCHECK ret = curl_global_init (CURL_GLOBAL_ALL); if (ret != CURLE_OK) { - _LOGE ("unable to init cURL, connectivity check will not work: (%d) %s", - ret, curl_easy_strerror (ret)); + _LOGE ("unable to init cURL, connectivity check will not work: (%d) %s", + ret, curl_easy_strerror (ret)); } #endif diff --git a/src/nm-core-utils.c b/src/nm-core-utils.c index 3047ebc8..6f55e62a 100644 --- a/src/nm-core-utils.c +++ b/src/nm-core-utils.c @@ -23,10 +23,8 @@ #include "nm-core-utils.h" -#include <errno.h> #include <fcntl.h> #include <fnmatch.h> -#include <string.h> #include <unistd.h> #include <stdlib.h> #include <resolv.h> @@ -246,16 +244,20 @@ nm_ethernet_address_is_valid (gconstpointer addr, gssize len) gconstpointer nm_utils_ipx_address_clear_host_address (int family, gpointer dst, gconstpointer src, guint8 plen) { - g_return_val_if_fail (src, NULL); g_return_val_if_fail (dst, NULL); switch (family) { case AF_INET: g_return_val_if_fail (plen <= 32, NULL); + + if (!src) { + /* allow "self-assignment", by specifying %NULL as source. */ + src = dst; + } + *((guint32 *) dst) = nm_utils_ip4_address_clear_host_address (*((guint32 *) src), plen); break; case AF_INET6: - g_return_val_if_fail (plen <= 128, NULL); nm_utils_ip6_address_clear_host_address (dst, src, plen); break; default: @@ -441,6 +443,7 @@ nm_utils_modprobe (GError **error, gboolean suppress_error_logging, const char * /* construct the argument list */ argv = g_ptr_array_sized_new (4); g_ptr_array_add (argv, "/sbin/modprobe"); + g_ptr_array_add (argv, "--use-blacklist"); g_ptr_array_add (argv, (char *) arg1); va_start (ap, arg1); @@ -575,7 +578,7 @@ _kc_cb_timeout_grace_period (void *user_data) /* ESRCH means, process does not exist or is already a zombie. */ if (errsv != ESRCH) { nm_log_err (LOGD_CORE | data->log_domain, "%s: kill(SIGKILL) returned unexpected return value %d: (%s, %d)", - data->log_name, ret, strerror (errsv), errsv); + data->log_name, ret, nm_strerror_native (errsv), errsv); } } else { nm_log_dbg (data->log_domain, "%s: process not terminated after %ld usec. Sending SIGKILL signal", @@ -661,7 +664,7 @@ nm_utils_kill_child_async (pid_t pid, int sig, NMLogDomain log_domain, /* ECHILD means, the process is not a child/does not exist or it has SIGCHILD blocked. */ if (errsv != ECHILD) { nm_log_err (LOGD_CORE | log_domain, LOG_NAME_FMT ": unexpected error while waitpid: %s (%d)", - LOG_NAME_ARGS, strerror (errsv), errsv); + LOG_NAME_ARGS, nm_strerror_native (errsv), errsv); _kc_invoke_callback (pid, log_domain, log_name, callback, user_data, FALSE, -1); return; } @@ -673,7 +676,7 @@ nm_utils_kill_child_async (pid_t pid, int sig, NMLogDomain log_domain, /* ESRCH means, process does not exist or is already a zombie. */ if (errsv != ESRCH) { nm_log_err (LOGD_CORE | log_domain, LOG_NAME_FMT ": unexpected error sending %s: %s (%d)", - LOG_NAME_ARGS, _kc_signal_to_string (sig), strerror (errsv), errsv); + LOG_NAME_ARGS, _kc_signal_to_string (sig), nm_strerror_native (errsv), errsv); _kc_invoke_callback (pid, log_domain, log_name, callback, user_data, FALSE, -1); return; } @@ -687,7 +690,7 @@ nm_utils_kill_child_async (pid_t pid, int sig, NMLogDomain log_domain, } else { errsv = errno; nm_log_err (LOGD_CORE | log_domain, LOG_NAME_FMT ": failed due to unexpected return value %ld by waitpid (%s, %d) after sending %s", - LOG_NAME_ARGS, (long) ret, strerror (errsv), errsv, _kc_signal_to_string (sig)); + LOG_NAME_ARGS, (long) ret, nm_strerror_native (errsv), errsv, _kc_signal_to_string (sig)); _kc_invoke_callback (pid, log_domain, log_name, callback, user_data, FALSE, -1); } return; @@ -709,7 +712,7 @@ nm_utils_kill_child_async (pid_t pid, int sig, NMLogDomain log_domain, g_child_watch_add (pid, _kc_cb_watch_child, data); } -static inline gulong +static gulong _sleep_duration_convert_ms_to_us (guint32 sleep_duration_msec) { if (sleep_duration_msec > 0) { @@ -769,7 +772,7 @@ nm_utils_kill_child_sync (pid_t pid, int sig, NMLogDomain log_domain, const char /* ECHILD means, the process is not a child/does not exist or it has SIGCHILD blocked. */ if (errsv != ECHILD) { nm_log_err (LOGD_CORE | log_domain, LOG_NAME_FMT ": unexpected error while waitpid: %s (%d)", - LOG_NAME_ARGS, strerror (errsv), errsv); + LOG_NAME_ARGS, nm_strerror_native (errsv), errsv); goto out; } } @@ -780,7 +783,7 @@ nm_utils_kill_child_sync (pid_t pid, int sig, NMLogDomain log_domain, const char /* ESRCH means, process does not exist or is already a zombie. */ if (errsv != ESRCH) { nm_log_err (LOGD_CORE | log_domain, LOG_NAME_FMT ": failed to send %s: %s (%d)", - LOG_NAME_ARGS, _kc_signal_to_string (sig), strerror (errsv), errsv); + LOG_NAME_ARGS, _kc_signal_to_string (sig), nm_strerror_native (errsv), errsv); } else { /* let's try again with waitpid, probably there was a race... */ ret = waitpid (pid, &status, 0); @@ -791,7 +794,7 @@ nm_utils_kill_child_sync (pid_t pid, int sig, NMLogDomain log_domain, const char } else { errsv = errno; nm_log_err (LOGD_CORE | log_domain, LOG_NAME_FMT ": failed due to unexpected return value %ld by waitpid (%s, %d) after sending %s", - LOG_NAME_ARGS, (long) ret, strerror (errsv), errsv, _kc_signal_to_string (sig)); + LOG_NAME_ARGS, (long) ret, nm_strerror_native (errsv), errsv, _kc_signal_to_string (sig)); } } goto out; @@ -822,7 +825,7 @@ nm_utils_kill_child_sync (pid_t pid, int sig, NMLogDomain log_domain, const char /* ECHILD means, the process is not a child/does not exist or it has SIGCHILD blocked. */ if (errsv != ECHILD) { nm_log_err (LOGD_CORE | log_domain, LOG_NAME_FMT ": after sending %s, waitpid failed with %s (%d)%s", - LOG_NAME_ARGS, _kc_signal_to_string (sig), strerror (errsv), errsv, + LOG_NAME_ARGS, _kc_signal_to_string (sig), nm_strerror_native (errsv), errsv, was_waiting ? _kc_waited_to_string (buf_wait, wait_start_us) : ""); goto out; } @@ -861,7 +864,7 @@ nm_utils_kill_child_sync (pid_t pid, int sig, NMLogDomain log_domain, const char /* ESRCH means, process does not exist or is already a zombie. */ if (errsv != ESRCH) { nm_log_err (LOGD_CORE | log_domain, LOG_NAME_FMT ": failed to send SIGKILL (after sending %s), %s (%d)", - LOG_NAME_ARGS, _kc_signal_to_string (sig), strerror (errsv), errsv); + LOG_NAME_ARGS, _kc_signal_to_string (sig), nm_strerror_native (errsv), errsv); goto out; } } @@ -879,7 +882,7 @@ nm_utils_kill_child_sync (pid_t pid, int sig, NMLogDomain log_domain, const char if (errsv != EINTR) { nm_log_err (LOGD_CORE | log_domain, LOG_NAME_FMT ": after sending %s%s, waitpid failed with %s (%d)%s", - LOG_NAME_ARGS, _kc_signal_to_string (sig), send_kill ? " and SIGKILL" : "", strerror (errsv), errsv, + LOG_NAME_ARGS, _kc_signal_to_string (sig), send_kill ? " and SIGKILL" : "", nm_strerror_native (errsv), errsv, _kc_waited_to_string (buf_wait, wait_start_us)); goto out; } @@ -967,7 +970,7 @@ nm_utils_kill_process_sync (pid_t pid, guint64 start_time, int sig, NMLogDomain LOG_NAME_ARGS, _kc_signal_to_string (sig)); } else { nm_log_warn (LOGD_CORE | log_domain, LOG_NAME_PROCESS_FMT ": failed to send %s: %s (%d)", - LOG_NAME_ARGS, _kc_signal_to_string (sig), strerror (errsv), errsv); + LOG_NAME_ARGS, _kc_signal_to_string (sig), nm_strerror_native (errsv), errsv); } return; } @@ -1018,7 +1021,7 @@ nm_utils_kill_process_sync (pid_t pid, guint64 start_time, int sig, NMLogDomain was_waiting ? _kc_waited_to_string (buf_wait, wait_start_us) : ""); } else { nm_log_warn (LOGD_CORE | log_domain, LOG_NAME_PROCESS_FMT ": failed to kill(%ld, 0): %s (%d)%s", - LOG_NAME_ARGS, (long int) pid, strerror (errsv), errsv, + LOG_NAME_ARGS, (long int) pid, nm_strerror_native (errsv), errsv, was_waiting ? _kc_waited_to_string (buf_wait, wait_start_us) : ""); } return; @@ -1054,7 +1057,7 @@ nm_utils_kill_process_sync (pid_t pid, guint64 start_time, int sig, NMLogDomain LOG_NAME_ARGS, _kc_waited_to_string (buf_wait, wait_start_us)); } else { nm_log_warn (LOGD_CORE | log_domain, LOG_NAME_PROCESS_FMT ": failed to send SIGKILL (after sending %s), %s (%d)%s", - LOG_NAME_ARGS, _kc_signal_to_string (sig), strerror (errsv), errsv, + LOG_NAME_ARGS, _kc_signal_to_string (sig), nm_strerror_native (errsv), errsv, _kc_waited_to_string (buf_wait, wait_start_us)); } return; @@ -2393,11 +2396,11 @@ _uuid_data_init (UuidData *uuid_data, uuid_data->is_fake = is_fake; if (packed) { G_STATIC_ASSERT_EXPR (sizeof (uuid_data->str) >= (sizeof (*uuid) * 2 + 1)); - _nm_utils_bin2hexstr_full (uuid, - sizeof (*uuid), - '\0', - FALSE, - uuid_data->str); + nm_utils_bin2hexstr_full (uuid, + sizeof (*uuid), + '\0', + FALSE, + uuid_data->str); } else { G_STATIC_ASSERT_EXPR (sizeof (uuid_data->str) >= 37); _nm_utils_uuid_unparse (uuid, uuid_data->str); @@ -2430,14 +2433,14 @@ again: if ( nm_utils_file_get_contents (-1, "/etc/machine-id", 100*1024, 0, &content, NULL, NULL) >= 0 || nm_utils_file_get_contents (-1, LOCALSTATEDIR"/lib/dbus/machine-id", 100*1024, 0, &content, NULL, NULL) >= 0) { g_strstrip (content); - if (_nm_utils_hexstr2bin_full (content, - FALSE, - FALSE, - NULL, - 16, - (guint8 *) &uuid, - sizeof (uuid), - NULL)) { + if (nm_utils_hexstr2bin_full (content, + FALSE, + FALSE, + NULL, + 16, + (guint8 *) &uuid, + sizeof (uuid), + NULL)) { if (!nm_utils_uuid_is_null (&uuid)) { /* an all-zero machine-id is not valid. */ is_fake = FALSE; @@ -2459,7 +2462,7 @@ again: if (nm_utils_host_id_get (&seed_bin, &seed_len)) { /* we have no valid machine-id. Generate a fake one by hashing * the secret-key. This key is commonly persisted, so it should be - * stable accross reboots (despite having a broken system without + * stable across reboots (despite having a broken system without * proper machine-id). */ fake_type = "secret-key"; hash_seed = "ab085f06-b629-46d1-a553-84eeba5683b6"; @@ -2556,7 +2559,7 @@ _host_id_read_timestamp (gboolean use_secret_key_file, * the secret_key) if we are unable to access the secret_key file in the first place. * * Pick a random timestamp from the past two years. Yes, this timestamp - * is not stable accross restarts, but apparently neither is the host-id + * is not stable across restarts, but apparently neither is the host-id * nor the secret_key itself. */ #define EPOCH_TWO_YEARS (G_GINT64_CONSTANT (2 * 365 * 24 * 3600) * NM_UTILS_NS_PER_SECOND) @@ -3124,7 +3127,7 @@ nm_utils_stable_id_generated_complete (const char *stable_id_generated) guint8 buf[NM_UTILS_CHECKSUM_LENGTH_SHA1]; char *base64; - /* for NM_UTILS_STABLE_TYPE_GENERATED we genererate a possibly long string + /* for NM_UTILS_STABLE_TYPE_GENERATED we generate a possibly long string * by doing text-substitutions in nm_utils_stable_id_parse(). * * Let's shorten the (possibly) long stable_id to something more compact. */ @@ -3178,7 +3181,7 @@ nm_utils_stable_id_parse (const char *stable_id, * of ${...} patterns. * * At first, it looks a bit like bash parameter substitution. - * In contrast however, the process is unambigious so that the resulting + * In contrast however, the process is unambiguous so that the resulting * effective id differs if: * - the original, untranslated stable-id differs * - or any of the subsitutions differs. @@ -3581,7 +3584,7 @@ nm_utils_dhcp_client_id_mac (int arp_type, /** * nm_utils_create_dhcp_iaid: * @legacy_unstable_byteorder: legacy behavior is to generate a u32 iaid which - * is endianness dependant. This is to preserve backward compatibility. + * is endianness dependent. This is to preserve backward compatibility. * For non-legacy behavior, the returned integer is in stable endianness, * and corresponds to legacy behavior on little endian systems. * @interface_id: the seed for hashing when generating the ID. Usually, @@ -3624,7 +3627,7 @@ nm_utils_create_dhcp_iaid (gboolean legacy_unstable_byteorder, * @legacy_unstable_byteorder: historically, the code would generate a iaid * dependent on host endianness. This is undesirable, if backward compatibility * are not a concern, generate stable endianness. - * @interface_id: a binary identifer that is hashed into the DUID. + * @interface_id: a binary identifier that is hashed into the DUID. * Comonly this is the interface-name, but it may be the MAC address. * @interface_id_len: the length of @interface_id. * @machine_id: the binary identifier for the machine. It is hashed @@ -4019,7 +4022,7 @@ nm_utils_get_reverse_dns_domains_ip6 (const struct in6_addr *ip, guint8 plen, GP return; memcpy (&addr, ip, sizeof (struct in6_addr)); - nm_utils_ip6_address_clear_host_address (&addr, &addr, plen); + nm_utils_ip6_address_clear_host_address (&addr, NULL, plen); /* Number of nibbles to include in domains */ nibbles = (plen - 1) / 4 + 1; @@ -4143,7 +4146,7 @@ nm_utils_read_plugin_paths (const char *dirname, const char *prefix) errsv = errno; nm_log_warn (LOGD_CORE, "plugin: skip invalid file %s (error during stat: %s)", - data.path, strerror (errsv)); + data.path, nm_strerror_native (errsv)); goto skip; } diff --git a/src/nm-core-utils.h b/src/nm-core-utils.h index a93854a4..1b0d39ed 100644 --- a/src/nm-core-utils.h +++ b/src/nm-core-utils.h @@ -485,4 +485,8 @@ const char *nm_activation_type_to_string (NMActivationType activation_type); const char *nm_utils_parse_dns_domain (const char *domain, gboolean *is_routing); +/*****************************************************************************/ + +#define NM_VPN_ROUTE_METRIC_DEFAULT 50 + #endif /* __NM_CORE_UTILS_H__ */ diff --git a/src/nm-dbus-manager.c b/src/nm-dbus-manager.c index 9c8d6570..00fa6617 100644 --- a/src/nm-dbus-manager.c +++ b/src/nm-dbus-manager.c @@ -26,8 +26,6 @@ #include <unistd.h> #include <sys/stat.h> #include <sys/types.h> -#include <errno.h> -#include <string.h> #include "c-list/src/c-list.h" #include "nm-dbus-interface.h" diff --git a/src/nm-dcb.c b/src/nm-dcb.c index 5a46fa00..a63fdf3d 100644 --- a/src/nm-dcb.c +++ b/src/nm-dcb.c @@ -21,7 +21,6 @@ #include "nm-default.h" #include <sys/wait.h> -#include <string.h> #include "nm-dcb.h" #include "platform/nm-platform.h" diff --git a/src/nm-dhcp4-config.c b/src/nm-dhcp4-config.c index ceafddf5..fe0df3a7 100644 --- a/src/nm-dhcp4-config.c +++ b/src/nm-dhcp4-config.c @@ -22,8 +22,6 @@ #include "nm-dhcp4-config.h" -#include <string.h> - #include "nm-dbus-interface.h" #include "nm-utils.h" #include "nm-dbus-object.h" diff --git a/src/nm-dhcp6-config.c b/src/nm-dhcp6-config.c index d477521a..59266d55 100644 --- a/src/nm-dhcp6-config.c +++ b/src/nm-dhcp6-config.c @@ -22,8 +22,6 @@ #include "nm-dhcp6-config.h" -#include <string.h> - #include "nm-dbus-interface.h" #include "nm-utils.h" #include "nm-dbus-object.h" diff --git a/src/nm-dispatcher.c b/src/nm-dispatcher.c index 368b781a..c0ef1bb6 100644 --- a/src/nm-dispatcher.c +++ b/src/nm-dispatcher.c @@ -23,9 +23,6 @@ #include "nm-dispatcher.h" -#include <string.h> -#include <errno.h> - #include "nm-dispatcher-api.h" #include "NetworkManagerUtils.h" #include "nm-utils.h" @@ -965,7 +962,7 @@ dispatcher_dir_changed (GFileMonitor *monitor, else if (errsv == 0) _LOGD ("%s script directory '%s' has no scripts", item->description, item->dir); else { - _LOGD ("%s script directory '%s' error reading (%s)", item->description, item->dir, strerror (errsv)); + _LOGD ("%s script directory '%s' error reading (%s)", item->description, item->dir, nm_strerror_native (errsv)); item->has_scripts = TRUE; } } else { diff --git a/src/nm-firewall-manager.c b/src/nm-firewall-manager.c index 5b5e7cfa..a4b079b4 100644 --- a/src/nm-firewall-manager.c +++ b/src/nm-firewall-manager.c @@ -22,8 +22,6 @@ #include "nm-firewall-manager.h" -#include <string.h> - #include "NetworkManagerUtils.h" #include "c-list/src/c-list.h" diff --git a/src/nm-hostname-manager.c b/src/nm-hostname-manager.c index 88ff1604..d405a320 100644 --- a/src/nm-hostname-manager.c +++ b/src/nm-hostname-manager.c @@ -23,8 +23,6 @@ #include "nm-hostname-manager.h" #include <sys/stat.h> -#include <errno.h> -#include <string.h> #if HAVE_SELINUX #include <selinux/selinux.h> diff --git a/src/nm-iface-helper.c b/src/nm-iface-helper.c index 1229ad35..1ef9f5ae 100644 --- a/src/nm-iface-helper.c +++ b/src/nm-iface-helper.c @@ -23,11 +23,9 @@ #include <glib-unix.h> #include <getopt.h> #include <locale.h> -#include <errno.h> #include <stdlib.h> #include <unistd.h> #include <fcntl.h> -#include <string.h> #include <sys/resource.h> #include <sys/stat.h> #include <signal.h> @@ -389,6 +387,7 @@ main (int argc, char *argv[]) gs_unref_bytes GBytes *client_id = NULL; gs_free NMUtilsIPv6IfaceId *iid = NULL; guint sd_id; + int errsv; c_list_init (&gl.dad_failed_lst_head); @@ -397,11 +396,11 @@ main (int argc, char *argv[]) if (!do_early_setup (&argc, &argv)) return 1; - nm_logging_set_syslog_identifier ("nm-iface-helper"); - nm_logging_set_prefix ("%s[%ld] (%s): ", - _NMLOG_PREFIX_NAME, - (long) getpid (), - global_opt.ifname ?: "???"); + nm_logging_init_pre ("nm-iface-helper", + g_strdup_printf ("%s[%ld] (%s): ", + _NMLOG_PREFIX_NAME, + (long) getpid (), + global_opt.ifname ?: "???")); if (global_opt.g_fatal_warnings) { GLogLevelFlags fatal_mask; @@ -425,7 +424,8 @@ main (int argc, char *argv[]) gl.ifindex = nmp_utils_if_nametoindex (global_opt.ifname); if (gl.ifindex <= 0) { - fprintf (stderr, _("Failed to find interface index for %s (%s)\n"), global_opt.ifname, strerror (errno)); + errsv = errno; + fprintf (stderr, _("Failed to find interface index for %s (%s)\n"), global_opt.ifname, nm_strerror_native (errsv)); return 1; } pidfile = g_strdup_printf (NMIH_PID_FILE_FMT, gl.ifindex); @@ -450,12 +450,10 @@ main (int argc, char *argv[]) if (global_opt.become_daemon && !global_opt.debug) { if (daemon (0, 0) < 0) { - int saved_errno; - - saved_errno = errno; + errsv = errno; fprintf (stderr, _("Could not daemonize: %s [error %u]\n"), - g_strerror (saved_errno), - saved_errno); + nm_strerror_native (errsv), + errsv); return 1; } if (nm_main_utils_write_pidfile (pidfile)) @@ -466,8 +464,8 @@ main (int argc, char *argv[]) gl.main_loop = g_main_loop_new (NULL, FALSE); setup_signals (); - nm_logging_syslog_openlog (global_opt.logging_backend, - global_opt.debug); + nm_logging_init (global_opt.logging_backend, + global_opt.debug); _LOGI (LOGD_CORE, "nm-iface-helper (version " NM_DIST_VERSION ") is starting..."); diff --git a/src/nm-ip4-config.c b/src/nm-ip4-config.c index 1179a77f..1c06a42c 100644 --- a/src/nm-ip4-config.c +++ b/src/nm-ip4-config.c @@ -23,7 +23,6 @@ #include "nm-ip4-config.h" -#include <string.h> #include <arpa/inet.h> #include <resolv.h> #include <linux/rtnetlink.h> @@ -1512,6 +1511,7 @@ nm_ip4_config_subtract (NMIP4Config *dst, static gboolean _nm_ip4_config_intersect_helper (NMIP4Config *dst, const NMIP4Config *src, + gboolean intersect_addresses, gboolean intersect_routes, guint32 default_route_metric_penalty, gboolean update_dst) @@ -1534,24 +1534,26 @@ _nm_ip4_config_intersect_helper (NMIP4Config *dst, g_object_freeze_notify (G_OBJECT (dst)); /* addresses */ - changed = FALSE; - nm_ip_config_iter_ip4_address_for_each (&ipconf_iter, dst, &a) { - if (nm_dedup_multi_index_lookup_obj (src_priv->multi_idx, - &src_priv->idx_ip4_addresses, - NMP_OBJECT_UP_CAST (a))) - continue; - - if (!update_dst) - return TRUE; - - if (nm_dedup_multi_index_remove_entry (dst_priv->multi_idx, - ipconf_iter.current) != 1) - nm_assert_not_reached (); - changed = TRUE; - } - if (changed) { - _notify_addresses (dst); - result = TRUE; + if (intersect_addresses) { + changed = FALSE; + nm_ip_config_iter_ip4_address_for_each (&ipconf_iter, dst, &a) { + if (nm_dedup_multi_index_lookup_obj (src_priv->multi_idx, + &src_priv->idx_ip4_addresses, + NMP_OBJECT_UP_CAST (a))) + continue; + + if (!update_dst) + return TRUE; + + if (nm_dedup_multi_index_remove_entry (dst_priv->multi_idx, + ipconf_iter.current) != 1) + nm_assert_not_reached (); + changed = TRUE; + } + if (changed) { + _notify_addresses (dst); + result = TRUE; + } } /* ignore nameservers */ @@ -1600,12 +1602,12 @@ _nm_ip4_config_intersect_helper (NMIP4Config *dst, _notify (dst, PROP_GATEWAY); } -skip_routes: if (changed) { _notify_routes (dst); result = TRUE; } +skip_routes: /* ignore domains */ /* ignore dns searches */ /* ignore dns options */ @@ -1623,6 +1625,8 @@ skip_routes: * nm_ip4_config_intersect: * @dst: a configuration to be updated * @src: another configuration + * @intersect_addresses: whether addresses should be intersected + * @intersect_routes: whether routes should be intersected * @default_route_metric_penalty: the default route metric penalty * * Computes the intersection between @src and @dst and updates @dst in place @@ -1631,16 +1635,24 @@ skip_routes: void nm_ip4_config_intersect (NMIP4Config *dst, const NMIP4Config *src, + gboolean intersect_addresses, gboolean intersect_routes, guint32 default_route_metric_penalty) { - _nm_ip4_config_intersect_helper (dst, src, intersect_routes, default_route_metric_penalty, TRUE); + _nm_ip4_config_intersect_helper (dst, + src, + intersect_addresses, + intersect_routes, + default_route_metric_penalty, + TRUE); } /** * nm_ip4_config_intersect_alloc: * @a: a configuration * @b: another configuration + * @intersect_addresses: whether addresses should be intersected + * @intersect_routes: whether routes should be intersected * @default_route_metric_penalty: the default route metric penalty * * Computes the intersection between @a and @b and returns the result in a newly @@ -1655,17 +1667,24 @@ nm_ip4_config_intersect (NMIP4Config *dst, NMIP4Config * nm_ip4_config_intersect_alloc (const NMIP4Config *a, const NMIP4Config *b, + gboolean intersect_addresses, gboolean intersect_routes, guint32 default_route_metric_penalty) { NMIP4Config *a_copy; if (_nm_ip4_config_intersect_helper ((NMIP4Config *) a, b, + intersect_addresses, intersect_routes, - default_route_metric_penalty, FALSE)) { + default_route_metric_penalty, + FALSE)) { a_copy = nm_ip4_config_clone (a); - _nm_ip4_config_intersect_helper (a_copy, b, intersect_routes, - default_route_metric_penalty, TRUE); + _nm_ip4_config_intersect_helper (a_copy, + b, + intersect_addresses, + intersect_routes, + default_route_metric_penalty, + TRUE); return a_copy; } else return NULL; @@ -2153,7 +2172,7 @@ nm_ip4_config_get_first_address (const NMIP4Config *self) const NMPlatformIP4Address * _nmtst_ip4_config_get_address (const NMIP4Config *self, guint i) { - NMDedupMultiIter iter; + NMDedupMultiIter iter = { }; const NMPlatformIP4Address *a = NULL; guint j; @@ -2261,7 +2280,7 @@ _add_route (NMIP4Config *self, * nm_ip4_config_add_route: * @self: the #NMIP4Config * @new: the new route to add to @self - * @out_obj_new: (allow-none): (out): the added route object. Must be unrefed + * @out_obj_new: (allow-none) (out): the added route object. Must be unrefed * by caller. * * Adds the new route to @self. If a route with the same basic properties @@ -2901,7 +2920,7 @@ nm_ip4_config_nmpobj_remove (NMIP4Config *self, /*****************************************************************************/ -static inline void +static void hash_u32 (GChecksum *sum, guint32 n) { g_checksum_update (sum, (const guint8 *) &n, sizeof (n)); diff --git a/src/nm-ip4-config.h b/src/nm-ip4-config.h index 07fb7f12..6b4bfd64 100644 --- a/src/nm-ip4-config.h +++ b/src/nm-ip4-config.h @@ -189,10 +189,12 @@ void nm_ip4_config_subtract (NMIP4Config *dst, guint32 default_route_metric_penalty); void nm_ip4_config_intersect (NMIP4Config *dst, const NMIP4Config *src, + gboolean intersect_addresses, gboolean intersect_routes, guint32 default_route_metric_penalty); NMIP4Config *nm_ip4_config_intersect_alloc (const NMIP4Config *a, const NMIP4Config *b, + gboolean intersect_addresses, gboolean intersect_routes, guint32 default_route_metric_penalty); gboolean nm_ip4_config_replace (NMIP4Config *dst, const NMIP4Config *src, gboolean *relevant_changes); @@ -543,12 +545,14 @@ nm_ip_config_best_default_route_get (const NMIPConfig *self) static inline void nm_ip_config_intersect (NMIPConfig *dst, const NMIPConfig *src, + gboolean intersect_addresses, gboolean intersect_routes, guint32 default_route_metric_penalty) { _NM_IP_CONFIG_DISPATCH_SET_OP (, dst, src, nm_ip4_config_intersect, nm_ip6_config_intersect, + intersect_addresses, intersect_routes, default_route_metric_penalty); } @@ -591,6 +595,7 @@ nm_ip_config_replace (NMIPConfig *dst, static inline NMIPConfig * nm_ip_config_intersect_alloc (const NMIPConfig *a, const NMIPConfig *b, + gboolean intersect_addresses, gboolean intersect_routes, guint32 default_route_metric_penalty) { @@ -598,6 +603,7 @@ nm_ip_config_intersect_alloc (const NMIPConfig *a, nm_assert (NM_IS_IP4_CONFIG (b)); return (NMIPConfig *) nm_ip4_config_intersect_alloc ((const NMIP4Config *) a, (const NMIP4Config *) b, + intersect_addresses, intersect_routes, default_route_metric_penalty); } else { @@ -605,6 +611,7 @@ nm_ip_config_intersect_alloc (const NMIPConfig *a, nm_assert (NM_IS_IP6_CONFIG (b)); return (NMIPConfig *) nm_ip6_config_intersect_alloc ((const NMIP6Config *) a, (const NMIP6Config *) b, + intersect_addresses, intersect_routes, default_route_metric_penalty); } diff --git a/src/nm-ip6-config.c b/src/nm-ip6-config.c index 6d54809e..99a9ff88 100644 --- a/src/nm-ip6-config.c +++ b/src/nm-ip6-config.c @@ -23,7 +23,6 @@ #include "nm-ip6-config.h" -#include <string.h> #include <arpa/inet.h> #include <resolv.h> #include <linux/rtnetlink.h> @@ -1087,6 +1086,7 @@ nm_ip6_config_subtract (NMIP6Config *dst, static gboolean _nm_ip6_config_intersect_helper (NMIP6Config *dst, const NMIP6Config *src, + gboolean intersect_addresses, gboolean intersect_routes, guint32 default_route_metric_penalty, gboolean update_dst) @@ -1109,24 +1109,26 @@ _nm_ip6_config_intersect_helper (NMIP6Config *dst, g_object_freeze_notify (G_OBJECT (dst)); /* addresses */ - changed = FALSE; - nm_ip_config_iter_ip6_address_for_each (&ipconf_iter, dst, &a) { - if (nm_dedup_multi_index_lookup_obj (src_priv->multi_idx, - &src_priv->idx_ip6_addresses, - NMP_OBJECT_UP_CAST (a))) - continue; + if (intersect_addresses) { + changed = FALSE; + nm_ip_config_iter_ip6_address_for_each (&ipconf_iter, dst, &a) { + if (nm_dedup_multi_index_lookup_obj (src_priv->multi_idx, + &src_priv->idx_ip6_addresses, + NMP_OBJECT_UP_CAST (a))) + continue; - if (!update_dst) - return TRUE; + if (!update_dst) + return TRUE; - if (nm_dedup_multi_index_remove_entry (dst_priv->multi_idx, - ipconf_iter.current) != 1) - nm_assert_not_reached (); - changed = TRUE; - } - if (changed) { - _notify_addresses (dst); - result = TRUE; + if (nm_dedup_multi_index_remove_entry (dst_priv->multi_idx, + ipconf_iter.current) != 1) + nm_assert_not_reached (); + changed = TRUE; + } + if (changed) { + _notify_addresses (dst); + result = TRUE; + } } /* ignore nameservers */ @@ -1194,6 +1196,8 @@ skip_routes: * nm_ip6_config_intersect: * @dst: a configuration to be updated * @src: another configuration + * @intersect_addresses: whether addresses should be intersected + * @intersect_routes: whether routes should be intersected * @default_route_metric_penalty: the default route metric penalty * * Computes the intersection between @src and @dst and updates @dst in place @@ -1202,16 +1206,24 @@ skip_routes: void nm_ip6_config_intersect (NMIP6Config *dst, const NMIP6Config *src, + gboolean intersect_addresses, gboolean intersect_routes, guint32 default_route_metric_penalty) { - _nm_ip6_config_intersect_helper (dst, src, intersect_routes, default_route_metric_penalty, TRUE); + _nm_ip6_config_intersect_helper (dst, + src, + intersect_addresses, + intersect_routes, + default_route_metric_penalty, + TRUE); } /** * nm_ip6_config_intersect_alloc: * @a: a configuration * @b: another configuration + * @intersect_addresses: whether addresses should be intersected + * @intersect_routes: whether routes should be intersected * @default_route_metric_penalty: the default route metric penalty * * Computes the intersection between @a and @b and returns the result in a newly @@ -1226,17 +1238,25 @@ nm_ip6_config_intersect (NMIP6Config *dst, NMIP6Config * nm_ip6_config_intersect_alloc (const NMIP6Config *a, const NMIP6Config *b, + gboolean intersect_addresses, gboolean intersect_routes, guint32 default_route_metric_penalty) { NMIP6Config *a_copy; - if (_nm_ip6_config_intersect_helper ((NMIP6Config *) a, b, + if (_nm_ip6_config_intersect_helper ((NMIP6Config *) a, + b, + intersect_addresses, intersect_routes, - default_route_metric_penalty, FALSE)) { + default_route_metric_penalty, + FALSE)) { a_copy = nm_ip6_config_clone (a); - _nm_ip6_config_intersect_helper (a_copy, b, intersect_routes, - default_route_metric_penalty, TRUE); + _nm_ip6_config_intersect_helper (a_copy, + b, + intersect_addresses, + intersect_routes, + default_route_metric_penalty, + TRUE); return a_copy; } else return NULL; @@ -1925,7 +1945,7 @@ _add_route (NMIP6Config *self, * nm_ip6_config_add_route: * @self: the #NMIP6Config * @new: the new route to add to @self - * @out_obj_new: (allow-none): (out): the added route object. Must be unrefed + * @out_obj_new: (allow-none) (out): the added route object. Must be unrefed * by caller. * * Adds the new route to @self. If a route with the same basic properties @@ -2353,13 +2373,13 @@ nm_ip6_config_nmpobj_remove (NMIP6Config *self, /*****************************************************************************/ -static inline void +static void hash_u32 (GChecksum *sum, guint32 n) { g_checksum_update (sum, (const guint8 *) &n, sizeof (n)); } -static inline void +static void hash_in6addr (GChecksum *sum, const struct in6_addr *a) { if (a) diff --git a/src/nm-ip6-config.h b/src/nm-ip6-config.h index 862f237d..557e3796 100644 --- a/src/nm-ip6-config.h +++ b/src/nm-ip6-config.h @@ -130,10 +130,12 @@ void nm_ip6_config_subtract (NMIP6Config *dst, guint32 default_route_metric_penalty); void nm_ip6_config_intersect (NMIP6Config *dst, const NMIP6Config *src, + gboolean intersect_addresses, gboolean intersect_routes, guint32 default_route_metric_penalty); NMIP6Config *nm_ip6_config_intersect_alloc (const NMIP6Config *a, const NMIP6Config *b, + gboolean intersect_addresses, gboolean intersect_routes, guint32 default_route_metric_penalty); gboolean nm_ip6_config_replace (NMIP6Config *dst, const NMIP6Config *src, gboolean *relevant_changes); diff --git a/src/nm-keep-alive.c b/src/nm-keep-alive.c index e601483b..cfec138a 100644 --- a/src/nm-keep-alive.c +++ b/src/nm-keep-alive.c @@ -23,8 +23,6 @@ #include "nm-keep-alive.h" -#include <string.h> - #include "settings/nm-settings-connection.h" /*****************************************************************************/ @@ -98,7 +96,7 @@ _is_alive (NMKeepAlive *self) /* the D-Bus client is gone. The only other binding (below) for the connection's * visibility cannot keep the instance alive. * - * As such, a D-Bus client watch is authorative and overrules other conditions (that + * As such, a D-Bus client watch is authoritative and overrules other conditions (that * we have so far). */ return FALSE; } @@ -470,7 +468,7 @@ _nm_keep_alive_set_owner (NMKeepAlive *self, nm_assert (!owner || !priv->owner); /* optimally, we would take a reference to @owner. But the - * owner already owns a refrence to the keep-alive, so we cannot + * owner already owns a reference to the keep-alive, so we cannot * just own a reference back. * * We could register a weak-pointer here. But instead, declare that diff --git a/src/nm-logging.c b/src/nm-logging.c index 6f912f58..1ee94645 100644 --- a/src/nm-logging.c +++ b/src/nm-logging.c @@ -28,11 +28,9 @@ #include <stdio.h> #include <stdlib.h> #include <unistd.h> -#include <errno.h> #include <sys/wait.h> #include <sys/stat.h> #include <strings.h> -#include <string.h> #if SYSTEMD_JOURNAL #define SD_JOURNAL_SUPPRESS_LOCATION @@ -42,13 +40,50 @@ #include "nm-utils/nm-time-utils.h" #include "nm-errors.h" -void (*_nm_logging_clear_platform_logging_cache) (void); +/*****************************************************************************/ -static void -nm_log_handler (const char *log_domain, - GLogLevelFlags level, - const char *message, - gpointer ignored); +/* Notes about thread-safety: + * + * NetworkManager generally is single-threaded and uses a (GLib) mainloop. + * However, nm-logging is in parts thread-safe. That means: + * + * - functions that configure logging (nm_logging_init(), nm_logging_setup()) and + * most other functions MUST be called only from the main-thread. These functions + * are expected to be called infrequently, so they may or may not use a mutex + * (but the overhead is negligible here). + * + * - functions that do the actual logging logging (nm_log(), nm_logging_enabled()) are + * thread-safe and may be used from multiple threads. + * - When called from the not-main-thread, @mt_require_locking must be set to %TRUE. + * In this case, a Mutex will be used for accessing the global state. + * - When called from the main-thread, they may optionally pass @mt_require_locking %FALSE. + * This avoids extra locking and is in particular interesting for nm_logging_enabled(), + * which is expected to be called frequently and from the main-thread. + * + * Note that the logging macros honor %NM_THREAD_SAFE_ON_MAIN_THREAD define, to automatically + * set @mt_require_locking. That means, by default %NM_THREAD_SAFE_ON_MAIN_THREAD is "1", + * and code that only runs on the main-thread (which is the majority), can get away + * without locking. + */ + +/*****************************************************************************/ + +/* We have more then 32 logging domains. Assert that it compiles to a 64 bit sized enum */ +G_STATIC_ASSERT (sizeof (NMLogDomain) >= sizeof (guint64)); + +/* Combined domains */ +#define LOGD_ALL_STRING "ALL" +#define LOGD_DEFAULT_STRING "DEFAULT" +#define LOGD_DHCP_STRING "DHCP" +#define LOGD_IP_STRING "IP" + +/*****************************************************************************/ + +typedef enum { + LOG_BACKEND_GLIB, + LOG_BACKEND_SYSLOG, + LOG_BACKEND_JOURNAL, +} LogBackend; typedef struct { NMLogDomain num; @@ -71,6 +106,52 @@ typedef struct { GLogLevelFlags g_log_level; } LogLevelDesc; +typedef struct { + char *logging_domains_to_string; +} GlobalMain; + +typedef struct { + NMLogLevel log_level; + bool uses_syslog:1; + bool init_pre_done:1; + bool init_done:1; + bool debug_stderr:1; + const char *prefix; + const char *syslog_identifier; + + /* before we setup syslog (during start), the backend defaults to GLIB, meaning: + * we use g_log() for all logging. At that point, the application is not yet supposed + * to do any logging and doing so indicates a bug. + * + * Afterwards, the backend is either SYSLOG or JOURNAL. From that point, also + * g_log() is redirected to this backend via a logging handler. */ + LogBackend log_backend; +} Global; + +/*****************************************************************************/ + +G_LOCK_DEFINE_STATIC (log); + +/* This data must only be accessed from the main-thread (and as + * such does not need any lock). */ +static GlobalMain gl_main = { }; + +static union { + /* a union with an immutable and a mutable alias for the Global. + * Since nm-logging must be thread-safe, we must take care at which + * places we only read value ("imm") and where we modify them ("mut"). */ + Global mut; + const Global imm; +} gl = { + .imm = { + /* nm_logging_setup ("INFO", LOGD_DEFAULT_STRING, NULL, NULL); */ + .log_level = LOGL_INFO, + .log_backend = LOG_BACKEND_GLIB, + .syslog_identifier = "SYSLOG_IDENTIFIER="G_LOG_DOMAIN, + .prefix = "", + }, +}; + NMLogDomain _nm_logging_enabled_state[_LOGL_N_REAL] = { /* nm_logging_setup ("INFO", LOGD_DEFAULT_STRING, NULL, NULL); * @@ -81,102 +162,65 @@ NMLogDomain _nm_logging_enabled_state[_LOGL_N_REAL] = { [LOGL_ERR] = LOGD_DEFAULT, }; -static struct Global { - NMLogLevel log_level; - bool uses_syslog:1; - bool syslog_identifier_initialized:1; - bool debug_stderr:1; - const char *prefix; - const char *syslog_identifier; - enum { - /* before we setup syslog (during start), the backend defaults to GLIB, meaning: - * we use g_log() for all logging. At that point, the application is not yet supposed - * to do any logging and doing so indicates a bug. - * - * Afterwards, the backend is either SYSLOG or JOURNAL. From that point, also - * g_log() is redirected to this backend via a logging handler. */ - LOG_BACKEND_GLIB, - LOG_BACKEND_SYSLOG, - LOG_BACKEND_JOURNAL, - } log_backend; - char *logging_domains_to_string; - const LogLevelDesc level_desc[_LOGL_N]; - -#define _DOMAIN_DESC_LEN 39 - /* Would be nice to use C99 flexible array member here, - * but that feature doesn't seem well supported. */ - const LogDesc domain_desc[_DOMAIN_DESC_LEN]; -} global = { - /* nm_logging_setup ("INFO", LOGD_DEFAULT_STRING, NULL, NULL); */ - .log_level = LOGL_INFO, - .log_backend = LOG_BACKEND_GLIB, - .syslog_identifier = "SYSLOG_IDENTIFIER="G_LOG_DOMAIN, - .prefix = "", - .level_desc = { - [LOGL_TRACE] = { "TRACE", "<trace>", LOG_DEBUG, G_LOG_LEVEL_DEBUG, }, - [LOGL_DEBUG] = { "DEBUG", "<debug>", LOG_DEBUG, G_LOG_LEVEL_DEBUG, }, - [LOGL_INFO] = { "INFO", "<info>", LOG_INFO, G_LOG_LEVEL_INFO, }, - [LOGL_WARN] = { "WARN", "<warn>", LOG_WARNING, G_LOG_LEVEL_MESSAGE, }, - [LOGL_ERR] = { "ERR", "<error>", LOG_ERR, G_LOG_LEVEL_MESSAGE, }, - [_LOGL_OFF] = { "OFF", NULL, 0, 0, }, - [_LOGL_KEEP] = { "KEEP", NULL, 0, 0, }, - }, - .domain_desc = { - { LOGD_PLATFORM, "PLATFORM" }, - { LOGD_RFKILL, "RFKILL" }, - { LOGD_ETHER, "ETHER" }, - { LOGD_WIFI, "WIFI" }, - { LOGD_BT, "BT" }, - { LOGD_MB, "MB" }, - { LOGD_DHCP4, "DHCP4" }, - { LOGD_DHCP6, "DHCP6" }, - { LOGD_PPP, "PPP" }, - { LOGD_WIFI_SCAN, "WIFI_SCAN" }, - { LOGD_IP4, "IP4" }, - { LOGD_IP6, "IP6" }, - { LOGD_AUTOIP4, "AUTOIP4" }, - { LOGD_DNS, "DNS" }, - { LOGD_VPN, "VPN" }, - { LOGD_SHARING, "SHARING" }, - { LOGD_SUPPLICANT,"SUPPLICANT" }, - { LOGD_AGENTS, "AGENTS" }, - { LOGD_SETTINGS, "SETTINGS" }, - { LOGD_SUSPEND, "SUSPEND" }, - { LOGD_CORE, "CORE" }, - { LOGD_DEVICE, "DEVICE" }, - { LOGD_OLPC, "OLPC" }, - { LOGD_INFINIBAND,"INFINIBAND" }, - { LOGD_FIREWALL, "FIREWALL" }, - { LOGD_ADSL, "ADSL" }, - { LOGD_BOND, "BOND" }, - { LOGD_VLAN, "VLAN" }, - { LOGD_BRIDGE, "BRIDGE" }, - { LOGD_DBUS_PROPS,"DBUS_PROPS" }, - { LOGD_TEAM, "TEAM" }, - { LOGD_CONCHECK, "CONCHECK" }, - { LOGD_DCB, "DCB" }, - { LOGD_DISPATCH, "DISPATCH" }, - { LOGD_AUDIT, "AUDIT" }, - { LOGD_SYSTEMD, "SYSTEMD" }, - { LOGD_VPN_PLUGIN,"VPN_PLUGIN" }, - { LOGD_PROXY, "PROXY" }, - { 0, NULL } - /* keep _DOMAIN_DESC_LEN in sync */ - }, -}; +/*****************************************************************************/ -/* We have more then 32 logging domains. Assert that it compiles to a 64 bit sized enum */ -G_STATIC_ASSERT (sizeof (NMLogDomain) >= sizeof (guint64)); +static const LogLevelDesc level_desc[_LOGL_N] = { + [LOGL_TRACE] = { "TRACE", "<trace>", LOG_DEBUG, G_LOG_LEVEL_DEBUG, }, + [LOGL_DEBUG] = { "DEBUG", "<debug>", LOG_DEBUG, G_LOG_LEVEL_DEBUG, }, + [LOGL_INFO] = { "INFO", "<info>", LOG_INFO, G_LOG_LEVEL_INFO, }, + [LOGL_WARN] = { "WARN", "<warn>", LOG_WARNING, G_LOG_LEVEL_MESSAGE, }, + [LOGL_ERR] = { "ERR", "<error>", LOG_ERR, G_LOG_LEVEL_MESSAGE, }, + [_LOGL_OFF] = { "OFF", NULL, 0, 0, }, + [_LOGL_KEEP] = { "KEEP", NULL, 0, 0, }, +}; -/* Combined domains */ -#define LOGD_ALL_STRING "ALL" -#define LOGD_DEFAULT_STRING "DEFAULT" -#define LOGD_DHCP_STRING "DHCP" -#define LOGD_IP_STRING "IP" +static const LogDesc domain_desc[] = { + { LOGD_PLATFORM, "PLATFORM" }, + { LOGD_RFKILL, "RFKILL" }, + { LOGD_ETHER, "ETHER" }, + { LOGD_WIFI, "WIFI" }, + { LOGD_BT, "BT" }, + { LOGD_MB, "MB" }, + { LOGD_DHCP4, "DHCP4" }, + { LOGD_DHCP6, "DHCP6" }, + { LOGD_PPP, "PPP" }, + { LOGD_WIFI_SCAN, "WIFI_SCAN" }, + { LOGD_IP4, "IP4" }, + { LOGD_IP6, "IP6" }, + { LOGD_AUTOIP4, "AUTOIP4" }, + { LOGD_DNS, "DNS" }, + { LOGD_VPN, "VPN" }, + { LOGD_SHARING, "SHARING" }, + { LOGD_SUPPLICANT,"SUPPLICANT" }, + { LOGD_AGENTS, "AGENTS" }, + { LOGD_SETTINGS, "SETTINGS" }, + { LOGD_SUSPEND, "SUSPEND" }, + { LOGD_CORE, "CORE" }, + { LOGD_DEVICE, "DEVICE" }, + { LOGD_OLPC, "OLPC" }, + { LOGD_INFINIBAND,"INFINIBAND" }, + { LOGD_FIREWALL, "FIREWALL" }, + { LOGD_ADSL, "ADSL" }, + { LOGD_BOND, "BOND" }, + { LOGD_VLAN, "VLAN" }, + { LOGD_BRIDGE, "BRIDGE" }, + { LOGD_DBUS_PROPS,"DBUS_PROPS" }, + { LOGD_TEAM, "TEAM" }, + { LOGD_CONCHECK, "CONCHECK" }, + { LOGD_DCB, "DCB" }, + { LOGD_DISPATCH, "DISPATCH" }, + { LOGD_AUDIT, "AUDIT" }, + { LOGD_SYSTEMD, "SYSTEMD" }, + { LOGD_VPN_PLUGIN,"VPN_PLUGIN" }, + { LOGD_PROXY, "PROXY" }, + { 0 }, +}; /*****************************************************************************/ -static char *_domains_to_string (gboolean include_level_override); +static char *_domains_to_string (gboolean include_level_override, + NMLogLevel log_level, + const NMLogDomain log_state[static _LOGL_N_REAL]); /*****************************************************************************/ @@ -202,48 +246,30 @@ _syslog_identifier_valid_domain (const char *domain) } static gboolean -_syslog_identifier_assert (const struct Global *gl) +_syslog_identifier_assert (const char *syslog_identifier) { - g_assert (gl); - g_assert (gl->syslog_identifier); - g_assert (g_str_has_prefix (gl->syslog_identifier, "SYSLOG_IDENTIFIER=")); - g_assert (_syslog_identifier_valid_domain (&gl->syslog_identifier[NM_STRLEN ("SYSLOG_IDENTIFIER=")])); + g_assert (syslog_identifier); + g_assert (g_str_has_prefix (syslog_identifier, "SYSLOG_IDENTIFIER=")); + g_assert (_syslog_identifier_valid_domain (&syslog_identifier[NM_STRLEN ("SYSLOG_IDENTIFIER=")])); return TRUE; } static const char * -syslog_identifier_domain (const struct Global *gl) +syslog_identifier_domain (const char *syslog_identifier) { - nm_assert (_syslog_identifier_assert (gl)); - return &gl->syslog_identifier[NM_STRLEN ("SYSLOG_IDENTIFIER=")]; + nm_assert (_syslog_identifier_assert (syslog_identifier)); + return &syslog_identifier[NM_STRLEN ("SYSLOG_IDENTIFIER=")]; } #if SYSTEMD_JOURNAL static const char * -syslog_identifier_full (const struct Global *gl) +syslog_identifier_full (const char *syslog_identifier) { - nm_assert (_syslog_identifier_assert (gl)); - return &gl->syslog_identifier[0]; + nm_assert (_syslog_identifier_assert (syslog_identifier)); + return &syslog_identifier[0]; } #endif -void -nm_logging_set_syslog_identifier (const char *domain) -{ - if (global.log_backend != LOG_BACKEND_GLIB) - g_return_if_reached (); - - if (!_syslog_identifier_valid_domain (domain)) - g_return_if_reached (); - - if (global.syslog_identifier_initialized) - g_return_if_reached (); - - global.syslog_identifier_initialized = TRUE; - global.syslog_identifier = g_strdup_printf ("SYSLOG_IDENTIFIER=%s", domain); - nm_assert (_syslog_identifier_assert (&global)); -} - /*****************************************************************************/ static gboolean @@ -253,8 +279,8 @@ match_log_level (const char *level, { int i; - for (i = 0; i < G_N_ELEMENTS (global.level_desc); i++) { - if (!g_ascii_strcasecmp (global.level_desc[i].name, level)) { + for (i = 0; i < G_N_ELEMENTS (level_desc); i++) { + if (!g_ascii_strcasecmp (level_desc[i].name, level)) { *out_level = i; return TRUE; } @@ -272,31 +298,42 @@ nm_logging_setup (const char *level, GError **error) { GString *unrecognized = NULL; - NMLogDomain new_logging[G_N_ELEMENTS (_nm_logging_enabled_state)]; - NMLogLevel new_log_level = global.log_level; + NMLogDomain cur_log_state[_LOGL_N_REAL]; + NMLogDomain new_log_state[_LOGL_N_REAL]; + NMLogLevel cur_log_level; + NMLogLevel new_log_level; char **tmp, **iter; int i; gboolean had_platform_debug; gs_free char *domains_free = NULL; + NM_ASSERT_ON_MAIN_THREAD (); + g_return_val_if_fail (!bad_domains || !*bad_domains, FALSE); g_return_val_if_fail (!error || !*error, FALSE); - /* domains */ - if (!domains || !*domains) - domains = (domains_free = _domains_to_string (FALSE)); + cur_log_level = gl.imm.log_level; + memcpy (cur_log_state, _nm_logging_enabled_state, sizeof (cur_log_state)); - for (i = 0; i < G_N_ELEMENTS (new_logging); i++) - new_logging[i] = 0; + new_log_level = cur_log_level; + + if (!domains || !*domains) { + domains_free = _domains_to_string (FALSE, + cur_log_level, + cur_log_state); + domains = domains_free; + } + + for (i = 0; i < G_N_ELEMENTS (new_log_state); i++) + new_log_state[i] = 0; - /* levels */ if (level && *level) { if (!match_log_level (level, &new_log_level, error)) return FALSE; if (new_log_level == _LOGL_KEEP) { - new_log_level = global.log_level; - for (i = 0; i < G_N_ELEMENTS (new_logging); i++) - new_logging[i] = _nm_logging_enabled_state[i]; + new_log_level = cur_log_level; + for (i = 0; i < G_N_ELEMENTS (new_log_state); i++) + new_log_state[i] = cur_log_state[i]; } } @@ -353,7 +390,7 @@ nm_logging_setup (const char *level, continue; else { - for (diter = &global.domain_desc[0]; diter->name; diter++) { + for (diter = &domain_desc[0]; diter->name; diter++) { if (!g_ascii_strcasecmp (diter->name, *iter)) { bits = diter->num; break; @@ -377,34 +414,37 @@ nm_logging_setup (const char *level, } if (domain_log_level == _LOGL_KEEP) { - for (i = 0; i < G_N_ELEMENTS (new_logging); i++) - new_logging[i] = (new_logging[i] & ~bits) | (_nm_logging_enabled_state[i] & bits); + for (i = 0; i < G_N_ELEMENTS (new_log_state); i++) + new_log_state[i] = (new_log_state[i] & ~bits) | (cur_log_state[i] & bits); } else { - for (i = 0; i < G_N_ELEMENTS (new_logging); i++) { + for (i = 0; i < G_N_ELEMENTS (new_log_state); i++) { if (i < domain_log_level) - new_logging[i] &= ~bits; + new_log_state[i] &= ~bits; else { - new_logging[i] |= bits; + new_log_state[i] |= bits; if ( (protect & bits) && i < LOGL_INFO) - new_logging[i] &= ~protect; + new_log_state[i] &= ~protect; } } } } g_strfreev (tmp); - g_clear_pointer (&global.logging_domains_to_string, g_free); + g_clear_pointer (&gl_main.logging_domains_to_string, g_free); + + had_platform_debug = _nm_logging_enabled_lockfree (LOGL_DEBUG, LOGD_PLATFORM); + + G_LOCK (log); - had_platform_debug = nm_logging_enabled (LOGL_DEBUG, LOGD_PLATFORM); + gl.mut.log_level = new_log_level; + for (i = 0; i < G_N_ELEMENTS (new_log_state); i++) + _nm_logging_enabled_state[i] = new_log_state[i]; - global.log_level = new_log_level; - for (i = 0; i < G_N_ELEMENTS (new_logging); i++) - _nm_logging_enabled_state[i] = new_logging[i]; + G_UNLOCK (log); if ( had_platform_debug - && _nm_logging_clear_platform_logging_cache - && !nm_logging_enabled (LOGL_DEBUG, LOGD_PLATFORM)) { + && !_nm_logging_enabled_lockfree (LOGL_DEBUG, LOGD_PLATFORM)) { /* when debug logging is enabled, platform will cache all access to * sysctl. When the user disables debug-logging, we want to clear that * cache right away. */ @@ -420,7 +460,9 @@ nm_logging_setup (const char *level, const char * nm_logging_level_to_string (void) { - return global.level_desc[global.log_level].name; + NM_ASSERT_ON_MAIN_THREAD (); + + return level_desc[gl.imm.log_level].name; } const char * @@ -432,10 +474,10 @@ nm_logging_all_levels_to_string (void) int i; str = g_string_new (NULL); - for (i = 0; i < G_N_ELEMENTS (global.level_desc); i++) { + for (i = 0; i < G_N_ELEMENTS (level_desc); i++) { if (str->len) g_string_append_c (str, ','); - g_string_append (str, global.level_desc[i].name); + g_string_append (str, level_desc[i].name); } } @@ -445,27 +487,34 @@ nm_logging_all_levels_to_string (void) const char * nm_logging_domains_to_string (void) { - if (G_UNLIKELY (!global.logging_domains_to_string)) - global.logging_domains_to_string = _domains_to_string (TRUE); + NM_ASSERT_ON_MAIN_THREAD (); + + if (G_UNLIKELY (!gl_main.logging_domains_to_string)) { + gl_main.logging_domains_to_string = _domains_to_string (TRUE, + gl.imm.log_level, + _nm_logging_enabled_state); + } - return global.logging_domains_to_string; + return gl_main.logging_domains_to_string; } static char * -_domains_to_string (gboolean include_level_override) +_domains_to_string (gboolean include_level_override, + NMLogLevel log_level, + const NMLogDomain log_state[static _LOGL_N_REAL]) { const LogDesc *diter; GString *str; int i; - /* We don't just return g_strdup (global.log_domains) because we want to expand - * "DEFAULT" and "ALL". + /* We don't just return g_strdup() the logging domains that were set during + * nm_logging_setup(), because we want to expand "DEFAULT" and "ALL". */ str = g_string_sized_new (75); - for (diter = &global.domain_desc[0]; diter->name; diter++) { + for (diter = &domain_desc[0]; diter->name; diter++) { /* If it's set for any lower level, it will also be set for LOGL_ERR */ - if (!(diter->num & _nm_logging_enabled_state[LOGL_ERR])) + if (!(diter->num & log_state[LOGL_ERR])) continue; if (str->len) @@ -476,17 +525,17 @@ _domains_to_string (gboolean include_level_override) continue; /* Check if it's logging at a lower level than the default. */ - for (i = 0; i < global.log_level; i++) { - if (diter->num & _nm_logging_enabled_state[i]) { - g_string_append_printf (str, ":%s", global.level_desc[i].name); + for (i = 0; i < log_level; i++) { + if (diter->num & log_state[i]) { + g_string_append_printf (str, ":%s", level_desc[i].name); break; } } /* Check if it's logging at a higher level than the default. */ - if (!(diter->num & _nm_logging_enabled_state[global.log_level])) { - for (i = global.log_level + 1; i < G_N_ELEMENTS (_nm_logging_enabled_state); i++) { - if (diter->num & _nm_logging_enabled_state[i]) { - g_string_append_printf (str, ":%s", global.level_desc[i].name); + if (!(diter->num & log_state[log_level])) { + for (i = log_level + 1; i < _LOGL_N_REAL; i++) { + if (diter->num & log_state[i]) { + g_string_append_printf (str, ":%s", level_desc[i].name); break; } } @@ -504,7 +553,7 @@ nm_logging_all_domains_to_string (void) const LogDesc *diter; str = g_string_new (LOGD_DEFAULT_STRING); - for (diter = &global.domain_desc[0]; diter->name; diter++) { + for (diter = &domain_desc[0]; diter->name; diter++) { g_string_append_c (str, ','); g_string_append (str, diter->name); if (diter->num == LOGD_DHCP6) @@ -534,16 +583,29 @@ nm_logging_get_level (NMLogDomain domain) G_STATIC_ASSERT (LOGL_TRACE == 0); while ( sl > LOGL_TRACE - && nm_logging_enabled (sl - 1, domain)) + && _nm_logging_enabled_lockfree (sl - 1, domain)) sl--; return sl; } gboolean -_nm_log_enabled (NMLogLevel level, - NMLogDomain domain) +_nm_logging_enabled_locking (NMLogLevel level, + NMLogDomain domain) { - return nm_logging_enabled (level, domain); + gboolean v; + + G_LOCK (log); + v = _nm_logging_enabled_lockfree (level, domain); + G_UNLOCK (log); + return v; +} + +gboolean +_nm_log_enabled_impl (gboolean mt_require_locking, + NMLogLevel level, + NMLogDomain domain) +{ + return nm_logging_enabled_mt (mt_require_locking, level, domain); } #if SYSTEMD_JOURNAL @@ -606,6 +668,7 @@ void _nm_log_impl (const char *file, guint line, const char *func, + gboolean mt_require_locking, NMLogLevel level, NMLogDomain domain, int error, @@ -617,15 +680,37 @@ _nm_log_impl (const char *file, va_list args; char *msg; GTimeVal tv; - int errno_saved; - - if ((guint) level >= G_N_ELEMENTS (_nm_logging_enabled_state)) - g_return_if_reached (); + int errsv; + const NMLogDomain *cur_log_state; + NMLogDomain cur_log_state_copy[_LOGL_N_REAL]; + Global g_copy; + const Global *g; + + if (G_UNLIKELY (mt_require_locking)) { + G_LOCK (log); + /* we evaluate logging-enabled under lock. There is still a race that + * we might log the message below *after* logging was disabled. That means, + * when disabling logging, we might still log messages. */ + if (!_nm_logging_enabled_lockfree (level, domain)) { + G_UNLOCK (log); + return; + } + g_copy = gl.imm; + memcpy (cur_log_state_copy, _nm_logging_enabled_state, sizeof (cur_log_state_copy)); + G_UNLOCK (log); + g = &g_copy; + cur_log_state = cur_log_state_copy; + } else { + NM_ASSERT_ON_MAIN_THREAD (); + if (!_nm_logging_enabled_lockfree (level, domain)) + return; + g = &gl.imm; + cur_log_state = _nm_logging_enabled_state; + } - if (!(_nm_logging_enabled_state[level] & domain)) - return; + (void) cur_log_state; - errno_saved = errno; + errsv = errno; /* Make sure that %m maps to the specified error */ if (error != 0) { @@ -639,19 +724,19 @@ _nm_log_impl (const char *file, va_end (args); #define MESSAGE_FMT "%s%-7s [%ld.%04ld] %s" -#define MESSAGE_ARG(global, tv, msg) \ - (global).prefix, \ - (global).level_desc[level].level_str, \ +#define MESSAGE_ARG(prefix, tv, msg) \ + prefix, \ + level_desc[level].level_str, \ (tv).tv_sec, \ ((tv).tv_usec / 100), \ (msg) g_get_current_time (&tv); - if (global.debug_stderr) - g_printerr (MESSAGE_FMT"\n", MESSAGE_ARG (global, tv, msg)); + if (g->debug_stderr) + g_printerr (MESSAGE_FMT"\n", MESSAGE_ARG (g->prefix, tv, msg)); - switch (global.log_backend) { + switch (g->log_backend) { #if SYSTEMD_JOURNAL case LOG_BACKEND_JOURNAL: { @@ -666,18 +751,18 @@ _nm_log_impl (const char *file, now = nm_utils_get_monotonic_timestamp_ns (); boottime = nm_utils_monotonic_timestamp_as_boottime (now, 1); - _iovec_set_format_a (iov++, 30, "PRIORITY=%d", global.level_desc[level].syslog_level); - _iovec_set_format (iov++, iov_free++, "MESSAGE="MESSAGE_FMT, MESSAGE_ARG (global, tv, msg)); - _iovec_set_string (iov++, syslog_identifier_full (&global)); + _iovec_set_format_a (iov++, 30, "PRIORITY=%d", level_desc[level].syslog_level); + _iovec_set_format (iov++, iov_free++, "MESSAGE="MESSAGE_FMT, MESSAGE_ARG (g->prefix, tv, msg)); + _iovec_set_string (iov++, syslog_identifier_full (g->syslog_identifier)); _iovec_set_format_a (iov++, 30, "SYSLOG_PID=%ld", (long) getpid ()); { const LogDesc *diter; int i_domain = _NUM_MAX_FIELDS_SYSLOG_FACILITY; const char *s_domain_1 = NULL; NMLogDomain dom_all = domain; - NMLogDomain dom = dom_all & _nm_logging_enabled_state[level]; + NMLogDomain dom = dom_all & cur_log_state[level]; - for (diter = &global.domain_desc[0]; diter->name; diter++) { + for (diter = &domain_desc[0]; diter->name; diter++) { if (!NM_FLAGS_ANY (dom_all, diter->num)) continue; @@ -712,7 +797,7 @@ _nm_log_impl (const char *file, else _iovec_set_format_str_a (iov++, 30, "NM_LOG_DOMAINS=%s", s_domain_1); } - _iovec_set_format_str_a (iov++, 15, "NM_LOG_LEVEL=%s", global.level_desc[level].name); + _iovec_set_format_str_a (iov++, 15, "NM_LOG_LEVEL=%s", level_desc[level].name); if (func) _iovec_set_format (iov++, iov_free++, "CODE_FUNC=%s", func); _iovec_set_format (iov++, iov_free++, "CODE_FILE=%s", file ?: ""); @@ -737,18 +822,18 @@ _nm_log_impl (const char *file, break; #endif case LOG_BACKEND_SYSLOG: - syslog (global.level_desc[level].syslog_level, - MESSAGE_FMT, MESSAGE_ARG (global, tv, msg)); + syslog (level_desc[level].syslog_level, + MESSAGE_FMT, MESSAGE_ARG (g->prefix, tv, msg)); break; default: - g_log (syslog_identifier_domain (&global), global.level_desc[level].g_log_level, - MESSAGE_FMT, MESSAGE_ARG (global, tv, msg)); + g_log (syslog_identifier_domain (g->syslog_identifier), level_desc[level].g_log_level, + MESSAGE_FMT, MESSAGE_ARG (g->prefix, tv, msg)); break; } g_free (msg); - errno = errno_saved; + errno = errsv; } /*****************************************************************************/ @@ -758,7 +843,9 @@ _nm_utils_monotonic_timestamp_initialized (const struct timespec *tp, gint64 offset_sec, gboolean is_boottime) { - if (nm_logging_enabled (LOGL_DEBUG, LOGD_CORE)) { + NM_ASSERT_ON_MAIN_THREAD (); + + if (_nm_logging_enabled_lockfree (LOGL_DEBUG, LOGD_CORE)) { time_t now = time (NULL); struct tm tm; char s[255]; @@ -804,10 +891,14 @@ nm_log_handler (const char *log_domain, break; } - if (global.debug_stderr) - g_printerr ("%s%s\n", global.prefix, message ?: ""); + /* we don't need any locking here. The glib log handler gets only registered + * once during nm_logging_init() and the global data is not modified afterwards. */ + nm_assert (gl.imm.init_done); - switch (global.log_backend) { + if (gl.imm.debug_stderr) + g_printerr ("%s%s\n", gl.imm.prefix, message ?: ""); + + switch (gl.imm.log_backend) { #if SYSTEMD_JOURNAL case LOG_BACKEND_JOURNAL: { @@ -817,8 +908,8 @@ nm_log_handler (const char *log_domain, boottime = nm_utils_monotonic_timestamp_as_boottime (now, 1); sd_journal_send ("PRIORITY=%d", syslog_priority, - "MESSAGE=%s%s", global.prefix, message ?: "", - syslog_identifier_full (&global), + "MESSAGE=%s%s", gl.imm.prefix, message ?: "", + syslog_identifier_full (gl.imm.syslog_identifier), "SYSLOG_PID=%ld", (long) getpid (), "SYSLOG_FACILITY=GLIB", "GLIB_DOMAIN=%s", log_domain ?: "", @@ -830,7 +921,7 @@ nm_log_handler (const char *log_domain, break; #endif default: - syslog (syslog_priority, "%s%s", global.prefix, message ?: ""); + syslog (syslog_priority, "%s%s", gl.imm.prefix, message ?: ""); break; } } @@ -838,44 +929,63 @@ nm_log_handler (const char *log_domain, gboolean nm_logging_syslog_enabled (void) { - return global.uses_syslog; + NM_ASSERT_ON_MAIN_THREAD (); + + return gl.imm.uses_syslog; } void -nm_logging_set_prefix (const char *format, ...) +nm_logging_init_pre (const char *syslog_identifier, + char *prefix_take) { - char *prefix; - va_list ap; + /* this function may be called zero or one times, and only + * - on the main thread + * - not after nm_logging_init(). */ + + NM_ASSERT_ON_MAIN_THREAD (); - /* prefix can only be set once, to a non-empty string. Also, after - * nm_logging_syslog_openlog() the prefix cannot be set either. */ - if (global.log_backend != LOG_BACKEND_GLIB) + if (gl.imm.init_pre_done) g_return_if_reached (); - if (global.prefix[0]) + + if (gl.imm.init_done) g_return_if_reached (); - va_start (ap, format); - prefix = g_strdup_vprintf (format, ap); - va_end (ap); + if (!_syslog_identifier_valid_domain (syslog_identifier)) + g_return_if_reached (); - if (!prefix || !prefix[0]) + if (!prefix_take || !prefix_take[0]) g_return_if_reached (); + G_LOCK (log); + + gl.mut.init_pre_done = TRUE; + + gl.mut.syslog_identifier = g_strdup_printf ("SYSLOG_IDENTIFIER=%s", syslog_identifier); + nm_assert (_syslog_identifier_assert (gl.imm.syslog_identifier)); + /* we pass the allocated string on and never free it. */ - global.prefix = prefix; + gl.mut.prefix = prefix_take; + + G_UNLOCK (log); } void -nm_logging_syslog_openlog (const char *logging_backend, gboolean debug) +nm_logging_init (const char *logging_backend, gboolean debug) { gboolean fetch_monotonic_timestamp = FALSE; gboolean obsolete_debug_backend = FALSE; + LogBackend x_log_backend; + + /* this function may be called zero or one times, and only on the + * main thread. */ + + NM_ASSERT_ON_MAIN_THREAD (); nm_assert (NM_IN_STRSET (""NM_CONFIG_DEFAULT_LOGGING_BACKEND, NM_LOG_CONFIG_BACKEND_JOURNAL, NM_LOG_CONFIG_BACKEND_SYSLOG)); - if (global.log_backend != LOG_BACKEND_GLIB) + if (gl.imm.init_done) g_return_if_reached (); if (!logging_backend) @@ -892,26 +1002,36 @@ nm_logging_syslog_openlog (const char *logging_backend, gboolean debug) obsolete_debug_backend = TRUE; } + + G_LOCK (log); + #if SYSTEMD_JOURNAL if (!nm_streq (logging_backend, NM_LOG_CONFIG_BACKEND_SYSLOG)) { - global.log_backend = LOG_BACKEND_JOURNAL; - global.uses_syslog = TRUE; - global.debug_stderr = debug; + x_log_backend = LOG_BACKEND_JOURNAL; + + /* We only log the monotonic-timestamp with structured logging (journal). + * Only in this case, fetch the timestamp. */ fetch_monotonic_timestamp = TRUE; } else #endif { - global.log_backend = LOG_BACKEND_SYSLOG; - global.uses_syslog = TRUE; - global.debug_stderr = debug; - openlog (syslog_identifier_domain (&global), LOG_PID, LOG_DAEMON); + x_log_backend = LOG_BACKEND_SYSLOG; + openlog (syslog_identifier_domain (gl.imm.syslog_identifier), LOG_PID, LOG_DAEMON); } - g_log_set_handler (syslog_identifier_domain (&global), + gl.mut.init_done = TRUE; + gl.mut.log_backend = x_log_backend; + gl.mut.uses_syslog = TRUE; + gl.mut.debug_stderr = debug; + + g_log_set_handler (syslog_identifier_domain (gl.imm.syslog_identifier), G_LOG_LEVEL_MASK | G_LOG_FLAG_FATAL | G_LOG_FLAG_RECURSION, nm_log_handler, NULL); + G_UNLOCK (log); + + if (fetch_monotonic_timestamp) { /* ensure we read a monotonic timestamp. Reading the timestamp the first * time causes a logging message. We don't want to do that during _nm_log_impl. */ diff --git a/src/nm-logging.h b/src/nm-logging.h index 21263c7b..a824890a 100644 --- a/src/nm-logging.h +++ b/src/nm-logging.h @@ -54,10 +54,12 @@ LOGD_IP_from_af (int addr_family) /* A wrapper for the _nm_log_impl() function that adds call site information. * Contrary to nm_log(), it unconditionally calls the function without * checking whether logging for the given level and domain is enabled. */ -#define _nm_log(level, domain, error, ifname, con_uuid, ...) \ +#define _nm_log_mt(mt_require_locking, level, domain, error, ifname, con_uuid, ...) \ G_STMT_START { \ - _nm_log_impl (__FILE__, __LINE__, \ + _nm_log_impl (__FILE__, \ + __LINE__, \ _NM_LOG_FUNC, \ + (mt_require_locking), \ (level), \ (domain), \ (error), \ @@ -66,6 +68,9 @@ LOGD_IP_from_af (int addr_family) ""__VA_ARGS__); \ } G_STMT_END +#define _nm_log(level, domain, error, ifname, con_uuid, ...) \ + _nm_log_mt (!(NM_THREAD_SAFE_ON_MAIN_THREAD), level, domain, error, ifname, con_uuid, __VA_ARGS__) + /* nm_log() only evaluates its argument list after checking * whether logging for the given level/domain is enabled. */ #define nm_log(level, domain, ifname, con_uuid, ...) \ @@ -138,15 +143,35 @@ _nm_log_ptr_is_debug (NMLogLevel level) const char *nm_logging_level_to_string (void); const char *nm_logging_domains_to_string (void); +/*****************************************************************************/ + extern NMLogDomain _nm_logging_enabled_state[_LOGL_N_REAL]; + static inline gboolean -nm_logging_enabled (NMLogLevel level, NMLogDomain domain) +_nm_logging_enabled_lockfree (NMLogLevel level, NMLogDomain domain) { nm_assert (((guint) level) < G_N_ELEMENTS (_nm_logging_enabled_state)); return (((guint) level) < G_N_ELEMENTS (_nm_logging_enabled_state)) && !!(_nm_logging_enabled_state[level] & domain); } +gboolean _nm_logging_enabled_locking (NMLogLevel level, NMLogDomain domain); + +static inline gboolean +nm_logging_enabled_mt (gboolean mt_require_locking, NMLogLevel level, NMLogDomain domain) +{ + if (mt_require_locking) + return _nm_logging_enabled_locking (level, domain); + + NM_ASSERT_ON_MAIN_THREAD (); + return _nm_logging_enabled_lockfree (level, domain); +} + +#define nm_logging_enabled(level, domain) \ + nm_logging_enabled_mt (!(NM_THREAD_SAFE_ON_MAIN_THREAD), level, domain) + +/*****************************************************************************/ + NMLogLevel nm_logging_get_level (NMLogDomain domain); const char *nm_logging_all_levels_to_string (void); @@ -157,10 +182,11 @@ gboolean nm_logging_setup (const char *level, char **bad_domains, GError **error); -void nm_logging_set_syslog_identifier (const char *domain); -void nm_logging_set_prefix (const char *format, ...) _nm_printf (1, 2); +void nm_logging_init_pre (const char *syslog_identifier, + char *prefix_take); + +void nm_logging_init (const char *logging_backend, gboolean debug); -void nm_logging_syslog_openlog (const char *logging_backend, gboolean debug); gboolean nm_logging_syslog_enabled (void); /*****************************************************************************/ @@ -271,8 +297,6 @@ gboolean nm_logging_syslog_enabled (void); #define _LOG3t_err(errsv, ...) G_STMT_START { if (FALSE) { _NMLOG3_err (errsv, LOGL_TRACE, __VA_ARGS__); } } G_STMT_END #endif -extern void (*_nm_logging_clear_platform_logging_cache) (void); - /*****************************************************************************/ #define __NMLOG_DEFAULT(level, domain, prefix, ...) \ @@ -292,4 +316,8 @@ extern void (*_nm_logging_clear_platform_logging_cache) (void); _NM_UTILS_MACRO_REST(__VA_ARGS__)); \ } G_STMT_END +/*****************************************************************************/ + +extern void _nm_logging_clear_platform_logging_cache (void); + #endif /* __NETWORKMANAGER_LOGGING_H__ */ diff --git a/src/nm-manager.c b/src/nm-manager.c index 127d47a3..0bf6a751 100644 --- a/src/nm-manager.c +++ b/src/nm-manager.c @@ -25,8 +25,6 @@ #include <stdlib.h> #include <fcntl.h> -#include <errno.h> -#include <string.h> #include <unistd.h> #include "nm-utils/nm-c-list.h" @@ -2489,7 +2487,12 @@ get_existing_connection (NMManager *self, if (ifindex) { int master_ifindex = nm_platform_link_get_master (priv->platform, ifindex); - if (master_ifindex) { + /* Check that the master is activating before assuming a + * slave connection. However, ignore ovs-system master as + * we never manage it. + */ + if ( master_ifindex + && nm_platform_link_get_type (priv->platform, master_ifindex) != NM_LINK_TYPE_OPENVSWITCH) { master = nm_manager_get_device_by_ifindex (self, master_ifindex); if (!master) { _LOG2D (LOGD_DEVICE, device, "assume: don't assume because " @@ -2708,7 +2711,7 @@ recheck_assume_connection (NMManager *self, subject = nm_auth_subject_new_internal (); - /* Note: the lifetime of the activation connection is always bound to the profiles visiblity + /* Note: the lifetime of the activation connection is always bound to the profiles visibility * via NM_ACTIVATION_STATE_FLAG_LIFETIME_BOUND_TO_PROFILE_VISIBILITY. * * This only makes a difference, if the profile actually has "connection.permissions" @@ -3501,7 +3504,7 @@ nm_manager_get_best_device_for_connection (NMManager *self, flags = NM_DEVICE_CHECK_CON_AVAILABLE_NONE; else { /* if the profile is multi-connect=single, we also consider devices which - * are marked as unmanaged. And explicit user-request shows sufficent user + * are marked as unmanaged. And explicit user-request shows sufficient user * intent to make the device managed. * That is also, because we expect that such profile is suitably tied * to the intended device. So when an unmanaged device matches, the user's @@ -4421,7 +4424,7 @@ _activation_bind_lifetime_to_profile_visibility (NMAuthSubject *subject) * logs out, the connection becomes invisible and disconnects. * * - the profile at this time could already be invisible (e.g. if the - * user didn't ceate a proper session (sudo) and manually activates + * user didn't create a proper session (sudo) and manually activates * an invisible profile. In this case, we still want to bind the * lifetime, and it will disconnect after the user logs in and logs * out again. NMKeepAlive takes care of that. @@ -4906,7 +4909,7 @@ fail: * @activation_type: whether to assume the connection. That is, take over gracefully, * non-destructible. * @activation_reason: the reason for activation - * @initial_state_flags: the inital state flags for the activation. + * @initial_state_flags: the initial state flags for the activation. * @error: return location for an error * * Begins a new internally-initiated activation of @sett_conn on @device. @@ -5312,10 +5315,10 @@ activation_add_done (NMSettings *settings, nm_dbus_object_get_path (NM_DBUS_OBJECT (new_connection)), nm_dbus_object_get_path (NM_DBUS_OBJECT (active))); } else { - result_floating = g_variant_new ("(ooa{sv})", + result_floating = g_variant_new ("(oo@a{sv})", nm_dbus_object_get_path (NM_DBUS_OBJECT (new_connection)), nm_dbus_object_get_path (NM_DBUS_OBJECT (active)), - g_variant_new_array (G_VARIANT_TYPE ("a{sv}"), NULL, 0)); + g_variant_new_array (G_VARIANT_TYPE ("{sv}"), NULL, 0)); } g_dbus_method_invocation_return_value (context, result_floating); @@ -7186,10 +7189,10 @@ rfkill_change (NMManager *self, const char *desc, RfKillType rtype, gboolean ena int fd; struct rfkill_event event; ssize_t len; + int errsv; g_return_if_fail (rtype == RFKILL_TYPE_WLAN || rtype == RFKILL_TYPE_WWAN); - errno = 0; fd = open ("/dev/rfkill", O_RDWR | O_CLOEXEC); if (fd < 0) { if (errno == EACCES) @@ -7220,8 +7223,9 @@ rfkill_change (NMManager *self, const char *desc, RfKillType rtype, gboolean ena len = write (fd, &event, sizeof (event)); if (len < 0) { + errsv = errno; _LOGW (LOGD_RFKILL, "rfkill: (%s): failed to change Wi-Fi killswitch state: (%d) %s", - desc, errno, g_strerror (errno)); + desc, errsv, nm_strerror_native (errsv)); } else if (len == sizeof (event)) { _LOGI (LOGD_RFKILL, "rfkill: %s hardware radio set %s", desc, enabled ? "enabled" : "disabled"); diff --git a/src/nm-policy.c b/src/nm-policy.c index 77fc929c..540f4065 100644 --- a/src/nm-policy.c +++ b/src/nm-policy.c @@ -23,9 +23,7 @@ #include "nm-policy.h" -#include <string.h> #include <unistd.h> -#include <errno.h> #include <netdb.h> #include "NetworkManagerUtils.h" @@ -151,6 +149,25 @@ static NMDevice *get_default_device (NMPolicy *self, int addr_family); /*****************************************************************************/ +static void +_dns_manager_set_ip_config (NMDnsManager *dns_manager, + NMIPConfig *ip_config, + NMDnsIPConfigType ip_config_type, + NMDevice *device) +{ + if ( NM_IN_SET (ip_config_type, NM_DNS_IP_CONFIG_TYPE_DEFAULT, + NM_DNS_IP_CONFIG_TYPE_BEST_DEVICE) + && device + && nm_device_get_route_metric_default (nm_device_get_device_type (device)) == NM_VPN_ROUTE_METRIC_DEFAULT) { + /* some device types are inherently VPN. */ + ip_config_type = NM_DNS_IP_CONFIG_TYPE_VPN; + } + + nm_dns_manager_set_ip_config (dns_manager, ip_config, ip_config_type); +} + +/*****************************************************************************/ + typedef struct { NMPlatformIP6Address prefix; NMDevice *device; /* The requesting ("uplink") device */ @@ -508,15 +525,15 @@ settings_set_hostname_cb (const char *hostname, NMPolicy *self = NM_POLICY (user_data); NMPolicyPrivate *priv = NM_POLICY_GET_PRIVATE (self); int ret = 0; + int errsv; if (!result) { _LOGT (LOGD_DNS, "set-hostname: hostname set via dbus failed, fallback to \"sethostname\""); ret = sethostname (hostname, strlen (hostname)); if (ret != 0) { - int errsv = errno; - + errsv = errno; _LOGW (LOGD_DNS, "set-hostname: couldn't set the system hostname to '%s': (%d) %s", - hostname, errsv, strerror (errsv)); + hostname, errsv, nm_strerror_native (errsv)); if (errsv == EPERM) _LOGW (LOGD_DNS, "set-hostname: you should use hostnamed when systemd hardening is in effect!"); } @@ -535,6 +552,7 @@ _get_hostname (NMPolicy *self) { NMPolicyPrivate *priv = NM_POLICY_GET_PRIVATE (self); char *hostname = NULL; + int errsv; /* If there is an in-progress hostname change, return * the last hostname set as would be set soon... @@ -553,10 +571,9 @@ _get_hostname (NMPolicy *self) /* ...or retrieve it by yourself */ hostname = g_malloc (HOST_NAME_BUFSIZE); if (gethostname (hostname, HOST_NAME_BUFSIZE -1) != 0) { - int errsv = errno; - + errsv = errno; _LOGT (LOGD_DNS, "get-hostname: couldn't get the system hostname: (%d) %s", - errsv, g_strerror (errsv)); + errsv, nm_strerror_native (errsv)); g_free (hostname); return NULL; } @@ -1092,19 +1109,21 @@ update_ip_dns (NMPolicy *self, int addr_family) gpointer ip_config; const char *ip_iface = NULL; NMVpnConnection *vpn = NULL; + NMDevice *device = NULL; nm_assert_addr_family (addr_family); - ip_config = get_best_ip_config (self, addr_family, &ip_iface, NULL, NULL, &vpn); + ip_config = get_best_ip_config (self, addr_family, &ip_iface, NULL, &device, &vpn); if (ip_config) { /* Tell the DNS manager this config is preferred by re-adding it with * a different IP config type. */ - nm_dns_manager_set_ip_config (NM_POLICY_GET_PRIVATE (self)->dns_manager, - ip_config, - vpn - ? NM_DNS_IP_CONFIG_TYPE_VPN - : NM_DNS_IP_CONFIG_TYPE_BEST_DEVICE); + _dns_manager_set_ip_config (NM_POLICY_GET_PRIVATE (self)->dns_manager, + ip_config, + vpn + ? NM_DNS_IP_CONFIG_TYPE_VPN + : NM_DNS_IP_CONFIG_TYPE_BEST_DEVICE, + device); } if (addr_family == AF_INET6) @@ -1851,10 +1870,10 @@ device_state_changed (NMDevice *device, ip4_config = nm_device_get_ip4_config (device); if (ip4_config) - nm_dns_manager_set_ip_config (priv->dns_manager, NM_IP_CONFIG_CAST (ip4_config), NM_DNS_IP_CONFIG_TYPE_DEFAULT); + _dns_manager_set_ip_config (priv->dns_manager, NM_IP_CONFIG_CAST (ip4_config), NM_DNS_IP_CONFIG_TYPE_DEFAULT, device); ip6_config = nm_device_get_ip6_config (device); if (ip6_config) - nm_dns_manager_set_ip_config (priv->dns_manager, NM_IP_CONFIG_CAST (ip6_config), NM_DNS_IP_CONFIG_TYPE_DEFAULT); + _dns_manager_set_ip_config (priv->dns_manager, NM_IP_CONFIG_CAST (ip6_config), NM_DNS_IP_CONFIG_TYPE_DEFAULT, device); update_routing_and_dns (self, FALSE); @@ -1981,7 +2000,7 @@ device_ip_config_changed (NMDevice *device, if (nm_device_get_state (device) == NM_DEVICE_STATE_ACTIVATED) { if (old_config != new_config) { if (new_config) - nm_dns_manager_set_ip_config (priv->dns_manager, new_config, NM_DNS_IP_CONFIG_TYPE_DEFAULT); + _dns_manager_set_ip_config (priv->dns_manager, new_config, NM_DNS_IP_CONFIG_TYPE_DEFAULT, device); if (old_config) nm_dns_manager_set_ip_config (priv->dns_manager, old_config, NM_DNS_IP_CONFIG_TYPE_REMOVED); } diff --git a/src/nm-rfkill-manager.c b/src/nm-rfkill-manager.c index 557f4cd9..534ad369 100644 --- a/src/nm-rfkill-manager.c +++ b/src/nm-rfkill-manager.c @@ -22,7 +22,6 @@ #include "nm-rfkill-manager.h" -#include <string.h> #include <libudev.h> #include "nm-utils/nm-udev-utils.h" diff --git a/src/nm-session-monitor.c b/src/nm-session-monitor.c index b67c537c..e8c25fd6 100644 --- a/src/nm-session-monitor.c +++ b/src/nm-session-monitor.c @@ -24,8 +24,6 @@ #include "nm-session-monitor.h" #include <pwd.h> -#include <errno.h> -#include <string.h> #include <sys/stat.h> #if SESSION_TRACKING_SYSTEMD && SESSION_TRACKING_ELOGIND @@ -206,13 +204,15 @@ static gboolean ck_update_cache (NMSessionMonitor *monitor) { struct stat statbuf; + int errsv; if (!monitor->ck.cache) return FALSE; /* Check the database file */ if (stat (CKDB_PATH, &statbuf) != 0) { - _LOGE ("failed to check ConsoleKit timestamp: %s", strerror (errno)); + errsv = errno; + _LOGE ("failed to check ConsoleKit timestamp: %s", nm_strerror_native (errsv)); return FALSE; } if (statbuf.st_mtime == monitor->ck.timestamp) diff --git a/src/nm-sleep-monitor.c b/src/nm-sleep-monitor.c index 54d75773..7e0ebe6c 100644 --- a/src/nm-sleep-monitor.c +++ b/src/nm-sleep-monitor.c @@ -21,8 +21,6 @@ #include "nm-sleep-monitor.h" -#include <errno.h> -#include <string.h> #include <sys/stat.h> #include <gio/gunixfdlist.h> diff --git a/src/nm-types.h b/src/nm-types.h index 277e0f6c..b6b49028 100644 --- a/src/nm-types.h +++ b/src/nm-types.h @@ -152,6 +152,7 @@ typedef enum { NM_LINK_TYPE_WIMAX, NM_LINK_TYPE_WPAN, NM_LINK_TYPE_6LOWPAN, + NM_LINK_TYPE_WIFI_P2P, /* Software types */ NM_LINK_TYPE_BNEP = 0x10000, /* Bluetooth Ethernet emulation */ diff --git a/src/org.freedesktop.NetworkManager.conf b/src/org.freedesktop.NetworkManager.conf index fa74b280..720c090e 100644 --- a/src/org.freedesktop.NetworkManager.conf +++ b/src/org.freedesktop.NetworkManager.conf @@ -84,6 +84,8 @@ send_interface="org.freedesktop.NetworkManager.WiMax.Nsp"/> <allow send_destination="org.freedesktop.NetworkManager" send_interface="org.freedesktop.NetworkManager.AccessPoint"/> + <allow send_destination="org.freedesktop.NetworkManager" + send_interface="org.freedesktop.NetworkManager.WifiP2PPeer"/> <!-- Devices (read-only, no security required) --> <allow send_destination="org.freedesktop.NetworkManager" @@ -93,6 +95,8 @@ <allow send_destination="org.freedesktop.NetworkManager" send_interface="org.freedesktop.NetworkManager.Device.Wireless"/> <allow send_destination="org.freedesktop.NetworkManager" + send_interface="org.freedesktop.NetworkManager.Device.WifiP2P"/> + <allow send_destination="org.freedesktop.NetworkManager" send_interface="org.freedesktop.NetworkManager.Device"/> <!-- Core stuff (read-only properties, no methods) --> diff --git a/src/platform/nm-fake-platform.c b/src/platform/nm-fake-platform.c index 814d9cea..30466159 100644 --- a/src/platform/nm-fake-platform.c +++ b/src/platform/nm-fake-platform.c @@ -22,7 +22,6 @@ #include "nm-fake-platform.h" -#include <errno.h> #include <unistd.h> #include <netinet/icmp6.h> #include <netinet/in.h> diff --git a/src/platform/nm-linux-platform.c b/src/platform/nm-linux-platform.c index 85214ec8..2f5c75b0 100644 --- a/src/platform/nm-linux-platform.c +++ b/src/platform/nm-linux-platform.c @@ -21,31 +21,30 @@ #include "nm-linux-platform.h" -#include <poll.h> +#include <arpa/inet.h> +#include <dlfcn.h> #include <endian.h> -#include <errno.h> -#include <unistd.h> -#include <sys/socket.h> -#include <sys/ioctl.h> #include <fcntl.h> -#include <dlfcn.h> -#include <arpa/inet.h> -#include <netinet/icmp6.h> -#include <netinet/in.h> +#include <libudev.h> #include <linux/ip.h> #include <linux/if_arp.h> #include <linux/if_link.h> #include <linux/if_tun.h> #include <linux/if_tunnel.h> #include <linux/ip6_tunnel.h> -#include <libudev.h> +#include <netinet/icmp6.h> +#include <netinet/in.h> +#include <poll.h> +#include <sys/ioctl.h> +#include <sys/socket.h> +#include <unistd.h> #include "nm-utils.h" #include "nm-core-internal.h" #include "nm-setting-vlan.h" -#include "nm-utils/nm-errno.h" #include "nm-utils/nm-secret-utils.h" +#include "nm-utils/nm-c-list.h" #include "nm-netlink.h" #include "nm-core-utils.h" #include "nmp-object.h" @@ -322,13 +321,27 @@ typedef enum { } DelayedActionType; #define FOR_EACH_DELAYED_ACTION(iflags, flags_all) \ - for ((iflags) = (DelayedActionType) 0x1LL; (iflags) <= DELAYED_ACTION_TYPE_MAX; (iflags) <<= 1) \ - if (NM_FLAGS_ANY (flags_all, iflags)) + for ((iflags) = (DelayedActionType) 0x1LL; \ + ({ \ + gboolean _good = FALSE; \ + \ + nm_assert (nm_utils_is_power_of_two (iflags)); \ + \ + while ((iflags) <= DELAYED_ACTION_TYPE_MAX) { \ + if (NM_FLAGS_ANY ((flags_all), (iflags))) { \ + _good = TRUE; \ + break; \ + } \ + (iflags) <<= 1; \ + } \ + _good; \ + }); \ + (iflags) <<= 1) typedef enum { /* Negative values are errors from kernel. Add dummy member to * make enum signed. */ - _WAIT_FOR_NL_RESPONSE_RESULT_SYSTEM_ERROR = -1, + _WAIT_FOR_NL_RESPONSE_RESULT_SYSTEM_ERROR = G_MININT, WAIT_FOR_NL_RESPONSE_RESULT_UNKNOWN = 0, WAIT_FOR_NL_RESPONSE_RESULT_RESPONSE_OK, @@ -376,8 +389,8 @@ typedef struct { bool pruning[_DELAYED_ACTION_IDX_REFRESH_ALL_NUM]; - bool sysctl_get_warned; GHashTable *sysctl_get_prev_values; + CList sysctl_list; NMUdevClient *udev_client; @@ -461,7 +474,7 @@ G_DEFINE_TYPE (NMLinuxPlatform, nm_linux_platform, NM_TYPE_PLATFORM) _LOG_print (__level, __domain, __errsv, self, \ _NM_UTILS_MACRO_FIRST (__VA_ARGS__) ": %s (%d)" \ _NM_UTILS_MACRO_REST (__VA_ARGS__), \ - g_strerror (__errsv), __errsv); \ + nm_strerror_native (__errsv), __errsv); \ } \ } G_STMT_END @@ -512,7 +525,7 @@ wait_for_nl_response_to_string (WaitForNlResponseResult seq_result, if (seq_result < 0) { nm_utils_strbuf_append (&buf, &buf_size, "failure %d (%s%s%s)", -((int) seq_result), - g_strerror (-((int) seq_result)), + nm_strerror_native (-((int) seq_result)), errmsg ? " - " : "", errmsg ?: ""); } @@ -577,7 +590,7 @@ _support_kernel_extended_ifa_flags_detect (struct nl_msg *msg) /* IFA_FLAGS is set for IPv4 and IPv6 addresses. It was added first to IPv6, * but if we encounter an IPv4 address with IFA_FLAGS, we surely have support. */ - if (NM_IN_SET (((struct ifaddrmsg *) nlmsg_data (msg_hdr))->ifa_family, AF_INET, AF_INET6)) + if (!NM_IN_SET (((struct ifaddrmsg *) nlmsg_data (msg_hdr))->ifa_family, AF_INET, AF_INET6)) return; /* see if the nl_msg contains the IFA_FLAGS attribute. If it does, @@ -1100,7 +1113,7 @@ _linktype_get_type (NMPlatform *platform, ******************************************************************/ #define NLMSG_TAIL(nmsg) \ - ((struct rtattr *) (((char *) (nmsg)) + NLMSG_ALIGN((nmsg)->nlmsg_len))) + ((struct rtattr *) (((char *) (nmsg)) + NLMSG_ALIGN ((nmsg)->nlmsg_len))) /* copied from iproute2's addattr_l(). */ static gboolean @@ -1154,31 +1167,29 @@ _parse_af_inet6 (NMPlatform *platform, guint8 *out_addr_gen_mode_inv, gboolean *out_addr_gen_mode_valid) { - static const struct nla_policy policy[IFLA_INET6_MAX+1] = { + static const struct nla_policy policy[] = { [IFLA_INET6_FLAGS] = { .type = NLA_U32 }, [IFLA_INET6_CACHEINFO] = { .minlen = nm_offsetofend (struct ifla_cacheinfo, retrans_time) }, [IFLA_INET6_CONF] = { .minlen = 4 }, [IFLA_INET6_STATS] = { .minlen = 8 }, [IFLA_INET6_ICMP6STATS] = { .minlen = 8 }, - [IFLA_INET6_TOKEN] = { .minlen = sizeof(struct in6_addr) }, + [IFLA_INET6_TOKEN] = { .minlen = sizeof (struct in6_addr) }, [IFLA_INET6_ADDR_GEN_MODE] = { .type = NLA_U8 }, }; - struct nlattr *tb[IFLA_INET6_MAX+1]; - int err; + struct nlattr *tb[G_N_ELEMENTS (policy)]; struct in6_addr i6_token; gboolean token_valid = FALSE; gboolean addr_gen_mode_valid = FALSE; guint8 i6_addr_gen_mode_inv = 0; - err = nla_parse_nested (tb, IFLA_INET6_MAX, attr, policy); - if (err < 0) + if (nla_parse_nested_arr (tb, attr, policy) < 0) return FALSE; - if (tb[IFLA_INET6_CONF] && nla_len(tb[IFLA_INET6_CONF]) % 4) + if (tb[IFLA_INET6_CONF] && nla_len (tb[IFLA_INET6_CONF]) % 4) return FALSE; - if (tb[IFLA_INET6_STATS] && nla_len(tb[IFLA_INET6_STATS]) % 8) + if (tb[IFLA_INET6_STATS] && nla_len (tb[IFLA_INET6_STATS]) % 8) return FALSE; - if (tb[IFLA_INET6_ICMP6STATS] && nla_len(tb[IFLA_INET6_ICMP6STATS]) % 8) + if (tb[IFLA_INET6_ICMP6STATS] && nla_len (tb[IFLA_INET6_ICMP6STATS]) % 8) return FALSE; if (_check_addr_or_return_val (tb, IFLA_INET6_TOKEN, sizeof (struct in6_addr), FALSE)) { @@ -1218,7 +1229,7 @@ _parse_af_inet6 (NMPlatform *platform, static NMPObject * _parse_lnk_gre (const char *kind, struct nlattr *info_data) { - static const struct nla_policy policy[IFLA_GRE_MAX + 1] = { + static const struct nla_policy policy[] = { [IFLA_GRE_LINK] = { .type = NLA_U32 }, [IFLA_GRE_IFLAGS] = { .type = NLA_U16 }, [IFLA_GRE_OFLAGS] = { .type = NLA_U16 }, @@ -1230,13 +1241,13 @@ _parse_lnk_gre (const char *kind, struct nlattr *info_data) [IFLA_GRE_TOS] = { .type = NLA_U8 }, [IFLA_GRE_PMTUDISC] = { .type = NLA_U8 }, }; - struct nlattr *tb[IFLA_GRE_MAX + 1]; - int err; + struct nlattr *tb[G_N_ELEMENTS (policy)]; NMPObject *obj; NMPlatformLnkGre *props; gboolean is_tap; - if (!info_data || !kind) + if ( !info_data + || !kind) return NULL; if (nm_streq (kind, "gretap")) @@ -1246,8 +1257,7 @@ _parse_lnk_gre (const char *kind, struct nlattr *info_data) else return NULL; - err = nla_parse_nested (tb, IFLA_GRE_MAX, info_data, policy); - if (err < 0) + if (nla_parse_nested_arr (tb, info_data, policy) < 0) return NULL; obj = nmp_object_new (is_tap ? NMP_OBJECT_TYPE_LNK_GRETAP : NMP_OBJECT_TYPE_LNK_GRE, NULL); @@ -1287,25 +1297,25 @@ _parse_lnk_gre (const char *kind, struct nlattr *info_data) static NMPObject * _parse_lnk_infiniband (const char *kind, struct nlattr *info_data) { - static const struct nla_policy policy[IFLA_IPOIB_MAX + 1] = { + static const struct nla_policy policy[] = { [IFLA_IPOIB_PKEY] = { .type = NLA_U16 }, [IFLA_IPOIB_MODE] = { .type = NLA_U16 }, [IFLA_IPOIB_UMCAST] = { .type = NLA_U16 }, }; - struct nlattr *tb[IFLA_IPOIB_MAX + 1]; + struct nlattr *tb[G_N_ELEMENTS (policy)]; NMPlatformLnkInfiniband *info; NMPObject *obj; - int err; const char *mode; - if (!info_data || g_strcmp0 (kind, "ipoib")) + if ( !info_data + || !nm_streq0 (kind, "ipoib")) return NULL; - err = nla_parse_nested (tb, IFLA_IPOIB_MAX, info_data, policy); - if (err < 0) + if (nla_parse_nested_arr (tb, info_data, policy) < 0) return NULL; - if (!tb[IFLA_IPOIB_PKEY] || !tb[IFLA_IPOIB_MODE]) + if ( !tb[IFLA_IPOIB_PKEY] + || !tb[IFLA_IPOIB_MODE]) return NULL; switch (nla_get_u16 (tb[IFLA_IPOIB_MODE])) { @@ -1333,29 +1343,26 @@ _parse_lnk_infiniband (const char *kind, struct nlattr *info_data) static NMPObject * _parse_lnk_ip6tnl (const char *kind, struct nlattr *info_data) { - static const struct nla_policy policy[IFLA_IPTUN_MAX + 1] = { + static const struct nla_policy policy[] = { [IFLA_IPTUN_LINK] = { .type = NLA_U32 }, - [IFLA_IPTUN_LOCAL] = { .type = NLA_UNSPEC, - .minlen = sizeof (struct in6_addr)}, - [IFLA_IPTUN_REMOTE] = { .type = NLA_UNSPEC, - .minlen = sizeof (struct in6_addr)}, + [IFLA_IPTUN_LOCAL] = { .minlen = sizeof (struct in6_addr)}, + [IFLA_IPTUN_REMOTE] = { .minlen = sizeof (struct in6_addr)}, [IFLA_IPTUN_TTL] = { .type = NLA_U8 }, [IFLA_IPTUN_ENCAP_LIMIT] = { .type = NLA_U8 }, [IFLA_IPTUN_FLOWINFO] = { .type = NLA_U32 }, [IFLA_IPTUN_PROTO] = { .type = NLA_U8 }, [IFLA_IPTUN_FLAGS] = { .type = NLA_U32 }, }; - struct nlattr *tb[IFLA_IPTUN_MAX + 1]; - int err; + struct nlattr *tb[G_N_ELEMENTS (policy)]; NMPObject *obj; NMPlatformLnkIp6Tnl *props; guint32 flowinfo; - if (!info_data || g_strcmp0 (kind, "ip6tnl")) + if ( !info_data + || !nm_streq0 (kind, "ip6tnl")) return NULL; - err = nla_parse_nested (tb, IFLA_IPTUN_MAX, info_data, policy); - if (err < 0) + if (nla_parse_nested_arr (tb, info_data, policy) < 0) return NULL; obj = nmp_object_new (NMP_OBJECT_TYPE_LNK_IP6TNL, NULL); @@ -1364,9 +1371,9 @@ _parse_lnk_ip6tnl (const char *kind, struct nlattr *info_data) if (tb[IFLA_IPTUN_LINK]) props->parent_ifindex = nla_get_u32 (tb[IFLA_IPTUN_LINK]); if (tb[IFLA_IPTUN_LOCAL]) - memcpy (&props->local, nla_data (tb[IFLA_IPTUN_LOCAL]), sizeof (props->local)); + props->local = *nla_data_as (struct in6_addr, tb[IFLA_IPTUN_LOCAL]); if (tb[IFLA_IPTUN_REMOTE]) - memcpy (&props->remote, nla_data (tb[IFLA_IPTUN_REMOTE]), sizeof (props->remote)); + props->remote = *nla_data_as (struct in6_addr, tb[IFLA_IPTUN_REMOTE]); if (tb[IFLA_IPTUN_TTL]) props->ttl = nla_get_u8 (tb[IFLA_IPTUN_TTL]); if (tb[IFLA_IPTUN_ENCAP_LIMIT]) @@ -1387,23 +1394,22 @@ _parse_lnk_ip6tnl (const char *kind, struct nlattr *info_data) static NMPObject * _parse_lnk_ip6gre (const char *kind, struct nlattr *info_data) { - static const struct nla_policy policy[IFLA_GRE_MAX + 1] = { + static const struct nla_policy policy[] = { [IFLA_GRE_LINK] = { .type = NLA_U32 }, [IFLA_GRE_IFLAGS] = { .type = NLA_U16 }, [IFLA_GRE_OFLAGS] = { .type = NLA_U16 }, [IFLA_GRE_IKEY] = { .type = NLA_U32 }, [IFLA_GRE_OKEY] = { .type = NLA_U32 }, [IFLA_GRE_LOCAL] = { .type = NLA_UNSPEC, - .minlen = sizeof (struct in6_addr)}, + .minlen = sizeof (struct in6_addr)}, [IFLA_GRE_REMOTE] = { .type = NLA_UNSPEC, - .minlen = sizeof (struct in6_addr)}, + .minlen = sizeof (struct in6_addr)}, [IFLA_GRE_TTL] = { .type = NLA_U8 }, [IFLA_GRE_ENCAP_LIMIT] = { .type = NLA_U8 }, [IFLA_GRE_FLOWINFO] = { .type = NLA_U32 }, [IFLA_GRE_FLAGS] = { .type = NLA_U32 }, }; - struct nlattr *tb[IFLA_GRE_MAX + 1]; - int err; + struct nlattr *tb[G_N_ELEMENTS (policy)]; NMPObject *obj; NMPlatformLnkIp6Tnl *props; guint32 flowinfo; @@ -1419,8 +1425,7 @@ _parse_lnk_ip6gre (const char *kind, struct nlattr *info_data) else return NULL; - err = nla_parse_nested (tb, IFLA_GRE_MAX, info_data, policy); - if (err < 0) + if (nla_parse_nested_arr (tb, info_data, policy) < 0) return NULL; obj = nmp_object_new (is_tap ? NMP_OBJECT_TYPE_LNK_IP6GRETAP : NMP_OBJECT_TYPE_LNK_IP6GRE, NULL); @@ -1439,9 +1444,9 @@ _parse_lnk_ip6gre (const char *kind, struct nlattr *info_data) if (tb[IFLA_GRE_OKEY]) props->output_key = ntohl (nla_get_u32 (tb[IFLA_GRE_OKEY])); if (tb[IFLA_GRE_LOCAL]) - memcpy (&props->local, nla_data (tb[IFLA_GRE_LOCAL]), sizeof (props->local)); + props->local = *nla_data_as (struct in6_addr, tb[IFLA_GRE_LOCAL]); if (tb[IFLA_GRE_REMOTE]) - memcpy (&props->remote, nla_data (tb[IFLA_GRE_REMOTE]), sizeof (props->remote)); + props->remote = *nla_data_as (struct in6_addr, tb[IFLA_GRE_REMOTE]); if (tb[IFLA_GRE_TTL]) props->ttl = nla_get_u8 (tb[IFLA_GRE_TTL]); if (tb[IFLA_GRE_ENCAP_LIMIT]) @@ -1462,7 +1467,7 @@ _parse_lnk_ip6gre (const char *kind, struct nlattr *info_data) static NMPObject * _parse_lnk_ipip (const char *kind, struct nlattr *info_data) { - static const struct nla_policy policy[IFLA_IPTUN_MAX + 1] = { + static const struct nla_policy policy[] = { [IFLA_IPTUN_LINK] = { .type = NLA_U32 }, [IFLA_IPTUN_LOCAL] = { .type = NLA_U32 }, [IFLA_IPTUN_REMOTE] = { .type = NLA_U32 }, @@ -1470,16 +1475,15 @@ _parse_lnk_ipip (const char *kind, struct nlattr *info_data) [IFLA_IPTUN_TOS] = { .type = NLA_U8 }, [IFLA_IPTUN_PMTUDISC] = { .type = NLA_U8 }, }; - struct nlattr *tb[IFLA_IPTUN_MAX + 1]; - int err; + struct nlattr *tb[G_N_ELEMENTS (policy)]; NMPObject *obj; NMPlatformLnkIpIp *props; - if (!info_data || g_strcmp0 (kind, "ipip")) + if ( !info_data + || !nm_streq0 (kind, "ipip")) return NULL; - err = nla_parse_nested (tb, IFLA_IPTUN_MAX, info_data, policy); - if (err < 0) + if (nla_parse_nested_arr (tb, info_data, policy) < 0) return NULL; obj = nmp_object_new (NMP_OBJECT_TYPE_LNK_IPIP, NULL); @@ -1500,28 +1504,27 @@ _parse_lnk_ipip (const char *kind, struct nlattr *info_data) static NMPObject * _parse_lnk_macvlan (const char *kind, struct nlattr *info_data) { - static const struct nla_policy policy[IFLA_MACVLAN_MAX + 1] = { + static const struct nla_policy policy[] = { [IFLA_MACVLAN_MODE] = { .type = NLA_U32 }, [IFLA_MACVLAN_FLAGS] = { .type = NLA_U16 }, }; NMPlatformLnkMacvlan *props; - struct nlattr *tb[IFLA_MACVLAN_MAX + 1]; - int err; + struct nlattr *tb[G_N_ELEMENTS (policy)]; NMPObject *obj; gboolean tap; - if (!info_data) + if ( !info_data + || !kind) return NULL; - if (!g_strcmp0 (kind, "macvlan")) + if (nm_streq (kind, "macvlan")) tap = FALSE; - else if (!g_strcmp0 (kind, "macvtap")) + else if (nm_streq (kind, "macvtap")) tap = TRUE; else return NULL; - err = nla_parse_nested (tb, IFLA_MACVLAN_MAX, info_data, policy); - if (err < 0) + if (nla_parse_nested_arr (tb, info_data, policy) < 0) return NULL; if (!tb[IFLA_MACVLAN_MODE]) @@ -1543,7 +1546,7 @@ _parse_lnk_macvlan (const char *kind, struct nlattr *info_data) static NMPObject * _parse_lnk_macsec (const char *kind, struct nlattr *info_data) { - static const struct nla_policy policy[__IFLA_MACSEC_MAX] = { + static const struct nla_policy policy[] = { [IFLA_MACSEC_SCI] = { .type = NLA_U64 }, [IFLA_MACSEC_ICV_LEN] = { .type = NLA_U8 }, [IFLA_MACSEC_CIPHER_SUITE] = { .type = NLA_U64 }, @@ -1557,33 +1560,32 @@ _parse_lnk_macsec (const char *kind, struct nlattr *info_data) [IFLA_MACSEC_REPLAY_PROTECT] = { .type = NLA_U8 }, [IFLA_MACSEC_VALIDATION] = { .type = NLA_U8 }, }; - struct nlattr *tb[__IFLA_MACSEC_MAX]; - int err; + struct nlattr *tb[G_N_ELEMENTS (policy)]; NMPObject *obj; NMPlatformLnkMacsec *props; - if (!info_data || !nm_streq0 (kind, "macsec")) + if ( !info_data + || !nm_streq0 (kind, "macsec")) return NULL; - err = nla_parse_nested (tb, __IFLA_MACSEC_MAX - 1, info_data, policy); - if (err < 0) + if (nla_parse_nested_arr (tb, info_data, policy) < 0) return NULL; obj = nmp_object_new (NMP_OBJECT_TYPE_LNK_MACSEC, NULL); props = &obj->lnk_macsec; - props->sci = tb[IFLA_MACSEC_SCI] ? be64toh (nla_get_u64 (tb[IFLA_MACSEC_SCI])) : 0; - props->icv_length = tb[IFLA_MACSEC_ICV_LEN] ? nla_get_u8 (tb[IFLA_MACSEC_ICV_LEN]) : 0; - props->cipher_suite = tb [IFLA_MACSEC_CIPHER_SUITE] ? nla_get_u64 (tb[IFLA_MACSEC_CIPHER_SUITE]) : 0; - props->window = tb [IFLA_MACSEC_WINDOW] ? nla_get_u32 (tb[IFLA_MACSEC_WINDOW]) : 0; - props->encoding_sa = tb[IFLA_MACSEC_ENCODING_SA] ? !!nla_get_u8 (tb[IFLA_MACSEC_ENCODING_SA]) : 0; - props->encrypt = tb[IFLA_MACSEC_ENCRYPT] ? !!nla_get_u8 (tb[IFLA_MACSEC_ENCRYPT]) : 0; - props->protect = tb[IFLA_MACSEC_PROTECT] ? !!nla_get_u8 (tb[IFLA_MACSEC_PROTECT]) : 0; - props->include_sci = tb[IFLA_MACSEC_INC_SCI] ? !!nla_get_u8 (tb[IFLA_MACSEC_INC_SCI]) : 0; - props->es = tb[IFLA_MACSEC_ES] ? !!nla_get_u8 (tb[IFLA_MACSEC_ES]) : 0; - props->scb = tb[IFLA_MACSEC_SCB] ? !!nla_get_u8 (tb[IFLA_MACSEC_SCB]) : 0; - props->replay_protect = tb[IFLA_MACSEC_REPLAY_PROTECT] ? !!nla_get_u8 (tb[IFLA_MACSEC_REPLAY_PROTECT]) : 0; - props->validation = tb[IFLA_MACSEC_VALIDATION] ? nla_get_u8 (tb[IFLA_MACSEC_VALIDATION]) : 0; + if (tb[IFLA_MACSEC_SCI]) { props->sci = nla_get_be64 (tb[IFLA_MACSEC_SCI]); } + if (tb[IFLA_MACSEC_ICV_LEN]) { props->icv_length = nla_get_u8 (tb[IFLA_MACSEC_ICV_LEN]); } + if (tb[IFLA_MACSEC_CIPHER_SUITE]) { props->cipher_suite = nla_get_u64 (tb[IFLA_MACSEC_CIPHER_SUITE]); } + if (tb[IFLA_MACSEC_WINDOW]) { props->window = nla_get_u32 (tb[IFLA_MACSEC_WINDOW]); } + if (tb[IFLA_MACSEC_ENCODING_SA]) { props->encoding_sa = !!nla_get_u8 (tb[IFLA_MACSEC_ENCODING_SA]); } + if (tb[IFLA_MACSEC_ENCRYPT]) { props->encrypt = !!nla_get_u8 (tb[IFLA_MACSEC_ENCRYPT]); } + if (tb[IFLA_MACSEC_PROTECT]) { props->protect = !!nla_get_u8 (tb[IFLA_MACSEC_PROTECT]); } + if (tb[IFLA_MACSEC_INC_SCI]) { props->include_sci = !!nla_get_u8 (tb[IFLA_MACSEC_INC_SCI]); } + if (tb[IFLA_MACSEC_ES]) { props->es = !!nla_get_u8 (tb[IFLA_MACSEC_ES]); } + if (tb[IFLA_MACSEC_SCB]) { props->scb = !!nla_get_u8 (tb[IFLA_MACSEC_SCB]); } + if (tb[IFLA_MACSEC_REPLAY_PROTECT]) { props->replay_protect = !!nla_get_u8 (tb[IFLA_MACSEC_REPLAY_PROTECT]); } + if (tb[IFLA_MACSEC_VALIDATION]) { props->validation = nla_get_u8 (tb[IFLA_MACSEC_VALIDATION]); } return obj; } @@ -1593,7 +1595,7 @@ _parse_lnk_macsec (const char *kind, struct nlattr *info_data) static NMPObject * _parse_lnk_sit (const char *kind, struct nlattr *info_data) { - static const struct nla_policy policy[IFLA_IPTUN_MAX + 1] = { + static const struct nla_policy policy[] = { [IFLA_IPTUN_LINK] = { .type = NLA_U32 }, [IFLA_IPTUN_LOCAL] = { .type = NLA_U32 }, [IFLA_IPTUN_REMOTE] = { .type = NLA_U32 }, @@ -1603,16 +1605,15 @@ _parse_lnk_sit (const char *kind, struct nlattr *info_data) [IFLA_IPTUN_FLAGS] = { .type = NLA_U16 }, [IFLA_IPTUN_PROTO] = { .type = NLA_U8 }, }; - struct nlattr *tb[IFLA_IPTUN_MAX + 1]; - int err; + struct nlattr *tb[G_N_ELEMENTS (policy)]; NMPObject *obj; NMPlatformLnkSit *props; - if (!info_data || g_strcmp0 (kind, "sit")) + if ( !info_data + || !nm_streq0 (kind, "sit")) return NULL; - err = nla_parse_nested (tb, IFLA_IPTUN_MAX, info_data, policy); - if (err < 0) + if (nla_parse_nested_arr (tb, info_data, policy) < 0) return NULL; obj = nmp_object_new (NMP_OBJECT_TYPE_LNK_SIT, NULL); @@ -1635,7 +1636,7 @@ _parse_lnk_sit (const char *kind, struct nlattr *info_data) static NMPObject * _parse_lnk_tun (const char *kind, struct nlattr *info_data) { - static const struct nla_policy policy[IFLA_TUN_MAX + 1] = { + static const struct nla_policy policy[] = { [IFLA_TUN_OWNER] = { .type = NLA_U32 }, [IFLA_TUN_GROUP] = { .type = NLA_U32 }, [IFLA_TUN_TYPE] = { .type = NLA_U8 }, @@ -1646,22 +1647,19 @@ _parse_lnk_tun (const char *kind, struct nlattr *info_data) [IFLA_TUN_NUM_QUEUES] = { .type = NLA_U32 }, [IFLA_TUN_NUM_DISABLED_QUEUES] = { .type = NLA_U32 }, }; - struct nlattr *tb[IFLA_TUN_MAX + 1]; - int err; + struct nlattr *tb[G_N_ELEMENTS (policy)]; NMPObject *obj; NMPlatformLnkTun *props; - if (!info_data || !nm_streq0 (kind, "tun")) + if ( !info_data + || !nm_streq0 (kind, "tun")) return NULL; - err = nla_parse_nested (tb, IFLA_TUN_MAX, info_data, policy); - if (err < 0) + if (nla_parse_nested_arr (tb, info_data, policy) < 0) return NULL; - if (!tb[IFLA_TUN_TYPE]) { - /* we require at least a type. */ + if (!tb[IFLA_TUN_TYPE]) return NULL; - } obj = nmp_object_new (NMP_OBJECT_TYPE_LNK_TUN, NULL); props = &obj->lnk_tun; @@ -1708,7 +1706,7 @@ _vlan_qos_mapping_from_nla (struct nlattr *nlattr, array = g_ptr_array_new (); nla_for_each_nested (nla, nlattr, remaining) { - if (nla_len (nla) < sizeof(NMVlanQosMapping)) + if (nla_len (nla) < sizeof (NMVlanQosMapping)) return FALSE; g_ptr_array_add (array, nla_data (nla)); } @@ -1749,22 +1747,22 @@ _vlan_qos_mapping_from_nla (struct nlattr *nlattr, static NMPObject * _parse_lnk_vlan (const char *kind, struct nlattr *info_data) { - static const struct nla_policy policy[IFLA_VLAN_MAX+1] = { + static const struct nla_policy policy[] = { [IFLA_VLAN_ID] = { .type = NLA_U16 }, [IFLA_VLAN_FLAGS] = { .minlen = nm_offsetofend (struct ifla_vlan_flags, flags) }, [IFLA_VLAN_INGRESS_QOS] = { .type = NLA_NESTED }, [IFLA_VLAN_EGRESS_QOS] = { .type = NLA_NESTED }, [IFLA_VLAN_PROTOCOL] = { .type = NLA_U16 }, }; - struct nlattr *tb[IFLA_VLAN_MAX+1]; - int err; + struct nlattr *tb[G_N_ELEMENTS (policy)]; nm_auto_nmpobj NMPObject *obj = NULL; NMPObject *obj_result; - if (!info_data || g_strcmp0 (kind, "vlan")) + if ( !info_data + || !nm_streq0 (kind, "vlan")) return NULL; - if ((err = nla_parse_nested (tb, IFLA_VLAN_MAX, info_data, policy)) < 0) + if (nla_parse_nested_arr (tb, info_data, policy) < 0) return NULL; if (!tb[IFLA_VLAN_ID]) @@ -1776,7 +1774,7 @@ _parse_lnk_vlan (const char *kind, struct nlattr *info_data) if (tb[IFLA_VLAN_FLAGS]) { struct ifla_vlan_flags flags; - nla_memcpy (&flags, tb[IFLA_VLAN_FLAGS], sizeof(flags)); + nla_memcpy (&flags, tb[IFLA_VLAN_FLAGS], sizeof (flags)); obj->lnk_vlan.flags = flags.flags; } @@ -1834,7 +1832,7 @@ struct nm_ifla_vxlan_port_range { static NMPObject * _parse_lnk_vxlan (const char *kind, struct nlattr *info_data) { - static const struct nla_policy policy[IFLA_VXLAN_MAX + 1] = { + static const struct nla_policy policy[] = { [IFLA_VXLAN_ID] = { .type = NLA_U32 }, [IFLA_VXLAN_GROUP] = { .type = NLA_U32 }, [IFLA_VXLAN_GROUP6] = { .type = NLA_UNSPEC, @@ -1857,16 +1855,14 @@ _parse_lnk_vxlan (const char *kind, struct nlattr *info_data) [IFLA_VXLAN_PORT] = { .type = NLA_U16 }, }; NMPlatformLnkVxlan *props; - struct nlattr *tb[IFLA_VXLAN_MAX + 1]; - struct nm_ifla_vxlan_port_range *range; - int err; + struct nlattr *tb[G_N_ELEMENTS (policy)]; NMPObject *obj; - if (!info_data || g_strcmp0 (kind, "vxlan")) + if ( !info_data + || !nm_streq0 (kind, "vxlan")) return NULL; - err = nla_parse_nested (tb, IFLA_VXLAN_MAX, info_data, policy); - if (err < 0) + if (nla_parse_nested_arr (tb, info_data, policy) < 0) return NULL; obj = nmp_object_new (NMP_OBJECT_TYPE_LNK_VXLAN, NULL); @@ -1881,10 +1877,10 @@ _parse_lnk_vxlan (const char *kind, struct nlattr *info_data) props->group = nla_get_u32 (tb[IFLA_VXLAN_GROUP]); if (tb[IFLA_VXLAN_LOCAL]) props->local = nla_get_u32 (tb[IFLA_VXLAN_LOCAL]); - if (tb[IFLA_VXLAN_GROUP6]) - memcpy (&props->group6, nla_data (tb[IFLA_VXLAN_GROUP6]), sizeof (props->group6)); if (tb[IFLA_VXLAN_LOCAL6]) - memcpy (&props->local6, nla_data (tb[IFLA_VXLAN_LOCAL6]), sizeof (props->local6)); + props->local6 = *nla_data_as (struct in6_addr, tb[IFLA_VXLAN_LOCAL6]); + if (tb[IFLA_VXLAN_GROUP6]) + props->group6 = *nla_data_as (struct in6_addr, tb[IFLA_VXLAN_GROUP6]); if (tb[IFLA_VXLAN_AGEING]) props->ageing = nla_get_u32 (tb[IFLA_VXLAN_AGEING]); @@ -1899,7 +1895,9 @@ _parse_lnk_vxlan (const char *kind, struct nlattr *info_data) props->dst_port = ntohs (nla_get_u16 (tb[IFLA_VXLAN_PORT])); if (tb[IFLA_VXLAN_PORT_RANGE]) { - range = nla_data (tb[IFLA_VXLAN_PORT_RANGE]); + struct nm_ifla_vxlan_port_range *range; + + range = nla_data_as (struct nm_ifla_vxlan_port_range, tb[IFLA_VXLAN_PORT_RANGE]); props->src_port_min = ntohs (range->low); props->src_port_max = ntohs (range->high); } @@ -1924,16 +1922,16 @@ static gboolean _wireguard_update_from_allowed_ips_nla (NMPWireGuardAllowedIP *allowed_ip, struct nlattr *nlattr) { - static const struct nla_policy policy[WGALLOWEDIP_A_MAX + 1] = { + static const struct nla_policy policy[] = { [WGALLOWEDIP_A_FAMILY] = { .type = NLA_U16 }, [WGALLOWEDIP_A_IPADDR] = { .minlen = sizeof (struct in_addr) }, [WGALLOWEDIP_A_CIDR_MASK] = { .type = NLA_U8 }, }; - struct nlattr *tb[WGALLOWEDIP_A_MAX + 1]; + struct nlattr *tb[G_N_ELEMENTS (policy)]; int family; int addr_len; - if (nla_parse_nested (tb, WGALLOWEDIP_A_MAX, nlattr, policy) < 0) + if (nla_parse_nested_arr (tb, nlattr, policy) < 0) return FALSE; if (!tb[WGALLOWEDIP_A_FAMILY]) @@ -1973,7 +1971,7 @@ _wireguard_update_from_peers_nla (CList *peers, GArray **p_allowed_ips, struct nlattr *peer_attr) { - static const struct nla_policy policy[WGPEER_A_MAX + 1] = { + static const struct nla_policy policy[] = { [WGPEER_A_PUBLIC_KEY] = { .minlen = NMP_WIREGUARD_PUBLIC_KEY_LEN }, [WGPEER_A_PRESHARED_KEY] = { }, [WGPEER_A_FLAGS] = { .type = NLA_U32 }, @@ -1984,10 +1982,10 @@ _wireguard_update_from_peers_nla (CList *peers, [WGPEER_A_TX_BYTES] = { .type = NLA_U64 }, [WGPEER_A_ALLOWEDIPS] = { .type = NLA_NESTED }, }; + struct nlattr *tb[G_N_ELEMENTS (policy)]; WireGuardPeerConstruct *peer_c; - struct nlattr *tb[WGPEER_A_MAX + 1]; - if (nla_parse_nested (tb, WGPEER_A_MAX, peer_attr, policy) < 0) + if (nla_parse_nested_arr (tb, peer_attr, policy) < 0) return FALSE; if (!tb[WGPEER_A_PUBLIC_KEY]) @@ -2017,12 +2015,14 @@ _wireguard_update_from_peers_nla (CList *peers, nm_sock_addr_union_cpy_untrusted (&peer_c->data.endpoint, tb[WGPEER_A_ENDPOINT] ? nla_data (tb[WGPEER_A_ENDPOINT]) : NULL, - tb[WGPEER_A_ENDPOINT] ? nla_len (tb[WGPEER_A_ENDPOINT]) : 0); + tb[WGPEER_A_ENDPOINT] ? nla_len (tb[WGPEER_A_ENDPOINT]) : 0); if (tb[WGPEER_A_PERSISTENT_KEEPALIVE_INTERVAL]) - peer_c->data.persistent_keepalive_interval = nla_get_u64 (tb[WGPEER_A_PERSISTENT_KEEPALIVE_INTERVAL]); - if (tb[WGPEER_A_LAST_HANDSHAKE_TIME]) - nla_memcpy (&peer_c->data.last_handshake_time, tb[WGPEER_A_LAST_HANDSHAKE_TIME], sizeof (peer_c->data.last_handshake_time)); + peer_c->data.persistent_keepalive_interval = nla_get_u16 (tb[WGPEER_A_PERSISTENT_KEEPALIVE_INTERVAL]); + if (tb[WGPEER_A_LAST_HANDSHAKE_TIME]) { + if (nla_len (tb[WGPEER_A_LAST_HANDSHAKE_TIME]) >= sizeof (peer_c->data.last_handshake_time)) + nla_memcpy (&peer_c->data.last_handshake_time, tb[WGPEER_A_LAST_HANDSHAKE_TIME], sizeof (peer_c->data.last_handshake_time)); + } if (tb[WGPEER_A_RX_BYTES]) peer_c->data.rx_bytes = nla_get_u64 (tb[WGPEER_A_RX_BYTES]); if (tb[WGPEER_A_TX_BYTES]) @@ -2070,7 +2070,7 @@ typedef struct { static int _wireguard_get_device_cb (struct nl_msg *msg, void *arg) { - static const struct nla_policy policy[WGDEVICE_A_MAX + 1] = { + static const struct nla_policy policy[] = { [WGDEVICE_A_IFINDEX] = { .type = NLA_U32 }, [WGDEVICE_A_IFNAME] = { .type = NLA_NUL_STRING, .maxlen = IFNAMSIZ }, [WGDEVICE_A_PRIVATE_KEY] = { }, @@ -2080,12 +2080,10 @@ _wireguard_get_device_cb (struct nl_msg *msg, void *arg) [WGDEVICE_A_FWMARK] = { .type = NLA_U32 }, [WGDEVICE_A_PEERS] = { .type = NLA_NESTED }, }; + struct nlattr *tb[G_N_ELEMENTS (policy)]; WireGuardParseData *parse_data = arg; - struct nlattr *tb[WGDEVICE_A_MAX + 1]; - int nlerr; - nlerr = genlmsg_parse (nlmsg_hdr (msg), 0, tb, WGDEVICE_A_MAX, policy); - if (nlerr < 0) + if (genlmsg_parse_arr (nlmsg_hdr (msg), 0, tb, policy) < 0) return NL_SKIP; if (tb[WGDEVICE_A_IFINDEX]) { @@ -2164,7 +2162,7 @@ _wireguard_read_info (NMPlatform *platform /* used only as logging context */, nm_assert (wireguard_family_id >= 0); nm_assert (ifindex > 0); - _LOGT ("wireguard: fetching infomation for ifindex %d (genl-id %d)...", ifindex, wireguard_family_id); + _LOGT ("wireguard: fetching information for ifindex %d (genl-id %d)...", ifindex, wireguard_family_id); msg = nlmsg_alloc (); @@ -2373,8 +2371,9 @@ _wireguard_create_change_nlmsgs (NMPlatform *platform, int wireguard_family_id, const NMPlatformLnkWireGuard *lnk_wireguard, const NMPWireGuardPeer *peers, + const NMPlatformWireGuardChangePeerFlags *peer_flags, guint peers_len, - gboolean replace_peers, + NMPlatformWireGuardChangeFlags change_flags, GPtrArray **out_msgs) { gs_unref_ptrarray GPtrArray *msgs = NULL; @@ -2386,6 +2385,7 @@ _wireguard_create_change_nlmsgs (NMPlatform *platform, struct nlattr *nest_curr_peer; struct nlattr *nest_allowed_ips; struct nlattr *nest_curr_allowed_ip; + NMPlatformWireGuardChangePeerFlags p_flags = NM_PLATFORM_WIREGUARD_CHANGE_PEER_FLAG_DEFAULT; #define _nla_nest_end(msg, nest_start) \ G_STMT_START { \ @@ -2420,12 +2420,19 @@ again: NLA_PUT_U32 (msg, WGDEVICE_A_IFINDEX, (guint32) ifindex); if (idx_peer_curr == IDX_NIL) { - NLA_PUT (msg, WGDEVICE_A_PRIVATE_KEY, sizeof (lnk_wireguard->private_key), lnk_wireguard->private_key); - NLA_PUT_U16 (msg, WGDEVICE_A_LISTEN_PORT, lnk_wireguard->listen_port); - NLA_PUT_U32 (msg, WGDEVICE_A_FWMARK, lnk_wireguard->fwmark); + guint32 flags; + + if (NM_FLAGS_HAS (change_flags, NM_PLATFORM_WIREGUARD_CHANGE_FLAG_HAS_PRIVATE_KEY)) + NLA_PUT (msg, WGDEVICE_A_PRIVATE_KEY, sizeof (lnk_wireguard->private_key), lnk_wireguard->private_key); + if (NM_FLAGS_HAS (change_flags, NM_PLATFORM_WIREGUARD_CHANGE_FLAG_HAS_LISTEN_PORT)) + NLA_PUT_U16 (msg, WGDEVICE_A_LISTEN_PORT, lnk_wireguard->listen_port); + if (NM_FLAGS_HAS (change_flags, NM_PLATFORM_WIREGUARD_CHANGE_FLAG_HAS_FWMARK)) + NLA_PUT_U32 (msg, WGDEVICE_A_FWMARK, lnk_wireguard->fwmark); - NLA_PUT_U32 (msg, WGDEVICE_A_FLAGS, - replace_peers ? WGDEVICE_F_REPLACE_PEERS : ((guint32) 0u)); + flags = 0; + if (NM_FLAGS_HAS (change_flags, NM_PLATFORM_WIREGUARD_CHANGE_FLAG_REPLACE_PEERS)) + flags |= WGDEVICE_F_REPLACE_PEERS; + NLA_PUT_U32 (msg, WGDEVICE_A_FLAGS, flags); } if (peers_len == 0) @@ -2444,6 +2451,21 @@ again: for (; idx_peer_curr < peers_len; idx_peer_curr++) { const NMPWireGuardPeer *p = &peers[idx_peer_curr]; + if (peer_flags) { + p_flags = peer_flags[idx_peer_curr]; + if (!NM_FLAGS_ANY (p_flags, NM_PLATFORM_WIREGUARD_CHANGE_PEER_FLAG_REMOVE_ME + | NM_PLATFORM_WIREGUARD_CHANGE_PEER_FLAG_HAS_PRESHARED_KEY + | NM_PLATFORM_WIREGUARD_CHANGE_PEER_FLAG_HAS_KEEPALIVE_INTERVAL + | NM_PLATFORM_WIREGUARD_CHANGE_PEER_FLAG_HAS_ENDPOINT + | NM_PLATFORM_WIREGUARD_CHANGE_PEER_FLAG_HAS_ALLOWEDIPS + | NM_PLATFORM_WIREGUARD_CHANGE_PEER_FLAG_REPLACE_ALLOWEDIPS)) { + /* no flags set. We take that as indication to skip configuring the peer + * entirely. */ + nm_assert (p_flags == NM_PLATFORM_WIREGUARD_CHANGE_PEER_FLAG_NONE); + continue; + } + } + nest_curr_peer = nla_nest_start (msg, 0); if (!nest_curr_peer) goto toobig_peers; @@ -2451,63 +2473,77 @@ again: if (nla_put (msg, WGPEER_A_PUBLIC_KEY, NMP_WIREGUARD_PUBLIC_KEY_LEN, p->public_key) < 0) goto toobig_peers; - if (idx_allowed_ips_curr == IDX_NIL) { - - if (nla_put (msg, WGPEER_A_PRESHARED_KEY, sizeof (p->preshared_key), p->preshared_key) < 0) - goto toobig_peers; - - if (nla_put_uint16 (msg, WGPEER_A_PERSISTENT_KEEPALIVE_INTERVAL, p->persistent_keepalive_interval) < 0) + if (NM_FLAGS_HAS (p_flags, NM_PLATFORM_WIREGUARD_CHANGE_PEER_FLAG_REMOVE_ME)) { + /* all other p_flags are silently ignored. */ + if (nla_put_uint32 (msg, WGPEER_A_FLAGS, WGPEER_F_REMOVE_ME) < 0) goto toobig_peers; + } else { - if (nla_put_uint32 (msg, WGPEER_A_FLAGS, WGPEER_F_REPLACE_ALLOWEDIPS) < 0) - goto toobig_peers; + if (idx_allowed_ips_curr == IDX_NIL) { + if ( NM_FLAGS_HAS (p_flags, NM_PLATFORM_WIREGUARD_CHANGE_PEER_FLAG_HAS_PRESHARED_KEY) + && nla_put (msg, WGPEER_A_PRESHARED_KEY, sizeof (p->preshared_key), p->preshared_key) < 0) + goto toobig_peers; - if (NM_IN_SET (p->endpoint.sa.sa_family, AF_INET, AF_INET6)) { - if (nla_put (msg, - WGPEER_A_ENDPOINT, - p->endpoint.sa.sa_family == AF_INET - ? sizeof (p->endpoint.in) - : sizeof (p->endpoint.in6), - &p->endpoint) < 0) + if ( NM_FLAGS_HAS (p_flags, NM_PLATFORM_WIREGUARD_CHANGE_PEER_FLAG_HAS_KEEPALIVE_INTERVAL) + && nla_put_uint16 (msg, WGPEER_A_PERSISTENT_KEEPALIVE_INTERVAL, p->persistent_keepalive_interval) < 0) goto toobig_peers; - } else - nm_assert (p->endpoint.sa.sa_family == AF_UNSPEC); - } - if (p->allowed_ips_len > 0) { - if (idx_allowed_ips_curr == IDX_NIL) - idx_allowed_ips_curr = 0; + if ( NM_FLAGS_HAS (p_flags, NM_PLATFORM_WIREGUARD_CHANGE_PEER_FLAG_REPLACE_ALLOWEDIPS) + && nla_put_uint32 (msg, WGPEER_A_FLAGS, WGPEER_F_REPLACE_ALLOWEDIPS) < 0) + goto toobig_peers; - nest_allowed_ips = nla_nest_start (msg, WGPEER_A_ALLOWEDIPS); - if (!nest_allowed_ips) - goto toobig_allowedips; + if (NM_FLAGS_HAS (p_flags, NM_PLATFORM_WIREGUARD_CHANGE_PEER_FLAG_HAS_ENDPOINT)) { + if (NM_IN_SET (p->endpoint.sa.sa_family, AF_INET, AF_INET6)) { + if (nla_put (msg, + WGPEER_A_ENDPOINT, + p->endpoint.sa.sa_family == AF_INET + ? sizeof (p->endpoint.in) + : sizeof (p->endpoint.in6), + &p->endpoint) < 0) + goto toobig_peers; + } else { + /* I think there is no way to clear an endpoint, though there shold be. */ + nm_assert (p->endpoint.sa.sa_family == AF_UNSPEC); + } + } + } - for (; idx_allowed_ips_curr < p->allowed_ips_len; idx_allowed_ips_curr++) { - const NMPWireGuardAllowedIP *aip = &p->allowed_ips[idx_allowed_ips_curr]; + if ( NM_FLAGS_HAS (p_flags, NM_PLATFORM_WIREGUARD_CHANGE_PEER_FLAG_HAS_ALLOWEDIPS) + && p->allowed_ips_len > 0) { + if (idx_allowed_ips_curr == IDX_NIL) + idx_allowed_ips_curr = 0; - nest_curr_allowed_ip = nla_nest_start (msg, 0); - if (!nest_curr_allowed_ip) + nest_allowed_ips = nla_nest_start (msg, WGPEER_A_ALLOWEDIPS); + if (!nest_allowed_ips) goto toobig_allowedips; - g_return_val_if_fail (NM_IN_SET (aip->family, AF_INET, AF_INET6), -NME_BUG); + for (; idx_allowed_ips_curr < p->allowed_ips_len; idx_allowed_ips_curr++) { + const NMPWireGuardAllowedIP *aip = &p->allowed_ips[idx_allowed_ips_curr]; - if (nla_put_uint16 (msg, WGALLOWEDIP_A_FAMILY, aip->family) < 0) - goto toobig_allowedips; - if (nla_put (msg, - WGALLOWEDIP_A_IPADDR, - nm_utils_addr_family_to_size (aip->family), - &aip->addr) < 0) - goto toobig_allowedips; - if (nla_put_uint8 (msg, WGALLOWEDIP_A_CIDR_MASK, aip->mask) < 0) - goto toobig_allowedips; + nest_curr_allowed_ip = nla_nest_start (msg, 0); + if (!nest_curr_allowed_ip) + goto toobig_allowedips; - _nla_nest_end (msg, nest_curr_allowed_ip); - nest_curr_allowed_ip = NULL; - } - idx_allowed_ips_curr = IDX_NIL; + g_return_val_if_fail (NM_IN_SET (aip->family, AF_INET, AF_INET6), -NME_BUG); - _nla_nest_end (msg, nest_allowed_ips); - nest_allowed_ips = NULL; + if (nla_put_uint16 (msg, WGALLOWEDIP_A_FAMILY, aip->family) < 0) + goto toobig_allowedips; + if (nla_put (msg, + WGALLOWEDIP_A_IPADDR, + nm_utils_addr_family_to_size (aip->family), + &aip->addr) < 0) + goto toobig_allowedips; + if (nla_put_uint8 (msg, WGALLOWEDIP_A_CIDR_MASK, aip->mask) < 0) + goto toobig_allowedips; + + _nla_nest_end (msg, nest_curr_allowed_ip); + nest_curr_allowed_ip = NULL; + } + idx_allowed_ips_curr = IDX_NIL; + + _nla_nest_end (msg, nest_allowed_ips); + nest_allowed_ips = NULL; + } } _nla_nest_end (msg, nest_curr_peer); @@ -2555,8 +2591,9 @@ link_wireguard_change (NMPlatform *platform, int ifindex, const NMPlatformLnkWireGuard *lnk_wireguard, const NMPWireGuardPeer *peers, + const NMPlatformWireGuardChangePeerFlags *peer_flags, guint peers_len, - gboolean replace_peers) + NMPlatformWireGuardChangeFlags change_flags) { NMLinuxPlatformPrivate *priv = NM_LINUX_PLATFORM_GET_PRIVATE (platform); gs_unref_ptrarray GPtrArray *msgs = NULL; @@ -2573,8 +2610,9 @@ link_wireguard_change (NMPlatform *platform, wireguard_family_id, lnk_wireguard, peers, + peer_flags, peers_len, - replace_peers, + change_flags, &msgs); if (r < 0) { _LOGW ("wireguard: set-device, cannot construct netlink message: %s", nm_strerror (r)); @@ -2610,7 +2648,7 @@ link_wireguard_change (NMPlatform *platform, static NMPObject * _new_from_nl_link (NMPlatform *platform, const NMPCache *cache, struct nlmsghdr *nlh, gboolean id_only) { - static const struct nla_policy policy[IFLA_MAX+1] = { + static const struct nla_policy policy[] = { [IFLA_IFNAME] = { .type = NLA_STRING, .maxlen = IFNAMSIZ }, [IFLA_MTU] = { .type = NLA_U32 }, @@ -2637,18 +2675,12 @@ _new_from_nl_link (NMPlatform *platform, const NMPCache *cache, struct nlmsghdr [IFLA_PHYS_PORT_ID] = { .type = NLA_UNSPEC }, [IFLA_NET_NS_PID] = { .type = NLA_U32 }, [IFLA_NET_NS_FD] = { .type = NLA_U32 }, - }; - static const struct nla_policy policy_link_info[IFLA_INFO_MAX+1] = { - [IFLA_INFO_KIND] = { .type = NLA_STRING }, - [IFLA_INFO_DATA] = { .type = NLA_NESTED }, - [IFLA_INFO_XSTATS] = { .type = NLA_NESTED }, + [IFLA_LINK_NETNSID] = { }, }; const struct ifinfomsg *ifi; - struct nlattr *tb[IFLA_MAX+1]; - struct nlattr *li[IFLA_INFO_MAX+1]; + struct nlattr *tb[G_N_ELEMENTS (policy)]; struct nlattr *nl_info_data = NULL; const char *nl_info_kind = NULL; - int err; nm_auto_nmpobj NMPObject *obj = NULL; gboolean completed_from_cache_val = FALSE; gboolean *completed_from_cache = cache ? &completed_from_cache_val : NULL; @@ -2662,6 +2694,7 @@ _new_from_nl_link (NMPlatform *platform, const NMPCache *cache, struct nlmsghdr if (!nlmsg_valid_hdr (nlh, sizeof (*ifi))) return NULL; + ifi = nlmsg_data (nlh); if (ifi->ifi_family != AF_UNSPEC) @@ -2674,13 +2707,12 @@ _new_from_nl_link (NMPlatform *platform, const NMPCache *cache, struct nlmsghdr if (id_only) return g_steal_pointer (&obj); - err = nlmsg_parse (nlh, sizeof (*ifi), tb, IFLA_MAX, policy); - if (err < 0) + if (nlmsg_parse_arr (nlh, sizeof (*ifi), tb, policy) < 0) return NULL; if (!tb[IFLA_IFNAME]) return NULL; - nla_strlcpy(obj->link.name, tb[IFLA_IFNAME], IFNAMSIZ); + nla_strlcpy (obj->link.name, tb[IFLA_IFNAME], IFNAMSIZ); if (!obj->link.name[0]) return NULL; @@ -2702,8 +2734,14 @@ _new_from_nl_link (NMPlatform *platform, const NMPCache *cache, struct nlmsghdr obj->link.mtu = nla_get_u32 (tb[IFLA_MTU]); if (tb[IFLA_LINKINFO]) { - err = nla_parse_nested (li, IFLA_INFO_MAX, tb[IFLA_LINKINFO], policy_link_info); - if (err < 0) + static const struct nla_policy policy_link_info[] = { + [IFLA_INFO_KIND] = { .type = NLA_STRING }, + [IFLA_INFO_DATA] = { .type = NLA_NESTED }, + [IFLA_INFO_XSTATS] = { .type = NLA_NESTED }, + }; + struct nlattr *li[G_N_ELEMENTS (policy_link_info)]; + + if (nla_parse_nested_arr (li, tb[IFLA_LINKINFO], policy_link_info) < 0) return NULL; if (li[IFLA_INFO_KIND]) @@ -2713,18 +2751,12 @@ _new_from_nl_link (NMPlatform *platform, const NMPCache *cache, struct nlmsghdr } if (tb[IFLA_STATS64]) { - /* tb[IFLA_STATS64] is only guaranteed to be 32bit-aligned, - * so in general we can't access the rtnl_link_stats64 struct - * members directly on 64bit architectures. */ - char *stats = nla_data (tb[IFLA_STATS64]); + const char *stats = nla_data (tb[IFLA_STATS64]); -#define READ_STAT64(member) \ - unaligned_read_ne64 (stats + offsetof (struct rtnl_link_stats64, member)) - - obj->link.rx_packets = READ_STAT64 (rx_packets); - obj->link.rx_bytes = READ_STAT64 (rx_bytes); - obj->link.tx_packets = READ_STAT64 (tx_packets); - obj->link.tx_bytes = READ_STAT64 (tx_bytes); + obj->link.rx_packets = unaligned_read_ne64 (&stats[G_STRUCT_OFFSET (struct rtnl_link_stats64, rx_packets)]); + obj->link.rx_bytes = unaligned_read_ne64 (&stats[G_STRUCT_OFFSET (struct rtnl_link_stats64, rx_bytes)]); + obj->link.tx_packets = unaligned_read_ne64 (&stats[G_STRUCT_OFFSET (struct rtnl_link_stats64, tx_packets)]); + obj->link.tx_bytes = unaligned_read_ne64 (&stats[G_STRUCT_OFFSET (struct rtnl_link_stats64, tx_bytes)]); } obj->link.n_ifi_flags = ifi->ifi_flags; @@ -2952,14 +2984,14 @@ _new_from_nl_link (NMPlatform *platform, const NMPCache *cache, struct nlmsghdr static NMPObject * _new_from_nl_addr (struct nlmsghdr *nlh, gboolean id_only) { - static const struct nla_policy policy[IFA_MAX+1] = { + static const struct nla_policy policy[] = { [IFA_LABEL] = { .type = NLA_STRING, - .maxlen = IFNAMSIZ }, + .maxlen = IFNAMSIZ }, [IFA_CACHEINFO] = { .minlen = nm_offsetofend (struct ifa_cacheinfo, tstamp) }, + [IFA_FLAGS] = { }, }; + struct nlattr *tb[G_N_ELEMENTS (policy)]; const struct ifaddrmsg *ifa; - struct nlattr *tb[IFA_MAX+1]; - int err; gboolean is_v4; nm_auto_nmpobj NMPObject *obj = NULL; int addr_len; @@ -2967,14 +2999,15 @@ _new_from_nl_addr (struct nlmsghdr *nlh, gboolean id_only) if (!nlmsg_valid_hdr (nlh, sizeof (*ifa))) return NULL; - ifa = nlmsg_data(nlh); + + ifa = nlmsg_data (nlh); if (!NM_IN_SET (ifa->ifa_family, AF_INET, AF_INET6)) return NULL; + is_v4 = ifa->ifa_family == AF_INET; - err = nlmsg_parse (nlh, sizeof(*ifa), tb, IFA_MAX, policy); - if (err < 0) + if (nlmsg_parse_arr (nlh, sizeof (*ifa), tb, policy) < 0) return NULL; addr_len = is_v4 @@ -3043,8 +3076,9 @@ _new_from_nl_addr (struct nlmsghdr *nlh, gboolean id_only) timestamp = 0; /* IPv6 only */ if (tb[IFA_CACHEINFO]) { - const struct ifa_cacheinfo *ca = nla_data(tb[IFA_CACHEINFO]); + const struct ifa_cacheinfo *ca; + ca = nla_data_as (struct ifa_cacheinfo, tb[IFA_CACHEINFO]); lifetime = ca->ifa_valid; preferred = ca->ifa_prefered; timestamp = ca->tstamp; @@ -3063,7 +3097,7 @@ _new_from_nl_addr (struct nlmsghdr *nlh, gboolean id_only) static NMPObject * _new_from_nl_route (struct nlmsghdr *nlh, gboolean id_only) { - static const struct nla_policy policy[RTA_MAX+1] = { + static const struct nla_policy policy[] = { [RTA_TABLE] = { .type = NLA_U32 }, [RTA_IIF] = { .type = NLA_U32 }, [RTA_OIF] = { .type = NLA_U32 }, @@ -3075,8 +3109,7 @@ _new_from_nl_route (struct nlmsghdr *nlh, gboolean id_only) [RTA_MULTIPATH] = { .type = NLA_NESTED }, }; const struct rtmsg *rtm; - struct nlattr *tb[RTA_MAX + 1]; - int err; + struct nlattr *tb[G_N_ELEMENTS (policy)]; gboolean is_v4; nm_auto_nmpobj NMPObject *obj = NULL; int addr_len; @@ -3084,13 +3117,21 @@ _new_from_nl_route (struct nlmsghdr *nlh, gboolean id_only) gboolean is_present; int ifindex; NMIPAddr gateway; - } nh; + } nh = { + .is_present = FALSE, + }; guint32 mss; - guint32 window = 0, cwnd = 0, initcwnd = 0, initrwnd = 0, mtu = 0, lock = 0; + guint32 window = 0; + guint32 cwnd = 0; + guint32 initcwnd = 0; + guint32 initrwnd = 0; + guint32 mtu = 0; + guint32 lock = 0; if (!nlmsg_valid_hdr (nlh, sizeof (*rtm))) return NULL; - rtm = nlmsg_data(nlh); + + rtm = nlmsg_data (nlh); /***************************************************************** * only handle ~normal~ routes. @@ -3102,8 +3143,10 @@ _new_from_nl_route (struct nlmsghdr *nlh, gboolean id_only) if (rtm->rtm_type != RTN_UNICAST) return NULL; - err = nlmsg_parse (nlh, sizeof (struct rtmsg), tb, RTA_MAX, policy); - if (err < 0) + if (nlmsg_parse_arr (nlh, + sizeof (struct rtmsg), + tb, + policy) < 0) return NULL; /*****************************************************************/ @@ -3120,39 +3163,49 @@ _new_from_nl_route (struct nlmsghdr *nlh, gboolean id_only) * parse nexthops. Only handle routes with one nh. *****************************************************************/ - memset (&nh, 0, sizeof (nh)); - if (tb[RTA_MULTIPATH]) { - struct rtnexthop *rtnh = nla_data (tb[RTA_MULTIPATH]); - size_t tlen = nla_len(tb[RTA_MULTIPATH]); + size_t tlen = nla_len (tb[RTA_MULTIPATH]); + struct rtnexthop *rtnh; - while (tlen >= sizeof(*rtnh) && tlen >= rtnh->rtnh_len) { + if (tlen < sizeof (*rtnh)) + goto rta_multipath_done; + + rtnh = nla_data_as (struct rtnexthop, tb[RTA_MULTIPATH]); + + if (tlen < rtnh->rtnh_len) + goto rta_multipath_done; + + while (TRUE) { if (nh.is_present) { /* we don't support multipath routes. */ return NULL; } - nh.is_present = TRUE; + nh.is_present = TRUE; nh.ifindex = rtnh->rtnh_ifindex; - if (rtnh->rtnh_len > sizeof(*rtnh)) { - struct nlattr *ntb[RTA_MAX + 1]; + if (rtnh->rtnh_len > sizeof (*rtnh)) { + struct nlattr *ntb[G_N_ELEMENTS (policy)]; - err = nla_parse (ntb, RTA_MAX, (struct nlattr *) - RTNH_DATA(rtnh), - rtnh->rtnh_len - sizeof (*rtnh), - policy); - if (err < 0) + if (nla_parse_arr (ntb, + (struct nlattr *) RTNH_DATA (rtnh), + rtnh->rtnh_len - sizeof (*rtnh), + policy) < 0) return NULL; if (_check_addr_or_return_null (ntb, RTA_GATEWAY, addr_len)) memcpy (&nh.gateway, nla_data (ntb[RTA_GATEWAY]), addr_len); } - tlen -= RTNH_ALIGN(rtnh->rtnh_len); - rtnh = RTNH_NEXT(rtnh); + if (tlen < RTNH_ALIGN (rtnh->rtnh_len) + sizeof (*rtnh)) + goto rta_multipath_done; + + tlen -= RTNH_ALIGN (rtnh->rtnh_len); + rtnh = RTNH_NEXT (rtnh); } +rta_multipath_done: + ; } if ( tb[RTA_OIF] @@ -3186,8 +3239,7 @@ _new_from_nl_route (struct nlmsghdr *nlh, gboolean id_only) mss = 0; if (tb[RTA_METRICS]) { - struct nlattr *mtb[RTAX_MAX + 1]; - static const struct nla_policy rtax_policy[RTAX_MAX + 1] = { + static const struct nla_policy rtax_policy[] = { [RTAX_LOCK] = { .type = NLA_U32 }, [RTAX_ADVMSS] = { .type = NLA_U32 }, [RTAX_WINDOW] = { .type = NLA_U32 }, @@ -3196,9 +3248,9 @@ _new_from_nl_route (struct nlmsghdr *nlh, gboolean id_only) [RTAX_INITRWND] = { .type = NLA_U32 }, [RTAX_MTU] = { .type = NLA_U32 }, }; + struct nlattr *mtb[G_N_ELEMENTS (rtax_policy)]; - err = nla_parse_nested (mtb, RTAX_MAX, tb[RTA_METRICS], rtax_policy); - if (err < 0) + if (nla_parse_nested_arr (mtb, tb[RTA_METRICS], rtax_policy) < 0) return NULL; if (mtb[RTAX_LOCK]) @@ -3233,7 +3285,7 @@ _new_from_nl_route (struct nlmsghdr *nlh, gboolean id_only) obj->ip_route.plen = rtm->rtm_dst_len; if (tb[RTA_PRIORITY]) - obj->ip_route.metric = nla_get_u32(tb[RTA_PRIORITY]); + obj->ip_route.metric = nla_get_u32 (tb[RTA_PRIORITY]); if (is_v4) obj->ip4_route.gateway = nh.gateway.addr4; @@ -3290,25 +3342,24 @@ _new_from_nl_route (struct nlmsghdr *nlh, gboolean id_only) 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] = { + static const struct nla_policy policy[] = { [TCA_KIND] = { .type = NLA_STRING }, }; + struct nlattr *tb[G_N_ELEMENTS (policy)]; + const struct tcmsg *tcm; + NMPObject *obj; - 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) + if (nlmsg_parse_arr (nlh, + sizeof (*tcm), + tb, + policy) < 0) return NULL; if (!tb[TCA_KIND]) return NULL; + tcm = nlmsg_data (nlh); + obj = nmp_object_new (NMP_OBJECT_TYPE_QDISC, NULL); obj->qdisc.kind = g_intern_string (nla_get_string (tb[TCA_KIND])); @@ -3324,25 +3375,21 @@ _new_from_nl_qdisc (struct nlmsghdr *nlh, gboolean id_only) 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] = { + static const struct nla_policy policy[] = { [TCA_KIND] = { .type = NLA_STRING }, }; + struct nlattr *tb[G_N_ELEMENTS (policy)]; + NMPObject *obj = NULL; + const struct tcmsg *tcm; - 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) + if (nlmsg_parse_arr (nlh, sizeof (*tcm), tb, policy) < 0) return NULL; if (!tb[TCA_KIND]) return NULL; + tcm = nlmsg_data (nlh); + obj = nmp_object_new (NMP_OBJECT_TYPE_TFILTER, NULL); obj->tfilter.kind = g_intern_string (nla_get_string (tb[TCA_KIND])); @@ -3464,14 +3511,14 @@ _nl_msg_new_link_set_linkinfo (struct nl_msg *msg, NLA_PUT_STRING (msg, IFLA_INFO_KIND, kind); if (veth_peer) { - struct ifinfomsg ifi = { }; + const struct ifinfomsg ifi = { }; struct nlattr *data, *info_peer; if (!(data = nla_nest_start (msg, IFLA_INFO_DATA))) goto nla_put_failure; if (!(info_peer = nla_nest_start (msg, 1 /*VETH_INFO_PEER*/))) goto nla_put_failure; - if (nlmsg_append (msg, &ifi, sizeof (ifi), NLMSG_ALIGNTO) < 0) + if (nlmsg_append_struct (msg, &ifi) < 0) goto nla_put_failure; NLA_PUT_STRING (msg, IFLA_IFNAME, veth_peer); nla_nest_end (msg, info_peer); @@ -3575,7 +3622,7 @@ _nl_msg_new_link_set_linkinfo_vlan (struct nl_msg *msg, for (i = 0; i < egress_qos_len; i++) { if (VLAN_XGRESS_PRIO_VALID (egress_qos[i].to)) { if (!qos) { - if (!(qos = nla_nest_start(msg, IFLA_VLAN_EGRESS_QOS))) + if (!(qos = nla_nest_start (msg, IFLA_VLAN_EGRESS_QOS))) goto nla_put_failure; } NLA_PUT (msg, i, sizeof (egress_qos[i]), &egress_qos[i]); @@ -3583,7 +3630,7 @@ _nl_msg_new_link_set_linkinfo_vlan (struct nl_msg *msg, } if (qos) - nla_nest_end(msg, qos); + nla_nest_end (msg, qos); } nla_nest_end (msg, data); @@ -3602,8 +3649,8 @@ _nl_msg_new_link (int nlmsg_type, unsigned flags_mask, unsigned flags_set) { - struct nl_msg *msg; - struct ifinfomsg ifi = { + nm_auto_nlmsg struct nl_msg *msg = NULL; + const struct ifinfomsg ifi = { .ifi_change = flags_mask, .ifi_flags = flags_set, .ifi_index = ifindex, @@ -3613,15 +3660,15 @@ _nl_msg_new_link (int nlmsg_type, msg = nlmsg_alloc_simple (nlmsg_type, nlmsg_flags); - if (nlmsg_append (msg, &ifi, sizeof (ifi), NLMSG_ALIGNTO) < 0) + if (nlmsg_append_struct (msg, &ifi) < 0) goto nla_put_failure; if (ifname) NLA_PUT_STRING (msg, IFLA_IFNAME, ifname); - return msg; + return g_steal_pointer (&msg); + nla_put_failure: - nlmsg_free (msg); g_return_val_if_reached (NULL); } @@ -3640,7 +3687,7 @@ _nl_msg_new_address (int nlmsg_type, guint32 preferred, const char *label) { - struct nl_msg *msg; + nm_auto_nlmsg struct nl_msg *msg = NULL; struct ifaddrmsg am = { .ifa_family = family, .ifa_index = ifindex, @@ -3667,7 +3714,7 @@ _nl_msg_new_address (int nlmsg_type, addr_len = family == AF_INET ? sizeof (in_addr_t) : sizeof (struct in6_addr); - if (nlmsg_append (msg, &am, sizeof (am), NLMSG_ALIGNTO) < 0) + if (nlmsg_append_struct (msg, &am) < 0) goto nla_put_failure; if (address) @@ -3698,7 +3745,7 @@ _nl_msg_new_address (int nlmsg_type, .ifa_prefered = preferred, }; - NLA_PUT (msg, IFA_CACHEINFO, sizeof(ca), &ca); + NLA_PUT (msg, IFA_CACHEINFO, sizeof (ca), &ca); } if (flags & ~((guint32) 0xFF)) { @@ -3711,10 +3758,9 @@ _nl_msg_new_address (int nlmsg_type, NLA_PUT_U32 (msg, IFA_FLAGS, flags); } - return msg; + return g_steal_pointer (&msg); nla_put_failure: - nlmsg_free (msg); g_return_val_if_reached (NULL); } @@ -3734,12 +3780,12 @@ _nl_msg_new_route (int nlmsg_type, guint16 nlmsgflags, const NMPObject *obj) { - struct nl_msg *msg; + nm_auto_nlmsg struct nl_msg *msg = NULL; const NMPClass *klass = NMP_OBJECT_GET_CLASS (obj); gboolean is_v4 = klass->addr_family == AF_INET; const guint32 lock = ip_route_get_lock_flag (NMP_OBJECT_CAST_IP_ROUTE (obj)); const guint32 table = nm_platform_route_table_uncoerce (NMP_OBJECT_CAST_IP_ROUTE (obj)->table_coerced, TRUE); - struct rtmsg rtmsg = { + const struct rtmsg rtmsg = { .rtm_family = klass->addr_family, .rtm_tos = is_v4 ? obj->ip4_route.tos @@ -3766,7 +3812,7 @@ _nl_msg_new_route (int nlmsg_type, msg = nlmsg_alloc_simple (nlmsg_type, (int) nlmsgflags); - if (nlmsg_append (msg, &rtmsg, sizeof (rtmsg), NLMSG_ALIGNTO) < 0) + if (nlmsg_append_struct (msg, &rtmsg) < 0) goto nla_put_failure; addr_len = is_v4 @@ -3824,7 +3870,7 @@ _nl_msg_new_route (int nlmsg_type, if (lock) NLA_PUT_U32 (msg, RTAX_LOCK, lock); - nla_nest_end(msg, metrics); + nla_nest_end (msg, metrics); } /* We currently don't have need for multi-hop routes... */ @@ -3840,10 +3886,9 @@ _nl_msg_new_route (int nlmsg_type, && obj->ip6_route.rt_pref != NM_ICMPV6_ROUTER_PREF_MEDIUM) NLA_PUT_U8 (msg, RTA_PREF, obj->ip6_route.rt_pref); - return msg; + return g_steal_pointer (&msg); nla_put_failure: - nlmsg_free (msg); g_return_val_if_reached (NULL); } @@ -3852,8 +3897,8 @@ _nl_msg_new_qdisc (int nlmsg_type, int nlmsg_flags, const NMPlatformQdisc *qdisc) { - struct nl_msg *msg; - struct tcmsg tcm = { + nm_auto_nlmsg struct nl_msg *msg = NULL; + const struct tcmsg tcm = { .tcm_family = qdisc->addr_family, .tcm_ifindex = qdisc->ifindex, .tcm_handle = qdisc->handle, @@ -3863,14 +3908,14 @@ _nl_msg_new_qdisc (int nlmsg_type, msg = nlmsg_alloc_simple (nlmsg_type, nlmsg_flags); - if (nlmsg_append (msg, &tcm, sizeof (tcm), NLMSG_ALIGNTO) < 0) + if (nlmsg_append_struct (msg, &tcm) < 0) goto nla_put_failure; NLA_PUT_STRING (msg, TCA_KIND, qdisc->kind); - return msg; + return g_steal_pointer (&msg); + nla_put_failure: - nlmsg_free (msg); g_return_val_if_reached (NULL); } @@ -3924,10 +3969,10 @@ _nl_msg_new_tfilter (int nlmsg_type, int nlmsg_flags, const NMPlatformTfilter *tfilter) { - struct nl_msg *msg; + nm_auto_nlmsg struct nl_msg *msg = NULL; struct nlattr *tc_options; struct nlattr *act_tab; - struct tcmsg tcm = { + const struct tcmsg tcm = { .tcm_family = tfilter->addr_family, .tcm_ifindex = tfilter->ifindex, .tcm_handle = tfilter->handle, @@ -3937,7 +3982,7 @@ _nl_msg_new_tfilter (int nlmsg_type, msg = nlmsg_alloc_simple (nlmsg_type, nlmsg_flags); - if (nlmsg_append (msg, &tcm, sizeof (tcm), NLMSG_ALIGNTO) < 0) + if (nlmsg_append_struct (msg, &tcm) < 0) goto nla_put_failure; NLA_PUT_STRING (msg, TCA_KIND, tfilter->kind); @@ -3955,9 +4000,9 @@ _nl_msg_new_tfilter (int nlmsg_type, nla_nest_end (msg, act_tab); - return msg; + return g_steal_pointer (&msg); + nla_put_failure: - nlmsg_free (msg); g_return_val_if_reached (NULL); } @@ -4052,10 +4097,10 @@ sysctl_set (NMPlatform *platform, const char *pathid, int dirfd, const char *pat errsv = errno; if (errsv == ENOENT) { _LOGD ("sysctl: failed to open '%s': (%d) %s", - pathid, errsv, strerror (errsv)); + pathid, errsv, nm_strerror_native (errsv)); } else { _LOGE ("sysctl: failed to open '%s': (%d) %s", - pathid, errsv, strerror (errsv)); + pathid, errsv, nm_strerror_native (errsv)); } errno = errsv; return FALSE; @@ -4066,10 +4111,10 @@ sysctl_set (NMPlatform *platform, const char *pathid, int dirfd, const char *pat errsv = errno; if (errsv == ENOENT) { _LOGD ("sysctl: failed to openat '%s': (%d) %s", - pathid, errsv, strerror (errsv)); + pathid, errsv, nm_strerror_native (errsv)); } else { _LOGE ("sysctl: failed to openat '%s': (%d) %s", - pathid, errsv, strerror (errsv)); + pathid, errsv, nm_strerror_native (errsv)); } errno = errsv; return FALSE; @@ -4119,7 +4164,7 @@ sysctl_set (NMPlatform *platform, const char *pathid, int dirfd, const char *pat } _NMLOG (level, "sysctl: failed to set '%s' to '%s': (%d) %s", - path, value, errsv, strerror (errsv)); + path, value, errsv, nm_strerror_native (errsv)); } else if (nwrote < len - 1) { _LOGE ("sysctl: failed to set '%s' to '%s' after three attempts", path, value); @@ -4146,8 +4191,8 @@ sysctl_set (NMPlatform *platform, const char *pathid, int dirfd, const char *pat static GSList *sysctl_clear_cache_list; -static void -_nm_logging_clear_platform_logging_cache_impl (void) +void +_nm_logging_clear_platform_logging_cache (void) { while (sysctl_clear_cache_list) { NMLinuxPlatformPrivate *priv = NM_LINUX_PLATFORM_GET_PRIVATE (sysctl_clear_cache_list->data); @@ -4156,42 +4201,71 @@ _nm_logging_clear_platform_logging_cache_impl (void) g_hash_table_destroy (priv->sysctl_get_prev_values); priv->sysctl_get_prev_values = NULL; - priv->sysctl_get_warned = FALSE; } } +typedef struct { + const char *path; + CList lst; + char *value; + char path_data[]; +} SysctlCacheEntry; + +static void +sysctl_cache_entry_free (SysctlCacheEntry *entry) +{ + c_list_unlink_stale (&entry->lst); + g_free (entry->value); + g_free (entry); +} + static void _log_dbg_sysctl_get_impl (NMPlatform *platform, const char *pathid, const char *contents) { NMLinuxPlatformPrivate *priv = NM_LINUX_PLATFORM_GET_PRIVATE (platform); - const char *prev_value = NULL; + SysctlCacheEntry *entry = NULL; if (!priv->sysctl_get_prev_values) { - _nm_logging_clear_platform_logging_cache = _nm_logging_clear_platform_logging_cache_impl; sysctl_clear_cache_list = g_slist_prepend (sysctl_clear_cache_list, platform); - priv->sysctl_get_prev_values = g_hash_table_new_full (nm_str_hash, g_str_equal, g_free, g_free); + c_list_init (&priv->sysctl_list); + priv->sysctl_get_prev_values = g_hash_table_new_full (nm_pstr_hash, + nm_pstr_equal, + (GDestroyNotify) sysctl_cache_entry_free, + NULL); } else - prev_value = g_hash_table_lookup (priv->sysctl_get_prev_values, pathid); + entry = g_hash_table_lookup (priv->sysctl_get_prev_values, &pathid); - if (prev_value) { - if (strcmp (prev_value, contents) != 0) { + if (entry) { + if (!nm_streq (entry->value, contents)) { gs_free char *contents_escaped = g_strescape (contents, NULL); - gs_free char *prev_value_escaped = g_strescape (prev_value, NULL); + gs_free char *prev_value_escaped = g_strescape (entry->value, NULL); _LOGD ("sysctl: reading '%s': '%s' (changed from '%s' on last read)", pathid, contents_escaped, prev_value_escaped); - g_hash_table_insert (priv->sysctl_get_prev_values, g_strdup (pathid), g_strdup (contents)); + g_free (entry->value); + entry->value = g_strdup (contents); } + nm_c_list_move_front (&priv->sysctl_list, &entry->lst); } else { gs_free char *contents_escaped = g_strescape (contents, NULL); + SysctlCacheEntry *old; + size_t len; + + len = strlen (pathid); + entry = g_malloc (sizeof (SysctlCacheEntry) + len + 1); + entry->value = g_strdup (contents); + entry->path = entry->path_data; + memcpy (entry->path_data, pathid, len + 1); + + /* Remove oldest entry when the cache becomes too big */ + if (g_hash_table_size (priv->sysctl_get_prev_values) > 1000) { + old = c_list_last_entry (&priv->sysctl_list, SysctlCacheEntry, lst); + g_hash_table_remove (priv->sysctl_get_prev_values, old); + } _LOGD ("sysctl: reading '%s': '%s'", pathid, contents_escaped); - g_hash_table_insert (priv->sysctl_get_prev_values, g_strdup (pathid), g_strdup (contents)); - if ( !priv->sysctl_get_warned - && g_hash_table_size (priv->sysctl_get_prev_values) > 50000) { - _LOGW ("sysctl: the internal cache for debug-logging of sysctl values grew pretty large. You can clear it by disabling debug-logging: `nmcli general logging level KEEP domains PLATFORM:INFO`."); - priv->sysctl_get_warned = TRUE; - } + g_hash_table_add (priv->sysctl_get_prev_values, entry); + c_list_link_front (&priv->sysctl_list, &entry->lst); } } @@ -4575,9 +4649,8 @@ delayed_action_handle_one (NMPlatform *platform) priv->delayed_action.flags &= ~DELAYED_ACTION_TYPE_REFRESH_ALL; if (_LOGt_ENABLED ()) { - FOR_EACH_DELAYED_ACTION (iflags, flags) { + FOR_EACH_DELAYED_ACTION (iflags, flags) _LOGt_delayed_action (iflags, NULL, "handle"); - } } delayed_action_handle_REFRESH_ALL (platform, flags); @@ -4661,9 +4734,8 @@ delayed_action_schedule (NMPlatform *platform, DelayedActionType action_type, gp priv->delayed_action.flags |= action_type; if (_LOGt_ENABLED ()) { - FOR_EACH_DELAYED_ACTION (iflags, action_type) { + FOR_EACH_DELAYED_ACTION (iflags, action_type) _LOGt_delayed_action (iflags, user_data, "schedule"); - } } } @@ -4993,7 +5065,7 @@ _nl_send_nlmsghdr (NMPlatform *platform, { NMLinuxPlatformPrivate *priv = NM_LINUX_PLATFORM_GET_PRIVATE (platform); guint32 seq; - int nle; + int errsv; nm_assert (nlhdr); @@ -5010,7 +5082,7 @@ _nl_send_nlmsghdr (NMPlatform *platform, }; struct msghdr msg = { .msg_name = &nladdr, - .msg_namelen = sizeof(nladdr), + .msg_namelen = sizeof (nladdr), .msg_iov = &iov, .msg_iovlen = 1, }; @@ -5022,13 +5094,13 @@ _nl_send_nlmsghdr (NMPlatform *platform, try_count = 0; again: - nle = sendmsg (nl_socket_get_fd (priv->nlh), &msg, 0); - if (nle < 0) { - nle = errno; - if (nle == EINTR && try_count++ < 100) + errsv = sendmsg (nl_socket_get_fd (priv->nlh), &msg, 0); + if (errsv < 0) { + errsv = errno; + if (errsv == EINTR && try_count++ < 100) goto again; - _LOGD ("netlink: nl-send-nlmsghdr: failed sending message: %s (%d)", g_strerror (nle), nle); - return -nle; + _LOGD ("netlink: nl-send-nlmsghdr: failed sending message: %s (%d)", nm_strerror_native (errsv), errsv); + return -nm_errno_from_native (errsv); } } @@ -5125,6 +5197,59 @@ do_request_link (NMPlatform *platform, int ifindex, const char *name) delayed_action_handle_all (platform, FALSE); } +static struct nl_msg * +_nl_msg_new_dump (NMPObjectType obj_type, + int preferred_addr_family) +{ + nm_auto_nlmsg struct nl_msg *nlmsg = NULL; + const NMPClass *klass; + + klass = nmp_class_from_type (obj_type); + + nm_assert (klass); + nm_assert (klass->rtm_gettype > 0); + + nlmsg = nlmsg_alloc_simple (klass->rtm_gettype, NLM_F_DUMP); + + if (klass->addr_family != AF_UNSPEC) { + /* if the class specifies a particular address family, then it is preferred. */ + nm_assert (NM_IN_SET (preferred_addr_family, AF_UNSPEC, klass->addr_family)); + preferred_addr_family = klass->addr_family; + } + + switch (klass->obj_type) { + case NMP_OBJECT_TYPE_QDISC: + case NMP_OBJECT_TYPE_TFILTER: + { + const struct tcmsg tcmsg = { + .tcm_family = preferred_addr_family, + }; + + if (nlmsg_append_struct (nlmsg, &tcmsg) < 0) + g_return_val_if_reached (NULL); + } + break; + case NMP_OBJECT_TYPE_LINK: + case NMP_OBJECT_TYPE_IP4_ADDRESS: + case NMP_OBJECT_TYPE_IP6_ADDRESS: + case NMP_OBJECT_TYPE_IP4_ROUTE: + case NMP_OBJECT_TYPE_IP6_ROUTE: + { + const struct rtgenmsg gmsg = { + .rtgen_family = preferred_addr_family, + }; + + if (nlmsg_append_struct (nlmsg, &gmsg) < 0) + g_return_val_if_reached (NULL); + } + break; + default: + g_return_val_if_reached (NULL); + } + + return g_steal_pointer (&nlmsg); +} + static void do_request_all_no_delayed_actions (NMPlatform *platform, DelayedActionType action_type) { @@ -5135,16 +5260,18 @@ do_request_all_no_delayed_actions (NMPlatform *platform, DelayedActionType actio action_type &= DELAYED_ACTION_TYPE_REFRESH_ALL; FOR_EACH_DELAYED_ACTION (iflags, action_type) { + NMPLookup lookup; + priv->pruning[delayed_action_refresh_all_to_idx (iflags)] = TRUE; + nmp_lookup_init_obj_type (&lookup, + delayed_action_refresh_to_object_type (iflags)); nmp_cache_dirty_set_all (nm_platform_get_cache (platform), - delayed_action_refresh_to_object_type (iflags)); + &lookup); } FOR_EACH_DELAYED_ACTION (iflags, action_type) { 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; - int nle; int *out_refresh_all_in_progress; out_refresh_all_in_progress = &priv->delayed_action.refresh_all_in_progress[delayed_action_refresh_all_to_idx (iflags)]; @@ -5162,31 +5289,23 @@ do_request_all_no_delayed_actions (NMPlatform *platform, DelayedActionType actio event_handler_read_netlink (platform, FALSE); - /* reimplement - * nl_rtgen_request (sk, klass->rtm_gettype, klass->addr_family, NLM_F_DUMP); - * because we need the sequence number. - */ - nlmsg = nlmsg_alloc_simple (klass->rtm_gettype, NLM_F_DUMP); + nlmsg = _nl_msg_new_dump (obj_type, AF_UNSPEC); + if (!nlmsg) + goto next_after_fail; - 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; + if (_nl_send_nlmsg (platform, + nlmsg, + NULL, + NULL, + DELAYED_ACTION_RESPONSE_TYPE_REFRESH_ALL_IN_PROGRESS, + out_refresh_all_in_progress) < 0) + goto next_after_fail; - if (_nl_send_nlmsg (platform, nlmsg, NULL, NULL, DELAYED_ACTION_RESPONSE_TYPE_REFRESH_ALL_IN_PROGRESS, out_refresh_all_in_progress) < 0) { - nm_assert (*out_refresh_all_in_progress > 0); - *out_refresh_all_in_progress -= 1; - } + continue; + +next_after_fail: + nm_assert (*out_refresh_all_in_progress > 0); + *out_refresh_all_in_progress -= 1; } } @@ -5273,9 +5392,9 @@ event_valid_msg (NMPlatform *platform, struct nl_msg *msg, gboolean handle_event NMPCacheOpsType cache_op; struct nlmsghdr *msghdr; char buf_nlmsghdr[400]; - gboolean id_only = FALSE; + gboolean is_del = FALSE; + gboolean is_dump = FALSE; NMPCache *cache = nm_platform_get_cache (platform); - gboolean is_dump; msghdr = nlmsg_hdr (msg); @@ -5286,37 +5405,38 @@ event_valid_msg (NMPlatform *platform, struct nl_msg *msg, gboolean handle_event if (!handle_events) return; - if (NM_IN_SET (msghdr->nlmsg_type, RTM_DELLINK, RTM_DELADDR, RTM_DELROUTE)) { + if (NM_IN_SET (msghdr->nlmsg_type, RTM_DELLINK, + RTM_DELADDR, + RTM_DELROUTE, + RTM_DELQDISC, + RTM_DELTFILTER)) { /* The event notifies about a deleted object. We don't need to initialize all * fields of the object. */ - id_only = TRUE; + is_del = TRUE; } - obj = nmp_object_new_from_nl (platform, cache, msg, id_only); + obj = nmp_object_new_from_nl (platform, cache, msg, is_del); if (!obj) { _LOGT ("event-notification: %s: ignore", nl_nlmsghdr_to_str (msghdr, buf_nlmsghdr, sizeof (buf_nlmsghdr))); return; } - switch (msghdr->nlmsg_type) { - case RTM_NEWADDR: - case RTM_NEWLINK: - case RTM_NEWROUTE: - case RTM_NEWQDISC: - case RTM_NEWTFILTER: + if ( !is_del + && NM_IN_SET (msghdr->nlmsg_type, RTM_NEWADDR, + RTM_NEWLINK, + RTM_NEWROUTE, + RTM_NEWQDISC, + RTM_NEWTFILTER)) { is_dump = delayed_action_refresh_all_in_progress (platform, delayed_action_refresh_from_object_type (NMP_OBJECT_GET_TYPE (obj))); - break; - default: - is_dump = FALSE; } _LOGT ("event-notification: %s%s: %s", nl_nlmsghdr_to_str (msghdr, buf_nlmsghdr, sizeof (buf_nlmsghdr)), is_dump ? ", in-dump" : "", nmp_object_to_string (obj, - id_only ? NMP_OBJECT_TO_STRING_ID : NMP_OBJECT_TO_STRING_PUBLIC, + is_del ? NMP_OBJECT_TO_STRING_ID : NMP_OBJECT_TO_STRING_PUBLIC, NULL, 0)); { @@ -6067,6 +6187,7 @@ link_set_sriov_params (NMPlatform *platform, gint64 current_num; char ifname[IFNAMSIZ]; char buf[64]; + int errsv; if (!nm_platform_netns_push (platform, &netns)) return FALSE; @@ -6114,7 +6235,8 @@ link_set_sriov_params (NMPlatform *platform, ifname, "device/sriov_numvfs"), "0")) { - _LOGW ("link: couldn't reset SR-IOV num_vfs: %s", strerror (errno)); + errsv = errno; + _LOGW ("link: couldn't reset SR-IOV num_vfs: %s", nm_strerror_native (errsv)); return FALSE; } } @@ -6129,7 +6251,8 @@ link_set_sriov_params (NMPlatform *platform, ifname, "device/sriov_drivers_autoprobe"), nm_sprintf_buf (buf, "%d", (int) autoprobe))) { - _LOGW ("link: couldn't set SR-IOV drivers-autoprobe to %d: %s", (int) autoprobe, strerror (errno)); + errsv = errno; + _LOGW ("link: couldn't set SR-IOV drivers-autoprobe to %d: %s", (int) autoprobe, nm_strerror_native (errsv)); return FALSE; } @@ -6138,7 +6261,8 @@ link_set_sriov_params (NMPlatform *platform, ifname, "device/sriov_numvfs"), nm_sprintf_buf (buf, "%u", num_vfs))) { - _LOGW ("link: couldn't set SR-IOV num_vfs to %d: %s", num_vfs, strerror (errno)); + errsv = errno; + _LOGW ("link: couldn't set SR-IOV num_vfs to %d: %s", num_vfs, nm_strerror_native (errsv)); return FALSE; } @@ -7373,7 +7497,7 @@ ip6_address_add (NMPlatform *platform, ifindex, &addr, plen, - &peer_addr, + IN6_IS_ADDR_UNSPECIFIED (&peer_addr) ? NULL : &peer_addr, flags, RT_SCOPE_UNIVERSE, lifetime, @@ -7548,7 +7672,7 @@ ip_route_get (NMPlatform *platform, nle = _nl_send_nlmsghdr (platform, &req.n, &seq_result, NULL, DELAYED_ACTION_RESPONSE_TYPE_ROUTE_GET, &route); if (nle < 0) { _LOGE ("get-route: failure sending netlink request \"%s\" (%d)", - g_strerror (-nle), -nle); + nm_strerror_native (-nle), -nle); return -NME_UNSPEC; } @@ -7792,20 +7916,22 @@ continue_reading: err = -NME_NL_MSG_TRUNC; abort_parsing = TRUE; } else if (e->error) { - int errsv = e->error > 0 ? e->error : -e->error; + int errsv = nm_errno_native (e->error); if ( NM_FLAGS_HAS (hdr->nlmsg_flags, NLM_F_ACK_TLVS) && hdr->nlmsg_len >= sizeof (*e) + e->msg.nlmsg_len) { - static const struct nla_policy policy[NLMSGERR_ATTR_MAX + 1] = { + static const struct nla_policy policy[] = { [NLMSGERR_ATTR_MSG] = { .type = NLA_STRING }, [NLMSGERR_ATTR_OFFS] = { .type = NLA_U32 }, }; - struct nlattr *tb[NLMSGERR_ATTR_MAX + 1]; + struct nlattr *tb[G_N_ELEMENTS (policy)]; struct nlattr *tlvs; tlvs = (struct nlattr *) ((char *) e + sizeof (*e) + e->msg.nlmsg_len - NLMSG_HDRLEN); - if (!nla_parse (tb, NLMSGERR_ATTR_MAX, tlvs, - hdr->nlmsg_len - sizeof (*e) - e->msg.nlmsg_len, policy)) { + if (nla_parse_arr (tb, + tlvs, + hdr->nlmsg_len - sizeof (*e) - e->msg.nlmsg_len, + policy) >= 0) { if (tb[NLMSGERR_ATTR_MSG]) extack_msg = nla_get_string (tb[NLMSGERR_ATTR_MSG]); } @@ -7813,11 +7939,11 @@ continue_reading: /* Error message reported back from kernel. */ _LOGD ("netlink: recvmsg: error message from kernel: %s (%d)%s%s%s for request %d", - strerror (errsv), + nm_strerror_native (errsv), errsv, NM_PRINT_FMT_QUOTED (extack_msg, " \"", extack_msg, "\"", ""), nlmsg_hdr (msg)->nlmsg_seq); - seq_result = -errsv; + seq_result = -NM_ERRNO_NATIVE (errsv); } else seq_result = WAIT_FOR_NL_RESPONSE_RESULT_RESPONSE_OK; } else @@ -7976,7 +8102,7 @@ after_read: int errsv = errno; if (errsv != EINTR) { - _LOGE ("netlink: read: poll failed with %s", strerror (errsv)); + _LOGE ("netlink: read: poll failed with %s", nm_strerror_native (errsv)); delayed_action_wait_for_nl_response_complete_all (platform, WAIT_FOR_NL_RESPONSE_RESULT_FAILED_POLL); return any; } diff --git a/src/platform/nm-netlink.c b/src/platform/nm-netlink.c index 6abc1c3a..71506a2c 100644 --- a/src/platform/nm-netlink.c +++ b/src/platform/nm-netlink.c @@ -25,8 +25,6 @@ #include <unistd.h> #include <fcntl.h> -#include "nm-utils/nm-errno.h" - /*****************************************************************************/ #ifndef SOL_NETLINK @@ -104,21 +102,30 @@ nl_nlmsghdr_to_str (const struct nlmsghdr *hdr, char *buf, gsize len) b = buf; switch (hdr->nlmsg_type) { - case RTM_NEWLINK: s = "RTM_NEWLINK"; break; - case RTM_DELLINK: s = "RTM_DELLINK"; break; - case RTM_NEWADDR: s = "RTM_NEWADDR"; break; - case RTM_DELADDR: s = "RTM_DELADDR"; break; - case RTM_NEWROUTE: s = "RTM_NEWROUTE"; break; - case RTM_DELROUTE: s = "RTM_DELROUTE"; break; - case RTM_NEWQDISC: s = "RTM_NEWQDISC"; break; - case RTM_DELQDISC: s = "RTM_DELQDISC"; break; - case RTM_NEWTFILTER: s = "RTM_NEWTFILTER"; break; - case RTM_DELTFILTER: s = "RTM_DELTFILTER"; break; - case NLMSG_NOOP: s = "NLMSG_NOOP"; break; - case NLMSG_ERROR: s = "NLMSG_ERROR"; break; - case NLMSG_DONE: s = "NLMSG_DONE"; break; - case NLMSG_OVERRUN: s = "NLMSG_OVERRUN"; break; - default: s = NULL; break; + case RTM_GETLINK: s = "RTM_GETLINK"; break; + case RTM_NEWLINK: s = "RTM_NEWLINK"; break; + case RTM_DELLINK: s = "RTM_DELLINK"; break; + case RTM_SETLINK: s = "RTM_SETLINK"; break; + case RTM_GETADDR: s = "RTM_GETADDR"; break; + case RTM_NEWADDR: s = "RTM_NEWADDR"; break; + case RTM_DELADDR: s = "RTM_DELADDR"; break; + case RTM_GETROUTE: s = "RTM_GETROUTE"; break; + case RTM_NEWROUTE: s = "RTM_NEWROUTE"; break; + case RTM_DELROUTE: s = "RTM_DELROUTE"; break; + case RTM_GETRULE: s = "RTM_GETRULE"; break; + case RTM_NEWRULE: s = "RTM_NEWRULE"; break; + case RTM_DELRULE: s = "RTM_DELRULE"; break; + case RTM_GETQDISC: s = "RTM_GETQDISC"; break; + case RTM_NEWQDISC: s = "RTM_NEWQDISC"; break; + case RTM_DELQDISC: s = "RTM_DELQDISC"; break; + case RTM_GETTFILTER: s = "RTM_GETTFILTER"; 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) @@ -207,6 +214,8 @@ nlmsg_reserve (struct nl_msg *n, size_t len, int pad) size_t nlmsg_len = n->nm_nlh->nlmsg_len; size_t tlen; + nm_assert (pad >= 0); + if (len > n->nm_size) return NULL; @@ -261,11 +270,12 @@ nlmsg_alloc_size (size_t len) if (len < sizeof (struct nlmsghdr)) len = sizeof (struct nlmsghdr); - nm = g_slice_new0 (struct nl_msg); - - nm->nm_protocol = -1; - nm->nm_size = len; - nm->nm_nlh = g_malloc0 (len); + nm = g_slice_new (struct nl_msg); + *nm = (struct nl_msg) { + .nm_protocol = -1, + .nm_size = len, + .nm_nlh = g_malloc0 (len), + }; nm->nm_nlh->nlmsg_len = nlmsg_total_size (0); return nm; } @@ -320,10 +330,18 @@ void nlmsg_free (struct nl_msg *msg) /*****************************************************************************/ int -nlmsg_append (struct nl_msg *n, void *data, size_t len, int pad) +nlmsg_append (struct nl_msg *n, + const void *data, + size_t len, + int pad) { void *tmp; + nm_assert (n); + nm_assert (data); + nm_assert (len > 0); + nm_assert (pad >= 0); + tmp = nlmsg_reserve (n, len, pad); if (tmp == NULL) return -ENOMEM; @@ -367,48 +385,77 @@ nlmsg_put (struct nl_msg *n, uint32_t pid, uint32_t seq, return nlh; } -uint64_t -nla_get_u64 (const struct nlattr *nla) -{ - uint64_t tmp = 0; - - if (nla && nla_len (nla) >= sizeof (tmp)) - memcpy (&tmp, nla_data (nla), sizeof (tmp)); - - return tmp; -} - size_t -nla_strlcpy (char *dst, const struct nlattr *nla, size_t dstsize) -{ - size_t srclen = nla_len (nla); - const char *src = nla_data (nla); - - if (srclen > 0 && src[srclen - 1] == '\0') - srclen--; +nla_strlcpy (char *dst, + const struct nlattr *nla, + size_t dstsize) +{ + const char *src; + size_t srclen; + size_t len; + + /* - Always writes @dstsize bytes to @dst + * - Copies the first non-NUL characters to @dst. + * Any characters after the first NUL bytes in @nla are ignored. + * - If the string @nla is longer than @dstsize, the string + * gets truncated. @dst will always be NUL terminated. */ + + if (G_UNLIKELY (dstsize <= 1)) { + if (dstsize == 1) + dst[0] = '\0'; + if ( nla + && (srclen = nla_len (nla)) > 0) + return strnlen (nla_data (nla), srclen); + return 0; + } - if (dstsize > 0) { - size_t len = (srclen >= dstsize) ? dstsize - 1 : srclen; + nm_assert (dst); - memset (dst, 0, dstsize); - memcpy (dst, src, len); + if (nla) { + srclen = nla_len (nla); + if (srclen > 0) { + src = nla_data (nla); + srclen = strnlen (src, srclen); + if (srclen > 0) { + len = NM_MIN (dstsize - 1, srclen); + memcpy (dst, src, len); + memset (&dst[len], 0, dstsize - len); + return srclen; + } + } } - return srclen; + memset (dst, 0, dstsize); + return 0; } -int -nla_memcpy (void *dest, const struct nlattr *src, int count) +size_t +nla_memcpy (void *dst, const struct nlattr *nla, size_t dstsize) { - int minlen; + size_t len; + int srclen; - if (!src) + if (!nla) return 0; - minlen = NM_MIN (count, (int) nla_len (src)); - memcpy (dest, nla_data (src), minlen); + srclen = nla_len (nla); - return minlen; + if (srclen <= 0) { + nm_assert (srclen == 0); + return 0; + } + + len = NM_MIN ((size_t) srclen, dstsize); + if (len > 0) { + /* there is a crucial difference between nla_strlcpy() and nla_memcpy(). + * The former always write @dstsize bytes (akin to strncpy()), here, we only + * write the bytes that we actually have (leaving the remainder undefined). */ + memcpy (dst, + nla_data (nla), + len); + } + + return srclen; } int @@ -548,7 +595,11 @@ validate_nla (const struct nlattr *nla, int maxtype, return -NME_UNSPEC; if (pt->type == NLA_STRING) { - const char *data = nla_data (nla); + const char *data; + + nm_assert (minlen > 0); + + data = nla_data (nla); if (data[nla_len (nla) - 1] != '\0') return -NME_UNSPEC; } @@ -574,15 +625,13 @@ nla_parse (struct nlattr *tb[], int maxtype, struct nlattr *head, int len, if (policy) { nmerr = validate_nla (nla, maxtype, policy); if (nmerr < 0) - goto errout; + return nmerr; } tb[type] = nla; } - nmerr = 0; -errout: - return nmerr; + return 0; } /*****************************************************************************/ @@ -721,21 +770,21 @@ genlmsg_parse (struct nlmsghdr *nlh, int hdrlen, struct nlattr *tb[], static int _genl_parse_getfamily (struct nl_msg *msg, void *arg) { - static const struct nla_policy ctrl_policy[CTRL_ATTR_MAX+1] = { + static const struct nla_policy ctrl_policy[] = { [CTRL_ATTR_FAMILY_ID] = { .type = NLA_U16 }, [CTRL_ATTR_FAMILY_NAME] = { .type = NLA_STRING, - .maxlen = GENL_NAMSIZ }, + .maxlen = GENL_NAMSIZ }, [CTRL_ATTR_VERSION] = { .type = NLA_U32 }, [CTRL_ATTR_HDRSIZE] = { .type = NLA_U32 }, [CTRL_ATTR_MAXATTR] = { .type = NLA_U32 }, [CTRL_ATTR_OPS] = { .type = NLA_NESTED }, [CTRL_ATTR_MCAST_GROUPS] = { .type = NLA_NESTED }, }; - struct nlattr *tb[CTRL_ATTR_MAX+1]; + struct nlattr *tb[G_N_ELEMENTS (ctrl_policy)]; struct nlmsghdr *nlh = nlmsg_hdr (msg); gint32 *response_data = arg; - if (genlmsg_parse (nlh, 0, tb, CTRL_ATTR_MAX, ctrl_policy)) + if (genlmsg_parse_arr (nlh, 0, tb, ctrl_policy) < 0) return NL_SKIP; if (tb[CTRL_ATTR_FAMILY_ID]) @@ -1061,7 +1110,7 @@ do { \ nmerr = _cb->type##_cb ((msg), _cb->type##_arg); \ switch (nmerr) { \ case NL_OK: \ - nmerr = 0; \ + nm_assert (nmerr == 0); \ break; \ case NL_SKIP: \ goto skip; \ @@ -1206,6 +1255,7 @@ skip: /* Multipart message not yet complete, continue reading */ nm_clear_g_free (&buf); + nmerr = 0; goto continue_reading; } @@ -1333,6 +1383,7 @@ nl_recv (struct nl_sock *sk, struct ucred tmpcreds; gboolean tmpcreds_has = FALSE; int retval; + int errsv; nm_assert (nla); nm_assert (buf && !*buf); @@ -1361,10 +1412,10 @@ retry: } if (n < 0) { - if (errno == EINTR) + errsv = errno; + if (errsv == EINTR) goto retry; - - retval = -nm_errno_from_native (errno); + retval = -nm_errno_from_native (errsv); goto abort; } diff --git a/src/platform/nm-netlink.h b/src/platform/nm-netlink.h index 84bbe27b..094a3c6f 100644 --- a/src/platform/nm-netlink.h +++ b/src/platform/nm-netlink.h @@ -25,6 +25,8 @@ #include <linux/rtnetlink.h> #include <linux/genetlink.h> +#include "nm-utils/unaligned.h" + /*****************************************************************************/ #define NLMSGERR_ATTR_UNUSED 0 @@ -87,8 +89,26 @@ struct nla_policy { /*****************************************************************************/ +/* static asserts that @tb and @policy are suitable arguments to nla_parse(). */ +#define _nl_static_assert_tb(tb, policy) \ + G_STMT_START { \ + \ + G_STATIC_ASSERT_EXPR (G_N_ELEMENTS (tb) > 0); \ + \ + /* we allow @policy to be either NULL or a C array. */ \ + G_STATIC_ASSERT_EXPR ( sizeof (policy) == sizeof (NULL) \ + || G_N_ELEMENTS (tb) == (sizeof (policy) / sizeof (struct nla_policy))); \ + \ + /* For above check to work, we don't support policy being an array with same size as + * sizeof(NULL), otherwise, the compile time check breaks down. */ \ + G_STATIC_ASSERT_EXPR (sizeof (NULL) != G_N_ELEMENTS (tb) * sizeof (struct nla_policy)); \ + \ + } G_STMT_END + +/*****************************************************************************/ + static inline int -nla_attr_size(int payload) +nla_attr_size (int payload) { nm_assert (payload >= 0); @@ -104,7 +124,7 @@ nla_total_size (int payload) static inline int nla_padlen (int payload) { - return nla_total_size(payload) - nla_attr_size(payload); + return nla_total_size (payload) - nla_attr_size (payload); } struct nlattr *nla_reserve (struct nl_msg *msg, int attrtype, int attrlen); @@ -112,32 +132,56 @@ struct nlattr *nla_reserve (struct nl_msg *msg, int attrtype, int attrlen); static inline int nla_len (const struct nlattr *nla) { - return nla->nla_len - NLA_HDRLEN; + nm_assert (nla); + nm_assert (nla->nla_len >= NLA_HDRLEN); + + return ((int) nla->nla_len) - NLA_HDRLEN; } static inline int nla_type (const struct nlattr *nla) { + nm_assert (nla_len (nla) >= 0); + return nla->nla_type & NLA_TYPE_MASK; } static inline void * nla_data (const struct nlattr *nla) { - nm_assert (nla); - return (char *) nla + NLA_HDRLEN; + nm_assert (nla_len (nla) >= 0); + + return &(((char *) nla)[NLA_HDRLEN]); } +#define nla_data_as(type, nla) \ + ({ \ + const struct nlattr *_nla = (nla); \ + \ + nm_assert (nla_len (_nla) >= sizeof (type)); \ + \ + /* note that casting the pointer is undefined behavior in C, if + * the data has wrong alignment. Netlink data is aligned to 4 bytes, + * that means, if the alignment is larger than 4, this is invalid. */ \ + G_STATIC_ASSERT_EXPR (_nm_alignof (type) <= NLA_ALIGNTO); \ + \ + (type *) nla_data (_nla); \ + }) + static inline uint8_t nla_get_u8 (const struct nlattr *nla) { - return *(const uint8_t *) nla_data (nla); + nm_assert (nla_len (nla) >= sizeof (uint8_t)); + + return *((const uint8_t *) nla_data (nla)); } -static inline uint8_t +static inline int8_t nla_get_s8 (const struct nlattr *nla) { - return *(const int8_t *) nla_data (nla); + nm_assert (nla_len (nla) >= sizeof (int8_t)); + + return *((const int8_t *) nla_data (nla)); } static inline uint8_t @@ -152,39 +196,80 @@ nla_get_u8_cond (/*const*/ struct nlattr *const*tb, int attr, uint8_t default_va static inline uint16_t nla_get_u16 (const struct nlattr *nla) { - return *(const uint16_t *) nla_data (nla); + nm_assert (nla_len (nla) >= sizeof (uint16_t)); + + return *((const uint16_t *) nla_data (nla)); } static inline uint32_t -nla_get_u32(const struct nlattr *nla) +nla_get_u32 (const struct nlattr *nla) { - return *(const uint32_t *) nla_data (nla); + nm_assert (nla_len (nla) >= sizeof (uint32_t)); + + return *((const uint32_t *) nla_data (nla)); } static inline int32_t -nla_get_s32(const struct nlattr *nla) +nla_get_s32 (const struct nlattr *nla) { - return *(const int32_t *) nla_data (nla); + nm_assert (nla_len (nla) >= sizeof (int32_t)); + + return *((const int32_t *) nla_data (nla)); +} + +static inline uint64_t +nla_get_u64 (const struct nlattr *nla) +{ + nm_assert (nla_len (nla) >= sizeof (uint64_t)); + + return unaligned_read_ne64 (nla_data (nla)); } -uint64_t nla_get_u64 (const struct nlattr *nla); +static inline uint64_t +nla_get_be64 (const struct nlattr *nla) +{ + nm_assert (nla_len (nla) >= sizeof (uint64_t)); + + return unaligned_read_be64 (nla_data (nla)); +} static inline char * nla_get_string (const struct nlattr *nla) { + nm_assert (nla_len (nla) >= 0); + return (char *) nla_data (nla); } size_t nla_strlcpy (char *dst, const struct nlattr *nla, size_t dstsize); -int nla_memcpy (void *dest, const struct nlattr *src, int count); +size_t nla_memcpy (void *dst, const struct nlattr *nla, size_t dstsize); + +#define nla_memcpy_checked_size(dst, nla, dstsize) \ + G_STMT_START { \ + void *const _dst = (dst); \ + const struct nlattr *const _nla = (nla); \ + const size_t _dstsize = (dstsize); \ + size_t _srcsize; \ + \ + /* assert that, if @nla is given, that it has the exact expected + * size. This implies that the caller previously verified the length + * of the attribute (via minlen/maxlen at nla_parse()). */ \ + \ + if (_nla) { \ + _srcsize = nla_memcpy (_dst, _nla, _dstsize); \ + nm_assert (_srcsize == _dstsize); \ + } \ + } G_STMT_END int nla_put (struct nl_msg *msg, int attrtype, int datalen, const void *data); static inline int nla_put_string (struct nl_msg *msg, int attrtype, const char *str) { - return nla_put(msg, attrtype, strlen(str) + 1, str); + nm_assert (str); + + return nla_put (msg, attrtype, strlen (str) + 1, str); } static inline int @@ -206,55 +291,55 @@ nla_put_uint32 (struct nl_msg *msg, int attrtype, uint32_t val) } #define NLA_PUT(msg, attrtype, attrlen, data) \ - do { \ - if (nla_put(msg, attrtype, attrlen, data) < 0) \ + G_STMT_START { \ + if (nla_put (msg, attrtype, attrlen, data) < 0) \ goto nla_put_failure; \ - } while(0) + } G_STMT_END #define NLA_PUT_TYPE(msg, type, attrtype, value) \ - do { \ + G_STMT_START { \ type __nla_tmp = value; \ - NLA_PUT(msg, attrtype, sizeof(type), &__nla_tmp); \ - } while(0) + NLA_PUT (msg, attrtype, sizeof (type), &__nla_tmp); \ + } G_STMT_END #define NLA_PUT_U8(msg, attrtype, value) \ - NLA_PUT_TYPE(msg, uint8_t, attrtype, value) + NLA_PUT_TYPE (msg, uint8_t, attrtype, value) #define NLA_PUT_S8(msg, attrtype, value) \ - NLA_PUT_TYPE(msg, int8_t, attrtype, value) + NLA_PUT_TYPE (msg, int8_t, attrtype, value) #define NLA_PUT_U16(msg, attrtype, value) \ - NLA_PUT_TYPE(msg, uint16_t, attrtype, value) + NLA_PUT_TYPE (msg, uint16_t, attrtype, value) #define NLA_PUT_U32(msg, attrtype, value) \ - NLA_PUT_TYPE(msg, uint32_t, attrtype, value) + NLA_PUT_TYPE (msg, uint32_t, attrtype, value) #define NLA_PUT_S32(msg, attrtype, value) \ - NLA_PUT_TYPE(msg, int32_t, attrtype, value) + NLA_PUT_TYPE (msg, int32_t, attrtype, value) #define NLA_PUT_U64(msg, attrtype, value) \ - NLA_PUT_TYPE(msg, uint64_t, attrtype, value) + NLA_PUT_TYPE (msg, uint64_t, attrtype, value) #define NLA_PUT_STRING(msg, attrtype, value) \ - NLA_PUT(msg, attrtype, (int) strlen(value) + 1, value) + NLA_PUT (msg, attrtype, (int) strlen (value) + 1, value) #define NLA_PUT_FLAG(msg, attrtype) \ - NLA_PUT(msg, attrtype, 0, NULL) + NLA_PUT (msg, attrtype, 0, NULL) struct nlattr *nla_find (const struct nlattr *head, int len, int attrtype); static inline int nla_ok (const struct nlattr *nla, int remaining) { - return remaining >= (int) sizeof(*nla) && - nla->nla_len >= sizeof(*nla) && + return remaining >= (int) sizeof (*nla) && + nla->nla_len >= sizeof (*nla) && nla->nla_len <= remaining; } static inline struct nlattr * -nla_next(const struct nlattr *nla, int *remaining) +nla_next (const struct nlattr *nla, int *remaining) { - int totlen = NLA_ALIGN(nla->nla_len); + int totlen = NLA_ALIGN (nla->nla_len); *remaining -= totlen; return (struct nlattr *) ((char *) nla + totlen); @@ -262,28 +347,47 @@ nla_next(const struct nlattr *nla, int *remaining) #define nla_for_each_attr(pos, head, len, rem) \ for (pos = head, rem = len; \ - nla_ok(pos, rem); \ - pos = nla_next(pos, &(rem))) + nla_ok (pos, rem); \ + pos = nla_next (pos, &(rem))) #define nla_for_each_nested(pos, nla, rem) \ - for (pos = (struct nlattr *) nla_data(nla), rem = nla_len(nla); \ - nla_ok(pos, rem); \ - pos = nla_next(pos, &(rem))) + for (pos = (struct nlattr *) nla_data (nla), rem = nla_len (nla); \ + nla_ok (pos, rem); \ + pos = nla_next (pos, &(rem))) void nla_nest_cancel (struct nl_msg *msg, const struct nlattr *attr); struct nlattr *nla_nest_start (struct nl_msg *msg, int attrtype); int nla_nest_end (struct nl_msg *msg, struct nlattr *start); -int nla_parse (struct nlattr *tb[], int maxtype, struct nlattr *head, int len, +int nla_parse (struct nlattr *tb[], + int maxtype, + struct nlattr *head, + int len, const struct nla_policy *policy); +#define nla_parse_arr(tb, head, len, policy) \ + ({ \ + _nl_static_assert_tb ((tb), (policy)); \ + \ + nla_parse ((tb), G_N_ELEMENTS (tb) - 1, (head), (len), (policy)); \ + }) + static inline int -nla_parse_nested (struct nlattr *tb[], int maxtype, struct nlattr *nla, +nla_parse_nested (struct nlattr *tb[], + int maxtype, + struct nlattr *nla, const struct nla_policy *policy) { - return nla_parse (tb, maxtype, nla_data(nla), nla_len(nla), policy); + return nla_parse (tb, maxtype, nla_data (nla), nla_len (nla), policy); } +#define nla_parse_nested_arr(tb, nla, policy) \ + ({ \ + _nl_static_assert_tb ((tb), (policy)); \ + \ + nla_parse_nested ((tb), G_N_ELEMENTS (tb) - 1, (nla), (policy)); \ + }) + /*****************************************************************************/ struct nl_msg *nlmsg_alloc (void); @@ -296,7 +400,13 @@ struct nl_msg *nlmsg_alloc_simple (int nlmsgtype, int flags); void *nlmsg_reserve (struct nl_msg *n, size_t len, int pad); -int nlmsg_append (struct nl_msg *n, void *data, size_t len, int pad); +int nlmsg_append (struct nl_msg *n, + const void *data, + size_t len, + int pad); + +#define nlmsg_append_struct(n, data) \ + nlmsg_append (n, (data), sizeof (*(data)), NLMSG_ALIGNTO) void nlmsg_free (struct nl_msg *msg); @@ -316,15 +426,15 @@ nlmsg_total_size (int payload) static inline int nlmsg_ok (const struct nlmsghdr *nlh, int remaining) { - return (remaining >= (int)sizeof(struct nlmsghdr) && - nlh->nlmsg_len >= sizeof(struct nlmsghdr) && + return (remaining >= (int) sizeof (struct nlmsghdr) && + nlh->nlmsg_len >= sizeof (struct nlmsghdr) && nlh->nlmsg_len <= remaining); } static inline struct nlmsghdr * nlmsg_next (struct nlmsghdr *nlh, int *remaining) { - int totlen = NLMSG_ALIGN(nlh->nlmsg_len); + int totlen = NLMSG_ALIGN (nlh->nlmsg_len); *remaining -= totlen; @@ -344,7 +454,7 @@ _nm_auto_nl_msg_cleanup (struct nl_msg **ptr) { nlmsg_free (*ptr); } -#define nm_auto_nlmsg nm_auto(_nm_auto_nl_msg_cleanup) +#define nm_auto_nlmsg nm_auto (_nm_auto_nl_msg_cleanup) static inline void * nlmsg_data (const struct nlmsghdr *nlh) @@ -355,13 +465,13 @@ nlmsg_data (const struct nlmsghdr *nlh) static inline void * nlmsg_tail (const struct nlmsghdr *nlh) { - return (unsigned char *) nlh + NLMSG_ALIGN(nlh->nlmsg_len); + return (unsigned char *) nlh + NLMSG_ALIGN (nlh->nlmsg_len); } struct nlmsghdr *nlmsg_hdr (struct nl_msg *n); static inline int -nlmsg_valid_hdr(const struct nlmsghdr *nlh, int hdrlen) +nlmsg_valid_hdr (const struct nlmsghdr *nlh, int hdrlen) { if (nlh->nlmsg_len < nlmsg_size (hdrlen)) return 0; @@ -384,8 +494,8 @@ nlmsg_attrlen (const struct nlmsghdr *nlh, int hdrlen) static inline struct nlattr * nlmsg_attrdata (const struct nlmsghdr *nlh, int hdrlen) { - unsigned char *data = nlmsg_data(nlh); - return (struct nlattr *) (data + NLMSG_ALIGN(hdrlen)); + unsigned char *data = nlmsg_data (nlh); + return (struct nlattr *) (data + NLMSG_ALIGN (hdrlen)); } static inline struct nlattr * @@ -396,8 +506,19 @@ nlmsg_find_attr (struct nlmsghdr *nlh, int hdrlen, int attrtype) attrtype); } -int nlmsg_parse (struct nlmsghdr *nlh, int hdrlen, struct nlattr *tb[], - int maxtype, const struct nla_policy *policy); +int nlmsg_parse (struct nlmsghdr *nlh, + int hdrlen, + struct nlattr *tb[], + int maxtype, + const struct nla_policy *policy); + +#define nlmsg_parse_arr(nlh, hdrlen, tb, policy) \ + ({ \ + _nl_static_assert_tb ((tb), (policy)); \ + G_STATIC_ASSERT_EXPR ((hdrlen) >= 0); \ + \ + nlmsg_parse ((nlh), (hdrlen), (tb), G_N_ELEMENTS (tb) - 1, (policy)); \ + }) struct nlmsghdr *nlmsg_put (struct nl_msg *n, uint32_t pid, uint32_t seq, int type, int payload, int flags); @@ -499,8 +620,20 @@ struct nlattr *genlmsg_attrdata (const struct genlmsghdr *gnlh, int hdrlen); int genlmsg_len (const struct genlmsghdr *gnlh); int genlmsg_attrlen (const struct genlmsghdr *gnlh, int hdrlen); int genlmsg_valid_hdr (struct nlmsghdr *nlh, int hdrlen); -int genlmsg_parse (struct nlmsghdr *nlh, int hdrlen, struct nlattr *tb[], - int maxtype, const struct nla_policy *policy); + +int genlmsg_parse (struct nlmsghdr *nlh, + int hdrlen, + struct nlattr *tb[], + int maxtype, + const struct nla_policy *policy); + +#define genlmsg_parse_arr(nlh, hdrlen, tb, policy) \ + ({ \ + _nl_static_assert_tb ((tb), (policy)); \ + G_STATIC_ASSERT_EXPR ((hdrlen) >= 0); \ + \ + genlmsg_parse ((nlh), (hdrlen), (tb), G_N_ELEMENTS (tb) - 1, (policy)); \ + }) int genl_ctrl_resolve (struct nl_sock *sk, const char *name); diff --git a/src/platform/nm-platform-utils.c b/src/platform/nm-platform-utils.c index 772d4667..93cd0b3c 100644 --- a/src/platform/nm-platform-utils.c +++ b/src/platform/nm-platform-utils.c @@ -22,9 +22,7 @@ #include "nm-platform-utils.h" -#include <string.h> #include <unistd.h> -#include <errno.h> #include <sys/ioctl.h> #include <linux/ethtool.h> #include <linux/sockios.h> @@ -86,7 +84,7 @@ socket_handle_init (SocketHandle *shandle, int ifindex) shandle->fd = socket (PF_INET, SOCK_DGRAM | SOCK_CLOEXEC, 0); if (shandle->fd < 0) { shandle->ifindex = 0; - return -errno; + return -NM_ERRNO_NATIVE (errno); } shandle->ifindex = ifindex; @@ -159,8 +157,8 @@ ethtool_call_handle (SocketHandle *shandle, gpointer edata) shandle->ifindex, _ethtool_data_to_string (edata, sbuf, sizeof (sbuf)), shandle->ifname, - strerror (errsv)); - return -errsv; + nm_strerror_native (errsv)); + return -NM_ERRNO_NATIVE (errsv); } nm_log_trace (LOGD_PLATFORM, "ethtool[%d]: %s, %s: success", @@ -183,7 +181,7 @@ ethtool_call_ifindex (int ifindex, gpointer edata) nm_log_trace (LOGD_PLATFORM, "ethtool[%d]: %s: failed creating ethtool socket: %s", ifindex, _ethtool_data_to_string (edata, sbuf, sizeof (sbuf)), - g_strerror (-r)); + nm_strerror_native (-r)); return r; } @@ -489,7 +487,7 @@ nmp_utils_ethtool_get_features (int ifindex) nm_log_trace (LOGD_PLATFORM, "ethtool[%d]: %s: failed creating ethtool socket: %s", ifindex, "get-features", - g_strerror (-r)); + nm_strerror_native (-r)); return FALSE; } @@ -620,7 +618,7 @@ nmp_utils_ethtool_set_features (int ifindex, nm_log_trace (LOGD_PLATFORM, "ethtool[%d]: %s: failed creating ethtool socket: %s", ifindex, "set-features", - g_strerror (-r)); + nm_strerror_native (-r)); return FALSE; } @@ -656,7 +654,7 @@ nmp_utils_ethtool_set_features (int ifindex, nm_log_trace (LOGD_PLATFORM, "ethtool[%d]: %s: failure setting features (%s)", ifindex, "set-features", - g_strerror (-r)); + nm_strerror_native (-r)); return FALSE; } @@ -766,7 +764,7 @@ nmp_utils_ethtool_supports_vlans (int ifindex) nm_log_trace (LOGD_PLATFORM, "ethtool[%d]: %s: failed creating ethtool socket: %s", ifindex, "support-vlans", - g_strerror (-r)); + nm_strerror_native (-r)); return FALSE; } @@ -805,7 +803,7 @@ nmp_utils_ethtool_get_peer_ifindex (int ifindex) nm_log_trace (LOGD_PLATFORM, "ethtool[%d]: %s: failed creating ethtool socket: %s", ifindex, "get-peer-ifindex", - g_strerror (-r)); + nm_strerror_native (-r)); return FALSE; } @@ -894,7 +892,7 @@ nmp_utils_ethtool_get_link_settings (int ifindex, | ADVERTISED_1000baseT_Full \ | ADVERTISED_10000baseT_Full ) -static inline guint32 +static guint32 get_baset_mode (guint32 speed, NMPlatformLinkDuplexType duplex) { if (duplex == NM_PLATFORM_LINK_DUPLEX_UNKNOWN) @@ -1045,13 +1043,14 @@ nmp_utils_mii_supports_carrier_detect (int ifindex) int r; struct ifreq ifr; struct mii_ioctl_data *mii; + int errsv; g_return_val_if_fail (ifindex > 0, FALSE); if ((r = socket_handle_init (&shandle, ifindex)) < 0) { nm_log_trace (LOGD_PLATFORM, "mii[%d]: carrier-detect no: failed creating ethtool socket: %s", ifindex, - g_strerror (-r)); + nm_strerror_native (-r)); return FALSE; } @@ -1059,7 +1058,8 @@ nmp_utils_mii_supports_carrier_detect (int ifindex) memcpy (ifr.ifr_name, shandle.ifname, IFNAMSIZ); if (ioctl (shandle.fd, SIOCGMIIPHY, &ifr) < 0) { - nm_log_trace (LOGD_PLATFORM, "mii[%d,%s]: carrier-detect no: SIOCGMIIPHY failed: %s", ifindex, shandle.ifname, strerror (errno)); + errsv = errno; + nm_log_trace (LOGD_PLATFORM, "mii[%d,%s]: carrier-detect no: SIOCGMIIPHY failed: %s", ifindex, shandle.ifname, nm_strerror_native (errsv)); return FALSE; } @@ -1068,7 +1068,8 @@ nmp_utils_mii_supports_carrier_detect (int ifindex) mii->reg_num = MII_BMSR; if (ioctl (shandle.fd, SIOCGMIIREG, &ifr) != 0) { - nm_log_trace (LOGD_PLATFORM, "mii[%d,%s]: carrier-detect no: SIOCGMIIREG failed: %s", ifindex, shandle.ifname, strerror (errno)); + errsv = errno; + nm_log_trace (LOGD_PLATFORM, "mii[%d,%s]: carrier-detect no: SIOCGMIIREG failed: %s", ifindex, shandle.ifname, nm_strerror_native (errsv)); return FALSE; } diff --git a/src/platform/nm-platform.c b/src/platform/nm-platform.c index 4bb31b17..fe0cb662 100644 --- a/src/platform/nm-platform.c +++ b/src/platform/nm-platform.c @@ -23,13 +23,11 @@ #include "nm-platform.h" #include <stdlib.h> -#include <errno.h> #include <unistd.h> #include <netinet/in.h> #include <arpa/inet.h> #include <sys/socket.h> #include <netdb.h> -#include <string.h> #include <linux/ip.h> #include <linux/if.h> #include <linux/if_tun.h> @@ -41,7 +39,7 @@ #include "nm-core-internal.h" #include "nm-utils/nm-dedup-multi.h" #include "nm-utils/nm-udev-utils.h" -#include "nm-utils/nm-errno.h" +#include "nm-utils/nm-secret-utils.h" #include "nm-core-utils.h" #include "nm-platform-utils.h" @@ -1985,6 +1983,24 @@ nm_platform_link_get_lnk_wireguard (NMPlatform *self, int ifindex, const NMPlatf /*****************************************************************************/ +NM_UTILS_FLAGS2STR_DEFINE_STATIC (_wireguard_change_flags_to_string, NMPlatformWireGuardChangeFlags, + NM_UTILS_FLAGS2STR (NM_PLATFORM_WIREGUARD_CHANGE_FLAG_NONE, "none"), + NM_UTILS_FLAGS2STR (NM_PLATFORM_WIREGUARD_CHANGE_FLAG_REPLACE_PEERS, "replace-peers"), + NM_UTILS_FLAGS2STR (NM_PLATFORM_WIREGUARD_CHANGE_FLAG_HAS_PRIVATE_KEY, "has-private-key"), + NM_UTILS_FLAGS2STR (NM_PLATFORM_WIREGUARD_CHANGE_FLAG_HAS_LISTEN_PORT, "has-listen-port"), + NM_UTILS_FLAGS2STR (NM_PLATFORM_WIREGUARD_CHANGE_FLAG_HAS_FWMARK, "has-fwmark"), +); + +NM_UTILS_FLAGS2STR_DEFINE_STATIC (_wireguard_change_peer_flags_to_string, NMPlatformWireGuardChangePeerFlags, + NM_UTILS_FLAGS2STR (NM_PLATFORM_WIREGUARD_CHANGE_PEER_FLAG_NONE, "none"), + NM_UTILS_FLAGS2STR (NM_PLATFORM_WIREGUARD_CHANGE_PEER_FLAG_REMOVE_ME, "remove"), + NM_UTILS_FLAGS2STR (NM_PLATFORM_WIREGUARD_CHANGE_PEER_FLAG_HAS_PRESHARED_KEY, "psk"), + NM_UTILS_FLAGS2STR (NM_PLATFORM_WIREGUARD_CHANGE_PEER_FLAG_HAS_KEEPALIVE_INTERVAL, "ka"), + NM_UTILS_FLAGS2STR (NM_PLATFORM_WIREGUARD_CHANGE_PEER_FLAG_HAS_ENDPOINT, "ep"), + NM_UTILS_FLAGS2STR (NM_PLATFORM_WIREGUARD_CHANGE_PEER_FLAG_HAS_ALLOWEDIPS, "aips"), + NM_UTILS_FLAGS2STR (NM_PLATFORM_WIREGUARD_CHANGE_PEER_FLAG_REPLACE_ALLOWEDIPS, "remove-aips"), +); + int nm_platform_link_wireguard_add (NMPlatform *self, const char *name, @@ -1998,8 +2014,9 @@ nm_platform_link_wireguard_change (NMPlatform *self, int ifindex, const NMPlatformLnkWireGuard *lnk_wireguard, const NMPWireGuardPeer *peers, + const NMPlatformWireGuardChangePeerFlags *peer_flags, guint peers_len, - gboolean replace_peers) + NMPlatformWireGuardChangeFlags change_flags) { _CHECK_SELF (self, klass, -NME_BUG); @@ -2008,6 +2025,7 @@ nm_platform_link_wireguard_change (NMPlatform *self, if (_LOGD_ENABLED ()) { char buf_lnk[256]; char buf_peers[512]; + char buf_change_flags[100]; buf_peers[0] = '\0'; if (peers_len > 0) { @@ -2020,25 +2038,31 @@ nm_platform_link_wireguard_change (NMPlatform *self, nm_utils_strbuf_append_str (&b, &len, " { "); nm_platform_wireguard_peer_to_string (&peers[i], b, len); nm_utils_strbuf_seek_end (&b, &len); + if (peer_flags) { + nm_utils_strbuf_append (&b, &len, + " (%s)", + _wireguard_change_peer_flags_to_string (peer_flags[i], buf_change_flags, sizeof (buf_change_flags))); + } nm_utils_strbuf_append_str (&b, &len, " } "); } nm_utils_strbuf_append_str (&b, &len, "}"); } - _LOG3D ("link: change wireguard ifindex %d, %s, %u peers%s%s", + _LOG3D ("link: change wireguard ifindex %d, %s, (%s), %u peers%s", ifindex, nm_platform_lnk_wireguard_to_string (lnk_wireguard, buf_lnk, sizeof (buf_lnk)), + _wireguard_change_flags_to_string (change_flags, buf_change_flags, sizeof (buf_change_flags)), peers_len, - buf_peers, - replace_peers ? " (replace-peers)" : " (update-peers)"); + buf_peers); } return klass->link_wireguard_change (self, ifindex, lnk_wireguard, peers, + peer_flags, peers_len, - replace_peers); + change_flags); } /*****************************************************************************/ @@ -2893,7 +2917,7 @@ nm_platform_link_veth_get_properties (NMPlatform *self, int ifindex, int *out_pe * nm_platform_link_tun_get_properties: * @self: the #NMPlatform instance * @ifindex: the ifindex to look up - * @out_properties: (out): (allow-none): return the read properties + * @out_properties: (out) (allow-none): return the read properties * * Only recent versions of kernel export tun properties via netlink. * So, if that's the case, then we have the NMPlatformLnkTun instance @@ -4218,7 +4242,7 @@ nm_platform_ip_route_get_prune_list (NMPlatform *self, * at the end of the operation. Note that if @routes contains * the same route, then it will not be deleted. @routes overrules * @routes_prune list. - * @out_temporary_not_available: (allow-none): (out): routes that could + * @out_temporary_not_available: (allow-none) (out): routes that could * currently not be synced. The caller shall keep them and try later again. * * Returns: %TRUE on success. @@ -5610,6 +5634,7 @@ nm_platform_wireguard_peer_to_string (const NMPWireGuardPeer *peer, char *buf, g char s_sockaddr[NM_UTILS_INET_ADDRSTRLEN + 100]; char s_endpoint[20 + sizeof (s_sockaddr)]; char s_addr[NM_UTILS_INET_ADDRSTRLEN]; + char s_keepalive[100]; guint i; nm_utils_to_string_buffer_init (&buf, &len); @@ -5627,18 +5652,22 @@ nm_platform_wireguard_peer_to_string (const NMPWireGuardPeer *peer, char *buf, g nm_utils_strbuf_append (&buf, &len, "public-key %s" - "%s" /* preshared-key */ - "%s" /* endpoint */ + "%s" /* preshared-key */ + "%s" /* endpoint */ " rx %"G_GUINT64_FORMAT " tx %"G_GUINT64_FORMAT + "%s" /* persistent-keepalive */ "%s", /* allowed-ips */ public_key_b64, - nm_utils_memeqzero (peer->preshared_key, sizeof (peer->preshared_key)) + nm_utils_memeqzero_secret (peer->preshared_key, sizeof (peer->preshared_key)) ? "" : " preshared-key (hidden)", s_endpoint, peer->rx_bytes, peer->tx_bytes, + peer->persistent_keepalive_interval > 0 + ? nm_sprintf_buf (s_keepalive, " keepalive %u", (guint) peer->persistent_keepalive_interval) + : "", peer->allowed_ips_len > 0 ? " allowed-ips" : ""); @@ -5676,7 +5705,7 @@ nm_platform_lnk_wireguard_to_string (const NMPlatformLnkWireGuard *lnk, char *bu ? " public-key " : "", public_b64 ?: "", - nm_utils_memeqzero (lnk->private_key, sizeof (lnk->private_key)) + nm_utils_memeqzero_secret (lnk->private_key, sizeof (lnk->private_key)) ? "" : " private-key (hidden)", lnk->listen_port, diff --git a/src/platform/nm-platform.h b/src/platform/nm-platform.h index 412ac597..37aa58fd 100644 --- a/src/platform/nm-platform.h +++ b/src/platform/nm-platform.h @@ -29,7 +29,6 @@ #include "nm-setting-wired.h" #include "nm-setting-wireless.h" #include "nm-setting-ip-tunnel.h" -#include "nm-utils/nm-errno.h" #define NM_TYPE_PLATFORM (nm_platform_get_type ()) #define NM_PLATFORM(obj) (G_TYPE_CHECK_INSTANCE_CAST ((obj), NM_TYPE_PLATFORM, NMPlatform)) @@ -749,11 +748,35 @@ typedef enum { } NMPlatformLinkDuplexType; typedef enum { - NM_PLATFORM_KERNEL_SUPPORT_EXTENDED_IFA_FLAGS = (1LL << 0), - NM_PLATFORM_KERNEL_SUPPORT_USER_IPV6LL = (1LL << 1), - NM_PLATFORM_KERNEL_SUPPORT_RTA_PREF = (1LL << 2), + NM_PLATFORM_KERNEL_SUPPORT_EXTENDED_IFA_FLAGS = (1LL << 0), + NM_PLATFORM_KERNEL_SUPPORT_USER_IPV6LL = (1LL << 1), + NM_PLATFORM_KERNEL_SUPPORT_RTA_PREF = (1LL << 2), } NMPlatformKernelSupportFlags; +typedef enum { + NM_PLATFORM_WIREGUARD_CHANGE_FLAG_NONE = 0, + NM_PLATFORM_WIREGUARD_CHANGE_FLAG_REPLACE_PEERS = (1LL << 0), + NM_PLATFORM_WIREGUARD_CHANGE_FLAG_HAS_PRIVATE_KEY = (1LL << 1), + NM_PLATFORM_WIREGUARD_CHANGE_FLAG_HAS_LISTEN_PORT = (1LL << 2), + NM_PLATFORM_WIREGUARD_CHANGE_FLAG_HAS_FWMARK = (1LL << 3), +} NMPlatformWireGuardChangeFlags; + +typedef enum { + NM_PLATFORM_WIREGUARD_CHANGE_PEER_FLAG_NONE = 0, + NM_PLATFORM_WIREGUARD_CHANGE_PEER_FLAG_REMOVE_ME = (1LL << 0), + NM_PLATFORM_WIREGUARD_CHANGE_PEER_FLAG_HAS_PRESHARED_KEY = (1LL << 1), + NM_PLATFORM_WIREGUARD_CHANGE_PEER_FLAG_HAS_KEEPALIVE_INTERVAL = (1LL << 2), + NM_PLATFORM_WIREGUARD_CHANGE_PEER_FLAG_HAS_ENDPOINT = (1LL << 3), + NM_PLATFORM_WIREGUARD_CHANGE_PEER_FLAG_HAS_ALLOWEDIPS = (1LL << 4), + NM_PLATFORM_WIREGUARD_CHANGE_PEER_FLAG_REPLACE_ALLOWEDIPS = (1LL << 5), + + NM_PLATFORM_WIREGUARD_CHANGE_PEER_FLAG_DEFAULT = NM_PLATFORM_WIREGUARD_CHANGE_PEER_FLAG_HAS_PRESHARED_KEY + | NM_PLATFORM_WIREGUARD_CHANGE_PEER_FLAG_HAS_KEEPALIVE_INTERVAL + | NM_PLATFORM_WIREGUARD_CHANGE_PEER_FLAG_HAS_ENDPOINT + | NM_PLATFORM_WIREGUARD_CHANGE_PEER_FLAG_HAS_ALLOWEDIPS, + +} NMPlatformWireGuardChangePeerFlags; + /*****************************************************************************/ struct _NMPlatformPrivate; @@ -831,8 +854,9 @@ typedef struct { int ifindex, const NMPlatformLnkWireGuard *lnk_wireguard, const struct _NMPWireGuardPeer *peers, + const NMPlatformWireGuardChangePeerFlags *peer_flags, guint peers_len, - gboolean replace_peers); + NMPlatformWireGuardChangeFlags change_flags); gboolean (*vlan_add) (NMPlatform *, const char *name, int parent, int vlanid, guint32 vlanflags, const NMPlatformLink **out_link); gboolean (*link_vlan_change) (NMPlatform *self, @@ -1394,8 +1418,9 @@ int nm_platform_link_wireguard_change (NMPlatform *self, int ifindex, const NMPlatformLnkWireGuard *lnk_wireguard, const struct _NMPWireGuardPeer *peers, + const NMPlatformWireGuardChangePeerFlags *peer_flags, guint peers_len, - gboolean replace_peers); + NMPlatformWireGuardChangeFlags change_flags); const NMPlatformIP6Address *nm_platform_ip6_address_get (NMPlatform *self, int ifindex, struct in6_addr address); diff --git a/src/platform/nmp-netns.c b/src/platform/nmp-netns.c index f1092fe9..f34dc83d 100644 --- a/src/platform/nmp-netns.c +++ b/src/platform/nmp-netns.c @@ -19,15 +19,26 @@ */ #include "nm-default.h" + #include "nmp-netns.h" #include <fcntl.h> -#include <errno.h> #include <sys/mount.h> #include <sys/stat.h> #include <sys/types.h> +#include <pthread.h> + +/*****************************************************************************/ -#include "NetworkManagerUtils.h" +/* NOTE: NMPNetns and all code used here must be thread-safe! */ + +/* we may not call logging functions from the main-thread alone. Hence, we + * require locking from nm-logging. Indicate that by setting NM_THREAD_SAFE_ON_MAIN_THREAD + * to zero. */ +#undef NM_THREAD_SAFE_ON_MAIN_THREAD +#define NM_THREAD_SAFE_ON_MAIN_THREAD 0 + +/*****************************************************************************/ #define PROC_SELF_NS_MNT "/proc/self/ns/mnt" #define PROC_SELF_NS_NET "/proc/self/ns/net" @@ -116,49 +127,81 @@ typedef struct { int ns_types; } NetnsInfo; -static void _stack_push (NMPNetns *netns, int ns_types); +static void _stack_push (GArray *netns_stack, + NMPNetns *netns, + int ns_types); static NMPNetns *_netns_new (GError **error); /*****************************************************************************/ -static GArray *netns_stack = NULL; +static NMPNetns * +_netns_get (NetnsInfo *info) +{ + nm_assert (!info || NMP_IS_NETNS (info->netns)); + return info ? info->netns : NULL; +} + +/*****************************************************************************/ + +static _nm_thread_local GArray *_netns_stack = NULL; static void -_stack_ensure_init_impl (void) +_netns_stack_clear_cb (gpointer data) { - NMPNetns *netns; - GError *error = NULL; + NetnsInfo *info = data; - nm_assert (!netns_stack); + nm_assert (NMP_IS_NETNS (info->netns)); + g_object_unref (info->netns); +} - netns_stack = g_array_new (FALSE, FALSE, sizeof (NetnsInfo)); +static GArray * +_netns_stack_get_impl (void) +{ + gs_unref_object NMPNetns *netns = NULL; + gs_free_error GError *error = NULL; + pthread_key_t key; + GArray *s; + + s = g_array_new (FALSE, FALSE, sizeof (NetnsInfo)); + g_array_set_clear_func (s, _netns_stack_clear_cb); + _netns_stack = s; /* at the bottom of the stack we must try to create a netns instance * that we never pop. It's the base to which we need to return. */ - netns = _netns_new (&error); - if (!netns) { - /* don't know how to recover from this error. Netns are not supported. */ _LOGE (NULL, "failed to create initial netns: %s", error->message); - g_clear_error (&error); - return; + return s; } - _stack_push (netns, _CLONE_NS_ALL); + /* we leak this instance inside the stack. */ + _stack_push (s, netns, _CLONE_NS_ALL); - /* we leak this instance inside netns_stack. It cannot be popped. */ - g_object_unref (netns); + /* finally, register a destructor function to cleanup the array. If we fail + * to do so, we will leak NMPNetns instances (and their file descriptor) when the + * thread exits. */ + if (pthread_key_create (&key, (void (*) (void *)) g_array_unref) != 0) + _LOGE (NULL, "failure to initialize thread-local storage"); + else if (pthread_setspecific (key, s) != 0) + _LOGE (NULL, "failure to set thread-local storage"); + + return s; } -#define _stack_ensure_init() \ - G_STMT_START { \ - if (G_UNLIKELY (!netns_stack)) { \ - _stack_ensure_init_impl (); \ - } \ - } G_STMT_END + +#define _netns_stack_get() \ + ({ \ + GArray *_s = _netns_stack; \ + \ + if (G_UNLIKELY (!_s)) \ + _s = _netns_stack_get_impl (); \ + _s; \ + }) + +/*****************************************************************************/ static NMPNetns * -_stack_current_netns (int ns_types) +_stack_current_netns (GArray *netns_stack, + int ns_types) { guint j; @@ -179,7 +222,9 @@ _stack_current_netns (int ns_types) } static int -_stack_current_ns_types (NMPNetns *netns, int ns_types) +_stack_current_ns_types (GArray *netns_stack, + NMPNetns *netns, + int ns_types) { const int ns_types_check[] = { _CLONE_NS_ALL_V }; guint i, j; @@ -212,27 +257,25 @@ _stack_current_ns_types (NMPNetns *netns, int ns_types) } static NetnsInfo * -_stack_peek (void) +_stack_peek (GArray *netns_stack) { - nm_assert (netns_stack); - if (netns_stack->len > 0) return &g_array_index (netns_stack, NetnsInfo, (netns_stack->len - 1)); return NULL; } static NetnsInfo * -_stack_bottom (void) +_stack_bottom (GArray *netns_stack) { - nm_assert (netns_stack); - if (netns_stack->len > 0) return &g_array_index (netns_stack, NetnsInfo, 0); return NULL; } static void -_stack_push (NMPNetns *netns, int ns_types) +_stack_push (GArray *netns_stack, + NMPNetns *netns, + int ns_types) { NetnsInfo *info; @@ -244,13 +287,15 @@ _stack_push (NMPNetns *netns, int ns_types) g_array_set_size (netns_stack, netns_stack->len + 1); info = &g_array_index (netns_stack, NetnsInfo, (netns_stack->len - 1)); - info->netns = g_object_ref (netns); - info->ns_types = ns_types; - info->count = 1; + *info = (NetnsInfo) { + .netns = g_object_ref (netns), + .ns_types = ns_types, + .count = 1, + }; } static void -_stack_pop (void) +_stack_pop (GArray *netns_stack) { NetnsInfo *info; @@ -262,13 +307,11 @@ _stack_pop (void) nm_assert (NMP_IS_NETNS (info->netns)); nm_assert (info->count == 1); - g_object_unref (info->netns); - g_array_set_size (netns_stack, netns_stack->len - 1); } static guint -_stack_size (void) +_stack_size (GArray *netns_stack) { nm_assert (netns_stack); @@ -289,7 +332,7 @@ _netns_new (GError **error) errsv = errno; g_set_error (error, NM_UTILS_ERROR, NM_UTILS_ERROR_UNKNOWN, "Failed opening netns: %s", - g_strerror (errsv)); + nm_strerror_native (errsv)); errno = errsv; return NULL; } @@ -299,7 +342,7 @@ _netns_new (GError **error) errsv = errno; g_set_error (error, NM_UTILS_ERROR, NM_UTILS_ERROR_UNKNOWN, "Failed opening mntns: %s", - g_strerror (errsv)); + nm_strerror_native (errsv)); nm_close (fd_net); errno = errsv; return NULL; @@ -332,31 +375,33 @@ _setns (NMPNetns *self, int type) } static gboolean -_netns_switch_push (NMPNetns *self, int ns_types) +_netns_switch_push (GArray *netns_stack, + NMPNetns *self, + int ns_types) { int errsv; if ( NM_FLAGS_HAS (ns_types, CLONE_NEWNET) - && !_stack_current_ns_types (self, CLONE_NEWNET) + && !_stack_current_ns_types (netns_stack, self, CLONE_NEWNET) && _setns (self, CLONE_NEWNET) != 0) { errsv = errno; - _LOGE (self, "failed to switch netns: %s", g_strerror (errsv)); + _LOGE (self, "failed to switch netns: %s", nm_strerror_native (errsv)); return FALSE; } if ( NM_FLAGS_HAS (ns_types, CLONE_NEWNS) - && !_stack_current_ns_types (self, CLONE_NEWNS) + && !_stack_current_ns_types (netns_stack, self, CLONE_NEWNS) && _setns (self, CLONE_NEWNS) != 0) { errsv = errno; - _LOGE (self, "failed to switch mntns: %s", g_strerror (errsv)); + _LOGE (self, "failed to switch mntns: %s", nm_strerror_native (errsv)); /* try to fix the mess by returning to the previous netns. */ if ( NM_FLAGS_HAS (ns_types, CLONE_NEWNET) - && !_stack_current_ns_types (self, CLONE_NEWNET)) { - self = _stack_current_netns (CLONE_NEWNET); + && !_stack_current_ns_types (netns_stack, self, CLONE_NEWNET)) { + self = _stack_current_netns (netns_stack, CLONE_NEWNET); if ( self && _setns (self, CLONE_NEWNET) != 0) { errsv = errno; - _LOGE (self, "failed to restore netns: %s", g_strerror (errsv)); + _LOGE (self, "failed to restore netns: %s", nm_strerror_native (errsv)); } } return FALSE; @@ -366,33 +411,36 @@ _netns_switch_push (NMPNetns *self, int ns_types) } static gboolean -_netns_switch_pop (NMPNetns *self, int ns_types) +_netns_switch_pop (GArray *netns_stack, + NMPNetns *self, + int ns_types) { int errsv; NMPNetns *current; int success = TRUE; if ( NM_FLAGS_HAS (ns_types, CLONE_NEWNET) - && (!self || !_stack_current_ns_types (self, CLONE_NEWNET))) { - current = _stack_current_netns (CLONE_NEWNET); + && ( !self + || !_stack_current_ns_types (netns_stack, self, CLONE_NEWNET))) { + current = _stack_current_netns (netns_stack, CLONE_NEWNET); if (!current) { g_warn_if_reached (); success = FALSE; } else if (_setns (current, CLONE_NEWNET) != 0) { errsv = errno; - _LOGE (self, "failed to switch netns: %s", g_strerror (errsv)); + _LOGE (self, "failed to switch netns: %s", nm_strerror_native (errsv)); success = FALSE; } } if ( NM_FLAGS_HAS (ns_types, CLONE_NEWNS) - && (!self || !_stack_current_ns_types (self, CLONE_NEWNS))) { - current = _stack_current_netns (CLONE_NEWNS); + && (!self || !_stack_current_ns_types (netns_stack, self, CLONE_NEWNS))) { + current = _stack_current_netns (netns_stack, CLONE_NEWNS); if (!current) { g_warn_if_reached (); success = FALSE; } else if (_setns (current, CLONE_NEWNS) != 0) { errsv = errno; - _LOGE (self, "failed to switch mntns: %s", g_strerror (errsv)); + _LOGE (self, "failed to switch mntns: %s", nm_strerror_native (errsv)); success = FALSE; } } @@ -423,32 +471,31 @@ nmp_netns_get_fd_mnt (NMPNetns *self) static gboolean _nmp_netns_push_type (NMPNetns *self, int ns_types) { + GArray *netns_stack = _netns_stack_get (); NetnsInfo *info; char sbuf[100]; - _stack_ensure_init (); - - info = _stack_peek (); + info = _stack_peek (netns_stack); g_return_val_if_fail (info, FALSE); if (info->netns == self && info->ns_types == ns_types) { info->count++; _LOGt (self, "push#%u* %s (increase count to %d)", - _stack_size () - 1, + _stack_size (netns_stack) - 1, _ns_types_to_str (ns_types, ns_types, sbuf), info->count); return TRUE; } _LOGD (self, "push#%u %s", - _stack_size (), + _stack_size (netns_stack), _ns_types_to_str (ns_types, - _stack_current_ns_types (self, ns_types), + _stack_current_ns_types (netns_stack, self, ns_types), sbuf)); - if (!_netns_switch_push (self, ns_types)) + if (!_netns_switch_push (netns_stack, self, ns_types)) return FALSE; - _stack_push (self, ns_types); + _stack_push (netns_stack, self, ns_types); return TRUE; } @@ -472,14 +519,13 @@ nmp_netns_push_type (NMPNetns *self, int ns_types) NMPNetns * nmp_netns_new (void) { + GArray *netns_stack = _netns_stack_get (); NMPNetns *self; int errsv; GError *error = NULL; unsigned long mountflags = 0; - _stack_ensure_init (); - - if (!_stack_peek ()) { + if (!_stack_peek (netns_stack)) { /* there are no netns instances. We cannot create a new one * (because after unshare we couldn't return to the original one). */ errno = ENOTSUP; @@ -488,19 +534,19 @@ nmp_netns_new (void) if (unshare (_CLONE_NS_ALL) != 0) { errsv = errno; - _LOGE (NULL, "failed to create new net and mnt namespace: %s", g_strerror (errsv)); + _LOGE (NULL, "failed to create new net and mnt namespace: %s", nm_strerror_native (errsv)); return NULL; } if (mount ("", "/", "none", MS_SLAVE | MS_REC, NULL) != 0) { errsv = errno; - _LOGE (NULL, "failed mount --make-rslave: %s", g_strerror (errsv)); + _LOGE (NULL, "failed mount --make-rslave: %s", nm_strerror_native (errsv)); goto err_out; } if (umount2 ("/sys", MNT_DETACH) != 0) { errsv = errno; - _LOGE (NULL, "failed umount /sys: %s", g_strerror (errsv)); + _LOGE (NULL, "failed umount /sys: %s", nm_strerror_native (errsv)); goto err_out; } @@ -509,7 +555,7 @@ nmp_netns_new (void) if (mount ("sysfs", "/sys", "sysfs", mountflags, NULL) != 0) { errsv = errno; - _LOGE (NULL, "failed mount /sys: %s", g_strerror (errsv)); + _LOGE (NULL, "failed mount /sys: %s", nm_strerror_native (errsv)); goto err_out; } @@ -521,11 +567,11 @@ nmp_netns_new (void) goto err_out; } - _stack_push (self, _CLONE_NS_ALL); + _stack_push (netns_stack, self, _CLONE_NS_ALL); return self; err_out: - _netns_switch_pop (NULL, _CLONE_NS_ALL); + _netns_switch_pop (netns_stack, NULL, _CLONE_NS_ALL); errno = errsv; return NULL; } @@ -533,14 +579,13 @@ err_out: gboolean nmp_netns_pop (NMPNetns *self) { + GArray *netns_stack = _netns_stack_get (); NetnsInfo *info; int ns_types; g_return_val_if_fail (NMP_IS_NETNS (self), FALSE); - _stack_ensure_init (); - - info = _stack_peek (); + info = _stack_peek (netns_stack); g_return_val_if_fail (info, FALSE); g_return_val_if_fail (info->netns == self, FALSE); @@ -548,52 +593,42 @@ nmp_netns_pop (NMPNetns *self) if (info->count > 1) { info->count--; _LOGt (self, "pop#%u* (decrease count to %d)", - _stack_size () - 1, info->count); + _stack_size (netns_stack) - 1, info->count); return TRUE; } g_return_val_if_fail (info->count == 1, FALSE); /* cannot pop the original netns. */ - g_return_val_if_fail (_stack_size () > 1, FALSE); + g_return_val_if_fail (_stack_size (netns_stack) > 1, FALSE); - _LOGD (self, "pop#%u", _stack_size () - 1); + _LOGD (self, "pop#%u", _stack_size (netns_stack) - 1); ns_types = info->ns_types; - _stack_pop (); + _stack_pop (netns_stack); - return _netns_switch_pop (self, ns_types); + return _netns_switch_pop (netns_stack, self, ns_types); } NMPNetns * nmp_netns_get_current (void) { - NetnsInfo *info; - - _stack_ensure_init (); - - info = _stack_peek (); - return info ? info->netns : NULL; + return _netns_get (_stack_peek (_netns_stack_get ())); } NMPNetns * nmp_netns_get_initial (void) { - NetnsInfo *info; - - _stack_ensure_init (); - - info = _stack_bottom (); - return info ? info->netns : NULL; + return _netns_get (_stack_bottom (_netns_stack_get ())); } gboolean nmp_netns_is_initial (void) { - if (G_UNLIKELY (!netns_stack)) - return TRUE; + GArray *netns_stack = _netns_stack_get (); - return nmp_netns_get_current () == nmp_netns_get_initial (); + return ( _netns_get (_stack_peek (netns_stack)) + == _netns_get (_stack_bottom (netns_stack))); } /*****************************************************************************/ @@ -618,7 +653,7 @@ nmp_netns_bind_to_path (NMPNetns *self, const char *filename, int *out_fd) errsv = errno; if (errsv != EEXIST) { _LOGE (self, "bind: failed to create directory %s: %s", - dirname, g_strerror (errsv)); + dirname, nm_strerror_native (errsv)); return FALSE; } } @@ -626,7 +661,7 @@ nmp_netns_bind_to_path (NMPNetns *self, const char *filename, int *out_fd) if ((fd = creat (filename, S_IRUSR | S_IRGRP | S_IROTH)) == -1) { errsv = errno; _LOGE (self, "bind: failed to create %s: %s", - filename, g_strerror (errsv)); + filename, nm_strerror_native (errsv)); return FALSE; } nm_close (fd); @@ -634,7 +669,7 @@ nmp_netns_bind_to_path (NMPNetns *self, const char *filename, int *out_fd) if (mount (PROC_SELF_NS_NET, filename, "none", MS_BIND, NULL) != 0) { errsv = errno; _LOGE (self, "bind: failed to mount %s to %s: %s", - PROC_SELF_NS_NET, filename, g_strerror (errsv)); + PROC_SELF_NS_NET, filename, nm_strerror_native (errsv)); unlink (filename); return FALSE; } @@ -642,7 +677,7 @@ nmp_netns_bind_to_path (NMPNetns *self, const char *filename, int *out_fd) if (out_fd) { if ((fd = open (filename, O_RDONLY | O_CLOEXEC)) == -1) { errsv = errno; - _LOGE (self, "bind: failed to open %s: %s", filename, g_strerror (errsv)); + _LOGE (self, "bind: failed to open %s: %s", filename, nm_strerror_native (errsv)); umount2 (filename, MNT_DETACH); unlink (filename); return FALSE; @@ -663,12 +698,12 @@ nmp_netns_bind_to_path_destroy (NMPNetns *self, const char *filename) if (umount2 (filename, MNT_DETACH) != 0) { errsv = errno; - _LOGE (self, "bind: failed to unmount2 %s: %s", filename, g_strerror (errsv)); + _LOGE (self, "bind: failed to unmount2 %s: %s", filename, nm_strerror_native (errsv)); return FALSE; } if (unlink (filename) != 0) { errsv = errno; - _LOGE (self, "bind: failed to unlink %s: %s", filename, g_strerror (errsv)); + _LOGE (self, "bind: failed to unlink %s: %s", filename, nm_strerror_native (errsv)); return FALSE; } return TRUE; diff --git a/src/platform/nmp-object.c b/src/platform/nmp-object.c index 80e65b49..6ec6fea1 100644 --- a/src/platform/nmp-object.c +++ b/src/platform/nmp-object.c @@ -1545,13 +1545,13 @@ _vt_cmd_plobj_id_hash_update (tfilter, NMPlatformTfilter, { obj->handle); }) -static inline void +static void _vt_cmd_plobj_hash_update_ip4_route (const NMPlatformObject *obj, NMHashState *h) { return nm_platform_ip4_route_hash_update ((const NMPlatformIP4Route *) obj, NM_PLATFORM_IP_ROUTE_CMP_TYPE_FULL, h); } -static inline void +static void _vt_cmd_plobj_hash_update_ip6_route (const NMPlatformObject *obj, NMHashState *h) { return nm_platform_ip6_route_hash_update ((const NMPlatformIP6Route *) obj, NM_PLATFORM_IP_ROUTE_CMP_TYPE_FULL, h); @@ -2519,10 +2519,10 @@ nmp_cache_remove_netlink (NMPCache *cache, * afterwards. Hence, during a dump, every update should move the object to the * end of the list, to obtain the correct order. That means, to use NM_DEDUP_MULTI_IDX_MODE_APPEND_FORCE, * instead of NM_DEDUP_MULTI_IDX_MODE_APPEND. - * @out_obj_old: (allow-none): (out): return the object with same ID as @obj_hand_over, + * @out_obj_old: (allow-none) (out): return the object with same ID as @obj_hand_over, * that was in the cache before update. If an object is returned, the caller must * unref it afterwards. - * @out_obj_new: (allow-none): (out): return the object from the cache after update. + * @out_obj_new: (allow-none) (out): return the object from the cache after update. * The caller must unref this object. * * Returns: how the cache changed. @@ -2920,15 +2920,15 @@ nmp_cache_update_link_master_connected (NMPCache *cache, /*****************************************************************************/ void -nmp_cache_dirty_set_all (NMPCache *cache, NMPObjectType obj_type) +nmp_cache_dirty_set_all (NMPCache *cache, + const NMPLookup *lookup) { - NMPObject obj_needle; - nm_assert (cache); + nm_assert (lookup); nm_dedup_multi_index_dirty_set_head (cache->multi_idx, - _idx_type_get (cache, NMP_CACHE_ID_TYPE_OBJECT_TYPE), - _nmp_object_stackinit_from_type (&obj_needle, obj_type)); + _idx_type_get (cache, lookup->cache_id_type), + &lookup->selector_obj); } /*****************************************************************************/ @@ -2977,7 +2977,6 @@ const NMPClass _nmp_classes[NMP_OBJECT_TYPE_MAX] = { .sizeof_data = sizeof (NMPObjectLink), .sizeof_public = sizeof (NMPlatformLink), .obj_type_name = "link", - .addr_family = AF_UNSPEC, .rtm_gettype = RTM_GETLINK, .signal_type_id = NM_PLATFORM_SIGNAL_ID_LINK, .signal_type = NM_PLATFORM_SIGNAL_LINK_CHANGED, diff --git a/src/platform/nmp-object.h b/src/platform/nmp-object.h index 4649441b..525e1440 100644 --- a/src/platform/nmp-object.h +++ b/src/platform/nmp-object.h @@ -31,6 +31,18 @@ struct udev_device; /*****************************************************************************/ +/* "struct __kernel_timespec" uses "long long", but we use gint64. In practice, + * these are the same types. */ +G_STATIC_ASSERT (sizeof (long long) == sizeof (gint64)); + +typedef struct { + /* like "struct __kernel_timespec". */ + gint64 tv_sec; + gint64 tv_nsec; +} NMPTimespec64; + +/*****************************************************************************/ + typedef union { struct sockaddr sa; struct sockaddr_in in; @@ -72,7 +84,8 @@ typedef struct { typedef struct _NMPWireGuardPeer { NMSockAddrUnion endpoint; - struct timespec last_handshake_time; + NMPTimespec64 last_handshake_time; + guint64 rx_bytes; guint64 tx_bytes; @@ -771,7 +784,8 @@ NMPCacheOpsType nmp_cache_update_link_master_connected (NMPCache *cache, const NMPObject **out_obj_old, const NMPObject **out_obj_new); -void nmp_cache_dirty_set_all (NMPCache *cache, NMPObjectType obj_type); +void nmp_cache_dirty_set_all (NMPCache *cache, + const NMPLookup *lookup); NMPCache *nmp_cache_new (NMDedupMultiIndex *multi_idx, gboolean use_udev); void nmp_cache_free (NMPCache *cache); diff --git a/src/platform/tests/meson.build b/src/platform/tests/meson.build index 3704e2ac..8086a46c 100644 --- a/src/platform/tests/meson.build +++ b/src/platform/tests/meson.build @@ -1,14 +1,14 @@ test_units = [ - ['test-link-fake', 'test-link.c', test_nm_dep_fake, 30], - ['test-link-linux', 'test-link.c', test_nm_dep_linux, 180], - ['test-address-fake', 'test-address.c', test_nm_dep_fake, 30], - ['test-address-linux', 'test-address.c', test_nm_dep_linux, 30], - ['test-general', 'test-general.c', test_nm_dep, 30], - ['test-nmp-object', 'test-nmp-object.c', test_nm_dep, 30], - ['test-route-fake', 'test-route.c', test_nm_dep_fake, 30], - ['test-route-linux', 'test-route.c', test_nm_dep_linux, 30], - ['test-cleanup-fake', 'test-cleanup.c', test_nm_dep_fake, 30], - ['test-cleanup-linux', 'test-cleanup.c', test_nm_dep_linux, 30], + ['test-link-fake', 'test-link.c', test_nm_dep_fake, default_test_timeout], + ['test-link-linux', 'test-link.c', test_nm_dep_linux, 900], + ['test-address-fake', 'test-address.c', test_nm_dep_fake, default_test_timeout], + ['test-address-linux', 'test-address.c', test_nm_dep_linux, default_test_timeout], + ['test-general', 'test-general.c', test_nm_dep, default_test_timeout], + ['test-nmp-object', 'test-nmp-object.c', test_nm_dep, default_test_timeout], + ['test-route-fake', 'test-route.c', test_nm_dep_fake, default_test_timeout], + ['test-route-linux', 'test-route.c', test_nm_dep_linux, default_test_timeout], + ['test-cleanup-fake', 'test-cleanup.c', test_nm_dep_fake, default_test_timeout], + ['test-cleanup-linux', 'test-cleanup.c', test_nm_dep_linux, default_test_timeout], ] foreach test_unit: test_units diff --git a/src/platform/tests/test-common.c b/src/platform/tests/test-common.c index 8e29b5ce..c510710b 100644 --- a/src/platform/tests/test-common.c +++ b/src/platform/tests/test-common.c @@ -1840,7 +1840,7 @@ nmtstp_namespace_create (int unshare_flags, GError **error) if (e != 0) { errsv = errno; g_set_error (error, NM_UTILS_ERROR, NM_UTILS_ERROR_UNKNOWN, - "pipe() failed with %d (%s)", errsv, strerror (errsv)); + "pipe() failed with %d (%s)", errsv, nm_strerror_native (errsv)); return FALSE; } @@ -1848,7 +1848,7 @@ nmtstp_namespace_create (int unshare_flags, GError **error) if (e != 0) { errsv = errno; g_set_error (error, NM_UTILS_ERROR, NM_UTILS_ERROR_UNKNOWN, - "pipe() failed with %d (%s)", errsv, strerror (errsv)); + "pipe() failed with %d (%s)", errsv, nm_strerror_native (errsv)); nm_close (pipefd_c2p[0]); nm_close (pipefd_c2p[1]); return FALSE; @@ -1858,7 +1858,7 @@ nmtstp_namespace_create (int unshare_flags, GError **error) if (pid < 0) { errsv = errno; g_set_error (error, NM_UTILS_ERROR, NM_UTILS_ERROR_UNKNOWN, - "fork() failed with %d (%s)", errsv, strerror (errsv)); + "fork() failed with %d (%s)", errsv, nm_strerror_native (errsv)); nm_close (pipefd_c2p[0]); nm_close (pipefd_c2p[1]); nm_close (pipefd_p2c[0]); @@ -1919,7 +1919,7 @@ nmtstp_namespace_create (int unshare_flags, GError **error) "child process failed for unknown reason"); } else { g_set_error (error, NM_UTILS_ERROR, NM_UTILS_ERROR_UNKNOWN, - "child process signaled failure %d (%s)", errsv, strerror (errsv)); + "child process signaled failure %d (%s)", errsv, nm_strerror_native (errsv)); } nm_close (pipefd_p2c[1]); kill (pid, SIGKILL); @@ -2074,14 +2074,14 @@ main (int argc, char **argv) if (unshare (CLONE_NEWNET | CLONE_NEWNS) != 0) { errsv = errno; - g_error ("unshare(CLONE_NEWNET|CLONE_NEWNS) failed with %s (%d)", strerror (errsv), errsv); + g_error ("unshare(CLONE_NEWNET|CLONE_NEWNS) failed with %s (%d)", nm_strerror_native (errsv), errsv); } /* We need a read-only /sys so that the platform knows there's no udev. */ mount (NULL, "/sys", "sysfs", MS_SLAVE, NULL); if (mount ("sys", "/sys", "sysfs", MS_RDONLY, NULL) != 0) { errsv = errno; - g_error ("mount(\"/sys\") failed with %s (%d)", strerror (errsv), errsv); + g_error ("mount(\"/sys\") failed with %s (%d)", nm_strerror_native (errsv), errsv); } } diff --git a/src/platform/tests/test-common.h b/src/platform/tests/test-common.h index 048fd9dd..aa1f5460 100644 --- a/src/platform/tests/test-common.h +++ b/src/platform/tests/test-common.h @@ -19,7 +19,6 @@ #include <stdlib.h> #include <unistd.h> #include <syslog.h> -#include <string.h> #include <arpa/inet.h> #include <linux/if.h> #include <linux/if_link.h> diff --git a/src/platform/tests/test-link.c b/src/platform/tests/test-link.c index bfd33058..71324301 100644 --- a/src/platform/tests/test-link.c +++ b/src/platform/tests/test-link.c @@ -860,9 +860,9 @@ _test_wireguard_change (NMPlatform *platform, if ((i % 2) == 1) { endpoint = (NMSockAddrUnion) { .in = { - .sin_family = AF_INET, - .sin_addr = nmtst_inet4_from_string (nm_sprintf_buf (s_addr, "192.168.7.%d", i)), - .sin_port = htons (14000 + i), + .sin_family = AF_INET, + .sin_addr.s_addr = nmtst_inet4_from_string (nm_sprintf_buf (s_addr, "192.168.7.%d", i)), + .sin_port = htons (14000 + i), }, }; } else { @@ -912,8 +912,12 @@ _test_wireguard_change (NMPlatform *platform, ifindex, &lnk_wireguard, (const NMPWireGuardPeer *) peers->data, + NULL, peers->len, - TRUE); + NM_PLATFORM_WIREGUARD_CHANGE_FLAG_HAS_PRIVATE_KEY + | NM_PLATFORM_WIREGUARD_CHANGE_FLAG_HAS_LISTEN_PORT + | NM_PLATFORM_WIREGUARD_CHANGE_FLAG_HAS_FWMARK + | NM_PLATFORM_WIREGUARD_CHANGE_FLAG_REPLACE_PEERS); g_assert (NMTST_NM_ERR_SUCCESS (r)); } @@ -2393,7 +2397,7 @@ _test_netns_check_skip (void) support_errsv = errno; } if (!support) { - _LOGD ("setns() failed with \"%s\". This indicates missing support (valgrind?)", g_strerror (support_errsv)); + _LOGD ("setns() failed with \"%s\". This indicates missing support (valgrind?)", nm_strerror_native (support_errsv)); g_test_skip ("No netns support (setns failed)"); return TRUE; } @@ -2983,6 +2987,69 @@ test_sysctl_netns_switch (void) /*****************************************************************************/ +static gpointer +_test_netns_mt_thread (gpointer data) +{ + NMPNetns *netns1 = data; + gs_unref_object NMPNetns *netns2 = NULL; + NMPNetns *netns_bottom; + NMPNetns *initial; + + netns_bottom = nmp_netns_get_initial (); + g_assert (netns_bottom); + + /* I don't know why, but we need to create a new netns here at least once. + * Otherwise, setns(, CLONE_NEWNS) below fails with EINVAL (???). + * + * Something is not right here, but what? */ + netns2 = nmp_netns_new (); + nmp_netns_pop (netns2); + g_clear_object (&netns2); + + nmp_netns_push (netns1); + nmp_netns_push_type (netns_bottom, CLONE_NEWNET); + nmp_netns_push_type (netns_bottom, CLONE_NEWNS); + nmp_netns_push_type (netns1, CLONE_NEWNS); + nmp_netns_pop (netns1); + nmp_netns_pop (netns_bottom); + nmp_netns_pop (netns_bottom); + nmp_netns_pop (netns1); + + initial = nmp_netns_get_initial (); + g_assert (NMP_IS_NETNS (initial)); + return g_object_ref (initial); +} + +static void +test_netns_mt (void) +{ + gs_unref_object NMPNetns *netns1 = NULL; + NMPNetns *initial_from_other_thread; + GThread *th; + + if (_test_netns_check_skip ()) + return; + + netns1 = nmp_netns_new (); + g_assert (NMP_NETNS (netns1)); + nmp_netns_pop (netns1); + + th = g_thread_new ("nm-test-netns-mt", _test_netns_mt_thread, netns1); + initial_from_other_thread = g_thread_join (th); + g_assert (NMP_IS_NETNS (initial_from_other_thread)); + + if (nmtst_get_rand_bool ()) { + nmp_netns_push (initial_from_other_thread); + nmp_netns_pop (initial_from_other_thread); + } + + g_object_add_weak_pointer (G_OBJECT (initial_from_other_thread), (gpointer *) &initial_from_other_thread); + g_object_unref (initial_from_other_thread); + g_assert (initial_from_other_thread == NULL); +} + +/*****************************************************************************/ + static void ethtool_features_dump (const NMEthtoolFeatureStates *features) { @@ -3137,6 +3204,8 @@ _nmtstp_setup_tests (void) g_test_add_vtable ("/general/netns/push", 0, NULL, _test_netns_setup, test_netns_push, _test_netns_teardown); g_test_add_vtable ("/general/netns/bind-to-path", 0, NULL, _test_netns_setup, test_netns_bind_to_path, _test_netns_teardown); + g_test_add_func ("/general/netns/mt", test_netns_mt); + g_test_add_func ("/general/sysctl/rename", test_sysctl_rename); g_test_add_func ("/general/sysctl/netns-switch", test_sysctl_netns_switch); diff --git a/src/platform/tests/test-route.c b/src/platform/tests/test-route.c index 4c0f686f..2619ec52 100644 --- a/src/platform/tests/test-route.c +++ b/src/platform/tests/test-route.c @@ -767,7 +767,7 @@ test_ip (gconstpointer test_data) const int EX_ = -1; struct { int ifindex; - } iface_data[10] = { 0 }; + } iface_data[10] = { { 0 }, }; int order_idx[G_N_ELEMENTS (iface_data)] = { 0 }; guint order_len; guint try; diff --git a/src/platform/wifi/nm-wifi-utils-nl80211.c b/src/platform/wifi/nm-wifi-utils-nl80211.c index 0df3d2d8..4f7ede97 100644 --- a/src/platform/wifi/nm-wifi-utils-nl80211.c +++ b/src/platform/wifi/nm-wifi-utils-nl80211.c @@ -24,15 +24,12 @@ #include "nm-wifi-utils-nl80211.h" -#include <errno.h> -#include <string.h> #include <sys/ioctl.h> #include <net/ethernet.h> #include <unistd.h> #include <linux/nl80211.h> #include <linux/if.h> -#include "nm-utils/nm-errno.h" #include "platform/nm-netlink.h" #include "nm-wifi-utils-private.h" #include "platform/nm-platform.h" @@ -184,8 +181,10 @@ nl80211_iface_info_handler (struct nl_msg *msg, void *arg) struct genlmsghdr *gnlh = nlmsg_data (nlmsg_hdr (msg)); struct nlattr *tb[NL80211_ATTR_MAX + 1]; - if (nla_parse (tb, NL80211_ATTR_MAX, genlmsg_attrdata (gnlh, 0), - genlmsg_attrlen (gnlh, 0), NULL) < 0) + if (nla_parse_arr (tb, + genlmsg_attrdata (gnlh, 0), + genlmsg_attrlen (gnlh, 0), + NULL) < 0) return NL_SKIP; if (!tb[NL80211_ATTR_IFTYPE]) @@ -279,16 +278,18 @@ nl80211_get_wake_on_wlan_handler (struct nl_msg *msg, void *arg) struct nlattr *trig[NUM_NL80211_WOWLAN_TRIG]; struct genlmsghdr *gnlh = nlmsg_data (nlmsg_hdr (msg)); - nla_parse (attrs, NL80211_ATTR_MAX, genlmsg_attrdata(gnlh, 0), - genlmsg_attrlen(gnlh, 0), NULL); + nla_parse_arr (attrs, + genlmsg_attrdata(gnlh, 0), + genlmsg_attrlen(gnlh, 0), + NULL); if (!attrs[NL80211_ATTR_WOWLAN_TRIGGERS]) return NL_SKIP; - nla_parse (trig, MAX_NL80211_WOWLAN_TRIG, - nla_data (attrs[NL80211_ATTR_WOWLAN_TRIGGERS]), - nla_len (attrs[NL80211_ATTR_WOWLAN_TRIGGERS]), - NULL); + nla_parse_arr (trig, + nla_data (attrs[NL80211_ATTR_WOWLAN_TRIGGERS]), + nla_len (attrs[NL80211_ATTR_WOWLAN_TRIGGERS]), + NULL); *wowl = NM_SETTING_WIRELESS_WAKE_ON_WLAN_NONE; if (trig[NL80211_WOWLAN_TRIG_ANY]) @@ -415,33 +416,35 @@ find_ssid (guint8 *ies, guint32 ies_len, static int nl80211_bss_dump_handler (struct nl_msg *msg, void *arg) { + static const struct nla_policy bss_policy[] = { + [NL80211_BSS_TSF] = { .type = NLA_U64 }, + [NL80211_BSS_FREQUENCY] = { .type = NLA_U32 }, + [NL80211_BSS_BSSID] = { .minlen = ETH_ALEN }, + [NL80211_BSS_BEACON_INTERVAL] = { .type = NLA_U16 }, + [NL80211_BSS_CAPABILITY] = { .type = NLA_U16 }, + [NL80211_BSS_INFORMATION_ELEMENTS] = { }, + [NL80211_BSS_SIGNAL_MBM] = { .type = NLA_U32 }, + [NL80211_BSS_SIGNAL_UNSPEC] = { .type = NLA_U8 }, + [NL80211_BSS_STATUS] = { .type = NLA_U32 }, + }; struct nl80211_bss_info *info = arg; struct genlmsghdr *gnlh = nlmsg_data (nlmsg_hdr (msg)); struct nlattr *tb[NL80211_ATTR_MAX + 1]; - struct nlattr *bss[NL80211_BSS_MAX + 1]; - static const struct nla_policy bss_policy[NL80211_BSS_MAX + 1] = { - [NL80211_BSS_TSF] = { .type = NLA_U64 }, - [NL80211_BSS_FREQUENCY] = { .type = NLA_U32 }, - [NL80211_BSS_BSSID] = { }, - [NL80211_BSS_BEACON_INTERVAL] = { .type = NLA_U16 }, - [NL80211_BSS_CAPABILITY] = { .type = NLA_U16 }, - [NL80211_BSS_INFORMATION_ELEMENTS] = { }, - [NL80211_BSS_SIGNAL_MBM] = { .type = NLA_U32 }, - [NL80211_BSS_SIGNAL_UNSPEC] = { .type = NLA_U8 }, - [NL80211_BSS_STATUS] = { .type = NLA_U32 }, - }; + struct nlattr *bss[G_N_ELEMENTS (bss_policy)]; guint32 status; - if (nla_parse (tb, NL80211_ATTR_MAX, genlmsg_attrdata (gnlh, 0), - genlmsg_attrlen (gnlh, 0), NULL) < 0) + if (nla_parse_arr (tb, + genlmsg_attrdata (gnlh, 0), + genlmsg_attrlen (gnlh, 0), + NULL) < 0) return NL_SKIP; if (tb[NL80211_ATTR_BSS] == NULL) return NL_SKIP; - if (nla_parse_nested (bss, NL80211_BSS_MAX, - tb[NL80211_ATTR_BSS], - bss_policy)) + if (nla_parse_nested_arr (bss, + tb[NL80211_ATTR_BSS], + bss_policy)) return NL_SKIP; if (bss[NL80211_BSS_STATUS] == NULL) @@ -461,21 +464,22 @@ nl80211_bss_dump_handler (struct nl_msg *msg, void *arg) info->freq = nla_get_u32 (bss[NL80211_BSS_FREQUENCY]); if (bss[NL80211_BSS_SIGNAL_UNSPEC]) - info->beacon_signal = - nla_get_u8 (bss[NL80211_BSS_SIGNAL_UNSPEC]); + info->beacon_signal = nla_get_u8 (bss[NL80211_BSS_SIGNAL_UNSPEC]); if (bss[NL80211_BSS_SIGNAL_MBM]) - info->beacon_signal = - nl80211_xbm_to_percent (nla_get_u32 (bss[NL80211_BSS_SIGNAL_MBM]), 100); + info->beacon_signal = nl80211_xbm_to_percent (nla_get_u32 (bss[NL80211_BSS_SIGNAL_MBM]), 100); if (bss[NL80211_BSS_INFORMATION_ELEMENTS]) { guint8 *ssid; guint32 ssid_len; find_ssid (nla_data (bss[NL80211_BSS_INFORMATION_ELEMENTS]), - nla_len (bss[NL80211_BSS_INFORMATION_ELEMENTS]), - &ssid, &ssid_len); - if (ssid && ssid_len && ssid_len <= sizeof (info->ssid)) { + nla_len (bss[NL80211_BSS_INFORMATION_ELEMENTS]), + &ssid, + &ssid_len); + if ( ssid + && ssid_len + && ssid_len <= sizeof (info->ssid)) { memcpy (info->ssid, ssid, ssid_len); info->ssid_len = ssid_len; } @@ -550,49 +554,50 @@ struct nl80211_station_info { static int nl80211_station_handler (struct nl_msg *msg, void *arg) { - struct nl80211_station_info *info = arg; - struct nlattr *tb[NL80211_ATTR_MAX + 1]; - struct genlmsghdr *gnlh = nlmsg_data (nlmsg_hdr (msg)); - struct nlattr *sinfo[NL80211_STA_INFO_MAX + 1]; - struct nlattr *rinfo[NL80211_RATE_INFO_MAX + 1]; - static const struct nla_policy stats_policy[NL80211_STA_INFO_MAX + 1] = { + static const struct nla_policy stats_policy[] = { [NL80211_STA_INFO_INACTIVE_TIME] = { .type = NLA_U32 }, - [NL80211_STA_INFO_RX_BYTES] = { .type = NLA_U32 }, - [NL80211_STA_INFO_TX_BYTES] = { .type = NLA_U32 }, - [NL80211_STA_INFO_RX_PACKETS] = { .type = NLA_U32 }, - [NL80211_STA_INFO_TX_PACKETS] = { .type = NLA_U32 }, - [NL80211_STA_INFO_SIGNAL] = { .type = NLA_U8 }, - [NL80211_STA_INFO_TX_BITRATE] = { .type = NLA_NESTED }, - [NL80211_STA_INFO_LLID] = { .type = NLA_U16 }, - [NL80211_STA_INFO_PLID] = { .type = NLA_U16 }, - [NL80211_STA_INFO_PLINK_STATE] = { .type = NLA_U8 }, + [NL80211_STA_INFO_RX_BYTES] = { .type = NLA_U32 }, + [NL80211_STA_INFO_TX_BYTES] = { .type = NLA_U32 }, + [NL80211_STA_INFO_RX_PACKETS] = { .type = NLA_U32 }, + [NL80211_STA_INFO_TX_PACKETS] = { .type = NLA_U32 }, + [NL80211_STA_INFO_SIGNAL] = { .type = NLA_U8 }, + [NL80211_STA_INFO_TX_BITRATE] = { .type = NLA_NESTED }, + [NL80211_STA_INFO_LLID] = { .type = NLA_U16 }, + [NL80211_STA_INFO_PLID] = { .type = NLA_U16 }, + [NL80211_STA_INFO_PLINK_STATE] = { .type = NLA_U8 }, }; - - static const struct nla_policy rate_policy[NL80211_RATE_INFO_MAX + 1] = { - [NL80211_RATE_INFO_BITRATE] = { .type = NLA_U16 }, - [NL80211_RATE_INFO_MCS] = { .type = NLA_U8 }, + static const struct nla_policy rate_policy[] = { + [NL80211_RATE_INFO_BITRATE] = { .type = NLA_U16 }, + [NL80211_RATE_INFO_MCS] = { .type = NLA_U8 }, [NL80211_RATE_INFO_40_MHZ_WIDTH] = { .type = NLA_FLAG }, - [NL80211_RATE_INFO_SHORT_GI] = { .type = NLA_FLAG }, + [NL80211_RATE_INFO_SHORT_GI] = { .type = NLA_FLAG }, }; + struct nlattr *rinfo[G_N_ELEMENTS (rate_policy)]; + struct nlattr *sinfo[G_N_ELEMENTS (stats_policy)]; + struct nl80211_station_info *info = arg; + struct nlattr *tb[NL80211_ATTR_MAX + 1]; + struct genlmsghdr *gnlh = nlmsg_data (nlmsg_hdr (msg)); - if (nla_parse (tb, NL80211_ATTR_MAX, genlmsg_attrdata (gnlh, 0), - genlmsg_attrlen (gnlh, 0), NULL) < 0) + if (nla_parse_arr (tb, + genlmsg_attrdata (gnlh, 0), + genlmsg_attrlen (gnlh, 0), + NULL) < 0) return NL_SKIP; if (tb[NL80211_ATTR_STA_INFO] == NULL) return NL_SKIP; - if (nla_parse_nested (sinfo, NL80211_STA_INFO_MAX, - tb[NL80211_ATTR_STA_INFO], - stats_policy)) + if (nla_parse_nested_arr (sinfo, + tb[NL80211_ATTR_STA_INFO], + stats_policy)) return NL_SKIP; if (sinfo[NL80211_STA_INFO_TX_BITRATE] == NULL) return NL_SKIP; - if (nla_parse_nested (rinfo, NL80211_RATE_INFO_MAX, - sinfo[NL80211_STA_INFO_TX_BITRATE], - rate_policy)) + if (nla_parse_nested_arr (rinfo, + sinfo[NL80211_STA_INFO_TX_BITRATE], + rate_policy)) return NL_SKIP; if (rinfo[NL80211_RATE_INFO_BITRATE] == NULL) @@ -717,37 +722,40 @@ struct nl80211_device_info { static int nl80211_wiphy_info_handler (struct nl_msg *msg, void *arg) { + static const struct nla_policy freq_policy[] = { + [NL80211_FREQUENCY_ATTR_FREQ] = { .type = NLA_U32 }, + [NL80211_FREQUENCY_ATTR_DISABLED] = { .type = NLA_FLAG }, +#ifdef NL80211_FREQUENCY_ATTR_NO_IR + [NL80211_FREQUENCY_ATTR_NO_IR] = { .type = NLA_FLAG }, +#else + [NL80211_FREQUENCY_ATTR_PASSIVE_SCAN] = { .type = NLA_FLAG }, + [NL80211_FREQUENCY_ATTR_NO_IBSS] = { .type = NLA_FLAG }, +#endif + [NL80211_FREQUENCY_ATTR_RADAR] = { .type = NLA_FLAG }, + [NL80211_FREQUENCY_ATTR_MAX_TX_POWER] = { .type = NLA_U32 }, + }; struct nlattr *tb[NL80211_ATTR_MAX + 1]; struct genlmsghdr *gnlh = nlmsg_data (nlmsg_hdr (msg)); struct nl80211_device_info *info = arg; NMWifiUtilsNl80211 *self = info->self; struct nlattr *tb_band[NL80211_BAND_ATTR_MAX + 1]; - struct nlattr *tb_freq[NL80211_FREQUENCY_ATTR_MAX + 1]; + struct nlattr *tb_freq[G_N_ELEMENTS (freq_policy)]; struct nlattr *nl_band; struct nlattr *nl_freq; int rem_freq; int rem_band; int freq_idx; - static const struct nla_policy freq_policy[NL80211_FREQUENCY_ATTR_MAX + 1] = { - [NL80211_FREQUENCY_ATTR_FREQ] = { .type = NLA_U32 }, - [NL80211_FREQUENCY_ATTR_DISABLED] = { .type = NLA_FLAG }, -#ifdef NL80211_FREQUENCY_ATTR_NO_IR - [NL80211_FREQUENCY_ATTR_NO_IR] = { .type = NLA_FLAG }, -#else - [NL80211_FREQUENCY_ATTR_PASSIVE_SCAN] = { .type = NLA_FLAG }, - [NL80211_FREQUENCY_ATTR_NO_IBSS] = { .type = NLA_FLAG }, -#endif - [NL80211_FREQUENCY_ATTR_RADAR] = { .type = NLA_FLAG }, - [NL80211_FREQUENCY_ATTR_MAX_TX_POWER] = { .type = NLA_U32 }, - }; + #ifdef NL80211_FREQUENCY_ATTR_NO_IR - G_STATIC_ASSERT (NL80211_FREQUENCY_ATTR_PASSIVE_SCAN == NL80211_FREQUENCY_ATTR_NO_IR && NL80211_FREQUENCY_ATTR_NO_IBSS == NL80211_FREQUENCY_ATTR_NO_IR); + G_STATIC_ASSERT_EXPR (NL80211_FREQUENCY_ATTR_PASSIVE_SCAN == NL80211_FREQUENCY_ATTR_NO_IR && NL80211_FREQUENCY_ATTR_NO_IBSS == NL80211_FREQUENCY_ATTR_NO_IR); #else - G_STATIC_ASSERT (NL80211_FREQUENCY_ATTR_PASSIVE_SCAN != NL80211_FREQUENCY_ATTR_NO_IBSS); + G_STATIC_ASSERT_EXPR (NL80211_FREQUENCY_ATTR_PASSIVE_SCAN != NL80211_FREQUENCY_ATTR_NO_IBSS); #endif - if (nla_parse (tb, NL80211_ATTR_MAX, genlmsg_attrdata (gnlh, 0), - genlmsg_attrlen (gnlh, 0), NULL) < 0) + if (nla_parse_arr (tb, + genlmsg_attrdata (gnlh, 0), + genlmsg_attrlen (gnlh, 0), + NULL) < 0) return NL_SKIP; if ( tb[NL80211_ATTR_WIPHY] == NULL @@ -793,14 +801,17 @@ static int nl80211_wiphy_info_handler (struct nl_msg *msg, void *arg) info->num_freqs = 0; nla_for_each_nested (nl_band, tb[NL80211_ATTR_WIPHY_BANDS], rem_band) { - if (nla_parse_nested (tb_band, NL80211_BAND_ATTR_MAX, nl_band, - NULL) < 0) + if (nla_parse_nested_arr (tb_band, + nl_band, + NULL) < 0) return NL_SKIP; - nla_for_each_nested (nl_freq, tb_band[NL80211_BAND_ATTR_FREQS], + nla_for_each_nested (nl_freq, + tb_band[NL80211_BAND_ATTR_FREQS], rem_freq) { - if (nla_parse_nested (tb_freq, NL80211_FREQUENCY_ATTR_MAX, - nl_freq, freq_policy) < 0) + if (nla_parse_nested_arr (tb_freq, + nl_freq, + freq_policy) < 0) continue; if (!tb_freq[NL80211_FREQUENCY_ATTR_FREQ]) @@ -815,21 +826,22 @@ static int nl80211_wiphy_info_handler (struct nl_msg *msg, void *arg) freq_idx = 0; nla_for_each_nested (nl_band, tb[NL80211_ATTR_WIPHY_BANDS], rem_band) { - if (nla_parse_nested (tb_band, NL80211_BAND_ATTR_MAX, nl_band, - NULL) < 0) + if (nla_parse_nested_arr (tb_band, + nl_band, + NULL) < 0) return NL_SKIP; nla_for_each_nested (nl_freq, tb_band[NL80211_BAND_ATTR_FREQS], rem_freq) { - if (nla_parse_nested (tb_freq, NL80211_FREQUENCY_ATTR_MAX, - nl_freq, freq_policy) < 0) + if (nla_parse_nested_arr (tb_freq, + nl_freq, + freq_policy) < 0) continue; if (!tb_freq[NL80211_FREQUENCY_ATTR_FREQ]) continue; - info->freqs[freq_idx] = - nla_get_u32 (tb_freq[NL80211_FREQUENCY_ATTR_FREQ]); + info->freqs[freq_idx] = nla_get_u32 (tb_freq[NL80211_FREQUENCY_ATTR_FREQ]); info->caps |= NM_WIFI_DEVICE_CAP_FREQ_VALID; @@ -844,11 +856,10 @@ static int nl80211_wiphy_info_handler (struct nl_msg *msg, void *arg) /* Read security/encryption support */ if (tb[NL80211_ATTR_CIPHER_SUITES]) { - int num; - int i; - __u32 *ciphers = nla_data (tb[NL80211_ATTR_CIPHER_SUITES]); + guint32 *ciphers = nla_data (tb[NL80211_ATTR_CIPHER_SUITES]); + guint i, num; - num = nla_len (tb[NL80211_ATTR_CIPHER_SUITES]) / sizeof (__u32); + num = nla_len (tb[NL80211_ATTR_CIPHER_SUITES]) / sizeof (guint32); for (i = 0; i < num; i++) { switch (ciphers[i]) { case WLAN_CIPHER_SUITE_WEP40: diff --git a/src/platform/wifi/nm-wifi-utils-wext.c b/src/platform/wifi/nm-wifi-utils-wext.c index 597f3152..3aa1720a 100644 --- a/src/platform/wifi/nm-wifi-utils-wext.c +++ b/src/platform/wifi/nm-wifi-utils-wext.c @@ -23,8 +23,6 @@ #include "nm-wifi-utils-wext.h" -#include <errno.h> -#include <string.h> #include <sys/ioctl.h> #include <net/ethernet.h> #include <unistd.h> @@ -117,7 +115,7 @@ get_ifname (int ifindex, char *buffer, const char *op) errsv = errno; _LOGW (LOGD_PLATFORM | LOGD_WIFI, "error getting interface name for ifindex %d, operation '%s': %s (%d)", - ifindex, op, g_strerror (errsv), errsv); + ifindex, op, nm_strerror_native (errsv), errsv); return FALSE; } @@ -129,15 +127,17 @@ wifi_wext_get_mode_ifname (NMWifiUtils *data, const char *ifname) { NMWifiUtilsWext *wext = (NMWifiUtilsWext *) data; struct iwreq wrq; + int errsv; memset (&wrq, 0, sizeof (struct iwreq)); nm_utils_ifname_cpy (wrq.ifr_name, ifname); if (ioctl (wext->fd, SIOCGIWMODE, &wrq) < 0) { - if (errno != ENODEV) { + errsv = errno; + if (errsv != ENODEV) { _LOGW (LOGD_PLATFORM | LOGD_WIFI, "(%s): error %d getting card mode", - ifname, errno); + ifname, errsv); } return NM_802_11_MODE_UNKNOWN; } @@ -253,7 +253,7 @@ wifi_wext_get_freq (NMWifiUtils *data) if (ioctl (wext->fd, SIOCGIWFREQ, &wrq) < 0) { _LOGW (LOGD_PLATFORM | LOGD_WIFI, "(%s): error getting frequency: %s", - ifname, strerror (errno)); + ifname, nm_strerror_native (errno)); return 0; } @@ -291,7 +291,7 @@ wifi_wext_get_bssid (NMWifiUtils *data, guint8 *out_bssid) if (ioctl (wext->fd, SIOCGIWAP, &wrq) < 0) { _LOGW (LOGD_PLATFORM | LOGD_WIFI, "(%s): error getting associated BSSID: %s", - ifname, strerror (errno)); + ifname, nm_strerror_native (errno)); return FALSE; } memcpy (out_bssid, &(wrq.u.ap_addr.sa_data), ETH_ALEN); @@ -429,7 +429,7 @@ wifi_wext_get_qual (NMWifiUtils *data) if (ioctl (wext->fd, SIOCGIWSTATS, &wrq) < 0) { _LOGW (LOGD_PLATFORM | LOGD_WIFI, "(%s): error getting signal strength: %s", - ifname, strerror (errno)); + ifname, nm_strerror_native (errno)); return -1; } @@ -476,7 +476,7 @@ wifi_wext_set_mesh_channel (NMWifiUtils *data, guint32 channel) if (ioctl (wext->fd, SIOCSIWFREQ, &wrq) < 0) { _LOGE (LOGD_PLATFORM | LOGD_WIFI | LOGD_OLPC, "(%s): error setting channel to %d: %s", - ifname, channel, strerror (errno)); + ifname, channel, nm_strerror_native (errno)); return FALSE; } @@ -506,15 +506,15 @@ wifi_wext_set_mesh_ssid (NMWifiUtils *data, const guint8 *ssid, gsize len) if (ioctl (wext->fd, SIOCSIWESSID, &wrq) == 0) return TRUE; - if (errno != ENODEV) { + errsv = errno; + if (errsv != ENODEV) { gs_free char *ssid_str = NULL; - errsv = errno; _LOGE (LOGD_PLATFORM | LOGD_WIFI | LOGD_OLPC, "(%s): error setting SSID to %s: %s", ifname, (ssid_str = _nm_utils_ssid_to_string_arr (ssid, len)), - strerror (errsv)); + nm_strerror_native (errsv)); } return FALSE; @@ -545,6 +545,7 @@ wext_get_range_ifname (NMWifiUtilsWext *wext, int i = 26; gboolean success = FALSE; struct iwreq wrq; + int errsv; memset (&wrq, 0, sizeof (struct iwreq)); nm_utils_ifname_cpy (wrq.ifr_name, ifname); @@ -561,11 +562,14 @@ wext_get_range_ifname (NMWifiUtilsWext *wext, *response_len = wrq.u.data.length; success = TRUE; break; - } else if (errno != EAGAIN) { - _LOGE (LOGD_PLATFORM | LOGD_WIFI, - "(%s): couldn't get driver range information (%d).", - ifname, errno); - break; + } else { + errsv = errno; + if (errsv != EAGAIN) { + _LOGE (LOGD_PLATFORM | LOGD_WIFI, + "(%s): couldn't get driver range information (%d).", + ifname, errsv); + break; + } } g_usleep (G_USEC_PER_SEC / 4); diff --git a/src/platform/wifi/nm-wifi-utils.c b/src/platform/wifi/nm-wifi-utils.c index 25d71c6a..96071faa 100644 --- a/src/platform/wifi/nm-wifi-utils.c +++ b/src/platform/wifi/nm-wifi-utils.c @@ -25,7 +25,6 @@ #include <sys/stat.h> #include <stdio.h> -#include <string.h> #include <fcntl.h> #include "nm-wifi-utils-private.h" diff --git a/src/platform/wpan/nm-wpan-utils.c b/src/platform/wpan/nm-wpan-utils.c index f8708bc6..b7a51e9b 100644 --- a/src/platform/wpan/nm-wpan-utils.c +++ b/src/platform/wpan/nm-wpan-utils.c @@ -23,7 +23,6 @@ #include <linux/if.h> -#include "nm-utils/nm-errno.h" #include "platform/linux/nl802154.h" #include "platform/nm-netlink.h" #include "platform/nm-platform-utils.h" @@ -154,17 +153,19 @@ struct nl802154_interface { static int nl802154_get_interface_handler (struct nl_msg *msg, void *arg) { + static const struct nla_policy nl802154_policy[] = { + [NL802154_ATTR_PAN_ID] = { .type = NLA_U16 }, + [NL802154_ATTR_SHORT_ADDR] = { .type = NLA_U16 }, + }; + struct nlattr *tb[G_N_ELEMENTS (nl802154_policy)]; struct nl802154_interface *info = arg; struct genlmsghdr *gnlh = nlmsg_data (nlmsg_hdr (msg)); - struct nlattr *tb[NL802154_ATTR_MAX + 1] = { 0, }; - static const struct nla_policy nl802154_policy[NL802154_ATTR_MAX + 1] = { - [NL802154_ATTR_PAN_ID] = { .type = NLA_U16 }, - [NL802154_ATTR_SHORT_ADDR] = { .type = NLA_U16 }, - }; - if (nla_parse (tb, NL802154_ATTR_MAX, genlmsg_attrdata (gnlh, 0), - genlmsg_attrlen (gnlh, 0), nl802154_policy) < 0) - return NL_SKIP; + if (nla_parse_arr (tb, + genlmsg_attrdata (gnlh, 0), + genlmsg_attrlen (gnlh, 0), + nl802154_policy) < 0) + return NL_SKIP; if (tb[NL802154_ATTR_PAN_ID]) info->pan_id = le16toh (nla_get_u16 (tb[NL802154_ATTR_PAN_ID])); diff --git a/src/ppp/nm-ppp-manager-call.c b/src/ppp/nm-ppp-manager-call.c index 8f658416..d951e4fd 100644 --- a/src/ppp/nm-ppp-manager-call.c +++ b/src/ppp/nm-ppp-manager-call.c @@ -24,7 +24,6 @@ #include <sys/types.h> #include <sys/stat.h> -#include <errno.h> #include "nm-manager.h" #include "nm-core-utils.h" diff --git a/src/ppp/nm-ppp-manager.c b/src/ppp/nm-ppp-manager.c index d8fdbab2..04c14dfb 100644 --- a/src/ppp/nm-ppp-manager.c +++ b/src/ppp/nm-ppp-manager.c @@ -26,11 +26,9 @@ #include <sys/types.h> #include <sys/wait.h> #include <signal.h> -#include <string.h> #include <unistd.h> #include <arpa/inet.h> #include <stdlib.h> -#include <errno.h> #include <sys/socket.h> #include <sys/ioctl.h> #include <asm/types.h> @@ -182,6 +180,7 @@ monitor_cb (gpointer user_data) NMPPPManager *self = NM_PPP_MANAGER (user_data); NMPPPManagerPrivate *priv = NM_PPP_MANAGER_GET_PRIVATE (self); const char *ifname; + int errsv; ifname = nm_platform_link_get_name (NM_PLATFORM_GET, priv->ifindex); @@ -193,8 +192,9 @@ monitor_cb (gpointer user_data) nm_utils_ifname_cpy (req.ifr_name, ifname); if (ioctl (priv->monitor_fd, SIOCGPPPSTATS, &req) < 0) { - if (errno != ENODEV) - _LOGW ("could not read ppp stats: %s", strerror (errno)); + errsv = errno; + if (errsv != ENODEV) + _LOGW ("could not read ppp stats: %s", nm_strerror_native (errsv)); } else { g_signal_emit (self, signals[STATS], 0, (guint) stats.p.ppp_ibytes, @@ -209,19 +209,23 @@ static void monitor_stats (NMPPPManager *self) { NMPPPManagerPrivate *priv = NM_PPP_MANAGER_GET_PRIVATE (self); + int errsv; /* already monitoring */ if (priv->monitor_fd >= 0) return; priv->monitor_fd = socket (AF_INET, SOCK_DGRAM | SOCK_CLOEXEC, 0); - if (priv->monitor_fd >= 0) { - g_warn_if_fail (priv->monitor_id == 0); - if (priv->monitor_id) - g_source_remove (priv->monitor_id); - priv->monitor_id = g_timeout_add_seconds (5, monitor_cb, self); - } else - _LOGW ("could not monitor PPP stats: %s", strerror (errno)); + if (priv->monitor_fd < 0) { + errsv = errno; + _LOGW ("could not monitor PPP stats: %s", nm_strerror_native (errsv)); + return; + } + + g_warn_if_fail (priv->monitor_id == 0); + if (priv->monitor_id) + g_source_remove (priv->monitor_id); + priv->monitor_id = g_timeout_add_seconds (5, monitor_cb, self); } /*****************************************************************************/ @@ -363,7 +367,7 @@ impl_ppp_manager_need_secrets (NMDBusObject *obj, const char *username = NULL; const char *password = NULL; guint32 tries; - GPtrArray *hints = NULL; + gs_unref_ptrarray GPtrArray *hints = NULL; GError *error = NULL; NMSecretAgentGetSecretsFlags flags = NM_SECRET_AGENT_GET_SECRETS_FLAG_ALLOW_INTERACTION; @@ -393,18 +397,18 @@ impl_ppp_manager_need_secrets (NMDBusObject *obj, if (tries > 1) flags |= NM_SECRET_AGENT_GET_SECRETS_FLAG_REQUEST_NEW; + if (hints) + g_ptr_array_add (hints, NULL); + priv->secrets_id = nm_act_request_get_secrets (priv->act_req, FALSE, priv->secrets_setting_name, flags, - hints ? g_ptr_array_index (hints, 0) : NULL, + hints ? (const char *const*) hints->pdata : NULL, ppp_secrets_cb, self); g_object_set_qdata (G_OBJECT (applied_connection), ppp_manager_secret_tries_quark (), GUINT_TO_POINTER (++tries)); priv->pending_secrets_context = invocation; - - if (hints) - g_ptr_array_free (hints, TRUE); } static void @@ -1049,8 +1053,8 @@ _ppp_manager_start (NMPPPManager *self, _LOGI ("starting PPP connection"); - _LOGD ("command line: %s", cmd_str); - (cmd_str = g_strjoinv (" ", (char **) ppp_cmd->pdata)); + _LOGD ("command line: %s", + (cmd_str = g_strjoinv (" ", (char **) ppp_cmd->pdata))); priv->pid = 0; if (!g_spawn_async (NULL, diff --git a/src/ppp/nm-pppd-plugin.c b/src/ppp/nm-pppd-plugin.c index 5e99be41..a8d6749a 100644 --- a/src/ppp/nm-pppd-plugin.c +++ b/src/ppp/nm-pppd-plugin.c @@ -22,7 +22,6 @@ #include <config.h> #define ___CONFIG_H__ -#include <string.h> #include <pppd/pppd.h> #include <pppd/fsm.h> #include <pppd/ipcp.h> diff --git a/src/settings/nm-agent-manager.c b/src/settings/nm-agent-manager.c index edadee14..8924c39f 100644 --- a/src/settings/nm-agent-manager.c +++ b/src/settings/nm-agent-manager.c @@ -22,7 +22,6 @@ #include "nm-agent-manager.h" -#include <string.h> #include <pwd.h> #include "nm-common-macros.h" diff --git a/src/settings/nm-settings-connection.c b/src/settings/nm-settings-connection.c index 0beb5ea7..8d1f9583 100644 --- a/src/settings/nm-settings-connection.c +++ b/src/settings/nm-settings-connection.c @@ -23,8 +23,6 @@ #include "nm-settings-connection.h" -#include <string.h> - #include "c-list/src/c-list.h" #include "nm-common-macros.h" @@ -208,141 +206,6 @@ nm_settings_connection_get_last_secret_agent_version_id (NMSettingsConnection *s /*****************************************************************************/ -/* Return TRUE to keep, FALSE to drop */ -typedef gboolean (*ForEachSecretFunc) (NMSettingSecretFlags flags, - gpointer user_data); - -/* Returns always a non-NULL, non-floating variant that must - * be unrefed by the caller. */ -static GVariant * -for_each_secret (NMConnection *self, - GVariant *secrets, - gboolean remove_non_secrets, - ForEachSecretFunc callback, - gpointer callback_data) -{ - GVariantBuilder secrets_builder, setting_builder; - GVariantIter secrets_iter, *setting_iter; - const char *setting_name; - - /* This function, given a dict of dicts representing new secrets of - * an NMConnection, walks through each toplevel dict (which represents a - * NMSetting), and for each setting, walks through that setting dict's - * properties. For each property that's a secret, it will check that - * secret's flags in the backing NMConnection object, and call a supplied - * callback. - * - * The one complexity is that the VPN setting's 'secrets' property is - * *also* a dict (since the key/value pairs are arbitrary and known - * only to the VPN plugin itself). That means we have three levels of - * dicts that we potentially have to traverse here. When we hit the - * VPN setting's 'secrets' property, we special-case that and iterate over - * each item in that 'secrets' dict, calling the supplied callback - * each time. - */ - - g_return_val_if_fail (callback, NULL); - - g_variant_iter_init (&secrets_iter, secrets); - g_variant_builder_init (&secrets_builder, NM_VARIANT_TYPE_CONNECTION); - while (g_variant_iter_next (&secrets_iter, "{&sa{sv}}", &setting_name, &setting_iter)) { - NMSetting *setting; - const char *secret_name; - GVariant *val; - - setting = nm_connection_get_setting_by_name (self, setting_name); - if (setting == NULL) { - g_variant_iter_free (setting_iter); - continue; - } - - g_variant_builder_init (&setting_builder, NM_VARIANT_TYPE_SETTING); - while (g_variant_iter_next (setting_iter, "{&sv}", &secret_name, &val)) { - NMSettingSecretFlags secret_flags = NM_SETTING_SECRET_FLAG_NONE; - - /* VPN secrets need slightly different treatment here since the - * "secrets" property is actually a hash table of secrets. - */ - if (NM_IS_SETTING_VPN (setting) && !g_strcmp0 (secret_name, NM_SETTING_VPN_SECRETS)) { - GVariantBuilder vpn_secrets_builder; - GVariantIter vpn_secrets_iter; - const char *vpn_secret_name, *secret; - - /* Iterate through each secret from the VPN dict in the overall secrets dict */ - g_variant_builder_init (&vpn_secrets_builder, G_VARIANT_TYPE ("a{ss}")); - g_variant_iter_init (&vpn_secrets_iter, val); - while (g_variant_iter_next (&vpn_secrets_iter, "{&s&s}", &vpn_secret_name, &secret)) { - if (!nm_setting_get_secret_flags (setting, vpn_secret_name, &secret_flags, NULL)) { - if (!remove_non_secrets) - g_variant_builder_add (&vpn_secrets_builder, "{ss}", vpn_secret_name, secret); - continue; - } - - if (callback (secret_flags, callback_data)) - g_variant_builder_add (&vpn_secrets_builder, "{ss}", vpn_secret_name, secret); - } - - g_variant_builder_add (&setting_builder, "{sv}", - secret_name, g_variant_builder_end (&vpn_secrets_builder)); - } else { - if (!nm_setting_get_secret_flags (setting, secret_name, &secret_flags, NULL)) { - if (!remove_non_secrets) - g_variant_builder_add (&setting_builder, "{sv}", secret_name, val); - continue; - } - if (callback (secret_flags, callback_data)) - g_variant_builder_add (&setting_builder, "{sv}", secret_name, val); - } - g_variant_unref (val); - } - - g_variant_iter_free (setting_iter); - g_variant_builder_add (&secrets_builder, "{sa{sv}}", setting_name, &setting_builder); - } - - return g_variant_ref_sink (g_variant_builder_end (&secrets_builder)); -} - -typedef gboolean (*FindSecretFunc) (NMSettingSecretFlags flags, - gpointer user_data); - -typedef struct { - FindSecretFunc find_func; - gpointer find_func_data; - gboolean found; -} FindSecretData; - -static gboolean -find_secret_for_each_func (NMSettingSecretFlags flags, - gpointer user_data) -{ - FindSecretData *data = user_data; - - if (!data->found) - data->found = data->find_func (flags, data->find_func_data); - return FALSE; -} - -static gboolean -find_secret (NMConnection *self, - GVariant *secrets, - FindSecretFunc callback, - gpointer callback_data) -{ - FindSecretData data; - GVariant *dummy; - - data.find_func = callback; - data.find_func_data = callback_data; - data.found = FALSE; - - dummy = for_each_secret (self, secrets, FALSE, find_secret_for_each_func, &data); - g_variant_unref (dummy); - return data.found; -} - -/*****************************************************************************/ - static void set_visible (NMSettingsConnection *self, gboolean new_visible) { @@ -938,8 +801,8 @@ typedef struct { } ForEachSecretFlags; static gboolean -validate_secret_flags (NMSettingSecretFlags flags, - gpointer user_data) +validate_secret_flags_cb (NMSettingSecretFlags flags, + gpointer user_data) { ForEachSecretFlags *cmp_flags = user_data; @@ -950,6 +813,18 @@ validate_secret_flags (NMSettingSecretFlags flags, return TRUE; } +static GVariant * +validate_secret_flags (NMConnection *connection, + GVariant *secrets, + ForEachSecretFlags *cmp_flags) +{ + return g_variant_ref_sink (_nm_connection_for_each_secret (connection, + secrets, + TRUE, + validate_secret_flags_cb, + cmp_flags)); +} + static gboolean secret_is_system_owned (NMSettingSecretFlags flags, gpointer user_data) @@ -992,7 +867,7 @@ get_cmp_flags (NMSettingsConnection *self, /* only needed for logging */ * save those system-owned secrets. If not, discard them and use the * existing secrets, or fail the connection. */ - *agent_had_system = find_secret (connection, secrets, secret_is_system_owned, NULL); + *agent_had_system = _nm_connection_find_secret (connection, secrets, secret_is_system_owned, NULL); if (*agent_had_system) { if (flags == NM_SECRET_AGENT_GET_SECRETS_FLAG_NONE) { /* No user interaction was allowed when requesting secrets; the @@ -1151,14 +1026,14 @@ get_secrets_done_cb (NMAgentManager *manager, /* Update the connection with our existing secrets from backing storage */ nm_connection_clear_secrets (nm_settings_connection_get_connection (self)); if (!dict || nm_connection_update_secrets (nm_settings_connection_get_connection (self), setting_name, dict, &local)) { - GVariant *filtered_secrets; + gs_unref_variant GVariant *filtered_secrets = NULL; /* Update the connection with the agent's secrets; by this point if any * system-owned secrets exist in 'secrets' the agent that provided them * will have been authenticated, so those secrets can replace the existing * system secrets. */ - filtered_secrets = for_each_secret (nm_settings_connection_get_connection (self), secrets, TRUE, validate_secret_flags, &cmp_flags); + filtered_secrets = validate_secret_flags (nm_settings_connection_get_connection (self), secrets, &cmp_flags); if (nm_connection_update_secrets (nm_settings_connection_get_connection (self), setting_name, filtered_secrets, &local)) { /* Now that all secrets are updated, copy and cache new secrets, * then save them to backing storage. @@ -1194,7 +1069,6 @@ get_secrets_done_cb (NMAgentManager *manager, call_id, local->message); } - g_variant_unref (filtered_secrets); } else { _LOGD ("(%s:%p) failed to update with existing secrets: %s", setting_name, @@ -1218,11 +1092,10 @@ get_secrets_done_cb (NMAgentManager *manager, nm_connection_clear_secrets (applied_connection); if (!dict || nm_connection_update_secrets (applied_connection, setting_name, dict, NULL)) { - GVariant *filtered_secrets; + gs_unref_variant GVariant *filtered_secrets = NULL; - filtered_secrets = for_each_secret (applied_connection, secrets, TRUE, validate_secret_flags, &cmp_flags); + filtered_secrets = validate_secret_flags (applied_connection, secrets, &cmp_flags); nm_connection_update_secrets (applied_connection, setting_name, filtered_secrets, NULL); - g_variant_unref (filtered_secrets); } } @@ -1878,6 +1751,9 @@ settings_connection_update (NMSettingsConnection *self, &error); if (!tmp) goto error; + + if (!nm_connection_verify_secrets (tmp, &error)) + goto error; } } @@ -2777,7 +2653,7 @@ _autoconnect_retries_set (NMSettingsConnection *self, /* NOTE: 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). */ + * the next-timeout every time a connection gets blocked). */ priv->autoconnect_retries_blocked_until = nm_utils_get_monotonic_timestamp_s () + AUTOCONNECT_RESET_RETRIES_TIMER; } } diff --git a/src/settings/nm-settings.c b/src/settings/nm-settings.c index 74de6cc2..fd1d316a 100644 --- a/src/settings/nm-settings.c +++ b/src/settings/nm-settings.c @@ -29,8 +29,6 @@ #include <unistd.h> #include <sys/stat.h> -#include <errno.h> -#include <string.h> #include <gmodule.h> #include <pwd.h> @@ -375,7 +373,7 @@ _clear_connections_cached_list (NMSettingsPrivate *priv) /** * nm_settings_get_connections: * @self: the #NMSettings - * @out_len: (out): (allow-none): returns the number of returned + * @out_len: (out) (allow-none): returns the number of returned * connections. * * Returns: (transfer none): a list of NMSettingsConnections. The list is @@ -638,7 +636,7 @@ add_plugin_load_file (NMSettings *self, const char *pname, GError **error) if (stat (path, &st) != 0) { errsv = errno; - _LOGW ("could not load plugin '%s' from file '%s': %s", pname, path, strerror (errsv)); + _LOGW ("could not load plugin '%s' from file '%s': %s", pname, path, nm_strerror_native (errsv)); return TRUE; } if (!S_ISREG (st.st_mode)) { diff --git a/src/settings/plugins/ibft/nms-ibft-connection.c b/src/settings/plugins/ibft/nms-ibft-connection.c index fb7f18f8..a36d8a31 100644 --- a/src/settings/plugins/ibft/nms-ibft-connection.c +++ b/src/settings/plugins/ibft/nms-ibft-connection.c @@ -22,7 +22,6 @@ #include "nms-ibft-connection.h" -#include <string.h> #include <net/ethernet.h> #include <netinet/ether.h> #include <glib/gstdio.h> diff --git a/src/settings/plugins/ibft/nms-ibft-plugin.c b/src/settings/plugins/ibft/nms-ibft-plugin.c index 69dd3733..00b25068 100644 --- a/src/settings/plugins/ibft/nms-ibft-plugin.c +++ b/src/settings/plugins/ibft/nms-ibft-plugin.c @@ -22,9 +22,7 @@ #include "nms-ibft-plugin.h" -#include <string.h> #include <unistd.h> -#include <errno.h> #include <gmodule.h> #include "nm-setting-connection.h" diff --git a/src/settings/plugins/ibft/nms-ibft-reader.c b/src/settings/plugins/ibft/nms-ibft-reader.c index ac5824a1..c6c14376 100644 --- a/src/settings/plugins/ibft/nms-ibft-reader.c +++ b/src/settings/plugins/ibft/nms-ibft-reader.c @@ -23,13 +23,11 @@ #include "nms-ibft-reader.h" #include <stdlib.h> -#include <string.h> #include <sys/types.h> #include <sys/socket.h> #include <arpa/inet.h> #include <sys/wait.h> #include <sys/inotify.h> -#include <errno.h> #include <sys/ioctl.h> #include <unistd.h> diff --git a/src/settings/plugins/ibft/tests/test-ibft.c b/src/settings/plugins/ibft/tests/test-ibft.c index 5e46be2e..4c45f574 100644 --- a/src/settings/plugins/ibft/tests/test-ibft.c +++ b/src/settings/plugins/ibft/tests/test-ibft.c @@ -23,7 +23,6 @@ #include <stdio.h> #include <stdarg.h> #include <unistd.h> -#include <string.h> #include <netinet/ether.h> #include <netinet/in.h> #include <arpa/inet.h> diff --git a/src/settings/plugins/ifcfg-rh/nm-inotify-helper.c b/src/settings/plugins/ifcfg-rh/nm-inotify-helper.c index e7a74a1a..04cbb5bc 100644 --- a/src/settings/plugins/ifcfg-rh/nm-inotify-helper.c +++ b/src/settings/plugins/ifcfg-rh/nm-inotify-helper.c @@ -23,9 +23,7 @@ #include "nm-inotify-helper.h" #include <unistd.h> -#include <string.h> #include <sys/inotify.h> -#include <errno.h> #include "NetworkManagerUtils.h" @@ -143,12 +141,12 @@ init_inotify (NMInotifyHelper *self) { NMInotifyHelperPrivate *priv = NM_INOTIFY_HELPER_GET_PRIVATE (self); GIOChannel *channel; + int errsv; priv->ifd = inotify_init1 (IN_CLOEXEC); if (priv->ifd == -1) { - int errsv = errno; - - nm_log_warn (LOGD_SETTINGS, "couldn't initialize inotify: %s (%d)", strerror (errsv), errsv); + errsv = errno; + nm_log_warn (LOGD_SETTINGS, "couldn't initialize inotify: %s (%d)", nm_strerror_native (errsv), errsv); return FALSE; } 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 ca319ddc..4f769c5f 100644 --- a/src/settings/plugins/ifcfg-rh/nms-ifcfg-rh-connection.c +++ b/src/settings/plugins/ifcfg-rh/nms-ifcfg-rh-connection.c @@ -22,7 +22,6 @@ #include "nms-ifcfg-rh-connection.h" -#include <string.h> #include <sys/inotify.h> #include <glib/gstdio.h> 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 05d4d738..89272edb 100644 --- a/src/settings/plugins/ifcfg-rh/nms-ifcfg-rh-plugin.c +++ b/src/settings/plugins/ifcfg-rh/nms-ifcfg-rh-plugin.c @@ -25,9 +25,7 @@ #include "nms-ifcfg-rh-plugin.h" -#include <string.h> #include <unistd.h> -#include <errno.h> #include <sys/types.h> #include <sys/stat.h> #include <gmodule.h> 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 6eb99d3b..7c1db225 100644 --- a/src/settings/plugins/ifcfg-rh/nms-ifcfg-rh-reader.c +++ b/src/settings/plugins/ifcfg-rh/nms-ifcfg-rh-reader.c @@ -23,13 +23,11 @@ #include "nms-ifcfg-rh-reader.h" #include <stdlib.h> -#include <string.h> #include <sys/types.h> #include <sys/socket.h> #include <arpa/inet.h> #include <sys/wait.h> #include <sys/inotify.h> -#include <errno.h> #include <sys/ioctl.h> #include <unistd.h> @@ -189,7 +187,7 @@ _secret_password_raw_to_bytes (const char *ifcfg_key, password_raw += 2; secret = nm_secret_buf_new (strlen (password_raw) / 2 + 3); - if (!_nm_utils_hexstr2bin_full (password_raw, FALSE, FALSE, ":", 0, secret->bin, secret->len, &len)) { + if (!nm_utils_hexstr2bin_full (password_raw, FALSE, FALSE, ":", 0, secret->bin, secret->len, &len)) { g_set_error (error, NM_SETTINGS_ERROR, NM_SETTINGS_ERROR_INVALID_CONNECTION, "Invalid hex password in %s", ifcfg_key); @@ -801,7 +799,7 @@ enum { * @options_route: (in-out): when line is from the OPTIONS setting, this is a pre-created * route object that is completed with the settings from options. Otherwise, * it shall point to %NULL and a new route is created and returned. - * @out_route: (out): (transfer-full): (allow-none): the parsed %NMIPRoute instance. + * @out_route: (out) (transfer-full) (allow-none): the parsed %NMIPRoute instance. * In case a @options_route is passed in, it returns the input route that was modified * in-place. But the caller must unref the returned route in either case. * @error: the failure description. @@ -1427,8 +1425,8 @@ make_user_setting (shvarFile *ifcfg) has_user_data = TRUE; } - return has_user_data - ? g_steal_pointer (&s_user) + return has_user_data + ? NM_SETTING (g_steal_pointer (&s_user)) : NULL; } @@ -1613,7 +1611,7 @@ make_ip4_setting (shvarFile *ifcfg, NULL); if (nm_streq (method, NM_SETTING_IP4_CONFIG_METHOD_DISABLED)) - return g_steal_pointer (&s_ip4); + return NM_SETTING (g_steal_pointer (&s_ip4)); /* Handle DHCP settings */ nm_clear_g_free (&value); @@ -1804,7 +1802,7 @@ make_ip4_setting (shvarFile *ifcfg, } g_object_set (s_ip4, NM_SETTING_IP_CONFIG_DAD_TIMEOUT, (int) timeout, NULL); - return g_steal_pointer (&s_ip4); + return NM_SETTING (g_steal_pointer (&s_ip4)); } static void @@ -2946,7 +2944,7 @@ make_wep_setting (shvarFile *ifcfg, return NULL; } - return g_steal_pointer (&s_wsec); + return NM_SETTING (g_steal_pointer (&s_wsec)); } static gboolean @@ -3612,7 +3610,7 @@ make_wpa_setting (shvarFile *ifcfg, gs_unref_object NMSettingWirelessSecurity *wsec = NULL; gs_free char *value = NULL; const char *v; - gboolean wpa_psk = FALSE, wpa_eap = FALSE, ieee8021x = FALSE; + gboolean wpa_psk = FALSE, wpa_sae = FALSE, wpa_eap = FALSE, ieee8021x = FALSE; int i_val; GError *local = NULL; @@ -3620,9 +3618,10 @@ make_wpa_setting (shvarFile *ifcfg, v = svGetValueStr (ifcfg, "KEY_MGMT", &value); wpa_psk = nm_streq0 (v, "WPA-PSK"); + wpa_sae = nm_streq0 (v, "SAE"); wpa_eap = nm_streq0 (v, "WPA-EAP"); ieee8021x = nm_streq0 (v, "IEEE8021X"); - if (!wpa_psk && !wpa_eap && !ieee8021x) + if (!wpa_psk && !wpa_sae && !wpa_eap && !ieee8021x) return NULL; /* Not WPA or Dynamic WEP */ /* WPS */ @@ -3636,7 +3635,7 @@ make_wpa_setting (shvarFile *ifcfg, NULL); /* Pairwise and Group ciphers (only relevant for WPA/RSN) */ - if (wpa_psk || wpa_eap) { + if (wpa_psk || wpa_sae || wpa_eap) { fill_wpa_ciphers (ifcfg, wsec, FALSE, adhoc); fill_wpa_ciphers (ifcfg, wsec, TRUE, adhoc); } @@ -3659,7 +3658,7 @@ make_wpa_setting (shvarFile *ifcfg, nm_setting_wireless_security_add_proto (wsec, "rsn"); } - if (wpa_psk) { + if (wpa_psk || wpa_sae) { NMSettingSecretFlags psk_flags; psk_flags = _secret_read_ifcfg_flags (ifcfg, "WPA_PSK_FLAGS"); @@ -3680,8 +3679,12 @@ make_wpa_setting (shvarFile *ifcfg, if (adhoc) g_object_set (wsec, NM_SETTING_WIRELESS_SECURITY_KEY_MGMT, "wpa-none", NULL); - else + else if (wpa_psk) g_object_set (wsec, NM_SETTING_WIRELESS_SECURITY_KEY_MGMT, "wpa-psk", NULL); + else if (wpa_sae) + g_object_set (wsec, NM_SETTING_WIRELESS_SECURITY_KEY_MGMT, "sae", NULL); + else + g_assert_not_reached (); } else if (wpa_eap || ieee8021x) { /* Adhoc mode is mutually exclusive with any 802.1x-based authentication */ if (adhoc) { @@ -3946,9 +3949,8 @@ make_wireless_setting (shvarFile *ifcfg, value = svGetValueStr_cp (ifcfg, "CHANNEL"); if (value) { - errno = 0; chan = _nm_utils_ascii_str_to_int64 (value, 10, 1, 196, 0); - if (errno || (chan == 0)) { + if (chan == 0) { g_set_error (error, NM_SETTINGS_ERROR, NM_SETTINGS_ERROR_INVALID_CONNECTION, "Invalid wireless channel '%s'", value); g_free (value); @@ -4992,7 +4994,7 @@ handle_bridge_option (NMSetting *setting, } else { v = _nm_utils_ascii_str_to_int64 (value, 10, 0, 1, -1); if (v == -1) { - error_message = g_strerror (errno); + error_message = nm_strerror_native (errno); goto warn; } } @@ -5004,7 +5006,7 @@ handle_bridge_option (NMSetting *setting, 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); + error_message = nm_strerror_native (errno); goto warn; } if (!nm_g_object_set_property_uint (G_OBJECT (setting), m[i].property_name, v, NULL)) { @@ -5229,16 +5231,14 @@ is_vlan_device (const char *name, shvarFile *parsed) static gboolean is_wifi_device (const char *name, shvarFile *parsed) { - int ifindex; + const NMPlatformLink *pllink; g_return_val_if_fail (name != NULL, FALSE); g_return_val_if_fail (parsed != NULL, FALSE); - ifindex = nm_platform_link_get_ifindex (NM_PLATFORM_GET, name); - if (ifindex == 0) - return FALSE; - - return nm_platform_link_get_type (NM_PLATFORM_GET, ifindex) == NM_LINK_TYPE_WIFI; + pllink = nm_platform_link_get_by_ifname (NM_PLATFORM_GET, name); + return pllink + && pllink->type == NM_LINK_TYPE_WIFI; } static void @@ -5384,7 +5384,7 @@ make_vlan_setting (shvarFile *ifcfg, parse_prio_map_list (s_vlan, ifcfg, "VLAN_INGRESS_PRIORITY_MAP", NM_VLAN_INGRESS_MAP); parse_prio_map_list (s_vlan, ifcfg, "VLAN_EGRESS_PRIORITY_MAP", NM_VLAN_EGRESS_MAP); - return g_steal_pointer (&s_vlan); + return NM_SETTING (g_steal_pointer (&s_vlan)); } static NMConnection * 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 49096d26..22c9061b 100644 --- a/src/settings/plugins/ifcfg-rh/nms-ifcfg-rh-utils.c +++ b/src/settings/plugins/ifcfg-rh/nms-ifcfg-rh-utils.c @@ -23,7 +23,6 @@ #include "nms-ifcfg-rh-utils.h" #include <stdlib.h> -#include <string.h> #include "nm-core-internal.h" #include "NetworkManagerUtils.h" 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 f5be7520..ee7fd161 100644 --- a/src/settings/plugins/ifcfg-rh/nms-ifcfg-rh-writer.c +++ b/src/settings/plugins/ifcfg-rh/nms-ifcfg-rh-writer.c @@ -22,11 +22,9 @@ #include "nms-ifcfg-rh-writer.h" -#include <string.h> #include <sys/types.h> #include <sys/socket.h> #include <arpa/inet.h> -#include <errno.h> #include <stdlib.h> #include <sys/stat.h> #include <unistd.h> @@ -603,6 +601,10 @@ write_wireless_security_setting (NMConnection *connection, svSetValueStr (ifcfg, "KEY_MGMT", "WPA-PSK"); wpa = TRUE; *no_8021x = TRUE; + } else if (!strcmp (key_mgmt, "sae")) { + svSetValueStr (ifcfg, "KEY_MGMT", "SAE"); + wpa = TRUE; + *no_8021x = TRUE; } else if (!strcmp (key_mgmt, "ieee8021x")) { svSetValueStr (ifcfg, "KEY_MGMT", "IEEE8021X"); dynamic_wep = TRUE; diff --git a/src/settings/plugins/ifcfg-rh/shvar.c b/src/settings/plugins/ifcfg-rh/shvar.c index 3259d936..f3d58e26 100644 --- a/src/settings/plugins/ifcfg-rh/shvar.c +++ b/src/settings/plugins/ifcfg-rh/shvar.c @@ -27,11 +27,9 @@ #include "shvar.h" -#include <errno.h> #include <fcntl.h> #include <stdio.h> #include <stdlib.h> -#include <string.h> #include <sys/types.h> #include <sys/stat.h> #include <unistd.h> @@ -215,9 +213,9 @@ _escape_ansic (const char *source) /*****************************************************************************/ -#define _char_req_escape(ch) NM_IN_SET (ch, '\"', '\\', '$', '`') -#define _char_req_escape_old(ch) NM_IN_SET (ch, '\"', '\\', '\'', '$', '`', '~') -#define _char_req_quotes(ch) NM_IN_SET (ch, ' ', '\'', '~', '\t', '|', '&', ';', '(', ')', '<', '>') +#define _char_req_escape(ch) NM_IN_SET (ch, '"', '\\', '$', '`') +#define _char_req_escape_old(ch) NM_IN_SET (ch, '"', '\\', '\'', '$', '`', '~') +#define _char_req_quotes(ch) NM_IN_SET (ch, ' ', '\'', '~', '\t', '|', '&', ';', '(', ')', '<', '>') const char * svEscape (const char *s, char **to_free) @@ -815,7 +813,7 @@ svOpenFileInternal (const char *name, gboolean create, GError **error) g_set_error (error, G_FILE_ERROR, g_file_error_from_errno (errsv), "Could not read file '%s': %s", - name, strerror (errsv)); + name, nm_strerror_native (errsv)); return NULL; } @@ -1317,34 +1315,32 @@ svWriteFile (shvarFile *s, int mode, GError **error) FILE *f; int tmpfd; CList *current; + int errsv; if (s->modified) { if (s->fd == -1) s->fd = open (s->fileName, O_WRONLY | O_CREAT | O_CLOEXEC, mode); if (s->fd == -1) { - int errsv = errno; - + errsv = errno; g_set_error (error, G_FILE_ERROR, g_file_error_from_errno (errsv), "Could not open file '%s' for writing: %s", - s->fileName, strerror (errsv)); + s->fileName, nm_strerror_native (errsv)); return FALSE; } if (ftruncate (s->fd, 0) < 0) { - int errsv = errno; - + errsv = errno; g_set_error (error, G_FILE_ERROR, g_file_error_from_errno (errsv), "Could not overwrite file '%s': %s", - s->fileName, strerror (errsv)); + s->fileName, nm_strerror_native (errsv)); return FALSE; } tmpfd = fcntl (s->fd, F_DUPFD_CLOEXEC, 0); if (tmpfd == -1) { - int errsv = errno; - + errsv = errno; g_set_error (error, G_FILE_ERROR, g_file_error_from_errno (errsv), "Internal error writing file '%s': %s", - s->fileName, strerror (errsv)); + s->fileName, nm_strerror_native (errsv)); return FALSE; } f = fdopen (tmpfd, "w"); diff --git a/src/settings/plugins/ifcfg-rh/tests/network-scripts/ifcfg-test-wifi-sae b/src/settings/plugins/ifcfg-rh/tests/network-scripts/ifcfg-test-wifi-sae new file mode 100644 index 00000000..68afbe97 --- /dev/null +++ b/src/settings/plugins/ifcfg-rh/tests/network-scripts/ifcfg-test-wifi-sae @@ -0,0 +1,5 @@ +TYPE=Wireless +DEVICE=wlan1 +ESSID=blahblah +MODE=Managed +KEY_MGMT=SAE diff --git a/src/settings/plugins/ifcfg-rh/tests/network-scripts/keys-test-wifi-sae b/src/settings/plugins/ifcfg-rh/tests/network-scripts/keys-test-wifi-sae new file mode 100644 index 00000000..5a9569ed --- /dev/null +++ b/src/settings/plugins/ifcfg-rh/tests/network-scripts/keys-test-wifi-sae @@ -0,0 +1 @@ +WPA_PSK="The king is dead." 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 d135ea43..b352fbfc 100644 --- a/src/settings/plugins/ifcfg-rh/tests/test-ifcfg-rh.c +++ b/src/settings/plugins/ifcfg-rh/tests/test-ifcfg-rh.c @@ -23,7 +23,6 @@ #include <stdio.h> #include <stdarg.h> #include <unistd.h> -#include <string.h> #include <linux/pkt_sched.h> #include <netinet/in.h> #include <arpa/inet.h> @@ -123,7 +122,7 @@ _assert_reread_same_FIXME (NMConnection *connection, NMConnection *reread) /* dummy path for an "expected" file, meaning: don't check for expected * written ifcfg file. */ -static const char const NO_EXPECTED[1]; +static const char NO_EXPECTED[1]; static void _assert_expected_content (NMConnection *connection, const char *filename, const char *expected) @@ -2967,6 +2966,45 @@ test_read_wifi_wpa_psk (void) } static void +test_read_wifi_sae (void) +{ + gs_unref_object NMConnection *connection = NULL; + NMSettingConnection *s_con; + NMSettingWireless *s_wireless; + NMSettingWirelessSecurity *s_wsec; + GBytes *ssid; + const char *expected_ssid = "blahblah"; + + connection = _connection_from_file (TEST_IFCFG_DIR"/ifcfg-test-wifi-sae", + NULL, TYPE_WIRELESS, NULL); + + s_con = nm_connection_get_setting_connection (connection); + g_assert (s_con); + g_assert_cmpstr (nm_setting_connection_get_id (s_con), ==, "System blahblah (test-wifi-sae)"); + + g_assert_cmpint (nm_setting_connection_get_timestamp (s_con), ==, 0); + g_assert (nm_setting_connection_get_autoconnect (s_con)); + + s_wireless = nm_connection_get_setting_wireless (connection); + g_assert (s_wireless); + + g_assert_cmpint (nm_setting_wireless_get_mtu (s_wireless), ==, 0); + + ssid = nm_setting_wireless_get_ssid (s_wireless); + g_assert (ssid); + g_assert_cmpmem (g_bytes_get_data (ssid, NULL), g_bytes_get_size (ssid), expected_ssid, strlen (expected_ssid)); + + g_assert (!nm_setting_wireless_get_bssid (s_wireless)); + g_assert_cmpstr (nm_setting_wireless_get_mode (s_wireless), ==, "infrastructure"); + + s_wsec = nm_connection_get_setting_wireless_security (connection); + g_assert (s_wsec); + g_assert_cmpstr (nm_setting_wireless_security_get_key_mgmt (s_wsec), ==, "sae"); + g_assert_cmpstr (nm_setting_wireless_security_get_psk (s_wsec), ==, "The king is dead."); + g_assert (!nm_setting_wireless_security_get_auth_alg (s_wsec)); +} + +static void test_read_wifi_wpa_psk_2 (void) { NMConnection *connection; @@ -9981,10 +10019,14 @@ NMTST_DEFINE (); int main (int argc, char **argv) { + int errsv; + nmtst_init_assert_logging (&argc, &argv, "INFO", "DEFAULT"); - if (g_mkdir_with_parents (TEST_SCRATCH_DIR_TMP, 0755) != 0) - g_error ("failure to create test directory \"%s\": %s", TEST_SCRATCH_DIR_TMP, g_strerror (errno)); + if (g_mkdir_with_parents (TEST_SCRATCH_DIR_TMP, 0755) != 0) { + errsv = errno; + g_error ("failure to create test directory \"%s\": %s", TEST_SCRATCH_DIR_TMP, nm_strerror_native (errsv)); + } g_test_add_func (TPATH "svUnescape", test_svUnescape); @@ -10081,6 +10123,7 @@ int main (int argc, char **argv) g_test_add_func (TPATH "wifi/read/wpa-psk/unquoted2", test_read_wifi_wpa_psk_unquoted2); g_test_add_func (TPATH "wifi/read/wpa-psk/adhoc", test_read_wifi_wpa_psk_adhoc); g_test_add_func (TPATH "wifi/read/wpa-psk/hex", test_read_wifi_wpa_psk_hex); + g_test_add_func (TPATH "wifi/read/sae", test_read_wifi_sae); g_test_add_func (TPATH "wifi/read/dynamic-wep/leap", test_read_wifi_dynamic_wep_leap); g_test_add_func (TPATH "wifi/read/wpa/eap/tls", test_read_wifi_wpa_eap_tls); g_test_add_func (TPATH "wifi/read/wpa/eap/ttls/tls", test_read_wifi_wpa_eap_ttls_tls); diff --git a/src/settings/plugins/ifupdown/nms-ifupdown-connection.c b/src/settings/plugins/ifupdown/nms-ifupdown-connection.c index 1b817044..d06078a9 100644 --- a/src/settings/plugins/ifupdown/nms-ifupdown-connection.c +++ b/src/settings/plugins/ifupdown/nms-ifupdown-connection.c @@ -24,7 +24,6 @@ #include "nms-ifupdown-connection.h" -#include <string.h> #include <glib/gstdio.h> #include "nm-dbus-interface.h" diff --git a/src/settings/plugins/ifupdown/nms-ifupdown-interface-parser.c b/src/settings/plugins/ifupdown/nms-ifupdown-interface-parser.c index 73ecc2f9..6587fc84 100644 --- a/src/settings/plugins/ifupdown/nms-ifupdown-interface-parser.c +++ b/src/settings/plugins/ifupdown/nms-ifupdown-interface-parser.c @@ -26,7 +26,6 @@ #include <stdio.h> #include <stdlib.h> -#include <string.h> #include <wordexp.h> #include <libgen.h> diff --git a/src/settings/plugins/ifupdown/nms-ifupdown-parser.c b/src/settings/plugins/ifupdown/nms-ifupdown-parser.c index 369fa70d..fd5561ae 100644 --- a/src/settings/plugins/ifupdown/nms-ifupdown-parser.c +++ b/src/settings/plugins/ifupdown/nms-ifupdown-parser.c @@ -25,10 +25,8 @@ #include "nms-ifupdown-parser.h" -#include <string.h> #include <arpa/inet.h> #include <stdlib.h> -#include <errno.h> #include <ctype.h> #include "nm-core-internal.h" @@ -63,7 +61,7 @@ _ifupdownplugin_guess_connection_type (if_block *block) { const char *ret_type = NULL; - if(nm_streq0 (ifparser_getkey (block, "inet"), "ppp")) + if (nm_streq0 (ifparser_getkey (block, "inet"), "ppp")) ret_type = NM_SETTING_PPP_SETTING_NAME; else { if_data *ifb; @@ -75,7 +73,7 @@ _ifupdownplugin_guess_connection_type (if_block *block) break; } } - if(!ret_type) + if (!ret_type) ret_type = NM_SETTING_WIRED_SETTING_NAME; } diff --git a/src/settings/plugins/ifupdown/nms-ifupdown-plugin.c b/src/settings/plugins/ifupdown/nms-ifupdown-plugin.c index b66eedc7..99a59477 100644 --- a/src/settings/plugins/ifupdown/nms-ifupdown-plugin.c +++ b/src/settings/plugins/ifupdown/nms-ifupdown-plugin.c @@ -26,7 +26,6 @@ #include "nms-ifupdown-plugin.h" -#include <string.h> #include <arpa/inet.h> #include <gmodule.h> @@ -282,8 +281,10 @@ initialize (NMSettingsPlugin *plugin) g_hash_table_iter_init (&iter, priv->eni_ifaces); while (g_hash_table_iter_next (&iter, NULL, (gpointer *) conn)) { - _nm_settings_plugin_emit_signal_connection_added (NM_SETTINGS_PLUGIN (self), - NM_SETTINGS_CONNECTION (conn)); + if (conn) { + _nm_settings_plugin_emit_signal_connection_added (NM_SETTINGS_PLUGIN (self), + NM_SETTINGS_CONNECTION (conn)); + } } } } diff --git a/src/settings/plugins/ifupdown/tests/test-ifupdown.c b/src/settings/plugins/ifupdown/tests/test-ifupdown.c index 82ee1c4a..674cb19c 100644 --- a/src/settings/plugins/ifupdown/tests/test-ifupdown.c +++ b/src/settings/plugins/ifupdown/tests/test-ifupdown.c @@ -20,8 +20,6 @@ #include "nm-default.h" -#include <string.h> - #include "nm-core-internal.h" #include "settings/plugins/ifupdown/nms-ifupdown-interface-parser.h" diff --git a/src/settings/plugins/keyfile/nms-keyfile-connection.c b/src/settings/plugins/keyfile/nms-keyfile-connection.c index 7511f206..3b362978 100644 --- a/src/settings/plugins/keyfile/nms-keyfile-connection.c +++ b/src/settings/plugins/keyfile/nms-keyfile-connection.c @@ -23,7 +23,6 @@ #include "nms-keyfile-connection.h" -#include <string.h> #include <glib/gstdio.h> #include "nm-dbus-interface.h" diff --git a/src/settings/plugins/keyfile/nms-keyfile-plugin.c b/src/settings/plugins/keyfile/nms-keyfile-plugin.c index ae9bea13..c13cc1ff 100644 --- a/src/settings/plugins/keyfile/nms-keyfile-plugin.c +++ b/src/settings/plugins/keyfile/nms-keyfile-plugin.c @@ -26,8 +26,6 @@ #include <sys/stat.h> #include <unistd.h> #include <sys/types.h> -#include <string.h> - #include <glib/gstdio.h> #include "nm-connection.h" diff --git a/src/settings/plugins/keyfile/nms-keyfile-reader.c b/src/settings/plugins/keyfile/nms-keyfile-reader.c index 314b1033..5778f13c 100644 --- a/src/settings/plugins/keyfile/nms-keyfile-reader.c +++ b/src/settings/plugins/keyfile/nms-keyfile-reader.c @@ -23,7 +23,6 @@ #include "nms-keyfile-reader.h" #include <sys/stat.h> -#include <string.h> #include "nm-keyfile-internal.h" diff --git a/src/settings/plugins/keyfile/nms-keyfile-utils.c b/src/settings/plugins/keyfile/nms-keyfile-utils.c index 8d4ec943..3c4b0288 100644 --- a/src/settings/plugins/keyfile/nms-keyfile-utils.c +++ b/src/settings/plugins/keyfile/nms-keyfile-utils.c @@ -23,7 +23,6 @@ #include "nms-keyfile-utils.h" #include <stdlib.h> -#include <string.h> #include <sys/stat.h> #include "nm-keyfile-internal.h" @@ -277,14 +276,14 @@ nms_keyfile_utils_check_file_permissions (NMSKeyfileFiletype filetype, if (stat (filename, &st) != 0) { errsv = errno; g_set_error (error, NM_SETTINGS_ERROR, NM_SETTINGS_ERROR_INVALID_CONNECTION, - "cannot access file: %s", g_strerror (errsv)); + "cannot access file: %s", nm_strerror_native (errsv)); return FALSE; } } else if (filetype == NMS_KEYFILE_FILETYPE_NMLOADED) { if (lstat (filename, &st) != 0) { errsv = errno; g_set_error (error, NM_SETTINGS_ERROR, NM_SETTINGS_ERROR_INVALID_CONNECTION, - "cannot access file: %s", g_strerror (errsv)); + "cannot access file: %s", nm_strerror_native (errsv)); return FALSE; } } else diff --git a/src/settings/plugins/keyfile/nms-keyfile-writer.c b/src/settings/plugins/keyfile/nms-keyfile-writer.c index 23a6a77c..8c75d8c7 100644 --- a/src/settings/plugins/keyfile/nms-keyfile-writer.c +++ b/src/settings/plugins/keyfile/nms-keyfile-writer.c @@ -26,8 +26,6 @@ #include <stdlib.h> #include <sys/stat.h> #include <unistd.h> -#include <errno.h> -#include <string.h> #include "nm-keyfile-internal.h" @@ -177,27 +175,30 @@ _internal_write_connection (NMConnection *connection, uid_t owner_uid, pid_t owner_grp, const char *existing_path, + gboolean existing_path_read_only, gboolean force_rename, char **out_path, NMConnection **out_reread, gboolean *out_reread_same, GError **error) { - gs_unref_keyfile GKeyFile *key_file = NULL; - gs_free char *data = NULL; - gsize len; + gs_unref_keyfile GKeyFile *kf_file = NULL; + gs_free char *kf_content_buf = NULL; + gsize kf_content_len; gs_free char *path = NULL; const char *id; WriteInfo info = { 0 }; GError *local_err = NULL; int errsv; - gboolean rename = force_rename; + gboolean rename; g_return_val_if_fail (!out_path || !*out_path, FALSE); g_return_val_if_fail (keyfile_dir && keyfile_dir[0] == '/', FALSE); - if (existing_path && !g_str_has_prefix (existing_path, keyfile_dir)) - rename = TRUE; + rename = force_rename + || existing_path_read_only + || ( existing_path + && !nm_utils_file_is_in_path (existing_path, keyfile_dir)); switch (_nm_connection_verify (connection, error)) { case NM_SETTING_VERIFY_NORMALIZABLE: @@ -214,11 +215,11 @@ _internal_write_connection (NMConnection *connection, info.keyfile_dir = keyfile_dir; - key_file = nm_keyfile_write (connection, _handler_write, &info, error); - if (!key_file) + kf_file = nm_keyfile_write (connection, _handler_write, &info, error); + if (!kf_file) return FALSE; - data = g_key_file_to_data (key_file, &len, error); - if (!data) + kf_content_buf = g_key_file_to_data (kf_file, &kf_content_len, error); + if (!kf_content_buf) return FALSE; if (!g_file_test (keyfile_dir, G_FILE_TEST_IS_DIR)) @@ -227,13 +228,14 @@ _internal_write_connection (NMConnection *connection, /* If we have existing file path, use it. Else generate one from * connection's ID. */ - if (existing_path != NULL && !rename) { + if ( existing_path + && !rename) path = g_strdup (existing_path); - } else { - char *filename_escaped = nm_keyfile_utils_create_filename (id, with_extension); + else { + gs_free char *filename_escaped = NULL; + filename_escaped = nm_keyfile_utils_create_filename (id, with_extension); path = g_build_filename (keyfile_dir, filename_escaped, NULL); - g_free (filename_escaped); } /* If a file with this path already exists (but isn't the existing path @@ -243,13 +245,15 @@ _internal_write_connection (NMConnection *connection, * there's a race here, but there's not a lot we can do about it, and * we shouldn't get more than one connection with the same UUID either. */ - if (g_strcmp0 (path, existing_path) != 0 && g_file_test (path, G_FILE_TEST_EXISTS)) { + if ( !nm_streq0 (path, existing_path) + && g_file_test (path, G_FILE_TEST_EXISTS)) { guint i; gboolean name_found = FALSE; /* A keyfile with this connection's ID already exists. Pick another name. */ for (i = 0; i < 100; i++) { - char *filename, *filename_escaped; + gs_free char *filename_escaped = NULL; + gs_free char *filename = NULL; if (i == 0) filename = g_strdup_printf ("%s-%s", id, nm_connection_get_uuid (connection)); @@ -260,15 +264,15 @@ _internal_write_connection (NMConnection *connection, g_free (path); path = g_strdup_printf ("%s/%s", keyfile_dir, filename_escaped); - g_free (filename); - g_free (filename_escaped); - if (g_strcmp0 (path, existing_path) == 0 || !g_file_test (path, G_FILE_TEST_EXISTS)) { + + if ( nm_streq0 (path, existing_path) + || !g_file_test (path, G_FILE_TEST_EXISTS)) { name_found = TRUE; break; } } if (!name_found) { - if (existing_path == NULL) { + if (existing_path_read_only || !existing_path) { /* this really should not happen, we tried hard to find an unused name... bail out. */ g_set_error (error, NM_SETTINGS_ERROR, NM_SETTINGS_ERROR_FAILED, "could not find suitable keyfile file name (%s already used)", path); @@ -281,13 +285,7 @@ _internal_write_connection (NMConnection *connection, } } - /* In case of updating the connection and changing the file path, - * we need to remove the old one, not to end up with two connections. - */ - if (existing_path != NULL && strcmp (path, existing_path) != 0) - unlink (existing_path); - - nm_utils_file_set_contents (path, data, len, 0600, &local_err); + nm_utils_file_set_contents (path, kf_content_buf, kf_content_len, 0600, &local_err); if (local_err) { g_set_error (error, NM_SETTINGS_ERROR, NM_SETTINGS_ERROR_FAILED, "error writing to file '%s': %s", @@ -300,17 +298,24 @@ _internal_write_connection (NMConnection *connection, errsv = errno; g_set_error (error, NM_SETTINGS_ERROR, NM_SETTINGS_ERROR_FAILED, "error chowning '%s': %s (%d)", - path, g_strerror (errsv), errsv); + path, nm_strerror_native (errsv), errsv); unlink (path); return FALSE; } - if (out_reread || out_reread_same) - { + /* In case of updating the connection and changing the file path, + * we need to remove the old one, not to end up with two connections. + */ + if ( existing_path + && !existing_path_read_only + && !nm_streq (path, existing_path)) + unlink (existing_path); + + if (out_reread || out_reread_same) { gs_unref_object NMConnection *reread = NULL; gboolean reread_same = FALSE; - reread = nms_keyfile_reader_from_keyfile (key_file, path, NULL, profile_dir, FALSE, NULL); + reread = nms_keyfile_reader_from_keyfile (kf_file, path, NULL, profile_dir, FALSE, NULL); nm_assert (NM_IS_CONNECTION (reread)); @@ -365,6 +370,7 @@ nms_keyfile_writer_connection (NMConnection *connection, 0, 0, existing_path, + FALSE, force_rename, out_path, out_reread, @@ -390,6 +396,7 @@ nms_keyfile_writer_test_connection (NMConnection *connection, owner_grp, NULL, FALSE, + FALSE, out_path, out_reread, out_reread_same, diff --git a/src/settings/plugins/keyfile/tests/meson.build b/src/settings/plugins/keyfile/tests/meson.build index 4253fe3c..752b6d7b 100644 --- a/src/settings/plugins/keyfile/tests/meson.build +++ b/src/settings/plugins/keyfile/tests/meson.build @@ -12,4 +12,5 @@ test( 'keyfile/' + test_unit, test_script, args: test_args + [exe.full_path()], + timeout: default_test_timeout, ) diff --git a/src/settings/plugins/keyfile/tests/test-keyfile.c b/src/settings/plugins/keyfile/tests/test-keyfile.c index cdc9bfb0..baecac13 100644 --- a/src/settings/plugins/keyfile/tests/test-keyfile.c +++ b/src/settings/plugins/keyfile/tests/test-keyfile.c @@ -23,7 +23,6 @@ #include <stdio.h> #include <stdarg.h> #include <unistd.h> -#include <string.h> #include <netinet/in.h> #include <arpa/inet.h> #include <sys/socket.h> @@ -2615,11 +2614,16 @@ NMTST_DEFINE (); int main (int argc, char **argv) { + int errsv; + _nm_utils_set_testing (NM_UTILS_TEST_NO_KEYFILE_OWNER_CHECK); + nmtst_init_assert_logging (&argc, &argv, "INFO", "DEFAULT"); - if (g_mkdir_with_parents (TEST_SCRATCH_DIR, 0755) != 0) - g_error ("failure to create test directory \"%s\": %s", TEST_SCRATCH_DIR, g_strerror (errno)); + if (g_mkdir_with_parents (TEST_SCRATCH_DIR, 0755) != 0) { + errsv = errno; + g_error ("failure to create test directory \"%s\": %s", TEST_SCRATCH_DIR, nm_strerror_native (errsv)); + } /* The tests */ g_test_add_func ("/keyfile/test_read_valid_wired_connection", test_read_valid_wired_connection); diff --git a/src/supplicant/nm-supplicant-config.c b/src/supplicant/nm-supplicant-config.c index 4acb634e..7708224b 100644 --- a/src/supplicant/nm-supplicant-config.c +++ b/src/supplicant/nm-supplicant-config.c @@ -23,7 +23,6 @@ #include "nm-supplicant-config.h" -#include <string.h> #include <stdlib.h> #include "nm-core-internal.h" @@ -404,11 +403,11 @@ nm_supplicant_config_add_setting_macsec (NMSupplicantConfig * self, value = nm_setting_macsec_get_mka_cak (setting); if ( !value - || !_nm_utils_hexstr2bin_buf (value, - FALSE, - FALSE, - NULL, - buffer_cak)) { + || !nm_utils_hexstr2bin_buf (value, + FALSE, + FALSE, + NULL, + buffer_cak)) { g_set_error_literal (error, NM_SUPPLICANT_ERROR, NM_SUPPLICANT_ERROR_CONFIG, @@ -425,11 +424,11 @@ nm_supplicant_config_add_setting_macsec (NMSupplicantConfig * self, value = nm_setting_macsec_get_mka_ckn (setting); if ( !value - || !_nm_utils_hexstr2bin_buf (value, - FALSE, - FALSE, - NULL, - buffer_ckn)) { + || !nm_utils_hexstr2bin_buf (value, + FALSE, + FALSE, + NULL, + buffer_ckn)) { g_set_error_literal (error, NM_SUPPLICANT_ERROR, NM_SUPPLICANT_ERROR_CONFIG, @@ -705,14 +704,14 @@ add_wep_key (NMSupplicantConfig *self, if ((key_len == 10) || (key_len == 26)) { guint8 buffer[26/2]; - if (!_nm_utils_hexstr2bin_full (key, - FALSE, - FALSE, - NULL, - key_len / 2, - buffer, - sizeof (buffer), - NULL)) { + if (!nm_utils_hexstr2bin_full (key, + FALSE, + FALSE, + NULL, + key_len / 2, + buffer, + sizeof (buffer), + NULL)) { g_set_error (error, NM_SUPPLICANT_ERROR, NM_SUPPLICANT_ERROR_CONFIG, "cannot add wep-key %s to suplicant config because key is not hex", name); @@ -807,15 +806,30 @@ nm_supplicant_config_add_setting_wireless_security (NMSupplicantConfig *self, if (psk) { size_t psk_len = strlen (psk); - if (psk_len == 64) { + + if (psk_len >= 8 && psk_len <= 63) { + /* Use TYPE_STRING here so that it gets pushed to the + * supplicant as a string, and therefore gets quoted, + * and therefore the supplicant will interpret it as a + * passphrase and not a hex key. + */ + if (!nm_supplicant_config_add_option_with_type (self, "psk", psk, -1, TYPE_STRING, "<hidden>", error)) + return FALSE; + } else if (nm_streq (key_mgmt, "sae")) { + /* If the SAE password doesn't comply with WPA-PSK limitation, + * we need to call it "sae_password" instead of "psk". + */ + if (!nm_supplicant_config_add_option_with_type (self, "sae_password", psk, -1, TYPE_STRING, "<hidden>", error)) + return FALSE; + } else if (psk_len == 64) { guint8 buffer[32]; /* Hex PSK */ - if (!_nm_utils_hexstr2bin_buf (psk, - FALSE, - FALSE, - NULL, - buffer)) { + if (!nm_utils_hexstr2bin_buf (psk, + FALSE, + FALSE, + NULL, + buffer)) { g_set_error (error, NM_SUPPLICANT_ERROR, NM_SUPPLICANT_ERROR_CONFIG, "Cannot add psk to supplicant config due to invalid hex"); return FALSE; @@ -827,14 +841,6 @@ nm_supplicant_config_add_setting_wireless_security (NMSupplicantConfig *self, "<hidden>", error)) return FALSE; - } else if (psk_len >= 8 && psk_len <= 63) { - /* Use TYPE_STRING here so that it gets pushed to the - * supplicant as a string, and therefore gets quoted, - * and therefore the supplicant will interpret it as a - * passphrase and not a hex key. - */ - if (!nm_supplicant_config_add_option_with_type (self, "psk", psk, -1, TYPE_STRING, "<hidden>", error)) - return FALSE; } else { g_set_error (error, NM_SUPPLICANT_ERROR, NM_SUPPLICANT_ERROR_CONFIG, "Cannot add psk to supplicant config due to invalid PSK length %u (not between 8 and 63 characters)", @@ -861,7 +867,8 @@ nm_supplicant_config_add_setting_wireless_security (NMSupplicantConfig *self, /* Only WPA-specific things when using WPA */ if ( !strcmp (key_mgmt, "wpa-none") || !strcmp (key_mgmt, "wpa-psk") - || !strcmp (key_mgmt, "wpa-eap")) { + || !strcmp (key_mgmt, "wpa-eap") + || !strcmp (key_mgmt, "sae")) { if (!ADD_STRING_LIST_VAL (self, setting, wireless_security, proto, protos, "proto", ' ', TRUE, NULL, error)) return FALSE; if (!ADD_STRING_LIST_VAL (self, setting, wireless_security, pairwise, pairwise, "pairwise", ' ', TRUE, NULL, error)) diff --git a/src/supplicant/nm-supplicant-interface.c b/src/supplicant/nm-supplicant-interface.c index c30adc58..f46689eb 100644 --- a/src/supplicant/nm-supplicant-interface.c +++ b/src/supplicant/nm-supplicant-interface.c @@ -25,7 +25,6 @@ #include "nm-supplicant-manager.h" #include <stdio.h> -#include <string.h> #include "NetworkManagerUtils.h" #include "nm-supplicant-config.h" @@ -729,9 +728,8 @@ iface_set_pmf_cb (GDBusProxy *proxy, GAsyncResult *result, gpointer user_data) self = NM_SUPPLICANT_INTERFACE (user_data); - /* This can fail if the supplicant doesn't support PMF */ if (error) - _LOGD ("failed to set Pmf=1: %s", error->message); + _LOGW ("failed to set Pmf=1: %s", error->message); iface_check_ready (self); } @@ -1452,7 +1450,7 @@ p2p_props_changed_cb (GDBusProxy *proxy, /* We already have the proxy, nothing to do. */ } else if (path && g_strcmp0 (path, "/") != 0) { if (priv->group_proxy != NULL) { - _LOGW ("P2P: Unexpected udpate of the group object path"); + _LOGW ("P2P: Unexpected update of the group object path"); priv->group_proxy_acquired = FALSE; _notify (self, PROP_P2P_GROUP_JOINED); _notify (self, PROP_P2P_GROUP_PATH); @@ -1548,7 +1546,7 @@ p2p_group_started (GDBusProxy *proxy, } } - /* Signal existance of the (new) interface. */ + /* Signal existence of the (new) interface. */ g_signal_emit (self, signals[GROUP_STARTED], 0, iface); g_object_unref (iface); } @@ -1639,21 +1637,9 @@ on_iface_proxy_acquired (GDBusProxy *proxy, GAsyncResult *result, gpointer user_ NULL, NULL); - /* Initialize global PMF setting to 'optional' */ - priv->ready_count++; - g_dbus_proxy_call (priv->iface_proxy, - DBUS_INTERFACE_PROPERTIES ".Set", - g_variant_new ("(ssv)", - WPAS_DBUS_IFACE_INTERFACE, - "Pmf", - g_variant_new_string ("1")), - G_DBUS_CALL_FLAGS_NONE, - -1, - priv->init_cancellable, - (GAsyncReadyCallback) iface_set_pmf_cb, - self); - - /* Check whether NetworkReply and AP mode are supported */ + /* Check whether NetworkReply and AP mode are supported. + * ready_count was initialized to 1 in interface_add_done(). + */ g_dbus_proxy_call (priv->iface_proxy, "NetworkReply", g_variant_new ("(oss)", @@ -1666,6 +1652,22 @@ on_iface_proxy_acquired (GDBusProxy *proxy, GAsyncResult *result, gpointer user_ (GAsyncReadyCallback) iface_check_netreply_cb, self); + if (priv->pmf_support == NM_SUPPLICANT_FEATURE_YES) { + /* Initialize global PMF setting to 'optional' */ + priv->ready_count++; + g_dbus_proxy_call (priv->iface_proxy, + DBUS_INTERFACE_PROPERTIES ".Set", + g_variant_new ("(ssv)", + WPAS_DBUS_IFACE_INTERFACE, + "Pmf", + g_variant_new_string ("1")), + G_DBUS_CALL_FLAGS_NONE, + -1, + priv->init_cancellable, + (GAsyncReadyCallback) iface_set_pmf_cb, + self); + } + if (priv->ap_support == NM_SUPPLICANT_FEATURE_UNKNOWN) { /* If the global supplicant capabilities property is not present, we can * fall back to checking whether the ProbeRequest method is supported. If @@ -2482,7 +2484,6 @@ nm_supplicant_interface_p2p_start_find (NMSupplicantInterface *self, priv = NM_SUPPLICANT_INTERFACE_GET_PRIVATE (self); - /* Find parameters */ g_variant_builder_init (&builder, G_VARIANT_TYPE_VARDICT); g_variant_builder_add (&builder, "{sv}", "Timeout", g_variant_new_int32 (timeout)); diff --git a/src/supplicant/nm-supplicant-manager.c b/src/supplicant/nm-supplicant-manager.c index 64a057f3..104aeee7 100644 --- a/src/supplicant/nm-supplicant-manager.c +++ b/src/supplicant/nm-supplicant-manager.c @@ -23,8 +23,6 @@ #include "nm-supplicant-manager.h" -#include <string.h> - #include "nm-supplicant-interface.h" #include "nm-supplicant-types.h" #include "nm-core-internal.h" @@ -71,7 +69,7 @@ NM_CACHED_QUARK_FCN ("nm-supplicant-error-quark", nm_supplicant_error_quark) /*****************************************************************************/ -static inline gboolean +static gboolean die_count_exceeded (guint32 count) { return count > 2; @@ -125,6 +123,72 @@ _sup_iface_last_ref (gpointer data, g_object_remove_toggle_ref ((GObject *) sup_iface, _sup_iface_last_ref, self); } +static void +on_supplicant_wfd_ies_set (GObject *source_object, + GAsyncResult *res, + gpointer user_data) +{ + gs_unref_variant GVariant *result = NULL; + gs_free_error GError *error = NULL; + + result = g_dbus_connection_call_finish (G_DBUS_CONNECTION (source_object), res, &error); + + if (!result) + _LOGW ("failed to set WFD IEs on wpa_supplicant: %s", error->message); +} + +/** + * nm_supplicant_manager_set_wfd_ies: + * @self: the #NMSupplicantManager + * @wfd_ies: a #GBytes with the WFD IEs or %NULL + * + * This function sets the global WFD IEs on wpa_supplicant. Note that + * it would make more sense if this was per-device, but wpa_supplicant + * simply does not work that way. + * */ +void +nm_supplicant_manager_set_wfd_ies (NMSupplicantManager *self, + GBytes *wfd_ies) +{ + NMSupplicantManagerPrivate *priv; + GVariantBuilder params; + GVariant *val; + + g_return_if_fail (NM_IS_SUPPLICANT_MANAGER (self)); + + priv = NM_SUPPLICANT_MANAGER_GET_PRIVATE (self); + + _LOGD ("setting WFD IEs for P2P operation"); + + if (wfd_ies) + val = g_variant_new_fixed_array (G_VARIANT_TYPE_BYTE, + g_bytes_get_data (wfd_ies, NULL), + g_bytes_get_size (wfd_ies), + sizeof (guint8)); + else + val = g_variant_new_fixed_array (G_VARIANT_TYPE_BYTE, + NULL, 0, sizeof (guint8)); + + g_variant_builder_init (¶ms, G_VARIANT_TYPE ("(ssv)")); + + g_variant_builder_add (¶ms, "s", g_dbus_proxy_get_interface_name (priv->proxy)); + g_variant_builder_add (¶ms, "s", "WFDIEs"); + g_variant_builder_add_value (¶ms, g_variant_new_variant (val)); + + g_dbus_connection_call (g_dbus_proxy_get_connection (priv->proxy), + g_dbus_proxy_get_name (priv->proxy), + g_dbus_proxy_get_object_path (priv->proxy), + "org.freedesktop.DBus.Properties", + "Set", + g_variant_builder_end (¶ms), + G_VARIANT_TYPE_UNIT, + G_DBUS_CALL_FLAGS_NO_AUTO_START, + 1000, + NULL, + on_supplicant_wfd_ies_set, + NULL); +} + /** * nm_supplicant_manager_create_interface: * @self: the #NMSupplicantManager diff --git a/src/supplicant/nm-supplicant-manager.h b/src/supplicant/nm-supplicant-manager.h index 7225a36b..058745fb 100644 --- a/src/supplicant/nm-supplicant-manager.h +++ b/src/supplicant/nm-supplicant-manager.h @@ -38,6 +38,9 @@ GType nm_supplicant_manager_get_type (void); NMSupplicantManager *nm_supplicant_manager_get (void); +void nm_supplicant_manager_set_wfd_ies (NMSupplicantManager *self, + GBytes *wfd_ies); + NMSupplicantInterface *nm_supplicant_manager_create_interface (NMSupplicantManager *mgr, const char *ifname, NMSupplicantDriver driver); diff --git a/src/supplicant/nm-supplicant-settings-verify.c b/src/supplicant/nm-supplicant-settings-verify.c index 1e25675d..f10bbb04 100644 --- a/src/supplicant/nm-supplicant-settings-verify.c +++ b/src/supplicant/nm-supplicant-settings-verify.c @@ -24,8 +24,6 @@ #include <stdio.h> #include <stdlib.h> -#include <string.h> -#include <errno.h> struct Opt { const char * key; @@ -72,7 +70,7 @@ const char * proto_allowed[] = { "WPA", "RSN", NULL }; const char * key_mgmt_allowed[] = { "WPA-PSK", "WPA-PSK-SHA256", "WPA-EAP", "WPA-EAP-SHA256", "FILS-SHA256", "FILS-SHA384", - "IEEE8021X", "WPA-NONE", + "IEEE8021X", "WPA-NONE", "SAE", "NONE", NULL }; const char * auth_alg_allowed[] = { "OPEN", "SHARED", "LEAP", NULL }; const char * eap_allowed[] = { "LEAP", "MD5", "TLS", "PEAP", "TTLS", "SIM", @@ -159,23 +157,13 @@ validate_type_int (const struct Opt * opt, const char * value, const guint32 len) { - long int intval; + gint64 v; g_return_val_if_fail (opt != NULL, FALSE); g_return_val_if_fail (value != NULL, FALSE); - errno = 0; - intval = strtol (value, NULL, 10); - if (errno != 0) - return FALSE; - - /* strtol returns a long, but we are dealing with ints */ - if (intval > INT_MAX || intval < INT_MIN) - return FALSE; - if (intval > opt->int_high || intval < opt->int_low) - return FALSE; - - return TRUE; + v = _nm_utils_ascii_str_to_int64 (value, 10, opt->int_low, opt->int_high, G_MININT64); + return v != G_MININT64 || errno == 0; } static gboolean diff --git a/src/supplicant/tests/meson.build b/src/supplicant/tests/meson.build index 7cc9d6af..fbccb313 100644 --- a/src/supplicant/tests/meson.build +++ b/src/supplicant/tests/meson.build @@ -10,4 +10,5 @@ test( 'supplicant/' + test_unit, test_script, args: test_args + [exe.full_path()], + timeout: default_test_timeout, ) diff --git a/src/supplicant/tests/test-supplicant-config.c b/src/supplicant/tests/test-supplicant-config.c index d7ec1fe2..2c7a71a3 100644 --- a/src/supplicant/tests/test-supplicant-config.c +++ b/src/supplicant/tests/test-supplicant-config.c @@ -23,7 +23,6 @@ #include <stdio.h> #include <stdarg.h> #include <unistd.h> -#include <string.h> #include <netinet/in.h> #include <arpa/inet.h> #include <sys/socket.h> @@ -389,6 +388,76 @@ test_wifi_wpa_psk (const char *detail, } static void +test_wifi_sae_psk (const char *psk) +{ + gs_unref_object NMConnection *connection = NULL; + gs_unref_variant GVariant *config_dict = NULL; + NMSettingWirelessSecurity *s_wsec; + gboolean success; + GError *error = NULL; + const unsigned char ssid_data[] = { 0x54, 0x65, 0x73, 0x74, 0x20, 0x53, 0x53, 0x49, 0x44 }; + gs_unref_bytes GBytes *ssid = g_bytes_new (ssid_data, sizeof (ssid_data)); + const char *bssid_str = "11:22:33:44:55:66"; + int short_psk = strlen (psk) < 8; + + connection = new_basic_connection ("Test Wifi SAE", ssid, bssid_str); + + /* Wifi Security setting */ + s_wsec = (NMSettingWirelessSecurity *) nm_setting_wireless_security_new (); + nm_connection_add_setting (connection, NM_SETTING (s_wsec)); + g_object_set (s_wsec, + NM_SETTING_WIRELESS_SECURITY_KEY_MGMT, "sae", + NM_SETTING_WIRELESS_SECURITY_PSK, psk, + NULL); + nm_setting_wireless_security_add_proto (s_wsec, "rsn"); + nm_setting_wireless_security_add_pairwise (s_wsec, "tkip"); + nm_setting_wireless_security_add_pairwise (s_wsec, "ccmp"); + nm_setting_wireless_security_add_group (s_wsec, "tkip"); + nm_setting_wireless_security_add_group (s_wsec, "ccmp"); + + success = nm_connection_verify (connection, &error); + g_assert_no_error (error); + g_assert (success); + + NMTST_EXPECT_NM_INFO ("Config: added 'ssid' value 'Test SSID'*"); + NMTST_EXPECT_NM_INFO ("Config: added 'scan_ssid' value '1'*"); + NMTST_EXPECT_NM_INFO ("Config: added 'bssid' value '11:22:33:44:55:66'*"); + NMTST_EXPECT_NM_INFO ("Config: added 'freq_list' value *"); + NMTST_EXPECT_NM_INFO ("Config: added 'key_mgmt' value 'SAE'"); + if (short_psk) + NMTST_EXPECT_NM_INFO ("Config: added 'sae_password' value *"); + else + NMTST_EXPECT_NM_INFO ("Config: added 'psk' value *"); + NMTST_EXPECT_NM_INFO ("Config: added 'proto' value 'RSN'"); + NMTST_EXPECT_NM_INFO ("Config: added 'pairwise' value 'TKIP CCMP'"); + NMTST_EXPECT_NM_INFO ("Config: added 'group' value 'TKIP CCMP'"); + NMTST_EXPECT_NM_INFO ("Config: added 'ieee80211w' value '0'"); + config_dict = build_supplicant_config (connection, 1500, 0, TRUE, TRUE); + + g_test_assert_expected_messages (); + g_assert (config_dict); + + validate_opt ("wifi-sae", config_dict, "scan_ssid", TYPE_INT, GINT_TO_POINTER (1)); + validate_opt ("wifi-sae", config_dict, "ssid", TYPE_BYTES, ssid); + validate_opt ("wifi-sae", config_dict, "bssid", TYPE_KEYWORD, bssid_str); + validate_opt ("wifi-sae", config_dict, "key_mgmt", TYPE_KEYWORD, "SAE"); + validate_opt ("wifi-sae", config_dict, "proto", TYPE_KEYWORD, "RSN"); + validate_opt ("wifi-sae", config_dict, "pairwise", TYPE_KEYWORD, "TKIP CCMP"); + validate_opt ("wifi-sae", config_dict, "group", TYPE_KEYWORD, "TKIP CCMP"); + if (short_psk) + validate_opt ("wifi-sae", config_dict, "sae_password", TYPE_KEYWORD, psk); + else + validate_opt ("wifi-sae", config_dict, "psk", TYPE_KEYWORD, psk); +} + +static void +test_wifi_sae (void) +{ + test_wifi_sae_psk ("Moo"); + test_wifi_sae_psk ("Hello World!"); +} + +static void test_wifi_wpa_psk_types (void) { const char *key1 = "d4721e911461d3cdef9793858e977fcda091779243abb7316c2f11605a160893"; @@ -580,6 +649,7 @@ int main (int argc, char **argv) g_test_add_func ("/supplicant-config/wifi-eap/locked-bssid", test_wifi_eap_locked_bssid); g_test_add_func ("/supplicant-config/wifi-eap/unlocked-bssid", test_wifi_eap_unlocked_bssid); g_test_add_func ("/supplicant-config/wifi-eap/fils-disabled", test_wifi_eap_fils_disabled); + g_test_add_func ("/supplicant-config/wifi-sae", test_wifi_sae); return g_test_run (); } diff --git a/src/systemd/sd-adapt-core/device-util.h b/src/systemd/sd-adapt-core/device-util.h new file mode 100644 index 00000000..637892c2 --- /dev/null +++ b/src/systemd/sd-adapt-core/device-util.h @@ -0,0 +1,3 @@ +#pragma once + +/* dummy header */ diff --git a/src/systemd/src/libsystemd-network/dhcp-identifier.c b/src/systemd/src/libsystemd-network/dhcp-identifier.c index 91f5e1b0..7fc8248a 100644 --- a/src/systemd/src/libsystemd-network/dhcp-identifier.c +++ b/src/systemd/src/libsystemd-network/dhcp-identifier.c @@ -13,6 +13,7 @@ #include "network-internal.h" #include "siphash24.h" #include "sparse-endian.h" +#include "stdio-util.h" #include "virt.h" #define SYSTEMD_PEN 43793 @@ -176,10 +177,10 @@ int dhcp_identifier_set_iaid( if (detect_container() <= 0) { /* not in a container, udev will be around */ - char ifindex_str[2 + DECIMAL_STR_MAX(int)]; + char ifindex_str[1 + DECIMAL_STR_MAX(int)]; int r; - sprintf(ifindex_str, "n%d", ifindex); + xsprintf(ifindex_str, "n%d", ifindex); if (sd_device_new_from_device_id(&device, ifindex_str) >= 0) { r = sd_device_get_is_initialized(device); if (r < 0) @@ -202,7 +203,7 @@ int dhcp_identifier_set_iaid( if (legacy_unstable_byteorder) /* for historical reasons (a bug), the bits were swapped and thus - * the result was endianness dependant. Preserve that behavior. */ + * the result was endianness dependent. Preserve that behavior. */ id32 = __bswap_32(id32); else /* the fixed behavior returns a stable byte order. Since LE is expected diff --git a/src/systemd/src/libsystemd-network/dhcp-lease-internal.h b/src/systemd/src/libsystemd-network/dhcp-lease-internal.h index 9d245a90..122042ab 100644 --- a/src/systemd/src/libsystemd-network/dhcp-lease-internal.h +++ b/src/systemd/src/libsystemd-network/dhcp-lease-internal.h @@ -41,7 +41,6 @@ struct sd_dhcp_lease { /* each 0 if unset */ be32_t address; be32_t server_address; - be32_t router; be32_t next_server; bool have_subnet_mask; @@ -50,6 +49,9 @@ struct sd_dhcp_lease { bool have_broadcast; be32_t broadcast; + struct in_addr *router; + size_t router_size; + struct in_addr *dns; size_t dns_size; diff --git a/src/systemd/src/libsystemd-network/dhcp-network.c b/src/systemd/src/libsystemd-network/dhcp-network.c index ba596908..810a2633 100644 --- a/src/systemd/src/libsystemd-network/dhcp-network.c +++ b/src/systemd/src/libsystemd-network/dhcp-network.c @@ -5,7 +5,6 @@ #include "nm-sd-adapt-core.h" -#include <errno.h> #include <net/ethernet.h> #include <net/if.h> #include <net/if_arp.h> @@ -52,12 +51,16 @@ static int _bind_raw_socket(int ifindex, union sockaddr_union *link, BPF_STMT(BPF_LD + BPF_B + BPF_ABS, offsetof(DHCPPacket, dhcp.htype)), /* A <- DHCP header type */ BPF_JUMP(BPF_JMP + BPF_JEQ + BPF_K, arp_type, 1, 0), /* header type == arp_type ? */ BPF_STMT(BPF_RET + BPF_K, 0), /* ignore */ - BPF_STMT(BPF_LD + BPF_B + BPF_ABS, offsetof(DHCPPacket, dhcp.hlen)), /* A <- MAC address length */ - BPF_JUMP(BPF_JMP + BPF_JEQ + BPF_K, dhcp_hlen, 1, 0), /* address length == dhcp_hlen ? */ - BPF_STMT(BPF_RET + BPF_K, 0), /* ignore */ BPF_STMT(BPF_LD + BPF_W + BPF_ABS, offsetof(DHCPPacket, dhcp.xid)), /* A <- client identifier */ BPF_JUMP(BPF_JMP + BPF_JEQ + BPF_K, xid, 1, 0), /* client identifier == xid ? */ BPF_STMT(BPF_RET + BPF_K, 0), /* ignore */ + BPF_STMT(BPF_LD + BPF_B + BPF_ABS, offsetof(DHCPPacket, dhcp.hlen)), /* A <- MAC address length */ + BPF_JUMP(BPF_JMP + BPF_JEQ + BPF_K, dhcp_hlen, 1, 0), /* address length == dhcp_hlen ? */ + BPF_STMT(BPF_RET + BPF_K, 0), /* ignore */ + + /* We only support MAC address length to be either 0 or 6 (ETH_ALEN). Optionally + * compare chaddr for ETH_ALEN bytes. */ + BPF_JUMP(BPF_JMP + BPF_JEQ + BPF_K, ETH_ALEN, 0, 12), /* A (the MAC address length) == ETH_ALEN ? */ BPF_STMT(BPF_LD + BPF_IMM, unaligned_read_be32(ð_mac->ether_addr_octet[0])), /* A <- 4 bytes of client's MAC */ BPF_STMT(BPF_MISC + BPF_TAX, 0), /* X <- A */ BPF_STMT(BPF_LD + BPF_W + BPF_ABS, offsetof(DHCPPacket, dhcp.chaddr)), /* A <- 4 bytes of MAC from dhcp.chaddr */ @@ -70,6 +73,7 @@ static int _bind_raw_socket(int ifindex, union sockaddr_union *link, BPF_STMT(BPF_ALU + BPF_XOR + BPF_X, 0), /* A xor X */ BPF_JUMP(BPF_JMP + BPF_JEQ + BPF_K, 0, 1, 0), /* A == 0 ? */ BPF_STMT(BPF_RET + BPF_K, 0), /* ignore */ + BPF_STMT(BPF_LD + BPF_W + BPF_ABS, offsetof(DHCPPacket, dhcp.magic)), /* A <- DHCP magic cookie */ BPF_JUMP(BPF_JMP + BPF_JEQ + BPF_K, DHCP_MAGIC_COOKIE, 1, 0), /* cookie == DHCP magic cookie ? */ BPF_STMT(BPF_RET + BPF_K, 0), /* ignore */ diff --git a/src/systemd/src/libsystemd-network/dhcp-option.c b/src/systemd/src/libsystemd-network/dhcp-option.c index b065ae49..c5fbe749 100644 --- a/src/systemd/src/libsystemd-network/dhcp-option.c +++ b/src/systemd/src/libsystemd-network/dhcp-option.c @@ -5,7 +5,6 @@ #include "nm-sd-adapt-core.h" -#include <errno.h> #include <stdint.h> #include <stdio.h> #include <string.h> diff --git a/src/systemd/src/libsystemd-network/dhcp-packet.c b/src/systemd/src/libsystemd-network/dhcp-packet.c index 9e565e28..91e8a54e 100644 --- a/src/systemd/src/libsystemd-network/dhcp-packet.c +++ b/src/systemd/src/libsystemd-network/dhcp-packet.c @@ -5,7 +5,6 @@ #include "nm-sd-adapt-core.h" -#include <errno.h> #include <net/ethernet.h> #include <net/if_arp.h> #include <string.h> diff --git a/src/systemd/src/libsystemd-network/dhcp6-network.c b/src/systemd/src/libsystemd-network/dhcp6-network.c index 73c195a7..d786756e 100644 --- a/src/systemd/src/libsystemd-network/dhcp6-network.c +++ b/src/systemd/src/libsystemd-network/dhcp6-network.c @@ -5,7 +5,6 @@ #include "nm-sd-adapt-core.h" -#include <errno.h> #include <netinet/in.h> #include <netinet/ip6.h> #include <stdio.h> diff --git a/src/systemd/src/libsystemd-network/dhcp6-option.c b/src/systemd/src/libsystemd-network/dhcp6-option.c index 5a83aaaa..3d5abe64 100644 --- a/src/systemd/src/libsystemd-network/dhcp6-option.c +++ b/src/systemd/src/libsystemd-network/dhcp6-option.c @@ -5,7 +5,6 @@ #include "nm-sd-adapt-core.h" -#include <errno.h> #include <netinet/in.h> #include <string.h> diff --git a/src/systemd/src/libsystemd-network/network-internal.c b/src/systemd/src/libsystemd-network/network-internal.c index d33c4feb..f85db47b 100644 --- a/src/systemd/src/libsystemd-network/network-internal.c +++ b/src/systemd/src/libsystemd-network/network-internal.c @@ -12,6 +12,7 @@ #include "alloc-util.h" #include "condition.h" #include "conf-parser.h" +#include "device-util.h" #include "dhcp-lease-internal.h" #include "ether-addr-util.h" #include "hexdecoct.h" @@ -43,31 +44,35 @@ const char *net_get_name(sd_device *device) { int net_get_unique_predictable_data(sd_device *device, uint64_t *result) { size_t l, sz = 0; - const char *name = NULL; + const char *name; int r; uint8_t *v; assert(device); + /* net_get_name() will return one of the device names based on stable information about the + * device. If this is not available, we fall back to using the device name. */ name = net_get_name(device); if (!name) - return -ENOENT; + (void) sd_device_get_sysname(device, &name); + if (!name) + return log_device_debug_errno(device, SYNTHETIC_ERRNO(ENODATA), + "No stable identifying information found"); + log_device_debug(device, "Using \"%s\" as stable identifying information", name); l = strlen(name); sz = sizeof(sd_id128_t) + l; - v = alloca(sz); + v = newa(uint8_t, sz); - /* fetch some persistent data unique to this machine */ + /* Fetch some persistent data unique to this machine */ r = sd_id128_get_machine((sd_id128_t*) v); if (r < 0) return r; memcpy(v + sizeof(sd_id128_t), name, l); - /* Let's hash the machine ID plus the device name. We - * use a fixed, but originally randomly created hash - * key here. */ + /* Let's hash the machine ID plus the device name. We use + * a fixed, but originally randomly created hash key here. */ *result = htole64(siphash24(v, sz, HASH_KEY.bytes)); - return 0; } @@ -105,7 +110,6 @@ bool net_match_config(Set *match_mac, Condition *match_arch, const struct ether_addr *dev_mac, const char *dev_path, - const char *dev_parent_driver, const char *dev_driver, const char *dev_type, const char *dev_name) { @@ -413,16 +417,33 @@ int config_parse_bridge_port_priority( } #endif /* NM_IGNORED */ -void serialize_in_addrs(FILE *f, const struct in_addr *addresses, size_t size) { - unsigned i; +size_t serialize_in_addrs(FILE *f, + const struct in_addr *addresses, + size_t size, + bool with_leading_space, + bool (*predicate)(const struct in_addr *addr)) { + size_t count; + size_t i; assert(f); assert(addresses); - assert(size); - for (i = 0; i < size; i++) - fprintf(f, "%s%s", inet_ntoa(addresses[i]), - (i < (size - 1)) ? " ": ""); + count = 0; + + for (i = 0; i < size; i++) { + char sbuf[INET_ADDRSTRLEN]; + + if (predicate && !predicate(&addresses[i])) + continue; + if (with_leading_space) + fputc(' ', f); + else + with_leading_space = true; + fputs(inet_ntop(AF_INET, &addresses[i], sbuf, sizeof(sbuf)), f); + count++; + } + + return count; } int deserialize_in_addrs(struct in_addr **ret, const char *string) { @@ -456,7 +477,7 @@ int deserialize_in_addrs(struct in_addr **ret, const char *string) { size++; } - *ret = TAKE_PTR(addresses); + *ret = size > 0 ? TAKE_PTR(addresses) : NULL; return size; } @@ -525,6 +546,7 @@ void serialize_dhcp_routes(FILE *f, const char *key, sd_dhcp_route **routes, siz fprintf(f, "%s=", key); for (i = 0; i < size; i++) { + char sbuf[INET_ADDRSTRLEN]; struct in_addr dest, gw; uint8_t length; @@ -532,8 +554,8 @@ void serialize_dhcp_routes(FILE *f, const char *key, sd_dhcp_route **routes, siz assert_se(sd_dhcp_route_get_gateway(routes[i], &gw) >= 0); assert_se(sd_dhcp_route_get_destination_prefix_length(routes[i], &length) >= 0); - fprintf(f, "%s/%" PRIu8, inet_ntoa(dest), length); - fprintf(f, ",%s%s", inet_ntoa(gw), (i < (size - 1)) ? " ": ""); + fprintf(f, "%s/%" PRIu8, inet_ntop(AF_INET, &dest, sbuf, sizeof(sbuf)), length); + fprintf(f, ",%s%s", inet_ntop(AF_INET, &gw, sbuf, sizeof(sbuf)), (i < (size - 1)) ? " ": ""); } fputs("\n", f); diff --git a/src/systemd/src/libsystemd-network/network-internal.h b/src/systemd/src/libsystemd-network/network-internal.h index dfe4c424..9119d9a4 100644 --- a/src/systemd/src/libsystemd-network/network-internal.h +++ b/src/systemd/src/libsystemd-network/network-internal.h @@ -8,7 +8,9 @@ #include "condition.h" #include "conf-parser.h" +#include "def.h" #include "set.h" +#include "strv.h" #define LINK_BRIDGE_PORT_PRIORITY_INVALID 128 #define LINK_BRIDGE_PORT_PRIORITY_MAX 63 @@ -25,7 +27,6 @@ bool net_match_config(Set *match_mac, Condition *match_arch, const struct ether_addr *dev_mac, const char *dev_path, - const char *dev_parent_driver, const char *dev_driver, const char *dev_type, const char *dev_name); @@ -42,7 +43,11 @@ int net_get_unique_predictable_data(sd_device *device, uint64_t *result); const char *net_get_name(sd_device *device); #endif /* NM_IGNORED */ -void serialize_in_addrs(FILE *f, const struct in_addr *addresses, size_t size); +size_t serialize_in_addrs(FILE *f, + const struct in_addr *addresses, + size_t size, + bool with_leading_space, + bool (*predicate)(const struct in_addr *addr)); int deserialize_in_addrs(struct in_addr **addresses, const char *string); void serialize_in6_addrs(FILE *f, const struct in6_addr *addresses, size_t size); @@ -56,3 +61,5 @@ int deserialize_dhcp_routes(struct sd_dhcp_route **ret, size_t *ret_size, size_t /* It is not necessary to add deserialize_dhcp_option(). Use unhexmem() instead. */ int serialize_dhcp_option(FILE *f, const char *key, const void *data, size_t size); + +#define NETWORK_DIRS ((const char* const*) CONF_PATHS_STRV("systemd/network")) diff --git a/src/systemd/src/libsystemd-network/sd-dhcp-client.c b/src/systemd/src/libsystemd-network/sd-dhcp-client.c index 2f9244d8..27f79638 100644 --- a/src/systemd/src/libsystemd-network/sd-dhcp-client.c +++ b/src/systemd/src/libsystemd-network/sd-dhcp-client.c @@ -5,7 +5,6 @@ #include "nm-sd-adapt-core.h" -#include <errno.h> #include <net/ethernet.h> #include <net/if_arp.h> #include <stdio.h> @@ -1681,8 +1680,7 @@ static int client_receive_message_udp( sd_dhcp_client *client = userdata; _cleanup_free_ DHCPMessage *message = NULL; - const struct ether_addr zero_mac = {}; - const struct ether_addr *expected_chaddr = NULL; + const uint8_t *expected_chaddr = NULL; uint8_t expected_hlen = 0; ssize_t len, buflen; @@ -1690,6 +1688,12 @@ static int client_receive_message_udp( assert(client); buflen = next_datagram_size_fd(fd); + if (buflen == -ENETDOWN) { + /* the link is down. Don't return an error or the I/O event + source will be disconnected and we won't be able to receive + packets again when the link comes back. */ + return 0; + } if (buflen < 0) return buflen; @@ -1699,7 +1703,8 @@ static int client_receive_message_udp( len = recv(fd, message, buflen, 0); if (len < 0) { - if (IN_SET(errno, EAGAIN, EINTR)) + /* see comment above for why we shouldn't error out on ENETDOWN. */ + if (IN_SET(errno, EAGAIN, EINTR, ENETDOWN)) return 0; return log_dhcp_client_errno(client, errno, @@ -1727,11 +1732,7 @@ static int client_receive_message_udp( if (client->arp_type == ARPHRD_ETHER) { expected_hlen = ETH_ALEN; - expected_chaddr = (const struct ether_addr *) &client->mac_addr; - } else { - /* Non-Ethernet links expect zero chaddr */ - expected_hlen = 0; - expected_chaddr = &zero_mac; + expected_chaddr = &client->mac_addr[0]; } if (message->hlen != expected_hlen) { @@ -1739,7 +1740,7 @@ static int client_receive_message_udp( return 0; } - if (memcmp(&message->chaddr[0], expected_chaddr, ETH_ALEN)) { + if (expected_hlen > 0 && memcmp(&message->chaddr[0], expected_chaddr, expected_hlen)) { log_dhcp_client(client, "Received chaddr does not match expected: ignoring"); return 0; } @@ -1781,6 +1782,8 @@ static int client_receive_message_raw( assert(client); buflen = next_datagram_size_fd(fd); + if (buflen == -ENETDOWN) + return 0; if (buflen < 0) return buflen; @@ -1792,7 +1795,7 @@ static int client_receive_message_raw( len = recvmsg(fd, &msg, 0); if (len < 0) { - if (IN_SET(errno, EAGAIN, EINTR)) + if (IN_SET(errno, EAGAIN, EINTR, ENETDOWN)) return 0; return log_dhcp_client_errno(client, errno, diff --git a/src/systemd/src/libsystemd-network/sd-dhcp-lease.c b/src/systemd/src/libsystemd-network/sd-dhcp-lease.c index fc5077c2..39d2a6d0 100644 --- a/src/systemd/src/libsystemd-network/sd-dhcp-lease.c +++ b/src/systemd/src/libsystemd-network/sd-dhcp-lease.c @@ -6,7 +6,6 @@ #include "nm-sd-adapt-core.h" #include <arpa/inet.h> -#include <errno.h> #include <stdio.h> #include <stdio_ext.h> #include <stdlib.h> @@ -153,15 +152,15 @@ int sd_dhcp_lease_get_root_path(sd_dhcp_lease *lease, const char **root_path) { return 0; } -int sd_dhcp_lease_get_router(sd_dhcp_lease *lease, struct in_addr *addr) { +int sd_dhcp_lease_get_router(sd_dhcp_lease *lease, const struct in_addr **addr) { assert_return(lease, -EINVAL); assert_return(addr, -EINVAL); - if (lease->router == 0) + if (lease->router_size <= 0) return -ENODATA; - addr->s_addr = lease->router; - return 0; + *addr = lease->router; + return (int) lease->router_size; } int sd_dhcp_lease_get_netmask(sd_dhcp_lease *lease, struct in_addr *addr) { @@ -263,6 +262,7 @@ static sd_dhcp_lease *dhcp_lease_free(sd_dhcp_lease *lease) { } free(lease->root_path); + free(lease->router); free(lease->timezone); free(lease->hostname); free(lease->domainname); @@ -372,23 +372,6 @@ static int lease_parse_domain(const uint8_t *option, size_t len, char **ret) { return 0; } -static void filter_bogus_addresses(struct in_addr *addresses, size_t *n) { - size_t i, j; - - /* Silently filter DNS/NTP servers supplied to us that do not make outside of the local scope. */ - - for (i = 0, j = 0; i < *n; i ++) { - - if (in4_addr_is_null(addresses+i) || - in4_addr_is_localhost(addresses+i)) - continue; - - addresses[j++] = addresses[i]; - } - - *n = j; -} - static int lease_parse_in_addrs(const uint8_t *option, size_t len, struct in_addr **ret, size_t *n_ret) { assert(option); assert(ret); @@ -410,8 +393,6 @@ static int lease_parse_in_addrs(const uint8_t *option, size_t len, struct in_add if (!addresses) return -ENOMEM; - filter_bogus_addresses(addresses, &n_addresses); - free(*ret); *ret = addresses; *n_ret = n_addresses; @@ -556,11 +537,9 @@ int dhcp_lease_parse_options(uint8_t code, uint8_t len, const void *option, void break; case SD_DHCP_OPTION_ROUTER: - if (len >= 4) { - r = lease_parse_be32(option, 4, &lease->router); - if (r < 0) - log_debug_errno(r, "Failed to parse router address, ignoring: %m"); - } + r = lease_parse_in_addrs(option, len, &lease->router, &lease->router_size); + if (r < 0) + log_debug_errno(r, "Failed to parse router addresses, ignoring: %m"); break; case SD_DHCP_OPTION_DOMAIN_NAME_SERVER: @@ -822,7 +801,6 @@ int dhcp_lease_new(sd_dhcp_lease **ret) { if (!lease) return -ENOMEM; - lease->router = INADDR_ANY; lease->n_ref = 1; *ret = lease; @@ -837,6 +815,7 @@ int dhcp_lease_save(sd_dhcp_lease *lease, const char *lease_file) { const struct in_addr *addresses; const void *client_id, *data; size_t client_id_len, data_len; + char sbuf[INET_ADDRSTRLEN]; const char *string; uint16_t mtu; _cleanup_free_ sd_dhcp_route **routes = NULL; @@ -859,27 +838,30 @@ int dhcp_lease_save(sd_dhcp_lease *lease, const char *lease_file) { r = sd_dhcp_lease_get_address(lease, &address); if (r >= 0) - fprintf(f, "ADDRESS=%s\n", inet_ntoa(address)); + fprintf(f, "ADDRESS=%s\n", inet_ntop(AF_INET, &address, sbuf, sizeof(sbuf))); r = sd_dhcp_lease_get_netmask(lease, &address); if (r >= 0) - fprintf(f, "NETMASK=%s\n", inet_ntoa(address)); + fprintf(f, "NETMASK=%s\n", inet_ntop(AF_INET, &address, sbuf, sizeof(sbuf))); - r = sd_dhcp_lease_get_router(lease, &address); - if (r >= 0) - fprintf(f, "ROUTER=%s\n", inet_ntoa(address)); + r = sd_dhcp_lease_get_router(lease, &addresses); + if (r > 0) { + fputs("ROUTER=", f); + serialize_in_addrs(f, addresses, r, false, NULL); + fputc('\n', f); + } r = sd_dhcp_lease_get_server_identifier(lease, &address); if (r >= 0) - fprintf(f, "SERVER_ADDRESS=%s\n", inet_ntoa(address)); + fprintf(f, "SERVER_ADDRESS=%s\n", inet_ntop(AF_INET, &address, sbuf, sizeof(sbuf))); r = sd_dhcp_lease_get_next_server(lease, &address); if (r >= 0) - fprintf(f, "NEXT_SERVER=%s\n", inet_ntoa(address)); + fprintf(f, "NEXT_SERVER=%s\n", inet_ntop(AF_INET, &address, sbuf, sizeof(sbuf))); r = sd_dhcp_lease_get_broadcast(lease, &address); if (r >= 0) - fprintf(f, "BROADCAST=%s\n", inet_ntoa(address)); + fprintf(f, "BROADCAST=%s\n", inet_ntop(AF_INET, &address, sbuf, sizeof(sbuf))); r = sd_dhcp_lease_get_mtu(lease, &mtu); if (r >= 0) @@ -900,15 +882,15 @@ int dhcp_lease_save(sd_dhcp_lease *lease, const char *lease_file) { r = sd_dhcp_lease_get_dns(lease, &addresses); if (r > 0) { fputs("DNS=", f); - serialize_in_addrs(f, addresses, r); - fputs("\n", f); + serialize_in_addrs(f, addresses, r, false, NULL); + fputc('\n', f); } r = sd_dhcp_lease_get_ntp(lease, &addresses); if (r > 0) { fputs("NTP=", f); - serialize_in_addrs(f, addresses, r); - fputs("\n", f); + serialize_in_addrs(f, addresses, r, false, NULL); + fputc('\n', f); } r = sd_dhcp_lease_get_domainname(lease, &string); @@ -919,7 +901,7 @@ int dhcp_lease_save(sd_dhcp_lease *lease, const char *lease_file) { if (r > 0) { fputs("DOMAIN_SEARCH_LIST=", f); fputstrv(f, search_domains, NULL, NULL); - fputs("\n", f); + fputc('\n', f); } r = sd_dhcp_lease_get_hostname(lease, &string); @@ -1082,9 +1064,11 @@ int dhcp_lease_load(sd_dhcp_lease **ret, const char *lease_file) { } if (router) { - r = inet_pton(AF_INET, router, &lease->router); - if (r <= 0) - log_debug("Failed to parse router %s, ignoring.", router); + r = deserialize_in_addrs(&lease->router, router); + if (r < 0) + log_debug_errno(r, "Failed to deserialize router addresses %s, ignoring: %m", router); + else + lease->router_size = r; } if (netmask) { diff --git a/src/systemd/src/libsystemd-network/sd-dhcp6-client.c b/src/systemd/src/libsystemd-network/sd-dhcp6-client.c index 6b55083e..b72cd82d 100644 --- a/src/systemd/src/libsystemd-network/sd-dhcp6-client.c +++ b/src/systemd/src/libsystemd-network/sd-dhcp6-client.c @@ -5,7 +5,6 @@ #include "nm-sd-adapt-core.h" -#include <errno.h> #include <string.h> #include <sys/ioctl.h> #include <linux/if_infiniband.h> @@ -1118,6 +1117,12 @@ static int client_receive_message( assert(client->event); buflen = next_datagram_size_fd(fd); + if (buflen == -ENETDOWN) { + /* the link is down. Don't return an error or the I/O event + source will be disconnected and we won't be able to receive + packets again when the link comes back. */ + return 0; + } if (buflen < 0) return buflen; @@ -1127,7 +1132,8 @@ static int client_receive_message( len = recv(fd, message, buflen, 0); if (len < 0) { - if (IN_SET(errno, EAGAIN, EINTR)) + /* see comment above for why we shouldn't error out on ENETDOWN. */ + if (IN_SET(errno, EAGAIN, EINTR, ENETDOWN)) return 0; return log_dhcp6_client_errno(client, errno, "Could not receive message from UDP socket: %m"); diff --git a/src/systemd/src/libsystemd-network/sd-dhcp6-lease.c b/src/systemd/src/libsystemd-network/sd-dhcp6-lease.c index 48188bf3..7263c96f 100644 --- a/src/systemd/src/libsystemd-network/sd-dhcp6-lease.c +++ b/src/systemd/src/libsystemd-network/sd-dhcp6-lease.c @@ -5,7 +5,6 @@ #include "nm-sd-adapt-core.h" -#include <errno.h> #include "alloc-util.h" #include "dhcp6-lease-internal.h" diff --git a/src/systemd/src/libsystemd-network/sd-ipv4acd.c b/src/systemd/src/libsystemd-network/sd-ipv4acd.c index b43da6b4..6de4adb5 100644 --- a/src/systemd/src/libsystemd-network/sd-ipv4acd.c +++ b/src/systemd/src/libsystemd-network/sd-ipv4acd.c @@ -6,7 +6,6 @@ #include "nm-sd-adapt-core.h" #include <arpa/inet.h> -#include <errno.h> #include <stdio.h> #include <stdlib.h> #include <string.h> diff --git a/src/systemd/src/libsystemd-network/sd-ipv4ll.c b/src/systemd/src/libsystemd-network/sd-ipv4ll.c index f1b94829..8b1e9665 100644 --- a/src/systemd/src/libsystemd-network/sd-ipv4ll.c +++ b/src/systemd/src/libsystemd-network/sd-ipv4ll.c @@ -6,7 +6,6 @@ #include "nm-sd-adapt-core.h" #include <arpa/inet.h> -#include <errno.h> #include <stdio.h> #include <stdlib.h> #include <string.h> diff --git a/src/systemd/src/libsystemd/sd-event/event-util.c b/src/systemd/src/libsystemd/sd-event/event-util.c index e8384cfd..2afacfe6 100644 --- a/src/systemd/src/libsystemd/sd-event/event-util.c +++ b/src/systemd/src/libsystemd/sd-event/event-util.c @@ -2,7 +2,6 @@ #include "nm-sd-adapt-core.h" -#include <errno.h> #include "event-source.h" #include "event-util.h" diff --git a/src/systemd/src/libsystemd/sd-event/sd-event.c b/src/systemd/src/libsystemd/sd-event/sd-event.c index e49cc9d8..6f77421b 100644 --- a/src/systemd/src/libsystemd/sd-event/sd-event.c +++ b/src/systemd/src/libsystemd/sd-event/sd-event.c @@ -472,6 +472,17 @@ static struct clock_data* event_get_clock_data(sd_event *e, EventSourceType t) { } } +static void event_free_signal_data(sd_event *e, struct signal_data *d) { + assert(e); + + if (!d) + return; + + hashmap_remove(e->signal_data, &d->priority); + safe_close(d->fd); + free(d); +} + static int event_make_signal_data( sd_event *e, int sig, @@ -561,11 +572,8 @@ static int event_make_signal_data( return 0; fail: - if (added) { - d->fd = safe_close(d->fd); - hashmap_remove(e->signal_data, &d->priority); - free(d); - } + if (added) + event_free_signal_data(e, d); return r; } @@ -584,11 +592,8 @@ static void event_unmask_signal_data(sd_event *e, struct signal_data *d, int sig assert_se(sigdelset(&d->sigset, sig) >= 0); if (sigisemptyset(&d->sigset)) { - /* If all the mask is all-zero we can get rid of the structure */ - hashmap_remove(e->signal_data, &d->priority); - safe_close(d->fd); - free(d); + event_free_signal_data(e, d); return; } diff --git a/src/systemd/src/libsystemd/sd-id128/id128-util.c b/src/systemd/src/libsystemd/sd-id128/id128-util.c index f8f0883c..6245e9df 100644 --- a/src/systemd/src/libsystemd/sd-id128/id128-util.c +++ b/src/systemd/src/libsystemd/sd-id128/id128-util.c @@ -2,7 +2,6 @@ #include "nm-sd-adapt-core.h" -#include <errno.h> #include <fcntl.h> #include <unistd.h> diff --git a/src/systemd/src/libsystemd/sd-id128/sd-id128.c b/src/systemd/src/libsystemd/sd-id128/sd-id128.c index a476017b..13a28291 100644 --- a/src/systemd/src/libsystemd/sd-id128/sd-id128.c +++ b/src/systemd/src/libsystemd/sd-id128/sd-id128.c @@ -2,7 +2,6 @@ #include "nm-sd-adapt-core.h" -#include <errno.h> #include <fcntl.h> #include <unistd.h> diff --git a/src/systemd/src/shared/dns-domain.h b/src/systemd/src/shared/dns-domain.h index 88b3eb11..17db7c52 100644 --- a/src/systemd/src/shared/dns-domain.h +++ b/src/systemd/src/shared/dns-domain.h @@ -1,7 +1,6 @@ /* SPDX-License-Identifier: LGPL-2.1+ */ #pragma once -#include <errno.h> #include <stdbool.h> #include <stddef.h> #include <stdint.h> diff --git a/src/systemd/src/systemd/sd-dhcp-lease.h b/src/systemd/src/systemd/sd-dhcp-lease.h index 4875f105..d299c791 100644 --- a/src/systemd/src/systemd/sd-dhcp-lease.h +++ b/src/systemd/src/systemd/sd-dhcp-lease.h @@ -39,7 +39,7 @@ int sd_dhcp_lease_get_t1(sd_dhcp_lease *lease, uint32_t *t1); int sd_dhcp_lease_get_t2(sd_dhcp_lease *lease, uint32_t *t2); int sd_dhcp_lease_get_broadcast(sd_dhcp_lease *lease, struct in_addr *addr); int sd_dhcp_lease_get_netmask(sd_dhcp_lease *lease, struct in_addr *addr); -int sd_dhcp_lease_get_router(sd_dhcp_lease *lease, struct in_addr *addr); +int sd_dhcp_lease_get_router(sd_dhcp_lease *lease, const struct in_addr **addr); int sd_dhcp_lease_get_next_server(sd_dhcp_lease *lease, struct in_addr *addr); int sd_dhcp_lease_get_server_identifier(sd_dhcp_lease *lease, struct in_addr *addr); int sd_dhcp_lease_get_dns(sd_dhcp_lease *lease, const struct in_addr **addr); diff --git a/src/tests/config/meson.build b/src/tests/config/meson.build index dc0a022c..f65f90bb 100644 --- a/src/tests/config/meson.build +++ b/src/tests/config/meson.build @@ -17,4 +17,5 @@ test( 'config/' + test_unit, test_script, args: test_args + [exe.full_path()], + timeout: default_test_timeout, ) diff --git a/src/tests/config/nm-test-device.c b/src/tests/config/nm-test-device.c index 49631583..3a8ef266 100644 --- a/src/tests/config/nm-test-device.c +++ b/src/tests/config/nm-test-device.c @@ -22,8 +22,6 @@ #include "nm-test-device.h" -#include <string.h> - #include "devices/nm-device-private.h" #include "nm-utils.h" @@ -77,6 +75,7 @@ nm_test_device_new (const char *hwaddr) return g_object_new (NM_TYPE_TEST_DEVICE, NM_DEVICE_IFACE, "dummy", NM_DEVICE_PERM_HW_ADDRESS, hwaddr, + NM_DEVICE_DEVICE_TYPE, NM_DEVICE_TYPE_ETHERNET, NULL); } diff --git a/src/tests/meson.build b/src/tests/meson.build index 9c51e8d4..153128f2 100644 --- a/src/tests/meson.build +++ b/src/tests/meson.build @@ -21,6 +21,7 @@ foreach test_unit: test_units 'src/' + test_unit, test_script, args: test_args + [exe.full_path()], + timeout: default_test_timeout, ) endforeach diff --git a/src/tests/test-dcb.c b/src/tests/test-dcb.c index 2ab0f890..6291f254 100644 --- a/src/tests/test-dcb.c +++ b/src/tests/test-dcb.c @@ -20,8 +20,6 @@ #include "nm-default.h" -#include <string.h> - #include "nm-dcb.h" #include "nm-test-utils-core.h" diff --git a/src/tests/test-general-with-expect.c b/src/tests/test-general-with-expect.c index ba8e3ce4..8339fa5d 100644 --- a/src/tests/test-general-with-expect.c +++ b/src/tests/test-general-with-expect.c @@ -20,8 +20,6 @@ #include "nm-default.h" -#include <string.h> -#include <errno.h> #include <time.h> #include <netinet/ether.h> #include <sys/types.h> @@ -42,7 +40,8 @@ test_nm_utils_monotonic_timestamp_as_boottime (void) clockid_t clockid; guint i; - if (clock_gettime (CLOCK_BOOTTIME, &tp) != 0 && errno == EINVAL) + if ( clock_gettime (CLOCK_BOOTTIME, &tp) != 0 + && errno == EINVAL) clockid = CLOCK_MONOTONIC; else clockid = CLOCK_BOOTTIME; diff --git a/src/tests/test-general.c b/src/tests/test-general.c index f065d127..0dee566e 100644 --- a/src/tests/test-general.c +++ b/src/tests/test-general.c @@ -20,8 +20,6 @@ #include "nm-default.h" -#include <string.h> -#include <errno.h> #include <net/if.h> #include <byteswap.h> @@ -1666,7 +1664,7 @@ test_duplicate_decl_specifier (void) /* have some static variables, so that the result is certainly not optimized out. */ static const int v_const[1] = { 1 }; static int v_result[1] = { }; - const const int v2 = 3; + const int v2 = 3; /* Test that we don't get a compiler warning about duplicate const specifier. * C99 allows that and it can easily happen in macros. */ @@ -2014,11 +2012,11 @@ test_machine_id_read (void) nmtst_logging_reenable (logstate); g_assert (machine_id); - g_assert (_nm_utils_bin2hexstr_full (machine_id, - sizeof (NMUuid), - '\0', - FALSE, - machine_id_str) == machine_id_str); + g_assert (nm_utils_bin2hexstr_full (machine_id, + sizeof (NMUuid), + '\0', + FALSE, + machine_id_str) == machine_id_str); g_assert (strlen (machine_id_str) == 32); g_assert_cmpstr (machine_id_str, ==, nm_utils_machine_id_str ()); @@ -2055,14 +2053,14 @@ test_nm_utils_dhcp_client_id_systemd_node_specific (gconstpointer test_data) guint64 duid_id; } d_array[] = { [0] = { - .machine_id = { 0xcb, 0xc2, 0x2e, 0x47, 0x41, 0x8e, 0x40, 0x2a, 0xa7, 0xb3, 0x0d, 0xea, 0x92, 0x83, 0x94, 0xef }, + .machine_id.uuid = { 0xcb, 0xc2, 0x2e, 0x47, 0x41, 0x8e, 0x40, 0x2a, 0xa7, 0xb3, 0x0d, 0xea, 0x92, 0x83, 0x94, 0xef }, .ifname = "lo", .ifname_hash_1 = 0x7297085c2b12c911llu, .iaid_ifname = htobe32 (0x5985c14du), .duid_id = htobe64 (0x3d769bb2c14d29e1u), }, [1] = { - .machine_id = { 0x11, 0x4e, 0xb4, 0xda, 0xd3, 0x22, 0x4a, 0xff, 0x9f, 0xc3, 0x30, 0x83, 0x38, 0xa0, 0xeb, 0xb7 }, + .machine_id.uuid = { 0x11, 0x4e, 0xb4, 0xda, 0xd3, 0x22, 0x4a, 0xff, 0x9f, 0xc3, 0x30, 0x83, 0x38, 0xa0, 0xeb, 0xb7 }, .ifname = "eth0", .ifname_hash_1 = 0x9e1cb083b54cd7b6llu, .iaid_ifname = htobe32 (0x2b506735u), diff --git a/src/tests/test-ip4-config.c b/src/tests/test-ip4-config.c index 9fea6af5..f98c84c3 100644 --- a/src/tests/test-ip4-config.c +++ b/src/tests/test-ip4-config.c @@ -20,7 +20,6 @@ #include "nm-default.h" -#include <string.h> #include <arpa/inet.h> #include "nm-ip4-config.h" diff --git a/src/tests/test-ip6-config.c b/src/tests/test-ip6-config.c index 51807dea..8f5f41d7 100644 --- a/src/tests/test-ip6-config.c +++ b/src/tests/test-ip6-config.c @@ -20,7 +20,6 @@ #include "nm-default.h" -#include <string.h> #include <arpa/inet.h> #include <linux/if_addr.h> diff --git a/src/tests/test-systemd.c b/src/tests/test-systemd.c index 05e22776..91edcab2 100644 --- a/src/tests/test-systemd.c +++ b/src/tests/test-systemd.c @@ -49,8 +49,9 @@ nm_utils_get_monotonic_timestamp_s (void) NMLogDomain _nm_logging_enabled_state[_LOGL_N_REAL]; gboolean -_nm_log_enabled (NMLogLevel level, - NMLogDomain domain) +_nm_log_enabled_impl (gboolean mt_require_locking, + NMLogLevel level, + NMLogDomain domain) { return FALSE; } @@ -59,6 +60,7 @@ void _nm_log_impl (const char *file, guint line, const char *func, + gboolean mt_require_locking, NMLogLevel level, NMLogDomain domain, int error, @@ -78,6 +80,12 @@ nm_logging_setup (const char *level, return TRUE; } +const char * +nm_strerror_native (int errsv) +{ + return g_strerror (errsv); +} + /*****************************************************************************/ static void diff --git a/src/tests/test-utils.c b/src/tests/test-utils.c index 9572ec7a..c326f790 100644 --- a/src/tests/test-utils.c +++ b/src/tests/test-utils.c @@ -20,8 +20,6 @@ #include "nm-default.h" -#include <string.h> -#include <errno.h> #include <arpa/inet.h> #include "nm-test-utils-core.h" diff --git a/src/vpn/nm-vpn-connection.c b/src/vpn/nm-vpn-connection.c index 6626f64a..5acf491a 100644 --- a/src/vpn/nm-vpn-connection.c +++ b/src/vpn/nm-vpn-connection.c @@ -23,11 +23,9 @@ #include "nm-vpn-connection.h" -#include <string.h> #include <sys/socket.h> #include <netinet/in.h> #include <arpa/inet.h> -#include <errno.h> #include <stdlib.h> #include <unistd.h> #include <syslog.h> @@ -729,15 +727,23 @@ add_ip4_vpn_gateway_route (NMIP4Config *config, const NMPlatformIP4Route *r = NMP_OBJECT_CAST_IP4_ROUTE (route_resolved); if (r->ifindex == ifindex) { + const NMPObject *obj; + /* `ip route get` always resolves the route, even if the destination is unreachable. * In which case, it pretends the destination is directly reachable. * - * So, only accept direct routes, if @vpn_gw is a private network. */ - if ( nm_platform_route_table_is_main (r->table_coerced) - && ( r->gateway - || nm_utils_ip_is_site_local (AF_INET, &vpn_gw))) { - parent_gw = r->gateway; - has_parent_gw = TRUE; + * So, only accept direct routes if @vpn_gw is a private network + * or if the parent device also has a direct default route */ + if (nm_platform_route_table_is_main (r->table_coerced)) { + if (r->gateway) { + parent_gw = r->gateway; + has_parent_gw = TRUE; + } else if (nm_utils_ip_is_site_local (AF_INET, &vpn_gw)) { + has_parent_gw = TRUE; + } else if ( (obj = nm_device_get_best_default_route (parent_device, AF_INET)) + && !NMP_OBJECT_CAST_IP4_ROUTE (obj)->gateway) { + has_parent_gw = TRUE; + } } } } @@ -803,15 +809,23 @@ add_ip6_vpn_gateway_route (NMIP6Config *config, const NMPlatformIP6Route *r = NMP_OBJECT_CAST_IP6_ROUTE (route_resolved); if (r->ifindex == ifindex) { + const NMPObject *obj; + /* `ip route get` always resolves the route, even if the destination is unreachable. * In which case, it pretends the destination is directly reachable. * - * So, only accept direct routes, if @vpn_gw is a private network. */ - if ( nm_platform_route_table_is_main (r->table_coerced) - && ( !IN6_IS_ADDR_UNSPECIFIED (&r->gateway) - || nm_utils_ip_is_site_local (AF_INET6, &vpn_gw))) { - parent_gw = &r->gateway; - has_parent_gw = TRUE; + * So, only accept direct routes if @vpn_gw is a private network + * or if the parent device also has a direct default route */ + if (nm_platform_route_table_is_main (r->table_coerced)) { + if (!IN6_IS_ADDR_UNSPECIFIED (&r->gateway)) { + parent_gw = &r->gateway; + has_parent_gw = TRUE; + } else if (nm_utils_ip_is_site_local (AF_INET6, &vpn_gw)) { + has_parent_gw = TRUE; + } else if ( (obj = nm_device_get_best_default_route (parent_device, AF_INET6)) + && IN6_IS_ADDR_UNSPECIFIED (&NMP_OBJECT_CAST_IP6_ROUTE (obj)->gateway)) { + has_parent_gw = TRUE; + } } } } @@ -1442,11 +1456,7 @@ get_route_table (NMVpnConnection *self, connection = _get_applied_connection (self); if (connection) { - if (addr_family == AF_INET) - s_ip = nm_connection_get_setting_ip4_config (connection); - else - s_ip = nm_connection_get_setting_ip6_config (connection); - + s_ip = nm_connection_get_setting_ip_config (connection, addr_family); if (s_ip) route_table = nm_setting_ip_config_get_route_table (s_ip); } diff --git a/src/vpn/nm-vpn-connection.h b/src/vpn/nm-vpn-connection.h index 5482fb0d..e70590b2 100644 --- a/src/vpn/nm-vpn-connection.h +++ b/src/vpn/nm-vpn-connection.h @@ -28,8 +28,6 @@ #include "nm-active-connection.h" #include "nm-vpn-plugin-info.h" -#define NM_VPN_ROUTE_METRIC_DEFAULT 50 - #define NM_TYPE_VPN_CONNECTION (nm_vpn_connection_get_type ()) #define NM_VPN_CONNECTION(obj) (G_TYPE_CHECK_INSTANCE_CAST ((obj), NM_TYPE_VPN_CONNECTION, NMVpnConnection)) #define NM_VPN_CONNECTION_CLASS(klass) (G_TYPE_CHECK_CLASS_CAST ((klass), NM_TYPE_VPN_CONNECTION, NMVpnConnectionClass)) diff --git a/src/vpn/nm-vpn-manager.c b/src/vpn/nm-vpn-manager.c index d0639168..0b27b9de 100644 --- a/src/vpn/nm-vpn-manager.c +++ b/src/vpn/nm-vpn-manager.c @@ -23,8 +23,6 @@ #include "nm-vpn-manager.h" -#include <string.h> - #include "nm-vpn-plugin-info.h" #include "nm-vpn-connection.h" #include "nm-setting-vpn.h" |