diff options
Diffstat (limited to 'fs/smbfs/request.c')
| -rw-r--r-- | fs/smbfs/request.c | 818 | 
1 files changed, 0 insertions, 818 deletions
diff --git a/fs/smbfs/request.c b/fs/smbfs/request.c deleted file mode 100644 index 45f45933e862..000000000000 --- a/fs/smbfs/request.c +++ /dev/null @@ -1,818 +0,0 @@ -/* - *  request.c - * - *  Copyright (C) 2001 by Urban Widmark - * - *  Please add a note about your changes to smbfs in the ChangeLog file. - */ - -#include <linux/kernel.h> -#include <linux/types.h> -#include <linux/fs.h> -#include <linux/slab.h> -#include <linux/net.h> -#include <linux/sched.h> - -#include <linux/smb_fs.h> -#include <linux/smbno.h> -#include <linux/smb_mount.h> - -#include "smb_debug.h" -#include "request.h" -#include "proto.h" - -/* #define SMB_SLAB_DEBUG	(SLAB_RED_ZONE | SLAB_POISON) */ -#define SMB_SLAB_DEBUG	0 - -/* cache for request structures */ -static struct kmem_cache *req_cachep; - -static int smb_request_send_req(struct smb_request *req); - -/* -  /proc/slabinfo: -  name, active, num, objsize, active_slabs, num_slaps, #pages -*/ - - -int smb_init_request_cache(void) -{ -	req_cachep = kmem_cache_create("smb_request", -				       sizeof(struct smb_request), 0, -				       SMB_SLAB_DEBUG | SLAB_HWCACHE_ALIGN, -				       NULL); -	if (req_cachep == NULL) -		return -ENOMEM; - -	return 0; -} - -void smb_destroy_request_cache(void) -{ -	kmem_cache_destroy(req_cachep); -} - -/* - * Allocate and initialise a request structure - */ -static struct smb_request *smb_do_alloc_request(struct smb_sb_info *server, -						int bufsize) -{ -	struct smb_request *req; -	unsigned char *buf = NULL; - -	req = kmem_cache_zalloc(req_cachep, GFP_KERNEL); -	VERBOSE("allocating request: %p\n", req); -	if (!req) -		goto out; - -	if (bufsize > 0) { -		buf = kmalloc(bufsize, GFP_NOFS); -		if (!buf) { -			kmem_cache_free(req_cachep, req); -			return NULL; -		} -	} - -	req->rq_buffer = buf; -	req->rq_bufsize = bufsize; -	req->rq_server = server; -	init_waitqueue_head(&req->rq_wait); -	INIT_LIST_HEAD(&req->rq_queue); -	atomic_set(&req->rq_count, 1); - -out: -	return req; -} - -struct smb_request *smb_alloc_request(struct smb_sb_info *server, int bufsize) -{ -	struct smb_request *req = NULL; - -	for (;;) { -		atomic_inc(&server->nr_requests); -		if (atomic_read(&server->nr_requests) <= MAX_REQUEST_HARD) { -			req = smb_do_alloc_request(server, bufsize); -			if (req != NULL) -				break; -		} - -#if 0 -		/* -		 * Try to free up at least one request in order to stay -		 * below the hard limit -		 */ -                if (nfs_try_to_free_pages(server)) -			continue; - -		if (fatal_signal_pending(current)) -			return ERR_PTR(-ERESTARTSYS); -		current->policy = SCHED_YIELD; -		schedule(); -#else -		/* FIXME: we want something like nfs does above, but that -		   requires changes to all callers and can wait. */ -		break; -#endif -	} -	return req; -} - -static void smb_free_request(struct smb_request *req) -{ -	atomic_dec(&req->rq_server->nr_requests); -	if (req->rq_buffer && !(req->rq_flags & SMB_REQ_STATIC)) -		kfree(req->rq_buffer); -	kfree(req->rq_trans2buffer); -	kmem_cache_free(req_cachep, req); -} - -/* - * What prevents a rget to race with a rput? The count must never drop to zero - * while it is in use. Only rput if it is ok that it is free'd. - */ -static void smb_rget(struct smb_request *req) -{ -	atomic_inc(&req->rq_count); -} -void smb_rput(struct smb_request *req) -{ -	if (atomic_dec_and_test(&req->rq_count)) { -		list_del_init(&req->rq_queue); -		smb_free_request(req); -	} -} - -/* setup to receive the data part of the SMB */ -static int smb_setup_bcc(struct smb_request *req) -{ -	int result = 0; -	req->rq_rlen = smb_len(req->rq_header) + 4 - req->rq_bytes_recvd; - -	if (req->rq_rlen > req->rq_bufsize) { -		PARANOIA("Packet too large %d > %d\n", -			 req->rq_rlen, req->rq_bufsize); -		return -ENOBUFS; -	} - -	req->rq_iov[0].iov_base = req->rq_buffer; -	req->rq_iov[0].iov_len  = req->rq_rlen; -	req->rq_iovlen = 1; - -	return result; -} - -/* - * Prepare a "normal" request structure. - */ -static int smb_setup_request(struct smb_request *req) -{ -	int len = smb_len(req->rq_header) + 4; -	req->rq_slen = len; - -	/* if we expect a data part in the reply we set the iov's to read it */ -	if (req->rq_resp_bcc) -		req->rq_setup_read = smb_setup_bcc; - -	/* This tries to support re-using the same request */ -	req->rq_bytes_sent = 0; -	req->rq_rcls = 0; -	req->rq_err = 0; -	req->rq_errno = 0; -	req->rq_fragment = 0; -	kfree(req->rq_trans2buffer); -	req->rq_trans2buffer = NULL; - -	return 0; -} - -/* - * Prepare a transaction2 request structure - */ -static int smb_setup_trans2request(struct smb_request *req) -{ -	struct smb_sb_info *server = req->rq_server; -	int mparam, mdata; -	static unsigned char padding[4]; - -	/* I know the following is very ugly, but I want to build the -	   smb packet as efficiently as possible. */ - -	const int smb_parameters = 15; -	const int header = SMB_HEADER_LEN + 2 * smb_parameters + 2; -	const int oparam = ALIGN(header + 3, sizeof(u32)); -	const int odata  = ALIGN(oparam + req->rq_lparm, sizeof(u32)); -	const int bcc = (req->rq_data ? odata + req->rq_ldata : -					oparam + req->rq_lparm) - header; - -	if ((bcc + oparam) > server->opt.max_xmit) -		return -ENOMEM; -	smb_setup_header(req, SMBtrans2, smb_parameters, bcc); - -	/* -	 * max parameters + max data + max setup == bufsize to make NT4 happy -	 * and not abort the transfer or split into multiple responses. It also -	 * makes smbfs happy as handling packets larger than the buffer size -	 * is extra work. -	 * -	 * OS/2 is probably going to hate me for this ... -	 */ -	mparam = SMB_TRANS2_MAX_PARAM; -	mdata = req->rq_bufsize - mparam; - -	mdata = server->opt.max_xmit - mparam - 100; -	if (mdata < 1024) { -		mdata = 1024; -		mparam = 20; -	} - -#if 0 -	/* NT/win2k has ~4k max_xmit, so with this we request more than it wants -	   to return as one SMB. Useful for testing the fragmented trans2 -	   handling. */ -	mdata = 8192; -#endif - -	WSET(req->rq_header, smb_tpscnt, req->rq_lparm); -	WSET(req->rq_header, smb_tdscnt, req->rq_ldata); -	WSET(req->rq_header, smb_mprcnt, mparam); -	WSET(req->rq_header, smb_mdrcnt, mdata); -	WSET(req->rq_header, smb_msrcnt, 0);    /* max setup always 0 ? */ -	WSET(req->rq_header, smb_flags, 0); -	DSET(req->rq_header, smb_timeout, 0); -	WSET(req->rq_header, smb_pscnt, req->rq_lparm); -	WSET(req->rq_header, smb_psoff, oparam - 4); -	WSET(req->rq_header, smb_dscnt, req->rq_ldata); -	WSET(req->rq_header, smb_dsoff, req->rq_data ? odata - 4 : 0); -	*(req->rq_header + smb_suwcnt) = 0x01;          /* setup count */ -	*(req->rq_header + smb_suwcnt + 1) = 0x00;      /* reserved */ -	WSET(req->rq_header, smb_setup0, req->rq_trans2_command); - -	req->rq_iovlen = 2; -	req->rq_iov[0].iov_base = (void *) req->rq_header; -	req->rq_iov[0].iov_len = oparam; -	req->rq_iov[1].iov_base = (req->rq_parm==NULL) ? padding : req->rq_parm; -	req->rq_iov[1].iov_len = req->rq_lparm; -	req->rq_slen = oparam + req->rq_lparm; - -	if (req->rq_data) { -		req->rq_iovlen += 2; -		req->rq_iov[2].iov_base = padding; -		req->rq_iov[2].iov_len = odata - oparam - req->rq_lparm; -		req->rq_iov[3].iov_base = req->rq_data; -		req->rq_iov[3].iov_len = req->rq_ldata; -		req->rq_slen = odata + req->rq_ldata; -	} - -	/* always a data part for trans2 replies */ -	req->rq_setup_read = smb_setup_bcc; - -	return 0; -} - -/* - * Add a request and tell smbiod to process it - */ -int smb_add_request(struct smb_request *req) -{ -	long timeleft; -	struct smb_sb_info *server = req->rq_server; -	int result = 0; - -	smb_setup_request(req); -	if (req->rq_trans2_command) { -		if (req->rq_buffer == NULL) { -			PARANOIA("trans2 attempted without response buffer!\n"); -			return -EIO; -		} -		result = smb_setup_trans2request(req); -	} -	if (result < 0) -		return result; - -#ifdef SMB_DEBUG_PACKET_SIZE -	add_xmit_stats(req); -#endif - -	/* add 'req' to the queue of requests */ -	if (smb_lock_server_interruptible(server)) -		return -EINTR; - -	/* -	 * Try to send the request as the process. If that fails we queue the -	 * request and let smbiod send it later. -	 */ - -	/* FIXME: each server has a number on the maximum number of parallel -	   requests. 10, 50 or so. We should not allow more requests to be -	   active. */ -	if (server->mid > 0xf000) -		server->mid = 0; -	req->rq_mid = server->mid++; -	WSET(req->rq_header, smb_mid, req->rq_mid); - -	result = 0; -	if (server->state == CONN_VALID) { -		if (list_empty(&server->xmitq)) -			result = smb_request_send_req(req); -		if (result < 0) { -			/* Connection lost? */ -			server->conn_error = result; -			server->state = CONN_INVALID; -		} -	} -	if (result != 1) -		list_add_tail(&req->rq_queue, &server->xmitq); -	smb_rget(req); - -	if (server->state != CONN_VALID) -		smbiod_retry(server); - -	smb_unlock_server(server); - -	smbiod_wake_up(); - -	timeleft = wait_event_interruptible_timeout(req->rq_wait, -				    req->rq_flags & SMB_REQ_RECEIVED, 30*HZ); -	if (!timeleft || signal_pending(current)) { -		/* -		 * On timeout or on interrupt we want to try and remove the -		 * request from the recvq/xmitq. -		 * First check if the request is still part of a queue. (May -		 * have been removed by some error condition) -		 */ -		smb_lock_server(server); -		if (!list_empty(&req->rq_queue)) { -			list_del_init(&req->rq_queue); -			smb_rput(req); -		} -		smb_unlock_server(server); -	} - -	if (!timeleft) { -		PARANOIA("request [%p, mid=%d] timed out!\n", -			 req, req->rq_mid); -		VERBOSE("smb_com:  %02x\n", *(req->rq_header + smb_com)); -		VERBOSE("smb_rcls: %02x\n", *(req->rq_header + smb_rcls)); -		VERBOSE("smb_flg:  %02x\n", *(req->rq_header + smb_flg)); -		VERBOSE("smb_tid:  %04x\n", WVAL(req->rq_header, smb_tid)); -		VERBOSE("smb_pid:  %04x\n", WVAL(req->rq_header, smb_pid)); -		VERBOSE("smb_uid:  %04x\n", WVAL(req->rq_header, smb_uid)); -		VERBOSE("smb_mid:  %04x\n", WVAL(req->rq_header, smb_mid)); -		VERBOSE("smb_wct:  %02x\n", *(req->rq_header + smb_wct)); - -		req->rq_rcls = ERRSRV; -		req->rq_err  = ERRtimeout; - -		/* Just in case it was "stuck" */ -		smbiod_wake_up(); -	} -	VERBOSE("woke up, rcls=%d\n", req->rq_rcls); - -	if (req->rq_rcls != 0) -		req->rq_errno = smb_errno(req); -	if (signal_pending(current)) -		req->rq_errno = -ERESTARTSYS; -	return req->rq_errno; -} - -/* - * Send a request and place it on the recvq if successfully sent. - * Must be called with the server lock held. - */ -static int smb_request_send_req(struct smb_request *req) -{ -	struct smb_sb_info *server = req->rq_server; -	int result; - -	if (req->rq_bytes_sent == 0) { -		WSET(req->rq_header, smb_tid, server->opt.tid); -		WSET(req->rq_header, smb_pid, 1); -		WSET(req->rq_header, smb_uid, server->opt.server_uid); -	} - -	result = smb_send_request(req); -	if (result < 0 && result != -EAGAIN) -		goto out; - -	result = 0; -	if (!(req->rq_flags & SMB_REQ_TRANSMITTED)) -		goto out; - -	list_move_tail(&req->rq_queue, &server->recvq); -	result = 1; -out: -	return result; -} - -/* - * Sends one request for this server. (smbiod) - * Must be called with the server lock held. - * Returns: <0 on error - *           0 if no request could be completely sent - *           1 if all data for one request was sent - */ -int smb_request_send_server(struct smb_sb_info *server) -{ -	struct list_head *head; -	struct smb_request *req; -	int result; - -	if (server->state != CONN_VALID) -		return 0; - -	/* dequeue first request, if any */ -	req = NULL; -	head = server->xmitq.next; -	if (head != &server->xmitq) { -		req = list_entry(head, struct smb_request, rq_queue); -	} -	if (!req) -		return 0; - -	result = smb_request_send_req(req); -	if (result < 0) { -		server->conn_error = result; -		list_move(&req->rq_queue, &server->xmitq); -		result = -EIO; -		goto out; -	} - -out: -	return result; -} - -/* - * Try to find a request matching this "mid". Typically the first entry will - * be the matching one. - */ -static struct smb_request *find_request(struct smb_sb_info *server, int mid) -{ -	struct list_head *tmp; -	struct smb_request *req = NULL; - -	list_for_each(tmp, &server->recvq) { -		req = list_entry(tmp, struct smb_request, rq_queue); -		if (req->rq_mid == mid) { -			break; -		} -		req = NULL; -	} - -	if (!req) { -		VERBOSE("received reply with mid %d but no request!\n", -			WVAL(server->header, smb_mid)); -		server->rstate = SMB_RECV_DROP; -	} - -	return req; -} - -/* - * Called when we have read the smb header and believe this is a response. - */ -static int smb_init_request(struct smb_sb_info *server, struct smb_request *req) -{ -	int hdrlen, wct; - -	memcpy(req->rq_header, server->header, SMB_HEADER_LEN); - -	wct = *(req->rq_header + smb_wct); -	if (wct > 20) {	 -		PARANOIA("wct too large, %d > 20\n", wct); -		server->rstate = SMB_RECV_DROP; -		return 0; -	} - -	req->rq_resp_wct = wct; -	hdrlen = SMB_HEADER_LEN + wct*2 + 2; -	VERBOSE("header length: %d   smb_wct: %2d\n", hdrlen, wct); - -	req->rq_bytes_recvd = SMB_HEADER_LEN; -	req->rq_rlen = hdrlen; -	req->rq_iov[0].iov_base = req->rq_header; -	req->rq_iov[0].iov_len  = hdrlen; -	req->rq_iovlen = 1; -	server->rstate = SMB_RECV_PARAM; - -#ifdef SMB_DEBUG_PACKET_SIZE -	add_recv_stats(smb_len(server->header)); -#endif -	return 0; -} - -/* - * Reads the SMB parameters - */ -static int smb_recv_param(struct smb_sb_info *server, struct smb_request *req) -{ -	int result; - -	result = smb_receive(server, req); -	if (result < 0) -		return result; -	if (req->rq_bytes_recvd < req->rq_rlen) -		return 0; - -	VERBOSE("result: %d   smb_bcc:  %04x\n", result, -		WVAL(req->rq_header, SMB_HEADER_LEN + -		     (*(req->rq_header + smb_wct) * 2))); - -	result = 0; -	req->rq_iov[0].iov_base = NULL; -	req->rq_rlen = 0; -	if (req->rq_callback) -		req->rq_callback(req); -	else if (req->rq_setup_read) -		result = req->rq_setup_read(req); -	if (result < 0) { -		server->rstate = SMB_RECV_DROP; -		return result; -	} - -	server->rstate = req->rq_rlen > 0 ? SMB_RECV_DATA : SMB_RECV_END; - -	req->rq_bytes_recvd = 0;	// recvd out of the iov - -	VERBOSE("rlen: %d\n", req->rq_rlen); -	if (req->rq_rlen < 0) { -		PARANOIA("Parameters read beyond end of packet!\n"); -		server->rstate = SMB_RECV_END; -		return -EIO; -	} -	return 0; -} - -/* - * Reads the SMB data - */ -static int smb_recv_data(struct smb_sb_info *server, struct smb_request *req) -{ -	int result; - -	result = smb_receive(server, req); -	if (result < 0) -		goto out; -	if (req->rq_bytes_recvd < req->rq_rlen) -		goto out; -	server->rstate = SMB_RECV_END; -out: -	VERBOSE("result: %d\n", result); -	return result; -} - -/* - * Receive a transaction2 response - * Return: 0 if the response has been fully read - *         1 if there are further "fragments" to read - *        <0 if there is an error - */ -static int smb_recv_trans2(struct smb_sb_info *server, struct smb_request *req) -{ -	unsigned char *inbuf; -	unsigned int parm_disp, parm_offset, parm_count, parm_tot; -	unsigned int data_disp, data_offset, data_count, data_tot; -	int hdrlen = SMB_HEADER_LEN + req->rq_resp_wct*2 - 2; - -	VERBOSE("handling trans2\n"); - -	inbuf = req->rq_header; -	data_tot    = WVAL(inbuf, smb_tdrcnt); -	parm_tot    = WVAL(inbuf, smb_tprcnt); -	parm_disp   = WVAL(inbuf, smb_prdisp); -	parm_offset = WVAL(inbuf, smb_proff); -	parm_count  = WVAL(inbuf, smb_prcnt); -	data_disp   = WVAL(inbuf, smb_drdisp); -	data_offset = WVAL(inbuf, smb_droff); -	data_count  = WVAL(inbuf, smb_drcnt); - -	/* Modify offset for the split header/buffer we use */ -	if (data_count || data_offset) { -		if (unlikely(data_offset < hdrlen)) -			goto out_bad_data; -		else -			data_offset -= hdrlen; -	} -	if (parm_count || parm_offset) { -		if (unlikely(parm_offset < hdrlen)) -			goto out_bad_parm; -		else -			parm_offset -= hdrlen; -	} - -	if (parm_count == parm_tot && data_count == data_tot) { -		/* -		 * This packet has all the trans2 data. -		 * -		 * We setup the request so that this will be the common -		 * case. It may be a server error to not return a -		 * response that fits. -		 */ -		VERBOSE("single trans2 response  " -			"dcnt=%u, pcnt=%u, doff=%u, poff=%u\n", -			data_count, parm_count, -			data_offset, parm_offset); -		req->rq_ldata = data_count; -		req->rq_lparm = parm_count; -		req->rq_data = req->rq_buffer + data_offset; -		req->rq_parm = req->rq_buffer + parm_offset; -		if (unlikely(parm_offset + parm_count > req->rq_rlen)) -			goto out_bad_parm; -		if (unlikely(data_offset + data_count > req->rq_rlen)) -			goto out_bad_data; -		return 0; -	} - -	VERBOSE("multi trans2 response  " -		"frag=%d, dcnt=%u, pcnt=%u, doff=%u, poff=%u\n", -		req->rq_fragment, -		data_count, parm_count, -		data_offset, parm_offset); - -	if (!req->rq_fragment) { -		int buf_len; - -		/* We got the first trans2 fragment */ -		req->rq_fragment = 1; -		req->rq_total_data = data_tot; -		req->rq_total_parm = parm_tot; -		req->rq_ldata = 0; -		req->rq_lparm = 0; - -		buf_len = data_tot + parm_tot; -		if (buf_len > SMB_MAX_PACKET_SIZE) -			goto out_too_long; - -		req->rq_trans2bufsize = buf_len; -		req->rq_trans2buffer = kzalloc(buf_len, GFP_NOFS); -		if (!req->rq_trans2buffer) -			goto out_no_mem; - -		req->rq_parm = req->rq_trans2buffer; -		req->rq_data = req->rq_trans2buffer + parm_tot; -	} else if (unlikely(req->rq_total_data < data_tot || -			    req->rq_total_parm < parm_tot)) -		goto out_data_grew; - -	if (unlikely(parm_disp + parm_count > req->rq_total_parm || -		     parm_offset + parm_count > req->rq_rlen)) -		goto out_bad_parm; -	if (unlikely(data_disp + data_count > req->rq_total_data || -		     data_offset + data_count > req->rq_rlen)) -		goto out_bad_data; - -	inbuf = req->rq_buffer; -	memcpy(req->rq_parm + parm_disp, inbuf + parm_offset, parm_count); -	memcpy(req->rq_data + data_disp, inbuf + data_offset, data_count); - -	req->rq_ldata += data_count; -	req->rq_lparm += parm_count; - -	/* -	 * Check whether we've received all of the data. Note that -	 * we use the packet totals -- total lengths might shrink! -	 */ -	if (req->rq_ldata >= data_tot && req->rq_lparm >= parm_tot) { -		req->rq_ldata = data_tot; -		req->rq_lparm = parm_tot; -		return 0; -	} -	return 1; - -out_too_long: -	printk(KERN_ERR "smb_trans2: data/param too long, data=%u, parm=%u\n", -		data_tot, parm_tot); -	goto out_EIO; -out_no_mem: -	printk(KERN_ERR "smb_trans2: couldn't allocate data area of %d bytes\n", -	       req->rq_trans2bufsize); -	req->rq_errno = -ENOMEM; -	goto out; -out_data_grew: -	printk(KERN_ERR "smb_trans2: data/params grew!\n"); -	goto out_EIO; -out_bad_parm: -	printk(KERN_ERR "smb_trans2: invalid parms, disp=%u, cnt=%u, tot=%u, ofs=%u\n", -	       parm_disp, parm_count, parm_tot, parm_offset); -	goto out_EIO; -out_bad_data: -	printk(KERN_ERR "smb_trans2: invalid data, disp=%u, cnt=%u, tot=%u, ofs=%u\n", -	       data_disp, data_count, data_tot, data_offset); -out_EIO: -	req->rq_errno = -EIO; -out: -	return req->rq_errno; -} - -/* - * State machine for receiving responses. We handle the fact that we can't - * read the full response in one try by having states telling us how much we - * have read. - * - * Must be called with the server lock held (only called from smbiod). - * - * Return: <0 on error - */ -int smb_request_recv(struct smb_sb_info *server) -{ -	struct smb_request *req = NULL; -	int result = 0; - -	if (smb_recv_available(server) <= 0) -		return 0; - -	VERBOSE("state: %d\n", server->rstate); -	switch (server->rstate) { -	case SMB_RECV_DROP: -		result = smb_receive_drop(server); -		if (result < 0) -			break; -		if (server->rstate == SMB_RECV_DROP) -			break; -		server->rstate = SMB_RECV_START; -		/* fallthrough */ -	case SMB_RECV_START: -		server->smb_read = 0; -		server->rstate = SMB_RECV_HEADER; -		/* fallthrough */ -	case SMB_RECV_HEADER: -		result = smb_receive_header(server); -		if (result < 0) -			break; -		if (server->rstate == SMB_RECV_HEADER) -			break; -		if (! (*(server->header + smb_flg) & SMB_FLAGS_REPLY) ) { -			server->rstate = SMB_RECV_REQUEST; -			break; -		} -		if (server->rstate != SMB_RECV_HCOMPLETE) -			break; -		/* fallthrough */ -	case SMB_RECV_HCOMPLETE: -		req = find_request(server, WVAL(server->header, smb_mid)); -		if (!req) -			break; -		smb_init_request(server, req); -		req->rq_rcls = *(req->rq_header + smb_rcls); -		req->rq_err  = WVAL(req->rq_header, smb_err); -		if (server->rstate != SMB_RECV_PARAM) -			break; -		/* fallthrough */ -	case SMB_RECV_PARAM: -		if (!req) -			req = find_request(server,WVAL(server->header,smb_mid)); -		if (!req) -			break; -		result = smb_recv_param(server, req); -		if (result < 0) -			break; -		if (server->rstate != SMB_RECV_DATA) -			break; -		/* fallthrough */ -	case SMB_RECV_DATA: -		if (!req) -			req = find_request(server,WVAL(server->header,smb_mid)); -		if (!req) -			break; -		result = smb_recv_data(server, req); -		if (result < 0) -			break; -		break; - -		/* We should never be called with any of these states */ -	case SMB_RECV_END: -	case SMB_RECV_REQUEST: -		BUG(); -	} - -	if (result < 0) { -		/* We saw an error */ -		return result; -	} - -	if (server->rstate != SMB_RECV_END) -		return 0; - -	result = 0; -	if (req->rq_trans2_command && req->rq_rcls == SUCCESS) -		result = smb_recv_trans2(server, req); - -	/* -	 * Response completely read. Drop any extra bytes sent by the server. -	 * (Yes, servers sometimes add extra bytes to responses) -	 */ -	VERBOSE("smb_len: %d   smb_read: %d\n", -		server->smb_len, server->smb_read); -	if (server->smb_read < server->smb_len) -		smb_receive_drop(server); - -	server->rstate = SMB_RECV_START; - -	if (!result) { -		list_del_init(&req->rq_queue); -		req->rq_flags |= SMB_REQ_RECEIVED; -		smb_rput(req); -		wake_up_interruptible(&req->rq_wait); -	} -	return 0; -}  | 
