xref: /illumos-gate/usr/src/lib/smbsrv/libsmbns/common/smbns_netbios.c (revision 7b59d02d2a384be9a08087b14defadd214b3c1dd)
1 /*
2  * CDDL HEADER START
3  *
4  * The contents of this file are subject to the terms of the
5  * Common Development and Distribution License (the "License").
6  * You may not use this file except in compliance with the License.
7  *
8  * You can obtain a copy of the license at usr/src/OPENSOLARIS.LICENSE
9  * or http://www.opensolaris.org/os/licensing.
10  * See the License for the specific language governing permissions
11  * and limitations under the License.
12  *
13  * When distributing Covered Code, include this CDDL HEADER in each
14  * file and include the License file at usr/src/OPENSOLARIS.LICENSE.
15  * If applicable, add the following below this CDDL HEADER, with the
16  * fields enclosed by brackets "[]" replaced with your own identifying
17  * information: Portions Copyright [yyyy] [name of copyright owner]
18  *
19  * CDDL HEADER END
20  */
21 /*
22  * Copyright 2008 Sun Microsystems, Inc.  All rights reserved.
23  * Use is subject to license terms.
24  */
25 
26 #pragma ident	"%Z%%M%	%I%	%E% SMI"
27 
28 /*
29  * Main startup code for SMB/NETBIOS and some utility routines
30  * for the NETBIOS layer.
31  */
32 
33 #include <synch.h>
34 #include <unistd.h>
35 #include <syslog.h>
36 #include <string.h>
37 #include <strings.h>
38 #include <sys/socket.h>
39 
40 #include <smbns_netbios.h>
41 
42 netbios_status_t nb_status;
43 
44 static pthread_t smb_nbns_thr; /* name service */
45 static pthread_t smb_nbds_thr; /* dgram service */
46 static pthread_t smb_nbts_thr; /* timer */
47 static pthread_t smb_nbbs_thr; /* browser */
48 
49 static void *smb_netbios_timer(void *);
50 
51 void
52 smb_netbios_chg_status(uint32_t status, int set)
53 {
54 	(void) mutex_lock(&nb_status.mtx);
55 	if (set)
56 		nb_status.state |= status;
57 	else
58 		nb_status.state &= ~status;
59 	(void) cond_broadcast(&nb_status.cv);
60 	(void) mutex_unlock(&nb_status.mtx);
61 }
62 
63 void
64 smb_netbios_shutdown(void)
65 {
66 	smb_netbios_chg_status(NETBIOS_SHUTTING_DOWN, 1);
67 
68 	(void) pthread_join(smb_nbts_thr, 0);
69 	(void) pthread_join(smb_nbbs_thr, 0);
70 	(void) pthread_join(smb_nbns_thr, 0);
71 	(void) pthread_join(smb_nbds_thr, 0);
72 
73 	nb_status.state = NETBIOS_SHUT_DOWN;
74 }
75 
76 int
77 smb_netbios_start(void)
78 {
79 	int rc;
80 	mutex_t *mp;
81 	cond_t *cvp;
82 
83 	/* Startup Netbios named; port 137 */
84 	rc = pthread_create(&smb_nbns_thr, 0,
85 	    smb_netbios_name_service_daemon, 0);
86 	if (rc)
87 		return (-1);
88 
89 	mp = &nb_status.mtx;
90 	cvp = &nb_status.cv;
91 
92 	(void) mutex_lock(mp);
93 	while (!(nb_status.state & (NETBIOS_NAME_SVC_RUNNING |
94 	    NETBIOS_NAME_SVC_FAILED))) {
95 		(void) cond_wait(cvp, mp);
96 	}
97 
98 	if (nb_status.state & NETBIOS_NAME_SVC_FAILED) {
99 		(void) mutex_unlock(mp);
100 		smb_netbios_shutdown();
101 		return (-1);
102 	}
103 	(void) mutex_unlock(mp);
104 
105 	smb_netbios_name_config();
106 
107 	/* Startup Netbios datagram service; port 138 */
108 	rc = pthread_create(&smb_nbds_thr, 0,
109 	    smb_netbios_datagram_service_daemon, 0);
110 	if (rc != 0) {
111 		smb_netbios_shutdown();
112 		return (-1);
113 	}
114 
115 	(void) mutex_lock(mp);
116 	while (!(nb_status.state & (NETBIOS_DATAGRAM_SVC_RUNNING |
117 	    NETBIOS_DATAGRAM_SVC_FAILED))) {
118 		(void) cond_wait(cvp, mp);
119 	}
120 
121 	if (nb_status.state & NETBIOS_DATAGRAM_SVC_FAILED) {
122 		(void) mutex_unlock(mp);
123 		smb_netbios_shutdown();
124 		return (-1);
125 	}
126 	(void) mutex_unlock(mp);
127 
128 	/* Startup Netbios browser service */
129 	rc = pthread_create(&smb_nbbs_thr, 0, smb_browser_daemon, 0);
130 	if (rc) {
131 		smb_netbios_shutdown();
132 		return (-1);
133 	}
134 
135 	/* Startup Our internal, 1 second resolution, timer */
136 	rc = pthread_create(&smb_nbts_thr, 0, smb_netbios_timer, 0);
137 	if (rc != 0) {
138 		smb_netbios_shutdown();
139 		return (-1);
140 	}
141 
142 	(void) mutex_lock(mp);
143 	while (!(nb_status.state & (NETBIOS_TIMER_RUNNING |
144 	    NETBIOS_TIMER_FAILED))) {
145 		(void) cond_wait(cvp, mp);
146 	}
147 
148 	if (nb_status.state & NETBIOS_TIMER_FAILED) {
149 		(void) mutex_unlock(mp);
150 		smb_netbios_shutdown();
151 		return (-1);
152 	}
153 	(void) mutex_unlock(mp);
154 
155 	return (0);
156 }
157 
158 /*ARGSUSED*/
159 static void *
160 smb_netbios_timer(void *arg)
161 {
162 	static unsigned int ticks = 0;
163 
164 	smb_netbios_chg_status(NETBIOS_TIMER_RUNNING, 1);
165 
166 	while ((nb_status.state & NETBIOS_SHUTTING_DOWN) == 0) {
167 		(void) sleep(1);
168 		ticks++;
169 
170 		if ((nb_status.state & NETBIOS_DATAGRAM_SVC_RUNNING) == 0)
171 			break;
172 
173 		if ((nb_status.state & NETBIOS_NAME_SVC_RUNNING) == 0)
174 			break;
175 
176 		smb_netbios_datagram_tick();
177 		smb_netbios_name_tick();
178 
179 		/* every 10 minutes */
180 		if ((ticks % 600) == 0)
181 			smb_netbios_cache_clean();
182 	}
183 
184 	nb_status.state &= ~NETBIOS_TIMER_RUNNING;
185 	if ((nb_status.state & NETBIOS_SHUTTING_DOWN) == 0) {
186 		/* either name or datagram service has failed */
187 		smb_netbios_shutdown();
188 	}
189 
190 	return (0);
191 }
192 
193 int
194 smb_first_level_name_encode(struct name_entry *name,
195 				unsigned char *out, int max_out)
196 {
197 	return (netbios_first_level_name_encode(name->name, name->scope,
198 	    out, max_out));
199 }
200 
201 int
202 smb_first_level_name_decode(unsigned char *in, struct name_entry *name)
203 {
204 	return (netbios_first_level_name_decode((char *)in, (char *)name->name,
205 	    (char *)name->scope));
206 }
207 
208 /*
209  * smb_encode_netbios_name
210  *
211  * Set up the name and scope fields in the destination name_entry structure.
212  * The name is padded with spaces to 15 bytes. The suffix is copied into the
213  * last byte, i.e. "netbiosname    <suffix>". The scope is copied and folded
214  * to uppercase.
215  */
216 void
217 smb_encode_netbios_name(unsigned char *name, char suffix, unsigned char *scope,
218     struct name_entry *dest)
219 {
220 	smb_tonetbiosname((char *)name, (char *)dest->name, suffix);
221 
222 	if (scope) {
223 		(void) strlcpy((char *)dest->scope, (const char *)scope,
224 		    sizeof (dest->scope));
225 	} else {
226 		(void) smb_config_getstr(SMB_CI_NBSCOPE, (char *)dest->scope,
227 		    sizeof (dest->scope));
228 	}
229 
230 	(void) utf8_strupr((char *)dest->scope);
231 }
232 
233 void
234 smb_init_name_struct(unsigned char *name, char suffix, unsigned char *scope,
235     uint32_t ipaddr, unsigned short port, uint32_t attr,
236     uint32_t addr_attr, struct name_entry *dest)
237 {
238 	bzero(dest, sizeof (struct name_entry));
239 	smb_encode_netbios_name(name, suffix, scope, dest);
240 
241 	switch (smb_node_type) {
242 	case 'H':
243 		dest->attributes = attr | NAME_ATTR_OWNER_TYPE_HNODE;
244 		break;
245 	case 'M':
246 		dest->attributes = attr | NAME_ATTR_OWNER_TYPE_MNODE;
247 		break;
248 	case 'P':
249 		dest->attributes = attr | NAME_ATTR_OWNER_TYPE_PNODE;
250 		break;
251 	case 'B':
252 	default:
253 		dest->attributes = attr | NAME_ATTR_OWNER_TYPE_BNODE;
254 		break;
255 	}
256 
257 	dest->addr_list.refresh_ttl = dest->addr_list.ttl =
258 	    TO_SECONDS(DEFAULT_TTL);
259 
260 	dest->addr_list.sin.sin_family = AF_INET;
261 	dest->addr_list.sinlen = sizeof (dest->addr_list.sin);
262 	dest->addr_list.sin.sin_addr.s_addr = ipaddr;
263 	dest->addr_list.sin.sin_port = port;
264 	dest->addr_list.attributes = addr_attr;
265 	dest->addr_list.forw = dest->addr_list.back = &dest->addr_list;
266 }
267