vserver 2.0 rc7
[linux-2.6.git] / fs / cifs / connect.c
index ff8a4df..e568cc4 100644 (file)
@@ -1,7 +1,7 @@
 /*
  *   fs/cifs/connect.c
  *
- *   Copyright (C) International Business Machines  Corp., 2002,2004
+ *   Copyright (C) International Business Machines  Corp., 2002,2005
  *   Author(s): Steve French (sfrench@us.ibm.com)
  *
  *   This library is free software; you can redistribute it and/or modify
@@ -28,6 +28,7 @@
 #include <linux/ctype.h>
 #include <linux/utsname.h>
 #include <linux/mempool.h>
+#include <linux/delay.h>
 #include <asm/uaccess.h>
 #include <asm/processor.h>
 #include "cifspdu.h"
@@ -47,7 +48,6 @@ extern void SMBencrypt(unsigned char *passwd, unsigned char *c8,
                       unsigned char *p24);
 extern void SMBNTencrypt(unsigned char *passwd, unsigned char *c8,
                         unsigned char *p24);
-extern int cifs_inet_pton(int, const char *, void *dst);
 
 extern mempool_t *cifs_req_poolp;
 
@@ -70,8 +70,10 @@ struct smb_vol {
        unsigned setuids:1;
        unsigned noperm:1;
        unsigned no_psx_acl:1; /* set if posix acl support should be disabled */
+       unsigned no_xattr:1;   /* set if xattr (EA) support should be disabled*/
        unsigned server_ino:1; /* use inode numbers from server ie UniqueId */
        unsigned direct_io:1;
+       unsigned remap:1;   /* set to remap seven reserved chars in filenames */
        unsigned int rsize;
        unsigned int wsize;
        unsigned int sockopt;
@@ -114,7 +116,7 @@ cifs_reconnect(struct TCP_Server_Info *server)
        spin_unlock(&GlobalMid_Lock);
        server->maxBuf = 0;
 
-       cFYI(1, ("Reconnecting tcp session "));
+       cFYI(1, ("Reconnecting tcp session"));
 
        /* before reconnecting the tcp session, mark the smb session (uid)
                and the tid bad so they are not used until reconnected */
@@ -155,9 +157,10 @@ cifs_reconnect(struct TCP_Server_Info *server)
                                        qhead);
                if(mid_entry) {
                        if(mid_entry->midState == MID_REQUEST_SUBMITTED) {
-                               /* Mark other intransit requests as needing retry so 
-                                 we do not immediately mark the session bad again 
-                                 (ie after we reconnect below) as they timeout too */
+                               /* Mark other intransit requests as needing
+                                  retry so we do not immediately mark the
+                                  session bad again (ie after we reconnect
+                                  below) as they timeout too */
                                mid_entry->midState = MID_RETRY_NEEDED;
                        }
                }
@@ -175,14 +178,14 @@ cifs_reconnect(struct TCP_Server_Info *server)
                                        server->workstation_RFC1001_name);
                }
                if(rc) {
-                       set_current_state(TASK_INTERRUPTIBLE);
-                       schedule_timeout(3 * HZ);
+                       msleep(3000);
                } else {
                        atomic_inc(&tcpSesReconnectCount);
                        spin_lock(&GlobalMid_Lock);
                        if(server->tcpStatus != CifsExiting)
                                server->tcpStatus = CifsGood;
-                       spin_unlock(&GlobalMid_Lock);
+                       server->sequence_number = 0;
+                       spin_unlock(&GlobalMid_Lock);                   
        /*              atomic_set(&server->inFlight,0);*/
                        wake_up(&server->response_q);
                }
