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