diff options
Diffstat (limited to 'src/core/devices')
85 files changed, 2895 insertions, 1320 deletions
diff --git a/src/core/devices/adsl/nm-atm-manager.c b/src/core/devices/adsl/nm-atm-manager.c index cc8d37e6..f3c0d367 100644 --- a/src/core/devices/adsl/nm-atm-manager.c +++ b/src/core/devices/adsl/nm-atm-manager.c @@ -17,7 +17,8 @@ /*****************************************************************************/ #define NM_TYPE_ATM_MANAGER (nm_atm_manager_get_type()) -#define NM_ATM_MANAGER(obj) (G_TYPE_CHECK_INSTANCE_CAST((obj), NM_TYPE_ATM_MANAGER, NMAtmManager)) +#define NM_ATM_MANAGER(obj) \ + (_NM_G_TYPE_CHECK_INSTANCE_CAST((obj), NM_TYPE_ATM_MANAGER, NMAtmManager)) #define NM_ATM_MANAGER_CLASS(klass) \ (G_TYPE_CHECK_CLASS_CAST((klass), NM_TYPE_ATM_MANAGER, NMAtmManagerClass)) #define NM_IS_ATM_MANAGER(obj) (G_TYPE_CHECK_INSTANCE_TYPE((obj), NM_TYPE_ATM_MANAGER)) diff --git a/src/core/devices/adsl/nm-device-adsl.c b/src/core/devices/adsl/nm-device-adsl.c index 79705c28..fcd16b1c 100644 --- a/src/core/devices/adsl/nm-device-adsl.c +++ b/src/core/devices/adsl/nm-device-adsl.c @@ -214,12 +214,12 @@ error: } static void -link_changed_cb(NMPlatform *platform, - int obj_type_i, - int ifindex, - NMPlatformLink *info, - int change_type_i, - NMDeviceAdsl *self) +link_changed_cb(NMPlatform *platform, + int obj_type_i, + int ifindex, + const NMPlatformLink *info, + int change_type_i, + NMDeviceAdsl *self) { const NMPlatformSignalChangeType change_type = change_type_i; diff --git a/src/core/devices/adsl/nm-device-adsl.h b/src/core/devices/adsl/nm-device-adsl.h index c5c18901..287a1401 100644 --- a/src/core/devices/adsl/nm-device-adsl.h +++ b/src/core/devices/adsl/nm-device-adsl.h @@ -10,7 +10,8 @@ #include "devices/nm-device.h" #define NM_TYPE_DEVICE_ADSL (nm_device_adsl_get_type()) -#define NM_DEVICE_ADSL(obj) (G_TYPE_CHECK_INSTANCE_CAST((obj), NM_TYPE_DEVICE_ADSL, NMDeviceAdsl)) +#define NM_DEVICE_ADSL(obj) \ + (_NM_G_TYPE_CHECK_INSTANCE_CAST((obj), NM_TYPE_DEVICE_ADSL, NMDeviceAdsl)) #define NM_DEVICE_ADSL_CLASS(klass) \ (G_TYPE_CHECK_CLASS_CAST((klass), NM_TYPE_DEVICE_ADSL, NMDeviceAdslClass)) #define NM_IS_DEVICE_ADSL(obj) (G_TYPE_CHECK_INSTANCE_TYPE((obj), NM_TYPE_DEVICE_ADSL)) diff --git a/src/core/devices/bluetooth/nm-bluez-manager.c b/src/core/devices/bluetooth/nm-bluez-manager.c index 6bc00faf..ac26ede8 100644 --- a/src/core/devices/bluetooth/nm-bluez-manager.c +++ b/src/core/devices/bluetooth/nm-bluez-manager.c @@ -1010,8 +1010,9 @@ _network_server_get_bluez_manager(const NMBtVTableNetworkServer *vtable_network_ { NMBluezManager *self; - self = (NMBluezManager *) (((char *) vtable_network_server) - - G_STRUCT_OFFSET(NMBluezManager, _priv.vtable_network_server)); + self = NM_CAST_ALIGN(NMBluezManager, + (((char *) vtable_network_server) + - G_STRUCT_OFFSET(NMBluezManager, _priv.vtable_network_server))); g_return_val_if_fail(NM_IS_BLUEZ_MANAGER(self), NULL); diff --git a/src/core/devices/bluetooth/nm-bluez-manager.h b/src/core/devices/bluetooth/nm-bluez-manager.h index 299f5c3b..7c823c64 100644 --- a/src/core/devices/bluetooth/nm-bluez-manager.h +++ b/src/core/devices/bluetooth/nm-bluez-manager.h @@ -8,7 +8,7 @@ #define NM_TYPE_BLUEZ_MANAGER (nm_bluez_manager_get_type()) #define NM_BLUEZ_MANAGER(obj) \ - (G_TYPE_CHECK_INSTANCE_CAST((obj), NM_TYPE_BLUEZ_MANAGER, NMBluezManager)) + (_NM_G_TYPE_CHECK_INSTANCE_CAST((obj), NM_TYPE_BLUEZ_MANAGER, NMBluezManager)) #define NM_BLUEZ_MANAGER_CLASS(klass) \ (G_TYPE_CHECK_CLASS_CAST((klass), NM_TYPE_BLUEZ_MANAGER, NMBluezManagerClass)) #define NM_IS_BLUEZ_MANAGER(obj) (G_TYPE_CHECK_INSTANCE_TYPE((obj), NM_TYPE_BLUEZ_MANAGER)) diff --git a/src/core/devices/bluetooth/nm-device-bt.h b/src/core/devices/bluetooth/nm-device-bt.h index 59457fba..bf17e91f 100644 --- a/src/core/devices/bluetooth/nm-device-bt.h +++ b/src/core/devices/bluetooth/nm-device-bt.h @@ -9,7 +9,7 @@ #include "devices/nm-device.h" #define NM_TYPE_DEVICE_BT (nm_device_bt_get_type()) -#define NM_DEVICE_BT(obj) (G_TYPE_CHECK_INSTANCE_CAST((obj), NM_TYPE_DEVICE_BT, NMDeviceBt)) +#define NM_DEVICE_BT(obj) (_NM_G_TYPE_CHECK_INSTANCE_CAST((obj), NM_TYPE_DEVICE_BT, NMDeviceBt)) #define NM_DEVICE_BT_CLASS(klass) \ (G_TYPE_CHECK_CLASS_CAST((klass), NM_TYPE_DEVICE_BT, NMDeviceBtClass)) #define NM_IS_DEVICE_BT(obj) (G_TYPE_CHECK_INSTANCE_TYPE((obj), NM_TYPE_DEVICE_BT)) diff --git a/src/core/devices/nm-device-6lowpan.c b/src/core/devices/nm-device-6lowpan.c index d6543356..870a1c14 100644 --- a/src/core/devices/nm-device-6lowpan.c +++ b/src/core/devices/nm-device-6lowpan.c @@ -21,7 +21,6 @@ /*****************************************************************************/ typedef struct { - gulong parent_state_id; } NMDevice6LowpanPrivate; struct _NMDevice6Lowpan { @@ -41,51 +40,15 @@ G_DEFINE_TYPE(NMDevice6Lowpan, nm_device_6lowpan, NM_TYPE_DEVICE) /*****************************************************************************/ static void -parent_state_changed(NMDevice *parent, - NMDeviceState new_state, - NMDeviceState old_state, - NMDeviceStateReason reason, - gpointer user_data) -{ - NMDevice6Lowpan *self = NM_DEVICE_6LOWPAN(user_data); - - nm_device_set_unmanaged_by_flags(NM_DEVICE(self), - NM_UNMANAGED_PARENT, - !nm_device_get_managed(parent, FALSE), - reason); -} - -static void parent_changed_notify(NMDevice *device, int old_ifindex, NMDevice *old_parent, int new_ifindex, NMDevice *new_parent) { - NMDevice6Lowpan *self = NM_DEVICE_6LOWPAN(device); - NMDevice6LowpanPrivate *priv = NM_DEVICE_6LOWPAN_GET_PRIVATE(self); - NM_DEVICE_CLASS(nm_device_6lowpan_parent_class) ->parent_changed_notify(device, old_ifindex, old_parent, new_ifindex, new_parent); - /* note that @self doesn't have to clear @parent_state_id on dispose, - * because NMDevice's dispose() will unset the parent, which in turn calls - * parent_changed_notify(). */ - nm_clear_g_signal_handler(old_parent, &priv->parent_state_id); - - if (new_parent) { - priv->parent_state_id = g_signal_connect(new_parent, - NM_DEVICE_STATE_CHANGED, - G_CALLBACK(parent_state_changed), - device); - - /* Set parent-dependent unmanaged flag */ - nm_device_set_unmanaged_by_flags(device, - NM_UNMANAGED_PARENT, - !nm_device_get_managed(new_parent, FALSE), - NM_DEVICE_STATE_REASON_PARENT_MANAGED_CHANGED); - } - if (new_ifindex > 0) { /* Recheck availability now that the parent has changed */ nm_device_queue_recheck_available(device, @@ -272,7 +235,7 @@ nm_device_6lowpan_class_init(NMDevice6LowpanClass *klass) #define NM_TYPE_6LOWPAN_DEVICE_FACTORY (nm_6lowpan_device_factory_get_type()) #define NM_6LOWPAN_DEVICE_FACTORY(obj) \ - (G_TYPE_CHECK_INSTANCE_CAST((obj), NM_TYPE_6LOWPAN_DEVICE_FACTORY, NM6LowpanDeviceFactory)) + (_NM_G_TYPE_CHECK_INSTANCE_CAST((obj), NM_TYPE_6LOWPAN_DEVICE_FACTORY, NM6LowpanDeviceFactory)) static NMDevice * create_device(NMDeviceFactory *factory, diff --git a/src/core/devices/nm-device-6lowpan.h b/src/core/devices/nm-device-6lowpan.h index 34ea3c8d..bc6f77c4 100644 --- a/src/core/devices/nm-device-6lowpan.h +++ b/src/core/devices/nm-device-6lowpan.h @@ -10,7 +10,7 @@ #define NM_TYPE_DEVICE_6LOWPAN (nm_device_6lowpan_get_type()) #define NM_DEVICE_6LOWPAN(obj) \ - (G_TYPE_CHECK_INSTANCE_CAST((obj), NM_TYPE_DEVICE_6LOWPAN, NMDevice6Lowpan)) + (_NM_G_TYPE_CHECK_INSTANCE_CAST((obj), NM_TYPE_DEVICE_6LOWPAN, NMDevice6Lowpan)) #define NM_DEVICE_6LOWPAN_CLASS(klass) \ (G_TYPE_CHECK_CLASS_CAST((klass), NM_TYPE_DEVICE_6LOWPAN, NMDevice6LowpanClass)) #define NM_IS_DEVICE_6LOWPAN(obj) (G_TYPE_CHECK_INSTANCE_TYPE((obj), NM_TYPE_DEVICE_6LOWPAN)) diff --git a/src/core/devices/nm-device-bond.c b/src/core/devices/nm-device-bond.c index 10765b60..0b0697e3 100644 --- a/src/core/devices/nm-device-bond.c +++ b/src/core/devices/nm-device-bond.c @@ -20,6 +20,7 @@ #include "libnm-core-intern/nm-core-internal.h" #include "nm-manager.h" #include "nm-setting-bond-port.h" +#include "nm-bond-manager.h" #define _NMLOG_DEVICE_TYPE NMDeviceBond #include "nm-device-logging.h" @@ -59,7 +60,8 @@ /*****************************************************************************/ struct _NMDeviceBond { - NMDevice parent; + NMDevice parent; + NMBondManager *bond_manager; }; struct _NMDeviceBondClass { @@ -178,7 +180,9 @@ update_connection(NMDevice *device, NMConnection *connection) gs_free char *value = NULL; char *p; - if (NM_IN_STRSET(option, NM_SETTING_BOND_OPTION_ACTIVE_SLAVE)) + if (NM_IN_STRSET(option, + NM_SETTING_BOND_OPTION_ACTIVE_SLAVE, + NM_SETTING_BOND_OPTION_BALANCE_SLB)) continue; value = @@ -224,9 +228,10 @@ controller_update_port_connection(NMDevice *self, GError **error) { NMSettingBondPort *s_port; - int ifindex_port = nm_device_get_ifindex(port); - uint queue_id = NM_BOND_PORT_QUEUE_ID_DEF; - gs_free char *queue_id_str = NULL; + int ifindex_port = nm_device_get_ifindex(port); + NMConnection *applied_connection = nm_device_get_applied_connection(self); + uint queue_id = NM_BOND_PORT_QUEUE_ID_DEF; + gs_free char *queue_id_str = NULL; g_return_val_if_fail(ifindex_port > 0, FALSE); @@ -243,7 +248,7 @@ controller_update_port_connection(NMDevice *self, g_object_set(nm_connection_get_setting_connection(connection), NM_SETTING_CONNECTION_MASTER, - nm_device_get_iface(self), + nm_connection_get_uuid(applied_connection), NM_SETTING_CONNECTION_SLAVE_TYPE, NM_SETTING_BOND_SETTING_NAME, NULL); @@ -274,10 +279,10 @@ set_arp_targets(NMDevice *device, const char *cur_arp_ip_target, const char *new in_addr_t a4; s = new_strv[i]; - if (nm_utils_parse_inaddr_bin(AF_INET, s, NULL, &a4)) { + if (nm_inet_parse_bin(AF_INET, s, NULL, &a4)) { char sbuf[INET_ADDRSTRLEN]; - _nm_utils_inet4_ntop(a4, sbuf); + nm_inet4_ntop(a4, sbuf); if (!nm_streq(s, sbuf)) { if (!free_list) free_list = g_ptr_array_new_with_free_func(g_free); @@ -368,7 +373,7 @@ _bond_arp_ip_target_to_platform(const char *value, in_addr_t out[static NM_BOND_ for (i = 0; ip[i]; i++) { if (added > NM_BOND_MAX_ARP_TARGETS - 1) break; - if (!nm_utils_parse_inaddr_bin(AF_INET, ip[i], NULL, &in_a)) + if (!nm_inet_parse_bin(AF_INET, ip[i], NULL, &in_a)) nm_assert_not_reached(); /* verify() already validated the IP addresses */ out[added++] = in_a; @@ -460,10 +465,97 @@ _platform_lnk_bond_init_from_setting(NMSettingBond *s_bond, NMPlatformLnkBond *p props->tlb_dynamic_lb_has = NM_IN_SET(props->mode, NM_BOND_MODE_TLB, NM_BOND_MODE_ALB); } +static void +_balance_slb_cb(NMBondManager *bond_manager, NMBondManagerEventType event_type, gpointer user_data) +{ + NMDevice *device = user_data; + NMDeviceBond *self = NM_DEVICE_BOND(device); + + nm_assert(NM_IS_DEVICE_BOND(self)); + nm_assert(self->bond_manager == bond_manager); + + switch (event_type) { + case NM_BOND_MANAGER_EVENT_TYPE_STATE: + switch (nm_bond_manager_get_state(bond_manager)) { + case NM_OPTION_BOOL_FALSE: + if (nm_device_get_state(device) <= NM_DEVICE_STATE_ACTIVATED) { + _LOGD(LOGD_BOND, "balance-slb: failed"); + nm_device_state_changed(device, + NM_DEVICE_STATE_FAILED, + NM_DEVICE_STATE_REASON_CONFIG_FAILED); + } + return; + case NM_OPTION_BOOL_TRUE: + if (nm_device_get_state(device) <= NM_DEVICE_STATE_ACTIVATED + && nm_device_devip_get_state(device, AF_UNSPEC) <= NM_DEVICE_IP_STATE_PENDING) { + nm_device_devip_set_state(device, AF_UNSPEC, NM_DEVICE_IP_STATE_READY, NULL); + } + return; + case NM_OPTION_BOOL_DEFAULT: + if (nm_device_get_state(device) <= NM_DEVICE_STATE_ACTIVATED + && nm_device_devip_get_state(device, AF_UNSPEC) == NM_DEVICE_IP_STATE_READY) { + /* We are again busy. We can also go back to "pending" from "ready". + * If ip-config state is not yet complete, this will further delay it. + * Otherwise, it should have no effect. */ + nm_device_devip_set_state(device, AF_UNSPEC, NM_DEVICE_IP_STATE_PENDING, NULL); + } + return; + } + nm_assert_not_reached(); + return; + } + + nm_assert_not_reached(); +} + +static void +_balance_slb_setup(NMDeviceBond *self, NMConnection *connection) +{ + int ifindex = nm_device_get_ifindex(NM_DEVICE(self)); + gboolean balance_slb = FALSE; + const char *uuid; + NMSettingBond *s_bond; + + if (ifindex > 0 && connection && (s_bond = nm_connection_get_setting_bond(connection))) + balance_slb = _v_intbool(s_bond, NM_SETTING_BOND_OPTION_BALANCE_SLB); + + if (!balance_slb) { + if (nm_clear_pointer(&self->bond_manager, nm_bond_manager_destroy)) { + _LOGD(LOGD_BOND, "balance-slb: stopped"); + nm_device_devip_set_state(NM_DEVICE(self), AF_UNSPEC, NM_DEVICE_IP_STATE_NONE, NULL); + } + return; + } + + uuid = nm_connection_get_uuid(connection); + + if (self->bond_manager) { + if (nm_bond_manager_get_ifindex(self->bond_manager) == ifindex + && nm_streq0(nm_bond_manager_get_connection_uuid(self->bond_manager), uuid)) { + _LOGD(LOGD_BOND, "balance-slb: reapply"); + nm_bond_manager_reapply(self->bond_manager); + return; + } + nm_clear_pointer(&self->bond_manager, nm_bond_manager_destroy); + _LOGD(LOGD_BOND, "balance-slb: restart"); + } + + _LOGD(LOGD_BOND, "balance-slb: start"); + if (nm_device_devip_get_state(NM_DEVICE(self), AF_UNSPEC) < NM_DEVICE_IP_STATE_PENDING) + nm_device_devip_set_state(NM_DEVICE(self), AF_UNSPEC, NM_DEVICE_IP_STATE_PENDING, NULL); + self->bond_manager = nm_bond_manager_new(nm_device_get_platform(NM_DEVICE(self)), + ifindex, + uuid, + _balance_slb_cb, + self); + nm_assert(nm_bond_manager_get_state(self->bond_manager) == NM_OPTION_BOOL_DEFAULT); +} + static NMActStageReturn act_stage1_prepare(NMDevice *device, NMDeviceStateReason *out_failure_reason) { - NMActStageReturn ret = NM_ACT_STAGE_RETURN_SUCCESS; + NMDeviceBond *self = NM_DEVICE_BOND(device); + NMActStageReturn ret = NM_ACT_STAGE_RETURN_SUCCESS; NMConnection *connection; NMSettingBond *s_bond; NMPlatformLnkBond props; @@ -476,6 +568,14 @@ act_stage1_prepare(NMDevice *device, NMDeviceStateReason *out_failure_reason) s_bond = nm_connection_get_setting_bond(connection); g_return_val_if_fail(s_bond, NM_ACT_STAGE_RETURN_FAILURE); + if (nm_device_sys_iface_state_is_external(device)) + return NM_ACT_STAGE_RETURN_SUCCESS; + + _balance_slb_setup(self, connection); + + if (nm_device_sys_iface_state_is_external_or_assume(device)) + return NM_ACT_STAGE_RETURN_SUCCESS; + _platform_lnk_bond_init_from_setting(s_bond, &props); /* Interface must be down to set bond options */ @@ -684,7 +784,7 @@ can_reapply_change(NMDevice *device, const char *name = *option_list; /* We support changes to these */ - if (NM_IN_STRSET(name, OPTIONS_REAPPLY_FULL)) + if (NM_IN_STRSET(name, OPTIONS_REAPPLY_FULL, NM_SETTING_BOND_OPTION_BALANCE_SLB)) continue; /* Reject any other changes */ @@ -730,6 +830,16 @@ reapply_connection(NMDevice *device, NMConnection *con_old, NMConnection *con_ne set_bond_arp_ip_targets(device, s_bond); set_bond_attrs_or_default(device, s_bond, NM_MAKE_STRV(OPTIONS_REAPPLY_SUBSET)); + + _balance_slb_setup(self, con_new); +} + +static void +deactivate(NMDevice *device) +{ + NMDeviceBond *self = NM_DEVICE_BOND(device); + + _balance_slb_setup(self, NULL); } /*****************************************************************************/ @@ -768,20 +878,22 @@ nm_device_bond_class_init(NMDeviceBondClass *klass) device_class->update_connection = update_connection; device_class->master_update_slave_connection = controller_update_port_connection; - device_class->create_and_realize = create_and_realize; - device_class->act_stage1_prepare = act_stage1_prepare; + device_class->create_and_realize = create_and_realize; + device_class->act_stage1_prepare = act_stage1_prepare; + device_class->act_stage1_prepare_also_for_external_or_assume = TRUE; device_class->get_configured_mtu = nm_device_get_configured_mtu_for_wired; device_class->attach_port = attach_port; device_class->detach_port = detach_port; device_class->can_reapply_change = can_reapply_change; device_class->reapply_connection = reapply_connection; + device_class->deactivate = deactivate; } /*****************************************************************************/ #define NM_TYPE_BOND_DEVICE_FACTORY (nm_bond_device_factory_get_type()) #define NM_BOND_DEVICE_FACTORY(obj) \ - (G_TYPE_CHECK_INSTANCE_CAST((obj), NM_TYPE_BOND_DEVICE_FACTORY, NMBondDeviceFactory)) + (_NM_G_TYPE_CHECK_INSTANCE_CAST((obj), NM_TYPE_BOND_DEVICE_FACTORY, NMBondDeviceFactory)) static NMDevice * create_device(NMDeviceFactory *factory, diff --git a/src/core/devices/nm-device-bond.h b/src/core/devices/nm-device-bond.h index 19301793..083189bb 100644 --- a/src/core/devices/nm-device-bond.h +++ b/src/core/devices/nm-device-bond.h @@ -9,7 +9,8 @@ #include "nm-device.h" #define NM_TYPE_DEVICE_BOND (nm_device_bond_get_type()) -#define NM_DEVICE_BOND(obj) (G_TYPE_CHECK_INSTANCE_CAST((obj), NM_TYPE_DEVICE_BOND, NMDeviceBond)) +#define NM_DEVICE_BOND(obj) \ + (_NM_G_TYPE_CHECK_INSTANCE_CAST((obj), NM_TYPE_DEVICE_BOND, NMDeviceBond)) #define NM_DEVICE_BOND_CLASS(klass) \ (G_TYPE_CHECK_CLASS_CAST((klass), NM_TYPE_DEVICE_BOND, NMDeviceBondClass)) #define NM_IS_DEVICE_BOND(obj) (G_TYPE_CHECK_INSTANCE_TYPE((obj), NM_TYPE_DEVICE_BOND)) diff --git a/src/core/devices/nm-device-bridge.c b/src/core/devices/nm-device-bridge.c index 31cf361e..c5ce34c2 100644 --- a/src/core/devices/nm-device-bridge.c +++ b/src/core/devices/nm-device-bridge.c @@ -679,9 +679,10 @@ master_update_slave_connection(NMDevice *device, NMDeviceBridge *self = NM_DEVICE_BRIDGE(device); NMSettingConnection *s_con; NMSettingBridgePort *s_port; - int ifindex_slave = nm_device_get_ifindex(slave); - const char *iface = nm_device_get_iface(device); - const Option *option; + int ifindex_slave = nm_device_get_ifindex(slave); + NMConnection *applied_connection = nm_device_get_applied_connection(device); + + const Option *option; g_return_val_if_fail(ifindex_slave > 0, FALSE); @@ -717,7 +718,7 @@ master_update_slave_connection(NMDevice *device, g_object_set(s_con, NM_SETTING_CONNECTION_MASTER, - iface, + nm_connection_get_uuid(applied_connection), NM_SETTING_CONNECTION_SLAVE_TYPE, NM_SETTING_BRIDGE_SETTING_NAME, NULL); @@ -1270,7 +1271,7 @@ nm_device_bridge_class_init(NMDeviceBridgeClass *klass) #define NM_TYPE_BRIDGE_DEVICE_FACTORY (nm_bridge_device_factory_get_type()) #define NM_BRIDGE_DEVICE_FACTORY(obj) \ - (G_TYPE_CHECK_INSTANCE_CAST((obj), NM_TYPE_BRIDGE_DEVICE_FACTORY, NMBridgeDeviceFactory)) + (_NM_G_TYPE_CHECK_INSTANCE_CAST((obj), NM_TYPE_BRIDGE_DEVICE_FACTORY, NMBridgeDeviceFactory)) static NMDevice * create_device(NMDeviceFactory *factory, diff --git a/src/core/devices/nm-device-bridge.h b/src/core/devices/nm-device-bridge.h index 32437947..6d9f1614 100644 --- a/src/core/devices/nm-device-bridge.h +++ b/src/core/devices/nm-device-bridge.h @@ -10,7 +10,7 @@ #define NM_TYPE_DEVICE_BRIDGE (nm_device_bridge_get_type()) #define NM_DEVICE_BRIDGE(obj) \ - (G_TYPE_CHECK_INSTANCE_CAST((obj), NM_TYPE_DEVICE_BRIDGE, NMDeviceBridge)) + (_NM_G_TYPE_CHECK_INSTANCE_CAST((obj), NM_TYPE_DEVICE_BRIDGE, NMDeviceBridge)) #define NM_DEVICE_BRIDGE_CLASS(klass) \ (G_TYPE_CHECK_CLASS_CAST((klass), NM_TYPE_DEVICE_BRIDGE, NMDeviceBridgeClass)) #define NM_IS_DEVICE_BRIDGE(obj) (G_TYPE_CHECK_INSTANCE_TYPE((obj), NM_TYPE_DEVICE_BRIDGE)) diff --git a/src/core/devices/nm-device-dummy.c b/src/core/devices/nm-device-dummy.c index de701a0d..36a0ee6f 100644 --- a/src/core/devices/nm-device-dummy.c +++ b/src/core/devices/nm-device-dummy.c @@ -136,7 +136,7 @@ nm_device_dummy_class_init(NMDeviceDummyClass *klass) #define NM_TYPE_DUMMY_DEVICE_FACTORY (nm_dummy_device_factory_get_type()) #define NM_DUMMY_DEVICE_FACTORY(obj) \ - (G_TYPE_CHECK_INSTANCE_CAST((obj), NM_TYPE_DUMMY_DEVICE_FACTORY, NMDummyDeviceFactory)) + (_NM_G_TYPE_CHECK_INSTANCE_CAST((obj), NM_TYPE_DUMMY_DEVICE_FACTORY, NMDummyDeviceFactory)) static NMDevice * create_device(NMDeviceFactory *factory, diff --git a/src/core/devices/nm-device-dummy.h b/src/core/devices/nm-device-dummy.h index 2845b4eb..9e550887 100644 --- a/src/core/devices/nm-device-dummy.h +++ b/src/core/devices/nm-device-dummy.h @@ -10,7 +10,7 @@ #define NM_TYPE_DEVICE_DUMMY (nm_device_dummy_get_type()) #define NM_DEVICE_DUMMY(obj) \ - (G_TYPE_CHECK_INSTANCE_CAST((obj), NM_TYPE_DEVICE_DUMMY, NMDeviceDummy)) + (_NM_G_TYPE_CHECK_INSTANCE_CAST((obj), NM_TYPE_DEVICE_DUMMY, NMDeviceDummy)) #define NM_DEVICE_DUMMY_CLASS(klass) \ (G_TYPE_CHECK_CLASS_CAST((klass), NM_TYPE_DEVICE_DUMMY, NMDeviceDummyClass)) #define NM_IS_DEVICE_DUMMY(obj) (G_TYPE_CHECK_INSTANCE_TYPE((obj), NM_TYPE_DEVICE_DUMMY)) diff --git a/src/core/devices/nm-device-ethernet.c b/src/core/devices/nm-device-ethernet.c index 4788cdc6..97cf84a1 100644 --- a/src/core/devices/nm-device-ethernet.c +++ b/src/core/devices/nm-device-ethernet.c @@ -1735,11 +1735,10 @@ new_default_connection(NMDevice *self) /* Create a stable UUID. The UUID is also the Network_ID for stable-privacy addr-gen-mode, * thus when it changes we will also generate different IPv6 addresses. */ - uuid = nm_uuid_generate_from_strings("default-wired", - nm_utils_machine_id_str(), - defname, - perm_hw_addr ?: iface, - NULL); + uuid = nm_uuid_generate_from_strings_old("default-wired", + nm_utils_machine_id_str(), + defname, + perm_hw_addr ?: iface); g_object_set(setting, NM_SETTING_CONNECTION_ID, @@ -2114,8 +2113,10 @@ nm_device_ethernet_class_init(NMDeviceEthernetClass *klass) /*****************************************************************************/ #define NM_TYPE_ETHERNET_DEVICE_FACTORY (nm_ethernet_device_factory_get_type()) -#define NM_ETHERNET_DEVICE_FACTORY(obj) \ - (G_TYPE_CHECK_INSTANCE_CAST((obj), NM_TYPE_ETHERNET_DEVICE_FACTORY, NMEthernetDeviceFactory)) +#define NM_ETHERNET_DEVICE_FACTORY(obj) \ + (_NM_G_TYPE_CHECK_INSTANCE_CAST((obj), \ + NM_TYPE_ETHERNET_DEVICE_FACTORY, \ + NMEthernetDeviceFactory)) static NMDevice * create_device(NMDeviceFactory *factory, diff --git a/src/core/devices/nm-device-ethernet.h b/src/core/devices/nm-device-ethernet.h index 6e134d71..6c4acb82 100644 --- a/src/core/devices/nm-device-ethernet.h +++ b/src/core/devices/nm-device-ethernet.h @@ -11,7 +11,7 @@ #define NM_TYPE_DEVICE_ETHERNET (nm_device_ethernet_get_type()) #define NM_DEVICE_ETHERNET(obj) \ - (G_TYPE_CHECK_INSTANCE_CAST((obj), NM_TYPE_DEVICE_ETHERNET, NMDeviceEthernet)) + (_NM_G_TYPE_CHECK_INSTANCE_CAST((obj), NM_TYPE_DEVICE_ETHERNET, NMDeviceEthernet)) #define NM_DEVICE_ETHERNET_CLASS(klass) \ (G_TYPE_CHECK_CLASS_CAST((klass), NM_TYPE_DEVICE_ETHERNET, NMDeviceEthernetClass)) #define NM_IS_DEVICE_ETHERNET(obj) (G_TYPE_CHECK_INSTANCE_TYPE((obj), NM_TYPE_DEVICE_ETHERNET)) diff --git a/src/core/devices/nm-device-factory.c b/src/core/devices/nm-device-factory.c index 41e9480f..2f0ae2e8 100644 --- a/src/core/devices/nm-device-factory.c +++ b/src/core/devices/nm-device-factory.c @@ -398,6 +398,7 @@ nm_device_factory_manager_load_factories(NMDeviceFactoryManagerFactoryFunc callb _ADD_INTERNAL(nm_ethernet_device_factory_get_type); _ADD_INTERNAL(nm_infiniband_device_factory_get_type); _ADD_INTERNAL(nm_ip_tunnel_device_factory_get_type); + _ADD_INTERNAL(nm_loopback_device_factory_get_type); _ADD_INTERNAL(nm_macsec_device_factory_get_type); _ADD_INTERNAL(nm_macvlan_device_factory_get_type); _ADD_INTERNAL(nm_ppp_device_factory_get_type); diff --git a/src/core/devices/nm-device-factory.h b/src/core/devices/nm-device-factory.h index 51d64767..ac5ae05f 100644 --- a/src/core/devices/nm-device-factory.h +++ b/src/core/devices/nm-device-factory.h @@ -17,7 +17,7 @@ #define NM_TYPE_DEVICE_FACTORY (nm_device_factory_get_type()) #define NM_DEVICE_FACTORY(obj) \ - (G_TYPE_CHECK_INSTANCE_CAST((obj), NM_TYPE_DEVICE_FACTORY, NMDeviceFactory)) + (_NM_G_TYPE_CHECK_INSTANCE_CAST((obj), NM_TYPE_DEVICE_FACTORY, NMDeviceFactory)) #define NM_DEVICE_FACTORY_CLASS(klass) \ (G_TYPE_CHECK_CLASS_CAST((klass), NM_TYPE_DEVICE_FACTORY, NMDeviceFactoryClass)) #define NM_IS_DEVICE_FACTORY(obj) (G_TYPE_CHECK_INSTANCE_TYPE((obj), NM_TYPE_DEVICE_FACTORY)) @@ -208,7 +208,8 @@ NMDevice *nm_device_factory_create_device(NMDeviceFactory *factory, \ NM_DEVICE_FACTORY_DECLARE_TYPES(st_code) \ \ - static void nm_##lower##_device_factory_init(NM##mixed##DeviceFactory *self) {} \ + static void nm_##lower##_device_factory_init(NM##mixed##DeviceFactory *self) \ + {} \ \ static void nm_##lower##_device_factory_class_init(NM##mixed##DeviceFactoryClass *klass) \ { \ diff --git a/src/core/devices/nm-device-generic.h b/src/core/devices/nm-device-generic.h index 48c43523..f06a5bdc 100644 --- a/src/core/devices/nm-device-generic.h +++ b/src/core/devices/nm-device-generic.h @@ -10,7 +10,7 @@ #define NM_TYPE_DEVICE_GENERIC (nm_device_generic_get_type()) #define NM_DEVICE_GENERIC(obj) \ - (G_TYPE_CHECK_INSTANCE_CAST((obj), NM_TYPE_DEVICE_GENERIC, NMDeviceGeneric)) + (_NM_G_TYPE_CHECK_INSTANCE_CAST((obj), NM_TYPE_DEVICE_GENERIC, NMDeviceGeneric)) #define NM_DEVICE_GENERIC_CLASS(klass) \ (G_TYPE_CHECK_CLASS_CAST((klass), NM_TYPE_DEVICE_GENERIC, NMDeviceGenericClass)) #define NM_IS_DEVICE_GENERIC(obj) (G_TYPE_CHECK_INSTANCE_TYPE((obj), NM_TYPE_DEVICE_GENERIC)) diff --git a/src/core/devices/nm-device-infiniband.c b/src/core/devices/nm-device-infiniband.c index 6b6aef86..d025931e 100644 --- a/src/core/devices/nm-device-infiniband.c +++ b/src/core/devices/nm-device-infiniband.c @@ -403,10 +403,10 @@ nm_device_infiniband_class_init(NMDeviceInfinibandClass *klass) /*****************************************************************************/ #define NM_TYPE_INFINIBAND_DEVICE_FACTORY (nm_infiniband_device_factory_get_type()) -#define NM_INFINIBAND_DEVICE_FACTORY(obj) \ - (G_TYPE_CHECK_INSTANCE_CAST((obj), \ - NM_TYPE_INFINIBAND_DEVICE_FACTORY, \ - NMInfinibandDeviceFactory)) +#define NM_INFINIBAND_DEVICE_FACTORY(obj) \ + (_NM_G_TYPE_CHECK_INSTANCE_CAST((obj), \ + NM_TYPE_INFINIBAND_DEVICE_FACTORY, \ + NMInfinibandDeviceFactory)) static NMDevice * create_device(NMDeviceFactory *factory, diff --git a/src/core/devices/nm-device-infiniband.h b/src/core/devices/nm-device-infiniband.h index 69994a2d..5c915dd4 100644 --- a/src/core/devices/nm-device-infiniband.h +++ b/src/core/devices/nm-device-infiniband.h @@ -10,7 +10,7 @@ #define NM_TYPE_DEVICE_INFINIBAND (nm_device_infiniband_get_type()) #define NM_DEVICE_INFINIBAND(obj) \ - (G_TYPE_CHECK_INSTANCE_CAST((obj), NM_TYPE_DEVICE_INFINIBAND, NMDeviceInfiniband)) + (_NM_G_TYPE_CHECK_INSTANCE_CAST((obj), NM_TYPE_DEVICE_INFINIBAND, NMDeviceInfiniband)) #define NM_DEVICE_INFINIBAND_CLASS(klass) \ (G_TYPE_CHECK_CLASS_CAST((klass), NM_TYPE_DEVICE_INFINIBAND, NMDeviceInfinibandClass)) #define NM_IS_DEVICE_INFINIBAND(obj) (G_TYPE_CHECK_INSTANCE_TYPE((obj), NM_TYPE_DEVICE_INFINIBAND)) diff --git a/src/core/devices/nm-device-ip-tunnel.c b/src/core/devices/nm-device-ip-tunnel.c index 02680dd7..5e5ba632 100644 --- a/src/core/devices/nm-device-ip-tunnel.c +++ b/src/core/devices/nm-device-ip-tunnel.c @@ -39,6 +39,7 @@ NM_GOBJECT_PROPERTIES_DEFINE(NMDeviceIPTunnel, PROP_OUTPUT_KEY, PROP_ENCAPSULATION_LIMIT, PROP_FLOW_LABEL, + PROP_FWMARK, PROP_FLAGS, ); typedef struct { @@ -53,6 +54,7 @@ typedef struct { char *output_key; guint8 encap_limit; guint32 flow_label; + guint32 fwmark; NMIPTunnelFlags flags; } NMDeviceIPTunnelPrivate; @@ -107,12 +109,12 @@ address_equal_pp(int addr_family, const char *a, const char *b) nm_assert_addr_family(addr_family); if (a) { - if (!nm_utils_parse_inaddr_bin(addr_family, a, NULL, &addr_a_val)) + if (!nm_inet_parse_bin(addr_family, a, NULL, &addr_a_val)) nm_assert_not_reached(); addr_a = &addr_a_val; } if (b) { - if (!nm_utils_parse_inaddr_bin(addr_family, b, NULL, &addr_b_val)) + if (!nm_inet_parse_bin(addr_family, b, NULL, &addr_b_val)) nm_assert_not_reached(); addr_b = &addr_b_val; } @@ -125,7 +127,7 @@ address_set(int addr_family, char **p_addr, const NMIPAddr *addr_new) { nm_assert_addr_family(addr_family); nm_assert(p_addr); - nm_assert(!*p_addr || nm_utils_ipaddr_is_normalized(addr_family, *p_addr)); + nm_assert(!*p_addr || nm_inet_is_normalized(addr_family, *p_addr)); if (!addr_new || nm_ip_addr_is_null(addr_family, addr_new)) { if (nm_clear_g_free(p_addr)) @@ -136,7 +138,7 @@ address_set(int addr_family, char **p_addr, const NMIPAddr *addr_new) if (*p_addr) { NMIPAddr addr_val; - if (!nm_utils_parse_inaddr_bin(addr_family, *p_addr, NULL, &addr_val)) + if (!nm_inet_parse_bin(addr_family, *p_addr, NULL, &addr_val)) nm_assert_not_reached(); if (nm_ip_addr_equal(addr_family, &addr_val, addr_new)) @@ -145,7 +147,7 @@ address_set(int addr_family, char **p_addr, const NMIPAddr *addr_new) g_free(*p_addr); } - *p_addr = nm_utils_inet_ntop_dup(addr_family, addr_new); + *p_addr = nm_inet_ntop_dup(addr_family, addr_new); return TRUE; } @@ -162,8 +164,10 @@ update_properties_from_ifindex(NMDevice *device, int ifindex) guint8 encap_limit = 0; gboolean pmtud = FALSE; guint32 flow_label = 0; + guint32 fwmark = 0; NMIPTunnelFlags flags = NM_IP_TUNNEL_FLAG_NONE; - char *key; + gs_free char *input_key = NULL; + gs_free char *output_key = NULL; if (ifindex <= 0) { clear: @@ -207,35 +211,10 @@ clear: tos = lnk->tos; pmtud = lnk->path_mtu_discovery; - if (NM_FLAGS_HAS(lnk->input_flags, NM_GRE_KEY)) { - key = g_strdup_printf("%u", lnk->input_key); - if (g_strcmp0(priv->input_key, key)) { - g_free(priv->input_key); - priv->input_key = key; - _notify(self, PROP_INPUT_KEY); - } else - g_free(key); - } else { - if (priv->input_key) { - nm_clear_g_free(&priv->input_key); - _notify(self, PROP_INPUT_KEY); - } - } - - if (NM_FLAGS_HAS(lnk->output_flags, NM_GRE_KEY)) { - key = g_strdup_printf("%u", lnk->output_key); - if (g_strcmp0(priv->output_key, key)) { - g_free(priv->output_key); - priv->output_key = key; - _notify(self, PROP_OUTPUT_KEY); - } else - g_free(key); - } else { - if (priv->output_key) { - nm_clear_g_free(&priv->output_key); - _notify(self, PROP_OUTPUT_KEY); - } - } + if (NM_FLAGS_HAS(lnk->input_flags, NM_GRE_KEY)) + input_key = g_strdup_printf("%u", lnk->input_key); + if (NM_FLAGS_HAS(lnk->output_flags, NM_GRE_KEY)) + output_key = g_strdup_printf("%u", lnk->output_key); } else if (priv->mode == NM_IP_TUNNEL_MODE_SIT) { const NMPlatformLnkSit *lnk; @@ -296,36 +275,45 @@ clear: flags = ip6tnl_flags_plat_to_setting(lnk->flags); if (NM_IN_SET(priv->mode, NM_IP_TUNNEL_MODE_IP6GRE, NM_IP_TUNNEL_MODE_IP6GRETAP)) { - if (NM_FLAGS_HAS(lnk->input_flags, NM_GRE_KEY)) { - key = g_strdup_printf("%u", lnk->input_key); - if (g_strcmp0(priv->input_key, key)) { - g_free(priv->input_key); - priv->input_key = key; - _notify(self, PROP_INPUT_KEY); - } else - g_free(key); - } else { - if (priv->input_key) { - nm_clear_g_free(&priv->input_key); - _notify(self, PROP_INPUT_KEY); - } - } + if (NM_FLAGS_HAS(lnk->input_flags, NM_GRE_KEY)) + input_key = g_strdup_printf("%u", lnk->input_key); + if (NM_FLAGS_HAS(lnk->output_flags, NM_GRE_KEY)) + output_key = g_strdup_printf("%u", lnk->output_key); + } + } else if (priv->mode == NM_IP_TUNNEL_MODE_VTI) { + const NMPlatformLnkVti *lnk; - if (NM_FLAGS_HAS(lnk->output_flags, NM_GRE_KEY)) { - key = g_strdup_printf("%u", lnk->output_key); - if (g_strcmp0(priv->output_key, key)) { - g_free(priv->output_key); - priv->output_key = key; - _notify(self, PROP_OUTPUT_KEY); - } else - g_free(key); - } else { - if (priv->output_key) { - nm_clear_g_free(&priv->output_key); - _notify(self, PROP_OUTPUT_KEY); - } - } + lnk = nm_platform_link_get_lnk_vti(nm_device_get_platform(device), ifindex, NULL); + if (!lnk) { + _LOGW(LOGD_PLATFORM, "could not read %s properties", "vti"); + goto clear; + } + + parent_ifindex = lnk->parent_ifindex; + local.addr4 = lnk->local; + remote.addr4 = lnk->remote; + fwmark = lnk->fwmark; + if (lnk->ikey) + input_key = g_strdup_printf("%u", lnk->ikey); + if (lnk->okey) + input_key = g_strdup_printf("%u", lnk->okey); + } else if (priv->mode == NM_IP_TUNNEL_MODE_VTI6) { + const NMPlatformLnkVti6 *lnk; + + lnk = nm_platform_link_get_lnk_vti6(nm_device_get_platform(device), ifindex, NULL); + if (!lnk) { + _LOGW(LOGD_PLATFORM, "could not read %s properties", "vti6"); + goto clear; } + + parent_ifindex = lnk->parent_ifindex; + local.addr6 = lnk->local; + remote.addr6 = lnk->remote; + fwmark = lnk->fwmark; + if (lnk->ikey) + input_key = g_strdup_printf("%u", lnk->ikey); + if (lnk->okey) + input_key = g_strdup_printf("%u", lnk->okey); } else g_return_if_reached(); @@ -337,7 +325,6 @@ clear: _notify(self, PROP_REMOTE); out: - if (priv->ttl != ttl) { priv->ttl = ttl; _notify(self, PROP_TTL); @@ -363,6 +350,23 @@ out: _notify(self, PROP_FLOW_LABEL); } + if (!nm_streq0(priv->input_key, input_key)) { + g_free(priv->input_key); + priv->input_key = g_steal_pointer(&input_key); + _notify(self, PROP_INPUT_KEY); + } + + if (!nm_streq0(priv->output_key, output_key)) { + g_free(priv->output_key); + priv->output_key = g_steal_pointer(&output_key); + _notify(self, PROP_OUTPUT_KEY); + } + + if (priv->fwmark != fwmark) { + priv->fwmark = fwmark; + _notify(self, PROP_FWMARK); + } + if (priv->flags != flags) { priv->flags = flags; _notify(self, PROP_FLAGS); @@ -467,11 +471,17 @@ update_connection(NMDevice *device, NMConnection *connection) NULL); } + if (nm_setting_ip_tunnel_get_fwmark(s_ip_tunnel) != priv->fwmark) { + g_object_set(G_OBJECT(s_ip_tunnel), NM_SETTING_IP_TUNNEL_FWMARK, priv->fwmark, NULL); + } + if (NM_IN_SET(priv->mode, NM_IP_TUNNEL_MODE_GRE, NM_IP_TUNNEL_MODE_GRETAP, NM_IP_TUNNEL_MODE_IP6GRE, - NM_IP_TUNNEL_MODE_IP6GRETAP)) { + NM_IP_TUNNEL_MODE_IP6GRETAP, + NM_IP_TUNNEL_MODE_VTI, + NM_IP_TUNNEL_MODE_VTI6)) { if (g_strcmp0(nm_setting_ip_tunnel_get_input_key(s_ip_tunnel), priv->input_key)) { g_object_set(G_OBJECT(s_ip_tunnel), NM_SETTING_IP_TUNNEL_INPUT_KEY, @@ -493,6 +503,7 @@ check_connection_compatible(NMDevice *device, NMConnection *connection, GError * NMDeviceIPTunnel *self = NM_DEVICE_IP_TUNNEL(device); NMDeviceIPTunnelPrivate *priv = NM_DEVICE_IP_TUNNEL_GET_PRIVATE(self); NMSettingIPTunnel *s_ip_tunnel; + NMIPTunnelMode mode; const char *parent; if (!NM_DEVICE_CLASS(nm_device_ip_tunnel_parent_class) @@ -500,8 +511,9 @@ check_connection_compatible(NMDevice *device, NMConnection *connection, GError * return FALSE; s_ip_tunnel = nm_connection_get_setting_ip_tunnel(connection); + mode = nm_setting_ip_tunnel_get_mode(s_ip_tunnel); - if (nm_setting_ip_tunnel_get_mode(s_ip_tunnel) != priv->mode) { + if (mode != priv->mode) { nm_utils_error_set_literal(error, NM_UTILS_ERROR_CONNECTION_AVAILABLE_TEMPORARY, "incompatible IP tunnel mode"); @@ -536,14 +548,16 @@ check_connection_compatible(NMDevice *device, NMConnection *connection, GError * return FALSE; } - if (nm_setting_ip_tunnel_get_ttl(s_ip_tunnel) != priv->ttl) { + if (!NM_IN_SET(mode, NM_IP_TUNNEL_MODE_VTI, NM_IP_TUNNEL_MODE_VTI6) + && nm_setting_ip_tunnel_get_ttl(s_ip_tunnel) != priv->ttl) { nm_utils_error_set_literal(error, NM_UTILS_ERROR_CONNECTION_AVAILABLE_TEMPORARY, "TTL of IP tunnel mismatches"); return FALSE; } - if (nm_setting_ip_tunnel_get_tos(s_ip_tunnel) != priv->tos) { + if (!NM_IN_SET(mode, NM_IP_TUNNEL_MODE_VTI, NM_IP_TUNNEL_MODE_VTI6) + && nm_setting_ip_tunnel_get_tos(s_ip_tunnel) != priv->tos) { nm_utils_error_set_literal(error, NM_UTILS_ERROR_CONNECTION_AVAILABLE_TEMPORARY, "TOS of IP tunnel mismatches"); @@ -551,11 +565,14 @@ check_connection_compatible(NMDevice *device, NMConnection *connection, GError * } if (priv->addr_family == AF_INET) { - if (nm_setting_ip_tunnel_get_path_mtu_discovery(s_ip_tunnel) - != priv->path_mtu_discovery) { - nm_utils_error_set_literal(error, - NM_UTILS_ERROR_CONNECTION_AVAILABLE_TEMPORARY, - "MTU discovery setting of IP tunnel mismatches"); + if (!NM_IN_SET(mode, NM_IP_TUNNEL_MODE_VTI, NM_IP_TUNNEL_MODE_VTI6) + && nm_setting_ip_tunnel_get_path_mtu_discovery(s_ip_tunnel) + != priv->path_mtu_discovery) { + nm_utils_error_set(error, + NM_UTILS_ERROR_CONNECTION_AVAILABLE_TEMPORARY, + "MTU discovery setting of IP tunnel mismatches: %d vs %d", + nm_setting_ip_tunnel_get_path_mtu_discovery(s_ip_tunnel), + priv->path_mtu_discovery); return FALSE; } } else { @@ -605,6 +622,10 @@ platform_link_to_tunnel_mode(const NMPlatformLink *link) return NM_IP_TUNNEL_MODE_IPIP; case NM_LINK_TYPE_SIT: return NM_IP_TUNNEL_MODE_SIT; + case NM_LINK_TYPE_VTI: + return NM_IP_TUNNEL_MODE_VTI; + case NM_LINK_TYPE_VTI6: + return NM_IP_TUNNEL_MODE_VTI6; default: g_return_val_if_reached(NM_IP_TUNNEL_MODE_UNKNOWN); } @@ -630,7 +651,9 @@ tunnel_mode_to_link_type(NMIPTunnelMode tunnel_mode) case NM_IP_TUNNEL_MODE_SIT: return NM_LINK_TYPE_SIT; case NM_IP_TUNNEL_MODE_VTI: + return NM_LINK_TYPE_VTI; case NM_IP_TUNNEL_MODE_VTI6: + return NM_LINK_TYPE_VTI6; case NM_IP_TUNNEL_MODE_ISATAP: return NM_LINK_TYPE_UNKNOWN; case NM_IP_TUNNEL_MODE_UNKNOWN: @@ -654,6 +677,8 @@ create_and_realize(NMDevice *device, NMPlatformLnkSit lnk_sit = {}; NMPlatformLnkIpIp lnk_ipip = {}; NMPlatformLnkIp6Tnl lnk_ip6tnl = {}; + NMPlatformLnkVti lnk_vti = {}; + NMPlatformLnkVti6 lnk_vti6 = {}; const char *str; gint64 val; NMIPTunnelMode mode; @@ -871,6 +896,81 @@ create_and_realize(NMDevice *device, return FALSE; } break; + case NM_IP_TUNNEL_MODE_VTI: + if (parent) + lnk_vti.parent_ifindex = nm_device_get_ifindex(parent); + + str = nm_setting_ip_tunnel_get_local(s_ip_tunnel); + if (str) + inet_pton(AF_INET, str, &lnk_vti.local); + + str = nm_setting_ip_tunnel_get_remote(s_ip_tunnel); + nm_assert(str); + inet_pton(AF_INET, str, &lnk_vti.remote); + + lnk_vti.ikey = _nm_utils_ascii_str_to_int64(nm_setting_ip_tunnel_get_input_key(s_ip_tunnel), + 10, + 0, + G_MAXUINT32, + 0); + lnk_vti.okey = + _nm_utils_ascii_str_to_int64(nm_setting_ip_tunnel_get_output_key(s_ip_tunnel), + 10, + 0, + G_MAXUINT32, + 0); + lnk_vti.fwmark = nm_setting_ip_tunnel_get_fwmark(s_ip_tunnel); + + r = nm_platform_link_vti_add(nm_device_get_platform(device), iface, &lnk_vti, out_plink); + if (r < 0) { + g_set_error(error, + NM_DEVICE_ERROR, + NM_DEVICE_ERROR_CREATION_FAILED, + "Failed to create VTI interface '%s' for '%s': %s", + iface, + nm_connection_get_id(connection), + nm_strerror(r)); + return FALSE; + } + break; + case NM_IP_TUNNEL_MODE_VTI6: + if (parent) + lnk_vti6.parent_ifindex = nm_device_get_ifindex(parent); + + str = nm_setting_ip_tunnel_get_local(s_ip_tunnel); + if (str) + inet_pton(AF_INET6, str, &lnk_vti6.local); + + str = nm_setting_ip_tunnel_get_remote(s_ip_tunnel); + nm_assert(str); + inet_pton(AF_INET6, str, &lnk_vti6.remote); + + lnk_vti6.ikey = + _nm_utils_ascii_str_to_int64(nm_setting_ip_tunnel_get_input_key(s_ip_tunnel), + 10, + 0, + G_MAXUINT32, + 0); + lnk_vti6.okey = + _nm_utils_ascii_str_to_int64(nm_setting_ip_tunnel_get_output_key(s_ip_tunnel), + 10, + 0, + G_MAXUINT32, + 0); + lnk_vti6.fwmark = nm_setting_ip_tunnel_get_fwmark(s_ip_tunnel); + + r = nm_platform_link_vti6_add(nm_device_get_platform(device), iface, &lnk_vti6, out_plink); + if (r < 0) { + g_set_error(error, + NM_DEVICE_ERROR, + NM_DEVICE_ERROR_CREATION_FAILED, + "Failed to create VTI6 interface '%s' for '%s': %s", + iface, + nm_connection_get_id(connection), + nm_strerror(r)); + return FALSE; + } + break; default: g_set_error(error, NM_DEVICE_ERROR, @@ -986,6 +1086,9 @@ get_property(GObject *object, guint prop_id, GValue *value, GParamSpec *pspec) case PROP_FLAGS: g_value_set_uint(value, priv->flags); break; + case PROP_FWMARK: + g_value_set_uint(value, priv->fwmark); + break; default: G_OBJECT_WARN_INVALID_PROPERTY_ID(object, prop_id, pspec); break; @@ -1021,7 +1124,8 @@ constructed(GObject *object) NM_IP_TUNNEL_MODE_IPIP6, NM_IP_TUNNEL_MODE_IP6IP6, NM_IP_TUNNEL_MODE_IP6GRE, - NM_IP_TUNNEL_MODE_IP6GRETAP)) + NM_IP_TUNNEL_MODE_IP6GRETAP, + NM_IP_TUNNEL_MODE_VTI6)) priv->addr_family = AF_INET6; else priv->addr_family = AF_INET; @@ -1070,6 +1174,9 @@ static const NMDBusInterfaceInfoExtended interface_info_device_ip_tunnel = { NM_DEFINE_DBUS_PROPERTY_INFO_EXTENDED_READABLE("FlowLabel", "u", NM_DEVICE_IP_TUNNEL_FLOW_LABEL), + NM_DEFINE_DBUS_PROPERTY_INFO_EXTENDED_READABLE("FwMark", + "u", + NM_DEVICE_IP_TUNNEL_FWMARK), NM_DEFINE_DBUS_PROPERTY_INFO_EXTENDED_READABLE("Flags", "u", NM_DEVICE_IP_TUNNEL_FLAGS), ), ), @@ -1097,7 +1204,9 @@ nm_device_ip_tunnel_class_init(NMDeviceIPTunnelClass *klass) NM_LINK_TYPE_IP6GRE, NM_LINK_TYPE_IP6GRETAP, NM_LINK_TYPE_IPIP, - NM_LINK_TYPE_SIT); + NM_LINK_TYPE_SIT, + NM_LINK_TYPE_VTI, + NM_LINK_TYPE_VTI6); device_class->act_stage1_prepare = act_stage1_prepare; device_class->link_changed = link_changed; @@ -1192,14 +1301,24 @@ nm_device_ip_tunnel_class_init(NMDeviceIPTunnelClass *klass) 0, G_PARAM_READWRITE | G_PARAM_STATIC_STRINGS); + obj_properties[PROP_FWMARK] = g_param_spec_uint(NM_DEVICE_IP_TUNNEL_FWMARK, + "", + "", + 0, + G_MAXUINT32, + 0, + G_PARAM_READWRITE | G_PARAM_STATIC_STRINGS); + g_object_class_install_properties(object_class, _PROPERTY_ENUMS_LAST, obj_properties); } /*****************************************************************************/ #define NM_TYPE_IP_TUNNEL_DEVICE_FACTORY (nm_ip_tunnel_device_factory_get_type()) -#define NM_IP_TUNNEL_DEVICE_FACTORY(obj) \ - (G_TYPE_CHECK_INSTANCE_CAST((obj), NM_TYPE_IP_TUNNEL_DEVICE_FACTORY, NMIPTunnelDeviceFactory)) +#define NM_IP_TUNNEL_DEVICE_FACTORY(obj) \ + (_NM_G_TYPE_CHECK_INSTANCE_CAST((obj), \ + NM_TYPE_IP_TUNNEL_DEVICE_FACTORY, \ + NMIPTunnelDeviceFactory)) static NMDevice * create_device(NMDeviceFactory *factory, @@ -1282,7 +1401,9 @@ NM_DEVICE_FACTORY_DEFINE_INTERNAL( NM_LINK_TYPE_IPIP, NM_LINK_TYPE_IP6TNL, NM_LINK_TYPE_IP6GRE, - NM_LINK_TYPE_IP6GRETAP) + NM_LINK_TYPE_IP6GRETAP, + NM_LINK_TYPE_VTI, + NM_LINK_TYPE_VTI6) NM_DEVICE_FACTORY_DECLARE_SETTING_TYPES(NM_SETTING_IP_TUNNEL_SETTING_NAME), factory_class->create_device = create_device; factory_class->get_connection_parent = get_connection_parent; diff --git a/src/core/devices/nm-device-ip-tunnel.h b/src/core/devices/nm-device-ip-tunnel.h index 0a941cc2..1d7b7381 100644 --- a/src/core/devices/nm-device-ip-tunnel.h +++ b/src/core/devices/nm-device-ip-tunnel.h @@ -11,7 +11,7 @@ #define NM_TYPE_DEVICE_IP_TUNNEL (nm_device_ip_tunnel_get_type()) #define NM_DEVICE_IP_TUNNEL(obj) \ - (G_TYPE_CHECK_INSTANCE_CAST((obj), NM_TYPE_DEVICE_IP_TUNNEL, NMDeviceIPTunnel)) + (_NM_G_TYPE_CHECK_INSTANCE_CAST((obj), NM_TYPE_DEVICE_IP_TUNNEL, NMDeviceIPTunnel)) #define NM_DEVICE_IP_TUNNEL_CLASS(klass) \ (G_TYPE_CHECK_CLASS_CAST((klass), NM_TYPE_DEVICE_IP_TUNNEL, NMDeviceIPTunnelClass)) #define NM_IS_DEVICE_IP_TUNNEL(obj) (G_TYPE_CHECK_INSTANCE_TYPE((obj), NM_TYPE_DEVICE_IP_TUNNEL)) @@ -31,6 +31,7 @@ #define NM_DEVICE_IP_TUNNEL_ENCAPSULATION_LIMIT "encapsulation-limit" #define NM_DEVICE_IP_TUNNEL_FLOW_LABEL "flow-label" #define NM_DEVICE_IP_TUNNEL_FLAGS "flags" +#define NM_DEVICE_IP_TUNNEL_FWMARK "fwmark" typedef struct _NMDeviceIPTunnel NMDeviceIPTunnel; typedef struct _NMDeviceIPTunnelClass NMDeviceIPTunnelClass; diff --git a/src/core/devices/nm-device-logging.h b/src/core/devices/nm-device-logging.h index c2602189..ffc90c2d 100644 --- a/src/core/devices/nm-device-logging.h +++ b/src/core/devices/nm-device-logging.h @@ -11,15 +11,12 @@ #if !_NM_CC_SUPPORT_GENERIC #define _NM_DEVICE_CAST(self) ((NMDevice *) (self)) #elif !defined(_NMLOG_DEVICE_TYPE) -#define _NM_DEVICE_CAST(self) \ - _Generic((self), NMDevice * : ((NMDevice *) (self)), NMDevice *const : ((NMDevice *) (self))) +#define _NM_DEVICE_CAST(self) _Generic((self), NMDevice * : ((NMDevice *) (self))) #else -#define _NM_DEVICE_CAST(self) \ - _Generic((self), \ - _NMLOG_DEVICE_TYPE * : ((NMDevice *) (self)), \ - _NMLOG_DEVICE_TYPE * const: ((NMDevice *) (self)), \ - NMDevice * : ((NMDevice *) (self)), \ - NMDevice * const: ((NMDevice *) (self))) +#define _NM_DEVICE_CAST(self) \ + _Generic((self), _NMLOG_DEVICE_TYPE * \ + : ((NMDevice *) (self)), NMDevice * \ + : ((NMDevice *) (self))) #endif #undef _NMLOG_ENABLED diff --git a/src/core/devices/nm-device-loopback.c b/src/core/devices/nm-device-loopback.c new file mode 100644 index 00000000..ec72aa96 --- /dev/null +++ b/src/core/devices/nm-device-loopback.c @@ -0,0 +1,166 @@ +/* SPDX-License-Identifier: LGPL-2.1-or-later */ +/* + * Copyright (C) 2022 Red Hat, Inc. + */ + +#include "src/core/nm-default-daemon.h" +#include "nm-device-loopback.h" +#include "nm-device-private.h" +#include "libnm-platform/nm-platform.h" +#include "nm-device-factory.h" +#include "nm-setting-loopback.h" +#include "libnm-core-aux-intern/nm-libnm-core-utils.h" + +#define _NMLOG_DEVICE_TYPE NMDeviceLoopback +#include "nm-device-logging.h" + +/*****************************************************************************/ + +struct _NMDeviceLoopback { + NMDevice parent; +}; + +struct _NMDeviceLoopbackClass { + NMDeviceClass parent; +}; + +G_DEFINE_TYPE(NMDeviceLoopback, nm_device_loopback, NM_TYPE_DEVICE) + +/*****************************************************************************/ + +static NMDeviceCapabilities +get_generic_capabilities(NMDevice *dev) +{ + /* In many aspects, loopback is a software device. Still, don't return + * NM_DEVICE_CAP_IS_SOFTWARE here, because we cannot delete nor create + * such an interface. */ + return NM_DEVICE_CAP_NONE; +} + +static guint32 +get_configured_mtu(NMDevice *device, NMDeviceMtuSource *out_source, gboolean *out_force) +{ + return nm_device_get_configured_mtu_from_connection(device, + NM_TYPE_SETTING_LOOPBACK, + out_source); +} + +static const char * +get_auto_ip_config_method(NMDevice *device, int addr_family) +{ + return NM_IS_IPv4(addr_family) ? NM_SETTING_IP4_CONFIG_METHOD_MANUAL + : NM_SETTING_IP6_CONFIG_METHOD_MANUAL; +} + +static gboolean +complete_connection(NMDevice *device, + NMConnection *connection, + const char *specific_object, + NMConnection *const *existing_connections, + GError **error) +{ + nm_utils_complete_generic_with_params(nm_device_get_platform(device), + connection, + NM_SETTING_LOOPBACK_SETTING_NAME, + existing_connections, + NULL, + _("Loopback connection"), + NULL, + nm_device_get_ip_iface(device)); + + _nm_connection_ensure_setting(connection, NM_TYPE_SETTING_LOOPBACK); + + return TRUE; +} + +static void +update_connection(NMDevice *device, NMConnection *connection) +{ + _nm_connection_ensure_setting(connection, NM_TYPE_SETTING_LOOPBACK); +} + +static gboolean +can_reapply_change(NMDevice *device, + const char *setting_name, + NMSetting *s_old, + NMSetting *s_new, + GHashTable *diffs, + GError **error) +{ + if (!nm_streq(setting_name, NM_SETTING_LOOPBACK_SETTING_NAME)) { + return NM_DEVICE_CLASS(nm_device_loopback_parent_class) + ->can_reapply_change(device, setting_name, s_old, s_new, diffs, error); + } + + return nm_device_hash_check_invalid_keys(diffs, + NM_SETTING_LOOPBACK_SETTING_NAME, + error, + NM_SETTING_LOOPBACK_MTU); +} + +/*****************************************************************************/ + +static const NMDBusInterfaceInfoExtended interface_info_device_loopback = { + .parent = NM_DEFINE_GDBUS_INTERFACE_INFO_INIT(NM_DBUS_INTERFACE_DEVICE_LOOPBACK, ), +}; + +static void +nm_device_loopback_init(NMDeviceLoopback *self) +{} + +static void +nm_device_loopback_class_init(NMDeviceLoopbackClass *klass) +{ + NMDeviceClass *device_class = NM_DEVICE_CLASS(klass); + NMDBusObjectClass *dbus_object_class = NM_DBUS_OBJECT_CLASS(klass); + + dbus_object_class->interface_infos = NM_DBUS_INTERFACE_INFOS(&interface_info_device_loopback); + + device_class->connection_type_supported = NM_SETTING_LOOPBACK_SETTING_NAME; + device_class->connection_type_check_compatible = NM_SETTING_LOOPBACK_SETTING_NAME; + device_class->link_types = NM_DEVICE_DEFINE_LINK_TYPES(NM_LINK_TYPE_LOOPBACK); + + device_class->complete_connection = complete_connection; + device_class->get_generic_capabilities = get_generic_capabilities; + device_class->update_connection = update_connection; + device_class->act_stage1_prepare_set_hwaddr_ethernet = TRUE; + device_class->get_auto_ip_config_method = get_auto_ip_config_method; + device_class->get_configured_mtu = get_configured_mtu; + device_class->allow_autoconnect_on_external = TRUE; + device_class->can_reapply_change = can_reapply_change; +} + +/*****************************************************************************/ + +#define NM_TYPE_LOOPBACK_DEVICE_FACTORY (nm_loopback_device_factory_get_type()) +#define NM_LOOPBACK_DEVICE_FACTORY(obj) \ + (_NM_G_TYPE_CHECK_INSTANCE_CAST((obj), \ + NM_TYPE_LOOPBACK_DEVICE_FACTORY, \ + NMLoopbackDeviceFactory)) + +static NMDevice * +create_device(NMDeviceFactory *factory, + const char *iface, + const NMPlatformLink *plink, + NMConnection *connection, + gboolean *out_ignore) +{ + return g_object_new(NM_TYPE_DEVICE_LOOPBACK, + NM_DEVICE_IFACE, + iface, + NM_DEVICE_TYPE_DESC, + "Loopback", + NM_DEVICE_DEVICE_TYPE, + NM_DEVICE_TYPE_LOOPBACK, + NM_DEVICE_LINK_TYPE, + NM_LINK_TYPE_LOOPBACK, + NULL); +} + +NM_DEVICE_FACTORY_DEFINE_INTERNAL( + LOOPBACK, + Loopback, + loopback, + NM_DEVICE_FACTORY_DECLARE_LINK_TYPES(NM_LINK_TYPE_LOOPBACK) + NM_DEVICE_FACTORY_DECLARE_SETTING_TYPES(NM_SETTING_LOOPBACK_SETTING_NAME), + factory_class->create_device = create_device;); diff --git a/src/core/devices/nm-device-loopback.h b/src/core/devices/nm-device-loopback.h new file mode 100644 index 00000000..fc62a94b --- /dev/null +++ b/src/core/devices/nm-device-loopback.h @@ -0,0 +1,27 @@ +/* SPDX-License-Identifier: LGPL-2.1-or-later */ +/* + * Copyright (C) 2022 Red Hat, Inc. + */ + +#ifndef __NETWORKMANAGER_DEVICE_LOOPBACK_H__ +#define __NETWORKMANAGER_DEVICE_LOOPBACK_H__ + +#include "nm-device-generic.h" + +#define NM_TYPE_DEVICE_LOOPBACK (nm_device_loopback_get_type()) +#define NM_DEVICE_LOOPBACK(obj) \ + (_NM_G_TYPE_CHECK_INSTANCE_CAST((obj), NM_TYPE_DEVICE_LOOPBACK, NMDeviceLoopback)) +#define NM_DEVICE_LOOPBACK_CLASS(klass) \ + (G_TYPE_CHECK_CLASS_CAST((klass), NM_TYPE_DEVICE_LOOPBACK, NMDeviceLoopbackClass)) +#define NM_IS_DEVICE_LOOPBACK(obj) (G_TYPE_CHECK_INSTANCE_TYPE((obj), NM_TYPE_DEVICE_LOOPBACK)) +#define NM_IS_DEVICE_LOOPBACK_CLASS(klass) \ + (G_TYPE_CHECK_CLASS_TYPE((klass), NM_TYPE_DEVICE_LOOPBACK)) +#define NM_DEVICE_LOOPBACK_GET_CLASS(obj) \ + (G_TYPE_INSTANCE_GET_CLASS((obj), NM_TYPE_DEVICE_LOOPBACK, NMDeviceLoopbackClass)) + +typedef struct _NMDeviceLoopback NMDeviceLoopback; +typedef struct _NMDeviceLoopbackClass NMDeviceLoopbackClass; + +GType nm_device_loopback_get_type(void); + +#endif /* __NETWORKMANAGER_DEVICE_LOOPBACK_H__ */ diff --git a/src/core/devices/nm-device-macsec.c b/src/core/devices/nm-device-macsec.c index 5b1f5fdc..130708bb 100644 --- a/src/core/devices/nm-device-macsec.c +++ b/src/core/devices/nm-device-macsec.c @@ -45,7 +45,6 @@ NM_GOBJECT_PROPERTIES_DEFINE(NMDeviceMacsec, typedef struct { NMPlatformLnkMacsec props; - gulong parent_state_id; gulong parent_mtu_id; struct { @@ -92,25 +91,6 @@ static NM_UTILS_LOOKUP_STR_DEFINE(validation_mode_to_string, NM_UTILS_LOOKUP_STR_ITEM(2, "strict"), ); static void -parent_state_changed(NMDevice *parent, - NMDeviceState new_state, - NMDeviceState old_state, - NMDeviceStateReason reason, - gpointer user_data) -{ - NMDeviceMacsec *self = NM_DEVICE_MACSEC(user_data); - - /* We'll react to our own carrier state notifications. Ignore the parent's. */ - if (nm_device_state_reason_check(reason) == NM_DEVICE_STATE_REASON_CARRIER) - return; - - nm_device_set_unmanaged_by_flags(NM_DEVICE(self), - NM_UNMANAGED_PARENT, - !nm_device_get_managed(parent, FALSE), - reason); -} - -static void parent_mtu_maybe_changed(NMDevice *parent, GParamSpec *pspec, gpointer user_data) { /* the MTU of a MACsec device is limited by the parent's MTU. @@ -132,27 +112,13 @@ parent_changed_notify(NMDevice *device, NM_DEVICE_CLASS(nm_device_macsec_parent_class) ->parent_changed_notify(device, old_ifindex, old_parent, new_ifindex, new_parent); - /* note that @self doesn't have to clear @parent_state_id on dispose, - * because NMDevice's dispose() will unset the parent, which in turn calls - * parent_changed_notify(). */ - nm_clear_g_signal_handler(old_parent, &priv->parent_state_id); nm_clear_g_signal_handler(old_parent, &priv->parent_mtu_id); if (new_parent) { - priv->parent_state_id = g_signal_connect(new_parent, - NM_DEVICE_STATE_CHANGED, - G_CALLBACK(parent_state_changed), - device); - priv->parent_mtu_id = g_signal_connect(new_parent, + priv->parent_mtu_id = g_signal_connect(new_parent, "notify::" NM_DEVICE_MTU, G_CALLBACK(parent_mtu_maybe_changed), device); - - /* Set parent-dependent unmanaged flag */ - nm_device_set_unmanaged_by_flags(device, - NM_UNMANAGED_PARENT, - !nm_device_get_managed(new_parent, FALSE), - NM_DEVICE_STATE_REASON_PARENT_MANAGED_CHANGED); } /* Recheck availability now that the parent has changed */ @@ -862,7 +828,6 @@ dispose(GObject *object) G_OBJECT_CLASS(nm_device_macsec_parent_class)->dispose(object); - nm_assert(NM_DEVICE_MACSEC_GET_PRIVATE(self)->parent_state_id == 0); nm_assert(NM_DEVICE_MACSEC_GET_PRIVATE(self)->parent_mtu_id == 0); } @@ -1011,7 +976,7 @@ nm_device_macsec_class_init(NMDeviceMacsecClass *klass) #define NM_TYPE_MACSEC_DEVICE_FACTORY (nm_macsec_device_factory_get_type()) #define NM_MACSEC_DEVICE_FACTORY(obj) \ - (G_TYPE_CHECK_INSTANCE_CAST((obj), NM_TYPE_MACSEC_DEVICE_FACTORY, NMMacsecDeviceFactory)) + (_NM_G_TYPE_CHECK_INSTANCE_CAST((obj), NM_TYPE_MACSEC_DEVICE_FACTORY, NMMacsecDeviceFactory)) static NMDevice * create_device(NMDeviceFactory *factory, diff --git a/src/core/devices/nm-device-macsec.h b/src/core/devices/nm-device-macsec.h index e91fe51c..fefb773c 100644 --- a/src/core/devices/nm-device-macsec.h +++ b/src/core/devices/nm-device-macsec.h @@ -10,7 +10,7 @@ #define NM_TYPE_DEVICE_MACSEC (nm_device_macsec_get_type()) #define NM_DEVICE_MACSEC(obj) \ - (G_TYPE_CHECK_INSTANCE_CAST((obj), NM_TYPE_DEVICE_MACSEC, NMDeviceMacsec)) + (_NM_G_TYPE_CHECK_INSTANCE_CAST((obj), NM_TYPE_DEVICE_MACSEC, NMDeviceMacsec)) #define NM_DEVICE_MACSEC_CLASS(klass) \ (G_TYPE_CHECK_CLASS_CAST((klass), NM_TYPE_DEVICE_MACSEC, NMDeviceMacsecClass)) #define NM_IS_DEVICE_MACSEC(obj) (G_TYPE_CHECK_INSTANCE_TYPE((obj), NM_TYPE_DEVICE_MACSEC)) diff --git a/src/core/devices/nm-device-macvlan.c b/src/core/devices/nm-device-macvlan.c index 40ecc5fd..3f57bfb1 100644 --- a/src/core/devices/nm-device-macvlan.c +++ b/src/core/devices/nm-device-macvlan.c @@ -29,7 +29,6 @@ NM_GOBJECT_PROPERTIES_DEFINE(NMDeviceMacvlan, PROP_MODE, PROP_NO_PROMISC, PROP_TAP, ); typedef struct { - gulong parent_state_id; gulong parent_mtu_id; NMPlatformLnkMacvlan props; } NMDeviceMacvlanPrivate; @@ -103,25 +102,6 @@ platform_mode_to_string(guint mode) /*****************************************************************************/ static void -parent_state_changed(NMDevice *parent, - NMDeviceState new_state, - NMDeviceState old_state, - NMDeviceStateReason reason, - gpointer user_data) -{ - NMDeviceMacvlan *self = NM_DEVICE_MACVLAN(user_data); - - /* We'll react to our own carrier state notifications. Ignore the parent's. */ - if (nm_device_state_reason_check(reason) == NM_DEVICE_STATE_REASON_CARRIER) - return; - - nm_device_set_unmanaged_by_flags(NM_DEVICE(self), - NM_UNMANAGED_PARENT, - !nm_device_get_managed(parent, FALSE), - reason); -} - -static void parent_mtu_maybe_changed(NMDevice *parent, GParamSpec *pspec, gpointer user_data) { /* the MTU of a macvlan/macvtap device is limited by the parent's MTU. @@ -143,27 +123,13 @@ parent_changed_notify(NMDevice *device, NM_DEVICE_CLASS(nm_device_macvlan_parent_class) ->parent_changed_notify(device, old_ifindex, old_parent, new_ifindex, new_parent); - /* note that @self doesn't have to clear @parent_state_id on dispose, - * because NMDevice's dispose() will unset the parent, which in turn calls - * parent_changed_notify(). */ - nm_clear_g_signal_handler(old_parent, &priv->parent_state_id); nm_clear_g_signal_handler(old_parent, &priv->parent_mtu_id); if (new_parent) { - priv->parent_state_id = g_signal_connect(new_parent, - NM_DEVICE_STATE_CHANGED, - G_CALLBACK(parent_state_changed), - device); - priv->parent_mtu_id = g_signal_connect(new_parent, + priv->parent_mtu_id = g_signal_connect(new_parent, "notify::" NM_DEVICE_MTU, G_CALLBACK(parent_mtu_maybe_changed), device); - - /* Set parent-dependent unmanaged flag */ - nm_device_set_unmanaged_by_flags(device, - NM_UNMANAGED_PARENT, - !nm_device_get_managed(new_parent, FALSE), - NM_DEVICE_STATE_REASON_PARENT_MANAGED_CHANGED); } if (new_ifindex > 0) { @@ -490,7 +456,6 @@ dispose(GObject *object) { G_OBJECT_CLASS(nm_device_macvlan_parent_class)->dispose(object); - nm_assert(NM_DEVICE_MACVLAN_GET_PRIVATE(object)->parent_state_id == 0); nm_assert(NM_DEVICE_MACVLAN_GET_PRIVATE(object)->parent_mtu_id == 0); } #endif @@ -566,7 +531,7 @@ nm_device_macvlan_class_init(NMDeviceMacvlanClass *klass) #define NM_TYPE_MACVLAN_DEVICE_FACTORY (nm_macvlan_device_factory_get_type()) #define NM_MACVLAN_DEVICE_FACTORY(obj) \ - (G_TYPE_CHECK_INSTANCE_CAST((obj), NM_TYPE_MACVLAN_DEVICE_FACTORY, NMMacvlanDeviceFactory)) + (_NM_G_TYPE_CHECK_INSTANCE_CAST((obj), NM_TYPE_MACVLAN_DEVICE_FACTORY, NMMacvlanDeviceFactory)) static NMDevice * create_device(NMDeviceFactory *factory, diff --git a/src/core/devices/nm-device-macvlan.h b/src/core/devices/nm-device-macvlan.h index 109a2bcd..86ac79c7 100644 --- a/src/core/devices/nm-device-macvlan.h +++ b/src/core/devices/nm-device-macvlan.h @@ -10,7 +10,7 @@ #define NM_TYPE_DEVICE_MACVLAN (nm_device_macvlan_get_type()) #define NM_DEVICE_MACVLAN(obj) \ - (G_TYPE_CHECK_INSTANCE_CAST((obj), NM_TYPE_DEVICE_MACVLAN, NMDeviceMacvlan)) + (_NM_G_TYPE_CHECK_INSTANCE_CAST((obj), NM_TYPE_DEVICE_MACVLAN, NMDeviceMacvlan)) #define NM_DEVICE_MACVLAN_CLASS(klass) \ (G_TYPE_CHECK_CLASS_CAST((klass), NM_TYPE_DEVICE_MACVLAN, NMDeviceMacvlanClass)) #define NM_IS_DEVICE_MACVLAN(obj) (G_TYPE_CHECK_INSTANCE_TYPE((obj), NM_TYPE_DEVICE_MACVLAN)) diff --git a/src/core/devices/nm-device-ppp.c b/src/core/devices/nm-device-ppp.c index 6615b65e..1860df3c 100644 --- a/src/core/devices/nm-device-ppp.c +++ b/src/core/devices/nm-device-ppp.c @@ -337,7 +337,7 @@ nm_device_ppp_class_init(NMDevicePppClass *klass) #define NM_TYPE_PPP_DEVICE_FACTORY (nm_ppp_device_factory_get_type()) #define NM_PPP_DEVICE_FACTORY(obj) \ - (G_TYPE_CHECK_INSTANCE_CAST((obj), NM_TYPE_PPP_DEVICE_FACTORY, NMPppDeviceFactory)) + (_NM_G_TYPE_CHECK_INSTANCE_CAST((obj), NM_TYPE_PPP_DEVICE_FACTORY, NMPppDeviceFactory)) static NMDevice * create_device(NMDeviceFactory *factory, diff --git a/src/core/devices/nm-device-ppp.h b/src/core/devices/nm-device-ppp.h index 24c119ab..0e8ca54a 100644 --- a/src/core/devices/nm-device-ppp.h +++ b/src/core/devices/nm-device-ppp.h @@ -7,7 +7,7 @@ #define __NETWORKMANAGER_DEVICE_PPP_H__ #define NM_TYPE_DEVICE_PPP (nm_device_ppp_get_type()) -#define NM_DEVICE_PPP(obj) (G_TYPE_CHECK_INSTANCE_CAST((obj), NM_TYPE_DEVICE_PPP, NMDevicePpp)) +#define NM_DEVICE_PPP(obj) (_NM_G_TYPE_CHECK_INSTANCE_CAST((obj), NM_TYPE_DEVICE_PPP, NMDevicePpp)) #define NM_DEVICE_PPP_CLASS(klass) \ (G_TYPE_CHECK_CLASS_CAST((klass), NM_TYPE_DEVICE_PPP, NMDevicePppClass)) #define NM_IS_DEVICE_PPP(obj) (G_TYPE_CHECK_INSTANCE_TYPE((obj), NM_TYPE_DEVICE_PPP)) diff --git a/src/core/devices/nm-device-tun.c b/src/core/devices/nm-device-tun.c index e623e9c0..cbea7d7d 100644 --- a/src/core/devices/nm-device-tun.c +++ b/src/core/devices/nm-device-tun.c @@ -527,7 +527,7 @@ nm_device_tun_class_init(NMDeviceTunClass *klass) #define NM_TYPE_TUN_DEVICE_FACTORY (nm_tun_device_factory_get_type()) #define NM_TUN_DEVICE_FACTORY(obj) \ - (G_TYPE_CHECK_INSTANCE_CAST((obj), NM_TYPE_TUN_DEVICE_FACTORY, NMTunDeviceFactory)) + (_NM_G_TYPE_CHECK_INSTANCE_CAST((obj), NM_TYPE_TUN_DEVICE_FACTORY, NMTunDeviceFactory)) static NMDevice * create_device(NMDeviceFactory *factory, diff --git a/src/core/devices/nm-device-tun.h b/src/core/devices/nm-device-tun.h index 84497ea0..866d6c4f 100644 --- a/src/core/devices/nm-device-tun.h +++ b/src/core/devices/nm-device-tun.h @@ -9,7 +9,7 @@ #include "nm-device-generic.h" #define NM_TYPE_DEVICE_TUN (nm_device_tun_get_type()) -#define NM_DEVICE_TUN(obj) (G_TYPE_CHECK_INSTANCE_CAST((obj), NM_TYPE_DEVICE_TUN, NMDeviceTun)) +#define NM_DEVICE_TUN(obj) (_NM_G_TYPE_CHECK_INSTANCE_CAST((obj), NM_TYPE_DEVICE_TUN, NMDeviceTun)) #define NM_DEVICE_TUN_CLASS(klass) \ (G_TYPE_CHECK_CLASS_CAST((klass), NM_TYPE_DEVICE_TUN, NMDeviceTunClass)) #define NM_IS_DEVICE_TUN(obj) (G_TYPE_CHECK_INSTANCE_TYPE((obj), NM_TYPE_DEVICE_TUN)) diff --git a/src/core/devices/nm-device-utils.c b/src/core/devices/nm-device-utils.c index 170922eb..2bf24ae6 100644 --- a/src/core/devices/nm-device-utils.c +++ b/src/core/devices/nm-device-utils.c @@ -171,25 +171,25 @@ typedef struct { #define _NMLOG_PREFIX_NAME "resolve-addr" #define _NMLOG_DOMAIN LOGD_CORE -#define _NMLOG2(level, info, ...) \ - G_STMT_START \ - { \ - if (nm_logging_enabled((level), (_NMLOG_DOMAIN))) { \ - ResolveAddrInfo *_info = (info); \ - char _addr_str[NM_UTILS_INET_ADDRSTRLEN]; \ - \ - _nm_log((level), \ - (_NMLOG_DOMAIN), \ - 0, \ - NULL, \ - NULL, \ - _NMLOG_PREFIX_NAME "[" NM_HASH_OBFUSCATE_PTR_FMT \ - ",%s]: " _NM_UTILS_MACRO_FIRST(__VA_ARGS__), \ - NM_HASH_OBFUSCATE_PTR(_info), \ - nm_utils_inet_ntop(_info->addr_family, &_info->address, _addr_str) \ - _NM_UTILS_MACRO_REST(__VA_ARGS__)); \ - } \ - } \ +#define _NMLOG2(level, info, ...) \ + G_STMT_START \ + { \ + if (nm_logging_enabled((level), (_NMLOG_DOMAIN))) { \ + ResolveAddrInfo *_info = (info); \ + char _addr_str[NM_INET_ADDRSTRLEN]; \ + \ + _nm_log((level), \ + (_NMLOG_DOMAIN), \ + 0, \ + NULL, \ + NULL, \ + _NMLOG_PREFIX_NAME "[" NM_HASH_OBFUSCATE_PTR_FMT \ + ",%s]: " _NM_UTILS_MACRO_FIRST(__VA_ARGS__), \ + NM_HASH_OBFUSCATE_PTR(_info), \ + nm_inet_ntop(_info->addr_family, &_info->address, _addr_str) \ + _NM_UTILS_MACRO_REST(__VA_ARGS__)); \ + } \ + } \ G_STMT_END static void @@ -234,9 +234,9 @@ resolve_addr_helper_cb(GObject *source, GAsyncResult *result, gpointer user_data static void resolve_addr_spawn_helper(ResolveAddrInfo *info) { - char addr_str[NM_UTILS_INET_ADDRSTRLEN]; + char addr_str[NM_INET_ADDRSTRLEN]; - nm_utils_inet_ntop(info->addr_family, &info->address, addr_str); + nm_inet_ntop(info->addr_family, &info->address, addr_str); _LOG2D(info, "start lookup via nm-daemon-helper"); nm_utils_spawn_helper(NM_MAKE_STRV("resolve-address", addr_str), g_task_get_cancellable(info->task), diff --git a/src/core/devices/nm-device-veth.c b/src/core/devices/nm-device-veth.c index 17115d33..c4b9e234 100644 --- a/src/core/devices/nm-device-veth.c +++ b/src/core/devices/nm-device-veth.c @@ -215,7 +215,7 @@ nm_device_veth_class_init(NMDeviceVethClass *klass) #define NM_TYPE_VETH_DEVICE_FACTORY (nm_veth_device_factory_get_type()) #define NM_VETH_DEVICE_FACTORY(obj) \ - (G_TYPE_CHECK_INSTANCE_CAST((obj), NM_TYPE_VETH_DEVICE_FACTORY, NMVethDeviceFactory)) + (_NM_G_TYPE_CHECK_INSTANCE_CAST((obj), NM_TYPE_VETH_DEVICE_FACTORY, NMVethDeviceFactory)) static NMDevice * create_device(NMDeviceFactory *factory, diff --git a/src/core/devices/nm-device-veth.h b/src/core/devices/nm-device-veth.h index d43a0a4b..39182363 100644 --- a/src/core/devices/nm-device-veth.h +++ b/src/core/devices/nm-device-veth.h @@ -9,7 +9,8 @@ #include "nm-device-ethernet.h" #define NM_TYPE_DEVICE_VETH (nm_device_veth_get_type()) -#define NM_DEVICE_VETH(obj) (G_TYPE_CHECK_INSTANCE_CAST((obj), NM_TYPE_DEVICE_VETH, NMDeviceVeth)) +#define NM_DEVICE_VETH(obj) \ + (_NM_G_TYPE_CHECK_INSTANCE_CAST((obj), NM_TYPE_DEVICE_VETH, NMDeviceVeth)) #define NM_DEVICE_VETH_CLASS(klass) \ (G_TYPE_CHECK_CLASS_CAST((klass), NM_TYPE_DEVICE_VETH, NMDeviceVethClass)) #define NM_IS_DEVICE_VETH(obj) (G_TYPE_CHECK_INSTANCE_TYPE((obj), NM_TYPE_DEVICE_VETH)) diff --git a/src/core/devices/nm-device-vlan.c b/src/core/devices/nm-device-vlan.c index 0c101c70..feb011db 100644 --- a/src/core/devices/nm-device-vlan.c +++ b/src/core/devices/nm-device-vlan.c @@ -8,6 +8,7 @@ #include "nm-device-vlan.h" #include <sys/socket.h> +#include <linux/if_ether.h> #include "nm-manager.h" #include "nm-utils.h" @@ -31,7 +32,6 @@ NM_GOBJECT_PROPERTIES_DEFINE(NMDeviceVlan, PROP_VLAN_ID, ); typedef struct { - gulong parent_state_id; gulong parent_hwaddr_id; gulong parent_mtu_id; guint vlan_id; @@ -54,25 +54,6 @@ G_DEFINE_TYPE(NMDeviceVlan, nm_device_vlan, NM_TYPE_DEVICE) /*****************************************************************************/ static void -parent_state_changed(NMDevice *parent, - NMDeviceState new_state, - NMDeviceState old_state, - NMDeviceStateReason reason, - gpointer user_data) -{ - NMDeviceVlan *self = NM_DEVICE_VLAN(user_data); - - /* We'll react to our own carrier state notifications. Ignore the parent's. */ - if (nm_device_state_reason_check(reason) == NM_DEVICE_STATE_REASON_CARRIER) - return; - - nm_device_set_unmanaged_by_flags(NM_DEVICE(self), - NM_UNMANAGED_PARENT, - !nm_device_get_managed(parent, FALSE), - reason); -} - -static void parent_mtu_maybe_changed(NMDevice *parent, GParamSpec *pspec, gpointer user_data) { /* the MTU of a VLAN device is limited by the parent's MTU. @@ -132,19 +113,10 @@ parent_changed_notify(NMDevice *device, NM_DEVICE_CLASS(nm_device_vlan_parent_class) ->parent_changed_notify(device, old_ifindex, old_parent, new_ifindex, new_parent); - /* note that @self doesn't have to clear @parent_state_id on dispose, - * because NMDevice's dispose() will unset the parent, which in turn calls - * parent_changed_notify(). */ - nm_clear_g_signal_handler(old_parent, &priv->parent_state_id); nm_clear_g_signal_handler(old_parent, &priv->parent_hwaddr_id); nm_clear_g_signal_handler(old_parent, &priv->parent_mtu_id); if (new_parent) { - priv->parent_state_id = g_signal_connect(new_parent, - NM_DEVICE_STATE_CHANGED, - G_CALLBACK(parent_state_changed), - device); - priv->parent_hwaddr_id = g_signal_connect(new_parent, "notify::" NM_DEVICE_HW_ADDRESS, G_CALLBACK(parent_hwaddr_maybe_changed), @@ -156,12 +128,6 @@ parent_changed_notify(NMDevice *device, G_CALLBACK(parent_mtu_maybe_changed), device); parent_mtu_maybe_changed(new_parent, NULL, self); - - /* Set parent-dependent unmanaged flag */ - nm_device_set_unmanaged_by_flags(device, - NM_UNMANAGED_PARENT, - !nm_device_get_managed(new_parent, FALSE), - NM_DEVICE_STATE_REASON_PARENT_MANAGED_CHANGED); } /* Recheck availability now that the parent has changed */ @@ -227,6 +193,8 @@ create_and_realize(NMDevice *device, int parent_ifindex; guint vlan_id; int r; + const char *protocol_str; + guint16 protocol = ETH_P_8021Q; s_vlan = nm_connection_get_setting_vlan(connection); g_assert(s_vlan); @@ -262,11 +230,22 @@ create_and_realize(NMDevice *device, vlan_id = nm_setting_vlan_get_id(s_vlan); + protocol_str = nm_setting_vlan_get_protocol(s_vlan); + if (protocol_str) { + if (nm_streq(protocol_str, "802.1ad")) + protocol = ETH_P_8021AD; + else + nm_assert(nm_streq(protocol_str, "802.1Q")); + } + r = nm_platform_link_vlan_add(nm_device_get_platform(device), iface, parent_ifindex, - vlan_id, - nm_setting_vlan_get_flags(s_vlan), + &((NMPlatformLnkVlan){ + .id = vlan_id, + .flags = nm_setting_vlan_get_flags(s_vlan), + .protocol = protocol, + }), out_plink); if (r < 0) { g_set_error(error, @@ -473,6 +452,9 @@ update_connection(NMDevice *device, NMConnection *connection) _nm_setting_vlan_set_priorities(s_vlan, NM_VLAN_INGRESS_MAP, NULL, 0); _nm_setting_vlan_set_priorities(s_vlan, NM_VLAN_EGRESS_MAP, NULL, 0); } + + if (polnk && polnk->lnk_vlan.protocol == ETH_P_8021AD) + g_object_set(s_vlan, NM_SETTING_VLAN_PROTOCOL, "802.1ad", NULL); } static NMActStageReturn @@ -592,7 +574,7 @@ nm_device_vlan_class_init(NMDeviceVlanClass *klass) #define NM_TYPE_VLAN_DEVICE_FACTORY (nm_vlan_device_factory_get_type()) #define NM_VLAN_DEVICE_FACTORY(obj) \ - (G_TYPE_CHECK_INSTANCE_CAST((obj), NM_TYPE_VLAN_DEVICE_FACTORY, NMVlanDeviceFactory)) + (_NM_G_TYPE_CHECK_INSTANCE_CAST((obj), NM_TYPE_VLAN_DEVICE_FACTORY, NMVlanDeviceFactory)) static NMDevice * create_device(NMDeviceFactory *factory, diff --git a/src/core/devices/nm-device-vlan.h b/src/core/devices/nm-device-vlan.h index 5270706f..06fef5cf 100644 --- a/src/core/devices/nm-device-vlan.h +++ b/src/core/devices/nm-device-vlan.h @@ -9,7 +9,8 @@ #include "nm-device.h" #define NM_TYPE_DEVICE_VLAN (nm_device_vlan_get_type()) -#define NM_DEVICE_VLAN(obj) (G_TYPE_CHECK_INSTANCE_CAST((obj), NM_TYPE_DEVICE_VLAN, NMDeviceVlan)) +#define NM_DEVICE_VLAN(obj) \ + (_NM_G_TYPE_CHECK_INSTANCE_CAST((obj), NM_TYPE_DEVICE_VLAN, NMDeviceVlan)) #define NM_DEVICE_VLAN_CLASS(klass) \ (G_TYPE_CHECK_CLASS_CAST((klass), NM_TYPE_DEVICE_VLAN, NMDeviceVlanClass)) #define NM_IS_DEVICE_VLAN(obj) (G_TYPE_CHECK_INSTANCE_TYPE((obj), NM_TYPE_DEVICE_VLAN)) diff --git a/src/core/devices/nm-device-vrf.c b/src/core/devices/nm-device-vrf.c index 91eb195a..ad31f3a2 100644 --- a/src/core/devices/nm-device-vrf.c +++ b/src/core/devices/nm-device-vrf.c @@ -347,7 +347,7 @@ nm_device_vrf_class_init(NMDeviceVrfClass *klass) #define NM_TYPE_VRF_DEVICE_FACTORY (nm_vrf_device_factory_get_type()) #define NM_VRF_DEVICE_FACTORY(obj) \ - (G_TYPE_CHECK_INSTANCE_CAST((obj), NM_TYPE_VRF_DEVICE_FACTORY, NMVrfDeviceFactory)) + (_NM_G_TYPE_CHECK_INSTANCE_CAST((obj), NM_TYPE_VRF_DEVICE_FACTORY, NMVrfDeviceFactory)) static NMDevice * create_device(NMDeviceFactory *factory, diff --git a/src/core/devices/nm-device-vrf.h b/src/core/devices/nm-device-vrf.h index 5169041c..c6580fb8 100644 --- a/src/core/devices/nm-device-vrf.h +++ b/src/core/devices/nm-device-vrf.h @@ -6,7 +6,7 @@ #include "nm-device-generic.h" #define NM_TYPE_DEVICE_VRF (nm_device_vrf_get_type()) -#define NM_DEVICE_VRF(obj) (G_TYPE_CHECK_INSTANCE_CAST((obj), NM_TYPE_DEVICE_VRF, NMDeviceVrf)) +#define NM_DEVICE_VRF(obj) (_NM_G_TYPE_CHECK_INSTANCE_CAST((obj), NM_TYPE_DEVICE_VRF, NMDeviceVrf)) #define NM_DEVICE_VRF_CLASS(klass) \ (G_TYPE_CHECK_CLASS_CAST((klass), NM_TYPE_DEVICE_VRF, NMDeviceVrfClass)) #define NM_IS_DEVICE_VRF(obj) (G_TYPE_CHECK_INSTANCE_TYPE((obj), NM_TYPE_DEVICE_VRF)) diff --git a/src/core/devices/nm-device-vxlan.c b/src/core/devices/nm-device-vxlan.c index bf7c94c0..44a7be33 100644 --- a/src/core/devices/nm-device-vxlan.c +++ b/src/core/devices/nm-device-vxlan.c @@ -174,15 +174,15 @@ create_and_realize(NMDevice *device, str = nm_setting_vxlan_get_local(s_vxlan); if (str) { - if (!nm_utils_parse_inaddr_bin(AF_INET, str, NULL, &props.local) - && !nm_utils_parse_inaddr_bin(AF_INET6, str, NULL, &props.local6)) + if (!nm_inet_parse_bin(AF_INET, str, NULL, &props.local) + && !nm_inet_parse_bin(AF_INET6, str, NULL, &props.local6)) return FALSE; } str = nm_setting_vxlan_get_remote(s_vxlan); if (str) { - if (!nm_utils_parse_inaddr_bin(AF_INET, str, NULL, &props.group) - && !nm_utils_parse_inaddr_bin(AF_INET6, str, NULL, &props.group6)) + if (!nm_inet_parse_bin(AF_INET, str, NULL, &props.group) + && !nm_inet_parse_bin(AF_INET6, str, NULL, &props.group6)) return FALSE; } @@ -223,7 +223,7 @@ address_matches(const char *candidate, in_addr_t addr4, struct in6_addr *addr6) if (!candidate) return addr4 == 0u && IN6_IS_ADDR_UNSPECIFIED(addr6); - if (!nm_utils_parse_inaddr_bin(AF_UNSPEC, candidate, &addr_family, &candidate_addr)) + if (!nm_inet_parse_bin(AF_UNSPEC, candidate, &addr_family, &candidate_addr)) return FALSE; if (!nm_ip_addr_equal(addr_family, @@ -401,7 +401,7 @@ update_connection(NMDevice *device, NMConnection *connection) { NMDeviceVxlanPrivate *priv = NM_DEVICE_VXLAN_GET_PRIVATE(device); NMSettingVxlan *s_vxlan = _nm_connection_ensure_setting(connection, NM_TYPE_SETTING_VXLAN); - char sbuf[NM_UTILS_INET_ADDRSTRLEN]; + char sbuf[NM_INET_ADDRSTRLEN]; if (priv->props.id != nm_setting_vxlan_get_id(s_vxlan)) g_object_set(G_OBJECT(s_vxlan), NM_SETTING_VXLAN_ID, priv->props.id, NULL); @@ -417,12 +417,12 @@ update_connection(NMDevice *device, NMConnection *connection) if (priv->props.group) { g_object_set(s_vxlan, NM_SETTING_VXLAN_REMOTE, - _nm_utils_inet4_ntop(priv->props.group, sbuf), + nm_inet4_ntop(priv->props.group, sbuf), NULL); } else { g_object_set(s_vxlan, NM_SETTING_VXLAN_REMOTE, - _nm_utils_inet6_ntop(&priv->props.group6, sbuf), + nm_inet6_ntop(&priv->props.group6, sbuf), NULL); } } @@ -433,12 +433,12 @@ update_connection(NMDevice *device, NMConnection *connection) if (priv->props.local) { g_object_set(s_vxlan, NM_SETTING_VXLAN_LOCAL, - _nm_utils_inet4_ntop(priv->props.local, sbuf), + nm_inet4_ntop(priv->props.local, sbuf), NULL); } else if (memcmp(&priv->props.local6, &in6addr_any, sizeof(in6addr_any))) { g_object_set(s_vxlan, NM_SETTING_VXLAN_LOCAL, - _nm_utils_inet6_ntop(&priv->props.local6, sbuf), + nm_inet6_ntop(&priv->props.local6, sbuf), NULL); } } @@ -510,15 +510,15 @@ get_property(GObject *object, guint prop_id, GValue *value, GParamSpec *pspec) break; case PROP_GROUP: if (priv->props.group) - g_value_take_string(value, nm_utils_inet4_ntop_dup(priv->props.group)); + g_value_take_string(value, nm_inet4_ntop_dup(priv->props.group)); else if (!IN6_IS_ADDR_UNSPECIFIED(&priv->props.group6)) - g_value_take_string(value, nm_utils_inet6_ntop_dup(&priv->props.group6)); + g_value_take_string(value, nm_inet6_ntop_dup(&priv->props.group6)); break; case PROP_LOCAL: if (priv->props.local) - g_value_take_string(value, nm_utils_inet4_ntop_dup(priv->props.local)); + g_value_take_string(value, nm_inet4_ntop_dup(priv->props.local)); else if (!IN6_IS_ADDR_UNSPECIFIED(&priv->props.local6)) - g_value_take_string(value, nm_utils_inet6_ntop_dup(&priv->props.local6)); + g_value_take_string(value, nm_inet6_ntop_dup(&priv->props.local6)); break; case PROP_TOS: g_value_set_uchar(value, priv->props.tos); @@ -741,7 +741,7 @@ nm_device_vxlan_class_init(NMDeviceVxlanClass *klass) #define NM_TYPE_VXLAN_DEVICE_FACTORY (nm_vxlan_device_factory_get_type()) #define NM_VXLAN_DEVICE_FACTORY(obj) \ - (G_TYPE_CHECK_INSTANCE_CAST((obj), NM_TYPE_VXLAN_DEVICE_FACTORY, NMVxlanDeviceFactory)) + (_NM_G_TYPE_CHECK_INSTANCE_CAST((obj), NM_TYPE_VXLAN_DEVICE_FACTORY, NMVxlanDeviceFactory)) static NMDevice * create_device(NMDeviceFactory *factory, diff --git a/src/core/devices/nm-device-vxlan.h b/src/core/devices/nm-device-vxlan.h index 4c4165e5..e53ae82e 100644 --- a/src/core/devices/nm-device-vxlan.h +++ b/src/core/devices/nm-device-vxlan.h @@ -10,7 +10,7 @@ #define NM_TYPE_DEVICE_VXLAN (nm_device_vxlan_get_type()) #define NM_DEVICE_VXLAN(obj) \ - (G_TYPE_CHECK_INSTANCE_CAST((obj), NM_TYPE_DEVICE_VXLAN, NMDeviceVxlan)) + (_NM_G_TYPE_CHECK_INSTANCE_CAST((obj), NM_TYPE_DEVICE_VXLAN, NMDeviceVxlan)) #define NM_DEVICE_VXLAN_CLASS(klass) \ (G_TYPE_CHECK_CLASS_CAST((klass), NM_TYPE_DEVICE_VXLAN, NMDeviceVxlanClass)) #define NM_IS_DEVICE_VXLAN(obj) (G_TYPE_CHECK_INSTANCE_TYPE((obj), NM_TYPE_DEVICE_VXLAN)) diff --git a/src/core/devices/nm-device-wireguard.c b/src/core/devices/nm-device-wireguard.c index 179c2a22..db02033d 100644 --- a/src/core/devices/nm-device-wireguard.c +++ b/src/core/devices/nm-device-wireguard.c @@ -219,7 +219,7 @@ _auto_default_route_get_enabled(NMSettingWireGuard *s_wg, 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)) + if (!nm_inet_parse_with_prefix_bin(AF_UNSPEC, aip, &addr_family, NULL, &prefix)) continue; if (prefix != 0) continue; @@ -1152,11 +1152,11 @@ _peers_get_platform_list(NMDeviceWireGuardPrivate *priv, aip = nm_wireguard_peer_get_allowed_ip(peer_data->peer, i_aip, &valid); if (!valid - || !nm_utils_parse_inaddr_prefix_bin(AF_UNSPEC, - aip, - &addr_family, - &addrbin, - &prefix)) { + || !nm_inet_parse_with_prefix_bin(AF_UNSPEC, + aip, + &addr_family, + &addrbin, + &prefix)) { /* the address is really not expected to be invalid, because then * the connection would not verify. Anyway, silently skip it. */ continue; @@ -1197,7 +1197,7 @@ skip: nm_assert(plp->_construct_idx_start < plp->_construct_idx_end); l = plp->_construct_idx_end - plp->_construct_idx_start; plp->allowed_ips = - &g_array_index(allowed_ips, NMPWireGuardAllowedIP, plp->_construct_idx_start); + &nm_g_array_index(allowed_ips, NMPWireGuardAllowedIP, plp->_construct_idx_start); plp->allowed_ips_len = l; } } @@ -1701,8 +1701,7 @@ _get_dev2_ip_config(NMDeviceWireGuard *self, int addr_family) aip = nm_wireguard_peer_get_allowed_ip(peer, j, &valid); - if (!valid - || !nm_utils_parse_inaddr_prefix_bin(addr_family, aip, NULL, &addrbin, &prefix)) + if (!valid || !nm_inet_parse_with_prefix_bin(addr_family, aip, NULL, &addrbin, &prefix)) continue; if (prefix < 0) @@ -1722,7 +1721,7 @@ _get_dev2_ip_config(NMDeviceWireGuard *self, int addr_family) NM_L3_CONFIG_DAT_FLAGS_IGNORE_MERGE_NO_DEFAULT_ROUTES); } - nm_utils_ipx_address_clear_host_address(addr_family, &addrbin, NULL, prefix); + nm_ip_addr_clear_host_address(addr_family, &addrbin, NULL, prefix); rtable_coerced = route_table_coerced; @@ -2062,8 +2061,10 @@ nm_device_wireguard_class_init(NMDeviceWireGuardClass *klass) /*************************************************************/ #define NM_TYPE_WIREGUARD_DEVICE_FACTORY (nm_wireguard_device_factory_get_type()) -#define NM_WIREGUARD_DEVICE_FACTORY(obj) \ - (G_TYPE_CHECK_INSTANCE_CAST((obj), NM_TYPE_WIREGUARD_DEVICE_FACTORY, NMWireGuardDeviceFactory)) +#define NM_WIREGUARD_DEVICE_FACTORY(obj) \ + (_NM_G_TYPE_CHECK_INSTANCE_CAST((obj), \ + NM_TYPE_WIREGUARD_DEVICE_FACTORY, \ + NMWireGuardDeviceFactory)) static NMDevice * create_device(NMDeviceFactory *factory, diff --git a/src/core/devices/nm-device-wireguard.h b/src/core/devices/nm-device-wireguard.h index 7e18bdba..8fb8f8cf 100644 --- a/src/core/devices/nm-device-wireguard.h +++ b/src/core/devices/nm-device-wireguard.h @@ -10,7 +10,7 @@ #define NM_TYPE_DEVICE_WIREGUARD (nm_device_wireguard_get_type()) #define NM_DEVICE_WIREGUARD(obj) \ - (G_TYPE_CHECK_INSTANCE_CAST((obj), NM_TYPE_DEVICE_WIREGUARD, NMDeviceWireGuard)) + (_NM_G_TYPE_CHECK_INSTANCE_CAST((obj), NM_TYPE_DEVICE_WIREGUARD, NMDeviceWireGuard)) #define NM_DEVICE_WIREGUARD_CLASS(klass) \ (G_TYPE_CHECK_CLASS_CAST((klass), NM_TYPE_DEVICE_WIREGUARD, NMDeviceWireGuardClass)) #define NM_IS_DEVICE_WIREGUARD(obj) (G_TYPE_CHECK_INSTANCE_TYPE((obj), NM_TYPE_DEVICE_WIREGUARD)) diff --git a/src/core/devices/nm-device-wpan.c b/src/core/devices/nm-device-wpan.c index ecb5ee23..98356ccf 100644 --- a/src/core/devices/nm-device-wpan.c +++ b/src/core/devices/nm-device-wpan.c @@ -221,7 +221,7 @@ nm_device_wpan_class_init(NMDeviceWpanClass *klass) #define NM_TYPE_WPAN_DEVICE_FACTORY (nm_wpan_device_factory_get_type()) #define NM_WPAN_DEVICE_FACTORY(obj) \ - (G_TYPE_CHECK_INSTANCE_CAST((obj), NM_TYPE_WPAN_DEVICE_FACTORY, NMWpanDeviceFactory)) + (_NM_G_TYPE_CHECK_INSTANCE_CAST((obj), NM_TYPE_WPAN_DEVICE_FACTORY, NMWpanDeviceFactory)) static NMDevice * create_device(NMDeviceFactory *factory, diff --git a/src/core/devices/nm-device-wpan.h b/src/core/devices/nm-device-wpan.h index 969929ae..39cf4656 100644 --- a/src/core/devices/nm-device-wpan.h +++ b/src/core/devices/nm-device-wpan.h @@ -7,7 +7,8 @@ #define __NETWORKMANAGER_DEVICE_WPAN_H__ #define NM_TYPE_DEVICE_WPAN (nm_device_wpan_get_type()) -#define NM_DEVICE_WPAN(obj) (G_TYPE_CHECK_INSTANCE_CAST((obj), NM_TYPE_DEVICE_WPAN, NMDeviceWpan)) +#define NM_DEVICE_WPAN(obj) \ + (_NM_G_TYPE_CHECK_INSTANCE_CAST((obj), NM_TYPE_DEVICE_WPAN, NMDeviceWpan)) #define NM_DEVICE_WPAN_CLASS(klass) \ (G_TYPE_CHECK_CLASS_CAST((klass), NM_TYPE_DEVICE_WPAN, NMDeviceWpanClass)) #define NM_IS_DEVICE_WPAN(obj) (G_TYPE_CHECK_INSTANCE_TYPE((obj), NM_TYPE_DEVICE_WPAN)) diff --git a/src/core/devices/nm-device.c b/src/core/devices/nm-device.c index c4f0f9a2..04478614 100644 --- a/src/core/devices/nm-device.c +++ b/src/core/devices/nm-device.c @@ -18,7 +18,7 @@ #include <netinet/in.h> #include <netinet/if_ether.h> #include <linux/if.h> -#include <linux/if_addr.h> +#include "nm-compat-headers/linux/if_addr.h" #include <linux/rtnetlink.h> #include <linux/if_ether.h> #include <linux/if_infiniband.h> @@ -59,6 +59,7 @@ #include "settings/nm-settings.h" #include "nm-setting-ethtool.h" #include "nm-setting-ovs-external-ids.h" +#include "nm-setting-ovs-other-config.h" #include "nm-setting-user.h" #include "nm-auth-utils.h" #include "nm-keep-alive.h" @@ -77,6 +78,7 @@ #include "nm-device-generic.h" #include "nm-device-bridge.h" +#include "nm-device-loopback.h" #include "nm-device-vlan.h" #include "nm-device-vrf.h" #include "nm-device-wireguard.h" @@ -110,6 +112,7 @@ typedef enum { CLEANUP_TYPE_KEEP, CLEANUP_TYPE_REMOVED, CLEANUP_TYPE_DECONFIGURE, + CLEANUP_TYPE_KEEP_REAPPLY, } CleanupType; typedef enum _nm_packed { @@ -848,7 +851,7 @@ static void _dev_ipshared4_spawn_dnsmasq(NMDevice *self); static void _dev_ipshared6_start(NMDevice *self); static void -_cleanup_ip_pre(NMDevice *self, int addr_family, CleanupType cleanup_type, gboolean from_reapply); +_cleanup_ip_pre(NMDevice *self, int addr_family, CleanupType cleanup_type, gboolean preserve_dhcp); static void concheck_update_state(NMDevice *self, int addr_family, @@ -1583,6 +1586,9 @@ _prop_get_ipv4_link_local(NMDevice *self) if (!s_ip4) return NM_SETTING_IP4_LL_DISABLED; + if (NM_IS_DEVICE_LOOPBACK(self)) + return NM_SETTING_IP4_LL_DISABLED; + link_local = nm_setting_ip4_config_get_link_local(s_ip4); if (link_local == NM_SETTING_IP4_LL_DEFAULT) { @@ -2736,12 +2742,6 @@ _ethtool_state_set(NMDevice *self) /*****************************************************************************/ -static gboolean -is_loopback(NMDevice *self) -{ - return NM_IS_DEVICE_GENERIC(self) && NM_DEVICE_GET_PRIVATE(self)->ifindex == 1; -} - gboolean nm_device_is_vpn(NMDevice *self) { @@ -3578,7 +3578,7 @@ _dev_ip_state_check_async(NMDevice *self, int addr_family) } static void -_dev_ip_state_cleanup(NMDevice *self, int addr_family, gboolean from_reapply) +_dev_ip_state_cleanup(NMDevice *self, int addr_family, gboolean keep_reapply) { NMDevicePrivate *priv = NM_DEVICE_GET_PRIVATE(self); int IS_IPv4; @@ -3586,7 +3586,7 @@ _dev_ip_state_cleanup(NMDevice *self, int addr_family, gboolean from_reapply) if (addr_family == AF_UNSPEC) { _dev_ip_state_set_state(self, addr_family, - from_reapply ? NM_DEVICE_IP_STATE_PENDING : NM_DEVICE_IP_STATE_NONE, + keep_reapply ? NM_DEVICE_IP_STATE_PENDING : NM_DEVICE_IP_STATE_NONE, "ip-state-clear"); return; } @@ -3597,7 +3597,7 @@ _dev_ip_state_cleanup(NMDevice *self, int addr_family, gboolean from_reapply) nm_clear_g_source_inst(&priv->ip_data_x[IS_IPv4].req_timeout_source); _dev_ip_state_set_state(self, addr_family, - from_reapply ? NM_DEVICE_IP_STATE_PENDING : NM_DEVICE_IP_STATE_NONE, + keep_reapply ? NM_DEVICE_IP_STATE_PENDING : NM_DEVICE_IP_STATE_NONE, "ip-state-clear"); priv->ip_data_x[IS_IPv4].wait_for_carrier = FALSE; priv->ip_data_x[IS_IPv4].wait_for_ports = FALSE; @@ -4129,18 +4129,30 @@ _dev_l3_cfg_notify_cb(NML3Cfg *l3cfg, const NML3ConfigNotifyData *notify_data, N /* Check if AC6 addresses completed DAD */ if (NM_FLAGS_ANY(notify_data->platform_change_on_idle.obj_type_flags, nmp_object_type_to_flags(NMP_OBJECT_TYPE_IP6_ADDRESS)) - && priv->ipac6_data.state == NM_DEVICE_IP_STATE_PENDING && priv->ipac6_data.l3cd - && nm_l3cfg_check_ready(l3cfg, - priv->ipac6_data.l3cd, - AF_INET6, - NM_L3CFG_CHECK_READY_FLAGS_IP6_DAD_READY, - NULL)) { - if (nm_l3cfg_has_temp_not_available_obj(priv->l3cfg, AF_INET6)) - _dev_l3_cfg_commit(self, FALSE); - - nm_clear_l3cd(&priv->ipac6_data.l3cd); - _dev_ipac6_set_state(self, NM_DEVICE_IP_STATE_READY); - _dev_ip_state_check_async(self, AF_INET6); + && priv->ipac6_data.state == NM_DEVICE_IP_STATE_PENDING && priv->ipac6_data.l3cd) { + gs_unref_array GArray *conflicts = NULL; + gboolean ready; + + ready = nm_l3cfg_check_ready(l3cfg, + priv->ipac6_data.l3cd, + AF_INET6, + NM_L3CFG_CHECK_READY_FLAGS_IP6_DAD_READY, + &conflicts); + if (conflicts) { + /* nm_ndisc_dad_failed() will emit a new "NDisc:config-received" + * signal; _dev_ipac6_ndisc_config_changed() will be called + * synchronously to update the current state and schedule a commit. */ + nm_ndisc_dad_failed(priv->ipac6_data.ndisc, conflicts, TRUE); + } else if (ready) { + if (nm_l3cfg_has_temp_not_available_obj(priv->l3cfg, AF_INET6)) + _dev_l3_cfg_commit(self, FALSE); + + nm_clear_l3cd(&priv->ipac6_data.l3cd); + _dev_ipac6_set_state(self, NM_DEVICE_IP_STATE_READY); + _dev_ip_state_check_async(self, AF_INET6); + } else { + /* wait */ + } } _dev_ipmanual_check_ready(self); @@ -5005,6 +5017,9 @@ nm_device_get_route_metric_default(NMDeviceType device_type) */ switch (device_type) { + case NM_DEVICE_TYPE_LOOPBACK: + return 30; + /* 50 is also used for VPN plugins (NM_VPN_ROUTE_METRIC_DEFAULT). * * Note that returning 50 from this function means that this device-type is @@ -5425,7 +5440,7 @@ concheck_is_possible(NMDevice *self) { NMDevicePrivate *priv = NM_DEVICE_GET_PRIVATE(self); - if (!nm_device_is_real(self) || is_loopback(self)) + if (!nm_device_is_real(self) || NM_IS_DEVICE_LOOPBACK(self)) return FALSE; /* we enable periodic checks for every device state (except UNKNOWN). Especially with @@ -6203,7 +6218,8 @@ nm_device_master_release_slave(NMDevice *self, NMDevicePrivate *priv; NMDevicePrivate *slave_priv; SlaveInfo *info; - gs_unref_object NMDevice *self_free = NULL; + gs_unref_object NMDevice *self_free = NULL; + gs_unref_object NMDevice *slave_free = NULL; g_return_if_fail(NM_DEVICE(self)); g_return_if_fail(NM_DEVICE(slave)); @@ -6246,14 +6262,15 @@ nm_device_master_release_slave(NMDevice *self, /* keep both alive until the end of the function. * Transfers ownership from slave_priv->master. */ - self_free = self; + nm_assert(self == slave_priv->master); + self_free = g_steal_pointer(&slave_priv->master); - c_list_unlink(&info->lst_slave); - slave_priv->master = NULL; + nm_assert(slave == info->slave); + slave_free = g_steal_pointer(&info->slave); + c_list_unlink(&info->lst_slave); g_signal_handler_disconnect(slave, info->watch_id); - g_object_unref(slave); - g_slice_free(SlaveInfo, info); + nm_g_slice_free(info); if (c_list_is_empty(&priv->slaves)) { _active_connection_set_state_flags_full(self, @@ -6577,27 +6594,30 @@ device_recheck_slave_status(NMDevice *self, const NMPlatformLink *plink) NM_DEVICE_STATE_REASON_CONNECTION_ASSUMED); } - if (master && NM_DEVICE_GET_CLASS(master)->attach_port) { - nm_device_master_add_slave(master, self, FALSE); + if (master) { + if (NM_DEVICE_GET_CLASS(master)->attach_port) { + nm_device_master_add_slave(master, self, FALSE); + } else { + _LOGD(LOGD_DEVICE, + "enslaved to non-master-type device %s; ignoring", + nm_device_get_iface(master)); + } goto out; } - if (master) { - _LOGD(LOGD_DEVICE, - "enslaved to non-master-type device %s; ignoring", - nm_device_get_iface(master)); - } else { + if (plink->master) { _LOGD(LOGD_DEVICE, "enslaved to unknown device %d (%s%s%s)", plink->master, NM_PRINT_FMT_QUOTED(plink_master, "\"", plink_master->name, "\"", "??")); + if (!priv->ifindex_changed_id) { + priv->ifindex_changed_id = g_signal_connect(nm_device_get_manager(self), + NM_MANAGER_DEVICE_IFINDEX_CHANGED, + G_CALLBACK(device_ifindex_changed_cb), + self); + } } - if (!priv->ifindex_changed_id) { - priv->ifindex_changed_id = g_signal_connect(nm_device_get_manager(self), - NM_MANAGER_DEVICE_IFINDEX_CHANGED, - G_CALLBACK(device_ifindex_changed_cb), - self); - } + return; out: @@ -6609,6 +6629,8 @@ device_ifindex_changed_cb(NMManager *manager, NMDevice *device_changed, NMDevice { NMDevicePrivate *priv = NM_DEVICE_GET_PRIVATE(self); + g_return_if_fail(priv->master_ifindex > 0); + if (priv->master_ifindex != nm_device_get_ifindex(device_changed)) return; @@ -7465,11 +7487,6 @@ realize_start_setup(NMDevice *self, NM_UNMANAGED_EXTERNAL_DOWN, _dev_unmanaged_is_external_down(self, TRUE)); - /* Unmanaged the loopback device with an explicit NM_UNMANAGED_BY_TYPE flag. - * Later we might want to manage 'lo' too. Currently, that doesn't work because - * NetworkManager might down the interface or remove the 127.0.0.1 address. */ - nm_device_set_unmanaged_flags(self, NM_UNMANAGED_BY_TYPE, is_loopback(self)); - nm_device_set_unmanaged_by_user_udev(self); nm_device_set_unmanaged_by_user_conf(self); @@ -7659,8 +7676,7 @@ nm_device_unrealize(NMDevice *self, gboolean remove_resources, GError **error) nm_device_set_unmanaged_flags(self, NM_UNMANAGED_PLATFORM_INIT, TRUE); nm_device_set_unmanaged_flags(self, - NM_UNMANAGED_PARENT | NM_UNMANAGED_BY_TYPE - | NM_UNMANAGED_USER_UDEV | NM_UNMANAGED_USER_EXPLICIT + NM_UNMANAGED_USER_UDEV | NM_UNMANAGED_USER_EXPLICIT | NM_UNMANAGED_EXTERNAL_DOWN | NM_UNMANAGED_IS_SLAVE, NM_UNMAN_FLAG_OP_FORGET); @@ -8585,7 +8601,7 @@ nm_device_generate_connection(NMDevice *self, pllink = nm_platform_link_get(nm_device_get_platform(self), priv->ifindex); if (pllink && pllink->inet6_token.id) { - char sbuf[NM_UTILS_INET_ADDRSTRLEN]; + char sbuf[NM_INET_ADDRSTRLEN]; g_object_set(s_ip6, NM_SETTING_IP6_CONFIG_ADDR_GEN_MODE, @@ -8776,6 +8792,14 @@ check_connection_compatible(NMDevice *self, NMConnection *connection, GError **e return FALSE; } + if (!nm_device_has_capability(self, NM_DEVICE_CAP_SRIOV) + && nm_connection_get_setting(connection, NM_TYPE_SETTING_SRIOV)) { + nm_utils_error_set_literal(error, + NM_UTILS_ERROR_CONNECTION_AVAILABLE_TEMPORARY, + "device does not support SR-IOV"); + return FALSE; + } + conn_iface = nm_manager_get_connection_iface(NM_MANAGER_GET, connection, NULL, NULL, &local); /* We always need a interface name for virtual devices, but for @@ -9359,14 +9383,17 @@ activate_stage1_device_prepare(NMDevice *self) nm_device_state_changed(self, NM_DEVICE_STATE_PREPARE, NM_DEVICE_STATE_REASON_NONE); if (priv->stage1_sriov_state != NM_DEVICE_STAGE_STATE_COMPLETED) { - NMSettingSriov *s_sriov; + NMSettingSriov *s_sriov = NULL; if (nm_device_sys_iface_state_is_external_or_assume(self)) { /* pass */ - } else if (priv->stage1_sriov_state == NM_DEVICE_STAGE_STATE_PENDING) + } else if (priv->stage1_sriov_state == NM_DEVICE_STAGE_STATE_PENDING) { return; - else if (priv->ifindex > 0 && nm_device_has_capability(self, NM_DEVICE_CAP_SRIOV) - && (s_sriov = nm_device_get_applied_setting(self, NM_TYPE_SETTING_SRIOV))) { + } else if (priv->ifindex > 0) { + s_sriov = nm_device_get_applied_setting(self, NM_TYPE_SETTING_SRIOV); + } + + if (s_sriov) { nm_auto_freev NMPlatformVF **plat_vfs = NULL; gs_free_error GError *error = NULL; NMSriovVF *vf; @@ -9374,6 +9401,8 @@ activate_stage1_device_prepare(NMDevice *self) guint num; guint i; + nm_assert(nm_device_has_capability(self, NM_DEVICE_CAP_SRIOV)); + autoprobe = nm_setting_sriov_get_autoprobe_drivers(s_sriov); if (autoprobe == NM_TERNARY_DEFAULT) { autoprobe = nm_config_data_get_connection_default_int64( @@ -10058,7 +10087,7 @@ _dev_ipmanual_check_ready(NMDevice *self) gboolean has_carrier; NML3CfgCheckReadyFlags flags; gboolean ready; - gboolean acd_used = FALSE; + gs_unref_array GArray *conflicts = NULL; int IS_IPv4; if (priv->ipmanual_data.state_4 != NM_DEVICE_IP_STATE_PENDING @@ -10101,8 +10130,8 @@ _dev_ipmanual_check_ready(NMDevice *self) priv->l3cds[L3_CONFIG_DATA_TYPE_MANUALIP].d, addr_family, flags, - &acd_used); - if (acd_used) { + &conflicts); + if (conflicts) { _dev_ipmanual_set_state(self, addr_family, NM_DEVICE_IP_STATE_FAILED); _dev_ip_state_check_async(self, AF_UNSPEC); } else if (ready) { @@ -10434,6 +10463,7 @@ _dev_ipdhcpx_start(NMDevice *self, int addr_family) .request_broadcast = request_broadcast, .acd_timeout_msec = _prop_get_ipv4_dad_timeout(self), }, + .previous_lease = priv->l3cds[L3_CONFIG_DATA_TYPE_DHCP_X(IS_IPv4)].d, }; priv->ipdhcp_data_4.client = @@ -10484,16 +10514,16 @@ _dev_ipdhcpx_start(NMDevice *self, int addr_family) G_CALLBACK(_dev_ipdhcpx_notify), self); - /* FIXME(l3cfg:dhcp:previous-lease): take the NML3ConfigData from the previous lease (if any) - * and pass it on to NMDhcpClient. This is a fake lease that we use initially (until - * NMDhcpClient got a real lease). Note that NMDhcpClient needs to check whether the - * lease already expired. */ - + /* Take the NML3ConfigData from the previous lease (if any) that was passed to the NMDhcpClient. + * This may be the old lease only used during the duration of a reapply until we get the + * new lease. */ previous_lease = nm_dhcp_client_get_lease(priv->ipdhcp_data_x[IS_IPv4].client); + if (!priv->ipdhcp_data_x[IS_IPv4].config) { priv->ipdhcp_data_x[IS_IPv4].config = nm_dhcp_config_new(addr_family, previous_lease); _notify(self, PROP_DHCPX_CONFIG(IS_IPv4)); } + if (previous_lease) { nm_dhcp_config_set_lease(priv->ipdhcp_data_x[IS_IPv4].config, previous_lease); _dev_l3_register_l3cds_set_one_full(self, @@ -10747,14 +10777,14 @@ nm_device_copy_ip6_dns_config(NMDevice *self, NMDevice *from_device) l3cd_src = priv_src->l3cds[L3_CONFIG_DATA_TYPE_AC_6].d; } if (l3cd_src) { - const char *const *strvarr; - const struct in6_addr *addrs; - guint n; - guint i; + const char *const *strvarr; + const char *const *addrs; + guint n; + guint i; addrs = nm_l3_config_data_get_nameservers(l3cd_src, AF_INET6, &n); for (i = 0; i < n; i++) - nm_l3_config_data_add_nameserver(l3cd, AF_INET6, &addrs[i]); + nm_l3_config_data_add_nameserver(l3cd, AF_INET6, addrs[i]); strvarr = nm_l3_config_data_get_searches(l3cd_src, AF_INET6, &n); for (i = 0; i < n; i++) @@ -10806,7 +10836,8 @@ _dev_ipll6_set_llstate(NMDevice *self, NML3IPv6LLState llstate, const struct in6 || (!priv->ipll_data_6.v6.ipv6ll && NM_IN_SET(priv->ipll_data_6.v6.llstate, NM_L3_IPV6LL_STATE_NONE, - NM_L3_IPV6LL_STATE_DEFUNCT))); + NM_L3_IPV6LL_STATE_DEFUNCT, + NM_L3_IPV6LL_STATE_READY))); switch (priv->ipll_data_6.v6.llstate) { case NM_L3_IPV6LL_STATE_NONE: @@ -10844,7 +10875,7 @@ _dev_ipll6_set_llstate(NMDevice *self, NML3IPv6LLState llstate, const struct in6 } if (changed) { - char sbuf[NM_UTILS_INET_ADDRSTRLEN]; + char sbuf[NM_INET_ADDRSTRLEN]; _LOGT_ipll(AF_INET6, "set state %s (was %s, llstate=%s, lladdr=%s)", @@ -10853,7 +10884,7 @@ _dev_ipll6_set_llstate(NMDevice *self, NML3IPv6LLState llstate, const struct in6 nm_l3_ipv6ll_state_to_string(priv->ipll_data_6.v6.llstate), nm_ip_addr_is_null(AF_INET6, &priv->ipll_data_6.v6.lladdr) ? "(none)" - : _nm_utils_inet6_ntop(&priv->ipll_data_6.v6.lladdr, sbuf)); + : nm_inet6_ntop(&priv->ipll_data_6.v6.lladdr, sbuf)); } if (changed) @@ -10889,6 +10920,11 @@ _dev_ipll6_start(NMDevice *self) if (priv->ipll_data_6.v6.ipv6ll) return; + if (NM_IS_DEVICE_LOOPBACK(self)) { + _dev_ipll6_set_llstate(self, NM_L3_IPV6LL_STATE_READY, NULL); + return; + } + if (!priv->l3cfg) { _LOGD(LOGD_IP6, "linklocal6: no IP link for IPv6"); goto out_fail; @@ -11000,6 +11036,10 @@ nm_device_get_configured_mtu_from_connection(NMDevice *self, if (setting) mtu = nm_setting_wireguard_get_mtu(NM_SETTING_WIREGUARD(setting)); global_property_name = NM_CON_DEFAULT("wireguard.mtu"); + } else if (setting_type == NM_TYPE_SETTING_LOOPBACK) { + if (setting) + mtu = nm_setting_loopback_get_mtu(NM_SETTING_LOOPBACK(setting)); + global_property_name = NM_CON_DEFAULT("loopback.mtu"); } else g_return_val_if_reached(0); @@ -11411,10 +11451,14 @@ _dev_ipac6_ndisc_config_changed(NMNDisc *ndisc, const NML3ConfigData *l3cd, NMDevice *self) { - NMDevicePrivate *priv = NM_DEVICE_GET_PRIVATE(self); - gboolean ready = TRUE; - NMDedupMultiIter iter; - const NMPObject *obj; + NMDevicePrivate *priv = NM_DEVICE_GET_PRIVATE(self); + gboolean ready; + + /* The ndisc configuration changes when we receive a new RA or + * when a lifetime expires; but also when DAD fails for a + * SLAAC address and we need to regenerate new stable-privacy + * addresses. In all these cases we update the AC6 configuration, + * schedule a commit and update the AC state. */ _dev_ipac6_grace_period_start(self, 0, TRUE); @@ -11425,22 +11469,11 @@ _dev_ipac6_ndisc_config_changed(NMNDisc *ndisc, FALSE); nm_clear_l3cd(&priv->ipac6_data.l3cd); - - /* wait that addresses are committed to platform and - * become non-tentative before declaring AC6 is ready.*/ - nm_l3_config_data_iter_obj_for_each (&iter, l3cd, &obj, NMP_OBJECT_TYPE_IP6_ADDRESS) { - const NMPlatformIP6Address *addr = NMP_OBJECT_CAST_IP6_ADDRESS(obj); - const NMPlatformIP6Address *plat_addr; - - plat_addr = nm_platform_ip6_address_get(nm_device_get_platform(self), - nm_device_get_ip_ifindex(self), - &addr->address); - if (!plat_addr || (plat_addr->n_ifa_flags & IFA_F_TENTATIVE)) { - ready = FALSE; - break; - } - } - + ready = nm_l3cfg_check_ready(priv->l3cfg, + l3cd, + AF_INET6, + NM_L3CFG_CHECK_READY_FLAGS_IP6_DAD_READY, + NULL); if (ready) { _dev_ipac6_set_state(self, NM_DEVICE_IP_STATE_READY); } else { @@ -12078,13 +12111,34 @@ activate_stage3_ip_config(NMDevice *self) ifindex = nm_device_get_ip_ifindex(self); + ipv4_method = nm_device_get_effective_ip_config_method(self, AF_INET); + if (nm_streq(ipv4_method, NM_SETTING_IP4_CONFIG_METHOD_AUTO)) { + /* "auto" usually means DHCPv4 or autoconf6, but it doesn't have to be. Subclasses + * can overwrite it. For example, you cannot run DHCPv4 on PPP/WireGuard links. */ + ipv4_method = klass->get_ip_method_auto(self, AF_INET); + } + + ipv6_method = nm_device_get_effective_ip_config_method(self, AF_INET6); + + if (nm_streq(ipv6_method, NM_SETTING_IP6_CONFIG_METHOD_AUTO)) { + ipv6_method = klass->get_ip_method_auto(self, AF_INET6); + } + if (priv->ip_data_4.do_reapply) { _LOGD_ip(AF_INET, "reapply..."); - _cleanup_ip_pre(self, AF_INET, CLEANUP_TYPE_DECONFIGURE, TRUE); + priv->ip_data_4.do_reapply = FALSE; + _cleanup_ip_pre(self, + AF_INET, + CLEANUP_TYPE_KEEP_REAPPLY, + nm_streq(ipv4_method, NM_SETTING_IP4_CONFIG_METHOD_AUTO)); } if (priv->ip_data_6.do_reapply) { _LOGD_ip(AF_INET6, "reapply..."); - _cleanup_ip_pre(self, AF_INET6, CLEANUP_TYPE_DECONFIGURE, TRUE); + priv->ip_data_6.do_reapply = FALSE; + _cleanup_ip_pre(self, + AF_INET6, + CLEANUP_TYPE_KEEP_REAPPLY, + nm_streq(ipv6_method, NM_SETTING_IP6_CONFIG_METHOD_AUTO)); } /* Add the interface to the specified firewall zone */ @@ -12136,18 +12190,6 @@ activate_stage3_ip_config(NMDevice *self) * let's do it! */ _commit_mtu(self); - ipv4_method = nm_device_get_effective_ip_config_method(self, AF_INET); - if (nm_streq(ipv4_method, NM_SETTING_IP4_CONFIG_METHOD_AUTO)) { - /* "auto" usually means DHCPv4 or autoconf6, but it doesn't have to be. Subclasses - * can overwrite it. For example, you cannot run DHCPv4 on PPP/WireGuard links. */ - ipv4_method = klass->get_ip_method_auto(self, AF_INET); - } - - ipv6_method = nm_device_get_effective_ip_config_method(self, AF_INET6); - if (nm_streq(ipv6_method, NM_SETTING_IP6_CONFIG_METHOD_AUTO)) { - ipv6_method = klass->get_ip_method_auto(self, AF_INET6); - } - if (!nm_device_sys_iface_state_is_external(self) && (!klass->ready_for_ip_config || klass->ready_for_ip_config(self, TRUE))) { if (priv->ipmanual_data.state_6 == NM_DEVICE_IP_STATE_NONE @@ -12274,16 +12316,28 @@ _dev_ipshared4_new_l3cd(NMDevice *self, NMConnection *connection, NMPlatformIP4A static gboolean _dev_ipshared4_init(NMDevice *self) { - static const char *const modules[] = {"ip_tables", - "iptable_nat", - "nf_nat_ftp", - "nf_nat_irc", - "nf_nat_sip", - "nf_nat_tftp", - "nf_nat_pptp", - "nf_nat_h323"}; - int errsv; - guint i; + static const char *const modules_iptables[] = {"ip_tables", "iptable_nat"}; + static const char *const modules_nftables[] = + {"nf_nat_ftp", "nf_nat_irc", "nf_nat_sip", "nf_nat_tftp", "nf_nat_pptp", "nf_nat_h323"}; + int errsv; + guint i; + + switch (nm_firewall_utils_get_backend()) { + case NM_FIREWALL_BACKEND_IPTABLES: + for (i = 0; i < G_N_ELEMENTS(modules_iptables); i++) + nmp_utils_modprobe(NULL, FALSE, modules_iptables[i], NULL); + break; + case NM_FIREWALL_BACKEND_NFTABLES: + for (i = 0; i < G_N_ELEMENTS(modules_nftables); i++) + nmp_utils_modprobe(NULL, FALSE, modules_nftables[i], NULL); + break; + case NM_FIREWALL_BACKEND_NONE: + /* do not modify network settings like ip forwarding */ + return TRUE; + default: + nm_assert_not_reached(); + break; + } if (nm_platform_sysctl_get_int32(nm_device_get_platform(self), NMP_SYSCTL_PATHID_ABSOLUTE("/proc/sys/net/ipv4/ip_forward"), @@ -12312,9 +12366,6 @@ _dev_ipshared4_init(NMDevice *self) nm_strerror_native(errsv)); } - for (i = 0; i < G_N_ELEMENTS(modules); i++) - nmp_utils_modprobe(NULL, FALSE, modules[i], NULL); - return TRUE; } @@ -12591,17 +12642,18 @@ delete_on_deactivate_check_and_schedule(NMDevice *self) } static void -_cleanup_ip_pre(NMDevice *self, int addr_family, CleanupType cleanup_type, gboolean from_reapply) +_cleanup_ip_pre(NMDevice *self, int addr_family, CleanupType cleanup_type, gboolean preserve_dhcp) { - const int IS_IPv4 = NM_IS_IPv4(addr_family); - NMDevicePrivate *priv = NM_DEVICE_GET_PRIVATE(self); + const int IS_IPv4 = NM_IS_IPv4(addr_family); + NMDevicePrivate *priv = NM_DEVICE_GET_PRIVATE(self); + gboolean keep_reapply = (cleanup_type == CLEANUP_TYPE_KEEP_REAPPLY); _dev_ipsharedx_cleanup(self, addr_family); _dev_ipdev_cleanup(self, AF_UNSPEC); _dev_ipdev_cleanup(self, addr_family); - _dev_ipdhcpx_cleanup(self, addr_family, TRUE, FALSE); + _dev_ipdhcpx_cleanup(self, addr_family, !preserve_dhcp || !keep_reapply, FALSE); if (!IS_IPv4) _dev_ipac6_cleanup(self); @@ -12613,8 +12665,8 @@ _cleanup_ip_pre(NMDevice *self, int addr_family, CleanupType cleanup_type, gbool nm_clear_g_signal_handler(nm_manager_get_dns_manager(priv->manager), &priv->ip_data.dnsmgr_update_pending_signal_id); - _dev_ip_state_cleanup(self, AF_UNSPEC, from_reapply); - _dev_ip_state_cleanup(self, addr_family, from_reapply); + _dev_ip_state_cleanup(self, AF_UNSPEC, keep_reapply); + _dev_ip_state_cleanup(self, addr_family, keep_reapply); } gboolean @@ -12762,7 +12814,9 @@ can_reapply_change(NMDevice *self, goto out_fail; } - if (nm_streq(setting_name, NM_SETTING_OVS_EXTERNAL_IDS_SETTING_NAME) + if (NM_IN_STRSET(setting_name, + NM_SETTING_OVS_EXTERNAL_IDS_SETTING_NAME, + NM_SETTING_OVS_OTHER_CONFIG_SETTING_NAME) && NM_DEVICE_GET_CLASS(self)->can_reapply_change_ovs_external_ids) { /* TODO: this means, you cannot reapply changes to the external-ids for * OVS system interfaces. */ @@ -12984,6 +13038,10 @@ check_and_reapply_connection(NMDevice *self, if (priv->state >= NM_DEVICE_STATE_ACTIVATED) nm_device_update_metered(self); + /* Notify dispatcher when re-applied */ + _LOGD(LOGD_DEVICE, "Notifying re-apply complete"); + nm_dispatcher_call_device(NM_DISPATCHER_ACTION_REAPPLY, self, NULL, NULL, NULL, NULL); + return TRUE; } @@ -13889,7 +13947,7 @@ nm_device_start_ip_check(NMDevice *self) NMSettingConnection *s_con; guint timeout = 0; const char *ping_binary = NULL; - char buf[NM_UTILS_INET_ADDRSTRLEN]; + char buf[NM_INET_ADDRSTRLEN]; NMLogDomain log_domain = LOGD_IP4; /* Shouldn't be any active ping here, since IP_CHECK happens after the @@ -13920,14 +13978,14 @@ nm_device_start_ip_check(NMDevice *self) } else if (priv->ip_data_4.state == NM_DEVICE_IP_STATE_READY) { gw = nm_l3_config_data_get_best_default_route(l3cd, AF_INET); if (gw) { - _nm_utils_inet4_ntop(NMP_OBJECT_CAST_IP4_ROUTE(gw)->gateway, buf); + nm_inet4_ntop(NMP_OBJECT_CAST_IP4_ROUTE(gw)->gateway, buf); ping_binary = nm_utils_find_helper("ping", "/usr/bin/ping", NULL); log_domain = LOGD_IP4; } } else if (priv->ip_data_6.state == NM_DEVICE_IP_STATE_READY) { gw = nm_l3_config_data_get_best_default_route(l3cd, AF_INET6); if (gw) { - _nm_utils_inet6_ntop(&NMP_OBJECT_CAST_IP6_ROUTE(gw)->gateway, buf); + nm_inet6_ntop(&NMP_OBJECT_CAST_IP6_ROUTE(gw)->gateway, buf); ping_binary = nm_utils_find_helper("ping6", "/usr/bin/ping6", NULL); log_domain = LOGD_IP6; } @@ -14151,8 +14209,6 @@ NM_UTILS_FLAGS2STR_DEFINE(nm_unmanaged_flags2str, NMUnmanagedFlags, NM_UTILS_FLAGS2STR(NM_UNMANAGED_SLEEPING, "sleeping"), NM_UTILS_FLAGS2STR(NM_UNMANAGED_QUITTING, "quitting"), - NM_UTILS_FLAGS2STR(NM_UNMANAGED_PARENT, "parent"), - NM_UTILS_FLAGS2STR(NM_UNMANAGED_BY_TYPE, "by-type"), NM_UTILS_FLAGS2STR(NM_UNMANAGED_PLATFORM_INIT, "platform-init"), NM_UTILS_FLAGS2STR(NM_UNMANAGED_USER_EXPLICIT, "user-explicit"), NM_UTILS_FLAGS2STR(NM_UNMANAGED_BY_DEFAULT, "by-default"), @@ -14847,9 +14903,10 @@ _nm_device_check_connection_available(NMDevice *self, } 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"); + nm_utils_error_set_literal( + error, + NM_UTILS_ERROR_CONNECTION_AVAILABLE_STRICTLY_UNMANAGED_DEVICE, + "device is strictly unmanaged"); return FALSE; } if (!NM_FLAGS_HAS(flags, @@ -16138,7 +16195,7 @@ nm_device_queue_state(NMDevice *self, NMDeviceState state, NMDeviceStateReason r /* We should only ever have one delayed state transition at a time */ if (priv->queued_state.id) { - _LOGW(LOGD_DEVICE, + _LOGD(LOGD_DEVICE, "queue-state[%s, reason:%s, id:%u]: %s", nm_device_state_to_string(priv->queued_state.state), nm_device_state_reason_to_string_a(priv->queued_state.reason), @@ -17127,6 +17184,12 @@ nm_device_clear_dns_lookup_data(NMDevice *self) nm_clear_pointer(&priv->hostname_resolver_x[i], _hostname_resolver_free); } +gboolean +nm_device_get_allow_autoconnect_on_external(NMDevice *self) +{ + return NM_DEVICE_GET_CLASS(self)->allow_autoconnect_on_external; +} + static GInetAddress * get_address_for_hostname_dns_lookup(NMDevice *self, int addr_family) { @@ -17151,10 +17214,12 @@ get_address_for_hostname_dns_lookup(NMDevice *self, int addr_family) if (head_entry) { c_list_for_each_entry (iter, &head_entry->lst_entries_head, lst_entries) { - const NMPlatformIPAddress *addr = NMP_OBJECT_CAST_IP_ADDRESS(iter->obj); + const NMPlatformIPXAddress *addr = NMP_OBJECT_CAST_IPX_ADDRESS(iter->obj); if (IS_IPv4) { - return g_inet_address_new_from_bytes(addr->address_ptr, G_SOCKET_FAMILY_IPV4); + if (nm_ip4_addr_is_loopback(addr->a4.address)) + continue; + return g_inet_address_new_from_bytes(addr->ax.address_ptr, G_SOCKET_FAMILY_IPV4); } /* For IPv6 prefer, in order: @@ -17163,15 +17228,19 @@ get_address_for_hostname_dns_lookup(NMDevice *self, int addr_family) * - link-local */ - if (!IN6_IS_ADDR_LINKLOCAL(addr->address_ptr)) { - if (!(addr->n_ifa_flags & IFA_F_DEPRECATED)) { - return g_inet_address_new_from_bytes(addr->address_ptr, G_SOCKET_FAMILY_IPV6); + if (IN6_ARE_ADDR_EQUAL(&addr->a6.address, &in6addr_loopback)) + continue; + + if (!IN6_IS_ADDR_LINKLOCAL(addr->ax.address_ptr)) { + if (!(addr->ax.n_ifa_flags & IFA_F_DEPRECATED)) { + return g_inet_address_new_from_bytes(addr->ax.address_ptr, + G_SOCKET_FAMILY_IPV6); } - addr6_nonll = addr->address_ptr; + addr6_nonll = addr->ax.address_ptr; continue; } - addr6_ll = addr->address_ptr; + addr6_ll = addr->ax.address_ptr; } if (addr6_nonll || addr6_ll) @@ -17578,7 +17647,7 @@ set_property(GObject *object, guint prop_id, const GValue *value, GParamSpec *ps nm_assert(priv->type == NM_DEVICE_TYPE_UNKNOWN); priv->type = g_value_get_uint(value); nm_assert(priv->type > NM_DEVICE_TYPE_UNKNOWN); - nm_assert(priv->type <= NM_DEVICE_TYPE_VRF); + nm_assert(priv->type <= NM_DEVICE_TYPE_LOOPBACK); break; case PROP_LINK_TYPE: /* construct-only */ diff --git a/src/core/devices/nm-device.h b/src/core/devices/nm-device.h index de850e68..f54457d1 100644 --- a/src/core/devices/nm-device.h +++ b/src/core/devices/nm-device.h @@ -91,7 +91,7 @@ #define NM_DEVICE_INTERFACE_FLAGS "interface-flags" #define NM_TYPE_DEVICE (nm_device_get_type()) -#define NM_DEVICE(obj) (G_TYPE_CHECK_INSTANCE_CAST((obj), NM_TYPE_DEVICE, NMDevice)) +#define NM_DEVICE(obj) (_NM_G_TYPE_CHECK_INSTANCE_CAST((obj), NM_TYPE_DEVICE, NMDevice)) #define NM_DEVICE_CLASS(klass) (G_TYPE_CHECK_CLASS_CAST((klass), NM_TYPE_DEVICE, NMDeviceClass)) #define NM_IS_DEVICE(obj) (G_TYPE_CHECK_INSTANCE_TYPE((obj), NM_TYPE_DEVICE)) #define NM_IS_DEVICE_CLASS(klass) (G_TYPE_CHECK_CLASS_TYPE((klass), NM_TYPE_DEVICE)) @@ -208,6 +208,8 @@ typedef struct _NMDeviceClass { bool can_reapply_change_ovs_external_ids : 1; + bool allow_autoconnect_on_external : 1; + NMRfkillType rfkill_type : 4; void (*state_changed)(NMDevice *device, @@ -561,8 +563,6 @@ void nm_device_copy_ip6_dns_config(NMDevice *self, NMDevice *from_device); * @NM_UNMANAGED_NONE: placeholder value * @NM_UNMANAGED_SLEEPING: %TRUE when unmanaged because NM is sleeping. * @NM_UNMANAGED_QUITTING: %TRUE when unmanaged because NM is shutting down. - * @NM_UNMANAGED_PARENT: %TRUE when unmanaged due to parent device being unmanaged - * @NM_UNMANAGED_BY_TYPE: %TRUE for unmanaging device by type, like loopback. * @NM_UNMANAGED_PLATFORM_INIT: %TRUE when unmanaged because platform link not * yet initialized. Unrealized device are also unmanaged for this reason. * @NM_UNMANAGED_USER_EXPLICIT: %TRUE when unmanaged by explicit user decision @@ -592,21 +592,19 @@ typedef enum { * the device cannot be managed. */ NM_UNMANAGED_SLEEPING = (1LL << 0), NM_UNMANAGED_QUITTING = (1LL << 1), - NM_UNMANAGED_PARENT = (1LL << 2), - NM_UNMANAGED_BY_TYPE = (1LL << 3), - NM_UNMANAGED_PLATFORM_INIT = (1LL << 4), - NM_UNMANAGED_USER_EXPLICIT = (1LL << 5), - NM_UNMANAGED_USER_SETTINGS = (1LL << 6), + NM_UNMANAGED_PLATFORM_INIT = (1LL << 2), + NM_UNMANAGED_USER_EXPLICIT = (1LL << 3), + NM_UNMANAGED_USER_SETTINGS = (1LL << 4), /* These flags can be non-effective and be overwritten * by other flags. */ - NM_UNMANAGED_BY_DEFAULT = (1LL << 7), - NM_UNMANAGED_USER_CONF = (1LL << 8), - NM_UNMANAGED_USER_UDEV = (1LL << 9), - NM_UNMANAGED_EXTERNAL_DOWN = (1LL << 10), - NM_UNMANAGED_IS_SLAVE = (1LL << 11), + NM_UNMANAGED_BY_DEFAULT = (1LL << 5), + NM_UNMANAGED_USER_CONF = (1LL << 6), + NM_UNMANAGED_USER_UDEV = (1LL << 7), + NM_UNMANAGED_EXTERNAL_DOWN = (1LL << 8), + NM_UNMANAGED_IS_SLAVE = (1LL << 9), - NM_UNMANAGED_ALL = ((1LL << 12) - 1), + NM_UNMANAGED_ALL = ((1LL << 10) - 1), } NMUnmanagedFlags; typedef enum { @@ -821,4 +819,6 @@ nm_device_get_hostname_from_dns_lookup(NMDevice *self, int addr_family, gboolean void nm_device_clear_dns_lookup_data(NMDevice *self); +gboolean nm_device_get_allow_autoconnect_on_external(NMDevice *self); + #endif /* __NETWORKMANAGER_DEVICE_H__ */ diff --git a/src/core/devices/nm-lldp-listener.c b/src/core/devices/nm-lldp-listener.c index 137bf8fb..ac7e97f0 100644 --- a/src/core/devices/nm-lldp-listener.c +++ b/src/core/devices/nm-lldp-listener.c @@ -15,24 +15,20 @@ #include "libnm-std-aux/unaligned.h" #include "libnm-platform/nm-platform.h" #include "libnm-glib-aux/nm-c-list.h" +#include "libnm-lldp/nm-lldp-rx.h" #include "nm-utils.h" -#include "libnm-systemd-core/nm-sd.h" - #define MAX_NEIGHBORS 128 #define MIN_UPDATE_INTERVAL_NSEC (2 * NM_UTILS_NSEC_PER_SEC) -#define LLDP_MAC_NEAREST_BRIDGE \ - (&((struct ether_addr){.ether_addr_octet = {0x01, 0x80, 0xc2, 0x00, 0x00, 0x0e}})) -#define LLDP_MAC_NEAREST_NON_TPMR_BRIDGE \ - (&((struct ether_addr){.ether_addr_octet = {0x01, 0x80, 0xc2, 0x00, 0x00, 0x03}})) -#define LLDP_MAC_NEAREST_CUSTOMER_BRIDGE \ - (&((struct ether_addr){.ether_addr_octet = {0x01, 0x80, 0xc2, 0x00, 0x00, 0x00}})) +#define LLDP_MAC_NEAREST_BRIDGE (&NM_ETHER_ADDR_INIT(0x01, 0x80, 0xc2, 0x00, 0x00, 0x0e)) +#define LLDP_MAC_NEAREST_NON_TPMR_BRIDGE (&NM_ETHER_ADDR_INIT(0x01, 0x80, 0xc2, 0x00, 0x00, 0x03)) +#define LLDP_MAC_NEAREST_CUSTOMER_BRIDGE (&NM_ETHER_ADDR_INIT(0x01, 0x80, 0xc2, 0x00, 0x00, 0x00)) /*****************************************************************************/ struct _NMLldpListener { - sd_lldp_rx *lldp_handle; + NMLldpRX *lldp_rx; GHashTable *lldp_neighbors; GVariant *variant; @@ -49,12 +45,12 @@ struct _NMLldpListener { /*****************************************************************************/ typedef struct { - GVariant *variant; - sd_lldp_neighbor *neighbor_sd; - char *chassis_id; - char *port_id; - guint8 chassis_id_type; - guint8 port_id_type; + GVariant *variant; + NMLldpNeighbor *neighbor_nm; + char *chassis_id; + char *port_id; + guint8 chassis_id_type; + guint8 port_id_type; } LldpNeighbor; /*****************************************************************************/ @@ -100,7 +96,7 @@ lldp_neighbor_get_raw(LldpNeighbor *neigh, const guint8 **out_raw_data, gsize *o nm_assert(neigh); - r = sd_lldp_neighbor_get_raw(neigh->neighbor_sd, &raw_data, &raw_len); + r = nm_lldp_neighbor_get_raw(neigh->neighbor_nm, &raw_data, &raw_len); nm_assert(r >= 0); nm_assert(raw_data); @@ -111,24 +107,24 @@ lldp_neighbor_get_raw(LldpNeighbor *neigh, const guint8 **out_raw_data, gsize *o } static gboolean -lldp_neighbor_id_get(struct sd_lldp_neighbor *neighbor_sd, - guint8 *out_chassis_id_type, - const guint8 **out_chassis_id, - gsize *out_chassis_id_len, - guint8 *out_port_id_type, - const guint8 **out_port_id, - gsize *out_port_id_len) +lldp_neighbor_id_get(NMLldpNeighbor *neighbor_nm, + guint8 *out_chassis_id_type, + const guint8 **out_chassis_id, + gsize *out_chassis_id_len, + guint8 *out_port_id_type, + const guint8 **out_port_id, + gsize *out_port_id_len) { int r; - r = sd_lldp_neighbor_get_chassis_id(neighbor_sd, + r = nm_lldp_neighbor_get_chassis_id(neighbor_nm, out_chassis_id_type, (gconstpointer *) out_chassis_id, out_chassis_id_len); if (r < 0) return FALSE; - r = sd_lldp_neighbor_get_port_id(neighbor_sd, + r = nm_lldp_neighbor_get_port_id(neighbor_nm, out_port_id_type, (gconstpointer *) out_port_id, out_port_id_len); @@ -139,82 +135,16 @@ lldp_neighbor_id_get(struct sd_lldp_neighbor *neighbor_sd, } static guint -lldp_neighbor_id_hash(gconstpointer ptr) +lldp_neighbor_id_hash(const LldpNeighbor *neigh) { - const LldpNeighbor *neigh = ptr; - guint8 chassis_id_type; - guint8 port_id_type; - const guint8 *chassis_id; - const guint8 *port_id; - gsize chassis_id_len; - gsize port_id_len; - NMHashState h; - - if (!lldp_neighbor_id_get(neigh->neighbor_sd, - &chassis_id_type, - &chassis_id, - &chassis_id_len, - &port_id_type, - &port_id, - &port_id_len)) { - nm_assert_not_reached(); - return 0; - } - - nm_hash_init(&h, 23423423u); - nm_hash_update_vals(&h, chassis_id_len, port_id_len, chassis_id_type, port_id_type); - nm_hash_update(&h, chassis_id, chassis_id_len); - nm_hash_update(&h, port_id, port_id_len); - return nm_hash_complete(&h); + return nm_lldp_neighbor_id_hash(nm_lldp_neighbor_get_id(neigh->neighbor_nm)); } static int lldp_neighbor_id_cmp(const LldpNeighbor *a, const LldpNeighbor *b) { - guint8 a_chassis_id_type; - guint8 b_chassis_id_type; - guint8 a_port_id_type; - guint8 b_port_id_type; - const guint8 *a_chassis_id; - const guint8 *b_chassis_id; - const guint8 *a_port_id; - const guint8 *b_port_id; - gsize a_chassis_id_len; - gsize b_chassis_id_len; - gsize a_port_id_len; - gsize b_port_id_len; - - NM_CMP_SELF(a, b); - - if (!lldp_neighbor_id_get(a->neighbor_sd, - &a_chassis_id_type, - &a_chassis_id, - &a_chassis_id_len, - &a_port_id_type, - &a_port_id, - &a_port_id_len)) { - nm_assert_not_reached(); - return FALSE; - } - - if (!lldp_neighbor_id_get(b->neighbor_sd, - &b_chassis_id_type, - &b_chassis_id, - &b_chassis_id_len, - &b_port_id_type, - &b_port_id, - &b_port_id_len)) { - nm_assert_not_reached(); - return FALSE; - } - - NM_CMP_DIRECT(a_chassis_id_type, b_chassis_id_type); - NM_CMP_DIRECT(a_port_id_type, b_port_id_type); - NM_CMP_DIRECT(a_chassis_id_len, b_chassis_id_len); - NM_CMP_DIRECT(a_port_id_len, b_port_id_len); - NM_CMP_DIRECT_MEMCMP(a_chassis_id, b_chassis_id, a_chassis_id_len); - NM_CMP_DIRECT_MEMCMP(a_port_id, b_port_id, a_port_id_len); - return 0; + return nm_lldp_neighbor_id_cmp(nm_lldp_neighbor_get_id(a->neighbor_nm), + nm_lldp_neighbor_get_id(b->neighbor_nm)); } static int @@ -225,7 +155,7 @@ lldp_neighbor_id_cmp_p(gconstpointer a, gconstpointer b, gpointer user_data) } static gboolean -lldp_neighbor_id_equal(gconstpointer a, gconstpointer b) +lldp_neighbor_id_equal(const LldpNeighbor *a, const LldpNeighbor *b) { return lldp_neighbor_id_cmp(a, b) == 0; } @@ -239,7 +169,7 @@ lldp_neighbor_free(LldpNeighbor *neighbor) g_free(neighbor->chassis_id); g_free(neighbor->port_id); nm_g_variant_unref(neighbor->variant); - sd_lldp_neighbor_unref(neighbor->neighbor_sd); + nm_lldp_neighbor_unref(neighbor->neighbor_nm); nm_g_slice_free(neighbor); } @@ -257,7 +187,7 @@ lldp_neighbor_equal(LldpNeighbor *a, LldpNeighbor *b) gsize raw_len_a; gsize raw_len_b; - if (a->neighbor_sd == b->neighbor_sd) + if (a->neighbor_nm == b->neighbor_nm) return TRUE; lldp_neighbor_get_raw(a, &raw_data_a, &raw_len_a); @@ -293,7 +223,7 @@ parse_management_address_tlv(const uint8_t *data, gsize len) if (len < 11) return NULL; - nm_assert((data[0] >> 1) == SD_LLDP_TYPE_MGMT_ADDRESS); + nm_assert((data[0] >> 1) == NM_LLDP_TYPE_MGMT_ADDRESS); nm_assert((((data[0] & 1) << 8) + data[1]) + 2 == len); data += 2; @@ -360,7 +290,7 @@ format_network_address(const guint8 *data, gsize sz) } else return NULL; - return nm_utils_inet_ntop_dup(family, &a); + return nm_inet_ntop_dup(family, &a); } static const char * @@ -402,7 +332,7 @@ format_string_cp(const guint8 *data, gsize len, gboolean allow_trim) } static LldpNeighbor * -lldp_neighbor_new(sd_lldp_neighbor *neighbor_sd) +lldp_neighbor_new(NMLldpNeighbor *neighbor_nm) { LldpNeighbor *neigh; guint8 chassis_id_type; @@ -414,7 +344,7 @@ lldp_neighbor_new(sd_lldp_neighbor *neighbor_sd) gs_free char *s_chassis_id = NULL; gs_free char *s_port_id = NULL; - if (!lldp_neighbor_id_get(neighbor_sd, + if (!lldp_neighbor_id_get(neighbor_nm, &chassis_id_type, &chassis_id, &chassis_id_len, @@ -424,17 +354,17 @@ lldp_neighbor_new(sd_lldp_neighbor *neighbor_sd) return NULL; switch (chassis_id_type) { - case SD_LLDP_CHASSIS_SUBTYPE_CHASSIS_COMPONENT: - case SD_LLDP_CHASSIS_SUBTYPE_INTERFACE_ALIAS: - case SD_LLDP_CHASSIS_SUBTYPE_PORT_COMPONENT: - case SD_LLDP_CHASSIS_SUBTYPE_INTERFACE_NAME: - case SD_LLDP_CHASSIS_SUBTYPE_LOCALLY_ASSIGNED: + case NM_LLDP_CHASSIS_SUBTYPE_CHASSIS_COMPONENT: + case NM_LLDP_CHASSIS_SUBTYPE_INTERFACE_ALIAS: + case NM_LLDP_CHASSIS_SUBTYPE_PORT_COMPONENT: + case NM_LLDP_CHASSIS_SUBTYPE_INTERFACE_NAME: + case NM_LLDP_CHASSIS_SUBTYPE_LOCALLY_ASSIGNED: s_chassis_id = format_string_cp(chassis_id, chassis_id_len, FALSE); break; - case SD_LLDP_CHASSIS_SUBTYPE_MAC_ADDRESS: + case NM_LLDP_CHASSIS_SUBTYPE_MAC_ADDRESS: s_chassis_id = nm_utils_hwaddr_ntoa(chassis_id, chassis_id_len); break; - case SD_LLDP_CHASSIS_SUBTYPE_NETWORK_ADDRESS: + case NM_LLDP_CHASSIS_SUBTYPE_NETWORK_ADDRESS: s_chassis_id = format_network_address(chassis_id, chassis_id_len); break; } @@ -446,16 +376,16 @@ lldp_neighbor_new(sd_lldp_neighbor *neighbor_sd) } switch (port_id_type) { - case SD_LLDP_PORT_SUBTYPE_INTERFACE_ALIAS: - case SD_LLDP_PORT_SUBTYPE_PORT_COMPONENT: - case SD_LLDP_PORT_SUBTYPE_INTERFACE_NAME: - case SD_LLDP_PORT_SUBTYPE_LOCALLY_ASSIGNED: + case NM_LLDP_PORT_SUBTYPE_INTERFACE_ALIAS: + case NM_LLDP_PORT_SUBTYPE_PORT_COMPONENT: + case NM_LLDP_PORT_SUBTYPE_INTERFACE_NAME: + case NM_LLDP_PORT_SUBTYPE_LOCALLY_ASSIGNED: s_port_id = format_string_cp(port_id, port_id_len, FALSE); break; - case SD_LLDP_PORT_SUBTYPE_MAC_ADDRESS: + case NM_LLDP_PORT_SUBTYPE_MAC_ADDRESS: s_port_id = nm_utils_hwaddr_ntoa(port_id, port_id_len); break; - case SD_LLDP_PORT_SUBTYPE_NETWORK_ADDRESS: + case NM_LLDP_PORT_SUBTYPE_NETWORK_ADDRESS: s_port_id = format_network_address(port_id, port_id_len); break; } @@ -468,7 +398,7 @@ lldp_neighbor_new(sd_lldp_neighbor *neighbor_sd) neigh = g_slice_new(LldpNeighbor); *neigh = (LldpNeighbor){ - .neighbor_sd = sd_lldp_neighbor_ref(neighbor_sd), + .neighbor_nm = nm_lldp_neighbor_ref(neighbor_nm), .chassis_id_type = chassis_id_type, .chassis_id = g_steal_pointer(&s_chassis_id), .port_id_type = port_id_type, @@ -480,15 +410,15 @@ lldp_neighbor_new(sd_lldp_neighbor *neighbor_sd) static GVariant * lldp_neighbor_to_variant(LldpNeighbor *neigh) { - struct ether_addr destination_address; - GVariantBuilder builder; - const char *str; - const guint8 *raw_data; - gsize raw_len; - uint16_t u16; - uint8_t *data8; - gsize len; - int r; + NMEtherAddr destination_address; + GVariantBuilder builder; + const char *str; + const guint8 *raw_data; + gsize raw_len; + uint16_t u16; + uint8_t *data8; + gsize len; + int r; if (neigh->variant) return neigh->variant; @@ -505,33 +435,33 @@ lldp_neighbor_to_variant(LldpNeighbor *neigh) nm_g_variant_builder_add_sv_uint32(&builder, NM_LLDP_ATTR_PORT_ID_TYPE, neigh->port_id_type); nm_g_variant_builder_add_sv_str(&builder, NM_LLDP_ATTR_PORT_ID, neigh->port_id); - r = sd_lldp_neighbor_get_destination_address(neigh->neighbor_sd, &destination_address); + r = nm_lldp_neighbor_get_destination_address(neigh->neighbor_nm, &destination_address); if (r < 0) str = NULL; - else if (nm_utils_ether_addr_equal(&destination_address, LLDP_MAC_NEAREST_BRIDGE)) + else if (nm_ether_addr_equal(&destination_address, LLDP_MAC_NEAREST_BRIDGE)) str = NM_LLDP_DEST_NEAREST_BRIDGE; - else if (nm_utils_ether_addr_equal(&destination_address, LLDP_MAC_NEAREST_NON_TPMR_BRIDGE)) + else if (nm_ether_addr_equal(&destination_address, LLDP_MAC_NEAREST_NON_TPMR_BRIDGE)) str = NM_LLDP_DEST_NEAREST_NON_TPMR_BRIDGE; - else if (nm_utils_ether_addr_equal(&destination_address, LLDP_MAC_NEAREST_CUSTOMER_BRIDGE)) + else if (nm_ether_addr_equal(&destination_address, LLDP_MAC_NEAREST_CUSTOMER_BRIDGE)) str = NM_LLDP_DEST_NEAREST_CUSTOMER_BRIDGE; else str = NULL; if (str) nm_g_variant_builder_add_sv_str(&builder, NM_LLDP_ATTR_DESTINATION, str); - if (sd_lldp_neighbor_get_port_description(neigh->neighbor_sd, &str) == 0) + if (nm_lldp_neighbor_get_port_description(neigh->neighbor_nm, &str) == 0) nm_g_variant_builder_add_sv_str(&builder, NM_LLDP_ATTR_PORT_DESCRIPTION, str); - if (sd_lldp_neighbor_get_system_name(neigh->neighbor_sd, &str) == 0) + if (nm_lldp_neighbor_get_system_name(neigh->neighbor_nm, &str) == 0) nm_g_variant_builder_add_sv_str(&builder, NM_LLDP_ATTR_SYSTEM_NAME, str); - if (sd_lldp_neighbor_get_system_description(neigh->neighbor_sd, &str) == 0) + if (nm_lldp_neighbor_get_system_description(neigh->neighbor_nm, &str) == 0) nm_g_variant_builder_add_sv_str(&builder, NM_LLDP_ATTR_SYSTEM_DESCRIPTION, str); - if (sd_lldp_neighbor_get_system_capabilities(neigh->neighbor_sd, &u16) == 0) + if (nm_lldp_neighbor_get_system_capabilities(neigh->neighbor_nm, &u16) == 0) nm_g_variant_builder_add_sv_uint32(&builder, NM_LLDP_ATTR_SYSTEM_CAPABILITIES, u16); - r = sd_lldp_neighbor_tlv_rewind(neigh->neighbor_sd); + r = nm_lldp_neighbor_tlv_rewind(neigh->neighbor_nm); if (r < 0) nm_assert_not_reached(); else { @@ -556,14 +486,14 @@ lldp_neighbor_to_variant(LldpNeighbor *neigh) guint8 type; guint8 subtype; - if (sd_lldp_neighbor_tlv_get_type(neigh->neighbor_sd, &type) < 0) + if (nm_lldp_neighbor_tlv_get_type(neigh->neighbor_nm, &type) < 0) continue; - if (sd_lldp_neighbor_tlv_get_raw(neigh->neighbor_sd, (void *) &data8, &len) < 0) + if (nm_lldp_neighbor_tlv_get_raw(neigh->neighbor_nm, (void *) &data8, &len) < 0) continue; switch (type) { - case SD_LLDP_TYPE_MGMT_ADDRESS: + case NM_LLDP_TYPE_MGMT_ADDRESS: tmp_variant = parse_management_address_tlv(data8, len); if (tmp_variant) { if (!v_management_addresses_has) { @@ -573,13 +503,13 @@ lldp_neighbor_to_variant(LldpNeighbor *neigh) g_variant_builder_add_value(&v_management_addresses, tmp_variant); } continue; - case SD_LLDP_TYPE_PRIVATE: + case NM_LLDP_TYPE_PRIVATE: break; default: continue; } - r = sd_lldp_neighbor_tlv_get_oui(neigh->neighbor_sd, oui, &subtype); + r = nm_lldp_neighbor_tlv_get_oui(neigh->neighbor_nm, oui, &subtype); if (r < 0) { if (r == -ENXIO) continue; @@ -609,15 +539,15 @@ lldp_neighbor_to_variant(LldpNeighbor *neigh) data8 += 6; len -= 6; - if (memcmp(oui, SD_LLDP_OUI_802_1, sizeof(oui)) == 0) { + if (memcmp(oui, NM_LLDP_OUI_802_1, sizeof(oui)) == 0) { switch (subtype) { - case SD_LLDP_OUI_802_1_SUBTYPE_PORT_VLAN_ID: + case NM_LLDP_OUI_802_1_SUBTYPE_PORT_VLAN_ID: if (len != 2) continue; if (!v_ieee_802_1_pvid) v_ieee_802_1_pvid = g_variant_new_uint32(unaligned_read_be16(data8)); break; - case SD_LLDP_OUI_802_1_SUBTYPE_PORT_PROTOCOL_VLAN_ID: + case NM_LLDP_OUI_802_1_SUBTYPE_PORT_PROTOCOL_VLAN_ID: if (len != 3) continue; if (!v_ieee_802_1_ppvid) { @@ -633,7 +563,7 @@ lldp_neighbor_to_variant(LldpNeighbor *neigh) g_variant_builder_add_value(&v_ieee_802_1_ppvids, g_variant_builder_end(&tmp_builder)); break; - case SD_LLDP_OUI_802_1_SUBTYPE_VLAN_NAME: + case NM_LLDP_OUI_802_1_SUBTYPE_VLAN_NAME: { gs_free char *name_to_free = NULL; const char *name; @@ -669,9 +599,9 @@ lldp_neighbor_to_variant(LldpNeighbor *neigh) default: continue; } - } else if (memcmp(oui, SD_LLDP_OUI_802_3, sizeof(oui)) == 0) { + } else if (memcmp(oui, NM_LLDP_OUI_802_3, sizeof(oui)) == 0) { switch (subtype) { - case SD_LLDP_OUI_802_3_SUBTYPE_MAC_PHY_CONFIG_STATUS: + case NM_LLDP_OUI_802_3_SUBTYPE_MAC_PHY_CONFIG_STATUS: if (len != 5) continue; @@ -687,7 +617,7 @@ lldp_neighbor_to_variant(LldpNeighbor *neigh) v_ieee_802_3_mac_phy_conf = g_variant_builder_end(&tmp_builder); } break; - case SD_LLDP_OUI_802_3_SUBTYPE_POWER_VIA_MDI: + case NM_LLDP_OUI_802_3_SUBTYPE_POWER_VIA_MDI: if (len != 3) continue; @@ -703,7 +633,7 @@ lldp_neighbor_to_variant(LldpNeighbor *neigh) v_ieee_802_3_power_via_mdi = g_variant_builder_end(&tmp_builder); } break; - case SD_LLDP_OUI_802_3_SUBTYPE_MAXIMUM_FRAME_SIZE: + case NM_LLDP_OUI_802_3_SUBTYPE_MAXIMUM_FRAME_SIZE: if (len != 2) continue; if (!v_ieee_802_3_max_frame_size) @@ -711,9 +641,9 @@ lldp_neighbor_to_variant(LldpNeighbor *neigh) g_variant_new_uint32(unaligned_read_be16(data8)); break; } - } else if (memcmp(oui, SD_LLDP_OUI_IANA, sizeof(oui)) == 0) { + } else if (memcmp(oui, NM_LLDP_OUI_IANA, sizeof(oui)) == 0) { switch (subtype) { - case SD_LLDP_OUI_IANA_SUBTYPE_MUD: + case NM_LLDP_OUI_IANA_SUBTYPE_MUD: if (!v_mud_url) { gs_free char *s_free = NULL; const char *s; @@ -725,7 +655,7 @@ lldp_neighbor_to_variant(LldpNeighbor *neigh) break; } } - } while (sd_lldp_neighbor_tlv_next(neigh->neighbor_sd) > 0); + } while (nm_lldp_neighbor_tlv_next(neigh->neighbor_nm) > 0); if (v_management_addresses_has) nm_g_variant_builder_add_sv(&builder, @@ -777,18 +707,17 @@ lldp_neighbor_to_variant(LldpNeighbor *neigh) GVariant * nmtst_lldp_parse_from_raw(const guint8 *raw_data, gsize raw_len) { - nm_auto(sd_lldp_neighbor_unrefp) sd_lldp_neighbor *neighbor_sd = NULL; - nm_auto(lldp_neighbor_freep) LldpNeighbor *neigh = NULL; - GVariant *variant; - int r; + nm_auto(nm_lldp_neighbor_unrefp) NMLldpNeighbor *neighbor_nm = NULL; + nm_auto(lldp_neighbor_freep) LldpNeighbor *neigh = NULL; + GVariant *variant; g_assert(raw_data); g_assert(raw_len > 0); - r = sd_lldp_neighbor_from_raw(&neighbor_sd, raw_data, raw_len); - g_assert(r >= 0); + neighbor_nm = nm_lldp_neighbor_new_from_raw(raw_data, raw_len); + g_assert(neighbor_nm); - neigh = lldp_neighbor_new(neighbor_sd); + neigh = lldp_neighbor_new(neighbor_nm); g_assert(neigh); variant = lldp_neighbor_to_variant(neigh); @@ -843,18 +772,18 @@ data_changed_schedule(NMLldpListener *self) } static void -process_lldp_neighbor(NMLldpListener *self, sd_lldp_neighbor *neighbor_sd, gboolean remove) +process_lldp_neighbor(NMLldpListener *self, NMLldpNeighbor *neighbor_nm, gboolean remove) { nm_auto(lldp_neighbor_freep) LldpNeighbor *neigh = NULL; LldpNeighbor *neigh_old; nm_assert(self); - nm_assert(self->lldp_handle); + nm_assert(self->lldp_rx); nm_assert(self->lldp_neighbors); - g_return_if_fail(neighbor_sd); + g_return_if_fail(neighbor_nm); - neigh = lldp_neighbor_new(neighbor_sd); + neigh = lldp_neighbor_new(neighbor_nm); if (!neigh) { _LOGT("process: failed to parse neighbor"); return; @@ -884,14 +813,17 @@ handle_changed: } static void -lldp_event_handler(sd_lldp_rx *lldp, sd_lldp_rx_event_t event, sd_lldp_neighbor *n, void *userdata) +lldp_event_handler(NMLldpRX *lldp, NMLldpRXEvent event, NMLldpNeighbor *n, void *user_data) { - process_lldp_neighbor(userdata, + NMLldpListener *self = user_data; + + _LOGD("event: %s", nm_lldp_rx_event_to_string(event)); + process_lldp_neighbor(self, n, !NM_IN_SET(event, - SD_LLDP_RX_EVENT_ADDED, - SD_LLDP_RX_EVENT_UPDATED, - SD_LLDP_RX_EVENT_REFRESHED)); + NM_LLDP_RX_EVENT_ADDED, + NM_LLDP_RX_EVENT_UPDATED, + NM_LLDP_RX_EVENT_REFRESHED)); } /*****************************************************************************/ @@ -935,35 +867,14 @@ nm_lldp_listener_new(int ifindex, gpointer notify_user_data, GError **error) { - NMLldpListener *self = NULL; - sd_lldp_rx *lldp_handle; - int r; + NMLldpListener *self = NULL; + nm_auto(nm_lldp_rx_unrefp) NMLldpRX *lldp_rx = NULL; + int r; g_return_val_if_fail(ifindex > 0, FALSE); g_return_val_if_fail(!error || !*error, FALSE); g_return_val_if_fail(notify_callback, FALSE); - r = sd_lldp_rx_new(&lldp_handle); - if (r < 0) { - g_set_error_literal(error, - NM_DEVICE_ERROR, - NM_DEVICE_ERROR_FAILED, - "initialization failed"); - return FALSE; - } - - r = sd_lldp_rx_set_ifindex(lldp_handle, ifindex); - if (r < 0) { - g_set_error_literal(error, - NM_DEVICE_ERROR, - NM_DEVICE_ERROR_FAILED, - "failed setting ifindex"); - goto fail_handle; - } - - r = sd_lldp_rx_set_neighbors_max(lldp_handle, MAX_NEIGHBORS); - nm_assert(r == 0); - self = g_slice_new(NMLldpListener); *self = (NMLldpListener){ .ifindex = ifindex, @@ -971,39 +882,33 @@ nm_lldp_listener_new(int ifindex, .notify_user_data = notify_user_data, }; - r = sd_lldp_rx_set_callback(lldp_handle, lldp_event_handler, self); - if (r < 0) { - g_set_error_literal(error, NM_DEVICE_ERROR, NM_DEVICE_ERROR_FAILED, "set callback failed"); - goto fail_handle; - } + nm_assert(nm_g_main_context_is_thread_default(g_main_context_default())); - r = sd_lldp_rx_attach_event(lldp_handle, NULL, 0); - if (r < 0) { - g_set_error_literal(error, NM_DEVICE_ERROR, NM_DEVICE_ERROR_FAILED, "attach event failed"); - goto fail_attached; - } + lldp_rx = nm_lldp_rx_new(&((NMLldpRXConfig){ + .ifindex = ifindex, + .neighbors_max = MAX_NEIGHBORS, + .callback = lldp_event_handler, + .userdata = self, + })); - r = sd_lldp_rx_start(lldp_handle); + r = nm_lldp_rx_start(lldp_rx); if (r < 0) { g_set_error_literal(error, NM_DEVICE_ERROR, NM_DEVICE_ERROR_FAILED, "start failed"); - goto fail_attached; + goto fail; } - self->lldp_neighbors = g_hash_table_new_full(lldp_neighbor_id_hash, - lldp_neighbor_id_equal, + self->lldp_neighbors = g_hash_table_new_full((GHashFunc) lldp_neighbor_id_hash, + (GEqualFunc) lldp_neighbor_id_equal, (GDestroyNotify) lldp_neighbor_free, NULL); - self->lldp_handle = lldp_handle; + + self->lldp_rx = g_steal_pointer(&lldp_rx); _LOGD("start lldp listener"); return self; -fail_attached: - sd_lldp_rx_detach_event(lldp_handle); -fail_handle: - if (self) - nm_g_slice_free(self); - sd_lldp_rx_unref(lldp_handle); +fail: + nm_g_slice_free(self); return NULL; } @@ -1012,9 +917,8 @@ nm_lldp_listener_destroy(NMLldpListener *self) { g_return_if_fail(self); - sd_lldp_rx_stop(self->lldp_handle); - sd_lldp_rx_detach_event(self->lldp_handle); - sd_lldp_rx_unref(self->lldp_handle); + nm_lldp_rx_stop(self->lldp_rx); + nm_lldp_rx_unref(self->lldp_rx); nm_clear_g_source_inst(&self->ratelimit_source); diff --git a/src/core/devices/ovs/nm-device-ovs-bridge.c b/src/core/devices/ovs/nm-device-ovs-bridge.c index 048afb02..7b319af3 100644 --- a/src/core/devices/ovs/nm-device-ovs-bridge.c +++ b/src/core/devices/ovs/nm-device-ovs-bridge.c @@ -16,6 +16,7 @@ #include "nm-setting-connection.h" #include "nm-setting-ovs-bridge.h" #include "nm-setting-ovs-external-ids.h" +#include "nm-setting-ovs-other-config.h" #include "libnm-core-intern/nm-core-internal.h" #define _NMLOG_DEVICE_TYPE NMDeviceOvsBridge @@ -124,13 +125,14 @@ nm_device_ovs_reapply_connection(NMDevice *self, NMConnection *con_old, NMConnec device_type = NM_DEVICE_TYPE_OVS_BRIDGE; } - nm_ovsdb_set_external_ids( - nm_ovsdb_get(), - device_type, - nm_device_get_ip_iface(self), - nm_connection_get_uuid(con_new), - _nm_connection_get_setting(con_old, NM_TYPE_SETTING_OVS_EXTERNAL_IDS), - _nm_connection_get_setting(con_new, NM_TYPE_SETTING_OVS_EXTERNAL_IDS)); + nm_ovsdb_set_reapply(nm_ovsdb_get(), + device_type, + nm_device_get_ip_iface(self), + nm_connection_get_uuid(con_new), + _nm_connection_get_setting(con_old, NM_TYPE_SETTING_OVS_EXTERNAL_IDS), + _nm_connection_get_setting(con_new, NM_TYPE_SETTING_OVS_EXTERNAL_IDS), + _nm_connection_get_setting(con_old, NM_TYPE_SETTING_OVS_OTHER_CONFIG), + _nm_connection_get_setting(con_new, NM_TYPE_SETTING_OVS_OTHER_CONFIG)); } /*****************************************************************************/ diff --git a/src/core/devices/ovs/nm-device-ovs-bridge.h b/src/core/devices/ovs/nm-device-ovs-bridge.h index 2b893343..51cc685d 100644 --- a/src/core/devices/ovs/nm-device-ovs-bridge.h +++ b/src/core/devices/ovs/nm-device-ovs-bridge.h @@ -8,7 +8,7 @@ #define NM_TYPE_DEVICE_OVS_BRIDGE (nm_device_ovs_bridge_get_type()) #define NM_DEVICE_OVS_BRIDGE(obj) \ - (G_TYPE_CHECK_INSTANCE_CAST((obj), NM_TYPE_DEVICE_OVS_BRIDGE, NMDeviceOvsBridge)) + (_NM_G_TYPE_CHECK_INSTANCE_CAST((obj), NM_TYPE_DEVICE_OVS_BRIDGE, NMDeviceOvsBridge)) #define NM_DEVICE_OVS_BRIDGE_CLASS(klass) \ (G_TYPE_CHECK_CLASS_CAST((klass), NM_TYPE_DEVICE_OVS_BRIDGE, NMDeviceOvsBridgeClass)) #define NM_IS_DEVICE_OVS_BRIDGE(obj) (G_TYPE_CHECK_INSTANCE_TYPE((obj), NM_TYPE_DEVICE_OVS_BRIDGE)) diff --git a/src/core/devices/ovs/nm-device-ovs-interface.h b/src/core/devices/ovs/nm-device-ovs-interface.h index 03b0e9a4..b8c951d2 100644 --- a/src/core/devices/ovs/nm-device-ovs-interface.h +++ b/src/core/devices/ovs/nm-device-ovs-interface.h @@ -8,7 +8,7 @@ #define NM_TYPE_DEVICE_OVS_INTERFACE (nm_device_ovs_interface_get_type()) #define NM_DEVICE_OVS_INTERFACE(obj) \ - (G_TYPE_CHECK_INSTANCE_CAST((obj), NM_TYPE_DEVICE_OVS_INTERFACE, NMDeviceOvsInterface)) + (_NM_G_TYPE_CHECK_INSTANCE_CAST((obj), NM_TYPE_DEVICE_OVS_INTERFACE, NMDeviceOvsInterface)) #define NM_DEVICE_OVS_INTERFACE_CLASS(klass) \ (G_TYPE_CHECK_CLASS_CAST((klass), NM_TYPE_DEVICE_OVS_INTERFACE, NMDeviceOvsInterfaceClass)) #define NM_IS_DEVICE_OVS_INTERFACE(obj) \ diff --git a/src/core/devices/ovs/nm-device-ovs-port.h b/src/core/devices/ovs/nm-device-ovs-port.h index f4516c01..87446fa4 100644 --- a/src/core/devices/ovs/nm-device-ovs-port.h +++ b/src/core/devices/ovs/nm-device-ovs-port.h @@ -8,7 +8,7 @@ #define NM_TYPE_DEVICE_OVS_PORT (nm_device_ovs_port_get_type()) #define NM_DEVICE_OVS_PORT(obj) \ - (G_TYPE_CHECK_INSTANCE_CAST((obj), NM_TYPE_DEVICE_OVS_PORT, NMDeviceOvsPort)) + (_NM_G_TYPE_CHECK_INSTANCE_CAST((obj), NM_TYPE_DEVICE_OVS_PORT, NMDeviceOvsPort)) #define NM_DEVICE_OVS_PORT_CLASS(klass) \ (G_TYPE_CHECK_CLASS_CAST((klass), NM_TYPE_DEVICE_OVS_PORT, NMDeviceOvsPortClass)) #define NM_IS_DEVICE_OVS_PORT(obj) (G_TYPE_CHECK_INSTANCE_TYPE((obj), NM_TYPE_DEVICE_OVS_PORT)) diff --git a/src/core/devices/ovs/nm-ovs-factory.c b/src/core/devices/ovs/nm-ovs-factory.c index ff2c7858..50023778 100644 --- a/src/core/devices/ovs/nm-ovs-factory.c +++ b/src/core/devices/ovs/nm-ovs-factory.c @@ -27,7 +27,8 @@ typedef struct { } NMOvsFactoryClass; #define NM_TYPE_OVS_FACTORY (nm_ovs_factory_get_type()) -#define NM_OVS_FACTORY(obj) (G_TYPE_CHECK_INSTANCE_CAST((obj), NM_TYPE_OVS_FACTORY, NMOvsFactory)) +#define NM_OVS_FACTORY(obj) \ + (_NM_G_TYPE_CHECK_INSTANCE_CAST((obj), NM_TYPE_OVS_FACTORY, NMOvsFactory)) #define NM_OVS_FACTORY_CLASS(klass) \ (G_TYPE_CHECK_CLASS_CAST((klass), NM_TYPE_OVS_FACTORY, NMOvsFactoryClass)) #define NM_IS_OVS_FACTORY(obj) (G_TYPE_CHECK_INSTANCE_TYPE((obj), NM_TYPE_OVS_FACTORY)) diff --git a/src/core/devices/ovs/nm-ovsdb.c b/src/core/devices/ovs/nm-ovsdb.c index 0d688396..85b7953f 100644 --- a/src/core/devices/ovs/nm-ovsdb.c +++ b/src/core/devices/ovs/nm-ovsdb.c @@ -17,6 +17,7 @@ #include "devices/nm-device.h" #include "nm-manager.h" #include "nm-setting-ovs-external-ids.h" +#include "nm-setting-ovs-other-config.h" #include "nm-priv-helper-call.h" #include "libnm-platform/nm-platform.h" @@ -24,18 +25,26 @@ #define OVSDB_MAX_FAILURES 3 +#define OTHER_CONFIG_HWADDR "hwaddr" + /*****************************************************************************/ #if JANSSON_VERSION_HEX < 0x020400 #warning "requires at least libjansson 2.4" #endif +typedef enum { + STRDICT_TYPE_EXTERNAL_IDS, + STRDICT_TYPE_OTHER_CONFIG, +} StrdictType; + typedef struct { char *port_uuid; char *name; char *connection_uuid; GPtrArray *interfaces; /* interface uuids */ GArray *external_ids; + GArray *other_config; } OpenvswitchPort; typedef struct { @@ -44,6 +53,7 @@ typedef struct { char *connection_uuid; GPtrArray *ports; /* port uuids */ GArray *external_ids; + GArray *other_config; } OpenvswitchBridge; typedef struct { @@ -52,6 +62,7 @@ typedef struct { char *type; char *connection_uuid; GArray *external_ids; + GArray *other_config; } OpenvswitchInterface; /*****************************************************************************/ @@ -66,7 +77,7 @@ typedef enum { OVSDB_ADD_INTERFACE, OVSDB_DEL_INTERFACE, OVSDB_SET_INTERFACE_MTU, - OVSDB_SET_EXTERNAL_IDS, + OVSDB_SET_REAPPLY, } OvsdbCommand; #define CALL_ID_UNSPEC G_MAXUINT64 @@ -92,9 +103,11 @@ typedef union { NMDeviceType device_type; char *ifname; char *connection_uuid; - GHashTable *exid_old; - GHashTable *exid_new; - } set_external_ids; + GHashTable *external_ids_old; + GHashTable *external_ids_new; + GHashTable *other_config_old; + GHashTable *other_config_new; + } set_reapply; } OvsdbMethodPayload; typedef struct { @@ -223,20 +236,24 @@ static void cleanup_check_ready(NMOvsdb *self); }, \ })) -#define OVSDB_METHOD_PAYLOAD_SET_EXTERNAL_IDS(xdevice_type, \ - xifname, \ - xconnection_uuid, \ - xexid_old, \ - xexid_new) \ - (&((const OvsdbMethodPayload){ \ - .set_external_ids = \ - { \ - .device_type = xdevice_type, \ - .ifname = (char *) NM_CONSTCAST(char, (xifname)), \ - .connection_uuid = (char *) NM_CONSTCAST(char, (xconnection_uuid)), \ - .exid_old = (xexid_old), \ - .exid_new = (xexid_new), \ - }, \ +#define OVSDB_METHOD_PAYLOAD_SET_REAPPLY(xdevice_type, \ + xifname, \ + xconnection_uuid, \ + xexternal_ids_old, \ + xexternal_ids_new, \ + xother_config_old, \ + xother_config_new) \ + (&((const OvsdbMethodPayload){ \ + .set_reapply = \ + { \ + .device_type = xdevice_type, \ + .ifname = (char *) NM_CONSTCAST(char, (xifname)), \ + .connection_uuid = (char *) NM_CONSTCAST(char, (xconnection_uuid)), \ + .external_ids_old = (xexternal_ids_old), \ + .external_ids_new = (xexternal_ids_new), \ + .other_config_old = (xother_config_old), \ + .other_config_new = (xother_config_new), \ + }, \ })) /*****************************************************************************/ @@ -291,11 +308,13 @@ _call_complete(OvsdbMethodCall *call, json_t *response, GError *error) case OVSDB_SET_INTERFACE_MTU: nm_clear_g_free(&call->payload.set_interface_mtu.ifname); break; - case OVSDB_SET_EXTERNAL_IDS: - nm_clear_g_free(&call->payload.set_external_ids.ifname); - nm_clear_g_free(&call->payload.set_external_ids.connection_uuid); - nm_clear_pointer(&call->payload.set_external_ids.exid_old, g_hash_table_destroy); - nm_clear_pointer(&call->payload.set_external_ids.exid_new, g_hash_table_destroy); + case OVSDB_SET_REAPPLY: + nm_clear_g_free(&call->payload.set_reapply.ifname); + nm_clear_g_free(&call->payload.set_reapply.connection_uuid); + nm_clear_pointer(&call->payload.set_reapply.external_ids_old, g_hash_table_destroy); + nm_clear_pointer(&call->payload.set_reapply.external_ids_new, g_hash_table_destroy); + nm_clear_pointer(&call->payload.set_reapply.other_config_old, g_hash_table_destroy); + nm_clear_pointer(&call->payload.set_reapply.other_config_new, g_hash_table_destroy); break; } @@ -312,6 +331,7 @@ _free_bridge(OpenvswitchBridge *ovs_bridge) g_free(ovs_bridge->connection_uuid); g_ptr_array_free(ovs_bridge->ports, TRUE); nm_g_array_unref(ovs_bridge->external_ids); + nm_g_array_unref(ovs_bridge->other_config); nm_g_slice_free(ovs_bridge); } @@ -323,6 +343,7 @@ _free_port(OpenvswitchPort *ovs_port) g_free(ovs_port->connection_uuid); g_ptr_array_free(ovs_port->interfaces, TRUE); nm_g_array_unref(ovs_port->external_ids); + nm_g_array_unref(ovs_port->other_config); nm_g_slice_free(ovs_port); } @@ -334,6 +355,7 @@ _free_interface(OpenvswitchInterface *ovs_interface) g_free(ovs_interface->connection_uuid); g_free(ovs_interface->type); nm_g_array_unref(ovs_interface->external_ids); + nm_g_array_unref(ovs_interface->other_config); nm_g_slice_free(ovs_interface); } @@ -447,19 +469,22 @@ ovsdb_call_method(NMOvsdb *self, call->payload.set_interface_mtu.ifname, call->payload.set_interface_mtu.mtu); break; - case OVSDB_SET_EXTERNAL_IDS: - call->payload.set_external_ids.device_type = payload->set_external_ids.device_type; - call->payload.set_external_ids.ifname = g_strdup(payload->set_external_ids.ifname); - call->payload.set_external_ids.connection_uuid = - g_strdup(payload->set_external_ids.connection_uuid); - call->payload.set_external_ids.exid_old = - nm_g_hash_table_ref(payload->set_external_ids.exid_old); - call->payload.set_external_ids.exid_new = - nm_g_hash_table_ref(payload->set_external_ids.exid_new); + case OVSDB_SET_REAPPLY: + call->payload.set_reapply.device_type = payload->set_reapply.device_type; + call->payload.set_reapply.ifname = g_strdup(payload->set_reapply.ifname); + call->payload.set_reapply.connection_uuid = g_strdup(payload->set_reapply.connection_uuid); + call->payload.set_reapply.external_ids_old = + nm_g_hash_table_ref(payload->set_reapply.external_ids_old); + call->payload.set_reapply.external_ids_new = + nm_g_hash_table_ref(payload->set_reapply.external_ids_new); + call->payload.set_reapply.other_config_old = + nm_g_hash_table_ref(payload->set_reapply.other_config_old); + call->payload.set_reapply.other_config_new = + nm_g_hash_table_ref(payload->set_reapply.other_config_new); _LOGT_call(call, - "new: set-external-ids con-uuid=%s, interface=%s", - call->payload.set_external_ids.connection_uuid, - call->payload.set_external_ids.ifname); + "new: set external-ids/other-config con-uuid=%s, interface=%s", + call->payload.set_reapply.connection_uuid, + call->payload.set_reapply.ifname); break; } @@ -604,12 +629,12 @@ _set_bridge_mac(json_t *params, const char *ifname, const char *mac) "other_config", "delete", "set", - "hwaddr", + OTHER_CONFIG_HWADDR, "other_config", "insert", "map", - "hwaddr", + OTHER_CONFIG_HWADDR, mac, "where", @@ -677,92 +702,155 @@ _set_port_interfaces(json_t *params, const char *ifname, json_t *new_interfaces) } static json_t * -_j_create_external_ids_array_new(NMConnection *connection) +_j_create_strdict_new(NMConnection *connection, + StrdictType strdict_type, + const char *other_config_hwaddr) { + NMSettingOvsOtherConfig *s_other_config = NULL; + NMSettingOvsExternalIDs *s_external_ids = NULL; json_t *array; - const char *const *external_ids = NULL; - guint n_external_ids = 0; + const char *const *strv = NULL; + guint n_strv = 0; guint i; const char *uuid; - NMSettingOvsExternalIDs *s_exid; nm_assert(NM_IS_CONNECTION(connection)); + nm_assert(NM_IN_SET(strdict_type, STRDICT_TYPE_EXTERNAL_IDS, STRDICT_TYPE_OTHER_CONFIG)); array = json_array(); - uuid = nm_connection_get_uuid(connection); - nm_assert(uuid); - json_array_append_new(array, json_pack("[s, s]", NM_OVS_EXTERNAL_ID_NM_CONNECTION_UUID, uuid)); + if (strdict_type == STRDICT_TYPE_EXTERNAL_IDS) { + uuid = nm_connection_get_uuid(connection); + nm_assert(uuid); + json_array_append_new(array, + json_pack("[s, s]", NM_OVS_EXTERNAL_ID_NM_CONNECTION_UUID, uuid)); + } else { + if (other_config_hwaddr) { + json_array_append_new(array, + json_pack("[s, s]", OTHER_CONFIG_HWADDR, other_config_hwaddr)); + } + } + + if (strdict_type == STRDICT_TYPE_EXTERNAL_IDS) { + s_external_ids = _nm_connection_get_setting(connection, NM_TYPE_SETTING_OVS_EXTERNAL_IDS); + if (s_external_ids) + strv = nm_setting_ovs_external_ids_get_data_keys(s_external_ids, &n_strv); + } else { + s_other_config = _nm_connection_get_setting(connection, NM_TYPE_SETTING_OVS_OTHER_CONFIG); + if (s_other_config) + strv = nm_setting_ovs_other_config_get_data_keys(s_other_config, &n_strv); + } + + for (i = 0; i < n_strv; i++) { + const char *k = strv[i]; - s_exid = _nm_connection_get_setting(connection, NM_TYPE_SETTING_OVS_EXTERNAL_IDS); - if (s_exid) - external_ids = nm_setting_ovs_external_ids_get_data_keys(s_exid, &n_external_ids); - for (i = 0; i < n_external_ids; i++) { - const char *k = external_ids[i]; + if (strdict_type == STRDICT_TYPE_OTHER_CONFIG && other_config_hwaddr + && nm_streq(k, OTHER_CONFIG_HWADDR)) { + /* "hwaddr" is explicitly overwritten. */ + continue; + } json_array_append_new( array, - json_pack("[s, s]", k, nm_setting_ovs_external_ids_get_data(s_exid, k))); + json_pack("[s, s]", + k, + strdict_type == STRDICT_TYPE_EXTERNAL_IDS + ? nm_setting_ovs_external_ids_get_data(s_external_ids, k) + : nm_setting_ovs_other_config_get_data(s_other_config, k))); } return json_pack("[s, o]", "map", array); } -static json_t * -_j_create_external_ids_array_update(const char *connection_uuid, - GHashTable *exid_old, - GHashTable *exid_new) +static void +_j_create_strv_array_update(json_t *mutations, + StrdictType strdict_type, + const char *connection_uuid, + GHashTable *hash_old, + GHashTable *hash_new) { GHashTableIter iter; - json_t *mutations; json_t *array; const char *key; const char *val; - nm_assert(connection_uuid); + /* This is called during reapply. We accept reapplying all settings, + * except other_config:hwaddr. That one cannot change and is specially + * handled below. The reason is that we knew the correct "hwaddr" during + * _j_create_strdict_new(), but we don't do now. At least not easily, + * and it's not clear that reapply of the MAC address is really useful. */ - mutations = json_array(); + nm_assert((!!connection_uuid) == (strdict_type == STRDICT_TYPE_EXTERNAL_IDS)); + nm_assert(NM_IN_SET(strdict_type, STRDICT_TYPE_EXTERNAL_IDS, STRDICT_TYPE_OTHER_CONFIG)); - array = json_array(); - if (exid_old) { - g_hash_table_iter_init(&iter, exid_old); + array = NULL; + if (hash_old) { + g_hash_table_iter_init(&iter, hash_old); while (g_hash_table_iter_next(&iter, (gpointer *) &key, NULL)) { + if (strdict_type == STRDICT_TYPE_OTHER_CONFIG && nm_streq(key, OTHER_CONFIG_HWADDR)) + continue; + if (!array) + array = json_array(); json_array_append_new(array, json_string(key)); } } - if (exid_new) { - g_hash_table_iter_init(&iter, exid_new); + if (hash_new) { + g_hash_table_iter_init(&iter, hash_new); while (g_hash_table_iter_next(&iter, (gpointer *) &key, NULL)) { - if (nm_g_hash_table_contains(exid_old, key)) + if (strdict_type == STRDICT_TYPE_OTHER_CONFIG && nm_streq(key, OTHER_CONFIG_HWADDR)) continue; + if (nm_g_hash_table_contains(hash_old, key)) + continue; + if (!array) + array = json_array(); json_array_append_new(array, json_string(key)); } } - if (!nm_g_hash_table_contains(exid_old, NM_OVS_EXTERNAL_ID_NM_PREFIX) - && !nm_g_hash_table_contains(exid_new, NM_OVS_EXTERNAL_ID_NM_PREFIX)) { - json_array_append_new(array, json_string(NM_OVS_EXTERNAL_ID_NM_PREFIX)); + if (strdict_type == STRDICT_TYPE_EXTERNAL_IDS) { + if (!nm_g_hash_table_contains(hash_old, NM_OVS_EXTERNAL_ID_NM_PREFIX) + && !nm_g_hash_table_contains(hash_new, NM_OVS_EXTERNAL_ID_NM_PREFIX)) { + if (!array) + array = json_array(); + json_array_append_new(array, json_string(NM_OVS_EXTERNAL_ID_NM_PREFIX)); + } + } + if (array) { + json_array_append_new( + mutations, + json_pack("[s, s, [s, o]]", + strdict_type == STRDICT_TYPE_EXTERNAL_IDS ? "external_ids" : "other_config", + "delete", + "set", + array)); } - json_array_append_new(mutations, - json_pack("[s, s, [s, o]]", "external_ids", "delete", "set", array)); array = json_array(); - json_array_append_new( - array, - json_pack("[s, s]", NM_OVS_EXTERNAL_ID_NM_CONNECTION_UUID, connection_uuid)); - - if (exid_new) { - g_hash_table_iter_init(&iter, exid_new); + if (strdict_type == STRDICT_TYPE_EXTERNAL_IDS) { + json_array_append_new( + array, + json_pack("[s, s]", NM_OVS_EXTERNAL_ID_NM_CONNECTION_UUID, connection_uuid)); + } + if (hash_new) { + g_hash_table_iter_init(&iter, hash_new); while (g_hash_table_iter_next(&iter, (gpointer *) &key, (gpointer *) &val)) { - if (NM_STR_HAS_PREFIX(key, NM_OVS_EXTERNAL_ID_NM_PREFIX)) + if (strdict_type == STRDICT_TYPE_EXTERNAL_IDS) { + if (NM_STR_HAS_PREFIX(key, NM_OVS_EXTERNAL_ID_NM_PREFIX)) + continue; + } + if (strdict_type == STRDICT_TYPE_OTHER_CONFIG && nm_streq(key, OTHER_CONFIG_HWADDR)) continue; json_array_append_new(array, json_pack("[s, s]", key, val)); } } - json_array_append_new(mutations, - json_pack("[s, s, [s, o]]", "external_ids", "insert", "map", array)); - return mutations; + json_array_append_new( + mutations, + json_pack("[s, s, [s, o]]", + strdict_type == STRDICT_TYPE_EXTERNAL_IDS ? "external_ids" : "other_config", + "insert", + "map", + array)); } /** @@ -779,18 +867,19 @@ _insert_interface(json_t *params, const char *type = NULL; NMSettingOvsInterface *s_ovs_iface; NMSettingOvsDpdk *s_ovs_dpdk; - const char *devargs; - guint32 n_rxq; char sbuf[64]; json_t *dpdk_array; NMSettingOvsPatch *s_ovs_patch; json_t *options = json_array(); json_t *row; - guint32 mtu = 0; + guint32 mtu = 0; + guint32 ofport_request = 0; s_ovs_iface = nm_connection_get_setting_ovs_interface(interface); - if (s_ovs_iface) - type = nm_setting_ovs_interface_get_interface_type(s_ovs_iface); + if (s_ovs_iface) { + type = nm_setting_ovs_interface_get_interface_type(s_ovs_iface); + ofport_request = nm_setting_ovs_interface_get_ofport_request(s_ovs_iface); + } if (nm_streq0(type, "internal")) { NMSettingWired *s_wired; @@ -808,8 +897,15 @@ _insert_interface(json_t *params, s_ovs_patch = nm_connection_get_setting_ovs_patch(interface); if (s_ovs_dpdk) { - devargs = nm_setting_ovs_dpdk_get_devargs(s_ovs_dpdk); - n_rxq = nm_setting_ovs_dpdk_get_n_rxq(s_ovs_dpdk); + const char *devargs; + guint32 n_rxq; + guint32 n_rxq_desc; + guint32 n_txq_desc; + + devargs = nm_setting_ovs_dpdk_get_devargs(s_ovs_dpdk); + n_rxq = nm_setting_ovs_dpdk_get_n_rxq(s_ovs_dpdk); + n_rxq_desc = nm_setting_ovs_dpdk_get_n_rxq_desc(s_ovs_dpdk); + n_txq_desc = nm_setting_ovs_dpdk_get_n_txq_desc(s_ovs_dpdk); dpdk_array = json_array(); @@ -820,6 +916,16 @@ _insert_interface(json_t *params, json_array_append_new(dpdk_array, json_pack("[s,s]", "n_rxq", nm_sprintf_buf(sbuf, "%u", n_rxq))); } + if (n_rxq_desc != 0) { + json_array_append_new( + dpdk_array, + json_pack("[s,s]", "n_rxq_desc", nm_sprintf_buf(sbuf, "%u", n_rxq_desc))); + } + if (n_txq_desc != 0) { + json_array_append_new( + dpdk_array, + json_pack("[s,s]", "n_txq_desc", nm_sprintf_buf(sbuf, "%u", n_txq_desc))); + } json_array_append_new(options, dpdk_array); @@ -831,7 +937,7 @@ _insert_interface(json_t *params, json_array_append_new(options, json_array()); } - row = json_pack("{s:s, s:s, s:o, s:o}", + row = json_pack("{s:s, s:s, s:o, s:o, s:o}", "name", nm_connection_get_interface_name(interface), "type", @@ -839,7 +945,9 @@ _insert_interface(json_t *params, "options", options, "external_ids", - _j_create_external_ids_array_new(interface)); + _j_create_strdict_new(interface, STRDICT_TYPE_EXTERNAL_IDS, NULL), + "other_config", + _j_create_strdict_new(interface, STRDICT_TYPE_OTHER_CONFIG, NULL)); if (cloned_mac) json_object_set_new(row, "mac", json_string(cloned_mac)); @@ -847,6 +955,9 @@ _insert_interface(json_t *params, if (mtu != 0) json_object_set_new(row, "mtu_request", json_integer(mtu)); + if (ofport_request != 0) + json_object_set_new(row, "ofport_request", json_integer(ofport_request)); + json_array_append_new(params, json_pack("{s:s, s:s, s:o, s:s}", "op", @@ -869,6 +980,7 @@ _insert_port(json_t *params, NMConnection *port, json_t *new_interfaces) { NMSettingOvsPort *s_ovs_port; const char *vlan_mode = NULL; + json_t *trunks = NULL; guint tag = 0; const char *lacp = NULL; const char *bond_mode = NULL; @@ -881,18 +993,34 @@ _insert_port(json_t *params, NMConnection *port, json_t *new_interfaces) row = json_object(); if (s_ovs_port) { + const GPtrArray *ranges; + guint i; + guint64 start; + guint64 end; + vlan_mode = nm_setting_ovs_port_get_vlan_mode(s_ovs_port); tag = nm_setting_ovs_port_get_tag(s_ovs_port); lacp = nm_setting_ovs_port_get_lacp(s_ovs_port); bond_mode = nm_setting_ovs_port_get_bond_mode(s_ovs_port); bond_updelay = nm_setting_ovs_port_get_bond_updelay(s_ovs_port); bond_downdelay = nm_setting_ovs_port_get_bond_downdelay(s_ovs_port); + + ranges = _nm_setting_ovs_port_get_trunks_arr(s_ovs_port); + for (i = 0; i < ranges->len; i++) { + if (!trunks) + trunks = json_array(); + nm_range_get_range(ranges->pdata[i], &start, &end); + for (; start <= end; start++) + json_array_append_new(trunks, json_integer(start)); + } } if (vlan_mode) json_object_set_new(row, "vlan_mode", json_string(vlan_mode)); if (tag) json_object_set_new(row, "tag", json_integer(tag)); + if (trunks) + json_object_set_new(row, "trunks", json_pack("[s, o]", "set", trunks)); if (lacp) json_object_set_new(row, "lacp", json_string(lacp)); if (bond_mode) @@ -904,7 +1032,12 @@ _insert_port(json_t *params, NMConnection *port, json_t *new_interfaces) json_object_set_new(row, "name", json_string(nm_connection_get_interface_name(port))); json_object_set_new(row, "interfaces", json_pack("[s, O]", "set", new_interfaces)); - json_object_set_new(row, "external_ids", _j_create_external_ids_array_new(port)); + json_object_set_new(row, + "external_ids", + _j_create_strdict_new(port, STRDICT_TYPE_EXTERNAL_IDS, NULL)); + json_object_set_new(row, + "other_config", + _j_create_strdict_new(port, STRDICT_TYPE_OTHER_CONFIG, NULL)); /* Create a new one. */ json_array_append_new(params, @@ -964,13 +1097,12 @@ _insert_bridge(json_t *params, 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)); - json_object_set_new(row, "external_ids", _j_create_external_ids_array_new(bridge)); - - if (cloned_mac) { - json_object_set_new(row, - "other_config", - json_pack("[s, [[s, s]]]", "map", "hwaddr", cloned_mac)); - } + json_object_set_new(row, + "external_ids", + _j_create_strdict_new(bridge, STRDICT_TYPE_EXTERNAL_IDS, NULL)); + json_object_set_new(row, + "other_config", + _j_create_strdict_new(bridge, STRDICT_TYPE_OTHER_CONFIG, cloned_mac)); /* Create a new one. */ json_array_append_new(params, @@ -1332,9 +1464,9 @@ ovsdb_next_command(NMOvsdb *self) switch (call->command) { case OVSDB_MONITOR: 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:[{s:[s, s, s, s, s]}]," " s:[{s:[]}]" "}]}", "id", @@ -1348,16 +1480,19 @@ ovsdb_next_command(NMOvsdb *self) "name", "ports", "external_ids", + "other_config", "Port", "columns", "name", "interfaces", "external_ids", + "other_config", "Interface", "columns", "name", "type", "external_ids", + "other_config", "error", "Open_vSwitch", "columns"); @@ -1398,24 +1533,38 @@ ovsdb_next_command(NMOvsdb *self) "==", call->payload.set_interface_mtu.ifname)); break; - case OVSDB_SET_EXTERNAL_IDS: + case OVSDB_SET_REAPPLY: + { + json_t *mutations; + + mutations = json_array(); + + _j_create_strv_array_update(mutations, + STRDICT_TYPE_EXTERNAL_IDS, + call->payload.set_reapply.connection_uuid, + call->payload.set_reapply.external_ids_old, + call->payload.set_reapply.external_ids_new); + _j_create_strv_array_update(mutations, + STRDICT_TYPE_OTHER_CONFIG, + NULL, + call->payload.set_reapply.other_config_old, + call->payload.set_reapply.other_config_new); + json_array_append_new( params, json_pack("{s:s, s:s, s:o, s:[[s, s, s]]}", "op", "mutate", "table", - _device_type_to_table(call->payload.set_external_ids.device_type), + _device_type_to_table(call->payload.set_reapply.device_type), "mutations", - _j_create_external_ids_array_update( - call->payload.set_external_ids.connection_uuid, - call->payload.set_external_ids.exid_old, - call->payload.set_external_ids.exid_new), + mutations, "where", "name", "==", - call->payload.set_external_ids.ifname)); + call->payload.set_reapply.ifname)); break; + } default: nm_assert_not_reached(); @@ -1500,19 +1649,18 @@ _uuids_to_array(const json_t *items) } static void -_external_ids_extract(json_t *external_ids, GArray **out_array, const char **out_connection_uuid) +_strdict_extract(json_t *strdict, GArray **out_array) { json_t *array; json_t *value; gsize index; nm_assert(out_array && !*out_array); - nm_assert(!out_connection_uuid || !*out_connection_uuid); - if (!nm_streq0("map", json_string_value(json_array_get(external_ids, 0)))) + if (!nm_streq0("map", json_string_value(json_array_get(strdict, 0)))) return; - array = json_array_get(external_ids, 1); + array = json_array_get(strdict, 1); json_array_foreach (array, index, value) { const char *key = json_string_value(json_array_get(value, 0)); @@ -1533,16 +1681,26 @@ _external_ids_extract(json_t *external_ids, GArray **out_array, const char **out .name = g_strdup(key), .value_str = g_strdup(val), }; - - if (out_connection_uuid && nm_streq(v->name, NM_OVS_EXTERNAL_ID_NM_CONNECTION_UUID)) { - *out_connection_uuid = v->value_str; - out_connection_uuid = NULL; - } } } +static const char * +_strdict_find_key(GArray *array, const char *key) +{ + gssize idx; + + idx = nm_utils_named_value_list_find(nm_g_array_first_p(array, NMUtilsNamedValue), + nm_g_array_len(array), + key, + FALSE); + if (idx < 0) + return NULL; + + return nm_g_array_index(array, NMUtilsNamedValue, idx).value_str; +} + static gboolean -_external_ids_equal(const GArray *arr1, const GArray *arr2) +_strdict_equals(const GArray *arr1, const GArray *arr2) { guint n; guint i; @@ -1552,19 +1710,19 @@ _external_ids_equal(const GArray *arr1, const GArray *arr2) if (n != nm_g_array_len(arr2)) return FALSE; for (i = 0; i < n; i++) { - const NMUtilsNamedValue *n1 = &g_array_index(arr1, NMUtilsNamedValue, i); - const NMUtilsNamedValue *n2 = &g_array_index(arr2, NMUtilsNamedValue, i); + const NMUtilsNamedValue *n1 = &nm_g_array_index(arr1, NMUtilsNamedValue, i); + const NMUtilsNamedValue *n2 = &nm_g_array_index(arr2, NMUtilsNamedValue, i); - if (!nm_streq0(n1->name, n2->name)) + if (!nm_streq(n1->name, n2->name)) return FALSE; - if (!nm_streq0(n1->value_str, n2->value_str)) + if (!nm_streq(n1->value_str, n2->value_str)) return FALSE; } return TRUE; } static char * -_external_ids_to_string(const GArray *arr) +_strdict_to_string(const GArray *arr) { NMStrBuf strbuf; guint i; @@ -1575,7 +1733,7 @@ _external_ids_to_string(const GArray *arr) strbuf = NM_STR_BUF_INIT(NM_UTILS_GET_NEXT_REALLOC_SIZE_104, FALSE); nm_str_buf_append(&strbuf, "["); for (i = 0; i < arr->len; i++) { - const NMUtilsNamedValue *n = &g_array_index(arr, NMUtilsNamedValue, i); + const NMUtilsNamedValue *n = &nm_g_array_index(arr, NMUtilsNamedValue, i); if (i > 0) nm_str_buf_append_c(&strbuf, ','); @@ -1605,8 +1763,9 @@ ovsdb_got_update(NMOvsdb *self, json_t *msg) json_t *interface = NULL; json_t *items; json_t *external_ids; + json_t *other_config; json_error_t json_error = { - 0, + 0, }; void *iter; const char *name; @@ -1644,12 +1803,13 @@ ovsdb_got_update(NMOvsdb *self, json_t *msg) json_object_foreach (interface, key, value) { OpenvswitchInterface *ovs_interface; gs_unref_array GArray *external_ids_arr = NULL; + gs_unref_array GArray *other_config_arr = NULL; const char *connection_uuid = NULL; json_t *error = NULL; int r; r = json_unpack(value, - "{s:{s:s, s:s, s?:o, s:o}}", + "{s:{s:s, s:s, s?:o, s:o, s:o}}", "new", "name", &name, @@ -1658,7 +1818,9 @@ ovsdb_got_update(NMOvsdb *self, json_t *msg) "error", &error, "external_ids", - &external_ids); + &external_ids, + "other_config", + &other_config); if (r != 0) { gpointer unused; @@ -1701,7 +1863,10 @@ ovsdb_got_update(NMOvsdb *self, json_t *msg) nm_clear_pointer(&ovs_interface, _free_interface); } - _external_ids_extract(external_ids, &external_ids_arr, &connection_uuid); + _strdict_extract(external_ids, &external_ids_arr); + connection_uuid = + _strdict_find_key(external_ids_arr, NM_OVS_EXTERNAL_ID_NM_CONNECTION_UUID); + _strdict_extract(other_config, &other_config_arr); if (ovs_interface) { gboolean changed = FALSE; @@ -1710,14 +1875,20 @@ ovsdb_got_update(NMOvsdb *self, json_t *msg) changed |= nm_strdup_reset(&ovs_interface->type, type); changed |= nm_strdup_reset(&ovs_interface->connection_uuid, connection_uuid); - if (!_external_ids_equal(ovs_interface->external_ids, external_ids_arr)) { + if (!_strdict_equals(ovs_interface->external_ids, external_ids_arr)) { NM_SWAP(&ovs_interface->external_ids, &external_ids_arr); changed = TRUE; } + if (!_strdict_equals(ovs_interface->other_config, other_config_arr)) { + NM_SWAP(&ovs_interface->other_config, &other_config_arr); + changed = TRUE; + } if (changed) { - gs_free char *strtmp = NULL; + gs_free char *strtmp1 = NULL; + gs_free char *strtmp2 = NULL; - _LOGT("obj[iface:%s]: changed an '%s' interface: %s%s%s, external-ids=%s", + _LOGT("obj[iface:%s]: changed an '%s' interface: %s%s%s, external-ids=%s, " + "other-config=%s", key, type, ovs_interface->name, @@ -1725,10 +1896,12 @@ ovsdb_got_update(NMOvsdb *self, json_t *msg) ", ", ovs_interface->connection_uuid, ""), - (strtmp = _external_ids_to_string(ovs_interface->external_ids))); + (strtmp1 = _strdict_to_string(ovs_interface->external_ids)), + (strtmp2 = _strdict_to_string(ovs_interface->other_config))); } } else { - gs_free char *strtmp = NULL; + gs_free char *strtmp1 = NULL; + gs_free char *strtmp2 = NULL; ovs_interface = g_slice_new(OpenvswitchInterface); *ovs_interface = (OpenvswitchInterface){ @@ -1737,17 +1910,20 @@ ovsdb_got_update(NMOvsdb *self, json_t *msg) .type = g_strdup(type), .connection_uuid = g_strdup(connection_uuid), .external_ids = g_steal_pointer(&external_ids_arr), + .other_config = g_steal_pointer(&other_config_arr), }; g_hash_table_add(priv->interfaces, ovs_interface); - _LOGT("obj[iface:%s]: added an '%s' interface: %s%s%s, external-ids=%s", - key, - ovs_interface->type, - ovs_interface->name, - NM_PRINT_FMT_QUOTED2(ovs_interface->connection_uuid, - ", ", - ovs_interface->connection_uuid, - ""), - (strtmp = _external_ids_to_string(ovs_interface->external_ids))); + _LOGT( + "obj[iface:%s]: added an '%s' interface: %s%s%s, external-ids=%s, other-config=%s", + key, + ovs_interface->type, + ovs_interface->name, + NM_PRINT_FMT_QUOTED2(ovs_interface->connection_uuid, + ", ", + ovs_interface->connection_uuid, + ""), + (strtmp1 = _strdict_to_string(ovs_interface->external_ids)), + (strtmp2 = _strdict_to_string(ovs_interface->other_config))); _signal_emit_device_added(self, ovs_interface->name, NM_DEVICE_TYPE_OVS_INTERFACE, @@ -1768,16 +1944,19 @@ ovsdb_got_update(NMOvsdb *self, json_t *msg) gs_unref_ptrarray GPtrArray *interfaces = NULL; OpenvswitchPort *ovs_port; gs_unref_array GArray *external_ids_arr = NULL; + gs_unref_array GArray *other_config_arr = NULL; const char *connection_uuid = NULL; int r; r = json_unpack(value, - "{s:{s:s, s:o, s:o}}", + "{s:{s:s, s:o, s:o, s:o}}", "new", "name", &name, "external_ids", &external_ids, + "other_config", + &other_config, "interfaces", &items); if (r != 0) { @@ -1811,7 +1990,11 @@ ovsdb_got_update(NMOvsdb *self, json_t *msg) nm_clear_pointer(&ovs_port, _free_port); } - _external_ids_extract(external_ids, &external_ids_arr, &connection_uuid); + _strdict_extract(external_ids, &external_ids_arr); + connection_uuid = + _strdict_find_key(external_ids_arr, NM_OVS_EXTERNAL_ID_NM_CONNECTION_UUID); + _strdict_extract(other_config, &other_config_arr); + interfaces = _uuids_to_array(items); if (ovs_port) { @@ -1825,24 +2008,31 @@ ovsdb_got_update(NMOvsdb *self, json_t *msg) NM_SWAP(&ovs_port->interfaces, &interfaces); changed = TRUE; } - if (!_external_ids_equal(ovs_port->external_ids, external_ids_arr)) { + if (!_strdict_equals(ovs_port->external_ids, external_ids_arr)) { NM_SWAP(&ovs_port->external_ids, &external_ids_arr); changed = TRUE; } + if (!_strdict_equals(ovs_port->other_config, other_config_arr)) { + NM_SWAP(&ovs_port->other_config, &other_config_arr); + changed = TRUE; + } if (changed) { - gs_free char *strtmp = NULL; + gs_free char *strtmp1 = NULL; + gs_free char *strtmp2 = NULL; - _LOGT("obj[port:%s]: changed a port: %s%s%s, external-ids=%s", + _LOGT("obj[port:%s]: changed a port: %s%s%s, external-ids=%s, other-config=%s", key, ovs_port->name, NM_PRINT_FMT_QUOTED2(ovs_port->connection_uuid, ", ", ovs_port->connection_uuid, ""), - (strtmp = _external_ids_to_string(ovs_port->external_ids))); + (strtmp1 = _strdict_to_string(ovs_port->external_ids)), + (strtmp2 = _strdict_to_string(ovs_port->other_config))); } } else { - gs_free char *strtmp = NULL; + gs_free char *strtmp1 = NULL; + gs_free char *strtmp2 = NULL; ovs_port = g_slice_new(OpenvswitchPort); *ovs_port = (OpenvswitchPort){ @@ -1851,16 +2041,18 @@ ovsdb_got_update(NMOvsdb *self, json_t *msg) .connection_uuid = g_strdup(connection_uuid), .interfaces = g_steal_pointer(&interfaces), .external_ids = g_steal_pointer(&external_ids_arr), + .other_config = g_steal_pointer(&other_config_arr), }; g_hash_table_add(priv->ports, ovs_port); - _LOGT("obj[port:%s]: added a port: %s%s%s, external-ids=%s", + _LOGT("obj[port:%s]: added a port: %s%s%s, external-ids=%s, other-config=%s", key, ovs_port->name, NM_PRINT_FMT_QUOTED2(ovs_port->connection_uuid, ", ", ovs_port->connection_uuid, ""), - (strtmp = _external_ids_to_string(ovs_port->external_ids))); + (strtmp1 = _strdict_to_string(ovs_port->external_ids)), + (strtmp2 = _strdict_to_string(ovs_port->other_config))); _signal_emit_device_added(self, ovs_port->name, NM_DEVICE_TYPE_OVS_PORT, NULL); } } @@ -1869,16 +2061,19 @@ ovsdb_got_update(NMOvsdb *self, json_t *msg) gs_unref_ptrarray GPtrArray *ports = NULL; OpenvswitchBridge *ovs_bridge; gs_unref_array GArray *external_ids_arr = NULL; + gs_unref_array GArray *other_config_arr = NULL; const char *connection_uuid = NULL; int r; r = json_unpack(value, - "{s:{s:s, s:o, s:o}}", + "{s:{s:s, s:o, s:o, s:o}}", "new", "name", &name, "external_ids", &external_ids, + "other_config", + &other_config, "ports", &items); @@ -1916,7 +2111,11 @@ ovsdb_got_update(NMOvsdb *self, json_t *msg) nm_clear_pointer(&ovs_bridge, _free_bridge); } - _external_ids_extract(external_ids, &external_ids_arr, &connection_uuid); + _strdict_extract(external_ids, &external_ids_arr); + connection_uuid = + _strdict_find_key(external_ids_arr, NM_OVS_EXTERNAL_ID_NM_CONNECTION_UUID); + _strdict_extract(other_config, &other_config_arr); + ports = _uuids_to_array(items); if (ovs_bridge) { @@ -1930,24 +2129,31 @@ ovsdb_got_update(NMOvsdb *self, json_t *msg) NM_SWAP(&ovs_bridge->ports, &ports); changed = TRUE; } - if (!_external_ids_equal(ovs_bridge->external_ids, external_ids_arr)) { + if (!_strdict_equals(ovs_bridge->external_ids, external_ids_arr)) { NM_SWAP(&ovs_bridge->external_ids, &external_ids_arr); changed = TRUE; } + if (!_strdict_equals(ovs_bridge->other_config, other_config_arr)) { + NM_SWAP(&ovs_bridge->other_config, &other_config_arr); + changed = TRUE; + } if (changed) { - gs_free char *strtmp = NULL; + gs_free char *strtmp1 = NULL; + gs_free char *strtmp2 = NULL; - _LOGT("obj[bridge:%s]: changed a bridge: %s%s%s, external-ids=%s", + _LOGT("obj[bridge:%s]: changed a bridge: %s%s%s, external-ids=%s, other-config=%s", key, ovs_bridge->name, NM_PRINT_FMT_QUOTED2(ovs_bridge->connection_uuid, ", ", ovs_bridge->connection_uuid, ""), - (strtmp = _external_ids_to_string(ovs_bridge->external_ids))); + (strtmp1 = _strdict_to_string(ovs_bridge->external_ids)), + (strtmp2 = _strdict_to_string(ovs_bridge->external_ids))); } } else { - gs_free char *strtmp = NULL; + gs_free char *strtmp1 = NULL; + gs_free char *strtmp2 = NULL; ovs_bridge = g_slice_new(OpenvswitchBridge); *ovs_bridge = (OpenvswitchBridge){ @@ -1956,16 +2162,18 @@ ovsdb_got_update(NMOvsdb *self, json_t *msg) .connection_uuid = g_strdup(connection_uuid), .ports = g_steal_pointer(&ports), .external_ids = g_steal_pointer(&external_ids_arr), + .other_config = g_steal_pointer(&other_config_arr), }; g_hash_table_add(priv->bridges, ovs_bridge); - _LOGT("obj[bridge:%s]: added a bridge: %s%s%s, external-ids=%s", + _LOGT("obj[bridge:%s]: added a bridge: %s%s%s, external-ids=%s, other-config=%s", key, ovs_bridge->name, NM_PRINT_FMT_QUOTED2(ovs_bridge->connection_uuid, ", ", ovs_bridge->connection_uuid, ""), - (strtmp = _external_ids_to_string(ovs_bridge->external_ids))); + (strtmp1 = _strdict_to_string(ovs_bridge->external_ids)), + (strtmp2 = _strdict_to_string(ovs_bridge->other_config))); _signal_emit_device_added(self, ovs_bridge->name, NM_DEVICE_TYPE_OVS_BRIDGE, NULL); } } @@ -2007,7 +2215,7 @@ ovsdb_got_msg(NMOvsdb *self, json_t *msg) { NMOvsdbPrivate *priv = NM_OVSDB_GET_PRIVATE(self); json_error_t json_error = { - 0, + 0, }; json_t *json_id = NULL; json_int_t id = (json_int_t) -1; @@ -2149,7 +2357,7 @@ ovsdb_read_cb(GObject *source_object, GAsyncResult *res, gpointer user_data) gssize size; json_t *msg; json_error_t json_error = { - 0, + 0, }; size = g_input_stream_read_finish(stream, res, &error); @@ -2703,31 +2911,50 @@ nm_ovsdb_set_interface_mtu(NMOvsdb *self, } void -nm_ovsdb_set_external_ids(NMOvsdb *self, - NMDeviceType device_type, - const char *ifname, - const char *connection_uuid, - NMSettingOvsExternalIDs *s_exid_old, - NMSettingOvsExternalIDs *s_exid_new) +nm_ovsdb_set_reapply(NMOvsdb *self, + NMDeviceType device_type, + const char *ifname, + const char *connection_uuid, + NMSettingOvsExternalIDs *s_external_ids_old, + NMSettingOvsExternalIDs *s_external_ids_new, + NMSettingOvsOtherConfig *s_other_config_old, + NMSettingOvsOtherConfig *s_other_config_new) { - gs_unref_hashtable GHashTable *exid_old = NULL; - gs_unref_hashtable GHashTable *exid_new = NULL; - - exid_old = - s_exid_old ? nm_strdict_clone(_nm_setting_ovs_external_ids_get_data(s_exid_old)) : NULL; - exid_new = - s_exid_new ? nm_strdict_clone(_nm_setting_ovs_external_ids_get_data(s_exid_new)) : NULL; + gs_unref_hashtable GHashTable *external_ids_old = NULL; + gs_unref_hashtable GHashTable *external_ids_new = NULL; + gs_unref_hashtable GHashTable *other_config_old = NULL; + gs_unref_hashtable GHashTable *other_config_new = NULL; + + external_ids_old = + s_external_ids_old + ? nm_strdict_clone(_nm_setting_ovs_external_ids_get_data(s_external_ids_old)) + : NULL; + external_ids_new = + s_external_ids_new + ? nm_strdict_clone(_nm_setting_ovs_external_ids_get_data(s_external_ids_new)) + : NULL; + + other_config_old = + s_other_config_old + ? nm_strdict_clone(_nm_setting_ovs_other_config_get_data(s_other_config_old)) + : NULL; + other_config_new = + s_other_config_new + ? nm_strdict_clone(_nm_setting_ovs_other_config_get_data(s_other_config_new)) + : NULL; ovsdb_call_method(self, NULL, NULL, FALSE, - OVSDB_SET_EXTERNAL_IDS, - OVSDB_METHOD_PAYLOAD_SET_EXTERNAL_IDS(device_type, - ifname, - connection_uuid, - exid_old, - exid_new)); + OVSDB_SET_REAPPLY, + OVSDB_METHOD_PAYLOAD_SET_REAPPLY(device_type, + ifname, + connection_uuid, + external_ids_old, + external_ids_new, + other_config_old, + other_config_new)); } /*****************************************************************************/ diff --git a/src/core/devices/ovs/nm-ovsdb.h b/src/core/devices/ovs/nm-ovsdb.h index a50db45a..a022ff00 100644 --- a/src/core/devices/ovs/nm-ovsdb.h +++ b/src/core/devices/ovs/nm-ovsdb.h @@ -7,7 +7,7 @@ #define __NETWORKMANAGER_OVSDB_H__ #define NM_TYPE_OVSDB (nm_ovsdb_get_type()) -#define NM_OVSDB(obj) (G_TYPE_CHECK_INSTANCE_CAST((obj), NM_TYPE_OVSDB, NMOvsdb)) +#define NM_OVSDB(obj) (_NM_G_TYPE_CHECK_INSTANCE_CAST((obj), NM_TYPE_OVSDB, NMOvsdb)) #define NM_OVSDB_CLASS(klass) (G_TYPE_CHECK_CLASS_CAST((klass), NM_TYPE_OVSDB, NMOvsdbClass)) #define NM_IS_OVSDB(obj) (G_TYPE_CHECK_INSTANCE_TYPE((obj), NM_TYPE_OVSDB)) #define NM_IS_OVSDB_CLASS(klass) (G_TYPE_CHECK_CLASS_TYPE((klass), NM_TYPE_OVSDB)) @@ -47,14 +47,14 @@ void nm_ovsdb_set_interface_mtu(NMOvsdb *self, NMOvsdbCallback callback, gpointer user_data); -struct _NMSettingOvsExternalIDs; - -void nm_ovsdb_set_external_ids(NMOvsdb *self, - NMDeviceType device_type, - const char *ifname, - const char *connection_uuid, - struct _NMSettingOvsExternalIDs *s_exid_old, - struct _NMSettingOvsExternalIDs *s_exid_new); +void nm_ovsdb_set_reapply(NMOvsdb *self, + NMDeviceType device_type, + const char *ifname, + const char *connection_uuid, + NMSettingOvsExternalIDs *s_external_ids_old, + NMSettingOvsExternalIDs *s_external_ids_new, + NMSettingOvsOtherConfig *s_other_config_old, + NMSettingOvsOtherConfig *s_other_config_new); gboolean nm_ovsdb_is_ready(NMOvsdb *self); diff --git a/src/core/devices/team/nm-device-team.c b/src/core/devices/team/nm-device-team.c index 9eca008a..3e3fe52b 100644 --- a/src/core/devices/team/nm-device-team.c +++ b/src/core/devices/team/nm-device-team.c @@ -144,6 +144,7 @@ _update_port_config(NMDeviceTeam *self, const char *port_iface, const char *sani NMDeviceTeamPrivate *priv = NM_DEVICE_TEAM_GET_PRIVATE(self); int err; + _LOGT(LOGD_TEAM, "setting port config: %s", sanitized_config); err = teamdctl_port_config_update_raw(priv->tdc, port_iface, sanitized_config); if (err != 0) { _LOGE(LOGD_TEAM, "failed to update config for port %s (err=%d)", port_iface, err); @@ -154,23 +155,20 @@ _update_port_config(NMDeviceTeam *self, const char *port_iface, const char *sani } static gboolean -ensure_teamd_connection(NMDevice *device) +ensure_teamd_connection(NMDevice *device, GError **error) { - NMDeviceTeam *self = NM_DEVICE_TEAM(device); - NMDeviceTeamPrivate *priv = NM_DEVICE_TEAM_GET_PRIVATE(self); - gs_free_error GError *error = NULL; - const char *port_iface; - const char *port_config; - GHashTableIter iter; + NMDeviceTeam *self = NM_DEVICE_TEAM(device); + NMDeviceTeamPrivate *priv = NM_DEVICE_TEAM_GET_PRIVATE(self); + const char *port_iface; + const char *port_config; + GHashTableIter iter; if (priv->tdc) return TRUE; - priv->tdc = _tdc_connect_new(self, nm_device_get_iface(device), &error); - if (!priv->tdc) { - _LOGE(LOGD_TEAM, "failed to connect to teamd: %s", error->message); + priv->tdc = _tdc_connect_new(self, nm_device_get_iface(device), error); + if (!priv->tdc) return FALSE; - } g_hash_table_iter_init(&iter, priv->port_configs); while (g_hash_table_iter_next(&iter, (gpointer *) &port_iface, (gpointer *) &port_config)) @@ -229,10 +227,17 @@ update_connection(NMDevice *device, NMConnection *connection) NMSettingTeam *s_team = _nm_connection_ensure_setting(connection, NM_TYPE_SETTING_TEAM); NMDeviceTeamPrivate *priv = NM_DEVICE_TEAM_GET_PRIVATE(self); struct teamdctl *tdc = priv->tdc; + GError *error = NULL; /* Read the configuration only if not already set */ - if (!priv->config && ensure_teamd_connection(device)) - teamd_read_config(self); + if (!priv->config) { + if (ensure_teamd_connection(device, &error)) { + teamd_read_config(self); + } else { + _LOGD(LOGD_TEAM, "could not connect to teamd: %s", error->message); + g_clear_error(&error); + } + } /* Restore previous tdc state */ if (priv->tdc && !tdc) { @@ -258,9 +263,10 @@ master_update_slave_connection(NMDevice *device, gs_free_error GError *connect_error = NULL; int err = 0; struct teamdctl *tdc; - const char *team_port_config = NULL; - const char *iface = nm_device_get_iface(device); - const char *iface_slave = nm_device_get_iface(slave); + const char *team_port_config = NULL; + const char *iface = nm_device_get_iface(device); + const char *iface_slave = nm_device_get_iface(slave); + NMConnection *applied_connection = nm_device_get_applied_connection(device); tdc = _tdc_connect_new(self, iface, &connect_error); if (!tdc) { @@ -299,7 +305,7 @@ master_update_slave_connection(NMDevice *device, g_object_set(nm_connection_get_setting_connection(connection), NM_SETTING_CONNECTION_MASTER, - iface, + nm_connection_get_uuid(applied_connection), NM_SETTING_CONNECTION_SLAVE_TYPE, NM_SETTING_TEAM_SETTING_NAME, NULL); @@ -397,6 +403,7 @@ teamd_ready(NMDeviceTeam *self) NMDeviceTeamPrivate *priv = NM_DEVICE_TEAM_GET_PRIVATE(self); NMDevice *device = NM_DEVICE(self); gboolean success; + GError *error = NULL; if (priv->kill_in_progress) { /* If we are currently killing teamd, we are not @@ -410,7 +417,11 @@ teamd_ready(NMDeviceTeam *self) * immediately. But if we are, and grabbing it failed, fail the * device activation. */ - success = ensure_teamd_connection(device); + success = ensure_teamd_connection(device, &error); + if (!success) { + _LOGW(LOGD_TEAM, "could not connect to teamd: %s", error->message); + g_clear_error(&error); + } if (nm_device_get_state(device) != NM_DEVICE_STATE_PREPARE || priv->stage1_state != NM_DEVICE_STAGE_STATE_PENDING) @@ -759,18 +770,20 @@ teamd_start(NMDeviceTeam *self) static NMActStageReturn act_stage1_prepare(NMDevice *device, NMDeviceStateReason *out_failure_reason) { - NMDeviceTeam *self = NM_DEVICE_TEAM(device); - NMDeviceTeamPrivate *priv = NM_DEVICE_TEAM_GET_PRIVATE(self); - gs_free_error GError *error = NULL; - NMSettingTeam *s_team; - const char *cfg; + NMDeviceTeam *self = NM_DEVICE_TEAM(device); + NMDeviceTeamPrivate *priv = NM_DEVICE_TEAM_GET_PRIVATE(self); + GError *error = NULL; + NMSettingTeam *s_team; + const char *cfg; if (nm_device_sys_iface_state_is_external(device)) return NM_ACT_STAGE_RETURN_SUCCESS; if (nm_device_sys_iface_state_is_external_or_assume(device)) { - if (ensure_teamd_connection(device)) + if (ensure_teamd_connection(device, &error)) return NM_ACT_STAGE_RETURN_SUCCESS; + _LOGD(LOGD_TEAM, "could not connect to teamd: %s", error->message); + g_clear_error(&error); } s_team = nm_device_get_applied_setting(device, NM_TYPE_SETTING_TEAM); @@ -803,6 +816,7 @@ act_stage1_prepare(NMDevice *device, NMDeviceStateReason *out_failure_reason) _LOGW(LOGD_TEAM, "existing teamd config mismatch; failed to kill existing teamd: %s", error->message); + g_clear_error(&error); NM_SET_OUT(out_failure_reason, NM_DEVICE_STATE_REASON_TEAMD_CONTROL_FAILED); return NM_ACT_STAGE_RETURN_FAILURE; } diff --git a/src/core/devices/team/nm-device-team.h b/src/core/devices/team/nm-device-team.h index 6f5cff93..e2a54c6e 100644 --- a/src/core/devices/team/nm-device-team.h +++ b/src/core/devices/team/nm-device-team.h @@ -9,7 +9,8 @@ #include "devices/nm-device.h" #define NM_TYPE_DEVICE_TEAM (nm_device_team_get_type()) -#define NM_DEVICE_TEAM(obj) (G_TYPE_CHECK_INSTANCE_CAST((obj), NM_TYPE_DEVICE_TEAM, NMDeviceTeam)) +#define NM_DEVICE_TEAM(obj) \ + (_NM_G_TYPE_CHECK_INSTANCE_CAST((obj), NM_TYPE_DEVICE_TEAM, NMDeviceTeam)) #define NM_DEVICE_TEAM_CLASS(klass) \ (G_TYPE_CHECK_CLASS_CAST((klass), NM_TYPE_DEVICE_TEAM, NMDeviceTeamClass)) #define NM_IS_DEVICE_TEAM(obj) (G_TYPE_CHECK_INSTANCE_TYPE((obj), NM_TYPE_DEVICE_TEAM)) diff --git a/src/core/devices/team/nm-team-factory.c b/src/core/devices/team/nm-team-factory.c index b446cbd0..68ea914e 100644 --- a/src/core/devices/team/nm-team-factory.c +++ b/src/core/devices/team/nm-team-factory.c @@ -17,7 +17,7 @@ #define NM_TYPE_TEAM_FACTORY (nm_team_factory_get_type()) #define NM_TEAM_FACTORY(obj) \ - (G_TYPE_CHECK_INSTANCE_CAST((obj), NM_TYPE_TEAM_FACTORY, NMTeamFactory)) + (_NM_G_TYPE_CHECK_INSTANCE_CAST((obj), NM_TYPE_TEAM_FACTORY, NMTeamFactory)) #define NM_TEAM_FACTORY_CLASS(klass) \ (G_TYPE_CHECK_CLASS_CAST((klass), NM_TYPE_TEAM_FACTORY, NMTeamFactoryClass)) #define NM_IS_TEAM_FACTORY(obj) (G_TYPE_CHECK_INSTANCE_TYPE((obj), NM_TYPE_TEAM_FACTORY)) diff --git a/src/core/devices/tests/test-lldp.c b/src/core/devices/tests/test-lldp.c index 048410c1..4cd602f7 100644 --- a/src/core/devices/tests/test-lldp.c +++ b/src/core/devices/tests/test-lldp.c @@ -12,9 +12,8 @@ #include <sys/stat.h> #include <sys/types.h> +#include "libnm-lldp/nm-lldp.h" #include "devices/nm-lldp-listener.h" -#include "libnm-systemd-core/nm-sd.h" - #include "platform/tests/test-common.h" #include "nm-test-utils-core.h" @@ -191,9 +190,9 @@ _test_recv_data0_check_do(GMainLoop *loop, NMLldpListener *listener, const TestR g_assert_cmpint(g_variant_n_children(neighbors), ==, 1); neighbor = get_lldp_neighbor(neighbors, - SD_LLDP_CHASSIS_SUBTYPE_MAC_ADDRESS, + NM_LLDP_CHASSIS_SUBTYPE_MAC_ADDRESS, "00:01:02:03:04:05", - SD_LLDP_PORT_SUBTYPE_INTERFACE_NAME, + NM_LLDP_PORT_SUBTYPE_INTERFACE_NAME, "1/3"); g_assert(neighbor); g_assert_cmpint(g_variant_n_children(neighbor), ==, 1 + 4 + 4); @@ -547,9 +546,9 @@ _test_recv_data1_check(GMainLoop *loop, NMLldpListener *listener, TestRecvCallba g_assert_cmpint(g_variant_n_children(neighbors), ==, 1); neighbor = get_lldp_neighbor(neighbors, - SD_LLDP_CHASSIS_SUBTYPE_MAC_ADDRESS, + NM_LLDP_CHASSIS_SUBTYPE_MAC_ADDRESS, "00:01:30:F9:AD:A0", - SD_LLDP_PORT_SUBTYPE_INTERFACE_NAME, + NM_LLDP_PORT_SUBTYPE_INTERFACE_NAME, "1/1"); g_assert(neighbor); g_assert_cmpint(g_variant_n_children(neighbor), ==, 1 + 4 + 16); @@ -874,7 +873,6 @@ test_recv(TestRecvFixture *fixture, gconstpointer user_data) TestRecvCallbackInfo info = {}; gsize i_frames; GError *error = NULL; - guint sd_id; if (fixture->ifindex == 0) { g_test_skip("Tun device not available"); @@ -884,8 +882,7 @@ test_recv(TestRecvFixture *fixture, gconstpointer user_data) listener = nm_lldp_listener_new(fixture->ifindex, lldp_neighbors_changed, &info, &error); nmtst_assert_success(listener, error); - loop = g_main_loop_new(NULL, FALSE); - sd_id = nm_sd_event_attach_default(); + loop = g_main_loop_new(NULL, FALSE); for (i_frames = 0; i_frames < data->frames_len; i_frames++) { const TestRecvFrame *f = data->frames[i_frames]; @@ -902,7 +899,6 @@ test_recv(TestRecvFixture *fixture, gconstpointer user_data) nm_clear_pointer(&listener, nm_lldp_listener_destroy); - nm_clear_g_source(&sd_id); nm_clear_pointer(&loop, g_main_loop_unref); } diff --git a/src/core/devices/wifi/nm-device-iwd-p2p.h b/src/core/devices/wifi/nm-device-iwd-p2p.h index 9ce353c0..98cf3762 100644 --- a/src/core/devices/wifi/nm-device-iwd-p2p.h +++ b/src/core/devices/wifi/nm-device-iwd-p2p.h @@ -11,7 +11,7 @@ #define NM_TYPE_DEVICE_IWD_P2P (nm_device_iwd_p2p_get_type()) #define NM_DEVICE_IWD_P2P(obj) \ - (G_TYPE_CHECK_INSTANCE_CAST((obj), NM_TYPE_DEVICE_IWD_P2P, NMDeviceIwdP2P)) + (_NM_G_TYPE_CHECK_INSTANCE_CAST((obj), NM_TYPE_DEVICE_IWD_P2P, NMDeviceIwdP2P)) #define NM_DEVICE_IWD_P2P_CLASS(klass) \ (G_TYPE_CHECK_CLASS_CAST((klass), NM_TYPE_DEVICE_IWD_P2P, NMDeviceIwdP2PClass)) #define NM_IS_DEVICE_IWD_P2P(obj) (G_TYPE_CHECK_INSTANCE_TYPE((obj), NM_TYPE_DEVICE_IWD_P2P)) diff --git a/src/core/devices/wifi/nm-device-iwd.c b/src/core/devices/wifi/nm-device-iwd.c index ab37cbec..e03227cd 100644 --- a/src/core/devices/wifi/nm-device-iwd.c +++ b/src/core/devices/wifi/nm-device-iwd.c @@ -8,6 +8,7 @@ #include "nm-device-iwd.h" #include <linux/if_ether.h> +#include <linux/rtnetlink.h> #include "devices/nm-device-private.h" #include "devices/nm-device.h" @@ -32,6 +33,7 @@ #include "supplicant/nm-supplicant-types.h" #include "nm-auth-utils.h" #include "nm-manager.h" +#include "nm-l3-config-data.h" #define _NMLOG_DEVICE_TYPE NMDeviceIwd #include "devices/nm-device-logging.h" @@ -70,6 +72,7 @@ typedef struct { bool secrets_failed : 1; bool networks_requested : 1; bool networks_changed : 1; + bool assuming : 1; gint64 last_scan; uint32_t ap_id; guint32 rate; @@ -77,6 +80,16 @@ typedef struct { GDBusMethodInvocation *pending_agent_request; NMActiveConnection *assumed_ac; guint assumed_ac_timeout; + + union { + struct { + const NML3ConfigData *pending_l3cd_6; + const NML3ConfigData *pending_l3cd_4; + }; + const NML3ConfigData *pending_l3cd_x[2]; + }; + + NMIwdManager *manager; } NMDeviceIwdPrivate; struct _NMDeviceIwd { @@ -289,6 +302,7 @@ insert_ap_from_network(NMDeviceIwd *self, gint64 last_seen_msec, int16_t signal) { + NMDeviceIwdPrivate *priv = NM_DEVICE_IWD_GET_PRIVATE(self); gs_unref_object GDBusProxy *network_proxy = NULL; nm_auto_ref_string NMRefString *bss_path = nm_ref_string_new(path); NMWifiAP *ap; @@ -299,7 +313,7 @@ insert_ap_from_network(NMDeviceIwd *self, } network_proxy = - nm_iwd_manager_get_dbus_interface(nm_iwd_manager_get(), path, NM_IWD_NETWORK_INTERFACE); + nm_iwd_manager_get_dbus_interface(priv->manager, path, NM_IWD_NETWORK_INTERFACE); ap = ap_from_network(self, network_proxy, bss_path, last_seen_msec, signal); if (!ap) @@ -525,6 +539,9 @@ cleanup_association_attempt(NMDeviceIwd *self, gboolean disconnect) if (disconnect && priv->dbus_station_proxy) send_disconnect(self); + + nm_clear_l3cd(&priv->pending_l3cd_6); + nm_clear_l3cd(&priv->pending_l3cd_4); } static void @@ -581,6 +598,10 @@ deactivate(NMDevice *device) if (!priv->dbus_obj) return; + /* Don't cause IWD to break the connection being assumed */ + if (priv->assuming) + return; + if (priv->dbus_station_proxy) { gs_unref_variant GVariant *value = g_dbus_proxy_get_cached_property(priv->dbus_station_proxy, "State"); @@ -673,7 +694,7 @@ deactivate_async(NMDevice *device, } static gboolean -is_connection_known_network(NMConnection *connection) +is_connection_known_network(NMIwdManager *manager, NMConnection *connection) { NMIwdNetworkSecurity security; gs_free char *ssid = NULL; @@ -681,17 +702,17 @@ is_connection_known_network(NMConnection *connection) if (!nm_wifi_connection_get_iwd_ssid_and_security(connection, &ssid, &security)) return FALSE; - return nm_iwd_manager_is_known_network(nm_iwd_manager_get(), ssid, security); + return nm_iwd_manager_is_known_network(manager, ssid, security); } static gboolean -is_ap_known_network(NMWifiAP *ap) +is_ap_known_network(NMIwdManager *manager, NMWifiAP *ap) { gs_unref_object GDBusProxy *network_proxy = NULL; gs_unref_variant GVariant *known_network = NULL; network_proxy = - nm_iwd_manager_get_dbus_interface(nm_iwd_manager_get(), + nm_iwd_manager_get_dbus_interface(manager, nm_ref_string_get_str(nm_wifi_ap_get_supplicant_path(ap)), NM_IWD_NETWORK_INTERFACE); if (!network_proxy) @@ -794,7 +815,8 @@ check_connection_compatible(NMDevice *device, NMConnection *connection, GError * * thus are Known Networks. */ if (security == NM_IWD_NETWORK_SECURITY_8021X) { - if (!is_connection_known_network(connection)) { + if (!is_connection_known_network(priv->manager, connection) + && !nm_iwd_manager_is_recently_mirrored(priv->manager, ssid)) { nm_utils_error_set_literal(error, NM_UTILS_ERROR_CONNECTION_AVAILABLE_INCOMPATIBLE, "802.1x connections must have IWD provisioning files"); @@ -927,7 +949,9 @@ check_connection_available(NMDevice *device, */ if (nm_wifi_connection_get_iwd_ssid_and_security(connection, NULL, &security) && security == NM_IWD_NETWORK_SECURITY_8021X) { - if (!is_ap_known_network(ap)) { + if (!is_ap_known_network(priv->manager, ap) + && !nm_iwd_manager_is_recently_mirrored(priv->manager, + nm_setting_wireless_get_ssid(s_wifi))) { nm_utils_error_set_literal( error, NM_UTILS_ERROR_CONNECTION_AVAILABLE_TEMPORARY, @@ -2044,7 +2068,7 @@ assume_connection(NMDeviceIwd *self, NMWifiAP *ap) * becomes "managed" only when ACTIVATED but for IWD it's really * managed when IP_CONFIG starts. */ - sett_conn = nm_iwd_manager_get_ap_mirror_connection(nm_iwd_manager_get(), ap); + sett_conn = nm_iwd_manager_get_ap_mirror_connection(priv->manager, ap); if (!sett_conn) goto error; @@ -2217,7 +2241,8 @@ act_stage1_prepare(NMDevice *device, NMDeviceStateReason *out_failure_reason) * for a first-time connection to a hidden network. If a hidden network is * a Known Network it should still have been in the AP list. */ - if (!nm_setting_wireless_get_hidden(s_wireless) || is_connection_known_network(connection)) + if (!nm_setting_wireless_get_hidden(s_wireless) + || is_connection_known_network(priv->manager, connection)) return NM_ACT_STAGE_RETURN_FAILURE; add_new: @@ -2270,6 +2295,18 @@ act_stage2_config(NMDevice *device, NMDeviceStateReason *out_failure_reason) goto out_fail; } + /* With priv->iwd_autoconnect we have to let IWD handle retries for + * infrastructure networks. IWD will not necessarily retry the same + * network after a failure but it will likely go into an autoconnect + * mode and we don't want to try to override the logic. We don't need + * to reset the retry count so we set no timeout. + */ + if (priv->iwd_autoconnect) { + NMSettingsConnection *sett_conn = nm_act_request_get_settings_connection(req); + + nm_settings_connection_autoconnect_retries_set(sett_conn, 0); + } + /* With priv->iwd_autoconnect, if we're assuming a connection because * of a state change to "connecting", signal stage 2 is still running. * If "connected" or "roaming", we can go right to the IP_CONFIG state @@ -2310,7 +2347,9 @@ act_stage2_config(NMDevice *device, NMDeviceStateReason *out_failure_reason) * fail, for other combinations we will let the Connect call fail * or ask us for any missing secrets through the Agent. */ - if (nm_connection_get_setting_802_1x(connection) && !is_ap_known_network(ap)) { + if (nm_connection_get_setting_802_1x(connection) && !is_ap_known_network(priv->manager, ap) + && !nm_iwd_manager_is_recently_mirrored(priv->manager, + nm_setting_wireless_get_ssid(s_wireless))) { _LOGI(LOGD_DEVICE | LOGD_WIFI, "Activation: (wifi) access point '%s' has 802.1x security but is not configured " "in IWD.", @@ -2351,7 +2390,7 @@ act_stage2_config(NMDevice *device, NMDeviceStateReason *out_failure_reason) } network_proxy = nm_iwd_manager_get_dbus_interface( - nm_iwd_manager_get(), + priv->manager, nm_ref_string_get_str(nm_wifi_ap_get_supplicant_path(ap)), NM_IWD_NETWORK_INTERFACE); if (!network_proxy) { @@ -2421,6 +2460,38 @@ out_fail: return NM_ACT_STAGE_RETURN_FAILURE; } +static void +act_stage3_ip_config(NMDevice *device, int addr_family) +{ + NMDeviceIwd *self = NM_DEVICE_IWD(device); + NMDeviceIwdPrivate *priv = NM_DEVICE_IWD_GET_PRIVATE(self); + const int IS_IPv4 = NM_IS_IPv4(addr_family); + + if (!nm_iwd_manager_get_netconfig_enabled(nm_iwd_manager_get())) { + NMDeviceClass *device_class = NM_DEVICE_CLASS(nm_device_iwd_parent_class); + + if (device_class->act_stage3_ip_config) + device_class->act_stage3_ip_config(device, addr_family); + + return; + } + + if (!priv->pending_l3cd_x[IS_IPv4]) + return; + + nm_device_devip_set_state(device, + addr_family, + NM_DEVICE_IP_STATE_READY, + priv->pending_l3cd_x[IS_IPv4]); + nm_clear_l3cd(&priv->pending_l3cd_x[IS_IPv4]); +} + +static gboolean +ready_for_ip_config(NMDevice *device, gboolean is_manual) +{ + return !nm_iwd_manager_get_netconfig_enabled(nm_iwd_manager_get()); +} + static guint32 get_configured_mtu(NMDevice *device, NMDeviceMtuSource *out_source, gboolean *out_force) { @@ -2719,12 +2790,20 @@ state_changed(NMDeviceIwd *self, const char *new_state) "IWD is connecting to the wrong AP, %s activation", switch_ap ? "replacing" : "aborting"); cleanup_association_attempt(self, !switch_ap); + + if (!switch_ap) { + nm_device_state_changed(device, + NM_DEVICE_STATE_FAILED, + NM_DEVICE_STATE_REASON_SUPPLICANT_DISCONNECT); + return; + } + + priv->assuming = TRUE; /* Don't send Station.Disconnect() */ nm_device_state_changed(device, - NM_DEVICE_STATE_FAILED, + NM_DEVICE_STATE_DISCONNECTED, NM_DEVICE_STATE_REASON_SUPPLICANT_DISCONNECT); - - if (switch_ap) - assume_connection(self, ap); + priv->assuming = FALSE; + assume_connection(self, ap); return; } @@ -3101,7 +3180,7 @@ nm_device_iwd_set_dbus_object(NMDeviceIwd *self, GDBusObject *object) goto error; } - adapter_proxy = nm_iwd_manager_get_dbus_interface(nm_iwd_manager_get(), + adapter_proxy = nm_iwd_manager_get_dbus_interface(priv->manager, g_variant_get_string(value, NULL), NM_IWD_WIPHY_INTERFACE); if (!adapter_proxy) { @@ -3278,7 +3357,7 @@ nm_device_iwd_agent_query(NMDeviceIwd *self, GDBusMethodInvocation *invocation) * it. IWD only queries us if it has not saved the PSK (e.g. by policy) * or a previous attempt has failed with current secrets so it wants a * fresh value. It doesn't know about agent-owned secrets so whenever - * possible and the PSK is saved and not asked from NM. However if this + * possible, the PSK is saved and not asked from NM. However if this * is a new connection it may include all of the needed settings already * so allow using these, too. Connection timestamp is set after * activation or after first activation failure (to 0). @@ -3368,6 +3447,341 @@ nm_device_iwd_network_add_remove(NMDeviceIwd *self, GDBusProxy *network, bool ad } } +static const NML3ConfigData * +nm_device_iwd_parse_netconfig(NMDeviceIwd *self, int addr_family, GVariantIter *config_iter) +{ + NMDevice *device = NM_DEVICE(self); + nm_auto_unref_l3cd_init NML3ConfigData *l3cd = NULL; + const char *key; + GVariant *value; + NMIPConfigSource source = NM_IP_CONFIG_SOURCE_UNKNOWN; + nm_auto_free_variant_iter GVariantIter *address_iter = NULL; + nm_auto_free_variant_iter GVariantIter *route_iter = NULL; + nm_auto_free_variant_iter GVariantIter *dns_iter = NULL; + nm_auto_free_variant_iter GVariantIter *domain_iter = NULL; + NMSettingConnectionMdns mdns = NM_SETTING_CONNECTION_MDNS_DEFAULT; + const char *str_value; + GVariantIter *entry_iter; + uint32_t timestamp = nm_utils_get_monotonic_timestamp_sec(); + + while (g_variant_iter_next(config_iter, "{&sv}", &key, &value)) { + _nm_unused gs_unref_variant GVariant *value_free = value; + + if (nm_streq(key, "Method")) { + if (!g_variant_is_of_type(value, G_VARIANT_TYPE_STRING) + || source != NM_IP_CONFIG_SOURCE_UNKNOWN) + goto param_error; + + str_value = g_variant_get_string(value, NULL); + if (nm_streq(str_value, "static")) + source = NM_IP_CONFIG_SOURCE_USER; + else if (nm_streq(str_value, "auto")) + /* Use SOURCE_DHCP as shorthand for the various autoconfiguration protocols */ + source = NM_IP_CONFIG_SOURCE_DHCP; + else + _LOGW(LOGD_WIFI, "iwd_parse_netconfig: Uknown Method value \"%s\"", str_value); + } + + if (nm_streq(key, "Addresses")) { + if (!g_variant_is_of_type(value, G_VARIANT_TYPE("aa{sv}")) || address_iter) + goto param_error; + + g_variant_get(value, "aa{sv}", &address_iter); + } + + if (nm_streq(key, "Routes")) { + if (!g_variant_is_of_type(value, G_VARIANT_TYPE("aa{sv}")) || route_iter) + goto param_error; + + g_variant_get(value, "aa{sv}", &route_iter); + } + + if (nm_streq(key, "DomainNameServers")) { + if (!g_variant_is_of_type(value, G_VARIANT_TYPE_STRING_ARRAY) || dns_iter) + goto param_error; + + g_variant_get(value, "as", &dns_iter); + } + + if (nm_streq(key, "DomainNames")) { + if (!g_variant_is_of_type(value, G_VARIANT_TYPE_STRING_ARRAY) || domain_iter) + goto param_error; + + g_variant_get(value, "as", &domain_iter); + } + + if (nm_streq(key, "MDNS")) { + if (!g_variant_is_of_type(value, G_VARIANT_TYPE_STRING) + || mdns != NM_SETTING_CONNECTION_MDNS_DEFAULT) + goto param_error; + + str_value = g_variant_get_string(value, NULL); + if (nm_streq(str_value, "yes")) + mdns = NM_SETTING_CONNECTION_MDNS_YES; + else if (nm_streq(str_value, "no")) + mdns = NM_SETTING_CONNECTION_MDNS_NO; + else if (nm_streq(str_value, "resolve")) + mdns = NM_SETTING_CONNECTION_MDNS_RESOLVE; + else + _LOGW(LOGD_WIFI, "iwd_parse_netconfig: Uknown MDNS value \"%s\"", str_value); + } + } + + if (!address_iter || !route_iter) + goto param_error; + + l3cd = nm_l3_config_data_new(nm_device_get_multi_index(device), + nm_device_get_ip_ifindex(device), + source); + + while (g_variant_iter_next(address_iter, "a{sv}", &entry_iter)) { + _nm_unused nm_auto_free_variant_iter GVariantIter *entry_iter_free = entry_iter; + const char *addr_str = NULL; + NMIPAddr addr_bin; + uint8_t plen = 0; + const char *bcast_str = NULL; + NMIPAddr bcast_bin = {}; + uint32_t valid_lifetime = NM_PLATFORM_LIFETIME_PERMANENT; + uint32_t preferred_lifetime = NM_PLATFORM_LIFETIME_PERMANENT; + NMPlatformIPXAddress a; + + while (g_variant_iter_next(entry_iter, "{&sv}", &key, &value)) { + _nm_unused gs_unref_variant GVariant *value_free = value; + + if (nm_streq(key, "Address")) { + if (!g_variant_is_of_type(value, G_VARIANT_TYPE_STRING) || addr_str) + goto param_error; + + addr_str = g_variant_get_string(value, NULL); + if (inet_pton(addr_family, addr_str, &addr_bin) != 1) + goto param_error; + } + + if (nm_streq(key, "PrefixLength")) { + if (!g_variant_is_of_type(value, G_VARIANT_TYPE_BYTE)) + goto param_error; + + plen = g_variant_get_byte(value); + } + + if (nm_streq(key, "Broadcast")) { + if (!g_variant_is_of_type(value, G_VARIANT_TYPE_STRING) || bcast_str) + goto param_error; + + bcast_str = g_variant_get_string(value, NULL); + if (inet_pton(addr_family, bcast_str, &bcast_bin) != 1) + goto param_error; + } + + if (nm_streq(key, "ValidLifetime")) { + if (!g_variant_is_of_type(value, G_VARIANT_TYPE_UINT32) + || valid_lifetime != NM_PLATFORM_LIFETIME_PERMANENT) + goto param_error; + + valid_lifetime = g_variant_get_uint32(value); + } + + if (nm_streq(key, "PreferredLifetime")) { + if (!g_variant_is_of_type(value, G_VARIANT_TYPE_UINT32) + || preferred_lifetime != NM_PLATFORM_LIFETIME_PERMANENT) + goto param_error; + + preferred_lifetime = g_variant_get_uint32(value); + } + } + + if (addr_str == NULL) + goto param_error; + + if (valid_lifetime != NM_PLATFORM_LIFETIME_PERMANENT + && preferred_lifetime == NM_PLATFORM_LIFETIME_PERMANENT) + preferred_lifetime = valid_lifetime; + + if (addr_family == AF_INET) { + a.a4 = (NMPlatformIP4Address){ + .address = addr_bin.addr4, + .peer_address = addr_bin.addr4, + .plen = plen, + .timestamp = (valid_lifetime != NM_PLATFORM_LIFETIME_PERMANENT) ? timestamp : 0, + .lifetime = valid_lifetime, + .preferred = preferred_lifetime, + .addr_source = source, + .use_ip4_broadcast_address = (bcast_str != NULL), + .broadcast_address = bcast_bin.addr4, + }; + } else { + a.a6 = (NMPlatformIP6Address){ + .address = addr_bin.addr6, + .plen = 128, + .timestamp = (valid_lifetime != NM_PLATFORM_LIFETIME_PERMANENT) ? timestamp : 0, + .lifetime = valid_lifetime, + .preferred = preferred_lifetime, + .addr_source = source, + }; + } + + nm_l3_config_data_add_address(l3cd, addr_family, NULL, &a.ax); + } + + while (g_variant_iter_next(route_iter, "a{sv}", &entry_iter)) { + _nm_unused nm_auto_free_variant_iter GVariantIter *entry_iter_free = entry_iter; + const char *dst_addr_str = NULL; + NMIPAddr dst_addr_bin = {}; + uint8_t dst_plen = 0; + const char *router_str = NULL; + NMIPAddr router_bin = {}; + const char *pref_src_str = NULL; + NMIPAddr pref_src_bin = {}; + _nm_unused uint32_t lifetime = NM_PLATFORM_LIFETIME_PERMANENT; + _nm_unused uint32_t priority = 0; + uint8_t preference = 0; + uint32_t mtu = 0; + NMPlatformIPXRoute r; + + while (g_variant_iter_next(entry_iter, "{&sv}", &key, &value)) { + _nm_unused gs_unref_variant GVariant *value_free = value; + + if (nm_streq(key, "Destination")) { + if (!g_variant_is_of_type(value, G_VARIANT_TYPE("(sy)")) || dst_addr_str) + goto param_error; + + g_variant_get(value, "(&sy)", &dst_addr_str, &dst_plen); + if (inet_pton(addr_family, dst_addr_str, &dst_addr_bin) != 1) + goto param_error; + } + + if (nm_streq(key, "Router")) { + if (!g_variant_is_of_type(value, G_VARIANT_TYPE_STRING) || router_str) + goto param_error; + + router_str = g_variant_get_string(value, NULL); + if (inet_pton(addr_family, router_str, &router_bin) != 1) + goto param_error; + } + + if (nm_streq(key, "PreferredSource")) { + if (!g_variant_is_of_type(value, G_VARIANT_TYPE_STRING) || pref_src_str) + goto param_error; + + pref_src_str = g_variant_get_string(value, NULL); + if (inet_pton(addr_family, pref_src_str, &pref_src_bin) != 1) + goto param_error; + } + + if (nm_streq(key, "Lifetime")) { + if (!g_variant_is_of_type(value, G_VARIANT_TYPE_UINT32) + || lifetime != NM_PLATFORM_LIFETIME_PERMANENT) + goto param_error; + + lifetime = g_variant_get_uint32(value); + } + + if (nm_streq(key, "Priority")) { + if (!g_variant_is_of_type(value, G_VARIANT_TYPE_UINT32)) + goto param_error; + + priority = g_variant_get_uint32(value); + } + + if (nm_streq(key, "Preference")) { + if (!g_variant_is_of_type(value, G_VARIANT_TYPE_BYTE)) + goto param_error; + + preference = g_variant_get_byte(value); + } + + if (nm_streq(key, "MTU")) { + if (!g_variant_is_of_type(value, G_VARIANT_TYPE_UINT32)) + goto param_error; + + mtu = g_variant_get_uint32(value); + } + } + + if (addr_family == AF_INET) { + r.r4 = (NMPlatformIP4Route){ + .network = dst_addr_str ? dst_addr_bin.addr4 : 0, + .plen = dst_addr_str ? dst_plen : 0, + .gateway = router_str ? router_bin.addr4 : 0, + .pref_src = pref_src_str ? pref_src_bin.addr4 : 0, + .scope_inv = + nm_platform_route_scope_inv(router_str ? RT_SCOPE_UNIVERSE : RT_SCOPE_LINK), + }; + } else { + r.r6 = (NMPlatformIP6Route){ + .network = dst_addr_str ? dst_addr_bin.addr6 : nm_ip_addr_zero.addr6, + .plen = dst_addr_str ? dst_plen : 0, + .gateway = router_str ? router_bin.addr6 : nm_ip_addr_zero.addr6, + .pref_src = pref_src_str ? pref_src_bin.addr6 : nm_ip_addr_zero.addr6, + .rt_pref = preference, + .r_rtm_flags = RTNH_F_ONLINK, + }; + } + + r.rx.metric_any = TRUE; + r.rx.mtu = mtu; + r.rx.rt_source = source; + r.rx.type_coerced = nm_platform_route_type_coerce(RTN_UNICAST); + r.rx.table_any = TRUE; + + /* TODO: set the lifetime */ + nm_l3_config_data_add_route(l3cd, addr_family, NULL, &r.rx); + } + + if (dns_iter) { + while (g_variant_iter_next(dns_iter, "&s", &str_value)) { + NMIPAddr dns_bin; + + if (inet_pton(addr_family, str_value, &dns_bin) != 1) + goto param_error; + + nm_l3_config_data_add_nameserver_detail(l3cd, addr_family, &dns_bin, NULL); + nm_l3_config_data_set_dns_priority(l3cd, addr_family, NM_DNS_PRIORITY_DEFAULT_NORMAL); + } + } + + if (domain_iter) { + while (g_variant_iter_next(domain_iter, "&s", &str_value)) + nm_l3_config_data_add_search(l3cd, addr_family, str_value); + } + + if (mdns != NM_SETTING_CONNECTION_MDNS_DEFAULT) + nm_l3_config_data_set_mdns(l3cd, mdns); + + return nm_l3_config_data_ref_and_seal(l3cd); + +param_error: + return NULL; +} + +bool +nm_device_iwd_set_netconfig(NMDeviceIwd *self, int addr_family, GVariantIter *config_iter) +{ + NMDevice *device = NM_DEVICE(self); + NMDeviceIwdPrivate *priv = NM_DEVICE_IWD_GET_PRIVATE(self); + const NML3ConfigData *l3cd; + NMDeviceState state = nm_device_get_state(device); + + if (state < NM_DEVICE_STATE_CONFIG || state > NM_DEVICE_STATE_ACTIVATED) + return FALSE; + + l3cd = nm_device_iwd_parse_netconfig(self, addr_family, config_iter); + if (!l3cd) { + _LOGE(LOGD_WIFI, "Malformed netconfig DBus structure"); + return FALSE; + } + + if (state == NM_DEVICE_STATE_CONFIG) { + nm_l3_config_data_unref(priv->pending_l3cd_x[NM_IS_IPv4(addr_family)]); + priv->pending_l3cd_x[NM_IS_IPv4(addr_family)] = l3cd; + } else { + nm_device_devip_set_state(device, addr_family, NM_DEVICE_IP_STATE_READY, l3cd); + nm_l3_config_data_unref(l3cd); + } + + return TRUE; +} + static void autoconnect_changed(NMDevice *device, GParamSpec *pspec, NMDeviceIwd *self) { @@ -3411,7 +3825,7 @@ nm_device_iwd_init(NMDeviceIwd *self) g_signal_connect(self, "notify::" NM_DEVICE_AUTOCONNECT, G_CALLBACK(autoconnect_changed), self); /* Make sure the manager is running */ - (void) nm_iwd_manager_get(); + priv->manager = g_object_ref(nm_iwd_manager_get()); } NMDevice * @@ -3443,6 +3857,8 @@ dispose(GObject *object) G_OBJECT_CLASS(nm_device_iwd_parent_class)->dispose(object); nm_assert(c_list_is_empty(&priv->aps_lst_head)); + + g_clear_object(&priv->manager); } static void @@ -3472,12 +3888,14 @@ nm_device_iwd_class_init(NMDeviceIwdClass *klass) device_class->set_enabled = set_enabled; device_class->get_type_description = get_type_description; - device_class->act_stage1_prepare = act_stage1_prepare; - device_class->act_stage2_config = act_stage2_config; - device_class->get_configured_mtu = get_configured_mtu; - device_class->deactivate = deactivate; - device_class->deactivate_async = deactivate_async; - device_class->can_reapply_change = can_reapply_change; + device_class->act_stage1_prepare = act_stage1_prepare; + device_class->act_stage2_config = act_stage2_config; + device_class->act_stage3_ip_config = act_stage3_ip_config; + device_class->ready_for_ip_config = ready_for_ip_config; + device_class->get_configured_mtu = get_configured_mtu; + device_class->deactivate = deactivate; + device_class->deactivate_async = deactivate_async; + device_class->can_reapply_change = can_reapply_change; /* Stage 1 needed only for the set_current_ap() call. Stage 2 is * needed if we're assuming a connection still in the "connecting" diff --git a/src/core/devices/wifi/nm-device-iwd.h b/src/core/devices/wifi/nm-device-iwd.h index bb136bf6..8449f7f6 100644 --- a/src/core/devices/wifi/nm-device-iwd.h +++ b/src/core/devices/wifi/nm-device-iwd.h @@ -11,7 +11,7 @@ #include "nm-device-wifi.h" #define NM_TYPE_DEVICE_IWD (nm_device_iwd_get_type()) -#define NM_DEVICE_IWD(obj) (G_TYPE_CHECK_INSTANCE_CAST((obj), NM_TYPE_DEVICE_IWD, NMDeviceIwd)) +#define NM_DEVICE_IWD(obj) (_NM_G_TYPE_CHECK_INSTANCE_CAST((obj), NM_TYPE_DEVICE_IWD, NMDeviceIwd)) #define NM_DEVICE_IWD_CLASS(klass) \ (G_TYPE_CHECK_CLASS_CAST((klass), NM_TYPE_DEVICE_IWD, NMDeviceIwdClass)) #define NM_IS_DEVICE_IWD(obj) (G_TYPE_CHECK_INSTANCE_TYPE((obj), NM_TYPE_DEVICE_IWD)) @@ -46,4 +46,6 @@ void _nm_device_iwd_request_scan(NMDeviceIwd *self, void nm_device_iwd_network_add_remove(NMDeviceIwd *device, GDBusProxy *network, bool add); +bool nm_device_iwd_set_netconfig(NMDeviceIwd *device, int addr_family, GVariantIter *config_iter); + #endif /* __NETWORKMANAGER_DEVICE_IWD_H__ */ diff --git a/src/core/devices/wifi/nm-device-olpc-mesh.h b/src/core/devices/wifi/nm-device-olpc-mesh.h index 79b7fd5d..af3abbc0 100644 --- a/src/core/devices/wifi/nm-device-olpc-mesh.h +++ b/src/core/devices/wifi/nm-device-olpc-mesh.h @@ -15,7 +15,7 @@ #define NM_TYPE_DEVICE_OLPC_MESH (nm_device_olpc_mesh_get_type()) #define NM_DEVICE_OLPC_MESH(obj) \ - (G_TYPE_CHECK_INSTANCE_CAST((obj), NM_TYPE_DEVICE_OLPC_MESH, NMDeviceOlpcMesh)) + (_NM_G_TYPE_CHECK_INSTANCE_CAST((obj), NM_TYPE_DEVICE_OLPC_MESH, NMDeviceOlpcMesh)) #define NM_DEVICE_OLPC_MESH_CLASS(klass) \ (G_TYPE_CHECK_CLASS_CAST((klass), NM_TYPE_DEVICE_OLPC_MESH, NMDeviceOlpcMeshClass)) #define NM_IS_DEVICE_OLPC_MESH(obj) (G_TYPE_CHECK_INSTANCE_TYPE((obj), NM_TYPE_DEVICE_OLPC_MESH)) diff --git a/src/core/devices/wifi/nm-device-wifi-p2p.c b/src/core/devices/wifi/nm-device-wifi-p2p.c index 4576af95..6c0a4d5e 100644 --- a/src/core/devices/wifi/nm-device-wifi-p2p.c +++ b/src/core/devices/wifi/nm-device-wifi-p2p.c @@ -22,7 +22,6 @@ #include "nm-act-request.h" #include "nm-l3-config-data.h" #include "nm-manager.h" -#include "nm-manager.h" #include "nm-setting-wifi-p2p.h" #include "nm-utils.h" #include "nm-wifi-p2p-peer.h" diff --git a/src/core/devices/wifi/nm-device-wifi-p2p.h b/src/core/devices/wifi/nm-device-wifi-p2p.h index d1aadd8e..08780464 100644 --- a/src/core/devices/wifi/nm-device-wifi-p2p.h +++ b/src/core/devices/wifi/nm-device-wifi-p2p.h @@ -11,7 +11,7 @@ #define NM_TYPE_DEVICE_WIFI_P2P (nm_device_wifi_p2p_get_type()) #define NM_DEVICE_WIFI_P2P(obj) \ - (G_TYPE_CHECK_INSTANCE_CAST((obj), NM_TYPE_DEVICE_WIFI_P2P, NMDeviceWifiP2P)) + (_NM_G_TYPE_CHECK_INSTANCE_CAST((obj), NM_TYPE_DEVICE_WIFI_P2P, NMDeviceWifiP2P)) #define NM_DEVICE_WIFI_P2P_CLASS(klass) \ (G_TYPE_CHECK_CLASS_CAST((klass), NM_TYPE_DEVICE_WIFI_P2P, NMDeviceWifiP2PClass)) #define NM_IS_DEVICE_WIFI_P2P(obj) (G_TYPE_CHECK_INSTANCE_TYPE((obj), NM_TYPE_DEVICE_WIFI_P2P)) diff --git a/src/core/devices/wifi/nm-device-wifi.c b/src/core/devices/wifi/nm-device-wifi.c index 8af974d0..171743d0 100644 --- a/src/core/devices/wifi/nm-device-wifi.c +++ b/src/core/devices/wifi/nm-device-wifi.c @@ -99,13 +99,13 @@ typedef struct { NMSupplMgrCreateIfaceHandle *sup_create_handle; NMSupplicantInterface *sup_iface; + GSource *scan_kickoff_timeout_source; + gint64 scan_last_complete_msec; gint64 scan_periodic_next_msec; gint64 scan_last_request_started_at_msec; - guint scan_kickoff_timeout_id; - guint ap_dump_id; guint periodic_update_id; @@ -508,7 +508,10 @@ _scan_notify_allowed(NMDeviceWifi *self, NMTernary do_kickoff) /* something prohibits scanning. */ } else if (NM_IN_SET(priv->mode, _NM_802_11_MODE_ADHOC, _NM_802_11_MODE_AP)) { /* Don't scan when a an AP or Ad-Hoc connection is active as it will - * disrupt connected clients or peers. */ + * disrupt connected clients or peers. + * + * Explicit scans are allowed however. */ + explicit_allowed = TRUE; } else if (NM_IN_SET(state, NM_DEVICE_STATE_DISCONNECTED, NM_DEVICE_STATE_FAILED)) { /* Can always scan when disconnected */ explicit_allowed = TRUE; @@ -659,7 +662,7 @@ supplicant_interface_release(NMDeviceWifi *self) NM_PENDING_ACTION_WAITING_FOR_SUPPLICANT, TRUE); - nm_clear_g_source(&priv->scan_kickoff_timeout_id); + nm_clear_g_source_inst(&priv->scan_kickoff_timeout_source); nm_clear_g_source_inst(&priv->scan_request_delay_source); nm_clear_g_cancellable(&priv->scan_request_cancellable); @@ -1718,9 +1721,9 @@ _scan_kickoff_timeout_cb(gpointer user_data) NMDeviceWifi *self = user_data; NMDeviceWifiPrivate *priv = NM_DEVICE_WIFI_GET_PRIVATE(self); - priv->scan_kickoff_timeout_id = 0; + nm_clear_g_source_inst(&priv->scan_kickoff_timeout_source); _scan_kickoff(self); - return G_SOURCE_REMOVE; + return G_SOURCE_CONTINUE; } static void @@ -1763,13 +1766,13 @@ _scan_kickoff(NMDeviceWifi *self) / 1000), (int) ((priv->scan_last_request_started_at_msec + ratelimit_duration_msec - now_msec) % 1000), - !priv->scan_kickoff_timeout_id ? ", schedule timeout" : ""); - if (!priv->scan_kickoff_timeout_id + !priv->scan_kickoff_timeout_source ? ", schedule timeout" : ""); + if (!priv->scan_kickoff_timeout_source && (priv->scan_explicit_allowed || priv->scan_periodic_allowed)) { - priv->scan_kickoff_timeout_id = g_timeout_add(priv->scan_last_request_started_at_msec - + ratelimit_duration_msec - now_msec, - _scan_kickoff_timeout_cb, - self); + priv->scan_kickoff_timeout_source = nm_g_timeout_add_source( + priv->scan_last_request_started_at_msec + ratelimit_duration_msec - now_msec, + _scan_kickoff_timeout_cb, + self); } return; } @@ -1786,14 +1789,16 @@ _scan_kickoff(NMDeviceWifi *self) _LOGT_scan("kickoff: don't scan (rate limited for another %d.%03d sec after previous scan)", timeout_msec / 1000, timeout_msec % 1000); - nm_clear_g_source(&priv->scan_kickoff_timeout_id); - priv->scan_kickoff_timeout_id = g_timeout_add(timeout_msec, _scan_kickoff_timeout_cb, self); + nm_clear_g_source_inst(&priv->scan_kickoff_timeout_source); + priv->scan_kickoff_timeout_source = + nm_g_timeout_add_source(timeout_msec, _scan_kickoff_timeout_cb, self); return; } if (priv->scan_explicit_requested) { if (!priv->scan_explicit_allowed) { - _LOGT_scan("kickoff: don't scan (explicit scan requested but not allowed)"); + _LOGT_scan( + "kickoff: don't scan (explicit scan requested but not allowed at the moment)"); return; } priv->scan_explicit_requested = FALSE; @@ -1803,7 +1808,7 @@ _scan_kickoff(NMDeviceWifi *self) _LOGT_scan("kickoff: don't scan (periodic scan currently not allowed)"); priv->scan_periodic_next_msec = 0; priv->scan_periodic_interval_sec = 0; - nm_clear_g_source(&priv->scan_kickoff_timeout_id); + nm_clear_g_source_inst(&priv->scan_kickoff_timeout_source); return; } @@ -1813,12 +1818,12 @@ _scan_kickoff(NMDeviceWifi *self) _LOGT_scan("kickoff: don't scan (periodic scan waiting for another %d.%03d sec%s)", (int) ((priv->scan_periodic_next_msec - now_msec) / 1000), (int) ((priv->scan_periodic_next_msec - now_msec) % 1000), - !priv->scan_kickoff_timeout_id ? ", schedule timeout" : ""); - if (!priv->scan_kickoff_timeout_id) { - priv->scan_kickoff_timeout_id = - g_timeout_add_seconds((priv->scan_periodic_next_msec - now_msec + 999) / 1000, - _scan_kickoff_timeout_cb, - self); + !priv->scan_kickoff_timeout_source ? ", schedule timeout" : ""); + if (!priv->scan_kickoff_timeout_source) { + priv->scan_kickoff_timeout_source = nm_g_timeout_add_seconds_source( + (priv->scan_periodic_next_msec - now_msec + 999) / 1000, + _scan_kickoff_timeout_cb, + self); } return; } diff --git a/src/core/devices/wifi/nm-device-wifi.h b/src/core/devices/wifi/nm-device-wifi.h index 3a85192e..17893a1b 100644 --- a/src/core/devices/wifi/nm-device-wifi.h +++ b/src/core/devices/wifi/nm-device-wifi.h @@ -10,7 +10,8 @@ #include "devices/nm-device.h" #define NM_TYPE_DEVICE_WIFI (nm_device_wifi_get_type()) -#define NM_DEVICE_WIFI(obj) (G_TYPE_CHECK_INSTANCE_CAST((obj), NM_TYPE_DEVICE_WIFI, NMDeviceWifi)) +#define NM_DEVICE_WIFI(obj) \ + (_NM_G_TYPE_CHECK_INSTANCE_CAST((obj), NM_TYPE_DEVICE_WIFI, NMDeviceWifi)) #define NM_DEVICE_WIFI_CLASS(klass) \ (G_TYPE_CHECK_CLASS_CAST((klass), NM_TYPE_DEVICE_WIFI, NMDeviceWifiClass)) #define NM_IS_DEVICE_WIFI(obj) (G_TYPE_CHECK_INSTANCE_TYPE((obj), NM_TYPE_DEVICE_WIFI)) diff --git a/src/core/devices/wifi/nm-iwd-manager.c b/src/core/devices/wifi/nm-iwd-manager.c index 2e0d51e5..0d4daf21 100644 --- a/src/core/devices/wifi/nm-iwd-manager.c +++ b/src/core/devices/wifi/nm-iwd-manager.c @@ -47,13 +47,18 @@ typedef struct { } KnownNetworkData; typedef struct { + GBytes *ssid; + gint64 timestamp; +} RecentlyMirroredData; + +typedef struct { NMManager *manager; NMSettings *settings; GCancellable *cancellable; gboolean running; GDBusObjectManager *object_manager; guint agent_id; - char *agent_path; + guint netconfig_agent_id; GHashTable *known_networks; NMDeviceIwd *last_agent_call_device; char *last_state_dir; @@ -62,6 +67,7 @@ typedef struct { GHashTable *p2p_devices; NMIwdWfdInfo wfd_info; guint wfd_use_count; + GSList *recently_mirrored; } NMIwdManagerPrivate; struct _NMIwdManager { @@ -271,6 +277,77 @@ return_error: "Secrets not available for this connection"); } +static void +netconfig_agent_dbus_method_cb(GDBusConnection *connection, + const char *sender, + const char *object_path, + const char *interface_name, + const char *method_name, + GVariant *parameters, + GDBusMethodInvocation *invocation, + gpointer user_data) +{ + NMIwdManager *self = user_data; + NMIwdManagerPrivate *priv = NM_IWD_MANAGER_GET_PRIVATE(self); + gs_free char *name_owner = NULL; + const char *device_path; + gs_unref_object GDBusInterface *device_obj = NULL; + NMDevice *device; + nm_auto_free_variant_iter GVariantIter *config_iter = NULL; + const char *ifname; + int addr_family; + + /* Be paranoid and check the sender address */ + name_owner = g_dbus_object_manager_client_get_name_owner( + G_DBUS_OBJECT_MANAGER_CLIENT(priv->object_manager)); + if (!nm_streq0(name_owner, sender)) + goto return_error; + + if (nm_streq(method_name, "ConfigureIPv4")) + addr_family = AF_INET; + else if (nm_streq(method_name, "ConfigureIPv6")) + addr_family = AF_INET6; + else + goto return_error; + + g_variant_get(parameters, "(&oa{sv})", &device_path, &config_iter); + + device_obj = g_dbus_object_manager_get_interface(priv->object_manager, + device_path, + NM_IWD_DEVICE_INTERFACE); + if (!device_obj) { + _LOGE("netconfig-agent-request: unable to find the device object"); + goto return_error; + } + + ifname = get_property_string_or_null(G_DBUS_PROXY(device_obj), "Name"); + if (!ifname) { + _LOGD("Name not cached for device at %s", device_path); + goto return_error; + } + + device = nm_manager_get_device(priv->manager, ifname, NM_DEVICE_TYPE_WIFI); + if (!device || !NM_IS_DEVICE_IWD(device)) { + _LOGD("NM device %s is not an IWD-managed device", ifname); + goto return_error; + } + + if (nm_device_iwd_set_netconfig(NM_DEVICE_IWD(device), addr_family, config_iter)) { + g_dbus_method_invocation_return_value(invocation, g_variant_new("()")); + return; + } + + _LOGD("netconfig-agent-request: device %s did not handle the IWD Netconfig Agent request", + ifname); + +return_error: + /* IWD doesn't look at the specific error */ + g_dbus_method_invocation_return_error_literal(invocation, + NM_DEVICE_ERROR, + NM_DEVICE_ERROR_INVALID_CONNECTION, + "Couldn't set netconfig data"); +} + static const GDBusInterfaceInfo iwd_agent_iface_info = NM_DEFINE_GDBUS_INTERFACE_INFO_INIT( "net.connman.iwd.Agent", .methods = NM_DEFINE_GDBUS_METHOD_INFOS( @@ -296,36 +373,55 @@ static const GDBusInterfaceInfo iwd_agent_iface_info = NM_DEFINE_GDBUS_INTERFACE .in_args = NM_DEFINE_GDBUS_ARG_INFOS( NM_DEFINE_GDBUS_ARG_INFO("reason", "s"), ), ), ), ); +static const GDBusInterfaceInfo iwd_netconfig_agent_iface_info = + NM_DEFINE_GDBUS_INTERFACE_INFO_INIT( + "net.connman.iwd.NetworkConfigurationAgent", + .methods = NM_DEFINE_GDBUS_METHOD_INFOS( + NM_DEFINE_GDBUS_METHOD_INFO("ConfigureIPv4", + .in_args = NM_DEFINE_GDBUS_ARG_INFOS( + NM_DEFINE_GDBUS_ARG_INFO("device", "o"), + NM_DEFINE_GDBUS_ARG_INFO("config", "a{sv}"), ), ), + NM_DEFINE_GDBUS_METHOD_INFO("ConfigureIPv6", + .in_args = NM_DEFINE_GDBUS_ARG_INFOS( + NM_DEFINE_GDBUS_ARG_INFO("device", "o"), + NM_DEFINE_GDBUS_ARG_INFO("config", "a{sv}"), ), ), ), ); + static guint -iwd_agent_export(GDBusConnection *connection, gpointer user_data, char **agent_path, GError **error) +iwd_agent_export(GDBusConnection *connection, gpointer user_data, GError **error) { static const GDBusInterfaceVTable vtable = { .method_call = agent_dbus_method_cb, }; - char path[50]; - unsigned int rnd; - guint id; - nm_random_get_bytes(&rnd, sizeof(rnd)); - - nm_sprintf_buf(path, "/agent/%u", rnd); + return g_dbus_connection_register_object( + connection, + NM_IWD_AGENT_PATH, + NM_UNCONST_PTR(GDBusInterfaceInfo, &iwd_agent_iface_info), + &vtable, + user_data, + NULL, + error); +} - id = - g_dbus_connection_register_object(connection, - path, - NM_UNCONST_PTR(GDBusInterfaceInfo, &iwd_agent_iface_info), - &vtable, - user_data, - NULL, - error); +static guint +iwd_netconfig_agent_export(GDBusConnection *connection, gpointer user_data, GError **error) +{ + static const GDBusInterfaceVTable vtable = { + .method_call = netconfig_agent_dbus_method_cb, + }; - if (id) - *agent_path = g_strdup(path); - return id; + return g_dbus_connection_register_object( + connection, + NM_IWD_AGENT_PATH, + NM_UNCONST_PTR(GDBusInterfaceInfo, &iwd_netconfig_agent_iface_info), + &vtable, + user_data, + NULL, + error); } static void -register_agent(NMIwdManager *self) +register_agent(NMIwdManager *self, const char *method) { NMIwdManagerPrivate *priv = NM_IWD_MANAGER_GET_PRIVATE(self); GDBusInterface *agent_manager; @@ -334,14 +430,14 @@ register_agent(NMIwdManager *self) "/net/connman/iwd", /* IWD 1.0+ */ NM_IWD_AGENT_MANAGER_INTERFACE); if (!agent_manager) { - _LOGE("unable to register the IWD Agent: PSK/8021x Wi-Fi networks may not work"); + _LOGE("unable to register the IWD Agent"); return; } /* Register our agent */ g_dbus_proxy_call(G_DBUS_PROXY(agent_manager), - "RegisterAgent", - g_variant_new("(o)", priv->agent_path), + method, + g_variant_new("(o)", NM_IWD_AGENT_PATH), G_DBUS_CALL_FLAGS_NONE, -1, NULL, @@ -353,6 +449,70 @@ register_agent(NMIwdManager *self) /*****************************************************************************/ +static void +recently_mirrored_data_free(void *data) +{ + RecentlyMirroredData *rmd = data; + + g_bytes_unref(rmd->ssid); + g_free(rmd); +} + +/* When we mirror an 802.1x connection to an IWD config file, and there's an + * AP in range with matching SSID, that connection should become available + * for activation. In IWD terms when an 802.1x network becomes a Known + * Network, it can be connected to using the .Connect D-Bus method. + * + * However there's a delay between writing the IWD config file and receiving + * the InterfaceAdded event for the Known Network so we don't immediately + * find out that the network can now be used. If an NM client creates a + * new connection for an 802.1x AP and tries to activate it immediately, + * NMDeviceIWD will not allow it to because it doesn't know the network is + * known yet. To work around this, we save the SSIDs of 802.1x connections + * we recently mirrored to IWD config files, for 2 seconds, and we treat + * them as Known Networks in that period since in theory activations should + * succeed. + */ +bool +nm_iwd_manager_is_recently_mirrored(NMIwdManager *self, const GBytes *ssid) +{ + NMIwdManagerPrivate *priv = NM_IWD_MANAGER_GET_PRIVATE(self); + gint64 now = nm_utils_get_monotonic_timestamp_nsec(); + GSList *iter; + RecentlyMirroredData *rmd; + + /* Drop entries older than 2 seconds */ + while (priv->recently_mirrored) { + rmd = priv->recently_mirrored->data; + if (now < rmd->timestamp + 2000000000) + break; + + priv->recently_mirrored = g_slist_remove(priv->recently_mirrored, rmd); + recently_mirrored_data_free(rmd); + } + + for (iter = priv->recently_mirrored; iter; iter = iter->next) { + rmd = iter->data; + if (g_bytes_equal(ssid, rmd->ssid)) + return TRUE; + } + + return FALSE; +} + +static void +save_mirrored(NMIwdManager *self, GBytes *ssid) +{ + NMIwdManagerPrivate *priv = NM_IWD_MANAGER_GET_PRIVATE(self); + RecentlyMirroredData *rmd = g_malloc(sizeof(RecentlyMirroredData)); + + rmd->ssid = g_bytes_ref(ssid); + rmd->timestamp = nm_utils_get_monotonic_timestamp_nsec(); + priv->recently_mirrored = g_slist_append(priv->recently_mirrored, rmd); +} + +/*****************************************************************************/ + static KnownNetworkId * known_network_id_new(const char *name, NMIwdNetworkSecurity security) { @@ -721,6 +881,9 @@ sett_conn_changed(NMSettingsConnection *sett_conn, "iwd: changed Wi-Fi connection %s mirrored as IWD profile %s", nm_settings_connection_get_id(sett_conn), full_path); + + if (security == NM_IWD_NETWORK_SECURITY_8021X) + save_mirrored(nm_iwd_manager_get(), ssid); } /* Look up an existing NMSettingsConnection for a network that has been @@ -1283,6 +1446,7 @@ connection_added(NMSettings *settings, NMSettingsConnection *sett_conn, gpointer gs_free_error GError *error = NULL; nm_auto_unref_keyfile GKeyFile *iwd_config = NULL; NMSettingsConnectionIntFlags flags; + NMIwdNetworkSecurity security; if (!nm_streq(nm_settings_connection_get_connection_type(sett_conn), "802-11-wireless")) return; @@ -1338,6 +1502,12 @@ connection_added(NMSettings *settings, NMSettingsConnection *sett_conn, gpointer _LOGD("New Wi-Fi connection %s mirrored as IWD profile %s", nm_settings_connection_get_id(sett_conn), full_path); + + if (nm_wifi_connection_get_iwd_ssid_and_security(conn, NULL, &security) + && security == NM_IWD_NETWORK_SECURITY_8021X) { + NMSettingWireless *s_wifi = nm_connection_get_setting_wireless(conn); + save_mirrored(nm_iwd_manager_get(), nm_setting_wireless_get_ssid(s_wifi)); + } } static gboolean @@ -1355,26 +1525,33 @@ _om_has_name_owner(GDBusObjectManager *object_manager) static void release_object_manager(NMIwdManager *self) { - NMIwdManagerPrivate *priv = NM_IWD_MANAGER_GET_PRIVATE(self); + NMIwdManagerPrivate *priv = NM_IWD_MANAGER_GET_PRIVATE(self); + GDBusConnection *agent_connection; + GDBusObjectManagerClient *omc; if (!priv->object_manager) return; g_signal_handlers_disconnect_by_data(priv->object_manager, self); - if (priv->agent_id) { - GDBusConnection *agent_connection; - GDBusObjectManagerClient *omc = G_DBUS_OBJECT_MANAGER_CLIENT(priv->object_manager); - - agent_connection = g_dbus_object_manager_client_get_connection(omc); + omc = G_DBUS_OBJECT_MANAGER_CLIENT(priv->object_manager); + agent_connection = g_dbus_object_manager_client_get_connection(omc); - /* We're is called when we're shutting down (i.e. our DBus connection - * is being closed, and IWD will detect this) or IWD was stopped so - * in either case calling UnregisterAgent will not do anything. - */ + /* We're called when we're shutting down (i.e. our DBus connection + * is being closed, and IWD will detect this) or IWD was stopped so + * in either case calling UnregisterAgent will not do anything. + * Just unregister the agent interfaces. The agents are on the same + * object (same path) but it seems g_dbus_connection_unregister_object() + * should be called for each interface on the object separately. + */ + if (priv->agent_id) { g_dbus_connection_unregister_object(agent_connection, priv->agent_id); priv->agent_id = 0; - nm_clear_g_free(&priv->agent_path); + } + + if (priv->netconfig_agent_id) { + g_dbus_connection_unregister_object(agent_connection, priv->netconfig_agent_id); + priv->netconfig_agent_id = 0; } g_clear_object(&priv->object_manager); @@ -1589,6 +1766,10 @@ next: } g_variant_iter_free(properties_iter); + + /* Register the netconfig agent only once we know netconfig is enabled */ + if (nm_iwd_manager_get_netconfig_enabled(self) && priv->netconfig_agent_id) + register_agent(self, "RegisterNetworkConfigurationAgent"); } static void @@ -1620,13 +1801,19 @@ got_object_manager(GObject *object, GAsyncResult *result, gpointer user_data) connection = g_dbus_object_manager_client_get_connection(G_DBUS_OBJECT_MANAGER_CLIENT(object_manager)); - priv->agent_id = iwd_agent_export(connection, self, &priv->agent_path, &error); + priv->agent_id = iwd_agent_export(connection, self, &error); if (!priv->agent_id) { _LOGE("failed to export the IWD Agent: PSK/8021x Wi-Fi networks may not work: %s", error->message); g_clear_error(&error); } + priv->netconfig_agent_id = iwd_netconfig_agent_export(connection, self, &error); + if (!priv->netconfig_agent_id) { + _LOGE("failed to export the IWD Netconfig Agent: %s", error->message); + g_clear_error(&error); + } + if (_om_has_name_owner(object_manager)) { GList *objects, *iter; gs_unref_object GDBusInterface *daemon = NULL; @@ -1654,7 +1841,7 @@ got_object_manager(GObject *object, GAsyncResult *result, gpointer user_data) g_list_free_full(objects, g_object_unref); if (priv->agent_id) - register_agent(self); + register_agent(self, "RegisterAgent"); priv->netconfig_enabled = false; /* Assume false until GetInfo() results come in */ @@ -1952,6 +2139,8 @@ dispose(GObject *object) g_hash_table_unref(nm_steal_pointer(&priv->p2p_devices)); + g_slist_free_full(nm_steal_pointer(&priv->recently_mirrored), recently_mirrored_data_free); + G_OBJECT_CLASS(nm_iwd_manager_parent_class)->dispose(object); } diff --git a/src/core/devices/wifi/nm-iwd-manager.h b/src/core/devices/wifi/nm-iwd-manager.h index 02cd6bba..80123c9a 100644 --- a/src/core/devices/wifi/nm-iwd-manager.h +++ b/src/core/devices/wifi/nm-iwd-manager.h @@ -30,8 +30,11 @@ #define NM_IWD_P2P_SERVICE_MANAGER_INTERFACE "net.connman.iwd.p2p.ServiceManager" #define NM_IWD_P2P_WFD_INTERFACE "net.connman.iwd.p2p.Display" +#define NM_IWD_AGENT_PATH NM_DBUS_PATH "/iwd/agent" + #define NM_TYPE_IWD_MANAGER (nm_iwd_manager_get_type()) -#define NM_IWD_MANAGER(obj) (G_TYPE_CHECK_INSTANCE_CAST((obj), NM_TYPE_IWD_MANAGER, NMIwdManager)) +#define NM_IWD_MANAGER(obj) \ + (_NM_G_TYPE_CHECK_INSTANCE_CAST((obj), NM_TYPE_IWD_MANAGER, NMIwdManager)) #define NM_IWD_MANAGER_CLASS(klass) \ (G_TYPE_CHECK_CLASS_CAST((klass), NM_TYPE_IWD_MANAGER, NMIwdManagerClass)) #define NM_IS_IWD_MANAGER(obj) (G_TYPE_CHECK_INSTANCE_TYPE((obj), NM_TYPE_IWD_MANAGER)) @@ -63,4 +66,6 @@ gboolean nm_iwd_manager_check_wfd_info_compatible(NMIwdManager *self, const NMIw gboolean nm_iwd_manager_register_wfd(NMIwdManager *self, const NMIwdWfdInfo *wfd_info); void nm_iwd_manager_unregister_wfd(NMIwdManager *self); +bool nm_iwd_manager_is_recently_mirrored(NMIwdManager *self, const GBytes *ssid); + #endif /* __NETWORKMANAGER_IWD_MANAGER_H__ */ diff --git a/src/core/devices/wifi/nm-wifi-ap.h b/src/core/devices/wifi/nm-wifi-ap.h index c0422900..93dc8edf 100644 --- a/src/core/devices/wifi/nm-wifi-ap.h +++ b/src/core/devices/wifi/nm-wifi-ap.h @@ -13,7 +13,7 @@ #include "libnm-base/nm-base.h" #define NM_TYPE_WIFI_AP (nm_wifi_ap_get_type()) -#define NM_WIFI_AP(obj) (G_TYPE_CHECK_INSTANCE_CAST((obj), NM_TYPE_WIFI_AP, NMWifiAP)) +#define NM_WIFI_AP(obj) (_NM_G_TYPE_CHECK_INSTANCE_CAST((obj), NM_TYPE_WIFI_AP, NMWifiAP)) #define NM_WIFI_AP_CLASS(klass) (G_TYPE_CHECK_CLASS_CAST((klass), NM_TYPE_WIFI_AP, NMWifiAPClass)) #define NM_IS_WIFI_AP(obj) (G_TYPE_CHECK_INSTANCE_TYPE((obj), NM_TYPE_WIFI_AP)) #define NM_IS_WIFI_AP_CLASS(klass) (G_TYPE_CHECK_CLASS_TYPE((klass), NM_TYPE_WIFI_AP)) diff --git a/src/core/devices/wifi/nm-wifi-factory.c b/src/core/devices/wifi/nm-wifi-factory.c index 5e354c6b..19880a90 100644 --- a/src/core/devices/wifi/nm-wifi-factory.c +++ b/src/core/devices/wifi/nm-wifi-factory.c @@ -24,7 +24,7 @@ #define NM_TYPE_WIFI_FACTORY (nm_wifi_factory_get_type()) #define NM_WIFI_FACTORY(obj) \ - (G_TYPE_CHECK_INSTANCE_CAST((obj), NM_TYPE_WIFI_FACTORY, NMWifiFactory)) + (_NM_G_TYPE_CHECK_INSTANCE_CAST((obj), NM_TYPE_WIFI_FACTORY, NMWifiFactory)) #define NM_WIFI_FACTORY_CLASS(klass) \ (G_TYPE_CHECK_CLASS_CAST((klass), NM_TYPE_WIFI_FACTORY, NMWifiFactoryClass)) #define NM_IS_WIFI_FACTORY(obj) (G_TYPE_CHECK_INSTANCE_TYPE((obj), NM_TYPE_WIFI_FACTORY)) diff --git a/src/core/devices/wifi/nm-wifi-p2p-peer.h b/src/core/devices/wifi/nm-wifi-p2p-peer.h index 5124d1de..b0abeb37 100644 --- a/src/core/devices/wifi/nm-wifi-p2p-peer.h +++ b/src/core/devices/wifi/nm-wifi-p2p-peer.h @@ -12,7 +12,7 @@ #define NM_TYPE_WIFI_P2P_PEER (nm_wifi_p2p_peer_get_type()) #define NM_WIFI_P2P_PEER(obj) \ - (G_TYPE_CHECK_INSTANCE_CAST((obj), NM_TYPE_WIFI_P2P_PEER, NMWifiP2PPeer)) + (_NM_G_TYPE_CHECK_INSTANCE_CAST((obj), NM_TYPE_WIFI_P2P_PEER, NMWifiP2PPeer)) #define NM_WIFI_P2P_PEER_CLASS(klass) \ (G_TYPE_CHECK_CLASS_CAST((klass), NM_TYPE_WIFI_P2P_PEER, NMWifiP2PPeerClass)) #define NM_IS_WIFI_P2P_PEER(obj) (G_TYPE_CHECK_INSTANCE_TYPE((obj), NM_TYPE_WIFI_P2P_PEER)) diff --git a/src/core/devices/wifi/nm-wifi-utils.c b/src/core/devices/wifi/nm-wifi-utils.c index 1a8204b0..8a8d062f 100644 --- a/src/core/devices/wifi/nm-wifi-utils.c +++ b/src/core/devices/wifi/nm-wifi-utils.c @@ -11,6 +11,7 @@ #include <netinet/if_ether.h> #include <stdlib.h> +#include "libnm-glib-aux/nm-str-buf.h" #include "nm-utils.h" #include "libnm-core-intern/nm-core-internal.h" #include "libnm-core-aux-intern/nm-libnm-core-utils.h" @@ -812,13 +813,12 @@ nm_wifi_utils_complete_connection(GBytes *ap_ssid, * setting. Since there's so much configuration required for it, there's * no way it can be automatically completed. */ - } else if (nm_streq0(key_mgmt, "wpa-psk") - || (ap_rsn_flags & NM_802_11_AP_SEC_KEY_MGMT_SAE - && (ap_wpa_flags & NM_802_11_AP_SEC_KEY_MGMT_PSK - || ap_rsn_flags & NM_802_11_AP_SEC_KEY_MGMT_PSK))) { + } else if (ap_rsn_flags & NM_802_11_AP_SEC_KEY_MGMT_SAE + && (ap_wpa_flags & NM_802_11_AP_SEC_KEY_MGMT_PSK + || ap_rsn_flags & NM_802_11_AP_SEC_KEY_MGMT_PSK)) { g_object_set(s_wsec, NM_SETTING_WIRELESS_SECURITY_KEY_MGMT, - "wpa-psk", + nm_streq0(key_mgmt, "sae") ? "sae" : "wpa-psk", NM_SETTING_WIRELESS_SECURITY_AUTH_ALG, "open", NULL); @@ -828,7 +828,7 @@ nm_wifi_utils_complete_connection(GBytes *ap_ssid, || NM_FLAGS_ANY(ap_rsn_flags, NM_802_11_AP_SEC_KEY_MGMT_OWE | NM_802_11_AP_SEC_KEY_MGMT_OWE_TM)) { g_object_set(s_wsec, NM_SETTING_WIRELESS_SECURITY_KEY_MGMT, "owe", NULL); - } else if (ap_wpa_flags & NM_802_11_AP_SEC_KEY_MGMT_PSK + } else if (nm_streq0(key_mgmt, "wpa-psk") || ap_wpa_flags & NM_802_11_AP_SEC_KEY_MGMT_PSK || ap_rsn_flags & NM_802_11_AP_SEC_KEY_MGMT_PSK) { g_object_set(s_wsec, NM_SETTING_WIRELESS_SECURITY_KEY_MGMT, @@ -1004,7 +1004,7 @@ psk_setting_to_iwd_config(GKeyFile *file, NMSettingWirelessSecurity *s_wsec, GEr if (NM_FLAGS_ANY(psk_flags, SECRETS_DONT_STORE_FLAGS)) { nm_log_info( LOGD_WIFI, - "IWD network config is being created wihout the PSK but IWD will save the PSK on " + "IWD network config is being created without the PSK but IWD will save the PSK on " "successful activation not honoring the psk-flags property"); } return TRUE; @@ -1549,10 +1549,16 @@ eap_setting_to_iwd_config(GKeyFile *file, NMSetting8021x *s_8021x, GError **erro } static gboolean -ip4_config_to_iwd_config(GKeyFile *file, NMSettingIPConfig *s_ip, GError **error) +ip_config_to_iwd_config(int addr_family, GKeyFile *file, NMSettingIPConfig *s_ip, GError **error) { - guint num; - struct in_addr ip; + const int IS_IPv4 = NM_IS_IPv4(addr_family); + nm_auto_str_buf NMStrBuf strbuf = NM_STR_BUF_INIT_A(NM_UTILS_GET_NEXT_REALLOC_SIZE_488, FALSE); + NMIPAddress *addr; + guint num; + guint i; + char buf[NM_INET_ADDRSTRLEN + 10]; + const char *kf_group = IS_IPv4 ? "IPv4" : "IPv6"; + const char *gw; /* These settings are not acutally used unless global * [General].EnableNetworkConfiguration is true, which we don't support. @@ -1564,15 +1570,26 @@ ip4_config_to_iwd_config(GKeyFile *file, NMSettingIPConfig *s_ip, GError **error if (!s_ip) return TRUE; + nm_assert(NM_IS_IPv4(addr_family) ? NM_IS_SETTING_IP4_CONFIG(s_ip) + : NM_IS_SETTING_IP6_CONFIG(s_ip)); + num = nm_setting_ip_config_get_num_dns(s_ip); if (num) { - nm_auto_free_gstring GString *s = g_string_sized_new(128); - guint i; - + nm_str_buf_reset(&strbuf); for (i = 0; i < num; i++) { - if (s->len) - g_string_append_c(s, ' '); - g_string_append(s, nm_setting_ip_config_get_dns(s_ip, i)); + char sbuf[NM_INET_ADDRSTRLEN]; + NMIPAddr a; + + if (!nm_utils_dnsname_parse_assert(addr_family, + nm_setting_ip_config_get_dns(s_ip, i), + NULL, + &a, + NULL)) + continue; + + if (strbuf.len > 0) + nm_str_buf_append_c(&strbuf, ' '); + nm_str_buf_append(&strbuf, nm_inet_ntop(addr_family, &a, sbuf)); } /* It doesn't matter whether we add the DNS under [IPv4] or [IPv6] * except that with method=auto the list will override the @@ -1581,97 +1598,61 @@ ip4_config_to_iwd_config(GKeyFile *file, NMSettingIPConfig *s_ip, GError **error * Note ignore-auto-dns=false isn't supported, this list always * overrides the DHCP DNSes. */ - g_key_file_set_string(file, "IPv4", "DNS", s->str); + g_key_file_set_string(file, kf_group, "DNS", nm_str_buf_get_str(&strbuf)); } - if (!nm_streq0(nm_setting_ip_config_get_method(s_ip), NM_SETTING_IP4_CONFIG_METHOD_MANUAL)) - return TRUE; - - num = nm_setting_ip_config_get_num_addresses(s_ip); - if (num) { - NMIPAddress *addr = nm_setting_ip_config_get_address(s_ip, 0); - guint prefix = nm_ip_address_get_prefix(addr); - in_addr_t netmask = _nm_utils_ip4_prefix_to_netmask(prefix); - char buf[INET_ADDRSTRLEN]; - - nm_ip_address_get_address_binary(addr, &ip); - g_key_file_set_string(file, "IPv4", "Address", nm_ip_address_get_address(addr)); - g_key_file_set_string(file, "IPv4", "Netmask", _nm_utils_inet4_ntop(netmask, buf)); - } else { - inet_pton(AF_INET, "10.42.0.100", &ip); - g_key_file_set_string(file, "IPv4", "Address", "10.42.0.100"); + if (!IS_IPv4) { + if (!NM_IN_STRSET(nm_setting_ip_config_get_method(s_ip), + NM_SETTING_IP6_CONFIG_METHOD_AUTO, + NM_SETTING_IP6_CONFIG_METHOD_DHCP, + NM_SETTING_IP6_CONFIG_METHOD_MANUAL)) + return TRUE; + g_key_file_set_boolean(file, kf_group, "Enabled", TRUE); } - if (nm_setting_ip_config_get_gateway(s_ip)) { - g_key_file_set_string(file, "IPv4", "Gateway", nm_setting_ip_config_get_gateway(s_ip)); - } else { - uint32_t val; - char buf[INET_ADDRSTRLEN]; - - /* IWD won't enable static IP unless both Address and Gateway are - * set so generate a gateway address if not known. - */ - val = (ntohl(ip.s_addr) & 0xfffffff0) + 1; - if (val == ntohl(ip.s_addr)) - val += 1; - g_key_file_set_string(file, "IPv4", "Gateway", _nm_utils_inet4_ntop(htonl(val), buf)); - } - - return TRUE; -} - -static gboolean -ip6_config_to_iwd_config(GKeyFile *file, NMSettingIPConfig *s_ip, GError **error) -{ - guint num; - NMIPAddress *addr; - char buf[INET6_ADDRSTRLEN + 10]; - - if (!s_ip) + num = nm_setting_ip_config_get_num_addresses(s_ip); + if (num == 0) return TRUE; - num = nm_setting_ip_config_get_num_dns(s_ip); - if (num) { - nm_auto_free_gstring GString *s = g_string_sized_new(128); - guint i; + addr = nm_setting_ip_config_get_address(s_ip, 0); + gw = nm_setting_ip_config_get_gateway(s_ip); - for (i = 0; i < num; i++) { - if (s->len) - g_string_append_c(s, ' '); - g_string_append(s, nm_setting_ip_config_get_dns(s_ip, i)); - } - g_key_file_set_string(file, "IPv6", "DNS", s->str); - } + if (IS_IPv4) { + in_addr_t ip; - if (!NM_IN_STRSET(nm_setting_ip_config_get_method(s_ip), - NM_SETTING_IP6_CONFIG_METHOD_AUTO, - NM_SETTING_IP6_CONFIG_METHOD_DHCP, - NM_SETTING_IP6_CONFIG_METHOD_MANUAL)) - return TRUE; + nm_ip_address_get_address_binary(addr, &ip); - g_key_file_set_boolean(file, "IPv6", "Enabled", TRUE); + g_key_file_set_string(file, kf_group, "Address", nm_ip_address_get_address(addr)); + g_key_file_set_string( + file, + kf_group, + "Netmask", + nm_inet4_ntop(nm_ip4_addr_netmask_from_prefix(nm_ip_address_get_prefix(addr)), buf)); - if (!nm_streq0(nm_setting_ip_config_get_method(s_ip), NM_SETTING_IP6_CONFIG_METHOD_MANUAL)) - return TRUE; + if (!gw) { + guint32 val; - if (!nm_setting_ip_config_get_num_addresses(s_ip)) { - g_set_error_literal(error, - NM_CONNECTION_ERROR, - NM_CONNECTION_ERROR_INVALID_PROPERTY, - "IP address required for IPv6 manual config"); - return FALSE; + /* IWD won't enable static IP unless both Address and Gateway are + * set so generate a gateway address if not known. + */ + val = (ntohl(ip) & 0xfffffff0) + 1; + if (val == ntohl(ip)) + val += 1; + gw = nm_inet4_ntop(htonl(val), buf); + } + g_key_file_set_string(file, kf_group, "Gateway", gw); + } else { + g_key_file_set_string(file, + kf_group, + "Address", + nm_sprintf_buf(buf, + "%s/%u", + nm_ip_address_get_address(addr), + nm_ip_address_get_prefix(addr))); + if (gw) + g_key_file_set_string(file, kf_group, "Gateway", gw); } - addr = nm_setting_ip_config_get_address(s_ip, 0); - g_key_file_set_string(file, - "IPv6", - "Address", - nm_sprintf_buf(buf, - "%s/%u", - nm_ip_address_get_address(addr), - nm_ip_address_get_prefix(addr))); - if (nm_setting_ip_config_get_gateway(s_ip)) - g_key_file_set_string(file, "IPv6", "Gateway", nm_setting_ip_config_get_gateway(s_ip)); return TRUE; } @@ -1759,13 +1740,15 @@ nm_wifi_utils_connection_to_iwd_config(NMConnection *connection, else if (cloned_mac_addr && nm_utils_hwaddr_valid(cloned_mac_addr, ETH_ALEN)) g_key_file_set_string(file, "Settings", "AddressOverride", cloned_mac_addr); - if (!ip4_config_to_iwd_config( + if (!ip_config_to_iwd_config( + AF_INET, file, NM_SETTING_IP_CONFIG(nm_connection_get_setting_ip4_config(connection)), error)) return NULL; - if (!ip6_config_to_iwd_config( + if (!ip_config_to_iwd_config( + AF_INET6, file, NM_SETTING_IP_CONFIG(nm_connection_get_setting_ip6_config(connection)), error)) diff --git a/src/core/devices/wwan/nm-device-modem.c b/src/core/devices/wwan/nm-device-modem.c index e0209aff..b83120f9 100644 --- a/src/core/devices/wwan/nm-device-modem.c +++ b/src/core/devices/wwan/nm-device-modem.c @@ -273,6 +273,15 @@ modem_state_cb(NMModem *modem, int new_state_i, int old_state_i, gpointer user_d /* Called when the ModemManager modem enabled state is changed externally * to NetworkManager (eg something using MM's D-Bus API directly). */ + + if (!NM_MODEM_GET_CLASS(priv->modem)->set_mm_enabled) { + /* We cannot re-enable this modem, thus device becomes unavailable. */ + nm_device_state_changed(device, + NM_DEVICE_STATE_UNAVAILABLE, + NM_DEVICE_STATE_REASON_USER_REQUESTED); + return; + } + if (nm_device_is_activating(device) || dev_state == NM_DEVICE_STATE_ACTIVATED) { /* user-initiated action, hence DISCONNECTED not FAILED */ nm_device_state_changed(device, @@ -435,6 +444,13 @@ check_connection_available(NMDevice *device, return FALSE; } + if (!NM_MODEM_GET_CLASS(priv->modem)->set_mm_enabled && state <= NM_MODEM_STATE_DISABLING) { + nm_utils_error_set_literal(error, + NM_UTILS_ERROR_CONNECTION_AVAILABLE_TEMPORARY, + "modem is disabled and NM cannot enable it"); + return FALSE; + } + if (state == NM_MODEM_STATE_LOCKED) { if (!nm_connection_get_setting_gsm(connection)) { nm_utils_error_set_literal(error, @@ -599,6 +615,11 @@ set_enabled(NMDevice *device, gboolean enabled) if (enabled == FALSE) { nm_device_state_changed(device, NM_DEVICE_STATE_UNAVAILABLE, NM_DEVICE_STATE_REASON_NONE); + } else { + /* It's possible that the modem is enabled outside of NM. Need to recheck. */ + nm_device_queue_recheck_available(device, + NM_DEVICE_STATE_REASON_MODEM_AVAILABLE, + NM_DEVICE_STATE_REASON_MODEM_FAILED); } } @@ -617,6 +638,9 @@ is_available(NMDevice *device, NMDeviceCheckDevAvailableFlags flags) if (modem_state <= NM_MODEM_STATE_INITIALIZING) return FALSE; + if (!NM_MODEM_GET_CLASS(priv->modem)->set_mm_enabled && modem_state <= NM_MODEM_STATE_DISABLING) + return FALSE; + return TRUE; } diff --git a/src/core/devices/wwan/nm-device-modem.h b/src/core/devices/wwan/nm-device-modem.h index f171d76f..317a5bde 100644 --- a/src/core/devices/wwan/nm-device-modem.h +++ b/src/core/devices/wwan/nm-device-modem.h @@ -11,7 +11,7 @@ #define NM_TYPE_DEVICE_MODEM (nm_device_modem_get_type()) #define NM_DEVICE_MODEM(obj) \ - (G_TYPE_CHECK_INSTANCE_CAST((obj), NM_TYPE_DEVICE_MODEM, NMDeviceModem)) + (_NM_G_TYPE_CHECK_INSTANCE_CAST((obj), NM_TYPE_DEVICE_MODEM, NMDeviceModem)) #define NM_DEVICE_MODEM_CLASS(klass) \ (G_TYPE_CHECK_CLASS_CAST((klass), NM_TYPE_DEVICE_MODEM, NMDeviceModemClass)) #define NM_IS_DEVICE_MODEM(obj) (G_TYPE_CHECK_INSTANCE_TYPE((obj), NM_TYPE_DEVICE_MODEM)) diff --git a/src/core/devices/wwan/nm-modem-broadband.c b/src/core/devices/wwan/nm-modem-broadband.c index db4fb29f..f0907c46 100644 --- a/src/core/devices/wwan/nm-modem-broadband.c +++ b/src/core/devices/wwan/nm-modem-broadband.c @@ -636,7 +636,7 @@ connect_context_step(NMModemBroadband *self) if (ctx->ip_types_i < ctx->ip_types->len) { NMModemIPType current; - current = g_array_index(ctx->ip_types, NMModemIPType, ctx->ip_types_i); + current = nm_g_array_index(ctx->ip_types, NMModemIPType, ctx->ip_types_i); if (current == NM_MODEM_IP_TYPE_IPV4) mm_simple_connect_properties_set_ip_type(ctx->connect_properties, @@ -993,7 +993,7 @@ stage3_ip_config_start(NMModem *modem, int addr_family, NMModemIPMethod ip_metho /* Fully fail if invalid IP address retrieved */ address_string = mm_bearer_ip_config_get_address(self->_priv.ipv4_config); if (!address_string - || !nm_utils_parse_inaddr_bin(AF_INET, address_string, NULL, &address_network)) { + || !nm_inet_parse_bin(AF_INET, address_string, NULL, &address_network)) { g_set_error(&error, NM_DEVICE_ERROR, NM_DEVICE_ERROR_INVALID_CONNECTION, @@ -1005,7 +1005,7 @@ stage3_ip_config_start(NMModem *modem, int addr_family, NMModemIPMethod ip_metho /* Missing gateway not a hard failure */ gw_string = mm_bearer_ip_config_get_gateway(self->_priv.ipv4_config); - if (gw_string && !nm_utils_parse_inaddr_bin(AF_INET, gw_string, NULL, &gw)) { + if (gw_string && !nm_inet_parse_bin(AF_INET, gw_string, NULL, &gw)) { g_set_error(&error, NM_DEVICE_ERROR, NM_DEVICE_ERROR_INVALID_CONNECTION, @@ -1057,9 +1057,8 @@ stage3_ip_config_start(NMModem *modem, int addr_family, NMModemIPMethod ip_metho dns = mm_bearer_ip_config_get_dns(self->_priv.ipv4_config); for (i = 0; dns && dns[i]; i++) { - if (nm_utils_parse_inaddr_bin(AF_INET, dns[i], NULL, &address_network) - && address_network > 0) { - nm_l3_config_data_add_nameserver(l3cd, AF_INET, &address_network); + if (nm_inet_parse_bin(AF_INET, dns[i], NULL, &address_network) && address_network > 0) { + nm_l3_config_data_add_nameserver_detail(l3cd, AF_INET, &address_network, NULL); _LOGI(" DNS %s", dns[i]); } } @@ -1174,7 +1173,7 @@ stage3_ip_config_start(NMModem *modem, int addr_family, NMModemIPMethod ip_metho struct in6_addr addr; if (inet_pton(AF_INET6, dns[i], &addr)) { - nm_l3_config_data_add_nameserver(l3cd, AF_INET6, &addr); + nm_l3_config_data_add_nameserver_detail(l3cd, AF_INET6, &addr, NULL); _LOGI(" DNS %s", dns[i]); } } diff --git a/src/core/devices/wwan/nm-modem-broadband.h b/src/core/devices/wwan/nm-modem-broadband.h index 627fe25a..e4467310 100644 --- a/src/core/devices/wwan/nm-modem-broadband.h +++ b/src/core/devices/wwan/nm-modem-broadband.h @@ -10,7 +10,7 @@ #define NM_TYPE_MODEM_BROADBAND (nm_modem_broadband_get_type()) #define NM_MODEM_BROADBAND(obj) \ - (G_TYPE_CHECK_INSTANCE_CAST((obj), NM_TYPE_MODEM_BROADBAND, NMModemBroadband)) + (_NM_G_TYPE_CHECK_INSTANCE_CAST((obj), NM_TYPE_MODEM_BROADBAND, NMModemBroadband)) #define NM_MODEM_BROADBAND_CLASS(klass) \ (G_TYPE_CHECK_CLASS_CAST((klass), NM_TYPE_MODEM_BROADBAND, NMModemBroadbandClass)) #define NM_IS_MODEM_BROADBAND(obj) (G_TYPE_CHECK_INSTANCE_TYPE((obj), NM_TYPE_MODEM_BROADBAND)) diff --git a/src/core/devices/wwan/nm-modem-manager.h b/src/core/devices/wwan/nm-modem-manager.h index e89a032b..a9339ffc 100644 --- a/src/core/devices/wwan/nm-modem-manager.h +++ b/src/core/devices/wwan/nm-modem-manager.h @@ -12,7 +12,7 @@ #define NM_TYPE_MODEM_MANAGER (nm_modem_manager_get_type()) #define NM_MODEM_MANAGER(obj) \ - (G_TYPE_CHECK_INSTANCE_CAST((obj), NM_TYPE_MODEM_MANAGER, NMModemManager)) + (_NM_G_TYPE_CHECK_INSTANCE_CAST((obj), NM_TYPE_MODEM_MANAGER, NMModemManager)) #define NM_MODEM_MANAGER_CLASS(klass) \ (G_TYPE_CHECK_CLASS_CAST((klass), NM_TYPE_MODEM_MANAGER, NMModemManagerClass)) #define NM_IS_MODEM_MANAGER(obj) (G_TYPE_CHECK_INSTANCE_TYPE((obj), NM_TYPE_MODEM_MANAGER)) diff --git a/src/core/devices/wwan/nm-modem-ofono.c b/src/core/devices/wwan/nm-modem-ofono.c index fc27c3fd..b3745621 100644 --- a/src/core/devices/wwan/nm-modem-ofono.c +++ b/src/core/devices/wwan/nm-modem-ofono.c @@ -7,8 +7,12 @@ #include "nm-modem-ofono.h" +#include "libnm-glib-aux/nm-dbus-aux.h" #include "libnm-core-intern/nm-core-internal.h" +#include "libnm-glib-aux/nm-uuid.h" #include "devices/nm-device-private.h" +#include "nm-setting-gsm.h" +#include "settings/nm-settings.h" #include "nm-modem.h" #include "libnm-platform/nm-platform.h" #include "nm-l3-config-data.h" @@ -27,27 +31,44 @@ /*****************************************************************************/ typedef struct { + NMModemOfono *self; + char *name; + char *type; + gboolean preferred; + GDBusProxy *proxy; +} OfonoContextData; + +typedef struct { GHashTable *connect_properties; + GHashTable *connections; + GHashTable *contexts; GDBusProxy *modem_proxy; GDBusProxy *connman_proxy; - GDBusProxy *context_proxy; GDBusProxy *sim_proxy; GCancellable *modem_proxy_cancellable; GCancellable *connman_proxy_cancellable; - GCancellable *context_proxy_cancellable; + GCancellable *connect_cancellable; GCancellable *sim_proxy_cancellable; GError *property_error; - char *context_path; char *imsi; gboolean modem_online; + gboolean connman_powered; gboolean gprs_attached; NML3ConfigData *l3cd_4; + NMSettings *settings; + + guint n_context_proxy_pending; + + /* unowned; reference held by 'contexts' above. */ + OfonoContextData *current_octx; + + GSource *deferred_connection_timeout_source; } NMModemOfonoPrivate; struct _NMModemOfono { @@ -96,6 +117,21 @@ G_DEFINE_TYPE(NMModemOfono, nm_modem_ofono, NM_TYPE_MODEM) /*****************************************************************************/ +/* + * Deterministic UUID is used to pair imsi+context with exported connection + * (via a pair of hash tables). + */ + +static char * +_generate_uuid(const char *imsi, const char *object_path) +{ + return nm_uuid_generate_from_strings( + NM_UUID_TYPE_VERSION5, + &NM_UUID_INIT(b5, 6b, ad, f5, ef, 9d, 4a, 21, a8, e7, 7d, db, 69, bb, 6b, ee), + imsi, + object_path); +} + static void get_capabilities(NMModem *_self, NMDeviceModemCapabilities *modem_caps, @@ -106,6 +142,8 @@ get_capabilities(NMModem *_self, *current_caps = NM_DEVICE_MODEM_CAPABILITY_GSM_UMTS; } +static void do_context_activate(NMModemOfono *self); + static void update_modem_state(NMModemOfono *self) { @@ -114,13 +152,16 @@ update_modem_state(NMModemOfono *self) NMModemState new_state = NM_MODEM_STATE_DISABLED; const char *reason = NULL; - _LOGI("'Attached': %s 'Online': %s 'IMSI': %s", + _LOGI("'Attached': %s 'Online': %s 'Powered': %s 'IMSI': %s", priv->gprs_attached ? "true" : "false", priv->modem_online ? "true" : "false", + priv->connman_powered ? "true" : "false", priv->imsi); if (priv->modem_online == FALSE) { reason = "modem 'Online=false'"; + } else if (priv->connman_powered == FALSE) { + reason = "ConnectionManager 'Powered=false'"; } else if (priv->imsi == NULL && state != NM_MODEM_STATE_ENABLING) { reason = "modem not ready"; } else if (priv->gprs_attached == FALSE) { @@ -131,8 +172,27 @@ update_modem_state(NMModemOfono *self) reason = "modem ready"; } - if (state != new_state) + if (state != new_state) { + if (new_state == NM_MODEM_STATE_DISABLED && priv->deferred_connection_timeout_source) { + /* + * Do this before set_state(), because we want the final device state + * to be "unavailable", not "failed" or "disconnected". + */ + _LOGI("canceling deferred context activation"); + + nm_clear_g_source_inst(&priv->deferred_connection_timeout_source); + nm_modem_emit_prepare_result(NM_MODEM(self), FALSE, NM_DEVICE_STATE_REASON_MODEM_BUSY); + } + nm_modem_set_state(NM_MODEM(self), new_state, reason); + + if (new_state == NM_MODEM_STATE_REGISTERED && priv->deferred_connection_timeout_source) { + _LOGI("resuming deferred context activation"); + + nm_clear_g_source_inst(&priv->deferred_connection_timeout_source); + do_context_activate(self); + } + } } /* Disconnect */ @@ -213,7 +273,8 @@ disconnect(NMModem *modem, ctx->callback = callback; ctx->callback_user_data = user_data; - if (state != NM_MODEM_STATE_CONNECTED || g_cancellable_is_cancelled(cancellable)) { + if (state != NM_MODEM_STATE_CONNECTED || g_cancellable_is_cancelled(cancellable) + || priv->current_octx == NULL) { nm_utils_invoke_on_idle(cancellable, disconnect_context_complete_on_idle, ctx); return; } @@ -222,7 +283,7 @@ disconnect(NMModem *modem, NM_MODEM_STATE_DISCONNECTING, nm_modem_state_to_string(NM_MODEM_STATE_DISCONNECTING)); - g_dbus_proxy_call(priv->context_proxy, + g_dbus_proxy_call(priv->current_octx->proxy, "SetProperty", g_variant_new("(sv)", "Active", g_variant_new("b", warn)), G_DBUS_CALL_FLAGS_NONE, @@ -230,6 +291,8 @@ disconnect(NMModem *modem, ctx->cancellable, disconnect_done, ctx); + + priv->current_octx = NULL; } static void @@ -251,7 +314,7 @@ check_connection_compatible_with_modem(NMModem *modem, NMConnection *connection, { NMModemOfono *self = NM_MODEM_OFONO(modem); NMModemOfonoPrivate *priv = NM_MODEM_OFONO_GET_PRIVATE(self); - const char *id; + const char *uuid; if (!_nm_connection_check_main_setting(connection, NM_SETTING_GSM_SETTING_NAME, NULL)) { nm_utils_error_set(error, @@ -268,19 +331,12 @@ check_connection_compatible_with_modem(NMModem *modem, NMConnection *connection, return FALSE; } - id = nm_connection_get_id(connection); - - if (!strstr(id, "/context")) { - nm_utils_error_set_literal(error, - NM_UTILS_ERROR_CONNECTION_AVAILABLE_TEMPORARY, - "the connection ID has no context"); - return FALSE; - } + uuid = nm_connection_get_uuid(connection); - if (!strstr(id, priv->imsi)) { + if (!g_hash_table_contains(priv->contexts, uuid)) { nm_utils_error_set_literal(error, NM_UTILS_ERROR_CONNECTION_AVAILABLE_TEMPORARY, - "the connection ID does not contain the IMSI"); + "connection ID does not match known contexts"); return FALSE; } @@ -398,11 +454,11 @@ _sim_proxy_new_cb(GObject *source, GAsyncResult *result, gpointer user_data) priv->sim_proxy = proxy; /* Watch for custom ofono PropertyChanged signals */ - _nm_dbus_signal_connect(priv->sim_proxy, - "PropertyChanged", - G_VARIANT_TYPE("(sv)"), - G_CALLBACK(sim_property_changed), - self); + _nm_dbus_proxy_signal_connect(priv->sim_proxy, + "PropertyChanged", + G_VARIANT_TYPE("(sv)"), + G_CALLBACK(sim_property_changed), + self); g_dbus_proxy_call(priv->sim_proxy, "GetProperties", @@ -469,6 +525,19 @@ handle_connman_property(GDBusProxy *proxy, const char *property, GVariant *v, gp update_modem_state(self); } + } else if (nm_streq(property, "Powered") && VARIANT_IS_OF_TYPE_BOOLEAN(v)) { + gboolean powered = g_variant_get_boolean(v); + gboolean old_powered = priv->connman_powered; + + _LOGD("Powered: %s", powered ? "True" : "False"); + + if (old_powered != powered) { + priv->connman_powered = powered; + + _LOGI("Powered %s -> %s", old_powered ? "true" : "false", powered ? "true" : "false"); + + update_modem_state(self); + } } } @@ -484,7 +553,6 @@ static void connman_get_properties_done(GObject *source, GAsyncResult *result, gpointer user_data) { NMModemOfono *self; - NMModemOfonoPrivate *priv; gs_free_error GError *error = NULL; gs_unref_variant GVariant *v_properties = NULL; gs_unref_variant GVariant *v_dict = NULL; @@ -498,9 +566,6 @@ connman_get_properties_done(GObject *source, GAsyncResult *result, gpointer user return; self = NM_MODEM_OFONO(user_data); - priv = NM_MODEM_OFONO_GET_PRIVATE(self); - - g_clear_object(&priv->connman_proxy_cancellable); if (!v_properties) { g_dbus_error_strip_remote_error(error); @@ -526,6 +591,366 @@ connman_get_properties_done(GObject *source, GAsyncResult *result, gpointer user } static void +ofono_context_data_free(OfonoContextData *octx) +{ + g_free(octx->name); + g_free(octx->type); + + if (octx->proxy) { + g_signal_handlers_disconnect_by_data(octx->proxy, octx); + g_object_unref(octx->proxy); + } + + g_slice_free(OfonoContextData, octx); +} + +static void +add_or_update_connection(NMModemOfono *self, const char *context_name, const char *uuid) +{ + NMModemOfonoPrivate *priv = NM_MODEM_OFONO_GET_PRIVATE(self); + gs_unref_object NMConnection *connection = NULL; + NMSetting *setting; + NMSettingsConnection *sett_conn; + gs_free_error GError *error = NULL; + + /* + * See first if we have an existing connection (from previous or current + * run of NM) that we can update in-place. + */ + + sett_conn = nm_settings_get_connection_by_uuid(priv->settings, uuid); + if (sett_conn + && !NM_FLAGS_HAS(nm_settings_connection_get_flags(sett_conn), + NM_SETTINGS_CONNECTION_INT_FLAGS_NM_GENERATED)) { + /* + * Either we have a coliding connection, or our connection has been + * modified by user. For the latter case it's safe to leave it alone; + * the UUID will still let it connect. However, for the first case, + * we can't really do anything about it unless we re-write the way we + * track connection <-> context, which I (Ratchanan) don't want to do + * right now... + */ + return; + } + + connection = nm_simple_connection_new(); + setting = nm_setting_connection_new(); + g_object_set(setting, + NM_SETTING_CONNECTION_ID, + context_name, + NM_SETTING_CONNECTION_UUID, + uuid, + NM_SETTING_CONNECTION_AUTOCONNECT, + TRUE, + NM_SETTING_CONNECTION_TYPE, + NM_SETTING_GSM_SETTING_NAME, + NULL); + nm_connection_add_setting(connection, setting); + + setting = nm_setting_gsm_new(); + + /* + * oFono should already know how to handle placing the call, but NM + * insists on having a number. Pass the usual *99#. + */ + g_object_set(setting, NM_SETTING_GSM_NUMBER, "*99#", NULL); + nm_connection_add_setting(connection, setting); + + if (!nm_connection_normalize(connection, NULL, NULL, &error)) { + nm_log_err(LOGD_MB, + "ofono: could not not generate a connection for %s: %s", + context_name, + error->message); + return; + } + + if (!sett_conn) { + nm_settings_add_connection(priv->settings, + NULL, /* plugin */ + connection, + NM_SETTINGS_CONNECTION_PERSIST_MODE_IN_MEMORY_ONLY, + NM_SETTINGS_CONNECTION_ADD_REASON_NONE, + NM_SETTINGS_CONNECTION_INT_FLAGS_NM_GENERATED, + &sett_conn, + &error); + } else { + nm_settings_update_connection(priv->settings, + sett_conn, + NULL, /* plugin_name */ + connection, + NM_SETTINGS_CONNECTION_PERSIST_MODE_IN_MEMORY_ONLY, + NM_SETTINGS_CONNECTION_INT_FLAGS_NM_GENERATED, + NM_SETTINGS_CONNECTION_INT_FLAGS_NONE, + NM_SETTINGS_CONNECTION_UPDATE_REASON_NONE, + /* log_context_name */ "ofono", + &error); + } + + if (!sett_conn) { + nm_log_warn(LOGD_MB, + "ofono: could not add or update new connection for '%s' (%s): %s", + context_name, + uuid, + error->message); + return; + } + + g_hash_table_insert(priv->connections, g_strdup(uuid), g_object_ref(sett_conn)); +} + +/* + * Used when we decide a connection is not needed. Rationale being that the + * connection could have been modified by user since it's created by us, + * after which we don't want to delete, but we don't want to track it either. + */ + +static void +untrack_connection_and_delete_if_generated(NMModemOfono *self, char const *uuid) +{ + NMModemOfonoPrivate *priv = NM_MODEM_OFONO_GET_PRIVATE(self); + NMSettingsConnection *sett_conn; + + sett_conn = g_hash_table_lookup(priv->connections, uuid); + if (!sett_conn) + return; + + if (NM_FLAGS_HAS(nm_settings_connection_get_flags(sett_conn), + NM_SETTINGS_CONNECTION_INT_FLAGS_NM_GENERATED)) + nm_settings_connection_delete(sett_conn, FALSE); + + g_hash_table_remove(priv->connections, uuid); +} + +static void +update_connection_list(NMModemOfono *self) +{ + NMModemOfonoPrivate *priv = NM_MODEM_OFONO_GET_PRIVATE(self); + GHashTableIter iter; + char *uuid; + OfonoContextData *octx; + OfonoContextData *octx_preferred = NULL; + + _LOGI("(re-)checking which context needs a connection"); + + g_hash_table_iter_init(&iter, priv->contexts); + while (g_hash_table_iter_next(&iter, (gpointer *) &uuid, (gpointer *) &octx)) { + if (octx->preferred) { + octx_preferred = octx; + break; + } + } + + g_hash_table_iter_init(&iter, priv->contexts); + while (g_hash_table_iter_next(&iter, (gpointer *) &uuid, (gpointer *) &octx)) { + gboolean connection_should_exist = + (!octx_preferred || octx_preferred == octx) + && (nm_streq(octx->type, "internet") || nm_streq(octx->type, "internet+mms")); + gboolean connection_exists = g_hash_table_contains(priv->connections, uuid); + + if (connection_should_exist && !connection_exists) { + _LOGI("creating connection for %s%s", + octx_preferred ? "preferred context " : "", + g_dbus_proxy_get_object_path(octx->proxy)); + add_or_update_connection(self, octx->name, uuid); + } else if (!connection_should_exist && connection_exists) { + _LOGI("removing connection for %s", g_dbus_proxy_get_object_path(octx->proxy)); + untrack_connection_and_delete_if_generated(self, uuid); + + /* priv->current_octx is deliberately not cleared here because the + * disconnection chain happens in another main loop iteration. + */ + } + } +} + +static void handle_settings(NMModemOfono *self, GVariant *v_dict); + +static void +context_property_changed(GDBusProxy *proxy, const char *property, GVariant *v, gpointer user_data) +{ + OfonoContextData *octx = user_data; + NMModemOfono *self = octx->self; + NMModemOfonoPrivate *priv = NM_MODEM_OFONO_GET_PRIVATE(self); + gs_unref_variant GVariant *v_inner = g_variant_get_child_value(v, 0); + + if (!v_inner) { + _LOGW("ofono: (%s): error handling PropertyChanged signal", + nm_modem_get_uid(NM_MODEM(self))); + return; + } + + if (nm_streq(property, "Name")) { + gs_free char *uuid = NULL; + + g_return_if_fail(g_variant_is_of_type(v_inner, G_VARIANT_TYPE_STRING)); + g_free(octx->name); + octx->name = g_variant_dup_string(v_inner, /* &length */ NULL); + + uuid = _generate_uuid(priv->imsi, g_dbus_proxy_get_object_path(proxy)); + if (g_hash_table_contains(priv->connections, uuid)) + add_or_update_connection(self, octx->name, uuid); + } else if (nm_streq(property, "Type")) { + g_return_if_fail(g_variant_is_of_type(v_inner, G_VARIANT_TYPE_STRING)); + g_free(octx->type); + octx->type = g_variant_dup_string(v_inner, /* &length */ NULL); + + update_connection_list(self); + } else if (nm_streq(property, "Preferred")) { + g_return_if_fail(g_variant_is_of_type(v_inner, G_VARIANT_TYPE_BOOLEAN)); + octx->preferred = g_variant_get_boolean(v_inner); + + update_connection_list(self); + } else if (nm_streq(property, "Settings") && priv->current_octx == octx) { + g_return_if_fail(g_variant_is_of_type(v_inner, G_VARIANT_TYPE_VARDICT)); + handle_settings(self, v_inner); + } +} + +static void +_context_proxy_new_cb(GObject *source, GAsyncResult *result, gpointer user_data) +{ + OfonoContextData *octx = user_data; + NMModemOfono *self; + NMModemOfonoPrivate *priv; + gs_free_error GError *error = NULL; + GDBusProxy *proxy; + char *uuid; + + proxy = g_dbus_proxy_new_for_bus_finish(result, &error); + if (!proxy && g_error_matches(error, G_IO_ERROR, G_IO_ERROR_CANCELLED)) { + ofono_context_data_free(octx); + return; + } + + self = octx->self; + priv = NM_MODEM_OFONO_GET_PRIVATE(self); + + if (!proxy) { + _LOGW("failed to create ConnectionContext proxy: %s", error->message); + ofono_context_data_free(octx); + return; + } + + _LOGD("recieved proxy for %s", g_dbus_proxy_get_object_path(proxy)); + octx->proxy = proxy; + + _nm_dbus_proxy_signal_connect(proxy, + "PropertyChanged", + G_VARIANT_TYPE("(sv)"), + G_CALLBACK(context_property_changed), + octx); + + uuid = _generate_uuid(priv->imsi, g_dbus_proxy_get_object_path(proxy)); + g_hash_table_insert(priv->contexts, uuid, octx); + priv->n_context_proxy_pending--; + + if (priv->n_context_proxy_pending == 0) + update_connection_list(self); +} + +static void +connman_context_removed(GDBusProxy *proxy, const char *object_path, gpointer user_data) +{ + NMModemOfono *self = NM_MODEM_OFONO(user_data); + NMModemOfonoPrivate *priv = NM_MODEM_OFONO_GET_PRIVATE(self); + gs_free char *uuid = NULL; + OfonoContextData *octx; + + /* look up the connction, and if we have connection disconnect and remove it */ + uuid = _generate_uuid(priv->imsi, object_path); + untrack_connection_and_delete_if_generated(self, uuid); + + octx = g_hash_table_lookup(priv->contexts, uuid); + if (octx) { + gboolean preferred = octx->preferred; + + if (octx == priv->current_octx) + priv->current_octx = NULL; + + g_hash_table_remove(priv->contexts, uuid); + + if (preferred) + update_connection_list(self); + } +} + +static void +connman_context_added(GDBusProxy *proxy, const char *object_path, GVariant *v, gpointer user_data) +{ + NMModemOfono *self = user_data; + NMModemOfonoPrivate *priv = NM_MODEM_OFONO_GET_PRIVATE(self); + OfonoContextData *octx; + gs_unref_variant GVariant *v_context_type = NULL; + gs_unref_variant GVariant *v_context_name = NULL; + gs_unref_variant GVariant *v_context_preferred = NULL; + + nm_log_info(LOGD_MB, "ofono: processing context %s", object_path); + + v_context_name = g_variant_lookup_value(v, "Name", G_VARIANT_TYPE_STRING); + v_context_type = g_variant_lookup_value(v, "Type", G_VARIANT_TYPE_STRING); + if (!v_context_name || !v_context_type) { + nm_log_err(LOGD_MB, "ofono: context dictionary is missing required key(s)."); + return; + } + + /* Preferred property exists in some oFono fork only (mostly Ubuntu Touch's). */ + v_context_preferred = g_variant_lookup_value(v, "Preferred", G_VARIANT_TYPE_BOOLEAN); + + octx = g_slice_new0(OfonoContextData); + octx->self = self; + octx->name = g_variant_dup_string(v_context_name, NULL); + octx->type = g_variant_dup_string(v_context_type, NULL); + octx->preferred = v_context_preferred && g_variant_get_boolean(v_context_preferred); + + priv->n_context_proxy_pending++; + g_dbus_proxy_new_for_bus(G_BUS_TYPE_SYSTEM, + G_DBUS_PROXY_FLAGS_DO_NOT_LOAD_PROPERTIES + | G_DBUS_PROXY_FLAGS_DO_NOT_AUTO_START, + NULL, /* GDBusInterfaceInfo */ + OFONO_DBUS_SERVICE, + object_path, + OFONO_DBUS_INTERFACE_CONNECTION_CONTEXT, + priv->connman_proxy_cancellable, + _context_proxy_new_cb, + octx); +} + +static void +connman_get_contexts_done(GObject *source, GAsyncResult *result, gpointer user_data) +{ + NMModemOfono *self; + gs_free_error GError *error = NULL; + gs_unref_variant GVariant *v_contexts = NULL; + gs_unref_variant GVariant *v_objects = NULL; + gs_unref_variant GVariant *v = NULL; + GVariantIter i; + const char *object_path; + + v_contexts = _nm_dbus_proxy_call_finish(G_DBUS_PROXY(source), + result, + G_VARIANT_TYPE("(a(oa{sv}))"), + &error); + if (!v_contexts && g_error_matches(error, G_IO_ERROR, G_IO_ERROR_CANCELLED)) + return; + + self = user_data; + + if (!v_contexts) { + g_dbus_error_strip_remote_error(error); + _LOGW("Error getting list of contexts: %s", error->message); + return; + } + + nm_log_info(LOGD_MB, "ofono: printing %s", g_variant_get_type_string(v_contexts)); + + v_objects = g_variant_get_child_value(v_contexts, 0); + + g_variant_iter_init(&i, v_objects); + while (g_variant_iter_loop(&i, "(&o@a{sv})", &object_path, &v)) + connman_context_added(NULL, object_path, v, self); +} + +static void _connman_proxy_new_cb(GObject *source, GAsyncResult *result, gpointer user_data) { NMModemOfono *self; @@ -548,11 +973,23 @@ _connman_proxy_new_cb(GObject *source, GAsyncResult *result, gpointer user_data) priv->connman_proxy = proxy; - _nm_dbus_signal_connect(priv->connman_proxy, - "PropertyChanged", - G_VARIANT_TYPE("(sv)"), - G_CALLBACK(connman_property_changed), - self); + _nm_dbus_proxy_signal_connect(priv->connman_proxy, + "PropertyChanged", + G_VARIANT_TYPE("(sv)"), + G_CALLBACK(connman_property_changed), + self); + + _nm_dbus_proxy_signal_connect(priv->connman_proxy, + "ContextAdded", + G_VARIANT_TYPE("(oa{sv})"), + G_CALLBACK(connman_context_added), + self); + + _nm_dbus_proxy_signal_connect(priv->connman_proxy, + "ContextRemoved", + G_VARIANT_TYPE("(o)"), + G_CALLBACK(connman_context_removed), + self); g_dbus_proxy_call(priv->connman_proxy, "GetProperties", @@ -562,6 +999,15 @@ _connman_proxy_new_cb(GObject *source, GAsyncResult *result, gpointer user_data) priv->connman_proxy_cancellable, connman_get_properties_done, self); + + g_dbus_proxy_call(priv->connman_proxy, + "GetContexts", + NULL, + G_DBUS_CALL_FLAGS_NONE, + 20000, + priv->connman_proxy_cancellable, + connman_get_contexts_done, + self); } static void @@ -572,6 +1018,9 @@ handle_connman_iface(NMModemOfono *self, gboolean found) _LOGD("ConnectionManager interface %sfound", found ? "" : "not "); if (!found && (priv->connman_proxy || priv->connman_proxy_cancellable)) { + GHashTableIter iter; + NMSettingsConnection *conn; + _LOGI("ConnectionManager interface disappeared"); nm_clear_g_cancellable(&priv->connman_proxy_cancellable); if (priv->connman_proxy) { @@ -584,6 +1033,18 @@ handle_connman_iface(NMModemOfono *self, gboolean found) */ priv->gprs_attached = FALSE; + g_hash_table_iter_init(&iter, priv->connections); + while (g_hash_table_iter_next(&iter, NULL, (gpointer *) &conn)) { + if (NM_FLAGS_HAS(nm_settings_connection_get_flags(conn), + NM_SETTINGS_CONNECTION_INT_FLAGS_NM_GENERATED)) { + nm_settings_connection_delete(conn, FALSE); + } + } + + priv->current_octx = NULL; + g_hash_table_remove_all(priv->connections); + g_hash_table_remove_all(priv->contexts); + update_modem_state(self); } else if (found && (!priv->connman_proxy && !priv->connman_proxy_cancellable)) { _LOGI("found new ConnectionManager interface"); @@ -716,7 +1177,7 @@ stage1_prepare_done(GObject *source, GAsyncResult *result, gpointer user_data) self = NM_MODEM_OFONO(user_data); priv = NM_MODEM_OFONO_GET_PRIVATE(self); - g_clear_object(&priv->context_proxy_cancellable); + g_clear_object(&priv->connect_cancellable); nm_clear_pointer(&priv->connect_properties, g_hash_table_destroy); @@ -730,9 +1191,8 @@ stage1_prepare_done(GObject *source, GAsyncResult *result, gpointer user_data) } static void -handle_settings(GVariant *v_dict, gpointer user_data) +handle_settings(NMModemOfono *self, GVariant *v_dict) { - NMModemOfono *self = NM_MODEM_OFONO(user_data); NMModemOfonoPrivate *priv = NM_MODEM_OFONO_GET_PRIVATE(self); char sbuf[NM_UTILS_TO_STRING_BUFFER_SIZE]; NMPlatformIP4Address address; @@ -744,14 +1204,20 @@ handle_settings(GVariant *v_dict, gpointer user_data) int ifindex; GError *error = NULL; - //_LOGD("PropertyChanged: %s", property); - /* * TODO: might be a good idea and re-factor this to mimic bluez-device, * ie. have this function just check the key, and call a sub-func to * handle the action. */ + if (nm_modem_get_state(NM_MODEM(self)) < NM_MODEM_STATE_REGISTERED) { + /* + * Connection definitely isn't happening. Avoid trigering bogus + * failure which would put device in a wrong state. + */ + return; + } + _LOGI("IPv4 static Settings:"); if (!g_variant_lookup(v_dict, "Interface", "&s", &interface)) { @@ -786,7 +1252,7 @@ handle_settings(GVariant *v_dict, gpointer user_data) _LOGW("Settings 'Address' missing"); goto out; } - if (!s || !nm_utils_parse_inaddr_bin(AF_INET, s, NULL, &address_network)) { + if (!s || !nm_inet_parse_bin(AF_INET, s, NULL, &address_network)) { _LOGW("can't convert 'Address' %s to addr", s ?: ""); goto out; } @@ -801,11 +1267,11 @@ handle_settings(GVariant *v_dict, gpointer user_data) _LOGW("Settings 'Netmask' missing"); goto out; } - if (!s || !nm_utils_parse_inaddr_bin(AF_INET, s, NULL, &address_network)) { + if (!s || !nm_inet_parse_bin(AF_INET, s, NULL, &address_network)) { _LOGW("invalid 'Netmask': %s", s ?: ""); goto out; } - address.plen = _nm_utils_ip4_netmask_to_prefix(address_network); + address.plen = nm_ip4_addr_netmask_to_prefix(address_network); _LOGI("Address: %s", nm_platform_ip4_address_to_string(&address, sbuf, sizeof(sbuf))); nm_l3_config_data_add_address_4(priv->l3cd_4, &address); @@ -814,7 +1280,7 @@ handle_settings(GVariant *v_dict, gpointer user_data) _LOGW("Settings 'Gateway' missing"); goto out; } - if (!nm_utils_parse_inaddr_bin(AF_INET, s, NULL, &gateway_network)) { + if (!nm_inet_parse_bin(AF_INET, s, NULL, &gateway_network)) { _LOGW("invalid 'Gateway': %s", s); goto out; } @@ -841,14 +1307,13 @@ handle_settings(GVariant *v_dict, gpointer user_data) gsize i; for (i = 0; array[i]; i++) { - if (!nm_utils_parse_inaddr_bin(AF_INET, array[i], NULL, &address_network) - || !address_network) { + if (!nm_inet_parse_bin(AF_INET, array[i], NULL, &address_network) || !address_network) { _LOGW("invalid NameServer: %s", array[i]); continue; } any_good = TRUE; _LOGI("DNS: %s", array[i]); - nm_l3_config_data_add_nameserver(priv->l3cd_4, AF_INET, &address_network); + nm_l3_config_data_add_nameserver_detail(priv->l3cd_4, AF_INET, &address_network, NULL); } if (!any_good) { _LOGW("Settings: 'DomainNameServers': none specified"); @@ -858,7 +1323,7 @@ handle_settings(GVariant *v_dict, gpointer user_data) if (g_variant_lookup(v_dict, "MessageProxy", "&s", &s)) { _LOGI("MessageProxy: %s", s); - if (s && nm_utils_parse_inaddr_bin(AF_INET, s, NULL, &address_network)) { + if (s && nm_inet_parse_bin(AF_INET, s, NULL, &address_network)) { const NMPlatformIP4Route mms_route = { .network = address_network, .plen = 32, @@ -893,28 +1358,6 @@ out: } static void -context_property_changed(GDBusProxy *proxy, const char *property, GVariant *v, gpointer user_data) -{ - NMModemOfono *self = NM_MODEM_OFONO(user_data); - gs_unref_variant GVariant *v_dict = NULL; - - _LOGD("PropertyChanged: %s", property); - - if (g_strcmp0(property, "Settings") != 0) - return; - - v_dict = g_variant_get_child_value(v, 0); - if (!v_dict) { - _LOGW("ofono: (%s): error getting IPv4 Settings", nm_modem_get_uid(NM_MODEM(self))); - return; - } - - g_assert(g_variant_is_of_type(v_dict, G_VARIANT_TYPE_VARDICT)); - - handle_settings(v_dict, user_data); -} - -static void stage3_ip_config_start(NMModem *modem, int addr_family, NMModemIPMethod ip_method) { NMModemOfono *self = NM_MODEM_OFONO(modem); @@ -948,17 +1391,13 @@ out: static void context_properties_cb(GDBusProxy *proxy, GAsyncResult *result, gpointer user_data) { - NMModemOfono *self; - NMModemOfonoPrivate *priv; + NMModemOfono *self = user_data; gs_free_error GError *error = NULL; gs_unref_variant GVariant *properties = NULL; gs_unref_variant GVariant *settings = NULL; gs_unref_variant GVariant *v_dict = NULL; gboolean active; - self = NM_MODEM_OFONO(user_data); - priv = NM_MODEM_OFONO_GET_PRIVATE(self); - properties = g_dbus_proxy_call_finish(proxy, result, &error); if (!properties) { @@ -978,13 +1417,6 @@ context_properties_cb(GDBusProxy *proxy, GAsyncResult *result, gpointer user_dat goto error; } - /* Watch for custom ofono PropertyChanged signals */ - _nm_dbus_signal_connect(priv->context_proxy, - "PropertyChanged", - G_VARIANT_TYPE("(sv)"), - G_CALLBACK(context_property_changed), - self); - if (active) { _LOGD("ofono: connection is already Active"); @@ -994,9 +1426,9 @@ context_properties_cb(GDBusProxy *proxy, GAsyncResult *result, gpointer user_dat goto error; } - handle_settings(settings, user_data); + handle_settings(self, settings); } else { - g_dbus_proxy_call(priv->context_proxy, + g_dbus_proxy_call(proxy, "SetProperty", g_variant_new("(sv)", "Active", g_variant_new("b", TRUE)), G_DBUS_CALL_FLAGS_NONE, @@ -1012,36 +1444,15 @@ error: } static void -context_proxy_new_cb(GObject *source, GAsyncResult *result, gpointer user_data) +do_context_activate(NMModemOfono *self) { - NMModemOfono *self; - NMModemOfonoPrivate *priv; - gs_free_error GError *error = NULL; - GDBusProxy *proxy; - - proxy = g_dbus_proxy_new_for_bus_finish(result, &error); - if (!proxy || g_error_matches(error, G_IO_ERROR, G_IO_ERROR_CANCELLED)) - return; + NMModemOfonoPrivate *priv = NM_MODEM_OFONO_GET_PRIVATE(self); - self = NM_MODEM_OFONO(user_data); - priv = NM_MODEM_OFONO_GET_PRIVATE(self); + g_return_if_fail(NM_IS_MODEM_OFONO(self)); - if (!proxy) { - _LOGE("failed to create ofono ConnectionContext DBus proxy: %s", error->message); - g_clear_object(&priv->context_proxy_cancellable); - nm_modem_emit_prepare_result(NM_MODEM(self), FALSE, NM_DEVICE_STATE_REASON_MODEM_BUSY); - return; - } + nm_clear_g_cancellable(&priv->connect_cancellable); - priv->context_proxy = proxy; - - if (!priv->gprs_attached) { - g_clear_object(&priv->context_proxy_cancellable); - nm_modem_emit_prepare_result(NM_MODEM(self), - FALSE, - NM_DEVICE_STATE_REASON_MODEM_NO_CARRIER); - return; - } + priv->connect_cancellable = g_cancellable_new(); /* We have an old copy of the settings from a previous activation, * clear it so that we can gate getting the IP config from oFono @@ -1051,39 +1462,16 @@ context_proxy_new_cb(GObject *source, GAsyncResult *result, gpointer user_data) /* We need to directly query ConnectionContextinteface to get the current * property values */ - g_dbus_proxy_call(priv->context_proxy, + g_dbus_proxy_call(priv->current_octx->proxy, "GetProperties", NULL, G_DBUS_CALL_FLAGS_NONE, 20000, - NULL, + priv->connect_cancellable, (GAsyncReadyCallback) context_properties_cb, self); } -static void -do_context_activate(NMModemOfono *self) -{ - NMModemOfonoPrivate *priv = NM_MODEM_OFONO_GET_PRIVATE(self); - - g_return_if_fail(NM_IS_MODEM_OFONO(self)); - - nm_clear_g_cancellable(&priv->context_proxy_cancellable); - g_clear_object(&priv->context_proxy); - - priv->context_proxy_cancellable = g_cancellable_new(); - - g_dbus_proxy_new_for_bus(G_BUS_TYPE_SYSTEM, - G_DBUS_PROXY_FLAGS_DO_NOT_AUTO_START, - NULL, - OFONO_DBUS_SERVICE, - priv->context_path, - OFONO_DBUS_INTERFACE_CONNECTION_CONTEXT, - priv->context_proxy_cancellable, - context_proxy_new_cb, - self); -} - static GHashTable * create_connect_properties(NMConnection *connection) { @@ -1109,6 +1497,20 @@ create_connect_properties(NMConnection *connection) return properties; } +static gboolean +wait_for_signal_timeout(gpointer user_data) +{ + NMModemOfono *self = NM_MODEM_OFONO(user_data); + NMModemOfonoPrivate *priv = NM_MODEM_OFONO_GET_PRIVATE(self); + + nm_modem_emit_prepare_result(NM_MODEM(self), + FALSE, + NM_DEVICE_STATE_REASON_GSM_REGISTRATION_TIMEOUT); + + nm_clear_g_source_inst(&priv->deferred_connection_timeout_source); + return G_SOURCE_REMOVE; +} + static NMActStageReturn modem_act_stage1_prepare(NMModem *modem, NMConnection *connection, @@ -1116,20 +1518,10 @@ modem_act_stage1_prepare(NMModem *modem, { NMModemOfono *self = NM_MODEM_OFONO(modem); NMModemOfonoPrivate *priv = NM_MODEM_OFONO_GET_PRIVATE(self); - const char *context_id; - char **id = NULL; + const char *uuid = nm_connection_get_uuid(connection); + OfonoContextData *octx = g_hash_table_lookup(priv->contexts, uuid); - context_id = nm_connection_get_id(connection); - id = g_strsplit(context_id, "/", 0); - g_return_val_if_fail(id[2], NM_ACT_STAGE_RETURN_FAILURE); - - _LOGD("trying %s %s", id[1], id[2]); - - g_free(priv->context_path); - priv->context_path = g_strdup_printf("%s/%s", nm_modem_get_path(modem), id[2]); - g_strfreev(id); - - if (!priv->context_path) { + if (!octx) { NM_SET_OUT(out_failure_reason, NM_DEVICE_STATE_REASON_GSM_APN_FAILED); return NM_ACT_STAGE_RETURN_FAILURE; } @@ -1139,11 +1531,19 @@ modem_act_stage1_prepare(NMModem *modem, priv->connect_properties = create_connect_properties(connection); - _LOGI("activating context %s", priv->context_path); + _LOGI("activating context %s", g_dbus_proxy_get_object_path(octx->proxy)); + priv->current_octx = octx; update_modem_state(self); if (nm_modem_get_state(modem) == NM_MODEM_STATE_REGISTERED) { do_context_activate(self); + } else if (nm_modem_get_state(modem) == NM_MODEM_STATE_SEARCHING) { + _LOGI("activation deferred while modem is searching for signal."); + + nm_clear_g_source_inst(&priv->deferred_connection_timeout_source); + priv->deferred_connection_timeout_source = + nm_g_timeout_add_seconds_source(60 /* seconds */, wait_for_signal_timeout, self); + /* update_modem_state() will advance the next step. */ } else { _LOGW("could not activate context: modem is not registered."); NM_SET_OUT(out_failure_reason, NM_DEVICE_STATE_REASON_MODEM_NO_CARRIER); @@ -1176,11 +1576,11 @@ modem_proxy_new_cb(GObject *source, GAsyncResult *result, gpointer user_data) priv->modem_proxy = proxy; - _nm_dbus_signal_connect(priv->modem_proxy, - "PropertyChanged", - G_VARIANT_TYPE("(sv)"), - G_CALLBACK(modem_property_changed), - self); + _nm_dbus_proxy_signal_connect(priv->modem_proxy, + "PropertyChanged", + G_VARIANT_TYPE("(sv)"), + G_CALLBACK(modem_property_changed), + self); g_dbus_proxy_call(priv->modem_proxy, "GetProperties", @@ -1196,7 +1596,17 @@ modem_proxy_new_cb(GObject *source, GAsyncResult *result, gpointer user_data) static void nm_modem_ofono_init(NMModemOfono *self) -{} +{ + NMModemOfonoPrivate *priv = NM_MODEM_OFONO_GET_PRIVATE(self); + + priv->modem_proxy_cancellable = g_cancellable_new(); + priv->connections = g_hash_table_new_full(nm_str_hash, g_str_equal, g_free, g_object_unref); + priv->contexts = g_hash_table_new_full(nm_str_hash, + g_str_equal, + g_free, + (GDestroyNotify) ofono_context_data_free); + priv->settings = g_object_ref(NM_SETTINGS_GET); +} static void constructed(GObject *object) @@ -1204,8 +1614,6 @@ constructed(GObject *object) NMModemOfono *self = NM_MODEM_OFONO(object); NMModemOfonoPrivate *priv = NM_MODEM_OFONO_GET_PRIVATE(self); - priv->modem_proxy_cancellable = g_cancellable_new(); - g_dbus_proxy_new_for_bus(G_BUS_TYPE_SYSTEM, G_DBUS_PROXY_FLAGS_DO_NOT_AUTO_START, NULL, @@ -1257,7 +1665,7 @@ dispose(GObject *object) nm_clear_g_cancellable(&priv->modem_proxy_cancellable); nm_clear_g_cancellable(&priv->connman_proxy_cancellable); - nm_clear_g_cancellable(&priv->context_proxy_cancellable); + nm_clear_g_cancellable(&priv->connect_cancellable); nm_clear_g_cancellable(&priv->sim_proxy_cancellable); if (priv->connect_properties) { @@ -1265,6 +1673,16 @@ dispose(GObject *object) priv->connect_properties = NULL; } + if (priv->connections) { + g_hash_table_destroy(priv->connections); + priv->connections = NULL; + } + + if (priv->contexts) { + g_hash_table_destroy(priv->contexts); + priv->contexts = NULL; + } + nm_clear_l3cd(&priv->l3cd_4); if (priv->modem_proxy) { @@ -1277,19 +1695,21 @@ dispose(GObject *object) g_clear_object(&priv->connman_proxy); } - if (priv->context_proxy) { - g_signal_handlers_disconnect_by_data(priv->context_proxy, self); - g_clear_object(&priv->context_proxy); - } - if (priv->sim_proxy) { g_signal_handlers_disconnect_by_data(priv->sim_proxy, self); g_clear_object(&priv->sim_proxy); } + if (priv->settings) { + g_signal_handlers_disconnect_by_data(priv->settings, self); + g_clear_object(&priv->settings); + } + g_free(priv->imsi); priv->imsi = NULL; + nm_clear_g_source_inst(&priv->deferred_connection_timeout_source); + G_OBJECT_CLASS(nm_modem_ofono_parent_class)->dispose(object); } diff --git a/src/core/devices/wwan/nm-modem-ofono.h b/src/core/devices/wwan/nm-modem-ofono.h index ebe21023..02ba49ad 100644 --- a/src/core/devices/wwan/nm-modem-ofono.h +++ b/src/core/devices/wwan/nm-modem-ofono.h @@ -8,8 +8,9 @@ #include "nm-modem.h" -#define NM_TYPE_MODEM_OFONO (nm_modem_ofono_get_type()) -#define NM_MODEM_OFONO(obj) (G_TYPE_CHECK_INSTANCE_CAST((obj), NM_TYPE_MODEM_OFONO, NMModemOfono)) +#define NM_TYPE_MODEM_OFONO (nm_modem_ofono_get_type()) +#define NM_MODEM_OFONO(obj) \ + (_NM_G_TYPE_CHECK_INSTANCE_CAST((obj), NM_TYPE_MODEM_OFONO, NMModemOfono)) #define NM_IS_MODEM_OFONO(obj) (G_TYPE_CHECK_INSTANCE_TYPE((obj), NM_TYPE_MODEM_OFONO)) #define NM_MODEM_OFONO_CLASS(klass) \ (G_TYPE_CHECK_CLASS_CAST((klass), NM_TYPE_MODEM_OFONO, NMModemOfonoClass)) diff --git a/src/core/devices/wwan/nm-modem.c b/src/core/devices/wwan/nm-modem.c index a5ee8ce8..0159d351 100644 --- a/src/core/devices/wwan/nm-modem.c +++ b/src/core/devices/wwan/nm-modem.c @@ -353,6 +353,12 @@ nm_modem_set_mm_enabled(NMModem *self, gboolean enabled) NMModemPrivate *priv = NM_MODEM_GET_PRIVATE(self); NMModemState prev_state = priv->state; + /* Not all modem classes support set_mm_enabled */ + if (!NM_MODEM_GET_CLASS(self)->set_mm_enabled) { + _LOGD("cannot enable modem: not implemented"); + return; + } + if (enabled && priv->state >= NM_MODEM_STATE_ENABLING) { _LOGD("cannot enable modem: already enabled"); return; @@ -375,9 +381,7 @@ nm_modem_set_mm_enabled(NMModem *self, gboolean enabled) return; } - /* Not all modem classes support set_mm_enabled */ - if (NM_MODEM_GET_CLASS(self)->set_mm_enabled) - NM_MODEM_GET_CLASS(self)->set_mm_enabled(self, enabled); + NM_MODEM_GET_CLASS(self)->set_mm_enabled(self, enabled); /* Pre-empt the state change signal */ nm_modem_set_state(self, diff --git a/src/core/devices/wwan/nm-modem.h b/src/core/devices/wwan/nm-modem.h index ca541073..ec001102 100644 --- a/src/core/devices/wwan/nm-modem.h +++ b/src/core/devices/wwan/nm-modem.h @@ -11,7 +11,7 @@ #include "devices/nm-device.h" #define NM_TYPE_MODEM (nm_modem_get_type()) -#define NM_MODEM(obj) (G_TYPE_CHECK_INSTANCE_CAST((obj), NM_TYPE_MODEM, NMModem)) +#define NM_MODEM(obj) (_NM_G_TYPE_CHECK_INSTANCE_CAST((obj), NM_TYPE_MODEM, NMModem)) #define NM_MODEM_CLASS(klass) (G_TYPE_CHECK_CLASS_CAST((klass), NM_TYPE_MODEM, NMModemClass)) #define NM_IS_MODEM(obj) (G_TYPE_CHECK_INSTANCE_TYPE((obj), NM_TYPE_MODEM)) #define NM_IS_MODEM_CLASS(klass) (G_TYPE_CHECK_CLASS_TYPE((klass), NM_TYPE_MODEM)) diff --git a/src/core/devices/wwan/nm-wwan-factory.c b/src/core/devices/wwan/nm-wwan-factory.c index 169407c7..1c6d351f 100644 --- a/src/core/devices/wwan/nm-wwan-factory.c +++ b/src/core/devices/wwan/nm-wwan-factory.c @@ -18,7 +18,7 @@ #define NM_TYPE_WWAN_FACTORY (nm_wwan_factory_get_type()) #define NM_WWAN_FACTORY(obj) \ - (G_TYPE_CHECK_INSTANCE_CAST((obj), NM_TYPE_WWAN_FACTORY, NMWwanFactory)) + (_NM_G_TYPE_CHECK_INSTANCE_CAST((obj), NM_TYPE_WWAN_FACTORY, NMWwanFactory)) #define NM_WWAN_FACTORY_CLASS(klass) \ (G_TYPE_CHECK_CLASS_CAST((klass), NM_TYPE_WWAN_FACTORY, NMWwanFactoryClass)) #define NM_IS_WWAN_FACTORY(obj) (G_TYPE_CHECK_INSTANCE_TYPE((obj), NM_TYPE_WWAN_FACTORY)) |