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