X-Git-Url: http://git.ozlabs.org/?p=ppp.git;a=blobdiff_plain;f=pppd%2Fsys-linux.c;h=89263ed1c5b75231471dc83271f591381cf45cd2;hp=b4a435d2a99368bdb48316c798961f1be8f08147;hb=388597eee99beac6e5b7430d24c377169f51bd57;hpb=6edf252483b30dbcdcc5059f01831455365d5b6e diff --git a/pppd/sys-linux.c b/pppd/sys-linux.c index b4a435d..89263ed 100644 --- a/pppd/sys-linux.c +++ b/pppd/sys-linux.c @@ -73,12 +73,12 @@ #include #include #include -#include #include #include #include #include +#include #include #include #include @@ -102,7 +102,7 @@ #define MAX_ADDR_LEN 7 #endif -#if __GLIBC__ >= 2 +#if !defined(__GLIBC__) || __GLIBC__ >= 2 #include /* glibc 2 conflicts with linux/types.h */ #include #include @@ -163,6 +163,7 @@ struct in6_ifreq { 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 */ @@ -207,6 +208,7 @@ static unsigned char inbuf[512]; /* buffer for chars read from loopback */ 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 */ @@ -234,6 +236,7 @@ static void close_route_table (void); 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); @@ -350,6 +353,10 @@ void sys_cleanup(void) */ 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); @@ -643,6 +650,21 @@ static int make_ppp_unit() } 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); + strncpy(ifr.ifr_name, t, IF_NAMESIZE); + strncpy(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; } @@ -1695,6 +1717,198 @@ int cifdefaultroute (int unit, u_int32_t ouraddr, u_int32_t gateway) 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. @@ -2152,7 +2366,6 @@ int ppp_available(void) } } - close (s); if (!ok) { slprintf(route_buffer, sizeof(route_buffer), "Sorry - PPP driver version %d.%d.%d is out of date\n", @@ -2162,6 +2375,7 @@ int ppp_available(void) } } } + close(s); return ok; } @@ -2638,7 +2852,10 @@ get_pty(master_fdp, slave_fdp, slave_name, uid) 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 */