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