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 2008 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 <synch.h> 29 #include <stdio.h> 30 #include <syslog.h> 31 #include <stdlib.h> 32 #include <arpa/inet.h> 33 #include <netdb.h> 34 35 #include <smbsrv/libsmbns.h> 36 #include <smbns_netbios.h> 37 38 #define NETBIOS_HTAB_SZ 128 39 #define NETBIOS_HKEY_SZ (NETBIOS_NAME_SZ + NETBIOS_DOMAIN_NAME_MAX) 40 41 #define NETBIOS_NAMEBUF char namebuf[20] 42 43 #define NETBIOS_SAME_IP(addr1, addr2) \ 44 ((addr1)->sin.sin_addr.s_addr == (addr2)->sin.sin_addr.s_addr) 45 46 int smb_netbios_name_debug = 0; 47 48 typedef char nb_key_t[NETBIOS_HKEY_SZ]; 49 static HT_HANDLE *smb_netbios_cache = 0; 50 static rwlock_t nb_cache_lock; 51 52 static char *smb_strname(struct name_entry *name, char *buf, int bufsize); 53 static void hash_callback(HT_ITEM *item); 54 static int smb_netbios_match(const char *key1, const char *key2, size_t n); 55 static void smb_netbios_cache_key(char *key, unsigned char *name, 56 unsigned char *scope); 57 58 int 59 smb_netbios_cache_init() 60 { 61 (void) rw_wrlock(&nb_cache_lock); 62 if (smb_netbios_cache == 0) { 63 smb_netbios_cache = ht_create_table(NETBIOS_HTAB_SZ, 64 NETBIOS_HKEY_SZ, HTHF_FIXED_KEY); 65 if (smb_netbios_cache == 0) { 66 syslog(LOG_ERR, 67 "smbd: cannot create NetBIOS name cache"); 68 (void) rw_unlock(&nb_cache_lock); 69 return (0); 70 } 71 (void) ht_register_callback(smb_netbios_cache, hash_callback); 72 ht_set_cmpfn(smb_netbios_cache, smb_netbios_match); 73 } 74 (void) rw_unlock(&nb_cache_lock); 75 76 return (1); 77 } 78 79 void 80 smb_netbios_cache_fini() 81 { 82 (void) rw_wrlock(&nb_cache_lock); 83 ht_destroy_table(smb_netbios_cache); 84 smb_netbios_cache = 0; 85 (void) rw_unlock(&nb_cache_lock); 86 } 87 88 void 89 smb_netbios_cache_clean() 90 { 91 (void) rw_wrlock(&nb_cache_lock); 92 (void) ht_clean_table(smb_netbios_cache); 93 (void) rw_unlock(&nb_cache_lock); 94 } 95 96 /* 97 * smb_netbios_cache_lookup 98 * 99 * Searches the name cache for the given entry, if found 100 * the entry will be locked before returning to caller 101 * so caller MUST unlock the entry after it's done with it. 102 */ 103 struct name_entry * 104 smb_netbios_cache_lookup(struct name_entry *name) 105 { 106 HT_ITEM *item; 107 nb_key_t key; 108 struct name_entry *entry = NULL; 109 unsigned char scope[SMB_PI_MAX_SCOPE]; 110 unsigned char hostname[MAXHOSTNAMELEN]; 111 112 if (NETBIOS_NAME_IS_STAR(name->name)) { 113 /* Return our address */ 114 (void) smb_config_getstr(SMB_CI_NBSCOPE, (char *)scope, 115 sizeof (scope)); 116 (void) utf8_strupr((char *)scope); 117 118 if (smb_getnetbiosname((char *)hostname, MAXHOSTNAMELEN) != 0) 119 return (NULL); 120 121 smb_encode_netbios_name(hostname, 0x00, scope, name); 122 } 123 124 (void) rw_rdlock(&nb_cache_lock); 125 126 smb_netbios_cache_key(key, name->name, name->scope); 127 item = ht_find_item(smb_netbios_cache, key); 128 if (item) { 129 entry = (struct name_entry *)item->hi_data; 130 (void) mutex_lock(&entry->mtx); 131 if ((entry->attributes & NAME_ATTR_CONFLICT) != 0) { 132 (void) mutex_unlock(&entry->mtx); 133 entry = NULL; 134 } 135 } 136 137 (void) rw_unlock(&nb_cache_lock); 138 return (entry); 139 } 140 141 void 142 smb_netbios_cache_unlock_entry(struct name_entry *name) 143 { 144 if (name) 145 (void) mutex_unlock(&name->mtx); 146 } 147 148 /* 149 * smb_netbios_cache_lookup_addr 150 * 151 * lookup the given 'name' in the cache and then checks 152 * if the address also matches with the found entry. 153 * 'name' is supposed to contain only one address. 154 * 155 * The found entry will be locked before returning to caller 156 * so caller MUST unlock the entry after it's done with it. 157 */ 158 struct name_entry * 159 smb_netbios_cache_lookup_addr(struct name_entry *name) 160 { 161 struct name_entry *entry = 0; 162 struct addr_entry *addr; 163 struct addr_entry *name_addr; 164 HT_ITEM *item; 165 nb_key_t key; 166 167 (void) rw_rdlock(&nb_cache_lock); 168 smb_netbios_cache_key(key, name->name, name->scope); 169 item = ht_find_item(smb_netbios_cache, key); 170 171 if (item && item->hi_data) { 172 name_addr = &name->addr_list; 173 entry = (struct name_entry *)item->hi_data; 174 (void) mutex_lock(&entry->mtx); 175 addr = &entry->addr_list; 176 do { 177 if (NETBIOS_SAME_IP(addr, name_addr)) { 178 /* note that entry lock isn't released here */ 179 (void) rw_unlock(&nb_cache_lock); 180 return (entry); 181 } 182 addr = addr->forw; 183 } while (addr != &entry->addr_list); 184 (void) mutex_unlock(&entry->mtx); 185 } 186 187 (void) rw_unlock(&nb_cache_lock); 188 return (0); 189 } 190 191 int 192 smb_netbios_cache_insert(struct name_entry *name) 193 { 194 struct name_entry *entry; 195 struct addr_entry *addr; 196 struct addr_entry *name_addr; 197 HT_ITEM *item; 198 nb_key_t key; 199 200 /* No point in adding a name with IP address 255.255.255.255 */ 201 if (name->addr_list.sin.sin_addr.s_addr == 0xffffffff) 202 return (0); 203 204 (void) rw_wrlock(&nb_cache_lock); 205 smb_netbios_cache_key(key, name->name, name->scope); 206 item = ht_find_item(smb_netbios_cache, key); 207 208 if (item && item->hi_data) { 209 /* Name already exists */ 210 entry = (struct name_entry *)item->hi_data; 211 (void) mutex_lock(&entry->mtx); 212 213 name_addr = &name->addr_list; 214 addr = &entry->addr_list; 215 if (NETBIOS_SAME_IP(addr, name_addr) && 216 (addr->sin.sin_port == name_addr->sin.sin_port)) { 217 entry->attributes |= 218 name_addr->attributes & NAME_ATTR_LOCAL; 219 syslog(LOG_DEBUG, "cache_insert: exists"); 220 (void) mutex_unlock(&entry->mtx); 221 (void) rw_unlock(&nb_cache_lock); 222 return (0); /* exists */ 223 } 224 225 /* Was not primary: looks for others */ 226 for (addr = entry->addr_list.forw; 227 addr != &entry->addr_list; addr = addr->forw) { 228 if (NETBIOS_SAME_IP(addr, name_addr) && 229 (addr->sin.sin_port == name_addr->sin.sin_port)) { 230 syslog(LOG_DEBUG, "cache_insert: dup"); 231 (void) mutex_unlock(&entry->mtx); 232 (void) rw_unlock(&nb_cache_lock); 233 return (0); /* exists */ 234 } 235 } 236 237 addr = (struct addr_entry *)malloc(sizeof (struct addr_entry)); 238 if (addr == 0) { 239 (void) mutex_unlock(&entry->mtx); 240 (void) rw_unlock(&nb_cache_lock); 241 return (-1); 242 } 243 *addr = name->addr_list; 244 entry->attributes |= addr->attributes; 245 QUEUE_INSERT_TAIL(&entry->addr_list, addr); 246 (void) mutex_unlock(&entry->mtx); 247 (void) rw_unlock(&nb_cache_lock); 248 return (0); 249 } 250 251 entry = (struct name_entry *)malloc(sizeof (struct name_entry)); 252 if (entry == 0) { 253 (void) rw_unlock(&nb_cache_lock); 254 return (-1); 255 } 256 *entry = *name; 257 entry->addr_list.forw = entry->addr_list.back = &entry->addr_list; 258 entry->attributes |= entry->addr_list.attributes; 259 (void) mutex_init(&entry->mtx, 0, 0); 260 if (ht_replace_item(smb_netbios_cache, key, entry) == 0) { 261 free(entry); 262 (void) rw_unlock(&nb_cache_lock); 263 return (-1); 264 } 265 266 (void) rw_unlock(&nb_cache_lock); 267 return (0); 268 } 269 270 271 void 272 smb_netbios_cache_delete(struct name_entry *name) 273 { 274 nb_key_t key; 275 HT_ITEM *item; 276 struct name_entry *entry; 277 278 (void) rw_wrlock(&nb_cache_lock); 279 smb_netbios_cache_key(key, name->name, name->scope); 280 item = ht_find_item(smb_netbios_cache, key); 281 if (item && item->hi_data) { 282 entry = (struct name_entry *)item->hi_data; 283 (void) mutex_lock(&entry->mtx); 284 ht_mark_delete(smb_netbios_cache, item); 285 (void) mutex_unlock(&entry->mtx); 286 } 287 (void) rw_unlock(&nb_cache_lock); 288 } 289 290 /* 291 * smb_netbios_cache_insert_list 292 * 293 * Insert a name with multiple addresses 294 */ 295 int 296 smb_netbios_cache_insert_list(struct name_entry *name) 297 { 298 struct name_entry entry; 299 struct addr_entry *addr; 300 301 addr = &name->addr_list; 302 do { 303 smb_init_name_struct(NETBIOS_EMPTY_NAME, 0, name->scope, 304 addr->sin.sin_addr.s_addr, 305 addr->sin.sin_port, 306 name->attributes, 307 addr->attributes, 308 &entry); 309 (void) memcpy(entry.name, name->name, NETBIOS_NAME_SZ); 310 entry.addr_list.refresh_ttl = entry.addr_list.ttl = 311 addr->refresh_ttl; 312 (void) smb_netbios_cache_insert(&entry); 313 addr = addr->forw; 314 } while (addr != &name->addr_list); 315 316 return (0); 317 } 318 319 void 320 smb_netbios_cache_update_entry(struct name_entry *entry, 321 struct name_entry *name) 322 { 323 struct addr_entry *addr; 324 struct addr_entry *name_addr; 325 326 addr = &entry->addr_list; 327 name_addr = &name->addr_list; 328 329 if (IS_UNIQUE(entry->attributes)) { 330 do { 331 addr->ttl = name_addr->ttl; 332 addr = addr->forw; 333 } while (addr != &entry->addr_list); 334 335 } else { 336 do { 337 if (NETBIOS_SAME_IP(addr, name_addr) && 338 (addr->sin.sin_port == name_addr->sin.sin_port)) { 339 addr->ttl = name_addr->ttl; 340 return; 341 } 342 addr = addr->forw; 343 } while (addr != &entry->addr_list); 344 } 345 } 346 347 /* 348 * smb_netbios_cache_status 349 * 350 * Scan the name cache and gather status for 351 * Node Status response for names in the given scope 352 */ 353 unsigned char * 354 smb_netbios_cache_status(unsigned char *buf, int bufsize, unsigned char *scope) 355 { 356 HT_ITERATOR hti; 357 HT_ITEM *item; 358 struct name_entry *name; 359 unsigned char *numnames; 360 unsigned char *scan; 361 unsigned char *scan_end; 362 363 scan = buf; 364 scan_end = scan + bufsize; 365 366 numnames = scan++; 367 *numnames = 0; 368 369 (void) rw_rdlock(&nb_cache_lock); 370 item = ht_findfirst(smb_netbios_cache, &hti); 371 do { 372 if (item == 0) 373 break; 374 375 if (item->hi_data == 0) 376 continue; 377 378 if ((scan + NETBIOS_NAME_SZ + 2) >= scan_end) 379 /* no room for adding next entry */ 380 break; 381 382 name = (struct name_entry *)item->hi_data; 383 (void) mutex_lock(&name->mtx); 384 385 if (IS_LOCAL(name->attributes) && 386 (strcasecmp((char *)scope, (char *)name->scope) == 0)) { 387 bcopy(name->name, scan, NETBIOS_NAME_SZ); 388 scan += NETBIOS_NAME_SZ; 389 *scan++ = PUBLIC_BITS(name->attributes) >> 8; 390 *scan++ = PUBLIC_BITS(name->attributes); 391 (*numnames)++; 392 } 393 394 (void) mutex_unlock(&name->mtx); 395 } while ((item = ht_findnext(&hti)) != 0); 396 (void) rw_unlock(&nb_cache_lock); 397 398 return (scan); 399 } 400 401 void 402 smb_netbios_cache_reset_ttl() 403 { 404 struct addr_entry *addr; 405 struct name_entry *name; 406 HT_ITERATOR hti; 407 HT_ITEM *item; 408 409 (void) rw_rdlock(&nb_cache_lock); 410 item = ht_findfirst(smb_netbios_cache, &hti); 411 do { 412 if (item == 0) 413 break; 414 415 if (item->hi_data == 0) 416 continue; 417 418 name = (struct name_entry *)item->hi_data; 419 (void) mutex_lock(&name->mtx); 420 421 addr = &name->addr_list; 422 do { 423 if (addr->ttl < 1) { 424 if (addr->refresh_ttl) 425 addr->ttl = addr->refresh_ttl; 426 else 427 addr->refresh_ttl = addr->ttl = 428 TO_SECONDS(DEFAULT_TTL); 429 } 430 addr = addr->forw; 431 } while (addr != &name->addr_list); 432 433 (void) mutex_unlock(&name->mtx); 434 } while ((item = ht_findnext(&hti)) != 0); 435 (void) rw_unlock(&nb_cache_lock); 436 } 437 438 /* 439 * Returns TRUE when given name is added to the refresh queue 440 * FALSE if not. 441 */ 442 static boolean_t 443 smb_netbios_cache_insrefq(name_queue_t *refq, HT_ITEM *item) 444 { 445 struct name_entry *name; 446 struct name_entry *refent; 447 448 name = (struct name_entry *)item->hi_data; 449 450 if (IS_LOCAL(name->attributes)) { 451 if (IS_UNIQUE(name->attributes)) { 452 refent = smb_netbios_name_dup(name, 1); 453 if (refent) 454 QUEUE_INSERT_TAIL(&refq->head, refent) 455 456 /* next name */ 457 return (B_TRUE); 458 } 459 } else { 460 ht_mark_delete(smb_netbios_cache, item); 461 refent = smb_netbios_name_dup(name, 0); 462 if (refent) 463 QUEUE_INSERT_TAIL(&refq->head, refent) 464 465 /* next name */ 466 return (B_TRUE); 467 } 468 469 return (B_FALSE); 470 } 471 472 /* 473 * smb_netbios_cache_refresh 474 * 475 * Scans the name cache and add all local unique names 476 * and non-local names the passed refresh queue. Non- 477 * local names will also be marked as deleted. 478 * 479 * NOTE that the caller MUST protect the queue using 480 * its mutex 481 */ 482 void 483 smb_netbios_cache_refresh(name_queue_t *refq) 484 { 485 struct name_entry *name; 486 struct addr_entry *addr; 487 HT_ITERATOR hti; 488 HT_ITEM *item; 489 490 bzero(&refq->head, sizeof (refq->head)); 491 refq->head.forw = refq->head.back = &refq->head; 492 493 (void) rw_rdlock(&nb_cache_lock); 494 item = ht_findfirst(smb_netbios_cache, &hti); 495 do { /* name loop */ 496 if (item == 0) 497 break; 498 499 if (item->hi_data == 0) 500 continue; 501 502 name = (struct name_entry *)item->hi_data; 503 (void) mutex_lock(&name->mtx); 504 505 addr = &name->addr_list; 506 do { /* address loop */ 507 if (addr->ttl > 0) { 508 addr->ttl--; 509 if (addr->ttl == 0) { 510 if (smb_netbios_cache_insrefq(refq, 511 item)) 512 break; 513 } 514 } 515 addr = addr->forw; 516 } while (addr != &name->addr_list); 517 518 (void) mutex_unlock(&name->mtx); 519 } while ((item = ht_findnext(&hti)) != 0); 520 (void) rw_unlock(&nb_cache_lock); 521 } 522 523 /* 524 * smb_netbios_cache_delete_locals 525 * 526 * Scans the name cache and add all local names to 527 * the passed delete queue. 528 * 529 * NOTE that the caller MUST protect the queue using 530 * its mutex 531 */ 532 void 533 smb_netbios_cache_delete_locals(name_queue_t *delq) 534 { 535 struct name_entry *entry; 536 struct name_entry *delent; 537 HT_ITERATOR hti; 538 HT_ITEM *item; 539 540 bzero(&delq->head, sizeof (delq->head)); 541 delq->head.forw = delq->head.back = &delq->head; 542 543 (void) rw_wrlock(&nb_cache_lock); 544 item = ht_findfirst(smb_netbios_cache, &hti); 545 do { 546 if (item == 0) 547 break; 548 549 if (item->hi_data == 0) 550 continue; 551 552 entry = (struct name_entry *)item->hi_data; 553 (void) mutex_lock(&entry->mtx); 554 555 if (IS_LOCAL(entry->attributes)) { 556 ht_mark_delete(smb_netbios_cache, item); 557 delent = smb_netbios_name_dup(entry, 1); 558 if (delent) 559 QUEUE_INSERT_TAIL(&delq->head, delent) 560 } 561 562 (void) mutex_unlock(&entry->mtx); 563 } while ((item = ht_findnext(&hti)) != 0); 564 (void) rw_unlock(&nb_cache_lock); 565 } 566 567 void 568 smb_netbios_name_freeaddrs(struct name_entry *entry) 569 { 570 struct addr_entry *addr; 571 572 if (entry == 0) 573 return; 574 575 while ((addr = entry->addr_list.forw) != &entry->addr_list) { 576 QUEUE_CLIP(addr); 577 free(addr); 578 } 579 } 580 581 /* 582 * smb_netbios_cache_count 583 * 584 * Returns the number of names in the cache 585 */ 586 int 587 smb_netbios_cache_count() 588 { 589 int cnt; 590 591 (void) rw_rdlock(&nb_cache_lock); 592 cnt = ht_get_total_items(smb_netbios_cache); 593 (void) rw_unlock(&nb_cache_lock); 594 595 return (cnt); 596 } 597 598 void 599 smb_netbios_cache_dump(void) 600 { 601 struct name_entry *name; 602 HT_ITERATOR hti; 603 HT_ITEM *item; 604 605 (void) rw_rdlock(&nb_cache_lock); 606 item = ht_findfirst(smb_netbios_cache, &hti); 607 while (item) { 608 if (item->hi_data) { 609 name = (struct name_entry *)item->hi_data; 610 (void) mutex_lock(&name->mtx); 611 smb_netbios_name_dump(name); 612 (void) mutex_unlock(&name->mtx); 613 } 614 item = ht_findnext(&hti); 615 } 616 (void) rw_unlock(&nb_cache_lock); 617 } 618 619 void 620 smb_netbios_name_dump(struct name_entry *entry) 621 { 622 struct addr_entry *addr; 623 int count = 0; 624 625 if (smb_netbios_name_debug == 0) 626 return; 627 628 syslog(LOG_DEBUG, "name='%15.15s<%02X>' scope='%s' attr=0x%x", 629 entry->name, entry->name[15], 630 entry->scope, entry->attributes); 631 addr = &entry->addr_list; 632 do { 633 syslog(LOG_DEBUG, "addr_list[%d]:", count++); 634 syslog(LOG_DEBUG, " attributes = 0x%x", addr->attributes); 635 syslog(LOG_DEBUG, " conflict_timer = %d", 636 addr->conflict_timer); 637 syslog(LOG_DEBUG, " refresh_ttl = %d", addr->refresh_ttl); 638 syslog(LOG_DEBUG, " ttl = %d", addr->ttl); 639 syslog(LOG_DEBUG, " sin.sin_addr = %s", 640 inet_ntoa(addr->sin.sin_addr)); 641 syslog(LOG_DEBUG, " sin.sin_port = %d", addr->sin.sin_port); 642 syslog(LOG_DEBUG, " sin.sinlen = %d", addr->sinlen); 643 addr = addr->forw; 644 } while (addr != &entry->addr_list); 645 } 646 647 void 648 smb_netbios_name_logf(struct name_entry *entry) 649 { 650 struct addr_entry *addr; 651 NETBIOS_NAMEBUF; 652 653 (void) smb_strname(entry, namebuf, sizeof (namebuf)); 654 syslog(LOG_DEBUG, "%s flags=0x%x\n", namebuf, entry->attributes); 655 addr = &entry->addr_list; 656 do { 657 syslog(LOG_DEBUG, " %s ttl=%d flags=0x%x", 658 inet_ntoa(addr->sin.sin_addr), 659 addr->ttl, addr->attributes); 660 addr = addr->forw; 661 } while (addr && (addr != &entry->addr_list)); 662 } 663 664 /* 665 * smb_netbios_name_dup 666 * 667 * Duplicate the given name entry. If 'alladdr' is 0 only 668 * copy the primary address otherwise duplicate all the 669 * addresses. NOTE that the duplicate structure is not 670 * like a regular cache entry i.e. it's a contiguous block 671 * of memory and each addr structure doesn't have it's own 672 * allocated memory. So, the returned structure can be freed 673 * by one free call. 674 */ 675 struct name_entry * 676 smb_netbios_name_dup(struct name_entry *entry, int alladdr) 677 { 678 struct addr_entry *addr; 679 struct addr_entry *dup_addr; 680 struct name_entry *dup; 681 int addr_cnt = 0; 682 int size = 0; 683 684 if (alladdr) { 685 addr = entry->addr_list.forw; 686 while (addr && (addr != &entry->addr_list)) { 687 addr_cnt++; 688 addr = addr->forw; 689 } 690 } 691 692 size = sizeof (struct name_entry) + 693 (addr_cnt * sizeof (struct addr_entry)); 694 dup = (struct name_entry *)malloc(size); 695 if (dup == 0) 696 return (0); 697 698 bzero(dup, size); 699 700 dup->forw = dup->back = dup; 701 dup->attributes = entry->attributes; 702 (void) memcpy(dup->name, entry->name, NETBIOS_NAME_SZ); 703 (void) strlcpy((char *)dup->scope, (char *)entry->scope, 704 NETBIOS_DOMAIN_NAME_MAX); 705 dup->addr_list = entry->addr_list; 706 dup->addr_list.forw = dup->addr_list.back = &dup->addr_list; 707 708 if (alladdr == 0) 709 return (dup); 710 711 /* LINTED - E_BAD_PTR_CAST_ALIGN */ 712 dup_addr = (struct addr_entry *)((unsigned char *)dup + 713 sizeof (struct name_entry)); 714 715 addr = entry->addr_list.forw; 716 while (addr && (addr != &entry->addr_list)) { 717 *dup_addr = *addr; 718 QUEUE_INSERT_TAIL(&dup->addr_list, dup_addr); 719 addr = addr->forw; 720 dup_addr++; 721 } 722 723 return (dup); 724 } 725 726 static char * 727 smb_strname(struct name_entry *name, char *buf, int bufsize) 728 { 729 char *p; 730 731 (void) snprintf(buf, bufsize, "%15.15s", name->name); 732 p = strchr(buf, ' '); 733 if (p) 734 (void) snprintf(p, 5, "<%02X>", name->name[15]); 735 736 return (buf); 737 } 738 739 static void 740 hash_callback(HT_ITEM *item) 741 { 742 struct name_entry *entry; 743 744 if (item && item->hi_data) { 745 entry = (struct name_entry *)item->hi_data; 746 smb_netbios_name_freeaddrs(entry); 747 free(entry); 748 } 749 } 750 751 752 /*ARGSUSED*/ 753 static int 754 smb_netbios_match(const char *key1, const char *key2, size_t n) 755 { 756 int res; 757 758 res = bcmp(key1, key2, NETBIOS_NAME_SZ); 759 if (res == 0) { 760 /* Names are the same, compare scopes */ 761 res = strcmp(key1 + NETBIOS_NAME_SZ, key2 + NETBIOS_NAME_SZ); 762 } 763 764 return (res); 765 } 766 767 static void 768 smb_netbios_cache_key(char *key, unsigned char *name, unsigned char *scope) 769 { 770 bzero(key, NETBIOS_HKEY_SZ); 771 (void) memcpy(key, name, NETBIOS_NAME_SZ); 772 (void) memcpy(key + NETBIOS_NAME_SZ, scope, 773 strlen((const char *)scope)); 774 } 775