#include <sys/types.h>
#include <sys/socket.h>
#include <sys/time.h>
-#include <sys/errno.h>
#include <sys/file.h>
#include <sys/stat.h>
#include <sys/utsname.h>
#include <sys/sysmacros.h>
+#include <errno.h>
#include <stdio.h>
#include <stdlib.h>
#include <syslog.h>
#define MAX_ADDR_LEN 7
#endif
-#if __GLIBC__ >= 2
+#if !defined(__GLIBC__) || __GLIBC__ >= 2
#include <asm/types.h> /* glibc 2 conflicts with linux/types.h */
#include <net/if.h>
#include <net/if_arp.h>
eui64_copy(eui64, sin6.s6_addr32[2]); \
} while (0)
+static const eui64_t nulleui64;
#endif /* INET6 */
/* We can get an EIO error on an ioctl if the modem has hung up */
static int if_is_up; /* Interface has been marked up */
static int if6_is_up; /* Interface has been marked up for IPv6, to help differentiate */
static int have_default_route; /* Gateway for default route added */
+static int have_default_route6; /* Gateway for default IPv6 route added */
static u_int32_t proxy_arp_addr; /* Addr for proxy arp entry added */
static char proxy_arp_dev[16]; /* Device for proxy arp entry */
static u_int32_t our_old_addr; /* for detecting address changes */
static int open_route_table (void);
static int read_route_table (struct rtentry *rt);
static int defaultroute_exists (struct rtentry *rt, int metric);
+static int defaultroute6_exists (struct in6_rtmsg *rt, int metric);
static int get_ether_addr (u_int32_t ipaddr, struct sockaddr *hwaddr,
char *name, int namelen);
static void decode_version (char *buf, int *version, int *mod, int *patch);
*/
if (have_default_route)
cifdefaultroute(0, 0, 0);
+#ifdef INET6
+ if (have_default_route6)
+ cif6defaultroute(0, nulleui64, nulleui64);
+#endif
if (has_proxy_arp)
cifproxyarp(0, proxy_arp_addr);
* make_ppp_unit - make a new ppp unit for ppp_dev_fd.
* Assumes new_style_driver.
*/
-static int make_ppp_unit()
+static int make_ppp_unit(void)
{
int x, flags;
}
if (x < 0)
error("Couldn't create new ppp unit: %m");
+
+ if (x == 0 && req_ifname[0] != '\0') {
+ struct ifreq ifr;
+ char t[MAXIFNAMELEN];
+ memset(&ifr, 0, sizeof(struct ifreq));
+ slprintf(t, sizeof(t), "%s%d", PPP_DRV_NAME, ifunit);
+ strlcpy(ifr.ifr_name, t, IF_NAMESIZE);
+ strlcpy(ifr.ifr_newname, req_ifname, IF_NAMESIZE);
+ x = ioctl(sock_fd, SIOCSIFNAME, &ifr);
+ if (x < 0)
+ error("Couldn't rename interface %s to %s: %m", t, req_ifname);
+ else
+ info("Renamed interface %s to %s", t, req_ifname);
+ }
+
return x;
}
* get_idle_time - return how long the link has been idle.
*/
int
-get_idle_time(u, ip)
- int u;
- struct ppp_idle *ip;
+get_idle_time(int u, struct ppp_idle *ip)
{
return ioctl(ppp_dev_fd, PPPIOCGIDLE, ip) >= 0;
}
* get_ppp_stats - return statistics for the link.
*/
int
-get_ppp_stats(u, stats)
- int u;
- struct pppd_stats *stats;
+get_ppp_stats(int u, struct pppd_stats *stats)
{
struct ifpppstatsreq req;
return 1;
}
+#ifdef INET6
+/*
+ * /proc/net/ipv6_route parsing stuff.
+ */
+static int route_dest_plen_col;
+static int open_route6_table (void);
+static int read_route6_table (struct in6_rtmsg *rt);
+
+/********************************************************************
+ *
+ * open_route6_table - open the interface to the route table
+ */
+static int open_route6_table (void)
+{
+ char *path;
+
+ close_route_table();
+
+ path = path_to_procfs("/net/ipv6_route");
+ route_fd = fopen (path, "r");
+ if (route_fd == NULL) {
+ error("can't open routing table %s: %m", path);
+ return 0;
+ }
+
+ /* default to usual columns */
+ route_dest_col = 0;
+ route_dest_plen_col = 1;
+ route_gw_col = 4;
+ route_metric_col = 5;
+ route_flags_col = 8;
+ route_dev_col = 9;
+ route_num_cols = 10;
+
+ return 1;
+}
+
+/********************************************************************
+ *
+ * read_route6_table - read the next entry from the route table
+ */
+
+static void hex_to_in6_addr(struct in6_addr *addr, const char *s)
+{
+ char hex8[9];
+ unsigned i;
+ uint32_t v;
+
+ hex8[8] = 0;
+ for (i = 0; i < 4; i++) {
+ memcpy(hex8, s + 8*i, 8);
+ v = strtoul(hex8, NULL, 16);
+ addr->s6_addr32[i] = v;
+ }
+}
+
+static int read_route6_table(struct in6_rtmsg *rt)
+{
+ char *cols[ROUTE_MAX_COLS], *p;
+ int col;
+
+ memset (rt, '\0', sizeof (struct in6_rtmsg));
+
+ if (fgets (route_buffer, sizeof (route_buffer), route_fd) == (char *) 0)
+ return 0;
+
+ p = route_buffer;
+ for (col = 0; col < route_num_cols; ++col) {
+ cols[col] = strtok(p, route_delims);
+ if (cols[col] == NULL)
+ return 0; /* didn't get enough columns */
+ p = NULL;
+ }
+
+ hex_to_in6_addr(&rt->rtmsg_dst, cols[route_dest_col]);
+ rt->rtmsg_dst_len = strtoul(cols[route_dest_plen_col], NULL, 16);
+ hex_to_in6_addr(&rt->rtmsg_gateway, cols[route_gw_col]);
+
+ rt->rtmsg_metric = strtoul(cols[route_metric_col], NULL, 16);
+ rt->rtmsg_flags = strtoul(cols[route_flags_col], NULL, 16);
+ rt->rtmsg_ifindex = if_nametoindex(cols[route_dev_col]);
+
+ return 1;
+}
+
+/********************************************************************
+ *
+ * defaultroute6_exists - determine if there is a default route
+ */
+
+static int defaultroute6_exists (struct in6_rtmsg *rt, int metric)
+{
+ int result = 0;
+
+ if (!open_route6_table())
+ return 0;
+
+ while (read_route6_table(rt) != 0) {
+ if ((rt->rtmsg_flags & RTF_UP) == 0)
+ continue;
+
+ if (rt->rtmsg_dst_len != 0)
+ continue;
+ if (rt->rtmsg_dst.s6_addr32[0] == 0L
+ && rt->rtmsg_dst.s6_addr32[1] == 0L
+ && rt->rtmsg_dst.s6_addr32[2] == 0L
+ && rt->rtmsg_dst.s6_addr32[3] == 0L
+ && (metric < 0 || rt->rtmsg_metric == metric)) {
+ result = 1;
+ break;
+ }
+ }
+
+ close_route_table();
+ return result;
+}
+
+/********************************************************************
+ *
+ * sif6defaultroute - assign a default route through the address given.
+ *
+ * If the global default_rt_repl_rest flag is set, then this function
+ * already replaced the original system defaultroute with some other
+ * route and it should just replace the current defaultroute with
+ * another one, without saving the current route. Use: demand mode,
+ * when pppd sets first a defaultroute it it's temporary ppp0 addresses
+ * and then changes the temporary addresses to the addresses for the real
+ * ppp connection when it has come up.
+ */
+
+int sif6defaultroute (int unit, eui64_t ouraddr, eui64_t gateway)
+{
+ struct in6_rtmsg rt;
+ char buf[IF_NAMESIZE];
+
+ if (defaultroute6_exists(&rt, dfl_route_metric) &&
+ rt.rtmsg_ifindex != if_nametoindex(ifname)) {
+ if (rt.rtmsg_flags & RTF_GATEWAY)
+ error("not replacing existing default route via gateway");
+ else
+ error("not replacing existing default route through %s",
+ if_indextoname(rt.rtmsg_ifindex, buf));
+ return 0;
+ }
+
+ memset (&rt, 0, sizeof (rt));
+
+ rt.rtmsg_ifindex = if_nametoindex(ifname);
+ rt.rtmsg_metric = dfl_route_metric + 1; /* +1 for binary compatibility */
+ rt.rtmsg_dst_len = 0;
+
+ rt.rtmsg_flags = RTF_UP;
+ if (ioctl(sock6_fd, SIOCADDRT, &rt) < 0) {
+ if ( ! ok_error ( errno ))
+ error("default route ioctl(SIOCADDRT): %m");
+ return 0;
+ }
+
+ have_default_route6 = 1;
+ return 1;
+}
+
+/********************************************************************
+ *
+ * cif6defaultroute - delete a default route through the address given.
+ */
+
+int cif6defaultroute (int unit, eui64_t ouraddr, eui64_t gateway)
+{
+ struct in6_rtmsg rt;
+
+ have_default_route6 = 0;
+
+ memset (&rt, '\0', sizeof (rt));
+
+ rt.rtmsg_ifindex = if_nametoindex(ifname);
+ rt.rtmsg_metric = dfl_route_metric + 1; /* +1 for binary compatibility */
+ rt.rtmsg_dst_len = 0;
+
+ rt.rtmsg_flags = RTF_UP;
+ if (ioctl(sock6_fd, SIOCDELRT, &rt) < 0 && errno != ESRCH) {
+ if (still_ppp()) {
+ if ( ! ok_error ( errno ))
+ error("default route ioctl(SIOCDELRT): %m");
+ return 0;
+ }
+ }
+
+ return 1;
+}
+#endif /* INET6 */
+
/********************************************************************
*
* sifproxyarp - Make a proxy ARP entry for the peer.
* interface on this system.
*/
char *
-get_first_ethernet()
+get_first_ethernet(void)
{
return "eth0";
}
}
}
- close (s);
if (!ok) {
slprintf(route_buffer, sizeof(route_buffer),
"Sorry - PPP driver version %d.%d.%d is out of date\n",
}
}
}
+ close(s);
return ok;
}
memset(&ifr6, 0, sizeof(ifr6));
IN6_LLADDR_FROM_EUI64(ifr6.ifr6_addr, our_eui64);
ifr6.ifr6_ifindex = ifr.ifr_ifindex;
- ifr6.ifr6_prefixlen = 10;
+ ifr6.ifr6_prefixlen = 128;
if (ioctl(sock6_fd, SIOCSIFADDR, &ifr6) < 0) {
error("sif6addr: ioctl(SIOCSIFADDR): %m (line %d)", __LINE__);
memset(&rt6, 0, sizeof(rt6));
IN6_LLADDR_FROM_EUI64(rt6.rtmsg_dst, his_eui64);
rt6.rtmsg_flags = RTF_UP;
- rt6.rtmsg_dst_len = 10;
+ rt6.rtmsg_dst_len = 128;
rt6.rtmsg_ifindex = ifr.ifr_ifindex;
rt6.rtmsg_metric = 1;
memset(&ifr6, 0, sizeof(ifr6));
IN6_LLADDR_FROM_EUI64(ifr6.ifr6_addr, our_eui64);
ifr6.ifr6_ifindex = ifr.ifr_ifindex;
- ifr6.ifr6_prefixlen = 10;
+ ifr6.ifr6_prefixlen = 128;
if (ioctl(sock6_fd, SIOCDIFADDR, &ifr6) < 0) {
if (errno != EADDRNOTAVAIL) {
* to the uid given. Assumes slave_name points to >= 16 bytes of space.
*/
int
-get_pty(master_fdp, slave_fdp, slave_name, uid)
- int *master_fdp;
- int *slave_fdp;
- char *slave_name;
- int uid;
+get_pty(int *master_fdp, int *slave_fdp, char *slave_name, int uid)
{
int i, mfd, sfd = -1;
char pty_name[16];
warn("Couldn't unlock pty slave %s: %m", pty_name);
#endif
if ((sfd = open(pty_name, O_RDWR | O_NOCTTY)) < 0)
+ {
warn("Couldn't open pty slave %s: %m", pty_name);
+ close(mfd);
+ }
}
}
#endif /* TIOCGPTN */
*/
int
-sifnpmode(u, proto, mode)
- int u;
- int proto;
- enum NPmode mode;
+sifnpmode(int u, int proto, enum NPmode mode)
{
struct npioctl npi;
* Use the hostname as part of the random number seed.
*/
int
-get_host_seed()
+get_host_seed(void)
{
int h;
char *p = hostname;
return 1;
}
#endif
+
+/********************************************************************
+ *
+ * get_time - Get current time, monotonic if possible.
+ */
+int
+get_time(struct timeval *tv)
+{
+/* Old glibc (< 2.3.4) does define CLOCK_MONOTONIC, but kernel may have it.
+ * Runtime checking makes it safe. */
+#ifndef CLOCK_MONOTONIC
+#define CLOCK_MONOTONIC 1
+#endif
+ static int monotonic = -1;
+ struct timespec ts;
+ int ret;
+
+ if (monotonic) {
+ ret = clock_gettime(CLOCK_MONOTONIC, &ts);
+ if (ret == 0) {
+ monotonic = 1;
+ if (tv) {
+ tv->tv_sec = ts.tv_sec;
+ tv->tv_usec = ts.tv_nsec / 1000;
+ }
+ return ret;
+ } else if (monotonic > 0)
+ return ret;
+
+ monotonic = 0;
+ warn("Couldn't use monotonic clock source: %m");
+ }
+
+ return gettimeofday(tv, NULL);
+}