]> git.ozlabs.org Git - ppp.git/blobdiff - pppd/sys-linux.c
pppd: Fix compilation on Linux when IPV6 is disabled (#360)
[ppp.git] / pppd / sys-linux.c
index 1e00366ba2914f5c1fba36fabd98e17edecaef72..ff3a249e81758ec042a6cd67991e6412532f8d1b 100644 (file)
 #include <sys/stat.h>
 #include <sys/utsname.h>
 #include <sys/sysmacros.h>
+#include <sys/param.h>
 
 #include <errno.h>
+#include <stddef.h>
 #include <stdio.h>
 #include <stdlib.h>
 #include <syslog.h>
@@ -97,6 +99,7 @@
 #include <fcntl.h>
 #include <ctype.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
 #include <netinet/in.h>
 #include <arpa/inet.h>
 
-#include <linux/ppp_defs.h>
-#include <linux/if_ppp.h>
+#include <linux/ppp-ioctl.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
+
 #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
 #include "fsm.h"
 #include "ipcp.h"
 
-#ifdef IPX_CHANGE
-#include "ipxcp.h"
-#if __GLIBC__ >= 2 && \
-    !(defined(__powerpc__) && __GLIBC__ == 2 && __GLIBC_MINOR__ == 0)
-#include <netipx/ipx.h>
-#else
-#include <linux/ipx.h>
-#endif
-#endif /* IPX_CHANGE */
+#ifdef PPP_WITH_IPV6CP
+#include "eui64.h"
+#endif /* PPP_WITH_IPV6CP */
 
-#ifdef PPP_FILTER
+#ifdef PPP_WITH_FILTER
 #include <pcap-bpf.h>
 #include <linux/filter.h>
-#endif /* PPP_FILTER */
+#endif /* PPP_WITH_FILTER */
 
 #ifdef LOCKLIB
 #include <sys/locks.h>
  */
 #include "termios_linux.h"
 
-#ifdef INET6
+#ifdef PPP_WITH_IPV6CP
 #ifndef _LINUX_IN6_H
 /*
  *    This is in linux/include/net/ipv6.h.
@@ -189,7 +194,7 @@ struct in6_ifreq {
        } while (0)
 
 static const eui64_t nulleui64;
-#endif /* INET6 */
+#endif /* PPP_WITH_IPV6CP */
 
 /* We can get an EIO error on an ioctl if the modem has hung up */
 #define ok_error(num) ((num)==EIO)
@@ -201,9 +206,9 @@ static int ppp_fd = -1;             /* fd which is set to PPP discipline */
 static int sock_fd = -1;       /* socket for doing interface ioctls */
 static int slave_fd = -1;      /* pty for old-style demand mode, slave */
 static int master_fd = -1;     /* pty for old-style demand mode, master */
-#ifdef INET6
+#ifdef PPP_WITH_IPV6CP
 static int sock6_fd = -1;
-#endif /* INET6 */
+#endif /* PPP_WITH_IPV6CP */
 
 /*
  * For the old-style kernel driver, this is the same as ppp_fd.
@@ -346,7 +351,7 @@ void sys_init(void)
     if (sock_fd < 0)
        fatal("Couldn't create IP socket: %m(%d)", errno);
 
-#ifdef INET6
+#ifdef PPP_WITH_IPV6CP
     sock6_fd = socket(AF_INET6, SOCK_DGRAM, 0);
     if (sock6_fd < 0)
        sock6_fd = -errno;      /* save errno for later */
@@ -372,15 +377,17 @@ void sys_cleanup(void)
        if_is_up = 0;
        sifdown(0);
     }
+#ifdef PPP_WITH_IPV6CP
     if (if6_is_up)
        sif6down(0);
+#endif
 
 /*
  * Delete any routes through the device.
  */
     if (have_default_route)
        cifdefaultroute(0, 0, 0);
-#ifdef INET6
+#ifdef PPP_WITH_IPV6CP
     if (have_default_route6)
        cif6defaultroute(0, nulleui64, nulleui64);
 #endif
