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