xref: /illumos-gate/usr/src/lib/smbsrv/libsmbns/common/smbns_netbios.c (revision a0aa776e20803c84edd153d9cb584fd67163aef3)
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 /*
22*a0aa776eSAlan 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 
31*a0aa776eSAlan Wright #include <sys/tzfile.h>
32*a0aa776eSAlan 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>
39*a0aa776eSAlan Wright #include <stdio.h>
40*a0aa776eSAlan Wright #include <pwd.h>
41*a0aa776eSAlan Wright #include <grp.h>
42da6c28aaSamw #include <smbns_netbios.h>
43da6c28aaSamw 
44*a0aa776eSAlan Wright #define	SMB_NETBIOS_DUMP_FILE		"netbios"
45da6c28aaSamw 
46*a0aa776eSAlan Wright static netbios_service_t nbtd;
47da6c28aaSamw 
48*a0aa776eSAlan Wright static void smb_netbios_shutdown(void);
49*a0aa776eSAlan Wright static void *smb_netbios_service(void *);
50*a0aa776eSAlan Wright static void smb_netbios_dump(void);
51da6c28aaSamw 
52*a0aa776eSAlan Wright /*
53*a0aa776eSAlan Wright  * Start the NetBIOS services
54*a0aa776eSAlan Wright  */
55*a0aa776eSAlan Wright int
56*a0aa776eSAlan Wright smb_netbios_start(void)
57da6c28aaSamw {
58*a0aa776eSAlan Wright 	pthread_t	tid;
59*a0aa776eSAlan Wright 	pthread_attr_t	attr;
60*a0aa776eSAlan Wright 	int		rc;
61*a0aa776eSAlan Wright 
62*a0aa776eSAlan Wright 	if (smb_netbios_cache_init() < 0)
63*a0aa776eSAlan Wright 		return (-1);
64*a0aa776eSAlan Wright 
65*a0aa776eSAlan Wright 	(void) pthread_attr_init(&attr);
66*a0aa776eSAlan Wright 	(void) pthread_attr_setdetachstate(&attr, PTHREAD_CREATE_DETACHED);
67*a0aa776eSAlan Wright 	rc = pthread_create(&tid, &attr, smb_netbios_service, NULL);
68*a0aa776eSAlan Wright 	(void) pthread_attr_destroy(&attr);
69*a0aa776eSAlan Wright 	return (rc);
70da6c28aaSamw }
71da6c28aaSamw 
72*a0aa776eSAlan Wright /*
73*a0aa776eSAlan Wright  * Stop the NetBIOS services
74*a0aa776eSAlan Wright  */
75da6c28aaSamw void
76*a0aa776eSAlan Wright smb_netbios_stop(void)
77da6c28aaSamw {
78*a0aa776eSAlan Wright 	char	fname[MAXPATHLEN];
79da6c28aaSamw 
80*a0aa776eSAlan Wright 	smb_netbios_event(NETBIOS_EVENT_STOP);
81*a0aa776eSAlan Wright 
82*a0aa776eSAlan Wright 	(void) snprintf(fname, MAXPATHLEN, "%s/%s",
83*a0aa776eSAlan Wright 	    SMB_VARRUN_DIR, SMB_NETBIOS_DUMP_FILE);
84*a0aa776eSAlan Wright 	(void) unlink(fname);
85da6c28aaSamw 
86da6c28aaSamw }
87da6c28aaSamw 
88*a0aa776eSAlan Wright /*
89*a0aa776eSAlan Wright  * Launch the NetBIOS Name Service, Datagram and Browser services
90*a0aa776eSAlan Wright  * and then sit in a loop providing a 1 second resolution timer.
91*a0aa776eSAlan Wright  * The timer will:
92*a0aa776eSAlan Wright  *	- update the netbios stats file every 10 minutes
93*a0aa776eSAlan Wright  *	- clean the cache every 10 minutes
94*a0aa776eSAlan Wright  */
95*a0aa776eSAlan Wright /*ARGSUSED*/
96*a0aa776eSAlan Wright static void *
97*a0aa776eSAlan Wright smb_netbios_service(void *arg)
98da6c28aaSamw {
99*a0aa776eSAlan Wright 	static uint32_t	ticks = 0;
100*a0aa776eSAlan Wright 	pthread_t	tid;
101*a0aa776eSAlan Wright 	int		rc;
102da6c28aaSamw 
103*a0aa776eSAlan Wright 	smb_netbios_event(NETBIOS_EVENT_START);
104da6c28aaSamw 
105*a0aa776eSAlan Wright 	rc = pthread_create(&tid, NULL, smb_netbios_name_service, NULL);
106*a0aa776eSAlan Wright 	if (rc != 0) {
107*a0aa776eSAlan Wright 		smb_netbios_shutdown();
108*a0aa776eSAlan Wright 		return (NULL);
109da6c28aaSamw 	}
110da6c28aaSamw 
111*a0aa776eSAlan Wright 	smb_netbios_wait(NETBIOS_EVENT_NS_START);
112*a0aa776eSAlan Wright 	if (smb_netbios_error()) {
113da6c28aaSamw 		smb_netbios_shutdown();
114*a0aa776eSAlan Wright 		return (NULL);
115da6c28aaSamw 	}
116da6c28aaSamw 
117da6c28aaSamw 	smb_netbios_name_config();
118da6c28aaSamw 
119*a0aa776eSAlan Wright 	rc = pthread_create(&tid, NULL, smb_netbios_datagram_service, NULL);
120dc20a302Sas 	if (rc != 0) {
121dc20a302Sas 		smb_netbios_shutdown();
122*a0aa776eSAlan Wright 		return (NULL);
123da6c28aaSamw 	}
124da6c28aaSamw 
125*a0aa776eSAlan Wright 	smb_netbios_wait(NETBIOS_EVENT_DGM_START);
126*a0aa776eSAlan Wright 	if (smb_netbios_error()) {
127da6c28aaSamw 		smb_netbios_shutdown();
128*a0aa776eSAlan Wright 		return (NULL);
129da6c28aaSamw 	}
130da6c28aaSamw 
131*a0aa776eSAlan Wright 	rc = pthread_create(&tid, NULL, smb_browser_service, NULL);
132dc20a302Sas 	if (rc != 0) {
133dc20a302Sas 		smb_netbios_shutdown();
134*a0aa776eSAlan Wright 		return (NULL);
135dc20a302Sas 	}
136da6c28aaSamw 
137*a0aa776eSAlan Wright 	smb_netbios_event(NETBIOS_EVENT_TIMER_START);
138dc20a302Sas 
139*a0aa776eSAlan Wright 	for (;;) {
140da6c28aaSamw 		(void) sleep(1);
1417b59d02dSjb 		ticks++;
142da6c28aaSamw 
143*a0aa776eSAlan Wright 		if (!smb_netbios_running())
144da6c28aaSamw 			break;
1457b59d02dSjb 
1467b59d02dSjb 		smb_netbios_datagram_tick();
1477b59d02dSjb 		smb_netbios_name_tick();
1487b59d02dSjb 
149*a0aa776eSAlan Wright 		if ((ticks % 600) == 0) {
150*a0aa776eSAlan Wright 			smb_netbios_event(NETBIOS_EVENT_DUMP);
1517b59d02dSjb 			smb_netbios_cache_clean();
152*a0aa776eSAlan Wright 		}
153da6c28aaSamw 	}
154da6c28aaSamw 
155*a0aa776eSAlan Wright 	smb_netbios_event(NETBIOS_EVENT_TIMER_STOP);
156*a0aa776eSAlan Wright 	smb_netbios_shutdown();
157*a0aa776eSAlan Wright 	return (NULL);
158*a0aa776eSAlan Wright }
159*a0aa776eSAlan Wright 
160*a0aa776eSAlan Wright static void
161*a0aa776eSAlan Wright smb_netbios_shutdown(void)
162*a0aa776eSAlan Wright {
163*a0aa776eSAlan Wright 	(void) pthread_join(nbtd.nbs_browser.s_tid, 0);
164*a0aa776eSAlan Wright 	(void) pthread_join(nbtd.nbs_dgm.s_tid, 0);
165*a0aa776eSAlan Wright 	(void) pthread_join(nbtd.nbs_ns.s_tid, 0);
166da6c28aaSamw 
167*a0aa776eSAlan Wright 	nbtd.nbs_browser.s_tid = 0;
168*a0aa776eSAlan Wright 	nbtd.nbs_dgm.s_tid = 0;
169*a0aa776eSAlan Wright 	nbtd.nbs_ns.s_tid = 0;
170*a0aa776eSAlan Wright 
171*a0aa776eSAlan Wright 	smb_netbios_cache_fini();
172*a0aa776eSAlan Wright 
173*a0aa776eSAlan Wright 	if (smb_netbios_error()) {
174*a0aa776eSAlan Wright 		smb_netbios_event(NETBIOS_EVENT_RESET);
175*a0aa776eSAlan Wright 		if (smb_netbios_start() != 0)
176*a0aa776eSAlan Wright 			syslog(LOG_ERR, "netbios: restart failed");
177*a0aa776eSAlan 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 
217da6c28aaSamw 	(void) utf8_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 }
254*a0aa776eSAlan Wright 
255*a0aa776eSAlan Wright void
256*a0aa776eSAlan Wright smb_netbios_event(netbios_event_t event)
257*a0aa776eSAlan Wright {
258*a0aa776eSAlan Wright 	static char *event_msg[] = {
259*a0aa776eSAlan Wright 		"startup",
260*a0aa776eSAlan Wright 		"shutdown",
261*a0aa776eSAlan Wright 		"restart",
262*a0aa776eSAlan Wright 		"name service started",
263*a0aa776eSAlan Wright 		"name service stopped",
264*a0aa776eSAlan Wright 		"datagram service started",
265*a0aa776eSAlan Wright 		"datagram service stopped",
266*a0aa776eSAlan Wright 		"browser service started",
267*a0aa776eSAlan Wright 		"browser service stopped",
268*a0aa776eSAlan Wright 		"timer service started",
269*a0aa776eSAlan Wright 		"timer service stopped",
270*a0aa776eSAlan Wright 		"error",
271*a0aa776eSAlan Wright 		"dump"
272*a0aa776eSAlan Wright 	};
273*a0aa776eSAlan Wright 
274*a0aa776eSAlan Wright 	(void) mutex_lock(&nbtd.nbs_mtx);
275*a0aa776eSAlan Wright 
276*a0aa776eSAlan Wright 	if (event == NETBIOS_EVENT_DUMP) {
277*a0aa776eSAlan Wright 		if (nbtd.nbs_last_event == NULL)
278*a0aa776eSAlan Wright 			nbtd.nbs_last_event = event_msg[event];
279*a0aa776eSAlan Wright 		smb_netbios_dump();
280*a0aa776eSAlan Wright 		(void) mutex_unlock(&nbtd.nbs_mtx);
281*a0aa776eSAlan Wright 		return;
282*a0aa776eSAlan Wright 	}
283*a0aa776eSAlan Wright 
284*a0aa776eSAlan Wright 	nbtd.nbs_last_event = event_msg[event];
285*a0aa776eSAlan Wright 	syslog(LOG_DEBUG, "netbios: %s", nbtd.nbs_last_event);
286*a0aa776eSAlan Wright 
287*a0aa776eSAlan Wright 	switch (nbtd.nbs_state) {
288*a0aa776eSAlan Wright 	case NETBIOS_STATE_INIT:
289*a0aa776eSAlan Wright 		if (event == NETBIOS_EVENT_START)
290*a0aa776eSAlan Wright 			nbtd.nbs_state = NETBIOS_STATE_RUNNING;
291*a0aa776eSAlan Wright 		break;
292*a0aa776eSAlan Wright 
293*a0aa776eSAlan Wright 	case NETBIOS_STATE_RUNNING:
294*a0aa776eSAlan Wright 		switch (event) {
295*a0aa776eSAlan Wright 		case NETBIOS_EVENT_NS_START:
296*a0aa776eSAlan Wright 			nbtd.nbs_ns.s_tid = pthread_self();
297*a0aa776eSAlan Wright 			nbtd.nbs_ns.s_up = B_TRUE;
298*a0aa776eSAlan Wright 			break;
299*a0aa776eSAlan Wright 		case NETBIOS_EVENT_NS_STOP:
300*a0aa776eSAlan Wright 			nbtd.nbs_ns.s_up = B_FALSE;
301*a0aa776eSAlan Wright 			break;
302*a0aa776eSAlan Wright 		case NETBIOS_EVENT_DGM_START:
303*a0aa776eSAlan Wright 			nbtd.nbs_dgm.s_tid = pthread_self();
304*a0aa776eSAlan Wright 			nbtd.nbs_dgm.s_up = B_TRUE;
305*a0aa776eSAlan Wright 			break;
306*a0aa776eSAlan Wright 		case NETBIOS_EVENT_DGM_STOP:
307*a0aa776eSAlan Wright 			nbtd.nbs_dgm.s_up = B_FALSE;
308*a0aa776eSAlan Wright 			break;
309*a0aa776eSAlan Wright 		case NETBIOS_EVENT_BROWSER_START:
310*a0aa776eSAlan Wright 			nbtd.nbs_browser.s_tid = pthread_self();
311*a0aa776eSAlan Wright 			nbtd.nbs_browser.s_up = B_TRUE;
312*a0aa776eSAlan Wright 			break;
313*a0aa776eSAlan Wright 		case NETBIOS_EVENT_BROWSER_STOP:
314*a0aa776eSAlan Wright 			nbtd.nbs_browser.s_up = B_FALSE;
315*a0aa776eSAlan Wright 			break;
316*a0aa776eSAlan Wright 		case NETBIOS_EVENT_TIMER_START:
317*a0aa776eSAlan Wright 			nbtd.nbs_timer.s_tid = pthread_self();
318*a0aa776eSAlan Wright 			nbtd.nbs_timer.s_up = B_TRUE;
319*a0aa776eSAlan Wright 			break;
320*a0aa776eSAlan Wright 		case NETBIOS_EVENT_TIMER_STOP:
321*a0aa776eSAlan Wright 			nbtd.nbs_timer.s_up = B_FALSE;
322*a0aa776eSAlan Wright 			break;
323*a0aa776eSAlan Wright 		case NETBIOS_EVENT_STOP:
324*a0aa776eSAlan Wright 			nbtd.nbs_state = NETBIOS_STATE_CLOSING;
325*a0aa776eSAlan Wright 			break;
326*a0aa776eSAlan Wright 		case NETBIOS_EVENT_ERROR:
327*a0aa776eSAlan Wright 			nbtd.nbs_state = NETBIOS_STATE_ERROR;
328*a0aa776eSAlan Wright 			++nbtd.nbs_errors;
329*a0aa776eSAlan Wright 			break;
330*a0aa776eSAlan Wright 		default:
331*a0aa776eSAlan Wright 			break;
332*a0aa776eSAlan Wright 		}
333*a0aa776eSAlan Wright 		break;
334*a0aa776eSAlan Wright 
335*a0aa776eSAlan Wright 	case NETBIOS_STATE_CLOSING:
336*a0aa776eSAlan Wright 	case NETBIOS_STATE_ERROR:
337*a0aa776eSAlan Wright 	default:
338*a0aa776eSAlan Wright 		switch (event) {
339*a0aa776eSAlan Wright 		case NETBIOS_EVENT_NS_STOP:
340*a0aa776eSAlan Wright 			nbtd.nbs_ns.s_up = B_FALSE;
341*a0aa776eSAlan Wright 			break;
342*a0aa776eSAlan Wright 		case NETBIOS_EVENT_DGM_STOP:
343*a0aa776eSAlan Wright 			nbtd.nbs_dgm.s_up = B_FALSE;
344*a0aa776eSAlan Wright 			break;
345*a0aa776eSAlan Wright 		case NETBIOS_EVENT_BROWSER_STOP:
346*a0aa776eSAlan Wright 			nbtd.nbs_browser.s_up = B_FALSE;
347*a0aa776eSAlan Wright 			break;
348*a0aa776eSAlan Wright 		case NETBIOS_EVENT_TIMER_STOP:
349*a0aa776eSAlan Wright 			nbtd.nbs_timer.s_up = B_FALSE;
350*a0aa776eSAlan Wright 			break;
351*a0aa776eSAlan Wright 		case NETBIOS_EVENT_STOP:
352*a0aa776eSAlan Wright 			nbtd.nbs_state = NETBIOS_STATE_CLOSING;
353*a0aa776eSAlan Wright 			break;
354*a0aa776eSAlan Wright 		case NETBIOS_EVENT_RESET:
355*a0aa776eSAlan Wright 			nbtd.nbs_state = NETBIOS_STATE_INIT;
356*a0aa776eSAlan Wright 			break;
357*a0aa776eSAlan Wright 		case NETBIOS_EVENT_ERROR:
358*a0aa776eSAlan Wright 			++nbtd.nbs_errors;
359*a0aa776eSAlan Wright 			break;
360*a0aa776eSAlan Wright 		default:
361*a0aa776eSAlan Wright 			break;
362*a0aa776eSAlan Wright 		}
363*a0aa776eSAlan Wright 		break;
364*a0aa776eSAlan Wright 	}
365*a0aa776eSAlan Wright 
366*a0aa776eSAlan Wright 	smb_netbios_dump();
367*a0aa776eSAlan Wright 	(void) cond_broadcast(&nbtd.nbs_cv);
368*a0aa776eSAlan Wright 	(void) mutex_unlock(&nbtd.nbs_mtx);
369*a0aa776eSAlan Wright }
370*a0aa776eSAlan Wright 
371*a0aa776eSAlan Wright void
372*a0aa776eSAlan Wright smb_netbios_wait(netbios_event_t event)
373*a0aa776eSAlan Wright {
374*a0aa776eSAlan Wright 	boolean_t *svc = NULL;
375*a0aa776eSAlan Wright 	boolean_t desired_state;
376*a0aa776eSAlan Wright 
377*a0aa776eSAlan Wright 	(void) mutex_lock(&nbtd.nbs_mtx);
378*a0aa776eSAlan Wright 
379*a0aa776eSAlan Wright 	switch (event) {
380*a0aa776eSAlan Wright 	case NETBIOS_EVENT_NS_START:
381*a0aa776eSAlan Wright 	case NETBIOS_EVENT_NS_STOP:
382*a0aa776eSAlan Wright 		svc = &nbtd.nbs_ns.s_up;
383*a0aa776eSAlan Wright 		desired_state =
384*a0aa776eSAlan Wright 		    (event == NETBIOS_EVENT_NS_START) ? B_TRUE : B_FALSE;
385*a0aa776eSAlan Wright 		break;
386*a0aa776eSAlan Wright 	case NETBIOS_EVENT_DGM_START:
387*a0aa776eSAlan Wright 	case NETBIOS_EVENT_DGM_STOP:
388*a0aa776eSAlan Wright 		svc = &nbtd.nbs_dgm.s_up;
389*a0aa776eSAlan Wright 		desired_state =
390*a0aa776eSAlan Wright 		    (event == NETBIOS_EVENT_DGM_START) ? B_TRUE : B_FALSE;
391*a0aa776eSAlan Wright 		break;
392*a0aa776eSAlan Wright 	case NETBIOS_EVENT_BROWSER_START:
393*a0aa776eSAlan Wright 	case NETBIOS_EVENT_BROWSER_STOP:
394*a0aa776eSAlan Wright 		svc = &nbtd.nbs_browser.s_up;
395*a0aa776eSAlan Wright 		desired_state =
396*a0aa776eSAlan Wright 		    (event == NETBIOS_EVENT_BROWSER_START) ? B_TRUE : B_FALSE;
397*a0aa776eSAlan Wright 		break;
398*a0aa776eSAlan Wright 	default:
399*a0aa776eSAlan Wright 		(void) mutex_unlock(&nbtd.nbs_mtx);
400*a0aa776eSAlan Wright 		return;
401*a0aa776eSAlan Wright 	}
402*a0aa776eSAlan Wright 
403*a0aa776eSAlan Wright 	while (*svc != desired_state) {
404*a0aa776eSAlan Wright 		if (nbtd.nbs_state != NETBIOS_STATE_RUNNING)
405*a0aa776eSAlan Wright 			break;
406*a0aa776eSAlan Wright 
407*a0aa776eSAlan Wright 		(void) cond_wait(&nbtd.nbs_cv, &nbtd.nbs_mtx);
408*a0aa776eSAlan Wright 	}
409*a0aa776eSAlan Wright 
410*a0aa776eSAlan Wright 	(void) mutex_unlock(&nbtd.nbs_mtx);
411*a0aa776eSAlan Wright }
412*a0aa776eSAlan Wright 
413*a0aa776eSAlan Wright void
414*a0aa776eSAlan Wright smb_netbios_sleep(time_t seconds)
415*a0aa776eSAlan Wright {
416*a0aa776eSAlan Wright 	timestruc_t reltimeout;
417*a0aa776eSAlan Wright 
418*a0aa776eSAlan Wright 	(void) mutex_lock(&nbtd.nbs_mtx);
419*a0aa776eSAlan Wright 
420*a0aa776eSAlan Wright 	if (nbtd.nbs_state == NETBIOS_STATE_RUNNING) {
421*a0aa776eSAlan Wright 		if (seconds == 0)
422*a0aa776eSAlan Wright 			seconds  = 1;
423*a0aa776eSAlan Wright 		reltimeout.tv_sec = seconds;
424*a0aa776eSAlan Wright 		reltimeout.tv_nsec = 0;
425*a0aa776eSAlan Wright 
426*a0aa776eSAlan Wright 		(void) cond_reltimedwait(&nbtd.nbs_cv,
427*a0aa776eSAlan Wright 		    &nbtd.nbs_mtx, &reltimeout);
428*a0aa776eSAlan Wright 	}
429*a0aa776eSAlan Wright 
430*a0aa776eSAlan Wright 	(void) mutex_unlock(&nbtd.nbs_mtx);
431*a0aa776eSAlan Wright }
432*a0aa776eSAlan Wright 
433*a0aa776eSAlan Wright boolean_t
434*a0aa776eSAlan Wright smb_netbios_running(void)
435*a0aa776eSAlan Wright {
436*a0aa776eSAlan Wright 	boolean_t is_running;
437*a0aa776eSAlan Wright 
438*a0aa776eSAlan Wright 	(void) mutex_lock(&nbtd.nbs_mtx);
439*a0aa776eSAlan Wright 
440*a0aa776eSAlan Wright 	if (nbtd.nbs_state == NETBIOS_STATE_RUNNING)
441*a0aa776eSAlan Wright 		is_running = B_TRUE;
442*a0aa776eSAlan Wright 	else
443*a0aa776eSAlan Wright 		is_running = B_FALSE;
444*a0aa776eSAlan Wright 
445*a0aa776eSAlan Wright 	(void) mutex_unlock(&nbtd.nbs_mtx);
446*a0aa776eSAlan Wright 	return (is_running);
447*a0aa776eSAlan Wright }
448*a0aa776eSAlan Wright 
449*a0aa776eSAlan Wright boolean_t
450*a0aa776eSAlan Wright smb_netbios_error(void)
451*a0aa776eSAlan Wright {
452*a0aa776eSAlan Wright 	boolean_t error;
453*a0aa776eSAlan Wright 
454*a0aa776eSAlan Wright 	(void) mutex_lock(&nbtd.nbs_mtx);
455*a0aa776eSAlan Wright 
456*a0aa776eSAlan Wright 	if (nbtd.nbs_state == NETBIOS_STATE_ERROR)
457*a0aa776eSAlan Wright 		error = B_TRUE;
458*a0aa776eSAlan Wright 	else
459*a0aa776eSAlan Wright 		error = B_FALSE;
460*a0aa776eSAlan Wright 
461*a0aa776eSAlan Wright 	(void) mutex_unlock(&nbtd.nbs_mtx);
462*a0aa776eSAlan Wright 	return (error);
463*a0aa776eSAlan Wright }
464*a0aa776eSAlan Wright 
465*a0aa776eSAlan Wright /*
466*a0aa776eSAlan Wright  * Write the service state to /var/run/smb/netbios.
467*a0aa776eSAlan Wright  *
468*a0aa776eSAlan Wright  * This is a private interface.  To update the file use:
469*a0aa776eSAlan Wright  *	smb_netbios_event(NETBIOS_EVENT_DUMP);
470*a0aa776eSAlan Wright  */
471*a0aa776eSAlan Wright static void
472*a0aa776eSAlan Wright smb_netbios_dump(void)
473*a0aa776eSAlan Wright {
474*a0aa776eSAlan Wright 	static struct {
475*a0aa776eSAlan Wright 		netbios_state_t state;
476*a0aa776eSAlan Wright 		char		*text;
477*a0aa776eSAlan Wright 	} sm[] = {
478*a0aa776eSAlan Wright 		{ NETBIOS_STATE_INIT,		"init" },
479*a0aa776eSAlan Wright 		{ NETBIOS_STATE_RUNNING,	"running" },
480*a0aa776eSAlan Wright 		{ NETBIOS_STATE_CLOSING,	"closing" },
481*a0aa776eSAlan Wright 		{ NETBIOS_STATE_ERROR,		"error" }
482*a0aa776eSAlan Wright 	};
483*a0aa776eSAlan Wright 
484*a0aa776eSAlan Wright 	char		fname[MAXPATHLEN];
485*a0aa776eSAlan Wright 	FILE		*fp;
486*a0aa776eSAlan Wright 	struct passwd	*pwd;
487*a0aa776eSAlan Wright 	struct group	*grp;
488*a0aa776eSAlan Wright 	uid_t		uid;
489*a0aa776eSAlan Wright 	gid_t		gid;
490*a0aa776eSAlan Wright 	char		*last_event = "none";
491*a0aa776eSAlan Wright 	int		i;
492*a0aa776eSAlan Wright 
493*a0aa776eSAlan Wright 	(void) snprintf(fname, MAXPATHLEN, "%s/%s",
494*a0aa776eSAlan Wright 	    SMB_VARRUN_DIR, SMB_NETBIOS_DUMP_FILE);
495*a0aa776eSAlan Wright 
496*a0aa776eSAlan Wright 	if ((fp = fopen(fname, "w")) == NULL)
497*a0aa776eSAlan Wright 		return;
498*a0aa776eSAlan Wright 
499*a0aa776eSAlan Wright 	pwd = getpwnam("root");
500*a0aa776eSAlan Wright 	grp = getgrnam("sys");
501*a0aa776eSAlan Wright 	uid = (pwd == NULL) ? 0 : pwd->pw_uid;
502*a0aa776eSAlan Wright 	gid = (grp == NULL) ? 3 : grp->gr_gid;
503*a0aa776eSAlan Wright 
504*a0aa776eSAlan Wright 	(void) lockf(fileno(fp), F_LOCK, 0);
505*a0aa776eSAlan Wright 	(void) fchmod(fileno(fp), 0600);
506*a0aa776eSAlan Wright 	(void) fchown(fileno(fp), uid, gid);
507*a0aa776eSAlan Wright 
508*a0aa776eSAlan Wright 	if (nbtd.nbs_last_event)
509*a0aa776eSAlan Wright 		last_event = nbtd.nbs_last_event;
510*a0aa776eSAlan Wright 
511*a0aa776eSAlan Wright 	for (i = 0; i < sizeof (sm) / sizeof (sm[0]); ++i) {
512*a0aa776eSAlan Wright 		if (nbtd.nbs_state == sm[i].state) {
513*a0aa776eSAlan Wright 			(void) fprintf(fp,
514*a0aa776eSAlan Wright 			    "State             %s  (event: %s, errors: %u)\n",
515*a0aa776eSAlan Wright 			    sm[i].text, last_event, nbtd.nbs_errors);
516*a0aa776eSAlan Wright 			break;
517*a0aa776eSAlan Wright 		}
518*a0aa776eSAlan Wright 	}
519*a0aa776eSAlan Wright 
520*a0aa776eSAlan Wright 	(void) fprintf(fp, "Name Service      %-7s  (%u)\n",
521*a0aa776eSAlan Wright 	    nbtd.nbs_ns.s_up ? "up" : "down", nbtd.nbs_ns.s_tid);
522*a0aa776eSAlan Wright 	(void) fprintf(fp, "Datagram Service  %-7s  (%u)\n",
523*a0aa776eSAlan Wright 	    nbtd.nbs_dgm.s_up ? "up" : "down", nbtd.nbs_dgm.s_tid);
524*a0aa776eSAlan Wright 	(void) fprintf(fp, "Browser Service   %-7s  (%u)\n",
525*a0aa776eSAlan Wright 	    nbtd.nbs_browser.s_up ? "up" : "down", nbtd.nbs_browser.s_tid);
526*a0aa776eSAlan Wright 	(void) fprintf(fp, "Timer Service     %-7s  (%u)\n",
527*a0aa776eSAlan Wright 	    nbtd.nbs_timer.s_up ? "up" : "down", nbtd.nbs_timer.s_tid);
528*a0aa776eSAlan Wright 
529*a0aa776eSAlan Wright 	smb_netbios_cache_dump(fp);
530*a0aa776eSAlan Wright 
531*a0aa776eSAlan Wright 	(void) lockf(fileno(fp), F_ULOCK, 0);
532*a0aa776eSAlan Wright 	(void) fclose(fp);
533*a0aa776eSAlan Wright }
534