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