xref: /titanic_44/usr/src/uts/common/fs/smbsrv/smb_session.c (revision bde3d612a7c090234c60e6e4578821237a5db135)
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(sv->si_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(sv->si_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(sv->si_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_cache_request = sv->si_cache_request;
706 	session->s_cache = sv->si_cache_session;
707 	session->s_magic = SMB_SESSION_MAGIC;
708 	return (session);
709 }
710 
711 void
712 smb_session_delete(smb_session_t *session)
713 {
714 	mbuf_chain_t	*mbc;
715 
716 	ASSERT(session->s_magic == SMB_SESSION_MAGIC);
717 
718 	session->s_magic = 0;
719 
720 	smb_rwx_destroy(&session->s_lock);
721 	smb_net_txl_destructor(&session->s_txlst);
722 
723 	while ((mbc = list_head(&session->s_oplock_brkreqs)) != NULL) {
724 		SMB_MBC_VALID(mbc);
725 		list_remove(&session->s_oplock_brkreqs, mbc);
726 		smb_mbc_free(mbc);
727 	}
728 	list_destroy(&session->s_oplock_brkreqs);
729 
730 	smb_slist_destructor(&session->s_req_list);
731 	smb_llist_destructor(&session->s_tree_list);
732 	smb_llist_destructor(&session->s_user_list);
733 	smb_llist_destructor(&session->s_xa_list);
734 
735 	ASSERT(session->s_tree_cnt == 0);
736 	ASSERT(session->s_file_cnt == 0);
737 	ASSERT(session->s_dir_cnt == 0);
738 
739 	smb_idpool_destructor(&session->s_tid_pool);
740 	smb_idpool_destructor(&session->s_uid_pool);
741 	if (session->sock != NULL) {
742 		if (session->s_local_port == IPPORT_NETBIOS_SSN)
743 			smb_server_dec_nbt_sess(session->s_server);
744 		else
745 			smb_server_dec_tcp_sess(session->s_server);
746 		smb_sodestroy(session->sock);
747 	}
748 	kmem_cache_free(session->s_cache, session);
749 }
750 
751 static void
752 smb_session_cancel(smb_session_t *session)
753 {
754 	smb_xa_t	*xa, *nextxa;
755 
756 	/* All the request currently being treated must be canceled. */
757 	smb_session_cancel_requests(session, NULL, NULL);
758 
759 	/*
760 	 * We wait for the completion of all the requests associated with
761 	 * this session.
762 	 */
763 	smb_slist_wait_for_empty(&session->s_req_list);
764 
765 	/*
766 	 * At this point the reference count of the users, trees, files,
767 	 * directories should be zero. It should be possible to destroy them
768 	 * without any problem.
769 	 */
770 	xa = smb_llist_head(&session->s_xa_list);
771 	while (xa) {
772 		nextxa = smb_llist_next(&session->s_xa_list, xa);
773 		smb_xa_close(xa);
774 		xa = nextxa;
775 	}
776 
777 	smb_session_logoff(session);
778 }
779 
780 /*
781  * Cancel requests.  If a non-null tree is specified, only requests specific
782  * to that tree will be cancelled.  If a non-null sr is specified, that sr
783  * will be not be cancelled - this would typically be the caller's sr.
784  */
785 void
786 smb_session_cancel_requests(
787     smb_session_t	*session,
788     smb_tree_t		*tree,
789     smb_request_t	*exclude_sr)
790 {
791 	smb_request_t	*sr;
792 
793 	smb_slist_enter(&session->s_req_list);
794 	sr = smb_slist_head(&session->s_req_list);
795 
796 	while (sr) {
797 		ASSERT(sr->sr_magic == SMB_REQ_MAGIC);
798 		if ((sr != exclude_sr) &&
799 		    (tree == NULL || sr->tid_tree == tree))
800 			smb_request_cancel(sr);
801 
802 		sr = smb_slist_next(&session->s_req_list, sr);
803 	}
804 
805 	smb_slist_exit(&session->s_req_list);
806 }
807 
808 void
809 smb_session_worker(void	*arg)
810 {
811 	smb_request_t	*sr;
812 	smb_srqueue_t	*srq;
813 
814 	sr = (smb_request_t *)arg;
815 	SMB_REQ_VALID(sr);
816 
817 	srq = sr->session->s_srqueue;
818 	smb_srqueue_waitq_to_runq(srq);
819 	sr->sr_worker = curthread;
820 	mutex_enter(&sr->sr_mutex);
821 	sr->sr_time_active = gethrtime();
822 	switch (sr->sr_state) {
823 	case SMB_REQ_STATE_SUBMITTED:
824 		mutex_exit(&sr->sr_mutex);
825 		if (smb_dispatch_request(sr)) {
826 			mutex_enter(&sr->sr_mutex);
827 			sr->sr_state = SMB_REQ_STATE_COMPLETED;
828 			mutex_exit(&sr->sr_mutex);
829 			smb_request_free(sr);
830 		}
831 		break;
832 
833 	default:
834 		ASSERT(sr->sr_state == SMB_REQ_STATE_CANCELED);
835 		sr->sr_state = SMB_REQ_STATE_COMPLETED;
836 		mutex_exit(&sr->sr_mutex);
837 		smb_request_free(sr);
838 		break;
839 	}
840 	smb_srqueue_runq_exit(srq);
841 }
842 
843 /*
844  * smb_session_lookup_user
845  */
846 static smb_user_t *
847 smb_session_lookup_user(smb_session_t *session, char *domain, char *name)
848 {
849 	smb_user_t	*user;
850 	smb_llist_t	*ulist;
851 
852 	ulist = &session->s_user_list;
853 	smb_llist_enter(ulist, RW_READER);
854 	user = smb_llist_head(ulist);
855 	while (user) {
856 		ASSERT(user->u_magic == SMB_USER_MAGIC);
857 		if (!smb_strcasecmp(user->u_name, name, 0) &&
858 		    !smb_strcasecmp(user->u_domain, domain, 0)) {
859 			if (smb_user_hold(user))
860 				break;
861 		}
862 		user = smb_llist_next(ulist, user);
863 	}
864 	smb_llist_exit(ulist);
865 
866 	return (user);
867 }
868 
869 /*
870  * If a user attempts to log in subsequently from the specified session,
871  * duplicates the existing SMB user instance such that all SMB user
872  * instances that corresponds to the same user on the given session
873  * reference the same user's cred.
874  *
875  * Returns NULL if the given user hasn't yet logged in from this
876  * specified session.  Otherwise, returns a user instance that corresponds
877  * to this subsequent login.
878  */
879 smb_user_t *
880 smb_session_dup_user(smb_session_t *session, char *domain, char *account_name)
881 {
882 	smb_user_t *orig_user = NULL;
883 	smb_user_t *user = NULL;
884 
885 	orig_user = smb_session_lookup_user(session, domain,
886 	    account_name);
887 
888 	if (orig_user) {
889 		user = smb_user_dup(orig_user);
890 		smb_user_release(orig_user);
891 	}
892 
893 	return (user);
894 }
895 
896 /*
897  * Find a user on the specified session by SMB UID.
898  */
899 smb_user_t *
900 smb_session_lookup_uid(smb_session_t *session, uint16_t uid)
901 {
902 	smb_user_t	*user;
903 	smb_llist_t	*user_list;
904 
905 	SMB_SESSION_VALID(session);
906 
907 	user_list = &session->s_user_list;
908 	smb_llist_enter(user_list, RW_READER);
909 
910 	user = smb_llist_head(user_list);
911 	while (user) {
912 		SMB_USER_VALID(user);
913 		ASSERT(user->u_session == session);
914 
915 		if (user->u_uid == uid) {
916 			if (!smb_user_hold(user))
917 				break;
918 
919 			smb_llist_exit(user_list);
920 			return (user);
921 		}
922 
923 		user = smb_llist_next(user_list, user);
924 	}
925 
926 	smb_llist_exit(user_list);
927 	return (NULL);
928 }
929 
930 void
931 smb_session_post_user(smb_session_t *session, smb_user_t *user)
932 {
933 	SMB_USER_VALID(user);
934 	ASSERT(user->u_refcnt == 0);
935 	ASSERT(user->u_state == SMB_USER_STATE_LOGGED_OFF);
936 	ASSERT(user->u_session == session);
937 
938 	smb_llist_post(&session->s_user_list, user, smb_user_delete);
939 }
940 
941 /*
942  * Find a tree by tree-id.
943  */
944 smb_tree_t *
945 smb_session_lookup_tree(
946     smb_session_t	*session,
947     uint16_t		tid)
948 
949 {
950 	smb_tree_t	*tree;
951 
952 	SMB_SESSION_VALID(session);
953 
954 	smb_llist_enter(&session->s_tree_list, RW_READER);
955 	tree = smb_llist_head(&session->s_tree_list);
956 
957 	while (tree) {
958 		ASSERT3U(tree->t_magic, ==, SMB_TREE_MAGIC);
959 		ASSERT(tree->t_session == session);
960 
961 		if (tree->t_tid == tid) {
962 			if (smb_tree_hold(tree)) {
963 				smb_llist_exit(&session->s_tree_list);
964 				return (tree);
965 			} else {
966 				smb_llist_exit(&session->s_tree_list);
967 				return (NULL);
968 			}
969 		}
970 
971 		tree = smb_llist_next(&session->s_tree_list, tree);
972 	}
973 
974 	smb_llist_exit(&session->s_tree_list);
975 	return (NULL);
976 }
977 
978 /*
979  * Find the first connected tree that matches the specified sharename.
980  * If the specified tree is NULL the search starts from the beginning of
981  * the user's tree list.  If a tree is provided the search starts just
982  * after that tree.
983  */
984 smb_tree_t *
985 smb_session_lookup_share(
986     smb_session_t	*session,
987     const char		*sharename,
988     smb_tree_t		*tree)
989 {
990 	SMB_SESSION_VALID(session);
991 	ASSERT(sharename);
992 
993 	smb_llist_enter(&session->s_tree_list, RW_READER);
994 
995 	if (tree) {
996 		ASSERT3U(tree->t_magic, ==, SMB_TREE_MAGIC);
997 		ASSERT(tree->t_session == session);
998 		tree = smb_llist_next(&session->s_tree_list, tree);
999 	} else {
1000 		tree = smb_llist_head(&session->s_tree_list);
1001 	}
1002 
1003 	while (tree) {
1004 		ASSERT3U(tree->t_magic, ==, SMB_TREE_MAGIC);
1005 		ASSERT(tree->t_session == session);
1006 		if (smb_strcasecmp(tree->t_sharename, sharename, 0) == 0) {
1007 			if (smb_tree_hold(tree)) {
1008 				smb_llist_exit(&session->s_tree_list);
1009 				return (tree);
1010 			}
1011 		}
1012 		tree = smb_llist_next(&session->s_tree_list, tree);
1013 	}
1014 
1015 	smb_llist_exit(&session->s_tree_list);
1016 	return (NULL);
1017 }
1018 
1019 /*
1020  * Find the first connected tree that matches the specified volume name.
1021  * If the specified tree is NULL the search starts from the beginning of
1022  * the user's tree list.  If a tree is provided the search starts just
1023  * after that tree.
1024  */
1025 smb_tree_t *
1026 smb_session_lookup_volume(
1027     smb_session_t	*session,
1028     const char		*name,
1029     smb_tree_t		*tree)
1030 {
1031 	SMB_SESSION_VALID(session);
1032 	ASSERT(name);
1033 
1034 	smb_llist_enter(&session->s_tree_list, RW_READER);
1035 
1036 	if (tree) {
1037 		ASSERT3U(tree->t_magic, ==, SMB_TREE_MAGIC);
1038 		ASSERT(tree->t_session == session);
1039 		tree = smb_llist_next(&session->s_tree_list, tree);
1040 	} else {
1041 		tree = smb_llist_head(&session->s_tree_list);
1042 	}
1043 
1044 	while (tree) {
1045 		ASSERT3U(tree->t_magic, ==, SMB_TREE_MAGIC);
1046 		ASSERT(tree->t_session == session);
1047 
1048 		if (smb_strcasecmp(tree->t_volume, name, 0) == 0) {
1049 			if (smb_tree_hold(tree)) {
1050 				smb_llist_exit(&session->s_tree_list);
1051 				return (tree);
1052 			}
1053 		}
1054 
1055 		tree = smb_llist_next(&session->s_tree_list, tree);
1056 	}
1057 
1058 	smb_llist_exit(&session->s_tree_list);
1059 	return (NULL);
1060 }
1061 
1062 /*
1063  * Disconnect all trees that match the specified client process-id.
1064  */
1065 void
1066 smb_session_close_pid(
1067     smb_session_t	*session,
1068     uint16_t		pid)
1069 {
1070 	smb_tree_t	*tree;
1071 
1072 	SMB_SESSION_VALID(session);
1073 
1074 	tree = smb_session_get_tree(session, NULL);
1075 	while (tree) {
1076 		smb_tree_t *next;
1077 		ASSERT3U(tree->t_magic, ==, SMB_TREE_MAGIC);
1078 		ASSERT(tree->t_session == session);
1079 		smb_tree_close_pid(tree, pid);
1080 		next = smb_session_get_tree(session, tree);
1081 		smb_tree_release(tree);
1082 		tree = next;
1083 	}
1084 }
1085 
1086 static void
1087 smb_session_tree_dtor(void *t)
1088 {
1089 	smb_tree_t	*tree = (smb_tree_t *)t;
1090 
1091 	smb_tree_disconnect(tree, B_TRUE);
1092 	/* release the ref acquired during the traversal loop */
1093 	smb_tree_release(tree);
1094 }
1095 
1096 
1097 /*
1098  * Disconnect all trees that this user has connected.
1099  */
1100 void
1101 smb_session_disconnect_owned_trees(
1102     smb_session_t	*session,
1103     smb_user_t		*owner)
1104 {
1105 	smb_tree_t	*tree;
1106 	smb_llist_t	*tree_list = &session->s_tree_list;
1107 
1108 	SMB_SESSION_VALID(session);
1109 	SMB_USER_VALID(owner);
1110 
1111 	smb_llist_enter(tree_list, RW_READER);
1112 
1113 	tree = smb_llist_head(tree_list);
1114 	while (tree) {
1115 		if ((tree->t_owner == owner) &&
1116 		    smb_tree_hold(tree)) {
1117 			/*
1118 			 * smb_tree_hold() succeeded, hence we are in state
1119 			 * SMB_TREE_STATE_CONNECTED; schedule this tree
1120 			 * for asynchronous disconnect, which will fire
1121 			 * after we drop the llist traversal lock.
1122 			 */
1123 			smb_llist_post(tree_list, tree, smb_session_tree_dtor);
1124 		}
1125 		tree = smb_llist_next(tree_list, tree);
1126 	}
1127 
1128 	/* drop the lock and flush the dtor queue */
1129 	smb_llist_exit(tree_list);
1130 }
1131 
1132 /*
1133  * Disconnect all trees that this user has connected.
1134  */
1135 void
1136 smb_session_disconnect_trees(
1137     smb_session_t	*session)
1138 {
1139 	smb_tree_t	*tree;
1140 
1141 	SMB_SESSION_VALID(session);
1142 
1143 	tree = smb_session_get_tree(session, NULL);
1144 	while (tree) {
1145 		ASSERT3U(tree->t_magic, ==, SMB_TREE_MAGIC);
1146 		ASSERT(tree->t_session == session);
1147 		smb_tree_disconnect(tree, B_TRUE);
1148 		smb_tree_release(tree);
1149 		tree = smb_session_get_tree(session, NULL);
1150 	}
1151 }
1152 
1153 /*
1154  * Disconnect all trees that match the specified share name.
1155  */
1156 void
1157 smb_session_disconnect_share(
1158     smb_session_t	*session,
1159     const char		*sharename)
1160 {
1161 	smb_tree_t	*tree;
1162 	smb_tree_t	*next;
1163 
1164 	SMB_SESSION_VALID(session);
1165 
1166 	tree = smb_session_lookup_share(session, sharename, NULL);
1167 	while (tree) {
1168 		ASSERT3U(tree->t_magic, ==, SMB_TREE_MAGIC);
1169 		ASSERT(tree->t_session == session);
1170 		smb_session_cancel_requests(session, tree, NULL);
1171 		smb_tree_disconnect(tree, B_TRUE);
1172 		next = smb_session_lookup_share(session, sharename, tree);
1173 		smb_tree_release(tree);
1174 		tree = next;
1175 	}
1176 }
1177 
1178 void
1179 smb_session_post_tree(smb_session_t *session, smb_tree_t *tree)
1180 {
1181 	SMB_SESSION_VALID(session);
1182 	SMB_TREE_VALID(tree);
1183 	ASSERT0(tree->t_refcnt);
1184 	ASSERT(tree->t_state == SMB_TREE_STATE_DISCONNECTED);
1185 	ASSERT(tree->t_session == session);
1186 
1187 	smb_llist_post(&session->s_tree_list, tree, smb_tree_dealloc);
1188 }
1189 
1190 /*
1191  * Get the next connected tree in the list.  A reference is taken on
1192  * the tree, which can be released later with smb_tree_release().
1193  *
1194  * If the specified tree is NULL the search starts from the beginning of
1195  * the tree list.  If a tree is provided the search starts just after
1196  * that tree.
1197  *
1198  * Returns NULL if there are no connected trees in the list.
1199  */
1200 static smb_tree_t *
1201 smb_session_get_tree(
1202     smb_session_t	*session,
1203     smb_tree_t		*tree)
1204 {
1205 	smb_llist_t	*tree_list;
1206 
1207 	SMB_SESSION_VALID(session);
1208 	tree_list = &session->s_tree_list;
1209 
1210 	smb_llist_enter(tree_list, RW_READER);
1211 
1212 	if (tree) {
1213 		ASSERT3U(tree->t_magic, ==, SMB_TREE_MAGIC);
1214 		tree = smb_llist_next(tree_list, tree);
1215 	} else {
1216 		tree = smb_llist_head(tree_list);
1217 	}
1218 
1219 	while (tree) {
1220 		if (smb_tree_hold(tree))
1221 			break;
1222 
1223 		tree = smb_llist_next(tree_list, tree);
1224 	}
1225 
1226 	smb_llist_exit(tree_list);
1227 	return (tree);
1228 }
1229 
1230 /*
1231  * Logoff all users associated with the specified session.
1232  */
1233 static void
1234 smb_session_logoff(smb_session_t *session)
1235 {
1236 	smb_user_t	*user;
1237 
1238 	SMB_SESSION_VALID(session);
1239 
1240 	smb_session_disconnect_trees(session);
1241 
1242 	smb_llist_enter(&session->s_user_list, RW_READER);
1243 
1244 	user = smb_llist_head(&session->s_user_list);
1245 	while (user) {
1246 		SMB_USER_VALID(user);
1247 		ASSERT(user->u_session == session);
1248 
1249 		if (smb_user_hold(user)) {
1250 			smb_user_logoff(user);
1251 			smb_user_release(user);
1252 		}
1253 
1254 		user = smb_llist_next(&session->s_user_list, user);
1255 	}
1256 
1257 	smb_llist_exit(&session->s_user_list);
1258 }
1259 
1260 /*
1261  * Copy the session workstation/client name to buf.  If the workstation
1262  * is an empty string (which it will be on TCP connections), use the
1263  * client IP address.
1264  */
1265 void
1266 smb_session_getclient(smb_session_t *sn, char *buf, size_t buflen)
1267 {
1268 	char		ipbuf[INET6_ADDRSTRLEN];
1269 	smb_inaddr_t	*ipaddr;
1270 
1271 	ASSERT(sn);
1272 	ASSERT(buf);
1273 	ASSERT(buflen);
1274 
1275 	*buf = '\0';
1276 
1277 	if (sn->workstation[0] != '\0') {
1278 		(void) strlcpy(buf, sn->workstation, buflen);
1279 		return;
1280 	}
1281 
1282 	ipaddr = &sn->ipaddr;
1283 	if (smb_inet_ntop(ipaddr, ipbuf, SMB_IPSTRLEN(ipaddr->a_family)))
1284 		(void) strlcpy(buf, ipbuf, buflen);
1285 }
1286 
1287 /*
1288  * Check whether or not the specified client name is the client of this
1289  * session.  The name may be in UNC format (\\CLIENT).
1290  *
1291  * A workstation/client name is setup on NBT connections as part of the
1292  * NetBIOS session request but that isn't available on TCP connections.
1293  * If the session doesn't have a client name we typically return the
1294  * client IP address as the workstation name on MSRPC requests.  So we
1295  * check for the IP address here in addition to the workstation name.
1296  */
1297 boolean_t
1298 smb_session_isclient(smb_session_t *sn, const char *client)
1299 {
1300 	char		buf[INET6_ADDRSTRLEN];
1301 	smb_inaddr_t	*ipaddr;
1302 
1303 	client += strspn(client, "\\");
1304 
1305 	if (smb_strcasecmp(client, sn->workstation, 0) == 0)
1306 		return (B_TRUE);
1307 
1308 	ipaddr = &sn->ipaddr;
1309 	if (smb_inet_ntop(ipaddr, buf, SMB_IPSTRLEN(ipaddr->a_family)) == NULL)
1310 		return (B_FALSE);
1311 
1312 	if (smb_strcasecmp(client, buf, 0) == 0)
1313 		return (B_TRUE);
1314 
1315 	return (B_FALSE);
1316 }
1317 
1318 /*
1319  * smb_request_alloc
1320  *
1321  * Allocate an smb_request_t structure from the kmem_cache.  Partially
1322  * initialize the found/new request.
1323  *
1324  * Returns pointer to a request
1325  */
1326 smb_request_t *
1327 smb_request_alloc(smb_session_t *session, int req_length)
1328 {
1329 	smb_request_t	*sr;
1330 
1331 	ASSERT(session->s_magic == SMB_SESSION_MAGIC);
1332 
1333 	sr = kmem_cache_alloc(session->s_cache_request, KM_SLEEP);
1334 
1335 	/*
1336 	 * Future:  Use constructor to pre-initialize some fields.  For now
1337 	 * there are so many fields that it is easiest just to zero the
1338 	 * whole thing and start over.
1339 	 */
1340 	bzero(sr, sizeof (smb_request_t));
1341 
1342 	mutex_init(&sr->sr_mutex, NULL, MUTEX_DEFAULT, NULL);
1343 	cv_init(&sr->sr_ncr.nc_cv, NULL, CV_DEFAULT, NULL);
1344 	smb_srm_init(sr);
1345 	sr->session = session;
1346 	sr->sr_server = session->s_server;
1347 	sr->sr_gmtoff = session->s_server->si_gmtoff;
1348 	sr->sr_cache = session->s_server->si_cache_request;
1349 	sr->sr_cfg = &session->s_cfg;
1350 	sr->command.max_bytes = req_length;
1351 	sr->reply.max_bytes = smb_maxbufsize;
1352 	sr->sr_req_length = req_length;
1353 	if (req_length)
1354 		sr->sr_request_buf = kmem_alloc(req_length, KM_SLEEP);
1355 	sr->sr_magic = SMB_REQ_MAGIC;
1356 	sr->sr_state = SMB_REQ_STATE_INITIALIZING;
1357 	smb_slist_insert_tail(&session->s_req_list, sr);
1358 	return (sr);
1359 }
1360 
1361 /*
1362  * smb_request_free
1363  *
1364  * release the memories which have been allocated for a smb request.
1365  */
1366 void
1367 smb_request_free(smb_request_t *sr)
1368 {
1369 	ASSERT(sr->sr_magic == SMB_REQ_MAGIC);
1370 	ASSERT(sr->session);
1371 	ASSERT(sr->r_xa == NULL);
1372 	ASSERT(sr->sr_ncr.nc_fname == NULL);
1373 
1374 	if (sr->fid_ofile != NULL) {
1375 		smb_ofile_request_complete(sr->fid_ofile);
1376 		smb_ofile_release(sr->fid_ofile);
1377 	}
1378 
1379 	if (sr->tid_tree != NULL)
1380 		smb_tree_release(sr->tid_tree);
1381 
1382 	if (sr->uid_user != NULL)
1383 		smb_user_release(sr->uid_user);
1384 
1385 	smb_slist_remove(&sr->session->s_req_list, sr);
1386 
1387 	sr->session = NULL;
1388 
1389 	smb_srm_fini(sr);
1390 
1391 	if (sr->sr_request_buf)
1392 		kmem_free(sr->sr_request_buf, sr->sr_req_length);
1393 	if (sr->command.chain)
1394 		m_freem(sr->command.chain);
1395 	if (sr->reply.chain)
1396 		m_freem(sr->reply.chain);
1397 	if (sr->raw_data.chain)
1398 		m_freem(sr->raw_data.chain);
1399 
1400 	sr->sr_magic = 0;
1401 	cv_destroy(&sr->sr_ncr.nc_cv);
1402 	mutex_destroy(&sr->sr_mutex);
1403 	kmem_cache_free(sr->sr_cache, sr);
1404 }
1405 
1406 void
1407 dump_smb_inaddr(smb_inaddr_t *ipaddr)
1408 {
1409 	char ipstr[INET6_ADDRSTRLEN];
1410 
1411 	if (smb_inet_ntop(ipaddr, ipstr, SMB_IPSTRLEN(ipaddr->a_family)))
1412 		cmn_err(CE_WARN, "error ipstr=%s", ipstr);
1413 	else
1414 		cmn_err(CE_WARN, "error converting ip address");
1415 }
1416 
1417 boolean_t
1418 smb_session_oplocks_enable(smb_session_t *session)
1419 {
1420 	SMB_SESSION_VALID(session);
1421 	if (session->s_cfg.skc_oplock_enable == 0)
1422 		return (B_FALSE);
1423 	else
1424 		return (B_TRUE);
1425 }
1426 
1427 boolean_t
1428 smb_session_levelII_oplocks(smb_session_t *session)
1429 {
1430 	SMB_SESSION_VALID(session);
1431 	return (session->capabilities & CAP_LEVEL_II_OPLOCKS);
1432 }
1433 
1434 /*
1435  * smb_session_oplock_break
1436  *
1437  * The session lock must NOT be held by the caller of this thread;
1438  * as this would cause a deadlock.
1439  */
1440 void
1441 smb_session_oplock_break(smb_session_t *session,
1442     uint16_t tid, uint16_t fid, uint8_t brk)
1443 {
1444 	mbuf_chain_t	*mbc;
1445 
1446 	SMB_SESSION_VALID(session);
1447 
1448 	mbc = smb_mbc_alloc(MLEN);
1449 
1450 	(void) smb_mbc_encodef(mbc, "Mb19.wwwwbb3.wbb10.",
1451 	    SMB_COM_LOCKING_ANDX,
1452 	    tid,
1453 	    0xFFFF, 0, 0xFFFF, 8, 0xFF,
1454 	    fid,
1455 	    LOCKING_ANDX_OPLOCK_RELEASE,
1456 	    (brk == SMB_OPLOCK_BREAK_TO_LEVEL_II) ? 1 : 0);
1457 
1458 	smb_rwx_rwenter(&session->s_lock, RW_WRITER);
1459 	switch (session->s_state) {
1460 	case SMB_SESSION_STATE_NEGOTIATED:
1461 	case SMB_SESSION_STATE_OPLOCK_BREAKING:
1462 	case SMB_SESSION_STATE_WRITE_RAW_ACTIVE:
1463 		session->s_state = SMB_SESSION_STATE_OPLOCK_BREAKING;
1464 		(void) smb_session_send(session, 0, mbc);
1465 		smb_mbc_free(mbc);
1466 		break;
1467 
1468 	case SMB_SESSION_STATE_READ_RAW_ACTIVE:
1469 		list_insert_tail(&session->s_oplock_brkreqs, mbc);
1470 		break;
1471 
1472 	case SMB_SESSION_STATE_DISCONNECTED:
1473 	case SMB_SESSION_STATE_TERMINATED:
1474 		smb_mbc_free(mbc);
1475 		break;
1476 
1477 	default:
1478 		SMB_PANIC();
1479 	}
1480 	smb_rwx_rwexit(&session->s_lock);
1481 }
1482 
1483 static void
1484 smb_session_genkey(smb_session_t *session)
1485 {
1486 	uint8_t		tmp_key[SMB_CHALLENGE_SZ];
1487 
1488 	(void) random_get_pseudo_bytes(tmp_key, SMB_CHALLENGE_SZ);
1489 	bcopy(tmp_key, &session->challenge_key, SMB_CHALLENGE_SZ);
1490 	session->challenge_len = SMB_CHALLENGE_SZ;
1491 
1492 	(void) random_get_pseudo_bytes(tmp_key, 4);
1493 	session->sesskey = tmp_key[0] | tmp_key[1] << 8 |
1494 	    tmp_key[2] << 16 | tmp_key[3] << 24;
1495 }
1496