X-Git-Url: http://git.ozlabs.org/?a=blobdiff_plain;f=pppd%2Fsys-linux.c;h=b7972b908e1c972797f0c66fd4685cf9070ee45d;hb=7ce9cb7b5313db7d354fbeabb87deaf6d5cd6aa2;hp=f38210a4720556cf53784008850dcc4858e4fb67;hpb=af30be0d252d0f38c40bff7178a00addecdd1bb1;p=ppp.git diff --git a/pppd/sys-linux.c b/pppd/sys-linux.c index f38210a..b7972b9 100644 --- a/pppd/sys-linux.c +++ b/pppd/sys-linux.c @@ -209,6 +209,8 @@ 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 struct rtentry old_def_rt; /* Old default route */ +static int default_rt_repl_rest; /* replace and restore old default rt */ 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 */ @@ -467,6 +469,13 @@ int generic_establish_ppp (int fd) if (new_style_driver) { int flags; + /* If a ppp_fd is already open, close it first */ + if (ppp_fd >= 0) { + close(ppp_fd); + remove_fd(ppp_fd); + ppp_fd = -1; + } + /* Open an instance of /dev/ppp and connect the channel to it */ if (ioctl(fd, PPPIOCGCHAN, &chindex) == -1) { error("Couldn't get channel number: %m"); @@ -625,7 +634,7 @@ void generic_disestablish_ppp(int dev_fd) * 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; @@ -1377,9 +1386,7 @@ int set_filters(struct bpf_program *pass, struct bpf_program *active) * 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; } @@ -1389,9 +1396,7 @@ get_idle_time(u, ip) * 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; @@ -1570,6 +1575,9 @@ static int read_route_table(struct rtentry *rt) p = NULL; } + SET_SA_FAMILY (rt->rt_dst, AF_INET); + SET_SA_FAMILY (rt->rt_gateway, AF_INET); + SIN_ADDR(rt->rt_dst) = strtoul(cols[route_dest_col], NULL, 16); SIN_ADDR(rt->rt_gateway) = strtoul(cols[route_gw_col], NULL, 16); SIN_ADDR(rt->rt_genmask) = strtoul(cols[route_mask_col], NULL, 16); @@ -1642,20 +1650,53 @@ int have_route_to(u_int32_t addr) /******************************************************************** * * sifdefaultroute - 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 sifdefaultroute (int unit, u_int32_t ouraddr, u_int32_t gateway) +int sifdefaultroute (int unit, u_int32_t ouraddr, u_int32_t gateway, bool replace) { - struct rtentry rt; + struct rtentry rt, tmp_rt; + struct rtentry *del_rt = NULL; - if (defaultroute_exists(&rt, dfl_route_metric) && strcmp(rt.rt_dev, ifname) != 0) { - if (rt.rt_flags & RTF_GATEWAY) - error("not replacing existing default route via %I with metric %d", - SIN_ADDR(rt.rt_gateway), dfl_route_metric); - else - error("not replacing existing default route through %s with metric %d", - rt.rt_dev, dfl_route_metric); - return 0; + if (default_rt_repl_rest) { + /* We have already replaced the original defaultroute, if we + * are called again, we will delete the current default route + * and set the new default route in this function. + * - this is normally only the case the doing demand: */ + if (defaultroute_exists(&tmp_rt, -1)) + del_rt = &tmp_rt; + } else if (defaultroute_exists(&old_def_rt, -1 ) && + strcmp( old_def_rt.rt_dev, ifname) != 0) { + /* + * We did not yet replace an existing default route, let's + * check if we should save and replace a default route: + */ + u_int32_t old_gateway = SIN_ADDR(old_def_rt.rt_gateway); + + if (old_gateway != gateway) { + if (!replace) { + error("not replacing default route to %s [%I]", + old_def_rt.rt_dev, old_gateway); + return 0; + } else { + /* we need to copy rt_dev because we need it permanent too: */ + char * tmp_dev = malloc(strlen(old_def_rt.rt_dev)+1); + strcpy(tmp_dev, old_def_rt.rt_dev); + old_def_rt.rt_dev = tmp_dev; + + notice("replacing old default route to %s [%I]", + old_def_rt.rt_dev, old_gateway); + default_rt_repl_rest = 1; + del_rt = &old_def_rt; + } + } } memset (&rt, 0, sizeof (rt)); @@ -1675,6 +1716,12 @@ int sifdefaultroute (int unit, u_int32_t ouraddr, u_int32_t gateway) error("default route ioctl(SIOCADDRT): %m"); return 0; } + if (default_rt_repl_rest && del_rt) + if (ioctl(sock_fd, SIOCDELRT, del_rt) < 0) { + if ( ! ok_error ( errno )) + error("del old default route ioctl(SIOCDELRT): %m(%d)", errno); + return 0; + } have_default_route = 1; return 1; @@ -1713,6 +1760,16 @@ int cifdefaultroute (int unit, u_int32_t ouraddr, u_int32_t gateway) return 0; } } + if (default_rt_repl_rest) { + notice("restoring old default route to %s [%I]", + old_def_rt.rt_dev, SIN_ADDR(old_def_rt.rt_gateway)); + if (ioctl(sock_fd, SIOCADDRT, &old_def_rt) < 0) { + if ( ! ok_error ( errno )) + error("restore default route ioctl(SIOCADDRT): %m(%d)", errno); + return 0; + } + default_rt_repl_rest = 0; + } return 1; } @@ -2091,7 +2148,7 @@ get_if_hwaddr(u_char *addr, char *name) sock_fd = socket(AF_INET, SOCK_DGRAM, 0); if (sock_fd < 0) - return 0; + return -1; memset(&ifreq.ifr_hwaddr, 0, sizeof(struct sockaddr)); strlcpy(ifreq.ifr_name, name, sizeof(ifreq.ifr_name)); ret = ioctl(sock_fd, SIOCGIFHWADDR, &ifreq); @@ -2102,13 +2159,43 @@ get_if_hwaddr(u_char *addr, char *name) } /* - * get_first_ethernet - return the name of the first ethernet-style - * interface on this system. + * get_first_ether_hwaddr - get the hardware address for the first + * ethernet-style interface on this system. */ -char * -get_first_ethernet() +int +get_first_ether_hwaddr(u_char *addr) { - return "eth0"; + struct if_nameindex *if_ni, *i; + struct ifreq ifreq; + int ret, sock_fd; + + sock_fd = socket(AF_INET, SOCK_DGRAM, 0); + if (sock_fd < 0) + return -1; + + if_ni = if_nameindex(); + if (!if_ni) { + close(sock_fd); + return -1; + } + + ret = -1; + + for (i = if_ni; !(i->if_index == 0 && i->if_name == NULL); i++) { + memset(&ifreq.ifr_hwaddr, 0, sizeof(struct sockaddr)); + strlcpy(ifreq.ifr_name, i->if_name, sizeof(ifreq.ifr_name)); + ret = ioctl(sock_fd, SIOCGIFHWADDR, &ifreq); + if (ret >= 0 && ifreq.ifr_hwaddr.sa_family == ARPHRD_ETHER) { + memcpy(addr, ifreq.ifr_hwaddr.sa_data, 6); + break; + } + ret = -1; + } + + if_freenameindex(if_ni); + close(sock_fd); + + return ret; } /******************************************************************** @@ -2826,11 +2913,7 @@ int cif6addr (int unit, eui64_t our_eui64, eui64_t his_eui64) * 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]; @@ -2956,10 +3039,7 @@ open_ppp_loopback(void) */ int -sifnpmode(u, proto, mode) - int u; - int proto; - enum NPmode mode; +sifnpmode(int u, int proto, enum NPmode mode) { struct npioctl npi; @@ -3070,7 +3150,7 @@ int cipxfaddr (int unit) * Use the hostname as part of the random number seed. */ int -get_host_seed() +get_host_seed(void) { int h; char *p = hostname; @@ -3118,54 +3198,6 @@ sys_check_options(void) return 1; } -#ifdef INET6 -/* - * ether_to_eui64 - Convert 48-bit Ethernet address into 64-bit EUI - * - * convert the 48-bit MAC address of eth0 into EUI 64. caller also assumes - * that the system has a properly configured Ethernet interface for this - * function to return non-zero. - */ -int -ether_to_eui64(eui64_t *p_eui64) -{ - struct ifreq ifr; - int skfd; - const unsigned char *ptr; - - skfd = socket(PF_INET6, SOCK_DGRAM, 0); - if(skfd == -1) - { - warn("could not open IPv6 socket"); - return 0; - } - - strcpy(ifr.ifr_name, "eth0"); - if(ioctl(skfd, SIOCGIFHWADDR, &ifr) < 0) - { - close(skfd); - warn("could not obtain hardware address for eth0"); - return 0; - } - close(skfd); - - /* - * And convert the EUI-48 into EUI-64, per RFC 2472 [sec 4.1] - */ - ptr = (unsigned char *) ifr.ifr_hwaddr.sa_data; - p_eui64->e8[0] = ptr[0] | 0x02; - p_eui64->e8[1] = ptr[1]; - p_eui64->e8[2] = ptr[2]; - p_eui64->e8[3] = 0xFF; - p_eui64->e8[4] = 0xFE; - p_eui64->e8[5] = ptr[3]; - p_eui64->e8[6] = ptr[4]; - p_eui64->e8[7] = ptr[5]; - - return 1; -} -#endif - /******************************************************************** * * get_time - Get current time, monotonic if possible.