ppp: backport patches improving ppp interface creation

Backport patches improving ppp interface creation. As a side effect this
also fix a bug from using netdev trigger that suffer from LED state
wrongly set due to using old ioctl for ppp creation.

Tested-by: Csaba Sipos <metro4@freemail.hu>
Signed-off-by: Christian Marangi <ansuelsmth@gmail.com>
This commit is contained in:
Christian Marangi 2023-06-13 23:19:02 +02:00
parent 244328b19c
commit 8c1bd9b6a5
No known key found for this signature in database
GPG Key ID: AC001D09ADBFEAD7
14 changed files with 1174 additions and 26 deletions

View File

@ -9,7 +9,7 @@ include $(TOPDIR)/rules.mk
include $(INCLUDE_DIR)/kernel.mk
PKG_NAME:=ppp
PKG_RELEASE:=4
PKG_RELEASE:=5
PKG_SOURCE_PROTO:=git
PKG_SOURCE_URL:=https://github.com/paulusmack/ppp

View File

@ -0,0 +1,54 @@
From 98ec18f098e5ef68e3a8cc6954fcaf5a7fb8b7be Mon Sep 17 00:00:00 2001
From: pali <7141871+pali@users.noreply.github.com>
Date: Mon, 15 Feb 2021 07:54:01 +0100
Subject: [PATCH] pppd: Fix compilation with older glibc or kernel headers
(#248)
MIME-Version: 1.0
Content-Type: text/plain; charset=UTF-8
Content-Transfer-Encoding: 8bit
glibc versions prior to 2.24 do not define SOL_NETLINK and linux kernel
versions prior to 4.3 do not define NETLINK_CAP_ACK. So add fallback
definitions for these macros into pppd/sys-linux.c file.
Also extend description why we call SOL_NETLINK/NETLINK_CAP_ACK option.
Signed-off-by: Pali Rohár <pali@kernel.org>
---
pppd/sys-linux.c | 18 +++++++++++++++++-
1 file changed, 17 insertions(+), 1 deletion(-)
--- a/pppd/sys-linux.c
+++ b/pppd/sys-linux.c
@@ -125,6 +125,14 @@
#include <linux/netlink.h>
#include <linux/rtnetlink.h>
#include <linux/if_addr.h>
+/* glibc versions prior to 2.24 do not define SOL_NETLINK */
+#ifndef SOL_NETLINK
+#define SOL_NETLINK 270
+#endif
+/* linux kernel versions prior to 4.3 do not define/support NETLINK_CAP_ACK */
+#ifndef NETLINK_CAP_ACK
+#define NETLINK_CAP_ACK 10
+#endif
#endif
#include "pppd.h"
@@ -2843,7 +2851,15 @@ static int append_peer_ipv6_address(unsi
if (fd < 0)
return 0;
- /* do not ask for error message content */
+ /*
+ * Tell kernel to not send to us payload of acknowledgment error message.
+ * NETLINK_CAP_ACK option is supported since Linux kernel version 4.3 and
+ * older kernel versions always send full payload in acknowledgment netlink
+ * message. We ignore payload of this message as we need only error code,
+ * to check if our set remote peer address request succeeded or failed.
+ * So ignore return value from the following setsockopt() call as setting
+ * option NETLINK_CAP_ACK means for us just a kernel hint / optimization.
+ */
one = 1;
setsockopt(fd, SOL_NETLINK, NETLINK_CAP_ACK, &one, sizeof(one));

View File

@ -0,0 +1,518 @@
From 81ad945630120cc1c27c8bb00503be42b76ff202 Mon Sep 17 00:00:00 2001
From: Jaco Kroon <jaco@uls.co.za>
Date: Thu, 13 Jan 2022 08:38:04 +0200
Subject: [PATCH] Expand byte count statistics to 64 bits (#298)
* Add Gigawords to radius packets where applicable.
IMPORTANT NOTE: The ioctl() only supports 32-bit counters. In order t
obtain 64-bit counters, these are now pulled in from sysfs (it's assumed
to be mounted on /sys which I'm assuming is standard).
It is unknown whether sysfs will be available everywhere, as such, keep
the ioctl() method in place, but attempt to detect wrap-overs.
If the sysfs mechanism fails, fail back to the ioctl().
Given maximum data rates, the intervals between calling this needs to be
such that no more than 4GB (2^32) bytes are sent or received in any
given interval. Mostly important for radius plugin where data
accounting may be in effect.
Towards this, a timer interval on 25 seconds is set to force a ioctl()
poll irrespective of the rate of stats update calls. This may be
important for especially radius that needs to provide interim-update
intervals, if the interim updates is too long and the counters could
wrap-over twice in a single interval. At 25 seconds we should detect
all wraps up to an effective data rate of 1.37Gbps, which for my
purposes is adequate.
Possible downsides, 4 files are opened, read and closed every time
statistics is requested. This results in 12 system calls every single
time statistics is required, compared to 1 for the ioctl. Efficiency is
unknown, but as a rule of thumb fewer system calls are better, this is
however not a critical path in my opinion, so should not be a problem.
If required I can run a few benchmarks using gettimeofday() to measure
actual impact.
Signed-off-by: Jaco Kroon <jaco@uls.co.za>
* Use netlink if possible to obtain 64-bit stats.
This uses two system calls per round.
This should be preferred where available. It seems the RTM_GETSTATS was
only added from 2016 some point (4.7.0 as per pali), which is in my
opinion old, but given experience with certain embedded systems does
need to be supported.
Signed-off-by: Jaco Kroon <jaco@uls.co.za>
Co-authored-by: Jaco Kroon <jaco@iewc.co.za>
---
pppd/main.c | 5 +-
pppd/plugins/radius/etc/dictionary | 2 +
pppd/plugins/radius/radius.c | 28 ++-
pppd/plugins/radius/radiusclient.h | 2 +
pppd/pppd.h | 9 +-
pppd/sys-linux.c | 281 ++++++++++++++++++++++++++++-
6 files changed, 313 insertions(+), 14 deletions(-)
--- a/pppd/main.c
+++ b/pppd/main.c
@@ -87,6 +87,7 @@
#include <sys/socket.h>
#include <netinet/in.h>
#include <arpa/inet.h>
+#include <inttypes.h>
#include "pppd.h"
#include "magic.h"
@@ -1230,9 +1231,9 @@ update_link_stats(int u)
slprintf(numbuf, sizeof(numbuf), "%u", link_connect_time);
script_setenv("CONNECT_TIME", numbuf, 0);
- slprintf(numbuf, sizeof(numbuf), "%u", link_stats.bytes_out);
+ snprintf(numbuf, sizeof(numbuf), "%" PRIu64, link_stats.bytes_out);
script_setenv("BYTES_SENT", numbuf, 0);
- slprintf(numbuf, sizeof(numbuf), "%u", link_stats.bytes_in);
+ snprintf(numbuf, sizeof(numbuf), "%" PRIu64, link_stats.bytes_in);
script_setenv("BYTES_RCVD", numbuf, 0);
}
--- a/pppd/plugins/radius/etc/dictionary
+++ b/pppd/plugins/radius/etc/dictionary
@@ -82,6 +82,8 @@ ATTRIBUTE Acct-Session-Time 46 integer
ATTRIBUTE Acct-Input-Packets 47 integer
ATTRIBUTE Acct-Output-Packets 48 integer
ATTRIBUTE Acct-Terminate-Cause 49 integer
+ATTRIBUTE Acct-Input-Gigawords 52 integer
+ATTRIBUTE Acct-Output-Gigawords 53 integer
ATTRIBUTE Chap-Challenge 60 string
ATTRIBUTE NAS-Port-Type 61 integer
ATTRIBUTE Port-Limit 62 integer
--- a/pppd/plugins/radius/radius.c
+++ b/pppd/plugins/radius/radius.c
@@ -1020,12 +1020,22 @@ radius_acct_stop(void)
av_type = link_connect_time;
rc_avpair_add(&send, PW_ACCT_SESSION_TIME, &av_type, 0, VENDOR_NONE);
- av_type = link_stats.bytes_out;
+ av_type = link_stats.bytes_out & 0xFFFFFFFF;
rc_avpair_add(&send, PW_ACCT_OUTPUT_OCTETS, &av_type, 0, VENDOR_NONE);
- av_type = link_stats.bytes_in;
+ if (link_stats.bytes_out > 0xFFFFFFFF) {
+ av_type = link_stats.bytes_out >> 32;
+ rc_avpair_add(&send, PW_ACCT_OUTPUT_GIGAWORDS, &av_type, 0, VENDOR_NONE);
+ }
+
+ av_type = link_stats.bytes_in & 0xFFFFFFFF;
rc_avpair_add(&send, PW_ACCT_INPUT_OCTETS, &av_type, 0, VENDOR_NONE);
+ if (link_stats.bytes_in > 0xFFFFFFFF) {
+ av_type = link_stats.bytes_in >> 32;
+ rc_avpair_add(&send, PW_ACCT_INPUT_GIGAWORDS, &av_type, 0, VENDOR_NONE);
+ }
+
av_type = link_stats.pkts_out;
rc_avpair_add(&send, PW_ACCT_OUTPUT_PACKETS, &av_type, 0, VENDOR_NONE);
@@ -1172,12 +1182,22 @@ radius_acct_interim(void *ignored)
av_type = link_connect_time;
rc_avpair_add(&send, PW_ACCT_SESSION_TIME, &av_type, 0, VENDOR_NONE);
- av_type = link_stats.bytes_out;
+ av_type = link_stats.bytes_out & 0xFFFFFFFF;
rc_avpair_add(&send, PW_ACCT_OUTPUT_OCTETS, &av_type, 0, VENDOR_NONE);
- av_type = link_stats.bytes_in;
+ if (link_stats.bytes_out > 0xFFFFFFFF) {
+ av_type = link_stats.bytes_out >> 32;
+ rc_avpair_add(&send, PW_ACCT_OUTPUT_GIGAWORDS, &av_type, 0, VENDOR_NONE);
+ }
+
+ av_type = link_stats.bytes_in & 0xFFFFFFFF;
rc_avpair_add(&send, PW_ACCT_INPUT_OCTETS, &av_type, 0, VENDOR_NONE);
+ if (link_stats.bytes_in > 0xFFFFFFFF) {
+ av_type = link_stats.bytes_in >> 32;
+ rc_avpair_add(&send, PW_ACCT_INPUT_GIGAWORDS, &av_type, 0, VENDOR_NONE);
+ }
+
av_type = link_stats.pkts_out;
rc_avpair_add(&send, PW_ACCT_OUTPUT_PACKETS, &av_type, 0, VENDOR_NONE);
--- a/pppd/plugins/radius/radiusclient.h
+++ b/pppd/plugins/radius/radiusclient.h
@@ -184,6 +184,8 @@ typedef struct pw_auth_hdr
#define PW_ACCT_LINK_COUNT 51 /* integer */
/* From RFC 2869 */
+#define PW_ACCT_INPUT_GIGAWORDS 52 /* integer */
+#define PW_ACCT_OUTPUT_GIGAWORDS 53 /* integer */
#define PW_ACCT_INTERIM_INTERVAL 85 /* integer */
/* Merit Experimental Extensions */
--- a/pppd/pppd.h
+++ b/pppd/pppd.h
@@ -53,6 +53,7 @@
#include <stdlib.h> /* for encrypt */
#include <unistd.h> /* for setkey */
#include <stdarg.h>
+#include <stdint.h>
#include <limits.h> /* for NGROUPS_MAX */
#include <sys/param.h> /* for MAXPATHLEN and BSD4_4, if defined */
#include <sys/types.h> /* for u_int32_t, if defined */
@@ -173,8 +174,8 @@ struct permitted_ip {
* pppd needs.
*/
struct pppd_stats {
- unsigned int bytes_in;
- unsigned int bytes_out;
+ uint64_t bytes_in;
+ uint64_t bytes_out;
unsigned int pkts_in;
unsigned int pkts_out;
};
@@ -347,7 +348,7 @@ extern char *max_tls_version;
extern unsigned int maxoctets; /* Maximum octetes per session (in bytes) */
extern int maxoctets_dir; /* Direction :
0 - in+out (default)
- 1 - in
+ 1 - in
2 - out
3 - max(in,out) */
extern int maxoctets_timeout; /* Timeout for check of octets limit */
@@ -356,7 +357,7 @@ extern int maxoctets_timeout; /*
#define PPP_OCTETS_DIRECTION_OUT 2
#define PPP_OCTETS_DIRECTION_MAXOVERAL 3
/* same as previos, but little different on RADIUS side */
-#define PPP_OCTETS_DIRECTION_MAXSESSION 4
+#define PPP_OCTETS_DIRECTION_MAXSESSION 4
#endif
#ifdef PPP_FILTER
--- a/pppd/sys-linux.c
+++ b/pppd/sys-linux.c
@@ -79,6 +79,7 @@
#include <sys/sysmacros.h>
#include <errno.h>
+#include <stddef.h>
#include <stdio.h>
#include <stdlib.h>
#include <syslog.h>
@@ -92,6 +93,7 @@
#include <ctype.h>
#include <termios.h>
#include <unistd.h>
+#include <limits.h>
/* This is in netdevice.h. However, this compile will fail miserably if
you attempt to include netdevice.h because it has so many references
@@ -121,9 +123,19 @@
#include <linux/ppp_defs.h>
#include <linux/if_ppp.h>
-#ifdef INET6
#include <linux/netlink.h>
#include <linux/rtnetlink.h>
+#include <linux/if_link.h>
+/* Attempt at retaining compile-support with older than 4.7 kernels, or kernels
+ * where RTM_NEWSTATS isn't defined for whatever reason.
+ */
+#ifndef RTM_NEWSTATS
+#define RTM_NEWSTATS 92
+#define RTM_GETSTATS 94
+#define IFLA_STATS_LINK_64 1
+#endif
+
+#ifdef INET6
#include <linux/if_addr.h>
/* glibc versions prior to 2.24 do not define SOL_NETLINK */
#ifndef SOL_NETLINK
@@ -1407,11 +1419,17 @@ get_idle_time(int u, struct ppp_idle *ip
/********************************************************************
*
- * get_ppp_stats - return statistics for the link.
+ * get_ppp_stats_iocl - return statistics for the link, using the ioctl() method,
+ * this only supports 32-bit counters, so need to count the wraps.
*/
-int
-get_ppp_stats(int u, struct pppd_stats *stats)
+static int
+get_ppp_stats_ioctl(int u, struct pppd_stats *stats)
{
+ static u_int32_t previbytes = 0;
+ static u_int32_t prevobytes = 0;
+ static u_int32_t iwraps = 0;
+ static u_int32_t owraps = 0;
+
struct ifpppstatsreq req;
memset (&req, 0, sizeof (req));
@@ -1426,7 +1444,262 @@ get_ppp_stats(int u, struct pppd_stats *
stats->bytes_out = req.stats.p.ppp_obytes;
stats->pkts_in = req.stats.p.ppp_ipackets;
stats->pkts_out = req.stats.p.ppp_opackets;
+
+ if (stats->bytes_in < previbytes)
+ ++iwraps;
+ if (stats->bytes_out < prevobytes)
+ ++owraps;
+
+ previbytes = stats->bytes_in;
+ prevobytes = stats->bytes_out;
+
+ stats->bytes_in += (uint64_t)iwraps << 32;
+ stats->bytes_out += (uint64_t)owraps << 32;
+
+ return 1;
+}
+
+/********************************************************************
+ * get_ppp_stats_rtnetlink - return statistics for the link, using rtnetlink
+ * This provides native 64-bit counters.
+ */
+static int
+get_ppp_stats_rtnetlink(int u, struct pppd_stats *stats)
+{
+ static int rtnl_fd = -1;
+
+ struct sockaddr_nl nladdr;
+ struct {
+ struct nlmsghdr nlh;
+ struct if_stats_msg ifsm;
+ } nlreq;
+ struct nlresp {
+ struct nlmsghdr nlh;
+ union {
+ struct {
+ struct nlmsgerr nlerr;
+ char __end_err[0];
+ };
+ struct {
+ struct rtmsg rth;
+ struct {
+ /* We only case about these first fields from rtnl_link_stats64 */
+ uint64_t rx_packets;
+ uint64_t tx_packets;
+ uint64_t rx_bytes;
+ uint64_t tx_bytes;
+ } stats;
+ char __end_stats[0];
+ };
+ };
+ } nlresp;
+ ssize_t nlresplen;
+ struct iovec iov;
+ struct msghdr msg;
+
+ memset(&nladdr, 0, sizeof(nladdr));
+ nladdr.nl_family = AF_NETLINK;
+
+ if (rtnl_fd < 0) {
+ rtnl_fd = socket(AF_NETLINK, SOCK_RAW, NETLINK_ROUTE);
+ if (rtnl_fd < 0) {
+ error("get_ppp_stats_rtnetlink: error creating NETLINK socket: %m (line %d)", __LINE__);
+ return 0;
+ }
+
+ if (bind(rtnl_fd, (struct sockaddr *)&nladdr, sizeof(nladdr)) < 0) {
+ error("get_ppp_stats_rtnetlink: bind(AF_NETLINK): %m (line %d)", __LINE__);
+ goto err;
+ }
+ }
+
+ memset(&nlreq, 0, sizeof(nlreq));
+ nlreq.nlh.nlmsg_len = sizeof(nlreq);
+ nlreq.nlh.nlmsg_type = RTM_GETSTATS;
+ nlreq.nlh.nlmsg_flags = NLM_F_REQUEST;
+
+ nlreq.ifsm.ifindex = if_nametoindex(ifname);
+ nlreq.ifsm.filter_mask = IFLA_STATS_LINK_64;
+
+ memset(&iov, 0, sizeof(iov));
+ iov.iov_base = &nlreq;
+ iov.iov_len = sizeof(nlreq);
+
+ memset(&msg, 0, sizeof(msg));
+ msg.msg_name = &nladdr;
+ msg.msg_namelen = sizeof(nladdr);
+ msg.msg_iov = &iov;
+ msg.msg_iovlen = 1;
+
+ if (sendmsg(rtnl_fd, &msg, 0) < 0) {
+ error("get_ppp_stats_rtnetlink: sendmsg(RTM_GETSTATS): %m (line %d)", __LINE__);
+ goto err;
+ }
+
+ /* We just need to repoint to IOV ... everything else stays the same */
+ iov.iov_base = &nlresp;
+ iov.iov_len = sizeof(nlresp);
+
+ nlresplen = recvmsg(rtnl_fd, &msg, 0);
+
+ if (nlresplen < 0) {
+ error("get_ppp_stats_rtnetlink: recvmsg(RTM_GETSTATS): %m (line %d)", __LINE__);
+ goto err;
+ }
+
+ if (nlresplen < sizeof(nlresp.nlh)) {
+ error("get_ppp_stats_rtnetlink: Netlink response message was incomplete (line %d)", __LINE__);
+ goto err;
+ }
+
+ if (nlresp.nlh.nlmsg_type == NLMSG_ERROR) {
+ if (nlresplen < offsetof(struct nlresp, __end_err)) {
+ if (kernel_version >= KVERSION(4,7,0))
+ error("get_ppp_stats_rtnetlink: Netlink responded with error: %s (line %d)", strerror(-nlresp.nlerr.error), __LINE__);
+ } else {
+ error("get_ppp_stats_rtnetlink: Netlink responded with an error message, but the nlmsgerr structure is incomplete (line %d).",
+ __LINE__);
+ }
+ goto err;
+ }
+
+ if (nlresp.nlh.nlmsg_type != RTM_NEWSTATS) {
+ error("get_ppp_stats_rtnetlink: Expected RTM_NEWSTATS response, found something else (mlmsg_type %d, line %d)",
+ nlresp.nlh.nlmsg_type, __LINE__);
+ goto err;
+ }
+
+ if (nlresplen < offsetof(struct nlresp, __end_stats)) {
+ error("get_ppp_stats_rtnetlink: Obtained an insufficiently sized rtnl_link_stats64 struct from the kernel (line %d).", __LINE__);
+ goto err;
+ }
+
+ stats->bytes_in = nlresp.stats.rx_bytes;
+ stats->bytes_out = nlresp.stats.tx_bytes;
+ stats->pkts_in = nlresp.stats.rx_packets;
+ stats->pkts_out = nlresp.stats.tx_packets;
+
return 1;
+err:
+ close(rtnl_fd);
+ rtnl_fd = -1;
+ return 0;
+}
+
+/********************************************************************
+ * get_ppp_stats_sysfs - return statistics for the link, using the files in sysfs,
+ * this provides native 64-bit counters.
+ */
+static int
+get_ppp_stats_sysfs(int u, struct pppd_stats *stats)
+{
+ char fname[PATH_MAX+1];
+ char buf[21], *err; /* 2^64 < 10^20 */
+ int blen, fd, rlen;
+ unsigned long long val;
+
+ struct {
+ const char* fname;
+ void* ptr;
+ unsigned size;
+ } slist[] = {
+#define statfield(fn, field) { .fname = #fn, .ptr = &stats->field, .size = sizeof(stats->field) }
+ statfield(rx_bytes, bytes_in),
+ statfield(tx_bytes, bytes_out),
+ statfield(rx_packets, pkts_in),
+ statfield(tx_packets, pkts_out),
+#undef statfield
+ };
+
+ blen = snprintf(fname, sizeof(fname), "/sys/class/net/%s/statistics/", ifname);
+ if (blen >= sizeof(fname))
+ return 0; /* ifname max 15, so this should be impossible */
+
+ for (int i = 0; i < sizeof(slist) / sizeof(*slist); ++i) {
+ if (snprintf(fname + blen, sizeof(fname) - blen, "%s", slist[i].fname) >= sizeof(fname) - blen) {
+ fname[blen] = 0;
+ error("sysfs stats: filename %s/%s overflowed PATH_MAX", fname, slist[i].fname);
+ return 0;
+ }
+
+ fd = open(fname, O_RDONLY);
+ if (fd < 0) {
+ error("%s: %m", fname);
+ return 0;
+ }
+
+ rlen = read(fd, buf, sizeof(buf) - 1);
+ close(fd);
+ if (rlen < 0) {
+ error("%s: %m", fname);
+ return 0;
+ }
+ /* trim trailing \n if present */
+ while (rlen > 0 && buf[rlen-1] == '\n')
+ rlen--;
+ buf[rlen] = 0;
+
+ errno = 0;
+ val = strtoull(buf, &err, 10);
+ if (*buf < '0' || *buf > '9' || errno != 0 || *err) {
+ error("string to number conversion error converting %s (from %s) for remaining string %s%s%s",
+ buf, fname, err, errno ? ": " : "", errno ? strerror(errno) : "");
+ return 0;
+ }
+ switch (slist[i].size) {
+#define stattype(type) case sizeof(type): *(type*)slist[i].ptr = (type)val; break
+ stattype(uint64_t);
+ stattype(uint32_t);
+ stattype(uint16_t);
+ stattype(uint8_t);
+#undef stattype
+ default:
+ error("Don't know how to store stats for %s of size %u", slist[i].fname, slist[i].size);
+ return 0;
+ }
+ }
+
+ return 1;
+}
+
+/********************************************************************
+ * Periodic timer function to be used to keep stats up to date in case of ioctl
+ * polling.
+ *
+ * Given the 25s interval this should be fine up to data rates of 1.37Gbps.
+ * If you do change the timer, remember to also bring the get_ppp_stats (which
+ * sets up the initial trigger) as well.
+ */
+static void
+ppp_stats_poller(void* u)
+{
+ struct pppd_stats dummy;
+ get_ppp_stats_ioctl((long)u, &dummy);
+ TIMEOUT(ppp_stats_poller, u, 25);
+}
+
+/********************************************************************
+ * get_ppp_stats - return statistics for the link.
+ */
+int get_ppp_stats(int u, struct pppd_stats *stats)
+{
+ static int (*func)(int, struct pppd_stats*) = NULL;
+
+ if (!func) {
+ if (get_ppp_stats_rtnetlink(u, stats)) {
+ func = get_ppp_stats_rtnetlink;
+ return 1;
+ }
+ if (get_ppp_stats_sysfs(u, stats)) {
+ func = get_ppp_stats_sysfs;
+ return 1;
+ }
+ warn("statistics falling back to ioctl which only supports 32-bit counters");
+ func = get_ppp_stats_ioctl;
+ TIMEOUT(ppp_stats_poller, (void*)(long)u, 25);
+ }
+
+ return func(u, stats);
}
/********************************************************************

View File

@ -0,0 +1,299 @@
From 4a54e34cf5629f9fed61f0b7d69ee3ba4d874bc6 Mon Sep 17 00:00:00 2001
From: =?UTF-8?q?Pali=20Roh=C3=A1r?= <pali@kernel.org>
Date: Sat, 9 Jul 2022 13:40:24 +0200
Subject: [PATCH] pppd: Add support for registering ppp interface via Linux
rtnetlink API
MIME-Version: 1.0
Content-Type: text/plain; charset=UTF-8
Content-Transfer-Encoding: 8bit
pppd currently creates ppp network interface via PPPIOCNEWUNIT ioctl API.
This API creates a new ppp network interface named "ppp<unit_id>". If user
supply option "ifname" with custom network name then pppd calls SIOCSIFNAME
ioctl to rename "ppp<unit_id>" to custom name immediately after successful
PPPIOCNEWUNIT ioctl call. If custom name is already registered then
SIOCSIFNAME ioctl fails and pppd close current channel (which destroy also
network interface).
This has side effect that in the first few miliseconds interface has
different name as what user supplied.
Tools like systemd, udev or NetworkManager are trying to query
interface attributes based on interface name immediately when new
network interface is created.
But if interface is renamed immediately after creation then these tools
fails. For example when running pppd with option "ifname ppp-wan" following
error is reported by systemd / udev into dmesg log:
[ 35.718732] PPP generic driver version 2.4.2
[ 35.793914] NET: Registered protocol family 24
[ 35.889924] systemd-udevd[1852]: link_config: autonegotiation is unset or enabled, the speed and duplex are not writable.
[ 35.901450] ppp-wan: renamed from ppp0
[ 35.930332] systemd-udevd[1852]: link_config: could not get ethtool features for ppp0
[ 35.939473] systemd-udevd[1852]: Could not set offload features of ppp0: No such device
There is an easy way to fix this issue: Use new rtnetlink API.
Via rtnetlink API it is possible to create ppp network interface with
custom ifname atomically. Just it is not possible to specify custom ppp
unit id.
So use new rtnetlink API when user requested custom ifname without custom
ppp unit id. This will avoid system issues with interface renaming as ppp
interface is directly registered with specified final name.
This has also advantage that if requested interface name already exists
then pppd fail during registering of networking interface and not during
renaming network interface which happens after successful registration.
If user supply custom ppp unit id then it is required to use old ioctl API
as currently it is the only API which allows specifying ppp unit id.
When user does not specify custom ifname stay also with old ioctl API.
There is currently a bug in kernel which cause that when empty interface is
specified in rtnetlink message for creating ppp interface then kernel
creates ppp interface but with pseudo-random name, not derived from ppp
unit id. And therefore it is not possible to retrieve what is the name of
newly created network interface. So when user does not specify interface
name via "ifname" option (which means that want from kernel to choose some
"free" interface name) it is needed to use old ioctl API which do it
correctly for now.
Signed-off-by: Pali Rohár <pali@kernel.org>
---
pppd/sys-linux.c | 194 ++++++++++++++++++++++++++++++++++++++++++++++-
1 file changed, 192 insertions(+), 2 deletions(-)
--- a/pppd/sys-linux.c
+++ b/pppd/sys-linux.c
@@ -126,6 +126,11 @@
#include <linux/netlink.h>
#include <linux/rtnetlink.h>
#include <linux/if_link.h>
+
+#ifdef INET6
+#include <linux/if_addr.h>
+#endif
+
/* Attempt at retaining compile-support with older than 4.7 kernels, or kernels
* where RTM_NEWSTATS isn't defined for whatever reason.
*/
@@ -135,16 +140,20 @@
#define IFLA_STATS_LINK_64 1
#endif
-#ifdef INET6
-#include <linux/if_addr.h>
/* glibc versions prior to 2.24 do not define SOL_NETLINK */
#ifndef SOL_NETLINK
#define SOL_NETLINK 270
#endif
+
/* linux kernel versions prior to 4.3 do not define/support NETLINK_CAP_ACK */
#ifndef NETLINK_CAP_ACK
#define NETLINK_CAP_ACK 10
#endif
+
+/* linux kernel versions prior to 4.7 do not define/support IFLA_PPP_DEV_FD */
+#ifndef IFLA_PPP_MAX
+/* IFLA_PPP_DEV_FD is declared as enum when IFLA_PPP_MAX is defined */
+#define IFLA_PPP_DEV_FD 1
#endif
#include "pppd.h"
@@ -657,6 +666,160 @@ void generic_disestablish_ppp(int dev_fd
}
/*
+ * make_ppp_unit_rtnetlink - register a new ppp network interface for ppp_dev_fd
+ * with specified req_ifname via rtnetlink. Interface name req_ifname must not
+ * be empty. Custom ppp unit id req_unit is ignored and kernel choose some free.
+ */
+static int make_ppp_unit_rtnetlink(void)
+{
+ struct {
+ struct nlmsghdr nlh;
+ struct ifinfomsg ifm;
+ struct {
+ struct rtattr rta;
+ char ifname[IFNAMSIZ];
+ } ifn;
+ struct {
+ struct rtattr rta;
+ struct {
+ struct rtattr rta;
+ char ifkind[sizeof("ppp")];
+ } ifik;
+ struct {
+ struct rtattr rta;
+ struct {
+ struct rtattr rta;
+ union {
+ int ppp_dev_fd;
+ } ppp;
+ } ifdata[1];
+ } ifid;
+ } ifli;
+ } nlreq;
+ struct {
+ struct nlmsghdr nlh;
+ struct nlmsgerr nlerr;
+ } nlresp;
+ struct sockaddr_nl nladdr;
+ struct iovec iov;
+ struct msghdr msg;
+ ssize_t nlresplen;
+ int one;
+ int fd;
+
+ fd = socket(AF_NETLINK, SOCK_RAW, NETLINK_ROUTE);
+ if (fd < 0) {
+ error("make_ppp_unit_rtnetlink: socket(NETLINK_ROUTE): %m (line %d)", __LINE__);
+ return 0;
+ }
+
+ /* Tell kernel to not send to us payload of acknowledgment error message. */
+ one = 1;
+ setsockopt(fd, SOL_NETLINK, NETLINK_CAP_ACK, &one, sizeof(one));
+
+ memset(&nladdr, 0, sizeof(nladdr));
+ nladdr.nl_family = AF_NETLINK;
+
+ if (bind(fd, (struct sockaddr *)&nladdr, sizeof(nladdr)) < 0) {
+ error("make_ppp_unit_rtnetlink: bind(AF_NETLINK): %m (line %d)", __LINE__);
+ close(fd);
+ return 0;
+ }
+
+ memset(&nlreq, 0, sizeof(nlreq));
+ nlreq.nlh.nlmsg_len = sizeof(nlreq);
+ nlreq.nlh.nlmsg_type = RTM_NEWLINK;
+ nlreq.nlh.nlmsg_flags = NLM_F_REQUEST | NLM_F_ACK | NLM_F_EXCL | NLM_F_CREATE;
+ nlreq.ifm.ifi_family = AF_UNSPEC;
+ nlreq.ifm.ifi_type = ARPHRD_NETROM;
+ nlreq.ifn.rta.rta_len = sizeof(nlreq.ifn);
+ nlreq.ifn.rta.rta_type = IFLA_IFNAME;
+ strlcpy(nlreq.ifn.ifname, req_ifname, sizeof(nlreq.ifn.ifname));
+ nlreq.ifli.rta.rta_len = sizeof(nlreq.ifli);
+ nlreq.ifli.rta.rta_type = IFLA_LINKINFO;
+ nlreq.ifli.ifik.rta.rta_len = sizeof(nlreq.ifli.ifik);
+ nlreq.ifli.ifik.rta.rta_type = IFLA_INFO_KIND;
+ strcpy(nlreq.ifli.ifik.ifkind, "ppp");
+ nlreq.ifli.ifid.rta.rta_len = sizeof(nlreq.ifli.ifid);
+ nlreq.ifli.ifid.rta.rta_type = IFLA_INFO_DATA;
+ nlreq.ifli.ifid.ifdata[0].rta.rta_len = sizeof(nlreq.ifli.ifid.ifdata[0]);
+ nlreq.ifli.ifid.ifdata[0].rta.rta_type = IFLA_PPP_DEV_FD;
+ nlreq.ifli.ifid.ifdata[0].ppp.ppp_dev_fd = ppp_dev_fd;
+
+ memset(&nladdr, 0, sizeof(nladdr));
+ nladdr.nl_family = AF_NETLINK;
+
+ memset(&iov, 0, sizeof(iov));
+ iov.iov_base = &nlreq;
+ iov.iov_len = sizeof(nlreq);
+
+ memset(&msg, 0, sizeof(msg));
+ msg.msg_name = &nladdr;
+ msg.msg_namelen = sizeof(nladdr);
+ msg.msg_iov = &iov;
+ msg.msg_iovlen = 1;
+
+ if (sendmsg(fd, &msg, 0) < 0) {
+ error("make_ppp_unit_rtnetlink: sendmsg(RTM_NEWLINK/NLM_F_CREATE): %m (line %d)", __LINE__);
+ close(fd);
+ return 0;
+ }
+
+ memset(&iov, 0, sizeof(iov));
+ iov.iov_base = &nlresp;
+ iov.iov_len = sizeof(nlresp);
+
+ memset(&msg, 0, sizeof(msg));
+ msg.msg_name = &nladdr;
+ msg.msg_namelen = sizeof(nladdr);
+ msg.msg_iov = &iov;
+ msg.msg_iovlen = 1;
+
+ nlresplen = recvmsg(fd, &msg, 0);
+
+ if (nlresplen < 0) {
+ error("make_ppp_unit_rtnetlink: recvmsg(NLM_F_ACK): %m (line %d)", __LINE__);
+ close(fd);
+ return 0;
+ }
+
+ close(fd);
+
+ if (nladdr.nl_family != AF_NETLINK) {
+ error("make_ppp_unit_rtnetlink: recvmsg(NLM_F_ACK): Not a netlink packet (line %d)", __LINE__);
+ return 0;
+ }
+
+ if ((size_t)nlresplen < sizeof(nlresp) || nlresp.nlh.nlmsg_len < sizeof(nlresp)) {
+ error("make_ppp_unit_rtnetlink: recvmsg(NLM_F_ACK): Acknowledgment netlink packet too short (line %d)", __LINE__);
+ return 0;
+ }
+
+ /* acknowledgment packet for NLM_F_ACK is NLMSG_ERROR */
+ if (nlresp.nlh.nlmsg_type != NLMSG_ERROR) {
+ error("make_ppp_unit_rtnetlink: recvmsg(NLM_F_ACK): Not an acknowledgment netlink packet (line %d)", __LINE__);
+ return 0;
+ }
+
+ /* error == 0 indicates success, negative value is errno code */
+ if (nlresp.nlerr.error != 0) {
+ /*
+ * Linux kernel versions prior to 4.7 do not support creating ppp
+ * interfaces via rtnetlink API and therefore error response is
+ * expected. On older kernel versions do not show this error message.
+ * When error is different than EEXIST then pppd tries to fallback to
+ * the old ioctl method.
+ */
+ errno = (nlresp.nlerr.error < 0) ? -nlresp.nlerr.error : EINVAL;
+ if (kernel_version >= KVERSION(4,7,0))
+ error("Couldn't create ppp interface %s: %m", req_ifname);
+ return 0;
+ }
+
+ return 1;
+}
+
+/*
* make_ppp_unit - make a new ppp unit for ppp_dev_fd.
* Assumes new_style_driver.
*/
@@ -676,6 +839,33 @@ static int make_ppp_unit(void)
|| fcntl(ppp_dev_fd, F_SETFL, flags | O_NONBLOCK) == -1)
warn("Couldn't set /dev/ppp to nonblock: %m");
+ /*
+ * Via rtnetlink it is possible to create ppp network interface with
+ * custom ifname atomically. But it is not possible to specify custom
+ * ppp unit id.
+ *
+ * Tools like systemd, udev or NetworkManager are trying to query
+ * interface attributes based on interface name immediately when new
+ * network interface is created. And therefore immediate interface
+ * renaming is causing issues.
+ *
+ * So use rtnetlink API only when user requested custom ifname. It will
+ * avoid system issues with interface renaming.
+ */
+ if (req_unit == -1 && req_ifname[0] != '\0' && kernel_version >= KVERSION(2,1,16)) {
+ if (make_ppp_unit_rtnetlink()) {
+ if (ioctl(ppp_dev_fd, PPPIOCGUNIT, &ifunit))
+ fatal("Couldn't retrieve PPP unit id: %m");
+ return 0;
+ }
+ /*
+ * If interface with requested name already exist return error
+ * otherwise fallback to old ioctl method.
+ */
+ if (errno == EEXIST)
+ return -1;
+ }
+
ifunit = req_unit;
x = ioctl(ppp_dev_fd, PPPIOCNEWUNIT, &ifunit);
if (x < 0 && req_unit >= 0 && errno == EEXIST) {

View File

@ -0,0 +1,59 @@
From 44609bfc974bdafc0316d069aabf5e2903efa805 Mon Sep 17 00:00:00 2001
From: pali <7141871+pali@users.noreply.github.com>
Date: Tue, 9 Aug 2022 11:20:15 +0200
Subject: [PATCH] pppd: Workaround for generating ppp unit id on Linux (#355)
MIME-Version: 1.0
Content-Type: text/plain; charset=UTF-8
Content-Transfer-Encoding: 8bit
Linux kernel has nasty bug / feature. If PPPIOCNEWUNIT is called with
negative ppp unit id (which is default option when command line argument
"unit" is not specified; and tells kernel to choose some free ppp unit id)
and the lowest unused/free ppp unit id is present in some existing network
interface name prefixed by "ppp" string then this PPPIOCNEWUNIT ioctl
fails. In this case kernel is basically unable to create a new ppp
interface via PPPIOCNEWUNIT ioctl when user does not specify some unused
and non-conflicted unit id.
Linux kernel should be fixed to choose usable ppp unit id when was
requested via PPPIOCNEWUNIT parameter -1.
Until this happens, add a workaround for pppd to help choosing some random
ppp unit id when kernel returns this error.
Simple test case (run on system when there is no ppp interface):
sudo ./pppd ifname ppp1 nodefaultroute noauth nolock local nodetach pty "./pppd nodefaultroute noauth nolock local nodetach notty"
Second pppd process without this patch prints into syslog following error:
pppd 2.4.10-dev started by pali, uid 0
Couldn't create new ppp unit: File exists
Exit.
With this patch it falls back to random ppp unit id and succeeds:
pppd 2.4.10-dev started by pali, uid 0
Using interface ppp1361
Connect: ppp1361 <--> /dev/pts/14
...
Signed-off-by: Pali Rohár <pali@kernel.org>
---
pppd/sys-linux.c | 5 +++++
1 file changed, 5 insertions(+)
--- a/pppd/sys-linux.c
+++ b/pppd/sys-linux.c
@@ -873,6 +873,11 @@ static int make_ppp_unit(void)
ifunit = -1;
x = ioctl(ppp_dev_fd, PPPIOCNEWUNIT, &ifunit);
}
+ if (x < 0 && errno == EEXIST) {
+ srand(time(NULL) * getpid());
+ ifunit = rand() % 10000;
+ x = ioctl(ppp_dev_fd, PPPIOCNEWUNIT, &ifunit);
+ }
if (x < 0)
error("Couldn't create new ppp unit: %m");

View File

@ -0,0 +1,218 @@
From 089687fbcc6524809ae9f4b2f8145fe3c2a91147 Mon Sep 17 00:00:00 2001
From: =?UTF-8?q?Pali=20Roh=C3=A1r?= <pali@kernel.org>
Date: Sat, 7 Aug 2021 19:48:01 +0200
Subject: [PATCH] pppd: Retry registering interface when on rtnetlink -EBUSY
error
MIME-Version: 1.0
Content-Type: text/plain; charset=UTF-8
Content-Transfer-Encoding: 8bit
Due to workaround in kernel module ppp_generic.ko in function
ppp_nl_newlink(), kernel may return -EBUSY error to prevent possible
mutex deadlock. In this case userspace needs to retry its request.
Proper way would be to fix kernel module to order requests and mutex
locking, so prevent deadlock in kernel and so never return this error to
userspace. Until it happens we need retry code in userspace.
Signed-off-by: Pali Rohár <pali@kernel.org>
[ backport to ppp 2.4.9 ]
Signed-off-by: Christian Marangi <ansuelsmth@gmail.com>
---
pppd/sys-linux.c | 9 ++++++++-
1 file changed, 8 insertions(+), 1 deletion(-)
--- a/pppd/sys-linux.c
+++ b/pppd/sys-linux.c
@@ -707,99 +707,101 @@ static int make_ppp_unit_rtnetlink(void)
int one;
int fd;
- fd = socket(AF_NETLINK, SOCK_RAW, NETLINK_ROUTE);
- if (fd < 0) {
- error("make_ppp_unit_rtnetlink: socket(NETLINK_ROUTE): %m (line %d)", __LINE__);
- return 0;
- }
-
- /* Tell kernel to not send to us payload of acknowledgment error message. */
- one = 1;
- setsockopt(fd, SOL_NETLINK, NETLINK_CAP_ACK, &one, sizeof(one));
+ do {
+ fd = socket(AF_NETLINK, SOCK_RAW, NETLINK_ROUTE);
+ if (fd < 0) {
+ error("make_ppp_unit_rtnetlink: socket(NETLINK_ROUTE): %m (line %d)", __LINE__);
+ return 0;
+ }
+
+ /* Tell kernel to not send to us payload of acknowledgment error message. */
+ one = 1;
+ setsockopt(fd, SOL_NETLINK, NETLINK_CAP_ACK, &one, sizeof(one));
+
+ memset(&nladdr, 0, sizeof(nladdr));
+ nladdr.nl_family = AF_NETLINK;
+
+ if (bind(fd, (struct sockaddr *)&nladdr, sizeof(nladdr)) < 0) {
+ error("make_ppp_unit_rtnetlink: bind(AF_NETLINK): %m (line %d)", __LINE__);
+ close(fd);
+ return 0;
+ }
+
+ memset(&nlreq, 0, sizeof(nlreq));
+ nlreq.nlh.nlmsg_len = sizeof(nlreq);
+ nlreq.nlh.nlmsg_type = RTM_NEWLINK;
+ nlreq.nlh.nlmsg_flags = NLM_F_REQUEST | NLM_F_ACK | NLM_F_EXCL | NLM_F_CREATE;
+ nlreq.ifm.ifi_family = AF_UNSPEC;
+ nlreq.ifm.ifi_type = ARPHRD_NETROM;
+ nlreq.ifn.rta.rta_len = sizeof(nlreq.ifn);
+ nlreq.ifn.rta.rta_type = IFLA_IFNAME;
+ strlcpy(nlreq.ifn.ifname, req_ifname, sizeof(nlreq.ifn.ifname));
+ nlreq.ifli.rta.rta_len = sizeof(nlreq.ifli);
+ nlreq.ifli.rta.rta_type = IFLA_LINKINFO;
+ nlreq.ifli.ifik.rta.rta_len = sizeof(nlreq.ifli.ifik);
+ nlreq.ifli.ifik.rta.rta_type = IFLA_INFO_KIND;
+ strcpy(nlreq.ifli.ifik.ifkind, "ppp");
+ nlreq.ifli.ifid.rta.rta_len = sizeof(nlreq.ifli.ifid);
+ nlreq.ifli.ifid.rta.rta_type = IFLA_INFO_DATA;
+ nlreq.ifli.ifid.ifdata[0].rta.rta_len = sizeof(nlreq.ifli.ifid.ifdata[0]);
+ nlreq.ifli.ifid.ifdata[0].rta.rta_type = IFLA_PPP_DEV_FD;
+ nlreq.ifli.ifid.ifdata[0].ppp.ppp_dev_fd = ppp_dev_fd;
+
+ memset(&nladdr, 0, sizeof(nladdr));
+ nladdr.nl_family = AF_NETLINK;
+
+ memset(&iov, 0, sizeof(iov));
+ iov.iov_base = &nlreq;
+ iov.iov_len = sizeof(nlreq);
+
+ memset(&msg, 0, sizeof(msg));
+ msg.msg_name = &nladdr;
+ msg.msg_namelen = sizeof(nladdr);
+ msg.msg_iov = &iov;
+ msg.msg_iovlen = 1;
+
+ if (sendmsg(fd, &msg, 0) < 0) {
+ error("make_ppp_unit_rtnetlink: sendmsg(RTM_NEWLINK/NLM_F_CREATE): %m (line %d)", __LINE__);
+ close(fd);
+ return 0;
+ }
+
+ memset(&iov, 0, sizeof(iov));
+ iov.iov_base = &nlresp;
+ iov.iov_len = sizeof(nlresp);
+
+ memset(&msg, 0, sizeof(msg));
+ msg.msg_name = &nladdr;
+ msg.msg_namelen = sizeof(nladdr);
+ msg.msg_iov = &iov;
+ msg.msg_iovlen = 1;
+
+ nlresplen = recvmsg(fd, &msg, 0);
+
+ if (nlresplen < 0) {
+ error("make_ppp_unit_rtnetlink: recvmsg(NLM_F_ACK): %m (line %d)", __LINE__);
+ close(fd);
+ return 0;
+ }
- memset(&nladdr, 0, sizeof(nladdr));
- nladdr.nl_family = AF_NETLINK;
-
- if (bind(fd, (struct sockaddr *)&nladdr, sizeof(nladdr)) < 0) {
- error("make_ppp_unit_rtnetlink: bind(AF_NETLINK): %m (line %d)", __LINE__);
close(fd);
- return 0;
- }
-
- memset(&nlreq, 0, sizeof(nlreq));
- nlreq.nlh.nlmsg_len = sizeof(nlreq);
- nlreq.nlh.nlmsg_type = RTM_NEWLINK;
- nlreq.nlh.nlmsg_flags = NLM_F_REQUEST | NLM_F_ACK | NLM_F_EXCL | NLM_F_CREATE;
- nlreq.ifm.ifi_family = AF_UNSPEC;
- nlreq.ifm.ifi_type = ARPHRD_NETROM;
- nlreq.ifn.rta.rta_len = sizeof(nlreq.ifn);
- nlreq.ifn.rta.rta_type = IFLA_IFNAME;
- strlcpy(nlreq.ifn.ifname, req_ifname, sizeof(nlreq.ifn.ifname));
- nlreq.ifli.rta.rta_len = sizeof(nlreq.ifli);
- nlreq.ifli.rta.rta_type = IFLA_LINKINFO;
- nlreq.ifli.ifik.rta.rta_len = sizeof(nlreq.ifli.ifik);
- nlreq.ifli.ifik.rta.rta_type = IFLA_INFO_KIND;
- strcpy(nlreq.ifli.ifik.ifkind, "ppp");
- nlreq.ifli.ifid.rta.rta_len = sizeof(nlreq.ifli.ifid);
- nlreq.ifli.ifid.rta.rta_type = IFLA_INFO_DATA;
- nlreq.ifli.ifid.ifdata[0].rta.rta_len = sizeof(nlreq.ifli.ifid.ifdata[0]);
- nlreq.ifli.ifid.ifdata[0].rta.rta_type = IFLA_PPP_DEV_FD;
- nlreq.ifli.ifid.ifdata[0].ppp.ppp_dev_fd = ppp_dev_fd;
-
- memset(&nladdr, 0, sizeof(nladdr));
- nladdr.nl_family = AF_NETLINK;
-
- memset(&iov, 0, sizeof(iov));
- iov.iov_base = &nlreq;
- iov.iov_len = sizeof(nlreq);
-
- memset(&msg, 0, sizeof(msg));
- msg.msg_name = &nladdr;
- msg.msg_namelen = sizeof(nladdr);
- msg.msg_iov = &iov;
- msg.msg_iovlen = 1;
-
- if (sendmsg(fd, &msg, 0) < 0) {
- error("make_ppp_unit_rtnetlink: sendmsg(RTM_NEWLINK/NLM_F_CREATE): %m (line %d)", __LINE__);
- close(fd);
- return 0;
- }
-
- memset(&iov, 0, sizeof(iov));
- iov.iov_base = &nlresp;
- iov.iov_len = sizeof(nlresp);
-
- memset(&msg, 0, sizeof(msg));
- msg.msg_name = &nladdr;
- msg.msg_namelen = sizeof(nladdr);
- msg.msg_iov = &iov;
- msg.msg_iovlen = 1;
-
- nlresplen = recvmsg(fd, &msg, 0);
-
- if (nlresplen < 0) {
- error("make_ppp_unit_rtnetlink: recvmsg(NLM_F_ACK): %m (line %d)", __LINE__);
- close(fd);
- return 0;
- }
-
- close(fd);
- if (nladdr.nl_family != AF_NETLINK) {
- error("make_ppp_unit_rtnetlink: recvmsg(NLM_F_ACK): Not a netlink packet (line %d)", __LINE__);
- return 0;
- }
-
- if ((size_t)nlresplen < sizeof(nlresp) || nlresp.nlh.nlmsg_len < sizeof(nlresp)) {
- error("make_ppp_unit_rtnetlink: recvmsg(NLM_F_ACK): Acknowledgment netlink packet too short (line %d)", __LINE__);
- return 0;
- }
-
- /* acknowledgment packet for NLM_F_ACK is NLMSG_ERROR */
- if (nlresp.nlh.nlmsg_type != NLMSG_ERROR) {
- error("make_ppp_unit_rtnetlink: recvmsg(NLM_F_ACK): Not an acknowledgment netlink packet (line %d)", __LINE__);
- return 0;
- }
+ if (nladdr.nl_family != AF_NETLINK) {
+ error("make_ppp_unit_rtnetlink: recvmsg(NLM_F_ACK): Not a netlink packet (line %d)", __LINE__);
+ return 0;
+ }
+
+ if ((size_t)nlresplen < sizeof(nlresp) || nlresp.nlh.nlmsg_len < sizeof(nlresp)) {
+ error("make_ppp_unit_rtnetlink: recvmsg(NLM_F_ACK): Acknowledgment netlink packet too short (line %d)", __LINE__);
+ return 0;
+ }
+
+ /* acknowledgment packet for NLM_F_ACK is NLMSG_ERROR */
+ if (nlresp.nlh.nlmsg_type != NLMSG_ERROR) {
+ error("make_ppp_unit_rtnetlink: recvmsg(NLM_F_ACK): Not an acknowledgment netlink packet (line %d)", __LINE__);
+ return 0;
+ }
+ } while (nlresp.nlerr.error == -EBUSY);
/* error == 0 indicates success, negative value is errno code */
if (nlresp.nlerr.error != 0) {

View File

@ -12,7 +12,7 @@ Signed-off-by: Jo-Philipp Wich <jo@mein.io>
--- a/pppd/main.c
+++ b/pppd/main.c
@@ -1034,7 +1034,8 @@ get_input(void)
@@ -1035,7 +1035,8 @@ get_input(void)
}
notice("Modem hangup");
hungup = 1;

View File

@ -119,7 +119,7 @@ Signed-off-by: George Kashperko <george@znau.edu.ua>
&& memcmp(vd.dptr, key.dptr, vd.dsize) == 0;
--- a/pppd/sys-linux.c
+++ b/pppd/sys-linux.c
@@ -706,6 +706,16 @@ void cfg_bundle(int mrru, int mtru, int
@@ -923,6 +923,16 @@ void cfg_bundle(int mrru, int mtru, int
add_fd(ppp_dev_fd);
}
@ -136,7 +136,7 @@ Signed-off-by: George Kashperko <george@znau.edu.ua>
/*
* make_new_bundle - create a new PPP unit (i.e. a bundle)
* and connect our channel to it. This should only get called
@@ -724,6 +734,8 @@ void make_new_bundle(int mrru, int mtru,
@@ -941,6 +951,8 @@ void make_new_bundle(int mrru, int mtru,
/* set the mrru and flags */
cfg_bundle(mrru, mtru, rssn, tssn);

View File

@ -12,7 +12,7 @@ Signed-off-by: Jo-Philipp Wich <jo@mein.io>
--- a/pppd/sys-linux.c
+++ b/pppd/sys-linux.c
@@ -1770,6 +1770,7 @@ int cifdefaultroute (int unit, u_int32_t
@@ -2248,6 +2248,7 @@ int cifdefaultroute (int unit, u_int32_t
SIN_ADDR(rt.rt_genmask) = 0L;
}

View File

@ -13,7 +13,7 @@ Signed-off-by: Jo-Philipp Wich <jo@mein.io>
--- a/pppd/sys-linux.c
+++ b/pppd/sys-linux.c
@@ -1720,6 +1720,9 @@ int sifdefaultroute (int unit, u_int32_t
@@ -2198,6 +2198,9 @@ int sifdefaultroute (int unit, u_int32_t
memset (&rt, 0, sizeof (rt));
SET_SA_FAMILY (rt.rt_dst, AF_INET);
@ -23,7 +23,7 @@ Signed-off-by: Jo-Philipp Wich <jo@mein.io>
rt.rt_dev = ifname;
rt.rt_metric = dfl_route_metric + 1; /* +1 for binary compatibility */
@@ -1728,7 +1731,7 @@ int sifdefaultroute (int unit, u_int32_t
@@ -2206,7 +2209,7 @@ int sifdefaultroute (int unit, u_int32_t
SIN_ADDR(rt.rt_genmask) = 0L;
}

View File

@ -10,7 +10,7 @@ Signed-off-by: Jo-Philipp Wich <jo@mein.io>
--- a/pppd/sys-linux.c
+++ b/pppd/sys-linux.c
@@ -206,7 +206,7 @@ static int driver_is_old = 0;
@@ -235,7 +235,7 @@ static int driver_is_old = 0;
static int restore_term = 0; /* 1 => we've munged the terminal */
static struct termios inittermios; /* Initial TTY termios */
@ -19,7 +19,7 @@ Signed-off-by: Jo-Philipp Wich <jo@mein.io>
static char loop_name[20];
static unsigned char inbuf[512]; /* buffer for chars read from loopback */
@@ -225,8 +225,8 @@ static int looped; /* 1 if using loop
@@ -254,8 +254,8 @@ static int looped; /* 1 if using loop
static int link_mtu; /* mtu for the link (not bundle) */
static struct utsname utsname; /* for the kernel version */
@ -29,7 +29,7 @@ Signed-off-by: Jo-Philipp Wich <jo@mein.io>
#define MAX_IFS 100
@@ -1455,11 +1455,12 @@ int ccp_fatal_error (int unit)
@@ -1933,11 +1933,12 @@ int ccp_fatal_error (int unit)
*
* path_to_procfs - find the path to the proc file system mount point
*/
@ -44,7 +44,7 @@ Signed-off-by: Jo-Philipp Wich <jo@mein.io>
struct mntent *mntent;
FILE *fp;
@@ -1481,6 +1482,7 @@ static char *path_to_procfs(const char *
@@ -1959,6 +1960,7 @@ static char *path_to_procfs(const char *
fclose (fp);
}
}
@ -52,7 +52,7 @@ Signed-off-by: Jo-Philipp Wich <jo@mein.io>
strlcpy(proc_path + proc_path_len, tail,
sizeof(proc_path) - proc_path_len);
@@ -2365,15 +2367,19 @@ int ppp_available(void)
@@ -2843,15 +2845,19 @@ int ppp_available(void)
int my_version, my_modification, my_patch;
int osmaj, osmin, ospatch;
@ -72,7 +72,7 @@ Signed-off-by: Jo-Philipp Wich <jo@mein.io>
/* XXX should get from driver */
driver_version = 2;
@@ -2433,6 +2439,7 @@ int ppp_available(void)
@@ -2911,6 +2917,7 @@ int ppp_available(void)
if (ok && ((ifr.ifr_hwaddr.sa_family & ~0xFF) != ARPHRD_PPP))
ok = 0;
@ -80,7 +80,7 @@ Signed-off-by: Jo-Philipp Wich <jo@mein.io>
/*
* This is the PPP device. Validate the version of the driver at this
@@ -3106,6 +3113,7 @@ get_pty(int *master_fdp, int *slave_fdp,
@@ -3592,6 +3599,7 @@ get_pty(int *master_fdp, int *slave_fdp,
}
#endif /* TIOCGPTN */
@ -88,7 +88,7 @@ Signed-off-by: Jo-Philipp Wich <jo@mein.io>
if (sfd < 0) {
/* the old way - scan through the pty name space */
for (i = 0; i < 64; ++i) {
@@ -3124,6 +3132,7 @@ get_pty(int *master_fdp, int *slave_fdp,
@@ -3610,6 +3618,7 @@ get_pty(int *master_fdp, int *slave_fdp,
}
}
}

View File

@ -7,7 +7,7 @@ Signed-off-by: Jo-Philipp Wich <jo@mein.io>
--- a/pppd/pppd.h
+++ b/pppd/pppd.h
@@ -317,7 +317,6 @@ extern int holdoff; /* Dead time before
@@ -318,7 +318,6 @@ extern int holdoff; /* Dead time before
extern bool holdoff_specified; /* true if user gave a holdoff value */
extern bool notty; /* Stdin/out is not a tty */
extern char *pty_socket; /* Socket to connect to pty */

View File

@ -7,7 +7,7 @@ Signed-off-by: Jo-Philipp Wich <jo@mein.io>
--- a/pppd/sys-linux.c
+++ b/pppd/sys-linux.c
@@ -2503,6 +2503,7 @@ int ppp_available(void)
@@ -2981,6 +2981,7 @@ int ppp_available(void)
void logwtmp (const char *line, const char *name, const char *host)
{
@ -15,7 +15,7 @@ Signed-off-by: Jo-Philipp Wich <jo@mein.io>
struct utmp ut, *utp;
pid_t mypid = getpid();
#if __GLIBC__ < 2
@@ -2568,6 +2569,7 @@ void logwtmp (const char *line, const ch
@@ -3046,6 +3047,7 @@ void logwtmp (const char *line, const ch
close (wtmp);
}
#endif

View File

@ -7,7 +7,7 @@ Signed-off-by: Jo-Philipp Wich <jo@mein.io>
--- a/pppd/main.c
+++ b/pppd/main.c
@@ -866,14 +866,17 @@ struct protocol_list {
@@ -867,14 +867,17 @@ struct protocol_list {
const char *name;
} protocol_list[] = {
{ 0x21, "IP" },
@ -25,7 +25,7 @@ Signed-off-by: Jo-Philipp Wich <jo@mein.io>
{ 0x33, "Stream Protocol ST-II" },
{ 0x35, "Banyan Vines" },
{ 0x39, "AppleTalk EDDP" },
@@ -887,8 +890,11 @@ struct protocol_list {
@@ -888,8 +891,11 @@ struct protocol_list {
{ 0x49, "Serial Data Transport Protocol (PPP-SDTP)" },
{ 0x4b, "SNA over 802.2" },
{ 0x4d, "SNA" },
@ -37,7 +37,7 @@ Signed-off-by: Jo-Philipp Wich <jo@mein.io>
{ 0x53, "Encryption" },
{ 0x55, "Individual Link Encryption" },
{ 0x57, "IPv6" },
@@ -899,12 +905,15 @@ struct protocol_list {
@@ -900,12 +906,15 @@ struct protocol_list {
{ 0x65, "RTP IPHC Compressed non-TCP" },
{ 0x67, "RTP IPHC Compressed UDP 8" },
{ 0x69, "RTP IPHC Compressed RTP 8" },
@ -53,7 +53,7 @@ Signed-off-by: Jo-Philipp Wich <jo@mein.io>
{ 0x0203, "IBM Source Routing BPDU" },
{ 0x0205, "DEC LANBridge100 Spanning Tree" },
{ 0x0207, "Cisco Discovery Protocol" },
@@ -916,15 +925,19 @@ struct protocol_list {
@@ -917,15 +926,19 @@ struct protocol_list {
{ 0x0231, "Luxcom" },
{ 0x0233, "Sigma Network Systems" },
{ 0x0235, "Apple Client Server Protocol" },
@ -73,7 +73,7 @@ Signed-off-by: Jo-Philipp Wich <jo@mein.io>
{ 0x4001, "Cray Communications Control Protocol" },
{ 0x4003, "CDPD Mobile Network Registration Protocol" },
{ 0x4005, "Expand accelerator protocol" },
@@ -935,8 +948,10 @@ struct protocol_list {
@@ -936,8 +949,10 @@ struct protocol_list {
{ 0x4023, "RefTek Protocol" },
{ 0x4025, "Fibre Channel" },
{ 0x4027, "EMIT Protocols" },
@ -84,7 +84,7 @@ Signed-off-by: Jo-Philipp Wich <jo@mein.io>
{ 0x8023, "OSI Network Layer Control Protocol" },
{ 0x8025, "Xerox NS IDP Control Protocol" },
{ 0x8027, "DECnet Phase IV Control Protocol" },
@@ -945,7 +960,9 @@ struct protocol_list {
@@ -946,7 +961,9 @@ struct protocol_list {
{ 0x8031, "Bridging NCP" },
{ 0x8033, "Stream Protocol Control Protocol" },
{ 0x8035, "Banyan Vines Control Protocol" },
@ -94,7 +94,7 @@ Signed-off-by: Jo-Philipp Wich <jo@mein.io>
{ 0x803f, "NETBIOS Framing Control Protocol" },
{ 0x8041, "Cisco Systems Control Protocol" },
{ 0x8043, "Ascom Timeplex" },
@@ -954,18 +971,24 @@ struct protocol_list {
@@ -955,18 +972,24 @@ struct protocol_list {
{ 0x8049, "Serial Data Control Protocol (PPP-SDCP)" },
{ 0x804b, "SNA over 802.2 Control Protocol" },
{ 0x804d, "SNA Control Protocol" },
@ -119,7 +119,7 @@ Signed-off-by: Jo-Philipp Wich <jo@mein.io>
{ 0x8207, "Cisco Discovery Protocol Control" },
{ 0x8209, "Netcs Twin Routing" },
{ 0x820b, "STP - Control Protocol" },
@@ -974,24 +997,29 @@ struct protocol_list {
@@ -975,24 +998,29 @@ struct protocol_list {
{ 0x8281, "MPLSCP" },
{ 0x8285, "IEEE p1284.4 standard - Protocol Control" },
{ 0x8287, "ETSI TETRA TNP1 Control Protocol" },