Esempio n. 1
0
/*
 * smb_handle_write_raw
 *
 * Called from smb_session_daemon() when the SMB command is SMB_COM_WRITE_RAW.
 * Dispatches the command to the worker thread and waits until the worker
 * has completed processing the command.
 *
 * Returns 0 for success, non-zero for failure
 */
int
smb_handle_write_raw(smb_session_t *session, smb_request_t *sr)
{
	int	drop_reason = 0;

	/*
	 * Set flag to indicate that we are waiting for raw data.  The
	 * worker thread will actually retrieve the raw data directly
	 * from the socket.  This should be the only case when a worker
	 * thread reads from the session socket.  When the data is read
	 * the worker will clear the flag.
	 */
	smb_rwx_rwenter(&session->s_lock, RW_WRITER);
	switch (session->s_state) {
	case SMB_SESSION_STATE_NEGOTIATED:
	case SMB_SESSION_STATE_OPLOCK_BREAKING:
		session->s_state = SMB_SESSION_STATE_WRITE_RAW_ACTIVE;
		smb_rwx_rwexit(&session->s_lock);
		smb_srqueue_waitq_enter(session->s_srqueue);
		sr->sr_state = SMB_REQ_STATE_SUBMITTED;
		(void) taskq_dispatch(session->s_server->sv_worker_pool,
		    smb_session_worker, sr, TQ_SLEEP);
		smb_rwx_rwenter(&session->s_lock, RW_READER);
		while (session->s_state == SMB_SESSION_STATE_WRITE_RAW_ACTIVE) {
			(void) smb_rwx_rwwait(&session->s_lock, -1);
		}
		drop_reason = session->s_write_raw_status;
		break;
	default:
		drop_reason = 21;
		break;
	}
	smb_rwx_rwexit(&session->s_lock);
	return (drop_reason);
}
Esempio n. 2
0
/*
 * This is the SMB2 handler for new smb requests, called from
 * smb_session_reader after SMB negotiate is done.  For most SMB2
 * requests, we just enqueue them for the smb_session_worker to
 * execute via the task queue, so they can block for resources
 * without stopping the reader thread.  A few protocol messages
 * are special cases and are handled directly here in the reader
 * thread so they don't wait for taskq scheduling.
 *
 * This function must either enqueue the new request for
 * execution via the task queue, or execute it directly
 * and then free it.  If this returns non-zero, the caller
 * will drop the session.
 */
int
smb2sr_newrq(smb_request_t *sr)
{
	uint32_t magic;
	uint16_t command;
	int rc;

	magic = LE_IN32(sr->sr_request_buf);
	if (magic != SMB2_PROTOCOL_MAGIC) {
		smb_request_free(sr);
		/* will drop the connection */
		return (EPROTO);
	}

	/*
	 * Execute Cancel requests immediately, (here in the
	 * reader thread) so they won't wait for any other
	 * commands we might already have in the task queue.
	 * Cancel also skips signature verification and
	 * does not consume a sequence number.
	 * [MS-SMB2] 3.2.4.24 Cancellation...
	 */
	command = LE_IN16((uint8_t *)sr->sr_request_buf + 12);
	if (command == SMB2_CANCEL) {
		rc = smb2sr_newrq_cancel(sr);
		smb_request_free(sr);
		return (rc);
	}

	/*
	 * XXX With SMB3 this is supposed to increment based on
	 * the number of credits consumed by a request.  Todo
	 */
	if (sr->session->signing.flags & SMB_SIGNING_ENABLED) {
		/* XXX MS-SMB2 is unclear on this. todo */
		sr->session->signing.seqnum++;
		sr->sr_seqnum = sr->session->signing.seqnum;
		sr->reply_seqnum = sr->sr_seqnum;
	}

	/*
	 * Submit the request to the task queue, which calls
	 * smb2_dispatch_request when the workload permits.
	 */
	sr->sr_time_submitted = gethrtime();
	sr->sr_state = SMB_REQ_STATE_SUBMITTED;
	sr->work_func = smb2sr_work;
	smb_srqueue_waitq_enter(sr->session->s_srqueue);
	(void) taskq_dispatch(sr->session->s_server->sv_worker_pool,
	    smb_session_worker, sr, TQ_SLEEP);

	return (0);

}
/*
 * smb_process_node_notify_change_queue
 *
 * This function searches notify change request queue and sends
 * 'NODE MODIFIED' reply to all requests which are related to a
 * specific node.
 * WatchTree flag: We handle this flag in a special manner just
 * for DAVE clients. When something is changed, we notify all
 * requests which came from DAVE clients on the same volume which
 * has been modified. We don't care about the tree that they wanted
 * us to monitor. any change in any part of the volume will lead
 * to notifying all notify change requests from DAVE clients on the
 * different parts of the volume hierarchy.
 */
