xref: /onnv-gate/usr/src/lib/smbsrv/libsmbns/common/smbns_netbios_cache.c (revision 10717:fe0545fc3cdd)
15331Samw /*
25331Samw  * CDDL HEADER START
35331Samw  *
45331Samw  * The contents of this file are subject to the terms of the
55331Samw  * Common Development and Distribution License (the "License").
65331Samw  * You may not use this file except in compliance with the License.
75331Samw  *
85331Samw  * You can obtain a copy of the license at usr/src/OPENSOLARIS.LICENSE
95331Samw  * or http://www.opensolaris.org/os/licensing.
105331Samw  * See the License for the specific language governing permissions
115331Samw  * and limitations under the License.
125331Samw  *
135331Samw  * When distributing Covered Code, include this CDDL HEADER in each
145331Samw  * file and include the License file at usr/src/OPENSOLARIS.LICENSE.
155331Samw  * If applicable, add the following below this CDDL HEADER, with the
165331Samw  * fields enclosed by brackets "[]" replaced with your own identifying
175331Samw  * information: Portions Copyright [yyyy] [name of copyright owner]
185331Samw  *
195331Samw  * CDDL HEADER END
205331Samw  */
215331Samw /*
22*10717Samw@Sun.COM  * Copyright 2009 Sun Microsystems, Inc.  All rights reserved.
235331Samw  * Use is subject to license terms.
245331Samw  */
255331Samw 
265331Samw #include <synch.h>
275331Samw #include <stdio.h>
285331Samw #include <syslog.h>
295331Samw #include <stdlib.h>
305331Samw #include <arpa/inet.h>
315331Samw #include <netdb.h>
325331Samw 
335331Samw #include <smbsrv/libsmbns.h>
345331Samw #include <smbns_netbios.h>
355331Samw 
365331Samw #define	NETBIOS_HTAB_SZ	128
375331Samw #define	NETBIOS_HKEY_SZ	(NETBIOS_NAME_SZ + NETBIOS_DOMAIN_NAME_MAX)
385331Samw 
395331Samw #define	NETBIOS_SAME_IP(addr1, addr2) \
405331Samw 	((addr1)->sin.sin_addr.s_addr == (addr2)->sin.sin_addr.s_addr)
415331Samw 
425331Samw typedef char nb_key_t[NETBIOS_HKEY_SZ];
435331Samw static HT_HANDLE *smb_netbios_cache = 0;
445331Samw static rwlock_t nb_cache_lock;
455331Samw 
46*10717Samw@Sun.COM static void smb_strname(struct name_entry *name, char *buf, int bufsize);
475331Samw static void hash_callback(HT_ITEM *item);
485331Samw static int smb_netbios_match(const char *key1, const char *key2, size_t n);
495331Samw static void smb_netbios_cache_key(char *key, unsigned char *name,
505331Samw 					unsigned char *scope);
515331Samw 
525331Samw int
smb_netbios_cache_init(void)53*10717Samw@Sun.COM smb_netbios_cache_init(void)
545331Samw {
555331Samw 	(void) rw_wrlock(&nb_cache_lock);
56*10717Samw@Sun.COM 	if (smb_netbios_cache == NULL) {
575331Samw 		smb_netbios_cache = ht_create_table(NETBIOS_HTAB_SZ,
585331Samw 		    NETBIOS_HKEY_SZ, HTHF_FIXED_KEY);
59*10717Samw@Sun.COM 		if (smb_netbios_cache == NULL) {
60*10717Samw@Sun.COM 			syslog(LOG_ERR, "nbns: cannot create name cache");
615331Samw 			(void) rw_unlock(&nb_cache_lock);
62*10717Samw@Sun.COM 			return (-1);
635331Samw 		}
645331Samw 		(void) ht_register_callback(smb_netbios_cache, hash_callback);
655331Samw 		ht_set_cmpfn(smb_netbios_cache, smb_netbios_match);
665331Samw 	}
675331Samw 	(void) rw_unlock(&nb_cache_lock);
685331Samw 
69*10717Samw@Sun.COM 	return (0);
705331Samw }
715331Samw 
725331Samw void
smb_netbios_cache_fini(void)736030Sjb150015 smb_netbios_cache_fini(void)
745331Samw {
755331Samw 	(void) rw_wrlock(&nb_cache_lock);
765331Samw 	ht_destroy_table(smb_netbios_cache);
77*10717Samw@Sun.COM 	smb_netbios_cache = NULL;
785331Samw 	(void) rw_unlock(&nb_cache_lock);
795331Samw }
805331Samw 
815331Samw void
smb_netbios_cache_clean(void)826030Sjb150015 smb_netbios_cache_clean(void)
835331Samw {
845331Samw 	(void) rw_wrlock(&nb_cache_lock);
855331Samw 	(void) ht_clean_table(smb_netbios_cache);
865331Samw 	(void) rw_unlock(&nb_cache_lock);
875331Samw }
885331Samw 
896030Sjb150015 int
smb_netbios_cache_getfirst(nbcache_iter_t * iter)906030Sjb150015 smb_netbios_cache_getfirst(nbcache_iter_t *iter)
916030Sjb150015 {
926030Sjb150015 	HT_ITEM *item;
936030Sjb150015 	struct name_entry *entry;
946030Sjb150015 
956030Sjb150015 	(void) rw_rdlock(&nb_cache_lock);
966030Sjb150015 	item = ht_findfirst(smb_netbios_cache, &iter->nbc_hti);
976030Sjb150015 	if (item == NULL || item->hi_data == NULL) {
986030Sjb150015 		(void) rw_unlock(&nb_cache_lock);
996030Sjb150015 		return (-1);
1006030Sjb150015 	}
1016030Sjb150015 
1026030Sjb150015 	entry = (struct name_entry *)item->hi_data;
1036030Sjb150015 	(void) mutex_lock(&entry->mtx);
1046030Sjb150015 	iter->nbc_entry = smb_netbios_name_dup(entry, 1);
1056030Sjb150015 	(void) mutex_unlock(&entry->mtx);
1066030Sjb150015 
1076030Sjb150015 	(void) rw_unlock(&nb_cache_lock);
1086030Sjb150015 
1096030Sjb150015 	return ((iter->nbc_entry) ? 0 : -1);
1106030Sjb150015 }
1116030Sjb150015 
1126030Sjb150015 int
smb_netbios_cache_getnext(nbcache_iter_t * iter)1136030Sjb150015 smb_netbios_cache_getnext(nbcache_iter_t *iter)
1146030Sjb150015 {
1156030Sjb150015 	HT_ITEM *item;
1166030Sjb150015 	struct name_entry *entry;
1176030Sjb150015 
1186030Sjb150015 	(void) rw_rdlock(&nb_cache_lock);
1196030Sjb150015 	item = ht_findnext(&iter->nbc_hti);
1206030Sjb150015 	if (item == NULL || item->hi_data == NULL) {
1216030Sjb150015 		(void) rw_unlock(&nb_cache_lock);
1226030Sjb150015 		return (-1);
1236030Sjb150015 	}
1246030Sjb150015 
1256030Sjb150015 	entry = (struct name_entry *)item->hi_data;
1266030Sjb150015 	(void) mutex_lock(&entry->mtx);
1276030Sjb150015 	iter->nbc_entry = smb_netbios_name_dup(entry, 1);
1286030Sjb150015 	(void) mutex_unlock(&entry->mtx);
1296030Sjb150015 
1306030Sjb150015 	(void) rw_unlock(&nb_cache_lock);
1316030Sjb150015 
1326030Sjb150015 	return ((iter->nbc_entry) ? 0 : -1);
1336030Sjb150015 }
1346030Sjb150015 
1355331Samw /*
1365331Samw  * smb_netbios_cache_lookup
1375331Samw  *
1385331Samw  * Searches the name cache for the given entry, if found
1395331Samw  * the entry will be locked before returning to caller
1405331Samw  * so caller MUST unlock the entry after it's done with it.
1415331Samw  */
1425331Samw struct name_entry *
smb_netbios_cache_lookup(struct name_entry * name)1435331Samw smb_netbios_cache_lookup(struct name_entry *name)
1445331Samw {
1455331Samw 	HT_ITEM *item;
1465331Samw 	nb_key_t key;
1475331Samw 	struct name_entry *entry = NULL;
1485331Samw 	unsigned char hostname[MAXHOSTNAMELEN];
1495331Samw 
1505331Samw 	if (NETBIOS_NAME_IS_STAR(name->name)) {
1515331Samw 		/* Return our address */
1526030Sjb150015 		if (smb_getnetbiosname((char *)hostname, sizeof (hostname))
1536030Sjb150015 		    != 0)
1545331Samw 			return (NULL);
1555331Samw 
1566030Sjb150015 		smb_encode_netbios_name(hostname, 0x00, NULL, name);
1575331Samw 	}
1585331Samw 
1595331Samw 	(void) rw_rdlock(&nb_cache_lock);
1605331Samw 
1615331Samw 	smb_netbios_cache_key(key, name->name, name->scope);
1625331Samw 	item = ht_find_item(smb_netbios_cache, key);
1635331Samw 	if (item) {
1645331Samw 		entry = (struct name_entry *)item->hi_data;
1655331Samw 		(void) mutex_lock(&entry->mtx);
1665331Samw 		if ((entry->attributes & NAME_ATTR_CONFLICT) != 0) {
1675331Samw 			(void) mutex_unlock(&entry->mtx);
1685331Samw 			entry = NULL;
1695331Samw 		}
1705331Samw 	}
1715331Samw 
1725331Samw 	(void) rw_unlock(&nb_cache_lock);
1735331Samw 	return (entry);
1745331Samw }
1755331Samw 
1765331Samw void
smb_netbios_cache_unlock_entry(struct name_entry * name)1775331Samw smb_netbios_cache_unlock_entry(struct name_entry *name)
1785331Samw {
1795331Samw 	if (name)
1805331Samw 		(void) mutex_unlock(&name->mtx);
1815331Samw }
1825331Samw 
1835331Samw /*
1845331Samw  * smb_netbios_cache_lookup_addr
1855331Samw  *
1865331Samw  * lookup the given 'name' in the cache and then checks
1875331Samw  * if the address also matches with the found entry.
1885331Samw  * 'name' is supposed to contain only one address.
1895331Samw  *
1905331Samw  * The found entry will be locked before returning to caller
1915331Samw  * so caller MUST unlock the entry after it's done with it.
1925331Samw  */
1935331Samw struct name_entry *
smb_netbios_cache_lookup_addr(struct name_entry * name)1945331Samw smb_netbios_cache_lookup_addr(struct name_entry *name)
1955331Samw {
1965331Samw 	struct name_entry *entry = 0;
197*10717Samw@Sun.COM 	addr_entry_t *addr;
198*10717Samw@Sun.COM 	addr_entry_t *name_addr;
1995331Samw 	HT_ITEM *item;
2005331Samw 	nb_key_t key;
2015331Samw 
2025331Samw 	(void) rw_rdlock(&nb_cache_lock);
2035331Samw 	smb_netbios_cache_key(key, name->name, name->scope);
2045331Samw 	item = ht_find_item(smb_netbios_cache, key);
2055331Samw 
2065331Samw 	if (item && item->hi_data) {
2075331Samw 		name_addr = &name->addr_list;
2085331Samw 		entry = (struct name_entry *)item->hi_data;
2095331Samw 		(void) mutex_lock(&entry->mtx);
2105331Samw 		addr = &entry->addr_list;
2115331Samw 		do {
2125331Samw 			if (NETBIOS_SAME_IP(addr, name_addr)) {
2135331Samw 				/* note that entry lock isn't released here */
2145331Samw 				(void) rw_unlock(&nb_cache_lock);
2155331Samw 				return (entry);
2165331Samw 			}
2175331Samw 			addr = addr->forw;
2185331Samw 		} while (addr != &entry->addr_list);
2195331Samw 		(void) mutex_unlock(&entry->mtx);
2205331Samw 	}
2215331Samw 
2225331Samw 	(void) rw_unlock(&nb_cache_lock);
2235331Samw 	return (0);
2245331Samw }
2255331Samw 
2265331Samw int
smb_netbios_cache_insert(struct name_entry * name)2275331Samw smb_netbios_cache_insert(struct name_entry *name)
2285331Samw {
2295331Samw 	struct name_entry *entry;
230*10717Samw@Sun.COM 	addr_entry_t *addr;
231*10717Samw@Sun.COM 	addr_entry_t *name_addr;
2325331Samw 	HT_ITEM *item;
2335331Samw 	nb_key_t key;
2346030Sjb150015 	int rc;
2355331Samw 
2365331Samw 	/* No point in adding a name with IP address 255.255.255.255 */
2375331Samw 	if (name->addr_list.sin.sin_addr.s_addr == 0xffffffff)
2385331Samw 		return (0);
2395331Samw 
2405331Samw 	(void) rw_wrlock(&nb_cache_lock);
2415331Samw 	smb_netbios_cache_key(key, name->name, name->scope);
2425331Samw 	item = ht_find_item(smb_netbios_cache, key);
2435331Samw 
2445331Samw 	if (item && item->hi_data) {
2455331Samw 		/* Name already exists */
2465331Samw 		entry = (struct name_entry *)item->hi_data;
2475331Samw 		(void) mutex_lock(&entry->mtx);
2485331Samw 
2495331Samw 		name_addr = &name->addr_list;
2505331Samw 		addr = &entry->addr_list;
2515331Samw 		if (NETBIOS_SAME_IP(addr, name_addr) &&
2525331Samw 		    (addr->sin.sin_port == name_addr->sin.sin_port)) {
2535331Samw 			entry->attributes |=
2545331Samw 			    name_addr->attributes & NAME_ATTR_LOCAL;
2555331Samw 			(void) mutex_unlock(&entry->mtx);
2565331Samw 			(void) rw_unlock(&nb_cache_lock);
2576030Sjb150015 			return (0);
2585331Samw 		}
2595331Samw 
2605331Samw 		/* Was not primary: looks for others */
2615331Samw 		for (addr = entry->addr_list.forw;
2625331Samw 		    addr != &entry->addr_list; addr = addr->forw) {
2635331Samw 			if (NETBIOS_SAME_IP(addr, name_addr) &&
2645331Samw 			    (addr->sin.sin_port == name_addr->sin.sin_port)) {
2655331Samw 				(void) mutex_unlock(&entry->mtx);
2665331Samw 				(void) rw_unlock(&nb_cache_lock);
2676030Sjb150015 				return (0);
2685331Samw 			}
2695331Samw 		}
2705331Samw 
271*10717Samw@Sun.COM 		if ((addr = malloc(sizeof (addr_entry_t))) != NULL) {
2726030Sjb150015 			*addr = name->addr_list;
2736030Sjb150015 			entry->attributes |= addr->attributes;
2746030Sjb150015 			QUEUE_INSERT_TAIL(&entry->addr_list, addr);
2756030Sjb150015 			rc = 0;
2766030Sjb150015 		} else {
2776030Sjb150015 			rc = -1;
2785331Samw 		}
2796030Sjb150015 
2805331Samw 		(void) mutex_unlock(&entry->mtx);
2815331Samw 		(void) rw_unlock(&nb_cache_lock);
2826030Sjb150015 		return (rc);
2835331Samw 	}
2845331Samw 
2856030Sjb150015 	if ((entry = malloc(sizeof (struct name_entry))) == NULL) {
2865331Samw 		(void) rw_unlock(&nb_cache_lock);
2875331Samw 		return (-1);
2885331Samw 	}
2896030Sjb150015 
2905331Samw 	*entry = *name;
2915331Samw 	entry->addr_list.forw = entry->addr_list.back = &entry->addr_list;
2925331Samw 	entry->attributes |= entry->addr_list.attributes;
2935331Samw 	(void) mutex_init(&entry->mtx, 0, 0);
2945331Samw 	if (ht_replace_item(smb_netbios_cache, key, entry) == 0) {
2955331Samw 		free(entry);
2965331Samw 		(void) rw_unlock(&nb_cache_lock);
2975331Samw 		return (-1);
2985331Samw 	}
2995331Samw 
3005331Samw 	(void) rw_unlock(&nb_cache_lock);
3015331Samw 	return (0);
3025331Samw }
3035331Samw 
3045331Samw 
3055331Samw void
smb_netbios_cache_delete(struct name_entry * name)3065331Samw smb_netbios_cache_delete(struct name_entry *name)
3075331Samw {
3085331Samw 	nb_key_t key;
3095331Samw 	HT_ITEM *item;
3105331Samw 	struct name_entry *entry;
3115331Samw 
3125331Samw 	(void) rw_wrlock(&nb_cache_lock);
3135331Samw 	smb_netbios_cache_key(key, name->name, name->scope);
3145331Samw 	item = ht_find_item(smb_netbios_cache, key);
3155331Samw 	if (item && item->hi_data) {
3165331Samw 		entry = (struct name_entry *)item->hi_data;
3175331Samw 		(void) mutex_lock(&entry->mtx);
3185331Samw 		ht_mark_delete(smb_netbios_cache, item);
3195331Samw 		(void) mutex_unlock(&entry->mtx);
3205331Samw 	}
3215331Samw 	(void) rw_unlock(&nb_cache_lock);
3225331Samw }
3235331Samw 
3245331Samw /*
3255331Samw  * smb_netbios_cache_insert_list
3265331Samw  *
3275331Samw  * Insert a name with multiple addresses
3285331Samw  */
3295331Samw int
smb_netbios_cache_insert_list(struct name_entry * name)3305331Samw smb_netbios_cache_insert_list(struct name_entry *name)
3315331Samw {
3325331Samw 	struct name_entry entry;
333*10717Samw@Sun.COM 	addr_entry_t *addr;
3345331Samw 
3355331Samw 	addr = &name->addr_list;
3365331Samw 	do {
3375331Samw 		smb_init_name_struct(NETBIOS_EMPTY_NAME, 0, name->scope,
3385331Samw 		    addr->sin.sin_addr.s_addr,
3395331Samw 		    addr->sin.sin_port,
3405331Samw 		    name->attributes,
3415331Samw 		    addr->attributes,
3425331Samw 		    &entry);
3435331Samw 		(void) memcpy(entry.name, name->name, NETBIOS_NAME_SZ);
3445331Samw 		entry.addr_list.refresh_ttl = entry.addr_list.ttl =
3455331Samw 		    addr->refresh_ttl;
3465331Samw 		(void) smb_netbios_cache_insert(&entry);
3475331Samw 		addr = addr->forw;
3485331Samw 	} while (addr != &name->addr_list);
3495331Samw 
3505331Samw 	return (0);
3515331Samw }
3525331Samw 
3535331Samw void
smb_netbios_cache_update_entry(struct name_entry * entry,struct name_entry * name)3545331Samw smb_netbios_cache_update_entry(struct name_entry *entry,
3555331Samw     struct name_entry *name)
3565331Samw {
357*10717Samw@Sun.COM 	addr_entry_t *addr;
358*10717Samw@Sun.COM 	addr_entry_t *name_addr;
3595331Samw 
3605331Samw 	addr = &entry->addr_list;
3615331Samw 	name_addr = &name->addr_list;
3625331Samw 
3635331Samw 	if (IS_UNIQUE(entry->attributes)) {
3645331Samw 		do {
3655331Samw 			addr->ttl = name_addr->ttl;
3665331Samw 			addr = addr->forw;
3675331Samw 		} while (addr != &entry->addr_list);
3685331Samw 
3695331Samw 	} else {
3705331Samw 		do {
3715331Samw 			if (NETBIOS_SAME_IP(addr, name_addr) &&
3725331Samw 			    (addr->sin.sin_port == name_addr->sin.sin_port)) {
3735331Samw 				addr->ttl = name_addr->ttl;
3745331Samw 				return;
3755331Samw 			}
3765331Samw 			addr = addr->forw;
3775331Samw 		} while (addr != &entry->addr_list);
3785331Samw 	}
3795331Samw }
3805331Samw 
3815331Samw /*
3825331Samw  * smb_netbios_cache_status
3835331Samw  *
3845331Samw  * Scan the name cache and gather status for
3855331Samw  * Node Status response for names in the given scope
3865331Samw  */
3875331Samw unsigned char *
smb_netbios_cache_status(unsigned char * buf,int bufsize,unsigned char * scope)3885331Samw smb_netbios_cache_status(unsigned char *buf, int bufsize, unsigned char *scope)
3895331Samw {
3905331Samw 	HT_ITERATOR hti;
3915331Samw 	HT_ITEM *item;
3925331Samw 	struct name_entry *name;
3935331Samw 	unsigned char *numnames;
3945331Samw 	unsigned char *scan;
3955331Samw 	unsigned char *scan_end;
3965331Samw 
3975331Samw 	scan = buf;
3985331Samw 	scan_end = scan + bufsize;
3995331Samw 
4005331Samw 	numnames = scan++;
4015331Samw 	*numnames = 0;
4025331Samw 
4035331Samw 	(void) rw_rdlock(&nb_cache_lock);
4045331Samw 	item = ht_findfirst(smb_netbios_cache, &hti);
4055331Samw 	do {
4065331Samw 		if (item == 0)
4075331Samw 			break;
4085331Samw 
4095331Samw 		if (item->hi_data == 0)
4105331Samw 			continue;
4115331Samw 
4125331Samw 		if ((scan + NETBIOS_NAME_SZ + 2) >= scan_end)
4135331Samw 			/* no room for adding next entry */
4145331Samw 			break;
4155331Samw 
4165331Samw 		name = (struct name_entry *)item->hi_data;
4175331Samw 		(void) mutex_lock(&name->mtx);
4185331Samw 
4195331Samw 		if (IS_LOCAL(name->attributes) &&
4205331Samw 		    (strcasecmp((char *)scope, (char *)name->scope) == 0)) {
4215331Samw 			bcopy(name->name, scan, NETBIOS_NAME_SZ);
4225331Samw 			scan += NETBIOS_NAME_SZ;
4235331Samw 			*scan++ = PUBLIC_BITS(name->attributes) >> 8;
4245331Samw 			*scan++ = PUBLIC_BITS(name->attributes);
4255331Samw 			(*numnames)++;
4265331Samw 		}
4275331Samw 
4285331Samw 		(void) mutex_unlock(&name->mtx);
4295331Samw 	} while ((item = ht_findnext(&hti)) != 0);
4305331Samw 	(void) rw_unlock(&nb_cache_lock);
4315331Samw 
4325331Samw 	return (scan);
4335331Samw }
4345331Samw 
4355331Samw void
smb_netbios_cache_reset_ttl()4365331Samw smb_netbios_cache_reset_ttl()
4375331Samw {
438*10717Samw@Sun.COM 	addr_entry_t *addr;
4395331Samw 	struct name_entry *name;
4405331Samw 	HT_ITERATOR hti;
4415331Samw 	HT_ITEM *item;
4425331Samw 
4435331Samw 	(void) rw_rdlock(&nb_cache_lock);
4445331Samw 	item = ht_findfirst(smb_netbios_cache, &hti);
4455331Samw 	do {
4465331Samw 		if (item == 0)
4475331Samw 			break;
4485331Samw 
4495331Samw 		if (item->hi_data == 0)
4505331Samw 			continue;
4515331Samw 
4525331Samw 		name = (struct name_entry *)item->hi_data;
4535331Samw 		(void) mutex_lock(&name->mtx);
4545331Samw 
4555331Samw 		addr = &name->addr_list;
4565331Samw 		do {
4575331Samw 			if (addr->ttl < 1) {
4585331Samw 				if (addr->refresh_ttl)
4595331Samw 					addr->ttl = addr->refresh_ttl;
4605331Samw 				else
4615331Samw 					addr->refresh_ttl = addr->ttl =
4625331Samw 					    TO_SECONDS(DEFAULT_TTL);
4635331Samw 			}
4645331Samw 			addr = addr->forw;
4655331Samw 		} while (addr != &name->addr_list);
4665331Samw 
4675331Samw 		(void) mutex_unlock(&name->mtx);
4685331Samw 	} while ((item = ht_findnext(&hti)) != 0);
4695331Samw 	(void) rw_unlock(&nb_cache_lock);
4705331Samw }
4715331Samw 
4725331Samw /*
4735331Samw  * Returns TRUE when given name is added to the refresh queue
4745331Samw  * FALSE if not.
4755331Samw  */
4765331Samw static boolean_t
smb_netbios_cache_insrefq(name_queue_t * refq,HT_ITEM * item)4775331Samw smb_netbios_cache_insrefq(name_queue_t *refq, HT_ITEM *item)
4785331Samw {
4795331Samw 	struct name_entry *name;
4805331Samw 	struct name_entry *refent;
4815331Samw 
4825331Samw 	name = (struct name_entry *)item->hi_data;
4835331Samw 
4845331Samw 	if (IS_LOCAL(name->attributes)) {
4855331Samw 		if (IS_UNIQUE(name->attributes)) {
4865331Samw 			refent = smb_netbios_name_dup(name, 1);
4875331Samw 			if (refent)
4885331Samw 				QUEUE_INSERT_TAIL(&refq->head, refent)
4895331Samw 
4905331Samw 			/* next name */
4915331Samw 			return (B_TRUE);
4925331Samw 		}
4935331Samw 	} else {
4945331Samw 		ht_mark_delete(smb_netbios_cache, item);
4955331Samw 		refent = smb_netbios_name_dup(name, 0);
4965331Samw 		if (refent)
4975331Samw 			QUEUE_INSERT_TAIL(&refq->head, refent)
4985331Samw 
4995331Samw 		/* next name */
5005331Samw 		return (B_TRUE);
5015331Samw 	}
5025331Samw 
5035331Samw 	return (B_FALSE);
5045331Samw }
5055331Samw 
5065331Samw /*
5075331Samw  * smb_netbios_cache_refresh
5085331Samw  *
5095331Samw  * Scans the name cache and add all local unique names
5105331Samw  * and non-local names the passed refresh queue. Non-
5115331Samw  * local names will also be marked as deleted.
5125331Samw  *
5135331Samw  * NOTE that the caller MUST protect the queue using
5145331Samw  * its mutex
5155331Samw  */
5165331Samw void
smb_netbios_cache_refresh(name_queue_t * refq)5175331Samw smb_netbios_cache_refresh(name_queue_t *refq)
5185331Samw {
5195331Samw 	struct name_entry *name;
520*10717Samw@Sun.COM 	addr_entry_t *addr;
5215331Samw 	HT_ITERATOR hti;
5225331Samw 	HT_ITEM *item;
5235331Samw 
5245331Samw 	bzero(&refq->head, sizeof (refq->head));
5255331Samw 	refq->head.forw = refq->head.back = &refq->head;
5265331Samw 
5275331Samw 	(void) rw_rdlock(&nb_cache_lock);
5285331Samw 	item = ht_findfirst(smb_netbios_cache, &hti);
5295331Samw 	do { /* name loop */
5305331Samw 		if (item == 0)
5315331Samw 			break;
5325331Samw 
5335331Samw 		if (item->hi_data == 0)
5345331Samw 			continue;
5355331Samw 
5365331Samw 		name = (struct name_entry *)item->hi_data;
5375331Samw 		(void) mutex_lock(&name->mtx);
5385331Samw 
5395331Samw 		addr = &name->addr_list;
5405331Samw 		do { /* address loop */
5415331Samw 			if (addr->ttl > 0) {
5425331Samw 				addr->ttl--;
5435331Samw 				if (addr->ttl == 0) {
5445331Samw 					if (smb_netbios_cache_insrefq(refq,
5455331Samw 					    item))
5465331Samw 						break;
5475331Samw 				}
5485331Samw 			}
5495331Samw 			addr = addr->forw;
5505331Samw 		} while (addr != &name->addr_list);
5515331Samw 
5525331Samw 		(void) mutex_unlock(&name->mtx);
5535331Samw 	} while ((item = ht_findnext(&hti)) != 0);
5545331Samw 	(void) rw_unlock(&nb_cache_lock);
5555331Samw }
5565331Samw 
5575331Samw /*
5585331Samw  * smb_netbios_cache_delete_locals
5595331Samw  *
5605331Samw  * Scans the name cache and add all local names to
5615331Samw  * the passed delete queue.
5625331Samw  *
5635331Samw  * NOTE that the caller MUST protect the queue using
5645331Samw  * its mutex
5655331Samw  */
5665331Samw void
smb_netbios_cache_delete_locals(name_queue_t * delq)5675331Samw smb_netbios_cache_delete_locals(name_queue_t *delq)
5685331Samw {
5695331Samw 	struct name_entry *entry;
5705331Samw 	struct name_entry *delent;
5715331Samw 	HT_ITERATOR hti;
5725331Samw 	HT_ITEM *item;
5735331Samw 
5745331Samw 	bzero(&delq->head, sizeof (delq->head));
5755331Samw 	delq->head.forw = delq->head.back = &delq->head;
5765331Samw 
5775331Samw 	(void) rw_wrlock(&nb_cache_lock);
5785331Samw 	item = ht_findfirst(smb_netbios_cache, &hti);
5795331Samw 	do {
5805331Samw 		if (item == 0)
5815331Samw 			break;
5825331Samw 
5835331Samw 		if (item->hi_data == 0)
5845331Samw 			continue;
5855331Samw 
5865331Samw 		entry = (struct name_entry *)item->hi_data;
5875331Samw 		(void) mutex_lock(&entry->mtx);
5885331Samw 
5895331Samw 		if (IS_LOCAL(entry->attributes)) {
5905331Samw 			ht_mark_delete(smb_netbios_cache, item);
5915331Samw 			delent = smb_netbios_name_dup(entry, 1);
5925331Samw 			if (delent)
5935331Samw 				QUEUE_INSERT_TAIL(&delq->head, delent)
5945331Samw 		}
5955331Samw 
5965331Samw 		(void) mutex_unlock(&entry->mtx);
5975331Samw 	} while ((item = ht_findnext(&hti)) != 0);
5985331Samw 	(void) rw_unlock(&nb_cache_lock);
5995331Samw }
6005331Samw 
6015331Samw void
smb_netbios_name_freeaddrs(struct name_entry * entry)6025331Samw smb_netbios_name_freeaddrs(struct name_entry *entry)
6035331Samw {
604*10717Samw@Sun.COM 	addr_entry_t *addr;
6055331Samw 
6065331Samw 	if (entry == 0)
6075331Samw 		return;
6085331Samw 
6095331Samw 	while ((addr = entry->addr_list.forw) != &entry->addr_list) {
6105331Samw 		QUEUE_CLIP(addr);
6115331Samw 		free(addr);
6125331Samw 	}
6135331Samw }
6145331Samw 
6155331Samw /*
6165331Samw  * smb_netbios_cache_count
6175331Samw  *
6185331Samw  * Returns the number of names in the cache
6195331Samw  */
6205331Samw int
smb_netbios_cache_count()6215331Samw smb_netbios_cache_count()
6225331Samw {
6235331Samw 	int cnt;
6245331Samw 
6255331Samw 	(void) rw_rdlock(&nb_cache_lock);
6265331Samw 	cnt = ht_get_total_items(smb_netbios_cache);
6275331Samw 	(void) rw_unlock(&nb_cache_lock);
6285331Samw 
6295331Samw 	return (cnt);
6305331Samw }
6315331Samw 
6325331Samw void
smb_netbios_cache_dump(FILE * fp)633*10717Samw@Sun.COM smb_netbios_cache_dump(FILE *fp)
6345331Samw {
6355331Samw 	struct name_entry *name;
6365331Samw 	HT_ITERATOR hti;
6375331Samw 	HT_ITEM *item;
6385331Samw 
6395331Samw 	(void) rw_rdlock(&nb_cache_lock);
640*10717Samw@Sun.COM 
641*10717Samw@Sun.COM 	if (ht_get_total_items(smb_netbios_cache) != 0) {
642*10717Samw@Sun.COM 		(void) fprintf(fp, "\n%-22s %-16s %-16s  %s\n",
643*10717Samw@Sun.COM 		    "Name", "Type", "Address", "TTL");
644*10717Samw@Sun.COM 		(void) fprintf(fp, "%s%s\n",
645*10717Samw@Sun.COM 		    "-------------------------------",
646*10717Samw@Sun.COM 		    "------------------------------");
647*10717Samw@Sun.COM 	}
648*10717Samw@Sun.COM 
6495331Samw 	item = ht_findfirst(smb_netbios_cache, &hti);
6505331Samw 	while (item) {
6515331Samw 		if (item->hi_data) {
6525331Samw 			name = (struct name_entry *)item->hi_data;
6535331Samw 			(void) mutex_lock(&name->mtx);
654*10717Samw@Sun.COM 			smb_netbios_name_dump(fp, name);
6555331Samw 			(void) mutex_unlock(&name->mtx);
6565331Samw 		}
6575331Samw 		item = ht_findnext(&hti);
6585331Samw 	}
6595331Samw 	(void) rw_unlock(&nb_cache_lock);
6605331Samw }
6615331Samw 
6625331Samw void
smb_netbios_name_dump(FILE * fp,struct name_entry * entry)663*10717Samw@Sun.COM smb_netbios_name_dump(FILE *fp, struct name_entry *entry)
6645331Samw {
665*10717Samw@Sun.COM 	char		buf[MAXHOSTNAMELEN];
666*10717Samw@Sun.COM 	addr_entry_t	*addr;
667*10717Samw@Sun.COM 	char		*type;
668*10717Samw@Sun.COM 	int		count = 0;
6695331Samw 
670*10717Samw@Sun.COM 	smb_strname(entry, buf, sizeof (buf));
671*10717Samw@Sun.COM 	type = (IS_UNIQUE(entry->attributes)) ? "UNIQUE" : "GROUP";
6725331Samw 
673*10717Samw@Sun.COM 	(void) fprintf(fp, "%s %-6s (0x%04x)  ", buf, type, entry->attributes);
674*10717Samw@Sun.COM 
6755331Samw 	addr = &entry->addr_list;
6765331Samw 	do {
677*10717Samw@Sun.COM 		if (count == 0)
678*10717Samw@Sun.COM 			(void) fprintf(fp, "%-16s  %d\n",
679*10717Samw@Sun.COM 			    inet_ntoa(addr->sin.sin_addr), addr->ttl);
680*10717Samw@Sun.COM 		else
681*10717Samw@Sun.COM 			(void) fprintf(fp, "%-28s  (0x%04x)  %-16s  %d\n",
682*10717Samw@Sun.COM 			    " ", addr->attributes,
683*10717Samw@Sun.COM 			    inet_ntoa(addr->sin.sin_addr), addr->ttl);
684*10717Samw@Sun.COM 		++count;
6855331Samw 		addr = addr->forw;
6865331Samw 	} while (addr != &entry->addr_list);
6875331Samw }
6885331Samw 
6895331Samw void
smb_netbios_name_logf(struct name_entry * entry)6905331Samw smb_netbios_name_logf(struct name_entry *entry)
6915331Samw {
692*10717Samw@Sun.COM 	char		namebuf[MAXHOSTNAMELEN];
693*10717Samw@Sun.COM 	addr_entry_t	*addr;
6945331Samw 
695*10717Samw@Sun.COM 	smb_strname(entry, namebuf, sizeof (namebuf));
6965331Samw 	syslog(LOG_DEBUG, "%s flags=0x%x\n", namebuf, entry->attributes);
6975331Samw 	addr = &entry->addr_list;
6985331Samw 	do {
699*10717Samw@Sun.COM 		syslog(LOG_DEBUG, "  %s ttl=%d flags=0x%x port=%d",
7005331Samw 		    inet_ntoa(addr->sin.sin_addr),
701*10717Samw@Sun.COM 		    addr->ttl, addr->attributes,
702*10717Samw@Sun.COM 		    addr->sin.sin_port);
7035331Samw 		addr = addr->forw;
7045331Samw 	} while (addr && (addr != &entry->addr_list));
7055331Samw }
7065331Samw 
7075331Samw /*
7085331Samw  * smb_netbios_name_dup
7095331Samw  *
7105331Samw  * Duplicate the given name entry. If 'alladdr' is 0 only
7115331Samw  * copy the primary address otherwise duplicate all the
7125331Samw  * addresses. NOTE that the duplicate structure is not
7135331Samw  * like a regular cache entry i.e. it's a contiguous block
7145331Samw  * of memory and each addr structure doesn't have it's own
7155331Samw  * allocated memory. So, the returned structure can be freed
7165331Samw  * by one free call.
7175331Samw  */
7185331Samw struct name_entry *
smb_netbios_name_dup(struct name_entry * entry,int alladdr)7195331Samw smb_netbios_name_dup(struct name_entry *entry, int alladdr)
7205331Samw {
721*10717Samw@Sun.COM 	addr_entry_t *addr;
722*10717Samw@Sun.COM 	addr_entry_t *dup_addr;
7235331Samw 	struct name_entry *dup;
7245331Samw 	int addr_cnt = 0;
7255331Samw 	int size = 0;
7265331Samw 
7275331Samw 	if (alladdr) {
7285331Samw 		addr = entry->addr_list.forw;
7295331Samw 		while (addr && (addr != &entry->addr_list)) {
7305331Samw 			addr_cnt++;
7315331Samw 			addr = addr->forw;
7325331Samw 		}
7335331Samw 	}
7345331Samw 
7355331Samw 	size = sizeof (struct name_entry) +
736*10717Samw@Sun.COM 	    (addr_cnt * sizeof (addr_entry_t));
7375331Samw 	dup = (struct name_entry *)malloc(size);
7385331Samw 	if (dup == 0)
7395331Samw 		return (0);
7405331Samw 
7415331Samw 	bzero(dup, size);
7425331Samw 
7435331Samw 	dup->forw = dup->back = dup;
7445331Samw 	dup->attributes = entry->attributes;
7455331Samw 	(void) memcpy(dup->name, entry->name, NETBIOS_NAME_SZ);
7465331Samw 	(void) strlcpy((char *)dup->scope, (char *)entry->scope,
7475331Samw 	    NETBIOS_DOMAIN_NAME_MAX);
7485331Samw 	dup->addr_list = entry->addr_list;
7495331Samw 	dup->addr_list.forw = dup->addr_list.back = &dup->addr_list;
7505331Samw 
7515331Samw 	if (alladdr == 0)
7525331Samw 		return (dup);
7535331Samw 
7545331Samw 	/* LINTED - E_BAD_PTR_CAST_ALIGN */
755*10717Samw@Sun.COM 	dup_addr = (addr_entry_t *)((unsigned char *)dup +
7565331Samw 	    sizeof (struct name_entry));
7575331Samw 
7585331Samw 	addr = entry->addr_list.forw;
7595331Samw 	while (addr && (addr != &entry->addr_list)) {
7605331Samw 		*dup_addr = *addr;
7615331Samw 		QUEUE_INSERT_TAIL(&dup->addr_list, dup_addr);
7625331Samw 		addr = addr->forw;
7635331Samw 		dup_addr++;
7645331Samw 	}
7655331Samw 
7665331Samw 	return (dup);
7675331Samw }
7685331Samw 
769*10717Samw@Sun.COM static void
smb_strname(struct name_entry * entry,char * buf,int bufsize)770*10717Samw@Sun.COM smb_strname(struct name_entry *entry, char *buf, int bufsize)
7715331Samw {
772*10717Samw@Sun.COM 	char	tmp[MAXHOSTNAMELEN];
773*10717Samw@Sun.COM 	char	*p;
7745331Samw 
775*10717Samw@Sun.COM 	(void) snprintf(tmp, MAXHOSTNAMELEN, "%15.15s", entry->name);
776*10717Samw@Sun.COM 	if ((p = strchr(tmp, ' ')) != NULL)
777*10717Samw@Sun.COM 		*p = '\0';
7785331Samw 
779*10717Samw@Sun.COM 	if (entry->scope[0] != '\0') {
780*10717Samw@Sun.COM 		(void) strlcat(tmp, ".", MAXHOSTNAMELEN);
781*10717Samw@Sun.COM 		(void) strlcat(tmp, (char *)entry->scope, MAXHOSTNAMELEN);
782*10717Samw@Sun.COM 	}
783*10717Samw@Sun.COM 
784*10717Samw@Sun.COM 	(void) snprintf(buf, bufsize, "%-16s  <%02X>", tmp, entry->name[15]);
7855331Samw }
7865331Samw 
7875331Samw static void
hash_callback(HT_ITEM * item)7885331Samw hash_callback(HT_ITEM *item)
7895331Samw {
7905331Samw 	struct name_entry *entry;
7915331Samw 
7925331Samw 	if (item && item->hi_data) {
7935331Samw 		entry = (struct name_entry *)item->hi_data;
7945331Samw 		smb_netbios_name_freeaddrs(entry);
7955331Samw 		free(entry);
7965331Samw 	}
7975331Samw }
7985331Samw 
7995331Samw 
8005331Samw /*ARGSUSED*/
8015331Samw static int
smb_netbios_match(const char * key1,const char * key2,size_t n)8025331Samw smb_netbios_match(const char *key1, const char *key2, size_t n)
8035331Samw {
8045331Samw 	int res;
8055331Samw 
8065331Samw 	res = bcmp(key1, key2, NETBIOS_NAME_SZ);
8075331Samw 	if (res == 0) {
8085331Samw 		/* Names are the same, compare scopes */
8095331Samw 		res = strcmp(key1 + NETBIOS_NAME_SZ, key2 + NETBIOS_NAME_SZ);
8105331Samw 	}
8115331Samw 
8125331Samw 	return (res);
8135331Samw }
8145331Samw 
8155331Samw static void
smb_netbios_cache_key(char * key,unsigned char * name,unsigned char * scope)8165331Samw smb_netbios_cache_key(char *key, unsigned char *name, unsigned char *scope)
8175331Samw {
8185331Samw 	bzero(key, NETBIOS_HKEY_SZ);
8195331Samw 	(void) memcpy(key, name, NETBIOS_NAME_SZ);
8205331Samw 	(void) memcpy(key + NETBIOS_NAME_SZ, scope,
8215331Samw 	    strlen((const char *)scope));
8225331Samw }
823