Merge remote-tracking branch 'origin/master'
[unleashed/lotheac.git] / usr / src / cmd / cmd-inet / usr.sbin / ipadm / ipadm.c
blob1232d3cb69279434f6617e8742bc052ebef63aa5
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 typedef struct cmd {
70 char *c_name;
71 cmdfunc_t *c_fn;
72 const char *c_usage;
73 } cmd_t;
75 static cmd_t cmds[] = {
76 /* interface management related sub-commands */
77 { "create-if", do_create_if, "\tcreate-if\t[-t] <interface>" },
78 { "disable-if", do_disable_if, "\tdisable-if\t-t <interface>" },
79 { "enable-if", do_enable_if, "\tenable-if\t-t <interface>" },
80 { "delete-if", do_delete_if, "\tdelete-if\t<interface>" },
81 { "show-if", do_show_if,
82 "\tshow-if\t\t[[-p] -o <field>,...] [<interface>]\n" },
83 { "set-ifprop", do_set_ifprop,
84 "\tset-ifprop\t[-t] -p <prop>=<value[,...]> -m <protocol> "
85 "<interface>" },
86 { "reset-ifprop", do_reset_ifprop,
87 "\treset-ifprop\t[-t] -p <prop> -m <protocol> <interface>" },
88 { "show-ifprop", do_show_ifprop,
89 "\tshow-ifprop\t[[-c] -o <field>,...] [-p <prop>,...]\n"
90 "\t\t\t[-m <protocol>] [interface]\n" },
92 /* address management related sub-commands */
93 { "create-addr", do_create_addr,
94 "\tcreate-addr\t[-t] -T static [-d] "
95 "-a{local|remote}=addr[/prefixlen]\n\t\t\t<addrobj>\n"
96 "\tcreate-addr\t[-t] -T dhcp [-w <seconds> | forever]\n"
97 "\t\t\t[-1] [-h <hostname>] <addrobj>\n"
98 "\tcreate-addr\t[-t] -T addrconf [-i interface-id]\n"
99 "\t\t\t[-p {stateful|stateless}={yes|no}] <addrobj>" },
100 { "down-addr", do_down_addr, "\tdown-addr\t[-t] <addrobj>" },
101 { "up-addr", do_up_addr, "\tup-addr\t\t[-t] <addrobj>" },
102 { "disable-addr", do_disable_addr, "\tdisable-addr\t-t <addrobj>" },
103 { "enable-addr", do_enable_addr, "\tenable-addr\t-t <addrobj>" },
104 { "refresh-addr", do_refresh_addr, "\trefresh-addr\t[-i] <addrobj>" },
105 { "delete-addr", do_delete_addr, "\tdelete-addr\t[-r] <addrobj>" },
106 { "show-addr", do_show_addr,
107 "\tshow-addr\t[[-p] -o <field>,...] [<addrobj>]\n" },
108 { "set-addrprop", do_set_addrprop,
109 "\tset-addrprop\t[-t] -p <prop>=<value[,...]> <addrobj>" },
110 { "reset-addrprop", do_reset_addrprop,
111 "\treset-addrprop\t[-t] -p <prop> <addrobj>" },
112 { "show-addrprop", do_show_addrprop,
113 "\tshow-addrprop\t[[-c] -o <field>,...] [-p <prop>,...] "
114 "<addrobj>\n" },
116 /* protocol properties related sub-commands */
117 { "set-prop", do_set_prop,
118 "\tset-prop\t[-t] -p <prop>[+|-]=<value[,...]> <protocol>" },
119 { "reset-prop", do_reset_prop,
120 "\treset-prop\t[-t] -p <prop> <protocol>" },
121 { "show-prop", do_show_prop,
122 "\tshow-prop\t[[-c] -o <field>,...] [-p <prop>,...]"
123 " [protocol]" }
126 static const struct option if_longopts[] = {
127 {"temporary", no_argument, 0, 't' },
128 { 0, 0, 0, 0 }
131 static const struct option show_prop_longopts[] = {
132 {"parsable", no_argument, 0, 'c' },
133 {"prop", required_argument, 0, 'p' },
134 {"output", required_argument, 0, 'o' },
135 { 0, 0, 0, 0 }
138 static const struct option show_ifprop_longopts[] = {
139 {"module", required_argument, 0, 'm' },
140 {"parsable", no_argument, 0, 'c' },
141 {"prop", required_argument, 0, 'p' },
142 {"output", required_argument, 0, 'o' },
143 { 0, 0, 0, 0 }
146 static const struct option set_prop_longopts[] = {
147 {"prop", required_argument, 0, 'p' },
148 {"temporary", no_argument, 0, 't' },
149 { 0, 0, 0, 0 }
152 static const struct option set_ifprop_longopts[] = {
153 {"module", required_argument, 0, 'm' },
154 {"prop", required_argument, 0, 'p' },
155 {"temporary", no_argument, 0, 't' },
156 { 0, 0, 0, 0 }
159 static const struct option addr_misc_longopts[] = {
160 {"inform", no_argument, 0, 'i' },
161 {"release", no_argument, 0, 'r' },
162 {"temporary", no_argument, 0, 't' },
163 { 0, 0, 0, 0 }
166 static const struct option addr_longopts[] = {
167 {"address", required_argument, 0, 'a' },
168 {"down", no_argument, 0, 'd' },
169 {"interface-id", required_argument, 0, 'i' },
170 {"primary", no_argument, 0, '1' },
171 {"prop", required_argument, 0, 'p' },
172 {"reqhost", required_argument, 0, 'h' },
173 {"temporary", no_argument, 0, 't' },
174 {"type", required_argument, 0, 'T' },
175 {"wait", required_argument, 0, 'w' },
176 { 0, 0, 0, 0 }
179 static const struct option show_addr_longopts[] = {
180 {"parsable", no_argument, 0, 'p' },
181 {"output", required_argument, 0, 'o' },
182 { 0, 0, 0, 0 }
185 static const struct option show_if_longopts[] = {
186 {"parsable", no_argument, 0, 'p' },
187 {"output", required_argument, 0, 'o' },
188 { 0, 0, 0, 0 }
191 /* callback functions to print show-* subcommands output */
192 static ofmt_cb_t print_prop_cb;
193 static ofmt_cb_t print_sa_cb;
194 static ofmt_cb_t print_si_cb;
196 /* structures for 'ipadm show-*' subcommands */
197 typedef enum {
198 IPADM_PROPFIELD_IFNAME,
199 IPADM_PROPFIELD_PROTO,
200 IPADM_PROPFIELD_ADDROBJ,
201 IPADM_PROPFIELD_PROPERTY,
202 IPADM_PROPFIELD_PERM,
203 IPADM_PROPFIELD_CURRENT,
204 IPADM_PROPFIELD_PERSISTENT,
205 IPADM_PROPFIELD_DEFAULT,
206 IPADM_PROPFIELD_POSSIBLE
207 } ipadm_propfield_index_t;
209 static ofmt_field_t intfprop_fields[] = {
210 /* name, field width, index, callback */
211 { "IFNAME", 12, IPADM_PROPFIELD_IFNAME, print_prop_cb},
212 { "PROPERTY", 16, IPADM_PROPFIELD_PROPERTY, print_prop_cb},
213 { "PROTO", 6, IPADM_PROPFIELD_PROTO, print_prop_cb},
214 { "PERM", 5, IPADM_PROPFIELD_PERM, print_prop_cb},
215 { "CURRENT", 11, IPADM_PROPFIELD_CURRENT, print_prop_cb},
216 { "PERSISTENT", 11, IPADM_PROPFIELD_PERSISTENT, print_prop_cb},
217 { "DEFAULT", 11, IPADM_PROPFIELD_DEFAULT, print_prop_cb},
218 { "POSSIBLE", 16, IPADM_PROPFIELD_POSSIBLE, print_prop_cb},
219 { NULL, 0, 0, NULL}
223 static ofmt_field_t modprop_fields[] = {
224 /* name, field width, index, callback */
225 { "PROTO", 6, IPADM_PROPFIELD_PROTO, print_prop_cb},
226 { "PROPERTY", 22, IPADM_PROPFIELD_PROPERTY, print_prop_cb},
227 { "PERM", 5, IPADM_PROPFIELD_PERM, print_prop_cb},
228 { "CURRENT", 13, IPADM_PROPFIELD_CURRENT, print_prop_cb},
229 { "PERSISTENT", 13, IPADM_PROPFIELD_PERSISTENT, print_prop_cb},
230 { "DEFAULT", 13, IPADM_PROPFIELD_DEFAULT, print_prop_cb},
231 { "POSSIBLE", 15, IPADM_PROPFIELD_POSSIBLE, print_prop_cb},
232 { NULL, 0, 0, NULL}
235 static ofmt_field_t addrprop_fields[] = {
236 /* name, field width, index, callback */
237 { "ADDROBJ", 18, IPADM_PROPFIELD_ADDROBJ, print_prop_cb},
238 { "PROPERTY", 11, IPADM_PROPFIELD_PROPERTY, print_prop_cb},
239 { "PERM", 5, IPADM_PROPFIELD_PERM, print_prop_cb},
240 { "CURRENT", 16, IPADM_PROPFIELD_CURRENT, print_prop_cb},
241 { "PERSISTENT", 16, IPADM_PROPFIELD_PERSISTENT, print_prop_cb},
242 { "DEFAULT", 16, IPADM_PROPFIELD_DEFAULT, print_prop_cb},
243 { "POSSIBLE", 15, IPADM_PROPFIELD_POSSIBLE, print_prop_cb},
244 { NULL, 0, 0, NULL}
247 typedef struct show_prop_state {
248 char sps_ifname[LIFNAMSIZ];
249 char sps_aobjname[IPADM_AOBJSIZ];
250 const char *sps_pname;
251 uint_t sps_proto;
252 char *sps_propval;
253 nvlist_t *sps_proplist;
254 boolean_t sps_parsable;
255 boolean_t sps_addrprop;
256 boolean_t sps_ifprop;
257 boolean_t sps_modprop;
258 ipadm_status_t sps_status;
259 ipadm_status_t sps_retstatus;
260 ofmt_handle_t sps_ofmt;
261 } show_prop_state_t;
263 typedef struct show_addr_state {
264 boolean_t sa_parsable;
265 boolean_t sa_persist;
266 ofmt_handle_t sa_ofmt;
267 } show_addr_state_t;
269 typedef struct show_if_state {
270 boolean_t si_parsable;
271 ofmt_handle_t si_ofmt;
272 } show_if_state_t;
274 typedef struct show_addr_args_s {
275 show_addr_state_t *sa_state;
276 ipadm_addr_info_t *sa_info;
277 } show_addr_args_t;
279 typedef struct show_if_args_s {
280 show_if_state_t *si_state;
281 ipadm_if_info_t *si_info;
282 } show_if_args_t;
284 typedef enum {
285 SA_ADDROBJ,
286 SA_TYPE,
287 SA_STATE,
288 SA_CURRENT,
289 SA_PERSISTENT,
290 SA_ADDR
291 } sa_field_index_t;
293 typedef enum {
294 SI_IFNAME,
295 SI_STATE,
296 SI_CURRENT,
297 SI_PERSISTENT
298 } si_field_index_t;
300 static ofmt_field_t show_addr_fields[] = {
301 /* name, field width, id, callback */
302 { "ADDROBJ", 18, SA_ADDROBJ, print_sa_cb},
303 { "TYPE", 9, SA_TYPE, print_sa_cb},
304 { "STATE", 13, SA_STATE, print_sa_cb},
305 { "CURRENT", 8, SA_CURRENT, print_sa_cb},
306 { "PERSISTENT", 11, SA_PERSISTENT, print_sa_cb},
307 { "ADDR", 46, SA_ADDR, print_sa_cb},
308 { NULL, 0, 0, NULL}
311 static ofmt_field_t show_if_fields[] = {
312 /* name, field width, id, callback */
313 { "IFNAME", 11, SI_IFNAME, print_si_cb},
314 { "STATE", 9, SI_STATE, print_si_cb},
315 { "CURRENT", 13, SI_CURRENT, print_si_cb},
316 { "PERSISTENT", 11, SI_PERSISTENT, print_si_cb},
317 { NULL, 0, 0, NULL}
320 #define IPADM_ALL_BITS ((uint_t)-1)
321 typedef struct intf_mask {
322 char *name;
323 uint64_t bits;
324 uint64_t mask;
325 } fmask_t;
328 * Handle to libipadm. Opened in main() before the sub-command specific
329 * function is called and is closed before the program exits.
331 ipadm_handle_t iph = NULL;
334 * Opaque ipadm address object. Used by all the address management subcommands.
336 ipadm_addrobj_t ipaddr = NULL;
338 static char *progname;
341 static void warn(const char *, ...);
342 static void die(const char *, ...) __NORETURN;
343 static void die_opterr(int, int, const char *) __NORETURN;
344 static void warn_ipadmerr(ipadm_status_t, const char *, ...);
345 static void ipadm_check_propstr(const char *, boolean_t, const char *);
346 static void process_misc_addrargs(int, char **, const char *, int *,
347 uint32_t *);
349 static void
350 usage(void)
352 int i;
353 cmd_t *cmdp;
355 (void) fprintf(stderr,
356 gettext("usage: ipadm <subcommand> <args> ...\n"));
357 for (i = 0; i < sizeof (cmds) / sizeof (cmds[0]); i++) {
358 cmdp = &cmds[i];
359 if (cmdp->c_usage != NULL)
360 (void) fprintf(stderr, "%s\n", gettext(cmdp->c_usage));
363 ipadm_destroy_addrobj(ipaddr);
364 ipadm_close(iph);
365 exit(1);
369 main(int argc, char *argv[])
371 int i;
372 cmd_t *cmdp;
373 ipadm_status_t status;
375 (void) setlocale(LC_ALL, "");
376 (void) textdomain(TEXT_DOMAIN);
378 if ((progname = strrchr(argv[0], '/')) == NULL)
379 progname = argv[0];
380 else
381 progname++;
383 status = ipadm_open(&iph, 0);
384 if (status != IPADM_SUCCESS) {
385 die("Could not open handle to library - %s",
386 ipadm_status2str(status));
389 if (argc < 2) {
390 char *args = "show-addr";
391 do_show_addr(1, &args, args);
392 ipadm_close(iph);
393 return (0);
396 for (i = 0; i < sizeof (cmds) / sizeof (cmds[0]); i++) {
397 cmdp = &cmds[i];
398 if (strcmp(argv[1], cmdp->c_name) == 0) {
399 cmdp->c_fn(argc - 1, &argv[1], gettext(cmdp->c_usage));
400 ipadm_destroy_addrobj(ipaddr);
401 ipadm_close(iph);
402 exit(0);
406 (void) fprintf(stderr, gettext("%s: unknown subcommand '%s'\n"),
407 progname, argv[1]);
408 usage();
410 return (0);
414 * Create an IP interface for which no saved configuration exists in the
415 * persistent store.
417 static void
418 do_create_if(int argc, char *argv[], const char *use)
420 ipadm_status_t status;
421 int option;
422 uint32_t flags = IPADM_OPT_PERSIST|IPADM_OPT_ACTIVE;
424 opterr = 0;
425 while ((option = getopt_long(argc, argv, ":t", if_longopts,
426 NULL)) != -1) {
427 switch (option) {
428 case 't':
430 * "ifconfig" mode - plumb interface, but do not
431 * restore settings that may exist in db.
433 flags &= ~IPADM_OPT_PERSIST;
434 break;
435 default:
436 die_opterr(optopt, option, use);
439 if (optind != (argc - 1))
440 die("Usage: %s", use);
441 status = ipadm_create_if(iph, argv[optind], AF_UNSPEC, flags);
442 if (status != IPADM_SUCCESS) {
443 die("Could not create %s : %s",
444 argv[optind], ipadm_status2str(status));
449 * Enable an IP interface based on the persistent configuration for
450 * that interface.
452 static void
453 do_enable_if(int argc, char *argv[], const char *use)
455 ipadm_status_t status;
456 int index;
457 uint32_t flags = IPADM_OPT_ACTIVE|IPADM_OPT_PERSIST;
459 process_misc_addrargs(argc, argv, use, &index, &flags);
460 if (flags & IPADM_OPT_PERSIST)
461 die("persistent operation not supported for enable-if");
462 status = ipadm_enable_if(iph, argv[index], flags);
463 if (status == IPADM_ALL_ADDRS_NOT_ENABLED) {
464 warn_ipadmerr(status, "");
465 } else if (status != IPADM_SUCCESS) {
466 die("Could not enable %s : %s",
467 argv[optind], ipadm_status2str(status));
472 * Remove an IP interface from both active and persistent configuration.
474 static void
475 do_delete_if(int argc, char *argv[], const char *use)
477 ipadm_status_t status;
478 uint32_t flags = IPADM_OPT_ACTIVE|IPADM_OPT_PERSIST;
480 if (argc != 2)
481 die("Usage: %s", use);
483 status = ipadm_delete_if(iph, argv[1], AF_UNSPEC, flags);
484 if (status != IPADM_SUCCESS) {
485 die("Could not delete %s: %s",
486 argv[optind], ipadm_status2str(status));
491 * Disable an IP interface by removing it from active configuration.
493 static void
494 do_disable_if(int argc, char *argv[], const char *use)
496 ipadm_status_t status;
497 int index;
498 uint32_t flags = IPADM_OPT_ACTIVE|IPADM_OPT_PERSIST;
500 process_misc_addrargs(argc, argv, use, &index, &flags);
501 if (flags & IPADM_OPT_PERSIST)
502 die("persistent operation not supported for disable-if");
503 status = ipadm_disable_if(iph, argv[index], flags);
504 if (status != IPADM_SUCCESS) {
505 die("Could not disable %s: %s",
506 argv[optind], ipadm_status2str(status));
511 * Print individual columns for the show-*prop subcommands.
513 static void
514 print_prop(show_prop_state_t *statep, uint_t flags, char *buf, size_t bufsize)
516 const char *prop_name = statep->sps_pname;
517 char *ifname = statep->sps_ifname;
518 char *propval = statep->sps_propval;
519 uint_t proto = statep->sps_proto;
520 size_t propsize = MAXPROPVALLEN;
521 ipadm_status_t status;
523 if (statep->sps_ifprop) {
524 status = ipadm_get_ifprop(iph, ifname, prop_name, propval,
525 &propsize, proto, flags);
526 } else if (statep->sps_modprop) {
527 status = ipadm_get_prop(iph, prop_name, propval, &propsize,
528 proto, flags);
529 } else {
530 status = ipadm_get_addrprop(iph, prop_name, propval, &propsize,
531 statep->sps_aobjname, flags);
534 if (status != IPADM_SUCCESS) {
535 if ((status == IPADM_NOTFOUND && (flags & IPADM_OPT_PERSIST)) ||
536 status == IPADM_ENXIO) {
537 propval[0] = '\0';
538 goto cont;
540 statep->sps_status = status;
541 statep->sps_retstatus = status;
542 return;
544 cont:
545 statep->sps_status = IPADM_SUCCESS;
546 (void) snprintf(buf, bufsize, "%s", propval);
550 * Callback function for show-*prop subcommands.
552 static boolean_t
553 print_prop_cb(ofmt_arg_t *ofarg, char *buf, size_t bufsize)
555 show_prop_state_t *statep = ofarg->ofmt_cbarg;
556 const char *propname = statep->sps_pname;
557 uint_t proto = statep->sps_proto;
558 boolean_t cont = B_TRUE;
561 * Fail retrieving remaining fields, if you fail
562 * to retrieve a field.
564 if (statep->sps_status != IPADM_SUCCESS)
565 return (B_FALSE);
567 switch (ofarg->ofmt_id) {
568 case IPADM_PROPFIELD_IFNAME:
569 (void) snprintf(buf, bufsize, "%s", statep->sps_ifname);
570 break;
571 case IPADM_PROPFIELD_PROTO:
572 (void) snprintf(buf, bufsize, "%s", ipadm_proto2str(proto));
573 break;
574 case IPADM_PROPFIELD_ADDROBJ:
575 (void) snprintf(buf, bufsize, "%s", statep->sps_aobjname);
576 break;
577 case IPADM_PROPFIELD_PROPERTY:
578 (void) snprintf(buf, bufsize, "%s", propname);
579 break;
580 case IPADM_PROPFIELD_PERM:
581 print_prop(statep, IPADM_OPT_PERM, buf, bufsize);
582 break;
583 case IPADM_PROPFIELD_CURRENT:
584 print_prop(statep, IPADM_OPT_ACTIVE, buf, bufsize);
585 break;
586 case IPADM_PROPFIELD_PERSISTENT:
587 print_prop(statep, IPADM_OPT_PERSIST, buf, bufsize);
588 break;
589 case IPADM_PROPFIELD_DEFAULT:
590 print_prop(statep, IPADM_OPT_DEFAULT, buf, bufsize);
591 break;
592 case IPADM_PROPFIELD_POSSIBLE:
593 print_prop(statep, IPADM_OPT_POSSIBLE, buf, bufsize);
594 break;
596 if (statep->sps_status != IPADM_SUCCESS)
597 cont = B_FALSE;
598 return (cont);
602 * Callback function called by the property walker (ipadm_walk_prop() or
603 * ipadm_walk_proptbl()), for every matched property. This function in turn
604 * calls ofmt_print() to print property information.
606 boolean_t
607 show_property(void *arg, const char *pname, uint_t proto)
609 show_prop_state_t *statep = arg;
611 statep->sps_pname = pname;
612 statep->sps_proto = proto;
613 statep->sps_status = IPADM_SUCCESS;
614 ofmt_print(statep->sps_ofmt, arg);
617 * if an object is not found or operation is not supported then
618 * stop the walker.
620 if (statep->sps_status == IPADM_NOTFOUND ||
621 statep->sps_status == IPADM_NOTSUP)
622 return (B_FALSE);
623 return (B_TRUE);
627 * Properties to be displayed is in `statep->sps_proplist'. If it is NULL,
628 * for all the properties for the specified object, display relevant
629 * information. Otherwise, for the selected property set, display relevant
630 * information
632 static void
633 show_properties(void *arg, int prop_class)
635 show_prop_state_t *statep = arg;
636 nvlist_t *nvl = statep->sps_proplist;
637 uint_t proto = statep->sps_proto;
638 nvpair_t *curr_nvp;
639 char *buf, *name;
640 ipadm_status_t status;
642 /* allocate sufficient buffer to hold a property value */
643 if ((buf = malloc(MAXPROPVALLEN)) == NULL)
644 die("insufficient memory");
645 statep->sps_propval = buf;
647 /* if no properties were specified, display all the properties */
648 if (nvl == NULL) {
649 (void) ipadm_walk_proptbl(proto, prop_class, show_property,
650 statep);
651 } else {
652 for (curr_nvp = nvlist_next_nvpair(nvl, NULL); curr_nvp;
653 curr_nvp = nvlist_next_nvpair(nvl, curr_nvp)) {
654 name = nvpair_name(curr_nvp);
655 status = ipadm_walk_prop(name, proto, prop_class,
656 show_property, statep);
657 if (status == IPADM_PROP_UNKNOWN)
658 (void) show_property(statep, name, proto);
662 free(buf);
666 * Display information for all or specific interface properties, either for a
667 * given interface or for all the interfaces in the system.
669 static void
670 do_show_ifprop(int argc, char **argv, const char *use)
672 int option;
673 nvlist_t *proplist = NULL;
674 char *fields_str = NULL;
675 char *ifname;
676 ofmt_handle_t ofmt;
677 ofmt_status_t oferr;
678 uint_t ofmtflags = 0;
679 uint_t proto;
680 boolean_t m_arg = B_FALSE;
681 char *protostr;
682 ipadm_if_info_t *ifinfo, *ifp;
683 ipadm_status_t status;
684 show_prop_state_t state;
686 protostr = "ip";
687 opterr = 0;
688 bzero(&state, sizeof (state));
689 state.sps_propval = NULL;
690 state.sps_parsable = B_FALSE;
691 state.sps_ifprop = B_TRUE;
692 state.sps_status = state.sps_retstatus = IPADM_SUCCESS;
693 while ((option = getopt_long(argc, argv, ":p:m:co:",
694 show_ifprop_longopts, NULL)) != -1) {
695 switch (option) {
696 case 'p':
697 if (ipadm_str2nvlist(optarg, &proplist,
698 IPADM_NORVAL) != 0)
699 die("invalid interface properties specified");
700 break;
701 case 'c':
702 state.sps_parsable = B_TRUE;
703 break;
704 case 'o':
705 fields_str = optarg;
706 break;
707 case 'm':
708 if (m_arg)
709 die("cannot specify more than one -m");
710 m_arg = B_TRUE;
711 protostr = optarg;
712 break;
713 default:
714 die_opterr(optopt, option, use);
715 break;
719 if (optind == argc - 1)
720 ifname = argv[optind];
721 else if (optind != argc)
722 die("Usage: %s", use);
723 else
724 ifname = NULL;
726 if ((proto = ipadm_str2proto(protostr)) == MOD_PROTO_NONE)
727 die("invalid protocol '%s' specified", protostr);
729 state.sps_proto = proto;
730 state.sps_proplist = proplist;
732 if (state.sps_parsable)
733 ofmtflags |= OFMT_PARSABLE;
734 oferr = ofmt_open(fields_str, intfprop_fields, ofmtflags, 0, &ofmt);
735 ofmt_check(oferr, state.sps_parsable, ofmt, die, warn);
736 state.sps_ofmt = ofmt;
738 /* retrieve interface(s) and print the properties */
739 status = ipadm_if_info(iph, ifname, &ifinfo, 0, LIFC_DEFAULT);
740 if (ifname != NULL && status == IPADM_ENXIO)
741 die("no such object '%s': %s", ifname,
742 ipadm_status2str(status));
743 if (status != IPADM_SUCCESS)
744 die("Error retrieving interface(s): %s",
745 ipadm_status2str(status));
746 for (ifp = ifinfo; ifp; ifp = ifp->ifi_next) {
747 (void) strlcpy(state.sps_ifname, ifp->ifi_name, LIFNAMSIZ);
748 state.sps_proto = proto;
749 show_properties(&state, IPADMPROP_CLASS_IF);
751 if (ifinfo)
752 ipadm_free_if_info(ifinfo);
754 nvlist_free(proplist);
755 ofmt_close(ofmt);
757 if (state.sps_retstatus != IPADM_SUCCESS) {
758 ipadm_close(iph);
759 exit(EXIT_FAILURE);
764 * set/reset the interface property for a given interface.
766 static void
767 set_ifprop(int argc, char **argv, boolean_t reset, const char *use)
769 int option;
770 ipadm_status_t status = IPADM_SUCCESS;
771 boolean_t p_arg = B_FALSE;
772 boolean_t m_arg = B_FALSE;
773 char *ifname, *nv, *protostr;
774 char *prop_name, *prop_val;
775 uint_t flags = IPADM_OPT_PERSIST;
776 uint_t proto;
778 nv = NULL;
779 protostr = NULL;
780 opterr = 0;
781 while ((option = getopt_long(argc, argv, ":m:p:t",
782 set_ifprop_longopts, NULL)) != -1) {
783 switch (option) {
784 case 'p':
785 if (p_arg)
786 die("-p must be specified once only");
787 p_arg = B_TRUE;
789 ipadm_check_propstr(optarg, reset, use);
790 nv = optarg;
791 break;
792 case 'm':
793 if (m_arg)
794 die("-m must be specified once only");
795 m_arg = B_TRUE;
796 protostr = optarg;
797 break;
798 case 't':
799 flags &= ~IPADM_OPT_PERSIST;
800 break;
801 default:
802 die_opterr(optopt, option, use);
806 if (!m_arg || !p_arg || optind != argc - 1)
807 die("Usage: %s", use);
809 ifname = argv[optind];
811 prop_name = nv;
812 prop_val = strchr(nv, '=');
813 if (prop_val != NULL)
814 *prop_val++ = '\0';
816 if ((proto = ipadm_str2proto(protostr)) == MOD_PROTO_NONE)
817 die("invalid protocol '%s' specified", protostr);
819 if (reset)
820 flags |= IPADM_OPT_DEFAULT;
821 else
822 flags |= IPADM_OPT_ACTIVE;
823 status = ipadm_set_ifprop(iph, ifname, prop_name, prop_val, proto,
824 flags);
826 if (status != IPADM_SUCCESS) {
827 if (reset)
828 die("reset-ifprop: %s: %s",
829 prop_name, ipadm_status2str(status));
830 else
831 die("set-ifprop: %s: %s",
832 prop_name, ipadm_status2str(status));
836 static void
837 do_set_ifprop(int argc, char **argv, const char *use)
839 set_ifprop(argc, argv, B_FALSE, use);
842 static void
843 do_reset_ifprop(int argc, char **argv, const char *use)
845 set_ifprop(argc, argv, B_TRUE, use);
849 * Display information for all or specific protocol properties, either for a
850 * given protocol or for supported protocols (IP/IPv4/IPv6/TCP/UDP/SCTP)
852 static void
853 do_show_prop(int argc, char **argv, const char *use)
855 char option;
856 nvlist_t *proplist = NULL;
857 char *fields_str = NULL;
858 char *protostr;
859 show_prop_state_t state;
860 ofmt_handle_t ofmt;
861 ofmt_status_t oferr;
862 uint_t ofmtflags = 0;
863 uint_t proto;
864 boolean_t p_arg = B_FALSE;
866 opterr = 0;
867 bzero(&state, sizeof (state));
868 state.sps_propval = NULL;
869 state.sps_parsable = B_FALSE;
870 state.sps_modprop = B_TRUE;
871 state.sps_status = state.sps_retstatus = IPADM_SUCCESS;
872 while ((option = getopt_long(argc, argv, ":p:co:", show_prop_longopts,
873 NULL)) != -1) {
874 switch (option) {
875 case 'p':
876 if (p_arg)
877 die("-p must be specified once only");
878 p_arg = B_TRUE;
879 if (ipadm_str2nvlist(optarg, &proplist,
880 IPADM_NORVAL) != 0)
881 die("invalid protocol properties specified");
882 break;
883 case 'c':
884 state.sps_parsable = B_TRUE;
885 break;
886 case 'o':
887 fields_str = optarg;
888 break;
889 default:
890 die_opterr(optopt, option, use);
891 break;
894 if (optind == argc - 1) {
895 protostr = argv[optind];
896 if ((proto = ipadm_str2proto(protostr)) == MOD_PROTO_NONE)
897 die("invalid protocol '%s' specified", protostr);
898 state.sps_proto = proto;
899 } else if (optind != argc) {
900 die("Usage: %s", use);
901 } else {
902 if (p_arg)
903 die("protocol must be specified when "
904 "property name is used");
905 state.sps_proto = MOD_PROTO_NONE;
908 state.sps_proplist = proplist;
910 if (state.sps_parsable)
911 ofmtflags |= OFMT_PARSABLE;
912 else
913 ofmtflags |= OFMT_WRAP;
914 oferr = ofmt_open(fields_str, modprop_fields, ofmtflags, 0, &ofmt);
915 ofmt_check(oferr, state.sps_parsable, ofmt, die, warn);
916 state.sps_ofmt = ofmt;
918 /* handles all the errors */
919 show_properties(&state, IPADMPROP_CLASS_MODULE);
921 nvlist_free(proplist);
922 ofmt_close(ofmt);
924 if (state.sps_retstatus != IPADM_SUCCESS) {
925 ipadm_close(iph);
926 exit(EXIT_FAILURE);
931 * Checks to see if there are any modifiers, + or -. If there are modifiers
932 * then sets IPADM_OPT_APPEND or IPADM_OPT_REMOVE, accordingly.
934 static void
935 parse_modifiers(const char *pstr, uint_t *flags, const char *use)
937 char *p;
939 if ((p = strchr(pstr, '=')) == NULL)
940 return;
942 if (p == pstr)
943 die("Invalid prop=val specified\n%s", use);
945 --p;
946 if (*p == '+')
947 *flags |= IPADM_OPT_APPEND;
948 else if (*p == '-')
949 *flags |= IPADM_OPT_REMOVE;
953 * set/reset the protocol property for a given protocol.
955 static void
956 set_prop(int argc, char **argv, boolean_t reset, const char *use)
958 int option;
959 ipadm_status_t status = IPADM_SUCCESS;
960 char *protostr, *nv, *prop_name, *prop_val;
961 boolean_t p_arg = B_FALSE;
962 uint_t proto;
963 uint_t flags = IPADM_OPT_PERSIST;
965 nv = NULL;
966 opterr = 0;
967 while ((option = getopt_long(argc, argv, ":p:t", set_prop_longopts,
968 NULL)) != -1) {
969 switch (option) {
970 case 'p':
971 if (p_arg)
972 die("-p must be specified once only");
973 p_arg = B_TRUE;
975 ipadm_check_propstr(optarg, reset, use);
976 nv = optarg;
977 break;
978 case 't':
979 flags &= ~IPADM_OPT_PERSIST;
980 break;
981 default:
982 die_opterr(optopt, option, use);
986 if (!p_arg || optind != argc - 1)
987 die("Usage: %s", use);
989 parse_modifiers(nv, &flags, use);
990 prop_name = nv;
991 prop_val = strchr(nv, '=');
992 if (prop_val != NULL) {
993 if (flags & (IPADM_OPT_APPEND|IPADM_OPT_REMOVE))
994 *(prop_val - 1) = '\0';
995 *prop_val++ = '\0';
997 protostr = argv[optind];
998 if ((proto = ipadm_str2proto(protostr)) == MOD_PROTO_NONE)
999 die("invalid protocol '%s' specified", protostr);
1001 if (reset)
1002 flags |= IPADM_OPT_DEFAULT;
1003 else
1004 flags |= IPADM_OPT_ACTIVE;
1005 status = ipadm_set_prop(iph, prop_name, prop_val, proto, flags);
1007 if (status != IPADM_SUCCESS) {
1008 if (reset)
1009 die("reset-prop: %s: %s",
1010 prop_name, ipadm_status2str(status));
1011 else
1012 die("set-prop: %s: %s",
1013 prop_name, ipadm_status2str(status));
1017 static void
1018 do_set_prop(int argc, char **argv, const char *use)
1020 set_prop(argc, argv, B_FALSE, use);
1023 static void
1024 do_reset_prop(int argc, char **argv, const char *use)
1026 set_prop(argc, argv, B_TRUE, use);
1029 /* PRINTFLIKE1 */
1030 static void
1031 warn(const char *format, ...)
1033 va_list alist;
1035 format = gettext(format);
1036 (void) fprintf(stderr, gettext("%s: warning: "), progname);
1038 va_start(alist, format);
1039 (void) vfprintf(stderr, format, alist);
1040 va_end(alist);
1042 (void) fprintf(stderr, "\n");
1045 /* PRINTFLIKE1 */
1046 static void
1047 die(const char *format, ...)
1049 va_list alist;
1051 format = gettext(format);
1052 (void) fprintf(stderr, "%s: ", progname);
1054 va_start(alist, format);
1055 (void) vfprintf(stderr, format, alist);
1056 va_end(alist);
1058 (void) putchar('\n');
1060 ipadm_destroy_addrobj(ipaddr);
1061 ipadm_close(iph);
1062 exit(EXIT_FAILURE);
1065 static void
1066 die_opterr(int opt, int opterr, const char *usage)
1068 switch (opterr) {
1069 case ':':
1070 die("option '-%c' requires a value\nusage: %s", opt,
1071 gettext(usage));
1072 break;
1073 case '?':
1074 default:
1075 die("unrecognized option '-%c'\nusage: %s", opt,
1076 gettext(usage));
1077 break;
1081 /* PRINTFLIKE2 */
1082 static void
1083 warn_ipadmerr(ipadm_status_t err, const char *format, ...)
1085 va_list alist;
1087 format = gettext(format);
1088 (void) fprintf(stderr, gettext("%s: warning: "), progname);
1090 va_start(alist, format);
1091 (void) vfprintf(stderr, format, alist);
1092 va_end(alist);
1094 (void) fprintf(stderr, "%s\n", ipadm_status2str(err));
1097 static void
1098 process_static_addrargs(const char *use, char *addrarg, const char *aobjname)
1100 int option;
1101 char *val;
1102 char *laddr = NULL;
1103 char *raddr = NULL;
1104 char *save_input_arg = addrarg;
1105 boolean_t found_mismatch = B_FALSE;
1106 ipadm_status_t status;
1107 enum { A_LOCAL, A_REMOTE };
1108 static char *addr_optstr[] = {
1109 "local",
1110 "remote",
1111 NULL,
1114 while (*addrarg != '\0') {
1115 option = getsubopt(&addrarg, addr_optstr, &val);
1116 switch (option) {
1117 case A_LOCAL:
1118 if (laddr != NULL)
1119 die("Multiple local addresses provided");
1120 laddr = val;
1121 break;
1122 case A_REMOTE:
1123 if (raddr != NULL)
1124 die("Multiple remote addresses provided");
1125 raddr = val;
1126 break;
1127 default:
1128 if (found_mismatch)
1129 die("Invalid address provided\nusage: %s", use);
1130 found_mismatch = B_TRUE;
1131 break;
1134 if (raddr != NULL && laddr == NULL)
1135 die("Missing local address\nusage: %s", use);
1137 /* If only one address is provided, it is assumed a local address. */
1138 if (laddr == NULL) {
1139 if (found_mismatch)
1140 laddr = save_input_arg;
1141 else
1142 die("Missing local address\nusage: %s", use);
1145 /* Initialize the addrobj for static addresses. */
1146 status = ipadm_create_addrobj(IPADM_ADDR_STATIC, aobjname, &ipaddr);
1147 if (status != IPADM_SUCCESS) {
1148 die("Error in creating address object: %s",
1149 ipadm_status2str(status));
1152 /* Set the local and remote addresses */
1153 status = ipadm_set_addr(ipaddr, laddr, AF_UNSPEC);
1154 if (status != IPADM_SUCCESS) {
1155 die("Error in setting local address: %s",
1156 ipadm_status2str(status));
1158 if (raddr != NULL) {
1159 status = ipadm_set_dst_addr(ipaddr, raddr, AF_UNSPEC);
1160 if (status != IPADM_SUCCESS) {
1161 die("Error in setting remote address: %s",
1162 ipadm_status2str(status));
1167 static void
1168 process_addrconf_addrargs(const char *use, char *addrarg)
1170 int option;
1171 char *val;
1172 enum { P_STATELESS, P_STATEFUL };
1173 static char *addr_optstr[] = {
1174 "stateless",
1175 "stateful",
1176 NULL,
1178 boolean_t stateless = B_FALSE;
1179 boolean_t stateless_arg = B_FALSE;
1180 boolean_t stateful = B_FALSE;
1181 boolean_t stateful_arg = B_FALSE;
1182 ipadm_status_t status;
1184 while (*addrarg != '\0') {
1185 option = getsubopt(&addrarg, addr_optstr, &val);
1186 switch (option) {
1187 case P_STATELESS:
1188 if (stateless_arg)
1189 die("Duplicate option");
1190 if (val == NULL)
1191 die("Invalid argument");
1192 if (strcmp(val, "yes") == 0)
1193 stateless = B_TRUE;
1194 else if (strcmp(val, "no") == 0)
1195 stateless = B_FALSE;
1196 else
1197 die("Invalid argument");
1198 stateless_arg = B_TRUE;
1199 break;
1200 case P_STATEFUL:
1201 if (stateful_arg)
1202 die("Duplicate option");
1203 if (val == NULL)
1204 die("Invalid argument");
1205 if (strcmp(val, "yes") == 0)
1206 stateful = B_TRUE;
1207 else if (strcmp(val, "no") == 0)
1208 stateful = B_FALSE;
1209 else
1210 die("Invalid argument");
1211 stateful_arg = B_TRUE;
1212 break;
1213 default:
1214 die_opterr(optopt, option, use);
1218 if (!stateless_arg && !stateful_arg)
1219 die("Invalid arguments for option -p");
1221 /* Set the addrobj fields for addrconf */
1222 if (stateless_arg) {
1223 status = ipadm_set_stateless(ipaddr, stateless);
1224 if (status != IPADM_SUCCESS) {
1225 die("Error in setting stateless option: %s",
1226 ipadm_status2str(status));
1229 if (stateful_arg) {
1230 status = ipadm_set_stateful(ipaddr, stateful);
1231 if (status != IPADM_SUCCESS) {
1232 die("Error in setting stateful option: %s",
1233 ipadm_status2str(status));
1239 * Creates static, dhcp or addrconf addresses and associates the created
1240 * addresses with the specified address object name.
1242 static void
1243 do_create_addr(int argc, char *argv[], const char *use)
1245 ipadm_status_t status;
1246 int option;
1247 uint32_t flags =
1248 IPADM_OPT_PERSIST|IPADM_OPT_ACTIVE|IPADM_OPT_UP|IPADM_OPT_V46;
1249 char *cp;
1250 char *atype = NULL;
1251 char *static_arg = NULL;
1252 char *addrconf_arg = NULL;
1253 char *interface_id = NULL;
1254 char *wait = NULL;
1255 char *reqhost = NULL;
1256 boolean_t s_opt = B_FALSE; /* static addr options */
1257 boolean_t auto_opt = B_FALSE; /* Addrconf options */
1258 boolean_t dhcp_opt = B_FALSE; /* dhcp options */
1259 boolean_t primary_opt = B_FALSE; /* dhcp primary option */
1261 opterr = 0;
1262 while ((option = getopt_long(argc, argv, ":1T:a:dh:i:p:w:t",
1263 addr_longopts, NULL)) != -1) {
1264 switch (option) {
1265 case '1':
1266 primary_opt = B_TRUE;
1267 break;
1268 case 'T':
1269 atype = optarg;
1270 break;
1271 case 'a':
1272 static_arg = optarg;
1273 s_opt = B_TRUE;
1274 break;
1275 case 'd':
1276 flags &= ~IPADM_OPT_UP;
1277 s_opt = B_TRUE;
1278 break;
1279 case 'h':
1280 reqhost = optarg;
1281 break;
1282 case 'i':
1283 interface_id = optarg;
1284 auto_opt = B_TRUE;
1285 break;
1286 case 'p':
1287 addrconf_arg = optarg;
1288 auto_opt = B_TRUE;
1289 break;
1290 case 'w':
1291 wait = optarg;
1292 dhcp_opt = B_TRUE;
1293 break;
1294 case 't':
1295 flags &= ~IPADM_OPT_PERSIST;
1296 break;
1297 default:
1298 die_opterr(optopt, option, use);
1301 if (atype == NULL || optind != (argc - 1)) {
1302 die("Invalid arguments\nusage: %s", use);
1303 } else if ((cp = strchr(argv[optind], '/')) == NULL ||
1304 strlen(++cp) == 0) {
1305 die("invalid address object name: %s\nusage: %s",
1306 argv[optind], use);
1310 * Allocate and initialize the addrobj based on the address type.
1312 if (strcmp(atype, "static") == 0) {
1313 if (static_arg == NULL || auto_opt || dhcp_opt ||
1314 reqhost != NULL || primary_opt) {
1315 die("Invalid arguments for type %s\nusage: %s",
1316 atype, use);
1318 process_static_addrargs(use, static_arg, argv[optind]);
1319 } else if (strcmp(atype, "dhcp") == 0) {
1320 if (auto_opt || s_opt) {
1321 die("Invalid arguments for type %s\nusage: %s",
1322 atype, use);
1325 /* Initialize the addrobj for dhcp addresses. */
1326 status = ipadm_create_addrobj(IPADM_ADDR_DHCP, argv[optind],
1327 &ipaddr);
1328 if (status != IPADM_SUCCESS) {
1329 die("Error in creating address object: %s",
1330 ipadm_status2str(status));
1332 if (wait != NULL) {
1333 int32_t ipadm_wait;
1335 if (strcmp(wait, "forever") == 0) {
1336 ipadm_wait = IPADM_DHCP_WAIT_FOREVER;
1337 } else {
1338 char *end;
1339 long timeout = strtol(wait, &end, 10);
1341 if (*end != '\0' || timeout < 0)
1342 die("Invalid argument");
1343 ipadm_wait = (int32_t)timeout;
1345 status = ipadm_set_wait_time(ipaddr, ipadm_wait);
1346 if (status != IPADM_SUCCESS) {
1347 die("Error in setting wait time: %s",
1348 ipadm_status2str(status));
1351 if (primary_opt) {
1352 status = ipadm_set_primary(ipaddr, B_TRUE);
1353 if (status != IPADM_SUCCESS) {
1354 die("Error in setting primary flag: %s",
1355 ipadm_status2str(status));
1358 if (reqhost != NULL) {
1359 status = ipadm_set_reqhost(ipaddr, reqhost);
1360 if (status != IPADM_SUCCESS) {
1361 die("Error in setting reqhost: %s",
1362 ipadm_status2str(status));
1365 } else if (strcmp(atype, "addrconf") == 0) {
1366 if (dhcp_opt || s_opt || reqhost != NULL || primary_opt) {
1367 die("Invalid arguments for type %s\nusage: %s",
1368 atype, use);
1371 /* Initialize the addrobj for ipv6-addrconf addresses. */
1372 status = ipadm_create_addrobj(IPADM_ADDR_IPV6_ADDRCONF,
1373 argv[optind], &ipaddr);
1374 if (status != IPADM_SUCCESS) {
1375 die("Error in creating address object: %s",
1376 ipadm_status2str(status));
1378 if (interface_id != NULL) {
1379 status = ipadm_set_interface_id(ipaddr, interface_id);
1380 if (status != IPADM_SUCCESS) {
1381 die("Error in setting interface ID: %s",
1382 ipadm_status2str(status));
1385 if (addrconf_arg)
1386 process_addrconf_addrargs(use, addrconf_arg);
1387 } else {
1388 die("Invalid address type %s", atype);
1391 status = ipadm_create_addr(iph, ipaddr, flags);
1392 if (status == IPADM_DHCP_IPC_TIMEOUT)
1393 warn_ipadmerr(status, "");
1394 else if (status != IPADM_SUCCESS)
1395 die("Could not create address: %s", ipadm_status2str(status));
1399 * Used by some address management functions to parse the command line
1400 * arguments and create `ipaddr' address object.
1402 static void
1403 process_misc_addrargs(int argc, char *argv[], const char *use, int *index,
1404 uint32_t *flags)
1406 int option;
1408 opterr = 0;
1409 while ((option = getopt_long(argc, argv, ":t", addr_misc_longopts,
1410 NULL)) != -1) {
1411 switch (option) {
1412 case 't':
1413 *flags &= ~IPADM_OPT_PERSIST;
1414 break;
1415 default:
1416 die_opterr(optopt, option, use);
1419 if (optind != (argc - 1))
1420 die("Usage: %s", use);
1422 *index = optind;
1426 * Remove an addrobj from both active and persistent configuration.
1428 static void
1429 do_delete_addr(int argc, char *argv[], const char *use)
1431 ipadm_status_t status;
1432 uint32_t flags = IPADM_OPT_ACTIVE|IPADM_OPT_PERSIST;
1433 int option;
1435 opterr = 0;
1436 while ((option = getopt_long(argc, argv, ":r", addr_misc_longopts,
1437 NULL)) != -1) {
1438 switch (option) {
1439 case 'r':
1440 flags |= IPADM_OPT_RELEASE;
1441 break;
1442 default:
1443 die_opterr(optopt, option, use);
1446 if (optind != (argc - 1))
1447 die("Usage: %s", use);
1449 status = ipadm_delete_addr(iph, argv[optind], flags);
1450 if (status != IPADM_SUCCESS) {
1451 die("could not delete address: %s",
1452 ipadm_status2str(status));
1457 * Enable an IP address based on the persistent configuration for that
1458 * IP address
1460 static void
1461 do_enable_addr(int argc, char *argv[], const char *use)
1463 ipadm_status_t status;
1464 int index;
1465 uint32_t flags = IPADM_OPT_ACTIVE|IPADM_OPT_PERSIST;
1467 process_misc_addrargs(argc, argv, use, &index, &flags);
1468 if (flags & IPADM_OPT_PERSIST)
1469 die("persistent operation not supported for enable-addr");
1471 status = ipadm_enable_addr(iph, argv[index], flags);
1472 if (status != IPADM_SUCCESS)
1473 die("could not enable address: %s", ipadm_status2str(status));
1477 * Mark the address identified by addrobj 'up'
1479 static void
1480 do_up_addr(int argc, char *argv[], const char *use)
1482 ipadm_status_t status;
1483 int index;
1484 uint32_t flags = IPADM_OPT_ACTIVE|IPADM_OPT_PERSIST;
1486 process_misc_addrargs(argc, argv, use, &index, &flags);
1487 status = ipadm_up_addr(iph, argv[index], flags);
1488 if (status != IPADM_SUCCESS) {
1489 die("Could not mark the address up: %s",
1490 ipadm_status2str(status));
1495 * Disable the specified addrobj by removing it from active cofiguration
1497 static void
1498 do_disable_addr(int argc, char *argv[], const char *use)
1500 ipadm_status_t status;
1501 int index;
1502 uint32_t flags = IPADM_OPT_ACTIVE|IPADM_OPT_PERSIST;
1504 process_misc_addrargs(argc, argv, use, &index, &flags);
1505 if (flags & IPADM_OPT_PERSIST)
1506 die("persistent operation not supported for disable-addr");
1508 status = ipadm_disable_addr(iph, argv[index], flags);
1509 if (status != IPADM_SUCCESS) {
1510 die("could not disable address: %s",
1511 ipadm_status2str(status));
1516 * Mark the address identified by addrobj 'down'
1518 static void
1519 do_down_addr(int argc, char *argv[], const char *use)
1521 ipadm_status_t status;
1522 int index;
1523 uint32_t flags = IPADM_OPT_ACTIVE|IPADM_OPT_PERSIST;
1525 process_misc_addrargs(argc, argv, use, &index, &flags);
1526 status = ipadm_down_addr(iph, argv[index], flags);
1527 if (status != IPADM_SUCCESS)
1528 die("Could not mark the address down: %s",
1529 ipadm_status2str(status));
1533 * Restart DAD for static address. Extend lease duration for DHCP addresses
1535 static void
1536 do_refresh_addr(int argc, char *argv[], const char *use)
1538 ipadm_status_t status;
1539 int option;
1540 uint32_t flags = 0;
1542 opterr = 0;
1543 while ((option = getopt_long(argc, argv, ":i", addr_misc_longopts,
1544 NULL)) != -1) {
1545 switch (option) {
1546 case 'i':
1547 flags |= IPADM_OPT_INFORM;
1548 break;
1549 default:
1550 die_opterr(optopt, option, use);
1553 if (optind != (argc - 1))
1554 die("Usage: %s", use);
1556 status = ipadm_refresh_addr(iph, argv[optind], flags);
1557 if (status == IPADM_DHCP_IPC_TIMEOUT)
1558 warn_ipadmerr(status, "");
1559 else if (status != IPADM_SUCCESS)
1560 die("could not refresh address %s", ipadm_status2str(status));
1563 static void
1564 sockaddr2str(const struct sockaddr_storage *ssp, char *buf, uint_t bufsize)
1566 socklen_t socklen;
1567 struct sockaddr *sp = (struct sockaddr *)ssp;
1569 switch (ssp->ss_family) {
1570 case AF_INET:
1571 socklen = sizeof (struct sockaddr_in);
1572 break;
1573 case AF_INET6:
1574 socklen = sizeof (struct sockaddr_in6);
1575 break;
1576 default:
1577 (void) strlcpy(buf, STR_UNKNOWN_VAL, bufsize);
1578 return;
1581 (void) getnameinfo(sp, socklen, buf, bufsize, NULL, 0,
1582 (NI_NOFQDN | NI_NUMERICHOST));
1585 static void
1586 flags2str(uint64_t flags, fmask_t *tbl, boolean_t is_bits,
1587 char *buf, uint_t bufsize)
1589 int i;
1590 boolean_t first = B_TRUE;
1592 if (is_bits) {
1593 for (i = 0; tbl[i].name; i++) {
1594 if ((flags & tbl[i].mask) == tbl[i].bits)
1595 (void) strlcat(buf, tbl[i].name, bufsize);
1596 else
1597 (void) strlcat(buf, "-", bufsize);
1599 } else {
1600 for (i = 0; tbl[i].name; i++) {
1601 if ((flags & tbl[i].mask) == tbl[i].bits) {
1602 if (!first)
1603 (void) strlcat(buf, ",", bufsize);
1604 (void) strlcat(buf, tbl[i].name, bufsize);
1605 first = B_FALSE;
1612 * return true if the address for lifname comes to us from the global zone
1613 * with 'allowed-ips' constraints.
1615 static boolean_t
1616 is_from_gz(const char *lifname)
1618 ipadm_if_info_t *if_info;
1619 char phyname[LIFNAMSIZ], *cp;
1620 boolean_t ret = B_FALSE;
1621 ipadm_status_t status;
1622 zoneid_t zoneid;
1623 ushort_t zflags;
1625 if ((zoneid = getzoneid()) == GLOBAL_ZONEID)
1626 return (B_FALSE); /* from-gz only makes sense in a NGZ */
1628 if (zone_getattr(zoneid, ZONE_ATTR_FLAGS, &zflags, sizeof (zflags)) < 0)
1629 return (B_FALSE);
1631 if (!(zflags & ZF_NET_EXCL))
1632 return (B_TRUE); /* everything is from the GZ for shared-ip */
1634 (void) strncpy(phyname, lifname, sizeof (phyname));
1635 if ((cp = strchr(phyname, ':')) != NULL)
1636 *cp = '\0';
1637 status = ipadm_if_info(iph, phyname, &if_info, 0, LIFC_DEFAULT);
1638 if (status != IPADM_SUCCESS)
1639 return (ret);
1641 if (if_info->ifi_cflags & IFIF_L3PROTECT)
1642 ret = B_TRUE;
1643 if (if_info)
1644 ipadm_free_if_info(if_info);
1645 return (ret);
1648 static boolean_t
1649 print_sa_cb(ofmt_arg_t *ofarg, char *buf, uint_t bufsize)
1651 show_addr_args_t *arg = ofarg->ofmt_cbarg;
1652 ipadm_addr_info_t *ainfo = arg->sa_info;
1653 char interface[LIFNAMSIZ];
1654 char addrbuf[MAXPROPVALLEN];
1655 char dstbuf[MAXPROPVALLEN];
1656 char prefixlenstr[MAXPROPVALLEN];
1657 int prefixlen;
1658 struct sockaddr_in *sin;
1659 struct sockaddr_in6 *sin6;
1660 sa_family_t af;
1661 char *phyname = NULL;
1662 struct ifaddrs *ifa = &ainfo->ia_ifa;
1663 fmask_t cflags_mask[] = {
1664 { "U", IA_UP, IA_UP },
1665 { "u", IA_UNNUMBERED, IA_UNNUMBERED },
1666 { "p", IA_PRIVATE, IA_PRIVATE },
1667 { "t", IA_TEMPORARY, IA_TEMPORARY },
1668 { "d", IA_DEPRECATED, IA_DEPRECATED },
1669 { NULL, 0, 0 }
1671 fmask_t pflags_mask[] = {
1672 { "U", IA_UP, IA_UP },
1673 { "p", IA_PRIVATE, IA_PRIVATE },
1674 { "d", IA_DEPRECATED, IA_DEPRECATED },
1675 { NULL, 0, 0 }
1677 fmask_t type[] = {
1678 { "static", IPADM_ADDR_STATIC, IPADM_ALL_BITS},
1679 { "addrconf", IPADM_ADDR_IPV6_ADDRCONF, IPADM_ALL_BITS},
1680 { "dhcp", IPADM_ADDR_DHCP, IPADM_ALL_BITS},
1681 { NULL, 0, 0 }
1683 fmask_t addr_state[] = {
1684 { "disabled", IFA_DISABLED, IPADM_ALL_BITS},
1685 { "duplicate", IFA_DUPLICATE, IPADM_ALL_BITS},
1686 { "down", IFA_DOWN, IPADM_ALL_BITS},
1687 { "tentative", IFA_TENTATIVE, IPADM_ALL_BITS},
1688 { "ok", IFA_OK, IPADM_ALL_BITS},
1689 { "inaccessible", IFA_INACCESSIBLE, IPADM_ALL_BITS},
1690 { NULL, 0, 0 }
1693 buf[0] = '\0';
1694 switch (ofarg->ofmt_id) {
1695 case SA_ADDROBJ:
1696 if (ainfo->ia_aobjname[0] == '\0') {
1697 (void) strncpy(interface, ifa->ifa_name, LIFNAMSIZ);
1698 phyname = strrchr(interface, ':');
1699 if (phyname)
1700 *phyname = '\0';
1701 (void) snprintf(buf, bufsize, "%s/%s", interface,
1702 STR_UNKNOWN_VAL);
1703 } else {
1704 (void) snprintf(buf, bufsize, "%s", ainfo->ia_aobjname);
1706 break;
1707 case SA_STATE:
1708 flags2str(ainfo->ia_state, addr_state, B_FALSE,
1709 buf, bufsize);
1710 break;
1711 case SA_TYPE:
1712 if (is_from_gz(ifa->ifa_name))
1713 (void) snprintf(buf, bufsize, "from-gz");
1714 else
1715 flags2str(ainfo->ia_atype, type, B_FALSE, buf,
1716 bufsize);
1717 break;
1718 case SA_CURRENT:
1719 flags2str(ainfo->ia_cflags, cflags_mask, B_TRUE, buf, bufsize);
1720 break;
1721 case SA_PERSISTENT:
1722 flags2str(ainfo->ia_pflags, pflags_mask, B_TRUE, buf, bufsize);
1723 break;
1724 case SA_ADDR:
1725 af = ifa->ifa_addr->sa_family;
1727 * If the address is 0.0.0.0 or :: and the origin is DHCP,
1728 * print STR_UNKNOWN_VAL.
1730 if (ainfo->ia_atype == IPADM_ADDR_DHCP) {
1731 sin = (struct sockaddr_in *)ifa->ifa_addr;
1732 sin6 = (struct sockaddr_in6 *)ifa->ifa_addr;
1733 if ((af == AF_INET &&
1734 sin->sin_addr.s_addr == INADDR_ANY) ||
1735 (af == AF_INET6 &&
1736 IN6_IS_ADDR_UNSPECIFIED(&sin6->sin6_addr))) {
1737 (void) snprintf(buf, bufsize, STR_UNKNOWN_VAL);
1738 break;
1741 if (ifa->ifa_netmask == NULL)
1742 prefixlen = 0;
1743 else
1744 prefixlen = mask2plen(ifa->ifa_netmask);
1745 bzero(prefixlenstr, sizeof (prefixlenstr));
1746 if (prefixlen > 0) {
1747 (void) snprintf(prefixlenstr, sizeof (prefixlenstr),
1748 "/%d", prefixlen);
1750 bzero(addrbuf, sizeof (addrbuf));
1751 bzero(dstbuf, sizeof (dstbuf));
1752 if (ainfo->ia_atype == IPADM_ADDR_STATIC) {
1754 * Print the hostname fields if the address is not
1755 * in active configuration.
1757 if (ainfo->ia_state == IFA_DISABLED) {
1758 (void) snprintf(buf, bufsize, "%s",
1759 ainfo->ia_sname);
1760 if (ainfo->ia_dname[0] != '\0') {
1761 (void) snprintf(dstbuf, sizeof (dstbuf),
1762 "->%s", ainfo->ia_dname);
1763 (void) strlcat(buf, dstbuf, bufsize);
1764 } else {
1765 (void) strlcat(buf, prefixlenstr,
1766 bufsize);
1768 break;
1772 * For the non-persistent case, we need to show the
1773 * currently configured addresses for source and
1774 * destination.
1776 sockaddr2str((struct sockaddr_storage *)ifa->ifa_addr,
1777 addrbuf, sizeof (addrbuf));
1778 if (ifa->ifa_flags & IFF_POINTOPOINT) {
1779 sockaddr2str(
1780 (struct sockaddr_storage *)ifa->ifa_dstaddr,
1781 dstbuf, sizeof (dstbuf));
1782 (void) snprintf(buf, bufsize, "%s->%s", addrbuf,
1783 dstbuf);
1784 } else {
1785 (void) snprintf(buf, bufsize, "%s%s", addrbuf,
1786 prefixlenstr);
1788 break;
1789 default:
1790 die("invalid input");
1791 break;
1794 return (B_TRUE);
1798 * Display address information, either for the given address or
1799 * for all the addresses managed by ipadm.
1801 static void
1802 do_show_addr(int argc, char *argv[], const char *use)
1804 ipadm_status_t status;
1805 show_addr_state_t state;
1806 char *def_fields_str = "addrobj,type,state,addr";
1807 char *fields_str = NULL;
1808 ipadm_addr_info_t *ainfo;
1809 ipadm_addr_info_t *ptr;
1810 show_addr_args_t sargs;
1811 int option;
1812 ofmt_handle_t ofmt;
1813 ofmt_status_t oferr;
1814 uint_t ofmtflags = 0;
1815 char *aname;
1816 char *ifname = NULL;
1817 char *cp;
1818 boolean_t found = B_FALSE;
1820 opterr = 0;
1821 state.sa_parsable = B_FALSE;
1822 state.sa_persist = B_FALSE;
1823 while ((option = getopt_long(argc, argv, "po:", show_addr_longopts,
1824 NULL)) != -1) {
1825 switch (option) {
1826 case 'p':
1827 state.sa_parsable = B_TRUE;
1828 break;
1829 case 'o':
1830 fields_str = optarg;
1831 break;
1832 default:
1833 die_opterr(optopt, option, use);
1834 break;
1837 if (state.sa_parsable && fields_str == NULL)
1838 die("-p requires -o");
1840 if (optind == argc - 1) {
1841 aname = argv[optind];
1842 if ((cp = strchr(aname, '/')) == NULL)
1843 die("Invalid address object name provided");
1844 if (*(cp + 1) == '\0') {
1845 ifname = aname;
1846 *cp = '\0';
1847 aname = NULL;
1849 } else if (optind == argc) {
1850 aname = NULL;
1851 } else {
1852 die("Usage: %s", use);
1855 if (state.sa_parsable)
1856 ofmtflags |= OFMT_PARSABLE;
1857 if (fields_str == NULL)
1858 fields_str = def_fields_str;
1859 oferr = ofmt_open(fields_str, show_addr_fields, ofmtflags, 0, &ofmt);
1861 ofmt_check(oferr, state.sa_parsable, ofmt, die, warn);
1862 state.sa_ofmt = ofmt;
1864 status = ipadm_addr_info(iph, ifname, &ainfo, 0, LIFC_DEFAULT);
1866 * Return without printing any error, if no addresses were found,
1867 * for the case where all addresses are requested.
1869 if (status != IPADM_SUCCESS)
1870 die("Could not get address: %s", ipadm_status2str(status));
1871 if (ainfo == NULL) {
1872 ofmt_close(ofmt);
1873 return;
1876 bzero(&sargs, sizeof (sargs));
1877 sargs.sa_state = &state;
1878 for (ptr = ainfo; ptr != NULL; ptr = IA_NEXT(ptr)) {
1879 sargs.sa_info = ptr;
1880 if (aname != NULL) {
1881 if (strcmp(sargs.sa_info->ia_aobjname, aname) != 0)
1882 continue;
1883 found = B_TRUE;
1885 ofmt_print(state.sa_ofmt, &sargs);
1887 if (ainfo)
1888 ipadm_free_addr_info(ainfo);
1889 if (aname != NULL && !found)
1890 die("Address object not found");
1893 static boolean_t
1894 print_si_cb(ofmt_arg_t *ofarg, char *buf, uint_t bufsize)
1896 show_if_args_t *arg = ofarg->ofmt_cbarg;
1897 ipadm_if_info_t *ifinfo = arg->si_info;
1898 char *ifname = ifinfo->ifi_name;
1899 fmask_t intf_state[] = {
1900 { "ok", IFIS_OK, IPADM_ALL_BITS},
1901 { "down", IFIS_DOWN, IPADM_ALL_BITS},
1902 { "disabled", IFIS_DISABLED, IPADM_ALL_BITS},
1903 { "failed", IFIS_FAILED, IPADM_ALL_BITS},
1904 { "offline", IFIS_OFFLINE, IPADM_ALL_BITS},
1905 { NULL, 0, 0 }
1907 fmask_t intf_pflags[] = {
1908 { "s", IFIF_STANDBY, IFIF_STANDBY },
1909 { "4", IFIF_IPV4, IFIF_IPV4 },
1910 { "6", IFIF_IPV6, IFIF_IPV6 },
1911 { NULL, 0, 0 }
1913 fmask_t intf_cflags[] = {
1914 { "b", IFIF_BROADCAST, IFIF_BROADCAST },
1915 { "m", IFIF_MULTICAST, IFIF_MULTICAST },
1916 { "p", IFIF_POINTOPOINT, IFIF_POINTOPOINT},
1917 { "v", IFIF_VIRTUAL, IFIF_VIRTUAL },
1918 { "I", IFIF_IPMP, IFIF_IPMP },
1919 { "s", IFIF_STANDBY, IFIF_STANDBY },
1920 { "i", IFIF_INACTIVE, IFIF_INACTIVE },
1921 { "V", IFIF_VRRP, IFIF_VRRP },
1922 { "a", IFIF_NOACCEPT, IFIF_NOACCEPT },
1923 { "Z", IFIF_L3PROTECT, IFIF_L3PROTECT },
1924 { "4", IFIF_IPV4, IFIF_IPV4 },
1925 { "6", IFIF_IPV6, IFIF_IPV6 },
1926 { NULL, 0, 0 }
1929 buf[0] = '\0';
1930 switch (ofarg->ofmt_id) {
1931 case SI_IFNAME:
1932 (void) snprintf(buf, bufsize, "%s", ifname);
1933 break;
1934 case SI_STATE:
1935 flags2str(ifinfo->ifi_state, intf_state, B_FALSE,
1936 buf, bufsize);
1937 break;
1938 case SI_CURRENT:
1939 flags2str(ifinfo->ifi_cflags, intf_cflags, B_TRUE,
1940 buf, bufsize);
1941 break;
1942 case SI_PERSISTENT:
1943 flags2str(ifinfo->ifi_pflags, intf_pflags, B_TRUE,
1944 buf, bufsize);
1945 break;
1946 default:
1947 die("invalid input");
1948 break;
1951 return (B_TRUE);
1955 * Display interface information, either for the given interface or
1956 * for all the interfaces in the system.
1958 static void
1959 do_show_if(int argc, char *argv[], const char *use)
1961 ipadm_status_t status;
1962 show_if_state_t state;
1963 char *fields_str = NULL;
1964 ipadm_if_info_t *if_info, *ptr;
1965 show_if_args_t sargs;
1966 int option;
1967 ofmt_handle_t ofmt;
1968 ofmt_status_t oferr;
1969 uint_t ofmtflags = 0;
1970 char *ifname = NULL;
1972 opterr = 0;
1973 state.si_parsable = B_FALSE;
1975 while ((option = getopt_long(argc, argv, "po:", show_if_longopts,
1976 NULL)) != -1) {
1977 switch (option) {
1978 case 'p':
1979 state.si_parsable = B_TRUE;
1980 break;
1981 case 'o':
1982 fields_str = optarg;
1983 break;
1984 default:
1985 die_opterr(optopt, option, use);
1986 break;
1989 if (optind == argc - 1)
1990 ifname = argv[optind];
1991 else if (optind != argc)
1992 die("Usage: %s", use);
1993 if (state.si_parsable)
1994 ofmtflags |= OFMT_PARSABLE;
1995 oferr = ofmt_open(fields_str, show_if_fields, ofmtflags, 0, &ofmt);
1996 ofmt_check(oferr, state.si_parsable, ofmt, die, warn);
1997 state.si_ofmt = ofmt;
1998 bzero(&sargs, sizeof (sargs));
1999 sargs.si_state = &state;
2000 status = ipadm_if_info(iph, ifname, &if_info, 0, LIFC_DEFAULT);
2002 * Return without printing any error, if no addresses were found.
2004 if (status != IPADM_SUCCESS) {
2005 die("Could not get interface(s): %s",
2006 ipadm_status2str(status));
2009 for (ptr = if_info; ptr; ptr = ptr->ifi_next) {
2010 sargs.si_info = ptr;
2011 ofmt_print(state.si_ofmt, &sargs);
2013 if (if_info)
2014 ipadm_free_if_info(if_info);
2018 * set/reset the address property for a given address
2020 static void
2021 set_addrprop(int argc, char **argv, boolean_t reset, const char *use)
2023 int option;
2024 ipadm_status_t status = IPADM_SUCCESS;
2025 boolean_t p_arg = B_FALSE;
2026 char *nv, *aobjname;
2027 char *prop_name, *prop_val;
2028 uint_t flags = IPADM_OPT_ACTIVE|IPADM_OPT_PERSIST;
2030 nv = NULL;
2031 opterr = 0;
2032 while ((option = getopt_long(argc, argv, ":i:p:t", set_ifprop_longopts,
2033 NULL)) != -1) {
2034 switch (option) {
2035 case 'p':
2036 if (p_arg)
2037 die("-p must be specified once only");
2038 p_arg = B_TRUE;
2040 ipadm_check_propstr(optarg, reset, use);
2041 nv = optarg;
2042 break;
2043 case 't':
2044 flags &= ~IPADM_OPT_PERSIST;
2045 break;
2046 default:
2047 die_opterr(optopt, option, use);
2051 if (!p_arg || optind != (argc - 1))
2052 die("Usage: %s", use);
2054 prop_name = nv;
2055 prop_val = strchr(nv, '=');
2056 if (prop_val != NULL)
2057 *prop_val++ = '\0';
2058 aobjname = argv[optind];
2059 if (reset)
2060 flags |= IPADM_OPT_DEFAULT;
2061 status = ipadm_set_addrprop(iph, prop_name, prop_val, aobjname, flags);
2062 if (status != IPADM_SUCCESS) {
2063 if (reset)
2064 die("reset-addrprop: %s: %s", prop_name,
2065 ipadm_status2str(status));
2066 else
2067 die("set-addrprop: %s: %s", prop_name,
2068 ipadm_status2str(status));
2073 * Sets a property on an address object.
2075 static void
2076 do_set_addrprop(int argc, char **argv, const char *use)
2078 set_addrprop(argc, argv, B_FALSE, use);
2082 * Resets a property to its default value on an address object.
2084 static void
2085 do_reset_addrprop(int argc, char **argv, const char *use)
2087 set_addrprop(argc, argv, B_TRUE, use);
2091 * Display information for all or specific address properties, either for a
2092 * given address or for all the addresses in the system.
2094 static void
2095 do_show_addrprop(int argc, char *argv[], const char *use)
2097 int option;
2098 nvlist_t *proplist = NULL;
2099 char *fields_str = NULL;
2100 show_prop_state_t state;
2101 ofmt_handle_t ofmt;
2102 ofmt_status_t oferr;
2103 uint_t ofmtflags = 0;
2104 char *aobjname = NULL;
2105 char *ifname = NULL;
2106 char *cp;
2107 ipadm_addr_info_t *ainfop = NULL;
2108 ipadm_addr_info_t *ptr;
2109 ipadm_status_t status;
2110 boolean_t found = B_FALSE;
2112 opterr = 0;
2113 bzero(&state, sizeof (state));
2114 state.sps_propval = NULL;
2115 state.sps_parsable = B_FALSE;
2116 state.sps_addrprop = B_TRUE;
2117 state.sps_proto = MOD_PROTO_NONE;
2118 state.sps_status = state.sps_retstatus = IPADM_SUCCESS;
2119 while ((option = getopt_long(argc, argv, ":p:i:cPo:",
2120 show_prop_longopts, NULL)) != -1) {
2121 switch (option) {
2122 case 'p':
2123 if (ipadm_str2nvlist(optarg, &proplist,
2124 IPADM_NORVAL) != 0)
2125 die("invalid addrobj properties specified");
2126 break;
2127 case 'c':
2128 state.sps_parsable = B_TRUE;
2129 break;
2130 case 'o':
2131 fields_str = optarg;
2132 break;
2133 default:
2134 die_opterr(optopt, option, use);
2135 break;
2138 if (optind == argc - 1) {
2139 aobjname = argv[optind];
2140 cp = strchr(aobjname, '/');
2141 if (cp == NULL)
2142 die("invalid addrobj name provided");
2143 if (*(cp + 1) == '\0') {
2144 ifname = aobjname;
2145 *cp = '\0';
2146 aobjname = NULL;
2148 } else if (optind != argc) {
2149 die("Usage: %s", use);
2151 state.sps_proplist = proplist;
2152 if (state.sps_parsable)
2153 ofmtflags |= OFMT_PARSABLE;
2154 oferr = ofmt_open(fields_str, addrprop_fields, ofmtflags, 0, &ofmt);
2155 ofmt_check(oferr, state.sps_parsable, ofmt, die, warn);
2156 state.sps_ofmt = ofmt;
2158 status = ipadm_addr_info(iph, ifname, &ainfop, 0, LIFC_DEFAULT);
2159 /* Return without printing any error, if no addresses were found */
2160 if (status == IPADM_NOTFOUND)
2161 return;
2162 if (status != IPADM_SUCCESS)
2163 die("error retrieving address: %s", ipadm_status2str(status));
2165 for (ptr = ainfop; ptr != NULL; ptr = IA_NEXT(ptr)) {
2166 char *taobjname = ptr->ia_aobjname;
2168 if (taobjname[0] == '\0')
2169 continue;
2170 if (aobjname != NULL) {
2171 if (strcmp(aobjname, taobjname) == 0)
2172 found = B_TRUE;
2173 else
2174 continue;
2176 if (ptr->ia_atype == IPADM_ADDR_IPV6_ADDRCONF) {
2177 if (found)
2178 break;
2179 else
2180 continue;
2182 (void) strlcpy(state.sps_aobjname, taobjname,
2183 sizeof (state.sps_aobjname));
2184 show_properties(&state, IPADMPROP_CLASS_ADDR);
2185 if (found)
2186 break;
2188 ipadm_free_addr_info(ainfop);
2190 if (aobjname != NULL && !found)
2191 die("addrobj not found: %s", aobjname);
2193 nvlist_free(proplist);
2194 ofmt_close(ofmt);
2195 if (state.sps_retstatus != IPADM_SUCCESS) {
2196 ipadm_close(iph);
2197 exit(EXIT_FAILURE);
2202 * check if the `pstr' adheres to following syntax
2203 * - prop=<value[,...]> (for set)
2204 * - prop (for reset)
2206 static void
2207 ipadm_check_propstr(const char *pstr, boolean_t reset, const char *use)
2209 char *nv;
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);