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