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