xref: /illumos-gate/usr/src/uts/common/fs/smbsrv/smb_session.c (revision 8622ec4569457733001d4982ef7f5b44427069be)
1 /*
2  * CDDL HEADER START
3  *
4  * The contents of this file are subject to the terms of the
5  * Common Development and Distribution License (the "License").
6  * You may not use this file except in compliance with the License.
7  *
8  * You can obtain a copy of the license at usr/src/OPENSOLARIS.LICENSE
9  * or http://www.opensolaris.org/os/licensing.
10  * See the License for the specific language governing permissions
11  * and limitations under the License.
12  *
13  * When distributing Covered Code, include this CDDL HEADER in each
14  * file and include the License file at usr/src/OPENSOLARIS.LICENSE.
15  * If applicable, add the following below this CDDL HEADER, with the
16  * fields enclosed by brackets "[]" replaced with your own identifying
17  * information: Portions Copyright [yyyy] [name of copyright owner]
18  *
19  * CDDL HEADER END
20  */
21 /*
22  * Copyright (c) 2007, 2010, Oracle and/or its affiliates. All rights reserved.
23  * Copyright 2012 Nexenta Systems, Inc.  All rights reserved.
24  */
25 #include <sys/atomic.h>
26 #include <sys/strsubr.h>
27 #include <sys/synch.h>
28 #include <sys/types.h>
29 #include <sys/socketvar.h>
30 #include <sys/sdt.h>
31 #include <sys/random.h>
32 #include <smbsrv/netbios.h>
33 #include <smbsrv/smb_kproto.h>
34 #include <smbsrv/string.h>
35 #include <inet/tcp.h>
36 
37 static volatile uint64_t smb_kids;
38 
39 uint32_t smb_keep_alive = SSN_KEEP_ALIVE_TIMEOUT;
40 
41 static void smb_session_cancel(smb_session_t *);
42 static int smb_session_message(smb_session_t *);
43 static int smb_session_xprt_puthdr(smb_session_t *, smb_xprt_t *,
44     uint8_t *, size_t);
45 static smb_user_t *smb_session_lookup_user(smb_session_t *, char *, char *);
46 static smb_tree_t *smb_session_get_tree(smb_session_t *, smb_tree_t *);
47 static void smb_session_logoff(smb_session_t *);
48 static void smb_request_init_command_mbuf(smb_request_t *sr);
49 void dump_smb_inaddr(smb_inaddr_t *ipaddr);
50 static void smb_session_genkey(smb_session_t *);
51 
52 void
53 smb_session_timers(smb_llist_t *ll)
54 {
55 	smb_session_t	*session;
56 
57 	smb_llist_enter(ll, RW_READER);
58 	session = smb_llist_head(ll);
59 	while (session != NULL) {
60 		/*
61 		 * Walk through the table and decrement each keep_alive
62 		 * timer that has not timed out yet. (keepalive > 0)
63 		 */
64 		SMB_SESSION_VALID(session);
65 		if (session->keep_alive &&
66 		    (session->keep_alive != (uint32_t)-1))
67 			session->keep_alive--;
68 		session = smb_llist_next(ll, session);
69 	}
70 	smb_llist_exit(ll);
71 }
72 
73 void
74 smb_session_correct_keep_alive_values(smb_llist_t *ll, uint32_t new_keep_alive)
75 {
76 	smb_session_t		*sn;
77 
78 	if (new_keep_alive == smb_keep_alive)
79 		return;
80 	/*
81 	 * keep alive == 0 means do not drop connection if it's idle
82 	 */
83 	smb_keep_alive = (new_keep_alive) ? new_keep_alive : -1;
84 
85 	/*
86 	 * Walk through the table and set each session to the new keep_alive
87 	 * value if they have not already timed out.  Block clock interrupts.
88 	 */
89 	smb_llist_enter(ll, RW_READER);
90 	sn = smb_llist_head(ll);
91 	while (sn != NULL) {
92 		SMB_SESSION_VALID(sn);
93 		if (sn->keep_alive != 0)
94 			sn->keep_alive = new_keep_alive;
95 		sn = smb_llist_next(ll, sn);
96 	}
97 	smb_llist_exit(ll);
98 }
99 
100 /*
101  * Send a session message - supports SMB-over-NBT and SMB-over-TCP.
102  *
103  * The mbuf chain is copied into a contiguous buffer so that the whole
104  * message is submitted to smb_sosend as a single request.  This should
105  * help Ethereal/Wireshark delineate the packets correctly even though
106  * TCP_NODELAY has been set on the socket.
107  *
108  * If an mbuf chain is provided, it will be freed and set to NULL here.
109  */
110 int
111 smb_session_send(smb_session_t *session, uint8_t type, mbuf_chain_t *mbc)
112 {
113 	smb_txreq_t	*txr;
114 	smb_xprt_t	hdr;
115 	int		rc;
116 
117 	switch (session->s_state) {
118 	case SMB_SESSION_STATE_DISCONNECTED:
119 	case SMB_SESSION_STATE_TERMINATED:
120 		if ((mbc != NULL) && (mbc->chain != NULL)) {
121 			m_freem(mbc->chain);
122 			mbc->chain = NULL;
123 			mbc->flags = 0;
124 		}
125 		return (ENOTCONN);
126 	default:
127 		break;
128 	}
129 
130 	txr = smb_net_txr_alloc();
131 
132 	if ((mbc != NULL) && (mbc->chain != NULL)) {
133 		rc = mbc_moveout(mbc, (caddr_t)&txr->tr_buf[NETBIOS_HDR_SZ],
134 		    sizeof (txr->tr_buf) - NETBIOS_HDR_SZ, &txr->tr_len);
135 		if (rc != 0) {
136 			smb_net_txr_free(txr);
137 			return (rc);
138 		}
139 	}
140 
141 	hdr.xh_type = type;
142 	hdr.xh_length = (uint32_t)txr->tr_len;
143 
144 	rc = smb_session_xprt_puthdr(session, &hdr, txr->tr_buf,
145 	    NETBIOS_HDR_SZ);
146 
147 	if (rc != 0) {
148 		smb_net_txr_free(txr);
149 		return (rc);
150 	}
151 	txr->tr_len += NETBIOS_HDR_SZ;
152 	smb_server_add_txb(session->s_server, (int64_t)txr->tr_len);
153 	return (smb_net_txr_send(session->sock, &session->s_txlst, txr));
154 }
155 
156 /*
157  * Read, process and respond to a NetBIOS session request.
158  *
159  * A NetBIOS session must be established for SMB-over-NetBIOS.  Validate
160  * the calling and called name format and save the client NetBIOS name,
161  * which is used when a NetBIOS session is established to check for and
162  * cleanup leftover state from a previous session.
163  *
164  * Session requests are not valid for SMB-over-TCP, which is unfortunate
165  * because without the client name leftover state cannot be cleaned up
166  * if the client is behind a NAT server.
167  */
168 static int
169 smb_session_request(struct smb_session *session)
170 {
171 	int			rc;
172 	char			*calling_name;
173 	char			*called_name;
174 	char 			client_name[NETBIOS_NAME_SZ];
175 	struct mbuf_chain 	mbc;
176 	char 			*names = NULL;
177 	smb_wchar_t		*wbuf = NULL;
178 	smb_xprt_t		hdr;
179 	char *p;
180 	int rc1, rc2;
181 
182 	session->keep_alive = smb_keep_alive;
183 
184 	if ((rc = smb_session_xprt_gethdr(session, &hdr)) != 0)
185 		return (rc);
186 
187 	DTRACE_PROBE2(receive__session__req__xprthdr, struct session *, session,
188 	    smb_xprt_t *, &hdr);
189 
190 	if ((hdr.xh_type != SESSION_REQUEST) ||
191 	    (hdr.xh_length != NETBIOS_SESSION_REQUEST_DATA_LENGTH)) {
192 		DTRACE_PROBE1(receive__session__req__failed,
193 		    struct session *, session);
194 		return (EINVAL);
195 	}
196 
197 	names = kmem_alloc(hdr.xh_length, KM_SLEEP);
198 
199 	if ((rc = smb_sorecv(session->sock, names, hdr.xh_length)) != 0) {
200 		kmem_free(names, hdr.xh_length);
201 		DTRACE_PROBE1(receive__session__req__failed,
202 		    struct session *, session);
203 		return (rc);
204 	}
205 
206 	DTRACE_PROBE3(receive__session__req__data, struct session *, session,
207 	    char *, names, uint32_t, hdr.xh_length);
208 
209 	called_name = &names[0];
210 	calling_name = &names[NETBIOS_ENCODED_NAME_SZ + 2];
211 
212 	rc1 = netbios_name_isvalid(called_name, 0);
213 	rc2 = netbios_name_isvalid(calling_name, client_name);
214 
215 	if (rc1 == 0 || rc2 == 0) {
216 
217 		DTRACE_PROBE3(receive__invalid__session__req,
218 		    struct session *, session, char *, names,
219 		    uint32_t, hdr.xh_length);
220 
221 		kmem_free(names, hdr.xh_length);
222 		MBC_INIT(&mbc, MAX_DATAGRAM_LENGTH);
223 		(void) smb_mbc_encodef(&mbc, "b",
224 		    DATAGRAM_INVALID_SOURCE_NAME_FORMAT);
225 		(void) smb_session_send(session, NEGATIVE_SESSION_RESPONSE,
226 		    &mbc);
227 		return (EINVAL);
228 	}
229 
230 	DTRACE_PROBE3(receive__session__req__calling__decoded,
231 	    struct session *, session,
232 	    char *, calling_name, char *, client_name);
233 
234 	/*
235 	 * The client NetBIOS name is in oem codepage format.
236 	 * We need to convert it to unicode and store it in
237 	 * multi-byte format.  We also need to strip off any
238 	 * spaces added as part of the NetBIOS name encoding.
239 	 */
240 	wbuf = kmem_alloc((SMB_PI_MAX_HOST * sizeof (smb_wchar_t)), KM_SLEEP);
241 	(void) oemtoucs(wbuf, client_name, SMB_PI_MAX_HOST, OEM_CPG_850);
242 	(void) smb_wcstombs(session->workstation, wbuf, SMB_PI_MAX_HOST);
243 	kmem_free(wbuf, (SMB_PI_MAX_HOST * sizeof (smb_wchar_t)));
244 
245 	if ((p = strchr(session->workstation, ' ')) != 0)
246 		*p = '\0';
247 
248 	kmem_free(names, hdr.xh_length);
249 	return (smb_session_send(session, POSITIVE_SESSION_RESPONSE, NULL));
250 }
251 
252 /*
253  * Read 4-byte header from the session socket and build an in-memory
254  * session transport header.  See smb_xprt_t definition for header
255  * format information.
256  *
257  * Direct hosted NetBIOS-less SMB (SMB-over-TCP) uses port 445.  The
258  * first byte of the four-byte header must be 0 and the next three
259  * bytes contain the length of the remaining data.
260  */
261 int
262 smb_session_xprt_gethdr(smb_session_t *session, smb_xprt_t *ret_hdr)
263 {
264 	int		rc;
265 	unsigned char	buf[NETBIOS_HDR_SZ];
266 
267 	if ((rc = smb_sorecv(session->sock, buf, NETBIOS_HDR_SZ)) != 0)
268 		return (rc);
269 
270 	switch (session->s_local_port) {
271 	case IPPORT_NETBIOS_SSN:
272 		ret_hdr->xh_type = buf[0];
273 		ret_hdr->xh_length = (((uint32_t)buf[1] & 1) << 16) |
274 		    ((uint32_t)buf[2] << 8) |
275 		    ((uint32_t)buf[3]);
276 		break;
277 
278 	case IPPORT_SMB:
279 		ret_hdr->xh_type = buf[0];
280 
281 		if (ret_hdr->xh_type != 0) {
282 			cmn_err(CE_WARN, "invalid type (%u)", ret_hdr->xh_type);
283 			dump_smb_inaddr(&session->ipaddr);
284 			return (EPROTO);
285 		}
286 
287 		ret_hdr->xh_length = ((uint32_t)buf[1] << 16) |
288 		    ((uint32_t)buf[2] << 8) |
289 		    ((uint32_t)buf[3]);
290 		break;
291 
292 	default:
293 		cmn_err(CE_WARN, "invalid port %u", session->s_local_port);
294 		dump_smb_inaddr(&session->ipaddr);
295 		return (EPROTO);
296 	}
297 
298 	return (0);
299 }
300 
301 /*
302  * Encode a transport session packet header into a 4-byte buffer.
303  * See smb_xprt_t definition for header format information.
304  */
305 static int
306 smb_session_xprt_puthdr(smb_session_t *session, smb_xprt_t *hdr,
307     uint8_t *buf, size_t buflen)
308 {
309 	if (session == NULL || hdr == NULL ||
310 	    buf == NULL || buflen < NETBIOS_HDR_SZ) {
311 		return (-1);
312 	}
313 
314 	switch (session->s_local_port) {
315 	case IPPORT_NETBIOS_SSN:
316 		buf[0] = hdr->xh_type;
317 		buf[1] = ((hdr->xh_length >> 16) & 1);
318 		buf[2] = (hdr->xh_length >> 8) & 0xff;
319 		buf[3] = hdr->xh_length & 0xff;
320 		break;
321 
322 	case IPPORT_SMB:
323 		buf[0] = hdr->xh_type;
324 		buf[1] = (hdr->xh_length >> 16) & 0xff;
325 		buf[2] = (hdr->xh_length >> 8) & 0xff;
326 		buf[3] = hdr->xh_length & 0xff;
327 		break;
328 
329 	default:
330 		cmn_err(CE_WARN, "invalid port %u", session->s_local_port);
331 		dump_smb_inaddr(&session->ipaddr);
332 		return (-1);
333 	}
334 
335 	return (0);
336 }
337 
338 static void
339 smb_request_init_command_mbuf(smb_request_t *sr)
340 {
341 
342 	/*
343 	 * Setup mbuf using the buffer we allocated.
344 	 */
345 	MBC_ATTACH_BUF(&sr->command, sr->sr_request_buf, sr->sr_req_length);
346 
347 	sr->command.flags = 0;
348 	sr->command.shadow_of = NULL;
349 }
350 
351 /*
352  * smb_request_cancel
353  *
354  * Handle a cancel for a request properly depending on the current request
355  * state.
356  */
357 void
358 smb_request_cancel(smb_request_t *sr)
359 {
360 	mutex_enter(&sr->sr_mutex);
361 	switch (sr->sr_state) {
362 
363 	case SMB_REQ_STATE_INITIALIZING:
364 	case SMB_REQ_STATE_SUBMITTED:
365 	case SMB_REQ_STATE_ACTIVE:
366 	case SMB_REQ_STATE_CLEANED_UP:
367 		sr->sr_state = SMB_REQ_STATE_CANCELED;
368 		break;
369 
370 	case SMB_REQ_STATE_WAITING_LOCK:
371 		/*
372 		 * This request is waiting on a lock.  Wakeup everything
373 		 * waiting on the lock so that the relevant thread regains
374 		 * control and notices that is has been canceled.  The
375 		 * other lock request threads waiting on this lock will go
376 		 * back to sleep when they discover they are still blocked.
377 		 */
378 		sr->sr_state = SMB_REQ_STATE_CANCELED;
379 
380 		ASSERT(sr->sr_awaiting != NULL);
381 		mutex_enter(&sr->sr_awaiting->l_mutex);
382 		cv_broadcast(&sr->sr_awaiting->l_cv);
383 		mutex_exit(&sr->sr_awaiting->l_mutex);
384 		break;
385 
386 	case SMB_REQ_STATE_WAITING_EVENT:
387 		/*
388 		 * This request is waiting in change notify.
389 		 */
390 		sr->sr_state = SMB_REQ_STATE_CANCELED;
391 		cv_signal(&sr->sr_ncr.nc_cv);
392 		break;
393 
394 	case SMB_REQ_STATE_EVENT_OCCURRED:
395 	case SMB_REQ_STATE_COMPLETED:
396 	case SMB_REQ_STATE_CANCELED:
397 		/*
398 		 * No action required for these states since the request
399 		 * is completing.
400 		 */
401 		break;
402 
403 	case SMB_REQ_STATE_FREE:
404 	default:
405 		SMB_PANIC();
406 	}
407 	mutex_exit(&sr->sr_mutex);
408 }
409 
410 /*
411  * smb_session_receiver
412  *
413  * Receives request from the network and dispatches them to a worker.
414  */
415 void
416 smb_session_receiver(smb_session_t *session)
417 {
418 	int	rc;
419 
420 	SMB_SESSION_VALID(session);
421 
422 	session->s_thread = curthread;
423 
424 	if (session->s_local_port == IPPORT_NETBIOS_SSN) {
425 		rc = smb_session_request(session);
426 		if (rc != 0) {
427 			smb_rwx_rwenter(&session->s_lock, RW_WRITER);
428 			session->s_state = SMB_SESSION_STATE_DISCONNECTED;
429 			smb_rwx_rwexit(&session->s_lock);
430 			return;
431 		}
432 	}
433 
434 	smb_rwx_rwenter(&session->s_lock, RW_WRITER);
435 	session->s_state = SMB_SESSION_STATE_ESTABLISHED;
436 	smb_rwx_rwexit(&session->s_lock);
437 
438 	(void) smb_session_message(session);
439 
440 	smb_rwx_rwenter(&session->s_lock, RW_WRITER);
441 	session->s_state = SMB_SESSION_STATE_DISCONNECTED;
442 	smb_rwx_rwexit(&session->s_lock);
443 
444 	smb_soshutdown(session->sock);
445 
446 	DTRACE_PROBE2(session__drop, struct session *, session, int, rc);
447 
448 	smb_session_cancel(session);
449 	/*
450 	 * At this point everything related to the session should have been
451 	 * cleaned up and we expect that nothing will attempt to use the
452 	 * socket.
453 	 */
454 }
455 
456 /*
457  * smb_session_disconnect
458  *
459  * Disconnects the session passed in.
460  */
461 void
462 smb_session_disconnect(smb_session_t *session)
463 {
464 	SMB_SESSION_VALID(session);
465 
466 	smb_rwx_rwenter(&session->s_lock, RW_WRITER);
467 	switch (session->s_state) {
468 	case SMB_SESSION_STATE_INITIALIZED:
469 	case SMB_SESSION_STATE_CONNECTED:
470 	case SMB_SESSION_STATE_ESTABLISHED:
471 	case SMB_SESSION_STATE_NEGOTIATED:
472 	case SMB_SESSION_STATE_OPLOCK_BREAKING:
473 	case SMB_SESSION_STATE_WRITE_RAW_ACTIVE:
474 	case SMB_SESSION_STATE_READ_RAW_ACTIVE:
475 		smb_soshutdown(session->sock);
476 		session->s_state = SMB_SESSION_STATE_DISCONNECTED;
477 		_NOTE(FALLTHRU)
478 	case SMB_SESSION_STATE_DISCONNECTED:
479 	case SMB_SESSION_STATE_TERMINATED:
480 		break;
481 	}
482 	smb_rwx_rwexit(&session->s_lock);
483 }
484 
485 /*
486  * Read and process SMB requests.
487  *
488  * Returns:
489  *	0	Success
490  *	1	Unable to read transport header
491  *	2	Invalid transport header type
492  *	3	Invalid SMB length (too small)
493  *	4	Unable to read SMB header
494  *	5	Invalid SMB header (bad magic number)
495  *	6	Unable to read SMB data
496  *	2x	Write raw failed
497  */
498 static int
499 smb_session_message(smb_session_t *session)
500 {
501 	smb_server_t	*sv;
502 	smb_request_t	*sr = NULL;
503 	smb_xprt_t	hdr;
504 	uint8_t		*req_buf;
505 	uint32_t	resid;
506 	int		rc;
507 
508 	sv = session->s_server;
509 
510 	for (;;) {
511 
512 		rc = smb_session_xprt_gethdr(session, &hdr);
513 		if (rc)
514 			return (rc);
515 
516 		DTRACE_PROBE2(session__receive__xprthdr, session_t *, session,
517 		    smb_xprt_t *, &hdr);
518 
519 		if (hdr.xh_type != SESSION_MESSAGE) {
520 			/*
521 			 * Anything other than SESSION_MESSAGE or
522 			 * SESSION_KEEP_ALIVE is an error.  A SESSION_REQUEST
523 			 * may indicate a new session request but we need to
524 			 * close this session and we can treat it as an error
525 			 * here.
526 			 */
527 			if (hdr.xh_type == SESSION_KEEP_ALIVE) {
528 				session->keep_alive = smb_keep_alive;
529 				continue;
530 			}
531 			return (EPROTO);
532 		}
533 
534 		if (hdr.xh_length < SMB_HEADER_LEN)
535 			return (EPROTO);
536 
537 		session->keep_alive = smb_keep_alive;
538 		/*
539 		 * Allocate a request context, read the SMB header and validate
540 		 * it. The sr includes a buffer large enough to hold the SMB
541 		 * request payload.  If the header looks valid, read any
542 		 * remaining data.
543 		 */
544 		sr = smb_request_alloc(session, hdr.xh_length);
545 
546 		req_buf = (uint8_t *)sr->sr_request_buf;
547 		resid = hdr.xh_length;
548 
549 		rc = smb_sorecv(session->sock, req_buf, SMB_HEADER_LEN);
550 		if (rc) {
551 			smb_request_free(sr);
552 			return (rc);
553 		}
554 
555 		if (SMB_PROTOCOL_MAGIC_INVALID(sr)) {
556 			smb_request_free(sr);
557 			return (EPROTO);
558 		}
559 
560 		if (resid > SMB_HEADER_LEN) {
561 			req_buf += SMB_HEADER_LEN;
562 			resid -= SMB_HEADER_LEN;
563 
564 			rc = smb_sorecv(session->sock, req_buf, resid);
565 			if (rc) {
566 				smb_request_free(sr);
567 				return (rc);
568 			}
569 		}
570 		smb_server_add_rxb(sv,
571 		    (int64_t)(hdr.xh_length + NETBIOS_HDR_SZ));
572 		/*
573 		 * Initialize command MBC to represent the received data.
574 		 */
575 		smb_request_init_command_mbuf(sr);
576 
577 		DTRACE_PROBE1(session__receive__smb, smb_request_t *, sr);
578 
579 		/*
580 		 * If this is a raw write, hand off the request.  The handler
581 		 * will retrieve the remaining raw data and process the request.
582 		 */
583 		if (SMB_IS_WRITERAW(sr)) {
584 			rc = smb_handle_write_raw(session, sr);
585 			if (rc == 0)
586 				continue;
587 			return (rc);
588 		}
589 		if (sr->session->signing.flags & SMB_SIGNING_ENABLED) {
590 			if (SMB_IS_NT_CANCEL(sr)) {
591 				sr->session->signing.seqnum++;
592 				sr->sr_seqnum = sr->session->signing.seqnum + 1;
593 				sr->reply_seqnum = 0;
594 			} else {
595 				sr->session->signing.seqnum += 2;
596 				sr->sr_seqnum = sr->session->signing.seqnum;
597 				sr->reply_seqnum = sr->sr_seqnum + 1;
598 			}
599 		}
600 		sr->sr_time_submitted = gethrtime();
601 		sr->sr_state = SMB_REQ_STATE_SUBMITTED;
602 		smb_srqueue_waitq_enter(session->s_srqueue);
603 		(void) taskq_dispatch(session->s_server->sv_worker_pool,
604 		    smb_session_worker, sr, TQ_SLEEP);
605 	}
606 }
607 
608 /*
609  * Port will be IPPORT_NETBIOS_SSN or IPPORT_SMB.
610  */
611 smb_session_t *
612 smb_session_create(ksocket_t new_so, uint16_t port, smb_server_t *sv,
613     int family)
614 {
615 	struct sockaddr_in	sin;
616 	socklen_t		slen;
617 	struct sockaddr_in6	sin6;
618 	smb_session_t		*session;
619 	int64_t			now;
620 
621 	session = kmem_cache_alloc(smb_cache_session, KM_SLEEP);
622 	bzero(session, sizeof (smb_session_t));
623 
624 	if (smb_idpool_constructor(&session->s_uid_pool)) {
625 		kmem_cache_free(smb_cache_session, session);
626 		return (NULL);
627 	}
628 	if (smb_idpool_constructor(&session->s_tid_pool)) {
629 		smb_idpool_destructor(&session->s_uid_pool);
630 		kmem_cache_free(smb_cache_session, session);
631 		return (NULL);
632 	}
633 
634 	now = ddi_get_lbolt64();
635 
636 	session->s_kid = SMB_NEW_KID();
637 	session->s_state = SMB_SESSION_STATE_INITIALIZED;
638 	session->native_os = NATIVE_OS_UNKNOWN;
639 	session->opentime = now;
640 	session->keep_alive = smb_keep_alive;
641 	session->activity_timestamp = now;
642 
643 	smb_session_genkey(session);
644 
645 	smb_slist_constructor(&session->s_req_list, sizeof (smb_request_t),
646 	    offsetof(smb_request_t, sr_session_lnd));
647 
648 	smb_llist_constructor(&session->s_user_list, sizeof (smb_user_t),
649 	    offsetof(smb_user_t, u_lnd));
650 
651 	smb_llist_constructor(&session->s_tree_list, sizeof (smb_tree_t),
652 	    offsetof(smb_tree_t, t_lnd));
653 
654 	smb_llist_constructor(&session->s_xa_list, sizeof (smb_xa_t),
655 	    offsetof(smb_xa_t, xa_lnd));
656 
657 	list_create(&session->s_oplock_brkreqs, sizeof (mbuf_chain_t),
658 	    offsetof(mbuf_chain_t, mbc_lnd));
659 
660 	smb_net_txl_constructor(&session->s_txlst);
661 
662 	smb_rwx_init(&session->s_lock);
663 
664 	if (new_so != NULL) {
665 		if (family == AF_INET) {
666 			slen = sizeof (sin);
667 			(void) ksocket_getsockname(new_so,
668 			    (struct sockaddr *)&sin, &slen, CRED());
669 			bcopy(&sin.sin_addr,
670 			    &session->local_ipaddr.au_addr.au_ipv4,
671 			    sizeof (in_addr_t));
672 			slen = sizeof (sin);
673 			(void) ksocket_getpeername(new_so,
674 			    (struct sockaddr *)&sin, &slen, CRED());
675 			bcopy(&sin.sin_addr,
676 			    &session->ipaddr.au_addr.au_ipv4,
677 			    sizeof (in_addr_t));
678 		} else {
679 			slen = sizeof (sin6);
680 			(void) ksocket_getsockname(new_so,
681 			    (struct sockaddr *)&sin6, &slen, CRED());
682 			bcopy(&sin6.sin6_addr,
683 			    &session->local_ipaddr.au_addr.au_ipv6,
684 			    sizeof (in6_addr_t));
685 			slen = sizeof (sin6);
686 			(void) ksocket_getpeername(new_so,
687 			    (struct sockaddr *)&sin6, &slen, CRED());
688 			bcopy(&sin6.sin6_addr,
689 			    &session->ipaddr.au_addr.au_ipv6,
690 			    sizeof (in6_addr_t));
691 		}
692 		session->ipaddr.a_family = family;
693 		session->local_ipaddr.a_family = family;
694 		session->s_local_port = port;
695 		session->sock = new_so;
696 		if (port == IPPORT_NETBIOS_SSN)
697 			smb_server_inc_nbt_sess(sv);
698 		else
699 			smb_server_inc_tcp_sess(sv);
700 	}
701 	session->s_server = sv;
702 	smb_server_get_cfg(sv, &session->s_cfg);
703 	session->s_srqueue = &sv->sv_srqueue;
704 
705 	session->s_magic = SMB_SESSION_MAGIC;
706 	return (session);
707 }
708 
709 void
710 smb_session_delete(smb_session_t *session)
711 {
712 	mbuf_chain_t	*mbc;
713 
714 	ASSERT(session->s_magic == SMB_SESSION_MAGIC);
715 
716 	session->s_magic = 0;
717 
718 	smb_rwx_destroy(&session->s_lock);
719 	smb_net_txl_destructor(&session->s_txlst);
720 
721 	while ((mbc = list_head(&session->s_oplock_brkreqs)) != NULL) {
722 		SMB_MBC_VALID(mbc);
723 		list_remove(&session->s_oplock_brkreqs, mbc);
724 		smb_mbc_free(mbc);
725 	}
726 	list_destroy(&session->s_oplock_brkreqs);
727 
728 	smb_slist_destructor(&session->s_req_list);
729 	smb_llist_destructor(&session->s_tree_list);
730 	smb_llist_destructor(&session->s_user_list);
731 	smb_llist_destructor(&session->s_xa_list);
732 
733 	ASSERT(session->s_tree_cnt == 0);
734 	ASSERT(session->s_file_cnt == 0);
735 	ASSERT(session->s_dir_cnt == 0);
736 
737 	smb_idpool_destructor(&session->s_tid_pool);
738 	smb_idpool_destructor(&session->s_uid_pool);
739 	if (session->sock != NULL) {
740 		if (session->s_local_port == IPPORT_NETBIOS_SSN)
741 			smb_server_dec_nbt_sess(session->s_server);
742 		else
743 			smb_server_dec_tcp_sess(session->s_server);
744 		smb_sodestroy(session->sock);
745 	}
746 	kmem_cache_free(smb_cache_session, session);
747 }
748 
749 static void
750 smb_session_cancel(smb_session_t *session)
751 {
752 	smb_xa_t	*xa, *nextxa;
753 
754 	/* All the request currently being treated must be canceled. */
755 	smb_session_cancel_requests(session, NULL, NULL);
756 
757 	/*
758 	 * We wait for the completion of all the requests associated with
759 	 * this session.
760 	 */
761 	smb_slist_wait_for_empty(&session->s_req_list);
762 
763 	/*
764 	 * At this point the reference count of the users, trees, files,
765 	 * directories should be zero. It should be possible to destroy them
766 	 * without any problem.
767 	 */
768 	xa = smb_llist_head(&session->s_xa_list);
769 	while (xa) {
770 		nextxa = smb_llist_next(&session->s_xa_list, xa);
771 		smb_xa_close(xa);
772 		xa = nextxa;
773 	}
774 
775 	smb_session_logoff(session);
776 }
777 
778 /*
779  * Cancel requests.  If a non-null tree is specified, only requests specific
780  * to that tree will be cancelled.  If a non-null sr is specified, that sr
781  * will be not be cancelled - this would typically be the caller's sr.
782  */
783 void
784 smb_session_cancel_requests(
785     smb_session_t	*session,
786     smb_tree_t		*tree,
787     smb_request_t	*exclude_sr)
788 {
789 	smb_request_t	*sr;
790 
791 	smb_slist_enter(&session->s_req_list);
792 	sr = smb_slist_head(&session->s_req_list);
793 
794 	while (sr) {
795 		ASSERT(sr->sr_magic == SMB_REQ_MAGIC);
796 		if ((sr != exclude_sr) &&
797 		    (tree == NULL || sr->tid_tree == tree))
798 			smb_request_cancel(sr);
799 
800 		sr = smb_slist_next(&session->s_req_list, sr);
801 	}
802 
803 	smb_slist_exit(&session->s_req_list);
804 }
805 
806 void
807 smb_session_worker(void	*arg)
808 {
809 	smb_request_t	*sr;
810 	smb_srqueue_t	*srq;
811 
812 	sr = (smb_request_t *)arg;
813 	SMB_REQ_VALID(sr);
814 
815 	srq = sr->session->s_srqueue;
816 	smb_srqueue_waitq_to_runq(srq);
817 	sr->sr_worker = curthread;
818 	mutex_enter(&sr->sr_mutex);
819 	sr->sr_time_active = gethrtime();
820 	switch (sr->sr_state) {
821 	case SMB_REQ_STATE_SUBMITTED:
822 		mutex_exit(&sr->sr_mutex);
823 		if (smb_dispatch_request(sr)) {
824 			mutex_enter(&sr->sr_mutex);
825 			sr->sr_state = SMB_REQ_STATE_COMPLETED;
826 			mutex_exit(&sr->sr_mutex);
827 			smb_request_free(sr);
828 		}
829 		break;
830 
831 	default:
832 		ASSERT(sr->sr_state == SMB_REQ_STATE_CANCELED);
833 		sr->sr_state = SMB_REQ_STATE_COMPLETED;
834 		mutex_exit(&sr->sr_mutex);
835 		smb_request_free(sr);
836 		break;
837 	}
838 	smb_srqueue_runq_exit(srq);
839 }
840 
841 /*
842  * smb_session_lookup_user
843  */
844 static smb_user_t *
845 smb_session_lookup_user(smb_session_t *session, char *domain, char *name)
846 {
847 	smb_user_t	*user;
848 	smb_llist_t	*ulist;
849 
850 	ulist = &session->s_user_list;
851 	smb_llist_enter(ulist, RW_READER);
852 	user = smb_llist_head(ulist);
853 	while (user) {
854 		ASSERT(user->u_magic == SMB_USER_MAGIC);
855 		if (!smb_strcasecmp(user->u_name, name, 0) &&
856 		    !smb_strcasecmp(user->u_domain, domain, 0)) {
857 			if (smb_user_hold(user))
858 				break;
859 		}
860 		user = smb_llist_next(ulist, user);
861 	}
862 	smb_llist_exit(ulist);
863 
864 	return (user);
865 }
866 
867 /*
868  * If a user attempts to log in subsequently from the specified session,
869  * duplicates the existing SMB user instance such that all SMB user
870  * instances that corresponds to the same user on the given session
871  * reference the same user's cred.
872  *
873  * Returns NULL if the given user hasn't yet logged in from this
874  * specified session.  Otherwise, returns a user instance that corresponds
875  * to this subsequent login.
876  */
877 smb_user_t *
878 smb_session_dup_user(smb_session_t *session, char *domain, char *account_name)
879 {
880 	smb_user_t *orig_user = NULL;
881 	smb_user_t *user = NULL;
882 
883 	orig_user = smb_session_lookup_user(session, domain,
884 	    account_name);
885 
886 	if (orig_user) {
887 		user = smb_user_dup(orig_user);
888 		smb_user_release(orig_user);
889 	}
890 
891 	return (user);
892 }
893 
894 /*
895  * Find a user on the specified session by SMB UID.
896  */
897 smb_user_t *
898 smb_session_lookup_uid(smb_session_t *session, uint16_t uid)
899 {
900 	smb_user_t	*user;
901 	smb_llist_t	*user_list;
902 
903 	SMB_SESSION_VALID(session);
904 
905 	user_list = &session->s_user_list;
906 	smb_llist_enter(user_list, RW_READER);
907 
908 	user = smb_llist_head(user_list);
909 	while (user) {
910 		SMB_USER_VALID(user);
911 		ASSERT(user->u_session == session);
912 
913 		if (user->u_uid == uid) {
914 			if (!smb_user_hold(user))
915 				break;
916 
917 			smb_llist_exit(user_list);
918 			return (user);
919 		}
920 
921 		user = smb_llist_next(user_list, user);
922 	}
923 
924 	smb_llist_exit(user_list);
925 	return (NULL);
926 }
927 
928 void
929 smb_session_post_user(smb_session_t *session, smb_user_t *user)
930 {
931 	SMB_USER_VALID(user);
932 	ASSERT(user->u_refcnt == 0);
933 	ASSERT(user->u_state == SMB_USER_STATE_LOGGED_OFF);
934 	ASSERT(user->u_session == session);
935 
936 	smb_llist_post(&session->s_user_list, user, smb_user_delete);
937 }
938 
939 /*
940  * Find a tree by tree-id.
941  */
942 smb_tree_t *
943 smb_session_lookup_tree(
944     smb_session_t	*session,
945     uint16_t		tid)
946 
947 {
948 	smb_tree_t	*tree;
949 
950 	SMB_SESSION_VALID(session);
951 
952 	smb_llist_enter(&session->s_tree_list, RW_READER);
953 	tree = smb_llist_head(&session->s_tree_list);
954 
955 	while (tree) {
956 		ASSERT3U(tree->t_magic, ==, SMB_TREE_MAGIC);
957 		ASSERT(tree->t_session == session);
958 
959 		if (tree->t_tid == tid) {
960 			if (smb_tree_hold(tree)) {
961 				smb_llist_exit(&session->s_tree_list);
962 				return (tree);
963 			} else {
964 				smb_llist_exit(&session->s_tree_list);
965 				return (NULL);
966 			}
967 		}
968 
969 		tree = smb_llist_next(&session->s_tree_list, tree);
970 	}
971 
972 	smb_llist_exit(&session->s_tree_list);
973 	return (NULL);
974 }
975 
976 /*
977  * Find the first connected tree that matches the specified sharename.
978  * If the specified tree is NULL the search starts from the beginning of
979  * the user's tree list.  If a tree is provided the search starts just
980  * after that tree.
981  */
982 smb_tree_t *
983 smb_session_lookup_share(
984     smb_session_t	*session,
985     const char		*sharename,
986     smb_tree_t		*tree)
987 {
988 	SMB_SESSION_VALID(session);
989 	ASSERT(sharename);
990 
991 	smb_llist_enter(&session->s_tree_list, RW_READER);
992 
993 	if (tree) {
994 		ASSERT3U(tree->t_magic, ==, SMB_TREE_MAGIC);
995 		ASSERT(tree->t_session == session);
996 		tree = smb_llist_next(&session->s_tree_list, tree);
997 	} else {
998 		tree = smb_llist_head(&session->s_tree_list);
999 	}
1000 
1001 	while (tree) {
1002 		ASSERT3U(tree->t_magic, ==, SMB_TREE_MAGIC);
1003 		ASSERT(tree->t_session == session);
1004 		if (smb_strcasecmp(tree->t_sharename, sharename, 0) == 0) {
1005 			if (smb_tree_hold(tree)) {
1006 				smb_llist_exit(&session->s_tree_list);
1007 				return (tree);
1008 			}
1009 		}
1010 		tree = smb_llist_next(&session->s_tree_list, tree);
1011 	}
1012 
1013 	smb_llist_exit(&session->s_tree_list);
1014 	return (NULL);
1015 }
1016 
1017 /*
1018  * Find the first connected tree that matches the specified volume name.
1019  * If the specified tree is NULL the search starts from the beginning of
1020  * the user's tree list.  If a tree is provided the search starts just
1021  * after that tree.
1022  */
1023 smb_tree_t *
1024 smb_session_lookup_volume(
1025     smb_session_t	*session,
1026     const char		*name,
1027     smb_tree_t		*tree)
1028 {
1029 	SMB_SESSION_VALID(session);
1030 	ASSERT(name);
1031 
1032 	smb_llist_enter(&session->s_tree_list, RW_READER);
1033 
1034 	if (tree) {
1035 		ASSERT3U(tree->t_magic, ==, SMB_TREE_MAGIC);
1036 		ASSERT(tree->t_session == session);
1037 		tree = smb_llist_next(&session->s_tree_list, tree);
1038 	} else {
1039 		tree = smb_llist_head(&session->s_tree_list);
1040 	}
1041 
1042 	while (tree) {
1043 		ASSERT3U(tree->t_magic, ==, SMB_TREE_MAGIC);
1044 		ASSERT(tree->t_session == session);
1045 
1046 		if (smb_strcasecmp(tree->t_volume, name, 0) == 0) {
1047 			if (smb_tree_hold(tree)) {
1048 				smb_llist_exit(&session->s_tree_list);
1049 				return (tree);
1050 			}
1051 		}
1052 
1053 		tree = smb_llist_next(&session->s_tree_list, tree);
1054 	}
1055 
1056 	smb_llist_exit(&session->s_tree_list);
1057 	return (NULL);
1058 }
1059 
1060 /*
1061  * Disconnect all trees that match the specified client process-id.
1062  */
1063 void
1064 smb_session_close_pid(
1065     smb_session_t	*session,
1066     uint16_t		pid)
1067 {
1068 	smb_tree_t	*tree;
1069 
1070 	SMB_SESSION_VALID(session);
1071 
1072 	tree = smb_session_get_tree(session, NULL);
1073 	while (tree) {
1074 		smb_tree_t *next;
1075 		ASSERT3U(tree->t_magic, ==, SMB_TREE_MAGIC);
1076 		ASSERT(tree->t_session == session);
1077 		smb_tree_close_pid(tree, pid);
1078 		next = smb_session_get_tree(session, tree);
1079 		smb_tree_release(tree);
1080 		tree = next;
1081 	}
1082 }
1083 
1084 static void
1085 smb_session_tree_dtor(void *t)
1086 {
1087 	smb_tree_t	*tree = (smb_tree_t *)t;
1088 
1089 	smb_tree_disconnect(tree, B_TRUE);
1090 	/* release the ref acquired during the traversal loop */
1091 	smb_tree_release(tree);
1092 }
1093 
1094 
1095 /*
1096  * Disconnect all trees that this user has connected.
1097  */
1098 void
1099 smb_session_disconnect_owned_trees(
1100     smb_session_t	*session,
1101     smb_user_t		*owner)
1102 {
1103 	smb_tree_t	*tree;
1104 	smb_llist_t	*tree_list = &session->s_tree_list;
1105 
1106 	SMB_SESSION_VALID(session);
1107 	SMB_USER_VALID(owner);
1108 
1109 	smb_llist_enter(tree_list, RW_READER);
1110 
1111 	tree = smb_llist_head(tree_list);
1112 	while (tree) {
1113 		if ((tree->t_owner == owner) &&
1114 		    smb_tree_hold(tree)) {
1115 			/*
1116 			 * smb_tree_hold() succeeded, hence we are in state
1117 			 * SMB_TREE_STATE_CONNECTED; schedule this tree
1118 			 * for asynchronous disconnect, which will fire
1119 			 * after we drop the llist traversal lock.
1120 			 */
1121 			smb_llist_post(tree_list, tree, smb_session_tree_dtor);
1122 		}
1123 		tree = smb_llist_next(tree_list, tree);
1124 	}
1125 
1126 	/* drop the lock and flush the dtor queue */
1127 	smb_llist_exit(tree_list);
1128 }
1129 
1130 /*
1131  * Disconnect all trees that this user has connected.
1132  */
1133 void
1134 smb_session_disconnect_trees(
1135     smb_session_t	*session)
1136 {
1137 	smb_tree_t	*tree;
1138 
1139 	SMB_SESSION_VALID(session);
1140 
1141 	tree = smb_session_get_tree(session, NULL);
1142 	while (tree) {
1143 		ASSERT3U(tree->t_magic, ==, SMB_TREE_MAGIC);
1144 		ASSERT(tree->t_session == session);
1145 		smb_tree_disconnect(tree, B_TRUE);
1146 		smb_tree_release(tree);
1147 		tree = smb_session_get_tree(session, NULL);
1148 	}
1149 }
1150 
1151 /*
1152  * Disconnect all trees that match the specified share name.
1153  */
1154 void
1155 smb_session_disconnect_share(
1156     smb_session_t	*session,
1157     const char		*sharename)
1158 {
1159 	smb_tree_t	*tree;
1160 	smb_tree_t	*next;
1161 
1162 	SMB_SESSION_VALID(session);
1163 
1164 	tree = smb_session_lookup_share(session, sharename, NULL);
1165 	while (tree) {
1166 		ASSERT3U(tree->t_magic, ==, SMB_TREE_MAGIC);
1167 		ASSERT(tree->t_session == session);
1168 		smb_session_cancel_requests(session, tree, NULL);
1169 		smb_tree_disconnect(tree, B_TRUE);
1170 		next = smb_session_lookup_share(session, sharename, tree);
1171 		smb_tree_release(tree);
1172 		tree = next;
1173 	}
1174 }
1175 
1176 void
1177 smb_session_post_tree(smb_session_t *session, smb_tree_t *tree)
1178 {
1179 	SMB_SESSION_VALID(session);
1180 	SMB_TREE_VALID(tree);
1181 	ASSERT0(tree->t_refcnt);
1182 	ASSERT(tree->t_state == SMB_TREE_STATE_DISCONNECTED);
1183 	ASSERT(tree->t_session == session);
1184 
1185 	smb_llist_post(&session->s_tree_list, tree, smb_tree_dealloc);
1186 }
1187 
1188 /*
1189  * Get the next connected tree in the list.  A reference is taken on
1190  * the tree, which can be released later with smb_tree_release().
1191  *
1192  * If the specified tree is NULL the search starts from the beginning of
1193  * the tree list.  If a tree is provided the search starts just after
1194  * that tree.
1195  *
1196  * Returns NULL if there are no connected trees in the list.
1197  */
1198 static smb_tree_t *
1199 smb_session_get_tree(
1200     smb_session_t	*session,
1201     smb_tree_t		*tree)
1202 {
1203 	smb_llist_t	*tree_list;
1204 
1205 	SMB_SESSION_VALID(session);
1206 	tree_list = &session->s_tree_list;
1207 
1208 	smb_llist_enter(tree_list, RW_READER);
1209 
1210 	if (tree) {
1211 		ASSERT3U(tree->t_magic, ==, SMB_TREE_MAGIC);
1212 		tree = smb_llist_next(tree_list, tree);
1213 	} else {
1214 		tree = smb_llist_head(tree_list);
1215 	}
1216 
1217 	while (tree) {
1218 		if (smb_tree_hold(tree))
1219 			break;
1220 
1221 		tree = smb_llist_next(tree_list, tree);
1222 	}
1223 
1224 	smb_llist_exit(tree_list);
1225 	return (tree);
1226 }
1227 
1228 /*
1229  * Logoff all users associated with the specified session.
1230  */
1231 static void
1232 smb_session_logoff(smb_session_t *session)
1233 {
1234 	smb_user_t	*user;
1235 
1236 	SMB_SESSION_VALID(session);
1237 
1238 	smb_session_disconnect_trees(session);
1239 
1240 	smb_llist_enter(&session->s_user_list, RW_READER);
1241 
1242 	user = smb_llist_head(&session->s_user_list);
1243 	while (user) {
1244 		SMB_USER_VALID(user);
1245 		ASSERT(user->u_session == session);
1246 
1247 		if (smb_user_hold(user)) {
1248 			smb_user_logoff(user);
1249 			smb_user_release(user);
1250 		}
1251 
1252 		user = smb_llist_next(&session->s_user_list, user);
1253 	}
1254 
1255 	smb_llist_exit(&session->s_user_list);
1256 }
1257 
1258 /*
1259  * Copy the session workstation/client name to buf.  If the workstation
1260  * is an empty string (which it will be on TCP connections), use the
1261  * client IP address.
1262  */
1263 void
1264 smb_session_getclient(smb_session_t *sn, char *buf, size_t buflen)
1265 {
1266 	char		ipbuf[INET6_ADDRSTRLEN];
1267 	smb_inaddr_t	*ipaddr;
1268 
1269 	ASSERT(sn);
1270 	ASSERT(buf);
1271 	ASSERT(buflen);
1272 
1273 	*buf = '\0';
1274 
1275 	if (sn->workstation[0] != '\0') {
1276 		(void) strlcpy(buf, sn->workstation, buflen);
1277 		return;
1278 	}
1279 
1280 	ipaddr = &sn->ipaddr;
1281 	if (smb_inet_ntop(ipaddr, ipbuf, SMB_IPSTRLEN(ipaddr->a_family)))
1282 		(void) strlcpy(buf, ipbuf, buflen);
1283 }
1284 
1285 /*
1286  * Check whether or not the specified client name is the client of this
1287  * session.  The name may be in UNC format (\\CLIENT).
1288  *
1289  * A workstation/client name is setup on NBT connections as part of the
1290  * NetBIOS session request but that isn't available on TCP connections.
1291  * If the session doesn't have a client name we typically return the
1292  * client IP address as the workstation name on MSRPC requests.  So we
1293  * check for the IP address here in addition to the workstation name.
1294  */
1295 boolean_t
1296 smb_session_isclient(smb_session_t *sn, const char *client)
1297 {
1298 	char		buf[INET6_ADDRSTRLEN];
1299 	smb_inaddr_t	*ipaddr;
1300 
1301 	client += strspn(client, "\\");
1302 
1303 	if (smb_strcasecmp(client, sn->workstation, 0) == 0)
1304 		return (B_TRUE);
1305 
1306 	ipaddr = &sn->ipaddr;
1307 	if (smb_inet_ntop(ipaddr, buf, SMB_IPSTRLEN(ipaddr->a_family)) == NULL)
1308 		return (B_FALSE);
1309 
1310 	if (smb_strcasecmp(client, buf, 0) == 0)
1311 		return (B_TRUE);
1312 
1313 	return (B_FALSE);
1314 }
1315 
1316 /*
1317  * smb_request_alloc
1318  *
1319  * Allocate an smb_request_t structure from the kmem_cache.  Partially
1320  * initialize the found/new request.
1321  *
1322  * Returns pointer to a request
1323  */
1324 smb_request_t *
1325 smb_request_alloc(smb_session_t *session, int req_length)
1326 {
1327 	smb_request_t	*sr;
1328 
1329 	ASSERT(session->s_magic == SMB_SESSION_MAGIC);
1330 
1331 	sr = kmem_cache_alloc(smb_cache_request, KM_SLEEP);
1332 
1333 	/*
1334 	 * Future:  Use constructor to pre-initialize some fields.  For now
1335 	 * there are so many fields that it is easiest just to zero the
1336 	 * whole thing and start over.
1337 	 */
1338 	bzero(sr, sizeof (smb_request_t));
1339 
1340 	mutex_init(&sr->sr_mutex, NULL, MUTEX_DEFAULT, NULL);
1341 	cv_init(&sr->sr_ncr.nc_cv, NULL, CV_DEFAULT, NULL);
1342 	smb_srm_init(sr);
1343 	sr->session = session;
1344 	sr->sr_server = session->s_server;
1345 	sr->sr_gmtoff = session->s_server->si_gmtoff;
1346 	sr->sr_cfg = &session->s_cfg;
1347 	sr->command.max_bytes = req_length;
1348 	sr->reply.max_bytes = smb_maxbufsize;
1349 	sr->sr_req_length = req_length;
1350 	if (req_length)
1351 		sr->sr_request_buf = kmem_alloc(req_length, KM_SLEEP);
1352 	sr->sr_magic = SMB_REQ_MAGIC;
1353 	sr->sr_state = SMB_REQ_STATE_INITIALIZING;
1354 	smb_slist_insert_tail(&session->s_req_list, sr);
1355 	return (sr);
1356 }
1357 
1358 /*
1359  * smb_request_free
1360  *
1361  * release the memories which have been allocated for a smb request.
1362  */
1363 void
1364 smb_request_free(smb_request_t *sr)
1365 {
1366 	ASSERT(sr->sr_magic == SMB_REQ_MAGIC);
1367 	ASSERT(sr->session);
1368 	ASSERT(sr->r_xa == NULL);
1369 	ASSERT(sr->sr_ncr.nc_fname == NULL);
1370 
1371 	if (sr->fid_ofile != NULL) {
1372 		smb_ofile_request_complete(sr->fid_ofile);
1373 		smb_ofile_release(sr->fid_ofile);
1374 	}
1375 
1376 	if (sr->tid_tree != NULL)
1377 		smb_tree_release(sr->tid_tree);
1378 
1379 	if (sr->uid_user != NULL)
1380 		smb_user_release(sr->uid_user);
1381 
1382 	smb_slist_remove(&sr->session->s_req_list, sr);
1383 
1384 	sr->session = NULL;
1385 
1386 	smb_srm_fini(sr);
1387 
1388 	if (sr->sr_request_buf)
1389 		kmem_free(sr->sr_request_buf, sr->sr_req_length);
1390 	if (sr->command.chain)
1391 		m_freem(sr->command.chain);
1392 	if (sr->reply.chain)
1393 		m_freem(sr->reply.chain);
1394 	if (sr->raw_data.chain)
1395 		m_freem(sr->raw_data.chain);
1396 
1397 	sr->sr_magic = 0;
1398 	cv_destroy(&sr->sr_ncr.nc_cv);
1399 	mutex_destroy(&sr->sr_mutex);
1400 	kmem_cache_free(smb_cache_request, sr);
1401 }
1402 
1403 void
1404 dump_smb_inaddr(smb_inaddr_t *ipaddr)
1405 {
1406 	char ipstr[INET6_ADDRSTRLEN];
1407 
1408 	if (smb_inet_ntop(ipaddr, ipstr, SMB_IPSTRLEN(ipaddr->a_family)))
1409 		cmn_err(CE_WARN, "error ipstr=%s", ipstr);
1410 	else
1411 		cmn_err(CE_WARN, "error converting ip address");
1412 }
1413 
1414 boolean_t
1415 smb_session_oplocks_enable(smb_session_t *session)
1416 {
1417 	SMB_SESSION_VALID(session);
1418 	if (session->s_cfg.skc_oplock_enable == 0)
1419 		return (B_FALSE);
1420 	else
1421 		return (B_TRUE);
1422 }
1423 
1424 boolean_t
1425 smb_session_levelII_oplocks(smb_session_t *session)
1426 {
1427 	SMB_SESSION_VALID(session);
1428 	return (session->capabilities & CAP_LEVEL_II_OPLOCKS);
1429 }
1430 
1431 /*
1432  * smb_session_oplock_break
1433  *
1434  * The session lock must NOT be held by the caller of this thread;
1435  * as this would cause a deadlock.
1436  */
1437 void
1438 smb_session_oplock_break(smb_session_t *session,
1439     uint16_t tid, uint16_t fid, uint8_t brk)
1440 {
1441 	mbuf_chain_t	*mbc;
1442 
1443 	SMB_SESSION_VALID(session);
1444 
1445 	mbc = smb_mbc_alloc(MLEN);
1446 
1447 	(void) smb_mbc_encodef(mbc, "Mb19.wwwwbb3.wbb10.",
1448 	    SMB_COM_LOCKING_ANDX,
1449 	    tid,
1450 	    0xFFFF, 0, 0xFFFF, 8, 0xFF,
1451 	    fid,
1452 	    LOCKING_ANDX_OPLOCK_RELEASE,
1453 	    (brk == SMB_OPLOCK_BREAK_TO_LEVEL_II) ? 1 : 0);
1454 
1455 	smb_rwx_rwenter(&session->s_lock, RW_WRITER);
1456 	switch (session->s_state) {
1457 	case SMB_SESSION_STATE_NEGOTIATED:
1458 	case SMB_SESSION_STATE_OPLOCK_BREAKING:
1459 	case SMB_SESSION_STATE_WRITE_RAW_ACTIVE:
1460 		session->s_state = SMB_SESSION_STATE_OPLOCK_BREAKING;
1461 		(void) smb_session_send(session, 0, mbc);
1462 		smb_mbc_free(mbc);
1463 		break;
1464 
1465 	case SMB_SESSION_STATE_READ_RAW_ACTIVE:
1466 		list_insert_tail(&session->s_oplock_brkreqs, mbc);
1467 		break;
1468 
1469 	case SMB_SESSION_STATE_DISCONNECTED:
1470 	case SMB_SESSION_STATE_TERMINATED:
1471 		smb_mbc_free(mbc);
1472 		break;
1473 
1474 	default:
1475 		SMB_PANIC();
1476 	}
1477 	smb_rwx_rwexit(&session->s_lock);
1478 }
1479 
1480 static void
1481 smb_session_genkey(smb_session_t *session)
1482 {
1483 	uint8_t		tmp_key[SMB_CHALLENGE_SZ];
1484 
1485 	(void) random_get_pseudo_bytes(tmp_key, SMB_CHALLENGE_SZ);
1486 	bcopy(tmp_key, &session->challenge_key, SMB_CHALLENGE_SZ);
1487 	session->challenge_len = SMB_CHALLENGE_SZ;
1488 
1489 	(void) random_get_pseudo_bytes(tmp_key, 4);
1490 	session->sesskey = tmp_key[0] | tmp_key[1] << 8 |
1491 	    tmp_key[2] << 16 | tmp_key[3] << 24;
1492 }
1493