mirror of
https://github.com/torvalds/linux.git
synced 2026-05-27 00:22:00 +02:00
cifs: SMB1 split: Move some SMB1 receive bits to smb1transport.c
Move some SMB1 receive bits to smb1transport.c from smb1ops.c where they're mixed in with unrelated code to do with encoding, decoding and processing PDUs. Signed-off-by: David Howells <dhowells@redhat.com> cc: Steve French <sfrench@samba.org> cc: Paulo Alcantara <pc@manguebit.org> cc: Enzo Matsumiya <ematsumiya@suse.de> cc: linux-cifs@vger.kernel.org cc: linux-fsdevel@vger.kernel.org cc: linux-kernel@vger.kernel.org Acked-by: Enzo Matsumiya <ematsumiya@suse.de> Signed-off-by: Steve French <stfrench@microsoft.com>
This commit is contained in:
parent
645427b7a6
commit
bae7afc4b4
|
|
@ -284,146 +284,6 @@ cifs_get_next_mid(struct TCP_Server_Info *server)
|
|||
return mid;
|
||||
}
|
||||
|
||||
/*
|
||||
return codes:
|
||||
0 not a transact2, or all data present
|
||||
>0 transact2 with that much data missing
|
||||
-EINVAL invalid transact2
|
||||
*/
|
||||
static int
|
||||
check2ndT2(char *buf)
|
||||
{
|
||||
struct smb_hdr *pSMB = (struct smb_hdr *)buf;
|
||||
struct smb_t2_rsp *pSMBt;
|
||||
int remaining;
|
||||
__u16 total_data_size, data_in_this_rsp;
|
||||
|
||||
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 */
|
||||
cifs_dbg(FYI, "Invalid transact2 word count\n");
|
||||
return -EINVAL;
|
||||
}
|
||||
|
||||
pSMBt = (struct smb_t2_rsp *)pSMB;
|
||||
|
||||
total_data_size = get_unaligned_le16(&pSMBt->t2_rsp.TotalDataCount);
|
||||
data_in_this_rsp = get_unaligned_le16(&pSMBt->t2_rsp.DataCount);
|
||||
|
||||
if (total_data_size == data_in_this_rsp)
|
||||
return 0;
|
||||
else if (total_data_size < data_in_this_rsp) {
|
||||
cifs_dbg(FYI, "total data %d smaller than data in frame %d\n",
|
||||
total_data_size, data_in_this_rsp);
|
||||
return -EINVAL;
|
||||
}
|
||||
|
||||
remaining = total_data_size - data_in_this_rsp;
|
||||
|
||||
cifs_dbg(FYI, "missing %d bytes from transact2, check next response\n",
|
||||
remaining);
|
||||
if (total_data_size > CIFSMaxBufSize) {
|
||||
cifs_dbg(VFS, "TotalDataSize %d is over maximum buffer %d\n",
|
||||
total_data_size, CIFSMaxBufSize);
|
||||
return -EINVAL;
|
||||
}
|
||||
return remaining;
|
||||
}
|
||||
|
||||
static int
|
||||
coalesce_t2(char *second_buf, struct smb_hdr *target_hdr, unsigned int *pdu_len)
|
||||
{
|
||||
struct smb_t2_rsp *pSMBs = (struct smb_t2_rsp *)second_buf;
|
||||
struct smb_t2_rsp *pSMBt = (struct smb_t2_rsp *)target_hdr;
|
||||
char *data_area_of_tgt;
|
||||
char *data_area_of_src;
|
||||
int remaining;
|
||||
unsigned int byte_count, total_in_tgt;
|
||||
__u16 tgt_total_cnt, src_total_cnt, total_in_src;
|
||||
|
||||
src_total_cnt = get_unaligned_le16(&pSMBs->t2_rsp.TotalDataCount);
|
||||
tgt_total_cnt = get_unaligned_le16(&pSMBt->t2_rsp.TotalDataCount);
|
||||
|
||||
if (tgt_total_cnt != src_total_cnt)
|
||||
cifs_dbg(FYI, "total data count of primary and secondary t2 differ source=%hu target=%hu\n",
|
||||
src_total_cnt, tgt_total_cnt);
|
||||
|
||||
total_in_tgt = get_unaligned_le16(&pSMBt->t2_rsp.DataCount);
|
||||
|
||||
remaining = tgt_total_cnt - total_in_tgt;
|
||||
|
||||
if (remaining < 0) {
|
||||
cifs_dbg(FYI, "Server sent too much data. tgt_total_cnt=%hu total_in_tgt=%u\n",
|
||||
tgt_total_cnt, total_in_tgt);
|
||||
return -EPROTO;
|
||||
}
|
||||
|
||||
if (remaining == 0) {
|
||||
/* nothing to do, ignore */
|
||||
cifs_dbg(FYI, "no more data remains\n");
|
||||
return 0;
|
||||
}
|
||||
|
||||
total_in_src = get_unaligned_le16(&pSMBs->t2_rsp.DataCount);
|
||||
if (remaining < total_in_src)
|
||||
cifs_dbg(FYI, "transact2 2nd response contains too much data\n");
|
||||
|
||||
/* find end of first SMB data area */
|
||||
data_area_of_tgt = (char *)&pSMBt->hdr.Protocol +
|
||||
get_unaligned_le16(&pSMBt->t2_rsp.DataOffset);
|
||||
|
||||
/* validate target area */
|
||||
data_area_of_src = (char *)&pSMBs->hdr.Protocol +
|
||||
get_unaligned_le16(&pSMBs->t2_rsp.DataOffset);
|
||||
|
||||
data_area_of_tgt += total_in_tgt;
|
||||
|
||||
total_in_tgt += total_in_src;
|
||||
/* is the result too big for the field? */
|
||||
if (total_in_tgt > USHRT_MAX) {
|
||||
cifs_dbg(FYI, "coalesced DataCount too large (%u)\n",
|
||||
total_in_tgt);
|
||||
return -EPROTO;
|
||||
}
|
||||
put_unaligned_le16(total_in_tgt, &pSMBt->t2_rsp.DataCount);
|
||||
|
||||
/* fix up the BCC */
|
||||
byte_count = get_bcc(target_hdr);
|
||||
byte_count += total_in_src;
|
||||
/* is the result too big for the field? */
|
||||
if (byte_count > USHRT_MAX) {
|
||||
cifs_dbg(FYI, "coalesced BCC too large (%u)\n", byte_count);
|
||||
return -EPROTO;
|
||||
}
|
||||
put_bcc(byte_count, target_hdr);
|
||||
|
||||
byte_count = *pdu_len;
|
||||
byte_count += total_in_src;
|
||||
/* don't allow buffer to overflow */
|
||||
if (byte_count > CIFSMaxBufSize + MAX_CIFS_HDR_SIZE) {
|
||||
cifs_dbg(FYI, "coalesced BCC exceeds buffer size (%u)\n",
|
||||
byte_count);
|
||||
return -ENOBUFS;
|
||||
}
|
||||
*pdu_len = byte_count;
|
||||
|
||||
/* copy second buffer into end of first buffer */
|
||||
memcpy(data_area_of_tgt, data_area_of_src, total_in_src);
|
||||
|
||||
if (remaining != total_in_src) {
|
||||
/* more responses to go */
|
||||
cifs_dbg(FYI, "waiting for more secondary responses\n");
|
||||
return 1;
|
||||
}
|
||||
|
||||
/* we are done */
|
||||
cifs_dbg(FYI, "found the last secondary response\n");
|
||||
return 0;
|
||||
}
|
||||
|
||||
static void
|
||||
cifs_downgrade_oplock(struct TCP_Server_Info *server,
|
||||
struct cifsInodeInfo *cinode, __u32 oplock,
|
||||
|
|
@ -432,37 +292,6 @@ cifs_downgrade_oplock(struct TCP_Server_Info *server,
|
|||
cifs_set_oplock_level(cinode, oplock);
|
||||
}
|
||||
|
||||
static bool
|
||||
cifs_check_trans2(struct mid_q_entry *mid, struct TCP_Server_Info *server,
|
||||
char *buf, int malformed)
|
||||
{
|
||||
if (malformed)
|
||||
return false;
|
||||
if (check2ndT2(buf) <= 0)
|
||||
return false;
|
||||
mid->multiRsp = true;
|
||||
if (mid->resp_buf) {
|
||||
/* merge response - fix up 1st*/
|
||||
malformed = coalesce_t2(buf, mid->resp_buf, &mid->response_pdu_len);
|
||||
if (malformed > 0)
|
||||
return true;
|
||||
/* All parts received or packet is malformed. */
|
||||
mid->multiEnd = true;
|
||||
dequeue_mid(server, mid, malformed);
|
||||
return true;
|
||||
}
|
||||
if (!server->large_buf) {
|
||||
/*FIXME: switch to already allocated largebuf?*/
|
||||
cifs_dbg(VFS, "1st trans2 resp needs bigbuf\n");
|
||||
} else {
|
||||
/* Have first buffer */
|
||||
mid->resp_buf = buf;
|
||||
mid->large_buf = true;
|
||||
server->bigbuf = NULL;
|
||||
}
|
||||
return true;
|
||||
}
|
||||
|
||||
static bool
|
||||
cifs_need_neg(struct TCP_Server_Info *server)
|
||||
{
|
||||
|
|
|
|||
|
|
@ -233,6 +233,8 @@ int SendReceive(const unsigned int xid, struct cifs_ses *ses,
|
|||
struct smb_hdr *in_buf, unsigned int in_len,
|
||||
struct smb_hdr *out_buf, int *pbytes_returned,
|
||||
const int flags);
|
||||
bool cifs_check_trans2(struct mid_q_entry *mid, struct TCP_Server_Info *server,
|
||||
char *buf, int malformed);
|
||||
|
||||
|
||||
#endif /* CONFIG_CIFS_ALLOW_INSECURE_LEGACY */
|
||||
|
|
|
|||
|
|
@ -263,3 +263,174 @@ SendReceive(const unsigned int xid, struct cifs_ses *ses,
|
|||
free_rsp_buf(resp_buf_type, resp_iov.iov_base);
|
||||
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(char *buf)
|
||||
{
|
||||
struct smb_hdr *pSMB = (struct smb_hdr *)buf;
|
||||
struct smb_t2_rsp *pSMBt;
|
||||
int remaining;
|
||||
__u16 total_data_size, data_in_this_rsp;
|
||||
|
||||
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 */
|
||||
cifs_dbg(FYI, "Invalid transact2 word count\n");
|
||||
return -EINVAL;
|
||||
}
|
||||
|
||||
pSMBt = (struct smb_t2_rsp *)pSMB;
|
||||
|
||||
total_data_size = get_unaligned_le16(&pSMBt->t2_rsp.TotalDataCount);
|
||||
data_in_this_rsp = get_unaligned_le16(&pSMBt->t2_rsp.DataCount);
|
||||
|
||||
if (total_data_size == data_in_this_rsp)
|
||||
return 0;
|
||||
else if (total_data_size < data_in_this_rsp) {
|
||||
cifs_dbg(FYI, "total data %d smaller than data in frame %d\n",
|
||||
total_data_size, data_in_this_rsp);
|
||||
return -EINVAL;
|
||||
}
|
||||
|
||||
remaining = total_data_size - data_in_this_rsp;
|
||||
|
||||
cifs_dbg(FYI, "missing %d bytes from transact2, check next response\n",
|
||||
remaining);
|
||||
if (total_data_size > CIFSMaxBufSize) {
|
||||
cifs_dbg(VFS, "TotalDataSize %d is over maximum buffer %d\n",
|
||||
total_data_size, CIFSMaxBufSize);
|
||||
return -EINVAL;
|
||||
}
|
||||
return remaining;
|
||||
}
|
||||
|
||||
static int
|
||||
coalesce_t2(char *second_buf, struct smb_hdr *target_hdr, unsigned int *pdu_len)
|
||||
{
|
||||
struct smb_t2_rsp *pSMBs = (struct smb_t2_rsp *)second_buf;
|
||||
struct smb_t2_rsp *pSMBt = (struct smb_t2_rsp *)target_hdr;
|
||||
char *data_area_of_tgt;
|
||||
char *data_area_of_src;
|
||||
int remaining;
|
||||
unsigned int byte_count, total_in_tgt;
|
||||
__u16 tgt_total_cnt, src_total_cnt, total_in_src;
|
||||
|
||||
src_total_cnt = get_unaligned_le16(&pSMBs->t2_rsp.TotalDataCount);
|
||||
tgt_total_cnt = get_unaligned_le16(&pSMBt->t2_rsp.TotalDataCount);
|
||||
|
||||
if (tgt_total_cnt != src_total_cnt)
|
||||
cifs_dbg(FYI, "total data count of primary and secondary t2 differ source=%hu target=%hu\n",
|
||||
src_total_cnt, tgt_total_cnt);
|
||||
|
||||
total_in_tgt = get_unaligned_le16(&pSMBt->t2_rsp.DataCount);
|
||||
|
||||
remaining = tgt_total_cnt - total_in_tgt;
|
||||
|
||||
if (remaining < 0) {
|
||||
cifs_dbg(FYI, "Server sent too much data. tgt_total_cnt=%hu total_in_tgt=%u\n",
|
||||
tgt_total_cnt, total_in_tgt);
|
||||
return -EPROTO;
|
||||
}
|
||||
|
||||
if (remaining == 0) {
|
||||
/* nothing to do, ignore */
|
||||
cifs_dbg(FYI, "no more data remains\n");
|
||||
return 0;
|
||||
}
|
||||
|
||||
total_in_src = get_unaligned_le16(&pSMBs->t2_rsp.DataCount);
|
||||
if (remaining < total_in_src)
|
||||
cifs_dbg(FYI, "transact2 2nd response contains too much data\n");
|
||||
|
||||
/* find end of first SMB data area */
|
||||
data_area_of_tgt = (char *)&pSMBt->hdr.Protocol +
|
||||
get_unaligned_le16(&pSMBt->t2_rsp.DataOffset);
|
||||
|
||||
/* validate target area */
|
||||
data_area_of_src = (char *)&pSMBs->hdr.Protocol +
|
||||
get_unaligned_le16(&pSMBs->t2_rsp.DataOffset);
|
||||
|
||||
data_area_of_tgt += total_in_tgt;
|
||||
|
||||
total_in_tgt += total_in_src;
|
||||
/* is the result too big for the field? */
|
||||
if (total_in_tgt > USHRT_MAX) {
|
||||
cifs_dbg(FYI, "coalesced DataCount too large (%u)\n",
|
||||
total_in_tgt);
|
||||
return -EPROTO;
|
||||
}
|
||||
put_unaligned_le16(total_in_tgt, &pSMBt->t2_rsp.DataCount);
|
||||
|
||||
/* fix up the BCC */
|
||||
byte_count = get_bcc(target_hdr);
|
||||
byte_count += total_in_src;
|
||||
/* is the result too big for the field? */
|
||||
if (byte_count > USHRT_MAX) {
|
||||
cifs_dbg(FYI, "coalesced BCC too large (%u)\n", byte_count);
|
||||
return -EPROTO;
|
||||
}
|
||||
put_bcc(byte_count, target_hdr);
|
||||
|
||||
byte_count = *pdu_len;
|
||||
byte_count += total_in_src;
|
||||
/* don't allow buffer to overflow */
|
||||
if (byte_count > CIFSMaxBufSize + MAX_CIFS_HDR_SIZE) {
|
||||
cifs_dbg(FYI, "coalesced BCC exceeds buffer size (%u)\n",
|
||||
byte_count);
|
||||
return -ENOBUFS;
|
||||
}
|
||||
*pdu_len = byte_count;
|
||||
|
||||
/* copy second buffer into end of first buffer */
|
||||
memcpy(data_area_of_tgt, data_area_of_src, total_in_src);
|
||||
|
||||
if (remaining != total_in_src) {
|
||||
/* more responses to go */
|
||||
cifs_dbg(FYI, "waiting for more secondary responses\n");
|
||||
return 1;
|
||||
}
|
||||
|
||||
/* we are done */
|
||||
cifs_dbg(FYI, "found the last secondary response\n");
|
||||
return 0;
|
||||
}
|
||||
|
||||
bool
|
||||
cifs_check_trans2(struct mid_q_entry *mid, struct TCP_Server_Info *server,
|
||||
char *buf, int malformed)
|
||||
{
|
||||
if (malformed)
|
||||
return false;
|
||||
if (check2ndT2(buf) <= 0)
|
||||
return false;
|
||||
mid->multiRsp = true;
|
||||
if (mid->resp_buf) {
|
||||
/* merge response - fix up 1st*/
|
||||
malformed = coalesce_t2(buf, mid->resp_buf, &mid->response_pdu_len);
|
||||
if (malformed > 0)
|
||||
return true;
|
||||
/* All parts received or packet is malformed. */
|
||||
mid->multiEnd = true;
|
||||
dequeue_mid(server, mid, malformed);
|
||||
return true;
|
||||
}
|
||||
if (!server->large_buf) {
|
||||
/*FIXME: switch to already allocated largebuf?*/
|
||||
cifs_dbg(VFS, "1st trans2 resp needs bigbuf\n");
|
||||
} else {
|
||||
/* Have first buffer */
|
||||
mid->resp_buf = buf;
|
||||
mid->large_buf = true;
|
||||
server->bigbuf = NULL;
|
||||
}
|
||||
return true;
|
||||
}
|
||||
|
|
|
|||
Loading…
Reference in New Issue
Block a user