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