xref: /illumos-gate/usr/src/lib/smbsrv/libsmbns/common/smbns_netbios.c (revision bbf6f00c25b6a2bed23c35eac6d62998ecdb338c)
1da6c28aaSamw /*
2da6c28aaSamw  * CDDL HEADER START
3da6c28aaSamw  *
4da6c28aaSamw  * The contents of this file are subject to the terms of the
5da6c28aaSamw  * Common Development and Distribution License (the "License").
6da6c28aaSamw  * You may not use this file except in compliance with the License.
7da6c28aaSamw  *
8da6c28aaSamw  * You can obtain a copy of the license at usr/src/OPENSOLARIS.LICENSE
9da6c28aaSamw  * or http://www.opensolaris.org/os/licensing.
10da6c28aaSamw  * See the License for the specific language governing permissions
11da6c28aaSamw  * and limitations under the License.
12da6c28aaSamw  *
13da6c28aaSamw  * When distributing Covered Code, include this CDDL HEADER in each
14da6c28aaSamw  * file and include the License file at usr/src/OPENSOLARIS.LICENSE.
15da6c28aaSamw  * If applicable, add the following below this CDDL HEADER, with the
16da6c28aaSamw  * fields enclosed by brackets "[]" replaced with your own identifying
17da6c28aaSamw  * information: Portions Copyright [yyyy] [name of copyright owner]
18da6c28aaSamw  *
19da6c28aaSamw  * CDDL HEADER END
20da6c28aaSamw  */
21da6c28aaSamw /*
22a0aa776eSAlan Wright  * Copyright 2009 Sun Microsystems, Inc.  All rights reserved.
23da6c28aaSamw  * Use is subject to license terms.
24da6c28aaSamw  */
25da6c28aaSamw 
26da6c28aaSamw /*
27da6c28aaSamw  * Main startup code for SMB/NETBIOS and some utility routines
28da6c28aaSamw  * for the NETBIOS layer.
29da6c28aaSamw  */
30da6c28aaSamw 
31a0aa776eSAlan Wright #include <sys/tzfile.h>
32a0aa776eSAlan Wright #include <assert.h>
33da6c28aaSamw #include <synch.h>
34da6c28aaSamw #include <unistd.h>
35da6c28aaSamw #include <syslog.h>
36da6c28aaSamw #include <string.h>
37da6c28aaSamw #include <strings.h>
38da6c28aaSamw #include <sys/socket.h>
39a0aa776eSAlan Wright #include <stdio.h>
40a0aa776eSAlan Wright #include <pwd.h>
41a0aa776eSAlan Wright #include <grp.h>
42da6c28aaSamw #include <smbns_netbios.h>
43da6c28aaSamw 
44a0aa776eSAlan Wright #define	SMB_NETBIOS_DUMP_FILE		"netbios"
45da6c28aaSamw 
46a0aa776eSAlan Wright static netbios_service_t nbtd;
47da6c28aaSamw 
48a0aa776eSAlan Wright static void smb_netbios_shutdown(void);
49a0aa776eSAlan Wright static void *smb_netbios_service(void *);
50a0aa776eSAlan Wright static void smb_netbios_dump(void);
51da6c28aaSamw 
52a0aa776eSAlan Wright /*
53a0aa776eSAlan Wright  * Start the NetBIOS services
54a0aa776eSAlan Wright  */
55a0aa776eSAlan Wright int
56a0aa776eSAlan Wright smb_netbios_start(void)
57da6c28aaSamw {
58a0aa776eSAlan Wright 	pthread_t	tid;
59a0aa776eSAlan Wright 	pthread_attr_t	attr;
60a0aa776eSAlan Wright 	int		rc;
61a0aa776eSAlan Wright 
62a0aa776eSAlan Wright 	if (smb_netbios_cache_init() < 0)
63a0aa776eSAlan Wright 		return (-1);
64a0aa776eSAlan Wright 
65a0aa776eSAlan Wright 	(void) pthread_attr_init(&attr);
66a0aa776eSAlan Wright 	(void) pthread_attr_setdetachstate(&attr, PTHREAD_CREATE_DETACHED);
67a0aa776eSAlan Wright 	rc = pthread_create(&tid, &attr, smb_netbios_service, NULL);
68a0aa776eSAlan Wright 	(void) pthread_attr_destroy(&attr);
69a0aa776eSAlan Wright 	return (rc);
70da6c28aaSamw }
71da6c28aaSamw 
72a0aa776eSAlan Wright /*
73a0aa776eSAlan Wright  * Stop the NetBIOS services
74a0aa776eSAlan Wright  */
75da6c28aaSamw void
76a0aa776eSAlan Wright smb_netbios_stop(void)
77da6c28aaSamw {
78a0aa776eSAlan Wright 	char	fname[MAXPATHLEN];
79da6c28aaSamw 
80a0aa776eSAlan Wright 	smb_netbios_event(NETBIOS_EVENT_STOP);
81a0aa776eSAlan Wright 
82a0aa776eSAlan Wright 	(void) snprintf(fname, MAXPATHLEN, "%s/%s",
83a0aa776eSAlan Wright 	    SMB_VARRUN_DIR, SMB_NETBIOS_DUMP_FILE);
84a0aa776eSAlan Wright 	(void) unlink(fname);
85da6c28aaSamw 
86da6c28aaSamw }
87da6c28aaSamw 
88a0aa776eSAlan Wright /*
89a0aa776eSAlan Wright  * Launch the NetBIOS Name Service, Datagram and Browser services
90a0aa776eSAlan Wright  * and then sit in a loop providing a 1 second resolution timer.
91a0aa776eSAlan Wright  * The timer will:
92a0aa776eSAlan Wright  *	- update the netbios stats file every 10 minutes
93a0aa776eSAlan Wright  *	- clean the cache every 10 minutes
94a0aa776eSAlan Wright  */
95a0aa776eSAlan Wright /*ARGSUSED*/
96a0aa776eSAlan Wright static void *
97a0aa776eSAlan Wright smb_netbios_service(void *arg)
98da6c28aaSamw {
99a0aa776eSAlan Wright 	static uint32_t	ticks = 0;
100a0aa776eSAlan Wright 	pthread_t	tid;
101a0aa776eSAlan Wright 	int		rc;
102da6c28aaSamw 
103a0aa776eSAlan Wright 	smb_netbios_event(NETBIOS_EVENT_START);
104da6c28aaSamw 
105a0aa776eSAlan Wright 	rc = pthread_create(&tid, NULL, smb_netbios_name_service, NULL);
106a0aa776eSAlan Wright 	if (rc != 0) {
107a0aa776eSAlan Wright 		smb_netbios_shutdown();
108a0aa776eSAlan Wright 		return (NULL);
109da6c28aaSamw 	}
110da6c28aaSamw 
111a0aa776eSAlan Wright 	smb_netbios_wait(NETBIOS_EVENT_NS_START);
112a0aa776eSAlan Wright 	if (smb_netbios_error()) {
113da6c28aaSamw 		smb_netbios_shutdown();
114a0aa776eSAlan Wright 		return (NULL);
115da6c28aaSamw 	}
116da6c28aaSamw 
117da6c28aaSamw 	smb_netbios_name_config();
118da6c28aaSamw 
119a0aa776eSAlan Wright 	rc = pthread_create(&tid, NULL, smb_netbios_datagram_service, NULL);
120dc20a302Sas 	if (rc != 0) {
121dc20a302Sas 		smb_netbios_shutdown();
122a0aa776eSAlan Wright 		return (NULL);
123da6c28aaSamw 	}
124da6c28aaSamw 
125a0aa776eSAlan Wright 	smb_netbios_wait(NETBIOS_EVENT_DGM_START);
126a0aa776eSAlan Wright 	if (smb_netbios_error()) {
127da6c28aaSamw 		smb_netbios_shutdown();
128a0aa776eSAlan Wright 		return (NULL);
129da6c28aaSamw 	}
130da6c28aaSamw 
131a0aa776eSAlan Wright 	rc = pthread_create(&tid, NULL, smb_browser_service, NULL);
132dc20a302Sas 	if (rc != 0) {
133dc20a302Sas 		smb_netbios_shutdown();
134a0aa776eSAlan Wright 		return (NULL);
135dc20a302Sas 	}
136da6c28aaSamw 
137a0aa776eSAlan Wright 	smb_netbios_event(NETBIOS_EVENT_TIMER_START);
138dc20a302Sas 
139a0aa776eSAlan Wright 	for (;;) {
140da6c28aaSamw 		(void) sleep(1);
1417b59d02dSjb 		ticks++;
142da6c28aaSamw 
143a0aa776eSAlan Wright 		if (!smb_netbios_running())
144da6c28aaSamw 			break;
1457b59d02dSjb 
1467b59d02dSjb 		smb_netbios_datagram_tick();
1477b59d02dSjb 		smb_netbios_name_tick();
1487b59d02dSjb 
149a0aa776eSAlan Wright 		if ((ticks % 600) == 0) {
150a0aa776eSAlan Wright 			smb_netbios_event(NETBIOS_EVENT_DUMP);
1517b59d02dSjb 			smb_netbios_cache_clean();
152a0aa776eSAlan Wright 		}
153da6c28aaSamw 	}
154da6c28aaSamw 
155a0aa776eSAlan Wright 	smb_netbios_event(NETBIOS_EVENT_TIMER_STOP);
156a0aa776eSAlan Wright 	smb_netbios_shutdown();
157a0aa776eSAlan Wright 	return (NULL);
158a0aa776eSAlan Wright }
159a0aa776eSAlan Wright 
160a0aa776eSAlan Wright static void
161a0aa776eSAlan Wright smb_netbios_shutdown(void)
162a0aa776eSAlan Wright {
163a0aa776eSAlan Wright 	(void) pthread_join(nbtd.nbs_browser.s_tid, 0);
164a0aa776eSAlan Wright 	(void) pthread_join(nbtd.nbs_dgm.s_tid, 0);
165a0aa776eSAlan Wright 	(void) pthread_join(nbtd.nbs_ns.s_tid, 0);
166da6c28aaSamw 
167a0aa776eSAlan Wright 	nbtd.nbs_browser.s_tid = 0;
168a0aa776eSAlan Wright 	nbtd.nbs_dgm.s_tid = 0;
169a0aa776eSAlan Wright 	nbtd.nbs_ns.s_tid = 0;
170a0aa776eSAlan Wright 
171a0aa776eSAlan Wright 	smb_netbios_cache_fini();
172a0aa776eSAlan Wright 
173a0aa776eSAlan Wright 	if (smb_netbios_error()) {
174a0aa776eSAlan Wright 		smb_netbios_event(NETBIOS_EVENT_RESET);
175a0aa776eSAlan Wright 		if (smb_netbios_start() != 0)
176a0aa776eSAlan Wright 			syslog(LOG_ERR, "netbios: restart failed");
177a0aa776eSAlan Wright 	}
178da6c28aaSamw }
179da6c28aaSamw 
180da6c28aaSamw int
181da6c28aaSamw smb_first_level_name_encode(struct name_entry *name,
182da6c28aaSamw 				unsigned char *out, int max_out)
183da6c28aaSamw {
184da6c28aaSamw 	return (netbios_first_level_name_encode(name->name, name->scope,
185da6c28aaSamw 	    out, max_out));
186da6c28aaSamw }
187da6c28aaSamw 
188da6c28aaSamw int
189da6c28aaSamw smb_first_level_name_decode(unsigned char *in, struct name_entry *name)
190da6c28aaSamw {
191da6c28aaSamw 	return (netbios_first_level_name_decode((char *)in, (char *)name->name,
192da6c28aaSamw 	    (char *)name->scope));
193da6c28aaSamw }
194da6c28aaSamw 
195da6c28aaSamw /*
196da6c28aaSamw  * smb_encode_netbios_name
197da6c28aaSamw  *
198da6c28aaSamw  * Set up the name and scope fields in the destination name_entry structure.
199da6c28aaSamw  * The name is padded with spaces to 15 bytes. The suffix is copied into the
200da6c28aaSamw  * last byte, i.e. "netbiosname    <suffix>". The scope is copied and folded
201da6c28aaSamw  * to uppercase.
202da6c28aaSamw  */
203da6c28aaSamw void
204da6c28aaSamw smb_encode_netbios_name(unsigned char *name, char suffix, unsigned char *scope,
205da6c28aaSamw     struct name_entry *dest)
206da6c28aaSamw {
2077b59d02dSjb 	smb_tonetbiosname((char *)name, (char *)dest->name, suffix);
208da6c28aaSamw 
2097b59d02dSjb 	if (scope) {
210da6c28aaSamw 		(void) strlcpy((char *)dest->scope, (const char *)scope,
2117b59d02dSjb 		    sizeof (dest->scope));
2127b59d02dSjb 	} else {
2137b59d02dSjb 		(void) smb_config_getstr(SMB_CI_NBSCOPE, (char *)dest->scope,
2147b59d02dSjb 		    sizeof (dest->scope));
215da6c28aaSamw 	}
2167b59d02dSjb 
217*bbf6f00cSJordan Brown 	(void) smb_strupr((char *)dest->scope);
218da6c28aaSamw }
219da6c28aaSamw 
220da6c28aaSamw void
221da6c28aaSamw smb_init_name_struct(unsigned char *name, char suffix, unsigned char *scope,
222da6c28aaSamw     uint32_t ipaddr, unsigned short port, uint32_t attr,
223da6c28aaSamw     uint32_t addr_attr, struct name_entry *dest)
224da6c28aaSamw {
225da6c28aaSamw 	bzero(dest, sizeof (struct name_entry));
226da6c28aaSamw 	smb_encode_netbios_name(name, suffix, scope, dest);
227da6c28aaSamw 
228da6c28aaSamw 	switch (smb_node_type) {
229da6c28aaSamw 	case 'H':
230da6c28aaSamw 		dest->attributes = attr | NAME_ATTR_OWNER_TYPE_HNODE;
231da6c28aaSamw 		break;
232da6c28aaSamw 	case 'M':
233da6c28aaSamw 		dest->attributes = attr | NAME_ATTR_OWNER_TYPE_MNODE;
234da6c28aaSamw 		break;
235da6c28aaSamw 	case 'P':
236da6c28aaSamw 		dest->attributes = attr | NAME_ATTR_OWNER_TYPE_PNODE;
237da6c28aaSamw 		break;
238da6c28aaSamw 	case 'B':
239da6c28aaSamw 	default:
240da6c28aaSamw 		dest->attributes = attr | NAME_ATTR_OWNER_TYPE_BNODE;
241da6c28aaSamw 		break;
242da6c28aaSamw 	}
243da6c28aaSamw 
244da6c28aaSamw 	dest->addr_list.refresh_ttl = dest->addr_list.ttl =
245da6c28aaSamw 	    TO_SECONDS(DEFAULT_TTL);
246da6c28aaSamw 
247da6c28aaSamw 	dest->addr_list.sin.sin_family = AF_INET;
248da6c28aaSamw 	dest->addr_list.sinlen = sizeof (dest->addr_list.sin);
249da6c28aaSamw 	dest->addr_list.sin.sin_addr.s_addr = ipaddr;
250da6c28aaSamw 	dest->addr_list.sin.sin_port = port;
251da6c28aaSamw 	dest->addr_list.attributes = addr_attr;
252da6c28aaSamw 	dest->addr_list.forw = dest->addr_list.back = &dest->addr_list;
253da6c28aaSamw }
254a0aa776eSAlan Wright 
255a0aa776eSAlan Wright void
256a0aa776eSAlan Wright smb_netbios_event(netbios_event_t event)
257a0aa776eSAlan Wright {
258a0aa776eSAlan Wright 	static char *event_msg[] = {
259a0aa776eSAlan Wright 		"startup",
260a0aa776eSAlan Wright 		"shutdown",
261a0aa776eSAlan Wright 		"restart",
262a0aa776eSAlan Wright 		"name service started",
263a0aa776eSAlan Wright 		"name service stopped",
264a0aa776eSAlan Wright 		"datagram service started",
265a0aa776eSAlan Wright 		"datagram service stopped",
266a0aa776eSAlan Wright 		"browser service started",
267a0aa776eSAlan Wright 		"browser service stopped",
268a0aa776eSAlan Wright 		"timer service started",
269a0aa776eSAlan Wright 		"timer service stopped",
270a0aa776eSAlan Wright 		"error",
271a0aa776eSAlan Wright 		"dump"
272a0aa776eSAlan Wright 	};
273a0aa776eSAlan Wright 
274a0aa776eSAlan Wright 	(void) mutex_lock(&nbtd.nbs_mtx);
275a0aa776eSAlan Wright 
276a0aa776eSAlan Wright 	if (event == NETBIOS_EVENT_DUMP) {
277a0aa776eSAlan Wright 		if (nbtd.nbs_last_event == NULL)
278a0aa776eSAlan Wright 			nbtd.nbs_last_event = event_msg[event];
279a0aa776eSAlan Wright 		smb_netbios_dump();
280a0aa776eSAlan Wright 		(void) mutex_unlock(&nbtd.nbs_mtx);
281a0aa776eSAlan Wright 		return;
282a0aa776eSAlan Wright 	}
283a0aa776eSAlan Wright 
284a0aa776eSAlan Wright 	nbtd.nbs_last_event = event_msg[event];
285a0aa776eSAlan Wright 	syslog(LOG_DEBUG, "netbios: %s", nbtd.nbs_last_event);
286a0aa776eSAlan Wright 
287a0aa776eSAlan Wright 	switch (nbtd.nbs_state) {
288a0aa776eSAlan Wright 	case NETBIOS_STATE_INIT:
289a0aa776eSAlan Wright 		if (event == NETBIOS_EVENT_START)
290a0aa776eSAlan Wright 			nbtd.nbs_state = NETBIOS_STATE_RUNNING;
291a0aa776eSAlan Wright 		break;
292a0aa776eSAlan Wright 
293a0aa776eSAlan Wright 	case NETBIOS_STATE_RUNNING:
294a0aa776eSAlan Wright 		switch (event) {
295a0aa776eSAlan Wright 		case NETBIOS_EVENT_NS_START:
296a0aa776eSAlan Wright 			nbtd.nbs_ns.s_tid = pthread_self();
297a0aa776eSAlan Wright 			nbtd.nbs_ns.s_up = B_TRUE;
298a0aa776eSAlan Wright 			break;
299a0aa776eSAlan Wright 		case NETBIOS_EVENT_NS_STOP:
300a0aa776eSAlan Wright 			nbtd.nbs_ns.s_up = B_FALSE;
301a0aa776eSAlan Wright 			break;
302a0aa776eSAlan Wright 		case NETBIOS_EVENT_DGM_START:
303a0aa776eSAlan Wright 			nbtd.nbs_dgm.s_tid = pthread_self();
304a0aa776eSAlan Wright 			nbtd.nbs_dgm.s_up = B_TRUE;
305a0aa776eSAlan Wright 			break;
306a0aa776eSAlan Wright 		case NETBIOS_EVENT_DGM_STOP:
307a0aa776eSAlan Wright 			nbtd.nbs_dgm.s_up = B_FALSE;
308a0aa776eSAlan Wright 			break;
309a0aa776eSAlan Wright 		case NETBIOS_EVENT_BROWSER_START:
310a0aa776eSAlan Wright 			nbtd.nbs_browser.s_tid = pthread_self();
311a0aa776eSAlan Wright 			nbtd.nbs_browser.s_up = B_TRUE;
312a0aa776eSAlan Wright 			break;
313a0aa776eSAlan Wright 		case NETBIOS_EVENT_BROWSER_STOP:
314a0aa776eSAlan Wright 			nbtd.nbs_browser.s_up = B_FALSE;
315a0aa776eSAlan Wright 			break;
316a0aa776eSAlan Wright 		case NETBIOS_EVENT_TIMER_START:
317a0aa776eSAlan Wright 			nbtd.nbs_timer.s_tid = pthread_self();
318a0aa776eSAlan Wright 			nbtd.nbs_timer.s_up = B_TRUE;
319a0aa776eSAlan Wright 			break;
320a0aa776eSAlan Wright 		case NETBIOS_EVENT_TIMER_STOP:
321a0aa776eSAlan Wright 			nbtd.nbs_timer.s_up = B_FALSE;
322a0aa776eSAlan Wright 			break;
323a0aa776eSAlan Wright 		case NETBIOS_EVENT_STOP:
324a0aa776eSAlan Wright 			nbtd.nbs_state = NETBIOS_STATE_CLOSING;
325a0aa776eSAlan Wright 			break;
326a0aa776eSAlan Wright 		case NETBIOS_EVENT_ERROR:
327a0aa776eSAlan Wright 			nbtd.nbs_state = NETBIOS_STATE_ERROR;
328a0aa776eSAlan Wright 			++nbtd.nbs_errors;
329a0aa776eSAlan Wright 			break;
330a0aa776eSAlan Wright 		default:
331a0aa776eSAlan Wright 			break;
332a0aa776eSAlan Wright 		}
333a0aa776eSAlan Wright 		break;
334a0aa776eSAlan Wright 
335a0aa776eSAlan Wright 	case NETBIOS_STATE_CLOSING:
336a0aa776eSAlan Wright 	case NETBIOS_STATE_ERROR:
337a0aa776eSAlan Wright 	default:
338a0aa776eSAlan Wright 		switch (event) {
339a0aa776eSAlan Wright 		case NETBIOS_EVENT_NS_STOP:
340a0aa776eSAlan Wright 			nbtd.nbs_ns.s_up = B_FALSE;
341a0aa776eSAlan Wright 			break;
342a0aa776eSAlan Wright 		case NETBIOS_EVENT_DGM_STOP:
343a0aa776eSAlan Wright 			nbtd.nbs_dgm.s_up = B_FALSE;
344a0aa776eSAlan Wright 			break;
345a0aa776eSAlan Wright 		case NETBIOS_EVENT_BROWSER_STOP:
346a0aa776eSAlan Wright 			nbtd.nbs_browser.s_up = B_FALSE;
347a0aa776eSAlan Wright 			break;
348a0aa776eSAlan Wright 		case NETBIOS_EVENT_TIMER_STOP:
349a0aa776eSAlan Wright 			nbtd.nbs_timer.s_up = B_FALSE;
350a0aa776eSAlan Wright 			break;
351a0aa776eSAlan Wright 		case NETBIOS_EVENT_STOP:
352a0aa776eSAlan Wright 			nbtd.nbs_state = NETBIOS_STATE_CLOSING;
353a0aa776eSAlan Wright 			break;
354a0aa776eSAlan Wright 		case NETBIOS_EVENT_RESET:
355a0aa776eSAlan Wright 			nbtd.nbs_state = NETBIOS_STATE_INIT;
356a0aa776eSAlan Wright 			break;
357a0aa776eSAlan Wright 		case NETBIOS_EVENT_ERROR:
358a0aa776eSAlan Wright 			++nbtd.nbs_errors;
359a0aa776eSAlan Wright 			break;
360a0aa776eSAlan Wright 		default:
361a0aa776eSAlan Wright 			break;
362a0aa776eSAlan Wright 		}
363a0aa776eSAlan Wright 		break;
364a0aa776eSAlan Wright 	}
365a0aa776eSAlan Wright 
366a0aa776eSAlan Wright 	smb_netbios_dump();
367a0aa776eSAlan Wright 	(void) cond_broadcast(&nbtd.nbs_cv);
368a0aa776eSAlan Wright 	(void) mutex_unlock(&nbtd.nbs_mtx);
369a0aa776eSAlan Wright }
370a0aa776eSAlan Wright 
371a0aa776eSAlan Wright void
372a0aa776eSAlan Wright smb_netbios_wait(netbios_event_t event)
373a0aa776eSAlan Wright {
374a0aa776eSAlan Wright 	boolean_t *svc = NULL;
375a0aa776eSAlan Wright 	boolean_t desired_state;
376a0aa776eSAlan Wright 
377a0aa776eSAlan Wright 	(void) mutex_lock(&nbtd.nbs_mtx);
378a0aa776eSAlan Wright 
379a0aa776eSAlan Wright 	switch (event) {
380a0aa776eSAlan Wright 	case NETBIOS_EVENT_NS_START:
381a0aa776eSAlan Wright 	case NETBIOS_EVENT_NS_STOP:
382a0aa776eSAlan Wright 		svc = &nbtd.nbs_ns.s_up;
383a0aa776eSAlan Wright 		desired_state =
384a0aa776eSAlan Wright 		    (event == NETBIOS_EVENT_NS_START) ? B_TRUE : B_FALSE;
385a0aa776eSAlan Wright 		break;
386a0aa776eSAlan Wright 	case NETBIOS_EVENT_DGM_START:
387a0aa776eSAlan Wright 	case NETBIOS_EVENT_DGM_STOP:
388a0aa776eSAlan Wright 		svc = &nbtd.nbs_dgm.s_up;
389a0aa776eSAlan Wright 		desired_state =
390a0aa776eSAlan Wright 		    (event == NETBIOS_EVENT_DGM_START) ? B_TRUE : B_FALSE;
391a0aa776eSAlan Wright 		break;
392a0aa776eSAlan Wright 	case NETBIOS_EVENT_BROWSER_START:
393a0aa776eSAlan Wright 	case NETBIOS_EVENT_BROWSER_STOP:
394a0aa776eSAlan Wright 		svc = &nbtd.nbs_browser.s_up;
395a0aa776eSAlan Wright 		desired_state =
396a0aa776eSAlan Wright 		    (event == NETBIOS_EVENT_BROWSER_START) ? B_TRUE : B_FALSE;
397a0aa776eSAlan Wright 		break;
398a0aa776eSAlan Wright 	default:
399a0aa776eSAlan Wright 		(void) mutex_unlock(&nbtd.nbs_mtx);
400a0aa776eSAlan Wright 		return;
401a0aa776eSAlan Wright 	}
402a0aa776eSAlan Wright 
403a0aa776eSAlan Wright 	while (*svc != desired_state) {
404a0aa776eSAlan Wright 		if (nbtd.nbs_state != NETBIOS_STATE_RUNNING)
405a0aa776eSAlan Wright 			break;
406a0aa776eSAlan Wright 
407a0aa776eSAlan Wright 		(void) cond_wait(&nbtd.nbs_cv, &nbtd.nbs_mtx);
408a0aa776eSAlan Wright 	}
409a0aa776eSAlan Wright 
410a0aa776eSAlan Wright 	(void) mutex_unlock(&nbtd.nbs_mtx);
411a0aa776eSAlan Wright }
412a0aa776eSAlan Wright 
413a0aa776eSAlan Wright void
414a0aa776eSAlan Wright smb_netbios_sleep(time_t seconds)
415a0aa776eSAlan Wright {
416a0aa776eSAlan Wright 	timestruc_t reltimeout;
417a0aa776eSAlan Wright 
418a0aa776eSAlan Wright 	(void) mutex_lock(&nbtd.nbs_mtx);
419a0aa776eSAlan Wright 
420a0aa776eSAlan Wright 	if (nbtd.nbs_state == NETBIOS_STATE_RUNNING) {
421a0aa776eSAlan Wright 		if (seconds == 0)
422a0aa776eSAlan Wright 			seconds  = 1;
423a0aa776eSAlan Wright 		reltimeout.tv_sec = seconds;
424a0aa776eSAlan Wright 		reltimeout.tv_nsec = 0;
425a0aa776eSAlan Wright 
426a0aa776eSAlan Wright 		(void) cond_reltimedwait(&nbtd.nbs_cv,
427a0aa776eSAlan Wright 		    &nbtd.nbs_mtx, &reltimeout);
428a0aa776eSAlan Wright 	}
429a0aa776eSAlan Wright 
430a0aa776eSAlan Wright 	(void) mutex_unlock(&nbtd.nbs_mtx);
431a0aa776eSAlan Wright }
432a0aa776eSAlan Wright 
433a0aa776eSAlan Wright boolean_t
434a0aa776eSAlan Wright smb_netbios_running(void)
435a0aa776eSAlan Wright {
436a0aa776eSAlan Wright 	boolean_t is_running;
437a0aa776eSAlan Wright 
438a0aa776eSAlan Wright 	(void) mutex_lock(&nbtd.nbs_mtx);
439a0aa776eSAlan Wright 
440a0aa776eSAlan Wright 	if (nbtd.nbs_state == NETBIOS_STATE_RUNNING)
441a0aa776eSAlan Wright 		is_running = B_TRUE;
442a0aa776eSAlan Wright 	else
443a0aa776eSAlan Wright 		is_running = B_FALSE;
444a0aa776eSAlan Wright 
445a0aa776eSAlan Wright 	(void) mutex_unlock(&nbtd.nbs_mtx);
446a0aa776eSAlan Wright 	return (is_running);
447a0aa776eSAlan Wright }
448a0aa776eSAlan Wright 
449a0aa776eSAlan Wright boolean_t
450a0aa776eSAlan Wright smb_netbios_error(void)
451a0aa776eSAlan Wright {
452a0aa776eSAlan Wright 	boolean_t error;
453a0aa776eSAlan Wright 
454a0aa776eSAlan Wright 	(void) mutex_lock(&nbtd.nbs_mtx);
455a0aa776eSAlan Wright 
456a0aa776eSAlan Wright 	if (nbtd.nbs_state == NETBIOS_STATE_ERROR)
457a0aa776eSAlan Wright 		error = B_TRUE;
458a0aa776eSAlan Wright 	else
459a0aa776eSAlan Wright 		error = B_FALSE;
460a0aa776eSAlan Wright 
461a0aa776eSAlan Wright 	(void) mutex_unlock(&nbtd.nbs_mtx);
462a0aa776eSAlan Wright 	return (error);
463a0aa776eSAlan Wright }
464a0aa776eSAlan Wright 
465a0aa776eSAlan Wright /*
466a0aa776eSAlan Wright  * Write the service state to /var/run/smb/netbios.
467a0aa776eSAlan Wright  *
468a0aa776eSAlan Wright  * This is a private interface.  To update the file use:
469a0aa776eSAlan Wright  *	smb_netbios_event(NETBIOS_EVENT_DUMP);
470a0aa776eSAlan Wright  */
471a0aa776eSAlan Wright static void
472a0aa776eSAlan Wright smb_netbios_dump(void)
473a0aa776eSAlan Wright {
474a0aa776eSAlan Wright 	static struct {
475a0aa776eSAlan Wright 		netbios_state_t state;
476a0aa776eSAlan Wright 		char		*text;
477a0aa776eSAlan Wright 	} sm[] = {
478a0aa776eSAlan Wright 		{ NETBIOS_STATE_INIT,		"init" },
479a0aa776eSAlan Wright 		{ NETBIOS_STATE_RUNNING,	"running" },
480a0aa776eSAlan Wright 		{ NETBIOS_STATE_CLOSING,	"closing" },
481a0aa776eSAlan Wright 		{ NETBIOS_STATE_ERROR,		"error" }
482a0aa776eSAlan Wright 	};
483a0aa776eSAlan Wright 
484a0aa776eSAlan Wright 	char		fname[MAXPATHLEN];
485a0aa776eSAlan Wright 	FILE		*fp;
486a0aa776eSAlan Wright 	struct passwd	*pwd;
487a0aa776eSAlan Wright 	struct group	*grp;
488a0aa776eSAlan Wright 	uid_t		uid;
489a0aa776eSAlan Wright 	gid_t		gid;
490a0aa776eSAlan Wright 	char		*last_event = "none";
491a0aa776eSAlan Wright 	int		i;
492a0aa776eSAlan Wright 
493a0aa776eSAlan Wright 	(void) snprintf(fname, MAXPATHLEN, "%s/%s",
494a0aa776eSAlan Wright 	    SMB_VARRUN_DIR, SMB_NETBIOS_DUMP_FILE);
495a0aa776eSAlan Wright 
496a0aa776eSAlan Wright 	if ((fp = fopen(fname, "w")) == NULL)
497a0aa776eSAlan Wright 		return;
498a0aa776eSAlan Wright 
499a0aa776eSAlan Wright 	pwd = getpwnam("root");
500a0aa776eSAlan Wright 	grp = getgrnam("sys");
501a0aa776eSAlan Wright 	uid = (pwd == NULL) ? 0 : pwd->pw_uid;
502a0aa776eSAlan Wright 	gid = (grp == NULL) ? 3 : grp->gr_gid;
503a0aa776eSAlan Wright 
504a0aa776eSAlan Wright 	(void) lockf(fileno(fp), F_LOCK, 0);
505a0aa776eSAlan Wright 	(void) fchmod(fileno(fp), 0600);
506a0aa776eSAlan Wright 	(void) fchown(fileno(fp), uid, gid);
507a0aa776eSAlan Wright 
508a0aa776eSAlan Wright 	if (nbtd.nbs_last_event)
509a0aa776eSAlan Wright 		last_event = nbtd.nbs_last_event;
510a0aa776eSAlan Wright 
511a0aa776eSAlan Wright 	for (i = 0; i < sizeof (sm) / sizeof (sm[0]); ++i) {
512a0aa776eSAlan Wright 		if (nbtd.nbs_state == sm[i].state) {
513a0aa776eSAlan Wright 			(void) fprintf(fp,
514a0aa776eSAlan Wright 			    "State             %s  (event: %s, errors: %u)\n",
515a0aa776eSAlan Wright 			    sm[i].text, last_event, nbtd.nbs_errors);
516a0aa776eSAlan Wright 			break;
517a0aa776eSAlan Wright 		}
518a0aa776eSAlan Wright 	}
519a0aa776eSAlan Wright 
520a0aa776eSAlan Wright 	(void) fprintf(fp, "Name Service      %-7s  (%u)\n",
521a0aa776eSAlan Wright 	    nbtd.nbs_ns.s_up ? "up" : "down", nbtd.nbs_ns.s_tid);
522a0aa776eSAlan Wright 	(void) fprintf(fp, "Datagram Service  %-7s  (%u)\n",
523a0aa776eSAlan Wright 	    nbtd.nbs_dgm.s_up ? "up" : "down", nbtd.nbs_dgm.s_tid);
524a0aa776eSAlan Wright 	(void) fprintf(fp, "Browser Service   %-7s  (%u)\n",
525a0aa776eSAlan Wright 	    nbtd.nbs_browser.s_up ? "up" : "down", nbtd.nbs_browser.s_tid);
526a0aa776eSAlan Wright 	(void) fprintf(fp, "Timer Service     %-7s  (%u)\n",
527a0aa776eSAlan Wright 	    nbtd.nbs_timer.s_up ? "up" : "down", nbtd.nbs_timer.s_tid);
528a0aa776eSAlan Wright 
529a0aa776eSAlan Wright 	smb_netbios_cache_dump(fp);
530a0aa776eSAlan Wright 
531a0aa776eSAlan Wright 	(void) lockf(fileno(fp), F_ULOCK, 0);
532a0aa776eSAlan Wright 	(void) fclose(fp);
533a0aa776eSAlan Wright }
534