xref: /titanic_41/usr/src/uts/common/fs/smbsrv/smb_server.c (revision ec39b9cf9a38586835b89f8cc2150710071adce3)
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 2009 Sun Microsystems, Inc.  All rights reserved.
23  * Use is subject to license terms.
24  */
25 
26 /*
27  * General Structures Layout
28  * -------------------------
29  *
30  * This is a simplified diagram showing the relationship between most of the
31  * main structures.
32  *
33  * +-------------------+
34  * |     SMB_SERVER    |
35  * +-------------------+
36  *          |
37  *          |
38  *          v
39  * +-------------------+       +-------------------+      +-------------------+
40  * |     SESSION       |<----->|     SESSION       |......|      SESSION      |
41  * +-------------------+       +-------------------+      +-------------------+
42  *          |
43  *          |
44  *          v
45  * +-------------------+       +-------------------+      +-------------------+
46  * |       USER        |<----->|       USER        |......|       USER        |
47  * +-------------------+       +-------------------+      +-------------------+
48  *          |
49  *          |
50  *          v
51  * +-------------------+       +-------------------+      +-------------------+
52  * |       TREE        |<----->|       TREE        |......|       TREE        |
53  * +-------------------+       +-------------------+      +-------------------+
54  *      |         |
55  *      |         |
56  *      |         v
57  *      |     +-------+       +-------+      +-------+
58  *      |     | OFILE |<----->| OFILE |......| OFILE |
59  *      |     +-------+       +-------+      +-------+
60  *      |
61  *      |
62  *      v
63  *  +-------+       +------+      +------+
64  *  | ODIR  |<----->| ODIR |......| ODIR |
65  *  +-------+       +------+      +------+
66  *
67  *
68  * Module Interface Overview
69  * -------------------------
70  *
71  *
72  *	    +===================================+
73  *	    |		 smbd daemon		|
74  *	    +===================================+
75  *	      |		     |		      ^
76  *	      |		     |		      |
77  * User	      |		     |		      |
78  * -----------|--------------|----------------|--------------------------------
79  * Kernel     |		     |		      |
80  *            |		     |		      |
81  *	      |		     |		      |
82  *  +=========|==============|================|=================+
83  *  |	      v		     v		      |			|
84  *  | +-----------+ +--------------------+ +------------------+ |
85  *  | |     IO    | | Kernel Door Server | | User Door Servers|	|
86  *  | | Interface | |     Interface      | |   Interface      | |
87  *  | +-----------+ +--------------------+ +------------------+ |
88  *  |		|	     |		      ^		^	|
89  *  |		v	     v		      |		|	|    +=========+
90  *  |	     +-----------------------------------+	|	|    |	       |
91  *  |	     + SMB Server Management (this file) |<------------------|	 ZFS   |
92  *  |	     +-----------------------------------+	|	|    |	       |
93  *  |							|	|    |  Module |
94  *  |	     +-----------------------------------+	|	|    |	       |
95  *  |	     +     SMB Server Internal Layers    |------+	|    +=========+
96  *  |	     +-----------------------------------+		|
97  *  |								|
98  *  |								|
99  *  +===========================================================+
100  *
101  *
102  * Server State Machine
103  * --------------------
104  *                                  |
105  *                                  | T0
106  *                                  |
107  *                                  v
108  *                    +-----------------------------+
109  *		      |   SMB_SERVER_STATE_CREATED  |
110  *		      +-----------------------------+
111  *				    |
112  *				    | T1
113  *				    |
114  *				    v
115  *		      +-----------------------------+
116  *		      | SMB_SERVER_STATE_CONFIGURED |
117  *		      +-----------------------------+
118  *				    |
119  *				    | T2
120  *				    |
121  *				    v
122  *		      +-----------------------------+
123  *		      |  SMB_SERVER_STATE_RUNNING   |
124  *		      +-----------------------------+
125  *				    |
126  *				    | T3
127  *				    |
128  *				    v
129  *		      +-----------------------------+
130  *		      |  SMB_SERVER_STATE_DELETING  |
131  *                    +-----------------------------+
132  *				    |
133  *				    |
134  *				    |
135  *				    v
136  *
137  * States
138  * ------
139  *
140  * SMB_SERVER_STATE_CREATED
141  *
142  *    This is the state of the server just after creation.
143  *
144  * SMB_SERVER_STATE_CONFIGURED
145  *
146  *    The server has been configured.
147  *
148  * SMB_SERVER_STATE_RUNNING
149  *
150  *    The server has been started. While in this state the threads listening on
151  *    the sockets car be started. The smbd daemon does so through an Ioctl:
152  *
153  *	smb_drv_ioctl(SMB_IOC_NBT_LISTEN) --> smb_server_nbt_listen()
154  *	smb_drv_ioctl(SMB_IOC_TCP_LISTEN) --> smb_server_nbt_listen()
155  *
156  *    When a client establishes a connection the thread listening leaves
157  *    temporarily the kernel. While in user space it creates a thread for the
158  *    new session. It then returns to kernel with the result of the thread
159  *    creation. If the creation failed the new session context is destroyed
160  *    before returning listening.
161  *
162  *    The new created thread enters the kernel though an Ioctl:
163  *
164  *	smb_drv_ioctl(SMB_IOC_NBT_RECEIVE) --> smb_server_nbt_receive()
165  *	smb_drv_ioctl(SMB_IOC_TCP_RECEIVE) --> smb_server_tcp_receive()
166  *
167  * SMB_SERVER_STATE_STOPPING
168  *
169  *    The threads listening on the NBT and TCP sockets are being terminated.
170  *
171  *
172  * Transitions
173  * -----------
174  *
175  * Transition T0
176  *
177  *    The daemon smbd triggers its creation by opening the smbsrv device. If
178  *    the zone where the daemon lives doesn't have an smb server yet it is
179  *    created.
180  *
181  *		smb_drv_open() --> smb_server_create()
182  *
183  * Transition T1
184  *
185  *    This transition occurs in smb_server_configure(). It is triggered by the
186  *    daemon through an Ioctl.
187  *
188  *	smb_drv_ioctl(SMB_IOC_CONFIG) --> smb_server_configure()
189  *
190  * Transition T2
191  *
192  *    This transition occurs in smb_server_start(). It is triggered by the
193  *    daemon through an Ioctl.
194  *
195  *	smb_drv_ioctl(SMB_IOC_START) --> smb_server_start()
196  *
197  * Transition T3
198  *
199  *    This transition occurs in smb_server_delete(). It is triggered by the
200  *    daemon when closing the smbsrv device
201  *
202  *		smb_drv_close() --> smb_server_delete()
203  *
204  * Comments
205  * --------
206  *
207  * This files assumes that there will one SMB server per zone. For now the
208  * smb server works only in global zone. There's nothing in this file preventing
209  * an smb server from being created in a non global zone. That limitation is
210  * enforced in user space.
211  */
212 
213 #include <sys/strsubr.h>
214 #include <sys/cmn_err.h>
215 #include <sys/priv.h>
216 #include <sys/socketvar.h>
217 #include <sys/zone.h>
218 #include <smbsrv/smb_kproto.h>
219 #include <smbsrv/netbios.h>
220 #include <smbsrv/smb_incl.h>
221 #include <smbsrv/cifs.h>
222 #include <smbsrv/smb_fsops.h>
223 #include <smbsrv/smb_share.h>
224 #include <smbsrv/smb_door_svc.h>
225 #include <smbsrv/smb_kstat.h>
226 
227 extern void smb_dispatch_kstat_init(void);
228 extern void smb_dispatch_kstat_fini(void);
229 extern void smb_reply_notify_change_request(smb_request_t *);
230 
231 static int smb_server_kstat_init(smb_server_t *);
232 static void smb_server_kstat_fini(smb_server_t *);
233 static int smb_server_kstat_update_info(kstat_t *, int);
234 static void smb_server_timers(smb_thread_t *, void *);
235 static int smb_server_listen(smb_server_t *, smb_listener_daemon_t *,
236     in_port_t, int, int);
237 static int smb_server_lookup(smb_server_t **);
238 static void smb_server_release(smb_server_t *);
239 static void smb_server_store_cfg(smb_server_t *, smb_ioc_cfg_t *);
240 static void smb_server_stop(smb_server_t *);
241 static int smb_server_fsop_start(smb_server_t *);
242 static void smb_server_fsop_stop(smb_server_t *);
243 
244 static void smb_server_disconnect_share(char *, smb_server_t *);
245 static void smb_server_thread_unexport(smb_thread_t *, void *);
246 
247 static void smb_server_enum_private(smb_session_list_t *, smb_svcenum_t *);
248 static int smb_server_sesion_disconnect(smb_session_list_t *, const char *,
249     const char *);
250 static int smb_server_fclose(smb_session_list_t *, uint32_t);
251 
252 static smb_llist_t	smb_servers;
253 
254 /*
255  * *****************************************************************************
256  * **************** Functions called from the device interface *****************
257  * *****************************************************************************
258  *
259  * These functions typically have to determine the relevant smb server
260  * to which the call applies.
261  */
262 
263 /*
264  * smb_server_svc_init
265  *
266  * This function must be called from smb_drv_attach().
267  */
268 int
269 smb_server_svc_init(void)
270 {
271 	int	rc = 0;
272 
273 	while (rc == 0) {
274 		if (rc = smb_mbc_init())
275 			continue;
276 		if (rc = smb_vop_init())
277 			continue;
278 		if (rc = smb_node_init())
279 			continue;
280 		if (rc = smb_fem_init())
281 			continue;
282 		if (rc = smb_user_init())
283 			continue;
284 		if (rc = smb_notify_init())
285 			continue;
286 		if (rc = smb_net_init())
287 			continue;
288 		smb_llist_constructor(&smb_servers, sizeof (smb_server_t),
289 		    offsetof(smb_server_t, sv_lnd));
290 		return (0);
291 	}
292 	smb_net_fini();
293 	smb_notify_fini();
294 	smb_user_fini();
295 	smb_fem_fini();
296 	smb_node_fini();
297 	smb_vop_fini();
298 	smb_mbc_fini();
299 	return (rc);
300 }
301 
302 /*
303  * smb_server_svc_fini
304  *
305  * This function must called from smb_drv_detach(). It will fail if servers
306  * still exist.
307  */
308 int
309 smb_server_svc_fini(void)
310 {
311 	int	rc = EBUSY;
312 
313 	if (smb_llist_get_count(&smb_servers) == 0) {
314 		smb_net_fini();
315 		smb_notify_fini();
316 		smb_user_fini();
317 		smb_fem_fini();
318 		smb_node_fini();
319 		smb_vop_fini();
320 		smb_mbc_fini();
321 		smb_llist_destructor(&smb_servers);
322 		rc = 0;
323 	}
324 	return (rc);
325 }
326 
327 /*
328  * smb_server_create
329  *
330  * This function will fail if there's already a server associated with the
331  * caller's zone.
332  */
333 int
334 smb_server_create(void)
335 {
336 	zoneid_t	zid;
337 	smb_server_t	*sv;
338 
339 	zid = getzoneid();
340 
341 	smb_llist_enter(&smb_servers, RW_WRITER);
342 	sv = smb_llist_head(&smb_servers);
343 	while (sv) {
344 		ASSERT(sv->sv_magic == SMB_SERVER_MAGIC);
345 		if (sv->sv_zid == zid) {
346 			smb_llist_exit(&smb_servers);
347 			return (EPERM);
348 		}
349 		sv = smb_llist_next(&smb_servers, sv);
350 	}
351 
352 	sv = kmem_zalloc(sizeof (smb_server_t), KM_NOSLEEP);
353 	if (sv == NULL) {
354 		smb_llist_exit(&smb_servers);
355 		return (ENOMEM);
356 	}
357 
358 	smb_llist_constructor(&sv->sv_vfs_list, sizeof (smb_vfs_t),
359 	    offsetof(smb_vfs_t, sv_lnd));
360 
361 	smb_slist_constructor(&sv->sv_unexport_list, sizeof (smb_unexport_t),
362 	    offsetof(smb_unexport_t, ux_lnd));
363 
364 	smb_session_list_constructor(&sv->sv_nbt_daemon.ld_session_list);
365 	smb_session_list_constructor(&sv->sv_tcp_daemon.ld_session_list);
366 
367 	sv->si_cache_unexport = kmem_cache_create("smb_unexport_cache",
368 	    sizeof (smb_unexport_t), 8, NULL, NULL, NULL, NULL, NULL, 0);
369 	sv->si_cache_vfs = kmem_cache_create("smb_vfs_cache",
370 	    sizeof (smb_vfs_t), 8, NULL, NULL, NULL, NULL, NULL, 0);
371 	sv->si_cache_request = kmem_cache_create("smb_request_cache",
372 	    sizeof (smb_request_t), 8, NULL, NULL, NULL, NULL, NULL, 0);
373 	sv->si_cache_session = kmem_cache_create("smb_session_cache",
374 	    sizeof (smb_session_t), 8, NULL, NULL, NULL, NULL, NULL, 0);
375 	sv->si_cache_user = kmem_cache_create("smb_user_cache",
376 	    sizeof (smb_user_t), 8, NULL, NULL, NULL, NULL, NULL, 0);
377 	sv->si_cache_tree = kmem_cache_create("smb_tree_cache",
378 	    sizeof (smb_tree_t), 8, NULL, NULL, NULL, NULL, NULL, 0);
379 	sv->si_cache_ofile = kmem_cache_create("smb_ofile_cache",
380 	    sizeof (smb_ofile_t), 8, NULL, NULL, NULL, NULL, NULL, 0);
381 	sv->si_cache_odir = kmem_cache_create("smb_odir_cache",
382 	    sizeof (smb_odir_t), 8, NULL, NULL, NULL, NULL, NULL, 0);
383 
384 	smb_thread_init(&sv->si_thread_timers,
385 	    "smb_timers", smb_server_timers, sv,
386 	    NULL, NULL);
387 
388 	smb_thread_init(&sv->si_thread_unexport, "smb_thread_unexport",
389 	    smb_server_thread_unexport, sv, NULL, NULL);
390 
391 	sv->sv_pid = curproc->p_pid;
392 
393 	smb_kdoor_clnt_init();
394 	smb_opipe_door_init();
395 	(void) smb_server_kstat_init(sv);
396 
397 	mutex_init(&sv->sv_mutex, NULL, MUTEX_DEFAULT, NULL);
398 	cv_init(&sv->sv_cv, NULL, CV_DEFAULT, NULL);
399 	sv->sv_state = SMB_SERVER_STATE_CREATED;
400 	sv->sv_magic = SMB_SERVER_MAGIC;
401 	sv->sv_zid = zid;
402 
403 	smb_llist_insert_tail(&smb_servers, sv);
404 	smb_llist_exit(&smb_servers);
405 	return (0);
406 }
407 
408 /*
409  * smb_server_delete
410  *
411  * This function will delete the server passed in. It will make sure that all
412  * activity associated that server has ceased before destroying it.
413  */
414 int
415 smb_server_delete(void)
416 {
417 	smb_server_t	*sv;
418 	smb_unexport_t	*ux;
419 	int		rc;
420 
421 	rc = smb_server_lookup(&sv);
422 	if (rc != 0)
423 		return (rc);
424 
425 	mutex_enter(&sv->sv_mutex);
426 	switch (sv->sv_state) {
427 	case SMB_SERVER_STATE_RUNNING:
428 	{
429 		boolean_t	nbt = B_FALSE;
430 		boolean_t	tcp = B_FALSE;
431 
432 		if (sv->sv_nbt_daemon.ld_kth) {
433 			tsignal(sv->sv_nbt_daemon.ld_kth, SIGINT);
434 			nbt = B_TRUE;
435 		}
436 		if (sv->sv_tcp_daemon.ld_kth) {
437 			tsignal(sv->sv_tcp_daemon.ld_kth, SIGINT);
438 			tcp = B_TRUE;
439 		}
440 		sv->sv_state = SMB_SERVER_STATE_DELETING;
441 		mutex_exit(&sv->sv_mutex);
442 		if (nbt)
443 			thread_join(sv->sv_nbt_daemon.ld_ktdid);
444 		if (tcp)
445 			thread_join(sv->sv_tcp_daemon.ld_ktdid);
446 		mutex_enter(&sv->sv_mutex);
447 		break;
448 	}
449 	case SMB_SERVER_STATE_CONFIGURED:
450 	case SMB_SERVER_STATE_CREATED:
451 		sv->sv_state = SMB_SERVER_STATE_DELETING;
452 		break;
453 	default:
454 		ASSERT(sv->sv_state == SMB_SERVER_STATE_DELETING);
455 		mutex_exit(&sv->sv_mutex);
456 		smb_server_release(sv);
457 		return (ENOTTY);
458 	}
459 
460 	ASSERT(sv->sv_state == SMB_SERVER_STATE_DELETING);
461 
462 	sv->sv_refcnt--;
463 	while (sv->sv_refcnt)
464 		cv_wait(&sv->sv_cv, &sv->sv_mutex);
465 
466 	mutex_exit(&sv->sv_mutex);
467 
468 	smb_llist_enter(&smb_servers, RW_WRITER);
469 	smb_llist_remove(&smb_servers, sv);
470 	smb_llist_exit(&smb_servers);
471 
472 	smb_server_stop(sv);
473 	rw_destroy(&sv->sv_cfg_lock);
474 	smb_opipe_door_fini();
475 	smb_kdoor_clnt_fini();
476 	smb_server_kstat_fini(sv);
477 	smb_llist_destructor(&sv->sv_vfs_list);
478 
479 	while ((ux = list_head(&sv->sv_unexport_list.sl_list)) != NULL) {
480 		smb_slist_remove(&sv->sv_unexport_list, ux);
481 		kmem_cache_free(sv->si_cache_unexport, ux);
482 	}
483 	smb_slist_destructor(&sv->sv_unexport_list);
484 
485 	kmem_cache_destroy(sv->si_cache_unexport);
486 	kmem_cache_destroy(sv->si_cache_vfs);
487 	kmem_cache_destroy(sv->si_cache_request);
488 	kmem_cache_destroy(sv->si_cache_session);
489 	kmem_cache_destroy(sv->si_cache_user);
490 	kmem_cache_destroy(sv->si_cache_tree);
491 	kmem_cache_destroy(sv->si_cache_ofile);
492 	kmem_cache_destroy(sv->si_cache_odir);
493 
494 	smb_thread_destroy(&sv->si_thread_timers);
495 	smb_thread_destroy(&sv->si_thread_unexport);
496 	mutex_destroy(&sv->sv_mutex);
497 	cv_destroy(&sv->sv_cv);
498 	sv->sv_magic = 0;
499 	kmem_free(sv, sizeof (smb_server_t));
500 
501 	return (0);
502 }
503 
504 /*
505  * smb_server_configure
506  */
507 int
508 smb_server_configure(smb_ioc_cfg_t *ioc)
509 {
510 	int		rc = 0;
511 	smb_server_t	*sv;
512 
513 	rc = smb_server_lookup(&sv);
514 	if (rc)
515 		return (rc);
516 
517 	mutex_enter(&sv->sv_mutex);
518 	switch (sv->sv_state) {
519 	case SMB_SERVER_STATE_CREATED:
520 		smb_server_store_cfg(sv, ioc);
521 		sv->sv_state = SMB_SERVER_STATE_CONFIGURED;
522 		break;
523 
524 	case SMB_SERVER_STATE_CONFIGURED:
525 		smb_server_store_cfg(sv, ioc);
526 		break;
527 
528 	case SMB_SERVER_STATE_RUNNING:
529 		rw_enter(&sv->sv_cfg_lock, RW_WRITER);
530 		smb_server_store_cfg(sv, ioc);
531 		rw_exit(&sv->sv_cfg_lock);
532 		break;
533 
534 	default:
535 		ASSERT(sv->sv_state == SMB_SERVER_STATE_DELETING);
536 		rc = EFAULT;
537 		break;
538 	}
539 	mutex_exit(&sv->sv_mutex);
540 
541 	smb_server_release(sv);
542 
543 	return (rc);
544 }
545 
546 /*
547  * smb_server_start
548  */
549 int
550 smb_server_start(smb_ioc_start_t *ioc)
551 {
552 	int		rc = 0;
553 	smb_server_t	*sv;
554 
555 	rc = smb_server_lookup(&sv);
556 	if (rc)
557 		return (rc);
558 
559 	mutex_enter(&sv->sv_mutex);
560 	switch (sv->sv_state) {
561 	case SMB_SERVER_STATE_CONFIGURED:
562 
563 		sv->sv_thread_pool = taskq_create("smb_workers",
564 		    sv->sv_cfg.skc_maxworkers, SMB_WORKER_PRIORITY,
565 		    sv->sv_cfg.skc_maxworkers, INT_MAX,
566 		    TASKQ_DYNAMIC|TASKQ_PREPOPULATE);
567 
568 		sv->sv_session = smb_session_create(NULL, 0, sv, 0);
569 
570 		if (sv->sv_thread_pool == NULL || sv->sv_session == NULL) {
571 			rc = ENOMEM;
572 			break;
573 		}
574 
575 		if (rc = smb_server_fsop_start(sv))
576 			break;
577 		ASSERT(sv->sv_lmshrd == NULL);
578 		sv->sv_lmshrd = smb_kshare_init(ioc->lmshrd);
579 		if (sv->sv_lmshrd == NULL)
580 			break;
581 		if (rc = smb_kdoor_clnt_open(ioc->udoor))
582 			break;
583 		if (rc = smb_thread_start(&sv->si_thread_timers))
584 			break;
585 		if (rc = smb_thread_start(&sv->si_thread_unexport))
586 			break;
587 		if (rc = smb_opipe_door_open(ioc->opipe)) {
588 			cmn_err(CE_WARN, "Cannot open opipe door");
589 			break;
590 		}
591 
592 		(void) oem_language_set("english");
593 
594 		sv->sv_state = SMB_SERVER_STATE_RUNNING;
595 		mutex_exit(&sv->sv_mutex);
596 		smb_server_release(sv);
597 		return (0);
598 	default:
599 		ASSERT((sv->sv_state == SMB_SERVER_STATE_CREATED) ||
600 		    (sv->sv_state == SMB_SERVER_STATE_RUNNING) ||
601 		    (sv->sv_state == SMB_SERVER_STATE_DELETING));
602 		mutex_exit(&sv->sv_mutex);
603 		smb_server_release(sv);
604 		return (ENOTTY);
605 	}
606 
607 	smb_server_stop(sv);
608 	mutex_exit(&sv->sv_mutex);
609 	smb_server_release(sv);
610 	return (rc);
611 }
612 
613 /*
614  * smb_server_nbt_listen: SMB-over-NetBIOS service
615  *
616  * Traditional SMB service over NetBIOS (port 139), which requires
617  * that a NetBIOS session be established.
618  */
619 int
620 smb_server_nbt_listen(smb_ioc_listen_t *ioc)
621 {
622 	smb_server_t	*sv;
623 	int		rc;
624 
625 	rc = smb_server_lookup(&sv);
626 	if (rc)
627 		return (rc);
628 
629 	mutex_enter(&sv->sv_mutex);
630 	switch (sv->sv_state) {
631 	case SMB_SERVER_STATE_RUNNING:
632 		if ((sv->sv_nbt_daemon.ld_kth != NULL) &&
633 		    (sv->sv_nbt_daemon.ld_kth != curthread)) {
634 			mutex_exit(&sv->sv_mutex);
635 			smb_server_release(sv);
636 			return (EACCES);
637 		} else {
638 			sv->sv_nbt_daemon.ld_kth = curthread;
639 			sv->sv_nbt_daemon.ld_ktdid = curthread->t_did;
640 		}
641 		break;
642 	default:
643 		ASSERT((sv->sv_state == SMB_SERVER_STATE_CREATED) ||
644 		    (sv->sv_state == SMB_SERVER_STATE_CONFIGURED) ||
645 		    (sv->sv_state == SMB_SERVER_STATE_DELETING));
646 		mutex_exit(&sv->sv_mutex);
647 		smb_server_release(sv);
648 		return (EFAULT);
649 	}
650 	mutex_exit(&sv->sv_mutex);
651 
652 	/*
653 	 * netbios must be ipv4
654 	 */
655 	rc = smb_server_listen(sv, &sv->sv_nbt_daemon, IPPORT_NETBIOS_SSN,
656 	    AF_INET, ioc->error);
657 
658 	if (rc) {
659 		mutex_enter(&sv->sv_mutex);
660 		sv->sv_nbt_daemon.ld_kth = NULL;
661 		mutex_exit(&sv->sv_mutex);
662 	}
663 
664 	smb_server_release(sv);
665 	return (rc);
666 }
667 
668 int
669 smb_server_tcp_listen(smb_ioc_listen_t *ioc)
670 {
671 	smb_server_t	*sv;
672 	int		rc;
673 
674 	rc = smb_server_lookup(&sv);
675 	if (rc)
676 		return (rc);
677 
678 	mutex_enter(&sv->sv_mutex);
679 	switch (sv->sv_state) {
680 	case SMB_SERVER_STATE_RUNNING:
681 		if ((sv->sv_tcp_daemon.ld_kth) &&
682 		    (sv->sv_tcp_daemon.ld_kth != curthread)) {
683 			mutex_exit(&sv->sv_mutex);
684 			smb_server_release(sv);
685 			return (EACCES);
686 		} else {
687 			sv->sv_tcp_daemon.ld_kth = curthread;
688 			sv->sv_tcp_daemon.ld_ktdid = curthread->t_did;
689 		}
690 		break;
691 	default:
692 		ASSERT((sv->sv_state == SMB_SERVER_STATE_CREATED) ||
693 		    (sv->sv_state == SMB_SERVER_STATE_CONFIGURED) ||
694 		    (sv->sv_state == SMB_SERVER_STATE_DELETING));
695 		mutex_exit(&sv->sv_mutex);
696 		smb_server_release(sv);
697 		return (EFAULT);
698 	}
699 	mutex_exit(&sv->sv_mutex);
700 
701 	if (sv->sv_cfg.skc_ipv6_enable)
702 		rc = smb_server_listen(sv, &sv->sv_tcp_daemon,
703 		    IPPORT_SMB, AF_INET6, ioc->error);
704 	else
705 		rc = smb_server_listen(sv, &sv->sv_tcp_daemon,
706 		    IPPORT_SMB, AF_INET, ioc->error);
707 	if (rc) {
708 		mutex_enter(&sv->sv_mutex);
709 		sv->sv_tcp_daemon.ld_kth = NULL;
710 		mutex_exit(&sv->sv_mutex);
711 	}
712 
713 	smb_server_release(sv);
714 	return (rc);
715 }
716 
717 /*
718  * smb_server_nbt_receive
719  */
720 int
721 smb_server_nbt_receive(void)
722 {
723 	int		rc;
724 	smb_server_t	*sv;
725 
726 	if ((rc = smb_server_lookup(&sv)) == 0) {
727 		rc = smb_session_daemon(&sv->sv_nbt_daemon.ld_session_list);
728 		smb_server_release(sv);
729 	}
730 
731 	return (rc);
732 }
733 
734 /*
735  * smb_server_tcp_receive
736  */
737 int
738 smb_server_tcp_receive(void)
739 {
740 	int		rc;
741 	smb_server_t	*sv;
742 
743 	if ((rc = smb_server_lookup(&sv)) == 0) {
744 		rc = smb_session_daemon(&sv->sv_tcp_daemon.ld_session_list);
745 		smb_server_release(sv);
746 	}
747 
748 	return (rc);
749 }
750 
751 int
752 smb_server_set_gmtoff(smb_ioc_gmt_t *ioc)
753 {
754 	int		rc;
755 	smb_server_t	*sv;
756 
757 	if ((rc = smb_server_lookup(&sv)) == 0) {
758 		sv->si_gmtoff = ioc->offset;
759 		smb_server_release(sv);
760 	}
761 
762 	return (rc);
763 }
764 
765 int
766 smb_server_numopen(smb_ioc_opennum_t *ioc)
767 {
768 	smb_server_t	*sv;
769 	int		rc;
770 
771 	if ((rc = smb_server_lookup(&sv)) == 0) {
772 		ioc->open_users = sv->sv_open_users;
773 		ioc->open_trees = sv->sv_open_trees;
774 		ioc->open_files = sv->sv_open_files;
775 		smb_server_release(sv);
776 	}
777 	return (rc);
778 }
779 
780 /*
781  * Enumerate objects within the server.  The svcenum provides the
782  * enumeration context, i.e. what the caller want to get back.
783  */
784 int
785 smb_server_enum(smb_ioc_svcenum_t *ioc)
786 {
787 	smb_svcenum_t		*svcenum = &ioc->svcenum;
788 	smb_server_t		*sv;
789 	smb_session_list_t	*se;
790 	int			rc;
791 
792 	switch (svcenum->se_type) {
793 	case SMB_SVCENUM_TYPE_USER:
794 	case SMB_SVCENUM_TYPE_TREE:
795 	case SMB_SVCENUM_TYPE_FILE:
796 		break;
797 	default:
798 		return (EINVAL);
799 	}
800 
801 	if ((rc = smb_server_lookup(&sv)) != 0)
802 		return (rc);
803 
804 	svcenum->se_bavail = svcenum->se_buflen;
805 	svcenum->se_bused = 0;
806 	svcenum->se_nitems = 0;
807 
808 	se = &sv->sv_nbt_daemon.ld_session_list;
809 	smb_server_enum_private(se, svcenum);
810 
811 	se = &sv->sv_tcp_daemon.ld_session_list;
812 	smb_server_enum_private(se, svcenum);
813 
814 	smb_server_release(sv);
815 	return (0);
816 }
817 
818 /*
819  * Look for sessions to disconnect by client and user name.
820  */
821 int
822 smb_server_session_close(smb_ioc_session_t *ioc)
823 {
824 	smb_session_list_t	*se;
825 	smb_server_t		*sv;
826 	int			nbt_cnt;
827 	int			tcp_cnt;
828 	int			rc;
829 
830 	if ((rc = smb_server_lookup(&sv)) != 0)
831 		return (rc);
832 
833 	se = &sv->sv_nbt_daemon.ld_session_list;
834 	nbt_cnt = smb_server_sesion_disconnect(se, ioc->client, ioc->username);
835 
836 	se = &sv->sv_tcp_daemon.ld_session_list;
837 	tcp_cnt = smb_server_sesion_disconnect(se, ioc->client, ioc->username);
838 
839 	smb_server_release(sv);
840 
841 	if ((nbt_cnt == 0) && (tcp_cnt == 0))
842 		return (ENOENT);
843 	return (0);
844 }
845 
846 /*
847  * Close a file by uniqid.
848  */
849 int
850 smb_server_file_close(smb_ioc_fileid_t *ioc)
851 {
852 	uint32_t		uniqid = ioc->uniqid;
853 	smb_session_list_t	*se;
854 	smb_server_t		*sv;
855 	int			rc;
856 
857 	if ((rc = smb_server_lookup(&sv)) != 0)
858 		return (rc);
859 
860 	se = &sv->sv_nbt_daemon.ld_session_list;
861 	rc = smb_server_fclose(se, uniqid);
862 
863 	if (rc == ENOENT) {
864 		se = &sv->sv_tcp_daemon.ld_session_list;
865 		rc = smb_server_fclose(se, uniqid);
866 	}
867 
868 	smb_server_release(sv);
869 	return (rc);
870 }
871 
872 /*
873  * These functions determine the relevant smb server to which the call apply.
874  */
875 
876 uint32_t
877 smb_server_get_session_count(void)
878 {
879 	smb_server_t	*sv;
880 	uint32_t	counter = 0;
881 
882 	if (smb_server_lookup(&sv))
883 		return (0);
884 
885 	rw_enter(&sv->sv_nbt_daemon.ld_session_list.se_lock, RW_READER);
886 	counter = sv->sv_nbt_daemon.ld_session_list.se_act.count;
887 	rw_exit(&sv->sv_nbt_daemon.ld_session_list.se_lock);
888 	rw_enter(&sv->sv_tcp_daemon.ld_session_list.se_lock, RW_READER);
889 	counter += sv->sv_tcp_daemon.ld_session_list.se_act.count;
890 	rw_exit(&sv->sv_tcp_daemon.ld_session_list.se_lock);
891 
892 	smb_server_release(sv);
893 
894 	return (counter);
895 }
896 
897 /*
898  * smb_server_disconnect_share
899  *
900  * Disconnects the specified share. This function should be called after the
901  * share passed in has been made unavailable by the "share manager".
902  */
903 static void
904 smb_server_disconnect_share(char *sharename, smb_server_t *sv)
905 {
906 	smb_session_disconnect_share(&sv->sv_nbt_daemon.ld_session_list,
907 	    sharename);
908 	smb_session_disconnect_share(&sv->sv_tcp_daemon.ld_session_list,
909 	    sharename);
910 }
911 
912 /*
913  * smb_server_share_export()
914  *
915  * This function handles kernel processing at share enable time.
916  *
917  * At share-enable time (LMSHRD_ADD), the file system corresponding to
918  * the share is checked for characteristics that are required for SMB
919  * sharing.  If this check passes, then a hold is taken on the root vnode
920  * of the file system (or a reference count on the corresponding smb_vfs_t
921  * is bumped), preventing an unmount.  (See smb_vfs_hold()).
922  */
923 
924 int
925 smb_server_share_export(smb_ioc_share_t *ioc)
926 {
927 	smb_server_t	*sv;
928 	int		error = 0;
929 	smb_node_t	*fnode = NULL;
930 	smb_node_t	*dnode;
931 	char		last_comp[MAXNAMELEN];
932 	smb_request_t	*sr;
933 
934 	if (smb_server_lookup(&sv))
935 		return (EINVAL);
936 
937 	mutex_enter(&sv->sv_mutex);
938 	switch (sv->sv_state) {
939 	case SMB_SERVER_STATE_RUNNING:
940 		break;
941 	default:
942 		mutex_exit(&sv->sv_mutex);
943 		return (ENOTACTIVE);
944 	}
945 	mutex_exit(&sv->sv_mutex);
946 
947 	sr = smb_request_alloc(sv->sv_session, 0);
948 	if (sr == NULL) {
949 		smb_server_release(sv);
950 		return (ENOMEM);
951 	}
952 
953 	sr->user_cr = kcred;
954 
955 	error = smb_pathname_reduce(sr, kcred, ioc->path,
956 	    NULL, NULL, &dnode, last_comp);
957 
958 	if (error) {
959 		smb_request_free(sr);
960 		smb_server_release(sv);
961 		return (error);
962 	}
963 
964 	error = smb_fsop_lookup(sr, sr->user_cr, SMB_FOLLOW_LINKS,
965 	    sv->si_root_smb_node, dnode, last_comp, &fnode);
966 
967 	smb_node_release(dnode);
968 
969 	if (error) {
970 		smb_request_free(sr);
971 		smb_server_release(sv);
972 		return (error);
973 	}
974 
975 	ASSERT(fnode->vp && fnode->vp->v_vfsp);
976 
977 #ifdef SMB_ENFORCE_NODEV
978 	if (vfs_optionisset(fnode->vp->v_vfsp, MNTOPT_NODEVICES, NULL) == 0) {
979 		smb_node_release(fnode);
980 		smb_request_free(sr);
981 		smb_server_release(sv);
982 		return (EINVAL);
983 	}
984 #endif /* SMB_ENFORCE_NODEV */
985 
986 	if (!smb_vfs_hold(sv, fnode->vp->v_vfsp))
987 		error = ENOMEM;
988 
989 	/*
990 	 * The refcount on the smb_vfs has been incremented.
991 	 * If it wasn't already, a hold has also been taken
992 	 * on the root vnode of the file system.
993 	 */
994 
995 	smb_node_release(fnode);
996 	smb_request_free(sr);
997 	smb_server_release(sv);
998 	return (error);
999 }
1000 
1001 /*
1002  * smb_server_share_unexport()
1003  *
1004  * This function is invoked when a share is disabled to disconnect trees
1005  * and close files.  Cleaning up may involve VOP and/or VFS calls, which
1006  * may conflict/deadlock with stuck threads if something is amiss with the
1007  * file system.  Queueing the request for asynchronous processing allows the
1008  * call to return immediately so that, if the unshare is being done in the
1009  * context of a forced unmount, the forced unmount will always be able to
1010  * proceed (unblocking stuck I/O and eventually allowing all blocked unshare
1011  * processes to complete).
1012  *
1013  * The path lookup to find the root vnode of the VFS in question and the
1014  * release of this vnode are done synchronously prior to any associated
1015  * unmount.  Doing these asynchronous to an associated unmount could run
1016  * the risk of a spurious EBUSY for a standard unmount or an EIO during
1017  * the path lookup due to a forced unmount finishing first.
1018  */
1019 
1020 int
1021 smb_server_share_unexport(smb_ioc_share_t *ioc)
1022 {
1023 	smb_server_t	*sv;
1024 	smb_request_t	*sr;
1025 	smb_unexport_t	*ux;
1026 	smb_node_t	*fnode = NULL;
1027 	smb_node_t	*dnode;
1028 	char		last_comp[MAXNAMELEN];
1029 	int		rc;
1030 
1031 	if ((rc = smb_server_lookup(&sv)))
1032 		return (rc);
1033 
1034 	mutex_enter(&sv->sv_mutex);
1035 	switch (sv->sv_state) {
1036 	case SMB_SERVER_STATE_RUNNING:
1037 		break;
1038 	default:
1039 		mutex_exit(&sv->sv_mutex);
1040 		return (ENOTACTIVE);
1041 	}
1042 	mutex_exit(&sv->sv_mutex);
1043 
1044 	sr = smb_request_alloc(sv->sv_session, 0);
1045 
1046 	if (sr == NULL) {
1047 		smb_server_release(sv);
1048 		return (ENOMEM);
1049 	}
1050 
1051 	sr->user_cr = kcred;
1052 
1053 	rc = smb_pathname_reduce(sr, kcred, ioc->path, NULL, NULL,
1054 	    &dnode, last_comp);
1055 
1056 	if (rc) {
1057 		smb_request_free(sr);
1058 		smb_server_release(sv);
1059 		return (rc);
1060 	}
1061 
1062 	rc = smb_fsop_lookup(sr, kcred, SMB_FOLLOW_LINKS, sv->si_root_smb_node,
1063 	    dnode, last_comp, &fnode);
1064 
1065 	smb_node_release(dnode);
1066 	smb_request_free(sr);
1067 
1068 	if (rc) {
1069 		smb_server_release(sv);
1070 		return (rc);
1071 	}
1072 
1073 	ASSERT(fnode->vp && fnode->vp->v_vfsp);
1074 
1075 	smb_vfs_rele(sv, fnode->vp->v_vfsp);
1076 
1077 	smb_node_release(fnode);
1078 
1079 	ux = kmem_cache_alloc(sv->si_cache_unexport, KM_SLEEP);
1080 
1081 	(void) strlcpy(ux->ux_sharename, ioc->name, MAXNAMELEN);
1082 
1083 	smb_slist_insert_tail(&sv->sv_unexport_list, ux);
1084 	smb_thread_signal(&sv->si_thread_unexport);
1085 
1086 	smb_server_release(sv);
1087 	return (0);
1088 }
1089 
1090 /*
1091  * smb_server_thread_unexport
1092  *
1093  * This function processes the unexport event list and disconnects shares
1094  * asynchronously.  The function executes as a zone-specific thread.
1095  *
1096  * The server arg passed in is safe to use without a reference count, because
1097  * the server cannot be deleted until smb_thread_stop()/destroy() return,
1098  * which is also when the thread exits.
1099  */
1100 
1101 static void
1102 smb_server_thread_unexport(smb_thread_t *thread, void *arg)
1103 {
1104 	smb_server_t *sv = (smb_server_t *)arg;
1105 	smb_unexport_t	*ux;
1106 
1107 	while (smb_thread_continue(thread)) {
1108 		while ((ux = list_head(&sv->sv_unexport_list.sl_list))
1109 		    != NULL) {
1110 			smb_slist_remove(&sv->sv_unexport_list, ux);
1111 			smb_server_disconnect_share(ux->ux_sharename, sv);
1112 			kmem_cache_free(sv->si_cache_unexport, ux);
1113 		}
1114 	}
1115 }
1116 
1117 /*
1118  * This is a special interface that will be utilized by ZFS to cause a share to
1119  * be added/removed.
1120  *
1121  * arg is either a lmshare_info_t or share_name from userspace.
1122  * It will need to be copied into the kernel.   It is lmshare_info_t
1123  * for add operations and share_name for delete operations.
1124  */
1125 int
1126 smb_server_share(void *arg, boolean_t add_share)
1127 {
1128 	smb_server_t	*sv;
1129 	int		rc;
1130 
1131 	rc = smb_server_lookup(&sv);
1132 	if (rc == 0) {
1133 		mutex_enter(&sv->sv_mutex);
1134 		switch (sv->sv_state) {
1135 		case SMB_SERVER_STATE_RUNNING:
1136 			mutex_exit(&sv->sv_mutex);
1137 			(void) smb_kshare_upcall(sv->sv_lmshrd, arg, add_share);
1138 			break;
1139 		default:
1140 			mutex_exit(&sv->sv_mutex);
1141 			break;
1142 		}
1143 		smb_server_release(sv);
1144 	}
1145 	return (0);
1146 }
1147 
1148 /*
1149  * *****************************************************************************
1150  * **************** Functions called from the internal layers ******************
1151  * *****************************************************************************
1152  *
1153  * These functions are provided the relevant smb server by the caller.
1154  */
1155 
1156 void
1157 smb_server_reconnection_check(smb_server_t *sv, smb_session_t *session)
1158 {
1159 	ASSERT(sv == session->s_server);
1160 
1161 	smb_session_reconnection_check(&sv->sv_nbt_daemon.ld_session_list,
1162 	    session);
1163 	smb_session_reconnection_check(&sv->sv_tcp_daemon.ld_session_list,
1164 	    session);
1165 }
1166 
1167 void
1168 smb_server_get_cfg(smb_server_t *sv, smb_kmod_cfg_t *cfg)
1169 {
1170 	rw_enter(&sv->sv_cfg_lock, RW_READER);
1171 	bcopy(&sv->sv_cfg, cfg, sizeof (*cfg));
1172 	rw_exit(&sv->sv_cfg_lock);
1173 }
1174 
1175 /*
1176  * *****************************************************************************
1177  * *************************** Static Functions ********************************
1178  * *****************************************************************************
1179  */
1180 
1181 static void
1182 smb_server_timers(smb_thread_t *thread, void *arg)
1183 {
1184 	smb_server_t	*sv = (smb_server_t *)arg;
1185 
1186 	ASSERT(sv != NULL);
1187 
1188 	while (smb_thread_continue_timedwait(thread, 1 /* Seconds */)) {
1189 		smb_session_timers(&sv->sv_nbt_daemon.ld_session_list);
1190 		smb_session_timers(&sv->sv_tcp_daemon.ld_session_list);
1191 	}
1192 }
1193 
1194 /*
1195  * smb_server_kstat_init
1196  */
1197 static int
1198 smb_server_kstat_init(smb_server_t *sv)
1199 {
1200 	(void) snprintf(sv->sv_ksp_name, sizeof (sv->sv_ksp_name), "%s%d",
1201 	    SMBSRV_KSTAT_NAME, sv->sv_zid);
1202 
1203 	sv->sv_ksp = kstat_create(SMBSRV_KSTAT_MODULE, 0, sv->sv_ksp_name,
1204 	    SMBSRV_KSTAT_CLASS, KSTAT_TYPE_NAMED,
1205 	    sizeof (sv->sv_ks_data) / sizeof (kstat_named_t),
1206 	    KSTAT_FLAG_VIRTUAL);
1207 
1208 	if (sv->sv_ksp) {
1209 		(void) strlcpy(sv->sv_ks_data.open_files.name, "open_files",
1210 		    sizeof (sv->sv_ks_data.open_files.name));
1211 		sv->sv_ks_data.open_files.data_type = KSTAT_DATA_UINT32;
1212 		(void) strlcpy(sv->sv_ks_data.open_trees.name, "connections",
1213 		    sizeof (sv->sv_ks_data.open_trees.name));
1214 		sv->sv_ks_data.open_trees.data_type = KSTAT_DATA_UINT32;
1215 		(void) strlcpy(sv->sv_ks_data.open_users.name, "sessions",
1216 		    sizeof (sv->sv_ks_data.open_users.name));
1217 		sv->sv_ks_data.open_users.data_type = KSTAT_DATA_UINT32;
1218 
1219 		mutex_init(&sv->sv_ksp_mutex, NULL, MUTEX_DEFAULT, NULL);
1220 		sv->sv_ksp->ks_lock = &sv->sv_ksp_mutex;
1221 		sv->sv_ksp->ks_data = (void *)&sv->sv_ks_data;
1222 		sv->sv_ksp->ks_update = smb_server_kstat_update_info;
1223 		kstat_install(sv->sv_ksp);
1224 	}
1225 
1226 	/* create and initialize smb kstats - smb_dispatch stats */
1227 	smb_dispatch_kstat_init();
1228 
1229 	return (0);
1230 }
1231 
1232 /*
1233  * smb_server_kstat_fini
1234  */
1235 static void
1236 smb_server_kstat_fini(smb_server_t *sv)
1237 {
1238 	if (sv->sv_ksp) {
1239 		kstat_delete(sv->sv_ksp);
1240 		mutex_destroy(&sv->sv_ksp_mutex);
1241 		sv->sv_ksp = NULL;
1242 	}
1243 	smb_dispatch_kstat_fini();
1244 }
1245 
1246 /* ARGSUSED */
1247 static int
1248 smb_server_kstat_update_info(kstat_t *ksp, int rw)
1249 {
1250 	smb_server_t	*sv;
1251 
1252 	if (rw == KSTAT_WRITE) {
1253 		return (EACCES);
1254 	} else {
1255 		ASSERT(MUTEX_HELD(ksp->ks_lock));
1256 
1257 		_NOTE(LINTED("pointer cast may result in improper alignment"))
1258 		sv = (smb_server_t *)((uint8_t *)(ksp->ks_data) -
1259 		    offsetof(smb_server_t, sv_ks_data));
1260 
1261 		ASSERT(sv->sv_magic == SMB_SERVER_MAGIC);
1262 
1263 		sv->sv_ks_data.open_files.value.ui32 = sv->sv_open_files;
1264 		sv->sv_ks_data.open_trees.value.ui32 = sv->sv_open_trees;
1265 		sv->sv_ks_data.open_users.value.ui32 = sv->sv_open_users;
1266 	}
1267 	return (0);
1268 }
1269 
1270 /*
1271  * smb_server_stop
1272  *
1273  * The mutex of the server must have been entered before calling this function.
1274  */
1275 static void
1276 smb_server_stop(smb_server_t *sv)
1277 {
1278 	ASSERT(sv->sv_magic == SMB_SERVER_MAGIC);
1279 
1280 	smb_opipe_door_close();
1281 	smb_thread_stop(&sv->si_thread_timers);
1282 	smb_thread_stop(&sv->si_thread_unexport);
1283 	smb_kdoor_clnt_close();
1284 	smb_kshare_fini(sv->sv_lmshrd);
1285 	sv->sv_lmshrd = NULL;
1286 	smb_server_fsop_stop(sv);
1287 
1288 	if (sv->sv_session) {
1289 		smb_session_delete(sv->sv_session);
1290 		sv->sv_session = NULL;
1291 	}
1292 
1293 	if (sv->sv_thread_pool) {
1294 		taskq_destroy(sv->sv_thread_pool);
1295 		sv->sv_thread_pool = NULL;
1296 	}
1297 }
1298 
1299 static int
1300 smb_server_listen(
1301     smb_server_t		*sv,
1302     smb_listener_daemon_t	*ld,
1303     in_port_t			port,
1304     int				family,
1305     int				pthread_create_error)
1306 {
1307 	int			rc;
1308 	ksocket_t		s_so;
1309 	const uint32_t		on = 1;
1310 	const uint32_t		off = 0;
1311 	smb_session_t		*session;
1312 
1313 	if (pthread_create_error) {
1314 		/*
1315 		 * Delete the last session created. The user space thread
1316 		 * creation failed.
1317 		 */
1318 		smb_session_list_delete_tail(&ld->ld_session_list);
1319 	}
1320 
1321 	if (ld->ld_so == NULL) {
1322 		/* First time listener */
1323 		if (family == AF_INET) {
1324 			ld->ld_sin.sin_family = (uint32_t)family;
1325 			ld->ld_sin.sin_port = htons(port);
1326 			ld->ld_sin.sin_addr.s_addr = htonl(INADDR_ANY);
1327 		} else {
1328 			ld->ld_sin6.sin6_family = (uint32_t)family;
1329 			ld->ld_sin6.sin6_port = htons(port);
1330 			(void) memset(&ld->ld_sin6.sin6_addr.s6_addr, 0,
1331 			    sizeof (ld->ld_sin6.sin6_addr.s6_addr));
1332 		}
1333 		ld->ld_so = smb_socreate(family, SOCK_STREAM, 0);
1334 		if (ld->ld_so) {
1335 
1336 			(void) ksocket_setsockopt(ld->ld_so, SOL_SOCKET,
1337 			    SO_MAC_EXEMPT, &off, sizeof (off), CRED());
1338 			(void) ksocket_setsockopt(ld->ld_so, SOL_SOCKET,
1339 			    SO_REUSEADDR, &on, sizeof (on), CRED());
1340 
1341 			if (family == AF_INET) {
1342 				rc = ksocket_bind(ld->ld_so,
1343 				    (struct sockaddr *)&ld->ld_sin,
1344 				    sizeof (ld->ld_sin), CRED());
1345 			} else {
1346 				rc = ksocket_bind(ld->ld_so,
1347 				    (struct sockaddr *)&ld->ld_sin6,
1348 				    sizeof (ld->ld_sin6), CRED());
1349 			}
1350 			if (rc == 0) {
1351 				rc =  ksocket_listen(ld->ld_so, 20, CRED());
1352 				if (rc < 0) {
1353 					cmn_err(CE_WARN,
1354 					    "Port %d: listen failed", port);
1355 					smb_soshutdown(ld->ld_so);
1356 					smb_sodestroy(ld->ld_so);
1357 					ld->ld_so = NULL;
1358 					return (rc);
1359 				}
1360 			} else {
1361 				cmn_err(CE_WARN,
1362 				    "Port %d: bind failed", port);
1363 				smb_soshutdown(ld->ld_so);
1364 				smb_sodestroy(ld->ld_so);
1365 				ld->ld_so = NULL;
1366 				return (rc);
1367 			}
1368 		} else {
1369 			cmn_err(CE_WARN,
1370 			    "Port %d: socket create failed", port);
1371 			return (ENOMEM);
1372 		}
1373 	}
1374 
1375 	DTRACE_PROBE1(so__wait__accept, struct sonode *, ld->ld_so);
1376 
1377 	for (;;) {
1378 		rc = ksocket_accept(ld->ld_so, NULL, NULL, &s_so, CRED());
1379 		if (rc == 0) {
1380 			uint32_t	txbuf_size = 128*1024;
1381 			uint32_t	on = 1;
1382 
1383 			DTRACE_PROBE1(so__accept, struct sonode *, s_so);
1384 
1385 			(void) ksocket_setsockopt(s_so, IPPROTO_TCP,
1386 			    TCP_NODELAY, &on, sizeof (on), CRED());
1387 			(void) ksocket_setsockopt(s_so, SOL_SOCKET,
1388 			    SO_KEEPALIVE, &on, sizeof (on), CRED());
1389 			(void) ksocket_setsockopt(s_so, SOL_SOCKET, SO_SNDBUF,
1390 			    (const void *)&txbuf_size, sizeof (txbuf_size),
1391 			    CRED());
1392 			/*
1393 			 * Create a session for this connection.
1394 			 */
1395 			session = smb_session_create(s_so, port, sv, family);
1396 			if (session) {
1397 				smb_session_list_append(&ld->ld_session_list,
1398 				    session);
1399 				break;
1400 			} else {
1401 				smb_soshutdown(s_so);
1402 				smb_sodestroy(s_so);
1403 			}
1404 			continue;
1405 		}
1406 		smb_session_list_signal(&ld->ld_session_list);
1407 		smb_soshutdown(ld->ld_so);
1408 		smb_sodestroy(ld->ld_so);
1409 		ld->ld_so = NULL;
1410 		break;
1411 	}
1412 
1413 	return (rc);
1414 }
1415 
1416 /*
1417  * smb_server_lookup
1418  *
1419  * This function tries to find the server associated with the zone of the
1420  * caller.
1421  */
1422 static int
1423 smb_server_lookup(smb_server_t **psv)
1424 {
1425 	zoneid_t	zid;
1426 	smb_server_t	*sv;
1427 
1428 	zid = getzoneid();
1429 
1430 	smb_llist_enter(&smb_servers, RW_READER);
1431 	sv = smb_llist_head(&smb_servers);
1432 	while (sv) {
1433 		ASSERT(sv->sv_magic == SMB_SERVER_MAGIC);
1434 		if (sv->sv_zid == zid) {
1435 			mutex_enter(&sv->sv_mutex);
1436 			if (sv->sv_state != SMB_SERVER_STATE_DELETING) {
1437 				sv->sv_refcnt++;
1438 				mutex_exit(&sv->sv_mutex);
1439 				smb_llist_exit(&smb_servers);
1440 				*psv = sv;
1441 				return (0);
1442 			}
1443 			mutex_exit(&sv->sv_mutex);
1444 			break;
1445 		}
1446 		sv = smb_llist_next(&smb_servers, sv);
1447 	}
1448 	smb_llist_exit(&smb_servers);
1449 	return (EPERM);
1450 }
1451 
1452 /*
1453  * smb_server_release
1454  *
1455  * This function decrements the reference count of the server and signals its
1456  * condition variable if the state of the server is SMB_SERVER_STATE_DELETING.
1457  */
1458 static void
1459 smb_server_release(smb_server_t *sv)
1460 {
1461 	ASSERT(sv->sv_magic == SMB_SERVER_MAGIC);
1462 
1463 	mutex_enter(&sv->sv_mutex);
1464 	ASSERT(sv->sv_refcnt);
1465 	sv->sv_refcnt--;
1466 	if ((sv->sv_refcnt == 0) && (sv->sv_state == SMB_SERVER_STATE_DELETING))
1467 		cv_signal(&sv->sv_cv);
1468 	mutex_exit(&sv->sv_mutex);
1469 }
1470 
1471 /*
1472  * Enumerate the users associated with a session list.
1473  */
1474 static void
1475 smb_server_enum_private(smb_session_list_t *se, smb_svcenum_t *svcenum)
1476 {
1477 	smb_session_t	*sn;
1478 	smb_llist_t	*ulist;
1479 	smb_user_t	*user;
1480 	int		rc = 0;
1481 
1482 	rw_enter(&se->se_lock, RW_READER);
1483 	sn = list_head(&se->se_act.lst);
1484 
1485 	while (sn != NULL) {
1486 		ASSERT(sn->s_magic == SMB_SESSION_MAGIC);
1487 		ulist = &sn->s_user_list;
1488 		smb_llist_enter(ulist, RW_READER);
1489 		user = smb_llist_head(ulist);
1490 
1491 		while (user != NULL) {
1492 			if (smb_user_hold(user)) {
1493 				rc = smb_user_enum(user, svcenum);
1494 				smb_user_release(user);
1495 			}
1496 
1497 			user = smb_llist_next(ulist, user);
1498 		}
1499 
1500 		smb_llist_exit(ulist);
1501 
1502 		if (rc != 0)
1503 			break;
1504 
1505 		sn = list_next(&se->se_act.lst, sn);
1506 	}
1507 
1508 	rw_exit(&se->se_lock);
1509 }
1510 
1511 /*
1512  * Disconnect sessions associated with the specified client and username.
1513  * Empty strings are treated as wildcards.
1514  */
1515 static int
1516 smb_server_sesion_disconnect(smb_session_list_t *se,
1517     const char *client, const char *name)
1518 {
1519 	smb_session_t	*sn;
1520 	smb_llist_t	*ulist;
1521 	smb_user_t	*user;
1522 	boolean_t	match;
1523 	int		count = 0;
1524 
1525 	rw_enter(&se->se_lock, RW_READER);
1526 	sn = list_head(&se->se_act.lst);
1527 
1528 	while (sn != NULL) {
1529 		ASSERT(sn->s_magic == SMB_SESSION_MAGIC);
1530 
1531 		if ((*client != '\0') && (!smb_session_isclient(sn, client))) {
1532 			sn = list_next(&se->se_act.lst, sn);
1533 			continue;
1534 		}
1535 
1536 		ulist = &sn->s_user_list;
1537 		smb_llist_enter(ulist, RW_READER);
1538 		user = smb_llist_head(ulist);
1539 
1540 		while (user != NULL) {
1541 			if (smb_user_hold(user)) {
1542 				match = (*name == '\0');
1543 				if (!match)
1544 					match = smb_user_namecmp(user, name);
1545 
1546 				if (match) {
1547 					smb_llist_exit(ulist);
1548 					smb_user_logoff(user);
1549 					++count;
1550 					smb_user_release(user);
1551 					smb_llist_enter(ulist, RW_READER);
1552 					user = smb_llist_head(ulist);
1553 					continue;
1554 				}
1555 
1556 				smb_user_release(user);
1557 			}
1558 
1559 			user = smb_llist_next(ulist, user);
1560 		}
1561 
1562 		smb_llist_exit(ulist);
1563 		sn = list_next(&se->se_act.lst, sn);
1564 	}
1565 
1566 	rw_exit(&se->se_lock);
1567 	return (count);
1568 }
1569 
1570 /*
1571  * Close a file by its unique id.
1572  */
1573 static int
1574 smb_server_fclose(smb_session_list_t *se, uint32_t uniqid)
1575 {
1576 	smb_session_t	*sn;
1577 	smb_llist_t	*ulist;
1578 	smb_user_t	*user;
1579 	int		rc = ENOENT;
1580 
1581 	rw_enter(&se->se_lock, RW_READER);
1582 	sn = list_head(&se->se_act.lst);
1583 
1584 	while ((sn != NULL) && (rc == ENOENT)) {
1585 		ASSERT(sn->s_magic == SMB_SESSION_MAGIC);
1586 		ulist = &sn->s_user_list;
1587 		smb_llist_enter(ulist, RW_READER);
1588 		user = smb_llist_head(ulist);
1589 
1590 		while ((user != NULL) && (rc == ENOENT)) {
1591 			if (smb_user_hold(user)) {
1592 				rc = smb_user_fclose(user, uniqid);
1593 				smb_user_release(user);
1594 			}
1595 
1596 			user = smb_llist_next(ulist, user);
1597 		}
1598 
1599 		smb_llist_exit(ulist);
1600 		sn = list_next(&se->se_act.lst, sn);
1601 	}
1602 
1603 	rw_exit(&se->se_lock);
1604 	return (rc);
1605 }
1606 
1607 static void
1608 smb_server_store_cfg(smb_server_t *sv, smb_ioc_cfg_t *ioc)
1609 {
1610 	if (ioc->maxconnections == 0)
1611 		ioc->maxconnections = 0xFFFFFFFF;
1612 
1613 	smb_session_correct_keep_alive_values(
1614 	    &sv->sv_nbt_daemon.ld_session_list, ioc->keepalive);
1615 	smb_session_correct_keep_alive_values(
1616 	    &sv->sv_tcp_daemon.ld_session_list, ioc->keepalive);
1617 
1618 	sv->sv_cfg.skc_maxworkers = ioc->maxworkers;
1619 	sv->sv_cfg.skc_maxconnections = ioc->maxconnections;
1620 	sv->sv_cfg.skc_keepalive = ioc->keepalive;
1621 	sv->sv_cfg.skc_restrict_anon = ioc->restrict_anon;
1622 	sv->sv_cfg.skc_signing_enable = ioc->signing_enable;
1623 	sv->sv_cfg.skc_signing_required = ioc->signing_required;
1624 	sv->sv_cfg.skc_oplock_enable = ioc->oplock_enable;
1625 	sv->sv_cfg.skc_sync_enable = ioc->sync_enable;
1626 	sv->sv_cfg.skc_secmode = ioc->secmode;
1627 	sv->sv_cfg.skc_ipv6_enable = ioc->ipv6_enable;
1628 	(void) strlcpy(sv->sv_cfg.skc_nbdomain, ioc->nbdomain,
1629 	    sizeof (sv->sv_cfg.skc_nbdomain));
1630 	(void) strlcpy(sv->sv_cfg.skc_fqdn, ioc->fqdn,
1631 	    sizeof (sv->sv_cfg.skc_fqdn));
1632 	(void) strlcpy(sv->sv_cfg.skc_hostname, ioc->hostname,
1633 	    sizeof (sv->sv_cfg.skc_hostname));
1634 	(void) strlcpy(sv->sv_cfg.skc_system_comment, ioc->system_comment,
1635 	    sizeof (sv->sv_cfg.skc_system_comment));
1636 }
1637 
1638 static int
1639 smb_server_fsop_start(smb_server_t *sv)
1640 {
1641 	int	error;
1642 
1643 	error = smb_node_root_init(rootdir, sv, &sv->si_root_smb_node);
1644 	if (error != 0)
1645 		sv->si_root_smb_node = NULL;
1646 
1647 	return (error);
1648 }
1649 
1650 static void
1651 smb_server_fsop_stop(smb_server_t *sv)
1652 {
1653 	if (sv->si_root_smb_node != NULL) {
1654 		smb_vfs_rele_all(sv);
1655 		smb_node_release(sv->si_root_smb_node);
1656 		sv->si_root_smb_node = NULL;
1657 	}
1658 }
1659