xref: /onnv-gate/usr/src/cmd/cmd-inet/usr.bin/pppd/sys-solaris.c (revision 9751:8e29565352fc)
10Sstevel@tonic-gate /*
20Sstevel@tonic-gate  * System-dependent procedures for pppd under Solaris 2.x (SunOS 5.x).
30Sstevel@tonic-gate  *
49354STim.Marsland@Sun.COM  * Copyright 2009 Sun Microsystems, Inc.  All rights reserved.
50Sstevel@tonic-gate  * Use is subject to license terms.
60Sstevel@tonic-gate  *
70Sstevel@tonic-gate  * Permission to use, copy, modify, and distribute this software and its
80Sstevel@tonic-gate  * documentation is hereby granted, provided that the above copyright
90Sstevel@tonic-gate  * notice appears in all copies.
100Sstevel@tonic-gate  *
110Sstevel@tonic-gate  * SUN MAKES NO REPRESENTATION OR WARRANTIES ABOUT THE SUITABILITY OF
120Sstevel@tonic-gate  * THE SOFTWARE, EITHER EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED
130Sstevel@tonic-gate  * TO THE IMPLIED WARRANTIES OF MERCHANTABILITY, FITNESS FOR A
140Sstevel@tonic-gate  * PARTICULAR PURPOSE, OR NON-INFRINGEMENT.  SUN SHALL NOT BE LIABLE FOR
150Sstevel@tonic-gate  * ANY DAMAGES SUFFERED BY LICENSEE AS A RESULT OF USING, MODIFYING OR
160Sstevel@tonic-gate  * DISTRIBUTING THIS SOFTWARE OR ITS DERIVATIVES
170Sstevel@tonic-gate  *
180Sstevel@tonic-gate  * Copyright (c) 1994 The Australian National University.
190Sstevel@tonic-gate  * All rights reserved.
200Sstevel@tonic-gate  *
210Sstevel@tonic-gate  * Permission to use, copy, modify, and distribute this software and its
220Sstevel@tonic-gate  * documentation is hereby granted, provided that the above copyright
230Sstevel@tonic-gate  * notice appears in all copies.  This software is provided without any
240Sstevel@tonic-gate  * warranty, express or implied. The Australian National University
250Sstevel@tonic-gate  * makes no representations about the suitability of this software for
260Sstevel@tonic-gate  * any purpose.
270Sstevel@tonic-gate  *
280Sstevel@tonic-gate  * IN NO EVENT SHALL THE AUSTRALIAN NATIONAL UNIVERSITY BE LIABLE TO ANY
290Sstevel@tonic-gate  * PARTY FOR DIRECT, INDIRECT, SPECIAL, INCIDENTAL, OR CONSEQUENTIAL DAMAGES
300Sstevel@tonic-gate  * ARISING OUT OF THE USE OF THIS SOFTWARE AND ITS DOCUMENTATION, EVEN IF
310Sstevel@tonic-gate  * THE AUSTRALIAN NATIONAL UNIVERSITY HAVE BEEN ADVISED OF THE POSSIBILITY
320Sstevel@tonic-gate  * OF SUCH DAMAGE.
330Sstevel@tonic-gate  *
340Sstevel@tonic-gate  * THE AUSTRALIAN NATIONAL UNIVERSITY SPECIFICALLY DISCLAIMS ANY WARRANTIES,
350Sstevel@tonic-gate  * INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY
360Sstevel@tonic-gate  * AND FITNESS FOR A PARTICULAR PURPOSE.  THE SOFTWARE PROVIDED HEREUNDER IS
370Sstevel@tonic-gate  * ON AN "AS IS" BASIS, AND THE AUSTRALIAN NATIONAL UNIVERSITY HAS NO
380Sstevel@tonic-gate  * OBLIGATION TO PROVIDE MAINTENANCE, SUPPORT, UPDATES, ENHANCEMENTS,
390Sstevel@tonic-gate  * OR MODIFICATIONS.
400Sstevel@tonic-gate  */
410Sstevel@tonic-gate 
420Sstevel@tonic-gate #define	RCSID	"$Id: sys-solaris.c,v 1.2 2000/04/21 01:27:57 masputra Exp $"
430Sstevel@tonic-gate 
440Sstevel@tonic-gate #include <limits.h>
450Sstevel@tonic-gate #include <stdio.h>
460Sstevel@tonic-gate #include <stddef.h>
470Sstevel@tonic-gate #include <stdlib.h>
480Sstevel@tonic-gate #include <ctype.h>
490Sstevel@tonic-gate #include <errno.h>
500Sstevel@tonic-gate #include <fcntl.h>
510Sstevel@tonic-gate #include <unistd.h>
520Sstevel@tonic-gate #include <netdb.h>
530Sstevel@tonic-gate #include <termios.h>
540Sstevel@tonic-gate #include <signal.h>
550Sstevel@tonic-gate #include <string.h>
560Sstevel@tonic-gate #include <stropts.h>
570Sstevel@tonic-gate #include <utmpx.h>
580Sstevel@tonic-gate #include <sys/types.h>
590Sstevel@tonic-gate #include <sys/ioccom.h>
600Sstevel@tonic-gate #include <sys/stream.h>
610Sstevel@tonic-gate #include <sys/stropts.h>
620Sstevel@tonic-gate #include <sys/socket.h>
630Sstevel@tonic-gate #include <sys/sockio.h>
640Sstevel@tonic-gate #include <sys/sysmacros.h>
650Sstevel@tonic-gate #include <sys/systeminfo.h>
660Sstevel@tonic-gate #include <sys/stat.h>
670Sstevel@tonic-gate #include <net/if.h>
680Sstevel@tonic-gate #include <net/if_arp.h>
690Sstevel@tonic-gate #include <net/route.h>
700Sstevel@tonic-gate #include <net/ppp_defs.h>
710Sstevel@tonic-gate #include <net/pppio.h>
720Sstevel@tonic-gate #include <net/if_types.h>
730Sstevel@tonic-gate #include <net/if_dl.h>
740Sstevel@tonic-gate #include <netinet/in.h>
750Sstevel@tonic-gate #include <sys/tihdr.h>
760Sstevel@tonic-gate #include <inet/mib2.h>
77741Smasputra #include <inet/ip.h>
780Sstevel@tonic-gate #include <sys/ethernet.h>
790Sstevel@tonic-gate #include <sys/ser_sync.h>
806631Sss150715 #include <libdlpi.h>
81*9751Sjames.d.carlson@sun.com #include <arpa/inet.h>
820Sstevel@tonic-gate 
830Sstevel@tonic-gate #include "pppd.h"
840Sstevel@tonic-gate #include "fsm.h"
850Sstevel@tonic-gate #include "lcp.h"
860Sstevel@tonic-gate #include "ipcp.h"
870Sstevel@tonic-gate #ifdef INET6
880Sstevel@tonic-gate #include "ipv6cp.h"
890Sstevel@tonic-gate #endif /* INET6 */
900Sstevel@tonic-gate #include "ccp.h"
910Sstevel@tonic-gate 
920Sstevel@tonic-gate #if !defined(lint) && !defined(_lint)
930Sstevel@tonic-gate static const char rcsid[] = RCSID;
940Sstevel@tonic-gate #endif
950Sstevel@tonic-gate 
960Sstevel@tonic-gate #define	PPPSTRTIMOUT	1	/* Timeout in seconds for ioctl */
970Sstevel@tonic-gate #define	MAX_POLLFDS	32
980Sstevel@tonic-gate #define	NMODULES	32
990Sstevel@tonic-gate 
1000Sstevel@tonic-gate #ifndef MAXIFS
1010Sstevel@tonic-gate #define	MAXIFS		256
1020Sstevel@tonic-gate #endif /* MAXIFS */
1030Sstevel@tonic-gate 
1040Sstevel@tonic-gate #ifdef INET6
1050Sstevel@tonic-gate #define	_IN6_LLX_FROM_EUI64(l, s, eui64, as, len)	\
1060Sstevel@tonic-gate 	(s->sin6_addr.s6_addr32[0] = htonl(as),		\
1070Sstevel@tonic-gate 	eui64_copy(eui64, s->sin6_addr.s6_addr32[2]),	\
1080Sstevel@tonic-gate 	s->sin6_family = AF_INET6,			\
1090Sstevel@tonic-gate 	l.lifr_addr.ss_family = AF_INET6,		\
1100Sstevel@tonic-gate 	l.lifr_addrlen = len,				\
1110Sstevel@tonic-gate 	l.lifr_addr = laddr)
1120Sstevel@tonic-gate 
1130Sstevel@tonic-gate /*
1140Sstevel@tonic-gate  * Generate a link-local address with an interface-id based on the given
1150Sstevel@tonic-gate  * EUI64 identifier.  Note that the len field is unused by SIOCSLIFADDR.
1160Sstevel@tonic-gate  */
1170Sstevel@tonic-gate #define	IN6_LLADDR_FROM_EUI64(l, s, eui64)		\
1180Sstevel@tonic-gate 	_IN6_LLX_FROM_EUI64(l, s, eui64, 0xfe800000, 0)
1190Sstevel@tonic-gate 
1200Sstevel@tonic-gate /*
1210Sstevel@tonic-gate  * Generate an EUI64 based interface-id for use by stateless address
1220Sstevel@tonic-gate  * autoconfiguration.  These are required to be 64 bits long as defined in
1230Sstevel@tonic-gate  * the "Interface Identifiers" section of the IPv6 Addressing Architecture
1240Sstevel@tonic-gate  * (RFC3513).
1250Sstevel@tonic-gate  */
1260Sstevel@tonic-gate #define	IN6_LLTOKEN_FROM_EUI64(l, s, eui64) \
1270Sstevel@tonic-gate 	_IN6_LLX_FROM_EUI64(l, s, eui64, 0, 64)
1280Sstevel@tonic-gate #endif /* INET6 */
1290Sstevel@tonic-gate 
1300Sstevel@tonic-gate #define	IPCP_ENABLED	ipcp_protent.enabled_flag
1310Sstevel@tonic-gate #ifdef INET6
1320Sstevel@tonic-gate #define	IPV6CP_ENABLED	ipv6cp_protent.enabled_flag
1330Sstevel@tonic-gate #endif /* INET6 */
1340Sstevel@tonic-gate 
1350Sstevel@tonic-gate /* For plug-in usage. */
1360Sstevel@tonic-gate int (*sys_read_packet_hook) __P((int retv, struct strbuf *ctrl,
1370Sstevel@tonic-gate     struct strbuf *data, int flags)) = NULL;
1380Sstevel@tonic-gate bool already_ppp = 0;			/* Already in PPP mode */
1390Sstevel@tonic-gate 
1400Sstevel@tonic-gate static int pppfd = -1;			/* ppp driver fd */
1410Sstevel@tonic-gate static int fdmuxid = -1;		/* driver mux fd */
1420Sstevel@tonic-gate static int ipfd = -1;			/* IPv4 fd */
1430Sstevel@tonic-gate static int ipmuxid = -1;		/* IPv4 mux fd */
1440Sstevel@tonic-gate static int ip6fd = -1;			/* IPv6 fd */
1450Sstevel@tonic-gate static int ip6muxid = -1;		/* IPv6 mux fd */
1460Sstevel@tonic-gate static bool if6_is_up = 0;		/* IPv6 if marked as up */
1470Sstevel@tonic-gate static bool if_is_up = 0;		/* IPv4 if marked as up */
1480Sstevel@tonic-gate static bool restore_term = 0;		/* Restore TTY after closing link */
1490Sstevel@tonic-gate static struct termios inittermios;	/* TTY settings */
1500Sstevel@tonic-gate static struct winsize wsinfo;		/* Initial window size info */
1510Sstevel@tonic-gate static pid_t tty_sid;			/* original sess ID for term */
1520Sstevel@tonic-gate static struct pollfd pollfds[MAX_POLLFDS]; /* array of polled fd */
1530Sstevel@tonic-gate static int n_pollfds = 0;		/* total count of polled fd */
1540Sstevel@tonic-gate static int link_mtu;			/* link Maximum Transmit Unit */
1550Sstevel@tonic-gate static int tty_nmodules;		/* total count of TTY modules used */
1560Sstevel@tonic-gate static char tty_modules[NMODULES][FMNAMESZ+1];
1570Sstevel@tonic-gate 					/* array of TTY modules used */
1580Sstevel@tonic-gate static int tty_npushed;			/* total count of pushed PPP modules */
1590Sstevel@tonic-gate static u_int32_t remote_addr;		/* IP address of peer */
1600Sstevel@tonic-gate static u_int32_t default_route_gateway;	/* Gateway for default route */
1610Sstevel@tonic-gate static u_int32_t proxy_arp_addr;	/* Addr for proxy arp entry */
1620Sstevel@tonic-gate static u_int32_t lastlink_status;	/* Last link status info */
1630Sstevel@tonic-gate 
1640Sstevel@tonic-gate static bool use_plink = 0;		/* Use I_LINK by default */
1650Sstevel@tonic-gate static bool plumbed = 0;		/* Use existing interface */
1660Sstevel@tonic-gate 
1670Sstevel@tonic-gate /* Default is to use /dev/sppp as driver. */
1680Sstevel@tonic-gate static const char *drvnam = PPP_DEV_NAME;
1690Sstevel@tonic-gate static bool integrated_driver = 0;
1700Sstevel@tonic-gate static int extra_dev_fd = -1;		/* keep open until ready */
1710Sstevel@tonic-gate 
1720Sstevel@tonic-gate static option_t solaris_option_list[] = {
1730Sstevel@tonic-gate 	{ "plink", o_bool, &use_plink, "Use I_PLINK instead of I_LINK",
1740Sstevel@tonic-gate 	    OPT_PRIV|1 },
1750Sstevel@tonic-gate 	{ "noplink", o_bool, &use_plink, "Use I_LINK instead of I_PLINK",
1760Sstevel@tonic-gate 	    OPT_PRIV|0 },
1770Sstevel@tonic-gate 	{ "plumbed", o_bool, &plumbed, "Use pre-plumbed interface",
1780Sstevel@tonic-gate 	    OPT_PRIV|1 },
1790Sstevel@tonic-gate 	{ NULL }
1800Sstevel@tonic-gate };
1810Sstevel@tonic-gate 
1820Sstevel@tonic-gate /*
1830Sstevel@tonic-gate  * Prototypes for procedures local to this file.
1840Sstevel@tonic-gate  */
1850Sstevel@tonic-gate static int translate_speed __P((int));
1860Sstevel@tonic-gate static int baud_rate_of __P((int));
1870Sstevel@tonic-gate static int get_ether_addr __P((u_int32_t, struct sockaddr_dl *, int));
1880Sstevel@tonic-gate static int strioctl __P((int, int, void *, int, int));
1890Sstevel@tonic-gate static int plumb_ipif __P((int));
1900Sstevel@tonic-gate static int unplumb_ipif __P((int));
1910Sstevel@tonic-gate #ifdef INET6
1920Sstevel@tonic-gate static int plumb_ip6if __P((int));
1930Sstevel@tonic-gate static int unplumb_ip6if __P((int));
1940Sstevel@tonic-gate static int open_ip6fd(void);
1950Sstevel@tonic-gate #endif /* INET6 */
1960Sstevel@tonic-gate static int open_ipfd(void);
1970Sstevel@tonic-gate static int sifroute __P((int, u_int32_t, u_int32_t, int, const char *));
1980Sstevel@tonic-gate static int giflags __P((u_int32_t, bool *));
1990Sstevel@tonic-gate static void handle_unbind __P((u_int32_t));
2000Sstevel@tonic-gate static void handle_bind __P((u_int32_t));
2010Sstevel@tonic-gate 
2020Sstevel@tonic-gate /*
2030Sstevel@tonic-gate  * Wrapper for regular ioctl; masks out EINTR.
2040Sstevel@tonic-gate  */
2050Sstevel@tonic-gate static int
myioctl(int fd,int cmd,void * arg)2060Sstevel@tonic-gate myioctl(int fd, int cmd, void *arg)
2070Sstevel@tonic-gate {
2080Sstevel@tonic-gate 	int retv;
2090Sstevel@tonic-gate 
2100Sstevel@tonic-gate 	errno = 0;
2110Sstevel@tonic-gate 	while ((retv = ioctl(fd, cmd, arg)) == -1) {
2120Sstevel@tonic-gate 		if (errno != EINTR)
2130Sstevel@tonic-gate 			break;
2140Sstevel@tonic-gate 	}
2150Sstevel@tonic-gate 	return (retv);
2160Sstevel@tonic-gate }
2170Sstevel@tonic-gate 
2180Sstevel@tonic-gate /*
2190Sstevel@tonic-gate  * sys_check_options()
2200Sstevel@tonic-gate  *
2210Sstevel@tonic-gate  * Check the options that the user specified.
2220Sstevel@tonic-gate  */
2230Sstevel@tonic-gate int
sys_check_options(void)2240Sstevel@tonic-gate sys_check_options(void)
2250Sstevel@tonic-gate {
2260Sstevel@tonic-gate 	if (plumbed) {
2270Sstevel@tonic-gate 		if (req_unit == -1)
2280Sstevel@tonic-gate 			req_unit = -2;
2290Sstevel@tonic-gate 		ipmuxid = 0;
2300Sstevel@tonic-gate 		ip6muxid = 0;
2310Sstevel@tonic-gate 	}
2320Sstevel@tonic-gate 	return (1);
2330Sstevel@tonic-gate }
2340Sstevel@tonic-gate 
2350Sstevel@tonic-gate /*
2360Sstevel@tonic-gate  * sys_options()
2370Sstevel@tonic-gate  *
2380Sstevel@tonic-gate  * Add or remove system-specific options.
2390Sstevel@tonic-gate  */
2400Sstevel@tonic-gate void
sys_options(void)2410Sstevel@tonic-gate sys_options(void)
2420Sstevel@tonic-gate {
2430Sstevel@tonic-gate 	(void) remove_option("ktune");
2440Sstevel@tonic-gate 	(void) remove_option("noktune");
2450Sstevel@tonic-gate 	add_options(solaris_option_list);
2460Sstevel@tonic-gate }
2470Sstevel@tonic-gate 
2480Sstevel@tonic-gate /*
2490Sstevel@tonic-gate  * sys_ifname()
2500Sstevel@tonic-gate  *
2510Sstevel@tonic-gate  * Set ifname[] to contain name of IP interface for this unit.
2520Sstevel@tonic-gate  */
2530Sstevel@tonic-gate void
sys_ifname(void)2540Sstevel@tonic-gate sys_ifname(void)
2550Sstevel@tonic-gate {
2560Sstevel@tonic-gate 	const char *cp;
2570Sstevel@tonic-gate 
2580Sstevel@tonic-gate 	if ((cp = strrchr(drvnam, '/')) == NULL)
2590Sstevel@tonic-gate 		cp = drvnam;
2600Sstevel@tonic-gate 	else
2610Sstevel@tonic-gate 		cp++;
2620Sstevel@tonic-gate 	(void) slprintf(ifname, sizeof (ifname), "%s%d", cp, ifunit);
2630Sstevel@tonic-gate }
2640Sstevel@tonic-gate 
2650Sstevel@tonic-gate /*
2660Sstevel@tonic-gate  * ppp_available()
2670Sstevel@tonic-gate  *
2680Sstevel@tonic-gate  * Check whether the system has any ppp interfaces.
2690Sstevel@tonic-gate  */
2700Sstevel@tonic-gate int
ppp_available(void)2710Sstevel@tonic-gate ppp_available(void)
2720Sstevel@tonic-gate {
2730Sstevel@tonic-gate 	struct stat buf;
2740Sstevel@tonic-gate 	int fd;
2750Sstevel@tonic-gate 	uint32_t typ;
2760Sstevel@tonic-gate 
2770Sstevel@tonic-gate 	if (stat(PPP_DEV_NAME, &buf) >= 0)
2780Sstevel@tonic-gate 		return (1);
2790Sstevel@tonic-gate 
2800Sstevel@tonic-gate 	/*
2810Sstevel@tonic-gate 	 * Simple check for system using Apollo POS without SUNWpppd
2820Sstevel@tonic-gate 	 * (/dev/sppp) installed.  This is intentionally not kept open
2830Sstevel@tonic-gate 	 * here, since the user may not have the same privileges (as
2840Sstevel@tonic-gate 	 * determined later).  If Apollo were just shipped with the
2850Sstevel@tonic-gate 	 * full complement of packages, this wouldn't be an issue.
2860Sstevel@tonic-gate 	 */
2870Sstevel@tonic-gate 	if (devnam[0] == '\0' &&
2880Sstevel@tonic-gate 	    (fd = open(devnam, O_RDWR | O_NONBLOCK | O_NOCTTY)) >= 0) {
2890Sstevel@tonic-gate 		if (strioctl(fd, PPPIO_GTYPE, &typ, 0, sizeof (typ)) >= 0 &&
2900Sstevel@tonic-gate 		    typ == PPPTYP_MUX) {
2910Sstevel@tonic-gate 			(void) close(fd);
2920Sstevel@tonic-gate 			return (1);
2930Sstevel@tonic-gate 		}
2940Sstevel@tonic-gate 		(void) close(fd);
2950Sstevel@tonic-gate 	}
2960Sstevel@tonic-gate 	return (0);
2970Sstevel@tonic-gate }
2980Sstevel@tonic-gate 
2990Sstevel@tonic-gate static int
open_ipfd(void)3000Sstevel@tonic-gate open_ipfd(void)
3010Sstevel@tonic-gate {
3020Sstevel@tonic-gate 	ipfd = open(IP_DEV_NAME, O_RDWR | O_NONBLOCK, 0);
3030Sstevel@tonic-gate 	if (ipfd < 0) {
3040Sstevel@tonic-gate 		error("Couldn't open IP device (%s): %m", IP_DEV_NAME);
3050Sstevel@tonic-gate 	}
3060Sstevel@tonic-gate 	return (ipfd);
3070Sstevel@tonic-gate }
3080Sstevel@tonic-gate 
3090Sstevel@tonic-gate static int
read_ip_interface(int unit)3100Sstevel@tonic-gate read_ip_interface(int unit)
3110Sstevel@tonic-gate {
3120Sstevel@tonic-gate 	struct ifreq ifr;
3130Sstevel@tonic-gate 	struct sockaddr_in sin;
3140Sstevel@tonic-gate 
3150Sstevel@tonic-gate 	if (ipfd == -1 && open_ipfd() == -1)
3160Sstevel@tonic-gate 		return (0);
3170Sstevel@tonic-gate 
3180Sstevel@tonic-gate 	BZERO(&ifr, sizeof (ifr));
3190Sstevel@tonic-gate 	(void) strlcpy(ifr.ifr_name, ifname, sizeof (ifr.ifr_name));
3200Sstevel@tonic-gate 
3210Sstevel@tonic-gate 	/* Get the existing MTU */
3220Sstevel@tonic-gate 	if (myioctl(ipfd, SIOCGIFMTU, &ifr) < 0) {
3230Sstevel@tonic-gate 		warn("Couldn't get IP MTU on %s: %m", ifr.ifr_name);
3240Sstevel@tonic-gate 		return (0);
3250Sstevel@tonic-gate 	}
3260Sstevel@tonic-gate 	dbglog("got MTU %d from interface", ifr.ifr_metric);
3270Sstevel@tonic-gate 	if (ifr.ifr_metric != 0 &&
3280Sstevel@tonic-gate 	    (lcp_allowoptions[unit].mru == 0 ||
3296631Sss150715 	    lcp_allowoptions[unit].mru > ifr.ifr_metric))
3300Sstevel@tonic-gate 		lcp_allowoptions[unit].mru = ifr.ifr_metric;
3310Sstevel@tonic-gate 
3320Sstevel@tonic-gate 	/* Get the local IP address */
3330Sstevel@tonic-gate 	if (ipcp_wantoptions[unit].ouraddr == 0 ||
3340Sstevel@tonic-gate 	    ipcp_from_hostname) {
3350Sstevel@tonic-gate 		if (myioctl(ipfd, SIOCGIFADDR, &ifr) < 0) {
3360Sstevel@tonic-gate 			warn("Couldn't get local IP address (%s): %m",
3370Sstevel@tonic-gate 			    ifr.ifr_name);
3380Sstevel@tonic-gate 			return (0);
3390Sstevel@tonic-gate 		}
3400Sstevel@tonic-gate 		BCOPY(&ifr.ifr_addr, &sin, sizeof (struct sockaddr_in));
3410Sstevel@tonic-gate 		ipcp_wantoptions[unit].ouraddr = sin.sin_addr.s_addr;
3420Sstevel@tonic-gate 		dbglog("got local address %I from interface",
3430Sstevel@tonic-gate 		    ipcp_wantoptions[unit].ouraddr);
3440Sstevel@tonic-gate 	}
3450Sstevel@tonic-gate 
3460Sstevel@tonic-gate 	/* Get the remote IP address */
3470Sstevel@tonic-gate 	if (ipcp_wantoptions[unit].hisaddr == 0) {
3480Sstevel@tonic-gate 		if (myioctl(ipfd, SIOCGIFDSTADDR, &ifr) < 0) {
3490Sstevel@tonic-gate 			warn("Couldn't get remote IP address (%s): %m",
3500Sstevel@tonic-gate 			    ifr.ifr_name);
3510Sstevel@tonic-gate 			return (0);
3520Sstevel@tonic-gate 		}
3530Sstevel@tonic-gate 		BCOPY(&ifr.ifr_dstaddr, &sin, sizeof (struct sockaddr_in));
3540Sstevel@tonic-gate 		ipcp_wantoptions[unit].hisaddr = sin.sin_addr.s_addr;
3550Sstevel@tonic-gate 		dbglog("got remote address %I from interface",
3560Sstevel@tonic-gate 		    ipcp_wantoptions[unit].hisaddr);
3570Sstevel@tonic-gate 	}
3580Sstevel@tonic-gate 	return (1);
3590Sstevel@tonic-gate }
3600Sstevel@tonic-gate 
3610Sstevel@tonic-gate #ifdef INET6
3620Sstevel@tonic-gate static int
open_ip6fd(void)3630Sstevel@tonic-gate open_ip6fd(void)
3640Sstevel@tonic-gate {
3650Sstevel@tonic-gate 	ip6fd = open(IP6_DEV_NAME, O_RDWR | O_NONBLOCK, 0);
3660Sstevel@tonic-gate 	if (ip6fd < 0) {
3670Sstevel@tonic-gate 		error("Couldn't open IPv6 device (%s): %m", IP6_DEV_NAME);
3680Sstevel@tonic-gate 	}
3690Sstevel@tonic-gate 	return (ip6fd);
3700Sstevel@tonic-gate }
3710Sstevel@tonic-gate 
3720Sstevel@tonic-gate static int
read_ipv6_interface(int unit)3730Sstevel@tonic-gate read_ipv6_interface(int unit)
3740Sstevel@tonic-gate {
3750Sstevel@tonic-gate 	struct lifreq lifr;
3760Sstevel@tonic-gate 	struct sockaddr_in6 *sin6 = (struct sockaddr_in6 *)&lifr.lifr_addr;
3770Sstevel@tonic-gate 
3780Sstevel@tonic-gate 	if (ip6fd == -1 && open_ip6fd() == -1)
3790Sstevel@tonic-gate 		return (0);
3800Sstevel@tonic-gate 
3810Sstevel@tonic-gate 	BZERO(&lifr, sizeof (lifr));
3820Sstevel@tonic-gate 	(void) strlcpy(lifr.lifr_name, ifname, sizeof (lifr.lifr_name));
3830Sstevel@tonic-gate 
3840Sstevel@tonic-gate 	/* Get the existing MTU */
3850Sstevel@tonic-gate 	if (myioctl(ip6fd, SIOCGLIFMTU, &lifr) < 0) {
3860Sstevel@tonic-gate 		warn("Couldn't get IPv6 MTU on %s: %m", lifr.lifr_name);
3870Sstevel@tonic-gate 		return (0);
3880Sstevel@tonic-gate 	}
3890Sstevel@tonic-gate 	if (lifr.lifr_mtu != 0 &&
3900Sstevel@tonic-gate 	    (lcp_allowoptions[unit].mru == 0 ||
3916631Sss150715 	    lcp_allowoptions[unit].mru > lifr.lifr_mtu))
3920Sstevel@tonic-gate 		lcp_allowoptions[unit].mru = lifr.lifr_mtu;
3930Sstevel@tonic-gate 
3940Sstevel@tonic-gate 	/* Get the local IPv6 address */
3950Sstevel@tonic-gate 	if (eui64_iszero(ipv6cp_wantoptions[unit].ourid) ||
3960Sstevel@tonic-gate 	    (ipcp_from_hostname && ipv6cp_wantoptions[unit].use_ip)) {
3970Sstevel@tonic-gate 		if (myioctl(ip6fd, SIOCGLIFADDR, &lifr) < 0) {
3980Sstevel@tonic-gate 			warn("Couldn't get local IPv6 address (%s): %m",
3990Sstevel@tonic-gate 			    lifr.lifr_name);
4000Sstevel@tonic-gate 			return (0);
4010Sstevel@tonic-gate 		}
4020Sstevel@tonic-gate 		eui64_copy(sin6->sin6_addr.s6_addr32[2],
4030Sstevel@tonic-gate 		    ipv6cp_wantoptions[unit].ourid);
4040Sstevel@tonic-gate 	}
4050Sstevel@tonic-gate 
4060Sstevel@tonic-gate 	/* Get the remote IP address */
4070Sstevel@tonic-gate 	if (eui64_iszero(ipv6cp_wantoptions[unit].hisid)) {
4080Sstevel@tonic-gate 		if (myioctl(ip6fd, SIOCGLIFDSTADDR, &lifr) < 0) {
4090Sstevel@tonic-gate 			warn("Couldn't get remote IPv6 address (%s): %m",
4100Sstevel@tonic-gate 			    lifr.lifr_name);
4110Sstevel@tonic-gate 			return (0);
4120Sstevel@tonic-gate 		}
4130Sstevel@tonic-gate 		eui64_copy(sin6->sin6_addr.s6_addr32[2],
4140Sstevel@tonic-gate 		    ipv6cp_wantoptions[unit].hisid);
4150Sstevel@tonic-gate 	}
4160Sstevel@tonic-gate 	return (1);
4170Sstevel@tonic-gate }
4180Sstevel@tonic-gate #endif /* INET6 */
4190Sstevel@tonic-gate 
4200Sstevel@tonic-gate /*
4210Sstevel@tonic-gate  * Read information on existing interface(s) and configure ourselves
4220Sstevel@tonic-gate  * to negotiate appropriately.
4230Sstevel@tonic-gate  */
4240Sstevel@tonic-gate static void
read_interface(int unit)4250Sstevel@tonic-gate read_interface(int unit)
4260Sstevel@tonic-gate {
4270Sstevel@tonic-gate 	dbglog("reading existing interface data; %sip %sipv6",
4280Sstevel@tonic-gate 	    IPCP_ENABLED ? "" : "!",
4290Sstevel@tonic-gate #ifdef INET6
4300Sstevel@tonic-gate 	    IPV6CP_ENABLED ? "" :
4310Sstevel@tonic-gate #endif
4320Sstevel@tonic-gate 	    "!");
4330Sstevel@tonic-gate 	if (IPCP_ENABLED && !read_ip_interface(unit))
4340Sstevel@tonic-gate 		IPCP_ENABLED = 0;
4350Sstevel@tonic-gate #ifdef INET6
4360Sstevel@tonic-gate 	if (IPV6CP_ENABLED && !read_ipv6_interface(unit))
4370Sstevel@tonic-gate 		IPV6CP_ENABLED = 0;
4380Sstevel@tonic-gate #endif
4390Sstevel@tonic-gate }
4400Sstevel@tonic-gate 
4410Sstevel@tonic-gate /*
4420Sstevel@tonic-gate  * sys_init()
4430Sstevel@tonic-gate  *
4440Sstevel@tonic-gate  * System-dependent initialization.
4450Sstevel@tonic-gate  */
4460Sstevel@tonic-gate void
sys_init(bool open_as_user)4470Sstevel@tonic-gate sys_init(bool open_as_user)
4480Sstevel@tonic-gate {
4490Sstevel@tonic-gate 	uint32_t x;
4500Sstevel@tonic-gate 	uint32_t typ;
4510Sstevel@tonic-gate 
4520Sstevel@tonic-gate 	if (pppfd != -1) {
4530Sstevel@tonic-gate 		return;
4540Sstevel@tonic-gate 	}
4550Sstevel@tonic-gate 
4560Sstevel@tonic-gate 	if (!direct_tty && devnam[0] != '\0') {
4570Sstevel@tonic-gate 		/*
4580Sstevel@tonic-gate 		 * Check for integrated driver-like devices (such as
4590Sstevel@tonic-gate 		 * POS).  These identify themselves as "PPP
4600Sstevel@tonic-gate 		 * multiplexor" drivers.
4610Sstevel@tonic-gate 		 */
4620Sstevel@tonic-gate 		if (open_as_user)
4630Sstevel@tonic-gate 			(void) seteuid(getuid());
4640Sstevel@tonic-gate 		pppfd = open(devnam, O_RDWR | O_NONBLOCK);
4650Sstevel@tonic-gate 		if (open_as_user)
4660Sstevel@tonic-gate 			(void) seteuid(0);
4670Sstevel@tonic-gate 		if (pppfd >= 0 &&
4680Sstevel@tonic-gate 		    strioctl(pppfd, PPPIO_GTYPE, &typ, 0, sizeof (typ)) >= 0 &&
4690Sstevel@tonic-gate 		    typ == PPPTYP_MUX) {
4700Sstevel@tonic-gate 			integrated_driver = 1;
4710Sstevel@tonic-gate 			drvnam = devnam;
4720Sstevel@tonic-gate 		} else if (demand) {
4730Sstevel@tonic-gate 			(void) close(pppfd);
4740Sstevel@tonic-gate 			pppfd = -1;
4750Sstevel@tonic-gate 		} else {
4760Sstevel@tonic-gate 			extra_dev_fd = pppfd;
4770Sstevel@tonic-gate 			pppfd = -1;
4780Sstevel@tonic-gate 		}
4790Sstevel@tonic-gate 	}
4800Sstevel@tonic-gate 
4810Sstevel@tonic-gate 	/*
4820Sstevel@tonic-gate 	 * Open Solaris PPP device driver.
4830Sstevel@tonic-gate 	 */
4840Sstevel@tonic-gate 	if (pppfd < 0)
4850Sstevel@tonic-gate 		pppfd = open(drvnam, O_RDWR | O_NONBLOCK);
4860Sstevel@tonic-gate 	if (pppfd < 0) {
4870Sstevel@tonic-gate 		fatal("Can't open %s: %m", drvnam);
4880Sstevel@tonic-gate 	}
4890Sstevel@tonic-gate 	if (kdebugflag & 1) {
4900Sstevel@tonic-gate 		x = PPPDBG_LOG + PPPDBG_DRIVER;
4910Sstevel@tonic-gate 		if (strioctl(pppfd, PPPIO_DEBUG, &x, sizeof (x), 0) < 0) {
4920Sstevel@tonic-gate 			warn("PPPIO_DEBUG ioctl for mux failed: %m");
4930Sstevel@tonic-gate 		}
4940Sstevel@tonic-gate 	}
4950Sstevel@tonic-gate 	/*
4960Sstevel@tonic-gate 	 * Assign a new PPA and get its unit number.
4970Sstevel@tonic-gate 	 */
4980Sstevel@tonic-gate 	x = req_unit;
4990Sstevel@tonic-gate 	if (strioctl(pppfd, PPPIO_NEWPPA, &x, sizeof (x), sizeof (x)) < 0) {
5000Sstevel@tonic-gate 		if (errno == ENXIO && plumbed)
5010Sstevel@tonic-gate 			fatal("No idle interfaces available for use");
5020Sstevel@tonic-gate 		fatal("PPPIO_NEWPPA ioctl failed: %m");
5030Sstevel@tonic-gate 	}
5040Sstevel@tonic-gate 	ifunit = x;
5050Sstevel@tonic-gate 	if (req_unit >= 0 && ifunit != req_unit) {
5060Sstevel@tonic-gate 		if (plumbed)
5070Sstevel@tonic-gate 			fatal("unable to get requested unit %d", req_unit);
5080Sstevel@tonic-gate 		else
5090Sstevel@tonic-gate 			warn("unable to get requested unit %d", req_unit);
5100Sstevel@tonic-gate 	}
5110Sstevel@tonic-gate 	/*
5120Sstevel@tonic-gate 	 * Enable packet time-stamping when idle option is specified. Note
5130Sstevel@tonic-gate 	 * that we need to only do this on the control stream. Subsequent
5140Sstevel@tonic-gate 	 * streams attached to this control stream (ppa) will inherit
5150Sstevel@tonic-gate 	 * the time-stamp bit.
5160Sstevel@tonic-gate 	 */
5170Sstevel@tonic-gate 	if (idle_time_limit > 0) {
5180Sstevel@tonic-gate 		if (strioctl(pppfd, PPPIO_USETIMESTAMP, NULL, 0, 0) < 0) {
5190Sstevel@tonic-gate 			warn("PPPIO_USETIMESTAMP ioctl failed: %m");
5200Sstevel@tonic-gate 		}
5210Sstevel@tonic-gate 	}
5220Sstevel@tonic-gate 	if (plumbed) {
5230Sstevel@tonic-gate 		sys_ifname();
5240Sstevel@tonic-gate 		read_interface(0);
5250Sstevel@tonic-gate 	}
5260Sstevel@tonic-gate }
5270Sstevel@tonic-gate 
5280Sstevel@tonic-gate int
sys_extra_fd(void)5290Sstevel@tonic-gate sys_extra_fd(void)
5300Sstevel@tonic-gate {
5310Sstevel@tonic-gate 	int fd;
5320Sstevel@tonic-gate 
5330Sstevel@tonic-gate 	fd = extra_dev_fd;
5340Sstevel@tonic-gate 	extra_dev_fd = -1;
5350Sstevel@tonic-gate 	return (fd);
5360Sstevel@tonic-gate }
5370Sstevel@tonic-gate 
5380Sstevel@tonic-gate static int
open_udpfd(void)5390Sstevel@tonic-gate open_udpfd(void)
5400Sstevel@tonic-gate {
5410Sstevel@tonic-gate 	int udpfd;
5420Sstevel@tonic-gate 
5430Sstevel@tonic-gate 	udpfd = open(UDP_DEV_NAME, O_RDWR | O_NONBLOCK, 0);
5440Sstevel@tonic-gate 	if (udpfd < 0) {
5450Sstevel@tonic-gate 		error("Couldn't open UDP device (%s): %m", UDP_DEV_NAME);
5460Sstevel@tonic-gate 	}
5470Sstevel@tonic-gate 	return (udpfd);
5480Sstevel@tonic-gate }
5490Sstevel@tonic-gate 
5500Sstevel@tonic-gate /*
5510Sstevel@tonic-gate  * plumb_ipif()
5520Sstevel@tonic-gate  *
5530Sstevel@tonic-gate  * Perform IP interface plumbing.
5540Sstevel@tonic-gate  */
5550Sstevel@tonic-gate /*ARGSUSED*/
5560Sstevel@tonic-gate static int
plumb_ipif(int unit)5570Sstevel@tonic-gate plumb_ipif(int unit)
5580Sstevel@tonic-gate {
5590Sstevel@tonic-gate 	int udpfd = -1, tmpfd;
5600Sstevel@tonic-gate 	uint32_t x;
5610Sstevel@tonic-gate 	struct ifreq ifr;
5620Sstevel@tonic-gate 
5630Sstevel@tonic-gate 	if (!IPCP_ENABLED || (ifunit == -1) || (pppfd == -1)) {
5640Sstevel@tonic-gate 		return (0);
5650Sstevel@tonic-gate 	}
5660Sstevel@tonic-gate 	if (plumbed)
5670Sstevel@tonic-gate 		return (1);
5680Sstevel@tonic-gate 	if (ipfd == -1 && open_ipfd() == -1)
5690Sstevel@tonic-gate 		return (0);
5700Sstevel@tonic-gate 	if (use_plink && (udpfd = open_udpfd()) == -1)
5710Sstevel@tonic-gate 		return (0);
5720Sstevel@tonic-gate 	tmpfd = open(drvnam, O_RDWR | O_NONBLOCK, 0);
5730Sstevel@tonic-gate 	if (tmpfd < 0) {
5740Sstevel@tonic-gate 		error("Couldn't open PPP device (%s): %m", drvnam);
5750Sstevel@tonic-gate 		if (udpfd != -1)
5760Sstevel@tonic-gate 			(void) close(udpfd);
5770Sstevel@tonic-gate 		return (0);
5780Sstevel@tonic-gate 	}
5790Sstevel@tonic-gate 	if (kdebugflag & 1) {
5800Sstevel@tonic-gate 		x = PPPDBG_LOG + PPPDBG_DRIVER;
5810Sstevel@tonic-gate 		if (strioctl(tmpfd, PPPIO_DEBUG, &x, sizeof (x), 0) < 0) {
5820Sstevel@tonic-gate 			warn("PPPIO_DEBUG ioctl for mux failed: %m");
5830Sstevel@tonic-gate 		}
5840Sstevel@tonic-gate 	}
5850Sstevel@tonic-gate 	if (myioctl(tmpfd, I_PUSH, IP_MOD_NAME) < 0) {
5860Sstevel@tonic-gate 		error("Couldn't push IP module (%s): %m", IP_MOD_NAME);
5870Sstevel@tonic-gate 		goto err_ret;
5880Sstevel@tonic-gate 	}
5890Sstevel@tonic-gate 	/*
5900Sstevel@tonic-gate 	 * Assign ppa according to the unit number returned by ppp device
5910Sstevel@tonic-gate 	 * after plumbing is completed above.  Without setting the ppa, ip
5920Sstevel@tonic-gate 	 * module will return EINVAL upon setting the interface UP
5930Sstevel@tonic-gate 	 * (SIOCSxIFFLAGS).  This is because ip module in 2.8 expects two
5940Sstevel@tonic-gate 	 * DLPI_INFO_REQ to be sent down to the driver (below ip) before
5950Sstevel@tonic-gate 	 * IFF_UP bit can be set. Plumbing the device causes one DLPI_INFO_REQ
5960Sstevel@tonic-gate 	 * to be sent down, and the second DLPI_INFO_REQ is sent upon receiving
5970Sstevel@tonic-gate 	 * IF_UNITSEL (old) or SIOCSLIFNAME (new) ioctls. Such setting of the
5980Sstevel@tonic-gate 	 * ppa is required because the ppp DLPI provider advertises itself as
5990Sstevel@tonic-gate 	 * a DLPI style 2 type, which requires a point of attachment to be
6000Sstevel@tonic-gate 	 * specified. The only way the user can specify a point of attachment
6010Sstevel@tonic-gate 	 * is via SIOCSLIFNAME or IF_UNITSEL.  Such changes in the behavior of
6020Sstevel@tonic-gate 	 * ip module was made to meet new or evolving standards requirements.
6030Sstevel@tonic-gate 	 */
6040Sstevel@tonic-gate 	if (myioctl(tmpfd, IF_UNITSEL, &ifunit) < 0) {
6050Sstevel@tonic-gate 		error("Couldn't set ppa for unit %d: %m", ifunit);
6060Sstevel@tonic-gate 		goto err_ret;
6070Sstevel@tonic-gate 	}
6080Sstevel@tonic-gate 	if (use_plink) {
6090Sstevel@tonic-gate 		ipmuxid = myioctl(udpfd, I_PLINK, (void *)tmpfd);
6100Sstevel@tonic-gate 		if (ipmuxid < 0) {
6110Sstevel@tonic-gate 			error("Can't I_PLINK PPP device to IP: %m");
6120Sstevel@tonic-gate 			goto err_ret;
6130Sstevel@tonic-gate 		}
6140Sstevel@tonic-gate 	} else {
6150Sstevel@tonic-gate 		ipmuxid = myioctl(ipfd, I_LINK, (void *)tmpfd);
6160Sstevel@tonic-gate 		if (ipmuxid < 0) {
6170Sstevel@tonic-gate 			error("Can't I_LINK PPP device to IP: %m");
6180Sstevel@tonic-gate 			goto err_ret;
6190Sstevel@tonic-gate 		}
6200Sstevel@tonic-gate 	}
6210Sstevel@tonic-gate 	BZERO(&ifr, sizeof (ifr));
6220Sstevel@tonic-gate 	(void) strlcpy(ifr.ifr_name, ifname, sizeof (ifr.ifr_name));
6230Sstevel@tonic-gate 	ifr.ifr_ip_muxid = ipmuxid;
6240Sstevel@tonic-gate 	ifr.ifr_arp_muxid = -1;
6250Sstevel@tonic-gate 	if (myioctl(ipfd, SIOCSIFMUXID, (caddr_t)&ifr) < 0) {
6260Sstevel@tonic-gate 		error("Can't set mux ID SIOCSIFMUXID on %s: %m", ifname);
6270Sstevel@tonic-gate 		goto err_ret;
6280Sstevel@tonic-gate 	}
6290Sstevel@tonic-gate 	if (udpfd != -1)
6300Sstevel@tonic-gate 		(void) close(udpfd);
6310Sstevel@tonic-gate 	(void) close(tmpfd);
6320Sstevel@tonic-gate 	return (1);
6330Sstevel@tonic-gate err_ret:
6340Sstevel@tonic-gate 	if (udpfd != -1)
6350Sstevel@tonic-gate 		(void) close(udpfd);
6360Sstevel@tonic-gate 	(void) close(tmpfd);
6370Sstevel@tonic-gate 	return (0);
6380Sstevel@tonic-gate }
6390Sstevel@tonic-gate 
6400Sstevel@tonic-gate /*
6410Sstevel@tonic-gate  * unplumb_ipif()
6420Sstevel@tonic-gate  *
6430Sstevel@tonic-gate  * Perform IP interface unplumbing.  Possibly called from die(), so there
6440Sstevel@tonic-gate  * shouldn't be any call to die() or fatal() here.
6450Sstevel@tonic-gate  */
6460Sstevel@tonic-gate static int
unplumb_ipif(int unit)6470Sstevel@tonic-gate unplumb_ipif(int unit)
6480Sstevel@tonic-gate {
6490Sstevel@tonic-gate 	int udpfd = -1, fd = -1;
6500Sstevel@tonic-gate 	int id;
6510Sstevel@tonic-gate 	struct lifreq lifr;
6520Sstevel@tonic-gate 
6530Sstevel@tonic-gate 	if (!IPCP_ENABLED || (ifunit == -1)) {
6540Sstevel@tonic-gate 		return (0);
6550Sstevel@tonic-gate 	}
6560Sstevel@tonic-gate 	if (!plumbed && (ipmuxid == -1 || (ipfd == -1 && !use_plink)))
6570Sstevel@tonic-gate 		return (1);
6580Sstevel@tonic-gate 	id = ipmuxid;
6590Sstevel@tonic-gate 	if (!plumbed && use_plink) {
6600Sstevel@tonic-gate 		if ((udpfd = open_udpfd()) == -1)
6610Sstevel@tonic-gate 			return (0);
6620Sstevel@tonic-gate 		/*
6630Sstevel@tonic-gate 		 * Note: must re-get mux ID, since any intervening
6640Sstevel@tonic-gate 		 * ifconfigs will change this.
6650Sstevel@tonic-gate 		 */
6660Sstevel@tonic-gate 		BZERO(&lifr, sizeof (lifr));
6670Sstevel@tonic-gate 		(void) strlcpy(lifr.lifr_name, ifname,
6680Sstevel@tonic-gate 		    sizeof (lifr.lifr_name));
6690Sstevel@tonic-gate 		if (myioctl(ipfd, SIOCGLIFMUXID, (caddr_t)&lifr) < 0) {
6700Sstevel@tonic-gate 			warn("Can't get mux fd: SIOCGLIFMUXID: %m");
6710Sstevel@tonic-gate 		} else {
6720Sstevel@tonic-gate 			id = lifr.lifr_ip_muxid;
6730Sstevel@tonic-gate 			fd = myioctl(udpfd, _I_MUXID2FD, (void *)id);
6740Sstevel@tonic-gate 			if (fd < 0) {
6750Sstevel@tonic-gate 				warn("Can't get mux fd: _I_MUXID2FD: %m");
6760Sstevel@tonic-gate 			}
6770Sstevel@tonic-gate 		}
6780Sstevel@tonic-gate 	}
6790Sstevel@tonic-gate 	/*
6800Sstevel@tonic-gate 	 * Mark down and unlink the ip interface.
6810Sstevel@tonic-gate 	 */
6820Sstevel@tonic-gate 	(void) sifdown(unit);
6830Sstevel@tonic-gate 	if (default_route_gateway != 0) {
6840Sstevel@tonic-gate 		(void) cifdefaultroute(0, default_route_gateway,
6850Sstevel@tonic-gate 		    default_route_gateway);
6860Sstevel@tonic-gate 	}
6870Sstevel@tonic-gate 	if (proxy_arp_addr != 0) {
6880Sstevel@tonic-gate 		(void) cifproxyarp(0, proxy_arp_addr);
6890Sstevel@tonic-gate 	}
6900Sstevel@tonic-gate 	ipmuxid = -1;
6910Sstevel@tonic-gate 	if (plumbed)
6920Sstevel@tonic-gate 		return (1);
6930Sstevel@tonic-gate 	if (use_plink) {
6940Sstevel@tonic-gate 		if (myioctl(udpfd, I_PUNLINK, (void *)id) < 0) {
6950Sstevel@tonic-gate 			error("Can't I_PUNLINK PPP from IP: %m");
6960Sstevel@tonic-gate 			if (fd != -1)
6970Sstevel@tonic-gate 				(void) close(fd);
6980Sstevel@tonic-gate 			(void) close(udpfd);
6990Sstevel@tonic-gate 			return (0);
7000Sstevel@tonic-gate 		}
7010Sstevel@tonic-gate 		if (fd != -1)
7020Sstevel@tonic-gate 			(void) close(fd);
7030Sstevel@tonic-gate 		(void) close(udpfd);
7040Sstevel@tonic-gate 	} else {
7050Sstevel@tonic-gate 		if (myioctl(ipfd, I_UNLINK, (void *)id) < 0) {
7060Sstevel@tonic-gate 			error("Can't I_UNLINK PPP from IP: %m");
7070Sstevel@tonic-gate 			return (0);
7080Sstevel@tonic-gate 		}
7090Sstevel@tonic-gate 	}
7100Sstevel@tonic-gate 	return (1);
7110Sstevel@tonic-gate }
7120Sstevel@tonic-gate 
7130Sstevel@tonic-gate /*
7140Sstevel@tonic-gate  * sys_cleanup()
7150Sstevel@tonic-gate  *
7160Sstevel@tonic-gate  * Restore any system state we modified before exiting: mark the
7170Sstevel@tonic-gate  * interface down, delete default route and/or proxy arp entry. This
7180Sstevel@tonic-gate  * should not call die() because it's called from die().
7190Sstevel@tonic-gate  */
7200Sstevel@tonic-gate void
sys_cleanup()7210Sstevel@tonic-gate sys_cleanup()
7220Sstevel@tonic-gate {
7230Sstevel@tonic-gate 	(void) unplumb_ipif(0);
7240Sstevel@tonic-gate #ifdef INET6
7250Sstevel@tonic-gate 	(void) unplumb_ip6if(0);
7260Sstevel@tonic-gate #endif /* INET6 */
7270Sstevel@tonic-gate }
7280Sstevel@tonic-gate 
7290Sstevel@tonic-gate /*
7300Sstevel@tonic-gate  * get_first_hwaddr()
7310Sstevel@tonic-gate  *
7320Sstevel@tonic-gate  * Stores the first hardware interface address found in the system
7330Sstevel@tonic-gate  * into addr and return 1 upon success, or 0 if none is found.  This
7340Sstevel@tonic-gate  * is also called from the multilink code.
7350Sstevel@tonic-gate  */
7360Sstevel@tonic-gate int
get_first_hwaddr(addr,msize)7370Sstevel@tonic-gate get_first_hwaddr(addr, msize)
7380Sstevel@tonic-gate 	uchar_t *addr;
7390Sstevel@tonic-gate 	int msize;
7400Sstevel@tonic-gate {
7410Sstevel@tonic-gate 	struct ifconf ifc;
7420Sstevel@tonic-gate 	register struct ifreq *pifreq;
7430Sstevel@tonic-gate 	struct ifreq ifr;
7440Sstevel@tonic-gate 	int fd, num_ifs, i;
7450Sstevel@tonic-gate 	uint_t fl, req_size;
7460Sstevel@tonic-gate 	char *req;
7470Sstevel@tonic-gate 	boolean_t found;
7480Sstevel@tonic-gate 
7490Sstevel@tonic-gate 	if (addr == NULL) {
7500Sstevel@tonic-gate 		return (0);
7510Sstevel@tonic-gate 	}
7520Sstevel@tonic-gate 	fd = socket(AF_INET, SOCK_DGRAM, 0);
7530Sstevel@tonic-gate 	if (fd < 0) {
7540Sstevel@tonic-gate 		error("get_first_hwaddr: error opening IP socket: %m");
7550Sstevel@tonic-gate 		return (0);
7560Sstevel@tonic-gate 	}
7570Sstevel@tonic-gate 	/*
7580Sstevel@tonic-gate 	 * Find out how many interfaces are running
7590Sstevel@tonic-gate 	 */
7600Sstevel@tonic-gate 	if (myioctl(fd, SIOCGIFNUM, (caddr_t)&num_ifs) < 0) {
7610Sstevel@tonic-gate 		num_ifs = MAXIFS;
7620Sstevel@tonic-gate 	}
7630Sstevel@tonic-gate 	req_size = num_ifs * sizeof (struct ifreq);
7640Sstevel@tonic-gate 	req = malloc(req_size);
7650Sstevel@tonic-gate 	if (req == NULL) {
7660Sstevel@tonic-gate 		novm("interface request structure.");
7670Sstevel@tonic-gate 	}
7680Sstevel@tonic-gate 	/*
7690Sstevel@tonic-gate 	 * Get interface configuration info for all interfaces
7700Sstevel@tonic-gate 	 */
7710Sstevel@tonic-gate 	ifc.ifc_len = req_size;
7720Sstevel@tonic-gate 	ifc.ifc_buf = req;
7730Sstevel@tonic-gate 	if (myioctl(fd, SIOCGIFCONF, &ifc) < 0) {
7740Sstevel@tonic-gate 		error("SIOCGIFCONF: %m");
7750Sstevel@tonic-gate 		(void) close(fd);
7760Sstevel@tonic-gate 		free(req);
7770Sstevel@tonic-gate 		return (0);
7780Sstevel@tonic-gate 	}
7790Sstevel@tonic-gate 	/*
7800Sstevel@tonic-gate 	 * And traverse each interface to look specifically for the first
7810Sstevel@tonic-gate 	 * occurence of an Ethernet interface which has been marked up
7820Sstevel@tonic-gate 	 */
7830Sstevel@tonic-gate 	pifreq = ifc.ifc_req;
7840Sstevel@tonic-gate 	found = 0;
7850Sstevel@tonic-gate 	for (i = ifc.ifc_len / sizeof (struct ifreq); i > 0; i--, pifreq++) {
7860Sstevel@tonic-gate 
7870Sstevel@tonic-gate 		if (strchr(pifreq->ifr_name, ':') != NULL) {
7880Sstevel@tonic-gate 			continue;
7890Sstevel@tonic-gate 		}
7900Sstevel@tonic-gate 		BZERO(&ifr, sizeof (ifr));
7910Sstevel@tonic-gate 		(void) strncpy(ifr.ifr_name, pifreq->ifr_name,
7920Sstevel@tonic-gate 		    sizeof (ifr.ifr_name));
7930Sstevel@tonic-gate 		if (myioctl(fd, SIOCGIFFLAGS, &ifr) < 0) {
7940Sstevel@tonic-gate 			continue;
7950Sstevel@tonic-gate 		}
7960Sstevel@tonic-gate 		fl = ifr.ifr_flags;
7970Sstevel@tonic-gate 		if ((fl & (IFF_UP|IFF_BROADCAST|IFF_POINTOPOINT|IFF_LOOPBACK))
7980Sstevel@tonic-gate 		    != (IFF_UP | IFF_BROADCAST)) {
7990Sstevel@tonic-gate 			continue;
8000Sstevel@tonic-gate 		}
8010Sstevel@tonic-gate 		if (get_if_hwaddr(addr, msize, ifr.ifr_name) <= 0) {
8020Sstevel@tonic-gate 			continue;
8030Sstevel@tonic-gate 		}
8040Sstevel@tonic-gate 		found = 1;
8050Sstevel@tonic-gate 		break;
8060Sstevel@tonic-gate 	}
8070Sstevel@tonic-gate 	free(req);
8080Sstevel@tonic-gate 	(void) close(fd);
8090Sstevel@tonic-gate 
8100Sstevel@tonic-gate 	return (found);
8110Sstevel@tonic-gate }
8120Sstevel@tonic-gate 
8130Sstevel@tonic-gate /*
8140Sstevel@tonic-gate  * get_if_hwaddr()
8150Sstevel@tonic-gate  *
8160Sstevel@tonic-gate  * Get the hardware address for the specified network interface device.
8170Sstevel@tonic-gate  * Return the length of the MAC address (in bytes) or -1 if error.
8180Sstevel@tonic-gate  */
8190Sstevel@tonic-gate int
get_if_hwaddr(uchar_t * addrp,int msize,char * linkname)8206631Sss150715 get_if_hwaddr(uchar_t *addrp, int msize, char *linkname)
8210Sstevel@tonic-gate {
8226631Sss150715 	dlpi_handle_t dh;
8236631Sss150715 	uchar_t physaddr[DLPI_PHYSADDR_MAX];
8246631Sss150715 	size_t physaddrlen = sizeof (physaddr);
8256631Sss150715 	int retv;
8260Sstevel@tonic-gate 
8276631Sss150715 	if ((addrp == NULL) || (linkname == NULL))
8280Sstevel@tonic-gate 		return (-1);
8296631Sss150715 
8300Sstevel@tonic-gate 	/*
8316631Sss150715 	 * Open the link and ask for hardware address.
8320Sstevel@tonic-gate 	 */
8336631Sss150715 	if ((retv = dlpi_open(linkname, &dh, 0)) != DLPI_SUCCESS) {
8346631Sss150715 		error("Could not open %s: %s", linkname, dlpi_strerror(retv));
8350Sstevel@tonic-gate 		return (-1);
8360Sstevel@tonic-gate 	}
8370Sstevel@tonic-gate 
8386631Sss150715 	retv = dlpi_get_physaddr(dh, DL_CURR_PHYS_ADDR,
8396631Sss150715 	    physaddr, &physaddrlen);
8406631Sss150715 	dlpi_close(dh);
8416631Sss150715 	if (retv != DLPI_SUCCESS) {
8426631Sss150715 		error("Could not get physical address on %s: %s", linkname,
8436631Sss150715 		    dlpi_strerror(retv));
8440Sstevel@tonic-gate 		return (-1);
8450Sstevel@tonic-gate 	}
8460Sstevel@tonic-gate 
8470Sstevel@tonic-gate 	/*
8480Sstevel@tonic-gate 	 * Check if we have enough space to copy the address to.
8490Sstevel@tonic-gate 	 */
8506631Sss150715 	if (physaddrlen > msize)
8510Sstevel@tonic-gate 		return (-1);
8526631Sss150715 	(void) memcpy(addrp, physaddr, physaddrlen);
8536631Sss150715 	return (physaddrlen);
8540Sstevel@tonic-gate }
8550Sstevel@tonic-gate 
8560Sstevel@tonic-gate /*
8570Sstevel@tonic-gate  * giflags()
8580Sstevel@tonic-gate  */
8590Sstevel@tonic-gate static int
giflags(u_int32_t flag,bool * retval)8600Sstevel@tonic-gate giflags(u_int32_t flag, bool *retval)
8610Sstevel@tonic-gate {
8620Sstevel@tonic-gate 	struct ifreq ifr;
8630Sstevel@tonic-gate 	int fd;
8640Sstevel@tonic-gate 
8650Sstevel@tonic-gate 	*retval = 0;
8660Sstevel@tonic-gate 	fd = socket(AF_INET, SOCK_DGRAM, 0);
8670Sstevel@tonic-gate 	if (fd < 0) {
8680Sstevel@tonic-gate 		error("giflags: error opening IP socket: %m");
8690Sstevel@tonic-gate 		return (errno);
8700Sstevel@tonic-gate 	}
8710Sstevel@tonic-gate 
8720Sstevel@tonic-gate 	BZERO(&ifr, sizeof (ifr));
8730Sstevel@tonic-gate 	(void) strncpy(ifr.ifr_name, ifname, sizeof (ifr.ifr_name));
8740Sstevel@tonic-gate 	if (ioctl(fd, SIOCGIFFLAGS, &ifr) < 0) {
8750Sstevel@tonic-gate 		(void) close(fd);
8760Sstevel@tonic-gate 		return (errno);
8770Sstevel@tonic-gate 	}
8780Sstevel@tonic-gate 
8790Sstevel@tonic-gate 	*retval = ((ifr.ifr_flags & flag) != 0);
8800Sstevel@tonic-gate 	(void) close(fd);
8810Sstevel@tonic-gate 	return (errno);
8820Sstevel@tonic-gate }
8830Sstevel@tonic-gate 
8840Sstevel@tonic-gate /*
8850Sstevel@tonic-gate  * sys_close()
8860Sstevel@tonic-gate  *
8870Sstevel@tonic-gate  * Clean up in a child process before exec-ing.
8880Sstevel@tonic-gate  */
8890Sstevel@tonic-gate void
sys_close()8900Sstevel@tonic-gate sys_close()
8910Sstevel@tonic-gate {
8920Sstevel@tonic-gate 	if (ipfd != -1) {
8930Sstevel@tonic-gate 		(void) close(ipfd);
8940Sstevel@tonic-gate 		ipfd = -1;
8950Sstevel@tonic-gate 	}
8960Sstevel@tonic-gate #ifdef INET6
8970Sstevel@tonic-gate 	if (ip6fd != -1) {
8980Sstevel@tonic-gate 		(void) close(ip6fd);
8990Sstevel@tonic-gate 		ip6fd = -1;
9000Sstevel@tonic-gate 	}
9010Sstevel@tonic-gate #endif /* INET6 */
9020Sstevel@tonic-gate 	if (pppfd != -1) {
9030Sstevel@tonic-gate 		(void) close(pppfd);
9040Sstevel@tonic-gate 		pppfd = -1;
9050Sstevel@tonic-gate 	}
9060Sstevel@tonic-gate }
9070Sstevel@tonic-gate 
9080Sstevel@tonic-gate /*
9090Sstevel@tonic-gate  * any_compressions()
9100Sstevel@tonic-gate  *
9110Sstevel@tonic-gate  * Check if compression is enabled or not.  In the STREAMS implementation of
9120Sstevel@tonic-gate  * kernel-portion pppd, the comp STREAMS module performs the ACFC, PFC, as
9130Sstevel@tonic-gate  * well CCP and VJ compressions. However, if the user has explicitly declare
9140Sstevel@tonic-gate  * to not enable them from the command line, there is no point of having the
9150Sstevel@tonic-gate  * comp module be pushed on the stream.
9160Sstevel@tonic-gate  */
9170Sstevel@tonic-gate static int
any_compressions(void)9180Sstevel@tonic-gate any_compressions(void)
9190Sstevel@tonic-gate {
9200Sstevel@tonic-gate 	if ((!lcp_wantoptions[0].neg_accompression) &&
9210Sstevel@tonic-gate 	    (!lcp_wantoptions[0].neg_pcompression) &&
9220Sstevel@tonic-gate 	    (!ccp_protent.enabled_flag) &&
9230Sstevel@tonic-gate 	    (!ipcp_wantoptions[0].neg_vj)) {
9240Sstevel@tonic-gate 		return (0);
9250Sstevel@tonic-gate 	}
9260Sstevel@tonic-gate 	return (1);
9270Sstevel@tonic-gate }
9280Sstevel@tonic-gate 
9290Sstevel@tonic-gate /*
9300Sstevel@tonic-gate  * modpush()
9310Sstevel@tonic-gate  *
9320Sstevel@tonic-gate  * Push a module on the stream.
9330Sstevel@tonic-gate  */
9340Sstevel@tonic-gate static int
modpush(int fd,const char * modname,const char * text)9350Sstevel@tonic-gate modpush(int fd, const char *modname, const char *text)
9360Sstevel@tonic-gate {
9370Sstevel@tonic-gate 	if (myioctl(fd, I_PUSH, (void *)modname) < 0) {
9380Sstevel@tonic-gate 		error("Couldn't push %s module: %m", text);
9390Sstevel@tonic-gate 		return (-1);
9400Sstevel@tonic-gate 	}
9410Sstevel@tonic-gate 	if (++tty_npushed == 1 && !already_ppp) {
9420Sstevel@tonic-gate 		if (strioctl(fd, PPPIO_LASTMOD, NULL, 0, 0) < 0) {
9430Sstevel@tonic-gate 			warn("unable to set LASTMOD on %s: %m", text);
9440Sstevel@tonic-gate 		}
9450Sstevel@tonic-gate 	}
9460Sstevel@tonic-gate 	return (0);
9470Sstevel@tonic-gate }
9480Sstevel@tonic-gate 
9490Sstevel@tonic-gate /*
9500Sstevel@tonic-gate  * establish_ppp()
9510Sstevel@tonic-gate  *
9520Sstevel@tonic-gate  * Turn the serial port into a ppp interface.
9530Sstevel@tonic-gate  */
9540Sstevel@tonic-gate int
establish_ppp(fd)9550Sstevel@tonic-gate establish_ppp(fd)
9560Sstevel@tonic-gate 	int fd;
9570Sstevel@tonic-gate {
9580Sstevel@tonic-gate 	int i;
9590Sstevel@tonic-gate 	uint32_t x;
9600Sstevel@tonic-gate 
9610Sstevel@tonic-gate 	if (default_device && !notty) {
9620Sstevel@tonic-gate 		tty_sid = getsid((pid_t)0);
9630Sstevel@tonic-gate 	}
9640Sstevel@tonic-gate 
9650Sstevel@tonic-gate 	if (integrated_driver)
9660Sstevel@tonic-gate 		return (pppfd);
9670Sstevel@tonic-gate 
9680Sstevel@tonic-gate 	/*
9690Sstevel@tonic-gate 	 * Pop any existing modules off the tty stream
9700Sstevel@tonic-gate 	 */
9710Sstevel@tonic-gate 	for (i = 0; ; ++i) {
9720Sstevel@tonic-gate 		if ((myioctl(fd, I_LOOK, tty_modules[i]) < 0) ||
9730Sstevel@tonic-gate 		    (strcmp(tty_modules[i], "ptem") == 0) ||
9740Sstevel@tonic-gate 		    (myioctl(fd, I_POP, (void *)0) < 0)) {
9750Sstevel@tonic-gate 			break;
9760Sstevel@tonic-gate 		}
9770Sstevel@tonic-gate 	}
9780Sstevel@tonic-gate 	tty_nmodules = i;
9790Sstevel@tonic-gate 	/*
9800Sstevel@tonic-gate 	 * Push the async hdlc module and the compressor module
9810Sstevel@tonic-gate 	 */
9820Sstevel@tonic-gate 	tty_npushed = 0;
9830Sstevel@tonic-gate 	if (!sync_serial && !already_ppp &&
9840Sstevel@tonic-gate 	    modpush(fd, AHDLC_MOD_NAME, "PPP async HDLC") < 0) {
9850Sstevel@tonic-gate 		return (-1);
9860Sstevel@tonic-gate 	}
9870Sstevel@tonic-gate 	/*
9880Sstevel@tonic-gate 	 * There's no need to push comp module if we don't intend
9890Sstevel@tonic-gate 	 * to compress anything
9900Sstevel@tonic-gate 	 */
9910Sstevel@tonic-gate 	if (any_compressions()) {
9920Sstevel@tonic-gate 		(void) modpush(fd, COMP_MOD_NAME, "PPP compression");
9930Sstevel@tonic-gate 	}
9940Sstevel@tonic-gate 
9950Sstevel@tonic-gate 	/*
9960Sstevel@tonic-gate 	 * Link the serial port under the PPP multiplexor
9970Sstevel@tonic-gate 	 */
9980Sstevel@tonic-gate 	if ((fdmuxid = myioctl(pppfd, I_LINK, (void *)fd)) < 0) {
9990Sstevel@tonic-gate 		error("Can't link tty to PPP mux: %m");
10000Sstevel@tonic-gate 		return (-1);
10010Sstevel@tonic-gate 	}
10020Sstevel@tonic-gate 	if (tty_npushed == 0 && !already_ppp) {
10030Sstevel@tonic-gate 		if (strioctl(pppfd, PPPIO_LASTMOD, NULL, 0, 0) < 0) {
10040Sstevel@tonic-gate 			warn("unable to set LASTMOD on PPP mux: %m");
10050Sstevel@tonic-gate 		}
10060Sstevel@tonic-gate 	}
10070Sstevel@tonic-gate 	/*
10080Sstevel@tonic-gate 	 * Debug configuration must occur *after* I_LINK.
10090Sstevel@tonic-gate 	 */
10100Sstevel@tonic-gate 	if (kdebugflag & 4) {
10110Sstevel@tonic-gate 		x = PPPDBG_LOG + PPPDBG_AHDLC;
10120Sstevel@tonic-gate 		if (strioctl(pppfd, PPPIO_DEBUG, &x, sizeof (x), 0) < 0) {
10130Sstevel@tonic-gate 			warn("PPPIO_DEBUG ioctl for ahdlc module failed: %m");
10140Sstevel@tonic-gate 		}
10150Sstevel@tonic-gate 	}
10160Sstevel@tonic-gate 	if (any_compressions() && (kdebugflag & 2)) {
10170Sstevel@tonic-gate 		x = PPPDBG_LOG + PPPDBG_COMP;
10180Sstevel@tonic-gate 		if (strioctl(pppfd, PPPIO_DEBUG, &x, sizeof (x), 0) < 0) {
10190Sstevel@tonic-gate 			warn("PPPIO_DEBUG ioctl for comp module failed: %m");
10200Sstevel@tonic-gate 		}
10210Sstevel@tonic-gate 	}
10220Sstevel@tonic-gate 	return (pppfd);
10230Sstevel@tonic-gate }
10240Sstevel@tonic-gate 
10250Sstevel@tonic-gate /*
10260Sstevel@tonic-gate  * restore_loop()
10270Sstevel@tonic-gate  *
10280Sstevel@tonic-gate  * Reattach the ppp unit to the loopback. This doesn't need to do anything
10290Sstevel@tonic-gate  * because disestablish_ppp does it
10300Sstevel@tonic-gate  */
10310Sstevel@tonic-gate void
restore_loop()10320Sstevel@tonic-gate restore_loop()
10330Sstevel@tonic-gate {
10340Sstevel@tonic-gate }
10350Sstevel@tonic-gate 
10360Sstevel@tonic-gate /*
10370Sstevel@tonic-gate  * disestablish_ppp()
10380Sstevel@tonic-gate  *
10390Sstevel@tonic-gate  * Restore the serial port to normal operation.  It attempts to reconstruct
10400Sstevel@tonic-gate  * the stream with the previously popped modules.  This shouldn't call die()
10410Sstevel@tonic-gate  * because it's called from die().  Stream reconstruction is needed in case
10420Sstevel@tonic-gate  * pppd is used for dial-in on /dev/tty and there's an option error.
10430Sstevel@tonic-gate  */
10440Sstevel@tonic-gate void
disestablish_ppp(fd)10450Sstevel@tonic-gate disestablish_ppp(fd)
10460Sstevel@tonic-gate 	int fd;
10470Sstevel@tonic-gate {
10480Sstevel@tonic-gate 	int i;
10490Sstevel@tonic-gate 
10500Sstevel@tonic-gate 	if (fdmuxid == -1 || integrated_driver) {
10510Sstevel@tonic-gate 		return;
10520Sstevel@tonic-gate 	}
10530Sstevel@tonic-gate 	if (myioctl(pppfd, I_UNLINK, (void *)fdmuxid) < 0) {
10540Sstevel@tonic-gate 		if (!hungup) {
10550Sstevel@tonic-gate 			error("Can't unlink tty from PPP mux: %m");
10560Sstevel@tonic-gate 		}
10570Sstevel@tonic-gate 	}
10580Sstevel@tonic-gate 	fdmuxid = -1;
10590Sstevel@tonic-gate 	if (!hungup) {
10600Sstevel@tonic-gate 		while (tty_npushed > 0 && myioctl(fd, I_POP, (void *)0) >= 0) {
10610Sstevel@tonic-gate 			--tty_npushed;
10620Sstevel@tonic-gate 		}
10630Sstevel@tonic-gate 		for (i = tty_nmodules - 1; i >= 0; --i) {
10640Sstevel@tonic-gate 			if (myioctl(fd, I_PUSH, tty_modules[i]) < 0) {
10650Sstevel@tonic-gate 				error("Couldn't restore tty module %s: %m",
10660Sstevel@tonic-gate 				    tty_modules[i]);
10670Sstevel@tonic-gate 			}
10680Sstevel@tonic-gate 		}
10690Sstevel@tonic-gate 	}
10700Sstevel@tonic-gate 	if (hungup && default_device && tty_sid > 0) {
10710Sstevel@tonic-gate 		/*
10720Sstevel@tonic-gate 		 * If we have received a hangup, we need to send a
10730Sstevel@tonic-gate 		 * SIGHUP to the terminal's controlling process.
10740Sstevel@tonic-gate 		 * The reason is that the original stream head for
10750Sstevel@tonic-gate 		 * the terminal hasn't seen the M_HANGUP message
10760Sstevel@tonic-gate 		 * (it went up through the ppp driver to the stream
10770Sstevel@tonic-gate 		 * head for our fd to /dev/ppp).
10780Sstevel@tonic-gate 		 */
10790Sstevel@tonic-gate 		(void) kill(tty_sid, SIGHUP);
10800Sstevel@tonic-gate 	}
10810Sstevel@tonic-gate }
10820Sstevel@tonic-gate 
10830Sstevel@tonic-gate /*
10840Sstevel@tonic-gate  * clean_check()
10850Sstevel@tonic-gate  *
10860Sstevel@tonic-gate  * Check whether the link seems not to be 8-bit clean
10870Sstevel@tonic-gate  */
10880Sstevel@tonic-gate void
clean_check()10890Sstevel@tonic-gate clean_check()
10900Sstevel@tonic-gate {
10910Sstevel@tonic-gate 	uint32_t x;
10920Sstevel@tonic-gate 	char *s = NULL;
10930Sstevel@tonic-gate 
10940Sstevel@tonic-gate 	/*
10950Sstevel@tonic-gate 	 * Skip this is synchronous link is used, since spppasyn won't
10960Sstevel@tonic-gate 	 * be anywhere in the stream below to handle the ioctl.
10970Sstevel@tonic-gate 	 */
10980Sstevel@tonic-gate 	if (sync_serial) {
10990Sstevel@tonic-gate 		return;
11000Sstevel@tonic-gate 	}
11010Sstevel@tonic-gate 
11020Sstevel@tonic-gate 	if (strioctl(pppfd, PPPIO_GCLEAN, &x, 0, sizeof (x)) < 0) {
11030Sstevel@tonic-gate 		warn("unable to obtain serial link status: %m");
11040Sstevel@tonic-gate 		return;
11050Sstevel@tonic-gate 	}
11060Sstevel@tonic-gate 	switch (~x) {
11070Sstevel@tonic-gate 	case RCV_B7_0:
11080Sstevel@tonic-gate 		s = "bit 7 set to 1";
11090Sstevel@tonic-gate 		break;
11100Sstevel@tonic-gate 	case RCV_B7_1:
11110Sstevel@tonic-gate 		s = "bit 7 set to 0";
11120Sstevel@tonic-gate 		break;
11130Sstevel@tonic-gate 	case RCV_EVNP:
11140Sstevel@tonic-gate 		s = "odd parity";
11150Sstevel@tonic-gate 		break;
11160Sstevel@tonic-gate 	case RCV_ODDP:
11170Sstevel@tonic-gate 		s = "even parity";
11180Sstevel@tonic-gate 		break;
11190Sstevel@tonic-gate 	}
11200Sstevel@tonic-gate 	if (s != NULL) {
11210Sstevel@tonic-gate 		warn("Serial link is not 8-bit clean:");
11220Sstevel@tonic-gate 		warn("All received characters had %s", s);
11230Sstevel@tonic-gate 	}
11240Sstevel@tonic-gate }
11250Sstevel@tonic-gate 
11260Sstevel@tonic-gate /*
11270Sstevel@tonic-gate  * List of valid speeds.
11280Sstevel@tonic-gate  */
11290Sstevel@tonic-gate struct speed {
11300Sstevel@tonic-gate 	int speed_int;
11310Sstevel@tonic-gate 	int speed_val;
11320Sstevel@tonic-gate } speeds [] = {
11330Sstevel@tonic-gate #ifdef B50
11340Sstevel@tonic-gate 	{ 50, B50 },
11350Sstevel@tonic-gate #endif
11360Sstevel@tonic-gate #ifdef B75
11370Sstevel@tonic-gate 	{ 75, B75 },
11380Sstevel@tonic-gate #endif
11390Sstevel@tonic-gate #ifdef B110
11400Sstevel@tonic-gate 	{ 110, B110 },
11410Sstevel@tonic-gate #endif
11420Sstevel@tonic-gate #ifdef B134
11430Sstevel@tonic-gate 	{ 134, B134 },
11440Sstevel@tonic-gate #endif
11450Sstevel@tonic-gate #ifdef B150
11460Sstevel@tonic-gate 	{ 150, B150 },
11470Sstevel@tonic-gate #endif
11480Sstevel@tonic-gate #ifdef B200
11490Sstevel@tonic-gate 	{ 200, B200 },
11500Sstevel@tonic-gate #endif
11510Sstevel@tonic-gate #ifdef B300
11520Sstevel@tonic-gate 	{ 300, B300 },
11530Sstevel@tonic-gate #endif
11540Sstevel@tonic-gate #ifdef B600
11550Sstevel@tonic-gate 	{ 600, B600 },
11560Sstevel@tonic-gate #endif
11570Sstevel@tonic-gate #ifdef B1200
11580Sstevel@tonic-gate 	{ 1200, B1200 },
11590Sstevel@tonic-gate #endif
11600Sstevel@tonic-gate #ifdef B1800
11610Sstevel@tonic-gate 	{ 1800, B1800 },
11620Sstevel@tonic-gate #endif
11630Sstevel@tonic-gate #ifdef B2000
11640Sstevel@tonic-gate 	{ 2000, B2000 },
11650Sstevel@tonic-gate #endif
11660Sstevel@tonic-gate #ifdef B2400
11670Sstevel@tonic-gate 	{ 2400, B2400 },
11680Sstevel@tonic-gate #endif
11690Sstevel@tonic-gate #ifdef B3600
11700Sstevel@tonic-gate 	{ 3600, B3600 },
11710Sstevel@tonic-gate #endif
11720Sstevel@tonic-gate #ifdef B4800
11730Sstevel@tonic-gate 	{ 4800, B4800 },
11740Sstevel@tonic-gate #endif
11750Sstevel@tonic-gate #ifdef B7200
11760Sstevel@tonic-gate 	{ 7200, B7200 },
11770Sstevel@tonic-gate #endif
11780Sstevel@tonic-gate #ifdef B9600
11790Sstevel@tonic-gate 	{ 9600, B9600 },
11800Sstevel@tonic-gate #endif
11810Sstevel@tonic-gate #ifdef B19200
11820Sstevel@tonic-gate 	{ 19200, B19200 },
11830Sstevel@tonic-gate #endif
11840Sstevel@tonic-gate #ifdef B38400
11850Sstevel@tonic-gate 	{ 38400, B38400 },
11860Sstevel@tonic-gate #endif
11870Sstevel@tonic-gate #ifdef EXTA
11880Sstevel@tonic-gate 	{ 19200, EXTA },
11890Sstevel@tonic-gate #endif
11900Sstevel@tonic-gate #ifdef EXTB
11910Sstevel@tonic-gate 	{ 38400, EXTB },
11920Sstevel@tonic-gate #endif
11930Sstevel@tonic-gate #ifdef B57600
11940Sstevel@tonic-gate 	{ 57600, B57600 },
11950Sstevel@tonic-gate #endif
11960Sstevel@tonic-gate #ifdef B76800
11970Sstevel@tonic-gate 	{ 76800, B76800 },
11980Sstevel@tonic-gate #endif
11990Sstevel@tonic-gate #ifdef B115200
12000Sstevel@tonic-gate 	{ 115200, B115200 },
12010Sstevel@tonic-gate #endif
12020Sstevel@tonic-gate #ifdef B153600
12030Sstevel@tonic-gate 	{ 153600, B153600 },
12040Sstevel@tonic-gate #endif
12050Sstevel@tonic-gate #ifdef B230400
12060Sstevel@tonic-gate 	{ 230400, B230400 },
12070Sstevel@tonic-gate #endif
12080Sstevel@tonic-gate #ifdef B307200
12090Sstevel@tonic-gate 	{ 307200, B307200 },
12100Sstevel@tonic-gate #endif
12110Sstevel@tonic-gate #ifdef B460800
12120Sstevel@tonic-gate 	{ 460800, B460800 },
12130Sstevel@tonic-gate #endif
12149354STim.Marsland@Sun.COM #ifdef B921600
12159354STim.Marsland@Sun.COM 	{ 921600, B921600 },
12169354STim.Marsland@Sun.COM #endif
12170Sstevel@tonic-gate 	{ 0, 0 }
12180Sstevel@tonic-gate };
12190Sstevel@tonic-gate 
12200Sstevel@tonic-gate /*
12210Sstevel@tonic-gate  * translate_speed()
12220Sstevel@tonic-gate  *
12230Sstevel@tonic-gate  * Translate from bits/second to a speed_t
12240Sstevel@tonic-gate  */
12250Sstevel@tonic-gate static int
translate_speed(int bps)12260Sstevel@tonic-gate translate_speed(int bps)
12270Sstevel@tonic-gate {
12280Sstevel@tonic-gate 	struct speed *speedp;
12290Sstevel@tonic-gate 
12300Sstevel@tonic-gate 	if (bps == 0) {
12310Sstevel@tonic-gate 		return (0);
12320Sstevel@tonic-gate 	}
12330Sstevel@tonic-gate 	for (speedp = speeds; speedp->speed_int; speedp++) {
12340Sstevel@tonic-gate 		if (bps == speedp->speed_int) {
12350Sstevel@tonic-gate 			return (speedp->speed_val);
12360Sstevel@tonic-gate 		}
12370Sstevel@tonic-gate 	}
12380Sstevel@tonic-gate 	set_source(&speed_info);
12390Sstevel@tonic-gate 	option_error("speed %d not supported", bps);
12400Sstevel@tonic-gate 	return (0);
12410Sstevel@tonic-gate }
12420Sstevel@tonic-gate 
12430Sstevel@tonic-gate /*
12440Sstevel@tonic-gate  * baud_rate_of()
12450Sstevel@tonic-gate  *
12460Sstevel@tonic-gate  * Translate from a speed_t to bits/second
12470Sstevel@tonic-gate  */
12480Sstevel@tonic-gate static int
baud_rate_of(int speed)12490Sstevel@tonic-gate baud_rate_of(int speed)
12500Sstevel@tonic-gate {
12510Sstevel@tonic-gate 	struct speed *speedp;
12520Sstevel@tonic-gate 
12530Sstevel@tonic-gate 	if (speed == 0) {
12540Sstevel@tonic-gate 		return (0);
12550Sstevel@tonic-gate 	}
12560Sstevel@tonic-gate 	for (speedp = speeds; speedp->speed_int; speedp++) {
12570Sstevel@tonic-gate 		if (speed == speedp->speed_val) {
12580Sstevel@tonic-gate 			return (speedp->speed_int);
12590Sstevel@tonic-gate 		}
12600Sstevel@tonic-gate 	}
12610Sstevel@tonic-gate 	return (0);
12620Sstevel@tonic-gate }
12630Sstevel@tonic-gate 
12640Sstevel@tonic-gate /*
12650Sstevel@tonic-gate  * set_up_tty()
12660Sstevel@tonic-gate  *
12670Sstevel@tonic-gate  * Set up the serial port on `fd' for 8 bits, no parity, at the requested
12680Sstevel@tonic-gate  * speed, etc.  If `local' is true, set CLOCAL regardless of whether the
12690Sstevel@tonic-gate  * modem option was specified.
12700Sstevel@tonic-gate  */
12710Sstevel@tonic-gate void
set_up_tty(fd,local)12720Sstevel@tonic-gate set_up_tty(fd, local)
12730Sstevel@tonic-gate 	int fd, local;
12740Sstevel@tonic-gate {
12750Sstevel@tonic-gate 	int speed;
12760Sstevel@tonic-gate 	struct termios tios;
12770Sstevel@tonic-gate 	struct scc_mode sm;
12780Sstevel@tonic-gate 
12790Sstevel@tonic-gate 	if (already_ppp)
12800Sstevel@tonic-gate 		return;
12810Sstevel@tonic-gate 
12820Sstevel@tonic-gate 	if (sync_serial) {
12830Sstevel@tonic-gate 		restore_term = 0;
12840Sstevel@tonic-gate 		speed = B0;
12850Sstevel@tonic-gate 		baud_rate = 0;
12860Sstevel@tonic-gate 
12870Sstevel@tonic-gate 		if (strioctl(fd, S_IOCGETMODE, &sm, sizeof (sm),
12880Sstevel@tonic-gate 		    sizeof (sm)) < 0) {
12890Sstevel@tonic-gate 			return;
12900Sstevel@tonic-gate 		}
12910Sstevel@tonic-gate 
12920Sstevel@tonic-gate 		baud_rate = sm.sm_baudrate;
12930Sstevel@tonic-gate 		dbglog("synchronous speed appears to be %d bps", baud_rate);
12940Sstevel@tonic-gate 	} else {
12950Sstevel@tonic-gate 		if (tcgetattr(fd, &tios) < 0) {
12960Sstevel@tonic-gate 			fatal("tcgetattr: %m");
12970Sstevel@tonic-gate 		}
12980Sstevel@tonic-gate 		if (!restore_term) {
12990Sstevel@tonic-gate 			inittermios = tios;
13000Sstevel@tonic-gate 			if (myioctl(fd, TIOCGWINSZ, &wsinfo) < 0) {
13010Sstevel@tonic-gate 				if (errno == EINVAL) {
13020Sstevel@tonic-gate 					/*
13030Sstevel@tonic-gate 					 * ptem returns EINVAL if all zeroes.
13040Sstevel@tonic-gate 					 * Strange and unfixable code.
13050Sstevel@tonic-gate 					 */
13060Sstevel@tonic-gate 					bzero(&wsinfo, sizeof (wsinfo));
13070Sstevel@tonic-gate 				} else {
13080Sstevel@tonic-gate 					warn("unable to get TTY window "
13090Sstevel@tonic-gate 					    "size: %m");
13100Sstevel@tonic-gate 				}
13110Sstevel@tonic-gate 			}
13120Sstevel@tonic-gate 		}
13130Sstevel@tonic-gate 		tios.c_cflag &= ~(CSIZE | CSTOPB | PARENB | CLOCAL);
13140Sstevel@tonic-gate 		if (crtscts > 0) {
13150Sstevel@tonic-gate 			tios.c_cflag |= CRTSCTS | CRTSXOFF;
13160Sstevel@tonic-gate 		} else if (crtscts < 0) {
13170Sstevel@tonic-gate 			tios.c_cflag &= ~CRTSCTS & ~CRTSXOFF;
13180Sstevel@tonic-gate 		}
13190Sstevel@tonic-gate 		tios.c_cflag |= CS8 | CREAD | HUPCL;
13200Sstevel@tonic-gate 		if (local || !modem) {
13210Sstevel@tonic-gate 			tios.c_cflag |= CLOCAL;
13220Sstevel@tonic-gate 		}
13230Sstevel@tonic-gate 		tios.c_iflag = IGNBRK | IGNPAR;
13240Sstevel@tonic-gate 		tios.c_oflag = 0;
13250Sstevel@tonic-gate 		tios.c_lflag = 0;
13260Sstevel@tonic-gate 		tios.c_cc[VMIN] = 1;
13270Sstevel@tonic-gate 		tios.c_cc[VTIME] = 0;
13280Sstevel@tonic-gate 
13290Sstevel@tonic-gate 		if (crtscts == -2) {
13300Sstevel@tonic-gate 			tios.c_iflag |= IXON | IXOFF;
13310Sstevel@tonic-gate 			tios.c_cc[VSTOP] = 0x13;	/* DC3 = XOFF = ^S */
13320Sstevel@tonic-gate 			tios.c_cc[VSTART] = 0x11;	/* DC1 = XON  = ^Q */
13330Sstevel@tonic-gate 		}
13340Sstevel@tonic-gate 		speed = translate_speed(inspeed);
13350Sstevel@tonic-gate 		if (speed) {
13360Sstevel@tonic-gate 			(void) cfsetospeed(&tios, speed);
13370Sstevel@tonic-gate 			(void) cfsetispeed(&tios, speed);
13380Sstevel@tonic-gate 		} else {
13390Sstevel@tonic-gate 			speed = cfgetospeed(&tios);
13400Sstevel@tonic-gate 			/*
13410Sstevel@tonic-gate 			 * We can't proceed if the serial port speed is 0,
13420Sstevel@tonic-gate 			 * since that implies that the serial port is disabled.
13430Sstevel@tonic-gate 			 */
13440Sstevel@tonic-gate 			if (speed == B0) {
13450Sstevel@tonic-gate 				fatal("Baud rate for %s is 0; need explicit "
13460Sstevel@tonic-gate 				    "baud rate", devnam);
13470Sstevel@tonic-gate 			}
13480Sstevel@tonic-gate 		}
13490Sstevel@tonic-gate 		if (tcsetattr(fd, TCSAFLUSH, &tios) < 0) {
13500Sstevel@tonic-gate 			fatal("tcsetattr: %m");
13510Sstevel@tonic-gate 		}
13520Sstevel@tonic-gate 		baud_rate = baud_rate_of(speed);
13530Sstevel@tonic-gate 		dbglog("%s speed set to %d bps",
13540Sstevel@tonic-gate 		    fd == pty_slave ? "pty" : "serial", baud_rate);
13550Sstevel@tonic-gate 		restore_term = 1;
13560Sstevel@tonic-gate 	}
13570Sstevel@tonic-gate }
13580Sstevel@tonic-gate 
13590Sstevel@tonic-gate /*
13600Sstevel@tonic-gate  * restore_tty()
13610Sstevel@tonic-gate  *
13620Sstevel@tonic-gate  * Restore the terminal to the saved settings.
13630Sstevel@tonic-gate  */
13640Sstevel@tonic-gate void
restore_tty(fd)13650Sstevel@tonic-gate restore_tty(fd)
13660Sstevel@tonic-gate 	int fd;
13670Sstevel@tonic-gate {
13680Sstevel@tonic-gate 	if (restore_term == 0) {
13690Sstevel@tonic-gate 		return;
13700Sstevel@tonic-gate 	}
13710Sstevel@tonic-gate 	if (!default_device) {
13720Sstevel@tonic-gate 		/*
13730Sstevel@tonic-gate 		 * Turn off echoing, because otherwise we can get into
13740Sstevel@tonic-gate 		 * a loop with the tty and the modem echoing to each
13750Sstevel@tonic-gate 		 * other. We presume we are the sole user of this tty
13760Sstevel@tonic-gate 		 * device, so when we close it, it will revert to its
13770Sstevel@tonic-gate 		 * defaults anyway.
13780Sstevel@tonic-gate 		 */
13790Sstevel@tonic-gate 		inittermios.c_lflag &= ~(ECHO | ECHONL);
13800Sstevel@tonic-gate 	}
13810Sstevel@tonic-gate 	if (tcsetattr(fd, TCSAFLUSH, &inittermios) < 0) {
13820Sstevel@tonic-gate 		if (!hungup && errno != ENXIO) {
13830Sstevel@tonic-gate 			warn("tcsetattr: %m");
13840Sstevel@tonic-gate 		}
13850Sstevel@tonic-gate 	}
13860Sstevel@tonic-gate 	if (wsinfo.ws_row != 0 || wsinfo.ws_col != 0 ||
13870Sstevel@tonic-gate 	    wsinfo.ws_xpixel != 0 || wsinfo.ws_ypixel != 0) {
13880Sstevel@tonic-gate 		if (myioctl(fd, TIOCSWINSZ, &wsinfo) < 0) {
13890Sstevel@tonic-gate 			warn("unable to set TTY window size: %m");
13900Sstevel@tonic-gate 		}
13910Sstevel@tonic-gate 	}
13920Sstevel@tonic-gate 	restore_term = 0;
13930Sstevel@tonic-gate }
13940Sstevel@tonic-gate 
13950Sstevel@tonic-gate /*
13960Sstevel@tonic-gate  * setdtr()
13970Sstevel@tonic-gate  *
13980Sstevel@tonic-gate  * Control the DTR line on the serial port. This is called from die(), so it
13990Sstevel@tonic-gate  * shouldn't call die()
14000Sstevel@tonic-gate  */
14010Sstevel@tonic-gate void
setdtr(fd,on)14020Sstevel@tonic-gate setdtr(fd, on)
14030Sstevel@tonic-gate 	int fd, on;
14040Sstevel@tonic-gate {
14050Sstevel@tonic-gate 	int modembits = TIOCM_DTR;
14060Sstevel@tonic-gate 	if (!already_ppp &&
14070Sstevel@tonic-gate 	    myioctl(fd, (on ? TIOCMBIS : TIOCMBIC), &modembits) < 0) {
14080Sstevel@tonic-gate 		warn("unable to set DTR line %s: %m", (on ? "ON" : "OFF"));
14090Sstevel@tonic-gate 	}
14100Sstevel@tonic-gate }
14110Sstevel@tonic-gate 
14120Sstevel@tonic-gate /*
14130Sstevel@tonic-gate  * open_loopback()
14140Sstevel@tonic-gate  *
14150Sstevel@tonic-gate  * Open the device we use for getting packets in demand mode. Under Solaris 2,
14160Sstevel@tonic-gate  * we use our existing fd to the ppp driver.
14170Sstevel@tonic-gate  */
14180Sstevel@tonic-gate int
open_ppp_loopback()14190Sstevel@tonic-gate open_ppp_loopback()
14200Sstevel@tonic-gate {
14210Sstevel@tonic-gate 	/*
14220Sstevel@tonic-gate 	 * Plumb the interface.
14230Sstevel@tonic-gate 	 */
14240Sstevel@tonic-gate 	if (IPCP_ENABLED && (plumb_ipif(0) == 0)) {
14250Sstevel@tonic-gate 		fatal("Unable to initialize IP interface for demand dial.");
14260Sstevel@tonic-gate 	}
14270Sstevel@tonic-gate #ifdef INET6
14280Sstevel@tonic-gate 	if (IPV6CP_ENABLED && (plumb_ip6if(0) == 0)) {
14290Sstevel@tonic-gate 		fatal("Unable to initialize IPv6 interface for demand dial.");
14300Sstevel@tonic-gate 	}
14310Sstevel@tonic-gate #endif /* INET6 */
14320Sstevel@tonic-gate 
14330Sstevel@tonic-gate 	return (pppfd);
14340Sstevel@tonic-gate }
14350Sstevel@tonic-gate 
14360Sstevel@tonic-gate /*
14370Sstevel@tonic-gate  * output()
14380Sstevel@tonic-gate  *
14390Sstevel@tonic-gate  * Output PPP packet downstream
14400Sstevel@tonic-gate  */
14410Sstevel@tonic-gate /*ARGSUSED*/
14420Sstevel@tonic-gate void
output(unit,p,len)14430Sstevel@tonic-gate output(unit, p, len)
14440Sstevel@tonic-gate 	int unit;
14450Sstevel@tonic-gate 	uchar_t *p;
14460Sstevel@tonic-gate 	int len;
14470Sstevel@tonic-gate {
14480Sstevel@tonic-gate 	struct strbuf data;
14490Sstevel@tonic-gate 	struct pollfd pfd;
14500Sstevel@tonic-gate 	int retries, n;
14510Sstevel@tonic-gate 	bool sent_ok = 1;
14520Sstevel@tonic-gate 
14530Sstevel@tonic-gate 	data.len = len;
14540Sstevel@tonic-gate 	data.buf = (caddr_t)p;
14550Sstevel@tonic-gate 	retries = 4;
14560Sstevel@tonic-gate 
14570Sstevel@tonic-gate 	while (putmsg(pppfd, NULL, &data, 0) < 0) {
14580Sstevel@tonic-gate 		if (errno == EINTR)
14590Sstevel@tonic-gate 			continue;
14600Sstevel@tonic-gate 		if (--retries < 0 ||
14610Sstevel@tonic-gate 		    (errno != EWOULDBLOCK && errno != EAGAIN)) {
14620Sstevel@tonic-gate 			if (errno != ENXIO) {
14630Sstevel@tonic-gate 				error("Couldn't send packet: %m");
14640Sstevel@tonic-gate 				sent_ok = 0;
14650Sstevel@tonic-gate 			}
14660Sstevel@tonic-gate 			break;
14670Sstevel@tonic-gate 		}
14680Sstevel@tonic-gate 		pfd.fd = pppfd;
14690Sstevel@tonic-gate 		pfd.events = POLLOUT;
14700Sstevel@tonic-gate 		do {
14710Sstevel@tonic-gate 			/* wait for up to 0.25 seconds */
14720Sstevel@tonic-gate 			n = poll(&pfd, 1, 250);
14730Sstevel@tonic-gate 		} while ((n == -1) && (errno == EINTR));
14740Sstevel@tonic-gate 	}
14750Sstevel@tonic-gate 	if (debug && sent_ok) {
14760Sstevel@tonic-gate 		dbglog("sent %P", p, len);
14770Sstevel@tonic-gate 	}
14780Sstevel@tonic-gate }
14790Sstevel@tonic-gate 
14800Sstevel@tonic-gate /*
14810Sstevel@tonic-gate  * wait_input()
14820Sstevel@tonic-gate  *
14830Sstevel@tonic-gate  * Wait until there is data available, for the length of time specified by
14840Sstevel@tonic-gate  * timo (indefinite if timo is NULL).
14850Sstevel@tonic-gate  */
14860Sstevel@tonic-gate void
wait_input(timo)14870Sstevel@tonic-gate wait_input(timo)
14880Sstevel@tonic-gate 	struct timeval *timo;
14890Sstevel@tonic-gate {
14900Sstevel@tonic-gate 	int t;
14910Sstevel@tonic-gate 
14920Sstevel@tonic-gate 	t = (timo == NULL ? -1 : (timo->tv_sec * 1000 + timo->tv_usec / 1000));
14930Sstevel@tonic-gate 	if ((poll(pollfds, n_pollfds, t) < 0) && (errno != EINTR)) {
14940Sstevel@tonic-gate 		fatal("poll: %m");
14950Sstevel@tonic-gate 	}
14960Sstevel@tonic-gate }
14970Sstevel@tonic-gate 
14980Sstevel@tonic-gate /*
14990Sstevel@tonic-gate  * add_fd()
15000Sstevel@tonic-gate  *
15010Sstevel@tonic-gate  * Add an fd to the set that wait_input waits for.
15020Sstevel@tonic-gate  */
15030Sstevel@tonic-gate void
add_fd(fd)15040Sstevel@tonic-gate add_fd(fd)
15050Sstevel@tonic-gate 	int fd;
15060Sstevel@tonic-gate {
15070Sstevel@tonic-gate 	int n;
15080Sstevel@tonic-gate 
15090Sstevel@tonic-gate 	if (fd < 0) {
15100Sstevel@tonic-gate 		return;
15110Sstevel@tonic-gate 	}
15120Sstevel@tonic-gate 	for (n = 0; n < n_pollfds; ++n) {
15130Sstevel@tonic-gate 		if (pollfds[n].fd == fd) {
15140Sstevel@tonic-gate 			return;
15150Sstevel@tonic-gate 		}
15160Sstevel@tonic-gate 	}
15170Sstevel@tonic-gate 	if (n_pollfds < MAX_POLLFDS) {
15180Sstevel@tonic-gate 		pollfds[n_pollfds].fd = fd;
15190Sstevel@tonic-gate 		pollfds[n_pollfds].events = POLLIN | POLLPRI | POLLHUP;
15200Sstevel@tonic-gate 		++n_pollfds;
15210Sstevel@tonic-gate 	} else {
15220Sstevel@tonic-gate 		fatal("add_fd: too many inputs!");
15230Sstevel@tonic-gate 	}
15240Sstevel@tonic-gate }
15250Sstevel@tonic-gate 
15260Sstevel@tonic-gate /*
15270Sstevel@tonic-gate  * remove_fd()
15280Sstevel@tonic-gate  *
15290Sstevel@tonic-gate  * Remove an fd from the set that wait_input waits for.
15300Sstevel@tonic-gate  */
15310Sstevel@tonic-gate void
remove_fd(fd)15320Sstevel@tonic-gate remove_fd(fd)
15330Sstevel@tonic-gate 	int fd;
15340Sstevel@tonic-gate {
15350Sstevel@tonic-gate 	int n;
15360Sstevel@tonic-gate 
15370Sstevel@tonic-gate 	for (n = 0; n < n_pollfds; ++n) {
15380Sstevel@tonic-gate 		if (pollfds[n].fd == fd) {
15390Sstevel@tonic-gate 			while (++n < n_pollfds) {
15400Sstevel@tonic-gate 				pollfds[n-1] = pollfds[n];
15410Sstevel@tonic-gate 			}
15420Sstevel@tonic-gate 			--n_pollfds;
15430Sstevel@tonic-gate 			break;
15440Sstevel@tonic-gate 		}
15450Sstevel@tonic-gate 	}
15460Sstevel@tonic-gate }
15470Sstevel@tonic-gate 
15480Sstevel@tonic-gate static void
dump_packet(uchar_t * buf,int len)15490Sstevel@tonic-gate dump_packet(uchar_t *buf, int len)
15500Sstevel@tonic-gate {
15510Sstevel@tonic-gate 	uchar_t *bp;
15520Sstevel@tonic-gate 	int proto, offs;
15530Sstevel@tonic-gate 	const char *cp;
15540Sstevel@tonic-gate 	char sbuf[32];
15550Sstevel@tonic-gate 	uint32_t src, dst;
15560Sstevel@tonic-gate 	struct protoent *pep;
1557*9751Sjames.d.carlson@sun.com 	struct in6_addr addr;
1558*9751Sjames.d.carlson@sun.com 	char fromstr[INET6_ADDRSTRLEN];
1559*9751Sjames.d.carlson@sun.com 	char tostr[INET6_ADDRSTRLEN];
15600Sstevel@tonic-gate 
15610Sstevel@tonic-gate 	if (len < 4) {
1562*9751Sjames.d.carlson@sun.com 		notice("strange link activity: %.*B", len, buf);
15630Sstevel@tonic-gate 		return;
15640Sstevel@tonic-gate 	}
15650Sstevel@tonic-gate 	bp = buf;
15660Sstevel@tonic-gate 	if (bp[0] == 0xFF && bp[1] == 0x03)
15670Sstevel@tonic-gate 		bp += 2;
15680Sstevel@tonic-gate 	proto = *bp++;
15690Sstevel@tonic-gate 	if (!(proto & 1))
15700Sstevel@tonic-gate 		proto = (proto << 8) + *bp++;
15710Sstevel@tonic-gate 	len -= bp-buf;
1572*9751Sjames.d.carlson@sun.com 	switch (proto) {
1573*9751Sjames.d.carlson@sun.com 	case PPP_IP:
1574*9751Sjames.d.carlson@sun.com 		if (len < IP_HDRLEN || get_ipv(bp) != 4 || get_iphl(bp) < 5) {
1575*9751Sjames.d.carlson@sun.com 			notice("strange IP packet activity: %16.*B", len, buf);
15760Sstevel@tonic-gate 			return;
15770Sstevel@tonic-gate 		}
15780Sstevel@tonic-gate 		src = get_ipsrc(bp);
15790Sstevel@tonic-gate 		dst = get_ipdst(bp);
15800Sstevel@tonic-gate 		proto = get_ipproto(bp);
15810Sstevel@tonic-gate 		if ((pep = getprotobynumber(proto)) != NULL) {
15820Sstevel@tonic-gate 			cp = pep->p_name;
15830Sstevel@tonic-gate 		} else {
15840Sstevel@tonic-gate 			(void) slprintf(sbuf, sizeof (sbuf), "IP proto %d",
15850Sstevel@tonic-gate 			    proto);
15860Sstevel@tonic-gate 			cp = sbuf;
15870Sstevel@tonic-gate 		}
15880Sstevel@tonic-gate 		if ((get_ipoff(bp) & IP_OFFMASK) != 0) {
15890Sstevel@tonic-gate 			len -= get_iphl(bp) * 4;
15900Sstevel@tonic-gate 			bp += get_iphl(bp) * 4;
1591*9751Sjames.d.carlson@sun.com 			notice("%s fragment from %I->%I: %8.*B", cp, src, dst,
15920Sstevel@tonic-gate 			    len, bp);
15930Sstevel@tonic-gate 		} else {
15940Sstevel@tonic-gate 			if (len > get_iplen(bp))
15950Sstevel@tonic-gate 				len = get_iplen(bp);
15960Sstevel@tonic-gate 			len -= get_iphl(bp) * 4;
15970Sstevel@tonic-gate 			bp += get_iphl(bp) * 4;
15980Sstevel@tonic-gate 			offs = proto == IPPROTO_TCP ? (get_tcpoff(bp)*4) : 8;
15990Sstevel@tonic-gate 			if (proto == IPPROTO_TCP || proto == IPPROTO_UDP)
1600*9751Sjames.d.carlson@sun.com 				notice("%s data:%d %s%I:%d->%I:%d: %8.*B", cp,
1601*9751Sjames.d.carlson@sun.com 				    len-offs,
1602*9751Sjames.d.carlson@sun.com 				    proto == IPPROTO_TCP ?
1603*9751Sjames.d.carlson@sun.com 				    tcp_flag_decode(get_tcpflags(bp)) : "",
1604*9751Sjames.d.carlson@sun.com 				    src, get_sport(bp), dst, get_dport(bp),
1605*9751Sjames.d.carlson@sun.com 				    len-offs, bp+offs);
16060Sstevel@tonic-gate 			else
1607*9751Sjames.d.carlson@sun.com 				notice("%s %d bytes %I->%I: %8.*B", cp, len,
16080Sstevel@tonic-gate 				    src, dst, len, bp);
16090Sstevel@tonic-gate 		}
16100Sstevel@tonic-gate 		return;
1611*9751Sjames.d.carlson@sun.com 
1612*9751Sjames.d.carlson@sun.com 	case PPP_IPV6:
1613*9751Sjames.d.carlson@sun.com 		if (len < IP6_HDRLEN) {
1614*9751Sjames.d.carlson@sun.com 			notice("strange IPv6 activity: %16.*B", len, buf);
1615*9751Sjames.d.carlson@sun.com 			return;
1616*9751Sjames.d.carlson@sun.com 		}
1617*9751Sjames.d.carlson@sun.com 		(void) BCOPY(get_ip6src(bp), &addr, sizeof (addr));
1618*9751Sjames.d.carlson@sun.com 		(void) inet_ntop(AF_INET6, &addr, fromstr, sizeof (fromstr));
1619*9751Sjames.d.carlson@sun.com 		(void) BCOPY(get_ip6dst(bp), &addr, sizeof (addr));
1620*9751Sjames.d.carlson@sun.com 		(void) inet_ntop(AF_INET6, &addr, tostr, sizeof (tostr));
1621*9751Sjames.d.carlson@sun.com 		proto = get_ip6nh(bp);
1622*9751Sjames.d.carlson@sun.com 		if (proto == IPPROTO_FRAGMENT) {
1623*9751Sjames.d.carlson@sun.com 			notice("IPv6 fragment from %s->%s", fromstr,
1624*9751Sjames.d.carlson@sun.com 			    tostr);
1625*9751Sjames.d.carlson@sun.com 			return;
1626*9751Sjames.d.carlson@sun.com 		}
1627*9751Sjames.d.carlson@sun.com 		if ((pep = getprotobynumber(proto)) != NULL) {
1628*9751Sjames.d.carlson@sun.com 			cp = pep->p_name;
1629*9751Sjames.d.carlson@sun.com 		} else {
1630*9751Sjames.d.carlson@sun.com 			(void) slprintf(sbuf, sizeof (sbuf), "IPv6 proto %d",
1631*9751Sjames.d.carlson@sun.com 			    proto);
1632*9751Sjames.d.carlson@sun.com 			cp = sbuf;
1633*9751Sjames.d.carlson@sun.com 		}
1634*9751Sjames.d.carlson@sun.com 		len -= IP6_HDRLEN;
1635*9751Sjames.d.carlson@sun.com 		bp += IP6_HDRLEN;
1636*9751Sjames.d.carlson@sun.com 		offs = proto == IPPROTO_TCP ? (get_tcpoff(bp)*4) : 8;
1637*9751Sjames.d.carlson@sun.com 		if (proto == IPPROTO_TCP || proto == IPPROTO_UDP)
1638*9751Sjames.d.carlson@sun.com 			notice("%s data:%d %s[%s]%d->[%s]%d: %8.*B", cp,
1639*9751Sjames.d.carlson@sun.com 			    len-offs,
1640*9751Sjames.d.carlson@sun.com 			    proto == IPPROTO_TCP ?
1641*9751Sjames.d.carlson@sun.com 			    tcp_flag_decode(get_tcpflags(bp)) : "",
1642*9751Sjames.d.carlson@sun.com 			    fromstr, get_sport(bp), tostr, get_dport(bp),
1643*9751Sjames.d.carlson@sun.com 			    len-offs, bp+offs);
1644*9751Sjames.d.carlson@sun.com 		else
1645*9751Sjames.d.carlson@sun.com 			notice("%s %d bytes %s->%s: %8.*B", cp, len,
1646*9751Sjames.d.carlson@sun.com 			    fromstr, tostr, len, bp);
1647*9751Sjames.d.carlson@sun.com 		return;
16480Sstevel@tonic-gate 	}
16490Sstevel@tonic-gate 	if ((cp = protocol_name(proto)) == NULL) {
16500Sstevel@tonic-gate 		(void) slprintf(sbuf, sizeof (sbuf), "0x#X", proto);
16510Sstevel@tonic-gate 		cp = (const char *)sbuf;
16520Sstevel@tonic-gate 	}
1653*9751Sjames.d.carlson@sun.com 	notice("link activity: %s %16.*B", cp, len, bp);
16540Sstevel@tonic-gate }
16550Sstevel@tonic-gate 
16560Sstevel@tonic-gate /*
16570Sstevel@tonic-gate  * handle_bind()
16580Sstevel@tonic-gate  */
16590Sstevel@tonic-gate static void
handle_bind(u_int32_t reason)16600Sstevel@tonic-gate handle_bind(u_int32_t reason)
16610Sstevel@tonic-gate {
16620Sstevel@tonic-gate 	/*
16630Sstevel@tonic-gate 	 * Here we might, in the future, handle DL_BIND_REQ notifications
16640Sstevel@tonic-gate 	 * in order to close and re-open a NCP when certain interface
16650Sstevel@tonic-gate 	 * parameters (addresses, etc.) are changed via external mechanisms
16660Sstevel@tonic-gate 	 * such as through the "ifconfig" program.
16670Sstevel@tonic-gate 	 */
16680Sstevel@tonic-gate 	switch (reason) {
16690Sstevel@tonic-gate 	case PPP_LINKSTAT_IPV4_BOUND:
16700Sstevel@tonic-gate 		break;
16710Sstevel@tonic-gate #ifdef INET6
16720Sstevel@tonic-gate 	case PPP_LINKSTAT_IPV6_BOUND:
16730Sstevel@tonic-gate 		break;
16740Sstevel@tonic-gate #endif
16750Sstevel@tonic-gate 	default:
16760Sstevel@tonic-gate 		error("handle_bind: unrecognized reason");
16770Sstevel@tonic-gate 		break;
16780Sstevel@tonic-gate 	}
16790Sstevel@tonic-gate }
16800Sstevel@tonic-gate 
16810Sstevel@tonic-gate /*
16820Sstevel@tonic-gate  * handle_unbind()
16830Sstevel@tonic-gate  */
16840Sstevel@tonic-gate static void
handle_unbind(u_int32_t reason)16850Sstevel@tonic-gate handle_unbind(u_int32_t reason)
16860Sstevel@tonic-gate {
16870Sstevel@tonic-gate 	bool iff_up_isset;
16880Sstevel@tonic-gate 	int rc;
16890Sstevel@tonic-gate 	static const char *unplumb_str = "unplumbed";
16900Sstevel@tonic-gate 	static const char *down_str = "downed";
16910Sstevel@tonic-gate 
16920Sstevel@tonic-gate 	/*
16930Sstevel@tonic-gate 	 * Since the kernel driver (sppp) notifies this daemon of the
16940Sstevel@tonic-gate 	 * DLPI bind/unbind activities (for the purpose of bringing down
16950Sstevel@tonic-gate 	 * a NCP), we need to explicitly test the "actual" status of
16960Sstevel@tonic-gate 	 * the interface instance for which the notification is destined
16970Sstevel@tonic-gate 	 * from.  This is because /dev/ip performs multiple DLPI attach-
16980Sstevel@tonic-gate 	 * bind-unbind-detach during the early life of the interface,
16990Sstevel@tonic-gate 	 * and when certain interface parameters change.  A DL_UNBIND_REQ
17000Sstevel@tonic-gate 	 * coming down to the sppp driver from /dev/ip (which results in
17010Sstevel@tonic-gate 	 * our receiving of the PPP_LINKSTAT_*_UNBOUND link status message)
17020Sstevel@tonic-gate 	 * is not enough to conclude that the interface has been marked
17030Sstevel@tonic-gate 	 * DOWN (its IFF_UP bit is cleared) or is going away.  Therefore,
17040Sstevel@tonic-gate 	 * we should query /dev/ip directly, upon receiving such *_UNBOUND
17050Sstevel@tonic-gate 	 * notification, to determine whether the interface is DOWN
17060Sstevel@tonic-gate 	 * for real, and only take the necessary actions when IFF_UP
17070Sstevel@tonic-gate 	 * bit for the interface instance is actually cleared.
17080Sstevel@tonic-gate 	 */
17090Sstevel@tonic-gate 	switch (reason) {
17100Sstevel@tonic-gate 	case PPP_LINKSTAT_IPV4_UNBOUND:
17110Sstevel@tonic-gate 		(void) sleep(1);
17120Sstevel@tonic-gate 		rc = giflags(IFF_UP, &iff_up_isset);
17130Sstevel@tonic-gate 		if (!iff_up_isset) {
17140Sstevel@tonic-gate 			if_is_up = 0;
17150Sstevel@tonic-gate 			ipmuxid = -1;
17160Sstevel@tonic-gate 			info("IPv4 interface %s by administrator",
17170Sstevel@tonic-gate 			    ((rc < 0 && rc == ENXIO) ? unplumb_str : down_str));
17180Sstevel@tonic-gate 			fsm_close(&ipcp_fsm[0],
17190Sstevel@tonic-gate 			    "administratively disconnected");
17200Sstevel@tonic-gate 		}
17210Sstevel@tonic-gate 		break;
17220Sstevel@tonic-gate #ifdef INET6
17230Sstevel@tonic-gate 	case PPP_LINKSTAT_IPV6_UNBOUND:
17240Sstevel@tonic-gate 		(void) sleep(1);
17250Sstevel@tonic-gate 		rc = giflags(IFF_UP, &iff_up_isset);
17260Sstevel@tonic-gate 		if (!iff_up_isset) {
17270Sstevel@tonic-gate 			if6_is_up = 0;
17280Sstevel@tonic-gate 			ip6muxid = -1;
17290Sstevel@tonic-gate 			info("IPv6 interface %s by administrator",
17300Sstevel@tonic-gate 			    ((rc < 0 && rc == ENXIO) ? unplumb_str : down_str));
17310Sstevel@tonic-gate 			fsm_close(&ipv6cp_fsm[0],
17320Sstevel@tonic-gate 			    "administratively disconnected");
17330Sstevel@tonic-gate 		}
17340Sstevel@tonic-gate 		break;
17350Sstevel@tonic-gate #endif
17360Sstevel@tonic-gate 	default:
17370Sstevel@tonic-gate 		error("handle_unbind: unrecognized reason");
17380Sstevel@tonic-gate 		break;
17390Sstevel@tonic-gate 	}
17400Sstevel@tonic-gate }
17410Sstevel@tonic-gate 
17420Sstevel@tonic-gate /*
17430Sstevel@tonic-gate  * read_packet()
17440Sstevel@tonic-gate  *
17450Sstevel@tonic-gate  * Get a PPP packet from the serial device.
17460Sstevel@tonic-gate  */
17470Sstevel@tonic-gate int
read_packet(buf)17480Sstevel@tonic-gate read_packet(buf)
17490Sstevel@tonic-gate 	uchar_t *buf;
17500Sstevel@tonic-gate {
17510Sstevel@tonic-gate 	struct strbuf ctrl;
17520Sstevel@tonic-gate 	struct strbuf data;
17530Sstevel@tonic-gate 	int flags;
17540Sstevel@tonic-gate 	int len;
17550Sstevel@tonic-gate 	int rc;
17560Sstevel@tonic-gate 	struct ppp_ls *plp;
17570Sstevel@tonic-gate 	uint32_t ctrlbuf[1536 / sizeof (uint32_t)];
17580Sstevel@tonic-gate 	bool flushmode;
17590Sstevel@tonic-gate 
17600Sstevel@tonic-gate 	flushmode = 0;
17610Sstevel@tonic-gate 	for (;;) {
17620Sstevel@tonic-gate 
17630Sstevel@tonic-gate 		data.maxlen = PPP_MRU + PPP_HDRLEN;
17640Sstevel@tonic-gate 		data.buf = (caddr_t)buf;
17650Sstevel@tonic-gate 
17660Sstevel@tonic-gate 		ctrl.maxlen = sizeof (ctrlbuf);
17670Sstevel@tonic-gate 		ctrl.buf = (caddr_t)ctrlbuf;
17680Sstevel@tonic-gate 
17690Sstevel@tonic-gate 		flags = 0;
17700Sstevel@tonic-gate 		rc = len = getmsg(pppfd, &ctrl, &data, &flags);
17710Sstevel@tonic-gate 		if (sys_read_packet_hook != NULL) {
17720Sstevel@tonic-gate 			rc = len = (*sys_read_packet_hook)(len, &ctrl, &data,
17730Sstevel@tonic-gate 			    flags);
17740Sstevel@tonic-gate 		}
17750Sstevel@tonic-gate 		if (len < 0) {
17760Sstevel@tonic-gate 			if (errno == EAGAIN || errno == EINTR) {
17770Sstevel@tonic-gate 				return (-1);
17780Sstevel@tonic-gate 			}
17790Sstevel@tonic-gate 			fatal("Error reading packet: %m");
17800Sstevel@tonic-gate 		}
17810Sstevel@tonic-gate 		if ((data.len > 0) && (ctrl.len < 0)) {
17820Sstevel@tonic-gate 			/*
17830Sstevel@tonic-gate 			 * If there's more data on stream head, keep reading
17840Sstevel@tonic-gate 			 * but discard, since the stream is now corrupt.
17850Sstevel@tonic-gate 			 */
17860Sstevel@tonic-gate 			if (rc & MOREDATA) {
17870Sstevel@tonic-gate 				dbglog("More data; input packet garbled");
17880Sstevel@tonic-gate 				flushmode = 1;
17890Sstevel@tonic-gate 				continue;
17900Sstevel@tonic-gate 			}
17910Sstevel@tonic-gate 			if (flushmode)
17920Sstevel@tonic-gate 				return (-1);
17930Sstevel@tonic-gate 			return (data.len);
17940Sstevel@tonic-gate 
17950Sstevel@tonic-gate 		} else if (ctrl.len > 0) {
17960Sstevel@tonic-gate 			/*
17970Sstevel@tonic-gate 			 * If there's more ctl on stream head, keep reading,
17980Sstevel@tonic-gate 			 * but start discarding.  We can't deal with fragmented
17990Sstevel@tonic-gate 			 * messages at all.
18000Sstevel@tonic-gate 			 */
18010Sstevel@tonic-gate 			if (rc & MORECTL) {
18020Sstevel@tonic-gate 				dbglog("More control; stream garbled");
18030Sstevel@tonic-gate 				flushmode = 1;
18040Sstevel@tonic-gate 				continue;
18050Sstevel@tonic-gate 			}
18060Sstevel@tonic-gate 			if (flushmode)
18070Sstevel@tonic-gate 				return (-1);
18080Sstevel@tonic-gate 			if (ctrl.len < sizeof (struct ppp_ls)) {
18090Sstevel@tonic-gate 				warn("read_packet: ctl.len %d < "
18100Sstevel@tonic-gate 				    "sizeof ppp_ls %d",
18110Sstevel@tonic-gate 				    ctrl.len, sizeof (struct ppp_ls));
18120Sstevel@tonic-gate 				return (-1);
18130Sstevel@tonic-gate 			}
18140Sstevel@tonic-gate 			plp = (struct ppp_ls *)ctrlbuf;
18150Sstevel@tonic-gate 			if (plp->magic != PPPLSMAGIC) {
18160Sstevel@tonic-gate 				/* Skip, as we don't understand it */
18170Sstevel@tonic-gate 				dbglog("read_packet: unrecognized control %lX",
18180Sstevel@tonic-gate 				    plp->magic);
18190Sstevel@tonic-gate 				return (-1);
18200Sstevel@tonic-gate 			}
18210Sstevel@tonic-gate 
18220Sstevel@tonic-gate 			lastlink_status = plp->ppp_message;
18230Sstevel@tonic-gate 
18240Sstevel@tonic-gate 			switch (plp->ppp_message) {
18250Sstevel@tonic-gate 			case PPP_LINKSTAT_HANGUP:
18260Sstevel@tonic-gate 				return (0);	/* Hangup */
18270Sstevel@tonic-gate 			/* For use by integrated drivers. */
18280Sstevel@tonic-gate 			case PPP_LINKSTAT_UP:
18290Sstevel@tonic-gate 				lcp_lowerdown(0);
18300Sstevel@tonic-gate 				lcp_lowerup(0);
18310Sstevel@tonic-gate 				return (0);
18320Sstevel@tonic-gate 			case PPP_LINKSTAT_NEEDUP:
1833*9751Sjames.d.carlson@sun.com 				if (data.len > 0)
18340Sstevel@tonic-gate 					dump_packet(buf, data.len);
18350Sstevel@tonic-gate 				return (-1);	/* Demand dial */
18360Sstevel@tonic-gate 			case PPP_LINKSTAT_IPV4_UNBOUND:
18370Sstevel@tonic-gate 				(void) handle_unbind(plp->ppp_message);
18380Sstevel@tonic-gate 				return (-1);
18390Sstevel@tonic-gate 			case PPP_LINKSTAT_IPV4_BOUND:
18400Sstevel@tonic-gate 				(void) handle_bind(plp->ppp_message);
18410Sstevel@tonic-gate 				return (-1);
18420Sstevel@tonic-gate #ifdef INET6
18430Sstevel@tonic-gate 			case PPP_LINKSTAT_IPV6_UNBOUND:
18440Sstevel@tonic-gate 				(void) handle_unbind(plp->ppp_message);
18450Sstevel@tonic-gate 				return (-1);
18460Sstevel@tonic-gate 			case PPP_LINKSTAT_IPV6_BOUND:
18470Sstevel@tonic-gate 				(void) handle_bind(plp->ppp_message);
18480Sstevel@tonic-gate 				return (-1);
18490Sstevel@tonic-gate #endif
18500Sstevel@tonic-gate 			default:
18510Sstevel@tonic-gate 				warn("read_packet: unknown link status type!");
18520Sstevel@tonic-gate 				return (-1);
18530Sstevel@tonic-gate 			}
18540Sstevel@tonic-gate 		} else {
18550Sstevel@tonic-gate 			/*
18560Sstevel@tonic-gate 			 * We get here on zero length data or control.
18570Sstevel@tonic-gate 			 */
18580Sstevel@tonic-gate 			return (-1);
18590Sstevel@tonic-gate 		}
18600Sstevel@tonic-gate 	}
18610Sstevel@tonic-gate }
18620Sstevel@tonic-gate 
18630Sstevel@tonic-gate /*
18640Sstevel@tonic-gate  * get_loop_output()
18650Sstevel@tonic-gate  *
18660Sstevel@tonic-gate  * Get outgoing packets from the ppp device, and detect when we want to bring
18670Sstevel@tonic-gate  * the real link up. Return value is 1 if we need to bring up the link, or 0
18680Sstevel@tonic-gate  * otherwise.
18690Sstevel@tonic-gate  */
18700Sstevel@tonic-gate int
get_loop_output()18710Sstevel@tonic-gate get_loop_output()
18720Sstevel@tonic-gate {
18730Sstevel@tonic-gate 	int loops;
18740Sstevel@tonic-gate 
18750Sstevel@tonic-gate 	/*
18760Sstevel@tonic-gate 	 * In the Solaris 2.x kernel-level portion implementation, packets
18770Sstevel@tonic-gate 	 * which are received on a demand-dial interface are immediately
18780Sstevel@tonic-gate 	 * discarded, and a notification message is sent up the control
18790Sstevel@tonic-gate 	 * stream to the pppd process.  Therefore, the call to read_packet()
18800Sstevel@tonic-gate 	 * below is merely there to wait for such message.
18810Sstevel@tonic-gate 	 */
18820Sstevel@tonic-gate 	lastlink_status = 0;
18830Sstevel@tonic-gate 	loops = 0;
18840Sstevel@tonic-gate 	while (read_packet(inpacket_buf) > 0) {
18850Sstevel@tonic-gate 		if (++loops > 10)
18860Sstevel@tonic-gate 			break;
18870Sstevel@tonic-gate 	}
18880Sstevel@tonic-gate 	return (lastlink_status == PPP_LINKSTAT_NEEDUP);
18890Sstevel@tonic-gate }
18900Sstevel@tonic-gate 
18910Sstevel@tonic-gate #ifdef MUX_FRAME
18920Sstevel@tonic-gate /*ARGSUSED*/
18930Sstevel@tonic-gate void
ppp_send_muxoption(unit,muxflag)18940Sstevel@tonic-gate ppp_send_muxoption(unit, muxflag)
18950Sstevel@tonic-gate 	int unit;
18960Sstevel@tonic-gate 	u_int32_t muxflag;
18970Sstevel@tonic-gate {
18980Sstevel@tonic-gate 	uint32_t	cf[2];
18990Sstevel@tonic-gate 
19000Sstevel@tonic-gate 	/*
19010Sstevel@tonic-gate 	 * Since muxed frame feature is implemented in the async module,
19020Sstevel@tonic-gate 	 * don't send down the ioctl in the synchronous case.
19030Sstevel@tonic-gate 	 */
19040Sstevel@tonic-gate 	if (!sync_serial && fdmuxid >= 0 && pppfd != -1) {
19050Sstevel@tonic-gate 		cf[0] = muxflag;
19060Sstevel@tonic-gate 		cf[1] = X_MUXMASK;
19070Sstevel@tonic-gate 
19080Sstevel@tonic-gate 		if (strioctl(pppfd, PPPIO_MUX, cf, sizeof (cf), 0) < 0) {
19090Sstevel@tonic-gate 			error("Couldn't set mux option: %m");
19100Sstevel@tonic-gate 		}
19110Sstevel@tonic-gate 	}
19120Sstevel@tonic-gate }
19130Sstevel@tonic-gate 
19140Sstevel@tonic-gate /*ARGSUSED*/
19150Sstevel@tonic-gate void
ppp_recv_muxoption(unit,muxflag)19160Sstevel@tonic-gate ppp_recv_muxoption(unit, muxflag)
19170Sstevel@tonic-gate 	int unit;
19180Sstevel@tonic-gate 	u_int32_t muxflag;
19190Sstevel@tonic-gate {
19200Sstevel@tonic-gate 	uint32_t	cf[2];
19210Sstevel@tonic-gate 
19220Sstevel@tonic-gate 	/*
19230Sstevel@tonic-gate 	 * Since muxed frame feature is implemented in the async module,
19240Sstevel@tonic-gate 	 * don't send down the ioctl in the synchronous case.
19250Sstevel@tonic-gate 	 */
19260Sstevel@tonic-gate 	if (!sync_serial && fdmuxid >= 0 && pppfd != -1) {
19270Sstevel@tonic-gate 		cf[0] = muxflag;
19280Sstevel@tonic-gate 		cf[1] = R_MUXMASK;
19290Sstevel@tonic-gate 
19300Sstevel@tonic-gate 		if (strioctl(pppfd, PPPIO_MUX, cf, sizeof (cf), 0) < 0) {
19310Sstevel@tonic-gate 			error("Couldn't set receive mux option: %m");
19320Sstevel@tonic-gate 		}
19330Sstevel@tonic-gate 	}
19340Sstevel@tonic-gate }
19350Sstevel@tonic-gate #endif
19360Sstevel@tonic-gate 
19370Sstevel@tonic-gate /*
19380Sstevel@tonic-gate  * ppp_send_config()
19390Sstevel@tonic-gate  *
19400Sstevel@tonic-gate  * Configure the transmit characteristics of the ppp interface.
19410Sstevel@tonic-gate  */
19420Sstevel@tonic-gate /*ARGSUSED*/
19430Sstevel@tonic-gate void
ppp_send_config(unit,mtu,asyncmap,pcomp,accomp)19440Sstevel@tonic-gate ppp_send_config(unit, mtu, asyncmap, pcomp, accomp)
19450Sstevel@tonic-gate 	int unit;
19460Sstevel@tonic-gate 	int mtu;
19470Sstevel@tonic-gate 	u_int32_t asyncmap;
19480Sstevel@tonic-gate 	int pcomp;
19490Sstevel@tonic-gate 	int accomp;
19500Sstevel@tonic-gate {
19510Sstevel@tonic-gate 	uint32_t cf[2];
19520Sstevel@tonic-gate 
19530Sstevel@tonic-gate 	if (pppfd == -1) {
19540Sstevel@tonic-gate 		error("ppp_send_config called with invalid device handle");
19550Sstevel@tonic-gate 		return;
19560Sstevel@tonic-gate 	}
19570Sstevel@tonic-gate 	cf[0] =	link_mtu = mtu;
19580Sstevel@tonic-gate 	if (strioctl(pppfd, PPPIO_MTU, cf, sizeof (cf[0]), 0) < 0) {
19590Sstevel@tonic-gate 		if (hungup && errno == ENXIO) {
19600Sstevel@tonic-gate 			return;
19610Sstevel@tonic-gate 		}
19620Sstevel@tonic-gate 		error("Couldn't set MTU: %m");
19630Sstevel@tonic-gate 	}
19640Sstevel@tonic-gate 	if (fdmuxid != -1) {
19650Sstevel@tonic-gate 		if (!sync_serial) {
19660Sstevel@tonic-gate 			if (strioctl(pppfd, PPPIO_XACCM, &asyncmap,
19670Sstevel@tonic-gate 			    sizeof (asyncmap), 0) < 0) {
19680Sstevel@tonic-gate 				error("Couldn't set transmit ACCM: %m");
19690Sstevel@tonic-gate 			}
19700Sstevel@tonic-gate 		}
19710Sstevel@tonic-gate 		cf[0] = (pcomp? COMP_PROT: 0) + (accomp? COMP_AC: 0);
19720Sstevel@tonic-gate 		cf[1] = COMP_PROT | COMP_AC;
19730Sstevel@tonic-gate 
19740Sstevel@tonic-gate 		if (any_compressions() && strioctl(pppfd, PPPIO_CFLAGS, cf,
19750Sstevel@tonic-gate 		    sizeof (cf), sizeof (cf[0])) < 0) {
19760Sstevel@tonic-gate 			error("Couldn't set prot/AC compression: %m");
19770Sstevel@tonic-gate 		}
19780Sstevel@tonic-gate 	}
19790Sstevel@tonic-gate }
19800Sstevel@tonic-gate 
19810Sstevel@tonic-gate /*
19820Sstevel@tonic-gate  * ppp_set_xaccm()
19830Sstevel@tonic-gate  *
19840Sstevel@tonic-gate  * Set the extended transmit ACCM for the interface.
19850Sstevel@tonic-gate  */
19860Sstevel@tonic-gate /*ARGSUSED*/
19870Sstevel@tonic-gate void
ppp_set_xaccm(unit,accm)19880Sstevel@tonic-gate ppp_set_xaccm(unit, accm)
19890Sstevel@tonic-gate 	int unit;
19900Sstevel@tonic-gate 	ext_accm accm;
19910Sstevel@tonic-gate {
19920Sstevel@tonic-gate 	if (sync_serial) {
19930Sstevel@tonic-gate 		return;
19940Sstevel@tonic-gate 	}
19950Sstevel@tonic-gate 	if (fdmuxid != -1 && strioctl(pppfd, PPPIO_XACCM, accm,
19960Sstevel@tonic-gate 	    sizeof (ext_accm), 0) < 0) {
19970Sstevel@tonic-gate 		if (!hungup || errno != ENXIO) {
19980Sstevel@tonic-gate 			warn("Couldn't set extended ACCM: %m");
19990Sstevel@tonic-gate 		}
20000Sstevel@tonic-gate 	}
20010Sstevel@tonic-gate }
20020Sstevel@tonic-gate 
20030Sstevel@tonic-gate /*
20040Sstevel@tonic-gate  * ppp_recv_config()
20050Sstevel@tonic-gate  *
20060Sstevel@tonic-gate  * Configure the receive-side characteristics of the ppp interface.
20070Sstevel@tonic-gate  */
20080Sstevel@tonic-gate /*ARGSUSED*/
20090Sstevel@tonic-gate void
ppp_recv_config(unit,mru,asyncmap,pcomp,accomp)20100Sstevel@tonic-gate ppp_recv_config(unit, mru, asyncmap, pcomp, accomp)
20110Sstevel@tonic-gate 	int unit;
20120Sstevel@tonic-gate 	int mru;
20130Sstevel@tonic-gate 	u_int32_t asyncmap;
20140Sstevel@tonic-gate 	int pcomp;
20150Sstevel@tonic-gate 	int accomp;
20160Sstevel@tonic-gate {
20170Sstevel@tonic-gate 	uint32_t cf[2];
20180Sstevel@tonic-gate 
20190Sstevel@tonic-gate 	if (pppfd == -1) {
20200Sstevel@tonic-gate 		error("ppp_recv_config called with invalid device handle");
20210Sstevel@tonic-gate 		return;
20220Sstevel@tonic-gate 	}
20230Sstevel@tonic-gate 	cf[0] = mru;
20240Sstevel@tonic-gate 	if (strioctl(pppfd, PPPIO_MRU, cf, sizeof (cf[0]), 0) < 0) {
20250Sstevel@tonic-gate 		if (hungup && errno == ENXIO) {
20260Sstevel@tonic-gate 			return;
20270Sstevel@tonic-gate 		}
20280Sstevel@tonic-gate 		error("Couldn't set MRU: %m");
20290Sstevel@tonic-gate 	}
20300Sstevel@tonic-gate 	if (fdmuxid != -1) {
20310Sstevel@tonic-gate 		if (!sync_serial) {
20320Sstevel@tonic-gate 			if (strioctl(pppfd, PPPIO_RACCM, &asyncmap,
20330Sstevel@tonic-gate 			    sizeof (asyncmap), 0) < 0) {
20340Sstevel@tonic-gate 				error("Couldn't set receive ACCM: %m");
20350Sstevel@tonic-gate 			}
20360Sstevel@tonic-gate 		}
20370Sstevel@tonic-gate 		cf[0] = (pcomp ? DECOMP_PROT : 0) + (accomp ? DECOMP_AC : 0);
20380Sstevel@tonic-gate 		cf[1] = DECOMP_PROT | DECOMP_AC;
20390Sstevel@tonic-gate 
20400Sstevel@tonic-gate 		if (any_compressions() && strioctl(pppfd, PPPIO_CFLAGS, cf,
20410Sstevel@tonic-gate 		    sizeof (cf), sizeof (cf[0])) < 0) {
20420Sstevel@tonic-gate 			error("Couldn't set prot/AC decompression: %m");
20430Sstevel@tonic-gate 		}
20440Sstevel@tonic-gate 	}
20450Sstevel@tonic-gate }
20460Sstevel@tonic-gate 
20470Sstevel@tonic-gate #ifdef NEGOTIATE_FCS
20480Sstevel@tonic-gate /*
20490Sstevel@tonic-gate  * ppp_send_fcs()
20500Sstevel@tonic-gate  *
20510Sstevel@tonic-gate  * Configure the sender-side FCS.
20520Sstevel@tonic-gate  */
20530Sstevel@tonic-gate /*ARGSUSED*/
20540Sstevel@tonic-gate void
ppp_send_fcs(unit,fcstype)20550Sstevel@tonic-gate ppp_send_fcs(unit, fcstype)
20560Sstevel@tonic-gate 	int unit, fcstype;
20570Sstevel@tonic-gate {
20580Sstevel@tonic-gate 	uint32_t fcs;
20590Sstevel@tonic-gate 
20600Sstevel@tonic-gate 	if (sync_serial) {
20610Sstevel@tonic-gate 		return;
20620Sstevel@tonic-gate 	}
20630Sstevel@tonic-gate 
20640Sstevel@tonic-gate 	if (fcstype & FCSALT_32) {
20650Sstevel@tonic-gate 		fcs = PPPFCS_32;
20660Sstevel@tonic-gate 	} else if (fcstype & FCSALT_NULL) {
20670Sstevel@tonic-gate 		fcs = PPPFCS_NONE;
20680Sstevel@tonic-gate 	} else {
20690Sstevel@tonic-gate 		fcs = PPPFCS_16;
20700Sstevel@tonic-gate 	}
20710Sstevel@tonic-gate 	if (strioctl(pppfd, PPPIO_XFCS, &fcs, sizeof (fcs), 0) < 0) {
20720Sstevel@tonic-gate 		warn("Couldn't set transmit FCS: %m");
20730Sstevel@tonic-gate 	}
20740Sstevel@tonic-gate }
20750Sstevel@tonic-gate 
20760Sstevel@tonic-gate /*
20770Sstevel@tonic-gate  * ppp_recv_fcs()
20780Sstevel@tonic-gate  *
20790Sstevel@tonic-gate  * Configure the receiver-side FCS.
20800Sstevel@tonic-gate  */
20810Sstevel@tonic-gate /*ARGSUSED*/
20820Sstevel@tonic-gate void
ppp_recv_fcs(unit,fcstype)20830Sstevel@tonic-gate ppp_recv_fcs(unit, fcstype)
20840Sstevel@tonic-gate 	int unit, fcstype;
20850Sstevel@tonic-gate {
20860Sstevel@tonic-gate 	uint32_t fcs;
20870Sstevel@tonic-gate 
20880Sstevel@tonic-gate 	if (sync_serial) {
20890Sstevel@tonic-gate 		return;
20900Sstevel@tonic-gate 	}
20910Sstevel@tonic-gate 
20920Sstevel@tonic-gate 	if (fcstype & FCSALT_32) {
20930Sstevel@tonic-gate 		fcs = PPPFCS_32;
20940Sstevel@tonic-gate 	} else if (fcstype & FCSALT_NULL) {
20950Sstevel@tonic-gate 		fcs = PPPFCS_NONE;
20960Sstevel@tonic-gate 	} else {
20970Sstevel@tonic-gate 		fcs = PPPFCS_16;
20980Sstevel@tonic-gate 	}
20990Sstevel@tonic-gate 	if (strioctl(pppfd, PPPIO_RFCS, &fcs, sizeof (fcs), 0) < 0) {
21000Sstevel@tonic-gate 		warn("Couldn't set receive FCS: %m");
21010Sstevel@tonic-gate 	}
21020Sstevel@tonic-gate }
21030Sstevel@tonic-gate #endif
21040Sstevel@tonic-gate 
21050Sstevel@tonic-gate /*
21060Sstevel@tonic-gate  * ccp_test()
21070Sstevel@tonic-gate  *
21080Sstevel@tonic-gate  * Ask kernel whether a given compression method is acceptable for use.
21090Sstevel@tonic-gate  */
21100Sstevel@tonic-gate /*ARGSUSED*/
21110Sstevel@tonic-gate int
ccp_test(unit,opt_ptr,opt_len,for_transmit)21120Sstevel@tonic-gate ccp_test(unit, opt_ptr, opt_len, for_transmit)
21130Sstevel@tonic-gate 	int unit;
21140Sstevel@tonic-gate 	uchar_t *opt_ptr;
21150Sstevel@tonic-gate 	int opt_len;
21160Sstevel@tonic-gate 	int for_transmit;
21170Sstevel@tonic-gate {
21180Sstevel@tonic-gate 	if (strioctl(pppfd, (for_transmit ? PPPIO_XCOMP : PPPIO_RCOMP),
21190Sstevel@tonic-gate 	    opt_ptr, opt_len, 0) >= 0) {
21200Sstevel@tonic-gate 		return (1);
21210Sstevel@tonic-gate 	}
21220Sstevel@tonic-gate 	warn("Error in %s ioctl: %m",
21230Sstevel@tonic-gate 	    (for_transmit ? "PPPIO_XCOMP" : "PPPIO_RCOMP"));
21240Sstevel@tonic-gate 	return ((errno == ENOSR) ? 0 : -1);
21250Sstevel@tonic-gate }
21260Sstevel@tonic-gate 
21270Sstevel@tonic-gate #ifdef COMP_TUNE
21280Sstevel@tonic-gate /*
21290Sstevel@tonic-gate  * ccp_tune()
21300Sstevel@tonic-gate  *
21310Sstevel@tonic-gate  * Tune compression effort level.
21320Sstevel@tonic-gate  */
21330Sstevel@tonic-gate /*ARGSUSED*/
21340Sstevel@tonic-gate void
ccp_tune(unit,effort)21350Sstevel@tonic-gate ccp_tune(unit, effort)
21360Sstevel@tonic-gate 	int unit, effort;
21370Sstevel@tonic-gate {
21380Sstevel@tonic-gate 	uint32_t x;
21390Sstevel@tonic-gate 
21400Sstevel@tonic-gate 	x = effort;
21410Sstevel@tonic-gate 	if (strioctl(pppfd, PPPIO_COMPLEV, &x, sizeof (x), 0) < 0) {
21420Sstevel@tonic-gate 		warn("unable to set compression effort level: %m");
21430Sstevel@tonic-gate 	}
21440Sstevel@tonic-gate }
21450Sstevel@tonic-gate #endif
21460Sstevel@tonic-gate 
21470Sstevel@tonic-gate /*
21480Sstevel@tonic-gate  * ccp_flags_set()
21490Sstevel@tonic-gate  *
21500Sstevel@tonic-gate  * Inform kernel about the current state of CCP.
21510Sstevel@tonic-gate  */
21520Sstevel@tonic-gate /*ARGSUSED*/
21530Sstevel@tonic-gate void
ccp_flags_set(unit,isopen,isup)21540Sstevel@tonic-gate ccp_flags_set(unit, isopen, isup)
21550Sstevel@tonic-gate 	int unit, isopen, isup;
21560Sstevel@tonic-gate {
21570Sstevel@tonic-gate 	uint32_t cf[2];
21580Sstevel@tonic-gate 
21590Sstevel@tonic-gate 	cf[0] = (isopen ? CCP_ISOPEN : 0) + (isup ? CCP_ISUP : 0);
21600Sstevel@tonic-gate 	cf[1] = CCP_ISOPEN | CCP_ISUP | CCP_ERROR | CCP_FATALERROR;
21610Sstevel@tonic-gate 
21620Sstevel@tonic-gate 	if (strioctl(pppfd, PPPIO_CFLAGS, cf, sizeof (cf), sizeof (cf[0]))
21630Sstevel@tonic-gate 	    < 0) {
21640Sstevel@tonic-gate 		if (!hungup || errno != ENXIO) {
21650Sstevel@tonic-gate 			error("Couldn't set kernel CCP state: %m");
21660Sstevel@tonic-gate 		}
21670Sstevel@tonic-gate 	}
21680Sstevel@tonic-gate }
21690Sstevel@tonic-gate 
21700Sstevel@tonic-gate /*
21710Sstevel@tonic-gate  * get_idle_time()
21720Sstevel@tonic-gate  *
21730Sstevel@tonic-gate  * Return how long the link has been idle.
21740Sstevel@tonic-gate  */
21750Sstevel@tonic-gate /*ARGSUSED*/
21760Sstevel@tonic-gate int
get_idle_time(u,pids)21770Sstevel@tonic-gate get_idle_time(u, pids)
21780Sstevel@tonic-gate 	int u;
21790Sstevel@tonic-gate 	struct ppp_idle *pids;
21800Sstevel@tonic-gate {
21810Sstevel@tonic-gate 	int rc;
21820Sstevel@tonic-gate 
21830Sstevel@tonic-gate 	rc = strioctl(pppfd, PPPIO_GIDLE, pids, 0, sizeof (struct ppp_idle));
21840Sstevel@tonic-gate 	if (rc < 0) {
21850Sstevel@tonic-gate 		warn("unable to obtain idle time: %m");
21860Sstevel@tonic-gate 	}
21870Sstevel@tonic-gate 	return ((rc == 0) ? 1 : 0);
21880Sstevel@tonic-gate }
21890Sstevel@tonic-gate 
21900Sstevel@tonic-gate /*
21910Sstevel@tonic-gate  * get_ppp_stats()
21920Sstevel@tonic-gate  *
21930Sstevel@tonic-gate  * Return statistics for the link.
21940Sstevel@tonic-gate  */
21950Sstevel@tonic-gate /*ARGSUSED*/
21960Sstevel@tonic-gate int
get_ppp_stats(u,stats)21970Sstevel@tonic-gate get_ppp_stats(u, stats)
21980Sstevel@tonic-gate 	int u;
21990Sstevel@tonic-gate 	struct pppd_stats *stats;
22000Sstevel@tonic-gate {
22010Sstevel@tonic-gate 	struct ppp_stats64 s64;
22020Sstevel@tonic-gate 	struct ppp_stats s;
22030Sstevel@tonic-gate 
22040Sstevel@tonic-gate 	/* Try first to get these from the 64-bit interface */
22050Sstevel@tonic-gate 	if (strioctl(pppfd, PPPIO_GETSTAT64, &s64, 0, sizeof (s64)) >= 0) {
22060Sstevel@tonic-gate 		stats->bytes_in = s64.p.ppp_ibytes;
22070Sstevel@tonic-gate 		stats->bytes_out = s64.p.ppp_obytes;
22080Sstevel@tonic-gate 		stats->pkts_in = s64.p.ppp_ipackets;
22090Sstevel@tonic-gate 		stats->pkts_out = s64.p.ppp_opackets;
22100Sstevel@tonic-gate 		return (1);
22110Sstevel@tonic-gate 	}
22120Sstevel@tonic-gate 
22130Sstevel@tonic-gate 	if (strioctl(pppfd, PPPIO_GETSTAT, &s, 0, sizeof (s)) < 0) {
22140Sstevel@tonic-gate 		error("Couldn't get link statistics: %m");
22150Sstevel@tonic-gate 		return (0);
22160Sstevel@tonic-gate 	}
22170Sstevel@tonic-gate 	stats->bytes_in = s.p.ppp_ibytes;
22180Sstevel@tonic-gate 	stats->bytes_out = s.p.ppp_obytes;
22190Sstevel@tonic-gate 	stats->pkts_in = s.p.ppp_ipackets;
22200Sstevel@tonic-gate 	stats->pkts_out = s.p.ppp_opackets;
22210Sstevel@tonic-gate 	return (1);
22220Sstevel@tonic-gate }
22230Sstevel@tonic-gate 
22240Sstevel@tonic-gate #if defined(FILTER_PACKETS)
22250Sstevel@tonic-gate /*
22260Sstevel@tonic-gate  * set_filters()
22270Sstevel@tonic-gate  *
22280Sstevel@tonic-gate  * Transfer the pass and active filters to the kernel.
22290Sstevel@tonic-gate  */
22300Sstevel@tonic-gate int
set_filters(pass,active)22310Sstevel@tonic-gate set_filters(pass, active)
22320Sstevel@tonic-gate 	struct bpf_program *pass;
22330Sstevel@tonic-gate 	struct bpf_program *active;
22340Sstevel@tonic-gate {
22350Sstevel@tonic-gate 	int ret = 1;
22360Sstevel@tonic-gate 
22370Sstevel@tonic-gate 	if (pass->bf_len > 0) {
22380Sstevel@tonic-gate 		if (strioctl(pppfd, PPPIO_PASSFILT, pass,
22390Sstevel@tonic-gate 		    sizeof (struct bpf_program), 0) < 0) {
22400Sstevel@tonic-gate 			error("Couldn't set pass-filter in kernel: %m");
22410Sstevel@tonic-gate 			ret = 0;
22420Sstevel@tonic-gate 		}
22430Sstevel@tonic-gate 	}
22440Sstevel@tonic-gate 	if (active->bf_len > 0) {
22450Sstevel@tonic-gate 		if (strioctl(pppfd, PPPIO_ACTIVEFILT, active,
22460Sstevel@tonic-gate 		    sizeof (struct bpf_program), 0) < 0) {
22470Sstevel@tonic-gate 			error("Couldn't set active-filter in kernel: %m");
22480Sstevel@tonic-gate 			ret = 0;
22490Sstevel@tonic-gate 		}
22500Sstevel@tonic-gate 	}
22510Sstevel@tonic-gate 	return (ret);
22520Sstevel@tonic-gate }
22530Sstevel@tonic-gate #endif /* FILTER_PACKETS */
22540Sstevel@tonic-gate 
22550Sstevel@tonic-gate /*
22560Sstevel@tonic-gate  * ccp_fatal_error()
22570Sstevel@tonic-gate  *
22580Sstevel@tonic-gate  * Returns 1 if decompression was disabled as a result of an error detected
22590Sstevel@tonic-gate  * after decompression of a packet, 0 otherwise.  This is necessary because
22600Sstevel@tonic-gate  * of patent nonsense.
22610Sstevel@tonic-gate  */
22620Sstevel@tonic-gate /*ARGSUSED*/
22630Sstevel@tonic-gate int
ccp_fatal_error(unit)22640Sstevel@tonic-gate ccp_fatal_error(unit)
22650Sstevel@tonic-gate 	int unit;
22660Sstevel@tonic-gate {
22670Sstevel@tonic-gate 	uint32_t cf[2];
22680Sstevel@tonic-gate 
22690Sstevel@tonic-gate 	cf[0] = cf[1] = 0;
22700Sstevel@tonic-gate 	if (strioctl(pppfd, PPPIO_CFLAGS, cf, sizeof (cf), sizeof (cf[0]))
22710Sstevel@tonic-gate 	    < 0) {
22720Sstevel@tonic-gate 		if (errno != ENXIO && errno != EINVAL) {
22730Sstevel@tonic-gate 			error("Couldn't get compression flags: %m");
22740Sstevel@tonic-gate 		}
22750Sstevel@tonic-gate 		return (0);
22760Sstevel@tonic-gate 	}
22770Sstevel@tonic-gate 	return (cf[0] & CCP_FATALERROR);
22780Sstevel@tonic-gate }
22790Sstevel@tonic-gate 
22800Sstevel@tonic-gate /*
22810Sstevel@tonic-gate  * sifvjcomp()
22820Sstevel@tonic-gate  *
22830Sstevel@tonic-gate  * Config TCP header compression.
22840Sstevel@tonic-gate  */
22850Sstevel@tonic-gate /*ARGSUSED*/
22860Sstevel@tonic-gate int
sifvjcomp(u,vjcomp,xcidcomp,xmaxcid)22870Sstevel@tonic-gate sifvjcomp(u, vjcomp, xcidcomp, xmaxcid)
22880Sstevel@tonic-gate 	int u, vjcomp, xcidcomp, xmaxcid;
22890Sstevel@tonic-gate {
22900Sstevel@tonic-gate 	uint32_t cf[2];
22910Sstevel@tonic-gate 	uchar_t maxcid[2];
22920Sstevel@tonic-gate 
22930Sstevel@tonic-gate 	/*
22940Sstevel@tonic-gate 	 * Since VJ compression code is in the comp module, there's no
22950Sstevel@tonic-gate 	 * point of sending down any ioctls pertaining to VJ compression
22960Sstevel@tonic-gate 	 * when the module isn't pushed on the stream.
22970Sstevel@tonic-gate 	 */
22980Sstevel@tonic-gate 	if (!any_compressions()) {
22990Sstevel@tonic-gate 		return (1);
23000Sstevel@tonic-gate 	}
23010Sstevel@tonic-gate 
23020Sstevel@tonic-gate 	if (vjcomp) {
23030Sstevel@tonic-gate 		maxcid[0] = xcidcomp;
23040Sstevel@tonic-gate 		maxcid[1] = 15;		/* XXX should be rmaxcid */
23050Sstevel@tonic-gate 
23060Sstevel@tonic-gate 		if (strioctl(pppfd, PPPIO_VJINIT, maxcid,
23070Sstevel@tonic-gate 		    sizeof (maxcid), 0) < 0) {
23080Sstevel@tonic-gate 			error("Couldn't initialize VJ compression: %m");
23090Sstevel@tonic-gate 			return (0);
23100Sstevel@tonic-gate 		}
23110Sstevel@tonic-gate 	}
23120Sstevel@tonic-gate 
23130Sstevel@tonic-gate 	cf[0] = (vjcomp ? COMP_VJC + DECOMP_VJC : 0)	/* XXX this is wrong */
23140Sstevel@tonic-gate 		+ (xcidcomp? COMP_VJCCID + DECOMP_VJCCID: 0);
23150Sstevel@tonic-gate 
23160Sstevel@tonic-gate 	cf[1] = COMP_VJC + DECOMP_VJC + COMP_VJCCID + DECOMP_VJCCID;
23170Sstevel@tonic-gate 
23180Sstevel@tonic-gate 	if (strioctl(pppfd, PPPIO_CFLAGS, cf, sizeof (cf), sizeof (cf[0]))
23190Sstevel@tonic-gate 	    < 0) {
23200Sstevel@tonic-gate 		if (vjcomp) {
23210Sstevel@tonic-gate 			error("Couldn't enable VJ compression: %m");
23220Sstevel@tonic-gate 		} else {
23230Sstevel@tonic-gate 			error("Couldn't disable VJ compression: %m");
23240Sstevel@tonic-gate 		}
23250Sstevel@tonic-gate 		return (0);
23260Sstevel@tonic-gate 	}
23270Sstevel@tonic-gate 	return (1);
23280Sstevel@tonic-gate }
23290Sstevel@tonic-gate 
23300Sstevel@tonic-gate /*
23310Sstevel@tonic-gate  * siflags()
23320Sstevel@tonic-gate  *
23330Sstevel@tonic-gate  * Set or clear the IP interface flags.
23340Sstevel@tonic-gate  */
23350Sstevel@tonic-gate int
siflags(f,set)23360Sstevel@tonic-gate siflags(f, set)
23370Sstevel@tonic-gate 	u_int32_t f;
23380Sstevel@tonic-gate 	int set;
23390Sstevel@tonic-gate {
23400Sstevel@tonic-gate 	struct ifreq ifr;
23410Sstevel@tonic-gate 
23420Sstevel@tonic-gate 	if (!IPCP_ENABLED || (ipmuxid == -1)) {
23430Sstevel@tonic-gate 		return (0);
23440Sstevel@tonic-gate 	}
23450Sstevel@tonic-gate 	if (ipfd == -1 && open_ipfd() == -1)
23460Sstevel@tonic-gate 		return (0);
23470Sstevel@tonic-gate 	BZERO(&ifr, sizeof (ifr));
23480Sstevel@tonic-gate 	(void) strlcpy(ifr.ifr_name, ifname, sizeof (ifr.ifr_name));
23490Sstevel@tonic-gate 	if (myioctl(ipfd, SIOCGIFFLAGS, &ifr) < 0) {
23500Sstevel@tonic-gate 		error("Couldn't get IP interface flags: %m");
23510Sstevel@tonic-gate 		return (0);
23520Sstevel@tonic-gate 	}
23530Sstevel@tonic-gate 	if (set) {
23540Sstevel@tonic-gate 		ifr.ifr_flags |= f;
23550Sstevel@tonic-gate 	} else {
23560Sstevel@tonic-gate 		ifr.ifr_flags &= ~f;
23570Sstevel@tonic-gate 	}
23580Sstevel@tonic-gate 	if (myioctl(ipfd, SIOCSIFFLAGS, &ifr) < 0) {
23590Sstevel@tonic-gate 		error("Couldn't set IP interface flags: %m");
23600Sstevel@tonic-gate 		return (0);
23610Sstevel@tonic-gate 	}
23620Sstevel@tonic-gate 	return (1);
23630Sstevel@tonic-gate }
23640Sstevel@tonic-gate 
23650Sstevel@tonic-gate /*
23660Sstevel@tonic-gate  * sifup()
23670Sstevel@tonic-gate  *
23680Sstevel@tonic-gate  * Config the interface up and enable IP packets to pass.
23690Sstevel@tonic-gate  */
23700Sstevel@tonic-gate /*ARGSUSED*/
23710Sstevel@tonic-gate int
sifup(u)23720Sstevel@tonic-gate sifup(u)
23730Sstevel@tonic-gate 	int u;
23740Sstevel@tonic-gate {
23750Sstevel@tonic-gate 	if (if_is_up) {
23760Sstevel@tonic-gate 		return (1);
23770Sstevel@tonic-gate 	} else if (!IPCP_ENABLED) {
23780Sstevel@tonic-gate 		warn("sifup called when IPCP is disabled");
23790Sstevel@tonic-gate 		return (0);
23800Sstevel@tonic-gate 	} else if (ipmuxid == -1) {
23810Sstevel@tonic-gate 		warn("sifup called in wrong state");
23820Sstevel@tonic-gate 		return (0);
23830Sstevel@tonic-gate 	} else if (!siflags(IFF_UP, 1)) {
23840Sstevel@tonic-gate 		error("Unable to mark the IP interface UP");
23850Sstevel@tonic-gate 		return (0);
23860Sstevel@tonic-gate 	}
23870Sstevel@tonic-gate 	if_is_up = 1;
23880Sstevel@tonic-gate 	return (1);
23890Sstevel@tonic-gate }
23900Sstevel@tonic-gate 
23910Sstevel@tonic-gate /*
23920Sstevel@tonic-gate  * sifdown()
23930Sstevel@tonic-gate  *
23940Sstevel@tonic-gate  * Config the interface down and disable IP.  Possibly called from die(),
23950Sstevel@tonic-gate  * so there shouldn't be any call to die() here.
23960Sstevel@tonic-gate  */
23970Sstevel@tonic-gate /*ARGSUSED*/
23980Sstevel@tonic-gate int
sifdown(u)23990Sstevel@tonic-gate sifdown(u)
24000Sstevel@tonic-gate 	int u;
24010Sstevel@tonic-gate {
24020Sstevel@tonic-gate 	if (!IPCP_ENABLED) {
24030Sstevel@tonic-gate 		warn("sifdown called when IPCP is disabled");
24040Sstevel@tonic-gate 		return (0);
24050Sstevel@tonic-gate 	} else if (!if_is_up || (ipmuxid == -1)) {
24060Sstevel@tonic-gate 		return (1);
24070Sstevel@tonic-gate 	} else if (!siflags(IFF_UP, 0)) {
24080Sstevel@tonic-gate 		error("Unable to mark the IP interface DOWN");
24090Sstevel@tonic-gate 		return (0);
24100Sstevel@tonic-gate 	}
24110Sstevel@tonic-gate 	if_is_up = 0;
24120Sstevel@tonic-gate 	return (1);
24130Sstevel@tonic-gate }
24140Sstevel@tonic-gate 
24150Sstevel@tonic-gate /*
24160Sstevel@tonic-gate  * sifnpmode()
24170Sstevel@tonic-gate  *
24180Sstevel@tonic-gate  * Set the mode for handling packets for a given NP.  Not worried
24190Sstevel@tonic-gate  * about performance here since this is done only rarely.
24200Sstevel@tonic-gate  */
24210Sstevel@tonic-gate /*ARGSUSED*/
24220Sstevel@tonic-gate int
sifnpmode(u,proto,mode)24230Sstevel@tonic-gate sifnpmode(u, proto, mode)
24240Sstevel@tonic-gate 	int u;
24250Sstevel@tonic-gate 	int proto;
24260Sstevel@tonic-gate 	enum NPmode mode;
24270Sstevel@tonic-gate {
24280Sstevel@tonic-gate 	uint32_t npi[2];
24290Sstevel@tonic-gate 	const char *cp;
24300Sstevel@tonic-gate 	static const struct npi_entry {
24310Sstevel@tonic-gate 		enum NPmode ne_value;
24320Sstevel@tonic-gate 		const char *ne_name;
24330Sstevel@tonic-gate 	} npi_list[] = {
24340Sstevel@tonic-gate 		{ NPMODE_PASS, "pass" },
24350Sstevel@tonic-gate 		{ NPMODE_DROP, "drop" },
24360Sstevel@tonic-gate 		{ NPMODE_ERROR, "error" },
24370Sstevel@tonic-gate 		{ NPMODE_QUEUE, "queue" },
24380Sstevel@tonic-gate 	};
24390Sstevel@tonic-gate 	int i;
24400Sstevel@tonic-gate 	char pname[32], mname[32];
24410Sstevel@tonic-gate 
24420Sstevel@tonic-gate 	npi[0] = proto;
24430Sstevel@tonic-gate 	npi[1] = (uint32_t)mode;
24440Sstevel@tonic-gate 
24450Sstevel@tonic-gate 	cp = protocol_name(proto);
24460Sstevel@tonic-gate 	if (cp == NULL)
24470Sstevel@tonic-gate 		(void) slprintf(pname, sizeof (pname), "NP %04X", proto);
24480Sstevel@tonic-gate 	else
24490Sstevel@tonic-gate 		(void) strlcpy(pname, cp, sizeof (pname));
24500Sstevel@tonic-gate 	for (i = 0; i < Dim(npi_list); i++)
24510Sstevel@tonic-gate 		if (npi_list[i].ne_value == mode)
24520Sstevel@tonic-gate 			break;
24530Sstevel@tonic-gate 	if (i >= Dim(npi_list))
24540Sstevel@tonic-gate 		(void) slprintf(mname, sizeof (mname), "mode %d", (int)mode);
24550Sstevel@tonic-gate 	else
24560Sstevel@tonic-gate 		(void) strlcpy(mname, npi_list[i].ne_name, sizeof (mname));
24570Sstevel@tonic-gate 
24580Sstevel@tonic-gate 	if ((proto == PPP_IP && !if_is_up) ||
24590Sstevel@tonic-gate 	    (proto == PPP_IPV6 && !if6_is_up)) {
24600Sstevel@tonic-gate 		dbglog("ignoring request to set %s to %s", pname, mname);
24610Sstevel@tonic-gate 		return (1);
24620Sstevel@tonic-gate 	}
24630Sstevel@tonic-gate 	if (strioctl(pppfd, PPPIO_NPMODE, npi, sizeof (npi), 0) < 0) {
24640Sstevel@tonic-gate 		error("unable to set %s to %s: %m", pname, mname);
24650Sstevel@tonic-gate 		return (0);
24660Sstevel@tonic-gate 	}
24670Sstevel@tonic-gate 	return (1);
24680Sstevel@tonic-gate }
24690Sstevel@tonic-gate 
24700Sstevel@tonic-gate /*
24710Sstevel@tonic-gate  * sifmtu()
24720Sstevel@tonic-gate  *
24730Sstevel@tonic-gate  * Config the interface IP MTU.
24740Sstevel@tonic-gate  */
24750Sstevel@tonic-gate int
sifmtu(mtu)24760Sstevel@tonic-gate sifmtu(mtu)
24770Sstevel@tonic-gate 	int mtu;
24780Sstevel@tonic-gate {
24790Sstevel@tonic-gate 	struct ifreq ifr;
24800Sstevel@tonic-gate 
24810Sstevel@tonic-gate 	if (!IPCP_ENABLED || (ipmuxid == -1)) {
24820Sstevel@tonic-gate 		return (0);
24830Sstevel@tonic-gate 	}
24840Sstevel@tonic-gate 	if (ipfd == -1 && open_ipfd() == -1)
24850Sstevel@tonic-gate 		return (0);
24860Sstevel@tonic-gate 	BZERO(&ifr, sizeof (ifr));
24870Sstevel@tonic-gate 	(void) strlcpy(ifr.ifr_name, ifname, sizeof (ifr.ifr_name));
24880Sstevel@tonic-gate 	ifr.ifr_metric = mtu;
24890Sstevel@tonic-gate 	if (myioctl(ipfd, SIOCSIFMTU, &ifr) < 0) {
24900Sstevel@tonic-gate 		error("Couldn't set IP MTU on %s to %d: %m", ifr.ifr_name,
24910Sstevel@tonic-gate 		    mtu);
24920Sstevel@tonic-gate 		return (0);
24930Sstevel@tonic-gate 	}
24940Sstevel@tonic-gate 	return (1);
24950Sstevel@tonic-gate }
24960Sstevel@tonic-gate 
24970Sstevel@tonic-gate /*
24980Sstevel@tonic-gate  * sifaddr()
24990Sstevel@tonic-gate  *
25000Sstevel@tonic-gate  * Config the interface IP addresses and netmask.
25010Sstevel@tonic-gate  */
25020Sstevel@tonic-gate /*ARGSUSED*/
25030Sstevel@tonic-gate int
sifaddr(u,o,h,m)25040Sstevel@tonic-gate sifaddr(u, o, h, m)
25050Sstevel@tonic-gate 	int u;
25060Sstevel@tonic-gate 	u_int32_t o;
25070Sstevel@tonic-gate 	u_int32_t h;
25080Sstevel@tonic-gate 	u_int32_t m;
25090Sstevel@tonic-gate {
25100Sstevel@tonic-gate 	struct ifreq ifr;
25110Sstevel@tonic-gate 	struct sockaddr_in sin;
25120Sstevel@tonic-gate 
25130Sstevel@tonic-gate 	if (!IPCP_ENABLED || (ipmuxid == -1 && plumb_ipif(u) == 0)) {
25140Sstevel@tonic-gate 		return (0);
25150Sstevel@tonic-gate 	}
25160Sstevel@tonic-gate 	if (ipfd == -1 && open_ipfd() == -1)
25170Sstevel@tonic-gate 		return (0);
25180Sstevel@tonic-gate 	/*
25190Sstevel@tonic-gate 	 * Set the IP interface MTU.
25200Sstevel@tonic-gate 	 */
25210Sstevel@tonic-gate 	if (!sifmtu(link_mtu)) {
25220Sstevel@tonic-gate 		return (0);
25230Sstevel@tonic-gate 	}
25240Sstevel@tonic-gate 	/*
25250Sstevel@tonic-gate 	 * Set the IP interface local point-to-point address.
25260Sstevel@tonic-gate 	 */
25270Sstevel@tonic-gate 	BZERO(&sin, sizeof (sin));
25280Sstevel@tonic-gate 	sin.sin_family = AF_INET;
25290Sstevel@tonic-gate 	sin.sin_addr.s_addr = o;
25300Sstevel@tonic-gate 
25310Sstevel@tonic-gate 	BZERO(&ifr, sizeof (ifr));
25320Sstevel@tonic-gate 	(void) strlcpy(ifr.ifr_name, ifname, sizeof (ifr.ifr_name));
25330Sstevel@tonic-gate 	ifr.ifr_addr = *(struct sockaddr *)&sin;
25340Sstevel@tonic-gate 	if (myioctl(ipfd, SIOCSIFADDR, &ifr) < 0) {
25350Sstevel@tonic-gate 		error("Couldn't set local IP address (%s): %m", ifr.ifr_name);
25360Sstevel@tonic-gate 		return (0);
25370Sstevel@tonic-gate 	}
25380Sstevel@tonic-gate 	/*
25390Sstevel@tonic-gate 	 * Set the IP interface remote point-to-point address.
25400Sstevel@tonic-gate 	 */
25410Sstevel@tonic-gate 	sin.sin_addr.s_addr = h;
25420Sstevel@tonic-gate 
25430Sstevel@tonic-gate 	ifr.ifr_dstaddr = *(struct sockaddr *)&sin;
25440Sstevel@tonic-gate 	if (myioctl(ipfd, SIOCSIFDSTADDR, &ifr) < 0) {
25450Sstevel@tonic-gate 		error("Couldn't set remote IP address (%s): %m", ifr.ifr_name);
25460Sstevel@tonic-gate 		return (0);
25470Sstevel@tonic-gate 	}
25480Sstevel@tonic-gate 	remote_addr = h;
25490Sstevel@tonic-gate 	return (1);
25500Sstevel@tonic-gate }
25510Sstevel@tonic-gate 
25520Sstevel@tonic-gate /*
25530Sstevel@tonic-gate  * cifaddr()
25540Sstevel@tonic-gate  *
25550Sstevel@tonic-gate  * Clear the interface IP addresses.
25560Sstevel@tonic-gate  */
25570Sstevel@tonic-gate /*ARGSUSED*/
25580Sstevel@tonic-gate int
cifaddr(u,o,h)25590Sstevel@tonic-gate cifaddr(u, o, h)
25600Sstevel@tonic-gate 	int u;
25610Sstevel@tonic-gate 	u_int32_t o;
25620Sstevel@tonic-gate 	u_int32_t h;
25630Sstevel@tonic-gate {
25640Sstevel@tonic-gate 	if (!IPCP_ENABLED) {
25650Sstevel@tonic-gate 		return (0);
25660Sstevel@tonic-gate 	}
25670Sstevel@tonic-gate 	/*
25680Sstevel@tonic-gate 	 * Most of the work is done in sifdown().
25690Sstevel@tonic-gate 	 */
25700Sstevel@tonic-gate 	remote_addr = 0;
25710Sstevel@tonic-gate 	return (1);
25720Sstevel@tonic-gate }
25730Sstevel@tonic-gate 
25740Sstevel@tonic-gate /*
25750Sstevel@tonic-gate  * sifroute()
25760Sstevel@tonic-gate  *
25770Sstevel@tonic-gate  * Add or delete a route.
25780Sstevel@tonic-gate  */
25790Sstevel@tonic-gate /*ARGSUSED*/
25800Sstevel@tonic-gate static int
sifroute(int u,u_int32_t l,u_int32_t g,int add,const char * str)25810Sstevel@tonic-gate sifroute(int u, u_int32_t l, u_int32_t g, int add, const char *str)
25820Sstevel@tonic-gate {
25830Sstevel@tonic-gate 	struct sockaddr_in sin_dst, sin_gtw;
25840Sstevel@tonic-gate 	struct rtentry rt;
25850Sstevel@tonic-gate 
25860Sstevel@tonic-gate 	if (!IPCP_ENABLED || (ipmuxid == -1)) {
25870Sstevel@tonic-gate 		error("Can't %s route: IP is not enabled", str);
25880Sstevel@tonic-gate 		return (0);
25890Sstevel@tonic-gate 	}
25900Sstevel@tonic-gate 	if (ipfd == -1 && open_ipfd() == -1)
25910Sstevel@tonic-gate 		return (0);
25920Sstevel@tonic-gate 
25930Sstevel@tonic-gate 	BZERO(&sin_dst, sizeof (sin_dst));
25940Sstevel@tonic-gate 	sin_dst.sin_family = AF_INET;
25950Sstevel@tonic-gate 	sin_dst.sin_addr.s_addr = l;
25960Sstevel@tonic-gate 
25970Sstevel@tonic-gate 	BZERO(&sin_gtw, sizeof (sin_gtw));
25980Sstevel@tonic-gate 	sin_gtw.sin_family = AF_INET;
25990Sstevel@tonic-gate 	sin_gtw.sin_addr.s_addr = g;
26000Sstevel@tonic-gate 
26010Sstevel@tonic-gate 	BZERO(&rt, sizeof (rt));
26020Sstevel@tonic-gate 	rt.rt_dst = *(struct sockaddr *)&sin_dst;
26030Sstevel@tonic-gate 	rt.rt_gateway = *(struct sockaddr *)&sin_gtw;
26040Sstevel@tonic-gate 	rt.rt_flags = (RTF_GATEWAY|RTF_STATIC);
26050Sstevel@tonic-gate 
26060Sstevel@tonic-gate 	if (myioctl(ipfd, (add ? SIOCADDRT : SIOCDELRT), &rt) < 0) {
26070Sstevel@tonic-gate 		error("Can't %s route: %m", str);
26080Sstevel@tonic-gate 		return (0);
26090Sstevel@tonic-gate 	}
26100Sstevel@tonic-gate 	return (1);
26110Sstevel@tonic-gate }
26120Sstevel@tonic-gate 
26130Sstevel@tonic-gate /*
26140Sstevel@tonic-gate  * sifdefaultroute()
26150Sstevel@tonic-gate  *
26160Sstevel@tonic-gate  * Assign a default route through the address given.
26170Sstevel@tonic-gate  */
26180Sstevel@tonic-gate /*ARGSUSED*/
26190Sstevel@tonic-gate int
sifdefaultroute(u,l,g)26200Sstevel@tonic-gate sifdefaultroute(u, l, g)
26210Sstevel@tonic-gate 	int u;
26220Sstevel@tonic-gate 	u_int32_t l;
26230Sstevel@tonic-gate 	u_int32_t g;
26240Sstevel@tonic-gate {
26250Sstevel@tonic-gate 	if (!sifroute(u, 0, g, 1, "add default")) {
26260Sstevel@tonic-gate 		return (0);
26270Sstevel@tonic-gate 	}
26280Sstevel@tonic-gate 	default_route_gateway = g;
26290Sstevel@tonic-gate 	return (1);
26300Sstevel@tonic-gate }
26310Sstevel@tonic-gate 
26320Sstevel@tonic-gate /*
26330Sstevel@tonic-gate  * cifdefaultroute()
26340Sstevel@tonic-gate  *
26350Sstevel@tonic-gate  * Delete a default route through the address given.
26360Sstevel@tonic-gate  */
26370Sstevel@tonic-gate /*ARGSUSED*/
26380Sstevel@tonic-gate int
cifdefaultroute(u,l,g)26390Sstevel@tonic-gate cifdefaultroute(u, l, g)
26400Sstevel@tonic-gate 	int u;
26410Sstevel@tonic-gate 	u_int32_t l;
26420Sstevel@tonic-gate 	u_int32_t g;
26430Sstevel@tonic-gate {
26440Sstevel@tonic-gate 	if (!sifroute(u, 0, g, 0, "delete default")) {
26450Sstevel@tonic-gate 		return (0);
26460Sstevel@tonic-gate 	}
26470Sstevel@tonic-gate 	default_route_gateway = 0;
26480Sstevel@tonic-gate 	return (1);
26490Sstevel@tonic-gate }
26500Sstevel@tonic-gate 
26510Sstevel@tonic-gate /*
26520Sstevel@tonic-gate  * sifproxyarp()
26530Sstevel@tonic-gate  *
26540Sstevel@tonic-gate  * Make a proxy ARP entry for the peer.
26550Sstevel@tonic-gate  */
26560Sstevel@tonic-gate /*ARGSUSED*/
26570Sstevel@tonic-gate int
sifproxyarp(unit,hisaddr,quietflag)26580Sstevel@tonic-gate sifproxyarp(unit, hisaddr, quietflag)
26590Sstevel@tonic-gate 	int unit;
26600Sstevel@tonic-gate 	u_int32_t hisaddr;
26610Sstevel@tonic-gate 	int quietflag;
26620Sstevel@tonic-gate {
26630Sstevel@tonic-gate 	struct sockaddr_in sin;
26640Sstevel@tonic-gate 	struct xarpreq arpreq;
26650Sstevel@tonic-gate 	const uchar_t *cp;
26660Sstevel@tonic-gate 	char *str = NULL;
26670Sstevel@tonic-gate 
26680Sstevel@tonic-gate 	if (!IPCP_ENABLED || (ipmuxid == -1)) {
26690Sstevel@tonic-gate 		return (0);
26700Sstevel@tonic-gate 	}
26710Sstevel@tonic-gate 	if (ipfd == -1 && open_ipfd() == -1)
26720Sstevel@tonic-gate 		return (0);
26730Sstevel@tonic-gate 
26740Sstevel@tonic-gate 	BZERO(&sin, sizeof (sin));
26750Sstevel@tonic-gate 	sin.sin_family = AF_INET;
26760Sstevel@tonic-gate 	sin.sin_addr.s_addr = hisaddr;
26770Sstevel@tonic-gate 
26780Sstevel@tonic-gate 	BZERO(&arpreq, sizeof (arpreq));
26790Sstevel@tonic-gate 	if (!get_ether_addr(hisaddr, &arpreq.xarp_ha, quietflag)) {
26800Sstevel@tonic-gate 		return (0);
26810Sstevel@tonic-gate 	}
26820Sstevel@tonic-gate 	BCOPY(&sin, &arpreq.xarp_pa, sizeof (sin));
26830Sstevel@tonic-gate 	arpreq.xarp_flags = ATF_PERM | ATF_PUBL;
26840Sstevel@tonic-gate 	arpreq.xarp_ha.sdl_family = AF_LINK;
26850Sstevel@tonic-gate 
26860Sstevel@tonic-gate 	if (myioctl(ipfd, SIOCSXARP, (caddr_t)&arpreq) < 0) {
26870Sstevel@tonic-gate 		if (!quietflag)
26880Sstevel@tonic-gate 			error("Couldn't set proxy ARP entry: %m");
26890Sstevel@tonic-gate 		return (0);
26900Sstevel@tonic-gate 	}
26910Sstevel@tonic-gate 	cp = (const uchar_t *)LLADDR(&arpreq.xarp_ha);
26920Sstevel@tonic-gate 	str = _link_ntoa(cp, str, arpreq.xarp_ha.sdl_alen, IFT_OTHER);
26930Sstevel@tonic-gate 	if (str != NULL) {
26940Sstevel@tonic-gate 		dbglog("established proxy ARP for %I using %s", hisaddr,
26950Sstevel@tonic-gate 		    str);
26960Sstevel@tonic-gate 		free(str);
26970Sstevel@tonic-gate 	}
26980Sstevel@tonic-gate 	proxy_arp_addr = hisaddr;
26990Sstevel@tonic-gate 	return (1);
27000Sstevel@tonic-gate }
27010Sstevel@tonic-gate 
27020Sstevel@tonic-gate /*
27030Sstevel@tonic-gate  * cifproxyarp()
27040Sstevel@tonic-gate  *
27050Sstevel@tonic-gate  * Delete the proxy ARP entry for the peer.
27060Sstevel@tonic-gate  */
27070Sstevel@tonic-gate /*ARGSUSED*/
27080Sstevel@tonic-gate int
cifproxyarp(unit,hisaddr)27090Sstevel@tonic-gate cifproxyarp(unit, hisaddr)
27100Sstevel@tonic-gate 	int unit;
27110Sstevel@tonic-gate 	u_int32_t hisaddr;
27120Sstevel@tonic-gate {
27130Sstevel@tonic-gate 	struct sockaddr_in sin;
27140Sstevel@tonic-gate 	struct xarpreq arpreq;
27150Sstevel@tonic-gate 
27160Sstevel@tonic-gate 	if (!IPCP_ENABLED || (ipmuxid == -1)) {
27170Sstevel@tonic-gate 		return (0);
27180Sstevel@tonic-gate 	}
27190Sstevel@tonic-gate 	if (ipfd == -1 && open_ipfd() == -1)
27200Sstevel@tonic-gate 		return (0);
27210Sstevel@tonic-gate 
27220Sstevel@tonic-gate 	BZERO(&sin, sizeof (sin));
27230Sstevel@tonic-gate 	sin.sin_family = AF_INET;
27240Sstevel@tonic-gate 	sin.sin_addr.s_addr = hisaddr;
27250Sstevel@tonic-gate 
27260Sstevel@tonic-gate 	BZERO(&arpreq, sizeof (arpreq));
27270Sstevel@tonic-gate 	BCOPY(&sin, &arpreq.xarp_pa, sizeof (sin));
27280Sstevel@tonic-gate 	arpreq.xarp_ha.sdl_family = AF_LINK;
27290Sstevel@tonic-gate 
27300Sstevel@tonic-gate 	if (myioctl(ipfd, SIOCDXARP, (caddr_t)&arpreq) < 0) {
27310Sstevel@tonic-gate 		error("Couldn't delete proxy ARP entry: %m");
27320Sstevel@tonic-gate 		return (0);
27330Sstevel@tonic-gate 	}
27340Sstevel@tonic-gate 	proxy_arp_addr = 0;
27350Sstevel@tonic-gate 	return (1);
27360Sstevel@tonic-gate }
27370Sstevel@tonic-gate 
27380Sstevel@tonic-gate /*
27390Sstevel@tonic-gate  * get_ether_addr()
27400Sstevel@tonic-gate  *
27410Sstevel@tonic-gate  * Get the hardware address of an interface on the the same subnet as
27420Sstevel@tonic-gate  * ipaddr.  This routine uses old-style interfaces for intentional
27430Sstevel@tonic-gate  * backward compatibility -- SIOCGLIF* isn't in older Solaris
27440Sstevel@tonic-gate  * releases.
27450Sstevel@tonic-gate  */
27460Sstevel@tonic-gate static int
get_ether_addr(u_int32_t ipaddr,struct sockaddr_dl * hwaddr,int quietflag)27470Sstevel@tonic-gate get_ether_addr(u_int32_t ipaddr, struct sockaddr_dl *hwaddr, int quietflag)
27480Sstevel@tonic-gate {
27490Sstevel@tonic-gate 	struct ifreq *ifr, *ifend, ifreq;
27500Sstevel@tonic-gate 	int nif, s, retv;
27510Sstevel@tonic-gate 	struct ifconf ifc;
27520Sstevel@tonic-gate 	u_int32_t ina, mask;
27530Sstevel@tonic-gate 	struct xarpreq req;
27540Sstevel@tonic-gate 	struct sockaddr_in sin;
27550Sstevel@tonic-gate 
27560Sstevel@tonic-gate 	if (ipfd == -1 && open_ipfd() == -1)
27570Sstevel@tonic-gate 		return (0);
27580Sstevel@tonic-gate 
27590Sstevel@tonic-gate 	/*
27600Sstevel@tonic-gate 	 * Scan through the system's network interfaces.
27610Sstevel@tonic-gate 	 */
27620Sstevel@tonic-gate 	if (myioctl(ipfd, SIOCGIFNUM, &nif) < 0) {
27630Sstevel@tonic-gate 		nif = MAXIFS;
27640Sstevel@tonic-gate 	}
27650Sstevel@tonic-gate 	if (nif <= 0)
27660Sstevel@tonic-gate 		return (0);
27670Sstevel@tonic-gate 	ifc.ifc_len = nif * sizeof (struct ifreq);
27680Sstevel@tonic-gate 	ifc.ifc_buf = (caddr_t)malloc(ifc.ifc_len);
27690Sstevel@tonic-gate 	if (ifc.ifc_buf == NULL) {
27700Sstevel@tonic-gate 		return (0);
27710Sstevel@tonic-gate 	}
27720Sstevel@tonic-gate 	if (myioctl(ipfd, SIOCGIFCONF, &ifc) < 0) {
27730Sstevel@tonic-gate 		error("Couldn't get system interface list: %m");
27740Sstevel@tonic-gate 		free(ifc.ifc_buf);
27750Sstevel@tonic-gate 		return (0);
27760Sstevel@tonic-gate 	}
27770Sstevel@tonic-gate 	/* LINTED */
27780Sstevel@tonic-gate 	ifend = (struct ifreq *)(ifc.ifc_buf + ifc.ifc_len);
27790Sstevel@tonic-gate 	for (ifr = ifc.ifc_req; ifr < ifend; ++ifr) {
27800Sstevel@tonic-gate 		if (ifr->ifr_addr.sa_family != AF_INET) {
27810Sstevel@tonic-gate 			continue;
27820Sstevel@tonic-gate 		}
27830Sstevel@tonic-gate 		/*
27840Sstevel@tonic-gate 		 * Check that the interface is up, and not
27850Sstevel@tonic-gate 		 * point-to-point or loopback.
27860Sstevel@tonic-gate 		 */
27870Sstevel@tonic-gate 		(void) strlcpy(ifreq.ifr_name, ifr->ifr_name,
27886631Sss150715 		    sizeof (ifreq.ifr_name));
27890Sstevel@tonic-gate 		if (myioctl(ipfd, SIOCGIFFLAGS, &ifreq) < 0) {
27900Sstevel@tonic-gate 			continue;
27910Sstevel@tonic-gate 		}
27920Sstevel@tonic-gate 		if ((ifreq.ifr_flags & (IFF_UP|IFF_BROADCAST|IFF_POINTOPOINT|
27930Sstevel@tonic-gate 		    IFF_LOOPBACK|IFF_NOARP)) != (IFF_UP|IFF_BROADCAST)) {
27940Sstevel@tonic-gate 			continue;
27950Sstevel@tonic-gate 		}
27960Sstevel@tonic-gate 		/*
27970Sstevel@tonic-gate 		 * Get its netmask and check that it's on the right subnet.
27980Sstevel@tonic-gate 		 */
27990Sstevel@tonic-gate 		if (myioctl(ipfd, SIOCGIFNETMASK, &ifreq) < 0) {
28000Sstevel@tonic-gate 			continue;
28010Sstevel@tonic-gate 		}
28020Sstevel@tonic-gate 		(void) memcpy(&sin, &ifr->ifr_addr, sizeof (sin));
28030Sstevel@tonic-gate 		ina = sin.sin_addr.s_addr;
28040Sstevel@tonic-gate 		(void) memcpy(&sin, &ifreq.ifr_addr, sizeof (sin));
28050Sstevel@tonic-gate 		mask = sin.sin_addr.s_addr;
28060Sstevel@tonic-gate 		if ((ipaddr & mask) == (ina & mask)) {
28070Sstevel@tonic-gate 			break;
28080Sstevel@tonic-gate 		}
28090Sstevel@tonic-gate 	}
28100Sstevel@tonic-gate 	if (ifr >= ifend) {
28110Sstevel@tonic-gate 		if (!quietflag)
28120Sstevel@tonic-gate 			warn("No suitable interface found for proxy ARP of %I",
28130Sstevel@tonic-gate 			    ipaddr);
28140Sstevel@tonic-gate 		free(ifc.ifc_buf);
28150Sstevel@tonic-gate 		return (0);
28160Sstevel@tonic-gate 	}
28170Sstevel@tonic-gate 	info("found interface %s for proxy ARP of %I", ifr->ifr_name, ipaddr);
28180Sstevel@tonic-gate 
28190Sstevel@tonic-gate 	/*
28200Sstevel@tonic-gate 	 * New way - get the address by doing an arp request.
28210Sstevel@tonic-gate 	 */
28220Sstevel@tonic-gate 	s = socket(AF_INET, SOCK_DGRAM, 0);
28230Sstevel@tonic-gate 	if (s < 0) {
28240Sstevel@tonic-gate 		error("get_ether_addr: error opening IP socket: %m");
28250Sstevel@tonic-gate 		free(ifc.ifc_buf);
28260Sstevel@tonic-gate 		return (0);
28270Sstevel@tonic-gate 	}
28280Sstevel@tonic-gate 	BZERO(&sin, sizeof (sin));
28290Sstevel@tonic-gate 	sin.sin_family = AF_INET;
28300Sstevel@tonic-gate 	sin.sin_addr.s_addr = ina;
28310Sstevel@tonic-gate 
28320Sstevel@tonic-gate 	BZERO(&req, sizeof (req));
28330Sstevel@tonic-gate 	BCOPY(&sin, &req.xarp_pa, sizeof (sin));
28340Sstevel@tonic-gate 	req.xarp_ha.sdl_family = AF_LINK;
28350Sstevel@tonic-gate 
28360Sstevel@tonic-gate 	if (myioctl(s, SIOCGXARP, &req) < 0) {
28370Sstevel@tonic-gate 		error("Couldn't get ARP entry for %I: %m", ina);
28380Sstevel@tonic-gate 		retv = 0;
28390Sstevel@tonic-gate 	} else {
28400Sstevel@tonic-gate 		(void) memcpy(hwaddr, &req.xarp_ha,
28410Sstevel@tonic-gate 		    sizeof (struct sockaddr_dl));
28420Sstevel@tonic-gate 		retv = 1;
28430Sstevel@tonic-gate 	}
28440Sstevel@tonic-gate 	(void) close(s);
28450Sstevel@tonic-gate 	free(ifc.ifc_buf);
28460Sstevel@tonic-gate 	return (retv);
28470Sstevel@tonic-gate }
28480Sstevel@tonic-gate 
28490Sstevel@tonic-gate /*
28500Sstevel@tonic-gate  * GetMask()
28510Sstevel@tonic-gate  *
28520Sstevel@tonic-gate  * Return mask (bogus, but needed for compatibility with other platforms).
28530Sstevel@tonic-gate  */
28540Sstevel@tonic-gate /*ARGSUSED*/
28550Sstevel@tonic-gate u_int32_t
GetMask(addr)28560Sstevel@tonic-gate GetMask(addr)
28570Sstevel@tonic-gate 	u_int32_t addr;
28580Sstevel@tonic-gate {
28590Sstevel@tonic-gate 	return (0xffffffffUL);
28600Sstevel@tonic-gate }
28610Sstevel@tonic-gate 
28620Sstevel@tonic-gate /*
28630Sstevel@tonic-gate  * logwtmp()
28640Sstevel@tonic-gate  *
28650Sstevel@tonic-gate  * Write an accounting record to the /var/adm/wtmp file.
28660Sstevel@tonic-gate  */
28670Sstevel@tonic-gate /*ARGSUSED*/
28680Sstevel@tonic-gate void
logwtmp(line,name,host)28690Sstevel@tonic-gate logwtmp(line, name, host)
28700Sstevel@tonic-gate 	const char *line;
28710Sstevel@tonic-gate 	const char *name;
28720Sstevel@tonic-gate 	const char *host;
28730Sstevel@tonic-gate {
28740Sstevel@tonic-gate 	static struct utmpx utmpx;
28750Sstevel@tonic-gate 
28760Sstevel@tonic-gate 	if (name[0] != '\0') {
28770Sstevel@tonic-gate 		/*
28780Sstevel@tonic-gate 		 * logging in
28790Sstevel@tonic-gate 		 */
28800Sstevel@tonic-gate 		(void) strncpy(utmpx.ut_user, name, sizeof (utmpx.ut_user));
28810Sstevel@tonic-gate 		(void) strncpy(utmpx.ut_id, ifname, sizeof (utmpx.ut_id));
28820Sstevel@tonic-gate 		(void) strncpy(utmpx.ut_line, line, sizeof (utmpx.ut_line));
28830Sstevel@tonic-gate 
28840Sstevel@tonic-gate 		utmpx.ut_pid = getpid();
28850Sstevel@tonic-gate 		utmpx.ut_type = USER_PROCESS;
28860Sstevel@tonic-gate 	} else {
28870Sstevel@tonic-gate 		utmpx.ut_type = DEAD_PROCESS;
28880Sstevel@tonic-gate 	}
28890Sstevel@tonic-gate 	(void) gettimeofday(&utmpx.ut_tv, NULL);
28900Sstevel@tonic-gate 	updwtmpx("/var/adm/wtmpx", &utmpx);
28910Sstevel@tonic-gate }
28920Sstevel@tonic-gate 
28930Sstevel@tonic-gate /*
28940Sstevel@tonic-gate  * get_host_seed()
28950Sstevel@tonic-gate  *
28960Sstevel@tonic-gate  * Return the serial number of this machine.
28970Sstevel@tonic-gate  */
28980Sstevel@tonic-gate int
get_host_seed()28990Sstevel@tonic-gate get_host_seed()
29000Sstevel@tonic-gate {
29010Sstevel@tonic-gate 	char buf[32];
29020Sstevel@tonic-gate 
29030Sstevel@tonic-gate 	if (sysinfo(SI_HW_SERIAL, buf, sizeof (buf)) < 0) {
29040Sstevel@tonic-gate 		error("sysinfo: %m");
29050Sstevel@tonic-gate 		return (0);
29060Sstevel@tonic-gate 	}
29070Sstevel@tonic-gate 	return ((int)strtoul(buf, NULL, 16));
29080Sstevel@tonic-gate }
29090Sstevel@tonic-gate 
29100Sstevel@tonic-gate /*
29110Sstevel@tonic-gate  * strioctl()
29120Sstevel@tonic-gate  *
29130Sstevel@tonic-gate  * Wrapper for STREAMS I_STR ioctl.  Masks out EINTR from caller.
29140Sstevel@tonic-gate  */
29150Sstevel@tonic-gate static int
strioctl(int fd,int cmd,void * ptr,int ilen,int olen)29160Sstevel@tonic-gate strioctl(int fd, int cmd, void *ptr, int ilen, int olen)
29170Sstevel@tonic-gate {
29180Sstevel@tonic-gate 	struct strioctl	str;
29190Sstevel@tonic-gate 
29200Sstevel@tonic-gate 	str.ic_cmd = cmd;
29210Sstevel@tonic-gate 	str.ic_timout = PPPSTRTIMOUT;
29220Sstevel@tonic-gate 	str.ic_len = ilen;
29230Sstevel@tonic-gate 	str.ic_dp = ptr;
29240Sstevel@tonic-gate 
29250Sstevel@tonic-gate 	if (myioctl(fd, I_STR, &str) == -1) {
29260Sstevel@tonic-gate 		return (-1);
29270Sstevel@tonic-gate 	}
29280Sstevel@tonic-gate 	if (str.ic_len != olen) {
29290Sstevel@tonic-gate 		dbglog("strioctl: expected %d bytes, got %d for cmd %x\n",
29300Sstevel@tonic-gate 		    olen, str.ic_len, cmd);
29310Sstevel@tonic-gate 	}
29320Sstevel@tonic-gate 	return (0);
29330Sstevel@tonic-gate }
29340Sstevel@tonic-gate 
29350Sstevel@tonic-gate /*
29360Sstevel@tonic-gate  * have_route_to()
29370Sstevel@tonic-gate  *
29380Sstevel@tonic-gate  * Determine if the system has a route to the specified IP address.
29390Sstevel@tonic-gate  * Returns 0 if not, 1 if so, -1 if we can't tell. `addr' is in network
29400Sstevel@tonic-gate  * byte order. For demand mode to work properly, we have to ignore routes
29410Sstevel@tonic-gate  * through our own interface. XXX Would be nice to use routing socket.
29420Sstevel@tonic-gate  */
29430Sstevel@tonic-gate int
have_route_to(addr)29440Sstevel@tonic-gate have_route_to(addr)
29450Sstevel@tonic-gate 	u_int32_t addr;
29460Sstevel@tonic-gate {
29470Sstevel@tonic-gate 	int r, flags, i;
29480Sstevel@tonic-gate 	struct {
29490Sstevel@tonic-gate 		struct T_optmgmt_req req;
29500Sstevel@tonic-gate 		struct opthdr hdr;
29510Sstevel@tonic-gate 	} req;
29520Sstevel@tonic-gate 	union {
29530Sstevel@tonic-gate 		struct T_optmgmt_ack ack;
29540Sstevel@tonic-gate 		unsigned char space[64];
29550Sstevel@tonic-gate 	} ack;
29560Sstevel@tonic-gate 	struct opthdr *rh;
29570Sstevel@tonic-gate 	struct strbuf cbuf, dbuf;
29580Sstevel@tonic-gate 	int nroutes;
29590Sstevel@tonic-gate 	mib2_ipRouteEntry_t routes[8];
29600Sstevel@tonic-gate 	mib2_ipRouteEntry_t *rp;
29610Sstevel@tonic-gate 
29620Sstevel@tonic-gate 	if (ipfd == -1 && open_ipfd() == -1)
29630Sstevel@tonic-gate 		return (0);
29640Sstevel@tonic-gate 
29650Sstevel@tonic-gate 	req.req.PRIM_type = T_OPTMGMT_REQ;
29660Sstevel@tonic-gate 	req.req.OPT_offset = (caddr_t)&req.hdr - (caddr_t)&req;
29670Sstevel@tonic-gate 	req.req.OPT_length = sizeof (req.hdr);
29680Sstevel@tonic-gate #ifdef T_CURRENT
29690Sstevel@tonic-gate 	req.req.MGMT_flags = T_CURRENT;
29700Sstevel@tonic-gate #else
29710Sstevel@tonic-gate 	/* Old-style */
29720Sstevel@tonic-gate 	req.req.MGMT_flags = T_CHECK;
29730Sstevel@tonic-gate #endif
29740Sstevel@tonic-gate 
29750Sstevel@tonic-gate 	req.hdr.level = MIB2_IP;
29760Sstevel@tonic-gate 	req.hdr.name = 0;
29770Sstevel@tonic-gate 	req.hdr.len = 0;
29780Sstevel@tonic-gate 
29790Sstevel@tonic-gate 	cbuf.buf = (caddr_t)&req;
29800Sstevel@tonic-gate 	cbuf.len = sizeof (req);
29810Sstevel@tonic-gate 
29820Sstevel@tonic-gate 	if (putmsg(ipfd, &cbuf, NULL, 0) == -1) {
29830Sstevel@tonic-gate 		warn("have_route_to: putmsg: %m");
29840Sstevel@tonic-gate 		return (-1);
29850Sstevel@tonic-gate 	}
29860Sstevel@tonic-gate 
29870Sstevel@tonic-gate 	for (;;) {
29880Sstevel@tonic-gate 		cbuf.buf = (caddr_t)&ack;
29890Sstevel@tonic-gate 		cbuf.maxlen = sizeof (ack);
29900Sstevel@tonic-gate 		dbuf.buf = (caddr_t)routes;
29910Sstevel@tonic-gate 		dbuf.maxlen = sizeof (routes);
29920Sstevel@tonic-gate 		flags = 0;
29930Sstevel@tonic-gate 		r = getmsg(ipfd, &cbuf, &dbuf, &flags);
29940Sstevel@tonic-gate 		if (r == -1) {
29950Sstevel@tonic-gate 			warn("have_route_to: getmsg: %m");
29960Sstevel@tonic-gate 			return (-1);
29970Sstevel@tonic-gate 		}
29980Sstevel@tonic-gate 
29990Sstevel@tonic-gate 		if (cbuf.len < sizeof (struct T_optmgmt_ack) ||
30000Sstevel@tonic-gate 		    ack.ack.PRIM_type != T_OPTMGMT_ACK ||
30010Sstevel@tonic-gate 		    ack.ack.MGMT_flags != T_SUCCESS ||
30020Sstevel@tonic-gate 		    ack.ack.OPT_length < sizeof (struct opthdr)) {
30030Sstevel@tonic-gate 			dbglog("have_route_to: bad message len=%d prim=%d",
30040Sstevel@tonic-gate 			    cbuf.len, ack.ack.PRIM_type);
30050Sstevel@tonic-gate 			return (-1);
30060Sstevel@tonic-gate 		}
30070Sstevel@tonic-gate 		/* LINTED */
30080Sstevel@tonic-gate 		rh = (struct opthdr *)((caddr_t)&ack + ack.ack.OPT_offset);
30090Sstevel@tonic-gate 		if (rh->level == 0 && rh->name == 0) {
30100Sstevel@tonic-gate 			break;
30110Sstevel@tonic-gate 		}
30120Sstevel@tonic-gate 		if (rh->level != MIB2_IP || rh->name != MIB2_IP_21) {
30130Sstevel@tonic-gate 			while (r == MOREDATA) {
30140Sstevel@tonic-gate 				r = getmsg(ipfd, NULL, &dbuf, &flags);
30150Sstevel@tonic-gate 			}
30160Sstevel@tonic-gate 			continue;
30170Sstevel@tonic-gate 		}
30180Sstevel@tonic-gate 
30190Sstevel@tonic-gate 		/*
30200Sstevel@tonic-gate 		 * Note that we have to skip routes to our own
30210Sstevel@tonic-gate 		 * interface in order for demand dial to work.
30220Sstevel@tonic-gate 		 *
30230Sstevel@tonic-gate 		 * XXX awful hack here.  We don't know our own
30240Sstevel@tonic-gate 		 * ifIndex, so we can't check ipRouteIfIndex here.
30250Sstevel@tonic-gate 		 * Instead, we check the next hop address.
30260Sstevel@tonic-gate 		 */
30270Sstevel@tonic-gate 		for (;;) {
30280Sstevel@tonic-gate 			nroutes = dbuf.len / sizeof (mib2_ipRouteEntry_t);
30290Sstevel@tonic-gate 			for (rp = routes, i = 0; i < nroutes; ++i, ++rp) {
30300Sstevel@tonic-gate 				if (rp->ipRouteNextHop != remote_addr &&
30310Sstevel@tonic-gate 				    ((addr ^ rp->ipRouteDest) &
30320Sstevel@tonic-gate 					rp->ipRouteMask) == 0) {
30330Sstevel@tonic-gate 					dbglog("have route to %I/%I via %I",
30340Sstevel@tonic-gate 					    rp->ipRouteDest,
30350Sstevel@tonic-gate 					    rp->ipRouteMask,
30360Sstevel@tonic-gate 					    rp->ipRouteNextHop);
30370Sstevel@tonic-gate 					return (1);
30380Sstevel@tonic-gate 				}
30390Sstevel@tonic-gate 			}
30400Sstevel@tonic-gate 			if (r == 0) {
30410Sstevel@tonic-gate 				break;
30420Sstevel@tonic-gate 			}
30430Sstevel@tonic-gate 			r = getmsg(ipfd, NULL, &dbuf, &flags);
30440Sstevel@tonic-gate 		}
30450Sstevel@tonic-gate 	}
30460Sstevel@tonic-gate 	return (0);
30470Sstevel@tonic-gate }
30480Sstevel@tonic-gate 
30490Sstevel@tonic-gate /*
30500Sstevel@tonic-gate  * get_pty()
30510Sstevel@tonic-gate  *
30520Sstevel@tonic-gate  * Get a pty master/slave pair and chown the slave side to the uid given.
30530Sstevel@tonic-gate  * Assumes slave_name points to MAXPATHLEN bytes of space.
30540Sstevel@tonic-gate  */
30550Sstevel@tonic-gate int
get_pty(master_fdp,slave_fdp,slave_name,uid)30560Sstevel@tonic-gate get_pty(master_fdp, slave_fdp, slave_name, uid)
30570Sstevel@tonic-gate 	int *master_fdp;
30580Sstevel@tonic-gate 	int *slave_fdp;
30590Sstevel@tonic-gate 	char *slave_name;
30600Sstevel@tonic-gate 	int uid;
30610Sstevel@tonic-gate {
30620Sstevel@tonic-gate 	int mfd;
30630Sstevel@tonic-gate 	int sfd;
30640Sstevel@tonic-gate 	char *pty_name;
30650Sstevel@tonic-gate 
30660Sstevel@tonic-gate 	mfd = open("/dev/ptmx", O_NOCTTY | O_RDWR);
30670Sstevel@tonic-gate 	if (mfd < 0) {
30680Sstevel@tonic-gate 		error("Couldn't open pty master: %m");
30690Sstevel@tonic-gate 		return (0);
30700Sstevel@tonic-gate 	}
30710Sstevel@tonic-gate 	pty_name = ptsname(mfd);
30720Sstevel@tonic-gate 	if (pty_name == NULL) {
30730Sstevel@tonic-gate 		dbglog("Didn't get pty slave name on first try; sleeping.");
30740Sstevel@tonic-gate 		/* In case "grow" operation is in progress; try again. */
30750Sstevel@tonic-gate 		(void) sleep(1);
30760Sstevel@tonic-gate 		pty_name = ptsname(mfd);
30770Sstevel@tonic-gate 	}
30780Sstevel@tonic-gate 	if (pty_name == NULL) {
30790Sstevel@tonic-gate 		error("Couldn't get name of pty slave");
30800Sstevel@tonic-gate 		(void) close(mfd);
30810Sstevel@tonic-gate 		return (0);
30820Sstevel@tonic-gate 	}
30830Sstevel@tonic-gate 	if (chown(pty_name, uid, -1) < 0) {
30840Sstevel@tonic-gate 		warn("Couldn't change owner of pty slave: %m");
30850Sstevel@tonic-gate 	}
30860Sstevel@tonic-gate 	if (chmod(pty_name, S_IRUSR | S_IWUSR) < 0) {
30870Sstevel@tonic-gate 		warn("Couldn't change permissions on pty slave: %m");
30880Sstevel@tonic-gate 	}
30890Sstevel@tonic-gate 	if (unlockpt(mfd) < 0) {
30900Sstevel@tonic-gate 		warn("Couldn't unlock pty slave: %m");
30910Sstevel@tonic-gate 	}
30920Sstevel@tonic-gate 	sfd = open(pty_name, O_RDWR);
30930Sstevel@tonic-gate 	if (sfd < 0) {
30940Sstevel@tonic-gate 		error("Couldn't open pty slave %s: %m", pty_name);
30950Sstevel@tonic-gate 		(void) close(mfd);
30960Sstevel@tonic-gate 		return (0);
30970Sstevel@tonic-gate 	}
30980Sstevel@tonic-gate 	if (myioctl(sfd, I_PUSH, "ptem") < 0) {
30990Sstevel@tonic-gate 		warn("Couldn't push ptem module on pty slave: %m");
31000Sstevel@tonic-gate 	}
31010Sstevel@tonic-gate 	dbglog("Using %s; master fd %d, slave fd %d", pty_name, mfd, sfd);
31020Sstevel@tonic-gate 
31030Sstevel@tonic-gate 	(void) strlcpy(slave_name, pty_name, MAXPATHLEN);
31040Sstevel@tonic-gate 
31050Sstevel@tonic-gate 	*master_fdp = mfd;
31060Sstevel@tonic-gate 	*slave_fdp = sfd;
31070Sstevel@tonic-gate 
31080Sstevel@tonic-gate 	return (1);
31090Sstevel@tonic-gate }
31100Sstevel@tonic-gate 
31110Sstevel@tonic-gate #ifdef INET6
31120Sstevel@tonic-gate static int
open_udp6fd(void)31130Sstevel@tonic-gate open_udp6fd(void)
31140Sstevel@tonic-gate {
31150Sstevel@tonic-gate 	int udp6fd;
31160Sstevel@tonic-gate 
31170Sstevel@tonic-gate 	udp6fd = open(UDP6_DEV_NAME, O_RDWR | O_NONBLOCK, 0);
31180Sstevel@tonic-gate 	if (udp6fd < 0) {
31190Sstevel@tonic-gate 		error("Couldn't open UDPv6 device (%s): %m", UDP6_DEV_NAME);
31200Sstevel@tonic-gate 	}
31210Sstevel@tonic-gate 	return (udp6fd);
31220Sstevel@tonic-gate }
31230Sstevel@tonic-gate 
31240Sstevel@tonic-gate /*
31250Sstevel@tonic-gate  * plumb_ip6if()
31260Sstevel@tonic-gate  *
31270Sstevel@tonic-gate  * Perform IPv6 interface plumbing.
31280Sstevel@tonic-gate  */
31290Sstevel@tonic-gate /*ARGSUSED*/
31300Sstevel@tonic-gate static int
plumb_ip6if(int unit)31310Sstevel@tonic-gate plumb_ip6if(int unit)
31320Sstevel@tonic-gate {
31330Sstevel@tonic-gate 	int udp6fd = -1, tmpfd;
31340Sstevel@tonic-gate 	uint32_t x;
31350Sstevel@tonic-gate 	struct lifreq lifr;
31360Sstevel@tonic-gate 
31370Sstevel@tonic-gate 	if (!IPV6CP_ENABLED || (ifunit == -1) || (pppfd == -1)) {
31380Sstevel@tonic-gate 		return (0);
31390Sstevel@tonic-gate 	}
31400Sstevel@tonic-gate 	if (plumbed)
31410Sstevel@tonic-gate 		return (1);
31420Sstevel@tonic-gate 	if (ip6fd == -1 && open_ip6fd() == -1)
31430Sstevel@tonic-gate 		return (0);
31440Sstevel@tonic-gate 	if (use_plink && (udp6fd = open_udp6fd()) == -1)
31450Sstevel@tonic-gate 		return (0);
31460Sstevel@tonic-gate 	tmpfd = open(drvnam, O_RDWR | O_NONBLOCK, 0);
31470Sstevel@tonic-gate 	if (tmpfd < 0) {
31480Sstevel@tonic-gate 		error("Couldn't open PPP device (%s): %m", drvnam);
31490Sstevel@tonic-gate 		if (udp6fd != -1)
31500Sstevel@tonic-gate 			(void) close(udp6fd);
31510Sstevel@tonic-gate 		return (0);
31520Sstevel@tonic-gate 	}
31530Sstevel@tonic-gate 	if (kdebugflag & 1) {
31540Sstevel@tonic-gate 		x = PPPDBG_LOG + PPPDBG_DRIVER;
31550Sstevel@tonic-gate 		if (strioctl(tmpfd, PPPIO_DEBUG, &x, sizeof (x), 0) < 0) {
31560Sstevel@tonic-gate 			warn("PPPIO_DEBUG ioctl for mux failed: %m");
31570Sstevel@tonic-gate 		}
31580Sstevel@tonic-gate 	}
31590Sstevel@tonic-gate 	if (myioctl(tmpfd, I_PUSH, IP_MOD_NAME) < 0) {
31600Sstevel@tonic-gate 		error("Couldn't push IP module(%s): %m", IP_MOD_NAME);
31610Sstevel@tonic-gate 		goto err_ret;
31620Sstevel@tonic-gate 	}
31630Sstevel@tonic-gate 	/*
31640Sstevel@tonic-gate 	 * Sets interface ppa and flags (refer to comments in plumb_ipif for
31650Sstevel@tonic-gate 	 * the IF_UNITSEL ioctl). In addition, the IFF_IPV6 bit must be set in
31660Sstevel@tonic-gate 	 * order to declare this as an IPv6 interface.
31670Sstevel@tonic-gate 	 */
31680Sstevel@tonic-gate 	BZERO(&lifr, sizeof (lifr));
31690Sstevel@tonic-gate 	if (myioctl(tmpfd, SIOCGLIFFLAGS, &lifr) < 0) {
31700Sstevel@tonic-gate 		error("Couldn't get IPv6 interface flags: %m");
31710Sstevel@tonic-gate 		goto err_ret;
31720Sstevel@tonic-gate 	}
31730Sstevel@tonic-gate 	lifr.lifr_flags |= IFF_IPV6;
31740Sstevel@tonic-gate 	lifr.lifr_flags &= ~(IFF_BROADCAST | IFF_IPV4);
31750Sstevel@tonic-gate 	lifr.lifr_ppa = ifunit;
31760Sstevel@tonic-gate 	(void) strlcpy(lifr.lifr_name, ifname, sizeof (lifr.lifr_name));
31770Sstevel@tonic-gate 	if (myioctl(tmpfd, SIOCSLIFNAME, &lifr) < 0) {
31780Sstevel@tonic-gate 		error("Can't set ifname for unit %d: %m", ifunit);
31790Sstevel@tonic-gate 		goto err_ret;
31800Sstevel@tonic-gate 	}
31810Sstevel@tonic-gate 	if (use_plink) {
31820Sstevel@tonic-gate 		ip6muxid = myioctl(udp6fd, I_PLINK, (void *)tmpfd);
31830Sstevel@tonic-gate 		if (ip6muxid < 0) {
31840Sstevel@tonic-gate 			error("Can't I_PLINK PPP device to IPv6: %m");
31850Sstevel@tonic-gate 			goto err_ret;
31860Sstevel@tonic-gate 		}
31870Sstevel@tonic-gate 	} else {
31880Sstevel@tonic-gate 		ip6muxid = myioctl(ip6fd, I_LINK, (void *)tmpfd);
31890Sstevel@tonic-gate 		if (ip6muxid < 0) {
31900Sstevel@tonic-gate 			error("Can't I_LINK PPP device to IPv6: %m");
31910Sstevel@tonic-gate 			goto err_ret;
31920Sstevel@tonic-gate 		}
31930Sstevel@tonic-gate 	}
31940Sstevel@tonic-gate 	lifr.lifr_ip_muxid = ip6muxid;
31950Sstevel@tonic-gate 	lifr.lifr_arp_muxid = -1;
31960Sstevel@tonic-gate 	if (myioctl(ip6fd, SIOCSLIFMUXID, (caddr_t)&lifr) < 0) {
31970Sstevel@tonic-gate 		error("Can't set mux ID:  SIOCSLIFMUXID: %m");
31980Sstevel@tonic-gate 		goto err_ret;
31990Sstevel@tonic-gate 	}
32000Sstevel@tonic-gate 	(void) close(tmpfd);
32010Sstevel@tonic-gate 	if (udp6fd != -1)
32020Sstevel@tonic-gate 		(void) close(udp6fd);
32030Sstevel@tonic-gate 	return (1);
32040Sstevel@tonic-gate 
32050Sstevel@tonic-gate err_ret:
32060Sstevel@tonic-gate 	(void) close(tmpfd);
32070Sstevel@tonic-gate 	if (udp6fd != -1)
32080Sstevel@tonic-gate 		(void) close(udp6fd);
32090Sstevel@tonic-gate 	return (0);
32100Sstevel@tonic-gate }
32110Sstevel@tonic-gate 
32120Sstevel@tonic-gate /*
32130Sstevel@tonic-gate  * unplumb_ip6if()
32140Sstevel@tonic-gate  *
32150Sstevel@tonic-gate  * Perform IPv6 interface unplumbing.  Possibly called from die(), so there
32160Sstevel@tonic-gate  * shouldn't be any call to die() here.
32170Sstevel@tonic-gate  */
32180Sstevel@tonic-gate static int
unplumb_ip6if(int unit)32190Sstevel@tonic-gate unplumb_ip6if(int unit)
32200Sstevel@tonic-gate {
32210Sstevel@tonic-gate 	int udp6fd = -1, fd = -1;
32220Sstevel@tonic-gate 	int id;
32230Sstevel@tonic-gate 	struct lifreq lifr;
32240Sstevel@tonic-gate 
32250Sstevel@tonic-gate 	if (!IPV6CP_ENABLED || ifunit == -1) {
32260Sstevel@tonic-gate 		return (0);
32270Sstevel@tonic-gate 	}
32280Sstevel@tonic-gate 	if (!plumbed && (ip6muxid == -1 || (ip6fd == -1 && !use_plink))) {
32290Sstevel@tonic-gate 		return (1);
32300Sstevel@tonic-gate 	}
32310Sstevel@tonic-gate 	id = ip6muxid;
32320Sstevel@tonic-gate 	if (!plumbed && use_plink) {
32330Sstevel@tonic-gate 		if ((udp6fd = open_udp6fd()) == -1)
32340Sstevel@tonic-gate 			return (0);
32350Sstevel@tonic-gate 		/*
32360Sstevel@tonic-gate 		 * Note: must re-get mux ID, since any intervening
32370Sstevel@tonic-gate 		 * ifconfigs will change this.
32380Sstevel@tonic-gate 		 */
32390Sstevel@tonic-gate 		BZERO(&lifr, sizeof (lifr));
32400Sstevel@tonic-gate 		(void) strlcpy(lifr.lifr_name, ifname,
32410Sstevel@tonic-gate 		    sizeof (lifr.lifr_name));
32420Sstevel@tonic-gate 		if (myioctl(ip6fd, SIOCGLIFMUXID, (caddr_t)&lifr) < 0) {
32430Sstevel@tonic-gate 			warn("Can't get mux fd: SIOCGLIFMUXID: %m");
32440Sstevel@tonic-gate 		} else {
32450Sstevel@tonic-gate 			id = lifr.lifr_ip_muxid;
32460Sstevel@tonic-gate 			fd = myioctl(udp6fd, _I_MUXID2FD, (void *)id);
32470Sstevel@tonic-gate 			if (fd < 0) {
32480Sstevel@tonic-gate 				warn("Can't get mux fd: _I_MUXID2FD: %m");
32490Sstevel@tonic-gate 			}
32500Sstevel@tonic-gate 		}
32510Sstevel@tonic-gate 	}
32520Sstevel@tonic-gate 	/*
32530Sstevel@tonic-gate 	 * Mark down and unlink the IPv6 interface.
32540Sstevel@tonic-gate 	 */
32550Sstevel@tonic-gate 	(void) sif6down(unit);
32560Sstevel@tonic-gate 	if (plumbed)
32570Sstevel@tonic-gate 		return (1);
32580Sstevel@tonic-gate 	ip6muxid = -1;
32590Sstevel@tonic-gate 	if (use_plink) {
32600Sstevel@tonic-gate 		if ((fd = myioctl(udp6fd, _I_MUXID2FD, (void *)id)) < 0) {
32610Sstevel@tonic-gate 			error("Can't recapture mux fd: _I_MUXID2FD: %m");
32620Sstevel@tonic-gate 			(void) close(udp6fd);
32630Sstevel@tonic-gate 			return (0);
32640Sstevel@tonic-gate 		}
32650Sstevel@tonic-gate 		if (myioctl(udp6fd, I_PUNLINK, (void *)id) < 0) {
32660Sstevel@tonic-gate 			error("Can't I_PUNLINK PPP from IPv6: %m");
32670Sstevel@tonic-gate 			(void) close(fd);
32680Sstevel@tonic-gate 			(void) close(udp6fd);
32690Sstevel@tonic-gate 			return (0);
32700Sstevel@tonic-gate 		}
32710Sstevel@tonic-gate 		(void) close(fd);
32720Sstevel@tonic-gate 		(void) close(udp6fd);
32730Sstevel@tonic-gate 	} else {
32740Sstevel@tonic-gate 		if (myioctl(ip6fd, I_UNLINK, (void *)id) < 0) {
32750Sstevel@tonic-gate 			error("Can't I_UNLINK PPP from IPv6: %m");
32760Sstevel@tonic-gate 			return (0);
32770Sstevel@tonic-gate 		}
32780Sstevel@tonic-gate 	}
32790Sstevel@tonic-gate 	return (1);
32800Sstevel@tonic-gate }
32810Sstevel@tonic-gate 
32820Sstevel@tonic-gate /*
32830Sstevel@tonic-gate  * sif6flags()
32840Sstevel@tonic-gate  *
32850Sstevel@tonic-gate  * Set or clear the IPv6 interface flags.
32860Sstevel@tonic-gate  */
32870Sstevel@tonic-gate int
sif6flags(f,set)32880Sstevel@tonic-gate sif6flags(f, set)
32890Sstevel@tonic-gate 	u_int32_t f;
32900Sstevel@tonic-gate 	int set;
32910Sstevel@tonic-gate {
32920Sstevel@tonic-gate 	struct lifreq lifr;
32930Sstevel@tonic-gate 	int fd;
32940Sstevel@tonic-gate 
32950Sstevel@tonic-gate 	if (!IPV6CP_ENABLED || (ip6muxid == -1)) {
32960Sstevel@tonic-gate 		return (0);
32970Sstevel@tonic-gate 	}
32980Sstevel@tonic-gate 	fd = socket(AF_INET6, SOCK_DGRAM, 0);
32990Sstevel@tonic-gate 	if (fd < 0) {
33000Sstevel@tonic-gate 		error("sif6flags: error opening IPv6 socket: %m");
33010Sstevel@tonic-gate 		return (0);
33020Sstevel@tonic-gate 	}
33030Sstevel@tonic-gate 	BZERO(&lifr, sizeof (lifr));
33040Sstevel@tonic-gate 	(void) strlcpy(lifr.lifr_name, ifname, sizeof (lifr.lifr_name));
33050Sstevel@tonic-gate 	if (myioctl(fd, SIOCGLIFFLAGS, &lifr) < 0) {
33060Sstevel@tonic-gate 		error("Couldn't get IPv6 interface flags: %m");
33070Sstevel@tonic-gate 		(void) close(fd);
33080Sstevel@tonic-gate 		return (0);
33090Sstevel@tonic-gate 	}
33100Sstevel@tonic-gate 	if (set) {
33110Sstevel@tonic-gate 		lifr.lifr_flags |= f;
33120Sstevel@tonic-gate 	} else {
33130Sstevel@tonic-gate 		lifr.lifr_flags &= ~f;
33140Sstevel@tonic-gate 	}
33150Sstevel@tonic-gate 	(void) strlcpy(lifr.lifr_name, ifname, sizeof (lifr.lifr_name));
33160Sstevel@tonic-gate 	if (myioctl(fd, SIOCSLIFFLAGS, &lifr) < 0) {
33170Sstevel@tonic-gate 		error("Couldn't set IPv6 interface flags: %m");
33180Sstevel@tonic-gate 		(void) close(fd);
33190Sstevel@tonic-gate 		return (0);
33200Sstevel@tonic-gate 	}
33210Sstevel@tonic-gate 	(void) close(fd);
33220Sstevel@tonic-gate 	return (1);
33230Sstevel@tonic-gate }
33240Sstevel@tonic-gate 
33250Sstevel@tonic-gate /*
33260Sstevel@tonic-gate  * sif6up()
33270Sstevel@tonic-gate  *
33280Sstevel@tonic-gate  * Config the IPv6 interface up and enable IPv6 packets to pass.
33290Sstevel@tonic-gate  */
33300Sstevel@tonic-gate /*ARGSUSED*/
33310Sstevel@tonic-gate int
sif6up(unit)33320Sstevel@tonic-gate sif6up(unit)
33330Sstevel@tonic-gate 	int unit;
33340Sstevel@tonic-gate {
33350Sstevel@tonic-gate 	if (if6_is_up) {
33360Sstevel@tonic-gate 		return (1);
33370Sstevel@tonic-gate 	} else if (!IPV6CP_ENABLED) {
33380Sstevel@tonic-gate 		warn("sif6up called when IPV6CP is disabled");
33390Sstevel@tonic-gate 		return (0);
33400Sstevel@tonic-gate 	} else if (ip6muxid == -1) {
33410Sstevel@tonic-gate 		warn("sif6up called in wrong state");
33420Sstevel@tonic-gate 		return (0);
33430Sstevel@tonic-gate 	} else if (!sif6flags(IFF_UP, 1)) {
33440Sstevel@tonic-gate 		error("Unable to mark the IPv6 interface UP");
33450Sstevel@tonic-gate 		return (0);
33460Sstevel@tonic-gate 	}
33470Sstevel@tonic-gate 	if6_is_up = 1;
33480Sstevel@tonic-gate 	return (1);
33490Sstevel@tonic-gate }
33500Sstevel@tonic-gate 
33510Sstevel@tonic-gate /*
33520Sstevel@tonic-gate  * sif6down()
33530Sstevel@tonic-gate  *
33540Sstevel@tonic-gate  * Config the IPv6 interface down and disable IPv6.  Possibly called from
33550Sstevel@tonic-gate  * die(), so there shouldn't be any call to die() here.
33560Sstevel@tonic-gate  */
33570Sstevel@tonic-gate /*ARGSUSED*/
33580Sstevel@tonic-gate int
sif6down(unit)33590Sstevel@tonic-gate sif6down(unit)
33600Sstevel@tonic-gate 	int unit;
33610Sstevel@tonic-gate {
33620Sstevel@tonic-gate 	if (!IPV6CP_ENABLED) {
33630Sstevel@tonic-gate 		warn("sif6down called when IPV6CP is disabled");
33640Sstevel@tonic-gate 		return (0);
33650Sstevel@tonic-gate 	} else if (!if6_is_up || (ip6muxid == -1)) {
33660Sstevel@tonic-gate 		return (1);
33670Sstevel@tonic-gate 	} else if (!sif6flags(IFF_UP, 0)) {
33680Sstevel@tonic-gate 		error("Unable to mark the IPv6 interface DOWN");
33690Sstevel@tonic-gate 		return (0);
33700Sstevel@tonic-gate 	}
33710Sstevel@tonic-gate 	if6_is_up = 0;
33720Sstevel@tonic-gate 	return (1);
33730Sstevel@tonic-gate }
33740Sstevel@tonic-gate 
33750Sstevel@tonic-gate /*
33760Sstevel@tonic-gate  * sif6mtu()
33770Sstevel@tonic-gate  *
33780Sstevel@tonic-gate  * Config the IPv6 interface MTU.
33790Sstevel@tonic-gate  */
33800Sstevel@tonic-gate int
sif6mtu(mtu)33810Sstevel@tonic-gate sif6mtu(mtu)
33820Sstevel@tonic-gate 	int mtu;
33830Sstevel@tonic-gate {
33840Sstevel@tonic-gate 	struct lifreq lifr;
33850Sstevel@tonic-gate 	int s;
33860Sstevel@tonic-gate 
33870Sstevel@tonic-gate 	if (!IPV6CP_ENABLED || (ip6muxid == -1)) {
33880Sstevel@tonic-gate 		return (0);
33890Sstevel@tonic-gate 	}
33900Sstevel@tonic-gate 	s = socket(AF_INET6, SOCK_DGRAM, 0);
33910Sstevel@tonic-gate 	if (s < 0) {
33920Sstevel@tonic-gate 		error("sif6mtu: error opening IPv6 socket: %m");
33930Sstevel@tonic-gate 		return (0);
33940Sstevel@tonic-gate 	}
33950Sstevel@tonic-gate 	BZERO(&lifr, sizeof (lifr));
33960Sstevel@tonic-gate 	(void) strlcpy(lifr.lifr_name, ifname, sizeof (lifr.lifr_name));
33970Sstevel@tonic-gate 	lifr.lifr_mtu = mtu;
33980Sstevel@tonic-gate 	if (myioctl(s, SIOCSLIFMTU, &lifr) < 0) {
33990Sstevel@tonic-gate 		error("Couldn't set IPv6 MTU (%s): %m", lifr.lifr_name);
34000Sstevel@tonic-gate 		(void) close(s);
34010Sstevel@tonic-gate 		return (0);
34020Sstevel@tonic-gate 	}
34030Sstevel@tonic-gate 	(void) close(s);
34040Sstevel@tonic-gate 	return (1);
34050Sstevel@tonic-gate }
34060Sstevel@tonic-gate 
34070Sstevel@tonic-gate /*
34080Sstevel@tonic-gate  * sif6addr()
34090Sstevel@tonic-gate  *
34100Sstevel@tonic-gate  * Config the interface with an IPv6 link-local address.
34110Sstevel@tonic-gate  */
34120Sstevel@tonic-gate /*ARGSUSED*/
34130Sstevel@tonic-gate int
sif6addr(unit,ourid,hisid)34140Sstevel@tonic-gate sif6addr(unit, ourid, hisid)
34150Sstevel@tonic-gate 	int unit;
34160Sstevel@tonic-gate 	eui64_t ourid;
34170Sstevel@tonic-gate 	eui64_t hisid;
34180Sstevel@tonic-gate {
34190Sstevel@tonic-gate 	struct lifreq lifr;
34200Sstevel@tonic-gate 	struct sockaddr_storage	laddr;
34210Sstevel@tonic-gate 	struct sockaddr_in6 *sin6 = (struct sockaddr_in6 *)&laddr;
34220Sstevel@tonic-gate 	int fd;
34230Sstevel@tonic-gate 
34240Sstevel@tonic-gate 	if (!IPV6CP_ENABLED || (ip6muxid == -1 && plumb_ip6if(unit) == 0)) {
34250Sstevel@tonic-gate 		return (0);
34260Sstevel@tonic-gate 	}
34270Sstevel@tonic-gate 	fd = socket(AF_INET6, SOCK_DGRAM, 0);
34280Sstevel@tonic-gate 	if (fd < 0) {
34290Sstevel@tonic-gate 		error("sif6addr: error opening IPv6 socket: %m");
34300Sstevel@tonic-gate 		return (0);
34310Sstevel@tonic-gate 	}
34320Sstevel@tonic-gate 	/*
34330Sstevel@tonic-gate 	 * Set the IPv6 interface MTU.
34340Sstevel@tonic-gate 	 */
34350Sstevel@tonic-gate 	if (!sif6mtu(link_mtu)) {
34360Sstevel@tonic-gate 		(void) close(fd);
34370Sstevel@tonic-gate 		return (0);
34380Sstevel@tonic-gate 	}
34390Sstevel@tonic-gate 	/*
34400Sstevel@tonic-gate 	 * Set the interface address token.  Do this because /dev/ppp responds
34410Sstevel@tonic-gate 	 * to DL_PHYS_ADDR_REQ with zero values, hence the interface token
34420Sstevel@tonic-gate 	 * came to be zero too, and without this, in.ndpd will complain.
34430Sstevel@tonic-gate 	 */
34440Sstevel@tonic-gate 	BZERO(&lifr, sizeof (lifr));
34450Sstevel@tonic-gate 	(void) strlcpy(lifr.lifr_name, ifname, sizeof (lifr.lifr_name));
34460Sstevel@tonic-gate 	BZERO(sin6, sizeof (struct sockaddr_in6));
34470Sstevel@tonic-gate 	IN6_LLTOKEN_FROM_EUI64(lifr, sin6, ourid);
34480Sstevel@tonic-gate 	if (myioctl(fd, SIOCSLIFTOKEN, &lifr) < 0) {
34490Sstevel@tonic-gate 		error("Couldn't set IPv6 token (%s): %m", lifr.lifr_name);
34500Sstevel@tonic-gate 		(void) close(fd);
34510Sstevel@tonic-gate 		return (0);
34520Sstevel@tonic-gate 	}
34530Sstevel@tonic-gate 	/*
34540Sstevel@tonic-gate 	 * Set the IPv6 interface local point-to-point address.
34550Sstevel@tonic-gate 	 */
34560Sstevel@tonic-gate 	IN6_LLADDR_FROM_EUI64(lifr, sin6, ourid);
34570Sstevel@tonic-gate 	if (myioctl(fd, SIOCSLIFADDR, &lifr) < 0) {
34580Sstevel@tonic-gate 		error("Couldn't set local IPv6 address (%s): %m",
34590Sstevel@tonic-gate 		    lifr.lifr_name);
34600Sstevel@tonic-gate 		(void) close(fd);
34610Sstevel@tonic-gate 		return (0);
34620Sstevel@tonic-gate 	}
34630Sstevel@tonic-gate 	/*
34640Sstevel@tonic-gate 	 * Set the IPv6 interface local point-to-point address.
34650Sstevel@tonic-gate 	 */
34660Sstevel@tonic-gate 	BZERO(&lifr, sizeof (lifr));
34670Sstevel@tonic-gate 	(void) strlcpy(lifr.lifr_name, ifname, sizeof (lifr.lifr_name));
34680Sstevel@tonic-gate 	IN6_LLADDR_FROM_EUI64(lifr, sin6, hisid);
34690Sstevel@tonic-gate 	if (myioctl(fd, SIOCSLIFDSTADDR, &lifr) < 0) {
34700Sstevel@tonic-gate 		error("Couldn't set remote IPv6 address (%s): %m",
34710Sstevel@tonic-gate 		    lifr.lifr_name);
34720Sstevel@tonic-gate 		(void) close(fd);
34730Sstevel@tonic-gate 		return (0);
34740Sstevel@tonic-gate 	}
34750Sstevel@tonic-gate 	(void) close(fd);
34760Sstevel@tonic-gate 	return (1);
34770Sstevel@tonic-gate }
34780Sstevel@tonic-gate 
34790Sstevel@tonic-gate /*
34800Sstevel@tonic-gate  * cif6addr()
34810Sstevel@tonic-gate  */
34820Sstevel@tonic-gate /*ARGSUSED*/
34830Sstevel@tonic-gate int
cif6addr(u,o,h)34840Sstevel@tonic-gate cif6addr(u, o, h)
34850Sstevel@tonic-gate 	int u;
34860Sstevel@tonic-gate 	eui64_t o;
34870Sstevel@tonic-gate 	eui64_t h;
34880Sstevel@tonic-gate {
34890Sstevel@tonic-gate 	if (!IPV6CP_ENABLED) {
34900Sstevel@tonic-gate 		return (0);
34910Sstevel@tonic-gate 	}
34920Sstevel@tonic-gate 	/*
34930Sstevel@tonic-gate 	 * Do nothing here, as everything has been done in sif6down().
34940Sstevel@tonic-gate 	 */
34950Sstevel@tonic-gate 	return (1);
34960Sstevel@tonic-gate }
34970Sstevel@tonic-gate 
34980Sstevel@tonic-gate /*
34990Sstevel@tonic-gate  * ether_to_eui64()
35000Sstevel@tonic-gate  *
35010Sstevel@tonic-gate  * Convert 48-bit Ethernet address into 64-bit EUI. Walks the list of valid
35020Sstevel@tonic-gate  * ethernet interfaces, and convert the first found 48-bit MAC address into
35030Sstevel@tonic-gate  * EUI 64. caller also assumes that the system has a properly configured
35040Sstevel@tonic-gate  * Ethernet interface for this function to return non-zero.
35050Sstevel@tonic-gate  */
35060Sstevel@tonic-gate int
ether_to_eui64(p_eui64)35070Sstevel@tonic-gate ether_to_eui64(p_eui64)
35080Sstevel@tonic-gate 	eui64_t *p_eui64;
35090Sstevel@tonic-gate {
35100Sstevel@tonic-gate 	struct ether_addr eth_addr;
35110Sstevel@tonic-gate 
35120Sstevel@tonic-gate 	if (p_eui64 == NULL) {
35130Sstevel@tonic-gate 		return (0);
35140Sstevel@tonic-gate 	}
35150Sstevel@tonic-gate 	if (!get_first_hwaddr(eth_addr.ether_addr_octet,
35160Sstevel@tonic-gate 	    sizeof (eth_addr.ether_addr_octet))) {
35170Sstevel@tonic-gate 		return (0);
35180Sstevel@tonic-gate 	}
35190Sstevel@tonic-gate 	/*
35200Sstevel@tonic-gate 	 * And convert the EUI-48 into EUI-64, per RFC 2472 [sec 4.1]
35210Sstevel@tonic-gate 	 */
35220Sstevel@tonic-gate 	p_eui64->e8[0] = (eth_addr.ether_addr_octet[0] & 0xFF) | 0x02;
35230Sstevel@tonic-gate 	p_eui64->e8[1] = (eth_addr.ether_addr_octet[1] & 0xFF);
35240Sstevel@tonic-gate 	p_eui64->e8[2] = (eth_addr.ether_addr_octet[2] & 0xFF);
35250Sstevel@tonic-gate 	p_eui64->e8[3] = 0xFF;
35260Sstevel@tonic-gate 	p_eui64->e8[4] = 0xFE;
35270Sstevel@tonic-gate 	p_eui64->e8[5] = (eth_addr.ether_addr_octet[3] & 0xFF);
35280Sstevel@tonic-gate 	p_eui64->e8[6] = (eth_addr.ether_addr_octet[4] & 0xFF);
35290Sstevel@tonic-gate 	p_eui64->e8[7] = (eth_addr.ether_addr_octet[5] & 0xFF);
35300Sstevel@tonic-gate 	return (1);
35310Sstevel@tonic-gate }
35320Sstevel@tonic-gate #endif /* INET6 */
35330Sstevel@tonic-gate 
35340Sstevel@tonic-gate struct bit_ent {
35350Sstevel@tonic-gate 	int val;
35360Sstevel@tonic-gate 	char *off, *on;
35370Sstevel@tonic-gate };
35380Sstevel@tonic-gate 
35390Sstevel@tonic-gate /* see sbuf[] below if you change this list */
35400Sstevel@tonic-gate static struct bit_ent bit_list[] = {
35410Sstevel@tonic-gate 	{ TIOCM_DTR, "dtr", "DTR" },
35420Sstevel@tonic-gate 	{ TIOCM_RTS, "rts", "RTS" },
35430Sstevel@tonic-gate 	{ TIOCM_CTS, "cts", "CTS" },
35440Sstevel@tonic-gate 	{ TIOCM_CD, "dcd", "DCD" },
35450Sstevel@tonic-gate 	{ TIOCM_RI, "ri", "RI" },
35460Sstevel@tonic-gate 	{ TIOCM_DSR, "dsr", "DSR" },
35470Sstevel@tonic-gate #if 0
35480Sstevel@tonic-gate 	{ TIOCM_LE, "disabled", "ENABLED" },
35490Sstevel@tonic-gate 	{ TIOCM_ST, NULL, "2nd-XMIT" },
35500Sstevel@tonic-gate 	{ TIOCM_SR, NULL, "2nd-RECV" },
35510Sstevel@tonic-gate #endif
35520Sstevel@tonic-gate 	{ 0, NULL, NULL }
35530Sstevel@tonic-gate };
35540Sstevel@tonic-gate 
35550Sstevel@tonic-gate static void
getbits(int fd,char * name,FILE * strptr)35560Sstevel@tonic-gate getbits(int fd, char *name, FILE *strptr)
35570Sstevel@tonic-gate {
35580Sstevel@tonic-gate 	int nmods, i;
35590Sstevel@tonic-gate 	struct str_list strlist;
35600Sstevel@tonic-gate 	struct bit_ent *be;
35610Sstevel@tonic-gate 	int mstate;
35620Sstevel@tonic-gate 	char sbuf[50];		/* sum of string lengths in bit_list */
35630Sstevel@tonic-gate 	char *str;
35640Sstevel@tonic-gate 
35650Sstevel@tonic-gate 	nmods = ioctl(fd, I_LIST, NULL);
35660Sstevel@tonic-gate 	if (nmods < 0) {
35670Sstevel@tonic-gate 		error("unable to get module count: %m");
35680Sstevel@tonic-gate 	} else {
35690Sstevel@tonic-gate 		strlist.sl_nmods = nmods;
35700Sstevel@tonic-gate 		strlist.sl_modlist = malloc(sizeof (struct str_mlist) * nmods);
35710Sstevel@tonic-gate 		if (strlist.sl_modlist == NULL)
35720Sstevel@tonic-gate 			novm("module list");
35730Sstevel@tonic-gate 		if (ioctl(fd, I_LIST, (caddr_t)&strlist) < 0) {
35740Sstevel@tonic-gate 			error("unable to get module names: %m");
35750Sstevel@tonic-gate 		} else {
35760Sstevel@tonic-gate 			for (i = 0; i < strlist.sl_nmods; i++)
35770Sstevel@tonic-gate 				(void) flprintf(strptr, "%d: %s", i,
35780Sstevel@tonic-gate 				    strlist.sl_modlist[i].l_name);
35790Sstevel@tonic-gate 			free(strlist.sl_modlist);
35800Sstevel@tonic-gate 		}
35810Sstevel@tonic-gate 	}
35820Sstevel@tonic-gate 	if (ioctl(fd, TIOCMGET, &mstate) < 0) {
35830Sstevel@tonic-gate 		error("unable to get modem state: %m");
35840Sstevel@tonic-gate 	} else {
35850Sstevel@tonic-gate 		sbuf[0] = '\0';
35860Sstevel@tonic-gate 		for (be = bit_list; be->val != 0; be++) {
35870Sstevel@tonic-gate 			str = (be->val & mstate) ? be->on : be->off;
35880Sstevel@tonic-gate 			if (str != NULL) {
35890Sstevel@tonic-gate 				if (sbuf[0] != '\0')
35900Sstevel@tonic-gate 					(void) strcat(sbuf, " ");
35910Sstevel@tonic-gate 				(void) strcat(sbuf, str);
35920Sstevel@tonic-gate 			}
35930Sstevel@tonic-gate 		}
35940Sstevel@tonic-gate 		(void) flprintf(strptr, "%s: %s\n", name, sbuf);
35950Sstevel@tonic-gate 	}
35960Sstevel@tonic-gate }
35970Sstevel@tonic-gate 
35980Sstevel@tonic-gate /*
35990Sstevel@tonic-gate  * Print state of serial link.  The stream might be linked under the
36000Sstevel@tonic-gate  * /dev/sppp driver.  If it is, then it's necessary to unlink it first
36010Sstevel@tonic-gate  * and relink it when done.  Otherwise, it's not possible to use
36020Sstevel@tonic-gate  * ioctl() on the stream.
36030Sstevel@tonic-gate  */
36040Sstevel@tonic-gate void
sys_print_state(FILE * strptr)36050Sstevel@tonic-gate sys_print_state(FILE *strptr)
36060Sstevel@tonic-gate {
36070Sstevel@tonic-gate 	bool was_linked;
36080Sstevel@tonic-gate 
36090Sstevel@tonic-gate 	if (pppfd == -1)
36100Sstevel@tonic-gate 		return;
36110Sstevel@tonic-gate 	if (ttyfd == -1) {
36120Sstevel@tonic-gate 		(void) flprintf(strptr, "serial link is not active");
36130Sstevel@tonic-gate 		return;
36140Sstevel@tonic-gate 	}
36150Sstevel@tonic-gate 	was_linked = fdmuxid != -1;
36160Sstevel@tonic-gate 	if (was_linked && ioctl(pppfd, I_UNLINK, fdmuxid) == -1) {
36170Sstevel@tonic-gate 		error("I_UNLINK: %m");
36180Sstevel@tonic-gate 	} else {
36190Sstevel@tonic-gate 		fdmuxid = -1;
36200Sstevel@tonic-gate 		getbits(ttyfd, devnam, strptr);
36210Sstevel@tonic-gate 		if (was_linked &&
36220Sstevel@tonic-gate 		    (fdmuxid = ioctl(pppfd, I_LINK, (void *)ttyfd)) == -1)
36230Sstevel@tonic-gate 			fatal("I_LINK: %m");
36240Sstevel@tonic-gate 	}
36250Sstevel@tonic-gate }
36260Sstevel@tonic-gate 
36270Sstevel@tonic-gate /*
36280Sstevel@tonic-gate  * send ioctl to driver asking it to block packets with network protocol
36290Sstevel@tonic-gate  * proto in the control queue until the queue for proto is plumbed.
36300Sstevel@tonic-gate  */
36310Sstevel@tonic-gate void
sys_block_proto(uint16_t proto)36320Sstevel@tonic-gate sys_block_proto(uint16_t proto)
36330Sstevel@tonic-gate {
36340Sstevel@tonic-gate 	if (proto > 0x7fff) {
36350Sstevel@tonic-gate 		warn("cannot block: not a network proto 0x%lx\n", proto);
36360Sstevel@tonic-gate 		return;
36370Sstevel@tonic-gate 	}
36380Sstevel@tonic-gate 	if (strioctl(pppfd, PPPIO_BLOCKNP, &proto, sizeof (proto), 0) < 0) {
36390Sstevel@tonic-gate 		warn("PPPIO_BLOCKNP ioctl failed %m");
36400Sstevel@tonic-gate 	}
36410Sstevel@tonic-gate }
36420Sstevel@tonic-gate /*
36430Sstevel@tonic-gate  * send ioctl to driver asking it to release packets with network protocol
36440Sstevel@tonic-gate  * proto from control queue to the protocol specific queue.
36450Sstevel@tonic-gate  */
36460Sstevel@tonic-gate void
sys_unblock_proto(uint16_t proto)36470Sstevel@tonic-gate sys_unblock_proto(uint16_t proto)
36480Sstevel@tonic-gate {
36490Sstevel@tonic-gate 	if (proto > 0x7fff) {
36500Sstevel@tonic-gate 		warn("cannot unblock: not a network proto 0x%lx\n", proto);
36510Sstevel@tonic-gate 		return;
36520Sstevel@tonic-gate 	}
36530Sstevel@tonic-gate 	if (strioctl(pppfd, PPPIO_UNBLOCKNP, &proto, sizeof (proto), 0) < 0) {
36540Sstevel@tonic-gate 		warn("PPPIO_UNBLOCKNP ioctl failed %m");
36550Sstevel@tonic-gate 	}
36560Sstevel@tonic-gate }
3657