From c521cffd7bb395e35befd3c9766fab8655cd27f1 Mon Sep 17 00:00:00 2001 From: Beniamino Galvani Date: Mon, 3 Jul 2017 18:45:04 +0200 Subject: [PATCH 1/9] device: ethernet: remove unused private member --- src/devices/nm-device-ethernet.c | 6 ------ 1 file changed, 6 deletions(-) diff --git a/src/devices/nm-device-ethernet.c b/src/devices/nm-device-ethernet.c index 8044ec3b85..83dc984dcc 100644 --- a/src/devices/nm-device-ethernet.c +++ b/src/devices/nm-device-ethernet.c @@ -108,7 +108,6 @@ typedef struct _NMDeviceEthernetPrivate { /* PPPoE */ NMPPPManager *ppp_manager; - NMIP4Config *pending_ip4_config; gint32 last_pppoe_time; guint pppoe_wait_id; @@ -1353,11 +1352,6 @@ deactivate (NMDevice *device) nm_clear_g_source (&priv->pppoe_wait_id); - if (priv->pending_ip4_config) { - g_object_unref (priv->pending_ip4_config); - priv->pending_ip4_config = NULL; - } - if (priv->ppp_manager) { nm_ppp_manager_stop_sync (priv->ppp_manager); g_clear_object (&priv->ppp_manager); From f83e56ec6dbe2b03a2ce19767ff992d2637d8de6 Mon Sep 17 00:00:00 2001 From: Beniamino Galvani Date: Fri, 30 Jun 2017 13:58:23 +0200 Subject: [PATCH 2/9] libnm,clients: add 'parent' property to PPPoE setting When the property is set, it specifies the device on which PPPoE is to be started. The ppp interface will be named as the connection.interface-name property. When the property is not set the previous behavior will be retained, i.e. the PPPoE connection will be started on connection.interface-name and the PPP interface will have a random name. --- clients/common/nm-meta-setting-desc.c | 6 +++ clients/common/settings-docs.c.in | 1 + libnm-core/nm-setting-pppoe.c | 55 +++++++++++++++++++++++++++ libnm-core/nm-setting-pppoe.h | 3 ++ libnm/libnm.ver | 1 + 5 files changed, 66 insertions(+) diff --git a/clients/common/nm-meta-setting-desc.c b/clients/common/nm-meta-setting-desc.c index 0928374eb2..9d68b23334 100644 --- a/clients/common/nm-meta-setting-desc.c +++ b/clients/common/nm-meta-setting-desc.c @@ -5789,6 +5789,12 @@ static const NMMetaPropertyInfo *const property_infos_OLPC_MESH[] = { #undef _CURRENT_NM_META_SETTING_TYPE #define _CURRENT_NM_META_SETTING_TYPE NM_META_SETTING_TYPE_PPPOE static const NMMetaPropertyInfo *const property_infos_PPPOE[] = { + PROPERTY_INFO_WITH_DESC (NM_SETTING_PPPOE_PARENT, + .is_cli_option = TRUE, + .property_alias = "parent", + .prompt = N_("PPPoE parent device"), + .property_type = &_pt_gobject_string, + ), PROPERTY_INFO_WITH_DESC (NM_SETTING_PPPOE_SERVICE, .is_cli_option = TRUE, .property_alias = "service", diff --git a/clients/common/settings-docs.c.in b/clients/common/settings-docs.c.in index a8afff5c0a..a4412270ac 100644 --- a/clients/common/settings-docs.c.in +++ b/clients/common/settings-docs.c.in @@ -280,6 +280,7 @@ #define DESCRIBE_DOC_NM_SETTING_PPP_REQUIRE_MPPE N_("If TRUE, MPPE (Microsoft Point-to-Point Encryption) will be required for the PPP session. If either 64-bit or 128-bit MPPE is not available the session will fail. Note that MPPE is not used on mobile broadband connections.") #define DESCRIBE_DOC_NM_SETTING_PPP_REQUIRE_MPPE_128 N_("If TRUE, 128-bit MPPE (Microsoft Point-to-Point Encryption) will be required for the PPP session, and the \"require-mppe\" property must also be set to TRUE. If 128-bit MPPE is not available the session will fail.") #define DESCRIBE_DOC_NM_SETTING_PPPOE_NAME N_("The setting's name, which uniquely identifies the setting within the connection. Each setting type has a name unique to that type, for example \"ppp\" or \"wireless\" or \"wired\".") +#define DESCRIBE_DOC_NM_SETTING_PPPOE_PARENT N_("If given, specifies the parent interface name on which this PPPoE connection should be created. If this property is not specified, the connection is activated on the interface specified in \"interface-name\" of NMSettingConnection.") #define DESCRIBE_DOC_NM_SETTING_PPPOE_PASSWORD N_("Password used to authenticate with the PPPoE service.") #define DESCRIBE_DOC_NM_SETTING_PPPOE_PASSWORD_FLAGS N_("Flags indicating how to handle the \"password\" property.") #define DESCRIBE_DOC_NM_SETTING_PPPOE_SERVICE N_("If specified, instruct PPPoE to only initiate sessions with access concentrators that provide the specified service. For most providers, this should be left blank. It is only required if there are multiple access concentrators or a specific service is known to be required.") diff --git a/libnm-core/nm-setting-pppoe.c b/libnm-core/nm-setting-pppoe.c index f72ee27385..3f9c2a9d6d 100644 --- a/libnm-core/nm-setting-pppoe.c +++ b/libnm-core/nm-setting-pppoe.c @@ -45,6 +45,7 @@ NM_SETTING_REGISTER_TYPE (NM_TYPE_SETTING_PPPOE) #define NM_SETTING_PPPOE_GET_PRIVATE(o) (G_TYPE_INSTANCE_GET_PRIVATE ((o), NM_TYPE_SETTING_PPPOE, NMSettingPppoePrivate)) typedef struct { + char *parent; char *service; char *username; char *password; @@ -53,6 +54,7 @@ typedef struct { enum { PROP_0, + PROP_PARENT, PROP_SERVICE, PROP_USERNAME, PROP_PASSWORD, @@ -74,6 +76,22 @@ nm_setting_pppoe_new (void) return (NMSetting *) g_object_new (NM_TYPE_SETTING_PPPOE, NULL); } +/** + * nm_setting_pppoe_get_parent: + * @setting: the #NMSettingPppoe + * + * Returns: the #NMSettingPppoe:parent property of the setting + * + * Since: 1.10 + **/ +const char * +nm_setting_pppoe_get_parent (NMSettingPppoe *setting) +{ + g_return_val_if_fail (NM_IS_SETTING_PPPOE (setting), NULL); + + return NM_SETTING_PPPOE_GET_PRIVATE (setting)->parent; +} + /** * nm_setting_pppoe_get_service: * @setting: the #NMSettingPppoe @@ -134,6 +152,7 @@ static gboolean verify (NMSetting *setting, NMConnection *connection, GError **error) { NMSettingPppoePrivate *priv = NM_SETTING_PPPOE_GET_PRIVATE (setting); + gs_free_error GError *local_error = NULL; if (!priv->username) { g_set_error_literal (error, @@ -160,6 +179,16 @@ verify (NMSetting *setting, NMConnection *connection, GError **error) return FALSE; } + if ( priv->parent + && !nm_utils_is_valid_iface_name (priv->parent, &local_error)) { + g_set_error (error, + NM_CONNECTION_ERROR, + NM_CONNECTION_ERROR_INVALID_PROPERTY, + "'%s': %s", priv->parent, local_error->message); + g_prefix_error (error, "%s.%s: ", NM_SETTING_PPPOE_SETTING_NAME, NM_SETTING_PPPOE_PARENT); + return FALSE; + } + return TRUE; } @@ -192,6 +221,10 @@ set_property (GObject *object, guint prop_id, NMSettingPppoePrivate *priv = NM_SETTING_PPPOE_GET_PRIVATE (object); switch (prop_id) { + case PROP_PARENT: + g_free (priv->parent); + priv->parent = g_value_dup_string (value); + break; case PROP_SERVICE: g_free (priv->service); priv->service = g_value_dup_string (value); @@ -220,6 +253,9 @@ get_property (GObject *object, guint prop_id, NMSettingPppoe *setting = NM_SETTING_PPPOE (object); switch (prop_id) { + case PROP_PARENT: + g_value_set_string (value, nm_setting_pppoe_get_parent (setting)); + break; case PROP_SERVICE: g_value_set_string (value, nm_setting_pppoe_get_service (setting)); break; @@ -266,6 +302,25 @@ nm_setting_pppoe_class_init (NMSettingPppoeClass *setting_class) parent_class->need_secrets = need_secrets; /* Properties */ + /** + * NMSettingPppoe:parent: + * + * If given, specifies the parent interface name on which this PPPoE + * connection should be created. If this property is not specified, + * the connection is activated on the interface specified in + * #NMSettingConnection:interface-name of #NMSettingConnection. + * + * Since: 1.10 + **/ + g_object_class_install_property + (object_class, PROP_PARENT, + g_param_spec_string (NM_SETTING_PPPOE_PARENT, "", "", + NULL, + G_PARAM_READWRITE | + G_PARAM_CONSTRUCT | + NM_SETTING_PARAM_INFERRABLE | + G_PARAM_STATIC_STRINGS)); + /** * NMSettingPppoe:service: * diff --git a/libnm-core/nm-setting-pppoe.h b/libnm-core/nm-setting-pppoe.h index b6717cde81..cab96e3b98 100644 --- a/libnm-core/nm-setting-pppoe.h +++ b/libnm-core/nm-setting-pppoe.h @@ -40,6 +40,7 @@ G_BEGIN_DECLS #define NM_SETTING_PPPOE_SETTING_NAME "pppoe" +#define NM_SETTING_PPPOE_PARENT "parent" #define NM_SETTING_PPPOE_SERVICE "service" #define NM_SETTING_PPPOE_USERNAME "username" #define NM_SETTING_PPPOE_PASSWORD "password" @@ -64,6 +65,8 @@ typedef struct { GType nm_setting_pppoe_get_type (void); NMSetting *nm_setting_pppoe_new (void); +NM_AVAILABLE_IN_1_10 +const char *nm_setting_pppoe_get_parent (NMSettingPppoe *setting); const char *nm_setting_pppoe_get_service (NMSettingPppoe *setting); const char *nm_setting_pppoe_get_username (NMSettingPppoe *setting); const char *nm_setting_pppoe_get_password (NMSettingPppoe *setting); diff --git a/libnm/libnm.ver b/libnm/libnm.ver index f1fb863d93..f22a0f1064 100644 --- a/libnm/libnm.ver +++ b/libnm/libnm.ver @@ -1182,6 +1182,7 @@ libnm_1_10_0 { global: nm_device_dummy_get_hw_address; nm_setting_bridge_get_group_forward_mask; + nm_setting_pppoe_get_parent; nm_setting_wireless_security_get_pmf; nm_setting_wireless_security_get_wps_method; nm_setting_wireless_security_pmf_get_type; From d5c2c3f6d7dff4d763d460052671d32f5389c815 Mon Sep 17 00:00:00 2001 From: Beniamino Galvani Date: Mon, 3 Jul 2017 10:10:34 +0200 Subject: [PATCH 3/9] platform: add nm_platform_link_set_name() We'll need it to rename the new PPP interface to a given name. --- src/platform/nm-linux-platform.c | 24 ++++++++++++++++++++++++ src/platform/nm-platform.c | 24 ++++++++++++++++++++++++ src/platform/nm-platform.h | 2 ++ 3 files changed, 50 insertions(+) diff --git a/src/platform/nm-linux-platform.c b/src/platform/nm-linux-platform.c index 42a77c5066..85d1591f1c 100644 --- a/src/platform/nm-linux-platform.c +++ b/src/platform/nm-linux-platform.c @@ -4463,6 +4463,29 @@ nla_put_failure: g_return_val_if_reached (NM_PLATFORM_ERROR_UNSPECIFIED); } +static NMPlatformError +link_set_name (NMPlatform *platform, int ifindex, const char *name) +{ + nm_auto_nlmsg struct nl_msg *nlmsg = NULL; + + _LOGD ("link: change %d: name: %s", ifindex, name); + + nlmsg = _nl_msg_new_link (RTM_NEWLINK, + 0, + ifindex, + NULL, + 0, + 0); + if (!nlmsg) + g_return_val_if_reached (NM_PLATFORM_ERROR_UNSPECIFIED); + + NLA_PUT (nlmsg, IFLA_IFNAME, strlen (name) + 1, name); + + return do_change_link (platform, ifindex, nlmsg) == NM_PLATFORM_ERROR_SUCCESS; +nla_put_failure: + g_return_val_if_reached (FALSE); +} + static gboolean link_get_permanent_address (NMPlatform *platform, int ifindex, @@ -6461,6 +6484,7 @@ nm_linux_platform_class_init (NMLinuxPlatformClass *klass) platform_class->link_set_address = link_set_address; platform_class->link_get_permanent_address = link_get_permanent_address; platform_class->link_set_mtu = link_set_mtu; + platform_class->link_set_name = link_set_name; platform_class->link_set_sriov_num_vfs = link_set_sriov_num_vfs; platform_class->link_get_physical_port_id = link_get_physical_port_id; diff --git a/src/platform/nm-platform.c b/src/platform/nm-platform.c index 03dc6943b6..e7935d49fb 100644 --- a/src/platform/nm-platform.c +++ b/src/platform/nm-platform.c @@ -1461,6 +1461,30 @@ nm_platform_link_get_mtu (NMPlatform *self, int ifindex) return pllink ? pllink->mtu : 0; } +/** + * nm_platform_link_set_name: + * @self: platform instance + * @ifindex: Interface index + * @name: The new interface name + * + * Set interface name. + */ +gboolean +nm_platform_link_set_name (NMPlatform *self, int ifindex, const char *name) +{ + _CHECK_SELF (self, klass, FALSE); + + g_return_val_if_fail (ifindex >= 0, FALSE); + g_return_val_if_fail (name, FALSE); + + _LOGD ("link: setting '%s' (%d) name %s", nm_platform_link_get_name (self, ifindex), ifindex, name); + + if (strlen (name) + 1 > IFNAMSIZ) + return FALSE; + + return klass->link_set_name (self, ifindex, name); +} + /** * nm_platform_link_get_physical_port_id: * @self: platform instance diff --git a/src/platform/nm-platform.h b/src/platform/nm-platform.h index a40d33f43d..8e922b95e0 100644 --- a/src/platform/nm-platform.h +++ b/src/platform/nm-platform.h @@ -682,6 +682,7 @@ typedef struct { size_t *length); NMPlatformError (*link_set_address) (NMPlatform *, int ifindex, gconstpointer address, size_t length); gboolean (*link_set_mtu) (NMPlatform *, int ifindex, guint32 mtu); + gboolean (*link_set_name) (NMPlatform *, int ifindex, const char *name); gboolean (*link_set_sriov_num_vfs) (NMPlatform *, int ifindex, guint num_vfs); char * (*link_get_physical_port_id) (NMPlatform *, int ifindex); @@ -946,6 +947,7 @@ gboolean nm_platform_link_set_ipv6_token (NMPlatform *self, int ifindex, NMUtils gboolean nm_platform_link_get_permanent_address (NMPlatform *self, int ifindex, guint8 *buf, size_t *length); NMPlatformError nm_platform_link_set_address (NMPlatform *self, int ifindex, const void *address, size_t length); gboolean nm_platform_link_set_mtu (NMPlatform *self, int ifindex, guint32 mtu); +gboolean nm_platform_link_set_name (NMPlatform *self, int ifindex, const char *name); gboolean nm_platform_link_set_sriov_num_vfs (NMPlatform *self, int ifindex, guint num_vfs); char *nm_platform_link_get_physical_port_id (NMPlatform *self, int ifindex); From df72cad107fd4e721488195109e29fae5f9b8e20 Mon Sep 17 00:00:00 2001 From: Beniamino Galvani Date: Tue, 6 Jun 2017 15:55:08 +0200 Subject: [PATCH 4/9] device: add NMDevicePPP The new device type represents a PPP interface, and will implement the activation of new-style PPPoE connections, i.e. the ones that don't claim the parent device. --- Makefile.am | 8 ++ ....freedesktop.NetworkManager.Device.Ppp.xml | 20 ++++ libnm-core/nm-dbus-interface.h | 3 + libnm/libnm.ver | 1 + libnm/nm-client.c | 3 + libnm/nm-device-ppp.c | 39 +++++++ libnm/nm-device-ppp.h | 36 ++++++ libnm/nm-device.c | 3 + libnm/nm-types.h | 1 + src/devices/nm-device-factory.c | 1 + src/devices/nm-device-ppp.c | 103 ++++++++++++++++++ src/devices/nm-device-ppp.h | 30 +++++ src/devices/nm-device.c | 2 + src/nm-types.h | 5 +- src/platform/nm-linux-platform.c | 5 +- 15 files changed, 257 insertions(+), 3 deletions(-) create mode 100644 introspection/org.freedesktop.NetworkManager.Device.Ppp.xml create mode 100644 libnm/nm-device-ppp.c create mode 100644 libnm/nm-device-ppp.h create mode 100644 src/devices/nm-device-ppp.c create mode 100644 src/devices/nm-device-ppp.h diff --git a/Makefile.am b/Makefile.am index ed9417a4d6..4e66a5e68b 100644 --- a/Makefile.am +++ b/Makefile.am @@ -206,6 +206,8 @@ introspection_sources = \ introspection/org.freedesktop.NetworkManager.Device.Modem.h \ introspection/org.freedesktop.NetworkManager.Device.OlpcMesh.c \ introspection/org.freedesktop.NetworkManager.Device.OlpcMesh.h \ + introspection/org.freedesktop.NetworkManager.Device.Ppp.c \ + introspection/org.freedesktop.NetworkManager.Device.Ppp.h \ introspection/org.freedesktop.NetworkManager.Device.Statistics.c \ introspection/org.freedesktop.NetworkManager.Device.Statistics.h \ introspection/org.freedesktop.NetworkManager.Device.Team.c \ @@ -279,6 +281,7 @@ DBUS_INTERFACE_DOCS = \ docs/api/dbus-org.freedesktop.NetworkManager.Device.Tun.xml \ docs/api/dbus-org.freedesktop.NetworkManager.Device.Bridge.xml \ docs/api/dbus-org.freedesktop.NetworkManager.Device.OlpcMesh.xml \ + docs/api/dbus-org.freedesktop.NetworkManager.Device.Ppp.xml \ docs/api/dbus-org.freedesktop.NetworkManager.DHCP4Config.xml \ docs/api/dbus-org.freedesktop.NetworkManager.Device.Generic.xml \ docs/api/dbus-org.freedesktop.NetworkManager.Device.Infiniband.xml \ @@ -326,6 +329,7 @@ dbusinterfaces_DATA = \ introspection/org.freedesktop.NetworkManager.Device.Macvlan.xml \ introspection/org.freedesktop.NetworkManager.Device.Modem.xml \ introspection/org.freedesktop.NetworkManager.Device.OlpcMesh.xml \ + introspection/org.freedesktop.NetworkManager.Device.Ppp.xml \ introspection/org.freedesktop.NetworkManager.Device.Statistics.xml \ introspection/org.freedesktop.NetworkManager.Device.Team.xml \ introspection/org.freedesktop.NetworkManager.Device.Tun.xml \ @@ -721,6 +725,7 @@ libnm_lib_h_pub_real = \ libnm/nm-device-macvlan.h \ libnm/nm-device-modem.h \ libnm/nm-device-olpc-mesh.h \ + libnm/nm-device-ppp.h \ libnm/nm-device-team.h \ libnm/nm-device-tun.h \ libnm/nm-device-vlan.h \ @@ -773,6 +778,7 @@ libnm_lib_c_real = \ libnm/nm-device-macvlan.c \ libnm/nm-device-modem.c \ libnm/nm-device-olpc-mesh.c \ + libnm/nm-device-ppp.c \ libnm/nm-device-team.c \ libnm/nm-device-tun.c \ libnm/nm-device-vlan.c \ @@ -1388,6 +1394,8 @@ src_libNetworkManager_la_SOURCES = \ src/devices/nm-device-macsec.h \ src/devices/nm-device-macvlan.c \ src/devices/nm-device-macvlan.h \ + src/devices/nm-device-ppp.c \ + src/devices/nm-device-ppp.h \ src/devices/nm-device-tun.c \ src/devices/nm-device-tun.h \ src/devices/nm-device-veth.c \ diff --git a/introspection/org.freedesktop.NetworkManager.Device.Ppp.xml b/introspection/org.freedesktop.NetworkManager.Device.Ppp.xml new file mode 100644 index 0000000000..00605f7219 --- /dev/null +++ b/introspection/org.freedesktop.NetworkManager.Device.Ppp.xml @@ -0,0 +1,20 @@ + + + + + + + + + + + diff --git a/libnm-core/nm-dbus-interface.h b/libnm-core/nm-dbus-interface.h index dd05f5e756..b089365ccc 100644 --- a/libnm-core/nm-dbus-interface.h +++ b/libnm-core/nm-dbus-interface.h @@ -68,6 +68,7 @@ #define NM_DBUS_INTERFACE_DEVICE_TUN NM_DBUS_INTERFACE_DEVICE ".Tun" #define NM_DBUS_INTERFACE_DEVICE_MACSEC NM_DBUS_INTERFACE_DEVICE ".Macsec" #define NM_DBUS_INTERFACE_DEVICE_MACVLAN NM_DBUS_INTERFACE_DEVICE ".Macvlan" +#define NM_DBUS_INTERFACE_DEVICE_PPP NM_DBUS_INTERFACE_DEVICE ".Ppp" #define NM_DBUS_INTERFACE_DEVICE_VXLAN NM_DBUS_INTERFACE_DEVICE ".Vxlan" #define NM_DBUS_INTERFACE_DEVICE_GRE NM_DBUS_INTERFACE_DEVICE ".Gre" #define NM_DBUS_INTERFACE_DEVICE_IP_TUNNEL NM_DBUS_INTERFACE_DEVICE ".IPTunnel" @@ -203,6 +204,7 @@ typedef enum { * @NM_DEVICE_TYPE_VETH: a VETH interface * @NM_DEVICE_TYPE_MACSEC: a MACsec interface * @NM_DEVICE_TYPE_DUMMY: a dummy interface + * @NM_DEVICE_TYPE_PPP: a PPP interface * * #NMDeviceType values indicate the type of hardware represented by a * device object. @@ -231,6 +233,7 @@ typedef enum { NM_DEVICE_TYPE_VETH = 20, NM_DEVICE_TYPE_MACSEC = 21, NM_DEVICE_TYPE_DUMMY = 22, + NM_DEVICE_TYPE_PPP = 23, } NMDeviceType; /** diff --git a/libnm/libnm.ver b/libnm/libnm.ver index f22a0f1064..85ec20c929 100644 --- a/libnm/libnm.ver +++ b/libnm/libnm.ver @@ -1181,6 +1181,7 @@ global: libnm_1_10_0 { global: nm_device_dummy_get_hw_address; + nm_device_ppp_get_type; nm_setting_bridge_get_group_forward_mask; nm_setting_pppoe_get_parent; nm_setting_wireless_security_get_pmf; diff --git a/libnm/nm-client.c b/libnm/nm-client.c index 38b69100f9..c8ce2d6eca 100644 --- a/libnm/nm-client.c +++ b/libnm/nm-client.c @@ -63,6 +63,7 @@ #include "nm-device-macvlan.h" #include "nm-device-modem.h" #include "nm-device-olpc-mesh.h" +#include "nm-device-ppp.h" #include "nm-device-team.h" #include "nm-device-tun.h" #include "nm-device-vlan.h" @@ -2078,6 +2079,8 @@ obj_nm_for_gdbus_object (NMClient *self, GDBusObject *object, GDBusObjectManager type = NM_TYPE_DEVICE_MODEM; else if (strcmp (ifname, NM_DBUS_INTERFACE_DEVICE_OLPC_MESH) == 0) type = NM_TYPE_DEVICE_OLPC_MESH; + else if (strcmp (ifname, NM_DBUS_INTERFACE_DEVICE_PPP) == 0) + type = NM_TYPE_DEVICE_PPP; else if (strcmp (ifname, NM_DBUS_INTERFACE_DEVICE_TEAM) == 0) type = NM_TYPE_DEVICE_TEAM; else if (strcmp (ifname, NM_DBUS_INTERFACE_DEVICE_TUN) == 0) diff --git a/libnm/nm-device-ppp.c b/libnm/nm-device-ppp.c new file mode 100644 index 0000000000..805d142820 --- /dev/null +++ b/libnm/nm-device-ppp.c @@ -0,0 +1,39 @@ +/* -*- Mode: C; tab-width: 4; indent-tabs-mode: t; c-basic-offset: 4 -*- */ +/* + * This library is free software; you can redistribute it and/or + * modify it under the terms of the GNU Lesser General Public + * License as published by the Free Software Foundation; either + * version 2 of the License, or (at your option) any later version. + * + * You should have received a copy of the GNU Lesser General Public + * License along with this program. If not, see . + * + * Copyright 2017 Red Hat, Inc. + */ + +#include "nm-default.h" + +#include "nm-device-ppp.h" +#include "nm-device.h" + +struct _NMDevicePpp { + NMDevice parent; +}; + +struct _NMDevicePppClass { + NMDeviceClass parent; +}; + +G_DEFINE_TYPE (NMDevicePpp, nm_device_ppp, NM_TYPE_DEVICE) + +#define NM_DEVICE_PPP_GET_PRIVATE(o) (G_TYPE_INSTANCE_GET_PRIVATE ((o), NM_TYPE_DEVICE_PPP, NMDevicePppPrivate)) + +static void +nm_device_ppp_init (NMDevicePpp *device) +{ +} + +static void +nm_device_ppp_class_init (NMDevicePppClass *klass) +{ +} diff --git a/libnm/nm-device-ppp.h b/libnm/nm-device-ppp.h new file mode 100644 index 0000000000..58ff5e1882 --- /dev/null +++ b/libnm/nm-device-ppp.h @@ -0,0 +1,36 @@ +/* -*- Mode: C; tab-width: 4; indent-tabs-mode: t; c-basic-offset: 4 -*- */ +/* + * This library is free software; you can redistribute it and/or + * modify it under the terms of the GNU Lesser General Public + * License as published by the Free Software Foundation; either + * version 2 of the License, or (at your option) any later version. + * + * You should have received a copy of the GNU Lesser General Public + * License along with this program. If not, see . + * + * Copyright 2017 Red Hat, Inc. + */ + +#ifndef __NM_DEVICE_PPP_H__ +#define __NM_DEVICE_PPP_H__ + +#if !defined (__NETWORKMANAGER_H_INSIDE__) && !defined (NETWORKMANAGER_COMPILATION) +#error "Only can be included directly." +#endif + +G_BEGIN_DECLS + +#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_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)) +#define NM_IS_DEVICE_PPP_CLASS(klass) (G_TYPE_CHECK_CLASS_TYPE ((klass), NM_TYPE_DEVICE_PPP)) +#define NM_DEVICE_PPP_GET_CLASS(obj) (G_TYPE_INSTANCE_GET_CLASS ((obj), NM_TYPE_DEVICE_PPP, NMDevicePppClass)) + +typedef struct _NMDevicePppClass NMDevicePppClass; + +GType nm_device_ppp_get_type (void); + +G_END_DECLS + +#endif /* __NM_DEVICE_PPP_H__ */ diff --git a/libnm/nm-device.c b/libnm/nm-device.c index 8c31e6cfa0..7f15436638 100644 --- a/libnm/nm-device.c +++ b/libnm/nm-device.c @@ -280,6 +280,7 @@ coerce_type (NMDeviceType type) case NM_DEVICE_TYPE_UNUSED2: case NM_DEVICE_TYPE_UNKNOWN: case NM_DEVICE_TYPE_DUMMY: + case NM_DEVICE_TYPE_PPP: return type; } return NM_DEVICE_TYPE_UNKNOWN; @@ -1551,6 +1552,8 @@ get_type_name (NMDevice *device) return _("MACsec"); case NM_DEVICE_TYPE_DUMMY: return _("Dummy"); + case NM_DEVICE_TYPE_PPP: + return _("PPP"); case NM_DEVICE_TYPE_GENERIC: case NM_DEVICE_TYPE_UNUSED1: case NM_DEVICE_TYPE_UNUSED2: diff --git a/libnm/nm-types.h b/libnm/nm-types.h index 84cf48f4c5..1e06d15feb 100644 --- a/libnm/nm-types.h +++ b/libnm/nm-types.h @@ -43,6 +43,7 @@ typedef struct _NMDeviceMacsec NMDeviceMacsec; typedef struct _NMDeviceMacvlan NMDeviceMacvlan; typedef struct _NMDeviceModem NMDeviceModem; typedef struct _NMDeviceOlpcMesh NMDeviceOlpcMesh; +typedef struct _NMDevicePpp NMDevicePpp; typedef struct _NMDeviceTeam NMDeviceTeam; typedef struct _NMDeviceTun NMDeviceTun; typedef struct _NMDeviceVlan NMDeviceVlan; diff --git a/src/devices/nm-device-factory.c b/src/devices/nm-device-factory.c index d0ad791acb..b163bc3d22 100644 --- a/src/devices/nm-device-factory.c +++ b/src/devices/nm-device-factory.c @@ -362,6 +362,7 @@ nm_device_factory_manager_load_factories (NMDeviceFactoryManagerFactoryFunc call _ADD_INTERNAL (nm_ip_tunnel_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); _ADD_INTERNAL (nm_tun_device_factory_get_type); _ADD_INTERNAL (nm_veth_device_factory_get_type); _ADD_INTERNAL (nm_vlan_device_factory_get_type); diff --git a/src/devices/nm-device-ppp.c b/src/devices/nm-device-ppp.c new file mode 100644 index 0000000000..d0f2c9526e --- /dev/null +++ b/src/devices/nm-device-ppp.c @@ -0,0 +1,103 @@ +/* -*- Mode: C; tab-width: 4; indent-tabs-mode: t; c-basic-offset: 4 -*- */ +/* NetworkManager -- Network link manager + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation; either version 2 of the License, or + * (at your option) any later version. + * + * You should have received a copy of the GNU General Public License + * along with this program. If not, see . + * + * Copyright (C) 2017 Red Hat, Inc. + */ + +#include "nm-default.h" + +#include "nm-device-ppp.h" + +#include "nm-device-factory.h" +#include "nm-device-private.h" +#include "platform/nm-platform.h" + +#include "introspection/org.freedesktop.NetworkManager.Device.Ppp.h" + +#include "nm-device-logging.h" +_LOG_DECLARE_SELF(NMDevicePpp); + +/*****************************************************************************/ + +typedef struct _NMDevicePppPrivate { + int dummy; +} NMDevicePppPrivate; + +struct _NMDevicePpp { + NMDevice parent; + NMDevicePppPrivate _priv; +}; + +struct _NMDevicePppClass { + NMDeviceClass parent; +}; + +G_DEFINE_TYPE (NMDevicePpp, nm_device_ppp, NM_TYPE_DEVICE) + +#define NM_DEVICE_PPP_GET_PRIVATE(self) _NM_GET_PRIVATE (self, NMDevicePpp, NM_IS_DEVICE_PPP) + +static NMDeviceCapabilities +get_generic_capabilities (NMDevice *device) +{ + return NM_DEVICE_CAP_IS_SOFTWARE; +} + +static void +nm_device_ppp_init (NMDevicePpp *self) +{ +} + +static void +dispose (GObject *object) +{ + G_OBJECT_CLASS (nm_device_ppp_parent_class)->dispose (object); +} + +static void +nm_device_ppp_class_init (NMDevicePppClass *klass) +{ + GObjectClass *object_class = G_OBJECT_CLASS (klass); + NMDeviceClass *parent_class = NM_DEVICE_CLASS (klass); + + NM_DEVICE_CLASS_DECLARE_TYPES (klass, NULL, NM_LINK_TYPE_PPP) + + object_class->dispose = dispose; + parent_class->get_generic_capabilities = get_generic_capabilities; + + nm_exported_object_class_add_interface (NM_EXPORTED_OBJECT_CLASS (klass), + NMDBUS_TYPE_DEVICE_PPP_SKELETON, + NULL); +} + +/*****************************************************************************/ + +#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)) + +static NMDevice * +create_device (NMDeviceFactory *factory, + const char *iface, + const NMPlatformLink *plink, + NMConnection *connection, + gboolean *out_ignore) +{ + return (NMDevice *) g_object_new (NM_TYPE_DEVICE_PPP, + NM_DEVICE_IFACE, iface, + NM_DEVICE_TYPE_DESC, "Ppp", + NM_DEVICE_DEVICE_TYPE, NM_DEVICE_TYPE_PPP, + NM_DEVICE_LINK_TYPE, NM_LINK_TYPE_PPP, + NULL); +} + +NM_DEVICE_FACTORY_DEFINE_INTERNAL (PPP, Ppp, ppp, + NM_DEVICE_FACTORY_DECLARE_LINK_TYPES (NM_LINK_TYPE_PPP), + factory_class->create_device = create_device; +); diff --git a/src/devices/nm-device-ppp.h b/src/devices/nm-device-ppp.h new file mode 100644 index 0000000000..aaa18b9b12 --- /dev/null +++ b/src/devices/nm-device-ppp.h @@ -0,0 +1,30 @@ +/* -*- Mode: C; tab-width: 4; indent-tabs-mode: t; c-basic-offset: 4 -*- */ +/* NetworkManager -- Network link manager + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation; either version 2 of the License, or + * (at your option) any later version. + * + * You should have received a copy of the GNU General Public License + * along with this program. If not, see . + * + * Copyright (C) 2017 Red Hat, Inc. + */ + +#ifndef __NETWORKMANAGER_DEVICE_PPP_H__ +#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_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)) +#define NM_IS_DEVICE_PPP_CLASS(klass) (G_TYPE_CHECK_CLASS_TYPE ((klass), NM_TYPE_DEVICE_PPP)) +#define NM_DEVICE_PPP_GET_CLASS(obj) (G_TYPE_INSTANCE_GET_CLASS ((obj), NM_TYPE_DEVICE_PPP, NMDevicePppClass)) + +typedef struct _NMDevicePpp NMDevicePpp; +typedef struct _NMDevicePppClass NMDevicePppClass; + +GType nm_device_ppp_get_type (void); + +#endif /* __NETWORKMANAGER_DEVICE_PPP_H__ */ diff --git a/src/devices/nm-device.c b/src/devices/nm-device.c index 259f776e54..1530b60716 100644 --- a/src/devices/nm-device.c +++ b/src/devices/nm-device.c @@ -1555,6 +1555,8 @@ nm_device_get_priority (NMDevice *self) return 425; case NM_DEVICE_TYPE_TUN: return 450; + case NM_DEVICE_TYPE_PPP: + return 460; case NM_DEVICE_TYPE_VXLAN: return 500; case NM_DEVICE_TYPE_DUMMY: diff --git a/src/nm-types.h b/src/nm-types.h index 2cc5769467..136cc450a8 100644 --- a/src/nm-types.h +++ b/src/nm-types.h @@ -142,7 +142,8 @@ typedef enum { NM_LINK_TYPE_WIMAX, /* Software types */ - NM_LINK_TYPE_DUMMY = 0x10000, + NM_LINK_TYPE_BNEP = 0x10000, /* Bluetooth Ethernet emulation */ + NM_LINK_TYPE_DUMMY, NM_LINK_TYPE_GRE, NM_LINK_TYPE_GRETAP, NM_LINK_TYPE_IFB, @@ -153,13 +154,13 @@ typedef enum { NM_LINK_TYPE_MACVLAN, NM_LINK_TYPE_MACVTAP, NM_LINK_TYPE_OPENVSWITCH, + NM_LINK_TYPE_PPP, NM_LINK_TYPE_SIT, NM_LINK_TYPE_TAP, NM_LINK_TYPE_TUN, NM_LINK_TYPE_VETH, NM_LINK_TYPE_VLAN, NM_LINK_TYPE_VXLAN, - NM_LINK_TYPE_BNEP, /* Bluetooth Ethernet emulation */ /* Software types with slaves */ NM_LINK_TYPE_BRIDGE = 0x10000 | 0x20000, diff --git a/src/platform/nm-linux-platform.c b/src/platform/nm-linux-platform.c index 85d1591f1c..cd45a2bf39 100644 --- a/src/platform/nm-linux-platform.c +++ b/src/platform/nm-linux-platform.c @@ -380,6 +380,7 @@ static const LinkDesc linktypes[] = { { NM_LINK_TYPE_WWAN_NET, "wwan", NULL, "wwan" }, { NM_LINK_TYPE_WIMAX, "wimax", "wimax", "wimax" }, + { NM_LINK_TYPE_BNEP, "bluetooth", NULL, "bluetooth" }, { NM_LINK_TYPE_DUMMY, "dummy", "dummy", NULL }, { NM_LINK_TYPE_GRE, "gre", "gre", NULL }, { NM_LINK_TYPE_GRETAP, "gretap", "gretap", NULL }, @@ -391,13 +392,13 @@ static const LinkDesc linktypes[] = { { NM_LINK_TYPE_MACVLAN, "macvlan", "macvlan", NULL }, { NM_LINK_TYPE_MACVTAP, "macvtap", "macvtap", NULL }, { NM_LINK_TYPE_OPENVSWITCH, "openvswitch", "openvswitch", NULL }, + { NM_LINK_TYPE_PPP, "ppp", NULL, "ppp" }, { NM_LINK_TYPE_SIT, "sit", "sit", NULL }, { NM_LINK_TYPE_TAP, "tap", NULL, NULL }, { NM_LINK_TYPE_TUN, "tun", NULL, NULL }, { NM_LINK_TYPE_VETH, "veth", "veth", NULL }, { NM_LINK_TYPE_VLAN, "vlan", "vlan", "vlan" }, { NM_LINK_TYPE_VXLAN, "vxlan", "vxlan", "vxlan" }, - { NM_LINK_TYPE_BNEP, "bluetooth", NULL, "bluetooth" }, { NM_LINK_TYPE_BRIDGE, "bridge", "bridge", "bridge" }, { NM_LINK_TYPE_BOND, "bond", "bond", "bond" }, @@ -696,6 +697,8 @@ _linktype_get_type (NMPlatform *platform, return NM_LINK_TYPE_SIT; else if (arptype == ARPHRD_TUNNEL6) return NM_LINK_TYPE_IP6TNL; + else if (arptype == ARPHRD_PPP) + return NM_LINK_TYPE_PPP; { NMPUtilsEthtoolDriverInfo driver_info; From 8665cdfefff50bb575eb03893d6361930bc8ad40 Mon Sep 17 00:00:00 2001 From: Beniamino Galvani Date: Fri, 30 Jun 2017 16:33:07 +0200 Subject: [PATCH 5/9] core: device-factory: implement match_connection() Make it possible to register different factories for the same setting type, and add a match_connection() method to let each factory decide if it's capable of handling a connection. This will be used to decide whether a PPPoE connection must be handled through the legacy Ethernet factory or through the new PPP factory. --- src/devices/bluetooth/nm-bluez-manager.c | 17 +++++++ src/devices/nm-device-bridge.c | 18 +++++++- src/devices/nm-device-factory.c | 58 +++++++++++++----------- src/devices/nm-device-factory.h | 8 ++++ 4 files changed, 74 insertions(+), 27 deletions(-) diff --git a/src/devices/bluetooth/nm-bluez-manager.c b/src/devices/bluetooth/nm-bluez-manager.c index 33bea4e27c..74bf027c72 100644 --- a/src/devices/bluetooth/nm-bluez-manager.c +++ b/src/devices/bluetooth/nm-bluez-manager.c @@ -26,6 +26,7 @@ #include #include "devices/nm-device-factory.h" +#include "devices/nm-device-bridge.h" #include "nm-setting-bluetooth.h" #include "settings/nm-settings.h" #include "nm-bluez4-manager.h" @@ -417,6 +418,21 @@ create_device (NMDeviceFactory *factory, return NULL; } +static gboolean +match_connection (NMDeviceFactory *factory, + NMConnection *connection) +{ + const char *type = nm_connection_get_connection_type (connection); + + nm_assert (nm_streq (type, NM_SETTING_BLUETOOTH_SETTING_NAME)); + + if ( nm_bt_vtable_network_server + && _nm_connection_get_setting_bluetooth_for_nap (connection)) + return FALSE; /* handled by the bridge factory */ + + return TRUE; +} + /*****************************************************************************/ static void @@ -461,5 +477,6 @@ nm_bluez_manager_class_init (NMBluezManagerClass *klass) factory_class->get_supported_types = get_supported_types; factory_class->create_device = create_device; + factory_class->match_connection = match_connection; factory_class->start = start; } diff --git a/src/devices/nm-device-bridge.c b/src/devices/nm-device-bridge.c index e3ba81a57d..ef5550cd6a 100644 --- a/src/devices/nm-device-bridge.c +++ b/src/devices/nm-device-bridge.c @@ -538,8 +538,24 @@ create_device (NMDeviceFactory *factory, NULL); } +static gboolean +match_connection (NMDeviceFactory *factory, + NMConnection *connection) +{ + const char *type = nm_connection_get_connection_type (connection); + + if (nm_streq (type, NM_SETTING_BRIDGE_SETTING_NAME)) + return TRUE; + + nm_assert (nm_streq (type, NM_SETTING_BLUETOOTH_SETTING_NAME)); + + return nm_bt_vtable_network_server + && _nm_connection_get_setting_bluetooth_for_nap (connection); +} + NM_DEVICE_FACTORY_DEFINE_INTERNAL (BRIDGE, Bridge, bridge, NM_DEVICE_FACTORY_DECLARE_LINK_TYPES (NM_LINK_TYPE_BRIDGE) - NM_DEVICE_FACTORY_DECLARE_SETTING_TYPES (NM_SETTING_BRIDGE_SETTING_NAME), + NM_DEVICE_FACTORY_DECLARE_SETTING_TYPES (NM_SETTING_BRIDGE_SETTING_NAME, NM_SETTING_BLUETOOTH_SETTING_NAME), factory_class->create_device = create_device; + factory_class->match_connection = match_connection; ); diff --git a/src/devices/nm-device-factory.c b/src/devices/nm-device-factory.c index b163bc3d22..4e0d7939d4 100644 --- a/src/devices/nm-device-factory.c +++ b/src/devices/nm-device-factory.c @@ -235,34 +235,24 @@ nm_device_factory_manager_find_factory_for_link_type (NMLinkType link_type) NMDeviceFactory * nm_device_factory_manager_find_factory_for_connection (NMConnection *connection) { + NMDeviceFactoryClass *klass; + NMDeviceFactory *factory; const char *type; + GSList *list; g_return_val_if_fail (factories_by_setting, NULL); type = nm_connection_get_connection_type (connection); + list = g_hash_table_lookup (factories_by_setting, type); - if ( nm_streq (type, NM_SETTING_BLUETOOTH_SETTING_NAME) - && _nm_connection_get_setting_bluetooth_for_nap (connection)) { - /* for Bluetooth NAP connections, we return the bridge factory - * instead of the bluetooth factory. - * - * In a way, this is a hack. The more orthodox solution would - * be that device factories don't only announce supported setting - * types, but instead match on a full fledged NMConnection. - * - * However, our device-factories are known at compile time. - * There is no need to keep this generic. We *know* which - * factory to choose. Making this generic would not make it - * cleaner. */ - if (!g_hash_table_lookup (factories_by_setting, type)) { - /* we need both the bluetooth and the bridge factory - * to make this work. */ - return NULL; - } - type = NM_SETTING_BRIDGE_SETTING_NAME; + for (; list; list = g_slist_next (list)) { + factory = list->data; + klass = NM_DEVICE_FACTORY_GET_CLASS (factory); + if (!klass->match_connection || klass->match_connection (factory, connection)) + return factory; } - return g_hash_table_lookup (factories_by_setting, type); + return NULL; } void @@ -283,9 +273,11 @@ nm_device_factory_manager_for_each_factory (NMDeviceFactoryManagerFactoryFunc ca if (factories_by_setting) { g_hash_table_iter_init (&iter, factories_by_setting); - while (g_hash_table_iter_next (&iter, NULL, (gpointer) &factory)) { - if (!g_slist_find (list, factory)) - list = g_slist_prepend (list, factory); + while (g_hash_table_iter_next (&iter, NULL, (gpointer) &list_iter)) { + for (; list_iter; list_iter = g_slist_next (list_iter)) { + if (!g_slist_find (list, list_iter->data)) + list = g_slist_prepend (list, list_iter->data); + } } } @@ -303,6 +295,7 @@ _add_factory (NMDeviceFactory *factory, { const NMLinkType *link_types = NULL; const char *const*setting_types = NULL; + GSList *list; int i; g_return_val_if_fail (factories_by_link, FALSE); @@ -313,8 +306,15 @@ _add_factory (NMDeviceFactory *factory, g_object_set_qdata_full (G_OBJECT (factory), plugin_path_quark (), g_strdup (path), g_free); for (i = 0; link_types && link_types[i] > NM_LINK_TYPE_UNKNOWN; i++) g_hash_table_insert (factories_by_link, GUINT_TO_POINTER (link_types[i]), g_object_ref (factory)); - for (i = 0; setting_types && setting_types[i]; i++) - g_hash_table_insert (factories_by_setting, (char *) setting_types[i], g_object_ref (factory)); + for (i = 0; setting_types && setting_types[i]; i++) { + list = g_hash_table_lookup (factories_by_setting, (char *) setting_types[i]); + if (list) + list = g_slist_append (list, g_object_ref (factory)); + else { + list = g_slist_append (list, g_object_ref (factory)); + g_hash_table_insert (factories_by_setting, (char *) setting_types[i], list); + } + } callback (factory, user_data); @@ -333,6 +333,12 @@ _load_internal_factory (GType factory_gtype, _add_factory (factory, "internal", callback, user_data); } +static void +factories_list_unref (GSList *list) +{ + g_slist_free_full (list, g_object_unref); +} + void nm_device_factory_manager_load_factories (NMDeviceFactoryManagerFactoryFunc callback, gpointer user_data) @@ -345,7 +351,7 @@ nm_device_factory_manager_load_factories (NMDeviceFactoryManagerFactoryFunc call g_return_if_fail (factories_by_setting == NULL); factories_by_link = g_hash_table_new_full (g_direct_hash, g_direct_equal, NULL, g_object_unref); - factories_by_setting = g_hash_table_new_full (g_str_hash, g_str_equal, NULL, g_object_unref); + factories_by_setting = g_hash_table_new_full (g_str_hash, g_str_equal, NULL, (GDestroyNotify) factories_list_unref); #define _ADD_INTERNAL(get_type_fcn) \ G_STMT_START { \ diff --git a/src/devices/nm-device-factory.h b/src/devices/nm-device-factory.h index 0c590f657a..33b596e6e6 100644 --- a/src/devices/nm-device-factory.h +++ b/src/devices/nm-device-factory.h @@ -71,6 +71,14 @@ typedef struct { */ void (*start) (NMDeviceFactory *factory); + /** + * match_connection: + * @connection: the #NMConnection + * + * Check if the factory supports the given connection. + */ + gboolean (*match_connection) (NMDeviceFactory *factory, NMConnection *connection); + /** * get_connection_parent: * @factory: the #NMDeviceFactory From 695f6ceebb7c2cc96e50e3156e7938616e021553 Mon Sep 17 00:00:00 2001 From: Beniamino Galvani Date: Fri, 30 Jun 2017 17:49:44 +0200 Subject: [PATCH 6/9] device: accept NULL plink For PPP devices we can't create a link in advance, as the link is created by pppd when the connection is established. --- src/devices/nm-device.c | 6 ++++-- 1 file changed, 4 insertions(+), 2 deletions(-) diff --git a/src/devices/nm-device.c b/src/devices/nm-device.c index 1530b60716..321f7cf8ca 100644 --- a/src/devices/nm-device.c +++ b/src/devices/nm-device.c @@ -2911,8 +2911,10 @@ nm_device_create_and_realize (NMDevice *self, if (NM_DEVICE_GET_CLASS (self)->create_and_realize) { if (!NM_DEVICE_GET_CLASS (self)->create_and_realize (self, connection, parent, &plink, error)) return FALSE; - plink_copy = *plink; - plink = &plink_copy; + if (plink) { + plink_copy = *plink; + plink = &plink_copy; + } } realize_start_setup (self, plink, From 6c3195931e94cab70208ce97f3b834f5d9f5ff62 Mon Sep 17 00:00:00 2001 From: Beniamino Galvani Date: Mon, 3 Jul 2017 16:24:59 +0200 Subject: [PATCH 7/9] core: implement activation of PPP devices Add code to NMPppDevice to activate new-style PPPoE connections. This is a bit tricky because we can't create the link as usual in create_and_realize(). Instead, we create a device without ifindex and start pppd in stage2; when pppd reports a new configuration, we rename the platform link to the correct name and set the ifindex into the device. This mechanism is inherently racy, but there is no way to tell pppd to create an arbitrary interface name. --- src/devices/nm-device-ppp.c | 240 +++++++++++++++++++++++++++++++- src/devices/nm-device-private.h | 2 + src/devices/nm-device.c | 34 +++++ src/nm-manager.c | 18 +++ src/nm-manager.h | 2 + 5 files changed, 293 insertions(+), 3 deletions(-) diff --git a/src/devices/nm-device-ppp.c b/src/devices/nm-device-ppp.c index d0f2c9526e..7c034f5f85 100644 --- a/src/devices/nm-device-ppp.c +++ b/src/devices/nm-device-ppp.c @@ -16,9 +16,15 @@ #include "nm-device-ppp.h" +#include "nm-act-request.h" #include "nm-device-factory.h" #include "nm-device-private.h" +#include "nm-manager.h" +#include "nm-setting-pppoe.h" #include "platform/nm-platform.h" +#include "ppp/nm-ppp-manager.h" +#include "ppp/nm-ppp-manager-call.h" +#include "ppp/nm-ppp-status.h" #include "introspection/org.freedesktop.NetworkManager.Device.Ppp.h" @@ -28,7 +34,9 @@ _LOG_DECLARE_SELF(NMDevicePpp); /*****************************************************************************/ typedef struct _NMDevicePppPrivate { - int dummy; + NMPPPManager *ppp_manager; + NMIP4Config *pending_ip4_config; + char *pending_ifname; } NMDevicePppPrivate; struct _NMDevicePpp { @@ -44,12 +52,185 @@ G_DEFINE_TYPE (NMDevicePpp, nm_device_ppp, NM_TYPE_DEVICE) #define NM_DEVICE_PPP_GET_PRIVATE(self) _NM_GET_PRIVATE (self, NMDevicePpp, NM_IS_DEVICE_PPP) +static gboolean +check_connection_compatible (NMDevice *device, NMConnection *connection) +{ + NMSettingPppoe *s_pppoe; + + if (!NM_DEVICE_CLASS (nm_device_ppp_parent_class)->check_connection_compatible (device, connection)) + return FALSE; + + if (!nm_streq0 (nm_connection_get_connection_type (connection), + NM_SETTING_PPPOE_SETTING_NAME)) + return FALSE; + + s_pppoe = nm_connection_get_setting_pppoe (connection); + nm_assert (s_pppoe); + + return !!nm_setting_pppoe_get_parent (s_pppoe); +} + static NMDeviceCapabilities get_generic_capabilities (NMDevice *device) { return NM_DEVICE_CAP_IS_SOFTWARE; } +static void +ppp_state_changed (NMPPPManager *ppp_manager, NMPPPStatus status, gpointer user_data) +{ + NMDevice *device = NM_DEVICE (user_data); + + switch (status) { + case NM_PPP_STATUS_DISCONNECT: + nm_device_state_changed (device, NM_DEVICE_STATE_FAILED, NM_DEVICE_STATE_REASON_PPP_DISCONNECT); + break; + case NM_PPP_STATUS_DEAD: + nm_device_state_changed (device, NM_DEVICE_STATE_FAILED, NM_DEVICE_STATE_REASON_PPP_FAILED); + break; + case NM_PPP_STATUS_RUNNING: + nm_device_activate_schedule_stage3_ip_config_start (device); + break; + default: + break; + } +} + +static void +ppp_ip4_config (NMPPPManager *ppp_manager, + const char *iface, + NMIP4Config *config, + gpointer user_data) +{ + NMDevice *device = NM_DEVICE (user_data); + NMDevicePpp *self = NM_DEVICE_PPP (device); + NMDevicePppPrivate *priv = NM_DEVICE_PPP_GET_PRIVATE (self); + + _LOGT (LOGD_DEVICE | LOGD_PPP, "received IPv4 config from pppd"); + + if (nm_device_get_state (device) == NM_DEVICE_STATE_IP_CONFIG) { + if (nm_device_activate_ip4_state_in_conf (device)) { + if (!nm_device_take_over_link (device, iface)) { + nm_device_state_changed (device, NM_DEVICE_STATE_FAILED, + NM_DEVICE_STATE_REASON_IP_CONFIG_UNAVAILABLE); + return; + } + nm_manager_remove_device (nm_manager_get (), iface); + nm_device_activate_schedule_ip4_config_result (device, config); + return; + } + } else { + if (priv->pending_ip4_config) + g_object_unref (priv->pending_ip4_config); + priv->pending_ip4_config = g_object_ref (config); + g_free (priv->pending_ifname); + priv->pending_ifname = g_strdup (iface); + } +} + +static NMActStageReturn +act_stage2_config (NMDevice *device, NMDeviceStateReason *out_failure_reason) +{ + NMDevicePpp *self = NM_DEVICE_PPP (device); + NMDevicePppPrivate *priv = NM_DEVICE_PPP_GET_PRIVATE (self); + NMSettingPppoe *s_pppoe; + NMActRequest *req; + GError *err = NULL; + + req = nm_device_get_act_request (NM_DEVICE (self)); + g_return_val_if_fail (req, NM_ACT_STAGE_RETURN_FAILURE); + + s_pppoe = (NMSettingPppoe *) nm_device_get_applied_setting ((NMDevice *) self, NM_TYPE_SETTING_PPPOE); + g_return_val_if_fail (s_pppoe, NM_ACT_STAGE_RETURN_FAILURE); + + g_clear_object (&priv->pending_ip4_config); + nm_clear_g_free (&priv->pending_ifname); + + priv->ppp_manager = nm_ppp_manager_create (nm_setting_pppoe_get_parent (s_pppoe), &err); + + if ( !priv->ppp_manager + || !nm_ppp_manager_start (priv->ppp_manager, req, + nm_setting_pppoe_get_username (s_pppoe), + 30, 0, &err)) { + _LOGW (LOGD_DEVICE | LOGD_PPP, "PPPoE failed to start: %s", err->message); + g_error_free (err); + + g_clear_object (&priv->ppp_manager); + + NM_SET_OUT (out_failure_reason, NM_DEVICE_STATE_REASON_PPP_START_FAILED); + return NM_ACT_STAGE_RETURN_FAILURE; + } + + g_signal_connect (priv->ppp_manager, NM_PPP_MANAGER_SIGNAL_STATE_CHANGED, + G_CALLBACK (ppp_state_changed), + self); + g_signal_connect (priv->ppp_manager, NM_PPP_MANAGER_SIGNAL_IP4_CONFIG, + G_CALLBACK (ppp_ip4_config), + self); + + return NM_ACT_STAGE_RETURN_POSTPONE; +} + +static NMActStageReturn +act_stage3_ip4_config_start (NMDevice *device, + NMIP4Config **out_config, + NMDeviceStateReason *out_failure_reason) +{ + NMDevicePpp *self = NM_DEVICE_PPP (device); + NMDevicePppPrivate *priv = NM_DEVICE_PPP_GET_PRIVATE (self); + + if (priv->pending_ip4_config) { + if (!nm_device_take_over_link (device, priv->pending_ifname)) + return NM_ACT_STAGE_RETURN_FAILURE; + nm_manager_remove_device (nm_manager_get (), priv->pending_ifname); + if (out_config) + *out_config = g_steal_pointer (&priv->pending_ip4_config); + else + g_clear_object (&priv->pending_ip4_config); + return NM_ACT_STAGE_RETURN_SUCCESS; + } + + /* Wait IPCP termination */ + return NM_ACT_STAGE_RETURN_POSTPONE; +} + +static gboolean +create_and_realize (NMDevice *device, + NMConnection *connection, + NMDevice *parent, + const NMPlatformLink **out_plink, + GError **error) +{ + int parent_ifindex; + + if (!parent) { + g_set_error (error, NM_DEVICE_ERROR, NM_DEVICE_ERROR_FAILED, + "PPP devices can not be created without a parent interface"); + return FALSE; + } + + parent_ifindex = nm_device_get_ifindex (parent); + g_warn_if_fail (parent_ifindex > 0); + + nm_device_parent_set_ifindex (device, parent_ifindex); + + /* The interface is created later */ + + return TRUE; +} + +static void +deactivate (NMDevice *device) +{ + NMDevicePpp *self = NM_DEVICE_PPP (device); + NMDevicePppPrivate *priv = NM_DEVICE_PPP_GET_PRIVATE (self); + + if (priv->ppp_manager) { + nm_ppp_manager_stop_sync (priv->ppp_manager); + g_clear_object (&priv->ppp_manager); + } +} + static void nm_device_ppp_init (NMDevicePpp *self) { @@ -58,6 +239,12 @@ nm_device_ppp_init (NMDevicePpp *self) static void dispose (GObject *object) { + NMDevicePpp *self = NM_DEVICE_PPP (object); + NMDevicePppPrivate *priv = NM_DEVICE_PPP_GET_PRIVATE (self); + + g_clear_object (&priv->pending_ip4_config); + nm_clear_g_free (&priv->pending_ifname); + G_OBJECT_CLASS (nm_device_ppp_parent_class)->dispose (object); } @@ -67,9 +254,15 @@ nm_device_ppp_class_init (NMDevicePppClass *klass) GObjectClass *object_class = G_OBJECT_CLASS (klass); NMDeviceClass *parent_class = NM_DEVICE_CLASS (klass); - NM_DEVICE_CLASS_DECLARE_TYPES (klass, NULL, NM_LINK_TYPE_PPP) + NM_DEVICE_CLASS_DECLARE_TYPES (klass, NM_SETTING_PPPOE_SETTING_NAME, NM_LINK_TYPE_PPP) object_class->dispose = dispose; + + parent_class->act_stage2_config = act_stage2_config; + parent_class->act_stage3_ip4_config_start = act_stage3_ip4_config_start; + parent_class->check_connection_compatible = check_connection_compatible; + parent_class->create_and_realize = create_and_realize; + parent_class->deactivate = deactivate; parent_class->get_generic_capabilities = get_generic_capabilities; nm_exported_object_class_add_interface (NM_EXPORTED_OBJECT_CLASS (klass), @@ -97,7 +290,48 @@ create_device (NMDeviceFactory *factory, NULL); } +static gboolean +match_connection (NMDeviceFactory *factory, NMConnection *connection) +{ + NMSettingPppoe *s_pppoe; + + s_pppoe = nm_connection_get_setting_pppoe (connection); + nm_assert (s_pppoe); + + return !!nm_setting_pppoe_get_parent (s_pppoe); +} + +static const char * +get_connection_parent (NMDeviceFactory *factory, NMConnection *connection) +{ + NMSettingPppoe *s_pppoe; + + nm_assert (nm_connection_is_type (connection, NM_SETTING_PPPOE_SETTING_NAME)); + + s_pppoe = nm_connection_get_setting_pppoe (connection); + nm_assert (s_pppoe); + + return nm_setting_pppoe_get_parent (s_pppoe); +} + +static char * +get_connection_iface (NMDeviceFactory *factory, + NMConnection *connection, + const char *parent_iface) +{ + nm_assert (nm_connection_is_type (connection, NM_SETTING_PPPOE_SETTING_NAME)); + + if (!parent_iface) + return NULL; + + return g_strdup (nm_connection_get_interface_name (connection)); +} + NM_DEVICE_FACTORY_DEFINE_INTERNAL (PPP, Ppp, ppp, - NM_DEVICE_FACTORY_DECLARE_LINK_TYPES (NM_LINK_TYPE_PPP), + NM_DEVICE_FACTORY_DECLARE_LINK_TYPES (NM_LINK_TYPE_PPP) + NM_DEVICE_FACTORY_DECLARE_SETTING_TYPES (NM_SETTING_PPPOE_SETTING_NAME), + factory_class->get_connection_parent = get_connection_parent; + factory_class->get_connection_iface = get_connection_iface; factory_class->create_device = create_device; + factory_class->match_connection = match_connection; ); diff --git a/src/devices/nm-device-private.h b/src/devices/nm-device-private.h index 05cb3f7d84..a02cab3159 100644 --- a/src/devices/nm-device-private.h +++ b/src/devices/nm-device-private.h @@ -57,6 +57,8 @@ gboolean nm_device_bring_up (NMDevice *self, gboolean wait, gboolean *no_firmwar void nm_device_take_down (NMDevice *self, gboolean block); +gboolean nm_device_take_over_link (NMDevice *self, const char *ifname); + gboolean nm_device_hw_addr_set (NMDevice *device, const char *addr, const char *detail, diff --git a/src/devices/nm-device.c b/src/devices/nm-device.c index 321f7cf8ca..3934c18f3c 100644 --- a/src/devices/nm-device.c +++ b/src/devices/nm-device.c @@ -1001,6 +1001,40 @@ nm_device_get_iface (NMDevice *self) return NM_DEVICE_GET_PRIVATE (self)->iface; } +gboolean +nm_device_take_over_link (NMDevice *self, const char *ifname) +{ + NMDevicePrivate *priv = NM_DEVICE_GET_PRIVATE (self); + const NMPlatformLink *plink; + NMPlatform *platform; + gboolean up, success; + int ifindex; + + g_return_val_if_fail (priv->ifindex <= 0, FALSE); + + platform = nm_device_get_platform (self); + plink = nm_platform_link_get_by_ifname (platform, ifname); + if (!plink) + return FALSE; + + ifindex = plink->ifindex; + up = NM_FLAGS_HAS (plink->n_ifi_flags, IFF_UP); + + /* Rename the link to the device ifname */ + if (up) + nm_platform_link_set_down (platform, ifindex); + success = nm_platform_link_set_name (platform, ifindex, nm_device_get_iface (self)); + if (up) + nm_platform_link_set_up (platform, ifindex, NULL); + + if (success) { + priv->ifindex = ifindex; + _notify (self, PROP_IFINDEX); + } + + return success; +} + int nm_device_get_ifindex (NMDevice *self) { diff --git a/src/nm-manager.c b/src/nm-manager.c index 3a8ada4360..e0cce262dc 100644 --- a/src/nm-manager.c +++ b/src/nm-manager.c @@ -1258,6 +1258,24 @@ nm_manager_iface_for_uuid (NMManager *self, const char *uuid) return nm_connection_get_interface_name (NM_CONNECTION (connection)); } +gboolean +nm_manager_remove_device (NMManager *self, const char *ifname) +{ + NMManagerPrivate *priv = NM_MANAGER_GET_PRIVATE (self); + GSList *iter; + NMDevice *d; + + for (iter = priv->devices; iter; iter = iter->next) { + d = iter->data; + if (nm_streq0 (nm_device_get_iface (d), ifname)) { + remove_device (self, d, FALSE, FALSE); + return TRUE; + } + } + + return FALSE; +} + /** * system_create_virtual_device: * @self: the #NMManager diff --git a/src/nm-manager.h b/src/nm-manager.h index fbbaffc314..0fdca8d458 100644 --- a/src/nm-manager.h +++ b/src/nm-manager.h @@ -124,4 +124,6 @@ gboolean nm_manager_deactivate_connection (NMManager *manager, void nm_manager_set_capability (NMManager *self, NMCapability cap); +gboolean nm_manager_remove_device (NMManager *self, const char *ifname); + #endif /* __NETWORKMANAGER_MANAGER_H__ */ From a7afa9ead7e8ca53d269ee69284056889f072281 Mon Sep 17 00:00:00 2001 From: Beniamino Galvani Date: Fri, 30 Jun 2017 17:51:04 +0200 Subject: [PATCH 8/9] device: use ppp device for new style pppoe setting --- libnm-core/nm-connection.c | 7 +++++++ src/devices/nm-device-ethernet.c | 16 ++++++++++++++++ 2 files changed, 23 insertions(+) diff --git a/libnm-core/nm-connection.c b/libnm-core/nm-connection.c index e41e6b6662..d2e528420e 100644 --- a/libnm-core/nm-connection.c +++ b/libnm-core/nm-connection.c @@ -1952,6 +1952,13 @@ nm_connection_is_virtual (NMConnection *connection) if (nm_streq (type, NM_SETTING_BLUETOOTH_SETTING_NAME)) return !!_nm_connection_get_setting_bluetooth_for_nap (connection); + if (nm_streq (type, NM_SETTING_PPPOE_SETTING_NAME)) { + NMSettingPppoe *s_pppoe; + + s_pppoe = nm_connection_get_setting_pppoe (connection); + return !!nm_setting_pppoe_get_parent (s_pppoe); + } + return FALSE; } diff --git a/src/devices/nm-device-ethernet.c b/src/devices/nm-device-ethernet.c index 83dc984dcc..eaa6a1f85d 100644 --- a/src/devices/nm-device-ethernet.c +++ b/src/devices/nm-device-ethernet.c @@ -1796,8 +1796,24 @@ create_device (NMDeviceFactory *factory, NULL); } +static gboolean +match_connection (NMDeviceFactory *factory, NMConnection *connection) +{ + const char *type = nm_connection_get_connection_type (connection); + NMSettingPppoe *s_pppoe; + + if (nm_streq (type, NM_SETTING_WIRED_SETTING_NAME)) + return TRUE; + + nm_assert (nm_streq (type, NM_SETTING_PPPOE_SETTING_NAME)); + s_pppoe = nm_connection_get_setting_pppoe (connection); + + return !nm_setting_pppoe_get_parent (s_pppoe); +} + NM_DEVICE_FACTORY_DEFINE_INTERNAL (ETHERNET, Ethernet, ethernet, NM_DEVICE_FACTORY_DECLARE_LINK_TYPES (NM_LINK_TYPE_ETHERNET) NM_DEVICE_FACTORY_DECLARE_SETTING_TYPES (NM_SETTING_WIRED_SETTING_NAME, NM_SETTING_PPPOE_SETTING_NAME), factory_class->create_device = create_device; + factory_class->match_connection = match_connection; ); From 74bf32ff9a672008017c23696c0eb7e9e02e6198 Mon Sep 17 00:00:00 2001 From: Beniamino Galvani Date: Mon, 3 Jul 2017 17:01:43 +0200 Subject: [PATCH 9/9] core: ppp: use a different unit for each activation We can't tell pppd to create an interface with a given name, so we use the name generated by kernel and rename the interface afterwards. A race condition can happen during the rename: NM receives the interface name from pppd, but in the meantime the interface could be deleted and another one with that name could appear. In this case we would rename the wrong interface. Using a changing unit index, we ensure that interfaces created by NM don't race with each others. There is still the chance to race with externally-created interfaces, but I guess this is not easily solvable since the pppd plugin does not expose the ifindex. When the specified unit is already in use, the kernel selects another one. --- src/ppp/nm-ppp-manager.c | 10 ++++++++++ 1 file changed, 10 insertions(+) diff --git a/src/ppp/nm-ppp-manager.c b/src/ppp/nm-ppp-manager.c index fec7ce375f..06703366f3 100644 --- a/src/ppp/nm-ppp-manager.c +++ b/src/ppp/nm-ppp-manager.c @@ -678,6 +678,7 @@ create_pppd_cmd_line (NMPPPManager *self, const char *pppd_binary = NULL; NMCmdLine *cmd; gboolean ppp_debug; + static int unit; g_return_val_if_fail (setting != NULL, NULL); @@ -842,6 +843,15 @@ create_pppd_cmd_line (NMPPPManager *self, nm_cmd_line_add_string (cmd, "plugin"); nm_cmd_line_add_string (cmd, NM_PPPD_PLUGIN); + if (pppoe && nm_setting_pppoe_get_parent (pppoe)) { + /* The PPP interface is going to be renamed, so pass a + * different unit each time so that activations don't + * race with each others. */ + nm_cmd_line_add_string (cmd, "unit"); + nm_cmd_line_add_int (cmd, unit); + unit = unit < G_MAXINT ? unit + 1 : 0; + } + return cmd; }