xref: /illumos-gate/usr/src/uts/common/fs/smbsrv/smb_server.c (revision 74e7dc986c89efca1f2e4451c7a572e05e4a6e4f)
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	"@(#)smb_server.c	1.10	08/08/07 SMI"
27 
28 /*
29  * General Structures Layout
30  * -------------------------
31  *
32  * This is a simplified diagram showing the relationship between most of the
33  * main structures.
34  *
35  * +-------------------+
36  * |     SMB_SERVER    |
37  * +-------------------+
38  *          |
39  *          |
40  *          v
41  * +-------------------+       +-------------------+      +-------------------+
42  * |     SESSION       |<----->|     SESSION       |......|      SESSION      |
43  * +-------------------+       +-------------------+      +-------------------+
44  *          |
45  *          |
46  *          v
47  * +-------------------+       +-------------------+      +-------------------+
48  * |       USER        |<----->|       USER        |......|       USER        |
49  * +-------------------+       +-------------------+      +-------------------+
50  *          |
51  *          |
52  *          v
53  * +-------------------+       +-------------------+      +-------------------+
54  * |       TREE        |<----->|       TREE        |......|       TREE        |
55  * +-------------------+       +-------------------+      +-------------------+
56  *      |         |
57  *      |         |
58  *      |         v
59  *      |     +-------+       +-------+      +-------+
60  *      |     | OFILE |<----->| OFILE |......| OFILE |
61  *      |     +-------+       +-------+      +-------+
62  *      |
63  *      |
64  *      v
65  *  +-------+       +------+      +------+
66  *  | ODIR  |<----->| ODIR |......| ODIR |
67  *  +-------+       +------+      +------+
68  *
69  *
70  * Module Interface Overview
71  * -------------------------
72  *
73  *
74  *	    +===================================+
75  *	    |		 smbd daemon		|
76  *	    +===================================+
77  *	      |		     |		      ^
78  *	      |		     |		      |
79  * User	      |		     |		      |
80  * -----------|--------------|----------------|--------------------------------
81  * Kernel     |		     |		      |
82  *            |		     |		      |
83  *	      |		     |		      |
84  *  +=========|==============|================|=================+
85  *  |	      v		     v		      |			|
86  *  | +-----------+ +--------------------+ +------------------+ |
87  *  | |     IO    | | Kernel Door Server | | User Door Servers|	|
88  *  | | Interface | |     Interface      | |   Interface      | |
89  *  | +-----------+ +--------------------+ +------------------+ |
90  *  |		|	     |		      ^		^	|
91  *  |		v	     v		      |		|	|    +=========+
92  *  |	     +-----------------------------------+	|	|    |	       |
93  *  |	     + SMB Server Management (this file) |<------------------|	 ZFS   |
94  *  |	     +-----------------------------------+	|	|    |	       |
95  *  |							|	|    |  Module |
96  *  |	     +-----------------------------------+	|	|    |	       |
97  *  |	     +     SMB Server Internal Layers    |------+	|    +=========+
98  *  |	     +-----------------------------------+		|
99  *  |								|
100  *  |								|
101  *  +===========================================================+
102  *
103  *
104  * Server State Machine
105  * --------------------
106  *                                  |
107  *                                  | T0
108  *                                  |
109  *                                  v
110  *                    +-----------------------------+
111  *		      |   SMB_SERVER_STATE_CREATED  |
112  *		      +-----------------------------+
113  *				    |
114  *				    | T1
115  *				    |
116  *				    v
117  *		      +-----------------------------+
118  *		      | SMB_SERVER_STATE_CONFIGURED |
119  *		      +-----------------------------+
120  *				    |
121  *				    | T2
122  *				    |
123  *				    v
124  *		      +-----------------------------+
125  *		      |  SMB_SERVER_STATE_RUNNING   |
126  *		      +-----------------------------+
127  *				    |
128  *				    | T3
129  *				    |
130  *				    v
131  *		      +-----------------------------+
132  *		      |  SMB_SERVER_STATE_DELETING  |
133  *                    +-----------------------------+
134  *				    |
135  *				    |
136  *				    |
137  *				    v
138  *
139  * States
140  * ------
141  *
142  * SMB_SERVER_STATE_CREATED
143  *
144  *    This is the state of the server just after creation.
145  *
146  * SMB_SERVER_STATE_CONFIGURED
147  *
148  *    The server has been configured.
149  *
150  * SMB_SERVER_STATE_RUNNING
151  *
152  *    The server has been started. While in this state the threads listening on
153  *    the sockets car be started. The smbd daemon does so through an Ioctl:
154  *
155  *	smb_drv_ioctl(SMB_IOC_NBT_LISTEN) --> smb_server_nbt_listen()
156  *	smb_drv_ioctl(SMB_IOC_TCP_LISTEN) --> smb_server_nbt_listen()
157  *
158  *    When a client establishes a connection the thread listening leaves
159  *    temporarily the kernel. While in user space it creates a thread for the
160  *    new session. It then returns to kernel with the result of the thread
161  *    creation. If the creation failed the new session context is destroyed
162  *    before returning listening.
163  *
164  *    The new created thread enters the kernel though an Ioctl:
165  *
166  *	smb_drv_ioctl(SMB_IOC_NBT_RECEIVE) --> smb_server_nbt_receive()
167  *	smb_drv_ioctl(SMB_IOC_TCP_RECEIVE) --> smb_server_tcp_receive()
168  *
169  * SMB_SERVER_STATE_STOPPING
170  *
171  *    The threads listening on the NBT and TCP sockets are being terminated.
172  *
173  *
174  * Transitions
175  * -----------
176  *
177  * Transition T0
178  *
179  *    The daemon smbd triggers its creation by opening the smbsrv device. If
180  *    the zone where the daemon lives doesn't have an smb server yet it is
181  *    created.
182  *
183  *		smb_drv_open() --> smb_server_create()
184  *
185  * Transition T1
186  *
187  *    This transition occurs in smb_server_configure(). It is triggered by the
188  *    daemon through an Ioctl.
189  *
190  *	smb_drv_ioctl(SMB_IOC_CONFIG) --> smb_server_configure()
191  *
192  * Transition T2
193  *
194  *    This transition occurs in smb_server_start(). It is triggered by the
195  *    daemon through an Ioctl.
196  *
197  *	smb_drv_ioctl(SMB_IOC_START) --> smb_server_start()
198  *
199  * Transition T3
200  *
201  *    This transition occurs in smb_server_delete(). It is triggered by the
202  *    daemon when closing the smbsrv device
203  *
204  *		smb_drv_close() --> smb_server_delete()
205  *
206  * Comments
207  * --------
208  *
209  * This files assumes that there will one SMB server per zone. For now the
210  * smb server works only in global zone. There's nothing in this file preventing
211  * an smb server from being created in a non global zone. That limitation is
212  * enforced in user space.
213  */
214 
215 #include <sys/strsubr.h>
216 #include <sys/cmn_err.h>
217 #include <sys/priv.h>
218 #include <sys/socketvar.h>
219 #include <sys/zone.h>
220 #include <smbsrv/smb_kproto.h>
221 #include <smbsrv/netbios.h>
222 #include <smbsrv/smb_incl.h>
223 #include <smbsrv/cifs.h>
224 #include <smbsrv/smb_fsops.h>
225 #include <smbsrv/smb_share.h>
226 #include <smbsrv/smb_door_svc.h>
227 #include <smbsrv/smb_kstat.h>
228 
229 extern void smb_dispatch_kstat_init(void);
230 extern void smb_dispatch_kstat_fini(void);
231 extern void smb_reply_notify_change_request(smb_request_t *);
232 
233 static int smb_server_kstat_init(smb_server_t *);
234 static void smb_server_kstat_fini(smb_server_t *);
235 static int smb_server_kstat_update_info(kstat_t *, int);
236 static void smb_server_timers(smb_thread_t *, void *);
237 static int smb_server_listen(smb_server_t *, smb_listener_daemon_t *,
238     in_port_t, int);
239 static int smb_server_lookup(smb_server_t **);
240 static void smb_server_release(smb_server_t *);
241 static int smb_server_ulist_geti(smb_session_list_t *, int,
242     smb_opipe_context_t *, int);
243 static void smb_server_store_cfg(smb_server_t *, smb_kmod_cfg_t *);
244 static void smb_server_stop(smb_server_t *);
245 static int smb_server_fsop_start(smb_server_t *);
246 static void smb_server_fsop_stop(smb_server_t *);
247 
248 static smb_llist_t	smb_servers;
249 
250 /*
251  * *****************************************************************************
252  * **************** Functions called from the device interface *****************
253  * *****************************************************************************
254  *
255  * These functions determine the relevant smb server to which the call apply.
256  */
257 
258 /*
259  * smb_server_svc_init
260  *
261  * This function must be called from smb_drv_attach().
262  */
263 int
264 smb_server_svc_init(void)
265 {
266 	int	rc = 0;
267 
268 	while (rc == 0) {
269 		if (rc = smb_vop_init())
270 			continue;
271 		if (rc = smb_node_init())
272 			continue;
273 		if (rc = smb_fem_init())
274 			continue;
275 		if (rc = smb_user_init())
276 			continue;
277 		if (rc = smb_notify_init())
278 			continue;
279 		if (rc = smb_net_init())
280 			continue;
281 		if (rc = smb_kdoor_srv_start())
282 			continue;
283 		smb_llist_constructor(&smb_servers, sizeof (smb_server_t),
284 		    offsetof(smb_server_t, sv_lnd));
285 		return (0);
286 	}
287 	smb_net_fini();
288 	smb_notify_fini();
289 	smb_user_fini();
290 	smb_fem_fini();
291 	smb_node_fini();
292 	smb_vop_fini();
293 	return (rc);
294 }
295 
296 /*
297  * smb_server_svc_fini
298  *
299  * This function must called from smb_drv_detach(). It will fail if servers
300  * still exist.
301  */
302 int
303 smb_server_svc_fini(void)
304 {
305 	int	rc = EBUSY;
306 
307 	if (smb_llist_get_count(&smb_servers) == 0) {
308 		smb_kdoor_srv_stop();
309 		smb_net_fini();
310 		smb_notify_fini();
311 		smb_user_fini();
312 		smb_fem_fini();
313 		smb_node_fini();
314 		smb_vop_fini();
315 		smb_llist_destructor(&smb_servers);
316 		rc = 0;
317 	}
318 	return (rc);
319 }
320 
321 /*
322  * smb_server_create
323  *
324  * This function will fail if there's already a server associated with the
325  * caller's zone.
326  */
327 int
328 smb_server_create(void)
329 {
330 	zoneid_t	zid;
331 	smb_server_t	*sv;
332 
333 	zid = getzoneid();
334 
335 	smb_llist_enter(&smb_servers, RW_WRITER);
336 	sv = smb_llist_head(&smb_servers);
337 	while (sv) {
338 		ASSERT(sv->sv_magic == SMB_SERVER_MAGIC);
339 		if (sv->sv_zid == zid) {
340 			smb_llist_exit(&smb_servers);
341 			return (EEXIST);
342 		}
343 		sv = smb_llist_next(&smb_servers, sv);
344 	}
345 
346 	sv = kmem_zalloc(sizeof (smb_server_t), KM_NOSLEEP);
347 	if (sv == NULL) {
348 		smb_llist_exit(&smb_servers);
349 		return (ENOMEM);
350 	}
351 
352 	smb_llist_constructor(&sv->sv_vfs_list, sizeof (smb_vfs_t),
353 	    offsetof(smb_vfs_t, sv_lnd));
354 
355 	smb_session_list_constructor(&sv->sv_nbt_daemon.ld_session_list);
356 	smb_session_list_constructor(&sv->sv_tcp_daemon.ld_session_list);
357 
358 	sv->si_cache_vfs = kmem_cache_create("smb_vfs_cache",
359 	    sizeof (smb_vfs_t), 8, NULL, NULL, NULL, NULL, NULL, 0);
360 	sv->si_cache_request = kmem_cache_create("smb_request_cache",
361 	    sizeof (smb_request_t), 8, NULL, NULL, NULL, NULL, NULL, 0);
362 	sv->si_cache_session = kmem_cache_create("smb_session_cache",
363 	    sizeof (smb_session_t), 8, NULL, NULL, NULL, NULL, NULL, 0);
364 	sv->si_cache_user = kmem_cache_create("smb_user_cache",
365 	    sizeof (smb_user_t), 8, NULL, NULL, NULL, NULL, NULL, 0);
366 	sv->si_cache_tree = kmem_cache_create("smb_tree_cache",
367 	    sizeof (smb_tree_t), 8, NULL, NULL, NULL, NULL, NULL, 0);
368 	sv->si_cache_ofile = kmem_cache_create("smb_ofile_cache",
369 	    sizeof (smb_ofile_t), 8, NULL, NULL, NULL, NULL, NULL, 0);
370 	sv->si_cache_odir = kmem_cache_create("smb_odir_cache",
371 	    sizeof (smb_odir_t), 8, NULL, NULL, NULL, NULL, NULL, 0);
372 	sv->si_cache_node = kmem_cache_create("smb_node_cache",
373 	    sizeof (smb_node_t), 8, NULL, NULL, NULL, NULL, NULL, 0);
374 
375 	smb_thread_init(&sv->si_thread_timers,
376 	    "smb_timers", smb_server_timers, sv,
377 	    NULL, NULL);
378 
379 	sv->sv_pid = curproc->p_pid;
380 
381 	smb_opipe_door_init();
382 	(void) smb_server_kstat_init(sv);
383 
384 	mutex_init(&sv->sv_mutex, NULL, MUTEX_DEFAULT, NULL);
385 	cv_init(&sv->sv_cv, NULL, CV_DEFAULT, NULL);
386 	sv->sv_state = SMB_SERVER_STATE_CREATED;
387 	sv->sv_magic = SMB_SERVER_MAGIC;
388 	sv->sv_zid = zid;
389 
390 	smb_llist_insert_tail(&smb_servers, sv);
391 	smb_llist_exit(&smb_servers);
392 	return (0);
393 }
394 
395 /*
396  * smb_server_delete
397  *
398  * This function will delete the server passed in. It will make sure that all
399  * activity associated that server has ceased before destroying it.
400  */
401 int
402 smb_server_delete(void)
403 {
404 	smb_server_t	*sv;
405 	int		rc;
406 
407 	rc = smb_server_lookup(&sv);
408 	if (rc != 0)
409 		return (rc);
410 
411 	mutex_enter(&sv->sv_mutex);
412 	switch (sv->sv_state) {
413 	case SMB_SERVER_STATE_RUNNING:
414 	{
415 		boolean_t	nbt = B_FALSE;
416 		boolean_t	tcp = B_FALSE;
417 
418 		if (sv->sv_nbt_daemon.ld_kth) {
419 			tsignal(sv->sv_nbt_daemon.ld_kth, SIGINT);
420 			nbt = B_TRUE;
421 		}
422 		if (sv->sv_tcp_daemon.ld_kth) {
423 			tsignal(sv->sv_tcp_daemon.ld_kth, SIGINT);
424 			tcp = B_TRUE;
425 		}
426 		sv->sv_state = SMB_SERVER_STATE_DELETING;
427 		mutex_exit(&sv->sv_mutex);
428 		if (nbt)
429 			thread_join(sv->sv_nbt_daemon.ld_ktdid);
430 		if (tcp)
431 			thread_join(sv->sv_tcp_daemon.ld_ktdid);
432 		mutex_enter(&sv->sv_mutex);
433 		break;
434 	}
435 	case SMB_SERVER_STATE_CONFIGURED:
436 	case SMB_SERVER_STATE_CREATED:
437 		sv->sv_state = SMB_SERVER_STATE_DELETING;
438 		break;
439 	default:
440 		ASSERT(sv->sv_state == SMB_SERVER_STATE_DELETING);
441 		mutex_exit(&sv->sv_mutex);
442 		smb_server_release(sv);
443 		return (ENOTTY);
444 	}
445 
446 	ASSERT(sv->sv_state == SMB_SERVER_STATE_DELETING);
447 
448 	sv->sv_refcnt--;
449 	while (sv->sv_refcnt)
450 		cv_wait(&sv->sv_cv, &sv->sv_mutex);
451 
452 	mutex_exit(&sv->sv_mutex);
453 
454 	smb_llist_enter(&smb_servers, RW_WRITER);
455 	smb_llist_remove(&smb_servers, sv);
456 	smb_llist_exit(&smb_servers);
457 
458 	smb_server_stop(sv);
459 	rw_destroy(&sv->sv_cfg_lock);
460 	smb_opipe_door_fini();
461 	smb_server_kstat_fini(sv);
462 	smb_llist_destructor(&sv->sv_vfs_list);
463 	kmem_cache_destroy(sv->si_cache_vfs);
464 	kmem_cache_destroy(sv->si_cache_request);
465 	kmem_cache_destroy(sv->si_cache_session);
466 	kmem_cache_destroy(sv->si_cache_user);
467 	kmem_cache_destroy(sv->si_cache_tree);
468 	kmem_cache_destroy(sv->si_cache_ofile);
469 	kmem_cache_destroy(sv->si_cache_odir);
470 	kmem_cache_destroy(sv->si_cache_node);
471 
472 	taskq_destroy(sv->sv_thread_pool);
473 	smb_thread_destroy(&sv->si_thread_timers);
474 	mutex_destroy(&sv->sv_mutex);
475 	cv_destroy(&sv->sv_cv);
476 	sv->sv_magic = 0;
477 	kmem_free(sv, sizeof (smb_server_t));
478 
479 	return (0);
480 }
481 
482 /*
483  * smb_server_configure
484  */
485 int
486 smb_server_configure(smb_kmod_cfg_t *cfg)
487 {
488 	int		rc = 0;
489 	smb_server_t	*sv;
490 
491 	rc = smb_server_lookup(&sv);
492 	if (rc)
493 		return (rc);
494 
495 	mutex_enter(&sv->sv_mutex);
496 	switch (sv->sv_state) {
497 	case SMB_SERVER_STATE_CREATED:
498 		smb_server_store_cfg(sv, cfg);
499 		sv->sv_state = SMB_SERVER_STATE_CONFIGURED;
500 		break;
501 
502 	case SMB_SERVER_STATE_CONFIGURED:
503 		smb_server_store_cfg(sv, cfg);
504 		break;
505 
506 	case SMB_SERVER_STATE_RUNNING:
507 		rw_enter(&sv->sv_cfg_lock, RW_WRITER);
508 		smb_server_store_cfg(sv, cfg);
509 		rw_exit(&sv->sv_cfg_lock);
510 		break;
511 
512 	default:
513 		ASSERT(sv->sv_state == SMB_SERVER_STATE_DELETING);
514 		rc = EFAULT;
515 		break;
516 	}
517 	mutex_exit(&sv->sv_mutex);
518 
519 	smb_server_release(sv);
520 
521 	return (rc);
522 }
523 
524 /*
525  * smb_server_start
526  */
527 int
528 smb_server_start(struct smb_io_start *io_start)
529 {
530 	int		rc = 0;
531 	smb_server_t	*sv;
532 
533 	rc = smb_server_lookup(&sv);
534 	if (rc)
535 		return (rc);
536 
537 	mutex_enter(&sv->sv_mutex);
538 	switch (sv->sv_state) {
539 	case SMB_SERVER_STATE_CONFIGURED:
540 
541 		sv->sv_thread_pool = taskq_create("smb_workers",
542 		    sv->sv_cfg.skc_maxworkers, SMB_WORKER_PRIORITY,
543 		    sv->sv_cfg.skc_maxworkers, INT_MAX,
544 		    TASKQ_DYNAMIC|TASKQ_PREPOPULATE);
545 
546 		sv->sv_session = smb_session_create(NULL, 0, sv);
547 		if (sv->sv_session == NULL) {
548 			rc = ENOMEM;
549 			break;
550 		}
551 
552 		if (rc = smb_server_fsop_start(sv))
553 			break;
554 		ASSERT(sv->sv_lmshrd == NULL);
555 		sv->sv_lmshrd = smb_kshare_init(io_start->lmshrd);
556 		if (sv->sv_lmshrd == NULL)
557 			break;
558 		if (rc = smb_kdoor_clnt_start(io_start->udoor))
559 			break;
560 		if (rc = smb_kdoor_srv_set_dwncall())
561 			break;
562 		if (rc = smb_thread_start(&sv->si_thread_timers))
563 			break;
564 		/*
565 		 * XXX We give up the NET_MAC_AWARE privilege because it keeps
566 		 * us from re-opening the connection when there are leftover TCP
567 		 * connections in TCPS_TIME_WAIT state.  There seem to be some
568 		 * security ramifications around reestablishing a connection
569 		 * while possessing the NET_MAC_AWARE privilege.
570 		 *
571 		 * This approach may cause problems when we try to support
572 		 * zones.  An alternative would be to retry the connection setup
573 		 * for a fixed period of time until the stale connections clear
574 		 * up but that implies we would be offline for a couple minutes
575 		 * every time the service is restarted with active connections.
576 		 */
577 		rc = setpflags(NET_MAC_AWARE, 0, CRED());
578 		if (rc) {
579 			cmn_err(CE_WARN,
580 			    "Cannot remove NET_MAC_AWARE privilege");
581 			break;
582 		}
583 		if (rc = smb_opipe_door_open(io_start->opipe)) {
584 			cmn_err(CE_WARN, "Cannot open opipe door");
585 			break;
586 		}
587 		sv->sv_state = SMB_SERVER_STATE_RUNNING;
588 		mutex_exit(&sv->sv_mutex);
589 		smb_server_release(sv);
590 		return (0);
591 	default:
592 		ASSERT((sv->sv_state == SMB_SERVER_STATE_CREATED) ||
593 		    (sv->sv_state == SMB_SERVER_STATE_RUNNING) ||
594 		    (sv->sv_state == SMB_SERVER_STATE_DELETING));
595 		mutex_exit(&sv->sv_mutex);
596 		smb_server_release(sv);
597 		return (ENOTTY);
598 	}
599 
600 	smb_server_stop(sv);
601 	mutex_exit(&sv->sv_mutex);
602 	smb_server_release(sv);
603 	return (rc);
604 }
605 
606 /*
607  * smb_server_nbt_listen: SMB-over-NetBIOS service
608  *
609  * Traditional SMB service over NetBIOS (port 139), which requires
610  * that a NetBIOS session be established.
611  */
612 int
613 smb_server_nbt_listen(int error)
614 {
615 	smb_server_t	*sv;
616 	int		rc;
617 
618 	rc = smb_server_lookup(&sv);
619 	if (rc)
620 		return (rc);
621 
622 	mutex_enter(&sv->sv_mutex);
623 	switch (sv->sv_state) {
624 	case SMB_SERVER_STATE_RUNNING:
625 		if ((sv->sv_nbt_daemon.ld_kth != NULL) &&
626 		    (sv->sv_nbt_daemon.ld_kth != curthread)) {
627 			mutex_exit(&sv->sv_mutex);
628 			return (EACCES);
629 		} else {
630 			sv->sv_nbt_daemon.ld_kth = curthread;
631 			sv->sv_nbt_daemon.ld_ktdid = curthread->t_did;
632 		}
633 		break;
634 	default:
635 		ASSERT((sv->sv_state == SMB_SERVER_STATE_CREATED) ||
636 		    (sv->sv_state == SMB_SERVER_STATE_CONFIGURED) ||
637 		    (sv->sv_state == SMB_SERVER_STATE_DELETING));
638 		mutex_exit(&sv->sv_mutex);
639 		smb_server_release(sv);
640 		return (EFAULT);
641 	}
642 	mutex_exit(&sv->sv_mutex);
643 
644 	rc = smb_server_listen(sv, &sv->sv_nbt_daemon, SSN_SRVC_TCP_PORT,
645 	    error);
646 
647 	if (rc) {
648 		mutex_enter(&sv->sv_mutex);
649 		sv->sv_nbt_daemon.ld_kth = NULL;
650 		mutex_exit(&sv->sv_mutex);
651 	}
652 
653 	smb_server_release(sv);
654 
655 	return (rc);
656 }
657 
658 int
659 smb_server_tcp_listen(int error)
660 {
661 	smb_server_t	*sv;
662 	int		rc;
663 
664 	rc = smb_server_lookup(&sv);
665 	if (rc)
666 		return (rc);
667 
668 	mutex_enter(&sv->sv_mutex);
669 	switch (sv->sv_state) {
670 	case SMB_SERVER_STATE_RUNNING:
671 		if ((sv->sv_tcp_daemon.ld_kth) &&
672 		    (sv->sv_tcp_daemon.ld_kth != curthread)) {
673 			mutex_exit(&sv->sv_mutex);
674 			return (EACCES);
675 		} else {
676 			sv->sv_tcp_daemon.ld_kth = curthread;
677 			sv->sv_tcp_daemon.ld_ktdid = curthread->t_did;
678 		}
679 		break;
680 	default:
681 		ASSERT((sv->sv_state == SMB_SERVER_STATE_CREATED) ||
682 		    (sv->sv_state == SMB_SERVER_STATE_CONFIGURED) ||
683 		    (sv->sv_state == SMB_SERVER_STATE_DELETING));
684 		mutex_exit(&sv->sv_mutex);
685 		return (EFAULT);
686 	}
687 	mutex_exit(&sv->sv_mutex);
688 
689 	rc = smb_server_listen(sv, &sv->sv_tcp_daemon, SMB_SRVC_TCP_PORT,
690 	    error);
691 
692 	if (rc) {
693 		mutex_enter(&sv->sv_mutex);
694 		sv->sv_tcp_daemon.ld_kth = NULL;
695 		mutex_exit(&sv->sv_mutex);
696 	}
697 
698 	smb_server_release(sv);
699 
700 	return (rc);
701 }
702 
703 /*
704  * smb_server_nbt_receive
705  */
706 int
707 smb_server_nbt_receive(void)
708 {
709 	int		rc;
710 	smb_server_t	*sv;
711 
712 	rc = smb_server_lookup(&sv);
713 	if (rc)
714 		return (rc);
715 
716 	rc = smb_session_daemon(&sv->sv_nbt_daemon.ld_session_list);
717 
718 	smb_server_release(sv);
719 
720 	return (rc);
721 }
722 
723 /*
724  * smb_server_tcp_receive
725  */
726 int
727 smb_server_tcp_receive(void)
728 {
729 	int		rc;
730 	smb_server_t	*sv;
731 
732 	rc = smb_server_lookup(&sv);
733 	if (rc)
734 		return (rc);
735 
736 	rc = smb_session_daemon(&sv->sv_tcp_daemon.ld_session_list);
737 
738 	smb_server_release(sv);
739 
740 	return (rc);
741 }
742 
743 int
744 smb_server_set_gmtoff(int32_t goff)
745 {
746 	int		rc;
747 	smb_server_t	*sv;
748 
749 
750 	rc = smb_server_lookup(&sv);
751 	if (rc)
752 		return (rc);
753 
754 	sv->si_gmtoff = goff;
755 
756 	smb_server_release(sv);
757 
758 	return (rc);
759 }
760 
761 /*
762  * *****************************************************************************
763  * ****************** Functions called from the door interface *****************
764  * *****************************************************************************
765  *
766  * These functions determine the relevant smb server to which the call apply.
767  */
768 
769 uint32_t
770 smb_server_get_user_count(void)
771 {
772 	smb_server_t	*sv;
773 	uint32_t	counter = 0;
774 
775 	if (smb_server_lookup(&sv))
776 		return (0);
777 
778 	counter = (uint32_t)sv->sv_open_users;
779 
780 	smb_server_release(sv);
781 
782 	return (counter);
783 }
784 
785 uint32_t
786 smb_server_get_session_count(void)
787 {
788 	smb_server_t	*sv;
789 	uint32_t	counter = 0;
790 
791 	if (smb_server_lookup(&sv))
792 		return (0);
793 
794 	rw_enter(&sv->sv_nbt_daemon.ld_session_list.se_lock, RW_READER);
795 	counter = sv->sv_nbt_daemon.ld_session_list.se_act.count;
796 	rw_exit(&sv->sv_nbt_daemon.ld_session_list.se_lock);
797 	rw_enter(&sv->sv_tcp_daemon.ld_session_list.se_lock, RW_READER);
798 	counter += sv->sv_tcp_daemon.ld_session_list.se_act.count;
799 	rw_exit(&sv->sv_tcp_daemon.ld_session_list.se_lock);
800 
801 	smb_server_release(sv);
802 
803 	return (counter);
804 }
805 
806 /*
807  * smb_session_disconnect_share
808  *
809  * Disconnects the specified share. This function should be called after the
810  * share passed in has been made unavailable by the "share manager".
811  */
812 void
813 smb_server_disconnect_share(char *sharename)
814 {
815 	smb_server_t	*sv;
816 
817 	if (smb_server_lookup(&sv))
818 		return;
819 
820 	smb_session_disconnect_share(&sv->sv_nbt_daemon.ld_session_list,
821 	    sharename);
822 	smb_session_disconnect_share(&sv->sv_tcp_daemon.ld_session_list,
823 	    sharename);
824 
825 	smb_server_release(sv);
826 }
827 
828 void
829 smb_server_disconnect_volume(const char *volname)
830 {
831 	smb_server_t	*sv;
832 
833 	if (smb_server_lookup(&sv))
834 		return;
835 
836 	smb_session_disconnect_volume(&sv->sv_nbt_daemon.ld_session_list,
837 	    volname);
838 	smb_session_disconnect_volume(&sv->sv_tcp_daemon.ld_session_list,
839 	    volname);
840 
841 	smb_server_release(sv);
842 }
843 
844 int
845 smb_server_dr_ulist_get(int offset, smb_dr_ulist_t *dr_ulist, int max_cnt)
846 {
847 	smb_server_t	*sv;
848 
849 	if (!dr_ulist)
850 		return (-1);
851 
852 	if (smb_server_lookup(&sv))
853 		return (-1);
854 
855 	dr_ulist->dul_cnt =
856 	    smb_server_ulist_geti(&sv->sv_nbt_daemon.ld_session_list,
857 	    offset, dr_ulist->dul_users, max_cnt);
858 	dr_ulist->dul_cnt +=
859 	    smb_server_ulist_geti(&sv->sv_tcp_daemon.ld_session_list,
860 	    offset - dr_ulist->dul_cnt, &dr_ulist->dul_users[dr_ulist->dul_cnt],
861 	    max_cnt);
862 
863 	return (dr_ulist->dul_cnt);
864 }
865 
866 /*
867  * smb_server_share_export()
868  *
869  * This function handles kernel processing at share enable time.
870  *
871  * At share-enable time (LMSHRD_ADD), the file system corresponding to
872  * the share is checked for characteristics that are required for SMB
873  * sharing.  If this check passes, then a hold is taken on the root vnode
874  * of the file system (or a reference count on the corresponding smb_vfs_t
875  * is bumped), preventing an unmount.  (See smb_vfs_hold()).
876  */
877 
878 int
879 smb_server_share_export(char *path)
880 {
881 	smb_server_t	*sv;
882 	int		error;
883 	smb_node_t	*fnode = NULL;
884 	smb_node_t	*dnode;
885 	smb_attr_t	ret_attr;
886 	char		last_comp[MAXNAMELEN];
887 	smb_request_t	*sr;
888 
889 	if (smb_server_lookup(&sv))
890 		return (EINVAL);
891 
892 	sr = smb_request_alloc(sv->sv_session, 0);
893 	if (sr == NULL) {
894 		smb_server_release(sv);
895 		return (ENOMEM);
896 	}
897 
898 	sr->user_cr = kcred;
899 
900 	error = smb_pathname_reduce(sr, kcred, path, NULL, NULL, &dnode,
901 	    last_comp);
902 
903 	if (error) {
904 		smb_request_free(sr);
905 		smb_server_release(sv);
906 		return (error);
907 	}
908 
909 	error = smb_fsop_lookup(sr, sr->user_cr, SMB_FOLLOW_LINKS, NULL, dnode,
910 	    last_comp, &fnode, &ret_attr, NULL, NULL);
911 
912 	smb_node_release(dnode);
913 
914 	if (error) {
915 		smb_request_free(sr);
916 		smb_server_release(sv);
917 		return (error);
918 	}
919 
920 	ASSERT(fnode->vp && fnode->vp->v_vfsp);
921 
922 #ifdef SMB_ENFORCE_NODEV
923 	if (vfs_optionisset(fnode->vp->v_vfsp, MNTOPT_NODEVICES, NULL) == 0)
924 		return (EINVAL);
925 #endif /* SMB_ENFORCE_NODEV */
926 
927 	if (!smb_vfs_hold(sv, fnode->vp->v_vfsp)) {
928 		smb_node_release(fnode);
929 		smb_request_free(sr);
930 		smb_server_release(sv);
931 		return (ENOMEM);
932 	}
933 
934 	/*
935 	 * The refcount on the smb_vfs has been incremented.
936 	 * If it wasn't already, a hold has also been taken
937 	 * on the root vnode of the file system.
938 	 */
939 
940 	smb_node_release(fnode);
941 	smb_request_free(sr);
942 	smb_server_release(sv);
943 	return (0);
944 }
945 
946 
947 
948 /*
949  * smb_server_share_unexport()
950  *
951  * This function handles kernel processing at share disable time.
952  *
953  * At share-disable time (LMSHRD_DELETE), the reference count on the
954  * corresponding smb_vfs_t is decremented.  If this is the last share
955  * on the file system, the hold on the root vnode of the file system
956  * will be released.  (See smb_vfs_rele().)
957  */
958 
959 int
960 smb_server_share_unexport(char *path, char *sharename)
961 {
962 	smb_server_t	*sv;
963 	int		error;
964 	smb_node_t	*fnode = NULL;
965 	smb_node_t	*dnode;
966 	smb_attr_t	ret_attr;
967 	char		last_comp[MAXNAMELEN];
968 	smb_request_t	*sr;
969 
970 	if (smb_server_lookup(&sv))
971 		return (EINVAL);
972 
973 	sr = smb_request_alloc(sv->sv_session, 0);
974 	if (sr == NULL) {
975 		smb_server_release(sv);
976 		return (ENOMEM);
977 	}
978 	sr->user_cr = kcred;
979 
980 	error = smb_pathname_reduce(sr, kcred, path, NULL, NULL, &dnode,
981 	    last_comp);
982 
983 	if (error) {
984 		smb_request_free(sr);
985 		smb_server_release(sv);
986 		return (error);
987 	}
988 
989 	error = smb_fsop_lookup(sr, kcred, SMB_FOLLOW_LINKS, NULL, dnode,
990 	    last_comp, &fnode, &ret_attr, NULL, NULL);
991 
992 	smb_node_release(dnode);
993 
994 	if (error) {
995 		smb_request_free(sr);
996 		smb_server_release(sv);
997 		return (error);
998 	}
999 
1000 	ASSERT(fnode->vp && fnode->vp->v_vfsp);
1001 
1002 	smb_session_disconnect_share(&sv->sv_nbt_daemon.ld_session_list,
1003 	    sharename);
1004 	smb_session_disconnect_share(&sv->sv_tcp_daemon.ld_session_list,
1005 	    sharename);
1006 	smb_vfs_rele(sv, fnode->vp->v_vfsp);
1007 	smb_node_release(fnode);
1008 	smb_request_free(sr);
1009 	smb_server_release(sv);
1010 	return (0);
1011 }
1012 
1013 /*
1014  * This is a special interface that will be utilized by ZFS to cause a share to
1015  * be added/removed.
1016  *
1017  * arg is either a lmshare_info_t or share_name from userspace.
1018  * It will need to be copied into the kernel.   It is lmshare_info_t
1019  * for add operations and share_name for delete operations.
1020  */
1021 int
1022 smb_server_share(void *arg, boolean_t add_share)
1023 {
1024 	smb_server_t	*sv;
1025 	int		rc;
1026 
1027 	rc = smb_server_lookup(&sv);
1028 	if (rc == 0) {
1029 		mutex_enter(&sv->sv_mutex);
1030 		if (sv->sv_state == SMB_SERVER_STATE_RUNNING) {
1031 			mutex_exit(&sv->sv_mutex);
1032 			rc = smb_kshare_upcall(sv->sv_lmshrd, arg, add_share);
1033 		} else {
1034 			mutex_exit(&sv->sv_mutex);
1035 			rc = EPERM;
1036 		}
1037 		smb_server_release(sv);
1038 	}
1039 	return (rc);
1040 }
1041 
1042 /*
1043  * *****************************************************************************
1044  * **************** Functions called from the internal layers ******************
1045  * *****************************************************************************
1046  *
1047  * These functions are provided the relevant smb server by the caller.
1048  */
1049 
1050 void
1051 smb_server_reconnection_check(smb_server_t *sv, smb_session_t *session)
1052 {
1053 	ASSERT(sv == session->s_server);
1054 
1055 	smb_session_reconnection_check(&sv->sv_nbt_daemon.ld_session_list,
1056 	    session);
1057 	smb_session_reconnection_check(&sv->sv_tcp_daemon.ld_session_list,
1058 	    session);
1059 }
1060 
1061 void
1062 smb_server_get_cfg(smb_server_t *sv, smb_kmod_cfg_t *cfg)
1063 {
1064 	rw_enter(&sv->sv_cfg_lock, RW_READER);
1065 	bcopy(&sv->sv_cfg, cfg, sizeof (*cfg));
1066 	rw_exit(&sv->sv_cfg_lock);
1067 }
1068 
1069 /*
1070  * *****************************************************************************
1071  * *************************** Static Functions ********************************
1072  * *****************************************************************************
1073  */
1074 
1075 static void
1076 smb_server_timers(smb_thread_t *thread, void *arg)
1077 {
1078 	smb_server_t	*sv = (smb_server_t *)arg;
1079 
1080 	ASSERT(sv != NULL);
1081 
1082 	while (smb_thread_continue_timedwait(thread, 1 /* Seconds */)) {
1083 		smb_session_timers(&sv->sv_nbt_daemon.ld_session_list);
1084 		smb_session_timers(&sv->sv_tcp_daemon.ld_session_list);
1085 	}
1086 }
1087 
1088 /*
1089  * smb_server_kstat_init
1090  */
1091 static int
1092 smb_server_kstat_init(smb_server_t *sv)
1093 {
1094 	(void) snprintf(sv->sv_ksp_name, sizeof (sv->sv_ksp_name), "%s%d",
1095 	    SMBSRV_KSTAT_NAME, sv->sv_zid);
1096 
1097 	sv->sv_ksp = kstat_create(SMBSRV_KSTAT_MODULE, 0, sv->sv_ksp_name,
1098 	    SMBSRV_KSTAT_CLASS, KSTAT_TYPE_NAMED,
1099 	    sizeof (sv->sv_ks_data) / sizeof (kstat_named_t),
1100 	    KSTAT_FLAG_VIRTUAL);
1101 
1102 	if (sv->sv_ksp) {
1103 		(void) strlcpy(sv->sv_ks_data.open_files.name, "open_files",
1104 		    sizeof (sv->sv_ks_data.open_files.name));
1105 		sv->sv_ks_data.open_files.data_type = KSTAT_DATA_UINT32;
1106 		(void) strlcpy(sv->sv_ks_data.open_trees.name, "connections",
1107 		    sizeof (sv->sv_ks_data.open_trees.name));
1108 		sv->sv_ks_data.open_trees.data_type = KSTAT_DATA_UINT32;
1109 		(void) strlcpy(sv->sv_ks_data.open_users.name, "sessions",
1110 		    sizeof (sv->sv_ks_data.open_users.name));
1111 		sv->sv_ks_data.open_users.data_type = KSTAT_DATA_UINT32;
1112 
1113 		mutex_init(&sv->sv_ksp_mutex, NULL, MUTEX_DEFAULT, NULL);
1114 		sv->sv_ksp->ks_lock = &sv->sv_ksp_mutex;
1115 		sv->sv_ksp->ks_data = (void *)&sv->sv_ks_data;
1116 		sv->sv_ksp->ks_update = smb_server_kstat_update_info;
1117 		kstat_install(sv->sv_ksp);
1118 	}
1119 
1120 	/* create and initialize smb kstats - smb_dispatch stats */
1121 	smb_dispatch_kstat_init();
1122 
1123 	return (0);
1124 }
1125 
1126 /*
1127  * smb_server_kstat_fini
1128  */
1129 static void
1130 smb_server_kstat_fini(smb_server_t *sv)
1131 {
1132 	if (sv->sv_ksp) {
1133 		kstat_delete(sv->sv_ksp);
1134 		mutex_destroy(&sv->sv_ksp_mutex);
1135 		sv->sv_ksp = NULL;
1136 	}
1137 	smb_dispatch_kstat_fini();
1138 }
1139 
1140 /* ARGSUSED */
1141 static int
1142 smb_server_kstat_update_info(kstat_t *ksp, int rw)
1143 {
1144 	smb_server_t	*sv;
1145 
1146 	if (rw == KSTAT_WRITE) {
1147 		return (EACCES);
1148 	} else {
1149 		ASSERT(MUTEX_HELD(ksp->ks_lock));
1150 
1151 		_NOTE(LINTED("pointer cast may result in improper alignment"))
1152 		sv = (smb_server_t *)((uint8_t *)(ksp->ks_data) -
1153 		    offsetof(smb_server_t, sv_ks_data));
1154 
1155 		ASSERT(sv->sv_magic == SMB_SERVER_MAGIC);
1156 
1157 		sv->sv_ks_data.open_files.value.ui32 = sv->sv_open_files;
1158 		sv->sv_ks_data.open_trees.value.ui32 = sv->sv_open_trees;
1159 		sv->sv_ks_data.open_users.value.ui32 = sv->sv_open_users;
1160 	}
1161 	return (0);
1162 }
1163 
1164 /*
1165  * smb_server_stop
1166  *
1167  * The mutex of the server must have been entered before calling this function.
1168  */
1169 static void
1170 smb_server_stop(smb_server_t *sv)
1171 {
1172 	ASSERT(sv->sv_magic == SMB_SERVER_MAGIC);
1173 
1174 	smb_opipe_door_close();
1175 	smb_thread_stop(&sv->si_thread_timers);
1176 	smb_kdoor_clnt_stop();
1177 	smb_kshare_fini(sv->sv_lmshrd);
1178 	sv->sv_lmshrd = NULL;
1179 	smb_server_fsop_stop(sv);
1180 	if (sv->sv_session) {
1181 		smb_session_delete(sv->sv_session);
1182 		sv->sv_session = NULL;
1183 	}
1184 }
1185 
1186 static int
1187 smb_server_listen(
1188     smb_server_t		*sv,
1189     smb_listener_daemon_t	*ld,
1190     in_port_t			port,
1191     int				pthread_create_error)
1192 {
1193 	int			rc;
1194 	struct sonode		*s_so;
1195 	uint32_t		on = 1;
1196 	smb_session_t		*session;
1197 
1198 	if (pthread_create_error) {
1199 		/*
1200 		 * Delete the last session created. The user space thread
1201 		 * creation failed.
1202 		 */
1203 		smb_session_list_delete_tail(&ld->ld_session_list);
1204 	}
1205 
1206 	if (ld->ld_so == NULL) {
1207 		/* First time listener */
1208 		ld->ld_sin.sin_family = AF_INET;
1209 		ld->ld_sin.sin_port = htons(port);
1210 		ld->ld_sin.sin_addr.s_addr = htonl(INADDR_ANY);
1211 		ld->ld_so = smb_socreate(AF_INET, SOCK_STREAM, 0);
1212 
1213 		if (ld->ld_so) {
1214 
1215 			(void) sosetsockopt(ld->ld_so, SOL_SOCKET,
1216 			    SO_REUSEADDR, (const void *)&on, sizeof (on));
1217 
1218 			rc = sobind(ld->ld_so, (struct sockaddr *)&ld->ld_sin,
1219 			    sizeof (ld->ld_sin), 0, 0);
1220 
1221 			if (rc == 0) {
1222 				rc =  solisten(ld->ld_so, 20);
1223 				if (rc < 0) {
1224 					cmn_err(CE_WARN,
1225 					    "Port %d: listen failed", port);
1226 					smb_soshutdown(ld->ld_so);
1227 					smb_sodestroy(ld->ld_so);
1228 					ld->ld_so = NULL;
1229 					return (rc);
1230 				}
1231 			} else {
1232 				cmn_err(CE_WARN,
1233 				    "Port %d: bind failed", port);
1234 				smb_soshutdown(ld->ld_so);
1235 				smb_sodestroy(ld->ld_so);
1236 				ld->ld_so = NULL;
1237 				return (rc);
1238 			}
1239 		} else {
1240 			cmn_err(CE_WARN,
1241 			    "Port %d: socket create failed", port);
1242 			return (ENOMEM);
1243 		}
1244 	}
1245 
1246 	DTRACE_PROBE1(so__wait__accept, struct sonode *, ld->ld_so);
1247 
1248 	for (;;) {
1249 		rc = soaccept(ld->ld_so, 0, &s_so);
1250 		if (rc == 0) {
1251 			uint32_t	txbuf_size = 128*1024;
1252 			uint32_t	on = 1;
1253 
1254 			DTRACE_PROBE1(so__accept, struct sonode *, s_so);
1255 
1256 			(void) sosetsockopt(s_so, IPPROTO_TCP, TCP_NODELAY,
1257 			    (const void *)&on, sizeof (on));
1258 			(void) sosetsockopt(s_so, SOL_SOCKET, SO_KEEPALIVE,
1259 			    (const void *)&on, sizeof (on));
1260 			(void) sosetsockopt(s_so, SOL_SOCKET, SO_SNDBUF,
1261 			    (const void *)&txbuf_size, sizeof (txbuf_size));
1262 			/*
1263 			 * Create a session for this connection.
1264 			 */
1265 			session = smb_session_create(s_so, port, sv);
1266 			if (session) {
1267 				smb_session_list_append(&ld->ld_session_list,
1268 				    session);
1269 				break;
1270 			} else {
1271 				smb_soshutdown(s_so);
1272 				smb_sodestroy(s_so);
1273 			}
1274 			continue;
1275 		}
1276 		smb_session_list_signal(&ld->ld_session_list);
1277 		smb_soshutdown(ld->ld_so);
1278 		smb_sodestroy(ld->ld_so);
1279 		ld->ld_so = NULL;
1280 		break;
1281 	}
1282 
1283 	return (rc);
1284 }
1285 
1286 /*
1287  * smb_server_lookup
1288  *
1289  * This function tries to find the server associated with the zone of the
1290  * caller.
1291  */
1292 static int
1293 smb_server_lookup(smb_server_t **psv)
1294 {
1295 	zoneid_t	zid;
1296 	smb_server_t	*sv;
1297 
1298 	zid = getzoneid();
1299 
1300 	smb_llist_enter(&smb_servers, RW_READER);
1301 	sv = smb_llist_head(&smb_servers);
1302 	while (sv) {
1303 		ASSERT(sv->sv_magic == SMB_SERVER_MAGIC);
1304 		if (sv->sv_zid == zid) {
1305 			mutex_enter(&sv->sv_mutex);
1306 			if (sv->sv_state != SMB_SERVER_STATE_DELETING) {
1307 				sv->sv_refcnt++;
1308 				mutex_exit(&sv->sv_mutex);
1309 				smb_llist_exit(&smb_servers);
1310 				*psv = sv;
1311 				return (0);
1312 			}
1313 			mutex_exit(&sv->sv_mutex);
1314 			break;
1315 		}
1316 		sv = smb_llist_next(&smb_servers, sv);
1317 	}
1318 	smb_llist_exit(&smb_servers);
1319 	return (EPERM);
1320 }
1321 
1322 /*
1323  * smb_server_release
1324  *
1325  * This function decrements the reference count of the server and signals its
1326  * condition variable if the state of the server is SMB_SERVER_STATE_DELETING.
1327  */
1328 static void
1329 smb_server_release(smb_server_t *sv)
1330 {
1331 	ASSERT(sv->sv_magic == SMB_SERVER_MAGIC);
1332 
1333 	mutex_enter(&sv->sv_mutex);
1334 	ASSERT(sv->sv_refcnt);
1335 	sv->sv_refcnt--;
1336 	if ((sv->sv_refcnt == 0) && (sv->sv_state == SMB_SERVER_STATE_DELETING))
1337 		cv_signal(&sv->sv_cv);
1338 	mutex_exit(&sv->sv_mutex);
1339 }
1340 
1341 static int
1342 smb_server_ulist_geti(
1343     smb_session_list_t	*se,
1344     int			offset,
1345     smb_opipe_context_t	*ctx,
1346     int			max_cnt)
1347 {
1348 	smb_session_t	*sn = NULL;
1349 	smb_user_t	*user;
1350 	smb_llist_t	*ulist;
1351 	int		cnt = 0, skip = 0;
1352 
1353 	rw_enter(&se->se_lock, RW_READER);
1354 	sn = list_head(&se->se_act.lst);
1355 	while (sn && (cnt < max_cnt)) {
1356 		ASSERT(sn->s_magic == SMB_SESSION_MAGIC);
1357 		ulist = &sn->s_user_list;
1358 		smb_llist_enter(ulist, RW_READER);
1359 		user = smb_llist_head(ulist);
1360 		while (user && (cnt < max_cnt)) {
1361 			ASSERT(user->u_magic == SMB_USER_MAGIC);
1362 			mutex_enter(&user->u_mutex);
1363 			if (user->u_state == SMB_USER_STATE_LOGGED_IN) {
1364 				if (skip++ < offset) {
1365 					mutex_exit(&user->u_mutex);
1366 					user = smb_llist_next(ulist, user);
1367 					continue;
1368 				}
1369 
1370 				smb_user_context_init(user, ctx);
1371 				ctx++;
1372 				cnt++;
1373 			}
1374 			mutex_exit(&user->u_mutex);
1375 			user = smb_llist_next(ulist, user);
1376 		}
1377 		smb_llist_exit(ulist);
1378 	}
1379 	rw_exit(&se->se_lock);
1380 	return (cnt);
1381 }
1382 
1383 static void
1384 smb_server_store_cfg(smb_server_t *sv, smb_kmod_cfg_t *cfg)
1385 {
1386 	if (cfg->skc_maxconnections == 0)
1387 		cfg->skc_maxconnections = 0xFFFFFFFF;
1388 
1389 	smb_session_correct_keep_alive_values(
1390 	    &sv->sv_nbt_daemon.ld_session_list, cfg->skc_keepalive);
1391 	smb_session_correct_keep_alive_values(
1392 	    &sv->sv_tcp_daemon.ld_session_list, cfg->skc_keepalive);
1393 
1394 	bcopy(cfg, &sv->sv_cfg, sizeof (sv->sv_cfg));
1395 }
1396 
1397 static int
1398 smb_server_fsop_start(smb_server_t *sv)
1399 {
1400 	int	error;
1401 
1402 	error = smb_node_root_init(rootdir, sv, &sv->si_root_smb_node);
1403 	if (error != 0)
1404 		sv->si_root_smb_node = NULL;
1405 
1406 	return (error);
1407 }
1408 
1409 static void
1410 smb_server_fsop_stop(smb_server_t *sv)
1411 {
1412 	if (sv->si_root_smb_node != NULL) {
1413 		smb_vfs_rele_all(sv);
1414 		smb_node_release(sv->si_root_smb_node);
1415 		sv->si_root_smb_node = NULL;
1416 	}
1417 }
1418