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 #define	RCSID	"$Id: sys-solaris.c,v 1.2 2000/04/21 01:27:57 masputra Exp $"
437c478bd9Sstevel@tonic-gate 
447c478bd9Sstevel@tonic-gate #include <limits.h>
457c478bd9Sstevel@tonic-gate #include <stdio.h>
467c478bd9Sstevel@tonic-gate #include <stddef.h>
477c478bd9Sstevel@tonic-gate #include <stdlib.h>
487c478bd9Sstevel@tonic-gate #include <ctype.h>
497c478bd9Sstevel@tonic-gate #include <errno.h>
507c478bd9Sstevel@tonic-gate #include <fcntl.h>
517c478bd9Sstevel@tonic-gate #include <unistd.h>
527c478bd9Sstevel@tonic-gate #include <netdb.h>
537c478bd9Sstevel@tonic-gate #include <termios.h>
547c478bd9Sstevel@tonic-gate #include <signal.h>
557c478bd9Sstevel@tonic-gate #include <string.h>
567c478bd9Sstevel@tonic-gate #include <stropts.h>
577c478bd9Sstevel@tonic-gate #include <utmpx.h>
587c478bd9Sstevel@tonic-gate #include <sys/types.h>
597c478bd9Sstevel@tonic-gate #include <sys/ioccom.h>
607c478bd9Sstevel@tonic-gate #include <sys/stream.h>
617c478bd9Sstevel@tonic-gate #include <sys/stropts.h>
627c478bd9Sstevel@tonic-gate #include <sys/socket.h>
637c478bd9Sstevel@tonic-gate #include <sys/sockio.h>
647c478bd9Sstevel@tonic-gate #include <sys/sysmacros.h>
657c478bd9Sstevel@tonic-gate #include <sys/systeminfo.h>
667c478bd9Sstevel@tonic-gate #include <sys/stat.h>
677c478bd9Sstevel@tonic-gate #include <net/if.h>
687c478bd9Sstevel@tonic-gate #include <net/if_arp.h>
697c478bd9Sstevel@tonic-gate #include <net/route.h>
707c478bd9Sstevel@tonic-gate #include <net/ppp_defs.h>
717c478bd9Sstevel@tonic-gate #include <net/pppio.h>
727c478bd9Sstevel@tonic-gate #include <net/if_types.h>
737c478bd9Sstevel@tonic-gate #include <net/if_dl.h>
747c478bd9Sstevel@tonic-gate #include <netinet/in.h>
757c478bd9Sstevel@tonic-gate #include <sys/tihdr.h>
767c478bd9Sstevel@tonic-gate #include <inet/mib2.h>
77ff550d0eSmasputra #include <inet/ip.h>
787c478bd9Sstevel@tonic-gate #include <sys/ethernet.h>
797c478bd9Sstevel@tonic-gate #include <sys/ser_sync.h>
80fb60e41dSss #include <libdlpi.h>
81*f53eecf5SJames Carlson #include <arpa/inet.h>
827c478bd9Sstevel@tonic-gate 
837c478bd9Sstevel@tonic-gate #include "pppd.h"
847c478bd9Sstevel@tonic-gate #include "fsm.h"
857c478bd9Sstevel@tonic-gate #include "lcp.h"
867c478bd9Sstevel@tonic-gate #include "ipcp.h"
877c478bd9Sstevel@tonic-gate #ifdef INET6
887c478bd9Sstevel@tonic-gate #include "ipv6cp.h"
897c478bd9Sstevel@tonic-gate #endif /* INET6 */
907c478bd9Sstevel@tonic-gate #include "ccp.h"
917c478bd9Sstevel@tonic-gate 
927c478bd9Sstevel@tonic-gate #if !defined(lint) && !defined(_lint)
937c478bd9Sstevel@tonic-gate static const char rcsid[] = RCSID;
947c478bd9Sstevel@tonic-gate #endif
957c478bd9Sstevel@tonic-gate 
967c478bd9Sstevel@tonic-gate #define	PPPSTRTIMOUT	1	/* Timeout in seconds for ioctl */
977c478bd9Sstevel@tonic-gate #define	MAX_POLLFDS	32
987c478bd9Sstevel@tonic-gate #define	NMODULES	32
997c478bd9Sstevel@tonic-gate 
1007c478bd9Sstevel@tonic-gate #ifndef MAXIFS
1017c478bd9Sstevel@tonic-gate #define	MAXIFS		256
1027c478bd9Sstevel@tonic-gate #endif /* MAXIFS */
1037c478bd9Sstevel@tonic-gate 
1047c478bd9Sstevel@tonic-gate #ifdef INET6
1057c478bd9Sstevel@tonic-gate #define	_IN6_LLX_FROM_EUI64(l, s, eui64, as, len)	\
1067c478bd9Sstevel@tonic-gate 	(s->sin6_addr.s6_addr32[0] = htonl(as),		\
1077c478bd9Sstevel@tonic-gate 	eui64_copy(eui64, s->sin6_addr.s6_addr32[2]),	\
1087c478bd9Sstevel@tonic-gate 	s->sin6_family = AF_INET6,			\
1097c478bd9Sstevel@tonic-gate 	l.lifr_addr.ss_family = AF_INET6,		\
1107c478bd9Sstevel@tonic-gate 	l.lifr_addrlen = len,				\
1117c478bd9Sstevel@tonic-gate 	l.lifr_addr = laddr)
1127c478bd9Sstevel@tonic-gate 
1137c478bd9Sstevel@tonic-gate /*
1147c478bd9Sstevel@tonic-gate  * Generate a link-local address with an interface-id based on the given
1157c478bd9Sstevel@tonic-gate  * EUI64 identifier.  Note that the len field is unused by SIOCSLIFADDR.
1167c478bd9Sstevel@tonic-gate  */
1177c478bd9Sstevel@tonic-gate #define	IN6_LLADDR_FROM_EUI64(l, s, eui64)		\
1187c478bd9Sstevel@tonic-gate 	_IN6_LLX_FROM_EUI64(l, s, eui64, 0xfe800000, 0)
1197c478bd9Sstevel@tonic-gate 
1207c478bd9Sstevel@tonic-gate /*
1217c478bd9Sstevel@tonic-gate  * Generate an EUI64 based interface-id for use by stateless address
1227c478bd9Sstevel@tonic-gate  * autoconfiguration.  These are required to be 64 bits long as defined in
1237c478bd9Sstevel@tonic-gate  * the "Interface Identifiers" section of the IPv6 Addressing Architecture
1247c478bd9Sstevel@tonic-gate  * (RFC3513).
1257c478bd9Sstevel@tonic-gate  */
1267c478bd9Sstevel@tonic-gate #define	IN6_LLTOKEN_FROM_EUI64(l, s, eui64) \
1277c478bd9Sstevel@tonic-gate 	_IN6_LLX_FROM_EUI64(l, s, eui64, 0, 64)
1287c478bd9Sstevel@tonic-gate #endif /* INET6 */
1297c478bd9Sstevel@tonic-gate 
1307c478bd9Sstevel@tonic-gate #define	IPCP_ENABLED	ipcp_protent.enabled_flag
1317c478bd9Sstevel@tonic-gate #ifdef INET6
1327c478bd9Sstevel@tonic-gate #define	IPV6CP_ENABLED	ipv6cp_protent.enabled_flag
1337c478bd9Sstevel@tonic-gate #endif /* INET6 */
1347c478bd9Sstevel@tonic-gate 
1357c478bd9Sstevel@tonic-gate /* For plug-in usage. */
1367c478bd9Sstevel@tonic-gate int (*sys_read_packet_hook) __P((int retv, struct strbuf *ctrl,
1377c478bd9Sstevel@tonic-gate     struct strbuf *data, int flags)) = NULL;
1387c478bd9Sstevel@tonic-gate bool already_ppp = 0;			/* Already in PPP mode */
1397c478bd9Sstevel@tonic-gate 
1407c478bd9Sstevel@tonic-gate static int pppfd = -1;			/* ppp driver fd */
1417c478bd9Sstevel@tonic-gate static int fdmuxid = -1;		/* driver mux fd */
1427c478bd9Sstevel@tonic-gate static int ipfd = -1;			/* IPv4 fd */
1437c478bd9Sstevel@tonic-gate static int ipmuxid = -1;		/* IPv4 mux fd */
1447c478bd9Sstevel@tonic-gate static int ip6fd = -1;			/* IPv6 fd */
1457c478bd9Sstevel@tonic-gate static int ip6muxid = -1;		/* IPv6 mux fd */
1467c478bd9Sstevel@tonic-gate static bool if6_is_up = 0;		/* IPv6 if marked as up */
1477c478bd9Sstevel@tonic-gate static bool if_is_up = 0;		/* IPv4 if marked as up */
1487c478bd9Sstevel@tonic-gate static bool restore_term = 0;		/* Restore TTY after closing link */
1497c478bd9Sstevel@tonic-gate static struct termios inittermios;	/* TTY settings */
1507c478bd9Sstevel@tonic-gate static struct winsize wsinfo;		/* Initial window size info */
1517c478bd9Sstevel@tonic-gate static pid_t tty_sid;			/* original sess ID for term */
1527c478bd9Sstevel@tonic-gate static struct pollfd pollfds[MAX_POLLFDS]; /* array of polled fd */
1537c478bd9Sstevel@tonic-gate static int n_pollfds = 0;		/* total count of polled fd */
1547c478bd9Sstevel@tonic-gate static int link_mtu;			/* link Maximum Transmit Unit */
1557c478bd9Sstevel@tonic-gate static int tty_nmodules;		/* total count of TTY modules used */
1567c478bd9Sstevel@tonic-gate static char tty_modules[NMODULES][FMNAMESZ+1];
1577c478bd9Sstevel@tonic-gate 					/* array of TTY modules used */
1587c478bd9Sstevel@tonic-gate static int tty_npushed;			/* total count of pushed PPP modules */
1597c478bd9Sstevel@tonic-gate static u_int32_t remote_addr;		/* IP address of peer */
1607c478bd9Sstevel@tonic-gate static u_int32_t default_route_gateway;	/* Gateway for default route */
1617c478bd9Sstevel@tonic-gate static u_int32_t proxy_arp_addr;	/* Addr for proxy arp entry */
1627c478bd9Sstevel@tonic-gate static u_int32_t lastlink_status;	/* Last link status info */
1637c478bd9Sstevel@tonic-gate 
1647c478bd9Sstevel@tonic-gate static bool use_plink = 0;		/* Use I_LINK by default */
1657c478bd9Sstevel@tonic-gate static bool plumbed = 0;		/* Use existing interface */
1667c478bd9Sstevel@tonic-gate 
1677c478bd9Sstevel@tonic-gate /* Default is to use /dev/sppp as driver. */
1687c478bd9Sstevel@tonic-gate static const char *drvnam = PPP_DEV_NAME;
1697c478bd9Sstevel@tonic-gate static bool integrated_driver = 0;
1707c478bd9Sstevel@tonic-gate static int extra_dev_fd = -1;		/* keep open until ready */
1717c478bd9Sstevel@tonic-gate 
1727c478bd9Sstevel@tonic-gate static option_t solaris_option_list[] = {
1737c478bd9Sstevel@tonic-gate 	{ "plink", o_bool, &use_plink, "Use I_PLINK instead of I_LINK",
1747c478bd9Sstevel@tonic-gate 	    OPT_PRIV|1 },
1757c478bd9Sstevel@tonic-gate 	{ "noplink", o_bool, &use_plink, "Use I_LINK instead of I_PLINK",
1767c478bd9Sstevel@tonic-gate 	    OPT_PRIV|0 },
1777c478bd9Sstevel@tonic-gate 	{ "plumbed", o_bool, &plumbed, "Use pre-plumbed interface",
1787c478bd9Sstevel@tonic-gate 	    OPT_PRIV|1 },
1797c478bd9Sstevel@tonic-gate 	{ NULL }
1807c478bd9Sstevel@tonic-gate };
1817c478bd9Sstevel@tonic-gate 
1827c478bd9Sstevel@tonic-gate /*
1837c478bd9Sstevel@tonic-gate  * Prototypes for procedures local to this file.
1847c478bd9Sstevel@tonic-gate  */
1857c478bd9Sstevel@tonic-gate static int translate_speed __P((int));
1867c478bd9Sstevel@tonic-gate static int baud_rate_of __P((int));
1877c478bd9Sstevel@tonic-gate static int get_ether_addr __P((u_int32_t, struct sockaddr_dl *, int));
1887c478bd9Sstevel@tonic-gate static int strioctl __P((int, int, void *, int, int));
1897c478bd9Sstevel@tonic-gate static int plumb_ipif __P((int));
1907c478bd9Sstevel@tonic-gate static int unplumb_ipif __P((int));
1917c478bd9Sstevel@tonic-gate #ifdef INET6
1927c478bd9Sstevel@tonic-gate static int plumb_ip6if __P((int));
1937c478bd9Sstevel@tonic-gate static int unplumb_ip6if __P((int));
1947c478bd9Sstevel@tonic-gate static int open_ip6fd(void);
1957c478bd9Sstevel@tonic-gate #endif /* INET6 */
1967c478bd9Sstevel@tonic-gate static int open_ipfd(void);
1977c478bd9Sstevel@tonic-gate static int sifroute __P((int, u_int32_t, u_int32_t, int, const char *));
1987c478bd9Sstevel@tonic-gate static int giflags __P((u_int32_t, bool *));
1997c478bd9Sstevel@tonic-gate static void handle_unbind __P((u_int32_t));
2007c478bd9Sstevel@tonic-gate static void handle_bind __P((u_int32_t));
2017c478bd9Sstevel@tonic-gate 
2027c478bd9Sstevel@tonic-gate /*
2037c478bd9Sstevel@tonic-gate  * Wrapper for regular ioctl; masks out EINTR.
2047c478bd9Sstevel@tonic-gate  */
2057c478bd9Sstevel@tonic-gate static int
2067c478bd9Sstevel@tonic-gate myioctl(int fd, int cmd, void *arg)
2077c478bd9Sstevel@tonic-gate {
2087c478bd9Sstevel@tonic-gate 	int retv;
2097c478bd9Sstevel@tonic-gate 
2107c478bd9Sstevel@tonic-gate 	errno = 0;
2117c478bd9Sstevel@tonic-gate 	while ((retv = ioctl(fd, cmd, arg)) == -1) {
2127c478bd9Sstevel@tonic-gate 		if (errno != EINTR)
2137c478bd9Sstevel@tonic-gate 			break;
2147c478bd9Sstevel@tonic-gate 	}
2157c478bd9Sstevel@tonic-gate 	return (retv);
2167c478bd9Sstevel@tonic-gate }
2177c478bd9Sstevel@tonic-gate 
2187c478bd9Sstevel@tonic-gate /*
2197c478bd9Sstevel@tonic-gate  * sys_check_options()
2207c478bd9Sstevel@tonic-gate  *
2217c478bd9Sstevel@tonic-gate  * Check the options that the user specified.
2227c478bd9Sstevel@tonic-gate  */
2237c478bd9Sstevel@tonic-gate int
2247c478bd9Sstevel@tonic-gate sys_check_options(void)
2257c478bd9Sstevel@tonic-gate {
2267c478bd9Sstevel@tonic-gate 	if (plumbed) {
2277c478bd9Sstevel@tonic-gate 		if (req_unit == -1)
2287c478bd9Sstevel@tonic-gate 			req_unit = -2;
2297c478bd9Sstevel@tonic-gate 		ipmuxid = 0;
2307c478bd9Sstevel@tonic-gate 		ip6muxid = 0;
2317c478bd9Sstevel@tonic-gate 	}
2327c478bd9Sstevel@tonic-gate 	return (1);
2337c478bd9Sstevel@tonic-gate }
2347c478bd9Sstevel@tonic-gate 
2357c478bd9Sstevel@tonic-gate /*
2367c478bd9Sstevel@tonic-gate  * sys_options()
2377c478bd9Sstevel@tonic-gate  *
2387c478bd9Sstevel@tonic-gate  * Add or remove system-specific options.
2397c478bd9Sstevel@tonic-gate  */
2407c478bd9Sstevel@tonic-gate void
2417c478bd9Sstevel@tonic-gate sys_options(void)
2427c478bd9Sstevel@tonic-gate {
2437c478bd9Sstevel@tonic-gate 	(void) remove_option("ktune");
2447c478bd9Sstevel@tonic-gate 	(void) remove_option("noktune");
2457c478bd9Sstevel@tonic-gate 	add_options(solaris_option_list);
2467c478bd9Sstevel@tonic-gate }
2477c478bd9Sstevel@tonic-gate 
2487c478bd9Sstevel@tonic-gate /*
2497c478bd9Sstevel@tonic-gate  * sys_ifname()
2507c478bd9Sstevel@tonic-gate  *
2517c478bd9Sstevel@tonic-gate  * Set ifname[] to contain name of IP interface for this unit.
2527c478bd9Sstevel@tonic-gate  */
2537c478bd9Sstevel@tonic-gate void
2547c478bd9Sstevel@tonic-gate sys_ifname(void)
2557c478bd9Sstevel@tonic-gate {
2567c478bd9Sstevel@tonic-gate 	const char *cp;
2577c478bd9Sstevel@tonic-gate 
2587c478bd9Sstevel@tonic-gate 	if ((cp = strrchr(drvnam, '/')) == NULL)
2597c478bd9Sstevel@tonic-gate 		cp = drvnam;
2607c478bd9Sstevel@tonic-gate 	else
2617c478bd9Sstevel@tonic-gate 		cp++;
2627c478bd9Sstevel@tonic-gate 	(void) slprintf(ifname, sizeof (ifname), "%s%d", cp, ifunit);
2637c478bd9Sstevel@tonic-gate }
2647c478bd9Sstevel@tonic-gate 
2657c478bd9Sstevel@tonic-gate /*
2667c478bd9Sstevel@tonic-gate  * ppp_available()
2677c478bd9Sstevel@tonic-gate  *
2687c478bd9Sstevel@tonic-gate  * Check whether the system has any ppp interfaces.
2697c478bd9Sstevel@tonic-gate  */
2707c478bd9Sstevel@tonic-gate int
2717c478bd9Sstevel@tonic-gate ppp_available(void)
2727c478bd9Sstevel@tonic-gate {
2737c478bd9Sstevel@tonic-gate 	struct stat buf;
2747c478bd9Sstevel@tonic-gate 	int fd;
2757c478bd9Sstevel@tonic-gate 	uint32_t typ;
2767c478bd9Sstevel@tonic-gate 
2777c478bd9Sstevel@tonic-gate 	if (stat(PPP_DEV_NAME, &buf) >= 0)
2787c478bd9Sstevel@tonic-gate 		return (1);
2797c478bd9Sstevel@tonic-gate 
2807c478bd9Sstevel@tonic-gate 	/*
2817c478bd9Sstevel@tonic-gate 	 * Simple check for system using Apollo POS without SUNWpppd
2827c478bd9Sstevel@tonic-gate 	 * (/dev/sppp) installed.  This is intentionally not kept open
2837c478bd9Sstevel@tonic-gate 	 * here, since the user may not have the same privileges (as
2847c478bd9Sstevel@tonic-gate 	 * determined later).  If Apollo were just shipped with the
2857c478bd9Sstevel@tonic-gate 	 * full complement of packages, this wouldn't be an issue.
2867c478bd9Sstevel@tonic-gate 	 */
2877c478bd9Sstevel@tonic-gate 	if (devnam[0] == '\0' &&
2887c478bd9Sstevel@tonic-gate 	    (fd = open(devnam, O_RDWR | O_NONBLOCK | O_NOCTTY)) >= 0) {
2897c478bd9Sstevel@tonic-gate 		if (strioctl(fd, PPPIO_GTYPE, &typ, 0, sizeof (typ)) >= 0 &&
2907c478bd9Sstevel@tonic-gate 		    typ == PPPTYP_MUX) {
2917c478bd9Sstevel@tonic-gate 			(void) close(fd);
2927c478bd9Sstevel@tonic-gate 			return (1);
2937c478bd9Sstevel@tonic-gate 		}
2947c478bd9Sstevel@tonic-gate 		(void) close(fd);
2957c478bd9Sstevel@tonic-gate 	}
2967c478bd9Sstevel@tonic-gate 	return (0);
2977c478bd9Sstevel@tonic-gate }
2987c478bd9Sstevel@tonic-gate 
2997c478bd9Sstevel@tonic-gate static int
3007c478bd9Sstevel@tonic-gate open_ipfd(void)
3017c478bd9Sstevel@tonic-gate {
3027c478bd9Sstevel@tonic-gate 	ipfd = open(IP_DEV_NAME, O_RDWR | O_NONBLOCK, 0);
3037c478bd9Sstevel@tonic-gate 	if (ipfd < 0) {
3047c478bd9Sstevel@tonic-gate 		error("Couldn't open IP device (%s): %m", IP_DEV_NAME);
3057c478bd9Sstevel@tonic-gate 	}
3067c478bd9Sstevel@tonic-gate 	return (ipfd);
3077c478bd9Sstevel@tonic-gate }
3087c478bd9Sstevel@tonic-gate 
3097c478bd9Sstevel@tonic-gate static int
3107c478bd9Sstevel@tonic-gate read_ip_interface(int unit)
3117c478bd9Sstevel@tonic-gate {
3127c478bd9Sstevel@tonic-gate 	struct ifreq ifr;
3137c478bd9Sstevel@tonic-gate 	struct sockaddr_in sin;
3147c478bd9Sstevel@tonic-gate 
3157c478bd9Sstevel@tonic-gate 	if (ipfd == -1 && open_ipfd() == -1)
3167c478bd9Sstevel@tonic-gate 		return (0);
3177c478bd9Sstevel@tonic-gate 
3187c478bd9Sstevel@tonic-gate 	BZERO(&ifr, sizeof (ifr));
3197c478bd9Sstevel@tonic-gate 	(void) strlcpy(ifr.ifr_name, ifname, sizeof (ifr.ifr_name));
3207c478bd9Sstevel@tonic-gate 
3217c478bd9Sstevel@tonic-gate 	/* Get the existing MTU */
3227c478bd9Sstevel@tonic-gate 	if (myioctl(ipfd, SIOCGIFMTU, &ifr) < 0) {
3237c478bd9Sstevel@tonic-gate 		warn("Couldn't get IP MTU on %s: %m", ifr.ifr_name);
3247c478bd9Sstevel@tonic-gate 		return (0);
3257c478bd9Sstevel@tonic-gate 	}
3267c478bd9Sstevel@tonic-gate 	dbglog("got MTU %d from interface", ifr.ifr_metric);
3277c478bd9Sstevel@tonic-gate 	if (ifr.ifr_metric != 0 &&
3287c478bd9Sstevel@tonic-gate 	    (lcp_allowoptions[unit].mru == 0 ||
329fb60e41dSss 	    lcp_allowoptions[unit].mru > ifr.ifr_metric))
3307c478bd9Sstevel@tonic-gate 		lcp_allowoptions[unit].mru = ifr.ifr_metric;
3317c478bd9Sstevel@tonic-gate 
3327c478bd9Sstevel@tonic-gate 	/* Get the local IP address */
3337c478bd9Sstevel@tonic-gate 	if (ipcp_wantoptions[unit].ouraddr == 0 ||
3347c478bd9Sstevel@tonic-gate 	    ipcp_from_hostname) {
3357c478bd9Sstevel@tonic-gate 		if (myioctl(ipfd, SIOCGIFADDR, &ifr) < 0) {
3367c478bd9Sstevel@tonic-gate 			warn("Couldn't get local IP address (%s): %m",
3377c478bd9Sstevel@tonic-gate 			    ifr.ifr_name);
3387c478bd9Sstevel@tonic-gate 			return (0);
3397c478bd9Sstevel@tonic-gate 		}
3407c478bd9Sstevel@tonic-gate 		BCOPY(&ifr.ifr_addr, &sin, sizeof (struct sockaddr_in));
3417c478bd9Sstevel@tonic-gate 		ipcp_wantoptions[unit].ouraddr = sin.sin_addr.s_addr;
3427c478bd9Sstevel@tonic-gate 		dbglog("got local address %I from interface",
3437c478bd9Sstevel@tonic-gate 		    ipcp_wantoptions[unit].ouraddr);
3447c478bd9Sstevel@tonic-gate 	}
3457c478bd9Sstevel@tonic-gate 
3467c478bd9Sstevel@tonic-gate 	/* Get the remote IP address */
3477c478bd9Sstevel@tonic-gate 	if (ipcp_wantoptions[unit].hisaddr == 0) {
3487c478bd9Sstevel@tonic-gate 		if (myioctl(ipfd, SIOCGIFDSTADDR, &ifr) < 0) {
3497c478bd9Sstevel@tonic-gate 			warn("Couldn't get remote IP address (%s): %m",
3507c478bd9Sstevel@tonic-gate 			    ifr.ifr_name);
3517c478bd9Sstevel@tonic-gate 			return (0);
3527c478bd9Sstevel@tonic-gate 		}
3537c478bd9Sstevel@tonic-gate 		BCOPY(&ifr.ifr_dstaddr, &sin, sizeof (struct sockaddr_in));
3547c478bd9Sstevel@tonic-gate 		ipcp_wantoptions[unit].hisaddr = sin.sin_addr.s_addr;
3557c478bd9Sstevel@tonic-gate 		dbglog("got remote address %I from interface",
3567c478bd9Sstevel@tonic-gate 		    ipcp_wantoptions[unit].hisaddr);
3577c478bd9Sstevel@tonic-gate 	}
3587c478bd9Sstevel@tonic-gate 	return (1);
3597c478bd9Sstevel@tonic-gate }
3607c478bd9Sstevel@tonic-gate 
3617c478bd9Sstevel@tonic-gate #ifdef INET6
3627c478bd9Sstevel@tonic-gate static int
3637c478bd9Sstevel@tonic-gate open_ip6fd(void)
3647c478bd9Sstevel@tonic-gate {
3657c478bd9Sstevel@tonic-gate 	ip6fd = open(IP6_DEV_NAME, O_RDWR | O_NONBLOCK, 0);
3667c478bd9Sstevel@tonic-gate 	if (ip6fd < 0) {
3677c478bd9Sstevel@tonic-gate 		error("Couldn't open IPv6 device (%s): %m", IP6_DEV_NAME);
3687c478bd9Sstevel@tonic-gate 	}
3697c478bd9Sstevel@tonic-gate 	return (ip6fd);
3707c478bd9Sstevel@tonic-gate }
3717c478bd9Sstevel@tonic-gate 
3727c478bd9Sstevel@tonic-gate static int
3737c478bd9Sstevel@tonic-gate read_ipv6_interface(int unit)
3747c478bd9Sstevel@tonic-gate {
3757c478bd9Sstevel@tonic-gate 	struct lifreq lifr;
3767c478bd9Sstevel@tonic-gate 	struct sockaddr_in6 *sin6 = (struct sockaddr_in6 *)&lifr.lifr_addr;
3777c478bd9Sstevel@tonic-gate 
3787c478bd9Sstevel@tonic-gate 	if (ip6fd == -1 && open_ip6fd() == -1)
3797c478bd9Sstevel@tonic-gate 		return (0);
3807c478bd9Sstevel@tonic-gate 
3817c478bd9Sstevel@tonic-gate 	BZERO(&lifr, sizeof (lifr));
3827c478bd9Sstevel@tonic-gate 	(void) strlcpy(lifr.lifr_name, ifname, sizeof (lifr.lifr_name));
3837c478bd9Sstevel@tonic-gate 
3847c478bd9Sstevel@tonic-gate 	/* Get the existing MTU */
3857c478bd9Sstevel@tonic-gate 	if (myioctl(ip6fd, SIOCGLIFMTU, &lifr) < 0) {
3867c478bd9Sstevel@tonic-gate 		warn("Couldn't get IPv6 MTU on %s: %m", lifr.lifr_name);
3877c478bd9Sstevel@tonic-gate 		return (0);
3887c478bd9Sstevel@tonic-gate 	}
3897c478bd9Sstevel@tonic-gate 	if (lifr.lifr_mtu != 0 &&
3907c478bd9Sstevel@tonic-gate 	    (lcp_allowoptions[unit].mru == 0 ||
391fb60e41dSss 	    lcp_allowoptions[unit].mru > lifr.lifr_mtu))
3927c478bd9Sstevel@tonic-gate 		lcp_allowoptions[unit].mru = lifr.lifr_mtu;
3937c478bd9Sstevel@tonic-gate 
3947c478bd9Sstevel@tonic-gate 	/* Get the local IPv6 address */
3957c478bd9Sstevel@tonic-gate 	if (eui64_iszero(ipv6cp_wantoptions[unit].ourid) ||
3967c478bd9Sstevel@tonic-gate 	    (ipcp_from_hostname && ipv6cp_wantoptions[unit].use_ip)) {
3977c478bd9Sstevel@tonic-gate 		if (myioctl(ip6fd, SIOCGLIFADDR, &lifr) < 0) {
3987c478bd9Sstevel@tonic-gate 			warn("Couldn't get local IPv6 address (%s): %m",
3997c478bd9Sstevel@tonic-gate 			    lifr.lifr_name);
4007c478bd9Sstevel@tonic-gate 			return (0);
4017c478bd9Sstevel@tonic-gate 		}
4027c478bd9Sstevel@tonic-gate 		eui64_copy(sin6->sin6_addr.s6_addr32[2],
4037c478bd9Sstevel@tonic-gate 		    ipv6cp_wantoptions[unit].ourid);
4047c478bd9Sstevel@tonic-gate 	}
4057c478bd9Sstevel@tonic-gate 
4067c478bd9Sstevel@tonic-gate 	/* Get the remote IP address */
4077c478bd9Sstevel@tonic-gate 	if (eui64_iszero(ipv6cp_wantoptions[unit].hisid)) {
4087c478bd9Sstevel@tonic-gate 		if (myioctl(ip6fd, SIOCGLIFDSTADDR, &lifr) < 0) {
4097c478bd9Sstevel@tonic-gate 			warn("Couldn't get remote IPv6 address (%s): %m",
4107c478bd9Sstevel@tonic-gate 			    lifr.lifr_name);
4117c478bd9Sstevel@tonic-gate 			return (0);
4127c478bd9Sstevel@tonic-gate 		}
4137c478bd9Sstevel@tonic-gate 		eui64_copy(sin6->sin6_addr.s6_addr32[2],
4147c478bd9Sstevel@tonic-gate 		    ipv6cp_wantoptions[unit].hisid);
4157c478bd9Sstevel@tonic-gate 	}
4167c478bd9Sstevel@tonic-gate 	return (1);
4177c478bd9Sstevel@tonic-gate }
4187c478bd9Sstevel@tonic-gate #endif /* INET6 */
4197c478bd9Sstevel@tonic-gate 
4207c478bd9Sstevel@tonic-gate /*
4217c478bd9Sstevel@tonic-gate  * Read information on existing interface(s) and configure ourselves
4227c478bd9Sstevel@tonic-gate  * to negotiate appropriately.
4237c478bd9Sstevel@tonic-gate  */
4247c478bd9Sstevel@tonic-gate static void
4257c478bd9Sstevel@tonic-gate read_interface(int unit)
4267c478bd9Sstevel@tonic-gate {
4277c478bd9Sstevel@tonic-gate 	dbglog("reading existing interface data; %sip %sipv6",
4287c478bd9Sstevel@tonic-gate 	    IPCP_ENABLED ? "" : "!",
4297c478bd9Sstevel@tonic-gate #ifdef INET6
4307c478bd9Sstevel@tonic-gate 	    IPV6CP_ENABLED ? "" :
4317c478bd9Sstevel@tonic-gate #endif
4327c478bd9Sstevel@tonic-gate 	    "!");
4337c478bd9Sstevel@tonic-gate 	if (IPCP_ENABLED && !read_ip_interface(unit))
4347c478bd9Sstevel@tonic-gate 		IPCP_ENABLED = 0;
4357c478bd9Sstevel@tonic-gate #ifdef INET6
4367c478bd9Sstevel@tonic-gate 	if (IPV6CP_ENABLED && !read_ipv6_interface(unit))
4377c478bd9Sstevel@tonic-gate 		IPV6CP_ENABLED = 0;
4387c478bd9Sstevel@tonic-gate #endif
4397c478bd9Sstevel@tonic-gate }
4407c478bd9Sstevel@tonic-gate 
4417c478bd9Sstevel@tonic-gate /*
4427c478bd9Sstevel@tonic-gate  * sys_init()
4437c478bd9Sstevel@tonic-gate  *
4447c478bd9Sstevel@tonic-gate  * System-dependent initialization.
4457c478bd9Sstevel@tonic-gate  */
4467c478bd9Sstevel@tonic-gate void
4477c478bd9Sstevel@tonic-gate sys_init(bool open_as_user)
4487c478bd9Sstevel@tonic-gate {
4497c478bd9Sstevel@tonic-gate 	uint32_t x;
4507c478bd9Sstevel@tonic-gate 	uint32_t typ;
4517c478bd9Sstevel@tonic-gate 
4527c478bd9Sstevel@tonic-gate 	if (pppfd != -1) {
4537c478bd9Sstevel@tonic-gate 		return;
4547c478bd9Sstevel@tonic-gate 	}
4557c478bd9Sstevel@tonic-gate 
4567c478bd9Sstevel@tonic-gate 	if (!direct_tty && devnam[0] != '\0') {
4577c478bd9Sstevel@tonic-gate 		/*
4587c478bd9Sstevel@tonic-gate 		 * Check for integrated driver-like devices (such as
4597c478bd9Sstevel@tonic-gate 		 * POS).  These identify themselves as "PPP
4607c478bd9Sstevel@tonic-gate 		 * multiplexor" drivers.
4617c478bd9Sstevel@tonic-gate 		 */
4627c478bd9Sstevel@tonic-gate 		if (open_as_user)
4637c478bd9Sstevel@tonic-gate 			(void) seteuid(getuid());
4647c478bd9Sstevel@tonic-gate 		pppfd = open(devnam, O_RDWR | O_NONBLOCK);
4657c478bd9Sstevel@tonic-gate 		if (open_as_user)
4667c478bd9Sstevel@tonic-gate 			(void) seteuid(0);
4677c478bd9Sstevel@tonic-gate 		if (pppfd >= 0 &&
4687c478bd9Sstevel@tonic-gate 		    strioctl(pppfd, PPPIO_GTYPE, &typ, 0, sizeof (typ)) >= 0 &&
4697c478bd9Sstevel@tonic-gate 		    typ == PPPTYP_MUX) {
4707c478bd9Sstevel@tonic-gate 			integrated_driver = 1;
4717c478bd9Sstevel@tonic-gate 			drvnam = devnam;
4727c478bd9Sstevel@tonic-gate 		} else if (demand) {
4737c478bd9Sstevel@tonic-gate 			(void) close(pppfd);
4747c478bd9Sstevel@tonic-gate 			pppfd = -1;
4757c478bd9Sstevel@tonic-gate 		} else {
4767c478bd9Sstevel@tonic-gate 			extra_dev_fd = pppfd;
4777c478bd9Sstevel@tonic-gate 			pppfd = -1;
4787c478bd9Sstevel@tonic-gate 		}
4797c478bd9Sstevel@tonic-gate 	}
4807c478bd9Sstevel@tonic-gate 
4817c478bd9Sstevel@tonic-gate 	/*
4827c478bd9Sstevel@tonic-gate 	 * Open Solaris PPP device driver.
4837c478bd9Sstevel@tonic-gate 	 */
4847c478bd9Sstevel@tonic-gate 	if (pppfd < 0)
4857c478bd9Sstevel@tonic-gate 		pppfd = open(drvnam, O_RDWR | O_NONBLOCK);
4867c478bd9Sstevel@tonic-gate 	if (pppfd < 0) {
4877c478bd9Sstevel@tonic-gate 		fatal("Can't open %s: %m", drvnam);
4887c478bd9Sstevel@tonic-gate 	}
4897c478bd9Sstevel@tonic-gate 	if (kdebugflag & 1) {
4907c478bd9Sstevel@tonic-gate 		x = PPPDBG_LOG + PPPDBG_DRIVER;
4917c478bd9Sstevel@tonic-gate 		if (strioctl(pppfd, PPPIO_DEBUG, &x, sizeof (x), 0) < 0) {
4927c478bd9Sstevel@tonic-gate 			warn("PPPIO_DEBUG ioctl for mux failed: %m");
4937c478bd9Sstevel@tonic-gate 		}
4947c478bd9Sstevel@tonic-gate 	}
4957c478bd9Sstevel@tonic-gate 	/*
4967c478bd9Sstevel@tonic-gate 	 * Assign a new PPA and get its unit number.
4977c478bd9Sstevel@tonic-gate 	 */
4987c478bd9Sstevel@tonic-gate 	x = req_unit;
4997c478bd9Sstevel@tonic-gate 	if (strioctl(pppfd, PPPIO_NEWPPA, &x, sizeof (x), sizeof (x)) < 0) {
5007c478bd9Sstevel@tonic-gate 		if (errno == ENXIO && plumbed)
5017c478bd9Sstevel@tonic-gate 			fatal("No idle interfaces available for use");
5027c478bd9Sstevel@tonic-gate 		fatal("PPPIO_NEWPPA ioctl failed: %m");
5037c478bd9Sstevel@tonic-gate 	}
5047c478bd9Sstevel@tonic-gate 	ifunit = x;
5057c478bd9Sstevel@tonic-gate 	if (req_unit >= 0 && ifunit != req_unit) {
5067c478bd9Sstevel@tonic-gate 		if (plumbed)
5077c478bd9Sstevel@tonic-gate 			fatal("unable to get requested unit %d", req_unit);
5087c478bd9Sstevel@tonic-gate 		else
5097c478bd9Sstevel@tonic-gate 			warn("unable to get requested unit %d", req_unit);
5107c478bd9Sstevel@tonic-gate 	}
5117c478bd9Sstevel@tonic-gate 	/*
5127c478bd9Sstevel@tonic-gate 	 * Enable packet time-stamping when idle option is specified. Note
5137c478bd9Sstevel@tonic-gate 	 * that we need to only do this on the control stream. Subsequent
5147c478bd9Sstevel@tonic-gate 	 * streams attached to this control stream (ppa) will inherit
5157c478bd9Sstevel@tonic-gate 	 * the time-stamp bit.
5167c478bd9Sstevel@tonic-gate 	 */
5177c478bd9Sstevel@tonic-gate 	if (idle_time_limit > 0) {
5187c478bd9Sstevel@tonic-gate 		if (strioctl(pppfd, PPPIO_USETIMESTAMP, NULL, 0, 0) < 0) {
5197c478bd9Sstevel@tonic-gate 			warn("PPPIO_USETIMESTAMP ioctl failed: %m");
5207c478bd9Sstevel@tonic-gate 		}
5217c478bd9Sstevel@tonic-gate 	}
5227c478bd9Sstevel@tonic-gate 	if (plumbed) {
5237c478bd9Sstevel@tonic-gate 		sys_ifname();
5247c478bd9Sstevel@tonic-gate 		read_interface(0);
5257c478bd9Sstevel@tonic-gate 	}
5267c478bd9Sstevel@tonic-gate }
5277c478bd9Sstevel@tonic-gate 
5287c478bd9Sstevel@tonic-gate int
5297c478bd9Sstevel@tonic-gate sys_extra_fd(void)
5307c478bd9Sstevel@tonic-gate {
5317c478bd9Sstevel@tonic-gate 	int fd;
5327c478bd9Sstevel@tonic-gate 
5337c478bd9Sstevel@tonic-gate 	fd = extra_dev_fd;
5347c478bd9Sstevel@tonic-gate 	extra_dev_fd = -1;
5357c478bd9Sstevel@tonic-gate 	return (fd);
5367c478bd9Sstevel@tonic-gate }
5377c478bd9Sstevel@tonic-gate 
5387c478bd9Sstevel@tonic-gate static int
5397c478bd9Sstevel@tonic-gate open_udpfd(void)
5407c478bd9Sstevel@tonic-gate {
5417c478bd9Sstevel@tonic-gate 	int udpfd;
5427c478bd9Sstevel@tonic-gate 
5437c478bd9Sstevel@tonic-gate 	udpfd = open(UDP_DEV_NAME, O_RDWR | O_NONBLOCK, 0);
5447c478bd9Sstevel@tonic-gate 	if (udpfd < 0) {
5457c478bd9Sstevel@tonic-gate 		error("Couldn't open UDP device (%s): %m", UDP_DEV_NAME);
5467c478bd9Sstevel@tonic-gate 	}
5477c478bd9Sstevel@tonic-gate 	return (udpfd);
5487c478bd9Sstevel@tonic-gate }
5497c478bd9Sstevel@tonic-gate 
5507c478bd9Sstevel@tonic-gate /*
5517c478bd9Sstevel@tonic-gate  * plumb_ipif()
5527c478bd9Sstevel@tonic-gate  *
5537c478bd9Sstevel@tonic-gate  * Perform IP interface plumbing.
5547c478bd9Sstevel@tonic-gate  */
5557c478bd9Sstevel@tonic-gate /*ARGSUSED*/
5567c478bd9Sstevel@tonic-gate static int
5577c478bd9Sstevel@tonic-gate plumb_ipif(int unit)
5587c478bd9Sstevel@tonic-gate {
5597c478bd9Sstevel@tonic-gate 	int udpfd = -1, tmpfd;
5607c478bd9Sstevel@tonic-gate 	uint32_t x;
5617c478bd9Sstevel@tonic-gate 	struct ifreq ifr;
5627c478bd9Sstevel@tonic-gate 
5637c478bd9Sstevel@tonic-gate 	if (!IPCP_ENABLED || (ifunit == -1) || (pppfd == -1)) {
5647c478bd9Sstevel@tonic-gate 		return (0);
5657c478bd9Sstevel@tonic-gate 	}
5667c478bd9Sstevel@tonic-gate 	if (plumbed)
5677c478bd9Sstevel@tonic-gate 		return (1);
5687c478bd9Sstevel@tonic-gate 	if (ipfd == -1 && open_ipfd() == -1)
5697c478bd9Sstevel@tonic-gate 		return (0);
5707c478bd9Sstevel@tonic-gate 	if (use_plink && (udpfd = open_udpfd()) == -1)
5717c478bd9Sstevel@tonic-gate 		return (0);
5727c478bd9Sstevel@tonic-gate 	tmpfd = open(drvnam, O_RDWR | O_NONBLOCK, 0);
5737c478bd9Sstevel@tonic-gate 	if (tmpfd < 0) {
5747c478bd9Sstevel@tonic-gate 		error("Couldn't open PPP device (%s): %m", drvnam);
5757c478bd9Sstevel@tonic-gate 		if (udpfd != -1)
5767c478bd9Sstevel@tonic-gate 			(void) close(udpfd);
5777c478bd9Sstevel@tonic-gate 		return (0);
5787c478bd9Sstevel@tonic-gate 	}
5797c478bd9Sstevel@tonic-gate 	if (kdebugflag & 1) {
5807c478bd9Sstevel@tonic-gate 		x = PPPDBG_LOG + PPPDBG_DRIVER;
5817c478bd9Sstevel@tonic-gate 		if (strioctl(tmpfd, PPPIO_DEBUG, &x, sizeof (x), 0) < 0) {
5827c478bd9Sstevel@tonic-gate 			warn("PPPIO_DEBUG ioctl for mux failed: %m");
5837c478bd9Sstevel@tonic-gate 		}
5847c478bd9Sstevel@tonic-gate 	}
5857c478bd9Sstevel@tonic-gate 	if (myioctl(tmpfd, I_PUSH, IP_MOD_NAME) < 0) {
5867c478bd9Sstevel@tonic-gate 		error("Couldn't push IP module (%s): %m", IP_MOD_NAME);
5877c478bd9Sstevel@tonic-gate 		goto err_ret;
5887c478bd9Sstevel@tonic-gate 	}
5897c478bd9Sstevel@tonic-gate 	/*
5907c478bd9Sstevel@tonic-gate 	 * Assign ppa according to the unit number returned by ppp device
5917c478bd9Sstevel@tonic-gate 	 * after plumbing is completed above.  Without setting the ppa, ip
5927c478bd9Sstevel@tonic-gate 	 * module will return EINVAL upon setting the interface UP
5937c478bd9Sstevel@tonic-gate 	 * (SIOCSxIFFLAGS).  This is because ip module in 2.8 expects two
5947c478bd9Sstevel@tonic-gate 	 * DLPI_INFO_REQ to be sent down to the driver (below ip) before
5957c478bd9Sstevel@tonic-gate 	 * IFF_UP bit can be set. Plumbing the device causes one DLPI_INFO_REQ
5967c478bd9Sstevel@tonic-gate 	 * to be sent down, and the second DLPI_INFO_REQ is sent upon receiving
5977c478bd9Sstevel@tonic-gate 	 * IF_UNITSEL (old) or SIOCSLIFNAME (new) ioctls. Such setting of the
5987c478bd9Sstevel@tonic-gate 	 * ppa is required because the ppp DLPI provider advertises itself as
5997c478bd9Sstevel@tonic-gate 	 * a DLPI style 2 type, which requires a point of attachment to be
6007c478bd9Sstevel@tonic-gate 	 * specified. The only way the user can specify a point of attachment
6017c478bd9Sstevel@tonic-gate 	 * is via SIOCSLIFNAME or IF_UNITSEL.  Such changes in the behavior of
6027c478bd9Sstevel@tonic-gate 	 * ip module was made to meet new or evolving standards requirements.
6037c478bd9Sstevel@tonic-gate 	 */
6047c478bd9Sstevel@tonic-gate 	if (myioctl(tmpfd, IF_UNITSEL, &ifunit) < 0) {
6057c478bd9Sstevel@tonic-gate 		error("Couldn't set ppa for unit %d: %m", ifunit);
6067c478bd9Sstevel@tonic-gate 		goto err_ret;
6077c478bd9Sstevel@tonic-gate 	}
6087c478bd9Sstevel@tonic-gate 	if (use_plink) {
6097c478bd9Sstevel@tonic-gate 		ipmuxid = myioctl(udpfd, I_PLINK, (void *)tmpfd);
6107c478bd9Sstevel@tonic-gate 		if (ipmuxid < 0) {
6117c478bd9Sstevel@tonic-gate 			error("Can't I_PLINK PPP device to IP: %m");
6127c478bd9Sstevel@tonic-gate 			goto err_ret;
6137c478bd9Sstevel@tonic-gate 		}
6147c478bd9Sstevel@tonic-gate 	} else {
6157c478bd9Sstevel@tonic-gate 		ipmuxid = myioctl(ipfd, I_LINK, (void *)tmpfd);
6167c478bd9Sstevel@tonic-gate 		if (ipmuxid < 0) {
6177c478bd9Sstevel@tonic-gate 			error("Can't I_LINK PPP device to IP: %m");
6187c478bd9Sstevel@tonic-gate 			goto err_ret;
6197c478bd9Sstevel@tonic-gate 		}
6207c478bd9Sstevel@tonic-gate 	}
6217c478bd9Sstevel@tonic-gate 	BZERO(&ifr, sizeof (ifr));
6227c478bd9Sstevel@tonic-gate 	(void) strlcpy(ifr.ifr_name, ifname, sizeof (ifr.ifr_name));
6237c478bd9Sstevel@tonic-gate 	ifr.ifr_ip_muxid = ipmuxid;
6247c478bd9Sstevel@tonic-gate 	ifr.ifr_arp_muxid = -1;
6257c478bd9Sstevel@tonic-gate 	if (myioctl(ipfd, SIOCSIFMUXID, (caddr_t)&ifr) < 0) {
6267c478bd9Sstevel@tonic-gate 		error("Can't set mux ID SIOCSIFMUXID on %s: %m", ifname);
6277c478bd9Sstevel@tonic-gate 		goto err_ret;
6287c478bd9Sstevel@tonic-gate 	}
6297c478bd9Sstevel@tonic-gate 	if (udpfd != -1)
6307c478bd9Sstevel@tonic-gate 		(void) close(udpfd);
6317c478bd9Sstevel@tonic-gate 	(void) close(tmpfd);
6327c478bd9Sstevel@tonic-gate 	return (1);
6337c478bd9Sstevel@tonic-gate err_ret:
6347c478bd9Sstevel@tonic-gate 	if (udpfd != -1)
6357c478bd9Sstevel@tonic-gate 		(void) close(udpfd);
6367c478bd9Sstevel@tonic-gate 	(void) close(tmpfd);
6377c478bd9Sstevel@tonic-gate 	return (0);
6387c478bd9Sstevel@tonic-gate }
6397c478bd9Sstevel@tonic-gate 
6407c478bd9Sstevel@tonic-gate /*
6417c478bd9Sstevel@tonic-gate  * unplumb_ipif()
6427c478bd9Sstevel@tonic-gate  *
6437c478bd9Sstevel@tonic-gate  * Perform IP interface unplumbing.  Possibly called from die(), so there
6447c478bd9Sstevel@tonic-gate  * shouldn't be any call to die() or fatal() here.
6457c478bd9Sstevel@tonic-gate  */
6467c478bd9Sstevel@tonic-gate static int
6477c478bd9Sstevel@tonic-gate unplumb_ipif(int unit)
6487c478bd9Sstevel@tonic-gate {
6497c478bd9Sstevel@tonic-gate 	int udpfd = -1, fd = -1;
6507c478bd9Sstevel@tonic-gate 	int id;
6517c478bd9Sstevel@tonic-gate 	struct lifreq lifr;
6527c478bd9Sstevel@tonic-gate 
6537c478bd9Sstevel@tonic-gate 	if (!IPCP_ENABLED || (ifunit == -1)) {
6547c478bd9Sstevel@tonic-gate 		return (0);
6557c478bd9Sstevel@tonic-gate 	}
6567c478bd9Sstevel@tonic-gate 	if (!plumbed && (ipmuxid == -1 || (ipfd == -1 && !use_plink)))
6577c478bd9Sstevel@tonic-gate 		return (1);
6587c478bd9Sstevel@tonic-gate 	id = ipmuxid;
6597c478bd9Sstevel@tonic-gate 	if (!plumbed && use_plink) {
6607c478bd9Sstevel@tonic-gate 		if ((udpfd = open_udpfd()) == -1)
6617c478bd9Sstevel@tonic-gate 			return (0);
6627c478bd9Sstevel@tonic-gate 		/*
6637c478bd9Sstevel@tonic-gate 		 * Note: must re-get mux ID, since any intervening
6647c478bd9Sstevel@tonic-gate 		 * ifconfigs will change this.
6657c478bd9Sstevel@tonic-gate 		 */
6667c478bd9Sstevel@tonic-gate 		BZERO(&lifr, sizeof (lifr));
6677c478bd9Sstevel@tonic-gate 		(void) strlcpy(lifr.lifr_name, ifname,
6687c478bd9Sstevel@tonic-gate 		    sizeof (lifr.lifr_name));
6697c478bd9Sstevel@tonic-gate 		if (myioctl(ipfd, SIOCGLIFMUXID, (caddr_t)&lifr) < 0) {
6707c478bd9Sstevel@tonic-gate 			warn("Can't get mux fd: SIOCGLIFMUXID: %m");
6717c478bd9Sstevel@tonic-gate 		} else {
6727c478bd9Sstevel@tonic-gate 			id = lifr.lifr_ip_muxid;
6737c478bd9Sstevel@tonic-gate 			fd = myioctl(udpfd, _I_MUXID2FD, (void *)id);
6747c478bd9Sstevel@tonic-gate 			if (fd < 0) {
6757c478bd9Sstevel@tonic-gate 				warn("Can't get mux fd: _I_MUXID2FD: %m");
6767c478bd9Sstevel@tonic-gate 			}
6777c478bd9Sstevel@tonic-gate 		}
6787c478bd9Sstevel@tonic-gate 	}
6797c478bd9Sstevel@tonic-gate 	/*
6807c478bd9Sstevel@tonic-gate 	 * Mark down and unlink the ip interface.
6817c478bd9Sstevel@tonic-gate 	 */
6827c478bd9Sstevel@tonic-gate 	(void) sifdown(unit);
6837c478bd9Sstevel@tonic-gate 	if (default_route_gateway != 0) {
6847c478bd9Sstevel@tonic-gate 		(void) cifdefaultroute(0, default_route_gateway,
6857c478bd9Sstevel@tonic-gate 		    default_route_gateway);
6867c478bd9Sstevel@tonic-gate 	}
6877c478bd9Sstevel@tonic-gate 	if (proxy_arp_addr != 0) {
6887c478bd9Sstevel@tonic-gate 		(void) cifproxyarp(0, proxy_arp_addr);
6897c478bd9Sstevel@tonic-gate 	}
6907c478bd9Sstevel@tonic-gate 	ipmuxid = -1;
6917c478bd9Sstevel@tonic-gate 	if (plumbed)
6927c478bd9Sstevel@tonic-gate 		return (1);
6937c478bd9Sstevel@tonic-gate 	if (use_plink) {
6947c478bd9Sstevel@tonic-gate 		if (myioctl(udpfd, I_PUNLINK, (void *)id) < 0) {
6957c478bd9Sstevel@tonic-gate 			error("Can't I_PUNLINK PPP from IP: %m");
6967c478bd9Sstevel@tonic-gate 			if (fd != -1)
6977c478bd9Sstevel@tonic-gate 				(void) close(fd);
6987c478bd9Sstevel@tonic-gate 			(void) close(udpfd);
6997c478bd9Sstevel@tonic-gate 			return (0);
7007c478bd9Sstevel@tonic-gate 		}
7017c478bd9Sstevel@tonic-gate 		if (fd != -1)
7027c478bd9Sstevel@tonic-gate 			(void) close(fd);
7037c478bd9Sstevel@tonic-gate 		(void) close(udpfd);
7047c478bd9Sstevel@tonic-gate 	} else {
7057c478bd9Sstevel@tonic-gate 		if (myioctl(ipfd, I_UNLINK, (void *)id) < 0) {
7067c478bd9Sstevel@tonic-gate 			error("Can't I_UNLINK PPP from IP: %m");
7077c478bd9Sstevel@tonic-gate 			return (0);
7087c478bd9Sstevel@tonic-gate 		}
7097c478bd9Sstevel@tonic-gate 	}
7107c478bd9Sstevel@tonic-gate 	return (1);
7117c478bd9Sstevel@tonic-gate }
7127c478bd9Sstevel@tonic-gate 
7137c478bd9Sstevel@tonic-gate /*
7147c478bd9Sstevel@tonic-gate  * sys_cleanup()
7157c478bd9Sstevel@tonic-gate  *
7167c478bd9Sstevel@tonic-gate  * Restore any system state we modified before exiting: mark the
7177c478bd9Sstevel@tonic-gate  * interface down, delete default route and/or proxy arp entry. This
7187c478bd9Sstevel@tonic-gate  * should not call die() because it's called from die().
7197c478bd9Sstevel@tonic-gate  */
7207c478bd9Sstevel@tonic-gate void
7217c478bd9Sstevel@tonic-gate sys_cleanup()
7227c478bd9Sstevel@tonic-gate {
7237c478bd9Sstevel@tonic-gate 	(void) unplumb_ipif(0);
7247c478bd9Sstevel@tonic-gate #ifdef INET6
7257c478bd9Sstevel@tonic-gate 	(void) unplumb_ip6if(0);
7267c478bd9Sstevel@tonic-gate #endif /* INET6 */
7277c478bd9Sstevel@tonic-gate }
7287c478bd9Sstevel@tonic-gate 
7297c478bd9Sstevel@tonic-gate /*
7307c478bd9Sstevel@tonic-gate  * get_first_hwaddr()
7317c478bd9Sstevel@tonic-gate  *
7327c478bd9Sstevel@tonic-gate  * Stores the first hardware interface address found in the system
7337c478bd9Sstevel@tonic-gate  * into addr and return 1 upon success, or 0 if none is found.  This
7347c478bd9Sstevel@tonic-gate  * is also called from the multilink code.
7357c478bd9Sstevel@tonic-gate  */
7367c478bd9Sstevel@tonic-gate int
7377c478bd9Sstevel@tonic-gate get_first_hwaddr(addr, msize)
7387c478bd9Sstevel@tonic-gate 	uchar_t *addr;
7397c478bd9Sstevel@tonic-gate 	int msize;
7407c478bd9Sstevel@tonic-gate {
7417c478bd9Sstevel@tonic-gate 	struct ifconf ifc;
7427c478bd9Sstevel@tonic-gate 	register struct ifreq *pifreq;
7437c478bd9Sstevel@tonic-gate 	struct ifreq ifr;
7447c478bd9Sstevel@tonic-gate 	int fd, num_ifs, i;
7457c478bd9Sstevel@tonic-gate 	uint_t fl, req_size;
7467c478bd9Sstevel@tonic-gate 	char *req;
7477c478bd9Sstevel@tonic-gate 	boolean_t found;
7487c478bd9Sstevel@tonic-gate 
7497c478bd9Sstevel@tonic-gate 	if (addr == NULL) {
7507c478bd9Sstevel@tonic-gate 		return (0);
7517c478bd9Sstevel@tonic-gate 	}
7527c478bd9Sstevel@tonic-gate 	fd = socket(AF_INET, SOCK_DGRAM, 0);
7537c478bd9Sstevel@tonic-gate 	if (fd < 0) {
7547c478bd9Sstevel@tonic-gate 		error("get_first_hwaddr: error opening IP socket: %m");
7557c478bd9Sstevel@tonic-gate 		return (0);
7567c478bd9Sstevel@tonic-gate 	}
7577c478bd9Sstevel@tonic-gate 	/*
7587c478bd9Sstevel@tonic-gate 	 * Find out how many interfaces are running
7597c478bd9Sstevel@tonic-gate 	 */
7607c478bd9Sstevel@tonic-gate 	if (myioctl(fd, SIOCGIFNUM, (caddr_t)&num_ifs) < 0) {
7617c478bd9Sstevel@tonic-gate 		num_ifs = MAXIFS;
7627c478bd9Sstevel@tonic-gate 	}
7637c478bd9Sstevel@tonic-gate 	req_size = num_ifs * sizeof (struct ifreq);
7647c478bd9Sstevel@tonic-gate 	req = malloc(req_size);
7657c478bd9Sstevel@tonic-gate 	if (req == NULL) {
7667c478bd9Sstevel@tonic-gate 		novm("interface request structure.");
7677c478bd9Sstevel@tonic-gate 	}
7687c478bd9Sstevel@tonic-gate 	/*
7697c478bd9Sstevel@tonic-gate 	 * Get interface configuration info for all interfaces
7707c478bd9Sstevel@tonic-gate 	 */
7717c478bd9Sstevel@tonic-gate 	ifc.ifc_len = req_size;
7727c478bd9Sstevel@tonic-gate 	ifc.ifc_buf = req;
7737c478bd9Sstevel@tonic-gate 	if (myioctl(fd, SIOCGIFCONF, &ifc) < 0) {
7747c478bd9Sstevel@tonic-gate 		error("SIOCGIFCONF: %m");
7757c478bd9Sstevel@tonic-gate 		(void) close(fd);
7767c478bd9Sstevel@tonic-gate 		free(req);
7777c478bd9Sstevel@tonic-gate 		return (0);
7787c478bd9Sstevel@tonic-gate 	}
7797c478bd9Sstevel@tonic-gate 	/*
7807c478bd9Sstevel@tonic-gate 	 * And traverse each interface to look specifically for the first
7817c478bd9Sstevel@tonic-gate 	 * occurence of an Ethernet interface which has been marked up
7827c478bd9Sstevel@tonic-gate 	 */
7837c478bd9Sstevel@tonic-gate 	pifreq = ifc.ifc_req;
7847c478bd9Sstevel@tonic-gate 	found = 0;
7857c478bd9Sstevel@tonic-gate 	for (i = ifc.ifc_len / sizeof (struct ifreq); i > 0; i--, pifreq++) {
7867c478bd9Sstevel@tonic-gate 
7877c478bd9Sstevel@tonic-gate 		if (strchr(pifreq->ifr_name, ':') != NULL) {
7887c478bd9Sstevel@tonic-gate 			continue;
7897c478bd9Sstevel@tonic-gate 		}
7907c478bd9Sstevel@tonic-gate 		BZERO(&ifr, sizeof (ifr));
7917c478bd9Sstevel@tonic-gate 		(void) strncpy(ifr.ifr_name, pifreq->ifr_name,
7927c478bd9Sstevel@tonic-gate 		    sizeof (ifr.ifr_name));
7937c478bd9Sstevel@tonic-gate 		if (myioctl(fd, SIOCGIFFLAGS, &ifr) < 0) {
7947c478bd9Sstevel@tonic-gate 			continue;
7957c478bd9Sstevel@tonic-gate 		}
7967c478bd9Sstevel@tonic-gate 		fl = ifr.ifr_flags;
7977c478bd9Sstevel@tonic-gate 		if ((fl & (IFF_UP|IFF_BROADCAST|IFF_POINTOPOINT|IFF_LOOPBACK))
7987c478bd9Sstevel@tonic-gate 		    != (IFF_UP | IFF_BROADCAST)) {
7997c478bd9Sstevel@tonic-gate 			continue;
8007c478bd9Sstevel@tonic-gate 		}
8017c478bd9Sstevel@tonic-gate 		if (get_if_hwaddr(addr, msize, ifr.ifr_name) <= 0) {
8027c478bd9Sstevel@tonic-gate 			continue;
8037c478bd9Sstevel@tonic-gate 		}
8047c478bd9Sstevel@tonic-gate 		found = 1;
8057c478bd9Sstevel@tonic-gate 		break;
8067c478bd9Sstevel@tonic-gate 	}
8077c478bd9Sstevel@tonic-gate 	free(req);
8087c478bd9Sstevel@tonic-gate 	(void) close(fd);
8097c478bd9Sstevel@tonic-gate 
8107c478bd9Sstevel@tonic-gate 	return (found);
8117c478bd9Sstevel@tonic-gate }
8127c478bd9Sstevel@tonic-gate 
8137c478bd9Sstevel@tonic-gate /*
8147c478bd9Sstevel@tonic-gate  * get_if_hwaddr()
8157c478bd9Sstevel@tonic-gate  *
8167c478bd9Sstevel@tonic-gate  * Get the hardware address for the specified network interface device.
8177c478bd9Sstevel@tonic-gate  * Return the length of the MAC address (in bytes) or -1 if error.
8187c478bd9Sstevel@tonic-gate  */
8197c478bd9Sstevel@tonic-gate int
820fb60e41dSss get_if_hwaddr(uchar_t *addrp, int msize, char *linkname)
821fb60e41dSss {
822fb60e41dSss 	dlpi_handle_t dh;
823fb60e41dSss 	uchar_t physaddr[DLPI_PHYSADDR_MAX];
824fb60e41dSss 	size_t physaddrlen = sizeof (physaddr);
825fb60e41dSss 	int retv;
826fb60e41dSss 
827fb60e41dSss 	if ((addrp == NULL) || (linkname == NULL))
8287c478bd9Sstevel@tonic-gate 		return (-1);
829fb60e41dSss 
8307c478bd9Sstevel@tonic-gate 	/*
831fb60e41dSss 	 * Open the link and ask for hardware address.
8327c478bd9Sstevel@tonic-gate 	 */
833fb60e41dSss 	if ((retv = dlpi_open(linkname, &dh, 0)) != DLPI_SUCCESS) {
834fb60e41dSss 		error("Could not open %s: %s", linkname, dlpi_strerror(retv));
8357c478bd9Sstevel@tonic-gate 		return (-1);
8367c478bd9Sstevel@tonic-gate 	}
8377c478bd9Sstevel@tonic-gate 
838fb60e41dSss 	retv = dlpi_get_physaddr(dh, DL_CURR_PHYS_ADDR,
839fb60e41dSss 	    physaddr, &physaddrlen);
840fb60e41dSss 	dlpi_close(dh);
841fb60e41dSss 	if (retv != DLPI_SUCCESS) {
842fb60e41dSss 		error("Could not get physical address on %s: %s", linkname,
843fb60e41dSss 		    dlpi_strerror(retv));
8447c478bd9Sstevel@tonic-gate 		return (-1);
8457c478bd9Sstevel@tonic-gate 	}
8467c478bd9Sstevel@tonic-gate 
8477c478bd9Sstevel@tonic-gate 	/*
8487c478bd9Sstevel@tonic-gate 	 * Check if we have enough space to copy the address to.
8497c478bd9Sstevel@tonic-gate 	 */
850fb60e41dSss 	if (physaddrlen > msize)
8517c478bd9Sstevel@tonic-gate 		return (-1);
852fb60e41dSss 	(void) memcpy(addrp, physaddr, physaddrlen);
853fb60e41dSss 	return (physaddrlen);
8547c478bd9Sstevel@tonic-gate }
8557c478bd9Sstevel@tonic-gate 
8567c478bd9Sstevel@tonic-gate /*
8577c478bd9Sstevel@tonic-gate  * giflags()
8587c478bd9Sstevel@tonic-gate  */
8597c478bd9Sstevel@tonic-gate static int
8607c478bd9Sstevel@tonic-gate giflags(u_int32_t flag, bool *retval)
8617c478bd9Sstevel@tonic-gate {
8627c478bd9Sstevel@tonic-gate 	struct ifreq ifr;
8637c478bd9Sstevel@tonic-gate 	int fd;
8647c478bd9Sstevel@tonic-gate 
8657c478bd9Sstevel@tonic-gate 	*retval = 0;
8667c478bd9Sstevel@tonic-gate 	fd = socket(AF_INET, SOCK_DGRAM, 0);
8677c478bd9Sstevel@tonic-gate 	if (fd < 0) {
8687c478bd9Sstevel@tonic-gate 		error("giflags: error opening IP socket: %m");
8697c478bd9Sstevel@tonic-gate 		return (errno);
8707c478bd9Sstevel@tonic-gate 	}
8717c478bd9Sstevel@tonic-gate 
8727c478bd9Sstevel@tonic-gate 	BZERO(&ifr, sizeof (ifr));
8737c478bd9Sstevel@tonic-gate 	(void) strncpy(ifr.ifr_name, ifname, sizeof (ifr.ifr_name));
8747c478bd9Sstevel@tonic-gate 	if (ioctl(fd, SIOCGIFFLAGS, &ifr) < 0) {
8757c478bd9Sstevel@tonic-gate 		(void) close(fd);
8767c478bd9Sstevel@tonic-gate 		return (errno);
8777c478bd9Sstevel@tonic-gate 	}
8787c478bd9Sstevel@tonic-gate 
8797c478bd9Sstevel@tonic-gate 	*retval = ((ifr.ifr_flags & flag) != 0);
8807c478bd9Sstevel@tonic-gate 	(void) close(fd);
8817c478bd9Sstevel@tonic-gate 	return (errno);
8827c478bd9Sstevel@tonic-gate }
8837c478bd9Sstevel@tonic-gate 
8847c478bd9Sstevel@tonic-gate /*
8857c478bd9Sstevel@tonic-gate  * sys_close()
8867c478bd9Sstevel@tonic-gate  *
8877c478bd9Sstevel@tonic-gate  * Clean up in a child process before exec-ing.
8887c478bd9Sstevel@tonic-gate  */
8897c478bd9Sstevel@tonic-gate void
8907c478bd9Sstevel@tonic-gate sys_close()
8917c478bd9Sstevel@tonic-gate {
8927c478bd9Sstevel@tonic-gate 	if (ipfd != -1) {
8937c478bd9Sstevel@tonic-gate 		(void) close(ipfd);
8947c478bd9Sstevel@tonic-gate 		ipfd = -1;
8957c478bd9Sstevel@tonic-gate 	}
8967c478bd9Sstevel@tonic-gate #ifdef INET6
8977c478bd9Sstevel@tonic-gate 	if (ip6fd != -1) {
8987c478bd9Sstevel@tonic-gate 		(void) close(ip6fd);
8997c478bd9Sstevel@tonic-gate 		ip6fd = -1;
9007c478bd9Sstevel@tonic-gate 	}
9017c478bd9Sstevel@tonic-gate #endif /* INET6 */
9027c478bd9Sstevel@tonic-gate 	if (pppfd != -1) {
9037c478bd9Sstevel@tonic-gate 		(void) close(pppfd);
9047c478bd9Sstevel@tonic-gate 		pppfd = -1;
9057c478bd9Sstevel@tonic-gate 	}
9067c478bd9Sstevel@tonic-gate }
9077c478bd9Sstevel@tonic-gate 
9087c478bd9Sstevel@tonic-gate /*
9097c478bd9Sstevel@tonic-gate  * any_compressions()
9107c478bd9Sstevel@tonic-gate  *
9117c478bd9Sstevel@tonic-gate  * Check if compression is enabled or not.  In the STREAMS implementation of
9127c478bd9Sstevel@tonic-gate  * kernel-portion pppd, the comp STREAMS module performs the ACFC, PFC, as
9137c478bd9Sstevel@tonic-gate  * well CCP and VJ compressions. However, if the user has explicitly declare
9147c478bd9Sstevel@tonic-gate  * to not enable them from the command line, there is no point of having the
9157c478bd9Sstevel@tonic-gate  * comp module be pushed on the stream.
9167c478bd9Sstevel@tonic-gate  */
9177c478bd9Sstevel@tonic-gate static int
9187c478bd9Sstevel@tonic-gate any_compressions(void)
9197c478bd9Sstevel@tonic-gate {
9207c478bd9Sstevel@tonic-gate 	if ((!lcp_wantoptions[0].neg_accompression) &&
9217c478bd9Sstevel@tonic-gate 	    (!lcp_wantoptions[0].neg_pcompression) &&
9227c478bd9Sstevel@tonic-gate 	    (!ccp_protent.enabled_flag) &&
9237c478bd9Sstevel@tonic-gate 	    (!ipcp_wantoptions[0].neg_vj)) {
9247c478bd9Sstevel@tonic-gate 		return (0);
9257c478bd9Sstevel@tonic-gate 	}
9267c478bd9Sstevel@tonic-gate 	return (1);
9277c478bd9Sstevel@tonic-gate }
9287c478bd9Sstevel@tonic-gate 
9297c478bd9Sstevel@tonic-gate /*
9307c478bd9Sstevel@tonic-gate  * modpush()
9317c478bd9Sstevel@tonic-gate  *
9327c478bd9Sstevel@tonic-gate  * Push a module on the stream.
9337c478bd9Sstevel@tonic-gate  */
9347c478bd9Sstevel@tonic-gate static int
9357c478bd9Sstevel@tonic-gate modpush(int fd, const char *modname, const char *text)
9367c478bd9Sstevel@tonic-gate {
9377c478bd9Sstevel@tonic-gate 	if (myioctl(fd, I_PUSH, (void *)modname) < 0) {
9387c478bd9Sstevel@tonic-gate 		error("Couldn't push %s module: %m", text);
9397c478bd9Sstevel@tonic-gate 		return (-1);
9407c478bd9Sstevel@tonic-gate 	}
9417c478bd9Sstevel@tonic-gate 	if (++tty_npushed == 1 && !already_ppp) {
9427c478bd9Sstevel@tonic-gate 		if (strioctl(fd, PPPIO_LASTMOD, NULL, 0, 0) < 0) {
9437c478bd9Sstevel@tonic-gate 			warn("unable to set LASTMOD on %s: %m", text);
9447c478bd9Sstevel@tonic-gate 		}
9457c478bd9Sstevel@tonic-gate 	}
9467c478bd9Sstevel@tonic-gate 	return (0);
9477c478bd9Sstevel@tonic-gate }
9487c478bd9Sstevel@tonic-gate 
9497c478bd9Sstevel@tonic-gate /*
9507c478bd9Sstevel@tonic-gate  * establish_ppp()
9517c478bd9Sstevel@tonic-gate  *
9527c478bd9Sstevel@tonic-gate  * Turn the serial port into a ppp interface.
9537c478bd9Sstevel@tonic-gate  */
9547c478bd9Sstevel@tonic-gate int
9557c478bd9Sstevel@tonic-gate establish_ppp(fd)
9567c478bd9Sstevel@tonic-gate 	int fd;
9577c478bd9Sstevel@tonic-gate {
9587c478bd9Sstevel@tonic-gate 	int i;
9597c478bd9Sstevel@tonic-gate 	uint32_t x;
9607c478bd9Sstevel@tonic-gate 
9617c478bd9Sstevel@tonic-gate 	if (default_device && !notty) {
9627c478bd9Sstevel@tonic-gate 		tty_sid = getsid((pid_t)0);
9637c478bd9Sstevel@tonic-gate 	}
9647c478bd9Sstevel@tonic-gate 
9657c478bd9Sstevel@tonic-gate 	if (integrated_driver)
9667c478bd9Sstevel@tonic-gate 		return (pppfd);
9677c478bd9Sstevel@tonic-gate 
9687c478bd9Sstevel@tonic-gate 	/*
9697c478bd9Sstevel@tonic-gate 	 * Pop any existing modules off the tty stream
9707c478bd9Sstevel@tonic-gate 	 */
9717c478bd9Sstevel@tonic-gate 	for (i = 0; ; ++i) {
9727c478bd9Sstevel@tonic-gate 		if ((myioctl(fd, I_LOOK, tty_modules[i]) < 0) ||
9737c478bd9Sstevel@tonic-gate 		    (strcmp(tty_modules[i], "ptem") == 0) ||
9747c478bd9Sstevel@tonic-gate 		    (myioctl(fd, I_POP, (void *)0) < 0)) {
9757c478bd9Sstevel@tonic-gate 			break;
9767c478bd9Sstevel@tonic-gate 		}
9777c478bd9Sstevel@tonic-gate 	}
9787c478bd9Sstevel@tonic-gate 	tty_nmodules = i;
9797c478bd9Sstevel@tonic-gate 	/*
9807c478bd9Sstevel@tonic-gate 	 * Push the async hdlc module and the compressor module
9817c478bd9Sstevel@tonic-gate 	 */
9827c478bd9Sstevel@tonic-gate 	tty_npushed = 0;
9837c478bd9Sstevel@tonic-gate 	if (!sync_serial && !already_ppp &&
9847c478bd9Sstevel@tonic-gate 	    modpush(fd, AHDLC_MOD_NAME, "PPP async HDLC") < 0) {
9857c478bd9Sstevel@tonic-gate 		return (-1);
9867c478bd9Sstevel@tonic-gate 	}
9877c478bd9Sstevel@tonic-gate 	/*
9887c478bd9Sstevel@tonic-gate 	 * There's no need to push comp module if we don't intend
9897c478bd9Sstevel@tonic-gate 	 * to compress anything
9907c478bd9Sstevel@tonic-gate 	 */
9917c478bd9Sstevel@tonic-gate 	if (any_compressions()) {
9927c478bd9Sstevel@tonic-gate 		(void) modpush(fd, COMP_MOD_NAME, "PPP compression");
9937c478bd9Sstevel@tonic-gate 	}
9947c478bd9Sstevel@tonic-gate 
9957c478bd9Sstevel@tonic-gate 	/*
9967c478bd9Sstevel@tonic-gate 	 * Link the serial port under the PPP multiplexor
9977c478bd9Sstevel@tonic-gate 	 */
9987c478bd9Sstevel@tonic-gate 	if ((fdmuxid = myioctl(pppfd, I_LINK, (void *)fd)) < 0) {
9997c478bd9Sstevel@tonic-gate 		error("Can't link tty to PPP mux: %m");
10007c478bd9Sstevel@tonic-gate 		return (-1);
10017c478bd9Sstevel@tonic-gate 	}
10027c478bd9Sstevel@tonic-gate 	if (tty_npushed == 0 && !already_ppp) {
10037c478bd9Sstevel@tonic-gate 		if (strioctl(pppfd, PPPIO_LASTMOD, NULL, 0, 0) < 0) {
10047c478bd9Sstevel@tonic-gate 			warn("unable to set LASTMOD on PPP mux: %m");
10057c478bd9Sstevel@tonic-gate 		}
10067c478bd9Sstevel@tonic-gate 	}
10077c478bd9Sstevel@tonic-gate 	/*
10087c478bd9Sstevel@tonic-gate 	 * Debug configuration must occur *after* I_LINK.
10097c478bd9Sstevel@tonic-gate 	 */
10107c478bd9Sstevel@tonic-gate 	if (kdebugflag & 4) {
10117c478bd9Sstevel@tonic-gate 		x = PPPDBG_LOG + PPPDBG_AHDLC;
10127c478bd9Sstevel@tonic-gate 		if (strioctl(pppfd, PPPIO_DEBUG, &x, sizeof (x), 0) < 0) {
10137c478bd9Sstevel@tonic-gate 			warn("PPPIO_DEBUG ioctl for ahdlc module failed: %m");
10147c478bd9Sstevel@tonic-gate 		}
10157c478bd9Sstevel@tonic-gate 	}
10167c478bd9Sstevel@tonic-gate 	if (any_compressions() && (kdebugflag & 2)) {
10177c478bd9Sstevel@tonic-gate 		x = PPPDBG_LOG + PPPDBG_COMP;
10187c478bd9Sstevel@tonic-gate 		if (strioctl(pppfd, PPPIO_DEBUG, &x, sizeof (x), 0) < 0) {
10197c478bd9Sstevel@tonic-gate 			warn("PPPIO_DEBUG ioctl for comp module failed: %m");
10207c478bd9Sstevel@tonic-gate 		}
10217c478bd9Sstevel@tonic-gate 	}
10227c478bd9Sstevel@tonic-gate 	return (pppfd);
10237c478bd9Sstevel@tonic-gate }
10247c478bd9Sstevel@tonic-gate 
10257c478bd9Sstevel@tonic-gate /*
10267c478bd9Sstevel@tonic-gate  * restore_loop()
10277c478bd9Sstevel@tonic-gate  *
10287c478bd9Sstevel@tonic-gate  * Reattach the ppp unit to the loopback. This doesn't need to do anything
10297c478bd9Sstevel@tonic-gate  * because disestablish_ppp does it
10307c478bd9Sstevel@tonic-gate  */
10317c478bd9Sstevel@tonic-gate void
10327c478bd9Sstevel@tonic-gate restore_loop()
10337c478bd9Sstevel@tonic-gate {
10347c478bd9Sstevel@tonic-gate }
10357c478bd9Sstevel@tonic-gate 
10367c478bd9Sstevel@tonic-gate /*
10377c478bd9Sstevel@tonic-gate  * disestablish_ppp()
10387c478bd9Sstevel@tonic-gate  *
10397c478bd9Sstevel@tonic-gate  * Restore the serial port to normal operation.  It attempts to reconstruct
10407c478bd9Sstevel@tonic-gate  * the stream with the previously popped modules.  This shouldn't call die()
10417c478bd9Sstevel@tonic-gate  * because it's called from die().  Stream reconstruction is needed in case
10427c478bd9Sstevel@tonic-gate  * pppd is used for dial-in on /dev/tty and there's an option error.
10437c478bd9Sstevel@tonic-gate  */
10447c478bd9Sstevel@tonic-gate void
10457c478bd9Sstevel@tonic-gate disestablish_ppp(fd)
10467c478bd9Sstevel@tonic-gate 	int fd;
10477c478bd9Sstevel@tonic-gate {
10487c478bd9Sstevel@tonic-gate 	int i;
10497c478bd9Sstevel@tonic-gate 
10507c478bd9Sstevel@tonic-gate 	if (fdmuxid == -1 || integrated_driver) {
10517c478bd9Sstevel@tonic-gate 		return;
10527c478bd9Sstevel@tonic-gate 	}
10537c478bd9Sstevel@tonic-gate 	if (myioctl(pppfd, I_UNLINK, (void *)fdmuxid) < 0) {
10547c478bd9Sstevel@tonic-gate 		if (!hungup) {
10557c478bd9Sstevel@tonic-gate 			error("Can't unlink tty from PPP mux: %m");
10567c478bd9Sstevel@tonic-gate 		}
10577c478bd9Sstevel@tonic-gate 	}
10587c478bd9Sstevel@tonic-gate 	fdmuxid = -1;
10597c478bd9Sstevel@tonic-gate 	if (!hungup) {
10607c478bd9Sstevel@tonic-gate 		while (tty_npushed > 0 && myioctl(fd, I_POP, (void *)0) >= 0) {
10617c478bd9Sstevel@tonic-gate 			--tty_npushed;
10627c478bd9Sstevel@tonic-gate 		}
10637c478bd9Sstevel@tonic-gate 		for (i = tty_nmodules - 1; i >= 0; --i) {
10647c478bd9Sstevel@tonic-gate 			if (myioctl(fd, I_PUSH, tty_modules[i]) < 0) {
10657c478bd9Sstevel@tonic-gate 				error("Couldn't restore tty module %s: %m",
10667c478bd9Sstevel@tonic-gate 				    tty_modules[i]);
10677c478bd9Sstevel@tonic-gate 			}
10687c478bd9Sstevel@tonic-gate 		}
10697c478bd9Sstevel@tonic-gate 	}
10707c478bd9Sstevel@tonic-gate 	if (hungup && default_device && tty_sid > 0) {
10717c478bd9Sstevel@tonic-gate 		/*
10727c478bd9Sstevel@tonic-gate 		 * If we have received a hangup, we need to send a
10737c478bd9Sstevel@tonic-gate 		 * SIGHUP to the terminal's controlling process.
10747c478bd9Sstevel@tonic-gate 		 * The reason is that the original stream head for
10757c478bd9Sstevel@tonic-gate 		 * the terminal hasn't seen the M_HANGUP message
10767c478bd9Sstevel@tonic-gate 		 * (it went up through the ppp driver to the stream
10777c478bd9Sstevel@tonic-gate 		 * head for our fd to /dev/ppp).
10787c478bd9Sstevel@tonic-gate 		 */
10797c478bd9Sstevel@tonic-gate 		(void) kill(tty_sid, SIGHUP);
10807c478bd9Sstevel@tonic-gate 	}
10817c478bd9Sstevel@tonic-gate }
10827c478bd9Sstevel@tonic-gate 
10837c478bd9Sstevel@tonic-gate /*
10847c478bd9Sstevel@tonic-gate  * clean_check()
10857c478bd9Sstevel@tonic-gate  *
10867c478bd9Sstevel@tonic-gate  * Check whether the link seems not to be 8-bit clean
10877c478bd9Sstevel@tonic-gate  */
10887c478bd9Sstevel@tonic-gate void
10897c478bd9Sstevel@tonic-gate clean_check()
10907c478bd9Sstevel@tonic-gate {
10917c478bd9Sstevel@tonic-gate 	uint32_t x;
10927c478bd9Sstevel@tonic-gate 	char *s = NULL;
10937c478bd9Sstevel@tonic-gate 
10947c478bd9Sstevel@tonic-gate 	/*
10957c478bd9Sstevel@tonic-gate 	 * Skip this is synchronous link is used, since spppasyn won't
10967c478bd9Sstevel@tonic-gate 	 * be anywhere in the stream below to handle the ioctl.
10977c478bd9Sstevel@tonic-gate 	 */
10987c478bd9Sstevel@tonic-gate 	if (sync_serial) {
10997c478bd9Sstevel@tonic-gate 		return;
11007c478bd9Sstevel@tonic-gate 	}
11017c478bd9Sstevel@tonic-gate 
11027c478bd9Sstevel@tonic-gate 	if (strioctl(pppfd, PPPIO_GCLEAN, &x, 0, sizeof (x)) < 0) {
11037c478bd9Sstevel@tonic-gate 		warn("unable to obtain serial link status: %m");
11047c478bd9Sstevel@tonic-gate 		return;
11057c478bd9Sstevel@tonic-gate 	}
11067c478bd9Sstevel@tonic-gate 	switch (~x) {
11077c478bd9Sstevel@tonic-gate 	case RCV_B7_0:
11087c478bd9Sstevel@tonic-gate 		s = "bit 7 set to 1";
11097c478bd9Sstevel@tonic-gate 		break;
11107c478bd9Sstevel@tonic-gate 	case RCV_B7_1:
11117c478bd9Sstevel@tonic-gate 		s = "bit 7 set to 0";
11127c478bd9Sstevel@tonic-gate 		break;
11137c478bd9Sstevel@tonic-gate 	case RCV_EVNP:
11147c478bd9Sstevel@tonic-gate 		s = "odd parity";
11157c478bd9Sstevel@tonic-gate 		break;
11167c478bd9Sstevel@tonic-gate 	case RCV_ODDP:
11177c478bd9Sstevel@tonic-gate 		s = "even parity";
11187c478bd9Sstevel@tonic-gate 		break;
11197c478bd9Sstevel@tonic-gate 	}
11207c478bd9Sstevel@tonic-gate 	if (s != NULL) {
11217c478bd9Sstevel@tonic-gate 		warn("Serial link is not 8-bit clean:");
11227c478bd9Sstevel@tonic-gate 		warn("All received characters had %s", s);
11237c478bd9Sstevel@tonic-gate 	}
11247c478bd9Sstevel@tonic-gate }
11257c478bd9Sstevel@tonic-gate 
11267c478bd9Sstevel@tonic-gate /*
11277c478bd9Sstevel@tonic-gate  * List of valid speeds.
11287c478bd9Sstevel@tonic-gate  */
11297c478bd9Sstevel@tonic-gate struct speed {
11307c478bd9Sstevel@tonic-gate 	int speed_int;
11317c478bd9Sstevel@tonic-gate 	int speed_val;
11327c478bd9Sstevel@tonic-gate } speeds [] = {
11337c478bd9Sstevel@tonic-gate #ifdef B50
11347c478bd9Sstevel@tonic-gate 	{ 50, B50 },
11357c478bd9Sstevel@tonic-gate #endif
11367c478bd9Sstevel@tonic-gate #ifdef B75
11377c478bd9Sstevel@tonic-gate 	{ 75, B75 },
11387c478bd9Sstevel@tonic-gate #endif
11397c478bd9Sstevel@tonic-gate #ifdef B110
11407c478bd9Sstevel@tonic-gate 	{ 110, B110 },
11417c478bd9Sstevel@tonic-gate #endif
11427c478bd9Sstevel@tonic-gate #ifdef B134
11437c478bd9Sstevel@tonic-gate 	{ 134, B134 },
11447c478bd9Sstevel@tonic-gate #endif
11457c478bd9Sstevel@tonic-gate #ifdef B150
11467c478bd9Sstevel@tonic-gate 	{ 150, B150 },
11477c478bd9Sstevel@tonic-gate #endif
11487c478bd9Sstevel@tonic-gate #ifdef B200
11497c478bd9Sstevel@tonic-gate 	{ 200, B200 },
11507c478bd9Sstevel@tonic-gate #endif
11517c478bd9Sstevel@tonic-gate #ifdef B300
11527c478bd9Sstevel@tonic-gate 	{ 300, B300 },
11537c478bd9Sstevel@tonic-gate #endif
11547c478bd9Sstevel@tonic-gate #ifdef B600
11557c478bd9Sstevel@tonic-gate 	{ 600, B600 },
11567c478bd9Sstevel@tonic-gate #endif
11577c478bd9Sstevel@tonic-gate #ifdef B1200
11587c478bd9Sstevel@tonic-gate 	{ 1200, B1200 },
11597c478bd9Sstevel@tonic-gate #endif
11607c478bd9Sstevel@tonic-gate #ifdef B1800
11617c478bd9Sstevel@tonic-gate 	{ 1800, B1800 },
11627c478bd9Sstevel@tonic-gate #endif
11637c478bd9Sstevel@tonic-gate #ifdef B2000
11647c478bd9Sstevel@tonic-gate 	{ 2000, B2000 },
11657c478bd9Sstevel@tonic-gate #endif
11667c478bd9Sstevel@tonic-gate #ifdef B2400
11677c478bd9Sstevel@tonic-gate 	{ 2400, B2400 },
11687c478bd9Sstevel@tonic-gate #endif
11697c478bd9Sstevel@tonic-gate #ifdef B3600
11707c478bd9Sstevel@tonic-gate 	{ 3600, B3600 },
11717c478bd9Sstevel@tonic-gate #endif
11727c478bd9Sstevel@tonic-gate #ifdef B4800
11737c478bd9Sstevel@tonic-gate 	{ 4800, B4800 },
11747c478bd9Sstevel@tonic-gate #endif
11757c478bd9Sstevel@tonic-gate #ifdef B7200
11767c478bd9Sstevel@tonic-gate 	{ 7200, B7200 },
11777c478bd9Sstevel@tonic-gate #endif
11787c478bd9Sstevel@tonic-gate #ifdef B9600
11797c478bd9Sstevel@tonic-gate 	{ 9600, B9600 },
11807c478bd9Sstevel@tonic-gate #endif
11817c478bd9Sstevel@tonic-gate #ifdef B19200
11827c478bd9Sstevel@tonic-gate 	{ 19200, B19200 },
11837c478bd9Sstevel@tonic-gate #endif
11847c478bd9Sstevel@tonic-gate #ifdef B38400
11857c478bd9Sstevel@tonic-gate 	{ 38400, B38400 },
11867c478bd9Sstevel@tonic-gate #endif
11877c478bd9Sstevel@tonic-gate #ifdef EXTA
11887c478bd9Sstevel@tonic-gate 	{ 19200, EXTA },
11897c478bd9Sstevel@tonic-gate #endif
11907c478bd9Sstevel@tonic-gate #ifdef EXTB
11917c478bd9Sstevel@tonic-gate 	{ 38400, EXTB },
11927c478bd9Sstevel@tonic-gate #endif
11937c478bd9Sstevel@tonic-gate #ifdef B57600
11947c478bd9Sstevel@tonic-gate 	{ 57600, B57600 },
11957c478bd9Sstevel@tonic-gate #endif
11967c478bd9Sstevel@tonic-gate #ifdef B76800
11977c478bd9Sstevel@tonic-gate 	{ 76800, B76800 },
11987c478bd9Sstevel@tonic-gate #endif
11997c478bd9Sstevel@tonic-gate #ifdef B115200
12007c478bd9Sstevel@tonic-gate 	{ 115200, B115200 },
12017c478bd9Sstevel@tonic-gate #endif
12027c478bd9Sstevel@tonic-gate #ifdef B153600
12037c478bd9Sstevel@tonic-gate 	{ 153600, B153600 },
12047c478bd9Sstevel@tonic-gate #endif
12057c478bd9Sstevel@tonic-gate #ifdef B230400
12067c478bd9Sstevel@tonic-gate 	{ 230400, B230400 },
12077c478bd9Sstevel@tonic-gate #endif
12087c478bd9Sstevel@tonic-gate #ifdef B307200
12097c478bd9Sstevel@tonic-gate 	{ 307200, B307200 },
12107c478bd9Sstevel@tonic-gate #endif
12117c478bd9Sstevel@tonic-gate #ifdef B460800
12127c478bd9Sstevel@tonic-gate 	{ 460800, B460800 },
1213de81e71eSTim Marsland #endif
1214de81e71eSTim Marsland #ifdef B921600
1215de81e71eSTim Marsland 	{ 921600, B921600 },
12167c478bd9Sstevel@tonic-gate #endif
12177c478bd9Sstevel@tonic-gate 	{ 0, 0 }
12187c478bd9Sstevel@tonic-gate };
12197c478bd9Sstevel@tonic-gate 
12207c478bd9Sstevel@tonic-gate /*
12217c478bd9Sstevel@tonic-gate  * translate_speed()
12227c478bd9Sstevel@tonic-gate  *
12237c478bd9Sstevel@tonic-gate  * Translate from bits/second to a speed_t
12247c478bd9Sstevel@tonic-gate  */
12257c478bd9Sstevel@tonic-gate static int
12267c478bd9Sstevel@tonic-gate translate_speed(int bps)
12277c478bd9Sstevel@tonic-gate {
12287c478bd9Sstevel@tonic-gate 	struct speed *speedp;
12297c478bd9Sstevel@tonic-gate 
12307c478bd9Sstevel@tonic-gate 	if (bps == 0) {
12317c478bd9Sstevel@tonic-gate 		return (0);
12327c478bd9Sstevel@tonic-gate 	}
12337c478bd9Sstevel@tonic-gate 	for (speedp = speeds; speedp->speed_int; speedp++) {
12347c478bd9Sstevel@tonic-gate 		if (bps == speedp->speed_int) {
12357c478bd9Sstevel@tonic-gate 			return (speedp->speed_val);
12367c478bd9Sstevel@tonic-gate 		}
12377c478bd9Sstevel@tonic-gate 	}
12387c478bd9Sstevel@tonic-gate 	set_source(&speed_info);
12397c478bd9Sstevel@tonic-gate 	option_error("speed %d not supported", bps);
12407c478bd9Sstevel@tonic-gate 	return (0);
12417c478bd9Sstevel@tonic-gate }
12427c478bd9Sstevel@tonic-gate 
12437c478bd9Sstevel@tonic-gate /*
12447c478bd9Sstevel@tonic-gate  * baud_rate_of()
12457c478bd9Sstevel@tonic-gate  *
12467c478bd9Sstevel@tonic-gate  * Translate from a speed_t to bits/second
12477c478bd9Sstevel@tonic-gate  */
12487c478bd9Sstevel@tonic-gate static int
12497c478bd9Sstevel@tonic-gate baud_rate_of(int speed)
12507c478bd9Sstevel@tonic-gate {
12517c478bd9Sstevel@tonic-gate 	struct speed *speedp;
12527c478bd9Sstevel@tonic-gate 
12537c478bd9Sstevel@tonic-gate 	if (speed == 0) {
12547c478bd9Sstevel@tonic-gate 		return (0);
12557c478bd9Sstevel@tonic-gate 	}
12567c478bd9Sstevel@tonic-gate 	for (speedp = speeds; speedp->speed_int; speedp++) {
12577c478bd9Sstevel@tonic-gate 		if (speed == speedp->speed_val) {
12587c478bd9Sstevel@tonic-gate 			return (speedp->speed_int);
12597c478bd9Sstevel@tonic-gate 		}
12607c478bd9Sstevel@tonic-gate 	}
12617c478bd9Sstevel@tonic-gate 	return (0);
12627c478bd9Sstevel@tonic-gate }
12637c478bd9Sstevel@tonic-gate 
12647c478bd9Sstevel@tonic-gate /*
12657c478bd9Sstevel@tonic-gate  * set_up_tty()
12667c478bd9Sstevel@tonic-gate  *
12677c478bd9Sstevel@tonic-gate  * Set up the serial port on `fd' for 8 bits, no parity, at the requested
12687c478bd9Sstevel@tonic-gate  * speed, etc.  If `local' is true, set CLOCAL regardless of whether the
12697c478bd9Sstevel@tonic-gate  * modem option was specified.
12707c478bd9Sstevel@tonic-gate  */
12717c478bd9Sstevel@tonic-gate void
12727c478bd9Sstevel@tonic-gate set_up_tty(fd, local)
12737c478bd9Sstevel@tonic-gate 	int fd, local;
12747c478bd9Sstevel@tonic-gate {
12757c478bd9Sstevel@tonic-gate 	int speed;
12767c478bd9Sstevel@tonic-gate 	struct termios tios;
12777c478bd9Sstevel@tonic-gate 	struct scc_mode sm;
12787c478bd9Sstevel@tonic-gate 
12797c478bd9Sstevel@tonic-gate 	if (already_ppp)
12807c478bd9Sstevel@tonic-gate 		return;
12817c478bd9Sstevel@tonic-gate 
12827c478bd9Sstevel@tonic-gate 	if (sync_serial) {
12837c478bd9Sstevel@tonic-gate 		restore_term = 0;
12847c478bd9Sstevel@tonic-gate 		speed = B0;
12857c478bd9Sstevel@tonic-gate 		baud_rate = 0;
12867c478bd9Sstevel@tonic-gate 
12877c478bd9Sstevel@tonic-gate 		if (strioctl(fd, S_IOCGETMODE, &sm, sizeof (sm),
12887c478bd9Sstevel@tonic-gate 		    sizeof (sm)) < 0) {
12897c478bd9Sstevel@tonic-gate 			return;
12907c478bd9Sstevel@tonic-gate 		}
12917c478bd9Sstevel@tonic-gate 
12927c478bd9Sstevel@tonic-gate 		baud_rate = sm.sm_baudrate;
12937c478bd9Sstevel@tonic-gate 		dbglog("synchronous speed appears to be %d bps", baud_rate);
12947c478bd9Sstevel@tonic-gate 	} else {
12957c478bd9Sstevel@tonic-gate 		if (tcgetattr(fd, &tios) < 0) {
12967c478bd9Sstevel@tonic-gate 			fatal("tcgetattr: %m");
12977c478bd9Sstevel@tonic-gate 		}
12987c478bd9Sstevel@tonic-gate 		if (!restore_term) {
12997c478bd9Sstevel@tonic-gate 			inittermios = tios;
13007c478bd9Sstevel@tonic-gate 			if (myioctl(fd, TIOCGWINSZ, &wsinfo) < 0) {
13017c478bd9Sstevel@tonic-gate 				if (errno == EINVAL) {
13027c478bd9Sstevel@tonic-gate 					/*
13037c478bd9Sstevel@tonic-gate 					 * ptem returns EINVAL if all zeroes.
13047c478bd9Sstevel@tonic-gate 					 * Strange and unfixable code.
13057c478bd9Sstevel@tonic-gate 					 */
13067c478bd9Sstevel@tonic-gate 					bzero(&wsinfo, sizeof (wsinfo));
13077c478bd9Sstevel@tonic-gate 				} else {
13087c478bd9Sstevel@tonic-gate 					warn("unable to get TTY window "
13097c478bd9Sstevel@tonic-gate 					    "size: %m");
13107c478bd9Sstevel@tonic-gate 				}
13117c478bd9Sstevel@tonic-gate 			}
13127c478bd9Sstevel@tonic-gate 		}
13137c478bd9Sstevel@tonic-gate 		tios.c_cflag &= ~(CSIZE | CSTOPB | PARENB | CLOCAL);
13147c478bd9Sstevel@tonic-gate 		if (crtscts > 0) {
13157c478bd9Sstevel@tonic-gate 			tios.c_cflag |= CRTSCTS | CRTSXOFF;
13167c478bd9Sstevel@tonic-gate 		} else if (crtscts < 0) {
13177c478bd9Sstevel@tonic-gate 			tios.c_cflag &= ~CRTSCTS & ~CRTSXOFF;
13187c478bd9Sstevel@tonic-gate 		}
13197c478bd9Sstevel@tonic-gate 		tios.c_cflag |= CS8 | CREAD | HUPCL;
13207c478bd9Sstevel@tonic-gate 		if (local || !modem) {
13217c478bd9Sstevel@tonic-gate 			tios.c_cflag |= CLOCAL;
13227c478bd9Sstevel@tonic-gate 		}
13237c478bd9Sstevel@tonic-gate 		tios.c_iflag = IGNBRK | IGNPAR;
13247c478bd9Sstevel@tonic-gate 		tios.c_oflag = 0;
13257c478bd9Sstevel@tonic-gate 		tios.c_lflag = 0;
13267c478bd9Sstevel@tonic-gate 		tios.c_cc[VMIN] = 1;
13277c478bd9Sstevel@tonic-gate 		tios.c_cc[VTIME] = 0;
13287c478bd9Sstevel@tonic-gate 
13297c478bd9Sstevel@tonic-gate 		if (crtscts == -2) {
13307c478bd9Sstevel@tonic-gate 			tios.c_iflag |= IXON | IXOFF;
13317c478bd9Sstevel@tonic-gate 			tios.c_cc[VSTOP] = 0x13;	/* DC3 = XOFF = ^S */
13327c478bd9Sstevel@tonic-gate 			tios.c_cc[VSTART] = 0x11;	/* DC1 = XON  = ^Q */
13337c478bd9Sstevel@tonic-gate 		}
13347c478bd9Sstevel@tonic-gate 		speed = translate_speed(inspeed);
13357c478bd9Sstevel@tonic-gate 		if (speed) {
13367c478bd9Sstevel@tonic-gate 			(void) cfsetospeed(&tios, speed);
13377c478bd9Sstevel@tonic-gate 			(void) cfsetispeed(&tios, speed);
13387c478bd9Sstevel@tonic-gate 		} else {
13397c478bd9Sstevel@tonic-gate 			speed = cfgetospeed(&tios);
13407c478bd9Sstevel@tonic-gate 			/*
13417c478bd9Sstevel@tonic-gate 			 * We can't proceed if the serial port speed is 0,
13427c478bd9Sstevel@tonic-gate 			 * since that implies that the serial port is disabled.
13437c478bd9Sstevel@tonic-gate 			 */
13447c478bd9Sstevel@tonic-gate 			if (speed == B0) {
13457c478bd9Sstevel@tonic-gate 				fatal("Baud rate for %s is 0; need explicit "
13467c478bd9Sstevel@tonic-gate 				    "baud rate", devnam);
13477c478bd9Sstevel@tonic-gate 			}
13487c478bd9Sstevel@tonic-gate 		}
13497c478bd9Sstevel@tonic-gate 		if (tcsetattr(fd, TCSAFLUSH, &tios) < 0) {
13507c478bd9Sstevel@tonic-gate 			fatal("tcsetattr: %m");
13517c478bd9Sstevel@tonic-gate 		}
13527c478bd9Sstevel@tonic-gate 		baud_rate = baud_rate_of(speed);
13537c478bd9Sstevel@tonic-gate 		dbglog("%s speed set to %d bps",
13547c478bd9Sstevel@tonic-gate 		    fd == pty_slave ? "pty" : "serial", baud_rate);
13557c478bd9Sstevel@tonic-gate 		restore_term = 1;
13567c478bd9Sstevel@tonic-gate 	}
13577c478bd9Sstevel@tonic-gate }
13587c478bd9Sstevel@tonic-gate 
13597c478bd9Sstevel@tonic-gate /*
13607c478bd9Sstevel@tonic-gate  * restore_tty()
13617c478bd9Sstevel@tonic-gate  *
13627c478bd9Sstevel@tonic-gate  * Restore the terminal to the saved settings.
13637c478bd9Sstevel@tonic-gate  */
13647c478bd9Sstevel@tonic-gate void
13657c478bd9Sstevel@tonic-gate restore_tty(fd)
13667c478bd9Sstevel@tonic-gate 	int fd;
13677c478bd9Sstevel@tonic-gate {
13687c478bd9Sstevel@tonic-gate 	if (restore_term == 0) {
13697c478bd9Sstevel@tonic-gate 		return;
13707c478bd9Sstevel@tonic-gate 	}
13717c478bd9Sstevel@tonic-gate 	if (!default_device) {
13727c478bd9Sstevel@tonic-gate 		/*
13737c478bd9Sstevel@tonic-gate 		 * Turn off echoing, because otherwise we can get into
13747c478bd9Sstevel@tonic-gate 		 * a loop with the tty and the modem echoing to each
13757c478bd9Sstevel@tonic-gate 		 * other. We presume we are the sole user of this tty
13767c478bd9Sstevel@tonic-gate 		 * device, so when we close it, it will revert to its
13777c478bd9Sstevel@tonic-gate 		 * defaults anyway.
13787c478bd9Sstevel@tonic-gate 		 */
13797c478bd9Sstevel@tonic-gate 		inittermios.c_lflag &= ~(ECHO | ECHONL);
13807c478bd9Sstevel@tonic-gate 	}
13817c478bd9Sstevel@tonic-gate 	if (tcsetattr(fd, TCSAFLUSH, &inittermios) < 0) {
13827c478bd9Sstevel@tonic-gate 		if (!hungup && errno != ENXIO) {
13837c478bd9Sstevel@tonic-gate 			warn("tcsetattr: %m");
13847c478bd9Sstevel@tonic-gate 		}
13857c478bd9Sstevel@tonic-gate 	}
13867c478bd9Sstevel@tonic-gate 	if (wsinfo.ws_row != 0 || wsinfo.ws_col != 0 ||
13877c478bd9Sstevel@tonic-gate 	    wsinfo.ws_xpixel != 0 || wsinfo.ws_ypixel != 0) {
13887c478bd9Sstevel@tonic-gate 		if (myioctl(fd, TIOCSWINSZ, &wsinfo) < 0) {
13897c478bd9Sstevel@tonic-gate 			warn("unable to set TTY window size: %m");
13907c478bd9Sstevel@tonic-gate 		}
13917c478bd9Sstevel@tonic-gate 	}
13927c478bd9Sstevel@tonic-gate 	restore_term = 0;
13937c478bd9Sstevel@tonic-gate }
13947c478bd9Sstevel@tonic-gate 
13957c478bd9Sstevel@tonic-gate /*
13967c478bd9Sstevel@tonic-gate  * setdtr()
13977c478bd9Sstevel@tonic-gate  *
13987c478bd9Sstevel@tonic-gate  * Control the DTR line on the serial port. This is called from die(), so it
13997c478bd9Sstevel@tonic-gate  * shouldn't call die()
14007c478bd9Sstevel@tonic-gate  */
14017c478bd9Sstevel@tonic-gate void
14027c478bd9Sstevel@tonic-gate setdtr(fd, on)
14037c478bd9Sstevel@tonic-gate 	int fd, on;
14047c478bd9Sstevel@tonic-gate {
14057c478bd9Sstevel@tonic-gate 	int modembits = TIOCM_DTR;
14067c478bd9Sstevel@tonic-gate 	if (!already_ppp &&
14077c478bd9Sstevel@tonic-gate 	    myioctl(fd, (on ? TIOCMBIS : TIOCMBIC), &modembits) < 0) {
14087c478bd9Sstevel@tonic-gate 		warn("unable to set DTR line %s: %m", (on ? "ON" : "OFF"));
14097c478bd9Sstevel@tonic-gate 	}
14107c478bd9Sstevel@tonic-gate }
14117c478bd9Sstevel@tonic-gate 
14127c478bd9Sstevel@tonic-gate /*
14137c478bd9Sstevel@tonic-gate  * open_loopback()
14147c478bd9Sstevel@tonic-gate  *
14157c478bd9Sstevel@tonic-gate  * Open the device we use for getting packets in demand mode. Under Solaris 2,
14167c478bd9Sstevel@tonic-gate  * we use our existing fd to the ppp driver.
14177c478bd9Sstevel@tonic-gate  */
14187c478bd9Sstevel@tonic-gate int
14197c478bd9Sstevel@tonic-gate open_ppp_loopback()
14207c478bd9Sstevel@tonic-gate {
14217c478bd9Sstevel@tonic-gate 	/*
14227c478bd9Sstevel@tonic-gate 	 * Plumb the interface.
14237c478bd9Sstevel@tonic-gate 	 */
14247c478bd9Sstevel@tonic-gate 	if (IPCP_ENABLED && (plumb_ipif(0) == 0)) {
14257c478bd9Sstevel@tonic-gate 		fatal("Unable to initialize IP interface for demand dial.");
14267c478bd9Sstevel@tonic-gate 	}
14277c478bd9Sstevel@tonic-gate #ifdef INET6
14287c478bd9Sstevel@tonic-gate 	if (IPV6CP_ENABLED && (plumb_ip6if(0) == 0)) {
14297c478bd9Sstevel@tonic-gate 		fatal("Unable to initialize IPv6 interface for demand dial.");
14307c478bd9Sstevel@tonic-gate 	}
14317c478bd9Sstevel@tonic-gate #endif /* INET6 */
14327c478bd9Sstevel@tonic-gate 
14337c478bd9Sstevel@tonic-gate 	return (pppfd);
14347c478bd9Sstevel@tonic-gate }
14357c478bd9Sstevel@tonic-gate 
14367c478bd9Sstevel@tonic-gate /*
14377c478bd9Sstevel@tonic-gate  * output()
14387c478bd9Sstevel@tonic-gate  *
14397c478bd9Sstevel@tonic-gate  * Output PPP packet downstream
14407c478bd9Sstevel@tonic-gate  */
14417c478bd9Sstevel@tonic-gate /*ARGSUSED*/
14427c478bd9Sstevel@tonic-gate void
14437c478bd9Sstevel@tonic-gate output(unit, p, len)
14447c478bd9Sstevel@tonic-gate 	int unit;
14457c478bd9Sstevel@tonic-gate 	uchar_t *p;
14467c478bd9Sstevel@tonic-gate 	int len;
14477c478bd9Sstevel@tonic-gate {
14487c478bd9Sstevel@tonic-gate 	struct strbuf data;
14497c478bd9Sstevel@tonic-gate 	struct pollfd pfd;
14507c478bd9Sstevel@tonic-gate 	int retries, n;
14517c478bd9Sstevel@tonic-gate 	bool sent_ok = 1;
14527c478bd9Sstevel@tonic-gate 
14537c478bd9Sstevel@tonic-gate 	data.len = len;
14547c478bd9Sstevel@tonic-gate 	data.buf = (caddr_t)p;
14557c478bd9Sstevel@tonic-gate 	retries = 4;
14567c478bd9Sstevel@tonic-gate 
14577c478bd9Sstevel@tonic-gate 	while (putmsg(pppfd, NULL, &data, 0) < 0) {
14587c478bd9Sstevel@tonic-gate 		if (errno == EINTR)
14597c478bd9Sstevel@tonic-gate 			continue;
14607c478bd9Sstevel@tonic-gate 		if (--retries < 0 ||
14617c478bd9Sstevel@tonic-gate 		    (errno != EWOULDBLOCK && errno != EAGAIN)) {
14627c478bd9Sstevel@tonic-gate 			if (errno != ENXIO) {
14637c478bd9Sstevel@tonic-gate 				error("Couldn't send packet: %m");
14647c478bd9Sstevel@tonic-gate 				sent_ok = 0;
14657c478bd9Sstevel@tonic-gate 			}
14667c478bd9Sstevel@tonic-gate 			break;
14677c478bd9Sstevel@tonic-gate 		}
14687c478bd9Sstevel@tonic-gate 		pfd.fd = pppfd;
14697c478bd9Sstevel@tonic-gate 		pfd.events = POLLOUT;
14707c478bd9Sstevel@tonic-gate 		do {
14717c478bd9Sstevel@tonic-gate 			/* wait for up to 0.25 seconds */
14727c478bd9Sstevel@tonic-gate 			n = poll(&pfd, 1, 250);
14737c478bd9Sstevel@tonic-gate 		} while ((n == -1) && (errno == EINTR));
14747c478bd9Sstevel@tonic-gate 	}
14757c478bd9Sstevel@tonic-gate 	if (debug && sent_ok) {
14767c478bd9Sstevel@tonic-gate 		dbglog("sent %P", p, len);
14777c478bd9Sstevel@tonic-gate 	}
14787c478bd9Sstevel@tonic-gate }
14797c478bd9Sstevel@tonic-gate 
14807c478bd9Sstevel@tonic-gate /*
14817c478bd9Sstevel@tonic-gate  * wait_input()
14827c478bd9Sstevel@tonic-gate  *
14837c478bd9Sstevel@tonic-gate  * Wait until there is data available, for the length of time specified by
14847c478bd9Sstevel@tonic-gate  * timo (indefinite if timo is NULL).
14857c478bd9Sstevel@tonic-gate  */
14867c478bd9Sstevel@tonic-gate void
14877c478bd9Sstevel@tonic-gate wait_input(timo)
14887c478bd9Sstevel@tonic-gate 	struct timeval *timo;
14897c478bd9Sstevel@tonic-gate {
14907c478bd9Sstevel@tonic-gate 	int t;
14917c478bd9Sstevel@tonic-gate 
14927c478bd9Sstevel@tonic-gate 	t = (timo == NULL ? -1 : (timo->tv_sec * 1000 + timo->tv_usec / 1000));
14937c478bd9Sstevel@tonic-gate 	if ((poll(pollfds, n_pollfds, t) < 0) && (errno != EINTR)) {
14947c478bd9Sstevel@tonic-gate 		fatal("poll: %m");
14957c478bd9Sstevel@tonic-gate 	}
14967c478bd9Sstevel@tonic-gate }
14977c478bd9Sstevel@tonic-gate 
14987c478bd9Sstevel@tonic-gate /*
14997c478bd9Sstevel@tonic-gate  * add_fd()
15007c478bd9Sstevel@tonic-gate  *
15017c478bd9Sstevel@tonic-gate  * Add an fd to the set that wait_input waits for.
15027c478bd9Sstevel@tonic-gate  */
15037c478bd9Sstevel@tonic-gate void
15047c478bd9Sstevel@tonic-gate add_fd(fd)
15057c478bd9Sstevel@tonic-gate 	int fd;
15067c478bd9Sstevel@tonic-gate {
15077c478bd9Sstevel@tonic-gate 	int n;
15087c478bd9Sstevel@tonic-gate 
15097c478bd9Sstevel@tonic-gate 	if (fd < 0) {
15107c478bd9Sstevel@tonic-gate 		return;
15117c478bd9Sstevel@tonic-gate 	}
15127c478bd9Sstevel@tonic-gate 	for (n = 0; n < n_pollfds; ++n) {
15137c478bd9Sstevel@tonic-gate 		if (pollfds[n].fd == fd) {
15147c478bd9Sstevel@tonic-gate 			return;
15157c478bd9Sstevel@tonic-gate 		}
15167c478bd9Sstevel@tonic-gate 	}
15177c478bd9Sstevel@tonic-gate 	if (n_pollfds < MAX_POLLFDS) {
15187c478bd9Sstevel@tonic-gate 		pollfds[n_pollfds].fd = fd;
15197c478bd9Sstevel@tonic-gate 		pollfds[n_pollfds].events = POLLIN | POLLPRI | POLLHUP;
15207c478bd9Sstevel@tonic-gate 		++n_pollfds;
15217c478bd9Sstevel@tonic-gate 	} else {
15227c478bd9Sstevel@tonic-gate 		fatal("add_fd: too many inputs!");
15237c478bd9Sstevel@tonic-gate 	}
15247c478bd9Sstevel@tonic-gate }
15257c478bd9Sstevel@tonic-gate 
15267c478bd9Sstevel@tonic-gate /*
15277c478bd9Sstevel@tonic-gate  * remove_fd()
15287c478bd9Sstevel@tonic-gate  *
15297c478bd9Sstevel@tonic-gate  * Remove an fd from the set that wait_input waits for.
15307c478bd9Sstevel@tonic-gate  */
15317c478bd9Sstevel@tonic-gate void
15327c478bd9Sstevel@tonic-gate remove_fd(fd)
15337c478bd9Sstevel@tonic-gate 	int fd;
15347c478bd9Sstevel@tonic-gate {
15357c478bd9Sstevel@tonic-gate 	int n;
15367c478bd9Sstevel@tonic-gate 
15377c478bd9Sstevel@tonic-gate 	for (n = 0; n < n_pollfds; ++n) {
15387c478bd9Sstevel@tonic-gate 		if (pollfds[n].fd == fd) {
15397c478bd9Sstevel@tonic-gate 			while (++n < n_pollfds) {
15407c478bd9Sstevel@tonic-gate 				pollfds[n-1] = pollfds[n];
15417c478bd9Sstevel@tonic-gate 			}
15427c478bd9Sstevel@tonic-gate 			--n_pollfds;
15437c478bd9Sstevel@tonic-gate 			break;
15447c478bd9Sstevel@tonic-gate 		}
15457c478bd9Sstevel@tonic-gate 	}
15467c478bd9Sstevel@tonic-gate }
15477c478bd9Sstevel@tonic-gate 
15487c478bd9Sstevel@tonic-gate static void
15497c478bd9Sstevel@tonic-gate dump_packet(uchar_t *buf, int len)
15507c478bd9Sstevel@tonic-gate {
15517c478bd9Sstevel@tonic-gate 	uchar_t *bp;
15527c478bd9Sstevel@tonic-gate 	int proto, offs;
15537c478bd9Sstevel@tonic-gate 	const char *cp;
15547c478bd9Sstevel@tonic-gate 	char sbuf[32];
15557c478bd9Sstevel@tonic-gate 	uint32_t src, dst;
15567c478bd9Sstevel@tonic-gate 	struct protoent *pep;
1557*f53eecf5SJames Carlson 	struct in6_addr addr;
1558*f53eecf5SJames Carlson 	char fromstr[INET6_ADDRSTRLEN];
1559*f53eecf5SJames Carlson 	char tostr[INET6_ADDRSTRLEN];
15607c478bd9Sstevel@tonic-gate 
15617c478bd9Sstevel@tonic-gate 	if (len < 4) {
1562*f53eecf5SJames Carlson 		notice("strange link activity: %.*B", len, buf);
15637c478bd9Sstevel@tonic-gate 		return;
15647c478bd9Sstevel@tonic-gate 	}
15657c478bd9Sstevel@tonic-gate 	bp = buf;
15667c478bd9Sstevel@tonic-gate 	if (bp[0] == 0xFF && bp[1] == 0x03)
15677c478bd9Sstevel@tonic-gate 		bp += 2;
15687c478bd9Sstevel@tonic-gate 	proto = *bp++;
15697c478bd9Sstevel@tonic-gate 	if (!(proto & 1))
15707c478bd9Sstevel@tonic-gate 		proto = (proto << 8) + *bp++;
15717c478bd9Sstevel@tonic-gate 	len -= bp-buf;
1572*f53eecf5SJames Carlson 	switch (proto) {
1573*f53eecf5SJames Carlson 	case PPP_IP:
1574*f53eecf5SJames Carlson 		if (len < IP_HDRLEN || get_ipv(bp) != 4 || get_iphl(bp) < 5) {
1575*f53eecf5SJames Carlson 			notice("strange IP packet activity: %16.*B", len, buf);
15767c478bd9Sstevel@tonic-gate 			return;
15777c478bd9Sstevel@tonic-gate 		}
15787c478bd9Sstevel@tonic-gate 		src = get_ipsrc(bp);
15797c478bd9Sstevel@tonic-gate 		dst = get_ipdst(bp);
15807c478bd9Sstevel@tonic-gate 		proto = get_ipproto(bp);
15817c478bd9Sstevel@tonic-gate 		if ((pep = getprotobynumber(proto)) != NULL) {
15827c478bd9Sstevel@tonic-gate 			cp = pep->p_name;
15837c478bd9Sstevel@tonic-gate 		} else {
15847c478bd9Sstevel@tonic-gate 			(void) slprintf(sbuf, sizeof (sbuf), "IP proto %d",
15857c478bd9Sstevel@tonic-gate 			    proto);
15867c478bd9Sstevel@tonic-gate 			cp = sbuf;
15877c478bd9Sstevel@tonic-gate 		}
15887c478bd9Sstevel@tonic-gate 		if ((get_ipoff(bp) & IP_OFFMASK) != 0) {
15897c478bd9Sstevel@tonic-gate 			len -= get_iphl(bp) * 4;
15907c478bd9Sstevel@tonic-gate 			bp += get_iphl(bp) * 4;
1591*f53eecf5SJames Carlson 			notice("%s fragment from %I->%I: %8.*B", cp, src, dst,
15927c478bd9Sstevel@tonic-gate 			    len, bp);
15937c478bd9Sstevel@tonic-gate 		} else {
15947c478bd9Sstevel@tonic-gate 			if (len > get_iplen(bp))
15957c478bd9Sstevel@tonic-gate 				len = get_iplen(bp);
15967c478bd9Sstevel@tonic-gate 			len -= get_iphl(bp) * 4;
15977c478bd9Sstevel@tonic-gate 			bp += get_iphl(bp) * 4;
15987c478bd9Sstevel@tonic-gate 			offs = proto == IPPROTO_TCP ? (get_tcpoff(bp)*4) : 8;
15997c478bd9Sstevel@tonic-gate 			if (proto == IPPROTO_TCP || proto == IPPROTO_UDP)
1600*f53eecf5SJames Carlson 				notice("%s data:%d %s%I:%d->%I:%d: %8.*B", cp,
1601*f53eecf5SJames Carlson 				    len-offs,
1602*f53eecf5SJames Carlson 				    proto == IPPROTO_TCP ?
1603*f53eecf5SJames Carlson 				    tcp_flag_decode(get_tcpflags(bp)) : "",
1604*f53eecf5SJames Carlson 				    src, get_sport(bp), dst, get_dport(bp),
1605*f53eecf5SJames Carlson 				    len-offs, bp+offs);
16067c478bd9Sstevel@tonic-gate 			else
1607*f53eecf5SJames Carlson 				notice("%s %d bytes %I->%I: %8.*B", cp, len,
16087c478bd9Sstevel@tonic-gate 				    src, dst, len, bp);
16097c478bd9Sstevel@tonic-gate 		}
16107c478bd9Sstevel@tonic-gate 		return;
1611*f53eecf5SJames Carlson 
1612*f53eecf5SJames Carlson 	case PPP_IPV6:
1613*f53eecf5SJames Carlson 		if (len < IP6_HDRLEN) {
1614*f53eecf5SJames Carlson 			notice("strange IPv6 activity: %16.*B", len, buf);
1615*f53eecf5SJames Carlson 			return;
1616*f53eecf5SJames Carlson 		}
1617*f53eecf5SJames Carlson 		(void) BCOPY(get_ip6src(bp), &addr, sizeof (addr));
1618*f53eecf5SJames Carlson 		(void) inet_ntop(AF_INET6, &addr, fromstr, sizeof (fromstr));
1619*f53eecf5SJames Carlson 		(void) BCOPY(get_ip6dst(bp), &addr, sizeof (addr));
1620*f53eecf5SJames Carlson 		(void) inet_ntop(AF_INET6, &addr, tostr, sizeof (tostr));
1621*f53eecf5SJames Carlson 		proto = get_ip6nh(bp);
1622*f53eecf5SJames Carlson 		if (proto == IPPROTO_FRAGMENT) {
1623*f53eecf5SJames Carlson 			notice("IPv6 fragment from %s->%s", fromstr,
1624*f53eecf5SJames Carlson 			    tostr);
1625*f53eecf5SJames Carlson 			return;
1626*f53eecf5SJames Carlson 		}
1627*f53eecf5SJames Carlson 		if ((pep = getprotobynumber(proto)) != NULL) {
1628*f53eecf5SJames Carlson 			cp = pep->p_name;
1629*f53eecf5SJames Carlson 		} else {
1630*f53eecf5SJames Carlson 			(void) slprintf(sbuf, sizeof (sbuf), "IPv6 proto %d",
1631*f53eecf5SJames Carlson 			    proto);
1632*f53eecf5SJames Carlson 			cp = sbuf;
1633*f53eecf5SJames Carlson 		}
1634*f53eecf5SJames Carlson 		len -= IP6_HDRLEN;
1635*f53eecf5SJames Carlson 		bp += IP6_HDRLEN;
1636*f53eecf5SJames Carlson 		offs = proto == IPPROTO_TCP ? (get_tcpoff(bp)*4) : 8;
1637*f53eecf5SJames Carlson 		if (proto == IPPROTO_TCP || proto == IPPROTO_UDP)
1638*f53eecf5SJames Carlson 			notice("%s data:%d %s[%s]%d->[%s]%d: %8.*B", cp,
1639*f53eecf5SJames Carlson 			    len-offs,
1640*f53eecf5SJames Carlson 			    proto == IPPROTO_TCP ?
1641*f53eecf5SJames Carlson 			    tcp_flag_decode(get_tcpflags(bp)) : "",
1642*f53eecf5SJames Carlson 			    fromstr, get_sport(bp), tostr, get_dport(bp),
1643*f53eecf5SJames Carlson 			    len-offs, bp+offs);
1644*f53eecf5SJames Carlson 		else
1645*f53eecf5SJames Carlson 			notice("%s %d bytes %s->%s: %8.*B", cp, len,
1646*f53eecf5SJames Carlson 			    fromstr, tostr, len, bp);
1647*f53eecf5SJames Carlson 		return;
16487c478bd9Sstevel@tonic-gate 	}
16497c478bd9Sstevel@tonic-gate 	if ((cp = protocol_name(proto)) == NULL) {
16507c478bd9Sstevel@tonic-gate 		(void) slprintf(sbuf, sizeof (sbuf), "0x#X", proto);
16517c478bd9Sstevel@tonic-gate 		cp = (const char *)sbuf;
16527c478bd9Sstevel@tonic-gate 	}
1653*f53eecf5SJames Carlson 	notice("link activity: %s %16.*B", cp, len, bp);
16547c478bd9Sstevel@tonic-gate }
16557c478bd9Sstevel@tonic-gate 
16567c478bd9Sstevel@tonic-gate /*
16577c478bd9Sstevel@tonic-gate  * handle_bind()
16587c478bd9Sstevel@tonic-gate  */
16597c478bd9Sstevel@tonic-gate static void
16607c478bd9Sstevel@tonic-gate handle_bind(u_int32_t reason)
16617c478bd9Sstevel@tonic-gate {
16627c478bd9Sstevel@tonic-gate 	/*
16637c478bd9Sstevel@tonic-gate 	 * Here we might, in the future, handle DL_BIND_REQ notifications
16647c478bd9Sstevel@tonic-gate 	 * in order to close and re-open a NCP when certain interface
16657c478bd9Sstevel@tonic-gate 	 * parameters (addresses, etc.) are changed via external mechanisms
16667c478bd9Sstevel@tonic-gate 	 * such as through the "ifconfig" program.
16677c478bd9Sstevel@tonic-gate 	 */
16687c478bd9Sstevel@tonic-gate 	switch (reason) {
16697c478bd9Sstevel@tonic-gate 	case PPP_LINKSTAT_IPV4_BOUND:
16707c478bd9Sstevel@tonic-gate 		break;
16717c478bd9Sstevel@tonic-gate #ifdef INET6
16727c478bd9Sstevel@tonic-gate 	case PPP_LINKSTAT_IPV6_BOUND:
16737c478bd9Sstevel@tonic-gate 		break;
16747c478bd9Sstevel@tonic-gate #endif
16757c478bd9Sstevel@tonic-gate 	default:
16767c478bd9Sstevel@tonic-gate 		error("handle_bind: unrecognized reason");
16777c478bd9Sstevel@tonic-gate 		break;
16787c478bd9Sstevel@tonic-gate 	}
16797c478bd9Sstevel@tonic-gate }
16807c478bd9Sstevel@tonic-gate 
16817c478bd9Sstevel@tonic-gate /*
16827c478bd9Sstevel@tonic-gate  * handle_unbind()
16837c478bd9Sstevel@tonic-gate  */
16847c478bd9Sstevel@tonic-gate static void
16857c478bd9Sstevel@tonic-gate handle_unbind(u_int32_t reason)
16867c478bd9Sstevel@tonic-gate {
16877c478bd9Sstevel@tonic-gate 	bool iff_up_isset;
16887c478bd9Sstevel@tonic-gate 	int rc;
16897c478bd9Sstevel@tonic-gate 	static const char *unplumb_str = "unplumbed";
16907c478bd9Sstevel@tonic-gate 	static const char *down_str = "downed";
16917c478bd9Sstevel@tonic-gate 
16927c478bd9Sstevel@tonic-gate 	/*
16937c478bd9Sstevel@tonic-gate 	 * Since the kernel driver (sppp) notifies this daemon of the
16947c478bd9Sstevel@tonic-gate 	 * DLPI bind/unbind activities (for the purpose of bringing down
16957c478bd9Sstevel@tonic-gate 	 * a NCP), we need to explicitly test the "actual" status of
16967c478bd9Sstevel@tonic-gate 	 * the interface instance for which the notification is destined
16977c478bd9Sstevel@tonic-gate 	 * from.  This is because /dev/ip performs multiple DLPI attach-
16987c478bd9Sstevel@tonic-gate 	 * bind-unbind-detach during the early life of the interface,
16997c478bd9Sstevel@tonic-gate 	 * and when certain interface parameters change.  A DL_UNBIND_REQ
17007c478bd9Sstevel@tonic-gate 	 * coming down to the sppp driver from /dev/ip (which results in
17017c478bd9Sstevel@tonic-gate 	 * our receiving of the PPP_LINKSTAT_*_UNBOUND link status message)
17027c478bd9Sstevel@tonic-gate 	 * is not enough to conclude that the interface has been marked
17037c478bd9Sstevel@tonic-gate 	 * DOWN (its IFF_UP bit is cleared) or is going away.  Therefore,
17047c478bd9Sstevel@tonic-gate 	 * we should query /dev/ip directly, upon receiving such *_UNBOUND
17057c478bd9Sstevel@tonic-gate 	 * notification, to determine whether the interface is DOWN
17067c478bd9Sstevel@tonic-gate 	 * for real, and only take the necessary actions when IFF_UP
17077c478bd9Sstevel@tonic-gate 	 * bit for the interface instance is actually cleared.
17087c478bd9Sstevel@tonic-gate 	 */
17097c478bd9Sstevel@tonic-gate 	switch (reason) {
17107c478bd9Sstevel@tonic-gate 	case PPP_LINKSTAT_IPV4_UNBOUND:
17117c478bd9Sstevel@tonic-gate 		(void) sleep(1);
17127c478bd9Sstevel@tonic-gate 		rc = giflags(IFF_UP, &iff_up_isset);
17137c478bd9Sstevel@tonic-gate 		if (!iff_up_isset) {
17147c478bd9Sstevel@tonic-gate 			if_is_up = 0;
17157c478bd9Sstevel@tonic-gate 			ipmuxid = -1;
17167c478bd9Sstevel@tonic-gate 			info("IPv4 interface %s by administrator",
17177c478bd9Sstevel@tonic-gate 			    ((rc < 0 && rc == ENXIO) ? unplumb_str : down_str));
17187c478bd9Sstevel@tonic-gate 			fsm_close(&ipcp_fsm[0],
17197c478bd9Sstevel@tonic-gate 			    "administratively disconnected");
17207c478bd9Sstevel@tonic-gate 		}
17217c478bd9Sstevel@tonic-gate 		break;
17227c478bd9Sstevel@tonic-gate #ifdef INET6
17237c478bd9Sstevel@tonic-gate 	case PPP_LINKSTAT_IPV6_UNBOUND:
17247c478bd9Sstevel@tonic-gate 		(void) sleep(1);
17257c478bd9Sstevel@tonic-gate 		rc = giflags(IFF_UP, &iff_up_isset);
17267c478bd9Sstevel@tonic-gate 		if (!iff_up_isset) {
17277c478bd9Sstevel@tonic-gate 			if6_is_up = 0;
17287c478bd9Sstevel@tonic-gate 			ip6muxid = -1;
17297c478bd9Sstevel@tonic-gate 			info("IPv6 interface %s by administrator",
17307c478bd9Sstevel@tonic-gate 			    ((rc < 0 && rc == ENXIO) ? unplumb_str : down_str));
17317c478bd9Sstevel@tonic-gate 			fsm_close(&ipv6cp_fsm[0],
17327c478bd9Sstevel@tonic-gate 			    "administratively disconnected");
17337c478bd9Sstevel@tonic-gate 		}
17347c478bd9Sstevel@tonic-gate 		break;
17357c478bd9Sstevel@tonic-gate #endif
17367c478bd9Sstevel@tonic-gate 	default:
17377c478bd9Sstevel@tonic-gate 		error("handle_unbind: unrecognized reason");
17387c478bd9Sstevel@tonic-gate 		break;
17397c478bd9Sstevel@tonic-gate 	}
17407c478bd9Sstevel@tonic-gate }
17417c478bd9Sstevel@tonic-gate 
17427c478bd9Sstevel@tonic-gate /*
17437c478bd9Sstevel@tonic-gate  * read_packet()
17447c478bd9Sstevel@tonic-gate  *
17457c478bd9Sstevel@tonic-gate  * Get a PPP packet from the serial device.
17467c478bd9Sstevel@tonic-gate  */
17477c478bd9Sstevel@tonic-gate int
17487c478bd9Sstevel@tonic-gate read_packet(buf)
17497c478bd9Sstevel@tonic-gate 	uchar_t *buf;
17507c478bd9Sstevel@tonic-gate {
17517c478bd9Sstevel@tonic-gate 	struct strbuf ctrl;
17527c478bd9Sstevel@tonic-gate 	struct strbuf data;
17537c478bd9Sstevel@tonic-gate 	int flags;
17547c478bd9Sstevel@tonic-gate 	int len;
17557c478bd9Sstevel@tonic-gate 	int rc;
17567c478bd9Sstevel@tonic-gate 	struct ppp_ls *plp;
17577c478bd9Sstevel@tonic-gate 	uint32_t ctrlbuf[1536 / sizeof (uint32_t)];
17587c478bd9Sstevel@tonic-gate 	bool flushmode;
17597c478bd9Sstevel@tonic-gate 
17607c478bd9Sstevel@tonic-gate 	flushmode = 0;
17617c478bd9Sstevel@tonic-gate 	for (;;) {
17627c478bd9Sstevel@tonic-gate 
17637c478bd9Sstevel@tonic-gate 		data.maxlen = PPP_MRU + PPP_HDRLEN;
17647c478bd9Sstevel@tonic-gate 		data.buf = (caddr_t)buf;
17657c478bd9Sstevel@tonic-gate 
17667c478bd9Sstevel@tonic-gate 		ctrl.maxlen = sizeof (ctrlbuf);
17677c478bd9Sstevel@tonic-gate 		ctrl.buf = (caddr_t)ctrlbuf;
17687c478bd9Sstevel@tonic-gate 
17697c478bd9Sstevel@tonic-gate 		flags = 0;
17707c478bd9Sstevel@tonic-gate 		rc = len = getmsg(pppfd, &ctrl, &data, &flags);
17717c478bd9Sstevel@tonic-gate 		if (sys_read_packet_hook != NULL) {
17727c478bd9Sstevel@tonic-gate 			rc = len = (*sys_read_packet_hook)(len, &ctrl, &data,
17737c478bd9Sstevel@tonic-gate 			    flags);
17747c478bd9Sstevel@tonic-gate 		}
17757c478bd9Sstevel@tonic-gate 		if (len < 0) {
17767c478bd9Sstevel@tonic-gate 			if (errno == EAGAIN || errno == EINTR) {
17777c478bd9Sstevel@tonic-gate 				return (-1);
17787c478bd9Sstevel@tonic-gate 			}
17797c478bd9Sstevel@tonic-gate 			fatal("Error reading packet: %m");
17807c478bd9Sstevel@tonic-gate 		}
17817c478bd9Sstevel@tonic-gate 		if ((data.len > 0) && (ctrl.len < 0)) {
17827c478bd9Sstevel@tonic-gate 			/*
17837c478bd9Sstevel@tonic-gate 			 * If there's more data on stream head, keep reading
17847c478bd9Sstevel@tonic-gate 			 * but discard, since the stream is now corrupt.
17857c478bd9Sstevel@tonic-gate 			 */
17867c478bd9Sstevel@tonic-gate 			if (rc & MOREDATA) {
17877c478bd9Sstevel@tonic-gate 				dbglog("More data; input packet garbled");
17887c478bd9Sstevel@tonic-gate 				flushmode = 1;
17897c478bd9Sstevel@tonic-gate 				continue;
17907c478bd9Sstevel@tonic-gate 			}
17917c478bd9Sstevel@tonic-gate 			if (flushmode)
17927c478bd9Sstevel@tonic-gate 				return (-1);
17937c478bd9Sstevel@tonic-gate 			return (data.len);
17947c478bd9Sstevel@tonic-gate 
17957c478bd9Sstevel@tonic-gate 		} else if (ctrl.len > 0) {
17967c478bd9Sstevel@tonic-gate 			/*
17977c478bd9Sstevel@tonic-gate 			 * If there's more ctl on stream head, keep reading,
17987c478bd9Sstevel@tonic-gate 			 * but start discarding.  We can't deal with fragmented
17997c478bd9Sstevel@tonic-gate 			 * messages at all.
18007c478bd9Sstevel@tonic-gate 			 */
18017c478bd9Sstevel@tonic-gate 			if (rc & MORECTL) {
18027c478bd9Sstevel@tonic-gate 				dbglog("More control; stream garbled");
18037c478bd9Sstevel@tonic-gate 				flushmode = 1;
18047c478bd9Sstevel@tonic-gate 				continue;
18057c478bd9Sstevel@tonic-gate 			}
18067c478bd9Sstevel@tonic-gate 			if (flushmode)
18077c478bd9Sstevel@tonic-gate 				return (-1);
18087c478bd9Sstevel@tonic-gate 			if (ctrl.len < sizeof (struct ppp_ls)) {
18097c478bd9Sstevel@tonic-gate 				warn("read_packet: ctl.len %d < "
18107c478bd9Sstevel@tonic-gate 				    "sizeof ppp_ls %d",
18117c478bd9Sstevel@tonic-gate 				    ctrl.len, sizeof (struct ppp_ls));
18127c478bd9Sstevel@tonic-gate 				return (-1);
18137c478bd9Sstevel@tonic-gate 			}
18147c478bd9Sstevel@tonic-gate 			plp = (struct ppp_ls *)ctrlbuf;
18157c478bd9Sstevel@tonic-gate 			if (plp->magic != PPPLSMAGIC) {
18167c478bd9Sstevel@tonic-gate 				/* Skip, as we don't understand it */
18177c478bd9Sstevel@tonic-gate 				dbglog("read_packet: unrecognized control %lX",
18187c478bd9Sstevel@tonic-gate 				    plp->magic);
18197c478bd9Sstevel@tonic-gate 				return (-1);
18207c478bd9Sstevel@tonic-gate 			}
18217c478bd9Sstevel@tonic-gate 
18227c478bd9Sstevel@tonic-gate 			lastlink_status = plp->ppp_message;
18237c478bd9Sstevel@tonic-gate 
18247c478bd9Sstevel@tonic-gate 			switch (plp->ppp_message) {
18257c478bd9Sstevel@tonic-gate 			case PPP_LINKSTAT_HANGUP:
18267c478bd9Sstevel@tonic-gate 				return (0);	/* Hangup */
18277c478bd9Sstevel@tonic-gate 			/* For use by integrated drivers. */
18287c478bd9Sstevel@tonic-gate 			case PPP_LINKSTAT_UP:
18297c478bd9Sstevel@tonic-gate 				lcp_lowerdown(0);
18307c478bd9Sstevel@tonic-gate 				lcp_lowerup(0);
18317c478bd9Sstevel@tonic-gate 				return (0);
18327c478bd9Sstevel@tonic-gate 			case PPP_LINKSTAT_NEEDUP:
1833*f53eecf5SJames Carlson 				if (data.len > 0)
18347c478bd9Sstevel@tonic-gate 					dump_packet(buf, data.len);
18357c478bd9Sstevel@tonic-gate 				return (-1);	/* Demand dial */
18367c478bd9Sstevel@tonic-gate 			case PPP_LINKSTAT_IPV4_UNBOUND:
18377c478bd9Sstevel@tonic-gate 				(void) handle_unbind(plp->ppp_message);
18387c478bd9Sstevel@tonic-gate 				return (-1);
18397c478bd9Sstevel@tonic-gate 			case PPP_LINKSTAT_IPV4_BOUND:
18407c478bd9Sstevel@tonic-gate 				(void) handle_bind(plp->ppp_message);
18417c478bd9Sstevel@tonic-gate 				return (-1);
18427c478bd9Sstevel@tonic-gate #ifdef INET6
18437c478bd9Sstevel@tonic-gate 			case PPP_LINKSTAT_IPV6_UNBOUND:
18447c478bd9Sstevel@tonic-gate 				(void) handle_unbind(plp->ppp_message);
18457c478bd9Sstevel@tonic-gate 				return (-1);
18467c478bd9Sstevel@tonic-gate 			case PPP_LINKSTAT_IPV6_BOUND:
18477c478bd9Sstevel@tonic-gate 				(void) handle_bind(plp->ppp_message);
18487c478bd9Sstevel@tonic-gate 				return (-1);
18497c478bd9Sstevel@tonic-gate #endif
18507c478bd9Sstevel@tonic-gate 			default:
18517c478bd9Sstevel@tonic-gate 				warn("read_packet: unknown link status type!");
18527c478bd9Sstevel@tonic-gate 				return (-1);
18537c478bd9Sstevel@tonic-gate 			}
18547c478bd9Sstevel@tonic-gate 		} else {
18557c478bd9Sstevel@tonic-gate 			/*
18567c478bd9Sstevel@tonic-gate 			 * We get here on zero length data or control.
18577c478bd9Sstevel@tonic-gate 			 */
18587c478bd9Sstevel@tonic-gate 			return (-1);
18597c478bd9Sstevel@tonic-gate 		}
18607c478bd9Sstevel@tonic-gate 	}
18617c478bd9Sstevel@tonic-gate }
18627c478bd9Sstevel@tonic-gate 
18637c478bd9Sstevel@tonic-gate /*
18647c478bd9Sstevel@tonic-gate  * get_loop_output()
18657c478bd9Sstevel@tonic-gate  *
18667c478bd9Sstevel@tonic-gate  * Get outgoing packets from the ppp device, and detect when we want to bring
18677c478bd9Sstevel@tonic-gate  * the real link up. Return value is 1 if we need to bring up the link, or 0
18687c478bd9Sstevel@tonic-gate  * otherwise.
18697c478bd9Sstevel@tonic-gate  */
18707c478bd9Sstevel@tonic-gate int
18717c478bd9Sstevel@tonic-gate get_loop_output()
18727c478bd9Sstevel@tonic-gate {
18737c478bd9Sstevel@tonic-gate 	int loops;
18747c478bd9Sstevel@tonic-gate 
18757c478bd9Sstevel@tonic-gate 	/*
18767c478bd9Sstevel@tonic-gate 	 * In the Solaris 2.x kernel-level portion implementation, packets
18777c478bd9Sstevel@tonic-gate 	 * which are received on a demand-dial interface are immediately
18787c478bd9Sstevel@tonic-gate 	 * discarded, and a notification message is sent up the control
18797c478bd9Sstevel@tonic-gate 	 * stream to the pppd process.  Therefore, the call to read_packet()
18807c478bd9Sstevel@tonic-gate 	 * below is merely there to wait for such message.
18817c478bd9Sstevel@tonic-gate 	 */
18827c478bd9Sstevel@tonic-gate 	lastlink_status = 0;
18837c478bd9Sstevel@tonic-gate 	loops = 0;
18847c478bd9Sstevel@tonic-gate 	while (read_packet(inpacket_buf) > 0) {
18857c478bd9Sstevel@tonic-gate 		if (++loops > 10)
18867c478bd9Sstevel@tonic-gate 			break;
18877c478bd9Sstevel@tonic-gate 	}
18887c478bd9Sstevel@tonic-gate 	return (lastlink_status == PPP_LINKSTAT_NEEDUP);
18897c478bd9Sstevel@tonic-gate }
18907c478bd9Sstevel@tonic-gate 
18917c478bd9Sstevel@tonic-gate #ifdef MUX_FRAME
18927c478bd9Sstevel@tonic-gate /*ARGSUSED*/
18937c478bd9Sstevel@tonic-gate void
18947c478bd9Sstevel@tonic-gate ppp_send_muxoption(unit, muxflag)
18957c478bd9Sstevel@tonic-gate 	int unit;
18967c478bd9Sstevel@tonic-gate 	u_int32_t muxflag;
18977c478bd9Sstevel@tonic-gate {
18987c478bd9Sstevel@tonic-gate 	uint32_t	cf[2];
18997c478bd9Sstevel@tonic-gate 
19007c478bd9Sstevel@tonic-gate 	/*
19017c478bd9Sstevel@tonic-gate 	 * Since muxed frame feature is implemented in the async module,
19027c478bd9Sstevel@tonic-gate 	 * don't send down the ioctl in the synchronous case.
19037c478bd9Sstevel@tonic-gate 	 */
19047c478bd9Sstevel@tonic-gate 	if (!sync_serial && fdmuxid >= 0 && pppfd != -1) {
19057c478bd9Sstevel@tonic-gate 		cf[0] = muxflag;
19067c478bd9Sstevel@tonic-gate 		cf[1] = X_MUXMASK;
19077c478bd9Sstevel@tonic-gate 
19087c478bd9Sstevel@tonic-gate 		if (strioctl(pppfd, PPPIO_MUX, cf, sizeof (cf), 0) < 0) {
19097c478bd9Sstevel@tonic-gate 			error("Couldn't set mux option: %m");
19107c478bd9Sstevel@tonic-gate 		}
19117c478bd9Sstevel@tonic-gate 	}
19127c478bd9Sstevel@tonic-gate }
19137c478bd9Sstevel@tonic-gate 
19147c478bd9Sstevel@tonic-gate /*ARGSUSED*/
19157c478bd9Sstevel@tonic-gate void
19167c478bd9Sstevel@tonic-gate ppp_recv_muxoption(unit, muxflag)
19177c478bd9Sstevel@tonic-gate 	int unit;
19187c478bd9Sstevel@tonic-gate 	u_int32_t muxflag;
19197c478bd9Sstevel@tonic-gate {
19207c478bd9Sstevel@tonic-gate 	uint32_t	cf[2];
19217c478bd9Sstevel@tonic-gate 
19227c478bd9Sstevel@tonic-gate 	/*
19237c478bd9Sstevel@tonic-gate 	 * Since muxed frame feature is implemented in the async module,
19247c478bd9Sstevel@tonic-gate 	 * don't send down the ioctl in the synchronous case.
19257c478bd9Sstevel@tonic-gate 	 */
19267c478bd9Sstevel@tonic-gate 	if (!sync_serial && fdmuxid >= 0 && pppfd != -1) {
19277c478bd9Sstevel@tonic-gate 		cf[0] = muxflag;
19287c478bd9Sstevel@tonic-gate 		cf[1] = R_MUXMASK;
19297c478bd9Sstevel@tonic-gate 
19307c478bd9Sstevel@tonic-gate 		if (strioctl(pppfd, PPPIO_MUX, cf, sizeof (cf), 0) < 0) {
19317c478bd9Sstevel@tonic-gate 			error("Couldn't set receive mux option: %m");
19327c478bd9Sstevel@tonic-gate 		}
19337c478bd9Sstevel@tonic-gate 	}
19347c478bd9Sstevel@tonic-gate }
19357c478bd9Sstevel@tonic-gate #endif
19367c478bd9Sstevel@tonic-gate 
19377c478bd9Sstevel@tonic-gate /*
19387c478bd9Sstevel@tonic-gate  * ppp_send_config()
19397c478bd9Sstevel@tonic-gate  *
19407c478bd9Sstevel@tonic-gate  * Configure the transmit characteristics of the ppp interface.
19417c478bd9Sstevel@tonic-gate  */
19427c478bd9Sstevel@tonic-gate /*ARGSUSED*/
19437c478bd9Sstevel@tonic-gate void
19447c478bd9Sstevel@tonic-gate ppp_send_config(unit, mtu, asyncmap, pcomp, accomp)
19457c478bd9Sstevel@tonic-gate 	int unit;
19467c478bd9Sstevel@tonic-gate 	int mtu;
19477c478bd9Sstevel@tonic-gate 	u_int32_t asyncmap;
19487c478bd9Sstevel@tonic-gate 	int pcomp;
19497c478bd9Sstevel@tonic-gate 	int accomp;
19507c478bd9Sstevel@tonic-gate {
19517c478bd9Sstevel@tonic-gate 	uint32_t cf[2];
19527c478bd9Sstevel@tonic-gate 
19537c478bd9Sstevel@tonic-gate 	if (pppfd == -1) {
19547c478bd9Sstevel@tonic-gate 		error("ppp_send_config called with invalid device handle");
19557c478bd9Sstevel@tonic-gate 		return;
19567c478bd9Sstevel@tonic-gate 	}
19577c478bd9Sstevel@tonic-gate 	cf[0] =	link_mtu = mtu;
19587c478bd9Sstevel@tonic-gate 	if (strioctl(pppfd, PPPIO_MTU, cf, sizeof (cf[0]), 0) < 0) {
19597c478bd9Sstevel@tonic-gate 		if (hungup && errno == ENXIO) {
19607c478bd9Sstevel@tonic-gate 			return;
19617c478bd9Sstevel@tonic-gate 		}
19627c478bd9Sstevel@tonic-gate 		error("Couldn't set MTU: %m");
19637c478bd9Sstevel@tonic-gate 	}
19647c478bd9Sstevel@tonic-gate 	if (fdmuxid != -1) {
19657c478bd9Sstevel@tonic-gate 		if (!sync_serial) {
19667c478bd9Sstevel@tonic-gate 			if (strioctl(pppfd, PPPIO_XACCM, &asyncmap,
19677c478bd9Sstevel@tonic-gate 			    sizeof (asyncmap), 0) < 0) {
19687c478bd9Sstevel@tonic-gate 				error("Couldn't set transmit ACCM: %m");
19697c478bd9Sstevel@tonic-gate 			}
19707c478bd9Sstevel@tonic-gate 		}
19717c478bd9Sstevel@tonic-gate 		cf[0] = (pcomp? COMP_PROT: 0) + (accomp? COMP_AC: 0);
19727c478bd9Sstevel@tonic-gate 		cf[1] = COMP_PROT | COMP_AC;
19737c478bd9Sstevel@tonic-gate 
19747c478bd9Sstevel@tonic-gate 		if (any_compressions() && strioctl(pppfd, PPPIO_CFLAGS, cf,
19757c478bd9Sstevel@tonic-gate 		    sizeof (cf), sizeof (cf[0])) < 0) {
19767c478bd9Sstevel@tonic-gate 			error("Couldn't set prot/AC compression: %m");
19777c478bd9Sstevel@tonic-gate 		}
19787c478bd9Sstevel@tonic-gate 	}
19797c478bd9Sstevel@tonic-gate }
19807c478bd9Sstevel@tonic-gate 
19817c478bd9Sstevel@tonic-gate /*
19827c478bd9Sstevel@tonic-gate  * ppp_set_xaccm()
19837c478bd9Sstevel@tonic-gate  *
19847c478bd9Sstevel@tonic-gate  * Set the extended transmit ACCM for the interface.
19857c478bd9Sstevel@tonic-gate  */
19867c478bd9Sstevel@tonic-gate /*ARGSUSED*/
19877c478bd9Sstevel@tonic-gate void
19887c478bd9Sstevel@tonic-gate ppp_set_xaccm(unit, accm)
19897c478bd9Sstevel@tonic-gate 	int unit;
19907c478bd9Sstevel@tonic-gate 	ext_accm accm;
19917c478bd9Sstevel@tonic-gate {
19927c478bd9Sstevel@tonic-gate 	if (sync_serial) {
19937c478bd9Sstevel@tonic-gate 		return;
19947c478bd9Sstevel@tonic-gate 	}
19957c478bd9Sstevel@tonic-gate 	if (fdmuxid != -1 && strioctl(pppfd, PPPIO_XACCM, accm,
19967c478bd9Sstevel@tonic-gate 	    sizeof (ext_accm), 0) < 0) {
19977c478bd9Sstevel@tonic-gate 		if (!hungup || errno != ENXIO) {
19987c478bd9Sstevel@tonic-gate 			warn("Couldn't set extended ACCM: %m");
19997c478bd9Sstevel@tonic-gate 		}
20007c478bd9Sstevel@tonic-gate 	}
20017c478bd9Sstevel@tonic-gate }
20027c478bd9Sstevel@tonic-gate 
20037c478bd9Sstevel@tonic-gate /*
20047c478bd9Sstevel@tonic-gate  * ppp_recv_config()
20057c478bd9Sstevel@tonic-gate  *
20067c478bd9Sstevel@tonic-gate  * Configure the receive-side characteristics of the ppp interface.
20077c478bd9Sstevel@tonic-gate  */
20087c478bd9Sstevel@tonic-gate /*ARGSUSED*/
20097c478bd9Sstevel@tonic-gate void
20107c478bd9Sstevel@tonic-gate ppp_recv_config(unit, mru, asyncmap, pcomp, accomp)
20117c478bd9Sstevel@tonic-gate 	int unit;
20127c478bd9Sstevel@tonic-gate 	int mru;
20137c478bd9Sstevel@tonic-gate 	u_int32_t asyncmap;
20147c478bd9Sstevel@tonic-gate 	int pcomp;
20157c478bd9Sstevel@tonic-gate 	int accomp;
20167c478bd9Sstevel@tonic-gate {
20177c478bd9Sstevel@tonic-gate 	uint32_t cf[2];
20187c478bd9Sstevel@tonic-gate 
20197c478bd9Sstevel@tonic-gate 	if (pppfd == -1) {
20207c478bd9Sstevel@tonic-gate 		error("ppp_recv_config called with invalid device handle");
20217c478bd9Sstevel@tonic-gate 		return;
20227c478bd9Sstevel@tonic-gate 	}
20237c478bd9Sstevel@tonic-gate 	cf[0] = mru;
20247c478bd9Sstevel@tonic-gate 	if (strioctl(pppfd, PPPIO_MRU, cf, sizeof (cf[0]), 0) < 0) {
20257c478bd9Sstevel@tonic-gate 		if (hungup && errno == ENXIO) {
20267c478bd9Sstevel@tonic-gate 			return;
20277c478bd9Sstevel@tonic-gate 		}
20287c478bd9Sstevel@tonic-gate 		error("Couldn't set MRU: %m");
20297c478bd9Sstevel@tonic-gate 	}
20307c478bd9Sstevel@tonic-gate 	if (fdmuxid != -1) {
20317c478bd9Sstevel@tonic-gate 		if (!sync_serial) {
20327c478bd9Sstevel@tonic-gate 			if (strioctl(pppfd, PPPIO_RACCM, &asyncmap,
20337c478bd9Sstevel@tonic-gate 			    sizeof (asyncmap), 0) < 0) {
20347c478bd9Sstevel@tonic-gate 				error("Couldn't set receive ACCM: %m");
20357c478bd9Sstevel@tonic-gate 			}
20367c478bd9Sstevel@tonic-gate 		}
20377c478bd9Sstevel@tonic-gate 		cf[0] = (pcomp ? DECOMP_PROT : 0) + (accomp ? DECOMP_AC : 0);
20387c478bd9Sstevel@tonic-gate 		cf[1] = DECOMP_PROT | DECOMP_AC;
20397c478bd9Sstevel@tonic-gate 
20407c478bd9Sstevel@tonic-gate 		if (any_compressions() && strioctl(pppfd, PPPIO_CFLAGS, cf,
20417c478bd9Sstevel@tonic-gate 		    sizeof (cf), sizeof (cf[0])) < 0) {
20427c478bd9Sstevel@tonic-gate 			error("Couldn't set prot/AC decompression: %m");
20437c478bd9Sstevel@tonic-gate 		}
20447c478bd9Sstevel@tonic-gate 	}
20457c478bd9Sstevel@tonic-gate }
20467c478bd9Sstevel@tonic-gate 
20477c478bd9Sstevel@tonic-gate #ifdef NEGOTIATE_FCS
20487c478bd9Sstevel@tonic-gate /*
20497c478bd9Sstevel@tonic-gate  * ppp_send_fcs()
20507c478bd9Sstevel@tonic-gate  *
20517c478bd9Sstevel@tonic-gate  * Configure the sender-side FCS.
20527c478bd9Sstevel@tonic-gate  */
20537c478bd9Sstevel@tonic-gate /*ARGSUSED*/
20547c478bd9Sstevel@tonic-gate void
20557c478bd9Sstevel@tonic-gate ppp_send_fcs(unit, fcstype)
20567c478bd9Sstevel@tonic-gate 	int unit, fcstype;
20577c478bd9Sstevel@tonic-gate {
20587c478bd9Sstevel@tonic-gate 	uint32_t fcs;
20597c478bd9Sstevel@tonic-gate 
20607c478bd9Sstevel@tonic-gate 	if (sync_serial) {
20617c478bd9Sstevel@tonic-gate 		return;
20627c478bd9Sstevel@tonic-gate 	}
20637c478bd9Sstevel@tonic-gate 
20647c478bd9Sstevel@tonic-gate 	if (fcstype & FCSALT_32) {
20657c478bd9Sstevel@tonic-gate 		fcs = PPPFCS_32;
20667c478bd9Sstevel@tonic-gate 	} else if (fcstype & FCSALT_NULL) {
20677c478bd9Sstevel@tonic-gate 		fcs = PPPFCS_NONE;
20687c478bd9Sstevel@tonic-gate 	} else {
20697c478bd9Sstevel@tonic-gate 		fcs = PPPFCS_16;
20707c478bd9Sstevel@tonic-gate 	}
20717c478bd9Sstevel@tonic-gate 	if (strioctl(pppfd, PPPIO_XFCS, &fcs, sizeof (fcs), 0) < 0) {
20727c478bd9Sstevel@tonic-gate 		warn("Couldn't set transmit FCS: %m");
20737c478bd9Sstevel@tonic-gate 	}
20747c478bd9Sstevel@tonic-gate }
20757c478bd9Sstevel@tonic-gate 
20767c478bd9Sstevel@tonic-gate /*
20777c478bd9Sstevel@tonic-gate  * ppp_recv_fcs()
20787c478bd9Sstevel@tonic-gate  *
20797c478bd9Sstevel@tonic-gate  * Configure the receiver-side FCS.
20807c478bd9Sstevel@tonic-gate  */
20817c478bd9Sstevel@tonic-gate /*ARGSUSED*/
20827c478bd9Sstevel@tonic-gate void
20837c478bd9Sstevel@tonic-gate ppp_recv_fcs(unit, fcstype)
20847c478bd9Sstevel@tonic-gate 	int unit, fcstype;
20857c478bd9Sstevel@tonic-gate {
20867c478bd9Sstevel@tonic-gate 	uint32_t fcs;
20877c478bd9Sstevel@tonic-gate 
20887c478bd9Sstevel@tonic-gate 	if (sync_serial) {
20897c478bd9Sstevel@tonic-gate 		return;
20907c478bd9Sstevel@tonic-gate 	}
20917c478bd9Sstevel@tonic-gate 
20927c478bd9Sstevel@tonic-gate 	if (fcstype & FCSALT_32) {
20937c478bd9Sstevel@tonic-gate 		fcs = PPPFCS_32;
20947c478bd9Sstevel@tonic-gate 	} else if (fcstype & FCSALT_NULL) {
20957c478bd9Sstevel@tonic-gate 		fcs = PPPFCS_NONE;
20967c478bd9Sstevel@tonic-gate 	} else {
20977c478bd9Sstevel@tonic-gate 		fcs = PPPFCS_16;
20987c478bd9Sstevel@tonic-gate 	}
20997c478bd9Sstevel@tonic-gate 	if (strioctl(pppfd, PPPIO_RFCS, &fcs, sizeof (fcs), 0) < 0) {
21007c478bd9Sstevel@tonic-gate 		warn("Couldn't set receive FCS: %m");
21017c478bd9Sstevel@tonic-gate 	}
21027c478bd9Sstevel@tonic-gate }
21037c478bd9Sstevel@tonic-gate #endif
21047c478bd9Sstevel@tonic-gate 
21057c478bd9Sstevel@tonic-gate /*
21067c478bd9Sstevel@tonic-gate  * ccp_test()
21077c478bd9Sstevel@tonic-gate  *
21087c478bd9Sstevel@tonic-gate  * Ask kernel whether a given compression method is acceptable for use.
21097c478bd9Sstevel@tonic-gate  */
21107c478bd9Sstevel@tonic-gate /*ARGSUSED*/
21117c478bd9Sstevel@tonic-gate int
21127c478bd9Sstevel@tonic-gate ccp_test(unit, opt_ptr, opt_len, for_transmit)
21137c478bd9Sstevel@tonic-gate 	int unit;
21147c478bd9Sstevel@tonic-gate 	uchar_t *opt_ptr;
21157c478bd9Sstevel@tonic-gate 	int opt_len;
21167c478bd9Sstevel@tonic-gate 	int for_transmit;
21177c478bd9Sstevel@tonic-gate {
21187c478bd9Sstevel@tonic-gate 	if (strioctl(pppfd, (for_transmit ? PPPIO_XCOMP : PPPIO_RCOMP),
21197c478bd9Sstevel@tonic-gate 	    opt_ptr, opt_len, 0) >= 0) {
21207c478bd9Sstevel@tonic-gate 		return (1);
21217c478bd9Sstevel@tonic-gate 	}
21227c478bd9Sstevel@tonic-gate 	warn("Error in %s ioctl: %m",
21237c478bd9Sstevel@tonic-gate 	    (for_transmit ? "PPPIO_XCOMP" : "PPPIO_RCOMP"));
21247c478bd9Sstevel@tonic-gate 	return ((errno == ENOSR) ? 0 : -1);
21257c478bd9Sstevel@tonic-gate }
21267c478bd9Sstevel@tonic-gate 
21277c478bd9Sstevel@tonic-gate #ifdef COMP_TUNE
21287c478bd9Sstevel@tonic-gate /*
21297c478bd9Sstevel@tonic-gate  * ccp_tune()
21307c478bd9Sstevel@tonic-gate  *
21317c478bd9Sstevel@tonic-gate  * Tune compression effort level.
21327c478bd9Sstevel@tonic-gate  */
21337c478bd9Sstevel@tonic-gate /*ARGSUSED*/
21347c478bd9Sstevel@tonic-gate void
21357c478bd9Sstevel@tonic-gate ccp_tune(unit, effort)
21367c478bd9Sstevel@tonic-gate 	int unit, effort;
21377c478bd9Sstevel@tonic-gate {
21387c478bd9Sstevel@tonic-gate 	uint32_t x;
21397c478bd9Sstevel@tonic-gate 
21407c478bd9Sstevel@tonic-gate 	x = effort;
21417c478bd9Sstevel@tonic-gate 	if (strioctl(pppfd, PPPIO_COMPLEV, &x, sizeof (x), 0) < 0) {
21427c478bd9Sstevel@tonic-gate 		warn("unable to set compression effort level: %m");
21437c478bd9Sstevel@tonic-gate 	}
21447c478bd9Sstevel@tonic-gate }
21457c478bd9Sstevel@tonic-gate #endif
21467c478bd9Sstevel@tonic-gate 
21477c478bd9Sstevel@tonic-gate /*
21487c478bd9Sstevel@tonic-gate  * ccp_flags_set()
21497c478bd9Sstevel@tonic-gate  *
21507c478bd9Sstevel@tonic-gate  * Inform kernel about the current state of CCP.
21517c478bd9Sstevel@tonic-gate  */
21527c478bd9Sstevel@tonic-gate /*ARGSUSED*/
21537c478bd9Sstevel@tonic-gate void
21547c478bd9Sstevel@tonic-gate ccp_flags_set(unit, isopen, isup)
21557c478bd9Sstevel@tonic-gate 	int unit, isopen, isup;
21567c478bd9Sstevel@tonic-gate {
21577c478bd9Sstevel@tonic-gate 	uint32_t cf[2];
21587c478bd9Sstevel@tonic-gate 
21597c478bd9Sstevel@tonic-gate 	cf[0] = (isopen ? CCP_ISOPEN : 0) + (isup ? CCP_ISUP : 0);
21607c478bd9Sstevel@tonic-gate 	cf[1] = CCP_ISOPEN | CCP_ISUP | CCP_ERROR | CCP_FATALERROR;
21617c478bd9Sstevel@tonic-gate 
21627c478bd9Sstevel@tonic-gate 	if (strioctl(pppfd, PPPIO_CFLAGS, cf, sizeof (cf), sizeof (cf[0]))
21637c478bd9Sstevel@tonic-gate 	    < 0) {
21647c478bd9Sstevel@tonic-gate 		if (!hungup || errno != ENXIO) {
21657c478bd9Sstevel@tonic-gate 			error("Couldn't set kernel CCP state: %m");
21667c478bd9Sstevel@tonic-gate 		}
21677c478bd9Sstevel@tonic-gate 	}
21687c478bd9Sstevel@tonic-gate }
21697c478bd9Sstevel@tonic-gate 
21707c478bd9Sstevel@tonic-gate /*
21717c478bd9Sstevel@tonic-gate  * get_idle_time()
21727c478bd9Sstevel@tonic-gate  *
21737c478bd9Sstevel@tonic-gate  * Return how long the link has been idle.
21747c478bd9Sstevel@tonic-gate  */
21757c478bd9Sstevel@tonic-gate /*ARGSUSED*/
21767c478bd9Sstevel@tonic-gate int
21777c478bd9Sstevel@tonic-gate get_idle_time(u, pids)
21787c478bd9Sstevel@tonic-gate 	int u;
21797c478bd9Sstevel@tonic-gate 	struct ppp_idle *pids;
21807c478bd9Sstevel@tonic-gate {
21817c478bd9Sstevel@tonic-gate 	int rc;
21827c478bd9Sstevel@tonic-gate 
21837c478bd9Sstevel@tonic-gate 	rc = strioctl(pppfd, PPPIO_GIDLE, pids, 0, sizeof (struct ppp_idle));
21847c478bd9Sstevel@tonic-gate 	if (rc < 0) {
21857c478bd9Sstevel@tonic-gate 		warn("unable to obtain idle time: %m");
21867c478bd9Sstevel@tonic-gate 	}
21877c478bd9Sstevel@tonic-gate 	return ((rc == 0) ? 1 : 0);
21887c478bd9Sstevel@tonic-gate }
21897c478bd9Sstevel@tonic-gate 
21907c478bd9Sstevel@tonic-gate /*
21917c478bd9Sstevel@tonic-gate  * get_ppp_stats()
21927c478bd9Sstevel@tonic-gate  *
21937c478bd9Sstevel@tonic-gate  * Return statistics for the link.
21947c478bd9Sstevel@tonic-gate  */
21957c478bd9Sstevel@tonic-gate /*ARGSUSED*/
21967c478bd9Sstevel@tonic-gate int
21977c478bd9Sstevel@tonic-gate get_ppp_stats(u, stats)
21987c478bd9Sstevel@tonic-gate 	int u;
21997c478bd9Sstevel@tonic-gate 	struct pppd_stats *stats;
22007c478bd9Sstevel@tonic-gate {
22017c478bd9Sstevel@tonic-gate 	struct ppp_stats64 s64;
22027c478bd9Sstevel@tonic-gate 	struct ppp_stats s;
22037c478bd9Sstevel@tonic-gate 
22047c478bd9Sstevel@tonic-gate 	/* Try first to get these from the 64-bit interface */
22057c478bd9Sstevel@tonic-gate 	if (strioctl(pppfd, PPPIO_GETSTAT64, &s64, 0, sizeof (s64)) >= 0) {
22067c478bd9Sstevel@tonic-gate 		stats->bytes_in = s64.p.ppp_ibytes;
22077c478bd9Sstevel@tonic-gate 		stats->bytes_out = s64.p.ppp_obytes;
22087c478bd9Sstevel@tonic-gate 		stats->pkts_in = s64.p.ppp_ipackets;
22097c478bd9Sstevel@tonic-gate 		stats->pkts_out = s64.p.ppp_opackets;
22107c478bd9Sstevel@tonic-gate 		return (1);
22117c478bd9Sstevel@tonic-gate 	}
22127c478bd9Sstevel@tonic-gate 
22137c478bd9Sstevel@tonic-gate 	if (strioctl(pppfd, PPPIO_GETSTAT, &s, 0, sizeof (s)) < 0) {
22147c478bd9Sstevel@tonic-gate 		error("Couldn't get link statistics: %m");
22157c478bd9Sstevel@tonic-gate 		return (0);
22167c478bd9Sstevel@tonic-gate 	}
22177c478bd9Sstevel@tonic-gate 	stats->bytes_in = s.p.ppp_ibytes;
22187c478bd9Sstevel@tonic-gate 	stats->bytes_out = s.p.ppp_obytes;
22197c478bd9Sstevel@tonic-gate 	stats->pkts_in = s.p.ppp_ipackets;
22207c478bd9Sstevel@tonic-gate 	stats->pkts_out = s.p.ppp_opackets;
22217c478bd9Sstevel@tonic-gate 	return (1);
22227c478bd9Sstevel@tonic-gate }
22237c478bd9Sstevel@tonic-gate 
22247c478bd9Sstevel@tonic-gate #if defined(FILTER_PACKETS)
22257c478bd9Sstevel@tonic-gate /*
22267c478bd9Sstevel@tonic-gate  * set_filters()
22277c478bd9Sstevel@tonic-gate  *
22287c478bd9Sstevel@tonic-gate  * Transfer the pass and active filters to the kernel.
22297c478bd9Sstevel@tonic-gate  */
22307c478bd9Sstevel@tonic-gate int
22317c478bd9Sstevel@tonic-gate set_filters(pass, active)
22327c478bd9Sstevel@tonic-gate 	struct bpf_program *pass;
22337c478bd9Sstevel@tonic-gate 	struct bpf_program *active;
22347c478bd9Sstevel@tonic-gate {
22357c478bd9Sstevel@tonic-gate 	int ret = 1;
22367c478bd9Sstevel@tonic-gate 
22377c478bd9Sstevel@tonic-gate 	if (pass->bf_len > 0) {
22387c478bd9Sstevel@tonic-gate 		if (strioctl(pppfd, PPPIO_PASSFILT, pass,
22397c478bd9Sstevel@tonic-gate 		    sizeof (struct bpf_program), 0) < 0) {
22407c478bd9Sstevel@tonic-gate 			error("Couldn't set pass-filter in kernel: %m");
22417c478bd9Sstevel@tonic-gate 			ret = 0;
22427c478bd9Sstevel@tonic-gate 		}
22437c478bd9Sstevel@tonic-gate 	}
22447c478bd9Sstevel@tonic-gate 	if (active->bf_len > 0) {
22457c478bd9Sstevel@tonic-gate 		if (strioctl(pppfd, PPPIO_ACTIVEFILT, active,
22467c478bd9Sstevel@tonic-gate 		    sizeof (struct bpf_program), 0) < 0) {
22477c478bd9Sstevel@tonic-gate 			error("Couldn't set active-filter in kernel: %m");
22487c478bd9Sstevel@tonic-gate 			ret = 0;
22497c478bd9Sstevel@tonic-gate 		}
22507c478bd9Sstevel@tonic-gate 	}
22517c478bd9Sstevel@tonic-gate 	return (ret);
22527c478bd9Sstevel@tonic-gate }
22537c478bd9Sstevel@tonic-gate #endif /* FILTER_PACKETS */
22547c478bd9Sstevel@tonic-gate 
22557c478bd9Sstevel@tonic-gate /*
22567c478bd9Sstevel@tonic-gate  * ccp_fatal_error()
22577c478bd9Sstevel@tonic-gate  *
22587c478bd9Sstevel@tonic-gate  * Returns 1 if decompression was disabled as a result of an error detected
22597c478bd9Sstevel@tonic-gate  * after decompression of a packet, 0 otherwise.  This is necessary because
22607c478bd9Sstevel@tonic-gate  * of patent nonsense.
22617c478bd9Sstevel@tonic-gate  */
22627c478bd9Sstevel@tonic-gate /*ARGSUSED*/
22637c478bd9Sstevel@tonic-gate int
22647c478bd9Sstevel@tonic-gate ccp_fatal_error(unit)
22657c478bd9Sstevel@tonic-gate 	int unit;
22667c478bd9Sstevel@tonic-gate {
22677c478bd9Sstevel@tonic-gate 	uint32_t cf[2];
22687c478bd9Sstevel@tonic-gate 
22697c478bd9Sstevel@tonic-gate 	cf[0] = cf[1] = 0;
22707c478bd9Sstevel@tonic-gate 	if (strioctl(pppfd, PPPIO_CFLAGS, cf, sizeof (cf), sizeof (cf[0]))
22717c478bd9Sstevel@tonic-gate 	    < 0) {
22727c478bd9Sstevel@tonic-gate 		if (errno != ENXIO && errno != EINVAL) {
22737c478bd9Sstevel@tonic-gate 			error("Couldn't get compression flags: %m");
22747c478bd9Sstevel@tonic-gate 		}
22757c478bd9Sstevel@tonic-gate 		return (0);
22767c478bd9Sstevel@tonic-gate 	}
22777c478bd9Sstevel@tonic-gate 	return (cf[0] & CCP_FATALERROR);
22787c478bd9Sstevel@tonic-gate }
22797c478bd9Sstevel@tonic-gate 
22807c478bd9Sstevel@tonic-gate /*
22817c478bd9Sstevel@tonic-gate  * sifvjcomp()
22827c478bd9Sstevel@tonic-gate  *
22837c478bd9Sstevel@tonic-gate  * Config TCP header compression.
22847c478bd9Sstevel@tonic-gate  */
22857c478bd9Sstevel@tonic-gate /*ARGSUSED*/
22867c478bd9Sstevel@tonic-gate int
22877c478bd9Sstevel@tonic-gate sifvjcomp(u, vjcomp, xcidcomp, xmaxcid)
22887c478bd9Sstevel@tonic-gate 	int u, vjcomp, xcidcomp, xmaxcid;
22897c478bd9Sstevel@tonic-gate {
22907c478bd9Sstevel@tonic-gate 	uint32_t cf[2];
22917c478bd9Sstevel@tonic-gate 	uchar_t maxcid[2];
22927c478bd9Sstevel@tonic-gate 
22937c478bd9Sstevel@tonic-gate 	/*
22947c478bd9Sstevel@tonic-gate 	 * Since VJ compression code is in the comp module, there's no
22957c478bd9Sstevel@tonic-gate 	 * point of sending down any ioctls pertaining to VJ compression
22967c478bd9Sstevel@tonic-gate 	 * when the module isn't pushed on the stream.
22977c478bd9Sstevel@tonic-gate 	 */
22987c478bd9Sstevel@tonic-gate 	if (!any_compressions()) {
22997c478bd9Sstevel@tonic-gate 		return (1);
23007c478bd9Sstevel@tonic-gate 	}
23017c478bd9Sstevel@tonic-gate 
23027c478bd9Sstevel@tonic-gate 	if (vjcomp) {
23037c478bd9Sstevel@tonic-gate 		maxcid[0] = xcidcomp;
23047c478bd9Sstevel@tonic-gate 		maxcid[1] = 15;		/* XXX should be rmaxcid */
23057c478bd9Sstevel@tonic-gate 
23067c478bd9Sstevel@tonic-gate 		if (strioctl(pppfd, PPPIO_VJINIT, maxcid,
23077c478bd9Sstevel@tonic-gate 		    sizeof (maxcid), 0) < 0) {
23087c478bd9Sstevel@tonic-gate 			error("Couldn't initialize VJ compression: %m");
23097c478bd9Sstevel@tonic-gate 			return (0);
23107c478bd9Sstevel@tonic-gate 		}
23117c478bd9Sstevel@tonic-gate 	}
23127c478bd9Sstevel@tonic-gate 
23137c478bd9Sstevel@tonic-gate 	cf[0] = (vjcomp ? COMP_VJC + DECOMP_VJC : 0)	/* XXX this is wrong */
23147c478bd9Sstevel@tonic-gate 		+ (xcidcomp? COMP_VJCCID + DECOMP_VJCCID: 0);
23157c478bd9Sstevel@tonic-gate 
23167c478bd9Sstevel@tonic-gate 	cf[1] = COMP_VJC + DECOMP_VJC + COMP_VJCCID + DECOMP_VJCCID;
23177c478bd9Sstevel@tonic-gate 
23187c478bd9Sstevel@tonic-gate 	if (strioctl(pppfd, PPPIO_CFLAGS, cf, sizeof (cf), sizeof (cf[0]))
23197c478bd9Sstevel@tonic-gate 	    < 0) {
23207c478bd9Sstevel@tonic-gate 		if (vjcomp) {
23217c478bd9Sstevel@tonic-gate 			error("Couldn't enable VJ compression: %m");
23227c478bd9Sstevel@tonic-gate 		} else {
23237c478bd9Sstevel@tonic-gate 			error("Couldn't disable VJ compression: %m");
23247c478bd9Sstevel@tonic-gate 		}
23257c478bd9Sstevel@tonic-gate 		return (0);
23267c478bd9Sstevel@tonic-gate 	}
23277c478bd9Sstevel@tonic-gate 	return (1);
23287c478bd9Sstevel@tonic-gate }
23297c478bd9Sstevel@tonic-gate 
23307c478bd9Sstevel@tonic-gate /*
23317c478bd9Sstevel@tonic-gate  * siflags()
23327c478bd9Sstevel@tonic-gate  *
23337c478bd9Sstevel@tonic-gate  * Set or clear the IP interface flags.
23347c478bd9Sstevel@tonic-gate  */
23357c478bd9Sstevel@tonic-gate int
23367c478bd9Sstevel@tonic-gate siflags(f, set)
23377c478bd9Sstevel@tonic-gate 	u_int32_t f;
23387c478bd9Sstevel@tonic-gate 	int set;
23397c478bd9Sstevel@tonic-gate {
23407c478bd9Sstevel@tonic-gate 	struct ifreq ifr;
23417c478bd9Sstevel@tonic-gate 
23427c478bd9Sstevel@tonic-gate 	if (!IPCP_ENABLED || (ipmuxid == -1)) {
23437c478bd9Sstevel@tonic-gate 		return (0);
23447c478bd9Sstevel@tonic-gate 	}
23457c478bd9Sstevel@tonic-gate 	if (ipfd == -1 && open_ipfd() == -1)
23467c478bd9Sstevel@tonic-gate 		return (0);
23477c478bd9Sstevel@tonic-gate 	BZERO(&ifr, sizeof (ifr));
23487c478bd9Sstevel@tonic-gate 	(void) strlcpy(ifr.ifr_name, ifname, sizeof (ifr.ifr_name));
23497c478bd9Sstevel@tonic-gate 	if (myioctl(ipfd, SIOCGIFFLAGS, &ifr) < 0) {
23507c478bd9Sstevel@tonic-gate 		error("Couldn't get IP interface flags: %m");
23517c478bd9Sstevel@tonic-gate 		return (0);
23527c478bd9Sstevel@tonic-gate 	}
23537c478bd9Sstevel@tonic-gate 	if (set) {
23547c478bd9Sstevel@tonic-gate 		ifr.ifr_flags |= f;
23557c478bd9Sstevel@tonic-gate 	} else {
23567c478bd9Sstevel@tonic-gate 		ifr.ifr_flags &= ~f;
23577c478bd9Sstevel@tonic-gate 	}
23587c478bd9Sstevel@tonic-gate 	if (myioctl(ipfd, SIOCSIFFLAGS, &ifr) < 0) {
23597c478bd9Sstevel@tonic-gate 		error("Couldn't set IP interface flags: %m");
23607c478bd9Sstevel@tonic-gate 		return (0);
23617c478bd9Sstevel@tonic-gate 	}
23627c478bd9Sstevel@tonic-gate 	return (1);
23637c478bd9Sstevel@tonic-gate }
23647c478bd9Sstevel@tonic-gate 
23657c478bd9Sstevel@tonic-gate /*
23667c478bd9Sstevel@tonic-gate  * sifup()
23677c478bd9Sstevel@tonic-gate  *
23687c478bd9Sstevel@tonic-gate  * Config the interface up and enable IP packets to pass.
23697c478bd9Sstevel@tonic-gate  */
23707c478bd9Sstevel@tonic-gate /*ARGSUSED*/
23717c478bd9Sstevel@tonic-gate int
23727c478bd9Sstevel@tonic-gate sifup(u)
23737c478bd9Sstevel@tonic-gate 	int u;
23747c478bd9Sstevel@tonic-gate {
23757c478bd9Sstevel@tonic-gate 	if (if_is_up) {
23767c478bd9Sstevel@tonic-gate 		return (1);
23777c478bd9Sstevel@tonic-gate 	} else if (!IPCP_ENABLED) {
23787c478bd9Sstevel@tonic-gate 		warn("sifup called when IPCP is disabled");
23797c478bd9Sstevel@tonic-gate 		return (0);
23807c478bd9Sstevel@tonic-gate 	} else if (ipmuxid == -1) {
23817c478bd9Sstevel@tonic-gate 		warn("sifup called in wrong state");
23827c478bd9Sstevel@tonic-gate 		return (0);
23837c478bd9Sstevel@tonic-gate 	} else if (!siflags(IFF_UP, 1)) {
23847c478bd9Sstevel@tonic-gate 		error("Unable to mark the IP interface UP");
23857c478bd9Sstevel@tonic-gate 		return (0);
23867c478bd9Sstevel@tonic-gate 	}
23877c478bd9Sstevel@tonic-gate 	if_is_up = 1;
23887c478bd9Sstevel@tonic-gate 	return (1);
23897c478bd9Sstevel@tonic-gate }
23907c478bd9Sstevel@tonic-gate 
23917c478bd9Sstevel@tonic-gate /*
23927c478bd9Sstevel@tonic-gate  * sifdown()
23937c478bd9Sstevel@tonic-gate  *
23947c478bd9Sstevel@tonic-gate  * Config the interface down and disable IP.  Possibly called from die(),
23957c478bd9Sstevel@tonic-gate  * so there shouldn't be any call to die() here.
23967c478bd9Sstevel@tonic-gate  */
23977c478bd9Sstevel@tonic-gate /*ARGSUSED*/
23987c478bd9Sstevel@tonic-gate int
23997c478bd9Sstevel@tonic-gate sifdown(u)
24007c478bd9Sstevel@tonic-gate 	int u;
24017c478bd9Sstevel@tonic-gate {
24027c478bd9Sstevel@tonic-gate 	if (!IPCP_ENABLED) {
24037c478bd9Sstevel@tonic-gate 		warn("sifdown called when IPCP is disabled");
24047c478bd9Sstevel@tonic-gate 		return (0);
24057c478bd9Sstevel@tonic-gate 	} else if (!if_is_up || (ipmuxid == -1)) {
24067c478bd9Sstevel@tonic-gate 		return (1);
24077c478bd9Sstevel@tonic-gate 	} else if (!siflags(IFF_UP, 0)) {
24087c478bd9Sstevel@tonic-gate 		error("Unable to mark the IP interface DOWN");
24097c478bd9Sstevel@tonic-gate 		return (0);
24107c478bd9Sstevel@tonic-gate 	}
24117c478bd9Sstevel@tonic-gate 	if_is_up = 0;
24127c478bd9Sstevel@tonic-gate 	return (1);
24137c478bd9Sstevel@tonic-gate }
24147c478bd9Sstevel@tonic-gate 
24157c478bd9Sstevel@tonic-gate /*
24167c478bd9Sstevel@tonic-gate  * sifnpmode()
24177c478bd9Sstevel@tonic-gate  *
24187c478bd9Sstevel@tonic-gate  * Set the mode for handling packets for a given NP.  Not worried
24197c478bd9Sstevel@tonic-gate  * about performance here since this is done only rarely.
24207c478bd9Sstevel@tonic-gate  */
24217c478bd9Sstevel@tonic-gate /*ARGSUSED*/
24227c478bd9Sstevel@tonic-gate int
24237c478bd9Sstevel@tonic-gate sifnpmode(u, proto, mode)
24247c478bd9Sstevel@tonic-gate 	int u;
24257c478bd9Sstevel@tonic-gate 	int proto;
24267c478bd9Sstevel@tonic-gate 	enum NPmode mode;
24277c478bd9Sstevel@tonic-gate {
24287c478bd9Sstevel@tonic-gate 	uint32_t npi[2];
24297c478bd9Sstevel@tonic-gate 	const char *cp;
24307c478bd9Sstevel@tonic-gate 	static const struct npi_entry {
24317c478bd9Sstevel@tonic-gate 		enum NPmode ne_value;
24327c478bd9Sstevel@tonic-gate 		const char *ne_name;
24337c478bd9Sstevel@tonic-gate 	} npi_list[] = {
24347c478bd9Sstevel@tonic-gate 		{ NPMODE_PASS, "pass" },
24357c478bd9Sstevel@tonic-gate 		{ NPMODE_DROP, "drop" },
24367c478bd9Sstevel@tonic-gate 		{ NPMODE_ERROR, "error" },
24377c478bd9Sstevel@tonic-gate 		{ NPMODE_QUEUE, "queue" },
24387c478bd9Sstevel@tonic-gate 	};
24397c478bd9Sstevel@tonic-gate 	int i;
24407c478bd9Sstevel@tonic-gate 	char pname[32], mname[32];
24417c478bd9Sstevel@tonic-gate 
24427c478bd9Sstevel@tonic-gate 	npi[0] = proto;
24437c478bd9Sstevel@tonic-gate 	npi[1] = (uint32_t)mode;
24447c478bd9Sstevel@tonic-gate 
24457c478bd9Sstevel@tonic-gate 	cp = protocol_name(proto);
24467c478bd9Sstevel@tonic-gate 	if (cp == NULL)
24477c478bd9Sstevel@tonic-gate 		(void) slprintf(pname, sizeof (pname), "NP %04X", proto);
24487c478bd9Sstevel@tonic-gate 	else
24497c478bd9Sstevel@tonic-gate 		(void) strlcpy(pname, cp, sizeof (pname));
24507c478bd9Sstevel@tonic-gate 	for (i = 0; i < Dim(npi_list); i++)
24517c478bd9Sstevel@tonic-gate 		if (npi_list[i].ne_value == mode)
24527c478bd9Sstevel@tonic-gate 			break;
24537c478bd9Sstevel@tonic-gate 	if (i >= Dim(npi_list))
24547c478bd9Sstevel@tonic-gate 		(void) slprintf(mname, sizeof (mname), "mode %d", (int)mode);
24557c478bd9Sstevel@tonic-gate 	else
24567c478bd9Sstevel@tonic-gate 		(void) strlcpy(mname, npi_list[i].ne_name, sizeof (mname));
24577c478bd9Sstevel@tonic-gate 
24587c478bd9Sstevel@tonic-gate 	if ((proto == PPP_IP && !if_is_up) ||
24597c478bd9Sstevel@tonic-gate 	    (proto == PPP_IPV6 && !if6_is_up)) {
24607c478bd9Sstevel@tonic-gate 		dbglog("ignoring request to set %s to %s", pname, mname);
24617c478bd9Sstevel@tonic-gate 		return (1);
24627c478bd9Sstevel@tonic-gate 	}
24637c478bd9Sstevel@tonic-gate 	if (strioctl(pppfd, PPPIO_NPMODE, npi, sizeof (npi), 0) < 0) {
24647c478bd9Sstevel@tonic-gate 		error("unable to set %s to %s: %m", pname, mname);
24657c478bd9Sstevel@tonic-gate 		return (0);
24667c478bd9Sstevel@tonic-gate 	}
24677c478bd9Sstevel@tonic-gate 	return (1);
24687c478bd9Sstevel@tonic-gate }
24697c478bd9Sstevel@tonic-gate 
24707c478bd9Sstevel@tonic-gate /*
24717c478bd9Sstevel@tonic-gate  * sifmtu()
24727c478bd9Sstevel@tonic-gate  *
24737c478bd9Sstevel@tonic-gate  * Config the interface IP MTU.
24747c478bd9Sstevel@tonic-gate  */
24757c478bd9Sstevel@tonic-gate int
24767c478bd9Sstevel@tonic-gate sifmtu(mtu)
24777c478bd9Sstevel@tonic-gate 	int mtu;
24787c478bd9Sstevel@tonic-gate {
24797c478bd9Sstevel@tonic-gate 	struct ifreq ifr;
24807c478bd9Sstevel@tonic-gate 
24817c478bd9Sstevel@tonic-gate 	if (!IPCP_ENABLED || (ipmuxid == -1)) {
24827c478bd9Sstevel@tonic-gate 		return (0);
24837c478bd9Sstevel@tonic-gate 	}
24847c478bd9Sstevel@tonic-gate 	if (ipfd == -1 && open_ipfd() == -1)
24857c478bd9Sstevel@tonic-gate 		return (0);
24867c478bd9Sstevel@tonic-gate 	BZERO(&ifr, sizeof (ifr));
24877c478bd9Sstevel@tonic-gate 	(void) strlcpy(ifr.ifr_name, ifname, sizeof (ifr.ifr_name));
24887c478bd9Sstevel@tonic-gate 	ifr.ifr_metric = mtu;
24897c478bd9Sstevel@tonic-gate 	if (myioctl(ipfd, SIOCSIFMTU, &ifr) < 0) {
24907c478bd9Sstevel@tonic-gate 		error("Couldn't set IP MTU on %s to %d: %m", ifr.ifr_name,
24917c478bd9Sstevel@tonic-gate 		    mtu);
24927c478bd9Sstevel@tonic-gate 		return (0);
24937c478bd9Sstevel@tonic-gate 	}
24947c478bd9Sstevel@tonic-gate 	return (1);
24957c478bd9Sstevel@tonic-gate }
24967c478bd9Sstevel@tonic-gate 
24977c478bd9Sstevel@tonic-gate /*
24987c478bd9Sstevel@tonic-gate  * sifaddr()
24997c478bd9Sstevel@tonic-gate  *
25007c478bd9Sstevel@tonic-gate  * Config the interface IP addresses and netmask.
25017c478bd9Sstevel@tonic-gate  */
25027c478bd9Sstevel@tonic-gate /*ARGSUSED*/
25037c478bd9Sstevel@tonic-gate int
25047c478bd9Sstevel@tonic-gate sifaddr(u, o, h, m)
25057c478bd9Sstevel@tonic-gate 	int u;
25067c478bd9Sstevel@tonic-gate 	u_int32_t o;
25077c478bd9Sstevel@tonic-gate 	u_int32_t h;
25087c478bd9Sstevel@tonic-gate 	u_int32_t m;
25097c478bd9Sstevel@tonic-gate {
25107c478bd9Sstevel@tonic-gate 	struct ifreq ifr;
25117c478bd9Sstevel@tonic-gate 	struct sockaddr_in sin;
25127c478bd9Sstevel@tonic-gate 
25137c478bd9Sstevel@tonic-gate 	if (!IPCP_ENABLED || (ipmuxid == -1 && plumb_ipif(u) == 0)) {
25147c478bd9Sstevel@tonic-gate 		return (0);
25157c478bd9Sstevel@tonic-gate 	}
25167c478bd9Sstevel@tonic-gate 	if (ipfd == -1 && open_ipfd() == -1)
25177c478bd9Sstevel@tonic-gate 		return (0);
25187c478bd9Sstevel@tonic-gate 	/*
25197c478bd9Sstevel@tonic-gate 	 * Set the IP interface MTU.
25207c478bd9Sstevel@tonic-gate 	 */
25217c478bd9Sstevel@tonic-gate 	if (!sifmtu(link_mtu)) {
25227c478bd9Sstevel@tonic-gate 		return (0);
25237c478bd9Sstevel@tonic-gate 	}
25247c478bd9Sstevel@tonic-gate 	/*
25257c478bd9Sstevel@tonic-gate 	 * Set the IP interface local point-to-point address.
25267c478bd9Sstevel@tonic-gate 	 */
25277c478bd9Sstevel@tonic-gate 	BZERO(&sin, sizeof (sin));
25287c478bd9Sstevel@tonic-gate 	sin.sin_family = AF_INET;
25297c478bd9Sstevel@tonic-gate 	sin.sin_addr.s_addr = o;
25307c478bd9Sstevel@tonic-gate 
25317c478bd9Sstevel@tonic-gate 	BZERO(&ifr, sizeof (ifr));
25327c478bd9Sstevel@tonic-gate 	(void) strlcpy(ifr.ifr_name, ifname, sizeof (ifr.ifr_name));
25337c478bd9Sstevel@tonic-gate 	ifr.ifr_addr = *(struct sockaddr *)&sin;
25347c478bd9Sstevel@tonic-gate 	if (myioctl(ipfd, SIOCSIFADDR, &ifr) < 0) {
25357c478bd9Sstevel@tonic-gate 		error("Couldn't set local IP address (%s): %m", ifr.ifr_name);
25367c478bd9Sstevel@tonic-gate 		return (0);
25377c478bd9Sstevel@tonic-gate 	}
25387c478bd9Sstevel@tonic-gate 	/*
25397c478bd9Sstevel@tonic-gate 	 * Set the IP interface remote point-to-point address.
25407c478bd9Sstevel@tonic-gate 	 */
25417c478bd9Sstevel@tonic-gate 	sin.sin_addr.s_addr = h;
25427c478bd9Sstevel@tonic-gate 
25437c478bd9Sstevel@tonic-gate 	ifr.ifr_dstaddr = *(struct sockaddr *)&sin;
25447c478bd9Sstevel@tonic-gate 	if (myioctl(ipfd, SIOCSIFDSTADDR, &ifr) < 0) {
25457c478bd9Sstevel@tonic-gate 		error("Couldn't set remote IP address (%s): %m", ifr.ifr_name);
25467c478bd9Sstevel@tonic-gate 		return (0);
25477c478bd9Sstevel@tonic-gate 	}
25487c478bd9Sstevel@tonic-gate 	remote_addr = h;
25497c478bd9Sstevel@tonic-gate 	return (1);
25507c478bd9Sstevel@tonic-gate }
25517c478bd9Sstevel@tonic-gate 
25527c478bd9Sstevel@tonic-gate /*
25537c478bd9Sstevel@tonic-gate  * cifaddr()
25547c478bd9Sstevel@tonic-gate  *
25557c478bd9Sstevel@tonic-gate  * Clear the interface IP addresses.
25567c478bd9Sstevel@tonic-gate  */
25577c478bd9Sstevel@tonic-gate /*ARGSUSED*/
25587c478bd9Sstevel@tonic-gate int
25597c478bd9Sstevel@tonic-gate cifaddr(u, o, h)
25607c478bd9Sstevel@tonic-gate 	int u;
25617c478bd9Sstevel@tonic-gate 	u_int32_t o;
25627c478bd9Sstevel@tonic-gate 	u_int32_t h;
25637c478bd9Sstevel@tonic-gate {
25647c478bd9Sstevel@tonic-gate 	if (!IPCP_ENABLED) {
25657c478bd9Sstevel@tonic-gate 		return (0);
25667c478bd9Sstevel@tonic-gate 	}
25677c478bd9Sstevel@tonic-gate 	/*
25687c478bd9Sstevel@tonic-gate 	 * Most of the work is done in sifdown().
25697c478bd9Sstevel@tonic-gate 	 */
25707c478bd9Sstevel@tonic-gate 	remote_addr = 0;
25717c478bd9Sstevel@tonic-gate 	return (1);
25727c478bd9Sstevel@tonic-gate }
25737c478bd9Sstevel@tonic-gate 
25747c478bd9Sstevel@tonic-gate /*
25757c478bd9Sstevel@tonic-gate  * sifroute()
25767c478bd9Sstevel@tonic-gate  *
25777c478bd9Sstevel@tonic-gate  * Add or delete a route.
25787c478bd9Sstevel@tonic-gate  */
25797c478bd9Sstevel@tonic-gate /*ARGSUSED*/
25807c478bd9Sstevel@tonic-gate static int
25817c478bd9Sstevel@tonic-gate sifroute(int u, u_int32_t l, u_int32_t g, int add, const char *str)
25827c478bd9Sstevel@tonic-gate {
25837c478bd9Sstevel@tonic-gate 	struct sockaddr_in sin_dst, sin_gtw;
25847c478bd9Sstevel@tonic-gate 	struct rtentry rt;
25857c478bd9Sstevel@tonic-gate 
25867c478bd9Sstevel@tonic-gate 	if (!IPCP_ENABLED || (ipmuxid == -1)) {
25877c478bd9Sstevel@tonic-gate 		error("Can't %s route: IP is not enabled", str);
25887c478bd9Sstevel@tonic-gate 		return (0);
25897c478bd9Sstevel@tonic-gate 	}
25907c478bd9Sstevel@tonic-gate 	if (ipfd == -1 && open_ipfd() == -1)
25917c478bd9Sstevel@tonic-gate 		return (0);
25927c478bd9Sstevel@tonic-gate 
25937c478bd9Sstevel@tonic-gate 	BZERO(&sin_dst, sizeof (sin_dst));
25947c478bd9Sstevel@tonic-gate 	sin_dst.sin_family = AF_INET;
25957c478bd9Sstevel@tonic-gate 	sin_dst.sin_addr.s_addr = l;
25967c478bd9Sstevel@tonic-gate 
25977c478bd9Sstevel@tonic-gate 	BZERO(&sin_gtw, sizeof (sin_gtw));
25987c478bd9Sstevel@tonic-gate 	sin_gtw.sin_family = AF_INET;
25997c478bd9Sstevel@tonic-gate 	sin_gtw.sin_addr.s_addr = g;
26007c478bd9Sstevel@tonic-gate 
26017c478bd9Sstevel@tonic-gate 	BZERO(&rt, sizeof (rt));
26027c478bd9Sstevel@tonic-gate 	rt.rt_dst = *(struct sockaddr *)&sin_dst;
26037c478bd9Sstevel@tonic-gate 	rt.rt_gateway = *(struct sockaddr *)&sin_gtw;
26047c478bd9Sstevel@tonic-gate 	rt.rt_flags = (RTF_GATEWAY|RTF_STATIC);
26057c478bd9Sstevel@tonic-gate 
26067c478bd9Sstevel@tonic-gate 	if (myioctl(ipfd, (add ? SIOCADDRT : SIOCDELRT), &rt) < 0) {
26077c478bd9Sstevel@tonic-gate 		error("Can't %s route: %m", str);
26087c478bd9Sstevel@tonic-gate 		return (0);
26097c478bd9Sstevel@tonic-gate 	}
26107c478bd9Sstevel@tonic-gate 	return (1);
26117c478bd9Sstevel@tonic-gate }
26127c478bd9Sstevel@tonic-gate 
26137c478bd9Sstevel@tonic-gate /*
26147c478bd9Sstevel@tonic-gate  * sifdefaultroute()
26157c478bd9Sstevel@tonic-gate  *
26167c478bd9Sstevel@tonic-gate  * Assign a default route through the address given.
26177c478bd9Sstevel@tonic-gate  */
26187c478bd9Sstevel@tonic-gate /*ARGSUSED*/
26197c478bd9Sstevel@tonic-gate int
26207c478bd9Sstevel@tonic-gate sifdefaultroute(u, l, g)
26217c478bd9Sstevel@tonic-gate 	int u;
26227c478bd9Sstevel@tonic-gate 	u_int32_t l;
26237c478bd9Sstevel@tonic-gate 	u_int32_t g;
26247c478bd9Sstevel@tonic-gate {
26257c478bd9Sstevel@tonic-gate 	if (!sifroute(u, 0, g, 1, "add default")) {
26267c478bd9Sstevel@tonic-gate 		return (0);
26277c478bd9Sstevel@tonic-gate 	}
26287c478bd9Sstevel@tonic-gate 	default_route_gateway = g;
26297c478bd9Sstevel@tonic-gate 	return (1);
26307c478bd9Sstevel@tonic-gate }
26317c478bd9Sstevel@tonic-gate 
26327c478bd9Sstevel@tonic-gate /*
26337c478bd9Sstevel@tonic-gate  * cifdefaultroute()
26347c478bd9Sstevel@tonic-gate  *
26357c478bd9Sstevel@tonic-gate  * Delete a default route through the address given.
26367c478bd9Sstevel@tonic-gate  */
26377c478bd9Sstevel@tonic-gate /*ARGSUSED*/
26387c478bd9Sstevel@tonic-gate int
26397c478bd9Sstevel@tonic-gate cifdefaultroute(u, l, g)
26407c478bd9Sstevel@tonic-gate 	int u;
26417c478bd9Sstevel@tonic-gate 	u_int32_t l;
26427c478bd9Sstevel@tonic-gate 	u_int32_t g;
26437c478bd9Sstevel@tonic-gate {
26447c478bd9Sstevel@tonic-gate 	if (!sifroute(u, 0, g, 0, "delete default")) {
26457c478bd9Sstevel@tonic-gate 		return (0);
26467c478bd9Sstevel@tonic-gate 	}
26477c478bd9Sstevel@tonic-gate 	default_route_gateway = 0;
26487c478bd9Sstevel@tonic-gate 	return (1);
26497c478bd9Sstevel@tonic-gate }
26507c478bd9Sstevel@tonic-gate 
26517c478bd9Sstevel@tonic-gate /*
26527c478bd9Sstevel@tonic-gate  * sifproxyarp()
26537c478bd9Sstevel@tonic-gate  *
26547c478bd9Sstevel@tonic-gate  * Make a proxy ARP entry for the peer.
26557c478bd9Sstevel@tonic-gate  */
26567c478bd9Sstevel@tonic-gate /*ARGSUSED*/
26577c478bd9Sstevel@tonic-gate int
26587c478bd9Sstevel@tonic-gate sifproxyarp(unit, hisaddr, quietflag)
26597c478bd9Sstevel@tonic-gate 	int unit;
26607c478bd9Sstevel@tonic-gate 	u_int32_t hisaddr;
26617c478bd9Sstevel@tonic-gate 	int quietflag;
26627c478bd9Sstevel@tonic-gate {
26637c478bd9Sstevel@tonic-gate 	struct sockaddr_in sin;
26647c478bd9Sstevel@tonic-gate 	struct xarpreq arpreq;
26657c478bd9Sstevel@tonic-gate 	const uchar_t *cp;
26667c478bd9Sstevel@tonic-gate 	char *str = NULL;
26677c478bd9Sstevel@tonic-gate 
26687c478bd9Sstevel@tonic-gate 	if (!IPCP_ENABLED || (ipmuxid == -1)) {
26697c478bd9Sstevel@tonic-gate 		return (0);
26707c478bd9Sstevel@tonic-gate 	}
26717c478bd9Sstevel@tonic-gate 	if (ipfd == -1 && open_ipfd() == -1)
26727c478bd9Sstevel@tonic-gate 		return (0);
26737c478bd9Sstevel@tonic-gate 
26747c478bd9Sstevel@tonic-gate 	BZERO(&sin, sizeof (sin));
26757c478bd9Sstevel@tonic-gate 	sin.sin_family = AF_INET;
26767c478bd9Sstevel@tonic-gate 	sin.sin_addr.s_addr = hisaddr;
26777c478bd9Sstevel@tonic-gate 
26787c478bd9Sstevel@tonic-gate 	BZERO(&arpreq, sizeof (arpreq));
26797c478bd9Sstevel@tonic-gate 	if (!get_ether_addr(hisaddr, &arpreq.xarp_ha, quietflag)) {
26807c478bd9Sstevel@tonic-gate 		return (0);
26817c478bd9Sstevel@tonic-gate 	}
26827c478bd9Sstevel@tonic-gate 	BCOPY(&sin, &arpreq.xarp_pa, sizeof (sin));
26837c478bd9Sstevel@tonic-gate 	arpreq.xarp_flags = ATF_PERM | ATF_PUBL;
26847c478bd9Sstevel@tonic-gate 	arpreq.xarp_ha.sdl_family = AF_LINK;
26857c478bd9Sstevel@tonic-gate 
26867c478bd9Sstevel@tonic-gate 	if (myioctl(ipfd, SIOCSXARP, (caddr_t)&arpreq) < 0) {
26877c478bd9Sstevel@tonic-gate 		if (!quietflag)
26887c478bd9Sstevel@tonic-gate 			error("Couldn't set proxy ARP entry: %m");
26897c478bd9Sstevel@tonic-gate 		return (0);
26907c478bd9Sstevel@tonic-gate 	}
26917c478bd9Sstevel@tonic-gate 	cp = (const uchar_t *)LLADDR(&arpreq.xarp_ha);
26927c478bd9Sstevel@tonic-gate 	str = _link_ntoa(cp, str, arpreq.xarp_ha.sdl_alen, IFT_OTHER);
26937c478bd9Sstevel@tonic-gate 	if (str != NULL) {
26947c478bd9Sstevel@tonic-gate 		dbglog("established proxy ARP for %I using %s", hisaddr,
26957c478bd9Sstevel@tonic-gate 		    str);
26967c478bd9Sstevel@tonic-gate 		free(str);
26977c478bd9Sstevel@tonic-gate 	}
26987c478bd9Sstevel@tonic-gate 	proxy_arp_addr = hisaddr;
26997c478bd9Sstevel@tonic-gate 	return (1);
27007c478bd9Sstevel@tonic-gate }
27017c478bd9Sstevel@tonic-gate 
27027c478bd9Sstevel@tonic-gate /*
27037c478bd9Sstevel@tonic-gate  * cifproxyarp()
27047c478bd9Sstevel@tonic-gate  *
27057c478bd9Sstevel@tonic-gate  * Delete the proxy ARP entry for the peer.
27067c478bd9Sstevel@tonic-gate  */
27077c478bd9Sstevel@tonic-gate /*ARGSUSED*/
27087c478bd9Sstevel@tonic-gate int
27097c478bd9Sstevel@tonic-gate cifproxyarp(unit, hisaddr)
27107c478bd9Sstevel@tonic-gate 	int unit;
27117c478bd9Sstevel@tonic-gate 	u_int32_t hisaddr;
27127c478bd9Sstevel@tonic-gate {
27137c478bd9Sstevel@tonic-gate 	struct sockaddr_in sin;
27147c478bd9Sstevel@tonic-gate 	struct xarpreq arpreq;
27157c478bd9Sstevel@tonic-gate 
27167c478bd9Sstevel@tonic-gate 	if (!IPCP_ENABLED || (ipmuxid == -1)) {
27177c478bd9Sstevel@tonic-gate 		return (0);
27187c478bd9Sstevel@tonic-gate 	}
27197c478bd9Sstevel@tonic-gate 	if (ipfd == -1 && open_ipfd() == -1)
27207c478bd9Sstevel@tonic-gate 		return (0);
27217c478bd9Sstevel@tonic-gate 
27227c478bd9Sstevel@tonic-gate 	BZERO(&sin, sizeof (sin));
27237c478bd9Sstevel@tonic-gate 	sin.sin_family = AF_INET;
27247c478bd9Sstevel@tonic-gate 	sin.sin_addr.s_addr = hisaddr;
27257c478bd9Sstevel@tonic-gate 
27267c478bd9Sstevel@tonic-gate 	BZERO(&arpreq, sizeof (arpreq));
27277c478bd9Sstevel@tonic-gate 	BCOPY(&sin, &arpreq.xarp_pa, sizeof (sin));
27287c478bd9Sstevel@tonic-gate 	arpreq.xarp_ha.sdl_family = AF_LINK;
27297c478bd9Sstevel@tonic-gate 
27307c478bd9Sstevel@tonic-gate 	if (myioctl(ipfd, SIOCDXARP, (caddr_t)&arpreq) < 0) {
27317c478bd9Sstevel@tonic-gate 		error("Couldn't delete proxy ARP entry: %m");
27327c478bd9Sstevel@tonic-gate 		return (0);
27337c478bd9Sstevel@tonic-gate 	}
27347c478bd9Sstevel@tonic-gate 	proxy_arp_addr = 0;
27357c478bd9Sstevel@tonic-gate 	return (1);
27367c478bd9Sstevel@tonic-gate }
27377c478bd9Sstevel@tonic-gate 
27387c478bd9Sstevel@tonic-gate /*
27397c478bd9Sstevel@tonic-gate  * get_ether_addr()
27407c478bd9Sstevel@tonic-gate  *
27417c478bd9Sstevel@tonic-gate  * Get the hardware address of an interface on the the same subnet as
27427c478bd9Sstevel@tonic-gate  * ipaddr.  This routine uses old-style interfaces for intentional
27437c478bd9Sstevel@tonic-gate  * backward compatibility -- SIOCGLIF* isn't in older Solaris
27447c478bd9Sstevel@tonic-gate  * releases.
27457c478bd9Sstevel@tonic-gate  */
27467c478bd9Sstevel@tonic-gate static int
27477c478bd9Sstevel@tonic-gate get_ether_addr(u_int32_t ipaddr, struct sockaddr_dl *hwaddr, int quietflag)
27487c478bd9Sstevel@tonic-gate {
27497c478bd9Sstevel@tonic-gate 	struct ifreq *ifr, *ifend, ifreq;
27507c478bd9Sstevel@tonic-gate 	int nif, s, retv;
27517c478bd9Sstevel@tonic-gate 	struct ifconf ifc;
27527c478bd9Sstevel@tonic-gate 	u_int32_t ina, mask;
27537c478bd9Sstevel@tonic-gate 	struct xarpreq req;
27547c478bd9Sstevel@tonic-gate 	struct sockaddr_in sin;
27557c478bd9Sstevel@tonic-gate 
27567c478bd9Sstevel@tonic-gate 	if (ipfd == -1 && open_ipfd() == -1)
27577c478bd9Sstevel@tonic-gate 		return (0);
27587c478bd9Sstevel@tonic-gate 
27597c478bd9Sstevel@tonic-gate 	/*
27607c478bd9Sstevel@tonic-gate 	 * Scan through the system's network interfaces.
27617c478bd9Sstevel@tonic-gate 	 */
27627c478bd9Sstevel@tonic-gate 	if (myioctl(ipfd, SIOCGIFNUM, &nif) < 0) {
27637c478bd9Sstevel@tonic-gate 		nif = MAXIFS;
27647c478bd9Sstevel@tonic-gate 	}
27657c478bd9Sstevel@tonic-gate 	if (nif <= 0)
27667c478bd9Sstevel@tonic-gate 		return (0);
27677c478bd9Sstevel@tonic-gate 	ifc.ifc_len = nif * sizeof (struct ifreq);
27687c478bd9Sstevel@tonic-gate 	ifc.ifc_buf = (caddr_t)malloc(ifc.ifc_len);
27697c478bd9Sstevel@tonic-gate 	if (ifc.ifc_buf == NULL) {
27707c478bd9Sstevel@tonic-gate 		return (0);
27717c478bd9Sstevel@tonic-gate 	}
27727c478bd9Sstevel@tonic-gate 	if (myioctl(ipfd, SIOCGIFCONF, &ifc) < 0) {
27737c478bd9Sstevel@tonic-gate 		error("Couldn't get system interface list: %m");
27747c478bd9Sstevel@tonic-gate 		free(ifc.ifc_buf);
27757c478bd9Sstevel@tonic-gate 		return (0);
27767c478bd9Sstevel@tonic-gate 	}
27777c478bd9Sstevel@tonic-gate 	/* LINTED */
27787c478bd9Sstevel@tonic-gate 	ifend = (struct ifreq *)(ifc.ifc_buf + ifc.ifc_len);
27797c478bd9Sstevel@tonic-gate 	for (ifr = ifc.ifc_req; ifr < ifend; ++ifr) {
27807c478bd9Sstevel@tonic-gate 		if (ifr->ifr_addr.sa_family != AF_INET) {
27817c478bd9Sstevel@tonic-gate 			continue;
27827c478bd9Sstevel@tonic-gate 		}
27837c478bd9Sstevel@tonic-gate 		/*
27847c478bd9Sstevel@tonic-gate 		 * Check that the interface is up, and not
27857c478bd9Sstevel@tonic-gate 		 * point-to-point or loopback.
27867c478bd9Sstevel@tonic-gate 		 */
27877c478bd9Sstevel@tonic-gate 		(void) strlcpy(ifreq.ifr_name, ifr->ifr_name,
2788fb60e41dSss 		    sizeof (ifreq.ifr_name));
27897c478bd9Sstevel@tonic-gate 		if (myioctl(ipfd, SIOCGIFFLAGS, &ifreq) < 0) {
27907c478bd9Sstevel@tonic-gate 			continue;
27917c478bd9Sstevel@tonic-gate 		}
27927c478bd9Sstevel@tonic-gate 		if ((ifreq.ifr_flags & (IFF_UP|IFF_BROADCAST|IFF_POINTOPOINT|
27937c478bd9Sstevel@tonic-gate 		    IFF_LOOPBACK|IFF_NOARP)) != (IFF_UP|IFF_BROADCAST)) {
27947c478bd9Sstevel@tonic-gate 			continue;
27957c478bd9Sstevel@tonic-gate 		}
27967c478bd9Sstevel@tonic-gate 		/*
27977c478bd9Sstevel@tonic-gate 		 * Get its netmask and check that it's on the right subnet.
27987c478bd9Sstevel@tonic-gate 		 */
27997c478bd9Sstevel@tonic-gate 		if (myioctl(ipfd, SIOCGIFNETMASK, &ifreq) < 0) {
28007c478bd9Sstevel@tonic-gate 			continue;
28017c478bd9Sstevel@tonic-gate 		}
28027c478bd9Sstevel@tonic-gate 		(void) memcpy(&sin, &ifr->ifr_addr, sizeof (sin));
28037c478bd9Sstevel@tonic-gate 		ina = sin.sin_addr.s_addr;
28047c478bd9Sstevel@tonic-gate 		(void) memcpy(&sin, &ifreq.ifr_addr, sizeof (sin));
28057c478bd9Sstevel@tonic-gate 		mask = sin.sin_addr.s_addr;
28067c478bd9Sstevel@tonic-gate 		if ((ipaddr & mask) == (ina & mask)) {
28077c478bd9Sstevel@tonic-gate 			break;
28087c478bd9Sstevel@tonic-gate 		}
28097c478bd9Sstevel@tonic-gate 	}
28107c478bd9Sstevel@tonic-gate 	if (ifr >= ifend) {
28117c478bd9Sstevel@tonic-gate 		if (!quietflag)
28127c478bd9Sstevel@tonic-gate 			warn("No suitable interface found for proxy ARP of %I",
28137c478bd9Sstevel@tonic-gate 			    ipaddr);
28147c478bd9Sstevel@tonic-gate 		free(ifc.ifc_buf);
28157c478bd9Sstevel@tonic-gate 		return (0);
28167c478bd9Sstevel@tonic-gate 	}
28177c478bd9Sstevel@tonic-gate 	info("found interface %s for proxy ARP of %I", ifr->ifr_name, ipaddr);
28187c478bd9Sstevel@tonic-gate 
28197c478bd9Sstevel@tonic-gate 	/*
28207c478bd9Sstevel@tonic-gate 	 * New way - get the address by doing an arp request.
28217c478bd9Sstevel@tonic-gate 	 */
28227c478bd9Sstevel@tonic-gate 	s = socket(AF_INET, SOCK_DGRAM, 0);
28237c478bd9Sstevel@tonic-gate 	if (s < 0) {
28247c478bd9Sstevel@tonic-gate 		error("get_ether_addr: error opening IP socket: %m");
28257c478bd9Sstevel@tonic-gate 		free(ifc.ifc_buf);
28267c478bd9Sstevel@tonic-gate 		return (0);
28277c478bd9Sstevel@tonic-gate 	}
28287c478bd9Sstevel@tonic-gate 	BZERO(&sin, sizeof (sin));
28297c478bd9Sstevel@tonic-gate 	sin.sin_family = AF_INET;
28307c478bd9Sstevel@tonic-gate 	sin.sin_addr.s_addr = ina;
28317c478bd9Sstevel@tonic-gate 
28327c478bd9Sstevel@tonic-gate 	BZERO(&req, sizeof (req));
28337c478bd9Sstevel@tonic-gate 	BCOPY(&sin, &req.xarp_pa, sizeof (sin));
28347c478bd9Sstevel@tonic-gate 	req.xarp_ha.sdl_family = AF_LINK;
28357c478bd9Sstevel@tonic-gate 
28367c478bd9Sstevel@tonic-gate 	if (myioctl(s, SIOCGXARP, &req) < 0) {
28377c478bd9Sstevel@tonic-gate 		error("Couldn't get ARP entry for %I: %m", ina);
28387c478bd9Sstevel@tonic-gate 		retv = 0;
28397c478bd9Sstevel@tonic-gate 	} else {
28407c478bd9Sstevel@tonic-gate 		(void) memcpy(hwaddr, &req.xarp_ha,
28417c478bd9Sstevel@tonic-gate 		    sizeof (struct sockaddr_dl));
28427c478bd9Sstevel@tonic-gate 		retv = 1;
28437c478bd9Sstevel@tonic-gate 	}
28447c478bd9Sstevel@tonic-gate 	(void) close(s);
28457c478bd9Sstevel@tonic-gate 	free(ifc.ifc_buf);
28467c478bd9Sstevel@tonic-gate 	return (retv);
28477c478bd9Sstevel@tonic-gate }
28487c478bd9Sstevel@tonic-gate 
28497c478bd9Sstevel@tonic-gate /*
28507c478bd9Sstevel@tonic-gate  * GetMask()
28517c478bd9Sstevel@tonic-gate  *
28527c478bd9Sstevel@tonic-gate  * Return mask (bogus, but needed for compatibility with other platforms).
28537c478bd9Sstevel@tonic-gate  */
28547c478bd9Sstevel@tonic-gate /*ARGSUSED*/
28557c478bd9Sstevel@tonic-gate u_int32_t
28567c478bd9Sstevel@tonic-gate GetMask(addr)
28577c478bd9Sstevel@tonic-gate 	u_int32_t addr;
28587c478bd9Sstevel@tonic-gate {
28597c478bd9Sstevel@tonic-gate 	return (0xffffffffUL);
28607c478bd9Sstevel@tonic-gate }
28617c478bd9Sstevel@tonic-gate 
28627c478bd9Sstevel@tonic-gate /*
28637c478bd9Sstevel@tonic-gate  * logwtmp()
28647c478bd9Sstevel@tonic-gate  *
28657c478bd9Sstevel@tonic-gate  * Write an accounting record to the /var/adm/wtmp file.
28667c478bd9Sstevel@tonic-gate  */
28677c478bd9Sstevel@tonic-gate /*ARGSUSED*/
28687c478bd9Sstevel@tonic-gate void
28697c478bd9Sstevel@tonic-gate logwtmp(line, name, host)
28707c478bd9Sstevel@tonic-gate 	const char *line;
28717c478bd9Sstevel@tonic-gate 	const char *name;
28727c478bd9Sstevel@tonic-gate 	const char *host;
28737c478bd9Sstevel@tonic-gate {
28747c478bd9Sstevel@tonic-gate 	static struct utmpx utmpx;
28757c478bd9Sstevel@tonic-gate 
28767c478bd9Sstevel@tonic-gate 	if (name[0] != '\0') {
28777c478bd9Sstevel@tonic-gate 		/*
28787c478bd9Sstevel@tonic-gate 		 * logging in
28797c478bd9Sstevel@tonic-gate 		 */
28807c478bd9Sstevel@tonic-gate 		(void) strncpy(utmpx.ut_user, name, sizeof (utmpx.ut_user));
28817c478bd9Sstevel@tonic-gate 		(void) strncpy(utmpx.ut_id, ifname, sizeof (utmpx.ut_id));
28827c478bd9Sstevel@tonic-gate 		(void) strncpy(utmpx.ut_line, line, sizeof (utmpx.ut_line));
28837c478bd9Sstevel@tonic-gate 
28847c478bd9Sstevel@tonic-gate 		utmpx.ut_pid = getpid();
28857c478bd9Sstevel@tonic-gate 		utmpx.ut_type = USER_PROCESS;
28867c478bd9Sstevel@tonic-gate 	} else {
28877c478bd9Sstevel@tonic-gate 		utmpx.ut_type = DEAD_PROCESS;
28887c478bd9Sstevel@tonic-gate 	}
28897c478bd9Sstevel@tonic-gate 	(void) gettimeofday(&utmpx.ut_tv, NULL);
28907c478bd9Sstevel@tonic-gate 	updwtmpx("/var/adm/wtmpx", &utmpx);
28917c478bd9Sstevel@tonic-gate }
28927c478bd9Sstevel@tonic-gate 
28937c478bd9Sstevel@tonic-gate /*
28947c478bd9Sstevel@tonic-gate  * get_host_seed()
28957c478bd9Sstevel@tonic-gate  *
28967c478bd9Sstevel@tonic-gate  * Return the serial number of this machine.
28977c478bd9Sstevel@tonic-gate  */
28987c478bd9Sstevel@tonic-gate int
28997c478bd9Sstevel@tonic-gate get_host_seed()
29007c478bd9Sstevel@tonic-gate {
29017c478bd9Sstevel@tonic-gate 	char buf[32];
29027c478bd9Sstevel@tonic-gate 
29037c478bd9Sstevel@tonic-gate 	if (sysinfo(SI_HW_SERIAL, buf, sizeof (buf)) < 0) {
29047c478bd9Sstevel@tonic-gate 		error("sysinfo: %m");
29057c478bd9Sstevel@tonic-gate 		return (0);
29067c478bd9Sstevel@tonic-gate 	}
29077c478bd9Sstevel@tonic-gate 	return ((int)strtoul(buf, NULL, 16));
29087c478bd9Sstevel@tonic-gate }
29097c478bd9Sstevel@tonic-gate 
29107c478bd9Sstevel@tonic-gate /*
29117c478bd9Sstevel@tonic-gate  * strioctl()
29127c478bd9Sstevel@tonic-gate  *
29137c478bd9Sstevel@tonic-gate  * Wrapper for STREAMS I_STR ioctl.  Masks out EINTR from caller.
29147c478bd9Sstevel@tonic-gate  */
29157c478bd9Sstevel@tonic-gate static int
29167c478bd9Sstevel@tonic-gate strioctl(int fd, int cmd, void *ptr, int ilen, int olen)
29177c478bd9Sstevel@tonic-gate {
29187c478bd9Sstevel@tonic-gate 	struct strioctl	str;
29197c478bd9Sstevel@tonic-gate 
29207c478bd9Sstevel@tonic-gate 	str.ic_cmd = cmd;
29217c478bd9Sstevel@tonic-gate 	str.ic_timout = PPPSTRTIMOUT;
29227c478bd9Sstevel@tonic-gate 	str.ic_len = ilen;
29237c478bd9Sstevel@tonic-gate 	str.ic_dp = ptr;
29247c478bd9Sstevel@tonic-gate 
29257c478bd9Sstevel@tonic-gate 	if (myioctl(fd, I_STR, &str) == -1) {
29267c478bd9Sstevel@tonic-gate 		return (-1);
29277c478bd9Sstevel@tonic-gate 	}
29287c478bd9Sstevel@tonic-gate 	if (str.ic_len != olen) {
29297c478bd9Sstevel@tonic-gate 		dbglog("strioctl: expected %d bytes, got %d for cmd %x\n",
29307c478bd9Sstevel@tonic-gate 		    olen, str.ic_len, cmd);
29317c478bd9Sstevel@tonic-gate 	}
29327c478bd9Sstevel@tonic-gate 	return (0);
29337c478bd9Sstevel@tonic-gate }
29347c478bd9Sstevel@tonic-gate 
29357c478bd9Sstevel@tonic-gate /*
29367c478bd9Sstevel@tonic-gate  * have_route_to()
29377c478bd9Sstevel@tonic-gate  *
29387c478bd9Sstevel@tonic-gate  * Determine if the system has a route to the specified IP address.
29397c478bd9Sstevel@tonic-gate  * Returns 0 if not, 1 if so, -1 if we can't tell. `addr' is in network
29407c478bd9Sstevel@tonic-gate  * byte order. For demand mode to work properly, we have to ignore routes
29417c478bd9Sstevel@tonic-gate  * through our own interface. XXX Would be nice to use routing socket.
29427c478bd9Sstevel@tonic-gate  */
29437c478bd9Sstevel@tonic-gate int
29447c478bd9Sstevel@tonic-gate have_route_to(addr)
29457c478bd9Sstevel@tonic-gate 	u_int32_t addr;
29467c478bd9Sstevel@tonic-gate {
29477c478bd9Sstevel@tonic-gate 	int r, flags, i;
29487c478bd9Sstevel@tonic-gate 	struct {
29497c478bd9Sstevel@tonic-gate 		struct T_optmgmt_req req;
29507c478bd9Sstevel@tonic-gate 		struct opthdr hdr;
29517c478bd9Sstevel@tonic-gate 	} req;
29527c478bd9Sstevel@tonic-gate 	union {
29537c478bd9Sstevel@tonic-gate 		struct T_optmgmt_ack ack;
29547c478bd9Sstevel@tonic-gate 		unsigned char space[64];
29557c478bd9Sstevel@tonic-gate 	} ack;
29567c478bd9Sstevel@tonic-gate 	struct opthdr *rh;
29577c478bd9Sstevel@tonic-gate 	struct strbuf cbuf, dbuf;
29587c478bd9Sstevel@tonic-gate 	int nroutes;
29597c478bd9Sstevel@tonic-gate 	mib2_ipRouteEntry_t routes[8];
29607c478bd9Sstevel@tonic-gate 	mib2_ipRouteEntry_t *rp;
29617c478bd9Sstevel@tonic-gate 
29627c478bd9Sstevel@tonic-gate 	if (ipfd == -1 && open_ipfd() == -1)
29637c478bd9Sstevel@tonic-gate 		return (0);
29647c478bd9Sstevel@tonic-gate 
29657c478bd9Sstevel@tonic-gate 	req.req.PRIM_type = T_OPTMGMT_REQ;
29667c478bd9Sstevel@tonic-gate 	req.req.OPT_offset = (caddr_t)&req.hdr - (caddr_t)&req;
29677c478bd9Sstevel@tonic-gate 	req.req.OPT_length = sizeof (req.hdr);
29687c478bd9Sstevel@tonic-gate #ifdef T_CURRENT
29697c478bd9Sstevel@tonic-gate 	req.req.MGMT_flags = T_CURRENT;
29707c478bd9Sstevel@tonic-gate #else
29717c478bd9Sstevel@tonic-gate 	/* Old-style */
29727c478bd9Sstevel@tonic-gate 	req.req.MGMT_flags = T_CHECK;
29737c478bd9Sstevel@tonic-gate #endif
29747c478bd9Sstevel@tonic-gate 
29757c478bd9Sstevel@tonic-gate 	req.hdr.level = MIB2_IP;
29767c478bd9Sstevel@tonic-gate 	req.hdr.name = 0;
29777c478bd9Sstevel@tonic-gate 	req.hdr.len = 0;
29787c478bd9Sstevel@tonic-gate 
29797c478bd9Sstevel@tonic-gate 	cbuf.buf = (caddr_t)&req;
29807c478bd9Sstevel@tonic-gate 	cbuf.len = sizeof (req);
29817c478bd9Sstevel@tonic-gate 
29827c478bd9Sstevel@tonic-gate 	if (putmsg(ipfd, &cbuf, NULL, 0) == -1) {
29837c478bd9Sstevel@tonic-gate 		warn("have_route_to: putmsg: %m");
29847c478bd9Sstevel@tonic-gate 		return (-1);
29857c478bd9Sstevel@tonic-gate 	}
29867c478bd9Sstevel@tonic-gate 
29877c478bd9Sstevel@tonic-gate 	for (;;) {
29887c478bd9Sstevel@tonic-gate 		cbuf.buf = (caddr_t)&ack;
29897c478bd9Sstevel@tonic-gate 		cbuf.maxlen = sizeof (ack);
29907c478bd9Sstevel@tonic-gate 		dbuf.buf = (caddr_t)routes;
29917c478bd9Sstevel@tonic-gate 		dbuf.maxlen = sizeof (routes);
29927c478bd9Sstevel@tonic-gate 		flags = 0;
29937c478bd9Sstevel@tonic-gate 		r = getmsg(ipfd, &cbuf, &dbuf, &flags);
29947c478bd9Sstevel@tonic-gate 		if (r == -1) {
29957c478bd9Sstevel@tonic-gate 			warn("have_route_to: getmsg: %m");
29967c478bd9Sstevel@tonic-gate 			return (-1);
29977c478bd9Sstevel@tonic-gate 		}
29987c478bd9Sstevel@tonic-gate 
29997c478bd9Sstevel@tonic-gate 		if (cbuf.len < sizeof (struct T_optmgmt_ack) ||
30007c478bd9Sstevel@tonic-gate 		    ack.ack.PRIM_type != T_OPTMGMT_ACK ||
30017c478bd9Sstevel@tonic-gate 		    ack.ack.MGMT_flags != T_SUCCESS ||
30027c478bd9Sstevel@tonic-gate 		    ack.ack.OPT_length < sizeof (struct opthdr)) {
30037c478bd9Sstevel@tonic-gate 			dbglog("have_route_to: bad message len=%d prim=%d",
30047c478bd9Sstevel@tonic-gate 			    cbuf.len, ack.ack.PRIM_type);
30057c478bd9Sstevel@tonic-gate 			return (-1);
30067c478bd9Sstevel@tonic-gate 		}
30077c478bd9Sstevel@tonic-gate 		/* LINTED */
30087c478bd9Sstevel@tonic-gate 		rh = (struct opthdr *)((caddr_t)&ack + ack.ack.OPT_offset);
30097c478bd9Sstevel@tonic-gate 		if (rh->level == 0 && rh->name == 0) {
30107c478bd9Sstevel@tonic-gate 			break;
30117c478bd9Sstevel@tonic-gate 		}
30127c478bd9Sstevel@tonic-gate 		if (rh->level != MIB2_IP || rh->name != MIB2_IP_21) {
30137c478bd9Sstevel@tonic-gate 			while (r == MOREDATA) {
30147c478bd9Sstevel@tonic-gate 				r = getmsg(ipfd, NULL, &dbuf, &flags);
30157c478bd9Sstevel@tonic-gate 			}
30167c478bd9Sstevel@tonic-gate 			continue;
30177c478bd9Sstevel@tonic-gate 		}
30187c478bd9Sstevel@tonic-gate 
30197c478bd9Sstevel@tonic-gate 		/*
30207c478bd9Sstevel@tonic-gate 		 * Note that we have to skip routes to our own
30217c478bd9Sstevel@tonic-gate 		 * interface in order for demand dial to work.
30227c478bd9Sstevel@tonic-gate 		 *
30237c478bd9Sstevel@tonic-gate 		 * XXX awful hack here.  We don't know our own
30247c478bd9Sstevel@tonic-gate 		 * ifIndex, so we can't check ipRouteIfIndex here.
30257c478bd9Sstevel@tonic-gate 		 * Instead, we check the next hop address.
30267c478bd9Sstevel@tonic-gate 		 */
30277c478bd9Sstevel@tonic-gate 		for (;;) {
30287c478bd9Sstevel@tonic-gate 			nroutes = dbuf.len / sizeof (mib2_ipRouteEntry_t);
30297c478bd9Sstevel@tonic-gate 			for (rp = routes, i = 0; i < nroutes; ++i, ++rp) {
30307c478bd9Sstevel@tonic-gate 				if (rp->ipRouteNextHop != remote_addr &&
30317c478bd9Sstevel@tonic-gate 				    ((addr ^ rp->ipRouteDest) &
30327c478bd9Sstevel@tonic-gate 					rp->ipRouteMask) == 0) {
30337c478bd9Sstevel@tonic-gate 					dbglog("have route to %I/%I via %I",
30347c478bd9Sstevel@tonic-gate 					    rp->ipRouteDest,
30357c478bd9Sstevel@tonic-gate 					    rp->ipRouteMask,
30367c478bd9Sstevel@tonic-gate 					    rp->ipRouteNextHop);
30377c478bd9Sstevel@tonic-gate 					return (1);
30387c478bd9Sstevel@tonic-gate 				}
30397c478bd9Sstevel@tonic-gate 			}
30407c478bd9Sstevel@tonic-gate 			if (r == 0) {
30417c478bd9Sstevel@tonic-gate 				break;
30427c478bd9Sstevel@tonic-gate 			}
30437c478bd9Sstevel@tonic-gate 			r = getmsg(ipfd, NULL, &dbuf, &flags);
30447c478bd9Sstevel@tonic-gate 		}
30457c478bd9Sstevel@tonic-gate 	}
30467c478bd9Sstevel@tonic-gate 	return (0);
30477c478bd9Sstevel@tonic-gate }
30487c478bd9Sstevel@tonic-gate 
30497c478bd9Sstevel@tonic-gate /*
30507c478bd9Sstevel@tonic-gate  * get_pty()
30517c478bd9Sstevel@tonic-gate  *
30527c478bd9Sstevel@tonic-gate  * Get a pty master/slave pair and chown the slave side to the uid given.
30537c478bd9Sstevel@tonic-gate  * Assumes slave_name points to MAXPATHLEN bytes of space.
30547c478bd9Sstevel@tonic-gate  */
30557c478bd9Sstevel@tonic-gate int
30567c478bd9Sstevel@tonic-gate get_pty(master_fdp, slave_fdp, slave_name, uid)
30577c478bd9Sstevel@tonic-gate 	int *master_fdp;
30587c478bd9Sstevel@tonic-gate 	int *slave_fdp;
30597c478bd9Sstevel@tonic-gate 	char *slave_name;
30607c478bd9Sstevel@tonic-gate 	int uid;
30617c478bd9Sstevel@tonic-gate {
30627c478bd9Sstevel@tonic-gate 	int mfd;
30637c478bd9Sstevel@tonic-gate 	int sfd;
30647c478bd9Sstevel@tonic-gate 	char *pty_name;
30657c478bd9Sstevel@tonic-gate 
30667c478bd9Sstevel@tonic-gate 	mfd = open("/dev/ptmx", O_NOCTTY | O_RDWR);
30677c478bd9Sstevel@tonic-gate 	if (mfd < 0) {
30687c478bd9Sstevel@tonic-gate 		error("Couldn't open pty master: %m");
30697c478bd9Sstevel@tonic-gate 		return (0);
30707c478bd9Sstevel@tonic-gate 	}
30717c478bd9Sstevel@tonic-gate 	pty_name = ptsname(mfd);
30727c478bd9Sstevel@tonic-gate 	if (pty_name == NULL) {
30737c478bd9Sstevel@tonic-gate 		dbglog("Didn't get pty slave name on first try; sleeping.");
30747c478bd9Sstevel@tonic-gate 		/* In case "grow" operation is in progress; try again. */
30757c478bd9Sstevel@tonic-gate 		(void) sleep(1);
30767c478bd9Sstevel@tonic-gate 		pty_name = ptsname(mfd);
30777c478bd9Sstevel@tonic-gate 	}
30787c478bd9Sstevel@tonic-gate 	if (pty_name == NULL) {
30797c478bd9Sstevel@tonic-gate 		error("Couldn't get name of pty slave");
30807c478bd9Sstevel@tonic-gate 		(void) close(mfd);
30817c478bd9Sstevel@tonic-gate 		return (0);
30827c478bd9Sstevel@tonic-gate 	}
30837c478bd9Sstevel@tonic-gate 	if (chown(pty_name, uid, -1) < 0) {
30847c478bd9Sstevel@tonic-gate 		warn("Couldn't change owner of pty slave: %m");
30857c478bd9Sstevel@tonic-gate 	}
30867c478bd9Sstevel@tonic-gate 	if (chmod(pty_name, S_IRUSR | S_IWUSR) < 0) {
30877c478bd9Sstevel@tonic-gate 		warn("Couldn't change permissions on pty slave: %m");
30887c478bd9Sstevel@tonic-gate 	}
30897c478bd9Sstevel@tonic-gate 	if (unlockpt(mfd) < 0) {
30907c478bd9Sstevel@tonic-gate 		warn("Couldn't unlock pty slave: %m");
30917c478bd9Sstevel@tonic-gate 	}
30927c478bd9Sstevel@tonic-gate 	sfd = open(pty_name, O_RDWR);
30937c478bd9Sstevel@tonic-gate 	if (sfd < 0) {
30947c478bd9Sstevel@tonic-gate 		error("Couldn't open pty slave %s: %m", pty_name);
30957c478bd9Sstevel@tonic-gate 		(void) close(mfd);
30967c478bd9Sstevel@tonic-gate 		return (0);
30977c478bd9Sstevel@tonic-gate 	}
30987c478bd9Sstevel@tonic-gate 	if (myioctl(sfd, I_PUSH, "ptem") < 0) {
30997c478bd9Sstevel@tonic-gate 		warn("Couldn't push ptem module on pty slave: %m");
31007c478bd9Sstevel@tonic-gate 	}
31017c478bd9Sstevel@tonic-gate 	dbglog("Using %s; master fd %d, slave fd %d", pty_name, mfd, sfd);
31027c478bd9Sstevel@tonic-gate 
31037c478bd9Sstevel@tonic-gate 	(void) strlcpy(slave_name, pty_name, MAXPATHLEN);
31047c478bd9Sstevel@tonic-gate 
31057c478bd9Sstevel@tonic-gate 	*master_fdp = mfd;
31067c478bd9Sstevel@tonic-gate 	*slave_fdp = sfd;
31077c478bd9Sstevel@tonic-gate 
31087c478bd9Sstevel@tonic-gate 	return (1);
31097c478bd9Sstevel@tonic-gate }
31107c478bd9Sstevel@tonic-gate 
31117c478bd9Sstevel@tonic-gate #ifdef INET6
31127c478bd9Sstevel@tonic-gate static int
31137c478bd9Sstevel@tonic-gate open_udp6fd(void)
31147c478bd9Sstevel@tonic-gate {
31157c478bd9Sstevel@tonic-gate 	int udp6fd;
31167c478bd9Sstevel@tonic-gate 
31177c478bd9Sstevel@tonic-gate 	udp6fd = open(UDP6_DEV_NAME, O_RDWR | O_NONBLOCK, 0);
31187c478bd9Sstevel@tonic-gate 	if (udp6fd < 0) {
31197c478bd9Sstevel@tonic-gate 		error("Couldn't open UDPv6 device (%s): %m", UDP6_DEV_NAME);
31207c478bd9Sstevel@tonic-gate 	}
31217c478bd9Sstevel@tonic-gate 	return (udp6fd);
31227c478bd9Sstevel@tonic-gate }
31237c478bd9Sstevel@tonic-gate 
31247c478bd9Sstevel@tonic-gate /*
31257c478bd9Sstevel@tonic-gate  * plumb_ip6if()
31267c478bd9Sstevel@tonic-gate  *
31277c478bd9Sstevel@tonic-gate  * Perform IPv6 interface plumbing.
31287c478bd9Sstevel@tonic-gate  */
31297c478bd9Sstevel@tonic-gate /*ARGSUSED*/
31307c478bd9Sstevel@tonic-gate static int
31317c478bd9Sstevel@tonic-gate plumb_ip6if(int unit)
31327c478bd9Sstevel@tonic-gate {
31337c478bd9Sstevel@tonic-gate 	int udp6fd = -1, tmpfd;
31347c478bd9Sstevel@tonic-gate 	uint32_t x;
31357c478bd9Sstevel@tonic-gate 	struct lifreq lifr;
31367c478bd9Sstevel@tonic-gate 
31377c478bd9Sstevel@tonic-gate 	if (!IPV6CP_ENABLED || (ifunit == -1) || (pppfd == -1)) {
31387c478bd9Sstevel@tonic-gate 		return (0);
31397c478bd9Sstevel@tonic-gate 	}
31407c478bd9Sstevel@tonic-gate 	if (plumbed)
31417c478bd9Sstevel@tonic-gate 		return (1);
31427c478bd9Sstevel@tonic-gate 	if (ip6fd == -1 && open_ip6fd() == -1)
31437c478bd9Sstevel@tonic-gate 		return (0);
31447c478bd9Sstevel@tonic-gate 	if (use_plink && (udp6fd = open_udp6fd()) == -1)
31457c478bd9Sstevel@tonic-gate 		return (0);
31467c478bd9Sstevel@tonic-gate 	tmpfd = open(drvnam, O_RDWR | O_NONBLOCK, 0);
31477c478bd9Sstevel@tonic-gate 	if (tmpfd < 0) {
31487c478bd9Sstevel@tonic-gate 		error("Couldn't open PPP device (%s): %m", drvnam);
31497c478bd9Sstevel@tonic-gate 		if (udp6fd != -1)
31507c478bd9Sstevel@tonic-gate 			(void) close(udp6fd);
31517c478bd9Sstevel@tonic-gate 		return (0);
31527c478bd9Sstevel@tonic-gate 	}
31537c478bd9Sstevel@tonic-gate 	if (kdebugflag & 1) {
31547c478bd9Sstevel@tonic-gate 		x = PPPDBG_LOG + PPPDBG_DRIVER;
31557c478bd9Sstevel@tonic-gate 		if (strioctl(tmpfd, PPPIO_DEBUG, &x, sizeof (x), 0) < 0) {
31567c478bd9Sstevel@tonic-gate 			warn("PPPIO_DEBUG ioctl for mux failed: %m");
31577c478bd9Sstevel@tonic-gate 		}
31587c478bd9Sstevel@tonic-gate 	}
31597c478bd9Sstevel@tonic-gate 	if (myioctl(tmpfd, I_PUSH, IP_MOD_NAME) < 0) {
31607c478bd9Sstevel@tonic-gate 		error("Couldn't push IP module(%s): %m", IP_MOD_NAME);
31617c478bd9Sstevel@tonic-gate 		goto err_ret;
31627c478bd9Sstevel@tonic-gate 	}
31637c478bd9Sstevel@tonic-gate 	/*
31647c478bd9Sstevel@tonic-gate 	 * Sets interface ppa and flags (refer to comments in plumb_ipif for
31657c478bd9Sstevel@tonic-gate 	 * the IF_UNITSEL ioctl). In addition, the IFF_IPV6 bit must be set in
31667c478bd9Sstevel@tonic-gate 	 * order to declare this as an IPv6 interface.
31677c478bd9Sstevel@tonic-gate 	 */
31687c478bd9Sstevel@tonic-gate 	BZERO(&lifr, sizeof (lifr));
31697c478bd9Sstevel@tonic-gate 	if (myioctl(tmpfd, SIOCGLIFFLAGS, &lifr) < 0) {
31707c478bd9Sstevel@tonic-gate 		error("Couldn't get IPv6 interface flags: %m");
31717c478bd9Sstevel@tonic-gate 		goto err_ret;
31727c478bd9Sstevel@tonic-gate 	}
31737c478bd9Sstevel@tonic-gate 	lifr.lifr_flags |= IFF_IPV6;
31747c478bd9Sstevel@tonic-gate 	lifr.lifr_flags &= ~(IFF_BROADCAST | IFF_IPV4);
31757c478bd9Sstevel@tonic-gate 	lifr.lifr_ppa = ifunit;
31767c478bd9Sstevel@tonic-gate 	(void) strlcpy(lifr.lifr_name, ifname, sizeof (lifr.lifr_name));
31777c478bd9Sstevel@tonic-gate 	if (myioctl(tmpfd, SIOCSLIFNAME, &lifr) < 0) {
31787c478bd9Sstevel@tonic-gate 		error("Can't set ifname for unit %d: %m", ifunit);
31797c478bd9Sstevel@tonic-gate 		goto err_ret;
31807c478bd9Sstevel@tonic-gate 	}
31817c478bd9Sstevel@tonic-gate 	if (use_plink) {
31827c478bd9Sstevel@tonic-gate 		ip6muxid = myioctl(udp6fd, I_PLINK, (void *)tmpfd);
31837c478bd9Sstevel@tonic-gate 		if (ip6muxid < 0) {
31847c478bd9Sstevel@tonic-gate 			error("Can't I_PLINK PPP device to IPv6: %m");
31857c478bd9Sstevel@tonic-gate 			goto err_ret;
31867c478bd9Sstevel@tonic-gate 		}
31877c478bd9Sstevel@tonic-gate 	} else {
31887c478bd9Sstevel@tonic-gate 		ip6muxid = myioctl(ip6fd, I_LINK, (void *)tmpfd);
31897c478bd9Sstevel@tonic-gate 		if (ip6muxid < 0) {
31907c478bd9Sstevel@tonic-gate 			error("Can't I_LINK PPP device to IPv6: %m");
31917c478bd9Sstevel@tonic-gate 			goto err_ret;
31927c478bd9Sstevel@tonic-gate 		}
31937c478bd9Sstevel@tonic-gate 	}
31947c478bd9Sstevel@tonic-gate 	lifr.lifr_ip_muxid = ip6muxid;
31957c478bd9Sstevel@tonic-gate 	lifr.lifr_arp_muxid = -1;
31967c478bd9Sstevel@tonic-gate 	if (myioctl(ip6fd, SIOCSLIFMUXID, (caddr_t)&lifr) < 0) {
31977c478bd9Sstevel@tonic-gate 		error("Can't set mux ID:  SIOCSLIFMUXID: %m");
31987c478bd9Sstevel@tonic-gate 		goto err_ret;
31997c478bd9Sstevel@tonic-gate 	}
32007c478bd9Sstevel@tonic-gate 	(void) close(tmpfd);
32017c478bd9Sstevel@tonic-gate 	if (udp6fd != -1)
32027c478bd9Sstevel@tonic-gate 		(void) close(udp6fd);
32037c478bd9Sstevel@tonic-gate 	return (1);
32047c478bd9Sstevel@tonic-gate 
32057c478bd9Sstevel@tonic-gate err_ret:
32067c478bd9Sstevel@tonic-gate 	(void) close(tmpfd);
32077c478bd9Sstevel@tonic-gate 	if (udp6fd != -1)
32087c478bd9Sstevel@tonic-gate 		(void) close(udp6fd);
32097c478bd9Sstevel@tonic-gate 	return (0);
32107c478bd9Sstevel@tonic-gate }
32117c478bd9Sstevel@tonic-gate 
32127c478bd9Sstevel@tonic-gate /*
32137c478bd9Sstevel@tonic-gate  * unplumb_ip6if()
32147c478bd9Sstevel@tonic-gate  *
32157c478bd9Sstevel@tonic-gate  * Perform IPv6 interface unplumbing.  Possibly called from die(), so there
32167c478bd9Sstevel@tonic-gate  * shouldn't be any call to die() here.
32177c478bd9Sstevel@tonic-gate  */
32187c478bd9Sstevel@tonic-gate static int
32197c478bd9Sstevel@tonic-gate unplumb_ip6if(int unit)
32207c478bd9Sstevel@tonic-gate {
32217c478bd9Sstevel@tonic-gate 	int udp6fd = -1, fd = -1;
32227c478bd9Sstevel@tonic-gate 	int id;
32237c478bd9Sstevel@tonic-gate 	struct lifreq lifr;
32247c478bd9Sstevel@tonic-gate 
32257c478bd9Sstevel@tonic-gate 	if (!IPV6CP_ENABLED || ifunit == -1) {
32267c478bd9Sstevel@tonic-gate 		return (0);
32277c478bd9Sstevel@tonic-gate 	}
32287c478bd9Sstevel@tonic-gate 	if (!plumbed && (ip6muxid == -1 || (ip6fd == -1 && !use_plink))) {
32297c478bd9Sstevel@tonic-gate 		return (1);
32307c478bd9Sstevel@tonic-gate 	}
32317c478bd9Sstevel@tonic-gate 	id = ip6muxid;
32327c478bd9Sstevel@tonic-gate 	if (!plumbed && use_plink) {
32337c478bd9Sstevel@tonic-gate 		if ((udp6fd = open_udp6fd()) == -1)
32347c478bd9Sstevel@tonic-gate 			return (0);
32357c478bd9Sstevel@tonic-gate 		/*
32367c478bd9Sstevel@tonic-gate 		 * Note: must re-get mux ID, since any intervening
32377c478bd9Sstevel@tonic-gate 		 * ifconfigs will change this.
32387c478bd9Sstevel@tonic-gate 		 */
32397c478bd9Sstevel@tonic-gate 		BZERO(&lifr, sizeof (lifr));
32407c478bd9Sstevel@tonic-gate 		(void) strlcpy(lifr.lifr_name, ifname,
32417c478bd9Sstevel@tonic-gate 		    sizeof (lifr.lifr_name));
32427c478bd9Sstevel@tonic-gate 		if (myioctl(ip6fd, SIOCGLIFMUXID, (caddr_t)&lifr) < 0) {
32437c478bd9Sstevel@tonic-gate 			warn("Can't get mux fd: SIOCGLIFMUXID: %m");
32447c478bd9Sstevel@tonic-gate 		} else {
32457c478bd9Sstevel@tonic-gate 			id = lifr.lifr_ip_muxid;
32467c478bd9Sstevel@tonic-gate 			fd = myioctl(udp6fd, _I_MUXID2FD, (void *)id);
32477c478bd9Sstevel@tonic-gate 			if (fd < 0) {
32487c478bd9Sstevel@tonic-gate 				warn("Can't get mux fd: _I_MUXID2FD: %m");
32497c478bd9Sstevel@tonic-gate 			}
32507c478bd9Sstevel@tonic-gate 		}
32517c478bd9Sstevel@tonic-gate 	}
32527c478bd9Sstevel@tonic-gate 	/*
32537c478bd9Sstevel@tonic-gate 	 * Mark down and unlink the IPv6 interface.
32547c478bd9Sstevel@tonic-gate 	 */
32557c478bd9Sstevel@tonic-gate 	(void) sif6down(unit);
32567c478bd9Sstevel@tonic-gate 	if (plumbed)
32577c478bd9Sstevel@tonic-gate 		return (1);
32587c478bd9Sstevel@tonic-gate 	ip6muxid = -1;
32597c478bd9Sstevel@tonic-gate 	if (use_plink) {
32607c478bd9Sstevel@tonic-gate 		if ((fd = myioctl(udp6fd, _I_MUXID2FD, (void *)id)) < 0) {
32617c478bd9Sstevel@tonic-gate 			error("Can't recapture mux fd: _I_MUXID2FD: %m");
32627c478bd9Sstevel@tonic-gate 			(void) close(udp6fd);
32637c478bd9Sstevel@tonic-gate 			return (0);
32647c478bd9Sstevel@tonic-gate 		}
32657c478bd9Sstevel@tonic-gate 		if (myioctl(udp6fd, I_PUNLINK, (void *)id) < 0) {
32667c478bd9Sstevel@tonic-gate 			error("Can't I_PUNLINK PPP from IPv6: %m");
32677c478bd9Sstevel@tonic-gate 			(void) close(fd);
32687c478bd9Sstevel@tonic-gate 			(void) close(udp6fd);
32697c478bd9Sstevel@tonic-gate 			return (0);
32707c478bd9Sstevel@tonic-gate 		}
32717c478bd9Sstevel@tonic-gate 		(void) close(fd);
32727c478bd9Sstevel@tonic-gate 		(void) close(udp6fd);
32737c478bd9Sstevel@tonic-gate 	} else {
32747c478bd9Sstevel@tonic-gate 		if (myioctl(ip6fd, I_UNLINK, (void *)id) < 0) {
32757c478bd9Sstevel@tonic-gate 			error("Can't I_UNLINK PPP from IPv6: %m");
32767c478bd9Sstevel@tonic-gate 			return (0);
32777c478bd9Sstevel@tonic-gate 		}
32787c478bd9Sstevel@tonic-gate 	}
32797c478bd9Sstevel@tonic-gate 	return (1);
32807c478bd9Sstevel@tonic-gate }
32817c478bd9Sstevel@tonic-gate 
32827c478bd9Sstevel@tonic-gate /*
32837c478bd9Sstevel@tonic-gate  * sif6flags()
32847c478bd9Sstevel@tonic-gate  *
32857c478bd9Sstevel@tonic-gate  * Set or clear the IPv6 interface flags.
32867c478bd9Sstevel@tonic-gate  */
32877c478bd9Sstevel@tonic-gate int
32887c478bd9Sstevel@tonic-gate sif6flags(f, set)
32897c478bd9Sstevel@tonic-gate 	u_int32_t f;
32907c478bd9Sstevel@tonic-gate 	int set;
32917c478bd9Sstevel@tonic-gate {
32927c478bd9Sstevel@tonic-gate 	struct lifreq lifr;
32937c478bd9Sstevel@tonic-gate 	int fd;
32947c478bd9Sstevel@tonic-gate 
32957c478bd9Sstevel@tonic-gate 	if (!IPV6CP_ENABLED || (ip6muxid == -1)) {
32967c478bd9Sstevel@tonic-gate 		return (0);
32977c478bd9Sstevel@tonic-gate 	}
32987c478bd9Sstevel@tonic-gate 	fd = socket(AF_INET6, SOCK_DGRAM, 0);
32997c478bd9Sstevel@tonic-gate 	if (fd < 0) {
33007c478bd9Sstevel@tonic-gate 		error("sif6flags: error opening IPv6 socket: %m");
33017c478bd9Sstevel@tonic-gate 		return (0);
33027c478bd9Sstevel@tonic-gate 	}
33037c478bd9Sstevel@tonic-gate 	BZERO(&lifr, sizeof (lifr));
33047c478bd9Sstevel@tonic-gate 	(void) strlcpy(lifr.lifr_name, ifname, sizeof (lifr.lifr_name));
33057c478bd9Sstevel@tonic-gate 	if (myioctl(fd, SIOCGLIFFLAGS, &lifr) < 0) {
33067c478bd9Sstevel@tonic-gate 		error("Couldn't get IPv6 interface flags: %m");
33077c478bd9Sstevel@tonic-gate 		(void) close(fd);
33087c478bd9Sstevel@tonic-gate 		return (0);
33097c478bd9Sstevel@tonic-gate 	}
33107c478bd9Sstevel@tonic-gate 	if (set) {
33117c478bd9Sstevel@tonic-gate 		lifr.lifr_flags |= f;
33127c478bd9Sstevel@tonic-gate 	} else {
33137c478bd9Sstevel@tonic-gate 		lifr.lifr_flags &= ~f;
33147c478bd9Sstevel@tonic-gate 	}
33157c478bd9Sstevel@tonic-gate 	(void) strlcpy(lifr.lifr_name, ifname, sizeof (lifr.lifr_name));
33167c478bd9Sstevel@tonic-gate 	if (myioctl(fd, SIOCSLIFFLAGS, &lifr) < 0) {
33177c478bd9Sstevel@tonic-gate 		error("Couldn't set IPv6 interface flags: %m");
33187c478bd9Sstevel@tonic-gate 		(void) close(fd);
33197c478bd9Sstevel@tonic-gate 		return (0);
33207c478bd9Sstevel@tonic-gate 	}
33217c478bd9Sstevel@tonic-gate 	(void) close(fd);
33227c478bd9Sstevel@tonic-gate 	return (1);
33237c478bd9Sstevel@tonic-gate }
33247c478bd9Sstevel@tonic-gate 
33257c478bd9Sstevel@tonic-gate /*
33267c478bd9Sstevel@tonic-gate  * sif6up()
33277c478bd9Sstevel@tonic-gate  *
33287c478bd9Sstevel@tonic-gate  * Config the IPv6 interface up and enable IPv6 packets to pass.
33297c478bd9Sstevel@tonic-gate  */
33307c478bd9Sstevel@tonic-gate /*ARGSUSED*/
33317c478bd9Sstevel@tonic-gate int
33327c478bd9Sstevel@tonic-gate sif6up(unit)
33337c478bd9Sstevel@tonic-gate 	int unit;
33347c478bd9Sstevel@tonic-gate {
33357c478bd9Sstevel@tonic-gate 	if (if6_is_up) {
33367c478bd9Sstevel@tonic-gate 		return (1);
33377c478bd9Sstevel@tonic-gate 	} else if (!IPV6CP_ENABLED) {
33387c478bd9Sstevel@tonic-gate 		warn("sif6up called when IPV6CP is disabled");
33397c478bd9Sstevel@tonic-gate 		return (0);
33407c478bd9Sstevel@tonic-gate 	} else if (ip6muxid == -1) {
33417c478bd9Sstevel@tonic-gate 		warn("sif6up called in wrong state");
33427c478bd9Sstevel@tonic-gate 		return (0);
33437c478bd9Sstevel@tonic-gate 	} else if (!sif6flags(IFF_UP, 1)) {
33447c478bd9Sstevel@tonic-gate 		error("Unable to mark the IPv6 interface UP");
33457c478bd9Sstevel@tonic-gate 		return (0);
33467c478bd9Sstevel@tonic-gate 	}
33477c478bd9Sstevel@tonic-gate 	if6_is_up = 1;
33487c478bd9Sstevel@tonic-gate 	return (1);
33497c478bd9Sstevel@tonic-gate }
33507c478bd9Sstevel@tonic-gate 
33517c478bd9Sstevel@tonic-gate /*
33527c478bd9Sstevel@tonic-gate  * sif6down()
33537c478bd9Sstevel@tonic-gate  *
33547c478bd9Sstevel@tonic-gate  * Config the IPv6 interface down and disable IPv6.  Possibly called from
33557c478bd9Sstevel@tonic-gate  * die(), so there shouldn't be any call to die() here.
33567c478bd9Sstevel@tonic-gate  */
33577c478bd9Sstevel@tonic-gate /*ARGSUSED*/
33587c478bd9Sstevel@tonic-gate int
33597c478bd9Sstevel@tonic-gate sif6down(unit)
33607c478bd9Sstevel@tonic-gate 	int unit;
33617c478bd9Sstevel@tonic-gate {
33627c478bd9Sstevel@tonic-gate 	if (!IPV6CP_ENABLED) {
33637c478bd9Sstevel@tonic-gate 		warn("sif6down called when IPV6CP is disabled");
33647c478bd9Sstevel@tonic-gate 		return (0);
33657c478bd9Sstevel@tonic-gate 	} else if (!if6_is_up || (ip6muxid == -1)) {
33667c478bd9Sstevel@tonic-gate 		return (1);
33677c478bd9Sstevel@tonic-gate 	} else if (!sif6flags(IFF_UP, 0)) {
33687c478bd9Sstevel@tonic-gate 		error("Unable to mark the IPv6 interface DOWN");
33697c478bd9Sstevel@tonic-gate 		return (0);
33707c478bd9Sstevel@tonic-gate 	}
33717c478bd9Sstevel@tonic-gate 	if6_is_up = 0;
33727c478bd9Sstevel@tonic-gate 	return (1);
33737c478bd9Sstevel@tonic-gate }
33747c478bd9Sstevel@tonic-gate 
33757c478bd9Sstevel@tonic-gate /*
33767c478bd9Sstevel@tonic-gate  * sif6mtu()
33777c478bd9Sstevel@tonic-gate  *
33787c478bd9Sstevel@tonic-gate  * Config the IPv6 interface MTU.
33797c478bd9Sstevel@tonic-gate  */
33807c478bd9Sstevel@tonic-gate int
33817c478bd9Sstevel@tonic-gate sif6mtu(mtu)
33827c478bd9Sstevel@tonic-gate 	int mtu;
33837c478bd9Sstevel@tonic-gate {
33847c478bd9Sstevel@tonic-gate 	struct lifreq lifr;
33857c478bd9Sstevel@tonic-gate 	int s;
33867c478bd9Sstevel@tonic-gate 
33877c478bd9Sstevel@tonic-gate 	if (!IPV6CP_ENABLED || (ip6muxid == -1)) {
33887c478bd9Sstevel@tonic-gate 		return (0);
33897c478bd9Sstevel@tonic-gate 	}
33907c478bd9Sstevel@tonic-gate 	s = socket(AF_INET6, SOCK_DGRAM, 0);
33917c478bd9Sstevel@tonic-gate 	if (s < 0) {
33927c478bd9Sstevel@tonic-gate 		error("sif6mtu: error opening IPv6 socket: %m");
33937c478bd9Sstevel@tonic-gate 		return (0);
33947c478bd9Sstevel@tonic-gate 	}
33957c478bd9Sstevel@tonic-gate 	BZERO(&lifr, sizeof (lifr));
33967c478bd9Sstevel@tonic-gate 	(void) strlcpy(lifr.lifr_name, ifname, sizeof (lifr.lifr_name));
33977c478bd9Sstevel@tonic-gate 	lifr.lifr_mtu = mtu;
33987c478bd9Sstevel@tonic-gate 	if (myioctl(s, SIOCSLIFMTU, &lifr) < 0) {
33997c478bd9Sstevel@tonic-gate 		error("Couldn't set IPv6 MTU (%s): %m", lifr.lifr_name);
34007c478bd9Sstevel@tonic-gate 		(void) close(s);
34017c478bd9Sstevel@tonic-gate 		return (0);
34027c478bd9Sstevel@tonic-gate 	}
34037c478bd9Sstevel@tonic-gate 	(void) close(s);
34047c478bd9Sstevel@tonic-gate 	return (1);
34057c478bd9Sstevel@tonic-gate }
34067c478bd9Sstevel@tonic-gate 
34077c478bd9Sstevel@tonic-gate /*
34087c478bd9Sstevel@tonic-gate  * sif6addr()
34097c478bd9Sstevel@tonic-gate  *
34107c478bd9Sstevel@tonic-gate  * Config the interface with an IPv6 link-local address.
34117c478bd9Sstevel@tonic-gate  */
34127c478bd9Sstevel@tonic-gate /*ARGSUSED*/
34137c478bd9Sstevel@tonic-gate int
34147c478bd9Sstevel@tonic-gate sif6addr(unit, ourid, hisid)
34157c478bd9Sstevel@tonic-gate 	int unit;
34167c478bd9Sstevel@tonic-gate 	eui64_t ourid;
34177c478bd9Sstevel@tonic-gate 	eui64_t hisid;
34187c478bd9Sstevel@tonic-gate {
34197c478bd9Sstevel@tonic-gate 	struct lifreq lifr;
34207c478bd9Sstevel@tonic-gate 	struct sockaddr_storage	laddr;
34217c478bd9Sstevel@tonic-gate 	struct sockaddr_in6 *sin6 = (struct sockaddr_in6 *)&laddr;
34227c478bd9Sstevel@tonic-gate 	int fd;
34237c478bd9Sstevel@tonic-gate 
34247c478bd9Sstevel@tonic-gate 	if (!IPV6CP_ENABLED || (ip6muxid == -1 && plumb_ip6if(unit) == 0)) {
34257c478bd9Sstevel@tonic-gate 		return (0);
34267c478bd9Sstevel@tonic-gate 	}
34277c478bd9Sstevel@tonic-gate 	fd = socket(AF_INET6, SOCK_DGRAM, 0);
34287c478bd9Sstevel@tonic-gate 	if (fd < 0) {
34297c478bd9Sstevel@tonic-gate 		error("sif6addr: error opening IPv6 socket: %m");
34307c478bd9Sstevel@tonic-gate 		return (0);
34317c478bd9Sstevel@tonic-gate 	}
34327c478bd9Sstevel@tonic-gate 	/*
34337c478bd9Sstevel@tonic-gate 	 * Set the IPv6 interface MTU.
34347c478bd9Sstevel@tonic-gate 	 */
34357c478bd9Sstevel@tonic-gate 	if (!sif6mtu(link_mtu)) {
34367c478bd9Sstevel@tonic-gate 		(void) close(fd);
34377c478bd9Sstevel@tonic-gate 		return (0);
34387c478bd9Sstevel@tonic-gate 	}
34397c478bd9Sstevel@tonic-gate 	/*
34407c478bd9Sstevel@tonic-gate 	 * Set the interface address token.  Do this because /dev/ppp responds
34417c478bd9Sstevel@tonic-gate 	 * to DL_PHYS_ADDR_REQ with zero values, hence the interface token
34427c478bd9Sstevel@tonic-gate 	 * came to be zero too, and without this, in.ndpd will complain.
34437c478bd9Sstevel@tonic-gate 	 */
34447c478bd9Sstevel@tonic-gate 	BZERO(&lifr, sizeof (lifr));
34457c478bd9Sstevel@tonic-gate 	(void) strlcpy(lifr.lifr_name, ifname, sizeof (lifr.lifr_name));
34467c478bd9Sstevel@tonic-gate 	BZERO(sin6, sizeof (struct sockaddr_in6));
34477c478bd9Sstevel@tonic-gate 	IN6_LLTOKEN_FROM_EUI64(lifr, sin6, ourid);
34487c478bd9Sstevel@tonic-gate 	if (myioctl(fd, SIOCSLIFTOKEN, &lifr) < 0) {
34497c478bd9Sstevel@tonic-gate 		error("Couldn't set IPv6 token (%s): %m", lifr.lifr_name);
34507c478bd9Sstevel@tonic-gate 		(void) close(fd);
34517c478bd9Sstevel@tonic-gate 		return (0);
34527c478bd9Sstevel@tonic-gate 	}
34537c478bd9Sstevel@tonic-gate 	/*
34547c478bd9Sstevel@tonic-gate 	 * Set the IPv6 interface local point-to-point address.
34557c478bd9Sstevel@tonic-gate 	 */
34567c478bd9Sstevel@tonic-gate 	IN6_LLADDR_FROM_EUI64(lifr, sin6, ourid);
34577c478bd9Sstevel@tonic-gate 	if (myioctl(fd, SIOCSLIFADDR, &lifr) < 0) {
34587c478bd9Sstevel@tonic-gate 		error("Couldn't set local IPv6 address (%s): %m",
34597c478bd9Sstevel@tonic-gate 		    lifr.lifr_name);
34607c478bd9Sstevel@tonic-gate 		(void) close(fd);
34617c478bd9Sstevel@tonic-gate 		return (0);
34627c478bd9Sstevel@tonic-gate 	}
34637c478bd9Sstevel@tonic-gate 	/*
34647c478bd9Sstevel@tonic-gate 	 * Set the IPv6 interface local point-to-point address.
34657c478bd9Sstevel@tonic-gate 	 */
34667c478bd9Sstevel@tonic-gate 	BZERO(&lifr, sizeof (lifr));
34677c478bd9Sstevel@tonic-gate 	(void) strlcpy(lifr.lifr_name, ifname, sizeof (lifr.lifr_name));
34687c478bd9Sstevel@tonic-gate 	IN6_LLADDR_FROM_EUI64(lifr, sin6, hisid);
34697c478bd9Sstevel@tonic-gate 	if (myioctl(fd, SIOCSLIFDSTADDR, &lifr) < 0) {
34707c478bd9Sstevel@tonic-gate 		error("Couldn't set remote IPv6 address (%s): %m",
34717c478bd9Sstevel@tonic-gate 		    lifr.lifr_name);
34727c478bd9Sstevel@tonic-gate 		(void) close(fd);
34737c478bd9Sstevel@tonic-gate 		return (0);
34747c478bd9Sstevel@tonic-gate 	}
34757c478bd9Sstevel@tonic-gate 	(void) close(fd);
34767c478bd9Sstevel@tonic-gate 	return (1);
34777c478bd9Sstevel@tonic-gate }
34787c478bd9Sstevel@tonic-gate 
34797c478bd9Sstevel@tonic-gate /*
34807c478bd9Sstevel@tonic-gate  * cif6addr()
34817c478bd9Sstevel@tonic-gate  */
34827c478bd9Sstevel@tonic-gate /*ARGSUSED*/
34837c478bd9Sstevel@tonic-gate int
34847c478bd9Sstevel@tonic-gate cif6addr(u, o, h)
34857c478bd9Sstevel@tonic-gate 	int u;
34867c478bd9Sstevel@tonic-gate 	eui64_t o;
34877c478bd9Sstevel@tonic-gate 	eui64_t h;
34887c478bd9Sstevel@tonic-gate {
34897c478bd9Sstevel@tonic-gate 	if (!IPV6CP_ENABLED) {
34907c478bd9Sstevel@tonic-gate 		return (0);
34917c478bd9Sstevel@tonic-gate 	}
34927c478bd9Sstevel@tonic-gate 	/*
34937c478bd9Sstevel@tonic-gate 	 * Do nothing here, as everything has been done in sif6down().
34947c478bd9Sstevel@tonic-gate 	 */
34957c478bd9Sstevel@tonic-gate 	return (1);
34967c478bd9Sstevel@tonic-gate }
34977c478bd9Sstevel@tonic-gate 
34987c478bd9Sstevel@tonic-gate /*
34997c478bd9Sstevel@tonic-gate  * ether_to_eui64()
35007c478bd9Sstevel@tonic-gate  *
35017c478bd9Sstevel@tonic-gate  * Convert 48-bit Ethernet address into 64-bit EUI. Walks the list of valid
35027c478bd9Sstevel@tonic-gate  * ethernet interfaces, and convert the first found 48-bit MAC address into
35037c478bd9Sstevel@tonic-gate  * EUI 64. caller also assumes that the system has a properly configured
35047c478bd9Sstevel@tonic-gate  * Ethernet interface for this function to return non-zero.
35057c478bd9Sstevel@tonic-gate  */
35067c478bd9Sstevel@tonic-gate int
35077c478bd9Sstevel@tonic-gate ether_to_eui64(p_eui64)
35087c478bd9Sstevel@tonic-gate 	eui64_t *p_eui64;
35097c478bd9Sstevel@tonic-gate {
35107c478bd9Sstevel@tonic-gate 	struct ether_addr eth_addr;
35117c478bd9Sstevel@tonic-gate 
35127c478bd9Sstevel@tonic-gate 	if (p_eui64 == NULL) {
35137c478bd9Sstevel@tonic-gate 		return (0);
35147c478bd9Sstevel@tonic-gate 	}
35157c478bd9Sstevel@tonic-gate 	if (!get_first_hwaddr(eth_addr.ether_addr_octet,
35167c478bd9Sstevel@tonic-gate 	    sizeof (eth_addr.ether_addr_octet))) {
35177c478bd9Sstevel@tonic-gate 		return (0);
35187c478bd9Sstevel@tonic-gate 	}
35197c478bd9Sstevel@tonic-gate 	/*
35207c478bd9Sstevel@tonic-gate 	 * And convert the EUI-48 into EUI-64, per RFC 2472 [sec 4.1]
35217c478bd9Sstevel@tonic-gate 	 */
35227c478bd9Sstevel@tonic-gate 	p_eui64->e8[0] = (eth_addr.ether_addr_octet[0] & 0xFF) | 0x02;
35237c478bd9Sstevel@tonic-gate 	p_eui64->e8[1] = (eth_addr.ether_addr_octet[1] & 0xFF);
35247c478bd9Sstevel@tonic-gate 	p_eui64->e8[2] = (eth_addr.ether_addr_octet[2] & 0xFF);
35257c478bd9Sstevel@tonic-gate 	p_eui64->e8[3] = 0xFF;
35267c478bd9Sstevel@tonic-gate 	p_eui64->e8[4] = 0xFE;
35277c478bd9Sstevel@tonic-gate 	p_eui64->e8[5] = (eth_addr.ether_addr_octet[3] & 0xFF);
35287c478bd9Sstevel@tonic-gate 	p_eui64->e8[6] = (eth_addr.ether_addr_octet[4] & 0xFF);
35297c478bd9Sstevel@tonic-gate 	p_eui64->e8[7] = (eth_addr.ether_addr_octet[5] & 0xFF);
35307c478bd9Sstevel@tonic-gate 	return (1);
35317c478bd9Sstevel@tonic-gate }
35327c478bd9Sstevel@tonic-gate #endif /* INET6 */
35337c478bd9Sstevel@tonic-gate 
35347c478bd9Sstevel@tonic-gate struct bit_ent {
35357c478bd9Sstevel@tonic-gate 	int val;
35367c478bd9Sstevel@tonic-gate 	char *off, *on;
35377c478bd9Sstevel@tonic-gate };
35387c478bd9Sstevel@tonic-gate 
35397c478bd9Sstevel@tonic-gate /* see sbuf[] below if you change this list */
35407c478bd9Sstevel@tonic-gate static struct bit_ent bit_list[] = {
35417c478bd9Sstevel@tonic-gate 	{ TIOCM_DTR, "dtr", "DTR" },
35427c478bd9Sstevel@tonic-gate 	{ TIOCM_RTS, "rts", "RTS" },
35437c478bd9Sstevel@tonic-gate 	{ TIOCM_CTS, "cts", "CTS" },
35447c478bd9Sstevel@tonic-gate 	{ TIOCM_CD, "dcd", "DCD" },
35457c478bd9Sstevel@tonic-gate 	{ TIOCM_RI, "ri", "RI" },
35467c478bd9Sstevel@tonic-gate 	{ TIOCM_DSR, "dsr", "DSR" },
35477c478bd9Sstevel@tonic-gate #if 0
35487c478bd9Sstevel@tonic-gate 	{ TIOCM_LE, "disabled", "ENABLED" },
35497c478bd9Sstevel@tonic-gate 	{ TIOCM_ST, NULL, "2nd-XMIT" },
35507c478bd9Sstevel@tonic-gate 	{ TIOCM_SR, NULL, "2nd-RECV" },
35517c478bd9Sstevel@tonic-gate #endif
35527c478bd9Sstevel@tonic-gate 	{ 0, NULL, NULL }
35537c478bd9Sstevel@tonic-gate };
35547c478bd9Sstevel@tonic-gate 
35557c478bd9Sstevel@tonic-gate static void
35567c478bd9Sstevel@tonic-gate getbits(int fd, char *name, FILE *strptr)
35577c478bd9Sstevel@tonic-gate {
35587c478bd9Sstevel@tonic-gate 	int nmods, i;
35597c478bd9Sstevel@tonic-gate 	struct str_list strlist;
35607c478bd9Sstevel@tonic-gate 	struct bit_ent *be;
35617c478bd9Sstevel@tonic-gate 	int mstate;
35627c478bd9Sstevel@tonic-gate 	char sbuf[50];		/* sum of string lengths in bit_list */
35637c478bd9Sstevel@tonic-gate 	char *str;
35647c478bd9Sstevel@tonic-gate 
35657c478bd9Sstevel@tonic-gate 	nmods = ioctl(fd, I_LIST, NULL);
35667c478bd9Sstevel@tonic-gate 	if (nmods < 0) {
35677c478bd9Sstevel@tonic-gate 		error("unable to get module count: %m");
35687c478bd9Sstevel@tonic-gate 	} else {
35697c478bd9Sstevel@tonic-gate 		strlist.sl_nmods = nmods;
35707c478bd9Sstevel@tonic-gate 		strlist.sl_modlist = malloc(sizeof (struct str_mlist) * nmods);
35717c478bd9Sstevel@tonic-gate 		if (strlist.sl_modlist == NULL)
35727c478bd9Sstevel@tonic-gate 			novm("module list");
35737c478bd9Sstevel@tonic-gate 		if (ioctl(fd, I_LIST, (caddr_t)&strlist) < 0) {
35747c478bd9Sstevel@tonic-gate 			error("unable to get module names: %m");
35757c478bd9Sstevel@tonic-gate 		} else {
35767c478bd9Sstevel@tonic-gate 			for (i = 0; i < strlist.sl_nmods; i++)
35777c478bd9Sstevel@tonic-gate 				(void) flprintf(strptr, "%d: %s", i,
35787c478bd9Sstevel@tonic-gate 				    strlist.sl_modlist[i].l_name);
35797c478bd9Sstevel@tonic-gate 			free(strlist.sl_modlist);
35807c478bd9Sstevel@tonic-gate 		}
35817c478bd9Sstevel@tonic-gate 	}
35827c478bd9Sstevel@tonic-gate 	if (ioctl(fd, TIOCMGET, &mstate) < 0) {
35837c478bd9Sstevel@tonic-gate 		error("unable to get modem state: %m");
35847c478bd9Sstevel@tonic-gate 	} else {
35857c478bd9Sstevel@tonic-gate 		sbuf[0] = '\0';
35867c478bd9Sstevel@tonic-gate 		for (be = bit_list; be->val != 0; be++) {
35877c478bd9Sstevel@tonic-gate 			str = (be->val & mstate) ? be->on : be->off;
35887c478bd9Sstevel@tonic-gate 			if (str != NULL) {
35897c478bd9Sstevel@tonic-gate 				if (sbuf[0] != '\0')
35907c478bd9Sstevel@tonic-gate 					(void) strcat(sbuf, " ");
35917c478bd9Sstevel@tonic-gate 				(void) strcat(sbuf, str);
35927c478bd9Sstevel@tonic-gate 			}
35937c478bd9Sstevel@tonic-gate 		}
35947c478bd9Sstevel@tonic-gate 		(void) flprintf(strptr, "%s: %s\n", name, sbuf);
35957c478bd9Sstevel@tonic-gate 	}
35967c478bd9Sstevel@tonic-gate }
35977c478bd9Sstevel@tonic-gate 
35987c478bd9Sstevel@tonic-gate /*
35997c478bd9Sstevel@tonic-gate  * Print state of serial link.  The stream might be linked under the
36007c478bd9Sstevel@tonic-gate  * /dev/sppp driver.  If it is, then it's necessary to unlink it first
36017c478bd9Sstevel@tonic-gate  * and relink it when done.  Otherwise, it's not possible to use
36027c478bd9Sstevel@tonic-gate  * ioctl() on the stream.
36037c478bd9Sstevel@tonic-gate  */
36047c478bd9Sstevel@tonic-gate void
36057c478bd9Sstevel@tonic-gate sys_print_state(FILE *strptr)
36067c478bd9Sstevel@tonic-gate {
36077c478bd9Sstevel@tonic-gate 	bool was_linked;
36087c478bd9Sstevel@tonic-gate 
36097c478bd9Sstevel@tonic-gate 	if (pppfd == -1)
36107c478bd9Sstevel@tonic-gate 		return;
36117c478bd9Sstevel@tonic-gate 	if (ttyfd == -1) {
36127c478bd9Sstevel@tonic-gate 		(void) flprintf(strptr, "serial link is not active");
36137c478bd9Sstevel@tonic-gate 		return;
36147c478bd9Sstevel@tonic-gate 	}
36157c478bd9Sstevel@tonic-gate 	was_linked = fdmuxid != -1;
36167c478bd9Sstevel@tonic-gate 	if (was_linked && ioctl(pppfd, I_UNLINK, fdmuxid) == -1) {
36177c478bd9Sstevel@tonic-gate 		error("I_UNLINK: %m");
36187c478bd9Sstevel@tonic-gate 	} else {
36197c478bd9Sstevel@tonic-gate 		fdmuxid = -1;
36207c478bd9Sstevel@tonic-gate 		getbits(ttyfd, devnam, strptr);
36217c478bd9Sstevel@tonic-gate 		if (was_linked &&
36227c478bd9Sstevel@tonic-gate 		    (fdmuxid = ioctl(pppfd, I_LINK, (void *)ttyfd)) == -1)
36237c478bd9Sstevel@tonic-gate 			fatal("I_LINK: %m");
36247c478bd9Sstevel@tonic-gate 	}
36257c478bd9Sstevel@tonic-gate }
36267c478bd9Sstevel@tonic-gate 
36277c478bd9Sstevel@tonic-gate /*
36287c478bd9Sstevel@tonic-gate  * send ioctl to driver asking it to block packets with network protocol
36297c478bd9Sstevel@tonic-gate  * proto in the control queue until the queue for proto is plumbed.
36307c478bd9Sstevel@tonic-gate  */
36317c478bd9Sstevel@tonic-gate void
36327c478bd9Sstevel@tonic-gate sys_block_proto(uint16_t proto)
36337c478bd9Sstevel@tonic-gate {
36347c478bd9Sstevel@tonic-gate 	if (proto > 0x7fff) {
36357c478bd9Sstevel@tonic-gate 		warn("cannot block: not a network proto 0x%lx\n", proto);
36367c478bd9Sstevel@tonic-gate 		return;
36377c478bd9Sstevel@tonic-gate 	}
36387c478bd9Sstevel@tonic-gate 	if (strioctl(pppfd, PPPIO_BLOCKNP, &proto, sizeof (proto), 0) < 0) {
36397c478bd9Sstevel@tonic-gate 		warn("PPPIO_BLOCKNP ioctl failed %m");
36407c478bd9Sstevel@tonic-gate 	}
36417c478bd9Sstevel@tonic-gate }
36427c478bd9Sstevel@tonic-gate /*
36437c478bd9Sstevel@tonic-gate  * send ioctl to driver asking it to release packets with network protocol
36447c478bd9Sstevel@tonic-gate  * proto from control queue to the protocol specific queue.
36457c478bd9Sstevel@tonic-gate  */
36467c478bd9Sstevel@tonic-gate void
36477c478bd9Sstevel@tonic-gate sys_unblock_proto(uint16_t proto)
36487c478bd9Sstevel@tonic-gate {
36497c478bd9Sstevel@tonic-gate 	if (proto > 0x7fff) {
36507c478bd9Sstevel@tonic-gate 		warn("cannot unblock: not a network proto 0x%lx\n", proto);
36517c478bd9Sstevel@tonic-gate 		return;
36527c478bd9Sstevel@tonic-gate 	}
36537c478bd9Sstevel@tonic-gate 	if (strioctl(pppfd, PPPIO_UNBLOCKNP, &proto, sizeof (proto), 0) < 0) {
36547c478bd9Sstevel@tonic-gate 		warn("PPPIO_UNBLOCKNP ioctl failed %m");
36557c478bd9Sstevel@tonic-gate 	}
36567c478bd9Sstevel@tonic-gate }
3657