@@ -190,12 +193,129 @@ 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)
 {
        int length;
        unsigned int pdu_length, total_read;
        struct smb_hdr *smb_buffer = NULL;
+       struct smb_hdr *bigbuf = NULL;
+       struct smb_hdr *smallbuf = NULL;
        struct msghdr smb_msg;
        struct kvec iov;
        struct socket *csocket = server->ssocket;
@@ -204,13 +324,16 @@ cifs_demultiplex_thread(struct TCP_Server_Info *server)
        struct task_struct *task_to_wake = NULL;
        struct mid_q_entry *mid_entry;
        char *temp;
+       int isLargeBuf = FALSE;
+       int isMultiRsp;
+       int reconnect;
 
        daemonize("cifsd");
        allow_signal(SIGKILL);
        current->flags |= PF_MEMALLOC;
        server->tsk = current;  /* save process info to wake at shutdown */
        cFYI(1, ("Demultiplex PID: %d", current->pid));
-       write_lock(&GlobalSMBSeslock);
+       write_lock(&GlobalSMBSeslock); 
        atomic_inc(&tcpSesAllocCount);
        length = tcpSesAllocCount.counter;
        write_unlock(&GlobalSMBSeslock);
@@ -221,233 +344,296 @@ cifs_demultiplex_thread(struct TCP_Server_Info *server)
        }
 
        while (server->tcpStatus != CifsExiting) {
-               if (smb_buffer == NULL)
-                       smb_buffer = cifs_buf_get();
-               else
-                       memset(smb_buffer, 0, sizeof (struct smb_hdr));
-
-               if (smb_buffer == NULL) {
-                       cERROR(1,("Can not get memory for SMB response"));
-                       set_current_state(TASK_INTERRUPTIBLE);
-                       schedule_timeout(HZ * 3); /* give system time to free memory */
-                       continue;
+               if (bigbuf == NULL) {
+                       bigbuf = cifs_buf_get();
+                       if(bigbuf == NULL) {
+                               cERROR(1,("No memory for large SMB response"));
+                               msleep(3000);
+                               /* retry will check if exiting */
+                               continue;
+                       }
+               } else if(isLargeBuf) {
+                       /* we are reusing a dirtry large buf, clear its start */
+                       memset(bigbuf, 0, sizeof (struct smb_hdr));
                }
+
+               if (smallbuf == NULL) {
+                       smallbuf = cifs_small_buf_get();
+                       if(smallbuf == NULL) {
+                               cERROR(1,("No memory for SMB response"));
+                               msleep(1000);
+                               /* retry will check if exiting */
+                               continue;
+                       }
+                       /* beginning of smb buffer is cleared in our buf_get */
+               } else /* if existing small buf clear beginning */
+                       memset(smallbuf, 0, sizeof (struct smb_hdr));
+
+               isLargeBuf = FALSE;
+               isMultiRsp = FALSE;
+               smb_buffer = smallbuf;
                iov.iov_base = smb_buffer;
-               iov.iov_len = sizeof (struct smb_hdr) - 1;      
-        /* 1 byte less above since wct is not always returned in error cases */
+               iov.iov_len = 4;
                smb_msg.msg_control = NULL;
                smb_msg.msg_controllen = 0;
-
                length =
                    kernel_recvmsg(csocket, &smb_msg,
-                                  &iov, 1,
-                                  sizeof (struct smb_hdr) -
-                                  1 /* RFC1001 header and SMB header */ ,
-                                  MSG_PEEK /* flags see socket.h */ );
+                                &iov, 1, 4, 0 /* BB see socket.h flags */);
 
                if(server->tcpStatus == CifsExiting) {
                        break;
                } else if (server->tcpStatus == CifsNeedReconnect) {
-                       cFYI(1,("Reconnecting after server stopped responding"));
+                       cFYI(1,("Reconnect after server stopped responding"));
                        cifs_reconnect(server);
                        cFYI(1,("call to reconnect done"));
                        csocket = server->ssocket;
                        continue;
-               } else if ((length == -ERESTARTSYS) || (length == -EAGAIN)
-                               || ((length > 0) && (length <= 3)) ) {
-                       set_current_state(TASK_INTERRUPTIBLE);
-                       schedule_timeout(1); /* minimum sleep to prevent looping
+               } 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 */
                        continue;
                } else if (length <= 0) {
                        if(server->tcpStatus == CifsNew) {
-                               cFYI(1,("tcp session abended prematurely (after SMBnegprot)"));
-                               /* some servers kill tcp session rather than returning
-                                       smb negprot error in which case reconnecting here is
-                                       not going to help - return error to mount */
+                               cFYI(1,("tcp session abend after SMBnegprot"));
+                               /* some servers kill the TCP session rather than
+                                  returning an SMB negprot error, in which
+                                  case reconnecting here is not going to help,
+                                  and so simply return error to mount */
                                break;
                        }
                        if(length == -EINTR) { 
                                cFYI(1,("cifsd thread killed"));
                                break;
                        }
-                       cFYI(1,("Reconnecting after unexpected peek error %d",length));
+                       cFYI(1,("Reconnect after unexpected peek error %d",
+                               length));
+                       cifs_reconnect(server);
+                       csocket = server->ssocket;
+                       wake_up(&server->response_q);
+                       continue;
+               } else if (length < 4) {
+                       cFYI(1,
+                           ("Frame under four bytes received (%d bytes long)",
+                             length));
                        cifs_reconnect(server);
                        csocket = server->ssocket;
                        wake_up(&server->response_q);
                        continue;
                }
 
-               pdu_length = 4 + ntohl(smb_buffer->smb_buf_length);
-               /* Only read pdu_length after below checks for too short (due
-                  to e.g. int overflow) and too long ie beyond end of buf */
-               cFYI(1, ("Peek length rcvd: 0x%x beginning 0x%x)", length, pdu_length));
+               /* the right amount was read from socket - 4 bytes */
+
+               pdu_length = ntohl(smb_buffer->smb_buf_length);
+               cFYI(1,("rfc1002 length(big endian)0x%x)", pdu_length+4));
 
                temp = (char *) smb_buffer;
-               if (length > 3) {
-                       if (temp[0] == (char) RFC1002_SESSION_KEEP_ALIVE) {
-                               iov.iov_base = smb_buffer;
-                               iov.iov_len = 4;
-                               length = kernel_recvmsg(csocket, &smb_msg,
-                                                       &iov, 1, 4, 0);
-                               cFYI(0,("Received 4 byte keep alive packet"));
-                       } else if (temp[0] == (char) RFC1002_POSITIVE_SESSION_RESPONSE) {
-                               iov.iov_base = smb_buffer;
-                               iov.iov_len = 4;
-                               length = kernel_recvmsg(csocket, &smb_msg,
-                                                       &iov, 1, 4, 0);
-                                       cFYI(1,("Good RFC 1002 session rsp"));
-                       } else if ((temp[0] == (char)RFC1002_NEGATIVE_SESSION_RESPONSE)
-                                  && (length == 5)) {
-                               /* we get this from Windows 98 instead of error on SMB negprot response */
-                               cFYI(1,("Negative RFC 1002 Session Response Error 0x%x)",temp[4]));
-                               if(server->tcpStatus == CifsNew) {
-                                       /* if nack on negprot (rather than 
-                                       ret of smb negprot error) reconnecting
-                                       not going to help, ret error to mount */
-                                       break;
-                               } else {
-                                       /* give server a second to
-                                       clean up before reconnect attempt */
-                                       set_current_state(TASK_INTERRUPTIBLE);
-                                       schedule_timeout(HZ);
-                                       /* always try 445 first on reconnect
-                                       since we get NACK on some if we ever
-                                       connected to port 139 (the NACK is 
-                                       since we do not begin with RFC1001
-                                       session initialize frame) */
-                                       server->addr.sockAddr.sin_port = htons(CIFS_PORT);
-                                       cifs_reconnect(server);
-                                       csocket = server->ssocket;
-                                       wake_up(&server->response_q);
-                                       continue;
-                               }
-                       } else if (temp[0] != (char) 0) {
-                               cERROR(1,("Unknown RFC 1002 frame"));
-                               cifs_dump_mem(" Received Data: ", temp, length);
+               if (temp[0] == (char) RFC1002_SESSION_KEEP_ALIVE) {
+                       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 RFC1002 Session Response Error 0x%x)",
+                               temp[4]));
+                       if(server->tcpStatus == CifsNew) {
+                               /* if nack on negprot (rather than 
+                               ret of smb negprot error) reconnecting
+                               not going to help, ret error to mount */
+                               break;
+                       } else {
+                               /* give server a second to
+                               clean up before reconnect attempt */
+                               msleep(1000);
+                               /* always try 445 first on reconnect
+                               since we get NACK on some if we ever
+                               connected to port 139 (the NACK is 
+                               since we do not begin with RFC1001
+                               session initialize frame) */
+                               server->addr.sockAddr.sin_port = 
+                                       htons(CIFS_PORT);
                                cifs_reconnect(server);
                                csocket = server->ssocket;
+                               wake_up(&server->response_q);
                                continue;
-                       } else {
-                               if (length < 16) {
-                                       /* We can not validate the SMB unless 
-                                       at least this much of SMB available
-                                       so give the socket time to copy
-                                       a few more bytes and retry */ 
-                                       set_current_state(TASK_INTERRUPTIBLE);
-                                       schedule_timeout(10);
-                                       continue;
-                               } else if( (pdu_length >
-                                       CIFSMaxBufSize + MAX_CIFS_HDR_SIZE)
-                                   || (pdu_length <
-                                       sizeof (struct smb_hdr) - 1)
-                                   || (checkSMBhdr
-                                    (smb_buffer, smb_buffer->Mid))) {
-                                       cERROR(1,
-                                           ("Invalid size or format for SMB found with length %d and pdu_length %d",
-                                               length, pdu_length));
-                                       cifs_dump_mem("Received Data is: ",temp,sizeof(struct smb_hdr)+3);
-                                       /* could we fix this network corruption by finding next 
-                                               smb header (instead of killing the session) and
-                                               restart reading from next valid SMB found? */
-                                       cifs_reconnect(server);
-                                       csocket = server->ssocket;
-                                       continue;
-                               } else {        /* length ok */
-
-                                       length = 0;
-                                       iov.iov_base = smb_buffer;
-                                       iov.iov_len = pdu_length;
-                                       for (total_read = 0; 
-                                            total_read < pdu_length;
-                                            total_read += length) {    
-                                               length = kernel_recvmsg(csocket, &smb_msg, 
-                                                       &iov, 1,
-                                                       pdu_length - total_read, 0);
-                                               if (length == 0) {
-                                                       cERROR(1,
-                                                              ("Zero length receive when expecting %d ",
-                                                               pdu_length - total_read));
-                                                       cifs_reconnect(server);
-                                                       csocket = server->ssocket;
-                                                       continue;
-                                               }
-                                       }
-                               }
+                       }
+               } else if (temp[0] != (char) 0) {
+                       cERROR(1,("Unknown RFC 1002 frame"));
+                       cifs_dump_mem(" Received Data: ", temp, length);
+                       cifs_reconnect(server);
+                       csocket = server->ssocket;
+                       continue;
+               }
 
-                               dump_smb(smb_buffer, length);
-                               if (checkSMB
-                                   (smb_buffer, smb_buffer->Mid, total_read)) {
-                                       cERROR(1, ("Bad SMB Received "));
-                                       continue;
-                               }
+               /* 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 pdu_length %d",
+                                       length, pdu_length+4));
+                       cifs_reconnect(server);
+                       csocket = server->ssocket;
+                       wake_up(&server->response_q);
+                       continue;
+               } 
 
-                               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);
+               /* else length ok */
+               reconnect = 0;
 
