dmake: do not set MAKEFLAGS=k
[unleashed/tickless.git] / usr / src / lib / smbsrv / libsmbns / common / smbns_netbios.c
blobd5f029c455d064f6c0f157b82ee8f84d6b95942e
1 /*
2 * CDDL HEADER START
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.
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.
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]
19 * CDDL HEADER END
22 * Copyright 2009 Sun Microsystems, Inc. All rights reserved.
23 * Use is subject to license terms.
27 * Main startup code for SMB/NETBIOS and some utility routines
28 * for the NETBIOS layer.
31 #include <sys/tzfile.h>
32 #include <assert.h>
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 #include <stdio.h>
40 #include <pwd.h>
41 #include <grp.h>
42 #include <smbns_netbios.h>
44 #define SMB_NETBIOS_DUMP_FILE "netbios"
46 static netbios_service_t nbtd;
48 static void smb_netbios_shutdown(void);
49 static void *smb_netbios_service(void *);
50 static void smb_netbios_dump(void);
53 * Start the NetBIOS services
55 int
56 smb_netbios_start(void)
58 pthread_t tid;
59 pthread_attr_t attr;
60 int rc;
62 if (smb_netbios_cache_init() < 0)
63 return (-1);
65 (void) pthread_attr_init(&attr);
66 (void) pthread_attr_setdetachstate(&attr, PTHREAD_CREATE_DETACHED);
67 rc = pthread_create(&tid, &attr, smb_netbios_service, NULL);
68 (void) pthread_attr_destroy(&attr);
69 return (rc);
73 * Stop the NetBIOS services
75 void
76 smb_netbios_stop(void)
78 char fname[MAXPATHLEN];
80 smb_netbios_event(NETBIOS_EVENT_STOP);
82 (void) snprintf(fname, MAXPATHLEN, "%s/%s",
83 SMB_VARRUN_DIR, SMB_NETBIOS_DUMP_FILE);
84 (void) unlink(fname);
89 * Launch the NetBIOS Name Service, Datagram and Browser services
90 * and then sit in a loop providing a 1 second resolution timer.
91 * The timer will:
92 * - update the netbios stats file every 10 minutes
93 * - clean the cache every 10 minutes
95 /*ARGSUSED*/
96 static void *
97 smb_netbios_service(void *arg)
99 static uint32_t ticks = 0;
100 pthread_t tid;
101 int rc;
103 smb_netbios_event(NETBIOS_EVENT_START);
105 rc = pthread_create(&tid, NULL, smb_netbios_name_service, NULL);
106 if (rc != 0) {
107 smb_netbios_shutdown();
108 return (NULL);
111 smb_netbios_wait(NETBIOS_EVENT_NS_START);
112 if (smb_netbios_error()) {
113 smb_netbios_shutdown();
114 return (NULL);
117 smb_netbios_name_config();
119 rc = pthread_create(&tid, NULL, smb_netbios_datagram_service, NULL);
120 if (rc != 0) {
121 smb_netbios_shutdown();
122 return (NULL);
125 smb_netbios_wait(NETBIOS_EVENT_DGM_START);
126 if (smb_netbios_error()) {
127 smb_netbios_shutdown();
128 return (NULL);
131 rc = pthread_create(&tid, NULL, smb_browser_service, NULL);
132 if (rc != 0) {
133 smb_netbios_shutdown();
134 return (NULL);
137 smb_netbios_event(NETBIOS_EVENT_TIMER_START);
139 for (;;) {
140 (void) sleep(1);
141 ticks++;
143 if (!smb_netbios_running())
144 break;
146 smb_netbios_datagram_tick();
147 smb_netbios_name_tick();
149 if ((ticks % 600) == 0) {
150 smb_netbios_event(NETBIOS_EVENT_DUMP);
151 smb_netbios_cache_clean();
155 smb_netbios_event(NETBIOS_EVENT_TIMER_STOP);
156 smb_netbios_shutdown();
157 return (NULL);
160 static void
161 smb_netbios_shutdown(void)
163 (void) pthread_join(nbtd.nbs_browser.s_tid, 0);
164 (void) pthread_join(nbtd.nbs_dgm.s_tid, 0);
165 (void) pthread_join(nbtd.nbs_ns.s_tid, 0);
167 nbtd.nbs_browser.s_tid = 0;
168 nbtd.nbs_dgm.s_tid = 0;
169 nbtd.nbs_ns.s_tid = 0;
171 smb_netbios_cache_fini();
173 if (smb_netbios_error()) {
174 smb_netbios_event(NETBIOS_EVENT_RESET);
175 if (smb_netbios_start() != 0)
176 syslog(LOG_ERR, "netbios: restart failed");
181 smb_first_level_name_encode(struct name_entry *name,
182 unsigned char *out, int max_out)
184 return (netbios_first_level_name_encode(name->name, name->scope,
185 out, max_out));
189 smb_first_level_name_decode(unsigned char *in, struct name_entry *name)
191 return (netbios_first_level_name_decode((char *)in, (char *)name->name,
192 (char *)name->scope));
196 * smb_encode_netbios_name
198 * Set up the name and scope fields in the destination name_entry structure.
199 * The name is padded with spaces to 15 bytes. The suffix is copied into the
200 * last byte, i.e. "netbiosname <suffix>". The scope is copied and folded
201 * to uppercase.
203 void
204 smb_encode_netbios_name(unsigned char *name, char suffix, unsigned char *scope,
205 struct name_entry *dest)
207 smb_tonetbiosname((char *)name, (char *)dest->name, suffix);
209 if (scope) {
210 (void) strlcpy((char *)dest->scope, (const char *)scope,
211 sizeof (dest->scope));
212 } else {
213 (void) smb_config_getstr(SMB_CI_NBSCOPE, (char *)dest->scope,
214 sizeof (dest->scope));
217 (void) smb_strupr((char *)dest->scope);
220 void
221 smb_init_name_struct(unsigned char *name, char suffix, unsigned char *scope,
222 uint32_t ipaddr, unsigned short port, uint32_t attr,
223 uint32_t addr_attr, struct name_entry *dest)
225 bzero(dest, sizeof (struct name_entry));
226 smb_encode_netbios_name(name, suffix, scope, dest);
228 switch (smb_node_type) {
229 case 'H':
230 dest->attributes = attr | NAME_ATTR_OWNER_TYPE_HNODE;
231 break;
232 case 'M':
233 dest->attributes = attr | NAME_ATTR_OWNER_TYPE_MNODE;
234 break;
235 case 'P':
236 dest->attributes = attr | NAME_ATTR_OWNER_TYPE_PNODE;
237 break;
238 case 'B':
239 default:
240 dest->attributes = attr | NAME_ATTR_OWNER_TYPE_BNODE;
241 break;
244 dest->addr_list.refresh_ttl = dest->addr_list.ttl =
245 TO_SECONDS(DEFAULT_TTL);
247 dest->addr_list.sin.sin_family = AF_INET;
248 dest->addr_list.sinlen = sizeof (dest->addr_list.sin);
249 dest->addr_list.sin.sin_addr.s_addr = ipaddr;
250 dest->addr_list.sin.sin_port = port;
251 dest->addr_list.attributes = addr_attr;
252 dest->addr_list.forw = dest->addr_list.back = &dest->addr_list;
255 void
256 smb_netbios_event(netbios_event_t event)
258 static char *event_msg[] = {
259 "startup",
260 "shutdown",
261 "restart",
262 "name service started",
263 "name service stopped",
264 "datagram service started",
265 "datagram service stopped",
266 "browser service started",
267 "browser service stopped",
268 "timer service started",
269 "timer service stopped",
270 "error",
271 "dump"
274 (void) mutex_lock(&nbtd.nbs_mtx);
276 if (event == NETBIOS_EVENT_DUMP) {
277 if (nbtd.nbs_last_event == NULL)
278 nbtd.nbs_last_event = event_msg[event];
279 smb_netbios_dump();
280 (void) mutex_unlock(&nbtd.nbs_mtx);
281 return;
284 nbtd.nbs_last_event = event_msg[event];
285 syslog(LOG_DEBUG, "netbios: %s", nbtd.nbs_last_event);
287 switch (nbtd.nbs_state) {
288 case NETBIOS_STATE_INIT:
289 if (event == NETBIOS_EVENT_START)
290 nbtd.nbs_state = NETBIOS_STATE_RUNNING;
291 break;
293 case NETBIOS_STATE_RUNNING:
294 switch (event) {
295 case NETBIOS_EVENT_NS_START:
296 nbtd.nbs_ns.s_tid = pthread_self();
297 nbtd.nbs_ns.s_up = B_TRUE;
298 break;
299 case NETBIOS_EVENT_NS_STOP:
300 nbtd.nbs_ns.s_up = B_FALSE;
301 break;
302 case NETBIOS_EVENT_DGM_START:
303 nbtd.nbs_dgm.s_tid = pthread_self();
304 nbtd.nbs_dgm.s_up = B_TRUE;
305 break;
306 case NETBIOS_EVENT_DGM_STOP:
307 nbtd.nbs_dgm.s_up = B_FALSE;
308 break;
309 case NETBIOS_EVENT_BROWSER_START:
310 nbtd.nbs_browser.s_tid = pthread_self();
311 nbtd.nbs_browser.s_up = B_TRUE;
312 break;
313 case NETBIOS_EVENT_BROWSER_STOP:
314 nbtd.nbs_browser.s_up = B_FALSE;
315 break;
316 case NETBIOS_EVENT_TIMER_START:
317 nbtd.nbs_timer.s_tid = pthread_self();
318 nbtd.nbs_timer.s_up = B_TRUE;
319 break;
320 case NETBIOS_EVENT_TIMER_STOP:
321 nbtd.nbs_timer.s_up = B_FALSE;
322 break;
323 case NETBIOS_EVENT_STOP:
324 nbtd.nbs_state = NETBIOS_STATE_CLOSING;
325 break;
326 case NETBIOS_EVENT_ERROR:
327 nbtd.nbs_state = NETBIOS_STATE_ERROR;
328 ++nbtd.nbs_errors;
329 break;
330 default:
331 break;
333 break;
335 case NETBIOS_STATE_CLOSING:
336 case NETBIOS_STATE_ERROR:
337 default:
338 switch (event) {
339 case NETBIOS_EVENT_NS_STOP:
340 nbtd.nbs_ns.s_up = B_FALSE;
341 break;
342 case NETBIOS_EVENT_DGM_STOP:
343 nbtd.nbs_dgm.s_up = B_FALSE;
344 break;
345 case NETBIOS_EVENT_BROWSER_STOP:
346 nbtd.nbs_browser.s_up = B_FALSE;
347 break;
348 case NETBIOS_EVENT_TIMER_STOP:
349 nbtd.nbs_timer.s_up = B_FALSE;
350 break;
351 case NETBIOS_EVENT_STOP:
352 nbtd.nbs_state = NETBIOS_STATE_CLOSING;
353 break;
354 case NETBIOS_EVENT_RESET:
355 nbtd.nbs_state = NETBIOS_STATE_INIT;
356 break;
357 case NETBIOS_EVENT_ERROR:
358 ++nbtd.nbs_errors;
359 break;
360 default:
361 break;
363 break;
366 smb_netbios_dump();
367 (void) cond_broadcast(&nbtd.nbs_cv);
368 (void) mutex_unlock(&nbtd.nbs_mtx);
371 void
372 smb_netbios_wait(netbios_event_t event)
374 boolean_t *svc = NULL;
375 boolean_t desired_state;
377 (void) mutex_lock(&nbtd.nbs_mtx);
379 switch (event) {
380 case NETBIOS_EVENT_NS_START:
381 case NETBIOS_EVENT_NS_STOP:
382 svc = &nbtd.nbs_ns.s_up;
383 desired_state =
384 (event == NETBIOS_EVENT_NS_START) ? B_TRUE : B_FALSE;
385 break;
386 case NETBIOS_EVENT_DGM_START:
387 case NETBIOS_EVENT_DGM_STOP:
388 svc = &nbtd.nbs_dgm.s_up;
389 desired_state =
390 (event == NETBIOS_EVENT_DGM_START) ? B_TRUE : B_FALSE;
391 break;
392 case NETBIOS_EVENT_BROWSER_START:
393 case NETBIOS_EVENT_BROWSER_STOP:
394 svc = &nbtd.nbs_browser.s_up;
395 desired_state =
396 (event == NETBIOS_EVENT_BROWSER_START) ? B_TRUE : B_FALSE;
397 break;
398 default:
399 (void) mutex_unlock(&nbtd.nbs_mtx);
400 return;
403 while (*svc != desired_state) {
404 if (nbtd.nbs_state != NETBIOS_STATE_RUNNING)
405 break;
407 (void) cond_wait(&nbtd.nbs_cv, &nbtd.nbs_mtx);
410 (void) mutex_unlock(&nbtd.nbs_mtx);
413 void
414 smb_netbios_sleep(time_t seconds)
416 timestruc_t reltimeout;
418 (void) mutex_lock(&nbtd.nbs_mtx);
420 if (nbtd.nbs_state == NETBIOS_STATE_RUNNING) {
421 if (seconds == 0)
422 seconds = 1;
423 reltimeout.tv_sec = seconds;
424 reltimeout.tv_nsec = 0;
426 (void) cond_reltimedwait(&nbtd.nbs_cv,
427 &nbtd.nbs_mtx, &reltimeout);
430 (void) mutex_unlock(&nbtd.nbs_mtx);
433 boolean_t
434 smb_netbios_running(void)
436 boolean_t is_running;
438 (void) mutex_lock(&nbtd.nbs_mtx);
440 if (nbtd.nbs_state == NETBIOS_STATE_RUNNING)
441 is_running = B_TRUE;
442 else
443 is_running = B_FALSE;
445 (void) mutex_unlock(&nbtd.nbs_mtx);
446 return (is_running);
449 boolean_t
450 smb_netbios_error(void)
452 boolean_t error;
454 (void) mutex_lock(&nbtd.nbs_mtx);
456 if (nbtd.nbs_state == NETBIOS_STATE_ERROR)
457 error = B_TRUE;
458 else
459 error = B_FALSE;
461 (void) mutex_unlock(&nbtd.nbs_mtx);
462 return (error);
466 * Write the service state to /var/run/smb/netbios.
468 * This is a private interface. To update the file use:
469 * smb_netbios_event(NETBIOS_EVENT_DUMP);
471 static void
472 smb_netbios_dump(void)
474 static struct {
475 netbios_state_t state;
476 char *text;
477 } sm[] = {
478 { NETBIOS_STATE_INIT, "init" },
479 { NETBIOS_STATE_RUNNING, "running" },
480 { NETBIOS_STATE_CLOSING, "closing" },
481 { NETBIOS_STATE_ERROR, "error" }
484 char fname[MAXPATHLEN];
485 FILE *fp;
486 struct passwd *pwd;
487 struct group *grp;
488 uid_t uid;
489 gid_t gid;
490 char *last_event = "none";
491 int i;
493 (void) snprintf(fname, MAXPATHLEN, "%s/%s",
494 SMB_VARRUN_DIR, SMB_NETBIOS_DUMP_FILE);
496 if ((fp = fopen(fname, "w")) == NULL)
497 return;
499 pwd = getpwnam("root");
500 grp = getgrnam("sys");
501 uid = (pwd == NULL) ? 0 : pwd->pw_uid;
502 gid = (grp == NULL) ? 3 : grp->gr_gid;
504 (void) lockf(fileno(fp), F_LOCK, 0);
505 (void) fchmod(fileno(fp), 0600);
506 (void) fchown(fileno(fp), uid, gid);
508 if (nbtd.nbs_last_event)
509 last_event = nbtd.nbs_last_event;
511 for (i = 0; i < sizeof (sm) / sizeof (sm[0]); ++i) {
512 if (nbtd.nbs_state == sm[i].state) {
513 (void) fprintf(fp,
514 "State %s (event: %s, errors: %u)\n",
515 sm[i].text, last_event, nbtd.nbs_errors);
516 break;
520 (void) fprintf(fp, "Name Service %-7s (%u)\n",
521 nbtd.nbs_ns.s_up ? "up" : "down", nbtd.nbs_ns.s_tid);
522 (void) fprintf(fp, "Datagram Service %-7s (%u)\n",
523 nbtd.nbs_dgm.s_up ? "up" : "down", nbtd.nbs_dgm.s_tid);
524 (void) fprintf(fp, "Browser Service %-7s (%u)\n",
525 nbtd.nbs_browser.s_up ? "up" : "down", nbtd.nbs_browser.s_tid);
526 (void) fprintf(fp, "Timer Service %-7s (%u)\n",
527 nbtd.nbs_timer.s_up ? "up" : "down", nbtd.nbs_timer.s_tid);
529 smb_netbios_cache_dump(fp);
531 (void) lockf(fileno(fp), F_ULOCK, 0);
532 (void) fclose(fp);