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.
This commit is contained in:
@@ -16,9 +16,15 @@
|
|||||||
|
|
||||||
#include "nm-device-ppp.h"
|
#include "nm-device-ppp.h"
|
||||||
|
|
||||||
|
#include "nm-act-request.h"
|
||||||
#include "nm-device-factory.h"
|
#include "nm-device-factory.h"
|
||||||
#include "nm-device-private.h"
|
#include "nm-device-private.h"
|
||||||
|
#include "nm-manager.h"
|
||||||
|
#include "nm-setting-pppoe.h"
|
||||||
#include "platform/nm-platform.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"
|
#include "introspection/org.freedesktop.NetworkManager.Device.Ppp.h"
|
||||||
|
|
||||||
@@ -28,7 +34,9 @@ _LOG_DECLARE_SELF(NMDevicePpp);
|
|||||||
/*****************************************************************************/
|
/*****************************************************************************/
|
||||||
|
|
||||||
typedef struct _NMDevicePppPrivate {
|
typedef struct _NMDevicePppPrivate {
|
||||||
int dummy;
|
NMPPPManager *ppp_manager;
|
||||||
|
NMIP4Config *pending_ip4_config;
|
||||||
|
char *pending_ifname;
|
||||||
} NMDevicePppPrivate;
|
} NMDevicePppPrivate;
|
||||||
|
|
||||||
struct _NMDevicePpp {
|
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)
|
#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
|
static NMDeviceCapabilities
|
||||||
get_generic_capabilities (NMDevice *device)
|
get_generic_capabilities (NMDevice *device)
|
||||||
{
|
{
|
||||||
return NM_DEVICE_CAP_IS_SOFTWARE;
|
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
|
static void
|
||||||
nm_device_ppp_init (NMDevicePpp *self)
|
nm_device_ppp_init (NMDevicePpp *self)
|
||||||
{
|
{
|
||||||
@@ -58,6 +239,12 @@ nm_device_ppp_init (NMDevicePpp *self)
|
|||||||
static void
|
static void
|
||||||
dispose (GObject *object)
|
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);
|
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);
|
GObjectClass *object_class = G_OBJECT_CLASS (klass);
|
||||||
NMDeviceClass *parent_class = NM_DEVICE_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;
|
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;
|
parent_class->get_generic_capabilities = get_generic_capabilities;
|
||||||
|
|
||||||
nm_exported_object_class_add_interface (NM_EXPORTED_OBJECT_CLASS (klass),
|
nm_exported_object_class_add_interface (NM_EXPORTED_OBJECT_CLASS (klass),
|
||||||
@@ -97,7 +290,48 @@ create_device (NMDeviceFactory *factory,
|
|||||||
NULL);
|
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_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->create_device = create_device;
|
||||||
|
factory_class->match_connection = match_connection;
|
||||||
);
|
);
|
||||||
|
@@ -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);
|
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,
|
gboolean nm_device_hw_addr_set (NMDevice *device,
|
||||||
const char *addr,
|
const char *addr,
|
||||||
const char *detail,
|
const char *detail,
|
||||||
|
@@ -1001,6 +1001,40 @@ nm_device_get_iface (NMDevice *self)
|
|||||||
return NM_DEVICE_GET_PRIVATE (self)->iface;
|
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
|
int
|
||||||
nm_device_get_ifindex (NMDevice *self)
|
nm_device_get_ifindex (NMDevice *self)
|
||||||
{
|
{
|
||||||
|
@@ -1258,6 +1258,24 @@ nm_manager_iface_for_uuid (NMManager *self, const char *uuid)
|
|||||||
return nm_connection_get_interface_name (NM_CONNECTION (connection));
|
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:
|
* system_create_virtual_device:
|
||||||
* @self: the #NMManager
|
* @self: the #NMManager
|
||||||
|
@@ -124,4 +124,6 @@ gboolean nm_manager_deactivate_connection (NMManager *manager,
|
|||||||
|
|
||||||
void nm_manager_set_capability (NMManager *self, NMCapability cap);
|
void nm_manager_set_capability (NMManager *self, NMCapability cap);
|
||||||
|
|
||||||
|
gboolean nm_manager_remove_device (NMManager *self, const char *ifname);
|
||||||
|
|
||||||
#endif /* __NETWORKMANAGER_MANAGER_H__ */
|
#endif /* __NETWORKMANAGER_MANAGER_H__ */
|
||||||
|
Reference in New Issue
Block a user