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 2007 Sun Microsystems, Inc. All rights reserved. 23 * Use is subject to license terms. 24 */ 25 26 #pragma ident "%Z%%M% %I% %E% SMI" 27 28 #include <stdlib.h> 29 #include <strings.h> 30 #include <errno.h> 31 #include <ctype.h> 32 #include <sys/types.h> 33 #include <sys/stat.h> 34 #include <sys/dld.h> 35 #include <sys/zone.h> 36 #include <fcntl.h> 37 #include <unistd.h> 38 #include <libdevinfo.h> 39 #include <zone.h> 40 #include <libwladm.h> 41 #include <libdladm_impl.h> 42 43 #include <dlfcn.h> 44 #include <link.h> 45 46 static dladm_status_t i_dladm_set_prop_db(const char *, const char *, 47 char **, uint_t); 48 static dladm_status_t i_dladm_get_prop_db(const char *, const char *, 49 char **, uint_t *); 50 static dladm_status_t i_dladm_get_prop_temp(const char *, dladm_prop_type_t, 51 const char *, char **, uint_t *); 52 static dladm_status_t i_dladm_set_prop_temp(const char *, const char *, 53 char **, uint_t, uint_t, char **); 54 static boolean_t i_dladm_is_prop_temponly(const char *prop_name, 55 char **); 56 57 typedef struct val_desc { 58 char *vd_name; 59 void *vd_val; 60 } val_desc_t; 61 62 struct prop_desc; 63 64 typedef dladm_status_t pd_getf_t(const char *, char **, uint_t *); 65 typedef dladm_status_t pd_setf_t(const char *, val_desc_t *, uint_t); 66 typedef dladm_status_t pd_checkf_t(struct prop_desc *, char **, 67 uint_t, val_desc_t **); 68 69 static pd_getf_t do_get_zone; 70 static pd_setf_t do_set_zone; 71 static pd_checkf_t do_check_zone; 72 73 typedef struct prop_desc { 74 char *pd_name; 75 val_desc_t pd_defval; 76 val_desc_t *pd_modval; 77 uint_t pd_nmodval; 78 boolean_t pd_temponly; 79 pd_setf_t *pd_set; 80 pd_getf_t *pd_getmod; 81 pd_getf_t *pd_get; 82 pd_checkf_t *pd_check; 83 } prop_desc_t; 84 85 static prop_desc_t prop_table[] = { 86 { "zone", { "", NULL }, NULL, 0, B_TRUE, 87 do_set_zone, NULL, 88 do_get_zone, do_check_zone} 89 }; 90 91 #define MAX_PROPS (sizeof (prop_table) / sizeof (prop_desc_t)) 92 93 /* 94 * Convert a wladm_status_t to a dladm_status_t. This is used by wrappers 95 * to libwladm routines (e.g. dladm_set_prop()). Note that the mapping is 96 * not 1-1; whenever possible we try to look for an error code with a 97 * similar meaning. Error codes with no suitable counterpart in libdladm 98 * will be mapped to DLADM_STATUS_FAILED. Clients who require clearer error 99 * reporting should use libwladm directly. 100 */ 101 static dladm_status_t 102 dladm_wladmstatus2status(wladm_status_t wstatus) 103 { 104 switch (wstatus) { 105 case WLADM_STATUS_OK: 106 return (DLADM_STATUS_OK); 107 case WLADM_STATUS_FAILED: 108 return (DLADM_STATUS_FAILED); 109 case WLADM_STATUS_NOTSUP: 110 return (DLADM_STATUS_NOTSUP); 111 case WLADM_STATUS_BADARG: 112 return (DLADM_STATUS_BADARG); 113 case WLADM_STATUS_NOTFOUND: 114 return (DLADM_STATUS_NOTFOUND); 115 case WLADM_STATUS_BADVAL: 116 return (DLADM_STATUS_BADVAL); 117 case WLADM_STATUS_LINKINVAL: 118 return (DLADM_STATUS_LINKINVAL); 119 case WLADM_STATUS_NOMEM: 120 return (DLADM_STATUS_NOMEM); 121 case WLADM_STATUS_PROPRDONLY: 122 return (DLADM_STATUS_PROPRDONLY); 123 case WLADM_STATUS_TOOSMALL: 124 return (DLADM_STATUS_TOOSMALL); 125 case WLADM_STATUS_BADVALCNT: 126 return (DLADM_STATUS_BADVALCNT); 127 default: 128 return (DLADM_STATUS_FAILED); 129 } 130 } 131 132 dladm_status_t 133 dladm_set_prop(const char *link, const char *prop_name, char **prop_val, 134 uint_t val_cnt, uint_t flags, char **errprop) 135 { 136 dladm_status_t status = DLADM_STATUS_BADARG; 137 138 if (link == NULL || (prop_val == NULL && val_cnt > 0) || 139 (prop_val != NULL && val_cnt == 0) || flags == 0) 140 return (DLADM_STATUS_BADARG); 141 142 if ((flags & DLADM_OPT_TEMP) != 0) { 143 status = i_dladm_set_prop_temp(link, prop_name, prop_val, 144 val_cnt, flags, errprop); 145 if (status == DLADM_STATUS_TEMPONLY && 146 (flags & DLADM_OPT_PERSIST) != 0) 147 return (DLADM_STATUS_TEMPONLY); 148 149 if (status == DLADM_STATUS_NOTFOUND) { 150 status = DLADM_STATUS_BADARG; 151 if (wladm_is_valid(link)) { 152 status = dladm_wladmstatus2status( 153 wladm_set_prop(link, prop_name, 154 prop_val, val_cnt, errprop)); 155 } 156 } 157 if (status != DLADM_STATUS_OK) 158 return (status); 159 } 160 if ((flags & DLADM_OPT_PERSIST) != 0) { 161 if (i_dladm_is_prop_temponly(prop_name, errprop)) 162 return (DLADM_STATUS_TEMPONLY); 163 164 status = i_dladm_set_prop_db(link, prop_name, 165 prop_val, val_cnt); 166 } 167 return (status); 168 } 169 170 dladm_status_t 171 dladm_walk_prop(const char *link, void *arg, 172 boolean_t (*func)(void *, const char *)) 173 { 174 int i; 175 176 if (link == NULL || func == NULL) 177 return (DLADM_STATUS_BADARG); 178 179 /* For wifi links, show wifi properties first */ 180 if (wladm_is_valid(link)) { 181 dladm_status_t status; 182 183 status = dladm_wladmstatus2status( 184 wladm_walk_prop(link, arg, func)); 185 if (status != DLADM_STATUS_OK) 186 return (status); 187 } 188 189 /* Then show data-link properties if there are any */ 190 for (i = 0; i < MAX_PROPS; i++) { 191 if (!func(arg, prop_table[i].pd_name)) 192 break; 193 } 194 return (DLADM_STATUS_OK); 195 } 196 197 dladm_status_t 198 dladm_get_prop(const char *link, dladm_prop_type_t type, 199 const char *prop_name, char **prop_val, uint_t *val_cntp) 200 { 201 dladm_status_t status; 202 203 if (link == NULL || prop_name == NULL || prop_val == NULL || 204 val_cntp == NULL || *val_cntp == 0) 205 return (DLADM_STATUS_BADARG); 206 207 if (type == DLADM_PROP_VAL_PERSISTENT) { 208 return (i_dladm_get_prop_db(link, prop_name, 209 prop_val, val_cntp)); 210 } 211 212 status = i_dladm_get_prop_temp(link, type, prop_name, 213 prop_val, val_cntp); 214 if (status != DLADM_STATUS_NOTFOUND) 215 return (status); 216 217 if (wladm_is_valid(link)) { 218 wladm_prop_type_t wtype; 219 220 switch (type) { 221 case DLADM_PROP_VAL_CURRENT: 222 wtype = WLADM_PROP_VAL_CURRENT; 223 break; 224 case DLADM_PROP_VAL_DEFAULT: 225 wtype = WLADM_PROP_VAL_DEFAULT; 226 break; 227 case DLADM_PROP_VAL_MODIFIABLE: 228 wtype = WLADM_PROP_VAL_MODIFIABLE; 229 break; 230 default: 231 return (DLADM_STATUS_BADARG); 232 } 233 234 return (dladm_wladmstatus2status( 235 wladm_get_prop(link, wtype, prop_name, 236 prop_val, val_cntp))); 237 } 238 return (DLADM_STATUS_BADARG); 239 } 240 241 /* 242 * Data structures used for implementing persistent link properties 243 */ 244 typedef struct linkprop_val { 245 const char *lv_name; 246 struct linkprop_val *lv_nextval; 247 } linkprop_val_t; 248 249 typedef struct linkprop_info { 250 const char *li_name; 251 struct linkprop_info *li_nextprop; 252 struct linkprop_val *li_val; 253 } linkprop_info_t; 254 255 typedef struct linkprop_db_state linkprop_db_state_t; 256 257 typedef boolean_t (*linkprop_db_op_t)(linkprop_db_state_t *, 258 char *, linkprop_info_t *, dladm_status_t *); 259 260 struct linkprop_db_state { 261 linkprop_db_op_t ls_op; 262 const char *ls_link; 263 const char *ls_propname; 264 char **ls_propval; 265 uint_t *ls_valcntp; 266 }; 267 268 static void 269 free_linkprops(linkprop_info_t *lip) 270 { 271 linkprop_info_t *lip_next; 272 linkprop_val_t *lvp, *lvp_next; 273 274 for (; lip != NULL; lip = lip_next) { 275 lip_next = lip->li_nextprop; 276 for (lvp = lip->li_val; lvp != NULL; lvp = lvp_next) { 277 lvp_next = lvp->lv_nextval; 278 free(lvp); 279 } 280 free(lip); 281 } 282 } 283 284 /* 285 * Generate an entry in the link property database. 286 * Each entry has this format: 287 * <linkname> <prop0>=<val0>,...,<valn>;...;<propn>=<val0>,...,<valn>; 288 */ 289 static void 290 generate_linkprop_line(linkprop_db_state_t *lsp, char *buf, 291 linkprop_info_t *listp, dladm_status_t *statusp) 292 { 293 char tmpbuf[MAXLINELEN]; 294 char *ptr, *lim = tmpbuf + MAXLINELEN; 295 linkprop_info_t *lip = listp; 296 linkprop_val_t *lvp = NULL; 297 298 /* 299 * Delete line if there are no properties left. 300 */ 301 if (lip == NULL || 302 (lip->li_val == NULL && lip->li_nextprop == NULL)) { 303 buf[0] = '\0'; 304 return; 305 } 306 ptr = tmpbuf; 307 ptr += snprintf(ptr, BUFLEN(lim, ptr), "%s\t", lsp->ls_link); 308 for (; lip != NULL; lip = lip->li_nextprop) { 309 /* 310 * Skip properties without values. 311 */ 312 if (lip->li_val == NULL) 313 continue; 314 315 ptr += snprintf(ptr, BUFLEN(lim, ptr), "%s=", lip->li_name); 316 for (lvp = lip->li_val; lvp != NULL; lvp = lvp->lv_nextval) { 317 ptr += snprintf(ptr, BUFLEN(lim, ptr), "%s%c", 318 lvp->lv_name, 319 ((lvp->lv_nextval == NULL) ? ';' : ',')); 320 } 321 } 322 if (ptr > lim) { 323 *statusp = DLADM_STATUS_TOOSMALL; 324 return; 325 } 326 (void) snprintf(buf, MAXLINELEN, "%s\n", tmpbuf); 327 } 328 329 /* 330 * This function is used to update or create an entry in the persistent db. 331 * process_linkprop_db() will first scan the db for an entry matching the 332 * specified link. If a match is found, this function is invoked with the 333 * entry's contents (buf) and its linked-list representation (listp). lsp 334 * holds the name and values of the property to be added or updated; this 335 * information will be merged with listp. Subsequently, an updated entry 336 * will be written to buf, which will in turn be written to disk by 337 * process_linkprop_db(). If no entry matches the specified link, listp 338 * will be NULL; a new entry will be generated in this case and it will 339 * contain only the property information in lsp. 340 */ 341 static boolean_t 342 process_linkprop_set(linkprop_db_state_t *lsp, char *buf, 343 linkprop_info_t *listp, dladm_status_t *statusp) 344 { 345 dladm_status_t status; 346 linkprop_info_t *lastp = NULL, *lip = listp, *nlip = NULL; 347 linkprop_val_t **lvpp; 348 int i; 349 350 if (lsp->ls_propname == NULL) { 351 buf[0] = '\0'; 352 return (B_FALSE); 353 } 354 355 /* 356 * Find the linkprop we want to change. 357 */ 358 for (; lip != NULL; lip = lip->li_nextprop) { 359 if (strcmp(lip->li_name, lsp->ls_propname) == 0) 360 break; 361 362 lastp = lip; 363 } 364 365 if (lip == NULL) { 366 /* 367 * If the linkprop is not found, append it to the list. 368 */ 369 if ((nlip = malloc(sizeof (linkprop_info_t))) == NULL) { 370 status = DLADM_STATUS_NOMEM; 371 goto fail; 372 } 373 /* 374 * nlip will need to be freed later if there is no list to 375 * append to. 376 */ 377 if (lastp != NULL) 378 lastp->li_nextprop = nlip; 379 nlip->li_name = lsp->ls_propname; 380 nlip->li_nextprop = NULL; 381 nlip->li_val = NULL; 382 lvpp = &nlip->li_val; 383 } else { 384 linkprop_val_t *lvp, *lvp_next; 385 386 /* 387 * If the linkprop is found, delete the existing values from it. 388 */ 389 for (lvp = lip->li_val; lvp != NULL; lvp = lvp_next) { 390 lvp_next = lvp->lv_nextval; 391 free(lvp); 392 } 393 lip->li_val = NULL; 394 lvpp = &lip->li_val; 395 } 396 397 /* 398 * Fill our linkprop with the specified values. 399 */ 400 for (i = 0; i < *lsp->ls_valcntp; i++) { 401 if ((*lvpp = malloc(sizeof (linkprop_val_t))) == NULL) { 402 status = DLADM_STATUS_NOMEM; 403 goto fail; 404 } 405 (*lvpp)->lv_name = lsp->ls_propval[i]; 406 (*lvpp)->lv_nextval = NULL; 407 lvpp = &(*lvpp)->lv_nextval; 408 } 409 410 if (listp != NULL) { 411 generate_linkprop_line(lsp, buf, listp, statusp); 412 } else { 413 generate_linkprop_line(lsp, buf, nlip, statusp); 414 free_linkprops(nlip); 415 } 416 return (B_FALSE); 417 418 fail: 419 *statusp = status; 420 if (listp == NULL) 421 free_linkprops(nlip); 422 423 return (B_FALSE); 424 } 425 426 /* 427 * This function is used for retrieving the values for a specific property. 428 * It gets called if an entry matching the specified link exists in the db. 429 * The entry is converted into a linked-list listp. This list is then scanned 430 * for the specified property name; if a matching property exists, its 431 * associated values are copied to the array lsp->ls_propval. 432 */ 433 /* ARGSUSED */ 434 static boolean_t 435 process_linkprop_get(linkprop_db_state_t *lsp, char *buf, 436 linkprop_info_t *listp, dladm_status_t *statusp) 437 { 438 linkprop_info_t *lip = listp; 439 linkprop_val_t *lvp; 440 uint_t valcnt = 0; 441 442 /* 443 * Find the linkprop we want to get. 444 */ 445 for (; lip != NULL; lip = lip->li_nextprop) { 446 if (strcmp(lip->li_name, lsp->ls_propname) == 0) 447 break; 448 } 449 if (lip == NULL) { 450 *statusp = DLADM_STATUS_NOTFOUND; 451 return (B_FALSE); 452 } 453 454 for (lvp = lip->li_val; lvp != NULL; lvp = lvp->lv_nextval) { 455 (void) strncpy(lsp->ls_propval[valcnt], lvp->lv_name, 456 DLADM_PROP_VAL_MAX); 457 458 if (++valcnt >= *lsp->ls_valcntp && lvp->lv_nextval != NULL) { 459 *statusp = DLADM_STATUS_TOOSMALL; 460 return (B_FALSE); 461 } 462 } 463 /* 464 * This function is meant to be called at most once for each call 465 * to process_linkprop_db(). For this reason, it's ok to overwrite 466 * the caller's valcnt array size with the actual number of values 467 * returned. 468 */ 469 *lsp->ls_valcntp = valcnt; 470 return (B_FALSE); 471 } 472 473 /* 474 * This is used for initializing link properties. 475 * Unlike the other routines, this gets called for every entry in the 476 * database. lsp->ls_link is not user-specified but instead is set to 477 * the current link being processed. 478 */ 479 /* ARGSUSED */ 480 static boolean_t 481 process_linkprop_init(linkprop_db_state_t *lsp, char *buf, 482 linkprop_info_t *listp, dladm_status_t *statusp) 483 { 484 dladm_status_t status = DLADM_STATUS_OK; 485 linkprop_info_t *lip = listp; 486 linkprop_val_t *lvp; 487 uint_t valcnt, i; 488 char **propval; 489 490 for (; lip != NULL; lip = lip->li_nextprop) { 491 /* 492 * Construct the propval array and fill it with 493 * values from listp. 494 */ 495 for (lvp = lip->li_val, valcnt = 0; 496 lvp != NULL; lvp = lvp->lv_nextval, valcnt++); 497 498 propval = malloc(sizeof (char *) * valcnt); 499 if (propval == NULL) { 500 *statusp = DLADM_STATUS_NOMEM; 501 break; 502 } 503 lvp = lip->li_val; 504 for (i = 0; i < valcnt; i++, lvp = lvp->lv_nextval) 505 propval[i] = (char *)lvp->lv_name; 506 507 status = dladm_set_prop(lsp->ls_link, lip->li_name, 508 propval, valcnt, DLADM_OPT_TEMP, NULL); 509 510 /* 511 * We continue with initializing other properties even 512 * after encountering an error. This error will be 513 * propagated to the caller via 'statusp'. 514 */ 515 if (status != DLADM_STATUS_OK) 516 *statusp = status; 517 518 free(propval); 519 } 520 return (B_TRUE); 521 } 522 523 static int 524 parse_linkprops(char *buf, linkprop_info_t **lipp) 525 { 526 int i, len; 527 char *curr; 528 linkprop_info_t *lip = NULL; 529 linkprop_info_t **tailp = lipp; 530 linkprop_val_t *lvp = NULL; 531 linkprop_val_t **vtailp = NULL; 532 533 curr = buf; 534 len = strlen(buf); 535 for (i = 0; i < len; i++) { 536 char c = buf[i]; 537 boolean_t match = (c == '=' || c == ',' || c == ';'); 538 539 /* 540 * Move to the next character if there is no match and 541 * if we have not reached the last character. 542 */ 543 if (!match && i != len - 1) 544 continue; 545 546 if (match) { 547 /* 548 * Nul-terminate the string pointed to by 'curr'. 549 */ 550 buf[i] = '\0'; 551 if (*curr == '\0') 552 goto fail; 553 } 554 555 if (lip != NULL) { 556 /* 557 * We get here after we have processed the "<prop>=" 558 * pattern. The pattern we are now interested in is 559 * "<val0>,<val1>,...,<valn>;". For each value we 560 * find, a linkprop_val_t will be allocated and 561 * added to the current 'lip'. 562 */ 563 if (c == '=') 564 goto fail; 565 566 lvp = malloc(sizeof (*lvp)); 567 if (lvp == NULL) 568 goto fail; 569 570 lvp->lv_name = curr; 571 lvp->lv_nextval = NULL; 572 *vtailp = lvp; 573 vtailp = &lvp->lv_nextval; 574 575 if (c == ';') { 576 tailp = &lip->li_nextprop; 577 vtailp = NULL; 578 lip = NULL; 579 } 580 } else { 581 /* 582 * lip == NULL indicates that 'curr' must be refering 583 * to a property name. We allocate a new linkprop_info_t 584 * append it to the list given by the caller. 585 */ 586 if (c != '=') 587 goto fail; 588 589 lip = malloc(sizeof (*lip)); 590 if (lip == NULL) 591 goto fail; 592 593 lip->li_name = curr; 594 lip->li_val = NULL; 595 lip->li_nextprop = NULL; 596 *tailp = lip; 597 vtailp = &lip->li_val; 598 } 599 curr = buf + i + 1; 600 } 601 /* 602 * The list must be non-empty and the last character must be ';'. 603 */ 604 if (*lipp == NULL || lip != NULL) 605 goto fail; 606 607 return (0); 608 609 fail: 610 free_linkprops(*lipp); 611 *lipp = NULL; 612 return (-1); 613 } 614 615 static boolean_t 616 process_linkprop_line(linkprop_db_state_t *lsp, char *buf, 617 dladm_status_t *statusp) 618 { 619 linkprop_info_t *lip = NULL; 620 int i, len, llen; 621 char *str, *lasts; 622 boolean_t cont, nolink = B_FALSE; 623 624 /* 625 * Skip leading spaces, blank lines, and comments. 626 */ 627 len = strlen(buf); 628 for (i = 0; i < len; i++) { 629 if (!isspace(buf[i])) 630 break; 631 } 632 if (i == len || buf[i] == '#') 633 return (B_TRUE); 634 635 str = buf + i; 636 if (lsp->ls_link != NULL) { 637 /* 638 * Skip links we're not interested in. 639 * Note that strncmp() and isspace() are used here 640 * instead of strtok() and strcmp() because we don't 641 * want to modify buf in case it does not contain the 642 * specified link. 643 */ 644 llen = strlen(lsp->ls_link); 645 if (strncmp(str, lsp->ls_link, llen) != 0 || 646 !isspace(str[llen])) 647 return (B_TRUE); 648 } else { 649 /* 650 * If a link is not specified, find the link name 651 * and assign it to lsp->ls_link. 652 */ 653 if (strtok_r(str, " \n\t", &lasts) == NULL) 654 goto fail; 655 656 llen = strlen(str); 657 lsp->ls_link = str; 658 nolink = B_TRUE; 659 } 660 str += llen + 1; 661 if (str >= buf + len) 662 goto fail; 663 664 /* 665 * Now find the list of link properties. 666 */ 667 if ((str = strtok_r(str, " \n\t", &lasts)) == NULL) 668 goto fail; 669 670 if (parse_linkprops(str, &lip) < 0) 671 goto fail; 672 673 cont = (*lsp->ls_op)(lsp, buf, lip, statusp); 674 free_linkprops(lip); 675 if (nolink) 676 lsp->ls_link = NULL; 677 return (cont); 678 679 fail: 680 free_linkprops(lip); 681 if (nolink) 682 lsp->ls_link = NULL; 683 684 /* 685 * Delete corrupted line. 686 */ 687 buf[0] = '\0'; 688 return (B_TRUE); 689 } 690 691 static dladm_status_t 692 process_linkprop_db(void *arg, FILE *fp, FILE *nfp) 693 { 694 linkprop_db_state_t *lsp = arg; 695 dladm_status_t status = DLADM_STATUS_OK; 696 char buf[MAXLINELEN]; 697 boolean_t cont = B_TRUE; 698 699 /* 700 * This loop processes each line of the configuration file. 701 * buf can potentially be modified by process_linkprop_line(). 702 * If this is a write operation and buf is not truncated, buf will 703 * be written to disk. process_linkprop_line() will no longer be 704 * called after it returns B_FALSE; at which point the remainder 705 * of the file will continue to be read and, if necessary, written 706 * to disk as well. 707 */ 708 while (fgets(buf, MAXLINELEN, fp) != NULL) { 709 if (cont) 710 cont = process_linkprop_line(lsp, buf, &status); 711 712 if (nfp != NULL && buf[0] != '\0' && fputs(buf, nfp) == EOF) { 713 status = dladm_errno2status(errno); 714 break; 715 } 716 } 717 718 if (status != DLADM_STATUS_OK || !cont) 719 return (status); 720 721 if (lsp->ls_op == process_linkprop_set) { 722 /* 723 * If the specified link is not found above, we add the 724 * link and its properties to the configuration file. 725 */ 726 (void) (*lsp->ls_op)(lsp, buf, NULL, &status); 727 if (status == DLADM_STATUS_OK && fputs(buf, nfp) == EOF) 728 status = dladm_errno2status(errno); 729 } 730 731 if (lsp->ls_op == process_linkprop_get) 732 status = DLADM_STATUS_NOTFOUND; 733 734 return (status); 735 } 736 737 #define LINKPROP_RW_DB(statep, writeop) \ 738 (i_dladm_rw_db("/etc/dladm/linkprop.conf", \ 739 S_IRUSR | S_IWUSR | S_IRGRP | S_IROTH, process_linkprop_db, \ 740 (statep), (writeop))) 741 742 static dladm_status_t 743 i_dladm_set_prop_db(const char *link, const char *prop_name, 744 char **prop_val, uint_t val_cnt) 745 { 746 linkprop_db_state_t state; 747 748 state.ls_op = process_linkprop_set; 749 state.ls_link = link; 750 state.ls_propname = prop_name; 751 state.ls_propval = prop_val; 752 state.ls_valcntp = &val_cnt; 753 754 return (LINKPROP_RW_DB(&state, B_TRUE)); 755 } 756 757 static dladm_status_t 758 i_dladm_get_prop_db(const char *link, const char *prop_name, 759 char **prop_val, uint_t *val_cntp) 760 { 761 linkprop_db_state_t state; 762 763 state.ls_op = process_linkprop_get; 764 state.ls_link = link; 765 state.ls_propname = prop_name; 766 state.ls_propval = prop_val; 767 state.ls_valcntp = val_cntp; 768 769 return (LINKPROP_RW_DB(&state, B_FALSE)); 770 } 771 772 dladm_status_t 773 dladm_init_linkprop(void) 774 { 775 linkprop_db_state_t state; 776 777 state.ls_op = process_linkprop_init; 778 state.ls_link = NULL; 779 state.ls_propname = NULL; 780 state.ls_propval = NULL; 781 state.ls_valcntp = NULL; 782 783 return (LINKPROP_RW_DB(&state, B_FALSE)); 784 } 785 786 static dladm_status_t 787 i_dladm_get_zoneid(const char *link, zoneid_t *zidp) 788 { 789 int fd; 790 dld_hold_vlan_t dhv; 791 792 if ((fd = open(DLD_CONTROL_DEV, O_RDWR)) < 0) 793 return (dladm_errno2status(errno)); 794 795 bzero(&dhv, sizeof (dld_hold_vlan_t)); 796 (void) strlcpy(dhv.dhv_name, link, IFNAMSIZ); 797 dhv.dhv_zid = -1; 798 799 if (i_dladm_ioctl(fd, DLDIOCZIDGET, &dhv, sizeof (dhv)) < 0 && 800 errno != ENOENT) { 801 dladm_status_t status = dladm_errno2status(errno); 802 803 (void) close(fd); 804 return (status); 805 } 806 807 if (errno == ENOENT) 808 *zidp = GLOBAL_ZONEID; 809 else 810 *zidp = dhv.dhv_zid; 811 812 (void) close(fd); 813 return (DLADM_STATUS_OK); 814 } 815 816 typedef int (*zone_get_devroot_t)(char *, char *, size_t); 817 818 static int 819 i_dladm_get_zone_dev(char *zone_name, char *dev, size_t devlen) 820 { 821 char root[MAXPATHLEN]; 822 zone_get_devroot_t real_zone_get_devroot; 823 void *dlhandle; 824 void *sym; 825 int ret; 826 827 if ((dlhandle = dlopen("libzonecfg.so.1", RTLD_LAZY)) == NULL) 828 return (-1); 829 830 if ((sym = dlsym(dlhandle, "zone_get_devroot")) == NULL) { 831 (void) dlclose(dlhandle); 832 return (-1); 833 } 834 835 real_zone_get_devroot = (zone_get_devroot_t)sym; 836 837 if ((ret = real_zone_get_devroot(zone_name, root, sizeof (root))) == 0) 838 (void) snprintf(dev, devlen, "%s%s", root, "/dev"); 839 (void) dlclose(dlhandle); 840 return (ret); 841 } 842 843 static dladm_status_t 844 i_dladm_add_deventry(zoneid_t zid, const char *link) 845 { 846 char path[MAXPATHLEN]; 847 di_prof_t prof = NULL; 848 char zone_name[ZONENAME_MAX]; 849 dladm_status_t status; 850 851 if (getzonenamebyid(zid, zone_name, sizeof (zone_name)) < 0) 852 return (dladm_errno2status(errno)); 853 if (i_dladm_get_zone_dev(zone_name, path, sizeof (path)) != 0) 854 return (dladm_errno2status(errno)); 855 if (di_prof_init(path, &prof) != 0) 856 return (dladm_errno2status(errno)); 857 858 status = DLADM_STATUS_OK; 859 if (di_prof_add_dev(prof, link) != 0) { 860 status = dladm_errno2status(errno); 861 goto cleanup; 862 } 863 if (di_prof_commit(prof) != 0) 864 status = dladm_errno2status(errno); 865 cleanup: 866 if (prof) 867 di_prof_fini(prof); 868 869 return (status); 870 } 871 872 static dladm_status_t 873 i_dladm_remove_deventry(zoneid_t zid, const char *link) 874 { 875 char path[MAXPATHLEN]; 876 di_prof_t prof = NULL; 877 char zone_name[ZONENAME_MAX]; 878 dladm_status_t status; 879 880 if (getzonenamebyid(zid, zone_name, sizeof (zone_name)) < 0) 881 return (dladm_errno2status(errno)); 882 if (i_dladm_get_zone_dev(zone_name, path, sizeof (path)) != 0) 883 return (dladm_errno2status(errno)); 884 if (di_prof_init(path, &prof) != 0) 885 return (dladm_errno2status(errno)); 886 887 status = DLADM_STATUS_OK; 888 if (di_prof_add_exclude(prof, link) != 0) { 889 status = dladm_errno2status(errno); 890 goto cleanup; 891 } 892 if (di_prof_commit(prof) != 0) 893 status = dladm_errno2status(errno); 894 cleanup: 895 if (prof) 896 di_prof_fini(prof); 897 898 return (status); 899 } 900 901 static dladm_status_t 902 do_get_zone(const char *link, char **prop_val, uint_t *val_cnt) 903 { 904 char zone_name[ZONENAME_MAX]; 905 zoneid_t zid; 906 dladm_status_t status; 907 908 status = i_dladm_get_zoneid(link, &zid); 909 if (status != DLADM_STATUS_OK) 910 return (status); 911 912 *val_cnt = 1; 913 if (zid != GLOBAL_ZONEID) { 914 if (getzonenamebyid(zid, zone_name, sizeof (zone_name)) < 0) 915 return (dladm_errno2status(errno)); 916 917 (void) strncpy(*prop_val, zone_name, DLADM_PROP_VAL_MAX); 918 } else { 919 *prop_val[0] = '\0'; 920 } 921 922 return (DLADM_STATUS_OK); 923 } 924 925 static dladm_status_t 926 do_set_zone(const char *link, val_desc_t *vdp, uint_t val_cnt) 927 { 928 dladm_status_t status; 929 zoneid_t zid_old, zid_new; 930 char buff[IF_NAMESIZE + 1]; 931 struct stat st; 932 933 if (val_cnt != 1) 934 return (DLADM_STATUS_BADVALCNT); 935 936 status = i_dladm_get_zoneid(link, &zid_old); 937 if (status != DLADM_STATUS_OK) 938 return (status); 939 940 /* Do nothing if setting to current value */ 941 zid_new = (zoneid_t)vdp->vd_val; 942 if (zid_new == zid_old) 943 return (DLADM_STATUS_OK); 944 945 /* Do a stat to get the vlan created by MAC, if it's not there */ 946 (void) strcpy(buff, "/dev/"); 947 (void) strlcat(buff, link, IF_NAMESIZE); 948 (void) stat(buff, &st); 949 950 if (zid_old != GLOBAL_ZONEID) { 951 if (dladm_rele_link(link, GLOBAL_ZONEID, B_TRUE) < 0) 952 return (dladm_errno2status(errno)); 953 954 if (zone_remove_datalink(zid_old, (char *)link) != 0 && 955 errno != ENXIO) { 956 status = dladm_errno2status(errno); 957 goto rollback1; 958 } 959 960 status = i_dladm_remove_deventry(zid_old, link); 961 if (status != DLADM_STATUS_OK) 962 goto rollback2; 963 } 964 965 if (zid_new != GLOBAL_ZONEID) { 966 if (zone_add_datalink(zid_new, (char *)link) != 0) { 967 status = dladm_errno2status(errno); 968 goto rollback3; 969 } 970 971 if (dladm_hold_link(link, zid_new, B_TRUE) < 0) { 972 (void) zone_remove_datalink(zid_new, (char *)link); 973 status = dladm_errno2status(errno); 974 goto rollback3; 975 } 976 977 status = i_dladm_add_deventry(zid_new, link); 978 if (status != DLADM_STATUS_OK) { 979 (void) dladm_rele_link(link, GLOBAL_ZONEID, B_FALSE); 980 (void) zone_remove_datalink(zid_new, (char *)link); 981 goto rollback3; 982 } 983 } 984 return (DLADM_STATUS_OK); 985 986 rollback3: 987 if (zid_old != GLOBAL_ZONEID) 988 (void) i_dladm_add_deventry(zid_old, link); 989 rollback2: 990 if (zid_old != GLOBAL_ZONEID) 991 (void) zone_add_datalink(zid_old, (char *)link); 992 rollback1: 993 (void) dladm_hold_link(link, zid_old, B_FALSE); 994 cleanexit: 995 return (status); 996 } 997 998 /* ARGSUSED */ 999 static dladm_status_t 1000 do_check_zone(prop_desc_t *pdp, char **prop_val, uint_t val_cnt, 1001 val_desc_t **vdpp) 1002 { 1003 zoneid_t zid; 1004 val_desc_t *vdp = NULL; 1005 1006 if (val_cnt != 1) 1007 return (DLADM_STATUS_BADVALCNT); 1008 1009 if ((zid = getzoneidbyname(*prop_val)) == -1) 1010 return (DLADM_STATUS_BADVAL); 1011 1012 if (zid != GLOBAL_ZONEID) { 1013 ushort_t flags; 1014 1015 if (zone_getattr(zid, ZONE_ATTR_FLAGS, &flags, 1016 sizeof (flags)) < 0) { 1017 return (dladm_errno2status(errno)); 1018 } 1019 1020 if (!(flags & ZF_NET_EXCL)) { 1021 return (DLADM_STATUS_BADVAL); 1022 } 1023 } 1024 1025 vdp = malloc(sizeof (val_desc_t)); 1026 if (vdp == NULL) 1027 return (DLADM_STATUS_NOMEM); 1028 1029 vdp->vd_val = (void *)zid; 1030 *vdpp = vdp; 1031 return (DLADM_STATUS_OK); 1032 } 1033 1034 static dladm_status_t 1035 i_dladm_get_prop_temp(const char *link, dladm_prop_type_t type, 1036 const char *prop_name, char **prop_val, uint_t *val_cntp) 1037 { 1038 int i; 1039 dladm_status_t status; 1040 uint_t cnt; 1041 prop_desc_t *pdp; 1042 1043 if (link == NULL || prop_name == NULL || prop_val == NULL || 1044 val_cntp == NULL || *val_cntp == 0) 1045 return (DLADM_STATUS_BADARG); 1046 1047 for (i = 0; i < MAX_PROPS; i++) 1048 if (strcasecmp(prop_name, prop_table[i].pd_name) == 0) 1049 break; 1050 1051 if (i == MAX_PROPS) 1052 return (DLADM_STATUS_NOTFOUND); 1053 1054 pdp = &prop_table[i]; 1055 status = DLADM_STATUS_OK; 1056 1057 switch (type) { 1058 case DLADM_PROP_VAL_CURRENT: 1059 status = pdp->pd_get(link, prop_val, val_cntp); 1060 break; 1061 case DLADM_PROP_VAL_DEFAULT: 1062 if (pdp->pd_defval.vd_name == NULL) { 1063 status = DLADM_STATUS_NOTSUP; 1064 break; 1065 } 1066 (void) strcpy(*prop_val, pdp->pd_defval.vd_name); 1067 *val_cntp = 1; 1068 break; 1069 1070 case DLADM_PROP_VAL_MODIFIABLE: 1071 if (pdp->pd_getmod != NULL) { 1072 status = pdp->pd_getmod(link, prop_val, val_cntp); 1073 break; 1074 } 1075 cnt = pdp->pd_nmodval; 1076 if (cnt == 0) { 1077 status = DLADM_STATUS_NOTSUP; 1078 } else if (cnt > *val_cntp) { 1079 status = DLADM_STATUS_TOOSMALL; 1080 } else { 1081 for (i = 0; i < cnt; i++) { 1082 (void) strcpy(prop_val[i], 1083 pdp->pd_modval[i].vd_name); 1084 } 1085 *val_cntp = cnt; 1086 } 1087 break; 1088 default: 1089 status = DLADM_STATUS_BADARG; 1090 break; 1091 } 1092 1093 return (status); 1094 } 1095 1096 static dladm_status_t 1097 i_dladm_set_one_prop_temp(const char *link, prop_desc_t *pdp, char **prop_val, 1098 uint_t val_cnt, uint_t flags) 1099 { 1100 dladm_status_t status; 1101 val_desc_t *vdp = NULL; 1102 uint_t cnt; 1103 1104 if (pdp->pd_temponly && (flags & DLADM_OPT_PERSIST) != 0) 1105 return (DLADM_STATUS_TEMPONLY); 1106 1107 if (pdp->pd_set == NULL) 1108 return (DLADM_STATUS_PROPRDONLY); 1109 1110 if (prop_val != NULL) { 1111 if (pdp->pd_check != NULL) 1112 status = pdp->pd_check(pdp, prop_val, val_cnt, &vdp); 1113 else 1114 status = DLADM_STATUS_BADARG; 1115 1116 if (status != DLADM_STATUS_OK) 1117 return (status); 1118 1119 cnt = val_cnt; 1120 } else { 1121 if (pdp->pd_defval.vd_name == NULL) 1122 return (DLADM_STATUS_NOTSUP); 1123 1124 if ((vdp = malloc(sizeof (val_desc_t))) == NULL) 1125 return (DLADM_STATUS_NOMEM); 1126 1127 (void) memcpy(vdp, &pdp->pd_defval, sizeof (val_desc_t)); 1128 cnt = 1; 1129 } 1130 1131 status = pdp->pd_set(link, vdp, cnt); 1132 1133 free(vdp); 1134 return (status); 1135 } 1136 1137 static dladm_status_t 1138 i_dladm_set_prop_temp(const char *link, const char *prop_name, char **prop_val, 1139 uint_t val_cnt, uint_t flags, char **errprop) 1140 { 1141 int i; 1142 dladm_status_t status = DLADM_STATUS_OK; 1143 boolean_t found = B_FALSE; 1144 1145 for (i = 0; i < MAX_PROPS; i++) { 1146 prop_desc_t *pdp = &prop_table[i]; 1147 dladm_status_t s; 1148 1149 if (prop_name != NULL && 1150 (strcasecmp(prop_name, pdp->pd_name) != 0)) 1151 continue; 1152 1153 found = B_TRUE; 1154 s = i_dladm_set_one_prop_temp(link, pdp, prop_val, val_cnt, 1155 flags); 1156 1157 if (prop_name != NULL) { 1158 status = s; 1159 break; 1160 } else { 1161 if (s != DLADM_STATUS_OK && 1162 s != DLADM_STATUS_NOTSUP) { 1163 if (errprop != NULL) 1164 *errprop = pdp->pd_name; 1165 status = s; 1166 break; 1167 } 1168 } 1169 } 1170 1171 if (!found) 1172 status = DLADM_STATUS_NOTFOUND; 1173 1174 return (status); 1175 } 1176 1177 static boolean_t 1178 i_dladm_is_prop_temponly(const char *prop_name, char **errprop) 1179 { 1180 int i; 1181 1182 for (i = 0; i < MAX_PROPS; i++) { 1183 prop_desc_t *pdp = &prop_table[i]; 1184 1185 if (prop_name != NULL && 1186 (strcasecmp(prop_name, pdp->pd_name) != 0)) 1187 continue; 1188 1189 if (errprop != NULL) 1190 *errprop = pdp->pd_name; 1191 1192 if (pdp->pd_temponly) 1193 return (B_TRUE); 1194 } 1195 1196 return (B_FALSE); 1197 } 1198 1199 boolean_t 1200 dladm_is_prop_temponly(const char *prop_name, char **errprop) 1201 { 1202 return (i_dladm_is_prop_temponly(prop_name, errprop)); 1203 } 1204