X-Git-Url: http://git.ozlabs.org/?p=ppp.git;a=blobdiff_plain;f=pppd%2Fsys-svr4.c;h=8f1845370dfd995e46383c6f967e5425db1aba0d;hp=5357aebfeb91bcb45aac7f6c7abc069068534cb9;hb=66b97cb2741ff687e731834eb6458281df3dd412;hpb=6a53c48e7fe9a14bc21750afdf5d309e6720bba0 diff --git a/pppd/sys-svr4.c b/pppd/sys-svr4.c index 5357aeb..8f18453 100644 --- a/pppd/sys-svr4.c +++ b/pppd/sys-svr4.c @@ -1,31 +1,96 @@ /* * System-dependent procedures for pppd under Solaris 2. * - * Copyright (c) 1994 The Australian National University. + * Parts re-written by Adi Masputra , based on + * the original sys-svr4.c + * + * Copyright (c) 2000 by Sun Microsystems, Inc. * All rights reserved. * * Permission to use, copy, modify, and distribute this software and its * documentation is hereby granted, provided that the above copyright - * notice appears in all copies. This software is provided without any - * warranty, express or implied. The Australian National University - * makes no representations about the suitability of this software for - * any purpose. + * notice appears in all copies. + * + * SUN MAKES NO REPRESENTATION OR WARRANTIES ABOUT THE SUITABILITY OF + * THE SOFTWARE, EITHER EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED + * TO THE IMPLIED WARRANTIES OF MERCHANTABILITY, FITNESS FOR A + * PARTICULAR PURPOSE, OR NON-INFRINGEMENT. SUN SHALL NOT BE LIABLE FOR + * ANY DAMAGES SUFFERED BY LICENSEE AS A RESULT OF USING, MODIFYING OR + * DISTRIBUTING THIS SOFTWARE OR ITS DERIVATIVES + * + * Copyright (c) 1995-2002 Paul Mackerras. All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * + * 1. Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * + * 2. Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in + * the documentation and/or other materials provided with the + * distribution. + * + * 3. The name(s) of the authors of this software must not be used to + * endorse or promote products derived from this software without + * prior written permission. + * + * 4. Redistributions of any form whatsoever must retain the following + * acknowledgment: + * "This product includes software developed by Paul Mackerras + * ". + * + * THE AUTHORS OF THIS SOFTWARE DISCLAIM ALL WARRANTIES WITH REGARD TO + * THIS SOFTWARE, INCLUDING ALL IMPLIED WARRANTIES OF MERCHANTABILITY + * AND FITNESS, IN NO EVENT SHALL THE AUTHORS BE LIABLE FOR ANY + * SPECIAL, INDIRECT OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES + * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN + * AN ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING + * OUT OF OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. + * + * Derived from main.c and pppd.h, which are: * - * IN NO EVENT SHALL THE AUSTRALIAN NATIONAL UNIVERSITY BE LIABLE TO ANY - * PARTY FOR DIRECT, INDIRECT, SPECIAL, INCIDENTAL, OR CONSEQUENTIAL DAMAGES - * ARISING OUT OF THE USE OF THIS SOFTWARE AND ITS DOCUMENTATION, EVEN IF - * THE AUSTRALIAN NATIONAL UNIVERSITY HAVE BEEN ADVISED OF THE POSSIBILITY - * OF SUCH DAMAGE. + * Copyright (c) 1984-2000 Carnegie Mellon University. All rights reserved. * - * THE AUSTRALIAN NATIONAL UNIVERSITY SPECIFICALLY DISCLAIMS ANY WARRANTIES, - * INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY - * AND FITNESS FOR A PARTICULAR PURPOSE. THE SOFTWARE PROVIDED HEREUNDER IS - * ON AN "AS IS" BASIS, AND THE AUSTRALIAN NATIONAL UNIVERSITY HAS NO - * OBLIGATION TO PROVIDE MAINTENANCE, SUPPORT, UPDATES, ENHANCEMENTS, - * OR MODIFICATIONS. + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * + * 1. Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * + * 2. Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in + * the documentation and/or other materials provided with the + * distribution. + * + * 3. The name "Carnegie Mellon University" must not be used to + * endorse or promote products derived from this software without + * prior written permission. For permission or any legal + * details, please contact + * Office of Technology Transfer + * Carnegie Mellon University + * 5000 Forbes Avenue + * Pittsburgh, PA 15213-3890 + * (412) 268-4387, fax: (412) 268-7395 + * tech-transfer@andrew.cmu.edu + * + * 4. Redistributions of any form whatsoever must retain the following + * acknowledgment: + * "This product includes software developed by Computing Services + * at Carnegie Mellon University (http://www.cmu.edu/computing/)." + * + * CARNEGIE MELLON UNIVERSITY DISCLAIMS ALL WARRANTIES WITH REGARD TO + * THIS SOFTWARE, INCLUDING ALL IMPLIED WARRANTIES OF MERCHANTABILITY + * AND FITNESS, IN NO EVENT SHALL CARNEGIE MELLON UNIVERSITY BE LIABLE + * FOR ANY SPECIAL, INDIRECT OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES + * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN + * AN ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING + * OUT OF OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. */ -#define RCSID "$Id: sys-svr4.c,v 1.35 1999/09/30 19:59:06 masputra Exp $" +#define RCSID "$Id: sys-svr4.c,v 1.45 2002/12/04 23:03:33 paulus Exp $" #include #include @@ -67,9 +132,52 @@ #endif #include "pppd.h" +#include "fsm.h" +#include "lcp.h" +#include "ipcp.h" +#include "ccp.h" + +#if !defined(PPP_DEV_NAME) +#define PPP_DEV_NAME "/dev/ppp" +#endif /* !defined(PPP_DEV_NAME) */ + +#if !defined(AHDLC_MOD_NAME) +#define AHDLC_MOD_NAME "ppp_ahdl" +#endif /* !defined(AHDLC_MOD_NAME) */ + +#if !defined(COMP_MOD_NAME) +#define COMP_MOD_NAME "ppp_comp" +#endif /* !defined(COMP_MOD_NAME) */ + +#if !defined(IP_DEV_NAME) +#define IP_DEV_NAME "/dev/ip" +#endif /* !defined(IP_DEV_NAME) */ + +#if !defined(IP_MOD_NAME) +#define IP_MOD_NAME "ip" +#endif /* !defined(IP_MOD_NAME) */ + +#if !defined(UDP_DEV_NAME) && defined(SOL2) +#define UDP_DEV_NAME "/dev/udp" +#endif /* !defined(UDP_DEV_NAME) && defined(SOL2) */ + +#if !defined(UDP6_DEV_NAME) && defined(SOL2) +#define UDP6_DEV_NAME "/dev/udp6" +#endif /* !defined(UDP6_DEV_NAME) && defined(SOL2) */ static const char rcsid[] = RCSID; +#if defined(SOL2) +/* + * "/dev/udp" is used as a multiplexor to PLINK the interface stream + * under. It is used in place of "/dev/ip" since STREAMS will not let + * a driver be PLINK'ed under itself, and "/dev/ip" is typically the + * driver at the bottom of the tunneling interfaces stream. + */ +static char *mux_dev_name = UDP_DEV_NAME; +#else +static char *mux_dev_name = IP_DEV_NAME; +#endif static int pppfd; static int fdmuxid = -1; static int ipfd; @@ -97,6 +205,13 @@ static int if6_is_up = 0; /* IPv6 interface has been marked up */ #endif /* defined(INET6) && defined(SOL2) */ +#if defined(INET6) && defined(SOL2) +static char first_ether_name[LIFNAMSIZ]; /* Solaris 8 and above */ +#else +static char first_ether_name[IFNAMSIZ]; /* Before Solaris 8 */ +#define MAXIFS 256 /* Max # of interfaces */ +#endif /* defined(INET6) && defined(SOL2) */ + static int restore_term; static struct termios inittermios; #ifndef CRTSCTS @@ -156,8 +271,8 @@ static int strioctl __P((int, int, void *, int, int)); */ static int sifppa(fd, ppa) - int fd; - int ppa; + int fd; + int ppa; { return (int)ioctl(fd, IF_UNITSEL, (char *)&ppa); } @@ -165,47 +280,13 @@ sifppa(fd, ppa) #if defined(SOL2) && defined(INET6) /* - * slifname - Sets interface ppa and flags - * - * in addition to the comments stated in sifppa(), IFF_IPV6 bit must - * be set in order to declare this as an IPv6 interface - */ -static int -slifname(fd, ppa) - int fd; - int ppa; -{ - struct lifreq lifr; - int ret; - - memset(&lifr, 0, sizeof(lifr)); - ret = ioctl(fd, SIOCGLIFFLAGS, &lifr); - if (ret < 0) - goto slifname_done; - - lifr.lifr_flags |= IFF_IPV6; - lifr.lifr_flags &= ~(IFF_BROADCAST | IFF_IPV4); - lifr.lifr_ppa = ppa; - strlcpy(lifr.lifr_name, ifname, sizeof(lifr.lifr_name)); - - ret = ioctl(fd, SIOCSLIFNAME, &lifr); - -slifname_done: - return ret; - - -} - -/* - * ether_to_eui64 - Convert 48-bit Ethernet address into 64-bit EUI + * get_first_ethernet - returns the first Ethernet interface name found in + * the system, or NULL if none is found * - * walks the list of valid ethernet interfaces, and convert the first - * found 48-bit MAC address into EUI 64. caller also assumes that - * the system has a properly configured Ethernet interface for this - * function to return non-zero. + * NOTE: This is the lifreq version (Solaris 8 and above) */ -int -ether_to_eui64(eui64_t *p_eui64) +char * +get_first_ethernet() { struct lifnum lifn; struct lifconf lifc; @@ -214,8 +295,6 @@ ether_to_eui64(eui64_t *p_eui64) int fd, num_ifs, i, found; uint_t fl, req_size; char *req; - struct sockaddr s_eth_addr; - struct ether_addr *eth_addr = (struct ether_addr *)&s_eth_addr.sa_data; fd = socket(AF_INET, SOCK_DGRAM, 0); if (fd < 0) { @@ -262,7 +341,7 @@ ether_to_eui64(eui64_t *p_eui64) */ plifreq = lifc.lifc_req; found = 0; - for (i = lifc.lifc_len / sizeof(struct lifreq); i>0; i--, plifreq++) { + for (i = lifc.lifc_len / sizeof(struct lifreq); i > 0; i--, plifreq++) { if (strchr(plifreq->lifr_name, ':') != NULL) continue; @@ -287,7 +366,177 @@ ether_to_eui64(eui64_t *p_eui64) free(req); close(fd); - if (!found) { + if (found) { + strncpy(first_ether_name, lifr.lifr_name, sizeof(first_ether_name)); + return (char *)first_ether_name; + } else + return NULL; +} +#else +/* + * get_first_ethernet - returns the first Ethernet interface name found in + * the system, or NULL if none is found + * + * NOTE: This is the ifreq version (before Solaris 8). + */ +char * +get_first_ethernet() +{ + struct ifconf ifc; + struct ifreq *pifreq; + struct ifreq ifr; + int fd, num_ifs, i, found; + uint_t fl, req_size; + char *req; + + fd = socket(AF_INET, SOCK_DGRAM, 0); + if (fd < 0) { + return 0; + } + + /* + * Find out how many interfaces are running + */ + if (ioctl(fd, SIOCGIFNUM, (char *)&num_ifs) < 0) { + num_ifs = MAXIFS; + } + + req_size = num_ifs * sizeof(struct ifreq); + req = malloc(req_size); + if (req == NULL) { + close(fd); + error("out of memory"); + return 0; + } + + /* + * Get interface configuration info for all interfaces + */ + ifc.ifc_len = req_size; + ifc.ifc_buf = req; + if (ioctl(fd, SIOCGIFCONF, &ifc) < 0) { + close(fd); + free(req); + error("SIOCGIFCONF: %m"); + return 0; + } + + /* + * And traverse each interface to look specifically for the first + * occurence of an Ethernet interface which has been marked up + */ + pifreq = ifc.ifc_req; + found = 0; + for (i = ifc.ifc_len / sizeof(struct ifreq); i > 0; i--, pifreq++) { + + if (strchr(pifreq->ifr_name, ':') != NULL) + continue; + + memset(&ifr, 0, sizeof(ifr)); + strncpy(ifr.ifr_name, pifreq->ifr_name, sizeof(ifr.ifr_name)); + if (ioctl(fd, SIOCGIFFLAGS, &ifr) < 0) { + close(fd); + free(req); + error("SIOCGIFFLAGS: %m"); + return 0; + } + fl = ifr.ifr_flags; + + if ((fl & (IFF_UP|IFF_BROADCAST|IFF_POINTOPOINT|IFF_LOOPBACK|IFF_NOARP)) + != (IFF_UP | IFF_BROADCAST)) + continue; + + found = 1; + break; + } + free(req); + close(fd); + + if (found) { + strncpy(first_ether_name, ifr.ifr_name, sizeof(first_ether_name)); + return (char *)first_ether_name; + } else + return NULL; +} +#endif /* defined(SOL2) && defined(INET6) */ + +#if defined(SOL2) +/* + * get_if_hwaddr - get the hardware address for the specified + * network interface device. + */ +int +get_if_hwaddr(u_char *addr, char *if_name) +{ + struct sockaddr s_eth_addr; + struct ether_addr *eth_addr = (struct ether_addr *)&s_eth_addr.sa_data; + + if (if_name == NULL) + return -1; + + /* + * Send DL_INFO_REQ to the driver to solicit its MAC address + */ + if (!get_hw_addr_dlpi(if_name, &s_eth_addr)) { + error("could not obtain hardware address for %s", if_name); + return -1; + } + + memcpy(addr, eth_addr->ether_addr_octet, 6); + return 1; +} +#endif /* SOL2 */ + +#if defined(SOL2) && defined(INET6) +/* + * slifname - Sets interface ppa and flags + * + * in addition to the comments stated in sifppa(), IFF_IPV6 bit must + * be set in order to declare this as an IPv6 interface + */ +static int +slifname(fd, ppa) + int fd; + int ppa; +{ + struct lifreq lifr; + int ret; + + memset(&lifr, 0, sizeof(lifr)); + ret = ioctl(fd, SIOCGLIFFLAGS, &lifr); + if (ret < 0) + goto slifname_done; + + lifr.lifr_flags |= IFF_IPV6; + lifr.lifr_flags &= ~(IFF_BROADCAST | IFF_IPV4); + lifr.lifr_ppa = ppa; + strlcpy(lifr.lifr_name, ifname, sizeof(lifr.lifr_name)); + + ret = ioctl(fd, SIOCSLIFNAME, &lifr); + +slifname_done: + return ret; + + +} + + +/* + * ether_to_eui64 - Convert 48-bit Ethernet address into 64-bit EUI + * + * walks the list of valid ethernet interfaces, and convert the first + * found 48-bit MAC address 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 sockaddr s_eth_addr; + struct ether_addr *eth_addr = (struct ether_addr *)&s_eth_addr.sa_data; + char *if_name; + + if ((if_name = get_first_ethernet()) == NULL) { error("no persistent id can be found"); return 0; } @@ -295,8 +544,8 @@ ether_to_eui64(eui64_t *p_eui64) /* * Send DL_INFO_REQ to the driver to solicit its MAC address */ - if (!get_hw_addr_dlpi(plifreq->lifr_name, &s_eth_addr)) { - error("could not obtain hardware address for %s", plifreq->lifr_name); + if (!get_hw_addr_dlpi(if_name, &s_eth_addr)) { + error("could not obtain hardware address for %s", if_name); return 0; } @@ -323,23 +572,24 @@ void sys_init() { int ifd, x; + struct ifreq ifr; #if defined(INET6) && defined(SOL2) int i6fd; + struct lifreq lifr; #endif /* defined(INET6) && defined(SOL2) */ #if !defined(SOL2) - struct ifreq ifr; struct { union DL_primitives prim; char space[64]; } reply; #endif /* !defined(SOL2) */ - ipfd = open("/dev/ip", O_RDWR, 0); + ipfd = open(mux_dev_name, O_RDWR, 0); if (ipfd < 0) fatal("Couldn't open IP device: %m"); #if defined(INET6) && defined(SOL2) - ip6fd = open("/dev/ip", O_RDWR, 0); + ip6fd = open(UDP6_DEV_NAME, O_RDWR, 0); if (ip6fd < 0) fatal("Couldn't open IP device (2): %m"); #endif /* defined(INET6) && defined(SOL2) */ @@ -347,9 +597,9 @@ sys_init() if (default_device && !notty) tty_sid = getsid((pid_t)0); - pppfd = open("/dev/ppp", O_RDWR | O_NONBLOCK, 0); + pppfd = open(PPP_DEV_NAME, O_RDWR | O_NONBLOCK, 0); if (pppfd < 0) - fatal("Can't open /dev/ppp: %m"); + fatal("Can't open %s: %m", PPP_DEV_NAME); if (kdebugflag & 1) { x = PPPDBG_LOG + PPPDBG_DRIVER; strioctl(pppfd, PPPIO_DEBUG, &x, sizeof(int), 0); @@ -359,31 +609,33 @@ sys_init() if (strioctl(pppfd, PPPIO_NEWPPA, &ifunit, 0, sizeof(int)) < 0) fatal("Can't create new PPP interface: %m"); +#if defined(SOL2) + /* + * Since sys_init() is called prior to ifname being set in main(), + * we need to get the ifname now, otherwise slifname(), and others, + * will fail, or maybe, I should move them to a later point ? + * + */ + sprintf(ifname, "ppp%d", ifunit); +#endif /* defined(SOL2) */ /* * Open the ppp device again and link it under the ip multiplexor. * IP will assign a unit number which hopefully is the same as ifunit. * I don't know any way to be certain they will be the same. :-( */ - ifd = open("/dev/ppp", O_RDWR, 0); + ifd = open(PPP_DEV_NAME, O_RDWR, 0); if (ifd < 0) - fatal("Can't open /dev/ppp (2): %m"); + fatal("Can't open %s (2): %m", PPP_DEV_NAME); if (kdebugflag & 1) { x = PPPDBG_LOG + PPPDBG_DRIVER; strioctl(ifd, PPPIO_DEBUG, &x, sizeof(int), 0); } #if defined(INET6) && defined(SOL2) - /* - * Since sys_init() is called prior to ifname being set in main(), - * we need to get the ifname now, otherwise slifname() will fail, - * or maybe, I should move slifname() to a later point ? - */ - sprintf(ifname, "ppp%d", ifunit); - - i6fd = open("/dev/ppp", O_RDWR, 0); + i6fd = open(PPP_DEV_NAME, O_RDWR, 0); if (i6fd < 0) { close(ifd); - fatal("Can't open /dev/ppp (3): %m"); + fatal("Can't open %s (3): %m", PPP_DEV_NAME); } if (kdebugflag & 1) { x = PPPDBG_LOG + PPPDBG_DRIVER; @@ -392,7 +644,7 @@ sys_init() #endif /* defined(INET6) && defined(SOL2) */ #if defined(SOL2) - if (ioctl(ifd, I_PUSH, "ip") < 0) { + if (ioctl(ifd, I_PUSH, IP_MOD_NAME) < 0) { close(ifd); #if defined(INET6) close(i6fd); @@ -418,7 +670,7 @@ sys_init() * explicitly enable it. Note that the interface will be marked * IPv6 during slifname(). */ - if (ioctl(i6fd, I_PUSH, "ip") < 0) { + if (ioctl(i6fd, I_PUSH, IP_MOD_NAME) < 0) { close(ifd); close(i6fd); fatal("Can't push IP module (2): %m"); @@ -436,6 +688,34 @@ sys_init() } #endif /* defined(INET6) */ + ipmuxid = ioctl(ipfd, I_PLINK, ifd); + close(ifd); + if (ipmuxid < 0) { +#if defined(INET6) + close(i6fd); +#endif /* defined(INET6) */ + fatal("Can't I_PLINK PPP device to IP: %m"); + } + + memset(&ifr, 0, sizeof(ifr)); + sprintf(ifr.ifr_name, "%s", ifname); + ifr.ifr_ip_muxid = ipmuxid; + + /* + * In Sol 8 and later, STREAMS dynamic module plumbing feature exists. + * This is so that an arbitrary module can be inserted, or deleted, + * between ip module and the device driver without tearing down the + * existing stream. Such feature requires the mux ids, which is set + * by SIOCSIFMUXID (or SIOCLSIFMUXID). + */ + if (ioctl(ipfd, SIOCSIFMUXID, &ifr) < 0) { + ioctl(ipfd, I_PUNLINK, ipmuxid); +#if defined(INET6) + close(i6fd); +#endif /* defined(INET6) */ + fatal("SIOCSIFMUXID: %m"); + } + #else /* else if !defined(SOL2) */ if (dlpi_attach(ifd, ifunit) < 0 || @@ -443,18 +723,33 @@ sys_init() close(ifd); fatal("Can't attach to ppp%d: %m", ifunit); } -#endif /* defined(SOL2) */ ipmuxid = ioctl(ipfd, I_LINK, ifd); close(ifd); if (ipmuxid < 0) fatal("Can't link PPP device to IP: %m"); +#endif /* defined(SOL2) */ #if defined(INET6) && defined(SOL2) - ip6muxid = ioctl(ip6fd, I_LINK, i6fd); + ip6muxid = ioctl(ip6fd, I_PLINK, i6fd); close(i6fd); - if (ip6muxid < 0) + if (ip6muxid < 0) { + ioctl(ipfd, I_PUNLINK, ipmuxid); + fatal("Can't I_PLINK PPP device to IP (2): %m"); + } + + memset(&lifr, 0, sizeof(lifr)); + sprintf(lifr.lifr_name, "%s", ifname); + lifr.lifr_ip_muxid = ip6muxid; + + /* + * Let IP know of the mux id [see comment for SIOCSIFMUXID above] + */ + if (ioctl(ip6fd, SIOCSLIFMUXID, &lifr) < 0) { + ioctl(ipfd, I_PUNLINK, ipmuxid); + ioctl(ip6fd, I_PUNLINK, ip6muxid); fatal("Can't link PPP device to IP (2): %m"); + } #endif /* defined(INET6) && defined(SOL2) */ #if !defined(SOL2) @@ -476,7 +771,12 @@ sys_init() void sys_cleanup() { +#if defined(SOL2) struct ifreq ifr; +#if defined(INET6) + struct lifreq lifr; +#endif /* defined(INET6) */ +#endif /* defined(SOL2) */ #if defined(SOL2) && defined(INET6) if (if6_is_up) @@ -488,6 +788,53 @@ sys_cleanup() cifdefaultroute(0, default_route_gateway, default_route_gateway); if (proxy_arp_addr) cifproxyarp(0, proxy_arp_addr); +#if defined(SOL2) + /* + * Make sure we ask ip what the muxid, because 'ifconfig modlist' will + * unlink and re-link the modules, causing the muxid to change. + */ + memset(&ifr, 0, sizeof(ifr)); + sprintf(ifr.ifr_name, "%s", ifname); + if (ioctl(ipfd, SIOCGIFFLAGS, &ifr) < 0) { + error("SIOCGIFFLAGS: %m"); + return; + } + + if (ioctl(ipfd, SIOCGIFMUXID, &ifr) < 0) { + error("SIOCGIFMUXID: %m"); + return; + } + + ipmuxid = ifr.ifr_ip_muxid; + + if (ioctl(ipfd, I_PUNLINK, ipmuxid) < 0) { + error("Can't I_PUNLINK PPP from IP: %m"); + return; + } +#if defined(INET6) + /* + * Make sure we ask ip what the muxid, because 'ifconfig modlist' will + * unlink and re-link the modules, causing the muxid to change. + */ + memset(&lifr, 0, sizeof(lifr)); + sprintf(lifr.lifr_name, "%s", ifname); + if (ioctl(ip6fd, SIOCGLIFFLAGS, &lifr) < 0) { + error("SIOCGLIFFLAGS: %m"); + return; + } + + if (ioctl(ip6fd, SIOCGLIFMUXID, &lifr) < 0) { + error("SIOCGLIFMUXID: %m"); + return; + } + + ip6muxid = lifr.lifr_ip_muxid; + + if (ioctl(ip6fd, I_PUNLINK, ip6muxid) < 0) { + error("Can't I_PUNLINK PPP from IP (2): %m"); + } +#endif /* defined(INET6) */ +#endif /* defined(SOL2) */ } /* @@ -547,7 +894,28 @@ ppp_available() { struct stat buf; - return stat("/dev/ppp", &buf) >= 0; + return stat(PPP_DEV_NAME, &buf) >= 0; +} + +/* + * any_compressions - see if compression is enabled or not + * + * In the STREAMS implementation of kernel-portion pppd, + * the comp STREAMS module performs the ACFC, PFC, as well + * CCP and VJ compressions. However, if the user has explicitly + * declare to not enable them from the command line, there is + * no point of having the comp module be pushed on the stream. + */ +static int +any_compressions() +{ + if ((!lcp_wantoptions[0].neg_accompression) && + (!lcp_wantoptions[0].neg_pcompression) && + (!ccp_protent.enabled_flag) && + (!ipcp_wantoptions[0].neg_vj)) { + return 0; + } + return 1; } /* @@ -571,7 +939,7 @@ establish_ppp(fd) tty_npushed = 0; if(!sync_serial) { - if (ioctl(fd, I_PUSH, "ppp_ahdl") < 0) { + if (ioctl(fd, I_PUSH, AHDLC_MOD_NAME) < 0) { error("Couldn't push PPP Async HDLC module: %m"); return -1; } @@ -581,12 +949,21 @@ establish_ppp(fd) i = PPPDBG_LOG + PPPDBG_AHDLC; strioctl(pppfd, PPPIO_DEBUG, &i, sizeof(int), 0); } - if (ioctl(fd, I_PUSH, "ppp_comp") < 0) - error("Couldn't push PPP compression module: %m"); - else - ++tty_npushed; + /* + * There's no need to push comp module if we don't intend + * to compress anything + */ + if (any_compressions()) { + if (ioctl(fd, I_PUSH, COMP_MOD_NAME) < 0) + error("Couldn't push PPP compression module: %m"); + else + ++tty_npushed; + } + if (kdebugflag & 2) { - i = PPPDBG_LOG + PPPDBG_COMP; + i = PPPDBG_LOG; + if (any_compressions()) + i += PPPDBG_COMP; strioctl(pppfd, PPPIO_DEBUG, &i, sizeof(int), 0); } @@ -753,6 +1130,18 @@ struct speed { #endif #ifdef B115200 { 115200, B115200 }, +#endif +#ifdef B153600 + { 153600, B153600 }, +#endif +#ifdef B230400 + { 230400, B230400 }, +#endif +#ifdef B307200 + { 307200, B307200 }, +#endif +#ifdef B460800 + { 460800, B460800 }, #endif { 0, 0 } }; @@ -812,7 +1201,7 @@ set_up_tty(fd, local) #ifndef CRTSCTS termiox_ok = 1; - if (ioctl (fd, TCGETX, &tiox) < 0) { + if (!sync_serial && ioctl (fd, TCGETX, &tiox) < 0) { termiox_ok = 0; if (errno != ENOTTY) error("TCGETX: %m"); @@ -824,7 +1213,8 @@ set_up_tty(fd, local) #ifndef CRTSCTS inittermiox = tiox; #endif - ioctl(fd, TIOCGWINSZ, &wsinfo); + if (!sync_serial) + ioctl(fd, TIOCGWINSZ, &wsinfo); } tios.c_cflag &= ~(CSIZE | CSTOPB | PARENB | CLOCAL); @@ -868,7 +1258,7 @@ set_up_tty(fd, local) * We can't proceed if the serial port speed is 0, * since that implies that the serial port is disabled. */ - if (speed == B0) + if ((speed == B0) && !sync_serial) fatal("Baud rate for %s is 0; need explicit baud rate", devnam); } @@ -876,13 +1266,14 @@ set_up_tty(fd, local) fatal("tcsetattr: %m"); #ifndef CRTSCTS - if (termiox_ok && ioctl (fd, TCSETXF, &tiox) < 0){ + if (!sync_serial && termiox_ok && ioctl (fd, TCSETXF, &tiox) < 0){ error("TCSETXF: %m"); } #endif baud_rate = inspeed = baud_rate_of(speed); - restore_term = 1; + if (!sync_serial) + restore_term = 1; } /* @@ -902,16 +1293,17 @@ restore_tty(fd) */ inittermios.c_lflag &= ~(ECHO | ECHONL); } - if (tcsetattr(fd, TCSAFLUSH, &inittermios) < 0) + if (!sync_serial && tcsetattr(fd, TCSAFLUSH, &inittermios) < 0) if (!hungup && errno != ENXIO) warn("tcsetattr: %m"); #ifndef CRTSCTS - if (ioctl (fd, TCSETXF, &inittermiox) < 0){ + if (!sync_serial && ioctl (fd, TCSETXF, &inittermiox) < 0){ if (!hungup && errno != ENXIO) error("TCSETXF: %m"); } #endif - ioctl(fd, TIOCSWINSZ, &wsinfo); + if (!sync_serial) + ioctl(fd, TIOCSWINSZ, &wsinfo); restore_term = 0; } } @@ -953,8 +1345,8 @@ output(unit, p, len) int retries; struct pollfd pfd; - if (debug) - dbglog("sent %P", p, len); + dump_packet("sent", p, len); + if (snoop_send_hook) snoop_send_hook(p, len); data.len = len; data.buf = (caddr_t) p; @@ -1135,13 +1527,15 @@ ppp_send_config(unit, mtu, asyncmap, pcomp, accomp) error("Couldn't set MTU: %m"); } if (fdmuxid >= 0) { - /* can't set these if we don't have a stream attached below /dev/ppp */ - if (strioctl(pppfd, PPPIO_XACCM, &asyncmap, sizeof(asyncmap), 0) < 0) { - error("Couldn't set transmit ACCM: %m"); + if (!sync_serial) { + if (strioctl(pppfd, PPPIO_XACCM, &asyncmap, sizeof(asyncmap), 0) < 0) { + error("Couldn't set transmit ACCM: %m"); + } } cf[0] = (pcomp? COMP_PROT: 0) + (accomp? COMP_AC: 0); cf[1] = COMP_PROT | COMP_AC; - if (strioctl(pppfd, PPPIO_CFLAGS, cf, sizeof(cf), sizeof(int)) < 0) { + if (any_compressions() && + strioctl(pppfd, PPPIO_CFLAGS, cf, sizeof(cf), sizeof(int)) < 0) { error("Couldn't set prot/AC compression: %m"); } } @@ -1178,6 +1572,9 @@ ppp_set_xaccm(unit, accm) int unit; ext_accm accm; { + if (sync_serial) + return; + if (fdmuxid >= 0 && strioctl(pppfd, PPPIO_XACCM, accm, sizeof(ext_accm), 0) < 0) { if (!hungup || errno != ENXIO) @@ -1204,13 +1601,15 @@ ppp_recv_config(unit, mru, asyncmap, pcomp, accomp) error("Couldn't set MRU: %m"); } if (fdmuxid >= 0) { - /* can't set these if we don't have a stream attached below /dev/ppp */ - if (strioctl(pppfd, PPPIO_RACCM, &asyncmap, sizeof(asyncmap), 0) < 0) { - error("Couldn't set receive ACCM: %m"); + if (!sync_serial) { + if (strioctl(pppfd, PPPIO_RACCM, &asyncmap, sizeof(asyncmap), 0) < 0) { + error("Couldn't set receive ACCM: %m"); + } } cf[0] = (pcomp? DECOMP_PROT: 0) + (accomp? DECOMP_AC: 0); cf[1] = DECOMP_PROT | DECOMP_AC; - if (strioctl(pppfd, PPPIO_CFLAGS, cf, sizeof(cf), sizeof(int)) < 0) { + if (any_compressions() && + strioctl(pppfd, PPPIO_CFLAGS, cf, sizeof(cf), sizeof(int)) < 0) { error("Couldn't set prot/AC decompression: %m"); } } @@ -1269,7 +1668,8 @@ get_ppp_stats(u, stats) { struct ppp_stats s; - if (strioctl(pppfd, PPPIO_GETSTAT, &s, 0, sizeof(s)) < 0) { + if (!sync_serial && + strioctl(pppfd, PPPIO_GETSTAT, &s, 0, sizeof(s)) < 0) { error("Couldn't get link statistics: %m"); return 0; } @@ -2251,9 +2651,9 @@ have_route_to(addr) mib2_ipRouteEntry_t routes[8]; mib2_ipRouteEntry_t *rp; - fd = open("/dev/ip", O_RDWR); + fd = open(mux_dev_name, O_RDWR); if (fd < 0) { - warn("have_route_to: couldn't open /dev/ip: %m"); + warn("have_route_to: couldn't open %s: %m", mux_dev_name); return -1; }