about summary refs log tree commit diff
path: root/src/core/devices/nm-device-ppp.c
diff options
context:
space:
mode:
Diffstat (limited to 'src/core/devices/nm-device-ppp.c')
-rw-r--r--src/core/devices/nm-device-ppp.c288
1 files changed, 141 insertions, 147 deletions
diff --git a/src/core/devices/nm-device-ppp.c b/src/core/devices/nm-device-ppp.c
index 04051bec..5ff32401 100644
--- a/src/core/devices/nm-device-ppp.c
+++ b/src/core/devices/nm-device-ppp.c
@@ -7,16 +7,14 @@
 
 #include "nm-device-ppp.h"
 
-#include "nm-ip4-config.h"
+#include "nm-l3-config-data.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 "libnm-platform/nm-platform.h"
-#include "ppp/nm-ppp-manager.h"
-#include "ppp/nm-ppp-manager-call.h"
-#include "ppp/nm-ppp-status.h"
+#include "ppp/nm-ppp-mgr.h"
 
 #define _NMLOG_DEVICE_TYPE NMDevicePpp
 #include "nm-device-logging.h"
@@ -24,8 +22,7 @@
 /*****************************************************************************/
 
 typedef struct _NMDevicePppPrivate {
-    NMPPPManager *ppp_manager;
-    NMIP4Config * ip4_config;
+    NMPppMgr *ppp_mgr;
 } NMDevicePppPrivate;
 
 struct _NMDevicePpp {
@@ -42,86 +39,92 @@ 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, NMDevice)
 
+/*****************************************************************************/
+
 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)
+_ppp_mgr_cleanup(NMDevicePpp *self)
 {
-    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;
-    default:
-        break;
-    }
+    NMDevicePppPrivate *priv = NM_DEVICE_PPP_GET_PRIVATE(self);
+
+    nm_clear_pointer(&priv->ppp_mgr, nm_ppp_mgr_destroy);
 }
 
 static void
-ppp_ifindex_set(NMPPPManager *ppp_manager, int ifindex, const char *iface, gpointer user_data)
+_ppp_mgr_stage3_maybe_ready(NMDevicePpp *self)
 {
-    NMDevice *    device        = NM_DEVICE(user_data);
-    NMDevicePpp * self          = NM_DEVICE_PPP(device);
-    gs_free char *old_name      = NULL;
-    gs_free_error GError *error = NULL;
-
-    if (!nm_device_take_over_link(device, ifindex, &old_name, &error)) {
-        _LOGW(LOGD_DEVICE | LOGD_PPP,
-              "could not take control of link %d: %s",
-              ifindex,
-              error->message);
-        nm_device_state_changed(device,
-                                NM_DEVICE_STATE_FAILED,
-                                NM_DEVICE_STATE_REASON_IP_CONFIG_UNAVAILABLE);
-        return;
-    }
+    NMDevice           *device = NM_DEVICE(self);
+    NMDevicePppPrivate *priv   = NM_DEVICE_PPP_GET_PRIVATE(self);
+    int                 IS_IPv4;
+
+    for (IS_IPv4 = 1; IS_IPv4 >= 0; IS_IPv4--) {
+        const int             addr_family = IS_IPv4 ? AF_INET : AF_INET6;
+        const NMPppMgrIPData *ip_data;
 
-    if (old_name)
-        nm_manager_remove_device(NM_MANAGER_GET, old_name, NM_DEVICE_TYPE_PPP);
+        ip_data = nm_ppp_mgr_get_ip_data(priv->ppp_mgr, addr_family);
+        if (ip_data->ip_received)
+            nm_device_devip_set_state(device, addr_family, NM_DEVICE_IP_STATE_READY, ip_data->l3cd);
+    }
 
-    nm_device_activate_schedule_stage3_ip_config_start(device);
+    if (nm_ppp_mgr_get_state(priv->ppp_mgr) >= NM_PPP_MGR_STATE_HAVE_IP_CONFIG)
+        nm_device_devip_set_state(device, AF_UNSPEC, NM_DEVICE_IP_STATE_READY, NULL);
 }
 
 static void
