diff options
| author | Michael Biebl <biebl@debian.org> | 2019-07-31 10:51:42 +0200 |
|---|---|---|
| committer | Michael Biebl <biebl@debian.org> | 2019-07-31 10:51:42 +0200 |
| commit | 2e5fa45ddfbb5cffa1e78221f1cea706e2f298af (patch) | |
| tree | 86f69d36c56de3074280456eddc854a780b8e04b /src/devices | |
| parent | 85563b7fc7ec2cd21e38debb9b28db342e2e8e7c (diff) | |
New upstream version 1.19.90 upstream/1.19.90
Diffstat (limited to 'src/devices')
102 files changed, 1737 insertions, 617 deletions
diff --git a/src/devices/adsl/nm-atm-manager.c b/src/devices/adsl/nm-atm-manager.c index f312b5a3..bc0bf5c6 100644 --- a/src/devices/adsl/nm-atm-manager.c +++ b/src/devices/adsl/nm-atm-manager.c @@ -1,4 +1,3 @@ -/* -*- Mode: C; tab-width: 4; indent-tabs-mode: t; c-basic-offset: 4 -*- */ /* NetworkManager -- Network link manager * * This program is free software; you can redistribute it and/or modify diff --git a/src/devices/adsl/nm-device-adsl.c b/src/devices/adsl/nm-device-adsl.c index b3b87dc7..59c87851 100644 --- a/src/devices/adsl/nm-device-adsl.c +++ b/src/devices/adsl/nm-device-adsl.c @@ -1,4 +1,3 @@ -/* -*- Mode: C; tab-width: 4; indent-tabs-mode: t; c-basic-offset: 4 -*- */ /* NetworkManager -- Network link manager * * This program is free software; you can redistribute it and/or modify @@ -131,6 +130,7 @@ complete_connection (NMDevice *device, NULL, _("ADSL connection"), NULL, + NULL, FALSE); /* No IPv6 yet by default */ return TRUE; } @@ -487,9 +487,9 @@ act_stage3_ip4_config_start (NMDevice *device, if (priv->ppp_manager) { nm_ppp_manager_set_route_parameters (priv->ppp_manager, - nm_device_get_route_table (device, AF_INET, TRUE), + nm_device_get_route_table (device, AF_INET), nm_device_get_route_metric (device, AF_INET), - nm_device_get_route_table (device, AF_INET6, TRUE), + nm_device_get_route_table (device, AF_INET6), nm_device_get_route_metric (device, AF_INET6)); } diff --git a/src/devices/adsl/nm-device-adsl.h b/src/devices/adsl/nm-device-adsl.h index 351c8e7a..2d3a9fc7 100644 --- a/src/devices/adsl/nm-device-adsl.h +++ b/src/devices/adsl/nm-device-adsl.h @@ -1,4 +1,3 @@ -/* -*- Mode: C; tab-width: 4; indent-tabs-mode: t; c-basic-offset: 4 -*- */ /* NetworkManager -- Network link manager * * This program is free software; you can redistribute it and/or modify diff --git a/src/devices/bluetooth/nm-bluez-common.h b/src/devices/bluetooth/nm-bluez-common.h index d72bea81..956375bb 100644 --- a/src/devices/bluetooth/nm-bluez-common.h +++ b/src/devices/bluetooth/nm-bluez-common.h @@ -1,4 +1,3 @@ -/* -*- Mode: C; tab-width: 4; indent-tabs-mode: t; c-basic-offset: 4 -*- */ /* NetworkManager -- Network link manager * * This program is free software; you can redistribute it and/or modify diff --git a/src/devices/bluetooth/nm-bluez-device.c b/src/devices/bluetooth/nm-bluez-device.c index 377ee478..fb0a72c4 100644 --- a/src/devices/bluetooth/nm-bluez-device.c +++ b/src/devices/bluetooth/nm-bluez-device.c @@ -1,4 +1,3 @@ -/* -*- Mode: C; tab-width: 4; indent-tabs-mode: t; c-basic-offset: 4 -*- */ /* NetworkManager -- Network link manager * * This program is free software; you can redistribute it and/or modify @@ -236,15 +235,18 @@ pan_connection_check_create (NMBluezDevice *self) * which then already finds the suitable connection in priv->connections. This is confusing, * so block the signal. check_emit_usable will succeed after this function call returns. */ g_signal_handlers_block_by_func (priv->settings, cp_connection_added, self); - added = nm_settings_add_connection (priv->settings, connection, FALSE, &error); + nm_settings_add_connection (priv->settings, + connection, + NM_SETTINGS_CONNECTION_PERSIST_MODE_IN_MEMORY_ONLY, + NM_SETTINGS_CONNECTION_ADD_REASON_NONE, + NM_SETTINGS_CONNECTION_INT_FLAGS_NM_GENERATED, + &added, + &error); g_signal_handlers_unblock_by_func (priv->settings, cp_connection_added, self); if (added) { nm_assert (!g_slist_find (priv->connections, added)); nm_assert (connection_compatible (self, added)); - - nm_settings_connection_set_flags (added, NM_SETTINGS_CONNECTION_INT_FLAGS_NM_GENERATED, TRUE); - priv->connections = g_slist_prepend (priv->connections, g_object_ref (added)); priv->pan_connection = added; nm_log_dbg (LOGD_BT, "bluez[%s] added new Bluetooth connection for NAP device: '%s' (%s)", priv->path, id, uuid); @@ -393,7 +395,7 @@ cp_connection_removed (NMSettings *settings, static void cp_connection_updated (NMSettings *settings, NMSettingsConnection *sett_conn, - gboolean by_user, + guint update_reason_u, NMBluezDevice *self) { if (_internal_track_connection (self, sett_conn, @@ -1226,7 +1228,7 @@ dispose (GObject *object) if (to_delete) { nm_log_dbg (LOGD_BT, "bluez[%s] removing Bluetooth connection for NAP device: '%s' (%s)", priv->path, nm_settings_connection_get_id (to_delete), nm_settings_connection_get_uuid (to_delete)); - nm_settings_connection_delete (to_delete, NULL); + nm_settings_connection_delete (to_delete, FALSE); g_object_unref (to_delete); } diff --git a/src/devices/bluetooth/nm-bluez-device.h b/src/devices/bluetooth/nm-bluez-device.h index d2d0beb0..e8dd2ced 100644 --- a/src/devices/bluetooth/nm-bluez-device.h +++ b/src/devices/bluetooth/nm-bluez-device.h @@ -1,4 +1,3 @@ -/* -*- Mode: C; tab-width: 4; indent-tabs-mode: t; c-basic-offset: 4 -*- */ /* NetworkManager -- Network link manager * * This program is free software; you can redistribute it and/or modify diff --git a/src/devices/bluetooth/nm-bluez-manager.c b/src/devices/bluetooth/nm-bluez-manager.c index 9cd3a519..7577ab8b 100644 --- a/src/devices/bluetooth/nm-bluez-manager.c +++ b/src/devices/bluetooth/nm-bluez-manager.c @@ -1,4 +1,3 @@ -/* -*- Mode: C; tab-width: 4; indent-tabs-mode: t; c-basic-offset: 4 -*- */ /* NetworkManager -- Network link manager * * This program is free software; you can redistribute it and/or modify diff --git a/src/devices/bluetooth/nm-bluez4-adapter.c b/src/devices/bluetooth/nm-bluez4-adapter.c index 3a456deb..bd230e90 100644 --- a/src/devices/bluetooth/nm-bluez4-adapter.c +++ b/src/devices/bluetooth/nm-bluez4-adapter.c @@ -1,4 +1,3 @@ -/* -*- Mode: C; tab-width: 4; indent-tabs-mode: t; c-basic-offset: 4 -*- */ /* NetworkManager -- Network link manager * * This program is free software; you can redistribute it and/or modify diff --git a/src/devices/bluetooth/nm-bluez4-adapter.h b/src/devices/bluetooth/nm-bluez4-adapter.h index 0aa4ff91..82bd2de8 100644 --- a/src/devices/bluetooth/nm-bluez4-adapter.h +++ b/src/devices/bluetooth/nm-bluez4-adapter.h @@ -1,4 +1,3 @@ -/* -*- Mode: C; tab-width: 4; indent-tabs-mode: t; c-basic-offset: 4 -*- */ /* NetworkManager -- Network link manager * * This program is free software; you can redistribute it and/or modify diff --git a/src/devices/bluetooth/nm-bluez4-manager.c b/src/devices/bluetooth/nm-bluez4-manager.c index 82d995be..8327776d 100644 --- a/src/devices/bluetooth/nm-bluez4-manager.c +++ b/src/devices/bluetooth/nm-bluez4-manager.c @@ -1,4 +1,3 @@ -/* -*- Mode: C; tab-width: 4; indent-tabs-mode: t; c-basic-offset: 4 -*- */ /* NetworkManager -- Network link manager * * This program is free software; you can redistribute it and/or modify diff --git a/src/devices/bluetooth/nm-bluez5-dun.c b/src/devices/bluetooth/nm-bluez5-dun.c index ff3a0da9..04859f9a 100644 --- a/src/devices/bluetooth/nm-bluez5-dun.c +++ b/src/devices/bluetooth/nm-bluez5-dun.c @@ -1,4 +1,3 @@ -/* -*- Mode: C; tab-width: 4; indent-tabs-mode: t; c-basic-offset: 4 -*- */ /* NetworkManager -- Network link manager * * This program is free software; you can redistribute it and/or modify diff --git a/src/devices/bluetooth/nm-bluez5-dun.h b/src/devices/bluetooth/nm-bluez5-dun.h index b75e4399..b605414b 100644 --- a/src/devices/bluetooth/nm-bluez5-dun.h +++ b/src/devices/bluetooth/nm-bluez5-dun.h @@ -1,4 +1,3 @@ -/* -*- Mode: C; tab-width: 4; indent-tabs-mode: t; c-basic-offset: 4 -*- */ /* NetworkManager -- Network link manager * * This program is free software; you can redistribute it and/or modify diff --git a/src/devices/bluetooth/nm-bluez5-manager.c b/src/devices/bluetooth/nm-bluez5-manager.c index be15d824..7bcd04e5 100644 --- a/src/devices/bluetooth/nm-bluez5-manager.c +++ b/src/devices/bluetooth/nm-bluez5-manager.c @@ -1,4 +1,3 @@ -/* -*- Mode: C; tab-width: 4; indent-tabs-mode: t; c-basic-offset: 4 -*- */ /* NetworkManager -- Network link manager * * This program is free software; you can redistribute it and/or modify diff --git a/src/devices/bluetooth/nm-bluez5-manager.h b/src/devices/bluetooth/nm-bluez5-manager.h index 43694435..14ac842e 100644 --- a/src/devices/bluetooth/nm-bluez5-manager.h +++ b/src/devices/bluetooth/nm-bluez5-manager.h @@ -1,4 +1,3 @@ -/* -*- Mode: C; tab-width: 4; indent-tabs-mode: t; c-basic-offset: 4 -*- */ /* NetworkManager -- Network link manager * * This program is free software; you can redistribute it and/or modify diff --git a/src/devices/bluetooth/nm-bt-error.c b/src/devices/bluetooth/nm-bt-error.c index 66c65b6d..bc9e5aa4 100644 --- a/src/devices/bluetooth/nm-bt-error.c +++ b/src/devices/bluetooth/nm-bt-error.c @@ -1,4 +1,3 @@ -/* -*- Mode: C; tab-width: 4; indent-tabs-mode: t; c-basic-offset: 4 -*- */ /* NetworkManager -- Network link manager * * This program is free software; you can redistribute it and/or modify diff --git a/src/devices/bluetooth/nm-bt-error.h b/src/devices/bluetooth/nm-bt-error.h index fa3a9570..ed7ed90d 100644 --- a/src/devices/bluetooth/nm-bt-error.h +++ b/src/devices/bluetooth/nm-bt-error.h @@ -1,4 +1,3 @@ -/* -*- Mode: C; tab-width: 4; indent-tabs-mode: t; c-basic-offset: 4 -*- */ /* NetworkManager -- Network link manager * * This program is free software; you can redistribute it and/or modify diff --git a/src/devices/bluetooth/nm-device-bt.c b/src/devices/bluetooth/nm-device-bt.c index e79251ce..0853c926 100644 --- a/src/devices/bluetooth/nm-device-bt.c +++ b/src/devices/bluetooth/nm-device-bt.c @@ -1,4 +1,3 @@ -/* -*- Mode: C; tab-width: 4; indent-tabs-mode: t; c-basic-offset: 4 -*- */ /* NetworkManager -- Network link manager * * This program is free software; you can redistribute it and/or modify @@ -341,6 +340,7 @@ complete_connection (NMDevice *device, preferred, fallback_prefix, NULL, + NULL, is_dun ? FALSE : TRUE); /* No IPv6 yet for DUN */ setting_bdaddr = nm_setting_bluetooth_get_bdaddr (s_bt); diff --git a/src/devices/bluetooth/nm-device-bt.h b/src/devices/bluetooth/nm-device-bt.h index b90dbd2a..6c8a5773 100644 --- a/src/devices/bluetooth/nm-device-bt.h +++ b/src/devices/bluetooth/nm-device-bt.h @@ -1,4 +1,3 @@ -/* -*- Mode: C; tab-width: 4; indent-tabs-mode: t; c-basic-offset: 4 -*- */ /* NetworkManager -- Network link manager * * This program is free software; you can redistribute it and/or modify diff --git a/src/devices/nm-acd-manager.c b/src/devices/nm-acd-manager.c index f437ce3a..16d3df8a 100644 --- a/src/devices/nm-acd-manager.c +++ b/src/devices/nm-acd-manager.c @@ -1,4 +1,3 @@ -/* -*- Mode: C; tab-width: 4; indent-tabs-mode: t; c-basic-offset: 4 -*- */ /* NetworkManager -- Network link manager * * This program is free software; you can redistribute it and/or modify diff --git a/src/devices/nm-acd-manager.h b/src/devices/nm-acd-manager.h index 08c0b798..53c88e4b 100644 --- a/src/devices/nm-acd-manager.h +++ b/src/devices/nm-acd-manager.h @@ -1,4 +1,3 @@ -/* -*- Mode: C; tab-width: 4; indent-tabs-mode: t; c-basic-offset: 4 -*- */ /* NetworkManager -- Network link manager * * This program is free software; you can redistribute it and/or modify diff --git a/src/devices/nm-device-6lowpan.c b/src/devices/nm-device-6lowpan.c index 40103747..7a279431 100644 --- a/src/devices/nm-device-6lowpan.c +++ b/src/devices/nm-device-6lowpan.c @@ -190,6 +190,7 @@ complete_connection (NMDevice *device, NULL, _("6LOWPAN connection"), NULL, + NULL, TRUE); s_6lowpan = NM_SETTING_6LOWPAN (nm_connection_get_setting (connection, NM_TYPE_SETTING_6LOWPAN)); diff --git a/src/devices/nm-device-bond.c b/src/devices/nm-device-bond.c index 37159fca..fd79348d 100644 --- a/src/devices/nm-device-bond.c +++ b/src/devices/nm-device-bond.c @@ -1,4 +1,3 @@ -/* -*- Mode: C; tab-width: 4; indent-tabs-mode: t; c-basic-offset: 4 -*- */ /* NetworkManager -- Network link manager * * This program is free software; you can redistribute it and/or modify @@ -70,6 +69,7 @@ complete_connection (NMDevice *device, NULL, _("Bond connection"), "bond", + NULL, TRUE); s_bond = nm_connection_get_setting_bond (connection); @@ -413,6 +413,12 @@ release_slave (NMDevice *device, NMDeviceBond *self = NM_DEVICE_BOND (device); gboolean success; gs_free char *address = NULL; + int ifindex_slave; + + ifindex_slave = nm_device_get_ip_ifindex (slave); + + if (ifindex_slave <= 0) + _LOGD (LOGD_TEAM, "bond slave %s is already released", nm_device_get_ip_iface (slave)); if (configure) { /* When the last slave is released the bond MAC will be set to a random @@ -420,16 +426,18 @@ release_slave (NMDevice *device, */ address = g_strdup (nm_device_get_hw_address (device)); - success = nm_platform_link_release (nm_device_get_platform (device), - nm_device_get_ip_ifindex (device), - nm_device_get_ip_ifindex (slave)); - - if (success) { - _LOGI (LOGD_BOND, "released bond slave %s", - nm_device_get_ip_iface (slave)); - } else { - _LOGW (LOGD_BOND, "failed to release bond slave %s", - nm_device_get_ip_iface (slave)); + if (ifindex_slave > 0) { + success = nm_platform_link_release (nm_device_get_platform (device), + nm_device_get_ip_ifindex (device), + ifindex_slave); + + if (success) { + _LOGI (LOGD_BOND, "released bond slave %s", + nm_device_get_ip_iface (slave)); + } else { + _LOGW (LOGD_BOND, "failed to release bond slave %s", + nm_device_get_ip_iface (slave)); + } } nm_platform_process_events (nm_device_get_platform (device)); @@ -440,11 +448,15 @@ release_slave (NMDevice *device, * IFF_UP), so we must bring it back up here to ensure carrier changes and * other state is noticed by the now-released slave. */ - if (!nm_device_bring_up (slave, TRUE, NULL)) - _LOGW (LOGD_BOND, "released bond slave could not be brought up."); + if (ifindex_slave > 0) { + if (!nm_device_bring_up (slave, TRUE, NULL)) + _LOGW (LOGD_BOND, "released bond slave could not be brought up."); + } } else { - _LOGI (LOGD_BOND, "bond slave %s was released", - nm_device_get_ip_iface (slave)); + if (ifindex_slave > 0) { + _LOGI (LOGD_BOND, "bond slave %s was released", + nm_device_get_ip_iface (slave)); + } } } diff --git a/src/devices/nm-device-bond.h b/src/devices/nm-device-bond.h index b4e9b0e8..9448950b 100644 --- a/src/devices/nm-device-bond.h +++ b/src/devices/nm-device-bond.h @@ -1,4 +1,3 @@ -/* -*- Mode: C; tab-width: 4; indent-tabs-mode: t; c-basic-offset: 4 -*- */ /* NetworkManager -- Network link manager * * This program is free software; you can redistribute it and/or modify diff --git a/src/devices/nm-device-bridge.c b/src/devices/nm-device-bridge.c index 4275af91..ade9eb0d 100644 --- a/src/devices/nm-device-bridge.c +++ b/src/devices/nm-device-bridge.c @@ -1,4 +1,3 @@ -/* -*- Mode: C; tab-width: 4; indent-tabs-mode: t; c-basic-offset: 4 -*- */ /* NetworkManager -- Network link manager * * This program is free software; you can redistribute it and/or modify @@ -153,6 +152,7 @@ complete_connection (NMDevice *device, NULL, _("Bridge connection"), "bridge", + NULL, TRUE); s_bridge = nm_connection_get_setting_bridge (connection); @@ -625,11 +625,19 @@ release_slave (NMDevice *device, { NMDeviceBridge *self = NM_DEVICE_BRIDGE (device); gboolean success; + int ifindex_slave; + + ifindex_slave = nm_device_get_ip_ifindex (slave); + + if (ifindex_slave <= 0) { + _LOGD (LOGD_TEAM, "bond slave %s is already released", nm_device_get_ip_iface (slave)); + return; + } if (configure) { success = nm_platform_link_release (nm_device_get_platform (device), nm_device_get_ip_ifindex (device), - nm_device_get_ip_ifindex (slave)); + ifindex_slave); if (success) { _LOGI (LOGD_BRIDGE, "detached bridge port %s", diff --git a/src/devices/nm-device-bridge.h b/src/devices/nm-device-bridge.h index 44b4ed72..bc5ed04c 100644 --- a/src/devices/nm-device-bridge.h +++ b/src/devices/nm-device-bridge.h @@ -1,4 +1,3 @@ -/* -*- Mode: C; tab-width: 4; indent-tabs-mode: t; c-basic-offset: 4 -*- */ /* NetworkManager -- Network link manager * * This program is free software; you can redistribute it and/or modify diff --git a/src/devices/nm-device-dummy.c b/src/devices/nm-device-dummy.c index 47a45342..9c0c3035 100644 --- a/src/devices/nm-device-dummy.c +++ b/src/devices/nm-device-dummy.c @@ -1,4 +1,3 @@ -/* -*- Mode: C; tab-width: 4; indent-tabs-mode: t; c-basic-offset: 4 -*- */ /* NetworkManager -- Network link manager * * This program is free software; you can redistribute it and/or modify @@ -66,6 +65,7 @@ complete_connection (NMDevice *device, NULL, _("Dummy connection"), NULL, + NULL, TRUE); s_dummy = nm_connection_get_setting_dummy (connection); diff --git a/src/devices/nm-device-dummy.h b/src/devices/nm-device-dummy.h index cc89a847..a380d366 100644 --- a/src/devices/nm-device-dummy.h +++ b/src/devices/nm-device-dummy.h @@ -1,4 +1,3 @@ -/* -*- Mode: C; tab-width: 4; indent-tabs-mode: t; c-basic-offset: 4 -*- */ /* NetworkManager -- Network link manager * * This program is free software; you can redistribute it and/or modify diff --git a/src/devices/nm-device-ethernet-utils.c b/src/devices/nm-device-ethernet-utils.c index b18eadfa..1d7a060e 100644 --- a/src/devices/nm-device-ethernet-utils.c +++ b/src/devices/nm-device-ethernet-utils.c @@ -1,4 +1,3 @@ -/* -*- Mode: C; tab-width: 4; indent-tabs-mode: t; c-basic-offset: 4 -*- */ /* This program is free software; you can redistribute it and/or modify * it under the terms of the GNU General Public License as published by * the Free Software Foundation; either version 2 of the License, or diff --git a/src/devices/nm-device-ethernet-utils.h b/src/devices/nm-device-ethernet-utils.h index 7e5c8b31..6355c4ec 100644 --- a/src/devices/nm-device-ethernet-utils.h +++ b/src/devices/nm-device-ethernet-utils.h @@ -1,4 +1,3 @@ -/* -*- Mode: C; tab-width: 4; indent-tabs-mode: t; c-basic-offset: 4 -*- */ /* This program is free software; you can redistribute it and/or modify * it under the terms of the GNU General Public License as published by * the Free Software Foundation; either version 2 of the License, or diff --git a/src/devices/nm-device-ethernet.c b/src/devices/nm-device-ethernet.c index 170c7e28..3e84847e 100644 --- a/src/devices/nm-device-ethernet.c +++ b/src/devices/nm-device-ethernet.c @@ -1,4 +1,3 @@ -/* -*- Mode: C; tab-width: 4; indent-tabs-mode: t; c-basic-offset: 4 -*- */ /* NetworkManager -- Network link manager * * This program is free software; you can redistribute it and/or modify @@ -561,7 +560,7 @@ build_supplicant_config (NMDeviceEthernet *self, mtu = nm_platform_link_get_mtu (nm_device_get_platform (NM_DEVICE (self)), nm_device_get_ifindex (NM_DEVICE (self))); - config = nm_supplicant_config_new (FALSE, FALSE); + config = nm_supplicant_config_new (FALSE, FALSE, FALSE, FALSE); security = nm_connection_get_setting_802_1x (connection); if (!nm_supplicant_config_add_setting_8021x (config, security, con_uuid, mtu, TRUE, error)) { @@ -1008,9 +1007,9 @@ pppoe_stage3_ip4_config_start (NMDeviceEthernet *self, NMDeviceStateReason *out_ if (priv->ppp_manager) { nm_ppp_manager_set_route_parameters (priv->ppp_manager, - nm_device_get_route_table (device, AF_INET, TRUE), + nm_device_get_route_table (device, AF_INET), nm_device_get_route_metric (device, AF_INET), - nm_device_get_route_table (device, AF_INET6, TRUE), + nm_device_get_route_table (device, AF_INET6), nm_device_get_route_metric (device, AF_INET6)); } @@ -1390,9 +1389,6 @@ complete_connection (NMDevice *device, { NMSettingWired *s_wired; NMSettingPppoe *s_pppoe; - const char *setting_mac; - const char *perm_hw_addr; - gboolean perm_hw_addr_is_fake; s_pppoe = nm_connection_get_setting_pppoe (connection); @@ -1402,6 +1398,12 @@ complete_connection (NMDevice *device, if (s_pppoe && !nm_setting_verify (NM_SETTING (s_pppoe), NULL, error)) return FALSE; + s_wired = nm_connection_get_setting_wired (connection); + if (!s_wired) { + s_wired = (NMSettingWired *) nm_setting_wired_new (); + nm_connection_add_setting (connection, NM_SETTING (s_wired)); + } + /* Default to an ethernet-only connection, but if a PPPoE setting was given * then PPPoE should be our connection type. */ @@ -1412,34 +1414,9 @@ complete_connection (NMDevice *device, NULL, s_pppoe ? _("PPPoE connection") : _("Wired connection"), NULL, + nm_setting_wired_get_mac_address (s_wired) ? NULL : nm_device_get_iface (device), s_pppoe ? FALSE : TRUE); /* No IPv6 by default yet for PPPoE */ - s_wired = nm_connection_get_setting_wired (connection); - if (!s_wired) { - s_wired = (NMSettingWired *) nm_setting_wired_new (); - nm_connection_add_setting (connection, NM_SETTING (s_wired)); - } - - perm_hw_addr = nm_device_get_permanent_hw_address_full (device, TRUE, &perm_hw_addr_is_fake); - if (perm_hw_addr && !perm_hw_addr_is_fake) { - setting_mac = nm_setting_wired_get_mac_address (s_wired); - if (setting_mac) { - /* Make sure the setting MAC (if any) matches the device's permanent MAC */ - if (!nm_utils_hwaddr_matches (setting_mac, -1, perm_hw_addr, -1)) { - g_set_error_literal (error, - NM_CONNECTION_ERROR, - NM_CONNECTION_ERROR_INVALID_PROPERTY, - _("connection does not match device")); - g_prefix_error (error, "%s.%s: ", NM_SETTING_WIRED_SETTING_NAME, NM_SETTING_WIRED_MAC_ADDRESS); - return FALSE; - } - } else { - g_object_set (G_OBJECT (s_wired), - NM_SETTING_WIRED_MAC_ADDRESS, perm_hw_addr, - NULL); - } - } - return TRUE; } @@ -1452,17 +1429,14 @@ new_default_connection (NMDevice *self) gs_unref_hashtable GHashTable *existing_ids = NULL; struct udev_device *dev; const char *perm_hw_addr; + const char *iface; const char *uprop = "0"; gs_free char *defname = NULL; gs_free char *uuid = NULL; guint i, n_connections; - if (nm_config_get_no_auto_default_for_device (nm_config_get (), self)) - return NULL; - perm_hw_addr = nm_device_get_permanent_hw_address (self); - if (!perm_hw_addr) - return NULL; + iface = nm_device_get_iface (self); connection = nm_simple_connection_new (); setting = nm_setting_connection_new (); @@ -1483,7 +1457,7 @@ new_default_connection (NMDevice *self) uuid = _nm_utils_uuid_generate_from_strings ("default-wired", nm_utils_machine_id_str (), defname, - perm_hw_addr, + perm_hw_addr ?: iface, NULL); g_object_set (setting, @@ -1493,13 +1467,9 @@ new_default_connection (NMDevice *self) NM_SETTING_CONNECTION_AUTOCONNECT_PRIORITY, NM_SETTING_CONNECTION_AUTOCONNECT_PRIORITY_MIN, NM_SETTING_CONNECTION_UUID, uuid, NM_SETTING_CONNECTION_TIMESTAMP, (guint64) time (NULL), + NM_SETTING_CONNECTION_INTERFACE_NAME, iface, NULL); - /* Lock the connection to the device */ - setting = nm_setting_wired_new (); - g_object_set (setting, NM_SETTING_WIRED_MAC_ADDRESS, perm_hw_addr, NULL); - nm_connection_add_setting (connection, setting); - /* Check if we should create a Link-Local only connection */ dev = nm_platform_link_get_udev_device (nm_device_get_platform (NM_DEVICE (self)), nm_device_get_ip_ifindex (self)); if (dev) @@ -1575,11 +1545,11 @@ update_connection (NMDevice *device, NMConnection *connection) g_object_set (s_wired, NM_SETTING_WIRED_S390_SUBCHANNELS, priv->subchannels_dbus, NULL); if (priv->s390_nettype) g_object_set (s_wired, NM_SETTING_WIRED_S390_NETTYPE, priv->s390_nettype, NULL); + + _nm_setting_wired_clear_s390_options (s_wired); g_hash_table_iter_init (&iter, priv->s390_options); - while (g_hash_table_iter_next (&iter, &key, &value)) { + while (g_hash_table_iter_next (&iter, &key, &value)) nm_setting_wired_add_s390_option (s_wired, (const char *) key, (const char *) value); - } - } static void diff --git a/src/devices/nm-device-ethernet.h b/src/devices/nm-device-ethernet.h index 22fae293..d7de519c 100644 --- a/src/devices/nm-device-ethernet.h +++ b/src/devices/nm-device-ethernet.h @@ -1,4 +1,3 @@ -/* -*- Mode: C; tab-width: 4; indent-tabs-mode: t; c-basic-offset: 4 -*- */ /* NetworkManager -- Network link manager * * This program is free software; you can redistribute it and/or modify diff --git a/src/devices/nm-device-factory.c b/src/devices/nm-device-factory.c index 30aca038..c0ec1d2e 100644 --- a/src/devices/nm-device-factory.c +++ b/src/devices/nm-device-factory.c @@ -1,4 +1,3 @@ -/* -*- Mode: C; tab-width: 4; indent-tabs-mode: t; c-basic-offset: 4 -*- */ /* NetworkManager * * This program is free software; you can redistribute it and/or modify diff --git a/src/devices/nm-device-factory.h b/src/devices/nm-device-factory.h index 33b596e6..7fe371ad 100644 --- a/src/devices/nm-device-factory.h +++ b/src/devices/nm-device-factory.h @@ -1,4 +1,3 @@ -/* -*- Mode: C; tab-width: 4; indent-tabs-mode: t; c-basic-offset: 4 -*- */ /* NetworkManager -- Network link manager * * This program is free software; you can redistribute it and/or modify diff --git a/src/devices/nm-device-generic.c b/src/devices/nm-device-generic.c index d00aa93b..39232acf 100644 --- a/src/devices/nm-device-generic.c +++ b/src/devices/nm-device-generic.c @@ -1,4 +1,3 @@ -/* -*- Mode: C; tab-width: 4; indent-tabs-mode: t; c-basic-offset: 4 -*- */ /* NetworkManager -- Network link manager * * This program is free software; you can redistribute it and/or modify diff --git a/src/devices/nm-device-generic.h b/src/devices/nm-device-generic.h index 42442180..9c59851a 100644 --- a/src/devices/nm-device-generic.h +++ b/src/devices/nm-device-generic.h @@ -1,4 +1,3 @@ -/* -*- Mode: C; tab-width: 4; indent-tabs-mode: t; c-basic-offset: 4 -*- */ /* NetworkManager -- Network link manager * * This program is free software; you can redistribute it and/or modify diff --git a/src/devices/nm-device-infiniband.c b/src/devices/nm-device-infiniband.c index 4db7d8a7..89db2af2 100644 --- a/src/devices/nm-device-infiniband.c +++ b/src/devices/nm-device-infiniband.c @@ -1,4 +1,3 @@ -/* -*- Mode: C; tab-width: 4; indent-tabs-mode: t; c-basic-offset: 4 -*- */ /* NetworkManager -- Network link manager * * This program is free software; you can redistribute it and/or modify @@ -161,8 +160,12 @@ complete_connection (NMDevice *device, GError **error) { NMSettingInfiniband *s_infiniband; - const char *setting_mac; - const char *hw_address; + + s_infiniband = nm_connection_get_setting_infiniband (connection); + if (!s_infiniband) { + s_infiniband = (NMSettingInfiniband *) nm_setting_infiniband_new (); + nm_connection_add_setting (connection, NM_SETTING (s_infiniband)); + } nm_utils_complete_generic (nm_device_get_platform (device), connection, @@ -171,31 +174,9 @@ complete_connection (NMDevice *device, NULL, _("InfiniBand connection"), NULL, + nm_setting_infiniband_get_mac_address (s_infiniband) ? NULL : nm_device_get_iface (device), TRUE); - s_infiniband = nm_connection_get_setting_infiniband (connection); - if (!s_infiniband) { - s_infiniband = (NMSettingInfiniband *) nm_setting_infiniband_new (); - nm_connection_add_setting (connection, NM_SETTING (s_infiniband)); - } - - setting_mac = nm_setting_infiniband_get_mac_address (s_infiniband); - hw_address = nm_device_get_permanent_hw_address (device); - if (setting_mac) { - /* Make sure the setting MAC (if any) matches the device's MAC */ - if (!nm_utils_hwaddr_matches (setting_mac, -1, hw_address, -1)) { - g_set_error_literal (error, - NM_CONNECTION_ERROR, - NM_CONNECTION_ERROR_INVALID_PROPERTY, - _("connection does not match device")); - g_prefix_error (error, "%s.%s: ", NM_SETTING_INFINIBAND_SETTING_NAME, NM_SETTING_INFINIBAND_MAC_ADDRESS); - return FALSE; - } - } else { - /* Lock the connection to this device by default */ - g_object_set (G_OBJECT (s_infiniband), NM_SETTING_INFINIBAND_MAC_ADDRESS, hw_address, NULL); - } - if (!nm_setting_infiniband_get_transport_mode (s_infiniband)) g_object_set (G_OBJECT (s_infiniband), NM_SETTING_INFINIBAND_TRANSPORT_MODE, "datagram", NULL); diff --git a/src/devices/nm-device-infiniband.h b/src/devices/nm-device-infiniband.h index 719c9cc9..55d0aadc 100644 --- a/src/devices/nm-device-infiniband.h +++ b/src/devices/nm-device-infiniband.h @@ -1,4 +1,3 @@ -/* -*- Mode: C; tab-width: 4; indent-tabs-mode: t; c-basic-offset: 4 -*- */ /* NetworkManager -- Network link manager * * This program is free software; you can redistribute it and/or modify diff --git a/src/devices/nm-device-ip-tunnel.c b/src/devices/nm-device-ip-tunnel.c index 96275947..ede4487e 100644 --- a/src/devices/nm-device-ip-tunnel.c +++ b/src/devices/nm-device-ip-tunnel.c @@ -1,4 +1,3 @@ -/* -*- Mode: C; tab-width: 4; indent-tabs-mode: t; c-basic-offset: 4 -*- */ /* NetworkManager -- Network link manager * * This program is free software; you can redistribute it and/or modify @@ -421,6 +420,7 @@ complete_connection (NMDevice *device, NULL, _("IP tunnel connection"), NULL, + NULL, TRUE); s_ip_tunnel = nm_connection_get_setting_ip_tunnel (connection); diff --git a/src/devices/nm-device-ip-tunnel.h b/src/devices/nm-device-ip-tunnel.h index 1109ace4..e38d36eb 100644 --- a/src/devices/nm-device-ip-tunnel.h +++ b/src/devices/nm-device-ip-tunnel.h @@ -1,4 +1,3 @@ -/* -*- Mode: C; tab-width: 4; indent-tabs-mode: t; c-basic-offset: 4 -*- */ /* NetworkManager -- Network link manager * * This program is free software; you can redistribute it and/or modify diff --git a/src/devices/nm-device-logging.h b/src/devices/nm-device-logging.h index f0c7e591..c45a0552 100644 --- a/src/devices/nm-device-logging.h +++ b/src/devices/nm-device-logging.h @@ -1,4 +1,3 @@ -/* -*- Mode: C; tab-width: 4; indent-tabs-mode: t; c-basic-offset: 4 -*- */ /* NetworkManager -- Network link manager * * This program is free software; you can redistribute it and/or modify diff --git a/src/devices/nm-device-macsec.c b/src/devices/nm-device-macsec.c index 1a6b64a4..e3e3a895 100644 --- a/src/devices/nm-device-macsec.c +++ b/src/devices/nm-device-macsec.c @@ -1,4 +1,3 @@ -/* -*- Mode: C; tab-width: 4; indent-tabs-mode: t; c-basic-offset: 4 -*- */ /* NetworkManager -- Network link manager * * This program is free software; you can redistribute it and/or modify @@ -225,7 +224,7 @@ build_supplicant_config (NMDeviceMacsec *self, GError **error) mtu = nm_platform_link_get_mtu (nm_device_get_platform (NM_DEVICE (self)), nm_device_get_ifindex (NM_DEVICE (self))); - config = nm_supplicant_config_new (FALSE, FALSE); + config = nm_supplicant_config_new (FALSE, FALSE, FALSE, FALSE); s_macsec = nm_device_get_applied_setting (NM_DEVICE (self), NM_TYPE_SETTING_MACSEC); diff --git a/src/devices/nm-device-macsec.h b/src/devices/nm-device-macsec.h index 23e9d2c9..e6919d4c 100644 --- a/src/devices/nm-device-macsec.h +++ b/src/devices/nm-device-macsec.h @@ -1,4 +1,3 @@ -/* -*- Mode: C; tab-width: 4; indent-tabs-mode: t; c-basic-offset: 4 -*- */ /* NetworkManager -- Network link manager * * This program is free software; you can redistribute it and/or modify diff --git a/src/devices/nm-device-macvlan.c b/src/devices/nm-device-macvlan.c index aa2a0ac0..709f98da 100644 --- a/src/devices/nm-device-macvlan.c +++ b/src/devices/nm-device-macvlan.c @@ -1,4 +1,3 @@ -/* -*- Mode: C; tab-width: 4; indent-tabs-mode: t; c-basic-offset: 4 -*- */ /* NetworkManager -- Network link manager * * This program is free software; you can redistribute it and/or modify @@ -364,6 +363,7 @@ complete_connection (NMDevice *device, NULL, _("MACVLAN connection"), NULL, + NULL, TRUE); s_macvlan = nm_connection_get_setting_macvlan (connection); diff --git a/src/devices/nm-device-macvlan.h b/src/devices/nm-device-macvlan.h index c7d4be7c..9e76f5c9 100644 --- a/src/devices/nm-device-macvlan.h +++ b/src/devices/nm-device-macvlan.h @@ -1,4 +1,3 @@ -/* -*- Mode: C; tab-width: 4; indent-tabs-mode: t; c-basic-offset: 4 -*- */ /* NetworkManager -- Network link manager * * This program is free software; you can redistribute it and/or modify diff --git a/src/devices/nm-device-ppp.c b/src/devices/nm-device-ppp.c index 3c310146..f2e68f73 100644 --- a/src/devices/nm-device-ppp.c +++ b/src/devices/nm-device-ppp.c @@ -1,4 +1,3 @@ -/* -*- Mode: C; tab-width: 4; indent-tabs-mode: t; c-basic-offset: 4 -*- */ /* NetworkManager -- Network link manager * * This program is free software; you can redistribute it and/or modify @@ -117,6 +116,25 @@ ppp_ip4_config (NMPPPManager *ppp_manager, } } +static gboolean +check_connection_compatible (NMDevice *device, NMConnection *connection, GError **error) +{ + NMSettingPppoe *s_pppoe; + + if (!NM_DEVICE_CLASS (nm_device_ppp_parent_class)->check_connection_compatible (device, connection, error)) + return FALSE; + + s_pppoe = nm_connection_get_setting_pppoe (connection); + if ( !s_pppoe + || !nm_setting_pppoe_get_parent (s_pppoe)) { + nm_utils_error_set_literal (error, NM_UTILS_ERROR_CONNECTION_AVAILABLE_INCOMPATIBLE, + "the connection doesn't specify a PPPoE parent interface"); + return FALSE; + } + + return TRUE; +} + static NMActStageReturn act_stage2_config (NMDevice *device, NMDeviceStateReason *out_failure_reason) { @@ -140,9 +158,9 @@ act_stage2_config (NMDevice *device, NMDeviceStateReason *out_failure_reason) if (priv->ppp_manager) { nm_ppp_manager_set_route_parameters (priv->ppp_manager, - nm_device_get_route_table (device, AF_INET, TRUE), + nm_device_get_route_table (device, AF_INET), nm_device_get_route_metric (device, AF_INET), - nm_device_get_route_table (device, AF_INET6, TRUE), + nm_device_get_route_table (device, AF_INET6), nm_device_get_route_metric (device, AF_INET6)); } @@ -280,6 +298,7 @@ nm_device_ppp_class_init (NMDevicePppClass *klass) device_class->act_stage2_config = act_stage2_config; device_class->act_stage3_ip_config_start = act_stage3_ip_config_start; + device_class->check_connection_compatible = check_connection_compatible; 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-ppp.h b/src/devices/nm-device-ppp.h index aaa18b9b..097f4b97 100644 --- a/src/devices/nm-device-ppp.h +++ b/src/devices/nm-device-ppp.h @@ -1,4 +1,3 @@ -/* -*- Mode: C; tab-width: 4; indent-tabs-mode: t; c-basic-offset: 4 -*- */ /* NetworkManager -- Network link manager * * This program is free software; you can redistribute it and/or modify diff --git a/src/devices/nm-device-private.h b/src/devices/nm-device-private.h index dd98e92f..0a414af9 100644 --- a/src/devices/nm-device-private.h +++ b/src/devices/nm-device-private.h @@ -1,4 +1,3 @@ -/* -*- Mode: C; tab-width: 4; indent-tabs-mode: t; c-basic-offset: 4 -*- */ /* NetworkManager -- Network link manager * * This program is free software; you can redistribute it and/or modify diff --git a/src/devices/nm-device-tun.c b/src/devices/nm-device-tun.c index 90360c9e..afe83f50 100644 --- a/src/devices/nm-device-tun.c +++ b/src/devices/nm-device-tun.c @@ -1,4 +1,3 @@ -/* -*- Mode: C; tab-width: 4; indent-tabs-mode: t; c-basic-offset: 4 -*- */ /* NetworkManager -- Network link manager * * This program is free software; you can redistribute it and/or modify @@ -156,6 +155,7 @@ complete_connection (NMDevice *device, NULL, _("TUN connection"), NULL, + NULL, TRUE); s_tun = nm_connection_get_setting_tun (connection); diff --git a/src/devices/nm-device-tun.h b/src/devices/nm-device-tun.h index b0d309bb..f665b942 100644 --- a/src/devices/nm-device-tun.h +++ b/src/devices/nm-device-tun.h @@ -1,4 +1,3 @@ -/* -*- Mode: C; tab-width: 4; indent-tabs-mode: t; c-basic-offset: 4 -*- */ /* NetworkManager -- Network link manager * * This program is free software; you can redistribute it and/or modify diff --git a/src/devices/nm-device-veth.c b/src/devices/nm-device-veth.c index d7a59bae..0d6425d4 100644 --- a/src/devices/nm-device-veth.c +++ b/src/devices/nm-device-veth.c @@ -1,4 +1,3 @@ -/* -*- Mode: C; tab-width: 4; indent-tabs-mode: t; c-basic-offset: 4 -*- */ /* NetworkManager -- Network link manager * * This program is free software; you can redistribute it and/or modify diff --git a/src/devices/nm-device-veth.h b/src/devices/nm-device-veth.h index 53ccf925..07217ff9 100644 --- a/src/devices/nm-device-veth.h +++ b/src/devices/nm-device-veth.h @@ -1,4 +1,3 @@ -/* -*- Mode: C; tab-width: 4; indent-tabs-mode: t; c-basic-offset: 4 -*- */ /* NetworkManager -- Network link manager * * This program is free software; you can redistribute it and/or modify diff --git a/src/devices/nm-device-vlan.c b/src/devices/nm-device-vlan.c index ace6a24b..0467a6e4 100644 --- a/src/devices/nm-device-vlan.c +++ b/src/devices/nm-device-vlan.c @@ -1,4 +1,3 @@ -/* -*- Mode: C; tab-width: 4; indent-tabs-mode: t; c-basic-offset: 4 -*- */ /* NetworkManager -- Network link manager * * This program is free software; you can redistribute it and/or modify @@ -399,6 +398,7 @@ complete_connection (NMDevice *device, NULL, _("VLAN connection"), NULL, + NULL, TRUE); s_vlan = nm_connection_get_setting_vlan (connection); diff --git a/src/devices/nm-device-vlan.h b/src/devices/nm-device-vlan.h index 375e8fa4..c463db58 100644 --- a/src/devices/nm-device-vlan.h +++ b/src/devices/nm-device-vlan.h @@ -1,4 +1,3 @@ -/* -*- Mode: C; tab-width: 4; indent-tabs-mode: t; c-basic-offset: 4 -*- */ /* NetworkManager -- Network link manager * * This program is free software; you can redistribute it and/or modify diff --git a/src/devices/nm-device-vxlan.c b/src/devices/nm-device-vxlan.c index fc73c099..1a700ba4 100644 --- a/src/devices/nm-device-vxlan.c +++ b/src/devices/nm-device-vxlan.c @@ -1,4 +1,3 @@ -/* -*- Mode: C; tab-width: 4; indent-tabs-mode: t; c-basic-offset: 4 -*- */ /* NetworkManager -- Network link manager * * This program is free software; you can redistribute it and/or modify @@ -368,6 +367,7 @@ complete_connection (NMDevice *device, NULL, _("VXLAN connection"), NULL, + NULL, TRUE); s_vxlan = nm_connection_get_setting_vxlan (connection); diff --git a/src/devices/nm-device-vxlan.h b/src/devices/nm-device-vxlan.h index 511b7156..dd14d910 100644 --- a/src/devices/nm-device-vxlan.h +++ b/src/devices/nm-device-vxlan.h @@ -1,4 +1,3 @@ -/* -*- Mode: C; tab-width: 4; indent-tabs-mode: t; c-basic-offset: 4 -*- */ /* NetworkManager -- Network link manager * * This program is free software; you can redistribute it and/or modify diff --git a/src/devices/nm-device-wireguard.c b/src/devices/nm-device-wireguard.c index f8c7d1c3..d36573cf 100644 --- a/src/devices/nm-device-wireguard.c +++ b/src/devices/nm-device-wireguard.c @@ -21,12 +21,16 @@ #include "nm-device-wireguard.h" +#include <linux/rtnetlink.h> +#include <linux/fib_rules.h> + #include "nm-setting-wireguard.h" #include "nm-core-internal.h" #include "nm-glib-aux/nm-secret-utils.h" #include "nm-device-private.h" #include "platform/nm-platform.h" #include "platform/nmp-object.h" +#include "platform/nmp-rules-manager.h" #include "nm-device-factory.h" #include "nm-active-connection.h" #include "nm-act-request.h" @@ -134,10 +138,21 @@ typedef struct { GHashTable *peers; gint64 resolve_next_try_at; - guint resolve_next_try_id; - gint64 link_config_last_at; + + guint resolve_next_try_id; guint link_config_delayed_id; + + guint32 auto_default_route_fwmark; + + guint32 auto_default_route_priority; + + bool auto_default_route_enabled_4:1; + bool auto_default_route_enabled_6:1; + bool auto_default_route_initialized:1; + bool auto_default_route_refresh:1; + bool auto_default_route_priority_initialized:1; + } NMDeviceWireGuardPrivate; struct _NMDeviceWireGuard { @@ -177,6 +192,394 @@ NM_UTILS_LOOKUP_STR_DEFINE_STATIC (_link_config_mode_to_string, LinkConfigMode, /*****************************************************************************/ +static void +_auto_default_route_get_enabled (NMSettingWireGuard *s_wg, + NMConnection *connection, + gboolean *out_enabled_v4, + gboolean *out_enabled_v6) +{ + NMTernary enabled_v4; + NMTernary enabled_v6; + + enabled_v4 = nm_setting_wireguard_get_ip4_auto_default_route (s_wg); + enabled_v6 = nm_setting_wireguard_get_ip6_auto_default_route (s_wg); + + if (enabled_v4 == NM_TERNARY_DEFAULT) { + if (nm_setting_ip_config_get_never_default (nm_connection_get_setting_ip_config (connection, AF_INET))) + enabled_v4 = FALSE; + } + if (enabled_v6 == NM_TERNARY_DEFAULT) { + if (nm_setting_ip_config_get_never_default (nm_connection_get_setting_ip_config (connection, AF_INET6))) + enabled_v6 = FALSE; + } + + if ( enabled_v4 == NM_TERNARY_DEFAULT + || enabled_v6 == NM_TERNARY_DEFAULT) { + guint i, n_peers; + + 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++) { + const char *aip; + gboolean valid; + int prefix; + int addr_family; + + aip = nm_wireguard_peer_get_allowed_ip (peer, j, &valid); + if (!valid) + continue; + if (!nm_utils_parse_inaddr_prefix_bin (AF_UNSPEC, + aip, + &addr_family, + NULL, + &prefix)) + continue; + if (prefix != 0) + continue; + + if (addr_family == AF_INET) { + if (enabled_v4 == NM_TERNARY_DEFAULT) { + enabled_v4 = TRUE; + if (enabled_v6 != NM_TERNARY_DEFAULT) + goto done; + } + } else { + if (enabled_v6 == NM_TERNARY_DEFAULT) { + enabled_v6 = TRUE; + if (enabled_v4 != NM_TERNARY_DEFAULT) + goto done; + } + } + } + } +done: + ; + } + + *out_enabled_v4 = (enabled_v4 == TRUE); + *out_enabled_v6 = (enabled_v6 == TRUE); +} + +static guint32 +_auto_default_route_find_unused_table (NMPlatform *platform) +{ + guint32 table; + int is_ipv4; + + for (table = 51820; TRUE; table++) { + const NMDedupMultiHeadEntry *head_entry; + const guint32 table_coerced = nm_platform_route_table_coerce (table); + NMDedupMultiIter iter; + const NMPObject *plobj; + + /* find a table/fwmark that is not yet in use. */ + + for (is_ipv4 = 0; is_ipv4 < 2; is_ipv4++) { + head_entry = nm_platform_lookup_object (platform, + is_ipv4 + ? NMP_OBJECT_TYPE_IP4_ROUTE + : NMP_OBJECT_TYPE_IP6_ROUTE, + -1); + nmp_cache_iter_for_each (&iter, head_entry, &plobj) { + if (NMP_OBJECT_CAST_IP_ROUTE (plobj)->table_coerced == table_coerced) + goto try_next_table; + } + } + + head_entry = nm_platform_lookup_object_by_addr_family (platform, + NMP_OBJECT_TYPE_ROUTING_RULE, + AF_UNSPEC); + nmp_cache_iter_for_each (&iter, head_entry, &plobj) { + const NMPlatformRoutingRule *rr = NMP_OBJECT_CAST_ROUTING_RULE (plobj); + + if (rr->fwmark == table) + goto try_next_table; + } + + head_entry = nm_platform_lookup_obj_type (platform, NMP_OBJECT_TYPE_LINK); + nmp_cache_iter_for_each (&iter, head_entry, &plobj) { + const NMPObject *lnk_wg; + + if (plobj->link.type != NM_LINK_TYPE_WIREGUARD) + continue; + + lnk_wg = plobj->_link.netlink.lnk; + + if (!lnk_wg) + continue; + + if (NMP_OBJECT_GET_TYPE (lnk_wg) != NMP_OBJECT_TYPE_LNK_WIREGUARD) + continue; + + if (NMP_OBJECT_CAST_LNK_WIREGUARD (lnk_wg)->fwmark == table) + goto try_next_table; + } + + return table; +try_next_table: + ; + } +} + +#define PRIO_WIDTH ((guint32) 2) + +static gboolean +_auto_default_route_find_priority_exists (const NMDedupMultiHeadEntry *head_entry, + guint32 priority) +{ + NMDedupMultiIter iter; + const NMPObject *plobj; + + nmp_cache_iter_for_each (&iter, head_entry, &plobj) { + const NMPlatformRoutingRule *rr = NMP_OBJECT_CAST_ROUTING_RULE (plobj); + + /* we don't differenciate between IPv4 vs. IPv6. There should be no + * conflicting rules with the same priority. */ + if ( rr->priority >= priority + && rr->priority < priority + PRIO_WIDTH) + return TRUE; + } + + return FALSE; +} + +static guint32 +_auto_default_route_find_priority (NMPlatform *platform, + const char *uuid) +{ + const NMDedupMultiHeadEntry *head_entry; + guint64 rnd_seed; + const guint32 PRIME_NUMBER = 1111567573u; + const guint32 RANGE_TOP = ((32766u - 2u * PRIO_WIDTH) / PRIO_WIDTH); + const guint32 RANGE_LEN1 = 200u; + const guint32 RANGE_LEN2 = (RANGE_TOP - 100u) - RANGE_LEN1; + guint32 range_len; + guint32 range_top; + guint32 prio_candidate = 0; + guint32 i_step; + guint32 i; + + /* For the auto-default-route policy routing rule we add 4 rules (2 Ipv4 and 2 IPv6). + * Hence, we choose a priority for the first (of the two rules) and the second + * rule gets priority + 1. + * We want a priority that is + * - unused so far. + * - smaller than 32766u (which is the priority of the default rules for IPv4 and IPv6) + * - stable for each connection but different between connections (we hash the UUID + * as a "random" seed) + * - if possible, close to 32766u (RANGE_LEN1). Only otherwise fallback to the entire + * range (RANGE_LEN2). + */ + + rnd_seed = c_siphash_hash ((const guint8 [16]) { 0xb9, 0x39, 0x8e, 0xed, 0x15, 0xb3, 0xd1, 0xc4, 0x5f, 0x45, 0x00, 0x4f, 0xec, 0xc2, 0x2b, 0x7e }, + (const guint8 *) uuid, + uuid ? strlen (uuid) + 1u : 0u); + + head_entry = nm_platform_lookup_object_by_addr_family (platform, + NMP_OBJECT_TYPE_ROUTING_RULE, + AF_UNSPEC); + + range_len = RANGE_LEN1; + range_top = RANGE_TOP; + +again: + i_step = ((guint32) rnd_seed) % range_len; + for (i = 0; i < range_len; i++) { + + /* we sample the range in a stable, but somewhat arbitrary order to + * find an unused priority. */ + i_step = (i_step + PRIME_NUMBER) % range_len; + + nm_assert (i_step < range_top); + + prio_candidate = (range_top - i_step) * PRIO_WIDTH; + + nm_assert (prio_candidate < 32766u); + + if (!_auto_default_route_find_priority_exists (head_entry, prio_candidate)) + return prio_candidate; + } + + if (range_len == RANGE_LEN1) { + /* within the narrow range close to RANGE_TOP we couldn't find any unused + * priority. Retry with the entire range... */ + range_len = RANGE_LEN2; + range_top -= RANGE_LEN1; + goto again; + } + + /* Couldn't find an unused one? Very odd, this really should not happen unless there + * are thousands of rules already. Just pick the last one we sampled. */ + return prio_candidate; +} + +static void +_auto_default_route_init (NMDeviceWireGuard *self) +{ + NMDeviceWireGuardPrivate *priv = NM_DEVICE_WIREGUARD_GET_PRIVATE (self); + NMConnection *connection; + NMSettingWireGuard *s_wg; + gboolean enabled_v4; + gboolean enabled_v6; + gboolean refreshing_only; + guint32 old_fwmark; + char sbuf1[100]; + + if (G_LIKELY ( priv->auto_default_route_initialized + && !priv->auto_default_route_refresh)) + return; + + refreshing_only = priv->auto_default_route_initialized + && priv->auto_default_route_refresh; + priv->auto_default_route_refresh = FALSE; + + connection = nm_device_get_applied_connection (NM_DEVICE (self)); + + s_wg = _nm_connection_get_setting (connection, NM_TYPE_SETTING_WIREGUARD); + + old_fwmark = priv->auto_default_route_fwmark; + + priv->auto_default_route_fwmark = nm_setting_wireguard_get_fwmark (s_wg); + + _auto_default_route_get_enabled (s_wg, + connection, + &enabled_v4, + &enabled_v6); + priv->auto_default_route_enabled_4 = enabled_v4; + priv->auto_default_route_enabled_6 = enabled_v6; + priv->auto_default_route_initialized = TRUE; + + if ( ( priv->auto_default_route_enabled_4 + || priv->auto_default_route_enabled_6) + && priv->auto_default_route_fwmark == 0u) { + if (refreshing_only) + priv->auto_default_route_fwmark = old_fwmark; + else + priv->auto_default_route_fwmark = _auto_default_route_find_unused_table (nm_device_get_platform (NM_DEVICE (self))); + } + + _LOGT (LOGD_DEVICE, + "auto-default-route is %s for IPv4 and %s for IPv6%s", + priv->auto_default_route_enabled_4 ? "enabled" : "disabled", + priv->auto_default_route_enabled_6 ? "enabled" : "disabled", + priv->auto_default_route_enabled_4 || priv->auto_default_route_enabled_6 + ? nm_sprintf_buf (sbuf1, " (fwmark 0x%x)", priv->auto_default_route_fwmark) + : ""); +} + +static GPtrArray * +get_extra_rules (NMDevice *device) +{ + NMDeviceWireGuard *self = NM_DEVICE_WIREGUARD (device); + NMDeviceWireGuardPrivate *priv = NM_DEVICE_WIREGUARD_GET_PRIVATE (self); + gs_unref_ptrarray GPtrArray *extra_rules = NULL; + guint32 priority = 0; + int is_ipv4; + NMConnection *connection; + + _auto_default_route_init (self); + + connection = nm_device_get_applied_connection (device); + if (!connection) + return NULL; + + for (is_ipv4 = 0; is_ipv4 < 2; is_ipv4++) { + NMSettingIPConfig *s_ip; + int addr_family = is_ipv4 ? AF_INET : AF_INET6; + guint32 table_main; + guint32 fwmark; + + if (is_ipv4) { + if (!priv->auto_default_route_enabled_4) + continue; + } else { + if (!priv->auto_default_route_enabled_6) + continue; + } + + if (!extra_rules) { + if (priv->auto_default_route_priority_initialized) + priority = priv->auto_default_route_priority; + else { + priority = _auto_default_route_find_priority (nm_device_get_platform (device), + nm_connection_get_uuid (connection)); + priv->auto_default_route_priority = priority; + priv->auto_default_route_priority_initialized = TRUE; + } + extra_rules = g_ptr_array_new_with_free_func ((GDestroyNotify) nmp_object_unref); + } + + s_ip = nm_connection_get_setting_ip_config (connection, addr_family); + table_main = nm_setting_ip_config_get_route_table (s_ip); + if (table_main == 0) + table_main = RT_TABLE_MAIN; + + fwmark = priv->auto_default_route_fwmark; + + G_STATIC_ASSERT_EXPR (PRIO_WIDTH == 2); + + g_ptr_array_add (extra_rules, + nmp_object_new (NMP_OBJECT_TYPE_ROUTING_RULE, + &((const NMPlatformRoutingRule) { + .priority = priority, + .addr_family = addr_family, + .action = FR_ACT_TO_TBL, + .table = table_main, + .suppress_prefixlen_inverse = ~((guint32) 0u), + }))); + + g_ptr_array_add (extra_rules, + nmp_object_new (NMP_OBJECT_TYPE_ROUTING_RULE, + &((const NMPlatformRoutingRule) { + .priority = priority + 1u, + .addr_family = addr_family, + .action = FR_ACT_TO_TBL, + .table = fwmark, + .flags = FIB_RULE_INVERT, + .fwmark = fwmark, + .fwmask = 0xFFFFFFFFu, + }))); + } + + return g_steal_pointer (&extra_rules); +} + +static guint32 +coerce_route_table (NMDevice *device, + int addr_family, + guint32 route_table, + gboolean is_user_config) +{ + NMDeviceWireGuard *self = NM_DEVICE_WIREGUARD (device); + NMDeviceWireGuardPrivate *priv = NM_DEVICE_WIREGUARD_GET_PRIVATE (self); + gboolean auto_default_route_enabled; + + if (route_table != 0u) + return route_table; + + _auto_default_route_init (self); + + auto_default_route_enabled = (addr_family == AF_INET) + ? priv->auto_default_route_enabled_4 + : priv->auto_default_route_enabled_6; + + if (auto_default_route_enabled) { + /* we need to enable full-sync mode of all routing tables. */ + _LOGT (LOGD_DEVICE, "coerce ipv%c.route-table setting to \"main\" (table 254) as we enable auto-default-route handling", + nm_utils_addr_family_to_char (addr_family)); + return RT_TABLE_MAIN; + } + + return 0; +} + +/*****************************************************************************/ + static gboolean _peer_data_equal (gconstpointer ptr_a, gconstpointer ptr_b) { @@ -1084,6 +1487,8 @@ link_config (NMDeviceWireGuard *self, _LOGT (LOGD_DEVICE, "wireguard link config (%s, %s)...", reason, _link_config_mode_to_string (config_mode)); + _auto_default_route_init (self); + 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); @@ -1127,10 +1532,10 @@ link_config (NMDeviceWireGuard *self, 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_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_lnk.fwmark = priv->auto_default_route_fwmark; wg_change_flags |= NM_PLATFORM_WIREGUARD_CHANGE_FLAG_HAS_FWMARK; if (nm_utils_base64secret_decode (nm_setting_wireguard_get_private_key (s_wg), @@ -1256,6 +1661,7 @@ static NMIPConfig * _get_dev2_ip_config (NMDeviceWireGuard *self, int addr_family) { + NMDeviceWireGuardPrivate *priv = NM_DEVICE_WIREGUARD_GET_PRIVATE (self); gs_unref_object NMIPConfig *ip_config = NULL; NMConnection *connection; NMSettingWireGuard *s_wg; @@ -1264,6 +1670,9 @@ _get_dev2_ip_config (NMDeviceWireGuard *self, int ip_ifindex; guint32 route_metric; guint32 route_table_coerced; + gboolean auto_default_route_enabled; + + _auto_default_route_init (self); connection = nm_device_get_applied_connection (NM_DEVICE (self)); @@ -1301,7 +1710,11 @@ _get_dev2_ip_config (NMDeviceWireGuard *self, 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)); + route_table_coerced = nm_platform_route_table_coerce (nm_device_get_route_table (NM_DEVICE (self), addr_family)); + + auto_default_route_enabled = (addr_family == AF_INET) + ? priv->auto_default_route_enabled_4 + : priv->auto_default_route_enabled_6; n_peers = nm_setting_wireguard_get_peers_len (s_wg); for (i = 0; i < n_peers; i++) { @@ -1316,6 +1729,7 @@ _get_dev2_ip_config (NMDeviceWireGuard *self, const char *aip; gboolean valid; int prefix; + guint32 rtable_coerced; aip = nm_wireguard_peer_get_allowed_ip (peer, j, &valid); @@ -1335,13 +1749,24 @@ _get_dev2_ip_config (NMDeviceWireGuard *self, nm_utils_ipx_address_clear_host_address (addr_family, &addrbin, NULL, prefix); + rtable_coerced = route_table_coerced; + + if ( prefix == 0 + && auto_default_route_enabled) { + /* In auto-default-route mode, we place the default route in a table that + * has the same number as the fwmark. wg-quick does that too. If you don't + * like that, configure the rules and the default-route explicitly in the + * connection profile. */ + rtable_coerced = nm_platform_route_table_coerce (priv->auto_default_route_fwmark); + } + 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, + .table_coerced = rtable_coerced, .metric = route_metric, }; } else { @@ -1350,7 +1775,7 @@ _get_dev2_ip_config (NMDeviceWireGuard *self, .plen = prefix, .ifindex = ip_ifindex, .rt_source = NM_IP_CONFIG_SOURCE_USER, - .table_coerced = route_table_coerced, + .table_coerced = rtable_coerced, .metric = route_metric, }; } @@ -1406,20 +1831,28 @@ get_configured_mtu (NMDevice *device, NMDeviceMtuSource *out_source) } static void +_device_cleanup (NMDeviceWireGuard *self) +{ + NMDeviceWireGuardPrivate *priv = NM_DEVICE_WIREGUARD_GET_PRIVATE (self); + + _peers_remove_all (priv); + + _secrets_cancel (self); + + priv->auto_default_route_initialized = FALSE; + priv->auto_default_route_priority_initialized = FALSE; +} + +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)); + _device_cleanup (NM_DEVICE_WIREGUARD (device)); } /*****************************************************************************/ @@ -1440,6 +1873,8 @@ can_reapply_change (NMDevice *device, NM_SETTING_WIREGUARD_SETTING_NAME, error, NM_SETTING_WIREGUARD_FWMARK, + NM_SETTING_WIREGUARD_IP4_AUTO_DEFAULT_ROUTE, + NM_SETTING_WIREGUARD_IP6_AUTO_DEFAULT_ROUTE, NM_SETTING_WIREGUARD_LISTEN_PORT, NM_SETTING_WIREGUARD_PEERS, NM_SETTING_WIREGUARD_PEER_ROUTES, @@ -1461,9 +1896,12 @@ reapply_connection (NMDevice *device, NMConnection *con_new) { NMDeviceWireGuard *self = NM_DEVICE_WIREGUARD (device); + NMDeviceWireGuardPrivate *priv = NM_DEVICE_WIREGUARD_GET_PRIVATE (self); gs_unref_object NMIPConfig *ip4_config = NULL; gs_unref_object NMIPConfig *ip6_config = NULL; + priv->auto_default_route_refresh = TRUE; + ip4_config = _get_dev2_ip_config (self, AF_INET); ip6_config = _get_dev2_ip_config (self, AF_INET6); @@ -1567,11 +2005,8 @@ 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); + _device_cleanup (self); G_OBJECT_CLASS (nm_device_wireguard_parent_class)->dispose (object); } @@ -1589,6 +2024,8 @@ finalize (GObject *object) g_object_unref (priv->dns_manager); } + g_hash_table_destroy (priv->peers); + G_OBJECT_CLASS (nm_device_wireguard_parent_class)->finalize (object); } @@ -1631,6 +2068,8 @@ nm_device_wireguard_class_init (NMDeviceWireGuardClass *klass) device_class->can_reapply_change = can_reapply_change; device_class->reapply_connection = reapply_connection; device_class->get_configured_mtu = get_configured_mtu; + device_class->get_extra_rules = get_extra_rules; + device_class->coerce_route_table = coerce_route_table; obj_properties[PROP_PUBLIC_KEY] = g_param_spec_variant (NM_DEVICE_WIREGUARD_PUBLIC_KEY, diff --git a/src/devices/nm-device-wpan.c b/src/devices/nm-device-wpan.c index cdfd1f70..88234412 100644 --- a/src/devices/nm-device-wpan.c +++ b/src/devices/nm-device-wpan.c @@ -67,6 +67,7 @@ complete_connection (NMDevice *device, NULL, _("WPAN connection"), NULL, + NULL, TRUE); s_wpan = NM_SETTING_WPAN (nm_connection_get_setting (connection, NM_TYPE_SETTING_WPAN)); diff --git a/src/devices/nm-device.c b/src/devices/nm-device.c index bd4fbcc3..feb5110d 100644 --- a/src/devices/nm-device.c +++ b/src/devices/nm-device.c @@ -1,4 +1,3 @@ -/* -*- Mode: C; tab-width: 4; indent-tabs-mode: t; c-basic-offset: 4 -*- */ /* NetworkManager -- Network link manager * * This program is free software; you can redistribute it and/or modify @@ -128,6 +127,15 @@ typedef struct { int ifindex; } DeleteOnDeactivateData; +typedef struct { + NMDevice *device; + GCancellable *cancellable; + NMPlatformAsyncCallback callback; + gpointer callback_data; + guint num_vfs; + NMTernary autoprobe; +} SriovOp; + typedef void (*AcdCallback) (NMDevice *, NMIP4Config **, gboolean); typedef struct { @@ -328,16 +336,18 @@ typedef struct _NMDevicePrivate { ActivationHandleData act_handle4; /* for layer2 and IPv4. */ ActivationHandleData act_handle6; guint recheck_assume_id; + struct { guint call_id; NMDeviceStateReason available_reason; NMDeviceStateReason unavailable_reason; - } recheck_available; + } recheck_available; + struct { - guint call_id; + NMDispatcherCallId *call_id; NMDeviceState post_state; NMDeviceStateReason post_state_reason; - } dispatcher; + } dispatcher; /* Link stuff */ guint link_connected_id; @@ -378,6 +388,9 @@ typedef struct _NMDevicePrivate { bool v4_route_table_initialized:1; bool v6_route_table_initialized:1; + bool v4_route_table_full_sync_before:1; + bool v6_route_table_full_sync_before:1; + NMDeviceAutoconnectBlockedFlags autoconnect_blocked_flags:5; bool is_enslaved:1; @@ -397,8 +410,7 @@ typedef struct _NMDevicePrivate { /* Proxy Configuration */ NMProxyConfig *proxy_config; - NMPacrunnerManager *pacrunner_manager; - NMPacrunnerCallId *pacrunner_call_id; + NMPacrunnerConfId *pacrunner_conf_id; /* IP configuration info. Combined config from VPN, settings, and device */ union { @@ -575,12 +587,16 @@ typedef struct _NMDevicePrivate { guint check_delete_unrealized_id; struct { + SriovOp *pending; /* SR-IOV operation currently running */ + SriovOp *next; /* next SR-IOV operation scheduled */ + } sriov; + + struct { guint timeout_id; guint refresh_rate_ms; guint64 tx_bytes; guint64 rx_bytes; } stats; - } NMDevicePrivate; G_DEFINE_ABSTRACT_TYPE (NMDevice, nm_device, NM_TYPE_DBUS_OBJECT) @@ -636,7 +652,8 @@ static void realize_start_setup (NMDevice *self, gboolean assume_state_guess_assume, const char *assume_state_connection_uuid, gboolean set_nm_owned, - NMUnmanFlagOp unmanaged_user_explicit); + NMUnmanFlagOp unmanaged_user_explicit, + gboolean force_platform_init); static void _set_mtu (NMDevice *self, guint32 mtu); static void _commit_mtu (NMDevice *self, const NMIP4Config *config); static void _cancel_activation (NMDevice *self); @@ -1898,7 +1915,7 @@ get_ip_iface_identifier (NMDevice *self, NMUtilsIPv6IfaceId *out_iid) const NMPlatformLink *pllink; const guint8 *hwaddr; guint8 pseudo_hwaddr[ETH_ALEN]; - guint hwaddr_len; + gsize hwaddr_len; int ifindex; gboolean success; @@ -1911,13 +1928,9 @@ get_ip_iface_identifier (NMDevice *self, NMUtilsIPv6IfaceId *out_iid) || NM_IN_SET (pllink->type, NM_LINK_TYPE_NONE, NM_LINK_TYPE_UNKNOWN)) return FALSE; - if (pllink->addr.len <= 0) + hwaddr = nmp_link_address_get (&pllink->l_address, &hwaddr_len); + if (hwaddr_len <= 0) return FALSE; - if (pllink->addr.len > NM_UTILS_HWADDR_LEN_MAX) - g_return_val_if_reached (FALSE); - - hwaddr = pllink->addr.data; - hwaddr_len = pllink->addr.len; if (pllink->type == NM_LINK_TYPE_6LOWPAN) { /* If the underlying IEEE 802.15.4 device has a short address we generate @@ -1949,7 +1962,7 @@ get_ip_iface_identifier (NMDevice *self, NMUtilsIPv6IfaceId *out_iid) out_iid); if (!success) { _LOGW (LOGD_PLATFORM, "failed to generate interface identifier " - "for link type %u hwaddr_len %u", pllink->type, (unsigned) pllink->addr.len); + "for link type %u hwaddr_len %zu", pllink->type, hwaddr_len); } return success; } @@ -2247,30 +2260,27 @@ _get_llmnr (NMDevice *self) NM_SETTING_CONNECTION_LLMNR_DEFAULT); } -guint32 -nm_device_get_route_table (NMDevice *self, - int addr_family, - gboolean fallback_main) +static guint32 +_get_route_table (NMDevice *self, + int addr_family) { - NMDevicePrivate *priv; + NMDevicePrivate *priv = NM_DEVICE_GET_PRIVATE (self); + NMDeviceClass *klass; NMConnection *connection; NMSettingIPConfig *s_ip; guint32 route_table = 0; + gboolean is_user_config = TRUE; nm_assert_addr_family (addr_family); - g_return_val_if_fail (NM_IS_DEVICE (self), RT_TABLE_MAIN); - - priv = NM_DEVICE_GET_PRIVATE (self); - /* the route table setting affects how we sync routes. We shall * not change it while the device is active, hence, cache it. */ if (addr_family == AF_INET) { if (priv->v4_route_table_initialized) - return priv->v4_route_table ?: (fallback_main ? RT_TABLE_MAIN : 0); + return priv->v4_route_table; } else { if (priv->v6_route_table_initialized) - return priv->v6_route_table ?: (fallback_main ? RT_TABLE_MAIN : 0); + return priv->v6_route_table; } connection = nm_device_get_applied_connection (self); @@ -2278,23 +2288,28 @@ nm_device_get_route_table (NMDevice *self, 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); - - /* we only lookup the global default if we also have an applied - * connection. Otherwise, the connection is not active, and the - * connection default doesn't matter. */ - if (route_table == 0) { - const char *property; - - property = addr_family == AF_INET - ? NM_CON_DEFAULT ("ipv4.route-table") - : NM_CON_DEFAULT ("ipv6.route-table"); - route_table = nm_config_data_get_connection_default_int64 (NM_CONFIG_GET_DATA, - property, - self, - 0, G_MAXUINT32, 0); + } + if (route_table == 0u) { + gint64 v; + + v = nm_config_data_get_connection_default_int64 (NM_CONFIG_GET_DATA, + addr_family == AF_INET + ? NM_CON_DEFAULT ("ipv4.route-table") + : NM_CON_DEFAULT ("ipv6.route-table"), + self, + 0, + G_MAXUINT32, + -1); + if (v != -1) { + route_table = v; + is_user_config = FALSE; } } + klass = NM_DEVICE_GET_CLASS (self); + if (klass->coerce_route_table) + route_table = klass->coerce_route_table (self, addr_family, route_table, is_user_config); + if (addr_family == AF_INET) { priv->v4_route_table_initialized = TRUE; priv->v4_route_table = route_table; @@ -2307,9 +2322,57 @@ nm_device_get_route_table (NMDevice *self, "ipv%c.route-table = %u%s", addr_family == AF_INET ? '4' : '6', (guint) (route_table ?: RT_TABLE_MAIN), - route_table ? "" : " (policy routing not enabled)"); + route_table != 0u ? "" : " (policy routing not enabled)"); - return route_table ?: (fallback_main ? RT_TABLE_MAIN : 0); + return route_table; +} + +guint32 +nm_device_get_route_table (NMDevice *self, + int addr_family) +{ + guint32 route_table; + + g_return_val_if_fail (NM_IS_DEVICE (self), RT_TABLE_MAIN); + + route_table = _get_route_table (self, addr_family); + return route_table ?: (guint32) RT_TABLE_MAIN; +} + +static NMIPRouteTableSyncMode +_get_route_table_sync_mode_stateful (NMDevice *self, + int addr_family) +{ + NMDevicePrivate *priv = NM_DEVICE_GET_PRIVATE (self); + gboolean full_sync_now; + gboolean full_sync_eff; + + full_sync_now = _get_route_table (self, addr_family) != 0u; + + if (full_sync_now) + full_sync_eff = TRUE; + else { + /* When we change from full-sync to no full-sync, we do a last full-sync one + * more time. For that, we determine the effective full-state based on the + * cached/previous full-sync flag. + * + * The purpose of this is to support reapply of route-table (and thus the + * full-sync mode). If reapply toggles from full-sync to no-full-sync, we must + * sync one last time. */ + if (addr_family == AF_INET) + full_sync_eff = priv->v4_route_table_full_sync_before; + else + full_sync_eff = priv->v6_route_table_full_sync_before; + } + + if (addr_family == AF_INET) + priv->v4_route_table_full_sync_before = full_sync_now; + else + priv->v6_route_table_full_sync_before = full_sync_now; + + return full_sync_eff + ? NM_IP_ROUTE_TABLE_SYNC_MODE_FULL + : NM_IP_ROUTE_TABLE_SYNC_MODE_MAIN; } const NMPObject * @@ -2801,6 +2864,7 @@ concheck_update_state (NMDevice *self, NM_CONNECTIVITY_PORTAL, NM_CONNECTIVITY_FULL, NM_CONNECTIVITY_FAKE, + NM_CONNECTIVITY_NONE, NM_CONNECTIVITY_ERROR)); if (state == NM_CONNECTIVITY_ERROR) { @@ -2823,14 +2887,6 @@ concheck_update_state (NMDevice *self, state = NM_CONNECTIVITY_LIMITED; } else state = NM_CONNECTIVITY_NONE; - } else if (state == NM_CONNECTIVITY_LIMITED) { - /* NMConnectivity cannot distinguish between NONE and LIMITED connectivity. In both - * cases, it just failed to fetch the URL. - * - * NMDevice coerces a LIMITED state to NONE here, if the logical state of the device - * is disconnected. */ - if (priv->state <= NM_DEVICE_STATE_DISCONNECTED) - state = NM_CONNECTIVITY_NONE; } if (priv->concheck_x[IS_IPv4].state == state) { @@ -3096,28 +3152,17 @@ concheck_start (NMDevice *self, && !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"; - } - } + gboolean due_to_all; + int val; + val = nm_platform_sysctl_ip_conf_get_rp_filter_ipv4 (nm_device_get_platform (self), + ifname, + TRUE, + &due_to_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); + "This might break connectivity checking for IPv4 on this device", + due_to_all ? "all" : ifname); } } @@ -3127,6 +3172,7 @@ concheck_start (NMDevice *self, handle->c_handle = nm_connectivity_check_start (concheck_get_mgr (self), handle->addr_family, + nm_device_get_platform (self), nm_device_get_ip_ifindex (self), nm_device_get_ip_iface (self), concheck_cb, @@ -3588,7 +3634,7 @@ nm_device_set_carrier (NMDevice *self, gboolean carrier) now_ms = nm_utils_get_monotonic_timestamp_ms (); until_ms = NM_MAX (now_ms + _get_carrier_wait_ms (self), priv->carrier_wait_until_ms); priv->carrier_defer_id = g_timeout_add (until_ms - now_ms, carrier_disconnected_action_cb, self); - _LOGD (LOGD_DEVICE, "carrier: link disconnected (deferring action for %ld milli seconds) (id=%u)", + _LOGD (LOGD_DEVICE, "carrier: link disconnected (deferring action for %ld milliseconds) (id=%u)", (long) (until_ms - now_ms), priv->carrier_defer_id); } } @@ -3890,16 +3936,12 @@ 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->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 (!ip_config_merge_and_apply (self, AF_INET, TRUE)) + _LOGW (LOGD_IP4, "failed applying IP4 config after link comes up again"); 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"); - } + if (!ip_config_merge_and_apply (self, AF_INET6, TRUE)) + _LOGW (LOGD_IP6, "failed applying IP6 config after link comes up again"); } if (update_unmanaged_specs) @@ -4086,7 +4128,8 @@ nm_device_realize_start (NMDevice *self, assume_state_guess_assume, assume_state_connection_uuid, set_nm_owned, - unmanaged_user_explicit); + unmanaged_user_explicit, + FALSE); return TRUE; } @@ -4131,7 +4174,8 @@ nm_device_create_and_realize (NMDevice *self, plink, FALSE, /* assume_state_guess_assume */ NULL, /* assume_state_connection_uuid */ - FALSE, NM_UNMAN_FLAG_OP_FORGET); + FALSE, NM_UNMAN_FLAG_OP_FORGET, + TRUE); nm_device_realize_finish (self, plink); if (nm_device_get_managed (self, FALSE)) { @@ -4192,6 +4236,86 @@ nm_device_update_from_platform_link (NMDevice *self, const NMPlatformLink *plink } } +static void sriov_op_cb (GError *error, gpointer user_data); + +static void +sriov_op_start (NMDevice *self, SriovOp *op) +{ + NMDevicePrivate *priv = NM_DEVICE_GET_PRIVATE (self); + + nm_assert (!priv->sriov.pending); + + op->cancellable = g_cancellable_new (); + op->device = g_object_ref (self); + priv->sriov.pending = op; + + nm_platform_link_set_sriov_params_async (nm_device_get_platform (self), + priv->ifindex, + op->num_vfs, + op->autoprobe, + sriov_op_cb, + op, + op->cancellable); +} + +static void +sriov_op_cb (GError *error, gpointer user_data) +{ + SriovOp *op = user_data; + gs_unref_object NMDevice *self = op->device; + NMDevicePrivate *priv = NM_DEVICE_GET_PRIVATE (self); + + nm_assert (op == priv->sriov.pending); + + priv->sriov.pending = NULL; + + if (op->callback) + op->callback (error, op->callback_data); + + g_clear_object (&op->cancellable); + g_slice_free (SriovOp, op); + + if (priv->sriov.next) { + sriov_op_start (self, + g_steal_pointer (&priv->sriov.next)); + } +} + +static void +sriov_op_queue (NMDevice *self, + guint num_vfs, + NMTernary autoprobe, + NMPlatformAsyncCallback callback, + gpointer callback_data) +{ + NMDevicePrivate *priv = NM_DEVICE_GET_PRIVATE (self); + GError *error = NULL; + SriovOp *op; + + op = g_slice_new0 (SriovOp); + op->num_vfs = num_vfs; + op->autoprobe = autoprobe; + op->callback = callback; + op->callback_data = callback_data; + + if (priv->sriov.next) { + /* Cancel the next operation immediately */ + if (priv->sriov.next->callback) { + nm_utils_error_set_cancelled (&error, FALSE, NULL); + priv->sriov.next->callback (error, priv->sriov.next->callback_data); + g_clear_error (&error); + } + g_slice_free (SriovOp, priv->sriov.next); + priv->sriov.next = NULL; + } + + if (priv->sriov.pending) { + priv->sriov.next = op; + g_cancellable_cancel (priv->sriov.pending->cancellable); + } else + sriov_op_start (self, op); +} + static void device_init_static_sriov_num_vfs (NMDevice *self) { @@ -4206,10 +4330,8 @@ device_init_static_sriov_num_vfs (NMDevice *self) self, NULL); num_vfs = _nm_utils_ascii_str_to_int64 (value, 10, 0, G_MAXINT32, -1); - if (num_vfs >= 0) { - nm_platform_link_set_sriov_params (nm_device_get_platform (self), - priv->ifindex, num_vfs, NM_TERNARY_DEFAULT); - } + if (num_vfs >= 0) + sriov_op_queue (self, num_vfs, NM_TERNARY_DEFAULT, NULL, NULL); } } @@ -4223,11 +4345,11 @@ config_changed (NMConfig *config, NMDevicePrivate *priv = NM_DEVICE_GET_PRIVATE (self); if ( priv->state <= NM_DEVICE_STATE_DISCONNECTED - || priv->state > NM_DEVICE_STATE_ACTIVATED) + || priv->state > NM_DEVICE_STATE_ACTIVATED) { priv->ignore_carrier = nm_config_data_get_ignore_carrier (config_data, self); - - if (NM_FLAGS_HAS (changes, NM_CONFIG_CHANGE_VALUES)) - device_init_static_sriov_num_vfs (self); + if (NM_FLAGS_HAS (changes, NM_CONFIG_CHANGE_VALUES)) + device_init_static_sriov_num_vfs (self); + } } static void @@ -4248,6 +4370,8 @@ realize_start_notify (NMDevice *self, * @set_nm_owned: if TRUE and device is a software-device, set nm-owned. * TRUE. * @unmanaged_user_explicit: the user-explict unmanaged flag to set. + * @force_platform_init: if TRUE the platform-init unmanaged flag is + * forcefully cleared. * * Update the device from backing resource properties (like hardware * addresses, carrier states, driver/firmware info, etc). This function @@ -4261,14 +4385,17 @@ realize_start_setup (NMDevice *self, gboolean assume_state_guess_assume, const char *assume_state_connection_uuid, gboolean set_nm_owned, - NMUnmanFlagOp unmanaged_user_explicit) + NMUnmanFlagOp unmanaged_user_explicit, + gboolean force_platform_init) { NMDevicePrivate *priv; NMDeviceClass *klass; + NMPlatform *platform; static guint32 id = 0; NMDeviceCapabilities capabilities = 0; NMConfig *config; guint real_rate; + gboolean unmanaged; /* plink is a NMPlatformLink type, however, we require it to come from the platform * cache (where else would it come from?). */ @@ -4289,6 +4416,7 @@ realize_start_setup (NMDevice *self, _LOGD (LOGD_DEVICE, "start setup of %s, kernel ifindex %d", G_OBJECT_TYPE_NAME (self), plink ? plink->ifindex : 0); klass = NM_DEVICE_GET_CLASS (self); + platform = nm_device_get_platform (self); /* Balanced by a thaw in nm_device_realize_finish() */ g_object_freeze_notify (G_OBJECT (self)); @@ -4307,19 +4435,19 @@ realize_start_setup (NMDevice *self, nm_device_update_from_platform_link (self, plink); if (priv->ifindex > 0) { - priv->physical_port_id = nm_platform_link_get_physical_port_id (nm_device_get_platform (self), priv->ifindex); + priv->physical_port_id = nm_platform_link_get_physical_port_id (platform, priv->ifindex); _notify (self, PROP_PHYSICAL_PORT_ID); - priv->dev_id = nm_platform_link_get_dev_id (nm_device_get_platform (self), priv->ifindex); + priv->dev_id = nm_platform_link_get_dev_id (platform, priv->ifindex); - if (nm_platform_link_is_software (nm_device_get_platform (self), priv->ifindex)) + if (nm_platform_link_is_software (platform, priv->ifindex)) capabilities |= NM_DEVICE_CAP_IS_SOFTWARE; _set_mtu (self, - nm_platform_link_get_mtu (nm_device_get_platform (self), + nm_platform_link_get_mtu (platform, priv->ifindex)); - nm_platform_link_get_driver_info (nm_device_get_platform (self), + nm_platform_link_get_driver_info (platform, priv->ifindex, NULL, &priv->driver_version, @@ -4330,9 +4458,9 @@ realize_start_setup (NMDevice *self, _notify (self, PROP_FIRMWARE_VERSION); if (nm_platform_kernel_support_get (NM_PLATFORM_KERNEL_SUPPORT_TYPE_USER_IPV6LL)) - priv->ipv6ll_handle = nm_platform_link_get_user_ipv6ll_enabled (nm_device_get_platform (self), priv->ifindex); + priv->ipv6ll_handle = nm_platform_link_get_user_ipv6ll_enabled (platform, priv->ifindex); - if (nm_platform_link_supports_sriov (nm_device_get_platform (self), priv->ifindex)) + if (nm_platform_link_supports_sriov (platform, priv->ifindex)) capabilities |= NM_DEVICE_CAP_SRIOV; } @@ -4398,8 +4526,12 @@ realize_start_setup (NMDevice *self, nm_device_set_unmanaged_by_user_udev (self); nm_device_set_unmanaged_by_user_conf (self); + unmanaged = plink + && !plink->initialized + && !force_platform_init; + nm_device_set_unmanaged_flags (self, NM_UNMANAGED_PLATFORM_INIT, - plink && !plink->initialized); + unmanaged); } /** @@ -4941,7 +5073,7 @@ static void check_ip_state (NMDevice *self, gboolean may_fail, gboolean full_state_update) { NMDevicePrivate *priv = NM_DEVICE_GET_PRIVATE (self); - gboolean ip4_disabled = FALSE, ip6_ignore = FALSE; + gboolean ip4_disabled = FALSE, ip6_disabled = FALSE; NMSettingIPConfig *s_ip4, *s_ip6; NMDeviceState state; @@ -4961,9 +5093,10 @@ check_ip_state (NMDevice *self, gboolean may_fail, gboolean full_state_update) ip4_disabled = TRUE; s_ip6 = nm_device_get_applied_setting (self, NM_TYPE_SETTING_IP6_CONFIG); - if (s_ip6 && nm_streq0 (nm_setting_ip_config_get_method (s_ip6), - NM_SETTING_IP6_CONFIG_METHOD_IGNORE)) - ip6_ignore = TRUE; + if (s_ip6 && NM_IN_STRSET (nm_setting_ip_config_get_method (s_ip6), + NM_SETTING_IP6_CONFIG_METHOD_IGNORE, + NM_SETTING_IP6_CONFIG_METHOD_DISABLED)) + ip6_disabled = TRUE; if ( priv->ip_state_4 == NM_DEVICE_IP_STATE_DONE && priv->ip_state_6 == NM_DEVICE_IP_STATE_DONE) { @@ -4973,7 +5106,7 @@ check_ip_state (NMDevice *self, gboolean may_fail, gboolean full_state_update) } 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))) { + && (priv->ip_state_6 == NM_DEVICE_IP_STATE_FAIL || (ip6_disabled && 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)) { @@ -5010,7 +5143,7 @@ check_ip_state (NMDevice *self, gboolean may_fail, gboolean full_state_update) /* If at least a method has completed, proceed with activation */ if ( (priv->ip_state_4 == NM_DEVICE_IP_STATE_DONE && !ip4_disabled) - || (priv->ip_state_6 == NM_DEVICE_IP_STATE_DONE && !ip6_ignore)) { + || (priv->ip_state_6 == NM_DEVICE_IP_STATE_DONE && !ip6_disabled)) { if (full_state_update) nm_device_state_changed (self, NM_DEVICE_STATE_IP_CHECK, NM_DEVICE_STATE_REASON_NONE); return; @@ -5565,8 +5698,9 @@ nm_device_generate_connection (NMDevice *self, */ ip4_method = nm_utils_get_ip_config_method (connection, AF_INET); ip6_method = nm_utils_get_ip_config_method (connection, AF_INET6); - if ( g_strcmp0 (ip4_method, NM_SETTING_IP4_CONFIG_METHOD_DISABLED) == 0 - && g_strcmp0 (ip6_method, NM_SETTING_IP6_CONFIG_METHOD_IGNORE) == 0 + if ( nm_streq0 (ip4_method, NM_SETTING_IP4_CONFIG_METHOD_DISABLED) + && NM_IN_STRSET (ip6_method, NM_SETTING_IP6_CONFIG_METHOD_IGNORE, + NM_SETTING_IP6_CONFIG_METHOD_DISABLED) && !nm_setting_connection_get_master (NM_SETTING_CONNECTION (s_con)) && c_list_is_empty (&priv->slaves)) { NM_SET_OUT (out_maybe_later, TRUE); @@ -5631,7 +5765,10 @@ nm_device_complete_connection (NMDevice *self, error)) return FALSE; - return nm_connection_verify (connection, error); + if (!nm_connection_normalize (connection, NULL, NULL, error)) + return FALSE; + + return nm_device_check_connection_compatible (self, connection, error); } gboolean @@ -5652,11 +5789,9 @@ nm_device_match_parent (NMDevice *self, const char *parent) * no connection active on the device or when a connection with * that UUID is active. */ - connection = nm_device_get_applied_connection (self); - if (!connection) - return TRUE; - - if (!nm_streq0 (parent, nm_connection_get_uuid (connection))) + connection = nm_device_get_applied_connection (parent_device); + if ( connection + && !nm_streq0 (parent, nm_connection_get_uuid (connection))) return FALSE; } else { /* Interface name */ @@ -6255,6 +6390,41 @@ sriov_vf_config_to_platform (NMDevice *self, return g_steal_pointer (&plat_vf); } +static void +sriov_params_cb (GError *error, gpointer data) +{ + NMDevice *self; + NMDevicePrivate *priv; + nm_auto_freev NMPlatformVF **plat_vfs = NULL; + + nm_utils_user_data_unpack (data, &self, &plat_vfs); + + if (nm_utils_error_is_cancelled (error, TRUE)) + return; + + priv = NM_DEVICE_GET_PRIVATE (self); + + if (error) { + _LOGE (LOGD_DEVICE, "failed to set SR-IOV parameters: %s", error->message); + nm_device_state_changed (self, + NM_DEVICE_STATE_FAILED, + NM_DEVICE_STATE_REASON_SRIOV_CONFIGURATION_FAILED); + return; + } + + if (!nm_platform_link_set_sriov_vfs (nm_device_get_platform (self), + priv->ifindex, + (const NMPlatformVF *const *) plat_vfs)) { + _LOGE (LOGD_DEVICE, "failed to apply SR-IOV VFs"); + nm_device_state_changed (self, + NM_DEVICE_STATE_FAILED, + NM_DEVICE_STATE_REASON_SRIOV_CONFIGURATION_FAILED); + return; + } + + nm_device_activate_schedule_stage2_device_config (self); +} + static NMActStageReturn act_stage1_prepare (NMDevice *self, NMDeviceStateReason *out_failure_reason) { @@ -6269,6 +6439,7 @@ act_stage1_prepare (NMDevice *self, NMDeviceStateReason *out_failure_reason) gs_free_error GError *error = NULL; NMSriovVF *vf; NMTernary autoprobe; + gpointer *data; autoprobe = nm_setting_sriov_get_autoprobe_drivers (s_sriov); if (autoprobe == NM_TERNARY_DEFAULT) { @@ -6295,24 +6466,19 @@ act_stage1_prepare (NMDevice *self, NMDeviceStateReason *out_failure_reason) } } - if (!nm_platform_link_set_sriov_params (nm_device_get_platform (self), - priv->ifindex, - nm_setting_sriov_get_total_vfs (s_sriov), - autoprobe)) { - _LOGE (LOGD_DEVICE, "failed to apply SR-IOV parameters"); - NM_SET_OUT (out_failure_reason, NM_DEVICE_STATE_REASON_SRIOV_CONFIGURATION_FAILED); - return NM_ACT_STAGE_RETURN_FAILURE; - } - - if (!nm_platform_link_set_sriov_vfs (nm_device_get_platform (self), - priv->ifindex, - (const NMPlatformVF *const *) plat_vfs)) { - _LOGE (LOGD_DEVICE, "failed to apply SR-IOV VFs"); - NM_SET_OUT (out_failure_reason, NM_DEVICE_STATE_REASON_SRIOV_CONFIGURATION_FAILED); - return NM_ACT_STAGE_RETURN_FAILURE; - } + /* When changing the number of VFs the kernel can block + * for very long time in the write to sysfs, especially + * if autoprobe-drivers is enabled. Do it asynchronously + * to avoid blocking the entire NM process. + */ + data = nm_utils_user_data_pack (self, g_steal_pointer (&plat_vfs)); + sriov_op_queue (self, + nm_setting_sriov_get_total_vfs (s_sriov), + autoprobe, + sriov_params_cb, + data); + return NM_ACT_STAGE_RETURN_POSTPONE; } - return NM_ACT_STAGE_RETURN_SUCCESS; } @@ -6328,6 +6494,9 @@ activate_stage1_device_prepare (NMDevice *self) NMDevicePrivate *priv = NM_DEVICE_GET_PRIVATE (self); NMActStageReturn ret = NM_ACT_STAGE_RETURN_SUCCESS; + priv->v4_route_table_initialized = FALSE; + priv->v6_route_table_initialized = FALSE; + _set_ip_state (self, AF_INET, NM_DEVICE_IP_STATE_NONE); _set_ip_state (self, AF_INET6, NM_DEVICE_IP_STATE_NONE); @@ -6430,11 +6599,15 @@ _routing_rules_sync (NMDevice *self, { NMDevicePrivate *priv = NM_DEVICE_GET_PRIVATE (self); NMPRulesManager *rules_manager = nm_netns_get_rules_manager (nm_device_get_netns (self)); + NMDeviceClass *klass = NM_DEVICE_GET_CLASS (self); gboolean untrack_only_dirty = FALSE; gboolean keep_deleted_rules; - gpointer user_tag; + gpointer user_tag_1; + gpointer user_tag_2; - user_tag = priv; + /* take two arbitrary user-tag pointers that belong to @self. */ + user_tag_1 = &priv->v4_route_table; + user_tag_2 = &priv->v6_route_table; if (set_mode == NM_TERNARY_TRUE) { NMConnection *applied_connection; @@ -6443,7 +6616,9 @@ _routing_rules_sync (NMDevice *self, int is_ipv4; untrack_only_dirty = TRUE; - nmp_rules_manager_set_dirty (rules_manager, user_tag); + nmp_rules_manager_set_dirty (rules_manager, user_tag_1); + if (klass->get_extra_rules) + nmp_rules_manager_set_dirty (rules_manager, user_tag_2); applied_connection = nm_device_get_applied_connection (self); @@ -6461,15 +6636,37 @@ _routing_rules_sync (NMDevice *self, rule = nm_setting_ip_config_get_routing_rule (s_ip, i); nm_ip_routing_rule_to_platform (rule, &plrule); + + /* We track this rule, but we also make it explicitly not weakly-tracked + * (meaning to untrack NMP_RULES_MANAGER_EXTERN_WEAKLY_TRACKED_USER_TAG at + * the same time). */ nmp_rules_manager_track (rules_manager, &plrule, 10, - user_tag); + user_tag_1, + NMP_RULES_MANAGER_EXTERN_WEAKLY_TRACKED_USER_TAG); + } + } + + if (klass->get_extra_rules) { + gs_unref_ptrarray GPtrArray *extra_rules = NULL; + + extra_rules = klass->get_extra_rules (self); + if (extra_rules) { + for (i = 0; i < extra_rules->len; i++) { + nmp_rules_manager_track (rules_manager, + NMP_OBJECT_CAST_ROUTING_RULE (extra_rules->pdata[i]), + 10, + user_tag_2, + NMP_RULES_MANAGER_EXTERN_WEAKLY_TRACKED_USER_TAG); + } } } } - nmp_rules_manager_untrack_all (rules_manager, user_tag, !untrack_only_dirty); + nmp_rules_manager_untrack_all (rules_manager, user_tag_1, !untrack_only_dirty); + if (klass->get_extra_rules) + nmp_rules_manager_untrack_all (rules_manager, user_tag_2, !untrack_only_dirty); keep_deleted_rules = FALSE; if (set_mode == NM_TERNARY_DEFAULT) { @@ -6500,7 +6697,7 @@ tc_commit (NMDevice *self) NMSettingTCConfig *s_tc = NULL; int ip_ifindex; guint nqdiscs, ntfilters; - int i; + guint i; connection = nm_device_get_applied_connection (self); if (connection) @@ -6508,7 +6705,7 @@ tc_commit (NMDevice *self) ip_ifindex = nm_device_get_ip_ifindex (self); if (!ip_ifindex) - return s_tc == NULL; + return s_tc == NULL; if (s_tc) { nqdiscs = nm_setting_tc_config_get_num_qdiscs (s_tc); @@ -6520,12 +6717,40 @@ tc_commit (NMDevice *self) NMPlatformQdisc *qdisc = NMP_OBJECT_CAST_QDISC (q); qdisc->ifindex = ip_ifindex; + + /* Note: kind string is still owned by NMTCTfilter. + * This qdisc instance must not be kept alive beyond this function. + * nm_platform_qdisc_sync() promises to do that. */ qdisc->kind = nm_tc_qdisc_get_kind (s_qdisc); + qdisc->addr_family = AF_UNSPEC; qdisc->handle = nm_tc_qdisc_get_handle (s_qdisc); qdisc->parent = nm_tc_qdisc_get_parent (s_qdisc); qdisc->info = 0; +#define GET_ATTR(name, dst, variant_type, type, dflt) G_STMT_START { \ + GVariant *_variant = nm_tc_qdisc_get_attribute (s_qdisc, ""name""); \ + \ + if ( _variant \ + && g_variant_is_of_type (_variant, G_VARIANT_TYPE_ ## variant_type)) \ + (dst) = g_variant_get_ ## type (_variant); \ + else \ + (dst) = (dflt); \ +} G_STMT_END + + if (strcmp (qdisc->kind, "fq_codel") == 0) { + GET_ATTR ("limit", qdisc->fq_codel.limit, UINT32, uint32, 0); + GET_ATTR ("flows", qdisc->fq_codel.flows, UINT32, uint32, 0); + GET_ATTR ("target", qdisc->fq_codel.target, UINT32, uint32, 0); + GET_ATTR ("interval", qdisc->fq_codel.interval, UINT32, uint32, 0); + GET_ATTR ("quantum", qdisc->fq_codel.quantum, UINT32, uint32, 0); + GET_ATTR ("ce_threshold", qdisc->fq_codel.ce_threshold, UINT32, uint32, NM_PLATFORM_FQ_CODEL_CE_THRESHOLD_DISABLED); + GET_ATTR ("memory_limit", qdisc->fq_codel.memory_limit, UINT32, uint32, NM_PLATFORM_FQ_CODEL_MEMORY_LIMIT_UNSET); + GET_ATTR ("ecn", qdisc->fq_codel.ecn, BOOLEAN, boolean, FALSE); + } + +#undef GET_ADDR + g_ptr_array_add (qdiscs, q); } @@ -6539,7 +6764,12 @@ tc_commit (NMDevice *self) NMPlatformTfilter *tfilter = NMP_OBJECT_CAST_TFILTER (q); tfilter->ifindex = ip_ifindex; + + /* Note: kind string is still owned by NMTCTfilter. + * This tfilter instance must not be kept alive beyond this function. + * nm_platform_tfilter_sync() promises to do that. */ tfilter->kind = nm_tc_tfilter_get_kind (s_tfilter); + tfilter->addr_family = AF_UNSPEC; tfilter->handle = nm_tc_tfilter_get_handle (s_tfilter); tfilter->parent = nm_tc_tfilter_get_parent (s_tfilter); @@ -6547,16 +6777,42 @@ tc_commit (NMDevice *self) action = nm_tc_tfilter_get_action (s_tfilter); if (action) { + GVariant *var; + + /* Note: kind string is still owned by NMTCAction. + * This tfilter instance must not be kept alive beyond this function. + * nm_platform_tfilter_sync() promises to do that. */ tfilter->action.kind = nm_tc_action_get_kind (action); - if (strcmp (tfilter->action.kind, "simple") == 0) { - GVariant *sdata; - sdata = nm_tc_action_get_attribute (action, "sdata"); - if (sdata && g_variant_is_of_type (sdata, G_VARIANT_TYPE_BYTESTRING)) { + if (strcmp (tfilter->action.kind, "simple") == 0) { + var = nm_tc_action_get_attribute (action, "sdata"); + if (var && g_variant_is_of_type (var, G_VARIANT_TYPE_BYTESTRING)) { g_strlcpy (tfilter->action.simple.sdata, - g_variant_get_bytestring (sdata), + g_variant_get_bytestring (var), sizeof (tfilter->action.simple.sdata)); } + } else if (strcmp (tfilter->action.kind, "mirred") == 0) { + if (nm_tc_action_get_attribute (action, "egress")) + tfilter->action.mirred.egress = TRUE; + + if (nm_tc_action_get_attribute (action, "ingress")) + tfilter->action.mirred.ingress = TRUE; + + if (nm_tc_action_get_attribute (action, "mirror")) + tfilter->action.mirred.mirror = TRUE; + + if (nm_tc_action_get_attribute (action, "redirect")) + tfilter->action.mirred.redirect = TRUE; + + var = nm_tc_action_get_attribute (action, "dev"); + if (var && g_variant_is_of_type (var, G_VARIANT_TYPE_STRING)) { + int ifindex; + + ifindex = nm_platform_link_get_ifindex (nm_device_get_platform (self), + g_variant_get_string (var, NULL)); + if (ifindex > 0) + tfilter->action.mirred.ifindex = ifindex; + } } } @@ -6941,7 +7197,7 @@ ipv4ll_get_ip4_config (NMDevice *self, guint32 lla) route.network = htonl (0xE0000000L); route.plen = 4; route.rt_source = NM_IP_CONFIG_SOURCE_IP4LL; - route.table_coerced = nm_platform_route_table_coerce (nm_device_get_route_table (self, AF_INET, TRUE)); + route.table_coerced = nm_platform_route_table_coerce (nm_device_get_route_table (self, AF_INET)); route.metric = nm_device_get_route_metric (self, AF_INET); nm_ip4_config_add_route (config, &route, NULL); @@ -7110,12 +7366,12 @@ ensure_con_ip_config (NMDevice *self, int addr_family) nm_connection_get_setting_ip4_config (connection), _get_mdns (self), _get_llmnr (self), - nm_device_get_route_table (self, addr_family, TRUE), + nm_device_get_route_table (self, addr_family), nm_device_get_route_metric (self, addr_family)); } else { nm_ip6_config_merge_setting (NM_IP6_CONFIG (con_ip_config), nm_connection_get_setting_ip6_config (connection), - nm_device_get_route_table (self, addr_family, TRUE), + nm_device_get_route_table (self, addr_family), nm_device_get_route_metric (self, addr_family)); } @@ -7332,12 +7588,12 @@ ip_config_merge_and_apply (NMDevice *self, if (commit) { if (IS_IPv4) { nm_ip4_config_add_dependent_routes (NM_IP4_CONFIG (composite), - nm_device_get_route_table (self, addr_family, TRUE), + nm_device_get_route_table (self, addr_family), nm_device_get_route_metric (self, addr_family), &ip4_dev_route_blacklist); } else { nm_ip6_config_add_dependent_routes (NM_IP6_CONFIG (composite), - nm_device_get_route_table (self, addr_family, TRUE), + nm_device_get_route_table (self, addr_family), nm_device_get_route_metric (self, addr_family)); } } @@ -7350,15 +7606,23 @@ ip_config_merge_and_apply (NMDevice *self, } if (!IS_IPv4) { + const NMPlatformLink *link; NMUtilsIPv6IfaceId iid; + NMPlatform *platform; + int ifindex; if ( commit && priv->ndisc_started && ip6_addr_gen_token && nm_utils_ipv6_interface_identifier_get_from_token (&iid, ip6_addr_gen_token)) { - nm_platform_link_set_ipv6_token (nm_device_get_platform (self), - nm_device_get_ip_ifindex (self), - iid); + platform = nm_device_get_platform (self); + ifindex = nm_device_get_ip_ifindex (self); + link = nm_platform_link_get (platform, ifindex); + + if (link && link->inet6_token.id == iid.id) + _LOGT (LOGD_DEVICE | LOGD_IP6, "token %s already set", ip6_addr_gen_token); + else + nm_platform_link_set_ipv6_token (platform, ifindex, iid); } } @@ -7470,9 +7734,13 @@ clear_config: static void dhcp4_dad_cb (NMDevice *self, NMIP4Config **configs, gboolean success) { - if (success) + NMDevicePrivate *priv = NM_DEVICE_GET_PRIVATE (self); + + if (success) { + nm_dhcp_client_accept (priv->dhcp4.client, NULL); nm_device_activate_schedule_ip_config_result (self, AF_INET, NM_IP_CONFIG_CAST (configs[1])); - else { + } else { + nm_dhcp_client_decline (priv->dhcp4.client, "Address conflict detected", NULL); nm_device_ip_method_failed (self, AF_INET, NM_DEVICE_STATE_REASON_IP_ADDRESS_DUPLICATE); } @@ -7531,7 +7799,7 @@ dhcp4_state_changed (NMDhcpClient *client, 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_table (self, AF_INET), nm_device_get_route_metric (self, AF_INET)); configs = g_new0 (NMIP4Config *, 3); @@ -7738,9 +8006,11 @@ dhcp4_start (NMDevice *self) NMDevicePrivate *priv = NM_DEVICE_GET_PRIVATE (self); NMSettingIPConfig *s_ip4; gs_unref_bytes GBytes *hwaddr = NULL; + gs_unref_bytes GBytes *bcast_hwaddr = NULL; gs_unref_bytes GBytes *client_id = NULL; NMConnection *connection; GError *error = NULL; + const NMPlatformLink *pllink; connection = nm_device_get_applied_connection (self); g_return_val_if_fail (connection, FALSE); @@ -7751,8 +8021,11 @@ dhcp4_start (NMDevice *self) nm_dbus_object_clear_and_unexport (&priv->dhcp4.config); priv->dhcp4.config = nm_dhcp4_config_new (); - hwaddr = nm_platform_link_get_address_as_bytes (nm_device_get_platform (self), - nm_device_get_ip_ifindex (self)); + pllink = nm_platform_link_get (nm_device_get_platform (self), nm_device_get_ip_ifindex (self)); + if (pllink) { + hwaddr = nmp_link_address_get_as_bytes (&pllink->l_address); + bcast_hwaddr = nmp_link_address_get_as_bytes (&pllink->l_broadcast); + } client_id = dhcp4_get_client_id (self, connection, hwaddr); @@ -7762,8 +8035,9 @@ dhcp4_start (NMDevice *self) nm_device_get_ip_iface (self), nm_device_get_ip_ifindex (self), hwaddr, + bcast_hwaddr, nm_connection_get_uuid (connection), - nm_device_get_route_table (self, AF_INET, TRUE), + nm_device_get_route_table (self, AF_INET), nm_device_get_route_metric (self, AF_INET), nm_setting_ip_config_get_dhcp_send_hostname (s_ip4), nm_setting_ip_config_get_dhcp_hostname (s_ip4), @@ -7892,7 +8166,9 @@ connection_ip_method_requires_carrier (NMConnection *connection, NM_SETTING_IP4_CONFIG_METHOD_LINK_LOCAL); } - NM_SET_OUT (out_ip_enabled, !nm_streq (method, NM_SETTING_IP6_CONFIG_METHOD_IGNORE)); + NM_SET_OUT (out_ip_enabled, + !NM_IN_STRSET (method, NM_SETTING_IP6_CONFIG_METHOD_IGNORE, + NM_SETTING_IP6_CONFIG_METHOD_DISABLED)); return NM_IN_STRSET (method, NM_SETTING_IP6_CONFIG_METHOD_AUTO, NM_SETTING_IP6_CONFIG_METHOD_DHCP, NM_SETTING_IP6_CONFIG_METHOD_SHARED, @@ -8537,8 +8813,10 @@ 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 *bcast_hwaddr = NULL; gs_unref_bytes GBytes *duid = NULL; gboolean enforce_duid = FALSE; + const NMPlatformLink *pllink; GError *error = NULL; const NMPlatformIP6Address *ll_addr = NULL; @@ -8558,8 +8836,11 @@ dhcp6_start_with_link_ready (NMDevice *self, NMConnection *connection) return FALSE; } - hwaddr = nm_platform_link_get_address_as_bytes (nm_device_get_platform (self), - nm_device_get_ip_ifindex (self)); + pllink = nm_platform_link_get (nm_device_get_platform (self), nm_device_get_ip_ifindex (self)); + if (pllink) { + hwaddr = nmp_link_address_get_as_bytes (&pllink->l_address); + bcast_hwaddr = nmp_link_address_get_as_bytes (&pllink->l_broadcast); + } duid = dhcp6_get_duid (self, connection, hwaddr, &enforce_duid); priv->dhcp6.client = nm_dhcp_manager_start_ip6 (nm_dhcp_manager_get (), @@ -8567,9 +8848,10 @@ dhcp6_start_with_link_ready (NMDevice *self, NMConnection *connection) nm_device_get_ip_iface (self), nm_device_get_ip_ifindex (self), hwaddr, + bcast_hwaddr, &ll_addr->address, nm_connection_get_uuid (connection), - nm_device_get_route_table (self, AF_INET6, TRUE), + nm_device_get_route_table (self, AF_INET6), nm_device_get_route_metric (self, AF_INET6), nm_setting_ip_config_get_dhcp_send_hostname (s_ip6), nm_setting_ip_config_get_dhcp_hostname (s_ip6), @@ -9087,7 +9369,8 @@ _commit_mtu (NMDevice *self, const NMIP4Config *config) s_ip6 = nm_device_get_applied_setting (self, NM_TYPE_SETTING_IP6_CONFIG); if ( s_ip6 && !NM_IN_STRSET (nm_setting_ip_config_get_method (s_ip6), - NM_SETTING_IP6_CONFIG_METHOD_IGNORE)) { + NM_SETTING_IP6_CONFIG_METHOD_IGNORE + NM_SETTING_IP6_CONFIG_METHOD_DISABLED)) { /* the interface has IPv6 enabled. The MTU with IPv6 cannot be smaller * then 1280. * @@ -9262,7 +9545,7 @@ ndisc_config_changed (NMNDisc *ndisc, const NMNDiscData *rdata, guint changed_in rdata->gateways_n, rdata->routes, rdata->routes_n, - nm_device_get_route_table (self, AF_INET6, TRUE), + nm_device_get_route_table (self, AF_INET6), nm_device_get_route_metric (self, AF_INET6), nm_platform_kernel_support_get (NM_PLATFORM_KERNEL_SUPPORT_TYPE_RTA_PREF)); if (priv->ac_ip6_config.current) { @@ -9271,7 +9554,7 @@ ndisc_config_changed (NMNDisc *ndisc, const NMNDiscData *rdata, guint changed_in rdata->gateways_n, rdata->routes, rdata->routes_n, - nm_device_get_route_table (self, AF_INET6, TRUE), + nm_device_get_route_table (self, AF_INET6), nm_device_get_route_metric (self, AF_INET6), nm_platform_kernel_support_get (NM_PLATFORM_KERNEL_SUPPORT_TYPE_RTA_PREF)); } @@ -9763,7 +10046,7 @@ act_stage3_ip_config_start (NMDevice *self, 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_table (self, AF_INET), nm_device_get_route_metric (self, AF_INET)); configs = g_new0 (NMIP4Config *, 2); configs[0] = config; @@ -9795,6 +10078,11 @@ act_stage3_ip_config_start (NMDevice *self, NMSettingIP6ConfigPrivacy ip6_privacy = NM_SETTING_IP6_CONFIG_PRIVACY_UNKNOWN; const char *ip6_privacy_str = "0"; + if (nm_streq (method, NM_SETTING_IP6_CONFIG_METHOD_DISABLED)) { + nm_device_sysctl_ip_conf_set (self, AF_INET6, "disable_ipv6", "1"); + return NM_ACT_STAGE_RETURN_IP_DONE; + } + if (nm_streq (method, NM_SETTING_IP6_CONFIG_METHOD_IGNORE)) { if ( !priv->master && !nm_device_sys_iface_state_is_external (self)) { @@ -10948,7 +11236,7 @@ nm_device_reactivate_ip4_config (NMDevice *self, s_ip4_new, _get_mdns (self), _get_llmnr (self), - nm_device_get_route_table (self, AF_INET, TRUE), + nm_device_get_route_table (self, AF_INET), nm_device_get_route_metric (self, AF_INET)); method_old = s_ip4_old @@ -11022,7 +11310,7 @@ nm_device_reactivate_ip6_config (NMDevice *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), + nm_device_get_route_table (self, AF_INET6), nm_device_get_route_metric (self, AF_INET6)); method_old = s_ip6_old @@ -11073,21 +11361,17 @@ nm_device_reactivate_ip6_config (NMDevice *self, } static void -_pacrunner_manager_send (NMDevice *self) +_pacrunner_manager_add (NMDevice *self) { NMDevicePrivate *priv = NM_DEVICE_GET_PRIVATE (self); - nm_pacrunner_manager_remove_clear (priv->pacrunner_manager, - &priv->pacrunner_call_id); + nm_pacrunner_manager_remove_clear (&priv->pacrunner_conf_id); - if (!priv->pacrunner_manager) - priv->pacrunner_manager = g_object_ref (nm_pacrunner_manager_get ()); - - priv->pacrunner_call_id = nm_pacrunner_manager_send (priv->pacrunner_manager, - nm_device_get_ip_iface (self), - priv->proxy_config, - NULL, - NULL); + priv->pacrunner_conf_id = nm_pacrunner_manager_add (nm_pacrunner_manager_get (), + priv->proxy_config, + nm_device_get_ip_iface (self), + NULL, + NULL); } static void @@ -11095,16 +11379,19 @@ reactivate_proxy_config (NMDevice *self) { NMDevicePrivate *priv = NM_DEVICE_GET_PRIVATE (self); - if (!priv->pacrunner_call_id) + if (!priv->pacrunner_conf_id) return; nm_device_set_proxy_config (self, priv->dhcp4.pac_url); - _pacrunner_manager_send (self); + _pacrunner_manager_add (self); } static gboolean -can_reapply_change (NMDevice *self, const char *setting_name, - NMSetting *s_old, NMSetting *s_new, - GHashTable *diffs, GError **error) +can_reapply_change (NMDevice *self, + const char *setting_name, + NMSetting *s_old, + NMSetting *s_new, + GHashTable *diffs, + GError **error) { if (nm_streq (setting_name, NM_SETTING_CONNECTION_SETTING_NAME)) { /* Whitelist allowed properties from "connection" setting which are @@ -11127,32 +11414,9 @@ can_reapply_change (NMDevice *self, const char *setting_name, NM_SETTING_CONNECTION_MDNS, NM_SETTING_CONNECTION_LLMNR); } else if (NM_IN_STRSET (setting_name, - NM_SETTING_PROXY_SETTING_NAME)) { - return TRUE; - } else if (NM_IN_STRSET (setting_name, + NM_SETTING_PROXY_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 - * re-activation. - * - * The problem is really that changing the setting also affects the sync - * mode. So, switching from NM_IP_ROUTE_TABLE_SYNC_MODE_MAIN to - * NM_IP_ROUTE_TABLE_SYNC_MODE_FULL would somehow require us to get rid - * of additional routes, but we don't know which routes were added by NM - * and which should be removed. - * - * Note how nm_device_get_route_table() caches the value for the duration of the - * activation. */ - g_set_error (error, - NM_DEVICE_ERROR, - NM_DEVICE_ERROR_INCOMPATIBLE_CONNECTION, - "Can't reapply changes to '%s.%s' setting", - setting_name, - NM_SETTING_IP_CONFIG_ROUTE_TABLE); - return FALSE; - } return TRUE; } else { g_set_error (error, @@ -11278,7 +11542,7 @@ check_and_reapply_connection (NMDevice *self, || !nm_streq0 (nm_setting_connection_get_stable_id (s_con_a), nm_setting_connection_get_stable_id (s_con_n))) { connection_clean_free = nm_simple_connection_new_clone (connection); connection_clean = connection_clean_free; - s_con_n = nm_connection_get_setting_connection (connection); + s_con_n = nm_connection_get_setting_connection (connection_clean); g_object_set (s_con_n, NM_SETTING_CONNECTION_ID, nm_setting_connection_get_id (s_con_a), NM_SETTING_CONNECTION_UUID, nm_setting_connection_get_uuid (s_con_a), @@ -11298,8 +11562,17 @@ check_and_reapply_connection (NMDevice *self, priv->v4_commit_first_time = TRUE; priv->v6_commit_first_time = TRUE; + priv->v4_route_table_initialized = FALSE; + priv->v6_route_table_initialized = FALSE; + /************************************************************************** * Reapply changes + * + * Note that reapply_connection() is called as very first. This is for example + * important for NMDeviceWireGuard, which implements coerce_route_table() + * and get_extra_rules(). + * That is because NMDeviceWireGuard caches settings, so during reapply that + * cache must be updated *first*. *************************************************************************/ klass->reapply_connection (self, con_old, con_new); @@ -11312,9 +11585,14 @@ check_and_reapply_connection (NMDevice *self, s_ip6_old = nm_connection_get_setting_ip6_config (con_old); s_ip6_new = nm_connection_get_setting_ip6_config (con_new); + /* Allow reapply of MTU */ + priv->mtu_source = NM_DEVICE_MTU_SOURCE_NONE; + nm_device_reactivate_ip4_config (self, s_ip4_old, s_ip4_new); nm_device_reactivate_ip6_config (self, s_ip6_old, s_ip6_new); + _routing_rules_sync (self, NM_TERNARY_TRUE); + reactivate_proxy_config (self); return TRUE; @@ -12097,9 +12375,7 @@ nm_device_set_ip_config (NMDevice *self, if (IS_IPv4) { success = nm_ip4_config_commit (NM_IP4_CONFIG (new_config), nm_device_get_platform (self), - nm_device_get_route_table (self, addr_family, FALSE) - ? NM_IP_ROUTE_TABLE_SYNC_MODE_FULL - : NM_IP_ROUTE_TABLE_SYNC_MODE_MAIN); + _get_route_table_sync_mode_stateful (self, addr_family)); nm_platform_ip4_dev_route_blacklist_set (nm_device_get_platform (self), nm_ip_config_get_ifindex (new_config), ip4_dev_route_blacklist); @@ -12108,9 +12384,7 @@ nm_device_set_ip_config (NMDevice *self, success = nm_ip6_config_commit (NM_IP6_CONFIG (new_config), nm_device_get_platform (self), - nm_device_get_route_table (self, addr_family, FALSE) - ? NM_IP_ROUTE_TABLE_SYNC_MODE_FULL - : NM_IP_ROUTE_TABLE_SYNC_MODE_MAIN, + _get_route_table_sync_mode_stateful (self, addr_family), &temporary_not_available); if (!_rt6_temporary_not_available_set (self, temporary_not_available)) @@ -12173,16 +12447,28 @@ nm_device_set_ip_config (NMDevice *self, if ( nm_device_sys_iface_state_is_external (self) && (settings_connection = nm_device_get_settings_connection (self)) - && NM_FLAGS_HAS (nm_settings_connection_get_flags (settings_connection), - NM_SETTINGS_CONNECTION_INT_FLAGS_NM_GENERATED) + && NM_FLAGS_ALL (nm_settings_connection_get_flags (settings_connection), + NM_SETTINGS_CONNECTION_INT_FLAGS_UNSAVED + | NM_SETTINGS_CONNECTION_INT_FLAGS_VOLATILE + | NM_SETTINGS_CONNECTION_INT_FLAGS_NM_GENERATED) && nm_active_connection_get_activation_type (NM_ACTIVE_CONNECTION (priv->act_request.obj)) == NM_ACTIVATION_TYPE_EXTERNAL) { - g_object_freeze_notify (G_OBJECT (settings_connection)); - /* FIXME(copy-on-write-connection): avoid modifying NMConnection instances and share them via copy-on-write. */ - nm_connection_add_setting (nm_settings_connection_get_connection (settings_connection), + gs_unref_object NMConnection *new_connection = NULL; + + new_connection = nm_simple_connection_new_clone (nm_settings_connection_get_connection (settings_connection)); + + nm_connection_add_setting (new_connection, IS_IPv4 ? nm_ip4_config_create_setting (priv->ip_config_4) : nm_ip6_config_create_setting (priv->ip_config_6)); - g_object_thaw_notify (G_OBJECT (settings_connection)); + + nm_settings_connection_update (settings_connection, + new_connection, + NM_SETTINGS_CONNECTION_PERSIST_MODE_IN_MEMORY, + NM_SETTINGS_CONNECTION_INT_FLAGS_NONE, + NM_SETTINGS_CONNECTION_INT_FLAGS_NONE, + NM_SETTINGS_CONNECTION_UPDATE_REASON_NONE, + "update-external", + NULL); } nm_device_queue_recheck_assume (self); @@ -12307,29 +12593,31 @@ nm_device_get_ip6_config (NMDevice *self) /*****************************************************************************/ -static void +static gboolean dispatcher_cleanup (NMDevice *self) { NMDevicePrivate *priv = NM_DEVICE_GET_PRIVATE (self); - if (priv->dispatcher.call_id) { - nm_dispatcher_call_cancel (priv->dispatcher.call_id); - priv->dispatcher.call_id = 0; - priv->dispatcher.post_state = NM_DEVICE_STATE_UNKNOWN; - priv->dispatcher.post_state_reason = NM_DEVICE_STATE_REASON_NONE; - } + if (!priv->dispatcher.call_id) + return FALSE; + + nm_dispatcher_call_cancel (g_steal_pointer (&priv->dispatcher.call_id)); + priv->dispatcher.post_state = NM_DEVICE_STATE_UNKNOWN; + priv->dispatcher.post_state_reason = NM_DEVICE_STATE_REASON_NONE; + return TRUE; } static void -dispatcher_complete_proceed_state (guint call_id, gpointer user_data) +dispatcher_complete_proceed_state (NMDispatcherCallId *call_id, gpointer user_data) { NMDevice *self = NM_DEVICE (user_data); NMDevicePrivate *priv = NM_DEVICE_GET_PRIVATE (self); g_return_if_fail (call_id == priv->dispatcher.call_id); - priv->dispatcher.call_id = 0; - nm_device_queue_state (self, priv->dispatcher.post_state, + priv->dispatcher.call_id = NULL; + nm_device_queue_state (self, + priv->dispatcher.post_state, priv->dispatcher.post_state_reason); priv->dispatcher.post_state = NM_DEVICE_STATE_UNKNOWN; priv->dispatcher.post_state_reason = NM_DEVICE_STATE_REASON_NONE; @@ -12342,10 +12630,8 @@ ip_check_pre_up (NMDevice *self) { NMDevicePrivate *priv = NM_DEVICE_GET_PRIVATE (self); - if (priv->dispatcher.call_id != 0) { - g_warn_if_reached (); - dispatcher_cleanup (self); - } + if (dispatcher_cleanup (self)) + nm_assert_not_reached (); priv->dispatcher.post_state = NM_DEVICE_STATE_SECONDARIES; priv->dispatcher.post_state_reason = NM_DEVICE_STATE_REASON_NONE; @@ -12883,7 +13169,8 @@ update_ext_ip_config (NMDevice *self, int addr_family, gboolean intersect_config for (iter = priv->vpn_configs_6; iter; iter = iter->next) nm_ip6_config_intersect (iter->data, priv->ext_ip_config_6, is_up, is_up, 0); - if ( priv->ipv6ll_has + if ( is_up + && priv->ipv6ll_has && !nm_ip6_config_lookup_address (priv->ext_ip_config_6, &priv->ipv6ll_addr)) priv->ipv6ll_has = FALSE; } @@ -13218,7 +13505,7 @@ _get_managed_by_flags(NMUnmanagedFlags flags, NMUnmanagedFlags mask, gboolean fo return TRUE; /* A for-user-request, is effectively the same as pretending - * that user-dbus flag is cleared. */ + * that user-explicit flag is cleared. */ mask |= NM_UNMANAGED_USER_EXPLICIT; flags &= ~NM_UNMANAGED_USER_EXPLICIT; } @@ -13270,6 +13557,9 @@ _get_managed_by_flags(NMUnmanagedFlags flags, NMUnmanagedFlags mask, gboolean fo * nm_device_get_managed: * @self: the #NMDevice * @for_user_request: whether to check the flags for an explicit user-request + * Setting this to %TRUE has the same effect as if %NM_UNMANAGED_USER_EXPLICIT + * unmanaged flag would be unset (meaning: explicitly not-unmanaged). + * If this parameter is %TRUE, the device can only appear more managed. * * Whether the device is unmanaged according to the unmanaged flags. * @@ -13839,13 +14129,17 @@ _nm_device_check_connection_available (NMDevice *self, return FALSE; } if (state < NM_DEVICE_STATE_UNAVAILABLE) { - if (!nm_device_get_managed (self, TRUE)) { - if (!nm_device_get_managed (self, FALSE)) { + if (nm_device_get_managed (self, FALSE)) { + /* device is managed, both for user-requests and non-user-requests alike. */ + } else { + if (!nm_device_get_managed (self, TRUE)) { + /* device is strictly unmanaged by authoritative unmanaged reasons. */ nm_utils_error_set_literal (error, NM_UTILS_ERROR_CONNECTION_AVAILABLE_UNMANAGED_DEVICE, "device is strictly unmanaged"); return FALSE; } if (!NM_FLAGS_HAS (flags, _NM_DEVICE_CHECK_CON_AVAILABLE_FOR_USER_REQUEST_OVERRULE_UNMANAGED)) { + /* device could be managed for an explict user-request, but this is not such a request. */ nm_utils_error_set_literal (error, NM_UTILS_ERROR_CONNECTION_AVAILABLE_UNMANAGED_DEVICE, "device is currently unmanaged"); return FALSE; @@ -14126,7 +14420,7 @@ cp_connection_added (NMSettings *settings, NMSettingsConnection *sett_conn, gpoi } static void -cp_connection_updated (NMSettings *settings, NMSettingsConnection *sett_conn, gboolean by_user, gpointer user_data) +cp_connection_updated (NMSettings *settings, NMSettingsConnection *sett_conn, guint update_reason_u, gpointer user_data) { cp_connection_added_or_updated (user_data, sett_conn); } @@ -14339,6 +14633,9 @@ _cleanup_generic_post (NMDevice *self, CleanupType cleanup_type) priv->v4_route_table_initialized = FALSE; priv->v6_route_table_initialized = FALSE; + priv->v4_route_table_full_sync_before = FALSE; + priv->v6_route_table_full_sync_before = FALSE; + priv->default_route_metric_penalty_ip4_has = FALSE; priv->default_route_metric_penalty_ip6_has = FALSE; @@ -14732,6 +15029,34 @@ ip6_managed_setup (NMDevice *self) } static void +deactivate_ready (NMDevice *self, NMDeviceStateReason reason) +{ + NMDevicePrivate *priv = NM_DEVICE_GET_PRIVATE (self); + + if (priv->dispatcher.call_id) + return; + + if (priv->sriov.pending) + return; + nm_assert (!priv->sriov.next); + + nm_device_queue_state (self, NM_DEVICE_STATE_DISCONNECTED, reason); +} + +static void +sriov_deactivate_cb (GError *error, gpointer user_data) +{ + NMDevice *self; + gpointer reason; + + if (nm_utils_error_is_cancelled (error, TRUE)) + return; + + nm_utils_user_data_unpack (user_data, &self, &reason); + deactivate_ready (self, (NMDeviceStateReason) reason); +} + +static void deactivate_async_ready (NMDevice *self, GError *error, gpointer user_data) @@ -14751,11 +15076,12 @@ deactivate_async_ready (NMDevice *self, _LOGW (LOGD_DEVICE, "Deactivation failed: %s", error->message); } - nm_device_queue_state (self, NM_DEVICE_STATE_DISCONNECTED, reason); + + deactivate_ready (self, reason); } static void -deactivate_dispatcher_complete (guint call_id, gpointer user_data) +deactivate_dispatcher_complete (NMDispatcherCallId *call_id, gpointer user_data) { NMDevice *self = NM_DEVICE (user_data); NMDevicePrivate *priv = NM_DEVICE_GET_PRIVATE (self); @@ -14764,9 +15090,9 @@ deactivate_dispatcher_complete (guint call_id, gpointer user_data) g_return_if_fail (call_id == priv->dispatcher.call_id); g_return_if_fail (priv->dispatcher.post_state == NM_DEVICE_STATE_DISCONNECTED); - reason = priv->dispatcher.post_state_reason; + reason = priv->state_reason; - priv->dispatcher.call_id = 0; + priv->dispatcher.call_id = NULL; priv->dispatcher.post_state = NM_DEVICE_STATE_UNKNOWN; priv->dispatcher.post_state_reason = NM_DEVICE_STATE_REASON_NONE; @@ -14780,7 +15106,7 @@ deactivate_dispatcher_complete (guint call_id, gpointer user_data) deactivate_async_ready, GUINT_TO_POINTER (reason)); } else - nm_device_queue_state (self, NM_DEVICE_STATE_DISCONNECTED, reason); + deactivate_ready (self, reason); } static void @@ -14993,12 +15319,6 @@ _set_state_full (NMDevice *self, } break; case NM_DEVICE_STATE_DEACTIVATING: - if ( (s_sriov = nm_device_get_applied_setting (self, NM_TYPE_SETTING_SRIOV)) - && priv->ifindex > 0) { - nm_platform_link_set_sriov_params (nm_device_get_platform (self), - priv->ifindex, 0, NM_TERNARY_TRUE); - } - _cancel_activation (self); /* We cache the ignore_carrier state to not react on config-reloads while the connection @@ -15020,10 +15340,18 @@ _set_state_full (NMDevice *self, /* Just proceed on errors */ deactivate_dispatcher_complete (0, self); } + + if ( priv->ifindex > 0 + && (s_sriov = nm_device_get_applied_setting (self, NM_TYPE_SETTING_SRIOV))) { + sriov_op_queue (self, + 0, + NM_TERNARY_TRUE, + sriov_deactivate_cb, + nm_utils_user_data_pack (self, (gpointer) reason)); + } } - nm_pacrunner_manager_remove_clear (priv->pacrunner_manager, - &priv->pacrunner_call_id); + nm_pacrunner_manager_remove_clear (&priv->pacrunner_conf_id); break; case NM_DEVICE_STATE_DISCONNECTED: if ( priv->queued_act_request @@ -15043,7 +15371,7 @@ _set_state_full (NMDevice *self, NULL, NULL, NULL); if (priv->proxy_config) - _pacrunner_manager_send (self); + _pacrunner_manager_add (self); break; case NM_DEVICE_STATE_FAILED: /* Usually upon failure the activation chain is interrupted in @@ -15076,7 +15404,7 @@ _set_state_full (NMDevice *self, * and those we haven't tried yet (no timestamp). */ if (sett_conn && !nm_settings_connection_get_timestamp (sett_conn, NULL)) - nm_settings_connection_update_timestamp (sett_conn, (guint64) 0, TRUE); + nm_settings_connection_update_timestamp (sett_conn, (guint64) 0); /* Schedule the transition to DISCONNECTED. The device can't transition * immediately because we can't change states again from the state @@ -16286,9 +16614,7 @@ dispose (GObject *object) dispatcher_cleanup (self); - nm_pacrunner_manager_remove_clear (priv->pacrunner_manager, - &priv->pacrunner_call_id); - g_clear_object (&priv->pacrunner_manager); + nm_pacrunner_manager_remove_clear (&priv->pacrunner_conf_id); _cleanup_generic_pre (self, CLEANUP_TYPE_KEEP); diff --git a/src/devices/nm-device.h b/src/devices/nm-device.h index d11c33ab..ae6aab39 100644 --- a/src/devices/nm-device.h +++ b/src/devices/nm-device.h @@ -1,4 +1,3 @@ -/* -*- Mode: C; tab-width: 4; indent-tabs-mode: t; c-basic-offset: 4 -*- */ /* NetworkManager -- Network link manager * * This program is free software; you can redistribute it and/or modify @@ -321,6 +320,12 @@ typedef struct _NMDeviceClass { void (* set_enabled) (NMDevice *self, gboolean enabled); + /* let the subclass return additional NMPlatformRoutingRule (in form of NMPObject + * pointers) that shall be added to the rules provided by this device. + * The returned GPtrArray will be g_ptr_array_unref()'ed. The subclass may or + * may not keep an additional reference and return this array again and again. */ + GPtrArray *(*get_extra_rules) (NMDevice *self); + /* allow derived classes to override the result of nm_device_autoconnect_allowed(). * If the value changes, the class should call nm_device_emit_recheck_auto_activate(), * which emits NM_DEVICE_RECHECK_AUTO_ACTIVATE signal. */ @@ -332,6 +337,13 @@ typedef struct _NMDeviceClass { guint32 (*get_configured_mtu) (NMDevice *self, NMDeviceMtuSource *out_source); + /* allow the subclass to overwrite the routing table. This is mainly useful + * to change from partial mode (route-table=0) to full-sync mode (route-table=254). */ + guint32 (*coerce_route_table) (NMDevice *self, + int addr_family, + guint32 route_table, + gboolean is_user_config); + const char *(*get_auto_ip_config_method) (NMDevice *self, int addr_family); /* Checks whether the connection is compatible with the device using @@ -497,7 +509,7 @@ NMDeviceType nm_device_get_device_type (NMDevice *dev); NMLinkType nm_device_get_link_type (NMDevice *dev); NMMetered nm_device_get_metered (NMDevice *dev); -guint32 nm_device_get_route_table (NMDevice *self, int addr_family, gboolean fallback_main); +guint32 nm_device_get_route_table (NMDevice *self, int addr_family); guint32 nm_device_get_route_metric (NMDevice *dev, int addr_family); guint32 nm_device_get_route_metric_default (NMDeviceType device_type); diff --git a/src/devices/nm-lldp-listener.c b/src/devices/nm-lldp-listener.c index 831054ba..c0d78315 100644 --- a/src/devices/nm-lldp-listener.c +++ b/src/devices/nm-lldp-listener.c @@ -1,4 +1,3 @@ -/* -*- Mode: C; tab-width: 4; indent-tabs-mode: t; c-basic-offset: 4 -*- */ /* NetworkManager -- Network link manager * * This program is free software; you can redistribute it and/or modify diff --git a/src/devices/nm-lldp-listener.h b/src/devices/nm-lldp-listener.h index 1afa8456..c44ca59f 100644 --- a/src/devices/nm-lldp-listener.h +++ b/src/devices/nm-lldp-listener.h @@ -1,4 +1,3 @@ -/* -*- Mode: C; tab-width: 4; indent-tabs-mode: t; c-basic-offset: 4 -*- */ /* NetworkManager -- Network link manager * * This program is free software; you can redistribute it and/or modify diff --git a/src/devices/ovs/nm-device-ovs-interface.c b/src/devices/ovs/nm-device-ovs-interface.c index e3d3f9ee..83de3c3d 100644 --- a/src/devices/ovs/nm-device-ovs-interface.c +++ b/src/devices/ovs/nm-device-ovs-interface.c @@ -95,6 +95,7 @@ check_connection_compatible (NMDevice *device, NMConnection *connection, GError s_ovs_iface = nm_connection_get_setting_ovs_interface (connection); if (!NM_IN_STRSET (nm_setting_ovs_interface_get_interface_type (s_ovs_iface), + "dpdk", "internal", "patch")) { nm_utils_error_set_literal (error, NM_UTILS_ERROR_CONNECTION_AVAILABLE_TEMPORARY, diff --git a/src/devices/ovs/nm-device-ovs-port.c b/src/devices/ovs/nm-device-ovs-port.c index 35eb739f..8a93a5a9 100644 --- a/src/devices/ovs/nm-device-ovs-port.c +++ b/src/devices/ovs/nm-device-ovs-port.c @@ -140,13 +140,18 @@ del_iface_cb (GError *error, gpointer user_data) static void release_slave (NMDevice *device, NMDevice *slave, gboolean configure) { - nm_ovsdb_del_interface (nm_ovsdb_get (), nm_device_get_iface (slave), - del_iface_cb, g_object_ref (slave)); - - /* Open VSwitch is going to delete this one. We must ignore what happens - * next with the interface. */ - if (NM_IS_DEVICE_OVS_INTERFACE (slave)) - nm_device_update_from_platform_link (slave, NULL); + NMDeviceOvsPort *self = NM_DEVICE_OVS_PORT (device); + + if (configure) { + _LOGI (LOGD_DEVICE, "releasing ovs interface %s", nm_device_get_ip_iface (slave)); + nm_ovsdb_del_interface (nm_ovsdb_get (), nm_device_get_iface (slave), + del_iface_cb, g_object_ref (slave)); + /* Open VSwitch is going to delete this one. We must ignore what happens + * next with the interface. */ + if (NM_IS_DEVICE_OVS_INTERFACE (slave)) + nm_device_update_from_platform_link (slave, NULL); + } else + _LOGI (LOGD_DEVICE, "ovs interface %s was released", nm_device_get_ip_iface (slave)); } /*****************************************************************************/ diff --git a/src/devices/ovs/nm-ovs-factory.c b/src/devices/ovs/nm-ovs-factory.c index 2124b2a0..fdf07bd3 100644 --- a/src/devices/ovs/nm-ovs-factory.c +++ b/src/devices/ovs/nm-ovs-factory.c @@ -26,7 +26,9 @@ #include "nm-device-ovs-bridge.h" #include "platform/nm-platform.h" #include "nm-core-internal.h" +#include "settings/nm-settings.h" #include "devices/nm-device-factory.h" +#include "devices/nm-device-private.h" /*****************************************************************************/ @@ -51,7 +53,13 @@ G_DEFINE_TYPE (NMOvsFactory, nm_ovs_factory, NM_TYPE_DEVICE_FACTORY) /*****************************************************************************/ #define _NMLOG_DOMAIN LOGD_DEVICE -#define _NMLOG(level, ...) __NMLOG_DEFAULT (level, _NMLOG_DOMAIN, "ovs", __VA_ARGS__) +#define _NMLOG(level, ifname, con_uuid, ...) \ + G_STMT_START { \ + nm_log ((level), _NMLOG_DOMAIN, (ifname), (con_uuid), \ + "ovs: " _NM_UTILS_MACRO_FIRST(__VA_ARGS__) \ + _NM_UTILS_MACRO_REST(__VA_ARGS__)); \ + } G_STMT_END + /*****************************************************************************/ @@ -139,6 +147,36 @@ ovsdb_device_removed (NMOvsdb *ovsdb, const char *name, NMDeviceType device_type } static void +ovsdb_interface_failed (NMOvsdb *ovsdb, + const char *name, + const char *connection_uuid, + const char *error, + NMDeviceFactory *self) +{ + NMDevice *device = NULL; + NMSettingsConnection *connection = NULL; + + _LOGI (name, connection_uuid, "ovs interface \"%s\" (%s) failed: %s", name, connection_uuid, error); + + device = nm_manager_get_device (nm_manager_get (), name, NM_DEVICE_TYPE_OVS_INTERFACE); + if (!device) + return; + + if (connection_uuid) + connection = nm_settings_get_connection_by_uuid (nm_device_get_settings (device), connection_uuid); + + if (connection) { + nm_settings_connection_autoconnect_blocked_reason_set (connection, + NM_SETTINGS_AUTO_CONNECT_BLOCKED_REASON_FAILED, + TRUE); + } + + nm_device_state_changed (device, + NM_DEVICE_STATE_FAILED, + NM_DEVICE_STATE_REASON_OVSDB_FAILED); +} + +static void start (NMDeviceFactory *self) { NMOvsdb *ovsdb; @@ -147,6 +185,7 @@ start (NMDeviceFactory *self) g_signal_connect_object (ovsdb, NM_OVSDB_DEVICE_ADDED, G_CALLBACK (ovsdb_device_added), self, (GConnectFlags) 0); g_signal_connect_object (ovsdb, NM_OVSDB_DEVICE_REMOVED, G_CALLBACK (ovsdb_device_removed), self, (GConnectFlags) 0); + g_signal_connect_object (ovsdb, NM_OVSDB_INTERFACE_FAILED, G_CALLBACK (ovsdb_interface_failed), self, (GConnectFlags) 0); } static NMDevice * diff --git a/src/devices/ovs/nm-ovsdb.c b/src/devices/ovs/nm-ovsdb.c index 5b50f840..e5de466c 100644 --- a/src/devices/ovs/nm-ovsdb.c +++ b/src/devices/ovs/nm-ovsdb.c @@ -25,8 +25,7 @@ #include <gio/gunixsocketaddress.h> #include "nm-glib-aux/nm-jansson.h" -#include "devices/nm-device.h" -#include "platform/nm-platform.h" +#include "nm-core-utils.h" #include "nm-core-internal.h" /*****************************************************************************/ @@ -58,7 +57,7 @@ typedef struct { enum { DEVICE_ADDED, DEVICE_REMOVED, - DEVICE_CHANGED, + INTERFACE_FAILED, LAST_SIGNAL }; @@ -341,6 +340,7 @@ _insert_interface (json_t *params, NMConnection *interface) { const char *type = NULL; NMSettingOvsInterface *s_ovs_iface; + NMSettingOvsDpdk *s_ovs_dpdk; NMSettingOvsPatch *s_ovs_patch; json_t *options = json_array (); @@ -349,11 +349,20 @@ _insert_interface (json_t *params, NMConnection *interface) type = nm_setting_ovs_interface_get_interface_type (s_ovs_iface); json_array_append_new (options, json_string ("map")); - s_ovs_patch = nm_connection_get_setting_ovs_patch (interface); - if (s_ovs_patch) { + + s_ovs_dpdk = (NMSettingOvsDpdk *) nm_connection_get_setting (interface, + NM_TYPE_SETTING_OVS_DPDK); + if (!s_ovs_dpdk) + s_ovs_patch = nm_connection_get_setting_ovs_patch (interface); + + if (s_ovs_dpdk) { + json_array_append_new (options, json_pack ("[[s, s]]", + "dpdk-devargs", + nm_setting_ovs_dpdk_get_devargs (s_ovs_dpdk))); + } else if (s_ovs_patch) { json_array_append_new (options, json_pack ("[[s, s]]", - "peer", - nm_setting_ovs_patch_get_peer (s_ovs_patch))); + "peer", + nm_setting_ovs_patch_get_peer (s_ovs_patch))); } else { json_array_append_new (options, json_array ()); } @@ -436,6 +445,7 @@ _insert_bridge (json_t *params, NMConnection *bridge, json_t *new_ports) gboolean mcast_snooping_enable = FALSE; gboolean rstp_enable = FALSE; gboolean stp_enable = FALSE; + const char *datapath_type = NULL; json_t *row; s_ovs_bridge = nm_connection_get_setting_ovs_bridge (bridge); @@ -447,6 +457,7 @@ _insert_bridge (json_t *params, NMConnection *bridge, json_t *new_ports) mcast_snooping_enable = nm_setting_ovs_bridge_get_mcast_snooping_enable (s_ovs_bridge); rstp_enable = nm_setting_ovs_bridge_get_rstp_enable (s_ovs_bridge); stp_enable = nm_setting_ovs_bridge_get_stp_enable (s_ovs_bridge); + datapath_type = nm_setting_ovs_bridge_get_datapath_type (s_ovs_bridge); } if (fail_mode) @@ -457,6 +468,8 @@ _insert_bridge (json_t *params, NMConnection *bridge, json_t *new_ports) json_object_set_new (row, "rstp_enable", json_boolean (rstp_enable)); if (stp_enable) json_object_set_new (row, "stp_enable", json_boolean (stp_enable)); + if (datapath_type) + json_object_set_new (row, "datapath_type", json_string (datapath_type)); json_object_set_new (row, "name", json_string (nm_connection_get_interface_name (bridge))); json_object_set_new (row, "ports", json_pack ("[s, O]", "set", new_ports)); @@ -534,9 +547,14 @@ _add_interface (NMOvsdb *self, json_t *params, json_array_append_new (ports, json_pack ("[s, s]", "uuid", port_uuid)); - if ( g_strcmp0 (ovs_port->name, nm_connection_get_interface_name (port)) != 0 - || g_strcmp0 (ovs_port->connection_uuid, nm_connection_get_uuid (port)) != 0) + if (!ovs_port) { + /* This would be a violation of ovsdb's reference integrity (a bug). */ + _LOGW ("Unknown port '%s' in bridge '%s'", port_uuid, bridge_uuid); continue; + } else if ( strcmp (ovs_port->name, nm_connection_get_interface_name (port)) != 0 + || g_strcmp0 (ovs_port->connection_uuid, nm_connection_get_uuid (port)) != 0) { + continue; + } for (ii = 0; ii < ovs_port->interfaces->len; ii++) { interface_uuid = g_ptr_array_index (ovs_port->interfaces, ii); @@ -544,9 +562,13 @@ _add_interface (NMOvsdb *self, json_t *params, json_array_append_new (interfaces, json_pack ("[s, s]", "uuid", interface_uuid)); - if ( g_strcmp0 (ovs_interface->name, nm_connection_get_interface_name (interface)) == 0 - && g_strcmp0 (ovs_interface->connection_uuid, nm_connection_get_uuid (interface)) == 0) + if (!ovs_interface) { + /* This would be a violation of ovsdb's reference integrity (a bug). */ + _LOGW ("Unknown interface '%s' in port '%s'", interface_uuid, port_uuid); + } else if ( strcmp (ovs_interface->name, nm_connection_get_interface_name (interface)) == 0 + && g_strcmp0 (ovs_interface->connection_uuid, nm_connection_get_uuid (interface)) == 0) { has_interface = TRUE; + } } break; @@ -642,16 +664,27 @@ _delete_interface (NMOvsdb *self, json_t *params, const char *ifname) interfaces_changed = FALSE; + if (!ovs_port) { + /* This would be a violation of ovsdb's reference integrity (a bug). */ + _LOGW ("Unknown port '%s' in bridge '%s'", port_uuid, bridge_uuid); + continue; + } + for (ii = 0; ii < ovs_port->interfaces->len; ii++) { interface_uuid = g_ptr_array_index (ovs_port->interfaces, ii); ovs_interface = g_hash_table_lookup (priv->interfaces, interface_uuid); json_array_append_new (interfaces, json_pack ("[s,s]", "uuid", interface_uuid)); - if (strcmp (ovs_interface->name, ifname) == 0) { - /* skip the interface */ - interfaces_changed = TRUE; - continue; + if (ovs_interface) { + if (strcmp (ovs_interface->name, ifname) == 0) { + /* skip the interface */ + interfaces_changed = TRUE; + continue; + } + } else { + /* This would be a violation of ovsdb's reference integrity (a bug). */ + _LOGW ("Unknown interface '%s' in port '%s'", interface_uuid, port_uuid); } json_array_append_new (new_interfaces, json_pack ("[s,s]", "uuid", interface_uuid)); @@ -718,14 +751,14 @@ ovsdb_next_command (NMOvsdb *self) msg = json_pack ("{s:i, s:s, s:[s, n, {" " s:[{s:[s, s, s]}]," " s:[{s:[s, s, s]}]," - " s:[{s:[s, s, s]}]," + " s:[{s:[s, s, s, s]}]," " s:[{s:[]}]" "}]}", "id", call->id, "method", "monitor", "params", "Open_vSwitch", "Bridge", "columns", "name", "ports", "external_ids", "Port", "columns", "name", "interfaces", "external_ids", - "Interface", "columns", "name", "type", "external_ids", + "Interface", "columns", "name", "type", "external_ids", "error", "Open_vSwitch", "columns"); break; case OVSDB_ADD_INTERFACE: @@ -864,21 +897,25 @@ ovsdb_got_update (NMOvsdb *self, json_t *msg) /* Interfaces */ json_object_foreach (interface, key, value) { + json_t *error = NULL; gboolean old = FALSE; gboolean new = FALSE; if (json_unpack (value, "{s:{}}", "old") == 0) old = TRUE; - if (json_unpack (value, "{s:{s:s, s:s, s:o}}", "new", + if (json_unpack (value, "{s:{s:s, s:s, s?:o, s:o}}", "new", "name", &name, "type", &type, + "error", &error, "external_ids", &external_ids) == 0) new = TRUE; if (old) { ovs_interface = g_hash_table_lookup (priv->interfaces, key); - if (!new || g_strcmp0 (ovs_interface->name, name) != 0) { + if (!ovs_interface) { + _LOGW ("Interface '%s' was not seen", key); + } else if (!new || strcmp (ovs_interface->name, name) != 0) { old = FALSE; _LOGT ("removed an '%s' interface: %s%s%s", ovs_interface->type, ovs_interface->name, @@ -899,12 +936,11 @@ ovsdb_got_update (NMOvsdb *self, json_t *msg) ovs_interface->name = g_strdup (name); ovs_interface->type = g_strdup (type); ovs_interface->connection_uuid = _connection_uuid_from_external_ids (external_ids); + g_hash_table_insert (priv->interfaces, g_strdup (key), ovs_interface); if (old) { _LOGT ("changed an '%s' interface: %s%s%s", type, ovs_interface->name, ovs_interface->connection_uuid ? ", " : "", ovs_interface->connection_uuid ?: ""); - g_signal_emit (self, signals[DEVICE_CHANGED], 0, - "ovs-interface", ovs_interface->name); } else { _LOGT ("added an '%s' interface: %s%s%s", ovs_interface->type, ovs_interface->name, @@ -917,7 +953,14 @@ ovsdb_got_update (NMOvsdb *self, json_t *msg) ovs_interface->name, NM_DEVICE_TYPE_OVS_INTERFACE); } } - g_hash_table_insert (priv->interfaces, g_strdup (key), ovs_interface); + /* The error is a string. No error is indicated by an empty set, + * because why the fuck not: [ "set": [] ] */ + if (error && json_is_string (error)) { + g_signal_emit (self, signals[INTERFACE_FAILED], 0, + ovs_interface->name, + ovs_interface->connection_uuid, + json_string_value (error)); + } } } @@ -954,12 +997,11 @@ ovsdb_got_update (NMOvsdb *self, json_t *msg) ovs_port->connection_uuid = _connection_uuid_from_external_ids (external_ids); ovs_port->interfaces = g_ptr_array_new_with_free_func (g_free); _uuids_to_array (ovs_port->interfaces, items); + g_hash_table_insert (priv->ports, g_strdup (key), ovs_port); if (old) { _LOGT ("changed a port: %s%s%s", ovs_port->name, ovs_port->connection_uuid ? ", " : "", ovs_port->connection_uuid ?: ""); - g_signal_emit (self, signals[DEVICE_CHANGED], 0, - NM_SETTING_OVS_PORT_SETTING_NAME, ovs_port->name); } else { _LOGT ("added a port: %s%s%s", ovs_port->name, ovs_port->connection_uuid ? ", " : "", @@ -967,7 +1009,6 @@ ovsdb_got_update (NMOvsdb *self, json_t *msg) g_signal_emit (self, signals[DEVICE_ADDED], 0, ovs_port->name, NM_DEVICE_TYPE_OVS_PORT); } - g_hash_table_insert (priv->ports, g_strdup (key), ovs_port); } } @@ -1004,12 +1045,11 @@ ovsdb_got_update (NMOvsdb *self, json_t *msg) ovs_bridge->connection_uuid = _connection_uuid_from_external_ids (external_ids); ovs_bridge->ports = g_ptr_array_new_with_free_func (g_free); _uuids_to_array (ovs_bridge->ports, items); + g_hash_table_insert (priv->bridges, g_strdup (key), ovs_bridge); if (old) { _LOGT ("changed a bridge: %s%s%s", ovs_bridge->name, ovs_bridge->connection_uuid ? ", " : "", ovs_bridge->connection_uuid ?: ""); - g_signal_emit (self, signals[DEVICE_CHANGED], 0, - NM_SETTING_OVS_BRIDGE_SETTING_NAME, ovs_bridge->name); } else { _LOGT ("added a bridge: %s%s%s", ovs_bridge->name, ovs_bridge->connection_uuid ? ", " : "", @@ -1017,7 +1057,6 @@ ovsdb_got_update (NMOvsdb *self, json_t *msg) g_signal_emit (self, signals[DEVICE_ADDED], 0, ovs_bridge->name, NM_DEVICE_TYPE_OVS_BRIDGE); } - g_hash_table_insert (priv->bridges, g_strdup (key), ovs_bridge); } } @@ -1562,19 +1601,19 @@ nm_ovsdb_class_init (NMOvsdbClass *klass) G_OBJECT_CLASS_TYPE (object_class), G_SIGNAL_RUN_LAST, 0, NULL, NULL, NULL, - G_TYPE_NONE, 2, G_TYPE_POINTER, G_TYPE_UINT); + G_TYPE_NONE, 2, G_TYPE_STRING, G_TYPE_UINT); signals[DEVICE_REMOVED] = g_signal_new (NM_OVSDB_DEVICE_REMOVED, G_OBJECT_CLASS_TYPE (object_class), G_SIGNAL_RUN_LAST, 0, NULL, NULL, NULL, - G_TYPE_NONE, 2, G_TYPE_POINTER, G_TYPE_UINT); + G_TYPE_NONE, 2, G_TYPE_STRING, G_TYPE_UINT); - signals[DEVICE_CHANGED] = - g_signal_new (NM_OVSDB_DEVICE_CHANGED, + signals[INTERFACE_FAILED] = + g_signal_new (NM_OVSDB_INTERFACE_FAILED, G_OBJECT_CLASS_TYPE (object_class), G_SIGNAL_RUN_LAST, 0, NULL, NULL, NULL, - G_TYPE_NONE, 2, G_TYPE_POINTER, G_TYPE_UINT); + G_TYPE_NONE, 3, G_TYPE_STRING, G_TYPE_STRING, G_TYPE_STRING); } diff --git a/src/devices/ovs/nm-ovsdb.h b/src/devices/ovs/nm-ovsdb.h index cf9fe2a2..279155a4 100644 --- a/src/devices/ovs/nm-ovsdb.h +++ b/src/devices/ovs/nm-ovsdb.h @@ -27,9 +27,9 @@ #define NM_IS_OVSDB_CLASS(klass) (G_TYPE_CHECK_CLASS_TYPE ((klass), NM_TYPE_OVSDB)) #define NM_OVSDB_GET_CLASS(obj) (G_TYPE_INSTANCE_GET_CLASS ((obj), NM_TYPE_OVSDB, NMOvsdbClass)) -#define NM_OVSDB_DEVICE_ADDED "device-added" -#define NM_OVSDB_DEVICE_REMOVED "device-removed" -#define NM_OVSDB_DEVICE_CHANGED "device-changed" +#define NM_OVSDB_DEVICE_ADDED "device-added" +#define NM_OVSDB_DEVICE_REMOVED "device-removed" +#define NM_OVSDB_INTERFACE_FAILED "interface-failed" typedef struct _NMOvsdb NMOvsdb; typedef struct _NMOvsdbClass NMOvsdbClass; diff --git a/src/devices/team/nm-device-team.c b/src/devices/team/nm-device-team.c index 287f4d1b..a60a9fda 100644 --- a/src/devices/team/nm-device-team.c +++ b/src/devices/team/nm-device-team.c @@ -1,4 +1,3 @@ -/* -*- Mode: C; tab-width: 4; indent-tabs-mode: t; c-basic-offset: 4 -*- */ /* NetworkManager -- Network link manager * * This program is free software; you can redistribute it and/or modify @@ -101,6 +100,7 @@ complete_connection (NMDevice *device, NULL, _("Team connection"), "team", + NULL, TRUE); s_team = nm_connection_get_setting_team (connection); @@ -694,6 +694,9 @@ deactivate (NMDevice *device) NMDeviceTeam *self = NM_DEVICE_TEAM (device); NMDeviceTeamPrivate *priv = NM_DEVICE_TEAM_GET_PRIVATE (self); + if (nm_device_sys_iface_state_is_external (device)) + return; + if (priv->teamd_pid || priv->tdc) _LOGI (LOGD_TEAM, "deactivation: stopping teamd..."); @@ -771,11 +774,19 @@ release_slave (NMDevice *device, NMDeviceTeam *self = NM_DEVICE_TEAM (device); NMDeviceTeamPrivate *priv = NM_DEVICE_TEAM_GET_PRIVATE (self); gboolean success; + int ifindex_slave; + + ifindex_slave = nm_device_get_ip_ifindex (slave); + + if (ifindex_slave <= 0) { + _LOGD (LOGD_TEAM, "team port %s is already released", nm_device_get_ip_iface (slave)); + return; + } if (configure) { success = nm_platform_link_release (nm_device_get_platform (device), nm_device_get_ip_ifindex (device), - nm_device_get_ip_ifindex (slave)); + ifindex_slave); if (success) _LOGI (LOGD_TEAM, "released team port %s", nm_device_get_ip_iface (slave)); @@ -786,9 +797,10 @@ release_slave (NMDevice *device, * IFF_UP), so we must bring it back up here to ensure carrier changes and * other state is noticed by the now-released port. */ - if (!nm_device_bring_up (slave, TRUE, NULL)) + if (!nm_device_bring_up (slave, TRUE, NULL)) { _LOGW (LOGD_TEAM, "released team port %s could not be brought up", nm_device_get_ip_iface (slave)); + } nm_clear_g_source (&priv->teamd_read_timeout); priv->teamd_read_timeout = g_timeout_add_seconds (5, diff --git a/src/devices/team/nm-device-team.h b/src/devices/team/nm-device-team.h index bbb1417f..0c0b5101 100644 --- a/src/devices/team/nm-device-team.h +++ b/src/devices/team/nm-device-team.h @@ -1,4 +1,3 @@ -/* -*- Mode: C; tab-width: 4; indent-tabs-mode: t; c-basic-offset: 4 -*- */ /* NetworkManager -- Network link manager * * Copyright (C) 2013 Jiri Pirko <jiri@resnulli.us> diff --git a/src/devices/team/nm-team-factory.c b/src/devices/team/nm-team-factory.c index f18b943d..21a85701 100644 --- a/src/devices/team/nm-team-factory.c +++ b/src/devices/team/nm-team-factory.c @@ -1,4 +1,3 @@ -/* -*- Mode: C; tab-width: 4; indent-tabs-mode: t; c-basic-offset: 4 -*- */ /* NetworkManager -- Network link manager * * This program is free software; you can redistribute it and/or modify diff --git a/src/devices/tests/meson.build b/src/devices/tests/meson.build index 4702c656..4b4c5c7e 100644 --- a/src/devices/tests/meson.build +++ b/src/devices/tests/meson.build @@ -9,7 +9,6 @@ foreach test_unit: test_units test_unit + '.c', dependencies: test_nm_dep, ) - test( 'devices/' + test_unit, test_script, diff --git a/src/devices/tests/test-acd.c b/src/devices/tests/test-acd.c index 8b52ee2c..42accfaf 100644 --- a/src/devices/tests/test-acd.c +++ b/src/devices/tests/test-acd.c @@ -1,4 +1,3 @@ -/* -*- Mode: C; tab-width: 4; indent-tabs-mode: t; c-basic-offset: 4 -*- */ /* nm-platform.c - Handle runtime kernel networking configuration * * This program is free software; you can redistribute it and/or modify diff --git a/src/devices/tests/test-lldp.c b/src/devices/tests/test-lldp.c index 7b135f58..ad157b7e 100644 --- a/src/devices/tests/test-lldp.c +++ b/src/devices/tests/test-lldp.c @@ -1,4 +1,3 @@ -/* -*- Mode: C; tab-width: 4; indent-tabs-mode: t; c-basic-offset: 4 -*- */ /* nm-platform.c - Handle runtime kernel networking configuration * * This program is free software; you can redistribute it and/or modify @@ -457,7 +456,7 @@ _test_recv_fixture_setup (TestRecvFixture *fixture, gconstpointer user_data) fixture->ifindex = link->ifindex; fixture->fd = nm_steal_fd (&fd); - memcpy (fixture->mac, link->addr.data, ETH_ALEN); + memcpy (fixture->mac, link->l_address.data, ETH_ALEN); } typedef struct { diff --git a/src/devices/wifi/nm-device-iwd.c b/src/devices/wifi/nm-device-iwd.c index da7d0685..9cfe5f70 100644 --- a/src/devices/wifi/nm-device-iwd.c +++ b/src/devices/wifi/nm-device-iwd.c @@ -1,4 +1,3 @@ -/* -*- Mode: C; tab-width: 4; indent-tabs-mode: t; c-basic-offset: 4 -*- */ /* NetworkManager -- Network link manager * * This program is free software; you can redistribute it and/or modify @@ -780,12 +779,10 @@ complete_connection (NMDevice *device, NMDeviceIwd *self = NM_DEVICE_IWD (device); NMDeviceIwdPrivate *priv = NM_DEVICE_IWD_GET_PRIVATE (self); NMSettingWireless *s_wifi; - const char *setting_mac; gs_free char *ssid_utf8 = NULL; NMWifiAP *ap; GBytes *ssid; GBytes *setting_ssid = NULL; - const char *perm_hw_addr; const char *mode; s_wifi = nm_connection_get_setting_wireless (connection); @@ -875,36 +872,9 @@ complete_connection (NMDevice *device, ssid_utf8, ssid_utf8, NULL, + nm_setting_wireless_get_mac_address (s_wifi) ? NULL : nm_device_get_iface (device), TRUE); - perm_hw_addr = nm_device_get_permanent_hw_address (device); - if (perm_hw_addr) { - setting_mac = nm_setting_wireless_get_mac_address (s_wifi); - if (setting_mac) { - /* Make sure the setting MAC (if any) matches the device's permanent MAC */ - if (!nm_utils_hwaddr_matches (setting_mac, -1, perm_hw_addr, -1)) { - g_set_error_literal (error, - NM_CONNECTION_ERROR, - NM_CONNECTION_ERROR_INVALID_PROPERTY, - "connection does not match device"); - g_prefix_error (error, "%s.%s: ", NM_SETTING_WIRELESS_SETTING_NAME, NM_SETTING_WIRELESS_MAC_ADDRESS); - return FALSE; - } - } else { - guint8 tmp[ETH_ALEN]; - - /* Lock the connection to this device by default if it uses a - * permanent MAC address (ie not a 'locally administered' one) - */ - nm_utils_hwaddr_aton (perm_hw_addr, tmp, ETH_ALEN); - if (!(tmp[0] & 0x02)) { - g_object_set (G_OBJECT (s_wifi), - NM_SETTING_WIRELESS_MAC_ADDRESS, perm_hw_addr, - NULL); - } - } - } - return TRUE; } diff --git a/src/devices/wifi/nm-device-iwd.h b/src/devices/wifi/nm-device-iwd.h index 4a2bd31e..aab45b7b 100644 --- a/src/devices/wifi/nm-device-iwd.h +++ b/src/devices/wifi/nm-device-iwd.h @@ -1,4 +1,3 @@ -/* -*- Mode: C; tab-width: 4; indent-tabs-mode: t; c-basic-offset: 4 -*- */ /* NetworkManager -- Network link manager * * This program is free software; you can redistribute it and/or modify diff --git a/src/devices/wifi/nm-device-olpc-mesh.c b/src/devices/wifi/nm-device-olpc-mesh.c index 1172a613..3c865c55 100644 --- a/src/devices/wifi/nm-device-olpc-mesh.c +++ b/src/devices/wifi/nm-device-olpc-mesh.c @@ -1,4 +1,3 @@ -/* -*- Mode: C; tab-width: 4; indent-tabs-mode: t; c-basic-offset: 4 -*- */ /* NetworkManager -- Network link manager * * Dan Williams <dcbw@redhat.com> @@ -133,6 +132,7 @@ complete_connection (NMDevice *device, NULL, _("Mesh"), NULL, + NULL, FALSE); /* No IPv6 by default */ return TRUE; diff --git a/src/devices/wifi/nm-device-olpc-mesh.h b/src/devices/wifi/nm-device-olpc-mesh.h index bf0e4da9..619fc46a 100644 --- a/src/devices/wifi/nm-device-olpc-mesh.h +++ b/src/devices/wifi/nm-device-olpc-mesh.h @@ -1,5 +1,3 @@ -/* -*- Mode: C; tab-width: 4; indent-tabs-mode: t; c-basic-offset: 4 -*- */ - /* NetworkManager -- Network link manager * * Dan Williams <dcbw@redhat.com> diff --git a/src/devices/wifi/nm-device-wifi-p2p.c b/src/devices/wifi/nm-device-wifi-p2p.c index 8381ebc7..c5826e24 100644 --- a/src/devices/wifi/nm-device-wifi-p2p.c +++ b/src/devices/wifi/nm-device-wifi-p2p.c @@ -331,6 +331,7 @@ complete_connection (NMDevice *device, setting_name, setting_name, NULL, + NULL, TRUE); return TRUE; diff --git a/src/devices/wifi/nm-device-wifi.c b/src/devices/wifi/nm-device-wifi.c index 3a58c620..2ffba47a 100644 --- a/src/devices/wifi/nm-device-wifi.c +++ b/src/devices/wifi/nm-device-wifi.c @@ -1,4 +1,3 @@ -/* -*- Mode: C; tab-width: 4; indent-tabs-mode: t; c-basic-offset: 4 -*- */ /* NetworkManager -- Network link manager * * This program is free software; you can redistribute it and/or modify @@ -545,6 +544,60 @@ wake_on_wlan_restore (NMDeviceWifi *self) } static void +disconnect_cb (NMSupplicantInterface *iface, GError *error, gpointer user_data) +{ + gs_unref_object NMDeviceWifi *self = NULL; + NMDeviceDeactivateCallback callback; + gpointer callback_user_data; + + nm_utils_user_data_unpack (user_data, &self, &callback, &callback_user_data); + + /* error will be freed by sup_iface */ + callback (NM_DEVICE (self), error, callback_user_data); +} + +static void +disconnect_cb_on_idle (gpointer user_data, + GCancellable *cancellable) +{ + gs_unref_object NMDeviceWifi *self = NULL; + NMDeviceDeactivateCallback callback; + gpointer callback_user_data; + gs_free_error GError *cancelled_error = NULL; + + nm_utils_user_data_unpack (user_data, &self, &callback, &callback_user_data); + + g_cancellable_set_error_if_cancelled (cancellable, &cancelled_error); + callback (NM_DEVICE (self), cancelled_error, callback_user_data); +} + +static void +deactivate_async (NMDevice *device, + GCancellable *cancellable, + NMDeviceDeactivateCallback callback, + gpointer callback_user_data) { + NMDeviceWifi *self = NM_DEVICE_WIFI (device); + NMDeviceWifiPrivate *priv = NM_DEVICE_WIFI_GET_PRIVATE (self); + gpointer user_data; + + nm_assert (G_IS_CANCELLABLE (cancellable)); + nm_assert (callback); + + user_data = nm_utils_user_data_pack (g_object_ref (self), callback, callback_user_data); + if (!priv->sup_iface) { + nm_utils_invoke_on_idle (disconnect_cb_on_idle, user_data, cancellable); + return; + } + + cleanup_association_attempt (self, FALSE); + + nm_supplicant_interface_disconnect_async (priv->sup_iface, + cancellable, + disconnect_cb, + user_data); +} + +static void deactivate (NMDevice *device) { NMDeviceWifi *self = NM_DEVICE_WIFI (device); @@ -695,6 +748,20 @@ check_connection_compatible (NMDevice *device, NMConnection *connection, GError return FALSE; } } + } else if (g_strcmp0 (mode, NM_SETTING_WIRELESS_MODE_MESH) == 0) { + if (!(priv->capabilities & NM_WIFI_DEVICE_CAP_MESH)) { + nm_utils_error_set_literal (error, NM_UTILS_ERROR_CONNECTION_AVAILABLE_TEMPORARY, + "the device does not support Mesh mode"); + return FALSE; + } + + if (priv->sup_iface) { + if (nm_supplicant_interface_get_mesh_support (priv->sup_iface) == NM_SUPPLICANT_FEATURE_NO) { + nm_utils_error_set_literal (error, NM_UTILS_ERROR_CONNECTION_AVAILABLE_TEMPORARY, + "wpa_supplicant does not support Mesh mode"); + return FALSE; + } + } } // FIXME: check channel/freq/band against bands the hardware supports @@ -739,12 +806,13 @@ check_connection_available (NMDevice *device, return TRUE; } - /* Ad-Hoc and AP connections are always available because they may be + /* Ad-Hoc, AP and Mesh connections are always available because they may be * started at any time. */ mode = nm_setting_wireless_get_mode (s_wifi); if ( g_strcmp0 (mode, NM_SETTING_WIRELESS_MODE_ADHOC) == 0 - || g_strcmp0 (mode, NM_SETTING_WIRELESS_MODE_AP) == 0) + || g_strcmp0 (mode, NM_SETTING_WIRELESS_MODE_AP) == 0 + || g_strcmp0 (mode, NM_SETTING_WIRELESS_MODE_MESH) == 0) return TRUE; /* Hidden SSIDs obviously don't always appear in the scan list either. @@ -778,13 +846,11 @@ complete_connection (NMDevice *device, NMDeviceWifi *self = NM_DEVICE_WIFI (device); NMDeviceWifiPrivate *priv = NM_DEVICE_WIFI_GET_PRIVATE (self); NMSettingWireless *s_wifi; - const char *setting_mac; gs_free char *ssid_utf8 = NULL; NMWifiAP *ap; GBytes *ssid = NULL; GBytes *setting_ssid = NULL; gboolean hidden = FALSE; - const char *perm_hw_addr; const char *mode; s_wifi = nm_connection_get_setting_wireless (connection); @@ -908,27 +974,12 @@ complete_connection (NMDevice *device, ssid_utf8, ssid_utf8, NULL, + nm_setting_wireless_get_mac_address (s_wifi) ? NULL : nm_device_get_iface (device), TRUE); if (hidden) g_object_set (s_wifi, NM_SETTING_WIRELESS_HIDDEN, TRUE, NULL); - perm_hw_addr = nm_device_get_permanent_hw_address (device); - if (perm_hw_addr) { - setting_mac = nm_setting_wireless_get_mac_address (s_wifi); - if (setting_mac) { - /* Make sure the setting MAC (if any) matches the device's permanent MAC */ - if (!nm_utils_hwaddr_matches (setting_mac, -1, perm_hw_addr, -1)) { - g_set_error_literal (error, - NM_CONNECTION_ERROR, - NM_CONNECTION_ERROR_INVALID_PROPERTY, - _("connection does not match device")); - g_prefix_error (error, "%s.%s: ", NM_SETTING_WIRELESS_SETTING_NAME, NM_SETTING_WIRELESS_MAC_ADDRESS); - return FALSE; - } - } - } - return TRUE; } @@ -972,7 +1023,8 @@ can_auto_connect (NMDevice *device, NMConnection *connection; NMSettingWireless *s_wifi; NMWifiAP *ap; - const char *method, *mode; + const char *method6, *mode; + gboolean auto4, auto6; guint64 timestamp = 0; nm_assert (!specific_object || !*specific_object); @@ -985,13 +1037,20 @@ can_auto_connect (NMDevice *device, s_wifi = nm_connection_get_setting_wireless (connection); g_return_val_if_fail (s_wifi, FALSE); - /* Always allow autoconnect for AP and non-autoconf Ad-Hoc */ - method = nm_utils_get_ip_config_method (connection, AF_INET); + /* Always allow autoconnect for AP and non-autoconf Ad-Hoc or Mesh */ + auto4 = nm_streq0 (nm_utils_get_ip_config_method (connection, AF_INET), + NM_SETTING_IP4_CONFIG_METHOD_AUTO); + method6 = nm_utils_get_ip_config_method (connection, AF_INET6); + auto6 = nm_streq0 (method6, NM_SETTING_IP6_CONFIG_METHOD_AUTO) + || nm_streq0 (method6, NM_SETTING_IP6_CONFIG_METHOD_DHCP); + mode = nm_setting_wireless_get_mode (s_wifi); + if (nm_streq0 (mode, NM_SETTING_WIRELESS_MODE_AP)) return TRUE; - else if ( nm_streq0 (mode, NM_SETTING_WIRELESS_MODE_ADHOC) - && !nm_streq0 (method, NM_SETTING_IP4_CONFIG_METHOD_AUTO)) + else if (!auto4 && nm_streq0 (mode, NM_SETTING_WIRELESS_MODE_ADHOC)) + return TRUE; + else if (!auto4 && !auto6 && nm_streq0 (mode, NM_SETTING_WIRELESS_MODE_MESH)) return TRUE; /* Don't autoconnect to networks that have been tried at least once @@ -1531,13 +1590,14 @@ try_fill_ssid_for_hidden_ap (NMDeviceWifi *self, NMSettingsConnection *sett_conn = connections[i]; NMSettingWireless *s_wifi; + if (!nm_settings_connection_has_seen_bssid (sett_conn, bssid)) + continue; s_wifi = nm_connection_get_setting_wireless (nm_settings_connection_get_connection (sett_conn)); - if (s_wifi) { - if (nm_settings_connection_has_seen_bssid (sett_conn, bssid)) { - nm_wifi_ap_set_ssid (ap, nm_setting_wireless_get_ssid (s_wifi)); - break; - } - } + if (!s_wifi) + continue; + + nm_wifi_ap_set_ssid (ap, nm_setting_wireless_get_ssid (s_wifi)); + break; } } @@ -1777,9 +1837,10 @@ supplicant_iface_wps_credentials_cb (NMSupplicantInterface *iface, } if (secrets) { if (nm_settings_connection_new_secrets (nm_act_request_get_settings_connection (req), - nm_act_request_get_applied_connection (req), - NM_SETTING_WIRELESS_SECURITY_SETTING_NAME, - secrets, &error)) { + nm_act_request_get_applied_connection (req), + NM_SETTING_WIRELESS_SECURITY_SETTING_NAME, + secrets, + &error)) { wifi_secrets_cancel (self); nm_device_activate_schedule_stage1_device_prepare (NM_DEVICE (self)); } else { @@ -2398,6 +2459,7 @@ supplicant_connection_timeout_cb (gpointer user_data) g_assert (connection); if ( priv->mode == NM_802_11_MODE_ADHOC + || priv->mode == NM_802_11_MODE_MESH || priv->mode == NM_802_11_MODE_AP) { /* In Ad-Hoc and AP modes there's nothing to check the encryption key * (if any), so supplicant timeouts here are almost certainly the wifi @@ -2468,7 +2530,9 @@ build_supplicant_config (NMDeviceWifi *self, config = nm_supplicant_config_new ( nm_supplicant_interface_get_pmf_support (priv->sup_iface) == NM_SUPPLICANT_FEATURE_YES, - nm_supplicant_interface_get_fils_support (priv->sup_iface) == NM_SUPPLICANT_FEATURE_YES); + nm_supplicant_interface_get_fils_support (priv->sup_iface) == NM_SUPPLICANT_FEATURE_YES, + nm_supplicant_interface_get_ft_support (priv->sup_iface) == NM_SUPPLICANT_FEATURE_YES, + nm_supplicant_interface_get_sha384_support (priv->sup_iface) == NM_SUPPLICANT_FEATURE_YES); /* Warn if AP mode may not be supported */ if ( g_strcmp0 (nm_setting_wireless_get_mode (s_wireless), NM_SETTING_WIRELESS_MODE_AP) == 0 @@ -2635,7 +2699,8 @@ act_stage1_prepare (NMDevice *device, NMDeviceStateReason *out_failure_reason) /* Scanning not done in AP mode; clear the scan list */ remove_all_aps (self); - } + } else if (g_strcmp0 (mode, NM_SETTING_WIRELESS_MODE_MESH) == 0) + priv->mode = NM_802_11_MODE_MESH; _notify (self, PROP_MODE); /* The kernel doesn't support Ad-Hoc WPA connections well at this time, @@ -2655,8 +2720,8 @@ act_stage1_prepare (NMDevice *device, NMDeviceStateReason *out_failure_reason) if (!nm_device_hw_addr_set_cloned (device, connection, TRUE)) return NM_ACT_STAGE_RETURN_FAILURE; - /* AP mode never uses a specific object or existing scanned AP */ - if (priv->mode != NM_802_11_MODE_AP) { + /* AP and Mesh modes never use a specific object or existing scanned AP */ + if (priv->mode != NM_802_11_MODE_AP && priv->mode != NM_802_11_MODE_MESH) { ap_path = nm_active_connection_get_specific_object (NM_ACTIVE_CONNECTION (req)); ap = ap_path ? nm_wifi_ap_lookup_for_device (NM_DEVICE (self), ap_path) : NULL; if (ap) @@ -2672,10 +2737,10 @@ act_stage1_prepare (NMDevice *device, NMDeviceStateReason *out_failure_reason) } /* If the user is trying to connect to an AP that NM doesn't yet know about - * (hidden network or something) or starting a Hotspot, create an fake AP - * from the security settings in the connection. This "fake" AP gets used - * until the real one is found in the scan list (Ad-Hoc or Hidden), or until - * the device is deactivated (Hotspot). + * (hidden network or something), starting a Hotspot or joining a Mesh, + * create a fake APfrom the security settings in the connection. This "fake" + * AP gets used until the real one is found in the scan list (Ad-Hoc or Hidden), + * or until the device is deactivated (Hotspot). */ ap = nm_wifi_ap_new_fake_from_connection (connection); g_return_val_if_fail (ap != NULL, NM_ACT_STAGE_RETURN_FAILURE); @@ -2763,6 +2828,7 @@ act_stage2_config (NMDevice *device, NMDeviceStateReason *out_failure_reason) NMDeviceWifiPrivate *priv = NM_DEVICE_WIFI_GET_PRIVATE (self); NMActStageReturn ret = NM_ACT_STAGE_RETURN_FAILURE; NMSupplicantConfig *config = NULL; + NM80211Mode ap_mode; NMActRequest *req; NMWifiAP *ap; NMConnection *connection; @@ -2783,6 +2849,7 @@ act_stage2_config (NMDevice *device, NMDeviceStateReason *out_failure_reason) NM_SET_OUT (out_failure_reason, NM_DEVICE_STATE_REASON_SUPPLICANT_FAILED); goto out; } + ap_mode = nm_wifi_ap_get_mode (ap); connection = nm_act_request_get_applied_connection (req); g_assert (connection); @@ -2822,14 +2889,16 @@ act_stage2_config (NMDevice *device, NMDeviceStateReason *out_failure_reason) priv->ssid_found = FALSE; - /* Supplicant requires an initial frequency for Ad-Hoc and Hotspot; if the user - * didn't specify one and we didn't find an AP that matched the connection, - * just pick a frequency the device supports. + /* Supplicant requires an initial frequency for Ad-Hoc, Hotspot and Mesh; + * if the user didn't specify one and we didn't find an AP that matched + * the connection, just pick a frequency the device supports. */ - if ((nm_wifi_ap_get_mode (ap) == NM_802_11_MODE_ADHOC) || nm_wifi_ap_is_hotspot (ap)) + if ( ap_mode == NM_802_11_MODE_ADHOC + || ap_mode == NM_802_11_MODE_MESH + || nm_wifi_ap_is_hotspot (ap)) ensure_hotspot_frequency (self, s_wireless, ap); - if (nm_wifi_ap_get_mode (ap) == NM_802_11_MODE_INFRA) + if (ap_mode == NM_802_11_MODE_INFRA) set_powersave (device); /* Build up the supplicant configuration */ @@ -3386,6 +3455,7 @@ nm_device_wifi_class_init (NMDeviceWifiClass *klass) device_class->get_configured_mtu = get_configured_mtu; 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_async = deactivate_async; device_class->deactivate = deactivate; device_class->deactivate_reset_hw_addr = deactivate_reset_hw_addr; device_class->unmanaged_on_quit = unmanaged_on_quit; diff --git a/src/devices/wifi/nm-device-wifi.h b/src/devices/wifi/nm-device-wifi.h index 116ad11e..82f62be6 100644 --- a/src/devices/wifi/nm-device-wifi.h +++ b/src/devices/wifi/nm-device-wifi.h @@ -1,4 +1,3 @@ -/* -*- Mode: C; tab-width: 4; indent-tabs-mode: t; c-basic-offset: 4 -*- */ /* NetworkManager -- Network link manager * * This program is free software; you can redistribute it and/or modify diff --git a/src/devices/wifi/nm-iwd-manager.c b/src/devices/wifi/nm-iwd-manager.c index 494fca32..5b550ea4 100644 --- a/src/devices/wifi/nm-iwd-manager.c +++ b/src/devices/wifi/nm-iwd-manager.c @@ -1,4 +1,3 @@ -/* -*- Mode: C; tab-width: 4; indent-tabs-mode: t; c-basic-offset: 4 -*- */ /* NetworkManager -- Network link manager * * This program is free software; you can redistribute it and/or modify @@ -437,7 +436,6 @@ mirror_8021x_connection (NMIwdManager *self, NM_SETTING_CONNECTION_TYPE, NM_SETTING_WIRELESS_SETTING_NAME, NM_SETTING_CONNECTION_ID, name, NM_SETTING_CONNECTION_UUID, nm_utils_uuid_generate_buf (uuid), - NM_SETTING_CONNECTION_READ_ONLY, TRUE, NULL)); nm_connection_add_setting (connection, setting); @@ -470,19 +468,19 @@ mirror_8021x_connection (NMIwdManager *self, if (!nm_connection_normalize (connection, NULL, NULL, NULL)) return NULL; - settings_connection = nm_settings_add_connection (priv->settings, connection, - FALSE, &error); - if (!settings_connection) { + if (!nm_settings_add_connection (priv->settings, + connection, + NM_SETTINGS_CONNECTION_PERSIST_MODE_IN_MEMORY_ONLY, + NM_SETTINGS_CONNECTION_ADD_REASON_NONE, + NM_SETTINGS_CONNECTION_INT_FLAGS_NM_GENERATED, + &settings_connection, + &error)) { _LOGW ("failed to add a mirror NMConnection for IWD's Known Network '%s': %s", name, error->message); g_error_free (error); return NULL; } - nm_settings_connection_set_flags (settings_connection, - NM_SETTINGS_CONNECTION_INT_FLAGS_NM_GENERATED | - NM_SETTINGS_CONNECTION_INT_FLAGS_UNSAVED, - TRUE); return settings_connection; } @@ -499,7 +497,7 @@ mirror_8021x_connection_take_and_delete (NMSettingsConnection *sett_conn) /* If connection has not been saved since we created it * in interface_added it too can be removed now. */ if (NM_FLAGS_HAS (flags, NM_SETTINGS_CONNECTION_INT_FLAGS_NM_GENERATED)) - nm_settings_connection_delete (sett_conn, NULL); + nm_settings_connection_delete (sett_conn, FALSE); g_object_unref (sett_conn); } @@ -900,7 +898,7 @@ nm_iwd_manager_init (NMIwdManager *self) g_signal_connect (priv->manager, NM_MANAGER_DEVICE_ADDED, G_CALLBACK (device_added), self); - priv->settings = g_object_ref (nm_settings_get ()); + priv->settings = g_object_ref (NM_SETTINGS_GET); g_signal_connect (priv->settings, NM_SETTINGS_SIGNAL_CONNECTION_REMOVED, G_CALLBACK (connection_removed), self); diff --git a/src/devices/wifi/nm-iwd-manager.h b/src/devices/wifi/nm-iwd-manager.h index 57b7007a..b410e4ce 100644 --- a/src/devices/wifi/nm-iwd-manager.h +++ b/src/devices/wifi/nm-iwd-manager.h @@ -1,4 +1,3 @@ -/* -*- Mode: C; tab-width: 4; indent-tabs-mode: t; c-basic-offset: 4 -*- */ /* NetworkManager -- Network link manager * * This program is free software; you can redistribute it and/or modify diff --git a/src/devices/wifi/nm-wifi-ap.c b/src/devices/wifi/nm-wifi-ap.c index 87daff59..c7ab7f04 100644 --- a/src/devices/wifi/nm-wifi-ap.c +++ b/src/devices/wifi/nm-wifi-ap.c @@ -1,4 +1,3 @@ -/* -*- Mode: C; tab-width: 4; indent-tabs-mode: t; c-basic-offset: 4 -*- */ /* NetworkManager -- Network link manager * * This program is free software; you can redistribute it and/or modify @@ -260,7 +259,8 @@ nm_wifi_ap_set_mode (NMWifiAP *ap, const NM80211Mode mode) g_return_val_if_fail (NM_IS_WIFI_AP (ap), FALSE); g_return_val_if_fail ( mode == NM_802_11_MODE_ADHOC - || mode == NM_802_11_MODE_INFRA, FALSE); + || mode == NM_802_11_MODE_INFRA + || mode == NM_802_11_MODE_MESH, FALSE); priv = NM_WIFI_AP_GET_PRIVATE (ap); @@ -418,9 +418,11 @@ security_from_vardict (GVariant *security) if ( g_variant_lookup (security, "KeyMgmt", "^a&s", &array) && array) { - if (g_strv_contains (array, "wpa-psk")) + if (g_strv_contains (array, "wpa-psk") || + g_strv_contains (array, "wpa-ft-psk")) flags |= NM_802_11_AP_SEC_KEY_MGMT_PSK; if (g_strv_contains (array, "wpa-eap") || + g_strv_contains (array, "wpa-ft-eap") || g_strv_contains (array, "wpa-fils-sha256") || g_strv_contains (array, "wpa-fils-sha384")) flags |= NM_802_11_AP_SEC_KEY_MGMT_802_1X; @@ -815,6 +817,8 @@ nm_wifi_ap_update_from_properties (NMWifiAP *ap, changed |= nm_wifi_ap_set_mode (ap, NM_802_11_MODE_INFRA); else if (!g_strcmp0 (s, "ad-hoc")) changed |= nm_wifi_ap_set_mode (ap, NM_802_11_MODE_ADHOC); + else if (!g_strcmp0 (s, "mesh")) + changed |= nm_wifi_ap_set_mode (ap, NM_802_11_MODE_MESH); } if (g_variant_lookup (properties, "Signal", "n", &i16)) @@ -1007,7 +1011,9 @@ nm_wifi_ap_to_string (const NMWifiAP *self, ? '#' : (priv->fake ? 'f' - : 'a'))), + : (priv->mode == NM_802_11_MODE_MESH + ? 'm' + : 'a')))), chan, priv->strength, priv->flags & NM_802_11_AP_FLAGS_PRIVACY ? 'P' : '_', @@ -1072,6 +1078,8 @@ nm_wifi_ap_check_compatible (NMWifiAP *self, if ( !strcmp (mode, "ap") && (priv->mode != NM_802_11_MODE_INFRA || priv->hotspot != TRUE)) return FALSE; + if (!strcmp (mode, "mesh") && (priv->mode != NM_802_11_MODE_MESH)) + return FALSE; } band = nm_setting_wireless_get_band (s_wireless); @@ -1115,6 +1123,7 @@ nm_wifi_ap_complete_connection (NMWifiAP *self, return nm_wifi_utils_complete_connection (priv->ssid, priv->address, priv->mode, + priv->freq, priv->flags, priv->wpa_flags, priv->rsn_flags, @@ -1245,6 +1254,8 @@ nm_wifi_ap_new_fake_from_connection (NMConnection *connection) nm_wifi_ap_set_mode (ap, NM_802_11_MODE_INFRA); else if (!strcmp (mode, "adhoc")) nm_wifi_ap_set_mode (ap, NM_802_11_MODE_ADHOC); + else if (!strcmp (mode, "mesh")) + nm_wifi_ap_set_mode (ap, NM_802_11_MODE_MESH); else if (!strcmp (mode, "ap")) { nm_wifi_ap_set_mode (ap, NM_802_11_MODE_INFRA); NM_WIFI_AP_GET_PRIVATE (ap)->hotspot = TRUE; diff --git a/src/devices/wifi/nm-wifi-ap.h b/src/devices/wifi/nm-wifi-ap.h index 7462e9d1..755e722c 100644 --- a/src/devices/wifi/nm-wifi-ap.h +++ b/src/devices/wifi/nm-wifi-ap.h @@ -1,4 +1,3 @@ -/* -*- Mode: C; tab-width: 4; indent-tabs-mode: t; c-basic-offset: 4 -*- */ /* NetworkManager -- Network link manager * * This program is free software; you can redistribute it and/or modify diff --git a/src/devices/wifi/nm-wifi-common.c b/src/devices/wifi/nm-wifi-common.c index c95620e7..96828d59 100644 --- a/src/devices/wifi/nm-wifi-common.c +++ b/src/devices/wifi/nm-wifi-common.c @@ -1,4 +1,3 @@ -/*-*- Mode: C; tab-width: 4; indent-tabs-mode: t; c-basic-offset: 4 -*- */ /* * This library is free software; you can redistribute it and/or * modify it under the terms of the GNU Lesser General Public diff --git a/src/devices/wifi/nm-wifi-common.h b/src/devices/wifi/nm-wifi-common.h index 91cbeb55..81d657ec 100644 --- a/src/devices/wifi/nm-wifi-common.h +++ b/src/devices/wifi/nm-wifi-common.h @@ -1,4 +1,3 @@ -/* -*- Mode: C; tab-width: 4; indent-tabs-mode: t; c-basic-offset: 4 -*- */ /* * This library is free software; you can redistribute it and/or * modify it under the terms of the GNU Lesser General Public diff --git a/src/devices/wifi/nm-wifi-factory.c b/src/devices/wifi/nm-wifi-factory.c index 9a89bbe9..2f069882 100644 --- a/src/devices/wifi/nm-wifi-factory.c +++ b/src/devices/wifi/nm-wifi-factory.c @@ -1,4 +1,3 @@ -/* -*- Mode: C; tab-width: 4; indent-tabs-mode: t; c-basic-offset: 4 -*- */ /* NetworkManager -- Network link manager * * This program is free software; you can redistribute it and/or modify diff --git a/src/devices/wifi/nm-wifi-utils.c b/src/devices/wifi/nm-wifi-utils.c index c6e8b3e0..426eeea8 100644 --- a/src/devices/wifi/nm-wifi-utils.c +++ b/src/devices/wifi/nm-wifi-utils.c @@ -1,4 +1,3 @@ -/*-*- Mode: C; tab-width: 4; indent-tabs-mode: t; c-basic-offset: 4 -*- */ /* * This library is free software; you can redistribute it and/or * modify it under the terms of the GNU Lesser General Public @@ -25,6 +24,7 @@ #include <stdlib.h> #include "nm-utils.h" +#include "nm-core-internal.h" static gboolean verify_no_wep (NMSettingWirelessSecurity *s_wsec, const char *tag, GError **error) @@ -527,6 +527,7 @@ gboolean nm_wifi_utils_complete_connection (GBytes *ap_ssid, const char *bssid, NM80211Mode ap_mode, + guint32 ap_freq, guint32 ap_flags, guint32 ap_wpa_flags, guint32 ap_rsn_flags, @@ -540,6 +541,7 @@ nm_wifi_utils_complete_connection (GBytes *ap_ssid, GBytes *ssid; const char *mode, *key_mgmt, *auth_alg, *leap_username; gboolean adhoc = FALSE; + gboolean mesh = FALSE; s_wifi = nm_connection_get_setting_wireless (connection); g_assert (s_wifi); @@ -576,6 +578,10 @@ nm_wifi_utils_complete_connection (GBytes *ap_ssid, if (ap_mode == NM_802_11_MODE_ADHOC) valid = TRUE; adhoc = TRUE; + } else if (!strcmp (mode, NM_SETTING_WIRELESS_MODE_MESH)) { + if (ap_mode == NM_802_11_MODE_MESH) + valid = TRUE; + mesh = TRUE; } if (valid == FALSE) { @@ -591,10 +597,57 @@ nm_wifi_utils_complete_connection (GBytes *ap_ssid, if (ap_mode == NM_802_11_MODE_ADHOC) { mode = NM_SETTING_WIRELESS_MODE_ADHOC; adhoc = TRUE; + } else if (ap_mode == NM_802_11_MODE_MESH) { + mode = NM_SETTING_WIRELESS_MODE_MESH; + mesh = TRUE; } g_object_set (G_OBJECT (s_wifi), NM_SETTING_WIRELESS_MODE, mode, NULL); } + /* For now mesh requires channel and band, fill them only if both not present. + * Do not check existing values against an existing ap/mesh point, + * mesh join will start a new network if required */ + if (mesh) { + const char *band; + guint32 channel; + gboolean band_valid = TRUE; + gboolean chan_valid = TRUE; + gboolean valid; + + band = nm_setting_wireless_get_band (s_wifi); + channel = nm_setting_wireless_get_channel (s_wifi); + + valid = ((band == NULL) && (channel == 0)) + || ((band != NULL) && (channel != 0)); + + if ((band == NULL) && (channel == 0)) { + channel = nm_utils_wifi_freq_to_channel (ap_freq); + if (channel) { + g_object_set (s_wifi, + NM_SETTING_WIRELESS_CHANNEL, channel, + NULL); + } else { + chan_valid = FALSE; + } + + band = nm_utils_wifi_freq_to_band (ap_freq); + if (band) { + g_object_set (s_wifi, NM_SETTING_WIRELESS_BAND, band, NULL); + } else { + band_valid = FALSE; + } + } + + if (!valid || !chan_valid || !band_valid) { + g_set_error (error, + NM_CONNECTION_ERROR, + NM_CONNECTION_ERROR_INVALID_PROPERTY, + _("connection does not match mesh point")); + g_prefix_error (error, "%s.%s: ", NM_SETTING_WIRELESS_SETTING_NAME, NM_SETTING_WIRELESS_MODE); + return FALSE; + } + } + /* Security */ /* Open */ diff --git a/src/devices/wifi/nm-wifi-utils.h b/src/devices/wifi/nm-wifi-utils.h index 03238c24..251d122f 100644 --- a/src/devices/wifi/nm-wifi-utils.h +++ b/src/devices/wifi/nm-wifi-utils.h @@ -1,4 +1,3 @@ -/* -*- Mode: C; tab-width: 4; indent-tabs-mode: t; c-basic-offset: 4 -*- */ /* * This library is free software; you can redistribute it and/or * modify it under the terms of the GNU Lesser General Public @@ -37,6 +36,7 @@ typedef enum { gboolean nm_wifi_utils_complete_connection (GBytes *ssid, const char *bssid, NM80211Mode mode, + guint32 ap_freq, guint32 flags, guint32 wpa_flags, guint32 rsn_flags, diff --git a/src/devices/wifi/tests/meson.build b/src/devices/wifi/tests/meson.build index 895853c4..ba756d53 100644 --- a/src/devices/wifi/tests/meson.build +++ b/src/devices/wifi/tests/meson.build @@ -1,13 +1,13 @@ -test_unit = 'test-general' +test_unit = 'test-devices-wifi' exe = executable( - 'wifi-' + test_unit, + test_unit, [test_unit + '.c'] + common_sources, dependencies: test_nm_dep, ) test( - 'devices/wifi/' + test_unit, + 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-devices-wifi.c index e0899837..a0b3e17f 100644 --- a/src/devices/wifi/tests/test-general.c +++ b/src/devices/wifi/tests/test-devices-wifi.c @@ -1,4 +1,3 @@ -/* -*- Mode: C; tab-width: 4; indent-tabs-mode: t; c-basic-offset: 4 -*- */ /* * This program is free software; you can redistribute it and/or modify * it under the terms of the GNU General Public License as published by @@ -86,6 +85,7 @@ complete_connection (const char *ssid, return nm_wifi_utils_complete_connection (ssid_b, bssid, mode, + 0, flags, wpa_flags, rsn_flags, diff --git a/src/devices/wwan/libnm-wwan.ver b/src/devices/wwan/libnm-wwan.ver index ea966afe..7ccebcb5 100644 --- a/src/devices/wwan/libnm-wwan.ver +++ b/src/devices/wwan/libnm-wwan.ver @@ -7,13 +7,16 @@ global: nm_modem_deactivate; nm_modem_deactivate_async; nm_modem_device_state_changed; + nm_modem_get_apn; nm_modem_get_capabilities; nm_modem_get_configured_mtu; nm_modem_get_control_port; + nm_modem_get_device_id; nm_modem_get_driver; nm_modem_get_iid; nm_modem_get_path; nm_modem_get_ip_ifindex; + nm_modem_get_operator_code; nm_modem_get_secrets; nm_modem_get_state; nm_modem_get_type; diff --git a/src/devices/wwan/nm-device-modem.c b/src/devices/wwan/nm-device-modem.c index 1e316280..042a6ca4 100644 --- a/src/devices/wwan/nm-device-modem.c +++ b/src/devices/wwan/nm-device-modem.c @@ -1,4 +1,3 @@ -/* -*- Mode: C; tab-width: 4; indent-tabs-mode: t; c-basic-offset: 4 -*- */ /* NetworkManager -- Network link manager * * This program is free software; you can redistribute it and/or modify @@ -15,7 +14,7 @@ * with this program; if not, write to the Free Software Foundation, Inc., * 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA. * - * Copyright (C) 2009 - 2011 Red Hat, Inc. + * Copyright (C) 2009 - 2019 Red Hat, Inc. */ #include "nm-default.h" @@ -36,10 +35,13 @@ _LOG_DECLARE_SELF(NMDeviceModem); /*****************************************************************************/ -NM_GOBJECT_PROPERTIES_DEFINE_BASE ( +NM_GOBJECT_PROPERTIES_DEFINE (NMDeviceModem, PROP_MODEM, PROP_CAPABILITIES, PROP_CURRENT_CAPABILITIES, + PROP_DEVICE_ID, + PROP_OPERATOR_CODE, + PROP_APN, ); typedef struct { @@ -47,6 +49,9 @@ typedef struct { NMDeviceModemCapabilities caps; NMDeviceModemCapabilities current_caps; gboolean rf_enabled; + char *device_id; + char *operator_code; + char *apn; } NMDeviceModemPrivate; struct _NMDeviceModem { @@ -308,6 +313,34 @@ ip_ifindex_changed_cb (NMModem *modem, GParamSpec *pspec, gpointer user_data) } static void +operator_code_changed_cb (NMModem *modem, GParamSpec *pspec, gpointer user_data) +{ + NMDeviceModem *self = NM_DEVICE_MODEM (user_data); + NMDeviceModemPrivate *priv = NM_DEVICE_MODEM_GET_PRIVATE (self); + const char *operator_code = nm_modem_get_operator_code (modem); + + if (g_strcmp0 (priv->operator_code, operator_code) != 0) { + g_free (priv->operator_code); + priv->operator_code = g_strdup (operator_code); + _notify (self, PROP_OPERATOR_CODE); + } +} + +static void +apn_changed_cb (NMModem *modem, GParamSpec *pspec, gpointer user_data) +{ + NMDeviceModem *self = NM_DEVICE_MODEM (user_data); + NMDeviceModemPrivate *priv = NM_DEVICE_MODEM_GET_PRIVATE (self); + const char *apn = nm_modem_get_apn (modem); + + if (g_strcmp0 (priv->apn, apn) != 0) { + g_free (priv->apn); + priv->apn = g_strdup (apn); + _notify (self, PROP_APN); + } +} + +static void ids_changed_cb (NMModem *modem, GParamSpec *pspec, gpointer user_data) { nm_device_recheck_available_connections (NM_DEVICE (user_data)); @@ -499,7 +532,11 @@ complete_connection (NMDevice *device, { NMDeviceModemPrivate *priv = NM_DEVICE_MODEM_GET_PRIVATE ((NMDeviceModem *) device); - return nm_modem_complete_connection (priv->modem, connection, existing_connections, error); + return nm_modem_complete_connection (priv->modem, + nm_device_get_iface (device), + connection, + existing_connections, + error); } static void @@ -688,6 +725,8 @@ set_modem (NMDeviceModem *self, NMModem *modem) g_signal_connect (modem, "notify::" NM_MODEM_DEVICE_ID, G_CALLBACK (ids_changed_cb), self); g_signal_connect (modem, "notify::" NM_MODEM_SIM_ID, G_CALLBACK (ids_changed_cb), self); g_signal_connect (modem, "notify::" NM_MODEM_SIM_OPERATOR_ID, G_CALLBACK (ids_changed_cb), self); + g_signal_connect (modem, "notify::" NM_MODEM_OPERATOR_CODE, G_CALLBACK (operator_code_changed_cb), self); + g_signal_connect (modem, "notify::" NM_MODEM_APN, G_CALLBACK (apn_changed_cb), self); } static guint32 @@ -718,6 +757,15 @@ get_property (GObject *object, guint prop_id, case PROP_CURRENT_CAPABILITIES: g_value_set_uint (value, priv->current_caps); break; + case PROP_DEVICE_ID: + g_value_set_string (value, priv->device_id); + break; + case PROP_OPERATOR_CODE: + g_value_set_string (value, priv->operator_code); + break; + case PROP_APN: + g_value_set_string (value, priv->apn); + break; default: G_OBJECT_WARN_INVALID_PROPERTY_ID (object, prop_id, pspec); break; @@ -741,6 +789,10 @@ set_property (GObject *object, guint prop_id, case PROP_CURRENT_CAPABILITIES: priv->current_caps = g_value_get_uint (value); break; + case PROP_DEVICE_ID: + /* construct-only */ + priv->device_id = g_value_dup_string (value); + break; default: G_OBJECT_WARN_INVALID_PROPERTY_ID (object, prop_id, pspec); break; @@ -775,6 +827,7 @@ nm_device_modem_new (NMModem *modem) NM_DEVICE_MODEM_MODEM, modem, NM_DEVICE_MODEM_CAPABILITIES, caps, NM_DEVICE_MODEM_CURRENT_CAPABILITIES, current_caps, + NM_DEVICE_MODEM_DEVICE_ID, nm_modem_get_device_id (modem), NULL); } @@ -788,6 +841,10 @@ dispose (GObject *object) g_clear_object (&priv->modem); } + g_clear_pointer (&priv->device_id, g_free); + g_clear_pointer (&priv->operator_code, g_free); + g_clear_pointer (&priv->apn, g_free); + G_OBJECT_CLASS (nm_device_modem_parent_class)->dispose (object); } @@ -800,6 +857,9 @@ static const NMDBusInterfaceInfoExtended interface_info_device_modem = { .properties = NM_DEFINE_GDBUS_PROPERTY_INFOS ( NM_DEFINE_DBUS_PROPERTY_INFO_EXTENDED_READABLE_L ("ModemCapabilities", "u", NM_DEVICE_MODEM_CAPABILITIES), NM_DEFINE_DBUS_PROPERTY_INFO_EXTENDED_READABLE_L ("CurrentCapabilities", "u", NM_DEVICE_MODEM_CURRENT_CAPABILITIES), + NM_DEFINE_DBUS_PROPERTY_INFO_EXTENDED_READABLE ("DeviceId", "s", NM_DEVICE_MODEM_DEVICE_ID), + NM_DEFINE_DBUS_PROPERTY_INFO_EXTENDED_READABLE ("OperatorCode", "s", NM_DEVICE_MODEM_OPERATOR_CODE), + NM_DEFINE_DBUS_PROPERTY_INFO_EXTENDED_READABLE ("Apn", "s", NM_DEVICE_MODEM_APN), ), ), .legacy_property_changed = TRUE, @@ -857,5 +917,23 @@ nm_device_modem_class_init (NMDeviceModemClass *klass) G_PARAM_READWRITE | G_PARAM_CONSTRUCT_ONLY | G_PARAM_STATIC_STRINGS); + obj_properties[PROP_DEVICE_ID] = + g_param_spec_string (NM_DEVICE_MODEM_DEVICE_ID, "", "", + NULL, + G_PARAM_READWRITE | G_PARAM_CONSTRUCT_ONLY | + G_PARAM_STATIC_STRINGS); + + obj_properties[PROP_OPERATOR_CODE] = + g_param_spec_string (NM_DEVICE_MODEM_OPERATOR_CODE, "", "", + NULL, + G_PARAM_READABLE | + G_PARAM_STATIC_STRINGS); + + obj_properties[PROP_APN] = + g_param_spec_string (NM_DEVICE_MODEM_APN, "", "", + NULL, + G_PARAM_READABLE | + G_PARAM_STATIC_STRINGS); + g_object_class_install_properties (object_class, _PROPERTY_ENUMS_LAST, obj_properties); } diff --git a/src/devices/wwan/nm-device-modem.h b/src/devices/wwan/nm-device-modem.h index 65bda8b6..0a557f57 100644 --- a/src/devices/wwan/nm-device-modem.h +++ b/src/devices/wwan/nm-device-modem.h @@ -1,4 +1,3 @@ -/* -*- Mode: C; tab-width: 4; indent-tabs-mode: t; c-basic-offset: 4 -*- */ /* NetworkManager -- Network link manager * * This program is free software; you can redistribute it and/or modify @@ -34,6 +33,9 @@ #define NM_DEVICE_MODEM_MODEM "modem" #define NM_DEVICE_MODEM_CAPABILITIES "modem-capabilities" #define NM_DEVICE_MODEM_CURRENT_CAPABILITIES "current-capabilities" +#define NM_DEVICE_MODEM_DEVICE_ID "device-id" +#define NM_DEVICE_MODEM_OPERATOR_CODE "operator-code" +#define NM_DEVICE_MODEM_APN "apn" typedef struct _NMDeviceModem NMDeviceModem; typedef struct _NMDeviceModemClass NMDeviceModemClass; diff --git a/src/devices/wwan/nm-modem-broadband.c b/src/devices/wwan/nm-modem-broadband.c index ffdc61a6..5716500a 100644 --- a/src/devices/wwan/nm-modem-broadband.c +++ b/src/devices/wwan/nm-modem-broadband.c @@ -1,4 +1,3 @@ -/* -*- Mode: C; tab-width: 4; indent-tabs-mode: t; c-basic-offset: 4 -*- */ /* NetworkManager -- Network link manager * * This program is free software; you can redistribute it and/or modify @@ -79,6 +78,7 @@ typedef struct { MMObject *modem_object; /* Per-interface objects */ MMModem *modem_iface; + MMModem3gpp *modem_3gpp_iface; MMModemSimple *simple_iface; MMSim *sim_iface; @@ -213,12 +213,13 @@ owns_port (NMModem *_self, const char *iface) NMModemBroadband *self = NM_MODEM_BROADBAND (_self); const MMModemPortInfo *ports = NULL; guint n_ports = 0, i; - gboolean owns = FALSE; mm_modem_peek_ports (self->_priv.modem_iface, &ports, &n_ports); - for (i = 0; i < n_ports && !owns; i++) - owns = (g_strcmp0 (iface, ports[i].name) == 0); - return owns; + for (i = 0; i < n_ports; i++) { + if (nm_streq0 (iface, ports[i].name)) + return TRUE; + } + return FALSE; } /*****************************************************************************/ @@ -547,6 +548,8 @@ connect_context_step (NMModemBroadband *self) else g_assert_not_reached (); + _nm_modem_set_apn (NM_MODEM (self), mm_simple_connect_properties_get_apn (ctx->connect_properties)); + _LOGD ("launching connection with ip type '%s' (try %d)", nm_modem_ip_type_to_string (current), ctx->ip_type_tries + 1); @@ -656,12 +659,13 @@ check_connection_compatible_with_modem (NMModem *_self, NMConnection *connection /*****************************************************************************/ static gboolean -complete_connection (NMModem *_self, +complete_connection (NMModem *modem, + const char *iface, NMConnection *connection, NMConnection *const*existing_connections, GError **error) { - NMModemBroadband *self = NM_MODEM_BROADBAND (_self); + NMModemBroadband *self = NM_MODEM_BROADBAND (modem); MMModemCapability modem_caps; NMSettingPpp *s_ppp; @@ -679,6 +683,20 @@ complete_connection (NMModem *_self, } if (MODEM_CAPS_3GPP (modem_caps)) { + NMSettingGsm *s_gsm; + + s_gsm = nm_connection_get_setting_gsm (connection); + if (!s_gsm) { + s_gsm = (NMSettingGsm *) nm_setting_gsm_new (); + nm_connection_add_setting (connection, NM_SETTING (s_gsm)); + } + + if (!nm_setting_gsm_get_device_id (s_gsm)) { + g_object_set (G_OBJECT (s_gsm), + NM_SETTING_GSM_DEVICE_ID, nm_modem_get_device_id (modem), + NULL); + } + nm_utils_complete_generic (NM_PLATFORM_GET, connection, NM_SETTING_GSM_SETTING_NAME, @@ -686,6 +704,7 @@ complete_connection (NMModem *_self, NULL, _("GSM connection"), NULL, + NULL, FALSE); /* No IPv6 yet by default */ return TRUE; @@ -710,6 +729,7 @@ complete_connection (NMModem *_self, NULL, _("CDMA connection"), NULL, + iface, FALSE); /* No IPv6 yet by default */ return TRUE; @@ -1140,6 +1160,7 @@ disconnect (NMModem *modem, DisconnectContext *ctx; connect_context_clear (self); + _nm_modem_set_apn (NM_MODEM (self), NULL); ctx = g_slice_new0 (DisconnectContext); ctx->self = g_object_ref (self); @@ -1320,6 +1341,15 @@ supported_ip_families_changed (MMModem *modem, GParamSpec *pspec, gpointer user_ NULL); } +static void +operator_code_changed (MMModem3gpp *modem_3gpp, GParamSpec *pspec, gpointer user_data) +{ + NMModemBroadband *self = NM_MODEM_BROADBAND (user_data); + + g_return_if_fail (modem_3gpp == self->_priv.modem_3gpp_iface); + _nm_modem_set_operator_code (NM_MODEM (self), mm_modem_3gpp_get_operator_code (modem_3gpp)); +} + /*****************************************************************************/ static void @@ -1353,6 +1383,7 @@ set_property (GObject *object, /* construct-only */ self->_priv.modem_object = g_value_dup_object (value); self->_priv.modem_iface = mm_object_get_modem (self->_priv.modem_object); + self->_priv.modem_3gpp_iface = mm_object_get_modem_3gpp (self->_priv.modem_object); g_assert (self->_priv.modem_iface != NULL); g_signal_connect (self->_priv.modem_iface, "state-changed", @@ -1368,6 +1399,13 @@ set_property (GObject *object, G_CALLBACK (supported_ip_families_changed), self); + if (self->_priv.modem_3gpp_iface) { + g_signal_connect (self->_priv.modem_3gpp_iface, + "notify::operator-code", + G_CALLBACK (operator_code_changed), + self); + } + /* Note: don't grab the Simple iface here; the Modem interface is the * only one assumed to be always valid and available */ break; @@ -1389,7 +1427,9 @@ nm_modem_broadband_new (GObject *object, GError **error) { MMObject *modem_object; MMModem *modem_iface; + MMModem3gpp *modem_3gpp_iface; const char *const*drivers; + const char *operator_code = NULL; gs_free char *driver = NULL; g_return_val_if_fail (MM_IS_OBJECT (object), NULL); @@ -1405,6 +1445,10 @@ nm_modem_broadband_new (GObject *object, GError **error) if (drivers) driver = g_strjoinv (", ", (char **) drivers); + modem_3gpp_iface = mm_object_peek_modem_3gpp (modem_object); + if (modem_3gpp_iface) + operator_code = mm_modem_3gpp_get_operator_code (modem_3gpp_iface); + return g_object_new (NM_TYPE_MODEM_BROADBAND, NM_MODEM_PATH, mm_object_get_path (modem_object), NM_MODEM_UID, mm_modem_get_primary_port (modem_iface), @@ -1414,6 +1458,7 @@ nm_modem_broadband_new (GObject *object, GError **error) NM_MODEM_DEVICE_ID, mm_modem_get_device_identifier (modem_iface), NM_MODEM_BROADBAND_MODEM, modem_object, NM_MODEM_DRIVER, driver, + NM_MODEM_OPERATOR_CODE, operator_code, NULL); } @@ -1430,7 +1475,17 @@ dispose (GObject *object) g_clear_object (&self->_priv.ipv4_config); g_clear_object (&self->_priv.ipv6_config); g_clear_object (&self->_priv.bearer); - g_clear_object (&self->_priv.modem_iface); + + if (self->_priv.modem_iface) { + g_signal_handlers_disconnect_by_data (self->_priv.modem_iface, self); + g_clear_object (&self->_priv.modem_iface); + } + + if (self->_priv.modem_3gpp_iface) { + g_signal_handlers_disconnect_by_data (self->_priv.modem_3gpp_iface, self); + g_clear_object (&self->_priv.modem_3gpp_iface); + } + g_clear_object (&self->_priv.simple_iface); g_clear_object (&self->_priv.sim_iface); g_clear_object (&self->_priv.modem_object); diff --git a/src/devices/wwan/nm-modem-broadband.h b/src/devices/wwan/nm-modem-broadband.h index 4948cb3b..9404f0b9 100644 --- a/src/devices/wwan/nm-modem-broadband.h +++ b/src/devices/wwan/nm-modem-broadband.h @@ -1,4 +1,3 @@ -/* -*- Mode: C; tab-width: 4; indent-tabs-mode: t; c-basic-offset: 4 -*- */ /* NetworkManager -- Network link manager * * This program is free software; you can redistribute it and/or modify diff --git a/src/devices/wwan/nm-modem-manager.c b/src/devices/wwan/nm-modem-manager.c index 4be089c0..db2c0192 100644 --- a/src/devices/wwan/nm-modem-manager.c +++ b/src/devices/wwan/nm-modem-manager.c @@ -1,4 +1,3 @@ -/* -*- Mode: C; tab-width: 4; indent-tabs-mode: t; c-basic-offset: 4 -*- */ /* NetworkManager -- Network link manager * * This program is free software; you can redistribute it and/or modify diff --git a/src/devices/wwan/nm-modem-manager.h b/src/devices/wwan/nm-modem-manager.h index 5f913083..1a26fd9f 100644 --- a/src/devices/wwan/nm-modem-manager.h +++ b/src/devices/wwan/nm-modem-manager.h @@ -1,4 +1,3 @@ -/* -*- Mode: C; tab-width: 4; indent-tabs-mode: t; c-basic-offset: 4 -*- */ /* NetworkManager -- Network link manager * * This program is free software; you can redistribute it and/or modify diff --git a/src/devices/wwan/nm-modem-ofono.c b/src/devices/wwan/nm-modem-ofono.c index 78d9a9f0..31111b62 100644 --- a/src/devices/wwan/nm-modem-ofono.c +++ b/src/devices/wwan/nm-modem-ofono.c @@ -1,4 +1,3 @@ -/* -*- Mode: C; tab-width: 4; indent-tabs-mode: t; c-basic-offset: 4 -*- */ /* NetworkManager -- Network link manager * * This program is free software; you can redistribute it and/or modify diff --git a/src/devices/wwan/nm-modem-ofono.h b/src/devices/wwan/nm-modem-ofono.h index d9cb68ac..1dcd79b0 100644 --- a/src/devices/wwan/nm-modem-ofono.h +++ b/src/devices/wwan/nm-modem-ofono.h @@ -1,4 +1,3 @@ -/* -*- Mode: C; tab-width: 4; indent-tabs-mode: t; c-basic-offset: 4 -*- */ /* NetworkManager -- Network link manager * * This program is free software; you can redistribute it and/or modify diff --git a/src/devices/wwan/nm-modem.c b/src/devices/wwan/nm-modem.c index 17794229..617096a7 100644 --- a/src/devices/wwan/nm-modem.c +++ b/src/devices/wwan/nm-modem.c @@ -1,4 +1,3 @@ -/* -*- Mode: C; tab-width: 4; indent-tabs-mode: t; c-basic-offset: 4 -*- */ /* NetworkManager -- Network link manager * * This program is free software; you can redistribute it and/or modify @@ -52,6 +51,8 @@ NM_GOBJECT_PROPERTIES_DEFINE (NMModem, PROP_SIM_ID, PROP_IP_TYPES, PROP_SIM_OPERATOR_ID, + PROP_OPERATOR_CODE, + PROP_APN, ); enum { @@ -90,6 +91,8 @@ typedef struct _NMModemPrivate { char *sim_id; NMModemIPType ip_types; char *sim_operator_id; + char *operator_code; + char *apn; NMPPPManager *ppp_manager; @@ -344,7 +347,8 @@ nm_modem_get_connection_ip_type (NMModem *self, s_ip6 = nm_connection_get_setting_ip6_config (connection); if (s_ip6) { method = nm_setting_ip_config_get_method (s_ip6); - if (g_strcmp0 (method, NM_SETTING_IP6_CONFIG_METHOD_IGNORE) == 0) + if (NM_IN_STRSET (method, NM_SETTING_IP6_CONFIG_METHOD_IGNORE, + NM_SETTING_IP6_CONFIG_METHOD_DISABLED)) ip6 = FALSE; ip6_may_fail = nm_setting_ip_config_get_may_fail (s_ip6); } @@ -436,6 +440,18 @@ nm_modem_get_sim_operator_id (NMModem *self) return NM_MODEM_GET_PRIVATE (self)->sim_operator_id; } +const char * +nm_modem_get_operator_code (NMModem *self) +{ + return NM_MODEM_GET_PRIVATE (self)->operator_code; +} + +const char * +nm_modem_get_apn (NMModem *self) +{ + return NM_MODEM_GET_PRIVATE (self)->apn; +} + /*****************************************************************************/ /* IP method PPP */ @@ -824,8 +840,9 @@ nm_modem_stage3_ip6_config_start (NMModem *self, method = nm_utils_get_ip_config_method (connection, AF_INET6); - /* Only Ignore and Auto methods make sense for WWAN */ - if (nm_streq (method, NM_SETTING_IP6_CONFIG_METHOD_IGNORE)) + /* Only Ignore, Disabled and Auto methods make sense for WWAN */ + if (NM_IN_STRSET (method, NM_SETTING_IP6_CONFIG_METHOD_IGNORE, + NM_SETTING_IP6_CONFIG_METHOD_DISABLED)) return NM_ACT_STAGE_RETURN_IP_DONE; if (!nm_streq (method, NM_SETTING_IP6_CONFIG_METHOD_AUTO)) { @@ -1086,6 +1103,7 @@ nm_modem_check_connection_compatible (NMModem *self, NMConnection *connection, G gboolean nm_modem_complete_connection (NMModem *self, + const char *iface, NMConnection *connection, NMConnection *const*existing_connections, GError **error) @@ -1100,7 +1118,7 @@ nm_modem_complete_connection (NMModem *self, return FALSE; } - return klass->complete_connection (self, connection, existing_connections, error); + return klass->complete_connection (self, iface, connection, existing_connections, error); } /*****************************************************************************/ @@ -1556,9 +1574,9 @@ nm_modem_set_route_parameters_from_device (NMModem *self, g_return_if_fail (NM_IS_DEVICE (device)); nm_modem_set_route_parameters (self, - nm_device_get_route_table (device, AF_INET, TRUE), + nm_device_get_route_table (device, AF_INET), nm_device_get_route_metric (device, AF_INET), - nm_device_get_route_table (device, AF_INET6, TRUE), + nm_device_get_route_table (device, AF_INET6), nm_device_get_route_metric (device, AF_INET6)); } @@ -1576,6 +1594,30 @@ nm_modem_get_capabilities (NMModem *self, /*****************************************************************************/ +void +_nm_modem_set_operator_code (NMModem *self, const char *operator_code) +{ + NMModemPrivate *priv = NM_MODEM_GET_PRIVATE (self); + + if (g_strcmp0 (priv->operator_code, operator_code) != 0) { + g_free (priv->operator_code); + priv->operator_code = g_strdup (operator_code); + _notify (self, PROP_OPERATOR_CODE); + } +} + +void +_nm_modem_set_apn (NMModem *self, const char *apn) +{ + NMModemPrivate *priv = NM_MODEM_GET_PRIVATE (self); + + if (g_strcmp0 (priv->apn, apn) != 0) { + g_free (priv->apn); + priv->apn = g_strdup (apn); + _notify (self, PROP_APN); + } +} + static void get_property (GObject *object, guint prop_id, GValue *value, GParamSpec *pspec) @@ -1614,6 +1656,12 @@ get_property (GObject *object, guint prop_id, case PROP_SIM_OPERATOR_ID: g_value_set_string (value, priv->sim_operator_id); break; + case PROP_OPERATOR_CODE: + g_value_set_string (value, priv->operator_code); + break; + case PROP_APN: + g_value_set_string (value, priv->apn); + break; default: G_OBJECT_WARN_INVALID_PROPERTY_ID (object, prop_id, pspec); break; @@ -1666,6 +1714,10 @@ set_property (GObject *object, guint prop_id, if (s && s[0]) priv->sim_operator_id = g_strdup (s); break; + case PROP_OPERATOR_CODE: + /* construct-only */ + priv->operator_code = g_value_dup_string (value); + break; default: G_OBJECT_WARN_INVALID_PROPERTY_ID (object, prop_id, pspec); break; @@ -1727,6 +1779,8 @@ finalize (GObject *object) g_free (priv->device_id); g_free (priv->sim_id); g_free (priv->sim_operator_id); + g_free (priv->operator_code); + g_free (priv->apn); G_OBJECT_CLASS (nm_modem_parent_class)->finalize (object); } @@ -1810,6 +1864,18 @@ nm_modem_class_init (NMModemClass *klass) G_PARAM_READWRITE | G_PARAM_CONSTRUCT | G_PARAM_STATIC_STRINGS); + obj_properties[PROP_OPERATOR_CODE] = + g_param_spec_string (NM_MODEM_OPERATOR_CODE, "", "", + NULL, + G_PARAM_READWRITE | G_PARAM_CONSTRUCT | + G_PARAM_STATIC_STRINGS); + + obj_properties[PROP_APN] = + g_param_spec_string (NM_MODEM_APN, "", "", + NULL, + G_PARAM_READABLE | + G_PARAM_STATIC_STRINGS); + g_object_class_install_properties (object_class, _PROPERTY_ENUMS_LAST, obj_properties); signals[PPP_STATS] = diff --git a/src/devices/wwan/nm-modem.h b/src/devices/wwan/nm-modem.h index f7b6bfe9..f5b386e8 100644 --- a/src/devices/wwan/nm-modem.h +++ b/src/devices/wwan/nm-modem.h @@ -1,4 +1,3 @@ -/* -*- Mode: C; tab-width: 4; indent-tabs-mode: t; c-basic-offset: 4 -*- */ /* NetworkManager -- Network link manager * * This program is free software; you can redistribute it and/or modify @@ -43,6 +42,8 @@ #define NM_MODEM_SIM_ID "sim-id" #define NM_MODEM_IP_TYPES "ip-types" /* Supported IP types */ #define NM_MODEM_SIM_OPERATOR_ID "sim-operator-id" +#define NM_MODEM_OPERATOR_CODE "operator-code" +#define NM_MODEM_APN "apn" /* Signals */ #define NM_MODEM_PPP_STATS "ppp-stats" @@ -130,6 +131,7 @@ typedef struct { GError **error); gboolean (*complete_connection) (NMModem *modem, + const char *iface, NMConnection *connection, NMConnection *const*existing_connections, GError **error); @@ -174,6 +176,8 @@ const char *nm_modem_get_device_id (NMModem *modem); const char *nm_modem_get_sim_id (NMModem *modem); const char *nm_modem_get_sim_operator_id (NMModem *modem); gboolean nm_modem_get_iid (NMModem *modem, NMUtilsIPv6IfaceId *out_iid); +const char *nm_modem_get_operator_code (NMModem *modem); +const char *nm_modem_get_apn (NMModem *modem); gboolean nm_modem_set_data_port (NMModem *self, NMPlatform *platform, @@ -194,6 +198,7 @@ gboolean nm_modem_check_connection_compatible (NMModem *self, GError **error); gboolean nm_modem_complete_connection (NMModem *self, + const char *iface, NMConnection *connection, NMConnection *const*existing_connections, GError **error); @@ -284,4 +289,7 @@ const char *nm_modem_ip_type_to_string (NMModemIPType ip_type); guint32 nm_modem_get_configured_mtu (NMDevice *self, NMDeviceMtuSource *out_source); +void _nm_modem_set_operator_code (NMModem *self, const char *operator_code); +void _nm_modem_set_apn (NMModem *self, const char *apn); + #endif /* __NETWORKMANAGER_MODEM_H__ */ diff --git a/src/devices/wwan/nm-wwan-factory.c b/src/devices/wwan/nm-wwan-factory.c index c9ee27ff..a0e5c160 100644 --- a/src/devices/wwan/nm-wwan-factory.c +++ b/src/devices/wwan/nm-wwan-factory.c @@ -1,4 +1,3 @@ -/* -*- Mode: C; tab-width: 4; indent-tabs-mode: t; c-basic-offset: 4 -*- */ /* NetworkManager -- Network link manager * * This program is free software; you can redistribute it and/or modify |