about summary refs log tree commit diff
path: root/src/core/ppp
diff options
context:
space:
mode:
authorMichael Biebl <biebl@debian.org>2022-02-14 19:23:28 +0100
committerMichael Biebl <biebl@debian.org>2022-02-14 19:23:28 +0100
commit2f94dba7385fd0e0ef19a06eb4a2fcf6c43d7946 (patch)
treee2222f5577115985dd52044d2991253403cdd952 /src/core/ppp
parent88c227d90a6b7b388c5c85d72802a0ca8f05ed5c (diff)
New upstream version 1.35.91 upstream/1.35.91
Diffstat (limited to 'src/core/ppp')
-rw-r--r--src/core/ppp/nm-ppp-manager-call.c32
-rw-r--r--src/core/ppp/nm-ppp-manager-call.h14
-rw-r--r--src/core/ppp/nm-ppp-manager.c436
-rw-r--r--src/core/ppp/nm-ppp-manager.h5
-rw-r--r--src/core/ppp/nm-ppp-mgr.c620
-rw-r--r--src/core/ppp/nm-ppp-mgr.h131
-rw-r--r--src/core/ppp/nm-ppp-plugin-api.h14
-rw-r--r--src/core/ppp/nm-ppp-status.h5
-rw-r--r--src/core/ppp/nm-pppd-plugin.c12
9 files changed, 1000 insertions, 269 deletions
diff --git a/src/core/ppp/nm-ppp-manager-call.c b/src/core/ppp/nm-ppp-manager-call.c
index 5e84f596..8c788fad 100644
--- a/src/core/ppp/nm-ppp-manager-call.c
+++ b/src/core/ppp/nm-ppp-manager-call.c
@@ -25,9 +25,9 @@ static const NMPPPOps *_ppp_ops = NULL;
 NMPPPManager *
 nm_ppp_manager_create(const char *iface, GError **error)
 {
-    NMPPPManager *  ret;
-    GModule *       plugin;
-    GError *        error_local = NULL;
+    NMPPPManager   *ret;
+    GModule        *plugin;
+    GError         *error_local = NULL;
     struct stat     st;
     const NMPPPOps *ppp_ops;
 
@@ -94,31 +94,13 @@ again:
     return ret;
 }
 