-                                       if ((mid_entry->mid == smb_buffer->Mid) && (mid_entry->midState == MID_REQUEST_SUBMITTED)) {
-                                               cFYI(1,
-                                                    (" Mid 0x%x matched - waking up ",mid_entry->mid));
-                                               task_to_wake = mid_entry->tsk;
-                                               mid_entry->resp_buf =
-                                                   smb_buffer;
-                                               mid_entry->midState =
-                                                   MID_RESPONSE_RECEIVED;
+               if(pdu_length > MAX_CIFS_HDR_SIZE - 4) {
+                       isLargeBuf = TRUE;
+                       memcpy(bigbuf, smallbuf, 4);
+                       smb_buffer = bigbuf;
+               }
+               length = 0;
+               iov.iov_base = 4 + (char *)smb_buffer;
+               iov.iov_len = pdu_length;
+               for (total_read = 0; total_read < pdu_length; 
+                    total_read += length) {
+                       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) {
+                               cifs_reconnect(server);
+                               csocket = server->ssocket;
+                               /* Reconnect wakes up rspns q */
+                               /* Now we will reread sock */
+                               reconnect = 1;
+                               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*/
+                               continue;
+                       } else if (length <= 0) {
+                               cERROR(1,("Received no data, expecting %d",
+                                             pdu_length - total_read));
+                               cifs_reconnect(server);
+                               csocket = server->ssocket;
+                               reconnect = 1;
+                               break;
+                       }
+               }
+               if(reconnect == 2)
+                       break;
+               else if(reconnect == 1)
+                       continue;
+
+               length += 4; /* account for rfc1002 hdr */
+       
+
+               dump_smb(smb_buffer, length);
+               if (checkSMB (smb_buffer, smb_buffer->Mid, total_read+4)) {
+                       cERROR(1, ("Bad SMB Received "));
+                       continue;
+               }
+
+
+               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);
+
+                       if ((mid_entry->mid == smb_buffer->Mid) && 
+                           (mid_entry->midState == MID_REQUEST_SUBMITTED) &&
+                           (mid_entry->command == smb_buffer->Command)) {
+                               if(check2ndT2(smb_buffer,server->maxBuf) > 0) {
+                                       /* We have a multipart transact2 resp */
+                                       isMultiRsp = TRUE;
+                                       if(mid_entry->resp_buf) {
+                                               /* merge response - fix up 1st*/
+                                               if(coalesce_t2(smb_buffer, 
+                                                       mid_entry->resp_buf)) {
+                                                       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 {
+                                                       /* Have first buffer */
+                                                       mid_entry->resp_buf =
+                                                                smb_buffer;
+                                                       mid_entry->largeBuf = 1;
+                                                       bigbuf = NULL;
+                                               }
                                        }
-                               }
-                               spin_unlock(&GlobalMid_Lock);
-                               if (task_to_wake) {
-                                       smb_buffer = NULL;      /* will be freed by users thread after he is done */
-                                       wake_up_process(task_to_wake);
-                               } else if (is_valid_oplock_break(smb_buffer) == FALSE) {                          
-                                       cERROR(1, ("No task to wake, unknown frame rcvd!"));
-                                       cifs_dump_mem("Received Data is: ",temp,sizeof(struct smb_hdr));
-                               }
+                                       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;
                        }
-               } else {
-                       cFYI(0,
-                            ("Frame less than four bytes received  %d bytes long.",
-                             length));
-                       if (length > 0) {
-                               length = kernel_recvmsg(csocket, &smb_msg,
-                                       &iov, 1,
-                                       length, 0);     /* throw away junk frame */
-                               cFYI(1,
-                                    (" with junk  0x%x in it ",
-                                     *(__u32 *) smb_buffer));
+               }
+               spin_unlock(&GlobalMid_Lock);
+               if (task_to_wake) {
+                       /* Was previous buf put in mpx struct for multi-rsp? */
+                       if(!isMultiRsp) {
+                               /* smb buffer will be freed by user thread */
+                               if(isLargeBuf) {
+                                       bigbuf = NULL;
+                               } else
+                                       smallbuf = NULL;
                        }
+                       wake_up_process(task_to_wake);
+               } 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;
-       atomic_set(&server->inFlight, 0);
+       /* check if we have blocked requests that need to free */
+       /* Note that cifs_max_pending is normally 50, but
+       can be set at module install time to as little as two */
+       if(atomic_read(&server->inFlight) >= cifs_max_pending)
+               atomic_set(&server->inFlight, cifs_max_pending - 1);
+       /* We do not want to set the max_pending too low or we
+       could end up with the counter going negative */
        spin_unlock(&GlobalMid_Lock);
        /* Although there should not be any requests blocked on 
        this queue it can not hurt to be paranoid and try to wake up requests
-       that may haven been blocked when more than 50 at time were on the wire 
+       that may haven been blocked when more than 50 at time were on the wire
        to the same server - they now will see the session is in exit state
        and get out of SendReceive.  */
        wake_up_all(&server->request_q);
        /* give those requests time to exit */
-       set_current_state(TASK_INTERRUPTIBLE);
-       schedule_timeout(HZ/8);
-
+       msleep(125);
+       
        if(server->ssocket) {
                sock_release(csocket);
                server->ssocket = NULL;
        }
-       if (smb_buffer) /* buffer usually freed in free_mid - need to free it on error or exit */
-               cifs_buf_release(smb_buffer);
+       /* buffer usuallly freed in free_mid - need to free it here on exit */
+       if (bigbuf != NULL)
+               cifs_buf_release(bigbuf);
+       if (smallbuf != NULL)
+               cifs_small_buf_release(smallbuf);
 
        read_lock(&GlobalSMBSeslock);
        if (list_empty(&server->pending_mid_q)) {
-               /* loop through server session structures attached to this and mark them dead */
+               /* loop through server session structures attached to this and
+                   mark them dead */
                list_for_each(tmp, &GlobalSMBSessionList) {
                        ses =
                            list_entry(tmp, struct cifsSesInfo,
@@ -459,12 +645,23 @@ cifs_demultiplex_thread(struct TCP_Server_Info *server)
                }
                read_unlock(&GlobalSMBSeslock);
        } else {
+               /* although we can not zero the server struct pointer yet,
+               since there are active requests which may depnd on them,
+               mark the corresponding SMB sessions as exiting too */
+               list_for_each(tmp, &GlobalSMBSessionList) {
+                       ses = list_entry(tmp, struct cifsSesInfo,
+                                        cifsSessionList);
+                       if (ses->server == server) {
+                               ses->status = CifsExiting;
+                       }
+               }
+
                spin_lock(&GlobalMid_Lock);
                list_for_each(tmp, &server->pending_mid_q) {
                mid_entry = list_entry(tmp, struct mid_q_entry, qhead);
                        if (mid_entry->midState == MID_REQUEST_SUBMITTED) {
                                cFYI(1,
-                                        (" Clearing Mid 0x%x - waking up ",mid_entry->mid));
+                                 ("Clearing Mid 0x%x - waking up ",mid_entry->mid));
                                task_to_wake = mid_entry->tsk;
                                if(task_to_wake) {
                                        wake_up_process(task_to_wake);
@@ -473,47 +670,51 @@ cifs_demultiplex_thread(struct TCP_Server_Info *server)
                }
                spin_unlock(&GlobalMid_Lock);
                read_unlock(&GlobalSMBSeslock);
-               set_current_state(TASK_INTERRUPTIBLE);
                /* 1/8th of sec is more than enough time for them to exit */
-               schedule_timeout(HZ/8); 
+               msleep(125);
        }
 
        if (list_empty(&server->pending_mid_q)) {
                /* mpx threads have not exited yet give them 
                at least the smb send timeout time for long ops */
+               /* due to delays on oplock break requests, we need
+               to wait at least 45 seconds before giving up
+               on a request getting a response and going ahead
+               and killing cifsd */
                cFYI(1, ("Wait for exit from demultiplex thread"));
-               set_current_state(TASK_INTERRUPTIBLE);
-               schedule_timeout(46 * HZ);      
+               msleep(46000);
                /* if threads still have not exited they are probably never
                coming home not much else we can do but free the memory */
        }
-       kfree(server);
 
        write_lock(&GlobalSMBSeslock);
        atomic_dec(&tcpSesAllocCount);
        length = tcpSesAllocCount.counter;
+
+       /* last chance to mark ses pointers invalid
+       if there are any pointing to this (e.g
+       if a crazy root user tried to kill cifsd 
+       kernel thread explicitly this might happen) */
+       list_for_each(tmp, &GlobalSMBSessionList) {
+               ses = list_entry(tmp, struct cifsSesInfo,
+                               cifsSessionList);
+               if (ses->server == server) {
+                       ses->server = NULL;
+               }
+       }
        write_unlock(&GlobalSMBSeslock);
+
+       kfree(server);
        if(length  > 0) {
                mempool_resize(cifs_req_poolp,
                        length + cifs_min_rcv,
                        GFP_KERNEL);
        }
-
-       set_current_state(TASK_INTERRUPTIBLE);
-       schedule_timeout(HZ/4);
+       
+       msleep(250);
        return 0;
 }
 
-static void * 
-cifs_kcalloc(size_t size, int type)
-{
-       void *addr;
-       addr = kmalloc(size, type);
-       if (addr)
-               memset(addr, 0, size);
-       return addr;
-}
-
 static int
 cifs_parse_mount_options(char *options, const char *devname,struct smb_vol *vol)
 {
@@ -530,7 +731,8 @@ cifs_parse_mount_options(char *options, const char *devname,struct smb_vol *vol)
                /* does not have to be a perfect mapping since the field is
                informational, only used for servers that do not support
                port 445 and it can be overridden at mount time */
-               vol->source_rfc1001_name[i] = toupper(system_utsname.nodename[i]);
+               vol->source_rfc1001_name[i] = 
+                       toupper(system_utsname.nodename[i]);
        }
        vol->source_rfc1001_name[15] = 0;
 
@@ -560,7 +762,12 @@ cifs_parse_mount_options(char *options, const char *devname,struct smb_vol *vol)
                        continue;
                if ((value = strchr(data, '=')) != NULL)
                        *value++ = '\0';
-               if (strnicmp(data, "user", 4) == 0) {
+
+               if (strnicmp(data, "user_xattr",10) == 0) {/*parse before user*/
+                       vol->no_xattr = 0;
+               } else if (strnicmp(data, "nouser_xattr",12) == 0) {
+                       vol->no_xattr = 1;
+               } else if (strnicmp(data, "user", 4) == 0) {
                        if (!value || !*value) {
                                printk(KERN_WARNING
                                       "CIFS: invalid or missing username\n");
@@ -573,9 +780,18 @@ cifs_parse_mount_options(char *options, const char *devname,struct smb_vol *vol)
                                return 1;
                        }
                } else if (strnicmp(data, "pass", 4) == 0) {
-                       if (!value || !*value) {
+                       if (!value) {
                                vol->password = NULL;
                                continue;
+                       } else if(value[0] == 0) {
+                               /* check if string begins with double comma
+                                  since that would mean the password really
+                                  does start with a comma, and would not
+                                  indicate an empty string */
+                               if(value[1] != separator[0]) {
+                                       vol->password = NULL;
+                                       continue;
+                               }
                        }
                        temp_len = strlen(value);
                        /* removed password length check, NTLM passwords
@@ -590,15 +806,23 @@ cifs_parse_mount_options(char *options, const char *devname,struct smb_vol *vol)
 
                        /* NB: password legally can have multiple commas and
                        the only illegal character in a password is null */
-                               
-                       if ((value[temp_len] == 0) && (value[temp_len+1] == separator[0])) {
+
+                       if ((value[temp_len] == 0) && 
+                           (value[temp_len+1] == separator[0])) {
                                /* reinsert comma */
                                value[temp_len] = separator[0];
                                temp_len+=2;  /* move after the second comma */
                                while(value[temp_len] != 0)  {
-                                       if((value[temp_len] == separator[0]) && (value[temp_len+1] != separator[0])) {
-                                               /* single comma indicating start of next parm */
-                                               break;
+                                       if (value[temp_len] == separator[0]) {
+                                               if (value[temp_len+1] == 
+                                                    separator[0]) {
+                                               /* skip second comma */
+                                                       temp_len++;
+                                               } else { 
+                                               /* single comma indicating start
+                                                        of next parm */
+                                                       break;
+                                               }
                                        }
                                        temp_len++;
                                }
@@ -606,22 +830,32 @@ cifs_parse_mount_options(char *options, const char *devname,struct smb_vol *vol)
                                        options = NULL;
                                } else {
                                        value[temp_len] = 0;
-                                       /* move options to point to start of next parm */
+                                       /* point option to start of next parm */
                                        options = value + temp_len + 1;
                                }
-                               /* go from value to (value + temp_len) condensing double commas to singles */
-                               vol->password = cifs_kcalloc(temp_len, GFP_KERNEL);
+                               /* go from value to value + temp_len condensing 
+                               double commas to singles. Note that this ends up
+                               allocating a few bytes too many, which is ok */
+                               vol->password = kcalloc(1, temp_len, GFP_KERNEL);
+                               if(vol->password == NULL) {
+                                       printk("CIFS: no memory for pass\n");
+                                       return 1;
+                               }
                                for(i=0,j=0;i<temp_len;i++,j++) {
                                        vol->password[j] = value[i];
-                                       if(value[i] == separator[0] && value[i+1] == separator[0]) {
+                                       if(value[i] == separator[0]
+                                               && value[i+1] == separator[0]) {
                                                /* skip second comma */
                                                i++;
                                        }
                                }
-                               /* value[temp_len] is zeroed above so
-                                        vol->password[temp_len] guaranteed to be null */
+                               vol->password[j] = 0;
                        } else {
-                               vol->password = cifs_kcalloc(temp_len + 1, GFP_KERNEL);
+                               vol->password = kcalloc(1, temp_len+1, GFP_KERNEL);
+                               if(vol->password == NULL) {
+                                       printk("CIFS: no memory for pass\n");
+                                       return 1;
+                               }
                                strcpy(vol->password, value);
                        }
                } else if (strnicmp(data, "ip", 2) == 0) {
@@ -785,6 +1019,10 @@ cifs_parse_mount_options(char *options, const char *devname,struct smb_vol *vol)
                        vol->noperm = 0;
                } else if (strnicmp(data, "noperm", 6) == 0) {
                        vol->noperm = 1;
+               } else if (strnicmp(data, "mapchars", 8) == 0) {
+                       vol->remap = 1;
+               } else if (strnicmp(data, "nomapchars", 10) == 0) {
+                       vol->remap = 0;
                } else if (strnicmp(data, "setuids", 7) == 0) {
                        vol->setuids = 1;
                } else if (strnicmp(data, "nosetuids", 9) == 0) {
@@ -845,7 +1083,7 @@ cifs_parse_mount_options(char *options, const char *devname,struct smb_vol *vol)
                        return 1;
                }
        }
-       if(vol->UNCip == 0)
+       if(vol->UNCip == NULL)
                vol->UNCip = &vol->UNC[2];
 
        return 0;
@@ -933,14 +1171,15 @@ find_unc(__be32 new_target_ip_addr, char *uncName, char *userName)
 
 int
 connect_to_dfs_path(int xid, struct cifsSesInfo *pSesInfo,
-                   const char *old_path, const struct nls_table *nls_codepage)
+                   const char *old_path, const struct nls_table *nls_codepage,
+                   int remap)
 {
        unsigned char *referrals = NULL;
        unsigned int num_referrals;
        int rc = 0;
 
        rc = get_dfs_path(xid, pSesInfo,old_path, nls_codepage, 
-                       &num_referrals, &referrals);
+                       &num_referrals, &referrals, remap);
 
        /* BB Add in code to: if valid refrl, if not ip address contact
                the helper that resolves tcp names, mount to it, try to 
@@ -955,7 +1194,8 @@ connect_to_dfs_path(int xid, struct cifsSesInfo *pSesInfo,
 int
 get_dfs_path(int xid, struct cifsSesInfo *pSesInfo,
                        const char *old_path, const struct nls_table *nls_codepage, 
-                       unsigned int *pnum_referrals, unsigned char ** preferrals)
+                       unsigned int *pnum_referrals, 
+                       unsigned char ** preferrals, int remap)
 {
        char *temp_unc;
        int rc = 0;
@@ -980,7 +1220,7 @@ get_dfs_path(int xid, struct cifsSesInfo *pSesInfo,
        }
        if (rc == 0)
                rc = CIFSGetDFSRefer(xid, pSesInfo, old_path, preferrals,
-                                    pnum_referrals, nls_codepage);
+                                    pnum_referrals, nls_codepage, remap);
 
        return rc;
 }
@@ -1077,7 +1317,7 @@ ipv4_connect(struct sockaddr_in *psin_server, struct socket **csocket,
                sessinit is sent but no second negprot */
                struct rfc1002_session_packet * ses_init_buf;
                struct smb_hdr * smb_buf;
-               ses_init_buf = cifs_kcalloc(sizeof(struct rfc1002_session_packet), GFP_KERNEL);
+               ses_init_buf = kcalloc(1, sizeof(struct rfc1002_session_packet), GFP_KERNEL);
                if(ses_init_buf) {
                        ses_init_buf->trailer.session_req.called_len = 32;
                        rfc1002mangle(ses_init_buf->trailer.session_req.called_name,
@@ -1212,6 +1452,7 @@ cifs_mount(struct super_block *sb, struct cifs_sb_info *cifs_sb,
        }
 
        if (volume_info.username) {
+               /* BB fixme parse for domain name here */
                cFYI(1, ("Username: %s ", volume_info.username));
 
        } else {
@@ -1366,6 +1607,7 @@ cifs_mount(struct super_block *sb, struct cifs_sb_info *cifs_sb,
                        } else
                                rc = 0;
                        memcpy(srvTcp->workstation_RFC1001_name, volume_info.source_rfc1001_name,16);
+                       srvTcp->sequence_number = 0;
                }
        }
 
@@ -1409,14 +1651,14 @@ cifs_mount(struct super_block *sb, struct cifs_sb_info *cifs_sb,
     
        /* search for existing tcon to this server share */
        if (!rc) {
-               if((volume_info.rsize) && (volume_info.rsize + MAX_CIFS_HDR_SIZE < srvTcp->maxBuf))
+               if((volume_info.rsize) && (volume_info.rsize <= CIFSMaxBufSize))
                        cifs_sb->rsize = volume_info.rsize;
                else
                        cifs_sb->rsize = srvTcp->maxBuf - MAX_CIFS_HDR_SIZE; /* default */
-               if((volume_info.wsize) && (volume_info.wsize + MAX_CIFS_HDR_SIZE < srvTcp->maxBuf))
+               if((volume_info.wsize) && (volume_info.wsize <= CIFSMaxBufSize))
                        cifs_sb->wsize = volume_info.wsize;
                else
-                       cifs_sb->wsize = srvTcp->maxBuf - MAX_CIFS_HDR_SIZE; /* default */
+                       cifs_sb->wsize = CIFSMaxBufSize; /* default */
                if(cifs_sb->rsize < PAGE_CACHE_SIZE) {
                        cifs_sb->rsize = PAGE_CACHE_SIZE;
                        cERROR(1,("Attempt to set readsize for mount to less than one page (4096)"));
@@ -1433,6 +1675,10 @@ cifs_mount(struct super_block *sb, struct cifs_sb_info *cifs_sb,
                        cifs_sb->mnt_cifs_flags |= CIFS_MOUNT_SET_UID;
                if(volume_info.server_ino)
                        cifs_sb->mnt_cifs_flags |= CIFS_MOUNT_SERVER_INUM;
+               if(volume_info.remap)
+                       cifs_sb->mnt_cifs_flags |= CIFS_MOUNT_MAP_SPECIAL_CHR;
+               if(volume_info.no_xattr)
+                       cifs_sb->mnt_cifs_flags |= CIFS_MOUNT_NO_XATTR;
                if(volume_info.direct_io) {
                        cERROR(1,("mounting share using direct i/o"));
                        cifs_sb->mnt_cifs_flags |= CIFS_MOUNT_DIRECT_IO;
@@ -1459,11 +1705,10 @@ cifs_mount(struct super_block *sb, struct cifs_sb_info *cifs_sb,
                                if ((strchr(volume_info.UNC + 3, '\\') == NULL)
                                    && (strchr(volume_info.UNC + 3, '/') ==
                                        NULL)) {
-                                       rc = connect_to_dfs_path(xid,
-                                                                pSesInfo,
-                                                                "",
-                                                                cifs_sb->
-                                                                local_nls);
+                                       rc = connect_to_dfs_path(xid, pSesInfo,
+                                                       "", cifs_sb->local_nls,
+                                                       cifs_sb->mnt_cifs_flags & 
+                                                         CIFS_MOUNT_MAP_SPECIAL_CHR);
                                        if(volume_info.UNC)
                                                kfree(volume_info.UNC);
                                        FreeXid(xid);
@@ -1504,7 +1749,7 @@ cifs_mount(struct super_block *sb, struct cifs_sb_info *cifs_sb,
                 /* If find_unc succeeded then rc == 0 so we can not end */
                if (tcon)  /* up accidently freeing someone elses tcon struct */
                        tconInfoFree(tcon);
-               if (existingCifsSes == 0) {
+               if (existingCifsSes == NULL) {
                        if (pSesInfo) {
                                if ((pSesInfo->server) && 
                                    (pSesInfo->status == CifsGood)) {
@@ -1526,10 +1771,10 @@ cifs_mount(struct super_block *sb, struct cifs_sb_info *cifs_sb,
                tcon->ses = pSesInfo;
 
                /* do not care if following two calls succeed - informational only */
-               CIFSSMBQFSDeviceInfo(xid, tcon, cifs_sb->local_nls);
-               CIFSSMBQFSAttributeInfo(xid, tcon, cifs_sb->local_nls);
+               CIFSSMBQFSDeviceInfo(xid, tcon);
+               CIFSSMBQFSAttributeInfo(xid, tcon);
                if (tcon->ses->capabilities & CAP_UNIX) {
-                       if(!CIFSSMBQFSUnixInfo(xid, tcon, cifs_sb->local_nls)) {
+                       if(!CIFSSMBQFSUnixInfo(xid, tcon)) {
                                if(!volume_info.no_psx_acl) {
                                        if(CIFS_UNIX_POSIX_ACL_CAP & 
                                           le64_to_cpu(tcon->fsUnixInfo.Capability))
@@ -1575,7 +1820,7 @@ CIFSSessSetup(unsigned int xid, struct cifsSesInfo *ses,
        user = ses->userName;
        domain = ses->domainName;
        smb_buffer = cifs_buf_get();
-       if (smb_buffer == 0) {
+       if (smb_buffer == NULL) {
                return -ENOMEM;
        }
        smb_buffer_response = smb_buffer;
@@ -1592,7 +1837,8 @@ CIFSSessSetup(unsigned int xid, struct cifsSesInfo *ses,
        if(ses->server->secMode & (SECMODE_SIGN_REQUIRED | SECMODE_SIGN_ENABLED))
                smb_buffer->Flags2 |= SMBFLG2_SECURITY_SIGNATURE;
 
-       capabilities = CAP_LARGE_FILES | CAP_NT_SMBS | CAP_LEVEL_II_OPLOCKS;
+       capabilities = CAP_LARGE_FILES | CAP_NT_SMBS | CAP_LEVEL_II_OPLOCKS |
+               CAP_LARGE_WRITE_X | CAP_LARGE_READ_X;
        if (ses->capabilities & CAP_UNICODE) {
                smb_buffer->Flags2 |= SMBFLG2_UNICODE;
                capabilities |= CAP_UNICODE;
@@ -1619,7 +1865,7 @@ CIFSSessSetup(unsigned int xid, struct cifsSesInfo *ses,
        bcc_ptr += CIFS_SESSION_KEY_SIZE;
 
        if (ses->capabilities & CAP_UNICODE) {
-               if ((long) bcc_ptr % 2) {       /* must be word aligned for Unicode */
+               if ((long) bcc_ptr % 2) { /* must be word aligned for Unicode */
                        *bcc_ptr = 0;
                        bcc_ptr++;
                }
@@ -1629,7 +1875,8 @@ CIFSSessSetup(unsigned int xid, struct cifsSesInfo *ses,
                        bytes_returned =
                                cifs_strtoUCS((wchar_t *) bcc_ptr, user, 100,
                                        nls_codepage);
-               bcc_ptr += 2 * bytes_returned;  /* convert num 16 bit words to bytes */
+               /* convert number of 16 bit words to bytes */
+               bcc_ptr += 2 * bytes_returned;
                bcc_ptr += 2;   /* trailing null */
                if (domain == NULL)
                        bytes_returned =
@@ -1646,8 +1893,8 @@ CIFSSessSetup(unsigned int xid, struct cifsSesInfo *ses,
                                  32, nls_codepage);
                bcc_ptr += 2 * bytes_returned;
                bytes_returned =
-                   cifs_strtoUCS((wchar_t *) bcc_ptr, system_utsname.release, 32,
-                                 nls_codepage);
+                   cifs_strtoUCS((wchar_t *) bcc_ptr, system_utsname.release,
+                                 32, nls_codepage);
                bcc_ptr += 2 * bytes_returned;
                bcc_ptr += 2;
                bytes_returned =
@@ -1717,7 +1964,9 @@ CIFSSessSetup(unsigned int xid, struct cifsSesInfo *ses,
 /* We look for obvious messed up bcc or strings in response so we do not go off
    the end since (at least) WIN2K and Windows XP have a major bug in not null
    terminating last Unicode string in response  */
-                               ses->serverOS = cifs_kcalloc(2 * (len + 1), GFP_KERNEL);
+                               ses->serverOS = kcalloc(1, 2 * (len + 1), GFP_KERNEL);
+                               if(ses->serverOS == NULL)
+                                       goto sesssetup_nomem;
                                cifs_strfromUCS_le(ses->serverOS,
                                           (wchar_t *)bcc_ptr, len,nls_codepage);
                                bcc_ptr += 2 * (len + 1);
@@ -1727,18 +1976,27 @@ CIFSSessSetup(unsigned int xid, struct cifsSesInfo *ses,
                                if (remaining_words > 0) {
                                        len = UniStrnlen((wchar_t *)bcc_ptr,
                                                         remaining_words-1);
-                                       ses->serverNOS =cifs_kcalloc(2 * (len + 1),GFP_KERNEL);
+                                       ses->serverNOS = kcalloc(1, 2 * (len + 1),GFP_KERNEL);
+                                       if(ses->serverNOS == NULL)
+                                               goto sesssetup_nomem;
                                        cifs_strfromUCS_le(ses->serverNOS,
                                                           (wchar_t *)bcc_ptr,len,nls_codepage);
                                        bcc_ptr += 2 * (len + 1);
                                        ses->serverNOS[2 * len] = 0;
                                        ses->serverNOS[1 + (2 * len)] = 0;
+                                       if(strncmp(ses->serverNOS,
+                                               "NT LAN Manager 4",16) == 0) {
+                                               cFYI(1,("NT4 server"));
+                                               ses->flags |= CIFS_SES_NT4;
+                                       }
                                        remaining_words -= len + 1;
                                        if (remaining_words > 0) {
-                                               len = UniStrnlen((wchar_t *) bcc_ptr, remaining_words); 
+                                               len = UniStrnlen((wchar_t *) bcc_ptr, remaining_words);
           /* last string is not always null terminated (for e.g. for Windows XP & 2000) */
                                                ses->serverDomain =
-                                                   cifs_kcalloc(2*(len+1),GFP_KERNEL);
+                                                   kcalloc(1, 2*(len+1),GFP_KERNEL);
+                                               if(ses->serverDomain == NULL)
+                                                       goto sesssetup_nomem;
                                                cifs_strfromUCS_le(ses->serverDomain,
                                                     (wchar_t *)bcc_ptr,len,nls_codepage);
                                                bcc_ptr += 2 * (len + 1);
@@ -1746,21 +2004,25 @@ CIFSSessSetup(unsigned int xid, struct cifsSesInfo *ses,
                                                ses->serverDomain[1+(2*len)] = 0;
                                        } /* else no more room so create dummy domain string */
                                        else
-                                               ses->serverDomain =
-                                                   cifs_kcalloc(2,
-                                                           GFP_KERNEL);
+                                               ses->serverDomain = 
+                                                       kcalloc(1, 2, GFP_KERNEL);
                                } else {        /* no room so create dummy domain and NOS string */
+                                       /* if these kcallocs fail not much we
+                                          can do, but better to not fail the
+                                          sesssetup itself */
                                        ses->serverDomain =
-                                           cifs_kcalloc(2, GFP_KERNEL);
+                                           kcalloc(1, 2, GFP_KERNEL);
                                        ses->serverNOS =
-                                           cifs_kcalloc(2, GFP_KERNEL);
+                                           kcalloc(1, 2, GFP_KERNEL);
                                }
                        } else {        /* ASCII */
                                len = strnlen(bcc_ptr, 1024);
                                if (((long) bcc_ptr + len) - (long)
                                    pByteArea(smb_buffer_response)
                                            <= BCC(smb_buffer_response)) {
-                                       ses->serverOS = cifs_kcalloc(len + 1,GFP_KERNEL);
+                                       ses->serverOS = kcalloc(1, len + 1,GFP_KERNEL);
+                                       if(ses->serverOS == NULL)
+                                               goto sesssetup_nomem;
                                        strncpy(ses->serverOS,bcc_ptr, len);
 
                                        bcc_ptr += len;
@@ -1768,14 +2030,18 @@ CIFSSessSetup(unsigned int xid, struct cifsSesInfo *ses,
                                        bcc_ptr++;
 
                                        len = strnlen(bcc_ptr, 1024);
-                                       ses->serverNOS = cifs_kcalloc(len + 1,GFP_KERNEL);
+                                       ses->serverNOS = kcalloc(1, len + 1,GFP_KERNEL);
+                                       if(ses->serverNOS == NULL)
+                                               goto sesssetup_nomem;
                                        strncpy(ses->serverNOS, bcc_ptr, len);
                                        bcc_ptr += len;
                                        bcc_ptr[0] = 0;
                                        bcc_ptr++;
 
                                        len = strnlen(bcc_ptr, 1024);
-                                       ses->serverDomain = cifs_kcalloc(len + 1,GFP_KERNEL);
+                                       ses->serverDomain = kcalloc(1, len + 1,GFP_KERNEL);
+                                       if(ses->serverDomain == NULL)
+                                               goto sesssetup_nomem;
                                        strncpy(ses->serverDomain, bcc_ptr, len);
                                        bcc_ptr += len;
                                        bcc_ptr[0] = 0;
@@ -1795,7 +2061,9 @@ CIFSSessSetup(unsigned int xid, struct cifsSesInfo *ses,
                        smb_buffer_response->WordCount));
                rc = -EIO;
        }
-       
+sesssetup_nomem:       /* do not return an error on nomem for the info strings,
+                          since that could make reconnection harder, and
+                          reconnection might be needed to free memory */
        if (smb_buffer)
                cifs_buf_release(smb_buffer);
 
@@ -1828,7 +2096,7 @@ CIFSSpnegoSessSetup(unsigned int xid, struct cifsSesInfo *ses,
        domain = ses->domainName;
 
        smb_buffer = cifs_buf_get();
-       if (smb_buffer == 0) {
+       if (smb_buffer == NULL) {
                return -ENOMEM;
        }
        smb_buffer_response = smb_buffer;
@@ -1972,7 +2240,7 @@ CIFSSpnegoSessSetup(unsigned int xid, struct cifsSesInfo *ses,
    the end since (at least) WIN2K and Windows XP have a major bug in not null
    terminating last Unicode string in response  */
                                        ses->serverOS =
-                                           cifs_kcalloc(2 * (len + 1), GFP_KERNEL);
+                                           kcalloc(1, 2 * (len + 1), GFP_KERNEL);
                                        cifs_strfromUCS_le(ses->serverOS,
                                                           (wchar_t *)
                                                           bcc_ptr, len,
@@ -1986,7 +2254,7 @@ CIFSSpnegoSessSetup(unsigned int xid, struct cifsSesInfo *ses,
                                                                 remaining_words
                                                                 - 1);
                                                ses->serverNOS =
-                                                   cifs_kcalloc(2 * (len + 1),
+                                                   kcalloc(1, 2 * (len + 1),
                                                            GFP_KERNEL);
                                                cifs_strfromUCS_le(ses->serverNOS,
                                                                   (wchar_t *)bcc_ptr,
@@ -1999,7 +2267,7 @@ CIFSSpnegoSessSetup(unsigned int xid, struct cifsSesInfo *ses,
                                                if (remaining_words > 0) {
                                                        len = UniStrnlen((wchar_t *) bcc_ptr, remaining_words); 
                             /* last string is not always null terminated (for e.g. for Windows XP & 2000) */
-                                                       ses->serverDomain = cifs_kcalloc(2*(len+1),GFP_KERNEL);
+                                                       ses->serverDomain = kcalloc(1, 2*(len+1),GFP_KERNEL);
                                                        cifs_strfromUCS_le(ses->serverDomain,
                                                             (wchar_t *)bcc_ptr, 
                                  len,
@@ -2010,10 +2278,10 @@ CIFSSpnegoSessSetup(unsigned int xid, struct cifsSesInfo *ses,
                                                } /* else no more room so create dummy domain string */
                                                else
                                                        ses->serverDomain =
-                                                           cifs_kcalloc(2,GFP_KERNEL);
+                                                           kcalloc(1, 2,GFP_KERNEL);
                                        } else {        /* no room so create dummy domain and NOS string */
-                                               ses->serverDomain = cifs_kcalloc(2, GFP_KERNEL);
-                                               ses->serverNOS = cifs_kcalloc(2, GFP_KERNEL);
+                                               ses->serverDomain = kcalloc(1, 2, GFP_KERNEL);
+                                               ses->serverNOS = kcalloc(1, 2, GFP_KERNEL);
                                        }
                                } else {        /* ASCII */
 
@@ -2021,7 +2289,7 @@ CIFSSpnegoSessSetup(unsigned int xid, struct cifsSesInfo *ses,
                                        if (((long) bcc_ptr + len) - (long)
                                            pByteArea(smb_buffer_response)
                                            <= BCC(smb_buffer_response)) {
-                                               ses->serverOS = cifs_kcalloc(len + 1, GFP_KERNEL);
+                                               ses->serverOS = kcalloc(1, len + 1, GFP_KERNEL);
                                                strncpy(ses->serverOS, bcc_ptr, len);
 
                                                bcc_ptr += len;
@@ -2029,14 +2297,14 @@ CIFSSpnegoSessSetup(unsigned int xid, struct cifsSesInfo *ses,
                                                bcc_ptr++;
 
                                                len = strnlen(bcc_ptr, 1024);
-                                               ses->serverNOS = cifs_kcalloc(len + 1,GFP_KERNEL);
+                                               ses->serverNOS = kcalloc(1, len + 1,GFP_KERNEL);
                                                strncpy(ses->serverNOS, bcc_ptr, len);
                                                bcc_ptr += len;
                                                bcc_ptr[0] = 0;
                                                bcc_ptr++;
 
                                                len = strnlen(bcc_ptr, 1024);
-                                               ses->serverDomain = cifs_kcalloc(len + 1, GFP_KERNEL);
+                                               ses->serverDomain = kcalloc(1, len + 1, GFP_KERNEL);
                                                strncpy(ses->serverDomain, bcc_ptr, len);
                                                bcc_ptr += len;
                                                bcc_ptr[0] = 0;
@@ -2093,7 +2361,7 @@ CIFSNTLMSSPNegotiateSessSetup(unsigned int xid,
        domain = ses->domainName;
        *pNTLMv2_flag = FALSE;
        smb_buffer = cifs_buf_get();
-       if (smb_buffer == 0) {
+       if (smb_buffer == NULL) {
                return -ENOMEM;
        }
        smb_buffer_response = smb_buffer;
@@ -2286,7 +2554,7 @@ CIFSNTLMSSPNegotiateSessSetup(unsigned int xid,
    the end since (at least) WIN2K and Windows XP have a major bug in not null
    terminating last Unicode string in response  */
                                        ses->serverOS =
-                                           cifs_kcalloc(2 * (len + 1), GFP_KERNEL);
+                                           kcalloc(1, 2 * (len + 1), GFP_KERNEL);
                                        cifs_strfromUCS_le(ses->serverOS,
                                                           (wchar_t *)
                                                           bcc_ptr, len,
@@ -2301,7 +2569,7 @@ CIFSNTLMSSPNegotiateSessSetup(unsigned int xid,
                                                                 remaining_words
                                                                 - 1);
                                                ses->serverNOS =
-                                                   cifs_kcalloc(2 * (len + 1),
+                                                   kcalloc(1, 2 * (len + 1),
                                                            GFP_KERNEL);
                                                cifs_strfromUCS_le(ses->
                                                                   serverNOS,
@@ -2318,7 +2586,7 @@ CIFSNTLMSSPNegotiateSessSetup(unsigned int xid,
                                                        len = UniStrnlen((wchar_t *) bcc_ptr, remaining_words); 
            /* last string is not always null terminated (for e.g. for Windows XP & 2000) */
                                                        ses->serverDomain =
-                                                           cifs_kcalloc(2 *
+                                                           kcalloc(1, 2 *
                                                                    (len +
                                                                     1),
                                                                    GFP_KERNEL);
@@ -2344,13 +2612,13 @@ CIFSNTLMSSPNegotiateSessSetup(unsigned int xid,
                                                } /* else no more room so create dummy domain string */
                                                else
                                                        ses->serverDomain =
-                                                           cifs_kcalloc(2,
+                                                           kcalloc(1, 2,
                                                                    GFP_KERNEL);
                                        } else {        /* no room so create dummy domain and NOS string */
                                                ses->serverDomain =
-                                                   cifs_kcalloc(2, GFP_KERNEL);
+                                                   kcalloc(1, 2, GFP_KERNEL);
                                                ses->serverNOS =
-                                                   cifs_kcalloc(2, GFP_KERNEL);
+                                                   kcalloc(1, 2, GFP_KERNEL);
                                        }
                                } else {        /* ASCII */
                                        len = strnlen(bcc_ptr, 1024);
@@ -2358,7 +2626,7 @@ CIFSNTLMSSPNegotiateSessSetup(unsigned int xid,
                                            pByteArea(smb_buffer_response)
                                            <= BCC(smb_buffer_response)) {
                                                ses->serverOS =
-                                                   cifs_kcalloc(len + 1,
+                                                   kcalloc(1, len + 1,
                                                            GFP_KERNEL);
                                                strncpy(ses->serverOS,
                                                        bcc_ptr, len);
@@ -2369,7 +2637,7 @@ CIFSNTLMSSPNegotiateSessSetup(unsigned int xid,
 
                                                len = strnlen(bcc_ptr, 1024);
                                                ses->serverNOS =
-                                                   cifs_kcalloc(len + 1,
+                                                   kcalloc(1, len + 1,
                                                            GFP_KERNEL);
                                                strncpy(ses->serverNOS, bcc_ptr, len);
                                                bcc_ptr += len;
@@ -2378,7 +2646,7 @@ CIFSNTLMSSPNegotiateSessSetup(unsigned int xid,
 
                                                len = strnlen(bcc_ptr, 1024);
                                                ses->serverDomain =
-                                                   cifs_kcalloc(len + 1,
+                                                   kcalloc(1, len + 1,
                                                            GFP_KERNEL);
                                                strncpy(ses->serverDomain, bcc_ptr, len);       
                                                bcc_ptr += len;
@@ -2435,7 +2703,7 @@ CIFSNTLMSSPAuthSessSetup(unsigned int xid, struct cifsSesInfo *ses,
        user = ses->userName;
        domain = ses->domainName;
        smb_buffer = cifs_buf_get();
-       if (smb_buffer == 0) {
+       if (smb_buffer == NULL) {
                return -ENOMEM;
        }
        smb_buffer_response = smb_buffer;
@@ -2680,7 +2948,7 @@ CIFSNTLMSSPAuthSessSetup(unsigned int xid, struct cifsSesInfo *ses,
   the end since (at least) WIN2K and Windows XP have a major bug in not null
   terminating last Unicode string in response  */
                                        ses->serverOS =
-                                           cifs_kcalloc(2 * (len + 1), GFP_KERNEL);
+                                           kcalloc(1, 2 * (len + 1), GFP_KERNEL);
                                        cifs_strfromUCS_le(ses->serverOS,
                                                           (wchar_t *)
                                                           bcc_ptr, len,
@@ -2695,7 +2963,7 @@ CIFSNTLMSSPAuthSessSetup(unsigned int xid, struct cifsSesInfo *ses,
                                                                 remaining_words
                                                                 - 1);
                                                ses->serverNOS =
-                                                   cifs_kcalloc(2 * (len + 1),
+                                                   kcalloc(1, 2 * (len + 1),
                                                            GFP_KERNEL);
                                                cifs_strfromUCS_le(ses->
                                                                   serverNOS,
@@ -2711,7 +2979,7 @@ CIFSNTLMSSPAuthSessSetup(unsigned int xid, struct cifsSesInfo *ses,
                                                        len = UniStrnlen((wchar_t *) bcc_ptr, remaining_words); 
      /* last string not always null terminated (e.g. for Windows XP & 2000) */
                                                        ses->serverDomain =
-                                                           cifs_kcalloc(2 *
+                                                           kcalloc(1, 2 *
                                                                    (len +
                                                                     1),
                                                                    GFP_KERNEL);
@@ -2736,17 +3004,17 @@ CIFSNTLMSSPAuthSessSetup(unsigned int xid, struct cifsSesInfo *ses,
                                                            = 0;
                                                } /* else no more room so create dummy domain string */
                                                else
-                                                       ses->serverDomain = cifs_kcalloc(2,GFP_KERNEL);
+                                                       ses->serverDomain = kcalloc(1, 2,GFP_KERNEL);
                                        } else {  /* no room so create dummy domain and NOS string */
-                                               ses->serverDomain = cifs_kcalloc(2, GFP_KERNEL);
-                                               ses->serverNOS = cifs_kcalloc(2, GFP_KERNEL);
+                                               ses->serverDomain = kcalloc(1, 2, GFP_KERNEL);
+                                               ses->serverNOS = kcalloc(1, 2, GFP_KERNEL);
                                        }
                                } else {        /* ASCII */
                                        len = strnlen(bcc_ptr, 1024);
                                        if (((long) bcc_ptr + len) - 
                         (long) pByteArea(smb_buffer_response) 
                             <= BCC(smb_buffer_response)) {
-                                               ses->serverOS = cifs_kcalloc(len + 1,GFP_KERNEL);
+                                               ses->serverOS = kcalloc(1, len + 1,GFP_KERNEL);
                                                strncpy(ses->serverOS,bcc_ptr, len);
 
                                                bcc_ptr += len;
@@ -2754,14 +3022,14 @@ CIFSNTLMSSPAuthSessSetup(unsigned int xid, struct cifsSesInfo *ses,
                                                bcc_ptr++;
 
                                                len = strnlen(bcc_ptr, 1024);
-                                               ses->serverNOS = cifs_kcalloc(len+1,GFP_KERNEL);
+                                               ses->serverNOS = kcalloc(1, len+1,GFP_KERNEL);
                                                strncpy(ses->serverNOS, bcc_ptr, len);  
                                                bcc_ptr += len;
                                                bcc_ptr[0] = 0;
                                                bcc_ptr++;
 
                                                len = strnlen(bcc_ptr, 1024);
-                                               ses->serverDomain = cifs_kcalloc(len+1,GFP_KERNEL);
+                                               ses->serverDomain = kcalloc(1, len+1,GFP_KERNEL);
                                                strncpy(ses->serverDomain, bcc_ptr, len);
                                                bcc_ptr += len;
                                                bcc_ptr[0] = 0;
@@ -2809,7 +3077,7 @@ CIFSTCon(unsigned int xid, struct cifsSesInfo *ses,
                return -EIO;
 
        smb_buffer = cifs_buf_get();
-       if (smb_buffer == 0) {
+       if (smb_buffer == NULL) {
                return -ENOMEM;
        }
        smb_buffer_response = smb_buffer;
@@ -2873,7 +3141,7 @@ CIFSTCon(unsigned int xid, struct cifsSesInfo *ses,
                                if(tcon->nativeFileSystem)
                                        kfree(tcon->nativeFileSystem);
                                tcon->nativeFileSystem =
-                                   cifs_kcalloc(length + 2, GFP_KERNEL);
+                                   kcalloc(1, length + 2, GFP_KERNEL);
                                cifs_strfromUCS_le(tcon->nativeFileSystem,
                                                   (wchar_t *) bcc_ptr,
                                                   length, nls_codepage);
@@ -2891,7 +3159,7 @@ CIFSTCon(unsigned int xid, struct cifsSesInfo *ses,
                                if(tcon->nativeFileSystem)
                                        kfree(tcon->nativeFileSystem);
                                tcon->nativeFileSystem =
-                                   cifs_kcalloc(length + 1, GFP_KERNEL);
+                                   kcalloc(1, length + 1, GFP_KERNEL);
                                strncpy(tcon->nativeFileSystem, bcc_ptr,
                                        length);
                        }
@@ -2937,7 +3205,8 @@ cifs_umount(struct super_block *sb, struct cifs_sb_info *cifs_sb)
                                return 0;
                        } else if (rc == -ESHUTDOWN) {
                                cFYI(1,("Waking up socket by sending it signal"));
-                               send_sig(SIGKILL,cifsd_task,1);
+                               if(cifsd_task)
+                                       send_sig(SIGKILL,cifsd_task,1);
                                rc = 0;
                        } /* else - we have an smb session
                                left on this socket do not kill cifsd */
@@ -2963,6 +3232,7 @@ int cifs_setup_session(unsigned int xid, struct cifsSesInfo *pSesInfo,
        int rc = 0;
        char ntlm_session_key[CIFS_SESSION_KEY_SIZE];
        int ntlmv2_flag = FALSE;
+       int first_time = 0;
 
        /* what if server changes its buffer size after dropping the session? */
        if(pSesInfo->server->maxBuf == 0) /* no need to send on reconnect */ {
@@ -2981,12 +3251,13 @@ int cifs_setup_session(unsigned int xid, struct cifsSesInfo *pSesInfo,
                        spin_unlock(&GlobalMid_Lock);
 
                }
+               first_time = 1;
        }
        if (!rc) {
                pSesInfo->capabilities = pSesInfo->server->capabilities;
                if(linuxExtEnabled == 0)
                        pSesInfo->capabilities &= (~CAP_UNIX);
-               pSesInfo->sequence_number = 0;
+       /*      pSesInfo->sequence_number = 0;*/
                cFYI(1,("Security Mode: 0x%x Capabilities: 0x%x Time Zone: %d",
                        pSesInfo->server->secMode,
                        pSesInfo->server->capabilities,
@@ -3011,25 +3282,35 @@ int cifs_setup_session(unsigned int xid, struct cifsSesInfo *pSesInfo,
                                if(ntlmv2_flag) {
                                        char * v2_response;
                                        cFYI(1,("Can use more secure NTLM version 2 password hash"));
-                                       CalcNTLMv2_partial_mac_key(pSesInfo, 
-                                               nls_info);
-                                       v2_response = kmalloc(16 + 64 /* blob */, GFP_KERNEL);
+                                       if(CalcNTLMv2_partial_mac_key(pSesInfo, 
+                                               nls_info)) {
+                                               rc = -ENOMEM;
+                                               goto ss_err_exit;
+                                       } else
+                                               v2_response = kmalloc(16 + 64 /* blob */, GFP_KERNEL);
                                        if(v2_response) {
                                                CalcNTLMv2_response(pSesInfo,v2_response);
-/*                                             cifs_calculate_ntlmv2_mac_key(pSesInfo->mac_signing_key, response, ntlm_session_key, */
+                               /*              if(first_time)
+                                                       cifs_calculate_ntlmv2_mac_key(
+                                                         pSesInfo->server->mac_signing_key, 
+                                                         response, ntlm_session_key, */
                                                kfree(v2_response);
                                        /* BB Put dummy sig in SessSetup PDU? */
-                                       } else
+                                       } else {
                                                rc = -ENOMEM;
+                                               goto ss_err_exit;
+                                       }
 
                                } else {
                                        SMBNTencrypt(pSesInfo->password,
                                                pSesInfo->server->cryptKey,
                                                ntlm_session_key);
 
-                                       cifs_calculate_mac_key(pSesInfo->mac_signing_key,
-                                               ntlm_session_key,
-                                               pSesInfo->password);
+                                       if(first_time)
+                                               cifs_calculate_mac_key(
+                                                       pSesInfo->server->mac_signing_key,
+                                                       ntlm_session_key,
+                                                       pSesInfo->password);
                                }
                        /* for better security the weaker lanman hash not sent
                           in AuthSessSetup so we no longer calculate it */
@@ -3045,8 +3326,11 @@ int cifs_setup_session(unsigned int xid, struct cifsSesInfo *pSesInfo,
                                pSesInfo->server->cryptKey,
                                ntlm_session_key);
 
-                       cifs_calculate_mac_key(pSesInfo->mac_signing_key, 
-                               ntlm_session_key, pSesInfo->password);
+                       if(first_time)          
+                               cifs_calculate_mac_key(
+                                       pSesInfo->server->mac_signing_key,
+                                       ntlm_session_key, pSesInfo->password);
+
                        rc = CIFSSessSetup(xid, pSesInfo,
                                ntlm_session_key, nls_info);
                }
@@ -3057,6 +3341,7 @@ int cifs_setup_session(unsigned int xid, struct cifsSesInfo *pSesInfo,
                        pSesInfo->status = CifsGood;
                }
        }
+ss_err_exit:
        return rc;
 }