1da6c28aaSamw /* 2da6c28aaSamw * CDDL HEADER START 3da6c28aaSamw * 4da6c28aaSamw * The contents of this file are subject to the terms of the 5da6c28aaSamw * Common Development and Distribution License (the "License"). 6da6c28aaSamw * You may not use this file except in compliance with the License. 7da6c28aaSamw * 8da6c28aaSamw * You can obtain a copy of the license at usr/src/OPENSOLARIS.LICENSE 9da6c28aaSamw * or http://www.opensolaris.org/os/licensing. 10da6c28aaSamw * See the License for the specific language governing permissions 11da6c28aaSamw * and limitations under the License. 12da6c28aaSamw * 13da6c28aaSamw * When distributing Covered Code, include this CDDL HEADER in each 14da6c28aaSamw * file and include the License file at usr/src/OPENSOLARIS.LICENSE. 15da6c28aaSamw * If applicable, add the following below this CDDL HEADER, with the 16da6c28aaSamw * fields enclosed by brackets "[]" replaced with your own identifying 17da6c28aaSamw * information: Portions Copyright [yyyy] [name of copyright owner] 18da6c28aaSamw * 19da6c28aaSamw * CDDL HEADER END 20da6c28aaSamw */ 21da6c28aaSamw /* 22*a0aa776eSAlan Wright * Copyright 2009 Sun Microsystems, Inc. All rights reserved. 23da6c28aaSamw * Use is subject to license terms. 24da6c28aaSamw */ 25da6c28aaSamw 26da6c28aaSamw #include <synch.h> 27da6c28aaSamw #include <stdio.h> 28da6c28aaSamw #include <syslog.h> 29da6c28aaSamw #include <stdlib.h> 30da6c28aaSamw #include <arpa/inet.h> 31da6c28aaSamw #include <netdb.h> 32da6c28aaSamw 33da6c28aaSamw #include <smbsrv/libsmbns.h> 34da6c28aaSamw #include <smbns_netbios.h> 35da6c28aaSamw 36da6c28aaSamw #define NETBIOS_HTAB_SZ 128 37da6c28aaSamw #define NETBIOS_HKEY_SZ (NETBIOS_NAME_SZ + NETBIOS_DOMAIN_NAME_MAX) 38da6c28aaSamw 39da6c28aaSamw #define NETBIOS_SAME_IP(addr1, addr2) \ 40da6c28aaSamw ((addr1)->sin.sin_addr.s_addr == (addr2)->sin.sin_addr.s_addr) 41da6c28aaSamw 42da6c28aaSamw typedef char nb_key_t[NETBIOS_HKEY_SZ]; 43da6c28aaSamw static HT_HANDLE *smb_netbios_cache = 0; 44da6c28aaSamw static rwlock_t nb_cache_lock; 45da6c28aaSamw 46*a0aa776eSAlan Wright static void smb_strname(struct name_entry *name, char *buf, int bufsize); 47da6c28aaSamw static void hash_callback(HT_ITEM *item); 48da6c28aaSamw static int smb_netbios_match(const char *key1, const char *key2, size_t n); 49da6c28aaSamw static void smb_netbios_cache_key(char *key, unsigned char *name, 50da6c28aaSamw unsigned char *scope); 51da6c28aaSamw 52da6c28aaSamw int 53*a0aa776eSAlan Wright smb_netbios_cache_init(void) 54da6c28aaSamw { 55da6c28aaSamw (void) rw_wrlock(&nb_cache_lock); 56*a0aa776eSAlan Wright if (smb_netbios_cache == NULL) { 57da6c28aaSamw smb_netbios_cache = ht_create_table(NETBIOS_HTAB_SZ, 58da6c28aaSamw NETBIOS_HKEY_SZ, HTHF_FIXED_KEY); 59*a0aa776eSAlan Wright if (smb_netbios_cache == NULL) { 60*a0aa776eSAlan Wright syslog(LOG_ERR, "nbns: cannot create name cache"); 61da6c28aaSamw (void) rw_unlock(&nb_cache_lock); 62*a0aa776eSAlan Wright return (-1); 63da6c28aaSamw } 64da6c28aaSamw (void) ht_register_callback(smb_netbios_cache, hash_callback); 65da6c28aaSamw ht_set_cmpfn(smb_netbios_cache, smb_netbios_match); 66da6c28aaSamw } 67da6c28aaSamw (void) rw_unlock(&nb_cache_lock); 68da6c28aaSamw 69*a0aa776eSAlan Wright return (0); 70da6c28aaSamw } 71da6c28aaSamw 72da6c28aaSamw void 737b59d02dSjb smb_netbios_cache_fini(void) 74da6c28aaSamw { 75da6c28aaSamw (void) rw_wrlock(&nb_cache_lock); 76da6c28aaSamw ht_destroy_table(smb_netbios_cache); 77*a0aa776eSAlan Wright smb_netbios_cache = NULL; 78da6c28aaSamw (void) rw_unlock(&nb_cache_lock); 79da6c28aaSamw } 80da6c28aaSamw 81da6c28aaSamw void 827b59d02dSjb smb_netbios_cache_clean(void) 83da6c28aaSamw { 84da6c28aaSamw (void) rw_wrlock(&nb_cache_lock); 85da6c28aaSamw (void) ht_clean_table(smb_netbios_cache); 86da6c28aaSamw (void) rw_unlock(&nb_cache_lock); 87da6c28aaSamw } 88da6c28aaSamw 897b59d02dSjb int 907b59d02dSjb smb_netbios_cache_getfirst(nbcache_iter_t *iter) 917b59d02dSjb { 927b59d02dSjb HT_ITEM *item; 937b59d02dSjb struct name_entry *entry; 947b59d02dSjb 957b59d02dSjb (void) rw_rdlock(&nb_cache_lock); 967b59d02dSjb item = ht_findfirst(smb_netbios_cache, &iter->nbc_hti); 977b59d02dSjb if (item == NULL || item->hi_data == NULL) { 987b59d02dSjb (void) rw_unlock(&nb_cache_lock); 997b59d02dSjb return (-1); 1007b59d02dSjb } 1017b59d02dSjb 1027b59d02dSjb entry = (struct name_entry *)item->hi_data; 1037b59d02dSjb (void) mutex_lock(&entry->mtx); 1047b59d02dSjb iter->nbc_entry = smb_netbios_name_dup(entry, 1); 1057b59d02dSjb (void) mutex_unlock(&entry->mtx); 1067b59d02dSjb 1077b59d02dSjb (void) rw_unlock(&nb_cache_lock); 1087b59d02dSjb 1097b59d02dSjb return ((iter->nbc_entry) ? 0 : -1); 1107b59d02dSjb } 1117b59d02dSjb 1127b59d02dSjb int 1137b59d02dSjb smb_netbios_cache_getnext(nbcache_iter_t *iter) 1147b59d02dSjb { 1157b59d02dSjb HT_ITEM *item; 1167b59d02dSjb struct name_entry *entry; 1177b59d02dSjb 1187b59d02dSjb (void) rw_rdlock(&nb_cache_lock); 1197b59d02dSjb item = ht_findnext(&iter->nbc_hti); 1207b59d02dSjb if (item == NULL || item->hi_data == NULL) { 1217b59d02dSjb (void) rw_unlock(&nb_cache_lock); 1227b59d02dSjb return (-1); 1237b59d02dSjb } 1247b59d02dSjb 1257b59d02dSjb entry = (struct name_entry *)item->hi_data; 1267b59d02dSjb (void) mutex_lock(&entry->mtx); 1277b59d02dSjb iter->nbc_entry = smb_netbios_name_dup(entry, 1); 1287b59d02dSjb (void) mutex_unlock(&entry->mtx); 1297b59d02dSjb 1307b59d02dSjb (void) rw_unlock(&nb_cache_lock); 1317b59d02dSjb 1327b59d02dSjb return ((iter->nbc_entry) ? 0 : -1); 1337b59d02dSjb } 1347b59d02dSjb 135da6c28aaSamw /* 136da6c28aaSamw * smb_netbios_cache_lookup 137da6c28aaSamw * 138da6c28aaSamw * Searches the name cache for the given entry, if found 139da6c28aaSamw * the entry will be locked before returning to caller 140da6c28aaSamw * so caller MUST unlock the entry after it's done with it. 141da6c28aaSamw */ 142da6c28aaSamw struct name_entry * 143da6c28aaSamw smb_netbios_cache_lookup(struct name_entry *name) 144da6c28aaSamw { 145da6c28aaSamw HT_ITEM *item; 146da6c28aaSamw nb_key_t key; 147da6c28aaSamw struct name_entry *entry = NULL; 148da6c28aaSamw unsigned char hostname[MAXHOSTNAMELEN]; 149da6c28aaSamw 150da6c28aaSamw if (NETBIOS_NAME_IS_STAR(name->name)) { 151da6c28aaSamw /* Return our address */ 1527b59d02dSjb if (smb_getnetbiosname((char *)hostname, sizeof (hostname)) 1537b59d02dSjb != 0) 154da6c28aaSamw return (NULL); 155da6c28aaSamw 1567b59d02dSjb smb_encode_netbios_name(hostname, 0x00, NULL, name); 157da6c28aaSamw } 158da6c28aaSamw 159da6c28aaSamw (void) rw_rdlock(&nb_cache_lock); 160da6c28aaSamw 161da6c28aaSamw smb_netbios_cache_key(key, name->name, name->scope); 162da6c28aaSamw item = ht_find_item(smb_netbios_cache, key); 163da6c28aaSamw if (item) { 164da6c28aaSamw entry = (struct name_entry *)item->hi_data; 165da6c28aaSamw (void) mutex_lock(&entry->mtx); 166da6c28aaSamw if ((entry->attributes & NAME_ATTR_CONFLICT) != 0) { 167da6c28aaSamw (void) mutex_unlock(&entry->mtx); 168da6c28aaSamw entry = NULL; 169da6c28aaSamw } 170da6c28aaSamw } 171da6c28aaSamw 172da6c28aaSamw (void) rw_unlock(&nb_cache_lock); 173da6c28aaSamw return (entry); 174da6c28aaSamw } 175da6c28aaSamw 176da6c28aaSamw void 177da6c28aaSamw smb_netbios_cache_unlock_entry(struct name_entry *name) 178da6c28aaSamw { 179da6c28aaSamw if (name) 180da6c28aaSamw (void) mutex_unlock(&name->mtx); 181da6c28aaSamw } 182da6c28aaSamw 183da6c28aaSamw /* 184da6c28aaSamw * smb_netbios_cache_lookup_addr 185da6c28aaSamw * 186da6c28aaSamw * lookup the given 'name' in the cache and then checks 187da6c28aaSamw * if the address also matches with the found entry. 188da6c28aaSamw * 'name' is supposed to contain only one address. 189da6c28aaSamw * 190da6c28aaSamw * The found entry will be locked before returning to caller 191da6c28aaSamw * so caller MUST unlock the entry after it's done with it. 192da6c28aaSamw */ 193da6c28aaSamw struct name_entry * 194da6c28aaSamw smb_netbios_cache_lookup_addr(struct name_entry *name) 195da6c28aaSamw { 196da6c28aaSamw struct name_entry *entry = 0; 197*a0aa776eSAlan Wright addr_entry_t *addr; 198*a0aa776eSAlan Wright addr_entry_t *name_addr; 199da6c28aaSamw HT_ITEM *item; 200da6c28aaSamw nb_key_t key; 201da6c28aaSamw 202da6c28aaSamw (void) rw_rdlock(&nb_cache_lock); 203da6c28aaSamw smb_netbios_cache_key(key, name->name, name->scope); 204da6c28aaSamw item = ht_find_item(smb_netbios_cache, key); 205da6c28aaSamw 206da6c28aaSamw if (item && item->hi_data) { 207da6c28aaSamw name_addr = &name->addr_list; 208da6c28aaSamw entry = (struct name_entry *)item->hi_data; 209da6c28aaSamw (void) mutex_lock(&entry->mtx); 210da6c28aaSamw addr = &entry->addr_list; 211da6c28aaSamw do { 212da6c28aaSamw if (NETBIOS_SAME_IP(addr, name_addr)) { 213da6c28aaSamw /* note that entry lock isn't released here */ 214da6c28aaSamw (void) rw_unlock(&nb_cache_lock); 215da6c28aaSamw return (entry); 216da6c28aaSamw } 217da6c28aaSamw addr = addr->forw; 218da6c28aaSamw } while (addr != &entry->addr_list); 219da6c28aaSamw (void) mutex_unlock(&entry->mtx); 220da6c28aaSamw } 221da6c28aaSamw 222da6c28aaSamw (void) rw_unlock(&nb_cache_lock); 223da6c28aaSamw return (0); 224da6c28aaSamw } 225da6c28aaSamw 226da6c28aaSamw int 227da6c28aaSamw smb_netbios_cache_insert(struct name_entry *name) 228da6c28aaSamw { 229da6c28aaSamw struct name_entry *entry; 230*a0aa776eSAlan Wright addr_entry_t *addr; 231*a0aa776eSAlan Wright addr_entry_t *name_addr; 232da6c28aaSamw HT_ITEM *item; 233da6c28aaSamw nb_key_t key; 2347b59d02dSjb int rc; 235da6c28aaSamw 236da6c28aaSamw /* No point in adding a name with IP address 255.255.255.255 */ 237da6c28aaSamw if (name->addr_list.sin.sin_addr.s_addr == 0xffffffff) 238da6c28aaSamw return (0); 239da6c28aaSamw 240da6c28aaSamw (void) rw_wrlock(&nb_cache_lock); 241da6c28aaSamw smb_netbios_cache_key(key, name->name, name->scope); 242da6c28aaSamw item = ht_find_item(smb_netbios_cache, key); 243da6c28aaSamw 244da6c28aaSamw if (item && item->hi_data) { 245da6c28aaSamw /* Name already exists */ 246da6c28aaSamw entry = (struct name_entry *)item->hi_data; 247da6c28aaSamw (void) mutex_lock(&entry->mtx); 248da6c28aaSamw 249da6c28aaSamw name_addr = &name->addr_list; 250da6c28aaSamw addr = &entry->addr_list; 251da6c28aaSamw if (NETBIOS_SAME_IP(addr, name_addr) && 252da6c28aaSamw (addr->sin.sin_port == name_addr->sin.sin_port)) { 253da6c28aaSamw entry->attributes |= 254da6c28aaSamw name_addr->attributes & NAME_ATTR_LOCAL; 255da6c28aaSamw (void) mutex_unlock(&entry->mtx); 256da6c28aaSamw (void) rw_unlock(&nb_cache_lock); 2577b59d02dSjb return (0); 258da6c28aaSamw } 259da6c28aaSamw 260da6c28aaSamw /* Was not primary: looks for others */ 261da6c28aaSamw for (addr = entry->addr_list.forw; 262da6c28aaSamw addr != &entry->addr_list; addr = addr->forw) { 263da6c28aaSamw if (NETBIOS_SAME_IP(addr, name_addr) && 264da6c28aaSamw (addr->sin.sin_port == name_addr->sin.sin_port)) { 265da6c28aaSamw (void) mutex_unlock(&entry->mtx); 266da6c28aaSamw (void) rw_unlock(&nb_cache_lock); 2677b59d02dSjb return (0); 268da6c28aaSamw } 269da6c28aaSamw } 270da6c28aaSamw 271*a0aa776eSAlan Wright if ((addr = malloc(sizeof (addr_entry_t))) != NULL) { 2727b59d02dSjb *addr = name->addr_list; 2737b59d02dSjb entry->attributes |= addr->attributes; 2747b59d02dSjb QUEUE_INSERT_TAIL(&entry->addr_list, addr); 2757b59d02dSjb rc = 0; 2767b59d02dSjb } else { 2777b59d02dSjb rc = -1; 278da6c28aaSamw } 2797b59d02dSjb 280da6c28aaSamw (void) mutex_unlock(&entry->mtx); 281da6c28aaSamw (void) rw_unlock(&nb_cache_lock); 2827b59d02dSjb return (rc); 283da6c28aaSamw } 284da6c28aaSamw 2857b59d02dSjb if ((entry = malloc(sizeof (struct name_entry))) == NULL) { 286da6c28aaSamw (void) rw_unlock(&nb_cache_lock); 287da6c28aaSamw return (-1); 288da6c28aaSamw } 2897b59d02dSjb 290da6c28aaSamw *entry = *name; 291da6c28aaSamw entry->addr_list.forw = entry->addr_list.back = &entry->addr_list; 292da6c28aaSamw entry->attributes |= entry->addr_list.attributes; 293da6c28aaSamw (void) mutex_init(&entry->mtx, 0, 0); 294da6c28aaSamw if (ht_replace_item(smb_netbios_cache, key, entry) == 0) { 295da6c28aaSamw free(entry); 296da6c28aaSamw (void) rw_unlock(&nb_cache_lock); 297da6c28aaSamw return (-1); 298da6c28aaSamw } 299da6c28aaSamw 300da6c28aaSamw (void) rw_unlock(&nb_cache_lock); 301da6c28aaSamw return (0); 302da6c28aaSamw } 303da6c28aaSamw 304da6c28aaSamw 305da6c28aaSamw void 306da6c28aaSamw smb_netbios_cache_delete(struct name_entry *name) 307da6c28aaSamw { 308da6c28aaSamw nb_key_t key; 309da6c28aaSamw HT_ITEM *item; 310da6c28aaSamw struct name_entry *entry; 311da6c28aaSamw 312da6c28aaSamw (void) rw_wrlock(&nb_cache_lock); 313da6c28aaSamw smb_netbios_cache_key(key, name->name, name->scope); 314da6c28aaSamw item = ht_find_item(smb_netbios_cache, key); 315da6c28aaSamw if (item && item->hi_data) { 316da6c28aaSamw entry = (struct name_entry *)item->hi_data; 317da6c28aaSamw (void) mutex_lock(&entry->mtx); 318da6c28aaSamw ht_mark_delete(smb_netbios_cache, item); 319da6c28aaSamw (void) mutex_unlock(&entry->mtx); 320da6c28aaSamw } 321da6c28aaSamw (void) rw_unlock(&nb_cache_lock); 322da6c28aaSamw } 323da6c28aaSamw 324da6c28aaSamw /* 325da6c28aaSamw * smb_netbios_cache_insert_list 326da6c28aaSamw * 327da6c28aaSamw * Insert a name with multiple addresses 328da6c28aaSamw */ 329da6c28aaSamw int 330da6c28aaSamw smb_netbios_cache_insert_list(struct name_entry *name) 331da6c28aaSamw { 332da6c28aaSamw struct name_entry entry; 333*a0aa776eSAlan Wright addr_entry_t *addr; 334da6c28aaSamw 335da6c28aaSamw addr = &name->addr_list; 336da6c28aaSamw do { 337da6c28aaSamw smb_init_name_struct(NETBIOS_EMPTY_NAME, 0, name->scope, 338da6c28aaSamw addr->sin.sin_addr.s_addr, 339da6c28aaSamw addr->sin.sin_port, 340da6c28aaSamw name->attributes, 341da6c28aaSamw addr->attributes, 342da6c28aaSamw &entry); 343da6c28aaSamw (void) memcpy(entry.name, name->name, NETBIOS_NAME_SZ); 344da6c28aaSamw entry.addr_list.refresh_ttl = entry.addr_list.ttl = 345da6c28aaSamw addr->refresh_ttl; 346da6c28aaSamw (void) smb_netbios_cache_insert(&entry); 347da6c28aaSamw addr = addr->forw; 348da6c28aaSamw } while (addr != &name->addr_list); 349da6c28aaSamw 350da6c28aaSamw return (0); 351da6c28aaSamw } 352da6c28aaSamw 353da6c28aaSamw void 354da6c28aaSamw smb_netbios_cache_update_entry(struct name_entry *entry, 355da6c28aaSamw struct name_entry *name) 356da6c28aaSamw { 357*a0aa776eSAlan Wright addr_entry_t *addr; 358*a0aa776eSAlan Wright addr_entry_t *name_addr; 359da6c28aaSamw 360da6c28aaSamw addr = &entry->addr_list; 361da6c28aaSamw name_addr = &name->addr_list; 362da6c28aaSamw 363da6c28aaSamw if (IS_UNIQUE(entry->attributes)) { 364da6c28aaSamw do { 365da6c28aaSamw addr->ttl = name_addr->ttl; 366da6c28aaSamw addr = addr->forw; 367da6c28aaSamw } while (addr != &entry->addr_list); 368da6c28aaSamw 369da6c28aaSamw } else { 370da6c28aaSamw do { 371da6c28aaSamw if (NETBIOS_SAME_IP(addr, name_addr) && 372da6c28aaSamw (addr->sin.sin_port == name_addr->sin.sin_port)) { 373da6c28aaSamw addr->ttl = name_addr->ttl; 374da6c28aaSamw return; 375da6c28aaSamw } 376da6c28aaSamw addr = addr->forw; 377da6c28aaSamw } while (addr != &entry->addr_list); 378da6c28aaSamw } 379da6c28aaSamw } 380da6c28aaSamw 381da6c28aaSamw /* 382da6c28aaSamw * smb_netbios_cache_status 383da6c28aaSamw * 384da6c28aaSamw * Scan the name cache and gather status for 385da6c28aaSamw * Node Status response for names in the given scope 386da6c28aaSamw */ 387da6c28aaSamw unsigned char * 388da6c28aaSamw smb_netbios_cache_status(unsigned char *buf, int bufsize, unsigned char *scope) 389da6c28aaSamw { 390da6c28aaSamw HT_ITERATOR hti; 391da6c28aaSamw HT_ITEM *item; 392da6c28aaSamw struct name_entry *name; 393da6c28aaSamw unsigned char *numnames; 394da6c28aaSamw unsigned char *scan; 395da6c28aaSamw unsigned char *scan_end; 396da6c28aaSamw 397da6c28aaSamw scan = buf; 398da6c28aaSamw scan_end = scan + bufsize; 399da6c28aaSamw 400da6c28aaSamw numnames = scan++; 401da6c28aaSamw *numnames = 0; 402da6c28aaSamw 403da6c28aaSamw (void) rw_rdlock(&nb_cache_lock); 404da6c28aaSamw item = ht_findfirst(smb_netbios_cache, &hti); 405da6c28aaSamw do { 406da6c28aaSamw if (item == 0) 407da6c28aaSamw break; 408da6c28aaSamw 409da6c28aaSamw if (item->hi_data == 0) 410da6c28aaSamw continue; 411da6c28aaSamw 412da6c28aaSamw if ((scan + NETBIOS_NAME_SZ + 2) >= scan_end) 413da6c28aaSamw /* no room for adding next entry */ 414da6c28aaSamw break; 415da6c28aaSamw 416da6c28aaSamw name = (struct name_entry *)item->hi_data; 417da6c28aaSamw (void) mutex_lock(&name->mtx); 418da6c28aaSamw 419da6c28aaSamw if (IS_LOCAL(name->attributes) && 420da6c28aaSamw (strcasecmp((char *)scope, (char *)name->scope) == 0)) { 421da6c28aaSamw bcopy(name->name, scan, NETBIOS_NAME_SZ); 422da6c28aaSamw scan += NETBIOS_NAME_SZ; 423da6c28aaSamw *scan++ = PUBLIC_BITS(name->attributes) >> 8; 424da6c28aaSamw *scan++ = PUBLIC_BITS(name->attributes); 425da6c28aaSamw (*numnames)++; 426da6c28aaSamw } 427da6c28aaSamw 428da6c28aaSamw (void) mutex_unlock(&name->mtx); 429da6c28aaSamw } while ((item = ht_findnext(&hti)) != 0); 430da6c28aaSamw (void) rw_unlock(&nb_cache_lock); 431da6c28aaSamw 432da6c28aaSamw return (scan); 433da6c28aaSamw } 434da6c28aaSamw 435da6c28aaSamw void 436da6c28aaSamw smb_netbios_cache_reset_ttl() 437da6c28aaSamw { 438*a0aa776eSAlan Wright addr_entry_t *addr; 439da6c28aaSamw struct name_entry *name; 440da6c28aaSamw HT_ITERATOR hti; 441da6c28aaSamw HT_ITEM *item; 442da6c28aaSamw 443da6c28aaSamw (void) rw_rdlock(&nb_cache_lock); 444da6c28aaSamw item = ht_findfirst(smb_netbios_cache, &hti); 445da6c28aaSamw do { 446da6c28aaSamw if (item == 0) 447da6c28aaSamw break; 448da6c28aaSamw 449da6c28aaSamw if (item->hi_data == 0) 450da6c28aaSamw continue; 451da6c28aaSamw 452da6c28aaSamw name = (struct name_entry *)item->hi_data; 453da6c28aaSamw (void) mutex_lock(&name->mtx); 454da6c28aaSamw 455da6c28aaSamw addr = &name->addr_list; 456da6c28aaSamw do { 457da6c28aaSamw if (addr->ttl < 1) { 458da6c28aaSamw if (addr->refresh_ttl) 459da6c28aaSamw addr->ttl = addr->refresh_ttl; 460da6c28aaSamw else 461da6c28aaSamw addr->refresh_ttl = addr->ttl = 462da6c28aaSamw TO_SECONDS(DEFAULT_TTL); 463da6c28aaSamw } 464da6c28aaSamw addr = addr->forw; 465da6c28aaSamw } while (addr != &name->addr_list); 466da6c28aaSamw 467da6c28aaSamw (void) mutex_unlock(&name->mtx); 468da6c28aaSamw } while ((item = ht_findnext(&hti)) != 0); 469da6c28aaSamw (void) rw_unlock(&nb_cache_lock); 470da6c28aaSamw } 471da6c28aaSamw 472da6c28aaSamw /* 473da6c28aaSamw * Returns TRUE when given name is added to the refresh queue 474da6c28aaSamw * FALSE if not. 475da6c28aaSamw */ 476da6c28aaSamw static boolean_t 477da6c28aaSamw smb_netbios_cache_insrefq(name_queue_t *refq, HT_ITEM *item) 478da6c28aaSamw { 479da6c28aaSamw struct name_entry *name; 480da6c28aaSamw struct name_entry *refent; 481da6c28aaSamw 482da6c28aaSamw name = (struct name_entry *)item->hi_data; 483da6c28aaSamw 484da6c28aaSamw if (IS_LOCAL(name->attributes)) { 485da6c28aaSamw if (IS_UNIQUE(name->attributes)) { 486da6c28aaSamw refent = smb_netbios_name_dup(name, 1); 487da6c28aaSamw if (refent) 488da6c28aaSamw QUEUE_INSERT_TAIL(&refq->head, refent) 489da6c28aaSamw 490da6c28aaSamw /* next name */ 491da6c28aaSamw return (B_TRUE); 492da6c28aaSamw } 493da6c28aaSamw } else { 494da6c28aaSamw ht_mark_delete(smb_netbios_cache, item); 495da6c28aaSamw refent = smb_netbios_name_dup(name, 0); 496da6c28aaSamw if (refent) 497da6c28aaSamw QUEUE_INSERT_TAIL(&refq->head, refent) 498da6c28aaSamw 499da6c28aaSamw /* next name */ 500da6c28aaSamw return (B_TRUE); 501da6c28aaSamw } 502da6c28aaSamw 503da6c28aaSamw return (B_FALSE); 504da6c28aaSamw } 505da6c28aaSamw 506da6c28aaSamw /* 507da6c28aaSamw * smb_netbios_cache_refresh 508da6c28aaSamw * 509da6c28aaSamw * Scans the name cache and add all local unique names 510da6c28aaSamw * and non-local names the passed refresh queue. Non- 511da6c28aaSamw * local names will also be marked as deleted. 512da6c28aaSamw * 513da6c28aaSamw * NOTE that the caller MUST protect the queue using 514da6c28aaSamw * its mutex 515da6c28aaSamw */ 516da6c28aaSamw void 517da6c28aaSamw smb_netbios_cache_refresh(name_queue_t *refq) 518da6c28aaSamw { 519da6c28aaSamw struct name_entry *name; 520*a0aa776eSAlan Wright addr_entry_t *addr; 521da6c28aaSamw HT_ITERATOR hti; 522da6c28aaSamw HT_ITEM *item; 523da6c28aaSamw 524da6c28aaSamw bzero(&refq->head, sizeof (refq->head)); 525da6c28aaSamw refq->head.forw = refq->head.back = &refq->head; 526da6c28aaSamw 527da6c28aaSamw (void) rw_rdlock(&nb_cache_lock); 528da6c28aaSamw item = ht_findfirst(smb_netbios_cache, &hti); 529da6c28aaSamw do { /* name loop */ 530da6c28aaSamw if (item == 0) 531da6c28aaSamw break; 532da6c28aaSamw 533da6c28aaSamw if (item->hi_data == 0) 534da6c28aaSamw continue; 535da6c28aaSamw 536da6c28aaSamw name = (struct name_entry *)item->hi_data; 537da6c28aaSamw (void) mutex_lock(&name->mtx); 538da6c28aaSamw 539da6c28aaSamw addr = &name->addr_list; 540da6c28aaSamw do { /* address loop */ 541da6c28aaSamw if (addr->ttl > 0) { 542da6c28aaSamw addr->ttl--; 543da6c28aaSamw if (addr->ttl == 0) { 544da6c28aaSamw if (smb_netbios_cache_insrefq(refq, 545da6c28aaSamw item)) 546da6c28aaSamw break; 547da6c28aaSamw } 548da6c28aaSamw } 549da6c28aaSamw addr = addr->forw; 550da6c28aaSamw } while (addr != &name->addr_list); 551da6c28aaSamw 552da6c28aaSamw (void) mutex_unlock(&name->mtx); 553da6c28aaSamw } while ((item = ht_findnext(&hti)) != 0); 554da6c28aaSamw (void) rw_unlock(&nb_cache_lock); 555da6c28aaSamw } 556da6c28aaSamw 557da6c28aaSamw /* 558da6c28aaSamw * smb_netbios_cache_delete_locals 559da6c28aaSamw * 560da6c28aaSamw * Scans the name cache and add all local names to 561da6c28aaSamw * the passed delete queue. 562da6c28aaSamw * 563da6c28aaSamw * NOTE that the caller MUST protect the queue using 564da6c28aaSamw * its mutex 565da6c28aaSamw */ 566da6c28aaSamw void 567da6c28aaSamw smb_netbios_cache_delete_locals(name_queue_t *delq) 568da6c28aaSamw { 569da6c28aaSamw struct name_entry *entry; 570da6c28aaSamw struct name_entry *delent; 571da6c28aaSamw HT_ITERATOR hti; 572da6c28aaSamw HT_ITEM *item; 573da6c28aaSamw 574da6c28aaSamw bzero(&delq->head, sizeof (delq->head)); 575da6c28aaSamw delq->head.forw = delq->head.back = &delq->head; 576da6c28aaSamw 577da6c28aaSamw (void) rw_wrlock(&nb_cache_lock); 578da6c28aaSamw item = ht_findfirst(smb_netbios_cache, &hti); 579da6c28aaSamw do { 580da6c28aaSamw if (item == 0) 581da6c28aaSamw break; 582da6c28aaSamw 583da6c28aaSamw if (item->hi_data == 0) 584da6c28aaSamw continue; 585da6c28aaSamw 586da6c28aaSamw entry = (struct name_entry *)item->hi_data; 587da6c28aaSamw (void) mutex_lock(&entry->mtx); 588da6c28aaSamw 589da6c28aaSamw if (IS_LOCAL(entry->attributes)) { 590da6c28aaSamw ht_mark_delete(smb_netbios_cache, item); 591da6c28aaSamw delent = smb_netbios_name_dup(entry, 1); 592da6c28aaSamw if (delent) 593da6c28aaSamw QUEUE_INSERT_TAIL(&delq->head, delent) 594da6c28aaSamw } 595da6c28aaSamw 596da6c28aaSamw (void) mutex_unlock(&entry->mtx); 597da6c28aaSamw } while ((item = ht_findnext(&hti)) != 0); 598da6c28aaSamw (void) rw_unlock(&nb_cache_lock); 599da6c28aaSamw } 600da6c28aaSamw 601da6c28aaSamw void 602da6c28aaSamw smb_netbios_name_freeaddrs(struct name_entry *entry) 603da6c28aaSamw { 604*a0aa776eSAlan Wright addr_entry_t *addr; 605da6c28aaSamw 606da6c28aaSamw if (entry == 0) 607da6c28aaSamw return; 608da6c28aaSamw 609da6c28aaSamw while ((addr = entry->addr_list.forw) != &entry->addr_list) { 610da6c28aaSamw QUEUE_CLIP(addr); 611da6c28aaSamw free(addr); 612da6c28aaSamw } 613da6c28aaSamw } 614da6c28aaSamw 615da6c28aaSamw /* 616da6c28aaSamw * smb_netbios_cache_count 617da6c28aaSamw * 618da6c28aaSamw * Returns the number of names in the cache 619da6c28aaSamw */ 620da6c28aaSamw int 621da6c28aaSamw smb_netbios_cache_count() 622da6c28aaSamw { 623da6c28aaSamw int cnt; 624da6c28aaSamw 625da6c28aaSamw (void) rw_rdlock(&nb_cache_lock); 626da6c28aaSamw cnt = ht_get_total_items(smb_netbios_cache); 627da6c28aaSamw (void) rw_unlock(&nb_cache_lock); 628da6c28aaSamw 629da6c28aaSamw return (cnt); 630da6c28aaSamw } 631da6c28aaSamw 632da6c28aaSamw void 633*a0aa776eSAlan Wright smb_netbios_cache_dump(FILE *fp) 634da6c28aaSamw { 635da6c28aaSamw struct name_entry *name; 636da6c28aaSamw HT_ITERATOR hti; 637da6c28aaSamw HT_ITEM *item; 638da6c28aaSamw 639da6c28aaSamw (void) rw_rdlock(&nb_cache_lock); 640*a0aa776eSAlan Wright 641*a0aa776eSAlan Wright if (ht_get_total_items(smb_netbios_cache) != 0) { 642*a0aa776eSAlan Wright (void) fprintf(fp, "\n%-22s %-16s %-16s %s\n", 643*a0aa776eSAlan Wright "Name", "Type", "Address", "TTL"); 644*a0aa776eSAlan Wright (void) fprintf(fp, "%s%s\n", 645*a0aa776eSAlan Wright "-------------------------------", 646*a0aa776eSAlan Wright "------------------------------"); 647*a0aa776eSAlan Wright } 648*a0aa776eSAlan Wright 649da6c28aaSamw item = ht_findfirst(smb_netbios_cache, &hti); 650da6c28aaSamw while (item) { 651da6c28aaSamw if (item->hi_data) { 652da6c28aaSamw name = (struct name_entry *)item->hi_data; 653da6c28aaSamw (void) mutex_lock(&name->mtx); 654*a0aa776eSAlan Wright smb_netbios_name_dump(fp, name); 655da6c28aaSamw (void) mutex_unlock(&name->mtx); 656da6c28aaSamw } 657da6c28aaSamw item = ht_findnext(&hti); 658da6c28aaSamw } 659da6c28aaSamw (void) rw_unlock(&nb_cache_lock); 660da6c28aaSamw } 661da6c28aaSamw 662da6c28aaSamw void 663*a0aa776eSAlan Wright smb_netbios_name_dump(FILE *fp, struct name_entry *entry) 664da6c28aaSamw { 665*a0aa776eSAlan Wright char buf[MAXHOSTNAMELEN]; 666*a0aa776eSAlan Wright addr_entry_t *addr; 667*a0aa776eSAlan Wright char *type; 668*a0aa776eSAlan Wright int count = 0; 669da6c28aaSamw 670*a0aa776eSAlan Wright smb_strname(entry, buf, sizeof (buf)); 671*a0aa776eSAlan Wright type = (IS_UNIQUE(entry->attributes)) ? "UNIQUE" : "GROUP"; 672*a0aa776eSAlan Wright 673*a0aa776eSAlan Wright (void) fprintf(fp, "%s %-6s (0x%04x) ", buf, type, entry->attributes); 674da6c28aaSamw 675da6c28aaSamw addr = &entry->addr_list; 676da6c28aaSamw do { 677*a0aa776eSAlan Wright if (count == 0) 678*a0aa776eSAlan Wright (void) fprintf(fp, "%-16s %d\n", 679*a0aa776eSAlan Wright inet_ntoa(addr->sin.sin_addr), addr->ttl); 680*a0aa776eSAlan Wright else 681*a0aa776eSAlan Wright (void) fprintf(fp, "%-28s (0x%04x) %-16s %d\n", 682*a0aa776eSAlan Wright " ", addr->attributes, 683*a0aa776eSAlan Wright inet_ntoa(addr->sin.sin_addr), addr->ttl); 684*a0aa776eSAlan Wright ++count; 685da6c28aaSamw addr = addr->forw; 686da6c28aaSamw } while (addr != &entry->addr_list); 687da6c28aaSamw } 688da6c28aaSamw 689da6c28aaSamw void 690da6c28aaSamw smb_netbios_name_logf(struct name_entry *entry) 691da6c28aaSamw { 692*a0aa776eSAlan Wright char namebuf[MAXHOSTNAMELEN]; 693*a0aa776eSAlan Wright addr_entry_t *addr; 694da6c28aaSamw 695*a0aa776eSAlan Wright smb_strname(entry, namebuf, sizeof (namebuf)); 696da6c28aaSamw syslog(LOG_DEBUG, "%s flags=0x%x\n", namebuf, entry->attributes); 697da6c28aaSamw addr = &entry->addr_list; 698da6c28aaSamw do { 699*a0aa776eSAlan Wright syslog(LOG_DEBUG, " %s ttl=%d flags=0x%x port=%d", 700da6c28aaSamw inet_ntoa(addr->sin.sin_addr), 701*a0aa776eSAlan Wright addr->ttl, addr->attributes, 702*a0aa776eSAlan Wright addr->sin.sin_port); 703da6c28aaSamw addr = addr->forw; 704da6c28aaSamw } while (addr && (addr != &entry->addr_list)); 705da6c28aaSamw } 706da6c28aaSamw 707da6c28aaSamw /* 708da6c28aaSamw * smb_netbios_name_dup 709da6c28aaSamw * 710da6c28aaSamw * Duplicate the given name entry. If 'alladdr' is 0 only 711da6c28aaSamw * copy the primary address otherwise duplicate all the 712da6c28aaSamw * addresses. NOTE that the duplicate structure is not 713da6c28aaSamw * like a regular cache entry i.e. it's a contiguous block 714da6c28aaSamw * of memory and each addr structure doesn't have it's own 715da6c28aaSamw * allocated memory. So, the returned structure can be freed 716da6c28aaSamw * by one free call. 717da6c28aaSamw */ 718da6c28aaSamw struct name_entry * 719da6c28aaSamw smb_netbios_name_dup(struct name_entry *entry, int alladdr) 720da6c28aaSamw { 721*a0aa776eSAlan Wright addr_entry_t *addr; 722*a0aa776eSAlan Wright addr_entry_t *dup_addr; 723da6c28aaSamw struct name_entry *dup; 724da6c28aaSamw int addr_cnt = 0; 725da6c28aaSamw int size = 0; 726da6c28aaSamw 727da6c28aaSamw if (alladdr) { 728da6c28aaSamw addr = entry->addr_list.forw; 729da6c28aaSamw while (addr && (addr != &entry->addr_list)) { 730da6c28aaSamw addr_cnt++; 731da6c28aaSamw addr = addr->forw; 732da6c28aaSamw } 733da6c28aaSamw } 734da6c28aaSamw 735da6c28aaSamw size = sizeof (struct name_entry) + 736*a0aa776eSAlan Wright (addr_cnt * sizeof (addr_entry_t)); 737da6c28aaSamw dup = (struct name_entry *)malloc(size); 738da6c28aaSamw if (dup == 0) 739da6c28aaSamw return (0); 740da6c28aaSamw 741da6c28aaSamw bzero(dup, size); 742da6c28aaSamw 743da6c28aaSamw dup->forw = dup->back = dup; 744da6c28aaSamw dup->attributes = entry->attributes; 745da6c28aaSamw (void) memcpy(dup->name, entry->name, NETBIOS_NAME_SZ); 746da6c28aaSamw (void) strlcpy((char *)dup->scope, (char *)entry->scope, 747da6c28aaSamw NETBIOS_DOMAIN_NAME_MAX); 748da6c28aaSamw dup->addr_list = entry->addr_list; 749da6c28aaSamw dup->addr_list.forw = dup->addr_list.back = &dup->addr_list; 750da6c28aaSamw 751da6c28aaSamw if (alladdr == 0) 752da6c28aaSamw return (dup); 753da6c28aaSamw 754da6c28aaSamw /* LINTED - E_BAD_PTR_CAST_ALIGN */ 755*a0aa776eSAlan Wright dup_addr = (addr_entry_t *)((unsigned char *)dup + 756da6c28aaSamw sizeof (struct name_entry)); 757da6c28aaSamw 758da6c28aaSamw addr = entry->addr_list.forw; 759da6c28aaSamw while (addr && (addr != &entry->addr_list)) { 760da6c28aaSamw *dup_addr = *addr; 761da6c28aaSamw QUEUE_INSERT_TAIL(&dup->addr_list, dup_addr); 762da6c28aaSamw addr = addr->forw; 763da6c28aaSamw dup_addr++; 764da6c28aaSamw } 765da6c28aaSamw 766da6c28aaSamw return (dup); 767da6c28aaSamw } 768da6c28aaSamw 769*a0aa776eSAlan Wright static void 770*a0aa776eSAlan Wright smb_strname(struct name_entry *entry, char *buf, int bufsize) 771da6c28aaSamw { 772*a0aa776eSAlan Wright char tmp[MAXHOSTNAMELEN]; 773*a0aa776eSAlan Wright char *p; 774*a0aa776eSAlan Wright 775*a0aa776eSAlan Wright (void) snprintf(tmp, MAXHOSTNAMELEN, "%15.15s", entry->name); 776*a0aa776eSAlan Wright if ((p = strchr(tmp, ' ')) != NULL) 777*a0aa776eSAlan Wright *p = '\0'; 778da6c28aaSamw 779*a0aa776eSAlan Wright if (entry->scope[0] != '\0') { 780*a0aa776eSAlan Wright (void) strlcat(tmp, ".", MAXHOSTNAMELEN); 781*a0aa776eSAlan Wright (void) strlcat(tmp, (char *)entry->scope, MAXHOSTNAMELEN); 782*a0aa776eSAlan Wright } 783da6c28aaSamw 784*a0aa776eSAlan Wright (void) snprintf(buf, bufsize, "%-16s <%02X>", tmp, entry->name[15]); 785da6c28aaSamw } 786da6c28aaSamw 787da6c28aaSamw static void 788da6c28aaSamw hash_callback(HT_ITEM *item) 789da6c28aaSamw { 790da6c28aaSamw struct name_entry *entry; 791da6c28aaSamw 792da6c28aaSamw if (item && item->hi_data) { 793da6c28aaSamw entry = (struct name_entry *)item->hi_data; 794da6c28aaSamw smb_netbios_name_freeaddrs(entry); 795da6c28aaSamw free(entry); 796da6c28aaSamw } 797da6c28aaSamw } 798da6c28aaSamw 799da6c28aaSamw 800da6c28aaSamw /*ARGSUSED*/ 801da6c28aaSamw static int 802da6c28aaSamw smb_netbios_match(const char *key1, const char *key2, size_t n) 803da6c28aaSamw { 804da6c28aaSamw int res; 805da6c28aaSamw 806da6c28aaSamw res = bcmp(key1, key2, NETBIOS_NAME_SZ); 807da6c28aaSamw if (res == 0) { 808da6c28aaSamw /* Names are the same, compare scopes */ 809da6c28aaSamw res = strcmp(key1 + NETBIOS_NAME_SZ, key2 + NETBIOS_NAME_SZ); 810da6c28aaSamw } 811da6c28aaSamw 812da6c28aaSamw return (res); 813da6c28aaSamw } 814da6c28aaSamw 815da6c28aaSamw static void 816da6c28aaSamw smb_netbios_cache_key(char *key, unsigned char *name, unsigned char *scope) 817da6c28aaSamw { 818da6c28aaSamw bzero(key, NETBIOS_HKEY_SZ); 819da6c28aaSamw (void) memcpy(key, name, NETBIOS_NAME_SZ); 820da6c28aaSamw (void) memcpy(key + NETBIOS_NAME_SZ, scope, 821da6c28aaSamw strlen((const char *)scope)); 822da6c28aaSamw } 823