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