diff mbox

[2/3] SMBTrans functions for Named Pipes

Message ID 4a4634330910151041i33a3036ft8d7f729b5ec77618@mail.gmail.com
State New
Headers show

Commit Message

Shirish Pargaonkar Oct. 15, 2009, 5:41 p.m. UTC
SMB Trans commands (except WaitNamedPipe)

From d11c8d19f9e1bf5d3ed615a38ce99e97dfe0b7dd Mon Sep 17 00:00:00 2001
From: Shirish Pargaonkar <shirishpargaonkar@gmail.com>
Date: Thu, 15 Oct 2009 08:16:26 -0500
Subject: [PATCH] SMB Trans functions for Named Pipe support

---
 fs/cifs/cifssmb.c |  488 +++++++++++++++++++++++++++++++++++++++++++++++++++++
 1 files changed, 488 insertions(+), 0 deletions(-)
diff mbox

Patch

diff --git a/fs/cifs/cifssmb.c b/fs/cifs/cifssmb.c
index 941441d..9d6b77b 100644
--- a/fs/cifs/cifssmb.c
+++ b/fs/cifs/cifssmb.c
@@ -5675,4 +5675,492 @@  SetEARetry:
 	return rc;
 }

+int
+CIFSSMBTransQNmPipe(const int xid, struct cifsTconInfo *tcon,
+		unsigned long arg, __u16 netfid,
+		const struct nls_table *nls_codepage, int remap)
+{
+	TRANS_REQ *pSMB = NULL;
+	TRANS_RSP *pSMBr = NULL;
+	int rc = 0;
+	int name_len, param_len;
+	int pad;
+	int bytes_returned = 0;
+	__u16 offset;
+	__u16 byte_count = 0;
+	char *fileName = "\\PIPE\\";
+	char *bcc_ptr;
+	struct qnmp_info qnmpipeinfo;
+
+	cFYI(1, ("In CIFSSMBTransQNmPipe"));
+qnmpiperetry:
+	rc = smb_init(SMB_COM_TRANSACTION, 16, tcon, (void **) &pSMB,
+		      (void **) &pSMBr);
+	if (rc)
+		return rc;
+
+	offset = offsetof(TRANS_REQ, Name) - 4;
+	pad = offset % 4;
+	if (pad)
+		offset += pad;
+	bcc_ptr = (char *)pSMB + offset + 4;
+	if (pSMB->hdr.Flags2 & SMBFLG2_UNICODE) {
+		name_len =
+		    cifsConvertToUCS((__le16 *) bcc_ptr, fileName,
+				     PATH_MAX, nls_codepage, remap);
+		name_len++;	/* trailing null */
+		name_len *= 2;
+	} else {	/* BB improve the check for buffer overruns BB */
+		name_len = strnlen(fileName, PATH_MAX);
+		name_len++;	/* trailing null */
+		strncpy(bcc_ptr, fileName, name_len);
+	}
+	byte_count += (1 + pad + name_len);
+
+	offset += name_len;
+	pad = offset % 4;
+	if (pad)
+		offset += pad;
+	pSMB->ParameterCount = 2;
+	pSMB->TotalParameterCount = 2;
+	pSMB->ParameterOffset = offset;
+	bcc_ptr = (char *)pSMB + offset + 4;
+	*bcc_ptr++ = 0x1;
+	*bcc_ptr = 0x0;
+	param_len = 2;
+	byte_count += (pad + param_len);
+
+	offset += param_len;
+	pad = offset % 4;
+	if (pad)
+		offset += pad;
+	pSMB->DataOffset = 0;
+	pSMB->DataCount = 0;
+	pSMB->TotalDataCount = 0;
+
+	pSMB->MaxParameterCount = 0;
+	/* BB find max SMB PDU from sess */
+	pSMB->MaxDataCount = cpu_to_le16(4280);
+	pSMB->MaxSetupCount = 0;
+
+	pSMB->Flags = 0;
+	pSMB->Timeout = 0;
+
+	pSMB->SetupCount = 2;
+	pSMB->Function = cpu_to_le16(TRANS_QUERY_NMPIPE_INFO);
+	pSMB->Fid = cpu_to_le16(netfid);
+
+	pSMB->ByteCount = cpu_to_le16(byte_count);
+
+	pSMB->hdr.smb_buf_length += byte_count;
+	rc = SendReceive(xid, tcon->ses, (struct smb_hdr *) pSMB,
+			 (struct smb_hdr *) pSMBr, &bytes_returned, 0);
+	if (rc) {
+		cFYI(1, ("CIFSSMBTransQNmPipe returned %d", rc));
+	} else {
+		offset = le16_to_cpu(pSMBr->DataOffset);
+		bcc_ptr = (char *)pSMBr + offset + 4;
+		qnmpipeinfo.outbuf = le16_to_cpu(*(unsigned short *)bcc_ptr);
+		bcc_ptr += 2;
+		qnmpipeinfo.inbuf = le16_to_cpu(*(unsigned short *)bcc_ptr);
+		bcc_ptr += 2;
+		qnmpipeinfo.maxinst = le16_to_cpu(*(unsigned short *)bcc_ptr);
+		bcc_ptr += 2;
+		qnmpipeinfo.curinst = *bcc_ptr;
+		bcc_ptr += 2;
+		qnmpipeinfo.length = *bcc_ptr;
+		bcc_ptr += 2;
+		if (pSMBr->hdr.Flags2 & SMBFLG2_UNICODE) {
+			rc = cifs_from_ucs2(qnmpipeinfo.pipename,
+				(__le16 *)bcc_ptr,
+				(int)qnmpipeinfo.length,
+				(int)(qnmpipeinfo.length - 2),
+				nls_codepage, 0);
+		} else
+			strncpy(qnmpipeinfo.pipename, bcc_ptr,
+				qnmpipeinfo.length);
+		memcpy((char *)arg, &qnmpipeinfo, sizeof(struct qnmp_info));
+	}
+
+	cifs_buf_release(pSMB);
+
+	if (rc == -EAGAIN)
+		goto qnmpiperetry;
+
+	return rc;
+}
+
+int
+CIFSSMBTransSetNmPHState(const int xid, struct cifsTconInfo *tcon,
+		unsigned long arg, __u16 netfid,
+		const struct nls_table *nls_codepage, int remap)
+{
+	TRANS_REQ *pSMB = NULL;
+	TRANS_RSP *pSMBr = NULL;
+	int rc = 0;
+	int name_len, param_len;
+	int pad;
+	int bytes_returned = 0;
+	__u16 offset;
+	__u16 byte_count = 0;
+	char *fileName = "\\PIPE\\";
+	char *bcc_ptr;
+	unsigned short mode;
+
+	cFYI(1, ("In CIFSSMBTransSetNmPHandState"));
+setnmaphandstateretry:
+	rc = smb_init(SMB_COM_TRANSACTION, 16, tcon, (void **) &pSMB,
+		      (void **) &pSMBr);
+	if (rc)
+		return rc;
+
+	offset = offsetof(TRANS_REQ, Name) - 4;
+	pad = offset % 4;
+	if (pad)
+		offset += pad;
+	bcc_ptr = (char *)pSMB + offset + 4;
+	if (pSMB->hdr.Flags2 & SMBFLG2_UNICODE) {
+		name_len =
+		    cifsConvertToUCS((__le16 *) bcc_ptr, fileName,
+				     PATH_MAX, nls_codepage, remap);
+		name_len++;	/* trailing null */
+		name_len *= 2;
+	} else {	/* BB improve the check for buffer overruns BB */
+		name_len = strnlen(fileName, PATH_MAX);
+		name_len++;	/* trailing null */
+		strncpy(bcc_ptr, fileName, name_len);
+	}
+	byte_count += (1 + pad + name_len);
+
+	offset += name_len;
+	pad = offset % 4;
+	if (pad)
+		offset += pad;
+	pSMB->ParameterCount = 2;
+	pSMB->TotalParameterCount = 2;
+	pSMB->ParameterOffset = offset;
+	bcc_ptr = (char *)pSMB + offset + 4;
+	mode = (*(unsigned short *)(arg));
+	*(unsigned short *)bcc_ptr = cpu_to_le16(mode);
+	bcc_ptr += 2;
+	param_len = 2;
+	byte_count += (pad + param_len);
+
+	offset += param_len;
+	pad = offset % 4;
+	if (pad)
+		offset += pad;
+	pSMB->DataOffset = 0;
+	pSMB->DataCount = 0;
+	pSMB->TotalDataCount = 0;
+
+	pSMB->MaxParameterCount = 0;
+	pSMB->MaxDataCount = 0;
+	pSMB->MaxSetupCount = 0;
+
+	pSMB->Flags = 0;
+	pSMB->Timeout = 0;
+
+	pSMB->SetupCount = 2;
+	pSMB->Function = cpu_to_le16(TRANS_SET_NMPIPE_STATE);
+	pSMB->Fid = cpu_to_le16(netfid);
+
+	pSMB->ByteCount = cpu_to_le16(byte_count);
+
+	pSMB->hdr.smb_buf_length += byte_count;
+	rc = SendReceive(xid, tcon->ses, (struct smb_hdr *) pSMB,
+			 (struct smb_hdr *) pSMBr, &bytes_returned, 0);
+	if (rc)
+		cFYI(1, ("CIFSSMBTranSetNmPHandState returned %d", rc));
+
+	cifs_buf_release(pSMB);
+
+	if (rc == -EAGAIN)
+		goto setnmaphandstateretry;
+
+	return rc;
+}
+
+int
+CIFSSMBTransPeekNmPipe(const int xid, struct cifsTconInfo *tcon,
+		unsigned long arg, __u16 netfid,
+		const struct nls_table *nls_codepage, int remap)
+{
+	TRANS_REQ *pSMB = NULL;
+	TRANS_RSP *pSMBr = NULL;
+	int rc = 0;
+	int name_len;
+	int pad;
+	int bytes_returned = 0;
+	int size;
+	__u16 offset;
+	__u16 byte_count = 0;
+	char *fileName = "\\PIPE\\";
+	char *bcc_ptr;
+
+	cFYI(1, ("In CIFSSMBTransPeekNmPipe"));
+peeknmpiperetry:
+	rc = smb_init(SMB_COM_TRANSACTION, 16, tcon, (void **) &pSMB,
+		      (void **) &pSMBr);
+	if (rc)
+		return rc;
+
+	offset = offsetof(TRANS_REQ, Name) - 4;
+	pad = offset % 4;
+	if (pad)
+		offset += pad;
+	bcc_ptr = (char *)pSMB + offset + 4;
+	if (pSMB->hdr.Flags2 & SMBFLG2_UNICODE) {
+		name_len =
+		    cifsConvertToUCS((__le16 *) bcc_ptr, fileName,
+				     PATH_MAX, nls_codepage, remap);
+		name_len++;	/* trailing null */
+		name_len *= 2;
+	} else {	/* BB improve the check for buffer overruns BB */
+		name_len = strnlen(fileName, PATH_MAX);
+		name_len++;	/* trailing null */
+		strncpy(bcc_ptr, fileName, name_len);
+	}
+	byte_count += (1 + pad + name_len);
+
+	offset += name_len;
+	pad = offset % 4;
+	if (pad)
+		offset += pad;
+	pSMB->ParameterCount = 0;
+	pSMB->TotalParameterCount = 0;
+	pSMB->ParameterOffset = offset;
+	byte_count += pad;
+
+	pSMB->DataOffset = 0;
+	pSMB->DataCount = 0;
+	pSMB->TotalDataCount = 0;
+
+	pSMB->MaxParameterCount = 6;
+	/* BB find max SMB PDU from sess */
+	pSMB->MaxDataCount = cpu_to_le16(4280);
+	pSMB->MaxSetupCount = 0;
+
+	pSMB->Flags = 0;
+	pSMB->Timeout = 0;
+
+	pSMB->SetupCount = 2;
+	pSMB->Function = cpu_to_le16(TRANS_PEEK_NMPIPE);
+	pSMB->Fid = cpu_to_le16(netfid);
+
+	pSMB->ByteCount = cpu_to_le16(byte_count);
+
+	pSMB->hdr.smb_buf_length += byte_count;
+	rc = SendReceive(xid, tcon->ses, (struct smb_hdr *) pSMB,
+			 (struct smb_hdr *) pSMBr, &bytes_returned, 0);
+	if (rc) {
+		cFYI(1, ("CIFSSMBTranPeekNmPipe returned %d", rc));
+	} else {
+		offset = le16_to_cpu(pSMBr->ParameterOffset);
+		bcc_ptr = (char *)pSMBr + offset + 4;
+		((struct peeknmp_info *)arg)->bavail =
+				le16_to_cpu(*(unsigned short *)bcc_ptr);
+		bcc_ptr += 2;
+		((struct peeknmp_info *)arg)->bremain =
+			le16_to_cpu(*(unsigned short *)bcc_ptr);
+		bcc_ptr += 2;
+		((struct peeknmp_info *)arg)->conntype =
+			le16_to_cpu(*(unsigned short *)bcc_ptr);
+		bcc_ptr += 2;
+		if (((struct peeknmp_info *)arg)->size >
+				((struct peeknmp_info *)arg)->bavail)
+			size = ((struct peeknmp_info *)arg)->bavail;
+		else
+			size = ((struct peeknmp_info *)arg)->size;
+		memcpy(((struct peeknmp_info *)arg)->buffer, bcc_ptr, size);
+	}
+
+	cifs_buf_release(pSMB);
+
+	if (rc == -EAGAIN)
+		goto peeknmpiperetry;
+
+	return rc;
+}
+
+int
+CIFSSMBTransGetNmPHState(const int xid, struct cifsTconInfo *tcon,
+		unsigned long arg, __u16 netfid,
+		const struct nls_table *nls_codepage, int remap)
+{
+	TRANS_REQ *pSMB = NULL;
+	TRANS_RSP *pSMBr = NULL;
+	int rc = 0;
+	int name_len;
+	int pad;
+	int bytes_returned = 0;
+	__u16 offset;
+	__u16 byte_count = 0;
+	char *fileName = "\\PIPE\\";
+	char *bcc_ptr;
+	struct qnmp_hinfo qnmpipehinfo;
+
+	cFYI(1, ("In CIFSSMBTransSetNmPHandState"));
+getnmaphandstateretry:
+	rc = smb_init(SMB_COM_TRANSACTION, 16, tcon, (void **) &pSMB,
+		      (void **) &pSMBr);
+	if (rc)
+		return rc;
+
+	offset = offsetof(TRANS_REQ, Name) - 4;
+	pad = offset % 4;
+	if (pad)
+		offset += pad;
+	bcc_ptr = (char *)pSMB + offset + 4;
+	if (pSMB->hdr.Flags2 & SMBFLG2_UNICODE) {
+		name_len =
+		    cifsConvertToUCS((__le16 *) bcc_ptr, fileName,
+				     PATH_MAX, nls_codepage, remap);
+		name_len++;	/* trailing null */
+		name_len *= 2;
+	} else {	/* BB improve the check for buffer overruns BB */
+		name_len = strnlen(fileName, PATH_MAX);
+		name_len++;	/* trailing null */
+		strncpy(bcc_ptr, fileName, name_len);
+	}
+	byte_count += (1 + pad + name_len);
+
+	offset += name_len;
+	pad = offset % 4;
+	if (pad)
+		offset += pad;
+	pSMB->ParameterCount = 0;
+	pSMB->TotalParameterCount = 0;
+	pSMB->ParameterOffset = offset;
+
+	pSMB->DataCount = 0;
+	pSMB->TotalDataCount = 0;
+	pSMB->DataOffset = offset;
+
+	pSMB->MaxParameterCount = 2;
+	pSMB->MaxDataCount = 0;
+	pSMB->MaxSetupCount = 0;
+
+	pSMB->Flags = 0;
+	pSMB->Timeout = 0;
+
+	pSMB->SetupCount = 2;
+	pSMB->Function = cpu_to_le16(TRANS_QUERY_NMPIPE_STATE);
+	pSMB->Fid = cpu_to_le16(netfid);
+
+	byte_count += pad;
+	pSMB->ByteCount = cpu_to_le16(byte_count);
+
+	pSMB->hdr.smb_buf_length += byte_count;
+	rc = SendReceive(xid, tcon->ses, (struct smb_hdr *) pSMB,
+			 (struct smb_hdr *) pSMBr, &bytes_returned, 0);
+	if (rc) {
+		cFYI(1, ("CIFSSMBTranGetNmPHandState returned %d", rc));
+	} else {
+		offset = le16_to_cpu(pSMBr->ParameterOffset);
+		bcc_ptr = (char *)pSMBr + offset + 4;
+		qnmpipehinfo.mode = le16_to_cpu(*(unsigned short *)bcc_ptr);
+		memcpy((char *)arg, &qnmpipehinfo, sizeof(struct qnmp_hinfo));
+	}
+
+	cifs_buf_release(pSMB);
+
+	if (rc == -EAGAIN)
+		goto getnmaphandstateretry;
+
+	return rc;
+}
+
+int
+CIFSSMBTransNmPipe(const int xid, struct cifsTconInfo *tcon,
+		unsigned char *arg, __u16 netfid,
+		const struct nls_table *nls_codepage, int remap)
+{
+	TRANS_REQ *pSMB = NULL;
+	TRANS_RSP *pSMBr = NULL;
+	int rc = 0;
+	int name_len;
+	int pad;
+	int bytes_returned = 0;
+	__u16 offset;
+	__u16 byte_count = 0;
+	char *fileName = "\\PIPE\\";
+	char *bcc_ptr;
+
+	cFYI(1, ("In CIFSSMBTransNmPipe"));
+transnmpiperetry:
+	rc = smb_init(SMB_COM_TRANSACTION, 16, tcon, (void **) &pSMB,
+		      (void **) &pSMBr);
+	if (rc)
+		return rc;
+
+	offset = offsetof(TRANS_REQ, Name) - 4;
+	pad = offset % 4;
+	if (pad)
+		offset += pad;
+	bcc_ptr = (char *)pSMB + offset + 4;
+	if (pSMB->hdr.Flags2 & SMBFLG2_UNICODE) {
+		name_len =
+		    cifsConvertToUCS((__le16 *) bcc_ptr, fileName,
+				     PATH_MAX, nls_codepage, remap);
+		name_len++;	/* trailing null */
+		name_len *= 2;
+	} else {	/* BB improve the check for buffer overruns BB */
+		name_len = strnlen(fileName, PATH_MAX);
+		name_len++;	/* trailing null */
+		strncpy(bcc_ptr, fileName, name_len);
+	}
+	byte_count += (1 + pad + name_len);
+
+	offset += name_len;
+	pad = offset % 4;
+	if (pad)
+		offset += pad;
+	pSMB->ParameterOffset = offset;
+	pSMB->ParameterCount = 0;
+	pSMB->TotalParameterCount = 0;
+
+	pSMB->DataOffset = offset;
+	pSMB->DataCount = ((struct transnmp_info *)arg)->wsize;
+	pSMB->TotalDataCount = pSMB->DataCount;
+	bcc_ptr = (char *)pSMB + offset + 4;
+	memcpy(bcc_ptr, ((struct transnmp_info *)arg)->sendbuf,
+					pSMB->DataCount);
+	byte_count += (pad + pSMB->DataCount);
+
+	pSMB->MaxParameterCount = 0;
+	/* BB find max SMB PDU from sess */
+	pSMB->MaxDataCount = cpu_to_le16(4280);
+	pSMB->MaxSetupCount = 0;
+
+	pSMB->Flags = 0;
+	pSMB->Timeout = 0;
+
+	pSMB->SetupCount = 2;
+	pSMB->Function = cpu_to_le16(TRANS_TRANSACT_NMPIPE);
+	pSMB->Fid = cpu_to_le16(netfid);
+
+	pSMB->ByteCount = cpu_to_le16(byte_count);
+
+	pSMB->hdr.smb_buf_length += byte_count;
+	rc = SendReceive(xid, tcon->ses, (struct smb_hdr *) pSMB,
+			 (struct smb_hdr *) pSMBr, &bytes_returned, 0);
+	if (rc) {
+		cFYI(1, ("CIFSSMBTransQNmPipe returned %d", rc));
+	} else {
+		offset = le16_to_cpu(pSMBr->DataOffset);
+		bcc_ptr = ((char *)pSMBr + offset + 4);
+		byte_count = le16_to_cpu(pSMBr->DataCount);
+		((struct transnmp_info *)arg)->rsize = byte_count;
+		memcpy(((struct transnmp_info *)arg)->recvbuf, bcc_ptr,
+				byte_count);
+	}
+
+	cifs_buf_release(pSMB);
+
+	if (rc == -EAGAIN)
+		goto transnmpiperetry;
+
+	return rc;
+}
 #endif