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 /*
22a0aa776eSAlan 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
46a0aa776eSAlan 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
smb_netbios_cache_init(void)53a0aa776eSAlan Wright smb_netbios_cache_init(void)
54da6c28aaSamw {
55da6c28aaSamw (void) rw_wrlock(&nb_cache_lock);
56a0aa776eSAlan Wright if (smb_netbios_cache == NULL) {
57da6c28aaSamw smb_netbios_cache = ht_create_table(NETBIOS_HTAB_SZ,
58da6c28aaSamw NETBIOS_HKEY_SZ, HTHF_FIXED_KEY);
59a0aa776eSAlan Wright if (smb_netbios_cache == NULL) {
60a0aa776eSAlan Wright syslog(LOG_ERR, "nbns: cannot create name cache");
61da6c28aaSamw (void) rw_unlock(&nb_cache_lock);
62a0aa776eSAlan 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
69a0aa776eSAlan Wright return (0);
70da6c28aaSamw }
71da6c28aaSamw
72da6c28aaSamw void
smb_netbios_cache_fini(void)737b59d02dSjb150015 smb_netbios_cache_fini(void)
74da6c28aaSamw {
75da6c28aaSamw (void) rw_wrlock(&nb_cache_lock);
76da6c28aaSamw ht_destroy_table(smb_netbios_cache);
77a0aa776eSAlan Wright smb_netbios_cache = NULL;
78da6c28aaSamw (void) rw_unlock(&nb_cache_lock);
79da6c28aaSamw }
80da6c28aaSamw
81da6c28aaSamw void
smb_netbios_cache_clean(void)827b59d02dSjb150015 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
897b59d02dSjb150015 int
smb_netbios_cache_getfirst(nbcache_iter_t * iter)907b59d02dSjb150015 smb_netbios_cache_getfirst(nbcache_iter_t *iter)
917b59d02dSjb150015 {
927b59d02dSjb150015 HT_ITEM *item;
937b59d02dSjb150015 struct name_entry *entry;
947b59d02dSjb150015
957b59d02dSjb150015 (void) rw_rdlock(&nb_cache_lock);
967b59d02dSjb150015 item = ht_findfirst(smb_netbios_cache, &iter->nbc_hti);
977b59d02dSjb150015 if (item == NULL || item->hi_data == NULL) {
987b59d02dSjb150015 (void) rw_unlock(&nb_cache_lock);
997b59d02dSjb150015 return (-1);
1007b59d02dSjb150015 }
1017b59d02dSjb150015
1027b59d02dSjb150015 entry = (struct name_entry *)item->hi_data;
1037b59d02dSjb150015 (void) mutex_lock(&entry->mtx);
1047b59d02dSjb150015 iter->nbc_entry = smb_netbios_name_dup(entry, 1);
1057b59d02dSjb150015 (void) mutex_unlock(&entry->mtx);
1067b59d02dSjb150015
1077b59d02dSjb150015 (void) rw_unlock(&nb_cache_lock);
1087b59d02dSjb150015
1097b59d02dSjb150015 return ((iter->nbc_entry) ? 0 : -1);
1107b59d02dSjb150015 }
1117b59d02dSjb150015
1127b59d02dSjb150015 int
smb_netbios_cache_getnext(nbcache_iter_t * iter)1137b59d02dSjb150015 smb_netbios_cache_getnext(nbcache_iter_t *iter)
1147b59d02dSjb150015 {
1157b59d02dSjb150015 HT_ITEM *item;
1167b59d02dSjb150015 struct name_entry *entry;
1177b59d02dSjb150015
1187b59d02dSjb150015 (void) rw_rdlock(&nb_cache_lock);
1197b59d02dSjb150015 item = ht_findnext(&iter->nbc_hti);
1207b59d02dSjb150015 if (item == NULL || item->hi_data == NULL) {
1217b59d02dSjb150015 (void) rw_unlock(&nb_cache_lock);
1227b59d02dSjb150015 return (-1);
1237b59d02dSjb150015 }
1247b59d02dSjb150015
1257b59d02dSjb150015 entry = (struct name_entry *)item->hi_data;
1267b59d02dSjb150015 (void) mutex_lock(&entry->mtx);
1277b59d02dSjb150015 iter->nbc_entry = smb_netbios_name_dup(entry, 1);
1287b59d02dSjb150015 (void) mutex_unlock(&entry->mtx);
1297b59d02dSjb150015
1307b59d02dSjb150015 (void) rw_unlock(&nb_cache_lock);
1317b59d02dSjb150015
1327b59d02dSjb150015 return ((iter->nbc_entry) ? 0 : -1);
1337b59d02dSjb150015 }
1347b59d02dSjb150015
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 *
smb_netbios_cache_lookup(struct name_entry * name)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 */
1527b59d02dSjb150015 if (smb_getnetbiosname((char *)hostname, sizeof (hostname))
1537b59d02dSjb150015 != 0)
154da6c28aaSamw return (NULL);
155da6c28aaSamw
1567b59d02dSjb150015 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
smb_netbios_cache_unlock_entry(struct name_entry * name)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 *
smb_netbios_cache_lookup_addr(struct name_entry * name)194da6c28aaSamw smb_netbios_cache_lookup_addr(struct name_entry *name)
195da6c28aaSamw {
196da6c28aaSamw struct name_entry *entry = 0;
197a0aa776eSAlan Wright addr_entry_t *addr;
198a0aa776eSAlan 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
smb_netbios_cache_insert(struct name_entry * name)227da6c28aaSamw smb_netbios_cache_insert(struct name_entry *name)
228da6c28aaSamw {
229da6c28aaSamw struct name_entry *entry;
230a0aa776eSAlan Wright addr_entry_t *addr;
231a0aa776eSAlan Wright addr_entry_t *name_addr;
232da6c28aaSamw HT_ITEM *item;
233da6c28aaSamw nb_key_t key;
2347b59d02dSjb150015 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);
2577b59d02dSjb150015 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);
267da6c28aaSamw return (0);
268da6c28aaSamw }
2697b59d02dSjb150015 }
270da6c28aaSamw
271a0aa776eSAlan Wright if ((addr = malloc(sizeof (addr_entry_t))) != NULL) {
2727b59d02dSjb150015 *addr = name->addr_list;
2737b59d02dSjb150015 entry->attributes |= addr->attributes;
2747b59d02dSjb150015 QUEUE_INSERT_TAIL(&entry->addr_list, addr);
2757b59d02dSjb150015 rc = 0;
2767b59d02dSjb150015 } else {
2777b59d02dSjb150015 rc = -1;
2787b59d02dSjb150015 }
2797b59d02dSjb150015
2807b59d02dSjb150015 (void) mutex_unlock(&entry->mtx);
2817b59d02dSjb150015 (void) rw_unlock(&nb_cache_lock);
2827b59d02dSjb150015 return (rc);
2837b59d02dSjb150015 }
2847b59d02dSjb150015
2857b59d02dSjb150015 if ((entry = malloc(sizeof (struct name_entry))) == NULL) {
286da6c28aaSamw (void) rw_unlock(&nb_cache_lock);
287da6c28aaSamw return (-1);
288da6c28aaSamw }
2897b59d02dSjb150015
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
smb_netbios_cache_delete(struct name_entry * name)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
smb_netbios_cache_insert_list(struct name_entry * name)330da6c28aaSamw smb_netbios_cache_insert_list(struct name_entry *name)
331da6c28aaSamw {
332da6c28aaSamw struct name_entry entry;
333a0aa776eSAlan 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
smb_netbios_cache_update_entry(struct name_entry * entry,struct name_entry * name)354da6c28aaSamw smb_netbios_cache_update_entry(struct name_entry *entry,
355da6c28aaSamw struct name_entry *name)
356da6c28aaSamw {
357a0aa776eSAlan Wright addr_entry_t *addr;
358a0aa776eSAlan 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 *
smb_netbios_cache_status(unsigned char * buf,int bufsize,unsigned char * scope)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;
423dc41c81fSRichard Lowe *scan++ = (PUBLIC_BITS(name->attributes) >> 8) & 0xff;
424dc41c81fSRichard Lowe *scan++ = PUBLIC_BITS(name->attributes) & 0xff;
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
smb_netbios_cache_reset_ttl()436da6c28aaSamw smb_netbios_cache_reset_ttl()
437da6c28aaSamw {
438a0aa776eSAlan 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
smb_netbios_cache_insrefq(name_queue_t * refq,HT_ITEM * item)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);
487*8421bc58SToomas Soome if (refent) {
488da6c28aaSamw QUEUE_INSERT_TAIL(&refq->head, refent)
489*8421bc58SToomas Soome }
490da6c28aaSamw
491da6c28aaSamw /* next name */
492da6c28aaSamw return (B_TRUE);
493da6c28aaSamw }
494da6c28aaSamw } else {
495da6c28aaSamw ht_mark_delete(smb_netbios_cache, item);
496da6c28aaSamw refent = smb_netbios_name_dup(name, 0);
497*8421bc58SToomas Soome if (refent) {
498da6c28aaSamw QUEUE_INSERT_TAIL(&refq->head, refent)
499*8421bc58SToomas Soome }
500da6c28aaSamw
501da6c28aaSamw /* next name */
502da6c28aaSamw return (B_TRUE);
503da6c28aaSamw }
504da6c28aaSamw
505da6c28aaSamw return (B_FALSE);
506da6c28aaSamw }
507da6c28aaSamw
508da6c28aaSamw /*
509da6c28aaSamw * smb_netbios_cache_refresh
510da6c28aaSamw *
511da6c28aaSamw * Scans the name cache and add all local unique names
512da6c28aaSamw * and non-local names the passed refresh queue. Non-
513da6c28aaSamw * local names will also be marked as deleted.
514da6c28aaSamw *
515da6c28aaSamw * NOTE that the caller MUST protect the queue using
516da6c28aaSamw * its mutex
517da6c28aaSamw */
518da6c28aaSamw void
smb_netbios_cache_refresh(name_queue_t * refq)519da6c28aaSamw smb_netbios_cache_refresh(name_queue_t *refq)
520da6c28aaSamw {
521da6c28aaSamw struct name_entry *name;
522a0aa776eSAlan Wright addr_entry_t *addr;
523da6c28aaSamw HT_ITERATOR hti;
524da6c28aaSamw HT_ITEM *item;
525da6c28aaSamw
526da6c28aaSamw bzero(&refq->head, sizeof (refq->head));
527da6c28aaSamw refq->head.forw = refq->head.back = &refq->head;
528da6c28aaSamw
529da6c28aaSamw (void) rw_rdlock(&nb_cache_lock);
530da6c28aaSamw item = ht_findfirst(smb_netbios_cache, &hti);
531da6c28aaSamw do { /* name loop */
532da6c28aaSamw if (item == 0)
533da6c28aaSamw break;
534da6c28aaSamw
535da6c28aaSamw if (item->hi_data == 0)
536da6c28aaSamw continue;
537da6c28aaSamw
538da6c28aaSamw name = (struct name_entry *)item->hi_data;
539da6c28aaSamw (void) mutex_lock(&name->mtx);
540da6c28aaSamw
541da6c28aaSamw addr = &name->addr_list;
542da6c28aaSamw do { /* address loop */
543da6c28aaSamw if (addr->ttl > 0) {
544da6c28aaSamw addr->ttl--;
545da6c28aaSamw if (addr->ttl == 0) {
546da6c28aaSamw if (smb_netbios_cache_insrefq(refq,
547da6c28aaSamw item))
548da6c28aaSamw break;
549da6c28aaSamw }
550da6c28aaSamw }
551da6c28aaSamw addr = addr->forw;
552da6c28aaSamw } while (addr != &name->addr_list);
553da6c28aaSamw
554da6c28aaSamw (void) mutex_unlock(&name->mtx);
555da6c28aaSamw } while ((item = ht_findnext(&hti)) != 0);
556da6c28aaSamw (void) rw_unlock(&nb_cache_lock);
557da6c28aaSamw }
558da6c28aaSamw
559da6c28aaSamw /*
560da6c28aaSamw * smb_netbios_cache_delete_locals
561da6c28aaSamw *
562da6c28aaSamw * Scans the name cache and add all local names to
563da6c28aaSamw * the passed delete queue.
564da6c28aaSamw *
565da6c28aaSamw * NOTE that the caller MUST protect the queue using
566da6c28aaSamw * its mutex
567da6c28aaSamw */
568da6c28aaSamw void
smb_netbios_cache_delete_locals(name_queue_t * delq)569da6c28aaSamw smb_netbios_cache_delete_locals(name_queue_t *delq)
570da6c28aaSamw {
571da6c28aaSamw struct name_entry *entry;
572da6c28aaSamw struct name_entry *delent;
573da6c28aaSamw HT_ITERATOR hti;
574da6c28aaSamw HT_ITEM *item;
575da6c28aaSamw
576da6c28aaSamw bzero(&delq->head, sizeof (delq->head));
577da6c28aaSamw delq->head.forw = delq->head.back = &delq->head;
578da6c28aaSamw
579da6c28aaSamw (void) rw_wrlock(&nb_cache_lock);
580da6c28aaSamw item = ht_findfirst(smb_netbios_cache, &hti);
581da6c28aaSamw do {
582da6c28aaSamw if (item == 0)
583da6c28aaSamw break;
584da6c28aaSamw
585da6c28aaSamw if (item->hi_data == 0)
586da6c28aaSamw continue;
587da6c28aaSamw
588da6c28aaSamw entry = (struct name_entry *)item->hi_data;
589da6c28aaSamw (void) mutex_lock(&entry->mtx);
590da6c28aaSamw
591da6c28aaSamw if (IS_LOCAL(entry->attributes)) {
592da6c28aaSamw ht_mark_delete(smb_netbios_cache, item);
593da6c28aaSamw delent = smb_netbios_name_dup(entry, 1);
594*8421bc58SToomas Soome if (delent) {
595da6c28aaSamw QUEUE_INSERT_TAIL(&delq->head, delent)
596da6c28aaSamw }
597*8421bc58SToomas Soome }
598da6c28aaSamw
599da6c28aaSamw (void) mutex_unlock(&entry->mtx);
600da6c28aaSamw } while ((item = ht_findnext(&hti)) != 0);
601da6c28aaSamw (void) rw_unlock(&nb_cache_lock);
602da6c28aaSamw }
603da6c28aaSamw
604da6c28aaSamw void
smb_netbios_name_freeaddrs(struct name_entry * entry)605da6c28aaSamw smb_netbios_name_freeaddrs(struct name_entry *entry)
606da6c28aaSamw {
607a0aa776eSAlan Wright addr_entry_t *addr;
608da6c28aaSamw
609da6c28aaSamw if (entry == 0)
610da6c28aaSamw return;
611da6c28aaSamw
612da6c28aaSamw while ((addr = entry->addr_list.forw) != &entry->addr_list) {
613da6c28aaSamw QUEUE_CLIP(addr);
614da6c28aaSamw free(addr);
615da6c28aaSamw }
616da6c28aaSamw }
617da6c28aaSamw
618da6c28aaSamw /*
619da6c28aaSamw * smb_netbios_cache_count
620da6c28aaSamw *
621da6c28aaSamw * Returns the number of names in the cache
622da6c28aaSamw */
623da6c28aaSamw int
smb_netbios_cache_count()624da6c28aaSamw smb_netbios_cache_count()
625da6c28aaSamw {
626da6c28aaSamw int cnt;
627da6c28aaSamw
628da6c28aaSamw (void) rw_rdlock(&nb_cache_lock);
629da6c28aaSamw cnt = ht_get_total_items(smb_netbios_cache);
630da6c28aaSamw (void) rw_unlock(&nb_cache_lock);
631da6c28aaSamw
632da6c28aaSamw return (cnt);
633da6c28aaSamw }
634da6c28aaSamw
635da6c28aaSamw void
smb_netbios_cache_dump(FILE * fp)636a0aa776eSAlan Wright smb_netbios_cache_dump(FILE *fp)
637da6c28aaSamw {
638da6c28aaSamw struct name_entry *name;
639da6c28aaSamw HT_ITERATOR hti;
640da6c28aaSamw HT_ITEM *item;
641da6c28aaSamw
642da6c28aaSamw (void) rw_rdlock(&nb_cache_lock);
643a0aa776eSAlan Wright
644a0aa776eSAlan Wright if (ht_get_total_items(smb_netbios_cache) != 0) {
645a0aa776eSAlan Wright (void) fprintf(fp, "\n%-22s %-16s %-16s %s\n",
646a0aa776eSAlan Wright "Name", "Type", "Address", "TTL");
647a0aa776eSAlan Wright (void) fprintf(fp, "%s%s\n",
648a0aa776eSAlan Wright "-------------------------------",
649a0aa776eSAlan Wright "------------------------------");
650a0aa776eSAlan Wright }
651a0aa776eSAlan Wright
652da6c28aaSamw item = ht_findfirst(smb_netbios_cache, &hti);
653da6c28aaSamw while (item) {
654da6c28aaSamw if (item->hi_data) {
655da6c28aaSamw name = (struct name_entry *)item->hi_data;
656da6c28aaSamw (void) mutex_lock(&name->mtx);
657a0aa776eSAlan Wright smb_netbios_name_dump(fp, name);
658da6c28aaSamw (void) mutex_unlock(&name->mtx);
659da6c28aaSamw }
660da6c28aaSamw item = ht_findnext(&hti);
661da6c28aaSamw }
662da6c28aaSamw (void) rw_unlock(&nb_cache_lock);
663da6c28aaSamw }
664da6c28aaSamw
665da6c28aaSamw void
smb_netbios_name_dump(FILE * fp,struct name_entry * entry)666a0aa776eSAlan Wright smb_netbios_name_dump(FILE *fp, struct name_entry *entry)
667da6c28aaSamw {
668a0aa776eSAlan Wright char buf[MAXHOSTNAMELEN];
669a0aa776eSAlan Wright addr_entry_t *addr;
670a0aa776eSAlan Wright char *type;
671da6c28aaSamw int count = 0;
672da6c28aaSamw
673a0aa776eSAlan Wright smb_strname(entry, buf, sizeof (buf));
674a0aa776eSAlan Wright type = (IS_UNIQUE(entry->attributes)) ? "UNIQUE" : "GROUP";
675da6c28aaSamw
676a0aa776eSAlan Wright (void) fprintf(fp, "%s %-6s (0x%04x) ", buf, type, entry->attributes);
677a0aa776eSAlan Wright
678da6c28aaSamw addr = &entry->addr_list;
679da6c28aaSamw do {
680a0aa776eSAlan Wright if (count == 0)
681a0aa776eSAlan Wright (void) fprintf(fp, "%-16s %d\n",
682a0aa776eSAlan Wright inet_ntoa(addr->sin.sin_addr), addr->ttl);
683a0aa776eSAlan Wright else
684a0aa776eSAlan Wright (void) fprintf(fp, "%-28s (0x%04x) %-16s %d\n",
685a0aa776eSAlan Wright " ", addr->attributes,
686a0aa776eSAlan Wright inet_ntoa(addr->sin.sin_addr), addr->ttl);
687a0aa776eSAlan Wright ++count;
688da6c28aaSamw addr = addr->forw;
689da6c28aaSamw } while (addr != &entry->addr_list);
690da6c28aaSamw }
691da6c28aaSamw
692da6c28aaSamw void
smb_netbios_name_logf(struct name_entry * entry)693da6c28aaSamw smb_netbios_name_logf(struct name_entry *entry)
694da6c28aaSamw {
695a0aa776eSAlan Wright char namebuf[MAXHOSTNAMELEN];
696a0aa776eSAlan Wright addr_entry_t *addr;
697da6c28aaSamw
698a0aa776eSAlan Wright smb_strname(entry, namebuf, sizeof (namebuf));
699da6c28aaSamw syslog(LOG_DEBUG, "%s flags=0x%x\n", namebuf, entry->attributes);
700da6c28aaSamw addr = &entry->addr_list;
701da6c28aaSamw do {
702a0aa776eSAlan Wright syslog(LOG_DEBUG, " %s ttl=%d flags=0x%x port=%d",
703da6c28aaSamw inet_ntoa(addr->sin.sin_addr),
704a0aa776eSAlan Wright addr->ttl, addr->attributes,
705a0aa776eSAlan Wright addr->sin.sin_port);
706da6c28aaSamw addr = addr->forw;
707da6c28aaSamw } while (addr && (addr != &entry->addr_list));
708da6c28aaSamw }
709da6c28aaSamw
710da6c28aaSamw /*
711da6c28aaSamw * smb_netbios_name_dup
712da6c28aaSamw *
713da6c28aaSamw * Duplicate the given name entry. If 'alladdr' is 0 only
714da6c28aaSamw * copy the primary address otherwise duplicate all the
715da6c28aaSamw * addresses. NOTE that the duplicate structure is not
716da6c28aaSamw * like a regular cache entry i.e. it's a contiguous block
717da6c28aaSamw * of memory and each addr structure doesn't have it's own
718da6c28aaSamw * allocated memory. So, the returned structure can be freed
719da6c28aaSamw * by one free call.
720da6c28aaSamw */
721da6c28aaSamw struct name_entry *
smb_netbios_name_dup(struct name_entry * entry,int alladdr)722da6c28aaSamw smb_netbios_name_dup(struct name_entry *entry, int alladdr)
723da6c28aaSamw {
724a0aa776eSAlan Wright addr_entry_t *addr;
725a0aa776eSAlan Wright addr_entry_t *dup_addr;
726da6c28aaSamw struct name_entry *dup;
727da6c28aaSamw int addr_cnt = 0;
728da6c28aaSamw int size = 0;
729da6c28aaSamw
730da6c28aaSamw if (alladdr) {
731da6c28aaSamw addr = entry->addr_list.forw;
732da6c28aaSamw while (addr && (addr != &entry->addr_list)) {
733da6c28aaSamw addr_cnt++;
734da6c28aaSamw addr = addr->forw;
735da6c28aaSamw }
736da6c28aaSamw }
737da6c28aaSamw
738da6c28aaSamw size = sizeof (struct name_entry) +
739a0aa776eSAlan Wright (addr_cnt * sizeof (addr_entry_t));
740da6c28aaSamw dup = (struct name_entry *)malloc(size);
741da6c28aaSamw if (dup == 0)
742da6c28aaSamw return (0);
743da6c28aaSamw
744da6c28aaSamw bzero(dup, size);
745da6c28aaSamw
746da6c28aaSamw dup->forw = dup->back = dup;
747da6c28aaSamw dup->attributes = entry->attributes;
748da6c28aaSamw (void) memcpy(dup->name, entry->name, NETBIOS_NAME_SZ);
749da6c28aaSamw (void) strlcpy((char *)dup->scope, (char *)entry->scope,
750da6c28aaSamw NETBIOS_DOMAIN_NAME_MAX);
751da6c28aaSamw dup->addr_list = entry->addr_list;
752da6c28aaSamw dup->addr_list.forw = dup->addr_list.back = &dup->addr_list;
753da6c28aaSamw
754da6c28aaSamw if (alladdr == 0)
755da6c28aaSamw return (dup);
756da6c28aaSamw
757da6c28aaSamw /* LINTED - E_BAD_PTR_CAST_ALIGN */
758a0aa776eSAlan Wright dup_addr = (addr_entry_t *)((unsigned char *)dup +
759da6c28aaSamw sizeof (struct name_entry));
760da6c28aaSamw
761da6c28aaSamw addr = entry->addr_list.forw;
762da6c28aaSamw while (addr && (addr != &entry->addr_list)) {
763da6c28aaSamw *dup_addr = *addr;
764da6c28aaSamw QUEUE_INSERT_TAIL(&dup->addr_list, dup_addr);
765da6c28aaSamw addr = addr->forw;
766da6c28aaSamw dup_addr++;
767da6c28aaSamw }
768da6c28aaSamw
769da6c28aaSamw return (dup);
770da6c28aaSamw }
771da6c28aaSamw
772a0aa776eSAlan Wright static void
smb_strname(struct name_entry * entry,char * buf,int bufsize)773a0aa776eSAlan Wright smb_strname(struct name_entry *entry, char *buf, int bufsize)
774da6c28aaSamw {
775a0aa776eSAlan Wright char tmp[MAXHOSTNAMELEN];
776da6c28aaSamw char *p;
777da6c28aaSamw
778a0aa776eSAlan Wright (void) snprintf(tmp, MAXHOSTNAMELEN, "%15.15s", entry->name);
779a0aa776eSAlan Wright if ((p = strchr(tmp, ' ')) != NULL)
780a0aa776eSAlan Wright *p = '\0';
781da6c28aaSamw
782a0aa776eSAlan Wright if (entry->scope[0] != '\0') {
783a0aa776eSAlan Wright (void) strlcat(tmp, ".", MAXHOSTNAMELEN);
784a0aa776eSAlan Wright (void) strlcat(tmp, (char *)entry->scope, MAXHOSTNAMELEN);
785a0aa776eSAlan Wright }
786a0aa776eSAlan Wright
787a0aa776eSAlan Wright (void) snprintf(buf, bufsize, "%-16s <%02X>", tmp, entry->name[15]);
788da6c28aaSamw }
789da6c28aaSamw
790da6c28aaSamw static void
hash_callback(HT_ITEM * item)791da6c28aaSamw hash_callback(HT_ITEM *item)
792da6c28aaSamw {
793da6c28aaSamw struct name_entry *entry;
794da6c28aaSamw
795da6c28aaSamw if (item && item->hi_data) {
796da6c28aaSamw entry = (struct name_entry *)item->hi_data;
797da6c28aaSamw smb_netbios_name_freeaddrs(entry);
798da6c28aaSamw free(entry);
799da6c28aaSamw }
800da6c28aaSamw }
801da6c28aaSamw
802da6c28aaSamw
803da6c28aaSamw /*ARGSUSED*/
804da6c28aaSamw static int
smb_netbios_match(const char * key1,const char * key2,size_t n)805da6c28aaSamw smb_netbios_match(const char *key1, const char *key2, size_t n)
806da6c28aaSamw {
807da6c28aaSamw int res;
808da6c28aaSamw
809da6c28aaSamw res = bcmp(key1, key2, NETBIOS_NAME_SZ);
810da6c28aaSamw if (res == 0) {
811da6c28aaSamw /* Names are the same, compare scopes */
812da6c28aaSamw res = strcmp(key1 + NETBIOS_NAME_SZ, key2 + NETBIOS_NAME_SZ);
813da6c28aaSamw }
814da6c28aaSamw
815da6c28aaSamw return (res);
816da6c28aaSamw }
817da6c28aaSamw
818da6c28aaSamw static void
smb_netbios_cache_key(char * key,unsigned char * name,unsigned char * scope)819da6c28aaSamw smb_netbios_cache_key(char *key, unsigned char *name, unsigned char *scope)
820da6c28aaSamw {
821da6c28aaSamw bzero(key, NETBIOS_HKEY_SZ);
822da6c28aaSamw (void) memcpy(key, name, NETBIOS_NAME_SZ);
823da6c28aaSamw (void) memcpy(key + NETBIOS_NAME_SZ, scope,
824da6c28aaSamw strlen((const char *)scope));
825da6c28aaSamw }
826