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