summary refs log tree commit diff
path: root/src/core/ppp/nm-pppd-compat.c
diff options
context:
space:
mode:
Diffstat (limited to 'src/core/ppp/nm-pppd-compat.c')
-rw-r--r--src/core/ppp/nm-pppd-compat.c308
1 files changed, 308 insertions, 0 deletions
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
+}