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