1da6c28aamw/*
2da6c28aamw * CDDL HEADER START
3da6c28aamw *
4da6c28aamw * The contents of this file are subject to the terms of the
5da6c28aamw * Common Development and Distribution License (the "License").
6da6c28aamw * You may not use this file except in compliance with the License.
7da6c28aamw *
8da6c28aamw * You can obtain a copy of the license at usr/src/OPENSOLARIS.LICENSE
9da6c28aamw * or http://www.opensolaris.org/os/licensing.
10da6c28aamw * See the License for the specific language governing permissions
11da6c28aamw * and limitations under the License.
12da6c28aamw *
13da6c28aamw * When distributing Covered Code, include this CDDL HEADER in each
14da6c28aamw * file and include the License file at usr/src/OPENSOLARIS.LICENSE.
15da6c28aamw * If applicable, add the following below this CDDL HEADER, with the
16da6c28aamw * fields enclosed by brackets "[]" replaced with your own identifying
17da6c28aamw * information: Portions Copyright [yyyy] [name of copyright owner]
18da6c28aamw *
19da6c28aamw * CDDL HEADER END
20da6c28aamw */
21da6c28aamw/*
22a0aa776Alan Wright * Copyright 2009 Sun Microsystems, Inc.  All rights reserved.
23da6c28aamw * Use is subject to license terms.
24da6c28aamw */
25da6c28aamw
26da6c28aamw#include <synch.h>
27da6c28aamw#include <stdio.h>
28da6c28aamw#include <syslog.h>
29da6c28aamw#include <stdlib.h>
30da6c28aamw#include <arpa/inet.h>
31da6c28aamw#include <netdb.h>
32da6c28aamw
33da6c28aamw#include <smbsrv/libsmbns.h>
34da6c28aamw#include <smbns_netbios.h>
35da6c28aamw
36da6c28aamw#define	NETBIOS_HTAB_SZ	128
37da6c28aamw#define	NETBIOS_HKEY_SZ	(NETBIOS_NAME_SZ + NETBIOS_DOMAIN_NAME_MAX)
38da6c28aamw
39da6c28aamw#define	NETBIOS_SAME_IP(addr1, addr2) \
40da6c28aamw	((addr1)->sin.sin_addr.s_addr == (addr2)->sin.sin_addr.s_addr)
41da6c28aamw
42da6c28aamwtypedef char nb_key_t[NETBIOS_HKEY_SZ];
43da6c28aamwstatic HT_HANDLE *smb_netbios_cache = 0;
44da6c28aamwstatic rwlock_t nb_cache_lock;
45da6c28aamw
46a0aa776Alan Wrightstatic void smb_strname(struct name_entry *name, char *buf, int bufsize);
47da6c28aamwstatic void hash_callback(HT_ITEM *item);
48da6c28aamwstatic int smb_netbios_match(const char *key1, const char *key2, size_t n);
49da6c28aamwstatic void smb_netbios_cache_key(char *key, unsigned char *name,
50da6c28aamw					unsigned char *scope);
51da6c28aamw
52da6c28aamwint
53a0aa776Alan Wrightsmb_netbios_cache_init(void)
54da6c28aamw{
55da6c28aamw	(void) rw_wrlock(&nb_cache_lock);
56a0aa776Alan Wright	if (smb_netbios_cache == NULL) {
57da6c28aamw		smb_netbios_cache = ht_create_table(NETBIOS_HTAB_SZ,
58da6c28aamw		    NETBIOS_HKEY_SZ, HTHF_FIXED_KEY);
59a0aa776Alan Wright		if (smb_netbios_cache == NULL) {
60a0aa776Alan Wright			syslog(LOG_ERR, "nbns: cannot create name cache");
61da6c28aamw			(void) rw_unlock(&nb_cache_lock);
62a0aa776Alan Wright			return (-1);
63da6c28aamw		}
64da6c28aamw		(void) ht_register_callback(smb_netbios_cache, hash_callback);
65da6c28aamw		ht_set_cmpfn(smb_netbios_cache, smb_netbios_match);
66da6c28aamw	}
67da6c28aamw	(void) rw_unlock(&nb_cache_lock);
68da6c28aamw
69a0aa776Alan Wright	return (0);
70da6c28aamw}
71da6c28aamw
72da6c28aamwvoid
737b59d02jbsmb_netbios_cache_fini(void)
74da6c28aamw{
75da6c28aamw	(void) rw_wrlock(&nb_cache_lock);
76da6c28aamw	ht_destroy_table(smb_netbios_cache);
77a0aa776Alan Wright	smb_netbios_cache = NULL;
78da6c28aamw	(void) rw_unlock(&nb_cache_lock);
79da6c28aamw}
80da6c28aamw
81da6c28aamwvoid
827b59d02jbsmb_netbios_cache_clean(void)
83da6c28aamw{
84da6c28aamw	(void) rw_wrlock(&nb_cache_lock);
85da6c28aamw	(void) ht_clean_table(smb_netbios_cache);
86da6c28aamw	(void) rw_unlock(&nb_cache_lock);
87da6c28aamw}
88da6c28aamw
897b59d02jbint
907b59d02jbsmb_netbios_cache_getfirst(nbcache_iter_t *iter)
917b59d02jb{
927b59d02jb	HT_ITEM *item;
937b59d02jb	struct name_entry *entry;
947b59d02jb
957b59d02jb	(void) rw_rdlock(&nb_cache_lock);
967b59d02jb	item = ht_findfirst(smb_netbios_cache, &iter->nbc_hti);
977b59d02jb	if (item == NULL || item->hi_data == NULL) {
987b59d02jb		(void) rw_unlock(&nb_cache_lock);
997b59d02jb		return (-1);
1007b59d02jb	}
1017b59d02jb
1027b59d02jb	entry = (struct name_entry *)item->hi_data;
1037b59d02jb	(void) mutex_lock(&entry->mtx);
1047b59d02jb	iter->nbc_entry = smb_netbios_name_dup(entry, 1);
1057b59d02jb	(void) mutex_unlock(&entry->mtx);
1067b59d02jb
1077b59d02jb	(void) rw_unlock(&nb_cache_lock);
1087b59d02jb
1097b59d02jb	return ((iter->nbc_entry) ? 0 : -1);
1107b59d02jb}
1117b59d02jb
1127b59d02jbint
1137b59d02jbsmb_netbios_cache_getnext(nbcache_iter_t *iter)
1147b59d02jb{
1157b59d02jb	HT_ITEM *item;
1167b59d02jb	struct name_entry *entry;
1177b59d02jb
1187b59d02jb	(void) rw_rdlock(&nb_cache_lock);
1197b59d02jb	item = ht_findnext(&iter->nbc_hti);
1207b59d02jb	if (item == NULL || item->hi_data == NULL) {
1217b59d02jb		(void) rw_unlock(&nb_cache_lock);
1227b59d02jb		return (-1);
1237b59d02jb	}
1247b59d02jb
1257b59d02jb	entry = (struct name_entry *)item->hi_data;
1267b59d02jb	(void) mutex_lock(&entry->mtx);
1277b59d02jb	iter->nbc_entry = smb_netbios_name_dup(entry, 1);
1287b59d02jb	(void) mutex_unlock(&entry->mtx);
1297b59d02jb
1307b59d02jb	(void) rw_unlock(&nb_cache_lock);
1317b59d02jb
1327b59d02jb	return ((iter->nbc_entry) ? 0 : -1);
1337b59d02jb}
1347b59d02jb
135da6c28aamw/*
136da6c28aamw * smb_netbios_cache_lookup
137da6c28aamw *
138da6c28aamw * Searches the name cache for the given entry, if found
139da6c28aamw * the entry will be locked before returning to caller
140da6c28aamw * so caller MUST unlock the entry after it's done with it.
141da6c28aamw */
142da6c28aamwstruct name_entry *
143da6c28aamwsmb_netbios_cache_lookup(struct name_entry *name)
144da6c28aamw{
145da6c28aamw	HT_ITEM *item;
146da6c28aamw	nb_key_t key;
147da6c28aamw	struct name_entry *entry = NULL;
148da6c28aamw	unsigned char hostname[MAXHOSTNAMELEN];
149da6c28aamw
150da6c28aamw	if (NETBIOS_NAME_IS_STAR(name->name)) {
151da6c28aamw		/* Return our address */
1527b59d02jb		if (smb_getnetbiosname((char *)hostname, sizeof (hostname))
1537b59d02jb		    != 0)
154da6c28aamw			return (NULL);
155da6c28aamw
1567b59d02jb		smb_encode_netbios_name(hostname, 0x00, NULL, name);
157da6c28aamw	}
158da6c28aamw
159da6c28aamw	(void) rw_rdlock(&nb_cache_lock);
160da6c28aamw
161da6c28aamw	smb_netbios_cache_key(key, name->name, name->scope);
162da6c28aamw	item = ht_find_item(smb_netbios_cache, key);
163da6c28aamw	if (item) {
164da6c28aamw		entry = (struct name_entry *)item->hi_data;
165da6c28aamw		(void) mutex_lock(&entry->mtx);
166da6c28aamw		if ((entry->attributes & NAME_ATTR_CONFLICT) != 0) {
167da6c28aamw			(void) mutex_unlock(&entry->mtx);
168da6c28aamw			entry = NULL;
169da6c28aamw		}
170da6c28aamw	}
171da6c28aamw
172da6c28aamw	(void) rw_unlock(&nb_cache_lock);
173da6c28aamw	return (entry);
174da6c28aamw}
175da6c28aamw
176da6c28aamwvoid
177da6c28aamwsmb_netbios_cache_unlock_entry(struct name_entry *name)
178da6c28aamw{
179da6c28aamw	if (name)
180da6c28aamw		(void) mutex_unlock(&name->mtx);
181da6c28aamw}
182da6c28aamw
183da6c28aamw/*
184da6c28aamw * smb_netbios_cache_lookup_addr
185da6c28aamw *
186da6c28aamw * lookup the given 'name' in the cache and then checks
187da6c28aamw * if the address also matches with the found entry.
188da6c28aamw * 'name' is supposed to contain only one address.
189da6c28aamw *
190da6c28aamw * The found entry will be locked before returning to caller
191da6c28aamw * so caller MUST unlock the entry after it's done with it.
192da6c28aamw */
193da6c28aamwstruct name_entry *
194da6c28aamwsmb_netbios_cache_lookup_addr(struct name_entry *name)
195da6c28aamw{
196da6c28aamw	struct name_entry *entry = 0;
197a0aa776Alan Wright	addr_entry_t *addr;
198a0aa776Alan Wright	addr_entry_t *name_addr;
199da6c28aamw	HT_ITEM *item;
200da6c28aamw	nb_key_t key;
201da6c28aamw
202da6c28aamw	(void) rw_rdlock(&nb_cache_lock);
203da6c28aamw	smb_netbios_cache_key(key, name->name, name->scope);
204