diff options
| author | Michael Biebl <biebl@debian.org> | 2018-06-17 14:54:10 +0200 |
|---|---|---|
| committer | Michael Biebl <biebl@debian.org> | 2018-06-17 14:54:10 +0200 |
| commit | 069cb5c3a525ebcc19cc2927964258acaca87b13 (patch) | |
| tree | 66ac6b21a44d630c0fc281c0df327239d491226a /src/devices | |
| parent | 04bc9e1cd3544445d883ad29ea108c1645c8e7b7 (diff) | |
New upstream version 1.11.90 upstream/1.11.90
Diffstat (limited to 'src/devices')
| -rw-r--r-- | src/devices/bluetooth/nm-device-bt.c | 7 | ||||
| -rw-r--r-- | src/devices/nm-device-ethernet.c | 36 | ||||
| -rw-r--r-- | src/devices/nm-device-macsec.c | 1 | ||||
| -rw-r--r-- | src/devices/nm-device-private.h | 2 | ||||
| -rw-r--r-- | src/devices/nm-device.c | 427 | ||||
| -rw-r--r-- | src/devices/ovs/nm-device-ovs-interface.c | 2 | ||||
| -rw-r--r-- | src/devices/wifi/nm-device-iwd.c | 15 | ||||
| -rw-r--r-- | src/devices/wifi/nm-device-iwd.h | 1 | ||||
| -rw-r--r-- | src/devices/wifi/nm-device-wifi.c | 91 | ||||
| -rw-r--r-- | src/devices/wifi/nm-device-wifi.h | 1 | ||||
| -rw-r--r-- | src/devices/wifi/nm-wifi-common.c | 1 | ||||
| -rw-r--r-- | src/devices/wwan/nm-device-modem.c | 2 | ||||
| -rw-r--r-- | src/devices/wwan/nm-modem.c | 13 | ||||
| -rw-r--r-- | src/devices/wwan/nm-modem.h | 2 |
14 files changed, 500 insertions, 101 deletions
diff --git a/src/devices/bluetooth/nm-device-bt.c b/src/devices/bluetooth/nm-device-bt.c index 1d237d92..92ad0b31 100644 --- a/src/devices/bluetooth/nm-device-bt.c +++ b/src/devices/bluetooth/nm-device-bt.c @@ -903,11 +903,8 @@ act_stage3_ip6_config_start (NMDevice *device, { 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, - nm_device_get_act_request (device), - out_failure_reason); - } + 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); } diff --git a/src/devices/nm-device-ethernet.c b/src/devices/nm-device-ethernet.c index 6c5e33e4..87d16dbe 100644 --- a/src/devices/nm-device-ethernet.c +++ b/src/devices/nm-device-ethernet.c @@ -753,13 +753,6 @@ supplicant_interface_init (NMDeviceEthernet *self) return TRUE; } -NM_UTILS_LOOKUP_STR_DEFINE_STATIC (link_duplex_to_string, NMPlatformLinkDuplexType, - NM_UTILS_LOOKUP_DEFAULT_WARN (NULL), - NM_UTILS_LOOKUP_STR_ITEM (NM_PLATFORM_LINK_DUPLEX_UNKNOWN, "unknown"), - NM_UTILS_LOOKUP_STR_ITEM (NM_PLATFORM_LINK_DUPLEX_FULL, "full"), - NM_UTILS_LOOKUP_STR_ITEM (NM_PLATFORM_LINK_DUPLEX_HALF, "half"), -); - static NMPlatformLinkDuplexType link_duplex_to_platform (const char *duplex) { @@ -787,13 +780,11 @@ link_negotiation_set (NMDevice *device) s_wired = (NMSettingWired *) nm_device_get_applied_setting (device, NM_TYPE_SETTING_WIRED); if (s_wired) { autoneg = nm_setting_wired_get_auto_negotiate (s_wired); - if (!autoneg) { - speed = nm_setting_wired_get_speed (s_wired); - duplex = link_duplex_to_platform (nm_setting_wired_get_duplex (s_wired)); - if (!speed && !duplex) { - _LOGD (LOGD_DEVICE, "set-link: ignore link negotiation"); - return; - } + speed = nm_setting_wired_get_speed (s_wired); + duplex = link_duplex_to_platform (nm_setting_wired_get_duplex (s_wired)); + if (!autoneg && !speed && !duplex) { + _LOGD (LOGD_DEVICE, "set-link: ignore link negotiation"); + return; } } @@ -804,20 +795,23 @@ link_negotiation_set (NMDevice *device) } /* If link negotiation setting are already in place do nothing and return with success */ - if ( (!!autoneg == !!link_autoneg) - && (!speed || (speed == link_speed)) - && (!duplex || (duplex == link_duplex))) { + if ( !!autoneg == !!link_autoneg + && speed == link_speed + && duplex == link_duplex) { _LOGD (LOGD_DEVICE, "set-link: link negotiation is already configured"); return; } - if (autoneg) - _LOGD (LOGD_DEVICE, "set-link: configure autonegotiation"); + if (autoneg && !speed && !duplex) + _LOGD (LOGD_DEVICE, "set-link: configure auto-negotiation"); else { - _LOGD (LOGD_DEVICE, "set-link: configure static negotiation (%u Mbit%s - %s duplex%s)", + _LOGD (LOGD_DEVICE, "set-link: configure %snegotiation (%u Mbit%s - %s duplex%s)", + autoneg ? "auto-" : "static ", speed ?: link_speed, speed ? "" : "*", - duplex ? link_duplex_to_string (duplex) : link_duplex_to_string (link_duplex), + duplex + ? nm_platform_link_duplex_type_to_string (duplex) + : nm_platform_link_duplex_type_to_string (link_duplex), duplex ? "" : "*"); } diff --git a/src/devices/nm-device-macsec.c b/src/devices/nm-device-macsec.c index 4eaf5469..166bfb57 100644 --- a/src/devices/nm-device-macsec.c +++ b/src/devices/nm-device-macsec.c @@ -704,6 +704,7 @@ create_and_realize (NMDevice *device, sci.s.port = htons (nm_setting_macsec_get_port (s_macsec)); lnk.sci = be64toh (sci.u); lnk.validation = nm_setting_macsec_get_validation (s_macsec); + lnk.include_sci = nm_setting_macsec_get_send_sci (s_macsec); parent_ifindex = nm_device_get_ifindex (parent); g_warn_if_fail (parent_ifindex > 0); diff --git a/src/devices/nm-device-private.h b/src/devices/nm-device-private.h index 0b844411..c76debff 100644 --- a/src/devices/nm-device-private.h +++ b/src/devices/nm-device-private.h @@ -134,7 +134,7 @@ void nm_device_commit_mtu (NMDevice *self); } gboolean _nm_device_hash_check_invalid_keys (GHashTable *hash, const char *setting_name, - GError **error, const char **argv); + GError **error, const char **whitelist); #define nm_device_hash_check_invalid_keys(hash, setting_name, error, ...) \ _nm_device_hash_check_invalid_keys (hash, setting_name, error, ((const char *[]) { __VA_ARGS__, NULL })) diff --git a/src/devices/nm-device.c b/src/devices/nm-device.c index 9a40a0dd..9df41410 100644 --- a/src/devices/nm-device.c +++ b/src/devices/nm-device.c @@ -37,8 +37,11 @@ #include <linux/if_arp.h> #include <linux/rtnetlink.h> #include <linux/pkt_sched.h> +#include <uuid/uuid.h> #include "nm-utils/nm-dedup-multi.h" +#include "nm-utils/nm-random-utils.h" +#include "nm-utils/unaligned.h" #include "nm-common-macros.h" #include "nm-device-private.h" @@ -6830,11 +6833,12 @@ dhcp4_grace_period_expired (gpointer user_data) } static void -dhcp4_fail (NMDevice *self, gboolean timeout) +dhcp4_fail (NMDevice *self) { NMDevicePrivate *priv = NM_DEVICE_GET_PRIVATE (self); - _LOGD (LOGD_DHCP4, "DHCPv4 failed%s", timeout ? " (timeout)" : ""); + _LOGD (LOGD_DHCP4, "DHCPv4 failed (ip_state %s)", + _ip_state_to_string (priv->ip4_state)); /* Keep client running if there are static addresses configured * on the interface. @@ -6848,7 +6852,7 @@ dhcp4_fail (NMDevice *self, gboolean timeout) * configuration. */ if ( !priv->dhcp4.was_active - && (timeout || priv->ip4_state == IP_CONF)) { + && priv->ip4_state == IP_CONF) { dhcp4_cleanup (self, CLEANUP_TYPE_DECONFIGURE, FALSE); nm_device_activate_schedule_ip4_config_timeout (self); return; @@ -6911,7 +6915,7 @@ dhcp4_state_changed (NMDhcpClient *client, case NM_DHCP_STATE_BOUND: if (!ip4_config) { _LOGW (LOGD_DHCP4, "failed to get IPv4 config in response to DHCP event."); - dhcp4_fail (self, FALSE); + dhcp4_fail (self); break; } @@ -6950,11 +6954,11 @@ dhcp4_state_changed (NMDhcpClient *client, if (dhcp4_lease_change (self, ip4_config)) nm_device_update_metered (self); else - dhcp4_fail (self, FALSE); + dhcp4_fail (self); } break; case NM_DHCP_STATE_TIMEOUT: - dhcp4_fail (self, TRUE); + dhcp4_fail (self); break; case NM_DHCP_STATE_EXPIRE: /* Ignore expiry before we even have a lease (NAK, old lease, etc) */ @@ -6963,7 +6967,7 @@ dhcp4_state_changed (NMDhcpClient *client, /* fall through */ case NM_DHCP_STATE_DONE: case NM_DHCP_STATE_FAIL: - dhcp4_fail (self, FALSE); + dhcp4_fail (self); break; default: break; @@ -7014,13 +7018,32 @@ get_dhcp_timeout (NMDevice *self, int addr_family) } static GBytes * -dhcp4_get_client_id (NMDevice *self, NMConnection *connection) +dhcp4_get_client_id_mac (const guint8 *hwaddr /* ETH_ALEN bytes */) +{ + guint8 *client_id_buf; + guint8 hwaddr_type = ARPHRD_ETHER; + + client_id_buf = g_malloc (ETH_ALEN + 1); + client_id_buf[0] = hwaddr_type; + memcpy (&client_id_buf[1], hwaddr, ETH_ALEN); + return g_bytes_new_take (client_id_buf, ETH_ALEN + 1); +} + +static GBytes * +dhcp4_get_client_id (NMDevice *self, + NMConnection *connection, + GBytes *hwaddr) { NMSettingIPConfig *s_ip4; const char *client_id; gs_free char *client_id_default = NULL; guint8 *client_id_buf; - gboolean is_mac; + const char *fail_reason; + guint8 hwaddr_bin_buf[NM_UTILS_HWADDR_LEN_MAX]; + const guint8 *hwaddr_bin; + gsize hwaddr_len; + GBytes *result; + gs_free char *logstr1 = NULL; s_ip4 = nm_connection_get_setting_ip4_config (connection); client_id = nm_setting_ip4_config_get_dhcp_client_id (NM_SETTING_IP4_CONFIG (s_ip4)); @@ -7028,42 +7051,54 @@ dhcp4_get_client_id (NMDevice *self, NMConnection *connection) if (!client_id) { client_id_default = nm_config_data_get_connection_default (NM_CONFIG_GET_DATA, "ipv4.dhcp-client-id", self); - if (client_id_default && client_id_default[0]) + if (client_id_default && client_id_default[0]) { + /* a non-empty client-id is always valid, see nm_dhcp_utils_client_id_string_to_bytes(). */ client_id = client_id_default; + } } - if (!client_id) + if (!client_id) { + _LOGD (LOGD_DEVICE | LOGD_DHCP4 | LOGD_IP4, + "ipv4.dhcp-client-id: no explicity client-id configured"); return NULL; + } - if ( (is_mac = nm_streq (client_id, "mac")) - || nm_streq (client_id, "perm-mac")) { - const char *hwaddr; - char addr_buf[NM_UTILS_HWADDR_LEN_MAX]; - gsize addr_len; - guint8 addr_type; - - hwaddr = is_mac - ? nm_device_get_hw_address (self) - : nm_device_get_permanent_hw_address (self); - if (!hwaddr) - return NULL; + if (nm_streq (client_id, "mac")) { + if (!hwaddr) { + fail_reason = "failed to get current MAC address"; + goto out_fail; + } + + hwaddr_bin = g_bytes_get_data (hwaddr, &hwaddr_len); + if (hwaddr_len != ETH_ALEN) { + fail_reason = "MAC address is not ethernet"; + goto out_fail; + } + + result = dhcp4_get_client_id_mac (hwaddr_bin); + goto out_good; + } + + if (nm_streq (client_id, "perm-mac")) { + const char *hwaddr_str; + + hwaddr_str = nm_device_get_permanent_hw_address (self); + if (!hwaddr_str) { + fail_reason = "failed to get permanent MAC address"; + goto out_fail; + } - if (!_nm_utils_hwaddr_aton (hwaddr, addr_buf, sizeof (addr_buf), &addr_len)) + if (!_nm_utils_hwaddr_aton (hwaddr_str, hwaddr_bin_buf, sizeof (hwaddr_bin_buf), &hwaddr_len)) g_return_val_if_reached (NULL); - switch (addr_len) { - case ETH_ALEN: - addr_type = ARPHRD_ETHER; - break; - default: + if (hwaddr_len != ETH_ALEN) { /* unsupported type. */ - return NULL; + fail_reason = "MAC address is not ethernet"; + goto out_fail; } - client_id_buf = g_malloc (addr_len + 1); - client_id_buf[0] = addr_type; - memcpy (&client_id_buf[1], addr_buf, addr_len); - return g_bytes_new_take (client_id_buf, addr_len + 1); + result = dhcp4_get_client_id_mac (hwaddr_bin_buf); + goto out_good; } if (nm_streq (client_id, "stable")) { @@ -7099,10 +7134,30 @@ dhcp4_get_client_id (NMDevice *self, NMConnection *connection) client_id_buf = g_malloc (1 + 15); client_id_buf[0] = 0; memcpy (&client_id_buf[1], buf, 15); - return g_bytes_new_take (client_id_buf, 1 + 15); + result = g_bytes_new_take (client_id_buf, 1 + 15); + goto out_good; } - return nm_dhcp_utils_client_id_string_to_bytes (client_id); + result = nm_dhcp_utils_client_id_string_to_bytes (client_id); + goto out_good; + +out_fail: + nm_assert (fail_reason); + _LOGW (LOGD_DEVICE | LOGD_DHCP4 | LOGD_IP4, + "ipv4.dhcp-client-id: failure to generate client id (%s). Use random client id", + fail_reason); + client_id_buf = g_malloc (1 + 15); + client_id_buf[0] = 0; + nm_utils_random_bytes (&client_id_buf[1], 15); + result = g_bytes_new_take (client_id_buf, 1 + 15); + +out_good: + nm_assert (result); + _LOGD (LOGD_DEVICE | LOGD_DHCP4 | LOGD_IP4, + "ipv4.dhcp-client-id: use \"%s\" client ID: %s", + client_id, + (logstr1 = nm_dhcp_utils_duid_to_string (result))); + return result; } static NMActStageReturn @@ -7126,7 +7181,7 @@ dhcp4_start (NMDevice *self) hwaddr = nm_platform_link_get_address_as_bytes (nm_device_get_platform (self), nm_device_get_ip_ifindex (self)); - client_id = dhcp4_get_client_id (self, connection); + client_id = dhcp4_get_client_id (self, connection, hwaddr); g_warn_if_fail (priv->dhcp4.client == NULL); priv->dhcp4.client = nm_dhcp_manager_start_ip4 (nm_dhcp_manager_get (), @@ -7678,12 +7733,260 @@ dhcp6_prefix_delegated (NMDhcpClient *client, g_signal_emit (self, signals[IP6_PREFIX_DELEGATED], 0, prefix); } +/* RFC 3315 defines the epoch for the DUID-LLT time field on Jan 1st 2000. */ +#define EPOCH_DATETIME_200001010000 946684800 + +static GBytes * +generate_duid_llt (const guint8 *hwaddr /* ETH_ALEN bytes */, + gint64 time) +{ + GByteArray *duid_arr; + const guint16 duid_type = htons (1); + const guint16 hw_type = htons (ARPHRD_ETHER); + const guint32 duid_time = htonl (NM_MAX (0, time - EPOCH_DATETIME_200001010000)); + + duid_arr = g_byte_array_sized_new (2 + 4 + 2 + ETH_ALEN); + + g_byte_array_append (duid_arr, (const guint8 *) &duid_type, 2); + g_byte_array_append (duid_arr, (const guint8 *) &hw_type, 2); + g_byte_array_append (duid_arr, (const guint8 *) &duid_time, 4); + g_byte_array_append (duid_arr, hwaddr, ETH_ALEN); + + return g_byte_array_free_to_bytes (duid_arr); +} + +static GBytes * +generate_duid_ll (const guint8 *hwaddr /* ETH_ALEN bytes */) +{ + GByteArray *duid_arr; + const guint16 duid_type = htons (3); + const guint16 hw_type = htons (ARPHRD_ETHER); + + duid_arr = g_byte_array_sized_new (2 + 2 + ETH_ALEN); + + g_byte_array_append (duid_arr, (const guint8 *) &duid_type, 2); + g_byte_array_append (duid_arr, (const guint8 *) &hw_type, 2); + g_byte_array_append (duid_arr, hwaddr, ETH_ALEN); + + return g_byte_array_free_to_bytes (duid_arr); +} + +static GBytes * +generate_duid_uuid (guint8 *data, gsize data_len) +{ + const guint16 duid_type = g_htons (4); + const int DUID_SIZE = 18; + guint8 *duid_buffer; + + nm_assert (data); + nm_assert (data_len >= 16); + + /* Generate a DHCP Unique Identifier for DHCPv6 using the + * DUID-UUID method (see RFC 6355 section 4). Format is: + * + * u16: type (DUID-UUID = 4) + * u8[16]: UUID bytes + */ + duid_buffer = g_malloc (DUID_SIZE); + + G_STATIC_ASSERT_EXPR (sizeof (duid_type) == 2); + memcpy (&duid_buffer[0], &duid_type, 2); + + /* UUID is 128 bits, we just take the first 128 bits + * (regardless of data size) as the DUID-UUID. + */ + memcpy (&duid_buffer[2], data, 16); + + return g_bytes_new_take (duid_buffer, DUID_SIZE); +} + +static GBytes * +generate_duid_from_machine_id (void) +{ + gs_free const char *machine_id_s = NULL; + uuid_t uuid; + GChecksum *sum; + guint8 sha256_digest[32]; + gsize len = sizeof (sha256_digest); + static GBytes *global_duid = NULL; + + if (global_duid) + return g_bytes_ref (global_duid); + + machine_id_s = nm_utils_machine_id_read (); + if (!nm_utils_machine_id_parse (machine_id_s, uuid)) + return NULL; + + /* Hash the machine ID so it's not leaked to the network */ + sum = g_checksum_new (G_CHECKSUM_SHA256); + g_checksum_update (sum, (const guchar *) &uuid, sizeof (uuid)); + g_checksum_get_digest (sum, sha256_digest, &len); + g_checksum_free (sum); + + global_duid = generate_duid_uuid (sha256_digest, len); + return g_bytes_ref (global_duid); +} + +static GBytes * +dhcp6_get_duid (NMDevice *self, NMConnection *connection, GBytes *hwaddr, NMDhcpDuidEnforce *out_enforce) +{ + NMSettingIPConfig *s_ip6; + const char *duid; + gs_free char *duid_default = NULL; + const char *duid_error; + GBytes *duid_out; + guint8 sha256_digest[32]; + gsize len = sizeof (sha256_digest); + NMDhcpDuidEnforce duid_enforce = NM_DHCP_DUID_ENFORCE_ALWAYS; + gs_free char *logstr1 = NULL; + + s_ip6 = nm_connection_get_setting_ip6_config (connection); + duid = nm_setting_ip6_config_get_dhcp_duid (NM_SETTING_IP6_CONFIG (s_ip6)); + + if (!duid) { + duid_default = nm_config_data_get_connection_default (NM_CONFIG_GET_DATA, + "ipv6.dhcp-duid", self); + duid = duid_default; + if (!duid) + duid = "lease"; + } + + if (nm_streq (duid, "lease")) { + duid_enforce = NM_DHCP_DUID_ENFORCE_NEVER; + duid_out = generate_duid_from_machine_id (); + if (!duid_out) { + duid_error = "failure to read machine-id"; + goto out_fail; + } + goto out_good; + } + + if (!_nm_utils_dhcp_duid_valid (duid, &duid_out)) { + duid_error = "invalid duid"; + goto out_fail; + } + + if (duid_out) + goto out_good; + + if (NM_IN_STRSET (duid, "ll", "llt")) { + if (!hwaddr) { + duid_error = "missing link-layer address"; + goto out_fail; + } + if (g_bytes_get_size (hwaddr) != ETH_ALEN) { + duid_error = "unsupported link-layer address"; + goto out_fail; + } + + if (nm_streq (duid, "ll")) { + duid_out = generate_duid_ll (g_bytes_get_data (hwaddr, NULL)); + } else { + gint64 time; + + time = nm_utils_secret_key_get_timestamp (); + if (!time) { + duid_error = "cannot retrieve the secret key timestamp"; + goto out_fail; + } + + duid_out = generate_duid_llt (g_bytes_get_data (hwaddr, NULL), time); + } + + goto out_good; + } + + if (NM_IN_STRSET (duid, "stable-ll", "stable-llt", "stable-uuid")) { + NMUtilsStableType stable_type; + const char *stable_id = NULL; + guint32 salted_header; + GChecksum *sum; + const guint8 *secret_key; + gsize secret_key_len; + + stable_id = _get_stable_id (self, connection, &stable_type); + if (!stable_id) + g_return_val_if_reached (NULL); + + salted_header = htonl (670531087 + stable_type); + + nm_utils_secret_key_get (&secret_key, &secret_key_len); + + sum = g_checksum_new (G_CHECKSUM_SHA256); + + g_checksum_update (sum, (const guchar *) &salted_header, sizeof (salted_header)); + g_checksum_update (sum, (const guchar *) stable_id, -1); + g_checksum_update (sum, (const guchar *) secret_key, secret_key_len); + + g_checksum_get_digest (sum, sha256_digest, &len); + g_checksum_free (sum); + + if (nm_streq (duid, "stable-ll")) { + duid_out = generate_duid_ll (sha256_digest); + } else if (nm_streq (duid, "stable-llt")) { + gint64 time; + +#define EPOCH_DATETIME_THREE_YEARS (356 * 24 * 3600 * 3) + + /* We want a variable time between the secret_key timestamp and three years + * before. Let's compute the time (in seconds) from 0 to 3 years; then we'll + * subtract it from the secret_key timestamp. + */ + time = nm_utils_secret_key_get_timestamp (); + if (!time) { + duid_error = "cannot retrieve the secret key timestamp"; + goto out_fail; + } + /* don't use too old timestamps. They cannot be expressed in DUID-LLT and + * would all be truncated to zero. */ + time = NM_MAX (time, EPOCH_DATETIME_200001010000 + EPOCH_DATETIME_THREE_YEARS); + time -= (unaligned_read_be32 (&sha256_digest[ETH_ALEN]) % EPOCH_DATETIME_THREE_YEARS); + + duid_out = generate_duid_llt (sha256_digest, time); + } else { + nm_assert (nm_streq (duid, "stable-uuid")); + duid_out = generate_duid_uuid (sha256_digest, len); + } + + goto out_good; + } + + g_return_val_if_reached (NULL); + +out_fail: + nm_assert (!duid_out && duid_error); + { + guint8 uuid[16]; + + _LOGW (LOGD_IP6 | LOGD_DHCP6, + "ipv6.dhcp-duid: failure to generate %s DUID: %s. Fallback to random DUID-UUID.", + duid, duid_error); + + nm_utils_random_bytes (uuid, sizeof (uuid)); + duid_out = generate_duid_uuid (uuid, sizeof (uuid)); + } + +out_good: + nm_assert (duid_out); + _LOGD (LOGD_IP6 | LOGD_DHCP6, + "ipv6.dhcp-duid: generate %s DUID '%s' (%s)", + duid, + (logstr1 = nm_dhcp_utils_duid_to_string (duid_out)), + (duid_enforce == NM_DHCP_DUID_ENFORCE_ALWAYS) ? "enforcing" : "fallback"); + + NM_SET_OUT (out_enforce, duid_enforce); + return duid_out; +} + static gboolean dhcp6_start_with_link_ready (NMDevice *self, NMConnection *connection) { NMDevicePrivate *priv = NM_DEVICE_GET_PRIVATE (self); NMSettingIPConfig *s_ip6; gs_unref_bytes GBytes *hwaddr = NULL; + gs_unref_bytes GBytes *duid = NULL; + NMDhcpDuidEnforce enforce_duid = NM_DHCP_DUID_ENFORCE_NEVER; + const NMPlatformIP6Address *ll_addr = NULL; g_assert (connection); @@ -7704,6 +8007,7 @@ dhcp6_start_with_link_ready (NMDevice *self, NMConnection *connection) hwaddr = nm_platform_link_get_address_as_bytes (nm_device_get_platform (self), nm_device_get_ip_ifindex (self)); + duid = dhcp6_get_duid (self, connection, hwaddr, &enforce_duid); priv->dhcp6.client = nm_dhcp_manager_start_ip6 (nm_dhcp_manager_get (), nm_device_get_multi_index (self), nm_device_get_ip_iface (self), @@ -7715,6 +8019,8 @@ dhcp6_start_with_link_ready (NMDevice *self, NMConnection *connection) nm_device_get_route_metric (self, AF_INET6), nm_setting_ip_config_get_dhcp_send_hostname (s_ip6), nm_setting_ip_config_get_dhcp_hostname (s_ip6), + duid, + enforce_duid, get_dhcp_timeout (self, AF_INET6), priv->dhcp_anycast_address, (priv->dhcp6.mode == NM_NDISC_DHCP_LEVEL_OTHERCONF) ? TRUE : FALSE, @@ -8139,8 +8445,10 @@ _commit_mtu (NMDevice *self, const NMIP4Config *config) if (ifindex <= 0) return; - if (nm_device_sys_iface_state_is_external_or_assume (self)) { - /* for assumed connections we don't tamper with the MTU. */ + if ( !nm_device_get_applied_connection (self) + || nm_device_sys_iface_state_is_external_or_assume (self)) { + /* we don't tamper with the MTU of disconnected and + * external/assumed devices. */ return; } @@ -9886,43 +10194,45 @@ _cleanup_ip_pre (NMDevice *self, int addr_family, CleanupType cleanup_type) gboolean _nm_device_hash_check_invalid_keys (GHashTable *hash, const char *setting_name, - GError **error, const char **argv) + GError **error, const char **whitelist) { - guint found_keys = 0; + guint found_whitelisted_keys = 0; guint i; nm_assert (hash && g_hash_table_size (hash) > 0); - nm_assert (argv && argv[0]); + nm_assert (whitelist && whitelist[0]); #if NM_MORE_ASSERTS > 10 - /* Assert that the keys are unique. */ + /* Require whitelist to only contain unique keys. */ { gs_unref_hashtable GHashTable *check_dups = g_hash_table_new_full (nm_str_hash, g_str_equal, NULL, NULL); - for (i = 0; argv[i]; i++) { - if (!g_hash_table_add (check_dups, (char *) argv[i])) + for (i = 0; whitelist[i]; i++) { + if (!g_hash_table_add (check_dups, (char *) whitelist[i])) nm_assert (FALSE); } nm_assert (g_hash_table_size (check_dups) > 0); } #endif - for (i = 0; argv[i]; i++) { - if (g_hash_table_contains (hash, argv[i])) - found_keys++; + for (i = 0; whitelist[i]; i++) { + if (g_hash_table_contains (hash, whitelist[i])) + found_whitelisted_keys++; } - if (found_keys != g_hash_table_size (hash)) { + if (found_whitelisted_keys == g_hash_table_size (hash)) { + /* Good, there are only whitelisted keys in the hash. */ + return TRUE; + } + + if (error) { GHashTableIter iter; const char *k = NULL; const char *first_invalid_key = NULL; - if (!error) - return FALSE; - g_hash_table_iter_init (&iter, hash); while (g_hash_table_iter_next (&iter, (gpointer *) &k, NULL)) { - if (nm_utils_strv_find_first ((char **) argv, -1, k) < 0) { + if (nm_utils_strv_find_first ((char **) whitelist, -1, k) < 0) { first_invalid_key = k; break; } @@ -9942,10 +10252,9 @@ _nm_device_hash_check_invalid_keys (GHashTable *hash, const char *setting_name, first_invalid_key); } g_return_val_if_fail (first_invalid_key, FALSE); - return FALSE; } - return TRUE; + return FALSE; } void @@ -10088,9 +10397,11 @@ can_reapply_change (NMDevice *self, const char *setting_name, NM_SETTING_CONNECTION_METERED, NM_SETTING_CONNECTION_LLDP); } else if (NM_IN_STRSET (setting_name, - NM_SETTING_IP4_CONFIG_SETTING_NAME, - NM_SETTING_IP6_CONFIG_SETTING_NAME, NM_SETTING_PROXY_SETTING_NAME)) { + return TRUE; + } else if (NM_IN_STRSET (setting_name, + NM_SETTING_IP4_CONFIG_SETTING_NAME, + NM_SETTING_IP6_CONFIG_SETTING_NAME)) { if (g_hash_table_contains (diffs, NM_SETTING_IP_CONFIG_ROUTE_TABLE)) { /* changing the route-table setting is complicated, because it affects * how we sync the routes. Don't support changing it without full @@ -10221,7 +10532,7 @@ check_and_reapply_connection (NMDevice *self, if (diffs) { NMConnection *connection_clean = connection; - gs_free NMConnection *connection_clean_free = NULL; + gs_unref_object NMConnection *connection_clean_free = NULL; { NMSettingConnection *s_con_a, *s_con_n; diff --git a/src/devices/ovs/nm-device-ovs-interface.c b/src/devices/ovs/nm-device-ovs-interface.c index eefe38c8..c59af7a6 100644 --- a/src/devices/ovs/nm-device-ovs-interface.c +++ b/src/devices/ovs/nm-device-ovs-interface.c @@ -116,7 +116,7 @@ link_changed (NMDevice *device, { NMDeviceOvsInterfacePrivate *priv = NM_DEVICE_OVS_INTERFACE_GET_PRIVATE (device); - if (priv->waiting_for_interface) { + if (pllink && priv->waiting_for_interface) { priv->waiting_for_interface = FALSE; nm_device_bring_up (device, TRUE, NULL); nm_device_activate_schedule_stage3_ip_config_start (device); diff --git a/src/devices/wifi/nm-device-iwd.c b/src/devices/wifi/nm-device-iwd.c index d3c5ae9a..d28fcdbd 100644 --- a/src/devices/wifi/nm-device-iwd.c +++ b/src/devices/wifi/nm-device-iwd.c @@ -54,6 +54,7 @@ NM_GOBJECT_PROPERTIES_DEFINE (NMDeviceIwd, PROP_ACTIVE_ACCESS_POINT, PROP_CAPABILITIES, PROP_SCANNING, + PROP_LAST_SCAN, ); enum { @@ -79,6 +80,7 @@ typedef struct { bool can_connect:1; bool scanning:1; bool scan_requested:1; + gint64 last_scan; } NMDeviceIwdPrivate; struct _NMDeviceIwd { @@ -863,6 +865,8 @@ scan_cb (GObject *source, GAsyncResult *res, gpointer user_data) priv = NM_DEVICE_IWD_GET_PRIVATE (self); priv->scan_requested = FALSE; + priv->last_scan = nm_utils_get_monotonic_timestamp_ms (); + _notify (self, PROP_LAST_SCAN); /* On success, priv->scanning becomes true right before or right * after this callback, so the next automatic scan will be @@ -1530,6 +1534,12 @@ get_property (GObject *object, guint prop_id, case PROP_SCANNING: g_value_set_boolean (value, priv->scanning); break; + case PROP_LAST_SCAN: + g_value_set_int64 (value, + priv->last_scan > 0 + ? nm_utils_monotonic_timestamp_as_boottime (priv->last_scan, NM_UTILS_NS_PER_MSEC) + : (gint64) -1); + break; default: G_OBJECT_WARN_INVALID_PROPERTY_ID (object, prop_id, pspec); break; @@ -1909,6 +1919,11 @@ nm_device_iwd_class_init (NMDeviceIwdClass *klass) G_PARAM_READABLE | G_PARAM_STATIC_STRINGS); + obj_properties[PROP_LAST_SCAN] = + g_param_spec_int64 (NM_DEVICE_IWD_LAST_SCAN, "", "", + -1, G_MAXINT64, -1, + G_PARAM_READABLE | G_PARAM_STATIC_STRINGS); + g_object_class_install_properties (object_class, _PROPERTY_ENUMS_LAST, obj_properties); signals[SCANNING_PROHIBITED] = diff --git a/src/devices/wifi/nm-device-iwd.h b/src/devices/wifi/nm-device-iwd.h index 699ba1bb..a4253f52 100644 --- a/src/devices/wifi/nm-device-iwd.h +++ b/src/devices/wifi/nm-device-iwd.h @@ -38,6 +38,7 @@ #define NM_DEVICE_IWD_ACTIVE_ACCESS_POINT NM_DEVICE_WIFI_ACTIVE_ACCESS_POINT #define NM_DEVICE_IWD_CAPABILITIES NM_DEVICE_WIFI_CAPABILITIES #define NM_DEVICE_IWD_SCANNING NM_DEVICE_WIFI_SCANNING +#define NM_DEVICE_IWD_LAST_SCAN NM_DEVICE_WIFI_LAST_SCAN #define NM_DEVICE_IWD_SCANNING_PROHIBITED NM_DEVICE_WIFI_SCANNING_PROHIBITED diff --git a/src/devices/wifi/nm-device-wifi.c b/src/devices/wifi/nm-device-wifi.c index 90f94557..1a86e13b 100644 --- a/src/devices/wifi/nm-device-wifi.c +++ b/src/devices/wifi/nm-device-wifi.c @@ -74,6 +74,7 @@ NM_GOBJECT_PROPERTIES_DEFINE (NMDeviceWifi, PROP_ACTIVE_ACCESS_POINT, PROP_CAPABILITIES, PROP_SCANNING, + PROP_LAST_SCAN, ); enum { @@ -96,8 +97,8 @@ typedef struct { bool ssid_found:1; bool is_scanning:1; - gint32 last_scan; - gint32 scheduled_scan_time; + gint64 last_scan; /* milliseconds */ + gint32 scheduled_scan_time; /* seconds */ guint8 scan_interval; /* seconds */ guint pending_scan_id; guint ap_dump_id; @@ -1126,7 +1127,7 @@ _nm_device_wifi_request_scan (NMDeviceWifi *self, { NMDeviceWifiPrivate *priv = NM_DEVICE_WIFI_GET_PRIVATE (self); NMDevice *device = NM_DEVICE (self); - gint32 last_scan; + gint64 last_scan; if ( !priv->enabled || !priv->sup_iface @@ -1147,8 +1148,8 @@ _nm_device_wifi_request_scan (NMDeviceWifi *self, return; } - last_scan = nm_supplicant_interface_get_last_scan_time (priv->sup_iface); - if (last_scan && (nm_utils_get_monotonic_timestamp_s () - last_scan) < 10) { + last_scan = nm_supplicant_interface_get_last_scan (priv->sup_iface); + if (last_scan && (nm_utils_get_monotonic_timestamp_ms () - last_scan) < 10 * NM_UTILS_MSEC_PER_SECOND) { g_dbus_method_invocation_return_error_literal (invocation, NM_DEVICE_ERROR, NM_DEVICE_ERROR_NOT_ALLOWED, @@ -1422,7 +1423,8 @@ supplicant_iface_scan_done_cb (NMSupplicantInterface *iface, _LOGD (LOGD_WIFI, "wifi-scan: scan-done callback: %s", success ? "successful" : "failed"); - priv->last_scan = nm_utils_get_monotonic_timestamp_s (); + priv->last_scan = nm_utils_get_monotonic_timestamp_ms (); + _notify (self, PROP_LAST_SCAN); schedule_scan (self, success); _requested_scan_set (self, FALSE); @@ -1445,9 +1447,9 @@ ap_list_dump (gpointer user_data) NMWifiAP *ap; gint32 now_s = nm_utils_get_monotonic_timestamp_s (); - _LOGD (LOGD_WIFI_SCAN, "APs: [now:%u last:%u next:%u]", + _LOGD (LOGD_WIFI_SCAN, "APs: [now:%u last:%" G_GINT64_FORMAT " next:%u]", now_s, - priv->last_scan, + priv->last_scan / NM_UTILS_MSEC_PER_SECOND, priv->scheduled_scan_time); c_list_for_each_entry (ap, &priv->aps_lst_head, aps_lst) _ap_dump (self, LOGL_DEBUG, ap, "dump", now_s); @@ -2421,6 +2423,48 @@ error: /*****************************************************************************/ +static gboolean +wake_on_wlan_enable (NMDeviceWifi *self) +{ + NMSettingWirelessWakeOnWLan wowl; + NMSettingWireless *s_wireless; + gs_free char *value = NULL; + + s_wireless = (NMSettingWireless *) nm_device_get_applied_setting (NM_DEVICE (self), NM_TYPE_SETTING_WIRELESS); + if (s_wireless) { + wowl = nm_setting_wireless_get_wake_on_wlan (s_wireless); + if (wowl != NM_SETTING_WIRELESS_WAKE_ON_WLAN_DEFAULT) + goto found; + } + + value = nm_config_data_get_connection_default (NM_CONFIG_GET_DATA, + "wifi.wake-on-wlan", + NM_DEVICE (self)); + + if (value) { + wowl = _nm_utils_ascii_str_to_int64 (value, 10, + NM_SETTING_WIRELESS_WAKE_ON_WLAN_NONE, + G_MAXINT32, + NM_SETTING_WIRELESS_WAKE_ON_WLAN_DEFAULT); + + if (NM_FLAGS_ANY (wowl, NM_SETTING_WIRELESS_WAKE_ON_WLAN_EXCLUSIVE_FLAGS)) { + if (!nm_utils_is_power_of_two (wowl)) { + _LOGD (LOGD_WIFI, "invalid default value %u for wake-on-wlan: " + "'default' and 'ignore' are exclusive flags", (guint) wowl); + wowl = NM_SETTING_WIRELESS_WAKE_ON_WLAN_DEFAULT; + } + } else if (NM_FLAGS_ANY (wowl, ~NM_SETTING_WIRELESS_WAKE_ON_WLAN_ALL)) { + _LOGD (LOGD_WIFI, "invalid default value %u for wake-on-wlan", (guint) wowl); + wowl = NM_SETTING_WIRELESS_WAKE_ON_WLAN_DEFAULT; + } + if (wowl != NM_SETTING_WIRELESS_WAKE_ON_WLAN_DEFAULT) + goto found; + } + wowl = NM_SETTING_WIRELESS_WAKE_ON_WLAN_IGNORE; +found: + return nm_platform_wifi_set_wake_on_wlan (NM_PLATFORM_GET, nm_device_get_ifindex (NM_DEVICE (self)), wowl); +} + static NMActStageReturn act_stage1_prepare (NMDevice *device, NMDeviceStateReason *out_failure_reason) { @@ -2614,6 +2658,8 @@ act_stage2_config (NMDevice *device, NMDeviceStateReason *out_failure_reason) s_wireless = nm_connection_get_setting_wireless (connection); g_assert (s_wireless); + wake_on_wlan_enable (self); + /* If we need secrets, get them */ setting_name = nm_connection_need_secrets (connection, NULL); if (setting_name) { @@ -3081,7 +3127,8 @@ can_reapply_change (NMDevice *device, return nm_device_hash_check_invalid_keys (diffs, NM_SETTING_WIRELESS_SETTING_NAME, error, - NM_SETTING_WIRELESS_MTU); /* reapplied with IP config */ + NM_SETTING_WIRELESS_MTU, /* reapplied with IP config */ + NM_SETTING_WIRELESS_WAKE_ON_WLAN); } device_class = NM_DEVICE_CLASS (nm_device_wifi_parent_class); @@ -3093,6 +3140,20 @@ can_reapply_change (NMDevice *device, error); } +static void +reapply_connection (NMDevice *device, NMConnection *con_old, NMConnection *con_new) +{ + NMDeviceWifi *self = NM_DEVICE_WIFI (device); + + NM_DEVICE_CLASS (nm_device_wifi_parent_class)->reapply_connection (device, + con_old, + con_new); + + _LOGD (LOGD_DEVICE, "reapplying wireless settings"); + + wake_on_wlan_enable (self); +} + /*****************************************************************************/ static void @@ -3123,6 +3184,12 @@ get_property (GObject *object, guint prop_id, case PROP_SCANNING: g_value_set_boolean (value, priv->is_scanning); break; + case PROP_LAST_SCAN: + g_value_set_int64 (value, + priv->last_scan > 0 + ? nm_utils_monotonic_timestamp_as_boottime (priv->last_scan, NM_UTILS_NS_PER_MSEC) + : (gint64) -1); + break; default: G_OBJECT_WARN_INVALID_PROPERTY_ID (object, prop_id, pspec); break; @@ -3256,6 +3323,7 @@ nm_device_wifi_class_init (NMDeviceWifiClass *klass) parent_class->deactivate_reset_hw_addr = deactivate_reset_hw_addr; parent_class->unmanaged_on_quit = unmanaged_on_quit; parent_class->can_reapply_change = can_reapply_change; + parent_class->reapply_connection = reapply_connection; parent_class->state_changed = device_state_changed; @@ -3300,6 +3368,11 @@ nm_device_wifi_class_init (NMDeviceWifiClass *klass) G_PARAM_READABLE | G_PARAM_STATIC_STRINGS); + obj_properties[PROP_LAST_SCAN] = + g_param_spec_int64 (NM_DEVICE_WIFI_LAST_SCAN, "", "", + -1, G_MAXINT64, -1, + G_PARAM_READABLE | G_PARAM_STATIC_STRINGS); + g_object_class_install_properties (object_class, _PROPERTY_ENUMS_LAST, obj_properties); signals[SCANNING_PROHIBITED] = diff --git a/src/devices/wifi/nm-device-wifi.h b/src/devices/wifi/nm-device-wifi.h index c13b00de..1c555f5f 100644 --- a/src/devices/wifi/nm-device-wifi.h +++ b/src/devices/wifi/nm-device-wifi.h @@ -37,6 +37,7 @@ #define NM_DEVICE_WIFI_ACTIVE_ACCESS_POINT "active-access-point" #define NM_DEVICE_WIFI_CAPABILITIES "wireless-capabilities" #define NM_DEVICE_WIFI_SCANNING "scanning" +#define NM_DEVICE_WIFI_LAST_SCAN "last-scan" #define NM_DEVICE_WIFI_SCANNING_PROHIBITED "scanning-prohibited" diff --git a/src/devices/wifi/nm-wifi-common.c b/src/devices/wifi/nm-wifi-common.c index e5e16f03..8e079d11 100644 --- a/src/devices/wifi/nm-wifi-common.c +++ b/src/devices/wifi/nm-wifi-common.c @@ -200,6 +200,7 @@ const NMDBusInterfaceInfoExtended nm_interface_info_device_wireless = { NM_DEFINE_DBUS_PROPERTY_INFO_EXTENDED_READABLE_L ("AccessPoints", "ao", NM_DEVICE_WIFI_ACCESS_POINTS), NM_DEFINE_DBUS_PROPERTY_INFO_EXTENDED_READABLE_L ("ActiveAccessPoint", "o", NM_DEVICE_WIFI_ACTIVE_ACCESS_POINT), NM_DEFINE_DBUS_PROPERTY_INFO_EXTENDED_READABLE_L ("WirelessCapabilities", "u", NM_DEVICE_WIFI_CAPABILITIES), + NM_DEFINE_DBUS_PROPERTY_INFO_EXTENDED_READABLE ("LastScan", "x", NM_DEVICE_WIFI_LAST_SCAN), ), ), .legacy_property_changed = TRUE, diff --git a/src/devices/wwan/nm-device-modem.c b/src/devices/wwan/nm-device-modem.c index 2a3e9ebe..352b1c3e 100644 --- a/src/devices/wwan/nm-device-modem.c +++ b/src/devices/wwan/nm-device-modem.c @@ -542,7 +542,7 @@ act_stage3_ip6_config_start (NMDevice *device, NMDeviceStateReason *out_failure_reason) { return nm_modem_stage3_ip6_config_start (NM_DEVICE_MODEM_GET_PRIVATE ((NMDeviceModem *) device)->modem, - nm_device_get_act_request (device), + device, out_failure_reason); } diff --git a/src/devices/wwan/nm-modem.c b/src/devices/wwan/nm-modem.c index fbe99cc3..ff1579d1 100644 --- a/src/devices/wwan/nm-modem.c +++ b/src/devices/wwan/nm-modem.c @@ -704,6 +704,8 @@ nm_modem_stage3_ip4_config_start (NMModem *self, connection = nm_act_request_get_applied_connection (req); g_return_val_if_fail (connection, NM_ACT_STAGE_RETURN_FAILURE); + nm_modem_set_route_parameters_from_device (self, device); + method = nm_utils_get_ip_config_method (connection, NM_TYPE_SETTING_IP4_CONFIG); /* Only Disabled and Auto methods make sense for WWAN */ @@ -745,8 +747,6 @@ nm_modem_ip4_pre_commit (NMModem *modem, { NMModemPrivate *priv = NM_MODEM_GET_PRIVATE (modem); - nm_modem_set_route_parameters_from_device (modem, device); - /* If the modem has an ethernet-type data interface (ie, not PPP and thus * not point-to-point) and IP config has a /32 prefix, then we assume that * ARP will be pointless and we turn it off. @@ -804,20 +804,25 @@ stage3_ip6_config_request (NMModem *self, NMDeviceStateReason *out_failure_reaso NMActStageReturn nm_modem_stage3_ip6_config_start (NMModem *self, - NMActRequest *req, + NMDevice *device, NMDeviceStateReason *out_failure_reason) { NMModemPrivate *priv; + NMActRequest *req; NMActStageReturn ret; NMConnection *connection; const char *method; g_return_val_if_fail (NM_IS_MODEM (self), NM_ACT_STAGE_RETURN_FAILURE); - g_return_val_if_fail (NM_IS_ACT_REQUEST (req), NM_ACT_STAGE_RETURN_FAILURE); + + req = nm_device_get_act_request (device); + g_return_val_if_fail (req, NM_ACT_STAGE_RETURN_FAILURE); connection = nm_act_request_get_applied_connection (req); g_return_val_if_fail (connection, NM_ACT_STAGE_RETURN_FAILURE); + nm_modem_set_route_parameters_from_device (self, device); + method = nm_utils_get_ip_config_method (connection, NM_TYPE_SETTING_IP6_CONFIG); /* Only Ignore and Auto methods make sense for WWAN */ diff --git a/src/devices/wwan/nm-modem.h b/src/devices/wwan/nm-modem.h index 3e281c0c..6e78d2d5 100644 --- a/src/devices/wwan/nm-modem.h +++ b/src/devices/wwan/nm-modem.h @@ -221,7 +221,7 @@ NMActStageReturn nm_modem_stage3_ip4_config_start (NMModem *modem, NMDeviceStateReason *out_failure_reason); NMActStageReturn nm_modem_stage3_ip6_config_start (NMModem *modem, - NMActRequest *req, + NMDevice *device, NMDeviceStateReason *out_failure_reason); void nm_modem_ip4_pre_commit (NMModem *modem, NMDevice *device, NMIP4Config *config); |