From 31fb4d9b37abc3d8e776d9cf14620619d58aedb5 Mon Sep 17 00:00:00 2001 From: Jaco Kroon Date: Wed, 24 Aug 2022 15:58:47 +0200 Subject: [PATCH] pppd: consolidate the interface up/down code a bit. This no longer differentiates between which sub protocols brings an interface up or down, merely tracks which sub protocols have brought up and interface, and which have not yet taken it down. There is one caveat here, I use pointer comparison on these names, so the absolutely cannot be anything other than a compile-time constant, and I'm not sure whether or not at least -O1 is required or not, ie, if the compiler will eliminate multiple "STRINGS" to a single instance in memory. I'm unable to test the solaris code, but I don't see any reason why this should not work. Signed-off-by: Jaco Kroon --- pppd/ipcp.c | 6 +-- pppd/ipv6cp.c | 21 ++------ pppd/main.c | 79 ++++++++++++++++++++++++++++++ pppd/pppd.h | 8 +-- pppd/sys-linux.c | 101 +++++++------------------------------- pppd/sys-solaris.c | 118 ++++++++------------------------------------- 6 files changed, 129 insertions(+), 204 deletions(-) diff --git a/pppd/ipcp.c b/pppd/ipcp.c index 776f06f0e..91c78dfe5 100644 --- a/pppd/ipcp.c +++ b/pppd/ipcp.c @@ -1768,7 +1768,7 @@ ip_demand_conf(int u) if (!sifaddr(u, wo->ouraddr, wo->hisaddr, GetMask(wo->ouraddr))) return 0; ipcp_script(PPP_PATH_IPPREUP, 1); - if (!sifup(u)) + if (!set_ifup("IPCP")) return 0; if (!sifnpmode(u, PPP_IP, NPMODE_QUEUE)) return 0; @@ -1943,7 +1943,7 @@ ipcp_up(fsm *f) } /* bring the interface up for IP */ - if (!sifup(f->unit)) { + if (!set_ifup("IPCP")) { if (debug) warn("Interface failed to come up"); ipcp_close(f->unit, "Interface configuration failed"); @@ -2038,7 +2038,7 @@ ipcp_down(fsm *f) sifnpmode(f->unit, PPP_IP, NPMODE_QUEUE); } else { sifnpmode(f->unit, PPP_IP, NPMODE_DROP); - sifdown(f->unit); + set_ifdown("IPCP"); ipcp_clear_addrs(f->unit, ipcp_gotoptions[f->unit].ouraddr, ipcp_hisoptions[f->unit].hisaddr, 0); } diff --git a/pppd/ipv6cp.c b/pppd/ipv6cp.c index 5a9984142..16d6d9c41 100644 --- a/pppd/ipv6cp.c +++ b/pppd/ipv6cp.c @@ -1237,14 +1237,10 @@ ipv6_demand_conf(int u) eui64_magic_nz(wo->ourid); } - if (!sif6up(u)) + if (!set_ifup("IPV6CP")) return 0; if (!sif6addr(u, wo->ourid, wo->hisid)) return 0; -#if !defined(__linux__) && !(defined(SVR4) && (defined(SNI) || defined(__USLC__))) - if (!sifup(u)) - return 0; -#endif if (!sifnpmode(u, PPP_IPV6, NPMODE_QUEUE)) return 0; if (wo->default_route) @@ -1345,9 +1341,9 @@ ipv6cp_up(fsm *f) } else { /* bring the interface up for IPv6 */ - if (!sif6up(f->unit)) { + if (!set_ifup("IPV6CP")) { if (debug) - warn("sif6up failed (IPV6)"); + warn("set_ifup failed (IPV6)"); ipv6cp_close(f->unit, "Interface configuration failed"); return; } @@ -1418,17 +1414,10 @@ ipv6cp_down(fsm *f) sifnpmode(f->unit, PPP_IPV6, NPMODE_QUEUE); } else { sifnpmode(f->unit, PPP_IPV6, NPMODE_DROP); -#if !defined(__linux__) && !(defined(SVR4) && (defined(SNI) || defined(__USLC))) - sif6down(f->unit); -#endif - ipv6cp_clear_addrs(f->unit, + ipv6cp_clear_addrs(f->unit, ipv6cp_gotoptions[f->unit].ourid, ipv6cp_hisoptions[f->unit].hisid); -#if defined(__linux__) - sif6down(f->unit); -#elif defined(SVR4) && (defined(SNI) || defined(__USLC)) - sifdown(f->unit); -#endif + set_ifdown("IPV6CP"); } /* Execute the ipv6-down script */ diff --git a/pppd/main.c b/pppd/main.c index 7e4775226..b979bdc5b 100644 --- a/pppd/main.c +++ b/pppd/main.c @@ -133,6 +133,7 @@ char *progname; /* Name of this program */ char hostname[MAXNAMELEN]; /* Our hostname */ static char pidfilename[MAXPATHLEN]; /* name of pid file */ static char linkpidfile[MAXPATHLEN]; /* name of linkname pid file */ +static const char** up_protos = NULL; /* simple list of names of sub protocols which has signalled the interface into an UP state, or NULL if the interface is down */ char ppp_devnam[MAXPATHLEN]; /* name of PPP tty (maybe ttypx) */ uid_t uid; /* Our real user-id */ struct notifier *pidchange = NULL; @@ -747,6 +748,77 @@ set_ifunit(int iskey) } } +/* + * set_ifup - called in order to set the ppp interface to up, if not already + * brought up. + * + * It's important that the sub-protocol not be a dynamically allocated string, ie, + * use set_ipup("IPCP") ... + */ +int +set_ifup(const char* name) +{ + int i; + const char** t; + + if (!up_protos && !netif_set_up()) + return 0; + + i = 0; + while (up_protos && up_protos[i]) { + if (up_protos[i] == name) { + warn("%s previously signalled ifup, this is probably a bug in the protocol.", + name); + return 1; + } + ++i; + } + info("%s is now UP", name); + + /* i is index where we insert the sub protocol */ + t = realloc(up_protos, (i + 2) * sizeof(*up_protos)); + if (t == NULL) { + error("Memory allocation error trying to add %s to the list of UP protocols.", name); + } else { + up_protos = t; + up_protos[i] = name; + up_protos[i+1] = NULL; + } + + return 1; +} + +/* + * set_ifdown - called in order to set the ppp interface to down, the interface will + * only be downned if all sub protocols have signalled down. + * + * It's important that the sub-protocol not be a dynamically allocated string, ie, + * use set_ipup("IPCP") ... + */ +int +set_ifdown(const char* name) +{ + int i = 0; + const char** t; + + while (up_protos && up_protos[i] && up_protos[i] != name) + ++i; + + if (!up_protos || !up_protos[i]) { + error("%s has not signalled ifup, or has already signalled ifdown."); + return 0; + } + + while (up_protos[i]) { + up_protos[i] = up_protos[i+1]; + ++i; + } + + info("%s is now DOWN", name); + + return netif_set_down(); +} + /* * detach - detach us from the controlling terminal. */ @@ -1174,6 +1246,13 @@ die(int status) static void cleanup(void) { + if (up_protos) { + const char** remprotos = up_protos; + warn("Some protocols were left UP at time of cleanup."); + while (*remprotos) + set_ifdown(*remprotos++); + free(up_protos); + } sys_cleanup(); if (fd_ppp >= 0) diff --git a/pppd/pppd.h b/pppd/pppd.h index bd9faf0f9..304329be3 100644 --- a/pppd/pppd.h +++ b/pppd/pppd.h @@ -702,21 +702,21 @@ int get_idle_time(int, struct ppp_idle *); /* Find out how long link has been idle */ int get_ppp_stats(int, struct pppd_stats *); /* Return link statistics */ +int set_ifup(const char*); /* Set the PPP interface to UP for a named sub protocol */ +int set_ifdown(const char*); /* Set the PPP interface to DOWN for a named sub protocol */ void netif_set_mtu(int, int); /* Set PPP interface MTU */ int netif_get_mtu(int); /* Get PPP interface MTU */ +int netif_set_up(); /* Configure i/f up (system specific) */ +int netif_set_down(); /* Configure i/f down (system specific) */ int sifvjcomp(int, int, int, int); /* Configure VJ TCP header compression */ -int sifup(int); /* Configure i/f up for one protocol */ int sifnpmode(int u, int proto, enum NPmode mode); /* Set mode for handling packets for proto */ -int sifdown(int); /* Configure i/f down for one protocol */ int sifaddr(int, u_int32_t, u_int32_t, u_int32_t); /* Configure IPv4 addresses for i/f */ int cifaddr(int, u_int32_t, u_int32_t); /* Reset i/f IP addresses */ #ifdef PPP_WITH_IPV6CP -int sif6up(int); /* Configure i/f up for IPv6 */ -int sif6down(int); /* Configure i/f down for IPv6 */ int sif6addr(int, eui64_t, eui64_t); /* Configure IPv6 addresses for i/f */ int cif6addr(int, eui64_t, eui64_t); diff --git a/pppd/sys-linux.c b/pppd/sys-linux.c index dc3b4d658..40d2eff7b 100644 --- a/pppd/sys-linux.c +++ b/pppd/sys-linux.c @@ -243,8 +243,6 @@ int new_style_driver = 0; static char loop_name[20]; 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 struct rtentry old_def_rt; /* Old default route */ @@ -283,7 +281,7 @@ static void decode_version (char *buf, int *version, int *mod, int *patch); static int set_kdebugflag(int level); static int ppp_registered(void); static int make_ppp_unit(void); -static int setifstate (int u, int state); +static int setifstate(int state); extern u_char inpacket_buf[]; /* borrowed from main.c */ @@ -519,18 +517,6 @@ void sys_init(void) void sys_cleanup(void) { -/* - * Take down the device - */ - if (if_is_up) { - if_is_up = 0; - sifdown(0); - } -#ifdef PPP_WITH_IPV6CP - if (if6_is_up) - sif6down(0); -#endif - /* * Delete any routes through the device. */ @@ -3083,79 +3069,12 @@ int sifvjcomp (int u, int vjcomp, int cidcomp, int maxcid) return 1; } -/******************************************************************** - * - * sifup - Config the interface up and enable IP packets to pass. - */ - -int sifup(int u) -{ - int ret; - - if ((ret = setifstate(u, 1))) - if_is_up++; - - return ret; -} - -/******************************************************************** - * - * sifdown - Disable the indicated protocol and config the interface - * down if there are no remaining protocols. - */ - -int sifdown (int u) -{ - if (if_is_up && --if_is_up > 0) - return 1; - -#ifdef PPP_WITH_IPV6CP - if (if6_is_up) - return 1; -#endif /* PPP_WITH_IPV6CP */ - - return setifstate(u, 0); -} - -#ifdef PPP_WITH_IPV6CP -/******************************************************************** - * - * sif6up - Config the interface up for IPv6 - */ - -int sif6up(int u) -{ - int ret; - - if ((ret = setifstate(u, 1))) - if6_is_up = 1; - - return ret; -} - -/******************************************************************** - * - * sif6down - Disable the IPv6CP protocol and config the interface - * down if there are no remaining protocols. - */ - -int sif6down (int u) -{ - if6_is_up = 0; - - if (if_is_up) - return 1; - - return setifstate(u, 0); -} -#endif /* PPP_WITH_IPV6CP */ - /******************************************************************** * * setifstate - Config the interface up or down */ -static int setifstate (int u, int state) +static int setifstate (int state) { struct ifreq ifr; @@ -3180,6 +3099,22 @@ static int setifstate (int u, int state) return 1; } +/******************************************************************** + * netif_set_up - Config the interface up + */ +int netif_set_up() +{ + return setifstate(1); +} + +/******************************************************************** + * netif_set_down - Config the interface down + */ +int netif_set_down() +{ + return setifstate(0); +} + /******************************************************************** * * sifaddr - Config the interface IP addresses and netmask. diff --git a/pppd/sys-solaris.c b/pppd/sys-solaris.c index d903721de..36a121521 100644 --- a/pppd/sys-solaris.c +++ b/pppd/sys-solaris.c @@ -197,7 +197,6 @@ static int ipmuxid = -1; #if defined(PPP_WITH_IPV6CP) && defined(SOL2) static int ip6fd; /* IP file descriptor */ static int ip6muxid = -1; /* Multiplexer file descriptor */ -static int if6_is_up = 0; /* IPv6 interface has been marked up */ #define IN6_SOCKADDR_FROM_EUI64(s, eui64) do { \ (s)->sin6_family = AF_INET6; \ @@ -256,7 +255,6 @@ static int tty_nmodules; static char tty_modules[NMODULES][FMNAMESZ+1]; static int tty_npushed; -static int if_is_up; /* Interface has been marked up */ static u_int32_t remote_addr; /* IP address of peer */ static u_int32_t default_route_gateway; /* Gateway for default route added */ static eui64_t default_route_gateway6; /* Gateway for default IPv6 route added */ @@ -755,12 +753,6 @@ sys_cleanup(void) #endif /* defined(PPP_WITH_IPV6CP) */ #endif /* defined(SOL2) */ -#if defined(SOL2) && defined(PPP_WITH_IPV6CP) - if (if6_is_up) - sif6down(0); -#endif /* defined(SOL2) && defined(PPP_WITH_IPV6CP) */ - if (if_is_up) - sifdown(0); if (default_route_gateway) cifdefaultroute(0, default_route_gateway, default_route_gateway); if (default_route_gateway6.e32[0] != 0 || default_route_gateway6.e32[1] != 0) @@ -1696,49 +1688,44 @@ sifvjcomp(int u, int vjcomp, int xcidcomp, int xmaxcid) } /* - * sifup - Config the interface up and enable IP packets to pass. + * setifstate - Set the interface up/down. */ -int -sifup(int u) +static +int setifstate(int state) { struct ifreq ifr; strlcpy(ifr.ifr_name, ifname, sizeof(ifr.ifr_name)); if (ioctl(ipfd, SIOCGIFFLAGS, &ifr) < 0) { - error("Couldn't mark interface up (get): %m"); + error("Couldn't mark interface %s (get): %m", state ? "up" : "down"); return 0; } - ifr.ifr_flags |= IFF_UP; + if (state) + ifr.ifr_flags |= IFF_UP; + else + ifr.ifr_flags &= ~IFF_UP; if (ioctl(ipfd, SIOCSIFFLAGS, &ifr) < 0) { - error("Couldn't mark interface up (set): %m"); + error("Couldn't mark interface %s (set): %m", state ? "up" : "down"); return 0; } - if_is_up = 1; return 1; + } /* - * sifdown - Config the interface down and disable IP. + * netif_set_up - Config the interface up and enable IP packets to pass. */ -int -sifdown(int u) +int netif_set_up() { - struct ifreq ifr; + return setifstate(1); +} - if (ipmuxid < 0) - return 1; - strlcpy(ifr.ifr_name, ifname, sizeof(ifr.ifr_name)); - if (ioctl(ipfd, SIOCGIFFLAGS, &ifr) < 0) { - error("Couldn't mark interface down (get): %m"); - return 0; - } - ifr.ifr_flags &= ~IFF_UP; - if (ioctl(ipfd, SIOCSIFFLAGS, &ifr) < 0) { - error("Couldn't mark interface down (set): %m"); - return 0; - } - if_is_up = 0; - return 1; +/* + * netif_set_up - Config the interface up and enable IP packets to pass. + */ +int netif_set_down() +{ + return setifstate(0); } /* @@ -1759,71 +1746,6 @@ sifnpmode(int u, int proto, enum NPmode mode) } #if defined(SOL2) && defined(PPP_WITH_IPV6CP) -/* - * sif6up - Config the IPv6 interface up and enable IPv6 packets to pass. - */ -int -sif6up(int u) -{ - struct lifreq lifr; - int fd; - - fd = socket(AF_INET6, SOCK_DGRAM, 0); - if (fd < 0) { - return 0; - } - - memset(&lifr, 0, sizeof(lifr)); - strlcpy(lifr.lifr_name, ifname, sizeof(lifr.lifr_name)); - if (ioctl(fd, SIOCGLIFFLAGS, &lifr) < 0) { - close(fd); - return 0; - } - - lifr.lifr_flags |= IFF_UP; - strlcpy(lifr.lifr_name, ifname, sizeof(lifr.lifr_name)); - if (ioctl(fd, SIOCSLIFFLAGS, &lifr) < 0) { - close(fd); - return 0; - } - - if6_is_up = 1; - close(fd); - return 1; -} - -/* - * sifdown - Config the IPv6 interface down and disable IPv6. - */ -int -sif6down(int u) -{ - struct lifreq lifr; - int fd; - - fd = socket(AF_INET6, SOCK_DGRAM, 0); - if (fd < 0) - return 0; - - memset(&lifr, 0, sizeof(lifr)); - strlcpy(lifr.lifr_name, ifname, sizeof(lifr.lifr_name)); - if (ioctl(fd, SIOCGLIFFLAGS, &lifr) < 0) { - close(fd); - return 0; - } - - lifr.lifr_flags &= ~IFF_UP; - strlcpy(lifr.lifr_name, ifname, sizeof(lifr.lifr_name)); - if (ioctl(fd, SIOCGLIFFLAGS, &lifr) < 0) { - close(fd); - return 0; - } - - if6_is_up = 0; - close(fd); - return 1; -} - /* * sif6addr - Config the interface with an IPv6 link-local address */