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