1da6c28aamw/*
2da6c28aamw * CDDL HEADER START
3da6c28aamw *
4da6c28aamw * The contents of this file are subject to the terms of the
5da6c28aamw * Common Development and Distribution License (the "License").
6da6c28aamw * You may not use this file except in compliance with the License.
7da6c28aamw *
8da6c28aamw * You can obtain a copy of the license at usr/src/OPENSOLARIS.LICENSE
9da6c28aamw * or http://www.opensolaris.org/os/licensing.
10da6c28aamw * See the License for the specific language governing permissions
11da6c28aamw * and limitations under the License.
12da6c28aamw *
13da6c28aamw * When distributing Covered Code, include this CDDL HEADER in each
14da6c28aamw * file and include the License file at usr/src/OPENSOLARIS.LICENSE.
15da6c28aamw * If applicable, add the following below this CDDL HEADER, with the
16da6c28aamw * fields enclosed by brackets "[]" replaced with your own identifying
17da6c28aamw * information: Portions Copyright [yyyy] [name of copyright owner]
18da6c28aamw *
19da6c28aamw * CDDL HEADER END
20da6c28aamw */
21da6c28aamw/*
22a0aa776Alan Wright * Copyright 2009 Sun Microsystems, Inc.  All rights reserved.
23da6c28aamw * Use is subject to license terms.
24da6c28aamw */
25da6c28aamw
26da6c28aamw/*
27da6c28aamw * Main startup code for SMB/NETBIOS and some utility routines
28da6c28aamw * for the NETBIOS layer.
29da6c28aamw */
30da6c28aamw
31a0aa776Alan Wright#include <sys/tzfile.h>
32a0aa776Alan Wright#include <assert.h>
33da6c28aamw#include <synch.h>
34da6c28aamw#include <unistd.h>
35da6c28aamw#include <syslog.h>
36da6c28aamw#include <string.h>
37da6c28aamw#include <strings.h>
38da6c28aamw#include <sys/socket.h>
39a0aa776Alan Wright#include <stdio.h>
40a0aa776Alan Wright#include <pwd.h>
41a0aa776Alan Wright#include <grp.h>
42da6c28aamw#include <smbns_netbios.h>
43da6c28aamw
44a0aa776Alan Wright#define	SMB_NETBIOS_DUMP_FILE		"netbios"
45da6c28aamw
46a0aa776Alan Wrightstatic netbios_service_t nbtd;
47da6c28aamw
48a0aa776Alan Wrightstatic void smb_netbios_shutdown(void);
49a0aa776Alan Wrightstatic void *smb_netbios_service(void *);
50a0aa776Alan Wrightstatic void smb_netbios_dump(void);
51da6c28aamw
52a0aa776Alan Wright/*
53a0aa776Alan Wright * Start the NetBIOS services
54a0aa776Alan Wright */
55a0aa776Alan Wrightint
56a0aa776Alan Wrightsmb_netbios_start(void)
57da6c28aamw{
58a0aa776Alan Wright	pthread_t	tid;
59a0aa776Alan Wright	pthread_attr_t	attr;
60a0aa776Alan Wright	int		rc;
61a0aa776Alan Wright
62a0aa776Alan Wright	if (smb_netbios_cache_init() < 0)
63a0aa776Alan Wright		return (-1);
64a0aa776Alan Wright
65a0aa776Alan Wright	(void) pthread_attr_init(&attr);
66a0aa776Alan Wright	(void) pthread_attr_setdetachstate(&attr, PTHREAD_CREATE_DETACHED);
67a0aa776Alan Wright	rc = pthread_create(&tid, &attr, smb_netbios_service, NULL);
68a0aa776Alan Wright	(void) pthread_attr_destroy(&attr);
69a0aa776Alan Wright	return (rc);
70da6c28aamw}
71da6c28aamw
72a0aa776Alan Wright/*
73a0aa776Alan Wright * Stop the NetBIOS services
74a0aa776Alan Wright */
75da6c28aamwvoid
76a0aa776Alan Wrightsmb_netbios_stop(void)
77da6c28aamw{
78a0aa776Alan Wright	char	fname[MAXPATHLEN];
79da6c28aamw
80a0aa776Alan Wright	smb_netbios_event(NETBIOS_EVENT_STOP);
81a0aa776Alan Wright
82a0aa776Alan Wright	(void) snprintf(fname, MAXPATHLEN, "%s/%s",
83a0aa776Alan Wright	    SMB_VARRUN_DIR, SMB_NETBIOS_DUMP_FILE);
84a0aa776Alan Wright	(void) unlink(fname);
85da6c28aamw
86da6c28aamw}
87da6c28aamw
88a0aa776Alan Wright/*
89a0aa776Alan Wright * Launch the NetBIOS Name Service, Datagram and Browser services
90a0aa776Alan Wright * and then sit in a loop providing a 1 second resolution timer.
91a0aa776Alan Wright * The timer will:
92a0aa776Alan Wright *	- update the netbios stats file every 10 minutes
93a0aa776Alan Wright *	- clean the cache every 10 minutes
94a0aa776Alan Wright */
95a0aa776Alan Wright/*ARGSUSED*/
96a0aa776Alan Wrightstatic void *
97a0aa776Alan Wrightsmb_netbios_service(void *arg)
98da6c28aamw{
99a0aa776Alan Wright	static uint32_t	ticks = 0;
100a0aa776Alan Wright	pthread_t	tid;
101a0aa776Alan Wright	int		rc;
102da6c28aamw
103a0aa776Alan Wright	smb_netbios_event(NETBIOS_EVENT_START);
104da6c28aamw
105a0aa776Alan Wright	rc = pthread_create(&tid, NULL, smb_netbios_name_service, NULL);
106a0aa776Alan Wright	if (rc != 0) {
107a0aa776Alan Wright		smb_netbios_shutdown();
108a0aa776Alan Wright		return (NULL);
109da6c28aamw	}
110da6c28aamw
111a0aa776Alan Wright	smb_netbios_wait(NETBIOS_EVENT_NS_START);
112a0aa776Alan Wright	if (smb_netbios_error()) {
113da6c28aamw		smb_netbios_shutdown();
114a0aa776Alan Wright		return (NULL);
115da6c28aamw	}
116da6c28aamw
117da6c28aamw	smb_netbios_name_config();
118da6c28aamw
119a0aa776Alan Wright	rc = pthread_create(&tid, NULL, smb_netbios_datagram_service, NULL);
120dc20a30as	if (rc != 0) {
121dc20a30as		smb_netbios_shutdown();
122a0aa776Alan Wright		return (NULL);
123da6c28aamw	}
124da6c28aamw
125a0aa776Alan Wright	smb_netbios_wait(NETBIOS_EVENT_DGM_START);
126a0aa776Alan Wright	if (smb_netbios_error()) {
127da6c28aamw		smb_netbios_shutdown();
128a0aa776Alan Wright		return (NULL);
129da6c28aamw	}
130da6c28aamw
131a0aa776Alan Wright	rc = pthread_create(&tid, NULL, smb_browser_service, NULL);
132dc20a30as	if (rc != 0) {
133dc20a30as		smb_netbios_shutdown();
134a0aa776Alan Wright		return (NULL);
135dc20a30as	}
136da6c28aamw
137a0aa776Alan Wright	smb_netbios_event(NETBIOS_EVENT_TIMER_START);
138dc20a30as
139a0aa776Alan Wright	for (;;) {
140da6c28aamw		(void) sleep(1);
1417b59d02jb		ticks++;
142da6c28aamw
143a0aa776Alan Wright		if (!smb_netbios_running())
144da6c28aamw			break;
1457b59d02jb
1467b59d02jb		smb_netbios_datagram_tick();
1477b59d02jb		smb_netbios_name_tick();
1487b59d02jb
149a0aa776Alan Wright		if ((ticks % 600) == 0) {
150a0aa776Alan Wright			smb_netbios_event(NETBIOS_EVENT_DUMP);
1517b59d02jb			smb_netbios_cache_clean();
152a0aa776Alan Wright		}
153da6c28aamw	}
154da6c28aamw
155a0aa776Alan Wright	smb_netbios_event(NETBIOS_EVENT_TIMER_STOP);
156a0aa776Alan Wright	smb_netbios_shutdown();
157a0aa776Alan Wright	return (NULL);
158a0aa776Alan Wright}
159a0aa776Alan Wright
160a0aa776Alan Wrightstatic void
161a0aa776Alan Wrightsmb_netbios_shutdown(void)
162a0aa776Alan Wright{
163a0aa776Alan Wright	(void) pthread_join(nbtd.nbs_browser.s_tid, 0);
164a0aa776Alan Wright	(void) pthread_join(nbtd.nbs_dgm.s_tid, 0);
165a0aa776Alan Wright	(void) pthread_join(nbtd.nbs_ns.s_tid, 0);
166da6c28aamw
167a0aa776Alan Wright	nbtd.nbs_browser.s_tid = 0;
168a0aa776Alan Wright	nbtd.nbs_dgm.s_tid = 0;
169a0aa776Alan Wright	nbtd.nbs_ns.s_tid = 0;
170a0aa776Alan Wright
171a0aa776Alan Wright	smb_netbios_cache_fini();
172a0aa776Alan Wright
173a0aa776Alan Wright	if (smb_netbios_error()) {
174a0aa776Alan Wright		smb_netbios_event(NETBIOS_EVENT_RESET);
175a0aa776Alan Wright		if (smb_netbios_start() != 0)
176a0aa776Alan Wright			syslog(LOG_ERR, "netbios: restart failed");
177a0aa776Alan Wright	}
178da6c28aamw}
179da6c28aamw
180da6c28aamwint
181da6c28aamwsmb_first_level_name_encode(struct name_entry *name,
182da6c28aamw				unsigned char *out, int max_out)
183da6c28aamw{
184da6c28aamw	return (netbios_first_level_name_encode(name->name, name->scope,
185da6c28aamw	    out, max_out));
186da6c28aamw}
187da6c28aamw
188da6c28aamwint
189da6c28aamwsmb_first_level_name_decode(unsigned char *in, struct name_entry *name)
190da6c28aamw{
191da6c28aamw	return (netbios_first_level_name_decode((char *)in, (char *)name->name,
192da6c28aamw	    (char *)name->scope));
193da6c28aamw}
194da6c28aamw
195da6c28aamw/*
196da6c28aamw * smb_encode_netbios_name
197da6c28aamw *
198da6c28aamw * Set up the name and scope fields in the destination name_entry structure.
199da6c28aamw * The name is padded with spaces to 15 bytes. The suffix is copied into the
200da6c28aamw * last byte, i.e. "netbiosname    <suffix>". The scope is copied and folded
201da6c28aamw * to uppercase.
202da6c28aamw */
203da6c28aamwvoid
204da6c28aamwsmb_encode_netbios_name(unsigned char *name, char suffix, unsigned char *scope,
205da6c28aamw    struct name_entry *dest)
206da6c28aamw{
2077b59d02jb	smb_tonetbiosname((char *)name, (char *)dest->name, suffix);
208da6c28aamw
2097b59d02jb	if (scope) {
210da6c28aamw		(void) strlcpy((char *)dest->scope, (const char *)scope,
2117b59d02jb		    sizeof (dest->scope));
2127b59d02jb	} else {
2137b59d02jb		(void) smb_config_getstr(SMB_CI_NBSCOPE, (char *)dest->scope,
2147b59d02jb		    sizeof (dest->scope));
215da6c28aamw	}
2167b59d02jb
217bbf6f00Jordan Brown	(void) smb_strupr((char *)dest->scope);
218da6c28aamw}
219da6c28aamw
220da6c28aamwvoid
221da6c28aamwsmb_init_name_struct(unsigned char *name, char suffix, unsigned char *scope,
222da6c28aamw    uint32_t ipaddr, unsigned short port, uint32_t attr,
223da6c28aamw    uint32_t addr_attr, struct name_entry *dest)
224da6c28aamw{
225da6c28aamw	bzero(dest, sizeof (struct name_entry));
226da6c28aamw	smb_encode_netbios_name(name, suffix, scope, dest);
227da6c28aamw
228da6c28aamw	switch (smb_node_type) {
229da6c28aamw	case 'H':
230da6c28aamw		dest->attributes = attr | NAME_ATTR_OWNER_TYPE_HNODE;
231da6c28aamw		break;
232da6c28aamw	case 'M':
233da6c28aamw		dest->attributes = attr | NAME_ATTR_OWNER_TYPE_MNODE;
234da6c28aamw		break;
235da6c28aamw	case 'P':
236da6c28aamw		dest->attributes = attr | NAME_ATTR_OWNER_TYPE_PNODE;
237da6c28aamw		break;
238da6c28aamw	case 'B':
239da6c28aamw	default:
240da6c28aamw		dest->attributes = attr | NAME_ATTR_OWNER_TYPE_BNODE;
241da6c28aamw		break;
242