xref: /onnv-gate/usr/src/uts/common/fs/smbsrv/smb_server.c (revision 11963:061945695ce1)
16139Sjb150015 /*
26139Sjb150015  * CDDL HEADER START
36139Sjb150015  *
46139Sjb150015  * The contents of this file are subject to the terms of the
56139Sjb150015  * Common Development and Distribution License (the "License").
66139Sjb150015  * You may not use this file except in compliance with the License.
76139Sjb150015  *
86139Sjb150015  * You can obtain a copy of the license at usr/src/OPENSOLARIS.LICENSE
96139Sjb150015  * or http://www.opensolaris.org/os/licensing.
106139Sjb150015  * See the License for the specific language governing permissions
116139Sjb150015  * and limitations under the License.
126139Sjb150015  *
136139Sjb150015  * When distributing Covered Code, include this CDDL HEADER in each
146139Sjb150015  * file and include the License file at usr/src/OPENSOLARIS.LICENSE.
156139Sjb150015  * If applicable, add the following below this CDDL HEADER, with the
166139Sjb150015  * fields enclosed by brackets "[]" replaced with your own identifying
176139Sjb150015  * information: Portions Copyright [yyyy] [name of copyright owner]
186139Sjb150015  *
196139Sjb150015  * CDDL HEADER END
206139Sjb150015  */
216139Sjb150015 /*
22*11963SAfshin.Ardakani@Sun.COM  * Copyright 2010 Sun Microsystems, Inc.  All rights reserved.
236139Sjb150015  * Use is subject to license terms.
246139Sjb150015  */
256139Sjb150015 
266139Sjb150015 /*
276139Sjb150015  * General Structures Layout
286139Sjb150015  * -------------------------
296139Sjb150015  *
306139Sjb150015  * This is a simplified diagram showing the relationship between most of the
316139Sjb150015  * main structures.
326139Sjb150015  *
336139Sjb150015  * +-------------------+
346139Sjb150015  * |     SMB_SERVER    |
356139Sjb150015  * +-------------------+
366139Sjb150015  *          |
376139Sjb150015  *          |
386139Sjb150015  *          v
396139Sjb150015  * +-------------------+       +-------------------+      +-------------------+
406139Sjb150015  * |     SESSION       |<----->|     SESSION       |......|      SESSION      |
416139Sjb150015  * +-------------------+       +-------------------+      +-------------------+
426139Sjb150015  *          |
436139Sjb150015  *          |
446139Sjb150015  *          v
456139Sjb150015  * +-------------------+       +-------------------+      +-------------------+
466139Sjb150015  * |       USER        |<----->|       USER        |......|       USER        |
476139Sjb150015  * +-------------------+       +-------------------+      +-------------------+
486139Sjb150015  *          |
496139Sjb150015  *          |
506139Sjb150015  *          v
516139Sjb150015  * +-------------------+       +-------------------+      +-------------------+
526139Sjb150015  * |       TREE        |<----->|       TREE        |......|       TREE        |
536139Sjb150015  * +-------------------+       +-------------------+      +-------------------+
546139Sjb150015  *      |         |
556139Sjb150015  *      |         |
566139Sjb150015  *      |         v
576139Sjb150015  *      |     +-------+       +-------+      +-------+
586139Sjb150015  *      |     | OFILE |<----->| OFILE |......| OFILE |
596139Sjb150015  *      |     +-------+       +-------+      +-------+
606139Sjb150015  *      |
616139Sjb150015  *      |
626139Sjb150015  *      v
636139Sjb150015  *  +-------+       +------+      +------+
646139Sjb150015  *  | ODIR  |<----->| ODIR |......| ODIR |
656139Sjb150015  *  +-------+       +------+      +------+
666139Sjb150015  *
676139Sjb150015  *
686139Sjb150015  * Module Interface Overview
696139Sjb150015  * -------------------------
706139Sjb150015  *
716139Sjb150015  *
726139Sjb150015  *	    +===================================+
736139Sjb150015  *	    |		 smbd daemon		|
746139Sjb150015  *	    +===================================+
756139Sjb150015  *	      |		     |		      ^
766139Sjb150015  *	      |		     |		      |
776139Sjb150015  * User	      |		     |		      |
786139Sjb150015  * -----------|--------------|----------------|--------------------------------
796139Sjb150015  * Kernel     |		     |		      |
806139Sjb150015  *            |		     |		      |
816139Sjb150015  *	      |		     |		      |
826139Sjb150015  *  +=========|==============|================|=================+
836139Sjb150015  *  |	      v		     v		      |			|
846139Sjb150015  *  | +-----------+ +--------------------+ +------------------+ |
856139Sjb150015  *  | |     IO    | | Kernel Door Server | | User Door Servers|	|
866139Sjb150015  *  | | Interface | |     Interface      | |   Interface      | |
876139Sjb150015  *  | +-----------+ +--------------------+ +------------------+ |
886139Sjb150015  *  |		|	     |		      ^		^	|
896139Sjb150015  *  |		v	     v		      |		|	|    +=========+
906139Sjb150015  *  |	     +-----------------------------------+	|	|    |	       |
916139Sjb150015  *  |	     + SMB Server Management (this file) |<------------------|	 ZFS   |
926139Sjb150015  *  |	     +-----------------------------------+	|	|    |	       |
936139Sjb150015  *  |							|	|    |  Module |
946139Sjb150015  *  |	     +-----------------------------------+	|	|    |	       |
956139Sjb150015  *  |	     +     SMB Server Internal Layers    |------+	|    +=========+
966139Sjb150015  *  |	     +-----------------------------------+		|
976139Sjb150015  *  |								|
986139Sjb150015  *  |								|
996139Sjb150015  *  +===========================================================+
1006139Sjb150015  *
1016139Sjb150015  *
1026139Sjb150015  * Server State Machine
1036139Sjb150015  * --------------------
1046139Sjb150015  *                                  |
1056139Sjb150015  *                                  | T0
1066139Sjb150015  *                                  |
1076139Sjb150015  *                                  v
1086139Sjb150015  *                    +-----------------------------+
1096139Sjb150015  *		      |   SMB_SERVER_STATE_CREATED  |
1106139Sjb150015  *		      +-----------------------------+
1116139Sjb150015  *				    |
1126139Sjb150015  *				    | T1
1136139Sjb150015  *				    |
1146139Sjb150015  *				    v
1156139Sjb150015  *		      +-----------------------------+
1166139Sjb150015  *		      | SMB_SERVER_STATE_CONFIGURED |
1176139Sjb150015  *		      +-----------------------------+
1186139Sjb150015  *				    |
1196139Sjb150015  *				    | T2
1206139Sjb150015  *				    |
1216139Sjb150015  *				    v
1226139Sjb150015  *		      +-----------------------------+
123*11963SAfshin.Ardakani@Sun.COM  *		      |  SMB_SERVER_STATE_RUNNING / |
124*11963SAfshin.Ardakani@Sun.COM  *		      |  SMB_SERVER_STATE_STOPPING  |
1256139Sjb150015  *		      +-----------------------------+
1266139Sjb150015  *				    |
1276139Sjb150015  *				    | T3
1286139Sjb150015  *				    |
1296139Sjb150015  *				    v
1306139Sjb150015  *		      +-----------------------------+
1316139Sjb150015  *		      |  SMB_SERVER_STATE_DELETING  |
1326139Sjb150015  *                    +-----------------------------+
1336139Sjb150015  *				    |
1346139Sjb150015  *				    |
1356139Sjb150015  *				    |
1366139Sjb150015  *				    v
1376139Sjb150015  *
1386139Sjb150015  * States
1396139Sjb150015  * ------
1406139Sjb150015  *
1416139Sjb150015  * SMB_SERVER_STATE_CREATED
1426139Sjb150015  *
1436139Sjb150015  *    This is the state of the server just after creation.
1446139Sjb150015  *
1456139Sjb150015  * SMB_SERVER_STATE_CONFIGURED
1466139Sjb150015  *
1476139Sjb150015  *    The server has been configured.
1486139Sjb150015  *
1496139Sjb150015  * SMB_SERVER_STATE_RUNNING
1506139Sjb150015  *
1516139Sjb150015  *    The server has been started. While in this state the threads listening on
1526139Sjb150015  *    the sockets car be started. The smbd daemon does so through an Ioctl:
1536139Sjb150015  *
1546139Sjb150015  *	smb_drv_ioctl(SMB_IOC_NBT_LISTEN) --> smb_server_nbt_listen()
1556139Sjb150015  *	smb_drv_ioctl(SMB_IOC_TCP_LISTEN) --> smb_server_nbt_listen()
1566139Sjb150015  *
1576139Sjb150015  *    When a client establishes a connection the thread listening leaves
1586139Sjb150015  *    temporarily the kernel. While in user space it creates a thread for the
1596139Sjb150015  *    new session. It then returns to kernel with the result of the thread
1606139Sjb150015  *    creation. If the creation failed the new session context is destroyed
1616139Sjb150015  *    before returning listening.
1626139Sjb150015  *
1636139Sjb150015  *    The new created thread enters the kernel though an Ioctl:
1646139Sjb150015  *
1656139Sjb150015  *	smb_drv_ioctl(SMB_IOC_NBT_RECEIVE) --> smb_server_nbt_receive()
1666139Sjb150015  *	smb_drv_ioctl(SMB_IOC_TCP_RECEIVE) --> smb_server_tcp_receive()
1676139Sjb150015  *
1686139Sjb150015  * SMB_SERVER_STATE_STOPPING
1696139Sjb150015  *
1706139Sjb150015  *    The threads listening on the NBT and TCP sockets are being terminated.
1716139Sjb150015  *
1726139Sjb150015  *
1736139Sjb150015  * Transitions
1746139Sjb150015  * -----------
1756139Sjb150015  *
1766139Sjb150015  * Transition T0
1776139Sjb150015  *
1786139Sjb150015  *    The daemon smbd triggers its creation by opening the smbsrv device. If
1796139Sjb150015  *    the zone where the daemon lives doesn't have an smb server yet it is
1806139Sjb150015  *    created.
1816139Sjb150015  *
1826139Sjb150015  *		smb_drv_open() --> smb_server_create()
1836139Sjb150015  *
1846139Sjb150015  * Transition T1
1856139Sjb150015  *
1866139Sjb150015  *    This transition occurs in smb_server_configure(). It is triggered by the
1876139Sjb150015  *    daemon through an Ioctl.
1886139Sjb150015  *
1896139Sjb150015  *	smb_drv_ioctl(SMB_IOC_CONFIG) --> smb_server_configure()
1906139Sjb150015  *
1916139Sjb150015  * Transition T2
1926139Sjb150015  *
1936139Sjb150015  *    This transition occurs in smb_server_start(). It is triggered by the
1946139Sjb150015  *    daemon through an Ioctl.
1956139Sjb150015  *
1966139Sjb150015  *	smb_drv_ioctl(SMB_IOC_START) --> smb_server_start()
1976139Sjb150015  *
1986139Sjb150015  * Transition T3
1996139Sjb150015  *
2006139Sjb150015  *    This transition occurs in smb_server_delete(). It is triggered by the
2016139Sjb150015  *    daemon when closing the smbsrv device
2026139Sjb150015  *
2036139Sjb150015  *		smb_drv_close() --> smb_server_delete()
2046139Sjb150015  *
2056139Sjb150015  * Comments
2066139Sjb150015  * --------
2076139Sjb150015  *
2086139Sjb150015  * This files assumes that there will one SMB server per zone. For now the
2096139Sjb150015  * smb server works only in global zone. There's nothing in this file preventing
2106139Sjb150015  * an smb server from being created in a non global zone. That limitation is
2116139Sjb150015  * enforced in user space.
2126139Sjb150015  */
2136139Sjb150015 
2146139Sjb150015 #include <sys/strsubr.h>
2156139Sjb150015 #include <sys/cmn_err.h>
2166139Sjb150015 #include <sys/priv.h>
2176139Sjb150015 #include <sys/socketvar.h>
2186139Sjb150015 #include <sys/zone.h>
21910966SJordan.Brown@Sun.COM #include <netinet/in.h>
22010966SJordan.Brown@Sun.COM #include <netinet/in_systm.h>
22110966SJordan.Brown@Sun.COM #include <netinet/ip.h>
22210966SJordan.Brown@Sun.COM #include <netinet/ip_icmp.h>
22310966SJordan.Brown@Sun.COM #include <netinet/ip_var.h>
22410966SJordan.Brown@Sun.COM #include <netinet/tcp.h>
2256139Sjb150015 #include <smbsrv/smb_kproto.h>
22610966SJordan.Brown@Sun.COM #include <smbsrv/string.h>
2276139Sjb150015 #include <smbsrv/netbios.h>
2286139Sjb150015 #include <smbsrv/smb_fsops.h>
2297052Samw #include <smbsrv/smb_share.h>
230*11963SAfshin.Ardakani@Sun.COM #include <smbsrv/smb_door.h>
2316432Sas200622 #include <smbsrv/smb_kstat.h>
2326139Sjb150015 
233*11963SAfshin.Ardakani@Sun.COM #define	SMB_EVENT_TIMEOUT		45	/* seconds */
234*11963SAfshin.Ardakani@Sun.COM 
235*11963SAfshin.Ardakani@Sun.COM #define	SMB_REAPER_RATE_DEFAULT		4
236*11963SAfshin.Ardakani@Sun.COM 
2376139Sjb150015 extern void smb_dispatch_kstat_init(void);
2386139Sjb150015 extern void smb_dispatch_kstat_fini(void);
2396139Sjb150015 extern void smb_reply_notify_change_request(smb_request_t *);
2406139Sjb150015 
2416139Sjb150015 static int smb_server_kstat_init(smb_server_t *);
2426139Sjb150015 static void smb_server_kstat_fini(smb_server_t *);
2436139Sjb150015 static int smb_server_kstat_update_info(kstat_t *, int);
2446139Sjb150015 static void smb_server_timers(smb_thread_t *, void *);
2456139Sjb150015 static int smb_server_listen(smb_server_t *, smb_listener_daemon_t *,
2468670SJose.Borrego@Sun.COM     in_port_t, int, int);
247*11963SAfshin.Ardakani@Sun.COM static void smb_server_listen_fini(smb_listener_daemon_t *);
248*11963SAfshin.Ardakani@Sun.COM static kt_did_t smb_server_listener_tid(smb_listener_daemon_t *);
2496139Sjb150015 static int smb_server_lookup(smb_server_t **);
2506139Sjb150015 static void smb_server_release(smb_server_t *);
2519832Samw@Sun.COM static void smb_server_store_cfg(smb_server_t *, smb_ioc_cfg_t *);
252*11963SAfshin.Ardakani@Sun.COM static void smb_server_shutdown(smb_server_t *);
2536139Sjb150015 static int smb_server_fsop_start(smb_server_t *);
2546139Sjb150015 static void smb_server_fsop_stop(smb_server_t *);
255*11963SAfshin.Ardakani@Sun.COM static void smb_server_signal_listeners(smb_server_t *);
256*11963SAfshin.Ardakani@Sun.COM static void smb_event_cancel(smb_server_t *, uint32_t);
257*11963SAfshin.Ardakani@Sun.COM static void smb_event_notify(smb_server_t *, uint32_t);
258*11963SAfshin.Ardakani@Sun.COM static uint32_t smb_event_alloc_txid(void);
2596139Sjb150015 
260*11963SAfshin.Ardakani@Sun.COM static void smb_server_disconnect_share(smb_session_list_t *, const char *);
2617619SJose.Borrego@Sun.COM static void smb_server_thread_unexport(smb_thread_t *, void *);
26210122SJordan.Brown@Sun.COM static void smb_server_enum_private(smb_session_list_t *, smb_svcenum_t *);
26310122SJordan.Brown@Sun.COM static int smb_server_sesion_disconnect(smb_session_list_t *, const char *,
26410122SJordan.Brown@Sun.COM     const char *);
26510122SJordan.Brown@Sun.COM static int smb_server_fclose(smb_session_list_t *, uint32_t);
26610122SJordan.Brown@Sun.COM 
267*11963SAfshin.Ardakani@Sun.COM int smb_event_debug = 0;
268*11963SAfshin.Ardakani@Sun.COM 
2696139Sjb150015 static smb_llist_t	smb_servers;
2706139Sjb150015 
2716139Sjb150015 /*
2726139Sjb150015  * *****************************************************************************
2736139Sjb150015  * **************** Functions called from the device interface *****************
2746139Sjb150015  * *****************************************************************************
2756139Sjb150015  *
27610122SJordan.Brown@Sun.COM  * These functions typically have to determine the relevant smb server
27710122SJordan.Brown@Sun.COM  * to which the call applies.
2786139Sjb150015  */
2796139Sjb150015 
2806139Sjb150015 /*
2816139Sjb150015  * smb_server_svc_init
2826139Sjb150015  *
2837348SJose.Borrego@Sun.COM  * This function must be called from smb_drv_attach().
2846139Sjb150015  */
2856139Sjb150015 int
2866139Sjb150015 smb_server_svc_init(void)
2876139Sjb150015 {
2886139Sjb150015 	int	rc = 0;
2896139Sjb150015 
2906139Sjb150015 	while (rc == 0) {
2918934SJose.Borrego@Sun.COM 		if (rc = smb_mbc_init())
2928934SJose.Borrego@Sun.COM 			continue;
2936139Sjb150015 		if (rc = smb_vop_init())
2946139Sjb150015 			continue;
2956139Sjb150015 		if (rc = smb_node_init())
2966496Sjb150015 			continue;
2976139Sjb150015 		if (rc = smb_fem_init())
2986496Sjb150015 			continue;
2997348SJose.Borrego@Sun.COM 		if (rc = smb_user_init())
3007348SJose.Borrego@Sun.COM 			continue;
3016139Sjb150015 		if (rc = smb_notify_init())
3026496Sjb150015 			continue;
3036496Sjb150015 		if (rc = smb_net_init())
3046496Sjb150015 			continue;
305*11963SAfshin.Ardakani@Sun.COM 		smb_llist_init();
3066139Sjb150015 		smb_llist_constructor(&smb_servers, sizeof (smb_server_t),
3076139Sjb150015 		    offsetof(smb_server_t, sv_lnd));
3086139Sjb150015 		return (0);
3096139Sjb150015 	}
310*11963SAfshin.Ardakani@Sun.COM 
311*11963SAfshin.Ardakani@Sun.COM 	smb_llist_fini();
3126496Sjb150015 	smb_net_fini();
3136139Sjb150015 	smb_notify_fini();
3147348SJose.Borrego@Sun.COM 	smb_user_fini();
3156139Sjb150015 	smb_fem_fini();
3166139Sjb150015 	smb_node_fini();
3176139Sjb150015 	smb_vop_fini();
3188934SJose.Borrego@Sun.COM 	smb_mbc_fini();
3196139Sjb150015 	return (rc);
3206139Sjb150015 }
3216139Sjb150015 
3226139Sjb150015 /*
3236139Sjb150015  * smb_server_svc_fini
3246139Sjb150015  *
3256139Sjb150015  * This function must called from smb_drv_detach(). It will fail if servers
3266139Sjb150015  * still exist.
3276139Sjb150015  */
3286139Sjb150015 int
3296139Sjb150015 smb_server_svc_fini(void)
3306139Sjb150015 {
3316139Sjb150015 	int	rc = EBUSY;
3326139Sjb150015 
3336139Sjb150015 	if (smb_llist_get_count(&smb_servers) == 0) {
334*11963SAfshin.Ardakani@Sun.COM 		smb_llist_fini();
3356496Sjb150015 		smb_net_fini();
3366139Sjb150015 		smb_notify_fini();
3377348SJose.Borrego@Sun.COM 		smb_user_fini();
3386139Sjb150015 		smb_fem_fini();
3396139Sjb150015 		smb_node_fini();
3406139Sjb150015 		smb_vop_fini();
3418934SJose.Borrego@Sun.COM 		smb_mbc_fini();
3426139Sjb150015 		smb_llist_destructor(&smb_servers);
3436139Sjb150015 		rc = 0;
3446139Sjb150015 	}
3456139Sjb150015 	return (rc);
3466139Sjb150015 }
3476139Sjb150015 
3486139Sjb150015 /*
3496139Sjb150015  * smb_server_create
3506139Sjb150015  *
3516139Sjb150015  * This function will fail if there's already a server associated with the
3526139Sjb150015  * caller's zone.
3536139Sjb150015  */
3546139Sjb150015 int
3556139Sjb150015 smb_server_create(void)
3566139Sjb150015 {
3576139Sjb150015 	zoneid_t	zid;
3586139Sjb150015 	smb_server_t	*sv;
3596139Sjb150015 
3606139Sjb150015 	zid = getzoneid();
3616139Sjb150015 
3626139Sjb150015 	smb_llist_enter(&smb_servers, RW_WRITER);
3636139Sjb150015 	sv = smb_llist_head(&smb_servers);
3646139Sjb150015 	while (sv) {
365*11963SAfshin.Ardakani@Sun.COM 		SMB_SERVER_VALID(sv);
3666139Sjb150015 		if (sv->sv_zid == zid) {
3676139Sjb150015 			smb_llist_exit(&smb_servers);
3688167Samw@Sun.COM 			return (EPERM);
3696139Sjb150015 		}
3706139Sjb150015 		sv = smb_llist_next(&smb_servers, sv);
3716139Sjb150015 	}
3726139Sjb150015 
3736139Sjb150015 	sv = kmem_zalloc(sizeof (smb_server_t), KM_NOSLEEP);
3746139Sjb150015 	if (sv == NULL) {
3756139Sjb150015 		smb_llist_exit(&smb_servers);
3766139Sjb150015 		return (ENOMEM);
3776139Sjb150015 	}
3786139Sjb150015 
3796139Sjb150015 	smb_llist_constructor(&sv->sv_vfs_list, sizeof (smb_vfs_t),
3806139Sjb150015 	    offsetof(smb_vfs_t, sv_lnd));
3816139Sjb150015 
382*11963SAfshin.Ardakani@Sun.COM 	smb_llist_constructor(&sv->sv_opipe_list, sizeof (smb_opipe_t),
383*11963SAfshin.Ardakani@Sun.COM 	    offsetof(smb_opipe_t, p_lnd));
384*11963SAfshin.Ardakani@Sun.COM 
385*11963SAfshin.Ardakani@Sun.COM 	smb_llist_constructor(&sv->sv_event_list, sizeof (smb_event_t),
386*11963SAfshin.Ardakani@Sun.COM 	    offsetof(smb_event_t, se_lnd));
387*11963SAfshin.Ardakani@Sun.COM 
3887619SJose.Borrego@Sun.COM 	smb_slist_constructor(&sv->sv_unexport_list, sizeof (smb_unexport_t),
3897619SJose.Borrego@Sun.COM 	    offsetof(smb_unexport_t, ux_lnd));
3907619SJose.Borrego@Sun.COM 
3916139Sjb150015 	smb_session_list_constructor(&sv->sv_nbt_daemon.ld_session_list);
3926139Sjb150015 	smb_session_list_constructor(&sv->sv_tcp_daemon.ld_session_list);
3936139Sjb150015 
3947619SJose.Borrego@Sun.COM 	sv->si_cache_unexport = kmem_cache_create("smb_unexport_cache",
3957619SJose.Borrego@Sun.COM 	    sizeof (smb_unexport_t), 8, NULL, NULL, NULL, NULL, NULL, 0);
3966139Sjb150015 	sv->si_cache_vfs = kmem_cache_create("smb_vfs_cache",
3976139Sjb150015 	    sizeof (smb_vfs_t), 8, NULL, NULL, NULL, NULL, NULL, 0);
3986139Sjb150015 	sv->si_cache_request = kmem_cache_create("smb_request_cache",
3996139Sjb150015 	    sizeof (smb_request_t), 8, NULL, NULL, NULL, NULL, NULL, 0);
4006139Sjb150015 	sv->si_cache_session = kmem_cache_create("smb_session_cache",
4016139Sjb150015 	    sizeof (smb_session_t), 8, NULL, NULL, NULL, NULL, NULL, 0);
4026139Sjb150015 	sv->si_cache_user = kmem_cache_create("smb_user_cache",
4036139Sjb150015 	    sizeof (smb_user_t), 8, NULL, NULL, NULL, NULL, NULL, 0);
4046139Sjb150015 	sv->si_cache_tree = kmem_cache_create("smb_tree_cache",
4056139Sjb150015 	    sizeof (smb_tree_t), 8, NULL, NULL, NULL, NULL, NULL, 0);
4066139Sjb150015 	sv->si_cache_ofile = kmem_cache_create("smb_ofile_cache",
4076139Sjb150015 	    sizeof (smb_ofile_t), 8, NULL, NULL, NULL, NULL, NULL, 0);
4086139Sjb150015 	sv->si_cache_odir = kmem_cache_create("smb_odir_cache",
4096139Sjb150015 	    sizeof (smb_odir_t), 8, NULL, NULL, NULL, NULL, NULL, 0);
410*11963SAfshin.Ardakani@Sun.COM 	sv->si_cache_opipe = kmem_cache_create("smb_opipe_cache",
411*11963SAfshin.Ardakani@Sun.COM 	    sizeof (smb_opipe_t), 8, NULL, NULL, NULL, NULL, NULL, 0);
412*11963SAfshin.Ardakani@Sun.COM 	sv->si_cache_event = kmem_cache_create("smb_event_cache",
413*11963SAfshin.Ardakani@Sun.COM 	    sizeof (smb_event_t), 8, NULL, NULL, NULL, NULL, NULL, 0);
4146139Sjb150015 
4156139Sjb150015 	smb_thread_init(&sv->si_thread_timers,
4166139Sjb150015 	    "smb_timers", smb_server_timers, sv,
4176139Sjb150015 	    NULL, NULL);
4186139Sjb150015 
4197619SJose.Borrego@Sun.COM 	smb_thread_init(&sv->si_thread_unexport, "smb_thread_unexport",
4207619SJose.Borrego@Sun.COM 	    smb_server_thread_unexport, sv, NULL, NULL);
4217619SJose.Borrego@Sun.COM 
4226432Sas200622 	sv->sv_pid = curproc->p_pid;
4236139Sjb150015 
424*11963SAfshin.Ardakani@Sun.COM 	smb_kdoor_init();
4257052Samw 	smb_opipe_door_init();
4266139Sjb150015 	(void) smb_server_kstat_init(sv);
4276139Sjb150015 
4286139Sjb150015 	mutex_init(&sv->sv_mutex, NULL, MUTEX_DEFAULT, NULL);
4296139Sjb150015 	cv_init(&sv->sv_cv, NULL, CV_DEFAULT, NULL);
4306139Sjb150015 	sv->sv_state = SMB_SERVER_STATE_CREATED;
4316139Sjb150015 	sv->sv_magic = SMB_SERVER_MAGIC;
4326139Sjb150015 	sv->sv_zid = zid;
4336139Sjb150015 
4346139Sjb150015 	smb_llist_insert_tail(&smb_servers, sv);
4356139Sjb150015 	smb_llist_exit(&smb_servers);
4366139Sjb150015 	return (0);
4376139Sjb150015 }
4386139Sjb150015 
4396139Sjb150015 /*
4406139Sjb150015  * smb_server_delete
4416139Sjb150015  *
4426139Sjb150015  * This function will delete the server passed in. It will make sure that all
4436139Sjb150015  * activity associated that server has ceased before destroying it.
4446139Sjb150015  */
4456139Sjb150015 int
4466139Sjb150015 smb_server_delete(void)
4476139Sjb150015 {
4486139Sjb150015 	smb_server_t	*sv;
4497619SJose.Borrego@Sun.COM 	smb_unexport_t	*ux;
450*11963SAfshin.Ardakani@Sun.COM 	kt_did_t	nbt_tid;
451*11963SAfshin.Ardakani@Sun.COM 	kt_did_t	tcp_tid;
4526139Sjb150015 	int		rc;
4536139Sjb150015 
4546139Sjb150015 	rc = smb_server_lookup(&sv);
4556139Sjb150015 	if (rc != 0)
4566139Sjb150015 		return (rc);
4576139Sjb150015 
4586139Sjb150015 	mutex_enter(&sv->sv_mutex);
4596139Sjb150015 	switch (sv->sv_state) {
4606139Sjb150015 	case SMB_SERVER_STATE_RUNNING:
461*11963SAfshin.Ardakani@Sun.COM 	case SMB_SERVER_STATE_STOPPING:
462*11963SAfshin.Ardakani@Sun.COM 		sv->sv_state = SMB_SERVER_STATE_STOPPING;
463*11963SAfshin.Ardakani@Sun.COM 		smb_server_signal_listeners(sv);
464*11963SAfshin.Ardakani@Sun.COM 		nbt_tid = smb_server_listener_tid(&sv->sv_nbt_daemon);
465*11963SAfshin.Ardakani@Sun.COM 		tcp_tid = smb_server_listener_tid(&sv->sv_tcp_daemon);
4666139Sjb150015 
4676139Sjb150015 		sv->sv_state = SMB_SERVER_STATE_DELETING;
4686139Sjb150015 		mutex_exit(&sv->sv_mutex);
469*11963SAfshin.Ardakani@Sun.COM 
470*11963SAfshin.Ardakani@Sun.COM 		if (nbt_tid != 0)
471*11963SAfshin.Ardakani@Sun.COM 			thread_join(nbt_tid);
472*11963SAfshin.Ardakani@Sun.COM 		if (tcp_tid != 0)
473*11963SAfshin.Ardakani@Sun.COM 			thread_join(tcp_tid);
474*11963SAfshin.Ardakani@Sun.COM 
475*11963SAfshin.Ardakani@Sun.COM 		smb_server_listen_fini(&sv->sv_nbt_daemon);
476*11963SAfshin.Ardakani@Sun.COM 		smb_server_listen_fini(&sv->sv_tcp_daemon);
4776139Sjb150015 		mutex_enter(&sv->sv_mutex);
4786139Sjb150015 		break;
4796139Sjb150015 	case SMB_SERVER_STATE_CONFIGURED:
4806139Sjb150015 	case SMB_SERVER_STATE_CREATED:
4816139Sjb150015 		sv->sv_state = SMB_SERVER_STATE_DELETING;
4826139Sjb150015 		break;
4836139Sjb150015 	default:
484*11963SAfshin.Ardakani@Sun.COM 		SMB_SERVER_STATE_VALID(sv->sv_state);
4856139Sjb150015 		mutex_exit(&sv->sv_mutex);
4866139Sjb150015 		smb_server_release(sv);
4876139Sjb150015 		return (ENOTTY);
4886139Sjb150015 	}
4896139Sjb150015 
4906139Sjb150015 	ASSERT(sv->sv_state == SMB_SERVER_STATE_DELETING);
4916139Sjb150015 
4926139Sjb150015 	sv->sv_refcnt--;
4936139Sjb150015 	while (sv->sv_refcnt)
4946139Sjb150015 		cv_wait(&sv->sv_cv, &sv->sv_mutex);
4956139Sjb150015 
4966139Sjb150015 	mutex_exit(&sv->sv_mutex);
4976139Sjb150015 
4986139Sjb150015 	smb_llist_enter(&smb_servers, RW_WRITER);
4996139Sjb150015 	smb_llist_remove(&smb_servers, sv);
5006139Sjb150015 	smb_llist_exit(&smb_servers);
5016139Sjb150015 
502*11963SAfshin.Ardakani@Sun.COM 	smb_server_shutdown(sv);
5036139Sjb150015 	rw_destroy(&sv->sv_cfg_lock);
5047052Samw 	smb_opipe_door_fini();
505*11963SAfshin.Ardakani@Sun.COM 	smb_kdoor_fini();
5066139Sjb150015 	smb_server_kstat_fini(sv);
5076139Sjb150015 	smb_llist_destructor(&sv->sv_vfs_list);
508*11963SAfshin.Ardakani@Sun.COM 	smb_llist_destructor(&sv->sv_opipe_list);
509*11963SAfshin.Ardakani@Sun.COM 	smb_llist_destructor(&sv->sv_event_list);
5107619SJose.Borrego@Sun.COM 
5117619SJose.Borrego@Sun.COM 	while ((ux = list_head(&sv->sv_unexport_list.sl_list)) != NULL) {
5127619SJose.Borrego@Sun.COM 		smb_slist_remove(&sv->sv_unexport_list, ux);
5137619SJose.Borrego@Sun.COM 		kmem_cache_free(sv->si_cache_unexport, ux);
5147619SJose.Borrego@Sun.COM 	}
5157619SJose.Borrego@Sun.COM 	smb_slist_destructor(&sv->sv_unexport_list);
5167619SJose.Borrego@Sun.COM 
5177619SJose.Borrego@Sun.COM 	kmem_cache_destroy(sv->si_cache_unexport);
5186139Sjb150015 	kmem_cache_destroy(sv->si_cache_vfs);
5196139Sjb150015 	kmem_cache_destroy(sv->si_cache_request);
5206139Sjb150015 	kmem_cache_destroy(sv->si_cache_session);
5216139Sjb150015 	kmem_cache_destroy(sv->si_cache_user);
5226139Sjb150015 	kmem_cache_destroy(sv->si_cache_tree);
5236139Sjb150015 	kmem_cache_destroy(sv->si_cache_ofile);
5246139Sjb150015 	kmem_cache_destroy(sv->si_cache_odir);
525*11963SAfshin.Ardakani@Sun.COM 	kmem_cache_destroy(sv->si_cache_opipe);
526*11963SAfshin.Ardakani@Sun.COM 	kmem_cache_destroy(sv->si_cache_event);
5276139Sjb150015 
5286139Sjb150015 	smb_thread_destroy(&sv->si_thread_timers);
5297619SJose.Borrego@Sun.COM 	smb_thread_destroy(&sv->si_thread_unexport);
5306139Sjb150015 	mutex_destroy(&sv->sv_mutex);
5316139Sjb150015 	cv_destroy(&sv->sv_cv);
5326139Sjb150015 	sv->sv_magic = 0;
5336139Sjb150015 	kmem_free(sv, sizeof (smb_server_t));
5346139Sjb150015 
5356139Sjb150015 	return (0);
5366139Sjb150015 }
5376139Sjb150015 
5386139Sjb150015 /*
5396139Sjb150015  * smb_server_configure
5406139Sjb150015  */
5416139Sjb150015 int
5429832Samw@Sun.COM smb_server_configure(smb_ioc_cfg_t *ioc)
5436139Sjb150015 {
5446139Sjb150015 	int		rc = 0;
5456139Sjb150015 	smb_server_t	*sv;
5466139Sjb150015 
5476139Sjb150015 	rc = smb_server_lookup(&sv);
5486139Sjb150015 	if (rc)
5496139Sjb150015 		return (rc);
5506139Sjb150015 
5516139Sjb150015 	mutex_enter(&sv->sv_mutex);
5526139Sjb150015 	switch (sv->sv_state) {
5536139Sjb150015 	case SMB_SERVER_STATE_CREATED:
5549832Samw@Sun.COM 		smb_server_store_cfg(sv, ioc);
5556139Sjb150015 		sv->sv_state = SMB_SERVER_STATE_CONFIGURED;
5566139Sjb150015 		break;
5576139Sjb150015 
5586139Sjb150015 	case SMB_SERVER_STATE_CONFIGURED:
5599832Samw@Sun.COM 		smb_server_store_cfg(sv, ioc);
5606139Sjb150015 		break;
5616139Sjb150015 
5626139Sjb150015 	case SMB_SERVER_STATE_RUNNING:
563*11963SAfshin.Ardakani@Sun.COM 	case SMB_SERVER_STATE_STOPPING:
5646139Sjb150015 		rw_enter(&sv->sv_cfg_lock, RW_WRITER);
5659832Samw@Sun.COM 		smb_server_store_cfg(sv, ioc);
5666139Sjb150015 		rw_exit(&sv->sv_cfg_lock);
5676139Sjb150015 		break;
5686139Sjb150015 
5696139Sjb150015 	default:
570*11963SAfshin.Ardakani@Sun.COM 		SMB_SERVER_STATE_VALID(sv->sv_state);
5716139Sjb150015 		rc = EFAULT;
5726139Sjb150015 		break;
5736139Sjb150015 	}
5746139Sjb150015 	mutex_exit(&sv->sv_mutex);
5756139Sjb150015 
5766139Sjb150015 	smb_server_release(sv);
5776139Sjb150015 
5786139Sjb150015 	return (rc);
5796139Sjb150015 }
5806139Sjb150015 
5816139Sjb150015 /*
5826139Sjb150015  * smb_server_start
5836139Sjb150015  */
5846139Sjb150015 int
5859832Samw@Sun.COM smb_server_start(smb_ioc_start_t *ioc)
5866139Sjb150015 {
5876139Sjb150015 	int		rc = 0;
5886139Sjb150015 	smb_server_t	*sv;
5896139Sjb150015 
5906139Sjb150015 	rc = smb_server_lookup(&sv);
5916139Sjb150015 	if (rc)
5926139Sjb150015 		return (rc);
5936139Sjb150015 
5946139Sjb150015 	mutex_enter(&sv->sv_mutex);
5956139Sjb150015 	switch (sv->sv_state) {
5966139Sjb150015 	case SMB_SERVER_STATE_CONFIGURED:
59710966SJordan.Brown@Sun.COM 		smb_codepage_init();
5986139Sjb150015 
5996139Sjb150015 		sv->sv_thread_pool = taskq_create("smb_workers",
6006139Sjb150015 		    sv->sv_cfg.skc_maxworkers, SMB_WORKER_PRIORITY,
6016139Sjb150015 		    sv->sv_cfg.skc_maxworkers, INT_MAX,
6026139Sjb150015 		    TASKQ_DYNAMIC|TASKQ_PREPOPULATE);
6036139Sjb150015 
6048670SJose.Borrego@Sun.COM 		sv->sv_session = smb_session_create(NULL, 0, sv, 0);
6057588Samw@Sun.COM 
6067588Samw@Sun.COM 		if (sv->sv_thread_pool == NULL || sv->sv_session == NULL) {
6076139Sjb150015 			rc = ENOMEM;
6086139Sjb150015 			break;
6096139Sjb150015 		}
6106139Sjb150015 
6116139Sjb150015 		if (rc = smb_server_fsop_start(sv))
6126139Sjb150015 			break;
6136139Sjb150015 		ASSERT(sv->sv_lmshrd == NULL);
6149832Samw@Sun.COM 		sv->sv_lmshrd = smb_kshare_init(ioc->lmshrd);
6156139Sjb150015 		if (sv->sv_lmshrd == NULL)
6166139Sjb150015 			break;
617*11963SAfshin.Ardakani@Sun.COM 		if (rc = smb_kdoor_open(ioc->udoor)) {
618*11963SAfshin.Ardakani@Sun.COM 			cmn_err(CE_WARN, "Cannot open smbd door");
6196139Sjb150015 			break;
620*11963SAfshin.Ardakani@Sun.COM 		}
621*11963SAfshin.Ardakani@Sun.COM 		if (rc = smb_opipe_door_open(ioc->opipe)) {
622*11963SAfshin.Ardakani@Sun.COM 			cmn_err(CE_WARN, "Cannot open opipe door");
623*11963SAfshin.Ardakani@Sun.COM 			break;
624*11963SAfshin.Ardakani@Sun.COM 		}
6256139Sjb150015 		if (rc = smb_thread_start(&sv->si_thread_timers))
6266139Sjb150015 			break;
6277619SJose.Borrego@Sun.COM 		if (rc = smb_thread_start(&sv->si_thread_unexport))
6287619SJose.Borrego@Sun.COM 			break;
6296139Sjb150015 		sv->sv_state = SMB_SERVER_STATE_RUNNING;
6306139Sjb150015 		mutex_exit(&sv->sv_mutex);
6316139Sjb150015 		smb_server_release(sv);
6326139Sjb150015 		return (0);
6336139Sjb150015 	default:
634*11963SAfshin.Ardakani@Sun.COM 		SMB_SERVER_STATE_VALID(sv->sv_state);
6356139Sjb150015 		mutex_exit(&sv->sv_mutex);
6366139Sjb150015 		smb_server_release(sv);
6376139Sjb150015 		return (ENOTTY);
6386139Sjb150015 	}
6396139Sjb150015 
640*11963SAfshin.Ardakani@Sun.COM 	smb_server_shutdown(sv);
6416139Sjb150015 	mutex_exit(&sv->sv_mutex);
6426139Sjb150015 	smb_server_release(sv);
6436139Sjb150015 	return (rc);
6446139Sjb150015 }
6456139Sjb150015 
6466139Sjb150015 /*
647*11963SAfshin.Ardakani@Sun.COM  * An smbd is shutting down.
648*11963SAfshin.Ardakani@Sun.COM  */
649*11963SAfshin.Ardakani@Sun.COM int
650*11963SAfshin.Ardakani@Sun.COM smb_server_stop(void)
651*11963SAfshin.Ardakani@Sun.COM {
652*11963SAfshin.Ardakani@Sun.COM 	smb_server_t	*sv;
653*11963SAfshin.Ardakani@Sun.COM 	int		rc;
654*11963SAfshin.Ardakani@Sun.COM 
655*11963SAfshin.Ardakani@Sun.COM 	if ((rc = smb_server_lookup(&sv)) != 0)
656*11963SAfshin.Ardakani@Sun.COM 		return (rc);
657*11963SAfshin.Ardakani@Sun.COM 
658*11963SAfshin.Ardakani@Sun.COM 	mutex_enter(&sv->sv_mutex);
659*11963SAfshin.Ardakani@Sun.COM 	switch (sv->sv_state) {
660*11963SAfshin.Ardakani@Sun.COM 	case SMB_SERVER_STATE_RUNNING:
661*11963SAfshin.Ardakani@Sun.COM 		sv->sv_state = SMB_SERVER_STATE_STOPPING;
662*11963SAfshin.Ardakani@Sun.COM 		smb_server_signal_listeners(sv);
663*11963SAfshin.Ardakani@Sun.COM 		break;
664*11963SAfshin.Ardakani@Sun.COM 	default:
665*11963SAfshin.Ardakani@Sun.COM 		SMB_SERVER_STATE_VALID(sv->sv_state);
666*11963SAfshin.Ardakani@Sun.COM 		break;
667*11963SAfshin.Ardakani@Sun.COM 	}
668*11963SAfshin.Ardakani@Sun.COM 	mutex_exit(&sv->sv_mutex);
669*11963SAfshin.Ardakani@Sun.COM 
670*11963SAfshin.Ardakani@Sun.COM 	smb_server_release(sv);
671*11963SAfshin.Ardakani@Sun.COM 	return (0);
672*11963SAfshin.Ardakani@Sun.COM }
673*11963SAfshin.Ardakani@Sun.COM 
674*11963SAfshin.Ardakani@Sun.COM boolean_t
675*11963SAfshin.Ardakani@Sun.COM smb_server_is_stopping(void)
676*11963SAfshin.Ardakani@Sun.COM {
677*11963SAfshin.Ardakani@Sun.COM 	smb_server_t	*sv;
678*11963SAfshin.Ardakani@Sun.COM 	boolean_t	status;
679*11963SAfshin.Ardakani@Sun.COM 
680*11963SAfshin.Ardakani@Sun.COM 	if (smb_server_lookup(&sv) != 0)
681*11963SAfshin.Ardakani@Sun.COM 		return (B_TRUE);
682*11963SAfshin.Ardakani@Sun.COM 
683*11963SAfshin.Ardakani@Sun.COM 	SMB_SERVER_VALID(sv);
684*11963SAfshin.Ardakani@Sun.COM 
685*11963SAfshin.Ardakani@Sun.COM 	mutex_enter(&sv->sv_mutex);
686*11963SAfshin.Ardakani@Sun.COM 
687*11963SAfshin.Ardakani@Sun.COM 	switch (sv->sv_state) {
688*11963SAfshin.Ardakani@Sun.COM 	case SMB_SERVER_STATE_STOPPING:
689*11963SAfshin.Ardakani@Sun.COM 	case SMB_SERVER_STATE_DELETING:
690*11963SAfshin.Ardakani@Sun.COM 		status = B_TRUE;
691*11963SAfshin.Ardakani@Sun.COM 		break;
692*11963SAfshin.Ardakani@Sun.COM 	default:
693*11963SAfshin.Ardakani@Sun.COM 		status = B_FALSE;
694*11963SAfshin.Ardakani@Sun.COM 		break;
695*11963SAfshin.Ardakani@Sun.COM 	}
696*11963SAfshin.Ardakani@Sun.COM 
697*11963SAfshin.Ardakani@Sun.COM 	mutex_exit(&sv->sv_mutex);
698*11963SAfshin.Ardakani@Sun.COM 	smb_server_release(sv);
699*11963SAfshin.Ardakani@Sun.COM 	return (status);
700*11963SAfshin.Ardakani@Sun.COM }
701*11963SAfshin.Ardakani@Sun.COM 
702*11963SAfshin.Ardakani@Sun.COM int
703*11963SAfshin.Ardakani@Sun.COM smb_server_cancel_event(uint32_t txid)
704*11963SAfshin.Ardakani@Sun.COM {
705*11963SAfshin.Ardakani@Sun.COM 	smb_server_t	*sv;
706*11963SAfshin.Ardakani@Sun.COM 	int		rc;
707*11963SAfshin.Ardakani@Sun.COM 
708*11963SAfshin.Ardakani@Sun.COM 	if ((rc = smb_server_lookup(&sv)) == 0) {
709*11963SAfshin.Ardakani@Sun.COM 		smb_event_cancel(sv, txid);
710*11963SAfshin.Ardakani@Sun.COM 		smb_server_release(sv);
711*11963SAfshin.Ardakani@Sun.COM 	}
712*11963SAfshin.Ardakani@Sun.COM 
713*11963SAfshin.Ardakani@Sun.COM 	return (rc);
714*11963SAfshin.Ardakani@Sun.COM }
715*11963SAfshin.Ardakani@Sun.COM 
716*11963SAfshin.Ardakani@Sun.COM int
717*11963SAfshin.Ardakani@Sun.COM smb_server_notify_event(smb_ioc_event_t *ioc)
718*11963SAfshin.Ardakani@Sun.COM {
719*11963SAfshin.Ardakani@Sun.COM 	smb_server_t	*sv;
720*11963SAfshin.Ardakani@Sun.COM 	int		rc;
721*11963SAfshin.Ardakani@Sun.COM 
722*11963SAfshin.Ardakani@Sun.COM 	if ((rc = smb_server_lookup(&sv)) == 0) {
723*11963SAfshin.Ardakani@Sun.COM 		smb_event_notify(sv, ioc->txid);
724*11963SAfshin.Ardakani@Sun.COM 		smb_server_release(sv);
725*11963SAfshin.Ardakani@Sun.COM 	}
726*11963SAfshin.Ardakani@Sun.COM 
727*11963SAfshin.Ardakani@Sun.COM 	return (rc);
728*11963SAfshin.Ardakani@Sun.COM }
729*11963SAfshin.Ardakani@Sun.COM 
730*11963SAfshin.Ardakani@Sun.COM /*
731*11963SAfshin.Ardakani@Sun.COM  * SMB-over-NetBIOS (port 139)
7326139Sjb150015  *
733*11963SAfshin.Ardakani@Sun.COM  * Traditional SMB service over NetBIOS, which requires that a NetBIOS
734*11963SAfshin.Ardakani@Sun.COM  * session be established.
7356139Sjb150015  */
7366139Sjb150015 int
7379832Samw@Sun.COM smb_server_nbt_listen(smb_ioc_listen_t *ioc)
7386139Sjb150015 {
7396139Sjb150015 	smb_server_t	*sv;
7406139Sjb150015 	int		rc;
7416139Sjb150015 
7426139Sjb150015 	rc = smb_server_lookup(&sv);
7436139Sjb150015 	if (rc)
7446139Sjb150015 		return (rc);
7456139Sjb150015 
7466139Sjb150015 	mutex_enter(&sv->sv_mutex);
7476139Sjb150015 	switch (sv->sv_state) {
7486139Sjb150015 	case SMB_SERVER_STATE_RUNNING:
7496139Sjb150015 		if ((sv->sv_nbt_daemon.ld_kth != NULL) &&
7506139Sjb150015 		    (sv->sv_nbt_daemon.ld_kth != curthread)) {
7516139Sjb150015 			mutex_exit(&sv->sv_mutex);
7529422SAfshin.Ardakani@Sun.COM 			smb_server_release(sv);
7536139Sjb150015 			return (EACCES);
7546139Sjb150015 		} else {
7556139Sjb150015 			sv->sv_nbt_daemon.ld_kth = curthread;
7566139Sjb150015 			sv->sv_nbt_daemon.ld_ktdid = curthread->t_did;
7576139Sjb150015 		}
7586139Sjb150015 		break;
759*11963SAfshin.Ardakani@Sun.COM 	case SMB_SERVER_STATE_STOPPING:
760*11963SAfshin.Ardakani@Sun.COM 		mutex_exit(&sv->sv_mutex);
761*11963SAfshin.Ardakani@Sun.COM 		smb_server_release(sv);
762*11963SAfshin.Ardakani@Sun.COM 		return (ECANCELED);
7636139Sjb150015 	default:
764*11963SAfshin.Ardakani@Sun.COM 		SMB_SERVER_STATE_VALID(sv->sv_state);
7656139Sjb150015 		mutex_exit(&sv->sv_mutex);
7666139Sjb150015 		smb_server_release(sv);
7676139Sjb150015 		return (EFAULT);
7686139Sjb150015 	}
7696139Sjb150015 	mutex_exit(&sv->sv_mutex);
7706139Sjb150015 
7718670SJose.Borrego@Sun.COM 	/*
7728670SJose.Borrego@Sun.COM 	 * netbios must be ipv4
7738670SJose.Borrego@Sun.COM 	 */
77410717Samw@Sun.COM 	rc = smb_server_listen(sv, &sv->sv_nbt_daemon, IPPORT_NETBIOS_SSN,
7759832Samw@Sun.COM 	    AF_INET, ioc->error);
7766139Sjb150015 
777*11963SAfshin.Ardakani@Sun.COM 	mutex_enter(&sv->sv_mutex);
778*11963SAfshin.Ardakani@Sun.COM 	sv->sv_nbt_daemon.ld_kth = NULL;
779*11963SAfshin.Ardakani@Sun.COM 
780*11963SAfshin.Ardakani@Sun.COM 	mutex_exit(&sv->sv_mutex);
7816139Sjb150015 
7826139Sjb150015 	smb_server_release(sv);
7836139Sjb150015 	return (rc);
7846139Sjb150015 }
7856139Sjb150015 
786*11963SAfshin.Ardakani@Sun.COM /*
787*11963SAfshin.Ardakani@Sun.COM  *  SMB-over-TCP (port 445)
788*11963SAfshin.Ardakani@Sun.COM  */
7896139Sjb150015 int
7909832Samw@Sun.COM smb_server_tcp_listen(smb_ioc_listen_t *ioc)
7916139Sjb150015 {
7926139Sjb150015 	smb_server_t	*sv;
7936139Sjb150015 	int		rc;
7946139Sjb150015 
7956139Sjb150015 	rc = smb_server_lookup(&sv);
7966139Sjb150015 	if (rc)
7976139Sjb150015 		return (rc);
7986139Sjb150015 
7996139Sjb150015 	mutex_enter(&sv->sv_mutex);
8006139Sjb150015 	switch (sv->sv_state) {
8016139Sjb150015 	case SMB_SERVER_STATE_RUNNING:
802*11963SAfshin.Ardakani@Sun.COM 		if ((sv->sv_tcp_daemon.ld_kth != NULL) &&
8036139Sjb150015 		    (sv->sv_tcp_daemon.ld_kth != curthread)) {
8046139Sjb150015 			mutex_exit(&sv->sv_mutex);
8059422SAfshin.Ardakani@Sun.COM 			smb_server_release(sv);
8066139Sjb150015 			return (EACCES);
8076139Sjb150015 		} else {
8086139Sjb150015 			sv->sv_tcp_daemon.ld_kth = curthread;
8096139Sjb150015 			sv->sv_tcp_daemon.ld_ktdid = curthread->t_did;
8106139Sjb150015 		}
8116139Sjb150015 		break;
812*11963SAfshin.Ardakani@Sun.COM 	case SMB_SERVER_STATE_STOPPING:
813*11963SAfshin.Ardakani@Sun.COM 		mutex_exit(&sv->sv_mutex);
814*11963SAfshin.Ardakani@Sun.COM 		smb_server_release(sv);
815*11963SAfshin.Ardakani@Sun.COM 		return (ECANCELED);
8166139Sjb150015 	default:
817*11963SAfshin.Ardakani@Sun.COM 		SMB_SERVER_STATE_VALID(sv->sv_state);
8186139Sjb150015 		mutex_exit(&sv->sv_mutex);
8199422SAfshin.Ardakani@Sun.COM 		smb_server_release(sv);
8206139Sjb150015 		return (EFAULT);
8216139Sjb150015 	}
8226139Sjb150015 	mutex_exit(&sv->sv_mutex);
8236139Sjb150015 
8248670SJose.Borrego@Sun.COM 	if (sv->sv_cfg.skc_ipv6_enable)
8258670SJose.Borrego@Sun.COM 		rc = smb_server_listen(sv, &sv->sv_tcp_daemon,
82610717Samw@Sun.COM 		    IPPORT_SMB, AF_INET6, ioc->error);
8278670SJose.Borrego@Sun.COM 	else
8288670SJose.Borrego@Sun.COM 		rc = smb_server_listen(sv, &sv->sv_tcp_daemon,
82910717Samw@Sun.COM 		    IPPORT_SMB, AF_INET, ioc->error);
830*11963SAfshin.Ardakani@Sun.COM 
831*11963SAfshin.Ardakani@Sun.COM 	mutex_enter(&sv->sv_mutex);
832*11963SAfshin.Ardakani@Sun.COM 	sv->sv_tcp_daemon.ld_kth = NULL;
833*11963SAfshin.Ardakani@Sun.COM 
834*11963SAfshin.Ardakani@Sun.COM 	mutex_exit(&sv->sv_mutex);
8356139Sjb150015 
8366139Sjb150015 	smb_server_release(sv);
8376139Sjb150015 	return (rc);
8386139Sjb150015 }
8396139Sjb150015 
8406139Sjb150015 /*
8416139Sjb150015  * smb_server_nbt_receive
8426139Sjb150015  */
8436139Sjb150015 int
8446139Sjb150015 smb_server_nbt_receive(void)
8456139Sjb150015 {
8466139Sjb150015 	int		rc;
8476139Sjb150015 	smb_server_t	*sv;
8486139Sjb150015 
8499422SAfshin.Ardakani@Sun.COM 	if ((rc = smb_server_lookup(&sv)) == 0) {
8509422SAfshin.Ardakani@Sun.COM 		rc = smb_session_daemon(&sv->sv_nbt_daemon.ld_session_list);
8519422SAfshin.Ardakani@Sun.COM 		smb_server_release(sv);
8529422SAfshin.Ardakani@Sun.COM 	}
8536139Sjb150015 
8546139Sjb150015 	return (rc);
8556139Sjb150015 }
8566139Sjb150015 
8576139Sjb150015 /*
8586139Sjb150015  * smb_server_tcp_receive
8596139Sjb150015  */
8606139Sjb150015 int
8616139Sjb150015 smb_server_tcp_receive(void)
8626139Sjb150015 {
8636139Sjb150015 	int		rc;
8646139Sjb150015 	smb_server_t	*sv;
8656139Sjb150015 
8669422SAfshin.Ardakani@Sun.COM 	if ((rc = smb_server_lookup(&sv)) == 0) {
8679422SAfshin.Ardakani@Sun.COM 		rc = smb_session_daemon(&sv->sv_tcp_daemon.ld_session_list);
8689422SAfshin.Ardakani@Sun.COM 		smb_server_release(sv);
8699422SAfshin.Ardakani@Sun.COM 	}
8706139Sjb150015 
8716139Sjb150015 	return (rc);
8726139Sjb150015 }
8736139Sjb150015 
8746139Sjb150015 int
8759832Samw@Sun.COM smb_server_set_gmtoff(smb_ioc_gmt_t *ioc)
8766139Sjb150015 {
8776139Sjb150015 	int		rc;
8786139Sjb150015 	smb_server_t	*sv;
8796139Sjb150015 
8809422SAfshin.Ardakani@Sun.COM 	if ((rc = smb_server_lookup(&sv)) == 0) {
8819832Samw@Sun.COM 		sv->si_gmtoff = ioc->offset;
8829422SAfshin.Ardakani@Sun.COM 		smb_server_release(sv);
8839422SAfshin.Ardakani@Sun.COM 	}
8846139Sjb150015 
8856139Sjb150015 	return (rc);
8866139Sjb150015 }
8876139Sjb150015 
8889832Samw@Sun.COM int
88910122SJordan.Brown@Sun.COM smb_server_numopen(smb_ioc_opennum_t *ioc)
8909832Samw@Sun.COM {
8919832Samw@Sun.COM 	smb_server_t	*sv;
8929832Samw@Sun.COM 	int		rc;
8939832Samw@Sun.COM 
8949832Samw@Sun.COM 	if ((rc = smb_server_lookup(&sv)) == 0) {
89510122SJordan.Brown@Sun.COM 		ioc->open_users = sv->sv_open_users;
89610122SJordan.Brown@Sun.COM 		ioc->open_trees = sv->sv_open_trees;
89710122SJordan.Brown@Sun.COM 		ioc->open_files = sv->sv_open_files;
8989832Samw@Sun.COM 		smb_server_release(sv);
8999832Samw@Sun.COM 	}
9009832Samw@Sun.COM 	return (rc);
9019832Samw@Sun.COM }
9029832Samw@Sun.COM 
9036139Sjb150015 /*
90410122SJordan.Brown@Sun.COM  * Enumerate objects within the server.  The svcenum provides the
90510122SJordan.Brown@Sun.COM  * enumeration context, i.e. what the caller want to get back.
90610122SJordan.Brown@Sun.COM  */
90710122SJordan.Brown@Sun.COM int
90810122SJordan.Brown@Sun.COM smb_server_enum(smb_ioc_svcenum_t *ioc)
90910122SJordan.Brown@Sun.COM {
91010122SJordan.Brown@Sun.COM 	smb_svcenum_t		*svcenum = &ioc->svcenum;
91110122SJordan.Brown@Sun.COM 	smb_server_t		*sv;
91210122SJordan.Brown@Sun.COM 	smb_session_list_t	*se;
91310122SJordan.Brown@Sun.COM 	int			rc;
91410122SJordan.Brown@Sun.COM 
91510122SJordan.Brown@Sun.COM 	switch (svcenum->se_type) {
91610122SJordan.Brown@Sun.COM 	case SMB_SVCENUM_TYPE_USER:
91710122SJordan.Brown@Sun.COM 	case SMB_SVCENUM_TYPE_TREE:
91810122SJordan.Brown@Sun.COM 	case SMB_SVCENUM_TYPE_FILE:
91910122SJordan.Brown@Sun.COM 		break;
92010122SJordan.Brown@Sun.COM 	default:
92110122SJordan.Brown@Sun.COM 		return (EINVAL);
92210122SJordan.Brown@Sun.COM 	}
92310122SJordan.Brown@Sun.COM 
92410122SJordan.Brown@Sun.COM 	if ((rc = smb_server_lookup(&sv)) != 0)
92510122SJordan.Brown@Sun.COM 		return (rc);
92610122SJordan.Brown@Sun.COM 
92710122SJordan.Brown@Sun.COM 	svcenum->se_bavail = svcenum->se_buflen;
92810122SJordan.Brown@Sun.COM 	svcenum->se_bused = 0;
92910122SJordan.Brown@Sun.COM 	svcenum->se_nitems = 0;
93010122SJordan.Brown@Sun.COM 
93110122SJordan.Brown@Sun.COM 	se = &sv->sv_nbt_daemon.ld_session_list;
93210122SJordan.Brown@Sun.COM 	smb_server_enum_private(se, svcenum);
93310122SJordan.Brown@Sun.COM 
93410122SJordan.Brown@Sun.COM 	se = &sv->sv_tcp_daemon.ld_session_list;
93510122SJordan.Brown@Sun.COM 	smb_server_enum_private(se, svcenum);
93610122SJordan.Brown@Sun.COM 
93710122SJordan.Brown@Sun.COM 	smb_server_release(sv);
93810122SJordan.Brown@Sun.COM 	return (0);
93910122SJordan.Brown@Sun.COM }
94010122SJordan.Brown@Sun.COM 
94110122SJordan.Brown@Sun.COM /*
94210122SJordan.Brown@Sun.COM  * Look for sessions to disconnect by client and user name.
94310122SJordan.Brown@Sun.COM  */
94410122SJordan.Brown@Sun.COM int
94510122SJordan.Brown@Sun.COM smb_server_session_close(smb_ioc_session_t *ioc)
94610122SJordan.Brown@Sun.COM {
94710122SJordan.Brown@Sun.COM 	smb_session_list_t	*se;
94810122SJordan.Brown@Sun.COM 	smb_server_t		*sv;
94910122SJordan.Brown@Sun.COM 	int			nbt_cnt;
95010122SJordan.Brown@Sun.COM 	int			tcp_cnt;
95110122SJordan.Brown@Sun.COM 	int			rc;
95210122SJordan.Brown@Sun.COM 
95310122SJordan.Brown@Sun.COM 	if ((rc = smb_server_lookup(&sv)) != 0)
95410122SJordan.Brown@Sun.COM 		return (rc);
95510122SJordan.Brown@Sun.COM 
95610122SJordan.Brown@Sun.COM 	se = &sv->sv_nbt_daemon.ld_session_list;
95710122SJordan.Brown@Sun.COM 	nbt_cnt = smb_server_sesion_disconnect(se, ioc->client, ioc->username);
95810122SJordan.Brown@Sun.COM 
95910122SJordan.Brown@Sun.COM 	se = &sv->sv_tcp_daemon.ld_session_list;
96010122SJordan.Brown@Sun.COM 	tcp_cnt = smb_server_sesion_disconnect(se, ioc->client, ioc->username);
96110122SJordan.Brown@Sun.COM 
96210122SJordan.Brown@Sun.COM 	smb_server_release(sv);
96310122SJordan.Brown@Sun.COM 
96410122SJordan.Brown@Sun.COM 	if ((nbt_cnt == 0) && (tcp_cnt == 0))
96510122SJordan.Brown@Sun.COM 		return (ENOENT);
96610122SJordan.Brown@Sun.COM 	return (0);
96710122SJordan.Brown@Sun.COM }
96810122SJordan.Brown@Sun.COM 
96910122SJordan.Brown@Sun.COM /*
97010122SJordan.Brown@Sun.COM  * Close a file by uniqid.
97110122SJordan.Brown@Sun.COM  */
97210122SJordan.Brown@Sun.COM int
97310122SJordan.Brown@Sun.COM smb_server_file_close(smb_ioc_fileid_t *ioc)
97410122SJordan.Brown@Sun.COM {
97510122SJordan.Brown@Sun.COM 	uint32_t		uniqid = ioc->uniqid;
97610122SJordan.Brown@Sun.COM 	smb_session_list_t	*se;
97710122SJordan.Brown@Sun.COM 	smb_server_t		*sv;
97810122SJordan.Brown@Sun.COM 	int			rc;
97910122SJordan.Brown@Sun.COM 
98010122SJordan.Brown@Sun.COM 	if ((rc = smb_server_lookup(&sv)) != 0)
98110122SJordan.Brown@Sun.COM 		return (rc);
98210122SJordan.Brown@Sun.COM 
98310122SJordan.Brown@Sun.COM 	se = &sv->sv_nbt_daemon.ld_session_list;
98410122SJordan.Brown@Sun.COM 	rc = smb_server_fclose(se, uniqid);
98510122SJordan.Brown@Sun.COM 
98610122SJordan.Brown@Sun.COM 	if (rc == ENOENT) {
98710122SJordan.Brown@Sun.COM 		se = &sv->sv_tcp_daemon.ld_session_list;
98810122SJordan.Brown@Sun.COM 		rc = smb_server_fclose(se, uniqid);
98910122SJordan.Brown@Sun.COM 	}
99010122SJordan.Brown@Sun.COM 
99110122SJordan.Brown@Sun.COM 	smb_server_release(sv);
99210122SJordan.Brown@Sun.COM 	return (rc);
99310122SJordan.Brown@Sun.COM }
99410122SJordan.Brown@Sun.COM 
99510122SJordan.Brown@Sun.COM /*
9966139Sjb150015  * These functions determine the relevant smb server to which the call apply.
9976139Sjb150015  */
9986139Sjb150015 
9996139Sjb150015 uint32_t
10006139Sjb150015 smb_server_get_session_count(void)
10016139Sjb150015 {
10026139Sjb150015 	smb_server_t	*sv;
10036139Sjb150015 	uint32_t	counter = 0;
10046139Sjb150015 
10056139Sjb150015 	if (smb_server_lookup(&sv))
10066139Sjb150015 		return (0);
10076139Sjb150015 
10086139Sjb150015 	rw_enter(&sv->sv_nbt_daemon.ld_session_list.se_lock, RW_READER);
10096139Sjb150015 	counter = sv->sv_nbt_daemon.ld_session_list.se_act.count;
10106139Sjb150015 	rw_exit(&sv->sv_nbt_daemon.ld_session_list.se_lock);
10116139Sjb150015 	rw_enter(&sv->sv_tcp_daemon.ld_session_list.se_lock, RW_READER);
10126139Sjb150015 	counter += sv->sv_tcp_daemon.ld_session_list.se_act.count;
10136139Sjb150015 	rw_exit(&sv->sv_tcp_daemon.ld_session_list.se_lock);
10146139Sjb150015 
10156139Sjb150015 	smb_server_release(sv);
10166139Sjb150015 
10176139Sjb150015 	return (counter);
10186139Sjb150015 }
10196139Sjb150015 
10206139Sjb150015 /*
1021*11963SAfshin.Ardakani@Sun.COM  * Disconnect the specified share.
1022*11963SAfshin.Ardakani@Sun.COM  * Typically called when a share has been removed.
10236139Sjb150015  */
10247619SJose.Borrego@Sun.COM static void
1025*11963SAfshin.Ardakani@Sun.COM smb_server_disconnect_share(smb_session_list_t *slist, const char *sharename)
10266139Sjb150015 {
1027*11963SAfshin.Ardakani@Sun.COM 	smb_session_t		*session;
1028*11963SAfshin.Ardakani@Sun.COM 
1029*11963SAfshin.Ardakani@Sun.COM 	rw_enter(&slist->se_lock, RW_READER);
1030*11963SAfshin.Ardakani@Sun.COM 
1031*11963SAfshin.Ardakani@Sun.COM 	session = list_head(&slist->se_act.lst);
1032*11963SAfshin.Ardakani@Sun.COM 	while (session) {
1033*11963SAfshin.Ardakani@Sun.COM 		ASSERT(session->s_magic == SMB_SESSION_MAGIC);
1034*11963SAfshin.Ardakani@Sun.COM 		smb_rwx_rwenter(&session->s_lock, RW_READER);
1035*11963SAfshin.Ardakani@Sun.COM 		switch (session->s_state) {
1036*11963SAfshin.Ardakani@Sun.COM 		case SMB_SESSION_STATE_NEGOTIATED:
1037*11963SAfshin.Ardakani@Sun.COM 		case SMB_SESSION_STATE_OPLOCK_BREAKING:
1038*11963SAfshin.Ardakani@Sun.COM 		case SMB_SESSION_STATE_WRITE_RAW_ACTIVE:
1039*11963SAfshin.Ardakani@Sun.COM 			smb_session_disconnect_share(session, sharename);
1040*11963SAfshin.Ardakani@Sun.COM 			break;
1041*11963SAfshin.Ardakani@Sun.COM 		default:
1042*11963SAfshin.Ardakani@Sun.COM 			break;
1043*11963SAfshin.Ardakani@Sun.COM 		}
1044*11963SAfshin.Ardakani@Sun.COM 		smb_rwx_rwexit(&session->s_lock);
1045*11963SAfshin.Ardakani@Sun.COM 		session = list_next(&slist->se_act.lst, session);
1046*11963SAfshin.Ardakani@Sun.COM 	}
1047*11963SAfshin.Ardakani@Sun.COM 
1048*11963SAfshin.Ardakani@Sun.COM 	rw_exit(&slist->se_lock);
10496139Sjb150015 }
10506139Sjb150015 
10516139Sjb150015 /*
10526139Sjb150015  * smb_server_share_export()
10536139Sjb150015  *
10546139Sjb150015  * This function handles kernel processing at share enable time.
10556139Sjb150015  *
10566139Sjb150015  * At share-enable time (LMSHRD_ADD), the file system corresponding to
10576139Sjb150015  * the share is checked for characteristics that are required for SMB
10586139Sjb150015  * sharing.  If this check passes, then a hold is taken on the root vnode
10596139Sjb150015  * of the file system (or a reference count on the corresponding smb_vfs_t
10606139Sjb150015  * is bumped), preventing an unmount.  (See smb_vfs_hold()).
10616139Sjb150015  */
10626139Sjb150015 
10636139Sjb150015 int
10649832Samw@Sun.COM smb_server_share_export(smb_ioc_share_t *ioc)
10656139Sjb150015 {
10666139Sjb150015 	smb_server_t	*sv;
10679422SAfshin.Ardakani@Sun.COM 	int		error = 0;
10686139Sjb150015 	smb_node_t	*fnode = NULL;
10696139Sjb150015 	smb_node_t	*dnode;
10706139Sjb150015 	char		last_comp[MAXNAMELEN];
10716139Sjb150015 	smb_request_t	*sr;
10726139Sjb150015 
10736139Sjb150015 	if (smb_server_lookup(&sv))
10746139Sjb150015 		return (EINVAL);
10756139Sjb150015 
10769832Samw@Sun.COM 	mutex_enter(&sv->sv_mutex);
10779832Samw@Sun.COM 	switch (sv->sv_state) {
10789832Samw@Sun.COM 	case SMB_SERVER_STATE_RUNNING:
1079*11963SAfshin.Ardakani@Sun.COM 	case SMB_SERVER_STATE_STOPPING:
10809832Samw@Sun.COM 		break;
10819832Samw@Sun.COM 	default:
10829832Samw@Sun.COM 		mutex_exit(&sv->sv_mutex);
10839832Samw@Sun.COM 		return (ENOTACTIVE);
10849832Samw@Sun.COM 	}
10859832Samw@Sun.COM 	mutex_exit(&sv->sv_mutex);
10869832Samw@Sun.COM 
10876139Sjb150015 	sr = smb_request_alloc(sv->sv_session, 0);
10886139Sjb150015 	if (sr == NULL) {
10896139Sjb150015 		smb_server_release(sv);
10906139Sjb150015 		return (ENOMEM);
10916139Sjb150015 	}
10926139Sjb150015 
10936139Sjb150015 	sr->user_cr = kcred;
10946139Sjb150015 
10959832Samw@Sun.COM 	error = smb_pathname_reduce(sr, kcred, ioc->path,
10969832Samw@Sun.COM 	    NULL, NULL, &dnode, last_comp);
10976139Sjb150015 
10986139Sjb150015 	if (error) {
10996139Sjb150015 		smb_request_free(sr);
11006139Sjb150015 		smb_server_release(sv);
11016139Sjb150015 		return (error);
11026139Sjb150015 	}
11036139Sjb150015 
11049231SAfshin.Ardakani@Sun.COM 	error = smb_fsop_lookup(sr, sr->user_cr, SMB_FOLLOW_LINKS,
110510001SJoyce.McIntosh@Sun.COM 	    sv->si_root_smb_node, dnode, last_comp, &fnode);
11066139Sjb150015 
11076139Sjb150015 	smb_node_release(dnode);
11086139Sjb150015 
11096139Sjb150015 	if (error) {
11106139Sjb150015 		smb_request_free(sr);
11116139Sjb150015 		smb_server_release(sv);
11126139Sjb150015 		return (error);
11136139Sjb150015 	}
11146139Sjb150015 
11156139Sjb150015 	ASSERT(fnode->vp && fnode->vp->v_vfsp);
11166139Sjb150015 
11176139Sjb150015 #ifdef SMB_ENFORCE_NODEV
11189422SAfshin.Ardakani@Sun.COM 	if (vfs_optionisset(fnode->vp->v_vfsp, MNTOPT_NODEVICES, NULL) == 0) {
11196139Sjb150015 		smb_node_release(fnode);
11206139Sjb150015 		smb_request_free(sr);
11216139Sjb150015 		smb_server_release(sv);
11229422SAfshin.Ardakani@Sun.COM 		return (EINVAL);
11236139Sjb150015 	}
11249422SAfshin.Ardakani@Sun.COM #endif /* SMB_ENFORCE_NODEV */
11259422SAfshin.Ardakani@Sun.COM 
11269422SAfshin.Ardakani@Sun.COM 	if (!smb_vfs_hold(sv, fnode->vp->v_vfsp))
11279422SAfshin.Ardakani@Sun.COM 		error = ENOMEM;
11286139Sjb150015 
11296139Sjb150015 	/*
11306139Sjb150015 	 * The refcount on the smb_vfs has been incremented.
11316139Sjb150015 	 * If it wasn't already, a hold has also been taken
11326139Sjb150015 	 * on the root vnode of the file system.
11336139Sjb150015 	 */
11346139Sjb150015 
11356139Sjb150015 	smb_node_release(fnode);
11366139Sjb150015 	smb_request_free(sr);
11376139Sjb150015 	smb_server_release(sv);
11389422SAfshin.Ardakani@Sun.COM 	return (error);
11396139Sjb150015 }
11406139Sjb150015 
11416139Sjb150015 /*
11426139Sjb150015  * smb_server_share_unexport()
11436139Sjb150015  *
11447619SJose.Borrego@Sun.COM  * This function is invoked when a share is disabled to disconnect trees
11457619SJose.Borrego@Sun.COM  * and close files.  Cleaning up may involve VOP and/or VFS calls, which
11467619SJose.Borrego@Sun.COM  * may conflict/deadlock with stuck threads if something is amiss with the
11477619SJose.Borrego@Sun.COM  * file system.  Queueing the request for asynchronous processing allows the
11487619SJose.Borrego@Sun.COM  * call to return immediately so that, if the unshare is being done in the
11497619SJose.Borrego@Sun.COM  * context of a forced unmount, the forced unmount will always be able to
11507619SJose.Borrego@Sun.COM  * proceed (unblocking stuck I/O and eventually allowing all blocked unshare
11517619SJose.Borrego@Sun.COM  * processes to complete).
11526139Sjb150015  *
11537619SJose.Borrego@Sun.COM  * The path lookup to find the root vnode of the VFS in question and the
11547619SJose.Borrego@Sun.COM  * release of this vnode are done synchronously prior to any associated
11557619SJose.Borrego@Sun.COM  * unmount.  Doing these asynchronous to an associated unmount could run
11567619SJose.Borrego@Sun.COM  * the risk of a spurious EBUSY for a standard unmount or an EIO during
11577619SJose.Borrego@Sun.COM  * the path lookup due to a forced unmount finishing first.
11586139Sjb150015  */
11596139Sjb150015 
11606139Sjb150015 int
11619832Samw@Sun.COM smb_server_share_unexport(smb_ioc_share_t *ioc)
11626139Sjb150015 {
11636139Sjb150015 	smb_server_t	*sv;
11647619SJose.Borrego@Sun.COM 	smb_request_t	*sr;
11657619SJose.Borrego@Sun.COM 	smb_unexport_t	*ux;
11666139Sjb150015 	smb_node_t	*fnode = NULL;
11676139Sjb150015 	smb_node_t	*dnode;
11686139Sjb150015 	char		last_comp[MAXNAMELEN];
11697619SJose.Borrego@Sun.COM 	int		rc;
11706139Sjb150015 
11717619SJose.Borrego@Sun.COM 	if ((rc = smb_server_lookup(&sv)))
11727619SJose.Borrego@Sun.COM 		return (rc);
11736139Sjb150015 
11749832Samw@Sun.COM 	mutex_enter(&sv->sv_mutex);
11759832Samw@Sun.COM 	switch (sv->sv_state) {
11769832Samw@Sun.COM 	case SMB_SERVER_STATE_RUNNING:
1177*11963SAfshin.Ardakani@Sun.COM 	case SMB_SERVER_STATE_STOPPING:
11789832Samw@Sun.COM 		break;
11799832Samw@Sun.COM 	default:
11809832Samw@Sun.COM 		mutex_exit(&sv->sv_mutex);
11819832Samw@Sun.COM 		return (ENOTACTIVE);
11829832Samw@Sun.COM 	}
11839832Samw@Sun.COM 	mutex_exit(&sv->sv_mutex);
11849832Samw@Sun.COM 
11856139Sjb150015 	sr = smb_request_alloc(sv->sv_session, 0);
11867619SJose.Borrego@Sun.COM 
11876139Sjb150015 	if (sr == NULL) {
11886139Sjb150015 		smb_server_release(sv);
11896139Sjb150015 		return (ENOMEM);
11906139Sjb150015 	}
11917619SJose.Borrego@Sun.COM 
11926139Sjb150015 	sr->user_cr = kcred;
11936139Sjb150015 
11949832Samw@Sun.COM 	rc = smb_pathname_reduce(sr, kcred, ioc->path, NULL, NULL,
11959832Samw@Sun.COM 	    &dnode, last_comp);
11966139Sjb150015 
11977619SJose.Borrego@Sun.COM 	if (rc) {
11986139Sjb150015 		smb_request_free(sr);
11996139Sjb150015 		smb_server_release(sv);
12007619SJose.Borrego@Sun.COM 		return (rc);
12016139Sjb150015 	}
12026139Sjb150015 
12039231SAfshin.Ardakani@Sun.COM 	rc = smb_fsop_lookup(sr, kcred, SMB_FOLLOW_LINKS, sv->si_root_smb_node,
120410001SJoyce.McIntosh@Sun.COM 	    dnode, last_comp, &fnode);
12056139Sjb150015 
12066139Sjb150015 	smb_node_release(dnode);
12077619SJose.Borrego@Sun.COM 	smb_request_free(sr);
12086139Sjb150015 
12097619SJose.Borrego@Sun.COM 	if (rc) {
12106139Sjb150015 		smb_server_release(sv);
12117619SJose.Borrego@Sun.COM 		return (rc);
12126139Sjb150015 	}
12136139Sjb150015 
12146139Sjb150015 	ASSERT(fnode->vp && fnode->vp->v_vfsp);
12156139Sjb150015 
12166139Sjb150015 	smb_vfs_rele(sv, fnode->vp->v_vfsp);
12177619SJose.Borrego@Sun.COM 
12186139Sjb150015 	smb_node_release(fnode);
12197619SJose.Borrego@Sun.COM 
12207619SJose.Borrego@Sun.COM 	ux = kmem_cache_alloc(sv->si_cache_unexport, KM_SLEEP);
12217619SJose.Borrego@Sun.COM 
12229832Samw@Sun.COM 	(void) strlcpy(ux->ux_sharename, ioc->name, MAXNAMELEN);
12237619SJose.Borrego@Sun.COM 
12247619SJose.Borrego@Sun.COM 	smb_slist_insert_tail(&sv->sv_unexport_list, ux);
12257619SJose.Borrego@Sun.COM 	smb_thread_signal(&sv->si_thread_unexport);
12267619SJose.Borrego@Sun.COM 
12276139Sjb150015 	smb_server_release(sv);
12286139Sjb150015 	return (0);
12296139Sjb150015 }
12306139Sjb150015 
12316139Sjb150015 /*
12327619SJose.Borrego@Sun.COM  * smb_server_thread_unexport
12337619SJose.Borrego@Sun.COM  *
12347619SJose.Borrego@Sun.COM  * This function processes the unexport event list and disconnects shares
12357619SJose.Borrego@Sun.COM  * asynchronously.  The function executes as a zone-specific thread.
12367619SJose.Borrego@Sun.COM  *
12377619SJose.Borrego@Sun.COM  * The server arg passed in is safe to use without a reference count, because
12387619SJose.Borrego@Sun.COM  * the server cannot be deleted until smb_thread_stop()/destroy() return,
12397619SJose.Borrego@Sun.COM  * which is also when the thread exits.
12407619SJose.Borrego@Sun.COM  */
12417619SJose.Borrego@Sun.COM 
12427619SJose.Borrego@Sun.COM static void
12437619SJose.Borrego@Sun.COM smb_server_thread_unexport(smb_thread_t *thread, void *arg)
12447619SJose.Borrego@Sun.COM {
1245*11963SAfshin.Ardakani@Sun.COM 	smb_server_t		*sv = (smb_server_t *)arg;
1246*11963SAfshin.Ardakani@Sun.COM 	smb_unexport_t		*ux;
1247*11963SAfshin.Ardakani@Sun.COM 	smb_session_list_t	*slist;
12487619SJose.Borrego@Sun.COM 
12497619SJose.Borrego@Sun.COM 	while (smb_thread_continue(thread)) {
12507619SJose.Borrego@Sun.COM 		while ((ux = list_head(&sv->sv_unexport_list.sl_list))
12517619SJose.Borrego@Sun.COM 		    != NULL) {
12527619SJose.Borrego@Sun.COM 			smb_slist_remove(&sv->sv_unexport_list, ux);
1253*11963SAfshin.Ardakani@Sun.COM 
1254*11963SAfshin.Ardakani@Sun.COM 			slist = &sv->sv_nbt_daemon.ld_session_list;
1255*11963SAfshin.Ardakani@Sun.COM 			smb_server_disconnect_share(slist, ux->ux_sharename);
1256*11963SAfshin.Ardakani@Sun.COM 
1257*11963SAfshin.Ardakani@Sun.COM 			slist = &sv->sv_tcp_daemon.ld_session_list;
1258*11963SAfshin.Ardakani@Sun.COM 			smb_server_disconnect_share(slist, ux->ux_sharename);
1259*11963SAfshin.Ardakani@Sun.COM 
12607619SJose.Borrego@Sun.COM 			kmem_cache_free(sv->si_cache_unexport, ux);
12617619SJose.Borrego@Sun.COM 		}
12627619SJose.Borrego@Sun.COM 	}
12637619SJose.Borrego@Sun.COM }
12647619SJose.Borrego@Sun.COM 
12657619SJose.Borrego@Sun.COM /*
12666139Sjb150015  * This is a special interface that will be utilized by ZFS to cause a share to
12676139Sjb150015  * be added/removed.
12686139Sjb150015  *
12696139Sjb150015  * arg is either a lmshare_info_t or share_name from userspace.
12706139Sjb150015  * It will need to be copied into the kernel.   It is lmshare_info_t
12716139Sjb150015  * for add operations and share_name for delete operations.
12726139Sjb150015  */
12736139Sjb150015 int
12746139Sjb150015 smb_server_share(void *arg, boolean_t add_share)
12756139Sjb150015 {
12766139Sjb150015 	smb_server_t	*sv;
12776139Sjb150015 	int		rc;
12786139Sjb150015 
12796139Sjb150015 	rc = smb_server_lookup(&sv);
12806139Sjb150015 	if (rc == 0) {
12816139Sjb150015 		mutex_enter(&sv->sv_mutex);
12829832Samw@Sun.COM 		switch (sv->sv_state) {
12839832Samw@Sun.COM 		case SMB_SERVER_STATE_RUNNING:
12846139Sjb150015 			mutex_exit(&sv->sv_mutex);
12859832Samw@Sun.COM 			(void) smb_kshare_upcall(sv->sv_lmshrd, arg, add_share);
12869832Samw@Sun.COM 			break;
12879832Samw@Sun.COM 		default:
12886139Sjb150015 			mutex_exit(&sv->sv_mutex);
12899832Samw@Sun.COM 			break;
12906139Sjb150015 		}
12916139Sjb150015 		smb_server_release(sv);
12926139Sjb150015 	}
12939832Samw@Sun.COM 	return (0);
12946139Sjb150015 }
12956139Sjb150015 
12966139Sjb150015 /*
12976139Sjb150015  * *****************************************************************************
12986139Sjb150015  * **************** Functions called from the internal layers ******************
12996139Sjb150015  * *****************************************************************************
13006139Sjb150015  *
13016139Sjb150015  * These functions are provided the relevant smb server by the caller.
13026139Sjb150015  */
13036139Sjb150015 
13046139Sjb150015 void
13056139Sjb150015 smb_server_reconnection_check(smb_server_t *sv, smb_session_t *session)
13066139Sjb150015 {
13076139Sjb150015 	ASSERT(sv == session->s_server);
13086139Sjb150015 
13096139Sjb150015 	smb_session_reconnection_check(&sv->sv_nbt_daemon.ld_session_list,
13106139Sjb150015 	    session);
13116139Sjb150015 	smb_session_reconnection_check(&sv->sv_tcp_daemon.ld_session_list,
13126139Sjb150015 	    session);
13136139Sjb150015 }
13146139Sjb150015 
13156139Sjb150015 void
13166139Sjb150015 smb_server_get_cfg(smb_server_t *sv, smb_kmod_cfg_t *cfg)
13176139Sjb150015 {
13186139Sjb150015 	rw_enter(&sv->sv_cfg_lock, RW_READER);
13196139Sjb150015 	bcopy(&sv->sv_cfg, cfg, sizeof (*cfg));
13206139Sjb150015 	rw_exit(&sv->sv_cfg_lock);
13216139Sjb150015 }
13226139Sjb150015 
13236139Sjb150015 /*
13246139Sjb150015  * *****************************************************************************
13256139Sjb150015  * *************************** Static Functions ********************************
13266139Sjb150015  * *****************************************************************************
13276139Sjb150015  */
13286139Sjb150015 
13296139Sjb150015 static void
13306139Sjb150015 smb_server_timers(smb_thread_t *thread, void *arg)
13316139Sjb150015 {
13326139Sjb150015 	smb_server_t	*sv = (smb_server_t *)arg;
13336139Sjb150015 
13346139Sjb150015 	ASSERT(sv != NULL);
13356139Sjb150015 
13366139Sjb150015 	while (smb_thread_continue_timedwait(thread, 1 /* Seconds */)) {
13376139Sjb150015 		smb_session_timers(&sv->sv_nbt_daemon.ld_session_list);
13386139Sjb150015 		smb_session_timers(&sv->sv_tcp_daemon.ld_session_list);
13396139Sjb150015 	}
13406139Sjb150015 }
13416139Sjb150015 
13426139Sjb150015 /*
13436139Sjb150015  * smb_server_kstat_init
13446139Sjb150015  */
13456139Sjb150015 static int
13466139Sjb150015 smb_server_kstat_init(smb_server_t *sv)
13476139Sjb150015 {
13486432Sas200622 	(void) snprintf(sv->sv_ksp_name, sizeof (sv->sv_ksp_name), "%s%d",
13496432Sas200622 	    SMBSRV_KSTAT_NAME, sv->sv_zid);
13506139Sjb150015 
13516432Sas200622 	sv->sv_ksp = kstat_create(SMBSRV_KSTAT_MODULE, 0, sv->sv_ksp_name,
13526432Sas200622 	    SMBSRV_KSTAT_CLASS, KSTAT_TYPE_NAMED,
13536432Sas200622 	    sizeof (sv->sv_ks_data) / sizeof (kstat_named_t),
13546139Sjb150015 	    KSTAT_FLAG_VIRTUAL);
13556139Sjb150015 
13566139Sjb150015 	if (sv->sv_ksp) {
13576139Sjb150015 		(void) strlcpy(sv->sv_ks_data.open_files.name, "open_files",
13586139Sjb150015 		    sizeof (sv->sv_ks_data.open_files.name));
13596139Sjb150015 		sv->sv_ks_data.open_files.data_type = KSTAT_DATA_UINT32;
13606139Sjb150015 		(void) strlcpy(sv->sv_ks_data.open_trees.name, "connections",
13616139Sjb150015 		    sizeof (sv->sv_ks_data.open_trees.name));
13626139Sjb150015 		sv->sv_ks_data.open_trees.data_type = KSTAT_DATA_UINT32;
13636139Sjb150015 		(void) strlcpy(sv->sv_ks_data.open_users.name, "sessions",
13646139Sjb150015 		    sizeof (sv->sv_ks_data.open_users.name));
13656139Sjb150015 		sv->sv_ks_data.open_users.data_type = KSTAT_DATA_UINT32;
13666139Sjb150015 
13676139Sjb150015 		mutex_init(&sv->sv_ksp_mutex, NULL, MUTEX_DEFAULT, NULL);
13686139Sjb150015 		sv->sv_ksp->ks_lock = &sv->sv_ksp_mutex;
13696139Sjb150015 		sv->sv_ksp->ks_data = (void *)&sv->sv_ks_data;
13706139Sjb150015 		sv->sv_ksp->ks_update = smb_server_kstat_update_info;
13716139Sjb150015 		kstat_install(sv->sv_ksp);
13726139Sjb150015 	}
13736139Sjb150015 
13746139Sjb150015 	/* create and initialize smb kstats - smb_dispatch stats */
13756139Sjb150015 	smb_dispatch_kstat_init();
13766139Sjb150015 
13776139Sjb150015 	return (0);
13786139Sjb150015 }
13796139Sjb150015 
13806139Sjb150015 /*
13816139Sjb150015  * smb_server_kstat_fini
13826139Sjb150015  */
13836139Sjb150015 static void
13846139Sjb150015 smb_server_kstat_fini(smb_server_t *sv)
13856139Sjb150015 {
13866139Sjb150015 	if (sv->sv_ksp) {
13876139Sjb150015 		kstat_delete(sv->sv_ksp);
13886139Sjb150015 		mutex_destroy(&sv->sv_ksp_mutex);
13896139Sjb150015 		sv->sv_ksp = NULL;
13906139Sjb150015 	}
13916139Sjb150015 	smb_dispatch_kstat_fini();
13926139Sjb150015 }
13936139Sjb150015 
13946139Sjb150015 /* ARGSUSED */
13956139Sjb150015 static int
13966139Sjb150015 smb_server_kstat_update_info(kstat_t *ksp, int rw)
13976139Sjb150015 {
13986139Sjb150015 	smb_server_t	*sv;
13996139Sjb150015 
14006139Sjb150015 	if (rw == KSTAT_WRITE) {
14016139Sjb150015 		return (EACCES);
14026139Sjb150015 	} else {
14036139Sjb150015 		ASSERT(MUTEX_HELD(ksp->ks_lock));
14046139Sjb150015 
14056139Sjb150015 		_NOTE(LINTED("pointer cast may result in improper alignment"))
14066139Sjb150015 		sv = (smb_server_t *)((uint8_t *)(ksp->ks_data) -
14076139Sjb150015 		    offsetof(smb_server_t, sv_ks_data));
14086139Sjb150015 
1409*11963SAfshin.Ardakani@Sun.COM 		SMB_SERVER_VALID(sv);
14106139Sjb150015 
14116139Sjb150015 		sv->sv_ks_data.open_files.value.ui32 = sv->sv_open_files;
14126139Sjb150015 		sv->sv_ks_data.open_trees.value.ui32 = sv->sv_open_trees;
14136139Sjb150015 		sv->sv_ks_data.open_users.value.ui32 = sv->sv_open_users;
14146139Sjb150015 	}
14156139Sjb150015 	return (0);
14166139Sjb150015 }
14176139Sjb150015 
14186139Sjb150015 /*
14196139Sjb150015  * The mutex of the server must have been entered before calling this function.
14206139Sjb150015  */
14216139Sjb150015 static void
1422*11963SAfshin.Ardakani@Sun.COM smb_server_shutdown(smb_server_t *sv)
14236139Sjb150015 {
1424*11963SAfshin.Ardakani@Sun.COM 	SMB_SERVER_VALID(sv);
14256139Sjb150015 
14267052Samw 	smb_opipe_door_close();
14276139Sjb150015 	smb_thread_stop(&sv->si_thread_timers);
14287619SJose.Borrego@Sun.COM 	smb_thread_stop(&sv->si_thread_unexport);
1429*11963SAfshin.Ardakani@Sun.COM 	smb_kdoor_close();
14306771Sjb150015 	smb_kshare_fini(sv->sv_lmshrd);
14316849Sjb150015 	sv->sv_lmshrd = NULL;
14326139Sjb150015 	smb_server_fsop_stop(sv);
14337588Samw@Sun.COM 
14346139Sjb150015 	if (sv->sv_session) {
14356139Sjb150015 		smb_session_delete(sv->sv_session);
14366139Sjb150015 		sv->sv_session = NULL;
14376139Sjb150015 	}
14387588Samw@Sun.COM 
14397588Samw@Sun.COM 	if (sv->sv_thread_pool) {
14407588Samw@Sun.COM 		taskq_destroy(sv->sv_thread_pool);
14417588Samw@Sun.COM 		sv->sv_thread_pool = NULL;
14427588Samw@Sun.COM 	}
14436139Sjb150015 }
14446139Sjb150015 
14456139Sjb150015 static int
14466139Sjb150015 smb_server_listen(
14476139Sjb150015     smb_server_t		*sv,
14486139Sjb150015     smb_listener_daemon_t	*ld,
14496139Sjb150015     in_port_t			port,
14508670SJose.Borrego@Sun.COM     int				family,
14516139Sjb150015     int				pthread_create_error)
14526139Sjb150015 {
1453*11963SAfshin.Ardakani@Sun.COM 	int			rc = 0;
14548348SEric.Yu@Sun.COM 	ksocket_t		s_so;
1455*11963SAfshin.Ardakani@Sun.COM 	uint32_t		on;
1456*11963SAfshin.Ardakani@Sun.COM 	uint32_t		off;
1457*11963SAfshin.Ardakani@Sun.COM 	uint32_t		txbuf_size;
14586139Sjb150015 	smb_session_t		*session;
14596139Sjb150015 
14606139Sjb150015 	if (pthread_create_error) {
14616139Sjb150015 		/*
14626139Sjb150015 		 * Delete the last session created. The user space thread
14636139Sjb150015 		 * creation failed.
14646139Sjb150015 		 */
14656139Sjb150015 		smb_session_list_delete_tail(&ld->ld_session_list);
14666139Sjb150015 	}
14676139Sjb150015 
14686139Sjb150015 	if (ld->ld_so == NULL) {
14696139Sjb150015 		/* First time listener */
14708670SJose.Borrego@Sun.COM 		if (family == AF_INET) {
14718670SJose.Borrego@Sun.COM 			ld->ld_sin.sin_family = (uint32_t)family;
14728670SJose.Borrego@Sun.COM 			ld->ld_sin.sin_port = htons(port);
14738670SJose.Borrego@Sun.COM 			ld->ld_sin.sin_addr.s_addr = htonl(INADDR_ANY);
14748670SJose.Borrego@Sun.COM 		} else {
14758670SJose.Borrego@Sun.COM 			ld->ld_sin6.sin6_family = (uint32_t)family;
14768670SJose.Borrego@Sun.COM 			ld->ld_sin6.sin6_port = htons(port);
14778670SJose.Borrego@Sun.COM 			(void) memset(&ld->ld_sin6.sin6_addr.s6_addr, 0,
14788670SJose.Borrego@Sun.COM 			    sizeof (ld->ld_sin6.sin6_addr.s6_addr));
14798670SJose.Borrego@Sun.COM 		}
1480*11963SAfshin.Ardakani@Sun.COM 
14818670SJose.Borrego@Sun.COM 		ld->ld_so = smb_socreate(family, SOCK_STREAM, 0);
1482*11963SAfshin.Ardakani@Sun.COM 		if (ld->ld_so == NULL) {
1483*11963SAfshin.Ardakani@Sun.COM 			cmn_err(CE_WARN, "port %d: socket create failed", port);
1484*11963SAfshin.Ardakani@Sun.COM 			return (ENOMEM);
1485*11963SAfshin.Ardakani@Sun.COM 		}
14866139Sjb150015 
1487*11963SAfshin.Ardakani@Sun.COM 		off = 0;
1488*11963SAfshin.Ardakani@Sun.COM 		(void) ksocket_setsockopt(ld->ld_so, SOL_SOCKET,
1489*11963SAfshin.Ardakani@Sun.COM 		    SO_MAC_EXEMPT, &off, sizeof (off), CRED());
1490*11963SAfshin.Ardakani@Sun.COM 
1491*11963SAfshin.Ardakani@Sun.COM 		on = 1;
1492*11963SAfshin.Ardakani@Sun.COM 		(void) ksocket_setsockopt(ld->ld_so, SOL_SOCKET,
1493*11963SAfshin.Ardakani@Sun.COM 		    SO_REUSEADDR, &on, sizeof (on), CRED());
14949021Samw@Sun.COM 
1495*11963SAfshin.Ardakani@Sun.COM 		if (family == AF_INET) {
1496*11963SAfshin.Ardakani@Sun.COM 			rc = ksocket_bind(ld->ld_so,
1497*11963SAfshin.Ardakani@Sun.COM 			    (struct sockaddr *)&ld->ld_sin,
1498*11963SAfshin.Ardakani@Sun.COM 			    sizeof (ld->ld_sin), CRED());
14996139Sjb150015 		} else {
1500*11963SAfshin.Ardakani@Sun.COM 			rc = ksocket_bind(ld->ld_so,
1501*11963SAfshin.Ardakani@Sun.COM 			    (struct sockaddr *)&ld->ld_sin6,
1502*11963SAfshin.Ardakani@Sun.COM 			    sizeof (ld->ld_sin6), CRED());
1503*11963SAfshin.Ardakani@Sun.COM 		}
1504*11963SAfshin.Ardakani@Sun.COM 
1505*11963SAfshin.Ardakani@Sun.COM 		if (rc != 0) {
1506*11963SAfshin.Ardakani@Sun.COM 			cmn_err(CE_WARN, "port %d: bind failed (%d)", port, rc);
1507*11963SAfshin.Ardakani@Sun.COM 			smb_server_listen_fini(ld);
1508*11963SAfshin.Ardakani@Sun.COM 			return (rc);
1509*11963SAfshin.Ardakani@Sun.COM 		}
1510*11963SAfshin.Ardakani@Sun.COM 
1511*11963SAfshin.Ardakani@Sun.COM 		rc =  ksocket_listen(ld->ld_so, 20, CRED());
1512*11963SAfshin.Ardakani@Sun.COM 		if (rc < 0) {
1513*11963SAfshin.Ardakani@Sun.COM 			cmn_err(CE_WARN, "port %d: listen failed", port);
1514*11963SAfshin.Ardakani@Sun.COM 			smb_server_listen_fini(ld);
1515*11963SAfshin.Ardakani@Sun.COM 			return (rc);
15166139Sjb150015 		}
15176139Sjb150015 	}
15186139Sjb150015 
15196139Sjb150015 	DTRACE_PROBE1(so__wait__accept, struct sonode *, ld->ld_so);
15206139Sjb150015 
15216139Sjb150015 	for (;;) {
1522*11963SAfshin.Ardakani@Sun.COM 		if (smb_server_is_stopping()) {
1523*11963SAfshin.Ardakani@Sun.COM 			rc = ECANCELED;
1524*11963SAfshin.Ardakani@Sun.COM 			break;
1525*11963SAfshin.Ardakani@Sun.COM 		}
1526*11963SAfshin.Ardakani@Sun.COM 
15278348SEric.Yu@Sun.COM 		rc = ksocket_accept(ld->ld_so, NULL, NULL, &s_so, CRED());
1528*11963SAfshin.Ardakani@Sun.COM 		if (rc != 0)
1529*11963SAfshin.Ardakani@Sun.COM 			break;
1530*11963SAfshin.Ardakani@Sun.COM 
1531*11963SAfshin.Ardakani@Sun.COM 		if (smb_server_is_stopping()) {
1532*11963SAfshin.Ardakani@Sun.COM 			smb_soshutdown(s_so);
1533*11963SAfshin.Ardakani@Sun.COM 			smb_sodestroy(s_so);
1534*11963SAfshin.Ardakani@Sun.COM 			rc = ECANCELED;
1535*11963SAfshin.Ardakani@Sun.COM 			break;
1536*11963SAfshin.Ardakani@Sun.COM 		}
15376139Sjb150015 
1538*11963SAfshin.Ardakani@Sun.COM 		DTRACE_PROBE1(so__accept, struct sonode *, s_so);
1539*11963SAfshin.Ardakani@Sun.COM 
1540*11963SAfshin.Ardakani@Sun.COM 		on = 1;
1541*11963SAfshin.Ardakani@Sun.COM 		(void) ksocket_setsockopt(s_so, IPPROTO_TCP, TCP_NODELAY,
1542*11963SAfshin.Ardakani@Sun.COM 		    &on, sizeof (on), CRED());
1543*11963SAfshin.Ardakani@Sun.COM 
1544*11963SAfshin.Ardakani@Sun.COM 		on = 1;
1545*11963SAfshin.Ardakani@Sun.COM 		(void) ksocket_setsockopt(s_so, SOL_SOCKET, SO_KEEPALIVE,
1546*11963SAfshin.Ardakani@Sun.COM 		    &on, sizeof (on), CRED());
15476139Sjb150015 
1548*11963SAfshin.Ardakani@Sun.COM 		txbuf_size = 128*1024;
1549*11963SAfshin.Ardakani@Sun.COM 		(void) ksocket_setsockopt(s_so, SOL_SOCKET, SO_SNDBUF,
1550*11963SAfshin.Ardakani@Sun.COM 		    (const void *)&txbuf_size, sizeof (txbuf_size), CRED());
1551*11963SAfshin.Ardakani@Sun.COM 
1552*11963SAfshin.Ardakani@Sun.COM 		/*
1553*11963SAfshin.Ardakani@Sun.COM 		 * Create a session for this connection.
1554*11963SAfshin.Ardakani@Sun.COM 		 */
1555*11963SAfshin.Ardakani@Sun.COM 		session = smb_session_create(s_so, port, sv, family);
1556*11963SAfshin.Ardakani@Sun.COM 		if (session) {
1557*11963SAfshin.Ardakani@Sun.COM 			smb_session_list_append(&ld->ld_session_list, session);
1558*11963SAfshin.Ardakani@Sun.COM 			rc = 0;
1559*11963SAfshin.Ardakani@Sun.COM 			break;
1560*11963SAfshin.Ardakani@Sun.COM 		} else {
1561*11963SAfshin.Ardakani@Sun.COM 			smb_soshutdown(s_so);
1562*11963SAfshin.Ardakani@Sun.COM 			smb_sodestroy(s_so);
15636139Sjb150015 		}
1564*11963SAfshin.Ardakani@Sun.COM 	}
1565*11963SAfshin.Ardakani@Sun.COM 
1566*11963SAfshin.Ardakani@Sun.COM 	if (rc != 0)
1567*11963SAfshin.Ardakani@Sun.COM 		smb_server_listen_fini(ld);
1568*11963SAfshin.Ardakani@Sun.COM 
1569*11963SAfshin.Ardakani@Sun.COM 	return (rc);
1570*11963SAfshin.Ardakani@Sun.COM }
1571*11963SAfshin.Ardakani@Sun.COM 
1572*11963SAfshin.Ardakani@Sun.COM static void
1573*11963SAfshin.Ardakani@Sun.COM smb_server_listen_fini(smb_listener_daemon_t *ld)
1574*11963SAfshin.Ardakani@Sun.COM {
1575*11963SAfshin.Ardakani@Sun.COM 	if (ld->ld_so != NULL) {
15766139Sjb150015 		smb_session_list_signal(&ld->ld_session_list);
15776139Sjb150015 		smb_soshutdown(ld->ld_so);
15786139Sjb150015 		smb_sodestroy(ld->ld_so);
15796139Sjb150015 		ld->ld_so = NULL;
1580*11963SAfshin.Ardakani@Sun.COM 	}
1581*11963SAfshin.Ardakani@Sun.COM }
1582*11963SAfshin.Ardakani@Sun.COM 
1583*11963SAfshin.Ardakani@Sun.COM static kt_did_t
1584*11963SAfshin.Ardakani@Sun.COM smb_server_listener_tid(smb_listener_daemon_t *ld)
1585*11963SAfshin.Ardakani@Sun.COM {
1586*11963SAfshin.Ardakani@Sun.COM 	kt_did_t	tid;
1587*11963SAfshin.Ardakani@Sun.COM 
1588*11963SAfshin.Ardakani@Sun.COM 	if (ld->ld_ktdid != 0) {
1589*11963SAfshin.Ardakani@Sun.COM 		tid = ld->ld_ktdid;
1590*11963SAfshin.Ardakani@Sun.COM 		ld->ld_ktdid = 0;
15916139Sjb150015 	}
15926139Sjb150015 
1593*11963SAfshin.Ardakani@Sun.COM 	return (tid);
15946139Sjb150015 }
15956139Sjb150015 
15966139Sjb150015 /*
15976139Sjb150015  * smb_server_lookup
15986139Sjb150015  *
15996139Sjb150015  * This function tries to find the server associated with the zone of the
16006139Sjb150015  * caller.
16016139Sjb150015  */
16026139Sjb150015 static int
16036139Sjb150015 smb_server_lookup(smb_server_t **psv)
16046139Sjb150015 {
16056139Sjb150015 	zoneid_t	zid;
16066139Sjb150015 	smb_server_t	*sv;
16076139Sjb150015 
16086139Sjb150015 	zid = getzoneid();
16096139Sjb150015 
16106139Sjb150015 	smb_llist_enter(&smb_servers, RW_READER);
16116139Sjb150015 	sv = smb_llist_head(&smb_servers);
16126139Sjb150015 	while (sv) {
1613*11963SAfshin.Ardakani@Sun.COM 		SMB_SERVER_VALID(sv);
16146139Sjb150015 		if (sv->sv_zid == zid) {
16156139Sjb150015 			mutex_enter(&sv->sv_mutex);
16166139Sjb150015 			if (sv->sv_state != SMB_SERVER_STATE_DELETING) {
16176139Sjb150015 				sv->sv_refcnt++;
16186139Sjb150015 				mutex_exit(&sv->sv_mutex);
16196139Sjb150015 				smb_llist_exit(&smb_servers);
16206139Sjb150015 				*psv = sv;
16216139Sjb150015 				return (0);
16226139Sjb150015 			}
16236139Sjb150015 			mutex_exit(&sv->sv_mutex);
16246139Sjb150015 			break;
16256139Sjb150015 		}
16266139Sjb150015 		sv = smb_llist_next(&smb_servers, sv);
16276139Sjb150015 	}
16286139Sjb150015 	smb_llist_exit(&smb_servers);
16296139Sjb150015 	return (EPERM);
16306139Sjb150015 }
16316139Sjb150015 
16326139Sjb150015 /*
16336139Sjb150015  * smb_server_release
16346139Sjb150015  *
16356139Sjb150015  * This function decrements the reference count of the server and signals its
16366139Sjb150015  * condition variable if the state of the server is SMB_SERVER_STATE_DELETING.
16376139Sjb150015  */
16386139Sjb150015 static void
16396139Sjb150015 smb_server_release(smb_server_t *sv)
16406139Sjb150015 {
1641*11963SAfshin.Ardakani@Sun.COM 	SMB_SERVER_VALID(sv);
16426139Sjb150015 
16436139Sjb150015 	mutex_enter(&sv->sv_mutex);
16446139Sjb150015 	ASSERT(sv->sv_refcnt);
16456139Sjb150015 	sv->sv_refcnt--;
16466139Sjb150015 	if ((sv->sv_refcnt == 0) && (sv->sv_state == SMB_SERVER_STATE_DELETING))
16476139Sjb150015 		cv_signal(&sv->sv_cv);
16486139Sjb150015 	mutex_exit(&sv->sv_mutex);
16496139Sjb150015 }
16506139Sjb150015 
165110122SJordan.Brown@Sun.COM /*
165210122SJordan.Brown@Sun.COM  * Enumerate the users associated with a session list.
165310122SJordan.Brown@Sun.COM  */
165410122SJordan.Brown@Sun.COM static void
165510122SJordan.Brown@Sun.COM smb_server_enum_private(smb_session_list_t *se, smb_svcenum_t *svcenum)
16566139Sjb150015 {
165710122SJordan.Brown@Sun.COM 	smb_session_t	*sn;
165810122SJordan.Brown@Sun.COM 	smb_llist_t	*ulist;
165910122SJordan.Brown@Sun.COM 	smb_user_t	*user;
166010122SJordan.Brown@Sun.COM 	int		rc = 0;
16616139Sjb150015 
16626139Sjb150015 	rw_enter(&se->se_lock, RW_READER);
16636139Sjb150015 	sn = list_head(&se->se_act.lst);
166410122SJordan.Brown@Sun.COM 
166510122SJordan.Brown@Sun.COM 	while (sn != NULL) {
16666139Sjb150015 		ASSERT(sn->s_magic == SMB_SESSION_MAGIC);
16676139Sjb150015 		ulist = &sn->s_user_list;
16686139Sjb150015 		smb_llist_enter(ulist, RW_READER);
16696139Sjb150015 		user = smb_llist_head(ulist);
167010122SJordan.Brown@Sun.COM 
167110122SJordan.Brown@Sun.COM 		while (user != NULL) {
167210122SJordan.Brown@Sun.COM 			if (smb_user_hold(user)) {
167310122SJordan.Brown@Sun.COM 				rc = smb_user_enum(user, svcenum);
167410122SJordan.Brown@Sun.COM 				smb_user_release(user);
167510122SJordan.Brown@Sun.COM 			}
167610122SJordan.Brown@Sun.COM 
167710122SJordan.Brown@Sun.COM 			user = smb_llist_next(ulist, user);
167810122SJordan.Brown@Sun.COM 		}
167910122SJordan.Brown@Sun.COM 
168010122SJordan.Brown@Sun.COM 		smb_llist_exit(ulist);
168110122SJordan.Brown@Sun.COM 
168210122SJordan.Brown@Sun.COM 		if (rc != 0)
168310122SJordan.Brown@Sun.COM 			break;
168410122SJordan.Brown@Sun.COM 
168510122SJordan.Brown@Sun.COM 		sn = list_next(&se->se_act.lst, sn);
168610122SJordan.Brown@Sun.COM 	}
168710122SJordan.Brown@Sun.COM 
168810122SJordan.Brown@Sun.COM 	rw_exit(&se->se_lock);
168910122SJordan.Brown@Sun.COM }
169010122SJordan.Brown@Sun.COM 
169110122SJordan.Brown@Sun.COM /*
169210122SJordan.Brown@Sun.COM  * Disconnect sessions associated with the specified client and username.
169310122SJordan.Brown@Sun.COM  * Empty strings are treated as wildcards.
169410122SJordan.Brown@Sun.COM  */
169510122SJordan.Brown@Sun.COM static int
169610122SJordan.Brown@Sun.COM smb_server_sesion_disconnect(smb_session_list_t *se,
169710122SJordan.Brown@Sun.COM     const char *client, const char *name)
169810122SJordan.Brown@Sun.COM {
169910122SJordan.Brown@Sun.COM 	smb_session_t	*sn;
170010122SJordan.Brown@Sun.COM 	smb_llist_t	*ulist;
170110122SJordan.Brown@Sun.COM 	smb_user_t	*user;
170210122SJordan.Brown@Sun.COM 	boolean_t	match;
170310122SJordan.Brown@Sun.COM 	int		count = 0;
170410122SJordan.Brown@Sun.COM 
170510122SJordan.Brown@Sun.COM 	rw_enter(&se->se_lock, RW_READER);
170610122SJordan.Brown@Sun.COM 	sn = list_head(&se->se_act.lst);
170710122SJordan.Brown@Sun.COM 
170810122SJordan.Brown@Sun.COM 	while (sn != NULL) {
170910122SJordan.Brown@Sun.COM 		ASSERT(sn->s_magic == SMB_SESSION_MAGIC);
171010122SJordan.Brown@Sun.COM 
171110122SJordan.Brown@Sun.COM 		if ((*client != '\0') && (!smb_session_isclient(sn, client))) {
171210122SJordan.Brown@Sun.COM 			sn = list_next(&se->se_act.lst, sn);
171310122SJordan.Brown@Sun.COM 			continue;
171410122SJordan.Brown@Sun.COM 		}
171510122SJordan.Brown@Sun.COM 
171610122SJordan.Brown@Sun.COM 		ulist = &sn->s_user_list;
171710122SJordan.Brown@Sun.COM 		smb_llist_enter(ulist, RW_READER);
171810122SJordan.Brown@Sun.COM 		user = smb_llist_head(ulist);
171910122SJordan.Brown@Sun.COM 
172010122SJordan.Brown@Sun.COM 		while (user != NULL) {
172110122SJordan.Brown@Sun.COM 			if (smb_user_hold(user)) {
172210122SJordan.Brown@Sun.COM 				match = (*name == '\0');
172310122SJordan.Brown@Sun.COM 				if (!match)
172410122SJordan.Brown@Sun.COM 					match = smb_user_namecmp(user, name);
172510122SJordan.Brown@Sun.COM 
172610122SJordan.Brown@Sun.COM 				if (match) {
172710122SJordan.Brown@Sun.COM 					smb_llist_exit(ulist);
172810122SJordan.Brown@Sun.COM 					smb_user_logoff(user);
172910122SJordan.Brown@Sun.COM 					++count;
173010122SJordan.Brown@Sun.COM 					smb_user_release(user);
173110122SJordan.Brown@Sun.COM 					smb_llist_enter(ulist, RW_READER);
173210122SJordan.Brown@Sun.COM 					user = smb_llist_head(ulist);
173310122SJordan.Brown@Sun.COM 					continue;
17346139Sjb150015 				}
173510122SJordan.Brown@Sun.COM 
173610122SJordan.Brown@Sun.COM 				smb_user_release(user);
17376139Sjb150015 			}
173810122SJordan.Brown@Sun.COM 
17396139Sjb150015 			user = smb_llist_next(ulist, user);
17406139Sjb150015 		}
174110122SJordan.Brown@Sun.COM 
17426139Sjb150015 		smb_llist_exit(ulist);
17437961SNatalie.Li@Sun.COM 		sn = list_next(&se->se_act.lst, sn);
17446139Sjb150015 	}
174510122SJordan.Brown@Sun.COM 
17466139Sjb150015 	rw_exit(&se->se_lock);
174710122SJordan.Brown@Sun.COM 	return (count);
174810122SJordan.Brown@Sun.COM }
174910122SJordan.Brown@Sun.COM 
175010122SJordan.Brown@Sun.COM /*
175110122SJordan.Brown@Sun.COM  * Close a file by its unique id.
175210122SJordan.Brown@Sun.COM  */
175310122SJordan.Brown@Sun.COM static int
175410122SJordan.Brown@Sun.COM smb_server_fclose(smb_session_list_t *se, uint32_t uniqid)
175510122SJordan.Brown@Sun.COM {
175610122SJordan.Brown@Sun.COM 	smb_session_t	*sn;
175710122SJordan.Brown@Sun.COM 	smb_llist_t	*ulist;
175810122SJordan.Brown@Sun.COM 	smb_user_t	*user;
175910122SJordan.Brown@Sun.COM 	int		rc = ENOENT;
176010122SJordan.Brown@Sun.COM 
176110122SJordan.Brown@Sun.COM 	rw_enter(&se->se_lock, RW_READER);
176210122SJordan.Brown@Sun.COM 	sn = list_head(&se->se_act.lst);
176310122SJordan.Brown@Sun.COM 
176410122SJordan.Brown@Sun.COM 	while ((sn != NULL) && (rc == ENOENT)) {
176510122SJordan.Brown@Sun.COM 		ASSERT(sn->s_magic == SMB_SESSION_MAGIC);
176610122SJordan.Brown@Sun.COM 		ulist = &sn->s_user_list;
176710122SJordan.Brown@Sun.COM 		smb_llist_enter(ulist, RW_READER);
176810122SJordan.Brown@Sun.COM 		user = smb_llist_head(ulist);
176910122SJordan.Brown@Sun.COM 
177010122SJordan.Brown@Sun.COM 		while ((user != NULL) && (rc == ENOENT)) {
177110122SJordan.Brown@Sun.COM 			if (smb_user_hold(user)) {
177210122SJordan.Brown@Sun.COM 				rc = smb_user_fclose(user, uniqid);
177310122SJordan.Brown@Sun.COM 				smb_user_release(user);
177410122SJordan.Brown@Sun.COM 			}
177510122SJordan.Brown@Sun.COM 
177610122SJordan.Brown@Sun.COM 			user = smb_llist_next(ulist, user);
177710122SJordan.Brown@Sun.COM 		}
177810122SJordan.Brown@Sun.COM 
177910122SJordan.Brown@Sun.COM 		smb_llist_exit(ulist);
178010122SJordan.Brown@Sun.COM 		sn = list_next(&se->se_act.lst, sn);
178110122SJordan.Brown@Sun.COM 	}
178210122SJordan.Brown@Sun.COM 
178310122SJordan.Brown@Sun.COM 	rw_exit(&se->se_lock);
178410122SJordan.Brown@Sun.COM 	return (rc);
17856139Sjb150015 }
17866139Sjb150015 
17876139Sjb150015 static void
17889832Samw@Sun.COM smb_server_store_cfg(smb_server_t *sv, smb_ioc_cfg_t *ioc)
17896139Sjb150015 {
17909832Samw@Sun.COM 	if (ioc->maxconnections == 0)
17919832Samw@Sun.COM 		ioc->maxconnections = 0xFFFFFFFF;
17926139Sjb150015 
17936139Sjb150015 	smb_session_correct_keep_alive_values(
17949832Samw@Sun.COM 	    &sv->sv_nbt_daemon.ld_session_list, ioc->keepalive);
17956139Sjb150015 	smb_session_correct_keep_alive_values(
17969832Samw@Sun.COM 	    &sv->sv_tcp_daemon.ld_session_list, ioc->keepalive);
17976139Sjb150015 
17989832Samw@Sun.COM 	sv->sv_cfg.skc_maxworkers = ioc->maxworkers;
17999832Samw@Sun.COM 	sv->sv_cfg.skc_maxconnections = ioc->maxconnections;
18009832Samw@Sun.COM 	sv->sv_cfg.skc_keepalive = ioc->keepalive;
18019832Samw@Sun.COM 	sv->sv_cfg.skc_restrict_anon = ioc->restrict_anon;
18029832Samw@Sun.COM 	sv->sv_cfg.skc_signing_enable = ioc->signing_enable;
18039832Samw@Sun.COM 	sv->sv_cfg.skc_signing_required = ioc->signing_required;
18049832Samw@Sun.COM 	sv->sv_cfg.skc_oplock_enable = ioc->oplock_enable;
18059832Samw@Sun.COM 	sv->sv_cfg.skc_sync_enable = ioc->sync_enable;
18069832Samw@Sun.COM 	sv->sv_cfg.skc_secmode = ioc->secmode;
18079832Samw@Sun.COM 	sv->sv_cfg.skc_ipv6_enable = ioc->ipv6_enable;
18089832Samw@Sun.COM 	(void) strlcpy(sv->sv_cfg.skc_nbdomain, ioc->nbdomain,
18099832Samw@Sun.COM 	    sizeof (sv->sv_cfg.skc_nbdomain));
18109832Samw@Sun.COM 	(void) strlcpy(sv->sv_cfg.skc_fqdn, ioc->fqdn,
18119832Samw@Sun.COM 	    sizeof (sv->sv_cfg.skc_fqdn));
18129832Samw@Sun.COM 	(void) strlcpy(sv->sv_cfg.skc_hostname, ioc->hostname,
18139832Samw@Sun.COM 	    sizeof (sv->sv_cfg.skc_hostname));
18149832Samw@Sun.COM 	(void) strlcpy(sv->sv_cfg.skc_system_comment, ioc->system_comment,
18159832Samw@Sun.COM 	    sizeof (sv->sv_cfg.skc_system_comment));
18166139Sjb150015 }
18176139Sjb150015 
18186139Sjb150015 static int
18196139Sjb150015 smb_server_fsop_start(smb_server_t *sv)
18206139Sjb150015 {
18216139Sjb150015 	int	error;
18226139Sjb150015 
18236139Sjb150015 	error = smb_node_root_init(rootdir, sv, &sv->si_root_smb_node);
18246139Sjb150015 	if (error != 0)
18256139Sjb150015 		sv->si_root_smb_node = NULL;
18266139Sjb150015 
18276139Sjb150015 	return (error);
18286139Sjb150015 }
18296139Sjb150015 
18306139Sjb150015 static void
18316139Sjb150015 smb_server_fsop_stop(smb_server_t *sv)
18326139Sjb150015 {
18336139Sjb150015 	if (sv->si_root_smb_node != NULL) {
18346139Sjb150015 		smb_vfs_rele_all(sv);
18356139Sjb150015 		smb_node_release(sv->si_root_smb_node);
18366139Sjb150015 		sv->si_root_smb_node = NULL;
18376139Sjb150015 	}
18386139Sjb150015 }
1839*11963SAfshin.Ardakani@Sun.COM 
1840*11963SAfshin.Ardakani@Sun.COM static void
1841*11963SAfshin.Ardakani@Sun.COM smb_server_signal_listeners(smb_server_t *sv)
1842*11963SAfshin.Ardakani@Sun.COM {
1843*11963SAfshin.Ardakani@Sun.COM 	SMB_SERVER_VALID(sv);
1844*11963SAfshin.Ardakani@Sun.COM 	ASSERT(sv->sv_state == SMB_SERVER_STATE_STOPPING);
1845*11963SAfshin.Ardakani@Sun.COM 	ASSERT(MUTEX_HELD(&sv->sv_mutex));
1846*11963SAfshin.Ardakani@Sun.COM 
1847*11963SAfshin.Ardakani@Sun.COM 	smb_event_cancel(sv, 0);
1848*11963SAfshin.Ardakani@Sun.COM 
1849*11963SAfshin.Ardakani@Sun.COM 	if (sv->sv_nbt_daemon.ld_kth != NULL) {
1850*11963SAfshin.Ardakani@Sun.COM 		tsignal(sv->sv_nbt_daemon.ld_kth, SIGINT);
1851*11963SAfshin.Ardakani@Sun.COM 		sv->sv_nbt_daemon.ld_kth = NULL;
1852*11963SAfshin.Ardakani@Sun.COM 	}
1853*11963SAfshin.Ardakani@Sun.COM 
1854*11963SAfshin.Ardakani@Sun.COM 	if (sv->sv_tcp_daemon.ld_kth != NULL) {
1855*11963SAfshin.Ardakani@Sun.COM 		tsignal(sv->sv_tcp_daemon.ld_kth, SIGINT);
1856*11963SAfshin.Ardakani@Sun.COM 		sv->sv_tcp_daemon.ld_kth = NULL;
1857*11963SAfshin.Ardakani@Sun.COM 	}
1858*11963SAfshin.Ardakani@Sun.COM }
1859*11963SAfshin.Ardakani@Sun.COM 
1860*11963SAfshin.Ardakani@Sun.COM smb_event_t *
1861*11963SAfshin.Ardakani@Sun.COM smb_event_create(void)
1862*11963SAfshin.Ardakani@Sun.COM {
1863*11963SAfshin.Ardakani@Sun.COM 	smb_server_t	*sv;
1864*11963SAfshin.Ardakani@Sun.COM 	smb_event_t	*event;
1865*11963SAfshin.Ardakani@Sun.COM 
1866*11963SAfshin.Ardakani@Sun.COM 	if (smb_server_is_stopping())
1867*11963SAfshin.Ardakani@Sun.COM 		return (NULL);
1868*11963SAfshin.Ardakani@Sun.COM 
1869*11963SAfshin.Ardakani@Sun.COM 	if (smb_server_lookup(&sv) != 0) {
1870*11963SAfshin.Ardakani@Sun.COM 		cmn_err(CE_NOTE, "smb_event_create failed");
1871*11963SAfshin.Ardakani@Sun.COM 		return (NULL);
1872*11963SAfshin.Ardakani@Sun.COM 	}
1873*11963SAfshin.Ardakani@Sun.COM 
1874*11963SAfshin.Ardakani@Sun.COM 	event = kmem_cache_alloc(sv->si_cache_event, KM_SLEEP);
1875*11963SAfshin.Ardakani@Sun.COM 
1876*11963SAfshin.Ardakani@Sun.COM 	bzero(event, sizeof (smb_event_t));
1877*11963SAfshin.Ardakani@Sun.COM 	mutex_init(&event->se_mutex, NULL, MUTEX_DEFAULT, NULL);
1878*11963SAfshin.Ardakani@Sun.COM 	cv_init(&event->se_cv, NULL, CV_DEFAULT, NULL);
1879*11963SAfshin.Ardakani@Sun.COM 	event->se_magic = SMB_EVENT_MAGIC;
1880*11963SAfshin.Ardakani@Sun.COM 	event->se_txid = smb_event_alloc_txid();
1881*11963SAfshin.Ardakani@Sun.COM 	event->se_server = sv;
1882*11963SAfshin.Ardakani@Sun.COM 
1883*11963SAfshin.Ardakani@Sun.COM 	smb_llist_enter(&sv->sv_event_list, RW_WRITER);
1884*11963SAfshin.Ardakani@Sun.COM 	smb_llist_insert_tail(&sv->sv_event_list, event);
1885*11963SAfshin.Ardakani@Sun.COM 	smb_llist_exit(&sv->sv_event_list);
1886*11963SAfshin.Ardakani@Sun.COM 
1887*11963SAfshin.Ardakani@Sun.COM 	smb_server_release(sv);
1888*11963SAfshin.Ardakani@Sun.COM 	return (event);
1889*11963SAfshin.Ardakani@Sun.COM }
1890*11963SAfshin.Ardakani@Sun.COM 
1891*11963SAfshin.Ardakani@Sun.COM void
1892*11963SAfshin.Ardakani@Sun.COM smb_event_destroy(smb_event_t *event)
1893*11963SAfshin.Ardakani@Sun.COM {
1894*11963SAfshin.Ardakani@Sun.COM 	smb_server_t	*sv;
1895*11963SAfshin.Ardakani@Sun.COM 
1896*11963SAfshin.Ardakani@Sun.COM 	if (event == NULL)
1897*11963SAfshin.Ardakani@Sun.COM 		return;
1898*11963SAfshin.Ardakani@Sun.COM 
1899*11963SAfshin.Ardakani@Sun.COM 	SMB_EVENT_VALID(event);
1900*11963SAfshin.Ardakani@Sun.COM 	ASSERT(event->se_waittime == 0);
1901*11963SAfshin.Ardakani@Sun.COM 
1902*11963SAfshin.Ardakani@Sun.COM 	if (smb_server_lookup(&sv) != 0)
1903*11963SAfshin.Ardakani@Sun.COM 		return;
1904*11963SAfshin.Ardakani@Sun.COM 
1905*11963SAfshin.Ardakani@Sun.COM 	smb_llist_enter(&sv->sv_event_list, RW_WRITER);
1906*11963SAfshin.Ardakani@Sun.COM 	smb_llist_remove(&sv->sv_event_list, event);
1907*11963SAfshin.Ardakani@Sun.COM 	smb_llist_exit(&sv->sv_event_list);
1908*11963SAfshin.Ardakani@Sun.COM 
1909*11963SAfshin.Ardakani@Sun.COM 	event->se_magic = (uint32_t)~SMB_EVENT_MAGIC;
1910*11963SAfshin.Ardakani@Sun.COM 	cv_destroy(&event->se_cv);
1911*11963SAfshin.Ardakani@Sun.COM 	mutex_destroy(&event->se_mutex);
1912*11963SAfshin.Ardakani@Sun.COM 
1913*11963SAfshin.Ardakani@Sun.COM 	kmem_cache_free(sv->si_cache_event, event);
1914*11963SAfshin.Ardakani@Sun.COM 	smb_server_release(sv);
1915*11963SAfshin.Ardakani@Sun.COM }
1916*11963SAfshin.Ardakani@Sun.COM 
1917*11963SAfshin.Ardakani@Sun.COM /*
1918*11963SAfshin.Ardakani@Sun.COM  * Get the txid for the specified event.
1919*11963SAfshin.Ardakani@Sun.COM  */
1920*11963SAfshin.Ardakani@Sun.COM uint32_t
1921*11963SAfshin.Ardakani@Sun.COM smb_event_txid(smb_event_t *event)
1922*11963SAfshin.Ardakani@Sun.COM {
1923*11963SAfshin.Ardakani@Sun.COM 	if (event != NULL) {
1924*11963SAfshin.Ardakani@Sun.COM 		SMB_EVENT_VALID(event);
1925*11963SAfshin.Ardakani@Sun.COM 		return (event->se_txid);
1926*11963SAfshin.Ardakani@Sun.COM 	}
1927*11963SAfshin.Ardakani@Sun.COM 
1928*11963SAfshin.Ardakani@Sun.COM 	cmn_err(CE_NOTE, "smb_event_txid failed");
1929*11963SAfshin.Ardakani@Sun.COM 	return ((uint32_t)-1);
1930*11963SAfshin.Ardakani@Sun.COM }
1931*11963SAfshin.Ardakani@Sun.COM 
1932*11963SAfshin.Ardakani@Sun.COM /*
1933*11963SAfshin.Ardakani@Sun.COM  * Wait for event notification.
1934*11963SAfshin.Ardakani@Sun.COM  */
1935*11963SAfshin.Ardakani@Sun.COM int
1936*11963SAfshin.Ardakani@Sun.COM smb_event_wait(smb_event_t *event)
1937*11963SAfshin.Ardakani@Sun.COM {
1938*11963SAfshin.Ardakani@Sun.COM 	int	seconds = 1;
1939*11963SAfshin.Ardakani@Sun.COM 	int	ticks;
1940*11963SAfshin.Ardakani@Sun.COM 
1941*11963SAfshin.Ardakani@Sun.COM 	if (event == NULL)
1942*11963SAfshin.Ardakani@Sun.COM 		return (EINVAL);
1943*11963SAfshin.Ardakani@Sun.COM 
1944*11963SAfshin.Ardakani@Sun.COM 	SMB_EVENT_VALID(event);
1945*11963SAfshin.Ardakani@Sun.COM 
1946*11963SAfshin.Ardakani@Sun.COM 	mutex_enter(&event->se_mutex);
1947*11963SAfshin.Ardakani@Sun.COM 	event->se_waittime = 1;
1948*11963SAfshin.Ardakani@Sun.COM 	event->se_errno = 0;
1949*11963SAfshin.Ardakani@Sun.COM 
1950*11963SAfshin.Ardakani@Sun.COM 	while (!(event->se_notified)) {
1951*11963SAfshin.Ardakani@Sun.COM 		if (smb_event_debug && ((event->se_waittime % 10) == 0))
1952*11963SAfshin.Ardakani@Sun.COM 			cmn_err(CE_NOTE, "smb_event_wait[%d] (%d sec)",
1953*11963SAfshin.Ardakani@Sun.COM 			    event->se_txid, event->se_waittime);
1954*11963SAfshin.Ardakani@Sun.COM 
1955*11963SAfshin.Ardakani@Sun.COM 		if (event->se_errno != 0)
1956*11963SAfshin.Ardakani@Sun.COM 			break;
1957*11963SAfshin.Ardakani@Sun.COM 
1958*11963SAfshin.Ardakani@Sun.COM 		if (event->se_waittime > SMB_EVENT_TIMEOUT) {
1959*11963SAfshin.Ardakani@Sun.COM 			event->se_errno = ETIME;
1960*11963SAfshin.Ardakani@Sun.COM 			break;
1961*11963SAfshin.Ardakani@Sun.COM 		}
1962*11963SAfshin.Ardakani@Sun.COM 
1963*11963SAfshin.Ardakani@Sun.COM 		ticks = SEC_TO_TICK(seconds);
1964*11963SAfshin.Ardakani@Sun.COM 		(void) cv_reltimedwait(&event->se_cv,
1965*11963SAfshin.Ardakani@Sun.COM 		    &event->se_mutex, (clock_t)ticks, TR_CLOCK_TICK);
1966*11963SAfshin.Ardakani@Sun.COM 		++event->se_waittime;
1967*11963SAfshin.Ardakani@Sun.COM 	}
1968*11963SAfshin.Ardakani@Sun.COM 
1969*11963SAfshin.Ardakani@Sun.COM 	event->se_waittime = 0;
1970*11963SAfshin.Ardakani@Sun.COM 	event->se_notified = B_FALSE;
1971*11963SAfshin.Ardakani@Sun.COM 	cv_signal(&event->se_cv);
1972*11963SAfshin.Ardakani@Sun.COM 	mutex_exit(&event->se_mutex);
1973*11963SAfshin.Ardakani@Sun.COM 	return (event->se_errno);
1974*11963SAfshin.Ardakani@Sun.COM }
1975*11963SAfshin.Ardakani@Sun.COM 
1976*11963SAfshin.Ardakani@Sun.COM /*
1977*11963SAfshin.Ardakani@Sun.COM  * If txid is non-zero, cancel the specified event.
1978*11963SAfshin.Ardakani@Sun.COM  * Otherwise, cancel all events.
1979*11963SAfshin.Ardakani@Sun.COM  */
1980*11963SAfshin.Ardakani@Sun.COM static void
1981*11963SAfshin.Ardakani@Sun.COM smb_event_cancel(smb_server_t *sv, uint32_t txid)
1982*11963SAfshin.Ardakani@Sun.COM {
1983*11963SAfshin.Ardakani@Sun.COM 	smb_event_t	*event;
1984*11963SAfshin.Ardakani@Sun.COM 	smb_llist_t	*event_list;
1985*11963SAfshin.Ardakani@Sun.COM 
1986*11963SAfshin.Ardakani@Sun.COM 	SMB_SERVER_VALID(sv);
1987*11963SAfshin.Ardakani@Sun.COM 
1988*11963SAfshin.Ardakani@Sun.COM 	event_list = &sv->sv_event_list;
1989*11963SAfshin.Ardakani@Sun.COM 	smb_llist_enter(event_list, RW_WRITER);
1990*11963SAfshin.Ardakani@Sun.COM 
1991*11963SAfshin.Ardakani@Sun.COM 	event = smb_llist_head(event_list);
1992*11963SAfshin.Ardakani@Sun.COM 	while (event) {
1993*11963SAfshin.Ardakani@Sun.COM 		SMB_EVENT_VALID(event);
1994*11963SAfshin.Ardakani@Sun.COM 
1995*11963SAfshin.Ardakani@Sun.COM 		if (txid == 0 || event->se_txid == txid) {
1996*11963SAfshin.Ardakani@Sun.COM 			mutex_enter(&event->se_mutex);
1997*11963SAfshin.Ardakani@Sun.COM 			event->se_errno = ECANCELED;
1998*11963SAfshin.Ardakani@Sun.COM 			event->se_notified = B_TRUE;
1999*11963SAfshin.Ardakani@Sun.COM 			cv_signal(&event->se_cv);
2000*11963SAfshin.Ardakani@Sun.COM 			mutex_exit(&event->se_mutex);
2001*11963SAfshin.Ardakani@Sun.COM 
2002*11963SAfshin.Ardakani@Sun.COM 			if (txid != 0)
2003*11963SAfshin.Ardakani@Sun.COM 				break;
2004*11963SAfshin.Ardakani@Sun.COM 		}
2005*11963SAfshin.Ardakani@Sun.COM 
2006*11963SAfshin.Ardakani@Sun.COM 		event = smb_llist_next(event_list, event);
2007*11963SAfshin.Ardakani@Sun.COM 	}
2008*11963SAfshin.Ardakani@Sun.COM 
2009*11963SAfshin.Ardakani@Sun.COM 	smb_llist_exit(event_list);
2010*11963SAfshin.Ardakani@Sun.COM }
2011*11963SAfshin.Ardakani@Sun.COM 
2012*11963SAfshin.Ardakani@Sun.COM /*
2013*11963SAfshin.Ardakani@Sun.COM  * If txid is non-zero, notify the specified event.
2014*11963SAfshin.Ardakani@Sun.COM  * Otherwise, notify all events.
2015*11963SAfshin.Ardakani@Sun.COM  */
2016*11963SAfshin.Ardakani@Sun.COM static void
2017*11963SAfshin.Ardakani@Sun.COM smb_event_notify(smb_server_t *sv, uint32_t txid)
2018*11963SAfshin.Ardakani@Sun.COM {
2019*11963SAfshin.Ardakani@Sun.COM 	smb_event_t	*event;
2020*11963SAfshin.Ardakani@Sun.COM 	smb_llist_t	*event_list;
2021*11963SAfshin.Ardakani@Sun.COM 
2022*11963SAfshin.Ardakani@Sun.COM 	SMB_SERVER_VALID(sv);
2023*11963SAfshin.Ardakani@Sun.COM 
2024*11963SAfshin.Ardakani@Sun.COM 	event_list = &sv->sv_event_list;
2025*11963SAfshin.Ardakani@Sun.COM 	smb_llist_enter(event_list, RW_READER);
2026*11963SAfshin.Ardakani@Sun.COM 
2027*11963SAfshin.Ardakani@Sun.COM 	event = smb_llist_head(event_list);
2028*11963SAfshin.Ardakani@Sun.COM 	while (event) {
2029*11963SAfshin.Ardakani@Sun.COM 		SMB_EVENT_VALID(event);
2030*11963SAfshin.Ardakani@Sun.COM 
2031*11963SAfshin.Ardakani@Sun.COM 		if (txid == 0 || event->se_txid == txid) {
2032*11963SAfshin.Ardakani@Sun.COM 			mutex_enter(&event->se_mutex);
2033*11963SAfshin.Ardakani@Sun.COM 			event->se_notified = B_TRUE;
2034*11963SAfshin.Ardakani@Sun.COM 			cv_signal(&event->se_cv);
2035*11963SAfshin.Ardakani@Sun.COM 			mutex_exit(&event->se_mutex);
2036*11963SAfshin.Ardakani@Sun.COM 
2037*11963SAfshin.Ardakani@Sun.COM 			if (txid != 0)
2038*11963SAfshin.Ardakani@Sun.COM 				break;
2039*11963SAfshin.Ardakani@Sun.COM 		}
2040*11963SAfshin.Ardakani@Sun.COM 
2041*11963SAfshin.Ardakani@Sun.COM 		event = smb_llist_next(event_list, event);
2042*11963SAfshin.Ardakani@Sun.COM 	}
2043*11963SAfshin.Ardakani@Sun.COM 
2044*11963SAfshin.Ardakani@Sun.COM 	smb_llist_exit(event_list);
2045*11963SAfshin.Ardakani@Sun.COM }
2046*11963SAfshin.Ardakani@Sun.COM 
2047*11963SAfshin.Ardakani@Sun.COM /*
2048*11963SAfshin.Ardakani@Sun.COM  * Allocate a new transaction id (txid).
2049*11963SAfshin.Ardakani@Sun.COM  *
2050*11963SAfshin.Ardakani@Sun.COM  * 0 or -1 are not assigned because they are used to detect invalid
2051*11963SAfshin.Ardakani@Sun.COM  * conditions or to indicate all open id's.
2052*11963SAfshin.Ardakani@Sun.COM  */
2053*11963SAfshin.Ardakani@Sun.COM static uint32_t
2054*11963SAfshin.Ardakani@Sun.COM smb_event_alloc_txid(void)
2055*11963SAfshin.Ardakani@Sun.COM {
2056*11963SAfshin.Ardakani@Sun.COM 	static kmutex_t	txmutex;
2057*11963SAfshin.Ardakani@Sun.COM 	static uint32_t	txid;
2058*11963SAfshin.Ardakani@Sun.COM 	uint32_t	txid_ret;
2059*11963SAfshin.Ardakani@Sun.COM 
2060*11963SAfshin.Ardakani@Sun.COM 	mutex_enter(&txmutex);
2061*11963SAfshin.Ardakani@Sun.COM 
2062*11963SAfshin.Ardakani@Sun.COM 	if (txid == 0)
2063*11963SAfshin.Ardakani@Sun.COM 		txid = ddi_get_lbolt() << 11;
2064*11963SAfshin.Ardakani@Sun.COM 
2065*11963SAfshin.Ardakani@Sun.COM 	do {
2066*11963SAfshin.Ardakani@Sun.COM 		++txid;
2067*11963SAfshin.Ardakani@Sun.COM 	} while (txid == 0 || txid == (uint32_t)-1);
2068*11963SAfshin.Ardakani@Sun.COM 
2069*11963SAfshin.Ardakani@Sun.COM 	txid_ret = txid;
2070*11963SAfshin.Ardakani@Sun.COM 	mutex_exit(&txmutex);
2071*11963SAfshin.Ardakani@Sun.COM 
2072*11963SAfshin.Ardakani@Sun.COM 	return (txid_ret);
2073*11963SAfshin.Ardakani@Sun.COM }
2074