@@ -400,7 +407,7 @@ sys_close(void)
        close(ppp_dev_fd);
     if (sock_fd >= 0)
        close(sock_fd);
-#ifdef INET6
+#ifdef PPP_WITH_IPV6CP
     if (sock6_fd >= 0)
        close(sock6_fd);
 #endif
@@ -897,6 +904,9 @@ struct speed {
 #ifdef B115200
     { 115200, B115200 },
 #endif
+#ifdef B153600
+    { 153600, B153600 },
+#endif
 #ifdef EXTA
     { 19200, EXTA },
 #endif
@@ -906,6 +916,9 @@ struct speed {
 #ifdef B230400
     { 230400, B230400 },
 #endif
+#ifdef B307200
+    { 307200, B307200 },
+#endif
 #ifdef B460800
     { 460800, B460800 },
 #endif
@@ -915,6 +928,9 @@ struct speed {
 #ifdef B576000
     { 576000, B576000 },
 #endif
+#ifdef B614400
+    { 614400, B614400 },
+#endif
 #ifdef B921600
     { 921600, B921600 },
 #endif
@@ -1411,7 +1427,7 @@ void ccp_flags_set (int unit, int isopen, int isup)
                modify_flags(ppp_dev_fd, SC_CCP_OPEN|SC_CCP_UP, x);
 }
 
-#ifdef PPP_FILTER
+#ifdef PPP_WITH_FILTER
 /*
  * set_filters - set the active and pass filters in the kernel driver.
  */
@@ -1436,7 +1452,7 @@ int set_filters(struct bpf_program *pass, struct bpf_program *active)
        }
        return 1;
 }
-#endif /* PPP_FILTER */
+#endif /* PPP_WITH_FILTER */
 
 /********************************************************************
  *
@@ -1450,26 +1466,288 @@ 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)
 {
-    struct ifpppstatsreq req;
+    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 ifreq req;
+    struct ppp_stats data;
 
     memset (&req, 0, sizeof (req));
 
-    req.stats_ptr = (caddr_t) &req.stats;
-    strlcpy(req.ifr__name, ifname, sizeof(req.ifr__name));
+    req.ifr_data = (caddr_t) &data;
+    strlcpy(req.ifr_name, ifname, sizeof(req.ifr_name));
     if (ioctl(sock_fd, SIOCGPPPSTATS, &req) < 0) {
        error("Couldn't get PPP statistics: %m");
        return 0;
     }
-    stats->bytes_in = req.stats.p.ppp_ibytes;
-    stats->bytes_out = req.stats.p.ppp_obytes;
-    stats->pkts_in = req.stats.p.ppp_ipackets;
-    stats->pkts_out = req.stats.p.ppp_opackets;
+    stats->bytes_in = data.p.ppp_ibytes;
+    stats->bytes_out = data.p.ppp_obytes;
+    stats->pkts_in = data.p.ppp_ipackets;
+    stats->pkts_out = data.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);
 }
 
 /********************************************************************
@@ -1831,7 +2109,7 @@ int cifdefaultroute (int unit, u_int32_t ouraddr, u_int32_t gateway)
     return 1;
 }
 
-#ifdef INET6
+#ifdef PPP_WITH_IPV6CP
 /*
  * /proc/net/ipv6_route parsing stuff.
  */
@@ -2021,7 +2299,7 @@ int cif6defaultroute (int unit, eui64_t ouraddr, eui64_t gateway)
 
     return 1;
 }
-#endif /* INET6 */
+#endif /* PPP_WITH_IPV6CP */
 
 /********************************************************************
  *
@@ -2647,15 +2925,15 @@ int sifdown (int u)
     if (if_is_up && --if_is_up > 0)
        return 1;
 
-#ifdef INET6
+#ifdef PPP_WITH_IPV6CP
     if (if6_is_up)
        return 1;
-#endif /* INET6 */
+#endif /* PPP_WITH_IPV6CP */
 
     return setifstate(u, 0);
 }
 
