Home | History | Annotate | Download | only in smbsrv
      1 /*
      2  * CDDL HEADER START
      3  *
      4  * The contents of this file are subject to the terms of the
      5  * Common Development and Distribution License (the "License").
      6  * You may not use this file except in compliance with the License.
      7  *
      8  * You can obtain a copy of the license at usr/src/OPENSOLARIS.LICENSE
      9  * or http://www.opensolaris.org/os/licensing.
     10  * See the License for the specific language governing permissions
     11  * and limitations under the License.
     12  *
     13  * When distributing Covered Code, include this CDDL HEADER in each
     14  * file and include the License file at usr/src/OPENSOLARIS.LICENSE.
     15  * If applicable, add the following below this CDDL HEADER, with the
     16  * fields enclosed by brackets "[]" replaced with your own identifying
     17  * information: Portions Copyright [yyyy] [name of copyright owner]
     18  *
     19  * CDDL HEADER END
     20  */
     21 /*
     22  * Copyright 2009 Sun Microsystems, Inc.  All rights reserved.
     23  * Use is subject to license terms.
     24  */
     25 
     26 #include <sys/atomic.h>
     27 #include <sys/strsubr.h>
     28 #include <sys/synch.h>
     29 #include <sys/types.h>
     30 #include <sys/socketvar.h>
     31 #include <sys/sdt.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 void smb_request_init_command_mbuf(smb_request_t *sr);
     47 void dump_smb_inaddr(smb_inaddr_t *ipaddr);
     48 
     49 void
     50 smb_session_timers(smb_session_list_t *se)
     51 {
     52 	smb_session_t	*session;
     53 
     54 	rw_enter(&se->se_lock, RW_READER);
     55 	session = list_head(&se->se_act.lst);
     56 	while (session) {
     57 		/*
     58 		 * Walk through the table and decrement each keep_alive
     59 		 * timer that has not timed out yet. (keepalive > 0)
     60 		 */
     61 		ASSERT(session->s_magic == SMB_SESSION_MAGIC);
     62 		if (session->keep_alive &&
     63 		    (session->keep_alive != (uint32_t)-1))
     64 			session->keep_alive--;
     65 		session = list_next(&se->se_act.lst, session);
     66 	}
     67 	rw_exit(&se->se_lock);
     68 }
     69 
     70 void
     71 smb_session_correct_keep_alive_values(
     72     smb_session_list_t	*se,
     73     uint32_t		new_keep_alive)
     74 {
     75 	smb_session_t		*sn;
     76 
     77 	if (new_keep_alive == smb_keep_alive)
     78 		return;
     79 	/*
     80 	 * keep alive == 0 means do not drop connection if it's idle
     81 	 */
     82 	smb_keep_alive = (new_keep_alive) ? new_keep_alive : -1;
     83 
     84 	/*
     85 	 * Walk through the table and set each session to the new keep_alive
     86 	 * value if they have not already timed out.  Block clock interrupts.
     87 	 */
     88 	rw_enter(&se->se_lock, RW_READER);
     89 	sn = list_head(&se->se_rdy.lst);
     90 	while (sn) {
     91 		ASSERT(sn->s_magic == SMB_SESSION_MAGIC);
     92 		sn->keep_alive = new_keep_alive;
     93 		sn = list_next(&se->se_rdy.lst, sn);
     94 	}
     95 	sn = list_head(&se->se_act.lst);
     96 	while (sn) {
     97 		ASSERT(sn->s_magic == SMB_SESSION_MAGIC);
     98 		if (sn->keep_alive)
     99 			sn->keep_alive = new_keep_alive;
    100 		sn = list_next(&se->se_act.lst, sn);
    101 	}
    102 	rw_exit(&se->se_lock);
    103 }
    104 
    105 /*
    106  * smb_reconnection_check
    107  *
    108  * This function is called when a client indicates its current connection
    109  * should be the only one it has with the server, as indicated by VC=0 in
    110  * a SessionSetupX request. We go through the session list and destroy any
    111  * stale connections for that client.
    112  *
    113  * Clients don't associate IP addresses and servers. So a client may make
    114  * independent connections (i.e. with VC=0) to a server with multiple
    115  * IP addresses. So, when checking for a reconnection, we need to include
    116  * the local IP address, to which the client is connecting, when checking
    117  * for stale sessions.
    118  *
    119  * Also check the server's NetBIOS name to support simultaneous access by
    120  * multiple clients behind a NAT server.  This will only work for SMB over
    121  * NetBIOS on TCP port 139, it will not work SMB over TCP port 445 because
    122  * there is no NetBIOS name.  See also Knowledge Base article Q301673.
    123  */
    124 void
    125 smb_session_reconnection_check(smb_session_list_t *se, smb_session_t *sess)
    126 {
    127 	smb_session_t	*sn;
    128 
    129 	rw_enter(&se->se_lock, RW_READER);
    130 	sn = list_head(&se->se_act.lst);
    131 	while (sn) {
    132 		ASSERT(sn->s_magic == SMB_SESSION_MAGIC);
    133 		if ((sn != sess) &&
    134 		    smb_inet_equal(&sn->ipaddr, &sess->ipaddr) &&
    135 		    smb_inet_equal(&sn->local_ipaddr, &sess->local_ipaddr) &&
    136 		    (strcasecmp(sn->workstation, sess->workstation) == 0) &&
    137 		    (sn->opentime <= sess->opentime) &&
    138 		    (sn->s_kid < sess->s_kid)) {
    139 			tsignal(sn->s_thread, SIGUSR1);
    140 		}
    141 		sn = list_next(&se->se_act.lst, sn);
    142 	}
    143 	rw_exit(&se->se_lock);
    144 }
    145 
    146 /*
    147  * Send a session message - supports SMB-over-NBT and SMB-over-TCP.
    148  *
    149  * The mbuf chain is copied into a contiguous buffer so that the whole
    150  * message is submitted to smb_sosend as a single request.  This should
    151  * help Ethereal/Wireshark delineate the packets correctly even though
    152  * TCP_NODELAY has been set on the socket.
    153  *
    154  * If an mbuf chain is provided, it will be freed and set to NULL here.
    155  */
    156 int
    157 smb_session_send(smb_session_t *session, uint8_t type, mbuf_chain_t *mbc)
    158 {
    159 	smb_txreq_t	*txr;
    160 	smb_xprt_t	hdr;
    161 	int		rc;
    162 
    163 	switch (session->s_state) {
    164 	case SMB_SESSION_STATE_DISCONNECTED:
    165 	case SMB_SESSION_STATE_TERMINATED:
    166 		if ((mbc != NULL) && (mbc->chain != NULL)) {
    167 			m_freem(mbc->chain);
    168 			mbc->chain = NULL;
    169 			mbc->flags = 0;
    170 		}
    171 		return (ENOTCONN);
    172 	default:
    173 		break;
    174 	}
    175 
    176 	txr = smb_net_txr_alloc();
    177 
    178 	if ((mbc != NULL) && (mbc->chain != NULL)) {
    179 		rc = mbc_moveout(mbc, (caddr_t)&txr->tr_buf[NETBIOS_HDR_SZ],
    180 		    sizeof (txr->tr_buf) - NETBIOS_HDR_SZ, &txr->tr_len);
    181 		if (rc != 0) {
    182 			smb_net_txr_free(txr);
    183 			return (rc);
    184 		}
    185 	}
    186 
    187 	hdr.xh_type = type;
    188 	hdr.xh_length = (uint32_t)txr->tr_len;
    189 
    190 	rc = smb_session_xprt_puthdr(session, &hdr, txr->tr_buf,
    191 	    NETBIOS_HDR_SZ);
    192 
    193 	if (rc != 0) {
    194 		smb_net_txr_free(txr);
    195 		return (rc);
    196 	}
    197 	txr->tr_len += NETBIOS_HDR_SZ;
    198 	return (smb_net_txr_send(session->sock, &session->s_txlst, txr));
    199 }
    200 
    201 /*
    202  * Read, process and respond to a NetBIOS session request.
    203  *
    204  * A NetBIOS session must be established for SMB-over-NetBIOS.  Validate
    205  * the calling and called name format and save the client NetBIOS name,
    206  * which is used when a NetBIOS session is established to check for and
    207  * cleanup leftover state from a previous session.
    208  *
    209  * Session requests are not valid for SMB-over-TCP, which is unfortunate
    210  * because without the client name leftover state cannot be cleaned up
    211  * if the client is behind a NAT server.
    212  */
    213 static int
    214 smb_session_request(struct smb_session *session)
    215 {
    216 	int			rc;
    217 	char			*calling_name;
    218 	char			*called_name;
    219 	char 			client_name[NETBIOS_NAME_SZ];
    220 	struct mbuf_chain 	mbc;
    221 	char 			*names = NULL;
    222 	smb_wchar_t		*wbuf = NULL;
    223 	smb_xprt_t		hdr;
    224 	char *p;
    225 	int rc1, rc2;
    226 
    227 	session->keep_alive = smb_keep_alive;
    228 
    229 	if ((rc = smb_session_xprt_gethdr(session, &hdr)) != 0)
    230 		return (rc);
    231 
    232 	DTRACE_PROBE2(receive__session__req__xprthdr, struct session *, session,
    233 	    smb_xprt_t *, &hdr);
    234 
    235 	if ((hdr.xh_type != SESSION_REQUEST) ||
    236 	    (hdr.xh_length != NETBIOS_SESSION_REQUEST_DATA_LENGTH)) {
    237 		DTRACE_PROBE1(receive__session__req__failed,
    238 		    struct session *, session);
    239 		return (EINVAL);
    240 	}
    241 
    242 	names = kmem_alloc(hdr.xh_length, KM_SLEEP);
    243 
    244 	if ((rc = smb_sorecv(session->sock, names, hdr.xh_length)) != 0) {
    245 		kmem_free(names, hdr.xh_length);
    246 		DTRACE_PROBE1(receive__session__req__failed,
    247 		    struct session *, session);
    248 		return (rc);
    249 	}
    250 
    251 	DTRACE_PROBE3(receive__session__req__data, struct session *, session,
    252 	    char *, names, uint32_t, hdr.xh_length);
    253 
    254 	called_name = &names[0];
    255 	calling_name = &names[NETBIOS_ENCODED_NAME_SZ + 2];
    256 
    257 	rc1 = netbios_name_isvalid(called_name, 0);
    258 	rc2 = netbios_name_isvalid(calling_name, client_name);
    259 
    260 	if (rc1 == 0 || rc2 == 0) {
    261 
    262 		DTRACE_PROBE3(receive__invalid__session__req,
    263 		    struct session *, session, char *, names,
    264 		    uint32_t, hdr.xh_length);
    265 
    266 		kmem_free(names, hdr.xh_length);
    267 		MBC_INIT(&mbc, MAX_DATAGRAM_LENGTH);
    268 		(void) smb_mbc_encodef(&mbc, "b",
    269 		    DATAGRAM_INVALID_SOURCE_NAME_FORMAT);
    270 		(void) smb_session_send(session, NEGATIVE_SESSION_RESPONSE,
    271 		    &mbc);
    272 		return (EINVAL);
    273 	}
    274 
    275 	DTRACE_PROBE3(receive__session__req__calling__decoded,
    276 	    struct session *, session,
    277 	    char *, calling_name, char *, client_name);
    278 
    279 	/*
    280 	 * The client NetBIOS name is in oem codepage format.
    281 	 * We need to convert it to unicode and store it in
    282 	 * multi-byte format.  We also need to strip off any
    283 	 * spaces added as part of the NetBIOS name encoding.
    284 	 */
    285 	wbuf = kmem_alloc((SMB_PI_MAX_HOST * sizeof (smb_wchar_t)), KM_SLEEP);
    286 	(void) oemtoucs(wbuf, client_name, SMB_PI_MAX_HOST, OEM_CPG_850);
    287 	(void) smb_wcstombs(session->workstation, wbuf, SMB_PI_MAX_HOST);
    288 	kmem_free(wbuf, (SMB_PI_MAX_HOST * sizeof (smb_wchar_t)));
    289 
    290 	if ((p = strchr(session->workstation, ' ')) != 0)
    291 		*p = '\0';
    292 
    293 	kmem_free(names, hdr.xh_length);
    294 	return (smb_session_send(session, POSITIVE_SESSION_RESPONSE, NULL));
    295 }
    296 
    297 /*
    298  * Read 4-byte header from the session socket and build an in-memory
    299  * session transport header.  See smb_xprt_t definition for header
    300  * format information.
    301  *
    302  * Direct hosted NetBIOS-less SMB (SMB-over-TCP) uses port 445.  The
    303  * first byte of the four-byte header must be 0 and the next three
    304  * bytes contain the length of the remaining data.
    305  */
    306 int
    307 smb_session_xprt_gethdr(smb_session_t *session, smb_xprt_t *ret_hdr)
    308 {
    309 	int		rc;
    310 	unsigned char	buf[NETBIOS_HDR_SZ];
    311 
    312 	if ((rc = smb_sorecv(session->sock, buf, NETBIOS_HDR_SZ)) != 0)
    313 		return (rc);
    314 
    315 	switch (session->s_local_port) {
    316 	case IPPORT_NETBIOS_SSN:
    317 		ret_hdr->xh_type = buf[0];
    318 		ret_hdr->xh_length = (((uint32_t)buf[1] & 1) << 16) |
    319 		    ((uint32_t)buf[2] << 8) |
    320 		    ((uint32_t)buf[3]);
    321 		break;
    322 
    323 	case IPPORT_SMB:
    324 		ret_hdr->xh_type = buf[0];
    325 
    326 		if (ret_hdr->xh_type != 0) {
    327 			cmn_err(CE_WARN, "invalid type (%u)", ret_hdr->xh_type);
    328 			dump_smb_inaddr(&session->ipaddr);
    329 			return (EPROTO);
    330 		}
    331 
    332 		ret_hdr->xh_length = ((uint32_t)buf[1] << 16) |
    333 		    ((uint32_t)buf[2] << 8) |
    334 		    ((uint32_t)buf[3]);
    335 		break;
    336 
    337 	default:
    338 		cmn_err(CE_WARN, "invalid port %u", session->s_local_port);
    339 		dump_smb_inaddr(&session->ipaddr);
    340 		return (EPROTO);
    341 	}
    342 
    343 	return (0);
    344 }
    345 
    346 /*
    347  * Encode a transport session packet header into a 4-byte buffer.
    348  * See smb_xprt_t definition for header format information.
    349  */
    350 static int
    351 smb_session_xprt_puthdr(smb_session_t *session, smb_xprt_t *hdr,
    352     uint8_t *buf, size_t buflen)
    353 {
    354 	if (session == NULL || hdr == NULL ||
    355 	    buf == NULL || buflen < NETBIOS_HDR_SZ) {
    356 		return (-1);
    357 	}
    358 
    359 	switch (session->s_local_port) {
    360 	case IPPORT_NETBIOS_SSN:
    361 		buf[0] = hdr->xh_type;
    362 		buf[1] = ((hdr->xh_length >> 16) & 1);
    363 		buf[2] = (hdr->xh_length >> 8) & 0xff;
    364 		buf[3] = hdr->xh_length & 0xff;
    365 		break;
    366 
    367 	case IPPORT_SMB:
    368 		buf[0] = hdr->xh_type;
    369 		buf[1] = (hdr->xh_length >> 16) & 0xff;
    370 		buf[2] = (hdr->xh_length >> 8) & 0xff;
    371 		buf[3] = hdr->xh_length & 0xff;
    372 		break;
    373 
    374 	default:
    375 		cmn_err(CE_WARN, "invalid port %u", session->s_local_port);
    376 		dump_smb_inaddr(&session->ipaddr);
    377 		return (-1);
    378 	}
    379 
    380 	return (0);
    381 }
    382 
    383 static void
    384 smb_request_init_command_mbuf(smb_request_t *sr)
    385 {
    386 	MGET(sr->command.chain, 0, MT_DATA);
    387 
    388 	/*
    389 	 * Setup mbuf, mimic MCLGET but use the complete packet buffer.
    390 	 */
    391 	sr->command.chain->m_ext.ext_buf = sr->sr_request_buf;
    392 	sr->command.chain->m_data = sr->command.chain->m_ext.ext_buf;
    393 	sr->command.chain->m_len = sr->sr_req_length;
    394 	sr->command.chain->m_flags |= M_EXT;
    395 	sr->command.chain->m_ext.ext_size = sr->sr_req_length;
    396 	sr->command.chain->m_ext.ext_ref = &mclrefnoop;
    397 
    398 	/*
    399 	 * Initialize the rest of the mbuf_chain fields
    400 	 */
    401 	sr->command.flags = 0;
    402 	sr->command.shadow_of = 0;
    403 	sr->command.max_bytes = sr->sr_req_length;
    404 	sr->command.chain_offset = 0;
    405 }
    406 
    407 /*
    408  * smb_request_cancel
    409  *
    410  * Handle a cancel for a request properly depending on the current request
    411  * state.
    412  */
    413 void
    414 smb_request_cancel(smb_request_t *sr)
    415 {
    416 	mutex_enter(&sr->sr_mutex);
    417 	switch (sr->sr_state) {
    418 
    419 	case SMB_REQ_STATE_SUBMITTED:
    420 	case SMB_REQ_STATE_ACTIVE:
    421 	case SMB_REQ_STATE_CLEANED_UP:
    422 		sr->sr_state = SMB_REQ_STATE_CANCELED;
    423 		break;
    424 
    425 	case SMB_REQ_STATE_WAITING_LOCK:
    426 		/*
    427 		 * This request is waiting on a lock.  Wakeup everything
    428 		 * waiting on the lock so that the relevant thread regains
    429 		 * control and notices that is has been canceled.  The
    430 		 * other lock request threads waiting on this lock will go
    431 		 * back to sleep when they discover they are still blocked.
    432 		 */
    433 		sr->sr_state = SMB_REQ_STATE_CANCELED;
    434 
    435 		ASSERT(sr->sr_awaiting != NULL);
    436 		mutex_enter(&sr->sr_awaiting->l_mutex);
    437 		cv_broadcast(&sr->sr_awaiting->l_cv);
    438 		mutex_exit(&sr->sr_awaiting->l_mutex);
    439 		break;
    440 
    441 	case SMB_REQ_STATE_WAITING_EVENT:
    442 	case SMB_REQ_STATE_EVENT_OCCURRED:
    443 		/*
    444 		 * Cancellations for these states are handled by the
    445 		 * notify-change code
    446 		 */
    447 		break;
    448 
    449 	case SMB_REQ_STATE_COMPLETED:
    450 	case SMB_REQ_STATE_CANCELED:
    451 		/*
    452 		 * No action required for these states since the request
    453 		 * is completing.
    454 		 */
    455 		break;
    456 	/*
    457 	 * Cases included:
    458 	 *	SMB_REQ_STATE_FREE:
    459 	 *	SMB_REQ_STATE_INITIALIZING:
    460 	 */
    461 	default:
    462 		SMB_PANIC();
    463 	}
    464 	mutex_exit(&sr->sr_mutex);
    465 }
    466 
    467 /*
    468  * This is the entry point for processing SMB messages over NetBIOS or
    469  * SMB-over-TCP.
    470  *
    471  * NetBIOS connections require a session request to establish a session
    472  * on which to send session messages.
    473  *
    474  * Session requests are not valid on SMB-over-TCP.  We don't need to do
    475  * anything here as session requests will be treated as an error when
    476  * handling session messages.
    477  */
    478 int
    479 smb_session_daemon(smb_session_list_t *se)
    480 {
    481 	int		rc = 0;
    482 	smb_session_t	*session;
    483 
    484 	session = smb_session_list_activate_head(se);
    485 	if (session == NULL)
    486 		return (EINVAL);
    487 
    488 	if (session->s_local_port == IPPORT_NETBIOS_SSN) {
    489 		rc = smb_session_request(session);
    490 		if (rc) {
    491 			smb_rwx_rwenter(&session->s_lock, RW_WRITER);
    492 			session->s_state = SMB_SESSION_STATE_DISCONNECTED;
    493 			smb_rwx_rwexit(&session->s_lock);
    494 			smb_session_list_terminate(se, session);
    495 			return (rc);
    496 		}
    497 	}
    498 
    499 	smb_rwx_rwenter(&session->s_lock, RW_WRITER);
    500 	session->s_state = SMB_SESSION_STATE_ESTABLISHED;
    501 	smb_rwx_rwexit(&session->s_lock);
    502 
    503 	rc = smb_session_message(session);
    504 
    505 	smb_rwx_rwenter(&session->s_lock, RW_WRITER);
    506 	session->s_state = SMB_SESSION_STATE_DISCONNECTED;
    507 	smb_rwx_rwexit(&session->s_lock);
    508 
    509 	smb_soshutdown(session->sock);
    510 
    511 	DTRACE_PROBE2(session__drop, struct session *, session, int, rc);
    512 
    513 	smb_session_cancel(session);
    514 
    515 	/*
    516 	 * At this point everything related to the session should have been
    517 	 * cleaned up and we expect that nothing will attempt to use the
    518 	 * socket.
    519 	 */
    520 	smb_session_list_terminate(se, session);
    521 
    522 	return (rc);
    523 }
    524 
    525 /*
    526  * Read and process SMB requests.
    527  *
    528  * Returns:
    529  *	0	Success
    530  *	1	Unable to read transport header
    531  *	2	Invalid transport header type
    532  *	3	Invalid SMB length (too small)
    533  *	4	Unable to read SMB header
    534  *	5	Invalid SMB header (bad magic number)
    535  *	6	Unable to read SMB data
    536  *	2x	Write raw failed
    537  */
    538 static int
    539 smb_session_message(smb_session_t *session)
    540 {
    541 	smb_request_t	*sr = NULL;
    542 	smb_xprt_t	hdr;
    543 	uint8_t		*req_buf;
    544 	uint32_t	resid;
    545 	int		rc;
    546 
    547 	for (;;) {
    548 
    549 		rc = smb_session_xprt_gethdr(session, &hdr);
    550 		if (rc)
    551 			return (rc);
    552 
    553 		DTRACE_PROBE2(session__receive__xprthdr, session_t *, session,
    554 		    smb_xprt_t *, &hdr);
    555 
    556 		if (hdr.xh_type != SESSION_MESSAGE) {
    557 			/*
    558 			 * Anything other than SESSION_MESSAGE or
    559 			 * SESSION_KEEP_ALIVE is an error.  A SESSION_REQUEST
    560 			 * may indicate a new session request but we need to
    561 			 * close this session and we can treat it as an error
    562 			 * here.
    563 			 */
    564 			if (hdr.xh_type == SESSION_KEEP_ALIVE) {
    565 				session->keep_alive = smb_keep_alive;
    566 				continue;
    567 			}
    568 			return (EPROTO);
    569 		}
    570 
    571 		if (hdr.xh_length < SMB_HEADER_LEN)
    572 			return (EPROTO);
    573 
    574 		session->keep_alive = smb_keep_alive;
    575 
    576 		/*
    577 		 * Allocate a request context, read the SMB header and validate
    578 		 * it. The sr includes a buffer large enough to hold the SMB
    579 		 * request payload.  If the header looks valid, read any
    580 		 * remaining data.
    581 		 */
    582 		sr = smb_request_alloc(session, hdr.xh_length);
    583 
    584 		req_buf = (uint8_t *)sr->sr_request_buf;
    585 		resid = hdr.xh_length;
    586 
    587 		rc = smb_sorecv(session->sock, req_buf, SMB_HEADER_LEN);
    588 		if (rc) {
    589 			smb_request_free(sr);
    590 			return (rc);
    591 		}
    592 
    593 		if (SMB_PROTOCOL_MAGIC_INVALID(sr)) {
    594 			smb_request_free(sr);
    595 			return (EPROTO);
    596 		}
    597 
    598 		if (resid > SMB_HEADER_LEN) {
    599 			req_buf += SMB_HEADER_LEN;
    600 			resid -= SMB_HEADER_LEN;
    601 
    602 			rc = smb_sorecv(session->sock, req_buf, resid);
    603 			if (rc) {
    604 				smb_request_free(sr);
    605 				return (rc);
    606 			}
    607 		}
    608 
    609 		/*
    610 		 * Initialize command MBC to represent the received data.
    611 		 */
    612 		smb_request_init_command_mbuf(sr);
    613 
    614 		DTRACE_PROBE1(session__receive__smb, smb_request_t *, sr);
    615 
    616 		/*
    617 		 * If this is a raw write, hand off the request.  The handler
    618 		 * will retrieve the remaining raw data and process the request.
    619 		 */
    620 		if (SMB_IS_WRITERAW(sr)) {
    621 			rc = smb_handle_write_raw(session, sr);
    622 			/* XXX smb_request_free(sr); ??? */
    623 			return (rc);
    624 		}
    625 
    626 		sr->sr_state = SMB_REQ_STATE_SUBMITTED;
    627 		(void) taskq_dispatch(session->s_server->sv_thread_pool,
    628 		    smb_session_worker, sr, TQ_SLEEP);
    629 	}
    630 }
    631 
    632 /*
    633  * Port will be IPPORT_NETBIOS_SSN or IPPORT_SMB.
    634  */
    635 smb_session_t *
    636 smb_session_create(ksocket_t new_so, uint16_t port, smb_server_t *sv,
    637     int family)
    638 {
    639 	struct sockaddr_in	sin;
    640 	socklen_t		slen;
    641 	struct sockaddr_in6	sin6;
    642 	smb_session_t		*session;
    643 	int64_t			now;
    644 
    645 	session = kmem_cache_alloc(sv->si_cache_session, KM_SLEEP);
    646 	bzero(session, sizeof (smb_session_t));
    647 
    648 	if (smb_idpool_constructor(&session->s_uid_pool)) {
    649 		kmem_cache_free(sv->si_cache_session, session);
    650 		return (NULL);
    651 	}
    652 
    653 	now = ddi_get_lbolt64();
    654 
    655 	session->s_kid = SMB_NEW_KID();
    656 	session->s_state = SMB_SESSION_STATE_INITIALIZED;
    657 	session->native_os = NATIVE_OS_UNKNOWN;
    658 	session->opentime = now;
    659 	session->keep_alive = smb_keep_alive;
    660 	session->activity_timestamp = now;
    661 
    662 	smb_slist_constructor(&session->s_req_list, sizeof (smb_request_t),
    663 	    offsetof(smb_request_t, sr_session_lnd));
    664 
    665 	smb_llist_constructor(&session->s_user_list, sizeof (smb_user_t),
    666 	    offsetof(smb_user_t, u_lnd));
    667 
    668 	smb_llist_constructor(&session->s_xa_list, sizeof (smb_xa_t),
    669 	    offsetof(smb_xa_t, xa_lnd));
    670 
    671 	list_create(&session->s_oplock_brkreqs, sizeof (mbuf_chain_t),
    672 	    offsetof(mbuf_chain_t, mbc_lnd));
    673 
    674 	smb_net_txl_constructor(&session->s_txlst);
    675 
    676 	smb_rwx_init(&session->s_lock);
    677 
    678 	if (new_so) {
    679 		if (family == AF_INET) {
    680 			slen = sizeof (sin);
    681 			(void) ksocket_getsockname(new_so,
    682 			    (struct sockaddr *)&sin, &slen, CRED());
    683 			bcopy(&sin.sin_addr,
    684 			    &session->local_ipaddr.au_addr.au_ipv4,
    685 			    sizeof (in_addr_t));
    686 			slen = sizeof (sin);
    687 			(void) ksocket_getpeername(new_so,
    688 			    (struct sockaddr *)&sin, &slen, CRED());
    689 			bcopy(&sin.sin_addr,
    690 			    &session->ipaddr.au_addr.au_ipv4,
    691 			    sizeof (in_addr_t));
    692 		} else {
    693 			slen = sizeof (sin6);
    694 			(void) ksocket_getsockname(new_so,
    695 			    (struct sockaddr *)&sin6, &slen, CRED());
    696 			bcopy(&sin6.sin6_addr,
    697 			    &session->local_ipaddr.au_addr.au_ipv6,
    698 			    sizeof (in6_addr_t));
    699 			slen = sizeof (sin6);
    700 			(void) ksocket_getpeername(new_so,
    701 			    (struct sockaddr *)&sin6, &slen, CRED());
    702 			bcopy(&sin6.sin6_addr,
    703 			    &session->ipaddr.au_addr.au_ipv6,
    704 			    sizeof (in6_addr_t));
    705 		}
    706 		session->ipaddr.a_family = family;
    707 		session->local_ipaddr.a_family = family;
    708 		session->s_local_port = port;
    709 		session->sock = new_so;
    710 	}
    711 
    712 	session->s_server = sv;
    713 	smb_server_get_cfg(sv, &session->s_cfg);
    714 	session->s_cache_request = sv->si_cache_request;
    715 	session->s_cache = sv->si_cache_session;
    716 	session->s_magic = SMB_SESSION_MAGIC;
    717 	return (session);
    718 }
    719 
    720 void
    721 smb_session_delete(smb_session_t *session)
    722 {
    723 	mbuf_chain_t	*mbc;
    724 
    725 	ASSERT(session->s_magic == SMB_SESSION_MAGIC);
    726 
    727 	session->s_magic = 0;
    728 
    729 	smb_rwx_destroy(&session->s_lock);
    730 	smb_net_txl_destructor(&session->s_txlst);
    731 
    732 	while ((mbc = list_head(&session->s_oplock_brkreqs)) != NULL) {
    733 		SMB_MBC_VALID(mbc);
    734 		list_remove(&session->s_oplock_brkreqs, mbc);
    735 		smb_mbc_free(mbc);
    736 	}
    737 	list_destroy(&session->s_oplock_brkreqs);
    738 
    739 	smb_slist_destructor(&session->s_req_list);
    740 	smb_llist_destructor(&session->s_user_list);
    741 	smb_llist_destructor(&session->s_xa_list);
    742 
    743 	ASSERT(session->s_tree_cnt == 0);
    744 	ASSERT(session->s_file_cnt == 0);
    745 	ASSERT(session->s_dir_cnt == 0);
    746 
    747 	smb_idpool_destructor(&session->s_uid_pool);
    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 	smb_user_logoff_all(session);
    777 }
    778 
    779 /*
    780  * Cancel requests.  If a non-null tree is specified, only requests specific
    781  * to that tree will be cancelled.  If a non-null sr is specified, that sr
    782  * will be not be cancelled - this would typically be the caller's sr.
    783  */
    784 void
    785 smb_session_cancel_requests(
    786     smb_session_t	*session,
    787     smb_tree_t		*tree,
    788     smb_request_t	*exclude_sr)
    789 {
    790 	smb_request_t	*sr;
    791 
    792 	smb_process_session_notify_change_queue(session, tree);
    793 
    794 	smb_slist_enter(&session->s_req_list);
    795 	sr = smb_slist_head(&session->s_req_list);
    796 
    797 	while (sr) {
    798 		ASSERT(sr->sr_magic == SMB_REQ_MAGIC);
    799 		if ((sr != exclude_sr) &&
    800 		    (tree == NULL || sr->tid_tree == tree))
    801 			smb_request_cancel(sr);
    802 
    803 		sr = smb_slist_next(&session->s_req_list, sr);
    804 	}
    805 
    806 	smb_slist_exit(&session->s_req_list);
    807 }
    808 
    809 void
    810 smb_session_worker(void	*arg)
    811 {
    812 	smb_request_t	*sr;
    813 
    814 	sr = (smb_request_t *)arg;
    815 
    816 	ASSERT(sr->sr_magic == SMB_REQ_MAGIC);
    817 
    818 	sr->sr_worker = curthread;
    819 	mutex_enter(&sr->sr_mutex);
    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 }
    839 
    840 /*
    841  * smb_session_disconnect_share
    842  *
    843  * Disconnects the specified share. This function should be called after the
    844  * share passed in has been made unavailable by the "share manager".
    845  */
    846 void
    847 smb_session_disconnect_share(smb_session_list_t *se, char *sharename)
    848 {
    849 	smb_session_t	*session;
    850 
    851 	rw_enter(&se->se_lock, RW_READER);
    852 	session = list_head(&se->se_act.lst);
    853 	while (session) {
    854 		ASSERT(session->s_magic == SMB_SESSION_MAGIC);
    855 		smb_rwx_rwenter(&session->s_lock, RW_READER);
    856 		switch (session->s_state) {
    857 		case SMB_SESSION_STATE_NEGOTIATED:
    858 		case SMB_SESSION_STATE_OPLOCK_BREAKING:
    859 		case SMB_SESSION_STATE_WRITE_RAW_ACTIVE: {
    860 			smb_user_t	*user;
    861 			smb_user_t	*next;
    862 
    863 			user = smb_user_lookup_by_state(session, NULL);
    864 			while (user) {
    865 				smb_user_disconnect_share(user, sharename);
    866 				next = smb_user_lookup_by_state(session, user);
    867 				smb_user_release(user);
    868 				user = next;
    869 			}
    870 			break;
    871 
    872 		}
    873 		default:
    874 			break;
    875 		}
    876 		smb_rwx_rwexit(&session->s_lock);
    877 		session = list_next(&se->se_act.lst, session);
    878 	}
    879 	rw_exit(&se->se_lock);
    880 }
    881 
    882 void
    883 smb_session_list_constructor(smb_session_list_t *se)
    884 {
    885 	bzero(se, sizeof (*se));
    886 	rw_init(&se->se_lock, NULL, RW_DEFAULT, NULL);
    887 	list_create(&se->se_rdy.lst, sizeof (smb_session_t),
    888 	    offsetof(smb_session_t, s_lnd));
    889 	list_create(&se->se_act.lst, sizeof (smb_session_t),
    890 	    offsetof(smb_session_t, s_lnd));
    891 }
    892 
    893 void
    894 smb_session_list_destructor(smb_session_list_t *se)
    895 {
    896 	list_destroy(&se->se_rdy.lst);
    897 	list_destroy(&se->se_act.lst);
    898 	rw_destroy(&se->se_lock);
    899 }
    900 
    901 void
    902 smb_session_list_append(smb_session_list_t *se, smb_session_t *session)
    903 {
    904 	ASSERT(session->s_magic == SMB_SESSION_MAGIC);
    905 	ASSERT(session->s_state == SMB_SESSION_STATE_INITIALIZED);
    906 
    907 	rw_enter(&se->se_lock, RW_WRITER);
    908 	list_insert_tail(&se->se_rdy.lst, session);
    909 	se->se_rdy.count++;
    910 	se->se_wrop++;
    911 	rw_exit(&se->se_lock);
    912 }
    913 
    914 void
    915 smb_session_list_delete_tail(smb_session_list_t *se)
    916 {
    917 	smb_session_t	*session;
    918 
    919 	rw_enter(&se->se_lock, RW_WRITER);
    920 	session = list_tail(&se->se_rdy.lst);
    921 	if (session) {
    922 		ASSERT(session->s_magic == SMB_SESSION_MAGIC);
    923 		ASSERT(session->s_state == SMB_SESSION_STATE_INITIALIZED);
    924 		list_remove(&se->se_rdy.lst, session);
    925 		ASSERT(se->se_rdy.count);
    926 		se->se_rdy.count--;
    927 		rw_exit(&se->se_lock);
    928 		smb_session_delete(session);
    929 		return;
    930 	}
    931 	rw_exit(&se->se_lock);
    932 }
    933 
    934 smb_session_t *
    935 smb_session_list_activate_head(smb_session_list_t *se)
    936 {
    937 	smb_session_t	*session;
    938 
    939 	rw_enter(&se->se_lock, RW_WRITER);
    940 	session = list_head(&se->se_rdy.lst);
    941 	if (session) {
    942 		ASSERT(session->s_magic == SMB_SESSION_MAGIC);
    943 		smb_rwx_rwenter(&session->s_lock, RW_WRITER);
    944 		ASSERT(session->s_state == SMB_SESSION_STATE_INITIALIZED);
    945 		session->s_thread = curthread;
    946 		session->s_ktdid = session->s_thread->t_did;
    947 		smb_rwx_rwexit(&session->s_lock);
    948 		list_remove(&se->se_rdy.lst, session);
    949 		se->se_rdy.count--;
    950 		list_insert_tail(&se->se_act.lst, session);
    951 		se->se_act.count++;
    952 		se->se_wrop++;
    953 	}
    954 	rw_exit(&se->se_lock);
    955 	return (session);
    956 }
    957 
    958 void
    959 smb_session_list_terminate(smb_session_list_t *se, smb_session_t *session)
    960 {
    961 	ASSERT(session->s_magic == SMB_SESSION_MAGIC);
    962 
    963 	rw_enter(&se->se_lock, RW_WRITER);
    964 
    965 	smb_rwx_rwenter(&session->s_lock, RW_WRITER);
    966 	ASSERT(session->s_state == SMB_SESSION_STATE_DISCONNECTED);
    967 	session->s_state = SMB_SESSION_STATE_TERMINATED;
    968 	smb_sodestroy(session->sock);
    969 	session->sock = NULL;
    970 	smb_rwx_rwexit(&session->s_lock);
    971 
    972 	list_remove(&se->se_act.lst, session);
    973 	se->se_act.count--;
    974 	se->se_wrop++;
    975 
    976 	ASSERT(session->s_thread == curthread);
    977 
    978 	rw_exit(&se->se_lock);
    979 
    980 	smb_session_delete(session);
    981 }
    982 
    983 /*
    984  * smb_session_list_signal
    985  *
    986  * This function signals all the session threads. The intent is to terminate
    987  * them. The sessions still in the SMB_SESSION_STATE_INITIALIZED are delete
    988  * immediately.
    989  *
    990  * This function must only be called by the threads listening and accepting
    991  * connections. They must pass in their respective session list.
    992  */
    993 void
    994 smb_session_list_signal(smb_session_list_t *se)
    995 {
    996 	smb_session_t	*session;
    997 
    998 	rw_enter(&se->se_lock, RW_WRITER);
    999 	while (session = list_head(&se->se_rdy.lst)) {
   1000 
   1001 		ASSERT(session->s_magic == SMB_SESSION_MAGIC);
   1002 
   1003 		smb_rwx_rwenter(&session->s_lock, RW_WRITER);
   1004 		ASSERT(session->s_state == SMB_SESSION_STATE_INITIALIZED);
   1005 		session->s_state = SMB_SESSION_STATE_TERMINATED;
   1006 		smb_sodestroy(session->sock);
   1007 		session->sock = NULL;
   1008 		smb_rwx_rwexit(&session->s_lock);
   1009 
   1010 		list_remove(&se->se_rdy.lst, session);
   1011 		se->se_rdy.count--;
   1012 		se->se_wrop++;
   1013 
   1014 		rw_exit(&se->se_lock);
   1015 		smb_session_delete(session);
   1016 		rw_enter(&se->se_lock, RW_WRITER);
   1017 	}
   1018 	rw_downgrade(&se->se_lock);
   1019 
   1020 	session = list_head(&se->se_act.lst);
   1021 	while (session) {
   1022 
   1023 		ASSERT(session->s_magic == SMB_SESSION_MAGIC);
   1024 		tsignal(session->s_thread, SIGUSR1);
   1025 		session = list_next(&se->se_act.lst, session);
   1026 	}
   1027 	rw_exit(&se->se_lock);
   1028 }
   1029 
   1030 /*
   1031  * smb_session_lookup_user
   1032  */
   1033 static smb_user_t *
   1034 smb_session_lookup_user(smb_session_t *session, char *domain, char *name)
   1035 {
   1036 	smb_user_t	*user;
   1037 	smb_llist_t	*ulist;
   1038 
   1039 	ulist = &session->s_user_list;
   1040 	smb_llist_enter(ulist, RW_READER);
   1041 	user = smb_llist_head(ulist);
   1042 	while (user) {
   1043 		ASSERT(user->u_magic == SMB_USER_MAGIC);
   1044 		if (!smb_strcasecmp(user->u_name, name, 0) &&
   1045 		    !smb_strcasecmp(user->u_domain, domain, 0)) {
   1046 			if (smb_user_hold(user))
   1047 				break;
   1048 		}
   1049 		user = smb_llist_next(ulist, user);
   1050 	}
   1051 	smb_llist_exit(ulist);
   1052 
   1053 	return (user);
   1054 }
   1055 
   1056 /*
   1057  * If a user attempts to log in subsequently from the specified session,
   1058  * duplicates the existing SMB user instance such that all SMB user
   1059  * instances that corresponds to the same user on the given session
   1060  * reference the same user's cred.
   1061  *
   1062  * Returns NULL if the given user hasn't yet logged in from this
   1063  * specified session.  Otherwise, returns a user instance that corresponds
   1064  * to this subsequent login.
   1065  */
   1066 smb_user_t *
   1067 smb_session_dup_user(smb_session_t *session, char *domain, char *account_name)
   1068 {
   1069 	smb_user_t *orig_user = NULL;
   1070 	smb_user_t *user = NULL;
   1071 
   1072 	orig_user = smb_session_lookup_user(session, domain,
   1073 	    account_name);
   1074 
   1075 	if (orig_user) {
   1076 		user = smb_user_dup(orig_user);
   1077 		smb_user_release(orig_user);
   1078 	}
   1079 
   1080 	return (user);
   1081 }
   1082 
   1083 /*
   1084  * Copy the session workstation/client name to buf.  If the workstation
   1085  * is an empty string (which it will be on TCP connections), use the
   1086  * client IP address.
   1087  */
   1088 void
   1089 smb_session_getclient(smb_session_t *sn, char *buf, size_t buflen)
   1090 {
   1091 	char		ipbuf[INET6_ADDRSTRLEN];
   1092 	smb_inaddr_t	*ipaddr;
   1093 
   1094 	ASSERT(sn);
   1095 	ASSERT(buf);
   1096 	ASSERT(buflen);
   1097 
   1098 	*buf = '\0';
   1099 
   1100 	if (sn->workstation[0] != '\0') {
   1101 		(void) strlcpy(buf, sn->workstation, buflen);
   1102 		return;
   1103 	}
   1104 
   1105 	ipaddr = &sn->ipaddr;
   1106 	if (smb_inet_ntop(ipaddr, ipbuf, SMB_IPSTRLEN(ipaddr->a_family)))
   1107 		(void) strlcpy(buf, ipbuf, buflen);
   1108 }
   1109 
   1110 /*
   1111  * Check whether or not the specified client name is the client of this
   1112  * session.  The name may be in UNC format (\\CLIENT).
   1113  *
   1114  * A workstation/client name is setup on NBT connections as part of the
   1115  * NetBIOS session request but that isn't available on TCP connections.
   1116  * If the session doesn't have a client name we typically return the
   1117  * client IP address as the workstation name on MSRPC requests.  So we
   1118  * check for the IP address here in addition to the workstation name.
   1119  */
   1120 boolean_t
   1121 smb_session_isclient(smb_session_t *sn, const char *client)
   1122 {
   1123 	char		buf[INET6_ADDRSTRLEN];
   1124 	smb_inaddr_t	*ipaddr;
   1125 
   1126 	client += strspn(client, "\\");
   1127 
   1128 	if (smb_strcasecmp(client, sn->workstation, 0) == 0)
   1129 		return (B_TRUE);
   1130 
   1131 	ipaddr = &sn->ipaddr;
   1132 	if (smb_inet_ntop(ipaddr, buf, SMB_IPSTRLEN(ipaddr->a_family)) == NULL)
   1133 		return (B_FALSE);
   1134 
   1135 	if (smb_strcasecmp(client, buf, 0) == 0)
   1136 		return (B_TRUE);
   1137 
   1138 	return (B_FALSE);
   1139 }
   1140 
   1141 /*
   1142  * smb_request_alloc
   1143  *
   1144  * Allocate an smb_request_t structure from the kmem_cache.  Partially
   1145  * initialize the found/new request.
   1146  *
   1147  * Returns pointer to a request
   1148  */
   1149 smb_request_t *
   1150 smb_request_alloc(smb_session_t *session, int req_length)
   1151 {
   1152 	smb_request_t	*sr;
   1153 
   1154 	ASSERT(session->s_magic == SMB_SESSION_MAGIC);
   1155 
   1156 	sr = kmem_cache_alloc(session->s_cache_request, KM_SLEEP);
   1157 
   1158 	/*
   1159 	 * Future:  Use constructor to pre-initialize some fields.  For now
   1160 	 * there are so many fields that it is easiest just to zero the
   1161 	 * whole thing and start over.
   1162 	 */
   1163 	bzero(sr, sizeof (smb_request_t));
   1164 
   1165 	mutex_init(&sr->sr_mutex, NULL, MUTEX_DEFAULT, NULL);
   1166 	smb_srm_init(sr);
   1167 	sr->session = session;
   1168 	sr->sr_server = session->s_server;
   1169 	sr->sr_gmtoff = session->s_server->si_gmtoff;
   1170 	sr->sr_cache = session->s_server->si_cache_request;
   1171 	sr->sr_cfg = &session->s_cfg;
   1172 	sr->command.max_bytes = req_length;
   1173 	sr->reply.max_bytes = smb_maxbufsize;
   1174 	sr->sr_req_length = req_length;
   1175 	if (req_length)
   1176 		sr->sr_request_buf = kmem_alloc(req_length, KM_SLEEP);
   1177 	sr->sr_magic = SMB_REQ_MAGIC;
   1178 	sr->sr_state = SMB_REQ_STATE_INITIALIZING;
   1179 	smb_slist_insert_tail(&session->s_req_list, sr);
   1180 	return (sr);
   1181 }
   1182 
   1183 /*
   1184  * smb_request_free
   1185  *
   1186  * release the memories which have been allocated for a smb request.
   1187  */
   1188 void
   1189 smb_request_free(smb_request_t *sr)
   1190 {
   1191 	ASSERT(sr->sr_magic == SMB_REQ_MAGIC);
   1192 	ASSERT(sr->session);
   1193 	ASSERT(sr->r_xa == NULL);
   1194 
   1195 	if (sr->fid_ofile != NULL)
   1196 		smb_ofile_release(sr->fid_ofile);
   1197 
   1198 	if (sr->tid_tree != NULL)
   1199 		smb_tree_release(sr->tid_tree);
   1200 
   1201 	if (sr->uid_user != NULL)
   1202 		smb_user_release(sr->uid_user);
   1203 
   1204 	smb_slist_remove(&sr->session->s_req_list, sr);
   1205 
   1206 	sr->session = NULL;
   1207 
   1208 	smb_srm_fini(sr);
   1209 
   1210 	if (sr->sr_request_buf)
   1211 		kmem_free(sr->sr_request_buf, sr->sr_req_length);
   1212 	if (sr->command.chain)
   1213 		m_freem(sr->command.chain);
   1214 	if (sr->reply.chain)
   1215 		m_freem(sr->reply.chain);
   1216 	if (sr->raw_data.chain)
   1217 		m_freem(sr->raw_data.chain);
   1218 
   1219 	sr->sr_magic = 0;
   1220 	mutex_destroy(&sr->sr_mutex);
   1221 	kmem_cache_free(sr->sr_cache, sr);
   1222 }
   1223 
   1224 void
   1225 dump_smb_inaddr(smb_inaddr_t *ipaddr)
   1226 {
   1227 	char ipstr[INET6_ADDRSTRLEN];
   1228 
   1229 	if (smb_inet_ntop(ipaddr, ipstr, SMB_IPSTRLEN(ipaddr->a_family)))
   1230 		cmn_err(CE_WARN, "error ipstr=%s", ipstr);
   1231 	else
   1232 		cmn_err(CE_WARN, "error converting ip address");
   1233 }
   1234 
   1235 boolean_t
   1236 smb_session_oplocks_enable(smb_session_t *session)
   1237 {
   1238 	SMB_SESSION_VALID(session);
   1239 	if (session->s_cfg.skc_oplock_enable == 0)
   1240 		return (B_FALSE);
   1241 	else
   1242 		return (B_TRUE);
   1243 }
   1244 
   1245 /*
   1246  * smb_session_breaking_oplock
   1247  *
   1248  * This MUST be a cross-session call, i.e. the caller must be in a different
   1249  * context than the one passed. The mutex of the SMB node requiring an oplock
   1250  * break MUST be dropped before calling this function. This last requirement is
   1251  * due to a potential deadlock that can occur when trying to enter the lock of
   1252  * the session passed in.
   1253  */
   1254 void
   1255 smb_session_oplock_break(smb_session_t *session, smb_ofile_t *of)
   1256 {
   1257 	mbuf_chain_t	*mbc;
   1258 
   1259 	SMB_SESSION_VALID(session);
   1260 
   1261 	mbc = smb_mbc_alloc(MLEN);
   1262 
   1263 	(void) smb_mbc_encodef(mbc, "Mb19.wwwwbb3.ww10.",
   1264 	    SMB_COM_LOCKING_ANDX,
   1265 	    SMB_TREE_GET_TID(SMB_OFILE_GET_TREE(of)),
   1266 	    0xFFFF, 0, 0xFFFF, 8, 0xFF,
   1267 	    SMB_OFILE_GET_FID(of),
   1268 	    LOCKING_ANDX_OPLOCK_RELEASE);
   1269 
   1270 	smb_rwx_rwenter(&session->s_lock, RW_WRITER);
   1271 	switch (session->s_state) {
   1272 	case SMB_SESSION_STATE_NEGOTIATED:
   1273 	case SMB_SESSION_STATE_OPLOCK_BREAKING:
   1274 		session->s_state = SMB_SESSION_STATE_OPLOCK_BREAKING;
   1275 		(void) smb_session_send(session, 0, mbc);
   1276 		smb_mbc_free(mbc);
   1277 		break;
   1278 
   1279 	case SMB_SESSION_STATE_READ_RAW_ACTIVE:
   1280 		list_insert_tail(&session->s_oplock_brkreqs, mbc);
   1281 		break;
   1282 
   1283 	case SMB_SESSION_STATE_DISCONNECTED:
   1284 	case SMB_SESSION_STATE_TERMINATED:
   1285 		smb_mbc_free(mbc);
   1286 		break;
   1287 
   1288 	default:
   1289 		SMB_PANIC();
   1290 	}
   1291 	smb_rwx_rwexit(&session->s_lock);
   1292 }
   1293