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