-#ifdef INET6
+#ifdef PPP_WITH_IPV6CP
 /********************************************************************
  *
  * sif6up - Config the interface up for IPv6
@@ -2686,7 +2964,7 @@ int sif6down (int u)
 
     return setifstate(u, 0);
 }
-#endif /* INET6 */
+#endif /* PPP_WITH_IPV6CP */
 
 /********************************************************************
  *
@@ -2857,7 +3135,7 @@ int cifaddr (int unit, u_int32_t our_adr, u_int32_t his_adr)
        }
     }
 
-    /* This way it is possible to have an IPX-only or IPv6-only interface */
+    /* This way it is possible to have an IPv6-only interface */
     memset(&ifr, 0, sizeof(ifr));
     SET_SA_FAMILY(ifr.ifr_addr, AF_INET);
     strlcpy(ifr.ifr_name, ifname, sizeof(ifr.ifr_name));
@@ -2874,7 +3152,7 @@ int cifaddr (int unit, u_int32_t our_adr, u_int32_t his_adr)
     return 1;
 }
 
-#ifdef INET6
+#ifdef PPP_WITH_IPV6CP
 /********************************************************************
  *
  * sif6addr_rtnetlink - Config the interface with both IPv6 link-local addresses via rtnetlink
@@ -2941,7 +3219,19 @@ static int sif6addr_rtnetlink(unsigned int iface, eui64_t our_eui64, eui64_t his
     IN6_LLADDR_FROM_EUI64(nlreq.addrs[0].addr, our_eui64);
     nlreq.addrs[1].rta.rta_len = sizeof(nlreq.addrs[1]);
     nlreq.addrs[1].rta.rta_type = IFA_ADDRESS;
-    IN6_LLADDR_FROM_EUI64(nlreq.addrs[1].addr, his_eui64);
+
+    /*
+     * To set only local address, older kernel expects that local address is
+     * in IFA_ADDRESS field (not IFA_LOCAL). New kernels with support for peer
+     * address, ignore IFA_ADDRESS if is same as IFA_LOCAL. So for backward
+     * compatibility when setting only local address, set it via both IFA_LOCAL
+     * and IFA_ADDRESS fields. Same logic is implemented in 'ip address' command
+     * from iproute2 project.
+     */
+    if (!eui64_iszero(his_eui64))
+        IN6_LLADDR_FROM_EUI64(nlreq.addrs[1].addr, his_eui64);
+    else
+        IN6_LLADDR_FROM_EUI64(nlreq.addrs[1].addr, our_eui64);
 
     memset(&nladdr, 0, sizeof(nladdr));
     nladdr.nl_family = AF_NETLINK;
@@ -3059,7 +3349,9 @@ int sif6addr (int unit, eui64_t our_eui64, eui64_t his_eui64)
             error("sif6addr: ioctl(SIOCSIFADDR): %m (line %d)", __LINE__);
             return 0;
         }
+    }
 
