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 /* 23 * Copyright 2008 Sun Microsystems, Inc. All rights reserved. 24 * Use is subject to license terms. 25 */ 26 27 #pragma ident "%Z%%M% %I% %E% SMI" 28 29 /* 30 * Utility functions used by the dlmgmtd daemon. 31 */ 32 33 #include <assert.h> 34 #include <pthread.h> 35 #include <stddef.h> 36 #include <stdlib.h> 37 #include <stdio.h> 38 #include <strings.h> 39 #include <syslog.h> 40 #include <stdarg.h> 41 #include <libdlpi.h> 42 #include "dlmgmt_impl.h" 43 44 /* 45 * There are two datalink AVL tables. One table (dlmgmt_name_avl) is keyed by 46 * the link name, and the other (dlmgmt_id_avl) is keyed by the link id. 47 * Each link will be present in both tables. 48 */ 49 avl_tree_t dlmgmt_name_avl; 50 avl_tree_t dlmgmt_id_avl; 51 52 avl_tree_t dlmgmt_dlconf_avl; 53 54 static pthread_rwlock_t dlmgmt_avl_lock = PTHREAD_RWLOCK_INITIALIZER; 55 static pthread_mutex_t dlmgmt_avl_mutex = PTHREAD_MUTEX_INITIALIZER; 56 static pthread_cond_t dlmgmt_avl_cv = PTHREAD_COND_INITIALIZER; 57 static pthread_rwlock_t dlmgmt_dlconf_lock = PTHREAD_RWLOCK_INITIALIZER; 58 59 typedef struct dlmgmt_prefix { 60 struct dlmgmt_prefix *lp_next; 61 char lp_prefix[MAXLINKNAMELEN]; 62 uint_t lp_nextppa; 63 } dlmgmt_prefix_t; 64 static dlmgmt_prefix_t *dlmgmt_prefixlist; 65 66 static datalink_id_t dlmgmt_nextlinkid; 67 static datalink_id_t dlmgmt_nextconfid = 1; 68 69 static int linkattr_add(dlmgmt_linkattr_t **, 70 dlmgmt_linkattr_t *); 71 static int linkattr_rm(dlmgmt_linkattr_t **, 72 dlmgmt_linkattr_t *); 73 static int link_create(const char *, datalink_class_t, uint32_t, 74 uint32_t, dlmgmt_link_t **); 75 76 static void dlmgmt_advance_linkid(dlmgmt_link_t *); 77 static void dlmgmt_advance_ppa(dlmgmt_link_t *); 78 79 void 80 dlmgmt_log(int pri, const char *fmt, ...) 81 { 82 va_list alist; 83 84 va_start(alist, fmt); 85 if (debug) { 86 (void) vfprintf(stderr, fmt, alist); 87 (void) fputc('\n', stderr); 88 } else { 89 vsyslog(pri, fmt, alist); 90 } 91 va_end(alist); 92 } 93 94 static int 95 cmp_link_by_name(const void *v1, const void *v2) 96 { 97 const dlmgmt_link_t *link1 = v1; 98 const dlmgmt_link_t *link2 = v2; 99 int cmp; 100 101 cmp = strcmp(link1->ll_link, link2->ll_link); 102 return ((cmp == 0) ? 0 : ((cmp < 0) ? -1 : 1)); 103 } 104 105 static int 106 cmp_link_by_id(const void *v1, const void *v2) 107 { 108 const dlmgmt_link_t *link1 = v1; 109 const dlmgmt_link_t *link2 = v2; 110 111 if ((uint64_t)(link1->ll_linkid) == (uint64_t)(link2->ll_linkid)) 112 return (0); 113 else if ((uint64_t)(link1->ll_linkid) < (uint64_t)(link2->ll_linkid)) 114 return (-1); 115 else 116 return (1); 117 } 118 119 static int 120 cmp_dlconf_by_id(const void *v1, const void *v2) 121 { 122 const dlmgmt_dlconf_t *dlconfp1 = v1; 123 const dlmgmt_dlconf_t *dlconfp2 = v2; 124 125 if (dlconfp1->ld_id == dlconfp2->ld_id) 126 return (0); 127 else if (dlconfp1->ld_id < dlconfp2->ld_id) 128 return (-1); 129 else 130 return (1); 131 } 132 133 int 134 dlmgmt_linktable_init() 135 { 136 /* 137 * Initialize the prefix list. First add the "net" prefix to the list. 138 */ 139 dlmgmt_prefixlist = malloc(sizeof (dlmgmt_prefix_t)); 140 if (dlmgmt_prefixlist == NULL) { 141 dlmgmt_log(LOG_WARNING, "dlmgmt_linktable_init() failed: %s", 142 strerror(ENOMEM)); 143 return (ENOMEM); 144 } 145 146 dlmgmt_prefixlist->lp_next = NULL; 147 dlmgmt_prefixlist->lp_nextppa = 0; 148 (void) strlcpy(dlmgmt_prefixlist->lp_prefix, "net", MAXLINKNAMELEN); 149 150 avl_create(&dlmgmt_name_avl, cmp_link_by_name, sizeof (dlmgmt_link_t), 151 offsetof(dlmgmt_link_t, ll_node_by_name)); 152 avl_create(&dlmgmt_id_avl, cmp_link_by_id, sizeof (dlmgmt_link_t), 153 offsetof(dlmgmt_link_t, ll_node_by_id)); 154 avl_create(&dlmgmt_dlconf_avl, cmp_dlconf_by_id, 155 sizeof (dlmgmt_dlconf_t), offsetof(dlmgmt_dlconf_t, ld_node)); 156 dlmgmt_nextlinkid = 1; 157 return (0); 158 } 159 160 void 161 dlmgmt_linktable_fini() 162 { 163 dlmgmt_prefix_t *lpp, *next; 164 165 for (lpp = dlmgmt_prefixlist; lpp != NULL; lpp = next) { 166 next = lpp->lp_next; 167 free(lpp); 168 } 169 170 avl_destroy(&dlmgmt_dlconf_avl); 171 avl_destroy(&dlmgmt_name_avl); 172 avl_destroy(&dlmgmt_id_avl); 173 } 174 175 static int 176 linkattr_add(dlmgmt_linkattr_t **headp, dlmgmt_linkattr_t *attrp) 177 { 178 if (*headp == NULL) { 179 *headp = attrp; 180 } else { 181 (*headp)->lp_prev = attrp; 182 attrp->lp_next = *headp; 183 *headp = attrp; 184 } 185 return (0); 186 } 187 188 static int 189 linkattr_rm(dlmgmt_linkattr_t **headp, dlmgmt_linkattr_t *attrp) 190 { 191 dlmgmt_linkattr_t *next, *prev; 192 193 next = attrp->lp_next; 194 prev = attrp->lp_prev; 195 if (next != NULL) 196 next->lp_prev = prev; 197 if (prev != NULL) 198 prev->lp_next = next; 199 else 200 *headp = next; 201 202 return (0); 203 } 204 205 int 206 linkattr_set(dlmgmt_linkattr_t **headp, const char *attr, void *attrval, 207 size_t attrsz, dladm_datatype_t type) 208 { 209 dlmgmt_linkattr_t *attrp; 210 int err; 211 212 /* 213 * See whether the attr is already set. 214 */ 215 for (attrp = *headp; attrp != NULL; attrp = attrp->lp_next) { 216 if (strcmp(attrp->lp_name, attr) == 0) 217 break; 218 } 219 220 if (attrp != NULL) { 221 /* 222 * It is already set. If the value changed, update it. 223 */ 224 if (linkattr_equal(headp, attr, attrval, attrsz)) 225 return (0); 226 227 free(attrp->lp_val); 228 } else { 229 /* 230 * It is not set yet, allocate the linkattr and prepend to the 231 * list. 232 */ 233 if ((attrp = calloc(1, sizeof (dlmgmt_linkattr_t))) == NULL) 234 return (ENOMEM); 235 236 if ((err = linkattr_add(headp, attrp)) != 0) { 237 free(attrp); 238 return (err); 239 } 240 (void) strlcpy(attrp->lp_name, attr, MAXLINKATTRLEN); 241 } 242 if ((attrp->lp_val = calloc(1, attrsz)) == NULL) { 243 (void) linkattr_rm(headp, attrp); 244 free(attrp); 245 return (ENOMEM); 246 } 247 248 bcopy(attrval, attrp->lp_val, attrsz); 249 attrp->lp_sz = attrsz; 250 attrp->lp_type = type; 251 return (0); 252 } 253 254 int 255 linkattr_unset(dlmgmt_linkattr_t **headp, const char *attr) 256 { 257 dlmgmt_linkattr_t *attrp, *prev; 258 259 /* 260 * See whether the attr exists. 261 */ 262 for (prev = NULL, attrp = *headp; attrp != NULL; 263 prev = attrp, attrp = attrp->lp_next) { 264 if (strcmp(attrp->lp_name, attr) == 0) 265 break; 266 } 267 268 /* 269 * This attribute is not set in the first place. Return success. 270 */ 271 if (attrp == NULL) 272 return (0); 273 274 /* 275 * Remove this attr from the list. 276 */ 277 if (prev == NULL) 278 *headp = attrp->lp_next; 279 else 280 prev->lp_next = attrp->lp_next; 281 282 free(attrp->lp_val); 283 free(attrp); 284 return (0); 285 } 286 287 int 288 linkattr_get(dlmgmt_linkattr_t **headp, const char *attr, void **attrvalp, 289 size_t *attrszp, dladm_datatype_t *typep) 290 { 291 dlmgmt_linkattr_t *attrp = *headp; 292 293 /* 294 * find the specific attr. 295 */ 296 for (attrp = *headp; attrp != NULL; attrp = attrp->lp_next) { 297 if (strcmp(attrp->lp_name, attr) == 0) 298 break; 299 } 300 301 if (attrp == NULL) 302 return (ENOENT); 303 304 *attrvalp = attrp->lp_val; 305 *attrszp = attrp->lp_sz; 306 if (typep != NULL) 307 *typep = attrp->lp_type; 308 return (0); 309 } 310 311 boolean_t 312 linkattr_equal(dlmgmt_linkattr_t **headp, const char *attr, void *attrval, 313 size_t attrsz) 314 { 315 void *saved_attrval; 316 size_t saved_attrsz; 317 318 if (linkattr_get(headp, attr, &saved_attrval, &saved_attrsz, NULL) != 0) 319 return (B_FALSE); 320 321 return ((saved_attrsz == attrsz) && 322 (memcmp(saved_attrval, attrval, attrsz) == 0)); 323 } 324 325 static int 326 dlmgmt_table_readwritelock(boolean_t write) 327 { 328 if (write) 329 return (pthread_rwlock_trywrlock(&dlmgmt_avl_lock)); 330 else 331 return (pthread_rwlock_tryrdlock(&dlmgmt_avl_lock)); 332 } 333 334 void 335 dlmgmt_table_lock(boolean_t write) 336 { 337 (void) pthread_mutex_lock(&dlmgmt_avl_mutex); 338 while (dlmgmt_table_readwritelock(write) == EBUSY) 339 (void) pthread_cond_wait(&dlmgmt_avl_cv, &dlmgmt_avl_mutex); 340 341 (void) pthread_mutex_unlock(&dlmgmt_avl_mutex); 342 } 343 344 void 345 dlmgmt_table_unlock() 346 { 347 (void) pthread_rwlock_unlock(&dlmgmt_avl_lock); 348 (void) pthread_mutex_lock(&dlmgmt_avl_mutex); 349 (void) pthread_cond_broadcast(&dlmgmt_avl_cv); 350 (void) pthread_mutex_unlock(&dlmgmt_avl_mutex); 351 } 352 353 static int 354 link_create(const char *name, datalink_class_t class, uint32_t media, 355 uint32_t flags, dlmgmt_link_t **linkpp) 356 { 357 dlmgmt_link_t *linkp = NULL; 358 int err = 0; 359 360 if (dlmgmt_nextlinkid == DATALINK_INVALID_LINKID) { 361 err = ENOSPC; 362 goto done; 363 } 364 365 if ((linkp = calloc(1, sizeof (dlmgmt_link_t))) == NULL) { 366 err = ENOMEM; 367 goto done; 368 } 369 370 (void) strlcpy(linkp->ll_link, name, MAXLINKNAMELEN); 371 linkp->ll_class = class; 372 linkp->ll_media = media; 373 linkp->ll_linkid = dlmgmt_nextlinkid; 374 linkp->ll_flags = flags; 375 linkp->ll_gen = 0; 376 done: 377 *linkpp = linkp; 378 return (err); 379 } 380 381 void 382 link_destroy(dlmgmt_link_t *linkp) 383 { 384 dlmgmt_linkattr_t *next, *attrp; 385 386 for (attrp = linkp->ll_head; attrp != NULL; attrp = next) { 387 next = attrp->lp_next; 388 free(attrp->lp_val); 389 free(attrp); 390 } 391 free(linkp); 392 } 393 394 dlmgmt_link_t * 395 link_by_id(datalink_id_t linkid) 396 { 397 dlmgmt_link_t link; 398 399 link.ll_linkid = linkid; 400 return (avl_find(&dlmgmt_id_avl, &link, NULL)); 401 } 402 403 dlmgmt_link_t * 404 link_by_name(const char *name) 405 { 406 dlmgmt_link_t link; 407 408 (void) strlcpy(link.ll_link, name, MAXLINKNAMELEN); 409 return (avl_find(&dlmgmt_name_avl, &link, NULL)); 410 } 411 412 int 413 dlmgmt_create_common(const char *name, datalink_class_t class, uint32_t media, 414 uint32_t flags, dlmgmt_link_t **linkpp) 415 { 416 dlmgmt_link_t link, *linkp, *tmp; 417 avl_index_t name_where, id_where; 418 int err; 419 420 /* 421 * Validate the link. 422 */ 423 if (!dladm_valid_linkname(name)) 424 return (EINVAL); 425 426 /* 427 * Check to see whether this is an existing link name. 428 */ 429 (void) strlcpy(link.ll_link, name, MAXLINKNAMELEN); 430 if ((linkp = avl_find(&dlmgmt_name_avl, &link, &name_where)) != NULL) 431 return (EEXIST); 432 433 if ((err = link_create(name, class, media, flags, &linkp)) != 0) 434 return (err); 435 436 link.ll_linkid = linkp->ll_linkid; 437 tmp = avl_find(&dlmgmt_id_avl, &link, &id_where); 438 assert(tmp == NULL); 439 avl_insert(&dlmgmt_name_avl, linkp, name_where); 440 avl_insert(&dlmgmt_id_avl, linkp, id_where); 441 dlmgmt_advance(linkp); 442 *linkpp = linkp; 443 return (0); 444 } 445 446 int 447 dlmgmt_destroy_common(dlmgmt_link_t *linkp, uint32_t flags) 448 { 449 if ((linkp->ll_flags & flags) == 0) { 450 /* 451 * The link does not exist in the specified space. 452 */ 453 return (ENOENT); 454 } 455 linkp->ll_flags &= ~flags; 456 if (!(linkp->ll_flags & DLMGMT_PERSIST)) { 457 dlmgmt_linkattr_t *next, *attrp; 458 459 for (attrp = linkp->ll_head; attrp != NULL; attrp = next) { 460 next = attrp->lp_next; 461 free(attrp->lp_val); 462 free(attrp); 463 } 464 linkp->ll_head = NULL; 465 } 466 467 if (linkp->ll_flags == 0) { 468 avl_remove(&dlmgmt_id_avl, linkp); 469 avl_remove(&dlmgmt_name_avl, linkp); 470 link_destroy(linkp); 471 } 472 473 return (0); 474 } 475 476 int 477 dlmgmt_getattr_common(dlmgmt_linkattr_t **headp, const char *attr, 478 dlmgmt_getattr_retval_t **retvalpp, size_t *retszp) 479 { 480 int err; 481 void *attrval; 482 size_t attrsz; 483 dladm_datatype_t attrtype; 484 dlmgmt_getattr_retval_t *retvalp; 485 486 err = linkattr_get(headp, attr, &attrval, &attrsz, &attrtype); 487 if (err != 0) 488 return (err); 489 490 assert(attrsz > 0); 491 *retszp = sizeof (dlmgmt_getattr_retval_t) + attrsz - 1; 492 if ((retvalp = malloc(*retszp)) == NULL) 493 return (ENOMEM); 494 495 retvalp->lr_err = 0; 496 retvalp->lr_type = attrtype; 497 bcopy(attrval, retvalp->lr_attr, attrsz); 498 *retvalpp = retvalp; 499 return (0); 500 } 501 502 void 503 dlmgmt_dlconf_table_lock(boolean_t write) 504 { 505 if (write) 506 (void) pthread_rwlock_wrlock(&dlmgmt_dlconf_lock); 507 else 508 (void) pthread_rwlock_rdlock(&dlmgmt_dlconf_lock); 509 } 510 511 void 512 dlmgmt_dlconf_table_unlock() 513 { 514 (void) pthread_rwlock_unlock(&dlmgmt_dlconf_lock); 515 } 516 517 int 518 dlconf_create(const char *name, datalink_id_t linkid, datalink_class_t class, 519 uint32_t media, dlmgmt_dlconf_t **dlconfpp) 520 { 521 dlmgmt_dlconf_t *dlconfp = NULL; 522 int err = 0; 523 524 if (dlmgmt_nextconfid == 0) { 525 err = ENOSPC; 526 goto done; 527 } 528 529 if ((dlconfp = calloc(1, sizeof (dlmgmt_dlconf_t))) == NULL) { 530 err = ENOMEM; 531 goto done; 532 } 533 534 (void) strlcpy(dlconfp->ld_link, name, MAXLINKNAMELEN); 535 dlconfp->ld_linkid = linkid; 536 dlconfp->ld_class = class; 537 dlconfp->ld_media = media; 538 dlconfp->ld_id = dlmgmt_nextconfid; 539 540 done: 541 *dlconfpp = dlconfp; 542 return (err); 543 } 544 545 void 546 dlconf_destroy(dlmgmt_dlconf_t *dlconfp) 547 { 548 dlmgmt_linkattr_t *next, *attrp; 549 550 for (attrp = dlconfp->ld_head; attrp != NULL; attrp = next) { 551 next = attrp->lp_next; 552 free(attrp->lp_val); 553 free(attrp); 554 } 555 free(dlconfp); 556 } 557 558 int 559 dlmgmt_generate_name(const char *prefix, char *name, size_t size) 560 { 561 dlmgmt_prefix_t *lpp, *prev = NULL; 562 563 /* 564 * See whether the requested prefix is already in the list. 565 */ 566 for (lpp = dlmgmt_prefixlist; lpp != NULL; prev = lpp, 567 lpp = lpp->lp_next) { 568 if (strcmp(prefix, lpp->lp_prefix) == 0) 569 break; 570 } 571 572 /* 573 * Not found. 574 */ 575 if (lpp == NULL) { 576 dlmgmt_link_t *linkp, link; 577 578 assert(prev != NULL); 579 580 /* 581 * First add this new prefix into the prefix list. 582 */ 583 if ((lpp = malloc(sizeof (dlmgmt_prefix_t))) == NULL) 584 return (ENOMEM); 585 586 prev->lp_next = lpp; 587 lpp->lp_next = NULL; 588 lpp->lp_nextppa = 0; 589 (void) strlcpy(lpp->lp_prefix, prefix, MAXLINKNAMELEN); 590 591 /* 592 * Now determine this prefix's nextppa. 593 */ 594 (void) snprintf(link.ll_link, MAXLINKNAMELEN, "%s%d", 595 prefix, lpp->lp_nextppa); 596 linkp = avl_find(&dlmgmt_name_avl, &link, NULL); 597 if (linkp != NULL) 598 dlmgmt_advance_ppa(linkp); 599 } 600 601 if (lpp->lp_nextppa == (uint_t)-1) 602 return (ENOSPC); 603 604 (void) snprintf(name, size, "%s%d", prefix, lpp->lp_nextppa); 605 return (0); 606 } 607 608 /* 609 * Advance the next available ppa value if the name prefix of the current 610 * link is in the prefix list. 611 */ 612 static void 613 dlmgmt_advance_ppa(dlmgmt_link_t *linkp) 614 { 615 dlmgmt_prefix_t *lpp; 616 char prefix[MAXLINKNAMELEN]; 617 uint_t start, ppa; 618 619 (void) dlpi_parselink(linkp->ll_link, prefix, &ppa); 620 621 /* 622 * See whether the requested prefix is already in the list. 623 */ 624 for (lpp = dlmgmt_prefixlist; lpp != NULL; lpp = lpp->lp_next) { 625 if (strcmp(prefix, lpp->lp_prefix) == 0) 626 break; 627 } 628 629 /* 630 * If the link name prefix is in the list, advance the 631 * next available ppa for the <prefix>N name. 632 */ 633 if (lpp == NULL || lpp->lp_nextppa != ppa) 634 return; 635 636 start = lpp->lp_nextppa++; 637 linkp = AVL_NEXT(&dlmgmt_name_avl, linkp); 638 while (lpp->lp_nextppa != start) { 639 if (lpp->lp_nextppa == (uint_t)-1) { 640 dlmgmt_link_t link; 641 642 /* 643 * wrapped around. search from <prefix>1. 644 */ 645 lpp->lp_nextppa = 0; 646 (void) snprintf(link.ll_link, MAXLINKNAMELEN, 647 "%s%d", lpp->lp_prefix, lpp->lp_nextppa); 648 linkp = avl_find(&dlmgmt_name_avl, &link, NULL); 649 if (linkp == NULL) 650 return; 651 } else { 652 if (linkp == NULL) 653 return; 654 (void) dlpi_parselink(linkp->ll_link, prefix, &ppa); 655 if ((strcmp(prefix, lpp->lp_prefix) != 0) || 656 (ppa != lpp->lp_nextppa)) { 657 return; 658 } 659 } 660 linkp = AVL_NEXT(&dlmgmt_name_avl, linkp); 661 lpp->lp_nextppa++; 662 } 663 lpp->lp_nextppa = (uint_t)-1; 664 } 665 666 /* 667 * Advance to the next available linkid value. 668 */ 669 static void 670 dlmgmt_advance_linkid(dlmgmt_link_t *linkp) 671 { 672 datalink_id_t start; 673 674 if (linkp->ll_linkid != dlmgmt_nextlinkid) 675 return; 676 677 start = dlmgmt_nextlinkid; 678 linkp = AVL_NEXT(&dlmgmt_id_avl, linkp); 679 680 do { 681 if (dlmgmt_nextlinkid == DATALINK_MAX_LINKID) { 682 dlmgmt_link_t link; 683 684 /* 685 * wrapped around. search from 1. 686 */ 687 dlmgmt_nextlinkid = 1; 688 link.ll_linkid = 1; 689 linkp = avl_find(&dlmgmt_id_avl, &link, NULL); 690 if (linkp == NULL) 691 return; 692 } else { 693 dlmgmt_nextlinkid++; 694 if (linkp == NULL) 695 return; 696 if (linkp->ll_linkid != dlmgmt_nextlinkid) 697 return; 698 } 699 700 linkp = AVL_NEXT(&dlmgmt_id_avl, linkp); 701 } while (dlmgmt_nextlinkid != start); 702 703 dlmgmt_nextlinkid = DATALINK_INVALID_LINKID; 704 } 705 706 /* 707 * Advance various global values, for example, next linkid value, next ppa for 708 * various prefix etc. 709 */ 710 void 711 dlmgmt_advance(dlmgmt_link_t *linkp) 712 { 713 dlmgmt_advance_linkid(linkp); 714 dlmgmt_advance_ppa(linkp); 715 } 716 717 /* 718 * Advance to the next available dlconf id. 719 */ 720 void 721 dlmgmt_advance_dlconfid(dlmgmt_dlconf_t *dlconfp) 722 { 723 uint_t start; 724 725 start = dlmgmt_nextconfid++; 726 dlconfp = AVL_NEXT(&dlmgmt_dlconf_avl, dlconfp); 727 while (dlmgmt_nextconfid != start) { 728 if (dlmgmt_nextconfid == 0) { 729 dlmgmt_dlconf_t dlconf; 730 731 /* 732 * wrapped around. search from 1. 733 */ 734 dlconf.ld_id = dlmgmt_nextconfid = 1; 735 dlconfp = avl_find(&dlmgmt_name_avl, &dlconf, NULL); 736 if (dlconfp == NULL) 737 return; 738 } else { 739 if ((dlconfp == NULL) || 740 (dlconfp->ld_id != dlmgmt_nextconfid)) { 741 return; 742 } 743 } 744 dlconfp = AVL_NEXT(&dlmgmt_name_avl, dlconfp); 745 dlmgmt_nextconfid++; 746 } 747 dlmgmt_nextconfid = 0; 748 } 749