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

📄 connect.c

📁 Linux内核自带的cifs模块
💻 C
📖 第 1 页 / 共 5 页
字号:
/* *   fs/cifs/connect.c * *   Copyright (C) International Business Machines  Corp., 2002,2007 *   Author(s): Steve French (sfrench@us.ibm.com) * *   This library is free software; you can redistribute it and/or modify *   it under the terms of the GNU Lesser General Public License as published *   by the Free Software Foundation; either version 2.1 of the License, or *   (at your option) any later version. * *   This library is distributed in the hope that it will be useful, *   but WITHOUT ANY WARRANTY; without even the implied warranty of *   MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See *   the GNU Lesser General Public License for more details. * *   You should have received a copy of the GNU Lesser General Public License *   along with this library; if not, write to the Free Software *   Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA */#include <linux/fs.h>#include <linux/net.h>#include <linux/string.h>#include <linux/list.h>#include <linux/wait.h>#include <linux/ipv6.h>#include <linux/pagemap.h>#include <linux/ctype.h>#include <linux/utsname.h>#include <linux/delay.h>#include <linux/completion.h>#include <linux/version.h>#if LINUX_VERSION_CODE > KERNEL_VERSION(2, 5, 0)#include <linux/mempool.h>#include <linux/pagevec.h>#if LINUX_VERSION_CODE > KERNEL_VERSION(2,6,19)#include <linux/freezer.h>#endif /* 2.6.19 */#endif#include <linux/kthread.h>#include <asm/uaccess.h>#include <asm/processor.h>#include "cifspdu.h"#include "cifsglob.h"#include "cifsproto.h"#include "cifs_unicode.h"#include "cifs_debug.h"#include "cifs_fs_sb.h"#include "ntlmssp.h"#include "nterr.h"#include "rfc1002pdu.h"#include "cn_cifs.h"#define CIFS_PORT 445#define RFC1001_PORT 139#if LINUX_VERSION_CODE < KERNEL_VERSION(2, 6, 7)#define sock_create_kern sock_create#endifstatic DECLARE_COMPLETION(cifsd_complete);extern void SMBNTencrypt(unsigned char *passwd, unsigned char *c8,			 unsigned char *p24);#if LINUX_VERSION_CODE > KERNEL_VERSION(2, 5, 0)extern mempool_t *cifs_req_poolp;#else /* old 2.4 kernel */#ifndef PAGEVEC_SIZE#define PAGEVEC_SIZE 14#endif#endifstruct smb_vol {	char *username;	char *password;	char *domainname;	char *UNC;	char *UNCip;	char *in6_addr;  /* ipv6 address as human readable form of in6_addr */	char *iocharset;  /* local code page for mapping to and from Unicode */	char source_rfc1001_name[16]; /* netbios name of client */	char target_rfc1001_name[16]; /* netbios name of server for Win9x/ME */	uid_t linux_uid;	gid_t linux_gid;	mode_t file_mode;	mode_t dir_mode;	unsigned secFlg;	unsigned rw:1;	unsigned retry:1;	unsigned intr:1;	unsigned setuids:1;	unsigned override_uid:1;	unsigned override_gid:1;	unsigned noperm:1;	unsigned no_psx_acl:1; /* set if posix acl support should be disabled */	unsigned cifs_acl:1;	unsigned no_xattr:1;   /* set if xattr (EA) support should be disabled*/	unsigned server_ino:1; /* use inode numbers from server ie UniqueId */	unsigned direct_io:1;	unsigned remap:1;   /* set to remap seven reserved chars in filenames */	unsigned posix_paths:1;   /* unset to not ask for posix pathnames. */	unsigned no_linux_ext:1;	unsigned sfu_emul:1;	unsigned nullauth:1; /* attempt to authenticate with null user */	unsigned nocase;     /* request case insensitive filenames */	unsigned nobrl;      /* disable sending byte range locks to srv */	unsigned int rsize;	unsigned int wsize;	unsigned int sockopt;	unsigned short int port;	char *prepath;};static int ipv4_connect(struct sockaddr_in *psin_server,			struct socket **csocket,			char *netb_name,			char *server_netb_name);static int ipv6_connect(struct sockaddr_in6 *psin_server,			struct socket **csocket);	/*	 * cifs tcp session reconnection	 *	 * mark tcp session as reconnecting so temporarily locked	 * mark all smb sessions as reconnecting for tcp session	 * reconnect tcp session	 * wake up waiters on reconnection? - (not needed currently)	 */static intcifs_reconnect(struct TCP_Server_Info *server){	int rc = 0;	struct list_head *tmp;	struct cifsSesInfo *ses;	struct cifsTconInfo *tcon;	struct mid_q_entry *mid_entry;	spin_lock(&GlobalMid_Lock);	if (kthread_should_stop()) {		/* the demux thread will exit normally		next time through the loop */		spin_unlock(&GlobalMid_Lock);		return rc;	} else		server->tcpStatus = CifsNeedReconnect;	spin_unlock(&GlobalMid_Lock);	server->maxBuf = 0;	cFYI(1, ("Reconnecting tcp session"));	/* before reconnecting the tcp session, mark the smb session (uid)		and the tid bad so they are not used until reconnected */	read_lock(&GlobalSMBSeslock);	list_for_each(tmp, &GlobalSMBSessionList) {		ses = list_entry(tmp, struct cifsSesInfo, cifsSessionList);		if (ses->server) {			if (ses->server == server) {				ses->status = CifsNeedReconnect;				ses->ipc_tid = 0;			}		}		/* else tcp and smb sessions need reconnection */	}	list_for_each(tmp, &GlobalTreeConnectionList) {		tcon = list_entry(tmp, struct cifsTconInfo, cifsConnectionList);		if ((tcon) && (tcon->ses) && (tcon->ses->server == server))			tcon->tidStatus = CifsNeedReconnect;	}	read_unlock(&GlobalSMBSeslock);	/* do not want to be sending data on a socket we are freeing */	down(&server->tcpSem);	if (server->ssocket) {		cFYI(1, ("State: 0x%x Flags: 0x%lx", server->ssocket->state,			server->ssocket->flags));		server->ssocket->ops->shutdown(server->ssocket, SEND_SHUTDOWN);		cFYI(1, ("Post shutdown state: 0x%x Flags: 0x%lx",			server->ssocket->state,			server->ssocket->flags));		sock_release(server->ssocket);		server->ssocket = NULL;	}	spin_lock(&GlobalMid_Lock);	list_for_each(tmp, &server->pending_mid_q) {		mid_entry = list_entry(tmp, struct					mid_q_entry,					qhead);		if (mid_entry) {			if (mid_entry->midState == MID_REQUEST_SUBMITTED) {				/* Mark other intransit requests as needing				   retry so we do not immediately mark the				   session bad again (ie after we reconnect				   below) as they timeout too */				mid_entry->midState = MID_RETRY_NEEDED;			}		}	}	spin_unlock(&GlobalMid_Lock);	up(&server->tcpSem);	while ((!kthread_should_stop()) && (server->tcpStatus != CifsGood)) {#if LINUX_VERSION_CODE > KERNEL_VERSION(2, 6, 12)		try_to_freeze();#endif		if (server->protocolType == IPV6) {			rc = ipv6_connect(&server->addr.sockAddr6,					  &server->ssocket);		} else {			rc = ipv4_connect(&server->addr.sockAddr,					&server->ssocket,					server->workstation_RFC1001_name,					server->server_RFC1001_name);		}		if (rc) {			cFYI(1, ("reconnect error %d", rc));			msleep(3000);		} else {			atomic_inc(&tcpSesReconnectCount);			spin_lock(&GlobalMid_Lock);			if (!kthread_should_stop())				server->tcpStatus = CifsGood;			server->sequence_number = 0;			spin_unlock(&GlobalMid_Lock);	/*		atomic_set(&server->inFlight,0);*/			wake_up(&server->response_q);		}	}	return rc;}/*	return codes:		0 	not a transact2, or all data present		>0 	transact2 with that much data missing		-EINVAL = invalid transact2 */static int check2ndT2(struct smb_hdr *pSMB, unsigned int maxBufSize){	struct smb_t2_rsp *pSMBt;	int total_data_size;	int data_in_this_rsp;	int remaining;	if (pSMB->Command != SMB_COM_TRANSACTION2)		return 0;	/* check for plausible wct, bcc and t2 data and parm sizes */	/* check for parm and data offset going beyond end of smb */	if (pSMB->WordCount != 10) { /* coalesce_t2 depends on this */		cFYI(1, ("invalid transact2 word count"));		return -EINVAL;	}	pSMBt = (struct smb_t2_rsp *)pSMB;	total_data_size = le16_to_cpu(pSMBt->t2_rsp.TotalDataCount);	data_in_this_rsp = le16_to_cpu(pSMBt->t2_rsp.DataCount);	remaining = total_data_size - data_in_this_rsp;	if (remaining == 0)		return 0;	else if (remaining < 0) {		cFYI(1, ("total data %d smaller than data in frame %d",			total_data_size, data_in_this_rsp));		return -EINVAL;	} else {		cFYI(1, ("missing %d bytes from transact2, check next response",			remaining));		if (total_data_size > maxBufSize) {			cERROR(1, ("TotalDataSize %d is over maximum buffer %d",				total_data_size, maxBufSize));			return -EINVAL;		}		return remaining;	}}static int coalesce_t2(struct smb_hdr *psecond, struct smb_hdr *pTargetSMB){	struct smb_t2_rsp *pSMB2 = (struct smb_t2_rsp *)psecond;	struct smb_t2_rsp *pSMBt  = (struct smb_t2_rsp *)pTargetSMB;	int total_data_size;	int total_in_buf;	int remaining;	int total_in_buf2;	char *data_area_of_target;	char *data_area_of_buf2;	__u16 byte_count;	total_data_size = le16_to_cpu(pSMBt->t2_rsp.TotalDataCount);	if (total_data_size != le16_to_cpu(pSMB2->t2_rsp.TotalDataCount)) {		cFYI(1, ("total data size of primary and secondary t2 differ"));	}	total_in_buf = le16_to_cpu(pSMBt->t2_rsp.DataCount);	remaining = total_data_size - total_in_buf;	if (remaining < 0)		return -EINVAL;	if (remaining == 0) /* nothing to do, ignore */		return 0;	total_in_buf2 = le16_to_cpu(pSMB2->t2_rsp.DataCount);	if (remaining < total_in_buf2) {		cFYI(1, ("transact2 2nd response contains too much data"));	}	/* find end of first SMB data area */	data_area_of_target = (char *)&pSMBt->hdr.Protocol +				le16_to_cpu(pSMBt->t2_rsp.DataOffset);	/* validate target area */	data_area_of_buf2 = (char *) &pSMB2->hdr.Protocol +					le16_to_cpu(pSMB2->t2_rsp.DataOffset);	data_area_of_target += total_in_buf;	/* copy second buffer into end of first buffer */	memcpy(data_area_of_target, data_area_of_buf2, total_in_buf2);	total_in_buf += total_in_buf2;	pSMBt->t2_rsp.DataCount = cpu_to_le16(total_in_buf);	byte_count = le16_to_cpu(BCC_LE(pTargetSMB));	byte_count += total_in_buf2;	BCC_LE(pTargetSMB) = cpu_to_le16(byte_count);	byte_count = pTargetSMB->smb_buf_length;	byte_count += total_in_buf2;	/* BB also add check that we are not beyond maximum buffer size */	pTargetSMB->smb_buf_length = byte_count;	if (remaining == total_in_buf2) {		cFYI(1, ("found the last secondary response"));		return 0; /* we are done */	} else /* more responses to go */		return 1;}static intcifs_demultiplex_thread(struct TCP_Server_Info *server){	int length;	unsigned int pdu_length, total_read;	struct smb_hdr *smb_buffer = NULL;	struct smb_hdr *bigbuf = NULL;	struct smb_hdr *smallbuf = NULL;	struct msghdr smb_msg;	struct kvec iov;	struct socket *csocket = server->ssocket;	struct list_head *tmp;	struct cifsSesInfo *ses;	struct task_struct *task_to_wake = NULL;	struct mid_q_entry *mid_entry;	char temp;	int isLargeBuf = FALSE;	int isMultiRsp;	int reconnect;#if LINUX_VERSION_CODE < KERNEL_VERSION(2, 6, 8)	mm_segment_t temp_fs;#endif#if LINUX_VERSION_CODE < KERNEL_VERSION(2, 5, 0)	daemonize();	sprintf(current->comm,"cifsd");#endif	current->flags |= PF_MEMALLOC;	server->tsk = current;	/* save process info to wake at shutdown */	cFYI(1, ("Demultiplex PID: %d", current->pid));	write_lock(&GlobalSMBSeslock);	atomic_inc(&tcpSesAllocCount);	length = tcpSesAllocCount.counter;	write_unlock(&GlobalSMBSeslock);	complete(&cifsd_complete);#if LINUX_VERSION_CODE > KERNEL_VERSION(2, 6, 10)	if (length  > 1)		mempool_resize(cifs_req_poolp, length + cifs_min_rcv,				GFP_KERNEL);#endif#if LINUX_VERSION_CODE < KERNEL_VERSION(2, 6, 8)	temp_fs = get_fs();	/* we must turn off socket api parm checking */	set_fs(get_ds());#elif LINUX_VERSION_CODE > KERNEL_VERSION(2, 6, 22)	set_freezable();#endif	while (!kthread_should_stop()) {#if LINUX_VERSION_CODE > KERNEL_VERSION(2, 6, 12)		if (try_to_freeze())			continue;#endif		if (bigbuf == NULL) {			bigbuf = cifs_buf_get();			if (!bigbuf) {				cERROR(1, ("No memory for large SMB response"));				msleep(3000);				/* retry will check if exiting */				continue;			}		} else if (isLargeBuf) {			/* we are reusing a dirty large buf, clear its start */			memset(bigbuf, 0, sizeof(struct smb_hdr));		}		if (smallbuf == NULL) {			smallbuf = cifs_small_buf_get();			if (!smallbuf) {				cERROR(1, ("No memory for SMB response"));				msleep(1000);				/* retry will check if exiting */				continue;			}			/* beginning of smb buffer is cleared in our buf_get */		} else /* if existing small buf clear beginning */			memset(smallbuf, 0, sizeof(struct smb_hdr));		isLargeBuf = FALSE;		isMultiRsp = FALSE;		smb_buffer = smallbuf;		iov.iov_base = smb_buffer;		iov.iov_len = 4;		smb_msg.msg_control = NULL;

⌨️ 快捷键说明

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