1a90cf9f2SGordon Ross /* 2a90cf9f2SGordon Ross * This file and its contents are supplied under the terms of the 3a90cf9f2SGordon Ross * Common Development and Distribution License ("CDDL"), version 1.0. 4a90cf9f2SGordon Ross * You may only use this file in accordance with the terms of version 5a90cf9f2SGordon Ross * 1.0 of the CDDL. 6a90cf9f2SGordon Ross * 7a90cf9f2SGordon Ross * A full copy of the text of the CDDL should have accompanied this 8a90cf9f2SGordon Ross * source. A copy of the CDDL is also available via the Internet at 9a90cf9f2SGordon Ross * http://www.illumos.org/license/CDDL. 10a90cf9f2SGordon Ross */ 11a90cf9f2SGordon Ross 12a90cf9f2SGordon Ross /* 1358ccc3dcSGordon Ross * Copyright 2016 Nexenta Systems, Inc. All rights reserved. 14a90cf9f2SGordon Ross */ 15a90cf9f2SGordon Ross 16a90cf9f2SGordon Ross 17a90cf9f2SGordon Ross #include <smbsrv/smb2_kproto.h> 18a90cf9f2SGordon Ross #include <smbsrv/smb_kstat.h> 19a90cf9f2SGordon Ross #include <smbsrv/smb2.h> 20a90cf9f2SGordon Ross 21a90cf9f2SGordon Ross /* 22a90cf9f2SGordon Ross * Saved state for a command that "goes async". When a compound request 23a90cf9f2SGordon Ross * contains a command that may block indefinitely, the compound reply is 24a90cf9f2SGordon Ross * composed with an "interim response" for that command, and information 25a90cf9f2SGordon Ross * needed to actually dispatch that command is saved on a list of "async" 26a90cf9f2SGordon Ross * commands for this compound request. After the compound reply is sent, 27a90cf9f2SGordon Ross * the list of async commands is processed, and those may block as long 28a90cf9f2SGordon Ross * as they need to without affecting the initial compound request. 29a90cf9f2SGordon Ross * 30a90cf9f2SGordon Ross * Now interestingly, this "async" mechanism is not used with the full 31a90cf9f2SGordon Ross * range of asynchrony that one might imagine. The design of async 32a90cf9f2SGordon Ross * request processing can be drastically simplified if we can assume 33a90cf9f2SGordon Ross * that there's no need to run more than one async command at a time. 34a90cf9f2SGordon Ross * With that simplifying assumption, we can continue using the current 35a90cf9f2SGordon Ross * "one worker thread per request message" model, which has very simple 36a90cf9f2SGordon Ross * locking rules etc. The same worker thread that handles the initial 37a90cf9f2SGordon Ross * compound request can handle the list of async requests. 38a90cf9f2SGordon Ross * 39a90cf9f2SGordon Ross * As it turns out, SMB2 clients do not try to use more than one "async" 40a90cf9f2SGordon Ross * command in a compound. If they were to do so, the [MS-SMB2] spec. 41a90cf9f2SGordon Ross * allows us to decline additional async requests with an error. 42a90cf9f2SGordon Ross * 43a90cf9f2SGordon Ross * smb_async_req_t is the struct used to save an "async" request on 44a90cf9f2SGordon Ross * the list of requests that had an interim reply in the initial 45a90cf9f2SGordon Ross * compound reply. This includes everything needed to restart 46a90cf9f2SGordon Ross * processing at the async command. 47a90cf9f2SGordon Ross */ 48a90cf9f2SGordon Ross 49a90cf9f2SGordon Ross typedef struct smb2_async_req { 50a90cf9f2SGordon Ross 51a90cf9f2SGordon Ross smb_sdrc_t (*ar_func)(smb_request_t *); 52a90cf9f2SGordon Ross 53a90cf9f2SGordon Ross int ar_cmd_hdr; /* smb2_cmd_hdr offset */ 54a90cf9f2SGordon Ross int ar_cmd_len; /* length from hdr */ 55a90cf9f2SGordon Ross 56a90cf9f2SGordon Ross /* 57a90cf9f2SGordon Ross * SMB2 header fields. 58a90cf9f2SGordon Ross */ 59a90cf9f2SGordon Ross uint16_t ar_cmd_code; 60a90cf9f2SGordon Ross uint16_t ar_uid; 61a90cf9f2SGordon Ross uint16_t ar_tid; 62a90cf9f2SGordon Ross uint32_t ar_pid; 63a90cf9f2SGordon Ross uint32_t ar_hdr_flags; 64a90cf9f2SGordon Ross uint64_t ar_messageid; 65a90cf9f2SGordon Ross } smb2_async_req_t; 66a90cf9f2SGordon Ross 67a90cf9f2SGordon Ross void smb2sr_do_async(smb_request_t *); 68a90cf9f2SGordon Ross smb_sdrc_t smb2_invalid_cmd(smb_request_t *); 69a90cf9f2SGordon Ross static void smb2_tq_work(void *); 70a90cf9f2SGordon Ross 71adb064afSToomas Soome static const smb_disp_entry_t 72a90cf9f2SGordon Ross smb2_disp_table[SMB2__NCMDS] = { 73a90cf9f2SGordon Ross 74a90cf9f2SGordon Ross /* text-name, pre, func, post, cmd-code, dialect, flags */ 75a90cf9f2SGordon Ross 76a90cf9f2SGordon Ross { "smb2_negotiate", NULL, 77a90cf9f2SGordon Ross smb2_negotiate, NULL, 0, 0, 78a90cf9f2SGordon Ross SDDF_SUPPRESS_TID | SDDF_SUPPRESS_UID }, 79a90cf9f2SGordon Ross 80a90cf9f2SGordon Ross { "smb2_session_setup", NULL, 81a90cf9f2SGordon Ross smb2_session_setup, NULL, 0, 0, 82a90cf9f2SGordon Ross SDDF_SUPPRESS_TID | SDDF_SUPPRESS_UID }, 83a90cf9f2SGordon Ross 84a90cf9f2SGordon Ross { "smb2_logoff", NULL, 85a90cf9f2SGordon Ross smb2_logoff, NULL, 0, 0, 86a90cf9f2SGordon Ross SDDF_SUPPRESS_TID }, 87a90cf9f2SGordon Ross 88a90cf9f2SGordon Ross { "smb2_tree_connect", NULL, 89a90cf9f2SGordon Ross smb2_tree_connect, NULL, 0, 0, 90a90cf9f2SGordon Ross SDDF_SUPPRESS_TID }, 91a90cf9f2SGordon Ross 92a90cf9f2SGordon Ross { "smb2_tree_disconn", NULL, 93a90cf9f2SGordon Ross smb2_tree_disconn, NULL, 0, 0 }, 94a90cf9f2SGordon Ross 95a90cf9f2SGordon Ross { "smb2_create", NULL, 96a90cf9f2SGordon Ross smb2_create, NULL, 0, 0 }, 97a90cf9f2SGordon Ross 98a90cf9f2SGordon Ross { "smb2_close", NULL, 99a90cf9f2SGordon Ross smb2_close, NULL, 0, 0 }, 100a90cf9f2SGordon Ross 101a90cf9f2SGordon Ross { "smb2_flush", NULL, 102a90cf9f2SGordon Ross smb2_flush, NULL, 0, 0 }, 103a90cf9f2SGordon Ross 104a90cf9f2SGordon Ross { "smb2_read", NULL, 105a90cf9f2SGordon Ross smb2_read, NULL, 0, 0 }, 106a90cf9f2SGordon Ross 107a90cf9f2SGordon Ross { "smb2_write", NULL, 108a90cf9f2SGordon Ross smb2_write, NULL, 0, 0 }, 109a90cf9f2SGordon Ross 110a90cf9f2SGordon Ross { "smb2_lock", NULL, 111a90cf9f2SGordon Ross smb2_lock, NULL, 0, 0 }, 112a90cf9f2SGordon Ross 113a90cf9f2SGordon Ross { "smb2_ioctl", NULL, 114a90cf9f2SGordon Ross smb2_ioctl, NULL, 0, 0 }, 115a90cf9f2SGordon Ross 116a90cf9f2SGordon Ross /* 117a90cf9f2SGordon Ross * Note: Cancel gets the "invalid command" handler because 118a90cf9f2SGordon Ross * that's always handled directly in the reader. We should 119a90cf9f2SGordon Ross * never get to the function using this table, but note: 120a90cf9f2SGordon Ross * We CAN get here if a nasty client adds cancel to some 121a90cf9f2SGordon Ross * compound message, which is a protocol violation. 122a90cf9f2SGordon Ross */ 123a90cf9f2SGordon Ross { "smb2_cancel", NULL, 124a90cf9f2SGordon Ross smb2_invalid_cmd, NULL, 0, 0 }, 125a90cf9f2SGordon Ross 126a90cf9f2SGordon Ross { "smb2_echo", NULL, 127a90cf9f2SGordon Ross smb2_echo, NULL, 0, 0, 128a90cf9f2SGordon Ross SDDF_SUPPRESS_UID | SDDF_SUPPRESS_TID }, 129a90cf9f2SGordon Ross 130a90cf9f2SGordon Ross { "smb2_query_dir", NULL, 131a90cf9f2SGordon Ross smb2_query_dir, NULL, 0, 0 }, 132a90cf9f2SGordon Ross 133a90cf9f2SGordon Ross { "smb2_change_notify", NULL, 134a90cf9f2SGordon Ross smb2_change_notify, NULL, 0, 0 }, 135a90cf9f2SGordon Ross 136a90cf9f2SGordon Ross { "smb2_query_info", NULL, 137a90cf9f2SGordon Ross smb2_query_info, NULL, 0, 0 }, 138a90cf9f2SGordon Ross 139a90cf9f2SGordon Ross { "smb2_set_info", NULL, 140a90cf9f2SGordon Ross smb2_set_info, NULL, 0, 0 }, 141a90cf9f2SGordon Ross 142a90cf9f2SGordon Ross { "smb2_oplock_break_ack", NULL, 143a90cf9f2SGordon Ross smb2_oplock_break_ack, NULL, 0, 0 }, 144a90cf9f2SGordon Ross 145a90cf9f2SGordon Ross { "smb2_invalid_cmd", NULL, 146a90cf9f2SGordon Ross smb2_invalid_cmd, NULL, 0, 0, 147a90cf9f2SGordon Ross SDDF_SUPPRESS_UID | SDDF_SUPPRESS_TID }, 148a90cf9f2SGordon Ross }; 149a90cf9f2SGordon Ross 150a90cf9f2SGordon Ross smb_sdrc_t 151a90cf9f2SGordon Ross smb2_invalid_cmd(smb_request_t *sr) 152a90cf9f2SGordon Ross { 153a90cf9f2SGordon Ross #ifdef DEBUG 154a90cf9f2SGordon Ross cmn_err(CE_NOTE, "clnt %s bad SMB2 cmd code", 155a90cf9f2SGordon Ross sr->session->ip_addr_str); 156a90cf9f2SGordon Ross #endif 157a90cf9f2SGordon Ross sr->smb2_status = NT_STATUS_INVALID_PARAMETER; 158a90cf9f2SGordon Ross return (SDRC_DROP_VC); 159a90cf9f2SGordon Ross } 160a90cf9f2SGordon Ross 161a90cf9f2SGordon Ross /* 162a90cf9f2SGordon Ross * This is the SMB2 handler for new smb requests, called from 163a90cf9f2SGordon Ross * smb_session_reader after SMB negotiate is done. For most SMB2 164a90cf9f2SGordon Ross * requests, we just enqueue them for the smb_session_worker to 165a90cf9f2SGordon Ross * execute via the task queue, so they can block for resources 166a90cf9f2SGordon Ross * without stopping the reader thread. A few protocol messages 167a90cf9f2SGordon Ross * are special cases and are handled directly here in the reader 168a90cf9f2SGordon Ross * thread so they don't wait for taskq scheduling. 169a90cf9f2SGordon Ross * 170a90cf9f2SGordon Ross * This function must either enqueue the new request for 171a90cf9f2SGordon Ross * execution via the task queue, or execute it directly 172a90cf9f2SGordon Ross * and then free it. If this returns non-zero, the caller 173a90cf9f2SGordon Ross * will drop the session. 174a90cf9f2SGordon Ross */ 175a90cf9f2SGordon Ross int 176a90cf9f2SGordon Ross smb2sr_newrq(smb_request_t *sr) 177a90cf9f2SGordon Ross { 178a90cf9f2SGordon Ross uint32_t magic; 179a90cf9f2SGordon Ross uint16_t command; 180a90cf9f2SGordon Ross int rc; 181a90cf9f2SGordon Ross 182a90cf9f2SGordon Ross magic = LE_IN32(sr->sr_request_buf); 183a90cf9f2SGordon Ross if (magic != SMB2_PROTOCOL_MAGIC) { 184a90cf9f2SGordon Ross smb_request_free(sr); 185a90cf9f2SGordon Ross /* will drop the connection */ 186a90cf9f2SGordon Ross return (EPROTO); 187a90cf9f2SGordon Ross } 188a90cf9f2SGordon Ross 189a90cf9f2SGordon Ross /* 190a90cf9f2SGordon Ross * Execute Cancel requests immediately, (here in the 191a90cf9f2SGordon Ross * reader thread) so they won't wait for any other 192a90cf9f2SGordon Ross * commands we might already have in the task queue. 193a90cf9f2SGordon Ross * Cancel also skips signature verification and 194a90cf9f2SGordon Ross * does not consume a sequence number. 195a90cf9f2SGordon Ross * [MS-SMB2] 3.2.4.24 Cancellation... 196a90cf9f2SGordon Ross */ 197a90cf9f2SGordon Ross command = LE_IN16((uint8_t *)sr->sr_request_buf + 12); 198a90cf9f2SGordon Ross if (command == SMB2_CANCEL) { 199a90cf9f2SGordon Ross rc = smb2sr_newrq_cancel(sr); 200a90cf9f2SGordon Ross smb_request_free(sr); 201a90cf9f2SGordon Ross return (rc); 202a90cf9f2SGordon Ross } 203a90cf9f2SGordon Ross 204a90cf9f2SGordon Ross /* 205a90cf9f2SGordon Ross * Submit the request to the task queue, which calls 206a90cf9f2SGordon Ross * smb2_tq_work when the workload permits. 207a90cf9f2SGordon Ross */ 208a90cf9f2SGordon Ross sr->sr_time_submitted = gethrtime(); 209a90cf9f2SGordon Ross sr->sr_state = SMB_REQ_STATE_SUBMITTED; 210a90cf9f2SGordon Ross smb_srqueue_waitq_enter(sr->session->s_srqueue); 211a90cf9f2SGordon Ross (void) taskq_dispatch(sr->sr_server->sv_worker_pool, 212a90cf9f2SGordon Ross smb2_tq_work, sr, TQ_SLEEP); 213a90cf9f2SGordon Ross 214a90cf9f2SGordon Ross return (0); 215a90cf9f2SGordon Ross } 216a90cf9f2SGordon Ross 217a90cf9f2SGordon Ross static void 218a90cf9f2SGordon Ross smb2_tq_work(void *arg) 219a90cf9f2SGordon Ross { 220a90cf9f2SGordon Ross smb_request_t *sr; 221a90cf9f2SGordon Ross smb_srqueue_t *srq; 222a90cf9f2SGordon Ross 223a90cf9f2SGordon Ross sr = (smb_request_t *)arg; 224a90cf9f2SGordon Ross SMB_REQ_VALID(sr); 225a90cf9f2SGordon Ross 226a90cf9f2SGordon Ross srq = sr->session->s_srqueue; 227a90cf9f2SGordon Ross smb_srqueue_waitq_to_runq(srq); 228a90cf9f2SGordon Ross sr->sr_worker = curthread; 229a90cf9f2SGordon Ross sr->sr_time_active = gethrtime(); 230a90cf9f2SGordon Ross 231a90cf9f2SGordon Ross /* 232a90cf9f2SGordon Ross * In contrast with SMB1, SMB2 must _always_ dispatch to 233a90cf9f2SGordon Ross * the handler function, because cancelled requests need 234a90cf9f2SGordon Ross * an error reply (NT_STATUS_CANCELLED). 235a90cf9f2SGordon Ross */ 236a90cf9f2SGordon Ross smb2sr_work(sr); 237a90cf9f2SGordon Ross 238a90cf9f2SGordon Ross smb_srqueue_runq_exit(srq); 239a90cf9f2SGordon Ross } 240a90cf9f2SGordon Ross 241a90cf9f2SGordon Ross /* 242a90cf9f2SGordon Ross * smb2sr_work 243a90cf9f2SGordon Ross * 244a90cf9f2SGordon Ross * This function processes each SMB command in the current request 245a90cf9f2SGordon Ross * (which may be a compound request) building a reply containing 246a90cf9f2SGordon Ross * SMB reply messages, one-to-one with the SMB commands. Some SMB 247a90cf9f2SGordon Ross * commands (change notify, blocking locks) may require both an 248a90cf9f2SGordon Ross * "interim response" and a later "async response" at completion. 249a90cf9f2SGordon Ross * In such cases, we'll encode the interim response in the reply 250a90cf9f2SGordon Ross * compound we're building, and put the (now async) command on a 251a90cf9f2SGordon Ross * list of commands that need further processing. After we've 252a90cf9f2SGordon Ross * finished processing the commands in this compound and building 253a90cf9f2SGordon Ross * the compound reply, we'll send the compound reply, and finally 254a90cf9f2SGordon Ross * process the list of async commands. 255a90cf9f2SGordon Ross * 256a90cf9f2SGordon Ross * As we work our way through the compound request and reply, 257a90cf9f2SGordon Ross * we need to keep track of the bounds of the current request 258a90cf9f2SGordon Ross * and reply. For the request, this uses an MBC_SHADOW_CHAIN 259a90cf9f2SGordon Ross * that begins at smb2_cmd_hdr. The reply is appended to the 260a90cf9f2SGordon Ross * sr->reply chain starting at smb2_reply_hdr. 261a90cf9f2SGordon Ross * 262a90cf9f2SGordon Ross * This function must always free the smb request. 263a90cf9f2SGordon Ross */ 264a90cf9f2SGordon Ross void 265a90cf9f2SGordon Ross smb2sr_work(struct smb_request *sr) 266a90cf9f2SGordon Ross { 267a90cf9f2SGordon Ross const smb_disp_entry_t *sdd; 268a90cf9f2SGordon Ross smb_disp_stats_t *sds; 269a90cf9f2SGordon Ross smb_session_t *session; 270a90cf9f2SGordon Ross uint32_t msg_len; 271a90cf9f2SGordon Ross uint16_t cmd_idx; 272a90cf9f2SGordon Ross int rc = 0; 273a90cf9f2SGordon Ross boolean_t disconnect = B_FALSE; 274a90cf9f2SGordon Ross boolean_t related; 275a90cf9f2SGordon Ross 276a90cf9f2SGordon Ross session = sr->session; 277a90cf9f2SGordon Ross 278a90cf9f2SGordon Ross ASSERT(sr->tid_tree == 0); 279a90cf9f2SGordon Ross ASSERT(sr->uid_user == 0); 280a90cf9f2SGordon Ross ASSERT(sr->fid_ofile == 0); 281a90cf9f2SGordon Ross sr->smb_fid = (uint16_t)-1; 282a90cf9f2SGordon Ross sr->smb2_status = 0; 283a90cf9f2SGordon Ross 284a90cf9f2SGordon Ross /* temporary until we identify a user */ 285a90cf9f2SGordon Ross sr->user_cr = zone_kcred(); 286a90cf9f2SGordon Ross 287a90cf9f2SGordon Ross mutex_enter(&sr->sr_mutex); 288a90cf9f2SGordon Ross switch (sr->sr_state) { 289a90cf9f2SGordon Ross case SMB_REQ_STATE_SUBMITTED: 290a90cf9f2SGordon Ross case SMB_REQ_STATE_CLEANED_UP: 291a90cf9f2SGordon Ross sr->sr_state = SMB_REQ_STATE_ACTIVE; 292a90cf9f2SGordon Ross break; 293a90cf9f2SGordon Ross default: 294a90cf9f2SGordon Ross ASSERT(0); 295a90cf9f2SGordon Ross /* FALLTHROUGH */ 296a90cf9f2SGordon Ross case SMB_REQ_STATE_CANCELED: 297a90cf9f2SGordon Ross sr->smb2_status = NT_STATUS_CANCELLED; 298a90cf9f2SGordon Ross break; 299a90cf9f2SGordon Ross } 300a90cf9f2SGordon Ross mutex_exit(&sr->sr_mutex); 301a90cf9f2SGordon Ross 302a90cf9f2SGordon Ross cmd_start: 303a90cf9f2SGordon Ross /* 304a90cf9f2SGordon Ross * Decode the request header 305a90cf9f2SGordon Ross * 306a90cf9f2SGordon Ross * Most problems with decoding will result in the error 307a90cf9f2SGordon Ross * STATUS_INVALID_PARAMETER. If the decoding problem 308a90cf9f2SGordon Ross * prevents continuing, we'll close the connection. 309a90cf9f2SGordon Ross * [MS-SMB2] 3.3.5.2.6 Handling Incorrectly Formatted... 310a90cf9f2SGordon Ross * 311a90cf9f2SGordon Ross * We treat some status codes as if "sticky", meaning 312a90cf9f2SGordon Ross * once they're set after some command handler returns, 313a90cf9f2SGordon Ross * all remaining commands get this status without even 314a90cf9f2SGordon Ross * calling the command-specific handler. The cancelled 315a90cf9f2SGordon Ross * status is used above, and insufficient_resources is 316a90cf9f2SGordon Ross * used when smb2sr_go_async declines to "go async". 317a90cf9f2SGordon Ross * Otherwise initialize to zero (success). 318a90cf9f2SGordon Ross */ 319a90cf9f2SGordon Ross if (sr->smb2_status != NT_STATUS_CANCELLED && 320a90cf9f2SGordon Ross sr->smb2_status != NT_STATUS_INSUFFICIENT_RESOURCES) 321a90cf9f2SGordon Ross sr->smb2_status = 0; 322a90cf9f2SGordon Ross 323a90cf9f2SGordon Ross sr->smb2_cmd_hdr = sr->command.chain_offset; 324a90cf9f2SGordon Ross if ((rc = smb2_decode_header(sr)) != 0) { 325a90cf9f2SGordon Ross cmn_err(CE_WARN, "clnt %s bad SMB2 header", 326a90cf9f2SGordon Ross session->ip_addr_str); 327a90cf9f2SGordon Ross disconnect = B_TRUE; 328a90cf9f2SGordon Ross goto cleanup; 329a90cf9f2SGordon Ross } 330a90cf9f2SGordon Ross 331a90cf9f2SGordon Ross /* 332a90cf9f2SGordon Ross * The SMB2_FLAGS_SERVER_TO_REDIR should only appear 333a90cf9f2SGordon Ross * in messages from the server back to the client. 334a90cf9f2SGordon Ross */ 335a90cf9f2SGordon Ross if ((sr->smb2_hdr_flags & SMB2_FLAGS_SERVER_TO_REDIR) != 0) { 336a90cf9f2SGordon Ross cmn_err(CE_WARN, "clnt %s bad SMB2 flags", 337a90cf9f2SGordon Ross session->ip_addr_str); 338a90cf9f2SGordon Ross disconnect = B_TRUE; 339a90cf9f2SGordon Ross goto cleanup; 340a90cf9f2SGordon Ross } 341a90cf9f2SGordon Ross related = (sr->smb2_hdr_flags & SMB2_FLAGS_RELATED_OPERATIONS); 342a90cf9f2SGordon Ross 343a90cf9f2SGordon Ross /* 344a90cf9f2SGordon Ross * In case we bail out with an error before we get to the 345a90cf9f2SGordon Ross * section that computes the credit grant, initialize the 346a90cf9f2SGordon Ross * response header fields so that credits won't change. 347a90cf9f2SGordon Ross * Note: SMB 2.02 clients may send credit charge zero. 348a90cf9f2SGordon Ross */ 349a90cf9f2SGordon Ross if (sr->smb2_credit_charge == 0) 350a90cf9f2SGordon Ross sr->smb2_credit_charge = 1; 351a90cf9f2SGordon Ross sr->smb2_credit_response = sr->smb2_credit_charge; 352a90cf9f2SGordon Ross 353a90cf9f2SGordon Ross /* 354a90cf9f2SGordon Ross * Reserve space for the reply header, and save the offset. 355a90cf9f2SGordon Ross * The reply header will be overwritten later. If we have 356a90cf9f2SGordon Ross * already exhausted the output space, then this client is 357a90cf9f2SGordon Ross * trying something funny. Log it and kill 'em. 358a90cf9f2SGordon Ross */ 359a90cf9f2SGordon Ross sr->smb2_reply_hdr = sr->reply.chain_offset; 360a90cf9f2SGordon Ross if ((rc = smb2_encode_header(sr, B_FALSE)) != 0) { 361a90cf9f2SGordon Ross cmn_err(CE_WARN, "clnt %s excessive reply", 362a90cf9f2SGordon Ross session->ip_addr_str); 363a90cf9f2SGordon Ross disconnect = B_TRUE; 364a90cf9f2SGordon Ross goto cleanup; 365a90cf9f2SGordon Ross } 366a90cf9f2SGordon Ross 367a90cf9f2SGordon Ross /* 368a90cf9f2SGordon Ross * Figure out the length of data following the SMB2 header. 369a90cf9f2SGordon Ross * It ends at either the next SMB2 header if there is one 370a90cf9f2SGordon Ross * (smb2_next_command != 0) or at the end of the message. 371a90cf9f2SGordon Ross */ 372a90cf9f2SGordon Ross if (sr->smb2_next_command != 0) { 373a90cf9f2SGordon Ross /* [MS-SMB2] says this is 8-byte aligned */ 374a90cf9f2SGordon Ross msg_len = sr->smb2_next_command; 375a90cf9f2SGordon Ross if ((msg_len & 7) != 0 || (msg_len < SMB2_HDR_SIZE) || 376a90cf9f2SGordon Ross ((sr->smb2_cmd_hdr + msg_len) > sr->command.max_bytes)) { 377a90cf9f2SGordon Ross cmn_err(CE_WARN, "clnt %s bad SMB2 next cmd", 378a90cf9f2SGordon Ross session->ip_addr_str); 379a90cf9f2SGordon Ross disconnect = B_TRUE; 380a90cf9f2SGordon Ross goto cleanup; 381a90cf9f2SGordon Ross } 382a90cf9f2SGordon Ross } else { 383a90cf9f2SGordon Ross msg_len = sr->command.max_bytes - sr->smb2_cmd_hdr; 384a90cf9f2SGordon Ross } 385a90cf9f2SGordon Ross 386a90cf9f2SGordon Ross /* 387a90cf9f2SGordon Ross * Setup a shadow chain for this SMB2 command, starting 388a90cf9f2SGordon Ross * with the header and ending at either the next command 389a90cf9f2SGordon Ross * or the end of the message. The signing check below 390a90cf9f2SGordon Ross * needs the entire SMB2 command. After that's done, we 391a90cf9f2SGordon Ross * advance chain_offset to the end of the header where 392a90cf9f2SGordon Ross * the command specific handlers continue decoding. 393a90cf9f2SGordon Ross */ 394a90cf9f2SGordon Ross (void) MBC_SHADOW_CHAIN(&sr->smb_data, &sr->command, 395a90cf9f2SGordon Ross sr->smb2_cmd_hdr, msg_len); 396a90cf9f2SGordon Ross 397*ac2bf314SMatt Barden /* 398*ac2bf314SMatt Barden * We will consume the data for this request from smb_data. 399*ac2bf314SMatt Barden * That effectively consumes msg_len bytes from sr->command 400*ac2bf314SMatt Barden * but doesn't update its chain_offset, so we need to update 401*ac2bf314SMatt Barden * that here to make later received bytes accounting work. 402*ac2bf314SMatt Barden */ 403*ac2bf314SMatt Barden sr->command.chain_offset = sr->smb2_cmd_hdr + msg_len; 404*ac2bf314SMatt Barden ASSERT(sr->command.chain_offset <= sr->command.max_bytes); 405*ac2bf314SMatt Barden 406a90cf9f2SGordon Ross /* 407a90cf9f2SGordon Ross * Validate the commmand code, get dispatch table entries. 408a90cf9f2SGordon Ross * [MS-SMB2] 3.3.5.2.6 Handling Incorrectly Formatted... 409a90cf9f2SGordon Ross * 410a90cf9f2SGordon Ross * The last slot in the dispatch table is used to handle 411a90cf9f2SGordon Ross * invalid commands. Same for statistics. 412a90cf9f2SGordon Ross */ 413a90cf9f2SGordon Ross if (sr->smb2_cmd_code < SMB2_INVALID_CMD) 414a90cf9f2SGordon Ross cmd_idx = sr->smb2_cmd_code; 415a90cf9f2SGordon Ross else 416a90cf9f2SGordon Ross cmd_idx = SMB2_INVALID_CMD; 417a90cf9f2SGordon Ross sdd = &smb2_disp_table[cmd_idx]; 418a90cf9f2SGordon Ross sds = &session->s_server->sv_disp_stats2[cmd_idx]; 419a90cf9f2SGordon Ross 420a90cf9f2SGordon Ross /* 421a90cf9f2SGordon Ross * If this command is NOT "related" to the previous, 422a90cf9f2SGordon Ross * clear out the UID, TID, FID state that might be 423a90cf9f2SGordon Ross * left over from the previous command. 424a90cf9f2SGordon Ross * 425a90cf9f2SGordon Ross * If the command IS related, any new IDs are ignored, 426a90cf9f2SGordon Ross * and we simply continue with the previous user, tree, 427a90cf9f2SGordon Ross * and open file. 428a90cf9f2SGordon Ross */ 429a90cf9f2SGordon Ross if (!related) { 430a90cf9f2SGordon Ross /* 431a90cf9f2SGordon Ross * Drop user, tree, file; carefully ordered to 432a90cf9f2SGordon Ross * avoid dangling references: file, tree, user 433a90cf9f2SGordon Ross */ 434a90cf9f2SGordon Ross if (sr->fid_ofile != NULL) { 435a90cf9f2SGordon Ross smb_ofile_request_complete(sr->fid_ofile); 436a90cf9f2SGordon Ross smb_ofile_release(sr->fid_ofile); 437a90cf9f2SGordon Ross sr->fid_ofile = NULL; 438a90cf9f2SGordon Ross } 439a90cf9f2SGordon Ross if (sr->tid_tree != NULL) { 440a90cf9f2SGordon Ross smb_tree_release(sr->tid_tree); 441a90cf9f2SGordon Ross sr->tid_tree = NULL; 442a90cf9f2SGordon Ross } 443a90cf9f2SGordon Ross if (sr->uid_user != NULL) { 444a90cf9f2SGordon Ross smb_user_release(sr->uid_user); 445a90cf9f2SGordon Ross sr->uid_user = NULL; 446a90cf9f2SGordon Ross sr->user_cr = zone_kcred(); 447a90cf9f2SGordon Ross } 448a90cf9f2SGordon Ross } 449a90cf9f2SGordon Ross 450a90cf9f2SGordon Ross /* 451a90cf9f2SGordon Ross * Make sure we have a user and tree as needed 452a90cf9f2SGordon Ross * according to the flags for the this command. 453a90cf9f2SGordon Ross * Note that we may have inherited these. 454a90cf9f2SGordon Ross */ 455a90cf9f2SGordon Ross if ((sdd->sdt_flags & SDDF_SUPPRESS_UID) == 0) { 456a90cf9f2SGordon Ross /* 457a90cf9f2SGordon Ross * This command requires a user session. 458a90cf9f2SGordon Ross */ 459a90cf9f2SGordon Ross if (related) { 460a90cf9f2SGordon Ross /* 461a90cf9f2SGordon Ross * Previous command should have given us a user. 462a90cf9f2SGordon Ross * [MS-SMB2] 3.3.5.2 Handling Related Requests 463a90cf9f2SGordon Ross */ 464a90cf9f2SGordon Ross if (sr->uid_user == NULL) { 465a90cf9f2SGordon Ross smb2sr_put_error(sr, 466a90cf9f2SGordon Ross NT_STATUS_INVALID_PARAMETER); 467a90cf9f2SGordon Ross goto cmd_done; 468a90cf9f2SGordon Ross } 469a90cf9f2SGordon Ross sr->smb_uid = sr->uid_user->u_uid; 470a90cf9f2SGordon Ross } else { 471a90cf9f2SGordon Ross /* 472a90cf9f2SGordon Ross * Lookup the UID 473a90cf9f2SGordon Ross * [MS-SMB2] 3.3.5.2 Verifying the Session 474a90cf9f2SGordon Ross */ 475a90cf9f2SGordon Ross ASSERT(sr->uid_user == NULL); 476a90cf9f2SGordon Ross sr->uid_user = smb_session_lookup_uid(session, 477a90cf9f2SGordon Ross sr->smb_uid); 478a90cf9f2SGordon Ross if (sr->uid_user == NULL) { 479a90cf9f2SGordon Ross smb2sr_put_error(sr, 480a90cf9f2SGordon Ross NT_STATUS_USER_SESSION_DELETED); 481a90cf9f2SGordon Ross goto cmd_done; 482a90cf9f2SGordon Ross } 483a90cf9f2SGordon Ross sr->user_cr = smb_user_getcred(sr->uid_user); 484a90cf9f2SGordon Ross } 485a90cf9f2SGordon Ross ASSERT(sr->uid_user != NULL); 486a90cf9f2SGordon Ross } 487a90cf9f2SGordon Ross 488a90cf9f2SGordon Ross if ((sdd->sdt_flags & SDDF_SUPPRESS_TID) == 0) { 489a90cf9f2SGordon Ross /* 490a90cf9f2SGordon Ross * This command requires a tree connection. 491a90cf9f2SGordon Ross */ 492a90cf9f2SGordon Ross if (related) { 493a90cf9f2SGordon Ross /* 494a90cf9f2SGordon Ross * Previous command should have given us a tree. 495a90cf9f2SGordon Ross * [MS-SMB2] 3.3.5.2 Handling Related Requests 496a90cf9f2SGordon Ross */ 497a90cf9f2SGordon Ross if (sr->tid_tree == NULL) { 498a90cf9f2SGordon Ross smb2sr_put_error(sr, 499a90cf9f2SGordon Ross NT_STATUS_INVALID_PARAMETER); 500a90cf9f2SGordon Ross goto cmd_done; 501a90cf9f2SGordon Ross } 502a90cf9f2SGordon Ross sr->smb_tid = sr->tid_tree->t_tid; 503a90cf9f2SGordon Ross } else { 504a90cf9f2SGordon Ross /* 505a90cf9f2SGordon Ross * Lookup the TID 506a90cf9f2SGordon Ross * [MS-SMB2] 3.3.5.2 Verifying the Tree Connect 507a90cf9f2SGordon Ross */ 508a90cf9f2SGordon Ross ASSERT(sr->tid_tree == NULL); 509a90cf9f2SGordon Ross sr->tid_tree = smb_session_lookup_tree(session, 510a90cf9f2SGordon Ross sr->smb_tid); 511a90cf9f2SGordon Ross if (sr->tid_tree == NULL) { 512a90cf9f2SGordon Ross smb2sr_put_error(sr, 513a90cf9f2SGordon Ross NT_STATUS_NETWORK_NAME_DELETED); 514a90cf9f2SGordon Ross goto cmd_done; 515a90cf9f2SGordon Ross } 516a90cf9f2SGordon Ross } 517a90cf9f2SGordon Ross ASSERT(sr->tid_tree != NULL); 518a90cf9f2SGordon Ross } 519a90cf9f2SGordon Ross 520a90cf9f2SGordon Ross /* 521a90cf9f2SGordon Ross * SMB2 signature verification, two parts: 522a90cf9f2SGordon Ross * (a) Require SMB2_FLAGS_SIGNED (for most request types) 523a90cf9f2SGordon Ross * (b) If SMB2_FLAGS_SIGNED is set, check the signature. 524a90cf9f2SGordon Ross * [MS-SMB2] 3.3.5.2.4 Verifying the Signature 525a90cf9f2SGordon Ross */ 526a90cf9f2SGordon Ross 527a90cf9f2SGordon Ross /* 528a90cf9f2SGordon Ross * No user session means no signature check. That's OK, 529a90cf9f2SGordon Ross * i.e. for commands marked SDDF_SUPPRESS_UID above. 530a90cf9f2SGordon Ross * Note, this also means we won't sign the reply. 531a90cf9f2SGordon Ross */ 532a90cf9f2SGordon Ross if (sr->uid_user == NULL) 533a90cf9f2SGordon Ross sr->smb2_hdr_flags &= ~SMB2_FLAGS_SIGNED; 534a90cf9f2SGordon Ross 535a90cf9f2SGordon Ross /* 536a90cf9f2SGordon Ross * The SDDF_SUPPRESS_UID dispatch is set for requests that 537a90cf9f2SGordon Ross * don't need a UID (user). These also don't require a 538a90cf9f2SGordon Ross * signature check here. 539a90cf9f2SGordon Ross */ 540a90cf9f2SGordon Ross if ((sdd->sdt_flags & SDDF_SUPPRESS_UID) == 0 && 541a90cf9f2SGordon Ross sr->uid_user != NULL && 542a90cf9f2SGordon Ross (sr->uid_user->u_sign_flags & SMB_SIGNING_CHECK) != 0) { 543a90cf9f2SGordon Ross /* 544a90cf9f2SGordon Ross * This request type should be signed, and 545a90cf9f2SGordon Ross * we're configured to require signatures. 546a90cf9f2SGordon Ross */ 547a90cf9f2SGordon Ross if ((sr->smb2_hdr_flags & SMB2_FLAGS_SIGNED) == 0) { 548a90cf9f2SGordon Ross smb2sr_put_error(sr, NT_STATUS_ACCESS_DENIED); 549a90cf9f2SGordon Ross goto cmd_done; 550a90cf9f2SGordon Ross } 551a90cf9f2SGordon Ross rc = smb2_sign_check_request(sr); 552a90cf9f2SGordon Ross if (rc != 0) { 553a90cf9f2SGordon Ross DTRACE_PROBE1(smb2__sign__check, smb_request_t, sr); 554a90cf9f2SGordon Ross smb2sr_put_error(sr, NT_STATUS_ACCESS_DENIED); 555a90cf9f2SGordon Ross goto cmd_done; 556a90cf9f2SGordon Ross } 557a90cf9f2SGordon Ross } 558a90cf9f2SGordon Ross 559a90cf9f2SGordon Ross /* 560a90cf9f2SGordon Ross * Now that the signing check is done with smb_data, 561a90cf9f2SGordon Ross * advance past the SMB2 header we decoded earlier. 562a90cf9f2SGordon Ross * This leaves sr->smb_data correctly positioned 563a90cf9f2SGordon Ross * for command-specific decoding in the dispatch 564a90cf9f2SGordon Ross * function called next. 565a90cf9f2SGordon Ross */ 566a90cf9f2SGordon Ross sr->smb_data.chain_offset = sr->smb2_cmd_hdr + SMB2_HDR_SIZE; 567a90cf9f2SGordon Ross 568a90cf9f2SGordon Ross /* 569a90cf9f2SGordon Ross * SMB2 credits determine how many simultaneous commands the 570a90cf9f2SGordon Ross * client may issue, and bounds the range of message IDs those 571a90cf9f2SGordon Ross * commands may use. With multi-credit support, commands may 572a90cf9f2SGordon Ross * use ranges of message IDs, where the credits used by each 573a90cf9f2SGordon Ross * command are proportional to their data transfer size. 574a90cf9f2SGordon Ross * 575a90cf9f2SGordon Ross * Every command may request an increase or decrease of 576a90cf9f2SGordon Ross * the currently granted credits, based on the difference 577a90cf9f2SGordon Ross * between the credit request and the credit charge. 578a90cf9f2SGordon Ross * [MS-SMB2] 3.3.1.2 Algorithm for the Granting of Credits 579a90cf9f2SGordon Ross * 580a90cf9f2SGordon Ross * Most commands have credit_request=1, credit_charge=1, 581a90cf9f2SGordon Ross * which keeps the credit grant unchanged. 582a90cf9f2SGordon Ross * 583a90cf9f2SGordon Ross * All we're really doing here (for now) is reducing the 584a90cf9f2SGordon Ross * credit_response if the client requests a credit increase 585a90cf9f2SGordon Ross * that would take their credit over the maximum, and 586a90cf9f2SGordon Ross * limiting the decrease so they don't run out of credits. 587a90cf9f2SGordon Ross * 588a90cf9f2SGordon Ross * Later, this could do something dynamic based on load. 589a90cf9f2SGordon Ross * 590a90cf9f2SGordon Ross * One other non-obvious bit about credits: We keep the 591a90cf9f2SGordon Ross * session s_max_credits low until the 1st authentication, 592a90cf9f2SGordon Ross * at which point we'll set the normal maximum_credits. 593a90cf9f2SGordon Ross * Some clients ask for more credits with session setup, 594a90cf9f2SGordon Ross * and we need to handle that requested increase _after_ 595a90cf9f2SGordon Ross * the command-specific handler returns so it won't be 596a90cf9f2SGordon Ross * restricted to the lower (pre-auth) limit. 597a90cf9f2SGordon Ross */ 598a90cf9f2SGordon Ross sr->smb2_credit_response = sr->smb2_credit_request; 599a90cf9f2SGordon Ross if (sr->smb2_credit_request < sr->smb2_credit_charge) { 600a90cf9f2SGordon Ross uint16_t cur, d; 601a90cf9f2SGordon Ross 602a90cf9f2SGordon Ross mutex_enter(&session->s_credits_mutex); 603a90cf9f2SGordon Ross cur = session->s_cur_credits; 604a90cf9f2SGordon Ross 605a90cf9f2SGordon Ross /* Handle credit decrease. */ 606a90cf9f2SGordon Ross d = sr->smb2_credit_charge - sr->smb2_credit_request; 607a90cf9f2SGordon Ross cur -= d; 608a90cf9f2SGordon Ross if (cur & 0x8000) { 609a90cf9f2SGordon Ross /* 610a90cf9f2SGordon Ross * underflow (bad credit charge or request) 611a90cf9f2SGordon Ross * leave credits unchanged (response=charge) 612a90cf9f2SGordon Ross */ 613a90cf9f2SGordon Ross cur = session->s_cur_credits; 614a90cf9f2SGordon Ross sr->smb2_credit_response = sr->smb2_credit_charge; 615a90cf9f2SGordon Ross DTRACE_PROBE1(smb2__credit__neg, smb_request_t, sr); 616a90cf9f2SGordon Ross } 617a90cf9f2SGordon Ross 618a90cf9f2SGordon Ross /* 619a90cf9f2SGordon Ross * The server MUST ensure that the number of credits 620a90cf9f2SGordon Ross * held by the client is never reduced to zero. 621a90cf9f2SGordon Ross * [MS-SMB2] 3.3.1.2 622a90cf9f2SGordon Ross */ 623a90cf9f2SGordon Ross if (cur == 0) { 624a90cf9f2SGordon Ross cur = 1; 625a90cf9f2SGordon Ross sr->smb2_credit_response += 1; 626a90cf9f2SGordon Ross DTRACE_PROBE1(smb2__credit__min, smb_request_t, sr); 627a90cf9f2SGordon Ross } 628a90cf9f2SGordon Ross 629a90cf9f2SGordon Ross DTRACE_PROBE3(smb2__credit__decrease, 630a90cf9f2SGordon Ross smb_request_t, sr, int, (int)cur, 631a90cf9f2SGordon Ross int, (int)session->s_cur_credits); 632a90cf9f2SGordon Ross 633a90cf9f2SGordon Ross session->s_cur_credits = cur; 634a90cf9f2SGordon Ross mutex_exit(&session->s_credits_mutex); 635a90cf9f2SGordon Ross } 636a90cf9f2SGordon Ross 637a90cf9f2SGordon Ross /* 638a90cf9f2SGordon Ross * The real work: call the SMB2 command handler 639a90cf9f2SGordon Ross * (except for "sticky" smb2_status - see above) 640a90cf9f2SGordon Ross */ 641a90cf9f2SGordon Ross sr->sr_time_start = gethrtime(); 642a90cf9f2SGordon Ross rc = SDRC_SUCCESS; 643a90cf9f2SGordon Ross if (sr->smb2_status == 0) { 644a90cf9f2SGordon Ross /* NB: not using pre_op */ 645a90cf9f2SGordon Ross rc = (*sdd->sdt_function)(sr); 646a90cf9f2SGordon Ross /* NB: not using post_op */ 647a90cf9f2SGordon Ross } 648a90cf9f2SGordon Ross 649a90cf9f2SGordon Ross MBC_FLUSH(&sr->raw_data); 650a90cf9f2SGordon Ross 651a90cf9f2SGordon Ross /* 652a90cf9f2SGordon Ross * Second half of SMB2 credit handling (increases) 653a90cf9f2SGordon Ross */ 654a90cf9f2SGordon Ross if (sr->smb2_credit_request > sr->smb2_credit_charge) { 655a90cf9f2SGordon Ross uint16_t cur, d; 656a90cf9f2SGordon Ross 657a90cf9f2SGordon Ross mutex_enter(&session->s_credits_mutex); 658a90cf9f2SGordon Ross cur = session->s_cur_credits; 659a90cf9f2SGordon Ross 660a90cf9f2SGordon Ross /* Handle credit increase. */ 661a90cf9f2SGordon Ross d = sr->smb2_credit_request - sr->smb2_credit_charge; 662a90cf9f2SGordon Ross cur += d; 663a90cf9f2SGordon Ross 664a90cf9f2SGordon Ross /* 665a90cf9f2SGordon Ross * If new credits would be above max, 666a90cf9f2SGordon Ross * reduce the credit grant. 667a90cf9f2SGordon Ross */ 668a90cf9f2SGordon Ross if (cur > session->s_max_credits) { 669a90cf9f2SGordon Ross d = cur - session->s_max_credits; 670a90cf9f2SGordon Ross cur = session->s_max_credits; 671a90cf9f2SGordon Ross sr->smb2_credit_response -= d; 672a90cf9f2SGordon Ross DTRACE_PROBE1(smb2__credit__max, smb_request_t, sr); 673a90cf9f2SGordon Ross } 674a90cf9f2SGordon Ross 675a90cf9f2SGordon Ross DTRACE_PROBE3(smb2__credit__increase, 676a90cf9f2SGordon Ross smb_request_t, sr, int, (int)cur, 677a90cf9f2SGordon Ross int, (int)session->s_cur_credits); 678a90cf9f2SGordon Ross 679a90cf9f2SGordon Ross session->s_cur_credits = cur; 680a90cf9f2SGordon Ross mutex_exit(&session->s_credits_mutex); 681a90cf9f2SGordon Ross } 682a90cf9f2SGordon Ross 683a90cf9f2SGordon Ross cmd_done: 684a90cf9f2SGordon Ross /* 685a90cf9f2SGordon Ross * Pad the reply to align(8) if necessary. 686a90cf9f2SGordon Ross */ 687a90cf9f2SGordon Ross if (sr->reply.chain_offset & 7) { 688a90cf9f2SGordon Ross int padsz = 8 - (sr->reply.chain_offset & 7); 689a90cf9f2SGordon Ross (void) smb_mbc_encodef(&sr->reply, "#.", padsz); 690a90cf9f2SGordon Ross } 691a90cf9f2SGordon Ross ASSERT((sr->reply.chain_offset & 7) == 0); 692a90cf9f2SGordon Ross 693a90cf9f2SGordon Ross /* 694a90cf9f2SGordon Ross * Record some statistics: latency, rx bytes, tx bytes. 695a90cf9f2SGordon Ross */ 696*ac2bf314SMatt Barden smb_server_inc_req(sr->sr_server); 697a90cf9f2SGordon Ross smb_latency_add_sample(&sds->sdt_lat, 698a90cf9f2SGordon Ross gethrtime() - sr->sr_time_start); 699a90cf9f2SGordon Ross atomic_add_64(&sds->sdt_rxb, 700a90cf9f2SGordon Ross (int64_t)(sr->command.chain_offset - sr->smb2_cmd_hdr)); 701a90cf9f2SGordon Ross atomic_add_64(&sds->sdt_txb, 702a90cf9f2SGordon Ross (int64_t)(sr->reply.chain_offset - sr->smb2_reply_hdr)); 703a90cf9f2SGordon Ross 704a90cf9f2SGordon Ross switch (rc) { 705a90cf9f2SGordon Ross case SDRC_SUCCESS: 706a90cf9f2SGordon Ross break; 707a90cf9f2SGordon Ross default: 708a90cf9f2SGordon Ross /* 709a90cf9f2SGordon Ross * SMB2 does not use the other dispatch return codes. 710a90cf9f2SGordon Ross * If we see something else, log an event so we'll 711a90cf9f2SGordon Ross * know something is returning bogus status codes. 712a90cf9f2SGordon Ross * If you see these in the log, use dtrace to find 713a90cf9f2SGordon Ross * the code returning something else. 714a90cf9f2SGordon Ross */ 715a90cf9f2SGordon Ross #ifdef DEBUG 716a90cf9f2SGordon Ross cmn_err(CE_NOTE, "handler for %u returned 0x%x", 717a90cf9f2SGordon Ross sr->smb2_cmd_code, rc); 718a90cf9f2SGordon Ross #endif 719a90cf9f2SGordon Ross /* FALLTHROUGH */ 720a90cf9f2SGordon Ross case SDRC_ERROR: 721a90cf9f2SGordon Ross if (sr->smb2_status == 0) 722a90cf9f2SGordon Ross sr->smb2_status = NT_STATUS_INTERNAL_ERROR; 723a90cf9f2SGordon Ross break; 724a90cf9f2SGordon Ross case SDRC_DROP_VC: 725a90cf9f2SGordon Ross disconnect = B_TRUE; 726a90cf9f2SGordon Ross goto cleanup; 727a90cf9f2SGordon Ross } 728a90cf9f2SGordon Ross 729a90cf9f2SGordon Ross /* 730a90cf9f2SGordon Ross * If there's a next command, figure out where it starts, 731a90cf9f2SGordon Ross * and fill in the next command offset for the reply. 732a90cf9f2SGordon Ross * Note: We sanity checked smb2_next_command above 733a90cf9f2SGordon Ross * (the offset to the next command). Similarly set 734a90cf9f2SGordon Ross * smb2_next_reply as the offset to the next reply. 735a90cf9f2SGordon Ross */ 736a90cf9f2SGordon Ross if (sr->smb2_next_command != 0) { 737a90cf9f2SGordon Ross sr->command.chain_offset = 738a90cf9f2SGordon Ross sr->smb2_cmd_hdr + sr->smb2_next_command; 739a90cf9f2SGordon Ross sr->smb2_next_reply = 740a90cf9f2SGordon Ross sr->reply.chain_offset - sr->smb2_reply_hdr; 741a90cf9f2SGordon Ross } else { 742a90cf9f2SGordon Ross sr->smb2_next_reply = 0; 743a90cf9f2SGordon Ross } 744a90cf9f2SGordon Ross 745a90cf9f2SGordon Ross /* 746a90cf9f2SGordon Ross * Overwrite the SMB2 header for the response of 747a90cf9f2SGordon Ross * this command (possibly part of a compound). 748a90cf9f2SGordon Ross * encode_header adds: SMB2_FLAGS_SERVER_TO_REDIR 749a90cf9f2SGordon Ross */ 750a90cf9f2SGordon Ross (void) smb2_encode_header(sr, B_TRUE); 751a90cf9f2SGordon Ross 752a90cf9f2SGordon Ross if (sr->smb2_hdr_flags & SMB2_FLAGS_SIGNED) 753a90cf9f2SGordon Ross smb2_sign_reply(sr); 754a90cf9f2SGordon Ross 755a90cf9f2SGordon Ross if (sr->smb2_next_command != 0) 756a90cf9f2SGordon Ross goto cmd_start; 757a90cf9f2SGordon Ross 758a90cf9f2SGordon Ross /* 759a90cf9f2SGordon Ross * We've done all the commands in this compound. 760a90cf9f2SGordon Ross * Send it out. 761a90cf9f2SGordon Ross */ 762a90cf9f2SGordon Ross smb2_send_reply(sr); 763a90cf9f2SGordon Ross 764a90cf9f2SGordon Ross /* 765a90cf9f2SGordon Ross * If any of the requests "went async", process those now. 766a90cf9f2SGordon Ross * The async. function "keeps" this sr, changing its state 767a90cf9f2SGordon Ross * to completed and calling smb_request_free(). 768a90cf9f2SGordon Ross */ 769a90cf9f2SGordon Ross if (sr->sr_async_req != NULL) { 770a90cf9f2SGordon Ross smb2sr_do_async(sr); 771a90cf9f2SGordon Ross return; 772a90cf9f2SGordon Ross } 773a90cf9f2SGordon Ross 774a90cf9f2SGordon Ross cleanup: 775a90cf9f2SGordon Ross if (disconnect) { 776a90cf9f2SGordon Ross smb_rwx_rwenter(&session->s_lock, RW_WRITER); 777a90cf9f2SGordon Ross switch (session->s_state) { 778a90cf9f2SGordon Ross case SMB_SESSION_STATE_DISCONNECTED: 779a90cf9f2SGordon Ross case SMB_SESSION_STATE_TERMINATED: 780a90cf9f2SGordon Ross break; 781a90cf9f2SGordon Ross default: 782a90cf9f2SGordon Ross smb_soshutdown(session->sock); 783a90cf9f2SGordon Ross session->s_state = SMB_SESSION_STATE_DISCONNECTED; 784a90cf9f2SGordon Ross break; 785a90cf9f2SGordon Ross } 786a90cf9f2SGordon Ross smb_rwx_rwexit(&session->s_lock); 787a90cf9f2SGordon Ross } 788a90cf9f2SGordon Ross 789a90cf9f2SGordon Ross mutex_enter(&sr->sr_mutex); 790a90cf9f2SGordon Ross sr->sr_state = SMB_REQ_STATE_COMPLETED; 791a90cf9f2SGordon Ross mutex_exit(&sr->sr_mutex); 792a90cf9f2SGordon Ross 793a90cf9f2SGordon Ross smb_request_free(sr); 794a90cf9f2SGordon Ross } 795a90cf9f2SGordon Ross 796a90cf9f2SGordon Ross /* 797a90cf9f2SGordon Ross * Dispatch an async request using saved information. 798a90cf9f2SGordon Ross * See smb2sr_save_async and [MS-SMB2] 3.3.4.2 799a90cf9f2SGordon Ross * 800a90cf9f2SGordon Ross * This is sort of a "lite" version of smb2sr_work. Initialize the 801a90cf9f2SGordon Ross * command and reply areas as they were when the command-speicific 802a90cf9f2SGordon Ross * handler started (in case it needs to decode anything again). 803a90cf9f2SGordon Ross * Call the async function, which builds the command-specific part 804a90cf9f2SGordon Ross * of the response. Finally, send the response and free the sr. 805a90cf9f2SGordon Ross */ 806a90cf9f2SGordon Ross void 807a90cf9f2SGordon Ross smb2sr_do_async(smb_request_t *sr) 808a90cf9f2SGordon Ross { 809a90cf9f2SGordon Ross const smb_disp_entry_t *sdd; 810a90cf9f2SGordon Ross smb_disp_stats_t *sds; 811a90cf9f2SGordon Ross smb2_async_req_t *ar; 812a90cf9f2SGordon Ross int rc = 0; 813a90cf9f2SGordon Ross 814a90cf9f2SGordon Ross /* 815a90cf9f2SGordon Ross * Restore what smb2_decode_header found. 816a90cf9f2SGordon Ross * (In lieu of decoding it again.) 817a90cf9f2SGordon Ross */ 818a90cf9f2SGordon Ross ar = sr->sr_async_req; 819a90cf9f2SGordon Ross sr->smb2_cmd_hdr = ar->ar_cmd_hdr; 820a90cf9f2SGordon Ross sr->smb2_cmd_code = ar->ar_cmd_code; 821a90cf9f2SGordon Ross sr->smb2_hdr_flags = ar->ar_hdr_flags; 822a90cf9f2SGordon Ross sr->smb2_async_id = (uintptr_t)ar; 823a90cf9f2SGordon Ross sr->smb2_messageid = ar->ar_messageid; 824a90cf9f2SGordon Ross sr->smb_pid = ar->ar_pid; 825a90cf9f2SGordon Ross sr->smb_tid = ar->ar_tid; 826a90cf9f2SGordon Ross sr->smb_uid = ar->ar_uid; 827a90cf9f2SGordon Ross sr->smb2_status = 0; 828a90cf9f2SGordon Ross 829a90cf9f2SGordon Ross /* 830a90cf9f2SGordon Ross * Async requests don't grant credits, because any credits 831a90cf9f2SGordon Ross * should have gone out with the interim reply. 832a90cf9f2SGordon Ross * An async reply goes alone (no next reply). 833a90cf9f2SGordon Ross */ 834a90cf9f2SGordon Ross sr->smb2_credit_response = 0; 835a90cf9f2SGordon Ross sr->smb2_next_reply = 0; 836a90cf9f2SGordon Ross 837a90cf9f2SGordon Ross /* 838a90cf9f2SGordon Ross * Setup input mbuf_chain 839a90cf9f2SGordon Ross */ 840a90cf9f2SGordon Ross ASSERT(ar->ar_cmd_len >= SMB2_HDR_SIZE); 841a90cf9f2SGordon Ross (void) MBC_SHADOW_CHAIN(&sr->smb_data, &sr->command, 842a90cf9f2SGordon Ross sr->smb2_cmd_hdr + SMB2_HDR_SIZE, 843a90cf9f2SGordon Ross ar->ar_cmd_len - SMB2_HDR_SIZE); 844a90cf9f2SGordon Ross 845a90cf9f2SGordon Ross /* 846a90cf9f2SGordon Ross * Setup output mbuf_chain 847a90cf9f2SGordon Ross */ 848a90cf9f2SGordon Ross MBC_FLUSH(&sr->reply); 849a90cf9f2SGordon Ross sr->smb2_reply_hdr = sr->reply.chain_offset; 850a90cf9f2SGordon Ross (void) smb2_encode_header(sr, B_FALSE); 851a90cf9f2SGordon Ross 852a90cf9f2SGordon Ross VERIFY3U(sr->smb2_cmd_code, <, SMB2_INVALID_CMD); 853a90cf9f2SGordon Ross sdd = &smb2_disp_table[sr->smb2_cmd_code]; 854a90cf9f2SGordon Ross sds = sr->session->s_server->sv_disp_stats2; 855a90cf9f2SGordon Ross sds = &sds[sr->smb2_cmd_code]; 856a90cf9f2SGordon Ross 857a90cf9f2SGordon Ross /* 858a90cf9f2SGordon Ross * Keep the UID, TID, ofile we have. 859a90cf9f2SGordon Ross */ 860a90cf9f2SGordon Ross if ((sdd->sdt_flags & SDDF_SUPPRESS_UID) == 0 && 861a90cf9f2SGordon Ross sr->uid_user == NULL) { 862a90cf9f2SGordon Ross smb2sr_put_error(sr, NT_STATUS_USER_SESSION_DELETED); 863a90cf9f2SGordon Ross goto cmd_done; 864a90cf9f2SGordon Ross } 865a90cf9f2SGordon Ross if ((sdd->sdt_flags & SDDF_SUPPRESS_TID) == 0 && 866a90cf9f2SGordon Ross sr->tid_tree == NULL) { 867a90cf9f2SGordon Ross smb2sr_put_error(sr, NT_STATUS_NETWORK_NAME_DELETED); 868a90cf9f2SGordon Ross goto cmd_done; 869a90cf9f2SGordon Ross } 870a90cf9f2SGordon Ross 871a90cf9f2SGordon Ross /* 872a90cf9f2SGordon Ross * Signature already verified 873a90cf9f2SGordon Ross * Credits handled... 874a90cf9f2SGordon Ross * 875a90cf9f2SGordon Ross * Just call the async handler function. 876a90cf9f2SGordon Ross */ 877a90cf9f2SGordon Ross rc = ar->ar_func(sr); 878a90cf9f2SGordon Ross if (rc != 0 && sr->smb2_status == 0) 879a90cf9f2SGordon Ross sr->smb2_status = NT_STATUS_INTERNAL_ERROR; 880a90cf9f2SGordon Ross 881a90cf9f2SGordon Ross cmd_done: 882a90cf9f2SGordon Ross /* 883a90cf9f2SGordon Ross * Pad the reply to align(8) if necessary. 884a90cf9f2SGordon Ross */ 885a90cf9f2SGordon Ross if (sr->reply.chain_offset & 7) { 886a90cf9f2SGordon Ross int padsz = 8 - (sr->reply.chain_offset & 7); 887a90cf9f2SGordon Ross (void) smb_mbc_encodef(&sr->reply, "#.", padsz); 888a90cf9f2SGordon Ross } 889a90cf9f2SGordon Ross ASSERT((sr->reply.chain_offset & 7) == 0); 890a90cf9f2SGordon Ross 891a90cf9f2SGordon Ross /* 892a90cf9f2SGordon Ross * Record some statistics: (just tx bytes here) 893a90cf9f2SGordon Ross */ 894a90cf9f2SGordon Ross atomic_add_64(&sds->sdt_txb, 895a90cf9f2SGordon Ross (int64_t)(sr->reply.chain_offset - sr->smb2_reply_hdr)); 896a90cf9f2SGordon Ross 897a90cf9f2SGordon Ross /* 898a90cf9f2SGordon Ross * Overwrite the SMB2 header for the response of 899a90cf9f2SGordon Ross * this command (possibly part of a compound). 900a90cf9f2SGordon Ross * The call adds: SMB2_FLAGS_SERVER_TO_REDIR 901a90cf9f2SGordon Ross */ 902a90cf9f2SGordon Ross (void) smb2_encode_header(sr, B_TRUE); 903a90cf9f2SGordon Ross 904a90cf9f2SGordon Ross if (sr->smb2_hdr_flags & SMB2_FLAGS_SIGNED) 905a90cf9f2SGordon Ross smb2_sign_reply(sr); 906a90cf9f2SGordon Ross 907a90cf9f2SGordon Ross smb2_send_reply(sr); 908a90cf9f2SGordon Ross 909a90cf9f2SGordon Ross /* 910a90cf9f2SGordon Ross * Done. Unlink and free. 911a90cf9f2SGordon Ross */ 912a90cf9f2SGordon Ross sr->sr_async_req = NULL; 913a90cf9f2SGordon Ross kmem_free(ar, sizeof (*ar)); 914a90cf9f2SGordon Ross 915a90cf9f2SGordon Ross mutex_enter(&sr->sr_mutex); 916a90cf9f2SGordon Ross sr->sr_state = SMB_REQ_STATE_COMPLETED; 917a90cf9f2SGordon Ross mutex_exit(&sr->sr_mutex); 918a90cf9f2SGordon Ross 919a90cf9f2SGordon Ross smb_request_free(sr); 920a90cf9f2SGordon Ross } 921a90cf9f2SGordon Ross 922a90cf9f2SGordon Ross /* 923a90cf9f2SGordon Ross * In preparation for sending an "interim response", save 924a90cf9f2SGordon Ross * all the state we'll need to run an async command later, 925a90cf9f2SGordon Ross * and assign an "async id" for this (now async) command. 926a90cf9f2SGordon Ross * See [MS-SMB2] 3.3.4.2 927a90cf9f2SGordon Ross * 928a90cf9f2SGordon Ross * If more than one request in a compound request tries to 929a90cf9f2SGordon Ross * "go async", we can "say no". See [MS-SMB2] 3.3.4.2 930a90cf9f2SGordon Ross * If an operation would require asynchronous processing 931a90cf9f2SGordon Ross * but resources are constrained, the server MAY choose to 932a90cf9f2SGordon Ross * fail that operation with STATUS_INSUFFICIENT_RESOURCES. 933a90cf9f2SGordon Ross * 934a90cf9f2SGordon Ross * For simplicity, we further restrict the cases where we're 935a90cf9f2SGordon Ross * willing to "go async", and only allow the last command in a 936a90cf9f2SGordon Ross * compound to "go async". It happens that this is the only 937a90cf9f2SGordon Ross * case where we're actually asked to go async anyway. This 938a90cf9f2SGordon Ross * simplification also means there can be at most one command 939a90cf9f2SGordon Ross * in a compound that "goes async" (the last one). 940a90cf9f2SGordon Ross * 941a90cf9f2SGordon Ross * If we agree to "go async", this should return STATUS_PENDING. 942a90cf9f2SGordon Ross * Otherwise return STATUS_INSUFFICIENT_RESOURCES for this and 943a90cf9f2SGordon Ross * all requests following this request. (See the comments re. 944a90cf9f2SGordon Ross * "sticky" smb2_status values in smb2sr_work). 945a90cf9f2SGordon Ross * 946a90cf9f2SGordon Ross * Note: the Async ID we assign here is arbitrary, and need only 947a90cf9f2SGordon Ross * be unique among pending async responses on this connection, so 948a90cf9f2SGordon Ross * this just uses an object address as the Async ID. 949a90cf9f2SGordon Ross * 950a90cf9f2SGordon Ross * Also, the assigned worker is the ONLY thread using this 951a90cf9f2SGordon Ross * async request object (sr_async_req) so no locking. 952a90cf9f2SGordon Ross */ 953a90cf9f2SGordon Ross uint32_t 954a90cf9f2SGordon Ross smb2sr_go_async(smb_request_t *sr, 955adb064afSToomas Soome smb_sdrc_t (*async_func)(smb_request_t *)) 956a90cf9f2SGordon Ross { 957a90cf9f2SGordon Ross smb2_async_req_t *ar; 958a90cf9f2SGordon Ross 959a90cf9f2SGordon Ross if (sr->smb2_next_command != 0) 960a90cf9f2SGordon Ross return (NT_STATUS_INSUFFICIENT_RESOURCES); 961a90cf9f2SGordon Ross 962a90cf9f2SGordon Ross ASSERT(sr->sr_async_req == NULL); 963a90cf9f2SGordon Ross ar = kmem_zalloc(sizeof (*ar), KM_SLEEP); 964a90cf9f2SGordon Ross 965a90cf9f2SGordon Ross /* 966a90cf9f2SGordon Ross * Place an interim response in the compound reply. 967a90cf9f2SGordon Ross * 968a90cf9f2SGordon Ross * Turn on the "async" flag for both the (synchronous) 969a90cf9f2SGordon Ross * interim response and the (later) async response, 970a90cf9f2SGordon Ross * by storing that in flags before coping into ar. 971a90cf9f2SGordon Ross */ 972a90cf9f2SGordon Ross sr->smb2_hdr_flags |= SMB2_FLAGS_ASYNC_COMMAND; 973a90cf9f2SGordon Ross sr->smb2_async_id = (uintptr_t)ar; 974a90cf9f2SGordon Ross 975a90cf9f2SGordon Ross ar->ar_func = async_func; 976a90cf9f2SGordon Ross ar->ar_cmd_hdr = sr->smb2_cmd_hdr; 977a90cf9f2SGordon Ross ar->ar_cmd_len = sr->smb_data.max_bytes - sr->smb2_cmd_hdr; 978a90cf9f2SGordon Ross 979a90cf9f2SGordon Ross ar->ar_cmd_code = sr->smb2_cmd_code; 98058ccc3dcSGordon Ross ar->ar_hdr_flags = sr->smb2_hdr_flags; 981a90cf9f2SGordon Ross ar->ar_messageid = sr->smb2_messageid; 982a90cf9f2SGordon Ross ar->ar_pid = sr->smb_pid; 983a90cf9f2SGordon Ross ar->ar_tid = sr->smb_tid; 984a90cf9f2SGordon Ross ar->ar_uid = sr->smb_uid; 985a90cf9f2SGordon Ross 986a90cf9f2SGordon Ross sr->sr_async_req = ar; 987a90cf9f2SGordon Ross 988a90cf9f2SGordon Ross /* Interim responses are NOT signed. */ 989a90cf9f2SGordon Ross sr->smb2_hdr_flags &= ~SMB2_FLAGS_SIGNED; 990a90cf9f2SGordon Ross 991a90cf9f2SGordon Ross return (NT_STATUS_PENDING); 992a90cf9f2SGordon Ross } 993a90cf9f2SGordon Ross 994a90cf9f2SGordon Ross int 995a90cf9f2SGordon Ross smb2_decode_header(smb_request_t *sr) 996a90cf9f2SGordon Ross { 997a90cf9f2SGordon Ross uint64_t ssnid; 998a90cf9f2SGordon Ross uint32_t pid, tid; 999a90cf9f2SGordon Ross uint16_t hdr_len; 1000a90cf9f2SGordon Ross int rc; 1001a90cf9f2SGordon Ross 1002a90cf9f2SGordon Ross rc = smb_mbc_decodef( 1003a90cf9f2SGordon Ross &sr->command, "Nwww..wwllqllq16c", 1004a90cf9f2SGordon Ross &hdr_len, /* w */ 1005a90cf9f2SGordon Ross &sr->smb2_credit_charge, /* w */ 1006a90cf9f2SGordon Ross &sr->smb2_chan_seq, /* w */ 1007a90cf9f2SGordon Ross /* reserved .. */ 1008a90cf9f2SGordon Ross &sr->smb2_cmd_code, /* w */ 1009a90cf9f2SGordon Ross &sr->smb2_credit_request, /* w */ 1010a90cf9f2SGordon Ross &sr->smb2_hdr_flags, /* l */ 1011a90cf9f2SGordon Ross &sr->smb2_next_command, /* l */ 1012a90cf9f2SGordon Ross &sr->smb2_messageid, /* q */ 1013a90cf9f2SGordon Ross &pid, /* l */ 1014a90cf9f2SGordon Ross &tid, /* l */ 1015a90cf9f2SGordon Ross &ssnid, /* q */ 1016a90cf9f2SGordon Ross sr->smb2_sig); /* 16c */ 1017a90cf9f2SGordon Ross if (rc) 1018a90cf9f2SGordon Ross return (rc); 1019a90cf9f2SGordon Ross 1020a90cf9f2SGordon Ross if (hdr_len != SMB2_HDR_SIZE) 1021a90cf9f2SGordon Ross return (-1); 1022a90cf9f2SGordon Ross 1023a90cf9f2SGordon Ross sr->smb_uid = (uint16_t)ssnid; /* XXX wide UIDs */ 1024a90cf9f2SGordon Ross 1025a90cf9f2SGordon Ross if (sr->smb2_hdr_flags & SMB2_FLAGS_ASYNC_COMMAND) { 1026a90cf9f2SGordon Ross sr->smb2_async_id = pid | 1027a90cf9f2SGordon Ross ((uint64_t)tid) << 32; 1028a90cf9f2SGordon Ross } else { 1029a90cf9f2SGordon Ross sr->smb_pid = pid; 1030a90cf9f2SGordon Ross sr->smb_tid = (uint16_t)tid; /* XXX wide TIDs */ 1031a90cf9f2SGordon Ross } 1032a90cf9f2SGordon Ross 1033a90cf9f2SGordon Ross return (rc); 1034a90cf9f2SGordon Ross } 1035a90cf9f2SGordon Ross 1036a90cf9f2SGordon Ross int 1037a90cf9f2SGordon Ross smb2_encode_header(smb_request_t *sr, boolean_t overwrite) 1038a90cf9f2SGordon Ross { 1039a90cf9f2SGordon Ross uint64_t ssnid = sr->smb_uid; 1040a90cf9f2SGordon Ross uint64_t pid_tid_aid; /* pid+tid, or async id */ 1041a90cf9f2SGordon Ross uint32_t reply_hdr_flags; 1042a90cf9f2SGordon Ross int rc; 1043a90cf9f2SGordon Ross 1044a90cf9f2SGordon Ross if (sr->smb2_hdr_flags & SMB2_FLAGS_ASYNC_COMMAND) { 1045a90cf9f2SGordon Ross pid_tid_aid = sr->smb2_async_id; 1046a90cf9f2SGordon Ross } else { 1047a90cf9f2SGordon Ross pid_tid_aid = sr->smb_pid | 1048a90cf9f2SGordon Ross ((uint64_t)sr->smb_tid) << 32; 1049a90cf9f2SGordon Ross } 1050a90cf9f2SGordon Ross reply_hdr_flags = sr->smb2_hdr_flags | SMB2_FLAGS_SERVER_TO_REDIR; 1051a90cf9f2SGordon Ross 1052a90cf9f2SGordon Ross if (overwrite) { 1053a90cf9f2SGordon Ross rc = smb_mbc_poke(&sr->reply, 1054a90cf9f2SGordon Ross sr->smb2_reply_hdr, 1055a90cf9f2SGordon Ross "Nwwlwwllqqq16c", 1056a90cf9f2SGordon Ross SMB2_HDR_SIZE, /* w */ 1057a90cf9f2SGordon Ross sr->smb2_credit_charge, /* w */ 1058a90cf9f2SGordon Ross sr->smb2_status, /* l */ 1059a90cf9f2SGordon Ross sr->smb2_cmd_code, /* w */ 1060a90cf9f2SGordon Ross sr->smb2_credit_response, /* w */ 1061a90cf9f2SGordon Ross reply_hdr_flags, /* l */ 1062a90cf9f2SGordon Ross sr->smb2_next_reply, /* l */ 1063a90cf9f2SGordon Ross sr->smb2_messageid, /* q */ 1064a90cf9f2SGordon Ross pid_tid_aid, /* q */ 1065a90cf9f2SGordon Ross ssnid, /* q */ 1066a90cf9f2SGordon Ross sr->smb2_sig); /* 16c */ 1067a90cf9f2SGordon Ross } else { 1068a90cf9f2SGordon Ross rc = smb_mbc_encodef(&sr->reply, 1069a90cf9f2SGordon Ross "Nwwlwwllqqq16c", 1070a90cf9f2SGordon Ross SMB2_HDR_SIZE, /* w */ 1071a90cf9f2SGordon Ross sr->smb2_credit_charge, /* w */ 1072a90cf9f2SGordon Ross sr->smb2_status, /* l */ 1073a90cf9f2SGordon Ross sr->smb2_cmd_code, /* w */ 1074a90cf9f2SGordon Ross sr->smb2_credit_response, /* w */ 1075a90cf9f2SGordon Ross reply_hdr_flags, /* l */ 1076a90cf9f2SGordon Ross sr->smb2_next_reply, /* l */ 1077a90cf9f2SGordon Ross sr->smb2_messageid, /* q */ 1078a90cf9f2SGordon Ross pid_tid_aid, /* q */ 1079a90cf9f2SGordon Ross ssnid, /* q */ 1080a90cf9f2SGordon Ross sr->smb2_sig); /* 16c */ 1081a90cf9f2SGordon Ross } 1082a90cf9f2SGordon Ross 1083a90cf9f2SGordon Ross return (rc); 1084a90cf9f2SGordon Ross } 1085a90cf9f2SGordon Ross 1086a90cf9f2SGordon Ross void 1087a90cf9f2SGordon Ross smb2_send_reply(smb_request_t *sr) 1088a90cf9f2SGordon Ross { 1089a90cf9f2SGordon Ross 1090a90cf9f2SGordon Ross if (smb_session_send(sr->session, 0, &sr->reply) == 0) 1091a90cf9f2SGordon Ross sr->reply.chain = 0; 1092a90cf9f2SGordon Ross } 1093a90cf9f2SGordon Ross 1094a90cf9f2SGordon Ross /* 1095a90cf9f2SGordon Ross * This wrapper function exists to help catch calls to smbsr_status() 1096a90cf9f2SGordon Ross * (which is SMB1-specific) in common code. See smbsr_status(). 1097a90cf9f2SGordon Ross * If the log message below is seen, put a dtrace probe on this 1098a90cf9f2SGordon Ross * function with a stack() action to see who is calling the SMB1 1099a90cf9f2SGordon Ross * "put error" from common code, and fix it. 1100a90cf9f2SGordon Ross */ 1101a90cf9f2SGordon Ross void 1102a90cf9f2SGordon Ross smbsr_status_smb2(smb_request_t *sr, DWORD status) 1103a90cf9f2SGordon Ross { 1104a90cf9f2SGordon Ross const char *name; 1105a90cf9f2SGordon Ross 1106a90cf9f2SGordon Ross if (sr->smb2_cmd_code < SMB2__NCMDS) 1107a90cf9f2SGordon Ross name = smb2_disp_table[sr->smb2_cmd_code].sdt_name; 1108a90cf9f2SGordon Ross else 1109a90cf9f2SGordon Ross name = "<unknown>"; 1110a90cf9f2SGordon Ross #ifdef DEBUG 1111a90cf9f2SGordon Ross cmn_err(CE_NOTE, "smbsr_status called for %s", name); 1112a90cf9f2SGordon Ross #endif 1113a90cf9f2SGordon Ross 1114a90cf9f2SGordon Ross smb2sr_put_error_data(sr, status, NULL); 1115a90cf9f2SGordon Ross } 1116a90cf9f2SGordon Ross 1117a90cf9f2SGordon Ross void 1118a90cf9f2SGordon Ross smb2sr_put_errno(struct smb_request *sr, int errnum) 1119a90cf9f2SGordon Ross { 1120a90cf9f2SGordon Ross uint32_t status = smb_errno2status(errnum); 1121a90cf9f2SGordon Ross smb2sr_put_error_data(sr, status, NULL); 1122a90cf9f2SGordon Ross } 1123a90cf9f2SGordon Ross 1124a90cf9f2SGordon Ross void 1125a90cf9f2SGordon Ross smb2sr_put_error(smb_request_t *sr, uint32_t status) 1126a90cf9f2SGordon Ross { 1127a90cf9f2SGordon Ross smb2sr_put_error_data(sr, status, NULL); 1128a90cf9f2SGordon Ross } 1129a90cf9f2SGordon Ross 1130a90cf9f2SGordon Ross /* 1131a90cf9f2SGordon Ross * Build an SMB2 error response. [MS-SMB2] 2.2.2 1132a90cf9f2SGordon Ross */ 1133a90cf9f2SGordon Ross void 1134a90cf9f2SGordon Ross smb2sr_put_error_data(smb_request_t *sr, uint32_t status, mbuf_chain_t *mbc) 1135a90cf9f2SGordon Ross { 1136a90cf9f2SGordon Ross DWORD len; 1137a90cf9f2SGordon Ross 1138a90cf9f2SGordon Ross /* 1139a90cf9f2SGordon Ross * The common dispatch code writes this when it 1140a90cf9f2SGordon Ross * updates the SMB2 header before sending. 1141a90cf9f2SGordon Ross */ 1142a90cf9f2SGordon Ross sr->smb2_status = status; 1143a90cf9f2SGordon Ross 1144a90cf9f2SGordon Ross /* Rewind to the end of the SMB header. */ 1145a90cf9f2SGordon Ross sr->reply.chain_offset = sr->smb2_reply_hdr + SMB2_HDR_SIZE; 1146a90cf9f2SGordon Ross 1147a90cf9f2SGordon Ross /* 1148a90cf9f2SGordon Ross * NB: Must provide at least one byte of error data, 1149a90cf9f2SGordon Ross * per [MS-SMB2] 2.2.2 1150a90cf9f2SGordon Ross */ 1151a90cf9f2SGordon Ross if (mbc != NULL && (len = MBC_LENGTH(mbc)) != 0) { 1152a90cf9f2SGordon Ross (void) smb_mbc_encodef( 1153a90cf9f2SGordon Ross &sr->reply, 1154a90cf9f2SGordon Ross "wwlC", 1155a90cf9f2SGordon Ross 9, /* StructSize */ /* w */ 1156a90cf9f2SGordon Ross 0, /* reserved */ /* w */ 1157a90cf9f2SGordon Ross len, /* l */ 1158a90cf9f2SGordon Ross mbc); /* C */ 1159a90cf9f2SGordon Ross } else { 1160a90cf9f2SGordon Ross (void) smb_mbc_encodef( 1161a90cf9f2SGordon Ross &sr->reply, 1162a90cf9f2SGordon Ross "wwl.", 1163a90cf9f2SGordon Ross 9, /* StructSize */ /* w */ 1164a90cf9f2SGordon Ross 0, /* reserved */ /* w */ 1165a90cf9f2SGordon Ross 0); /* l. */ 1166a90cf9f2SGordon Ross } 1167a90cf9f2SGordon Ross } 1168a90cf9f2SGordon Ross 1169a90cf9f2SGordon Ross /* 1170a90cf9f2SGordon Ross * smb2sr_lookup_fid 1171a90cf9f2SGordon Ross * 1172a90cf9f2SGordon Ross * Setup sr->fid_ofile, either inherited from a related command, 1173a90cf9f2SGordon Ross * or obtained via FID lookup. Similar inheritance logic as in 1174a90cf9f2SGordon Ross * smb2sr_work. 1175a90cf9f2SGordon Ross */ 1176a90cf9f2SGordon Ross uint32_t 1177a90cf9f2SGordon Ross smb2sr_lookup_fid(smb_request_t *sr, smb2fid_t *fid) 1178a90cf9f2SGordon Ross { 1179a90cf9f2SGordon Ross boolean_t related = sr->smb2_hdr_flags & 1180a90cf9f2SGordon Ross SMB2_FLAGS_RELATED_OPERATIONS; 1181a90cf9f2SGordon Ross 1182a90cf9f2SGordon Ross if (related) { 1183a90cf9f2SGordon Ross if (sr->fid_ofile == NULL) 1184a90cf9f2SGordon Ross return (NT_STATUS_INVALID_PARAMETER); 1185a90cf9f2SGordon Ross sr->smb_fid = sr->fid_ofile->f_fid; 1186a90cf9f2SGordon Ross return (0); 1187a90cf9f2SGordon Ross } 1188a90cf9f2SGordon Ross 1189a90cf9f2SGordon Ross /* 1190a90cf9f2SGordon Ross * If we could be sure this is called only once per cmd, 1191a90cf9f2SGordon Ross * we could simply ASSERT(sr->fid_ofile == NULL) here. 1192a90cf9f2SGordon Ross * However, there are cases where it can be called again 1193a90cf9f2SGordon Ross * handling the same command, so let's tolerate that. 1194a90cf9f2SGordon Ross */ 1195a90cf9f2SGordon Ross if (sr->fid_ofile == NULL) { 1196a90cf9f2SGordon Ross sr->smb_fid = (uint16_t)fid->temporal; 1197a90cf9f2SGordon Ross sr->fid_ofile = smb_ofile_lookup_by_fid(sr, sr->smb_fid); 1198a90cf9f2SGordon Ross } 1199a90cf9f2SGordon Ross if (sr->fid_ofile == NULL) 1200a90cf9f2SGordon Ross return (NT_STATUS_FILE_CLOSED); 1201a90cf9f2SGordon Ross 1202a90cf9f2SGordon Ross return (0); 1203a90cf9f2SGordon Ross } 1204a90cf9f2SGordon Ross 1205a90cf9f2SGordon Ross /* 1206a90cf9f2SGordon Ross * smb2_dispatch_stats_init 1207a90cf9f2SGordon Ross * 1208a90cf9f2SGordon Ross * Initializes dispatch statistics for SMB2. 1209a90cf9f2SGordon Ross * See also smb_dispatch_stats_init(), which fills in 1210a90cf9f2SGordon Ross * the lower part of the statistics array, from zero 1211a90cf9f2SGordon Ross * through SMB_COM_NUM; 1212a90cf9f2SGordon Ross */ 1213a90cf9f2SGordon Ross void 1214a90cf9f2SGordon Ross smb2_dispatch_stats_init(smb_server_t *sv) 1215a90cf9f2SGordon Ross { 1216a90cf9f2SGordon Ross smb_disp_stats_t *sds = sv->sv_disp_stats2; 1217a90cf9f2SGordon Ross smb_kstat_req_t *ksr; 1218a90cf9f2SGordon Ross int i; 1219a90cf9f2SGordon Ross 1220a90cf9f2SGordon Ross ksr = ((smbsrv_kstats_t *)sv->sv_ksp->ks_data)->ks_reqs2; 1221a90cf9f2SGordon Ross 1222a90cf9f2SGordon Ross for (i = 0; i < SMB2__NCMDS; i++, ksr++) { 1223a90cf9f2SGordon Ross smb_latency_init(&sds[i].sdt_lat); 1224a90cf9f2SGordon Ross (void) strlcpy(ksr->kr_name, smb2_disp_table[i].sdt_name, 1225a90cf9f2SGordon Ross sizeof (ksr->kr_name)); 1226a90cf9f2SGordon Ross } 1227a90cf9f2SGordon Ross } 1228a90cf9f2SGordon Ross 1229a90cf9f2SGordon Ross /* 1230a90cf9f2SGordon Ross * smb2_dispatch_stats_fini 1231a90cf9f2SGordon Ross * 1232a90cf9f2SGordon Ross * Frees and destroyes the resources used for statistics. 1233a90cf9f2SGordon Ross */ 1234a90cf9f2SGordon Ross void 1235a90cf9f2SGordon Ross smb2_dispatch_stats_fini(smb_server_t *sv) 1236a90cf9f2SGordon Ross { 1237a90cf9f2SGordon Ross smb_disp_stats_t *sds = sv->sv_disp_stats2; 1238a90cf9f2SGordon Ross int i; 1239a90cf9f2SGordon Ross 1240a90cf9f2SGordon Ross for (i = 0; i < SMB2__NCMDS; i++) 1241a90cf9f2SGordon Ross smb_latency_destroy(&sds[i].sdt_lat); 1242a90cf9f2SGordon Ross } 1243a90cf9f2SGordon Ross 1244a90cf9f2SGordon Ross void 1245a90cf9f2SGordon Ross smb2_dispatch_stats_update(smb_server_t *sv, 1246a90cf9f2SGordon Ross smb_kstat_req_t *ksr, int first, int nreq) 1247a90cf9f2SGordon Ross { 1248a90cf9f2SGordon Ross smb_disp_stats_t *sds = sv->sv_disp_stats2; 1249a90cf9f2SGordon Ross int i; 1250a90cf9f2SGordon Ross int last; 1251a90cf9f2SGordon Ross 1252a90cf9f2SGordon Ross last = first + nreq - 1; 1253a90cf9f2SGordon Ross 1254a90cf9f2SGordon Ross if ((first < SMB2__NCMDS) && (last < SMB2__NCMDS)) { 1255a90cf9f2SGordon Ross for (i = first; i <= last; i++, ksr++) { 1256a90cf9f2SGordon Ross ksr->kr_rxb = sds[i].sdt_rxb; 1257a90cf9f2SGordon Ross ksr->kr_txb = sds[i].sdt_txb; 1258a90cf9f2SGordon Ross mutex_enter(&sds[i].sdt_lat.ly_mutex); 1259a90cf9f2SGordon Ross ksr->kr_nreq = sds[i].sdt_lat.ly_a_nreq; 1260a90cf9f2SGordon Ross ksr->kr_sum = sds[i].sdt_lat.ly_a_sum; 1261a90cf9f2SGordon Ross ksr->kr_a_mean = sds[i].sdt_lat.ly_a_mean; 1262a90cf9f2SGordon Ross ksr->kr_a_stddev = 1263a90cf9f2SGordon Ross sds[i].sdt_lat.ly_a_stddev; 1264a90cf9f2SGordon Ross ksr->kr_d_mean = sds[i].sdt_lat.ly_d_mean; 1265a90cf9f2SGordon Ross ksr->kr_d_stddev = 1266a90cf9f2SGordon Ross sds[i].sdt_lat.ly_d_stddev; 1267a90cf9f2SGordon Ross sds[i].sdt_lat.ly_d_mean = 0; 1268a90cf9f2SGordon Ross sds[i].sdt_lat.ly_d_nreq = 0; 1269a90cf9f2SGordon Ross sds[i].sdt_lat.ly_d_stddev = 0; 1270a90cf9f2SGordon Ross sds[i].sdt_lat.ly_d_sum = 0; 1271a90cf9f2SGordon Ross mutex_exit(&sds[i].sdt_lat.ly_mutex); 1272a90cf9f2SGordon Ross } 1273a90cf9f2SGordon Ross } 1274a90cf9f2SGordon Ross } 1275