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