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]
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>
38 #include <sys/socket.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
56 smb_netbios_start(void)
62 if (smb_netbios_cache_init() < 0)
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
);
73 * Stop the NetBIOS services
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
);
89 * Launch the NetBIOS Name Service, Datagram and Browser services
90 * and then sit in a loop providing a 1 second resolution timer.
92 * - update the netbios stats file every 10 minutes
93 * - clean the cache every 10 minutes
97 smb_netbios_service(void *arg
)
99 static uint32_t ticks
= 0;
103 smb_netbios_event(NETBIOS_EVENT_START
);
105 rc
= pthread_create(&tid
, NULL
, smb_netbios_name_service
, NULL
);
107 smb_netbios_shutdown();
111 smb_netbios_wait(NETBIOS_EVENT_NS_START
);
112 if (smb_netbios_error()) {
113 smb_netbios_shutdown();
117 smb_netbios_name_config();
119 rc
= pthread_create(&tid
, NULL
, smb_netbios_datagram_service
, NULL
);
121 smb_netbios_shutdown();
125 smb_netbios_wait(NETBIOS_EVENT_DGM_START
);
126 if (smb_netbios_error()) {
127 smb_netbios_shutdown();
131 rc
= pthread_create(&tid
, NULL
, smb_browser_service
, NULL
);
133 smb_netbios_shutdown();
137 smb_netbios_event(NETBIOS_EVENT_TIMER_START
);
143 if (!smb_netbios_running())
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();
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
,
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
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
);
210 (void) strlcpy((char *)dest
->scope
, (const char *)scope
,
211 sizeof (dest
->scope
));
213 (void) smb_config_getstr(SMB_CI_NBSCOPE
, (char *)dest
->scope
,
214 sizeof (dest
->scope
));
217 (void) smb_strupr((char *)dest
->scope
);
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
) {
230 dest
->attributes
= attr
| NAME_ATTR_OWNER_TYPE_HNODE
;
233 dest
->attributes
= attr
| NAME_ATTR_OWNER_TYPE_MNODE
;
236 dest
->attributes
= attr
| NAME_ATTR_OWNER_TYPE_PNODE
;
240 dest
->attributes
= attr
| NAME_ATTR_OWNER_TYPE_BNODE
;
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
;
256 smb_netbios_event(netbios_event_t event
)
258 static char *event_msg
[] = {
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",
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
];
280 (void) mutex_unlock(&nbtd
.nbs_mtx
);
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
;
293 case NETBIOS_STATE_RUNNING
:
295 case NETBIOS_EVENT_NS_START
:
296 nbtd
.nbs_ns
.s_tid
= pthread_self();
297 nbtd
.nbs_ns
.s_up
= B_TRUE
;
299 case NETBIOS_EVENT_NS_STOP
:
300 nbtd
.nbs_ns
.s_up
= B_FALSE
;
302 case NETBIOS_EVENT_DGM_START
:
303 nbtd
.nbs_dgm
.s_tid
= pthread_self();
304 nbtd
.nbs_dgm
.s_up
= B_TRUE
;
306 case NETBIOS_EVENT_DGM_STOP
:
307 nbtd
.nbs_dgm
.s_up
= B_FALSE
;
309 case NETBIOS_EVENT_BROWSER_START
:
310 nbtd
.nbs_browser
.s_tid
= pthread_self();
311 nbtd
.nbs_browser
.s_up
= B_TRUE
;
313 case NETBIOS_EVENT_BROWSER_STOP
:
314 nbtd
.nbs_browser
.s_up
= B_FALSE
;
316 case NETBIOS_EVENT_TIMER_START
:
317 nbtd
.nbs_timer
.s_tid
= pthread_self();
318 nbtd
.nbs_timer
.s_up
= B_TRUE
;
320 case NETBIOS_EVENT_TIMER_STOP
:
321 nbtd
.nbs_timer
.s_up
= B_FALSE
;
323 case NETBIOS_EVENT_STOP
:
324 nbtd
.nbs_state
= NETBIOS_STATE_CLOSING
;
326 case NETBIOS_EVENT_ERROR
:
327 nbtd
.nbs_state
= NETBIOS_STATE_ERROR
;
335 case NETBIOS_STATE_CLOSING
:
336 case NETBIOS_STATE_ERROR
:
339 case NETBIOS_EVENT_NS_STOP
:
340 nbtd
.nbs_ns
.s_up
= B_FALSE
;
342 case NETBIOS_EVENT_DGM_STOP
:
343 nbtd
.nbs_dgm
.s_up
= B_FALSE
;
345 case NETBIOS_EVENT_BROWSER_STOP
:
346 nbtd
.nbs_browser
.s_up
= B_FALSE
;
348 case NETBIOS_EVENT_TIMER_STOP
:
349 nbtd
.nbs_timer
.s_up
= B_FALSE
;
351 case NETBIOS_EVENT_STOP
:
352 nbtd
.nbs_state
= NETBIOS_STATE_CLOSING
;
354 case NETBIOS_EVENT_RESET
:
355 nbtd
.nbs_state
= NETBIOS_STATE_INIT
;
357 case NETBIOS_EVENT_ERROR
:
367 (void) cond_broadcast(&nbtd
.nbs_cv
);
368 (void) mutex_unlock(&nbtd
.nbs_mtx
);
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
);
380 case NETBIOS_EVENT_NS_START
:
381 case NETBIOS_EVENT_NS_STOP
:
382 svc
= &nbtd
.nbs_ns
.s_up
;
384 (event
== NETBIOS_EVENT_NS_START
) ? B_TRUE
: B_FALSE
;
386 case NETBIOS_EVENT_DGM_START
:
387 case NETBIOS_EVENT_DGM_STOP
:
388 svc
= &nbtd
.nbs_dgm
.s_up
;
390 (event
== NETBIOS_EVENT_DGM_START
) ? B_TRUE
: B_FALSE
;
392 case NETBIOS_EVENT_BROWSER_START
:
393 case NETBIOS_EVENT_BROWSER_STOP
:
394 svc
= &nbtd
.nbs_browser
.s_up
;
396 (event
== NETBIOS_EVENT_BROWSER_START
) ? B_TRUE
: B_FALSE
;
399 (void) mutex_unlock(&nbtd
.nbs_mtx
);
403 while (*svc
!= desired_state
) {
404 if (nbtd
.nbs_state
!= NETBIOS_STATE_RUNNING
)
407 (void) cond_wait(&nbtd
.nbs_cv
, &nbtd
.nbs_mtx
);
410 (void) mutex_unlock(&nbtd
.nbs_mtx
);
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
) {
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
);
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
)
443 is_running
= B_FALSE
;
445 (void) mutex_unlock(&nbtd
.nbs_mtx
);
450 smb_netbios_error(void)
454 (void) mutex_lock(&nbtd
.nbs_mtx
);
456 if (nbtd
.nbs_state
== NETBIOS_STATE_ERROR
)
461 (void) mutex_unlock(&nbtd
.nbs_mtx
);
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);
472 smb_netbios_dump(void)
475 netbios_state_t state
;
478 { NETBIOS_STATE_INIT
, "init" },
479 { NETBIOS_STATE_RUNNING
, "running" },
480 { NETBIOS_STATE_CLOSING
, "closing" },
481 { NETBIOS_STATE_ERROR
, "error" }
484 char fname
[MAXPATHLEN
];
490 char *last_event
= "none";
493 (void) snprintf(fname
, MAXPATHLEN
, "%s/%s",
494 SMB_VARRUN_DIR
, SMB_NETBIOS_DUMP_FILE
);
496 if ((fp
= fopen(fname
, "w")) == NULL
)
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
) {
514 "State %s (event: %s, errors: %u)\n",
515 sm
[i
].text
, last_event
, nbtd
.nbs_errors
);
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);