/*
* System-dependent procedures for pppd under Solaris 2.
*
- * Copyright (c) 1994 The Australian National University.
+ * Parts re-written by Adi Masputra <adi.masputra@sun.com>, 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. 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.
+ *
+ * 3. Redistributions of any form whatsoever must retain the following
+ * acknowledgment:
+ * "This product includes software developed by Paul Mackerras
+ * <paulus@samba.org>".
+ *
+ * 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.
*
- * 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.
+ * Derived from main.c and pppd.h, which are:
*
- * 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.
+ * Copyright (c) 1984-2000 Carnegie Mellon University. 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 "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.36 1999/10/08 01:09:03 masputra Exp $"
+#define RCSID "$Id: sys-svr4.c,v 1.46 2004/11/04 10:02:26 paulus Exp $"
#include <limits.h>
#include <stdio.h>
#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"
static const char rcsid[] = RCSID;
-static char *mux_dev_name;
+#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;
#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
#if defined(SOL2) && defined(INET6)
/*
- * slifname - Sets interface ppa and flags
+ * get_first_ethernet - returns the first Ethernet interface name found in
+ * the system, or NULL if none is found
*
- * in addition to the comments stated in sifppa(), IFF_IPV6 bit must
- * be set in order to declare this as an IPv6 interface
+ * NOTE: This is the lifreq version (Solaris 8 and above)
*/
-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)
+char *
+get_first_ethernet()
{
struct lifnum lifn;
struct lifconf lifc;
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) {
*/
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;
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;
}
/*
* 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;
}
} reply;
#endif /* !defined(SOL2) */
-#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.
- */
- mux_dev_name = UDP_DEV_NAME;
-#else
- mux_dev_name = IP_DEV_NAME;
-#endif
-
ipfd = open(mux_dev_name, O_RDWR, 0);
if (ipfd < 0)
fatal("Couldn't open IP device: %m");
ifr.ifr_ip_muxid = ipmuxid;
/*
- * In Sol 8 and later, STREAMS dynamic module plumbing feature exits.
+ * 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
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;
+}
+
/*
* establish_ppp - Turn the serial port into a ppp interface.
*/
i = PPPDBG_LOG + PPPDBG_AHDLC;
strioctl(pppfd, PPPIO_DEBUG, &i, sizeof(int), 0);
}
- if (ioctl(fd, I_PUSH, COMP_MOD_NAME) < 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);
}
#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 }
};
#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");
#ifndef CRTSCTS
inittermiox = tiox;
#endif
- ioctl(fd, TIOCGWINSZ, &wsinfo);
+ if (!sync_serial)
+ ioctl(fd, TIOCGWINSZ, &wsinfo);
}
tios.c_cflag &= ~(CSIZE | CSTOPB | PARENB | CLOCAL);
* 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);
}
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;
}
/*
*/
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;
}
}
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;
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");
}
}
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)
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");
}
}
{
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;
}