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