xref: /illumos-gate/usr/src/lib/smbsrv/libsmbns/common/smbns_netbios_name.c (revision 48bbca816818409505a6e214d0911fda44e622e3)
1da6c28aaSamw /*
2da6c28aaSamw  * CDDL HEADER START
3da6c28aaSamw  *
4da6c28aaSamw  * The contents of this file are subject to the terms of the
5da6c28aaSamw  * Common Development and Distribution License (the "License").
6da6c28aaSamw  * You may not use this file except in compliance with the License.
7da6c28aaSamw  *
8da6c28aaSamw  * You can obtain a copy of the license at usr/src/OPENSOLARIS.LICENSE
9da6c28aaSamw  * or http://www.opensolaris.org/os/licensing.
10da6c28aaSamw  * See the License for the specific language governing permissions
11da6c28aaSamw  * and limitations under the License.
12da6c28aaSamw  *
13da6c28aaSamw  * When distributing Covered Code, include this CDDL HEADER in each
14da6c28aaSamw  * file and include the License file at usr/src/OPENSOLARIS.LICENSE.
15da6c28aaSamw  * If applicable, add the following below this CDDL HEADER, with the
16da6c28aaSamw  * fields enclosed by brackets "[]" replaced with your own identifying
17da6c28aaSamw  * information: Portions Copyright [yyyy] [name of copyright owner]
18da6c28aaSamw  *
19da6c28aaSamw  * CDDL HEADER END
20da6c28aaSamw  */
21da6c28aaSamw /*
229fb67ea3Safshin salek ardakani - Sun Microsystems - Irvine United States  * Copyright 2010 Sun Microsystems, Inc.  All rights reserved.
23da6c28aaSamw  * Use is subject to license terms.
24*48bbca81SDaniel Hoffman  * Copyright (c) 2016 by Delphix. All rights reserved.
25da6c28aaSamw  */
26da6c28aaSamw 
27da6c28aaSamw /*
28a0aa776eSAlan Wright  * NetBIOS name resolution node types.
29da6c28aaSamw  *
30a0aa776eSAlan Wright  * A B-node (broadcast node) uses broadcasts for name registration
31a0aa776eSAlan Wright  * and resolution.  Routers typically do not forward broadcasts and
32a0aa776eSAlan Wright  * only computers on the local subnet will respond.
33da6c28aaSamw  *
34a0aa776eSAlan Wright  * A P-node (peer-to-peer node) uses a NetBIOS name server (WINS)
35a0aa776eSAlan Wright  * to resolve NetBIOS names, which allows it to work across routers.
36a0aa776eSAlan Wright  * In order to function in a P-node environment, all computers must
37a0aa776eSAlan Wright  * be configured to use the NetBIOS name server because P-nodes do
38a0aa776eSAlan Wright  * not broadcast on the network.
39da6c28aaSamw  *
40a0aa776eSAlan Wright  * A mixed node (M-node) behaves as a B-node by default.  If it cannot
41a0aa776eSAlan Wright  * resolve the name via broadcast then it tries a NetBIOS name server
42a0aa776eSAlan Wright  * lookup (P-node).
43da6c28aaSamw  *
44a0aa776eSAlan Wright  * A hybrid node (H-node) behaves as a P-node by default.  If it cannot
45a0aa776eSAlan Wright  * resolve the name using a NetBIOS name server then it resorts to
46a0aa776eSAlan Wright  * broadcasts (B-node).
47da6c28aaSamw  *
48a0aa776eSAlan Wright  * NetBIOS Name Service Protocols
49da6c28aaSamw  *
50a0aa776eSAlan Wright  * A REQUEST packet is always sent to the well known UDP port 137.
51a0aa776eSAlan Wright  * The destination address is normally either the IP broadcast address or
52a0aa776eSAlan Wright  * the address of the NAME - the address of the NAME server it set up at
53a0aa776eSAlan Wright  * initialization time.  In rare cases, a request packet will be sent to
54a0aa776eSAlan Wright  * an end node, e.g.  a NAME QUERY REQUEST sent to "challenge" a node.
55da6c28aaSamw  *
56a0aa776eSAlan Wright  * A RESPONSE packet is always sent to the source UDP port and source IP
57a0aa776eSAlan Wright  * address of the request packet.
58da6c28aaSamw  *
59a0aa776eSAlan Wright  * A DEMAND packet must always be sent to the well known UDP port 137.
60a0aa776eSAlan Wright  * There is no restriction on the target IP address.
61da6c28aaSamw  *
62a0aa776eSAlan Wright  * A transaction ID is a value composed from the requestor's IP address and
63a0aa776eSAlan Wright  * a unique 16 bit value generated by the originator of the transaction.
64da6c28aaSamw  */
65da6c28aaSamw 
66da6c28aaSamw #include <unistd.h>
67da6c28aaSamw #include <syslog.h>
68da6c28aaSamw #include <stdlib.h>
69da6c28aaSamw #include <synch.h>
70da6c28aaSamw #include <errno.h>
71da6c28aaSamw #include <netdb.h>
72da6c28aaSamw #include <sys/socket.h>
73da6c28aaSamw #include <sys/sockio.h>
74da6c28aaSamw #include <arpa/inet.h>
75da6c28aaSamw #include <net/if_arp.h>
76da6c28aaSamw 
77da6c28aaSamw #include <smbsrv/libsmbns.h>
78da6c28aaSamw #include <smbns_netbios.h>
79da6c28aaSamw 
80a0aa776eSAlan Wright /*
81a0aa776eSAlan Wright  * RFC 1002 4.2.1.1.  HEADER
82a0aa776eSAlan Wright  */
83a0aa776eSAlan Wright #define	QUESTION_TYPE_NETBIOS_GENERAL	0x20
84a0aa776eSAlan Wright #define	QUESTION_TYPE_NETBIOS_STATUS	0x21
85a0aa776eSAlan Wright 
86a0aa776eSAlan Wright #define	QUESTION_CLASS_INTERNET		0x0001
87da6c28aaSamw 
88a0aa776eSAlan Wright /*
89a0aa776eSAlan Wright  * RFC 1002 4.2.1.3.  RESOURCE RECORD
90a0aa776eSAlan Wright  */
91a0aa776eSAlan Wright #define	RR_TYPE_IP_ADDRESS_RESOURCE	0x0001
92a0aa776eSAlan Wright #define	RR_TYPE_NAME_SERVER_RESOURCE	0x0002
93a0aa776eSAlan Wright #define	RR_TYPE_NULL_RESOURCE		0x000A
94a0aa776eSAlan Wright #define	RR_TYPE_NETBIOS_RESOURCE	0x0020
95a0aa776eSAlan Wright #define	RR_TYPE_NETBIOS_STATUS		0x0021
96a0aa776eSAlan Wright 
97a0aa776eSAlan Wright /*
98a0aa776eSAlan Wright  *
99a0aa776eSAlan Wright  * RESOURCE RECORD RR_CLASS field definitions
100a0aa776eSAlan Wright  */
101a0aa776eSAlan Wright #define	RR_CLASS_INTERNET_CLASS		0x0001
102a0aa776eSAlan Wright 
103a0aa776eSAlan Wright /*
104a0aa776eSAlan Wright  * NB_FLAGS field of the RESOURCE RECORD RDATA field for RR_TYPE of NB.
105a0aa776eSAlan Wright  */
106a0aa776eSAlan Wright #define	RR_FLAGS_NB_ONT_MASK		0x6000
107a0aa776eSAlan Wright #define	RR_FLAGS_NB_ONT_B_NODE		0x0000
108a0aa776eSAlan Wright #define	RR_FLAGS_NB_ONT_P_NODE		0x2000
109a0aa776eSAlan Wright #define	RR_FLAGS_NB_ONT_M_NODE		0x4000
110a0aa776eSAlan Wright #define	RR_FLAGS_NB_ONT_RESERVED	0x6000
111a0aa776eSAlan Wright #define	RR_FLAGS_NB_GROUP_NAME		0x8000
112a0aa776eSAlan Wright 
113a0aa776eSAlan Wright #define	NAME_FLAGS_PERMANENT_NAME	0x0200
114a0aa776eSAlan Wright #define	NAME_FLAGS_ACTIVE_NAME		0x0400
115a0aa776eSAlan Wright #define	NAME_FLAGS_CONFLICT		0x0800
116a0aa776eSAlan Wright #define	NAME_FLAGS_DEREGISTER		0x1000
117a0aa776eSAlan Wright #define	NAME_FLAGS_ONT_MASK		0x6000
118a0aa776eSAlan Wright #define	NAME_FLAGS_ONT_B_NODE		0x0000
119a0aa776eSAlan Wright #define	NAME_FLAGS_ONT_P_NODE		0x2000
120a0aa776eSAlan Wright #define	NAME_FLAGS_ONT_M_NODE		0x4000
121a0aa776eSAlan Wright #define	NAME_FLAGS_ONT_RESERVED		0x6000
122a0aa776eSAlan Wright #define	NAME_FLAGS_GROUP_NAME		0x8000
123a0aa776eSAlan Wright 
124a0aa776eSAlan Wright #define	MAX_NETBIOS_REPLY_DATA_SIZE	500
125a0aa776eSAlan Wright 
126a0aa776eSAlan Wright #define	NAME_HEADER_SIZE		12
127da6c28aaSamw 
128a0aa776eSAlan Wright typedef struct nbt_name_reply {
129a0aa776eSAlan Wright 	struct nbt_name_reply	*forw;
130a0aa776eSAlan Wright 	struct nbt_name_reply	*back;
131a0aa776eSAlan Wright 	struct name_packet	*packet;
132a0aa776eSAlan Wright 	addr_entry_t		*addr;
133a0aa776eSAlan Wright 	uint16_t		name_trn_id;
134a0aa776eSAlan Wright 	boolean_t		reply_ready;
135a0aa776eSAlan Wright } nbt_name_reply_t;
136a0aa776eSAlan Wright 
137a0aa776eSAlan Wright static nbt_name_reply_t reply_queue;
138da6c28aaSamw static mutex_t rq_mtx;
139a0aa776eSAlan Wright static cond_t rq_cv;
140da6c28aaSamw 
141a0aa776eSAlan Wright static mutex_t nbt_name_config_mtx;
142da6c28aaSamw 
143da6c28aaSamw static name_queue_t delete_queue;
144da6c28aaSamw static name_queue_t refresh_queue;
145da6c28aaSamw 
146da6c28aaSamw static int name_sock = 0;
147da6c28aaSamw 
148da6c28aaSamw static int bcast_num = 0;
149da6c28aaSamw static int nbns_num = 0;
150a0aa776eSAlan Wright static addr_entry_t smb_bcast_list[SMB_PI_MAX_NETWORKS];
151a0aa776eSAlan Wright static addr_entry_t smb_nbns[SMB_PI_MAX_WINS];
152da6c28aaSamw 
153a0aa776eSAlan Wright static int smb_netbios_process_response(uint16_t, addr_entry_t *,
154da6c28aaSamw     struct name_packet *, uint32_t);
155da6c28aaSamw 
156a0aa776eSAlan Wright static int smb_send_name_service_packet(addr_entry_t *addr,
157da6c28aaSamw     struct name_packet *packet);
158da6c28aaSamw 
159a0aa776eSAlan Wright /*
160a0aa776eSAlan Wright  * Allocate a transaction id.
161a0aa776eSAlan Wright  */
162a0aa776eSAlan Wright static uint16_t
163a0aa776eSAlan Wright smb_netbios_name_trn_id(void)
164a0aa776eSAlan Wright {
165a0aa776eSAlan Wright 	static uint16_t trn_id;
166a0aa776eSAlan Wright 	static mutex_t trn_id_mtx;
167a0aa776eSAlan Wright 
168a0aa776eSAlan Wright 	(void) mutex_lock(&trn_id_mtx);
169a0aa776eSAlan Wright 
170a0aa776eSAlan Wright 	do {
171a0aa776eSAlan Wright 		++trn_id;
172a0aa776eSAlan Wright 	} while (trn_id == 0 || trn_id == (uint16_t)-1);
173a0aa776eSAlan Wright 
174a0aa776eSAlan Wright 	(void) mutex_unlock(&trn_id_mtx);
175a0aa776eSAlan Wright 	return (trn_id);
176a0aa776eSAlan Wright }
177a0aa776eSAlan Wright 
178da6c28aaSamw static int
179a0aa776eSAlan Wright smb_end_node_challenge(nbt_name_reply_t *reply_info)
180da6c28aaSamw {
181da6c28aaSamw 	int			rc;
182da6c28aaSamw 	uint32_t		retry;
183a0aa776eSAlan Wright 	uint16_t		tid;
184da6c28aaSamw 	struct resource_record	*answer;
185da6c28aaSamw 	struct name_question	question;
186a0aa776eSAlan Wright 	addr_entry_t		*addr;
187da6c28aaSamw 	struct name_entry 	*destination;
188da6c28aaSamw 	struct name_packet	packet;
189da6c28aaSamw 	struct timespec 	st;
190da6c28aaSamw 
191da6c28aaSamw 	/*
192da6c28aaSamw 	 * The response packet has in it the address of the presumed owner
193da6c28aaSamw 	 * of the name.  Challenge that owner.  If owner either does not
194*48bbca81SDaniel Hoffman 	 * respond or indicates that they no longer own the name, claim the
195da6c28aaSamw 	 * name.  Otherwise, the name cannot be claimed.
196da6c28aaSamw 	 */
197da6c28aaSamw 
198da6c28aaSamw 	if ((answer = reply_info->packet->answer) == 0)
199da6c28aaSamw 		return (-1);
200da6c28aaSamw 
201da6c28aaSamw 	destination = answer->name;
202da6c28aaSamw 	question.name = answer->name;
203da6c28aaSamw 
204da6c28aaSamw 	packet.info = NAME_QUERY_REQUEST | NM_FLAGS_UNICAST;
205da6c28aaSamw 	packet.qdcount = 1;	/* question entries */
206da6c28aaSamw 	packet.question = &question;
207da6c28aaSamw 	packet.ancount = 0;	/* answer recs */
208da6c28aaSamw 	packet.answer = NULL;
209da6c28aaSamw 	packet.nscount = 0;	/* authority recs */
210da6c28aaSamw 	packet.authority = NULL;
211da6c28aaSamw 	packet.arcount = 0;	/* additional recs */
212da6c28aaSamw 	packet.additional = NULL;
213da6c28aaSamw 
214da6c28aaSamw 	addr = &destination->addr_list;
215da6c28aaSamw 	for (retry = 0; retry < UCAST_REQ_RETRY_COUNT; retry++) {
216a0aa776eSAlan Wright 		tid = smb_netbios_name_trn_id();
217da6c28aaSamw 		packet.name_trn_id = tid;
218da6c28aaSamw 		if (smb_send_name_service_packet(addr, &packet) >= 0) {
219da6c28aaSamw 			if ((rc = smb_netbios_process_response(tid, addr,
220da6c28aaSamw 			    &packet, UCAST_REQ_RETRY_TIMEOUT)) != 0)
221da6c28aaSamw 				return (rc);
222da6c28aaSamw 		}
223da6c28aaSamw 		st.tv_sec = 0;
224da6c28aaSamw 		st.tv_nsec = (UCAST_REQ_RETRY_TIMEOUT * 1000000);
225da6c28aaSamw 		(void) nanosleep(&st, 0);
226da6c28aaSamw 	}
227da6c28aaSamw 	/* No reply */
228da6c28aaSamw 	return (0);
229da6c28aaSamw }
230da6c28aaSamw 
231a0aa776eSAlan Wright static nbt_name_reply_t *
232a0aa776eSAlan Wright smb_name_get_reply(uint16_t tid, uint32_t timeout)
233da6c28aaSamw {
234a0aa776eSAlan Wright 	uint16_t		info;
235da6c28aaSamw 	struct resource_record	*answer;
236a0aa776eSAlan Wright 	nbt_name_reply_t 	*reply;
237da6c28aaSamw 	uint32_t 		wait_time, to_save; /* in millisecond */
238da6c28aaSamw 	struct timeval 		wt;
239da6c28aaSamw 	timestruc_t 		to;
240da6c28aaSamw 
241da6c28aaSamw 	to_save = timeout;
242a0aa776eSAlan Wright 	reply = malloc(sizeof (nbt_name_reply_t));
243a0aa776eSAlan Wright 	if (reply != NULL) {
244a0aa776eSAlan Wright 		reply->reply_ready = B_FALSE;
245da6c28aaSamw 		reply->name_trn_id = tid;
246da6c28aaSamw 		(void) mutex_lock(&rq_mtx);
247da6c28aaSamw 		QUEUE_INSERT_TAIL(&reply_queue, reply);
248da6c28aaSamw 		(void) mutex_unlock(&rq_mtx);
249da6c28aaSamw 
250da6c28aaSamw 		for (;;) {
251da6c28aaSamw 			(void) gettimeofday(&wt, 0);
252da6c28aaSamw 			wait_time = wt.tv_usec / 1000;
253da6c28aaSamw 
254da6c28aaSamw 			to.tv_sec = 0;
255da6c28aaSamw 			to.tv_nsec = timeout * 1000000;
256a0aa776eSAlan Wright 			(void) mutex_lock(&rq_mtx);
257a0aa776eSAlan Wright 			(void) cond_reltimedwait(&rq_cv, &rq_mtx, &to);
258a0aa776eSAlan Wright 			(void) mutex_unlock(&rq_mtx);
259da6c28aaSamw 
260a0aa776eSAlan Wright 			if (reply->reply_ready) {
261da6c28aaSamw 				info = reply->packet->info;
262da6c28aaSamw 				if (PACKET_TYPE(info) == WACK_RESPONSE) {
263da6c28aaSamw 					answer = reply->packet->answer;
264da6c28aaSamw 					wait_time = (answer) ?
265da6c28aaSamw 					    TO_MILLISECONDS(answer->ttl) :
266da6c28aaSamw 					    DEFAULT_TTL;
267da6c28aaSamw 					free(reply->addr);
268da6c28aaSamw 					free(reply->packet);
269da6c28aaSamw 					timeout = to_save + wait_time;
270a0aa776eSAlan Wright 					reply->reply_ready = B_FALSE;
271da6c28aaSamw 					reply->name_trn_id = tid;
272da6c28aaSamw 					(void) mutex_lock(&rq_mtx);
273da6c28aaSamw 					QUEUE_INSERT_TAIL(&reply_queue, reply);
274da6c28aaSamw 					(void) mutex_unlock(&rq_mtx);
275da6c28aaSamw 					continue;
276da6c28aaSamw 				}
277da6c28aaSamw 				return (reply);
278da6c28aaSamw 			}
279da6c28aaSamw 			(void) gettimeofday(&wt, 0);
280da6c28aaSamw 			wait_time = (wt.tv_usec / 1000) - wait_time;
281da6c28aaSamw 			if (wait_time >= timeout) {
282da6c28aaSamw 				(void) mutex_lock(&rq_mtx);
283da6c28aaSamw 				QUEUE_CLIP(reply);
284da6c28aaSamw 				(void) mutex_unlock(&rq_mtx);
285da6c28aaSamw 				free(reply);
286da6c28aaSamw 				break;
287da6c28aaSamw 			}
288da6c28aaSamw 			timeout -= wait_time;
289da6c28aaSamw 		}
290da6c28aaSamw 	}
291da6c28aaSamw 
292da6c28aaSamw 	return (0);
293da6c28aaSamw }
294da6c28aaSamw 
295da6c28aaSamw static void
296a0aa776eSAlan Wright smb_reply_ready(struct name_packet *packet, addr_entry_t *addr)
297da6c28aaSamw {
298a0aa776eSAlan Wright 	nbt_name_reply_t *reply;
299da6c28aaSamw 	struct resource_record *answer;
300da6c28aaSamw 
301da6c28aaSamw 	(void) mutex_lock(&rq_mtx);
302da6c28aaSamw 	for (reply = reply_queue.forw; reply != &reply_queue;
303da6c28aaSamw 	    reply = reply->forw) {
304da6c28aaSamw 		if (reply->name_trn_id == packet->name_trn_id) {
305da6c28aaSamw 			QUEUE_CLIP(reply);
306da6c28aaSamw 
307da6c28aaSamw 			reply->addr = addr;
308da6c28aaSamw 			reply->packet = packet;
309a0aa776eSAlan Wright 			reply->reply_ready = B_TRUE;
310a0aa776eSAlan Wright 			(void) cond_signal(&rq_cv);
311a0aa776eSAlan Wright 			(void) mutex_unlock(&rq_mtx);
312da6c28aaSamw 			return;
313da6c28aaSamw 		}
314da6c28aaSamw 	}
315da6c28aaSamw 	(void) mutex_unlock(&rq_mtx);
316da6c28aaSamw 
317da6c28aaSamw 	/* Presumably nobody is waiting any more... */
318da6c28aaSamw 	free(addr);
319da6c28aaSamw 
320da6c28aaSamw 	answer = packet->answer;
321da6c28aaSamw 	if (answer)
322da6c28aaSamw 		smb_netbios_name_freeaddrs(answer->name);
323da6c28aaSamw 	free(packet);
324da6c28aaSamw }
325da6c28aaSamw 
326da6c28aaSamw static int
327a0aa776eSAlan Wright smb_netbios_process_response(uint16_t tid, addr_entry_t *addr,
328da6c28aaSamw     struct name_packet *packet, uint32_t timeout)
329da6c28aaSamw {
330da6c28aaSamw 	int			rc = 0;
331a0aa776eSAlan Wright 	uint16_t		info;
332a0aa776eSAlan Wright 	nbt_name_reply_t 	*reply;
333da6c28aaSamw 	struct resource_record	*answer;
334da6c28aaSamw 	struct name_entry 	*name;
335da6c28aaSamw 	struct name_entry 	*entry;
336da6c28aaSamw 	struct name_question 	*question;
337da6c28aaSamw 	uint32_t 		ttl;
338da6c28aaSamw 
339da6c28aaSamw 	if ((reply = smb_name_get_reply(tid, timeout)) == 0) {
340da6c28aaSamw 		return (0); /* No reply: retry */
341da6c28aaSamw 	}
342da6c28aaSamw 	info = reply->packet->info;
343da6c28aaSamw 	answer = reply->packet->answer;
344da6c28aaSamw 
345da6c28aaSamw 	/* response */
346da6c28aaSamw 	switch (PACKET_TYPE(info)) {
347da6c28aaSamw 	case NAME_QUERY_RESPONSE:
348da6c28aaSamw 		if (POSITIVE_RESPONSE(info)) {
349da6c28aaSamw 			addr = &answer->name->addr_list;
350da6c28aaSamw 			do {
351da6c28aaSamw 				/*
352da6c28aaSamw 				 * Make sure that remote name is not
353da6c28aaSamw 				 * flagged local
354da6c28aaSamw 				 */
355da6c28aaSamw 				addr->attributes &= ~NAME_ATTR_LOCAL;
356da6c28aaSamw 
357a0aa776eSAlan Wright 				if (answer->ttl)
358a0aa776eSAlan Wright 					addr->ttl = answer->ttl;
359a0aa776eSAlan Wright 				else
360a0aa776eSAlan Wright 					addr->ttl = DEFAULT_TTL;
361a0aa776eSAlan Wright 				addr->refresh_ttl = TO_SECONDS(addr->ttl);
362a0aa776eSAlan Wright 				addr->ttl = addr->refresh_ttl;
363a0aa776eSAlan Wright 
364da6c28aaSamw 				addr = addr->forw;
365da6c28aaSamw 			} while (addr != &answer->name->addr_list);
366a0aa776eSAlan Wright 			smb_netbios_name_logf(answer->name);
367da6c28aaSamw 			(void) smb_netbios_cache_insert_list(answer->name);
368da6c28aaSamw 			rc = 1;
369da6c28aaSamw 		} else {
370da6c28aaSamw 			rc = -1;
371da6c28aaSamw 		}
372da6c28aaSamw 		break;
373da6c28aaSamw 
374da6c28aaSamw 	case NAME_REGISTRATION_RESPONSE:
375da6c28aaSamw 		if (NEGATIVE_RESPONSE(info)) {
376da6c28aaSamw 			if (RCODE(info) == RCODE_CFT_ERR) {
377da6c28aaSamw 				if (answer == 0) {
378da6c28aaSamw 					rc = -RCODE(info);
379da6c28aaSamw 					break;
380da6c28aaSamw 				}
381da6c28aaSamw 
382da6c28aaSamw 				name = answer->name;
383da6c28aaSamw 				entry = smb_netbios_cache_lookup(name);
384da6c28aaSamw 				if (entry) {
385da6c28aaSamw 					/*
386da6c28aaSamw 					 * a name in the state "conflict
387da6c28aaSamw 					 * detected" does not "logically" exist
388da6c28aaSamw 					 * on that node. No further session
389da6c28aaSamw 					 * will be accepted on that name.
390da6c28aaSamw 					 * No datagrams can be sent against
391da6c28aaSamw 					 * that name.
392da6c28aaSamw 					 * Such an entry will not be used for
393da6c28aaSamw 					 * purposes of processing incoming
394da6c28aaSamw 					 * request packets.
395da6c28aaSamw 					 * The only valid user NetBIOS operation
396da6c28aaSamw 					 * against such a name is DELETE NAME.
397da6c28aaSamw 					 */
398da6c28aaSamw 					entry->attributes |= NAME_ATTR_CONFLICT;
399da6c28aaSamw 					syslog(LOG_DEBUG,
400a0aa776eSAlan Wright 					    "nbns: name conflict: %15.15s",
401da6c28aaSamw 					    entry->name);
402da6c28aaSamw 					smb_netbios_cache_unlock_entry(entry);
403da6c28aaSamw 				}
404da6c28aaSamw 			}
405da6c28aaSamw 			rc = -RCODE(info);
406da6c28aaSamw 			break;
407da6c28aaSamw 		}
408da6c28aaSamw 
409da6c28aaSamw 		/*
410da6c28aaSamw 		 * name can be added:
411da6c28aaSamw 		 *   adjust refresh timeout value,
412da6c28aaSamw 		 *   TTL, for this name
413da6c28aaSamw 		 */
414da6c28aaSamw 		question = packet->question;
415a0aa776eSAlan Wright 		ttl = (answer && answer->ttl) ? answer->ttl : DEFAULT_TTL;
416a0aa776eSAlan Wright 		ttl = TO_SECONDS(ttl);
417da6c28aaSamw 		if ((entry = smb_netbios_cache_lookup(question->name)) != 0) {
418da6c28aaSamw 			addr = &entry->addr_list;
419da6c28aaSamw 			do {
420da6c28aaSamw 				if ((addr->refresh_ttl == 0) ||
421da6c28aaSamw 				    (ttl < addr->refresh_ttl))
422da6c28aaSamw 					addr->refresh_ttl = addr->ttl = ttl;
423da6c28aaSamw 				addr = addr->forw;
424da6c28aaSamw 			} while (addr != &entry->addr_list);
425da6c28aaSamw 			smb_netbios_cache_unlock_entry(entry);
426da6c28aaSamw 		}
427da6c28aaSamw 
428da6c28aaSamw 		rc = 1;
429da6c28aaSamw 		break;
430da6c28aaSamw 
431da6c28aaSamw 	case NAME_RELEASE_RESPONSE:
432da6c28aaSamw 		rc = 1;
433da6c28aaSamw 		break;
434da6c28aaSamw 
435da6c28aaSamw 	case END_NODE_CHALLENGE_REGISTRATION_REQUEST:
436da6c28aaSamw 		/*
437da6c28aaSamw 		 * The response packet has in it the
438da6c28aaSamw 		 * address of the presumed owner of the
439da6c28aaSamw 		 * name.  Challenge that owner.  If
440da6c28aaSamw 		 * owner either does not respond or
441*48bbca81SDaniel Hoffman 		 * indicates that they no longer own the
442da6c28aaSamw 		 * name, claim the name.  Otherwise,
443da6c28aaSamw 		 * the name cannot be claimed.
444da6c28aaSamw 		 */
445da6c28aaSamw 		rc = smb_end_node_challenge(reply);
446da6c28aaSamw 		break;
447da6c28aaSamw 
448da6c28aaSamw 	default:
449da6c28aaSamw 		rc = 0;
450da6c28aaSamw 		break;
451da6c28aaSamw 	}
452da6c28aaSamw 
453da6c28aaSamw 	if (answer)
454da6c28aaSamw 		smb_netbios_name_freeaddrs(answer->name);
455da6c28aaSamw 	free(reply->addr);
456da6c28aaSamw 	free(reply->packet);
457da6c28aaSamw 	free(reply);
458da6c28aaSamw 	return (rc);  /* retry */
459da6c28aaSamw }
460da6c28aaSamw 
461da6c28aaSamw /*
462da6c28aaSamw  * smb_name_buf_from_packet
463da6c28aaSamw  *
464da6c28aaSamw  * Description:
465da6c28aaSamw  *	Convert a NetBIOS Name Server Packet Block (npb)
466da6c28aaSamw  *	into the bits and bytes destined for the wire.
467da6c28aaSamw  *	The "buf" is used as a heap.
468da6c28aaSamw  *
469da6c28aaSamw  * Inputs:
470da6c28aaSamw  *	char *		buf	-> Buffer, from the wire
471da6c28aaSamw  *	unsigned	n_buf	-> Length of 'buf'
472da6c28aaSamw  *	name_packet	*npb	-> Packet block, decode into
473da6c28aaSamw  *	unsigned	n_npb	-> Max bytes in 'npb'
474da6c28aaSamw  *
475da6c28aaSamw  * Returns:
476da6c28aaSamw  *	>0	-> Encode successful, value is length of packet in "buf"
477da6c28aaSamw  *	-1	-> Hard error, can not possibly encode
478da6c28aaSamw  *	-2	-> Need more memory in buf -- it's too small
479da6c28aaSamw  */
480da6c28aaSamw static int
481a0aa776eSAlan Wright smb_name_buf_from_packet(unsigned char *buf, int n_buf,
482da6c28aaSamw     struct name_packet *npb)
483da6c28aaSamw {
484a0aa776eSAlan Wright 	addr_entry_t		*raddr;
485da6c28aaSamw 	unsigned char 		*heap = buf;
486da6c28aaSamw 	unsigned char 		*end_heap = heap + n_buf;
487da6c28aaSamw 	unsigned char 		*dnptrs[32];
488da6c28aaSamw 	unsigned char		comp_name_buf[MAX_NAME_LENGTH];
489da6c28aaSamw 	unsigned int		tmp;
490da6c28aaSamw 	int			i, step;
491da6c28aaSamw 
492da6c28aaSamw 	if (n_buf < NAME_HEADER_SIZE)
493da6c28aaSamw 		return (-1);		/* no header, impossible */
494da6c28aaSamw 
495da6c28aaSamw 	dnptrs[0] = heap;
496da6c28aaSamw 	dnptrs[1] = 0;
497da6c28aaSamw 
498da6c28aaSamw 	BE_OUT16(heap, npb->name_trn_id);
499da6c28aaSamw 	heap += 2;
500da6c28aaSamw 
501da6c28aaSamw 	BE_OUT16(heap, npb->info);
502da6c28aaSamw 	heap += 2;
503da6c28aaSamw 
504da6c28aaSamw 	BE_OUT16(heap, npb->qdcount);
505da6c28aaSamw 	heap += 2;
506da6c28aaSamw 
507da6c28aaSamw 	BE_OUT16(heap, npb->ancount);
508da6c28aaSamw 	heap += 2;
509da6c28aaSamw 
510da6c28aaSamw 	BE_OUT16(heap, npb->nscount);
511da6c28aaSamw 	heap += 2;
512da6c28aaSamw 
513da6c28aaSamw 	BE_OUT16(heap, npb->arcount);
514da6c28aaSamw 	heap += 2;
515da6c28aaSamw 
516da6c28aaSamw 	for (i = 0; i < npb->qdcount; i++) {
517da6c28aaSamw 		if ((heap + 34 + 4) > end_heap)
518da6c28aaSamw 			return (-2);
519da6c28aaSamw 
520da6c28aaSamw 		(void) smb_first_level_name_encode(npb->question[i].name,
521da6c28aaSamw 		    comp_name_buf, sizeof (comp_name_buf));
522da6c28aaSamw 		(void) strcpy((char *)heap, (char *)comp_name_buf);
523da6c28aaSamw 		heap += strlen((char *)comp_name_buf) + 1;
524da6c28aaSamw 
525da6c28aaSamw 		BE_OUT16(heap, npb->question[i].question_type);
526da6c28aaSamw 		heap += 2;
527da6c28aaSamw 
528da6c28aaSamw 		BE_OUT16(heap, npb->question[i].question_class);
529da6c28aaSamw 		heap += 2;
530da6c28aaSamw 	}
531da6c28aaSamw 
532da6c28aaSamw 	for (step = 1; step <= 3; step++) {
533da6c28aaSamw 		struct resource_record *nrr;
534da6c28aaSamw 		int n;
535da6c28aaSamw 
536da6c28aaSamw 		/* truly ugly, but saves code copying */
537da6c28aaSamw 		if (step == 1) {
538da6c28aaSamw 			n = npb->ancount;
539da6c28aaSamw 			nrr = npb->answer;
540da6c28aaSamw 		} else if (step == 2) {
541da6c28aaSamw 			n = npb->nscount;
542da6c28aaSamw 			nrr = npb->authority;
543da6c28aaSamw 		} else { /* step == 3 */
544da6c28aaSamw 			n = npb->arcount;
545da6c28aaSamw 			nrr = npb->additional;
546da6c28aaSamw 		}
547da6c28aaSamw 
548da6c28aaSamw 		for (i = 0; i < n; i++) {
549da6c28aaSamw 			if ((heap + 34 + 10) > end_heap)
550da6c28aaSamw 				return (-2);
551da6c28aaSamw 
552da6c28aaSamw 			(void) smb_first_level_name_encode(nrr->name,
553da6c28aaSamw 			    comp_name_buf, sizeof (comp_name_buf));
554da6c28aaSamw 			(void) strcpy((char *)heap, (char *)comp_name_buf);
555da6c28aaSamw 			heap += strlen((char *)comp_name_buf) + 1;
556da6c28aaSamw 
557da6c28aaSamw 			BE_OUT16(heap, nrr[i].rr_type);
558da6c28aaSamw 			heap += 2;
559da6c28aaSamw 
560da6c28aaSamw 			BE_OUT16(heap, nrr[i].rr_class);
561da6c28aaSamw 			heap += 2;
562da6c28aaSamw 
563da6c28aaSamw 			BE_OUT32(heap, nrr[i].ttl);
564da6c28aaSamw 			heap += 4;
565da6c28aaSamw 
566da6c28aaSamw 			BE_OUT16(heap, nrr[i].rdlength);
567da6c28aaSamw 			heap += 2;
568da6c28aaSamw 
569da6c28aaSamw 			if ((tmp = nrr[i].rdlength) > 0) {
570da6c28aaSamw 				if ((heap + tmp) > end_heap)
571da6c28aaSamw 					return (-2);
572da6c28aaSamw 
573da6c28aaSamw 				if (nrr[i].rr_type == NAME_RR_TYPE_NB &&
574da6c28aaSamw 				    nrr[i].rr_class == NAME_RR_CLASS_IN &&
575da6c28aaSamw 				    tmp >= 6 && nrr[i].rdata == 0) {
576da6c28aaSamw 					tmp = nrr[i].name->attributes &
577da6c28aaSamw 					    (NAME_ATTR_GROUP |
578da6c28aaSamw 					    NAME_ATTR_OWNER_NODE_TYPE);
579da6c28aaSamw 					BE_OUT16(heap, tmp);
580da6c28aaSamw 					heap += 2;
581da6c28aaSamw 
582da6c28aaSamw 					raddr = &nrr[i].name->addr_list;
583da6c28aaSamw 					(void) memcpy(heap,
584da6c28aaSamw 					    &raddr->sin.sin_addr.s_addr,
585da6c28aaSamw 					    sizeof (uint32_t));
586da6c28aaSamw 					heap += 4;
587da6c28aaSamw 				} else {
588da6c28aaSamw 					bcopy(nrr[i].rdata, heap, tmp);
589da6c28aaSamw 					heap += tmp;
590da6c28aaSamw 				}
591da6c28aaSamw 			}
592da6c28aaSamw 		}
593da6c28aaSamw 	}
594da6c28aaSamw 	return (heap - buf);
595da6c28aaSamw }
596da6c28aaSamw 
597da6c28aaSamw /*
598da6c28aaSamw  * strnchr
599da6c28aaSamw  *
600da6c28aaSamw  * Lookup for character 'c' in first 'n' chars of string 's'.
601da6c28aaSamw  * Returns pointer to the found char, otherwise returns 0.
602da6c28aaSamw  */
603da6c28aaSamw static char *
604da6c28aaSamw strnchr(const char *s, char c, int n)
605da6c28aaSamw {
606da6c28aaSamw 	char *ps = (char *)s;
607da6c28aaSamw 	char *es = (char *)s + n;
608da6c28aaSamw 
609da6c28aaSamw 	while (ps < es && *ps) {
610da6c28aaSamw 		if (*ps == c)
611da6c28aaSamw 			return (ps);
612da6c28aaSamw 
613da6c28aaSamw 		++ps;
614da6c28aaSamw 	}
615da6c28aaSamw 
616da6c28aaSamw 	if (*ps == '\0' && c == '\0')
617da6c28aaSamw 		return (ps);
618da6c28aaSamw 
619da6c28aaSamw 	return (0);
620da6c28aaSamw }
621da6c28aaSamw 
6227b59d02dSjb static boolean_t
623da6c28aaSamw is_multihome(char *name)
624da6c28aaSamw {
6257b59d02dSjb 	return (smb_nic_getnum(name) > 1);
626da6c28aaSamw }
627da6c28aaSamw 
628da6c28aaSamw /*
629da6c28aaSamw  * smb_netbios_getname
630da6c28aaSamw  *
631da6c28aaSamw  * Get the Netbios name part of the given record.
632da6c28aaSamw  * Does some boundary checks.
633da6c28aaSamw  *
634da6c28aaSamw  * Returns the name length on success, otherwise
635da6c28aaSamw  * returns 0.
636da6c28aaSamw  */
637da6c28aaSamw static int
638da6c28aaSamw smb_netbios_getname(char *name, char *buf, char *buf_end)
639da6c28aaSamw {
640da6c28aaSamw 	char *name_end;
641da6c28aaSamw 	int name_len;
642da6c28aaSamw 
643da6c28aaSamw 	if (buf >= buf_end) {
644da6c28aaSamw 		/* no room for a NB name */
645da6c28aaSamw 		return (0);
646da6c28aaSamw 	}
647da6c28aaSamw 
648da6c28aaSamw 	name_end = strnchr(buf, '\0', buf_end - buf + 1);
649da6c28aaSamw 	if (name_end == 0) {
650da6c28aaSamw 		/* not a valid NB name */
651da6c28aaSamw 		return (0);
652da6c28aaSamw 	}
653da6c28aaSamw 
654da6c28aaSamw 	name_len = name_end - buf + 1;
655da6c28aaSamw 
656da6c28aaSamw 	(void) strlcpy(name, buf, name_len);
657da6c28aaSamw 	return (name_len);
658da6c28aaSamw }
659da6c28aaSamw 
660da6c28aaSamw /*
661da6c28aaSamw  * smb_name_buf_to_packet
662da6c28aaSamw  *
663a0aa776eSAlan Wright  * Convert the bits and bytes that came from the wire into a NetBIOS
664a0aa776eSAlan Wright  * Name Server Packet Block (npb).  The "block" is used as a heap.
665da6c28aaSamw  *
666a0aa776eSAlan Wright  * Returns a pointer to a name packet on success.  Otherwise, returns
667a0aa776eSAlan Wright  * a NULL pointer.
668da6c28aaSamw  */
669da6c28aaSamw static struct name_packet *
670da6c28aaSamw smb_name_buf_to_packet(char *buf, int n_buf)
671da6c28aaSamw {
672da6c28aaSamw 	struct name_packet *npb;
673da6c28aaSamw 	unsigned char *heap;
674da6c28aaSamw 	unsigned char *scan = (unsigned char *)buf;
675da6c28aaSamw 	unsigned char *scan_end = scan + n_buf;
676da6c28aaSamw 	char name_buf[MAX_NAME_LENGTH];
677da6c28aaSamw 	struct resource_record *nrr = 0;
678da6c28aaSamw 	int	rc, i, n, nn, ns;
679a0aa776eSAlan Wright 	uint16_t name_trn_id, info;
680a0aa776eSAlan Wright 	uint16_t qdcount, ancount, nscount, arcount;
681a0aa776eSAlan Wright 	addr_entry_t *next;
682da6c28aaSamw 	int name_len;
683da6c28aaSamw 
684da6c28aaSamw 	if (n_buf < NAME_HEADER_SIZE) {
685da6c28aaSamw 		/* truncated header */
686a0aa776eSAlan Wright 		syslog(LOG_DEBUG, "nbns: short packet (%d bytes)", n_buf);
687a0aa776eSAlan Wright 		return (NULL);
688da6c28aaSamw 	}
689da6c28aaSamw 
690da6c28aaSamw 	name_trn_id = BE_IN16(scan); scan += 2;
691da6c28aaSamw 	info = BE_IN16(scan); scan += 2;
692da6c28aaSamw 	qdcount = BE_IN16(scan); scan += 2;
693da6c28aaSamw 	ancount = BE_IN16(scan); scan += 2;
694da6c28aaSamw 	nscount = BE_IN16(scan); scan += 2;
695da6c28aaSamw 	arcount = BE_IN16(scan); scan += 2;
696da6c28aaSamw 
697da6c28aaSamw 	ns = sizeof (struct name_entry);
698da6c28aaSamw 	n = n_buf + sizeof (struct name_packet) +
699da6c28aaSamw 	    ((unsigned)qdcount * (sizeof (struct name_question) + ns)) +
700da6c28aaSamw 	    ((unsigned)ancount * (sizeof (struct resource_record) + ns)) +
701da6c28aaSamw 	    ((unsigned)nscount * (sizeof (struct resource_record) + ns)) +
702da6c28aaSamw 	    ((unsigned)arcount * (sizeof (struct resource_record) + ns));
703da6c28aaSamw 
704a0aa776eSAlan Wright 	if ((npb = malloc(n)) == NULL)
705a0aa776eSAlan Wright 		return (NULL);
706da6c28aaSamw 
707a0aa776eSAlan Wright 	bzero(npb, n);
708da6c28aaSamw 	heap = npb->block_data;
709da6c28aaSamw 	npb->name_trn_id = name_trn_id;
710da6c28aaSamw 	npb->info = info;
711da6c28aaSamw 	npb->qdcount = qdcount;
712da6c28aaSamw 	npb->ancount = ancount;
713da6c28aaSamw 	npb->nscount = nscount;
714da6c28aaSamw 	npb->arcount = arcount;
715da6c28aaSamw 
716da6c28aaSamw 	/* scan is in position for question entries */
717da6c28aaSamw 
718da6c28aaSamw 	/*
719da6c28aaSamw 	 * Measure the space needed for the tables
720da6c28aaSamw 	 */
721da6c28aaSamw 	if (qdcount > 0) {
722da6c28aaSamw 		/* LINTED - E_BAD_PTR_CAST_ALIGN */
723da6c28aaSamw 		npb->question = (struct name_question *)heap;
724da6c28aaSamw 		heap += qdcount * sizeof (struct name_question);
725da6c28aaSamw 		for (i = 0; i < qdcount; i++) {
726da6c28aaSamw 			/* LINTED - E_BAD_PTR_CAST_ALIGN */
727da6c28aaSamw 			npb->question[i].name = (struct name_entry *)heap;
728da6c28aaSamw 			heap += sizeof (struct name_entry);
729da6c28aaSamw 		}
730da6c28aaSamw 	}
731da6c28aaSamw 
732da6c28aaSamw 	/* LINTED - E_BAD_PTR_CAST_ALIGN */
733da6c28aaSamw 	nrr = (struct resource_record *)heap;
734da6c28aaSamw 
735da6c28aaSamw 	if (ancount > 0) {
736da6c28aaSamw 		/* LINTED - E_BAD_PTR_CAST_ALIGN */
737da6c28aaSamw 		npb->answer = (struct resource_record *)heap;
738da6c28aaSamw 		heap += ancount * sizeof (struct resource_record);
739da6c28aaSamw 	}
740da6c28aaSamw 
741da6c28aaSamw 	if (nscount > 0) {
742da6c28aaSamw 		/* LINTED - E_BAD_PTR_CAST_ALIGN */
743da6c28aaSamw 		npb->authority = (struct resource_record *)heap;
744da6c28aaSamw 		heap += nscount * sizeof (struct resource_record);
745da6c28aaSamw 	}
746da6c28aaSamw 
747da6c28aaSamw 	if (arcount > 0) {
748da6c28aaSamw 		/* LINTED - E_BAD_PTR_CAST_ALIGN */
749da6c28aaSamw 		npb->additional = (struct resource_record *)heap;
750da6c28aaSamw 		heap += arcount * sizeof (struct resource_record);
751da6c28aaSamw 	}
752da6c28aaSamw 
753da6c28aaSamw 	/*
754da6c28aaSamw 	 * Populate each resource_record's .name field.
755da6c28aaSamw 	 * Done as a second pass so that all resource records
756da6c28aaSamw 	 * (answer, authority, additional) are consecutive via nrr[i].
757da6c28aaSamw 	 */
758da6c28aaSamw 	for (i = 0; i < (ancount + nscount + arcount); i++) {
759da6c28aaSamw 		/* LINTED - E_BAD_PTR_CAST_ALIGN */
760da6c28aaSamw 		nrr[i].name = (struct name_entry *)heap;
761da6c28aaSamw 		heap += sizeof (struct name_entry);
762da6c28aaSamw 	}
763da6c28aaSamw 
764da6c28aaSamw 
765da6c28aaSamw 	for (i = 0; i < npb->qdcount; i++) {
766da6c28aaSamw 		name_len = smb_netbios_getname(name_buf, (char *)scan,
767da6c28aaSamw 		    (char *)scan_end);
768da6c28aaSamw 		if (name_len <= 0) {
769da6c28aaSamw 			free(npb);
770a0aa776eSAlan Wright 			return (NULL);
771da6c28aaSamw 		}
772da6c28aaSamw 
773da6c28aaSamw 		smb_init_name_struct(NETBIOS_EMPTY_NAME, 0, 0, 0, 0, 0, 0,
774da6c28aaSamw 		    npb->question[i].name);
775da6c28aaSamw 		rc = smb_first_level_name_decode((unsigned char *)name_buf,
776da6c28aaSamw 		    npb->question[i].name);
777da6c28aaSamw 		if (rc < 0) {
778da6c28aaSamw 			/* Couldn't decode the question name */
779da6c28aaSamw 			free(npb);
780a0aa776eSAlan Wright 			return (NULL);
781da6c28aaSamw 		}
782da6c28aaSamw 
783da6c28aaSamw 		scan += name_len;
784da6c28aaSamw 		if (scan + 4 > scan_end) {
785da6c28aaSamw 			/* no room for Question Type(2) and Class(2) fields */
786da6c28aaSamw 			free(npb);
787a0aa776eSAlan Wright 			return (NULL);
788da6c28aaSamw 		}
789da6c28aaSamw 
790da6c28aaSamw 		npb->question[i].question_type = BE_IN16(scan); scan += 2;
791da6c28aaSamw 		npb->question[i].question_class = BE_IN16(scan); scan += 2;
792da6c28aaSamw 	}
793da6c28aaSamw 
794da6c28aaSamw 	/*
795da6c28aaSamw 	 * Cheat. Remaining sections are of the same resource_record
796da6c28aaSamw 	 * format. Table space is consecutive.
797da6c28aaSamw 	 */
798da6c28aaSamw 
799da6c28aaSamw 	for (i = 0; i < (ancount + nscount + arcount); i++) {
800da6c28aaSamw 		if (scan[0] == 0xc0) {
801da6c28aaSamw 			/* Namebuf is reused... */
802da6c28aaSamw 			rc = 2;
803da6c28aaSamw 		} else {
804da6c28aaSamw 			name_len = smb_netbios_getname(name_buf, (char *)scan,
805da6c28aaSamw 			    (char *)scan_end);
806da6c28aaSamw 			if (name_len <= 0) {
807da6c28aaSamw 				free(npb);
808a0aa776eSAlan Wright 				return (NULL);
809da6c28aaSamw 			}
810da6c28aaSamw 			rc = name_len;
811da6c28aaSamw 		}
812da6c28aaSamw 		scan += rc;
813da6c28aaSamw 
814da6c28aaSamw 		if (scan + 10 > scan_end) {
815da6c28aaSamw 			/*
816da6c28aaSamw 			 * no room for RR_TYPE (2), RR_CLASS (2), TTL (4) and
817da6c28aaSamw 			 * RDLENGTH (2) fields.
818da6c28aaSamw 			 */
819da6c28aaSamw 			free(npb);
820a0aa776eSAlan Wright 			return (NULL);
821da6c28aaSamw 		}
822da6c28aaSamw 
823da6c28aaSamw 		smb_init_name_struct(NETBIOS_EMPTY_NAME, 0, 0, 0, 0, 0, 0,
824da6c28aaSamw 		    nrr[i].name);
825da6c28aaSamw 		if ((rc = smb_first_level_name_decode((unsigned char *)name_buf,
826da6c28aaSamw 		    nrr[i].name)) < 0) {
827da6c28aaSamw 			free(npb);
828a0aa776eSAlan Wright 			return (NULL);
829da6c28aaSamw 		}
830da6c28aaSamw 
831da6c28aaSamw 		nrr[i].rr_type = BE_IN16(scan); scan += 2;
832da6c28aaSamw 		nrr[i].rr_class = BE_IN16(scan); scan += 2;
833da6c28aaSamw 		nrr[i].ttl = BE_IN32(scan); scan += 4;
834da6c28aaSamw 		nrr[i].rdlength = BE_IN16(scan); scan += 2;
835da6c28aaSamw 
836da6c28aaSamw 		if ((n = nrr[i].rdlength) > 0) {
837da6c28aaSamw 			if ((scan + n) > scan_end) {
838da6c28aaSamw 				/* no room for RDATA */
839da6c28aaSamw 				free(npb);
840a0aa776eSAlan Wright 				return (NULL);
841da6c28aaSamw 			}
842da6c28aaSamw 			bcopy(scan, heap, n);
843da6c28aaSamw 
844da6c28aaSamw 			nn = n;
845da6c28aaSamw 			if (nrr[i].rr_type == 0x0020 &&
846da6c28aaSamw 			    nrr[i].rr_class == 0x01 && n >= 6) {
847da6c28aaSamw 				while (nn) {
848da6c28aaSamw 					if (nn == 6)
849da6c28aaSamw 						next = &nrr[i].name->addr_list;
850da6c28aaSamw 					else {
851a0aa776eSAlan Wright 						next = malloc(
852a0aa776eSAlan Wright 						    sizeof (addr_entry_t));
853da6c28aaSamw 						if (next == 0) {
854da6c28aaSamw 							/* not enough memory */
855da6c28aaSamw 							free(npb);
856a0aa776eSAlan Wright 							return (NULL);
857da6c28aaSamw 						}
858da6c28aaSamw 						QUEUE_INSERT_TAIL(
859da6c28aaSamw 						    &nrr[i].name->addr_list,
860da6c28aaSamw 						    next);
861da6c28aaSamw 					}
862da6c28aaSamw 					nrr[i].name->attributes =
863da6c28aaSamw 					    BE_IN16(scan);
864da6c28aaSamw 					next->sin.sin_family = AF_INET;
865da6c28aaSamw 					next->sinlen = sizeof (next->sin);
866da6c28aaSamw 					(void) memcpy(
867da6c28aaSamw 					    &next->sin.sin_addr.s_addr,
868da6c28aaSamw 					    scan + 2, sizeof (uint32_t));
869da6c28aaSamw 					next->sin.sin_port =
870a0aa776eSAlan Wright 					    htons(IPPORT_NETBIOS_DGM);
871da6c28aaSamw 					nn -= 6;
872da6c28aaSamw 					scan += 6;
873da6c28aaSamw 				}
874da6c28aaSamw 			} else {
875da6c28aaSamw 				nrr[i].rdata = heap;
876da6c28aaSamw 				scan += n;
877da6c28aaSamw 			}
878da6c28aaSamw 			heap += n;
879da6c28aaSamw 		}
880da6c28aaSamw 	}
881da6c28aaSamw 	return (npb);
882da6c28aaSamw }
883da6c28aaSamw 
884da6c28aaSamw /*
885da6c28aaSamw  * smb_send_name_service_packet
886da6c28aaSamw  *
887da6c28aaSamw  * Description:
888da6c28aaSamw  *
889da6c28aaSamw  *	Send out a name service packet to proper destination.
890da6c28aaSamw  *
891da6c28aaSamw  * Inputs:
892da6c28aaSamw  *	struct netbios_name *dest	-> NETBIOS name of destination
893da6c28aaSamw  *	struct name_packet *packet	-> Packet to send
894da6c28aaSamw  *
895da6c28aaSamw  * Returns:
896da6c28aaSamw  *	success	->  >0
897da6c28aaSamw  *	failure	-> <=0
898da6c28aaSamw  */
899da6c28aaSamw static int
900a0aa776eSAlan Wright smb_send_name_service_packet(addr_entry_t *addr, struct name_packet *packet)
901da6c28aaSamw {
902da6c28aaSamw 	unsigned char buf[MAX_DATAGRAM_LENGTH];
903da6c28aaSamw 	int len;
904da6c28aaSamw 
905da6c28aaSamw 	if ((len = smb_name_buf_from_packet(buf, sizeof (buf), packet)) < 0) {
906da6c28aaSamw 		errno = EINVAL;
907da6c28aaSamw 		return (-1);
908da6c28aaSamw 	}
909da6c28aaSamw 
910da6c28aaSamw 	return (sendto(name_sock, buf, len, MSG_EOR,
911da6c28aaSamw 	    (struct sockaddr *)&addr->sin, addr->sinlen));
912da6c28aaSamw }
913da6c28aaSamw 
914da6c28aaSamw /*
915da6c28aaSamw  * smb_netbios_send_rcv
916da6c28aaSamw  *
917da6c28aaSamw  * This function sends the given NetBIOS packet to the given
918da6c28aaSamw  * address and get back the response. If send operation is not
919da6c28aaSamw  * successful, it's repeated 'retries' times.
920da6c28aaSamw  *
921da6c28aaSamw  * Returns:
922da6c28aaSamw  *		0		Unsuccessful send operation; no reply
923da6c28aaSamw  *		1		Got reply
924da6c28aaSamw  */
925da6c28aaSamw static int
926a0aa776eSAlan Wright smb_netbios_send_rcv(int bcast, addr_entry_t *destination,
927a0aa776eSAlan Wright     struct name_packet *packet, uint32_t retries, uint32_t timeout)
928da6c28aaSamw {
929da6c28aaSamw 	uint32_t retry;
930a0aa776eSAlan Wright 	uint16_t	tid;
931da6c28aaSamw 	struct timespec st;
932da6c28aaSamw 	int	rc;
933da6c28aaSamw 
934da6c28aaSamw 	for (retry = 0; retry < retries; retry++) {
935da6c28aaSamw 		if ((destination->flags & ADDR_FLAG_VALID) == 0)
936da6c28aaSamw 			return (0);
937da6c28aaSamw 
938a0aa776eSAlan Wright 		tid = smb_netbios_name_trn_id();
939da6c28aaSamw 		packet->name_trn_id = tid;
940da6c28aaSamw 		if (smb_send_name_service_packet(destination, packet) >= 0) {
941da6c28aaSamw 			rc = smb_netbios_process_response(tid, destination,
942da6c28aaSamw 			    packet, timeout);
943da6c28aaSamw 
944da6c28aaSamw 			if ((rc > 0) || (bcast == BROADCAST))
945da6c28aaSamw 				return (1);
946da6c28aaSamw 
947da6c28aaSamw 			if (rc != 0)
948da6c28aaSamw 				return (0);
949da6c28aaSamw 		}
950da6c28aaSamw 
951da6c28aaSamw 		st.tv_sec = 0;
952da6c28aaSamw 		st.tv_nsec = (timeout * 1000000);
953da6c28aaSamw 		(void) nanosleep(&st, 0);
954da6c28aaSamw 	}
955da6c28aaSamw 
956da6c28aaSamw 	return (0);
957da6c28aaSamw }
958da6c28aaSamw 
959da6c28aaSamw /*
960a0aa776eSAlan Wright  * RFC 1002 4.2.2.  NAME REGISTRATION REQUEST
961da6c28aaSamw  */
962da6c28aaSamw static int
963da6c28aaSamw smb_send_name_registration_request(int bcast, struct name_question *question,
964da6c28aaSamw     struct resource_record *additional)
965da6c28aaSamw {
966da6c28aaSamw 	int gotreply = 0;
967da6c28aaSamw 	uint32_t retries;
968da6c28aaSamw 	uint32_t timeout;
969a0aa776eSAlan Wright 	addr_entry_t *destination;
970da6c28aaSamw 	struct name_packet packet;
971da6c28aaSamw 	unsigned char type;
972da6c28aaSamw 	int i, addr_num, rc;
973da6c28aaSamw 
974da6c28aaSamw 	type = question->name->name[15];
975a0aa776eSAlan Wright 	if ((type != NBT_WKSTA) && (type != NBT_SERVER)) {
976a0aa776eSAlan Wright 		syslog(LOG_DEBUG, "nbns: name registration bad type (0x%02x)",
977a0aa776eSAlan Wright 		    type);
978da6c28aaSamw 		smb_netbios_name_logf(question->name);
979da6c28aaSamw 		question->name->attributes &= ~NAME_ATTR_LOCAL;
980da6c28aaSamw 		return (-1);
981da6c28aaSamw 	}
982da6c28aaSamw 
983da6c28aaSamw 	if (bcast == BROADCAST) {
984da6c28aaSamw 		if (bcast_num == 0)
985da6c28aaSamw 			return (0);
986da6c28aaSamw 		destination = smb_bcast_list;
987da6c28aaSamw 		addr_num = bcast_num;
988da6c28aaSamw 		retries = BCAST_REQ_RETRY_COUNT;
989da6c28aaSamw 		timeout = BCAST_REQ_RETRY_TIMEOUT;
990da6c28aaSamw 		packet.info = NAME_REGISTRATION_REQUEST | NM_FLAGS_BROADCAST;
991da6c28aaSamw 	} else {
992da6c28aaSamw 		if (nbns_num == 0)
993da6c28aaSamw 			return (0);
994da6c28aaSamw 		destination = smb_nbns;
995da6c28aaSamw 		addr_num = nbns_num;
996da6c28aaSamw 		retries = UCAST_REQ_RETRY_COUNT;
997da6c28aaSamw 		timeout = UCAST_REQ_RETRY_TIMEOUT;
998da6c28aaSamw 		packet.info = NAME_REGISTRATION_REQUEST | NM_FLAGS_UNICAST;
999da6c28aaSamw 	}
1000da6c28aaSamw 
1001da6c28aaSamw 	packet.qdcount = 1;	/* question entries */
1002da6c28aaSamw 	packet.question = question;
1003da6c28aaSamw 	packet.ancount = 0;	/* answer recs */
1004da6c28aaSamw 	packet.answer = NULL;
1005da6c28aaSamw 	packet.nscount = 0;	/* authority recs */
1006da6c28aaSamw 	packet.authority = NULL;
1007da6c28aaSamw 	packet.arcount = 1;	/* additional recs */
1008da6c28aaSamw 	packet.additional = additional;
1009da6c28aaSamw 
1010da6c28aaSamw 	if (IS_UNIQUE(question->name->attributes) &&
1011da6c28aaSamw 	    (is_multihome((char *)(question->name->name))))
1012da6c28aaSamw 		packet.info |= NAME_MULTIHOME_REGISTRATION_REQUEST;
1013da6c28aaSamw 
1014da6c28aaSamw 	for (i = 0; i < addr_num; i++) {
1015da6c28aaSamw 		/*
1016da6c28aaSamw 		 * Only register with the Primary WINS server,
1017da6c28aaSamw 		 * unless we got no reply.
1018da6c28aaSamw 		 */
1019da6c28aaSamw 		if ((bcast == UNICAST) && gotreply)
1020da6c28aaSamw 			break;
1021da6c28aaSamw 
1022da6c28aaSamw 		rc = smb_netbios_send_rcv(bcast, &destination[i], &packet,
1023da6c28aaSamw 		    retries, timeout);
1024da6c28aaSamw 		if (rc == 1)
1025da6c28aaSamw 			gotreply = 1;
1026da6c28aaSamw 	}
1027da6c28aaSamw 
1028da6c28aaSamw 	return (gotreply);
1029da6c28aaSamw }
1030da6c28aaSamw 
1031da6c28aaSamw /*
1032a0aa776eSAlan Wright  * RFC 1002 4.2.4.  NAME REFRESH REQUEST
1033da6c28aaSamw  */
1034da6c28aaSamw /*ARGSUSED*/
1035da6c28aaSamw static int
1036da6c28aaSamw smb_send_name_refresh_request(int bcast, struct name_question *question,
1037da6c28aaSamw     struct resource_record *additional, int force)
1038da6c28aaSamw {
1039da6c28aaSamw 	int rc = 0;
1040da6c28aaSamw 	int gotreply = 0;
1041da6c28aaSamw 	uint32_t retries;
1042da6c28aaSamw 	uint32_t timeout;
1043a0aa776eSAlan Wright 	addr_entry_t *addr;
1044a0aa776eSAlan Wright 	addr_entry_t *destination;
1045da6c28aaSamw 	struct name_packet packet;
1046da6c28aaSamw 	unsigned char type;
1047da6c28aaSamw 	int i, addr_num, q_addrs = 0;
1048da6c28aaSamw 
1049da6c28aaSamw 	type = question->name->name[15];
1050a0aa776eSAlan Wright 	if ((type != NBT_WKSTA) && (type != NBT_SERVER)) {
1051a0aa776eSAlan Wright 		syslog(LOG_DEBUG, "nbns: name refresh bad type (0x%02x)", type);
1052da6c28aaSamw 		smb_netbios_name_logf(question->name);
1053da6c28aaSamw 		question->name->attributes &= ~NAME_ATTR_LOCAL;
1054da6c28aaSamw 		return (-1);
1055da6c28aaSamw 	}
1056da6c28aaSamw 	switch (bcast) {
1057da6c28aaSamw 	case BROADCAST :
1058da6c28aaSamw 		if (bcast_num == 0)
1059da6c28aaSamw 			return (-1);
1060da6c28aaSamw 		destination = smb_bcast_list;
1061da6c28aaSamw 		addr_num = bcast_num;
1062da6c28aaSamw 		retries = BCAST_REQ_RETRY_COUNT;
1063da6c28aaSamw 		timeout = BCAST_REQ_RETRY_TIMEOUT;
1064da6c28aaSamw 		packet.info = NAME_REFRESH_REQUEST | NM_FLAGS_BROADCAST;
1065da6c28aaSamw 		break;
1066da6c28aaSamw 
1067da6c28aaSamw 	case UNICAST :
1068da6c28aaSamw 		if (nbns_num == 0)
1069da6c28aaSamw 			return (-1);
1070da6c28aaSamw 		destination = smb_nbns;
1071da6c28aaSamw 		addr_num = nbns_num;
1072da6c28aaSamw 		retries = UCAST_REQ_RETRY_COUNT;
1073da6c28aaSamw 		timeout = UCAST_REQ_RETRY_TIMEOUT;
1074da6c28aaSamw 		packet.info = NAME_REFRESH_REQUEST | NM_FLAGS_UNICAST;
1075da6c28aaSamw 		break;
1076da6c28aaSamw 
1077da6c28aaSamw 	default:
1078da6c28aaSamw 		destination = &question->name->addr_list;
1079da6c28aaSamw 		/*
1080da6c28aaSamw 		 * the value of addr_num is irrelvant here, because
1081da6c28aaSamw 		 * the code is going to do special_process so it doesn't
1082da6c28aaSamw 		 * need the addr_num. We set a value here just to avoid
1083da6c28aaSamw 		 * compiler warning.
1084da6c28aaSamw 		 */
1085da6c28aaSamw 		addr_num = 0;
1086da6c28aaSamw 		retries = UCAST_REQ_RETRY_COUNT;
1087da6c28aaSamw 		timeout = UCAST_REQ_RETRY_TIMEOUT;
1088da6c28aaSamw 		packet.info = NAME_REFRESH_REQUEST | NM_FLAGS_UNICAST;
1089da6c28aaSamw 		q_addrs = 1;
1090da6c28aaSamw 		break;
1091da6c28aaSamw 	}
1092da6c28aaSamw 
1093da6c28aaSamw 	if (IS_UNIQUE(question->name->attributes) &&
1094da6c28aaSamw 	    (is_multihome((char *)(question->name->name))))
1095da6c28aaSamw 		packet.info |= NAME_MULTIHOME_REGISTRATION_REQUEST;
1096da6c28aaSamw 
1097da6c28aaSamw 	packet.qdcount = 1;	/* question entries */
1098da6c28aaSamw 	packet.question = question;
1099da6c28aaSamw 	packet.ancount = 0;	/* answer recs */
1100da6c28aaSamw 	packet.answer = NULL;
1101da6c28aaSamw 	packet.nscount = 0;	/* authority recs */
1102da6c28aaSamw 	packet.authority = NULL;
1103da6c28aaSamw 	packet.arcount = 1;	/* additional recs */
1104da6c28aaSamw 	packet.additional = additional;
1105da6c28aaSamw 
1106da6c28aaSamw 	if (q_addrs)
1107da6c28aaSamw 		goto special_process;
1108da6c28aaSamw 
1109da6c28aaSamw 	for (i = 0; i < addr_num; i++) {
1110da6c28aaSamw 		rc = smb_netbios_send_rcv(bcast, &destination[i], &packet,
1111da6c28aaSamw 		    retries, timeout);
1112da6c28aaSamw 		if (rc == 1)
1113da6c28aaSamw 			gotreply = 1;
1114da6c28aaSamw 	}
1115da6c28aaSamw 
1116da6c28aaSamw 	return (gotreply);
1117da6c28aaSamw 
1118da6c28aaSamw special_process:
1119da6c28aaSamw 	addr = destination;
1120da6c28aaSamw 	do {
1121da6c28aaSamw 		rc = smb_netbios_send_rcv(bcast, addr, &packet,
1122da6c28aaSamw 		    retries, timeout);
1123da6c28aaSamw 		if (rc == 1)
1124da6c28aaSamw 			gotreply = 1;
1125da6c28aaSamw 		addr = addr->forw;
1126da6c28aaSamw 	} while (addr != destination);
1127da6c28aaSamw 
1128da6c28aaSamw 	return (gotreply);
1129da6c28aaSamw }
1130da6c28aaSamw 
1131da6c28aaSamw /*
1132a0aa776eSAlan Wright  * RFC 1002 4.2.5.  POSITIVE NAME REGISTRATION RESPONSE
1133a0aa776eSAlan Wright  * RFC 1002 4.2.6.  NEGATIVE NAME REGISTRATION RESPONSE
1134da6c28aaSamw  */
1135da6c28aaSamw static int
1136a0aa776eSAlan Wright smb_send_name_registration_response(addr_entry_t *addr,
1137a0aa776eSAlan Wright     struct name_packet *original_packet, uint16_t rcode)
1138da6c28aaSamw {
1139da6c28aaSamw 	struct name_packet	packet;
1140da6c28aaSamw 	struct resource_record	answer;
1141da6c28aaSamw 
1142da6c28aaSamw 	bzero(&packet, sizeof (struct name_packet));
1143da6c28aaSamw 	bzero(&answer, sizeof (struct resource_record));
1144da6c28aaSamw 
1145da6c28aaSamw 	packet.name_trn_id = original_packet->name_trn_id;
1146da6c28aaSamw 	packet.info = NAME_REGISTRATION_RESPONSE | NAME_NM_FLAGS_RA |
1147da6c28aaSamw 	    (rcode & NAME_RCODE_MASK);
1148da6c28aaSamw 	packet.qdcount = 0;	/* question entries */
1149da6c28aaSamw 	packet.question = NULL;
1150da6c28aaSamw 	packet.ancount = 1;	/* answer recs */
1151da6c28aaSamw 	packet.answer = &answer;
1152da6c28aaSamw 	packet.nscount = 0;	/* authority recs */
1153da6c28aaSamw 	packet.authority = NULL;
1154da6c28aaSamw 	packet.arcount = 0;	/* additional recs */
1155da6c28aaSamw 	packet.additional = NULL;
1156da6c28aaSamw 
1157da6c28aaSamw 	answer.name = original_packet->question->name;
1158da6c28aaSamw 	answer.rr_type = NAME_QUESTION_TYPE_NB;
1159da6c28aaSamw 	answer.rr_class = NAME_QUESTION_CLASS_IN;
1160da6c28aaSamw 	answer.ttl = original_packet->additional->ttl;
1161da6c28aaSamw 	answer.rdlength = original_packet->additional->rdlength;
1162da6c28aaSamw 	answer.rdata = original_packet->additional->rdata;
1163da6c28aaSamw 
1164da6c28aaSamw 	return (smb_send_name_service_packet(addr, &packet));
1165da6c28aaSamw }
1166da6c28aaSamw 
1167da6c28aaSamw /*
1168a0aa776eSAlan Wright  * RFC 1002 4.2.9.  NAME RELEASE REQUEST & DEMAND
1169da6c28aaSamw  */
1170da6c28aaSamw static int
1171da6c28aaSamw smb_send_name_release_request_and_demand(int bcast,
1172da6c28aaSamw     struct name_question *question, struct resource_record *additional)
1173da6c28aaSamw {
1174da6c28aaSamw 	int gotreply = 0;
1175da6c28aaSamw 	int i, rc;
1176da6c28aaSamw 	int addr_num;
1177da6c28aaSamw 	uint32_t retries;
1178da6c28aaSamw 	uint32_t timeout;
1179a0aa776eSAlan Wright 	addr_entry_t *destination;
1180da6c28aaSamw 	struct name_packet packet;
1181da6c28aaSamw 
1182da6c28aaSamw 	if (bcast == BROADCAST) {
1183da6c28aaSamw 		if (bcast_num == 0)
1184da6c28aaSamw 			return (-1);
1185da6c28aaSamw 		destination = smb_bcast_list;
1186da6c28aaSamw 		addr_num = bcast_num;
1187da6c28aaSamw 		retries = 1; /* BCAST_REQ_RETRY_COUNT */
1188da6c28aaSamw 		timeout = 100; /* BCAST_REQ_RETRY_TIMEOUT */
1189da6c28aaSamw 		packet.info = NAME_RELEASE_REQUEST | NM_FLAGS_BROADCAST;
1190da6c28aaSamw 	} else {
1191da6c28aaSamw 		if (nbns_num == 0)
1192da6c28aaSamw 			return (-1);
1193da6c28aaSamw 		destination = smb_nbns;
1194da6c28aaSamw 		addr_num = nbns_num;
1195da6c28aaSamw 		retries = 1; /* UCAST_REQ_RETRY_COUNT */
1196da6c28aaSamw 		timeout = 100; /* UCAST_REQ_RETRY_TIMEOUT */
1197da6c28aaSamw 		packet.info = NAME_RELEASE_REQUEST | NM_FLAGS_UNICAST;
1198da6c28aaSamw 	}
1199da6c28aaSamw 
1200da6c28aaSamw 	packet.qdcount = 1;	/* question entries */
1201da6c28aaSamw 	packet.question = question;
1202da6c28aaSamw 	packet.ancount = 0;	/* answer recs */
1203da6c28aaSamw 	packet.answer = NULL;
1204da6c28aaSamw 	packet.nscount = 0;	/* authority recs */
1205da6c28aaSamw 	packet.authority = NULL;
1206da6c28aaSamw 	packet.arcount = 1;	/* additional recs */
1207da6c28aaSamw 	packet.additional = additional;
1208da6c28aaSamw 
1209da6c28aaSamw 	for (i = 0; i < addr_num; i++) {
1210da6c28aaSamw 		rc = smb_netbios_send_rcv(bcast, &destination[i], &packet,
1211da6c28aaSamw 		    retries, timeout);
1212da6c28aaSamw 		if (rc == 1)
1213da6c28aaSamw 			gotreply = 1;
1214da6c28aaSamw 	}
1215da6c28aaSamw 
1216da6c28aaSamw 	return (gotreply);
1217da6c28aaSamw }
1218da6c28aaSamw 
1219da6c28aaSamw /*
1220a0aa776eSAlan Wright  * RFC 1002 4.2.10.  POSITIVE NAME RELEASE RESPONSE
1221a0aa776eSAlan Wright  * RFC 1002 4.2.11.  NEGATIVE NAME RELEASE RESPONSE
1222da6c28aaSamw  */
1223da6c28aaSamw static int
1224da6c28aaSamw /* LINTED - E_STATIC_UNUSED */
1225a0aa776eSAlan Wright smb_send_name_release_response(addr_entry_t *addr,
1226a0aa776eSAlan Wright     struct name_packet *original_packet, uint16_t rcode)
1227da6c28aaSamw {
1228da6c28aaSamw 	struct name_packet	packet;
1229da6c28aaSamw 	struct resource_record	answer;
1230da6c28aaSamw 
1231da6c28aaSamw 	bzero(&packet, sizeof (struct name_packet));
1232da6c28aaSamw 	bzero(&answer, sizeof (struct resource_record));
1233da6c28aaSamw 
1234da6c28aaSamw 	packet.name_trn_id = original_packet->name_trn_id;
1235da6c28aaSamw 	packet.info = NAME_RELEASE_RESPONSE | (rcode & NAME_RCODE_MASK);
1236da6c28aaSamw 	packet.qdcount = 0;	/* question entries */
1237da6c28aaSamw 	packet.question = NULL;
1238da6c28aaSamw 	packet.ancount = 1;	/* answer recs */
1239da6c28aaSamw 	packet.answer = &answer;
1240da6c28aaSamw 	packet.nscount = 0;	/* authority recs */
1241da6c28aaSamw 	packet.authority = NULL;
1242da6c28aaSamw 	packet.arcount = 0;	/* additional recs */
1243da6c28aaSamw 	packet.additional = NULL;
1244da6c28aaSamw 
1245da6c28aaSamw 	answer.name = original_packet->question->name;
1246da6c28aaSamw 	answer.rr_type = NAME_QUESTION_TYPE_NB;
1247da6c28aaSamw 	answer.rr_class = NAME_QUESTION_CLASS_IN;
1248da6c28aaSamw 	answer.ttl = original_packet->additional->ttl;
1249da6c28aaSamw 	answer.rdlength = original_packet->additional->rdlength;
1250da6c28aaSamw 	answer.rdata = original_packet->additional->rdata;
1251da6c28aaSamw 
1252da6c28aaSamw 	return (smb_send_name_service_packet(addr, &packet));
1253da6c28aaSamw }
1254da6c28aaSamw 
1255da6c28aaSamw /*
1256a0aa776eSAlan Wright  * RFC 1002 4.2.12.  NAME QUERY REQUEST
1257da6c28aaSamw  */
1258da6c28aaSamw static int
1259da6c28aaSamw smb_send_name_query_request(int bcast, struct name_question *question)
1260da6c28aaSamw {
1261da6c28aaSamw 	int			rc = 0;
1262da6c28aaSamw 	uint32_t		retry, retries;
1263da6c28aaSamw 	uint32_t		timeout;
1264a0aa776eSAlan Wright 	uint16_t		tid;
1265a0aa776eSAlan Wright 	addr_entry_t		*destination;
1266da6c28aaSamw 	struct name_packet	packet;
1267da6c28aaSamw 	int 			i, addr_num;
1268da6c28aaSamw 	struct timespec 	st;
1269da6c28aaSamw 
1270da6c28aaSamw 	if (bcast == BROADCAST) {
1271da6c28aaSamw 		if (bcast_num == 0)
1272da6c28aaSamw 			return (-1);
1273da6c28aaSamw 		destination = smb_bcast_list;
1274da6c28aaSamw 		addr_num = bcast_num;
1275da6c28aaSamw 		retries = BCAST_REQ_RETRY_COUNT;
1276da6c28aaSamw 		timeout = BCAST_REQ_RETRY_TIMEOUT;
1277da6c28aaSamw 		packet.info = NAME_QUERY_REQUEST | NM_FLAGS_BROADCAST;
1278da6c28aaSamw 	} else {
1279da6c28aaSamw 		if (nbns_num == 0)
1280da6c28aaSamw 			return (-1);
1281da6c28aaSamw 		destination = smb_nbns;
1282da6c28aaSamw 		addr_num = nbns_num;
1283da6c28aaSamw 		retries = UCAST_REQ_RETRY_COUNT;
1284da6c28aaSamw 		timeout = UCAST_REQ_RETRY_TIMEOUT;
1285da6c28aaSamw 		packet.info = NAME_QUERY_REQUEST | NM_FLAGS_UNICAST;
1286da6c28aaSamw 	}
1287da6c28aaSamw 	packet.qdcount = 1;	/* question entries */
1288da6c28aaSamw 	packet.question = question;
1289da6c28aaSamw 	packet.ancount = 0;	/* answer recs */
1290da6c28aaSamw 	packet.answer = NULL;
1291da6c28aaSamw 	packet.nscount = 0;	/* authority recs */
1292da6c28aaSamw 	packet.authority = NULL;
1293da6c28aaSamw 	packet.arcount = 0;	/* additional recs */
1294da6c28aaSamw 	packet.additional = NULL;
1295da6c28aaSamw 
1296da6c28aaSamw 	for (i = 0; i < addr_num; i++) {
1297da6c28aaSamw 		for (retry = 0; retry < retries; retry++) {
1298a0aa776eSAlan Wright 			if ((destination[i].flags & ADDR_FLAG_VALID) == 0)
1299da6c28aaSamw 				break;
1300a0aa776eSAlan Wright 			tid = smb_netbios_name_trn_id();
1301da6c28aaSamw 			packet.name_trn_id = tid;
1302da6c28aaSamw 
1303da6c28aaSamw 			if (smb_send_name_service_packet(&destination[i],
1304da6c28aaSamw 			    &packet) >= 0) {
1305da6c28aaSamw 				if ((rc = smb_netbios_process_response(tid,
1306da6c28aaSamw 				    &destination[i],
1307da6c28aaSamw 				    &packet, timeout)) != 0)
1308da6c28aaSamw 					break;
1309da6c28aaSamw 			}
1310da6c28aaSamw 			st.tv_sec = 0;
1311da6c28aaSamw 			st.tv_nsec = (timeout * 1000000);
1312da6c28aaSamw 			(void) nanosleep(&st, 0);
1313da6c28aaSamw 		}
1314da6c28aaSamw 	}
1315da6c28aaSamw 
1316da6c28aaSamw 	return (rc);
1317da6c28aaSamw }
1318da6c28aaSamw 
1319da6c28aaSamw /*
1320a0aa776eSAlan Wright  * RFC 1002 4.2.13.  POSITIVE NAME QUERY RESPONSE
1321a0aa776eSAlan Wright  * RFC 1002 4.2.14.  NEGATIVE NAME QUERY RESPONSE
1322da6c28aaSamw  */
1323da6c28aaSamw static int
1324a0aa776eSAlan Wright smb_send_name_query_response(addr_entry_t *addr,
1325da6c28aaSamw     struct name_packet *original_packet, struct name_entry *entry,
1326a0aa776eSAlan Wright     uint16_t rcode)
1327da6c28aaSamw {
1328a0aa776eSAlan Wright 	addr_entry_t		*raddr;
1329da6c28aaSamw 	struct name_packet	packet;
1330da6c28aaSamw 	struct resource_record	answer;
1331a0aa776eSAlan Wright 	uint16_t		attr;
1332da6c28aaSamw 	unsigned char 		data[MAX_DATAGRAM_LENGTH];
1333da6c28aaSamw 	unsigned char 		*scan = data;
133429bd2886SAlan Wright 	uint32_t		ret_addr;
1335da6c28aaSamw 
1336da6c28aaSamw 	packet.name_trn_id = original_packet->name_trn_id;
1337da6c28aaSamw 	packet.info = NAME_QUERY_RESPONSE | (rcode & NAME_RCODE_MASK);
1338da6c28aaSamw 	packet.qdcount = 0;	/* question entries */
1339da6c28aaSamw 	packet.question = NULL;
1340da6c28aaSamw 	packet.ancount = 1;	/* answer recs */
1341da6c28aaSamw 	packet.answer = &answer;
1342da6c28aaSamw 	packet.nscount = 0;	/* authority recs */
1343da6c28aaSamw 	packet.authority = NULL;
1344da6c28aaSamw 	packet.arcount = 0;	/* additional recs */
1345da6c28aaSamw 	packet.additional = NULL;
1346da6c28aaSamw 
1347da6c28aaSamw 	answer.name = entry;
1348da6c28aaSamw 	answer.rr_class = NAME_QUESTION_CLASS_IN;
1349da6c28aaSamw 	answer.ttl = entry->addr_list.ttl;
1350da6c28aaSamw 	answer.rdata = data;
1351da6c28aaSamw 	if (rcode) {
1352da6c28aaSamw 		answer.rr_type = NAME_RR_TYPE_NULL;
1353da6c28aaSamw 		answer.rdlength = 0;
1354da6c28aaSamw 		bzero(data, 6);
1355da6c28aaSamw 	} else {
1356da6c28aaSamw 		answer.rdlength = 0;
1357da6c28aaSamw 		answer.rr_type = NAME_QUESTION_TYPE_NB;
1358da6c28aaSamw 		raddr = &entry->addr_list;
1359da6c28aaSamw 		scan = data;
1360da6c28aaSamw 		do {
1361da6c28aaSamw 			attr = entry->attributes & (NAME_ATTR_GROUP |
1362da6c28aaSamw 			    NAME_ATTR_OWNER_NODE_TYPE);
1363da6c28aaSamw 
1364da6c28aaSamw 			BE_OUT16(scan, attr); scan += 2;
136529bd2886SAlan Wright 			ret_addr = LE_32(raddr->sin.sin_addr.s_addr);
136629bd2886SAlan Wright 			*scan++ = ret_addr;
136729bd2886SAlan Wright 			*scan++ = ret_addr >> 8;
136829bd2886SAlan Wright 			*scan++ = ret_addr >> 16;
136929bd2886SAlan Wright 			*scan++ = ret_addr >> 24;
1370da6c28aaSamw 
1371da6c28aaSamw 			answer.rdlength += 6;
1372da6c28aaSamw 			raddr = raddr->forw;
1373da6c28aaSamw 		} while (raddr != &entry->addr_list);
1374da6c28aaSamw 	}
1375da6c28aaSamw 
1376da6c28aaSamw 	return (smb_send_name_service_packet(addr, &packet));
1377da6c28aaSamw }
1378da6c28aaSamw 
1379da6c28aaSamw /*
1380a0aa776eSAlan Wright  * RFC 1002 4.2.18.  NODE STATUS RESPONSE
1381da6c28aaSamw  */
1382da6c28aaSamw static int
1383a0aa776eSAlan Wright smb_send_node_status_response(addr_entry_t *addr,
1384da6c28aaSamw     struct name_packet *original_packet)
1385da6c28aaSamw {
1386dc20a302Sas 	uint32_t		net_ipaddr;
1387dc20a302Sas 	int64_t			max_connections;
1388da6c28aaSamw 	struct arpreq 		arpreq;
1389da6c28aaSamw 	struct name_packet	packet;
1390da6c28aaSamw 	struct resource_record	answer;
1391da6c28aaSamw 	unsigned char 		*scan;
1392da6c28aaSamw 	unsigned char 		*scan_end;
1393da6c28aaSamw 	unsigned char		data[MAX_NETBIOS_REPLY_DATA_SIZE];
139455bf511dSas 	boolean_t scan_done = B_FALSE;
13957f667e74Sjose borrego 	smb_inaddr_t ipaddr;
1396da6c28aaSamw 
1397da6c28aaSamw 	bzero(&packet, sizeof (struct name_packet));
1398da6c28aaSamw 	bzero(&answer, sizeof (struct resource_record));
1399da6c28aaSamw 
1400da6c28aaSamw 	packet.name_trn_id = original_packet->name_trn_id;
1401da6c28aaSamw 	packet.info = NODE_STATUS_RESPONSE;
1402da6c28aaSamw 	packet.qdcount = 0;	/* question entries */
1403da6c28aaSamw 	packet.question = NULL;
1404da6c28aaSamw 	packet.ancount = 1;	/* answer recs */
1405da6c28aaSamw 	packet.answer = &answer;
1406da6c28aaSamw 	packet.nscount = 0;	/* authority recs */
1407da6c28aaSamw 	packet.authority = NULL;
1408da6c28aaSamw 	packet.arcount = 0;	/* additional recs */
1409da6c28aaSamw 	packet.additional = NULL;
1410da6c28aaSamw 
1411da6c28aaSamw 	answer.name = original_packet->question->name;
1412da6c28aaSamw 	answer.rr_type = NAME_RR_TYPE_NBSTAT;
1413da6c28aaSamw 	answer.rr_class = NAME_QUESTION_CLASS_IN;
1414da6c28aaSamw 	answer.ttl = 0;
1415da6c28aaSamw 	answer.rdata = data;
1416da6c28aaSamw 
1417da6c28aaSamw 	scan = smb_netbios_cache_status(data, MAX_NETBIOS_REPLY_DATA_SIZE,
1418da6c28aaSamw 	    original_packet->question->name->scope);
1419da6c28aaSamw 
1420da6c28aaSamw 	scan_end = data + MAX_NETBIOS_REPLY_DATA_SIZE;
1421da6c28aaSamw 
14227f667e74Sjose borrego 	ipaddr.a_ipv4 = addr->sin.sin_addr.s_addr;
14237f667e74Sjose borrego 	ipaddr.a_family = AF_INET;
1424fc724630SAlan Wright 	if (smb_nic_is_same_subnet(&ipaddr))
14257b59d02dSjb 		net_ipaddr = addr->sin.sin_addr.s_addr;
1426da6c28aaSamw 	else
14277b59d02dSjb 		net_ipaddr = 0;
1428da6c28aaSamw 
1429dc20a302Sas 	(void) smb_config_getnum(SMB_CI_MAX_CONNECTIONS, &max_connections);
1430dc20a302Sas 
143155bf511dSas 	while (!scan_done) {
1432da6c28aaSamw 		if ((scan + 6) >= scan_end) {
1433da6c28aaSamw 			packet.info |= NAME_NM_FLAGS_TC;
1434da6c28aaSamw 			break;
1435da6c28aaSamw 		}
1436da6c28aaSamw 
1437da6c28aaSamw 		if (net_ipaddr != 0) {
1438da6c28aaSamw 			struct sockaddr_in *s_in;
1439da6c28aaSamw 			int s;
1440da6c28aaSamw 
1441da6c28aaSamw 			s = socket(AF_INET, SOCK_DGRAM, 0);
1442da6c28aaSamw 			/* LINTED - E_BAD_PTR_CAST_ALIGN */
1443da6c28aaSamw 			s_in = (struct sockaddr_in *)&arpreq.arp_pa;
1444da6c28aaSamw 			s_in->sin_family = AF_INET;
1445da6c28aaSamw 			s_in->sin_addr.s_addr = net_ipaddr;
1446da6c28aaSamw 			if (ioctl(s, SIOCGARP, (caddr_t)&arpreq) < 0) {
1447da6c28aaSamw 				bzero(scan, 6);
1448da6c28aaSamw 			} else {
1449da6c28aaSamw 				bcopy(&arpreq.arp_ha.sa_data, scan, 6);
1450da6c28aaSamw 			}
1451da6c28aaSamw 			(void) close(s);
1452da6c28aaSamw 		} else {
1453da6c28aaSamw 			bzero(scan, 6);
1454da6c28aaSamw 		}
1455da6c28aaSamw 		scan += 6;
1456da6c28aaSamw 
1457da6c28aaSamw 		if ((scan + 26) >= scan_end) {
1458da6c28aaSamw 			packet.info |= NAME_NM_FLAGS_TC;
1459da6c28aaSamw 			break;
1460da6c28aaSamw 		}
1461da6c28aaSamw 		bzero(scan, 26);
1462da6c28aaSamw 		scan += 26;
1463da6c28aaSamw 
1464da6c28aaSamw 		if ((scan + 2) >= scan_end) {
1465da6c28aaSamw 			packet.info |= NAME_NM_FLAGS_TC;
1466da6c28aaSamw 			break;
1467da6c28aaSamw 		}
1468da6c28aaSamw 		BE_OUT16(scan, 0); scan += 2;
1469da6c28aaSamw 
1470da6c28aaSamw 		if ((scan + 2) >= scan_end) {
1471da6c28aaSamw 			packet.info |= NAME_NM_FLAGS_TC;
1472da6c28aaSamw 			break;
1473da6c28aaSamw 		}
1474da6c28aaSamw 		BE_OUT16(scan, 0); scan += 2;
1475da6c28aaSamw 
1476da6c28aaSamw 		if ((scan + 2) >= scan_end) {
1477da6c28aaSamw 			packet.info |= NAME_NM_FLAGS_TC;
1478da6c28aaSamw 			break;
1479da6c28aaSamw 		}
1480da6c28aaSamw 		BE_OUT16(scan, 0); scan += 2;
1481da6c28aaSamw 
1482da6c28aaSamw 		if ((scan + 2) >= scan_end) {
1483da6c28aaSamw 			packet.info |= NAME_NM_FLAGS_TC;
1484da6c28aaSamw 			break;
1485da6c28aaSamw 		}
1486da6c28aaSamw 		BE_OUT16(scan, 0); scan += 2;
1487da6c28aaSamw 
1488da6c28aaSamw 		if ((scan + 2) >= scan_end) {
1489da6c28aaSamw 			packet.info |= NAME_NM_FLAGS_TC;
1490da6c28aaSamw 			break;
1491da6c28aaSamw 		}
1492da6c28aaSamw 		BE_OUT16(scan, 0); scan += 2;
1493da6c28aaSamw 
1494da6c28aaSamw 		if ((scan + 2) >= scan_end) {
1495da6c28aaSamw 			packet.info |= NAME_NM_FLAGS_TC;
1496da6c28aaSamw 			break;
1497da6c28aaSamw 		}
1498da6c28aaSamw 		BE_OUT16(scan, 0); scan += 2;
1499da6c28aaSamw 
1500da6c28aaSamw 		if ((scan + 2) >= scan_end) {
1501da6c28aaSamw 			packet.info |= NAME_NM_FLAGS_TC;
1502da6c28aaSamw 			break;
1503da6c28aaSamw 		}
1504da6c28aaSamw 		BE_OUT16(scan, 0); scan += 2;
1505da6c28aaSamw 
1506da6c28aaSamw 		if ((scan + 2) >= scan_end) {
1507da6c28aaSamw 			packet.info |= NAME_NM_FLAGS_TC;
1508da6c28aaSamw 			break;
1509da6c28aaSamw 		}
1510da6c28aaSamw 		BE_OUT16(scan, max_connections); scan += 2;
1511da6c28aaSamw 
1512da6c28aaSamw 		if ((scan + 2) >= scan_end) {
1513da6c28aaSamw 			packet.info |= NAME_NM_FLAGS_TC;
1514da6c28aaSamw 			break;
1515da6c28aaSamw 		}
1516da6c28aaSamw 
1517da6c28aaSamw 		BE_OUT16(scan, 0); scan += 2;
1518da6c28aaSamw 
151955bf511dSas 		scan_done = B_TRUE;
1520da6c28aaSamw 	}
1521da6c28aaSamw 	answer.rdlength = scan - data;
1522da6c28aaSamw 	return (smb_send_name_service_packet(addr, &packet));
1523da6c28aaSamw }
1524da6c28aaSamw 
1525da6c28aaSamw static int
1526da6c28aaSamw smb_name_Bnode_add_name(struct name_entry *name)
1527da6c28aaSamw {
1528da6c28aaSamw 	struct name_question		question;
1529da6c28aaSamw 	struct resource_record		additional;
1530da6c28aaSamw 	unsigned char 			data[8];
1531a0aa776eSAlan Wright 	uint16_t			attr;
1532a0aa776eSAlan Wright 	addr_entry_t			*addr;
1533da6c28aaSamw 	int rc = 0;
1534da6c28aaSamw 
1535da6c28aaSamw 	addr = &name->addr_list;
1536da6c28aaSamw 
1537da6c28aaSamw 	do {
1538da6c28aaSamw 		/* build name service packet */
1539da6c28aaSamw 		question.name = name;
1540da6c28aaSamw 		/*
1541da6c28aaSamw 		 * question.name->attributes |= NAME_NB_FLAGS_ONT_B;
1542da6c28aaSamw 		 * This is commented because NAME_NB_FLAGS_ONT_B is 0
1543da6c28aaSamw 		 */
1544da6c28aaSamw 		question.question_type = NAME_QUESTION_TYPE_NB;
1545da6c28aaSamw 		question.question_class = NAME_QUESTION_CLASS_IN;
1546da6c28aaSamw 
1547da6c28aaSamw 		additional.name = name;
1548da6c28aaSamw 		additional.rr_class = NAME_QUESTION_CLASS_IN;
1549da6c28aaSamw 		additional.ttl = 0;
1550da6c28aaSamw 		additional.rdata = data;
1551da6c28aaSamw 		additional.rdlength = 6;
1552da6c28aaSamw 		additional.rr_type = NAME_QUESTION_TYPE_NB;
1553da6c28aaSamw 		attr = name->attributes & (NAME_ATTR_GROUP |
1554da6c28aaSamw 		    NAME_ATTR_OWNER_NODE_TYPE);
1555da6c28aaSamw 
1556da6c28aaSamw 		BE_OUT16(&data[0], attr);
1557da6c28aaSamw 		(void) memcpy(&data[2], &addr->sin.sin_addr.s_addr,
1558da6c28aaSamw 		    sizeof (uint32_t));
1559da6c28aaSamw 
1560da6c28aaSamw 		rc |= smb_send_name_registration_request(BROADCAST, &question,
1561da6c28aaSamw 		    &additional);
1562da6c28aaSamw 		addr = addr->forw;
1563da6c28aaSamw 
1564da6c28aaSamw 	} while (addr != &name->addr_list);
1565da6c28aaSamw 
1566da6c28aaSamw 	return (rc);
1567da6c28aaSamw }
1568da6c28aaSamw 
1569da6c28aaSamw static int
1570da6c28aaSamw smb_name_Bnode_find_name(struct name_entry *name)
1571da6c28aaSamw {
1572da6c28aaSamw 	struct name_question	question;
1573da6c28aaSamw 
1574da6c28aaSamw 	question.name = name;
1575da6c28aaSamw 	question.question_type = NAME_QUESTION_TYPE_NB;
1576da6c28aaSamw 	question.question_class = NAME_QUESTION_CLASS_IN;
1577da6c28aaSamw 
1578da6c28aaSamw 	return (smb_send_name_query_request(BROADCAST, &question));
1579da6c28aaSamw }
1580da6c28aaSamw 
1581da6c28aaSamw static int
1582da6c28aaSamw smb_name_Bnode_delete_name(struct name_entry *name)
1583da6c28aaSamw {
1584da6c28aaSamw 	struct name_question	question;
1585da6c28aaSamw 	struct resource_record	additional;
1586a0aa776eSAlan Wright 	addr_entry_t		*raddr;
1587a0aa776eSAlan Wright 	unsigned char		data[MAX_DATAGRAM_LENGTH];
1588a0aa776eSAlan Wright 	unsigned char		*scan = data;
1589da6c28aaSamw 	uint32_t		attr;
159029bd2886SAlan Wright 	uint32_t		ret_addr;
1591da6c28aaSamw 
1592da6c28aaSamw 	/* build packet */
1593da6c28aaSamw 	question.name = name;
1594da6c28aaSamw 	question.question_type = NAME_QUESTION_TYPE_NB;
1595da6c28aaSamw 	question.question_class = NAME_QUESTION_CLASS_IN;
1596da6c28aaSamw 
1597da6c28aaSamw 	additional.name = name;
1598da6c28aaSamw 	additional.rr_class = NAME_QUESTION_CLASS_IN;
1599da6c28aaSamw 	additional.ttl = 0;
1600da6c28aaSamw 	additional.rdata = data;
1601da6c28aaSamw 	additional.rdlength = 0;
1602da6c28aaSamw 	additional.rr_type = NAME_QUESTION_TYPE_NB;
1603da6c28aaSamw 	raddr = &name->addr_list;
1604da6c28aaSamw 	scan = data;
1605da6c28aaSamw 	do {
1606da6c28aaSamw 		attr = name->attributes & (NAME_ATTR_GROUP |
1607da6c28aaSamw 		    NAME_ATTR_OWNER_NODE_TYPE);
1608da6c28aaSamw 
1609da6c28aaSamw 		BE_OUT16(scan, attr); scan += 2;
161029bd2886SAlan Wright 		ret_addr = LE_32(raddr->sin.sin_addr.s_addr);
161129bd2886SAlan Wright 		*scan++ = ret_addr;
161229bd2886SAlan Wright 		*scan++ = ret_addr >> 8;
161329bd2886SAlan Wright 		*scan++ = ret_addr >> 16;
161429bd2886SAlan Wright 		*scan++ = ret_addr >> 24;
1615da6c28aaSamw 
1616da6c28aaSamw 		additional.rdlength += 6;
1617da6c28aaSamw 	} while (raddr != &name->addr_list);
1618da6c28aaSamw 
1619da6c28aaSamw 	return (smb_send_name_release_request_and_demand(BROADCAST,
1620da6c28aaSamw 	    &question, &additional));
1621da6c28aaSamw }
1622da6c28aaSamw 
1623da6c28aaSamw static int
1624da6c28aaSamw smb_name_Pnode_add_name(struct name_entry *name)
1625da6c28aaSamw {
1626da6c28aaSamw 	struct name_question		question;
1627da6c28aaSamw 	struct resource_record		additional;
1628da6c28aaSamw 	unsigned char 			data[8];
1629a0aa776eSAlan Wright 	uint16_t			attr;
1630a0aa776eSAlan Wright 	addr_entry_t			*addr;
1631da6c28aaSamw 	int rc = 0;
1632da6c28aaSamw 
1633da6c28aaSamw 	/* build packet */
1634da6c28aaSamw 	addr = &name->addr_list;
1635da6c28aaSamw 	do {
1636da6c28aaSamw 		question.name = name;
1637da6c28aaSamw 		question.question_type = NAME_QUESTION_TYPE_NB;
1638da6c28aaSamw 		question.question_class = NAME_QUESTION_CLASS_IN;
1639da6c28aaSamw 
1640da6c28aaSamw 		additional.name = name;
1641da6c28aaSamw 		additional.rr_class = NAME_QUESTION_CLASS_IN;
1642da6c28aaSamw 		additional.ttl = 0;
1643da6c28aaSamw 		additional.rdata = data;
1644da6c28aaSamw 		additional.rdlength = 6;
1645da6c28aaSamw 		additional.rr_type = NAME_QUESTION_TYPE_NB;
1646da6c28aaSamw 		attr = name->attributes &
1647da6c28aaSamw 		    (NAME_ATTR_GROUP | NAME_ATTR_OWNER_NODE_TYPE);
1648da6c28aaSamw 
1649da6c28aaSamw 		BE_OUT16(&data[0], attr);
1650da6c28aaSamw 		(void) memcpy(&data[2], &addr->sin.sin_addr.s_addr,
1651da6c28aaSamw 		    sizeof (uint32_t));
1652da6c28aaSamw 
1653da6c28aaSamw 		rc |= smb_send_name_registration_request(UNICAST, &question,
1654da6c28aaSamw 		    &additional);
1655da6c28aaSamw 
1656da6c28aaSamw 		addr = addr->forw;
1657da6c28aaSamw 
1658da6c28aaSamw 	} while (addr != &name->addr_list);
1659da6c28aaSamw 
1660da6c28aaSamw 	return (rc);
1661da6c28aaSamw }
1662da6c28aaSamw 
1663da6c28aaSamw static int
1664da6c28aaSamw smb_name_Pnode_refresh_name(struct name_entry *name)
1665da6c28aaSamw {
1666da6c28aaSamw 	struct name_question		question;
1667da6c28aaSamw 	struct resource_record		additional;
1668da6c28aaSamw 	unsigned char 			data[8];
1669a0aa776eSAlan Wright 	uint16_t			attr;
1670a0aa776eSAlan Wright 	addr_entry_t			*addr;
1671da6c28aaSamw 	int rc = 0;
1672da6c28aaSamw 
1673da6c28aaSamw 	/* build packet */
1674da6c28aaSamw 	addr = &name->addr_list;
1675da6c28aaSamw 	do {
1676da6c28aaSamw 		question.name = name;
1677da6c28aaSamw 		question.question_type = NAME_QUESTION_TYPE_NB;
1678da6c28aaSamw 		question.question_class = NAME_QUESTION_CLASS_IN;
1679da6c28aaSamw 
1680da6c28aaSamw 		additional.name = name;
1681da6c28aaSamw 		additional.rr_class = NAME_QUESTION_CLASS_IN;
1682da6c28aaSamw 		additional.ttl = 0;
1683da6c28aaSamw 		additional.rdata = data;
1684da6c28aaSamw 		additional.rdlength = 6;
1685da6c28aaSamw 		additional.rr_type = NAME_QUESTION_TYPE_NB;
1686da6c28aaSamw 		attr = name->attributes &
1687da6c28aaSamw 		    (NAME_ATTR_GROUP | NAME_ATTR_OWNER_NODE_TYPE);
1688da6c28aaSamw 
1689da6c28aaSamw 		BE_OUT16(&data[0], attr);
1690da6c28aaSamw 		(void) memcpy(&data[2], &addr->sin.sin_addr.s_addr,
1691da6c28aaSamw 		    sizeof (uint32_t));
1692da6c28aaSamw 
1693da6c28aaSamw 		rc |= smb_send_name_refresh_request(UNICAST, &question,
1694da6c28aaSamw 		    &additional, 1);
1695da6c28aaSamw 
1696da6c28aaSamw 		addr = addr->forw;
1697da6c28aaSamw 	} while (addr != &name->addr_list);
1698da6c28aaSamw 
1699da6c28aaSamw 	return (rc);
1700da6c28aaSamw }
1701da6c28aaSamw 
1702da6c28aaSamw static int
1703da6c28aaSamw smb_name_Pnode_find_name(struct name_entry *name)
1704da6c28aaSamw {
1705da6c28aaSamw 	struct name_question	question;
1706da6c28aaSamw 
1707da6c28aaSamw 	/*
1708da6c28aaSamw 	 * Host initiated processing for a P node
1709da6c28aaSamw 	 */
1710da6c28aaSamw 	question.name = name;
1711da6c28aaSamw 	question.name->attributes |= NAME_NB_FLAGS_ONT_P;
1712da6c28aaSamw 	question.question_type = NAME_QUESTION_TYPE_NB;
1713da6c28aaSamw 	question.question_class = NAME_QUESTION_CLASS_IN;
1714da6c28aaSamw 
1715da6c28aaSamw 	return (smb_send_name_query_request(UNICAST, &question));
1716da6c28aaSamw }
1717da6c28aaSamw 
1718da6c28aaSamw static int
1719da6c28aaSamw smb_name_Pnode_delete_name(struct name_entry *name)
1720da6c28aaSamw {
1721da6c28aaSamw 	struct name_question	question;
1722da6c28aaSamw 	struct resource_record	additional;
1723a0aa776eSAlan Wright 	addr_entry_t		*raddr;
1724a0aa776eSAlan Wright 	unsigned char		data[MAX_DATAGRAM_LENGTH];
1725a0aa776eSAlan Wright 	unsigned char		*scan = data;
1726da6c28aaSamw 	uint32_t		attr;
172729bd2886SAlan Wright 	uint32_t		ret_addr;
1728da6c28aaSamw 
1729da6c28aaSamw 	/* build packet */
1730da6c28aaSamw 	question.name = name;
1731da6c28aaSamw 	question.name->attributes |= NAME_NB_FLAGS_ONT_P;
1732da6c28aaSamw 	question.question_type = NAME_QUESTION_TYPE_NB;
1733da6c28aaSamw 	question.question_class = NAME_QUESTION_CLASS_IN;
1734da6c28aaSamw 
1735da6c28aaSamw 	additional.name = name;
1736da6c28aaSamw 	additional.rr_class = NAME_QUESTION_CLASS_IN;
1737da6c28aaSamw 	additional.ttl = 0;
1738da6c28aaSamw 	additional.rdata = data;
1739da6c28aaSamw 	additional.rdlength = 0;
1740da6c28aaSamw 	additional.rr_type = NAME_QUESTION_TYPE_NB;
1741da6c28aaSamw 	raddr = &name->addr_list;
1742da6c28aaSamw 	do {
1743da6c28aaSamw 		scan = data;
1744da6c28aaSamw 		attr = name->attributes & (NAME_ATTR_GROUP |
1745da6c28aaSamw 		    NAME_ATTR_OWNER_NODE_TYPE);
1746da6c28aaSamw 
1747da6c28aaSamw 		BE_OUT16(scan, attr); scan += 2;
174829bd2886SAlan Wright 		ret_addr = LE_32(raddr->sin.sin_addr.s_addr);
174929bd2886SAlan Wright 		*scan++ = ret_addr;
175029bd2886SAlan Wright 		*scan++ = ret_addr >> 8;
175129bd2886SAlan Wright 		*scan++ = ret_addr >> 16;
175229bd2886SAlan Wright 		*scan++ = ret_addr >> 24;
1753da6c28aaSamw 
1754da6c28aaSamw 		additional.rdlength = 6;
1755da6c28aaSamw 		raddr = raddr->forw;
1756da6c28aaSamw 		(void) smb_send_name_release_request_and_demand(UNICAST,
1757da6c28aaSamw 		    &question, &additional);
1758da6c28aaSamw 	} while (raddr != &name->addr_list);
1759da6c28aaSamw 
1760da6c28aaSamw 	return (1);
1761da6c28aaSamw }
1762da6c28aaSamw 
1763da6c28aaSamw static int
1764da6c28aaSamw smb_name_Mnode_add_name(struct name_entry *name)
1765da6c28aaSamw {
1766da6c28aaSamw 	if (smb_name_Bnode_add_name(name) > 0) {
1767da6c28aaSamw 		if (nbns_num == 0)
1768da6c28aaSamw 			return (1); /* No name server configured */
1769da6c28aaSamw 
1770da6c28aaSamw 		return (smb_name_Pnode_add_name(name));
1771da6c28aaSamw 	}
1772da6c28aaSamw 	return (-1);
1773da6c28aaSamw }
1774da6c28aaSamw 
1775da6c28aaSamw static int
1776da6c28aaSamw smb_name_Hnode_add_name(struct name_entry *name)
1777da6c28aaSamw {
1778da6c28aaSamw 	if (nbns_num > 0) {
1779da6c28aaSamw 		if (smb_name_Pnode_add_name(name) == 1)
1780da6c28aaSamw 			return (1);
1781da6c28aaSamw 	}
1782da6c28aaSamw 
1783da6c28aaSamw 	return (smb_name_Bnode_add_name(name));
1784da6c28aaSamw }
1785da6c28aaSamw 
1786da6c28aaSamw static int
1787da6c28aaSamw smb_name_Mnode_find_name(struct name_entry *name)
1788da6c28aaSamw {
1789da6c28aaSamw 	if (smb_name_Bnode_find_name(name) == 1)
1790da6c28aaSamw 		return (1);
1791da6c28aaSamw 
1792da6c28aaSamw 	if (nbns_num == 0)
1793da6c28aaSamw 		return (1); /* No name server configured */
1794da6c28aaSamw 
1795da6c28aaSamw 	return (smb_name_Pnode_find_name(name));
1796da6c28aaSamw }
1797da6c28aaSamw 
1798da6c28aaSamw static int
1799da6c28aaSamw smb_name_Hnode_find_name(struct name_entry *name)
1800da6c28aaSamw {
1801da6c28aaSamw 	if (nbns_num > 0)
1802da6c28aaSamw 		if (smb_name_Pnode_find_name(name) == 1)
1803da6c28aaSamw 			return (1);
1804da6c28aaSamw 
1805da6c28aaSamw 	return (smb_name_Bnode_find_name(name));
1806da6c28aaSamw }
1807da6c28aaSamw 
1808da6c28aaSamw static int
1809da6c28aaSamw smb_name_Mnode_delete_name(struct name_entry *name)
1810da6c28aaSamw {
1811da6c28aaSamw 	(void) smb_name_Bnode_delete_name(name);
1812da6c28aaSamw 
1813da6c28aaSamw 	if (nbns_num == 0)
1814da6c28aaSamw 		return (-1); /* No name server configured */
1815da6c28aaSamw 
1816da6c28aaSamw 	if (smb_name_Pnode_delete_name(name) > 0)
1817da6c28aaSamw 		return (1);
1818da6c28aaSamw 
1819da6c28aaSamw 	return (-1);
1820da6c28aaSamw }
1821da6c28aaSamw 
1822da6c28aaSamw static int
1823da6c28aaSamw smb_name_Hnode_delete_name(struct name_entry *name)
1824da6c28aaSamw {
1825da6c28aaSamw 	if (nbns_num > 0)
1826da6c28aaSamw 		if (smb_name_Pnode_delete_name(name) > 0)
1827da6c28aaSamw 			return (1);
1828da6c28aaSamw 
1829da6c28aaSamw 	return (smb_name_Bnode_delete_name(name));
1830da6c28aaSamw }
1831da6c28aaSamw 
1832da6c28aaSamw static void
1833a0aa776eSAlan Wright smb_name_process_Bnode_packet(struct name_packet *packet, addr_entry_t *addr)
1834da6c28aaSamw {
1835da6c28aaSamw 	struct name_entry 	*name;
1836da6c28aaSamw 	struct name_entry 	*entry;
1837da6c28aaSamw 	struct name_question 	*question;
1838da6c28aaSamw 	struct resource_record 	*additional;
1839da6c28aaSamw 
1840da6c28aaSamw 	question = packet->question;
1841da6c28aaSamw 	additional = packet->additional;
1842da6c28aaSamw 
1843da6c28aaSamw 	switch (packet->info & NAME_OPCODE_OPCODE_MASK) {
1844da6c28aaSamw 	case NAME_OPCODE_REFRESH:
1845da6c28aaSamw 		/* Guard against malformed packets */
1846da6c28aaSamw 		if ((question == 0) || (additional == 0))
1847da6c28aaSamw 			break;
1848da6c28aaSamw 		if (additional->name->addr_list.sin.sin_addr.s_addr == 0)
1849da6c28aaSamw 			break;
1850da6c28aaSamw 
1851da6c28aaSamw 		name = question->name;
1852da6c28aaSamw 		name->addr_list.ttl = additional->ttl;
1853da6c28aaSamw 		name->attributes = additional->name->attributes;
1854da6c28aaSamw 		name->addr_list.sin = additional->name->addr_list.sin;
1855da6c28aaSamw 		name->addr_list.forw = name->addr_list.back = &name->addr_list;
1856da6c28aaSamw 
1857da6c28aaSamw 		if ((entry = smb_netbios_cache_lookup_addr(name)) != 0) {
1858da6c28aaSamw 			smb_netbios_cache_update_entry(entry, question->name);
1859da6c28aaSamw 			smb_netbios_cache_unlock_entry(entry);
1860da6c28aaSamw 		}
1861da6c28aaSamw 		else
1862da6c28aaSamw 			(void) smb_netbios_cache_insert(question->name);
1863da6c28aaSamw 		break;
1864da6c28aaSamw 
1865da6c28aaSamw 	case NAME_OPCODE_QUERY:
1866da6c28aaSamw 		/*
1867da6c28aaSamw 		 * This opcode covers both NAME_QUERY_REQUEST and
1868da6c28aaSamw 		 * NODE_STATUS_REQUEST. They can be distinguished
1869da6c28aaSamw 		 * based on the type of question entry.
1870da6c28aaSamw 		 */
1871da6c28aaSamw 
1872da6c28aaSamw 		/* All query requests have to have question entry */
1873da6c28aaSamw 		if (question == 0)
1874da6c28aaSamw 			break;
1875da6c28aaSamw 
1876da6c28aaSamw 		if (question->question_type == NAME_QUESTION_TYPE_NB) {
1877da6c28aaSamw 			name = question->name;
1878da6c28aaSamw 			if ((entry = smb_netbios_cache_lookup(name)) != 0) {
1879da6c28aaSamw 				(void) smb_send_name_query_response(addr,
1880da6c28aaSamw 				    packet, entry, 0);
1881da6c28aaSamw 				smb_netbios_cache_unlock_entry(entry);
1882da6c28aaSamw 			}
1883da6c28aaSamw 		}
1884da6c28aaSamw 		else
1885da6c28aaSamw 		if (question->question_type == NAME_QUESTION_TYPE_NBSTAT) {
1886da6c28aaSamw 			/*
1887da6c28aaSamw 			 * Name of "*" may be used to force node to
1888da6c28aaSamw 			 * divulge status for administrative purposes
1889da6c28aaSamw 			 */
1890da6c28aaSamw 			name = question->name;
1891da6c28aaSamw 			entry = 0;
1892da6c28aaSamw 			if (NETBIOS_NAME_IS_STAR(name->name) ||
1893da6c28aaSamw 			    ((entry = smb_netbios_cache_lookup(name)) != 0)) {
1894da6c28aaSamw 				if (entry)
1895da6c28aaSamw 					smb_netbios_cache_unlock_entry(entry);
1896da6c28aaSamw 				/*
1897da6c28aaSamw 				 * send only those names that are
1898da6c28aaSamw 				 * in the same scope as the scope
1899da6c28aaSamw 				 * field in the request packet
1900da6c28aaSamw 				 */
1901da6c28aaSamw 				(void) smb_send_node_status_response(addr,
1902da6c28aaSamw 				    packet);
1903da6c28aaSamw 			}
1904da6c28aaSamw 		}
1905da6c28aaSamw 		break;
1906da6c28aaSamw 
1907da6c28aaSamw 	default:
1908da6c28aaSamw 		break;
1909da6c28aaSamw 	}
1910da6c28aaSamw }
1911da6c28aaSamw 
1912da6c28aaSamw static void
1913a0aa776eSAlan Wright smb_name_process_Pnode_packet(struct name_packet *packet, addr_entry_t *addr)
1914da6c28aaSamw {
1915da6c28aaSamw 	struct name_entry 	*name;
1916da6c28aaSamw 	struct name_entry 	*entry;
1917da6c28aaSamw 	struct name_question 	*question;
1918da6c28aaSamw 	struct resource_record 	*additional;
1919da6c28aaSamw 
1920da6c28aaSamw 	question = packet->question;
1921da6c28aaSamw 	additional = packet->additional;
1922da6c28aaSamw 
1923da6c28aaSamw 	if (packet->info & NAME_NM_FLAGS_B) {
1924da6c28aaSamw 		/*
1925da6c28aaSamw 		 * always ignore UDP broadcast packets
1926da6c28aaSamw 		 */
1927da6c28aaSamw 		return;
1928da6c28aaSamw 	}
1929da6c28aaSamw 
1930da6c28aaSamw 	switch (packet->info & NAME_OPCODE_OPCODE_MASK) {
1931da6c28aaSamw 	case NAME_OPCODE_REFRESH:
1932da6c28aaSamw 		/* Guard against malformed packets */
1933da6c28aaSamw 		if ((question == 0) || (additional == 0))
1934da6c28aaSamw 			break;
1935da6c28aaSamw 		if (additional->name->addr_list.sin.sin_addr.s_addr == 0)
1936da6c28aaSamw 			break;
1937da6c28aaSamw 
1938da6c28aaSamw 		name = question->name;
1939da6c28aaSamw 		name->addr_list.ttl = additional->ttl;
1940da6c28aaSamw 		name->attributes = additional->name->attributes;
1941da6c28aaSamw 		name->addr_list.sin = additional->name->addr_list.sin;
1942da6c28aaSamw 		name->addr_list.forw = name->addr_list.back = &name->addr_list;
1943da6c28aaSamw 
1944da6c28aaSamw 		if ((entry = smb_netbios_cache_lookup(name)) != 0) {
1945da6c28aaSamw 			smb_netbios_cache_update_entry(entry, name);
1946da6c28aaSamw 			smb_netbios_cache_unlock_entry(entry);
1947da6c28aaSamw 		}
1948da6c28aaSamw 		else
1949da6c28aaSamw 			(void) smb_netbios_cache_insert(name);
1950da6c28aaSamw 
1951da6c28aaSamw 		(void) smb_send_name_registration_response(addr, packet, 0);
1952da6c28aaSamw 		break;
1953da6c28aaSamw 
1954da6c28aaSamw 	case NAME_OPCODE_QUERY:
1955da6c28aaSamw 		/*
1956da6c28aaSamw 		 * This opcode covers both NAME_QUERY_REQUEST and
1957da6c28aaSamw 		 * NODE_STATUS_REQUEST. They can be distinguished
1958da6c28aaSamw 		 * based on the type of question entry.
1959da6c28aaSamw 		 */
1960da6c28aaSamw 
1961da6c28aaSamw 		/* All query requests have to have question entry */
1962da6c28aaSamw 		if (question == 0)
1963da6c28aaSamw 			break;
1964da6c28aaSamw 
1965da6c28aaSamw 		if (question->question_type == NAME_QUESTION_TYPE_NB) {
1966da6c28aaSamw 			name = question->name;
1967da6c28aaSamw 			if ((entry = smb_netbios_cache_lookup(name)) != 0) {
1968da6c28aaSamw 				/*
1969da6c28aaSamw 				 * send response to the IP address and port
1970da6c28aaSamw 				 * number from which the request was received.
1971da6c28aaSamw 				 */
1972da6c28aaSamw 				(void) smb_send_name_query_response(addr,
1973da6c28aaSamw 				    packet, entry, 0);
1974da6c28aaSamw 				smb_netbios_cache_unlock_entry(entry);
1975da6c28aaSamw 			} else {
1976da6c28aaSamw 				/*
1977da6c28aaSamw 				 * send response to the requestor
1978da6c28aaSamw 				 */
1979da6c28aaSamw 				(void) smb_send_name_query_response(addr,
1980da6c28aaSamw 				    packet, name, RCODE_NAM_ERR);
1981da6c28aaSamw 			}
1982da6c28aaSamw 		}
1983da6c28aaSamw 		else
1984da6c28aaSamw 		if (question->question_type == NAME_QUESTION_TYPE_NBSTAT) {
1985da6c28aaSamw 			/*
1986da6c28aaSamw 			 * Name of "*" may be used to force node to
1987da6c28aaSamw 			 * divulge status for administrative purposes
1988da6c28aaSamw 			 */
1989da6c28aaSamw 			name = question->name;
1990da6c28aaSamw 			entry = 0;
1991da6c28aaSamw 			if (NETBIOS_NAME_IS_STAR(name->name) ||
1992da6c28aaSamw 			    ((entry = smb_netbios_cache_lookup(name)) != 0)) {
1993da6c28aaSamw 				/*
1994da6c28aaSamw 				 * send only those names that are
1995da6c28aaSamw 				 * in the same scope as the scope
1996da6c28aaSamw 				 * field in the request packet
1997da6c28aaSamw 				 */
1998da6c28aaSamw 				if (entry)
1999da6c28aaSamw 					smb_netbios_cache_unlock_entry(entry);
2000da6c28aaSamw 				(void) smb_send_node_status_response(addr,
2001da6c28aaSamw 				    packet);
2002da6c28aaSamw 			}
2003da6c28aaSamw 		}
2004da6c28aaSamw 		break;
2005da6c28aaSamw 
2006da6c28aaSamw 	default:
2007da6c28aaSamw 		break;
2008da6c28aaSamw 	}
2009da6c28aaSamw }
2010da6c28aaSamw 
2011da6c28aaSamw static void
2012a0aa776eSAlan Wright smb_name_process_Mnode_packet(struct name_packet *packet, addr_entry_t *addr)
2013da6c28aaSamw {
2014da6c28aaSamw 	if (packet->info & NAME_NM_FLAGS_B)
2015da6c28aaSamw 		smb_name_process_Bnode_packet(packet, addr);
2016da6c28aaSamw 	else
2017da6c28aaSamw 		smb_name_process_Pnode_packet(packet, addr);
2018da6c28aaSamw }
2019da6c28aaSamw 
2020da6c28aaSamw static void
2021a0aa776eSAlan Wright smb_name_process_Hnode_packet(struct name_packet *packet, addr_entry_t *addr)
2022da6c28aaSamw {
2023da6c28aaSamw 	if (packet->info & NAME_NM_FLAGS_B)
2024da6c28aaSamw 		smb_name_process_Bnode_packet(packet, addr);
2025da6c28aaSamw 	else
2026da6c28aaSamw 		smb_name_process_Pnode_packet(packet, addr);
2027da6c28aaSamw }
2028da6c28aaSamw 
2029da6c28aaSamw 
2030da6c28aaSamw /*
2031da6c28aaSamw  * smb_netbios_name_tick
2032da6c28aaSamw  *
2033da6c28aaSamw  * Called once a second to handle name server timeouts.
2034da6c28aaSamw  */
2035da6c28aaSamw void
2036da6c28aaSamw smb_netbios_name_tick(void)
2037da6c28aaSamw {
2038da6c28aaSamw 	struct name_entry *name;
2039da6c28aaSamw 	struct name_entry *entry;
2040da6c28aaSamw 
2041da6c28aaSamw 	(void) mutex_lock(&refresh_queue.mtx);
2042da6c28aaSamw 	smb_netbios_cache_refresh(&refresh_queue);
2043da6c28aaSamw 
2044da6c28aaSamw 	while ((name = refresh_queue.head.forw) != &refresh_queue.head) {
2045da6c28aaSamw 		QUEUE_CLIP(name);
2046da6c28aaSamw 		if (IS_LOCAL(name->attributes)) {
2047da6c28aaSamw 			if (IS_UNIQUE(name->attributes)) {
2048da6c28aaSamw 				(void) smb_name_Pnode_refresh_name(name);
2049da6c28aaSamw 			}
2050da6c28aaSamw 		} else {
2051da6c28aaSamw 			entry = smb_name_find_name(name);
2052da6c28aaSamw 			smb_name_unlock_name(entry);
2053da6c28aaSamw 		}
2054da6c28aaSamw 		free(name);
2055da6c28aaSamw 	}
2056da6c28aaSamw 	(void) mutex_unlock(&refresh_queue.mtx);
2057da6c28aaSamw 
2058da6c28aaSamw 	smb_netbios_cache_reset_ttl();
2059da6c28aaSamw }
2060da6c28aaSamw 
2061da6c28aaSamw /*
2062da6c28aaSamw  * smb_name_find_name
2063da6c28aaSamw  *
2064da6c28aaSamw  * Lookup name cache for the given name.
2065da6c28aaSamw  * If it's not in the cache it'll send a
2066da6c28aaSamw  * name query request and then lookup the
2067da6c28aaSamw  * cache again. Note that if a name is
2068da6c28aaSamw  * returned it's locked and called MUST
2069da6c28aaSamw  * unlock it by calling smb_name_unlock_name()
2070da6c28aaSamw  */
2071da6c28aaSamw struct name_entry *
2072da6c28aaSamw smb_name_find_name(struct name_entry *name)
2073da6c28aaSamw {
2074da6c28aaSamw 	struct name_entry *result;
2075da6c28aaSamw 
2076da6c28aaSamw 	if ((result = smb_netbios_cache_lookup(name)) == 0) {
2077da6c28aaSamw 		switch (smb_node_type) {
2078da6c28aaSamw 		case 'B':
2079da6c28aaSamw 			(void) smb_name_Bnode_find_name(name);
2080da6c28aaSamw 			break;
2081da6c28aaSamw 		case 'P':
2082da6c28aaSamw 			(void) smb_name_Pnode_find_name(name);
2083da6c28aaSamw 			break;
2084da6c28aaSamw 		case 'M':
2085da6c28aaSamw 			(void) smb_name_Mnode_find_name(name);
2086da6c28aaSamw 			break;
2087da6c28aaSamw 		case 'H':
2088da6c28aaSamw 		default:
2089da6c28aaSamw 			(void) smb_name_Hnode_find_name(name);
2090da6c28aaSamw 			break;
2091da6c28aaSamw 		}
2092da6c28aaSamw 		return (smb_netbios_cache_lookup(name));
2093da6c28aaSamw 	}
2094da6c28aaSamw 
2095da6c28aaSamw 	return (result);
2096da6c28aaSamw }
2097da6c28aaSamw 
2098da6c28aaSamw void
2099da6c28aaSamw smb_name_unlock_name(struct name_entry *name)
2100da6c28aaSamw {
2101da6c28aaSamw 	smb_netbios_cache_unlock_entry(name);
2102da6c28aaSamw }
2103da6c28aaSamw 
2104da6c28aaSamw int
2105da6c28aaSamw smb_name_add_name(struct name_entry *name)
2106da6c28aaSamw {
2107da6c28aaSamw 	int			rc = 1;
2108da6c28aaSamw 
2109a0aa776eSAlan Wright 	smb_netbios_name_logf(name);
2110da6c28aaSamw 
2111da6c28aaSamw 	switch (smb_node_type) {
2112da6c28aaSamw 	case 'B':
2113da6c28aaSamw 		rc = smb_name_Bnode_add_name(name);
2114da6c28aaSamw 		break;
2115da6c28aaSamw 	case 'P':
2116da6c28aaSamw 		rc = smb_name_Pnode_add_name(name);
2117da6c28aaSamw 		break;
2118da6c28aaSamw 	case 'M':
2119da6c28aaSamw 		rc = smb_name_Mnode_add_name(name);
2120da6c28aaSamw 		break;
2121da6c28aaSamw 	case 'H':
2122da6c28aaSamw 	default:
2123da6c28aaSamw 		rc = smb_name_Hnode_add_name(name);
2124da6c28aaSamw 		break;
2125da6c28aaSamw 	}
2126da6c28aaSamw 
2127da6c28aaSamw 	if (rc >= 0)
2128da6c28aaSamw 		(void) smb_netbios_cache_insert(name);
2129da6c28aaSamw 
2130da6c28aaSamw 	return (rc);
2131da6c28aaSamw }
2132da6c28aaSamw 
2133da6c28aaSamw int
2134da6c28aaSamw smb_name_delete_name(struct name_entry *name)
2135da6c28aaSamw {
2136da6c28aaSamw 	int			rc;
2137da6c28aaSamw 	unsigned char type;
2138da6c28aaSamw 
2139da6c28aaSamw 	type = name->name[15];
2140a0aa776eSAlan Wright 	if ((type != NBT_WKSTA) && (type != NBT_SERVER)) {
2141a0aa776eSAlan Wright 		syslog(LOG_DEBUG, "nbns: name delete bad type (0x%02x)", type);
2142da6c28aaSamw 		smb_netbios_name_logf(name);
2143da6c28aaSamw 		name->attributes &= ~NAME_ATTR_LOCAL;
2144da6c28aaSamw 		return (-1);
2145da6c28aaSamw 	}
2146da6c28aaSamw 
2147da6c28aaSamw 	smb_netbios_cache_delete(name);
2148da6c28aaSamw 
2149da6c28aaSamw 	switch (smb_node_type) {
2150da6c28aaSamw 	case 'B':
2151da6c28aaSamw 		rc = smb_name_Bnode_delete_name(name);
2152da6c28aaSamw 		break;
2153da6c28aaSamw 	case 'P':
2154da6c28aaSamw 		rc = smb_name_Pnode_delete_name(name);
2155da6c28aaSamw 		break;
2156da6c28aaSamw 	case 'M':
2157da6c28aaSamw 		rc = smb_name_Mnode_delete_name(name);
2158da6c28aaSamw 		break;
2159da6c28aaSamw 	case 'H':
2160da6c28aaSamw 	default:
2161da6c28aaSamw 		rc = smb_name_Hnode_delete_name(name);
2162da6c28aaSamw 		break;
2163da6c28aaSamw 	}
2164da6c28aaSamw 
2165da6c28aaSamw 	if (rc > 0)
2166da6c28aaSamw 		return (0);
2167da6c28aaSamw 
2168da6c28aaSamw 	return (-1);
2169da6c28aaSamw }
2170da6c28aaSamw 
2171da6c28aaSamw typedef struct {
2172a0aa776eSAlan Wright 	addr_entry_t *addr;
2173da6c28aaSamw 	char *buf;
2174da6c28aaSamw 	int length;
2175da6c28aaSamw } worker_param_t;
2176da6c28aaSamw 
2177da6c28aaSamw /*
2178da6c28aaSamw  * smb_netbios_worker
2179da6c28aaSamw  *
2180da6c28aaSamw  * Process incoming request/response packets for Netbios
2181da6c28aaSamw  * name service (on port 138).
2182da6c28aaSamw  */
2183da6c28aaSamw void *
2184da6c28aaSamw smb_netbios_worker(void *arg)
2185da6c28aaSamw {
2186da6c28aaSamw 	worker_param_t *p = (worker_param_t *)arg;
2187a0aa776eSAlan Wright 	addr_entry_t *addr = p->addr;
2188da6c28aaSamw 	struct name_packet *packet;
2189da6c28aaSamw 
2190a0aa776eSAlan Wright 	if ((packet = smb_name_buf_to_packet(p->buf, p->length)) != NULL) {
2191da6c28aaSamw 		if (packet->info & NAME_OPCODE_R) {
2192da6c28aaSamw 			/* Reply packet */
2193da6c28aaSamw 			smb_reply_ready(packet, addr);
2194da6c28aaSamw 			free(p->buf);
2195da6c28aaSamw 			free(p);
2196a0aa776eSAlan Wright 			return (NULL);
2197da6c28aaSamw 		}
2198da6c28aaSamw 
2199da6c28aaSamw 		/* Request packet */
2200da6c28aaSamw 		switch (smb_node_type) {
2201da6c28aaSamw 		case 'B':
2202da6c28aaSamw 			smb_name_process_Bnode_packet(packet, addr);
2203da6c28aaSamw 			break;
2204da6c28aaSamw 		case 'P':
2205da6c28aaSamw 			smb_name_process_Pnode_packet(packet, addr);
2206da6c28aaSamw 			break;
2207da6c28aaSamw 		case 'M':
2208da6c28aaSamw 			smb_name_process_Mnode_packet(packet, addr);
2209da6c28aaSamw 			break;
2210da6c28aaSamw 		case 'H':
2211da6c28aaSamw 		default:
2212da6c28aaSamw 			smb_name_process_Hnode_packet(packet, addr);
2213da6c28aaSamw 			break;
2214da6c28aaSamw 		}
2215da6c28aaSamw 
2216da6c28aaSamw 		if (packet->answer)
2217da6c28aaSamw 			smb_netbios_name_freeaddrs(packet->answer->name);
2218da6c28aaSamw 		free(packet);
22197b59d02dSjb 	} else {
2220a0aa776eSAlan Wright 		syslog(LOG_ERR, "nbns: packet decode failed");
2221da6c28aaSamw 	}
2222da6c28aaSamw 
2223da6c28aaSamw 	free(addr);
2224da6c28aaSamw 	free(p->buf);
2225da6c28aaSamw 	free(p);
2226a0aa776eSAlan Wright 	return (NULL);
2227da6c28aaSamw }
2228da6c28aaSamw 
2229a0aa776eSAlan Wright /*
2230a0aa776eSAlan Wright  * Configure the node type.  If a WINS server has been specified,
2231a0aa776eSAlan Wright  * act like an H-node.  Otherwise, behave like a B-node.
2232a0aa776eSAlan Wright  */
2233da6c28aaSamw static void
2234a0aa776eSAlan Wright smb_netbios_node_config(void)
2235da6c28aaSamw {
2236a0aa776eSAlan Wright 	static smb_cfg_id_t	wins[SMB_PI_MAX_WINS] = {
2237a0aa776eSAlan Wright 		SMB_CI_WINS_SRV1,
2238a0aa776eSAlan Wright 		SMB_CI_WINS_SRV2
2239a0aa776eSAlan Wright 	};
2240a0aa776eSAlan Wright 	char		ipstr[16];
2241a0aa776eSAlan Wright 	uint32_t	ipaddr;
2242a0aa776eSAlan Wright 	int		i;
2243a0aa776eSAlan Wright 
2244a0aa776eSAlan Wright 	smb_node_type = SMB_NODETYPE_B;
2245a0aa776eSAlan Wright 	nbns_num = 0;
2246a0aa776eSAlan Wright 	bzero(smb_nbns, sizeof (addr_entry_t) * SMB_PI_MAX_WINS);
2247da6c28aaSamw 
2248a0aa776eSAlan Wright 	for (i = 0; i < SMB_PI_MAX_WINS; ++i) {
2249a0aa776eSAlan Wright 		ipstr[0] = '\0';
2250a0aa776eSAlan Wright 		(void) smb_config_getstr(wins[i], ipstr, sizeof (ipstr));
2251a0aa776eSAlan Wright 
2252a0aa776eSAlan Wright 		if ((ipaddr = inet_addr(ipstr)) == INADDR_NONE)
2253a0aa776eSAlan Wright 			continue;
2254a0aa776eSAlan Wright 
2255a0aa776eSAlan Wright 		smb_node_type = SMB_NODETYPE_H;
2256da6c28aaSamw 		smb_nbns[nbns_num].flags = ADDR_FLAG_VALID;
2257da6c28aaSamw 		smb_nbns[nbns_num].sinlen = sizeof (struct sockaddr_in);
2258da6c28aaSamw 		smb_nbns[nbns_num].sin.sin_family = AF_INET;
2259da6c28aaSamw 		smb_nbns[nbns_num].sin.sin_addr.s_addr = ipaddr;
2260a0aa776eSAlan Wright 		smb_nbns[nbns_num].sin.sin_port = htons(IPPORT_NETBIOS_NS);
2261a0aa776eSAlan Wright 		nbns_num++;
22627b59d02dSjb 	}
22637b59d02dSjb }
22647b59d02dSjb 
22657b59d02dSjb static void
22667b59d02dSjb smb_netbios_name_registration(void)
22677b59d02dSjb {
22687b59d02dSjb 	nbcache_iter_t nbc_iter;
22697b59d02dSjb 	struct name_entry *name;
22707b59d02dSjb 	int rc;
22717b59d02dSjb 
22727b59d02dSjb 	rc = smb_netbios_cache_getfirst(&nbc_iter);
22737b59d02dSjb 	while (rc == 0) {
22747b59d02dSjb 		name = nbc_iter.nbc_entry;
22757b59d02dSjb 		(void) smb_netbios_name_logf(name);
22767b59d02dSjb 		if (IS_UNIQUE(name->attributes) && IS_LOCAL(name->attributes)) {
22777b59d02dSjb 			switch (smb_node_type) {
22787b59d02dSjb 			case SMB_NODETYPE_B:
22797b59d02dSjb 				(void) smb_name_Bnode_add_name(name);
22807b59d02dSjb 				break;
22817b59d02dSjb 			case SMB_NODETYPE_P:
22827b59d02dSjb 				(void) smb_name_Pnode_add_name(name);
22837b59d02dSjb 				break;
22847b59d02dSjb 			case SMB_NODETYPE_M:
22857b59d02dSjb 				(void) smb_name_Mnode_add_name(name);
22867b59d02dSjb 				break;
22877b59d02dSjb 			case SMB_NODETYPE_H:
22887b59d02dSjb 			default:
22897b59d02dSjb 				(void) smb_name_Hnode_add_name(name);
22907b59d02dSjb 				break;
22917b59d02dSjb 			}
22927b59d02dSjb 		}
22937b59d02dSjb 		free(name);
22947b59d02dSjb 		rc = smb_netbios_cache_getnext(&nbc_iter);
2295da6c28aaSamw 	}
2296da6c28aaSamw }
2297da6c28aaSamw 
2298a0aa776eSAlan Wright /*
2299a0aa776eSAlan Wright  * Note that the node configuration must be setup before calling
2300a0aa776eSAlan Wright  * smb_init_name_struct().
2301a0aa776eSAlan Wright  */
2302da6c28aaSamw void
2303da6c28aaSamw smb_netbios_name_config(void)
2304da6c28aaSamw {
2305a0aa776eSAlan Wright 	addr_entry_t		*bcast_entry;
2306a0aa776eSAlan Wright 	struct name_entry	name;
2307a0aa776eSAlan Wright 	smb_niciter_t		ni;
2308a0aa776eSAlan Wright 	int			rc;
2309a0aa776eSAlan Wright 
2310a0aa776eSAlan Wright 	(void) mutex_lock(&nbt_name_config_mtx);
2311a0aa776eSAlan Wright 	smb_netbios_node_config();
2312da6c28aaSamw 
2313da6c28aaSamw 	bcast_num = 0;
2314da6c28aaSamw 	bzero(smb_bcast_list, sizeof (addr_entry_t) * SMB_PI_MAX_NETWORKS);
2315da6c28aaSamw 
23167b59d02dSjb 	rc = smb_nic_getfirst(&ni);
23179fb67ea3Safshin salek ardakani - Sun Microsystems - Irvine United States 	while (rc == SMB_NIC_SUCCESS) {
2318a0aa776eSAlan Wright 		if ((ni.ni_nic.nic_smbflags & SMB_NICF_NBEXCL) ||
2319a0aa776eSAlan Wright 		    (ni.ni_nic.nic_smbflags & SMB_NICF_ALIAS)) {
23207b59d02dSjb 			rc = smb_nic_getnext(&ni);
23217b59d02dSjb 			continue;
2322da6c28aaSamw 		}
2323da6c28aaSamw 
2324a0aa776eSAlan Wright 		bcast_entry = &smb_bcast_list[bcast_num];
2325a0aa776eSAlan Wright 		bcast_entry->flags = ADDR_FLAG_VALID;
2326a0aa776eSAlan Wright 		bcast_entry->attributes = NAME_ATTR_LOCAL;
2327a0aa776eSAlan Wright 		bcast_entry->sinlen = sizeof (struct sockaddr_in);
2328a0aa776eSAlan Wright 		bcast_entry->sin.sin_family = AF_INET;
2329a0aa776eSAlan Wright 		bcast_entry->sin.sin_port = htons(IPPORT_NETBIOS_NS);
2330a0aa776eSAlan Wright 		bcast_entry->sin.sin_addr.s_addr = ni.ni_nic.nic_bcast;
2331a0aa776eSAlan Wright 		bcast_num++;
2332da6c28aaSamw 
23337b59d02dSjb 		smb_init_name_struct((unsigned char *)ni.ni_nic.nic_host,
2334a0aa776eSAlan Wright 		    NBT_WKSTA, 0, ni.ni_nic.nic_ip.a_ipv4,
2335a0aa776eSAlan Wright 		    htons(IPPORT_NETBIOS_DGM),
23367b59d02dSjb 		    NAME_ATTR_UNIQUE, NAME_ATTR_LOCAL, &name);
23377b59d02dSjb 		(void) smb_netbios_cache_insert(&name);
2338da6c28aaSamw 
23397b59d02dSjb 		smb_init_name_struct((unsigned char *)ni.ni_nic.nic_host,
2340a0aa776eSAlan Wright 		    NBT_SERVER, 0, ni.ni_nic.nic_ip.a_ipv4,
2341a0aa776eSAlan Wright 		    htons(IPPORT_NETBIOS_DGM),
2342da6c28aaSamw 		    NAME_ATTR_UNIQUE, NAME_ATTR_LOCAL, &name);
23437b59d02dSjb 		(void) smb_netbios_cache_insert(&name);
2344a0aa776eSAlan Wright 
2345a0aa776eSAlan Wright 		rc = smb_nic_getnext(&ni);
2346a0aa776eSAlan Wright 	}
23477b59d02dSjb 
23487b59d02dSjb 	smb_netbios_name_registration();
2349a0aa776eSAlan Wright 	(void) mutex_unlock(&nbt_name_config_mtx);
2350da6c28aaSamw }
2351da6c28aaSamw 
2352da6c28aaSamw void
2353da6c28aaSamw smb_netbios_name_unconfig(void)
2354da6c28aaSamw {
2355da6c28aaSamw 	struct name_entry *name;
2356da6c28aaSamw 
2357a0aa776eSAlan Wright 	(void) mutex_lock(&nbt_name_config_mtx);
2358da6c28aaSamw 	(void) mutex_lock(&delete_queue.mtx);
2359da6c28aaSamw 	smb_netbios_cache_delete_locals(&delete_queue);
2360da6c28aaSamw 
2361da6c28aaSamw 	while ((name = delete_queue.head.forw) != &delete_queue.head) {
2362da6c28aaSamw 		QUEUE_CLIP(name);
2363da6c28aaSamw 		(void) smb_name_delete_name(name);
2364da6c28aaSamw 		free(name);
2365da6c28aaSamw 	}
2366da6c28aaSamw 	(void) mutex_unlock(&delete_queue.mtx);
2367a0aa776eSAlan Wright 	(void) mutex_unlock(&nbt_name_config_mtx);
2368da6c28aaSamw }
2369da6c28aaSamw 
2370da6c28aaSamw void
2371da6c28aaSamw smb_netbios_name_reconfig(void)
2372da6c28aaSamw {
2373da6c28aaSamw 	smb_netbios_name_unconfig();
2374da6c28aaSamw 	smb_netbios_name_config();
2375da6c28aaSamw }
2376da6c28aaSamw 
2377da6c28aaSamw /*
2378a0aa776eSAlan Wright  * NetBIOS Name Service (port 137)
2379da6c28aaSamw  */
2380da6c28aaSamw /*ARGSUSED*/
2381da6c28aaSamw void *
2382a0aa776eSAlan Wright smb_netbios_name_service(void *arg)
2383da6c28aaSamw {
2384da6c28aaSamw 	struct sockaddr_in	sin;
2385a0aa776eSAlan Wright 	addr_entry_t		*addr;
2386da6c28aaSamw 	int			len;
2387da6c28aaSamw 	int			flag = 1;
2388a0aa776eSAlan Wright 	char			*buf;
2389da6c28aaSamw 	worker_param_t 		*worker_param;
23907f667e74Sjose borrego 	smb_inaddr_t		ipaddr;
2391da6c28aaSamw 
2392da6c28aaSamw 	/*
2393da6c28aaSamw 	 * Initialize reply_queue
2394da6c28aaSamw 	 */
2395da6c28aaSamw 	bzero(&reply_queue, sizeof (reply_queue));
2396da6c28aaSamw 	reply_queue.forw = reply_queue.back = &reply_queue;
2397da6c28aaSamw 
2398da6c28aaSamw 	if ((name_sock = socket(AF_INET, SOCK_DGRAM, 0)) < 0) {
2399a0aa776eSAlan Wright 		syslog(LOG_ERR, "nbns: socket failed: %m");
2400a0aa776eSAlan Wright 		smb_netbios_event(NETBIOS_EVENT_ERROR);
2401a0aa776eSAlan Wright 		return (NULL);
2402da6c28aaSamw 	}
2403da6c28aaSamw 
2404a0aa776eSAlan Wright 	flag = 1;
2405a0aa776eSAlan Wright 	(void) setsockopt(name_sock, SOL_SOCKET, SO_REUSEADDR, &flag,
2406a0aa776eSAlan Wright 	    sizeof (flag));
2407a0aa776eSAlan Wright 	flag = 1;
2408da6c28aaSamw 	(void) setsockopt(name_sock, SOL_SOCKET, SO_BROADCAST, &flag,
2409da6c28aaSamw 	    sizeof (flag));
2410da6c28aaSamw 
2411da6c28aaSamw 	bzero(&sin, sizeof (struct sockaddr_in));
2412da6c28aaSamw 	sin.sin_family = AF_INET;
2413a0aa776eSAlan Wright 	sin.sin_port = htons(IPPORT_NETBIOS_NS);
2414da6c28aaSamw 	if (bind(name_sock, (struct sockaddr *)&sin, sizeof (sin)) != 0) {
2415a0aa776eSAlan Wright 		syslog(LOG_ERR, "nbns: bind(%d) failed: %m",
2416a0aa776eSAlan Wright 		    IPPORT_NETBIOS_NS);
2417da6c28aaSamw 		(void) close(name_sock);
2418a0aa776eSAlan Wright 		smb_netbios_event(NETBIOS_EVENT_ERROR);
2419a0aa776eSAlan Wright 		return (NULL);
2420da6c28aaSamw 	}
2421da6c28aaSamw 
2422a0aa776eSAlan Wright 	smb_netbios_event(NETBIOS_EVENT_NS_START);
2423da6c28aaSamw 
2424a0aa776eSAlan Wright 	while (smb_netbios_running()) {
2425a0aa776eSAlan Wright 		buf = malloc(MAX_DATAGRAM_LENGTH);
2426a0aa776eSAlan Wright 		addr = malloc(sizeof (addr_entry_t));
2427a0aa776eSAlan Wright 		if ((buf == NULL) || (addr == NULL)) {
2428a0aa776eSAlan Wright 			/* Sleep for 10 seconds and try again */
2429a0aa776eSAlan Wright 			free(addr);
2430da6c28aaSamw 			free(buf);
2431a0aa776eSAlan Wright 			smb_netbios_sleep(10);
2432da6c28aaSamw 			continue;
2433da6c28aaSamw 		}
2434a0aa776eSAlan Wright ignore:		bzero(addr, sizeof (addr_entry_t));
2435da6c28aaSamw 		addr->sinlen = sizeof (addr->sin);
2436da6c28aaSamw 		addr->forw = addr->back = addr;
2437da6c28aaSamw 
2438da6c28aaSamw 		if ((len = recvfrom(name_sock, buf, MAX_DATAGRAM_LENGTH,
2439da6c28aaSamw 		    0, (struct sockaddr *)&addr->sin, &addr->sinlen)) < 0) {
2440da6c28aaSamw 			if (errno == ENOMEM || errno == ENFILE ||
2441da6c28aaSamw 			    errno == EMFILE) {
2442a0aa776eSAlan Wright 				/* Sleep for 10 seconds and try again */
2443da6c28aaSamw 				free(buf);
2444da6c28aaSamw 				free(addr);
2445a0aa776eSAlan Wright 				smb_netbios_sleep(10);
2446da6c28aaSamw 				continue;
2447da6c28aaSamw 			}
2448a0aa776eSAlan Wright 			syslog(LOG_ERR, "nbns: recvfrom failed: %m");
2449da6c28aaSamw 			free(buf);
2450da6c28aaSamw 			free(addr);
2451a0aa776eSAlan Wright 			smb_netbios_event(NETBIOS_EVENT_ERROR);
2452da6c28aaSamw 			goto shutdown;
2453da6c28aaSamw 		}
2454da6c28aaSamw 
2455da6c28aaSamw 		/* Ignore any incoming packets from myself... */
24567f667e74Sjose borrego 
24577f667e74Sjose borrego 		ipaddr.a_ipv4 = addr->sin.sin_addr.s_addr;
24587f667e74Sjose borrego 		ipaddr.a_family = AF_INET;
2459fc724630SAlan Wright 		if (smb_nic_is_local(&ipaddr))
2460da6c28aaSamw 			goto ignore;
2461da6c28aaSamw 
2462da6c28aaSamw 		/*
2463da6c28aaSamw 		 * Launch a netbios worker to process the received packet.
2464da6c28aaSamw 		 */
2465a0aa776eSAlan Wright 		worker_param = malloc(sizeof (worker_param_t));
2466da6c28aaSamw 		if (worker_param) {
2467da6c28aaSamw 			pthread_t worker;
2468da6c28aaSamw 			pthread_attr_t tattr;
2469da6c28aaSamw 
2470da6c28aaSamw 			worker_param->addr = addr;
2471da6c28aaSamw 			worker_param->buf = buf;
2472da6c28aaSamw 			worker_param->length = len;
2473da6c28aaSamw 
2474da6c28aaSamw 			(void) pthread_attr_init(&tattr);
2475da6c28aaSamw 			(void) pthread_attr_setdetachstate(&tattr,
2476da6c28aaSamw 			    PTHREAD_CREATE_DETACHED);
2477da6c28aaSamw 			(void) pthread_create(&worker, &tattr,
2478da6c28aaSamw 			    smb_netbios_worker, worker_param);
2479da6c28aaSamw 			(void) pthread_attr_destroy(&tattr);
2480da6c28aaSamw 		}
2481da6c28aaSamw 	}
2482da6c28aaSamw 
2483da6c28aaSamw shutdown:
2484a0aa776eSAlan Wright 	smb_netbios_event(NETBIOS_EVENT_NS_STOP);
2485a0aa776eSAlan Wright 	smb_netbios_wait(NETBIOS_EVENT_BROWSER_STOP);
2486da6c28aaSamw 
2487a0aa776eSAlan Wright 	if (!smb_netbios_error())
2488da6c28aaSamw 		smb_netbios_name_unconfig();
2489a0aa776eSAlan Wright 
2490da6c28aaSamw 	(void) close(name_sock);
2491a0aa776eSAlan Wright 	return (NULL);
2492da6c28aaSamw }
2493