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