-void
-nm_ppp_manager_set_route_parameters(NMPPPManager *self,
-                                    guint32       ip4_route_table,
-                                    guint32       ip4_route_metric,
-                                    guint32       ip6_route_table,
-                                    guint32       ip6_route_metric)
-{
-    const NMPPPOps *ppp_ops = ppp_ops_get();
-
-    g_return_if_fail(ppp_ops);
-
-    ppp_ops->set_route_parameters(self,
-                                  ip4_route_table,
-                                  ip4_route_metric,
-                                  ip6_route_table,
-                                  ip6_route_metric);
-}
-
 gboolean
 nm_ppp_manager_start(NMPPPManager *self,
                      NMActRequest *req,
-                     const char *  ppp_name,
+                     const char   *ppp_name,
                      guint32       timeout_secs,
                      guint         baud_override,
-                     GError **     err)
+                     GError      **err)
 {
     const NMPPPOps *ppp_ops = ppp_ops_get();
 
@@ -128,8 +110,8 @@ nm_ppp_manager_start(NMPPPManager *self,
 }
 
 NMPPPManagerStopHandle *
-nm_ppp_manager_stop(NMPPPManager *           self,
-                    GCancellable *           cancellable,
+nm_ppp_manager_stop(NMPPPManager            *self,
+                    GCancellable            *cancellable,
                     NMPPPManagerStopCallback callback,
                     gpointer                 user_data)
 {
diff --git a/src/core/ppp/nm-ppp-manager-call.h b/src/core/ppp/nm-ppp-manager-call.h
index c831cf0d..ef081200 100644
--- a/src/core/ppp/nm-ppp-manager-call.h
+++ b/src/core/ppp/nm-ppp-manager-call.h
@@ -10,21 +10,15 @@
 
 NMPPPManager *nm_ppp_manager_create(const char *iface, GError **error);
 
-void nm_ppp_manager_set_route_parameters(NMPPPManager *ppp_manager,
-                                         guint32       ip4_route_table,
-                                         guint32       ip4_route_metric,
-                                         guint32       ip6_route_table,
-                                         guint32       ip6_route_metric);
-
 gboolean nm_ppp_manager_start(NMPPPManager *self,
                               NMActRequest *req,
-                              const char *  ppp_name,
+                              const char   *ppp_name,
                               guint32       timeout_secs,
                               guint         baud_override,
-                              GError **     error);
+                              GError      **error);
 
-NMPPPManagerStopHandle *nm_ppp_manager_stop(NMPPPManager *           self,
-                                            GCancellable *           cancellable,
+NMPPPManagerStopHandle *nm_ppp_manager_stop(NMPPPManager            *self,
+                                            GCancellable            *cancellable,
                                             NMPPPManagerStopCallback callback,
                                             gpointer                 user_data);
 
diff --git a/src/core/ppp/nm-ppp-manager.c b/src/core/ppp/nm-ppp-manager.c
index e6790f22..f1f10305 100644
--- a/src/core/ppp/nm-ppp-manager.c
+++ b/src/core/ppp/nm-ppp-manager.c
@@ -32,8 +32,7 @@
 #include "libnm-platform/nm-platform-utils.h"
 #include "libnm-core-intern/nm-core-internal.h"
 #include "nm-act-request.h"
-#include "nm-ip4-config.h"
-#include "nm-ip6-config.h"
+#include "nm-l3-config-data.h"
 #include "nm-dbus-object.h"
 
 #include "nm-pppd-plugin.h"
@@ -46,6 +45,26 @@ static NM_CACHED_QUARK_FCN("ppp-manager-secret-tries", ppp_manager_secret_tries_
 
 /*****************************************************************************/
 
+/* FIXME(l3cfg:ppp): I think NMPPPManager's API should be improved to be easier
+ * usable (by the higher layers). That means to make the class more complex, to
+ * provide a simpler API.
+ *
+ * For example:
+ *
+ * - NM_PPP_MANAGER_SIGNAL_STATE_CHANGED just gets re-emitted when we receive
+ *   the D-Bus call from the plugin. The emitted state is like NM_PPP_STATUS_SERIALCONN,
+ *   but none of the users cares about this (what would it mean anyway)? The
+ *   class should itself consume the state, and emit something more consumable
+ *   (like: interface is ready (with ifindex), IPvX configuration done (with l3cd).
+ *
+ * - currently signals can be emitted in any order, and it's not clear which
+ *   signals we can expect. For example, when we activate a device, we may want to wait
+ *   for IPv4 and IPv6 configuration, but it's not clear whether this configuration
+ *   is still to be received or whether we can stop waiting.
+ **/
+
+/*****************************************************************************/
+
 #define NM_TYPE_PPP_MANAGER (nm_ppp_manager_get_type())
 #define NM_PPP_MANAGER(obj) (G_TYPE_CHECK_INSTANCE_CAST((obj), NM_TYPE_PPP_MANAGER, NMPPPManager))
 #define NM_PPP_MANAGER_CLASS(klass) \
@@ -62,8 +81,7 @@ GType nm_ppp_manager_get_type(void);
 enum {
     STATE_CHANGED,
     IFINDEX_SET,
-    IP4_CONFIG,
-    IP6_CONFIG,
+    NEW_CONFIG,
     STATS,
 
     LAST_SIGNAL
@@ -80,10 +98,10 @@ typedef struct {
     char *ip_iface;
     int   ifindex;
 
-    NMActRequest *                act_req;
-    GDBusMethodInvocation *       pending_secrets_context;
+    NMActRequest                 *act_req;
+    GDBusMethodInvocation        *pending_secrets_context;
     NMActRequestGetSecretsCallId *secrets_id;
-    const char *                  secrets_setting_name;
+    const char                   *secrets_setting_name;
 
     guint ppp_watch_id;
     guint ppp_timeout_handler;
@@ -91,11 +109,6 @@ typedef struct {
     /* Monitoring */
     int   monitor_fd;
     guint monitor_id;
-
-    guint32 ip4_route_table;
-    guint32 ip4_route_metric;
-    guint32 ip6_route_table;
-    guint32 ip6_route_metric;
 } NMPPPManagerPrivate;
 
 struct _NMPPPManager {
@@ -121,8 +134,8 @@ G_DEFINE_TYPE(NMPPPManager, nm_ppp_manager, NM_TYPE_DBUS_OBJECT)
 
 static void _ppp_cleanup(NMPPPManager *self);
 
-static NMPPPManagerStopHandle *_ppp_manager_stop(NMPPPManager *           self,
-                                                 GCancellable *           cancellable,
+static NMPPPManagerStopHandle *_ppp_manager_stop(NMPPPManager            *self,
+                                                 GCancellable            *cancellable,
                                                  NMPPPManagerStopCallback callback,
                                                  gpointer                 user_data);
 
@@ -131,30 +144,19 @@ static void _ppp_manager_stop_cancel(NMPPPManagerStopHandle *handle);
 /*****************************************************************************/
 
 static void
-_ppp_manager_set_route_parameters(NMPPPManager *self,
-                                  guint32       ip4_route_table,
-                                  guint32       ip4_route_metric,
-                                  guint32       ip6_route_table,
-                                  guint32       ip6_route_metric)
+_emit_signal_new_config(NMPPPManager             *self,
+                        int                       addr_family,
+                        const NML3ConfigData     *l3cd,
+                        const NMUtilsIPv6IfaceId *iid)
 {
-    NMPPPManagerPrivate *priv;
+    nm_assert(NM_IS_PPP_MANAGER(self));
+    nm_assert_addr_family(addr_family);
+    nm_assert(NM_IS_L3_CONFIG_DATA(l3cd));
+    nm_assert((!!iid) == (addr_family == AF_INET6));
 
-    g_return_if_fail(NM_IS_PPP_MANAGER(self));
+    nm_l3_config_data_seal(l3cd);
 
-    priv = NM_PPP_MANAGER_GET_PRIVATE(self);
-    if (priv->ip4_route_table != ip4_route_table || priv->ip4_route_metric != ip4_route_metric
-        || priv->ip6_route_table != ip6_route_table || priv->ip6_route_metric != ip6_route_metric) {
-        priv->ip4_route_table  = ip4_route_table;
-        priv->ip4_route_metric = ip4_route_metric;
-        priv->ip6_route_table  = ip6_route_table;
-        priv->ip6_route_metric = ip6_route_metric;
-
-        _LOGT("route-parameters: table-v4: %u, metric-v4: %u, table-v6: %u, metric-v6: %u",
-              priv->ip4_route_table,
-              priv->ip4_route_metric,
-              priv->ip6_route_table,
-              priv->ip6_route_metric);
-    }
+    g_signal_emit(self, signals[NEW_CONFIG], 0, addr_family, l3cd, iid);
 }
 
 /*****************************************************************************/
@@ -162,9 +164,9 @@ _ppp_manager_set_route_parameters(NMPPPManager *self,
 static gboolean
 monitor_cb(gpointer user_data)
 {
-    NMPPPManager *       self = NM_PPP_MANAGER(user_data);
+    NMPPPManager        *self = NM_PPP_MANAGER(user_data);
     NMPPPManagerPrivate *priv = NM_PPP_MANAGER_GET_PRIVATE(self);
-    const char *         ifname;
+    const char          *ifname;
     int                  errsv;
 
     ifname = nm_platform_link_get_name(NM_PLATFORM_GET, priv->ifindex);
@@ -172,7 +174,7 @@ monitor_cb(gpointer user_data)
     if (ifname) {
         struct ppp_stats stats = {};
         struct ifreq     req   = {
-            .ifr_data = (caddr_t) &stats,
+                  .ifr_data = (caddr_t) &stats,
         };
 
         nm_utils_ifname_cpy(req.ifr_name, ifname);
@@ -230,14 +232,14 @@ cancel_get_secrets(NMPPPManager *self)
 
 static gboolean
 extract_details_from_connection(NMConnection *connection,
-                                const char *  secrets_setting_name,
-                                const char ** username,
-                                const char ** password,
-                                GError **     error)
+                                const char   *secrets_setting_name,
+                                const char  **username,
+                                const char  **password,
+                                GError      **error)
 {
     NMSettingConnection *s_con;
-    NMSetting *          setting;
-    const char *         setting_name;
+    NMSetting           *setting;
+    const char          *setting_name;
 
     g_return_val_if_fail(connection != NULL, FALSE);
     g_return_val_if_fail(username != NULL, FALSE);
@@ -290,18 +292,18 @@ extract_details_from_connection(NMConnection *connection,
 }
 
 static void
-ppp_secrets_cb(NMActRequest *                req,
+ppp_secrets_cb(NMActRequest                 *req,
                NMActRequestGetSecretsCallId *call_id,
-               NMSettingsConnection *        settings_connection, /* unused (we pass NULL here) */
-               GError *                      error,
+               NMSettingsConnection         *settings_connection, /* unused (we pass NULL here) */
+               GError                       *error,
                gpointer                      user_data)
 {
-    NMPPPManager *       self     = NM_PPP_MANAGER(user_data);
+    NMPPPManager        *self     = NM_PPP_MANAGER(user_data);
     NMPPPManagerPrivate *priv     = NM_PPP_MANAGER_GET_PRIVATE(self);
-    const char *         username = NULL;
-    const char *         password = NULL;
-    GError *             local    = NULL;
-    NMConnection *       applied_connection;
+    const char          *username = NULL;
+    const char          *password = NULL;
+    GError              *local    = NULL;
+    NMConnection        *applied_connection;
 
     g_return_if_fail(priv->pending_secrets_context != NULL);
     g_return_if_fail(req == priv->act_req);
@@ -344,22 +346,22 @@ out:
 }
 
 static void
-impl_ppp_manager_need_secrets(NMDBusObject *                     obj,
+impl_ppp_manager_need_secrets(NMDBusObject                      *obj,
                               const NMDBusInterfaceInfoExtended *interface_info,
-                              const NMDBusMethodInfoExtended *   method_info,
-                              GDBusConnection *                  connection,
-                              const char *                       sender,
-                              GDBusMethodInvocation *            invocation,
-                              GVariant *                         parameters)
+                              const NMDBusMethodInfoExtended    *method_info,
+                              GDBusConnection                   *connection,
+                              const char                        *sender,
+                              GDBusMethodInvocation             *invocation,
+                              GVariant                          *parameters)
 {
-    NMPPPManager *       self = NM_PPP_MANAGER(obj);
-    NMPPPManagerPrivate *priv = NM_PPP_MANAGER_GET_PRIVATE(self);
-    NMConnection *       applied_connection;
-    const char *         username = NULL;
-    const char *         password = NULL;
-    guint32              tries;
+    NMPPPManager                *self = NM_PPP_MANAGER(obj);
+    NMPPPManagerPrivate         *priv = NM_PPP_MANAGER_GET_PRIVATE(self);
+    NMConnection                *applied_connection;
+    const char                  *username = NULL;
+    const char                  *password = NULL;
+    guint32                      tries;
     gs_unref_ptrarray GPtrArray *hints = NULL;
-    GError *                     error = NULL;
+    GError                      *error = NULL;
     NMSecretAgentGetSecretsFlags flags = NM_SECRET_AGENT_GET_SECRETS_FLAG_ALLOW_INTERACTION;
 
     nm_active_connection_clear_secrets(NM_ACTIVE_CONNECTION(priv->act_req));
@@ -410,35 +412,42 @@ impl_ppp_manager_need_secrets(NMDBusObject *                     obj,
 }
 
 static void
-impl_ppp_manager_set_state(NMDBusObject *                     obj,
+impl_ppp_manager_set_state(NMDBusObject                      *obj,
                            const NMDBusInterfaceInfoExtended *interface_info,
-                           const NMDBusMethodInfoExtended *   method_info,
-                           GDBusConnection *                  connection,
-                           const char *                       sender,
-                           GDBusMethodInvocation *            invocation,
-                           GVariant *                         parameters)
+                           const NMDBusMethodInfoExtended    *method_info,
+                           GDBusConnection                   *connection,
+                           const char                        *sender,
+                           GDBusMethodInvocation             *invocation,
+                           GVariant                          *parameters)
 {
     NMPPPManager *self = NM_PPP_MANAGER(obj);
-    guint32       state;
+    guint32       ppp_state;
 
-    g_variant_get(parameters, "(u)", &state);
-    g_signal_emit(self, signals[STATE_CHANGED], 0, (guint) state);
+    g_variant_get(parameters, "(u)", &ppp_state);
+
+    if (ppp_state >= NM_PPP_STATUS_INTERN_DEAD) {
+        /* we don't expect an intern state to be reported by the plugin. */
+        ppp_state = NM_PPP_STATUS_UNKNOWN;
+    }
+
+    g_signal_emit(self, signals[STATE_CHANGED], 0, (guint) ppp_state);
     g_dbus_method_invocation_return_value(invocation, NULL);
 }
 
 static void
-impl_ppp_manager_set_ifindex(NMDBusObject *                     obj,
+impl_ppp_manager_set_ifindex(NMDBusObject                      *obj,
                              const NMDBusInterfaceInfoExtended *interface_info,
-                             const NMDBusMethodInfoExtended *   method_info,
-                             GDBusConnection *                  connection,
-                             const char *                       sender,
-                             GDBusMethodInvocation *            invocation,
-                             GVariant *                         parameters)
+                             const NMDBusMethodInfoExtended    *method_info,
+                             GDBusConnection                   *connection,
+                             const char                        *sender,
+                             GDBusMethodInvocation             *invocation,
+                             GVariant                          *parameters)
 {
-    NMPPPManager *        self                     = NM_PPP_MANAGER(obj);
-    NMPPPManagerPrivate * priv                     = NM_PPP_MANAGER_GET_PRIVATE(self);
-    const NMPlatformLink *plink                    = NULL;
-    nm_auto_nmpobj const NMPObject *obj_keep_alive = NULL;
+    NMPPPManager                   *self            = NM_PPP_MANAGER(obj);
+    gs_unref_object NMPPPManager   *self_keep_alive = NULL;
+    NMPPPManagerPrivate            *priv            = NM_PPP_MANAGER_GET_PRIVATE(self);
+    const NMPlatformLink           *plink           = NULL;
+    nm_auto_nmpobj const NMPObject *obj_keep_alive  = NULL;
     gint32                          ifindex;
 
     g_variant_get(parameters, "(i)", &ifindex);
@@ -456,6 +465,10 @@ impl_ppp_manager_set_ifindex(NMDBusObject *                     obj,
     if (ifindex > 0) {
         plink = nm_platform_link_get(NM_PLATFORM_GET, ifindex);
         if (!plink) {
+            /* processing events has side-effects. We need to keep self alive
+             * during that.*/
+            self_keep_alive = g_object_ref(self);
+
             nm_platform_process_events(NM_PLATFORM_GET);
             plink = nm_platform_link_get(NM_PLATFORM_GET, ifindex);
         }
@@ -481,8 +494,8 @@ static gboolean
 set_ip_config_common(NMPPPManager *self, GVariant *config_dict, guint32 *out_mtu)
 {
     NMPPPManagerPrivate *priv = NM_PPP_MANAGER_GET_PRIVATE(self);
-    NMConnection *       applied_connection;
-    NMSettingPpp *       s_ppp;
+    NMConnection        *applied_connection;
+    NMSettingPpp        *s_ppp;
 
     if (priv->ifindex <= 0)
         return FALSE;
@@ -502,21 +515,21 @@ set_ip_config_common(NMPPPManager *self, GVariant *config_dict, guint32 *out_mtu
 }
 
 static void
-impl_ppp_manager_set_ip4_config(NMDBusObject *                     obj,
+impl_ppp_manager_set_ip4_config(NMDBusObject                      *obj,
                                 const NMDBusInterfaceInfoExtended *interface_info,
-                                const NMDBusMethodInfoExtended *   method_info,
-                                GDBusConnection *                  connection,
-                                const char *                       sender,
-                                GDBusMethodInvocation *            invocation,
-                                GVariant *                         parameters)
+                                const NMDBusMethodInfoExtended    *method_info,
+                                GDBusConnection                   *connection,
+                                const char                        *sender,
+                                GDBusMethodInvocation             *invocation,
+                                GVariant                          *parameters)
 {
-    NMPPPManager *       self           = NM_PPP_MANAGER(obj);
-    NMPPPManagerPrivate *priv           = NM_PPP_MANAGER_GET_PRIVATE(self);
-    gs_unref_object NMIP4Config *config = NULL;
-    NMPlatformIP4Address         address;
-    guint32                      u32, mtu;
-    GVariantIter *               iter;
-    gs_unref_variant GVariant *config_dict = NULL;
+    NMPPPManager                           *self = NM_PPP_MANAGER(obj);
+    NMPPPManagerPrivate                    *priv = NM_PPP_MANAGER_GET_PRIVATE(self);
+    nm_auto_unref_l3cd_init NML3ConfigData *l3cd = NULL;
+    NMPlatformIP4Address                    address;
+    guint32                                 u32, mtu;
+    GVariantIter                           *iter;
+    gs_unref_variant GVariant              *config_dict = NULL;
 
     _LOGI("(IPv4 Config Get) reply received.");
 
@@ -527,37 +540,41 @@ impl_ppp_manager_set_ip4_config(NMDBusObject *                     obj,
     if (!set_ip_config_common(self, config_dict, &mtu))
         goto out;
 
-    config = nm_ip4_config_new(nm_platform_get_multi_idx(NM_PLATFORM_GET), priv->ifindex);
+    l3cd = nm_l3_config_data_new(nm_platform_get_multi_idx(NM_PLATFORM_GET),
+                                 priv->ifindex,
+                                 NM_IP_CONFIG_SOURCE_PPP);
 
-    if (mtu)
-        nm_ip4_config_set_mtu(config, mtu, NM_IP_CONFIG_SOURCE_PPP);
+    nm_l3_config_data_set_mtu(l3cd, mtu);
 
-    memset(&address, 0, sizeof(address));
-    address.plen = 32;
+    address = (NMPlatformIP4Address){
+        .plen = 32,
+    };
 
     if (g_variant_lookup(config_dict, NM_PPP_IP4_CONFIG_ADDRESS, "u", &u32))
         address.address = u32;
 
+    if (g_variant_lookup(config_dict, NM_PPP_IP4_CONFIG_PREFIX, "u", &u32))
+        address.plen = u32;
+
     if (g_variant_lookup(config_dict, NM_PPP_IP4_CONFIG_GATEWAY, "u", &u32)) {
         const NMPlatformIP4Route r = {
             .ifindex       = priv->ifindex,
             .rt_source     = NM_IP_CONFIG_SOURCE_PPP,
             .gateway       = u32,
-            .table_coerced = nm_platform_route_table_coerce(priv->ip4_route_table),
-            .metric        = priv->ip4_route_metric,
+            .table_any     = TRUE,
+            .table_coerced = 0,
+            .metric_any    = TRUE,
+            .metric        = 0,
         };
 
-        nm_ip4_config_add_route(config, &r, NULL);
+        nm_l3_config_data_add_route_4(l3cd, &r);
         address.peer_address = u32;
     } else
         address.peer_address = address.address;
 
-    if (g_variant_lookup(config_dict, NM_PPP_IP4_CONFIG_PREFIX, "u", &u32))
-        address.plen = u32;
-
-    if (address.address && address.plen && address.plen <= 32) {
+    if (address.address && address.plen > 0 && address.plen <= 32) {
         address.addr_source = NM_IP_CONFIG_SOURCE_PPP;
-        nm_ip4_config_add_address(config, &address);
+        nm_l3_config_data_add_address_4(l3cd, &address);
     } else {
         _LOGE("invalid IPv4 address received!");
         goto out;
@@ -565,18 +582,17 @@ impl_ppp_manager_set_ip4_config(NMDBusObject *                     obj,
 
     if (g_variant_lookup(config_dict, NM_PPP_IP4_CONFIG_DNS, "au", &iter)) {
         while (g_variant_iter_next(iter, "u", &u32))
-            nm_ip4_config_add_nameserver(config, u32);
+            nm_l3_config_data_add_nameserver(l3cd, AF_INET, &u32);
         g_variant_iter_free(iter);
     }
 
     if (g_variant_lookup(config_dict, NM_PPP_IP4_CONFIG_WINS, "au", &iter)) {
         while (g_variant_iter_next(iter, "u", &u32))
-            nm_ip4_config_add_wins(config, u32);
+            nm_l3_config_data_add_wins(l3cd, u32);
         g_variant_iter_free(iter);
     }
 
-    /* Push the IP4 config up to the device */
-    g_signal_emit(self, signals[IP4_CONFIG], 0, config);
+    _emit_signal_new_config(self, AF_INET, l3cd, NULL);
 
 out:
     g_dbus_method_invocation_return_value(invocation, NULL);
@@ -586,9 +602,9 @@ out:
  * returns the IID.
  */
 static gboolean
-iid_value_to_ll6_addr(GVariant *          dict,
-                      const char *        prop,
-                      struct in6_addr *   out_addr,
+iid_value_to_ll6_addr(GVariant           *dict,
+                      const char         *prop,
+                      struct in6_addr    *out_addr,
                       NMUtilsIPv6IfaceId *out_iid)
 {
     guint64 iid;
@@ -612,22 +628,22 @@ iid_value_to_ll6_addr(GVariant *          dict,
 }
 
 static void
-impl_ppp_manager_set_ip6_config(NMDBusObject *                     obj,
+impl_ppp_manager_set_ip6_config(NMDBusObject                      *obj,
                                 const NMDBusInterfaceInfoExtended *interface_info,
-                                const NMDBusMethodInfoExtended *   method_info,
-                                GDBusConnection *                  connection,
-                                const char *                       sender,
-                                GDBusMethodInvocation *            invocation,
-                                GVariant *                         parameters)
+                                const NMDBusMethodInfoExtended    *method_info,
+                                GDBusConnection                   *connection,
+                                const char                        *sender,
+                                GDBusMethodInvocation             *invocation,
+                                GVariant                          *parameters)
 {
-    NMPPPManager *       self           = NM_PPP_MANAGER(obj);
-    NMPPPManagerPrivate *priv           = NM_PPP_MANAGER_GET_PRIVATE(self);
-    gs_unref_object NMIP6Config *config = NULL;
-    NMPlatformIP6Address         addr;
-    struct in6_addr              a;
-    NMUtilsIPv6IfaceId           iid       = NM_UTILS_IPV6_IFACE_ID_INIT;
-    gboolean                     has_peer  = FALSE;
-    gs_unref_variant GVariant *config_dict = NULL;
+    NMPPPManager                           *self = NM_PPP_MANAGER(obj);
+    NMPPPManagerPrivate                    *priv = NM_PPP_MANAGER_GET_PRIVATE(self);
+    nm_auto_unref_l3cd_init NML3ConfigData *l3cd = NULL;
+    NMPlatformIP6Address                    address;
+    struct in6_addr                         a;
+    NMUtilsIPv6IfaceId                      iid         = NM_UTILS_IPV6_IFACE_ID_INIT;
+    gboolean                                has_peer    = FALSE;
+    gs_unref_variant GVariant              *config_dict = NULL;
 
     _LOGI("(IPv6 Config Get) reply received.");
 
@@ -638,32 +654,37 @@ impl_ppp_manager_set_ip6_config(NMDBusObject *                     obj,
     if (!set_ip_config_common(self, config_dict, NULL))
         goto out;
 
-    config = nm_ip6_config_new(nm_platform_get_multi_idx(NM_PLATFORM_GET), priv->ifindex);
+    l3cd = nm_l3_config_data_new(nm_platform_get_multi_idx(NM_PLATFORM_GET),
+                                 priv->ifindex,
+                                 NM_IP_CONFIG_SOURCE_PPP);
 
-    memset(&addr, 0, sizeof(addr));
-    addr.plen = 64;
+    address = (NMPlatformIP6Address){
+        .plen        = 64,
+        .addr_source = NM_IP_CONFIG_SOURCE_PPP,
+    };
 
     if (iid_value_to_ll6_addr(config_dict, NM_PPP_IP6_CONFIG_PEER_IID, &a, NULL)) {
         const NMPlatformIP6Route r = {
             .ifindex       = priv->ifindex,
             .rt_source     = NM_IP_CONFIG_SOURCE_PPP,
             .gateway       = a,
-            .table_coerced = nm_platform_route_table_coerce(priv->ip6_route_table),
-            .metric        = priv->ip6_route_metric,
+            .table_any     = TRUE,
+            .table_coerced = 0,
+            .metric_any    = TRUE,
+            .metric        = 0,
         };
 
-        nm_ip6_config_add_route(config, &r, NULL);
-        addr.peer_address = a;
-        has_peer          = TRUE;
+        nm_l3_config_data_add_route_6(l3cd, &r);
+        address.peer_address = a;
+        has_peer             = TRUE;
     }
 
-    if (iid_value_to_ll6_addr(config_dict, NM_PPP_IP6_CONFIG_OUR_IID, &addr.address, &iid)) {
+    if (iid_value_to_ll6_addr(config_dict, NM_PPP_IP6_CONFIG_OUR_IID, &address.address, &iid)) {
         if (!has_peer)
-            addr.peer_address = addr.address;
-        nm_ip6_config_add_address(config, &addr);
+            address.peer_address = address.address;
+        nm_l3_config_data_add_address_6(l3cd, &address);
 
-        /* Push the IPv6 config and interface identifier up to the device */
-        g_signal_emit(self, signals[IP6_CONFIG], 0, &iid, config);
+        _emit_signal_new_config(self, AF_INET6, l3cd, &iid);
     } else
         _LOGE("invalid IPv6 address received!");
 
@@ -703,7 +724,7 @@ static NM_UTILS_LOOKUP_STR_DEFINE(
 static void
 ppp_watch_cb(GPid pid, int status, gpointer user_data)
 {
-    NMPPPManager *       self = NM_PPP_MANAGER(user_data);
+    NMPPPManager        *self = NM_PPP_MANAGER(user_data);
     NMPPPManagerPrivate *priv = NM_PPP_MANAGER_GET_PRIVATE(self);
     int                  err;
     const long long      lpid = (long long) pid;
@@ -726,7 +747,7 @@ ppp_watch_cb(GPid pid, int status, gpointer user_data)
     priv->pid          = 0;
     priv->ppp_watch_id = 0;
     _ppp_cleanup(self);
-    g_signal_emit(self, signals[STATE_CHANGED], 0, (guint) NM_PPP_STATUS_DEAD);
+    g_signal_emit(self, signals[STATE_CHANGED], 0, (guint) NM_PPP_STATUS_INTERN_DEAD);
 }
 
 static gboolean
@@ -734,28 +755,34 @@ pppd_timed_out(gpointer data)
 {
     NMPPPManager *self = NM_PPP_MANAGER(data);
 
+    /* FIXME(l3cfg): we should not use NMPPPManager directly, instead use
+     * NMPppMgr. That one already schedules a (better) timer. We don't need
+     * a timeout here anymore.
+     *
+     * At this moment, NMPPPManager is still used by NMModem. Once that changes,
+     * this timer needs to go. */
     _LOGW("pppd timed out or didn't initialize our dbus module");
     _ppp_manager_stop(self, NULL, NULL, NULL);
 
-    g_signal_emit(self, signals[STATE_CHANGED], 0, (guint) NM_PPP_STATUS_DEAD);
+    g_signal_emit(self, signals[STATE_CHANGED], 0, (guint) NM_PPP_STATUS_INTERN_DEAD);
 
     return FALSE;
 }
 
 static GPtrArray *
-create_pppd_cmd_line(NMPPPManager *  self,
-                     NMSettingPpp *  setting,
+create_pppd_cmd_line(NMPPPManager   *self,
+                     NMSettingPpp   *setting,
                      NMSettingPppoe *pppoe,
-                     NMSettingAdsl * adsl,
-                     const char *    ppp_name,
+                     NMSettingAdsl  *adsl,
+                     const char     *ppp_name,
                      guint           baud_override,
                      gboolean        ip4_enabled,
                      gboolean        ip6_enabled,
-                     GError **       err)
+                     GError        **err)
 {
-    NMPPPManagerPrivate *priv        = NM_PPP_MANAGER_GET_PRIVATE(self);
-    const char *         pppd_binary = NULL;
-    gs_unref_ptrarray GPtrArray *cmd = NULL;
+    NMPPPManagerPrivate         *priv        = NM_PPP_MANAGER_GET_PRIVATE(self);
+    const char                  *pppd_binary = NULL;
+    gs_unref_ptrarray GPtrArray *cmd         = NULL;
     gboolean                     ppp_debug;
 
     g_return_val_if_fail(setting != NULL, NULL);
@@ -961,23 +988,22 @@ pppoe_fill_defaults(NMSettingPpp *setting)
 static gboolean
 _ppp_manager_start(NMPPPManager *self,
                    NMActRequest *req,
-                   const char *  ppp_name,
+                   const char   *ppp_name,
                    guint32       timeout_secs,
                    guint         baud_override,
-                   GError **     err)
+                   GError      **err)
 {
-    NMPPPManagerPrivate *priv;
-    NMConnection *       connection;
-    NMSettingPpp *       s_ppp;
+    NMPPPManagerPrivate          *priv;
+    NMConnection                 *connection;
+    NMSettingPpp                 *s_ppp;
     gs_unref_object NMSettingPpp *s_ppp_free = NULL;
-    NMSettingPppoe *              pppoe_setting;
-    NMSettingAdsl *               adsl_setting;
-    gs_unref_ptrarray GPtrArray *ppp_cmd = NULL;
-    gs_free char *               cmd_str = NULL;
-    struct stat                  st;
-    const char *                 ip6_method, *ip4_method;
-    gboolean                     ip6_enabled = FALSE;
-    gboolean                     ip4_enabled = FALSE;
+    NMSettingPppoe               *pppoe_setting;
+    NMSettingAdsl                *adsl_setting;
+    gs_unref_ptrarray GPtrArray  *ppp_cmd = NULL;
+    gs_free char                 *cmd_str = NULL;
+    struct stat                   st;
+    gboolean                      ip6_enabled;
+    gboolean                      ip4_enabled;
 
     g_return_val_if_fail(NM_IS_PPP_MANAGER(self), FALSE);
     g_return_val_if_fail(NM_IS_ACT_REQUEST(req), FALSE);
@@ -1022,11 +1048,7 @@ _ppp_manager_start(NMPPPManager *self,
 
     adsl_setting = (NMSettingAdsl *) nm_connection_get_setting(connection, NM_TYPE_SETTING_ADSL);
 
-    /* Figure out what address methods should be enabled */
-    ip4_method  = nm_utils_get_ip_config_method(connection, AF_INET);
-    ip4_enabled = nm_streq(ip4_method, NM_SETTING_IP4_CONFIG_METHOD_AUTO);
-    ip6_method  = nm_utils_get_ip_config_method(connection, AF_INET6);
-    ip6_enabled = nm_streq(ip6_method, NM_SETTING_IP6_CONFIG_METHOD_AUTO);
+    nm_utils_ppp_ip_methods_enabled(connection, &ip4_enabled, &ip6_enabled);
 
     ppp_cmd = create_pppd_cmd_line(self,
                                    s_ppp,
@@ -1059,9 +1081,10 @@ _ppp_manager_start(NMPPPManager *self,
 
     _LOGI("pppd started with pid %lld", (long long) priv->pid);
 
-    priv->ppp_watch_id        = g_child_watch_add(priv->pid, (GChildWatchFunc) ppp_watch_cb, self);
-    priv->ppp_timeout_handler = g_timeout_add_seconds(timeout_secs, pppd_timed_out, self);
-    priv->act_req             = g_object_ref(req);
+    priv->ppp_watch_id = g_child_watch_add(priv->pid, (GChildWatchFunc) ppp_watch_cb, self);
+    if (timeout_secs > 0)
+        priv->ppp_timeout_handler = g_timeout_add_seconds(timeout_secs, pppd_timed_out, self);
+    priv->act_req = g_object_ref(req);
 
     return TRUE;
 fail:
@@ -1096,7 +1119,7 @@ _ppp_cleanup(NMPPPManager *self)
 /*****************************************************************************/
 
 struct _NMPPPManagerStopHandle {
-    NMPPPManager *           self;
+    NMPPPManager            *self;
     NMPPPManagerStopCallback callback;
     gpointer                 user_data;
 
@@ -1170,13 +1193,13 @@ _stop_cancelled_cb(GCancellable *cancellable, gpointer user_data)
 }
 
 static NMPPPManagerStopHandle *
-_ppp_manager_stop(NMPPPManager *           self,
-                  GCancellable *           cancellable,
+_ppp_manager_stop(NMPPPManager            *self,
+                  GCancellable            *cancellable,
                   NMPPPManagerStopCallback callback,
                   gpointer                 user_data)
 {
-    NMPPPManagerPrivate *   priv = NM_PPP_MANAGER_GET_PRIVATE(self);
-    NMDBusObject *          dbus = NM_DBUS_OBJECT(self);
+    NMPPPManagerPrivate    *priv = NM_PPP_MANAGER_GET_PRIVATE(self);
+    NMDBusObject           *dbus = NM_DBUS_OBJECT(self);
     NMPPPManagerStopHandle *handle;
 
     if (nm_dbus_object_is_exported(dbus))
@@ -1290,12 +1313,8 @@ nm_ppp_manager_init(NMPPPManager *self)
 {
     NMPPPManagerPrivate *priv = NM_PPP_MANAGER_GET_PRIVATE(self);
 
-    priv->ifindex          = -1;
-    priv->monitor_fd       = -1;
-    priv->ip4_route_table  = RT_TABLE_MAIN;
-    priv->ip4_route_metric = 460;
-    priv->ip6_route_table  = RT_TABLE_MAIN;
-    priv->ip6_route_metric = 460;
+    priv->ifindex    = -1;
+    priv->monitor_fd = -1;
 }
 
 static NMPPPManager *
@@ -1309,7 +1328,7 @@ _ppp_manager_new(const char *iface)
 static void
 dispose(GObject *object)
 {
-    NMPPPManager *       self = (NMPPPManager *) object;
+    NMPPPManager        *self = (NMPPPManager *) object;
     NMPPPManagerPrivate *priv = NM_PPP_MANAGER_GET_PRIVATE(self);
 
     /* we expect the user to first stop the manager. As fallback,
@@ -1371,7 +1390,7 @@ static const NMDBusInterfaceInfoExtended interface_info_ppp = {
 static void
 nm_ppp_manager_class_init(NMPPPManagerClass *manager_class)
 {
-    GObjectClass *     object_class      = G_OBJECT_CLASS(manager_class);
+    GObjectClass      *object_class      = G_OBJECT_CLASS(manager_class);
     NMDBusObjectClass *dbus_object_class = NM_DBUS_OBJECT_CLASS(manager_class);
 
     object_class->dispose      = dispose;
@@ -1400,7 +1419,7 @@ nm_ppp_manager_class_init(NMPPPManagerClass *manager_class)
                                           NULL,
                                           G_TYPE_NONE,
                                           1,
-                                          G_TYPE_UINT);
+                                          G_TYPE_UINT /* ppp_state */);
 
     signals[IFINDEX_SET] = g_signal_new(NM_PPP_MANAGER_SIGNAL_IFINDEX_SET,
                                         G_OBJECT_CLASS_TYPE(object_class),
@@ -1411,21 +1430,10 @@ nm_ppp_manager_class_init(NMPPPManagerClass *manager_class)
                                         NULL,
                                         G_TYPE_NONE,
                                         2,
-                                        G_TYPE_INT,
-                                        G_TYPE_STRING);
-
-    signals[IP4_CONFIG] = g_signal_new(NM_PPP_MANAGER_SIGNAL_IP4_CONFIG,
-                                       G_OBJECT_CLASS_TYPE(object_class),
-                                       G_SIGNAL_RUN_FIRST,
-                                       0,
-                                       NULL,
-                                       NULL,
-                                       NULL,
-                                       G_TYPE_NONE,
-                                       1,
-                                       G_TYPE_OBJECT);
+                                        G_TYPE_INT /* ifindex */,
+                                        G_TYPE_STRING /* ifname */);
 
-    signals[IP6_CONFIG] = g_signal_new(NM_PPP_MANAGER_SIGNAL_IP6_CONFIG,
+    signals[NEW_CONFIG] = g_signal_new(NM_PPP_MANAGER_SIGNAL_NEW_CONFIG,
                                        G_OBJECT_CLASS_TYPE(object_class),
                                        G_SIGNAL_RUN_FIRST,
                                        0,
@@ -1433,9 +1441,10 @@ nm_ppp_manager_class_init(NMPPPManagerClass *manager_class)
                                        NULL,
                                        NULL,
                                        G_TYPE_NONE,
-                                       2,
-                                       G_TYPE_POINTER,
-                                       G_TYPE_OBJECT);
+                                       3,
+                                       G_TYPE_INT,      /* addr_family */
+                                       G_TYPE_POINTER,  /* (const NML3ConfigData *) */
+                                       G_TYPE_POINTER); /* (const NMUtilsIPv6IfaceId *) */
 
     signals[STATS] = g_signal_new(NM_PPP_MANAGER_SIGNAL_STATS,
                                   G_OBJECT_CLASS_TYPE(object_class),
@@ -1451,9 +1460,8 @@ nm_ppp_manager_class_init(NMPPPManagerClass *manager_class)
 }
 
 const NMPPPOps ppp_ops = {
-    .create               = _ppp_manager_new,
-    .set_route_parameters = _ppp_manager_set_route_parameters,
-    .start                = _ppp_manager_start,
-    .stop                 = _ppp_manager_stop,
-    .stop_cancel          = _ppp_manager_stop_cancel,
+    .create      = _ppp_manager_new,
+    .start       = _ppp_manager_start,
+    .stop        = _ppp_manager_stop,
+    .stop_cancel = _ppp_manager_stop_cancel,
 };
diff --git a/src/core/ppp/nm-ppp-manager.h b/src/core/ppp/nm-ppp-manager.h
index c41dda20..21ea3715 100644
--- a/src/core/ppp/nm-ppp-manager.h
+++ b/src/core/ppp/nm-ppp-manager.h
@@ -11,15 +11,14 @@
 
 #define NM_PPP_MANAGER_SIGNAL_STATE_CHANGED "state-changed"
 #define NM_PPP_MANAGER_SIGNAL_IFINDEX_SET   "ifindex-set"
-#define NM_PPP_MANAGER_SIGNAL_IP4_CONFIG    "ip4-config"
-#define NM_PPP_MANAGER_SIGNAL_IP6_CONFIG    "ip6-config"
+#define NM_PPP_MANAGER_SIGNAL_NEW_CONFIG    "new-config"
 #define NM_PPP_MANAGER_SIGNAL_STATS         "stats"
 
 typedef struct _NMPPPManager NMPPPManager;
 
 typedef struct _NMPPPManagerStopHandle NMPPPManagerStopHandle;
 
-typedef void (*NMPPPManagerStopCallback)(NMPPPManager *          manager,
+typedef void (*NMPPPManagerStopCallback)(NMPPPManager           *manager,
                                          NMPPPManagerStopHandle *handle,
                                          gboolean                was_cancelled,
                                          gpointer                user_data);
diff --git a/src/core/ppp/nm-ppp-mgr.c b/src/core/ppp/nm-ppp-mgr.c
new file mode 100644
index 00000000..31c173a3
--- /dev/null
+++ b/src/core/ppp/nm-ppp-mgr.c
@@ -0,0 +1,620 @@
+/* SPDX-License-Identifier: GPL-2.0-or-later */
+
+#include "src/core/nm-default-daemon.h"
+
+#include "nm-ppp-mgr.h"
+
+#include <net/if.h>
+
+#include "NetworkManagerUtils.h"
+#include "devices/nm-device-utils.h"
+#include "nm-act-request.h"
+#include "nm-netns.h"
+#include "nm-ppp-manager-call.h"
+#include "nm-ppp-status.h"
+
+/*****************************************************************************/
+
+struct _NMPppMgr {
+    NMPppMgrConfig config;
+    NMPPPManager  *ppp_manager;
+    GSource       *idle_start;
+    GSource       *connect_timeout_source;
+    union {
+        struct {
+            NMPppMgrIPData ip_data_6;
+            NMPppMgrIPData ip_data_4;
+        };
+        NMPppMgrIPData ip_data_x[2];
+    };
+    int                ifindex;
+    NMPppMgrStatsData  stats_data;
+    NMPppMgrState      state;
+    NMUtilsIPv6IfaceId ipv6_iid;
+    bool               ppp_started : 1;
+};
+
+/*****************************************************************************/
+
+#define _NMLOG_DOMAIN      LOGD_PPP
+#define _NMLOG_PREFIX_NAME "ppp-mgr"
+#define _NMLOG(level, ...) \
+    __NMLOG_DEFAULT_WITH_ADDR(level, _NMLOG_DOMAIN, _NMLOG_PREFIX_NAME, __VA_ARGS__)
+
+/*****************************************************************************/
+
+NM_UTILS_LOOKUP_STR_DEFINE(
+    nm_ppp_mgr_state_to_string,
+    NMPppMgrState,
+    NM_UTILS_LOOKUP_DEFAULT_WARN("???"),
+    NM_UTILS_LOOKUP_STR_ITEM(NM_PPP_MGR_STATE_STARTING, "starting"),
+    NM_UTILS_LOOKUP_STR_ITEM(NM_PPP_MGR_STATE_WAITING_FOR_IFINDEX, "waiting-for-ifindex"),
+    NM_UTILS_LOOKUP_STR_ITEM(NM_PPP_MGR_STATE_HAVE_IFINDEX, "have-ifindex"),
+    NM_UTILS_LOOKUP_STR_ITEM(NM_PPP_MGR_STATE_HAVE_IP_CONFIG, "have-ip-config"),
+    NM_UTILS_LOOKUP_STR_ITEM(NM_PPP_MGR_STATE_FAILED_TO_START, "failed-to-start"),
+    NM_UTILS_LOOKUP_STR_ITEM(NM_PPP_MGR_STATE_FAILED_TO_IFINDEX, "failed-to-ifindex"),
+    NM_UTILS_LOOKUP_STR_ITEM(NM_PPP_MGR_STATE_FAILED, "failed"));
+
+NM_UTILS_LOOKUP_STR_DEFINE(nm_ppp_mgr_callback_type_to_string,
+                           NMPppMgrCallbackType,
+                           NM_UTILS_LOOKUP_DEFAULT_WARN("???"),
+                           NM_UTILS_LOOKUP_STR_ITEM(NM_PPP_MGR_CALLBACK_TYPE_STATE_CHANGED,
+                                                    "state-changed"),
+                           NM_UTILS_LOOKUP_STR_ITEM(NM_PPP_MGR_CALLBACK_TYPE_STATS_CHANGED,
+                                                    "stats-changed"));
+
+/*****************************************************************************/
+
+#define SELF_TO_USERDATA(self) (&(self)->idle_start)
+
+#define SELF_FROM_USERDATA(user_data) \
+    ((NMPppMgr *) (((const char *) (user_data)) - G_STRUCT_OFFSET(NMPppMgr, idle_start)))
+
+/*****************************************************************************/
+
+gboolean
+_nm_assert_is_ppp_mgr(const NMPppMgr *self)
+{
+    nm_assert(G_IS_OBJECT(self->ppp_manager));
+    nm_assert(NM_IS_NETNS(self->config.netns));
+    nm_assert(self->config.parent_iface);
+
+    return TRUE;
+}
+
+/*****************************************************************************/
+
+static void
+_callback_emit_with_data(NMPppMgr *self, const NMPppMgrCallbackData *callback_data)
+{
+    char sbuf_int[30];
+
+    switch (callback_data->callback_type) {
+    case NM_PPP_MGR_CALLBACK_TYPE_STATE_CHANGED:
+        _LOGT("emit signal: %s, state=%s%s%s%s%s, reason=%s",
+              nm_ppp_mgr_callback_type_to_string(callback_data->callback_type),
+              nm_ppp_mgr_state_to_string(callback_data->data.state),
+              NM_PRINT_FMT_QUOTED2(callback_data->data.state != callback_data->data.old_state,
+                                   ", old-state=",
+                                   nm_ppp_mgr_state_to_string(callback_data->data.old_state),
+                                   ""),
+              NM_PRINT_FMT_QUOTED2(callback_data->data.ifindex > 0,
+                                   ", ifindex=",
+                                   nm_sprintf_buf(sbuf_int, "%d", callback_data->data.ifindex),
+                                   ""),
+              callback_data->data.reason_msg);
+        break;
+    case NM_PPP_MGR_CALLBACK_TYPE_STATS_CHANGED:
+        /* This signal might be emitted every 5 seconds. It's too verbose for logging.
+         * Be silent. */
+        break;
+    default:
+        nm_assert_not_reached();
+    }
+
+    self->config.callback(self, callback_data, self->config.user_data);
+}
+
+static void
+_callback_emit_state_change(NMPppMgr            *self,
+                            NMPppMgrCallbackType callback_type,
+                            NMPppMgrState        old_state,
+                            gboolean             ip_changed_4,
+                            gboolean             ip_changed_6,
+                            NMDeviceStateReason  reason,
+                            const char          *reason_msg)
+{
+    const NMPppMgrCallbackData callback_data = {
+        .callback_type = callback_type,
+        .data =
+            {
+                .old_state    = old_state,
+                .state        = self->state,
+                .ifindex      = self->ifindex,
+                .reason       = reason,
+                .reason_msg   = reason_msg,
+                .ip_data_4    = &self->ip_data_4,
+                .ip_data_6    = &self->ip_data_6,
+                .stats_data   = &self->stats_data,
+                .ip_changed_4 = ip_changed_4,
+                .ip_changed_6 = ip_changed_6,
+            },
+    };
+
+    _callback_emit_with_data(self, &callback_data);
+}
+
+/*****************************************************************************/
+
+NMPppMgrState
+nm_ppp_mgr_get_state(const NMPppMgr *self)
+{
+    g_return_val_if_fail(NM_IS_PPP_MGR(self), NM_PPP_MGR_STATE_FAILED);
+
+    return self->state;
+}
+
+int
+nm_ppp_mgr_get_ifindex(const NMPppMgr *self)
+{
+    g_return_val_if_fail(NM_IS_PPP_MGR(self), 0);
+
+    return self->ifindex;
+}
+
+const NMPppMgrIPData *
+nm_ppp_mgr_get_ip_data(const NMPppMgr *self, int addr_family)
+{
+    const int IS_IPv4 = NM_IS_IPv4(addr_family);
+
+    g_return_val_if_fail(NM_IS_PPP_MGR(self), NULL);
+
+    return &self->ip_data_x[IS_IPv4];
+}
+
+const NMPppMgrStatsData *
+nm_ppp_mgr_get_stats(const NMPppMgr *self)
+{
+    g_return_val_if_fail(NM_IS_PPP_MGR(self), NULL);
+
+    return &self->stats_data;
+}
+
+/*****************************************************************************/
+
+static void
+_set_state(NMPppMgr *self, NMPppMgrState state, NMPppMgrState *out_old_state)
+{
+    if (state >= NM_PPP_MGR_STATE_HAVE_IP_CONFIG)
+        nm_clear_g_source_inst(&self->connect_timeout_source);
+
+    NM_SET_OUT(out_old_state, self->state);
+    if (self->state != state) {
+        _LOGT("set state: %s (was %s)",
+              nm_ppp_mgr_state_to_string(state),
+              nm_ppp_mgr_state_to_string(self->state));
+        self->state = state;
+    }
+}
+
+static void
+_set_state_failed(NMPppMgr *self, NMPppMgrState state, NMPppMgrState *out_old_state)
+{
+    nm_assert(state >= _NM_PPP_MGR_STATE_FAILED_START);
+    nm_assert(self->state < _NM_PPP_MGR_STATE_FAILED_START);
+
+    _set_state(self, state, out_old_state);
+
+    self->ifindex = 0;
+    nm_clear_l3cd(&self->ip_data_4.l3cd);
+    nm_clear_l3cd(&self->ip_data_6.l3cd);
+    self->ip_data_4 = (NMPppMgrIPData){
+        .ip_received = FALSE,
+        .ip_enabled  = FALSE,
+    };
+    self->ip_data_6 = (NMPppMgrIPData){
+        .ip_received = FALSE,
+        .ip_enabled  = FALSE,
+    };
+
+    if (self->ppp_manager) {
+        g_signal_handlers_disconnect_by_data(self->ppp_manager, SELF_TO_USERDATA(self));
+        if (self->ppp_started) {
+            self->ppp_started = FALSE;
+            nm_ppp_manager_stop(self->ppp_manager, NULL, NULL, NULL);
+        }
+        g_object_unref(self->ppp_manager);
+    }
+}
+
+static gboolean
+_state_ready_for_have_ifindex(NMPppMgr *self)
+{
+    if (self->ip_data_4.ip_received) {
+        /* once we receive an IPv4 config, we consider this as ready.
+         *
+         * The problem is that we don't know when we can expect an IPv6 config
+         * too, so we cannot just keep waiting. I don't know how to solve this, but
+         * it means IPv4+IPv6 together doesn't work well (because we would not
+         * wait for IPv6, once IPv4 config is received. */
+        return TRUE;
+    }
+
+    return ((!self->ip_data_4.ip_enabled || self->ip_data_4.ip_received)
+            && (!self->ip_data_6.ip_enabled || self->ip_data_6.ip_received));
+}
+
+/*****************************************************************************/
+
+static void
+_ppp_signal_state_changed(NMPPPManager *ppp_manager, guint ppp_state_u, gpointer user_data)
+{
+    NMPppMgr           *self      = SELF_FROM_USERDATA(user_data);
+    NMPPPStatus         ppp_state = ppp_state_u;
+    NMPppMgrState       state;
+    NMPppMgrState       old_state;
+    NMDeviceStateReason reason;
+    const char         *reason_msg;
+
+    if ((guint) ppp_state != ppp_state_u)
+        ppp_state = NM_PPP_STATUS_UNKNOWN;
+
+    switch (ppp_state) {
+    case NM_PPP_STATUS_DISCONNECT:
+        state      = NM_PPP_MGR_STATE_FAILED;
+        reason     = NM_DEVICE_STATE_REASON_PPP_DISCONNECT;
+        reason_msg = "ppp signals disconnect";
+        break;
+    case NM_PPP_STATUS_DEAD:
+    case NM_PPP_STATUS_INTERN_DEAD:
+        state      = NM_PPP_MGR_STATE_FAILED;
+        reason     = NM_DEVICE_STATE_REASON_PPP_FAILED;
+        reason_msg = "ppp signals disconnect";
+        break;
+    default:
+        _LOGT("ppp signal about state changed: #%u signal (ignored)", ppp_state_u);
+        return;
+    }
+
+    _LOGT("ppp signal about state changed: #%u signal, new-state %s, state-reason=%s, %s",
+          ppp_state_u,
+          nm_ppp_mgr_state_to_string(state),
+          nm_device_state_reason_to_string(reason),
+          reason_msg);
+
+    _set_state_failed(self, state, &old_state);
+    _callback_emit_state_change(self,
+                                NM_PPP_MGR_CALLBACK_TYPE_STATE_CHANGED,
+                                old_state,
+                                FALSE,
+                                FALSE,
+                                reason,
+                                reason_msg);
+}
+
+static void
+_ppp_signal_ifindex_set(NMPPPManager *ppp_manager,
+                        int           ifindex,
+                        const char   *ifname,
+                        gpointer      user_data)
+{
+    NMPppMgr     *self = SELF_FROM_USERDATA(user_data);
+    NMPppMgrState old_state;
+    NMPppMgrState new_state;
+    gboolean      ip_changed_4;
+    gboolean      ip_changed_6;
+
+    if (ifindex <= 0) {
+        nm_assert(self->state == NM_PPP_MGR_STATE_WAITING_FOR_IFINDEX);
+        _LOGT("ifindex set: invalid ifindex received");
+        _set_state_failed(self, NM_PPP_MGR_STATE_FAILED_TO_IFINDEX, &old_state);
+        _callback_emit_state_change(self,
+                                    NM_PPP_MGR_CALLBACK_TYPE_STATE_CHANGED,
+                                    old_state,
+                                    FALSE,
+                                    FALSE,
+                                    NM_DEVICE_STATE_REASON_PPP_FAILED,
+                                    "invalid ifindex provided by ppp plugin");
+        return;
+    }
+
+    if (self->ifindex > 0) {
+        nm_assert(self->state > NM_PPP_MGR_STATE_WAITING_FOR_IFINDEX);
+        nm_assert(self->state < _NM_PPP_MGR_STATE_FAILED_START);
+
+        _LOGT("ifindex set: ignore ifindex %d, already set to %d", ifindex, self->ifindex);
+        return;
+    }
+
+    nm_assert(self->state == NM_PPP_MGR_STATE_WAITING_FOR_IFINDEX);
+    self->ifindex = ifindex;
+
+    if (_state_ready_for_have_ifindex(self)) {
+        new_state    = NM_PPP_MGR_STATE_HAVE_IP_CONFIG;
+        ip_changed_4 = self->ip_data_4.ip_received;
+        ip_changed_6 = self->ip_data_6.ip_received;
+    } else {
+        new_state    = NM_PPP_MGR_STATE_HAVE_IFINDEX;
+        ip_changed_4 = FALSE;
+        ip_changed_6 = FALSE;
+    }
+
+    _LOGT("ifindex set: ifindex %d", ifindex);
+
+    _set_state(self, new_state, &old_state);
+    _callback_emit_state_change(self,
+                                NM_PPP_MGR_CALLBACK_TYPE_STATE_CHANGED,
+                                old_state,
+                                ip_changed_4,
+                                ip_changed_6,
+                                NM_DEVICE_STATE_REASON_PPP_FAILED,
+                                "invalid ifindex provided by ppp plugin");
+}
+
+static void
+_ppp_signal_new_config(NMPPPManager             *ppp_manager,
+                       int                       addr_family,
+                       const NML3ConfigData     *l3cd,
+                       const NMUtilsIPv6IfaceId *iid,
+                       gpointer                  user_data)
+{
+    NMPppMgr     *self    = SELF_FROM_USERDATA(user_data);
+    const int     IS_IPv4 = NM_IS_IPv4(addr_family);
+    NMPppMgrState old_state;
+    gboolean      ip_changed_4;
+    gboolean      ip_changed_6;
+
+    nm_assert(self->state >= NM_PPP_MGR_STATE_WAITING_FOR_IFINDEX);
+    nm_assert(self->state < _NM_PPP_MGR_STATE_FAILED_START);
+
+    if (nm_l3_config_data_equal(self->ip_data_x[IS_IPv4].l3cd, l3cd))
+        l3cd = self->ip_data_x[IS_IPv4].l3cd;
+
+    nm_l3_config_data_reset(&self->ip_data_x[IS_IPv4].l3cd, l3cd);
+    if (!IS_IPv4) {
+        if (iid)
+            self->ipv6_iid = *iid;
+        else
+            self->ipv6_iid = (NMUtilsIPv6IfaceId) NM_UTILS_IPV6_IFACE_ID_INIT;
+        self->ip_data_6.ipv6_iid =
+            nm_utils_memeqzero(&self->ipv6_iid, sizeof(self->ipv6_iid)) ? NULL : &self->ipv6_iid;
+    }
+    self->ip_data_x[IS_IPv4].ip_received = TRUE;
+
+    if (self->state == NM_PPP_MGR_STATE_WAITING_FOR_IFINDEX) {
+        /* we still wait for the ifindex. We just cache the IP configuration,
+         * but leave the state unchanged. */
+        _LOGT("ip-config v%c received (still waiting for ifindex)",
+              nm_utils_addr_family_to_char(addr_family));
+        old_state = NM_PPP_MGR_STATE_WAITING_FOR_IFINDEX;
+    } else {
+        NMPppMgrState new_state;
+
+        _LOGT("ip-config v%c received", nm_utils_addr_family_to_char(addr_family));
+        new_state = _state_ready_for_have_ifindex(self) ? NM_PPP_MGR_STATE_HAVE_IP_CONFIG
+                                                        : NM_PPP_MGR_STATE_HAVE_IFINDEX;
+        nm_assert((self->state == NM_PPP_MGR_STATE_HAVE_IFINDEX)
+                  || (self->state == NM_PPP_MGR_STATE_HAVE_IP_CONFIG
+                      && new_state == NM_PPP_MGR_STATE_HAVE_IP_CONFIG));
+        _set_state(self, new_state, &old_state);
+    }
+
+    ip_changed_4 = IS_IPv4;
+    ip_changed_6 = !IS_IPv4;
+
+    _callback_emit_state_change(self,
+                                NM_PPP_MGR_CALLBACK_TYPE_STATE_CHANGED,
+                                old_state,
+                                ip_changed_4,
+                                ip_changed_6,
+                                NM_DEVICE_STATE_REASON_NONE,
+                                "ip config received");
+}
+
+static void
+_ppp_signal_stats(NMPPPManager *ppp_manager, guint in_bytes, guint out_bytes, gpointer user_data)
+{
+    NMPppMgr *self = SELF_FROM_USERDATA(user_data);
+
+    if (self->stats_data.in_bytes == in_bytes && self->stats_data.out_bytes == out_bytes)
+        return;
+
+    self->stats_data.in_bytes  = in_bytes;
+    self->stats_data.out_bytes = out_bytes;
+
+    _callback_emit_state_change(self,
+                                NM_PPP_MGR_CALLBACK_TYPE_STATS_CHANGED,
+                                self->state,
+                                FALSE,
+                                FALSE,
+                                NM_DEVICE_STATE_REASON_NONE,
+                                "stats update");
+}
+
+/*****************************************************************************/
+
+static gboolean
+_ifindex_timeout_cb(gpointer user_data)
+{
+    NMPppMgr     *self = user_data;
+    NMPppMgrState old_state;
+
+    nm_clear_g_source_inst(&self->connect_timeout_source);
+
+    _set_state_failed(self, NM_PPP_MGR_STATE_FAILED_TO_IFINDEX, &old_state);
+    _callback_emit_state_change(self,
+                                NM_PPP_MGR_CALLBACK_TYPE_STATE_CHANGED,
+                                old_state,
+                                FALSE,
+                                FALSE,
+                                NM_DEVICE_STATE_REASON_PPP_FAILED,
+                                "timeout connecting");
+    return G_SOURCE_CONTINUE;
+}
+
+/*****************************************************************************/
+
+static gboolean
+_idle_start_cb(gpointer user_data)
+{
+    NMPppMgr             *self  = user_data;
+    gs_free_error GError *error = NULL;
+    NMPppMgrState         old_state;
+    gboolean              ip4_enabled;
+    gboolean              ip6_enabled;
+    NMPlatform           *platform;
+    const NMPlatformLink *plink;
+
+    nm_clear_g_source_inst(&self->idle_start);
+
+    /* We only evaluate ipx_enabled here. That is because nm_ppp_manager_start()
+     * will evaluate it based on act_req's applied connection (like we do now),
+     * but as the applied connection can be reapplied, let's do it at the
+     * same time to be sure we agree.
+     *
+     * This should be nicer solved by NMPPPManager not accessing the NMConnection
+     * or make little/no use of NMActRequest. */
+    nm_utils_ppp_ip_methods_enabled(nm_act_request_get_applied_connection(self->config.act_req),
+                                    &ip4_enabled,
+                                    &ip6_enabled);
+    self->ip_data_4.ip_enabled = !!ip4_enabled;
+    self->ip_data_6.ip_enabled = !!ip6_enabled;
+
+    g_signal_connect(self->ppp_manager,
+                     NM_PPP_MANAGER_SIGNAL_STATE_CHANGED,
+                     G_CALLBACK(_ppp_signal_state_changed),
+                     SELF_TO_USERDATA(self));
+    g_signal_connect(self->ppp_manager,
+                     NM_PPP_MANAGER_SIGNAL_IFINDEX_SET,
+                     G_CALLBACK(_ppp_signal_ifindex_set),
+                     SELF_TO_USERDATA(self));
+    g_signal_connect(self->ppp_manager,
+                     NM_PPP_MANAGER_SIGNAL_NEW_CONFIG,
+                     G_CALLBACK(_ppp_signal_new_config),
+                     SELF_TO_USERDATA(self));
+    g_signal_connect(self->ppp_manager,
+                     NM_PPP_MANAGER_SIGNAL_STATS,
+                     G_CALLBACK(_ppp_signal_stats),
+                     SELF_TO_USERDATA(self));
+
+    platform = nm_netns_get_platform(self->config.netns);
+    plink    = nm_platform_link_get_by_ifname(platform, self->config.parent_iface);
+    if (plink && !NM_FLAGS_HAS(plink->n_ifi_flags, IFF_UP)) {
+        nm_platform_link_change_flags(platform, plink->ifindex, IFF_UP, TRUE);
+    }
+
+    self->ppp_started = TRUE;
+    if (!nm_ppp_manager_start(self->ppp_manager,
+                              self->config.act_req,
+                              self->config.ppp_username,
+                              0,
+                              self->config.baud_override,
+                              &error)) {
+        gs_free char *reason_msg = NULL;
+
+        _set_state_failed(self, NM_PPP_MGR_STATE_FAILED_TO_START, &old_state);
+        reason_msg = g_strdup_printf("failed to start: %s", error->message);
+        _callback_emit_state_change(self,
+                                    NM_PPP_MGR_CALLBACK_TYPE_STATE_CHANGED,
+                                    old_state,
+                                    FALSE,
+                                    FALSE,
+                                    NM_DEVICE_STATE_REASON_PPP_START_FAILED,
+                                    reason_msg);
+        return G_SOURCE_CONTINUE;
+    }
+
+    nm_assert(self->state == NM_PPP_MGR_STATE_STARTING);
+    _set_state(self, NM_PPP_MGR_STATE_WAITING_FOR_IFINDEX, &old_state);
+
+    self->connect_timeout_source =
+        nm_g_timeout_add_seconds_source(self->config.timeout_secs, _ifindex_timeout_cb, self);
+
+    _callback_emit_state_change(self,
+                                NM_PPP_MGR_CALLBACK_TYPE_STATE_CHANGED,
+                                old_state,
+                                FALSE,
+                                FALSE,
+                                NM_DEVICE_STATE_REASON_NONE,
+                                "pppd is starting");
+
+    return G_SOURCE_CONTINUE;
+}
+
+/*****************************************************************************/
+
+NMPppMgr *
+nm_ppp_mgr_start(const NMPppMgrConfig *config, GError **error)
+{
+    NMPppMgr     *self;
+    NMPPPManager *ppp_manager;
+
+    g_return_val_if_fail(config, NULL);
+    g_return_val_if_fail(NM_IS_NETNS(config->netns), NULL);
+    g_return_val_if_fail(config->parent_iface, NULL);
+    g_return_val_if_fail(NM_IS_ACT_REQUEST(config->act_req), NULL);
+    g_return_val_if_fail(config->callback, NULL);
+    g_return_val_if_fail(!error || !*error, NULL);
+
+    ppp_manager = nm_ppp_manager_create(config->parent_iface, error);
+
+    if (!ppp_manager)
+        return NULL;
+
+    self = g_slice_new(NMPppMgr);
+
+    *self = (NMPppMgr){
+        .config      = *config,
+        .ppp_manager = ppp_manager,
+        .idle_start  = nm_g_idle_add_source(_idle_start_cb, self),
+        .state       = NM_PPP_MGR_STATE_STARTING,
+        .ip_data_4 =
+            {
+                .ip_received = FALSE,
+                .ip_enabled  = NM_OPTION_BOOL_DEFAULT,
+            },
+        .ip_data_6 =
+            {
+                .ip_received = FALSE,
+                .ip_enabled  = NM_OPTION_BOOL_DEFAULT,
+            },
+        .stats_data =
+            {
+                .in_bytes  = 0,
+                .out_bytes = 0,
+            },
+    };
+
+    g_object_ref(self->config.act_req);
+    g_object_ref(self->config.netns);
+    self->config.parent_iface = g_strdup(self->config.parent_iface);
+    self->config.ppp_username = g_strdup(self->config.ppp_username);
+
+    _LOGD("created");
+
+    return self;
+}
+
+void
+nm_ppp_mgr_destroy(NMPppMgr *self)
+{
+    if (!self)
+        return;
+
+    _LOGD("destroying");
+
+    if (self->state < _NM_PPP_MGR_STATE_FAILED_START)
+        _set_state_failed(self, NM_PPP_MGR_STATE_FAILED, NULL);
+
+    nm_clear_g_source_inst(&self->idle_start);
+    nm_clear_g_source_inst(&self->connect_timeout_source);
+
+    g_object_unref(self->config.act_req);
+
+    g_free((char *) self->config.parent_iface);
+    g_free((char *) self->config.ppp_username);
+
+    g_object_unref(self->config.netns);
+
+    nm_g_slice_free(self);
+}
diff --git a/src/core/ppp/nm-ppp-mgr.h b/src/core/ppp/nm-ppp-mgr.h
new file mode 100644
index 00000000..f6165411
--- /dev/null
+++ b/src/core/ppp/nm-ppp-mgr.h
@@ -0,0 +1,131 @@
+/* SPDX-License-Identifier: GPL-2.0-or-later */
+
+#ifndef __NM_PPP_MGR_H__
+#define __NM_PPP_MGR_H__
+
+#include "nm-l3cfg.h"
+
+typedef struct _NMPppMgr NMPppMgr;
+
+typedef enum _nm_packed {
+    /* NMPppMgr is starting. It will call nm_ppp_manager_start() on an idle
+     * handler. */
+    NM_PPP_MGR_STATE_STARTING,
+
+    /* NMPppMgr called nm_ppp_manager_start() and is now waiting to get
+     * an ifindex. At this time, we theoretically might already get IP configuration
+     * but that is cached and meaningless until we have the ifindex. */
+    NM_PPP_MGR_STATE_WAITING_FOR_IFINDEX,
+
+    /* NMPppMgr received an ifindex from NMPPPManager. But no IP configuration
+     * is yet received. */
+    NM_PPP_MGR_STATE_HAVE_IFINDEX,
+
+    /* NMPppMgr received an ifindex and IP configuration from NMPPPManager.
+     * Whether we have IPv4 and/or IPv6 is unspecified.
+     *
+     * If we have only either IPv4 or IPv6, then it's also unclear unknown
+     * whether the other address family will still arrive or not. */
+    NM_PPP_MGR_STATE_HAVE_IP_CONFIG,
+
+    /* Meta enum value which is the first failed state. All states larger than
+     * this are final (dead) states. */
+    _NM_PPP_MGR_STATE_FAILED_START,
+
+    /* NMPPPManager failed to start. This is a final (dead) state. */
+    NM_PPP_MGR_STATE_FAILED_TO_START = _NM_PPP_MGR_STATE_FAILED_START,
+
+    /* NMPppMgr started, but it failed to get the ifindex (possibly after timeout).
+     * This is a final (dead) state. */
+    NM_PPP_MGR_STATE_FAILED_TO_IFINDEX,
+
+    /* An unspecified failed state. This is a final (dead) state. */
+    NM_PPP_MGR_STATE_FAILED,
+} NMPppMgrState;
+
+const char *nm_ppp_mgr_state_to_string(NMPppMgrState state);
+
+typedef enum {
+    NM_PPP_MGR_CALLBACK_TYPE_STATE_CHANGED,
+    NM_PPP_MGR_CALLBACK_TYPE_STATS_CHANGED,
+} NMPppMgrCallbackType;
+
+const char *nm_ppp_mgr_callback_type_to_string(NMPppMgrCallbackType callback_type);
+
+typedef struct {
+    guint32 in_bytes;
+    guint32 out_bytes;
+} NMPppMgrStatsData;
+
+typedef struct {
+    const NML3ConfigData     *l3cd;
+    const NMUtilsIPv6IfaceId *ipv6_iid;
+    NMOptionBool              ip_enabled;
+    bool                      ip_received;
+} NMPppMgrIPData;
+
+typedef struct {
+    NMPppMgrCallbackType callback_type;
+    union {
+        struct {
+            const char *reason_msg;
+            union {
+                struct {
+                    const NMPppMgrIPData *ip_data_6;
+                    const NMPppMgrIPData *ip_data_4;
+                };
+                const NMPppMgrIPData *ip_data_x[2];
+            };
+            const NMPppMgrStatsData *stats_data;
+            int                      ifindex;
+            NMDeviceStateReason      reason;
+            NMPppMgrState            old_state;
+            NMPppMgrState            state;
+            union {
+                struct {
+                    bool ip_changed_6;
+                    bool ip_changed_4;
+                };
+                bool ip_changed_x[2];
+            };
+        } data;
+    };
+} NMPppMgrCallbackData;
+
+typedef void (*NMPppMgrCallback)(NMPppMgr                   *self,
+                                 const NMPppMgrCallbackData *callback_data,
+                                 gpointer                    user_data);
+
+typedef struct {
+    NMNetns    *netns;
+    const char *parent_iface;
+
+    NMPppMgrCallback callback;
+    gpointer         user_data;
+
+    NMActRequest *act_req;
+    const char   *ppp_username;
+    guint32       timeout_secs;
+    guint         baud_override;
+} NMPppMgrConfig;
+
+gboolean _nm_assert_is_ppp_mgr(const NMPppMgr *self);
+
+#define NM_IS_PPP_MGR(self)                      \
+    ({                                           \
+        const NMPppMgr *_self = (self);          \
+                                                 \
+        nm_assert(_nm_assert_is_ppp_mgr(_self)); \
+        !!_self;                                 \
+    })
+
+NMPppMgr *nm_ppp_mgr_start(const NMPppMgrConfig *config, GError **error);
+
+NMPppMgrState            nm_ppp_mgr_get_state(const NMPppMgr *self);
+int                      nm_ppp_mgr_get_ifindex(const NMPppMgr *self);
+const NMPppMgrIPData    *nm_ppp_mgr_get_ip_data(const NMPppMgr *self, int addr_family);
+const NMPppMgrStatsData *nm_ppp_mgr_get_stats(const NMPppMgr *self);
+
+void nm_ppp_mgr_destroy(NMPppMgr *self);
+
+#endif /* __NM_PPP_MGR_H__ */
diff --git a/src/core/ppp/nm-ppp-plugin-api.h b/src/core/ppp/nm-ppp-plugin-api.h
index 647e1c24..de4cfae3 100644
--- a/src/core/ppp/nm-ppp-plugin-api.h
+++ b/src/core/ppp/nm-ppp-plugin-api.h
@@ -11,21 +11,15 @@
 typedef const struct {
     NMPPPManager *(*create)(const char *iface);
 
-    void (*set_route_parameters)(NMPPPManager *manager,
-                                 guint32       route_table_v4,
-                                 guint32       route_metric_v4,
-                                 guint32       route_table_v6,
-                                 guint32       route_metric_v6);
-
     gboolean (*start)(NMPPPManager *manager,
                       NMActRequest *req,
-                      const char *  ppp_name,
+                      const char   *ppp_name,
                       guint32       timeout_secs,
                       guint         baud_override,
-                      GError **     err);
+                      GError      **err);
 
-    NMPPPManagerStopHandle *(*stop)(NMPPPManager *           manager,
-                                    GCancellable *           cancellable,
+    NMPPPManagerStopHandle *(*stop)(NMPPPManager            *manager,
+                                    GCancellable            *cancellable,
                                     NMPPPManagerStopCallback callback,
                                     gpointer                 user_data);
 
diff --git a/src/core/ppp/nm-ppp-status.h b/src/core/ppp/nm-ppp-status.h
index c346b119..df0ac10b 100644
--- a/src/core/ppp/nm-ppp-status.h
+++ b/src/core/ppp/nm-ppp-status.h
@@ -22,7 +22,10 @@ typedef enum {
     NM_PPP_STATUS_TERMINATE,
     NM_PPP_STATUS_DISCONNECT,
     NM_PPP_STATUS_HOLDOFF,
-    NM_PPP_STATUS_MASTER
+    NM_PPP_STATUS_MASTER,
+
+    /* these states are internal and not announced by the pppd plugin. */
+    NM_PPP_STATUS_INTERN_DEAD,
 } NMPPPStatus;
 
 #endif /* __NM_PPP_STATUS_H__ */
diff --git a/src/core/ppp/nm-pppd-plugin.c b/src/core/ppp/nm-pppd-plugin.c
index 5ffa7d17..e2e34d2a 100644
--- a/src/core/ppp/nm-pppd-plugin.c
+++ b/src/core/ppp/nm-pppd-plugin.c
@@ -33,14 +33,14 @@ char pppd_version[] = VERSION;
 
 static struct {
     GDBusConnection *dbus_connection;
-    char *           ipparam;
+    char            *ipparam;
 } gl;
 
 static void
 nm_phasechange(int arg)
 {
     NMPPPStatus ppp_status = NM_PPP_STATUS_UNKNOWN;
-    char *      ppp_phase;
+    char       *ppp_phase;
 
     g_return_if_fail(G_IS_DBUS_CONNECTION(gl.dbus_connection));
 
@@ -332,10 +332,10 @@ get_pap_check(void)
 static int
 get_credentials(char *username, char *password)
 {
-    gs_unref_variant GVariant *ret = NULL;
-    gs_free_error GError *error    = NULL;
-    const char *          my_username;
-    const char *          my_password;
+    gs_unref_variant GVariant *ret   = NULL;
+    gs_free_error GError      *error = NULL;
+    const char                *my_username;
+    const char                *my_password;
 
     if (!password) {
         /* pppd is checking pap support; return 1 for supported */