void
smb_process_node_notify_change_queue(smb_node_t *node)
{
	smb_request_t	*sr;
	smb_request_t	*tmp;
	smb_node_t	*nc_node;
	boolean_t	sig = B_FALSE;

	ASSERT(node->n_magic == SMB_NODE_MAGIC);

	if (!(node->flags & NODE_FLAGS_NOTIFY_CHANGE))
		return;

	node->flags |= NODE_FLAGS_CHANGED;

	smb_slist_enter(&smb_ncr_list);
	smb_slist_enter(&smb_nce_list);
	sr = smb_slist_head(&smb_ncr_list);
	while (sr) {
		ASSERT(sr->sr_magic == SMB_REQ_MAGIC);
		tmp = smb_slist_next(&smb_ncr_list, sr);

		nc_node = sr->sr_ncr.nc_node;
		if (nc_node == node) {
			mutex_enter(&sr->sr_mutex);
			switch (sr->sr_state) {
			case SMB_REQ_STATE_WAITING_EVENT:
				smb_slist_obj_move(&smb_nce_list,
				    &smb_ncr_list, sr);
				smb_srqueue_waitq_enter(
				    sr->session->s_srqueue);
				sr->sr_state = SMB_REQ_STATE_EVENT_OCCURRED;
				sig = B_TRUE;
				break;
			default:
				ASSERT(0);
				break;
			}
			mutex_exit(&sr->sr_mutex);
		}
		sr = tmp;
	}
	smb_slist_exit(&smb_nce_list);
	smb_slist_exit(&smb_ncr_list);
	if (sig)
		smb_thread_signal(&smb_thread_notify_daemon);
}
/*
 * smb_process_session_notify_change_queue
 *
 * This function traverses notify change request queue and sends
 * cancel replies to all of requests that are related to a specific
 * session.
 */
void
smb_process_session_notify_change_queue(
    smb_session_t	*session,
    smb_tree_t		*tree)
{
	smb_request_t	*sr;
	smb_request_t	*tmp;
	boolean_t	sig = B_FALSE;

	smb_slist_enter(&smb_ncr_list);
	smb_slist_enter(&smb_nce_list);
	sr = smb_slist_head(&smb_ncr_list);
	while (sr) {
		ASSERT(sr->sr_magic == SMB_REQ_MAGIC);
		tmp = smb_slist_next(&smb_ncr_list, sr);
		if ((sr->session == session) &&
		    (tree == NULL || sr->tid_tree == tree)) {
			mutex_enter(&sr->sr_mutex);
			switch (sr->sr_state) {
			case SMB_REQ_STATE_WAITING_EVENT:
				smb_slist_obj_move(
				    &smb_nce_list,
				    &smb_ncr_list,
				    sr);
				smb_srqueue_waitq_enter(
				    sr->session->s_srqueue);
				sr->sr_state = SMB_REQ_STATE_CANCELED;
				sig = B_TRUE;
				break;
			default:
				ASSERT(0);
				break;
			}
			mutex_exit(&sr->sr_mutex);
		}
		sr = tmp;
	}
	smb_slist_exit(&smb_nce_list);
	smb_slist_exit(&smb_ncr_list);
	if (sig)
		smb_thread_signal(&smb_thread_notify_daemon);
}
void
smb_reply_specific_cancel_request(struct smb_request *zsr)
{
	smb_request_t	*sr;
	smb_request_t	*tmp;
	boolean_t	sig = B_FALSE;

	smb_slist_enter(&smb_ncr_list);
	smb_slist_enter(&smb_nce_list);
	sr = smb_slist_head(&smb_ncr_list);
	while (sr) {
		ASSERT(sr->sr_magic == SMB_REQ_MAGIC);
		tmp = smb_slist_next(&smb_ncr_list, sr);
		if ((sr->session == zsr->session) &&
		    (sr->smb_uid == zsr->smb_uid) &&
		    (sr->smb_pid == zsr->smb_pid) &&
		    (sr->smb_tid == zsr->smb_tid) &&
		    (sr->smb_mid == zsr->smb_mid)) {
			mutex_enter(&sr->sr_mutex);
			switch (sr->sr_state) {
			case SMB_REQ_STATE_WAITING_EVENT:
				smb_slist_obj_move(&smb_nce_list,
				    &smb_ncr_list, sr);
				smb_srqueue_waitq_enter(
				    sr->session->s_srqueue);
				sr->sr_state = SMB_REQ_STATE_CANCELED;
				sig = B_TRUE;
				break;
			default:
				ASSERT(0);
				break;
			}
			mutex_exit(&sr->sr_mutex);
		}
		sr = tmp;
	}
	smb_slist_exit(&smb_nce_list);
	smb_slist_exit(&smb_ncr_list);
	if (sig)
		smb_thread_signal(&smb_thread_notify_daemon);
}