⭐ 欢迎来到虫虫下载站! | 📦 资源下载 📁 资源专辑 ℹ️ 关于我们
⭐ 虫虫下载站

📄 request.c

📁 linux 内核源代码
💻 C
📖 第 1 页 / 共 2 页
字号:
 * 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;}

⌨️ 快捷键说明

复制代码 Ctrl + C
搜索代码 Ctrl + F
全屏模式 F11
切换主题 Ctrl + Shift + D
显示快捷键 ?
增大字号 Ctrl + =
减小字号 Ctrl + -