SMB Trans commands (except WaitNamedPipe) >From d11c8d19f9e1bf5d3ed615a38ce99e97dfe0b7dd Mon Sep 17 00:00:00 2001 From: Shirish Pargaonkar <shirishpargaonkar@xxxxxxxxx> 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 --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 -- 1.5.2 -- To unsubscribe from this list: send the line "unsubscribe linux-fsdevel" in the body of a message to majordomo@xxxxxxxxxxxxxxx More majordomo info at http://vger.kernel.org/majordomo-info.html