+    if (!ret && !eui64_iszero(his_eui64)) {
         /*
          * Linux kernel does not provide AF_INET6 ioctl SIOCSIFDSTADDR for
          * setting remote peer host address, so set only route to remote host.
@@ -3121,7 +3413,7 @@ int cif6addr (int unit, eui64_t our_eui64, eui64_t his_eui64)
     }
     return 1;
 }
-#endif /* INET6 */
+#endif /* PPP_WITH_IPV6CP */
 
 /*
  * get_pty - get a pty master/slave pair and chown the slave side
@@ -3274,99 +3566,6 @@ sifnpmode(int u, int proto, enum NPmode mode)
     return 1;
 }
 
-\f
-/********************************************************************
- *
- * sipxfaddr - Config the interface IPX networknumber
- */
-
-int sipxfaddr (int unit, unsigned long int network, unsigned char * node )
-{
-    int    result = 1;
-
-#ifdef IPX_CHANGE
-    int    skfd;
-    struct ifreq         ifr;
-    struct sockaddr_ipx *sipx = (struct sockaddr_ipx *) &ifr.ifr_addr;
-
-    skfd = socket (AF_IPX, SOCK_DGRAM, 0);
-    if (skfd < 0) {
-       if (! ok_error (errno))
-           dbglog("socket(AF_IPX): %m (line %d)", __LINE__);
-       result = 0;
-    }
-    else {
-       memset (&ifr, '\0', sizeof (ifr));
-       strlcpy (ifr.ifr_name, ifname, sizeof(ifr.ifr_name));
-
-       memcpy (sipx->sipx_node, node, IPX_NODE_LEN);
-       sipx->sipx_family  = AF_IPX;
-       sipx->sipx_port    = 0;
-       sipx->sipx_network = htonl (network);
-       sipx->sipx_type    = IPX_FRAME_ETHERII;
-       sipx->sipx_action  = IPX_CRTITF;
-/*
- *  Set the IPX device
- */
-       if (ioctl(skfd, SIOCSIFADDR, (caddr_t) &ifr) < 0) {
-           result = 0;
-           if (errno != EEXIST) {
-               if (! ok_error (errno))
-                   dbglog("ioctl(SIOCSIFADDR, CRTITF): %m (line %d)", __LINE__);
-           }
-           else {
-               warn("ioctl(SIOCSIFADDR, CRTITF): Address already exists");
-           }
-       }
-       close (skfd);
-    }
-#endif
-    return result;
-}
-
-/********************************************************************
- *
- * cipxfaddr - Clear the information for the IPX network. The IPX routes
- *            are removed and the device is no longer able to pass IPX
- *            frames.
- */
-
-int cipxfaddr (int unit)
-{
-    int    result = 1;
-
-#ifdef IPX_CHANGE
-    int    skfd;
-    struct ifreq         ifr;
-    struct sockaddr_ipx *sipx = (struct sockaddr_ipx *) &ifr.ifr_addr;
-
-    skfd = socket (AF_IPX, SOCK_DGRAM, 0);
-    if (skfd < 0) {
-       if (! ok_error (errno))
-           dbglog("socket(AF_IPX): %m (line %d)", __LINE__);
-       result = 0;
-    }
-    else {
-       memset (&ifr, '\0', sizeof (ifr));
-       strlcpy (ifr.ifr_name, ifname, sizeof(ifr.ifr_name));
-
-       sipx->sipx_type    = IPX_FRAME_ETHERII;
-       sipx->sipx_action  = IPX_DLTITF;
-       sipx->sipx_family  = AF_IPX;
-/*
- *  Set the IPX device
- */
-       if (ioctl(skfd, SIOCSIFADDR, (caddr_t) &ifr) < 0) {
-           if (! ok_error (errno))
-               info("ioctl(SIOCSIFADDR, IPX_DLTITF): %m (line %d)", __LINE__);
-           result = 0;
-       }
-       close (skfd);
-    }
-#endif
-    return result;
-}
-
 /*
  * Use the hostname as part of the random number seed.
  */
@@ -3390,22 +3589,6 @@ get_host_seed(void)
 int
 sys_check_options(void)
 {
-#ifdef IPX_CHANGE
-/*
- * Disable the IPX protocol if the support is not present in the kernel.
- */
-    char *path;
-
-    if (ipxcp_protent.enabled_flag) {
-       struct stat stat_buf;
-       if (  ((path = path_to_procfs("/net/ipx/interface")) == NULL
-           && (path = path_to_procfs("/net/ipx_interface")) == NULL)
-           || lstat(path, &stat_buf) < 0) {
-           error("IPX support is not present in the kernel\n");
-           ipxcp_protent.enabled_flag = 0;
-       }
-    }
-#endif
     if (demand && driver_is_old) {
        option_error("demand dialling is not supported by kernel driver "
                     "version %d.%d.%d", driver_version, driver_modification,