xref: /onnv-gate/usr/src/lib/smbsrv/libsmbns/common/smbns_netbios_name.c (revision 11963:061945695ce1)
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*11963SAfshin.Ardakani@Sun.COM  * Copyright 2010 Sun Microsystems, Inc.  All rights reserved.
235331Samw  * Use is subject to license terms.
245331Samw  */
255331Samw 
265331Samw /*
2710717Samw@Sun.COM  * NetBIOS name resolution node types.
285331Samw  *
2910717Samw@Sun.COM  * A B-node (broadcast node) uses broadcasts for name registration
3010717Samw@Sun.COM  * and resolution.  Routers typically do not forward broadcasts and
3110717Samw@Sun.COM  * only computers on the local subnet will respond.
325331Samw  *
3310717Samw@Sun.COM  * A P-node (peer-to-peer node) uses a NetBIOS name server (WINS)
3410717Samw@Sun.COM  * to resolve NetBIOS names, which allows it to work across routers.
3510717Samw@Sun.COM  * In order to function in a P-node environment, all computers must
3610717Samw@Sun.COM  * be configured to use the NetBIOS name server because P-nodes do
3710717Samw@Sun.COM  * not broadcast on the network.
385331Samw  *
3910717Samw@Sun.COM  * A mixed node (M-node) behaves as a B-node by default.  If it cannot
4010717Samw@Sun.COM  * resolve the name via broadcast then it tries a NetBIOS name server
4110717Samw@Sun.COM  * lookup (P-node).
425331Samw  *
4310717Samw@Sun.COM  * A hybrid node (H-node) behaves as a P-node by default.  If it cannot
4410717Samw@Sun.COM  * resolve the name using a NetBIOS name server then it resorts to
4510717Samw@Sun.COM  * broadcasts (B-node).
465331Samw  *
4710717Samw@Sun.COM  * NetBIOS Name Service Protocols
485331Samw  *
4910717Samw@Sun.COM  * A REQUEST packet is always sent to the well known UDP port 137.
5010717Samw@Sun.COM  * The destination address is normally either the IP broadcast address or
5110717Samw@Sun.COM  * the address of the NAME - the address of the NAME server it set up at
5210717Samw@Sun.COM  * initialization time.  In rare cases, a request packet will be sent to
5310717Samw@Sun.COM  * an end node, e.g.  a NAME QUERY REQUEST sent to "challenge" a node.
545331Samw  *
5510717Samw@Sun.COM  * A RESPONSE packet is always sent to the source UDP port and source IP
5610717Samw@Sun.COM  * address of the request packet.
575331Samw  *
5810717Samw@Sun.COM  * A DEMAND packet must always be sent to the well known UDP port 137.
5910717Samw@Sun.COM  * There is no restriction on the target IP address.
605331Samw  *
6110717Samw@Sun.COM  * A transaction ID is a value composed from the requestor's IP address and
6210717Samw@Sun.COM  * a unique 16 bit value generated by the originator of the transaction.
635331Samw  */
645331Samw 
655331Samw #include <unistd.h>
665331Samw #include <syslog.h>
675331Samw #include <stdlib.h>
685331Samw #include <synch.h>
695331Samw #include <errno.h>
705331Samw #include <netdb.h>
715331Samw #include <sys/socket.h>
725331Samw #include <sys/sockio.h>
735331Samw #include <arpa/inet.h>
745331Samw #include <net/if_arp.h>
755331Samw 
765331Samw #include <smbsrv/libsmbns.h>
775331Samw #include <smbns_netbios.h>
785331Samw 
7910717Samw@Sun.COM /*
8010717Samw@Sun.COM  * RFC 1002 4.2.1.1.  HEADER
8110717Samw@Sun.COM  */
8210717Samw@Sun.COM #define	QUESTION_TYPE_NETBIOS_GENERAL	0x20
8310717Samw@Sun.COM #define	QUESTION_TYPE_NETBIOS_STATUS	0x21
8410717Samw@Sun.COM 
8510717Samw@Sun.COM #define	QUESTION_CLASS_INTERNET		0x0001
8610717Samw@Sun.COM 
8710717Samw@Sun.COM /*
8810717Samw@Sun.COM  * RFC 1002 4.2.1.3.  RESOURCE RECORD
8910717Samw@Sun.COM  */
9010717Samw@Sun.COM #define	RR_TYPE_IP_ADDRESS_RESOURCE	0x0001
9110717Samw@Sun.COM #define	RR_TYPE_NAME_SERVER_RESOURCE	0x0002
9210717Samw@Sun.COM #define	RR_TYPE_NULL_RESOURCE		0x000A
9310717Samw@Sun.COM #define	RR_TYPE_NETBIOS_RESOURCE	0x0020
9410717Samw@Sun.COM #define	RR_TYPE_NETBIOS_STATUS		0x0021
9510717Samw@Sun.COM 
9610717Samw@Sun.COM /*
9710717Samw@Sun.COM  *
9810717Samw@Sun.COM  * RESOURCE RECORD RR_CLASS field definitions
9910717Samw@Sun.COM  */
10010717Samw@Sun.COM #define	RR_CLASS_INTERNET_CLASS		0x0001
1015331Samw 
10210717Samw@Sun.COM /*
10310717Samw@Sun.COM  * NB_FLAGS field of the RESOURCE RECORD RDATA field for RR_TYPE of NB.
10410717Samw@Sun.COM  */
10510717Samw@Sun.COM #define	RR_FLAGS_NB_ONT_MASK		0x6000
10610717Samw@Sun.COM #define	RR_FLAGS_NB_ONT_B_NODE		0x0000
10710717Samw@Sun.COM #define	RR_FLAGS_NB_ONT_P_NODE		0x2000
10810717Samw@Sun.COM #define	RR_FLAGS_NB_ONT_M_NODE		0x4000
10910717Samw@Sun.COM #define	RR_FLAGS_NB_ONT_RESERVED	0x6000
11010717Samw@Sun.COM #define	RR_FLAGS_NB_GROUP_NAME		0x8000
1115331Samw 
11210717Samw@Sun.COM #define	NAME_FLAGS_PERMANENT_NAME	0x0200
11310717Samw@Sun.COM #define	NAME_FLAGS_ACTIVE_NAME		0x0400
11410717Samw@Sun.COM #define	NAME_FLAGS_CONFLICT		0x0800
11510717Samw@Sun.COM #define	NAME_FLAGS_DEREGISTER		0x1000
11610717Samw@Sun.COM #define	NAME_FLAGS_ONT_MASK		0x6000
11710717Samw@Sun.COM #define	NAME_FLAGS_ONT_B_NODE		0x0000
11810717Samw@Sun.COM #define	NAME_FLAGS_ONT_P_NODE		0x2000
11910717Samw@Sun.COM #define	NAME_FLAGS_ONT_M_NODE		0x4000
12010717Samw@Sun.COM #define	NAME_FLAGS_ONT_RESERVED		0x6000
12110717Samw@Sun.COM #define	NAME_FLAGS_GROUP_NAME		0x8000
12210717Samw@Sun.COM 
12310717Samw@Sun.COM #define	MAX_NETBIOS_REPLY_DATA_SIZE	500
12410717Samw@Sun.COM 
12510717Samw@Sun.COM #define	NAME_HEADER_SIZE		12
1265331Samw 
12710717Samw@Sun.COM typedef struct nbt_name_reply {
12810717Samw@Sun.COM 	struct nbt_name_reply	*forw;
12910717Samw@Sun.COM 	struct nbt_name_reply	*back;
13010717Samw@Sun.COM 	struct name_packet	*packet;
13110717Samw@Sun.COM 	addr_entry_t		*addr;
13210717Samw@Sun.COM 	uint16_t		name_trn_id;
13310717Samw@Sun.COM 	boolean_t		reply_ready;
13410717Samw@Sun.COM } nbt_name_reply_t;
13510717Samw@Sun.COM 
13610717Samw@Sun.COM static nbt_name_reply_t reply_queue;
13710717Samw@Sun.COM static mutex_t rq_mtx;
13810717Samw@Sun.COM static cond_t rq_cv;
13910717Samw@Sun.COM 
14010717Samw@Sun.COM static mutex_t nbt_name_config_mtx;
1415331Samw 
1425331Samw static name_queue_t delete_queue;
1435331Samw static name_queue_t refresh_queue;
1445331Samw 
1455331Samw static int name_sock = 0;
1465331Samw 
1475331Samw static int bcast_num = 0;
1485331Samw static int nbns_num = 0;
14910717Samw@Sun.COM static addr_entry_t smb_bcast_list[SMB_PI_MAX_NETWORKS];
15010717Samw@Sun.COM static addr_entry_t smb_nbns[SMB_PI_MAX_WINS];
1515331Samw 
15210717Samw@Sun.COM static int smb_netbios_process_response(uint16_t, addr_entry_t *,
1535331Samw     struct name_packet *, uint32_t);
1545331Samw 
15510717Samw@Sun.COM static int smb_send_name_service_packet(addr_entry_t *addr,
1565331Samw     struct name_packet *packet);
1575331Samw 
15810717Samw@Sun.COM /*
15910717Samw@Sun.COM  * Allocate a transaction id.
16010717Samw@Sun.COM  */
16110717Samw@Sun.COM static uint16_t
smb_netbios_name_trn_id(void)16210717Samw@Sun.COM smb_netbios_name_trn_id(void)
16310717Samw@Sun.COM {
16410717Samw@Sun.COM 	static uint16_t trn_id;
16510717Samw@Sun.COM 	static mutex_t trn_id_mtx;
16610717Samw@Sun.COM 
16710717Samw@Sun.COM 	(void) mutex_lock(&trn_id_mtx);
16810717Samw@Sun.COM 
16910717Samw@Sun.COM 	do {
17010717Samw@Sun.COM 		++trn_id;
17110717Samw@Sun.COM 	} while (trn_id == 0 || trn_id == (uint16_t)-1);
17210717Samw@Sun.COM 
17310717Samw@Sun.COM 	(void) mutex_unlock(&trn_id_mtx);
17410717Samw@Sun.COM 	return (trn_id);
17510717Samw@Sun.COM }
17610717Samw@Sun.COM 
1775331Samw static int
smb_end_node_challenge(nbt_name_reply_t * reply_info)17810717Samw@Sun.COM smb_end_node_challenge(nbt_name_reply_t *reply_info)
1795331Samw {
1805331Samw 	int			rc;
1815331Samw 	uint32_t		retry;
18210717Samw@Sun.COM 	uint16_t		tid;
1835331Samw 	struct resource_record	*answer;
1845331Samw 	struct name_question	question;
18510717Samw@Sun.COM 	addr_entry_t		*addr;
1865331Samw 	struct name_entry 	*destination;
1875331Samw 	struct name_packet	packet;
1885331Samw 	struct timespec 	st;
1895331Samw 
1905331Samw 	/*
1915331Samw 	 * The response packet has in it the address of the presumed owner
1925331Samw 	 * of the name.  Challenge that owner.  If owner either does not
1935331Samw 	 * respond or indicates that he no longer owns the name, claim the
1945331Samw 	 * name.  Otherwise, the name cannot be claimed.
1955331Samw 	 */
1965331Samw 
1975331Samw 	if ((answer = reply_info->packet->answer) == 0)
1985331Samw 		return (-1);
1995331Samw 
2005331Samw 	destination = answer->name;
2015331Samw 	question.name = answer->name;
2025331Samw 
2035331Samw 	packet.info = NAME_QUERY_REQUEST | NM_FLAGS_UNICAST;
2045331Samw 	packet.qdcount = 1;	/* question entries */
2055331Samw 	packet.question = &question;
2065331Samw 	packet.ancount = 0;	/* answer recs */
2075331Samw 	packet.answer = NULL;
2085331Samw 	packet.nscount = 0;	/* authority recs */
2095331Samw 	packet.authority = NULL;
2105331Samw 	packet.arcount = 0;	/* additional recs */
2115331Samw 	packet.additional = NULL;
2125331Samw 
2135331Samw 	addr = &destination->addr_list;
2145331Samw 	for (retry = 0; retry < UCAST_REQ_RETRY_COUNT; retry++) {
21510717Samw@Sun.COM 		tid = smb_netbios_name_trn_id();
2165331Samw 		packet.name_trn_id = tid;
2175331Samw 		if (smb_send_name_service_packet(addr, &packet) >= 0) {
2185331Samw 			if ((rc = smb_netbios_process_response(tid, addr,
2195331Samw 			    &packet, UCAST_REQ_RETRY_TIMEOUT)) != 0)
2205331Samw 				return (rc);
2215331Samw 		}
2225331Samw 		st.tv_sec = 0;
2235331Samw 		st.tv_nsec = (UCAST_REQ_RETRY_TIMEOUT * 1000000);
2245331Samw 		(void) nanosleep(&st, 0);
2255331Samw 	}
2265331Samw 	/* No reply */
2275331Samw 	return (0);
2285331Samw }
2295331Samw 
23010717Samw@Sun.COM static nbt_name_reply_t *
smb_name_get_reply(uint16_t tid,uint32_t timeout)23110717Samw@Sun.COM smb_name_get_reply(uint16_t tid, uint32_t timeout)
2325331Samw {
23310717Samw@Sun.COM 	uint16_t		info;
2345331Samw 	struct resource_record	*answer;
23510717Samw@Sun.COM 	nbt_name_reply_t 	*reply;
2365331Samw 	uint32_t 		wait_time, to_save; /* in millisecond */
2375331Samw 	struct timeval 		wt;
2385331Samw 	timestruc_t 		to;
2395331Samw 
2405331Samw 	to_save = timeout;
24110717Samw@Sun.COM 	reply = malloc(sizeof (nbt_name_reply_t));
24210717Samw@Sun.COM 	if (reply != NULL) {
24310717Samw@Sun.COM 		reply->reply_ready = B_FALSE;
2445331Samw 		reply->name_trn_id = tid;
2455331Samw 		(void) mutex_lock(&rq_mtx);
2465331Samw 		QUEUE_INSERT_TAIL(&reply_queue, reply);
2475331Samw 		(void) mutex_unlock(&rq_mtx);
2485331Samw 
2495331Samw 		for (;;) {
2505331Samw 			(void) gettimeofday(&wt, 0);
2515331Samw 			wait_time = wt.tv_usec / 1000;
2525331Samw 
2535331Samw 			to.tv_sec = 0;
2545331Samw 			to.tv_nsec = timeout * 1000000;
25510717Samw@Sun.COM 			(void) mutex_lock(&rq_mtx);
25610717Samw@Sun.COM 			(void) cond_reltimedwait(&rq_cv, &rq_mtx, &to);
25710717Samw@Sun.COM 			(void) mutex_unlock(&rq_mtx);
2585331Samw 
25910717Samw@Sun.COM 			if (reply->reply_ready) {
2605331Samw 				info = reply->packet->info;
2615331Samw 				if (PACKET_TYPE(info) == WACK_RESPONSE) {
2625331Samw 					answer = reply->packet->answer;
2635331Samw 					wait_time = (answer) ?
2645331Samw 					    TO_MILLISECONDS(answer->ttl) :
2655331Samw 					    DEFAULT_TTL;
2665331Samw 					free(reply->addr);
2675331Samw 					free(reply->packet);
2685331Samw 					timeout = to_save + wait_time;
26910717Samw@Sun.COM 					reply->reply_ready = B_FALSE;
2705331Samw 					reply->name_trn_id = tid;
2715331Samw 					(void) mutex_lock(&rq_mtx);
2725331Samw 					QUEUE_INSERT_TAIL(&reply_queue, reply);
2735331Samw 					(void) mutex_unlock(&rq_mtx);
2745331Samw 					continue;
2755331Samw 				}
2765331Samw 				return (reply);
2775331Samw 			}
2785331Samw 			(void) gettimeofday(&wt, 0);
2795331Samw 			wait_time = (wt.tv_usec / 1000) - wait_time;
2805331Samw 			if (wait_time >= timeout) {
2815331Samw 				(void) mutex_lock(&rq_mtx);
2825331Samw 				QUEUE_CLIP(reply);
2835331Samw 				(void) mutex_unlock(&rq_mtx);
2845331Samw 				free(reply);
2855331Samw 				break;
2865331Samw 			}
2875331Samw 			timeout -= wait_time;
2885331Samw 		}
2895331Samw 	}
2905331Samw 
2915331Samw 	return (0);
2925331Samw }
2935331Samw 
2945331Samw static void
smb_reply_ready(struct name_packet * packet,addr_entry_t * addr)29510717Samw@Sun.COM smb_reply_ready(struct name_packet *packet, addr_entry_t *addr)
2965331Samw {
29710717Samw@Sun.COM 	nbt_name_reply_t *reply;
2985331Samw 	struct resource_record *answer;
2995331Samw 
3005331Samw 	(void) mutex_lock(&rq_mtx);
3015331Samw 	for (reply = reply_queue.forw; reply != &reply_queue;
3025331Samw 	    reply = reply->forw) {
3035331Samw 		if (reply->name_trn_id == packet->name_trn_id) {
3045331Samw 			QUEUE_CLIP(reply);
3055331Samw 
3065331Samw 			reply->addr = addr;
3075331Samw 			reply->packet = packet;
30810717Samw@Sun.COM 			reply->reply_ready = B_TRUE;
30910717Samw@Sun.COM 			(void) cond_signal(&rq_cv);
31010717Samw@Sun.COM 			(void) mutex_unlock(&rq_mtx);
3115331Samw 			return;
3125331Samw 		}
3135331Samw 	}
3145331Samw 	(void) mutex_unlock(&rq_mtx);
3155331Samw 
3165331Samw 	/* Presumably nobody is waiting any more... */
3175331Samw 	free(addr);
3185331Samw 
3195331Samw 	answer = packet->answer;
3205331Samw 	if (answer)
3215331Samw 		smb_netbios_name_freeaddrs(answer->name);
3225331Samw 	free(packet);
3235331Samw }
3245331Samw 
3255331Samw static int
smb_netbios_process_response(uint16_t tid,addr_entry_t * addr,struct name_packet * packet,uint32_t timeout)32610717Samw@Sun.COM smb_netbios_process_response(uint16_t tid, addr_entry_t *addr,
3275331Samw     struct name_packet *packet, uint32_t timeout)
3285331Samw {
3295331Samw 	int			rc = 0;
33010717Samw@Sun.COM 	uint16_t		info;
33110717Samw@Sun.COM 	nbt_name_reply_t 	*reply;
3325331Samw 	struct resource_record	*answer;
3335331Samw 	struct name_entry 	*name;
3345331Samw 	struct name_entry 	*entry;
3355331Samw 	struct name_question 	*question;
3365331Samw 	uint32_t 		ttl;
3375331Samw 
3385331Samw 	if ((reply = smb_name_get_reply(tid, timeout)) == 0) {
3395331Samw 		return (0); /* No reply: retry */
3405331Samw 	}
3415331Samw 	info = reply->packet->info;
3425331Samw 	answer = reply->packet->answer;
3435331Samw 
3445331Samw 	/* response */
3455331Samw 	switch (PACKET_TYPE(info)) {
3465331Samw 	case NAME_QUERY_RESPONSE:
3475331Samw 		if (POSITIVE_RESPONSE(info)) {
3485331Samw 			addr = &answer->name->addr_list;
3495331Samw 			do {
3505331Samw 				/*
3515331Samw 				 * Make sure that remote name is not
3525331Samw 				 * flagged local
3535331Samw 				 */
3545331Samw 				addr->attributes &= ~NAME_ATTR_LOCAL;
3555331Samw 
35610717Samw@Sun.COM 				if (answer->ttl)
35710717Samw@Sun.COM 					addr->ttl = answer->ttl;
35810717Samw@Sun.COM 				else
35910717Samw@Sun.COM 					addr->ttl = DEFAULT_TTL;
36010717Samw@Sun.COM 				addr->refresh_ttl = TO_SECONDS(addr->ttl);
36110717Samw@Sun.COM 				addr->ttl = addr->refresh_ttl;
36210717Samw@Sun.COM 
3635331Samw 				addr = addr->forw;
3645331Samw 			} while (addr != &answer->name->addr_list);
36510717Samw@Sun.COM 			smb_netbios_name_logf(answer->name);
3665331Samw 			(void) smb_netbios_cache_insert_list(answer->name);
3675331Samw 			rc = 1;
3685331Samw 		} else {
3695331Samw 			rc = -1;
3705331Samw 		}
3715331Samw 		break;
3725331Samw 
3735331Samw 	case NAME_REGISTRATION_RESPONSE:
3745331Samw 		if (NEGATIVE_RESPONSE(info)) {
3755331Samw 			if (RCODE(info) == RCODE_CFT_ERR) {
3765331Samw 				if (answer == 0) {
3775331Samw 					rc = -RCODE(info);
3785331Samw 					break;
3795331Samw 				}
3805331Samw 
3815331Samw 				name = answer->name;
3825331Samw 				entry = smb_netbios_cache_lookup(name);
3835331Samw 				if (entry) {
3845331Samw 					/*
3855331Samw 					 * a name in the state "conflict
3865331Samw 					 * detected" does not "logically" exist
3875331Samw 					 * on that node. No further session
3885331Samw 					 * will be accepted on that name.
3895331Samw 					 * No datagrams can be sent against
3905331Samw 					 * that name.
3915331Samw 					 * Such an entry will not be used for
3925331Samw 					 * purposes of processing incoming
3935331Samw 					 * request packets.
3945331Samw 					 * The only valid user NetBIOS operation
3955331Samw 					 * against such a name is DELETE NAME.
3965331Samw 					 */
3975331Samw 					entry->attributes |= NAME_ATTR_CONFLICT;
3985331Samw 					syslog(LOG_DEBUG,
39910717Samw@Sun.COM 					    "nbns: name conflict: %15.15s",
4005331Samw 					    entry->name);
4015331Samw 					smb_netbios_cache_unlock_entry(entry);
4025331Samw 				}
4035331Samw 			}
4045331Samw 			rc = -RCODE(info);
4055331Samw 			break;
4065331Samw 		}
4075331Samw 
4085331Samw 		/*
4095331Samw 		 * name can be added:
4105331Samw 		 *   adjust refresh timeout value,
4115331Samw 		 *   TTL, for this name
4125331Samw 		 */
4135331Samw 		question = packet->question;
41410717Samw@Sun.COM 		ttl = (answer && answer->ttl) ? answer->ttl : DEFAULT_TTL;
41510717Samw@Sun.COM 		ttl = TO_SECONDS(ttl);
4165331Samw 		if ((entry = smb_netbios_cache_lookup(question->name)) != 0) {
4175331Samw 			addr = &entry->addr_list;
4185331Samw 			do {
4195331Samw 				if ((addr->refresh_ttl == 0) ||
4205331Samw 				    (ttl < addr->refresh_ttl))
4215331Samw 					addr->refresh_ttl = addr->ttl = ttl;
4225331Samw 				addr = addr->forw;
4235331Samw 			} while (addr != &entry->addr_list);
4245331Samw 			smb_netbios_cache_unlock_entry(entry);
4255331Samw 		}
4265331Samw 
4275331Samw 		rc = 1;
4285331Samw 		break;
4295331Samw 
4305331Samw 	case NAME_RELEASE_RESPONSE:
4315331Samw 		rc = 1;
4325331Samw 		break;
4335331Samw 
4345331Samw 	case END_NODE_CHALLENGE_REGISTRATION_REQUEST:
4355331Samw 		/*
4365331Samw 		 * The response packet has in it the
4375331Samw 		 * address of the presumed owner of the
4385331Samw 		 * name.  Challenge that owner.  If
4395331Samw 		 * owner either does not respond or
4405331Samw 		 * indicates that he no longer owns the
4415331Samw 		 * name, claim the name.  Otherwise,
4425331Samw 		 * the name cannot be claimed.
4435331Samw 		 */
4445331Samw 		rc = smb_end_node_challenge(reply);
4455331Samw 		break;
4465331Samw 
4475331Samw 	default:
4485331Samw 		rc = 0;
4495331Samw 		break;
4505331Samw 	}
4515331Samw 
4525331Samw 	if (answer)
4535331Samw 		smb_netbios_name_freeaddrs(answer->name);
4545331Samw 	free(reply->addr);
4555331Samw 	free(reply->packet);
4565331Samw 	free(reply);
4575331Samw 	return (rc);  /* retry */
4585331Samw }
4595331Samw 
4605331Samw /*
4615331Samw  * smb_name_buf_from_packet
4625331Samw  *
4635331Samw  * Description:
4645331Samw  *	Convert a NetBIOS Name Server Packet Block (npb)
4655331Samw  *	into the bits and bytes destined for the wire.
4665331Samw  *	The "buf" is used as a heap.
4675331Samw  *
4685331Samw  * Inputs:
4695331Samw  *	char *		buf	-> Buffer, from the wire
4705331Samw  *	unsigned	n_buf	-> Length of 'buf'
4715331Samw  *	name_packet	*npb	-> Packet block, decode into
4725331Samw  *	unsigned	n_npb	-> Max bytes in 'npb'
4735331Samw  *
4745331Samw  * Returns:
4755331Samw  *	>0	-> Encode successful, value is length of packet in "buf"
4765331Samw  *	-1	-> Hard error, can not possibly encode
4775331Samw  *	-2	-> Need more memory in buf -- it's too small
4785331Samw  */
4795331Samw static int
smb_name_buf_from_packet(unsigned char * buf,int n_buf,struct name_packet * npb)48010717Samw@Sun.COM smb_name_buf_from_packet(unsigned char *buf, int n_buf,
4815331Samw     struct name_packet *npb)
4825331Samw {
48310717Samw@Sun.COM 	addr_entry_t		*raddr;
4845331Samw 	unsigned char 		*heap = buf;
4855331Samw 	unsigned char 		*end_heap = heap + n_buf;
4865331Samw 	unsigned char 		*dnptrs[32];
4875331Samw 	unsigned char		comp_name_buf[MAX_NAME_LENGTH];
4885331Samw 	unsigned int		tmp;
4895331Samw 	int			i, step;
4905331Samw 
4915331Samw 	if (n_buf < NAME_HEADER_SIZE)
4925331Samw 		return (-1);		/* no header, impossible */
4935331Samw 
4945331Samw 	dnptrs[0] = heap;
4955331Samw 	dnptrs[1] = 0;
4965331Samw 
4975331Samw 	BE_OUT16(heap, npb->name_trn_id);
4985331Samw 	heap += 2;
4995331Samw 
5005331Samw 	BE_OUT16(heap, npb->info);
5015331Samw 	heap += 2;
5025331Samw 
5035331Samw 	BE_OUT16(heap, npb->qdcount);
5045331Samw 	heap += 2;
5055331Samw 
5065331Samw 	BE_OUT16(heap, npb->ancount);
5075331Samw 	heap += 2;
5085331Samw 
5095331Samw 	BE_OUT16(heap, npb->nscount);
5105331Samw 	heap += 2;
5115331Samw 
5125331Samw 	BE_OUT16(heap, npb->arcount);
5135331Samw 	heap += 2;
5145331Samw 
5155331Samw 	for (i = 0; i < npb->qdcount; i++) {
5165331Samw 		if ((heap + 34 + 4) > end_heap)
5175331Samw 			return (-2);
5185331Samw 
5195331Samw 		(void) smb_first_level_name_encode(npb->question[i].name,
5205331Samw 		    comp_name_buf, sizeof (comp_name_buf));
5215331Samw 		(void) strcpy((char *)heap, (char *)comp_name_buf);
5225331Samw 		heap += strlen((char *)comp_name_buf) + 1;
5235331Samw 
5245331Samw 		BE_OUT16(heap, npb->question[i].question_type);
5255331Samw 		heap += 2;
5265331Samw 
5275331Samw 		BE_OUT16(heap, npb->question[i].question_class);
5285331Samw 		heap += 2;
5295331Samw 	}
5305331Samw 
5315331Samw 	for (step = 1; step <= 3; step++) {
5325331Samw 		struct resource_record *nrr;
5335331Samw 		int n;
5345331Samw 
5355331Samw 		/* truly ugly, but saves code copying */
5365331Samw 		if (step == 1) {
5375331Samw 			n = npb->ancount;
5385331Samw 			nrr = npb->answer;
5395331Samw 		} else if (step == 2) {
5405331Samw 			n = npb->nscount;
5415331Samw 			nrr = npb->authority;
5425331Samw 		} else { /* step == 3 */
5435331Samw 			n = npb->arcount;
5445331Samw 			nrr = npb->additional;
5455331Samw 		}
5465331Samw 
5475331Samw 		for (i = 0; i < n; i++) {
5485331Samw 			if ((heap + 34 + 10) > end_heap)
5495331Samw 				return (-2);
5505331Samw 
5515331Samw 			(void) smb_first_level_name_encode(nrr->name,
5525331Samw 			    comp_name_buf, sizeof (comp_name_buf));
5535331Samw 			(void) strcpy((char *)heap, (char *)comp_name_buf);
5545331Samw 			heap += strlen((char *)comp_name_buf) + 1;
5555331Samw 
5565331Samw 			BE_OUT16(heap, nrr[i].rr_type);
5575331Samw 			heap += 2;
5585331Samw 
5595331Samw 			BE_OUT16(heap, nrr[i].rr_class);
5605331Samw 			heap += 2;
5615331Samw 
5625331Samw 			BE_OUT32(heap, nrr[i].ttl);
5635331Samw 			heap += 4;
5645331Samw 
5655331Samw 			BE_OUT16(heap, nrr[i].rdlength);
5665331Samw 			heap += 2;
5675331Samw 
5685331Samw 			if ((tmp = nrr[i].rdlength) > 0) {
5695331Samw 				if ((heap + tmp) > end_heap)
5705331Samw 					return (-2);
5715331Samw 
5725331Samw 				if (nrr[i].rr_type == NAME_RR_TYPE_NB &&
5735331Samw 				    nrr[i].rr_class == NAME_RR_CLASS_IN &&
5745331Samw 				    tmp >= 6 && nrr[i].rdata == 0) {
5755331Samw 					tmp = nrr[i].name->attributes &
5765331Samw 					    (NAME_ATTR_GROUP |
5775331Samw 					    NAME_ATTR_OWNER_NODE_TYPE);
5785331Samw 					BE_OUT16(heap, tmp);
5795331Samw 					heap += 2;
5805331Samw 
5815331Samw 					raddr = &nrr[i].name->addr_list;
5825331Samw 					(void) memcpy(heap,
5835331Samw 					    &raddr->sin.sin_addr.s_addr,
5845331Samw 					    sizeof (uint32_t));
5855331Samw 					heap += 4;
5865331Samw 				} else {
5875331Samw 					bcopy(nrr[i].rdata, heap, tmp);
5885331Samw 					heap += tmp;
5895331Samw 				}
5905331Samw 			}
5915331Samw 		}
5925331Samw 	}
5935331Samw 	return (heap - buf);
5945331Samw }
5955331Samw 
5965331Samw /*
5975331Samw  * strnchr
5985331Samw  *
5995331Samw  * Lookup for character 'c' in first 'n' chars of string 's'.
6005331Samw  * Returns pointer to the found char, otherwise returns 0.
6015331Samw  */
6025331Samw static char *
strnchr(const char * s,char c,int n)6035331Samw strnchr(const char *s, char c, int n)
6045331Samw {
6055331Samw 	char *ps = (char *)s;
6065331Samw 	char *es = (char *)s + n;
6075331Samw 
6085331Samw 	while (ps < es && *ps) {
6095331Samw 		if (*ps == c)
6105331Samw 			return (ps);
6115331Samw 
6125331Samw 		++ps;
6135331Samw 	}
6145331Samw 
6155331Samw 	if (*ps == '\0' && c == '\0')
6165331Samw 		return (ps);
6175331Samw 
6185331Samw 	return (0);
6195331Samw }
6205331Samw 
6216030Sjb150015 static boolean_t
is_multihome(char * name)6225331Samw is_multihome(char *name)
6235331Samw {
6246030Sjb150015 	return (smb_nic_getnum(name) > 1);
6255331Samw }
6265331Samw 
6275331Samw /*
6285331Samw  * smb_netbios_getname
6295331Samw  *
6305331Samw  * Get the Netbios name part of the given record.
6315331Samw  * Does some boundary checks.
6325331Samw  *
6335331Samw  * Returns the name length on success, otherwise
6345331Samw  * returns 0.
6355331Samw  */
6365331Samw static int
smb_netbios_getname(char * name,char * buf,char * buf_end)6375331Samw smb_netbios_getname(char *name, char *buf, char *buf_end)
6385331Samw {
6395331Samw 	char *name_end;
6405331Samw 	int name_len;
6415331Samw 
6425331Samw 	if (buf >= buf_end) {
6435331Samw 		/* no room for a NB name */
6445331Samw 		return (0);
6455331Samw 	}
6465331Samw 
6475331Samw 	name_end = strnchr(buf, '\0', buf_end - buf + 1);
6485331Samw 	if (name_end == 0) {
6495331Samw 		/* not a valid NB name */
6505331Samw 		return (0);
6515331Samw 	}
6525331Samw 
6535331Samw 	name_len = name_end - buf + 1;
6545331Samw 
6555331Samw 	(void) strlcpy(name, buf, name_len);
6565331Samw 	return (name_len);
6575331Samw }
6585331Samw 
6595331Samw /*
6605331Samw  * smb_name_buf_to_packet
6615331Samw  *
66210717Samw@Sun.COM  * Convert the bits and bytes that came from the wire into a NetBIOS
66310717Samw@Sun.COM  * Name Server Packet Block (npb).  The "block" is used as a heap.
6645331Samw  *
66510717Samw@Sun.COM  * Returns a pointer to a name packet on success.  Otherwise, returns
66610717Samw@Sun.COM  * a NULL pointer.
6675331Samw  */
6685331Samw static struct name_packet *
smb_name_buf_to_packet(char * buf,int n_buf)6695331Samw smb_name_buf_to_packet(char *buf, int n_buf)
6705331Samw {
6715331Samw 	struct name_packet *npb;
6725331Samw 	unsigned char *heap;
6735331Samw 	unsigned char *scan = (unsigned char *)buf;
6745331Samw 	unsigned char *scan_end = scan + n_buf;
6755331Samw 	char name_buf[MAX_NAME_LENGTH];
6765331Samw 	struct resource_record *nrr = 0;
6775331Samw 	int	rc, i, n, nn, ns;
67810717Samw@Sun.COM 	uint16_t name_trn_id, info;
67910717Samw@Sun.COM 	uint16_t qdcount, ancount, nscount, arcount;
68010717Samw@Sun.COM 	addr_entry_t *next;
6815331Samw 	int name_len;
6825331Samw 
6835331Samw 	if (n_buf < NAME_HEADER_SIZE) {
6845331Samw 		/* truncated header */
68510717Samw@Sun.COM 		syslog(LOG_DEBUG, "nbns: short packet (%d bytes)", n_buf);
68610717Samw@Sun.COM 		return (NULL);
6875331Samw 	}
6885331Samw 
6895331Samw 	name_trn_id = BE_IN16(scan); scan += 2;
6905331Samw 	info = BE_IN16(scan); scan += 2;
6915331Samw 	qdcount = BE_IN16(scan); scan += 2;
6925331Samw 	ancount = BE_IN16(scan); scan += 2;
6935331Samw 	nscount = BE_IN16(scan); scan += 2;
6945331Samw 	arcount = BE_IN16(scan); scan += 2;
6955331Samw 
6965331Samw 	ns = sizeof (struct name_entry);
6975331Samw 	n = n_buf + sizeof (struct name_packet) +
6985331Samw 	    ((unsigned)qdcount * (sizeof (struct name_question) + ns)) +
6995331Samw 	    ((unsigned)ancount * (sizeof (struct resource_record) + ns)) +
7005331Samw 	    ((unsigned)nscount * (sizeof (struct resource_record) + ns)) +
7015331Samw 	    ((unsigned)arcount * (sizeof (struct resource_record) + ns));
7025331Samw 
70310717Samw@Sun.COM 	if ((npb = malloc(n)) == NULL)
70410717Samw@Sun.COM 		return (NULL);
70510717Samw@Sun.COM 
7065331Samw 	bzero(npb, n);
7075331Samw 	heap = npb->block_data;
7085331Samw 	npb->name_trn_id = name_trn_id;
7095331Samw 	npb->info = info;
7105331Samw 	npb->qdcount = qdcount;
7115331Samw 	npb->ancount = ancount;
7125331Samw 	npb->nscount = nscount;
7135331Samw 	npb->arcount = arcount;
7145331Samw 
7155331Samw 	/* scan is in position for question entries */
7165331Samw 
7175331Samw 	/*
7185331Samw 	 * Measure the space needed for the tables
7195331Samw 	 */
7205331Samw 	if (qdcount > 0) {
7215331Samw 		/* LINTED - E_BAD_PTR_CAST_ALIGN */
7225331Samw 		npb->question = (struct name_question *)heap;
7235331Samw 		heap += qdcount * sizeof (struct name_question);
7245331Samw 		for (i = 0; i < qdcount; i++) {
7255331Samw 			/* LINTED - E_BAD_PTR_CAST_ALIGN */
7265331Samw 			npb->question[i].name = (struct name_entry *)heap;
7275331Samw 			heap += sizeof (struct name_entry);
7285331Samw 		}
7295331Samw 	}
7305331Samw 
7315331Samw 	/* LINTED - E_BAD_PTR_CAST_ALIGN */
7325331Samw 	nrr = (struct resource_record *)heap;
7335331Samw 
7345331Samw 	if (ancount > 0) {
7355331Samw 		/* LINTED - E_BAD_PTR_CAST_ALIGN */
7365331Samw 		npb->answer = (struct resource_record *)heap;
7375331Samw 		heap += ancount * sizeof (struct resource_record);
7385331Samw 	}
7395331Samw 
7405331Samw 	if (nscount > 0) {
7415331Samw 		/* LINTED - E_BAD_PTR_CAST_ALIGN */
7425331Samw 		npb->authority = (struct resource_record *)heap;
7435331Samw 		heap += nscount * sizeof (struct resource_record);
7445331Samw 	}
7455331Samw 
7465331Samw 	if (arcount > 0) {
7475331Samw 		/* LINTED - E_BAD_PTR_CAST_ALIGN */
7485331Samw 		npb->additional = (struct resource_record *)heap;
7495331Samw 		heap += arcount * sizeof (struct resource_record);
7505331Samw 	}
7515331Samw 
7525331Samw 	/*
7535331Samw 	 * Populate each resource_record's .name field.
7545331Samw 	 * Done as a second pass so that all resource records
7555331Samw 	 * (answer, authority, additional) are consecutive via nrr[i].
7565331Samw 	 */
7575331Samw 	for (i = 0; i < (ancount + nscount + arcount); i++) {
7585331Samw 		/* LINTED - E_BAD_PTR_CAST_ALIGN */
7595331Samw 		nrr[i].name = (struct name_entry *)heap;
7605331Samw 		heap += sizeof (struct name_entry);
7615331Samw 	}
7625331Samw 
7635331Samw 
7645331Samw 	for (i = 0; i < npb->qdcount; i++) {
7655331Samw 		name_len = smb_netbios_getname(name_buf, (char *)scan,
7665331Samw 		    (char *)scan_end);
7675331Samw 		if (name_len <= 0) {
7685331Samw 			free(npb);
76910717Samw@Sun.COM 			return (NULL);
7705331Samw 		}
7715331Samw 
7725331Samw 		smb_init_name_struct(NETBIOS_EMPTY_NAME, 0, 0, 0, 0, 0, 0,
7735331Samw 		    npb->question[i].name);
7745331Samw 		rc = smb_first_level_name_decode((unsigned char *)name_buf,
7755331Samw 		    npb->question[i].name);
7765331Samw 		if (rc < 0) {
7775331Samw 			/* Couldn't decode the question name */
7785331Samw 			free(npb);
77910717Samw@Sun.COM 			return (NULL);
7805331Samw 		}
7815331Samw 
7825331Samw 		scan += name_len;
7835331Samw 		if (scan + 4 > scan_end) {
7845331Samw 			/* no room for Question Type(2) and Class(2) fields */
7855331Samw 			free(npb);
78610717Samw@Sun.COM 			return (NULL);
7875331Samw 		}
7885331Samw 
7895331Samw 		npb->question[i].question_type = BE_IN16(scan); scan += 2;
7905331Samw 		npb->question[i].question_class = BE_IN16(scan); scan += 2;
7915331Samw 	}
7925331Samw 
7935331Samw 	/*
7945331Samw 	 * Cheat. Remaining sections are of the same resource_record
7955331Samw 	 * format. Table space is consecutive.
7965331Samw 	 */
7975331Samw 
7985331Samw 	for (i = 0; i < (ancount + nscount + arcount); i++) {
7995331Samw 		if (scan[0] == 0xc0) {
8005331Samw 			/* Namebuf is reused... */
8015331Samw 			rc = 2;
8025331Samw 		} else {
8035331Samw 			name_len = smb_netbios_getname(name_buf, (char *)scan,
8045331Samw 			    (char *)scan_end);
8055331Samw 			if (name_len <= 0) {
8065331Samw 				free(npb);
80710717Samw@Sun.COM 				return (NULL);
8085331Samw 			}
8095331Samw 			rc = name_len;
8105331Samw 		}
8115331Samw 		scan += rc;
8125331Samw 
8135331Samw 		if (scan + 10 > scan_end) {
8145331Samw 			/*
8155331Samw 			 * no room for RR_TYPE (2), RR_CLASS (2), TTL (4) and
8165331Samw 			 * RDLENGTH (2) fields.
8175331Samw 			 */
8185331Samw 			free(npb);
81910717Samw@Sun.COM 			return (NULL);
8205331Samw 		}
8215331Samw 
8225331Samw 		smb_init_name_struct(NETBIOS_EMPTY_NAME, 0, 0, 0, 0, 0, 0,
8235331Samw 		    nrr[i].name);
8245331Samw 		if ((rc = smb_first_level_name_decode((unsigned char *)name_buf,
8255331Samw 		    nrr[i].name)) < 0) {
8265331Samw 			free(npb);
82710717Samw@Sun.COM 			return (NULL);
8285331Samw 		}
8295331Samw 
8305331Samw 		nrr[i].rr_type = BE_IN16(scan); scan += 2;
8315331Samw 		nrr[i].rr_class = BE_IN16(scan); scan += 2;
8325331Samw 		nrr[i].ttl = BE_IN32(scan); scan += 4;
8335331Samw 		nrr[i].rdlength = BE_IN16(scan); scan += 2;
8345331Samw 
8355331Samw 		if ((n = nrr[i].rdlength) > 0) {
8365331Samw 			if ((scan + n) > scan_end) {
8375331Samw 				/* no room for RDATA */
8385331Samw 				free(npb);
83910717Samw@Sun.COM 				return (NULL);
8405331Samw 			}
8415331Samw 			bcopy(scan, heap, n);
8425331Samw 
8435331Samw 			nn = n;
8445331Samw 			if (nrr[i].rr_type == 0x0020 &&
8455331Samw 			    nrr[i].rr_class == 0x01 && n >= 6) {
8465331Samw 				while (nn) {
8475331Samw 					if (nn == 6)
8485331Samw 						next = &nrr[i].name->addr_list;
8495331Samw 					else {
85010717Samw@Sun.COM 						next = malloc(
85110717Samw@Sun.COM 						    sizeof (addr_entry_t));
8525331Samw 						if (next == 0) {
8535331Samw 							/* not enough memory */
8545331Samw 							free(npb);
85510717Samw@Sun.COM 							return (NULL);
8565331Samw 						}
8575331Samw 						QUEUE_INSERT_TAIL(
8585331Samw 						    &nrr[i].name->addr_list,
8595331Samw 						    next);
8605331Samw 					}
8615331Samw 					nrr[i].name->attributes =
8625331Samw 					    BE_IN16(scan);
8635331Samw 					next->sin.sin_family = AF_INET;
8645331Samw 					next->sinlen = sizeof (next->sin);
8655331Samw 					(void) memcpy(
8665331Samw 					    &next->sin.sin_addr.s_addr,
8675331Samw 					    scan + 2, sizeof (uint32_t));
8685331Samw 					next->sin.sin_port =
86910717Samw@Sun.COM 					    htons(IPPORT_NETBIOS_DGM);
8705331Samw 					nn -= 6;
8715331Samw 					scan += 6;
8725331Samw 				}
8735331Samw 			} else {
8745331Samw 				nrr[i].rdata = heap;
8755331Samw 				scan += n;
8765331Samw 			}
8775331Samw 			heap += n;
8785331Samw 		}
8795331Samw 	}
8805331Samw 	return (npb);
8815331Samw }
8825331Samw 
8835331Samw /*
8845331Samw  * smb_send_name_service_packet
8855331Samw  *
8865331Samw  * Description:
8875331Samw  *
8885331Samw  *	Send out a name service packet to proper destination.
8895331Samw  *
8905331Samw  * Inputs:
8915331Samw  *	struct netbios_name *dest	-> NETBIOS name of destination
8925331Samw  *	struct name_packet *packet	-> Packet to send
8935331Samw  *
8945331Samw  * Returns:
8955331Samw  *	success	->  >0
8965331Samw  *	failure	-> <=0
8975331Samw  */
8985331Samw static int
smb_send_name_service_packet(addr_entry_t * addr,struct name_packet * packet)89910717Samw@Sun.COM smb_send_name_service_packet(addr_entry_t *addr, struct name_packet *packet)
9005331Samw {
9015331Samw 	unsigned char buf[MAX_DATAGRAM_LENGTH];
9025331Samw 	int len;
9035331Samw 
9045331Samw 	if ((len = smb_name_buf_from_packet(buf, sizeof (buf), packet)) < 0) {
9055331Samw 		errno = EINVAL;
9065331Samw 		return (-1);
9075331Samw 	}
9085331Samw 
9095331Samw 	return (sendto(name_sock, buf, len, MSG_EOR,
9105331Samw 	    (struct sockaddr *)&addr->sin, addr->sinlen));
9115331Samw }
9125331Samw 
9135331Samw /*
9145331Samw  * smb_netbios_send_rcv
9155331Samw  *
9165331Samw  * This function sends the given NetBIOS packet to the given
9175331Samw  * address and get back the response. If send operation is not
9185331Samw  * successful, it's repeated 'retries' times.
9195331Samw  *
9205331Samw  * Returns:
9215331Samw  *		0		Unsuccessful send operation; no reply
9225331Samw  *		1		Got reply
9235331Samw  */
9245331Samw static int
smb_netbios_send_rcv(int bcast,addr_entry_t * destination,struct name_packet * packet,uint32_t retries,uint32_t timeout)92510717Samw@Sun.COM smb_netbios_send_rcv(int bcast, addr_entry_t *destination,
92610717Samw@Sun.COM     struct name_packet *packet, uint32_t retries, uint32_t timeout)
9275331Samw {
9285331Samw 	uint32_t retry;
92910717Samw@Sun.COM 	uint16_t	tid;
9305331Samw 	struct timespec st;
9315331Samw 	int	rc;
9325331Samw 
9335331Samw 	for (retry = 0; retry < retries; retry++) {
9345331Samw 		if ((destination->flags & ADDR_FLAG_VALID) == 0)
9355331Samw 			return (0);
9365331Samw 
93710717Samw@Sun.COM 		tid = smb_netbios_name_trn_id();
9385331Samw 		packet->name_trn_id = tid;
9395331Samw 		if (smb_send_name_service_packet(destination, packet) >= 0) {
9405331Samw 			rc = smb_netbios_process_response(tid, destination,
9415331Samw 			    packet, timeout);
9425331Samw 
9435331Samw 			if ((rc > 0) || (bcast == BROADCAST))
9445331Samw 				return (1);
9455331Samw 
9465331Samw 			if (rc != 0)
9475331Samw 				return (0);
9485331Samw 		}
9495331Samw 
9505331Samw 		st.tv_sec = 0;
9515331Samw 		st.tv_nsec = (timeout * 1000000);
9525331Samw 		(void) nanosleep(&st, 0);
9535331Samw 	}
9545331Samw 
9555331Samw 	return (0);
9565331Samw }
9575331Samw 
9585331Samw /*
95910717Samw@Sun.COM  * RFC 1002 4.2.2.  NAME REGISTRATION REQUEST
9605331Samw  */
9615331Samw static int
smb_send_name_registration_request(int bcast,struct name_question * question,struct resource_record * additional)9625331Samw smb_send_name_registration_request(int bcast, struct name_question *question,
9635331Samw     struct resource_record *additional)
9645331Samw {
9655331Samw 	int gotreply = 0;
9665331Samw 	uint32_t retries;
9675331Samw 	uint32_t timeout;
96810717Samw@Sun.COM 	addr_entry_t *destination;
9695331Samw 	struct name_packet packet;
9705331Samw 	unsigned char type;
9715331Samw 	int i, addr_num, rc;
9725331Samw 
9735331Samw 	type = question->name->name[15];
97410717Samw@Sun.COM 	if ((type != NBT_WKSTA) && (type != NBT_SERVER)) {
97510717Samw@Sun.COM 		syslog(LOG_DEBUG, "nbns: name registration bad type (0x%02x)",
97610717Samw@Sun.COM 		    type);
9775331Samw 		smb_netbios_name_logf(question->name);
9785331Samw 		question->name->attributes &= ~NAME_ATTR_LOCAL;
9795331Samw 		return (-1);
9805331Samw 	}
9815331Samw 
9825331Samw 	if (bcast == BROADCAST) {
9835331Samw 		if (bcast_num == 0)
9845331Samw 			return (0);
9855331Samw 		destination = smb_bcast_list;
9865331Samw 		addr_num = bcast_num;
9875331Samw 		retries = BCAST_REQ_RETRY_COUNT;
9885331Samw 		timeout = BCAST_REQ_RETRY_TIMEOUT;
9895331Samw 		packet.info = NAME_REGISTRATION_REQUEST | NM_FLAGS_BROADCAST;
9905331Samw 	} else {
9915331Samw 		if (nbns_num == 0)
9925331Samw 			return (0);
9935331Samw 		destination = smb_nbns;
9945331Samw 		addr_num = nbns_num;
9955331Samw 		retries = UCAST_REQ_RETRY_COUNT;
9965331Samw 		timeout = UCAST_REQ_RETRY_TIMEOUT;
9975331Samw 		packet.info = NAME_REGISTRATION_REQUEST | NM_FLAGS_UNICAST;
9985331Samw 	}
9995331Samw 
10005331Samw 	packet.qdcount = 1;	/* question entries */
10015331Samw 	packet.question = question;
10025331Samw 	packet.ancount = 0;	/* answer recs */
10035331Samw 	packet.answer = NULL;
10045331Samw 	packet.nscount = 0;	/* authority recs */
10055331Samw 	packet.authority = NULL;
10065331Samw 	packet.arcount = 1;	/* additional recs */
10075331Samw 	packet.additional = additional;
10085331Samw 
10095331Samw 	if (IS_UNIQUE(question->name->attributes) &&
10105331Samw 	    (is_multihome((char *)(question->name->name))))
10115331Samw 		packet.info |= NAME_MULTIHOME_REGISTRATION_REQUEST;
10125331Samw 
10135331Samw 	for (i = 0; i < addr_num; i++) {
10145331Samw 		/*
10155331Samw 		 * Only register with the Primary WINS server,
10165331Samw 		 * unless we got no reply.
10175331Samw 		 */
10185331Samw 		if ((bcast == UNICAST) && gotreply)
10195331Samw 			break;
10205331Samw 
10215331Samw 		rc = smb_netbios_send_rcv(bcast, &destination[i], &packet,
10225331Samw 		    retries, timeout);
10235331Samw 		if (rc == 1)
10245331Samw 			gotreply = 1;
10255331Samw 	}
10265331Samw 
10275331Samw 	return (gotreply);
10285331Samw }
10295331Samw 
10305331Samw /*
103110717Samw@Sun.COM  * RFC 1002 4.2.4.  NAME REFRESH REQUEST
10325331Samw  */
10335331Samw /*ARGSUSED*/
10345331Samw static int
smb_send_name_refresh_request(int bcast,struct name_question * question,struct resource_record * additional,int force)10355331Samw smb_send_name_refresh_request(int bcast, struct name_question *question,
10365331Samw     struct resource_record *additional, int force)
10375331Samw {
10385331Samw 	int rc = 0;
10395331Samw 	int gotreply = 0;
10405331Samw 	uint32_t retries;
10415331Samw 	uint32_t timeout;
104210717Samw@Sun.COM 	addr_entry_t *addr;
104310717Samw@Sun.COM 	addr_entry_t *destination;
10445331Samw 	struct name_packet packet;
10455331Samw 	unsigned char type;
10465331Samw 	int i, addr_num, q_addrs = 0;
10475331Samw 
10485331Samw 	type = question->name->name[15];
104910717Samw@Sun.COM 	if ((type != NBT_WKSTA) && (type != NBT_SERVER)) {
105010717Samw@Sun.COM 		syslog(LOG_DEBUG, "nbns: name refresh bad type (0x%02x)", type);
10515331Samw 		smb_netbios_name_logf(question->name);
10525331Samw 		question->name->attributes &= ~NAME_ATTR_LOCAL;
10535331Samw 		return (-1);
10545331Samw 	}
10555331Samw 	switch (bcast) {
10565331Samw 	case BROADCAST :
10575331Samw 		if (bcast_num == 0)
10585331Samw 			return (-1);
10595331Samw 		destination = smb_bcast_list;
10605331Samw 		addr_num = bcast_num;
10615331Samw 		retries = BCAST_REQ_RETRY_COUNT;
10625331Samw 		timeout = BCAST_REQ_RETRY_TIMEOUT;
10635331Samw 		packet.info = NAME_REFRESH_REQUEST | NM_FLAGS_BROADCAST;
10645331Samw 		break;
10655331Samw 
10665331Samw 	case UNICAST :
10675331Samw 		if (nbns_num == 0)
10685331Samw 			return (-1);
10695331Samw 		destination = smb_nbns;
10705331Samw 		addr_num = nbns_num;
10715331Samw 		retries = UCAST_REQ_RETRY_COUNT;
10725331Samw 		timeout = UCAST_REQ_RETRY_TIMEOUT;
10735331Samw 		packet.info = NAME_REFRESH_REQUEST | NM_FLAGS_UNICAST;
10745331Samw 		break;
10755331Samw 
10765331Samw 	default:
10775331Samw 		destination = &question->name->addr_list;
10785331Samw 		/*
10795331Samw 		 * the value of addr_num is irrelvant here, because
10805331Samw 		 * the code is going to do special_process so it doesn't
10815331Samw 		 * need the addr_num. We set a value here just to avoid
10825331Samw 		 * compiler warning.
10835331Samw 		 */
10845331Samw 		addr_num = 0;
10855331Samw 		retries = UCAST_REQ_RETRY_COUNT;
10865331Samw 		timeout = UCAST_REQ_RETRY_TIMEOUT;
10875331Samw 		packet.info = NAME_REFRESH_REQUEST | NM_FLAGS_UNICAST;
10885331Samw 		q_addrs = 1;
10895331Samw 		break;
10905331Samw 	}
10915331Samw 
10925331Samw 	if (IS_UNIQUE(question->name->attributes) &&
10935331Samw 	    (is_multihome((char *)(question->name->name))))
10945331Samw 		packet.info |= NAME_MULTIHOME_REGISTRATION_REQUEST;
10955331Samw 
10965331Samw 	packet.qdcount = 1;	/* question entries */
10975331Samw 	packet.question = question;
10985331Samw 	packet.ancount = 0;	/* answer recs */
10995331Samw 	packet.answer = NULL;
11005331Samw 	packet.nscount = 0;	/* authority recs */
11015331Samw 	packet.authority = NULL;
11025331Samw 	packet.arcount = 1;	/* additional recs */
11035331Samw 	packet.additional = additional;
11045331Samw 
11055331Samw 	if (q_addrs)
11065331Samw 		goto special_process;
11075331Samw 
11085331Samw 	for (i = 0; i < addr_num; i++) {
11095331Samw 		rc = smb_netbios_send_rcv(bcast, &destination[i], &packet,
11105331Samw 		    retries, timeout);
11115331Samw 		if (rc == 1)
11125331Samw 			gotreply = 1;
11135331Samw 	}
11145331Samw 
11155331Samw 	return (gotreply);
11165331Samw 
11175331Samw special_process:
11185331Samw 	addr = destination;
11195331Samw 	do {
11205331Samw 		rc = smb_netbios_send_rcv(bcast, addr, &packet,
11215331Samw 		    retries, timeout);
11225331Samw 		if (rc == 1)
11235331Samw 			gotreply = 1;
11245331Samw 		addr = addr->forw;
11255331Samw 	} while (addr != destination);
11265331Samw 
11275331Samw 	return (gotreply);
11285331Samw }
11295331Samw 
11305331Samw /*
113110717Samw@Sun.COM  * RFC 1002 4.2.5.  POSITIVE NAME REGISTRATION RESPONSE
113210717Samw@Sun.COM  * RFC 1002 4.2.6.  NEGATIVE NAME REGISTRATION RESPONSE
11335331Samw  */
11345331Samw static int
smb_send_name_registration_response(addr_entry_t * addr,struct name_packet * original_packet,uint16_t rcode)113510717Samw@Sun.COM smb_send_name_registration_response(addr_entry_t *addr,
113610717Samw@Sun.COM     struct name_packet *original_packet, uint16_t rcode)
11375331Samw {
11385331Samw 	struct name_packet	packet;
11395331Samw 	struct resource_record	answer;
11405331Samw 
11415331Samw 	bzero(&packet, sizeof (struct name_packet));
11425331Samw 	bzero(&answer, sizeof (struct resource_record));
11435331Samw 
11445331Samw 	packet.name_trn_id = original_packet->name_trn_id;
11455331Samw 	packet.info = NAME_REGISTRATION_RESPONSE | NAME_NM_FLAGS_RA |
11465331Samw 	    (rcode & NAME_RCODE_MASK);
11475331Samw 	packet.qdcount = 0;	/* question entries */
11485331Samw 	packet.question = NULL;
11495331Samw 	packet.ancount = 1;	/* answer recs */
11505331Samw 	packet.answer = &answer;
11515331Samw 	packet.nscount = 0;	/* authority recs */
11525331Samw 	packet.authority = NULL;
11535331Samw 	packet.arcount = 0;	/* additional recs */
11545331Samw 	packet.additional = NULL;
11555331Samw 
11565331Samw 	answer.name = original_packet->question->name;
11575331Samw 	answer.rr_type = NAME_QUESTION_TYPE_NB;
11585331Samw 	answer.rr_class = NAME_QUESTION_CLASS_IN;
11595331Samw 	answer.ttl = original_packet->additional->ttl;
11605331Samw 	answer.rdlength = original_packet->additional->rdlength;
11615331Samw 	answer.rdata = original_packet->additional->rdata;
11625331Samw 
11635331Samw 	return (smb_send_name_service_packet(addr, &packet));
11645331Samw }
11655331Samw 
11665331Samw /*
116710717Samw@Sun.COM  * RFC 1002 4.2.9.  NAME RELEASE REQUEST & DEMAND
11685331Samw  */
11695331Samw static int
smb_send_name_release_request_and_demand(int bcast,struct name_question * question,struct resource_record * additional)11705331Samw smb_send_name_release_request_and_demand(int bcast,
11715331Samw     struct name_question *question, struct resource_record *additional)
11725331Samw {
11735331Samw 	int gotreply = 0;
11745331Samw 	int i, rc;
11755331Samw 	int addr_num;
11765331Samw 	uint32_t retries;
11775331Samw 	uint32_t timeout;
117810717Samw@Sun.COM 	addr_entry_t *destination;
11795331Samw 	struct name_packet packet;
11805331Samw 
11815331Samw 	if (bcast == BROADCAST) {
11825331Samw 		if (bcast_num == 0)
11835331Samw 			return (-1);
11845331Samw 		destination = smb_bcast_list;
11855331Samw 		addr_num = bcast_num;
11865331Samw 		retries = 1; /* BCAST_REQ_RETRY_COUNT */
11875331Samw 		timeout = 100; /* BCAST_REQ_RETRY_TIMEOUT */
11885331Samw 		packet.info = NAME_RELEASE_REQUEST | NM_FLAGS_BROADCAST;
11895331Samw 	} else {
11905331Samw 		if (nbns_num == 0)
11915331Samw 			return (-1);
11925331Samw 		destination = smb_nbns;
11935331Samw 		addr_num = nbns_num;
11945331Samw 		retries = 1; /* UCAST_REQ_RETRY_COUNT */
11955331Samw 		timeout = 100; /* UCAST_REQ_RETRY_TIMEOUT */
11965331Samw 		packet.info = NAME_RELEASE_REQUEST | NM_FLAGS_UNICAST;
11975331Samw 	}
11985331Samw 
11995331Samw 	packet.qdcount = 1;	/* question entries */
12005331Samw 	packet.question = question;
12015331Samw 	packet.ancount = 0;	/* answer recs */
12025331Samw 	packet.answer = NULL;
12035331Samw 	packet.nscount = 0;	/* authority recs */
12045331Samw 	packet.authority = NULL;
12055331Samw 	packet.arcount = 1;	/* additional recs */
12065331Samw 	packet.additional = additional;
12075331Samw 
12085331Samw 	for (i = 0; i < addr_num; i++) {
12095331Samw 		rc = smb_netbios_send_rcv(bcast, &destination[i], &packet,
12105331Samw 		    retries, timeout);
12115331Samw 		if (rc == 1)
12125331Samw 			gotreply = 1;
12135331Samw 	}
12145331Samw 
12155331Samw 	return (gotreply);
12165331Samw }
12175331Samw 
12185331Samw /*
121910717Samw@Sun.COM  * RFC 1002 4.2.10.  POSITIVE NAME RELEASE RESPONSE
122010717Samw@Sun.COM  * RFC 1002 4.2.11.  NEGATIVE NAME RELEASE RESPONSE
12215331Samw  */
12225331Samw static int
12235331Samw /* LINTED - E_STATIC_UNUSED */
smb_send_name_release_response(addr_entry_t * addr,struct name_packet * original_packet,uint16_t rcode)122410717Samw@Sun.COM smb_send_name_release_response(addr_entry_t *addr,
122510717Samw@Sun.COM     struct name_packet *original_packet, uint16_t rcode)
12265331Samw {
12275331Samw 	struct name_packet	packet;
12285331Samw 	struct resource_record	answer;
12295331Samw 
12305331Samw 	bzero(&packet, sizeof (struct name_packet));
12315331Samw 	bzero(&answer, sizeof (struct resource_record));
12325331Samw 
12335331Samw 	packet.name_trn_id = original_packet->name_trn_id;
12345331Samw 	packet.info = NAME_RELEASE_RESPONSE | (rcode & NAME_RCODE_MASK);
12355331Samw 	packet.qdcount = 0;	/* question entries */
12365331Samw 	packet.question = NULL;
12375331Samw 	packet.ancount = 1;	/* answer recs */
12385331Samw 	packet.answer = &answer;
12395331Samw 	packet.nscount = 0;	/* authority recs */
12405331Samw 	packet.authority = NULL;
12415331Samw 	packet.arcount = 0;	/* additional recs */
12425331Samw 	packet.additional = NULL;
12435331Samw 
12445331Samw 	answer.name = original_packet->question->name;
12455331Samw 	answer.rr_type = NAME_QUESTION_TYPE_NB;
12465331Samw 	answer.rr_class = NAME_QUESTION_CLASS_IN;
12475331Samw 	answer.ttl = original_packet->additional->ttl;
12485331Samw 	answer.rdlength = original_packet->additional->rdlength;
12495331Samw 	answer.rdata = original_packet->additional->rdata;
12505331Samw 
12515331Samw 	return (smb_send_name_service_packet(addr, &packet));
12525331Samw }
12535331Samw 
12545331Samw /*
125510717Samw@Sun.COM  * RFC 1002 4.2.12.  NAME QUERY REQUEST
12565331Samw  */
12575331Samw static int
smb_send_name_query_request(int bcast,struct name_question * question)12585331Samw smb_send_name_query_request(int bcast, struct name_question *question)
12595331Samw {
12605331Samw 	int			rc = 0;
12615331Samw 	uint32_t		retry, retries;
12625331Samw 	uint32_t		timeout;
126310717Samw@Sun.COM 	uint16_t		tid;
126410717Samw@Sun.COM 	addr_entry_t		*destination;
12655331Samw 	struct name_packet	packet;
12665331Samw 	int 			i, addr_num;
12675331Samw 	struct timespec 	st;
12685331Samw 
12695331Samw 	if (bcast == BROADCAST) {
12705331Samw 		if (bcast_num == 0)
12715331Samw 			return (-1);
12725331Samw 		destination = smb_bcast_list;
12735331Samw 		addr_num = bcast_num;
12745331Samw 		retries = BCAST_REQ_RETRY_COUNT;
12755331Samw 		timeout = BCAST_REQ_RETRY_TIMEOUT;
12765331Samw 		packet.info = NAME_QUERY_REQUEST | NM_FLAGS_BROADCAST;
12775331Samw 	} else {
12785331Samw 		if (nbns_num == 0)
12795331Samw 			return (-1);
12805331Samw 		destination = smb_nbns;
12815331Samw 		addr_num = nbns_num;
12825331Samw 		retries = UCAST_REQ_RETRY_COUNT;
12835331Samw 		timeout = UCAST_REQ_RETRY_TIMEOUT;
12845331Samw 		packet.info = NAME_QUERY_REQUEST | NM_FLAGS_UNICAST;
12855331Samw 	}
12865331Samw 	packet.qdcount = 1;	/* question entries */
12875331Samw 	packet.question = question;
12885331Samw 	packet.ancount = 0;	/* answer recs */
12895331Samw 	packet.answer = NULL;
12905331Samw 	packet.nscount = 0;	/* authority recs */
12915331Samw 	packet.authority = NULL;
12925331Samw 	packet.arcount = 0;	/* additional recs */
12935331Samw 	packet.additional = NULL;
12945331Samw 
12955331Samw 	for (i = 0; i < addr_num; i++) {
12965331Samw 		for (retry = 0; retry < retries; retry++) {
129710717Samw@Sun.COM 			if ((destination[i].flags & ADDR_FLAG_VALID) == 0)
12985331Samw 				break;
129910717Samw@Sun.COM 			tid = smb_netbios_name_trn_id();
13005331Samw 			packet.name_trn_id = tid;
13015331Samw 
13025331Samw 			if (smb_send_name_service_packet(&destination[i],
13035331Samw 			    &packet) >= 0) {
13045331Samw 				if ((rc = smb_netbios_process_response(tid,
13055331Samw 				    &destination[i],
13065331Samw 				    &packet, timeout)) != 0)
13075331Samw 					break;
13085331Samw 			}
13095331Samw 			st.tv_sec = 0;
13105331Samw 			st.tv_nsec = (timeout * 1000000);
13115331Samw 			(void) nanosleep(&st, 0);
13125331Samw 		}
13135331Samw 	}
13145331Samw 
13155331Samw 	return (rc);
13165331Samw }
13175331Samw 
13185331Samw /*
131910717Samw@Sun.COM  * RFC 1002 4.2.13.  POSITIVE NAME QUERY RESPONSE
132010717Samw@Sun.COM  * RFC 1002 4.2.14.  NEGATIVE NAME QUERY RESPONSE
13215331Samw  */
13225331Samw static int
smb_send_name_query_response(addr_entry_t * addr,struct name_packet * original_packet,struct name_entry * entry,uint16_t rcode)132310717Samw@Sun.COM smb_send_name_query_response(addr_entry_t *addr,
13245331Samw     struct name_packet *original_packet, struct name_entry *entry,
132510717Samw@Sun.COM     uint16_t rcode)
13265331Samw {
132710717Samw@Sun.COM 	addr_entry_t		*raddr;
13285331Samw 	struct name_packet	packet;
13295331Samw 	struct resource_record	answer;
133010717Samw@Sun.COM 	uint16_t		attr;
13315331Samw 	unsigned char 		data[MAX_DATAGRAM_LENGTH];
13325331Samw 	unsigned char 		*scan = data;
13339832Samw@Sun.COM 	uint32_t		ret_addr;
13345331Samw 
13355331Samw 	packet.name_trn_id = original_packet->name_trn_id;
13365331Samw 	packet.info = NAME_QUERY_RESPONSE | (rcode & NAME_RCODE_MASK);
13375331Samw 	packet.qdcount = 0;	/* question entries */
13385331Samw 	packet.question = NULL;
13395331Samw 	packet.ancount = 1;	/* answer recs */
13405331Samw 	packet.answer = &answer;
13415331Samw 	packet.nscount = 0;	/* authority recs */
13425331Samw 	packet.authority = NULL;
13435331Samw 	packet.arcount = 0;	/* additional recs */
13445331Samw 	packet.additional = NULL;
13455331Samw 
13465331Samw 	answer.name = entry;
13475331Samw 	answer.rr_class = NAME_QUESTION_CLASS_IN;
13485331Samw 	answer.ttl = entry->addr_list.ttl;
13495331Samw 	answer.rdata = data;
13505331Samw 	if (rcode) {
13515331Samw 		answer.rr_type = NAME_RR_TYPE_NULL;
13525331Samw 		answer.rdlength = 0;
13535331Samw 		bzero(data, 6);
13545331Samw 	} else {
13555331Samw 		answer.rdlength = 0;
13565331Samw 		answer.rr_type = NAME_QUESTION_TYPE_NB;
13575331Samw 		raddr = &entry->addr_list;
13585331Samw 		scan = data;
13595331Samw 		do {
13605331Samw 			attr = entry->attributes & (NAME_ATTR_GROUP |
13615331Samw 			    NAME_ATTR_OWNER_NODE_TYPE);
13625331Samw 
13635331Samw 			BE_OUT16(scan, attr); scan += 2;
13649832Samw@Sun.COM 			ret_addr = LE_32(raddr->sin.sin_addr.s_addr);
13659832Samw@Sun.COM 			*scan++ = ret_addr;
13669832Samw@Sun.COM 			*scan++ = ret_addr >> 8;
13679832Samw@Sun.COM 			*scan++ = ret_addr >> 16;
13689832Samw@Sun.COM 			*scan++ = ret_addr >> 24;
13695331Samw 
13705331Samw 			answer.rdlength += 6;
13715331Samw 			raddr = raddr->forw;
13725331Samw 		} while (raddr != &entry->addr_list);
13735331Samw 	}
13745331Samw 
13755331Samw 	return (smb_send_name_service_packet(addr, &packet));
13765331Samw }
13775331Samw 
13785331Samw /*
137910717Samw@Sun.COM  * RFC 1002 4.2.18.  NODE STATUS RESPONSE
13805331Samw  */
13815331Samw static int
smb_send_node_status_response(addr_entry_t * addr,struct name_packet * original_packet)138210717Samw@Sun.COM smb_send_node_status_response(addr_entry_t *addr,
13835331Samw     struct name_packet *original_packet)
13845331Samw {
13855772Sas200622 	uint32_t		net_ipaddr;
13865772Sas200622 	int64_t			max_connections;
13875331Samw 	struct arpreq 		arpreq;
13885331Samw 	struct name_packet	packet;
13895331Samw 	struct resource_record	answer;
13905331Samw 	unsigned char 		*scan;
13915331Samw 	unsigned char 		*scan_end;
13925331Samw 	unsigned char		data[MAX_NETBIOS_REPLY_DATA_SIZE];
13935521Sas200622 	boolean_t scan_done = B_FALSE;
13948670SJose.Borrego@Sun.COM 	smb_inaddr_t ipaddr;
13955331Samw 
13965331Samw 	bzero(&packet, sizeof (struct name_packet));
13975331Samw 	bzero(&answer, sizeof (struct resource_record));
13985331Samw 
13995331Samw 	packet.name_trn_id = original_packet->name_trn_id;
14005331Samw 	packet.info = NODE_STATUS_RESPONSE;
14015331Samw 	packet.qdcount = 0;	/* question entries */
14025331Samw 	packet.question = NULL;
14035331Samw 	packet.ancount = 1;	/* answer recs */
14045331Samw 	packet.answer = &answer;
14055331Samw 	packet.nscount = 0;	/* authority recs */
14065331Samw 	packet.authority = NULL;
14075331Samw 	packet.arcount = 0;	/* additional recs */
14085331Samw 	packet.additional = NULL;
14095331Samw 
14105331Samw 	answer.name = original_packet->question->name;
14115331Samw 	answer.rr_type = NAME_RR_TYPE_NBSTAT;
14125331Samw 	answer.rr_class = NAME_QUESTION_CLASS_IN;
14135331Samw 	answer.ttl = 0;
14145331Samw 	answer.rdata = data;
14155331Samw 
14165331Samw 	scan = smb_netbios_cache_status(data, MAX_NETBIOS_REPLY_DATA_SIZE,
14175331Samw 	    original_packet->question->name->scope);
14185331Samw 
14195331Samw 	scan_end = data + MAX_NETBIOS_REPLY_DATA_SIZE;
14205331Samw 
14218670SJose.Borrego@Sun.COM 	ipaddr.a_ipv4 = addr->sin.sin_addr.s_addr;
14228670SJose.Borrego@Sun.COM 	ipaddr.a_family = AF_INET;
14239021Samw@Sun.COM 	if (smb_nic_is_same_subnet(&ipaddr))
14246030Sjb150015 		net_ipaddr = addr->sin.sin_addr.s_addr;
14256030Sjb150015 	else
14265331Samw 		net_ipaddr = 0;
14275331Samw 
14285772Sas200622 	(void) smb_config_getnum(SMB_CI_MAX_CONNECTIONS, &max_connections);
14295772Sas200622 
14305521Sas200622 	while (!scan_done) {
14315331Samw 		if ((scan + 6) >= scan_end) {
14325331Samw 			packet.info |= NAME_NM_FLAGS_TC;
14335331Samw 			break;
14345331Samw 		}
14355331Samw 
14365331Samw 		if (net_ipaddr != 0) {
14375331Samw 			struct sockaddr_in *s_in;
14385331Samw 			int s;
14395331Samw 
14405331Samw 			s = socket(AF_INET, SOCK_DGRAM, 0);
14415331Samw 			/* LINTED - E_BAD_PTR_CAST_ALIGN */
14425331Samw 			s_in = (struct sockaddr_in *)&arpreq.arp_pa;
14435331Samw 			s_in->sin_family = AF_INET;
14445331Samw 			s_in->sin_addr.s_addr = net_ipaddr;
14455331Samw 			if (ioctl(s, SIOCGARP, (caddr_t)&arpreq) < 0) {
14465331Samw 				bzero(scan, 6);
14475331Samw 			} else {
14485331Samw 				bcopy(&arpreq.arp_ha.sa_data, scan, 6);
14495331Samw 			}
14505331Samw 			(void) close(s);
14515331Samw 		} else {
14525331Samw 			bzero(scan, 6);
14535331Samw 		}
14545331Samw 		scan += 6;
14555331Samw 
14565331Samw 		if ((scan + 26) >= scan_end) {
14575331Samw 			packet.info |= NAME_NM_FLAGS_TC;
14585331Samw 			break;
14595331Samw 		}
14605331Samw 		bzero(scan, 26);
14615331Samw 		scan += 26;
14625331Samw 
14635331Samw 		if ((scan + 2) >= scan_end) {
14645331Samw 			packet.info |= NAME_NM_FLAGS_TC;
14655331Samw 			break;
14665331Samw 		}
14675331Samw 		BE_OUT16(scan, 0); scan += 2;
14685331Samw 
14695331Samw 		if ((scan + 2) >= scan_end) {
14705331Samw 			packet.info |= NAME_NM_FLAGS_TC;
14715331Samw 			break;
14725331Samw 		}
14735331Samw 		BE_OUT16(scan, 0); scan += 2;
14745331Samw 
14755331Samw 		if ((scan + 2) >= scan_end) {
14765331Samw 			packet.info |= NAME_NM_FLAGS_TC;
14775331Samw 			break;
14785331Samw 		}
14795331Samw 		BE_OUT16(scan, 0); scan += 2;
14805331Samw 
14815331Samw 		if ((scan + 2) >= scan_end) {
14825331Samw 			packet.info |= NAME_NM_FLAGS_TC;
14835331Samw 			break;
14845331Samw 		}
14855331Samw 		BE_OUT16(scan, 0); scan += 2;
14865331Samw 
14875331Samw 		if ((scan + 2) >= scan_end) {
14885331Samw 			packet.info |= NAME_NM_FLAGS_TC;
14895331Samw 			break;
14905331Samw 		}
14915331Samw 		BE_OUT16(scan, 0); scan += 2;
14925331Samw 
14935331Samw 		if ((scan + 2) >= scan_end) {
14945331Samw 			packet.info |= NAME_NM_FLAGS_TC;
14955331Samw 			break;
14965331Samw 		}
14975331Samw 		BE_OUT16(scan, 0); scan += 2;
14985331Samw 
14995331Samw 		if ((scan + 2) >= scan_end) {
15005331Samw 			packet.info |= NAME_NM_FLAGS_TC;
15015331Samw 			break;
15025331Samw 		}
15035331Samw 		BE_OUT16(scan, 0); scan += 2;
15045331Samw 
15055331Samw 		if ((scan + 2) >= scan_end) {
15065331Samw 			packet.info |= NAME_NM_FLAGS_TC;
15075331Samw 			break;
15085331Samw 		}
15095331Samw 		BE_OUT16(scan, max_connections); scan += 2;
15105331Samw 
15115331Samw 		if ((scan + 2) >= scan_end) {
15125331Samw 			packet.info |= NAME_NM_FLAGS_TC;
15135331Samw 			break;
15145331Samw 		}
15155331Samw 
15165331Samw 		BE_OUT16(scan, 0); scan += 2;
15175331Samw 
15185521Sas200622 		scan_done = B_TRUE;
15195331Samw 	}
15205331Samw 	answer.rdlength = scan - data;
15215331Samw 	return (smb_send_name_service_packet(addr, &packet));
15225331Samw }
15235331Samw 
15245331Samw static int
smb_name_Bnode_add_name(struct name_entry * name)15255331Samw smb_name_Bnode_add_name(struct name_entry *name)
15265331Samw {
15275331Samw 	struct name_question		question;
15285331Samw 	struct resource_record		additional;
15295331Samw 	unsigned char 			data[8];
153010717Samw@Sun.COM 	uint16_t			attr;
153110717Samw@Sun.COM 	addr_entry_t			*addr;
15325331Samw 	int rc = 0;
15335331Samw 
15345331Samw 	addr = &name->addr_list;
15355331Samw 
15365331Samw 	do {
15375331Samw 		/* build name service packet */
15385331Samw 		question.name = name;
15395331Samw 		/*
15405331Samw 		 * question.name->attributes |= NAME_NB_FLAGS_ONT_B;
15415331Samw 		 * This is commented because NAME_NB_FLAGS_ONT_B is 0
15425331Samw 		 */
15435331Samw 		question.question_type = NAME_QUESTION_TYPE_NB;
15445331Samw 		question.question_class = NAME_QUESTION_CLASS_IN;
15455331Samw 
15465331Samw 		additional.name = name;
15475331Samw 		additional.rr_class = NAME_QUESTION_CLASS_IN;
15485331Samw 		additional.ttl = 0;
15495331Samw 		additional.rdata = data;
15505331Samw 		additional.rdlength = 6;
15515331Samw 		additional.rr_type = NAME_QUESTION_TYPE_NB;
15525331Samw 		attr = name->attributes & (NAME_ATTR_GROUP |
15535331Samw 		    NAME_ATTR_OWNER_NODE_TYPE);
15545331Samw 
15555331Samw 		BE_OUT16(&data[0], attr);
15565331Samw 		(void) memcpy(&data[2], &addr->sin.sin_addr.s_addr,
15575331Samw 		    sizeof (uint32_t));
15585331Samw 
15595331Samw 		rc |= smb_send_name_registration_request(BROADCAST, &question,
15605331Samw 		    &additional);
15615331Samw 		addr = addr->forw;
15625331Samw 
15635331Samw 	} while (addr != &name->addr_list);
15645331Samw 
15655331Samw 	return (rc);
15665331Samw }
15675331Samw 
15685331Samw static int
smb_name_Bnode_find_name(struct name_entry * name)15695331Samw smb_name_Bnode_find_name(struct name_entry *name)
15705331Samw {
15715331Samw 	struct name_question	question;
15725331Samw 
15735331Samw 	question.name = name;
15745331Samw 	question.question_type = NAME_QUESTION_TYPE_NB;
15755331Samw 	question.question_class = NAME_QUESTION_CLASS_IN;
15765331Samw 
15775331Samw 	return (smb_send_name_query_request(BROADCAST, &question));
15785331Samw }
15795331Samw 
15805331Samw static int
smb_name_Bnode_delete_name(struct name_entry * name)15815331Samw smb_name_Bnode_delete_name(struct name_entry *name)
15825331Samw {
15835331Samw 	struct name_question	question;
15845331Samw 	struct resource_record	additional;
158510717Samw@Sun.COM 	addr_entry_t		*raddr;
158610717Samw@Sun.COM 	unsigned char		data[MAX_DATAGRAM_LENGTH];
158710717Samw@Sun.COM 	unsigned char		*scan = data;
15885331Samw 	uint32_t		attr;
15899832Samw@Sun.COM 	uint32_t		ret_addr;
15905331Samw 
15915331Samw 	/* build packet */
15925331Samw 	question.name = name;
15935331Samw 	question.question_type = NAME_QUESTION_TYPE_NB;
15945331Samw 	question.question_class = NAME_QUESTION_CLASS_IN;
15955331Samw 
15965331Samw 	additional.name = name;
15975331Samw 	additional.rr_class = NAME_QUESTION_CLASS_IN;
15985331Samw 	additional.ttl = 0;
15995331Samw 	additional.rdata = data;
16005331Samw 	additional.rdlength = 0;
16015331Samw 	additional.rr_type = NAME_QUESTION_TYPE_NB;
16025331Samw 	raddr = &name->addr_list;
16035331Samw 	scan = data;
16045331Samw 	do {
16055331Samw 		attr = name->attributes & (NAME_ATTR_GROUP |
16065331Samw 		    NAME_ATTR_OWNER_NODE_TYPE);
16075331Samw 
16085331Samw 		BE_OUT16(scan, attr); scan += 2;
16099832Samw@Sun.COM 		ret_addr = LE_32(raddr->sin.sin_addr.s_addr);
16109832Samw@Sun.COM 		*scan++ = ret_addr;
16119832Samw@Sun.COM 		*scan++ = ret_addr >> 8;
16129832Samw@Sun.COM 		*scan++ = ret_addr >> 16;
16139832Samw@Sun.COM 		*scan++ = ret_addr >> 24;
16145331Samw 
16155331Samw 		additional.rdlength += 6;
16165331Samw 	} while (raddr != &name->addr_list);
16175331Samw 
16185331Samw 	return (smb_send_name_release_request_and_demand(BROADCAST,
16195331Samw 	    &question, &additional));
16205331Samw }
16215331Samw 
16225331Samw static int
smb_name_Pnode_add_name(struct name_entry * name)16235331Samw smb_name_Pnode_add_name(struct name_entry *name)
16245331Samw {
16255331Samw 	struct name_question		question;
16265331Samw 	struct resource_record		additional;
16275331Samw 	unsigned char 			data[8];
162810717Samw@Sun.COM 	uint16_t			attr;
162910717Samw@Sun.COM 	addr_entry_t			*addr;
16305331Samw 	int rc = 0;
16315331Samw 
16325331Samw 	/* build packet */
16335331Samw 	addr = &name->addr_list;
16345331Samw 	do {
16355331Samw 		question.name = name;
16365331Samw 		question.question_type = NAME_QUESTION_TYPE_NB;
16375331Samw 		question.question_class = NAME_QUESTION_CLASS_IN;
16385331Samw 
16395331Samw 		additional.name = name;
16405331Samw 		additional.rr_class = NAME_QUESTION_CLASS_IN;
16415331Samw 		additional.ttl = 0;
16425331Samw 		additional.rdata = data;
16435331Samw 		additional.rdlength = 6;
16445331Samw 		additional.rr_type = NAME_QUESTION_TYPE_NB;
16455331Samw 		attr = name->attributes &
16465331Samw 		    (NAME_ATTR_GROUP | NAME_ATTR_OWNER_NODE_TYPE);
16475331Samw 
16485331Samw 		BE_OUT16(&data[0], attr);
16495331Samw 		(void) memcpy(&data[2], &addr->sin.sin_addr.s_addr,
16505331Samw 		    sizeof (uint32_t));
16515331Samw 
16525331Samw 		rc |= smb_send_name_registration_request(UNICAST, &question,
16535331Samw 		    &additional);
16545331Samw 
16555331Samw 		addr = addr->forw;
16565331Samw 
16575331Samw 	} while (addr != &name->addr_list);
16585331Samw 
16595331Samw 	return (rc);
16605331Samw }
16615331Samw 
16625331Samw static int
smb_name_Pnode_refresh_name(struct name_entry * name)16635331Samw smb_name_Pnode_refresh_name(struct name_entry *name)
16645331Samw {
16655331Samw 	struct name_question		question;
16665331Samw 	struct resource_record		additional;
16675331Samw 	unsigned char 			data[8];
166810717Samw@Sun.COM 	uint16_t			attr;
166910717Samw@Sun.COM 	addr_entry_t			*addr;
16705331Samw 	int rc = 0;
16715331Samw 
16725331Samw 	/* build packet */
16735331Samw 	addr = &name->addr_list;
16745331Samw 	do {
16755331Samw 		question.name = name;
16765331Samw 		question.question_type = NAME_QUESTION_TYPE_NB;
16775331Samw 		question.question_class = NAME_QUESTION_CLASS_IN;
16785331Samw 
16795331Samw 		additional.name = name;
16805331Samw 		additional.rr_class = NAME_QUESTION_CLASS_IN;
16815331Samw 		additional.ttl = 0;
16825331Samw 		additional.rdata = data;
16835331Samw 		additional.rdlength = 6;
16845331Samw 		additional.rr_type = NAME_QUESTION_TYPE_NB;
16855331Samw 		attr = name->attributes &
16865331Samw 		    (NAME_ATTR_GROUP | NAME_ATTR_OWNER_NODE_TYPE);
16875331Samw 
16885331Samw 		BE_OUT16(&data[0], attr);
16895331Samw 		(void) memcpy(&data[2], &addr->sin.sin_addr.s_addr,
16905331Samw 		    sizeof (uint32_t));
16915331Samw 
16925331Samw 		rc |= smb_send_name_refresh_request(UNICAST, &question,
16935331Samw 		    &additional, 1);
16945331Samw 
16955331Samw 		addr = addr->forw;
16965331Samw 	} while (addr != &name->addr_list);
16975331Samw 
16985331Samw 	return (rc);
16995331Samw }
17005331Samw 
17015331Samw static int
smb_name_Pnode_find_name(struct name_entry * name)17025331Samw smb_name_Pnode_find_name(struct name_entry *name)
17035331Samw {
17045331Samw 	struct name_question	question;
17055331Samw 
17065331Samw 	/*
17075331Samw 	 * Host initiated processing for a P node
17085331Samw 	 */
17095331Samw 	question.name = name;
17105331Samw 	question.name->attributes |= NAME_NB_FLAGS_ONT_P;
17115331Samw 	question.question_type = NAME_QUESTION_TYPE_NB;
17125331Samw 	question.question_class = NAME_QUESTION_CLASS_IN;
17135331Samw 
17145331Samw 	return (smb_send_name_query_request(UNICAST, &question));
17155331Samw }
17165331Samw 
17175331Samw static int
smb_name_Pnode_delete_name(struct name_entry * name)17185331Samw smb_name_Pnode_delete_name(struct name_entry *name)
17195331Samw {
17205331Samw 	struct name_question	question;
17215331Samw 	struct resource_record	additional;
172210717Samw@Sun.COM 	addr_entry_t		*raddr;
172310717Samw@Sun.COM 	unsigned char		data[MAX_DATAGRAM_LENGTH];
172410717Samw@Sun.COM 	unsigned char		*scan = data;
17255331Samw 	uint32_t		attr;
17269832Samw@Sun.COM 	uint32_t		ret_addr;
17275331Samw 
17285331Samw 	/* build packet */
17295331Samw 	question.name = name;
17305331Samw 	question.name->attributes |= NAME_NB_FLAGS_ONT_P;
17315331Samw 	question.question_type = NAME_QUESTION_TYPE_NB;
17325331Samw 	question.question_class = NAME_QUESTION_CLASS_IN;
17335331Samw 
17345331Samw 	additional.name = name;
17355331Samw 	additional.rr_class = NAME_QUESTION_CLASS_IN;
17365331Samw 	additional.ttl = 0;
17375331Samw 	additional.rdata = data;
17385331Samw 	additional.rdlength = 0;
17395331Samw 	additional.rr_type = NAME_QUESTION_TYPE_NB;
17405331Samw 	raddr = &name->addr_list;
17415331Samw 	do {
17425331Samw 		scan = data;
17435331Samw 		attr = name->attributes & (NAME_ATTR_GROUP |
17445331Samw 		    NAME_ATTR_OWNER_NODE_TYPE);
17455331Samw 
17465331Samw 		BE_OUT16(scan, attr); scan += 2;
17479832Samw@Sun.COM 		ret_addr = LE_32(raddr->sin.sin_addr.s_addr);
17489832Samw@Sun.COM 		*scan++ = ret_addr;
17499832Samw@Sun.COM 		*scan++ = ret_addr >> 8;
17509832Samw@Sun.COM 		*scan++ = ret_addr >> 16;
17519832Samw@Sun.COM 		*scan++ = ret_addr >> 24;
17525331Samw 
17535331Samw 		additional.rdlength = 6;
17545331Samw 		raddr = raddr->forw;
17555331Samw 		(void) smb_send_name_release_request_and_demand(UNICAST,
17565331Samw 		    &question, &additional);
17575331Samw 	} while (raddr != &name->addr_list);
17585331Samw 
17595331Samw 	return (1);
17605331Samw }
17615331Samw 
17625331Samw static int
smb_name_Mnode_add_name(struct name_entry * name)17635331Samw smb_name_Mnode_add_name(struct name_entry *name)
17645331Samw {
17655331Samw 	if (smb_name_Bnode_add_name(name) > 0) {
17665331Samw 		if (nbns_num == 0)
17675331Samw 			return (1); /* No name server configured */
17685331Samw 
17695331Samw 		return (smb_name_Pnode_add_name(name));
17705331Samw 	}
17715331Samw 	return (-1);
17725331Samw }
17735331Samw 
17745331Samw static int
smb_name_Hnode_add_name(struct name_entry * name)17755331Samw smb_name_Hnode_add_name(struct name_entry *name)
17765331Samw {
17775331Samw 	if (nbns_num > 0) {
17785331Samw 		if (smb_name_Pnode_add_name(name) == 1)
17795331Samw 			return (1);
17805331Samw 	}
17815331Samw 
17825331Samw 	return (smb_name_Bnode_add_name(name));
17835331Samw }
17845331Samw 
17855331Samw static int
smb_name_Mnode_find_name(struct name_entry * name)17865331Samw smb_name_Mnode_find_name(struct name_entry *name)
17875331Samw {
17885331Samw 	if (smb_name_Bnode_find_name(name) == 1)
17895331Samw 		return (1);
17905331Samw 
17915331Samw 	if (nbns_num == 0)
17925331Samw 		return (1); /* No name server configured */
17935331Samw 
17945331Samw 	return (smb_name_Pnode_find_name(name));
17955331Samw }
17965331Samw 
17975331Samw static int
smb_name_Hnode_find_name(struct name_entry * name)17985331Samw smb_name_Hnode_find_name(struct name_entry *name)
17995331Samw {
18005331Samw 	if (nbns_num > 0)
18015331Samw 		if (smb_name_Pnode_find_name(name) == 1)
18025331Samw 			return (1);
18035331Samw 
18045331Samw 	return (smb_name_Bnode_find_name(name));
18055331Samw }
18065331Samw 
18075331Samw static int
smb_name_Mnode_delete_name(struct name_entry * name)18085331Samw smb_name_Mnode_delete_name(struct name_entry *name)
18095331Samw {
18105331Samw 	(void) smb_name_Bnode_delete_name(name);
18115331Samw 
18125331Samw 	if (nbns_num == 0)
18135331Samw 		return (-1); /* No name server configured */
18145331Samw 
18155331Samw 	if (smb_name_Pnode_delete_name(name) > 0)
18165331Samw 		return (1);
18175331Samw 
18185331Samw 	return (-1);
18195331Samw }
18205331Samw 
18215331Samw static int
smb_name_Hnode_delete_name(struct name_entry * name)18225331Samw smb_name_Hnode_delete_name(struct name_entry *name)
18235331Samw {
18245331Samw 	if (nbns_num > 0)
18255331Samw 		if (smb_name_Pnode_delete_name(name) > 0)
18265331Samw 			return (1);
18275331Samw 
18285331Samw 	return (smb_name_Bnode_delete_name(name));
18295331Samw }
18305331Samw 
18315331Samw static void
smb_name_process_Bnode_packet(struct name_packet * packet,addr_entry_t * addr)183210717Samw@Sun.COM smb_name_process_Bnode_packet(struct name_packet *packet, addr_entry_t *addr)
18335331Samw {
18345331Samw 	struct name_entry 	*name;
18355331Samw 	struct name_entry 	*entry;
18365331Samw 	struct name_question 	*question;
18375331Samw 	struct resource_record 	*additional;
18385331Samw 
18395331Samw 	question = packet->question;
18405331Samw 	additional = packet->additional;
18415331Samw 
18425331Samw 	switch (packet->info & NAME_OPCODE_OPCODE_MASK) {
18435331Samw 	case NAME_OPCODE_REFRESH:
18445331Samw 		/* Guard against malformed packets */
18455331Samw 		if ((question == 0) || (additional == 0))
18465331Samw 			break;
18475331Samw 		if (additional->name->addr_list.sin.sin_addr.s_addr == 0)
18485331Samw 			break;
18495331Samw 
18505331Samw 		name = question->name;
18515331Samw 		name->addr_list.ttl = additional->ttl;
18525331Samw 		name->attributes = additional->name->attributes;
18535331Samw 		name->addr_list.sin = additional->name->addr_list.sin;
18545331Samw 		name->addr_list.forw = name->addr_list.back = &name->addr_list;
18555331Samw 
18565331Samw 		if ((entry = smb_netbios_cache_lookup_addr(name)) != 0) {
18575331Samw 			smb_netbios_cache_update_entry(entry, question->name);
18585331Samw 			smb_netbios_cache_unlock_entry(entry);
18595331Samw 		}
18605331Samw 		else
18615331Samw 			(void) smb_netbios_cache_insert(question->name);
18625331Samw 		break;
18635331Samw 
18645331Samw 	case NAME_OPCODE_QUERY:
18655331Samw 		/*
18665331Samw 		 * This opcode covers both NAME_QUERY_REQUEST and
18675331Samw 		 * NODE_STATUS_REQUEST. They can be distinguished
18685331Samw 		 * based on the type of question entry.
18695331Samw 		 */
18705331Samw 
18715331Samw 		/* All query requests have to have question entry */
18725331Samw 		if (question == 0)
18735331Samw 			break;
18745331Samw 
18755331Samw 		if (question->question_type == NAME_QUESTION_TYPE_NB) {
18765331Samw 			name = question->name;
18775331Samw 			if ((entry = smb_netbios_cache_lookup(name)) != 0) {
18785331Samw 				(void) smb_send_name_query_response(addr,
18795331Samw 				    packet, entry, 0);
18805331Samw 				smb_netbios_cache_unlock_entry(entry);
18815331Samw 			}
18825331Samw 		}
18835331Samw 		else
18845331Samw 		if (question->question_type == NAME_QUESTION_TYPE_NBSTAT) {
18855331Samw 			/*
18865331Samw 			 * Name of "*" may be used to force node to
18875331Samw 			 * divulge status for administrative purposes
18885331Samw 			 */
18895331Samw 			name = question->name;
18905331Samw 			entry = 0;
18915331Samw 			if (NETBIOS_NAME_IS_STAR(name->name) ||
18925331Samw 			    ((entry = smb_netbios_cache_lookup(name)) != 0)) {
18935331Samw 				if (entry)
18945331Samw 					smb_netbios_cache_unlock_entry(entry);
18955331Samw 				/*
18965331Samw 				 * send only those names that are
18975331Samw 				 * in the same scope as the scope
18985331Samw 				 * field in the request packet
18995331Samw 				 */
19005331Samw 				(void) smb_send_node_status_response(addr,
19015331Samw 				    packet);
19025331Samw 			}
19035331Samw 		}
19045331Samw 		break;
19055331Samw 
19065331Samw 	default:
19075331Samw 		break;
19085331Samw 	}
19095331Samw }
19105331Samw 
19115331Samw static void
smb_name_process_Pnode_packet(struct name_packet * packet,addr_entry_t * addr)191210717Samw@Sun.COM smb_name_process_Pnode_packet(struct name_packet *packet, addr_entry_t *addr)
19135331Samw {
19145331Samw 	struct name_entry 	*name;
19155331Samw 	struct name_entry 	*entry;
19165331Samw 	struct name_question 	*question;
19175331Samw 	struct resource_record 	*additional;
19185331Samw 
19195331Samw 	question = packet->question;
19205331Samw 	additional = packet->additional;
19215331Samw 
19225331Samw 	if (packet->info & NAME_NM_FLAGS_B) {
19235331Samw 		/*
19245331Samw 		 * always ignore UDP broadcast packets
19255331Samw 		 */
19265331Samw 		return;
19275331Samw 	}
19285331Samw 
19295331Samw 	switch (packet->info & NAME_OPCODE_OPCODE_MASK) {
19305331Samw 	case NAME_OPCODE_REFRESH:
19315331Samw 		/* Guard against malformed packets */
19325331Samw 		if ((question == 0) || (additional == 0))
19335331Samw 			break;
19345331Samw 		if (additional->name->addr_list.sin.sin_addr.s_addr == 0)
19355331Samw 			break;
19365331Samw 
19375331Samw 		name = question->name;
19385331Samw 		name->addr_list.ttl = additional->ttl;
19395331Samw 		name->attributes = additional->name->attributes;
19405331Samw 		name->addr_list.sin = additional->name->addr_list.sin;
19415331Samw 		name->addr_list.forw = name->addr_list.back = &name->addr_list;
19425331Samw 
19435331Samw 		if ((entry = smb_netbios_cache_lookup(name)) != 0) {
19445331Samw 			smb_netbios_cache_update_entry(entry, name);
19455331Samw 			smb_netbios_cache_unlock_entry(entry);
19465331Samw 		}
19475331Samw 		else
19485331Samw 			(void) smb_netbios_cache_insert(name);
19495331Samw 
19505331Samw 		(void) smb_send_name_registration_response(addr, packet, 0);
19515331Samw 		break;
19525331Samw 
19535331Samw 	case NAME_OPCODE_QUERY:
19545331Samw 		/*
19555331Samw 		 * This opcode covers both NAME_QUERY_REQUEST and
19565331Samw 		 * NODE_STATUS_REQUEST. They can be distinguished
19575331Samw 		 * based on the type of question entry.
19585331Samw 		 */
19595331Samw 
19605331Samw 		/* All query requests have to have question entry */
19615331Samw 		if (question == 0)
19625331Samw 			break;
19635331Samw 
19645331Samw 		if (question->question_type == NAME_QUESTION_TYPE_NB) {
19655331Samw 			name = question->name;
19665331Samw 			if ((entry = smb_netbios_cache_lookup(name)) != 0) {
19675331Samw 				/*
19685331Samw 				 * send response to the IP address and port
19695331Samw 				 * number from which the request was received.
19705331Samw 				 */
19715331Samw 				(void) smb_send_name_query_response(addr,
19725331Samw 				    packet, entry, 0);
19735331Samw 				smb_netbios_cache_unlock_entry(entry);
19745331Samw 			} else {
19755331Samw 				/*
19765331Samw 				 * send response to the requestor
19775331Samw 				 */
19785331Samw 				(void) smb_send_name_query_response(addr,
19795331Samw 				    packet, name, RCODE_NAM_ERR);
19805331Samw 			}
19815331Samw 		}
19825331Samw 		else
19835331Samw 		if (question->question_type == NAME_QUESTION_TYPE_NBSTAT) {
19845331Samw 			/*
19855331Samw 			 * Name of "*" may be used to force node to
19865331Samw 			 * divulge status for administrative purposes
19875331Samw 			 */
19885331Samw 			name = question->name;
19895331Samw 			entry = 0;
19905331Samw 			if (NETBIOS_NAME_IS_STAR(name->name) ||
19915331Samw 			    ((entry = smb_netbios_cache_lookup(name)) != 0)) {
19925331Samw 				/*
19935331Samw 				 * send only those names that are
19945331Samw 				 * in the same scope as the scope
19955331Samw 				 * field in the request packet
19965331Samw 				 */
19975331Samw 				if (entry)
19985331Samw 					smb_netbios_cache_unlock_entry(entry);
19995331Samw 				(void) smb_send_node_status_response(addr,
20005331Samw 				    packet);
20015331Samw 			}
20025331Samw 		}
20035331Samw 		break;
20045331Samw 
20055331Samw 	default:
20065331Samw 		break;
20075331Samw 	}
20085331Samw }
20095331Samw 
20105331Samw static void
smb_name_process_Mnode_packet(struct name_packet * packet,addr_entry_t * addr)201110717Samw@Sun.COM smb_name_process_Mnode_packet(struct name_packet *packet, addr_entry_t *addr)
20125331Samw {
20135331Samw 	if (packet->info & NAME_NM_FLAGS_B)
20145331Samw 		smb_name_process_Bnode_packet(packet, addr);
20155331Samw 	else
20165331Samw 		smb_name_process_Pnode_packet(packet, addr);
20175331Samw }
20185331Samw 
20195331Samw static void
smb_name_process_Hnode_packet(struct name_packet * packet,addr_entry_t * addr)202010717Samw@Sun.COM smb_name_process_Hnode_packet(struct name_packet *packet, addr_entry_t *addr)
20215331Samw {
20225331Samw 	if (packet->info & NAME_NM_FLAGS_B)
20235331Samw 		smb_name_process_Bnode_packet(packet, addr);
20245331Samw 	else
20255331Samw 		smb_name_process_Pnode_packet(packet, addr);
20265331Samw }
20275331Samw 
20285331Samw 
20295331Samw /*
20305331Samw  * smb_netbios_name_tick
20315331Samw  *
20325331Samw  * Called once a second to handle name server timeouts.
20335331Samw  */
20345331Samw void
smb_netbios_name_tick(void)20355331Samw smb_netbios_name_tick(void)
20365331Samw {
20375331Samw 	struct name_entry *name;
20385331Samw 	struct name_entry *entry;
20395331Samw 
20405331Samw 	(void) mutex_lock(&refresh_queue.mtx);
20415331Samw 	smb_netbios_cache_refresh(&refresh_queue);
20425331Samw 
20435331Samw 	while ((name = refresh_queue.head.forw) != &refresh_queue.head) {
20445331Samw 		QUEUE_CLIP(name);
20455331Samw 		if (IS_LOCAL(name->attributes)) {
20465331Samw 			if (IS_UNIQUE(name->attributes)) {
20475331Samw 				(void) smb_name_Pnode_refresh_name(name);
20485331Samw 			}
20495331Samw 		} else {
20505331Samw 			entry = smb_name_find_name(name);
20515331Samw 			smb_name_unlock_name(entry);
20525331Samw 		}
20535331Samw 		free(name);
20545331Samw 	}
20555331Samw 	(void) mutex_unlock(&refresh_queue.mtx);
20565331Samw 
20575331Samw 	smb_netbios_cache_reset_ttl();
20585331Samw }
20595331Samw 
20605331Samw /*
20615331Samw  * smb_name_find_name
20625331Samw  *
20635331Samw  * Lookup name cache for the given name.
20645331Samw  * If it's not in the cache it'll send a
20655331Samw  * name query request and then lookup the
20665331Samw  * cache again. Note that if a name is
20675331Samw  * returned it's locked and called MUST
20685331Samw  * unlock it by calling smb_name_unlock_name()
20695331Samw  */
20705331Samw struct name_entry *
smb_name_find_name(struct name_entry * name)20715331Samw smb_name_find_name(struct name_entry *name)
20725331Samw {
20735331Samw 	struct name_entry *result;
20745331Samw 
20755331Samw 	if ((result = smb_netbios_cache_lookup(name)) == 0) {
20765331Samw 		switch (smb_node_type) {
20775331Samw 		case 'B':
20785331Samw 			(void) smb_name_Bnode_find_name(name);
20795331Samw 			break;
20805331Samw 		case 'P':
20815331Samw 			(void) smb_name_Pnode_find_name(name);
20825331Samw 			break;
20835331Samw 		case 'M':
20845331Samw 			(void) smb_name_Mnode_find_name(name);
20855331Samw 			break;
20865331Samw 		case 'H':
20875331Samw 		default:
20885331Samw 			(void) smb_name_Hnode_find_name(name);
20895331Samw 			break;
20905331Samw 		}
20915331Samw 		return (smb_netbios_cache_lookup(name));
20925331Samw 	}
20935331Samw 
20945331Samw 	return (result);
20955331Samw }
20965331Samw 
20975331Samw void
smb_name_unlock_name(struct name_entry * name)20985331Samw smb_name_unlock_name(struct name_entry *name)
20995331Samw {
21005331Samw 	smb_netbios_cache_unlock_entry(name);
21015331Samw }
21025331Samw 
21035331Samw int
smb_name_add_name(struct name_entry * name)21045331Samw smb_name_add_name(struct name_entry *name)
21055331Samw {
21065331Samw 	int			rc = 1;
21075331Samw 
210810717Samw@Sun.COM 	smb_netbios_name_logf(name);
21095331Samw 
21105331Samw 	switch (smb_node_type) {
21115331Samw 	case 'B':
21125331Samw 		rc = smb_name_Bnode_add_name(name);
21135331Samw 		break;
21145331Samw 	case 'P':
21155331Samw 		rc = smb_name_Pnode_add_name(name);
21165331Samw 		break;
21175331Samw 	case 'M':
21185331Samw 		rc = smb_name_Mnode_add_name(name);
21195331Samw 		break;
21205331Samw 	case 'H':
21215331Samw 	default:
21225331Samw 		rc = smb_name_Hnode_add_name(name);
21235331Samw 		break;
21245331Samw 	}
21255331Samw 
21265331Samw 	if (rc >= 0)
21275331Samw 		(void) smb_netbios_cache_insert(name);
21285331Samw 
21295331Samw 	return (rc);
21305331Samw }
21315331Samw 
21325331Samw int
smb_name_delete_name(struct name_entry * name)21335331Samw smb_name_delete_name(struct name_entry *name)
21345331Samw {
21355331Samw 	int			rc;
21365331Samw 	unsigned char type;
21375331Samw 
21385331Samw 	type = name->name[15];
213910717Samw@Sun.COM 	if ((type != NBT_WKSTA) && (type != NBT_SERVER)) {
214010717Samw@Sun.COM 		syslog(LOG_DEBUG, "nbns: name delete bad type (0x%02x)", type);
21415331Samw 		smb_netbios_name_logf(name);
21425331Samw 		name->attributes &= ~NAME_ATTR_LOCAL;
21435331Samw 		return (-1);
21445331Samw 	}
21455331Samw 
21465331Samw 	smb_netbios_cache_delete(name);
21475331Samw 
21485331Samw 	switch (smb_node_type) {
21495331Samw 	case 'B':
21505331Samw 		rc = smb_name_Bnode_delete_name(name);
21515331Samw 		break;
21525331Samw 	case 'P':
21535331Samw 		rc = smb_name_Pnode_delete_name(name);
21545331Samw 		break;
21555331Samw 	case 'M':
21565331Samw 		rc = smb_name_Mnode_delete_name(name);
21575331Samw 		break;
21585331Samw 	case 'H':
21595331Samw 	default:
21605331Samw 		rc = smb_name_Hnode_delete_name(name);
21615331Samw 		break;
21625331Samw 	}
21635331Samw 
21645331Samw 	if (rc > 0)
21655331Samw 		return (0);
21665331Samw 
21675331Samw 	return (-1);
21685331Samw }
21695331Samw 
21705331Samw typedef struct {
217110717Samw@Sun.COM 	addr_entry_t *addr;
21725331Samw 	char *buf;
21735331Samw 	int length;
21745331Samw } worker_param_t;
21755331Samw 
21765331Samw /*
21775331Samw  * smb_netbios_worker
21785331Samw  *
21795331Samw  * Process incoming request/response packets for Netbios
21805331Samw  * name service (on port 138).
21815331Samw  */
21825331Samw void *
smb_netbios_worker(void * arg)21835331Samw smb_netbios_worker(void *arg)
21845331Samw {
21855331Samw 	worker_param_t *p = (worker_param_t *)arg;
218610717Samw@Sun.COM 	addr_entry_t *addr = p->addr;
21875331Samw 	struct name_packet *packet;
21885331Samw 
218910717Samw@Sun.COM 	if ((packet = smb_name_buf_to_packet(p->buf, p->length)) != NULL) {
21905331Samw 		if (packet->info & NAME_OPCODE_R) {
21915331Samw 			/* Reply packet */
21925331Samw 			smb_reply_ready(packet, addr);
21935331Samw 			free(p->buf);
21945331Samw 			free(p);
219510717Samw@Sun.COM 			return (NULL);
21965331Samw 		}
21975331Samw 
21985331Samw 		/* Request packet */
21995331Samw 		switch (smb_node_type) {
22005331Samw 		case 'B':
22015331Samw 			smb_name_process_Bnode_packet(packet, addr);
22025331Samw 			break;
22035331Samw 		case 'P':
22045331Samw 			smb_name_process_Pnode_packet(packet, addr);
22055331Samw 			break;
22065331Samw 		case 'M':
22075331Samw 			smb_name_process_Mnode_packet(packet, addr);
22085331Samw 			break;
22095331Samw 		case 'H':
22105331Samw 		default:
22115331Samw 			smb_name_process_Hnode_packet(packet, addr);
22125331Samw 			break;
22135331Samw 		}
22145331Samw 
22155331Samw 		if (packet->answer)
22165331Samw 			smb_netbios_name_freeaddrs(packet->answer->name);
22175331Samw 		free(packet);
22186030Sjb150015 	} else {
221910717Samw@Sun.COM 		syslog(LOG_ERR, "nbns: packet decode failed");
22205331Samw 	}
22215331Samw 
22225331Samw 	free(addr);
22235331Samw 	free(p->buf);
22245331Samw 	free(p);
222510717Samw@Sun.COM 	return (NULL);
22265331Samw }
22275331Samw 
222810717Samw@Sun.COM /*
222910717Samw@Sun.COM  * Configure the node type.  If a WINS server has been specified,
223010717Samw@Sun.COM  * act like an H-node.  Otherwise, behave like a B-node.
223110717Samw@Sun.COM  */
22325331Samw static void
smb_netbios_node_config(void)223310717Samw@Sun.COM smb_netbios_node_config(void)
22345331Samw {
223510717Samw@Sun.COM 	static smb_cfg_id_t	wins[SMB_PI_MAX_WINS] = {
223610717Samw@Sun.COM 		SMB_CI_WINS_SRV1,
223710717Samw@Sun.COM 		SMB_CI_WINS_SRV2
223810717Samw@Sun.COM 	};
223910717Samw@Sun.COM 	char		ipstr[16];
224010717Samw@Sun.COM 	uint32_t	ipaddr;
224110717Samw@Sun.COM 	int		i;
22425331Samw 
224310717Samw@Sun.COM 	smb_node_type = SMB_NODETYPE_B;
224410717Samw@Sun.COM 	nbns_num = 0;
224510717Samw@Sun.COM 	bzero(smb_nbns, sizeof (addr_entry_t) * SMB_PI_MAX_WINS);
224610717Samw@Sun.COM 
224710717Samw@Sun.COM 	for (i = 0; i < SMB_PI_MAX_WINS; ++i) {
224810717Samw@Sun.COM 		ipstr[0] = '\0';
224910717Samw@Sun.COM 		(void) smb_config_getstr(wins[i], ipstr, sizeof (ipstr));
225010717Samw@Sun.COM 
225110717Samw@Sun.COM 		if ((ipaddr = inet_addr(ipstr)) == INADDR_NONE)
225210717Samw@Sun.COM 			continue;
225310717Samw@Sun.COM 
225410717Samw@Sun.COM 		smb_node_type = SMB_NODETYPE_H;
22555331Samw 		smb_nbns[nbns_num].flags = ADDR_FLAG_VALID;
22565331Samw 		smb_nbns[nbns_num].sinlen = sizeof (struct sockaddr_in);
22575331Samw 		smb_nbns[nbns_num].sin.sin_family = AF_INET;
22585331Samw 		smb_nbns[nbns_num].sin.sin_addr.s_addr = ipaddr;
225910717Samw@Sun.COM 		smb_nbns[nbns_num].sin.sin_port = htons(IPPORT_NETBIOS_NS);
226010717Samw@Sun.COM 		nbns_num++;
22616030Sjb150015 	}
22626030Sjb150015 }
22636030Sjb150015 
22646030Sjb150015 static void
smb_netbios_name_registration(void)22656030Sjb150015 smb_netbios_name_registration(void)
22666030Sjb150015 {
22676030Sjb150015 	nbcache_iter_t nbc_iter;
22686030Sjb150015 	struct name_entry *name;
22696030Sjb150015 	int rc;
22706030Sjb150015 
22716030Sjb150015 	rc = smb_netbios_cache_getfirst(&nbc_iter);
22726030Sjb150015 	while (rc == 0) {
22736030Sjb150015 		name = nbc_iter.nbc_entry;
22746030Sjb150015 		(void) smb_netbios_name_logf(name);
22756030Sjb150015 		if (IS_UNIQUE(name->attributes) && IS_LOCAL(name->attributes)) {
22766030Sjb150015 			switch (smb_node_type) {
22776030Sjb150015 			case SMB_NODETYPE_B:
22786030Sjb150015 				(void) smb_name_Bnode_add_name(name);
22796030Sjb150015 				break;
22806030Sjb150015 			case SMB_NODETYPE_P:
22816030Sjb150015 				(void) smb_name_Pnode_add_name(name);
22826030Sjb150015 				break;
22836030Sjb150015 			case SMB_NODETYPE_M:
22846030Sjb150015 				(void) smb_name_Mnode_add_name(name);
22856030Sjb150015 				break;
22866030Sjb150015 			case SMB_NODETYPE_H:
22876030Sjb150015 			default:
22886030Sjb150015 				(void) smb_name_Hnode_add_name(name);
22896030Sjb150015 				break;
22906030Sjb150015 			}
22916030Sjb150015 		}
22926030Sjb150015 		free(name);
22936030Sjb150015 		rc = smb_netbios_cache_getnext(&nbc_iter);
22945331Samw 	}
22955331Samw }
22965331Samw 
229710717Samw@Sun.COM /*
229810717Samw@Sun.COM  * Note that the node configuration must be setup before calling
229910717Samw@Sun.COM  * smb_init_name_struct().
230010717Samw@Sun.COM  */
23015331Samw void
smb_netbios_name_config(void)23025331Samw smb_netbios_name_config(void)
23035331Samw {
230410717Samw@Sun.COM 	addr_entry_t		*bcast_entry;
230510717Samw@Sun.COM 	struct name_entry	name;
230610717Samw@Sun.COM 	smb_niciter_t		ni;
230710717Samw@Sun.COM 	int			rc;
23085331Samw 
230910717Samw@Sun.COM 	(void) mutex_lock(&nbt_name_config_mtx);
231010717Samw@Sun.COM 	smb_netbios_node_config();
231110717Samw@Sun.COM 
23125331Samw 	bcast_num = 0;
23135331Samw 	bzero(smb_bcast_list, sizeof (addr_entry_t) * SMB_PI_MAX_NETWORKS);
23145331Samw 
23156030Sjb150015 	rc = smb_nic_getfirst(&ni);
2316*11963SAfshin.Ardakani@Sun.COM 	while (rc == SMB_NIC_SUCCESS) {
231710717Samw@Sun.COM 		if ((ni.ni_nic.nic_smbflags & SMB_NICF_NBEXCL) ||
231810717Samw@Sun.COM 		    (ni.ni_nic.nic_smbflags & SMB_NICF_ALIAS)) {
23196030Sjb150015 			rc = smb_nic_getnext(&ni);
23206030Sjb150015 			continue;
23215331Samw 		}
23225331Samw 
232310717Samw@Sun.COM 		bcast_entry = &smb_bcast_list[bcast_num];
232410717Samw@Sun.COM 		bcast_entry->flags = ADDR_FLAG_VALID;
232510717Samw@Sun.COM 		bcast_entry->attributes = NAME_ATTR_LOCAL;
232610717Samw@Sun.COM 		bcast_entry->sinlen = sizeof (struct sockaddr_in);
232710717Samw@Sun.COM 		bcast_entry->sin.sin_family = AF_INET;
232810717Samw@Sun.COM 		bcast_entry->sin.sin_port = htons(IPPORT_NETBIOS_NS);
232910717Samw@Sun.COM 		bcast_entry->sin.sin_addr.s_addr = ni.ni_nic.nic_bcast;
233010717Samw@Sun.COM 		bcast_num++;
23315331Samw 
23326030Sjb150015 		smb_init_name_struct((unsigned char *)ni.ni_nic.nic_host,
233310717Samw@Sun.COM 		    NBT_WKSTA, 0, ni.ni_nic.nic_ip.a_ipv4,
233410717Samw@Sun.COM 		    htons(IPPORT_NETBIOS_DGM),
23355331Samw 		    NAME_ATTR_UNIQUE, NAME_ATTR_LOCAL, &name);
23366030Sjb150015 		(void) smb_netbios_cache_insert(&name);
23376030Sjb150015 
23386030Sjb150015 		smb_init_name_struct((unsigned char *)ni.ni_nic.nic_host,
233910717Samw@Sun.COM 		    NBT_SERVER, 0, ni.ni_nic.nic_ip.a_ipv4,
234010717Samw@Sun.COM 		    htons(IPPORT_NETBIOS_DGM),
23416030Sjb150015 		    NAME_ATTR_UNIQUE, NAME_ATTR_LOCAL, &name);
23426030Sjb150015 		(void) smb_netbios_cache_insert(&name);
234310717Samw@Sun.COM 
234410717Samw@Sun.COM 		rc = smb_nic_getnext(&ni);
234510717Samw@Sun.COM 	}
23466030Sjb150015 
23476030Sjb150015 	smb_netbios_name_registration();
234810717Samw@Sun.COM 	(void) mutex_unlock(&nbt_name_config_mtx);
23495331Samw }
23505331Samw 
23515331Samw void
smb_netbios_name_unconfig(void)23525331Samw smb_netbios_name_unconfig(void)
23535331Samw {
23545331Samw 	struct name_entry *name;
23555331Samw 
235610717Samw@Sun.COM 	(void) mutex_lock(&nbt_name_config_mtx);
23575331Samw 	(void) mutex_lock(&delete_queue.mtx);
23585331Samw 	smb_netbios_cache_delete_locals(&delete_queue);
23595331Samw 
23605331Samw 	while ((name = delete_queue.head.forw) != &delete_queue.head) {
23615331Samw 		QUEUE_CLIP(name);
23625331Samw 		(void) smb_name_delete_name(name);
23635331Samw 		free(name);
23645331Samw 	}
23655331Samw 	(void) mutex_unlock(&delete_queue.mtx);
236610717Samw@Sun.COM 	(void) mutex_unlock(&nbt_name_config_mtx);
23675331Samw }
23685331Samw 
23695331Samw void
smb_netbios_name_reconfig(void)23705331Samw smb_netbios_name_reconfig(void)
23715331Samw {
23725331Samw 	smb_netbios_name_unconfig();
23735331Samw 	smb_netbios_name_config();
23745331Samw }
23755331Samw 
23765331Samw /*
237710717Samw@Sun.COM  * NetBIOS Name Service (port 137)
23785331Samw  */
23795331Samw /*ARGSUSED*/
23805331Samw void *
smb_netbios_name_service(void * arg)238110717Samw@Sun.COM smb_netbios_name_service(void *arg)
23825331Samw {
23835331Samw 	struct sockaddr_in	sin;
238410717Samw@Sun.COM 	addr_entry_t		*addr;
23855331Samw 	int			len;
23865331Samw 	int			flag = 1;
238710717Samw@Sun.COM 	char			*buf;
23885331Samw 	worker_param_t 		*worker_param;
23898670SJose.Borrego@Sun.COM 	smb_inaddr_t		ipaddr;
23905331Samw 
23915331Samw 	/*
23925331Samw 	 * Initialize reply_queue
23935331Samw 	 */
23945331Samw 	bzero(&reply_queue, sizeof (reply_queue));
23955331Samw 	reply_queue.forw = reply_queue.back = &reply_queue;
23965331Samw 
23975331Samw 	if ((name_sock = socket(AF_INET, SOCK_DGRAM, 0)) < 0) {
239810717Samw@Sun.COM 		syslog(LOG_ERR, "nbns: socket failed: %m");
239910717Samw@Sun.COM 		smb_netbios_event(NETBIOS_EVENT_ERROR);
240010717Samw@Sun.COM 		return (NULL);
24015331Samw 	}
24025331Samw 
240310717Samw@Sun.COM 	flag = 1;
240410717Samw@Sun.COM 	(void) setsockopt(name_sock, SOL_SOCKET, SO_REUSEADDR, &flag,
240510717Samw@Sun.COM 	    sizeof (flag));
240610717Samw@Sun.COM 	flag = 1;
24075331Samw 	(void) setsockopt(name_sock, SOL_SOCKET, SO_BROADCAST, &flag,
24085331Samw 	    sizeof (flag));
24095331Samw 
24105331Samw 	bzero(&sin, sizeof (struct sockaddr_in));
24115331Samw 	sin.sin_family = AF_INET;
241210717Samw@Sun.COM 	sin.sin_port = htons(IPPORT_NETBIOS_NS);
24135331Samw 	if (bind(name_sock, (struct sockaddr *)&sin, sizeof (sin)) != 0) {
241410717Samw@Sun.COM 		syslog(LOG_ERR, "nbns: bind(%d) failed: %m",
241510717Samw@Sun.COM 		    IPPORT_NETBIOS_NS);
24165331Samw 		(void) close(name_sock);
241710717Samw@Sun.COM 		smb_netbios_event(NETBIOS_EVENT_ERROR);
241810717Samw@Sun.COM 		return (NULL);
24195331Samw 	}
24205331Samw 
242110717Samw@Sun.COM 	smb_netbios_event(NETBIOS_EVENT_NS_START);
24225331Samw 
242310717Samw@Sun.COM 	while (smb_netbios_running()) {
242410717Samw@Sun.COM 		buf = malloc(MAX_DATAGRAM_LENGTH);
242510717Samw@Sun.COM 		addr = malloc(sizeof (addr_entry_t));
242610717Samw@Sun.COM 		if ((buf == NULL) || (addr == NULL)) {
242710717Samw@Sun.COM 			/* Sleep for 10 seconds and try again */
242810717Samw@Sun.COM 			free(addr);
242910717Samw@Sun.COM 			free(buf);
243010717Samw@Sun.COM 			smb_netbios_sleep(10);
24315331Samw 			continue;
24325331Samw 		}
243310717Samw@Sun.COM ignore:		bzero(addr, sizeof (addr_entry_t));
24345331Samw 		addr->sinlen = sizeof (addr->sin);
24355331Samw 		addr->forw = addr->back = addr;
24365331Samw 
24375331Samw 		if ((len = recvfrom(name_sock, buf, MAX_DATAGRAM_LENGTH,
24385331Samw 		    0, (struct sockaddr *)&addr->sin, &addr->sinlen)) < 0) {
24395331Samw 			if (errno == ENOMEM || errno == ENFILE ||
24405331Samw 			    errno == EMFILE) {
244110717Samw@Sun.COM 				/* Sleep for 10 seconds and try again */
24425331Samw 				free(buf);
24435331Samw 				free(addr);
244410717Samw@Sun.COM 				smb_netbios_sleep(10);
24455331Samw 				continue;
24465331Samw 			}
244710717Samw@Sun.COM 			syslog(LOG_ERR, "nbns: recvfrom failed: %m");
24485331Samw 			free(buf);
24495331Samw 			free(addr);
245010717Samw@Sun.COM 			smb_netbios_event(NETBIOS_EVENT_ERROR);
24515331Samw 			goto shutdown;
24525331Samw 		}
24535331Samw 
24545331Samw 		/* Ignore any incoming packets from myself... */
24558670SJose.Borrego@Sun.COM 
24568670SJose.Borrego@Sun.COM 		ipaddr.a_ipv4 = addr->sin.sin_addr.s_addr;
24578670SJose.Borrego@Sun.COM 		ipaddr.a_family = AF_INET;
24589021Samw@Sun.COM 		if (smb_nic_is_local(&ipaddr))
24595331Samw 			goto ignore;
24605331Samw 
24615331Samw 		/*
24625331Samw 		 * Launch a netbios worker to process the received packet.
24635331Samw 		 */
246410717Samw@Sun.COM 		worker_param = malloc(sizeof (worker_param_t));
24655331Samw 		if (worker_param) {
24665331Samw 			pthread_t worker;
24675331Samw 			pthread_attr_t tattr;
24685331Samw 
24695331Samw 			worker_param->addr = addr;
24705331Samw 			worker_param->buf = buf;
24715331Samw 			worker_param->length = len;
24725331Samw 
24735331Samw 			(void) pthread_attr_init(&tattr);
24745331Samw 			(void) pthread_attr_setdetachstate(&tattr,
24755331Samw 			    PTHREAD_CREATE_DETACHED);
24765331Samw 			(void) pthread_create(&worker, &tattr,
24775331Samw 			    smb_netbios_worker, worker_param);
24785331Samw 			(void) pthread_attr_destroy(&tattr);
24795331Samw 		}
24805331Samw 	}
24815331Samw 
24825331Samw shutdown:
248310717Samw@Sun.COM 	smb_netbios_event(NETBIOS_EVENT_NS_STOP);
248410717Samw@Sun.COM 	smb_netbios_wait(NETBIOS_EVENT_BROWSER_STOP);
24855331Samw 
248610717Samw@Sun.COM 	if (!smb_netbios_error())
24875331Samw 		smb_netbios_name_unconfig();
248810717Samw@Sun.COM 
24895331Samw 	(void) close(name_sock);
249010717Samw@Sun.COM 	return (NULL);
24915331Samw }
2492