17c478bd9Sstevel@tonic-gate /*
27c478bd9Sstevel@tonic-gate  * System-dependent procedures for pppd under Solaris 2.x (SunOS 5.x).
37c478bd9Sstevel@tonic-gate  *
4de81e71eSTim Marsland  * Copyright 2009 Sun Microsystems, Inc.  All rights reserved.
57c478bd9Sstevel@tonic-gate  * Use is subject to license terms.
67c478bd9Sstevel@tonic-gate  *
77c478bd9Sstevel@tonic-gate  * Permission to use, copy, modify, and distribute this software and its
87c478bd9Sstevel@tonic-gate  * documentation is hereby granted, provided that the above copyright
97c478bd9Sstevel@tonic-gate  * notice appears in all copies.
107c478bd9Sstevel@tonic-gate  *
117c478bd9Sstevel@tonic-gate  * SUN MAKES NO REPRESENTATION OR WARRANTIES ABOUT THE SUITABILITY OF
127c478bd9Sstevel@tonic-gate  * THE SOFTWARE, EITHER EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED
137c478bd9Sstevel@tonic-gate  * TO THE IMPLIED WARRANTIES OF MERCHANTABILITY, FITNESS FOR A
147c478bd9Sstevel@tonic-gate  * PARTICULAR PURPOSE, OR NON-INFRINGEMENT.  SUN SHALL NOT BE LIABLE FOR
157c478bd9Sstevel@tonic-gate  * ANY DAMAGES SUFFERED BY LICENSEE AS A RESULT OF USING, MODIFYING OR
167c478bd9Sstevel@tonic-gate  * DISTRIBUTING THIS SOFTWARE OR ITS DERIVATIVES
177c478bd9Sstevel@tonic-gate  *
187c478bd9Sstevel@tonic-gate  * Copyright (c) 1994 The Australian National University.
197c478bd9Sstevel@tonic-gate  * All rights reserved.
207c478bd9Sstevel@tonic-gate  *
217c478bd9Sstevel@tonic-gate  * Permission to use, copy, modify, and distribute this software and its
227c478bd9Sstevel@tonic-gate  * documentation is hereby granted, provided that the above copyright
237c478bd9Sstevel@tonic-gate  * notice appears in all copies.  This software is provided without any
247c478bd9Sstevel@tonic-gate  * warranty, express or implied. The Australian National University
257c478bd9Sstevel@tonic-gate  * makes no representations about the suitability of this software for
267c478bd9Sstevel@tonic-gate  * any purpose.
277c478bd9Sstevel@tonic-gate  *
287c478bd9Sstevel@tonic-gate  * IN NO EVENT SHALL THE AUSTRALIAN NATIONAL UNIVERSITY BE LIABLE TO ANY
297c478bd9Sstevel@tonic-gate  * PARTY FOR DIRECT, INDIRECT, SPECIAL, INCIDENTAL, OR CONSEQUENTIAL DAMAGES
307c478bd9Sstevel@tonic-gate  * ARISING OUT OF THE USE OF THIS SOFTWARE AND ITS DOCUMENTATION, EVEN IF
317c478bd9Sstevel@tonic-gate  * THE AUSTRALIAN NATIONAL UNIVERSITY HAVE BEEN ADVISED OF THE POSSIBILITY
327c478bd9Sstevel@tonic-gate  * OF SUCH DAMAGE.
337c478bd9Sstevel@tonic-gate  *
347c478bd9Sstevel@tonic-gate  * THE AUSTRALIAN NATIONAL UNIVERSITY SPECIFICALLY DISCLAIMS ANY WARRANTIES,
357c478bd9Sstevel@tonic-gate  * INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY
367c478bd9Sstevel@tonic-gate  * AND FITNESS FOR A PARTICULAR PURPOSE.  THE SOFTWARE PROVIDED HEREUNDER IS
377c478bd9Sstevel@tonic-gate  * ON AN "AS IS" BASIS, AND THE AUSTRALIAN NATIONAL UNIVERSITY HAS NO
387c478bd9Sstevel@tonic-gate  * OBLIGATION TO PROVIDE MAINTENANCE, SUPPORT, UPDATES, ENHANCEMENTS,
397c478bd9Sstevel@tonic-gate  * OR MODIFICATIONS.
407c478bd9Sstevel@tonic-gate  */
417c478bd9Sstevel@tonic-gate 
427c478bd9Sstevel@tonic-gate #include <limits.h>
437c478bd9Sstevel@tonic-gate #include <stdio.h>
447c478bd9Sstevel@tonic-gate #include <stddef.h>
457c478bd9Sstevel@tonic-gate #include <stdlib.h>
467c478bd9Sstevel@tonic-gate #include <ctype.h>
477c478bd9Sstevel@tonic-gate #include <errno.h>
487c478bd9Sstevel@tonic-gate #include <fcntl.h>
497c478bd9Sstevel@tonic-gate #include <unistd.h>
507c478bd9Sstevel@tonic-gate #include <netdb.h>
517c478bd9Sstevel@tonic-gate #include <termios.h>
527c478bd9Sstevel@tonic-gate #include <signal.h>
537c478bd9Sstevel@tonic-gate #include <string.h>
547c478bd9Sstevel@tonic-gate #include <stropts.h>
557c478bd9Sstevel@tonic-gate #include <utmpx.h>
567c478bd9Sstevel@tonic-gate #include <sys/types.h>
577c478bd9Sstevel@tonic-gate #include <sys/ioccom.h>
587c478bd9Sstevel@tonic-gate #include <sys/stream.h>
597c478bd9Sstevel@tonic-gate #include <sys/stropts.h>
607c478bd9Sstevel@tonic-gate #include <sys/socket.h>
617c478bd9Sstevel@tonic-gate #include <sys/sockio.h>
627c478bd9Sstevel@tonic-gate #include <sys/sysmacros.h>
637c478bd9Sstevel@tonic-gate #include <sys/systeminfo.h>
647c478bd9Sstevel@tonic-gate #include <sys/stat.h>
657c478bd9Sstevel@tonic-gate #include <net/if.h>
667c478bd9Sstevel@tonic-gate #include <net/if_arp.h>
677c478bd9Sstevel@tonic-gate #include <net/route.h>
687c478bd9Sstevel@tonic-gate #include <net/ppp_defs.h>
697c478bd9Sstevel@tonic-gate #include <net/pppio.h>
707c478bd9Sstevel@tonic-gate #include <net/if_types.h>
717c478bd9Sstevel@tonic-gate #include <net/if_dl.h>
727c478bd9Sstevel@tonic-gate #include <netinet/in.h>
737c478bd9Sstevel@tonic-gate #include <sys/tihdr.h>
747c478bd9Sstevel@tonic-gate #include <inet/mib2.h>
75ff550d0eSmasputra #include <inet/ip.h>
767c478bd9Sstevel@tonic-gate #include <sys/ethernet.h>
777c478bd9Sstevel@tonic-gate #include <sys/ser_sync.h>
78fb60e41dSss #include <libdlpi.h>
79f53eecf5SJames Carlson #include <arpa/inet.h>
807c478bd9Sstevel@tonic-gate 
817c478bd9Sstevel@tonic-gate #include "pppd.h"
827c478bd9Sstevel@tonic-gate #include "fsm.h"
837c478bd9Sstevel@tonic-gate #include "lcp.h"
847c478bd9Sstevel@tonic-gate #include "ipcp.h"
857c478bd9Sstevel@tonic-gate #ifdef INET6
867c478bd9Sstevel@tonic-gate #include "ipv6cp.h"
877c478bd9Sstevel@tonic-gate #endif /* INET6 */
887c478bd9Sstevel@tonic-gate #include "ccp.h"
897c478bd9Sstevel@tonic-gate 
907c478bd9Sstevel@tonic-gate #define	PPPSTRTIMOUT	1	/* Timeout in seconds for ioctl */
917c478bd9Sstevel@tonic-gate #define	MAX_POLLFDS	32
927c478bd9Sstevel@tonic-gate #define	NMODULES	32
937c478bd9Sstevel@tonic-gate 
947c478bd9Sstevel@tonic-gate #ifndef MAXIFS
957c478bd9Sstevel@tonic-gate #define	MAXIFS		256
967c478bd9Sstevel@tonic-gate #endif /* MAXIFS */
977c478bd9Sstevel@tonic-gate 
987c478bd9Sstevel@tonic-gate #ifdef INET6
997c478bd9Sstevel@tonic-gate #define	_IN6_LLX_FROM_EUI64(l, s, eui64, as, len)	\
1007c478bd9Sstevel@tonic-gate 	(s->sin6_addr.s6_addr32[0] = htonl(as),		\
1017c478bd9Sstevel@tonic-gate 	eui64_copy(eui64, s->sin6_addr.s6_addr32[2]),	\
1027c478bd9Sstevel@tonic-gate 	s->sin6_family = AF_INET6,			\
1037c478bd9Sstevel@tonic-gate 	l.lifr_addr.ss_family = AF_INET6,		\
1047c478bd9Sstevel@tonic-gate 	l.lifr_addrlen = len,				\
1057c478bd9Sstevel@tonic-gate 	l.lifr_addr = laddr)
1067c478bd9Sstevel@tonic-gate 
1077c478bd9Sstevel@tonic-gate /*
1087c478bd9Sstevel@tonic-gate  * Generate a link-local address with an interface-id based on the given
1097c478bd9Sstevel@tonic-gate  * EUI64 identifier.  Note that the len field is unused by SIOCSLIFADDR.
1107c478bd9Sstevel@tonic-gate  */
1117c478bd9Sstevel@tonic-gate #define	IN6_LLADDR_FROM_EUI64(l, s, eui64)		\
1127c478bd9Sstevel@tonic-gate 	_IN6_LLX_FROM_EUI64(l, s, eui64, 0xfe800000, 0)
1137c478bd9Sstevel@tonic-gate 
1147c478bd9Sstevel@tonic-gate /*
1157c478bd9Sstevel@tonic-gate  * Generate an EUI64 based interface-id for use by stateless address
1167c478bd9Sstevel@tonic-gate  * autoconfiguration.  These are required to be 64 bits long as defined in
1177c478bd9Sstevel@tonic-gate  * the "Interface Identifiers" section of the IPv6 Addressing Architecture
1187c478bd9Sstevel@tonic-gate  * (RFC3513).
1197c478bd9Sstevel@tonic-gate  */
1207c478bd9Sstevel@tonic-gate #define	IN6_LLTOKEN_FROM_EUI64(l, s, eui64) \
1217c478bd9Sstevel@tonic-gate 	_IN6_LLX_FROM_EUI64(l, s, eui64, 0, 64)
1227c478bd9Sstevel@tonic-gate #endif /* INET6 */
1237c478bd9Sstevel@tonic-gate 
1247c478bd9Sstevel@tonic-gate #define	IPCP_ENABLED	ipcp_protent.enabled_flag
1257c478bd9Sstevel@tonic-gate #ifdef INET6
1267c478bd9Sstevel@tonic-gate #define	IPV6CP_ENABLED	ipv6cp_protent.enabled_flag
1277c478bd9Sstevel@tonic-gate #endif /* INET6 */
1287c478bd9Sstevel@tonic-gate 
1297c478bd9Sstevel@tonic-gate /* For plug-in usage. */
1307c478bd9Sstevel@tonic-gate int (*sys_read_packet_hook) __P((int retv, struct strbuf *ctrl,
1317c478bd9Sstevel@tonic-gate     struct strbuf *data, int flags)) = NULL;
1327c478bd9Sstevel@tonic-gate bool already_ppp = 0;			/* Already in PPP mode */
1337c478bd9Sstevel@tonic-gate 
1347c478bd9Sstevel@tonic-gate static int pppfd = -1;			/* ppp driver fd */
1357c478bd9Sstevel@tonic-gate static int fdmuxid = -1;		/* driver mux fd */
1367c478bd9Sstevel@tonic-gate static int ipfd = -1;			/* IPv4 fd */
1377c478bd9Sstevel@tonic-gate static int ipmuxid = -1;		/* IPv4 mux fd */
1387c478bd9Sstevel@tonic-gate static int ip6fd = -1;			/* IPv6 fd */
1397c478bd9Sstevel@tonic-gate static int ip6muxid = -1;		/* IPv6 mux fd */
1407c478bd9Sstevel@tonic-gate static bool if6_is_up = 0;		/* IPv6 if marked as up */
1417c478bd9Sstevel@tonic-gate static bool if_is_up = 0;		/* IPv4 if marked as up */
1427c478bd9Sstevel@tonic-gate static bool restore_term = 0;		/* Restore TTY after closing link */
1437c478bd9Sstevel@tonic-gate static struct termios inittermios;	/* TTY settings */
1447c478bd9Sstevel@tonic-gate static struct winsize wsinfo;		/* Initial window size info */
1457c478bd9Sstevel@tonic-gate static pid_t tty_sid;			/* original sess ID for term */
1467c478bd9Sstevel@tonic-gate static struct pollfd pollfds[MAX_POLLFDS]; /* array of polled fd */
1477c478bd9Sstevel@tonic-gate static int n_pollfds = 0;		/* total count of polled fd */
1487c478bd9Sstevel@tonic-gate static int link_mtu;			/* link Maximum Transmit Unit */
1497c478bd9Sstevel@tonic-gate static int tty_nmodules;		/* total count of TTY modules used */
1507c478bd9Sstevel@tonic-gate static char tty_modules[NMODULES][FMNAMESZ+1];
1517c478bd9Sstevel@tonic-gate 					/* array of TTY modules used */
1527c478bd9Sstevel@tonic-gate static int tty_npushed;			/* total count of pushed PPP modules */
1537c478bd9Sstevel@tonic-gate static u_int32_t remote_addr;		/* IP address of peer */
1547c478bd9Sstevel@tonic-gate static u_int32_t default_route_gateway;	/* Gateway for default route */
1557c478bd9Sstevel@tonic-gate static u_int32_t proxy_arp_addr;	/* Addr for proxy arp entry */
1567c478bd9Sstevel@tonic-gate static u_int32_t lastlink_status;	/* Last link status info */
1577c478bd9Sstevel@tonic-gate 
1587c478bd9Sstevel@tonic-gate static bool use_plink = 0;		/* Use I_LINK by default */
1597c478bd9Sstevel@tonic-gate static bool plumbed = 0;		/* Use existing interface */
1607c478bd9Sstevel@tonic-gate 
1617c478bd9Sstevel@tonic-gate /* Default is to use /dev/sppp as driver. */
1627c478bd9Sstevel@tonic-gate static const char *drvnam = PPP_DEV_NAME;
1637c478bd9Sstevel@tonic-gate static bool integrated_driver = 0;
1647c478bd9Sstevel@tonic-gate static int extra_dev_fd = -1;		/* keep open until ready */
1657c478bd9Sstevel@tonic-gate 
1667c478bd9Sstevel@tonic-gate static option_t solaris_option_list[] = {
1677c478bd9Sstevel@tonic-gate 	{ "plink", o_bool, &use_plink, "Use I_PLINK instead of I_LINK",
1687c478bd9Sstevel@tonic-gate 	    OPT_PRIV|1 },
1697c478bd9Sstevel@tonic-gate 	{ "noplink", o_bool, &use_plink, "Use I_LINK instead of I_PLINK",
1707c478bd9Sstevel@tonic-gate 	    OPT_PRIV|0 },
1717c478bd9Sstevel@tonic-gate 	{ "plumbed", o_bool, &plumbed, "Use pre-plumbed interface",
1727c478bd9Sstevel@tonic-gate 	    OPT_PRIV|1 },
1737c478bd9Sstevel@tonic-gate 	{ NULL }
1747c478bd9Sstevel@tonic-gate };
1757c478bd9Sstevel@tonic-gate 
1767c478bd9Sstevel@tonic-gate /*
1777c478bd9Sstevel@tonic-gate  * Prototypes for procedures local to this file.
1787c478bd9Sstevel@tonic-gate  */
1797c478bd9Sstevel@tonic-gate static int translate_speed __P((int));
1807c478bd9Sstevel@tonic-gate static int baud_rate_of __P((int));
1817c478bd9Sstevel@tonic-gate static int get_ether_addr __P((u_int32_t, struct sockaddr_dl *, int));
1827c478bd9Sstevel@tonic-gate static int strioctl __P((int, int, void *, int, int));
1837c478bd9Sstevel@tonic-gate static int plumb_ipif __P((int));
1847c478bd9Sstevel@tonic-gate static int unplumb_ipif __P((int));
1857c478bd9Sstevel@tonic-gate #ifdef INET6
1867c478bd9Sstevel@tonic-gate static int plumb_ip6if __P((int));
1877c478bd9Sstevel@tonic-gate static int unplumb_ip6if __P((int));
1887c478bd9Sstevel@tonic-gate static int open_ip6fd(void);
1897c478bd9Sstevel@tonic-gate #endif /* INET6 */
1907c478bd9Sstevel@tonic-gate static int open_ipfd(void);
1917c478bd9Sstevel@tonic-gate static int sifroute __P((int, u_int32_t, u_int32_t, int, const char *));
1927c478bd9Sstevel@tonic-gate static int giflags __P((u_int32_t, bool *));
1937c478bd9Sstevel@tonic-gate static void handle_unbind __P((u_int32_t));
1947c478bd9Sstevel@tonic-gate static void handle_bind __P((u_int32_t));
1957c478bd9Sstevel@tonic-gate 
1967c478bd9Sstevel@tonic-gate /*
1977c478bd9Sstevel@tonic-gate  * Wrapper for regular ioctl; masks out EINTR.
1987c478bd9Sstevel@tonic-gate  */
1997c478bd9Sstevel@tonic-gate static int
myioctl(int fd,int cmd,void * arg)2007c478bd9Sstevel@tonic-gate myioctl(int fd, int cmd, void *arg)
2017c478bd9Sstevel@tonic-gate {
2027c478bd9Sstevel@tonic-gate 	int retv;
2037c478bd9Sstevel@tonic-gate 
2047c478bd9Sstevel@tonic-gate 	errno = 0;
2057c478bd9Sstevel@tonic-gate 	while ((retv = ioctl(fd, cmd, arg)) == -1) {
2067c478bd9Sstevel@tonic-gate 		if (errno != EINTR)
2077c478bd9Sstevel@tonic-gate 			break;
2087c478bd9Sstevel@tonic-gate 	}
2097c478bd9Sstevel@tonic-gate 	return (retv);
2107c478bd9Sstevel@tonic-gate }
2117c478bd9Sstevel@tonic-gate 
2127c478bd9Sstevel@tonic-gate /*
2137c478bd9Sstevel@tonic-gate  * sys_check_options()
2147c478bd9Sstevel@tonic-gate  *
2157c478bd9Sstevel@tonic-gate  * Check the options that the user specified.
2167c478bd9Sstevel@tonic-gate  */
2177c478bd9Sstevel@tonic-gate int
sys_check_options(void)2187c478bd9Sstevel@tonic-gate sys_check_options(void)
2197c478bd9Sstevel@tonic-gate {
2207c478bd9Sstevel@tonic-gate 	if (plumbed) {
2217c478bd9Sstevel@tonic-gate 		if (req_unit == -1)
2227c478bd9Sstevel@tonic-gate 			req_unit = -2;
2237c478bd9Sstevel@tonic-gate 		ipmuxid = 0;
2247c478bd9Sstevel@tonic-gate 		ip6muxid = 0;
2257c478bd9Sstevel@tonic-gate 	}
2267c478bd9Sstevel@tonic-gate 	return (1);
2277c478bd9Sstevel@tonic-gate }
2287c478bd9Sstevel@tonic-gate 
2297c478bd9Sstevel@tonic-gate /*
2307c478bd9Sstevel@tonic-gate  * sys_options()
2317c478bd9Sstevel@tonic-gate  *
2327c478bd9Sstevel@tonic-gate  * Add or remove system-specific options.
2337c478bd9Sstevel@tonic-gate  */
2347c478bd9Sstevel@tonic-gate void
sys_options(void)2357c478bd9Sstevel@tonic-gate sys_options(void)
2367c478bd9Sstevel@tonic-gate {
2377c478bd9Sstevel@tonic-gate 	(void) remove_option("ktune");
2387c478bd9Sstevel@tonic-gate 	(void) remove_option("noktune");
2397c478bd9Sstevel@tonic-gate 	add_options(solaris_option_list);
2407c478bd9Sstevel@tonic-gate }
2417c478bd9Sstevel@tonic-gate 
2427c478bd9Sstevel@tonic-gate /*
2437c478bd9Sstevel@tonic-gate  * sys_ifname()
2447c478bd9Sstevel@tonic-gate  *
2457c478bd9Sstevel@tonic-gate  * Set ifname[] to contain name of IP interface for this unit.
2467c478bd9Sstevel@tonic-gate  */
2477c478bd9Sstevel@tonic-gate void
sys_ifname(void)2487c478bd9Sstevel@tonic-gate sys_ifname(void)
2497c478bd9Sstevel@tonic-gate {
2507c478bd9Sstevel@tonic-gate 	const char *cp;
2517c478bd9Sstevel@tonic-gate 
2527c478bd9Sstevel@tonic-gate 	if ((cp = strrchr(drvnam, '/')) == NULL)
2537c478bd9Sstevel@tonic-gate 		cp = drvnam;
2547c478bd9Sstevel@tonic-gate 	else
2557c478bd9Sstevel@tonic-gate 		cp++;
2567c478bd9Sstevel@tonic-gate 	(void) slprintf(ifname, sizeof (ifname), "%s%d", cp, ifunit);
2577c478bd9Sstevel@tonic-gate }
2587c478bd9Sstevel@tonic-gate 
2597c478bd9Sstevel@tonic-gate /*
2607c478bd9Sstevel@tonic-gate  * ppp_available()
2617c478bd9Sstevel@tonic-gate  *
2627c478bd9Sstevel@tonic-gate  * Check whether the system has any ppp interfaces.
2637c478bd9Sstevel@tonic-gate  */
2647c478bd9Sstevel@tonic-gate int
ppp_available(void)2657c478bd9Sstevel@tonic-gate ppp_available(void)
2667c478bd9Sstevel@tonic-gate {
2677c478bd9Sstevel@tonic-gate 	struct stat buf;
2687c478bd9Sstevel@tonic-gate 	int fd;
2697c478bd9Sstevel@tonic-gate 	uint32_t typ;
2707c478bd9Sstevel@tonic-gate 
2717c478bd9Sstevel@tonic-gate 	if (stat(PPP_DEV_NAME, &buf) >= 0)
2727c478bd9Sstevel@tonic-gate 		return (1);
2737c478bd9Sstevel@tonic-gate 
2747c478bd9Sstevel@tonic-gate 	/*
2757c478bd9Sstevel@tonic-gate 	 * Simple check for system using Apollo POS without SUNWpppd
2767c478bd9Sstevel@tonic-gate 	 * (/dev/sppp) installed.  This is intentionally not kept open
2777c478bd9Sstevel@tonic-gate 	 * here, since the user may not have the same privileges (as
2787c478bd9Sstevel@tonic-gate 	 * determined later).  If Apollo were just shipped with the
2797c478bd9Sstevel@tonic-gate 	 * full complement of packages, this wouldn't be an issue.
2807c478bd9Sstevel@tonic-gate 	 */
2817c478bd9Sstevel@tonic-gate 	if (devnam[0] == '\0' &&
2827c478bd9Sstevel@tonic-gate 	    (fd = open(devnam, O_RDWR | O_NONBLOCK | O_NOCTTY)) >= 0) {
2837c478bd9Sstevel@tonic-gate 		if (strioctl(fd, PPPIO_GTYPE, &typ, 0, sizeof (typ)) >= 0 &&
2847c478bd9Sstevel@tonic-gate 		    typ == PPPTYP_MUX) {
2857c478bd9Sstevel@tonic-gate 			(void) close(fd);
2867c478bd9Sstevel@tonic-gate 			return (1);
2877c478bd9Sstevel@tonic-gate 		}
2887c478bd9Sstevel@tonic-gate 		(void) close(fd);
2897c478bd9Sstevel@tonic-gate 	}
2907c478bd9Sstevel@tonic-gate 	return (0);
2917c478bd9Sstevel@tonic-gate }
2927c478bd9Sstevel@tonic-gate 
2937c478bd9Sstevel@tonic-gate static int
open_ipfd(void)2947c478bd9Sstevel@tonic-gate open_ipfd(void)
2957c478bd9Sstevel@tonic-gate {
2967c478bd9Sstevel@tonic-gate 	ipfd = open(IP_DEV_NAME, O_RDWR | O_NONBLOCK, 0);
2977c478bd9Sstevel@tonic-gate 	if (ipfd < 0) {
2987c478bd9Sstevel@tonic-gate 		error("Couldn't open IP device (%s): %m", IP_DEV_NAME);
2997c478bd9Sstevel@tonic-gate 	}
3007c478bd9Sstevel@tonic-gate 	return (ipfd);
3017c478bd9Sstevel@tonic-gate }
3027c478bd9Sstevel@tonic-gate 
3037c478bd9Sstevel@tonic-gate static int
read_ip_interface(int unit)3047c478bd9Sstevel@tonic-gate read_ip_interface(int unit)
3057c478bd9Sstevel@tonic-gate {
3067c478bd9Sstevel@tonic-gate 	struct ifreq ifr;
3077c478bd9Sstevel@tonic-gate 	struct sockaddr_in sin;
3087c478bd9Sstevel@tonic-gate 
3097c478bd9Sstevel@tonic-gate 	if (ipfd == -1 && open_ipfd() == -1)
3107c478bd9Sstevel@tonic-gate 		return (0);
3117c478bd9Sstevel@tonic-gate 
3127c478bd9Sstevel@tonic-gate 	BZERO(&ifr, sizeof (ifr));
3137c478bd9Sstevel@tonic-gate 	(void) strlcpy(ifr.ifr_name, ifname, sizeof (ifr.ifr_name));
3147c478bd9Sstevel@tonic-gate 
3157c478bd9Sstevel@tonic-gate 	/* Get the existing MTU */
3167c478bd9Sstevel@tonic-gate 	if (myioctl(ipfd, SIOCGIFMTU, &ifr) < 0) {
3177c478bd9Sstevel@tonic-gate 		warn("Couldn't get IP MTU on %s: %m", ifr.ifr_name);
3187c478bd9Sstevel@tonic-gate 		return (0);
3197c478bd9Sstevel@tonic-gate 	}
3207c478bd9Sstevel@tonic-gate 	dbglog("got MTU %d from interface", ifr.ifr_metric);
3217c478bd9Sstevel@tonic-gate 	if (ifr.ifr_metric != 0 &&
3227c478bd9Sstevel@tonic-gate 	    (lcp_allowoptions[unit].mru == 0 ||
323fb60e41dSss 	    lcp_allowoptions[unit].mru > ifr.ifr_metric))
3247c478bd9Sstevel@tonic-gate 		lcp_allowoptions[unit].mru = ifr.ifr_metric;
3257c478bd9Sstevel@tonic-gate 
3267c478bd9Sstevel@tonic-gate 	/* Get the local IP address */
3277c478bd9Sstevel@tonic-gate 	if (ipcp_wantoptions[unit].ouraddr == 0 ||
3287c478bd9Sstevel@tonic-gate 	    ipcp_from_hostname) {
3297c478bd9Sstevel@tonic-gate 		if (myioctl(ipfd, SIOCGIFADDR, &ifr) < 0) {
3307c478bd9Sstevel@tonic-gate 			warn("Couldn't get local IP address (%s): %m",
3317c478bd9Sstevel@tonic-gate 			    ifr.ifr_name);
3327c478bd9Sstevel@tonic-gate 			return (0);
3337c478bd9Sstevel@tonic-gate 		}
3347c478bd9Sstevel@tonic-gate 		BCOPY(&ifr.ifr_addr, &sin, sizeof (struct sockaddr_in));
3357c478bd9Sstevel@tonic-gate 		ipcp_wantoptions[unit].ouraddr = sin.sin_addr.s_addr;
3367c478bd9Sstevel@tonic-gate 		dbglog("got local address %I from interface",
3377c478bd9Sstevel@tonic-gate 		    ipcp_wantoptions[unit].ouraddr);
3387c478bd9Sstevel@tonic-gate 	}
3397c478bd9Sstevel@tonic-gate 
3407c478bd9Sstevel@tonic-gate 	/* Get the remote IP address */
3417c478bd9Sstevel@tonic-gate 	if (ipcp_wantoptions[unit].hisaddr == 0) {
3427c478bd9Sstevel@tonic-gate 		if (myioctl(ipfd, SIOCGIFDSTADDR, &ifr) < 0) {
3437c478bd9Sstevel@tonic-gate 			warn("Couldn't get remote IP address (%s): %m",
3447c478bd9Sstevel@tonic-gate 			    ifr.ifr_name);
3457c478bd9Sstevel@tonic-gate 			return (0);
3467c478bd9Sstevel@tonic-gate 		}
3477c478bd9Sstevel@tonic-gate 		BCOPY(&ifr.ifr_dstaddr, &sin, sizeof (struct sockaddr_in));
3487c478bd9Sstevel@tonic-gate 		ipcp_wantoptions[unit].hisaddr = sin.sin_addr.s_addr;
3497c478bd9Sstevel@tonic-gate 		dbglog("got remote address %I from interface",
3507c478bd9Sstevel@tonic-gate 		    ipcp_wantoptions[unit].hisaddr);
3517c478bd9Sstevel@tonic-gate 	}
3527c478bd9Sstevel@tonic-gate 	return (1);
3537c478bd9Sstevel@tonic-gate }
3547c478bd9Sstevel@tonic-gate 
3557c478bd9Sstevel@tonic-gate #ifdef INET6
3567c478bd9Sstevel@tonic-gate static int
open_ip6fd(void)3577c478bd9Sstevel@tonic-gate open_ip6fd(void)
3587c478bd9Sstevel@tonic-gate {
3597c478bd9Sstevel@tonic-gate 	ip6fd = open(IP6_DEV_NAME, O_RDWR | O_NONBLOCK, 0);
3607c478bd9Sstevel@tonic-gate 	if (ip6fd < 0) {
3617c478bd9Sstevel@tonic-gate 		error("Couldn't open IPv6 device (%s): %m", IP6_DEV_NAME);
3627c478bd9Sstevel@tonic-gate 	}
3637c478bd9Sstevel@tonic-gate 	return (ip6fd);
3647c478bd9Sstevel@tonic-gate }
3657c478bd9Sstevel@tonic-gate 
3667c478bd9Sstevel@tonic-gate static int
read_ipv6_interface(int unit)3677c478bd9Sstevel@tonic-gate read_ipv6_interface(int unit)
3687c478bd9Sstevel@tonic-gate {
3697c478bd9Sstevel@tonic-gate 	struct lifreq lifr;
3707c478bd9Sstevel@tonic-gate 	struct sockaddr_in6 *sin6 = (struct sockaddr_in6 *)&lifr.lifr_addr;
3717c478bd9Sstevel@tonic-gate 
3727c478bd9Sstevel@tonic-gate 	if (ip6fd == -1 && open_ip6fd() == -1)
3737c478bd9Sstevel@tonic-gate 		return (0);
3747c478bd9Sstevel@tonic-gate 
3757c478bd9Sstevel@tonic-gate 	BZERO(&lifr, sizeof (lifr));
3767c478bd9Sstevel@tonic-gate 	(void) strlcpy(lifr.lifr_name, ifname, sizeof (lifr.lifr_name));
3777c478bd9Sstevel@tonic-gate 
3787c478bd9Sstevel@tonic-gate 	/* Get the existing MTU */
3797c478bd9Sstevel@tonic-gate 	if (myioctl(ip6fd, SIOCGLIFMTU, &lifr) < 0) {
3807c478bd9Sstevel@tonic-gate 		warn("Couldn't get IPv6 MTU on %s: %m", lifr.lifr_name);
3817c478bd9Sstevel@tonic-gate 		return (0);
3827c478bd9Sstevel@tonic-gate 	}
3837c478bd9Sstevel@tonic-gate 	if (lifr.lifr_mtu != 0 &&
3847c478bd9Sstevel@tonic-gate 	    (lcp_allowoptions[unit].mru == 0 ||
385fb60e41dSss 	    lcp_allowoptions[unit].mru > lifr.lifr_mtu))
3867c478bd9Sstevel@tonic-gate 		lcp_allowoptions[unit].mru = lifr.lifr_mtu;
3877c478bd9Sstevel@tonic-gate 
3887c478bd9Sstevel@tonic-gate 	/* Get the local IPv6 address */
3897c478bd9Sstevel@tonic-gate 	if (eui64_iszero(ipv6cp_wantoptions[unit].ourid) ||
3907c478bd9Sstevel@tonic-gate 	    (ipcp_from_hostname && ipv6cp_wantoptions[unit].use_ip)) {
3917c478bd9Sstevel@tonic-gate 		if (myioctl(ip6fd, SIOCGLIFADDR, &lifr) < 0) {
3927c478bd9Sstevel@tonic-gate 			warn("Couldn't get local IPv6 address (%s): %m",
3937c478bd9Sstevel@tonic-gate 			    lifr.lifr_name);
3947c478bd9Sstevel@tonic-gate 			return (0);
3957c478bd9Sstevel@tonic-gate 		}
3967c478bd9Sstevel@tonic-gate 		eui64_copy(sin6->sin6_addr.s6_addr32[2],
3977c478bd9Sstevel@tonic-gate 		    ipv6cp_wantoptions[unit].ourid);
3987c478bd9Sstevel@tonic-gate 	}
3997c478bd9Sstevel@tonic-gate 
4007c478bd9Sstevel@tonic-gate 	/* Get the remote IP address */
4017c478bd9Sstevel@tonic-gate 	if (eui64_iszero(ipv6cp_wantoptions[unit].hisid)) {
4027c478bd9Sstevel@tonic-gate 		if (myioctl(ip6fd, SIOCGLIFDSTADDR, &lifr) < 0) {
4037c478bd9Sstevel@tonic-gate 			warn("Couldn't get remote IPv6 address (%s): %m",
4047c478bd9Sstevel@tonic-gate 			    lifr.lifr_name);
4057c478bd9Sstevel@tonic-gate 			return (0);
4067c478bd9Sstevel@tonic-gate 		}
4077c478bd9Sstevel@tonic-gate 		eui64_copy(sin6->sin6_addr.s6_addr32[2],
4087c478bd9Sstevel@tonic-gate 		    ipv6cp_wantoptions[unit].hisid);
4097c478bd9Sstevel@tonic-gate 	}
4107c478bd9Sstevel@tonic-gate 	return (1);
4117c478bd9Sstevel@tonic-gate }
4127c478bd9Sstevel@tonic-gate #endif /* INET6 */
4137c478bd9Sstevel@tonic-gate 
4147c478bd9Sstevel@tonic-gate /*
4157c478bd9Sstevel@tonic-gate  * Read information on existing interface(s) and configure ourselves
4167c478bd9Sstevel@tonic-gate  * to negotiate appropriately.
4177c478bd9Sstevel@tonic-gate  */
4187c478bd9Sstevel@tonic-gate static void
read_interface(int unit)4197c478bd9Sstevel@tonic-gate read_interface(int unit)
4207c478bd9Sstevel@tonic-gate {
4217c478bd9Sstevel@tonic-gate 	dbglog("reading existing interface data; %sip %sipv6",
4227c478bd9Sstevel@tonic-gate 	    IPCP_ENABLED ? "" : "!",
4237c478bd9Sstevel@tonic-gate #ifdef INET6
4247c478bd9Sstevel@tonic-gate 	    IPV6CP_ENABLED ? "" :
4257c478bd9Sstevel@tonic-gate #endif
4267c478bd9Sstevel@tonic-gate 	    "!");
4277c478bd9Sstevel@tonic-gate 	if (IPCP_ENABLED && !read_ip_interface(unit))
4287c478bd9Sstevel@tonic-gate 		IPCP_ENABLED = 0;
4297c478bd9Sstevel@tonic-gate #ifdef INET6
4307c478bd9Sstevel@tonic-gate 	if (IPV6CP_ENABLED && !read_ipv6_interface(unit))
4317c478bd9Sstevel@tonic-gate 		IPV6CP_ENABLED = 0;
4327c478bd9Sstevel@tonic-gate #endif
4337c478bd9Sstevel@tonic-gate }
4347c478bd9Sstevel@tonic-gate 
4357c478bd9Sstevel@tonic-gate /*
4367c478bd9Sstevel@tonic-gate  * sys_init()
4377c478bd9Sstevel@tonic-gate  *
4387c478bd9Sstevel@tonic-gate  * System-dependent initialization.
4397c478bd9Sstevel@tonic-gate  */
4407c478bd9Sstevel@tonic-gate void
sys_init(bool open_as_user)4417c478bd9Sstevel@tonic-gate sys_init(bool open_as_user)
4427c478bd9Sstevel@tonic-gate {
4437c478bd9Sstevel@tonic-gate 	uint32_t x;
4447c478bd9Sstevel@tonic-gate 	uint32_t typ;
4457c478bd9Sstevel@tonic-gate 
4467c478bd9Sstevel@tonic-gate 	if (pppfd != -1) {
4477c478bd9Sstevel@tonic-gate 		return;
4487c478bd9Sstevel@tonic-gate 	}
4497c478bd9Sstevel@tonic-gate 
4507c478bd9Sstevel@tonic-gate 	if (!direct_tty && devnam[0] != '\0') {
4517c478bd9Sstevel@tonic-gate 		/*
4527c478bd9Sstevel@tonic-gate 		 * Check for integrated driver-like devices (such as
4537c478bd9Sstevel@tonic-gate 		 * POS).  These identify themselves as "PPP
4547c478bd9Sstevel@tonic-gate 		 * multiplexor" drivers.
4557c478bd9Sstevel@tonic-gate 		 */
4567c478bd9Sstevel@tonic-gate 		if (open_as_user)
4577c478bd9Sstevel@tonic-gate 			(void) seteuid(getuid());
4587c478bd9Sstevel@tonic-gate 		pppfd = open(devnam, O_RDWR | O_NONBLOCK);
4597c478bd9Sstevel@tonic-gate 		if (open_as_user)
4607c478bd9Sstevel@tonic-gate 			(void) seteuid(0);
4617c478bd9Sstevel@tonic-gate 		if (pppfd >= 0 &&
4627c478bd9Sstevel@tonic-gate 		    strioctl(pppfd, PPPIO_GTYPE, &typ, 0, sizeof (typ)) >= 0 &&
4637c478bd9Sstevel@tonic-gate 		    typ == PPPTYP_MUX) {
4647c478bd9Sstevel@tonic-gate 			integrated_driver = 1;
4657c478bd9Sstevel@tonic-gate 			drvnam = devnam;
4667c478bd9Sstevel@tonic-gate 		} else if (demand) {
4677c478bd9Sstevel@tonic-gate 			(void) close(pppfd);
4687c478bd9Sstevel@tonic-gate 			pppfd = -1;
4697c478bd9Sstevel@tonic-gate 		} else {
4707c478bd9Sstevel@tonic-gate 			extra_dev_fd = pppfd;
4717c478bd9Sstevel@tonic-gate 			pppfd = -1;
4727c478bd9Sstevel@tonic-gate 		}
4737c478bd9Sstevel@tonic-gate 	}
4747c478bd9Sstevel@tonic-gate 
4757c478bd9Sstevel@tonic-gate 	/*
4767c478bd9Sstevel@tonic-gate 	 * Open Solaris PPP device driver.
4777c478bd9Sstevel@tonic-gate 	 */
4787c478bd9Sstevel@tonic-gate 	if (pppfd < 0)
4797c478bd9Sstevel@tonic-gate 		pppfd = open(drvnam, O_RDWR | O_NONBLOCK);
4807c478bd9Sstevel@tonic-gate 	if (pppfd < 0) {
4817c478bd9Sstevel@tonic-gate 		fatal("Can't open %s: %m", drvnam);
4827c478bd9Sstevel@tonic-gate 	}
4837c478bd9Sstevel@tonic-gate 	if (kdebugflag & 1) {
4847c478bd9Sstevel@tonic-gate 		x = PPPDBG_LOG + PPPDBG_DRIVER;
4857c478bd9Sstevel@tonic-gate 		if (strioctl(pppfd, PPPIO_DEBUG, &x, sizeof (x), 0) < 0) {
4867c478bd9Sstevel@tonic-gate 			warn("PPPIO_DEBUG ioctl for mux failed: %m");
4877c478bd9Sstevel@tonic-gate 		}
4887c478bd9Sstevel@tonic-gate 	}
4897c478bd9Sstevel@tonic-gate 	/*
4907c478bd9Sstevel@tonic-gate 	 * Assign a new PPA and get its unit number.
4917c478bd9Sstevel@tonic-gate 	 */
4927c478bd9Sstevel@tonic-gate 	x = req_unit;
4937c478bd9Sstevel@tonic-gate 	if (strioctl(pppfd, PPPIO_NEWPPA, &x, sizeof (x), sizeof (x)) < 0) {
4947c478bd9Sstevel@tonic-gate 		if (errno == ENXIO && plumbed)
4957c478bd9Sstevel@tonic-gate 			fatal("No idle interfaces available for use");
4967c478bd9Sstevel@tonic-gate 		fatal("PPPIO_NEWPPA ioctl failed: %m");
4977c478bd9Sstevel@tonic-gate 	}
4987c478bd9Sstevel@tonic-gate 	ifunit = x;
4997c478bd9Sstevel@tonic-gate 	if (req_unit >= 0 && ifunit != req_unit) {
5007c478bd9Sstevel@tonic-gate 		if (plumbed)
5017c478bd9Sstevel@tonic-gate 			fatal("unable to get requested unit %d", req_unit);
5027c478bd9Sstevel@tonic-gate 		else
5037c478bd9Sstevel@tonic-gate 			warn("unable to get requested unit %d", req_unit);
5047c478bd9Sstevel@tonic-gate 	}
5057c478bd9Sstevel@tonic-gate 	/*
5067c478bd9Sstevel@tonic-gate 	 * Enable packet time-stamping when idle option is specified. Note
5077c478bd9Sstevel@tonic-gate 	 * that we need to only do this on the control stream. Subsequent
5087c478bd9Sstevel@tonic-gate 	 * streams attached to this control stream (ppa) will inherit
5097c478bd9Sstevel@tonic-gate 	 * the time-stamp bit.
5107c478bd9Sstevel@tonic-gate 	 */
5117c478bd9Sstevel@tonic-gate 	if (idle_time_limit > 0) {
5127c478bd9Sstevel@tonic-gate 		if (strioctl(pppfd, PPPIO_USETIMESTAMP, NULL, 0, 0) < 0) {
5137c478bd9Sstevel@tonic-gate 			warn("PPPIO_USETIMESTAMP ioctl failed: %m");
5147c478bd9Sstevel@tonic-gate 		}
5157c478bd9Sstevel@tonic-gate 	}
5167c478bd9Sstevel@tonic-gate 	if (plumbed) {
5177c478bd9Sstevel@tonic-gate 		sys_ifname();
5187c478bd9Sstevel@tonic-gate 		read_interface(0);
5197c478bd9Sstevel@tonic-gate 	}
5207c478bd9Sstevel@tonic-gate }
5217c478bd9Sstevel@tonic-gate 
5227c478bd9Sstevel@tonic-gate int
sys_extra_fd(void)5237c478bd9Sstevel@tonic-gate sys_extra_fd(void)
5247c478bd9Sstevel@tonic-gate {
5257c478bd9Sstevel@tonic-gate 	int fd;
5267c478bd9Sstevel@tonic-gate 
5277c478bd9Sstevel@tonic-gate 	fd = extra_dev_fd;
5287c478bd9Sstevel@tonic-gate 	extra_dev_fd = -1;
5297c478bd9Sstevel@tonic-gate 	return (fd);
5307c478bd9Sstevel@tonic-gate }
5317c478bd9Sstevel@tonic-gate 
5327c478bd9Sstevel@tonic-gate static int
open_udpfd(void)5337c478bd9Sstevel@tonic-gate open_udpfd(void)
5347c478bd9Sstevel@tonic-gate {
5357c478bd9Sstevel@tonic-gate 	int udpfd;
5367c478bd9Sstevel@tonic-gate 
5377c478bd9Sstevel@tonic-gate 	udpfd = open(UDP_DEV_NAME, O_RDWR | O_NONBLOCK, 0);
5387c478bd9Sstevel@tonic-gate 	if (udpfd < 0) {
5397c478bd9Sstevel@tonic-gate 		error("Couldn't open UDP device (%s): %m", UDP_DEV_NAME);
5407c478bd9Sstevel@tonic-gate 	}
5417c478bd9Sstevel@tonic-gate 	return (udpfd);
5427c478bd9Sstevel@tonic-gate }
5437c478bd9Sstevel@tonic-gate 
5447c478bd9Sstevel@tonic-gate /*
5457c478bd9Sstevel@tonic-gate  * plumb_ipif()
5467c478bd9Sstevel@tonic-gate  *
5477c478bd9Sstevel@tonic-gate  * Perform IP interface plumbing.
5487c478bd9Sstevel@tonic-gate  */
5497c478bd9Sstevel@tonic-gate /*ARGSUSED*/
5507c478bd9Sstevel@tonic-gate static int
plumb_ipif(int unit)5517c478bd9Sstevel@tonic-gate plumb_ipif(int unit)
5527c478bd9Sstevel@tonic-gate {
5537c478bd9Sstevel@tonic-gate 	int udpfd = -1, tmpfd;
5547c478bd9Sstevel@tonic-gate 	uint32_t x;
5557c478bd9Sstevel@tonic-gate 	struct ifreq ifr;
5567c478bd9Sstevel@tonic-gate 
5577c478bd9Sstevel@tonic-gate 	if (!IPCP_ENABLED || (ifunit == -1) || (pppfd == -1)) {
5587c478bd9Sstevel@tonic-gate 		return (0);
5597c478bd9Sstevel@tonic-gate 	}
5607c478bd9Sstevel@tonic-gate 	if (plumbed)
5617c478bd9Sstevel@tonic-gate 		return (1);
5627c478bd9Sstevel@tonic-gate 	if (ipfd == -1 && open_ipfd() == -1)
5637c478bd9Sstevel@tonic-gate 		return (0);
5647c478bd9Sstevel@tonic-gate 	if (use_plink && (udpfd = open_udpfd()) == -1)
5657c478bd9Sstevel@tonic-gate 		return (0);
5667c478bd9Sstevel@tonic-gate 	tmpfd = open(drvnam, O_RDWR | O_NONBLOCK, 0);
5677c478bd9Sstevel@tonic-gate 	if (tmpfd < 0) {
5687c478bd9Sstevel@tonic-gate 		error("Couldn't open PPP device (%s): %m", drvnam);
5697c478bd9Sstevel@tonic-gate 		if (udpfd != -1)
5707c478bd9Sstevel@tonic-gate 			(void) close(udpfd);
5717c478bd9Sstevel@tonic-gate 		return (0);
5727c478bd9Sstevel@tonic-gate 	}
5737c478bd9Sstevel@tonic-gate 	if (kdebugflag & 1) {
5747c478bd9Sstevel@tonic-gate 		x = PPPDBG_LOG + PPPDBG_DRIVER;
5757c478bd9Sstevel@tonic-gate 		if (strioctl(tmpfd, PPPIO_DEBUG, &x, sizeof (x), 0) < 0) {
5767c478bd9Sstevel@tonic-gate 			warn("PPPIO_DEBUG ioctl for mux failed: %m");
5777c478bd9Sstevel@tonic-gate 		}
5787c478bd9Sstevel@tonic-gate 	}
5797c478bd9Sstevel@tonic-gate 	if (myioctl(tmpfd, I_PUSH, IP_MOD_NAME) < 0) {
5807c478bd9Sstevel@tonic-gate 		error("Couldn't push IP module (%s): %m", IP_MOD_NAME);
5817c478bd9Sstevel@tonic-gate 		goto err_ret;
5827c478bd9Sstevel@tonic-gate 	}
5837c478bd9Sstevel@tonic-gate 	/*
5847c478bd9Sstevel@tonic-gate 	 * Assign ppa according to the unit number returned by ppp device
5857c478bd9Sstevel@tonic-gate 	 * after plumbing is completed above.  Without setting the ppa, ip
5867c478bd9Sstevel@tonic-gate 	 * module will return EINVAL upon setting the interface UP
5877c478bd9Sstevel@tonic-gate 	 * (SIOCSxIFFLAGS).  This is because ip module in 2.8 expects two
5887c478bd9Sstevel@tonic-gate 	 * DLPI_INFO_REQ to be sent down to the driver (below ip) before
5897c478bd9Sstevel@tonic-gate 	 * IFF_UP bit can be set. Plumbing the device causes one DLPI_INFO_REQ
5907c478bd9Sstevel@tonic-gate 	 * to be sent down, and the second DLPI_INFO_REQ is sent upon receiving
5917c478bd9Sstevel@tonic-gate 	 * IF_UNITSEL (old) or SIOCSLIFNAME (new) ioctls. Such setting of the
5927c478bd9Sstevel@tonic-gate 	 * ppa is required because the ppp DLPI provider advertises itself as
5937c478bd9Sstevel@tonic-gate 	 * a DLPI style 2 type, which requires a point of attachment to be
5947c478bd9Sstevel@tonic-gate 	 * specified. The only way the user can specify a point of attachment
5957c478bd9Sstevel@tonic-gate 	 * is via SIOCSLIFNAME or IF_UNITSEL.  Such changes in the behavior of
5967c478bd9Sstevel@tonic-gate 	 * ip module was made to meet new or evolving standards requirements.
5977c478bd9Sstevel@tonic-gate 	 */
5987c478bd9Sstevel@tonic-gate 	if (myioctl(tmpfd, IF_UNITSEL, &ifunit) < 0) {
5997c478bd9Sstevel@tonic-gate 		error("Couldn't set ppa for unit %d: %m", ifunit);
6007c478bd9Sstevel@tonic-gate 		goto err_ret;
6017c478bd9Sstevel@tonic-gate 	}
6027c478bd9Sstevel@tonic-gate 	if (use_plink) {
6037c478bd9Sstevel@tonic-gate 		ipmuxid = myioctl(udpfd, I_PLINK, (void *)tmpfd);
6047c478bd9Sstevel@tonic-gate 		if (ipmuxid < 0) {
6057c478bd9Sstevel@tonic-gate 			error("Can't I_PLINK PPP device to IP: %m");
6067c478bd9Sstevel@tonic-gate 			goto err_ret;
6077c478bd9Sstevel@tonic-gate 		}
6087c478bd9Sstevel@tonic-gate 	} else {
6097c478bd9Sstevel@tonic-gate 		ipmuxid = myioctl(ipfd, I_LINK, (void *)tmpfd);
6107c478bd9Sstevel@tonic-gate 		if (ipmuxid < 0) {
6117c478bd9Sstevel@tonic-gate 			error("Can't I_LINK PPP device to IP: %m");
6127c478bd9Sstevel@tonic-gate 			goto err_ret;
6137c478bd9Sstevel@tonic-gate 		}
6147c478bd9Sstevel@tonic-gate 	}
6157c478bd9Sstevel@tonic-gate 	BZERO(&ifr, sizeof (ifr));
6167c478bd9Sstevel@tonic-gate 	(void) strlcpy(ifr.ifr_name, ifname, sizeof (ifr.ifr_name));
6177c478bd9Sstevel@tonic-gate 	ifr.ifr_ip_muxid = ipmuxid;
6187c478bd9Sstevel@tonic-gate 	ifr.ifr_arp_muxid = -1;
6197c478bd9Sstevel@tonic-gate 	if (myioctl(ipfd, SIOCSIFMUXID, (caddr_t)&ifr) < 0) {
6207c478bd9Sstevel@tonic-gate 		error("Can't set mux ID SIOCSIFMUXID on %s: %m", ifname);
6217c478bd9Sstevel@tonic-gate 		goto err_ret;
6227c478bd9Sstevel@tonic-gate 	}
6237c478bd9Sstevel@tonic-gate 	if (udpfd != -1)
6247c478bd9Sstevel@tonic-gate 		(void) close(udpfd);
6257c478bd9Sstevel@tonic-gate 	(void) close(tmpfd);
6267c478bd9Sstevel@tonic-gate 	return (1);
6277c478bd9Sstevel@tonic-gate err_ret:
6287c478bd9Sstevel@tonic-gate 	if (udpfd != -1)
6297c478bd9Sstevel@tonic-gate 		(void) close(udpfd);
6307c478bd9Sstevel@tonic-gate 	(void) close(tmpfd);
6317c478bd9Sstevel@tonic-gate 	return (0);
6327c478bd9Sstevel@tonic-gate }
6337c478bd9Sstevel@tonic-gate 
6347c478bd9Sstevel@tonic-gate /*
6357c478bd9Sstevel@tonic-gate  * unplumb_ipif()
6367c478bd9Sstevel@tonic-gate  *
6377c478bd9Sstevel@tonic-gate  * Perform IP interface unplumbing.  Possibly called from die(), so there
6387c478bd9Sstevel@tonic-gate  * shouldn't be any call to die() or fatal() here.
6397c478bd9Sstevel@tonic-gate  */
6407c478bd9Sstevel@tonic-gate static int
unplumb_ipif(int unit)6417c478bd9Sstevel@tonic-gate unplumb_ipif(int unit)
6427c478bd9Sstevel@tonic-gate {
6437c478bd9Sstevel@tonic-gate 	int udpfd = -1, fd = -1;
6447c478bd9Sstevel@tonic-gate 	int id;
6457c478bd9Sstevel@tonic-gate 	struct lifreq lifr;
6467c478bd9Sstevel@tonic-gate 
6477c478bd9Sstevel@tonic-gate 	if (!IPCP_ENABLED || (ifunit == -1)) {
6487c478bd9Sstevel@tonic-gate 		return (0);
6497c478bd9Sstevel@tonic-gate 	}
6507c478bd9Sstevel@tonic-gate 	if (!plumbed && (ipmuxid == -1 || (ipfd == -1 && !use_plink)))
6517c478bd9Sstevel@tonic-gate 		return (1);
6527c478bd9Sstevel@tonic-gate 	id = ipmuxid;
6537c478bd9Sstevel@tonic-gate 	if (!plumbed && use_plink) {
6547c478bd9Sstevel@tonic-gate 		if ((udpfd = open_udpfd()) == -1)
6557c478bd9Sstevel@tonic-gate 			return (0);
6567c478bd9Sstevel@tonic-gate 		/*
6577c478bd9Sstevel@tonic-gate 		 * Note: must re-get mux ID, since any intervening
6587c478bd9Sstevel@tonic-gate 		 * ifconfigs will change this.
6597c478bd9Sstevel@tonic-gate 		 */
6607c478bd9Sstevel@tonic-gate 		BZERO(&lifr, sizeof (lifr));
6617c478bd9Sstevel@tonic-gate 		(void) strlcpy(lifr.lifr_name, ifname,
6627c478bd9Sstevel@tonic-gate 		    sizeof (lifr.lifr_name));
6637c478bd9Sstevel@tonic-gate 		if (myioctl(ipfd, SIOCGLIFMUXID, (caddr_t)&lifr) < 0) {
6647c478bd9Sstevel@tonic-gate 			warn("Can't get mux fd: SIOCGLIFMUXID: %m");
6657c478bd9Sstevel@tonic-gate 		} else {
6667c478bd9Sstevel@tonic-gate 			id = lifr.lifr_ip_muxid;
6677c478bd9Sstevel@tonic-gate 			fd = myioctl(udpfd, _I_MUXID2FD, (void *)id);
6687c478bd9Sstevel@tonic-gate 			if (fd < 0) {
6697c478bd9Sstevel@tonic-gate 				warn("Can't get mux fd: _I_MUXID2FD: %m");
6707c478bd9Sstevel@tonic-gate 			}
6717c478bd9Sstevel@tonic-gate 		}
6727c478bd9Sstevel@tonic-gate 	}
6737c478bd9Sstevel@tonic-gate 	/*
6747c478bd9Sstevel@tonic-gate 	 * Mark down and unlink the ip interface.
6757c478bd9Sstevel@tonic-gate 	 */
6767c478bd9Sstevel@tonic-gate 	(void) sifdown(unit);
6777c478bd9Sstevel@tonic-gate 	if (default_route_gateway != 0) {
6787c478bd9Sstevel@tonic-gate 		(void) cifdefaultroute(0, default_route_gateway,
6797c478bd9Sstevel@tonic-gate 		    default_route_gateway);
6807c478bd9Sstevel@tonic-gate 	}
6817c478bd9Sstevel@tonic-gate 	if (proxy_arp_addr != 0) {
6827c478bd9Sstevel@tonic-gate 		(void) cifproxyarp(0, proxy_arp_addr);
6837c478bd9Sstevel@tonic-gate 	}
6847c478bd9Sstevel@tonic-gate 	ipmuxid = -1;
6857c478bd9Sstevel@tonic-gate 	if (plumbed)
6867c478bd9Sstevel@tonic-gate 		return (1);
6877c478bd9Sstevel@tonic-gate 	if (use_plink) {
6887c478bd9Sstevel@tonic-gate 		if (myioctl(udpfd, I_PUNLINK, (void *)id) < 0) {
6897c478bd9Sstevel@tonic-gate 			error("Can't I_PUNLINK PPP from IP: %m");
6907c478bd9Sstevel@tonic-gate 			if (fd != -1)
6917c478bd9Sstevel@tonic-gate 				(void) close(fd);
6927c478bd9Sstevel@tonic-gate 			(void) close(udpfd);
6937c478bd9Sstevel@tonic-gate 			return (0);
6947c478bd9Sstevel@tonic-gate 		}
6957c478bd9Sstevel@tonic-gate 		if (fd != -1)
6967c478bd9Sstevel@tonic-gate 			(void) close(fd);
6977c478bd9Sstevel@tonic-gate 		(void) close(udpfd);
6987c478bd9Sstevel@tonic-gate 	} else {
6997c478bd9Sstevel@tonic-gate 		if (myioctl(ipfd, I_UNLINK, (void *)id) < 0) {
7007c478bd9Sstevel@tonic-gate 			error("Can't I_UNLINK PPP from IP: %m");
7017c478bd9Sstevel@tonic-gate 			return (0);
7027c478bd9Sstevel@tonic-gate 		}
7037c478bd9Sstevel@tonic-gate 	}
7047c478bd9Sstevel@tonic-gate 	return (1);
7057c478bd9Sstevel@tonic-gate }
7067c478bd9Sstevel@tonic-gate 
7077c478bd9Sstevel@tonic-gate /*
7087c478bd9Sstevel@tonic-gate  * sys_cleanup()
7097c478bd9Sstevel@tonic-gate  *
7107c478bd9Sstevel@tonic-gate  * Restore any system state we modified before exiting: mark the
7117c478bd9Sstevel@tonic-gate  * interface down, delete default route and/or proxy arp entry. This
7127c478bd9Sstevel@tonic-gate  * should not call die() because it's called from die().
7137c478bd9Sstevel@tonic-gate  */
7147c478bd9Sstevel@tonic-gate void
sys_cleanup()7157c478bd9Sstevel@tonic-gate sys_cleanup()
7167c478bd9Sstevel@tonic-gate {
7177c478bd9Sstevel@tonic-gate 	(void) unplumb_ipif(0);
7187c478bd9Sstevel@tonic-gate #ifdef INET6
7197c478bd9Sstevel@tonic-gate 	(void) unplumb_ip6if(0);
7207c478bd9Sstevel@tonic-gate #endif /* INET6 */
7217c478bd9Sstevel@tonic-gate }
7227c478bd9Sstevel@tonic-gate 
7237c478bd9Sstevel@tonic-gate /*
7247c478bd9Sstevel@tonic-gate  * get_first_hwaddr()
7257c478bd9Sstevel@tonic-gate  *
7267c478bd9Sstevel@tonic-gate  * Stores the first hardware interface address found in the system
7277c478bd9Sstevel@tonic-gate  * into addr and return 1 upon success, or 0 if none is found.  This
7287c478bd9Sstevel@tonic-gate  * is also called from the multilink code.
7297c478bd9Sstevel@tonic-gate  */
7307c478bd9Sstevel@tonic-gate int
get_first_hwaddr(addr,msize)7317c478bd9Sstevel@tonic-gate get_first_hwaddr(addr, msize)
7327c478bd9Sstevel@tonic-gate 	uchar_t *addr;
7337c478bd9Sstevel@tonic-gate 	int msize;
7347c478bd9Sstevel@tonic-gate {
7357c478bd9Sstevel@tonic-gate 	struct ifconf ifc;
7367c478bd9Sstevel@tonic-gate 	register struct ifreq *pifreq;
7377c478bd9Sstevel@tonic-gate 	struct ifreq ifr;
7387c478bd9Sstevel@tonic-gate 	int fd, num_ifs, i;
7397c478bd9Sstevel@tonic-gate 	uint_t fl, req_size;
7407c478bd9Sstevel@tonic-gate 	char *req;
7417c478bd9Sstevel@tonic-gate 	boolean_t found;
7427c478bd9Sstevel@tonic-gate 
7437c478bd9Sstevel@tonic-gate 	if (addr == NULL) {
7447c478bd9Sstevel@tonic-gate 		return (0);
7457c478bd9Sstevel@tonic-gate 	}
7467c478bd9Sstevel@tonic-gate 	fd = socket(AF_INET, SOCK_DGRAM, 0);
7477c478bd9Sstevel@tonic-gate 	if (fd < 0) {
7487c478bd9Sstevel@tonic-gate 		error("get_first_hwaddr: error opening IP socket: %m");
7497c478bd9Sstevel@tonic-gate 		return (0);
7507c478bd9Sstevel@tonic-gate 	}
7517c478bd9Sstevel@tonic-gate 	/*
7527c478bd9Sstevel@tonic-gate 	 * Find out how many interfaces are running
7537c478bd9Sstevel@tonic-gate 	 */
7547c478bd9Sstevel@tonic-gate 	if (myioctl(fd, SIOCGIFNUM, (caddr_t)&num_ifs) < 0) {
7557c478bd9Sstevel@tonic-gate 		num_ifs = MAXIFS;
7567c478bd9Sstevel@tonic-gate 	}
7577c478bd9Sstevel@tonic-gate 	req_size = num_ifs * sizeof (struct ifreq);
7587c478bd9Sstevel@tonic-gate 	req = malloc(req_size);
7597c478bd9Sstevel@tonic-gate 	if (req == NULL) {
7607c478bd9Sstevel@tonic-gate 		novm("interface request structure.");
7617c478bd9Sstevel@tonic-gate 	}
7627c478bd9Sstevel@tonic-gate 	/*
7637c478bd9Sstevel@tonic-gate 	 * Get interface configuration info for all interfaces
7647c478bd9Sstevel@tonic-gate 	 */
7657c478bd9Sstevel@tonic-gate 	ifc.ifc_len = req_size;
7667c478bd9Sstevel@tonic-gate 	ifc.ifc_buf = req;
7677c478bd9Sstevel@tonic-gate 	if (myioctl(fd, SIOCGIFCONF, &ifc) < 0) {
7687c478bd9Sstevel@tonic-gate 		error("SIOCGIFCONF: %m");
7697c478bd9Sstevel@tonic-gate 		(void) close(fd);
7707c478bd9Sstevel@tonic-gate 		free(req);
7717c478bd9Sstevel@tonic-gate 		return (0);
7727c478bd9Sstevel@tonic-gate 	}
7737c478bd9Sstevel@tonic-gate 	/*
7747c478bd9Sstevel@tonic-gate 	 * And traverse each interface to look specifically for the first
7757c478bd9Sstevel@tonic-gate 	 * occurence of an Ethernet interface which has been marked up
7767c478bd9Sstevel@tonic-gate 	 */
7777c478bd9Sstevel@tonic-gate 	pifreq = ifc.ifc_req;
7787c478bd9Sstevel@tonic-gate 	found = 0;
7797c478bd9Sstevel@tonic-gate 	for (i = ifc.ifc_len / sizeof (struct ifreq); i > 0; i--, pifreq++) {
7807c478bd9Sstevel@tonic-gate 
7817c478bd9Sstevel@tonic-gate 		if (strchr(pifreq->ifr_name, ':') != NULL) {
7827c478bd9Sstevel@tonic-gate 			continue;
7837c478bd9Sstevel@tonic-gate 		}
7847c478bd9Sstevel@tonic-gate 		BZERO(&ifr, sizeof (ifr));
7857c478bd9Sstevel@tonic-gate 		(void) strncpy(ifr.ifr_name, pifreq->ifr_name,
7867c478bd9Sstevel@tonic-gate 		    sizeof (ifr.ifr_name));
7877c478bd9Sstevel@tonic-gate 		if (myioctl(fd, SIOCGIFFLAGS, &ifr) < 0) {
7887c478bd9Sstevel@tonic-gate 			continue;
7897c478bd9Sstevel@tonic-gate 		}
7907c478bd9Sstevel@tonic-gate 		fl = ifr.ifr_flags;
7917c478bd9Sstevel@tonic-gate 		if ((fl & (IFF_UP|IFF_BROADCAST|IFF_POINTOPOINT|IFF_LOOPBACK))
7927c478bd9Sstevel@tonic-gate 		    != (IFF_UP | IFF_BROADCAST)) {
7937c478bd9Sstevel@tonic-gate 			continue;
7947c478bd9Sstevel@tonic-gate 		}
7957c478bd9Sstevel@tonic-gate 		if (get_if_hwaddr(addr, msize, ifr.ifr_name) <= 0) {
7967c478bd9Sstevel@tonic-gate 			continue;
7977c478bd9Sstevel@tonic-gate 		}
7987c478bd9Sstevel@tonic-gate 		found = 1;
7997c478bd9Sstevel@tonic-gate 		break;
8007c478bd9Sstevel@tonic-gate 	}
8017c478bd9Sstevel@tonic-gate 	free(req);
8027c478bd9Sstevel@tonic-gate 	(void) close(fd);
8037c478bd9Sstevel@tonic-gate 
8047c478bd9Sstevel@tonic-gate 	return (found);
8057c478bd9Sstevel@tonic-gate }
8067c478bd9Sstevel@tonic-gate 
8077c478bd9Sstevel@tonic-gate /*
8087c478bd9Sstevel@tonic-gate  * get_if_hwaddr()
8097c478bd9Sstevel@tonic-gate  *
8107c478bd9Sstevel@tonic-gate  * Get the hardware address for the specified network interface device.
8117c478bd9Sstevel@tonic-gate  * Return the length of the MAC address (in bytes) or -1 if error.
8127c478bd9Sstevel@tonic-gate  */
8137c478bd9Sstevel@tonic-gate int
get_if_hwaddr(uchar_t * addrp,int msize,char * linkname)814fb60e41dSss get_if_hwaddr(uchar_t *addrp, int msize, char *linkname)
815fb60e41dSss {
816fb60e41dSss 	dlpi_handle_t dh;
817fb60e41dSss 	uchar_t physaddr[DLPI_PHYSADDR_MAX];
818fb60e41dSss 	size_t physaddrlen = sizeof (physaddr);
819fb60e41dSss 	int retv;
820fb60e41dSss 
821fb60e41dSss 	if ((addrp == NULL) || (linkname == NULL))
8227c478bd9Sstevel@tonic-gate 		return (-1);
823fb60e41dSss 
8247c478bd9Sstevel@tonic-gate 	/*
825fb60e41dSss 	 * Open the link and ask for hardware address.
8267c478bd9Sstevel@tonic-gate 	 */
827fb60e41dSss 	if ((retv = dlpi_open(linkname, &dh, 0)) != DLPI_SUCCESS) {
828fb60e41dSss 		error("Could not open %s: %s", linkname, dlpi_strerror(retv));
8297c478bd9Sstevel@tonic-gate 		return (-1);
8307c478bd9Sstevel@tonic-gate 	}
8317c478bd9Sstevel@tonic-gate 
832fb60e41dSss 	retv = dlpi_get_physaddr(dh, DL_CURR_PHYS_ADDR,
833fb60e41dSss 	    physaddr, &physaddrlen);
834fb60e41dSss 	dlpi_close(dh);
835fb60e41dSss 	if (retv != DLPI_SUCCESS) {
836fb60e41dSss 		error("Could not get physical address on %s: %s", linkname,
837fb60e41dSss 		    dlpi_strerror(retv));
8387c478bd9Sstevel@tonic-gate 		return (-1);
8397c478bd9Sstevel@tonic-gate 	}
8407c478bd9Sstevel@tonic-gate 
8417c478bd9Sstevel@tonic-gate 	/*
8427c478bd9Sstevel@tonic-gate 	 * Check if we have enough space to copy the address to.
8437c478bd9Sstevel@tonic-gate 	 */
844fb60e41dSss 	if (physaddrlen > msize)
8457c478bd9Sstevel@tonic-gate 		return (-1);
846fb60e41dSss 	(void) memcpy(addrp, physaddr, physaddrlen);
847fb60e41dSss 	return (physaddrlen);
8487c478bd9Sstevel@tonic-gate }
8497c478bd9Sstevel@tonic-gate 
8507c478bd9Sstevel@tonic-gate /*
8517c478bd9Sstevel@tonic-gate  * giflags()
8527c478bd9Sstevel@tonic-gate  */
8537c478bd9Sstevel@tonic-gate static int
giflags(u_int32_t flag,bool * retval)8547c478bd9Sstevel@tonic-gate giflags(u_int32_t flag, bool *retval)
8557c478bd9Sstevel@tonic-gate {
8567c478bd9Sstevel@tonic-gate 	struct ifreq ifr;
8577c478bd9Sstevel@tonic-gate 	int fd;
8587c478bd9Sstevel@tonic-gate 
8597c478bd9Sstevel@tonic-gate 	*retval = 0;
8607c478bd9Sstevel@tonic-gate 	fd = socket(AF_INET, SOCK_DGRAM, 0);
8617c478bd9Sstevel@tonic-gate 	if (fd < 0) {
8627c478bd9Sstevel@tonic-gate 		error("giflags: error opening IP socket: %m");
8637c478bd9Sstevel@tonic-gate 		return (errno);
8647c478bd9Sstevel@tonic-gate 	}
8657c478bd9Sstevel@tonic-gate 
8667c478bd9Sstevel@tonic-gate 	BZERO(&ifr, sizeof (ifr));
8677c478bd9Sstevel@tonic-gate 	(void) strncpy(ifr.ifr_name, ifname, sizeof (ifr.ifr_name));
8687c478bd9Sstevel@tonic-gate 	if (ioctl(fd, SIOCGIFFLAGS, &ifr) < 0) {
8697c478bd9Sstevel@tonic-gate 		(void) close(fd);
8707c478bd9Sstevel@tonic-gate 		return (errno);
8717c478bd9Sstevel@tonic-gate 	}
8727c478bd9Sstevel@tonic-gate 
8737c478bd9Sstevel@tonic-gate 	*retval = ((ifr.ifr_flags & flag) != 0);
8747c478bd9Sstevel@tonic-gate 	(void) close(fd);
8757c478bd9Sstevel@tonic-gate 	return (errno);
8767c478bd9Sstevel@tonic-gate }
8777c478bd9Sstevel@tonic-gate 
8787c478bd9Sstevel@tonic-gate /*
8797c478bd9Sstevel@tonic-gate  * sys_close()
8807c478bd9Sstevel@tonic-gate  *
8817c478bd9Sstevel@tonic-gate  * Clean up in a child process before exec-ing.
8827c478bd9Sstevel@tonic-gate  */
8837c478bd9Sstevel@tonic-gate void
sys_close()8847c478bd9Sstevel@tonic-gate sys_close()
8857c478bd9Sstevel@tonic-gate {
8867c478bd9Sstevel@tonic-gate 	if (ipfd != -1) {
8877c478bd9Sstevel@tonic-gate 		(void) close(ipfd);
8887c478bd9Sstevel@tonic-gate 		ipfd = -1;
8897c478bd9Sstevel@tonic-gate 	}
8907c478bd9Sstevel@tonic-gate #ifdef INET6
8917c478bd9Sstevel@tonic-gate 	if (ip6fd != -1) {
8927c478bd9Sstevel@tonic-gate 		(void) close(ip6fd);
8937c478bd9Sstevel@tonic-gate 		ip6fd = -1;
8947c478bd9Sstevel@tonic-gate 	}
8957c478bd9Sstevel@tonic-gate #endif /* INET6 */
8967c478bd9Sstevel@tonic-gate 	if (pppfd != -1) {
8977c478bd9Sstevel@tonic-gate 		(void) close(pppfd);
8987c478bd9Sstevel@tonic-gate 		pppfd = -1;
8997c478bd9Sstevel@tonic-gate 	}
9007c478bd9Sstevel@tonic-gate }
9017c478bd9Sstevel@tonic-gate 
9027c478bd9Sstevel@tonic-gate /*
9037c478bd9Sstevel@tonic-gate  * any_compressions()
9047c478bd9Sstevel@tonic-gate  *
9057c478bd9Sstevel@tonic-gate  * Check if compression is enabled or not.  In the STREAMS implementation of
9067c478bd9Sstevel@tonic-gate  * kernel-portion pppd, the comp STREAMS module performs the ACFC, PFC, as
9077c478bd9Sstevel@tonic-gate  * well CCP and VJ compressions. However, if the user has explicitly declare
9087c478bd9Sstevel@tonic-gate  * to not enable them from the command line, there is no point of having the
9097c478bd9Sstevel@tonic-gate  * comp module be pushed on the stream.
9107c478bd9Sstevel@tonic-gate  */
9117c478bd9Sstevel@tonic-gate static int
any_compressions(void)9127c478bd9Sstevel@tonic-gate any_compressions(void)
9137c478bd9Sstevel@tonic-gate {
9147c478bd9Sstevel@tonic-gate 	if ((!lcp_wantoptions[0].neg_accompression) &&
9157c478bd9Sstevel@tonic-gate 	    (!lcp_wantoptions[0].neg_pcompression) &&
9167c478bd9Sstevel@tonic-gate 	    (!ccp_protent.enabled_flag) &&
9177c478bd9Sstevel@tonic-gate 	    (!ipcp_wantoptions[0].neg_vj)) {
9187c478bd9Sstevel@tonic-gate 		return (0);
9197c478bd9Sstevel@tonic-gate 	}
9207c478bd9Sstevel@tonic-gate 	return (1);
9217c478bd9Sstevel@tonic-gate }
9227c478bd9Sstevel@tonic-gate 
9237c478bd9Sstevel@tonic-gate /*
9247c478bd9Sstevel@tonic-gate  * modpush()
9257c478bd9Sstevel@tonic-gate  *
9267c478bd9Sstevel@tonic-gate  * Push a module on the stream.
9277c478bd9Sstevel@tonic-gate  */
9287c478bd9Sstevel@tonic-gate static int
modpush(int fd,const char * modname,const char * text)9297c478bd9Sstevel@tonic-gate modpush(int fd, const char *modname, const char *text)
9307c478bd9Sstevel@tonic-gate {
9317c478bd9Sstevel@tonic-gate 	if (myioctl(fd, I_PUSH, (void *)modname) < 0) {
9327c478bd9Sstevel@tonic-gate 		error("Couldn't push %s module: %m", text);
9337c478bd9Sstevel@tonic-gate 		return (-1);
9347c478bd9Sstevel@tonic-gate 	}
9357c478bd9Sstevel@tonic-gate 	if (++tty_npushed == 1 && !already_ppp) {
9367c478bd9Sstevel@tonic-gate 		if (strioctl(fd, PPPIO_LASTMOD, NULL, 0, 0) < 0) {
9377c478bd9Sstevel@tonic-gate 			warn("unable to set LASTMOD on %s: %m", text);
9387c478bd9Sstevel@tonic-gate 		}
9397c478bd9Sstevel@tonic-gate 	}
9407c478bd9Sstevel@tonic-gate 	return (0);
9417c478bd9Sstevel@tonic-gate }
9427c478bd9Sstevel@tonic-gate 
9437c478bd9Sstevel@tonic-gate /*
9447c478bd9Sstevel@tonic-gate  * establish_ppp()
9457c478bd9Sstevel@tonic-gate  *
9467c478bd9Sstevel@tonic-gate  * Turn the serial port into a ppp interface.
9477c478bd9Sstevel@tonic-gate  */
9487c478bd9Sstevel@tonic-gate int
establish_ppp(fd)9497c478bd9Sstevel@tonic-gate establish_ppp(fd)
9507c478bd9Sstevel@tonic-gate 	int fd;
9517c478bd9Sstevel@tonic-gate {
9527c478bd9Sstevel@tonic-gate 	int i;
9537c478bd9Sstevel@tonic-gate 	uint32_t x;
9547c478bd9Sstevel@tonic-gate 
9557c478bd9Sstevel@tonic-gate 	if (default_device && !notty) {
9567c478bd9Sstevel@tonic-gate 		tty_sid = getsid((pid_t)0);
9577c478bd9Sstevel@tonic-gate 	}
9587c478bd9Sstevel@tonic-gate 
9597c478bd9Sstevel@tonic-gate 	if (integrated_driver)
9607c478bd9Sstevel@tonic-gate 		return (pppfd);
9617c478bd9Sstevel@tonic-gate 
9627c478bd9Sstevel@tonic-gate 	/*
9637c478bd9Sstevel@tonic-gate 	 * Pop any existing modules off the tty stream
9647c478bd9Sstevel@tonic-gate 	 */
9657c478bd9Sstevel@tonic-gate 	for (i = 0; ; ++i) {
9667c478bd9Sstevel@tonic-gate 		if ((myioctl(fd, I_LOOK, tty_modules[i]) < 0) ||
9677c478bd9Sstevel@tonic-gate 		    (strcmp(tty_modules[i], "ptem") == 0) ||
9687c478bd9Sstevel@tonic-gate 		    (myioctl(fd, I_POP, (void *)0) < 0)) {
9697c478bd9Sstevel@tonic-gate 			break;
9707c478bd9Sstevel@tonic-gate 		}
9717c478bd9Sstevel@tonic-gate 	}
9727c478bd9Sstevel@tonic-gate 	tty_nmodules = i;
9737c478bd9Sstevel@tonic-gate 	/*
9747c478bd9Sstevel@tonic-gate 	 * Push the async hdlc module and the compressor module
9757c478bd9Sstevel@tonic-gate 	 */
9767c478bd9Sstevel@tonic-gate 	tty_npushed = 0;
9777c478bd9Sstevel@tonic-gate 	if (!sync_serial && !already_ppp &&
9787c478bd9Sstevel@tonic-gate 	    modpush(fd, AHDLC_MOD_NAME, "PPP async HDLC") < 0) {
9797c478bd9Sstevel@tonic-gate 		return (-1);
9807c478bd9Sstevel@tonic-gate 	}
9817c478bd9Sstevel@tonic-gate 	/*
9827c478bd9Sstevel@tonic-gate 	 * There's no need to push comp module if we don't intend
9837c478bd9Sstevel@tonic-gate 	 * to compress anything
9847c478bd9Sstevel@tonic-gate 	 */
9857c478bd9Sstevel@tonic-gate 	if (any_compressions()) {
9867c478bd9Sstevel@tonic-gate 		(void) modpush(fd, COMP_MOD_NAME, "PPP compression");
9877c478bd9Sstevel@tonic-gate 	}
9887c478bd9Sstevel@tonic-gate 
9897c478bd9Sstevel@tonic-gate 	/*
9907c478bd9Sstevel@tonic-gate 	 * Link the serial port under the PPP multiplexor
9917c478bd9Sstevel@tonic-gate 	 */
9927c478bd9Sstevel@tonic-gate 	if ((fdmuxid = myioctl(pppfd, I_LINK, (void *)fd)) < 0) {
9937c478bd9Sstevel@tonic-gate 		error("Can't link tty to PPP mux: %m");
9947c478bd9Sstevel@tonic-gate 		return (-1);
9957c478bd9Sstevel@tonic-gate 	}
9967c478bd9Sstevel@tonic-gate 	if (tty_npushed == 0 && !already_ppp) {
9977c478bd9Sstevel@tonic-gate 		if (strioctl(pppfd, PPPIO_LASTMOD, NULL, 0, 0) < 0) {
9987c478bd9Sstevel@tonic-gate 			warn("unable to set LASTMOD on PPP mux: %m");
9997c478bd9Sstevel@tonic-gate 		}
10007c478bd9Sstevel@tonic-gate 	}
10017c478bd9Sstevel@tonic-gate 	/*
10027c478bd9Sstevel@tonic-gate 	 * Debug configuration must occur *after* I_LINK.
10037c478bd9Sstevel@tonic-gate 	 */
10047c478bd9Sstevel@tonic-gate 	if (kdebugflag & 4) {
10057c478bd9Sstevel@tonic-gate 		x = PPPDBG_LOG + PPPDBG_AHDLC;
10067c478bd9Sstevel@tonic-gate 		if (strioctl(pppfd, PPPIO_DEBUG, &x, sizeof (x), 0) < 0) {
10077c478bd9Sstevel@tonic-gate 			warn("PPPIO_DEBUG ioctl for ahdlc module failed: %m");
10087c478bd9Sstevel@tonic-gate 		}
10097c478bd9Sstevel@tonic-gate 	}
10107c478bd9Sstevel@tonic-gate 	if (any_compressions() && (kdebugflag & 2)) {
10117c478bd9Sstevel@tonic-gate 		x = PPPDBG_LOG + PPPDBG_COMP;
10127c478bd9Sstevel@tonic-gate 		if (strioctl(pppfd, PPPIO_DEBUG, &x, sizeof (x), 0) < 0) {
10137c478bd9Sstevel@tonic-gate 			warn("PPPIO_DEBUG ioctl for comp module failed: %m");
10147c478bd9Sstevel@tonic-gate 		}
10157c478bd9Sstevel@tonic-gate 	}
10167c478bd9Sstevel@tonic-gate 	return (pppfd);
10177c478bd9Sstevel@tonic-gate }
10187c478bd9Sstevel@tonic-gate 
10197c478bd9Sstevel@tonic-gate /*
10207c478bd9Sstevel@tonic-gate  * restore_loop()
10217c478bd9Sstevel@tonic-gate  *
10227c478bd9Sstevel@tonic-gate  * Reattach the ppp unit to the loopback. This doesn't need to do anything
10237c478bd9Sstevel@tonic-gate  * because disestablish_ppp does it
10247c478bd9Sstevel@tonic-gate  */
10257c478bd9Sstevel@tonic-gate void
restore_loop()10267c478bd9Sstevel@tonic-gate restore_loop()
10277c478bd9Sstevel@tonic-gate {
10287c478bd9Sstevel@tonic-gate }
10297c478bd9Sstevel@tonic-gate 
10307c478bd9Sstevel@tonic-gate /*
10317c478bd9Sstevel@tonic-gate  * disestablish_ppp()
10327c478bd9Sstevel@tonic-gate  *
10337c478bd9Sstevel@tonic-gate  * Restore the serial port to normal operation.  It attempts to reconstruct
10347c478bd9Sstevel@tonic-gate  * the stream with the previously popped modules.  This shouldn't call die()
10357c478bd9Sstevel@tonic-gate  * because it's called from die().  Stream reconstruction is needed in case
10367c478bd9Sstevel@tonic-gate  * pppd is used for dial-in on /dev/tty and there's an option error.
10377c478bd9Sstevel@tonic-gate  */
10387c478bd9Sstevel@tonic-gate void
disestablish_ppp(fd)10397c478bd9Sstevel@tonic-gate disestablish_ppp(fd)
10407c478bd9Sstevel@tonic-gate 	int fd;
10417c478bd9Sstevel@tonic-gate {
10427c478bd9Sstevel@tonic-gate 	int i;
10437c478bd9Sstevel@tonic-gate 
10447c478bd9Sstevel@tonic-gate 	if (fdmuxid == -1 || integrated_driver) {
10457c478bd9Sstevel@tonic-gate 		return;
10467c478bd9Sstevel@tonic-gate 	}
10477c478bd9Sstevel@tonic-gate 	if (myioctl(pppfd, I_UNLINK, (void *)fdmuxid) < 0) {
10487c478bd9Sstevel@tonic-gate 		if (!hungup) {
10497c478bd9Sstevel@tonic-gate 			error("Can't unlink tty from PPP mux: %m");
10507c478bd9Sstevel@tonic-gate 		}
10517c478bd9Sstevel@tonic-gate 	}
10527c478bd9Sstevel@tonic-gate 	fdmuxid = -1;
10537c478bd9Sstevel@tonic-gate 	if (!hungup) {
10547c478bd9Sstevel@tonic-gate 		while (tty_npushed > 0 && myioctl(fd, I_POP, (void *)0) >= 0) {
10557c478bd9Sstevel@tonic-gate 			--tty_npushed;
10567c478bd9Sstevel@tonic-gate 		}
10577c478bd9Sstevel@tonic-gate 		for (i = tty_nmodules - 1; i >= 0; --i) {
10587c478bd9Sstevel@tonic-gate 			if (myioctl(fd, I_PUSH, tty_modules[i]) < 0) {
10597c478bd9Sstevel@tonic-gate 				error("Couldn't restore tty module %s: %m",
10607c478bd9Sstevel@tonic-gate 				    tty_modules[i]);
10617c478bd9Sstevel@tonic-gate 			}
10627c478bd9Sstevel@tonic-gate 		}
10637c478bd9Sstevel@tonic-gate 	}
10647c478bd9Sstevel@tonic-gate 	if (hungup && default_device && tty_sid > 0) {
10657c478bd9Sstevel@tonic-gate 		/*
10667c478bd9Sstevel@tonic-gate 		 * If we have received a hangup, we need to send a
10677c478bd9Sstevel@tonic-gate 		 * SIGHUP to the terminal's controlling process.
10687c478bd9Sstevel@tonic-gate 		 * The reason is that the original stream head for
10697c478bd9Sstevel@tonic-gate 		 * the terminal hasn't seen the M_HANGUP message
10707c478bd9Sstevel@tonic-gate 		 * (it went up through the ppp driver to the stream
10717c478bd9Sstevel@tonic-gate 		 * head for our fd to /dev/ppp).
10727c478bd9Sstevel@tonic-gate 		 */
10737c478bd9Sstevel@tonic-gate 		(void) kill(tty_sid, SIGHUP);
10747c478bd9Sstevel@tonic-gate 	}
10757c478bd9Sstevel@tonic-gate }
10767c478bd9Sstevel@tonic-gate 
10777c478bd9Sstevel@tonic-gate /*
10787c478bd9Sstevel@tonic-gate  * clean_check()
10797c478bd9Sstevel@tonic-gate  *
10807c478bd9Sstevel@tonic-gate  * Check whether the link seems not to be 8-bit clean
10817c478bd9Sstevel@tonic-gate  */
10827c478bd9Sstevel@tonic-gate void
clean_check()10837c478bd9Sstevel@tonic-gate clean_check()
10847c478bd9Sstevel@tonic-gate {
10857c478bd9Sstevel@tonic-gate 	uint32_t x;
10867c478bd9Sstevel@tonic-gate 	char *s = NULL;
10877c478bd9Sstevel@tonic-gate 
10887c478bd9Sstevel@tonic-gate 	/*
10897c478bd9Sstevel@tonic-gate 	 * Skip this is synchronous link is used, since spppasyn won't
10907c478bd9Sstevel@tonic-gate 	 * be anywhere in the stream below to handle the ioctl.
10917c478bd9Sstevel@tonic-gate 	 */
10927c478bd9Sstevel@tonic-gate 	if (sync_serial) {
10937c478bd9Sstevel@tonic-gate 		return;
10947c478bd9Sstevel@tonic-gate 	}
10957c478bd9Sstevel@tonic-gate 
10967c478bd9Sstevel@tonic-gate 	if (strioctl(pppfd, PPPIO_GCLEAN, &x, 0, sizeof (x)) < 0) {
10977c478bd9Sstevel@tonic-gate 		warn("unable to obtain serial link status: %m");
10987c478bd9Sstevel@tonic-gate 		return;
10997c478bd9Sstevel@tonic-gate 	}
11007c478bd9Sstevel@tonic-gate 	switch (~x) {
11017c478bd9Sstevel@tonic-gate 	case RCV_B7_0:
11027c478bd9Sstevel@tonic-gate 		s = "bit 7 set to 1";
11037c478bd9Sstevel@tonic-gate 		break;
11047c478bd9Sstevel@tonic-gate 	case RCV_B7_1:
11057c478bd9Sstevel@tonic-gate 		s = "bit 7 set to 0";
11067c478bd9Sstevel@tonic-gate 		break;
11077c478bd9Sstevel@tonic-gate 	case RCV_EVNP:
11087c478bd9Sstevel@tonic-gate 		s = "odd parity";
11097c478bd9Sstevel@tonic-gate 		break;
11107c478bd9Sstevel@tonic-gate 	case RCV_ODDP:
11117c478bd9Sstevel@tonic-gate 		s = "even parity";
11127c478bd9Sstevel@tonic-gate 		break;
11137c478bd9Sstevel@tonic-gate 	}
11147c478bd9Sstevel@tonic-gate 	if (s != NULL) {
11157c478bd9Sstevel@tonic-gate 		warn("Serial link is not 8-bit clean:");
11167c478bd9Sstevel@tonic-gate 		warn("All received characters had %s", s);
11177c478bd9Sstevel@tonic-gate 	}
11187c478bd9Sstevel@tonic-gate }
11197c478bd9Sstevel@tonic-gate 
11207c478bd9Sstevel@tonic-gate /*
11217c478bd9Sstevel@tonic-gate  * List of valid speeds.
11227c478bd9Sstevel@tonic-gate  */
11237c478bd9Sstevel@tonic-gate struct speed {
11247c478bd9Sstevel@tonic-gate 	int speed_int;
11257c478bd9Sstevel@tonic-gate 	int speed_val;
1126*d9c3e05cSJoshua M. Clulow } speeds[] = {
1127*d9c3e05cSJoshua M. Clulow 	{ 50,		B50 },
1128*d9c3e05cSJoshua M. Clulow 	{ 75,		B75 },
1129*d9c3e05cSJoshua M. Clulow 	{ 110,		B110 },
1130*d9c3e05cSJoshua M. Clulow 	{ 134,		B134 },
1131*d9c3e05cSJoshua M. Clulow 	{ 150,		B150 },
1132*d9c3e05cSJoshua M. Clulow 	{ 200,		B200 },
1133*d9c3e05cSJoshua M. Clulow 	{ 300,		B300 },
1134*d9c3e05cSJoshua M. Clulow 	{ 600,		B600 },
1135*d9c3e05cSJoshua M. Clulow 	{ 1200,		B1200 },
1136*d9c3e05cSJoshua M. Clulow 	{ 1800,		B1800 },
1137*d9c3e05cSJoshua M. Clulow 	{ 2400,		B2400 },
1138*d9c3e05cSJoshua M. Clulow 	{ 4800,		B4800 },
1139*d9c3e05cSJoshua M. Clulow 	{ 9600,		B9600 },
1140*d9c3e05cSJoshua M. Clulow 	{ 19200,	B19200 },
1141*d9c3e05cSJoshua M. Clulow 	{ 38400,	B38400 },
1142*d9c3e05cSJoshua M. Clulow 	{ 57600,	B57600 },
1143*d9c3e05cSJoshua M. Clulow 	{ 76800,	B76800 },
1144*d9c3e05cSJoshua M. Clulow 	{ 115200,	B115200 },
1145*d9c3e05cSJoshua M. Clulow 	{ 153600,	B153600 },
1146*d9c3e05cSJoshua M. Clulow 	{ 230400,	B230400 },
1147*d9c3e05cSJoshua M. Clulow 	{ 307200,	B307200 },
1148*d9c3e05cSJoshua M. Clulow 	{ 460800,	B460800 },
1149*d9c3e05cSJoshua M. Clulow 	{ 921600,	B921600 },
1150*d9c3e05cSJoshua M. Clulow 	{ 1000000,	B1000000 },
1151*d9c3e05cSJoshua M. Clulow 	{ 1152000,	B1152000 },
1152*d9c3e05cSJoshua M. Clulow 	{ 1500000,	B1500000 },
1153*d9c3e05cSJoshua M. Clulow 	{ 2000000,	B2000000 },
1154*d9c3e05cSJoshua M. Clulow 	{ 2500000,	B2500000 },
1155*d9c3e05cSJoshua M. Clulow 	{ 3000000,	B3000000 },
1156*d9c3e05cSJoshua M. Clulow 	{ 3500000,	B3500000 },
1157*d9c3e05cSJoshua M. Clulow 	{ 4000000,	B4000000 },
1158*d9c3e05cSJoshua M. Clulow 	{ 0,		0 }
11597c478bd9Sstevel@tonic-gate };
11607c478bd9Sstevel@tonic-gate 
11617c478bd9Sstevel@tonic-gate /*
11627c478bd9Sstevel@tonic-gate  * translate_speed()
11637c478bd9Sstevel@tonic-gate  *
11647c478bd9Sstevel@tonic-gate  * Translate from bits/second to a speed_t
11657c478bd9Sstevel@tonic-gate  */
11667c478bd9Sstevel@tonic-gate static int
translate_speed(int bps)11677c478bd9Sstevel@tonic-gate translate_speed(int bps)
11687c478bd9Sstevel@tonic-gate {
11697c478bd9Sstevel@tonic-gate 	struct speed *speedp;
11707c478bd9Sstevel@tonic-gate 
11717c478bd9Sstevel@tonic-gate 	if (bps == 0) {
11727c478bd9Sstevel@tonic-gate 		return (0);
11737c478bd9Sstevel@tonic-gate 	}
11747c478bd9Sstevel@tonic-gate 	for (speedp = speeds; speedp->speed_int; speedp++) {
11757c478bd9Sstevel@tonic-gate 		if (bps == speedp->speed_int) {
11767c478bd9Sstevel@tonic-gate 			return (speedp->speed_val);
11777c478bd9Sstevel@tonic-gate 		}
11787c478bd9Sstevel@tonic-gate 	}
11797c478bd9Sstevel@tonic-gate 	set_source(&speed_info);
11807c478bd9Sstevel@tonic-gate 	option_error("speed %d not supported", bps);
11817c478bd9Sstevel@tonic-gate 	return (0);
11827c478bd9Sstevel@tonic-gate }
11837c478bd9Sstevel@tonic-gate 
11847c478bd9Sstevel@tonic-gate /*
11857c478bd9Sstevel@tonic-gate  * baud_rate_of()
11867c478bd9Sstevel@tonic-gate  *
11877c478bd9Sstevel@tonic-gate  * Translate from a speed_t to bits/second
11887c478bd9Sstevel@tonic-gate  */
11897c478bd9Sstevel@tonic-gate static int
baud_rate_of(int speed)11907c478bd9Sstevel@tonic-gate baud_rate_of(int speed)
11917c478bd9Sstevel@tonic-gate {
11927c478bd9Sstevel@tonic-gate 	struct speed *speedp;
11937c478bd9Sstevel@tonic-gate