xref: /titanic_44/usr/src/uts/common/fs/smbsrv/smb_session.c (revision b819cea2f73f98c5662230cc9affc8cc84f77fcf)
1da6c28aaSamw /*
2da6c28aaSamw  * CDDL HEADER START
3da6c28aaSamw  *
4da6c28aaSamw  * The contents of this file are subject to the terms of the
5da6c28aaSamw  * Common Development and Distribution License (the "License").
6da6c28aaSamw  * You may not use this file except in compliance with the License.
7da6c28aaSamw  *
8da6c28aaSamw  * You can obtain a copy of the license at usr/src/OPENSOLARIS.LICENSE
9da6c28aaSamw  * or http://www.opensolaris.org/os/licensing.
10da6c28aaSamw  * See the License for the specific language governing permissions
11da6c28aaSamw  * and limitations under the License.
12da6c28aaSamw  *
13da6c28aaSamw  * When distributing Covered Code, include this CDDL HEADER in each
14da6c28aaSamw  * file and include the License file at usr/src/OPENSOLARIS.LICENSE.
15da6c28aaSamw  * If applicable, add the following below this CDDL HEADER, with the
16da6c28aaSamw  * fields enclosed by brackets "[]" replaced with your own identifying
17da6c28aaSamw  * information: Portions Copyright [yyyy] [name of copyright owner]
18da6c28aaSamw  *
19da6c28aaSamw  * CDDL HEADER END
20da6c28aaSamw  */
21da6c28aaSamw /*
22148c5f43SAlan Wright  * Copyright (c) 2007, 2010, Oracle and/or its affiliates. All rights reserved.
23*b819cea2SGordon Ross  * Copyright 2013 Nexenta Systems, Inc.  All rights reserved.
24da6c28aaSamw  */
25*b819cea2SGordon Ross 
26da6c28aaSamw #include <sys/atomic.h>
27da6c28aaSamw #include <sys/synch.h>
28da6c28aaSamw #include <sys/types.h>
29da6c28aaSamw #include <sys/sdt.h>
30f9bc6dadSDmitry.Savitsky@nexenta.com #include <sys/random.h>
31da6c28aaSamw #include <smbsrv/netbios.h>
32bbf6f00cSJordan Brown #include <smbsrv/smb_kproto.h>
33bbf6f00cSJordan Brown #include <smbsrv/string.h>
34*b819cea2SGordon Ross #include <netinet/tcp.h>
35*b819cea2SGordon Ross 
36*b819cea2SGordon Ross #define	SMB_NEW_KID()	atomic_inc_64_nv(&smb_kids)
37da6c28aaSamw 
38faa1795aSjb150015 static volatile uint64_t smb_kids;
39da6c28aaSamw 
40*b819cea2SGordon Ross /*
41*b819cea2SGordon Ross  * We track the keepalive in minutes, but this constant
42*b819cea2SGordon Ross  * specifies it in seconds, so convert to minutes.
43*b819cea2SGordon Ross  */
44*b819cea2SGordon Ross uint32_t smb_keep_alive = SMB_PI_KEEP_ALIVE_MIN / 60;
45da6c28aaSamw 
462c2961f8Sjose borrego static void smb_session_cancel(smb_session_t *);
47da6c28aaSamw static int smb_session_message(smb_session_t *);
48da6c28aaSamw static int smb_session_xprt_puthdr(smb_session_t *, smb_xprt_t *,
49da6c28aaSamw     uint8_t *, size_t);
50b89a8333Snatalie li - Sun Microsystems - Irvine United States static smb_user_t *smb_session_lookup_user(smb_session_t *, char *, char *);
513b13a1efSThomas Keiser static smb_tree_t *smb_session_get_tree(smb_session_t *, smb_tree_t *);
529fb67ea3Safshin salek ardakani - Sun Microsystems - Irvine United States static void smb_session_logoff(smb_session_t *);
53faa1795aSjb150015 static void smb_request_init_command_mbuf(smb_request_t *sr);
547f667e74Sjose borrego void dump_smb_inaddr(smb_inaddr_t *ipaddr);
55f9bc6dadSDmitry.Savitsky@nexenta.com static void smb_session_genkey(smb_session_t *);
56da6c28aaSamw 
57da6c28aaSamw void
smb_session_timers(smb_llist_t * ll)584163af6aSjose borrego smb_session_timers(smb_llist_t *ll)
59da6c28aaSamw {
60faa1795aSjb150015 	smb_session_t	*session;
61da6c28aaSamw 
624163af6aSjose borrego 	smb_llist_enter(ll, RW_READER);
634163af6aSjose borrego 	session = smb_llist_head(ll);
644163af6aSjose borrego 	while (session != NULL) {
65da6c28aaSamw 		/*
66da6c28aaSamw 		 * Walk through the table and decrement each keep_alive
67da6c28aaSamw 		 * timer that has not timed out yet. (keepalive > 0)
68da6c28aaSamw 		 */
694163af6aSjose borrego 		SMB_SESSION_VALID(session);
70faa1795aSjb150015 		if (session->keep_alive &&
71faa1795aSjb150015 		    (session->keep_alive != (uint32_t)-1))
72faa1795aSjb150015 			session->keep_alive--;
734163af6aSjose borrego 		session = smb_llist_next(ll, session);
74faa1795aSjb150015 	}
754163af6aSjose borrego 	smb_llist_exit(ll);
76faa1795aSjb150015 }
77da6c28aaSamw 
78faa1795aSjb150015 void
smb_session_correct_keep_alive_values(smb_llist_t * ll,uint32_t new_keep_alive)794163af6aSjose borrego smb_session_correct_keep_alive_values(smb_llist_t *ll, uint32_t new_keep_alive)
80faa1795aSjb150015 {
81faa1795aSjb150015 	smb_session_t		*sn;
82faa1795aSjb150015 
83*b819cea2SGordon Ross 	/*
84*b819cea2SGordon Ross 	 * Caller specifies seconds, but we track in minutes, so
85*b819cea2SGordon Ross 	 * convert to minutes (rounded up).
86*b819cea2SGordon Ross 	 */
87*b819cea2SGordon Ross 	new_keep_alive = (new_keep_alive + 59) / 60;
88*b819cea2SGordon Ross 
89faa1795aSjb150015 	if (new_keep_alive == smb_keep_alive)
90faa1795aSjb150015 		return;
91faa1795aSjb150015 	/*
92faa1795aSjb150015 	 * keep alive == 0 means do not drop connection if it's idle
93faa1795aSjb150015 	 */
94faa1795aSjb150015 	smb_keep_alive = (new_keep_alive) ? new_keep_alive : -1;
95faa1795aSjb150015 
96faa1795aSjb150015 	/*
97faa1795aSjb150015 	 * Walk through the table and set each session to the new keep_alive
98faa1795aSjb150015 	 * value if they have not already timed out.  Block clock interrupts.
99faa1795aSjb150015 	 */
1004163af6aSjose borrego 	smb_llist_enter(ll, RW_READER);
1014163af6aSjose borrego 	sn = smb_llist_head(ll);
1024163af6aSjose borrego 	while (sn != NULL) {
1034163af6aSjose borrego 		SMB_SESSION_VALID(sn);
1044163af6aSjose borrego 		if (sn->keep_alive != 0)
105faa1795aSjb150015 			sn->keep_alive = new_keep_alive;
1064163af6aSjose borrego 		sn = smb_llist_next(ll, sn);
107da6c28aaSamw 	}
1084163af6aSjose borrego 	smb_llist_exit(ll);
109da6c28aaSamw }
110da6c28aaSamw 
111da6c28aaSamw /*
112da6c28aaSamw  * Send a session message - supports SMB-over-NBT and SMB-over-TCP.
113da6c28aaSamw  *
114da6c28aaSamw  * The mbuf chain is copied into a contiguous buffer so that the whole
115da6c28aaSamw  * message is submitted to smb_sosend as a single request.  This should
116da6c28aaSamw  * help Ethereal/Wireshark delineate the packets correctly even though
117da6c28aaSamw  * TCP_NODELAY has been set on the socket.
118da6c28aaSamw  *
119da6c28aaSamw  * If an mbuf chain is provided, it will be freed and set to NULL here.
120da6c28aaSamw  */
121da6c28aaSamw int
smb_session_send(smb_session_t * session,uint8_t type,mbuf_chain_t * mbc)12221b7895dSjb150015 smb_session_send(smb_session_t *session, uint8_t type, mbuf_chain_t *mbc)
123da6c28aaSamw {
12421b7895dSjb150015 	smb_txreq_t	*txr;
125da6c28aaSamw 	smb_xprt_t	hdr;
126da6c28aaSamw 	int		rc;
127da6c28aaSamw 
128da6c28aaSamw 	switch (session->s_state) {
129da6c28aaSamw 	case SMB_SESSION_STATE_DISCONNECTED:
130da6c28aaSamw 	case SMB_SESSION_STATE_TERMINATED:
131da6c28aaSamw 		if ((mbc != NULL) && (mbc->chain != NULL)) {
132da6c28aaSamw 			m_freem(mbc->chain);
133da6c28aaSamw 			mbc->chain = NULL;
134da6c28aaSamw 			mbc->flags = 0;
135da6c28aaSamw 		}
136da6c28aaSamw 		return (ENOTCONN);
137da6c28aaSamw 	default:
138da6c28aaSamw 		break;
139da6c28aaSamw 	}
140da6c28aaSamw 
14121b7895dSjb150015 	txr = smb_net_txr_alloc();
142da6c28aaSamw 
143da6c28aaSamw 	if ((mbc != NULL) && (mbc->chain != NULL)) {
14421b7895dSjb150015 		rc = mbc_moveout(mbc, (caddr_t)&txr->tr_buf[NETBIOS_HDR_SZ],
14521b7895dSjb150015 		    sizeof (txr->tr_buf) - NETBIOS_HDR_SZ, &txr->tr_len);
14621b7895dSjb150015 		if (rc != 0) {
14721b7895dSjb150015 			smb_net_txr_free(txr);
14821b7895dSjb150015 			return (rc);
149da6c28aaSamw 		}
150da6c28aaSamw 	}
151da6c28aaSamw 
152da6c28aaSamw 	hdr.xh_type = type;
15321b7895dSjb150015 	hdr.xh_length = (uint32_t)txr->tr_len;
154da6c28aaSamw 
15521b7895dSjb150015 	rc = smb_session_xprt_puthdr(session, &hdr, txr->tr_buf,
1565cdbe942Sjb150015 	    NETBIOS_HDR_SZ);
15721b7895dSjb150015 
15821b7895dSjb150015 	if (rc != 0) {
15921b7895dSjb150015 		smb_net_txr_free(txr);
160da6c28aaSamw 		return (rc);
161da6c28aaSamw 	}
16221b7895dSjb150015 	txr->tr_len += NETBIOS_HDR_SZ;
163148c5f43SAlan Wright 	smb_server_add_txb(session->s_server, (int64_t)txr->tr_len);
16421b7895dSjb150015 	return (smb_net_txr_send(session->sock, &session->s_txlst, txr));
16521b7895dSjb150015 }
166da6c28aaSamw 
167da6c28aaSamw /*
168da6c28aaSamw  * Read, process and respond to a NetBIOS session request.
169da6c28aaSamw  *
170da6c28aaSamw  * A NetBIOS session must be established for SMB-over-NetBIOS.  Validate
171da6c28aaSamw  * the calling and called name format and save the client NetBIOS name,
172da6c28aaSamw  * which is used when a NetBIOS session is established to check for and
173da6c28aaSamw  * cleanup leftover state from a previous session.
174da6c28aaSamw  *
175da6c28aaSamw  * Session requests are not valid for SMB-over-TCP, which is unfortunate
176da6c28aaSamw  * because without the client name leftover state cannot be cleaned up
177da6c28aaSamw  * if the client is behind a NAT server.
178da6c28aaSamw  */
179da6c28aaSamw static int
smb_session_request(struct smb_session * session)180da6c28aaSamw smb_session_request(struct smb_session *session)
181da6c28aaSamw {
182da6c28aaSamw 	int			rc;
183da6c28aaSamw 	char			*calling_name;
184da6c28aaSamw 	char			*called_name;
185da6c28aaSamw 	char 			client_name[NETBIOS_NAME_SZ];
186da6c28aaSamw 	struct mbuf_chain 	mbc;
187da6c28aaSamw 	char 			*names = NULL;
188bbf6f00cSJordan Brown 	smb_wchar_t		*wbuf = NULL;
189da6c28aaSamw 	smb_xprt_t		hdr;
190da6c28aaSamw 	char *p;
191da6c28aaSamw 	int rc1, rc2;
192da6c28aaSamw 
193da6c28aaSamw 	session->keep_alive = smb_keep_alive;
194da6c28aaSamw 
195faa1795aSjb150015 	if ((rc = smb_session_xprt_gethdr(session, &hdr)) != 0)
196faa1795aSjb150015 		return (rc);
197da6c28aaSamw 
198da6c28aaSamw 	DTRACE_PROBE2(receive__session__req__xprthdr, struct session *, session,
199da6c28aaSamw 	    smb_xprt_t *, &hdr);
200da6c28aaSamw 
201da6c28aaSamw 	if ((hdr.xh_type != SESSION_REQUEST) ||
202da6c28aaSamw 	    (hdr.xh_length != NETBIOS_SESSION_REQUEST_DATA_LENGTH)) {
203da6c28aaSamw 		DTRACE_PROBE1(receive__session__req__failed,
204da6c28aaSamw 		    struct session *, session);
205da6c28aaSamw 		return (EINVAL);
206da6c28aaSamw 	}
207da6c28aaSamw 
208da6c28aaSamw 	names = kmem_alloc(hdr.xh_length, KM_SLEEP);
209da6c28aaSamw 
210da6c28aaSamw 	if ((rc = smb_sorecv(session->sock, names, hdr.xh_length)) != 0) {
211da6c28aaSamw 		kmem_free(names, hdr.xh_length);
212da6c28aaSamw 		DTRACE_PROBE1(receive__session__req__failed,
213da6c28aaSamw 		    struct session *, session);
214da6c28aaSamw 		return (rc);
215da6c28aaSamw 	}
216da6c28aaSamw 
217da6c28aaSamw 	DTRACE_PROBE3(receive__session__req__data, struct session *, session,
218da6c28aaSamw 	    char *, names, uint32_t, hdr.xh_length);
219da6c28aaSamw 
220da6c28aaSamw 	called_name = &names[0];
221da6c28aaSamw 	calling_name = &names[NETBIOS_ENCODED_NAME_SZ + 2];
222da6c28aaSamw 
223da6c28aaSamw 	rc1 = netbios_name_isvalid(called_name, 0);
224da6c28aaSamw 	rc2 = netbios_name_isvalid(calling_name, client_name);
225da6c28aaSamw 
226da6c28aaSamw 	if (rc1 == 0 || rc2 == 0) {
227da6c28aaSamw 
228da6c28aaSamw 		DTRACE_PROBE3(receive__invalid__session__req,
229da6c28aaSamw 		    struct session *, session, char *, names,
230da6c28aaSamw 		    uint32_t, hdr.xh_length);
231da6c28aaSamw 
232da6c28aaSamw 		kmem_free(names, hdr.xh_length);
233da6c28aaSamw 		MBC_INIT(&mbc, MAX_DATAGRAM_LENGTH);
2343db3f65cSamw 		(void) smb_mbc_encodef(&mbc, "b",
235da6c28aaSamw 		    DATAGRAM_INVALID_SOURCE_NAME_FORMAT);
236da6c28aaSamw 		(void) smb_session_send(session, NEGATIVE_SESSION_RESPONSE,
237da6c28aaSamw 		    &mbc);
238da6c28aaSamw 		return (EINVAL);
239da6c28aaSamw 	}
240da6c28aaSamw 
241da6c28aaSamw 	DTRACE_PROBE3(receive__session__req__calling__decoded,
242da6c28aaSamw 	    struct session *, session,
243da6c28aaSamw 	    char *, calling_name, char *, client_name);
244da6c28aaSamw 
245da6c28aaSamw 	/*
246da6c28aaSamw 	 * The client NetBIOS name is in oem codepage format.
247da6c28aaSamw 	 * We need to convert it to unicode and store it in
248da6c28aaSamw 	 * multi-byte format.  We also need to strip off any
249da6c28aaSamw 	 * spaces added as part of the NetBIOS name encoding.
250da6c28aaSamw 	 */
251bbf6f00cSJordan Brown 	wbuf = kmem_alloc((SMB_PI_MAX_HOST * sizeof (smb_wchar_t)), KM_SLEEP);
252bbf6f00cSJordan Brown 	(void) oemtoucs(wbuf, client_name, SMB_PI_MAX_HOST, OEM_CPG_850);
253bbf6f00cSJordan Brown 	(void) smb_wcstombs(session->workstation, wbuf, SMB_PI_MAX_HOST);
254bbf6f00cSJordan Brown 	kmem_free(wbuf, (SMB_PI_MAX_HOST * sizeof (smb_wchar_t)));
255da6c28aaSamw 
256da6c28aaSamw 	if ((p = strchr(session->workstation, ' ')) != 0)
257da6c28aaSamw 		*p = '\0';
258da6c28aaSamw 
259da6c28aaSamw 	kmem_free(names, hdr.xh_length);
260da6c28aaSamw 	return (smb_session_send(session, POSITIVE_SESSION_RESPONSE, NULL));
261da6c28aaSamw }
262da6c28aaSamw 
263da6c28aaSamw /*
264da6c28aaSamw  * Read 4-byte header from the session socket and build an in-memory
265da6c28aaSamw  * session transport header.  See smb_xprt_t definition for header
266da6c28aaSamw  * format information.
267da6c28aaSamw  *
268da6c28aaSamw  * Direct hosted NetBIOS-less SMB (SMB-over-TCP) uses port 445.  The
269da6c28aaSamw  * first byte of the four-byte header must be 0 and the next three
270da6c28aaSamw  * bytes contain the length of the remaining data.
271da6c28aaSamw  */
272da6c28aaSamw int
smb_session_xprt_gethdr(smb_session_t * session,smb_xprt_t * ret_hdr)273da6c28aaSamw smb_session_xprt_gethdr(smb_session_t *session, smb_xprt_t *ret_hdr)
274da6c28aaSamw {
275faa1795aSjb150015 	int		rc;
276da6c28aaSamw 	unsigned char	buf[NETBIOS_HDR_SZ];
277da6c28aaSamw 
278faa1795aSjb150015 	if ((rc = smb_sorecv(session->sock, buf, NETBIOS_HDR_SZ)) != 0)
279faa1795aSjb150015 		return (rc);
280da6c28aaSamw 
281da6c28aaSamw 	switch (session->s_local_port) {
282a0aa776eSAlan Wright 	case IPPORT_NETBIOS_SSN:
283da6c28aaSamw 		ret_hdr->xh_type = buf[0];
284da6c28aaSamw 		ret_hdr->xh_length = (((uint32_t)buf[1] & 1) << 16) |
285da6c28aaSamw 		    ((uint32_t)buf[2] << 8) |
286da6c28aaSamw 		    ((uint32_t)buf[3]);
287da6c28aaSamw 		break;
288da6c28aaSamw 
289a0aa776eSAlan Wright 	case IPPORT_SMB:
290da6c28aaSamw 		ret_hdr->xh_type = buf[0];
291da6c28aaSamw 
292da6c28aaSamw 		if (ret_hdr->xh_type != 0) {
2937f667e74Sjose borrego 			cmn_err(CE_WARN, "invalid type (%u)", ret_hdr->xh_type);
2947f667e74Sjose borrego 			dump_smb_inaddr(&session->ipaddr);
295faa1795aSjb150015 			return (EPROTO);
296da6c28aaSamw 		}
297da6c28aaSamw 
298da6c28aaSamw 		ret_hdr->xh_length = ((uint32_t)buf[1] << 16) |
299da6c28aaSamw 		    ((uint32_t)buf[2] << 8) |
300da6c28aaSamw 		    ((uint32_t)buf[3]);
301da6c28aaSamw 		break;
302da6c28aaSamw 
303da6c28aaSamw 	default:
3047f667e74Sjose borrego 		cmn_err(CE_WARN, "invalid port %u", session->s_local_port);
3057f667e74Sjose borrego 		dump_smb_inaddr(&session->ipaddr);
306faa1795aSjb150015 		return (EPROTO);
307da6c28aaSamw 	}
308da6c28aaSamw 
309da6c28aaSamw 	return (0);
310da6c28aaSamw }
311da6c28aaSamw 
312da6c28aaSamw /*
313da6c28aaSamw  * Encode a transport session packet header into a 4-byte buffer.
314da6c28aaSamw  * See smb_xprt_t definition for header format information.
315da6c28aaSamw  */
316da6c28aaSamw static int
smb_session_xprt_puthdr(smb_session_t * session,smb_xprt_t * hdr,uint8_t * buf,size_t buflen)317da6c28aaSamw smb_session_xprt_puthdr(smb_session_t *session, smb_xprt_t *hdr,
318da6c28aaSamw     uint8_t *buf, size_t buflen)
319da6c28aaSamw {
320da6c28aaSamw 	if (session == NULL || hdr == NULL ||
321da6c28aaSamw 	    buf == NULL || buflen < NETBIOS_HDR_SZ) {
322da6c28aaSamw 		return (-1);
323da6c28aaSamw 	}
324da6c28aaSamw 
325da6c28aaSamw 	switch (session->s_local_port) {
326a0aa776eSAlan Wright 	case IPPORT_NETBIOS_SSN:
327da6c28aaSamw 		buf[0] = hdr->xh_type;
328da6c28aaSamw 		buf[1] = ((hdr->xh_length >> 16) & 1);
329da6c28aaSamw 		buf[2] = (hdr->xh_length >> 8) & 0xff;
330da6c28aaSamw 		buf[3] = hdr->xh_length & 0xff;
331da6c28aaSamw 		break;
332da6c28aaSamw 
333a0aa776eSAlan Wright 	case IPPORT_SMB:
334da6c28aaSamw 		buf[0] = hdr->xh_type;
335da6c28aaSamw 		buf[1] = (hdr->xh_length >> 16) & 0xff;
336da6c28aaSamw 		buf[2] = (hdr->xh_length >> 8) & 0xff;
337da6c28aaSamw 		buf[3] = hdr->xh_length & 0xff;
338da6c28aaSamw 		break;
339da6c28aaSamw 
340da6c28aaSamw 	default:
3417f667e74Sjose borrego 		cmn_err(CE_WARN, "invalid port %u", session->s_local_port);
3427f667e74Sjose borrego 		dump_smb_inaddr(&session->ipaddr);
343da6c28aaSamw 		return (-1);
344da6c28aaSamw 	}
345da6c28aaSamw 
346da6c28aaSamw 	return (0);
347da6c28aaSamw }
348da6c28aaSamw 
349faa1795aSjb150015 static void
smb_request_init_command_mbuf(smb_request_t * sr)350da6c28aaSamw smb_request_init_command_mbuf(smb_request_t *sr)
351da6c28aaSamw {
352da6c28aaSamw 
353da6c28aaSamw 	/*
3547f3ef643SGordon Ross 	 * Setup mbuf using the buffer we allocated.
355da6c28aaSamw 	 */
3567f3ef643SGordon Ross 	MBC_ATTACH_BUF(&sr->command, sr->sr_request_buf, sr->sr_req_length);
357da6c28aaSamw 
358da6c28aaSamw 	sr->command.flags = 0;
3597f3ef643SGordon Ross 	sr->command.shadow_of = NULL;
360da6c28aaSamw }
361da6c28aaSamw 
362da6c28aaSamw /*
363da6c28aaSamw  * smb_request_cancel
364da6c28aaSamw  *
365da6c28aaSamw  * Handle a cancel for a request properly depending on the current request
366da6c28aaSamw  * state.
367da6c28aaSamw  */
368da6c28aaSamw void
smb_request_cancel(smb_request_t * sr)369da6c28aaSamw smb_request_cancel(smb_request_t *sr)
370da6c28aaSamw {
371da6c28aaSamw 	mutex_enter(&sr->sr_mutex);
372da6c28aaSamw 	switch (sr->sr_state) {
373da6c28aaSamw 
374584e0fceSGordon Ross 	case SMB_REQ_STATE_INITIALIZING:
375da6c28aaSamw 	case SMB_REQ_STATE_SUBMITTED:
376da6c28aaSamw 	case SMB_REQ_STATE_ACTIVE:
377da6c28aaSamw 	case SMB_REQ_STATE_CLEANED_UP:
378da6c28aaSamw 		sr->sr_state = SMB_REQ_STATE_CANCELED;
379da6c28aaSamw 		break;
380da6c28aaSamw 
381da6c28aaSamw 	case SMB_REQ_STATE_WAITING_LOCK:
382da6c28aaSamw 		/*
383da6c28aaSamw 		 * This request is waiting on a lock.  Wakeup everything
384da6c28aaSamw 		 * waiting on the lock so that the relevant thread regains
385da6c28aaSamw 		 * control and notices that is has been canceled.  The
386da6c28aaSamw 		 * other lock request threads waiting on this lock will go
387da6c28aaSamw 		 * back to sleep when they discover they are still blocked.
388da6c28aaSamw 		 */
389da6c28aaSamw 		sr->sr_state = SMB_REQ_STATE_CANCELED;
390da6c28aaSamw 
391da6c28aaSamw 		ASSERT(sr->sr_awaiting != NULL);
392da6c28aaSamw 		mutex_enter(&sr->sr_awaiting->l_mutex);
393da6c28aaSamw 		cv_broadcast(&sr->sr_awaiting->l_cv);
394da6c28aaSamw 		mutex_exit(&sr->sr_awaiting->l_mutex);
395da6c28aaSamw 		break;
396da6c28aaSamw 
397da6c28aaSamw 	case SMB_REQ_STATE_WAITING_EVENT:
398da6c28aaSamw 		/*
399ccc71be5SGordon Ross 		 * This request is waiting in change notify.
400da6c28aaSamw 		 */
401ccc71be5SGordon Ross 		sr->sr_state = SMB_REQ_STATE_CANCELED;
402ccc71be5SGordon Ross 		cv_signal(&sr->sr_ncr.nc_cv);
403da6c28aaSamw 		break;
404da6c28aaSamw 
405ccc71be5SGordon Ross 	case SMB_REQ_STATE_EVENT_OCCURRED:
406da6c28aaSamw 	case SMB_REQ_STATE_COMPLETED:
407da6c28aaSamw 	case SMB_REQ_STATE_CANCELED:
408da6c28aaSamw 		/*
409da6c28aaSamw 		 * No action required for these states since the request
410da6c28aaSamw 		 * is completing.
411da6c28aaSamw 		 */
412da6c28aaSamw 		break;
413584e0fceSGordon Ross 
414584e0fceSGordon Ross 	case SMB_REQ_STATE_FREE:
415da6c28aaSamw 	default:
4162c2961f8Sjose borrego 		SMB_PANIC();
417da6c28aaSamw 	}
418da6c28aaSamw 	mutex_exit(&sr->sr_mutex);
419da6c28aaSamw }
420da6c28aaSamw 
421da6c28aaSamw /*
4224163af6aSjose borrego  * smb_session_receiver
423da6c28aaSamw  *
4244163af6aSjose borrego  * Receives request from the network and dispatches them to a worker.
425da6c28aaSamw  */
4264163af6aSjose borrego void
smb_session_receiver(smb_session_t * session)4274163af6aSjose borrego smb_session_receiver(smb_session_t *session)
428da6c28aaSamw {
429*b819cea2SGordon Ross 	int	rc = 0;
430da6c28aaSamw 
4314163af6aSjose borrego 	SMB_SESSION_VALID(session);
4324163af6aSjose borrego 
4334163af6aSjose borrego 	session->s_thread = curthread;
434da6c28aaSamw 
435a0aa776eSAlan Wright 	if (session->s_local_port == IPPORT_NETBIOS_SSN) {
436da6c28aaSamw 		rc = smb_session_request(session);
4374163af6aSjose borrego 		if (rc != 0) {
438faa1795aSjb150015 			smb_rwx_rwenter(&session->s_lock, RW_WRITER);
439faa1795aSjb150015 			session->s_state = SMB_SESSION_STATE_DISCONNECTED;
440faa1795aSjb150015 			smb_rwx_rwexit(&session->s_lock);
4414163af6aSjose borrego 			return;
442faa1795aSjb150015 		}
443faa1795aSjb150015 	}
444da6c28aaSamw 
445da6c28aaSamw 	smb_rwx_rwenter(&session->s_lock, RW_WRITER);
446da6c28aaSamw 	session->s_state = SMB_SESSION_STATE_ESTABLISHED;
447da6c28aaSamw 	smb_rwx_rwexit(&session->s_lock);
448da6c28aaSamw 
4494163af6aSjose borrego 	(void) smb_session_message(session);
450da6c28aaSamw 
451da6c28aaSamw 	smb_rwx_rwenter(&session->s_lock, RW_WRITER);
452da6c28aaSamw 	session->s_state = SMB_SESSION_STATE_DISCONNECTED;
453da6c28aaSamw 	smb_rwx_rwexit(&session->s_lock);
454da6c28aaSamw 
455faa1795aSjb150015 	smb_soshutdown(session->sock);
456faa1795aSjb150015 
457da6c28aaSamw 	DTRACE_PROBE2(session__drop, struct session *, session, int, rc);
458da6c28aaSamw 
459da6c28aaSamw 	smb_session_cancel(session);
460da6c28aaSamw 	/*
461da6c28aaSamw 	 * At this point everything related to the session should have been
462da6c28aaSamw 	 * cleaned up and we expect that nothing will attempt to use the
463da6c28aaSamw 	 * socket.
464da6c28aaSamw 	 */
4654163af6aSjose borrego }
466da6c28aaSamw 
4674163af6aSjose borrego /*
4684163af6aSjose borrego  * smb_session_disconnect
4694163af6aSjose borrego  *
4704163af6aSjose borrego  * Disconnects the session passed in.
4714163af6aSjose borrego  */
4724163af6aSjose borrego void
smb_session_disconnect(smb_session_t * session)4734163af6aSjose borrego smb_session_disconnect(smb_session_t *session)
4744163af6aSjose borrego {
4754163af6aSjose borrego 	SMB_SESSION_VALID(session);
4764163af6aSjose borrego 
4774163af6aSjose borrego 	smb_rwx_rwenter(&session->s_lock, RW_WRITER);
4784163af6aSjose borrego 	switch (session->s_state) {
4794163af6aSjose borrego 	case SMB_SESSION_STATE_INITIALIZED:
4804163af6aSjose borrego 	case SMB_SESSION_STATE_CONNECTED:
4814163af6aSjose borrego 	case SMB_SESSION_STATE_ESTABLISHED:
4824163af6aSjose borrego 	case SMB_SESSION_STATE_NEGOTIATED:
4834163af6aSjose borrego 	case SMB_SESSION_STATE_OPLOCK_BREAKING:
4844163af6aSjose borrego 		smb_soshutdown(session->sock);
4854163af6aSjose borrego 		session->s_state = SMB_SESSION_STATE_DISCONNECTED;
4864163af6aSjose borrego 		_NOTE(FALLTHRU)
4874163af6aSjose borrego 	case SMB_SESSION_STATE_DISCONNECTED:
4884163af6aSjose borrego 	case SMB_SESSION_STATE_TERMINATED:
4894163af6aSjose borrego 		break;
4904163af6aSjose borrego 	}
4914163af6aSjose borrego 	smb_rwx_rwexit(&session->s_lock);
492da6c28aaSamw }
493da6c28aaSamw 
494da6c28aaSamw /*
495da6c28aaSamw  * Read and process SMB requests.
496da6c28aaSamw  *
497da6c28aaSamw  * Returns:
498da6c28aaSamw  *	0	Success
499da6c28aaSamw  *	1	Unable to read transport header
500da6c28aaSamw  *	2	Invalid transport header type
501da6c28aaSamw  *	3	Invalid SMB length (too small)
502da6c28aaSamw  *	4	Unable to read SMB header
503da6c28aaSamw  *	5	Invalid SMB header (bad magic number)
504da6c28aaSamw  *	6	Unable to read SMB data
505da6c28aaSamw  */
506da6c28aaSamw static int
smb_session_message(smb_session_t * session)507da6c28aaSamw smb_session_message(smb_session_t *session)
508da6c28aaSamw {
509148c5f43SAlan Wright 	smb_server_t	*sv;
510faa1795aSjb150015 	smb_request_t	*sr = NULL;
511da6c28aaSamw 	smb_xprt_t	hdr;
512da6c28aaSamw 	uint8_t		*req_buf;
513da6c28aaSamw 	uint32_t	resid;
514da6c28aaSamw 	int		rc;
515da6c28aaSamw 
516148c5f43SAlan Wright 	sv = session->s_server;
517148c5f43SAlan Wright 
518faa1795aSjb150015 	for (;;) {
519da6c28aaSamw 
520faa1795aSjb150015 		rc = smb_session_xprt_gethdr(session, &hdr);
521faa1795aSjb150015 		if (rc)
522faa1795aSjb150015 			return (rc);
523faa1795aSjb150015 
524faa1795aSjb150015 		DTRACE_PROBE2(session__receive__xprthdr, session_t *, session,
525da6c28aaSamw 		    smb_xprt_t *, &hdr);
526da6c28aaSamw 
527da6c28aaSamw 		if (hdr.xh_type != SESSION_MESSAGE) {
528da6c28aaSamw 			/*
529faa1795aSjb150015 			 * Anything other than SESSION_MESSAGE or
530faa1795aSjb150015 			 * SESSION_KEEP_ALIVE is an error.  A SESSION_REQUEST
531faa1795aSjb150015 			 * may indicate a new session request but we need to
532faa1795aSjb150015 			 * close this session and we can treat it as an error
533faa1795aSjb150015 			 * here.
534da6c28aaSamw 			 */
535da6c28aaSamw 			if (hdr.xh_type == SESSION_KEEP_ALIVE) {
536da6c28aaSamw 				session->keep_alive = smb_keep_alive;
537faa1795aSjb150015 				continue;
538da6c28aaSamw 			}
539faa1795aSjb150015 			return (EPROTO);
540da6c28aaSamw 		}
541da6c28aaSamw 
542da6c28aaSamw 		if (hdr.xh_length < SMB_HEADER_LEN)
543faa1795aSjb150015 			return (EPROTO);
544da6c28aaSamw 
545da6c28aaSamw 		session->keep_alive = smb_keep_alive;
546da6c28aaSamw 		/*
547faa1795aSjb150015 		 * Allocate a request context, read the SMB header and validate
548faa1795aSjb150015 		 * it. The sr includes a buffer large enough to hold the SMB
549faa1795aSjb150015 		 * request payload.  If the header looks valid, read any
550faa1795aSjb150015 		 * remaining data.
551da6c28aaSamw 		 */
552da6c28aaSamw 		sr = smb_request_alloc(session, hdr.xh_length);
553da6c28aaSamw 
554da6c28aaSamw 		req_buf = (uint8_t *)sr->sr_request_buf;
555da6c28aaSamw 		resid = hdr.xh_length;
556da6c28aaSamw 
557faa1795aSjb150015 		rc = smb_sorecv(session->sock, req_buf, SMB_HEADER_LEN);
558faa1795aSjb150015 		if (rc) {
559da6c28aaSamw 			smb_request_free(sr);
560faa1795aSjb150015 			return (rc);
561da6c28aaSamw 		}
562da6c28aaSamw 
563da6c28aaSamw 		if (SMB_PROTOCOL_MAGIC_INVALID(sr)) {
564da6c28aaSamw 			smb_request_free(sr);
565faa1795aSjb150015 			return (EPROTO);
566da6c28aaSamw 		}
567da6c28aaSamw 
568da6c28aaSamw 		if (resid > SMB_HEADER_LEN) {
569da6c28aaSamw 			req_buf += SMB_HEADER_LEN;
570da6c28aaSamw 			resid -= SMB_HEADER_LEN;
571da6c28aaSamw 
572faa1795aSjb150015 			rc = smb_sorecv(session->sock, req_buf, resid);
573faa1795aSjb150015 			if (rc) {
574da6c28aaSamw 				smb_request_free(sr);
575faa1795aSjb150015 				return (rc);
576da6c28aaSamw 			}
577da6c28aaSamw 		}
578148c5f43SAlan Wright 		smb_server_add_rxb(sv,
579148c5f43SAlan Wright 		    (int64_t)(hdr.xh_length + NETBIOS_HDR_SZ));
580da6c28aaSamw 		/*
581da6c28aaSamw 		 * Initialize command MBC to represent the received data.
582da6c28aaSamw 		 */
583da6c28aaSamw 		smb_request_init_command_mbuf(sr);
584da6c28aaSamw 
585da6c28aaSamw 		DTRACE_PROBE1(session__receive__smb, smb_request_t *, sr);
586da6c28aaSamw 
587148c5f43SAlan Wright 		if (sr->session->signing.flags & SMB_SIGNING_ENABLED) {
588148c5f43SAlan Wright 			if (SMB_IS_NT_CANCEL(sr)) {
589148c5f43SAlan Wright 				sr->session->signing.seqnum++;
590148c5f43SAlan Wright 				sr->sr_seqnum = sr->session->signing.seqnum + 1;
591148c5f43SAlan Wright 				sr->reply_seqnum = 0;
592148c5f43SAlan Wright 			} else {
593148c5f43SAlan Wright 				sr->session->signing.seqnum += 2;
594148c5f43SAlan Wright 				sr->sr_seqnum = sr->session->signing.seqnum;
595148c5f43SAlan Wright 				sr->reply_seqnum = sr->sr_seqnum + 1;
596148c5f43SAlan Wright 			}
597148c5f43SAlan Wright 		}
598148c5f43SAlan Wright 		sr->sr_time_submitted = gethrtime();
599da6c28aaSamw 		sr->sr_state = SMB_REQ_STATE_SUBMITTED;
600148c5f43SAlan Wright 		smb_srqueue_waitq_enter(session->s_srqueue);
6014163af6aSjose borrego 		(void) taskq_dispatch(session->s_server->sv_worker_pool,
602faa1795aSjb150015 		    smb_session_worker, sr, TQ_SLEEP);
603da6c28aaSamw 	}
604da6c28aaSamw }
605da6c28aaSamw 
606da6c28aaSamw /*
607a0aa776eSAlan Wright  * Port will be IPPORT_NETBIOS_SSN or IPPORT_SMB.
608da6c28aaSamw  */
609da6c28aaSamw smb_session_t *
smb_session_create(ksocket_t new_so,uint16_t port,smb_server_t * sv,int family)6107f667e74Sjose borrego smb_session_create(ksocket_t new_so, uint16_t port, smb_server_t *sv,
6117f667e74Sjose borrego     int family)
612da6c28aaSamw {
613da6c28aaSamw 	struct sockaddr_in	sin;
6140f1702c5SYu Xiangning 	socklen_t		slen;
6157f667e74Sjose borrego 	struct sockaddr_in6	sin6;
616da6c28aaSamw 	smb_session_t		*session;
617d3d50737SRafael Vanoni 	int64_t			now;
618da6c28aaSamw 
6198622ec45SGordon Ross 	session = kmem_cache_alloc(smb_cache_session, KM_SLEEP);
620da6c28aaSamw 	bzero(session, sizeof (smb_session_t));
621da6c28aaSamw 
622da6c28aaSamw 	if (smb_idpool_constructor(&session->s_uid_pool)) {
6238622ec45SGordon Ross 		kmem_cache_free(smb_cache_session, session);
624da6c28aaSamw 		return (NULL);
625da6c28aaSamw 	}
6263b13a1efSThomas Keiser 	if (smb_idpool_constructor(&session->s_tid_pool)) {
6273b13a1efSThomas Keiser 		smb_idpool_destructor(&session->s_uid_pool);
6288622ec45SGordon Ross 		kmem_cache_free(smb_cache_session, session);
6293b13a1efSThomas Keiser 		return (NULL);
6303b13a1efSThomas Keiser 	}
631da6c28aaSamw 
632d3d50737SRafael Vanoni 	now = ddi_get_lbolt64();
633d3d50737SRafael Vanoni 
634da6c28aaSamw 	session->s_kid = SMB_NEW_KID();
635faa1795aSjb150015 	session->s_state = SMB_SESSION_STATE_INITIALIZED;
636da6c28aaSamw 	session->native_os = NATIVE_OS_UNKNOWN;
637d3d50737SRafael Vanoni 	session->opentime = now;
638da6c28aaSamw 	session->keep_alive = smb_keep_alive;
639d3d50737SRafael Vanoni 	session->activity_timestamp = now;
640da6c28aaSamw 
641f9bc6dadSDmitry.Savitsky@nexenta.com 	smb_session_genkey(session);
642f9bc6dadSDmitry.Savitsky@nexenta.com 
643da6c28aaSamw 	smb_slist_constructor(&session->s_req_list, sizeof (smb_request_t),
644da6c28aaSamw 	    offsetof(smb_request_t, sr_session_lnd));
645da6c28aaSamw 
646da6c28aaSamw 	smb_llist_constructor(&session->s_user_list, sizeof (smb_user_t),
647da6c28aaSamw 	    offsetof(smb_user_t, u_lnd));
648da6c28aaSamw 
6493b13a1efSThomas Keiser 	smb_llist_constructor(&session->s_tree_list, sizeof (smb_tree_t),
6503b13a1efSThomas Keiser 	    offsetof(smb_tree_t, t_lnd));
6513b13a1efSThomas Keiser 
652da6c28aaSamw 	smb_llist_constructor(&session->s_xa_list, sizeof (smb_xa_t),
653da6c28aaSamw 	    offsetof(smb_xa_t, xa_lnd));
654da6c28aaSamw 
6555cdbe942Sjb150015 	smb_net_txl_constructor(&session->s_txlst);
6565cdbe942Sjb150015 
657da6c28aaSamw 	smb_rwx_init(&session->s_lock);
658da6c28aaSamw 
659148c5f43SAlan Wright 	if (new_so != NULL) {
6607f667e74Sjose borrego 		if (family == AF_INET) {
6610f1702c5SYu Xiangning 			slen = sizeof (sin);
6627f667e74Sjose borrego 			(void) ksocket_getsockname(new_so,
6637f667e74Sjose borrego 			    (struct sockaddr *)&sin, &slen, CRED());
664fc724630SAlan Wright 			bcopy(&sin.sin_addr,
665fc724630SAlan Wright 			    &session->local_ipaddr.au_addr.au_ipv4,
666fc724630SAlan Wright 			    sizeof (in_addr_t));
667fc724630SAlan Wright 			slen = sizeof (sin);
6687f667e74Sjose borrego 			(void) ksocket_getpeername(new_so,
6697f667e74Sjose borrego 			    (struct sockaddr *)&sin, &slen, CRED());
670fc724630SAlan Wright 			bcopy(&sin.sin_addr,
671fc724630SAlan Wright 			    &session->ipaddr.au_addr.au_ipv4,
672fc724630SAlan Wright 			    sizeof (in_addr_t));
6737f667e74Sjose borrego 		} else {
6747f667e74Sjose borrego 			slen = sizeof (sin6);
6757f667e74Sjose borrego 			(void) ksocket_getsockname(new_so,
6767f667e74Sjose borrego 			    (struct sockaddr *)&sin6, &slen, CRED());
677fc724630SAlan Wright 			bcopy(&sin6.sin6_addr,
678fc724630SAlan Wright 			    &session->local_ipaddr.au_addr.au_ipv6,
679fc724630SAlan Wright 			    sizeof (in6_addr_t));
680fc724630SAlan Wright 			slen = sizeof (sin6);
6817f667e74Sjose borrego 			(void) ksocket_getpeername(new_so,
6827f667e74Sjose borrego 			    (struct sockaddr *)&sin6, &slen, CRED());
683fc724630SAlan Wright 			bcopy(&sin6.sin6_addr,
684fc724630SAlan Wright 			    &session->ipaddr.au_addr.au_ipv6,
685fc724630SAlan Wright 			    sizeof (in6_addr_t));
6867f667e74Sjose borrego 		}
6877f667e74Sjose borrego 		session->ipaddr.a_family = family;
6887f667e74Sjose borrego 		session->local_ipaddr.a_family = family;
689da6c28aaSamw 		session->s_local_port = port;
690da6c28aaSamw 		session->sock = new_so;
691148c5f43SAlan Wright 		if (port == IPPORT_NETBIOS_SSN)
692148c5f43SAlan Wright 			smb_server_inc_nbt_sess(sv);
693148c5f43SAlan Wright 		else
694148c5f43SAlan Wright 			smb_server_inc_tcp_sess(sv);
695faa1795aSjb150015 	}
696faa1795aSjb150015 	session->s_server = sv;
697faa1795aSjb150015 	smb_server_get_cfg(sv, &session->s_cfg);
698148c5f43SAlan Wright 	session->s_srqueue = &sv->sv_srqueue;
699148c5f43SAlan Wright 
700da6c28aaSamw 	session->s_magic = SMB_SESSION_MAGIC;
701da6c28aaSamw 	return (session);
702da6c28aaSamw }
703da6c28aaSamw 
704da6c28aaSamw void
smb_session_delete(smb_session_t * session)705da6c28aaSamw smb_session_delete(smb_session_t *session)
706da6c28aaSamw {
7072c2961f8Sjose borrego 
708da6c28aaSamw 	ASSERT(session->s_magic == SMB_SESSION_MAGIC);
709da6c28aaSamw 
7102c2961f8Sjose borrego 	session->s_magic = 0;
711da6c28aaSamw 
712*b819cea2SGordon Ross 	if (session->sign_fini != NULL)
713*b819cea2SGordon Ross 		session->sign_fini(session);
714*b819cea2SGordon Ross 
715da6c28aaSamw 	smb_rwx_destroy(&session->s_lock);
7165cdbe942Sjb150015 	smb_net_txl_destructor(&session->s_txlst);
7172c2961f8Sjose borrego 
718da6c28aaSamw 	smb_slist_destructor(&session->s_req_list);
7193b13a1efSThomas Keiser 	smb_llist_destructor(&session->s_tree_list);
720da6c28aaSamw 	smb_llist_destructor(&session->s_user_list);
721da6c28aaSamw 	smb_llist_destructor(&session->s_xa_list);
722da6c28aaSamw 
723da6c28aaSamw 	ASSERT(session->s_tree_cnt == 0);
724da6c28aaSamw 	ASSERT(session->s_file_cnt == 0);
725da6c28aaSamw 	ASSERT(session->s_dir_cnt == 0);
726da6c28aaSamw 
7273b13a1efSThomas Keiser 	smb_idpool_destructor(&session->s_tid_pool);
728da6c28aaSamw 	smb_idpool_destructor(&session->s_uid_pool);
7294163af6aSjose borrego 	if (session->sock != NULL) {
7304163af6aSjose borrego 		if (session->s_local_port == IPPORT_NETBIOS_SSN)
7314163af6aSjose borrego 			smb_server_dec_nbt_sess(session->s_server);
7324163af6aSjose borrego 		else
7334163af6aSjose borrego 			smb_server_dec_tcp_sess(session->s_server);
7344163af6aSjose borrego 		smb_sodestroy(session->sock);
7354163af6aSjose borrego 	}
7368622ec45SGordon Ross 	kmem_cache_free(smb_cache_session, session);
737da6c28aaSamw }
738da6c28aaSamw 
7392c2961f8Sjose borrego static void
smb_session_cancel(smb_session_t * session)740da6c28aaSamw smb_session_cancel(smb_session_t *session)
741da6c28aaSamw {
742da6c28aaSamw 	smb_xa_t	*xa, *nextxa;
743da6c28aaSamw 
744da6c28aaSamw 	/* All the request currently being treated must be canceled. */
745c8ec8eeaSjose borrego 	smb_session_cancel_requests(session, NULL, NULL);
746da6c28aaSamw 
747da6c28aaSamw 	/*
748da6c28aaSamw 	 * We wait for the completion of all the requests associated with
749da6c28aaSamw 	 * this session.
750da6c28aaSamw 	 */
751da6c28aaSamw 	smb_slist_wait_for_empty(&session->s_req_list);
752da6c28aaSamw 
753da6c28aaSamw 	/*
754da6c28aaSamw 	 * At this point the reference count of the users, trees, files,
755da6c28aaSamw 	 * directories should be zero. It should be possible to destroy them
756da6c28aaSamw 	 * without any problem.
757da6c28aaSamw 	 */
758da6c28aaSamw 	xa = smb_llist_head(&session->s_xa_list);
759da6c28aaSamw 	while (xa) {
760da6c28aaSamw 		nextxa = smb_llist_next(&session->s_xa_list, xa);
761da6c28aaSamw 		smb_xa_close(xa);
762da6c28aaSamw 		xa = nextxa;
763da6c28aaSamw 	}
7649fb67ea3Safshin salek ardakani - Sun Microsystems - Irvine United States 
7659fb67ea3Safshin salek ardakani - Sun Microsystems - Irvine United States 	smb_session_logoff(session);
766da6c28aaSamw }
767da6c28aaSamw 
768c8ec8eeaSjose borrego /*
769c8ec8eeaSjose borrego  * Cancel requests.  If a non-null tree is specified, only requests specific
770c8ec8eeaSjose borrego  * to that tree will be cancelled.  If a non-null sr is specified, that sr
771c8ec8eeaSjose borrego  * will be not be cancelled - this would typically be the caller's sr.
772c8ec8eeaSjose borrego  */
773da6c28aaSamw void
smb_session_cancel_requests(smb_session_t * session,smb_tree_t * tree,smb_request_t * exclude_sr)774da6c28aaSamw smb_session_cancel_requests(
775c8ec8eeaSjose borrego     smb_session_t	*session,
776c8ec8eeaSjose borrego     smb_tree_t		*tree,
777c8ec8eeaSjose borrego     smb_request_t	*exclude_sr)
778da6c28aaSamw {
779da6c28aaSamw 	smb_request_t	*sr;
780da6c28aaSamw 
781da6c28aaSamw 	smb_slist_enter(&session->s_req_list);
782da6c28aaSamw 	sr = smb_slist_head(&session->s_req_list);
783c8ec8eeaSjose borrego 
784da6c28aaSamw 	while (sr) {
785da6c28aaSamw 		ASSERT(sr->sr_magic == SMB_REQ_MAGIC);
786c8ec8eeaSjose borrego 		if ((sr != exclude_sr) &&
787c8ec8eeaSjose borrego 		    (tree == NULL || sr->tid_tree == tree))
788da6c28aaSamw 			smb_request_cancel(sr);
789da6c28aaSamw 
790c8ec8eeaSjose borrego 		sr = smb_slist_next(&session->s_req_list, sr);
791da6c28aaSamw 	}
792c8ec8eeaSjose borrego 
793da6c28aaSamw 	smb_slist_exit(&session->s_req_list);
794da6c28aaSamw }
795da6c28aaSamw 
796da6c28aaSamw void
smb_session_worker(void * arg)7972c2961f8Sjose borrego smb_session_worker(void	*arg)
798da6c28aaSamw {
799da6c28aaSamw 	smb_request_t	*sr;
800148c5f43SAlan Wright 	smb_srqueue_t	*srq;
801da6c28aaSamw 
802da6c28aaSamw 	sr = (smb_request_t *)arg;
803148c5f43SAlan Wright 	SMB_REQ_VALID(sr);
804da6c28aaSamw 
805148c5f43SAlan Wright 	srq = sr->session->s_srqueue;
806148c5f43SAlan Wright 	smb_srqueue_waitq_to_runq(srq);
8072c2961f8Sjose borrego 	sr->sr_worker = curthread;
808da6c28aaSamw 	mutex_enter(&sr->sr_mutex);
809148c5f43SAlan Wright 	sr->sr_time_active = gethrtime();
810da6c28aaSamw 	switch (sr->sr_state) {
811da6c28aaSamw 	case SMB_REQ_STATE_SUBMITTED:
812da6c28aaSamw 		mutex_exit(&sr->sr_mutex);
81359229f98Sjose borrego 		if (smb_dispatch_request(sr)) {
814da6c28aaSamw 			mutex_enter(&sr->sr_mutex);
815da6c28aaSamw 			sr->sr_state = SMB_REQ_STATE_COMPLETED;
816da6c28aaSamw 			mutex_exit(&sr->sr_mutex);
817da6c28aaSamw 			smb_request_free(sr);
818da6c28aaSamw 		}
819da6c28aaSamw 		break;
820da6c28aaSamw 
821da6c28aaSamw 	default:
822da6c28aaSamw 		ASSERT(sr->sr_state == SMB_REQ_STATE_CANCELED);
823da6c28aaSamw 		sr->sr_state = SMB_REQ_STATE_COMPLETED;
824da6c28aaSamw 		mutex_exit(&sr->sr_mutex);
825da6c28aaSamw 		smb_request_free(sr);
826da6c28aaSamw 		break;
827da6c28aaSamw 	}
828148c5f43SAlan Wright 	smb_srqueue_runq_exit(srq);
829da6c28aaSamw }
830da6c28aaSamw 
831faa1795aSjb150015 /*
832b89a8333Snatalie li - Sun Microsystems - Irvine United States  * smb_session_lookup_user
833b89a8333Snatalie li - Sun Microsystems - Irvine United States  */
834b89a8333Snatalie li - Sun Microsystems - Irvine United States static smb_user_t *
smb_session_lookup_user(smb_session_t * session,char * domain,char * name)835b89a8333Snatalie li - Sun Microsystems - Irvine United States smb_session_lookup_user(smb_session_t *session, char *domain, char *name)
836b89a8333Snatalie li - Sun Microsystems - Irvine United States {
837b89a8333Snatalie li - Sun Microsystems - Irvine United States 	smb_user_t	*user;
838b89a8333Snatalie li - Sun Microsystems - Irvine United States 	smb_llist_t	*ulist;
839b89a8333Snatalie li - Sun Microsystems - Irvine United States 
840b89a8333Snatalie li - Sun Microsystems - Irvine United States 	ulist = &session->s_user_list;
841b89a8333Snatalie li - Sun Microsystems - Irvine United States 	smb_llist_enter(ulist, RW_READER);
842b89a8333Snatalie li - Sun Microsystems - Irvine United States 	user = smb_llist_head(ulist);
843b89a8333Snatalie li - Sun Microsystems - Irvine United States 	while (user) {
844b89a8333Snatalie li - Sun Microsystems - Irvine United States 		ASSERT(user->u_magic == SMB_USER_MAGIC);
845bbf6f00cSJordan Brown 		if (!smb_strcasecmp(user->u_name, name, 0) &&
846bbf6f00cSJordan Brown 		    !smb_strcasecmp(user->u_domain, domain, 0)) {
8471fcced4cSJordan Brown 			if (smb_user_hold(user))
848b89a8333Snatalie li - Sun Microsystems - Irvine United States 				break;
849b89a8333Snatalie li - Sun Microsystems - Irvine United States 		}
850b89a8333Snatalie li - Sun Microsystems - Irvine United States 		user = smb_llist_next(ulist, user);
851b89a8333Snatalie li - Sun Microsystems - Irvine United States 	}
852b89a8333Snatalie li - Sun Microsystems - Irvine United States 	smb_llist_exit(ulist);
853b89a8333Snatalie li - Sun Microsystems - Irvine United States 
854b89a8333Snatalie li - Sun Microsystems - Irvine United States 	return (user);
855b89a8333Snatalie li - Sun Microsystems - Irvine United States }
856b89a8333Snatalie li - Sun Microsystems - Irvine United States 
857b89a8333Snatalie li - Sun Microsystems - Irvine United States /*
858b89a8333Snatalie li - Sun Microsystems - Irvine United States  * If a user attempts to log in subsequently from the specified session,
859b89a8333Snatalie li - Sun Microsystems - Irvine United States  * duplicates the existing SMB user instance such that all SMB user
860b89a8333Snatalie li - Sun Microsystems - Irvine United States  * instances that corresponds to the same user on the given session
861b89a8333Snatalie li - Sun Microsystems - Irvine United States  * reference the same user's cred.
862b89a8333Snatalie li - Sun Microsystems - Irvine United States  *
863b89a8333Snatalie li - Sun Microsystems - Irvine United States  * Returns NULL if the given user hasn't yet logged in from this
864b89a8333Snatalie li - Sun Microsystems - Irvine United States  * specified session.  Otherwise, returns a user instance that corresponds
865b89a8333Snatalie li - Sun Microsystems - Irvine United States  * to this subsequent login.
866b89a8333Snatalie li - Sun Microsystems - Irvine United States  */
867b89a8333Snatalie li - Sun Microsystems - Irvine United States smb_user_t *
smb_session_dup_user(smb_session_t * session,char * domain,char * account_name)868b89a8333Snatalie li - Sun Microsystems - Irvine United States smb_session_dup_user(smb_session_t *session, char *domain, char *account_name)
869b89a8333Snatalie li - Sun Microsystems - Irvine United States {
870b89a8333Snatalie li - Sun Microsystems - Irvine United States 	smb_user_t *orig_user = NULL;
871b89a8333Snatalie li - Sun Microsystems - Irvine United States 	smb_user_t *user = NULL;
872b89a8333Snatalie li - Sun Microsystems - Irvine United States 
873b89a8333Snatalie li - Sun Microsystems - Irvine United States 	orig_user = smb_session_lookup_user(session, domain,
874b89a8333Snatalie li - Sun Microsystems - Irvine United States 	    account_name);
875b89a8333Snatalie li - Sun Microsystems - Irvine United States 
876b89a8333Snatalie li - Sun Microsystems - Irvine United States 	if (orig_user) {
877b89a8333Snatalie li - Sun Microsystems - Irvine United States 		user = smb_user_dup(orig_user);
878b89a8333Snatalie li - Sun Microsystems - Irvine United States 		smb_user_release(orig_user);
879b89a8333Snatalie li - Sun Microsystems - Irvine United States 	}
880b89a8333Snatalie li - Sun Microsystems - Irvine United States 
881b89a8333Snatalie li - Sun Microsystems - Irvine United States 	return (user);
882b89a8333Snatalie li - Sun Microsystems - Irvine United States }
883b89a8333Snatalie li - Sun Microsystems - Irvine United States 
884b89a8333Snatalie li - Sun Microsystems - Irvine United States /*
8859fb67ea3Safshin salek ardakani - Sun Microsystems - Irvine United States  * Find a user on the specified session by SMB UID.
8869fb67ea3Safshin salek ardakani - Sun Microsystems - Irvine United States  */
8879fb67ea3Safshin salek ardakani - Sun Microsystems - Irvine United States smb_user_t *
smb_session_lookup_uid(smb_session_t * session,uint16_t uid)8889fb67ea3Safshin salek ardakani - Sun Microsystems - Irvine United States smb_session_lookup_uid(smb_session_t *session, uint16_t uid)
8899fb67ea3Safshin salek ardakani - Sun Microsystems - Irvine United States {
8909fb67ea3Safshin salek ardakani - Sun Microsystems - Irvine United States 	smb_user_t	*user;
8919fb67ea3Safshin salek ardakani - Sun Microsystems - Irvine United States 	smb_llist_t	*user_list;
8929fb67ea3Safshin salek ardakani - Sun Microsystems - Irvine United States 
8939fb67ea3Safshin salek ardakani - Sun Microsystems - Irvine United States 	SMB_SESSION_VALID(session);
8949fb67ea3Safshin salek ardakani - Sun Microsystems - Irvine United States 
8959fb67ea3Safshin salek ardakani - Sun Microsystems - Irvine United States 	user_list = &session->s_user_list;
8969fb67ea3Safshin salek ardakani - Sun Microsystems - Irvine United States 	smb_llist_enter(user_list, RW_READER);
8979fb67ea3Safshin salek ardakani - Sun Microsystems - Irvine United States 
8989fb67ea3Safshin salek ardakani - Sun Microsystems - Irvine United States 	user = smb_llist_head(user_list);
8999fb67ea3Safshin salek ardakani - Sun Microsystems - Irvine United States 	while (user) {
9009fb67ea3Safshin salek ardakani - Sun Microsystems - Irvine United States 		SMB_USER_VALID(user);
9019fb67ea3Safshin salek ardakani - Sun Microsystems - Irvine United States 		ASSERT(user->u_session == session);
9029fb67ea3Safshin salek ardakani - Sun Microsystems - Irvine United States 
9039fb67ea3Safshin salek ardakani - Sun Microsystems - Irvine United States 		if (user->u_uid == uid) {
9049fb67ea3Safshin salek ardakani - Sun Microsystems - Irvine United States 			if (!smb_user_hold(user))
9059fb67ea3Safshin salek ardakani - Sun Microsystems - Irvine United States 				break;
9069fb67ea3Safshin salek ardakani - Sun Microsystems - Irvine United States 
9079fb67ea3Safshin salek ardakani - Sun Microsystems - Irvine United States 			smb_llist_exit(user_list);
9089fb67ea3Safshin salek ardakani - Sun Microsystems - Irvine United States 			return (user);
9099fb67ea3Safshin salek ardakani - Sun Microsystems - Irvine United States 		}
9109fb67ea3Safshin salek ardakani - Sun Microsystems - Irvine United States 
9119fb67ea3Safshin salek ardakani - Sun Microsystems - Irvine United States 		user = smb_llist_next(user_list, user);
9129fb67ea3Safshin salek ardakani - Sun Microsystems - Irvine United States 	}
9139fb67ea3Safshin salek ardakani - Sun Microsystems - Irvine United States 
9149fb67ea3Safshin salek ardakani - Sun Microsystems - Irvine United States 	smb_llist_exit(user_list);
9159fb67ea3Safshin salek ardakani - Sun Microsystems - Irvine United States 	return (NULL);
9169fb67ea3Safshin salek ardakani - Sun Microsystems - Irvine United States }
9179fb67ea3Safshin salek ardakani - Sun Microsystems - Irvine United States 
9189fb67ea3Safshin salek ardakani - Sun Microsystems - Irvine United States void
smb_session_post_user(smb_session_t * session,smb_user_t * user)9199fb67ea3Safshin salek ardakani - Sun Microsystems - Irvine United States smb_session_post_user(smb_session_t *session, smb_user_t *user)
9209fb67ea3Safshin salek ardakani - Sun Microsystems - Irvine United States {
9219fb67ea3Safshin salek ardakani - Sun Microsystems - Irvine United States 	SMB_USER_VALID(user);
9229fb67ea3Safshin salek ardakani - Sun Microsystems - Irvine United States 	ASSERT(user->u_refcnt == 0);
9239fb67ea3Safshin salek ardakani - Sun Microsystems - Irvine United States 	ASSERT(user->u_state == SMB_USER_STATE_LOGGED_OFF);
9249fb67ea3Safshin salek ardakani - Sun Microsystems - Irvine United States 	ASSERT(user->u_session == session);
9259fb67ea3Safshin salek ardakani - Sun Microsystems - Irvine United States 
9269fb67ea3Safshin salek ardakani - Sun Microsystems - Irvine United States 	smb_llist_post(&session->s_user_list, user, smb_user_delete);
9279fb67ea3Safshin salek ardakani - Sun Microsystems - Irvine United States }
9289fb67ea3Safshin salek ardakani - Sun Microsystems - Irvine United States 
9299fb67ea3Safshin salek ardakani - Sun Microsystems - Irvine United States /*
9303b13a1efSThomas Keiser  * Find a tree by tree-id.
9313b13a1efSThomas Keiser  */
9323b13a1efSThomas Keiser smb_tree_t *
smb_session_lookup_tree(smb_session_t * session,uint16_t tid)9333b13a1efSThomas Keiser smb_session_lookup_tree(
9343b13a1efSThomas Keiser     smb_session_t	*session,
9353b13a1efSThomas Keiser     uint16_t		tid)
9363b13a1efSThomas Keiser 
9373b13a1efSThomas Keiser {
9383b13a1efSThomas Keiser 	smb_tree_t	*tree;
9393b13a1efSThomas Keiser 
9403b13a1efSThomas Keiser 	SMB_SESSION_VALID(session);
9413b13a1efSThomas Keiser 
9423b13a1efSThomas Keiser 	smb_llist_enter(&session->s_tree_list, RW_READER);
9433b13a1efSThomas Keiser 	tree = smb_llist_head(&session->s_tree_list);
9443b13a1efSThomas Keiser 
9453b13a1efSThomas Keiser 	while (tree) {
9463b13a1efSThomas Keiser 		ASSERT3U(tree->t_magic, ==, SMB_TREE_MAGIC);
9473b13a1efSThomas Keiser 		ASSERT(tree->t_session == session);
9483b13a1efSThomas Keiser 
9493b13a1efSThomas Keiser 		if (tree->t_tid == tid) {
9503b13a1efSThomas Keiser 			if (smb_tree_hold(tree)) {
9513b13a1efSThomas Keiser 				smb_llist_exit(&session->s_tree_list);
9523b13a1efSThomas Keiser 				return (tree);
9533b13a1efSThomas Keiser 			} else {
9543b13a1efSThomas Keiser 				smb_llist_exit(&session->s_tree_list);
9553b13a1efSThomas Keiser 				return (NULL);
9563b13a1efSThomas Keiser 			}
9573b13a1efSThomas Keiser 		}
9583b13a1efSThomas Keiser 
9593b13a1efSThomas Keiser 		tree = smb_llist_next(&session->s_tree_list, tree);
9603b13a1efSThomas Keiser 	}
9613b13a1efSThomas Keiser 
9623b13a1efSThomas Keiser 	smb_llist_exit(&session->s_tree_list);
9633b13a1efSThomas Keiser 	return (NULL);
9643b13a1efSThomas Keiser }
9653b13a1efSThomas Keiser 
9663b13a1efSThomas Keiser /*
9673b13a1efSThomas Keiser  * Find the first connected tree that matches the specified sharename.
9683b13a1efSThomas Keiser  * If the specified tree is NULL the search starts from the beginning of
9693b13a1efSThomas Keiser  * the user's tree list.  If a tree is provided the search starts just
9703b13a1efSThomas Keiser  * after that tree.
9713b13a1efSThomas Keiser  */
9723b13a1efSThomas Keiser smb_tree_t *
smb_session_lookup_share(smb_session_t * session,const char * sharename,smb_tree_t * tree)9733b13a1efSThomas Keiser smb_session_lookup_share(
9743b13a1efSThomas Keiser     smb_session_t	*session,
9753b13a1efSThomas Keiser     const char		*sharename,
9763b13a1efSThomas Keiser     smb_tree_t		*tree)
9773b13a1efSThomas Keiser {
9783b13a1efSThomas Keiser 	SMB_SESSION_VALID(session);
9793b13a1efSThomas Keiser 	ASSERT(sharename);
9803b13a1efSThomas Keiser 
9813b13a1efSThomas Keiser 	smb_llist_enter(&session->s_tree_list, RW_READER);
9823b13a1efSThomas Keiser 
9833b13a1efSThomas Keiser 	if (tree) {
9843b13a1efSThomas Keiser 		ASSERT3U(tree->t_magic, ==, SMB_TREE_MAGIC);
9853b13a1efSThomas Keiser 		ASSERT(tree->t_session == session);
9863b13a1efSThomas Keiser 		tree = smb_llist_next(&session->s_tree_list, tree);
9873b13a1efSThomas Keiser 	} else {
9883b13a1efSThomas Keiser 		tree = smb_llist_head(&session->s_tree_list);
9893b13a1efSThomas Keiser 	}
9903b13a1efSThomas Keiser 
9913b13a1efSThomas Keiser 	while (tree) {
9923b13a1efSThomas Keiser 		ASSERT3U(tree->t_magic, ==, SMB_TREE_MAGIC);
9933b13a1efSThomas Keiser 		ASSERT(tree->t_session == session);
9943b13a1efSThomas Keiser 		if (smb_strcasecmp(tree->t_sharename, sharename, 0) == 0) {
9953b13a1efSThomas Keiser 			if (smb_tree_hold(tree)) {
9963b13a1efSThomas Keiser 				smb_llist_exit(&session->s_tree_list);
9973b13a1efSThomas Keiser 				return (tree);
9983b13a1efSThomas Keiser 			}
9993b13a1efSThomas Keiser 		}
10003b13a1efSThomas Keiser 		tree = smb_llist_next(&session->s_tree_list, tree);
10013b13a1efSThomas Keiser 	}
10023b13a1efSThomas Keiser 
10033b13a1efSThomas Keiser 	smb_llist_exit(&session->s_tree_list);
10043b13a1efSThomas Keiser 	return (NULL);
10053b13a1efSThomas Keiser }
10063b13a1efSThomas Keiser 
10073b13a1efSThomas Keiser /*
10083b13a1efSThomas Keiser  * Find the first connected tree that matches the specified volume name.
10093b13a1efSThomas Keiser  * If the specified tree is NULL the search starts from the beginning of
10103b13a1efSThomas Keiser  * the user's tree list.  If a tree is provided the search starts just
10113b13a1efSThomas Keiser  * after that tree.
10123b13a1efSThomas Keiser  */
10133b13a1efSThomas Keiser smb_tree_t *
smb_session_lookup_volume(smb_session_t * session,const char * name,smb_tree_t * tree)10143b13a1efSThomas Keiser smb_session_lookup_volume(
10153b13a1efSThomas Keiser     smb_session_t	*session,
10163b13a1efSThomas Keiser     const char		*name,
10173b13a1efSThomas Keiser     smb_tree_t		*tree)
10183b13a1efSThomas Keiser {
10193b13a1efSThomas Keiser 	SMB_SESSION_VALID(session);
10203b13a1efSThomas Keiser 	ASSERT(name);
10213b13a1efSThomas Keiser 
10223b13a1efSThomas Keiser 	smb_llist_enter(&session->s_tree_list, RW_READER);
10233b13a1efSThomas Keiser 
10243b13a1efSThomas Keiser 	if (tree) {
10253b13a1efSThomas Keiser 		ASSERT3U(tree->t_magic, ==, SMB_TREE_MAGIC);
10263b13a1efSThomas Keiser 		ASSERT(tree->t_session == session);
10273b13a1efSThomas Keiser 		tree = smb_llist_next(&session->s_tree_list, tree);
10283b13a1efSThomas Keiser 	} else {
10293b13a1efSThomas Keiser 		tree = smb_llist_head(&session->s_tree_list);
10303b13a1efSThomas Keiser 	}
10313b13a1efSThomas Keiser 
10323b13a1efSThomas Keiser 	while (tree) {
10333b13a1efSThomas Keiser 		ASSERT3U(tree->t_magic, ==, SMB_TREE_MAGIC);
10343b13a1efSThomas Keiser 		ASSERT(tree->t_session == session);
10353b13a1efSThomas Keiser 
10363b13a1efSThomas Keiser 		if (smb_strcasecmp(tree->t_volume, name, 0) == 0) {
10373b13a1efSThomas Keiser 			if (smb_tree_hold(tree)) {
10383b13a1efSThomas Keiser 				smb_llist_exit(&session->s_tree_list);
10393b13a1efSThomas Keiser 				return (tree);
10403b13a1efSThomas Keiser 			}
10413b13a1efSThomas Keiser 		}
10423b13a1efSThomas Keiser 
10433b13a1efSThomas Keiser 		tree = smb_llist_next(&session->s_tree_list, tree);
10443b13a1efSThomas Keiser 	}
10453b13a1efSThomas Keiser 
10463b13a1efSThomas Keiser 	smb_llist_exit(&session->s_tree_list);
10473b13a1efSThomas Keiser 	return (NULL);
10483b13a1efSThomas Keiser }
10493b13a1efSThomas Keiser 
10503b13a1efSThomas Keiser /*
10513b13a1efSThomas Keiser  * Disconnect all trees that match the specified client process-id.
10523b13a1efSThomas Keiser  */
10533b13a1efSThomas Keiser void
smb_session_close_pid(smb_session_t * session,uint16_t pid)10543b13a1efSThomas Keiser smb_session_close_pid(
10553b13a1efSThomas Keiser     smb_session_t	*session,
10563b13a1efSThomas Keiser     uint16_t		pid)
10573b13a1efSThomas Keiser {
10583b13a1efSThomas Keiser 	smb_tree_t	*tree;
10593b13a1efSThomas Keiser 
10603b13a1efSThomas Keiser 	SMB_SESSION_VALID(session);
10613b13a1efSThomas Keiser 
10623b13a1efSThomas Keiser 	tree = smb_session_get_tree(session, NULL);
10633b13a1efSThomas Keiser 	while (tree) {
10643b13a1efSThomas Keiser 		smb_tree_t *next;
10653b13a1efSThomas Keiser 		ASSERT3U(tree->t_magic, ==, SMB_TREE_MAGIC);
10663b13a1efSThomas Keiser 		ASSERT(tree->t_session == session);
10673b13a1efSThomas Keiser 		smb_tree_close_pid(tree, pid);
10683b13a1efSThomas Keiser 		next = smb_session_get_tree(session, tree);
10693b13a1efSThomas Keiser 		smb_tree_release(tree);
10703b13a1efSThomas Keiser 		tree = next;
10713b13a1efSThomas Keiser 	}
10723b13a1efSThomas Keiser }
10733b13a1efSThomas Keiser 
10743b13a1efSThomas Keiser static void
smb_session_tree_dtor(void * t)10753b13a1efSThomas Keiser smb_session_tree_dtor(void *t)
10763b13a1efSThomas Keiser {
10773b13a1efSThomas Keiser 	smb_tree_t	*tree = (smb_tree_t *)t;
10783b13a1efSThomas Keiser 
10793b13a1efSThomas Keiser 	smb_tree_disconnect(tree, B_TRUE);
10803b13a1efSThomas Keiser 	/* release the ref acquired during the traversal loop */
10813b13a1efSThomas Keiser 	smb_tree_release(tree);
10823b13a1efSThomas Keiser }
10833b13a1efSThomas Keiser 
10843b13a1efSThomas Keiser 
10853b13a1efSThomas Keiser /*
10863b13a1efSThomas Keiser  * Disconnect all trees that this user has connected.
10873b13a1efSThomas Keiser  */
10883b13a1efSThomas Keiser void
smb_session_disconnect_owned_trees(smb_session_t * session,smb_user_t * owner)10893b13a1efSThomas Keiser smb_session_disconnect_owned_trees(
10903b13a1efSThomas Keiser     smb_session_t	*session,
10913b13a1efSThomas Keiser     smb_user_t		*owner)
10923b13a1efSThomas Keiser {
10933b13a1efSThomas Keiser 	smb_tree_t	*tree;
10943b13a1efSThomas Keiser 	smb_llist_t	*tree_list = &session->s_tree_list;
10953b13a1efSThomas Keiser 
10963b13a1efSThomas Keiser 	SMB_SESSION_VALID(session);
10973b13a1efSThomas Keiser 	SMB_USER_VALID(owner);
10983b13a1efSThomas Keiser 
10993b13a1efSThomas Keiser 	smb_llist_enter(tree_list, RW_READER);
11003b13a1efSThomas Keiser 
11013b13a1efSThomas Keiser 	tree = smb_llist_head(tree_list);
11023b13a1efSThomas Keiser 	while (tree) {
11033b13a1efSThomas Keiser 		if ((tree->t_owner == owner) &&
11043b13a1efSThomas Keiser 		    smb_tree_hold(tree)) {
11053b13a1efSThomas Keiser 			/*
11063b13a1efSThomas Keiser 			 * smb_tree_hold() succeeded, hence we are in state
11073b13a1efSThomas Keiser 			 * SMB_TREE_STATE_CONNECTED; schedule this tree
11083b13a1efSThomas Keiser 			 * for asynchronous disconnect, which will fire
11093b13a1efSThomas Keiser 			 * after we drop the llist traversal lock.
11103b13a1efSThomas Keiser 			 */
11113b13a1efSThomas Keiser 			smb_llist_post(tree_list, tree, smb_session_tree_dtor);
11123b13a1efSThomas Keiser 		}
11133b13a1efSThomas Keiser 		tree = smb_llist_next(tree_list, tree);
11143b13a1efSThomas Keiser 	}
11153b13a1efSThomas Keiser 
11163b13a1efSThomas Keiser 	/* drop the lock and flush the dtor queue */
11173b13a1efSThomas Keiser 	smb_llist_exit(tree_list);
11183b13a1efSThomas Keiser }
11193b13a1efSThomas Keiser 
11203b13a1efSThomas Keiser /*
11213b13a1efSThomas Keiser  * Disconnect all trees that this user has connected.
11223b13a1efSThomas Keiser  */
11233b13a1efSThomas Keiser void
smb_session_disconnect_trees(smb_session_t * session)11243b13a1efSThomas Keiser smb_session_disconnect_trees(
11253b13a1efSThomas Keiser     smb_session_t	*session)
11263b13a1efSThomas Keiser {
11273b13a1efSThomas Keiser 	smb_tree_t	*tree;
11283b13a1efSThomas Keiser 
11293b13a1efSThomas Keiser 	SMB_SESSION_VALID(session);
11303b13a1efSThomas Keiser 
11313b13a1efSThomas Keiser 	tree = smb_session_get_tree(session, NULL);
11323b13a1efSThomas Keiser 	while (tree) {
11333b13a1efSThomas Keiser 		ASSERT3U(tree->t_magic, ==, SMB_TREE_MAGIC);
11343b13a1efSThomas Keiser 		ASSERT(tree->t_session == session);
11353b13a1efSThomas Keiser 		smb_tree_disconnect(tree, B_TRUE);
11363b13a1efSThomas Keiser 		smb_tree_release(tree);
11373b13a1efSThomas Keiser 		tree = smb_session_get_tree(session, NULL);
11383b13a1efSThomas Keiser 	}
11393b13a1efSThomas Keiser }
11403b13a1efSThomas Keiser 
11413b13a1efSThomas Keiser /*
11423b13a1efSThomas Keiser  * Disconnect all trees that match the specified share name.
11433b13a1efSThomas Keiser  */
11443b13a1efSThomas Keiser void
smb_session_disconnect_share(smb_session_t * session,const char * sharename)11453b13a1efSThomas Keiser smb_session_disconnect_share(
11463b13a1efSThomas Keiser     smb_session_t	*session,
11473b13a1efSThomas Keiser     const char		*sharename)
11483b13a1efSThomas Keiser {
11493b13a1efSThomas Keiser 	smb_tree_t	*tree;
11503b13a1efSThomas Keiser 	smb_tree_t	*next;
11513b13a1efSThomas Keiser 
11523b13a1efSThomas Keiser 	SMB_SESSION_VALID(session);
11533b13a1efSThomas Keiser 
11543b13a1efSThomas Keiser 	tree = smb_session_lookup_share(session, sharename, NULL);
11553b13a1efSThomas Keiser 	while (tree) {
11563b13a1efSThomas Keiser 		ASSERT3U(tree->t_magic, ==, SMB_TREE_MAGIC);
11573b13a1efSThomas Keiser 		ASSERT(tree->t_session == session);
11583b13a1efSThomas Keiser 		smb_session_cancel_requests(session, tree, NULL);
11593b13a1efSThomas Keiser 		smb_tree_disconnect(tree, B_TRUE);
11603b13a1efSThomas Keiser 		next = smb_session_lookup_share(session, sharename, tree);
11613b13a1efSThomas Keiser 		smb_tree_release(tree);
11623b13a1efSThomas Keiser 		tree = next;
11633b13a1efSThomas Keiser 	}
11643b13a1efSThomas Keiser }
11653b13a1efSThomas Keiser 
11663b13a1efSThomas Keiser void
smb_session_post_tree(smb_session_t * session,smb_tree_t * tree)11673b13a1efSThomas Keiser smb_session_post_tree(smb_session_t *session, smb_tree_t *tree)
11683b13a1efSThomas Keiser {
11693b13a1efSThomas Keiser 	SMB_SESSION_VALID(session);
11703b13a1efSThomas Keiser 	SMB_TREE_VALID(tree);
11713b13a1efSThomas Keiser 	ASSERT0(tree->t_refcnt);
11723b13a1efSThomas Keiser 	ASSERT(tree->t_state == SMB_TREE_STATE_DISCONNECTED);
11733b13a1efSThomas Keiser 	ASSERT(tree->t_session == session);
11743b13a1efSThomas Keiser 
11753b13a1efSThomas Keiser 	smb_llist_post(&session->s_tree_list, tree, smb_tree_dealloc);
11763b13a1efSThomas Keiser }
11773b13a1efSThomas Keiser 
11783b13a1efSThomas Keiser /*
11793b13a1efSThomas Keiser  * Get the next connected tree in the list.  A reference is taken on
11803b13a1efSThomas Keiser  * the tree, which can be released later with smb_tree_release().
11813b13a1efSThomas Keiser  *
11823b13a1efSThomas Keiser  * If the specified tree is NULL the search starts from the beginning of
11833b13a1efSThomas Keiser  * the tree list.  If a tree is provided the search starts just after
11843b13a1efSThomas Keiser  * that tree.
11853b13a1efSThomas Keiser  *
11863b13a1efSThomas Keiser  * Returns NULL if there are no connected trees in the list.
11873b13a1efSThomas Keiser  */
11883b13a1efSThomas Keiser static smb_tree_t *
smb_session_get_tree(smb_session_t * session,smb_tree_t * tree)11893b13a1efSThomas Keiser smb_session_get_tree(
11903b13a1efSThomas Keiser     smb_session_t	*session,
11913b13a1efSThomas Keiser     smb_tree_t		*tree)
11923b13a1efSThomas Keiser {
11933b13a1efSThomas Keiser 	smb_llist_t	*tree_list;
11943b13a1efSThomas Keiser 
11953b13a1efSThomas Keiser 	SMB_SESSION_VALID(session);
11963b13a1efSThomas Keiser 	tree_list = &session->s_tree_list;
11973b13a1efSThomas Keiser 
11983b13a1efSThomas Keiser 	smb_llist_enter(tree_list, RW_READER);
11993b13a1efSThomas Keiser 
12003b13a1efSThomas Keiser 	if (tree) {
12013b13a1efSThomas Keiser 		ASSERT3U(tree->t_magic, ==, SMB_TREE_MAGIC);
12023b13a1efSThomas Keiser 		tree = smb_llist_next(tree_list, tree);
12033b13a1efSThomas Keiser 	} else {
12043b13a1efSThomas Keiser 		tree = smb_llist_head(tree_list);
12053b13a1efSThomas Keiser 	}
12063b13a1efSThomas Keiser 
12073b13a1efSThomas Keiser 	while (tree) {
12083b13a1efSThomas Keiser 		if (smb_tree_hold(tree))
12093b13a1efSThomas Keiser 			break;
12103b13a1efSThomas Keiser 
12113b13a1efSThomas Keiser 		tree = smb_llist_next(tree_list, tree);
12123b13a1efSThomas Keiser 	}
12133b13a1efSThomas Keiser 
12143b13a1efSThomas Keiser 	smb_llist_exit(tree_list);
12153b13a1efSThomas Keiser 	return (tree);
12163b13a1efSThomas Keiser }
12173b13a1efSThomas Keiser 
12183b13a1efSThomas Keiser /*
12199fb67ea3Safshin salek ardakani - Sun Microsystems - Irvine United States  * Logoff all users associated with the specified session.
12209fb67ea3Safshin salek ardakani - Sun Microsystems - Irvine United States  */
12219fb67ea3Safshin salek ardakani - Sun Microsystems - Irvine United States static void
smb_session_logoff(smb_session_t * session)12229fb67ea3Safshin salek ardakani - Sun Microsystems - Irvine United States smb_session_logoff(smb_session_t *session)
12239fb67ea3Safshin salek ardakani - Sun Microsystems - Irvine United States {
12249fb67ea3Safshin salek ardakani - Sun Microsystems - Irvine United States 	smb_user_t	*user;
12259fb67ea3Safshin salek ardakani - Sun Microsystems - Irvine United States 
12269fb67ea3Safshin salek ardakani - Sun Microsystems - Irvine United States 	SMB_SESSION_VALID(session);
12279fb67ea3Safshin salek ardakani - Sun Microsystems - Irvine United States 
12283b13a1efSThomas Keiser 	smb_session_disconnect_trees(session);
12293b13a1efSThomas Keiser 
12309fb67ea3Safshin salek ardakani - Sun Microsystems - Irvine United States 	smb_llist_enter(&session->s_user_list, RW_READER);
12319fb67ea3Safshin salek ardakani - Sun Microsystems - Irvine United States 
12329fb67ea3Safshin salek ardakani - Sun Microsystems - Irvine United States 	user = smb_llist_head(&session->s_user_list);
12339fb67ea3Safshin salek ardakani - Sun Microsystems - Irvine United States 	while (user) {
12349fb67ea3Safshin salek ardakani - Sun Microsystems - Irvine United States 		SMB_USER_VALID(user);
12359fb67ea3Safshin salek ardakani - Sun Microsystems - Irvine United States 		ASSERT(user->u_session == session);
12369fb67ea3Safshin salek ardakani - Sun Microsystems - Irvine United States 
12379fb67ea3Safshin salek ardakani - Sun Microsystems - Irvine United States 		if (smb_user_hold(user)) {
12389fb67ea3Safshin salek ardakani - Sun Microsystems - Irvine United States 			smb_user_logoff(user);
12399fb67ea3Safshin salek ardakani - Sun Microsystems - Irvine United States 			smb_user_release(user);
12409fb67ea3Safshin salek ardakani - Sun Microsystems - Irvine United States 		}
12419fb67ea3Safshin salek ardakani - Sun Microsystems - Irvine United States 
12429fb67ea3Safshin salek ardakani - Sun Microsystems - Irvine United States 		user = smb_llist_next(&session->s_user_list, user);
12439fb67ea3Safshin salek ardakani - Sun Microsystems - Irvine United States 	}
12449fb67ea3Safshin salek ardakani - Sun Microsystems - Irvine United States 
12459fb67ea3Safshin salek ardakani - Sun Microsystems - Irvine United States 	smb_llist_exit(&session->s_user_list);
12469fb67ea3Safshin salek ardakani - Sun Microsystems - Irvine United States }
12479fb67ea3Safshin salek ardakani - Sun Microsystems - Irvine United States 
12489fb67ea3Safshin salek ardakani - Sun Microsystems - Irvine United States /*
12491fcced4cSJordan Brown  * Copy the session workstation/client name to buf.  If the workstation
12501fcced4cSJordan Brown  * is an empty string (which it will be on TCP connections), use the
12511fcced4cSJordan Brown  * client IP address.
12521fcced4cSJordan Brown  */
12531fcced4cSJordan Brown void
smb_session_getclient(smb_session_t * sn,char * buf,size_t buflen)12541fcced4cSJordan Brown smb_session_getclient(smb_session_t *sn, char *buf, size_t buflen)
12551fcced4cSJordan Brown {
12561fcced4cSJordan Brown 	char		ipbuf[INET6_ADDRSTRLEN];
12571fcced4cSJordan Brown 	smb_inaddr_t	*ipaddr;
12581fcced4cSJordan Brown 
12591fcced4cSJordan Brown 	ASSERT(sn);
12601fcced4cSJordan Brown 	ASSERT(buf);
12611fcced4cSJordan Brown 	ASSERT(buflen);
12621fcced4cSJordan Brown 
12631fcced4cSJordan Brown 	*buf = '\0';
12641fcced4cSJordan Brown 
12651fcced4cSJordan Brown 	if (sn->workstation[0] != '\0') {
12661fcced4cSJordan Brown 		(void) strlcpy(buf, sn->workstation, buflen);
12671fcced4cSJordan Brown 		return;
12681fcced4cSJordan Brown 	}
12691fcced4cSJordan Brown 
12701fcced4cSJordan Brown 	ipaddr = &sn->ipaddr;
12711fcced4cSJordan Brown 	if (smb_inet_ntop(ipaddr, ipbuf, SMB_IPSTRLEN(ipaddr->a_family)))
12721fcced4cSJordan Brown 		(void) strlcpy(buf, ipbuf, buflen);
12731fcced4cSJordan Brown }
12741fcced4cSJordan Brown 
12751fcced4cSJordan Brown /*
12761fcced4cSJordan Brown  * Check whether or not the specified client name is the client of this
12771fcced4cSJordan Brown  * session.  The name may be in UNC format (\\CLIENT).
12781fcced4cSJordan Brown  *
12791fcced4cSJordan Brown  * A workstation/client name is setup on NBT connections as part of the
12801fcced4cSJordan Brown  * NetBIOS session request but that isn't available on TCP connections.
12811fcced4cSJordan Brown  * If the session doesn't have a client name we typically return the
12821fcced4cSJordan Brown  * client IP address as the workstation name on MSRPC requests.  So we
12831fcced4cSJordan Brown  * check for the IP address here in addition to the workstation name.
12841fcced4cSJordan Brown  */
12851fcced4cSJordan Brown boolean_t
smb_session_isclient(smb_session_t * sn,const char * client)12861fcced4cSJordan Brown smb_session_isclient(smb_session_t *sn, const char *client)
12871fcced4cSJordan Brown {
12881fcced4cSJordan Brown 	char		buf[INET6_ADDRSTRLEN];
12891fcced4cSJordan Brown 	smb_inaddr_t	*ipaddr;
12901fcced4cSJordan Brown 
12911fcced4cSJordan Brown 	client += strspn(client, "\\");
12921fcced4cSJordan Brown 
1293bbf6f00cSJordan Brown 	if (smb_strcasecmp(client, sn->workstation, 0) == 0)
12941fcced4cSJordan Brown 		return (B_TRUE);
12951fcced4cSJordan Brown 
12961fcced4cSJordan Brown 	ipaddr = &sn->ipaddr;
12971fcced4cSJordan Brown 	if (smb_inet_ntop(ipaddr, buf, SMB_IPSTRLEN(ipaddr->a_family)) == NULL)
12981fcced4cSJordan Brown 		return (B_FALSE);
12991fcced4cSJordan Brown 
1300bbf6f00cSJordan Brown 	if (smb_strcasecmp(client, buf, 0) == 0)
13011fcced4cSJordan Brown 		return (B_TRUE);
13021fcced4cSJordan Brown 
13031fcced4cSJordan Brown 	return (B_FALSE);
13041fcced4cSJordan Brown }
13051fcced4cSJordan Brown 
13061fcced4cSJordan Brown /*
1307faa1795aSjb150015  * smb_request_alloc
1308faa1795aSjb150015  *
1309faa1795aSjb150015  * Allocate an smb_request_t structure from the kmem_cache.  Partially
1310faa1795aSjb150015  * initialize the found/new request.
1311faa1795aSjb150015  *
1312faa1795aSjb150015  * Returns pointer to a request
1313faa1795aSjb150015  */
1314faa1795aSjb150015 smb_request_t *
smb_request_alloc(smb_session_t * session,int req_length)1315faa1795aSjb150015 smb_request_alloc(smb_session_t *session, int req_length)
1316faa1795aSjb150015 {
1317faa1795aSjb150015 	smb_request_t	*sr;
1318faa1795aSjb150015 
1319faa1795aSjb150015 	ASSERT(session->s_magic == SMB_SESSION_MAGIC);
1320faa1795aSjb150015 
13218622ec45SGordon Ross 	sr = kmem_cache_alloc(smb_cache_request, KM_SLEEP);
1322faa1795aSjb150015 
1323faa1795aSjb150015 	/*
1324faa1795aSjb150015 	 * Future:  Use constructor to pre-initialize some fields.  For now
1325faa1795aSjb150015 	 * there are so many fields that it is easiest just to zero the
1326faa1795aSjb150015 	 * whole thing and start over.
1327faa1795aSjb150015 	 */
1328faa1795aSjb150015 	bzero(sr, sizeof (smb_request_t));
1329faa1795aSjb150015 
1330faa1795aSjb150015 	mutex_init(&sr->sr_mutex, NULL, MUTEX_DEFAULT, NULL);
1331ccc71be5SGordon Ross 	cv_init(&sr->sr_ncr.nc_cv, NULL, CV_DEFAULT, NULL);
1332bbf6f00cSJordan Brown 	smb_srm_init(sr);
1333faa1795aSjb150015 	sr->session = session;
1334faa1795aSjb150015 	sr->sr_server = session->s_server;
1335faa1795aSjb150015 	sr->sr_gmtoff = session->s_server->si_gmtoff;
1336faa1795aSjb150015 	sr->sr_cfg = &session->s_cfg;
1337faa1795aSjb150015 	sr->command.max_bytes = req_length;
1338faa1795aSjb150015 	sr->reply.max_bytes = smb_maxbufsize;
1339faa1795aSjb150015 	sr->sr_req_length = req_length;
1340faa1795aSjb150015 	if (req_length)
1341faa1795aSjb150015 		sr->sr_request_buf = kmem_alloc(req_length, KM_SLEEP);
1342faa1795aSjb150015 	sr->sr_magic = SMB_REQ_MAGIC;
1343faa1795aSjb150015 	sr->sr_state = SMB_REQ_STATE_INITIALIZING;
1344faa1795aSjb150015 	smb_slist_insert_tail(&session->s_req_list, sr);
1345faa1795aSjb150015 	return (sr);
1346faa1795aSjb150015 }
1347faa1795aSjb150015 
1348faa1795aSjb150015 /*
1349faa1795aSjb150015  * smb_request_free
1350faa1795aSjb150015  *
1351faa1795aSjb150015  * release the memories which have been allocated for a smb request.
1352faa1795aSjb150015  */
1353faa1795aSjb150015 void
smb_request_free(smb_request_t * sr)1354faa1795aSjb150015 smb_request_free(smb_request_t *sr)
1355faa1795aSjb150015 {
1356faa1795aSjb150015 	ASSERT(sr->sr_magic == SMB_REQ_MAGIC);
1357faa1795aSjb150015 	ASSERT(sr->session);
1358faa1795aSjb150015 	ASSERT(sr->r_xa == NULL);
1359ccc71be5SGordon Ross 	ASSERT(sr->sr_ncr.nc_fname == NULL);
1360faa1795aSjb150015 
1361cb174861Sjoyce mcintosh 	if (sr->fid_ofile != NULL) {
1362cb174861Sjoyce mcintosh 		smb_ofile_request_complete(sr->fid_ofile);
13632c2961f8Sjose borrego 		smb_ofile_release(sr->fid_ofile);
1364cb174861Sjoyce mcintosh 	}
13652c2961f8Sjose borrego 
13662c2961f8Sjose borrego 	if (sr->tid_tree != NULL)
1367faa1795aSjb150015 		smb_tree_release(sr->tid_tree);
1368faa1795aSjb150015 
13692c2961f8Sjose borrego 	if (sr->uid_user != NULL)
1370faa1795aSjb150015 		smb_user_release(sr->uid_user);
1371faa1795aSjb150015 
1372faa1795aSjb150015 	smb_slist_remove(&sr->session->s_req_list, sr);
1373faa1795aSjb150015 
1374faa1795aSjb150015 	sr->session = NULL;
1375faa1795aSjb150015 
1376bbf6f00cSJordan Brown 	smb_srm_fini(sr);
1377faa1795aSjb150015 
1378faa1795aSjb150015 	if (sr->sr_request_buf)
1379faa1795aSjb150015 		kmem_free(sr->sr_request_buf, sr->sr_req_length);
1380faa1795aSjb150015 	if (sr->command.chain)
1381faa1795aSjb150015 		m_freem(sr->command.chain);
1382faa1795aSjb150015 	if (sr->reply.chain)
1383faa1795aSjb150015 		m_freem(sr->reply.chain);
1384faa1795aSjb150015 	if (sr->raw_data.chain)
1385faa1795aSjb150015 		m_freem(sr->raw_data.chain);
1386faa1795aSjb150015 
1387faa1795aSjb150015 	sr->sr_magic = 0;
1388ccc71be5SGordon Ross 	cv_destroy(&sr->sr_ncr.nc_cv);
1389faa1795aSjb150015 	mutex_destroy(&sr->sr_mutex);
13908622ec45SGordon Ross 	kmem_cache_free(smb_cache_request, sr);
1391da6c28aaSamw }
13927f667e74Sjose borrego 
13937f667e74Sjose borrego void
dump_smb_inaddr(smb_inaddr_t * ipaddr)13947f667e74Sjose borrego dump_smb_inaddr(smb_inaddr_t *ipaddr)
13957f667e74Sjose borrego {
13967f667e74Sjose borrego 	char ipstr[INET6_ADDRSTRLEN];
13977f667e74Sjose borrego 
13987f667e74Sjose borrego 	if (smb_inet_ntop(ipaddr, ipstr, SMB_IPSTRLEN(ipaddr->a_family)))
13997f667e74Sjose borrego 		cmn_err(CE_WARN, "error ipstr=%s", ipstr);
14007f667e74Sjose borrego 	else
14017f667e74Sjose borrego 		cmn_err(CE_WARN, "error converting ip address");
14027f667e74Sjose borrego }
14032c2961f8Sjose borrego 
14042c2961f8Sjose borrego boolean_t
smb_session_oplocks_enable(smb_session_t * session)14052c2961f8Sjose borrego smb_session_oplocks_enable(smb_session_t *session)
14062c2961f8Sjose borrego {
14072c2961f8Sjose borrego 	SMB_SESSION_VALID(session);
14082c2961f8Sjose borrego 	if (session->s_cfg.skc_oplock_enable == 0)
14092c2961f8Sjose borrego 		return (B_FALSE);
14102c2961f8Sjose borrego 	else
14112c2961f8Sjose borrego 		return (B_TRUE);
14122c2961f8Sjose borrego }
14132c2961f8Sjose borrego 
1414cb174861Sjoyce mcintosh boolean_t
smb_session_levelII_oplocks(smb_session_t * session)1415cb174861Sjoyce mcintosh smb_session_levelII_oplocks(smb_session_t *session)
1416cb174861Sjoyce mcintosh {
1417cb174861Sjoyce mcintosh 	SMB_SESSION_VALID(session);
1418cb174861Sjoyce mcintosh 	return (session->capabilities & CAP_LEVEL_II_OPLOCKS);
1419cb174861Sjoyce mcintosh }
1420cb174861Sjoyce mcintosh 
14212c2961f8Sjose borrego /*
1422cb174861Sjoyce mcintosh  * smb_session_oplock_break
14232c2961f8Sjose borrego  *
1424cb174861Sjoyce mcintosh  * The session lock must NOT be held by the caller of this thread;
1425cb174861Sjoyce mcintosh  * as this would cause a deadlock.
14262c2961f8Sjose borrego  */
14272c2961f8Sjose borrego void
smb_session_oplock_break(smb_session_t * session,uint16_t tid,uint16_t fid,uint8_t brk)1428cb174861Sjoyce mcintosh smb_session_oplock_break(smb_session_t *session,
1429cb174861Sjoyce mcintosh     uint16_t tid, uint16_t fid, uint8_t brk)
14302c2961f8Sjose borrego {
14312c2961f8Sjose borrego 	mbuf_chain_t	*mbc;
14322c2961f8Sjose borrego 
14332c2961f8Sjose borrego 	SMB_SESSION_VALID(session);
14342c2961f8Sjose borrego 
14352c2961f8Sjose borrego 	mbc = smb_mbc_alloc(MLEN);
14362c2961f8Sjose borrego 
1437cb174861Sjoyce mcintosh 	(void) smb_mbc_encodef(mbc, "Mb19.wwwwbb3.wbb10.",
14382c2961f8Sjose borrego 	    SMB_COM_LOCKING_ANDX,
1439cb174861Sjoyce mcintosh 	    tid,
14402c2961f8Sjose borrego 	    0xFFFF, 0, 0xFFFF, 8, 0xFF,
1441cb174861Sjoyce mcintosh 	    fid,
1442cb174861Sjoyce mcintosh 	    LOCKING_ANDX_OPLOCK_RELEASE,
1443cb174861Sjoyce mcintosh 	    (brk == SMB_OPLOCK_BREAK_TO_LEVEL_II) ? 1 : 0);
14442c2961f8Sjose borrego 
14452c2961f8Sjose borrego 	smb_rwx_rwenter(&session->s_lock, RW_WRITER);
14462c2961f8Sjose borrego 	switch (session->s_state) {
14472c2961f8Sjose borrego 	case SMB_SESSION_STATE_NEGOTIATED:
14482c2961f8Sjose borrego 	case SMB_SESSION_STATE_OPLOCK_BREAKING:
14492c2961f8Sjose borrego 		session->s_state = SMB_SESSION_STATE_OPLOCK_BREAKING;
14502c2961f8Sjose borrego 		(void) smb_session_send(session, 0, mbc);
14512c2961f8Sjose borrego 		smb_mbc_free(mbc);
14522c2961f8Sjose borrego 		break;
14532c2961f8Sjose borrego 
14542c2961f8Sjose borrego 	case SMB_SESSION_STATE_DISCONNECTED:
14552c2961f8Sjose borrego 	case SMB_SESSION_STATE_TERMINATED:
14562c2961f8Sjose borrego 		smb_mbc_free(mbc);
14572c2961f8Sjose borrego 		break;
14582c2961f8Sjose borrego 
14592c2961f8Sjose borrego 	default:
14602c2961f8Sjose borrego 		SMB_PANIC();
14612c2961f8Sjose borrego 	}
14622c2961f8Sjose borrego 	smb_rwx_rwexit(&session->s_lock);
14632c2961f8Sjose borrego }
1464f9bc6dadSDmitry.Savitsky@nexenta.com 
1465f9bc6dadSDmitry.Savitsky@nexenta.com static void
smb_session_genkey(smb_session_t * session)1466f9bc6dadSDmitry.Savitsky@nexenta.com smb_session_genkey(smb_session_t *session)
1467f9bc6dadSDmitry.Savitsky@nexenta.com {
1468f9bc6dadSDmitry.Savitsky@nexenta.com 	uint8_t		tmp_key[SMB_CHALLENGE_SZ];
1469f9bc6dadSDmitry.Savitsky@nexenta.com 
1470f9bc6dadSDmitry.Savitsky@nexenta.com 	(void) random_get_pseudo_bytes(tmp_key, SMB_CHALLENGE_SZ);
1471f9bc6dadSDmitry.Savitsky@nexenta.com 	bcopy(tmp_key, &session->challenge_key, SMB_CHALLENGE_SZ);
1472f9bc6dadSDmitry.Savitsky@nexenta.com 	session->challenge_len = SMB_CHALLENGE_SZ;
1473f9bc6dadSDmitry.Savitsky@nexenta.com 
1474f9bc6dadSDmitry.Savitsky@nexenta.com 	(void) random_get_pseudo_bytes(tmp_key, 4);
1475f9bc6dadSDmitry.Savitsky@nexenta.com 	session->sesskey = tmp_key[0] | tmp_key[1] << 8 |
1476f9bc6dadSDmitry.Savitsky@nexenta.com 	    tmp_key[2] << 16 | tmp_key[3] << 24;
1477f9bc6dadSDmitry.Savitsky@nexenta.com }
1478