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