summary refs log tree commit diff
path: root/src/core/ppp
diff options
context:
space:
mode:
Diffstat (limited to 'src/core/ppp')
-rw-r--r--src/core/ppp/meson.build6
-rw-r--r--src/core/ppp/nm-ppp-manager.c6
-rw-r--r--src/core/ppp/nm-ppp-mgr.c2
-rw-r--r--src/core/ppp/nm-ppp-status.h37
-rw-r--r--src/core/ppp/nm-pppd-compat.c308
-rw-r--r--src/core/ppp/nm-pppd-compat.h64
-rw-r--r--src/core/ppp/nm-pppd-plugin.c198
7 files changed, 481 insertions, 140 deletions
diff --git a/src/core/ppp/meson.build b/src/core/ppp/meson.build
index 9ee46113..2365ffa8 100644
--- a/src/core/ppp/meson.build
+++ b/src/core/ppp/meson.build
@@ -3,7 +3,10 @@
 nm_pppd_plugin = shared_module(
   'nm-pppd-plugin',
   name_prefix: '',
-  sources: 'nm-pppd-plugin.c',
+  sources: [
+    'nm-pppd-compat.c',
+    'nm-pppd-plugin.c',
+  ],
   include_directories: [
     src_inc,
     top_inc,
@@ -11,6 +14,7 @@ nm_pppd_plugin = shared_module(
   dependencies: [
     libnm_core_public_dep,
     glib_dep,
+    pppd_dep,
   ],
   link_with: [
     libnm_core_impl,
diff --git a/src/core/ppp/nm-ppp-manager.c b/src/core/ppp/nm-ppp-manager.c
index 14cd5731..fbc5d075 100644
--- a/src/core/ppp/nm-ppp-manager.c
+++ b/src/core/ppp/nm-ppp-manager.c
@@ -428,7 +428,7 @@ impl_ppp_manager_set_state(NMDBusObject                      *obj,
 
     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;
+        ppp_state = NM_PPP_STATUS_INTERN_UNKNOWN;
     }
 
     g_signal_emit(self, signals[STATE_CHANGED], 0, (guint) ppp_state);
@@ -843,7 +843,7 @@ create_pppd_cmd_line(NMPPPManager   *self,
         const char *pppoe_service;
 
         nm_strv_ptrarray_add_string_dup(cmd, "plugin");
-        nm_strv_ptrarray_add_string_dup(cmd, "rp-pppoe.so");
+        nm_strv_ptrarray_add_string_dup(cmd, NM_PPPOE_PLUGIN_NAME);
 
         nm_strv_ptrarray_add_string_concat(cmd, "nic-", priv->parent_iface);
 
@@ -872,7 +872,7 @@ create_pppd_cmd_line(NMPPPManager   *self,
 
         } else if (!strcmp(protocol, NM_SETTING_ADSL_PROTOCOL_PPPOE)) {
             nm_strv_ptrarray_add_string_dup(cmd, "plugin");
-            nm_strv_ptrarray_add_string_dup(cmd, "rp-pppoe.so");
+            nm_strv_ptrarray_add_string_dup(cmd, NM_PPPOE_PLUGIN_NAME);
             nm_strv_ptrarray_add_string_dup(cmd, priv->parent_iface);
         }
 
diff --git a/src/core/ppp/nm-ppp-mgr.c b/src/core/ppp/nm-ppp-mgr.c
index bebffaf3..91d9a021 100644
--- a/src/core/ppp/nm-ppp-mgr.c
+++ b/src/core/ppp/nm-ppp-mgr.c
@@ -257,7 +257,7 @@ _ppp_signal_state_changed(NMPPPManager *ppp_manager, guint ppp_state_u, gpointer
     const char         *reason_msg;
 
     if ((guint) ppp_state != ppp_state_u)
-        ppp_state = NM_PPP_STATUS_UNKNOWN;
+        ppp_state = NM_PPP_STATUS_INTERN_UNKNOWN;
 
     switch (ppp_state) {
     case NM_PPP_STATUS_DISCONNECT:
diff --git a/src/core/ppp/nm-ppp-status.h b/src/core/ppp/nm-ppp-status.h
index df0ac10b..a2576e9c 100644
--- a/src/core/ppp/nm-ppp-status.h
+++ b/src/core/ppp/nm-ppp-status.h
@@ -8,24 +8,31 @@
 #define __NM_PPP_STATUS_H__
 
 typedef enum {
-    NM_PPP_STATUS_UNKNOWN,
-
-    NM_PPP_STATUS_DEAD,
-    NM_PPP_STATUS_INITIALIZE,
-    NM_PPP_STATUS_SERIALCONN,
-    NM_PPP_STATUS_DORMANT,
-    NM_PPP_STATUS_ESTABLISH,
-    NM_PPP_STATUS_AUTHENTICATE,
-    NM_PPP_STATUS_CALLBACK,
-    NM_PPP_STATUS_NETWORK,
-    NM_PPP_STATUS_RUNNING,
-    NM_PPP_STATUS_TERMINATE,
-    NM_PPP_STATUS_DISCONNECT,
-    NM_PPP_STATUS_HOLDOFF,
-    NM_PPP_STATUS_MASTER,
+
+    /* The numeric values correspond to the PHASE_{DEAD,} defines from <pppd/pppd.h>. */
+    NM_PPP_STATUS_DEAD         = 0,
+    NM_PPP_STATUS_INITIALIZE   = 1,
+    NM_PPP_STATUS_SERIALCONN   = 2,
+    NM_PPP_STATUS_DORMANT      = 3,
+    NM_PPP_STATUS_ESTABLISH    = 4,
+    NM_PPP_STATUS_AUTHENTICATE = 5,
+    NM_PPP_STATUS_CALLBACK     = 6,
+    NM_PPP_STATUS_NETWORK      = 7,
+    NM_PPP_STATUS_RUNNING      = 8,
+    NM_PPP_STATUS_TERMINATE    = 9,
+    NM_PPP_STATUS_DISCONNECT   = 10,
+    NM_PPP_STATUS_HOLDOFF      = 11,
+    NM_PPP_STATUS_MASTER       = 12,
 
     /* these states are internal and not announced by the pppd plugin. */
+    NM_PPP_STATUS_INTERN_UNKNOWN = 20,
     NM_PPP_STATUS_INTERN_DEAD,
 } NMPPPStatus;
 
+/*****************************************************************************/
+
+/* The plugin name "(rp-)pppoe.so" depends on the ppp version. */
+
+#define NM_PPPOE_PLUGIN_NAME (NM_PPP_VERSION_2_5_OR_NEWER ? "pppoe.so" : "rp-pppoe.so")
+
 #endif /* __NM_PPP_STATUS_H__ */
diff --git a/src/core/ppp/nm-pppd-compat.c b/src/core/ppp/nm-pppd-compat.c
new file mode 100644
index 00000000..f7940c55
--- /dev/null
+++ b/src/core/ppp/nm-pppd-compat.c
@@ -0,0 +1,308 @@
+/* SPDX-License-Identifier: LGPL-2.1-or-later */
+/*
+ * Copyright (C) 2023 Eivind Næss, eivnaes@yahoo.com
+ */
+
+/*****************************************************************************/
+
+/* PPP headers define some symbols as we do. We need to be careful to handle
+ * the conflict, and include stuff in a certain order. */
+
+#include <config.h>
+#define ___CONFIG_H__
+
+/*****************************************************************************/
+
+#if defined(__GNUC__) && (__GNUC__ > 4 || (__GNUC__ == 4 && __GNUC_MINOR__ >= 6))
+_Pragma("GCC diagnostic push") _Pragma("GCC diagnostic ignored \"-Wstrict-prototypes\"")
+#define _NM_PRAGMA_WARNING_REENABLE _Pragma("GCC diagnostic pop")
+#elif defined(__clang__)
+_Pragma("clang diagnostic push") _Pragma("clang diagnostic ignored \"-Wunknown-warning-option\"")
+    _Pragma("clang diagnostic ignored \"-Wstrict-prototypes\"")
+#define _NM_PRAGMA_WARNING_REENABLE _Pragma("clang diagnostic pop")
+#else
+#define _NM_PRAGMA_WARNING_REENABLE
+#endif
+
+/*****************************************************************************/
+
+#define INET6 1
+
+#include <pppd/pppd.h>
+
+#ifdef DATE
+/* Before ppp 2.5, pppd/patchlevel.h defined "DATE". Use that for detection. */
+#define PPP_VERSION_2_5_OR_NEWER 0
+#else
+#define PPP_VERSION_2_5_OR_NEWER 1
+#endif
+
+#include <pppd/eui64.h>
+#include <pppd/fsm.h>
+#include <pppd/ipcp.h>
+#include <pppd/ipv6cp.h>
+#include <pppd/upap.h>
+
+#if PPP_VERSION_2_5_OR_NEWER
+#include <pppd/chap.h>
+#else
+#include <pppd/chap-new.h>
+#include <pppd/chap_ms.h>
+#endif
+
+    char pppd_version[] = (
+#if PPP_VERSION_2_5_OR_NEWER
+        PPPD_VERSION
+#else
+            VERSION
+#endif
+    );
+
+#undef VERSION
+
+_NM_PRAGMA_WARNING_REENABLE;
+
+/*****************************************************************************/
+
+#include "libnm-glib-aux/nm-default-glib.h"
+
+#include "nm-pppd-compat.h"
+
+#include <net/if.h>
+#include <dlfcn.h>
+
+#include "nm-ppp-status.h"
+
+/*****************************************************************************/
+
+G_STATIC_ASSERT(PPP_VERSION_2_5_OR_NEWER == NM_PPP_VERSION_2_5_OR_NEWER);
+
+/*****************************************************************************/
+
+G_STATIC_ASSERT((gint64) NM_PPP_STATUS_DEAD == PHASE_DEAD);
+G_STATIC_ASSERT((gint64) NM_PPP_STATUS_INITIALIZE == PHASE_INITIALIZE);
+G_STATIC_ASSERT((gint64) NM_PPP_STATUS_SERIALCONN == PHASE_SERIALCONN);
+G_STATIC_ASSERT((gint64) NM_PPP_STATUS_DORMANT == PHASE_DORMANT);
+G_STATIC_ASSERT((gint64) NM_PPP_STATUS_ESTABLISH == PHASE_ESTABLISH);
+G_STATIC_ASSERT((gint64) NM_PPP_STATUS_AUTHENTICATE == PHASE_AUTHENTICATE);
+G_STATIC_ASSERT((gint64) NM_PPP_STATUS_CALLBACK == PHASE_CALLBACK);
+G_STATIC_ASSERT((gint64) NM_PPP_STATUS_NETWORK == PHASE_NETWORK);
+G_STATIC_ASSERT((gint64) NM_PPP_STATUS_RUNNING == PHASE_RUNNING);
+G_STATIC_ASSERT((gint64) NM_PPP_STATUS_TERMINATE == PHASE_TERMINATE);
+G_STATIC_ASSERT((gint64) NM_PPP_STATUS_DISCONNECT == PHASE_DISCONNECT);
+G_STATIC_ASSERT((gint64) NM_PPP_STATUS_HOLDOFF == PHASE_HOLDOFF);
+G_STATIC_ASSERT((gint64) NM_PPP_STATUS_MASTER == PHASE_MASTER);
+
+G_STATIC_ASSERT(NM_PPPD_COMPAT_MAXNAMELEN == MAXNAMELEN);
+G_STATIC_ASSERT(NM_PPPD_COMPAT_MAXSECRETLEN == MAXSECRETLEN);
+
+/*****************************************************************************/
+
+int
+nm_pppd_compat_get_ifunit(void)
+{
+    int i;
+
+#if PPP_VERSION_2_5_OR_NEWER
+    i = ppp_ifunit();
+#else
+    i = ifunit;
+#endif
+
+    return i;
+}
+
+const char *
+nm_pppd_compat_get_ifname(void)
+{
+    const char *s;
+
+#if PPP_VERSION_2_5_OR_NEWER
+    s = ppp_ifname();
+#else
+    s = ifname;
+#endif
+
+    nm_assert(s);
+    nm_assert(strlen(s) < IFNAMSIZ);
+    return s;
+}
+
+void
+nm_pppd_compat_set_ifname(const char *arg_ifname)
+{
+    nm_assert(arg_ifname);
+    nm_assert(strlen(arg_ifname) < IFNAMSIZ);
+
+#if PPP_VERSION_2_5_OR_NEWER
+    ppp_set_ifname(arg_ifname);
+#else
+    g_strlcpy(ifname, arg_ifname, IFNAMSIZ);
+#endif
+}
+
+const char *
+nm_pppd_compat_get_ipparam(void)
+{
+    const char *s;
+
+#if PPP_VERSION_2_5_OR_NEWER
+    s = ppp_ipparam();
+#else
+    s = ipparam;
+#endif
+
+    return s;
+}
+
+void
+nm_pppd_compat_get_ipcp_options(NMPppdCompatIPCPOptions *out_got, NMPppdCompatIPCPOptions *out_his)
+{
+    const ipcp_options *const got = &ipcp_gotoptions[0];
+    const ipcp_options *const his = &ipcp_hisoptions[0];
+
+    nm_assert(out_got);
+    nm_assert(out_his);
+
+    *out_got = (NMPppdCompatIPCPOptions){
+        .ouraddr  = got->ouraddr,
+        .hisaddr  = got->hisaddr,
+        .dnsaddr  = {got->dnsaddr[0], got->dnsaddr[1]},
+        .winsaddr = {got->winsaddr[0], got->winsaddr[1]},
+    };
+
+    *out_his = (NMPppdCompatIPCPOptions){
+        .ouraddr  = his->ouraddr,
+        .hisaddr  = his->hisaddr,
+        .dnsaddr  = {his->dnsaddr[0], his->dnsaddr[1]},
+        .winsaddr = {his->winsaddr[0], his->winsaddr[1]},
+    };
+}
+
+void
+nm_pppd_compat_get_ipv6cp_options(NMPppdCompatIPV6CPOptions *out_got,
+                                  NMPppdCompatIPV6CPOptions *out_his)
+{
+    const ipv6cp_options *const his = &ipv6cp_hisoptions[0];
+    const ipv6cp_options *const got = &ipv6cp_gotoptions[0];
+
+    G_STATIC_ASSERT(sizeof(guint64) == sizeof(eui64_t));
+
+    nm_assert(out_got);
+    nm_assert(out_his);
+
+    *out_got = (NMPppdCompatIPV6CPOptions){};
+    memcpy(&out_got->ourid, &got->ourid, sizeof(guint64));
+    memcpy(&out_got->hisid, &got->hisid, sizeof(guint64));
+
+    *out_his = (NMPppdCompatIPV6CPOptions){};
+    memcpy(&out_his->ourid, &his->ourid, sizeof(guint64));
+    memcpy(&out_his->hisid, &his->hisid, sizeof(guint64));
+}
+
+void
+nm_pppd_compat_set_chap_passwd_hook(int (*hook)(char *user, char *password))
+{
+    chap_passwd_hook = hook;
+}
+
+void
+nm_pppd_compat_set_chap_check_hook(int (*hook)(void))
+{
+    chap_check_hook = hook;
+}
+
+void
+nm_pppd_compat_set_pap_passwd_hook(int (*hook)(char *user, char *passwd))
+{
+    pap_passwd_hook = hook;
+}
+
+void
+nm_pppd_compat_set_pap_check_hook(int (*hook)(void))
+{
+    pap_check_hook = hook;
+}
+
+gboolean
+nm_pppd_compat_add_notify(NMPppdCompatNotifyT type, void (*func)(void *ctx, int arg), void *ctx)
+{
+    nm_assert(NM_IN_SET(type,
+                        NM_PPPD_COMPAT_NF_PID_CHANGE,
+                        NM_PPPD_COMPAT_NF_PHASE_CHANGE,
+                        NM_PPPD_COMPAT_NF_EXIT,
+                        NM_PPPD_COMPAT_NF_SIGNALED,
+                        NM_PPPD_COMPAT_NF_IP_UP,
+                        NM_PPPD_COMPAT_NF_IP_DOWN,
+                        NM_PPPD_COMPAT_NF_IPV6_UP,
+                        NM_PPPD_COMPAT_NF_IPV6_DOWN,
+                        NM_PPPD_COMPAT_NF_AUTH_UP,
+                        NM_PPPD_COMPAT_NF_LINK_DOWN,
+                        NM_PPPD_COMPAT_NF_FORK));
+    nm_assert(func);
+
+#if PPP_VERSION_2_5_OR_NEWER
+    {
+        G_STATIC_ASSERT((gint64) NM_PPPD_COMPAT_NF_PID_CHANGE == NF_PID_CHANGE);
+        G_STATIC_ASSERT((gint64) NM_PPPD_COMPAT_NF_PHASE_CHANGE == NF_PHASE_CHANGE);
+        G_STATIC_ASSERT((gint64) NM_PPPD_COMPAT_NF_EXIT == NF_EXIT);
+        G_STATIC_ASSERT((gint64) NM_PPPD_COMPAT_NF_SIGNALED == NF_SIGNALED);
+        G_STATIC_ASSERT((gint64) NM_PPPD_COMPAT_NF_IP_UP == NF_IP_UP);
+        G_STATIC_ASSERT((gint64) NM_PPPD_COMPAT_NF_IP_DOWN == NF_IP_DOWN);
+        G_STATIC_ASSERT((gint64) NM_PPPD_COMPAT_NF_IPV6_UP == NF_IPV6_UP);
+        G_STATIC_ASSERT((gint64) NM_PPPD_COMPAT_NF_IPV6_DOWN == NF_IPV6_DOWN);
+        G_STATIC_ASSERT((gint64) NM_PPPD_COMPAT_NF_AUTH_UP == NF_AUTH_UP);
+        G_STATIC_ASSERT((gint64) NM_PPPD_COMPAT_NF_LINK_DOWN == NF_LINK_DOWN);
+        G_STATIC_ASSERT((gint64) NM_PPPD_COMPAT_NF_FORK == NF_FORK);
+
+        ppp_add_notify((gint64) type, func, ctx);
+        return TRUE;
+    }
+#else
+    {
+        static struct notifier **list[] = {
+            [NM_PPPD_COMPAT_NF_PID_CHANGE]   = &pidchange,
+            [NM_PPPD_COMPAT_NF_PHASE_CHANGE] = &phasechange,
+            [NM_PPPD_COMPAT_NF_EXIT]         = &exitnotify,
+            [NM_PPPD_COMPAT_NF_SIGNALED]     = &sigreceived,
+            [NM_PPPD_COMPAT_NF_IP_UP]        = &ip_up_notifier,
+            [NM_PPPD_COMPAT_NF_IP_DOWN]      = &ip_down_notifier,
+            [NM_PPPD_COMPAT_NF_IPV6_UP]      = NULL /* ipv6_up_notifier */,
+            [NM_PPPD_COMPAT_NF_IPV6_DOWN]    = NULL /* ipv6_down_notifier */,
+            [NM_PPPD_COMPAT_NF_AUTH_UP]      = &auth_up_notifier,
+            [NM_PPPD_COMPAT_NF_LINK_DOWN]    = &link_down_notifier,
+            [NM_PPPD_COMPAT_NF_FORK]         = &fork_notifier,
+        };
+        struct notifier **notifier;
+
+        nm_assert(_NM_INT_NOT_NEGATIVE(type) && type < G_N_ELEMENTS(list));
+
+        if (NM_IN_SET(type, NM_PPPD_COMPAT_NF_IPV6_UP, NM_PPPD_COMPAT_NF_IPV6_DOWN)) {
+            static gsize load_once = 0;
+
+            /* pppd might be build without IPv6 support. Load the symbols dynamically. */
+            if (g_once_init_enter(&load_once)) {
+                void *handle;
+
+                handle = dlopen(NULL, RTLD_NOW | RTLD_GLOBAL);
+                if (handle) {
+                    list[NM_PPPD_COMPAT_NF_IPV6_UP]   = dlsym(handle, "ipv6_up_notifier");
+                    list[NM_PPPD_COMPAT_NF_IPV6_DOWN] = dlsym(handle, "ipv6_down_notifier");
+                    dlclose(handle);
+                }
+                g_once_init_leave(&load_once, 1);
+            }
+
+            notifier = list[type];
+        } else {
+            notifier = list[type];
+            nm_assert(notifier);
+        }
+
+        if (notifier)
+            add_notifier(notifier, func, ctx);
+
+        return !!notifier;
+    }
+#endif
+}
diff --git a/src/core/ppp/nm-pppd-compat.h b/src/core/ppp/nm-pppd-compat.h
new file mode 100644
index 00000000..11376e36
--- /dev/null
+++ b/src/core/ppp/nm-pppd-compat.h
@@ -0,0 +1,64 @@
+/* SPDX-License-Identifier: LGPL-2.1-or-later */
+/*
+ * Copyright (C) 2023 Eivind Næss, eivnaes@yahoo.com
+ */
+
+#ifndef __NM_PPPD_COMPAT_H__
+#define __NM_PPPD_COMPAT_H__
+
+#define NM_PPPD_COMPAT_MAXNAMELEN   256
+#define NM_PPPD_COMPAT_MAXSECRETLEN 256
+
+int nm_pppd_compat_get_ifunit(void);
+
+const char *nm_pppd_compat_get_ifname(void);
+void        nm_pppd_compat_set_ifname(const char *ifname);
+
+const char *nm_pppd_compat_get_ipparam(void);
+
+typedef struct {
+    /* has information from "ipcp_options" */
+    in_addr_t ouraddr;
+    in_addr_t hisaddr;
+    in_addr_t dnsaddr[2];
+    in_addr_t winsaddr[2];
+} NMPppdCompatIPCPOptions;
+
+void nm_pppd_compat_get_ipcp_options(NMPppdCompatIPCPOptions *out_got,
+                                     NMPppdCompatIPCPOptions *out_his);
+
+typedef struct {
+    /* has information from "ipv6cp_options" */
+    guint64 ourid;
+    guint64 hisid;
+} NMPppdCompatIPV6CPOptions;
+
+void nm_pppd_compat_get_ipv6cp_options(NMPppdCompatIPV6CPOptions *out_got,
+                                       NMPppdCompatIPV6CPOptions *out_his);
+
+void nm_pppd_compat_set_chap_passwd_hook(int (*hook)(char *user, char *password));
+
+void nm_pppd_compat_set_chap_check_hook(int (*hook)(void));
+
+void nm_pppd_compat_set_pap_passwd_hook(int (*hook)(char *user, char *passwd));
+
+void nm_pppd_compat_set_pap_check_hook(int (*hook)(void));
+
+typedef enum {
+    NM_PPPD_COMPAT_NF_PID_CHANGE,
+    NM_PPPD_COMPAT_NF_PHASE_CHANGE,
+    NM_PPPD_COMPAT_NF_EXIT,
+    NM_PPPD_COMPAT_NF_SIGNALED,
+    NM_PPPD_COMPAT_NF_IP_UP,
+    NM_PPPD_COMPAT_NF_IP_DOWN,
+    NM_PPPD_COMPAT_NF_IPV6_UP,
+    NM_PPPD_COMPAT_NF_IPV6_DOWN,
+    NM_PPPD_COMPAT_NF_AUTH_UP,
+    NM_PPPD_COMPAT_NF_LINK_DOWN,
+    NM_PPPD_COMPAT_NF_FORK,
+} NMPppdCompatNotifyT;
+
+gboolean
+nm_pppd_compat_add_notify(NMPppdCompatNotifyT type, void (*func)(void *ctx, int arg), void *ctx);
+
+#endif /* #ifdef __NM_PPPD_COMPAT_H__ */
diff --git a/src/core/ppp/nm-pppd-plugin.c b/src/core/ppp/nm-pppd-plugin.c
index e2e34d2a..93425f38 100644
--- a/src/core/ppp/nm-pppd-plugin.c
+++ b/src/core/ppp/nm-pppd-plugin.c
@@ -4,33 +4,23 @@
  * Copyright (C) 2008 Red Hat, Inc.
  */
 
-#include <config.h>
-#define ___CONFIG_H__
+#include "libnm-glib-aux/nm-default-glib.h"
+
+#include "nm-pppd-plugin.h"
 
-#include <pppd/pppd.h>
-#include <pppd/fsm.h>
-#include <pppd/ipcp.h>
 #include <sys/socket.h>
 #include <netinet/in.h>
 #include <net/if.h>
 #include <arpa/inet.h>
 #include <dlfcn.h>
+#include <glib.h>
 
-#define INET6
-#include <pppd/eui64.h>
-#include <pppd/ipv6cp.h>
-
-#include "libnm-glib-aux/nm-default-glib.h"
-
-#include "nm-dbus-interface.h"
-
-#include "nm-pppd-plugin.h"
+#include "nm-pppd-compat.h"
 #include "nm-ppp-status.h"
+#include "nm-dbus-interface.h"
 
 int plugin_init(void);
 
-char pppd_version[] = VERSION;
-
 static struct {
     GDBusConnection *dbus_connection;
     char            *ipparam;
@@ -39,73 +29,63 @@ static struct {
 static void
 nm_phasechange(int arg)
 {
-    NMPPPStatus ppp_status = NM_PPP_STATUS_UNKNOWN;
+    NMPPPStatus ppp_status;
     char       *ppp_phase;
 
     g_return_if_fail(G_IS_DBUS_CONNECTION(gl.dbus_connection));
 
+    ppp_status = arg;
+
     switch (arg) {
-    case PHASE_DEAD:
-        ppp_status = NM_PPP_STATUS_DEAD;
-        ppp_phase  = "dead";
+    case NM_PPP_STATUS_DEAD:
+        ppp_phase = "dead";
         break;
-    case PHASE_INITIALIZE:
-        ppp_status = NM_PPP_STATUS_INITIALIZE;
-        ppp_phase  = "initialize";
+    case NM_PPP_STATUS_INITIALIZE:
+        ppp_phase = "initialize";
         break;
-    case PHASE_SERIALCONN:
-        ppp_status = NM_PPP_STATUS_SERIALCONN;
-        ppp_phase  = "serial connection";
+    case NM_PPP_STATUS_SERIALCONN:
+        ppp_phase = "serial connection";
         break;
-    case PHASE_DORMANT:
-        ppp_status = NM_PPP_STATUS_DORMANT;
-        ppp_phase  = "dormant";
+    case NM_PPP_STATUS_DORMANT:
+        ppp_phase = "dormant";
         break;
-    case PHASE_ESTABLISH:
-        ppp_status = NM_PPP_STATUS_ESTABLISH;
-        ppp_phase  = "establish";
+    case NM_PPP_STATUS_ESTABLISH:
+        ppp_phase = "establish";
         break;
-    case PHASE_AUTHENTICATE:
-        ppp_status = NM_PPP_STATUS_AUTHENTICATE;
-        ppp_phase  = "authenticate";
+    case NM_PPP_STATUS_AUTHENTICATE:
+        ppp_phase = "authenticate";
         break;
-    case PHASE_CALLBACK:
-        ppp_status = NM_PPP_STATUS_CALLBACK;
-        ppp_phase  = "callback";
+    case NM_PPP_STATUS_CALLBACK:
+        ppp_phase = "callback";
         break;
-    case PHASE_NETWORK:
-        ppp_status = NM_PPP_STATUS_NETWORK;
-        ppp_phase  = "network";
+    case NM_PPP_STATUS_NETWORK:
+        ppp_phase = "network";
         break;
-    case PHASE_RUNNING:
-        ppp_status = NM_PPP_STATUS_RUNNING;
-        ppp_phase  = "running";
+    case NM_PPP_STATUS_RUNNING:
+        ppp_phase = "running";
         break;
-    case PHASE_TERMINATE:
-        ppp_status = NM_PPP_STATUS_TERMINATE;
-        ppp_phase  = "terminate";
+    case NM_PPP_STATUS_TERMINATE:
+        ppp_phase = "terminate";
         break;
-    case PHASE_DISCONNECT:
-        ppp_status = NM_PPP_STATUS_DISCONNECT;
-        ppp_phase  = "disconnect";
+    case NM_PPP_STATUS_DISCONNECT:
+        ppp_phase = "disconnect";
         break;
-    case PHASE_HOLDOFF:
-        ppp_status = NM_PPP_STATUS_HOLDOFF;
-        ppp_phase  = "holdoff";
+    case NM_PPP_STATUS_HOLDOFF:
+        ppp_phase = "holdoff";
         break;
-    case PHASE_MASTER:
-        ppp_status = NM_PPP_STATUS_MASTER;
-        ppp_phase  = "master";
+    case NM_PPP_STATUS_MASTER:
+        ppp_phase = "master";
         break;
 
     default:
-        ppp_phase = "unknown";
+        ppp_status = NM_PPP_STATUS_INTERN_UNKNOWN;
+        ppp_phase  = "unknown";
         break;
     }
 
     g_message("nm-ppp-plugin: status %d / phase '%s'", ppp_status, ppp_phase);
 
-    if (ppp_status != NM_PPP_STATUS_UNKNOWN) {
+    if (ppp_status != NM_PPP_STATUS_INTERN_UNKNOWN) {
         g_dbus_connection_call(gl.dbus_connection,
                                NM_DBUS_SERVICE,
                                gl.ipparam,
@@ -125,7 +105,7 @@ nm_phasechange(int arg)
         char                       new_name[IF_NAMESIZE];
         int                        ifindex;
 
-        ifindex = if_nametoindex(ifname);
+        ifindex = if_nametoindex(nm_pppd_compat_get_ifname());
 
         /* Make a sync call to ensure that when the call
          * terminates the interface already has its final
@@ -143,9 +123,12 @@ nm_phasechange(int arg)
                                           NULL);
 
         /* Update the name in pppd if NM changed it */
-        if (if_indextoname(ifindex, new_name) && !nm_streq0(ifname, new_name)) {
-            g_message("nm-ppp-plugin: interface name changed from '%s' to '%s'", ifname, new_name);
-            g_strlcpy(ifname, new_name, IF_NAMESIZE);
+        if (if_indextoname(ifindex, new_name)
+            && !nm_streq0(nm_pppd_compat_get_ifname(), new_name)) {
+            g_message("nm-ppp-plugin: interface name changed from '%s' to '%s'",
+                      nm_pppd_compat_get_ifname(),
+                      new_name);
+            nm_pppd_compat_set_ifname(new_name);
         }
     }
 }
@@ -154,7 +137,7 @@ static void
 nm_phasechange_hook(void *data, int arg)
 {
     /* We send the nofication in exitnotify instead */
-    if (arg == PHASE_DEAD)
+    if (arg == NM_PPP_STATUS_DEAD)
         return;
 
     nm_phasechange(arg);
@@ -163,18 +146,21 @@ nm_phasechange_hook(void *data, int arg)
 static void
 nm_ip_up(void *data, int arg)
 {
-    ipcp_options    opts      = ipcp_gotoptions[0];
-    ipcp_options    peer_opts = ipcp_hisoptions[0];
-    GVariantBuilder builder;
-    guint32         pppd_made_up_address = htonl(0x0a404040 + ifunit);
+    NMPppdCompatIPCPOptions opts;
+    NMPppdCompatIPCPOptions peer_opts;
+    GVariantBuilder         builder;
+    const in_addr_t         pppd_made_up_address =
+        htonl(0x0a404040u + ((guint) nm_pppd_compat_get_ifunit()));
 
     g_return_if_fail(G_IS_DBUS_CONNECTION(gl.dbus_connection));
 
     g_message("nm-ppp-plugin: ip-up event");
 
+    nm_pppd_compat_get_ipcp_options(&opts, &peer_opts);
+
     if (!opts.ouraddr) {
         g_warning("nm-ppp-plugin: didn't receive an internal IP from pppd!");
-        nm_phasechange(PHASE_DEAD);
+        nm_phasechange(NM_PPP_STATUS_DEAD);
         return;
     }
 
@@ -186,7 +172,7 @@ nm_ip_up(void *data, int arg)
     g_variant_builder_add(&builder,
                           "{sv}",
                           NM_PPP_IP4_CONFIG_INTERFACE,
-                          g_variant_new_string(ifname));
+                          g_variant_new_string(nm_pppd_compat_get_ifname()));
 
     g_variant_builder_add(&builder,
                           "{sv}",
@@ -263,28 +249,19 @@ nm_ip_up(void *data, int arg)
                            NULL);
 }
 
-static GVariant *
-eui64_to_variant(eui64_t eui)
-{
-    guint64 iid;
-
-    G_STATIC_ASSERT(sizeof(iid) == sizeof(eui));
-
-    memcpy(&iid, &eui, sizeof(eui));
-    return g_variant_new_uint64(iid);
-}
-
 static void
 nm_ip6_up(void *data, int arg)
 {
-    ipv6cp_options *ho = &ipv6cp_hisoptions[0];
-    ipv6cp_options *go = &ipv6cp_gotoptions[0];
-    GVariantBuilder builder;
+    NMPppdCompatIPV6CPOptions his;
+    NMPppdCompatIPV6CPOptions got;
+    GVariantBuilder           builder;
 
     g_return_if_fail(G_IS_DBUS_CONNECTION(gl.dbus_connection));
 
     g_message("nm-ppp-plugin: ip6-up event");
 
+    nm_pppd_compat_get_ipv6cp_options(&got, &his);
+
     g_variant_builder_init(&builder, G_VARIANT_TYPE_VARDICT);
     /* Keep sending the interface name to be backwards compatible
      * with older versions of NM during a package upgrade, where
@@ -292,12 +269,15 @@ nm_ip6_up(void *data, int arg)
     g_variant_builder_add(&builder,
                           "{sv}",
                           NM_PPP_IP6_CONFIG_INTERFACE,
-                          g_variant_new_string(ifname));
-    g_variant_builder_add(&builder, "{sv}", NM_PPP_IP6_CONFIG_OUR_IID, eui64_to_variant(go->ourid));
+                          g_variant_new_string(nm_pppd_compat_get_ifname()));
+    g_variant_builder_add(&builder,
+                          "{sv}",
+                          NM_PPP_IP6_CONFIG_OUR_IID,
+                          g_variant_new_uint64(got.ourid));
     g_variant_builder_add(&builder,
                           "{sv}",
                           NM_PPP_IP6_CONFIG_PEER_IID,
-                          eui64_to_variant(ho->hisid));
+                          g_variant_new_uint64(his.hisid));
 
     /* DNS is done via DHCPv6 or router advertisements */
 
@@ -368,8 +348,8 @@ get_credentials(char *username, char *password)
 
     g_variant_get(ret, "(&s&s)", &my_username, &my_password);
 
-    g_strlcpy(username, my_username, MAXNAMELEN);
-    g_strlcpy(password, my_password, MAXSECRETLEN);
+    g_strlcpy(username, my_username, NM_PPPD_COMPAT_MAXNAMELEN);
+    g_strlcpy(password, my_password, NM_PPPD_COMPAT_MAXSECRETLEN);
 
     return 1;
 }
@@ -382,7 +362,7 @@ nm_exit_notify(void *data, int arg)
     /* We wait until this point to notify dead phase to make sure that
      * the serial port has recovered already its original settings.
      */
-    nm_phasechange(PHASE_DEAD);
+    nm_phasechange(NM_PPP_STATUS_DEAD);
 
     g_message("nm-ppp-plugin: cleaning up");
 
@@ -390,27 +370,6 @@ nm_exit_notify(void *data, int arg)
     nm_clear_g_free(&gl.ipparam);
 }
 
-static void
-add_ip6_notifier(void)
-{
-    static struct notifier **notifier  = NULL;
-    static gsize             load_once = 0;
-
-    if (g_once_init_enter(&load_once)) {
-        void *handle = dlopen(NULL, RTLD_NOW | RTLD_GLOBAL);
-
-        if (handle) {
-            notifier = dlsym(handle, "ipv6_up_notifier");
-            dlclose(handle);
-        }
-        g_once_init_leave(&load_once, 1);
-    }
-    if (notifier)
-        add_notifier(notifier, nm_ip6_up, NULL);
-    else
-        g_message("nm-ppp-plugin: no IPV6CP notifier support; IPv6 not available");
-}
-
 int
 plugin_init(void)
 {
@@ -427,17 +386,16 @@ plugin_init(void)
         return -1;
     }
 
-    gl.ipparam = g_strdup(ipparam);
-
-    chap_passwd_hook = get_credentials;
-    chap_check_hook  = get_chap_check;
-    pap_passwd_hook  = get_credentials;
-    pap_check_hook   = get_pap_check;
+    gl.ipparam = g_strdup(nm_pppd_compat_get_ipparam());
 
-    add_notifier(&phasechange, nm_phasechange_hook, NULL);
-    add_notifier(&ip_up_notifier, nm_ip_up, NULL);
-    add_notifier(&exitnotify, nm_exit_notify, NULL);
-    add_ip6_notifier();
+    nm_pppd_compat_set_chap_passwd_hook(get_credentials);
+    nm_pppd_compat_set_chap_check_hook(get_chap_check);
+    nm_pppd_compat_set_pap_passwd_hook(get_credentials);
+    nm_pppd_compat_set_pap_check_hook(get_pap_check);
 
+    nm_pppd_compat_add_notify(NM_PPPD_COMPAT_NF_PHASE_CHANGE, nm_phasechange_hook, NULL);
+    nm_pppd_compat_add_notify(NM_PPPD_COMPAT_NF_IP_UP, nm_ip_up, NULL);
+    nm_pppd_compat_add_notify(NM_PPPD_COMPAT_NF_EXIT, nm_exit_notify, NULL);
+    nm_pppd_compat_add_notify(NM_PPPD_COMPAT_NF_IPV6_UP, nm_ip6_up, NULL);
     return 0;
 }