Home | History | Annotate | Download | only in pppd
      1     0    stevel /*
      2     0    stevel  * System-dependent procedures for pppd under Solaris 2.x (SunOS 5.x).
      3     0    stevel  *
      4  9354       Tim  * Copyright 2009 Sun Microsystems, Inc.  All rights reserved.
      5     0    stevel  * Use is subject to license terms.
      6     0    stevel  *
      7     0    stevel  * Permission to use, copy, modify, and distribute this software and its
      8     0    stevel  * documentation is hereby granted, provided that the above copyright
      9     0    stevel  * notice appears in all copies.
     10     0    stevel  *
     11     0    stevel  * SUN MAKES NO REPRESENTATION OR WARRANTIES ABOUT THE SUITABILITY OF
     12     0    stevel  * THE SOFTWARE, EITHER EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED
     13     0    stevel  * TO THE IMPLIED WARRANTIES OF MERCHANTABILITY, FITNESS FOR A
     14     0    stevel  * PARTICULAR PURPOSE, OR NON-INFRINGEMENT.  SUN SHALL NOT BE LIABLE FOR
     15     0    stevel  * ANY DAMAGES SUFFERED BY LICENSEE AS A RESULT OF USING, MODIFYING OR
     16     0    stevel  * DISTRIBUTING THIS SOFTWARE OR ITS DERIVATIVES
     17     0    stevel  *
     18     0    stevel  * Copyright (c) 1994 The Australian National University.
     19     0    stevel  * All rights reserved.
     20     0    stevel  *
     21     0    stevel  * Permission to use, copy, modify, and distribute this software and its
     22     0    stevel  * documentation is hereby granted, provided that the above copyright
     23     0    stevel  * notice appears in all copies.  This software is provided without any
     24     0    stevel  * warranty, express or implied. The Australian National University
     25     0    stevel  * makes no representations about the suitability of this software for
     26     0    stevel  * any purpose.
     27     0    stevel  *
     28     0    stevel  * IN NO EVENT SHALL THE AUSTRALIAN NATIONAL UNIVERSITY BE LIABLE TO ANY
     29     0    stevel  * PARTY FOR DIRECT, INDIRECT, SPECIAL, INCIDENTAL, OR CONSEQUENTIAL DAMAGES
     30     0    stevel  * ARISING OUT OF THE USE OF THIS SOFTWARE AND ITS DOCUMENTATION, EVEN IF
     31     0    stevel  * THE AUSTRALIAN NATIONAL UNIVERSITY HAVE BEEN ADVISED OF THE POSSIBILITY
     32     0    stevel  * OF SUCH DAMAGE.
     33     0    stevel  *
     34     0    stevel  * THE AUSTRALIAN NATIONAL UNIVERSITY SPECIFICALLY DISCLAIMS ANY WARRANTIES,
     35     0    stevel  * INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY
     36     0    stevel  * AND FITNESS FOR A PARTICULAR PURPOSE.  THE SOFTWARE PROVIDED HEREUNDER IS
     37     0    stevel  * ON AN "AS IS" BASIS, AND THE AUSTRALIAN NATIONAL UNIVERSITY HAS NO
     38     0    stevel  * OBLIGATION TO PROVIDE MAINTENANCE, SUPPORT, UPDATES, ENHANCEMENTS,
     39     0    stevel  * OR MODIFICATIONS.
     40     0    stevel  */
     41     0    stevel 
     42     0    stevel #define	RCSID	"$Id: sys-solaris.c,v 1.2 2000/04/21 01:27:57 masputra Exp $"
     43     0    stevel 
     44     0    stevel #include <limits.h>
     45     0    stevel #include <stdio.h>
     46     0    stevel #include <stddef.h>
     47     0    stevel #include <stdlib.h>
     48     0    stevel #include <ctype.h>
     49     0    stevel #include <errno.h>
     50     0    stevel #include <fcntl.h>
     51     0    stevel #include <unistd.h>
     52     0    stevel #include <netdb.h>
     53     0    stevel #include <termios.h>
     54     0    stevel #include <signal.h>
     55     0    stevel #include <string.h>
     56     0    stevel #include <stropts.h>
     57     0    stevel #include <utmpx.h>
     58     0    stevel #include <sys/types.h>
     59     0    stevel #include <sys/ioccom.h>
     60     0    stevel #include <sys/stream.h>
     61     0    stevel #include <sys/stropts.h>
     62     0    stevel #include <sys/socket.h>
     63     0    stevel #include <sys/sockio.h>
     64     0    stevel #include <sys/sysmacros.h>
     65     0    stevel #include <sys/systeminfo.h>
     66     0    stevel #include <sys/stat.h>
     67     0    stevel #include <net/if.h>
     68     0    stevel #include <net/if_arp.h>
     69     0    stevel #include <net/route.h>
     70     0    stevel #include <net/ppp_defs.h>
     71     0    stevel #include <net/pppio.h>
     72     0    stevel #include <net/if_types.h>
     73     0    stevel #include <net/if_dl.h>
     74     0    stevel #include <netinet/in.h>
     75     0    stevel #include <sys/tihdr.h>
     76     0    stevel #include <inet/mib2.h>
     77   741  masputra #include <inet/ip.h>
     78     0    stevel #include <sys/ethernet.h>
     79     0    stevel #include <sys/ser_sync.h>
     80  6631  ss150715 #include <libdlpi.h>
     81  9751     james #include <arpa/inet.h>
     82     0    stevel 
     83     0    stevel #include "pppd.h"
     84     0    stevel #include "fsm.h"
     85     0    stevel #include "lcp.h"
     86     0    stevel #include "ipcp.h"
     87     0    stevel #ifdef INET6
     88     0    stevel #include "ipv6cp.h"
     89     0    stevel #endif /* INET6 */
     90     0    stevel #include "ccp.h"
     91     0    stevel 
     92     0    stevel #if !defined(lint) && !defined(_lint)
     93     0    stevel static const char rcsid[] = RCSID;
     94     0    stevel #endif
     95     0    stevel 
     96     0    stevel #define	PPPSTRTIMOUT	1	/* Timeout in seconds for ioctl */
     97     0    stevel #define	MAX_POLLFDS	32
     98     0    stevel #define	NMODULES	32
     99     0    stevel 
    100     0    stevel #ifndef MAXIFS
    101     0    stevel #define	MAXIFS		256
    102     0    stevel #endif /* MAXIFS */
    103     0    stevel 
    104     0    stevel #ifdef INET6
    105     0    stevel #define	_IN6_LLX_FROM_EUI64(l, s, eui64, as, len)	\
    106     0    stevel 	(s->sin6_addr.s6_addr32[0] = htonl(as),		\
    107     0    stevel 	eui64_copy(eui64, s->sin6_addr.s6_addr32[2]),	\
    108     0    stevel 	s->sin6_family = AF_INET6,			\
    109     0    stevel 	l.lifr_addr.ss_family = AF_INET6,		\
    110     0    stevel 	l.lifr_addrlen = len,				\
    111     0    stevel 	l.lifr_addr = laddr)
    112     0    stevel 
    113     0    stevel /*
    114     0    stevel  * Generate a link-local address with an interface-id based on the given
    115     0    stevel  * EUI64 identifier.  Note that the len field is unused by SIOCSLIFADDR.
    116     0    stevel  */
    117     0    stevel #define	IN6_LLADDR_FROM_EUI64(l, s, eui64)		\
    118     0    stevel 	_IN6_LLX_FROM_EUI64(l, s, eui64, 0xfe800000, 0)
    119     0    stevel 
    120     0    stevel /*
    121     0    stevel  * Generate an EUI64 based interface-id for use by stateless address
    122     0    stevel  * autoconfiguration.  These are required to be 64 bits long as defined in
    123     0    stevel  * the "Interface Identifiers" section of the IPv6 Addressing Architecture
    124     0    stevel  * (RFC3513).
    125     0    stevel  */
    126     0    stevel #define	IN6_LLTOKEN_FROM_EUI64(l, s, eui64) \
    127     0    stevel 	_IN6_LLX_FROM_EUI64(l, s, eui64, 0, 64)
    128     0    stevel #endif /* INET6 */
    129     0    stevel 
    130     0    stevel #define	IPCP_ENABLED	ipcp_protent.enabled_flag
    131     0    stevel #ifdef INET6
    132     0    stevel #define	IPV6CP_ENABLED	ipv6cp_protent.enabled_flag
    133     0    stevel #endif /* INET6 */
    134     0    stevel 
    135     0    stevel /* For plug-in usage. */
    136     0    stevel int (*sys_read_packet_hook) __P((int retv, struct strbuf *ctrl,
    137     0    stevel     struct strbuf *data, int flags)) = NULL;
    138     0    stevel bool already_ppp = 0;			/* Already in PPP mode */
    139     0    stevel 
    140     0    stevel static int pppfd = -1;			/* ppp driver fd */
    141     0    stevel static int fdmuxid = -1;		/* driver mux fd */
    142     0    stevel static int ipfd = -1;			/* IPv4 fd */
    143     0    stevel static int ipmuxid = -1;		/* IPv4 mux fd */
    144     0    stevel static int ip6fd = -1;			/* IPv6 fd */
    145     0    stevel static int ip6muxid = -1;		/* IPv6 mux fd */
    146     0    stevel static bool if6_is_up = 0;		/* IPv6 if marked as up */
    147     0    stevel static bool if_is_up = 0;		/* IPv4 if marked as up */
    148     0    stevel static bool restore_term = 0;		/* Restore TTY after closing link */
    149     0    stevel static struct termios inittermios;	/* TTY settings */
    150     0    stevel static struct winsize wsinfo;		/* Initial window size info */
    151     0    stevel static pid_t tty_sid;			/* original sess ID for term */
    152     0    stevel static struct pollfd pollfds[MAX_POLLFDS]; /* array of polled fd */
    153     0    stevel static int n_pollfds = 0;		/* total count of polled fd */
    154     0    stevel static int link_mtu;			/* link Maximum Transmit Unit */
    155     0    stevel static int tty_nmodules;		/* total count of TTY modules used */
    156     0    stevel static char tty_modules[NMODULES][FMNAMESZ+1];
    157     0    stevel 					/* array of TTY modules used */
    158     0    stevel static int tty_npushed;			/* total count of pushed PPP modules */
    159     0    stevel static u_int32_t remote_addr;		/* IP address of peer */
    160     0    stevel static u_int32_t default_route_gateway;	/* Gateway for default route */
    161     0    stevel static u_int32_t proxy_arp_addr;	/* Addr for proxy arp entry */
    162     0    stevel static u_int32_t lastlink_status;	/* Last link status info */
    163     0    stevel 
    164     0    stevel static bool use_plink = 0;		/* Use I_LINK by default */
    165     0    stevel static bool plumbed = 0;		/* Use existing interface */
    166     0    stevel 
    167     0    stevel /* Default is to use /dev/sppp as driver. */
    168     0    stevel static const char *drvnam = PPP_DEV_NAME;
    169     0    stevel static bool integrated_driver = 0;
    170     0    stevel static int extra_dev_fd = -1;		/* keep open until ready */
    171     0    stevel 
    172     0    stevel static option_t solaris_option_list[] = {
    173     0    stevel 	{ "plink", o_bool, &use_plink, "Use I_PLINK instead of I_LINK",
    174     0    stevel 	    OPT_PRIV|1 },
    175     0    stevel 	{ "noplink", o_bool, &use_plink, "Use I_LINK instead of I_PLINK",
    176     0    stevel 	    OPT_PRIV|0 },
    177     0    stevel 	{ "plumbed", o_bool, &plumbed, "Use pre-plumbed interface",
    178     0    stevel 	    OPT_PRIV|1 },
    179     0    stevel 	{ NULL }
    180     0    stevel };
    181     0    stevel 
    182     0    stevel /*
    183     0    stevel  * Prototypes for procedures local to this file.
    184     0    stevel  */
    185     0    stevel static int translate_speed __P((int));
    186     0    stevel static int baud_rate_of __P((int));
    187     0    stevel static int get_ether_addr __P((u_int32_t, struct sockaddr_dl *, int));
    188     0    stevel static int strioctl __P((int, int, void *, int, int));
    189     0    stevel static int plumb_ipif __P((int));
    190     0    stevel static int unplumb_ipif __P((int));
    191     0    stevel #ifdef INET6
    192     0    stevel static int plumb_ip6if __P((int));
    193     0    stevel static int unplumb_ip6if __P((int));
    194     0    stevel static int open_ip6fd(void);
    195     0    stevel #endif /* INET6 */
    196     0    stevel static int open_ipfd(void);
    197     0    stevel static int sifroute __P((int, u_int32_t, u_int32_t, int, const char *));
    198     0    stevel static int giflags __P((u_int32_t, bool *));
    199     0    stevel static void handle_unbind __P((u_int32_t));
    200     0    stevel static void handle_bind __P((u_int32_t));
    201     0    stevel 
    202     0    stevel /*
    203     0    stevel  * Wrapper for regular ioctl; masks out EINTR.
    204     0    stevel  */
    205     0    stevel static int
    206     0    stevel myioctl(int fd, int cmd, void *arg)
    207     0    stevel {
    208     0    stevel 	int retv;
    209     0    stevel 
    210     0    stevel 	errno = 0;
    211     0    stevel 	while ((retv = ioctl(fd, cmd, arg)) == -1) {
    212     0    stevel 		if (errno != EINTR)
    213     0    stevel 			break;
    214     0    stevel 	}
    215     0    stevel 	return (retv);
    216     0    stevel }
    217     0    stevel 
    218     0    stevel /*
    219     0    stevel  * sys_check_options()
    220     0    stevel  *
    221     0    stevel  * Check the options that the user specified.
    222     0    stevel  */
    223     0    stevel int
    224     0    stevel sys_check_options(void)
    225     0    stevel {
    226     0    stevel 	if (plumbed) {
    227     0    stevel 		if (req_unit == -1)
    228     0    stevel 			req_unit = -2;
    229     0    stevel 		ipmuxid = 0;
    230     0    stevel 		ip6muxid = 0;
    231     0    stevel 	}
    232     0    stevel 	return (1);
    233     0    stevel }
    234     0    stevel 
    235     0    stevel /*
    236     0    stevel  * sys_options()
    237     0    stevel  *
    238     0    stevel  * Add or remove system-specific options.
    239     0    stevel  */
    240     0    stevel void
    241     0    stevel sys_options(void)
    242     0    stevel {
    243     0    stevel 	(void) remove_option("ktune");
    244     0    stevel 	(void) remove_option("noktune");
    245     0    stevel 	add_options(solaris_option_list);
    246     0    stevel }
    247     0    stevel 
    248     0    stevel /*
    249     0    stevel  * sys_ifname()
    250     0    stevel  *
    251     0    stevel  * Set ifname[] to contain name of IP interface for this unit.
    252     0    stevel  */
    253     0    stevel void
    254     0    stevel sys_ifname(void)
    255     0    stevel {
    256     0    stevel 	const char *cp;
    257     0    stevel 
    258     0    stevel 	if ((cp = strrchr(drvnam, '/')) == NULL)
    259     0    stevel 		cp = drvnam;
    260     0    stevel 	else
    261     0    stevel 		cp++;
    262     0    stevel 	(void) slprintf(ifname, sizeof (ifname), "%s%d", cp, ifunit);
    263     0    stevel }
    264     0    stevel 
    265     0    stevel /*
    266     0    stevel  * ppp_available()
    267     0    stevel  *
    268     0    stevel  * Check whether the system has any ppp interfaces.
    269     0    stevel  */
    270     0    stevel int
    271     0    stevel ppp_available(void)
    272     0    stevel {
    273     0    stevel 	struct stat buf;
    274     0    stevel 	int fd;
    275     0    stevel 	uint32_t typ;
    276     0    stevel 
    277     0    stevel 	if (stat(PPP_DEV_NAME, &buf) >= 0)
    278     0    stevel 		return (1);
    279     0    stevel 
    280     0    stevel 	/*
    281     0    stevel 	 * Simple check for system using Apollo POS without SUNWpppd
    282     0    stevel 	 * (/dev/sppp) installed.  This is intentionally not kept open
    283     0    stevel 	 * here, since the user may not have the same privileges (as
    284     0    stevel 	 * determined later).  If Apollo were just shipped with the
    285     0    stevel 	 * full complement of packages, this wouldn't be an issue.
    286     0    stevel 	 */
    287     0    stevel 	if (devnam[0] == '\0' &&
    288     0    stevel 	    (fd = open(devnam, O_RDWR | O_NONBLOCK | O_NOCTTY)) >= 0) {
    289     0    stevel 		if (strioctl(fd, PPPIO_GTYPE, &typ, 0, sizeof (typ)) >= 0 &&
    290     0    stevel 		    typ == PPPTYP_MUX) {
    291     0    stevel 			(void) close(fd);
    292     0    stevel 			return (1);
    293     0    stevel 		}
    294     0    stevel 		(void) close(fd);
    295     0    stevel 	}
    296     0    stevel 	return (0);
    297     0    stevel }
    298     0    stevel 
    299     0    stevel static int
    300     0    stevel open_ipfd(void)
    301     0    stevel {
    302     0    stevel 	ipfd = open(IP_DEV_NAME, O_RDWR | O_NONBLOCK, 0);
    303     0    stevel 	if (ipfd < 0) {
    304     0    stevel 		error("Couldn't open IP device (%s): %m", IP_DEV_NAME);
    305     0    stevel 	}
    306     0    stevel 	return (ipfd);
    307     0    stevel }
    308     0    stevel 
    309     0    stevel static int
    310     0    stevel read_ip_interface(int unit)
    311     0    stevel {
    312     0    stevel 	struct ifreq ifr;
    313     0    stevel 	struct sockaddr_in sin;
    314     0    stevel 
    315     0    stevel 	if (ipfd == -1 && open_ipfd() == -1)
    316     0    stevel 		return (0);
    317     0    stevel 
    318     0    stevel 	BZERO(&ifr, sizeof (ifr));
    319     0    stevel 	(void) strlcpy(ifr.ifr_name, ifname, sizeof (ifr.ifr_name));
    320     0    stevel 
    321     0    stevel 	/* Get the existing MTU */
    322     0    stevel 	if (myioctl(ipfd, SIOCGIFMTU, &ifr) < 0) {
    323     0    stevel 		warn("Couldn't get IP MTU on %s: %m", ifr.ifr_name);
    324     0    stevel 		return (0);
    325     0    stevel 	}
    326     0    stevel 	dbglog("got MTU %d from interface", ifr.ifr_metric);
    327     0    stevel 	if (ifr.ifr_metric != 0 &&
    328     0    stevel 	    (lcp_allowoptions[unit].mru == 0 ||
    329  6631  ss150715 	    lcp_allowoptions[unit].mru > ifr.ifr_metric))
    330     0    stevel 		lcp_allowoptions[unit].mru = ifr.ifr_metric;
    331     0    stevel 
    332     0    stevel 	/* Get the local IP address */
    333     0    stevel 	if (ipcp_wantoptions[unit].ouraddr == 0 ||
    334     0    stevel 	    ipcp_from_hostname) {
    335     0    stevel 		if (myioctl(ipfd, SIOCGIFADDR, &ifr) < 0) {
    336     0    stevel 			warn("Couldn't get local IP address (%s): %m",
    337     0    stevel 			    ifr.ifr_name);
    338     0    stevel 			return (0);
    339     0    stevel 		}
    340     0    stevel 		BCOPY(&ifr.ifr_addr, &sin, sizeof (struct sockaddr_in));
    341     0    stevel 		ipcp_wantoptions[unit].ouraddr = sin.sin_addr.s_addr;
    342     0    stevel 		dbglog("got local address %I from interface",
    343     0    stevel 		    ipcp_wantoptions[unit].ouraddr);
    344     0    stevel 	}
    345     0    stevel 
    346     0    stevel 	/* Get the remote IP address */
    347     0    stevel 	if (ipcp_wantoptions[unit].hisaddr == 0) {
    348     0    stevel 		if (myioctl(ipfd, SIOCGIFDSTADDR, &ifr) < 0) {
    349     0    stevel 			warn("Couldn't get remote IP address (%s): %m",
    350     0    stevel 			    ifr.ifr_name);
    351     0    stevel 			return (0);
    352     0    stevel 		}
    353     0    stevel 		BCOPY(&ifr.ifr_dstaddr, &sin, sizeof (struct sockaddr_in));
    354     0    stevel 		ipcp_wantoptions[unit].hisaddr = sin.sin_addr.s_addr;
    355     0    stevel 		dbglog("got remote address %I from interface",
    356     0    stevel 		    ipcp_wantoptions[unit].hisaddr);
    357     0    stevel 	}
    358     0    stevel 	return (1);
    359     0    stevel }
    360     0    stevel 
    361     0    stevel #ifdef INET6
    362     0    stevel static int
    363     0    stevel open_ip6fd(void)
    364     0    stevel {
    365     0    stevel 	ip6fd = open(IP6_DEV_NAME, O_RDWR | O_NONBLOCK, 0);
    366     0    stevel 	if (ip6fd < 0) {
    367     0    stevel 		error("Couldn't open IPv6 device (%s): %m", IP6_DEV_NAME);
    368     0    stevel 	}
    369     0    stevel 	return (ip6fd);
    370     0    stevel }
    371     0    stevel 
    372     0    stevel static int
    373     0    stevel read_ipv6_interface(int unit)
    374     0    stevel {
    375     0    stevel 	struct lifreq lifr;
    376     0    stevel 	struct sockaddr_in6 *sin6 = (struct sockaddr_in6 *)&lifr.lifr_addr;
    377     0    stevel 
    378     0    stevel 	if (ip6fd == -1 && open_ip6fd() == -1)
    379     0    stevel 		return (0);
    380     0    stevel 
    381     0    stevel 	BZERO(&lifr, sizeof (lifr));
    382     0    stevel 	(void) strlcpy(lifr.lifr_name, ifname, sizeof (lifr.lifr_name));
    383     0    stevel 
    384     0    stevel 	/* Get the existing MTU */
    385     0    stevel 	if (myioctl(ip6fd, SIOCGLIFMTU, &lifr) < 0) {
    386     0    stevel 		warn("Couldn't get IPv6 MTU on %s: %m", lifr.lifr_name);
    387     0    stevel 		return (0);
    388     0    stevel 	}
    389     0    stevel 	if (lifr.lifr_mtu != 0 &&
    390     0    stevel 	    (lcp_allowoptions[unit].mru == 0 ||
    391  6631  ss150715 	    lcp_allowoptions[unit].mru > lifr.lifr_mtu))
    392     0    stevel 		lcp_allowoptions[unit].mru = lifr.lifr_mtu;
    393     0    stevel 
    394     0    stevel 	/* Get the local IPv6 address */
    395     0    stevel 	if (eui64_iszero(ipv6cp_wantoptions[unit].ourid) ||
    396     0    stevel 	    (ipcp_from_hostname && ipv6cp_wantoptions[unit].use_ip)) {
    397     0    stevel 		if (myioctl(ip6fd, SIOCGLIFADDR, &lifr) < 0) {
    398     0    stevel 			warn("Couldn't get local IPv6 address (%s): %m",
    399     0    stevel 			    lifr.lifr_name);
    400     0    stevel 			return (0);
    401     0    stevel 		}
    402     0    stevel 		eui64_copy(sin6->sin6_addr.s6_addr32[2],
    403     0    stevel 		    ipv6cp_wantoptions[unit].ourid);
    404     0    stevel 	}
    405     0    stevel 
    406     0    stevel 	/* Get the remote IP address */
    407     0    stevel 	if (eui64_iszero(ipv6cp_wantoptions[unit].hisid)) {
    408     0    stevel 		if (myioctl(ip6fd, SIOCGLIFDSTADDR, &lifr) < 0) {
    409     0    stevel 			warn("Couldn't get remote IPv6 address (%s): %m",
    410     0    stevel 			    lifr.lifr_name);
    411     0    stevel 			return (0);
    412     0    stevel 		}
    413     0    stevel 		eui64_copy(sin6->sin6_addr.s6_addr32[2],
    414     0    stevel 		    ipv6cp_wantoptions[unit].hisid);
    415     0    stevel 	}
    416     0    stevel 	return (1);
    417     0    stevel }
    418     0    stevel #endif /* INET6 */
    419     0    stevel 
    420     0    stevel /*
    421     0    stevel  * Read information on existing interface(s) and configure ourselves
    422     0    stevel  * to negotiate appropriately.
    423     0    stevel  */
    424     0    stevel static void
    425     0    stevel read_interface(int unit)
    426     0    stevel {
    427     0    stevel 	dbglog("reading existing interface data; %sip %sipv6",
    428     0    stevel 	    IPCP_ENABLED ? "" : "!",
    429     0    stevel #ifdef INET6
    430     0    stevel 	    IPV6CP_ENABLED ? "" :
    431     0    stevel #endif
    432     0    stevel 	    "!");
    433     0    stevel 	if (IPCP_ENABLED && !read_ip_interface(unit))
    434     0    stevel 		IPCP_ENABLED = 0;
    435     0    stevel #ifdef INET6
    436     0    stevel 	if (IPV6CP_ENABLED && !read_ipv6_interface(unit))
    437     0    stevel 		IPV6CP_ENABLED = 0;
    438     0    stevel #endif
    439     0    stevel }
    440     0    stevel 
    441     0    stevel /*
    442     0    stevel  * sys_init()
    443     0    stevel  *
    444     0    stevel  * System-dependent initialization.
    445     0    stevel  */
    446     0    stevel void
    447     0    stevel sys_init(bool open_as_user)
    448     0    stevel {
    449     0    stevel 	uint32_t x;
    450     0    stevel 	uint32_t typ;
    451     0    stevel 
    452     0    stevel 	if (pppfd != -1) {
    453     0    stevel 		return;
    454     0    stevel 	}
    455     0    stevel 
    456     0    stevel 	if (!direct_tty && devnam[0] != '\0') {
    457     0    stevel 		/*
    458     0    stevel 		 * Check for integrated driver-like devices (such as
    459     0    stevel 		 * POS).  These identify themselves as "PPP
    460     0    stevel 		 * multiplexor" drivers.
    461     0    stevel 		 */
    462     0    stevel 		if (open_as_user)
    463     0    stevel 			(void) seteuid(getuid());
    464     0    stevel 		pppfd = open(devnam, O_RDWR | O_NONBLOCK);
    465     0    stevel 		if (open_as_user)
    466     0    stevel 			(void) seteuid(0);
    467     0    stevel 		if (pppfd >= 0 &&
    468     0    stevel 		    strioctl(pppfd, PPPIO_GTYPE, &typ, 0, sizeof (typ)) >= 0 &&
    469     0    stevel 		    typ == PPPTYP_MUX) {
    470     0    stevel 			integrated_driver = 1;
    471     0    stevel 			drvnam = devnam;
    472     0    stevel 		} else if (demand) {
    473     0    stevel 			(void) close(pppfd);
    474     0    stevel 			pppfd = -1;
    475     0    stevel 		} else {
    476     0    stevel 			extra_dev_fd = pppfd;
    477     0    stevel 			pppfd = -1;
    478     0    stevel 		}
    479     0    stevel 	}
    480     0    stevel 
    481     0    stevel 	/*
    482     0    stevel 	 * Open Solaris PPP device driver.
    483     0    stevel 	 */
    484     0    stevel 	if (pppfd < 0)
    485     0    stevel 		pppfd = open(drvnam, O_RDWR | O_NONBLOCK);
    486     0    stevel 	if (pppfd < 0) {
    487     0    stevel 		fatal("Can't open %s: %m", drvnam);
    488     0    stevel 	}
    489     0    stevel 	if (kdebugflag & 1) {
    490     0    stevel 		x = PPPDBG_LOG + PPPDBG_DRIVER;
    491     0    stevel 		if (strioctl(pppfd, PPPIO_DEBUG, &x, sizeof (x), 0) < 0) {
    492     0    stevel 			warn("PPPIO_DEBUG ioctl for mux failed: %m");
    493     0    stevel 		}
    494     0    stevel 	}
    495     0    stevel 	/*
    496     0    stevel 	 * Assign a new PPA and get its unit number.
    497     0    stevel 	 */
    498     0    stevel 	x = req_unit;
    499     0    stevel 	if (strioctl(pppfd, PPPIO_NEWPPA, &x, sizeof (x), sizeof (x)) < 0) {
    500     0    stevel 		if (errno == ENXIO && plumbed)
    501     0    stevel 			fatal("No idle interfaces available for use");
    502     0    stevel 		fatal("PPPIO_NEWPPA ioctl failed: %m");
    503     0    stevel 	}
    504     0    stevel 	ifunit = x;
    505     0    stevel 	if (req_unit >= 0 && ifunit != req_unit) {
    506     0    stevel 		if (plumbed)
    507     0    stevel 			fatal("unable to get requested unit %d", req_unit);
    508     0    stevel 		else
    509     0    stevel 			warn("unable to get requested unit %d", req_unit);
    510     0    stevel 	}
    511     0    stevel 	/*
    512     0    stevel 	 * Enable packet time-stamping when idle option is specified. Note
    513     0    stevel 	 * that we need to only do this on the control stream. Subsequent
    514     0    stevel 	 * streams attached to this control stream (ppa) will inherit
    515     0    stevel 	 * the time-stamp bit.
    516     0    stevel 	 */
    517     0    stevel 	if (idle_time_limit > 0) {
    518     0    stevel 		if (strioctl(pppfd, PPPIO_USETIMESTAMP, NULL, 0, 0) < 0) {
    519     0    stevel 			warn("PPPIO_USETIMESTAMP ioctl failed: %m");
    520     0    stevel 		}
    521     0    stevel 	}
    522     0    stevel 	if (plumbed) {
    523     0    stevel 		sys_ifname();
    524     0    stevel 		read_interface(0);
    525     0    stevel 	}
    526     0    stevel }
    527     0    stevel 
    528     0    stevel int
    529     0    stevel sys_extra_fd(void)
    530     0    stevel {
    531     0    stevel 	int fd;
    532     0    stevel 
    533     0    stevel 	fd = extra_dev_fd;
    534     0    stevel 	extra_dev_fd = -1;
    535     0    stevel 	return (fd);
    536     0    stevel }
    537     0    stevel 
    538     0    stevel static int
    539     0    stevel open_udpfd(void)
    540     0    stevel {
    541     0    stevel 	int udpfd;
    542     0    stevel 
    543     0    stevel 	udpfd = open(UDP_DEV_NAME, O_RDWR | O_NONBLOCK, 0);
    544     0    stevel 	if (udpfd < 0) {
    545     0    stevel 		error("Couldn't open UDP device (%s): %m", UDP_DEV_NAME);
    546     0    stevel 	}
    547     0    stevel 	return (udpfd);
    548     0    stevel }
    549     0    stevel 
    550     0    stevel /*
    551     0    stevel  * plumb_ipif()
    552     0    stevel  *
    553     0    stevel  * Perform IP interface plumbing.
    554     0    stevel  */
    555     0    stevel /*ARGSUSED*/
    556     0    stevel static int
    557     0    stevel plumb_ipif(int unit)
    558     0    stevel {
    559     0    stevel 	int udpfd = -1, tmpfd;
    560     0    stevel 	uint32_t x;
    561     0    stevel 	struct ifreq ifr;
    562     0    stevel 
    563     0    stevel 	if (!IPCP_ENABLED || (ifunit == -1) || (pppfd == -1)) {
    564     0    stevel 		return (0);
    565     0    stevel 	}
    566     0    stevel 	if (plumbed)
    567     0    stevel 		return (1);
    568     0    stevel 	if (ipfd == -1 && open_ipfd() == -1)
    569     0    stevel 		return (0);
    570     0    stevel 	if (use_plink && (udpfd = open_udpfd()) == -1)
    571     0    stevel 		return (0);
    572     0    stevel 	tmpfd = open(drvnam, O_RDWR | O_NONBLOCK, 0);
    573     0    stevel 	if (tmpfd < 0) {
    574     0    stevel 		error("Couldn't open PPP device (%s): %m", drvnam);
    575     0    stevel 		if (udpfd != -1)
    576     0    stevel 			(void) close(udpfd);
    577     0    stevel 		return (0);
    578     0    stevel 	}
    579     0    stevel 	if (kdebugflag & 1) {
    580     0    stevel 		x = PPPDBG_LOG + PPPDBG_DRIVER;
    581     0    stevel 		if (strioctl(tmpfd, PPPIO_DEBUG, &x, sizeof (x), 0) < 0) {
    582     0    stevel 			warn("PPPIO_DEBUG ioctl for mux failed: %m");
    583     0    stevel 		}
    584     0    stevel 	}
    585     0    stevel 	if (myioctl(tmpfd, I_PUSH, IP_MOD_NAME) < 0) {
    586     0    stevel 		error("Couldn't push IP module (%s): %m", IP_MOD_NAME);
    587     0    stevel 		goto err_ret;
    588     0    stevel 	}
    589     0    stevel 	/*
    590     0    stevel 	 * Assign ppa according to the unit number returned by ppp device
    591     0    stevel 	 * after plumbing is completed above.  Without setting the ppa, ip
    592     0    stevel 	 * module will return EINVAL upon setting the interface UP
    593     0    stevel 	 * (SIOCSxIFFLAGS).  This is because ip module in 2.8 expects two
    594     0    stevel 	 * DLPI_INFO_REQ to be sent down to the driver (below ip) before
    595     0    stevel 	 * IFF_UP bit can be set. Plumbing the device causes one DLPI_INFO_REQ
    596     0    stevel 	 * to be sent down, and the second DLPI_INFO_REQ is sent upon receiving
    597     0    stevel 	 * IF_UNITSEL (old) or SIOCSLIFNAME (new) ioctls. Such setting of the
    598     0    stevel 	 * ppa is required because the ppp DLPI provider advertises itself as
    599     0    stevel 	 * a DLPI style 2 type, which requires a point of attachment to be
    600     0    stevel 	 * specified. The only way the user can specify a point of attachment
    601     0    stevel 	 * is via SIOCSLIFNAME or IF_UNITSEL.  Such changes in the behavior of
    602     0    stevel 	 * ip module was made to meet new or evolving standards requirements.
    603     0    stevel 	 */
    604     0    stevel 	if (myioctl(tmpfd, IF_UNITSEL, &ifunit) < 0) {
    605     0    stevel 		error("Couldn't set ppa for unit %d: %m", ifunit);
    606     0    stevel 		goto err_ret;
    607     0    stevel 	}
    608     0    stevel 	if (use_plink) {
    609     0    stevel 		ipmuxid = myioctl(udpfd, I_PLINK, (void *)tmpfd);
    610     0    stevel 		if (ipmuxid < 0) {
    611     0    stevel 			error("Can't I_PLINK PPP device to IP: %m");
    612     0    stevel 			goto err_ret;
    613     0    stevel 		}
    614     0    stevel 	} else {
    615     0    stevel 		ipmuxid = myioctl(ipfd, I_LINK, (void *)tmpfd);
    616     0    stevel 		if (ipmuxid < 0) {
    617     0    stevel 			error("Can't I_LINK PPP device to IP: %m");
    618     0    stevel 			goto err_ret;
    619     0    stevel 		}
    620     0    stevel 	}
    621     0    stevel 	BZERO(&ifr, sizeof (ifr));
    622     0    stevel 	(void) strlcpy(ifr.ifr_name, ifname, sizeof (ifr.ifr_name));
    623     0    stevel 	ifr.ifr_ip_muxid = ipmuxid;
    624     0    stevel 	ifr.ifr_arp_muxid = -1;
    625     0    stevel 	if (myioctl(ipfd, SIOCSIFMUXID, (caddr_t)&ifr) < 0) {
    626     0    stevel 		error("Can't set mux ID SIOCSIFMUXID on %s: %m", ifname);
    627     0    stevel 		goto err_ret;
    628     0    stevel 	}
    629     0    stevel 	if (udpfd != -1)
    630     0    stevel 		(void) close(udpfd);
    631     0    stevel 	(void) close(tmpfd);
    632     0    stevel 	return (1);
    633     0    stevel err_ret:
    634     0    stevel 	if (udpfd != -1)
    635     0    stevel 		(void) close(udpfd);
    636     0    stevel 	(void) close(tmpfd);
    637     0    stevel 	return (0);
    638     0    stevel }
    639     0    stevel 
    640     0    stevel /*
    641     0    stevel  * unplumb_ipif()
    642     0    stevel  *
    643     0    stevel  * Perform IP interface unplumbing.  Possibly called from die(), so there
    644     0    stevel  * shouldn't be any call to die() or fatal() here.
    645     0    stevel  */
    646     0    stevel static int
    647     0    stevel unplumb_ipif(int unit)
    648     0    stevel {
    649     0    stevel 	int udpfd = -1, fd = -1;
    650     0    stevel 	int id;
    651     0    stevel 	struct lifreq lifr;
    652     0    stevel 
    653     0    stevel 	if (!IPCP_ENABLED || (ifunit == -1)) {
    654     0    stevel 		return (0);
    655     0    stevel 	}
    656     0    stevel 	if (!plumbed && (ipmuxid == -1 || (ipfd == -1 && !use_plink)))
    657     0    stevel 		return (1);
    658     0    stevel 	id = ipmuxid;
    659     0    stevel 	if (!plumbed && use_plink) {
    660     0    stevel 		if ((udpfd = open_udpfd()) == -1)
    661     0    stevel 			return (0);
    662     0    stevel 		/*
    663     0    stevel 		 * Note: must re-get mux ID, since any intervening
    664     0    stevel 		 * ifconfigs will change this.
    665     0    stevel 		 */
    666     0    stevel 		BZERO(&lifr, sizeof (lifr));
    667     0    stevel 		(void) strlcpy(lifr.lifr_name, ifname,
    668     0    stevel 		    sizeof (lifr.lifr_name));
    669     0    stevel 		if (myioctl(ipfd, SIOCGLIFMUXID, (caddr_t)&lifr) < 0) {
    670     0    stevel 			warn("Can't get mux fd: SIOCGLIFMUXID: %m");
    671     0    stevel 		} else {
    672     0    stevel 			id = lifr.lifr_ip_muxid;
    673     0    stevel 			fd = myioctl(udpfd, _I_MUXID2FD, (void *)id);
    674     0    stevel 			if (fd < 0) {
    675     0    stevel 				warn("Can't get mux fd: _I_MUXID2FD: %m");
    676     0    stevel 			}
    677     0    stevel 		}
    678     0    stevel 	}
    679     0    stevel 	/*
    680     0    stevel 	 * Mark down and unlink the ip interface.
    681     0    stevel 	 */
    682     0    stevel 	(void) sifdown(unit);
    683     0    stevel 	if (default_route_gateway != 0) {
    684     0    stevel 		(void) cifdefaultroute(0, default_route_gateway,
    685     0    stevel 		    default_route_gateway);
    686     0    stevel 	}
    687     0    stevel 	if (proxy_arp_addr != 0) {
    688     0    stevel 		(void) cifproxyarp(0, proxy_arp_addr);
    689     0    stevel 	}
    690     0    stevel 	ipmuxid = -1;
    691     0    stevel 	if (plumbed)
    692     0    stevel 		return (1);
    693     0    stevel 	if (use_plink) {
    694     0    stevel 		if (myioctl(udpfd, I_PUNLINK, (void *)id) < 0) {
    695     0    stevel 			error("Can't I_PUNLINK PPP from IP: %m");
    696     0    stevel 			if (fd != -1)
    697     0    stevel 				(void) close(fd);
    698     0    stevel 			(void) close(udpfd);
    699     0    stevel 			return (0);
    700     0    stevel 		}
    701     0    stevel 		if (fd != -1)
    702     0    stevel 			(void) close(fd);
    703     0    stevel 		(void) close(udpfd);
    704     0    stevel 	} else {
    705     0    stevel 		if (myioctl(ipfd, I_UNLINK, (void *)id) < 0) {
    706     0    stevel 			error("Can't I_UNLINK PPP from IP: %m");
    707     0    stevel 			return (0);
    708     0    stevel 		}
    709     0    stevel 	}
    710     0    stevel 	return (1);
    711     0    stevel }
    712     0    stevel 
    713     0    stevel /*
    714     0    stevel  * sys_cleanup()
    715     0    stevel  *
    716     0    stevel  * Restore any system state we modified before exiting: mark the
    717     0    stevel  * interface down, delete default route and/or proxy arp entry. This
    718     0    stevel  * should not call die() because it's called from die().
    719     0    stevel  */
    720     0    stevel void
    721     0    stevel sys_cleanup()
    722     0    stevel {
    723     0    stevel 	(void) unplumb_ipif(0);
    724     0    stevel #ifdef INET6
    725     0    stevel 	(void) unplumb_ip6if(0);
    726     0    stevel #endif /* INET6 */
    727     0    stevel }
    728     0    stevel 
    729     0    stevel /*
    730     0    stevel  * get_first_hwaddr()
    731     0    stevel  *
    732     0    stevel  * Stores the first hardware interface address found in the system
    733     0    stevel  * into addr and return 1 upon success, or 0 if none is found.  This
    734     0    stevel  * is also called from the multilink code.
    735     0    stevel  */
    736     0    stevel int
    737     0    stevel get_first_hwaddr(addr, msize)
    738     0    stevel 	uchar_t *addr;
    739     0    stevel 	int msize;
    740     0    stevel {
    741     0    stevel 	struct ifconf ifc;
    742     0    stevel 	register struct ifreq *pifreq;
    743     0    stevel 	struct ifreq ifr;
    744     0    stevel 	int fd, num_ifs, i;
    745     0    stevel 	uint_t fl, req_size;
    746     0    stevel 	char *req;
    747     0    stevel 	boolean_t found;
    748     0    stevel 
    749     0    stevel 	if (addr == NULL) {
    750     0    stevel 		return (0);
    751     0    stevel 	}
    752     0    stevel 	fd = socket(AF_INET, SOCK_DGRAM, 0);
    753     0    stevel 	if (fd < 0) {
    754     0    stevel 		error("get_first_hwaddr: error opening IP socket: %m");
    755     0    stevel 		return (0);
    756     0    stevel 	}
    757     0    stevel 	/*
    758     0    stevel 	 * Find out how many interfaces are running
    759     0    stevel 	 */
    760     0    stevel 	if (myioctl(fd, SIOCGIFNUM, (caddr_t)&num_ifs) < 0) {
    761     0    stevel 		num_ifs = MAXIFS;
    762     0    stevel 	}
    763     0    stevel 	req_size = num_ifs * sizeof (struct ifreq);
    764     0    stevel 	req = malloc(req_size);
    765     0    stevel 	if (req == NULL) {
    766     0    stevel 		novm("interface request structure.");
    767     0    stevel 	}
    768     0    stevel 	/*
    769     0    stevel 	 * Get interface configuration info for all interfaces
    770     0    stevel 	 */
    771     0    stevel 	ifc.ifc_len = req_size;
    772     0    stevel 	ifc.ifc_buf = req;
    773     0    stevel 	if (myioctl(fd, SIOCGIFCONF, &ifc) < 0) {
    774     0    stevel 		error("SIOCGIFCONF: %m");
    775     0    stevel 		(void) close(fd);
    776     0    stevel 		free(req);
    777     0    stevel 		return (0);
    778     0    stevel 	}
    779     0    stevel 	/*
    780     0    stevel 	 * And traverse each interface to look specifically for the first
    781     0    stevel 	 * occurence of an Ethernet interface which has been marked up
    782     0    stevel 	 */
    783     0    stevel 	pifreq = ifc.ifc_req;
    784     0    stevel 	found = 0;
    785     0    stevel 	for (i = ifc.ifc_len / sizeof (struct ifreq); i > 0; i--, pifreq++) {
    786     0    stevel 
    787     0    stevel 		if (strchr(pifreq->ifr_name, ':') != NULL) {
    788     0    stevel 			continue;
    789     0    stevel 		}
    790     0    stevel 		BZERO(&ifr, sizeof (ifr));
    791     0    stevel 		(void) strncpy(ifr.ifr_name, pifreq->ifr_name,
    792     0    stevel 		    sizeof (ifr.ifr_name));
    793     0    stevel 		if (myioctl(fd, SIOCGIFFLAGS, &ifr) < 0) {
    794     0    stevel 			continue;
    795     0    stevel 		}
    796     0    stevel 		fl = ifr.ifr_flags;
    797     0    stevel 		if ((fl & (IFF_UP|IFF_BROADCAST|IFF_POINTOPOINT|IFF_LOOPBACK))
    798     0    stevel 		    != (IFF_UP | IFF_BROADCAST)) {
    799     0    stevel 			continue;
    800     0    stevel 		}
    801     0    stevel 		if (get_if_hwaddr(addr, msize, ifr.ifr_name) <= 0) {
    802     0    stevel 			continue;
    803     0    stevel 		}
    804     0    stevel 		found = 1;
    805     0    stevel 		break;
    806     0    stevel 	}
    807     0    stevel 	free(req);
    808     0    stevel 	(void) close(fd);
    809     0    stevel 
    810     0    stevel 	return (found);
    811     0    stevel }
    812     0    stevel 
    813     0    stevel /*
    814     0    stevel  * get_if_hwaddr()
    815     0    stevel  *
    816     0    stevel  * Get the hardware address for the specified network interface device.
    817     0    stevel  * Return the length of the MAC address (in bytes) or -1 if error.
    818     0    stevel  */
    819     0    stevel int
    820  6631  ss150715 get_if_hwaddr(uchar_t *addrp, int msize, char *linkname)
    821     0    stevel {
    822  6631  ss150715 	dlpi_handle_t dh;
    823  6631  ss150715 	uchar_t physaddr[DLPI_PHYSADDR_MAX];
    824  6631  ss150715 	size_t physaddrlen = sizeof (physaddr);
    825  6631  ss150715 	int retv;
    826     0    stevel 
    827  6631  ss150715 	if ((addrp == NULL) || (linkname == NULL))
    828     0    stevel 		return (-1);
    829  6631  ss150715 
    830     0    stevel 	/*
    831  6631  ss150715 	 * Open the link and ask for hardware address.
    832     0    stevel 	 */
    833  6631  ss150715 	if ((retv = dlpi_open(linkname, &dh, 0)) != DLPI_SUCCESS) {
    834  6631  ss150715 		error("Could not open %s: %s", linkname, dlpi_strerror(retv));
    835     0    stevel 		return (-1);
    836     0    stevel 	}
    837     0    stevel 
    838  6631  ss150715 	retv = dlpi_get_physaddr(dh, DL_CURR_PHYS_ADDR,
    839  6631  ss150715 	    physaddr, &physaddrlen);
    840  6631  ss150715 	dlpi_close(dh);
    841  6631  ss150715 	if (retv != DLPI_SUCCESS) {
    842  6631  ss150715 		error("Could not get physical address on %s: %s", linkname,
    843  6631  ss150715 		    dlpi_strerror(retv));
    844     0    stevel 		return (-1);
    845     0    stevel 	}
    846     0    stevel 
    847     0    stevel 	/*
    848     0    stevel 	 * Check if we have enough space to copy the address to.
    849     0    stevel 	 */
    850  6631  ss150715 	if (physaddrlen > msize)
    851     0    stevel 		return (-1);
    852  6631  ss150715 	(void) memcpy(addrp, physaddr, physaddrlen);
    853  6631  ss150715 	return (physaddrlen);
    854     0    stevel }
    855     0    stevel 
    856     0    stevel /*
    857     0    stevel  * giflags()
    858     0    stevel  */
    859     0    stevel static int
    860     0    stevel giflags(u_int32_t flag, bool *retval)
    861     0    stevel {
    862     0    stevel 	struct ifreq ifr;
    863     0    stevel 	int fd;
    864     0    stevel 
    865     0    stevel 	*retval = 0;
    866     0    stevel 	fd = socket(AF_INET, SOCK_DGRAM, 0);
    867     0    stevel 	if (fd < 0) {
    868     0    stevel 		error("giflags: error opening IP socket: %m");
    869     0    stevel 		return (errno);
    870     0    stevel 	}
    871     0    stevel 
    872     0    stevel 	BZERO(&ifr, sizeof (ifr));
    873     0    stevel 	(void) strncpy(ifr.ifr_name, ifname, sizeof (ifr.ifr_name));
    874     0    stevel 	if (ioctl(fd, SIOCGIFFLAGS, &ifr) < 0) {
    875     0    stevel 		(void) close(fd);
    876     0    stevel 		return (errno);
    877     0    stevel 	}
    878     0    stevel 
    879     0    stevel 	*retval = ((ifr.ifr_flags & flag) != 0);
    880     0    stevel 	(void) close(fd);
    881     0    stevel 	return (errno);
    882     0    stevel }
    883     0    stevel 
    884     0    stevel /*
    885     0    stevel  * sys_close()
    886     0    stevel  *
    887     0    stevel  * Clean up in a child process before exec-ing.
    888     0    stevel  */
    889     0    stevel void
    890     0    stevel sys_close()
    891     0    stevel {
    892     0    stevel 	if (ipfd != -1) {
    893     0    stevel 		(void) close(ipfd);
    894     0    stevel 		ipfd = -1;
    895     0    stevel 	}
    896     0    stevel #ifdef INET6
    897     0    stevel 	if (ip6fd != -1) {
    898     0    stevel 		(void) close(ip6fd);
    899     0    stevel 		ip6fd = -1;
    900     0    stevel 	}
    901     0    stevel #endif /* INET6 */
    902     0    stevel 	if (pppfd != -1) {
    903     0    stevel 		(void) close(pppfd);
    904     0    stevel 		pppfd = -1;
    905     0    stevel 	}
    906     0    stevel }
    907     0    stevel 
    908     0    stevel /*
    909     0    stevel  * any_compressions()
    910     0    stevel  *
    911     0    stevel  * Check if compression is enabled or not.  In the STREAMS implementation of
    912     0    stevel  * kernel-portion pppd, the comp STREAMS module performs the ACFC, PFC, as
    913     0    stevel  * well CCP and VJ compressions. However, if the user has explicitly declare
    914     0    stevel  * to not enable them from the command line, there is no point of having the
    915     0    stevel  * comp module be pushed on the stream.
    916     0    stevel  */
    917     0    stevel static int
    918     0    stevel any_compressions(void)
    919     0    stevel {
    920     0    stevel 	if ((!lcp_wantoptions[0].neg_accompression) &&
    921     0    stevel 	    (!lcp_wantoptions[0].neg_pcompression) &&
    922     0    stevel 	    (!ccp_protent.enabled_flag) &&
    923     0    stevel 	    (!ipcp_wantoptions[0].neg_vj)) {
    924     0    stevel 		return (0);
    925     0    stevel 	}
    926     0    stevel 	return (1);
    927     0    stevel }
    928     0    stevel 
    929     0    stevel /*
    930     0    stevel  * modpush()
    931     0    stevel  *
    932     0    stevel  * Push a module on the stream.
    933     0    stevel  */
    934     0    stevel static int
    935     0    stevel modpush(int fd, const char *modname, const char *text)
    936     0    stevel {
    937     0    stevel 	if (myioctl(fd, I_PUSH, (void *)modname) < 0) {
    938     0    stevel 		error("Couldn't push %s module: %m", text);
    939     0    stevel 		return (-1);
    940     0    stevel 	}
    941     0    stevel 	if (++tty_npushed == 1 && !already_ppp) {
    942     0    stevel 		if (strioctl(fd, PPPIO_LASTMOD, NULL, 0, 0) < 0) {
    943     0    stevel 			warn("unable to set LASTMOD on %s: %m", text);
    944     0    stevel 		}
    945     0    stevel 	}
    946     0    stevel 	return (0);
    947     0    stevel }
    948     0    stevel 
    949     0    stevel /*
    950     0    stevel  * establish_ppp()
    951     0    stevel  *
    952     0    stevel  * Turn the serial port into a ppp interface.
    953     0    stevel  */
    954     0    stevel int
    955     0    stevel establish_ppp(fd)
    956     0    stevel 	int fd;
    957     0    stevel {
    958     0    stevel 	int i;
    959     0    stevel 	uint32_t x;
    960     0    stevel 
    961     0    stevel 	if (default_device && !notty) {
    962     0    stevel 		tty_sid = getsid((pid_t)0);
    963     0    stevel 	}
    964     0    stevel 
    965     0    stevel 	if (integrated_driver)
    966     0    stevel 		return (pppfd);
    967     0    stevel 
    968     0    stevel 	/*
    969     0    stevel 	 * Pop any existing modules off the tty stream
    970     0    stevel 	 */
    971     0    stevel 	for (i = 0; ; ++i) {
    972     0    stevel 		if ((myioctl(fd, I_LOOK, tty_modules[i]) < 0) ||
    973     0    stevel 		    (strcmp(tty_modules[i], "ptem") == 0) ||
    974     0    stevel 		    (myioctl(fd, I_POP, (void *)0) < 0)) {
    975     0    stevel 			break;
    976     0    stevel 		}
    977     0    stevel 	}
    978     0    stevel 	tty_nmodules = i;
    979     0    stevel 	/*
    980     0    stevel 	 * Push the async hdlc module and the compressor module
    981     0    stevel 	 */
    982     0    stevel 	tty_npushed = 0;
    983     0    stevel 	if (!sync_serial && !already_ppp &&
    984     0    stevel 	    modpush(fd, AHDLC_MOD_NAME, "PPP async HDLC") < 0) {
    985     0    stevel 		return (-1);
    986     0    stevel 	}
    987     0    stevel 	/*
    988     0    stevel 	 * There's no need to push comp module if we don't intend
    989     0    stevel 	 * to compress anything
    990     0    stevel 	 */
    991     0    stevel 	if (any_compressions()) {
    992     0    stevel 		(void) modpush(fd, COMP_MOD_NAME, "PPP compression");
    993     0    stevel 	}
    994     0    stevel 
    995     0    stevel 	/*
    996     0    stevel 	 * Link the serial port under the PPP multiplexor
    997     0    stevel 	 */
    998     0    stevel 	if ((fdmuxid = myioctl(pppfd, I_LINK, (void *)fd)) < 0) {
    999     0    stevel 		error("Can't link tty to PPP mux: %m");
   1000     0    stevel 		return (-1);
   1001     0    stevel 	}
   1002     0    stevel 	if (tty_npushed == 0 && !already_ppp) {
   1003     0    stevel 		if (strioctl(pppfd, PPPIO_LASTMOD, NULL, 0, 0) < 0) {
   1004     0    stevel 			warn("unable to set LASTMOD on PPP mux: %m");
   1005     0    stevel 		}
   1006     0    stevel 	}
   1007     0    stevel 	/*
   1008     0    stevel 	 * Debug configuration must occur *after* I_LINK.
   1009     0    stevel 	 */
   1010     0    stevel 	if (kdebugflag & 4) {
   1011     0    stevel 		x = PPPDBG_LOG + PPPDBG_AHDLC;
   1012     0    stevel 		if (strioctl(pppfd, PPPIO_DEBUG, &x, sizeof (x), 0) < 0) {
   1013     0    stevel 			warn("PPPIO_DEBUG ioctl for ahdlc module failed: %m");
   1014     0    stevel 		}
   1015     0    stevel 	}
   1016     0    stevel 	if (any_compressions() && (kdebugflag & 2)) {
   1017     0    stevel 		x = PPPDBG_LOG + PPPDBG_COMP;
   1018     0    stevel 		if (strioctl(pppfd, PPPIO_DEBUG, &x, sizeof (x), 0) < 0) {
   1019     0    stevel 			warn("PPPIO_DEBUG ioctl for comp module failed: %m");
   1020     0    stevel 		}
   1021     0    stevel 	}
   1022     0    stevel 	return (pppfd);
   1023     0    stevel }
   1024     0    stevel 
   1025     0    stevel /*
   1026     0    stevel  * restore_loop()
   1027     0    stevel  *
   1028     0    stevel  * Reattach the ppp unit to the loopback. This doesn't need to do anything
   1029     0    stevel  * because disestablish_ppp does it
   1030     0    stevel  */
   1031     0    stevel void
   1032     0    stevel restore_loop()
   1033     0    stevel {
   1034     0    stevel }
   1035     0    stevel 
   1036     0    stevel /*
   1037     0    stevel  * disestablish_ppp()
   1038     0    stevel  *
   1039     0    stevel  * Restore the serial port to normal operation.  It attempts to reconstruct
   1040     0    stevel  * the stream with the previously popped modules.  This shouldn't call die()
   1041     0    stevel  * because it's called from die().  Stream reconstruction is needed in case
   1042     0    stevel  * pppd is used for dial-in on /dev/tty and there's an option error.
   1043     0    stevel  */
   1044     0    stevel void
   1045     0    stevel disestablish_ppp(fd)
   1046     0    stevel 	int fd;
   1047     0    stevel {
   1048     0    stevel 	int i;
   1049     0    stevel 
   1050     0    stevel 	if (fdmuxid == -1 || integrated_driver) {
   1051     0    stevel 		return;
   1052     0    stevel 	}
   1053     0    stevel 	if (myioctl(pppfd, I_UNLINK, (void *)fdmuxid) < 0) {
   1054     0    stevel 		if (!hungup) {
   1055     0    stevel 			error("Can't unlink tty from PPP mux: %m");
   1056     0    stevel 		}
   1057     0    stevel 	}
   1058     0    stevel 	fdmuxid = -1;
   1059     0    stevel 	if (!hungup) {
   1060     0    stevel 		while (tty_npushed > 0 && myioctl(fd, I_POP, (void *)0) >= 0) {
   1061     0    stevel 			--tty_npushed;
   1062     0    stevel 		}
   1063     0    stevel 		for (i = tty_nmodules - 1; i >= 0; --i) {
   1064     0    stevel 			if (myioctl(fd, I_PUSH, tty_modules[i]) < 0) {
   1065     0    stevel 				error("Couldn't restore tty module %s: %m",
   1066     0    stevel 				    tty_modules[i]);
   1067     0    stevel 			}
   1068     0    stevel 		}
   1069     0    stevel 	}
   1070     0    stevel 	if (hungup && default_device && tty_sid > 0) {
   1071     0    stevel 		/*
   1072     0    stevel 		 * If we have received a hangup, we need to send a
   1073     0    stevel 		 * SIGHUP to the terminal's controlling process.
   1074     0    stevel 		 * The reason is that the original stream head for
   1075     0    stevel 		 * the terminal hasn't seen the M_HANGUP message
   1076     0    stevel 		 * (it went up through the ppp driver to the stream
   1077     0    stevel 		 * head for our fd to /dev/ppp).
   1078     0    stevel 		 */
   1079     0    stevel 		(void) kill(tty_sid, SIGHUP);
   1080     0    stevel 	}
   1081     0    stevel }
   1082     0    stevel 
   1083     0    stevel /*
   1084     0    stevel  * clean_check()
   1085     0    stevel  *
   1086     0    stevel  * Check whether the link seems not to be 8-bit clean
   1087     0    stevel  */
   1088     0    stevel void
   1089     0    stevel clean_check()
   1090     0    stevel {
   1091     0    stevel 	uint32_t x;
   1092     0    stevel 	char *s = NULL;
   1093     0    stevel 
   1094     0    stevel 	/*
   1095     0    stevel 	 * Skip this is synchronous link is used, since spppasyn won't
   1096     0    stevel 	 * be anywhere in the stream below to handle the ioctl.
   1097     0    stevel 	 */
   1098     0    stevel 	if (sync_serial) {
   1099     0    stevel 		return;
   1100     0    stevel 	}
   1101     0    stevel 
   1102     0    stevel 	if (strioctl(pppfd, PPPIO_GCLEAN, &x, 0, sizeof (x)) < 0) {
   1103     0    stevel 		warn("unable to obtain serial link status: %m");
   1104     0    stevel 		return;
   1105     0    stevel 	}
   1106     0    stevel 	switch (~x) {
   1107     0    stevel 	case RCV_B7_0:
   1108     0    stevel 		s = "bit 7 set to 1";
   1109     0    stevel 		break;
   1110     0    stevel 	case RCV_B7_1:
   1111     0    stevel 		s = "bit 7 set to 0";
   1112     0    stevel 		break;
   1113     0    stevel 	case RCV_EVNP:
   1114     0    stevel 		s = "odd parity";
   1115     0    stevel 		break;
   1116     0    stevel 	case RCV_ODDP:
   1117     0    stevel 		s = "even parity";
   1118     0    stevel 		break;
   1119     0    stevel 	}
   1120     0    stevel 	if (s != NULL) {
   1121     0    stevel 		warn("Serial link is not 8-bit clean:");
   1122     0    stevel 		warn("All received characters had %s", s);
   1123     0    stevel 	}
   1124     0    stevel }
   1125     0    stevel 
   1126     0    stevel /*
   1127     0    stevel  * List of valid speeds.
   1128     0    stevel  */
   1129     0    stevel struct speed {
   1130     0    stevel 	int speed_int;
   1131     0    stevel 	int speed_val;
   1132     0    stevel } speeds [] = {
   1133     0    stevel #ifdef B50
   1134     0    stevel 	{ 50, B50 },
   1135     0    stevel #endif
   1136     0    stevel #ifdef B75
   1137     0    stevel 	{ 75, B75 },
   1138     0    stevel #endif
   1139     0    stevel #ifdef B110
   1140     0    stevel 	{ 110, B110 },
   1141     0    stevel #endif
   1142     0    stevel #ifdef B134
   1143     0    stevel 	{ 134, B134 },
   1144     0    stevel #endif
   1145     0    stevel #ifdef B150
   1146     0    stevel 	{ 150, B150 },
   1147     0    stevel #endif
   1148     0    stevel #ifdef B200
   1149     0    stevel 	{ 200, B200 },
   1150     0    stevel #endif
   1151     0    stevel #ifdef B300
   1152     0    stevel 	{ 300, B300 },
   1153     0    stevel #endif
   1154     0    stevel #ifdef B600
   1155     0    stevel 	{ 600, B600 },
   1156     0    stevel #endif
   1157     0    stevel #ifdef B1200
   1158     0    stevel 	{ 1200, B1200 },
   1159     0    stevel #endif
   1160     0    stevel #ifdef B1800
   1161     0    stevel 	{ 1800, B1800 },
   1162     0    stevel #endif
   1163     0    stevel #ifdef B2000
   1164     0    stevel 	{ 2000, B2000 },
   1165     0    stevel #endif
   1166     0    stevel #ifdef B2400
   1167     0    stevel 	{ 2400, B2400 },
   1168     0    stevel #endif
   1169     0    stevel #ifdef B3600
   1170     0    stevel 	{ 3600, B3600 },
   1171     0    stevel #endif
   1172     0    stevel #ifdef B4800
   1173     0    stevel 	{ 4800, B4800 },
   1174     0    stevel #endif
   1175     0    stevel #ifdef B7200
   1176     0    stevel 	{ 7200, B7200 },
   1177     0    stevel #endif
   1178     0    stevel #ifdef B9600
   1179     0    stevel 	{ 9600, B9600 },
   1180     0    stevel #endif
   1181     0    stevel #ifdef B19200
   1182     0    stevel 	{ 19200, B19200 },
   1183     0    stevel #endif
   1184     0    stevel #ifdef B38400
   1185     0    stevel 	{ 38400, B38400 },
   1186     0    stevel #endif
   1187     0    stevel #ifdef EXTA
   1188     0    stevel 	{ 19200, EXTA },
   1189     0    stevel #endif
   1190     0    stevel #ifdef EXTB
   1191     0    stevel 	{ 38400, EXTB },
   1192     0    stevel #endif
   1193     0    stevel #ifdef B57600
   1194     0    stevel 	{ 57600, B57600 },
   1195     0    stevel #endif
   1196     0    stevel #ifdef B76800
   1197     0    stevel 	{ 76800, B76800 },
   1198     0    stevel #endif
   1199     0    stevel #ifdef B115200
   1200     0    stevel 	{ 115200, B115200 },
   1201     0    stevel #endif
   1202     0    stevel #ifdef B153600
   1203     0    stevel 	{ 153600, B153600 },
   1204     0    stevel #endif
   1205     0    stevel #ifdef B230400
   1206     0    stevel 	{ 230400, B230400 },
   1207     0    stevel #endif
   1208     0    stevel #ifdef B307200
   1209     0    stevel 	{ 307200, B307200 },
   1210     0    stevel #endif
   1211     0    stevel #ifdef B460800
   1212     0    stevel 	{ 460800, B460800 },
   1213  9354       Tim #endif
   1214  9354       Tim #ifdef B921600
   1215  9354       Tim 	{ 921600, B921600 },
   1216     0    stevel #endif
   1217     0    stevel 	{ 0, 0 }
   1218     0    stevel };
   1219     0    stevel 
   1220     0    stevel /*
   1221     0    stevel  * translate_speed()
   1222     0    stevel  *
   1223     0    stevel  * Translate from bits/second to a speed_t
   1224     0    stevel  */
   1225     0    stevel static int
   1226     0    stevel translate_speed(int bps)
   1227     0    stevel {
   1228     0    stevel 	struct speed *speedp;
   1229     0    stevel 
   1230     0    stevel 	if (bps == 0) {
   1231     0    stevel 		return (0);
   1232     0    stevel 	}
   1233     0    stevel 	for (speedp = speeds; speedp->speed_int; speedp++) {
   1234     0    stevel 		if (bps == speedp->speed_int) {
   1235     0    stevel 			return (speedp->speed_val);
   1236     0    stevel 		}
   1237     0    stevel 	}
   1238     0    stevel 	set_source(&speed_info);
   1239     0    stevel 	option_error("speed %d not supported", bps);
   1240     0    stevel 	return (0);
   1241     0    stevel }
   1242     0    stevel 
   1243     0    stevel /*
   1244     0    stevel  * baud_rate_of()
   1245     0    stevel  *
   1246     0    stevel  * Translate from a speed_t to bits/second
   1247     0    stevel  */
   1248     0    stevel static int
   1249     0    stevel baud_rate_of(int speed)
   1250     0    stevel {
   1251     0    stevel 	struct speed *speedp;
   1252     0    stevel 
   1253     0    stevel 	if (speed == 0) {
   1254     0    stevel 		return (0);
   1255     0    stevel 	}
   1256     0    stevel 	for (speedp = speeds; speedp->speed_int; speedp++) {
   1257     0    stevel 		if (speed == speedp->speed_val) {
   1258     0    stevel 			return (speedp->speed_int);
   1259     0    stevel 		}
   1260     0    stevel 	}
   1261     0    stevel 	return (0);
   1262     0    stevel }
   1263     0    stevel 
   1264     0    stevel /*
   1265     0    stevel  * set_up_tty()
   1266     0    stevel  *
   1267     0    stevel  * Set up the serial port on `fd' for 8 bits, no parity, at the requested
   1268     0    stevel  * speed, etc.  If `local' is true, set CLOCAL regardless of whether the
   1269     0    stevel  * modem option was specified.
   1270     0    stevel  */
   1271     0    stevel void
   1272     0    stevel set_up_tty(fd, local)
   1273     0    stevel 	int fd, local;
   1274     0    stevel {
   1275     0    stevel 	int speed;
   1276     0    stevel 	struct termios tios;
   1277     0    stevel 	struct scc_mode sm;
   1278     0    stevel 
   1279     0    stevel 	if (already_ppp)
   1280     0    stevel 		return;
   1281     0    stevel 
   1282     0    stevel 	if (sync_serial) {
   1283     0    stevel 		restore_term = 0;
   1284     0    stevel 		speed = B0;
   1285     0    stevel 		baud_rate = 0;
   1286     0    stevel 
   1287     0    stevel 		if (strioctl(fd, S_IOCGETMODE, &sm, sizeof (sm),
   1288     0    stevel 		    sizeof (sm)) < 0) {
   1289     0    stevel 			return;
   1290     0    stevel 		}
   1291     0    stevel 
   1292     0    stevel 		baud_rate = sm.sm_baudrate;
   1293     0    stevel 		dbglog("synchronous speed appears to be %d bps", baud_rate);
   1294     0    stevel 	} else {
   1295     0    stevel 		if (tcgetattr(fd, &tios) < 0) {
   1296     0    stevel 			fatal("tcgetattr: %m");
   1297     0    stevel 		}
   1298     0    stevel 		if (!restore_term) {
   1299     0    stevel 			inittermios = tios;
   1300     0    stevel 			if (myioctl(fd, TIOCGWINSZ, &wsinfo) < 0) {
   1301     0    stevel 				if (errno == EINVAL) {
   1302     0    stevel 					/*
   1303     0    stevel 					 * ptem returns EINVAL if all zeroes.
   1304     0    stevel 					 * Strange and unfixable code.
   1305     0    stevel 					 */
   1306     0    stevel 					bzero(&wsinfo, sizeof (wsinfo));
   1307     0    stevel 				} else {
   1308     0    stevel 					warn("unable to get TTY window "
   1309     0    stevel 					    "size: %m");
   1310     0    stevel 				}
   1311     0    stevel 			}
   1312     0    stevel 		}
   1313     0    stevel 		tios.c_cflag &= ~(CSIZE | CSTOPB | PARENB | CLOCAL);
   1314     0    stevel 		if (crtscts > 0) {
   1315     0    stevel 			tios.c_cflag |= CRTSCTS | CRTSXOFF;
   1316     0    stevel 		} else if (crtscts < 0) {
   1317     0    stevel 			tios.c_cflag &= ~CRTSCTS & ~CRTSXOFF;
   1318     0    stevel 		}
   1319     0    stevel 		tios.c_cflag |= CS8 | CREAD | HUPCL;
   1320     0    stevel 		if (local || !modem) {
   1321     0    stevel 			tios.c_cflag |= CLOCAL;
   1322     0    stevel 		}
   1323     0    stevel 		tios.c_iflag = IGNBRK | IGNPAR;
   1324     0    stevel 		tios.c_oflag = 0;
   1325     0    stevel 		tios.c_lflag = 0;
   1326     0    stevel 		tios.c_cc[VMIN] = 1;
   1327     0    stevel 		tios.c_cc[VTIME] = 0;
   1328     0    stevel 
   1329     0    stevel 		if (crtscts == -2) {
   1330     0    stevel 			tios.c_iflag |= IXON | IXOFF;
   1331     0    stevel 			tios.c_cc[VSTOP] = 0x13;	/* DC3 = XOFF = ^S */
   1332     0    stevel 			tios.c_cc[VSTART] = 0x11;	/* DC1 = XON  = ^Q */
   1333     0    stevel 		}
   1334     0    stevel 		speed = translate_speed(inspeed);
   1335     0    stevel 		if (speed) {
   1336     0    stevel 			(void) cfsetospeed(&tios, speed);
   1337     0    stevel 			(void) cfsetispeed(&tios, speed);
   1338     0    stevel 		} else {
   1339     0    stevel 			speed = cfgetospeed(&tios);
   1340     0    stevel 			/*
   1341     0    stevel 			 * We can't proceed if the serial port speed is 0,
   1342     0    stevel 			 * since that implies that the serial port is disabled.
   1343     0    stevel 			 */
   1344     0    stevel 			if (speed == B0) {
   1345     0    stevel 				fatal("Baud rate for %s is 0; need explicit "
   1346     0    stevel 				    "baud rate", devnam);
   1347     0    stevel 			}
   1348     0    stevel 		}
   1349     0    stevel 		if (tcsetattr(fd, TCSAFLUSH, &tios) < 0) {
   1350     0    stevel 			fatal("tcsetattr: %m");
   1351     0    stevel 		}
   1352     0    stevel 		baud_rate = baud_rate_of(speed);
   1353     0    stevel 		dbglog("%s speed set to %d bps",
   1354     0    stevel 		    fd == pty_slave ? "pty" : "serial", baud_rate);
   1355     0    stevel 		restore_term = 1;
   1356     0    stevel 	}
   1357     0    stevel }
   1358     0    stevel 
   1359     0    stevel /*
   1360     0    stevel  * restore_tty()
   1361     0    stevel  *
   1362     0    stevel  * Restore the terminal to the saved settings.
   1363     0    stevel  */
   1364     0    stevel void
   1365     0    stevel restore_tty(fd)
   1366     0    stevel 	int fd;
   1367     0    stevel {
   1368     0    stevel 	if (restore_term == 0) {
   1369     0    stevel 		return;
   1370     0    stevel 	}
   1371     0    stevel 	if (!default_device) {
   1372     0    stevel 		/*
   1373     0    stevel 		 * Turn off echoing, because otherwise we can get into
   1374     0    stevel 		 * a loop with the tty and the modem echoing to each
   1375     0    stevel 		 * other. We presume we are the sole user of this tty
   1376     0    stevel 		 * device, so when we close it, it will revert to its
   1377     0    stevel 		 * defaults anyway.
   1378     0    stevel 		 */
   1379     0    stevel 		inittermios.c_lflag &= ~(ECHO | ECHONL);
   1380     0    stevel 	}
   1381     0    stevel 	if (tcsetattr(fd, TCSAFLUSH, &inittermios) < 0) {
   1382     0    stevel 		if (!hungup && errno != ENXIO) {
   1383     0    stevel 			warn("tcsetattr: %m");
   1384     0    stevel 		}
   1385     0    stevel 	}
   1386     0    stevel 	if (wsinfo.ws_row != 0 || wsinfo.ws_col != 0 ||
   1387     0    stevel 	    wsinfo.ws_xpixel != 0 || wsinfo.ws_ypixel != 0) {
   1388     0    stevel 		if (myioctl(fd, TIOCSWINSZ, &wsinfo) < 0) {
   1389     0    stevel 			warn("unable to set TTY window size: %m");
   1390     0    stevel 		}
   1391     0    stevel 	}
   1392     0    stevel 	restore_term = 0;
   1393     0    stevel }
   1394     0    stevel 
   1395     0    stevel /*
   1396     0    stevel  * setdtr()
   1397     0    stevel  *
   1398     0    stevel  * Control the DTR line on the serial port. This is called from die(), so it
   1399     0    stevel  * shouldn't call die()
   1400     0    stevel  */
   1401     0    stevel void
   1402     0    stevel setdtr(fd, on)
   1403     0    stevel 	int fd, on;
   1404     0    stevel {
   1405     0    stevel 	int modembits = TIOCM_DTR;
   1406     0    stevel 	if (!already_ppp &&
   1407     0    stevel 	    myioctl(fd, (on ? TIOCMBIS : TIOCMBIC), &modembits) < 0) {
   1408     0    stevel 		warn("unable to set DTR line %s: %m", (on ? "ON" : "OFF"));
   1409     0    stevel 	}
   1410     0    stevel }
   1411     0    stevel 
   1412     0    stevel /*
   1413     0    stevel  * open_loopback()
   1414     0    stevel  *
   1415     0    stevel  * Open the device we use for getting packets in demand mode. Under Solaris 2,
   1416     0    stevel  * we use our existing fd to the ppp driver.
   1417     0    stevel  */
   1418     0    stevel int
   1419     0    stevel open_ppp_loopback()
   1420     0    stevel {
   1421     0    stevel 	/*
   1422     0    stevel 	 * Plumb the interface.
   1423     0    stevel 	 */
   1424     0    stevel 	if (IPCP_ENABLED && (plumb_ipif(0) == 0)) {
   1425     0    stevel 		fatal("Unable to initialize IP interface for demand dial.");
   1426     0    stevel 	}
   1427     0    stevel #ifdef INET6
   1428     0    stevel 	if (IPV6CP_ENABLED && (plumb_ip6if(0) == 0)) {
   1429     0    stevel 		fatal("Unable to initialize IPv6 interface for demand dial.");
   1430     0    stevel 	}
   1431     0    stevel #endif /* INET6 */
   1432     0    stevel 
   1433     0    stevel 	return (pppfd);
   1434     0    stevel }
   1435     0    stevel 
   1436     0    stevel /*
   1437     0    stevel  * output()
   1438     0    stevel  *
   1439     0    stevel  * Output PPP packet downstream
   1440     0    stevel  */
   1441     0    stevel /*ARGSUSED*/
   1442     0    stevel void
   1443     0    stevel output(unit, p, len)
   1444     0    stevel 	int unit;
   1445     0    stevel 	uchar_t *p;
   1446     0    stevel 	int len;
   1447     0    stevel {
   1448     0    stevel 	struct strbuf data;
   1449     0    stevel 	struct pollfd pfd;
   1450     0    stevel 	int retries, n;
   1451     0    stevel 	bool sent_ok = 1;
   1452     0    stevel 
   1453     0    stevel 	data.len = len;
   1454     0    stevel 	data.buf = (caddr_t)p;
   1455     0    stevel 	retries = 4;
   1456     0    stevel 
   1457     0    stevel 	while (putmsg(pppfd, NULL, &data, 0) < 0) {
   1458     0    stevel 		if (errno == EINTR)
   1459     0    stevel 			continue;
   1460     0    stevel 		if (--retries < 0 ||
   1461     0    stevel 		    (errno != EWOULDBLOCK && errno != EAGAIN)) {
   1462     0    stevel 			if (errno != ENXIO) {
   1463     0    stevel 				error("Couldn't send packet: %m");
   1464     0    stevel 				sent_ok = 0;
   1465     0    stevel 			}
   1466     0    stevel 			break;
   1467     0    stevel 		}
   1468     0    stevel 		pfd.fd = pppfd;
   1469     0    stevel 		pfd.events = POLLOUT;
   1470     0    stevel 		do {
   1471     0    stevel 			/* wait for up to 0.25 seconds */
   1472     0    stevel 			n = poll(&pfd, 1, 250);
   1473     0    stevel 		} while ((n == -1) && (errno == EINTR));
   1474     0    stevel 	}
   1475     0    stevel 	if (debug && sent_ok) {
   1476     0    stevel 		dbglog("sent %P", p, len);
   1477     0    stevel 	}
   1478     0    stevel }
   1479     0    stevel 
   1480     0    stevel /*
   1481     0    stevel  * wait_input()
   1482     0    stevel  *
   1483     0    stevel  * Wait until there is data available, for the length of time specified by
   1484     0    stevel  * timo (indefinite if timo is NULL).
   1485     0    stevel  */
   1486     0    stevel void
   1487     0    stevel wait_input(timo)
   1488     0    stevel 	struct timeval *timo;
   1489     0    stevel {
   1490     0    stevel 	int t;
   1491     0    stevel 
   1492     0    stevel 	t = (timo == NULL ? -1 : (timo->tv_sec * 1000 + timo->tv_usec / 1000));
   1493     0    stevel 	if ((poll(pollfds, n_pollfds, t) < 0) && (errno != EINTR)) {
   1494     0    stevel 		fatal("poll: %m");
   1495     0    stevel 	}
   1496     0    stevel }
   1497     0    stevel 
   1498     0    stevel /*
   1499     0    stevel  * add_fd()
   1500     0    stevel  *
   1501     0    stevel  * Add an fd to the set that wait_input waits for.
   1502     0    stevel  */
   1503     0    stevel void
   1504     0    stevel add_fd(fd)
   1505     0    stevel 	int fd;
   1506     0    stevel {
   1507     0    stevel 	int n;
   1508     0    stevel 
   1509     0    stevel 	if (fd < 0) {
   1510     0    stevel 		return;
   1511     0    stevel 	}
   1512     0    stevel 	for (n = 0; n < n_pollfds; ++n) {
   1513     0    stevel 		if (pollfds[n].fd == fd) {
   1514     0    stevel 			return;
   1515     0    stevel 		}
   1516     0    stevel 	}
   1517     0    stevel 	if (n_pollfds < MAX_POLLFDS) {
   1518     0    stevel 		pollfds[n_pollfds].fd = fd;
   1519     0    stevel 		pollfds[n_pollfds].events = POLLIN | POLLPRI | POLLHUP;
   1520     0    stevel 		++n_pollfds;
   1521     0    stevel 	} else {
   1522     0    stevel 		fatal("add_fd: too many inputs!");
   1523     0    stevel 	}
   1524     0    stevel }
   1525     0    stevel 
   1526     0    stevel /*
   1527     0    stevel  * remove_fd()
   1528     0    stevel  *
   1529     0    stevel  * Remove an fd from the set that wait_input waits for.
   1530     0    stevel  */
   1531     0    stevel void
   1532     0    stevel remove_fd(fd)
   1533     0    stevel 	int fd;
   1534     0    stevel {
   1535     0    stevel 	int n;
   1536     0    stevel 
   1537     0    stevel 	for (n = 0; n < n_pollfds; ++n) {
   1538     0    stevel 		if (pollfds[n].fd == fd) {
   1539     0    stevel 			while (++n < n_pollfds) {
   1540     0    stevel 				pollfds[n-1] = pollfds[n];
   1541     0    stevel 			}
   1542     0    stevel 			--n_pollfds;
   1543     0    stevel 			break;
   1544     0    stevel 		}
   1545     0    stevel 	}
   1546     0    stevel }
   1547     0    stevel 
   1548     0    stevel static void
   1549     0    stevel dump_packet(uchar_t *buf, int len)
   1550     0    stevel {
   1551     0    stevel 	uchar_t *bp;
   1552     0    stevel 	int proto, offs;
   1553     0    stevel 	const char *cp;
   1554     0    stevel 	char sbuf[32];
   1555     0    stevel 	uint32_t src, dst;
   1556     0    stevel 	struct protoent *pep;
   1557  9751     james 	struct in6_addr addr;
   1558  9751     james 	char fromstr[INET6_ADDRSTRLEN];
   1559  9751     james 	char tostr[INET6_ADDRSTRLEN];
   1560     0    stevel 
   1561     0    stevel 	if (len < 4) {
   1562  9751     james 		notice("strange link activity: %.*B", len, buf);
   1563     0    stevel 		return;
   1564     0    stevel 	}
   1565     0    stevel 	bp = buf;
   1566     0    stevel 	if (bp[0] == 0xFF && bp[1] == 0x03)
   1567     0    stevel 		bp += 2;
   1568     0    stevel 	proto = *bp++;
   1569     0    stevel 	if (!(proto & 1))
   1570     0    stevel 		proto = (proto << 8) + *bp++;
   1571     0    stevel 	len -= bp-buf;
   1572  9751     james 	switch (proto) {
   1573  9751     james 	case PPP_IP:
   1574  9751     james 		if (len < IP_HDRLEN || get_ipv(bp) != 4 || get_iphl(bp) < 5) {
   1575  9751     james 			notice("strange IP packet activity: %16.*B", len, buf);
   1576     0    stevel 			return;
   1577     0    stevel 		}
   1578     0    stevel 		src = get_ipsrc(bp);
   1579     0    stevel 		dst = get_ipdst(bp);
   1580     0    stevel 		proto = get_ipproto(bp);
   1581     0    stevel 		if ((pep = getprotobynumber(proto)) != NULL) {
   1582     0    stevel 			cp = pep->p_name;
   1583     0    stevel 		} else {
   1584     0    stevel 			(void) slprintf(sbuf, sizeof (sbuf), "IP proto %d",
   1585     0    stevel 			    proto);
   1586     0    stevel 			cp = sbuf;
   1587     0    stevel 		}
   1588     0    stevel 		if ((get_ipoff(bp) & IP_OFFMASK) != 0) {
   1589     0    stevel 			len -= get_iphl(bp) * 4;
   1590     0    stevel 			bp += get_iphl(bp) * 4;
   1591  9751     james 			notice("%s fragment from %I->%I: %8.*B", cp, src, dst,
   1592     0    stevel 			    len, bp);
   1593     0    stevel 		} else {
   1594     0    stevel 			if (len > get_iplen(bp))
   1595     0    stevel 				len = get_iplen(bp);
   1596     0    stevel 			len -= get_iphl(bp) * 4;
   1597     0    stevel 			bp += get_iphl(bp) * 4;
   1598     0    stevel 			offs = proto == IPPROTO_TCP ? (get_tcpoff(bp)*4) : 8;
   1599     0    stevel 			if (proto == IPPROTO_TCP || proto == IPPROTO_UDP)
   1600  9751     james 				notice("%s data:%d %s%I:%d->%I:%d: %8.*B", cp,
   1601  9751     james 				    len-offs,
   1602  9751     james 				    proto == IPPROTO_TCP ?
   1603  9751     james 				    tcp_flag_decode(get_tcpflags(bp)) : "",
   1604  9751     james 				    src, get_sport(bp), dst, get_dport(bp),
   1605  9751     james 				    len-offs, bp+offs);
   1606     0    stevel 			else
   1607  9751     james 				notice("%s %d bytes %I->%I: %8.*B", cp, len,
   1608     0    stevel 				    src, dst, len, bp);
   1609     0    stevel 		}
   1610  9751     james 		return;
   1611  9751     james 
   1612  9751     james 	case PPP_IPV6:
   1613  9751     james 		if (len < IP6_HDRLEN) {
   1614  9751     james 			notice("strange IPv6 activity: %16.*B", len, buf);
   1615  9751     james 			return;
   1616  9751     james 		}
   1617  9751     james 		(void) BCOPY(get_ip6src(bp), &addr, sizeof (addr));
   1618  9751     james 		(void) inet_ntop(AF_INET6, &addr, fromstr, sizeof (fromstr));
   1619  9751     james 		(void) BCOPY(get_ip6dst(bp), &addr, sizeof (addr));
   1620  9751     james 		(void) inet_ntop(AF_INET6, &addr, tostr, sizeof (tostr));
   1621  9751     james 		proto = get_ip6nh(bp);
   1622  9751     james 		if (proto == IPPROTO_FRAGMENT) {
   1623  9751     james 			notice("IPv6 fragment from %s->%s", fromstr,
   1624  9751     james 			    tostr);
   1625  9751     james 			return;
   1626  9751     james 		}
   1627  9751     james 		if ((pep = getprotobynumber(proto)) != NULL) {
   1628  9751     james 			cp = pep->p_name;
   1629  9751     james 		} else {
   1630  9751     james 			(void) slprintf(sbuf, sizeof (sbuf), "IPv6 proto %d",
   1631  9751     james 			    proto);
   1632  9751     james 			cp = sbuf;
   1633  9751     james 		}
   1634  9751     james 		len -= IP6_HDRLEN;
   1635  9751     james 		bp += IP6_HDRLEN;
   1636  9751     james 		offs = proto == IPPROTO_TCP ? (get_tcpoff(bp)*4) : 8;
   1637  9751     james 		if (proto == IPPROTO_TCP || proto == IPPROTO_UDP)
   1638  9751     james 			notice("%s data:%d %s[%s]%d->[%s]%d: %8.*B", cp,
   1639  9751     james 			    len-offs,
   1640  9751     james 			    proto == IPPROTO_TCP ?
   1641  9751     james 			    tcp_flag_decode(get_tcpflags(bp)) : "",
   1642  9751     james 			    fromstr, get_sport(bp), tostr, get_dport(bp),
   1643  9751     james 			    len-offs, bp+offs);
   1644  9751     james 		else
   1645  9751     james 			notice("%s %d bytes %s->%s: %8.*B", cp, len,
   1646  9751     james 			    fromstr, tostr, len, bp);
   1647     0    stevel 		return;
   1648     0    stevel 	}
   1649     0    stevel 	if ((cp = protocol_name(proto)) == NULL) {
   1650     0    stevel 		(void) slprintf(sbuf, sizeof (sbuf), "0x#X", proto);
   1651     0    stevel 		cp = (const char *)sbuf;
   1652     0    stevel 	}
   1653  9751     james 	notice("link activity: %s %16.*B", cp, len, bp);
   1654     0    stevel }
   1655     0    stevel 
   1656     0    stevel /*
   1657     0    stevel  * handle_bind()
   1658     0    stevel  */
   1659     0    stevel static void
   1660     0    stevel handle_bind(u_int32_t reason)
   1661     0    stevel {
   1662     0    stevel 	/*
   1663     0    stevel 	 * Here we might, in the future, handle DL_BIND_REQ notifications
   1664     0    stevel 	 * in order to close and re-open a NCP when certain interface
   1665     0    stevel 	 * parameters (addresses, etc.) are changed via external mechanisms
   1666     0    stevel 	 * such as through the "ifconfig" program.
   1667     0    stevel 	 */
   1668     0    stevel 	switch (reason) {
   1669     0    stevel 	case PPP_LINKSTAT_IPV4_BOUND:
   1670     0    stevel 		break;
   1671     0    stevel #ifdef INET6
   1672     0    stevel 	case PPP_LINKSTAT_IPV6_BOUND:
   1673     0    stevel 		break;
   1674     0    stevel #endif
   1675     0    stevel 	default:
   1676     0    stevel 		error("handle_bind: unrecognized reason");
   1677     0    stevel 		break;
   1678     0    stevel 	}
   1679     0    stevel }
   1680     0    stevel 
   1681     0    stevel /*
   1682     0    stevel  * handle_unbind()
   1683     0    stevel  */
   1684     0    stevel static void
   1685     0    stevel handle_unbind(u_int32_t reason)
   1686     0    stevel {
   1687     0    stevel 	bool iff_up_isset;
   1688     0    stevel 	int rc;
   1689     0    stevel 	static const char *unplumb_str = "unplumbed";
   1690     0    stevel 	static const char *down_str = "downed";
   1691     0    stevel 
   1692     0    stevel 	/*
   1693     0    stevel 	 * Since the kernel driver (sppp) notifies this daemon of the
   1694     0    stevel 	 * DLPI bind/unbind activities (for the purpose of bringing down
   1695     0    stevel 	 * a NCP), we need to explicitly test the "actual" status of
   1696     0    stevel 	 * the interface instance for which the notification is destined
   1697     0    stevel 	 * from.  This is because /dev/ip performs multiple DLPI attach-
   1698     0    stevel 	 * bind-unbind-detach during the early life of the interface,
   1699     0    stevel 	 * and when certain interface parameters change.  A DL_UNBIND_REQ
   1700     0    stevel 	 * coming down to the sppp driver from /dev/ip (which results in
   1701     0    stevel 	 * our receiving of the PPP_LINKSTAT_*_UNBOUND link status message)
   1702     0    stevel 	 * is not enough to conclude that the interface has been marked
   1703     0    stevel 	 * DOWN (its IFF_UP bit is cleared) or is going away.  Therefore,
   1704     0    stevel 	 * we should query /dev/ip directly, upon receiving such *_UNBOUND
   1705     0    stevel 	 * notification, to determine whether the interface is DOWN
   1706     0    stevel 	 * for real, and only take the necessary actions when IFF_UP
   1707     0    stevel 	 * bit for the interface instance is actually cleared.
   1708     0    stevel 	 */
   1709     0    stevel 	switch (reason) {
   1710     0    stevel 	case PPP_LINKSTAT_IPV4_UNBOUND:
   1711     0    stevel 		(void) sleep(1);
   1712     0    stevel 		rc = giflags(IFF_UP, &iff_up_isset);
   1713     0    stevel 		if (!iff_up_isset) {
   1714     0    stevel 			if_is_up = 0;
   1715     0    stevel 			ipmuxid = -1;
   1716     0    stevel 			info("IPv4 interface %s by administrator",
   1717     0    stevel 			    ((rc < 0 && rc == ENXIO) ? unplumb_str : down_str));
   1718     0    stevel 			fsm_close(&ipcp_fsm[0],
   1719     0    stevel 			    "administratively disconnected");
   1720     0    stevel 		}
   1721     0    stevel 		break;
   1722     0    stevel #ifdef INET6
   1723     0    stevel 	case PPP_LINKSTAT_IPV6_UNBOUND:
   1724     0    stevel 		(void) sleep(1);
   1725     0    stevel 		rc = giflags(IFF_UP, &iff_up_isset);
   1726     0    stevel 		if (!iff_up_isset) {
   1727     0    stevel 			if6_is_up = 0;
   1728     0    stevel 			ip6muxid = -1;
   1729     0    stevel 			info("IPv6 interface %s by administrator",
   1730     0    stevel 			    ((rc < 0 && rc == ENXIO) ? unplumb_str : down_str));
   1731     0    stevel 			fsm_close(&ipv6cp_fsm[0],
   1732     0    stevel 			    "administratively disconnected");
   1733     0    stevel 		}
   1734     0    stevel 		break;
   1735     0    stevel #endif
   1736     0    stevel 	default:
   1737     0    stevel 		error("handle_unbind: unrecognized reason");
   1738     0    stevel 		break;
   1739     0    stevel 	}
   1740     0    stevel }
   1741     0    stevel 
   1742     0    stevel /*
   1743     0    stevel  * read_packet()
   1744     0    stevel  *
   1745     0    stevel  * Get a PPP packet from the serial device.
   1746     0    stevel  */
   1747     0    stevel int
   1748     0    stevel read_packet(buf)
   1749     0    stevel 	uchar_t *buf;
   1750     0    stevel {
   1751     0    stevel 	struct strbuf ctrl;
   1752     0    stevel 	struct strbuf data;
   1753     0    stevel 	int flags;
   1754     0    stevel 	int len;
   1755     0    stevel 	int rc;
   1756     0    stevel 	struct ppp_ls *plp;
   1757     0    stevel 	uint32_t ctrlbuf[1536 / sizeof (uint32_t)];
   1758     0    stevel 	bool flushmode;
   1759     0    stevel 
   1760     0    stevel 	flushmode = 0;
   1761     0    stevel 	for (;;) {
   1762     0    stevel 
   1763     0    stevel 		data.maxlen = PPP_MRU + PPP_HDRLEN;
   1764     0    stevel 		data.buf = (caddr_t)buf;
   1765     0    stevel 
   1766     0    stevel 		ctrl.maxlen = sizeof (ctrlbuf);
   1767     0    stevel 		ctrl.buf = (caddr_t)ctrlbuf;
   1768     0    stevel 
   1769     0    stevel 		flags = 0;
   1770     0    stevel 		rc = len = getmsg(pppfd, &ctrl, &data, &flags);
   1771     0    stevel 		if (sys_read_packet_hook != NULL) {
   1772     0    stevel 			rc = len = (*sys_read_packet_hook)(len, &ctrl, &data,
   1773     0    stevel 			    flags);
   1774     0    stevel 		}
   1775     0    stevel 		if (len < 0) {
   1776     0    stevel 			if (errno == EAGAIN || errno == EINTR) {
   1777     0    stevel 				return (-1);
   1778     0    stevel 			}
   1779     0    stevel 			fatal("Error reading packet: %m");
   1780     0    stevel 		}
   1781     0    stevel 		if ((data.len > 0) && (ctrl.len < 0)) {
   1782     0    stevel 			/*
   1783     0    stevel 			 * If there's more data on stream head, keep reading
   1784     0    stevel 			 * but discard, since the stream is now corrupt.
   1785     0    stevel 			 */
   1786     0    stevel 			if (rc & MOREDATA) {
   1787     0    stevel 				dbglog("More data; input packet garbled");
   1788     0    stevel 				flushmode = 1;
   1789     0    stevel 				continue;
   1790     0    stevel 			}
   1791     0    stevel 			if (flushmode)
   1792     0    stevel 				return (-1);
   1793     0    stevel 			return (data.len);
   1794     0    stevel 
   1795     0    stevel 		} else if (ctrl.len > 0) {
   1796     0    stevel 			/*
   1797     0    stevel 			 * If there's more ctl on stream head, keep reading,
   1798     0    stevel 			 * but start discarding.  We can't deal with fragmented
   1799     0    stevel 			 * messages at all.
   1800     0    stevel 			 */
   1801     0    stevel 			if (rc & MORECTL) {
   1802     0    stevel 				dbglog("More control; stream garbled");
   1803     0    stevel 				flushmode = 1;
   1804     0    stevel 				continue;
   1805     0    stevel 			}
   1806     0    stevel 			if (flushmode)
   1807     0    stevel 				return (-1);
   1808     0    stevel 			if (ctrl.len < sizeof (struct ppp_ls)) {
   1809     0    stevel 				warn("read_packet: ctl.len %d < "
   1810     0    stevel 				    "sizeof ppp_ls %d",
   1811     0    stevel 				    ctrl.len, sizeof (struct ppp_ls));
   1812     0    stevel 				return (-1);
   1813     0    stevel 			}
   1814     0    stevel 			plp = (struct ppp_ls *)ctrlbuf;
   1815     0    stevel 			if (plp->magic != PPPLSMAGIC) {
   1816     0    stevel 				/* Skip, as we don't understand it */
   1817     0    stevel 				dbglog("read_packet: unrecognized control %lX",
   1818     0    stevel 				    plp->magic);
   1819     0    stevel 				return (-1);
   1820     0    stevel 			}
   1821     0    stevel 
   1822     0    stevel 			lastlink_status = plp->ppp_message;
   1823     0    stevel 
   1824     0    stevel 			switch (plp->ppp_message) {
   1825     0    stevel 			case PPP_LINKSTAT_HANGUP:
   1826     0    stevel 				return (0);	/* Hangup */
   1827     0    stevel 			/* For use by integrated drivers. */
   1828     0    stevel 			case PPP_LINKSTAT_UP:
   1829     0    stevel 				lcp_lowerdown(0);
   1830     0    stevel 				lcp_lowerup(0);
   1831     0    stevel 				return (0);
   1832     0    stevel 			case PPP_LINKSTAT_NEEDUP:
   1833  9751     james 				if (data.len > 0)
   1834     0    stevel 					dump_packet(buf, data.len);
   1835     0    stevel 				return (-1);	/* Demand dial */
   1836     0    stevel 			case PPP_LINKSTAT_IPV4_UNBOUND:
   1837     0    stevel 				(void) handle_unbind(plp->ppp_message);
   1838     0    stevel 				return (-1);
   1839     0    stevel 			case PPP_LINKSTAT_IPV4_BOUND:
   1840     0    stevel 				(void) handle_bind(plp->ppp_message);
   1841     0    stevel 				return (-1);
   1842     0    stevel #ifdef INET6
   1843     0    stevel 			case PPP_LINKSTAT_IPV6_UNBOUND:
   1844     0    stevel 				(void) handle_unbind(plp->ppp_message);
   1845     0    stevel 				return (-1);
   1846     0    stevel 			case PPP_LINKSTAT_IPV6_BOUND:
   1847     0    stevel 				(void) handle_bind(plp->ppp_message);
   1848     0    stevel 				return (-1);
   1849     0    stevel #endif
   1850     0    stevel 			default:
   1851     0    stevel 				warn("read_packet: unknown link status type!");
   1852     0    stevel 				return (-1);
   1853     0    stevel 			}
   1854     0    stevel 		} else {
   1855     0    stevel 			/*
   1856     0    stevel 			 * We get here on zero length data or control.
   1857     0    stevel 			 */
   1858     0    stevel 			return (-1);
   1859     0    stevel 		}
   1860     0    stevel 	}
   1861     0    stevel }
   1862     0    stevel 
   1863     0    stevel /*
   1864     0    stevel  * get_loop_output()
   1865     0    stevel  *
   1866     0    stevel  * Get outgoing packets from the ppp device, and detect when we want to bring
   1867     0    stevel  * the real link up. Return value is 1 if we need to bring up the link, or 0
   1868     0    stevel  * otherwise.
   1869     0    stevel  */
   1870     0    stevel int
   1871     0    stevel get_loop_output()
   1872     0    stevel {
   1873     0    stevel 	int loops;
   1874     0    stevel 
   1875     0    stevel 	/*
   1876     0    stevel 	 * In the Solaris 2.x kernel-level portion implementation, packets
   1877     0    stevel 	 * which are received on a demand-dial interface are immediately
   1878     0    stevel 	 * discarded, and a notification message is sent up the control
   1879     0    stevel 	 * stream to the pppd process.  Therefore, the call to read_packet()
   1880     0    stevel 	 * below is merely there to wait for such message.
   1881     0    stevel 	 */
   1882     0    stevel 	lastlink_status = 0;
   1883     0    stevel 	loops = 0;
   1884     0    stevel 	while (read_packet(inpacket_buf) > 0) {
   1885     0    stevel 		if (++loops > 10)
   1886     0    stevel 			break;
   1887     0    stevel 	}
   1888     0    stevel 	return (lastlink_status == PPP_LINKSTAT_NEEDUP);
   1889     0    stevel }
   1890     0    stevel 
   1891     0    stevel #ifdef MUX_FRAME
   1892     0    stevel /*ARGSUSED*/
   1893     0    stevel void
   1894     0    stevel ppp_send_muxoption(unit, muxflag)
   1895     0    stevel 	int unit;
   1896     0    stevel 	u_int32_t muxflag;
   1897     0    stevel {
   1898     0    stevel 	uint32_t	cf[2];
   1899     0    stevel 
   1900     0    stevel 	/*
   1901     0    stevel 	 * Since muxed frame feature is implemented in the async module,
   1902     0    stevel 	 * don't send down the ioctl in the synchronous case.
   1903     0    stevel 	 */
   1904     0    stevel 	if (!sync_serial && fdmuxid >= 0 && pppfd != -1) {
   1905     0    stevel 		cf[0] = muxflag;
   1906     0    stevel 		cf[1] = X_MUXMASK;
   1907     0    stevel 
   1908     0    stevel 		if (strioctl(pppfd, PPPIO_MUX, cf, sizeof (cf), 0) < 0) {
   1909     0    stevel 			error("Couldn't set mux option: %m");
   1910     0    stevel 		}
   1911     0    stevel 	}
   1912     0    stevel }
   1913     0    stevel 
   1914     0    stevel /*ARGSUSED*/
   1915     0    stevel void
   1916     0    stevel ppp_recv_muxoption(unit, muxflag)
   1917     0    stevel 	int unit;
   1918     0    stevel 	u_int32_t muxflag;
   1919     0    stevel {
   1920     0    stevel 	uint32_t	cf[2];
   1921     0    stevel 
   1922     0    stevel 	/*
   1923     0    stevel 	 * Since muxed frame feature is implemented in the async module,
   1924     0    stevel 	 * don't send down the ioctl in the synchronous case.
   1925     0    stevel 	 */
   1926     0    stevel 	if (!sync_serial && fdmuxid >= 0 && pppfd != -1) {
   1927     0    stevel 		cf[0] = muxflag;
   1928     0    stevel 		cf[1] = R_MUXMASK;
   1929     0    stevel 
   1930     0    stevel 		if (strioctl(pppfd, PPPIO_MUX, cf, sizeof (cf), 0) < 0) {
   1931     0    stevel 			error("Couldn't set receive mux option: %m");
   1932     0    stevel 		}
   1933     0    stevel 	}
   1934     0    stevel }
   1935     0    stevel #endif
   1936     0    stevel 
   1937     0    stevel /*
   1938     0    stevel  * ppp_send_config()
   1939     0    stevel  *
   1940     0    stevel  * Configure the transmit characteristics of the ppp interface.
   1941     0    stevel  */
   1942     0    stevel /*ARGSUSED*/
   1943     0    stevel void
   1944     0    stevel ppp_send_config(unit, mtu, asyncmap, pcomp, accomp)
   1945     0    stevel 	int unit;
   1946     0    stevel 	int mtu;
   1947     0    stevel 	u_int32_t asyncmap;
   1948     0    stevel 	int pcomp;
   1949     0    stevel 	int accomp;
   1950     0    stevel {
   1951     0    stevel 	uint32_t cf[2];
   1952     0    stevel 
   1953     0    stevel 	if (pppfd == -1) {
   1954     0    stevel 		error("ppp_send_config called with invalid device handle");
   1955     0    stevel 		return;
   1956     0    stevel 	}
   1957     0    stevel 	cf[0] =	link_mtu = mtu;
   1958     0    stevel 	if (strioctl(pppfd, PPPIO_MTU, cf, sizeof (cf[0]), 0) < 0) {
   1959     0    stevel 		if (hungup && errno == ENXIO) {
   1960     0    stevel 			return;
   1961     0    stevel 		}
   1962     0    stevel 		error("Couldn't set MTU: %m");
   1963     0    stevel 	}
   1964     0    stevel 	if (fdmuxid != -1) {
   1965     0    stevel 		if (!sync_serial) {
   1966     0    stevel 			if (strioctl(pppfd, PPPIO_XACCM, &asyncmap,
   1967     0    stevel 			    sizeof (asyncmap), 0) < 0) {
   1968     0    stevel 				error("Couldn't set transmit ACCM: %m");
   1969     0    stevel 			}
   1970     0    stevel 		}
   1971     0    stevel 		cf[0] = (pcomp? COMP_PROT: 0) + (accomp? COMP_AC: 0);
   1972     0    stevel 		cf[1] = COMP_PROT | COMP_AC;
   1973     0    stevel 
   1974     0    stevel 		if (any_compressions() && strioctl(pppfd, PPPIO_CFLAGS, cf,
   1975     0    stevel 		    sizeof (cf), sizeof (cf[0])) < 0) {
   1976     0    stevel 			error("Couldn't set prot/AC compression: %m");
   1977     0    stevel 		}
   1978     0    stevel 	}
   1979     0    stevel }
   1980     0    stevel 
   1981     0    stevel /*
   1982     0    stevel  * ppp_set_xaccm()
   1983     0    stevel  *
   1984     0    stevel  * Set the extended transmit ACCM for the interface.
   1985     0    stevel  */
   1986     0    stevel /*ARGSUSED*/
   1987     0    stevel void
   1988     0    stevel ppp_set_xaccm(unit, accm)
   1989     0    stevel 	int unit;
   1990     0    stevel 	ext_accm accm;
   1991     0    stevel {
   1992     0    stevel 	if (sync_serial) {
   1993     0    stevel 		return;
   1994     0    stevel 	}
   1995     0    stevel 	if (fdmuxid != -1 && strioctl(pppfd, PPPIO_XACCM, accm,
   1996     0    stevel 	    sizeof (ext_accm), 0) < 0) {
   1997     0    stevel 		if (!hungup || errno != ENXIO) {
   1998     0    stevel 			warn("Couldn't set extended ACCM: %m");
   1999     0    stevel 		}
   2000     0    stevel 	}
   2001     0    stevel }
   2002     0    stevel 
   2003     0    stevel /*
   2004     0    stevel  * ppp_recv_config()
   2005     0    stevel  *
   2006     0    stevel  * Configure the receive-side characteristics of the ppp interface.
   2007     0    stevel  */
   2008     0    stevel /*ARGSUSED*/
   2009     0    stevel void
   2010     0    stevel ppp_recv_config(unit, mru, asyncmap, pcomp, accomp)
   2011     0    stevel 	int unit;
   2012     0    stevel 	int mru;
   2013     0    stevel 	u_int32_t asyncmap;
   2014     0    stevel 	int pcomp;
   2015     0    stevel 	int accomp;
   2016     0    stevel {
   2017     0    stevel 	uint32_t cf[2];
   2018     0    stevel 
   2019     0    stevel 	if (pppfd == -1) {
   2020     0    stevel 		error("ppp_recv_config called with invalid device handle");
   2021     0    stevel 		return;
   2022     0    stevel 	}
   2023     0    stevel 	cf[0] = mru;
   2024     0    stevel 	if (strioctl(pppfd, PPPIO_MRU, cf, sizeof (cf[0]), 0) < 0) {
   2025     0    stevel 		if (hungup && errno == ENXIO) {
   2026     0    stevel 			return;
   2027     0    stevel 		}
   2028     0    stevel 		error("Couldn't set MRU: %m");
   2029     0    stevel 	}
   2030     0    stevel 	if (fdmuxid != -1) {
   2031     0    stevel 		if (!sync_serial) {
   2032     0    stevel 			if (strioctl(pppfd, PPPIO_RACCM, &asyncmap,
   2033     0    stevel 			    sizeof (asyncmap), 0) < 0) {
   2034     0    stevel 				error("Couldn't set receive ACCM: %m");
   2035     0    stevel 			}
   2036     0    stevel 		}
   2037     0    stevel 		cf[0] = (pcomp ? DECOMP_PROT : 0) + (accomp ? DECOMP_AC : 0);
   2038     0    stevel 		cf[1] = DECOMP_PROT | DECOMP_AC;
   2039     0    stevel 
   2040     0    stevel 		if (any_compressions() && strioctl(pppfd, PPPIO_CFLAGS, cf,
   2041     0    stevel 		    sizeof (cf), sizeof (cf[0])) < 0) {
   2042     0    stevel 			error("Couldn't set prot/AC decompression: %m");
   2043     0    stevel 		}
   2044     0    stevel 	}
   2045     0    stevel }
   2046     0    stevel 
   2047     0    stevel #ifdef NEGOTIATE_FCS
   2048     0    stevel /*
   2049     0    stevel  * ppp_send_fcs()
   2050     0    stevel  *
   2051     0    stevel  * Configure the sender-side FCS.
   2052     0    stevel  */
   2053     0    stevel /*ARGSUSED*/
   2054     0    stevel void
   2055     0    stevel ppp_send_fcs(unit, fcstype)
   2056     0    stevel 	int unit, fcstype;
   2057     0    stevel {
   2058     0    stevel 	uint32_t fcs;
   2059     0    stevel 
   2060     0    stevel 	if (sync_serial) {
   2061     0    stevel 		return;
   2062     0    stevel 	}
   2063     0    stevel 
   2064     0    stevel 	if (fcstype & FCSALT_32) {
   2065     0    stevel 		fcs = PPPFCS_32;
   2066     0    stevel 	} else if (fcstype & FCSALT_NULL) {
   2067     0    stevel 		fcs = PPPFCS_NONE;
   2068     0    stevel 	} else {
   2069     0    stevel 		fcs = PPPFCS_16;
   2070     0    stevel 	}
   2071     0    stevel 	if (strioctl(pppfd, PPPIO_XFCS, &fcs, sizeof (fcs), 0) < 0) {
   2072     0    stevel 		warn("Couldn't set transmit FCS: %m");
   2073     0    stevel 	}
   2074     0    stevel }
   2075     0    stevel 
   2076     0    stevel /*
   2077     0    stevel  * ppp_recv_fcs()
   2078     0    stevel  *
   2079     0    stevel  * Configure the receiver-side FCS.
   2080     0    stevel  */
   2081     0    stevel /*ARGSUSED*/
   2082     0    stevel void
   2083     0    stevel ppp_recv_fcs(unit, fcstype)
   2084     0    stevel 	int unit, fcstype;
   2085     0    stevel {
   2086     0    stevel 	uint32_t fcs;
   2087     0    stevel 
   2088     0    stevel 	if (sync_serial) {
   2089     0    stevel 		return;
   2090     0    stevel 	}
   2091     0    stevel 
   2092     0    stevel 	if (fcstype & FCSALT_32) {
   2093     0    stevel 		fcs = PPPFCS_32;
   2094     0    stevel 	} else if (fcstype & FCSALT_NULL) {
   2095     0    stevel 		fcs = PPPFCS_NONE;
   2096     0    stevel 	} else {
   2097     0    stevel 		fcs = PPPFCS_16;
   2098     0    stevel 	}
   2099     0    stevel 	if (strioctl(pppfd, PPPIO_RFCS, &fcs, sizeof (fcs), 0) < 0) {
   2100     0    stevel 		warn("Couldn't set receive FCS: %m");
   2101     0    stevel 	}
   2102     0    stevel }
   2103     0    stevel #endif
   2104     0    stevel 
   2105     0    stevel /*
   2106     0    stevel  * ccp_test()
   2107     0    stevel  *
   2108     0    stevel  * Ask kernel whether a given compression method is acceptable for use.
   2109     0    stevel  */
   2110     0    stevel /*ARGSUSED*/
   2111     0    stevel int
   2112     0    stevel ccp_test(unit, opt_ptr, opt_len, for_transmit)
   2113     0    stevel 	int unit;
   2114     0    stevel 	uchar_t *opt_ptr;
   2115     0    stevel 	int opt_len;
   2116     0    stevel 	int for_transmit;
   2117     0    stevel {
   2118     0    stevel 	if (strioctl(pppfd, (for_transmit ? PPPIO_XCOMP : PPPIO_RCOMP),
   2119     0    stevel 	    opt_ptr, opt_len, 0) >= 0) {
   2120     0    stevel 		return (1);
   2121     0    stevel 	}
   2122     0    stevel 	warn("Error in %s ioctl: %m",
   2123     0    stevel 	    (for_transmit ? "PPPIO_XCOMP" : "PPPIO_RCOMP"));
   2124     0    stevel 	return ((errno == ENOSR) ? 0 : -1);
   2125     0    stevel }
   2126     0    stevel 
   2127     0    stevel #ifdef COMP_TUNE
   2128     0    stevel /*
   2129     0    stevel  * ccp_tune()
   2130     0    stevel  *
   2131     0    stevel  * Tune compression effort level.
   2132     0    stevel  */
   2133     0    stevel /*ARGSUSED*/
   2134     0    stevel void
   2135     0    stevel ccp_tune(unit, effort)
   2136     0    stevel 	int unit, effort;
   2137     0    stevel {
   2138     0    stevel 	uint32_t x;
   2139     0    stevel 
   2140     0    stevel 	x = effort;
   2141     0    stevel 	if (strioctl(pppfd, PPPIO_COMPLEV, &x, sizeof (x), 0) < 0) {
   2142     0    stevel 		warn("unable to set compression effort level: %m");
   2143     0    stevel 	}
   2144     0    stevel }
   2145     0    stevel #endif
   2146     0    stevel 
   2147     0    stevel /*
   2148     0    stevel  * ccp_flags_set()
   2149     0    stevel  *
   2150     0    stevel  * Inform kernel about the current state of CCP.
   2151     0    stevel  */
   2152     0    stevel /*ARGSUSED*/
   2153     0    stevel void
   2154     0    stevel ccp_flags_set(unit, isopen, isup)
   2155     0    stevel 	int unit, isopen, isup;
   2156     0    stevel {
   2157     0    stevel 	uint32_t cf[2];
   2158     0    stevel 
   2159     0    stevel 	cf[0] = (isopen ? CCP_ISOPEN : 0) + (isup ? CCP_ISUP : 0);
   2160     0    stevel 	cf[1] = CCP_ISOPEN | CCP_ISUP | CCP_ERROR | CCP_FATALERROR;
   2161     0    stevel 
   2162     0    stevel 	if (strioctl(pppfd, PPPIO_CFLAGS, cf, sizeof (cf), sizeof (cf[0]))
   2163     0    stevel 	    < 0) {
   2164     0    stevel 		if (!hungup || errno != ENXIO) {
   2165     0    stevel 			error("Couldn't set kernel CCP state: %m");
   2166     0    stevel 		}
   2167     0    stevel 	}
   2168     0    stevel }
   2169     0    stevel 
   2170     0    stevel /*
   2171     0    stevel  * get_idle_time()
   2172     0    stevel  *
   2173     0    stevel  * Return how long the link has been idle.
   2174     0    stevel  */
   2175     0    stevel /*ARGSUSED*/
   2176     0    stevel int
   2177     0    stevel get_idle_time(u, pids)
   2178     0    stevel 	int u;
   2179     0    stevel 	struct ppp_idle *pids;
   2180     0    stevel {
   2181     0    stevel 	int rc;
   2182     0    stevel 
   2183     0    stevel 	rc = strioctl(pppfd, PPPIO_GIDLE, pids, 0, sizeof (struct ppp_idle));
   2184     0    stevel 	if (rc < 0) {
   2185     0    stevel 		warn("unable to obtain idle time: %m");
   2186     0    stevel 	}
   2187     0    stevel 	return ((rc == 0) ? 1 : 0);
   2188     0    stevel }
   2189     0    stevel 
   2190     0    stevel /*
   2191     0    stevel  * get_ppp_stats()
   2192     0    stevel  *
   2193     0    stevel  * Return statistics for the link.
   2194     0    stevel  */
   2195     0    stevel /*ARGSUSED*/
   2196     0    stevel int
   2197     0    stevel get_ppp_stats(u, stats)
   2198     0    stevel 	int u;
   2199     0    stevel 	struct pppd_stats *stats;
   2200     0    stevel {
   2201     0    stevel 	struct ppp_stats64 s64;
   2202     0    stevel 	struct ppp_stats s;
   2203     0    stevel 
   2204     0    stevel 	/* Try first to get these from the 64-bit interface */
   2205     0    stevel 	if (strioctl(pppfd, PPPIO_GETSTAT64, &s64, 0, sizeof (s64)) >= 0) {
   2206     0    stevel 		stats->bytes_in = s64.p.ppp_ibytes;
   2207     0    stevel 		stats->bytes_out = s64.p.ppp_obytes;
   2208     0    stevel 		stats->pkts_in = s64.p.ppp_ipackets;
   2209     0    stevel 		stats->pkts_out = s64.p.ppp_opackets;
   2210     0    stevel 		return (1);
   2211     0    stevel 	}
   2212     0    stevel 
   2213     0    stevel 	if (strioctl(pppfd, PPPIO_GETSTAT, &s, 0, sizeof (s)) < 0) {
   2214     0    stevel 		error("Couldn't get link statistics: %m");
   2215     0    stevel 		return (0);
   2216     0    stevel 	}
   2217     0    stevel 	stats->bytes_in = s.p.ppp_ibytes;
   2218     0    stevel 	stats->bytes_out = s.p.ppp_obytes;
   2219     0    stevel 	stats->pkts_in = s.p.ppp_ipackets;
   2220     0    stevel 	stats->pkts_out = s.p.ppp_opackets;
   2221     0    stevel 	return (1);
   2222     0    stevel }
   2223     0    stevel 
   2224     0    stevel #if defined(FILTER_PACKETS)
   2225     0    stevel /*
   2226     0    stevel  * set_filters()
   2227     0    stevel  *
   2228     0    stevel  * Transfer the pass and active filters to the kernel.
   2229     0    stevel  */
   2230     0    stevel int
   2231     0    stevel set_filters(pass, active)
   2232     0    stevel 	struct bpf_program *pass;
   2233     0    stevel 	struct bpf_program *active;
   2234     0    stevel {
   2235     0    stevel 	int ret = 1;
   2236     0    stevel 
   2237     0    stevel 	if (pass->bf_len > 0) {
   2238     0    stevel 		if (strioctl(pppfd, PPPIO_PASSFILT, pass,
   2239     0    stevel 		    sizeof (struct bpf_program), 0) < 0) {
   2240     0    stevel 			error("Couldn't set pass-filter in kernel: %m");
   2241     0    stevel 			ret = 0;
   2242     0    stevel 		}
   2243     0    stevel 	}
   2244     0    stevel 	if (active->bf_len > 0) {
   2245     0    stevel 		if (strioctl(pppfd, PPPIO_ACTIVEFILT, active,
   2246     0    stevel 		    sizeof (struct bpf_program), 0) < 0) {
   2247     0    stevel 			error("Couldn't set active-filter in kernel: %m");
   2248     0    stevel 			ret = 0;
   2249     0    stevel 		}
   2250     0    stevel 	}
   2251     0    stevel 	return (ret);
   2252     0    stevel }
   2253     0    stevel #endif /* FILTER_PACKETS */
   2254     0    stevel 
   2255     0    stevel /*
   2256     0    stevel  * ccp_fatal_error()
   2257     0    stevel  *
   2258     0    stevel  * Returns 1 if decompression was disabled as a result of an error detected
   2259     0    stevel  * after decompression of a packet, 0 otherwise.  This is necessary because
   2260     0    stevel  * of patent nonsense.
   2261     0    stevel  */
   2262     0    stevel /*ARGSUSED*/
   2263     0    stevel int
   2264     0    stevel ccp_fatal_error(unit)
   2265     0    stevel 	int unit;
   2266     0    stevel {
   2267     0    stevel 	uint32_t cf[2];
   2268     0    stevel 
   2269     0    stevel 	cf[0] = cf[1] = 0;
   2270     0    stevel 	if (strioctl(pppfd, PPPIO_CFLAGS, cf, sizeof (cf), sizeof (cf[0]))
   2271     0    stevel 	    < 0) {
   2272     0    stevel 		if (errno != ENXIO && errno != EINVAL) {
   2273     0    stevel 			error("Couldn't get compression flags: %m");
   2274     0    stevel 		}
   2275     0    stevel 		return (0);
   2276     0    stevel 	}
   2277     0    stevel 	return (cf[0] & CCP_FATALERROR);
   2278     0    stevel }
   2279     0    stevel 
   2280     0    stevel /*
   2281     0    stevel  * sifvjcomp()
   2282     0    stevel  *
   2283     0    stevel  * Config TCP header compression.
   2284     0    stevel  */
   2285     0    stevel /*ARGSUSED*/
   2286     0    stevel int
   2287     0    stevel sifvjcomp(u, vjcomp, xcidcomp, xmaxcid)
   2288     0    stevel 	int u, vjcomp, xcidcomp, xmaxcid;
   2289     0    stevel {
   2290     0    stevel 	uint32_t cf[2];
   2291     0    stevel 	uchar_t maxcid[2];
   2292     0    stevel 
   2293     0    stevel 	/*
   2294     0    stevel 	 * Since VJ compression code is in the comp module, there's no
   2295     0    stevel 	 * point of sending down any ioctls pertaining to VJ compression
   2296     0    stevel 	 * when the module isn't pushed on the stream.
   2297     0    stevel 	 */
   2298     0    stevel 	if (!any_compressions()) {
   2299     0    stevel 		return (1);
   2300     0    stevel 	}
   2301     0    stevel 
   2302     0    stevel 	if (vjcomp) {
   2303     0    stevel 		maxcid[0] = xcidcomp;
   2304     0    stevel 		maxcid[1] = 15;		/* XXX should be rmaxcid */
   2305     0    stevel 
   2306     0    stevel 		if (strioctl(pppfd, PPPIO_VJINIT, maxcid,
   2307     0    stevel 		    sizeof (maxcid), 0) < 0) {
   2308     0    stevel 			error("Couldn't initialize VJ compression: %m");
   2309     0    stevel 			return (0);
   2310     0    stevel 		}
   2311     0    stevel 	}
   2312     0    stevel 
   2313     0    stevel 	cf[0] = (vjcomp ? COMP_VJC + DECOMP_VJC : 0)	/* XXX this is wrong */
   2314     0    stevel 		+ (xcidcomp? COMP_VJCCID + DECOMP_VJCCID: 0);
   2315     0    stevel 
   2316     0    stevel 	cf[1] = COMP_VJC + DECOMP_VJC + COMP_VJCCID + DECOMP_VJCCID;
   2317     0    stevel 
   2318     0    stevel 	if (strioctl(pppfd, PPPIO_CFLAGS, cf, sizeof (cf), sizeof (cf[0]))
   2319     0    stevel 	    < 0) {
   2320     0    stevel 		if (vjcomp) {
   2321     0    stevel 			error("Couldn't enable VJ compression: %m");
   2322     0    stevel 		} else {
   2323     0    stevel 			error("Couldn't disable VJ compression: %m");
   2324     0    stevel 		}
   2325     0    stevel 		return (0);
   2326     0    stevel 	}
   2327     0    stevel 	return (1);
   2328     0    stevel }
   2329     0    stevel 
   2330     0    stevel /*
   2331     0    stevel  * siflags()
   2332     0    stevel  *
   2333     0    stevel  * Set or clear the IP interface flags.
   2334     0    stevel  */
   2335     0    stevel int
   2336     0    stevel siflags(f, set)
   2337     0    stevel 	u_int32_t f;
   2338     0    stevel 	int set;
   2339     0    stevel {
   2340     0    stevel 	struct ifreq ifr;
   2341     0    stevel 
   2342     0    stevel 	if (!IPCP_ENABLED || (ipmuxid == -1)) {
   2343     0    stevel 		return (0);
   2344     0    stevel 	}
   2345     0    stevel 	if (ipfd == -1 && open_ipfd() == -1)
   2346     0    stevel 		return (0);
   2347     0    stevel 	BZERO(&ifr, sizeof (ifr));
   2348     0    stevel 	(void) strlcpy(ifr.ifr_name, ifname, sizeof (ifr.ifr_name));
   2349     0    stevel 	if (myioctl(ipfd, SIOCGIFFLAGS, &ifr) < 0) {
   2350     0    stevel 		error("Couldn't get IP interface flags: %m");
   2351     0    stevel 		return (0);
   2352     0    stevel 	}
   2353     0    stevel 	if (set) {
   2354     0    stevel 		ifr.ifr_flags |= f;
   2355     0    stevel 	} else {
   2356     0    stevel 		ifr.ifr_flags &= ~f;
   2357     0    stevel 	}
   2358     0    stevel 	if (myioctl(ipfd, SIOCSIFFLAGS, &ifr) < 0) {
   2359     0    stevel 		error("Couldn't set IP interface flags: %m");
   2360     0    stevel 		return (0);
   2361     0    stevel 	}
   2362     0    stevel 	return (1);
   2363     0    stevel }
   2364     0    stevel 
   2365     0    stevel /*
   2366     0    stevel  * sifup()
   2367     0    stevel  *
   2368     0    stevel  * Config the interface up and enable IP packets to pass.
   2369     0    stevel  */
   2370     0    stevel /*ARGSUSED*/
   2371     0    stevel int
   2372     0    stevel sifup(u)
   2373     0    stevel 	int u;
   2374     0    stevel {
   2375     0    stevel 	if (if_is_up) {
   2376     0    stevel 		return (1);
   2377     0    stevel 	} else if (!IPCP_ENABLED) {
   2378     0    stevel 		warn("sifup called when IPCP is disabled");
   2379     0    stevel 		return (0);
   2380     0    stevel 	} else if (ipmuxid == -1) {
   2381     0    stevel 		warn("sifup called in wrong state");
   2382     0    stevel 		return (0);
   2383     0    stevel 	} else if (!siflags(IFF_UP, 1)) {
   2384     0    stevel 		error("Unable to mark the IP interface UP");
   2385     0    stevel 		return (0);
   2386     0    stevel 	}
   2387     0    stevel 	if_is_up = 1;
   2388     0    stevel 	return (1);
   2389     0    stevel }
   2390     0    stevel 
   2391     0    stevel /*
   2392     0    stevel  * sifdown()
   2393     0    stevel  *
   2394     0    stevel  * Config the interface down and disable IP.  Possibly called from die(),
   2395     0    stevel  * so there shouldn't be any call to die() here.
   2396     0    stevel  */
   2397     0    stevel /*ARGSUSED*/
   2398     0    stevel int
   2399     0    stevel sifdown(u)
   2400     0    stevel 	int u;
   2401     0    stevel {
   2402     0    stevel 	if (!IPCP_ENABLED) {
   2403     0    stevel 		warn("sifdown called when IPCP is disabled");
   2404     0    stevel 		return (0);
   2405     0    stevel 	} else if (!if_is_up || (ipmuxid == -1)) {
   2406     0    stevel 		return (1);
   2407     0    stevel 	} else if (!siflags(IFF_UP, 0)) {
   2408     0    stevel 		error("Unable to mark the IP interface DOWN");
   2409     0    stevel 		return (0);
   2410     0    stevel 	}
   2411     0    stevel 	if_is_up = 0;
   2412     0    stevel 	return (1);
   2413     0    stevel }
   2414     0    stevel 
   2415     0    stevel /*
   2416     0    stevel  * sifnpmode()
   2417     0    stevel  *
   2418     0    stevel  * Set the mode for handling packets for a given NP.  Not worried
   2419     0    stevel  * about performance here since this is done only rarely.
   2420     0    stevel  */
   2421     0    stevel /*ARGSUSED*/
   2422     0    stevel int
   2423     0    stevel sifnpmode(u, proto, mode)
   2424     0    stevel 	int u;
   2425     0    stevel 	int proto;
   2426     0    stevel 	enum NPmode mode;
   2427     0    stevel {
   2428     0    stevel 	uint32_t npi[2];
   2429     0    stevel 	const char *cp;
   2430     0    stevel 	static const struct npi_entry {
   2431     0    stevel 		enum NPmode ne_value;
   2432     0    stevel 		const char *ne_name;
   2433     0    stevel 	} npi_list[] = {
   2434     0    stevel 		{ NPMODE_PASS, "pass" },
   2435     0    stevel 		{ NPMODE_DROP, "drop" },
   2436     0    stevel 		{ NPMODE_ERROR, "error" },
   2437     0    stevel 		{ NPMODE_QUEUE, "queue" },
   2438     0    stevel 	};
   2439     0    stevel 	int i;
   2440     0    stevel 	char pname[32], mname[32];
   2441     0    stevel 
   2442     0    stevel 	npi[0] = proto;
   2443     0    stevel 	npi[1] = (uint32_t)mode;
   2444     0    stevel 
   2445     0    stevel 	cp = protocol_name(proto);
   2446     0    stevel 	if (cp == NULL)
   2447     0    stevel 		(void) slprintf(pname, sizeof (pname), "NP %04X", proto);
   2448     0    stevel 	else
   2449     0    stevel 		(void) strlcpy(pname, cp, sizeof (pname));
   2450     0    stevel 	for (i = 0; i < Dim(npi_list); i++)
   2451     0    stevel 		if (npi_list[i].ne_value == mode)
   2452     0    stevel 			break;
   2453     0    stevel 	if (i >= Dim(npi_list))
   2454     0    stevel 		(void) slprintf(mname, sizeof (mname), "mode %d", (int)mode);
   2455     0    stevel 	else
   2456     0    stevel 		(void) strlcpy(mname, npi_list[i].ne_name, sizeof (mname));
   2457     0    stevel 
   2458     0    stevel 	if ((proto == PPP_IP && !if_is_up) ||
   2459     0    stevel 	    (proto == PPP_IPV6 && !if6_is_up)) {
   2460     0    stevel 		dbglog("ignoring request to set %s to %s", pname, mname);
   2461     0    stevel 		return (1);
   2462     0    stevel 	}
   2463     0    stevel 	if (strioctl(pppfd, PPPIO_NPMODE, npi, sizeof (npi), 0) < 0) {
   2464     0    stevel 		error("unable to set %s to %s: %m", pname, mname);
   2465     0    stevel 		return (0);
   2466     0    stevel 	}
   2467     0    stevel 	return (1);
   2468     0    stevel }
   2469     0    stevel 
   2470     0    stevel /*
   2471     0    stevel  * sifmtu()
   2472     0    stevel  *
   2473     0    stevel  * Config the interface IP MTU.
   2474     0    stevel  */
   2475     0    stevel int
   2476     0    stevel sifmtu(mtu)
   2477     0    stevel 	int mtu;
   2478     0    stevel {
   2479     0    stevel 	struct ifreq ifr;
   2480     0    stevel 
   2481     0    stevel 	if (!IPCP_ENABLED || (ipmuxid == -1)) {
   2482     0    stevel 		return (0);
   2483     0    stevel 	}
   2484     0    stevel 	if (ipfd == -1 && open_ipfd() == -1)
   2485     0    stevel 		return (0);
   2486     0    stevel 	BZERO(&ifr, sizeof (ifr));
   2487     0    stevel 	(void) strlcpy(ifr.ifr_name, ifname, sizeof (ifr.ifr_name));
   2488     0    stevel 	ifr.ifr_metric = mtu;
   2489     0    stevel 	if (myioctl(ipfd, SIOCSIFMTU, &ifr) < 0) {
   2490     0    stevel 		error("Couldn't set IP MTU on %s to %d: %m", ifr.ifr_name,
   2491     0    stevel 		    mtu);
   2492     0    stevel 		return (0);
   2493     0    stevel 	}
   2494     0    stevel 	return (1);
   2495     0    stevel }
   2496     0    stevel 
   2497     0    stevel /*
   2498     0    stevel  * sifaddr()
   2499     0    stevel  *
   2500     0    stevel  * Config the interface IP addresses and netmask.
   2501     0    stevel  */
   2502     0    stevel /*ARGSUSED*/
   2503     0    stevel int
   2504     0    stevel sifaddr(u, o, h, m)
   2505     0    stevel 	int u;
   2506     0    stevel 	u_int32_t o;
   2507     0    stevel 	u_int32_t h;
   2508     0    stevel 	u_int32_t m;
   2509     0    stevel {
   2510     0    stevel 	struct ifreq ifr;
   2511     0    stevel 	struct sockaddr_in sin;
   2512     0    stevel 
   2513     0    stevel 	if (!IPCP_ENABLED || (ipmuxid == -1 && plumb_ipif(u) == 0)) {
   2514     0    stevel 		return (0);
   2515     0    stevel 	}
   2516     0    stevel 	if (ipfd == -1 && open_ipfd() == -1)
   2517     0    stevel 		return (0);
   2518     0    stevel 	/*
   2519     0    stevel 	 * Set the IP interface MTU.
   2520     0    stevel 	 */
   2521     0    stevel 	if (!sifmtu(link_mtu)) {
   2522     0    stevel 		return (0);
   2523     0    stevel 	}
   2524     0    stevel 	/*
   2525     0    stevel 	 * Set the IP interface local point-to-point address.
   2526     0    stevel 	 */
   2527     0    stevel 	BZERO(&sin, sizeof (sin));
   2528     0    stevel 	sin.sin_family = AF_INET;
   2529     0    stevel 	sin.sin_addr.s_addr = o;
   2530     0    stevel 
   2531     0    stevel 	BZERO(&ifr, sizeof (ifr));
   2532     0    stevel 	(void) strlcpy(ifr.ifr_name, ifname, sizeof (ifr.ifr_name));
   2533     0    stevel 	ifr.ifr_addr = *(struct sockaddr *)&sin;
   2534     0    stevel 	if (myioctl(ipfd, SIOCSIFADDR, &ifr) < 0) {
   2535     0    stevel 		error("Couldn't set local IP address (%s): %m", ifr.ifr_name);
   2536     0    stevel 		return (0);
   2537     0    stevel 	}
   2538     0    stevel 	/*
   2539     0    stevel 	 * Set the IP interface remote point-to-point address.
   2540     0    stevel 	 */
   2541     0    stevel 	sin.sin_addr.s_addr = h;
   2542     0    stevel 
   2543     0    stevel 	ifr.ifr_dstaddr = *(struct sockaddr *)&sin;
   2544     0    stevel 	if (myioctl(ipfd, SIOCSIFDSTADDR, &ifr) < 0) {
   2545     0    stevel 		error("Couldn't set remote IP address (%s): %m", ifr.ifr_name);
   2546     0    stevel 		return (0);
   2547     0    stevel 	}
   2548     0    stevel 	remote_addr = h;
   2549     0    stevel 	return (1);
   2550     0    stevel }
   2551     0    stevel 
   2552     0    stevel /*
   2553     0    stevel  * cifaddr()
   2554     0    stevel  *
   2555     0    stevel  * Clear the interface IP addresses.
   2556     0    stevel  */
   2557     0    stevel /*ARGSUSED*/
   2558     0    stevel int
   2559     0    stevel cifaddr(u, o, h)
   2560     0    stevel 	int u;
   2561     0    stevel 	u_int32_t o;
   2562     0    stevel 	u_int32_t h;
   2563     0    stevel {
   2564     0    stevel 	if (!IPCP_ENABLED) {
   2565     0    stevel 		return (0);
   2566     0    stevel 	}
   2567     0    stevel 	/*
   2568     0    stevel 	 * Most of the work is done in sifdown().
   2569     0    stevel 	 */
   2570     0    stevel 	remote_addr = 0;
   2571     0    stevel 	return (1);
   2572     0    stevel }
   2573     0    stevel 
   2574     0    stevel /*
   2575     0    stevel  * sifroute()
   2576     0    stevel  *
   2577     0    stevel  * Add or delete a route.
   2578     0    stevel  */
   2579     0    stevel /*ARGSUSED*/
   2580     0    stevel static int
   2581     0    stevel sifroute(int u, u_int32_t l, u_int32_t g, int add, const char *str)
   2582     0    stevel {
   2583     0    stevel 	struct sockaddr_in sin_dst, sin_gtw;
   2584     0    stevel 	struct rtentry rt;
   2585     0    stevel 
   2586     0    stevel 	if (!IPCP_ENABLED || (ipmuxid == -1)) {
   2587     0    stevel 		error("Can't %s route: IP is not enabled", str);
   2588     0    stevel 		return (0);
   2589     0    stevel 	}
   2590     0    stevel 	if (ipfd == -1 && open_ipfd() == -1)
   2591     0    stevel 		return (0);
   2592     0    stevel 
   2593     0    stevel 	BZERO(&sin_dst, sizeof (sin_dst));
   2594     0    stevel 	sin_dst.sin_family = AF_INET;
   2595     0    stevel 	sin_dst.sin_addr.s_addr = l;
   2596     0    stevel 
   2597     0    stevel 	BZERO(&sin_gtw, sizeof (sin_gtw));
   2598     0    stevel 	sin_gtw.sin_family = AF_INET;
   2599     0    stevel 	sin_gtw.sin_addr.s_addr = g;
   2600     0    stevel 
   2601     0    stevel 	BZERO(&rt, sizeof (rt));
   2602     0    stevel 	rt.rt_dst = *(struct sockaddr *)&sin_dst;
   2603     0    stevel 	rt.rt_gateway = *(struct sockaddr *)&sin_gtw;
   2604     0    stevel 	rt.rt_flags = (RTF_GATEWAY|RTF_STATIC);
   2605     0    stevel 
   2606     0    stevel 	if (myioctl(ipfd, (add ? SIOCADDRT : SIOCDELRT), &rt) < 0) {
   2607     0    stevel 		error("Can't %s route: %m", str);
   2608     0    stevel 		return (0);
   2609     0    stevel 	}
   2610     0    stevel 	return (1);
   2611     0    stevel }
   2612     0    stevel 
   2613     0    stevel /*
   2614     0    stevel  * sifdefaultroute()
   2615     0    stevel  *
   2616     0    stevel  * Assign a default route through the address given.
   2617     0    stevel  */
   2618     0    stevel /*ARGSUSED*/
   2619     0    stevel int
   2620     0    stevel sifdefaultroute(u, l, g)
   2621     0    stevel 	int u;
   2622     0    stevel 	u_int32_t l;
   2623     0    stevel 	u_int32_t g;
   2624     0    stevel {
   2625     0    stevel 	if (!sifroute(u, 0, g, 1, "add default")) {
   2626     0    stevel 		return (0);
   2627     0    stevel 	}
   2628     0    stevel 	default_route_gateway = g;
   2629     0    stevel 	return (1);
   2630     0    stevel }
   2631     0    stevel 
   2632     0    stevel /*
   2633     0    stevel  * cifdefaultroute()
   2634     0    stevel  *
   2635     0    stevel  * Delete a default route through the address given.
   2636     0    stevel  */
   2637     0    stevel /*ARGSUSED*/
   2638     0    stevel int
   2639     0    stevel cifdefaultroute(u, l, g)
   2640     0    stevel 	int u;
   2641     0    stevel 	u_int32_t l;
   2642     0    stevel 	u_int32_t g;
   2643     0    stevel {
   2644     0    stevel 	if (!sifroute(u, 0, g, 0, "delete default")) {
   2645     0    stevel 		return (0);
   2646     0    stevel 	}
   2647     0    stevel 	default_route_gateway = 0;
   2648     0    stevel 	return (1);
   2649     0    stevel }
   2650     0    stevel 
   2651     0    stevel /*
   2652     0    stevel  * sifproxyarp()
   2653     0    stevel  *
   2654     0    stevel  * Make a proxy ARP entry for the peer.
   2655     0    stevel  */
   2656     0    stevel /*ARGSUSED*/
   2657     0    stevel int
   2658     0    stevel sifproxyarp(unit, hisaddr, quietflag)
   2659     0    stevel 	int unit;
   2660     0    stevel 	u_int32_t hisaddr;
   2661     0    stevel 	int quietflag;
   2662     0    stevel {
   2663     0    stevel 	struct sockaddr_in sin;
   2664     0    stevel 	struct xarpreq arpreq;
   2665     0    stevel 	const uchar_t *cp;
   2666     0    stevel 	char *str = NULL;
   2667     0    stevel 
   2668     0    stevel 	if (!IPCP_ENABLED || (ipmuxid == -1)) {
   2669     0    stevel 		return (0);
   2670     0    stevel 	}
   2671     0    stevel 	if (ipfd == -1 && open_ipfd() == -1)
   2672     0    stevel 		return (0);
   2673     0    stevel 
   2674     0    stevel 	BZERO(&sin, sizeof (sin));
   2675     0    stevel 	sin.sin_family = AF_INET;
   2676     0    stevel 	sin.sin_addr.s_addr = hisaddr;
   2677     0    stevel 
   2678     0    stevel 	BZERO(&arpreq, sizeof (arpreq));
   2679     0    stevel 	if (!get_ether_addr(hisaddr, &arpreq.xarp_ha, quietflag)) {
   2680     0    stevel 		return (0);
   2681     0    stevel 	}
   2682     0    stevel 	BCOPY(&sin, &arpreq.xarp_pa, sizeof (sin));
   2683     0    stevel 	arpreq.xarp_flags = ATF_PERM | ATF_PUBL;
   2684     0    stevel 	arpreq.xarp_ha.sdl_family = AF_LINK;
   2685     0    stevel 
   2686     0    stevel 	if (myioctl(ipfd, SIOCSXARP, (caddr_t)&arpreq) < 0) {
   2687     0    stevel 		if (!quietflag)
   2688     0    stevel 			error("Couldn't set proxy ARP entry: %m");
   2689     0    stevel 		return (0);
   2690     0    stevel 	}
   2691     0    stevel 	cp = (const uchar_t *)LLADDR(&arpreq.xarp_ha);
   2692     0    stevel 	str = _link_ntoa(cp, str, arpreq.xarp_ha.sdl_alen, IFT_OTHER);
   2693     0    stevel 	if (str != NULL) {
   2694     0    stevel 		dbglog("established proxy ARP for %I using %s", hisaddr,
   2695     0    stevel 		    str);
   2696     0    stevel 		free(str);
   2697     0    stevel 	}
   2698     0    stevel 	proxy_arp_addr = hisaddr;
   2699     0    stevel 	return (1);
   2700     0    stevel }
   2701     0    stevel 
   2702     0    stevel /*
   2703     0    stevel  * cifproxyarp()
   2704     0    stevel  *
   2705     0    stevel  * Delete the proxy ARP entry for the peer.
   2706     0    stevel  */
   2707     0    stevel /*ARGSUSED*/
   2708     0    stevel int
   2709     0    stevel cifproxyarp(unit, hisaddr)
   2710     0    stevel 	int unit;
   2711     0    stevel 	u_int32_t hisaddr;
   2712     0    stevel {
   2713     0    stevel 	struct sockaddr_in sin;
   2714     0    stevel 	struct xarpreq arpreq;
   2715     0    stevel 
   2716     0    stevel 	if (!IPCP_ENABLED || (ipmuxid == -1)) {
   2717     0    stevel 		return (0);
   2718     0    stevel 	}
   2719     0    stevel 	if (ipfd == -1 && open_ipfd() == -1)
   2720     0    stevel 		return (0);
   2721     0    stevel 
   2722     0    stevel 	BZERO(&sin, sizeof (sin));
   2723     0    stevel 	sin.sin_family = AF_INET;
   2724     0    stevel 	sin.sin_addr.s_addr = hisaddr;
   2725     0    stevel 
   2726     0    stevel 	BZERO(&arpreq, sizeof (arpreq));
   2727     0    stevel 	BCOPY(&sin, &arpreq.xarp_pa, sizeof (sin));
   2728     0    stevel 	arpreq.xarp_ha.sdl_family = AF_LINK;
   2729     0    stevel 
   2730     0    stevel 	if (myioctl(ipfd, SIOCDXARP, (caddr_t)&arpreq) < 0) {
   2731     0    stevel 		error("Couldn't delete proxy ARP entry: %m");
   2732     0    stevel 		return (0);
   2733     0    stevel 	}
   2734     0    stevel 	proxy_arp_addr = 0;
   2735     0    stevel 	return (1);
   2736     0    stevel }
   2737     0    stevel 
   2738     0    stevel /*
   2739     0    stevel  * get_ether_addr()
   2740     0    stevel  *
   2741     0    stevel  * Get the hardware address of an interface on the the same subnet as
   2742     0    stevel  * ipaddr.  This routine uses old-style interfaces for intentional
   2743     0    stevel  * backward compatibility -- SIOCGLIF* isn't in older Solaris
   2744     0    stevel  * releases.
   2745     0    stevel  */
   2746     0    stevel static int
   2747     0    stevel get_ether_addr(u_int32_t ipaddr, struct sockaddr_dl *hwaddr, int quietflag)
   2748     0    stevel {
   2749     0    stevel 	struct ifreq *ifr, *ifend, ifreq;
   2750     0    stevel 	int nif, s, retv;
   2751     0    stevel 	struct ifconf ifc;
   2752     0    stevel 	u_int32_t ina, mask;
   2753     0    stevel 	struct xarpreq req;
   2754     0    stevel 	struct sockaddr_in sin;
   2755     0    stevel 
   2756     0    stevel 	if (ipfd == -1 && open_ipfd() == -1)
   2757     0    stevel 		return (0);
   2758     0    stevel 
   2759     0    stevel 	/*
   2760     0    stevel 	 * Scan through the system's network interfaces.
   2761     0    stevel 	 */
   2762     0    stevel 	if (myioctl(ipfd, SIOCGIFNUM, &nif) < 0) {
   2763     0    stevel 		nif = MAXIFS;
   2764     0    stevel 	}
   2765     0    stevel 	if (nif <= 0)
   2766     0    stevel 		return (0);
   2767     0    stevel 	ifc.ifc_len = nif * sizeof (struct ifreq);
   2768     0    stevel 	ifc.ifc_buf = (caddr_t)malloc(ifc.ifc_len);
   2769     0    stevel 	if (ifc.ifc_buf == NULL) {
   2770     0    stevel 		return (0);
   2771     0    stevel 	}
   2772     0    stevel 	if (myioctl(ipfd, SIOCGIFCONF, &ifc) < 0) {
   2773     0    stevel 		error("Couldn't get system interface list: %m");
   2774     0    stevel 		free(ifc.ifc_buf);
   2775     0    stevel 		return (0);
   2776     0    stevel 	}
   2777     0    stevel 	/* LINTED */
   2778     0    stevel 	ifend = (struct ifreq *)(ifc.ifc_buf + ifc.ifc_len);
   2779     0    stevel 	for (ifr = ifc.ifc_req; ifr < ifend; ++ifr) {
   2780     0    stevel 		if (ifr->ifr_addr.sa_family != AF_INET) {
   2781     0    stevel 			continue;
   2782     0    stevel 		}
   2783     0    stevel 		/*
   2784     0    stevel 		 * Check that the interface is up, and not
   2785     0    stevel 		 * point-to-point or loopback.
   2786     0    stevel 		 */
   2787     0    stevel 		(void) strlcpy(ifreq.ifr_name, ifr->ifr_name,
   2788  6631  ss150715 		    sizeof (ifreq.ifr_name));
   2789     0    stevel 		if (myioctl(ipfd, SIOCGIFFLAGS, &ifreq) < 0) {
   2790     0    stevel 			continue;
   2791     0    stevel 		}
   2792     0    stevel 		if ((ifreq.ifr_flags & (IFF_UP|IFF_BROADCAST|IFF_POINTOPOINT|
   2793     0    stevel 		    IFF_LOOPBACK|IFF_NOARP)) != (IFF_UP|IFF_BROADCAST)) {
   2794     0    stevel 			continue;
   2795     0    stevel 		}
   2796     0    stevel 		/*
   2797     0    stevel 		 * Get its netmask and check that it's on the right subnet.
   2798     0    stevel 		 */
   2799     0    stevel 		if (myioctl(ipfd, SIOCGIFNETMASK, &ifreq) < 0) {
   2800     0    stevel 			continue;
   2801     0    stevel 		}
   2802     0    stevel 		(void) memcpy(&sin, &ifr->ifr_addr, sizeof (sin));
   2803     0    stevel 		ina = sin.sin_addr.s_addr;
   2804     0    stevel 		(void) memcpy(&sin, &ifreq.ifr_addr, sizeof (sin));
   2805     0    stevel 		mask = sin.sin_addr.s_addr;
   2806     0    stevel 		if ((ipaddr & mask) == (ina & mask)) {
   2807     0    stevel 			break;
   2808     0    stevel 		}
   2809     0    stevel 	}
   2810     0    stevel 	if (ifr >= ifend) {
   2811     0    stevel 		if (!quietflag)
   2812     0    stevel 			warn("No suitable interface found for proxy ARP of %I",
   2813     0    stevel 			    ipaddr);
   2814     0    stevel 		free(ifc.ifc_buf);
   2815     0    stevel 		return (0);
   2816     0    stevel 	}
   2817     0    stevel 	info("found interface %s for proxy ARP of %I", ifr->ifr_name, ipaddr);
   2818     0    stevel 
   2819     0    stevel 	/*
   2820     0    stevel 	 * New way - get the address by doing an arp request.
   2821     0    stevel 	 */
   2822     0    stevel 	s = socket(AF_INET, SOCK_DGRAM, 0);
   2823     0    stevel 	if (s < 0) {
   2824     0    stevel 		error("get_ether_addr: error opening IP socket: %m");
   2825     0    stevel 		free(ifc.ifc_buf);
   2826     0    stevel 		return (0);
   2827     0    stevel 	}
   2828     0    stevel 	BZERO(&sin, sizeof (sin));
   2829     0    stevel 	sin.sin_family = AF_INET;
   2830     0    stevel 	sin.sin_addr.s_addr = ina;
   2831     0    stevel 
   2832     0    stevel 	BZERO(&req, sizeof (req));
   2833     0    stevel 	BCOPY(&sin, &req.xarp_pa, sizeof (sin));
   2834     0    stevel 	req.xarp_ha.sdl_family = AF_LINK;
   2835     0    stevel 
   2836     0    stevel 	if (myioctl(s, SIOCGXARP, &req) < 0) {
   2837     0    stevel 		error("Couldn't get ARP entry for %I: %m", ina);
   2838     0    stevel 		retv = 0;
   2839     0    stevel 	} else {
   2840     0    stevel 		(void) memcpy(hwaddr, &req.xarp_ha,
   2841     0    stevel 		    sizeof (struct sockaddr_dl));
   2842     0    stevel 		retv = 1;
   2843     0    stevel 	}
   2844     0    stevel 	(void) close(s);
   2845     0    stevel 	free(ifc.ifc_buf);
   2846     0    stevel 	return (retv);
   2847     0    stevel }
   2848     0    stevel 
   2849     0    stevel /*
   2850     0    stevel  * GetMask()
   2851     0    stevel  *
   2852     0    stevel  * Return mask (bogus, but needed for compatibility with other platforms).
   2853     0    stevel  */
   2854     0    stevel /*ARGSUSED*/
   2855     0    stevel u_int32_t
   2856     0    stevel GetMask(addr)
   2857     0    stevel 	u_int32_t addr;
   2858     0    stevel {
   2859     0    stevel 	return (0xffffffffUL);
   2860     0    stevel }
   2861     0    stevel 
   2862     0    stevel /*
   2863     0    stevel  * logwtmp()
   2864     0    stevel  *
   2865     0    stevel  * Write an accounting record to the /var/adm/wtmp file.
   2866     0    stevel  */
   2867     0    stevel /*ARGSUSED*/
   2868     0    stevel void
   2869     0    stevel logwtmp(line, name, host)
   2870     0    stevel 	const char *line;
   2871     0    stevel 	const char *name;
   2872     0    stevel 	const char *host;
   2873     0    stevel {
   2874     0    stevel 	static struct utmpx utmpx;
   2875     0    stevel 
   2876     0    stevel 	if (name[0] != '\0') {
   2877     0    stevel 		/*
   2878     0    stevel 		 * logging in
   2879     0    stevel 		 */
   2880     0    stevel 		(void) strncpy(utmpx.ut_user, name, sizeof (utmpx.ut_user));
   2881     0    stevel 		(void) strncpy(utmpx.ut_id, ifname, sizeof (utmpx.ut_id));
   2882     0    stevel 		(void) strncpy(utmpx.ut_line, line, sizeof (utmpx.ut_line));
   2883     0    stevel 
   2884     0    stevel 		utmpx.ut_pid = getpid();
   2885     0    stevel 		utmpx.ut_type = USER_PROCESS;
   2886     0    stevel 	} else {
   2887     0    stevel 		utmpx.ut_type = DEAD_PROCESS;
   2888     0    stevel 	}
   2889     0    stevel 	(void) gettimeofday(&utmpx.ut_tv, NULL);
   2890     0    stevel 	updwtmpx("/var/adm/wtmpx", &utmpx);
   2891     0    stevel }
   2892     0    stevel 
   2893     0    stevel /*
   2894     0    stevel  * get_host_seed()
   2895     0    stevel  *
   2896     0    stevel  * Return the serial number of this machine.
   2897     0    stevel  */
   2898     0    stevel int
   2899     0    stevel get_host_seed()
   2900     0    stevel {
   2901     0    stevel 	char buf[32];
   2902     0    stevel 
   2903     0    stevel 	if (sysinfo(SI_HW_SERIAL, buf, sizeof (buf)) < 0) {
   2904     0    stevel 		error("sysinfo: %m");
   2905     0    stevel 		return (0);
   2906     0    stevel 	}
   2907     0    stevel 	return ((int)strtoul(buf, NULL, 16));
   2908     0    stevel }
   2909     0    stevel 
   2910     0    stevel /*
   2911     0    stevel  * strioctl()
   2912     0    stevel  *
   2913     0    stevel  * Wrapper for STREAMS I_STR ioctl.  Masks out EINTR from caller.
   2914     0    stevel  */
   2915     0    stevel static int
   2916     0    stevel strioctl(int fd, int cmd, void *ptr, int ilen, int olen)
   2917     0    stevel {
   2918     0    stevel 	struct strioctl	str;
   2919     0    stevel 
   2920     0    stevel 	str.ic_cmd = cmd;
   2921     0    stevel 	str.ic_timout = PPPSTRTIMOUT;
   2922     0    stevel 	str.ic_len = ilen;
   2923     0    stevel 	str.ic_dp = ptr;
   2924     0    stevel 
   2925     0    stevel 	if (myioctl(fd, I_STR, &str) == -1) {
   2926     0    stevel 		return (-1);
   2927     0    stevel 	}
   2928     0    stevel 	if (str.ic_len != olen) {
   2929     0    stevel 		dbglog("strioctl: expected %d bytes, got %d for cmd %x\n",
   2930     0    stevel 		    olen, str.ic_len, cmd);
   2931     0    stevel 	}
   2932     0    stevel 	return (0);
   2933     0    stevel }
   2934     0    stevel 
   2935     0    stevel /*
   2936     0    stevel  * have_route_to()
   2937     0    stevel  *
   2938     0    stevel  * Determine if the system has a route to the specified IP address.
   2939     0    stevel  * Returns 0 if not, 1 if so, -1 if we can't tell. `addr' is in network
   2940     0    stevel  * byte order. For demand mode to work properly, we have to ignore routes
   2941     0    stevel  * through our own interface. XXX Would be nice to use routing socket.
   2942     0    stevel  */
   2943     0    stevel int
   2944     0    stevel have_route_to(addr)
   2945     0    stevel 	u_int32_t addr;
   2946     0    stevel {
   2947     0    stevel 	int r, flags, i;
   2948     0    stevel 	struct {
   2949     0    stevel 		struct T_optmgmt_req req;
   2950     0    stevel 		struct opthdr hdr;
   2951     0    stevel 	} req;
   2952     0    stevel 	union {
   2953     0    stevel 		struct T_optmgmt_ack ack;
   2954     0    stevel 		unsigned char space[64];
   2955     0    stevel 	} ack;
   2956     0    stevel 	struct opthdr *rh;
   2957     0    stevel 	struct strbuf cbuf, dbuf;
   2958     0    stevel 	int nroutes;
   2959     0    stevel 	mib2_ipRouteEntry_t routes[8];
   2960     0    stevel 	mib2_ipRouteEntry_t *rp;
   2961     0    stevel 
   2962     0    stevel 	if (ipfd == -1 && open_ipfd() == -1)
   2963     0    stevel 		return (0);
   2964     0    stevel 
   2965     0    stevel 	req.req.PRIM_type = T_OPTMGMT_REQ;
   2966     0    stevel 	req.req.OPT_offset = (caddr_t)&req.hdr - (caddr_t)&req;
   2967     0    stevel 	req.req.OPT_length = sizeof (req.hdr);
   2968     0    stevel #ifdef T_CURRENT
   2969     0    stevel 	req.req.MGMT_flags = T_CURRENT;
   2970     0    stevel #else
   2971     0    stevel 	/* Old-style */
   2972     0    stevel 	req.req.MGMT_flags = T_CHECK;
   2973     0    stevel #endif
   2974     0    stevel 
   2975     0    stevel 	req.hdr.level = MIB2_IP;
   2976     0    stevel 	req.hdr.name = 0;
   2977     0    stevel 	req.hdr.len = 0;
   2978     0    stevel 
   2979     0    stevel 	cbuf.buf = (caddr_t)&req;
   2980     0    stevel 	cbuf.len = sizeof (req);
   2981     0    stevel 
   2982     0    stevel 	if (putmsg(ipfd, &cbuf, NULL, 0) == -1) {
   2983     0    stevel 		warn("have_route_to: putmsg: %m");
   2984     0    stevel 		return (-1);
   2985     0    stevel 	}
   2986     0    stevel 
   2987     0    stevel 	for (;;) {
   2988     0    stevel 		cbuf.buf = (caddr_t)&ack;
   2989     0    stevel 		cbuf.maxlen = sizeof (ack);
   2990     0    stevel 		dbuf.buf = (caddr_t)routes;
   2991     0    stevel 		dbuf.maxlen = sizeof (routes);
   2992     0    stevel 		flags = 0;
   2993     0    stevel 		r = getmsg(ipfd, &cbuf, &dbuf, &flags);
   2994     0    stevel 		if (r == -1) {
   2995     0    stevel 			warn("have_route_to: getmsg: %m");
   2996     0    stevel 			return (-1);
   2997     0    stevel 		}
   2998     0    stevel 
   2999     0    stevel 		if (cbuf.len < sizeof (struct T_optmgmt_ack) ||
   3000     0    stevel 		    ack.ack.PRIM_type != T_OPTMGMT_ACK ||
   3001     0    stevel 		    ack.ack.MGMT_flags != T_SUCCESS ||
   3002     0    stevel 		    ack.ack.OPT_length < sizeof (struct opthdr)) {
   3003     0    stevel 			dbglog("have_route_to: bad message len=%d prim=%d",
   3004     0    stevel 			    cbuf.len, ack.ack.PRIM_type);
   3005     0    stevel 			return (-1);
   3006     0    stevel 		}
   3007     0    stevel 		/* LINTED */
   3008     0    stevel 		rh = (struct opthdr *)((caddr_t)&ack + ack.ack.OPT_offset);
   3009     0    stevel 		if (rh->level == 0 && rh->name == 0) {
   3010     0    stevel 			break;
   3011     0    stevel 		}
   3012     0    stevel 		if (rh->level != MIB2_IP || rh->name != MIB2_IP_21) {
   3013     0    stevel 			while (r == MOREDATA) {
   3014     0    stevel 				r = getmsg(ipfd, NULL, &dbuf, &flags);
   3015     0    stevel 			}
   3016     0    stevel 			continue;
   3017     0    stevel 		}
   3018     0    stevel 
   3019     0    stevel 		/*
   3020     0    stevel 		 * Note that we have to skip routes to our own
   3021     0    stevel 		 * interface in order for demand dial to work.
   3022     0    stevel 		 *
   3023     0    stevel 		 * XXX awful hack here.  We don't know our own
   3024     0    stevel 		 * ifIndex, so we can't check ipRouteIfIndex here.
   3025     0    stevel 		 * Instead, we check the next hop address.
   3026     0    stevel 		 */
   3027     0    stevel 		for (;;) {
   3028     0    stevel 			nroutes = dbuf.len / sizeof (mib2_ipRouteEntry_t);
   3029     0    stevel 			for (rp = routes, i = 0; i < nroutes; ++i, ++rp) {
   3030     0    stevel 				if (rp->ipRouteNextHop != remote_addr &&
   3031     0    stevel 				    ((addr ^ rp->ipRouteDest) &
   3032     0    stevel 					rp->ipRouteMask) == 0) {
   3033     0    stevel 					dbglog("have route to %I/%I via %I",
   3034     0    stevel 					    rp->ipRouteDest,
   3035     0    stevel 					    rp->ipRouteMask,
   3036     0    stevel 					    rp->ipRouteNextHop);
   3037     0    stevel 					return (1);
   3038     0    stevel 				}
   3039     0    stevel 			}
   3040     0    stevel 			if (r == 0) {
   3041     0    stevel 				break;
   3042     0    stevel 			}
   3043     0    stevel 			r = getmsg(ipfd, NULL, &dbuf, &flags);
   3044     0    stevel 		}
   3045     0    stevel 	}
   3046     0    stevel 	return (0);
   3047     0    stevel }
   3048     0    stevel 
   3049     0    stevel /*
   3050     0    stevel  * get_pty()
   3051     0    stevel  *
   3052     0    stevel  * Get a pty master/slave pair and chown the slave side to the uid given.
   3053     0    stevel  * Assumes slave_name points to MAXPATHLEN bytes of space.
   3054     0    stevel  */
   3055     0    stevel int
   3056     0    stevel get_pty(master_fdp, slave_fdp, slave_name, uid)
   3057     0    stevel 	int *master_fdp;
   3058     0    stevel 	int *slave_fdp;
   3059     0    stevel 	char *slave_name;
   3060     0    stevel 	int uid;
   3061     0    stevel {
   3062     0    stevel 	int mfd;
   3063     0    stevel 	int sfd;
   3064     0    stevel 	char *pty_name;
   3065     0    stevel 
   3066     0    stevel 	mfd = open("/dev/ptmx", O_NOCTTY | O_RDWR);
   3067     0    stevel 	if (mfd < 0) {
   3068     0    stevel 		error("Couldn't open pty master: %m");
   3069     0    stevel 		return (0);
   3070     0    stevel 	}
   3071     0    stevel 	pty_name = ptsname(mfd);
   3072     0    stevel 	if (pty_name == NULL) {
   3073     0    stevel 		dbglog("Didn't get pty slave name on first try; sleeping.");
   3074     0    stevel 		/* In case "grow" operation is in progress; try again. */
   3075     0    stevel 		(void) sleep(1);
   3076     0    stevel 		pty_name = ptsname(mfd);
   3077     0    stevel 	}
   3078     0    stevel 	if (pty_name == NULL) {
   3079     0    stevel 		error("Couldn't get name of pty slave");
   3080     0    stevel 		(void) close(mfd);
   3081     0    stevel 		return (0);
   3082     0    stevel 	}
   3083     0    stevel 	if (chown(pty_name, uid, -1) < 0) {
   3084     0    stevel 		warn("Couldn't change owner of pty slave: %m");
   3085     0    stevel 	}
   3086     0    stevel 	if (chmod(pty_name, S_IRUSR | S_IWUSR) < 0) {
   3087     0    stevel 		warn("Couldn't change permissions on pty slave: %m");
   3088     0    stevel 	}
   3089     0    stevel 	if (unlockpt(mfd) < 0) {
   3090     0    stevel 		warn("Couldn't unlock pty slave: %m");
   3091     0    stevel 	}
   3092     0    stevel 	sfd = open(pty_name, O_RDWR);
   3093     0    stevel 	if (sfd < 0) {
   3094     0    stevel 		error("Couldn't open pty slave %s: %m", pty_name);
   3095     0    stevel 		(void) close(mfd);
   3096     0    stevel 		return (0);
   3097     0    stevel 	}
   3098     0    stevel 	if (myioctl(sfd, I_PUSH, "ptem") < 0) {
   3099     0    stevel 		warn("Couldn't push ptem module on pty slave: %m");
   3100     0    stevel 	}
   3101     0    stevel 	dbglog("Using %s; master fd %d, slave fd %d", pty_name, mfd, sfd);
   3102     0    stevel 
   3103     0    stevel 	(void) strlcpy(slave_name, pty_name, MAXPATHLEN);
   3104     0    stevel 
   3105     0    stevel 	*master_fdp = mfd;
   3106     0    stevel 	*slave_fdp = sfd;
   3107     0    stevel 
   3108     0    stevel 	return (1);
   3109     0    stevel }
   3110     0    stevel 
   3111     0    stevel #ifdef INET6
   3112     0    stevel static int
   3113     0    stevel open_udp6fd(void)
   3114     0    stevel {
   3115     0    stevel 	int udp6fd;
   3116     0    stevel 
   3117     0    stevel 	udp6fd = open(UDP6_DEV_NAME, O_RDWR | O_NONBLOCK, 0);
   3118     0    stevel 	if (udp6fd < 0) {
   3119     0    stevel 		error("Couldn't open UDPv6 device (%s): %m", UDP6_DEV_NAME);
   3120     0    stevel 	}
   3121     0    stevel 	return (udp6fd);
   3122     0    stevel }
   3123     0    stevel 
   3124     0    stevel /*
   3125     0    stevel  * plumb_ip6if()
   3126     0    stevel  *
   3127     0    stevel  * Perform IPv6 interface plumbing.
   3128     0    stevel  */
   3129     0    stevel /*ARGSUSED*/
   3130     0    stevel static int
   3131     0    stevel plumb_ip6if(int unit)
   3132     0    stevel {
   3133     0    stevel 	int udp6fd = -1, tmpfd;
   3134     0    stevel 	uint32_t x;
   3135     0    stevel 	struct lifreq lifr;
   3136     0    stevel 
   3137     0    stevel 	if (!IPV6CP_ENABLED || (ifunit == -1) || (pppfd == -1)) {
   3138     0    stevel 		return (0);
   3139     0    stevel 	}
   3140     0    stevel 	if (plumbed)
   3141     0    stevel 		return (1);
   3142     0    stevel 	if (ip6fd == -1 && open_ip6fd() == -1)
   3143     0    stevel 		return (0);
   3144     0    stevel 	if (use_plink && (udp6fd = open_udp6fd()) == -1)
   3145     0    stevel 		return (0);
   3146     0    stevel 	tmpfd = open(drvnam, O_RDWR | O_NONBLOCK, 0);
   3147     0    stevel 	if (tmpfd < 0) {
   3148     0    stevel 		error("Couldn't open PPP device (%s): %m", drvnam);
   3149     0    stevel 		if (udp6fd != -1)
   3150     0    stevel 			(void) close(udp6fd);
   3151     0    stevel 		return (0);
   3152     0    stevel 	}
   3153     0    stevel 	if (kdebugflag & 1) {
   3154     0    stevel 		x = PPPDBG_LOG + PPPDBG_DRIVER;
   3155     0    stevel 		if (strioctl(tmpfd, PPPIO_DEBUG, &x, sizeof (x), 0) < 0) {
   3156     0    stevel 			warn("PPPIO_DEBUG ioctl for mux failed: %m");
   3157     0    stevel 		}
   3158     0    stevel 	}
   3159     0    stevel 	if (myioctl(tmpfd, I_PUSH, IP_MOD_NAME) < 0) {
   3160     0    stevel 		error("Couldn't push IP module(%s): %m", IP_MOD_NAME);
   3161     0    stevel 		goto err_ret;
   3162     0    stevel 	}
   3163     0    stevel 	/*
   3164     0    stevel 	 * Sets interface ppa and flags (refer to comments in plumb_ipif for
   3165     0    stevel 	 * the IF_UNITSEL ioctl). In addition, the IFF_IPV6 bit must be set in
   3166     0    stevel 	 * order to declare this as an IPv6 interface.
   3167     0    stevel 	 */
   3168     0    stevel 	BZERO(&lifr, sizeof (lifr));
   3169     0    stevel 	if (myioctl(tmpfd, SIOCGLIFFLAGS, &lifr) < 0) {
   3170     0    stevel 		error("Couldn't get IPv6 interface flags: %m");
   3171     0    stevel 		goto err_ret;
   3172     0    stevel 	}
   3173     0    stevel 	lifr.lifr_flags |= IFF_IPV6;
   3174     0    stevel 	lifr.lifr_flags &= ~(IFF_BROADCAST | IFF_IPV4);
   3175     0    stevel 	lifr.lifr_ppa = ifunit;
   3176     0    stevel 	(void) strlcpy(lifr.lifr_name, ifname, sizeof (lifr.lifr_name));
   3177     0    stevel 	if (myioctl(tmpfd, SIOCSLIFNAME, &lifr) < 0) {
   3178     0    stevel 		error("Can't set ifname for unit %d: %m", ifunit);
   3179     0    stevel 		goto err_ret;
   3180     0    stevel 	}
   3181     0    stevel 	if (use_plink) {
   3182     0    stevel 		ip6muxid = myioctl(udp6fd, I_PLINK, (void *)tmpfd);
   3183     0    stevel 		if (ip6muxid < 0) {
   3184     0    stevel 			error("Can't I_PLINK PPP device to IPv6: %m");
   3185     0    stevel 			goto err_ret;
   3186     0    stevel 		}
   3187     0    stevel 	} else {
   3188     0    stevel 		ip6muxid = myioctl(ip6fd, I_LINK, (void *)tmpfd);
   3189     0    stevel 		if (ip6muxid < 0) {
   3190     0    stevel 			error("Can't I_LINK PPP device to IPv6: %m");
   3191     0    stevel 			goto err_ret;
   3192     0    stevel 		}
   3193     0    stevel 	}
   3194     0    stevel 	lifr.lifr_ip_muxid = ip6muxid;
   3195     0    stevel 	lifr.lifr_arp_muxid = -1;
   3196     0    stevel 	if (myioctl(ip6fd, SIOCSLIFMUXID, (caddr_t)&lifr) < 0) {
   3197     0    stevel 		error("Can't set mux ID:  SIOCSLIFMUXID: %m");
   3198     0    stevel 		goto err_ret;
   3199     0    stevel 	}
   3200     0    stevel 	(void) close(tmpfd);
   3201     0    stevel 	if (udp6fd != -1)
   3202     0    stevel 		(void) close(udp6fd);
   3203     0    stevel 	return (1);
   3204     0    stevel 
   3205     0    stevel err_ret:
   3206     0    stevel 	(void) close(tmpfd);
   3207     0    stevel 	if (udp6fd != -1)
   3208     0    stevel 		(void) close(udp6fd);
   3209     0    stevel 	return (0);
   3210     0    stevel }