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