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