xref: /illumos-gate/usr/src/cmd/cmd-inet/usr.sbin/ipadm/ipadm.c (revision c81a25e9d3950dc5fab08d21f8be56d463b32c7a)
1 /*
2  * CDDL HEADER START
3  *
4  * The contents of this file are subject to the terms of the
5  * Common Development and Distribution License (the "License").
6  * You may not use this file except in compliance with the License.
7  *
8  * You can obtain a copy of the license at usr/src/OPENSOLARIS.LICENSE
9  * or http://www.opensolaris.org/os/licensing.
10  * See the License for the specific language governing permissions
11  * and limitations under the License.
12  *
13  * When distributing Covered Code, include this CDDL HEADER in each
14  * file and include the License file at usr/src/OPENSOLARIS.LICENSE.
15  * If applicable, add the following below this CDDL HEADER, with the
16  * fields enclosed by brackets "[]" replaced with your own identifying
17  * information: Portions Copyright [yyyy] [name of copyright owner]
18  *
19  * CDDL HEADER END
20  */
21 
22 /*
23  * Copyright (c) 2010, Oracle and/or its affiliates. All rights reserved.
24  * Copyright 2017 Nexenta Systems, Inc.
25  * Copyright 2017 Gary Mills
26  */
27 
28 #include <arpa/inet.h>
29 #include <errno.h>
30 #include <getopt.h>
31 #include <inet/ip.h>
32 #include <inet/iptun.h>
33 #include <inet/tunables.h>
34 #include <libdladm.h>
35 #include <libdliptun.h>
36 #include <libdllink.h>
37 #include <libinetutil.h>
38 #include <libipadm.h>
39 #include <locale.h>
40 #include <netdb.h>
41 #include <netinet/in.h>
42 #include <ofmt.h>
43 #include <stdarg.h>
44 #include <stddef.h>
45 #include <stdio.h>
46 #include <stdlib.h>
47 #include <string.h>
48 #include <strings.h>
49 #include <sys/stat.h>
50 #include <sys/types.h>
51 #include <zone.h>
52 
53 #define	STR_UNKNOWN_VAL	"?"
54 #define	LIFC_DEFAULT	(LIFC_NOXMIT | LIFC_TEMPORARY | LIFC_ALLZONES |\
55 			LIFC_UNDER_IPMP)
56 
57 typedef void cmdfunc_t(int, char **, const char *);
58 static cmdfunc_t do_create_if, do_delete_if, do_enable_if, do_disable_if;
59 static cmdfunc_t do_show_if;
60 static cmdfunc_t do_set_prop, do_show_prop, do_set_ifprop;
61 static cmdfunc_t do_show_ifprop, do_reset_ifprop, do_reset_prop;
62 static cmdfunc_t do_show_addrprop, do_set_addrprop, do_reset_addrprop;
63 static cmdfunc_t do_create_addr, do_delete_addr, do_show_addr;
64 static cmdfunc_t do_enable_addr, do_disable_addr;
65 static cmdfunc_t do_up_addr, do_down_addr, do_refresh_addr;
66 
67 typedef struct	cmd {
68 	char		*c_name;
69 	cmdfunc_t	*c_fn;
70 	const char	*c_usage;
71 } cmd_t;
72 
73 static cmd_t	cmds[] = {
74 	/* interface management related sub-commands */
75 	{ "create-if",	do_create_if,	"\tcreate-if\t[-t] <interface>"	},
76 	{ "disable-if",	do_disable_if,	"\tdisable-if\t-t <interface>"	},
77 	{ "enable-if",	do_enable_if,	"\tenable-if\t-t <interface>"	},
78 	{ "delete-if",	do_delete_if,	"\tdelete-if\t<interface>"	},
79 	{ "show-if",	do_show_if,
80 	    "\tshow-if\t\t[[-p] -o <field>,...] [<interface>]\n"	},
81 	{ "set-ifprop",	do_set_ifprop,
82 	    "\tset-ifprop\t[-t] -p <prop>=<value[,...]> -m <protocol> "
83 	    "<interface>" 						},
84 	{ "reset-ifprop", do_reset_ifprop,
85 	    "\treset-ifprop\t[-t] -p <prop> -m <protocol> <interface>"	},
86 	{ "show-ifprop", do_show_ifprop,
87 	    "\tshow-ifprop\t[[-c] -o <field>,...] [-p <prop>,...]\n"
88 	    "\t\t\t[-m <protocol>] [interface]\n" 			},
89 
90 	/* address management related sub-commands */
91 	{ "create-addr", do_create_addr,
92 	    "\tcreate-addr\t[-t] -T static [-d] "
93 	    "-a{local|remote}=addr[/prefixlen]\n\t\t\t<addrobj>\n"
94 	    "\tcreate-addr\t[-t] -T dhcp [-w <seconds> | forever] <addrobj>\n"
95 	    "\tcreate-addr\t[-t] -T addrconf [-i interface-id]\n"
96 	    "\t\t\t[-p {stateful|stateless}={yes|no}] <addrobj>" },
97 	{ "down-addr",	do_down_addr,	"\tdown-addr\t[-t] <addrobj>"	},
98 	{ "up-addr",	do_up_addr,	"\tup-addr\t\t[-t] <addrobj>"	},
99 	{ "disable-addr", do_disable_addr, "\tdisable-addr\t-t <addrobj>" },
100 	{ "enable-addr", do_enable_addr, "\tenable-addr\t-t <addrobj>"	},
101 	{ "refresh-addr", do_refresh_addr, "\trefresh-addr\t[-i] <addrobj>" },
102 	{ "delete-addr", do_delete_addr, "\tdelete-addr\t[-r] <addrobj>" },
103 	{ "show-addr",	do_show_addr,
104 	    "\tshow-addr\t[[-p] -o <field>,...] [<addrobj>]\n"		},
105 	{ "set-addrprop", do_set_addrprop,
106 	    "\tset-addrprop\t[-t] -p <prop>=<value[,...]> <addrobj>"	},
107 	{ "reset-addrprop", do_reset_addrprop,
108 	    "\treset-addrprop\t[-t] -p <prop> <addrobj>"		},
109 	{ "show-addrprop", do_show_addrprop,
110 	    "\tshow-addrprop\t[[-c] -o <field>,...] [-p <prop>,...] "
111 	    "<addrobj>\n" 						},
112 
113 	/* protocol properties related sub-commands */
114 	{ "set-prop",	do_set_prop,
115 	    "\tset-prop\t[-t] -p <prop>[+|-]=<value[,...]> <protocol>"	},
116 	{ "reset-prop",	do_reset_prop,
117 	    "\treset-prop\t[-t] -p <prop> <protocol>"			},
118 	{ "show-prop",	do_show_prop,
119 	    "\tshow-prop\t[[-c] -o <field>,...] [-p <prop>,...]"
120 	    " [protocol]"						}
121 };
122 
123 static const struct option if_longopts[] = {
124 	{"temporary",	no_argument,		0, 't'	},
125 	{ 0, 0, 0, 0 }
126 };
127 
128 static const struct option show_prop_longopts[] = {
129 	{"parsable",	no_argument,		0, 'c'	},
130 	{"prop",	required_argument,	0, 'p'	},
131 	{"output",	required_argument,	0, 'o'	},
132 	{ 0, 0, 0, 0 }
133 };
134 
135 static const struct option show_ifprop_longopts[] = {
136 	{"module",	required_argument,	0, 'm'	},
137 	{"parsable",	no_argument,		0, 'c'	},
138 	{"prop",	required_argument,	0, 'p'	},
139 	{"output",	required_argument,	0, 'o'	},
140 	{ 0, 0, 0, 0 }
141 };
142 
143 static const struct option set_prop_longopts[] = {
144 	{"prop",	required_argument,	0, 'p'	},
145 	{"temporary",	no_argument,		0, 't'	},
146 	{ 0, 0, 0, 0 }
147 };
148 
149 static const struct option set_ifprop_longopts[] = {
150 	{"module",	required_argument,	0, 'm'	},
151 	{"prop",	required_argument,	0, 'p'	},
152 	{"temporary",	no_argument,		0, 't'	},
153 	{ 0, 0, 0, 0 }
154 };
155 
156 static const struct option addr_misc_longopts[] = {
157 	{"inform",	no_argument,		0, 'i'	},
158 	{"release",	no_argument,		0, 'r'	},
159 	{"temporary",	no_argument,		0, 't'	},
160 	{ 0, 0, 0, 0 }
161 };
162 
163 static const struct option addr_longopts[] = {
164 	{"address",	required_argument,	0, 'a'	},
165 	{"down",	no_argument,		0, 'd'	},
166 	{"interface-id", required_argument,	0, 'i'	},
167 	{"prop",	required_argument,	0, 'p'	},
168 	{"temporary",	no_argument,		0, 't'	},
169 	{"type",	required_argument,	0, 'T'	},
170 	{"wait",	required_argument,	0, 'w'	},
171 	{ 0, 0, 0, 0 }
172 };
173 
174 static const struct option show_addr_longopts[] = {
175 	{"parsable",	no_argument,		0, 'p'	},
176 	{"output",	required_argument,	0, 'o'	},
177 	{ 0, 0, 0, 0 }
178 };
179 
180 static const struct option show_if_longopts[] = {
181 	{"parsable",	no_argument,		0, 'p'	},
182 	{"output",	required_argument,	0, 'o'	},
183 	{ 0, 0, 0, 0 }
184 };
185 
186 /* callback functions to print show-* subcommands output */
187 static ofmt_cb_t print_prop_cb;
188 static ofmt_cb_t print_sa_cb;
189 static ofmt_cb_t print_si_cb;
190 
191 /* structures for 'ipadm show-*' subcommands */
192 typedef enum {
193 	IPADM_PROPFIELD_IFNAME,
194 	IPADM_PROPFIELD_PROTO,
195 	IPADM_PROPFIELD_ADDROBJ,
196 	IPADM_PROPFIELD_PROPERTY,
197 	IPADM_PROPFIELD_PERM,
198 	IPADM_PROPFIELD_CURRENT,
199 	IPADM_PROPFIELD_PERSISTENT,
200 	IPADM_PROPFIELD_DEFAULT,
201 	IPADM_PROPFIELD_POSSIBLE
202 } ipadm_propfield_index_t;
203 
204 static ofmt_field_t intfprop_fields[] = {
205 /* name,	field width,	index,			callback */
206 { "IFNAME",	12,	IPADM_PROPFIELD_IFNAME,		print_prop_cb},
207 { "PROPERTY",	16,	IPADM_PROPFIELD_PROPERTY,	print_prop_cb},
208 { "PROTO",	6,	IPADM_PROPFIELD_PROTO,		print_prop_cb},
209 { "PERM",	5,	IPADM_PROPFIELD_PERM,		print_prop_cb},
210 { "CURRENT",	11,	IPADM_PROPFIELD_CURRENT,	print_prop_cb},
211 { "PERSISTENT",	11,	IPADM_PROPFIELD_PERSISTENT,	print_prop_cb},
212 { "DEFAULT",	11,	IPADM_PROPFIELD_DEFAULT,	print_prop_cb},
213 { "POSSIBLE",	16,	IPADM_PROPFIELD_POSSIBLE,	print_prop_cb},
214 { NULL,		0,	0,				NULL}
215 };
216 
217 
218 static ofmt_field_t modprop_fields[] = {
219 /* name,	field width,	index,			callback */
220 { "PROTO",	6,	IPADM_PROPFIELD_PROTO,		print_prop_cb},
221 { "PROPERTY",	22,	IPADM_PROPFIELD_PROPERTY,	print_prop_cb},
222 { "PERM",	5,	IPADM_PROPFIELD_PERM,		print_prop_cb},
223 { "CURRENT",	13,	IPADM_PROPFIELD_CURRENT,	print_prop_cb},
224 { "PERSISTENT",	13,	IPADM_PROPFIELD_PERSISTENT,	print_prop_cb},
225 { "DEFAULT",	13,	IPADM_PROPFIELD_DEFAULT,	print_prop_cb},
226 { "POSSIBLE",	15,	IPADM_PROPFIELD_POSSIBLE,	print_prop_cb},
227 { NULL,		0,	0,				NULL}
228 };
229 
230 static ofmt_field_t addrprop_fields[] = {
231 /* name,	field width,	index,			callback */
232 { "ADDROBJ",	18,	IPADM_PROPFIELD_ADDROBJ,	print_prop_cb},
233 { "PROPERTY",	11,	IPADM_PROPFIELD_PROPERTY,	print_prop_cb},
234 { "PERM",	5,	IPADM_PROPFIELD_PERM,		print_prop_cb},
235 { "CURRENT",	16,	IPADM_PROPFIELD_CURRENT,	print_prop_cb},
236 { "PERSISTENT",	16,	IPADM_PROPFIELD_PERSISTENT,	print_prop_cb},
237 { "DEFAULT",	16,	IPADM_PROPFIELD_DEFAULT,	print_prop_cb},
238 { "POSSIBLE",	15,	IPADM_PROPFIELD_POSSIBLE,	print_prop_cb},
239 { NULL,		0,	0,				NULL}
240 };
241 
242 typedef struct show_prop_state {
243 	char		sps_ifname[LIFNAMSIZ];
244 	char		sps_aobjname[IPADM_AOBJSIZ];
245 	const char	*sps_pname;
246 	uint_t		sps_proto;
247 	char		*sps_propval;
248 	nvlist_t	*sps_proplist;
249 	boolean_t	sps_parsable;
250 	boolean_t	sps_addrprop;
251 	boolean_t	sps_ifprop;
252 	boolean_t	sps_modprop;
253 	ipadm_status_t	sps_status;
254 	ipadm_status_t	sps_retstatus;
255 	ofmt_handle_t	sps_ofmt;
256 } show_prop_state_t;
257 
258 typedef struct show_addr_state {
259 	boolean_t	sa_parsable;
260 	boolean_t	sa_persist;
261 	ofmt_handle_t	sa_ofmt;
262 } show_addr_state_t;
263 
264 typedef struct show_if_state {
265 	boolean_t	si_parsable;
266 	ofmt_handle_t	si_ofmt;
267 } show_if_state_t;
268 
269 typedef struct show_addr_args_s {
270 	show_addr_state_t	*sa_state;
271 	ipadm_addr_info_t	*sa_info;
272 } show_addr_args_t;
273 
274 typedef struct show_if_args_s {
275 	show_if_state_t *si_state;
276 	ipadm_if_info_t *si_info;
277 } show_if_args_t;
278 
279 typedef enum {
280 	SA_ADDROBJ,
281 	SA_TYPE,
282 	SA_STATE,
283 	SA_CURRENT,
284 	SA_PERSISTENT,
285 	SA_ADDR
286 } sa_field_index_t;
287 
288 typedef enum {
289 	SI_IFNAME,
290 	SI_STATE,
291 	SI_CURRENT,
292 	SI_PERSISTENT
293 } si_field_index_t;
294 
295 static ofmt_field_t show_addr_fields[] = {
296 /* name,	field width,	id,		callback */
297 { "ADDROBJ",	18,		SA_ADDROBJ,	print_sa_cb},
298 { "TYPE",	9,		SA_TYPE,	print_sa_cb},
299 { "STATE",	13,		SA_STATE,	print_sa_cb},
300 { "CURRENT",	8,		SA_CURRENT,	print_sa_cb},
301 { "PERSISTENT",	11,		SA_PERSISTENT,	print_sa_cb},
302 { "ADDR",	46,		SA_ADDR,	print_sa_cb},
303 { NULL,		0,		0,		NULL}
304 };
305 
306 static ofmt_field_t show_if_fields[] = {
307 /* name,	field width,	id,		callback */
308 { "IFNAME",	11,		SI_IFNAME,	print_si_cb},
309 { "STATE",	9,		SI_STATE,	print_si_cb},
310 { "CURRENT",	13,		SI_CURRENT,	print_si_cb},
311 { "PERSISTENT",	11,		SI_PERSISTENT,	print_si_cb},
312 { NULL,		0,		0,		NULL}
313 };
314 
315 #define	IPADM_ALL_BITS	((uint_t)-1)
316 typedef struct intf_mask {
317 	char		*name;
318 	uint64_t	bits;
319 	uint64_t	mask;
320 } fmask_t;
321 
322 /*
323  * Handle to libipadm. Opened in main() before the sub-command specific
324  * function is called and is closed before the program exits.
325  */
326 ipadm_handle_t	iph = NULL;
327 
328 /*
329  * Opaque ipadm address object. Used by all the address management subcommands.
330  */
331 ipadm_addrobj_t	ipaddr = NULL;
332 
333 static char *progname;
334 
335 static void	die(const char *, ...);
336 static void	die_opterr(int, int, const char *);
337 static void	warn_ipadmerr(ipadm_status_t, const char *, ...);
338 static void 	ipadm_ofmt_check(ofmt_status_t, boolean_t, ofmt_handle_t);
339 static void 	ipadm_check_propstr(const char *, boolean_t, const char *);
340 static void 	process_misc_addrargs(int, char **, const char *, int *,
341 		    uint32_t *);
342 
343 static void
344 usage(void)
345 {
346 	int	i;
347 	cmd_t	*cmdp;
348 
349 	(void) fprintf(stderr,
350 	    gettext("usage:  ipadm <subcommand> <args> ...\n"));
351 	for (i = 0; i < sizeof (cmds) / sizeof (cmds[0]); i++) {
352 		cmdp = &cmds[i];
353 		if (cmdp->c_usage != NULL)
354 			(void) fprintf(stderr, "%s\n", gettext(cmdp->c_usage));
355 	}
356 
357 	ipadm_destroy_addrobj(ipaddr);
358 	ipadm_close(iph);
359 	exit(1);
360 }
361 
362 int
363 main(int argc, char *argv[])
364 {
365 	int	i;
366 	cmd_t	*cmdp;
367 	ipadm_status_t status;
368 
369 	(void) setlocale(LC_ALL, "");
370 	(void) textdomain(TEXT_DOMAIN);
371 
372 	if ((progname = strrchr(argv[0], '/')) == NULL)
373 		progname = argv[0];
374 	else
375 		progname++;
376 
377 	if (argc < 2)
378 		usage();
379 
380 	status = ipadm_open(&iph, 0);
381 	if (status != IPADM_SUCCESS) {
382 		die("Could not open handle to library - %s",
383 		    ipadm_status2str(status));
384 	}
385 
386 	for (i = 0; i < sizeof (cmds) / sizeof (cmds[0]); i++) {
387 		cmdp = &cmds[i];
388 		if (strcmp(argv[1], cmdp->c_name) == 0) {
389 			cmdp->c_fn(argc - 1, &argv[1], gettext(cmdp->c_usage));
390 			ipadm_destroy_addrobj(ipaddr);
391 			ipadm_close(iph);
392 			exit(0);
393 		}
394 	}
395 
396 	(void) fprintf(stderr, gettext("%s: unknown subcommand '%s'\n"),
397 	    progname, argv[1]);
398 	usage();
399 
400 	return (0);
401 }
402 
403 /*
404  * Create an IP interface for which no saved configuration exists in the
405  * persistent store.
406  */
407 static void
408 do_create_if(int argc, char *argv[], const char *use)
409 {
410 	ipadm_status_t	status;
411 	int		option;
412 	uint32_t	flags = IPADM_OPT_PERSIST|IPADM_OPT_ACTIVE;
413 
414 	opterr = 0;
415 	while ((option = getopt_long(argc, argv, ":t", if_longopts,
416 	    NULL)) != -1) {
417 		switch (option) {
418 		case 't':
419 			/*
420 			 * "ifconfig" mode - plumb interface, but do not
421 			 * restore settings that may exist in db.
422 			 */
423 			flags &= ~IPADM_OPT_PERSIST;
424 			break;
425 		default:
426 			die_opterr(optopt, option, use);
427 		}
428 	}
429 	if (optind != (argc - 1))
430 		die("Usage: %s", use);
431 	status = ipadm_create_if(iph, argv[optind], AF_UNSPEC, flags);
432 	if (status != IPADM_SUCCESS) {
433 		die("Could not create %s : %s",
434 		    argv[optind], ipadm_status2str(status));
435 	}
436 }
437 
438 /*
439  * Enable an IP interface based on the persistent configuration for
440  * that interface.
441  */
442 static void
443 do_enable_if(int argc, char *argv[], const char *use)
444 {
445 	ipadm_status_t	status;
446 	int		index;
447 	uint32_t 	flags = IPADM_OPT_ACTIVE|IPADM_OPT_PERSIST;
448 
449 	process_misc_addrargs(argc, argv, use, &index, &flags);
450 	if (flags & IPADM_OPT_PERSIST)
451 		die("persistent operation not supported for enable-if");
452 	status = ipadm_enable_if(iph, argv[index], flags);
453 	if (status == IPADM_ALL_ADDRS_NOT_ENABLED) {
454 		warn_ipadmerr(status, "");
455 	} else if (status != IPADM_SUCCESS) {
456 		die("Could not enable %s : %s",
457 		    argv[optind], ipadm_status2str(status));
458 	}
459 }
460 
461 /*
462  * Remove an IP interface from both active and persistent configuration.
463  */
464 static void
465 do_delete_if(int argc, char *argv[], const char *use)
466 {
467 	ipadm_status_t	status;
468 	uint32_t	flags = IPADM_OPT_ACTIVE|IPADM_OPT_PERSIST;
469 
470 	if (argc != 2)
471 		die("Usage: %s", use);
472 
473 	status = ipadm_delete_if(iph, argv[1], AF_UNSPEC, flags);
474 	if (status != IPADM_SUCCESS) {
475 		die("Could not delete %s: %s",
476 		    argv[optind], ipadm_status2str(status));
477 	}
478 }
479 
480 /*
481  * Disable an IP interface by removing it from active configuration.
482  */
483 static void
484 do_disable_if(int argc, char *argv[], const char *use)
485 {
486 	ipadm_status_t	status;
487 	int		index;
488 	uint32_t 	flags = IPADM_OPT_ACTIVE|IPADM_OPT_PERSIST;
489 
490 	process_misc_addrargs(argc, argv, use, &index, &flags);
491 	if (flags & IPADM_OPT_PERSIST)
492 		die("persistent operation not supported for disable-if");
493 	status = ipadm_disable_if(iph, argv[index], flags);
494 	if (status != IPADM_SUCCESS) {
495 		die("Could not disable %s: %s",
496 		    argv[optind], ipadm_status2str(status));
497 	}
498 }
499 
500 /*
501  * Print individual columns for the show-*prop subcommands.
502  */
503 static void
504 print_prop(show_prop_state_t *statep, uint_t flags, char *buf, size_t bufsize)
505 {
506 	const char		*prop_name = statep->sps_pname;
507 	char			*ifname = statep->sps_ifname;
508 	char			*propval = statep->sps_propval;
509 	uint_t			proto = statep->sps_proto;
510 	size_t			propsize = MAXPROPVALLEN;
511 	ipadm_status_t		status;
512 
513 	if (statep->sps_ifprop) {
514 		status = ipadm_get_ifprop(iph, ifname, prop_name, propval,
515 		    &propsize, proto, flags);
516 	} else if (statep->sps_modprop) {
517 		status = ipadm_get_prop(iph, prop_name, propval, &propsize,
518 		    proto, flags);
519 	} else {
520 		status = ipadm_get_addrprop(iph, prop_name, propval, &propsize,
521 		    statep->sps_aobjname, flags);
522 	}
523 
524 	if (status != IPADM_SUCCESS) {
525 		if ((status == IPADM_NOTFOUND && (flags & IPADM_OPT_PERSIST)) ||
526 		    status == IPADM_ENXIO) {
527 			propval[0] = '\0';
528 			goto cont;
529 		}
530 		statep->sps_status = status;
531 		statep->sps_retstatus = status;
532 		return;
533 	}
534 cont:
535 	statep->sps_status = IPADM_SUCCESS;
536 	(void) snprintf(buf, bufsize, "%s", propval);
537 }
538 
539 /*
540  * Callback function for show-*prop subcommands.
541  */
542 static boolean_t
543 print_prop_cb(ofmt_arg_t *ofarg, char *buf, size_t bufsize)
544 {
545 	show_prop_state_t	*statep = ofarg->ofmt_cbarg;
546 	const char		*propname = statep->sps_pname;
547 	uint_t			proto = statep->sps_proto;
548 	boolean_t		cont = _B_TRUE;
549 
550 	/*
551 	 * Fail retrieving remaining fields, if you fail
552 	 * to retrieve a field.
553 	 */
554 	if (statep->sps_status != IPADM_SUCCESS)
555 		return (_B_FALSE);
556 
557 	switch (ofarg->ofmt_id) {
558 	case IPADM_PROPFIELD_IFNAME:
559 		(void) snprintf(buf, bufsize, "%s", statep->sps_ifname);
560 		break;
561 	case IPADM_PROPFIELD_PROTO:
562 		(void) snprintf(buf, bufsize, "%s", ipadm_proto2str(proto));
563 		break;
564 	case IPADM_PROPFIELD_ADDROBJ:
565 		(void) snprintf(buf, bufsize, "%s", statep->sps_aobjname);
566 		break;
567 	case IPADM_PROPFIELD_PROPERTY:
568 		(void) snprintf(buf, bufsize, "%s", propname);
569 		break;
570 	case IPADM_PROPFIELD_PERM:
571 		print_prop(statep, IPADM_OPT_PERM, buf, bufsize);
572 		break;
573 	case IPADM_PROPFIELD_CURRENT:
574 		print_prop(statep, IPADM_OPT_ACTIVE, buf, bufsize);
575 		break;
576 	case IPADM_PROPFIELD_PERSISTENT:
577 		print_prop(statep, IPADM_OPT_PERSIST, buf, bufsize);
578 		break;
579 	case IPADM_PROPFIELD_DEFAULT:
580 		print_prop(statep, IPADM_OPT_DEFAULT, buf, bufsize);
581 		break;
582 	case IPADM_PROPFIELD_POSSIBLE:
583 		print_prop(statep, IPADM_OPT_POSSIBLE, buf, bufsize);
584 		break;
585 	}
586 	if (statep->sps_status != IPADM_SUCCESS)
587 		cont = _B_FALSE;
588 	return (cont);
589 }
590 
591 /*
592  * Callback function called by the property walker (ipadm_walk_prop() or
593  * ipadm_walk_proptbl()), for every matched property. This function in turn
594  * calls ofmt_print() to print property information.
595  */
596 boolean_t
597 show_property(void *arg, const char *pname, uint_t proto)
598 {
599 	show_prop_state_t	*statep = arg;
600 
601 	statep->sps_pname = pname;
602 	statep->sps_proto = proto;
603 	statep->sps_status = IPADM_SUCCESS;
604 	ofmt_print(statep->sps_ofmt, arg);
605 
606 	/*
607 	 * if an object is not found or operation is not supported then
608 	 * stop the walker.
609 	 */
610 	if (statep->sps_status == IPADM_NOTFOUND ||
611 	    statep->sps_status == IPADM_NOTSUP)
612 		return (_B_FALSE);
613 	return (_B_TRUE);
614 }
615 
616 /*
617  * Properties to be displayed is in `statep->sps_proplist'. If it is NULL,
618  * for all the properties for the specified object, relavant information, will
619  * be displayed. Otherwise, for the selected property set, display relevant
620  * information
621  */
622 static void
623 show_properties(void *arg, int prop_class)
624 {
625 	show_prop_state_t	*statep = arg;
626 	nvlist_t 		*nvl = statep->sps_proplist;
627 	uint_t			proto = statep->sps_proto;
628 	nvpair_t		*curr_nvp;
629 	char 			*buf, *name;
630 	ipadm_status_t		status;
631 
632 	/* allocate sufficient buffer to hold a property value */
633 	if ((buf = malloc(MAXPROPVALLEN)) == NULL)
634 		die("insufficient memory");
635 	statep->sps_propval = buf;
636 
637 	/* if no properties were specified, display all the properties */
638 	if (nvl == NULL) {
639 		(void) ipadm_walk_proptbl(proto, prop_class, show_property,
640 		    statep);
641 	} else {
642 		for (curr_nvp = nvlist_next_nvpair(nvl, NULL); curr_nvp;
643 		    curr_nvp = nvlist_next_nvpair(nvl, curr_nvp)) {
644 			name = nvpair_name(curr_nvp);
645 			status = ipadm_walk_prop(name, proto, prop_class,
646 			    show_property, statep);
647 			if (status == IPADM_PROP_UNKNOWN)
648 				(void) show_property(statep, name, proto);
649 		}
650 	}
651 
652 	free(buf);
653 }
654 
655 /*
656  * Display information for all or specific interface properties, either for a
657  * given interface or for all the interfaces in the system.
658  */
659 static void
660 do_show_ifprop(int argc, char **argv, const char *use)
661 {
662 	int 		option;
663 	nvlist_t 	*proplist = NULL;
664 	char		*fields_str = NULL;
665 	char 		*ifname;
666 	ofmt_handle_t	ofmt;
667 	ofmt_status_t	oferr;
668 	uint_t		ofmtflags = 0;
669 	uint_t		proto;
670 	boolean_t	m_arg = _B_FALSE;
671 	char		*protostr;
672 	ipadm_if_info_t	*ifinfo, *ifp;
673 	ipadm_status_t	status;
674 	show_prop_state_t state;
675 
676 	opterr = 0;
677 	bzero(&state, sizeof (state));
678 	state.sps_propval = NULL;
679 	state.sps_parsable = _B_FALSE;
680 	state.sps_ifprop = _B_TRUE;
681 	state.sps_status = state.sps_retstatus = IPADM_SUCCESS;
682 	while ((option = getopt_long(argc, argv, ":p:m:co:",
683 	    show_ifprop_longopts, NULL)) != -1) {
684 		switch (option) {
685 		case 'p':
686 			if (ipadm_str2nvlist(optarg, &proplist,
687 			    IPADM_NORVAL) != 0)
688 				die("invalid interface properties specified");
689 			break;
690 		case 'c':
691 			state.sps_parsable = _B_TRUE;
692 			break;
693 		case 'o':
694 			fields_str = optarg;
695 			break;
696 		case 'm':
697 			if (m_arg)
698 				die("cannot specify more than one -m");
699 			m_arg = _B_TRUE;
700 			protostr = optarg;
701 			break;
702 		default:
703 			die_opterr(optopt, option, use);
704 			break;
705 		}
706 	}
707 
708 	if (optind == argc - 1)
709 		ifname = argv[optind];
710 	else if (optind != argc)
711 		die("Usage: %s", use);
712 	else
713 		ifname = NULL;
714 
715 	if (!m_arg)
716 		protostr = "ip";
717 	if ((proto = ipadm_str2proto(protostr)) == MOD_PROTO_NONE)
718 		die("invalid protocol '%s' specified", protostr);
719 
720 	state.sps_proto = proto;
721 	state.sps_proplist = proplist;
722 
723 	if (state.sps_parsable)
724 		ofmtflags |= OFMT_PARSABLE;
725 	oferr = ofmt_open(fields_str, intfprop_fields, ofmtflags, 0, &ofmt);
726 	ipadm_ofmt_check(oferr, state.sps_parsable, ofmt);
727 	state.sps_ofmt = ofmt;
728 
729 	/* retrieve interface(s) and print the properties */
730 	status = ipadm_if_info(iph, ifname, &ifinfo, 0, LIFC_DEFAULT);
731 	if (ifname != NULL && status == IPADM_ENXIO)
732 		die("no such object '%s': %s", ifname,
733 		    ipadm_status2str(status));
734 	if (status != IPADM_SUCCESS)
735 		die("Error retrieving interface(s): %s",
736 		    ipadm_status2str(status));
737 	for (ifp = ifinfo; ifp; ifp = ifp->ifi_next) {
738 		(void) strlcpy(state.sps_ifname, ifp->ifi_name, LIFNAMSIZ);
739 		state.sps_proto = proto;
740 		show_properties(&state, IPADMPROP_CLASS_IF);
741 	}
742 	if (ifinfo)
743 		ipadm_free_if_info(ifinfo);
744 
745 	nvlist_free(proplist);
746 	ofmt_close(ofmt);
747 
748 	if (state.sps_retstatus != IPADM_SUCCESS) {
749 		ipadm_close(iph);
750 		exit(EXIT_FAILURE);
751 	}
752 }
753 
754 /*
755  * set/reset the interface property for a given interface.
756  */
757 static void
758 set_ifprop(int argc, char **argv, boolean_t reset, const char *use)
759 {
760 	int 			option;
761 	ipadm_status_t 		status = IPADM_SUCCESS;
762 	boolean_t 		p_arg = _B_FALSE;
763 	boolean_t		m_arg = _B_FALSE;
764 	char 			*ifname, *nv, *protostr;
765 	char			*prop_name, *prop_val;
766 	uint_t			flags = IPADM_OPT_PERSIST;
767 	uint_t			proto;
768 
769 	opterr = 0;
770 	while ((option = getopt_long(argc, argv, ":m:p:t",
771 	    set_ifprop_longopts, NULL)) != -1) {
772 		switch (option) {
773 		case 'p':
774 			if (p_arg)
775 				die("-p must be specified once only");
776 			p_arg = _B_TRUE;
777 
778 			ipadm_check_propstr(optarg, reset, use);
779 			nv = optarg;
780 			break;
781 		case 'm':
782 			if (m_arg)
783 				die("-m must be specified once only");
784 			m_arg = _B_TRUE;
785 			protostr = optarg;
786 			break;
787 		case 't':
788 			flags &= ~IPADM_OPT_PERSIST;
789 			break;
790 		default:
791 			die_opterr(optopt, option, use);
792 		}
793 	}
794 
795 	if (!m_arg || !p_arg || optind != argc - 1)
796 		die("Usage: %s", use);
797 
798 	ifname = argv[optind];
799 
800 	prop_name = nv;
801 	prop_val = strchr(nv, '=');
802 	if (prop_val != NULL)
803 		*prop_val++ = '\0';
804 
805 	if ((proto = ipadm_str2proto(protostr)) == MOD_PROTO_NONE)
806 		die("invalid protocol '%s' specified", protostr);
807 
808 	if (reset)
809 		flags |= IPADM_OPT_DEFAULT;
810 	else
811 		flags |= IPADM_OPT_ACTIVE;
812 	status = ipadm_set_ifprop(iph, ifname, prop_name, prop_val, proto,
813 	    flags);
814 
815 done:
816 	if (status != IPADM_SUCCESS) {
817 		if (reset)
818 			die("reset-ifprop: %s: %s",
819 			    prop_name, ipadm_status2str(status));
820 		else
821 			die("set-ifprop: %s: %s",
822 			    prop_name, ipadm_status2str(status));
823 	}
824 }
825 
826 static void
827 do_set_ifprop(int argc, char **argv, const char *use)
828 {
829 	set_ifprop(argc, argv, _B_FALSE, use);
830 }
831 
832 static void
833 do_reset_ifprop(int argc, char **argv, const char *use)
834 {
835 	set_ifprop(argc, argv, _B_TRUE, use);
836 }
837 
838 /*
839  * Display information for all or specific protocol properties, either for a
840  * given protocol or for supported protocols (IP/IPv4/IPv6/TCP/UDP/SCTP)
841  */
842 static void
843 do_show_prop(int argc, char **argv, const char *use)
844 {
845 	char 			option;
846 	nvlist_t 		*proplist = NULL;
847 	char			*fields_str = NULL;
848 	char 			*protostr;
849 	show_prop_state_t 	state;
850 	ofmt_handle_t		ofmt;
851 	ofmt_status_t		oferr;
852 	uint_t			ofmtflags = 0;
853 	uint_t			proto;
854 	boolean_t		p_arg = _B_FALSE;
855 
856 	opterr = 0;
857 	bzero(&state, sizeof (state));
858 	state.sps_propval = NULL;
859 	state.sps_parsable = _B_FALSE;
860 	state.sps_modprop = _B_TRUE;
861 	state.sps_status = state.sps_retstatus = IPADM_SUCCESS;
862 	while ((option = getopt_long(argc, argv, ":p:co:", show_prop_longopts,
863 	    NULL)) != -1) {
864 		switch (option) {
865 		case 'p':
866 			if (p_arg)
867 				die("-p must be specified once only");
868 			p_arg = _B_TRUE;
869 			if (ipadm_str2nvlist(optarg, &proplist,
870 			    IPADM_NORVAL) != 0)
871 				die("invalid protocol properties specified");
872 			break;
873 		case 'c':
874 			state.sps_parsable = _B_TRUE;
875 			break;
876 		case 'o':
877 			fields_str = optarg;
878 			break;
879 		default:
880 			die_opterr(optopt, option, use);
881 			break;
882 		}
883 	}
884 	if (optind == argc - 1) {
885 		protostr =  argv[optind];
886 		if ((proto = ipadm_str2proto(protostr)) == MOD_PROTO_NONE)
887 			die("invalid protocol '%s' specified", protostr);
888 		state.sps_proto = proto;
889 	} else if (optind != argc) {
890 		die("Usage: %s", use);
891 	} else {
892 		if (p_arg)
893 			die("protocol must be specified when "
894 			    "property name is used");
895 		state.sps_proto = MOD_PROTO_NONE;
896 	}
897 
898 	state.sps_proplist = proplist;
899 
900 	if (state.sps_parsable)
901 		ofmtflags |= OFMT_PARSABLE;
902 	else
903 		ofmtflags |= OFMT_WRAP;
904 	oferr = ofmt_open(fields_str, modprop_fields, ofmtflags, 0, &ofmt);
905 	ipadm_ofmt_check(oferr, state.sps_parsable, ofmt);
906 	state.sps_ofmt = ofmt;
907 
908 	/* handles all the errors */
909 	show_properties(&state, IPADMPROP_CLASS_MODULE);
910 
911 	nvlist_free(proplist);
912 	ofmt_close(ofmt);
913 
914 	if (state.sps_retstatus != IPADM_SUCCESS) {
915 		ipadm_close(iph);
916 		exit(EXIT_FAILURE);
917 	}
918 }
919 
920 /*
921  * Checks to see if there are any modifiers, + or -. If there are modifiers
922  * then sets IPADM_OPT_APPEND or IPADM_OPT_REMOVE, accordingly.
923  */
924 static void
925 parse_modifiers(const char *pstr, uint_t *flags, const char *use)
926 {
927 	char *p;
928 
929 	if ((p = strchr(pstr, '=')) == NULL)
930 		return;
931 
932 	if (p == pstr)
933 		die("Invalid prop=val specified\n%s", use);
934 
935 	--p;
936 	if (*p == '+')
937 		*flags |= IPADM_OPT_APPEND;
938 	else if (*p == '-')
939 		*flags |= IPADM_OPT_REMOVE;
940 }
941 
942 /*
943  * set/reset the protocol property for a given protocol.
944  */
945 static void
946 set_prop(int argc, char **argv, boolean_t reset, const char *use)
947 {
948 	int 			option;
949 	ipadm_status_t 		status = IPADM_SUCCESS;
950 	char 			*protostr, *nv, *prop_name, *prop_val;
951 	boolean_t 		p_arg = _B_FALSE;
952 	uint_t 			proto;
953 	uint_t			flags = IPADM_OPT_PERSIST;
954 
955 	opterr = 0;
956 	while ((option = getopt_long(argc, argv, ":p:t", set_prop_longopts,
957 	    NULL)) != -1) {
958 		switch (option) {
959 		case 'p':
960 			if (p_arg)
961 				die("-p must be specified once only");
962 			p_arg = _B_TRUE;
963 
964 			ipadm_check_propstr(optarg, reset, use);
965 			nv = optarg;
966 			break;
967 		case 't':
968 			flags &= ~IPADM_OPT_PERSIST;
969 			break;
970 		default:
971 			die_opterr(optopt, option, use);
972 		}
973 	}
974 
975 	if (!p_arg || optind != argc - 1)
976 		die("Usage: %s", use);
977 
978 	parse_modifiers(nv, &flags, use);
979 	prop_name = nv;
980 	prop_val = strchr(nv, '=');
981 	if (prop_val != NULL) {
982 		if (flags & (IPADM_OPT_APPEND|IPADM_OPT_REMOVE))
983 			*(prop_val - 1) = '\0';
984 		*prop_val++ = '\0';
985 	}
986 	protostr = argv[optind];
987 	if ((proto = ipadm_str2proto(protostr)) == MOD_PROTO_NONE)
988 		die("invalid protocol '%s' specified", protostr);
989 
990 	if (reset)
991 		flags |= IPADM_OPT_DEFAULT;
992 	else
993 		flags |= IPADM_OPT_ACTIVE;
994 	status = ipadm_set_prop(iph, prop_name, prop_val, proto, flags);
995 done:
996 	if (status != IPADM_SUCCESS) {
997 		if (reset)
998 			die("reset-prop: %s: %s",
999 			    prop_name, ipadm_status2str(status));
1000 		else
1001 			die("set-prop: %s: %s",
1002 			    prop_name, ipadm_status2str(status));
1003 	}
1004 }
1005 
1006 static void
1007 do_set_prop(int argc, char **argv, const char *use)
1008 {
1009 	set_prop(argc, argv, _B_FALSE, use);
1010 }
1011 
1012 static void
1013 do_reset_prop(int argc, char **argv, const char *use)
1014 {
1015 	set_prop(argc, argv,  _B_TRUE, use);
1016 }
1017 
1018 /* PRINTFLIKE1 */
1019 static void
1020 warn(const char *format, ...)
1021 {
1022 	va_list alist;
1023 
1024 	format = gettext(format);
1025 	(void) fprintf(stderr, gettext("%s: warning: "), progname);
1026 
1027 	va_start(alist, format);
1028 	(void) vfprintf(stderr, format, alist);
1029 	va_end(alist);
1030 
1031 	(void) fprintf(stderr, "\n");
1032 }
1033 
1034 /* PRINTFLIKE1 */
1035 static void
1036 die(const char *format, ...)
1037 {
1038 	va_list alist;
1039 
1040 	format = gettext(format);
1041 	(void) fprintf(stderr, "%s: ", progname);
1042 
1043 	va_start(alist, format);
1044 	(void) vfprintf(stderr, format, alist);
1045 	va_end(alist);
1046 
1047 	(void) putchar('\n');
1048 
1049 	ipadm_destroy_addrobj(ipaddr);
1050 	ipadm_close(iph);
1051 	exit(EXIT_FAILURE);
1052 }
1053 
1054 static void
1055 die_opterr(int opt, int opterr, const char *usage)
1056 {
1057 	switch (opterr) {
1058 	case ':':
1059 		die("option '-%c' requires a value\nusage: %s", opt,
1060 		    gettext(usage));
1061 		break;
1062 	case '?':
1063 	default:
1064 		die("unrecognized option '-%c'\nusage: %s", opt,
1065 		    gettext(usage));
1066 		break;
1067 	}
1068 }
1069 
1070 /* PRINTFLIKE2 */
1071 static void
1072 warn_ipadmerr(ipadm_status_t err, const char *format, ...)
1073 {
1074 	va_list alist;
1075 
1076 	format = gettext(format);
1077 	(void) fprintf(stderr, gettext("%s: warning: "), progname);
1078 
1079 	va_start(alist, format);
1080 	(void) vfprintf(stderr, format, alist);
1081 	va_end(alist);
1082 
1083 	(void) fprintf(stderr, "%s\n", ipadm_status2str(err));
1084 }
1085 
1086 static void
1087 process_static_addrargs(const char *use, char *addrarg, const char *aobjname)
1088 {
1089 	int		option;
1090 	char		*val;
1091 	char		*laddr = NULL;
1092 	char		*raddr = NULL;
1093 	char		*save_input_arg = addrarg;
1094 	boolean_t	found_mismatch = _B_FALSE;
1095 	ipadm_status_t	status;
1096 	enum		{ A_LOCAL, A_REMOTE };
1097 	static char	*addr_optstr[] = {
1098 		"local",
1099 		"remote",
1100 		NULL,
1101 	};
1102 
1103 	while (*addrarg != '\0') {
1104 		option = getsubopt(&addrarg, addr_optstr, &val);
1105 		switch (option) {
1106 		case A_LOCAL:
1107 			if (laddr != NULL)
1108 				die("Multiple local addresses provided");
1109 			laddr = val;
1110 			break;
1111 		case A_REMOTE:
1112 			if (raddr != NULL)
1113 				die("Multiple remote addresses provided");
1114 			raddr = val;
1115 			break;
1116 		default:
1117 			if (found_mismatch)
1118 				die("Invalid address provided\nusage: %s", use);
1119 			found_mismatch = _B_TRUE;
1120 			break;
1121 		}
1122 	}
1123 	if (raddr != NULL && laddr == NULL)
1124 		die("Missing local address\nusage: %s", use);
1125 
1126 	/* If only one address is provided, it is assumed a local address. */
1127 	if (laddr == NULL) {
1128 		if (found_mismatch)
1129 			laddr = save_input_arg;
1130 		else
1131 			die("Missing local address\nusage: %s", use);
1132 	}
1133 
1134 	/* Initialize the addrobj for static addresses. */
1135 	status = ipadm_create_addrobj(IPADM_ADDR_STATIC, aobjname, &ipaddr);
1136 	if (status != IPADM_SUCCESS) {
1137 		die("Error in creating address object: %s",
1138 		    ipadm_status2str(status));
1139 	}
1140 
1141 	/* Set the local and remote addresses */
1142 	status = ipadm_set_addr(ipaddr, laddr, AF_UNSPEC);
1143 	if (status != IPADM_SUCCESS) {
1144 		die("Error in setting local address: %s",
1145 		    ipadm_status2str(status));
1146 	}
1147 	if (raddr != NULL) {
1148 		status = ipadm_set_dst_addr(ipaddr, raddr, AF_UNSPEC);
1149 		if (status != IPADM_SUCCESS) {
1150 			die("Error in setting remote address: %s",
1151 			    ipadm_status2str(status));
1152 		}
1153 	}
1154 }
1155 
1156 static void
1157 process_addrconf_addrargs(const char *use, char *addrarg)
1158 {
1159 	int		option;
1160 	char		*val;
1161 	enum		{ P_STATELESS, P_STATEFUL };
1162 	static char	*addr_optstr[] = {
1163 		"stateless",
1164 		"stateful",
1165 		NULL,
1166 	};
1167 	boolean_t	stateless;
1168 	boolean_t	stateless_arg = _B_FALSE;
1169 	boolean_t	stateful;
1170 	boolean_t	stateful_arg = _B_FALSE;
1171 	ipadm_status_t	status;
1172 
1173 	while (*addrarg != '\0') {
1174 		option = getsubopt(&addrarg, addr_optstr, &val);
1175 		switch (option) {
1176 		case P_STATELESS:
1177 			if (stateless_arg)
1178 				die("Duplicate option");
1179 			if (val == NULL)
1180 				die("Invalid argument");
1181 			if (strcmp(val, "yes") == 0)
1182 				stateless = _B_TRUE;
1183 			else if (strcmp(val, "no") == 0)
1184 				stateless = _B_FALSE;
1185 			else
1186 				die("Invalid argument");
1187 			stateless_arg = _B_TRUE;
1188 			break;
1189 		case P_STATEFUL:
1190 			if (stateful_arg)
1191 				die("Duplicate option");
1192 			if (val == NULL)
1193 				die("Invalid argument");
1194 			if (strcmp(val, "yes") == 0)
1195 				stateful = _B_TRUE;
1196 			else if (strcmp(val, "no") == 0)
1197 				stateful = _B_FALSE;
1198 			else
1199 				die("Invalid argument");
1200 			stateful_arg = _B_TRUE;
1201 			break;
1202 		default:
1203 			die_opterr(optopt, option, use);
1204 		}
1205 	}
1206 
1207 	if (!stateless_arg && !stateful_arg)
1208 		die("Invalid arguments for option -p");
1209 
1210 	/* Set the addrobj fields for addrconf */
1211 	if (stateless_arg) {
1212 		status = ipadm_set_stateless(ipaddr, stateless);
1213 		if (status != IPADM_SUCCESS) {
1214 			die("Error in setting stateless option: %s",
1215 			    ipadm_status2str(status));
1216 		}
1217 	}
1218 	if (stateful_arg) {
1219 		status = ipadm_set_stateful(ipaddr, stateful);
1220 		if (status != IPADM_SUCCESS) {
1221 			die("Error in setting stateful option: %s",
1222 			    ipadm_status2str(status));
1223 		}
1224 	}
1225 }
1226 
1227 /*
1228  * Creates static, dhcp or addrconf addresses and associates the created
1229  * addresses with the specified address object name.
1230  */
1231 static void
1232 do_create_addr(int argc, char *argv[], const char *use)
1233 {
1234 	ipadm_status_t	status;
1235 	int		option;
1236 	uint32_t	flags =
1237 	    IPADM_OPT_PERSIST|IPADM_OPT_ACTIVE|IPADM_OPT_UP|IPADM_OPT_V46;
1238 	char		*cp;
1239 	char		*atype = NULL;
1240 	char		*static_arg = NULL;
1241 	char		*addrconf_arg = NULL;
1242 	char		*interface_id = NULL;
1243 	char		*wait = NULL;
1244 	boolean_t	s_opt = _B_FALSE;	/* static addr options */
1245 	boolean_t	auto_opt = _B_FALSE;	/* Addrconf options */
1246 	boolean_t	dhcp_opt = _B_FALSE;	/* dhcp options */
1247 
1248 	opterr = 0;
1249 	while ((option = getopt_long(argc, argv, ":T:a:di:p:w:t",
1250 	    addr_longopts, NULL)) != -1) {
1251 		switch (option) {
1252 		case 'T':
1253 			atype = optarg;
1254 			break;
1255 		case 'a':
1256 			static_arg = optarg;
1257 			s_opt = _B_TRUE;
1258 			break;
1259 		case 'd':
1260 			flags &= ~IPADM_OPT_UP;
1261 			s_opt = _B_TRUE;
1262 			break;
1263 		case 'i':
1264 			interface_id = optarg;
1265 			auto_opt = _B_TRUE;
1266 			break;
1267 		case 'p':
1268 			addrconf_arg = optarg;
1269 			auto_opt = _B_TRUE;
1270 			break;
1271 		case 'w':
1272 			wait = optarg;
1273 			dhcp_opt = _B_TRUE;
1274 			break;
1275 		case 't':
1276 			flags &= ~IPADM_OPT_PERSIST;
1277 			break;
1278 		default:
1279 			die_opterr(optopt, option, use);
1280 		}
1281 	}
1282 	if (atype == NULL || optind != (argc - 1)) {
1283 		die("Invalid arguments\nusage: %s", use);
1284 	} else if ((cp = strchr(argv[optind], '/')) == NULL ||
1285 	    strlen(++cp) == 0) {
1286 		die("invalid address object name: %s\nusage: %s",
1287 		    argv[optind], use);
1288 	}
1289 
1290 	/*
1291 	 * Allocate and initialize the addrobj based on the address type.
1292 	 */
1293 	if (strcmp(atype, "static") == 0) {
1294 		if (static_arg == NULL || auto_opt || dhcp_opt) {
1295 			die("Invalid arguments for type %s\nusage: %s",
1296 			    atype, use);
1297 		}
1298 		process_static_addrargs(use, static_arg, argv[optind]);
1299 	} else if (strcmp(atype, "dhcp") == 0) {
1300 		if (auto_opt || s_opt) {
1301 			die("Invalid arguments for type %s\nusage: %s",
1302 			    atype, use);
1303 		}
1304 
1305 		/* Initialize the addrobj for dhcp addresses. */
1306 		status = ipadm_create_addrobj(IPADM_ADDR_DHCP, argv[optind],
1307 		    &ipaddr);
1308 		if (status != IPADM_SUCCESS) {
1309 			die("Error in creating address object: %s",
1310 			    ipadm_status2str(status));
1311 		}
1312 		if (wait != NULL) {
1313 			int32_t ipadm_wait;
1314 
1315 			if (strcmp(wait, "forever") == 0) {
1316 				ipadm_wait = IPADM_DHCP_WAIT_FOREVER;
1317 			} else {
1318 				char *end;
1319 				long timeout = strtol(wait, &end, 10);
1320 
1321 				if (*end != '\0' || timeout < 0)
1322 					die("Invalid argument");
1323 				ipadm_wait = (int32_t)timeout;
1324 			}
1325 			status = ipadm_set_wait_time(ipaddr, ipadm_wait);
1326 			if (status != IPADM_SUCCESS) {
1327 				die("Error in setting wait time: %s",
1328 				    ipadm_status2str(status));
1329 			}
1330 		}
1331 	} else if (strcmp(atype, "addrconf") == 0) {
1332 		if (dhcp_opt || s_opt) {
1333 			die("Invalid arguments for type %s\nusage: %s",
1334 			    atype, use);
1335 		}
1336 
1337 		/* Initialize the addrobj for dhcp addresses. */
1338 		status = ipadm_create_addrobj(IPADM_ADDR_IPV6_ADDRCONF,
1339 		    argv[optind], &ipaddr);
1340 		if (status != IPADM_SUCCESS) {
1341 			die("Error in creating address object: %s",
1342 			    ipadm_status2str(status));
1343 		}
1344 		if (interface_id != NULL) {
1345 			status = ipadm_set_interface_id(ipaddr, interface_id);
1346 			if (status != IPADM_SUCCESS) {
1347 				die("Error in setting interface ID: %s",
1348 				    ipadm_status2str(status));
1349 			}
1350 		}
1351 		if (addrconf_arg)
1352 			process_addrconf_addrargs(use, addrconf_arg);
1353 	} else {
1354 		die("Invalid address type %s", atype);
1355 	}
1356 
1357 	status = ipadm_create_addr(iph, ipaddr, flags);
1358 	if (status == IPADM_DHCP_IPC_TIMEOUT)
1359 		warn_ipadmerr(status, "");
1360 	else if (status != IPADM_SUCCESS)
1361 		die("Could not create address: %s", ipadm_status2str(status));
1362 }
1363 
1364 /*
1365  * Used by some address management functions to parse the command line
1366  * arguments and create `ipaddr' address object.
1367  */
1368 static void
1369 process_misc_addrargs(int argc, char *argv[], const char *use, int *index,
1370     uint32_t *flags)
1371 {
1372 	int		option;
1373 
1374 	opterr = 0;
1375 	while ((option = getopt_long(argc, argv, ":t", addr_misc_longopts,
1376 	    NULL)) != -1) {
1377 		switch (option) {
1378 		case 't':
1379 			*flags &= ~IPADM_OPT_PERSIST;
1380 			break;
1381 		default:
1382 			die_opterr(optopt, option, use);
1383 		}
1384 	}
1385 	if (optind != (argc - 1))
1386 		die("Usage: %s", use);
1387 
1388 	*index = optind;
1389 }
1390 
1391 /*
1392  * Remove an addrobj from both active and persistent configuration.
1393  */
1394 static void
1395 do_delete_addr(int argc, char *argv[], const char *use)
1396 {
1397 	ipadm_status_t	status;
1398 	uint32_t 	flags = IPADM_OPT_ACTIVE|IPADM_OPT_PERSIST;
1399 	int		option;
1400 
1401 	opterr = 0;
1402 	while ((option = getopt_long(argc, argv, ":r", addr_misc_longopts,
1403 	    NULL)) != -1) {
1404 		switch (option) {
1405 		case 'r':
1406 			flags |= IPADM_OPT_RELEASE;
1407 			break;
1408 		default:
1409 			die_opterr(optopt, option, use);
1410 		}
1411 	}
1412 	if (optind != (argc - 1))
1413 		die("Usage: %s", use);
1414 
1415 	status = ipadm_delete_addr(iph, argv[optind], flags);
1416 	if (status != IPADM_SUCCESS) {
1417 		die("could not delete address: %s",
1418 		    ipadm_status2str(status));
1419 	}
1420 }
1421 
1422 /*
1423  * Enable an IP address based on the persistent configuration for that
1424  * IP address
1425  */
1426 static void
1427 do_enable_addr(int argc, char *argv[], const char *use)
1428 {
1429 	ipadm_status_t	status;
1430 	int		index;
1431 	uint32_t 	flags = IPADM_OPT_ACTIVE|IPADM_OPT_PERSIST;
1432 
1433 	process_misc_addrargs(argc, argv, use, &index, &flags);
1434 	if (flags & IPADM_OPT_PERSIST)
1435 		die("persistent operation not supported for enable-addr");
1436 
1437 	status = ipadm_enable_addr(iph, argv[index], flags);
1438 	if (status != IPADM_SUCCESS)
1439 		die("could not enable address: %s", ipadm_status2str(status));
1440 }
1441 
1442 /*
1443  * Mark the address identified by addrobj 'up'
1444  */
1445 static void
1446 do_up_addr(int argc, char *argv[], const char *use)
1447 {
1448 	ipadm_status_t	status;
1449 	int		index;
1450 	uint32_t 	flags = IPADM_OPT_ACTIVE|IPADM_OPT_PERSIST;
1451 
1452 	process_misc_addrargs(argc, argv, use, &index, &flags);
1453 	status = ipadm_up_addr(iph, argv[index], flags);
1454 	if (status != IPADM_SUCCESS) {
1455 		die("Could not mark the address up: %s",
1456 		    ipadm_status2str(status));
1457 	}
1458 }
1459 
1460 /*
1461  * Disable the specified addrobj by removing it from active cofiguration
1462  */
1463 static void
1464 do_disable_addr(int argc, char *argv[], const char *use)
1465 {
1466 	ipadm_status_t	status;
1467 	int		index;
1468 	uint32_t 	flags = IPADM_OPT_ACTIVE|IPADM_OPT_PERSIST;
1469 
1470 	process_misc_addrargs(argc, argv, use, &index, &flags);
1471 	if (flags & IPADM_OPT_PERSIST)
1472 		die("persistent operation not supported for disable-addr");
1473 
1474 	status = ipadm_disable_addr(iph, argv[index], flags);
1475 	if (status != IPADM_SUCCESS) {
1476 		die("could not disable address: %s",
1477 		    ipadm_status2str(status));
1478 	}
1479 }
1480 
1481 /*
1482  * Mark the address identified by addrobj 'down'
1483  */
1484 static void
1485 do_down_addr(int argc, char *argv[], const char *use)
1486 {
1487 	ipadm_status_t	status;
1488 	int		index;
1489 	uint32_t 	flags = IPADM_OPT_ACTIVE|IPADM_OPT_PERSIST;
1490 
1491 	process_misc_addrargs(argc, argv, use, &index, &flags);
1492 	status = ipadm_down_addr(iph, argv[index], flags);
1493 	if (status != IPADM_SUCCESS)
1494 		die("Could not mark the address down: %s",
1495 		    ipadm_status2str(status));
1496 }
1497 
1498 /*
1499  * Restart DAD for static address. Extend lease duration for DHCP addresses
1500  */
1501 static void
1502 do_refresh_addr(int argc, char *argv[], const char *use)
1503 {
1504 	ipadm_status_t	status;
1505 	int		option;
1506 	uint32_t	flags = 0;
1507 
1508 	opterr = 0;
1509 	while ((option = getopt_long(argc, argv, ":i", addr_misc_longopts,
1510 	    NULL)) != -1) {
1511 		switch (option) {
1512 		case 'i':
1513 			flags |= IPADM_OPT_INFORM;
1514 			break;
1515 		default:
1516 			die_opterr(optopt, option, use);
1517 		}
1518 	}
1519 	if (optind != (argc - 1))
1520 		die("Usage: %s", use);
1521 
1522 	status = ipadm_refresh_addr(iph, argv[optind], flags);
1523 	if (status == IPADM_DHCP_IPC_TIMEOUT)
1524 		warn_ipadmerr(status, "");
1525 	else if (status != IPADM_SUCCESS)
1526 		die("could not refresh address %s", ipadm_status2str(status));
1527 }
1528 
1529 static void
1530 sockaddr2str(const struct sockaddr_storage *ssp, char *buf, uint_t bufsize)
1531 {
1532 	socklen_t socklen;
1533 	struct sockaddr *sp = (struct sockaddr *)ssp;
1534 
1535 	switch (ssp->ss_family) {
1536 	case AF_INET:
1537 		socklen = sizeof (struct sockaddr_in);
1538 		break;
1539 	case AF_INET6:
1540 		socklen = sizeof (struct sockaddr_in6);
1541 		break;
1542 	default:
1543 		(void) strlcpy(buf, STR_UNKNOWN_VAL, bufsize);
1544 		return;
1545 	}
1546 
1547 	(void) getnameinfo(sp, socklen, buf, bufsize, NULL, 0,
1548 	    (NI_NOFQDN | NI_NUMERICHOST));
1549 }
1550 
1551 static void
1552 flags2str(uint64_t flags, fmask_t *tbl, boolean_t is_bits,
1553     char *buf, uint_t bufsize)
1554 {
1555 	int		i;
1556 	boolean_t	first = _B_TRUE;
1557 
1558 	if (is_bits) {
1559 		for (i = 0;  tbl[i].name; i++) {
1560 			if ((flags & tbl[i].mask) == tbl[i].bits)
1561 				(void) strlcat(buf, tbl[i].name, bufsize);
1562 			else
1563 				(void) strlcat(buf, "-", bufsize);
1564 		}
1565 	} else {
1566 		for (i = 0; tbl[i].name; i++) {
1567 			if ((flags & tbl[i].mask) == tbl[i].bits) {
1568 				if (!first)
1569 					(void) strlcat(buf, ",", bufsize);
1570 				(void) strlcat(buf, tbl[i].name, bufsize);
1571 				first = _B_FALSE;
1572 			}
1573 		}
1574 	}
1575 }
1576 
1577 /*
1578  * return true if the address for lifname comes to us from the global zone
1579  * with 'allowed-ips' constraints.
1580  */
1581 static boolean_t
1582 is_from_gz(const char *lifname)
1583 {
1584 	ipadm_if_info_t		*if_info;
1585 	char			phyname[LIFNAMSIZ], *cp;
1586 	boolean_t		ret = _B_FALSE;
1587 	ipadm_status_t		status;
1588 	zoneid_t		zoneid;
1589 	ushort_t		zflags;
1590 
1591 	if ((zoneid = getzoneid()) == GLOBAL_ZONEID)
1592 		return (_B_FALSE); /* from-gz only  makes sense in a NGZ */
1593 
1594 	if (zone_getattr(zoneid, ZONE_ATTR_FLAGS, &zflags, sizeof (zflags)) < 0)
1595 		return (_B_FALSE);
1596 
1597 	if (!(zflags & ZF_NET_EXCL))
1598 		return (_B_TRUE);  /* everything is from the GZ for shared-ip */
1599 
1600 	(void) strncpy(phyname, lifname, sizeof (phyname));
1601 	if ((cp = strchr(phyname, ':')) != NULL)
1602 		*cp = '\0';
1603 	status = ipadm_if_info(iph, phyname, &if_info, 0, LIFC_DEFAULT);
1604 	if (status != IPADM_SUCCESS)
1605 		return (ret);
1606 
1607 	if (if_info->ifi_cflags & IFIF_L3PROTECT)
1608 		ret = _B_TRUE;
1609 	if (if_info)
1610 		ipadm_free_if_info(if_info);
1611 	return (ret);
1612 }
1613 
1614 static boolean_t
1615 print_sa_cb(ofmt_arg_t *ofarg, char *buf, uint_t bufsize)
1616 {
1617 	show_addr_args_t	*arg = ofarg->ofmt_cbarg;
1618 	ipadm_addr_info_t	*ainfo = arg->sa_info;
1619 	char			interface[LIFNAMSIZ];
1620 	char			addrbuf[MAXPROPVALLEN];
1621 	char			dstbuf[MAXPROPVALLEN];
1622 	char			prefixlenstr[MAXPROPVALLEN];
1623 	int			prefixlen;
1624 	struct sockaddr_in	*sin;
1625 	struct sockaddr_in6	*sin6;
1626 	sa_family_t		af;
1627 	char			*phyname = NULL;
1628 	struct ifaddrs		*ifa = &ainfo->ia_ifa;
1629 	fmask_t cflags_mask[] = {
1630 		{ "U",	IA_UP,			IA_UP		},
1631 		{ "u",	IA_UNNUMBERED,		IA_UNNUMBERED	},
1632 		{ "p",	IA_PRIVATE,		IA_PRIVATE	},
1633 		{ "t",	IA_TEMPORARY,		IA_TEMPORARY	},
1634 		{ "d",	IA_DEPRECATED,		IA_DEPRECATED	},
1635 		{ NULL,		0,			0	}
1636 	};
1637 	fmask_t pflags_mask[] = {
1638 		{ "U",	IA_UP,			IA_UP		},
1639 		{ "p",	IA_PRIVATE,		IA_PRIVATE	},
1640 		{ "d",	IA_DEPRECATED,		IA_DEPRECATED	},
1641 		{ NULL,		0,			0	}
1642 	};
1643 	fmask_t type[] = {
1644 		{ "static",	IPADM_ADDR_STATIC,	IPADM_ALL_BITS},
1645 		{ "addrconf",	IPADM_ADDR_IPV6_ADDRCONF, IPADM_ALL_BITS},
1646 		{ "dhcp",	IPADM_ADDR_DHCP,	IPADM_ALL_BITS},
1647 		{ NULL,		0,			0	}
1648 	};
1649 	fmask_t addr_state[] = {
1650 		{ "disabled",	IFA_DISABLED,	IPADM_ALL_BITS},
1651 		{ "duplicate",	IFA_DUPLICATE,	IPADM_ALL_BITS},
1652 		{ "down",	IFA_DOWN,	IPADM_ALL_BITS},
1653 		{ "tentative",	IFA_TENTATIVE,	IPADM_ALL_BITS},
1654 		{ "ok",		IFA_OK,		IPADM_ALL_BITS},
1655 		{ "inaccessible", IFA_INACCESSIBLE, IPADM_ALL_BITS},
1656 		{ NULL,		0,		0	}
1657 	};
1658 
1659 	buf[0] = '\0';
1660 	switch (ofarg->ofmt_id) {
1661 	case SA_ADDROBJ:
1662 		if (ainfo->ia_aobjname[0] == '\0') {
1663 			(void) strncpy(interface, ifa->ifa_name, LIFNAMSIZ);
1664 			phyname = strrchr(interface, ':');
1665 			if (phyname)
1666 				*phyname = '\0';
1667 			(void) snprintf(buf, bufsize, "%s/%s", interface,
1668 			    STR_UNKNOWN_VAL);
1669 		} else {
1670 			(void) snprintf(buf, bufsize, "%s", ainfo->ia_aobjname);
1671 		}
1672 		break;
1673 	case SA_STATE:
1674 		flags2str(ainfo->ia_state, addr_state, _B_FALSE,
1675 		    buf, bufsize);
1676 		break;
1677 	case SA_TYPE:
1678 		if (is_from_gz(ifa->ifa_name))
1679 			(void) snprintf(buf, bufsize, "from-gz");
1680 		else
1681 			flags2str(ainfo->ia_atype, type, _B_FALSE, buf,
1682 			    bufsize);
1683 		break;
1684 	case SA_CURRENT:
1685 		flags2str(ainfo->ia_cflags, cflags_mask, _B_TRUE, buf, bufsize);
1686 		break;
1687 	case SA_PERSISTENT:
1688 		flags2str(ainfo->ia_pflags, pflags_mask, _B_TRUE, buf, bufsize);
1689 		break;
1690 	case SA_ADDR:
1691 		af = ifa->ifa_addr->sa_family;
1692 		/*
1693 		 * If the address is 0.0.0.0 or :: and the origin is DHCP,
1694 		 * print STR_UNKNOWN_VAL.
1695 		 */
1696 		if (ainfo->ia_atype == IPADM_ADDR_DHCP) {
1697 			sin = (struct sockaddr_in *)ifa->ifa_addr;
1698 			sin6 = (struct sockaddr_in6 *)ifa->ifa_addr;
1699 			if ((af == AF_INET &&
1700 			    sin->sin_addr.s_addr == INADDR_ANY) ||
1701 			    (af == AF_INET6 &&
1702 			    IN6_IS_ADDR_UNSPECIFIED(&sin6->sin6_addr))) {
1703 				(void) snprintf(buf, bufsize, STR_UNKNOWN_VAL);
1704 				break;
1705 			}
1706 		}
1707 		if (ifa->ifa_netmask == NULL)
1708 			prefixlen = 0;
1709 		else
1710 			prefixlen = mask2plen(ifa->ifa_netmask);
1711 		bzero(prefixlenstr, sizeof (prefixlenstr));
1712 		if (prefixlen > 0) {
1713 			(void) snprintf(prefixlenstr, sizeof (prefixlenstr),
1714 			    "/%d", prefixlen);
1715 		}
1716 		bzero(addrbuf, sizeof (addrbuf));
1717 		bzero(dstbuf, sizeof (dstbuf));
1718 		if (ainfo->ia_atype == IPADM_ADDR_STATIC) {
1719 			/*
1720 			 * Print the hostname fields if the address is not
1721 			 * in active configuration.
1722 			 */
1723 			if (ainfo->ia_state == IFA_DISABLED) {
1724 				(void) snprintf(buf, bufsize, "%s",
1725 				    ainfo->ia_sname);
1726 				if (ainfo->ia_dname[0] != '\0') {
1727 					(void) snprintf(dstbuf, sizeof (dstbuf),
1728 					    "->%s", ainfo->ia_dname);
1729 					(void) strlcat(buf, dstbuf, bufsize);
1730 				} else {
1731 					(void) strlcat(buf, prefixlenstr,
1732 					    bufsize);
1733 				}
1734 				break;
1735 			}
1736 		}
1737 		/*
1738 		 * For the non-persistent case, we need to show the
1739 		 * currently configured addresses for source and
1740 		 * destination.
1741 		 */
1742 		sockaddr2str((struct sockaddr_storage *)ifa->ifa_addr,
1743 		    addrbuf, sizeof (addrbuf));
1744 		if (ifa->ifa_flags & IFF_POINTOPOINT) {
1745 			sockaddr2str(
1746 			    (struct sockaddr_storage *)ifa->ifa_dstaddr,
1747 			    dstbuf, sizeof (dstbuf));
1748 			(void) snprintf(buf, bufsize, "%s->%s", addrbuf,
1749 			    dstbuf);
1750 		} else {
1751 			(void) snprintf(buf, bufsize, "%s%s", addrbuf,
1752 			    prefixlenstr);
1753 		}
1754 		break;
1755 	default:
1756 		die("invalid input");
1757 		break;
1758 	}
1759 
1760 	return (_B_TRUE);
1761 }
1762 
1763 /*
1764  * Display address information, either for the given address or
1765  * for all the addresses managed by ipadm.
1766  */
1767 static void
1768 do_show_addr(int argc, char *argv[], const char *use)
1769 {
1770 	ipadm_status_t		status;
1771 	show_addr_state_t	state;
1772 	char			*def_fields_str = "addrobj,type,state,addr";
1773 	char			*fields_str = NULL;
1774 	ipadm_addr_info_t	*ainfo;
1775 	ipadm_addr_info_t	*ptr;
1776 	show_addr_args_t	sargs;
1777 	int			option;
1778 	ofmt_handle_t		ofmt;
1779 	ofmt_status_t		oferr;
1780 	uint_t			ofmtflags = 0;
1781 	char			*aname;
1782 	char			*ifname = NULL;
1783 	char			*cp;
1784 	boolean_t		found = _B_FALSE;
1785 
1786 	opterr = 0;
1787 	state.sa_parsable = _B_FALSE;
1788 	state.sa_persist = _B_FALSE;
1789 	while ((option = getopt_long(argc, argv, "po:", show_addr_longopts,
1790 	    NULL)) != -1) {
1791 		switch (option) {
1792 		case 'p':
1793 			state.sa_parsable = _B_TRUE;
1794 			break;
1795 		case 'o':
1796 			fields_str = optarg;
1797 			break;
1798 		default:
1799 			die_opterr(optopt, option, use);
1800 			break;
1801 		}
1802 	}
1803 	if (state.sa_parsable && fields_str == NULL)
1804 		die("-p requires -o");
1805 
1806 	if (optind == argc - 1) {
1807 		aname = argv[optind];
1808 		if ((cp = strchr(aname, '/')) == NULL)
1809 			die("Invalid address object name provided");
1810 		if (*(cp + 1) == '\0') {
1811 			ifname = aname;
1812 			*cp = '\0';
1813 			aname = NULL;
1814 		}
1815 	} else if (optind == argc) {
1816 		aname = NULL;
1817 	} else {
1818 		die("Usage: %s", use);
1819 	}
1820 
1821 	if (state.sa_parsable)
1822 		ofmtflags |= OFMT_PARSABLE;
1823 	if (fields_str == NULL)
1824 		fields_str = def_fields_str;
1825 	oferr = ofmt_open(fields_str, show_addr_fields, ofmtflags, 0, &ofmt);
1826 
1827 	ipadm_ofmt_check(oferr, state.sa_parsable, ofmt);
1828 	state.sa_ofmt = ofmt;
1829 
1830 	status = ipadm_addr_info(iph, ifname, &ainfo, 0, LIFC_DEFAULT);
1831 	/*
1832 	 * Return without printing any error, if no addresses were found,
1833 	 * for the case where all addresses are requested.
1834 	 */
1835 	if (status != IPADM_SUCCESS)
1836 		die("Could not get address: %s", ipadm_status2str(status));
1837 	if (ainfo == NULL) {
1838 		ofmt_close(ofmt);
1839 		return;
1840 	}
1841 
1842 	bzero(&sargs, sizeof (sargs));
1843 	sargs.sa_state = &state;
1844 	for (ptr = ainfo; ptr != NULL; ptr = IA_NEXT(ptr)) {
1845 		sargs.sa_info = ptr;
1846 		if (aname != NULL) {
1847 			if (strcmp(sargs.sa_info->ia_aobjname, aname) != 0)
1848 				continue;
1849 			found = _B_TRUE;
1850 		}
1851 		ofmt_print(state.sa_ofmt, &sargs);
1852 	}
1853 	if (ainfo)
1854 		ipadm_free_addr_info(ainfo);
1855 	if (aname != NULL && !found)
1856 		die("Address object not found");
1857 }
1858 
1859 static boolean_t
1860 print_si_cb(ofmt_arg_t *ofarg, char *buf, uint_t bufsize)
1861 {
1862 	show_if_args_t		*arg = ofarg->ofmt_cbarg;
1863 	ipadm_if_info_t		*ifinfo = arg->si_info;
1864 	char			*ifname = ifinfo->ifi_name;
1865 	fmask_t intf_state[] = {
1866 		{ "ok",		IFIS_OK,	IPADM_ALL_BITS},
1867 		{ "down",	IFIS_DOWN,	IPADM_ALL_BITS},
1868 		{ "disabled",	IFIS_DISABLED,	IPADM_ALL_BITS},
1869 		{ "failed",	IFIS_FAILED,	IPADM_ALL_BITS},
1870 		{ "offline",	IFIS_OFFLINE,	IPADM_ALL_BITS},
1871 		{ NULL,		0,		0	}
1872 	};
1873 	fmask_t intf_pflags[] = {
1874 		{ "s",	IFIF_STANDBY,		IFIF_STANDBY	},
1875 		{ "4",	IFIF_IPV4,		IFIF_IPV4	},
1876 		{ "6",	IFIF_IPV6,		IFIF_IPV6	},
1877 		{ NULL,	0,			0		}
1878 	};
1879 	fmask_t intf_cflags[] = {
1880 		{ "b",	IFIF_BROADCAST,		IFIF_BROADCAST	},
1881 		{ "m",	IFIF_MULTICAST,		IFIF_MULTICAST	},
1882 		{ "p",	IFIF_POINTOPOINT,	IFIF_POINTOPOINT},
1883 		{ "v",	IFIF_VIRTUAL,		IFIF_VIRTUAL	},
1884 		{ "I",	IFIF_IPMP,		IFIF_IPMP	},
1885 		{ "s",	IFIF_STANDBY,		IFIF_STANDBY	},
1886 		{ "i",	IFIF_INACTIVE,		IFIF_INACTIVE	},
1887 		{ "V",	IFIF_VRRP,		IFIF_VRRP	},
1888 		{ "a",	IFIF_NOACCEPT,		IFIF_NOACCEPT	},
1889 		{ "Z",	IFIF_L3PROTECT,		IFIF_L3PROTECT	},
1890 		{ "4",	IFIF_IPV4,		IFIF_IPV4	},
1891 		{ "6",	IFIF_IPV6,		IFIF_IPV6	},
1892 		{ NULL,	0,			0		}
1893 	};
1894 
1895 	buf[0] = '\0';
1896 	switch (ofarg->ofmt_id) {
1897 	case SI_IFNAME:
1898 		(void) snprintf(buf, bufsize, "%s", ifname);
1899 		break;
1900 	case SI_STATE:
1901 		flags2str(ifinfo->ifi_state, intf_state, _B_FALSE,
1902 		    buf, bufsize);
1903 		break;
1904 	case SI_CURRENT:
1905 		flags2str(ifinfo->ifi_cflags, intf_cflags, _B_TRUE,
1906 		    buf, bufsize);
1907 		break;
1908 	case SI_PERSISTENT:
1909 		flags2str(ifinfo->ifi_pflags, intf_pflags, _B_TRUE,
1910 		    buf, bufsize);
1911 		break;
1912 	default:
1913 		die("invalid input");
1914 		break;
1915 	}
1916 
1917 	return (_B_TRUE);
1918 }
1919 
1920 /*
1921  * Display interface information, either for the given interface or
1922  * for all the interfaces in the system.
1923  */
1924 static void
1925 do_show_if(int argc, char *argv[], const char *use)
1926 {
1927 	ipadm_status_t		status;
1928 	show_if_state_t		state;
1929 	char			*fields_str = NULL;
1930 	ipadm_if_info_t		*if_info, *ptr;
1931 	show_if_args_t		sargs;
1932 	int			option;
1933 	ofmt_handle_t		ofmt;
1934 	ofmt_status_t		oferr;
1935 	uint_t			ofmtflags = 0;
1936 	char			*ifname = NULL;
1937 
1938 	opterr = 0;
1939 	state.si_parsable = _B_FALSE;
1940 
1941 	while ((option = getopt_long(argc, argv, "po:", show_if_longopts,
1942 	    NULL)) != -1) {
1943 		switch (option) {
1944 		case 'p':
1945 			state.si_parsable = _B_TRUE;
1946 			break;
1947 		case 'o':
1948 			fields_str = optarg;
1949 			break;
1950 		default:
1951 			die_opterr(optopt, option, use);
1952 			break;
1953 		}
1954 	}
1955 	if (optind == argc - 1)
1956 		ifname = argv[optind];
1957 	else if (optind != argc)
1958 		die("Usage: %s", use);
1959 	if (state.si_parsable)
1960 		ofmtflags |= OFMT_PARSABLE;
1961 	oferr = ofmt_open(fields_str, show_if_fields, ofmtflags, 0, &ofmt);
1962 	ipadm_ofmt_check(oferr, state.si_parsable, ofmt);
1963 	state.si_ofmt = ofmt;
1964 	bzero(&sargs, sizeof (sargs));
1965 	sargs.si_state = &state;
1966 	status = ipadm_if_info(iph, ifname, &if_info, 0, LIFC_DEFAULT);
1967 	/*
1968 	 * Return without printing any error, if no addresses were found.
1969 	 */
1970 	if (status != IPADM_SUCCESS) {
1971 		die("Could not get interface(s): %s",
1972 		    ipadm_status2str(status));
1973 	}
1974 
1975 	for (ptr = if_info; ptr; ptr = ptr->ifi_next) {
1976 		sargs.si_info = ptr;
1977 		ofmt_print(state.si_ofmt, &sargs);
1978 	}
1979 	if (if_info)
1980 		ipadm_free_if_info(if_info);
1981 }
1982 
1983 /*
1984  * set/reset the address property for a given address
1985  */
1986 static void
1987 set_addrprop(int argc, char **argv, boolean_t reset, const char *use)
1988 {
1989 	int 			option;
1990 	ipadm_status_t 		status = IPADM_SUCCESS;
1991 	boolean_t 		p_arg = _B_FALSE;
1992 	char 			*nv, *aobjname;
1993 	char			*prop_name, *prop_val;
1994 	uint_t			flags = IPADM_OPT_ACTIVE|IPADM_OPT_PERSIST;
1995 
1996 	opterr = 0;
1997 	while ((option = getopt_long(argc, argv, ":i:p:t", set_ifprop_longopts,
1998 	    NULL)) != -1) {
1999 		switch (option) {
2000 		case 'p':
2001 			if (p_arg)
2002 				die("-p must be specified once only");
2003 			p_arg = _B_TRUE;
2004 
2005 			ipadm_check_propstr(optarg, reset, use);
2006 			nv = optarg;
2007 			break;
2008 		case 't':
2009 			flags &= ~IPADM_OPT_PERSIST;
2010 			break;
2011 		default:
2012 			die_opterr(optopt, option, use);
2013 		}
2014 	}
2015 
2016 	if (!p_arg || optind != (argc - 1))
2017 		die("Usage: %s", use);
2018 
2019 	prop_name = nv;
2020 	prop_val = strchr(nv, '=');
2021 	if (prop_val != NULL)
2022 		*prop_val++ = '\0';
2023 	aobjname = argv[optind];
2024 	if (reset)
2025 		flags |= IPADM_OPT_DEFAULT;
2026 	status = ipadm_set_addrprop(iph, prop_name, prop_val, aobjname, flags);
2027 	if (status != IPADM_SUCCESS) {
2028 		if (reset)
2029 			die("reset-addrprop: %s: %s", prop_name,
2030 			    ipadm_status2str(status));
2031 		else
2032 			die("set-addrprop: %s: %s", prop_name,
2033 			    ipadm_status2str(status));
2034 	}
2035 }
2036 
2037 /*
2038  * Sets a property on an address object.
2039  */
2040 static void
2041 do_set_addrprop(int argc, char **argv, const char *use)
2042 {
2043 	set_addrprop(argc, argv, _B_FALSE, use);
2044 }
2045 
2046 /*
2047  * Resets a property to its default value on an address object.
2048  */
2049 static void
2050 do_reset_addrprop(int argc, char **argv, const char *use)
2051 {
2052 	set_addrprop(argc, argv,  _B_TRUE, use);
2053 }
2054 
2055 /*
2056  * Display information for all or specific address properties, either for a
2057  * given address or for all the addresses in the system.
2058  */
2059 static void
2060 do_show_addrprop(int argc, char *argv[], const char *use)
2061 {
2062 	int 			option;
2063 	nvlist_t 		*proplist = NULL;
2064 	char			*fields_str = NULL;
2065 	show_prop_state_t 	state;
2066 	ofmt_handle_t		ofmt;
2067 	ofmt_status_t		oferr;
2068 	uint_t			ofmtflags = 0;
2069 	char			*aobjname = NULL;
2070 	char			*ifname = NULL;
2071 	char			*cp;
2072 	ipadm_addr_info_t	*ainfop = NULL;
2073 	ipadm_addr_info_t	*ptr;
2074 	ipadm_status_t		status;
2075 	boolean_t		found = _B_FALSE;
2076 
2077 	opterr = 0;
2078 	bzero(&state, sizeof (state));
2079 	state.sps_propval = NULL;
2080 	state.sps_parsable = _B_FALSE;
2081 	state.sps_addrprop = _B_TRUE;
2082 	state.sps_proto = MOD_PROTO_NONE;
2083 	state.sps_status = state.sps_retstatus = IPADM_SUCCESS;
2084 	while ((option = getopt_long(argc, argv, ":p:i:cPo:",
2085 	    show_prop_longopts, NULL)) != -1) {
2086 		switch (option) {
2087 		case 'p':
2088 			if (ipadm_str2nvlist(optarg, &proplist,
2089 			    IPADM_NORVAL) != 0)
2090 				die("invalid addrobj properties specified");
2091 			break;
2092 		case 'c':
2093 			state.sps_parsable = _B_TRUE;
2094 			break;
2095 		case 'o':
2096 			fields_str = optarg;
2097 			break;
2098 		default:
2099 			die_opterr(optopt, option, use);
2100 			break;
2101 		}
2102 	}
2103 	if (optind == argc - 1) {
2104 		aobjname = argv[optind];
2105 		cp = strchr(aobjname, '/');
2106 		if (cp == NULL)
2107 			die("invalid addrobj name provided");
2108 		if (*(cp + 1) == '\0') {
2109 			ifname = aobjname;
2110 			*cp = '\0';
2111 			aobjname = NULL;
2112 		}
2113 	} else if (optind != argc) {
2114 		die("Usage: %s", use);
2115 	}
2116 	state.sps_proplist = proplist;
2117 	if (state.sps_parsable)
2118 		ofmtflags |= OFMT_PARSABLE;
2119 	oferr = ofmt_open(fields_str, addrprop_fields, ofmtflags, 0, &ofmt);
2120 	ipadm_ofmt_check(oferr, state.sps_parsable, ofmt);
2121 	state.sps_ofmt = ofmt;
2122 
2123 	status = ipadm_addr_info(iph, ifname, &ainfop, 0, LIFC_DEFAULT);
2124 	/* Return without printing any error, if no addresses were found */
2125 	if (status == IPADM_NOTFOUND)
2126 		return;
2127 	if (status != IPADM_SUCCESS)
2128 		die("error retrieving address: %s", ipadm_status2str(status));
2129 
2130 	for (ptr = ainfop; ptr != NULL; ptr = IA_NEXT(ptr)) {
2131 		char	*taobjname = ptr->ia_aobjname;
2132 
2133 		if (taobjname[0] == '\0')
2134 			continue;
2135 		if (aobjname != NULL) {
2136 			if (strcmp(aobjname, taobjname) == 0)
2137 				found = _B_TRUE;
2138 			else
2139 				continue;
2140 		}
2141 		if (ptr->ia_atype == IPADM_ADDR_IPV6_ADDRCONF) {
2142 			if (found)
2143 				break;
2144 			else
2145 				continue;
2146 		}
2147 		(void) strlcpy(state.sps_aobjname, taobjname,
2148 		    sizeof (state.sps_aobjname));
2149 		show_properties(&state, IPADMPROP_CLASS_ADDR);
2150 		if (found)
2151 			break;
2152 	}
2153 	ipadm_free_addr_info(ainfop);
2154 
2155 	if (aobjname != NULL && !found)
2156 		die("addrobj not found: %s", aobjname);
2157 
2158 	nvlist_free(proplist);
2159 	ofmt_close(ofmt);
2160 	if (state.sps_retstatus != IPADM_SUCCESS) {
2161 		ipadm_close(iph);
2162 		exit(EXIT_FAILURE);
2163 	}
2164 }
2165 
2166 static void
2167 ipadm_ofmt_check(ofmt_status_t oferr, boolean_t parsable,
2168     ofmt_handle_t ofmt)
2169 {
2170 	char buf[OFMT_BUFSIZE];
2171 
2172 	if (oferr == OFMT_SUCCESS)
2173 		return;
2174 	(void) ofmt_strerror(ofmt, oferr, buf, sizeof (buf));
2175 	/*
2176 	 * All errors are considered fatal in parsable mode.
2177 	 * NOMEM errors are always fatal, regardless of mode.
2178 	 * For other errors, we print diagnostics in human-readable
2179 	 * mode and processs what we can.
2180 	 */
2181 	if (parsable || oferr == OFMT_ENOFIELDS) {
2182 		ofmt_close(ofmt);
2183 		die(buf);
2184 	} else {
2185 		warn(buf);
2186 	}
2187 }
2188 
2189 /*
2190  * check if the `pstr' adheres to following syntax
2191  *	- prop=<value[,...]>	(for set)
2192  *	- prop			(for reset)
2193  */
2194 static void
2195 ipadm_check_propstr(const char *pstr, boolean_t reset, const char *use)
2196 {
2197 	char	*nv;
2198 
2199 	nv = strchr(pstr, '=');
2200 	if (reset) {
2201 		if (nv != NULL)
2202 			die("incorrect syntax used for -p.\n%s", use);
2203 	} else {
2204 		if (nv == NULL || *++nv == '\0')
2205 			die("please specify the value to be set.\n%s", use);
2206 		nv = strchr(nv, '=');
2207 		/* cannot have multiple 'prop=val' for single -p */
2208 		if (nv != NULL)
2209 			die("cannot specify more than one prop=val at "
2210 			    "a time.\n%s", use);
2211 	}
2212 }
2213