-_ppp_ip4_config_handle(NMDevicePpp *self)
+_ppp_mgr_callback(NMPppMgr *ppp_mgr, const NMPppMgrCallbackData *callback_data, gpointer user_data)
 {
-    NMDevice *          device = NM_DEVICE(self);
-    NMDevicePppPrivate *priv   = NM_DEVICE_PPP_GET_PRIVATE(self);
+    NMDevicePpp  *self   = NM_DEVICE_PPP(user_data);
+    NMDevice     *device = NM_DEVICE(self);
+    NMDeviceState device_state;
 
-    if (!priv->ip4_config)
+    if (callback_data->callback_type != NM_PPP_MGR_CALLBACK_TYPE_STATE_CHANGED)
         return;
 
-    if (nm_device_get_state(device) == NM_DEVICE_STATE_IP_CONFIG
-        && nm_device_activate_ip4_state_in_conf(device)) {
-        nm_device_activate_schedule_ip_config_result(
-            device,
-            AF_INET,
-            NM_IP_CONFIG_CAST(g_steal_pointer(&priv->ip4_config)));
+    device_state = nm_device_get_state(device);
+
+    if (callback_data->data.state >= _NM_PPP_MGR_STATE_FAILED_START) {
+        if (device_state <= NM_DEVICE_STATE_ACTIVATED)
+            nm_device_state_changed(device, NM_DEVICE_STATE_FAILED, callback_data->data.reason);
         return;
     }
-}
 
-static void
-ppp_ip4_config(NMPPPManager *ppp_manager, NMIP4Config *config, gpointer user_data)
-{
-    NMDevicePpp *       self = NM_DEVICE_PPP(user_data);
-    NMDevicePppPrivate *priv = NM_DEVICE_PPP_GET_PRIVATE(self);
+    if (device_state < NM_DEVICE_STATE_IP_CONFIG) {
+        if (callback_data->data.state >= NM_PPP_MGR_STATE_HAVE_IFINDEX) {
+            gs_free char         *old_name = NULL;
+            gs_free_error GError *error    = NULL;
+
+            if (!nm_device_take_over_link(device, callback_data->data.ifindex, &old_name, &error)) {
+                _LOGW(LOGD_DEVICE | LOGD_PPP,
+                      "could not take control of link %d: %s",
+                      callback_data->data.ifindex,
+                      error->message);
+                _ppp_mgr_cleanup(self);
+                nm_device_state_changed(device,
+                                        NM_DEVICE_STATE_FAILED,
+                                        NM_DEVICE_STATE_REASON_CONFIG_FAILED);
+                return;
+            }
+
+            if (old_name)
+                nm_manager_remove_device(NM_MANAGER_GET, old_name, NM_DEVICE_TYPE_PPP);
+
+            nm_device_activate_schedule_stage2_device_config(device, FALSE);
+        }
+        return;
+    }
 
-    _LOGT(LOGD_DEVICE | LOGD_PPP, "received IPv4 config from pppd");
-    nm_g_object_ref_set(&priv->ip4_config, config);
-    _ppp_ip4_config_handle(self);
+    _ppp_mgr_stage3_maybe_ready(self);
 }
 
+/*****************************************************************************/
+
 static gboolean
 check_connection_compatible(NMDevice *device, NMConnection *connection, GError **error)
 {
@@ -145,97 +148,92 @@ check_connection_compatible(NMDevice *device, NMConnection *connection, GError *
 static NMActStageReturn
 act_stage2_config(NMDevice *device, NMDeviceStateReason *out_failure_reason)
 {
-    NMDevicePpp *       self = NM_DEVICE_PPP(device);
+    NMDevicePpp        *self = NM_DEVICE_PPP(device);
     NMDevicePppPrivate *priv = NM_DEVICE_PPP_GET_PRIVATE(self);
-    NMSettingPppoe *    s_pppoe;
-    NMActRequest *      req;
-    GError *            error = NULL;
+    NMSettingPppoe     *s_pppoe;
+    NMActRequest       *req;
+
+    if (!priv->ppp_mgr) {
+        gs_free_error GError *error = NULL;
+
+        req = nm_device_get_act_request(device);
+        g_return_val_if_fail(req, NM_ACT_STAGE_RETURN_FAILURE);
+
+        s_pppoe = nm_device_get_applied_setting(device, NM_TYPE_SETTING_PPPOE);
+        g_return_val_if_fail(s_pppoe, NM_ACT_STAGE_RETURN_FAILURE);
+
+        priv->ppp_mgr = nm_ppp_mgr_start(&((const NMPppMgrConfig){
+                                             .netns        = nm_device_get_netns(device),
+                                             .parent_iface = nm_setting_pppoe_get_parent(s_pppoe),
+                                             .callback     = _ppp_mgr_callback,
+                                             .user_data    = self,
+                                             .act_req      = req,
+                                             .ppp_username = nm_setting_pppoe_get_username(s_pppoe),
+                                             .timeout_secs = 30,
+                                             .baud_override = 0,
+                                         }),
+                                         &error);
+        if (!priv->ppp_mgr) {
+            _LOGW(LOGD_DEVICE | LOGD_PPP, "PPPoE failed to start: %s", error->message);
+            *out_failure_reason = NM_DEVICE_STATE_REASON_PPP_START_FAILED;
+            return NM_ACT_STAGE_RETURN_FAILURE;
+        }
 
-    req = nm_device_get_act_request(device);
-    g_return_val_if_fail(req, NM_ACT_STAGE_RETURN_FAILURE);
+        return NM_ACT_STAGE_RETURN_POSTPONE;
+    }
 
-    s_pppoe = nm_device_get_applied_setting(device, NM_TYPE_SETTING_PPPOE);
-    g_return_val_if_fail(s_pppoe, NM_ACT_STAGE_RETURN_FAILURE);
+    if (nm_ppp_mgr_get_state(priv->ppp_mgr) < NM_PPP_MGR_STATE_HAVE_IFINDEX)
+        return NM_ACT_STAGE_RETURN_POSTPONE;
 
-    g_clear_object(&priv->ip4_config);
+    return NM_ACT_STAGE_RETURN_SUCCESS;
+}
 
-    priv->ppp_manager = nm_ppp_manager_create(nm_setting_pppoe_get_parent(s_pppoe), &error);
+static void
+act_stage3_ip_config(NMDevice *device, int addr_family)
+{
+    NMDevicePpp        *self = NM_DEVICE_PPP(device);
+    NMDevicePppPrivate *priv = NM_DEVICE_PPP_GET_PRIVATE(self);
+    NMPppMgrState       ppp_state;
 
-    if (priv->ppp_manager) {
-        nm_ppp_manager_set_route_parameters(priv->ppp_manager,
-                                            nm_device_get_route_table(device, AF_INET),
-                                            nm_device_get_route_metric(device, AF_INET),
-                                            nm_device_get_route_table(device, AF_INET6),
-                                            nm_device_get_route_metric(device, AF_INET6));
+    if (!priv->ppp_mgr) {
+        nm_assert_not_reached();
+        return;
     }
 
-    if (!priv->ppp_manager
-        || !nm_ppp_manager_start(priv->ppp_manager,
-                                 req,
-                                 nm_setting_pppoe_get_username(s_pppoe),
-                                 30,
-                                 0,
-                                 &error)) {
-        _LOGW(LOGD_DEVICE | LOGD_PPP, "PPPoE failed to start: %s", error->message);
-        g_error_free(error);
+    ppp_state = nm_ppp_mgr_get_state(priv->ppp_mgr);
 
-        g_clear_object(&priv->ppp_manager);
+    nm_assert(NM_IN_SET(ppp_state, NM_PPP_MGR_STATE_HAVE_IFINDEX, NM_PPP_MGR_STATE_HAVE_IP_CONFIG));
 
-        NM_SET_OUT(out_failure_reason, NM_DEVICE_STATE_REASON_PPP_START_FAILED);
-        return NM_ACT_STAGE_RETURN_FAILURE;
+    if (ppp_state < NM_PPP_MGR_STATE_HAVE_IP_CONFIG) {
+        nm_device_devip_set_state(device, AF_UNSPEC, NM_DEVICE_IP_STATE_PENDING, NULL);
+        return;
     }
 
-    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_IFINDEX_SET,
-                     G_CALLBACK(ppp_ifindex_set),
-                     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 gboolean
-_schedule_ip_config_result(gpointer user_data)
-{
-    gs_unref_object NMDevicePpp *self = user_data;
-
-    _ppp_ip4_config_handle(self);
-    return G_SOURCE_REMOVE;
+    _ppp_mgr_stage3_maybe_ready(self);
 }
 
-static NMActStageReturn
-act_stage3_ip_config_start(NMDevice *           device,
-                           int                  addr_family,
-                           gpointer *           out_config,
-                           NMDeviceStateReason *out_failure_reason)
+static const char *
+get_ip_method_auto(NMDevice *device, int addr_family)
 {
-    if (addr_family == AF_INET) {
-        NMDevicePpp *       self = NM_DEVICE_PPP(device);
-        NMDevicePppPrivate *priv = NM_DEVICE_PPP_GET_PRIVATE(self);
-
-        if (priv->ip4_config)
-            nm_g_idle_add(_schedule_ip_config_result, g_object_ref(self));
-
-        /* Wait IPCP termination */
-        return NM_ACT_STAGE_RETURN_POSTPONE;
+    if (NM_IS_IPv4(addr_family)) {
+        /* We cannot do DHCPv4 on a PPP link, instead we get "auto" IP addresses
+         * by pppd. Return "manual" here, which has the suitable effect to a
+         * (zero) manual addresses in addition. */
+        return NM_SETTING_IP6_CONFIG_METHOD_MANUAL;
     }
 
-    return NM_DEVICE_CLASS(nm_device_ppp_parent_class)
-        ->act_stage3_ip_config_start(device, addr_family, out_config, out_failure_reason);
+    /* We can do autoconf6 on an PPP link, but we should already get an IPv6
+     * address from pppd. Use that instead. We however do want to generate our
+     * (own) IPv6 link local address, so return "link-local". */
+    return NM_SETTING_IP6_CONFIG_METHOD_LINK_LOCAL;
 }
 
 static gboolean
-create_and_realize(NMDevice *             device,
-                   NMConnection *         connection,
-                   NMDevice *             parent,
+create_and_realize(NMDevice              *device,
+                   NMConnection          *connection,
+                   NMDevice              *parent,
                    const NMPlatformLink **out_plink,
-                   GError **              error)
+                   GError               **error)
 {
     int parent_ifindex;
 
@@ -260,17 +258,13 @@ create_and_realize(NMDevice *             device,
 static void
 deactivate(NMDevice *device)
 {
-    NMDevicePpp *       self = NM_DEVICE_PPP(device);
-    NMDevicePppPrivate *priv = NM_DEVICE_PPP_GET_PRIVATE(self);
+    NMDevicePpp *self = NM_DEVICE_PPP(device);
 
-    if (priv->ppp_manager) {
-        nm_ppp_manager_stop(priv->ppp_manager, NULL, NULL, NULL);
-        g_clear_object(&priv->ppp_manager);
-    }
-
-    g_clear_object(&priv->ip4_config);
+    _ppp_mgr_cleanup(self);
 }
 
+/*****************************************************************************/
+
 static void
 nm_device_ppp_init(NMDevicePpp *self)
 {}
@@ -278,10 +272,9 @@ 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);
+    NMDevicePpp *self = NM_DEVICE_PPP(object);
 
-    g_clear_object(&priv->ip4_config);
+    _ppp_mgr_cleanup(self);
 
     G_OBJECT_CLASS(nm_device_ppp_parent_class)->dispose(object);
 }
@@ -293,9 +286,9 @@ static const NMDBusInterfaceInfoExtended interface_info_device_ppp = {
 static void
 nm_device_ppp_class_init(NMDevicePppClass *klass)
 {
-    GObjectClass *     object_class      = G_OBJECT_CLASS(klass);
+    GObjectClass      *object_class      = G_OBJECT_CLASS(klass);
     NMDBusObjectClass *dbus_object_class = NM_DBUS_OBJECT_CLASS(klass);
-    NMDeviceClass *    device_class      = NM_DEVICE_CLASS(klass);
+    NMDeviceClass     *device_class      = NM_DEVICE_CLASS(klass);
 
     object_class->dispose = dispose;
 
@@ -306,7 +299,8 @@ nm_device_ppp_class_init(NMDevicePppClass *klass)
     device_class->link_types                       = NM_DEVICE_DEFINE_LINK_TYPES(NM_LINK_TYPE_PPP);
 
     device_class->act_stage2_config           = act_stage2_config;
-    device_class->act_stage3_ip_config_start  = act_stage3_ip_config_start;
+    device_class->act_stage3_ip_config        = act_stage3_ip_config;
+    device_class->get_ip_method_auto          = get_ip_method_auto;
     device_class->check_connection_compatible = check_connection_compatible;
     device_class->create_and_realize          = create_and_realize;
     device_class->deactivate                  = deactivate;
@@ -320,11 +314,11 @@ nm_device_ppp_class_init(NMDevicePppClass *klass)
     (G_TYPE_CHECK_INSTANCE_CAST((obj), NM_TYPE_PPP_DEVICE_FACTORY, NMPppDeviceFactory))
 
 static NMDevice *
-create_device(NMDeviceFactory *     factory,
-              const char *          iface,
+create_device(NMDeviceFactory      *factory,
+              const char           *iface,
               const NMPlatformLink *plink,
-              NMConnection *        connection,
-              gboolean *            out_ignore)
+              NMConnection         *connection,
+              gboolean             *out_ignore)
 {
     return g_object_new(NM_TYPE_DEVICE_PPP,
                         NM_DEVICE_IFACE,