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