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

📄 sock.c

📁 嵌入式系统设计与实例开发实验教材二源码 多线程应用程序设计 串行端口程序设计 AD接口实验 CAN总线通信实验 GPS通信实验 Linux内核移植与编译实验 IC卡读写实验 SD驱动使
💻 C
📖 第 1 页 / 共 2 页
字号:
	memcpy(packet, peek_buf, 4);	result = smb_receive_raw(socket, packet + 4, len);	if (result < 0)	{		VERBOSE("receive error: %d\n", result);		goto out;	}	server->rcls = *(packet + smb_rcls);	server->err  = WVAL(packet, smb_err);#ifdef SMBFS_DEBUG_VERBOSE	if (server->rcls != 0)		VERBOSE("rcls=%d, err=%d\n", server->rcls, server->err);#endifout:	return result;}/* * This routine checks first for "fast track" processing, as most * packets won't need to be copied. Otherwise, it allocates a new * packet to hold the incoming data. * * Note that the final server packet must be the larger of the two; * server packets aren't allowed to shrink. */static intsmb_receive_trans2(struct smb_sb_info *server,		   int *ldata, unsigned char **data,		   int *lparm, unsigned char **parm){	unsigned char *inbuf, *base, *rcv_buf = NULL;	unsigned int parm_disp, parm_offset, parm_count, parm_tot, parm_len = 0;	unsigned int data_disp, data_offset, data_count, data_tot, data_len = 0;	unsigned int total_p = 0, total_d = 0, buf_len = 0;	int result;	while (1) {		result = smb_receive(server);		if (result < 0)			goto out;		inbuf = server->packet;		if (server->rcls != 0) {			*parm = *data = inbuf;			*ldata = *lparm = 0;			goto out;		}		/*		 * Extract the control data from the packet.		 */		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);		base = smb_base(inbuf);		/*		 * Assume success and increment lengths.		 */		parm_len += parm_count;		data_len += data_count;		if (!rcv_buf) {			/*			 * Check for fast track processing ... just this packet.			 */			if (parm_count == parm_tot && data_count == data_tot) {				VERBOSE("fast track, parm=%u %u %u, data=%u %u %u\n",					parm_disp, parm_offset, parm_count,					data_disp, data_offset, data_count);				*parm  = base + parm_offset;				*data  = base + data_offset;				goto success;			}			/*			 * Save the total parameter and data length.			 */			total_d = data_tot;			total_p = parm_tot;			buf_len = total_d + total_p;			if (server->packet_size > buf_len)				buf_len = server->packet_size;			buf_len = smb_round_length(buf_len);			if (buf_len > SMB_MAX_PACKET_SIZE)				goto out_too_long;			rcv_buf = smb_vmalloc(buf_len);			if (!rcv_buf)				goto out_no_mem;			*parm = rcv_buf;			*data = rcv_buf + total_p;		} else if (data_tot > total_d || parm_tot > total_p)			goto out_data_grew;		if (parm_disp + parm_count > total_p)			goto out_bad_parm;		if (data_disp + data_count > total_d)			goto out_bad_data;		memcpy(*parm + parm_disp, base + parm_offset, parm_count);		memcpy(*data + data_disp, base + data_offset, data_count);		PARANOIA("copied, parm=%u of %u, data=%u of %u\n",			 parm_len, parm_tot, data_len, data_tot);		/*		 * Check whether we've received all of the data. Note that		 * we use the packet totals -- total lengths might shrink!		 */		if (data_len >= data_tot && parm_len >= parm_tot)			break;	}	/*	 * Install the new packet.  Note that it's possible, though	 * unlikely, that the new packet could be smaller than the	 * old one, in which case we just copy the data.	 */	inbuf = server->packet;	if (buf_len >= server->packet_size) {		server->packet_size = buf_len;		server->packet = rcv_buf;		rcv_buf = inbuf;	} else {		PARANOIA("copying data, old size=%d, new size=%u\n",			 server->packet_size, buf_len);		memcpy(inbuf, rcv_buf, parm_len + data_len);	}success:	*ldata = data_len;	*lparm = parm_len;out:	if (rcv_buf)		smb_vfree(rcv_buf);	return result;out_no_mem:	PARANOIA("couldn't allocate data area\n");	result = -ENOMEM;	goto out;out_too_long:	printk(KERN_ERR "smb_receive_trans2: data/param too long, data=%d, parm=%d\n",		data_tot, parm_tot);	goto out_error;out_data_grew:	printk(KERN_ERR "smb_receive_trans2: data/params grew!\n");	goto out_error;out_bad_parm:	printk(KERN_ERR "smb_receive_trans2: invalid parms, disp=%d, cnt=%d, tot=%d\n",		parm_disp, parm_count, parm_tot);	goto out_error;out_bad_data:	printk(KERN_ERR "smb_receive_trans2: invalid data, disp=%d, cnt=%d, tot=%d\n",		data_disp, data_count, data_tot);out_error:	result = -EIO;	goto out;}/* * Called with the server locked */intsmb_request(struct smb_sb_info *server){	unsigned long flags, sigpipe;	mm_segment_t fs;	sigset_t old_set;	int len, result;	unsigned char *buffer;	result = -EBADF;	buffer = server->packet;	if (!buffer)		goto bad_no_packet;	result = -EIO;	if (server->state != CONN_VALID)		goto bad_no_conn;	if ((result = smb_dont_catch_keepalive(server)) != 0)		goto bad_conn;	len = smb_len(buffer) + 4;	DEBUG1("len = %d cmd = 0x%X\n", len, buffer[8]);	spin_lock_irqsave(&current->sigmask_lock, flags);	sigpipe = sigismember(&current->pending.signal, SIGPIPE);	old_set = current->blocked;	siginitsetinv(&current->blocked, sigmask(SIGKILL)|sigmask(SIGSTOP));	recalc_sigpending(current);	spin_unlock_irqrestore(&current->sigmask_lock, flags);	fs = get_fs();	set_fs(get_ds());	result = smb_send_raw(server_sock(server), (void *) buffer, len);	if (result > 0)	{		result = smb_receive(server);	}	/* read/write errors are handled by errno */	spin_lock_irqsave(&current->sigmask_lock, flags);	if (result == -EPIPE && !sigpipe)		sigdelset(&current->pending.signal, SIGPIPE);	current->blocked = old_set;	recalc_sigpending(current);	spin_unlock_irqrestore(&current->sigmask_lock, flags);	set_fs(fs);	if (result >= 0)	{		int result2 = smb_catch_keepalive(server);		if (result2 < 0)		{			printk(KERN_ERR "smb_request: catch keepalive failed\n");			result = result2;		}	}	if (result < 0)		goto bad_conn;	/*	 * Check for fatal server errors ...	 */	if (server->rcls) {		int error = smb_errno(server);		if (error == -EBADSLT) {			printk(KERN_ERR "smb_request: tree ID invalid\n");			result = error;			goto bad_conn;		}	}out:	DEBUG1("result = %d\n", result);	return result;	bad_conn:	PARANOIA("result %d, setting invalid\n", result);	server->state = CONN_INVALID;	smb_invalidate_inodes(server);	goto out;		bad_no_packet:	printk(KERN_ERR "smb_request: no packet!\n");	goto out;bad_no_conn:	printk(KERN_ERR "smb_request: connection %d not valid!\n",	       server->state);	goto out;}#define ROUND_UP(x) (((x)+3) & ~3)static intsmb_send_trans2(struct smb_sb_info *server, __u16 trans2_command,		int ldata, unsigned char *data,		int lparam, unsigned char *param){	struct socket *sock = server_sock(server);	struct scm_cookie scm;	int err;	int mparam, mdata;	/* 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 oparam =		ROUND_UP(SMB_HEADER_LEN + 2 * smb_parameters + 2 + 3);	const int odata =		ROUND_UP(oparam + lparam);	const int bcc =		odata + ldata - (SMB_HEADER_LEN + 2 * smb_parameters + 2);	const int packet_length =		SMB_HEADER_LEN + 2 * smb_parameters + bcc + 2;	unsigned char padding[4] =	{0,};	char *p;	struct iovec iov[4];	struct msghdr msg;	/* FIXME! this test needs to include SMB overhead too, I think ... */	if ((bcc + oparam) > server->opt.max_xmit)		return -ENOMEM;	p = smb_setup_header(server, SMBtrans2, smb_parameters, bcc);	/*	 * max parameters + max data + max setup == max_xmit to make NT4 happy	 * and not abort the transfer or split into multiple responses.	 *	 * -100 is to make room for headers, which OS/2 seems to include in the	 * size calculation while NT4 does not?	 */	mparam = SMB_TRANS2_MAX_PARAM;	mdata = server->opt.max_xmit - mparam - 100;	if (mdata < 1024) {		mdata = 1024;		mparam = 20;	}	WSET(server->packet, smb_tpscnt, lparam);	WSET(server->packet, smb_tdscnt, ldata);	WSET(server->packet, smb_mprcnt, mparam);	WSET(server->packet, smb_mdrcnt, mdata);	WSET(server->packet, smb_msrcnt, 0);    /* max setup always 0 ? */	WSET(server->packet, smb_flags, 0);	DSET(server->packet, smb_timeout, 0);	WSET(server->packet, smb_pscnt, lparam);	WSET(server->packet, smb_psoff, oparam - 4);	WSET(server->packet, smb_dscnt, ldata);	WSET(server->packet, smb_dsoff, odata - 4);	WSET(server->packet, smb_suwcnt, 1);	WSET(server->packet, smb_setup0, trans2_command);	*p++ = 0;		/* null smb_name for trans2 */	*p++ = 'D';		/* this was added because OS/2 does it */	*p++ = ' ';	msg.msg_name = NULL;	msg.msg_namelen = 0;	msg.msg_control = NULL;	msg.msg_controllen = 0;	msg.msg_iov = iov;	msg.msg_iovlen = 4;	msg.msg_flags = 0;		iov[0].iov_base = (void *) server->packet;	iov[0].iov_len = oparam;	iov[1].iov_base = (param == NULL) ? padding : param;	iov[1].iov_len = lparam;	iov[2].iov_base = padding;	iov[2].iov_len = odata - oparam - lparam;	iov[3].iov_base = (data == NULL) ? padding : data;	iov[3].iov_len = ldata;	err = scm_send(sock, &msg, &scm);        if (err >= 0) {		err = sock->ops->sendmsg(sock, &msg, packet_length, &scm);		scm_destroy(&scm);	}	return err;}/* * This is not really a trans2 request, we assume that you only have * one packet to send. */intsmb_trans2_request(struct smb_sb_info *server, __u16 trans2_command,		   int ldata, unsigned char *data,		   int lparam, unsigned char *param,		   int *lrdata, unsigned char **rdata,		   int *lrparam, unsigned char **rparam){	sigset_t old_set;	unsigned long flags, sigpipe;	mm_segment_t fs;	int result;	DEBUG1("com=%d, ld=%d, lp=%d\n", trans2_command, ldata, lparam);	/*	 * These are initialized in smb_request_ok, but not here??	 */	server->rcls = 0;	server->err = 0;	result = -EIO;	if (server->state != CONN_VALID)		goto out;	if ((result = smb_dont_catch_keepalive(server)) != 0)		goto bad_conn;	spin_lock_irqsave(&current->sigmask_lock, flags);	sigpipe = sigismember(&current->pending.signal, SIGPIPE);	old_set = current->blocked;	siginitsetinv(&current->blocked, sigmask(SIGKILL)|sigmask(SIGSTOP));	recalc_sigpending(current);	spin_unlock_irqrestore(&current->sigmask_lock, flags);	fs = get_fs();	set_fs(get_ds());	result = smb_send_trans2(server, trans2_command,				 ldata, data, lparam, param);	if (result >= 0)	{		result = smb_receive_trans2(server,					    lrdata, rdata, lrparam, rparam);	}	/* read/write errors are handled by errno */	spin_lock_irqsave(&current->sigmask_lock, flags);	if (result == -EPIPE && !sigpipe)		sigdelset(&current->pending.signal, SIGPIPE);	current->blocked = old_set;	recalc_sigpending(current);	spin_unlock_irqrestore(&current->sigmask_lock, flags);	set_fs(fs);	if (result >= 0)	{		int result2 = smb_catch_keepalive(server);		if (result2 < 0)		{			result = result2;		}	}	if (result < 0)		goto bad_conn;	/*	 * Check for fatal server errors ...	 */	if (server->rcls) {		int error = smb_errno(server);		if (error == -EBADSLT) {			printk(KERN_ERR "smb_request: tree ID invalid\n");			result = error;			goto bad_conn;		}	}out:	return result;bad_conn:	PARANOIA("result=%d, setting invalid\n", result);	server->state = CONN_INVALID;	smb_invalidate_inodes(server);	goto out;}

⌨️ 快捷键说明

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