Loading fs/cifs/cifspdu.h +1 −1 Original line number Diff line number Diff line Loading @@ -330,7 +330,7 @@ struct smb_hdr { }; /* given a pointer to an smb_hdr retrieve the value of byte count */ #define BCC(smb_var) ( *(__u16 *)((char *)smb_var + sizeof(struct smb_hdr) + (2* smb_var->WordCount) ) ) #define BCC_LE(smb_var) ( *(__le16 *)((char *)smb_var + sizeof(struct smb_hdr) + (2* smb_var->WordCount) ) ) /* given a pointer to an smb_hdr retrieve the pointer to the byte area */ #define pByteArea(smb_var) ((unsigned char *)smb_var + sizeof(struct smb_hdr) + (2* smb_var->WordCount) + 2 ) Loading fs/cifs/connect.c +245 −103 Original line number Diff line number Diff line Loading @@ -194,6 +194,121 @@ cifs_reconnect(struct TCP_Server_Info *server) 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 sizes 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 = be32_to_cpu(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 = cpu_to_be32(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 int cifs_demultiplex_thread(struct TCP_Server_Info *server) { Loading @@ -211,6 +326,8 @@ cifs_demultiplex_thread(struct TCP_Server_Info *server) struct mid_q_entry *mid_entry; char *temp; int isLargeBuf = FALSE; int isMultiRsp; int reconnect; daemonize("cifsd"); allow_signal(SIGKILL); Loading Loading @@ -254,6 +371,7 @@ cifs_demultiplex_thread(struct TCP_Server_Info *server) memset(smallbuf, 0, sizeof (struct smb_hdr)); isLargeBuf = FALSE; isMultiRsp = FALSE; smb_buffer = smallbuf; iov.iov_base = smb_buffer; iov.iov_len = 4; Loading Loading @@ -311,13 +429,15 @@ cifs_demultiplex_thread(struct TCP_Server_Info *server) temp = (char *) smb_buffer; if (temp[0] == (char) RFC1002_SESSION_KEEP_ALIVE) { cFYI(0,("Received 4 byte keep alive packet")); continue; } else if (temp[0] == (char)RFC1002_POSITIVE_SESSION_RESPONSE) { cFYI(1,("Good RFC 1002 session rsp")); continue; } else if (temp[0] == (char)RFC1002_NEGATIVE_SESSION_RESPONSE) { /* we get this from Windows 98 instead of an error on SMB negprot response */ cFYI(1,("Negative RFC 1002 Session Response Error 0x%x)",temp[4])); cFYI(1,("Negative RFC1002 Session Response Error 0x%x)", temp[4])); if(server->tcpStatus == CifsNew) { /* if nack on negprot (rather than ret of smb negprot error) reconnecting Loading Loading @@ -345,19 +465,21 @@ cifs_demultiplex_thread(struct TCP_Server_Info *server) cifs_reconnect(server); csocket = server->ssocket; continue; } else { /* we have an SMB response */ if((pdu_length > CIFSMaxBufSize + MAX_CIFS_HDR_SIZE - 4) || } /* else we have an SMB response */ if((pdu_length > CIFSMaxBufSize + MAX_CIFS_HDR_SIZE - 4) || (pdu_length < sizeof (struct smb_hdr) - 1 - 4)) { cERROR(1, ("Invalid size SMB length %d and pdu_length %d", cERROR(1, ("Invalid size SMB length %d pdu_length %d", length, pdu_length+4)); cifs_reconnect(server); csocket = server->ssocket; wake_up(&server->response_q); continue; } else { /* length ok */ int reconnect = 0; } /* else length ok */ reconnect = 0; if(pdu_length > MAX_CIFS_HDR_SIZE - 4) { isLargeBuf = TRUE; Loading @@ -367,19 +489,16 @@ cifs_demultiplex_thread(struct TCP_Server_Info *server) length = 0; iov.iov_base = 4 + (char *)smb_buffer; iov.iov_len = pdu_length; for (total_read = 0; total_read < pdu_length; for (total_read = 0; total_read < pdu_length; total_read += length) { length = kernel_recvmsg(csocket, &smb_msg, &iov, 1, length = kernel_recvmsg(csocket, &smb_msg, &iov, 1, pdu_length - total_read, 0); if((server->tcpStatus == CifsExiting) || (length == -EINTR)) { /* then will exit */ reconnect = 2; break; } else if (server->tcpStatus == CifsNeedReconnect) { } else if (server->tcpStatus == CifsNeedReconnect) { cifs_reconnect(server); csocket = server->ssocket; /* Reconnect wakes up rspns q */ Loading @@ -388,9 +507,10 @@ cifs_demultiplex_thread(struct TCP_Server_Info *server) break; } else if ((length == -ERESTARTSYS) || (length == -EAGAIN)) { msleep(1); /* minimum sleep to prevent looping allowing socket to clear and app threads to set tcpStatus CifsNeedReconnect if server hung */ msleep(1); /* minimum sleep to prevent looping, allowing socket to clear and app threads to set tcpStatus CifsNeedReconnect if server hung*/ continue; } else if (length <= 0) { cERROR(1,("Received no data, expecting %d", Loading @@ -407,11 +527,10 @@ cifs_demultiplex_thread(struct TCP_Server_Info *server) continue; length += 4; /* account for rfc1002 hdr */ } dump_smb(smb_buffer, length); if (checkSMB (smb_buffer, smb_buffer->Mid, total_read+4)) { if (checkSMB (smb_buffer, smb_buffer->Mid, total_read+4)) { cERROR(1, ("Bad SMB Received ")); continue; } Loading @@ -420,27 +539,49 @@ cifs_demultiplex_thread(struct TCP_Server_Info *server) task_to_wake = NULL; spin_lock(&GlobalMid_Lock); list_for_each(tmp, &server->pending_mid_q) { mid_entry = list_entry(tmp, struct mid_q_entry, qhead); mid_entry = list_entry(tmp, struct mid_q_entry, qhead); if ((mid_entry->mid == smb_buffer->Mid) && (mid_entry->midState == MID_REQUEST_SUBMITTED) && (mid_entry->command == smb_buffer->Command)) { cFYI(1,("Found Mid 0x%x wake up" ,mid_entry->mid)); /* BB FIXME - missing code here BB */ /* check_2nd_t2(smb_buffer); */ task_to_wake = mid_entry->tsk; if ((mid_entry->mid == smb_buffer->Mid) && (mid_entry->midState == MID_REQUEST_SUBMITTED) && (mid_entry->command == smb_buffer->Command)) { cFYI(1,("Found Mid 0x%x wake", mid_entry->mid)); if(check2ndT2(smb_buffer,server->maxBuf) > 0) { /* We have a multipart transact2 resp */ if(mid_entry->resp_buf) { /* merge response - fix up 1st*/ if(coalesce_t2(smb_buffer, mid_entry->resp_buf)) { isMultiRsp = TRUE; break; } else { /* all parts received */ goto multi_t2_fnd; } } else { if(!isLargeBuf) { cERROR(1,("1st trans2 resp needs bigbuf")); /* BB maybe we can fix this up, switch to already allocated large buffer? */ } else { mid_entry->resp_buf = smb_buffer; mid_entry->midState = MID_RESPONSE_RECEIVED; mid_entry->largeBuf = 1; isMultiRsp = TRUE; bigbuf = NULL; } } break; } mid_entry->resp_buf = smb_buffer; if(isLargeBuf) mid_entry->largeBuf = 1; else mid_entry->largeBuf = 0; multi_t2_fnd: task_to_wake = mid_entry->tsk; mid_entry->midState = MID_RESPONSE_RECEIVED; break; } } spin_unlock(&GlobalMid_Lock); Loading @@ -449,14 +590,15 @@ cifs_demultiplex_thread(struct TCP_Server_Info *server) bigbuf = NULL; else smallbuf = NULL; smb_buffer = NULL; /* will be freed by users thread after he is done */ /* smb buffer freed by user thread when done */ wake_up_process(task_to_wake); } else if (is_valid_oplock_break(smb_buffer) == FALSE) { } else if ((is_valid_oplock_break(smb_buffer) == FALSE) && (isMultiRsp == FALSE)) { cERROR(1, ("No task to wake, unknown frame rcvd!")); cifs_dump_mem("Received Data is: ",temp,sizeof(struct smb_hdr)); } } } } /* end while !EXITING */ spin_lock(&GlobalMid_Lock); server->tcpStatus = CifsExiting; server->tsk = NULL; Loading Loading
fs/cifs/cifspdu.h +1 −1 Original line number Diff line number Diff line Loading @@ -330,7 +330,7 @@ struct smb_hdr { }; /* given a pointer to an smb_hdr retrieve the value of byte count */ #define BCC(smb_var) ( *(__u16 *)((char *)smb_var + sizeof(struct smb_hdr) + (2* smb_var->WordCount) ) ) #define BCC_LE(smb_var) ( *(__le16 *)((char *)smb_var + sizeof(struct smb_hdr) + (2* smb_var->WordCount) ) ) /* given a pointer to an smb_hdr retrieve the pointer to the byte area */ #define pByteArea(smb_var) ((unsigned char *)smb_var + sizeof(struct smb_hdr) + (2* smb_var->WordCount) + 2 ) Loading
fs/cifs/connect.c +245 −103 Original line number Diff line number Diff line Loading @@ -194,6 +194,121 @@ cifs_reconnect(struct TCP_Server_Info *server) 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 sizes 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 = be32_to_cpu(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 = cpu_to_be32(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 int cifs_demultiplex_thread(struct TCP_Server_Info *server) { Loading @@ -211,6 +326,8 @@ cifs_demultiplex_thread(struct TCP_Server_Info *server) struct mid_q_entry *mid_entry; char *temp; int isLargeBuf = FALSE; int isMultiRsp; int reconnect; daemonize("cifsd"); allow_signal(SIGKILL); Loading Loading @@ -254,6 +371,7 @@ cifs_demultiplex_thread(struct TCP_Server_Info *server) memset(smallbuf, 0, sizeof (struct smb_hdr)); isLargeBuf = FALSE; isMultiRsp = FALSE; smb_buffer = smallbuf; iov.iov_base = smb_buffer; iov.iov_len = 4; Loading Loading @@ -311,13 +429,15 @@ cifs_demultiplex_thread(struct TCP_Server_Info *server) temp = (char *) smb_buffer; if (temp[0] == (char) RFC1002_SESSION_KEEP_ALIVE) { cFYI(0,("Received 4 byte keep alive packet")); continue; } else if (temp[0] == (char)RFC1002_POSITIVE_SESSION_RESPONSE) { cFYI(1,("Good RFC 1002 session rsp")); continue; } else if (temp[0] == (char)RFC1002_NEGATIVE_SESSION_RESPONSE) { /* we get this from Windows 98 instead of an error on SMB negprot response */ cFYI(1,("Negative RFC 1002 Session Response Error 0x%x)",temp[4])); cFYI(1,("Negative RFC1002 Session Response Error 0x%x)", temp[4])); if(server->tcpStatus == CifsNew) { /* if nack on negprot (rather than ret of smb negprot error) reconnecting Loading Loading @@ -345,19 +465,21 @@ cifs_demultiplex_thread(struct TCP_Server_Info *server) cifs_reconnect(server); csocket = server->ssocket; continue; } else { /* we have an SMB response */ if((pdu_length > CIFSMaxBufSize + MAX_CIFS_HDR_SIZE - 4) || } /* else we have an SMB response */ if((pdu_length > CIFSMaxBufSize + MAX_CIFS_HDR_SIZE - 4) || (pdu_length < sizeof (struct smb_hdr) - 1 - 4)) { cERROR(1, ("Invalid size SMB length %d and pdu_length %d", cERROR(1, ("Invalid size SMB length %d pdu_length %d", length, pdu_length+4)); cifs_reconnect(server); csocket = server->ssocket; wake_up(&server->response_q); continue; } else { /* length ok */ int reconnect = 0; } /* else length ok */ reconnect = 0; if(pdu_length > MAX_CIFS_HDR_SIZE - 4) { isLargeBuf = TRUE; Loading @@ -367,19 +489,16 @@ cifs_demultiplex_thread(struct TCP_Server_Info *server) length = 0; iov.iov_base = 4 + (char *)smb_buffer; iov.iov_len = pdu_length; for (total_read = 0; total_read < pdu_length; for (total_read = 0; total_read < pdu_length; total_read += length) { length = kernel_recvmsg(csocket, &smb_msg, &iov, 1, length = kernel_recvmsg(csocket, &smb_msg, &iov, 1, pdu_length - total_read, 0); if((server->tcpStatus == CifsExiting) || (length == -EINTR)) { /* then will exit */ reconnect = 2; break; } else if (server->tcpStatus == CifsNeedReconnect) { } else if (server->tcpStatus == CifsNeedReconnect) { cifs_reconnect(server); csocket = server->ssocket; /* Reconnect wakes up rspns q */ Loading @@ -388,9 +507,10 @@ cifs_demultiplex_thread(struct TCP_Server_Info *server) break; } else if ((length == -ERESTARTSYS) || (length == -EAGAIN)) { msleep(1); /* minimum sleep to prevent looping allowing socket to clear and app threads to set tcpStatus CifsNeedReconnect if server hung */ msleep(1); /* minimum sleep to prevent looping, allowing socket to clear and app threads to set tcpStatus CifsNeedReconnect if server hung*/ continue; } else if (length <= 0) { cERROR(1,("Received no data, expecting %d", Loading @@ -407,11 +527,10 @@ cifs_demultiplex_thread(struct TCP_Server_Info *server) continue; length += 4; /* account for rfc1002 hdr */ } dump_smb(smb_buffer, length); if (checkSMB (smb_buffer, smb_buffer->Mid, total_read+4)) { if (checkSMB (smb_buffer, smb_buffer->Mid, total_read+4)) { cERROR(1, ("Bad SMB Received ")); continue; } Loading @@ -420,27 +539,49 @@ cifs_demultiplex_thread(struct TCP_Server_Info *server) task_to_wake = NULL; spin_lock(&GlobalMid_Lock); list_for_each(tmp, &server->pending_mid_q) { mid_entry = list_entry(tmp, struct mid_q_entry, qhead); mid_entry = list_entry(tmp, struct mid_q_entry, qhead); if ((mid_entry->mid == smb_buffer->Mid) && (mid_entry->midState == MID_REQUEST_SUBMITTED) && (mid_entry->command == smb_buffer->Command)) { cFYI(1,("Found Mid 0x%x wake up" ,mid_entry->mid)); /* BB FIXME - missing code here BB */ /* check_2nd_t2(smb_buffer); */ task_to_wake = mid_entry->tsk; if ((mid_entry->mid == smb_buffer->Mid) && (mid_entry->midState == MID_REQUEST_SUBMITTED) && (mid_entry->command == smb_buffer->Command)) { cFYI(1,("Found Mid 0x%x wake", mid_entry->mid)); if(check2ndT2(smb_buffer,server->maxBuf) > 0) { /* We have a multipart transact2 resp */ if(mid_entry->resp_buf) { /* merge response - fix up 1st*/ if(coalesce_t2(smb_buffer, mid_entry->resp_buf)) { isMultiRsp = TRUE; break; } else { /* all parts received */ goto multi_t2_fnd; } } else { if(!isLargeBuf) { cERROR(1,("1st trans2 resp needs bigbuf")); /* BB maybe we can fix this up, switch to already allocated large buffer? */ } else { mid_entry->resp_buf = smb_buffer; mid_entry->midState = MID_RESPONSE_RECEIVED; mid_entry->largeBuf = 1; isMultiRsp = TRUE; bigbuf = NULL; } } break; } mid_entry->resp_buf = smb_buffer; if(isLargeBuf) mid_entry->largeBuf = 1; else mid_entry->largeBuf = 0; multi_t2_fnd: task_to_wake = mid_entry->tsk; mid_entry->midState = MID_RESPONSE_RECEIVED; break; } } spin_unlock(&GlobalMid_Lock); Loading @@ -449,14 +590,15 @@ cifs_demultiplex_thread(struct TCP_Server_Info *server) bigbuf = NULL; else smallbuf = NULL; smb_buffer = NULL; /* will be freed by users thread after he is done */ /* smb buffer freed by user thread when done */ wake_up_process(task_to_wake); } else if (is_valid_oplock_break(smb_buffer) == FALSE) { } else if ((is_valid_oplock_break(smb_buffer) == FALSE) && (isMultiRsp == FALSE)) { cERROR(1, ("No task to wake, unknown frame rcvd!")); cifs_dump_mem("Received Data is: ",temp,sizeof(struct smb_hdr)); } } } } /* end while !EXITING */ spin_lock(&GlobalMid_Lock); server->tcpStatus = CifsExiting; server->tsk = NULL; Loading