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