xref: /titanic_44/usr/src/cmd/cmd-inet/usr.sbin/ifconfig/ifconfig.c (revision 8eea8e29cc4374d1ee24c25a07f45af132db3499)
1 /*
2  * Copyright 2005 Sun Microsystems, Inc.  All rights reserved.
3  * Use is subject to license terms.
4  */
5 /*
6  * Copyright (c) 1983 Regents of the University of California.
7  * All rights reserved.  The Berkeley software License Agreement
8  * specifies the terms and conditions for redistribution.
9  */
10 
11 #pragma ident	"%Z%%M%	%I%	%E% SMI"
12 
13 #include "defs.h"
14 #include "strings.h"
15 #include "ifconfig.h"
16 #include <compat.h>
17 
18 #include <sys/dlpi.h>
19 #include <libdlpi.h>
20 
21 #define	LOOPBACK_IF	"lo0"
22 
23 #define	NONE_STR	"none"
24 
25 #ifndef	ARP_MOD_NAME
26 #define	ARP_MOD_NAME	"arp"
27 #endif
28 
29 #ifndef	IP_DEV_NAME
30 #define	IP_DEV_NAME	"/dev/ip"
31 #endif
32 
33 #ifndef	IP_MOD_NAME
34 #define	IP_MOD_NAME	"ip"
35 #endif
36 
37 #ifndef	IP6_DEV_NAME
38 #define	IP6_DEV_NAME	"/dev/ip6"
39 #endif
40 
41 #ifndef	UDP_DEV_NAME
42 #define	UDP_DEV_NAME	"/dev/udp"
43 #endif
44 
45 #ifndef	UDP6_DEV_NAME
46 #define	UDP6_DEV_NAME	"/dev/udp6"
47 #endif
48 
49 #define	ADDRBITS_V4	32	/* number of bits in IPv4 address */
50 #define	ADDRBITS_V6	128	/* number of bits in IPv6 address */
51 
52 #define	AF_FUNC_STATUS		1	/* af_status func reports status */
53 #define	AF_FUNC_CONFIGINFO	2	/* af_status func reports configinfo */
54 
55 typedef struct if_flags {
56 	uint64_t iff_value;
57 	char	*iff_name;
58 } if_flags_t;
59 
60 static if_flags_t	if_flags_tbl[] = {
61 	{ IFF_UP,		"UP" },
62 	{ IFF_BROADCAST,	"BROADCAST" },
63 	{ IFF_DEBUG,		"DEBUG" },
64 	{ IFF_LOOPBACK,		"LOOPBACK" },
65 	{ IFF_POINTOPOINT,	"POINTOPOINT" },
66 	{ IFF_NOTRAILERS,	"NOTRAILERS" },
67 	{ IFF_RUNNING,		"RUNNING" },
68 	{ IFF_NOARP,		"NOARP" },
69 	{ IFF_PROMISC,		"PROMISC" },
70 	{ IFF_ALLMULTI,		"ALLMULTI" },
71 	{ IFF_INTELLIGENT,	"INTELLIGENT" },
72 	{ IFF_MULTICAST,	"MULTICAST" },
73 	{ IFF_MULTI_BCAST,	"MULTI_BCAST" },
74 	{ IFF_UNNUMBERED,	"UNNUMBERED" },
75 	{ IFF_DHCPRUNNING,	"DHCP" },
76 	{ IFF_PRIVATE,		"PRIVATE" },
77 	{ IFF_NOXMIT,		"NOXMIT" },
78 	{ IFF_NOLOCAL,		"NOLOCAL" },
79 	{ IFF_DEPRECATED,	"DEPRECATED" },
80 	{ IFF_ADDRCONF,		"ADDRCONF" },
81 	{ IFF_ROUTER,		"ROUTER" },
82 	{ IFF_NONUD,		"NONUD" },
83 	{ IFF_ANYCAST,		"ANYCAST" },
84 	{ IFF_NORTEXCH,		"NORTEXCH" },
85 	{ IFF_IPV4,		"IPv4" },
86 	{ IFF_IPV6,		"IPv6" },
87 	{ IFF_MIPRUNNING,	"MIP" },
88 	{ IFF_NOFAILOVER,	"NOFAILOVER" },
89 	{ IFF_FAILED,		"FAILED" },
90 	{ IFF_STANDBY,		"STANDBY" },
91 	{ IFF_INACTIVE,		"INACTIVE" },
92 	{ IFF_OFFLINE,		"OFFLINE" },
93 	{ IFF_XRESOLV,		"XRESOLV" },
94 	{ IFF_COS_ENABLED,	"CoS" },
95 	{ IFF_PREFERRED,	"PREFERRED" },
96 	{ IFF_TEMPORARY,	"TEMPORARY" },
97 	{ IFF_FIXEDMTU,		"FIXEDMTU" },
98 	{ IFF_VIRTUAL,		"VIRTUAL"}
99 };
100 
101 static struct	lifreq lifr;
102 /* current interface name a praticular function is accessing */
103 static char	name[LIFNAMSIZ];
104 /* foreach interface saved name */
105 static char	origname[LIFNAMSIZ];
106 static char savedname[LIFNAMSIZ];	/* For addif */
107 static int	setaddr;
108 static char partname[LIFNAMSIZ];
109 
110 uid_t	euid;
111 
112 /*
113  * Make sure the algorithm variables hold more than the sizeof an algorithm
114  * in PF_KEY.  (For now, more than a uint8_t.)  The NO_***_?ALG indicates that
115  * there was no algorithm requested, and in the ipsec_req that service should
116  * be disabled.  (E.g. if ah_aalg remains NO_AH_AALG, then AH will be
117  * disabled on that tunnel.)
118  */
119 #define	NO_AH_AALG 256
120 #define	NO_ESP_AALG 256
121 #define	NO_ESP_EALG 256
122 
123 /*
124  * iface_t
125  * used by setifether to create a list of interfaces to mark
126  * down-up when changing the ethernet address of an interface
127  */
128 typedef struct iface {
129 	struct lifreq lifr;
130 	struct iface *next;	/* pointer to the next list element */
131 } iface_t;
132 
133 static	iface_t	*logifs = NULL; /* list of logical interfaces */
134 static 	iface_t	*phyif	= NULL;	/* physical interface */
135 
136 int	s;
137 int	af = AF_INET;	/* default address family */
138 int	debug = 0;
139 int	all = 0;	/* setifdhcp() needs to know this */
140 int	verbose = 0;
141 int	v4compat = 0;	/* Compatible printing format */
142 boolean_t	partial = _B_FALSE;
143 
144 /*
145  * Function prototypes for command functions.
146  */
147 static int	addif(char *arg, int64_t param);
148 static int	inetplumb(char *arg, int64_t param);
149 static int	inetunplumb(char *arg, int64_t param);
150 static int	removeif(char *arg, int64_t param);
151 static int	setdebugflag(char *arg, int64_t param);
152 static int	setifaddr(char *arg, int64_t param);
153 static int	setifbroadaddr(char *arg, int64_t param);
154 static int	setifdstaddr(char *arg, int64_t param);
155 static int	setifether(char *arg, int64_t param);
156 static int	setifflags(char *arg, int64_t param);
157 static int	setifindex(char *arg, int64_t param);
158 static int	setifmetric(char *arg, int64_t param);
159 static int	setifmtu(char *arg, int64_t param);
160 static int	setifnetmask(char *arg, int64_t param);
161 static int	setifprefixlen(char *arg, int64_t param);
162 static int	setifrevarp(char *arg, int64_t param);
163 static int	setifsubnet(char *arg, int64_t param);
164 static int	setiftdst(char *arg, int64_t param);
165 static int	setiftoken(char *arg, int64_t param);
166 static int	setiftsrc(char *arg, int64_t param);
167 static int	setverboseflag(char *arg, int64_t param);
168 static int	set_tun_ah_alg(char *arg, int64_t param);
169 static int	set_tun_esp_auth_alg(char *arg, int64_t param);
170 static int	set_tun_esp_encr_alg(char *arg, int64_t param);
171 static int	modlist(char *arg, int64_t param);
172 static int	modinsert(char *arg, int64_t param);
173 static int	modremove(char *arg, int64_t param);
174 static int	setifgroupname(char *arg, int64_t param);
175 static int	configinfo(char *arg, int64_t param);
176 static void	print_config_flags(uint64_t flags);
177 static void	print_flags(uint64_t flags);
178 static void	print_ifether(char *ifname);
179 static int	set_tun_encap_limit(char *arg, int64_t param);
180 static int	clr_tun_encap_limit(char *arg, int64_t param);
181 static int	set_tun_hop_limit(char *arg, int64_t param);
182 static int	setzone(char *arg, int64_t param);
183 static int	setifsrc(char *arg, int64_t param);
184 
185 #ifdef DEBUG
186 static int	setnd(char *arg, int64_t param);
187 static int	delnd(char *arg, int64_t param);
188 static int	getnd(char *arg, int64_t param);
189 #endif /* DEBUG */
190 
191 /*
192  * Address family specific function prototypes.
193  */
194 static void	in_getaddr(char *s, struct sockaddr *saddr, int *plenp);
195 static void	in_status(int force, uint64_t flags);
196 static void	in_configinfo(int force, uint64_t flags);
197 static void	in6_getaddr(char *s, struct sockaddr *saddr, int *plenp);
198 static void	in6_status(int force, uint64_t flags);
199 static void	in6_configinfo(int force, uint64_t flags);
200 
201 /*
202  * Misc support functions
203  */
204 static int	devfs_entry(di_node_t node, di_minor_t minor, void *arg);
205 static void	foreachinterface(void (*func)(), int argc, char *argv[],
206 		    int af, int64_t onflags, int64_t offflags,
207 		    int64_t lifc_flags);
208 static void	ifconfig(int argc, char *argv[], int af, struct lifreq *lifrp);
209 static int	ifdad(char *ifname, struct sockaddr_in6 *laddr);
210 static boolean_t	in_getmask(struct sockaddr_in *saddr);
211 static int	in_getprefixlen(char *addr, boolean_t slash, int plen);
212 static boolean_t	in_prefixlentomask(int prefixlen, int maxlen,
213 			    uchar_t *mask);
214 static int	settaddr(char *, int (*)(icfg_handle_t,
215 			    const struct sockaddr *, socklen_t));
216 static void	status(void);
217 static void	ifstatus(const char *);
218 static void	usage(void);
219 static int	strioctl(int s, int cmd, char *buf, int buflen);
220 static int	setifdhcp(const char *caller, const char *ifname,
221 		    int argc, char *argv[]);
222 static int	ip_domux2fd(int *, int *, int *, int *);
223 static int	ip_plink(int, int, int, int);
224 static int	modop(char *arg, char op);
225 static int	get_lun(char *);
226 static void	selectifs(int argc, char *argv[], int af,
227 			struct lifreq *lifrp);
228 static int	updownifs(iface_t *ifs, int up);
229 
230 #define	max(a, b)	((a) < (b) ? (b) : (a))
231 
232 /*
233  * DHCP_EXIT_IF_FAILURE indicates that the operation failed, but if there
234  * are more interfaces to act on (i.e., ifconfig was invoked with -a), keep
235  * on going rather than exit with an error.
236  */
237 
238 #define	DHCP_EXIT_IF_FAILURE	-1
239 #define	DHCP_IPC_MAX_WAIT	15	/* max seconds to wait to start agent */
240 
241 #define	NEXTARG		0xffffff	/* command takes an argument */
242 #define	OPTARG		0xfffffe 	/* command takes an optional argument */
243 #define	AF_ANY		(-1)
244 
245 /* Refer to the comments in ifconfig() on the netmask "hack" */
246 #define	NETMASK_CMD	"netmask"
247 struct sockaddr_storage	g_netmask;
248 boolean_t		g_netmask_set = _B_FALSE;
249 
250 struct	cmd {
251 	char		*c_name;
252 	int64_t		c_parameter;	/* NEXTARG means next argv */
253 	int		(*c_func)(char *, int64_t);
254 	int		c_abortonfail;	/* don't continue parsing args */
255 					/* for the current interface */
256 	int	c_af;			/* address family restrictions */
257 } cmds[] = {
258 	{ "up",		IFF_UP,		setifflags,	0,	AF_ANY },
259 	{ "down",	-IFF_UP,	setifflags,	0,	AF_ANY },
260 	{ "trailers",	-IFF_NOTRAILERS, setifflags,	0,	AF_ANY },
261 	{ "-trailers",	IFF_NOTRAILERS,	setifflags,	0,	AF_ANY },
262 	{ "arp",	-IFF_NOARP,	setifflags,	0,	AF_INET },
263 	{ "-arp",	IFF_NOARP,	setifflags,	0,	AF_INET },
264 	{ "router",	IFF_ROUTER,	setifflags,	0,	AF_ANY },
265 	{ "-router",	-IFF_ROUTER,	setifflags,	0,	AF_ANY },
266 	{ "private",	IFF_PRIVATE,	setifflags,	0,	AF_ANY },
267 	{ "-private",	-IFF_PRIVATE,	setifflags,	0,	AF_ANY },
268 	{ "xmit",	-IFF_NOXMIT,	setifflags,	0,	AF_ANY },
269 	{ "-xmit",	IFF_NOXMIT,	setifflags,	0,	AF_ANY },
270 	{ "-nud",	IFF_NONUD,	setifflags,	0,	AF_INET6 },
271 	{ "nud",	-IFF_NONUD,	setifflags,	0,	AF_INET6 },
272 	{ "anycast",	IFF_ANYCAST,	setifflags,	0,	AF_ANY },
273 	{ "-anycast",	-IFF_ANYCAST,	setifflags,	0,	AF_ANY },
274 	{ "local",	-IFF_NOLOCAL,	setifflags,	0,	AF_ANY },
275 	{ "-local",	IFF_NOLOCAL,	setifflags,	0,	AF_ANY },
276 	{ "deprecated",	IFF_DEPRECATED,	setifflags,	0,	AF_ANY },
277 	{ "-deprecated", -IFF_DEPRECATED, setifflags,	0,	AF_ANY },
278 	{ "preferred",	IFF_PREFERRED,	setifflags,	0,	AF_INET6 },
279 	{ "-preferred",	-IFF_PREFERRED,	setifflags,	0,	AF_INET6 },
280 	{ "debug",	0,		setdebugflag,	0,	AF_ANY },
281 	{ "verbose",	0,		setverboseflag,	0,	AF_ANY },
282 	{ NETMASK_CMD,	NEXTARG,	setifnetmask,	0,	AF_INET },
283 	{ "metric",	NEXTARG,	setifmetric,	0,	AF_ANY },
284 	{ "mtu",	NEXTARG,	setifmtu,	0,	AF_ANY },
285 	{ "index",	NEXTARG,	setifindex,	0,	AF_ANY },
286 	{ "broadcast",	NEXTARG,	setifbroadaddr,	0,	AF_INET },
287 	{ "auto-revarp", 0,		setifrevarp,	1,	AF_INET },
288 	{ "plumb",	0,		inetplumb,	1,	AF_ANY },
289 	{ "unplumb",	0,		inetunplumb,	0,	AF_ANY },
290 	{ "subnet",	NEXTARG,	setifsubnet,	0,	AF_ANY },
291 	{ "token",	NEXTARG,	setiftoken,	0,	AF_INET6 },
292 	{ "tsrc",	NEXTARG,	setiftsrc,	0,	AF_ANY },
293 	{ "tdst",	NEXTARG,	setiftdst,	0,	AF_ANY },
294 	{ "encr_auth_algs", NEXTARG,	set_tun_esp_auth_alg, 0, AF_ANY },
295 	{ "encr_algs",	NEXTARG,	set_tun_esp_encr_alg, 0, AF_ANY },
296 	{ "auth_algs",	NEXTARG,	set_tun_ah_alg,	0,	AF_ANY },
297 	{ "addif",	NEXTARG,	addif,		1,	AF_ANY },
298 	{ "removeif",	NEXTARG,	removeif,	1,	AF_ANY },
299 	{ "modlist",	0,		modlist,	1,	AF_ANY },
300 	{ "modinsert",	NEXTARG,	modinsert,	1,	AF_ANY },
301 	{ "modremove",	NEXTARG,	modremove,	1,	AF_ANY },
302 	{ "failover",	-IFF_NOFAILOVER, setifflags,	1,	AF_ANY },
303 	{ "-failover",	IFF_NOFAILOVER, setifflags,	1,	AF_ANY },
304 	{ "standby",	IFF_STANDBY,	setifflags,	1,	AF_ANY },
305 	{ "-standby",	-IFF_STANDBY,	setifflags,	1,	AF_ANY },
306 	{ "failed",	IFF_FAILED,	setifflags,	1,	AF_ANY },
307 	{ "-failed",	-IFF_FAILED,	setifflags,	1,	AF_ANY },
308 	{ "group",	NEXTARG,	setifgroupname,	1,	AF_ANY },
309 	{ "configinfo",	0,		configinfo,	1,	AF_ANY },
310 	{ "encaplimit",	NEXTARG,	set_tun_encap_limit,	0,
311 	    AF_ANY },
312 	{ "-encaplimit", 0,		clr_tun_encap_limit,	0,
313 	    AF_ANY },
314 	{ "thoplimit",	NEXTARG,	set_tun_hop_limit,	0,
315 	    AF_ANY },
316 #ifdef DEBUG
317 	{ "getnd",	NEXTARG,	getnd,		0,	AF_INET6 },
318 	{ "setnd",	NEXTARG,	setnd,		0,	AF_INET6 },
319 	{ "delnd",	NEXTARG,	delnd,		0,	AF_INET6 },
320 #endif
321 /* XXX for testing SIOCT* ioctls. Remove */
322 	{ "set",	NEXTARG,	setifaddr,	0,	AF_ANY },
323 	{ "destination", NEXTARG,	setifdstaddr,	0,	AF_ANY },
324 	{ "zone",	NEXTARG,	setzone,	0,	AF_ANY },
325 	{ "-zone",	0,		setzone,	0,	AF_ANY },
326 	{ "ether",	OPTARG,		setifether,	0,	AF_ANY },
327 	{ "usesrc",	NEXTARG,	setifsrc,	0,	AF_ANY },
328 	{ 0,		0,		setifaddr,	0,	AF_ANY },
329 	{ 0,		0,		setifdstaddr,	0,	AF_ANY },
330 	{ 0,		0,		0,		0,	0 },
331 };
332 
333 
334 typedef struct if_config_cmd {
335 	uint64_t	iff_flag;
336 	char		*iff_name;
337 } if_config_cmd_t;
338 
339 static if_config_cmd_t	if_config_cmd_tbl[] = {
340 	{ IFF_UP,		"up" },
341 	{ IFF_NOTRAILERS,	"-trailers" },
342 	{ IFF_PRIVATE,		"private" },
343 	{ IFF_NOXMIT,		"-xmit" },
344 	{ IFF_ANYCAST,		"anycast" },
345 	{ IFF_NOLOCAL,		"-local" },
346 	{ IFF_DEPRECATED,	"deprecated" },
347 	{ IFF_NOFAILOVER,	"-failover" },
348 	{ IFF_STANDBY,		"standby" },
349 	{ IFF_FAILED,		"failed" },
350 	{ IFF_PREFERRED,	"preferred" },
351 	{ 0,			0 },
352 };
353 
354 typedef struct ni {
355 	char		ni_name[LIFNAMSIZ];
356 	struct ni	*ni_next;
357 } ni_t;
358 
359 static ni_t	*ni_list = NULL;
360 static int	num_ni = 0;
361 
362 /* End defines and structure definitions for ifconfig -a plumb */
363 
364 /* Known address families */
365 struct afswtch {
366 	char *af_name;
367 	short af_af;
368 	void (*af_status)();
369 	void (*af_getaddr)();
370 	void (*af_configinfo)();
371 } afs[] = {
372 	{ "inet", AF_INET, in_status, in_getaddr, in_configinfo },
373 	{ "inet6", AF_INET6, in6_status, in6_getaddr, in6_configinfo },
374 	{ 0, 0,	0, 0, 0 }
375 };
376 
377 #define	SOCKET_AF(af)	(((af) == AF_UNSPEC) ? AF_INET : (af))
378 
379 struct afswtch *afp;	/* the address family being set or asked about */
380 
381 int
382 main(int argc, char *argv[])
383 {
384 	/* Include IFF_NOXMIT, IFF_TEMPORARY and all zone interfaces */
385 	int64_t lifc_flags = LIFC_NOXMIT | LIFC_TEMPORARY | LIFC_ALLZONES;
386 	char *default_ip_str;
387 
388 	if (argc < 2) {
389 		usage();
390 		exit(1);
391 	}
392 	argc--, argv++;
393 	if (strlen(*argv) > sizeof (name) - 1) {
394 		(void) fprintf(stderr, "%s: interface name too long\n", *argv);
395 		exit(1);
396 	}
397 	(void) strncpy(name, *argv, sizeof (name));
398 	name[sizeof (name) - 1] = '\0';
399 	(void) strncpy(origname, name, sizeof (origname));	/* For addif */
400 	euid = geteuid();
401 	default_ip_str = NULL;
402 	v4compat = get_compat_flag(&default_ip_str);
403 	if (v4compat == DEFAULT_PROT_BAD_VALUE) {
404 		(void) fprintf(stderr,
405 		    "ifconfig: %s: Bad value for %s in %s\n", default_ip_str,
406 		    DEFAULT_IP, INET_DEFAULT_FILE);
407 		free(default_ip_str);
408 		exit(2);
409 	}
410 	free(default_ip_str);
411 	argc--, argv++;
412 	if (argc > 0) {
413 		struct afswtch *myafp;
414 
415 		for (myafp = afp = afs; myafp->af_name; myafp++) {
416 			if (strcmp(myafp->af_name, *argv) == 0) {
417 				afp = myafp; argc--; argv++;
418 				break;
419 			}
420 		}
421 		af = lifr.lifr_addr.ss_family = afp->af_af;
422 		if (af == AF_INET6) {
423 			v4compat = 0;
424 		}
425 	}
426 
427 	s = socket(SOCKET_AF(af), SOCK_DGRAM, 0);
428 	if (s < 0) {
429 		Perror0_exit("socket");
430 	}
431 
432 	/*
433 	 * Special interface names is any combination of these flags.
434 	 * Note that due to the ifconfig syntax they have to be combined
435 	 * as a single '-' option.
436 	 *	-a	All interfaces
437 	 *	-u	"up" interfaces
438 	 *	-d	"down" interfaces
439 	 *	-D	Interfaces not controlled by DHCP
440 	 *	-4	IPv4 interfaces
441 	 *	-6	IPv6 interfaces
442 	 *	-X	Turn on debug (not documented)
443 	 *	-v	Turn on verbose
444 	 *	-Z	Only interfaces in caller's zone
445 	 */
446 
447 	if (name[0] == '-') {
448 		/* One or more options */
449 		int64_t onflags = 0;
450 		int64_t offflags = 0;
451 		int c;
452 		char *av[2] = { "ifconfig", name };
453 
454 		while ((c = getopt(2, av, "audDXZ46v")) != -1) {
455 			switch ((char)c) {
456 			case 'a':
457 				all = 1;
458 				break;
459 			case 'u':
460 				onflags |= IFF_UP;
461 				break;
462 			case 'd':
463 				offflags |= IFF_UP;
464 				break;
465 			case 'D':
466 				offflags |= IFF_DHCPRUNNING;
467 				break;
468 			case 'X':
469 				debug += 3;
470 				break;
471 			case 'Z':
472 				lifc_flags &= ~LIFC_ALLZONES;
473 				break;
474 			case '4':
475 				/*
476 				 * -4 is not a compatable flag, therefore
477 				 * we assume they want v4compat turned off
478 				 */
479 				v4compat = 0;
480 				onflags |= IFF_IPV4;
481 				break;
482 			case '6':
483 				/*
484 				 * If they want IPv6, well then we'll assume
485 				 * they don't want IPv4 compat
486 				 */
487 				v4compat = 0;
488 				onflags |= IFF_IPV6;
489 				break;
490 			case 'v':
491 				verbose = 1;
492 				break;
493 			case '?':
494 				usage();
495 				exit(1);
496 			}
497 		}
498 		if (!all) {
499 			(void) fprintf(stderr,
500 			    "ifconfig: %s: no such interface\n",
501 			    name);
502 			exit(1);
503 		}
504 		foreachinterface(ifconfig, argc, argv, af, onflags, offflags,
505 		    lifc_flags);
506 	} else {
507 		ifconfig(argc, argv, af, (struct lifreq *)NULL);
508 	}
509 	return (0);
510 }
511 
512 /*
513  * For each interface, call (*func)(argc, argv, af, lifrp).
514  * Only call function if onflags and offflags are set or clear, respectively,
515  * in the interfaces flags field.
516  */
517 static void
518 foreachinterface(void (*func)(), int argc, char *argv[], int af,
519     int64_t onflags, int64_t offflags, int64_t lifc_flags)
520 {
521 	int n;
522 	char *buf;
523 	struct lifnum lifn;
524 	struct lifconf lifc;
525 	struct lifreq *lifrp;
526 	struct lifreq lifrl;	/* Local lifreq struct */
527 	int numifs;
528 	unsigned bufsize;
529 	ni_t *nip;
530 	int plumball = 0;
531 	int save_af = af;
532 
533 	/*
534 	 * Special case:
535 	 * ifconfig -a plumb should find all network interfaces
536 	 * in the machine by traversing the devinfo tree.
537 	 * Also, there is no need to  SIOCGLIF* ioctls, since
538 	 * those interfaces have already been plumbed
539 	 */
540 	if (argc > 0 && (strcmp(*argv, "plumb") == 0)) {
541 		/*
542 		 * Look through the kernel's devinfo tree for
543 		 * network devices
544 		 */
545 		di_node_t root;
546 
547 		/*
548 		 * DINFOCACHE is equivalent to DINFOSUBTREE | DINFOMINOR |
549 		 * DINFOPROP | DINFOFORCE.
550 		 */
551 		if ((root = di_init("/", DINFOCACHE)) == DI_NODE_NIL) {
552 			(void) fprintf(stderr, "ifconfig: di_init failed;"
553 			    " check the devinfo driver.\n");
554 			exit(1);
555 		}
556 
557 		(void) di_walk_minor(root, DDI_NT_NET, DI_CHECK_ALIAS, NULL,
558 		    devfs_entry);
559 		di_fini(root);
560 
561 		/*
562 		 * Now, translate the linked list into
563 		 * a struct lifreq buffer
564 		 */
565 		bufsize = num_ni * sizeof (struct lifreq);
566 		if ((buf = malloc(bufsize)) == NULL)
567 			Perror0_exit("foreachinterface: malloc failed");
568 
569 		lifc.lifc_family = AF_UNSPEC;
570 		lifc.lifc_flags = lifc_flags;
571 		lifc.lifc_len = bufsize;
572 		lifc.lifc_buf = buf;
573 
574 		for (n = 0, lifrp = lifc.lifc_req; n < num_ni; n++, lifrp++) {
575 			nip = ni_list;
576 			(void) strncpy(lifrp->lifr_name, nip->ni_name,
577 			    sizeof (lifr.lifr_name));
578 			ni_list = nip->ni_next;
579 			free(nip);
580 		}
581 
582 		plumball = 1;
583 	} else {
584 		lifn.lifn_family = AF_UNSPEC;
585 		lifn.lifn_flags = lifc_flags;
586 		if (ioctl(s, SIOCGLIFNUM, (char *)&lifn) < 0) {
587 			Perror0_exit("Could not determine number"
588 			    " of interfaces");
589 		}
590 		numifs = lifn.lifn_count;
591 		if (debug)
592 			(void) printf("ifconfig: %d interfaces\n",  numifs);
593 
594 		bufsize = numifs * sizeof (struct lifreq);
595 		if ((buf = malloc(bufsize)) == NULL) {
596 			Perror0("out of memory\n");
597 			(void) close(s);
598 			return;
599 		}
600 
601 		lifc.lifc_family = AF_UNSPEC;
602 		lifc.lifc_flags = lifc_flags;
603 		lifc.lifc_len = bufsize;
604 		lifc.lifc_buf = buf;
605 
606 		if (ioctl(s, SIOCGLIFCONF, (char *)&lifc) < 0) {
607 			Perror0("SIOCGLIFCONF");
608 			(void) close(s);
609 			free(buf);
610 			return;
611 		}
612 	}
613 
614 	lifrp = lifc.lifc_req;
615 	for (n = lifc.lifc_len / sizeof (struct lifreq); n > 0; n--, lifrp++) {
616 
617 		if (!plumball) {
618 			/*
619 			 * We must close and recreate the socket each time
620 			 * since we don't know what type of socket it is now
621 			 * (each status function may change it).
622 			 */
623 
624 			(void) close(s);
625 
626 			af = lifrp->lifr_addr.ss_family;
627 			s = socket(SOCKET_AF(af), SOCK_DGRAM, 0);
628 			if (s == -1) {
629 				/*
630 				 * Perror0() assumes the name to be in the
631 				 * globally defined lifreq structure.
632 				 */
633 				(void) strncpy(lifr.lifr_name,
634 				    lifrp->lifr_name, sizeof (lifr.lifr_name));
635 				Perror0_exit("socket");
636 			}
637 		}
638 
639 		/*
640 		 * Only service interfaces that match the on and off
641 		 * flags masks.
642 		 */
643 		if (onflags || offflags) {
644 			(void) memset(&lifrl, 0, sizeof (lifrl));
645 			(void) strncpy(lifrl.lifr_name, lifrp->lifr_name,
646 				sizeof (lifrl.lifr_name));
647 			if (ioctl(s, SIOCGLIFFLAGS, (caddr_t)&lifrl) < 0) {
648 				/*
649 				 * Perror0() assumes the name to be in the
650 				 * globally defined lifreq structure.
651 				 */
652 				(void) strncpy(lifr.lifr_name,
653 				    lifrp->lifr_name, sizeof (lifr.lifr_name));
654 				Perror0_exit("foreachinterface: SIOCGLIFFLAGS");
655 			}
656 			if ((lifrl.lifr_flags & onflags) != onflags)
657 				continue;
658 			if ((~lifrl.lifr_flags & offflags) != offflags)
659 				continue;
660 		}
661 
662 		if (!plumball) {
663 			(void) strncpy(lifrl.lifr_name, lifrp->lifr_name,
664 			    sizeof (lifrl.lifr_name));
665 			if (ioctl(s, SIOCGLIFADDR, (caddr_t)&lifrl) < 0) {
666 				/*
667 				 * Perror0() assumes the name to be in the
668 				 * globally defined lifreq structure.
669 				 */
670 				(void) strncpy(lifr.lifr_name,
671 				    lifrp->lifr_name, sizeof (lifr.lifr_name));
672 				Perror0("foreachinterface: SIOCGLIFADDR");
673 				continue;
674 			}
675 			if (lifrl.lifr_addr.ss_family != af) {
676 				/* Switch address family */
677 				af = lifrl.lifr_addr.ss_family;
678 				(void) close(s);
679 
680 				s = socket(SOCKET_AF(af), SOCK_DGRAM, 0);
681 				if (s == -1) {
682 					/*
683 					 * Perror0() assumes the name to be in
684 					 * the globally defined lifreq
685 					 * structure.
686 					 */
687 					(void) strncpy(lifr.lifr_name,
688 					    lifrp->lifr_name,
689 					    sizeof (lifr.lifr_name));
690 					Perror0_exit("socket");
691 				}
692 			}
693 		}
694 
695 		/*
696 		 * Reset global state
697 		 * setaddr: Used by parser to tear apart source and dest
698 		 * name and origname contain the name of the 'current'
699 		 * interface.
700 		 */
701 		setaddr = 0;
702 		(void) strncpy(name, lifrp->lifr_name, sizeof (name));
703 		(void) strncpy(origname, name, sizeof (origname));
704 
705 		if (partial) {
706 			if (debug)
707 				(void) fprintf(stderr,
708 				    "checking partial %s against %s\n",
709 				    partname, name);
710 			if (strncmp(name, partname, strlen(partname)))
711 				continue;
712 		}
713 		(*func)(argc, argv, save_af, lifrp);
714 		/* the func could have overwritten origname, so restore */
715 		(void) strncpy(name, origname, sizeof (name));
716 	}
717 	free(buf);
718 }
719 
720 static void
721 tun_reality_check(void)
722 {
723 	struct iftun_req treq;
724 	ipsec_req_t *ipsr;
725 
726 	(void) strncpy(treq.ifta_lifr_name, name, sizeof (treq.ifta_lifr_name));
727 	if (strchr(name, ':') != NULL) {
728 		/* Return, we don't need to check. */
729 		return;
730 	}
731 	if (ioctl(s, SIOCGTUNPARAM, (caddr_t)&treq) < 0 ||
732 	    (treq.ifta_flags & IFTUN_SECURITY) == 0) {
733 		/*
734 		 * Either not a tunnel (the SIOCGTUNPARAM fails on
735 		 * non-tunnels), or the security flag is not set.  Either
736 		 * way, return.
737 		 */
738 		return;
739 	}
740 
741 	ipsr = (ipsec_req_t *)&treq.ifta_secinfo;
742 
743 	if (ipsr->ipsr_esp_req != 0 &&
744 	    ipsr->ipsr_esp_auth_alg == SADB_AALG_NONE &&
745 	    ipsr->ipsr_ah_req == 0)
746 		(void) fprintf(stderr, "ifconfig: WARNING - tunnel with "
747 		    "only ESP and potentially no authentication.\n");
748 }
749 
750 /*
751  * for the specified interface call (*func)(argc, argv, af, lifrp).
752  */
753 
754 static void
755 ifconfig(int argc, char *argv[], int af, struct lifreq *lifrp)
756 {
757 	static boolean_t scan_netmask = _B_FALSE;
758 	int ret;
759 
760 	if (argc == 0) {
761 		status();
762 		return;
763 	}
764 
765 	if (strcmp(*argv, "auto-dhcp") == 0 || strcmp(*argv, "dhcp") == 0) {
766 		if (af == AF_INET) {
767 
768 			/*
769 			 * some errors are ignored in the case where
770 			 * more than one interface is being operated on.
771 			 */
772 			ret = setifdhcp("ifconfig", name, argc, argv);
773 			if (ret == DHCP_EXIT_IF_FAILURE) {
774 				if (!all)
775 					exit(DHCP_EXIT_FAILURE);
776 			} else if (ret != DHCP_EXIT_SUCCESS)
777 				exit(ret);
778 		} else
779 			(void) fprintf(stderr, "ifconfig: dhcp not supported "
780 			    "for inet6\n");
781 		return;
782 	}
783 
784 	/*
785 	 * The following is a "hack" to get around the existing interface
786 	 * setting mechanism.  Currently, each interface attribute,
787 	 * such as address, netmask, broadcast, ... is set separately.  But
788 	 * sometimes two or more attributes must be set together.  For
789 	 * example, setting an address without a netmask does not make sense.
790 	 * Yet they can be set separately for IPv4 address using the current
791 	 * ifconfig(1M) syntax.  The kernel then "infers" the correct netmask
792 	 * using the deprecated "IP address classes."  This is simply not
793 	 * correct.
794 	 *
795 	 * The "hack" below is to go thru the whole command list looking for
796 	 * the netmask command first.  Then use this netmask to set the
797 	 * address.  This does not provide an extensible way to accommodate
798 	 * future need for setting more than one attributes together.
799 	 *
800 	 * ifconfig(1M) is too overloaded and the code is so convoluted
801 	 * that it is "safer" not to re-architect the code to fix the above
802 	 * issue, hence this "hack."  We may be better off to have a new
803 	 * command with better syntax for configuring network interface
804 	 * parameters...
805 	 */
806 	if (!scan_netmask && afp->af_af == AF_INET) {
807 		int	largc;
808 		char	**largv;
809 
810 		/* Only go thru the command list once to find the netmask. */
811 		scan_netmask = _B_TRUE;
812 
813 		/*
814 		 * Currently, if multiple netmask commands are specified, the
815 		 * last one will be used as the final netmask.  So we need
816 		 * to scan the whole list to preserve this behavior.
817 		 */
818 		for (largc = argc, largv = argv; largc > 0; largc--, largv++) {
819 			if (strcmp(*largv, NETMASK_CMD) == 0) {
820 				if (--largc == 0)
821 					break;
822 				largv++;
823 				if (strcmp(*largv, "+") == 0) {
824 					if (in_getmask((struct sockaddr_in *)
825 					    &g_netmask)) {
826 						g_netmask_set = _B_TRUE;
827 					}
828 				} else {
829 					in_getaddr(*largv, (struct sockaddr *)
830 					    &g_netmask, NULL);
831 					g_netmask_set = _B_TRUE;
832 				}
833 				/* Continue the scan. */
834 			}
835 		}
836 	}
837 
838 	while (argc > 0) {
839 		struct cmd *p;
840 		boolean_t found_cmd;
841 
842 		if (debug)
843 			(void) printf("ifconfig: argv %s\n", *argv);
844 
845 		found_cmd = _B_FALSE;
846 		for (p = cmds; p->c_func; p++) {
847 			if (p->c_name) {
848 				if (strcmp(*argv, p->c_name) == 0) {
849 					/*
850 					 * indicate that the command was
851 					 * found and check to see if
852 					 * the address family is valid
853 					 */
854 					found_cmd = _B_TRUE;
855 					if (p->c_af == AF_ANY ||
856 					    af == p->c_af)
857 						break;
858 				}
859 			} else {
860 				if (p->c_af == AF_ANY ||
861 				    af == p->c_af)
862 					break;
863 			}
864 		}
865 		/*
866 		 * If we found the keyword, but the address family
867 		 * did not match spit out an error
868 		 */
869 		if (found_cmd && p->c_name == 0) {
870 			(void) fprintf(stderr, "ifconfig: Operation %s not"
871 			    " supported for %s\n", *argv, afp->af_name);
872 			exit(1);
873 		}
874 		/*
875 		 * else (no keyword found), we assume it's an address
876 		 * of some sort
877 		 */
878 		if (p->c_name == 0 && setaddr)
879 			p++;	/* got src, do dst */
880 		if (p->c_func) {
881 			if (p->c_af == AF_INET6) {
882 				v4compat = 0;
883 			}
884 			if (p->c_parameter == NEXTARG ||
885 			    p->c_parameter == OPTARG) {
886 				argc--, argv++;
887 				if (argc == 0 && p->c_parameter == NEXTARG) {
888 					(void) fprintf(stderr,
889 					    "ifconfig: no argument for %s\n",
890 					    p->c_name);
891 					exit(1);
892 				}
893 			}
894 			/*
895 			 *	Call the function if:
896 			 *
897 			 *		there's no address family
898 			 *		restriction
899 			 *	OR
900 			 *		we don't know the address yet
901 			 *		(because we were called from
902 			 *		main)
903 			 *	OR
904 			 *		there is a restriction AND
905 			 *		the address families match
906 			 */
907 			if ((p->c_af == AF_ANY)	||
908 			    (lifrp == (struct lifreq *)NULL) ||
909 			    (lifrp->lifr_addr.ss_family == p->c_af)) {
910 				ret = (*p->c_func)(*argv, p->c_parameter);
911 				/*
912 				 *	If c_func failed and we should
913 				 *	abort processing for this
914 				 *	interface on failure, return
915 				 *	now rather than going on to
916 				 *	process other commands for
917 				 *	the same interface.
918 				 */
919 				if (ret != 0 && p->c_abortonfail)
920 					return;
921 			}
922 		}
923 		argc--, argv++;
924 	}
925 
926 	/* Check to see if there's a security hole in the tunnel setup. */
927 	tun_reality_check();
928 }
929 
930 /* ARGSUSED */
931 static int
932 setdebugflag(char *val, int64_t arg)
933 {
934 	debug++;
935 	return (0);
936 }
937 
938 /* ARGSUSED */
939 static int
940 setverboseflag(char *val, int64_t arg)
941 {
942 	verbose++;
943 	return (0);
944 }
945 
946 /*
947  * Set the interface address. Handles <addr>, <addr>/<n> as well as /<n>
948  * syntax for setting the address, the address plus netmask, and just
949  * the netmask respectively.
950  */
951 /* ARGSUSED */
952 static int
953 setifaddr(char *addr, int64_t param)
954 {
955 	int prefixlen = 0;
956 	struct	sockaddr_storage laddr;
957 	struct	sockaddr_storage netmask;
958 	struct	sockaddr_in6 *sin6;
959 	struct	sockaddr_in *sin;
960 	struct	sockaddr_storage sav_netmask;
961 
962 	if (addr[0] == '/')
963 		return (setifprefixlen(addr, 0));
964 
965 	(*afp->af_getaddr)(addr, (struct sockaddr *)&laddr, &prefixlen);
966 
967 	(void) memset(&netmask, 0, sizeof (netmask));
968 	netmask.ss_family = afp->af_af;
969 	switch (prefixlen) {
970 	case NO_PREFIX:
971 		/* Nothing there - ok */
972 		break;
973 	case BAD_ADDR:
974 		(void) fprintf(stderr, "ifconfig: Bad prefix length in %s\n",
975 		    addr);
976 		exit(1);
977 	default:
978 		if (afp->af_af == AF_INET6) {
979 			sin6 = (struct sockaddr_in6 *)&netmask;
980 			if (!in_prefixlentomask(prefixlen, ADDRBITS_V6,
981 			    (uchar_t *)&sin6->sin6_addr)) {
982 				(void) fprintf(stderr, "ifconfig: "
983 				    "Bad prefix length: %d\n",
984 				    prefixlen);
985 				exit(1);
986 			}
987 		} else {
988 			sin = (struct sockaddr_in *)&netmask;
989 			if (!in_prefixlentomask(prefixlen, ADDRBITS_V4,
990 			    (uchar_t *)&sin->sin_addr)) {
991 				(void) fprintf(stderr, "ifconfig: "
992 				    "Bad prefix length: %d\n",
993 				    prefixlen);
994 				exit(1);
995 			}
996 		}
997 		/*
998 		 * Just in case of funny setting of both prefix and netmask,
999 		 * prefix should override the netmask command.
1000 		 */
1001 		g_netmask_set = _B_FALSE;
1002 		break;
1003 	}
1004 	/* Tell parser that an address was set */
1005 	setaddr++;
1006 	/* save copy of netmask to restore in case of error */
1007 	(void) strncpy(lifr.lifr_name, name, sizeof (lifr.lifr_name));
1008 	if (ioctl(s, SIOCGLIFNETMASK, (caddr_t)&lifr) < 0)
1009 		Perror0_exit("SIOCGLIFNETMASK");
1010 	sav_netmask = lifr.lifr_addr;
1011 
1012 	/*
1013 	 * Catch set of address for AF_INET6 to perform
1014 	 * duplicate address detection. Check that the interface is
1015 	 * up.
1016 	 */
1017 	if (afp->af_af == AF_INET6) {
1018 		if (ioctl(s, SIOCGLIFFLAGS, (caddr_t)&lifr) < 0) {
1019 			Perror0_exit("ifsetaddr: SIOCGLIFFLAGS");
1020 		}
1021 		if (lifr.lifr_flags & IFF_UP) {
1022 			if (debug)
1023 				(void) printf(
1024 				    "setifaddr: Calling ifdad flags %llx\n",
1025 				    lifr.lifr_flags);
1026 			if (ifdad(name, (struct sockaddr_in6 *)&laddr) == -1)
1027 				exit(3);
1028 		}
1029 	}
1030 
1031 	/*
1032 	 * If setting the address and not the mask, clear any existing mask
1033 	 * and the kernel will then assign the default (netmask has been set
1034 	 * to 0 in this case).  If setting both (either by using a prefix or
1035 	 * using the netmask command), set the mask first, so the address will
1036 	 * be interpreted correctly.
1037 	 */
1038 	lifr.lifr_addr = g_netmask_set ? g_netmask : netmask;
1039 	if (ioctl(s, SIOCSLIFNETMASK, (caddr_t)&lifr) < 0)
1040 		Perror0_exit("SIOCSLIFNETMASK");
1041 
1042 	if (debug) {
1043 		char abuf[INET6_ADDRSTRLEN];
1044 		void *addr = (afp->af_af == AF_INET) ?
1045 		    (void *)&((struct sockaddr_in *)&laddr)->sin_addr :
1046 		    (void *)&((struct sockaddr_in6 *)&laddr)->sin6_addr;
1047 
1048 		(void) printf("Setting %s af %d addr %s\n",
1049 		    lifr.lifr_name, afp->af_af,
1050 		    inet_ntop(afp->af_af, addr, abuf, sizeof (abuf)));
1051 	}
1052 	lifr.lifr_addr = laddr;
1053 	lifr.lifr_addr.ss_family = afp->af_af;
1054 	if (ioctl(s, SIOCSLIFADDR, (caddr_t)&lifr) < 0) {
1055 		/*
1056 		 * Restore the netmask
1057 		 */
1058 		int saverr = errno;
1059 
1060 		(void) strncpy(lifr.lifr_name, name, sizeof (lifr.lifr_name));
1061 		lifr.lifr_addr = sav_netmask;
1062 		(void) ioctl(s, SIOCSLIFNETMASK, (caddr_t)&lifr);
1063 		errno = saverr;
1064 		Perror0_exit("SIOCSLIFADDR");
1065 	}
1066 
1067 	return (0);
1068 }
1069 
1070 /*
1071  * The following functions are stolen from the ipseckey(1m) program.
1072  * Perhaps they should be somewhere common, but for now, we just maintain
1073  * two versions.  We do this because of the different semantics for which
1074  * algorithms we select ("requested" for ifconfig vs. "actual" for key).
1075  */
1076 
1077 static ulong_t
1078 parsenum(char *num)
1079 {
1080 	ulong_t rc;
1081 	char *end = NULL;
1082 
1083 	errno = 0;
1084 	rc = strtoul(num, &end, 0);
1085 	if (errno != 0 || end == num || *end != '\0') {
1086 		rc = (ulong_t)-1;
1087 	}
1088 
1089 	return (rc);
1090 }
1091 
1092 /*
1093  * Parse and reverse parse possible algorithm values, include numbers.
1094  * Mostly stolen from ipseckey.c. See the comments above parsenum() for why
1095  * this isn't common to ipseckey.c.
1096  *
1097  * NOTE: Static buffer in this function for the return value.  Since ifconfig
1098  *	 isn't multithreaded, this isn't a huge problem.
1099  */
1100 
1101 #define	NBUF_SIZE 20	/* Enough to print a large integer. */
1102 
1103 static char *
1104 rparsealg(uint8_t alg_value, int proto_num)
1105 {
1106 	struct ipsecalgent *alg;
1107 	static char numprint[128];	/* Enough to hold an algorithm name. */
1108 
1109 	/* Special-case 0 to return "<any-none>" */
1110 	if (alg_value == 0)
1111 		return ("<any-none>");
1112 
1113 	alg = getipsecalgbynum(alg_value, proto_num, NULL);
1114 	if (alg != NULL) {
1115 		(void) strlcpy(numprint, alg->a_names[0], sizeof (numprint));
1116 		freeipsecalgent(alg);
1117 	} else {
1118 		(void) snprintf(numprint, sizeof (numprint), "%d", alg_value);
1119 	}
1120 
1121 	return (numprint);
1122 }
1123 
1124 static uint_t
1125 parsealg(char *algname, int proto_num)
1126 {
1127 	struct ipsecalgent *alg;
1128 	ulong_t invalue;
1129 
1130 	if (algname == NULL) {
1131 		(void) fprintf(stderr, "ifconfig: Unexpected end of command "
1132 		    "line.\n");
1133 		exit(1);
1134 	}
1135 
1136 	/*
1137 	 * Special-case "none". Use strcasecmp because its length is
1138 	 * bound.
1139 	 */
1140 	if (strcasecmp("none", algname) == 0) {
1141 		return ((proto_num == IPSEC_PROTO_ESP) ?
1142 		    NO_ESP_EALG : NO_ESP_AALG);
1143 	}
1144 
1145 	alg = getipsecalgbyname(algname, proto_num, NULL);
1146 	if (alg != NULL) {
1147 		invalue = alg->a_alg_num;
1148 		freeipsecalgent(alg);
1149 		return ((uint_t)invalue);
1150 	}
1151 
1152 	/*
1153 	 * Since algorithms can be loaded during kernel run-time, check for
1154 	 * numeric algorithm values too.
1155 	 */
1156 	invalue = parsenum(algname);
1157 	if ((invalue & (ulong_t)0xff) == invalue)
1158 		return ((uint_t)invalue);
1159 
1160 	(void) fprintf(stderr, "ifconfig: %s algorithm type %s unknown.\n",
1161 	    (proto_num == IPSEC_PROTO_ESP) ?
1162 	    "Encryption" : "Authentication", algname);
1163 	exit(1);
1164 	/* NOTREACHED */
1165 }
1166 
1167 /*
1168  * Actual ifconfig functions to set tunnel security properties.
1169  */
1170 
1171 enum ipsec_alg_type { ESP_ENCR_ALG = 1, ESP_AUTH_ALG, AH_AUTH_ALG };
1172 
1173 boolean_t first_set_tun = _B_TRUE;
1174 boolean_t encr_alg_set = _B_FALSE;
1175 
1176 static int
1177 set_tun_algs(int which_alg, int alg)
1178 {
1179 	struct iftun_req treq;
1180 	ipsec_req_t *ipsr;
1181 
1182 	(void) strncpy(treq.ifta_lifr_name, name, sizeof (treq.ifta_lifr_name));
1183 	if (strchr(name, ':') != NULL) {
1184 		errno = EPERM;
1185 		Perror0_exit("Tunnel params on logical interfaces");
1186 	}
1187 	if (ioctl(s, SIOCGTUNPARAM, (caddr_t)&treq) < 0) {
1188 		if (errno == EOPNOTSUPP || errno == EINVAL)
1189 			Perror0_exit("Not a tunnel");
1190 		else Perror0_exit("SIOCGTUNPARAM");
1191 	}
1192 
1193 	ipsr = (ipsec_req_t *)&treq.ifta_secinfo;
1194 
1195 	if (treq.ifta_vers != IFTUN_VERSION) {
1196 		(void) fprintf(stderr,
1197 		    "Kernel tunnel secinfo version mismatch.\n");
1198 		exit(1);
1199 	}
1200 
1201 	/*
1202 	 * If I'm just starting off this ifconfig, I want a clean slate,
1203 	 * otherwise, I've captured the current tunnel security settings.
1204 	 * In the case of continuation, I merely add to the settings.
1205 	 */
1206 	if (first_set_tun) {
1207 		first_set_tun = _B_FALSE;
1208 		(void) memset(ipsr, 0, sizeof (*ipsr));
1209 	}
1210 
1211 	treq.ifta_flags = IFTUN_SECURITY;
1212 
1213 	switch (which_alg) {
1214 	case ESP_ENCR_ALG:
1215 		if (alg == NO_ESP_EALG) {
1216 			if (ipsr->ipsr_esp_auth_alg == SADB_AALG_NONE)
1217 				ipsr->ipsr_esp_req = 0;
1218 			ipsr->ipsr_esp_alg = SADB_EALG_NONE;
1219 		} else {
1220 			encr_alg_set = _B_TRUE;
1221 			ipsr->ipsr_esp_req =
1222 			    IPSEC_PREF_REQUIRED | IPSEC_PREF_UNIQUE;
1223 			ipsr->ipsr_esp_alg = alg;
1224 		}
1225 		break;
1226 	case ESP_AUTH_ALG:
1227 		if (alg == NO_ESP_AALG) {
1228 			if (ipsr->ipsr_esp_alg == SADB_EALG_NONE ||
1229 			    ipsr->ipsr_esp_alg == SADB_EALG_NULL)
1230 				ipsr->ipsr_esp_req = 0;
1231 			ipsr->ipsr_esp_auth_alg = SADB_AALG_NONE;
1232 		} else {
1233 			ipsr->ipsr_esp_req =
1234 			    IPSEC_PREF_REQUIRED | IPSEC_PREF_UNIQUE;
1235 			ipsr->ipsr_esp_auth_alg = alg;
1236 
1237 			/* Let the user specify NULL encryption implicitly. */
1238 			if (ipsr->ipsr_esp_alg == SADB_EALG_NONE &&
1239 			    !encr_alg_set)
1240 				ipsr->ipsr_esp_alg = SADB_EALG_NULL;
1241 		}
1242 		break;
1243 	case AH_AUTH_ALG:
1244 		if (alg == NO_AH_AALG) {
1245 			ipsr->ipsr_ah_req = 0;
1246 			ipsr->ipsr_auth_alg = SADB_AALG_NONE;
1247 		} else {
1248 			ipsr->ipsr_ah_req =
1249 			    IPSEC_PREF_REQUIRED | IPSEC_PREF_UNIQUE;
1250 			ipsr->ipsr_auth_alg = alg;
1251 		}
1252 		break;
1253 		/* Will never hit DEFAULT */
1254 	}
1255 
1256 	if (ioctl(s, SIOCSTUNPARAM, (caddr_t)&treq) < 0) {
1257 		Perror2_exit("set tunnel security properties",
1258 		    treq.ifta_lifr_name);
1259 	}
1260 
1261 	return (0);
1262 }
1263 
1264 /* ARGSUSED */
1265 static int
1266 set_tun_esp_encr_alg(char *addr, int64_t param)
1267 {
1268 	return (set_tun_algs(ESP_ENCR_ALG,
1269 		    parsealg(addr, IPSEC_PROTO_ESP)));
1270 }
1271 
1272 /* ARGSUSED */
1273 static int
1274 set_tun_esp_auth_alg(char *addr, int64_t param)
1275 {
1276 	return (set_tun_algs(ESP_AUTH_ALG,
1277 		    parsealg(addr, IPSEC_PROTO_AH)));
1278 }
1279 
1280 /* ARGSUSED */
1281 static int
1282 set_tun_ah_alg(char *addr, int64_t param)
1283 {
1284 	return (set_tun_algs(AH_AUTH_ALG,
1285 		    parsealg(addr, IPSEC_PROTO_AH)));
1286 }
1287 
1288 /* ARGSUSED */
1289 static int
1290 setifrevarp(char *arg, int64_t param)
1291 {
1292 	struct sockaddr_in	laddr;
1293 
1294 	if (afp->af_af == AF_INET6) {
1295 		(void) fprintf(stderr,
1296 		    "ifconfig: revarp not possible on IPv6 interface %s\n",
1297 		    name);
1298 		exit(1);
1299 	}
1300 	if (doifrevarp(name, &laddr)) {
1301 		(void) strncpy(lifr.lifr_name, name, sizeof (lifr.lifr_name));
1302 		laddr.sin_family = AF_INET;
1303 		(void) memcpy(&lifr.lifr_addr, &laddr, sizeof (laddr));
1304 		if (ioctl(s, SIOCSLIFADDR, (caddr_t)&lifr) < 0)
1305 			Perror0_exit("SIOCSLIFADDR");
1306 	}
1307 	return (0);
1308 }
1309 
1310 /* ARGSUSED */
1311 static int
1312 setifsubnet(char *addr, int64_t param)
1313 {
1314 	int prefixlen = 0;
1315 	struct	sockaddr_storage subnet;
1316 
1317 	(*afp->af_getaddr)(addr, &subnet, &prefixlen);
1318 
1319 	switch (prefixlen) {
1320 	case NO_PREFIX:
1321 		(void) fprintf(stderr,
1322 		    "ifconfig: Missing prefix length in subnet %s\n", addr);
1323 		exit(1);
1324 		/* NOTREACHED */
1325 	case BAD_ADDR:
1326 		(void) fprintf(stderr,
1327 		    "ifconfig: Bad prefix length in %s\n", addr);
1328 		exit(1);
1329 	default:
1330 		break;
1331 	}
1332 
1333 	lifr.lifr_addr = subnet;
1334 	lifr.lifr_addrlen = prefixlen;
1335 	(void) strncpy(lifr.lifr_name, name, sizeof (lifr.lifr_name));
1336 	if (ioctl(s, SIOCSLIFSUBNET, (caddr_t)&lifr) < 0)
1337 		Perror0_exit("SIOCSLIFSUBNET");
1338 
1339 	return (0);
1340 }
1341 
1342 /* ARGSUSED */
1343 static int
1344 setifnetmask(char *addr, int64_t param)
1345 {
1346 	struct sockaddr_in netmask;
1347 
1348 	assert(afp->af_af != AF_INET6);
1349 
1350 	if (strcmp(addr, "+") == 0) {
1351 		if (in_getmask(&netmask) == 0)
1352 			return (0);
1353 	} else {
1354 		in_getaddr(addr, (struct sockaddr *)&netmask, NULL);
1355 	}
1356 	(void) strncpy(lifr.lifr_name, name, sizeof (lifr.lifr_name));
1357 	(void) memcpy(&lifr.lifr_addr, &netmask, sizeof (netmask));
1358 	if (ioctl(s, SIOCSLIFNETMASK, (caddr_t)&lifr) < 0)
1359 		Perror0_exit("SIOCSLIFNETMASK");
1360 	return (0);
1361 }
1362 
1363 /*
1364  * Parse '/<n>' as a netmask.
1365  */
1366 /* ARGSUSED */
1367 static int
1368 setifprefixlen(char *addr, int64_t param)
1369 {
1370 	int prefixlen;
1371 	int af = afp->af_af;
1372 
1373 	prefixlen = in_getprefixlen(addr, _B_TRUE,
1374 	    (af == AF_INET) ? ADDRBITS_V4 : ADDRBITS_V6);
1375 	if (prefixlen < 0) {
1376 		(void) fprintf(stderr,
1377 		    "ifconfig: Bad prefix length in %s\n", addr);
1378 		exit(1);
1379 	}
1380 	(void) memset(&lifr.lifr_addr, 0, sizeof (lifr.lifr_addr));
1381 	lifr.lifr_addr.ss_family = af;
1382 	if (af == AF_INET6) {
1383 		struct sockaddr_in6 *sin6;
1384 
1385 		sin6 = (struct sockaddr_in6 *)&lifr.lifr_addr;
1386 		if (!in_prefixlentomask(prefixlen, ADDRBITS_V6,
1387 		    (uchar_t *)&sin6->sin6_addr)) {
1388 			(void) fprintf(stderr, "ifconfig: "
1389 			    "Bad prefix length: %d\n",
1390 			    prefixlen);
1391 			exit(1);
1392 		}
1393 	} else if (af == AF_INET) {
1394 		struct sockaddr_in *sin;
1395 
1396 		sin = (struct sockaddr_in *)&lifr.lifr_addr;
1397 		if (!in_prefixlentomask(prefixlen, ADDRBITS_V4,
1398 		    (uchar_t *)&sin->sin_addr)) {
1399 			(void) fprintf(stderr, "ifconfig: "
1400 			    "Bad prefix length: %d\n",
1401 			    prefixlen);
1402 			exit(1);
1403 		}
1404 	} else {
1405 		(void) fprintf(stderr, "ifconfig: setting prefix only supported"
1406 		    " for address family inet or inet6\n");
1407 		exit(1);
1408 	}
1409 	(void) strncpy(lifr.lifr_name, name, sizeof (lifr.lifr_name));
1410 	if (ioctl(s, SIOCSLIFNETMASK, (caddr_t)&lifr) < 0)
1411 		Perror0_exit("SIOCSLIFNETMASK");
1412 	return (0);
1413 }
1414 
1415 /* ARGSUSED */
1416 static int
1417 setifbroadaddr(char *addr, int64_t param)
1418 {
1419 	struct	sockaddr_in broadaddr;
1420 
1421 	assert(afp->af_af != AF_INET6);
1422 
1423 	if (strcmp(addr, "+") == 0) {
1424 		/*
1425 		 * This doesn't set the broadcast address at all. Rather, it
1426 		 * gets, then sets the interface's address, relying on the fact
1427 		 * that resetting the address will reset the broadcast address.
1428 		 */
1429 		(void) strncpy(lifr.lifr_name, name,
1430 		    sizeof (lifr.lifr_name));
1431 		if (ioctl(s, SIOCGLIFADDR, (caddr_t)&lifr) < 0) {
1432 			if (errno != EADDRNOTAVAIL)
1433 				Perror0_exit("SIOCGLIFADDR");
1434 			return (0);
1435 		}
1436 		if (ioctl(s, SIOCSLIFADDR, (caddr_t)&lifr) < 0)
1437 			Perror0_exit("SIOCGLIFADDR");
1438 
1439 		return (0);
1440 	}
1441 	in_getaddr(addr, (struct sockaddr *)&broadaddr, NULL);
1442 
1443 	(void) memcpy(&lifr.lifr_addr, &broadaddr, sizeof (broadaddr));
1444 	(void) strncpy(lifr.lifr_name, name, sizeof (lifr.lifr_name));
1445 	if (ioctl(s, SIOCSLIFBRDADDR, (caddr_t)&lifr) < 0)
1446 		Perror0_exit("SIOCSLIFBRDADDR");
1447 	return (0);
1448 }
1449 
1450 /*
1451  * set interface destination address
1452  */
1453 /* ARGSUSED */
1454 static int
1455 setifdstaddr(char *addr, int64_t param)
1456 {
1457 	(*afp->af_getaddr)(addr, (struct sockaddr *)&lifr.lifr_addr, NULL);
1458 	(void) strncpy(lifr.lifr_name, name, sizeof (lifr.lifr_name));
1459 	if (ioctl(s, SIOCSLIFDSTADDR, (caddr_t)&lifr) < 0)
1460 		Perror0_exit("setifdstaddr: SIOCSLIFDSTADDR");
1461 	return (0);
1462 }
1463 
1464 /* ARGSUSED */
1465 static int
1466 setifflags(char *val, int64_t value)
1467 {
1468 	int phyintlen, origphyintlen;
1469 
1470 	(void) strncpy(lifr.lifr_name, name, sizeof (lifr.lifr_name));
1471 	if (ioctl(s, SIOCGLIFFLAGS, (caddr_t)&lifr) < 0)
1472 		Perror0_exit("setifflags: SIOCGLIFFLAGS");
1473 
1474 	if (value == IFF_NOFAILOVER) {
1475 		/*
1476 		 * Fail if '-failover' is set after a prior addif created the
1477 		 * alias on a different interface. This can happen when the
1478 		 * interface is part of an IPMP group.
1479 		 */
1480 		phyintlen = strcspn(name, ":");
1481 		origphyintlen = strcspn(origname, ":");
1482 		if (phyintlen != origphyintlen ||
1483 		    strncmp(name, origname, phyintlen) != 0) {
1484 			(void) fprintf(stderr, "ifconfig: can't set -failover "
1485 			    "on failed/standby/offlined interface %s\n",
1486 			    origname);
1487 			exit(1);
1488 		}
1489 	}
1490 
1491 	/*
1492 	 * Catch "up" transition for AF_INET6 to perform duplicate address
1493 	 * detection. ifdad checks if an address has been set.
1494 	 */
1495 	if (afp->af_af == AF_INET6 && !(lifr.lifr_flags & IFF_UP) &&
1496 	    value == IFF_UP) {
1497 		if (debug)
1498 			(void) printf(
1499 			    "setifaddr:Calling ifdad flags %llx value 0x%llx\n",
1500 			    lifr.lifr_flags, value);
1501 		if (ifdad(name, NULL) == -1)
1502 			exit(1);
1503 	}
1504 
1505 	if (value < 0) {
1506 		value = -value;
1507 		lifr.lifr_flags &= ~value;
1508 	} else
1509 		lifr.lifr_flags |= value;
1510 	(void) strncpy(lifr.lifr_name, name, sizeof (lifr.lifr_name));
1511 	if (ioctl(s, SIOCSLIFFLAGS, (caddr_t)&lifr) < 0) {
1512 		Perror0_exit("setifflags: SIOCSLIFFLAGS");
1513 	}
1514 	return (0);
1515 }
1516 
1517 /* ARGSUSED */
1518 static int
1519 setifmetric(char *val, int64_t param)
1520 {
1521 	(void) strncpy(lifr.lifr_name, name, sizeof (lifr.lifr_name));
1522 	lifr.lifr_metric = atoi(val);
1523 	if (ioctl(s, SIOCSLIFMETRIC, (caddr_t)&lifr) < 0)
1524 		Perror0_exit("setifmetric: SIOCSLIFMETRIC");
1525 	return (0);
1526 }
1527 
1528 /* ARGSUSED */
1529 static int
1530 setifmtu(char *val, int64_t param)
1531 {
1532 	(void) strncpy(lifr.lifr_name, name, sizeof (lifr.lifr_name));
1533 	lifr.lifr_mtu = atoi(val);
1534 	if (ioctl(s, SIOCSLIFMTU, (caddr_t)&lifr) < 0)
1535 		Perror0_exit("setifmtu: SIOCSLIFMTU");
1536 	return (0);
1537 }
1538 
1539 /* ARGSUSED */
1540 static int
1541 setifindex(char *val, int64_t param)
1542 {
1543 	(void) strncpy(lifr.lifr_name, name, sizeof (lifr.lifr_name));
1544 	lifr.lifr_index = atoi(val);
1545 	if (ioctl(s, SIOCSLIFINDEX, (caddr_t)&lifr) < 0)
1546 		Perror0_exit("setifindex: SIOCSLIFINDEX");
1547 	return (0);
1548 }
1549 
1550 /* ARGSUSED */
1551 static int
1552 setifether(char *addr, int64_t param)
1553 {
1554 	uchar_t	*ea;
1555 	iface_t	*current;
1556 	int	maclen;
1557 
1558 	if (addr == NULL) {
1559 		ifstatus(name);
1560 		print_ifether(name);
1561 		return (0);
1562 	}
1563 
1564 	phyif = NULL;
1565 	logifs = NULL;
1566 
1567 	/*
1568 	 * if the IP interface in the arguments is a logical
1569 	 * interface, exit with an error now.
1570 	 */
1571 	if (strchr(name, ':') != NULL) {
1572 		(void) fprintf(stderr, "ifconfig: cannot change"
1573 		    " ethernet address of a logical interface\n");
1574 		exit(1);
1575 	}
1576 
1577 	ea = _link_aton(addr, &maclen);
1578 	if (ea == NULL) {
1579 		if (maclen == -1)
1580 			(void) fprintf(stderr,
1581 			    "ifconfig: %s: bad address\n", addr);
1582 		else
1583 			(void) fprintf(stderr, "ifconfig: malloc() failed\n");
1584 		exit(1);
1585 	}
1586 
1587 	(void) strncpy(savedname, name, sizeof (savedname));
1588 
1589 	/*
1590 	 * Call selectifs only for the IP interfaces that are ipv4.
1591 	 * offflags == IFF_IPV6 because you should not change the
1592 	 *		Ethernet address of an ipv6 interface
1593 	 */
1594 	foreachinterface(selectifs, 0, (char **)NULL, 0, 0, IFF_IPV6, 0);
1595 
1596 	/* If physical interface not found, exit now */
1597 	if (phyif == NULL) {
1598 		(void) fprintf(stderr,
1599 		    "ifconfig: interface %s not found\n", savedname);
1600 		exit(1);
1601 	}
1602 
1603 	/* Restore */
1604 	(void) strncpy(name, savedname, sizeof (name));
1605 	(void) strncpy(origname, savedname, sizeof (origname));
1606 	(void) strncpy(lifr.lifr_name, name, sizeof (lifr.lifr_name));
1607 
1608 	/*
1609 	 * close and reopen the socket
1610 	 * we don't know which type of socket we have now
1611 	 */
1612 	(void) close(s);
1613 	s = socket(SOCKET_AF(AF_UNSPEC), SOCK_DGRAM, 0);
1614 	if (s < 0) {
1615 		Perror0_exit("socket");
1616 	}
1617 
1618 	/*
1619 	 * mark down the logical interfaces first,
1620 	 * and then the physical interface
1621 	 */
1622 	if (updownifs(logifs, 0) < 0 || updownifs(phyif, 0) < 0) {
1623 		Perror0_exit("mark down interface failed");
1624 	}
1625 
1626 	/*
1627 	 * Change the physical address
1628 	 */
1629 	if (dlpi_set_address(savedname, ea, maclen) == -1) {
1630 		(void) fprintf(stderr,
1631 		    "ifconfig: failed setting mac address on %s\n",
1632 		    savedname);
1633 	}
1634 
1635 	/*
1636 	 * if any interfaces were marked down before changing the
1637 	 * ethernet address, put them up again.
1638 	 * First the physical interface, then the logical ones.
1639 	 */
1640 	if (updownifs(phyif, 1) < 0 || updownifs(logifs, 1) < 0) {
1641 		Perror0_exit("mark down interface failed");
1642 	}
1643 
1644 	/* Free the memory allocated by selectifs */
1645 	free(phyif);
1646 	for (current = logifs; current != NULL; current = logifs) {
1647 		logifs = logifs->next;
1648 		free(current);
1649 	}
1650 
1651 	return (0);
1652 }
1653 
1654 /*
1655  * Print an interface's Ethernet address, if it has one.
1656  */
1657 static void
1658 print_ifether(char *ifname)
1659 {
1660 	int		protocol;
1661 	icfg_if_t	interface;
1662 	icfg_handle_t	handle;
1663 	int		fd;
1664 
1665 	/*
1666 	 * Loopback interfaces and tunnels can't have MAC addresses,
1667 	 * so filter them out first.
1668 	 */
1669 	if (strcmp(ifname, LOOPBACK_IF) == 0)
1670 		return;
1671 
1672 	(void) strncpy(lifr.lifr_name, name, sizeof (lifr.lifr_name));
1673 
1674 	fd = socket(AF_INET, SOCK_DGRAM, 0);
1675 	if (fd == -1 || ioctl(fd, SIOCGLIFFLAGS, &lifr) == -1) {
1676 		/*
1677 		 * It's possible the interface is only configured for
1678 		 * IPv6; check again with AF_INET6.
1679 		 */
1680 		(void) close(fd);
1681 		fd = socket(AF_INET6, SOCK_DGRAM, 0);
1682 		if (fd == -1 || ioctl(fd, SIOCGLIFFLAGS, &lifr) == -1) {
1683 			(void) close(fd);
1684 			return;
1685 		}
1686 	}
1687 	(void) close(fd);
1688 
1689 	/* Virtual interfaces don't have MAC addresses */
1690 	if (lifr.lifr_flags & IFF_VIRTUAL)
1691 		return;
1692 
1693 	/*
1694 	 * We must be careful to set if_protocol based on the current
1695 	 * properties of the interface.  For instance, if "ip.tun0" is
1696 	 * configured only as an IPv6 tunnel, then if_protocol must be
1697 	 * set to AF_INET6 or icfg_get_tunnel_lower() will fail and
1698 	 * we will falsely conclude that it's not a tunnel.
1699 	 */
1700 	interface.if_protocol = AF_INET;
1701 	if (lifr.lifr_flags & IFF_IPV6)
1702 		interface.if_protocol = AF_INET6;
1703 
1704 	(void) strncpy(interface.if_name, ifname, sizeof (interface.if_name));
1705 
1706 	if (icfg_open(&handle, &interface) == ICFG_SUCCESS) {
1707 		if (icfg_get_tunnel_lower(handle, &protocol) == ICFG_SUCCESS) {
1708 			/* Tunnel op succeeded -- it's a tunnel so skip */
1709 			icfg_close(handle);
1710 			return;
1711 		}
1712 		icfg_close(handle);
1713 	}
1714 
1715 	dlpi_print_address(ifname);
1716 }
1717 
1718 /*
1719  * static void selectifs(int argc, char *argv[], int af, struct lifreq *rp)
1720  *
1721  * Called inside setifether() to create a list of interfaces to
1722  * mark down/up when changing the Ethernet address.
1723  * If the current interface is the physical interface passed
1724  * as an argument to ifconfig, update phyif.
1725  * If the current interface is a logical interface associated
1726  * to the physical interface, add it to the logifs list.
1727  */
1728 /* ARGSUSED */
1729 static void
1730 selectifs(int argc, char *argv[], int af, struct lifreq *rp)
1731 {
1732 	char		*colonp;
1733 	int		length;
1734 	iface_t		*current;
1735 
1736 	/*
1737 	 *  savedname=	name of the IP interface to which you want to
1738 	 *		change ethernet address
1739 	 *  name=	name of the current IP interface
1740 	 */
1741 	colonp = strchr(name, ':');
1742 	if (colonp == NULL)
1743 		length = max(strlen(savedname), strlen(name));
1744 	else
1745 		length = max(strlen(savedname), colonp - name);
1746 	if (strncmp(savedname, name, length) == 0) {
1747 		(void) strcpy(lifr.lifr_name, name);
1748 		if (ioctl(s, SIOCGLIFFLAGS, &lifr) < 0) {
1749 			Perror0("selectifs: SIOCGLIFFLAGS");
1750 			return;
1751 		}
1752 
1753 		if ((current = malloc(sizeof (iface_t))) == NULL) {
1754 			Perror0_exit("selectifs: malloc failed\n");
1755 		}
1756 
1757 		if (colonp == NULL) {
1758 			/* this is the physical interface */
1759 			phyif = current;
1760 			bcopy(&lifr, &phyif->lifr, sizeof (struct lifreq));
1761 			phyif->next = NULL;
1762 		} else {
1763 			/* this is a logical interface */
1764 			bcopy(&lifr, &current->lifr, sizeof (struct lifreq));
1765 			current->next = logifs;
1766 			logifs = current;
1767 		}
1768 	}
1769 }
1770 
1771 /*
1772  * static int updownifs(iface_t *ifs, int up)
1773  *
1774  * It takes in input a list of IP interfaces (ifs)
1775  * and a flag (up).
1776  * It marks each interface in the list down (up = 0)
1777  * or up (up > 0). This is done ONLY if the IP
1778  * interface was originally up.
1779  *
1780  * Return values:
1781  *  0 = everything OK
1782  * -1 = problem
1783  */
1784 static int
1785 updownifs(iface_t *ifs, int up)
1786 {
1787 	iface_t *current;
1788 	int	ret = 0;
1789 	int 	save_errno;
1790 	char	savename[LIFNAMSIZ];
1791 	uint64_t orig_flags;
1792 
1793 	for (current = ifs; current != NULL; current = current->next) {
1794 		if (current->lifr.lifr_flags & IFF_UP) {
1795 			orig_flags = current->lifr.lifr_flags;
1796 			if (!up)
1797 				current->lifr.lifr_flags &= ~IFF_UP;
1798 			if (ioctl(s, SIOCSLIFFLAGS, &current->lifr) < 0) {
1799 				save_errno = errno;
1800 				(void) strcpy(savename,
1801 				    current->lifr.lifr_name);
1802 				ret = -1;
1803 			}
1804 			if (!up) /* restore the original flags */
1805 				current->lifr.lifr_flags = orig_flags;
1806 		}
1807 	}
1808 
1809 	if (ret == -1) {
1810 		(void) strcpy(lifr.lifr_name, savename);
1811 		errno = save_errno;
1812 	}
1813 	return (ret);
1814 }
1815 
1816 /*
1817  * Create the next unused logical interface using the original name
1818  * and assign the address (and mask if '/<n>' is part of the address).
1819  * Use the new logical interface for subsequent subcommands by updating
1820  * the name variable.
1821  *
1822  * This allows syntax like:
1823  *	ifconfig le0 addif 109.106.86.130 netmask + up \
1824  *	addif 109.106.86.131 netmask + up
1825  */
1826 /* ARGSUSED */
1827 static int
1828 addif(char *str, int64_t param)
1829 {
1830 	int prefixlen = 0;
1831 	struct sockaddr_storage laddr;
1832 	struct sockaddr_storage mask;
1833 
1834 	(void) strncpy(name, origname, sizeof (name));
1835 
1836 	if (strchr(name, ':') != NULL) {
1837 		(void) fprintf(stderr,
1838 		    "ifconfig: addif: bad physical interface name %s\n",
1839 		    name);
1840 		exit(1);
1841 	}
1842 
1843 	/*
1844 	 * clear so parser will interpret next address as source followed
1845 	 * by possible dest
1846 	 */
1847 	setaddr = 0;
1848 	(*afp->af_getaddr)(str, (struct sockaddr *)&laddr, &prefixlen);
1849 
1850 	switch (prefixlen) {
1851 	case NO_PREFIX:
1852 		/* Nothing there - ok */
1853 		break;
1854 	case BAD_ADDR:
1855 		(void) fprintf(stderr,
1856 		    "ifconfig: Bad prefix length in %s\n", str);
1857 		exit(1);
1858 	default:
1859 		(void) memset(&mask, 0, sizeof (mask));
1860 		mask.ss_family = afp->af_af;
1861 		if (afp->af_af == AF_INET6) {
1862 			struct sockaddr_in6 *sin6;
1863 			sin6 = (struct sockaddr_in6 *)&mask;
1864 			if (!in_prefixlentomask(prefixlen, ADDRBITS_V6,
1865 			    (uchar_t *)&sin6->sin6_addr)) {
1866 				(void) fprintf(stderr, "ifconfig: "
1867 				    "Bad prefix length: %d\n",
1868 				    prefixlen);
1869 				exit(1);
1870 			}
1871 		} else {
1872 			struct sockaddr_in *sin;
1873 
1874 			sin = (struct sockaddr_in *)&mask;
1875 			if (!in_prefixlentomask(prefixlen, ADDRBITS_V4,
1876 			    (uchar_t *)&sin->sin_addr)) {
1877 				(void) fprintf(stderr, "ifconfig: "
1878 				    "Bad prefix length: %d\n",
1879 				    prefixlen);
1880 				exit(1);
1881 			}
1882 		}
1883 		break;
1884 	}
1885 
1886 	/* Set the address and then the mask (if there was one) */
1887 	(void) strncpy(lifr.lifr_name, name, sizeof (lifr.lifr_name));
1888 	lifr.lifr_addr = laddr;
1889 
1890 	/* Note: no need to do DAD here since the interface isn't up yet. */
1891 
1892 	if (ioctl(s, SIOCLIFADDIF, (caddr_t)&lifr) < 0)
1893 		Perror0_exit("addif: SIOCLIFADDIF");
1894 
1895 	(void) printf("Created new logical interface %s\n",
1896 	    lifr.lifr_name);
1897 	(void) strncpy(name, lifr.lifr_name, sizeof (name));
1898 
1899 	if (prefixlen >= 0) {
1900 		(void) strncpy(lifr.lifr_name, name, sizeof (lifr.lifr_name));
1901 		lifr.lifr_addr = mask;
1902 		if (ioctl(s, SIOCSLIFNETMASK, (caddr_t)&lifr) < 0)
1903 			Perror0_exit("addif: SIOCSLIFNETMASK");
1904 	}
1905 	/*
1906 	 * let parser know we got a source.
1907 	 * Next address, if given, should be dest
1908 	 */
1909 	setaddr++;
1910 	return (0);
1911 }
1912 
1913 /*
1914  * Remove a logical interface based on its IP address. Unlike addif
1915  * there is no '/<n>' here.
1916  * Verifies that the interface is down before it is removed.
1917  */
1918 /* ARGSUSED */
1919 static int
1920 removeif(char *str, int64_t param)
1921 {
1922 	struct sockaddr_storage laddr;
1923 
1924 	if (strchr(name, ':') != NULL) {
1925 		(void) fprintf(stderr,
1926 		    "ifconfig: removeif: bad physical interface name %s\n",
1927 		    name);
1928 		exit(1);
1929 	}
1930 
1931 	(*afp->af_getaddr)(str, &laddr, NULL);
1932 	lifr.lifr_addr = laddr;
1933 
1934 	(void) strncpy(lifr.lifr_name, name, sizeof (lifr.lifr_name));
1935 	if (ioctl(s, SIOCLIFREMOVEIF, (caddr_t)&lifr) < 0) {
1936 		if (errno == EBUSY) {
1937 			/* This can only happen if ipif_id = 0 */
1938 			(void) fprintf(stderr,
1939 			    "ifconfig: removeif: can't remove interface: %s\n",
1940 			    name);
1941 			exit(1);
1942 		}
1943 		Perror0_exit("removeif: SIOCLIFREMOVEIF");
1944 	}
1945 	return (0);
1946 }
1947 
1948 /*
1949  * If laddr is non-NULL it is used - otherwise we use the address on
1950  * the interface.
1951  */
1952 /* ARGSUSED */
1953 static int
1954 ifdad(char *ifname, struct sockaddr_in6 *laddr)
1955 {
1956 	struct sockaddr_in6 testaddr;
1957 	struct lifreq lifr2;	/* Avoid overriting lifr */
1958 
1959 	if (debug)
1960 		(void) printf("ifdad(%s)\n", ifname);
1961 
1962 	assert(afp->af_af == AF_INET6);
1963 
1964 	/*
1965 	 * Check the address assigned to the interface.
1966 	 * Skip the check if IFF_NOLOCAL, IFF_NONUD, IFF_ANYCAST, or
1967 	 * IFF_LOOPBACK.
1968 	 * Note that IFF_NONUD turns of both NUD and DAD.
1969 	 */
1970 	(void) strncpy(lifr2.lifr_name, ifname,
1971 	    sizeof (lifr2.lifr_name));
1972 	if (ioctl(s, SIOCGLIFFLAGS, (caddr_t)&lifr2) < 0) {
1973 		Perror0_exit("ifdad: SIOCGLIFFLAGS");
1974 	}
1975 	if (lifr2.lifr_flags & (IFF_NOLOCAL|IFF_LOOPBACK|IFF_NONUD|IFF_ANYCAST))
1976 		return (0);
1977 
1978 	if (laddr != NULL) {
1979 		testaddr = *laddr;
1980 	} else {
1981 		if (ioctl(s, SIOCGLIFADDR, (caddr_t)&lifr2) < 0) {
1982 			Perror0_exit("ifdad: SIOCGLIFADDR");
1983 		}
1984 		testaddr = *(struct sockaddr_in6 *)&lifr2.lifr_addr;
1985 	}
1986 
1987 	if (IN6_IS_ADDR_UNSPECIFIED(&testaddr.sin6_addr))
1988 		return (0);
1989 
1990 	if (do_dad(name, &testaddr) != 0)
1991 		return (-1);
1992 	else
1993 		return (0);
1994 }
1995 
1996 /*
1997  * Set the address token for IPv6.
1998  */
1999 /* ARGSUSED */
2000 static int
2001 setiftoken(char *addr, int64_t param)
2002 {
2003 	int prefixlen = 0;
2004 	struct sockaddr_in6 token;
2005 
2006 	in6_getaddr(addr, (struct sockaddr *)&token, &prefixlen);
2007 	switch (prefixlen) {
2008 	case NO_PREFIX:
2009 		(void) fprintf(stderr,
2010 		    "ifconfig: Missing prefix length in subnet %s\n", addr);
2011 		exit(1);
2012 		/* NOTREACHED */
2013 	case BAD_ADDR:
2014 		(void) fprintf(stderr,
2015 		    "ifconfig: Bad prefix length in %s\n", addr);
2016 		exit(1);
2017 	default:
2018 		break;
2019 	}
2020 	(void) memcpy(&lifr.lifr_addr, &token, sizeof (token));
2021 	lifr.lifr_addrlen = prefixlen;
2022 	(void) strncpy(lifr.lifr_name, name, sizeof (lifr.lifr_name));
2023 	if (ioctl(s, SIOCSLIFTOKEN, (caddr_t)&lifr) < 0)  {
2024 		Perror0_exit("setiftoken: SIOCSLIFTOKEN");
2025 	}
2026 	return (0);
2027 }
2028 
2029 /*
2030  * Return value: 0 on success, -1 on failure.
2031  */
2032 static int
2033 connect_to_mpathd(int family)
2034 {
2035 	int s;
2036 	struct sockaddr_storage ss;
2037 	struct sockaddr_in *sin = (struct sockaddr_in *)&ss;
2038 	struct sockaddr_in6 *sin6 = (struct sockaddr_in6 *)&ss;
2039 	struct in6_addr loopback_addr = IN6ADDR_LOOPBACK_INIT;
2040 	int addrlen;
2041 	int ret;
2042 	int on;
2043 
2044 	s = socket(family, SOCK_STREAM, 0);
2045 	if (s < 0) {
2046 		Perror0_exit("connect_to_mpathd: socket");
2047 	}
2048 	(void) bzero((char *)&ss, sizeof (ss));
2049 	ss.ss_family = family;
2050 	/*
2051 	 * Need to bind to a privileged port. For non-root, this
2052 	 * will fail. in.mpathd verifies that only commands coming
2053 	 * from privileged ports succeed so that ordinary users
2054 	 * can't connect and start talking to in.mpathd
2055 	 */
2056 	on = 1;
2057 	if (setsockopt(s, IPPROTO_TCP, TCP_ANONPRIVBIND, &on,
2058 	    sizeof (on)) < 0) {
2059 		Perror0_exit("connect_to_mpathd: setsockopt");
2060 	}
2061 	switch (family) {
2062 	case AF_INET:
2063 		sin->sin_port = 0;
2064 		sin->sin_addr.s_addr = htonl(INADDR_LOOPBACK);
2065 		addrlen = sizeof (struct sockaddr_in);
2066 		break;
2067 	case AF_INET6:
2068 		sin6->sin6_port = 0;
2069 		sin6->sin6_addr = loopback_addr;
2070 		addrlen = sizeof (struct sockaddr_in6);
2071 		break;
2072 	}
2073 	ret = bind(s, (struct sockaddr *)&ss, addrlen);
2074 	if (ret != 0) {
2075 		(void) close(s);
2076 		return (-1);
2077 	}
2078 
2079 	switch (family) {
2080 	case AF_INET:
2081 		sin->sin_port = htons(MPATHD_PORT);
2082 		break;
2083 	case AF_INET6:
2084 		sin6->sin6_port = htons(MPATHD_PORT);
2085 		break;
2086 	}
2087 	ret = connect(s, (struct sockaddr *)&ss, addrlen);
2088 	(void) close(s);
2089 	return (ret);
2090 }
2091 
2092 /* ARGSUSED */
2093 static int
2094 setifgroupname(char *grpname, int64_t param)
2095 {
2096 	if (debug) {
2097 		(void) printf("Setting groupname %s on interface %s\n",
2098 		    grpname, name);
2099 	}
2100 	(void) strncpy(lifr.lifr_name, name, sizeof (lifr.lifr_name));
2101 	(void) strncpy(lifr.lifr_groupname, grpname,
2102 	    sizeof (lifr.lifr_groupname));
2103 	if (ioctl(s, SIOCSLIFGROUPNAME, (caddr_t)&lifr) < 0) {
2104 		Perror0_exit("setifgroupname: SIOCSLIFGROUPNAME");
2105 	}
2106 
2107 	/*
2108 	 * If the SUNW_NO_MPATHD environment variable is set then don't
2109 	 * bother starting up in.mpathd.  See PSARC/2002/249 for the
2110 	 * depressing details on this bit of stupidity.
2111 	 */
2112 	if (getenv("SUNW_NO_MPATHD") != NULL) {
2113 		return (0);
2114 	}
2115 
2116 	/*
2117 	 * Try to connect to in.mpathd using IPv4. If we succeed,
2118 	 * we conclude that in.mpathd is running, and quit.
2119 	 */
2120 	if (connect_to_mpathd(AF_INET) == 0) {
2121 		/* connect succeeded, mpathd is already running */
2122 		return (0);
2123 	}
2124 	/*
2125 	 * Try to connect to in.mpathd using IPv6. If we succeed,
2126 	 * we conclude that in.mpathd is running, and quit.
2127 	 */
2128 	if (connect_to_mpathd(AF_INET6) == 0) {
2129 		/* connect succeeded, mpathd is already running */
2130 		return (0);
2131 	}
2132 
2133 	/*
2134 	 * in.mpathd may not be running. Start it now. If it is already
2135 	 * running, in.mpathd will take care of handling multiple incarnations
2136 	 * of itself. ifconfig only tries to optimize performance by not
2137 	 * starting another incarnation of in.mpathd.
2138 	 */
2139 	switch (fork()) {
2140 
2141 	case -1:
2142 		Perror0_exit("setifgroupname: fork");
2143 		/* NOTREACHED */
2144 	case 0:
2145 		(void) execl(MPATHD_PATH, MPATHD_PATH, NULL);
2146 		_exit(1);
2147 		/* NOTREACHED */
2148 	default:
2149 		return (0);
2150 	}
2151 }
2152 
2153 
2154 /*
2155  * To list all the modules above a given network interface.
2156  */
2157 /* ARGSUSED */
2158 static int
2159 modlist(char *null, int64_t param)
2160 {
2161 	int muxfd;
2162 	int ipfd_lowstr;
2163 	int arpfd_lowstr;
2164 	int num_mods;
2165 	int i;
2166 	struct str_list strlist;
2167 	int orig_arpid;
2168 
2169 	(void) strncpy(lifr.lifr_name, name, sizeof (lifr.lifr_name));
2170 	if (ip_domux2fd(&muxfd, &ipfd_lowstr, &arpfd_lowstr,
2171 	    &orig_arpid) < 0) {
2172 		return (-1);
2173 	}
2174 	if ((num_mods = ioctl(ipfd_lowstr, I_LIST, NULL)) < 0) {
2175 		Perror0("cannot I_LIST to get the number of modules");
2176 	} else {
2177 		if (debug > 0) {
2178 			(void) printf("Listing (%d) modules above %s\n",
2179 			    num_mods, name);
2180 		}
2181 
2182 		strlist.sl_nmods = num_mods;
2183 		strlist.sl_modlist = malloc(sizeof (struct str_mlist) *
2184 		    num_mods);
2185 		if (strlist.sl_modlist == NULL) {
2186 			Perror0("cannot malloc");
2187 		} else {
2188 			if (ioctl(ipfd_lowstr, I_LIST, (caddr_t)&strlist) < 0) {
2189 				Perror0("cannot I_LIST for module names");
2190 			} else {
2191 				for (i = 0; i < strlist.sl_nmods; i++) {
2192 				    (void) printf("%d %s\n", i,
2193 				    strlist.sl_modlist[i].l_name);
2194 				}
2195 			}
2196 			free(strlist.sl_modlist);
2197 		}
2198 	}
2199 	return (ip_plink(muxfd, ipfd_lowstr, arpfd_lowstr, orig_arpid));
2200 }
2201 
2202 #define	MODINSERT_OP	'i'
2203 #define	MODREMOVE_OP	'r'
2204 
2205 /*
2206  * To insert a module to the stream of the interface.  It is just a
2207  * wrapper.  The real function is modop().
2208  */
2209 /* ARGSUSED */
2210 static int
2211 modinsert(char *arg, int64_t param)
2212 {
2213 	return (modop(arg, MODINSERT_OP));
2214 }
2215 
2216 /*
2217  * To remove a module from the stream of the interface.  It is just a
2218  * wrapper.  The real function is modop().
2219  */
2220 /* ARGSUSED */
2221 static int
2222 modremove(char *arg, int64_t param)
2223 {
2224 	return (modop(arg, MODREMOVE_OP));
2225 }
2226 
2227 /*
2228  * Open a stream on /dev/udp, pop off all undesired modules (note that
2229  * the user may have configured autopush to add modules above or below
2230  * udp), and push the arp module onto raw IP.
2231  */
2232 static int
2233 open_arp_on_udp(char *udp_dev_name)
2234 {
2235 	int fd;
2236 	boolean_t popped;
2237 
2238 	if ((fd = open(udp_dev_name, O_RDWR)) == -1) {
2239 		Perror2("open", udp_dev_name);
2240 		return (-1);
2241 	}
2242 	errno = 0;
2243 	popped = _B_FALSE;
2244 	while (ioctl(fd, I_POP, 0) != -1)
2245 		popped = _B_TRUE;
2246 	if (!popped) {
2247 		Perror2("cannot pop", udp_dev_name);
2248 	} else if (errno != EINVAL) {
2249 		Perror2("pop", udp_dev_name);
2250 	} else if (ioctl(fd, I_PUSH, ARP_MOD_NAME) == -1) {
2251 		Perror2("arp PUSH", udp_dev_name);
2252 	} else {
2253 		return (fd);
2254 	}
2255 	(void) close(fd);
2256 	return (-1);
2257 }
2258 
2259 /*
2260  * Helper function for mod*() functions.  It gets a fd to the lower IP
2261  * stream and I_PUNLINK's the lower stream.  It also initializes the
2262  * global variable lifr.
2263  *
2264  * Param:
2265  *	int *udp_fd: (referenced) fd to /dev/udp (upper IP stream).
2266  *	int *fd: (referenced) fd to the lower IP stream.
2267  *
2268  * Return:
2269  *	-1 if operation fails, 0 otherwise.
2270  *
2271  * Please see the big block comment above plumb_one_device()
2272  * for the logic of the PLINK/PUNLINK
2273  */
2274 static int
2275 ip_domux2fd(int *muxfd, int *ipfd_lowstr, int *arpfd_lowstr, int *orig_arpid)
2276 {
2277 	int		ip_fd;
2278 	uint64_t	flags;
2279 	char		*udp_dev_name;
2280 	char		*ip_dev_name;
2281 
2282 	*orig_arpid = 0;
2283 	(void) strncpy(lifr.lifr_name, name, sizeof (lifr.lifr_name));
2284 	if (ioctl(s, SIOCGLIFFLAGS, (caddr_t)&lifr) < 0) {
2285 		Perror0_exit("status: SIOCGLIFFLAGS");
2286 	}
2287 	flags = lifr.lifr_flags;
2288 	if (flags & IFF_IPV4) {
2289 		udp_dev_name = UDP_DEV_NAME;
2290 		ip_dev_name  = IP_DEV_NAME;
2291 	} else if (flags & IFF_IPV6) {
2292 		udp_dev_name = UDP6_DEV_NAME;
2293 		ip_dev_name  = IP6_DEV_NAME;
2294 	} else {
2295 		return (-1);
2296 	}
2297 
2298 	if ((ip_fd = open(ip_dev_name, O_RDWR)) < 0) {
2299 		Perror2("open", ip_dev_name);
2300 		return (-1);
2301 	}
2302 	if (ioctl(ip_fd, SIOCGLIFMUXID, (caddr_t)&lifr) < 0) {
2303 		Perror2("SIOCGLIFMUXID", ip_dev_name);
2304 		return (-1);
2305 	}
2306 	if (debug > 0) {
2307 		(void) printf("ARP_muxid %d IP_muxid %d\n",
2308 		    lifr.lifr_arp_muxid, lifr.lifr_ip_muxid);
2309 	}
2310 
2311 	if ((*muxfd = open_arp_on_udp(udp_dev_name)) == -1)
2312 		return (-1);
2313 
2314 	if (lifr.lifr_arp_muxid != 0) {
2315 		if ((*arpfd_lowstr = ioctl(*muxfd, _I_MUXID2FD,
2316 		    lifr.lifr_arp_muxid)) < 0) {
2317 			if ((errno == EINVAL) &&
2318 			    (flags & (IFF_NOARP | IFF_IPV6))) {
2319 				/*
2320 				 * Some plumbing utilities set the muxid to
2321 				 * -1 or some invalid value to signify that
2322 				 * there is no arp stream. Set the muxid to 0
2323 				 * before trying to unplumb the IP stream.
2324 				 * IP does not allow the IP stream to be
2325 				 * unplumbed if it sees a non-null arp muxid,
2326 				 * for consistency of IP-ARP streams.
2327 				 */
2328 				*orig_arpid = lifr.lifr_arp_muxid;
2329 				lifr.lifr_arp_muxid = 0;
2330 				(void) ioctl(*muxfd, SIOCSLIFMUXID,
2331 				    (caddr_t)&lifr);
2332 				*arpfd_lowstr = -1;
2333 			} else {
2334 				Perror0("_I_MUXID2FD");
2335 				return (-1);
2336 			}
2337 		} else if (ioctl(*muxfd, I_PUNLINK,
2338 		    lifr.lifr_arp_muxid) < 0) {
2339 			Perror2("I_PUNLINK", udp_dev_name);
2340 			return (-1);
2341 		}
2342 	} else {
2343 		*arpfd_lowstr = -1;
2344 	}
2345 
2346 	if ((*ipfd_lowstr = ioctl(*muxfd, _I_MUXID2FD,
2347 	    lifr.lifr_ip_muxid)) < 0) {
2348 		Perror0("_I_MUXID2FD");
2349 		/* Undo any changes we made */
2350 		if (*orig_arpid != 0) {
2351 			lifr.lifr_arp_muxid = *orig_arpid;
2352 			(void) ioctl(*muxfd, SIOCSLIFMUXID, (caddr_t)&lifr);
2353 		}
2354 		return (-1);
2355 	}
2356 	if (ioctl(*muxfd, I_PUNLINK, lifr.lifr_ip_muxid) < 0) {
2357 		Perror2("I_PUNLINK", udp_dev_name);
2358 		/* Undo any changes we made */
2359 		if (*orig_arpid != 0) {
2360 			lifr.lifr_arp_muxid = *orig_arpid;
2361 			(void) ioctl(*muxfd, SIOCSLIFMUXID, (caddr_t)&lifr);
2362 		}
2363 		return (-1);
2364 	}
2365 	return (0);
2366 }
2367 
2368 /*
2369  * Helper function for mod*() functions.  It I_PLINK's back the upper and
2370  * lower IP streams.  Note that this function must be called after
2371  * ip_domux2fd().  In ip_domux2fd(), the global variable lifr is initialized
2372  * and ip_plink() needs information in lifr.  So ip_domux2fd() and ip_plink()
2373  * must be called in pairs.
2374  *
2375  * Param:
2376  *	int udp_fd: fd to /dev/udp (upper IP stream).
2377  *	int fd: fd to the lower IP stream.
2378  *
2379  * Return:
2380  *	-1 if operation fails, 0 otherwise.
2381  *
2382  * Please see the big block comment above plumb_one_device()
2383  * for the logic of the PLINK/PUNLINK
2384  */
2385 static int
2386 ip_plink(int muxfd, int ipfd_lowstr, int arpfd_lowstr, int orig_arpid)
2387 {
2388 	int ip_muxid;
2389 
2390 	ip_muxid = ioctl(muxfd, I_PLINK, ipfd_lowstr);
2391 	if (ip_muxid < 0) {
2392 		Perror2("I_PLINK", UDP_DEV_NAME);
2393 		return (-1);
2394 	}
2395 
2396 	/*
2397 	 * If there is an arp stream, plink it. If there is no
2398 	 * arp stream, then it is possible that the plumbing
2399 	 * utility could have stored any value in the arp_muxid.
2400 	 * If so, restore it from orig_arpid.
2401 	 */
2402 	if (arpfd_lowstr != -1) {
2403 		if (ioctl(muxfd, I_PLINK, arpfd_lowstr) < 0) {
2404 			Perror2("I_PLINK", UDP_DEV_NAME);
2405 			return (-1);
2406 		}
2407 	} else if (orig_arpid != 0) {
2408 		/* Undo the changes we did in ip_domux2fd */
2409 		lifr.lifr_arp_muxid = orig_arpid;
2410 		lifr.lifr_ip_muxid = ip_muxid;
2411 		(void) ioctl(muxfd, SIOCSLIFMUXID, (caddr_t)&lifr);
2412 	}
2413 
2414 	return (0);
2415 }
2416 
2417 
2418 /*
2419  * The names of other core TCP/IP stack modules which cannot be removed.
2420  */
2421 #ifndef	TUN_NAME
2422 #define	TUN_NAME	"tun"
2423 #endif
2424 
2425 #ifndef	ATUN_NAME
2426 #define	ATUN_NAME	"atun"
2427 #endif
2428 
2429 #ifndef	TUN6TO4_NAME
2430 #define	TUN6TO4_NAME	"6to4tun"
2431 #endif
2432 
2433 /*
2434  * The real function to perform module insertion/removal.
2435  *
2436  * Param:
2437  *	char *arg: the argument string module_name@position
2438  *	char op: operation, either MODINSERT_OP or MODREMOVE_OP.
2439  *
2440  * Return:
2441  *	Before doing ip_domux2fd(), this function calls exit(1) in case of
2442  *	error.  After ip_domux2fd() is done, it returns -1 for error, 0
2443  *	otherwise.
2444  */
2445 static int
2446 modop(char *arg, char op)
2447 {
2448 	char *pos_p;
2449 	int muxfd;
2450 	int ipfd_lowstr;  /* IP stream (lower stream of mux) to be plinked */
2451 	int arpfd_lowstr; /* ARP stream (lower stream of mux) to be plinked */
2452 	struct strmodconf mod;
2453 	char *at_char = "@";
2454 	char *arg_str;
2455 	int orig_arpid;
2456 
2457 	(void) strncpy(lifr.lifr_name, name, sizeof (lifr.lifr_name));
2458 
2459 	/* Need to save the original string for -a option. */
2460 	if ((arg_str = malloc(strlen(arg) + 1)) == NULL) {
2461 		Perror0("cannot malloc");
2462 		return (-1);
2463 	}
2464 	(void) strcpy(arg_str, arg);
2465 
2466 	if (*arg_str == *at_char) {
2467 		(void) fprintf(stderr,
2468 		    "ifconfig: must supply a module name\n");
2469 		exit(1);
2470 	}
2471 	mod.mod_name = strtok(arg_str, at_char);
2472 	if (strlen(mod.mod_name) > FMNAMESZ) {
2473 		(void) fprintf(stderr, "ifconfig: module name too long: %s\n",
2474 		    mod.mod_name);
2475 		exit(1);
2476 	}
2477 
2478 	/*
2479 	 * Need to make sure that the core TCP/IP stack modules are not
2480 	 * removed.  Otherwise, "bad" things can happen.  If a module
2481 	 * is removed and inserted back, it loses its old state.  But
2482 	 * the modules above it still have the old state.  E.g. IP assumes
2483 	 * fast data path while tunnel after re-inserted assumes that it can
2484 	 * receive M_DATA only in fast data path for which it does not have
2485 	 * any state.  This is a general caveat of _I_REMOVE/_I_INSERT.
2486 	 */
2487 	if (op == MODREMOVE_OP &&
2488 	    (strcmp(mod.mod_name, ARP_MOD_NAME) == 0 ||
2489 	    strcmp(mod.mod_name, IP_MOD_NAME) == 0 ||
2490 	    strcmp(mod.mod_name, TUN_NAME) == 0 ||
2491 	    strcmp(mod.mod_name, ATUN_NAME) == 0 ||
2492 	    strcmp(mod.mod_name, TUN6TO4_NAME) == 0)) {
2493 		(void) fprintf(stderr, "ifconfig: cannot remove %s\n",
2494 		    mod.mod_name);
2495 		exit(1);
2496 	}
2497 
2498 	if ((pos_p = strtok(NULL, at_char)) == NULL) {
2499 		(void) fprintf(stderr, "ifconfig: must supply a position\n");
2500 		exit(1);
2501 	}
2502 	mod.pos = atoi(pos_p);
2503 
2504 	if (ip_domux2fd(&muxfd, &ipfd_lowstr, &arpfd_lowstr,
2505 	    &orig_arpid) < 0) {
2506 		free(arg_str);
2507 		return (-1);
2508 	}
2509 	switch (op) {
2510 	case MODINSERT_OP:
2511 		if (debug > 0) {
2512 			(void) printf("Inserting module %s at %d\n",
2513 			    mod.mod_name, mod.pos);
2514 		}
2515 		if (ioctl(ipfd_lowstr, _I_INSERT, (caddr_t)&mod) < 0) {
2516 			Perror2("fail to insert module", mod.mod_name);
2517 		}
2518 		break;
2519 	case MODREMOVE_OP:
2520 		if (debug > 0) {
2521 			(void) printf("Removing module %s at %d\n",
2522 			    mod.mod_name, mod.pos);
2523 		}
2524 		if (ioctl(ipfd_lowstr, _I_REMOVE, (caddr_t)&mod) < 0) {
2525 			Perror2("fail to remove module", mod.mod_name);
2526 		}
2527 		break;
2528 	default:
2529 		/* Should never get to here. */
2530 		(void) fprintf(stderr, "Unknown operation\n");
2531 		break;
2532 	}
2533 	free(arg_str);
2534 	return (ip_plink(muxfd, ipfd_lowstr, arpfd_lowstr, orig_arpid));
2535 }
2536 
2537 #ifdef DEBUG
2538 
2539 /* ARGSUSED */
2540 static int
2541 getnd(char *addr, int64_t param)
2542 {
2543 	struct sockaddr_in6 v6addr;
2544 	char *str = NULL;
2545 
2546 	in6_getaddr(addr, &v6addr, NULL);
2547 	(void) memcpy(&lifr.lifr_nd.lnr_addr, &v6addr, sizeof (v6addr));
2548 	(void) strncpy(lifr.lifr_name, name, sizeof (lifr.lifr_name));
2549 	if (ioctl(s, SIOCLIFGETND, (caddr_t)&lifr) < 0)  {
2550 		Perror0_exit("SIOCLIFGETND");
2551 	}
2552 	str = _link_ntoa((const unsigned char *)lifr.lifr_nd.lnr_hdw_addr,
2553 	    str, lifr.lifr_nd.lnr_hdw_len, IFT_OTHER);
2554 	if (str != NULL) {
2555 		(void) printf("address %s", str);
2556 		free(str);
2557 	}
2558 	(void) printf(" state %d/%d/%d flags %x\n",
2559 		lifr.lifr_nd.lnr_state_create,
2560 		lifr.lifr_nd.lnr_state_same_lla,
2561 		lifr.lifr_nd.lnr_state_diff_lla,
2562 		lifr.lifr_nd.lnr_flags);
2563 	return (0);
2564 }
2565 
2566 /* ARGSUSED */
2567 static int
2568 delnd(char *addr, int64_t param)
2569 {
2570 	struct sockaddr_in6 v6addr;
2571 
2572 	in6_getaddr(addr, &v6addr, NULL);
2573 	(void) memcpy(&lifr.lifr_nd.lnr_addr, &v6addr, sizeof (v6addr));
2574 	(void) strncpy(lifr.lifr_name, name, sizeof (lifr.lifr_name));
2575 
2576 	lifr.lifr_nd.lnr_state_create = ND_UNCHANGED;
2577 	lifr.lifr_nd.lnr_state_same_lla = ND_UNCHANGED;
2578 	lifr.lifr_nd.lnr_state_diff_lla = ND_UNCHANGED;
2579 	lifr.lifr_nd.lnr_flags = 0;
2580 	if (ioctl(s, SIOCLIFDELND, (caddr_t)&lifr) < 0)  {
2581 		Perror0_exit("SIOCLIFDELND");
2582 	}
2583 	return (0);
2584 }
2585 
2586 /* ARGSUSED */
2587 static int
2588 setnd(char *addr, int64_t param)
2589 {
2590 	struct sockaddr_in6 v6addr;
2591 
2592 	/*
2593 	 * XXX parse phyaddr? Need syntax to fit in one argv.
2594 	 * XXX <proto addr>/<phyaddr> ??
2595 	 */
2596 	in6_getaddr(addr, &v6addr, NULL);
2597 	(void) memcpy(&lifr.lifr_nd.lnr_addr, &v6addr, sizeof (v6addr));
2598 	(void) memset(lifr.lifr_nd.lnr_hdw_addr, 0x55,
2599 	    sizeof (lifr.lifr_nd.lnr_hdw_addr));
2600 	lifr.lifr_nd.lnr_hdw_len = 6;
2601 	(void) strncpy(lifr.lifr_name, name, sizeof (lifr.lifr_name));
2602 
2603 	lifr.lifr_nd.lnr_state_create = ND_STALE;
2604 	lifr.lifr_nd.lnr_state_same_lla = ND_UNCHANGED;
2605 	lifr.lifr_nd.lnr_state_diff_lla = ND_STALE;
2606 	lifr.lifr_nd.lnr_flags = 0;
2607 
2608 	if (ioctl(s, SIOCLIFSETND, (caddr_t)&lifr) < 0)  {
2609 		Perror0_exit("SIOCLIFSETND");
2610 	}
2611 	return (0);
2612 }
2613 #endif /* DEBUG */
2614 
2615 /*
2616  * Set tunnel source address
2617  */
2618 /* ARGSUSED */
2619 static int
2620 setiftsrc(char *addr, int64_t param)
2621 {
2622 	return (settaddr(addr, icfg_set_tunnel_src));
2623 }
2624 
2625 /*
2626  * Set tunnel destination address
2627  */
2628 /* ARGSUSED */
2629 static int
2630 setiftdst(char *addr, int64_t param)
2631 {
2632 	return (settaddr(addr, icfg_set_tunnel_dest));
2633 }
2634 
2635 /*
2636  * sets tunnels src|dst address.  settaddr() expects the following:
2637  * addr: Points to a printable string containing the address to be
2638  *       set, e.g. 129.153.128.110.
2639  * fn:   Pointer to a libinetcfg routine that will do the actual work.
2640  *       The only valid functions are icfg_set_tunnel_src and
2641  *       icfg_set_tunnel_dest.
2642  */
2643 static int
2644 settaddr(char *addr,
2645     int (*fn)(icfg_handle_t, const struct sockaddr *, socklen_t))
2646 {
2647 	icfg_handle_t handle;
2648 	icfg_if_t interface;
2649 	struct sockaddr_storage laddr;
2650 	int lower;
2651 	int rc;
2652 
2653 	if (strchr(name, ':') != NULL) {
2654 		errno = EPERM;
2655 		Perror0_exit("Tunnel params on logical interfaces");
2656 	}
2657 	(void) strncpy(interface.if_name, name, sizeof (interface.if_name));
2658 	interface.if_protocol = SOCKET_AF(af);
2659 
2660 	/* Open interface. */
2661 	if ((rc = icfg_open(&handle, &interface)) != ICFG_SUCCESS)
2662 		Perror0_exit((char *)icfg_errmsg(rc));
2663 
2664 	rc = icfg_get_tunnel_lower(handle, &lower);
2665 	if (rc != ICFG_SUCCESS)
2666 		Perror0_exit((char *)icfg_errmsg(rc));
2667 
2668 	if (lower == AF_INET) {
2669 		in_getaddr(addr, (struct sockaddr *)&laddr, NULL);
2670 	} else {
2671 		in6_getaddr(addr, (struct sockaddr *)&laddr, NULL);
2672 	}
2673 
2674 	/* Call fn to do the real work, and close the interface. */
2675 	rc = (*fn)(handle, (struct sockaddr *)&laddr,
2676 	    sizeof (struct sockaddr_storage));
2677 	icfg_close(handle);
2678 
2679 	if (rc != ICFG_SUCCESS)
2680 		Perror0_exit((char *)icfg_errmsg(rc));
2681 
2682 	return (0);
2683 }
2684 
2685 /* Set tunnel encapsulation limit. */
2686 /* ARGSUSED */
2687 static int
2688 set_tun_encap_limit(char *arg, int64_t param)
2689 {
2690 	short limit;
2691 	icfg_if_t interface;
2692 	icfg_handle_t handle;
2693 	int rc;
2694 
2695 	if (strchr(name, ':') != NULL) {
2696 		errno = EPERM;
2697 		Perror0_exit("Tunnel params on logical interfaces");
2698 	}
2699 
2700 	if ((sscanf(arg, "%hd", &limit) != 1) || (limit < 0) ||
2701 	    (limit > 255)) {
2702 		errno = EINVAL;
2703 		Perror0_exit("Invalid encapsulation limit");
2704 	}
2705 
2706 	/* Open interface for configuration. */
2707 	(void) strncpy(interface.if_name, name, sizeof (interface.if_name));
2708 	interface.if_protocol = SOCKET_AF(af);
2709 	if (icfg_open(&handle, &interface) != ICFG_SUCCESS)
2710 		Perror0_exit("couldn't open interface");
2711 
2712 	rc = icfg_set_tunnel_encaplimit(handle, (int)limit);
2713 	icfg_close(handle);
2714 
2715 	if (rc != ICFG_SUCCESS)
2716 		Perror0_exit("Could not configure tunnel encapsulation limit");
2717 
2718 	return (0);
2719 }
2720 
2721 /* Disable encapsulation limit. */
2722 /* ARGSUSED */
2723 static int
2724 clr_tun_encap_limit(char *arg, int64_t param)
2725 {
2726 	icfg_if_t interface;
2727 	icfg_handle_t handle;
2728 	int rc;
2729 
2730 	if (strchr(name, ':') != NULL) {
2731 		errno = EPERM;
2732 		Perror0_exit("Tunnel params on logical interfaces");
2733 	}
2734 
2735 	/* Open interface for configuration. */
2736 	(void) strncpy(interface.if_name, name, sizeof (interface.if_name));
2737 	interface.if_protocol = SOCKET_AF(af);
2738 	if (icfg_open(&handle, &interface) != ICFG_SUCCESS)
2739 		Perror0_exit("couldn't open interface");
2740 
2741 	rc = icfg_set_tunnel_encaplimit(handle, -1);
2742 	icfg_close(handle);
2743 
2744 	if (rc != ICFG_SUCCESS)
2745 		Perror0_exit((char *)icfg_errmsg(rc));
2746 
2747 	return (0);
2748 }
2749 
2750 /* Set tunnel hop limit. */
2751 /* ARGSUSED */
2752 static int
2753 set_tun_hop_limit(char *arg, int64_t param)
2754 {
2755 	unsigned short limit;
2756 	icfg_if_t interface;
2757 	icfg_handle_t handle;
2758 	int rc;
2759 
2760 	if (strchr(name, ':') != NULL) {
2761 		errno = EPERM;
2762 		Perror0_exit("Tunnel params on logical interfaces");
2763 	}
2764 
2765 	/*
2766 	 * Check limit here since it's really only an 8-bit unsigned quantity.
2767 	 */
2768 	if ((sscanf(arg, "%hu", &limit) != 1) || (limit > 255)) {
2769 		errno = EINVAL;
2770 		Perror0_exit("Invalid hop limit");
2771 	}
2772 
2773 	/* Open interface for configuration. */
2774 	(void) strncpy(interface.if_name, name, sizeof (interface.if_name));
2775 	interface.if_protocol = SOCKET_AF(af);
2776 	if (icfg_open(&handle, &interface) != ICFG_SUCCESS)
2777 		Perror0_exit("couldn't open interface");
2778 
2779 	rc = icfg_set_tunnel_hoplimit(handle, (uint8_t)limit);
2780 	icfg_close(handle);
2781 
2782 	if (rc != ICFG_SUCCESS)
2783 		Perror0_exit("Could not configure tunnel hop limit");
2784 
2785 	return (0);
2786 }
2787 
2788 /* Set zone ID */
2789 static int
2790 setzone(char *arg, int64_t param)
2791 {
2792 	zoneid_t zoneid = GLOBAL_ZONEID;
2793 
2794 	if (param == NEXTARG) {
2795 		/* zone must be active */
2796 		if ((zoneid = getzoneidbyname(arg)) == -1) {
2797 			(void) fprintf(stderr,
2798 			    "ifconfig: unknown zone '%s'\n", arg);
2799 			exit(1);
2800 		}
2801 	}
2802 	(void) strlcpy(lifr.lifr_name, name, sizeof (lifr.lifr_name));
2803 	lifr.lifr_zoneid = zoneid;
2804 	if (ioctl(s, SIOCSLIFZONE, (caddr_t)&lifr) == -1)
2805 		Perror0_exit("SIOCSLIFZONE");
2806 	return (0);
2807 }
2808 
2809 /* Set source address to use */
2810 /* ARGSUSED */
2811 static int
2812 setifsrc(char *arg, int64_t param)
2813 {
2814 	uint_t ifindex = 0;
2815 	int rval;
2816 
2817 	(void) strncpy(lifr.lifr_name, name, sizeof (lifr.lifr_name));
2818 
2819 	/*
2820 	 * Argument can be either an interface name or "none". The latter means
2821 	 * that any previous selection is cleared.
2822 	 */
2823 
2824 	rval = strcmp(arg, name);
2825 	if (rval == 0) {
2826 		(void) fprintf(stderr,
2827 		    "ifconfig: Cannot specify same interface for usesrc"
2828 		    " group\n");
2829 		exit(1);
2830 	}
2831 
2832 	rval = strcmp(arg, NONE_STR);
2833 	if (rval != 0) {
2834 		if ((ifindex = if_nametoindex(arg)) == 0) {
2835 			(void) strncpy(lifr.lifr_name, arg, LIFNAMSIZ);
2836 			Perror0_exit("Could not get interface index");
2837 		}
2838 		lifr.lifr_index = ifindex;
2839 	} else {
2840 		if (ioctl(s, SIOCGLIFUSESRC, (caddr_t)&lifr) != 0)
2841 			Perror0_exit("Not a valid usesrc consumer");
2842 		lifr.lifr_index = 0;
2843 	}
2844 
2845 	if (debug)
2846 		(void) printf("setifsrc: lifr_name %s, lifr_index %d\n",
2847 		    lifr.lifr_name, lifr.lifr_index);
2848 
2849 	if (ioctl(s, SIOCSLIFUSESRC, (caddr_t)&lifr) == -1) {
2850 		if (rval == 0)
2851 			Perror0_exit("Cannot reset usesrc group");
2852 		else
2853 			Perror0_exit("Could not set source interface");
2854 	}
2855 
2856 	return (0);
2857 }
2858 
2859 /*
2860  * Print the interface status line associated with `ifname'
2861  */
2862 static void
2863 ifstatus(const char *ifname)
2864 {
2865 	uint64_t flags;
2866 	char if_usesrc_name[LIFNAMSIZ];
2867 	char *newbuf;
2868 	int n, numifs, rval = 0;
2869 	struct lifreq *lifrp;
2870 	struct lifsrcof lifs;
2871 
2872 	(void) strncpy(lifr.lifr_name, ifname, sizeof (lifr.lifr_name));
2873 	if (ioctl(s, SIOCGLIFFLAGS, (caddr_t)&lifr) < 0) {
2874 		Perror0_exit("status: SIOCGLIFFLAGS");
2875 	}
2876 	flags = lifr.lifr_flags;
2877 
2878 	/*
2879 	 * In V4 compatibility mode, we don't print the IFF_IPV4 flag or
2880 	 * interfaces with IFF_IPV6 set.
2881 	 */
2882 	if (v4compat) {
2883 		flags &= ~IFF_IPV4;
2884 		if (flags & IFF_IPV6)
2885 			return;
2886 	}
2887 
2888 	(void) printf("%s: ", ifname);
2889 	print_flags(flags);
2890 
2891 	(void) strncpy(lifr.lifr_name, ifname, sizeof (lifr.lifr_name));
2892 	if (ioctl(s, SIOCGLIFMETRIC, (caddr_t)&lifr) < 0) {
2893 		Perror0_exit("status: SIOCGLIFMETRIC");
2894 	} else {
2895 		if (lifr.lifr_metric)
2896 			(void) printf(" metric %d", lifr.lifr_metric);
2897 	}
2898 	if (ioctl(s, SIOCGLIFMTU, (caddr_t)&lifr) >= 0)
2899 		(void) printf(" mtu %d", lifr.lifr_metric);
2900 
2901 	/* don't print index or zone when in compatibility mode */
2902 	if (!v4compat) {
2903 		if (ioctl(s, SIOCGLIFINDEX, (caddr_t)&lifr) >= 0)
2904 			(void) printf(" index %d", lifr.lifr_index);
2905 		if (ioctl(s, SIOCGLIFZONE, (caddr_t)&lifr) >= 0 &&
2906 		    lifr.lifr_zoneid != getzoneid()) {
2907 			char zone_name[ZONENAME_MAX];
2908 
2909 			if (getzonenamebyid(lifr.lifr_zoneid, zone_name,
2910 			    sizeof (zone_name)) < 0) {
2911 				(void) printf("\n\tzone %d", lifr.lifr_zoneid);
2912 			} else {
2913 				(void) printf("\n\tzone %s", zone_name);
2914 			}
2915 		}
2916 	}
2917 
2918 	if (ioctl(s, SIOCGLIFINDEX, (caddr_t)&lifr) >= 0) {
2919 		lifs.lifs_ifindex = lifr.lifr_index;
2920 
2921 		/*
2922 		 * Find the number of interfaces that use this interfaces'
2923 		 * address as a source address
2924 		 */
2925 		lifs.lifs_buf = NULL;
2926 		lifs.lifs_maxlen = 0;
2927 		for (;;) {
2928 			/* The first pass will give the bufsize we need */
2929 			rval = ioctl(s, SIOCGLIFSRCOF, (char *)&lifs);
2930 			if (rval < 0) {
2931 				if (lifs.lifs_buf != NULL) {
2932 					free(lifs.lifs_buf);
2933 					lifs.lifs_buf = NULL;
2934 				}
2935 				lifs.lifs_len = 0;
2936 				break;
2937 			}
2938 			if (lifs.lifs_len <= lifs.lifs_maxlen)
2939 				break;
2940 			/* Use kernel's size + a small margin to avoid loops */
2941 			lifs.lifs_maxlen = lifs.lifs_len +
2942 			    5 * sizeof (struct lifreq);
2943 			/* For the first pass, realloc acts like malloc */
2944 			newbuf = realloc(lifs.lifs_buf, lifs.lifs_maxlen);
2945 			if (newbuf == NULL) {
2946 				if (lifs.lifs_buf != NULL) {
2947 					free(lifs.lifs_buf);
2948 					lifs.lifs_buf = NULL;
2949 				}
2950 				lifs.lifs_len = 0;
2951 				break;
2952 			}
2953 			lifs.lifs_buf = newbuf;
2954 		}
2955 
2956 
2957 		numifs = lifs.lifs_len / sizeof (struct lifreq);
2958 		if (numifs > 0) {
2959 			lifrp = lifs.lifs_req;
2960 			(void) printf("\n\tsrcof");
2961 			for (n = numifs; n > 0; n--, lifrp++) {
2962 				(void) printf(" %s", lifrp->lifr_name);
2963 			}
2964 		}
2965 
2966 		if (lifs.lifs_buf != NULL)
2967 			free(lifs.lifs_buf);
2968 	}
2969 
2970 	/* Find the interface whose source address this interface uses */
2971 	if (ioctl(s, SIOCGLIFUSESRC, (caddr_t)&lifr) == 0) {
2972 		if (lifr.lifr_index != 0) {
2973 			if (if_indextoname(lifr.lifr_index,
2974 			    if_usesrc_name) == NULL) {
2975 				(void) printf("\n\tusesrc ifIndex %d",
2976 				    lifr.lifr_index);
2977 			} else {
2978 				(void) printf("\n\tusesrc %s", if_usesrc_name);
2979 			}
2980 		}
2981 	}
2982 
2983 	(void) putchar('\n');
2984 }
2985 
2986 
2987 /*
2988  * Print the status of the interface.  If an address family was
2989  * specified, show it and it only; otherwise, show them all.
2990  */
2991 static void
2992 status(void)
2993 {
2994 	struct afswtch *p = afp;
2995 	uint64_t flags;
2996 
2997 	(void) strncpy(lifr.lifr_name, name, sizeof (lifr.lifr_name));
2998 	if (ioctl(s, SIOCGLIFFLAGS, (caddr_t)&lifr) < 0) {
2999 		Perror0_exit("status: SIOCGLIFFLAGS");
3000 	}
3001 
3002 	flags = lifr.lifr_flags;
3003 
3004 	/*
3005 	 * Only print the interface status if the address family matches
3006 	 * the interface family flag.
3007 	 */
3008 	if (p != NULL) {
3009 		if (((p->af_af == AF_INET6) && (flags & IFF_IPV4)) ||
3010 		    ((p->af_af == AF_INET) && (flags & IFF_IPV6)))
3011 			return;
3012 	}
3013 
3014 	/*
3015 	 * In V4 compatibility mode, don't print IFF_IPV6 interfaces.
3016 	 */
3017 	if (v4compat && (flags & IFF_IPV6))
3018 		return;
3019 
3020 	ifstatus(name);
3021 
3022 	if (p != NULL) {
3023 		(*p->af_status)(1, flags);
3024 	} else {
3025 		for (p = afs; p->af_name; p++) {
3026 			(void) close(s);
3027 			s = socket(SOCKET_AF(p->af_af), SOCK_DGRAM, 0);
3028 			/* set global af for use in p->af_status */
3029 			af = p->af_af;
3030 			if (s == -1) {
3031 				Perror0_exit("socket");
3032 			}
3033 			(*p->af_status)(0, flags);
3034 		}
3035 
3036 		/*
3037 		 * Historically, 'ether' has been an address family,
3038 		 * so print it here.
3039 		 */
3040 		print_ifether(name);
3041 	}
3042 }
3043 
3044 /*
3045  * Print the status of the interface in a format that can be used to
3046  * reconfigure the interface later. Code stolen from status() above.
3047  */
3048 /* ARGSUSED */
3049 static int
3050 configinfo(char *null, int64_t param)
3051 {
3052 	struct afswtch *p = afp;
3053 	uint64_t flags;
3054 	char phydevname[LIFNAMSIZ];
3055 	char if_usesrc_name[LIFNAMSIZ];
3056 	char *cp;
3057 
3058 	(void) strncpy(lifr.lifr_name, name, sizeof (lifr.lifr_name));
3059 	if (ioctl(s, SIOCGLIFFLAGS, (caddr_t)&lifr) < 0) {
3060 		Perror0_exit("status: SIOCGLIFFLAGS");
3061 	}
3062 	flags = lifr.lifr_flags;
3063 
3064 	if (debug) {
3065 		(void) printf("configinfo: name %s flags  0x%llx af_af %d\n",
3066 		    name, flags, p != NULL ? p->af_af : -1);
3067 	}
3068 
3069 	/* remove LIF component */
3070 	(void) strncpy(phydevname, name, sizeof (phydevname));
3071 	cp = strchr(phydevname, ':');
3072 	if (cp) {
3073 		*cp = 0;
3074 	}
3075 	phydevname[sizeof (phydevname) - 1] = '\0';
3076 
3077 	/*
3078 	 * if the interface is IPv4
3079 	 *	if we have a IPv6 address family restriction return
3080 	 *		so it won't print
3081 	 *	if we are in IPv4 compatibility mode, clear out IFF_IPV4
3082 	 *		so we don't print it.
3083 	 */
3084 	if (flags & IFF_IPV4) {
3085 		if (p && p->af_af == AF_INET6)
3086 			return (-1);
3087 		if (v4compat)
3088 			flags &= ~IFF_IPV4;
3089 
3090 		(void) printf("%s inet plumb", phydevname);
3091 	} else if (flags & IFF_IPV6) {
3092 		/*
3093 		 * else if the interface is IPv6
3094 		 *	if we have a IPv4 address family restriction return
3095 		 *	or we are in IPv4 compatibiltiy mode, return.
3096 		 */
3097 		if (p && p->af_af == AF_INET)
3098 			return (-1);
3099 		if (v4compat)
3100 			return (-1);
3101 
3102 		(void) printf("%s inet6 plumb", phydevname);
3103 	}
3104 
3105 	(void) strncpy(lifr.lifr_name, name, sizeof (lifr.lifr_name));
3106 	if (ioctl(s, SIOCGLIFMETRIC, (caddr_t)&lifr) < 0) {
3107 		Perror0_exit("configinfo: SIOCGLIFMETRIC");
3108 	} else {
3109 		if (lifr.lifr_metric)
3110 			(void) printf(" metric %d ", lifr.lifr_metric);
3111 	}
3112 	if (((flags & (IFF_VIRTUAL|IFF_LOOPBACK)) != IFF_VIRTUAL) &&
3113 		ioctl(s, SIOCGLIFMTU, (caddr_t)&lifr) >= 0)
3114 		(void) printf(" mtu %d", lifr.lifr_metric);
3115 
3116 	/* don't print index when in compatibility mode */
3117 	if (!v4compat) {
3118 		if (ioctl(s, SIOCGLIFINDEX, (caddr_t)&lifr) >= 0)
3119 			(void) printf(" index %d", lifr.lifr_index);
3120 	}
3121 
3122 	if (ioctl(s, SIOCGLIFUSESRC, (caddr_t)&lifr) == 0) {
3123 		if (lifr.lifr_index != 0) {
3124 			if (if_indextoname(lifr.lifr_index,
3125 			    if_usesrc_name) != NULL) {
3126 				(void) printf(" usesrc %s", if_usesrc_name);
3127 			}
3128 		}
3129 	}
3130 
3131 	if (p != NULL) {
3132 		(*p->af_configinfo)(1, flags);
3133 	} else {
3134 		for (p = afs; p->af_name; p++) {
3135 			(void) close(s);
3136 			s = socket(SOCKET_AF(p->af_af), SOCK_DGRAM, 0);
3137 			/* set global af for use in p->af_configinfo */
3138 			af = p->af_af;
3139 			if (s == -1) {
3140 				Perror0_exit("socket");
3141 			}
3142 			(*p->af_configinfo)(0, flags);
3143 		}
3144 	}
3145 
3146 	(void) printf("\n");
3147 
3148 	return (0);
3149 }
3150 
3151 static void
3152 print_tsec(struct iftun_req *tparams)
3153 {
3154 	ipsec_req_t *ipsr;
3155 
3156 	(void) printf("\ttunnel security settings  ");
3157 	/*
3158 	 * Deal with versioning, for now just point
3159 	 * an ipsec_req_t at ifta_secinfo.  If versions
3160 	 * change, something else will overlay ifta_secinfo.
3161 	 */
3162 	assert(tparams->ifta_vers == IFTUN_VERSION);
3163 
3164 	ipsr = (ipsec_req_t *)(&tparams->ifta_secinfo);
3165 	if (ipsr->ipsr_ah_req & IPSEC_PREF_REQUIRED) {
3166 		(void) printf("ah (%s)  ",
3167 		    rparsealg(ipsr->ipsr_auth_alg, IPSEC_PROTO_AH));
3168 	}
3169 	if (ipsr->ipsr_esp_req & IPSEC_PREF_REQUIRED) {
3170 		(void) printf("esp (%s",
3171 		    rparsealg(ipsr->ipsr_esp_alg, IPSEC_PROTO_ESP));
3172 		(void) printf("/%s)",
3173 		    rparsealg(ipsr->ipsr_esp_auth_alg, IPSEC_PROTO_AH));
3174 	}
3175 	(void) printf("\n");
3176 }
3177 
3178 static void
3179 tun_status(void)
3180 {
3181 	icfg_if_t interface;
3182 	int rc;
3183 	icfg_handle_t handle;
3184 	int protocol;
3185 	char srcbuf[INET6_ADDRSTRLEN];
3186 	char dstbuf[INET6_ADDRSTRLEN];
3187 	boolean_t tabbed;
3188 	uint8_t hoplimit;
3189 	int16_t encaplimit;
3190 	struct sockaddr_storage taddr;
3191 	socklen_t socklen = sizeof (taddr);
3192 
3193 	(void) strncpy(interface.if_name, name, sizeof (interface.if_name));
3194 	interface.if_protocol = SOCKET_AF(af);
3195 	if ((rc = icfg_open(&handle, &interface)) != ICFG_SUCCESS)
3196 		Perror0_exit((char *)icfg_errmsg(rc));
3197 
3198 	/*
3199 	 * only print tunnel info for lun 0.  If ioctl fails, assume
3200 	 * we are not a tunnel
3201 	 */
3202 	if (strchr(name, ':') != NULL ||
3203 	    icfg_get_tunnel_lower(handle, &protocol) != ICFG_SUCCESS) {
3204 		icfg_close(handle);
3205 		return;
3206 	}
3207 
3208 	switch (protocol) {
3209 	case AF_INET:
3210 		(void) printf("\tinet");
3211 		break;
3212 	case AF_INET6:
3213 		(void) printf("\tinet6");
3214 		break;
3215 	default:
3216 		Perror0_exit("\ttunnel: Illegal lower stream\n\t");
3217 		break;
3218 	}
3219 
3220 	rc = icfg_get_tunnel_src(handle, (struct sockaddr *)&taddr, &socklen);
3221 	if (rc == ICFG_NOT_SET) {
3222 		(void) strlcpy(srcbuf, (protocol == AF_INET) ? "0.0.0.0" :
3223 		    "::", sizeof (srcbuf));
3224 	} else if (rc != ICFG_SUCCESS) {
3225 		Perror0_exit((char *)icfg_errmsg(rc));
3226 	} else {
3227 		rc = icfg_sockaddr_to_str(protocol, (struct sockaddr *)&taddr,
3228 		    srcbuf, sizeof (srcbuf));
3229 		if (rc != ICFG_SUCCESS) {
3230 			Perror0_exit((char *)icfg_errmsg(rc));
3231 		}
3232 	}
3233 
3234 	(void) printf(" tunnel src %s ", srcbuf);
3235 
3236 	rc = icfg_get_tunnel_dest(handle, (struct sockaddr *)&taddr, &socklen);
3237 	if (rc == ICFG_NOT_SET) {
3238 		(void) printf("\n");
3239 	} else {
3240 		rc = icfg_sockaddr_to_str(protocol, (struct sockaddr *)&taddr,
3241 		    dstbuf, sizeof (dstbuf));
3242 		if (rc != ICFG_SUCCESS) {
3243 			Perror0_exit((char *)icfg_errmsg(rc));
3244 		}
3245 		(void) printf("tunnel dst %s\n", dstbuf);
3246 	}
3247 
3248 	if (handle->ifh_tunnel_params != NULL &&
3249 	    (handle->ifh_tunnel_params->ifta_flags & IFTUN_SECURITY))
3250 		print_tsec(handle->ifh_tunnel_params);
3251 
3252 	/*
3253 	 * tabbed indicates tabbed and printed.  Use it tell us whether
3254 	 * to tab and that we've printed something here, so we need a
3255 	 * newline
3256 	 */
3257 	tabbed = _B_FALSE;
3258 
3259 	if (icfg_get_tunnel_hoplimit(handle, &hoplimit) == ICFG_SUCCESS) {
3260 		(void) printf("\ttunnel hop limit %d ", hoplimit);
3261 		tabbed = _B_TRUE;
3262 	}
3263 
3264 	if ((protocol == AF_INET6) &&
3265 	    (icfg_get_tunnel_encaplimit(handle, &encaplimit) ==
3266 		ICFG_SUCCESS)) {
3267 		if (!tabbed) {
3268 			(void) printf("\t");
3269 			tabbed = _B_TRUE;
3270 		}
3271 		if (encaplimit >= 0) {
3272 			(void) printf("tunnel encapsulation limit %d",
3273 			    encaplimit);
3274 		} else {
3275 			(void) printf("tunnel encapsulation limit disabled");
3276 		}
3277 	}
3278 
3279 	if (tabbed)
3280 		(void) printf("\n");
3281 
3282 	icfg_close(handle);
3283 }
3284 
3285 static void
3286 in_status(int force, uint64_t flags)
3287 {
3288 	struct sockaddr_in *sin, *laddr;
3289 	struct	sockaddr_in netmask = { AF_INET };
3290 
3291 	if (debug)
3292 		(void) printf("in_status(%s) flags 0x%llx\n", name, flags);
3293 
3294 	/* only print status for IPv4 interfaces */
3295 	if (!(flags & IFF_IPV4))
3296 		return;
3297 
3298 	/* if the interface is a tunnel, print the tunnel status */
3299 	tun_status();
3300 
3301 	if (!(flags & IFF_NOLOCAL)) {
3302 		(void) strncpy(lifr.lifr_name, name, sizeof (lifr.lifr_name));
3303 		if (ioctl(s, SIOCGLIFADDR, (caddr_t)&lifr) < 0) {
3304 			if (errno == EADDRNOTAVAIL || errno == EAFNOSUPPORT ||
3305 			    errno == ENXIO) {
3306 				if (!force)
3307 					return;
3308 				(void) memset(&lifr.lifr_addr, 0,
3309 				    sizeof (lifr.lifr_addr));
3310 			} else
3311 				Perror0_exit("in_status: SIOCGLIFADDR");
3312 		}
3313 		sin = (struct sockaddr_in *)&lifr.lifr_addr;
3314 		(void) printf("\tinet %s ", inet_ntoa(sin->sin_addr));
3315 		laddr = sin;
3316 	} else {
3317 		(void) printf("\tinet ");
3318 	}
3319 
3320 	(void) strncpy(lifr.lifr_name, name, sizeof (lifr.lifr_name));
3321 	if (ioctl(s, SIOCGLIFSUBNET, (caddr_t)&lifr) < 0) {
3322 		if (errno == EADDRNOTAVAIL || errno == EAFNOSUPPORT ||
3323 		    errno == ENXIO) {
3324 			if (!force)
3325 				return;
3326 			(void) memset(&lifr.lifr_addr, 0,
3327 			    sizeof (lifr.lifr_addr));
3328 		} else {
3329 			Perror0_exit("in_status: SIOCGLIFSUBNET");
3330 		}
3331 	}
3332 	sin = (struct sockaddr_in *)&lifr.lifr_addr;
3333 	if ((flags & IFF_NOLOCAL) ||
3334 	    sin->sin_addr.s_addr != laddr->sin_addr.s_addr) {
3335 		(void) printf("subnet %s/%d ", inet_ntoa(sin->sin_addr),
3336 		    lifr.lifr_addrlen);
3337 	}
3338 	if (sin->sin_family != AF_INET) {
3339 		(void) printf("Wrong family: %d\n", sin->sin_family);
3340 	}
3341 
3342 	(void) strncpy(lifr.lifr_name, name, sizeof (lifr.lifr_name));
3343 	if (ioctl(s, SIOCGLIFNETMASK, (caddr_t)&lifr) < 0) {
3344 		if (errno != EADDRNOTAVAIL)
3345 			Perror0_exit("in_status: SIOCGLIFNETMASK");
3346 		(void) memset(&lifr.lifr_addr, 0, sizeof (lifr.lifr_addr));
3347 	} else
3348 		netmask.sin_addr =
3349 		    ((struct sockaddr_in *)&lifr.lifr_addr)->sin_addr;
3350 	if (flags & IFF_POINTOPOINT) {
3351 		(void) strncpy(lifr.lifr_name, name, sizeof (lifr.lifr_name));
3352 		if (ioctl(s, SIOCGLIFDSTADDR, (caddr_t)&lifr) < 0) {
3353 			if (errno == EADDRNOTAVAIL)
3354 				(void) memset(&lifr.lifr_addr, 0,
3355 				    sizeof (lifr.lifr_addr));
3356 			else
3357 			    Perror0_exit("in_status: SIOCGLIFDSTADDR");
3358 		}
3359 		sin = (struct sockaddr_in *)&lifr.lifr_dstaddr;
3360 		(void) printf("--> %s ", inet_ntoa(sin->sin_addr));
3361 	}
3362 	(void) printf("netmask %x ", ntohl(netmask.sin_addr.s_addr));
3363 	if (flags & IFF_BROADCAST) {
3364 		(void) strncpy(lifr.lifr_name, name, sizeof (lifr.lifr_name));
3365 		if (ioctl(s, SIOCGLIFBRDADDR, (caddr_t)&lifr) < 0) {
3366 			if (errno == EADDRNOTAVAIL)
3367 				(void) memset(&lifr.lifr_addr, 0,
3368 				    sizeof (lifr.lifr_addr));
3369 			else
3370 			    Perror0_exit("in_status: SIOCGLIFBRDADDR");
3371 		}
3372 		sin = (struct sockaddr_in *)&lifr.lifr_addr;
3373 		if (sin->sin_addr.s_addr != 0) {
3374 			(void) printf("broadcast %s",
3375 			    inet_ntoa(sin->sin_addr));
3376 		}
3377 	}
3378 	/* If there is a groupname, print it for lun 0 alone */
3379 	if (strchr(name, ':') == NULL) {
3380 		(void) memset(lifr.lifr_groupname, 0,
3381 		    sizeof (lifr.lifr_groupname));
3382 		if (ioctl(s, SIOCGLIFGROUPNAME, (caddr_t)&lifr) >= 0) {
3383 			if (strlen(lifr.lifr_groupname) > 0) {
3384 				(void) printf("\n\tgroupname %s",
3385 				    lifr.lifr_groupname);
3386 			}
3387 		}
3388 	}
3389 	(void) putchar('\n');
3390 }
3391 
3392 static void
3393 in6_status(int force, uint64_t flags)
3394 {
3395 	char abuf[INET6_ADDRSTRLEN];
3396 	struct sockaddr_in6 *sin6, *laddr6;
3397 
3398 	if (debug)
3399 		(void) printf("in6_status(%s) flags 0x%llx\n", name, flags);
3400 
3401 	if (!(flags & IFF_IPV6))
3402 		return;
3403 
3404 	/* if the interface is a tunnel, print the tunnel status */
3405 	tun_status();
3406 
3407 	if (!(flags & IFF_NOLOCAL)) {
3408 		(void) strncpy(lifr.lifr_name, name, sizeof (lifr.lifr_name));
3409 		if (ioctl(s, SIOCGLIFADDR, (caddr_t)&lifr) < 0) {
3410 			if (errno == EADDRNOTAVAIL || errno == EAFNOSUPPORT ||
3411 			    errno == ENXIO) {
3412 				if (!force)
3413 					return;
3414 				(void) memset(&lifr.lifr_addr, 0,
3415 				    sizeof (lifr.lifr_addr));
3416 			} else
3417 				Perror0_exit("in_status6: SIOCGLIFADDR");
3418 		}
3419 		sin6 = (struct sockaddr_in6 *)&lifr.lifr_addr;
3420 		(void) printf("\tinet6 %s/%d ",
3421 		    inet_ntop(AF_INET6, (void *)&sin6->sin6_addr,
3422 		    abuf, sizeof (abuf)),
3423 		    lifr.lifr_addrlen);
3424 		laddr6 = sin6;
3425 	} else {
3426 		(void) printf("\tinet6 ");
3427 	}
3428 	(void) strncpy(lifr.lifr_name, name, sizeof (lifr.lifr_name));
3429 	if (ioctl(s, SIOCGLIFSUBNET, (caddr_t)&lifr) < 0) {
3430 		if (errno == EADDRNOTAVAIL || errno == EAFNOSUPPORT ||
3431 		    errno == ENXIO) {
3432 			if (!force)
3433 				return;
3434 			(void) memset(&lifr.lifr_addr, 0,
3435 			    sizeof (lifr.lifr_addr));
3436 		} else
3437 			Perror0_exit("in_status6: SIOCGLIFSUBNET");
3438 	}
3439 	sin6 = (struct sockaddr_in6 *)&lifr.lifr_addr;
3440 	if ((flags & IFF_NOLOCAL) ||
3441 	    !IN6_ARE_ADDR_EQUAL(&sin6->sin6_addr, &laddr6->sin6_addr)) {
3442 		(void) printf("subnet %s/%d ",
3443 		    inet_ntop(AF_INET6, (void *)&sin6->sin6_addr,
3444 		    abuf, sizeof (abuf)),
3445 		    lifr.lifr_addrlen);
3446 	}
3447 	if (sin6->sin6_family != AF_INET6) {
3448 		(void) printf("Wrong family: %d\n", sin6->sin6_family);
3449 	}
3450 	if (flags & IFF_POINTOPOINT) {
3451 		(void) strncpy(lifr.lifr_name, name, sizeof (lifr.lifr_name));
3452 		if (ioctl(s, SIOCGLIFDSTADDR, (caddr_t)&lifr) < 0) {
3453 			if (errno == EADDRNOTAVAIL)
3454 				(void) memset(&lifr.lifr_addr, 0,
3455 				    sizeof (lifr.lifr_addr));
3456 			else
3457 			    Perror0_exit("in_status6: SIOCGLIFDSTADDR");
3458 		}
3459 		sin6 = (struct sockaddr_in6 *)&lifr.lifr_dstaddr;
3460 		(void) printf("--> %s ",
3461 		    inet_ntop(AF_INET6, (void *)&sin6->sin6_addr,
3462 		    abuf, sizeof (abuf)));
3463 	}
3464 	if (verbose) {
3465 		(void) putchar('\n');
3466 		(void) putchar('\t');
3467 		(void) strncpy(lifr.lifr_name, name, sizeof (lifr.lifr_name));
3468 		if (ioctl(s, SIOCGLIFTOKEN, (caddr_t)&lifr) < 0) {
3469 			if (errno == EADDRNOTAVAIL || errno == EINVAL)
3470 				(void) memset(&lifr.lifr_addr, 0,
3471 				    sizeof (lifr.lifr_addr));
3472 			else
3473 			    Perror0_exit("in_status6: SIOCGLIFTOKEN");
3474 		} else {
3475 			sin6 = (struct sockaddr_in6 *)&lifr.lifr_addr;
3476 			(void) printf("token %s/%d ",
3477 			    inet_ntop(AF_INET6, (void *)&sin6->sin6_addr,
3478 			    abuf, sizeof (abuf)),
3479 			    lifr.lifr_addrlen);
3480 		}
3481 		if (ioctl(s, SIOCGLIFLNKINFO, (caddr_t)&lifr) < 0) {
3482 			if (errno != EINVAL) {
3483 				Perror0_exit("in_status6: SIOCGLIFLNKINFO");
3484 			}
3485 		} else {
3486 			(void) printf("maxhops %u, reachtime %u ms, "
3487 			    "reachretrans %u ms, maxmtu %u ",
3488 			    lifr.lifr_ifinfo.lir_maxhops,
3489 			    lifr.lifr_ifinfo.lir_reachtime,
3490 			    lifr.lifr_ifinfo.lir_reachretrans,
3491 			    lifr.lifr_ifinfo.lir_maxmtu);
3492 		}
3493 	}
3494 	/* If there is a groupname, print it for lun 0 alone */
3495 	if (strchr(name, ':') == NULL) {
3496 		(void) memset(lifr.lifr_groupname, 0,
3497 		    sizeof (lifr.lifr_groupname));
3498 		if (ioctl(s, SIOCGLIFGROUPNAME, (caddr_t)&lifr) >= 0) {
3499 			if (strlen(lifr.lifr_groupname) > 0) {
3500 				(void) printf("\n\tgroupname %s",
3501 				    lifr.lifr_groupname);
3502 			}
3503 		}
3504 	}
3505 	(void) putchar('\n');
3506 }
3507 
3508 static void
3509 in_configinfo(int force, uint64_t flags)
3510 {
3511 	struct sockaddr_in *sin, *laddr;
3512 	struct	sockaddr_in netmask = { AF_INET };
3513 
3514 	if (debug)
3515 		(void) printf("in_configinfo(%s) flags 0x%llx\n", name, flags);
3516 
3517 	/* only configinfo info for IPv4 interfaces */
3518 	if (!(flags & IFF_IPV4))
3519 		return;
3520 
3521 	if (!(flags & IFF_NOLOCAL)) {
3522 		(void) strncpy(lifr.lifr_name, name, sizeof (lifr.lifr_name));
3523 		if (ioctl(s, SIOCGLIFADDR, (caddr_t)&lifr) < 0) {
3524 			if (errno == EADDRNOTAVAIL || errno == EAFNOSUPPORT ||
3525 			    errno == ENXIO) {
3526 				if (!force)
3527 					return;
3528 				(void) memset(&lifr.lifr_addr, 0,
3529 				    sizeof (lifr.lifr_addr));
3530 			} else
3531 				Perror0_exit("in_configinfo: SIOCGLIFADDR");
3532 		}
3533 		sin = (struct sockaddr_in *)&lifr.lifr_addr;
3534 		if (get_lun(name) != 0) {
3535 			(void) printf(" addif %s ", inet_ntoa(sin->sin_addr));
3536 		} else {
3537 			(void) printf(" set %s ", inet_ntoa(sin->sin_addr));
3538 		}
3539 		laddr = sin;
3540 	}
3541 
3542 	(void) strncpy(lifr.lifr_name, name, sizeof (lifr.lifr_name));
3543 	if (ioctl(s, SIOCGLIFSUBNET, (caddr_t)&lifr) < 0) {
3544 		if (errno == EADDRNOTAVAIL || errno == EAFNOSUPPORT ||
3545 		    errno == ENXIO) {
3546 			if (!force)
3547 				return;
3548 			(void) memset(&lifr.lifr_addr, 0,
3549 			    sizeof (lifr.lifr_addr));
3550 		} else {
3551 			Perror0_exit("in_configinfo: SIOCGLIFSUBNET");
3552 		}
3553 	}
3554 	sin = (struct sockaddr_in *)&lifr.lifr_addr;
3555 
3556 	if ((flags & IFF_NOLOCAL) ||
3557 	    sin->sin_addr.s_addr != laddr->sin_addr.s_addr) {
3558 		(void) printf(" subnet %s/%d ", inet_ntoa(sin->sin_addr),
3559 		    lifr.lifr_addrlen);
3560 	}
3561 	(void) strncpy(lifr.lifr_name, name, sizeof (lifr.lifr_name));
3562 	if (ioctl(s, SIOCGLIFNETMASK, (caddr_t)&lifr) < 0) {
3563 		if (errno != EADDRNOTAVAIL)
3564 			Perror0_exit("in_configinfo: SIOCGLIFNETMASK");
3565 		(void) memset(&lifr.lifr_addr, 0, sizeof (lifr.lifr_addr));
3566 	} else
3567 		netmask.sin_addr =
3568 		    ((struct sockaddr_in *)&lifr.lifr_addr)->sin_addr;
3569 	if (flags & IFF_POINTOPOINT) {
3570 		(void) strncpy(lifr.lifr_name, name, sizeof (lifr.lifr_name));
3571 		if (ioctl(s, SIOCGLIFDSTADDR, (caddr_t)&lifr) < 0) {
3572 			if (errno == EADDRNOTAVAIL)
3573 				(void) memset(&lifr.lifr_addr, 0,
3574 				    sizeof (lifr.lifr_addr));
3575 			else
3576 			    Perror0_exit("in_configinfo: SIOCGLIFDSTADDR");
3577 		}
3578 		sin = (struct sockaddr_in *)&lifr.lifr_dstaddr;
3579 		(void) printf(" destination %s ", inet_ntoa(sin->sin_addr));
3580 	}
3581 	(void) printf(" netmask 0x%x ", ntohl(netmask.sin_addr.s_addr));
3582 	if (flags & IFF_BROADCAST) {
3583 		(void) strncpy(lifr.lifr_name, name, sizeof (lifr.lifr_name));
3584 		if (ioctl(s, SIOCGLIFBRDADDR, (caddr_t)&lifr) < 0) {
3585 			if (errno == EADDRNOTAVAIL)
3586 				(void) memset(&lifr.lifr_addr, 0,
3587 				    sizeof (lifr.lifr_addr));
3588 			else
3589 			    Perror0_exit("in_configinfo: SIOCGLIFBRDADDR");
3590 		}
3591 		sin = (struct sockaddr_in *)&lifr.lifr_addr;
3592 		if (sin->sin_addr.s_addr != 0) {
3593 			(void) printf(" broadcast %s ",
3594 			    inet_ntoa(sin->sin_addr));
3595 		}
3596 	}
3597 
3598 	/* If there is a groupname, print it for lun 0 alone */
3599 	if (get_lun(name) == 0) {
3600 		(void) memset(lifr.lifr_groupname, 0,
3601 		    sizeof (lifr.lifr_groupname));
3602 		if (ioctl(s, SIOCGLIFGROUPNAME, (caddr_t)&lifr) >= 0) {
3603 			if (strlen(lifr.lifr_groupname) > 0) {
3604 				(void) printf(" group %s ",
3605 				    lifr.lifr_groupname);
3606 			}
3607 		}
3608 	}
3609 
3610 	/* Print flags to configure */
3611 	print_config_flags(flags);
3612 
3613 	/* IFF_NOARP applies to AF_INET only */
3614 	if (flags & IFF_NOARP) {
3615 		(void) printf("-arp ");
3616 	}
3617 }
3618 
3619 static void
3620 in6_configinfo(int force, uint64_t flags)
3621 {
3622 	char abuf[INET6_ADDRSTRLEN];
3623 	struct sockaddr_in6 *sin6, *laddr6;
3624 
3625 	if (debug)
3626 		(void) printf("in6_configinfo(%s) flags 0x%llx\n", name,
3627 		    flags);
3628 
3629 	if (!(flags & IFF_IPV6))
3630 		return;
3631 
3632 	if (!(flags & IFF_NOLOCAL)) {
3633 		(void) strncpy(lifr.lifr_name, name, sizeof (lifr.lifr_name));
3634 		if (ioctl(s, SIOCGLIFADDR, (caddr_t)&lifr) < 0) {
3635 			if (errno == EADDRNOTAVAIL || errno == EAFNOSUPPORT ||
3636 			    errno == ENXIO) {
3637 				if (!force)
3638 					return;
3639 				(void) memset(&lifr.lifr_addr, 0,
3640 				    sizeof (lifr.lifr_addr));
3641 			} else
3642 				Perror0_exit("in6_configinfo: SIOCGLIFADDR");
3643 		}
3644 		sin6 = (struct sockaddr_in6 *)&lifr.lifr_addr;
3645 		if (get_lun(name) != 0) {
3646 			(void) printf(" addif %s/%d ",
3647 			    inet_ntop(AF_INET6, (void *)&sin6->sin6_addr,
3648 			    abuf, sizeof (abuf)),
3649 			    lifr.lifr_addrlen);
3650 		} else {
3651 			(void) printf(" set %s/%d ",
3652 			    inet_ntop(AF_INET6, (void *)&sin6->sin6_addr,
3653 			    abuf, sizeof (abuf)),
3654 			    lifr.lifr_addrlen);
3655 		}
3656 		laddr6 = sin6;
3657 	}
3658 	(void) strncpy(lifr.lifr_name, name, sizeof (lifr.lifr_name));
3659 	if (ioctl(s, SIOCGLIFSUBNET, (caddr_t)&lifr) < 0) {
3660 		if (errno == EADDRNOTAVAIL || errno == EAFNOSUPPORT ||
3661 		    errno == ENXIO) {
3662 			if (!force)
3663 				return;
3664 			(void) memset(&lifr.lifr_addr, 0,
3665 			    sizeof (lifr.lifr_addr));
3666 		} else
3667 			Perror0_exit("in6_configinfo: SIOCGLIFSUBNET");
3668 	}
3669 	sin6 = (struct sockaddr_in6 *)&lifr.lifr_addr;
3670 	if ((flags & IFF_NOLOCAL) ||
3671 	    !IN6_ARE_ADDR_EQUAL(&sin6->sin6_addr, &laddr6->sin6_addr)) {
3672 		(void) printf(" subnet %s/%d ",
3673 		    inet_ntop(AF_INET6, (void *)&sin6->sin6_addr,
3674 		    abuf, sizeof (abuf)),
3675 		    lifr.lifr_addrlen);
3676 	}
3677 
3678 	if (flags & IFF_POINTOPOINT) {
3679 		(void) strncpy(lifr.lifr_name, name, sizeof (lifr.lifr_name));
3680 		if (ioctl(s, SIOCGLIFDSTADDR, (caddr_t)&lifr) < 0) {
3681 			if (errno == EADDRNOTAVAIL)
3682 				(void) memset(&lifr.lifr_addr, 0,
3683 				    sizeof (lifr.lifr_addr));
3684 			else
3685 			    Perror0_exit("in6_configinfo: SIOCGLIFDSTADDR");
3686 		}
3687 		sin6 = (struct sockaddr_in6 *)&lifr.lifr_dstaddr;
3688 		(void) printf(" destination %s ",
3689 		    inet_ntop(AF_INET6, (void *)&sin6->sin6_addr,
3690 		    abuf, sizeof (abuf)));
3691 	}
3692 
3693 	(void) strncpy(lifr.lifr_name, name, sizeof (lifr.lifr_name));
3694 	if (ioctl(s, SIOCGLIFTOKEN, (caddr_t)&lifr) < 0) {
3695 		if (errno == EADDRNOTAVAIL || errno == EINVAL)
3696 			(void) memset(&lifr.lifr_addr, 0,
3697 			    sizeof (lifr.lifr_addr));
3698 		else
3699 		    Perror0_exit("in6_configinfo: SIOCGLIFTOKEN");
3700 	} else {
3701 		sin6 = (struct sockaddr_in6 *)&lifr.lifr_addr;
3702 		(void) printf(" token %s/%d ",
3703 		    inet_ntop(AF_INET6, (void *)&sin6->sin6_addr,
3704 		    abuf, sizeof (abuf)),
3705 		    lifr.lifr_addrlen);
3706 	}
3707 
3708 	/* If there is a groupname, print it for lun 0 alone */
3709 	if (get_lun(name) == 0) {
3710 		(void) memset(lifr.lifr_groupname, 0,
3711 		    sizeof (lifr.lifr_groupname));
3712 		if (ioctl(s, SIOCGLIFGROUPNAME, (caddr_t)&lifr) >= 0) {
3713 			if (strlen(lifr.lifr_groupname) > 0) {
3714 				(void) printf(" group %s ",
3715 				    lifr.lifr_groupname);
3716 			}
3717 		}
3718 	}
3719 
3720 	/* Print flags to configure */
3721 	print_config_flags(flags);
3722 
3723 	/* IFF_NONUD applies to AF_INET6 only */
3724 	if (flags & IFF_NONUD) {
3725 		(void) printf("-nud ");
3726 	}
3727 }
3728 
3729 /* ARGSUSED */
3730 static int
3731 get_lun(char *rsrc)
3732 {
3733 	char resource[LIFNAMSIZ];
3734 	char *cp;
3735 
3736 	(void) strcpy(resource, rsrc);
3737 
3738 	/* remove LIF component */
3739 	cp = strchr(resource, ':');
3740 	if (cp) {
3741 		cp++;
3742 		return (atoi(cp));
3743 	}
3744 
3745 	return (0);
3746 }
3747 
3748 /*
3749  * We need to plink both the arp-device stream and the arp-ip-device stream.
3750  * However the muxid is stored only in IP. Plumbing 2 streams individually
3751  * is not atomic, and if ifconfig is killed, the resulting plumbing can
3752  * be inconsistent. For eg. if only the arp stream is plumbed, we have lost
3753  * the muxid, and the half-baked plumbing can neither be unplumbed nor
3754  * replumbed, thus requiring a reboot. To avoid the above the following
3755  * scheme is used.
3756  *
3757  * Ifconfig asks IP to enforce atomicity of plumbing the arp and IP streams.
3758  * This is done by pushing arp on to the mux (/dev/udp). ARP adds some
3759  * extra information in the I_PLINK and I_PUNLINK ioctls to let IP know
3760  * that the plumbing/unplumbing has to be done atomically. Ifconfig plumbs
3761  * the IP stream first, and unplumbs it last. The kernel (IP) does not
3762  * allow IP stream to be unplumbed without unplumbing arp stream. Similarly
3763  * it does not allow arp stream to be plumbed before IP stream is plumbed.
3764  * There is no need to use SIOCSLIFMUXID, since the whole operation is atomic,
3765  * and IP uses the info in the I_PLINK message to get the muxid.
3766  *
3767  * a. STREAMS does not allow us to use /dev/ip itself as the mux. So we use
3768  *    /dev/udp[6].
3769  * b. SIOCGLIFMUXID returns the muxid corresponding to the V4 or V6 stream
3770  *    depending on the open i.e. V4 vs V6 open. So we need to use /dev/udp
3771  *    or /dev/udp6.
3772  * c. We need to push ARP in order to get the required kernel support for
3773  *    atomic plumbings. The actual work done by ARP is explained in arp.c
3774  *    Without pushing ARP, we will still be able to plumb/unplumb. But
3775  *    it is not atomic, and is supported by the kernel for backward
3776  *    compatibility for other utilities like atmifconfig etc. In this case
3777  *    the utility must use SIOCSLIFMUXID.
3778  */
3779 static void
3780 plumb_one_device(dlpi_if_attr_t *diap, int ip_fd, int af)
3781 {
3782 	int	arp_fd = -1;
3783 	int	arp_muxid = -1, ip_muxid;
3784 	int	mux_fd;
3785 	char	*udp_dev_name;
3786 	dlpi_if_attr_t	dia;
3787 
3788 	if (debug)
3789 		(void) printf("plumb_one_device: ifname %s, ppa %d\n",
3790 		    diap->ifname, diap->ppa);
3791 
3792 	if (diap->style == DL_STYLE2 && dlpi_detach(ip_fd, -1) < 0)
3793 		Perror0_exit("dlpi_detach");
3794 
3795 	if (ioctl(ip_fd, I_PUSH, IP_MOD_NAME) == -1)
3796 		Perror2_exit("I_PUSH", IP_MOD_NAME);
3797 
3798 	/*
3799 	 * Push the ARP module onto the interface stream. IP uses
3800 	 * this to send resolution requests up to ARP. We need to
3801 	 * do this before the SLIFNAME ioctl is sent down because
3802 	 * the interface becomes publicly known as soon as the SLIFNAME
3803 	 * ioctl completes. Thus some other process trying to bring up
3804 	 * the interface after SLIFNAME but before we have pushed ARP
3805 	 * could hang. We pop the module again later if it is not needed.
3806 	 */
3807 	if (ioctl(ip_fd, I_PUSH, ARP_MOD_NAME) == -1)
3808 		Perror2_exit("I_PUSH", ARP_MOD_NAME);
3809 
3810 	/*
3811 	 * Set IFF_IPV4/IFF_IPV6 flags.
3812 	 * At this point in time the kernel also allows an
3813 	 * override of the CANTCHANGE flags.
3814 	 */
3815 
3816 	lifr.lifr_name[0] = '\0';
3817 	if (ioctl(ip_fd, SIOCGLIFFLAGS, (char *)&lifr) == -1)
3818 		Perror0_exit("plumb_one_device: SIOCGLIFFLAGS");
3819 
3820 	/* Set the name string and the IFF_IPV* flag */
3821 	if (af == AF_INET6) {
3822 		lifr.lifr_flags |= IFF_IPV6;
3823 		lifr.lifr_flags &= ~(IFF_BROADCAST | IFF_IPV4);
3824 	} else {
3825 		lifr.lifr_flags |= IFF_IPV4;
3826 		lifr.lifr_flags &= ~IFF_IPV6;
3827 	}
3828 
3829 	/* record the device and module names as interface name */
3830 	lifr.lifr_ppa = diap->ppa;
3831 	(void) strncpy(lifr.lifr_name, name, sizeof (lifr.lifr_name));
3832 
3833 	/* set the interface name */
3834 	if (ioctl(ip_fd, SIOCSLIFNAME, (char *)&lifr) == -1) {
3835 		if (errno != EEXIST)
3836 			Perror0_exit("SIOCSLIFNAME for ip");
3837 		/*
3838 		 * This difference between the way we behave for EEXIST
3839 		 * and that with other errors exists to preserve legacy
3840 		 * behaviour. Earlier when foreachinterface() and matcif()
3841 		 * were doing the duplicate interface name checks, for
3842 		 * already existing interfaces, inetplumb() returned "0".
3843 		 * To preserve this behaviour, Perror0() and return are
3844 		 * called for EEXIST.
3845 		 */
3846 		Perror0("SIOCSLIFNAME for ip");
3847 		return;
3848 	}
3849 
3850 	/* Get the full set of existing flags for this stream */
3851 	if (ioctl(ip_fd, SIOCGLIFFLAGS, (char *)&lifr) == -1)
3852 		Perror0_exit("plumb_one_device: SIOCFLIFFLAGS");
3853 
3854 	if (debug) {
3855 		(void) printf("plumb_one_device: %s got flags: \n",
3856 		    lifr.lifr_name);
3857 		print_flags(lifr.lifr_flags);
3858 		(void) putchar('\n');
3859 	}
3860 
3861 	/* Check if arp is not actually needed */
3862 	if (lifr.lifr_flags & (IFF_NOARP|IFF_IPV6)) {
3863 		if (ioctl(ip_fd, I_POP, 0) == -1)
3864 			Perror2_exit("I_POP", ARP_MOD_NAME);
3865 	}
3866 
3867 	/*
3868 	 * Open "/dev/udp" for use as a multiplexor to PLINK the
3869 	 * interface stream under. We use "/dev/udp" instead of "/dev/ip"
3870 	 * since STREAMS will not let you PLINK a driver under itself,
3871 	 * and "/dev/ip" is typically the driver at the bottom of
3872 	 * the stream for tunneling interfaces.
3873 	 */
3874 	if (af == AF_INET6)
3875 		udp_dev_name = UDP6_DEV_NAME;
3876 	else
3877 		udp_dev_name = UDP_DEV_NAME;
3878 	if ((mux_fd = open_arp_on_udp(udp_dev_name)) == -1)
3879 		exit(EXIT_FAILURE);
3880 
3881 	/* Check if arp is not needed */
3882 	if (lifr.lifr_flags & (IFF_NOARP|IFF_IPV6)) {
3883 		/*
3884 		 * PLINK the interface stream so that ifconfig can exit
3885 		 * without tearing down the stream.
3886 		 */
3887 		if ((ip_muxid = ioctl(mux_fd, I_PLINK, ip_fd)) == -1) {
3888 			Perror0_exit("I_PLINK for ip");
3889 		}
3890 		(void) close(mux_fd);
3891 		return;
3892 	}
3893 
3894 	/*
3895 	 * This interface does use ARP, so set up a separate stream
3896 	 * from the interface to ARP.
3897 	 *
3898 	 * Note: modules specified by the user are pushed
3899 	 * only on the interface stream, not on the ARP stream.
3900 	 */
3901 
3902 	if (debug)
3903 		(void) printf("plumb_one_device: ifname: %s\n",
3904 		    diap->ifname);
3905 	arp_fd = dlpi_if_open(diap->ifname, &dia, _B_FALSE);
3906 
3907 	if (dia.style == DL_STYLE2 && dlpi_detach(arp_fd, -1) < 0)
3908 		Perror0_exit("dlpi_detach");
3909 
3910 	if (ioctl(arp_fd, I_PUSH, ARP_MOD_NAME) == -1)
3911 		Perror2_exit("I_PUSH", ARP_MOD_NAME);
3912 
3913 	/*
3914 	 * Tell ARP the name and unit number for this interface.
3915 	 * Note that arp has no support for transparent ioctls.
3916 	 */
3917 	if (strioctl(arp_fd, SIOCSLIFNAME, (char *)&lifr,
3918 	    sizeof (lifr)) == -1) {
3919 		if (errno != EEXIST)
3920 			Perror0_exit("SIOCSLIFNAME for arp");
3921 		Perror0("SIOCSLIFNAME for arp");
3922 		(void) close(arp_fd);
3923 		(void) close(mux_fd);
3924 		return;
3925 	}
3926 	/*
3927 	 * PLINK the IP and ARP streams so that ifconfig can exit
3928 	 * without tearing down the stream.
3929 	 */
3930 	if ((ip_muxid = ioctl(mux_fd, I_PLINK, ip_fd)) == -1) {
3931 		Perror0_exit("I_PLINK for ip");
3932 	}
3933 	if ((arp_muxid = ioctl(mux_fd, I_PLINK, arp_fd)) == -1) {
3934 		(void) ioctl(mux_fd, I_PUNLINK, ip_muxid);
3935 		Perror0_exit("I_PLINK for arp");
3936 	}
3937 
3938 	if (debug)
3939 		(void) printf("arp muxid = %d\n", arp_muxid);
3940 	(void) close(arp_fd);
3941 	(void) close(mux_fd);
3942 }
3943 
3944 
3945 /*
3946  * If this is a physical interface then remove it.
3947  * If it is a logical interface name use SIOCLIFREMOVEIF to
3948  * remove it. In both cases fail if it doesn't exist.
3949  */
3950 /* ARGSUSED */
3951 static int
3952 inetunplumb(char *arg, int64_t param)
3953 {
3954 	int ip_muxid, arp_muxid;
3955 	int mux_fd;
3956 	char *udp_dev_name;
3957 	char *strptr;
3958 	uint64_t flags;
3959 	boolean_t changed_arp_muxid = _B_FALSE;
3960 	int save_errno;
3961 
3962 	strptr = strchr(name, ':');
3963 	if (strptr != NULL || strcmp(name, LOOPBACK_IF) == 0) {
3964 		/* Can't unplumb logical interface zero */
3965 		if (strptr != NULL && strcmp(strptr, ":0") == 0) {
3966 			(void) fprintf(stderr, "ifconfig: unplumb:"
3967 			    " Cannot unplumb %s: Invalid interface\n", name);
3968 			exit(1);
3969 		}
3970 		(void) strncpy(lifr.lifr_name, name, sizeof (lifr.lifr_name));
3971 		(void) memset(&lifr.lifr_addr, 0, sizeof (lifr.lifr_addr));
3972 
3973 		if (ioctl(s, SIOCLIFREMOVEIF, (caddr_t)&lifr) < 0)
3974 			Perror0_exit("unplumb: SIOCLIFREMOVEIF");
3975 		return (0);
3976 	}
3977 
3978 	/*
3979 	 * We used /dev/udp or udp6 to set up the mux. So we have to use
3980 	 * the same now for PUNLINK also.
3981 	 */
3982 	if (afp->af_af == AF_INET6)
3983 		udp_dev_name = UDP6_DEV_NAME;
3984 	else
3985 		udp_dev_name = UDP_DEV_NAME;
3986 
3987 	if ((mux_fd = open_arp_on_udp(udp_dev_name)) == -1)
3988 		exit(EXIT_FAILURE);
3989 
3990 	(void) strncpy(lifr.lifr_name, name, sizeof (lifr.lifr_name));
3991 	if (ioctl(mux_fd, SIOCGLIFFLAGS, (caddr_t)&lifr) < 0) {
3992 		Perror0_exit("unplumb: SIOCGLIFFLAGS");
3993 	}
3994 	flags = lifr.lifr_flags;
3995 	if (ioctl(mux_fd, SIOCGLIFMUXID, (caddr_t)&lifr) < 0) {
3996 		Perror0_exit("unplumb: SIOCGLIFMUXID");
3997 	}
3998 	arp_muxid = lifr.lifr_arp_muxid;
3999 	ip_muxid = lifr.lifr_ip_muxid;
4000 	/*
4001 	 * We don't have a good way of knowing whether the arp stream is
4002 	 * plumbed. We can't rely on IFF_NOARP because someone could
4003 	 * have turned it off later using "ifconfig xxx -arp".
4004 	 */
4005 	if (arp_muxid != 0) {
4006 		if (debug)
4007 			(void) printf("arp_muxid %d\n", arp_muxid);
4008 		if (ioctl(mux_fd, I_PUNLINK, arp_muxid) < 0) {
4009 			if ((errno == EINVAL) &&
4010 			    (flags & (IFF_NOARP | IFF_IPV6))) {
4011 				/*
4012 				 * Some plumbing utilities set the muxid to
4013 				 * -1 or some invalid value to signify that
4014 				 * there is no arp stream. Set the muxid to 0
4015 				 * before trying to unplumb the IP stream.
4016 				 * IP does not allow the IP stream to be
4017 				 * unplumbed if it sees a non-null arp muxid,
4018 				 * for consistency of IP-ARP streams.
4019 				 */
4020 				lifr.lifr_arp_muxid = 0;
4021 				(void) ioctl(mux_fd, SIOCSLIFMUXID,
4022 				    (caddr_t)&lifr);
4023 				changed_arp_muxid = _B_TRUE;
4024 			} else {
4025 				Perror0("I_PUNLINK for arp");
4026 			}
4027 		}
4028 	}
4029 	if (debug)
4030 		(void) printf("ip_muxid %d\n", ip_muxid);
4031 
4032 	if (ioctl(mux_fd, I_PUNLINK, ip_muxid) < 0) {
4033 		if (changed_arp_muxid) {
4034 			/*
4035 			 * Some error occurred, and we need to restore
4036 			 * everything back to what it was.
4037 			 */
4038 			save_errno = errno;
4039 			lifr.lifr_arp_muxid = arp_muxid;
4040 			lifr.lifr_ip_muxid = ip_muxid;
4041 			(void) ioctl(mux_fd, SIOCSLIFMUXID, (caddr_t)&lifr);
4042 			errno = save_errno;
4043 		}
4044 		Perror0_exit("I_PUNLINK for ip");
4045 	}
4046 	(void) close(mux_fd);
4047 	return (0);
4048 }
4049 
4050 /*
4051  * If this is a physical interface then create it unless it is already
4052  * present. If it is a logical interface name use SIOCLIFADDIF to
4053  * create and (and fail it if already exists.)
4054  * As a special case send SIOCLIFADDIF for the loopback interface. This
4055  * is needed since there is no other notion of plumbing the loopback
4056  * interface.
4057  */
4058 /* ARGSUSED */
4059 static int
4060 inetplumb(char *arg, int64_t param)
4061 {
4062 	char		*strptr;
4063 	int		dev_fd;
4064 	dlpi_if_attr_t	dia;
4065 	boolean_t	islo;
4066 
4067 	strptr = strchr(name, ':');
4068 	islo = (strcmp(name, LOOPBACK_IF) == 0);
4069 
4070 	if (strptr != NULL || islo) {
4071 		(void) memset(&lifr, 0, sizeof (lifr));
4072 		(void) strlcpy(lifr.lifr_name, name, sizeof (lifr.lifr_name));
4073 		if (islo && ioctl(s, SIOCGLIFADDR, (caddr_t)&lifr) >= 0) {
4074 			if (debug) {
4075 				(void) fprintf(stderr,
4076 				    "ifconfig: %s already exists\n", name);
4077 			}
4078 			return (0);
4079 		}
4080 		if (ioctl(s, SIOCLIFADDIF, (caddr_t)&lifr) < 0) {
4081 			if (errno == EEXIST) {
4082 				if (debug) {
4083 					(void) fprintf(stderr,
4084 					    "ifconfig: %s already exists\n",
4085 					    name);
4086 				}
4087 			} else {
4088 				Perror2_exit("plumb: SIOCLIFADDIF", name);
4089 			}
4090 		}
4091 		/*
4092 		 * IP can create the new logical interface on a different
4093 		 * physical interface in the same IPMP group. Take the new
4094 		 * interface into account for further operations.
4095 		 */
4096 		(void) strncpy(name, lifr.lifr_name, sizeof (name));
4097 		return (0);
4098 	}
4099 
4100 	if (debug)
4101 		(void) printf("inetplumb: %s af %d\n", name, afp->af_af);
4102 
4103 	if ((dev_fd = dlpi_if_open(name, &dia, _B_FALSE)) < 0) {
4104 		Perror2_exit("plumb", name);
4105 		/* NOTREACHED */
4106 	}
4107 
4108 	plumb_one_device(&dia, dev_fd, afp->af_af);
4109 	(void) close(dev_fd);
4110 	return (0);
4111 }
4112 
4113 void
4114 Perror0(char *cmd)
4115 {
4116 	int save_errno;
4117 
4118 	save_errno = errno;
4119 	(void) fprintf(stderr, "ifconfig: ");
4120 	errno = save_errno;
4121 	switch (errno) {
4122 
4123 	case ENXIO:
4124 		(void) fprintf(stderr, "%s: %s: no such interface\n",
4125 			cmd, lifr.lifr_name);
4126 		break;
4127 
4128 	case EPERM:
4129 		(void) fprintf(stderr, "%s: %s: permission denied\n",
4130 			cmd, lifr.lifr_name);
4131 		break;
4132 
4133 	case EEXIST:
4134 		(void) fprintf(stderr, "%s: %s: already exists\n",
4135 			cmd, lifr.lifr_name);
4136 		break;
4137 
4138 	default: {
4139 		char buf[BUFSIZ];
4140 
4141 		(void) snprintf(buf, sizeof (buf), "%s: %s",
4142 		    cmd, lifr.lifr_name);
4143 		perror(buf);
4144 	}
4145 	}
4146 }
4147 
4148 void
4149 Perror0_exit(char *cmd)
4150 {
4151 	Perror0(cmd);
4152 	exit(1);
4153 	/* NOTREACHED */
4154 }
4155 
4156 void
4157 Perror2(char *cmd, char *str)
4158 {
4159 	int save_errno;
4160 
4161 	save_errno = errno;
4162 	(void) fprintf(stderr, "ifconfig: ");
4163 	errno = save_errno;
4164 	switch (errno) {
4165 
4166 	case ENXIO:
4167 		(void) fprintf(stderr, "%s: %s: no such interface\n",
4168 			cmd, str);
4169 		break;
4170 
4171 	case EPERM:
4172 		(void) fprintf(stderr, "%s: %s: permission denied\n",
4173 			cmd, str);
4174 		break;
4175 
4176 	default: {
4177 		char buf[BUFSIZ];
4178 
4179 		(void) snprintf(buf, sizeof (buf), "%s: %s", cmd, str);
4180 		perror(buf);
4181 	}
4182 	}
4183 }
4184 
4185 /*
4186  * Print out error message (Perror2()) and exit
4187  */
4188 void
4189 Perror2_exit(char *cmd, char *str)
4190 {
4191 	Perror2(cmd, str);
4192 	exit(1);
4193 	/* NOTREACHED */
4194 }
4195 
4196 /*
4197  * If the last argument is non-NULL allow a <addr>/<n> syntax and
4198  * pass out <n> in *plenp.
4199  * If <n> doesn't parse return BAD_ADDR as *plenp.
4200  * If no /<n> is present return NO_PREFIX as *plenp.
4201  */
4202 static void
4203 in_getaddr(char *s, struct sockaddr *saddr, int *plenp)
4204 {
4205 	struct sockaddr_in *sin = (struct sockaddr_in *)saddr;
4206 	struct hostent *hp;
4207 	struct netent *np;
4208 	char str[BUFSIZ];
4209 	int error_num;
4210 
4211 	(void) strncpy(str, s, sizeof (str));
4212 
4213 	/*
4214 	 * Look for '/'<n> is plenp
4215 	 */
4216 	if (plenp != NULL) {
4217 		char *cp;
4218 
4219 		*plenp = in_getprefixlen(str, _B_TRUE, ADDRBITS_V4);
4220 		if (*plenp == BAD_ADDR)
4221 			return;
4222 		cp = strchr(str, '/');
4223 		if (cp != NULL)
4224 			*cp = '\0';
4225 	} else if (strchr(str, '/') != NULL) {
4226 		(void) fprintf(stderr, "ifconfig: %s: unexpected '/'\n", str);
4227 		exit(1);
4228 	}
4229 
4230 	(void) memset(sin, 0, sizeof (*sin));
4231 
4232 	/*
4233 	 *	Try to catch attempts to set the broadcast address to all 1's.
4234 	 */
4235 	if (strcmp(str, "255.255.255.255") == 0 ||
4236 	    (strtoul(str, (char **)NULL, 0) == 0xffffffffUL)) {
4237 		sin->sin_family = AF_INET;
4238 		sin->sin_addr.s_addr = 0xffffffff;
4239 		return;
4240 	}
4241 
4242 	hp = getipnodebyname(str, AF_INET, 0, &error_num);
4243 	if (hp) {
4244 		sin->sin_family = hp->h_addrtype;
4245 		(void) memcpy(&sin->sin_addr, hp->h_addr, hp->h_length);
4246 		freehostent(hp);
4247 		return;
4248 	}
4249 	np = getnetbyname(str);
4250 	if (np) {
4251 		sin->sin_family = np->n_addrtype;
4252 		sin->sin_addr = inet_makeaddr(np->n_net, INADDR_ANY);
4253 		return;
4254 	}
4255 	if (error_num == TRY_AGAIN) {
4256 		(void) fprintf(stderr, "ifconfig: %s: bad address "
4257 		    "(try again later)\n", s);
4258 	} else {
4259 		(void) fprintf(stderr, "ifconfig: %s: bad address\n", s);
4260 	}
4261 	exit(1);
4262 }
4263 
4264 /*
4265  * If the last argument is non-NULL allow a <addr>/<n> syntax and
4266  * pass out <n> in *plenp.
4267  * If <n> doesn't parse return BAD_ADDR as *plenp.
4268  * If no /<n> is present return NO_PREFIX as *plenp.
4269  */
4270 static void
4271 in6_getaddr(char *s, struct sockaddr *saddr, int *plenp)
4272 {
4273 	struct sockaddr_in6 *sin6 = (struct sockaddr_in6 *)saddr;
4274 	struct hostent *hp;
4275 	char str[BUFSIZ];
4276 	int error_num;
4277 
4278 	(void) strncpy(str, s, sizeof (str));
4279 
4280 	/*
4281 	 * Look for '/'<n> is plenp
4282 	 */
4283 	if (plenp != NULL) {
4284 		char *cp;
4285 
4286 		*plenp = in_getprefixlen(str, _B_TRUE, ADDRBITS_V6);
4287 		if (*plenp == BAD_ADDR)
4288 			return;
4289 		cp = strchr(str, '/');
4290 		if (cp != NULL)
4291 			*cp = '\0';
4292 	} else if (strchr(str, '/') != NULL) {
4293 		(void) fprintf(stderr, "ifconfig: %s: unexpected '/'\n", str);
4294 		exit(1);
4295 	}
4296 
4297 	(void) memset(sin6, 0, sizeof (*sin6));
4298 
4299 	hp = getipnodebyname(str, AF_INET6, 0, &error_num);
4300 	if (hp) {
4301 		sin6->sin6_family = hp->h_addrtype;
4302 		(void) memcpy(&sin6->sin6_addr, hp->h_addr, hp->h_length);
4303 		freehostent(hp);
4304 		return;
4305 	}
4306 	if (error_num == TRY_AGAIN) {
4307 		(void) fprintf(stderr, "ifconfig: %s: bad address "
4308 		    "(try again later)\n", s);
4309 	} else {
4310 		(void) fprintf(stderr, "ifconfig: %s: bad address\n", s);
4311 	}
4312 	exit(1);
4313 }
4314 
4315 /*
4316  * If "slash" is zero this parses the whole string as
4317  * an integer. With "slash" non zero it parses the tail part as an integer.
4318  *
4319  * If it is not a valid integer this returns BAD_ADDR.
4320  * If there is /<n> present this returns NO_PREFIX.
4321  */
4322 static int
4323 in_getprefixlen(char *addr, boolean_t slash, int max_plen)
4324 {
4325 	int prefixlen;
4326 	char *str, *end;
4327 
4328 	if (slash) {
4329 		str = strchr(addr, '/');
4330 		if (str == NULL)
4331 			return (NO_PREFIX);
4332 		str++;
4333 	} else
4334 		str = addr;
4335 
4336 	prefixlen = strtol(str, &end, 10);
4337 	if (prefixlen < 0)
4338 		return (BAD_ADDR);
4339 	if (str == end)
4340 		return (BAD_ADDR);
4341 	if (max_plen != 0 && max_plen < prefixlen)
4342 		return (BAD_ADDR);
4343 	return (prefixlen);
4344 }
4345 
4346 /*
4347  * Convert a prefix length to a mask.
4348  * Returns 1 if ok. 0 otherwise.
4349  * Assumes the mask array is zero'ed by the caller.
4350  */
4351 static boolean_t
4352 in_prefixlentomask(int prefixlen, int maxlen, uchar_t *mask)
4353 {
4354 	if (prefixlen < 0 || prefixlen > maxlen)
4355 		return (0);
4356 
4357 	while (prefixlen > 0) {
4358 		if (prefixlen >= 8) {
4359 			*mask++ = 0xFF;
4360 			prefixlen -= 8;
4361 			continue;
4362 		}
4363 		*mask |= 1 << (8 - prefixlen);
4364 		prefixlen--;
4365 	}
4366 	return (1);
4367 }
4368 
4369 static void
4370 print_flags(uint64_t flags)
4371 {
4372 	boolean_t first = _B_TRUE;
4373 	int cnt, i;
4374 
4375 	(void) printf("flags=%llx", flags);
4376 	cnt = sizeof (if_flags_tbl) / sizeof (if_flags_t);
4377 	for (i = 0; i < cnt; i++) {
4378 		if (flags & if_flags_tbl[i].iff_value) {
4379 			if (first) {
4380 				(void) printf("<");
4381 				first = _B_FALSE;
4382 			} else {
4383 				/*
4384 				 * It has to be here and not with the
4385 				 * printf below because for the last one,
4386 				 * we don't want a comma before the ">".
4387 				 */
4388 				(void) printf(",");
4389 			}
4390 			(void) printf("%s", if_flags_tbl[i].iff_name);
4391 		}
4392 	}
4393 	if (!first)
4394 		(void) printf(">");
4395 }
4396 
4397 static void
4398 print_config_flags(uint64_t flags)
4399 {
4400 	int cnt, i;
4401 
4402 	cnt = sizeof (if_config_cmd_tbl) / sizeof (if_config_cmd_t);
4403 	for (i = 0; i < cnt; i++) {
4404 		if (flags & if_config_cmd_tbl[i].iff_flag) {
4405 			(void) printf("%s ", if_config_cmd_tbl[i].iff_name);
4406 		}
4407 	}
4408 }
4409 
4410 /*
4411  * Look in the NIS for the network mask.
4412  * returns true if we found one to set.
4413  */
4414 static boolean_t
4415 in_getmask(struct sockaddr_in *saddr)
4416 {
4417 	struct sockaddr_in ifaddr;
4418 
4419 	/*
4420 	 * Read the address from the interface
4421 	 */
4422 	(void) strncpy(lifr.lifr_name, name, sizeof (lifr.lifr_name));
4423 	if (ioctl(s, SIOCGLIFADDR, (caddr_t)&lifr) < 0) {
4424 		if (errno != EADDRNOTAVAIL)
4425 			(void) fprintf(stderr, "Need net number for mask\n");
4426 		return (_B_FALSE);
4427 	}
4428 	ifaddr = *((struct sockaddr_in *)&lifr.lifr_addr);
4429 	if (getnetmaskbyaddr(ifaddr.sin_addr, &saddr->sin_addr) == 0) {
4430 		saddr->sin_family = AF_INET;
4431 		(void) printf("Setting netmask of %s to %s\n", name,
4432 		    inet_ntoa(saddr->sin_addr));
4433 		return (_B_TRUE);
4434 	}
4435 	return (_B_FALSE);
4436 }
4437 
4438 static int
4439 strioctl(int s, int cmd, char *buf, int buflen)
4440 {
4441 	struct strioctl ioc;
4442 
4443 	(void) memset(&ioc, 0, sizeof (ioc));
4444 	ioc.ic_cmd = cmd;
4445 	ioc.ic_timout = 0;
4446 	ioc.ic_len = buflen;
4447 	ioc.ic_dp = buf;
4448 	return (ioctl(s, I_STR, (char *)&ioc));
4449 }
4450 
4451 static void
4452 add_ni(char *name)
4453 {
4454 	ni_t **pp;
4455 	ni_t *p;
4456 
4457 	for (pp = &ni_list; (p = *pp) != NULL; pp = &(p->ni_next)) {
4458 		if (strcmp(p->ni_name, name) == 0) {
4459 			if (debug > 2)
4460 				(void) fprintf(stderr, "'%s' is a duplicate\n",
4461 				    name);
4462 			return;
4463 		}
4464 	}
4465 
4466 	if (debug > 2)
4467 		(void) fprintf(stderr, "adding '%s'\n",
4468 		    name);
4469 
4470 	if ((p = malloc(sizeof (ni_t))) == NULL)
4471 		return;
4472 
4473 	(void) strlcpy(p->ni_name, name, sizeof (p->ni_name));
4474 	p->ni_next = NULL;
4475 
4476 	*pp = p;
4477 	num_ni++;
4478 }
4479 
4480 /* ARGSUSED2 */
4481 static int
4482 devfs_entry(di_node_t node, di_minor_t minor, void *arg)
4483 {
4484 	char *provider;
4485 	int fd;
4486 	uint_t ppa;
4487 	dl_info_ack_t dlia;
4488 	char ifname[LIFNAMSIZ];
4489 
4490 	provider = di_minor_name(minor);
4491 
4492 	if (strlen(provider) > LIFNAMSIZ)
4493 		return (DI_WALK_CONTINUE);
4494 
4495 	if (debug > 2)
4496 		fprintf(stderr, "provider = %s\n", provider);
4497 
4498 	if ((fd = dlpi_open(provider)) < 0)
4499 		return (DI_WALK_CONTINUE);
4500 
4501 	if (debug > 2)
4502 		fprintf(stderr, "getting DL_INFO_ACK\n");
4503 
4504 	if (dlpi_info(fd, -1, &dlia, NULL, NULL, NULL, NULL, NULL, NULL) < 0)
4505 		goto done;
4506 
4507 	if (dlia.dl_provider_style == DL_STYLE1) {
4508 		if (debug > 2)
4509 			fprintf(stderr, "provider is DL_STYLE1\n");
4510 		add_ni(provider);
4511 		goto done;
4512 	}
4513 
4514 	if (debug > 2)
4515 		fprintf(stderr, "provider is DL_STYLE2\n");
4516 
4517 	if (di_minor_type(minor) != DDM_ALIAS) {
4518 		if (debug > 2)
4519 			(void) fprintf(stderr,
4520 			    "non-alias node, ignoring\n");
4521 		goto done;
4522 	}
4523 
4524 	if (debug > 2)
4525 		(void) fprintf(stderr,
4526 		    "alias node, using instance\n");
4527 	ppa = di_instance(node);
4528 
4529 	if (dlpi_attach(fd, -1, ppa) < 0) {
4530 		if (debug > 2)
4531 			(void) fprintf(stderr,
4532 			    "non-existent PPA, ignoring\n");
4533 		goto done;
4534 	}
4535 
4536 	(void) snprintf(ifname, LIFNAMSIZ, "%s%d", provider, ppa);
4537 	add_ni(ifname);
4538 
4539 done:
4540 	(void) dlpi_close(fd);
4541 	return (DI_WALK_CONTINUE);
4542 }
4543 
4544 /*
4545  * dhcp-related routines
4546  */
4547 
4548 static int
4549 setifdhcp(const char *caller, const char *ifname, int argc, char *argv[])
4550 {
4551 	dhcp_ipc_request_t	*request;
4552 	dhcp_ipc_reply_t	*reply	= NULL;
4553 	int			timeout = DHCP_IPC_WAIT_DEFAULT;
4554 	dhcp_ipc_type_t		type	= DHCP_START;
4555 	int			error;
4556 	boolean_t		is_primary = _B_FALSE;
4557 	boolean_t		started = _B_FALSE;
4558 
4559 	for (argv++; --argc > 0; argv++) {
4560 
4561 		if (strcmp(*argv, "primary") == 0) {
4562 			is_primary = _B_TRUE;
4563 			continue;
4564 		}
4565 
4566 		if (strcmp(*argv, "wait") == 0) {
4567 			if (--argc <= 0) {
4568 				usage();
4569 				return (DHCP_EXIT_BADARGS);
4570 			}
4571 			argv++;
4572 
4573 			if (strcmp(*argv, "forever") == 0) {
4574 				timeout = DHCP_IPC_WAIT_FOREVER;
4575 				continue;
4576 			}
4577 
4578 			if (sscanf(*argv, "%d", &timeout) != 1) {
4579 				usage();
4580 				return (DHCP_EXIT_BADARGS);
4581 			}
4582 
4583 			if (timeout < 0) {
4584 				usage();
4585 				return (DHCP_EXIT_BADARGS);
4586 			}
4587 			continue;
4588 		}
4589 
4590 		type = dhcp_string_to_request(*argv);
4591 		if (type == -1) {
4592 			usage();
4593 			return (DHCP_EXIT_BADARGS);
4594 		}
4595 	}
4596 
4597 	/*
4598 	 * Only try to start agent on start or inform; in all other cases it
4599 	 * has to already be running for anything to make sense.
4600 	 */
4601 	if (type == DHCP_START || type == DHCP_INFORM) {
4602 		if (dhcp_start_agent(DHCP_IPC_MAX_WAIT) == -1) {
4603 			(void) fprintf(stderr, "%s: unable to start %s\n",
4604 			    caller, DHCP_AGENT_PATH);
4605 			return (DHCP_EXIT_FAILURE);
4606 		}
4607 		started = _B_TRUE;
4608 	}
4609 
4610 	if (is_primary)
4611 		type = type | DHCP_PRIMARY;
4612 
4613 	request = dhcp_ipc_alloc_request(type, ifname, NULL, 0, DHCP_TYPE_NONE);
4614 	if (request == NULL) {
4615 		(void) fprintf(stderr, "%s: out of memory\n", caller);
4616 		return (DHCP_EXIT_SYSTEM);
4617 	}
4618 
4619 	error = dhcp_ipc_make_request(request, &reply, timeout);
4620 	if (error != 0) {
4621 		free(request);
4622 		/*
4623 		 * Re-map connect error to not under control if we didn't try a
4624 		 * start operation, as this has to be true and results in a
4625 		 * clearer message, not to mention preserving compatibility
4626 		 * with the days when we always started dhcpagent for every
4627 		 * request.
4628 		 */
4629 		if (error == DHCP_IPC_E_CONNECT && !started)
4630 			error = DHCP_IPC_E_UNKIF;
4631 		(void) fprintf(stderr, "%s: %s: %s\n", caller, ifname,
4632 		    dhcp_ipc_strerror(error));
4633 		return (DHCP_EXIT_FAILURE);
4634 	}
4635 
4636 	error = reply->return_code;
4637 	if (error != 0) {
4638 		free(request);
4639 		free(reply);
4640 
4641 		if (error == DHCP_IPC_E_TIMEOUT && timeout == 0)
4642 			return (DHCP_EXIT_SUCCESS);
4643 
4644 		(void) fprintf(stderr, "%s: %s: %s\n", caller, ifname,
4645 		    dhcp_ipc_strerror(error));
4646 
4647 		if (error == DHCP_IPC_E_TIMEOUT)
4648 			return (DHCP_EXIT_TIMEOUT);
4649 		else
4650 			return (DHCP_EXIT_IF_FAILURE);
4651 	}
4652 
4653 	if (DHCP_IPC_CMD(type) == DHCP_STATUS) {
4654 		(void) printf("%s", dhcp_status_hdr_string());
4655 		(void) printf("%s", dhcp_status_reply_to_string(reply));
4656 	}
4657 
4658 	free(request);
4659 	free(reply);
4660 	return (DHCP_EXIT_SUCCESS);
4661 }
4662 
4663 static void
4664 usage(void)
4665 {
4666 	(void) fprintf(stderr,
4667 	    "usage: ifconfig <interface> | -a[ 4 | 6 | D ][ u | d ][ Z ]\n");
4668 
4669 	(void) fprintf(stderr, "%s",
4670 	    "\t[ <addr_family> ]\n"
4671 	    "\t[ <address>[/<prefix_length>] [ <dest_address> ] ]\n"
4672 	    "\t[ set [ <address>][/<prefix_length>] ]"
4673 	    " [ <address>/<prefix_length>] ]\n"
4674 	    "\t[ destination <dest_address> ]\n"
4675 	    "\t[ addif <address>[/<prefix_length>]"
4676 	    "  [ <dest_address> ] ]\n"
4677 	    "\t[ removeif <address>[/<prefix_length>] ]\n"
4678 	    "\t[ arp | -arp ]\n"
4679 	    "\t[ auto-revarp ]\n"
4680 	    "\t[ broadcast <broad_addr> ]\n"
4681 	    "\t[ index <if_index> ]\n"
4682 	    "\t[ metric <n> ] [ mtu <n> ]\n"
4683 	    "\t[ netmask <mask> ]\n"
4684 	    "\t[ plumb ] [ unplumb ]\n"
4685 	    "\t[ preferred | -preferred ]\n"
4686 	    "\t[ private | -private ]\n"
4687 	    "\t[ local | -local ]\n"
4688 	    "\t[ router | -router ]\n"
4689 	    "\t[ subnet <subnet_address>]\n"
4690 	    "\t[ trailers | -trailers ]\n"
4691 	    "\t[ token <address>/<prefix_length> ]\n"
4692 	    "\t[ tsrc <tunnel_src_address> ]\n"
4693 	    "\t[ tdst <tunnel_dest_address> ]\n"
4694 	    "\t[ auth_algs <tunnel_AH_authentication_algorithm> ]\n"
4695 	    "\t[ encr_algs <tunnel_ESP_encryption_algorithm> ]\n"
4696 	    "\t[ encr_auth_algs <tunnel_ESP_authentication_algorithm> ]\n"
4697 	    "\t[ up ] [ down ]\n"
4698 	    "\t[ xmit | -xmit ]\n"
4699 	    "\t[ modlist ]\n"
4700 	    "\t[ modinsert <module_name@position> ]\n"
4701 	    "\t[ modremove <module_name@position> ]\n"
4702 	    "\t[ group <groupname>] | [ group \"\"]\n"
4703 	    "\t[ deprecated | -deprecated ]\n"
4704 	    "\t[ standby | -standby ]\n"
4705 	    "\t[ failover | -failover ]\n"
4706 	    "\t[ zone <zonename> | -zone ]\n"
4707 	    "\t[ usesrc <interface> ]\n");
4708 
4709 	(void) fprintf(stderr, "or\n");
4710 	(void) fprintf(stderr,
4711 	    "\tifconfig <interface> |  -a[ 4 | 6 | D ] [ u | d ]\n");
4712 
4713 	(void) fprintf(stderr, "%s", "\tauto-dhcp | dhcp\n"
4714 	    "\t[ wait <time> | forever ]\n\t[ primary ]\n"
4715 	    "\tstart | drop | ping | release | status | inform\n");
4716 }
4717