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