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

📄 cifssmb.c

📁 Linux Kernel 2.6.9 for OMAP1710
💻 C
📖 第 1 页 / 共 5 页
字号:
/* *   fs/cifs/cifssmb.c * *   Copyright (C) International Business Machines  Corp., 2002,2003 *   Author(s): Steve French (sfrench@us.ibm.com) * *   Contains the routines for constructing the SMB PDUs themselves * *   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 */ /* SMB/CIFS PDU handling routines here - except for leftovers in connect.c   */ /* These are mostly routines that operate on a pathname, or on a tree id     */ /* (mounted volume), but there are eight handle based routines which must be */ /* treated slightly different for reconnection purposes since we never want  */ /* to reuse a stale file handle and the caller knows the file handle */#include <linux/fs.h>#include <linux/kernel.h>#include <linux/vfs.h>#include <asm/uaccess.h>#include "cifspdu.h"#include "cifsglob.h"#include "cifsproto.h"#include "cifs_unicode.h"#include "cifs_debug.h"#ifdef CONFIG_CIFS_POSIXstatic struct {	int index;	char *name;} protocols[] = {	{CIFS_PROT, "\2NT LM 0.12"}, 	{CIFS_PROT, "\2POSIX 2"},	{BAD_PROT, "\2"}};#elsestatic struct {	int index;	char *name;} protocols[] = {	{CIFS_PROT, "\2NT LM 0.12"}, 	{BAD_PROT, "\2"}};#endif/* Mark as invalid, all open files on tree connections since they   were closed when session to server was lost */static void mark_open_files_invalid(struct cifsTconInfo * pTcon){	struct cifsFileInfo *open_file = NULL;	struct list_head * tmp;	struct list_head * tmp1;/* list all files open on tree connection and mark them invalid */	write_lock(&GlobalSMBSeslock);	list_for_each_safe(tmp, tmp1, &pTcon->openFileList) {		open_file = list_entry(tmp,struct cifsFileInfo, tlist);		if(open_file) {			open_file->invalidHandle = TRUE;		}	}	write_unlock(&GlobalSMBSeslock);	/* BB Add call to invalidate_inodes(sb) for all superblocks mounted to this tcon */}static intsmb_init(int smb_command, int wct, struct cifsTconInfo *tcon,	 void **request_buf /* returned */ ,	 void **response_buf /* returned */ ){	int rc = 0;	/* SMBs NegProt, SessSetup, uLogoff do not have tcon yet so	   check for tcp and smb session status done differently	   for those three - in the calling routine */	if(tcon) {		if((tcon->ses) && (tcon->ses->server)){			struct nls_table *nls_codepage;				/* Give Demultiplex thread up to 10 seconds to 					reconnect, should be greater than cifs socket					timeout which is 7 seconds */			while(tcon->ses->server->tcpStatus == CifsNeedReconnect) {				wait_event_interruptible_timeout(tcon->ses->server->response_q,					(tcon->ses->server->tcpStatus == CifsGood), 10 * HZ);				if(tcon->ses->server->tcpStatus == CifsNeedReconnect) {					/* on "soft" mounts we wait once */					if((tcon->retry == FALSE) || 					   (tcon->ses->status == CifsExiting)) {						cFYI(1,("gave up waiting on reconnect in smb_init"));						return -EHOSTDOWN;					} /* else "hard" mount - keep retrying until 					process is killed or server comes back up */				} else /* TCP session is reestablished now */					break;				 			}						nls_codepage = load_nls_default();		/* need to prevent multiple threads trying to		simultaneously reconnect the same SMB session */			down(&tcon->ses->sesSem);			if(tcon->ses->status == CifsNeedReconnect)				rc = cifs_setup_session(0, tcon->ses, nls_codepage);			if(!rc && (tcon->tidStatus == CifsNeedReconnect)) {				mark_open_files_invalid(tcon);				rc = CIFSTCon(0, tcon->ses, tcon->treeName, tcon,					nls_codepage);				up(&tcon->ses->sesSem);				if(rc == 0)					atomic_inc(&tconInfoReconnectCount);				cFYI(1, ("reconnect tcon rc = %d", rc));				/* Removed call to reopen open files here - 					it is safer (and faster) to reopen files					one at a time as needed in read and write */				/* Check if handle based operation so we 					know whether we can continue or not without					returning to caller to reset file handle */				switch(smb_command) {					case SMB_COM_READ_ANDX:					case SMB_COM_WRITE_ANDX:					case SMB_COM_CLOSE:					case SMB_COM_FIND_CLOSE2:					case SMB_COM_LOCKING_ANDX: {						unload_nls(nls_codepage);						return -EAGAIN;					}				}			} else {				up(&tcon->ses->sesSem);			}			unload_nls(nls_codepage);		} else {			return -EIO;		}	}	if(rc)		return rc;	*request_buf = cifs_buf_get();	if (*request_buf == 0) {		/* BB should we add a retry in here if not a writepage? */		return -ENOMEM;	}    /* Although the original thought was we needed the response buf for  */    /* potential retries of smb operations it turns out we can determine */    /* from the mid flags when the request buffer can be resent without  */    /* having to use a second distinct buffer for the response */	*response_buf = *request_buf; 	header_assemble((struct smb_hdr *) *request_buf, smb_command, tcon,			wct /*wct */ );#ifdef CONFIG_CIFS_STATS        if(tcon != NULL) {                atomic_inc(&tcon->num_smbs_sent);        }#endif	return rc;}intCIFSSMBNegotiate(unsigned int xid, struct cifsSesInfo *ses){	NEGOTIATE_REQ *pSMB;	NEGOTIATE_RSP *pSMBr;	int rc = 0;	int bytes_returned;	struct TCP_Server_Info * server;	u16 count;	if(ses->server)		server = ses->server;	else {		rc = -EIO;		return rc;	}	rc = smb_init(SMB_COM_NEGOTIATE, 0, NULL /* no tcon yet */ ,		      (void **) &pSMB, (void **) &pSMBr);	if (rc)		return rc;	pSMB->hdr.Flags2 |= SMBFLG2_UNICODE;	if (extended_security)		pSMB->hdr.Flags2 |= SMBFLG2_EXT_SEC;	count = strlen(protocols[0].name) + 1;	strncpy(pSMB->DialectsArray, protocols[0].name, 30);	    /* null guaranteed to be at end of source and target buffers anyway */	pSMB->hdr.smb_buf_length += count;	pSMB->ByteCount = cpu_to_le16(count);	rc = SendReceive(xid, ses, (struct smb_hdr *) pSMB,			 (struct smb_hdr *) pSMBr, &bytes_returned, 0);	if (rc == 0) {		server->secMode = pSMBr->SecurityMode;			server->secType = NTLM; /* BB override default for NTLMv2 or krb*/		/* one byte - no need to convert this or EncryptionKeyLen from le,*/		server->maxReq = le16_to_cpu(pSMBr->MaxMpxCount);		/* probably no need to store and check maxvcs */		server->maxBuf =			min(le32_to_cpu(pSMBr->MaxBufferSize),			(__u32) CIFS_MAX_MSGSIZE + MAX_CIFS_HDR_SIZE);		server->maxRw = le32_to_cpu(pSMBr->MaxRawSize);		cFYI(0, ("Max buf = %d ", ses->server->maxBuf));		GETU32(ses->server->sessid) = le32_to_cpu(pSMBr->SessionKey);		server->capabilities = le32_to_cpu(pSMBr->Capabilities);		server->timeZone = le16_to_cpu(pSMBr->ServerTimeZone);	        /* BB with UTC do we ever need to be using srvr timezone? */		if (pSMBr->EncryptionKeyLength == CIFS_CRYPTO_KEY_SIZE) {			memcpy(server->cryptKey, pSMBr->u.EncryptionKey,			       CIFS_CRYPTO_KEY_SIZE);		} else if ((pSMBr->hdr.Flags2 & SMBFLG2_EXT_SEC)			   && (pSMBr->EncryptionKeyLength == 0)) {			/* decode security blob */		} else			rc = -EIO;		/* BB might be helpful to save off the domain of server here */		if ((pSMBr->hdr.Flags2 & SMBFLG2_EXT_SEC) && 			(server->capabilities & CAP_EXTENDED_SECURITY)) {			count = pSMBr->ByteCount;			if (count < 16)				rc = -EIO;			else if (count == 16) {				server->secType = RawNTLMSSP;				if (server->socketUseCount.counter > 1) {					if (memcmp						(server->server_GUID,						pSMBr->u.extended_response.						GUID, 16) != 0) {						cFYI(1,							("UID of server does not match previous connection to same ip address"));						memcpy(server->							server_GUID,							pSMBr->u.							extended_response.							GUID, 16);					}				} else					memcpy(server->server_GUID,					       pSMBr->u.extended_response.					       GUID, 16);			} else {				rc = decode_negTokenInit(pSMBr->u.							 extended_response.							 SecurityBlob,							 count - 16,							 &server->secType);			}		} else			server->capabilities &= ~CAP_EXTENDED_SECURITY;		if(sign_CIFS_PDUs == FALSE) {        			if(server->secMode & SECMODE_SIGN_REQUIRED)				cERROR(1,				 ("Server requires /proc/fs/cifs/PacketSigningEnabled"));			server->secMode &= ~(SECMODE_SIGN_ENABLED | SECMODE_SIGN_REQUIRED);		} else if(sign_CIFS_PDUs == 1) {			if((server->secMode & SECMODE_SIGN_REQUIRED) == 0)				server->secMode &= ~(SECMODE_SIGN_ENABLED | SECMODE_SIGN_REQUIRED);		}					}	if (pSMB)		cifs_buf_release(pSMB);	return rc;}intCIFSSMBTDis(const int xid, struct cifsTconInfo *tcon){	struct smb_hdr *smb_buffer;	struct smb_hdr *smb_buffer_response;	int rc = 0;	int length;	cFYI(1, ("In tree disconnect"));	/*	 *  If last user of the connection and	 *  connection alive - disconnect it	 *  If this is the last connection on the server session disconnect it	 *  (and inside session disconnect we should check if tcp socket needs 	 *  to be freed and kernel thread woken up).	 */	if (tcon)		down(&tcon->tconSem);	else		return -EIO;	atomic_dec(&tcon->useCount);	if (atomic_read(&tcon->useCount) > 0) {		up(&tcon->tconSem);		return -EBUSY;	}	/* No need to return error on this operation if tid invalidated and 	closed on server already e.g. due to tcp session crashing */	if(tcon->tidStatus == CifsNeedReconnect) {		up(&tcon->tconSem);		return 0;  	}	if((tcon->ses == 0) || (tcon->ses->server == 0)) {    		up(&tcon->tconSem);		return -EIO;	}	rc = smb_init(SMB_COM_TREE_DISCONNECT, 0, tcon,		      (void **) &smb_buffer, (void **) &smb_buffer_response);	if (rc) {		up(&tcon->tconSem);		return rc;	}	rc = SendReceive(xid, tcon->ses, smb_buffer, smb_buffer_response,			 &length, 0);	if (rc)		cFYI(1, (" Tree disconnect failed %d", rc));	if (smb_buffer)		cifs_buf_release(smb_buffer);	up(&tcon->tconSem);	/* No need to return error on this operation if tid invalidated and 	closed on server already e.g. due to tcp session crashing */	if (rc == -EAGAIN)		rc = 0;	return rc;}intCIFSSMBLogoff(const int xid, struct cifsSesInfo *ses){	struct smb_hdr *smb_buffer_response;	LOGOFF_ANDX_REQ *pSMB;	int rc = 0;	int length;	cFYI(1, ("In SMBLogoff for session disconnect"));	if (ses)		down(&ses->sesSem);	else		return -EIO;	atomic_dec(&ses->inUse);	if (atomic_read(&ses->inUse) > 0) {		up(&ses->sesSem);		return -EBUSY;	}	rc = smb_init(SMB_COM_LOGOFF_ANDX, 2, NULL /* no tcon anymore */,		 (void **) &pSMB, (void **) &smb_buffer_response);		if(ses->server) {		if(ses->server->secMode & 		   (SECMODE_SIGN_REQUIRED | SECMODE_SIGN_ENABLED))			pSMB->hdr.Flags2 |= SMBFLG2_SECURITY_SIGNATURE;	}	if (rc) {		up(&ses->sesSem);		return rc;	}	pSMB->hdr.Uid = ses->Suid;	pSMB->AndXCommand = 0xFF;	rc = SendReceive(xid, ses, (struct smb_hdr *) pSMB,			 smb_buffer_response, &length, 0);	if (ses->server) {		atomic_dec(&ses->server->socketUseCount);		if (atomic_read(&ses->server->socketUseCount) == 0) {			spin_lock(&GlobalMid_Lock);			ses->server->tcpStatus = CifsExiting;			spin_unlock(&GlobalMid_Lock);			rc = -ESHUTDOWN;		}	}	if (pSMB)		cifs_buf_release(pSMB);	up(&ses->sesSem);	/* if session dead then we do not need to do ulogoff,		since server closed smb session, no sense reporting 		error */	if (rc == -EAGAIN)		rc = 0;	return rc;}intCIFSSMBDelFile(const int xid, struct cifsTconInfo *tcon,	       const char *fileName, const struct nls_table *nls_codepage){	DELETE_FILE_REQ *pSMB = NULL;	DELETE_FILE_RSP *pSMBr = NULL;	int rc = 0;	int bytes_returned;	int name_len;DelFileRetry:	rc = smb_init(SMB_COM_DELETE, 1, tcon, (void **) &pSMB,		      (void **) &pSMBr);	if (rc)		return rc;	if (pSMB->hdr.Flags2 & SMBFLG2_UNICODE) {		name_len =		    cifs_strtoUCS((wchar_t *) pSMB->fileName, fileName, 530				  /* find define for this maxpathcomponent */				  , nls_codepage);		name_len++;	/* trailing null */		name_len *= 2;

⌨️ 快捷键说明

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