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