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