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