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