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