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