fedora core 6 1.2949 + vserver 2.2.0
[linux-2.6.git] / fs / cifs / connect.c
index bb6b0f3..2caca06 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,2006
  *   Author(s): Steve French (sfrench@us.ibm.com)
  *
  *   This library is free software; you can redistribute it and/or modify
 #include <linux/string.h>
 #include <linux/list.h>
 #include <linux/wait.h>
-#include <linux/version.h>
 #include <linux/ipv6.h>
 #include <linux/pagemap.h>
 #include <linux/ctype.h>
 #include <linux/utsname.h>
 #include <linux/mempool.h>
+#include <linux/delay.h>
+#include <linux/completion.h>
+#include <linux/pagevec.h>
+#include <linux/freezer.h>
 #include <asm/uaccess.h>
 #include <asm/processor.h>
 #include "cifspdu.h"
 #include "ntlmssp.h"
 #include "nterr.h"
 #include "rfc1002pdu.h"
+#include "cn_cifs.h"
 
 #define CIFS_PORT 445
 #define RFC1001_PORT 139
 
-extern void SMBencrypt(unsigned char *passwd, unsigned char *c8,
-                      unsigned char *p24);
+static DECLARE_COMPLETION(cifsd_complete);
+
 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;
 
@@ -58,26 +61,42 @@ struct smb_vol {
        char *domainname;
        char *UNC;
        char *UNCip;
+       char *in6_addr;  /* ipv6 address as human readable form of in6_addr */
        char *iocharset;  /* local code page for mapping to and from Unicode */
        char source_rfc1001_name[16]; /* netbios name of client */
+       char target_rfc1001_name[16]; /* netbios name of server for Win9x/ME */
        uid_t linux_uid;
        gid_t linux_gid;
        mode_t file_mode;
        mode_t dir_mode;
-       int rw:1;
-       int retry:1;
-       int intr:1;
-       int setuids:1;
-       int noperm:1;
+       unsigned secFlg;
+       unsigned rw:1;
+       unsigned retry:1;
+       unsigned intr:1;
+       unsigned setuids:1;
+       unsigned noperm:1;
+       unsigned no_psx_acl:1; /* set if posix acl support should be disabled */
+       unsigned cifs_acl:1;
+       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 posix_paths:1;   /* unset to not ask for posix pathnames. */
+       unsigned sfu_emul:1;
+       unsigned nullauth:1; /* attempt to authenticate with null user */
+       unsigned nocase;     /* request case insensitive filenames */
+       unsigned nobrl;      /* disable sending byte range locks to srv */
        unsigned int rsize;
        unsigned int wsize;
        unsigned int sockopt;
        unsigned short int port;
+       char * prepath;
 };
 
 static int ipv4_connect(struct sockaddr_in *psin_server, 
                        struct socket **csocket,
-                       char * netb_name);
+                       char * netb_name,
+                       char * server_netb_name);
 static int ipv6_connect(struct sockaddr_in6 *psin_server, 
                        struct socket **csocket);
 
@@ -91,7 +110,7 @@ static int ipv6_connect(struct sockaddr_in6 *psin_server,
         * wake up waiters on reconnection? - (not needed currently)
         */
 
-int
+static int
 cifs_reconnect(struct TCP_Server_Info *server)
 {
        int rc = 0;
@@ -111,7 +130,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 */
@@ -152,9 +171,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;
                        }
                }
@@ -164,22 +184,25 @@ cifs_reconnect(struct TCP_Server_Info *server)
 
        while ((server->tcpStatus != CifsExiting) && (server->tcpStatus != CifsGood))
        {
+               try_to_freeze();
                if(server->protocolType == IPV6) {
                        rc = ipv6_connect(&server->addr.sockAddr6,&server->ssocket);
                } else {
                        rc = ipv4_connect(&server->addr.sockAddr, 
                                        &server->ssocket,
-                                       server->workstation_RFC1001_name);
+                                       server->workstation_RFC1001_name,
+                                       server->server_RFC1001_name);
                }
                if(rc) {
-                       set_current_state(TASK_INTERRUPTIBLE);
-                       schedule_timeout(3 * HZ);
+                       cFYI(1,("reconnect error %d",rc));
+                       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);
                }
@@ -187,12 +210,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 = 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 = 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;
@@ -200,244 +340,346 @@ cifs_demultiplex_thread(struct TCP_Server_Info *server)
        struct cifsSesInfo *ses;
        struct task_struct *task_to_wake = NULL;
        struct mid_q_entry *mid_entry;
-       char *temp;
+       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);
+       complete(&cifsd_complete);
        if(length  > 1) {
                mempool_resize(cifs_req_poolp,
-                       length + CIFS_MIN_RCV_POOL,
+                       length + cifs_min_rcv,
                        GFP_KERNEL);
        }
 
        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 */
+               if (try_to_freeze())
                        continue;
+               if (bigbuf == NULL) {
+                       bigbuf = cifs_buf_get();
+                       if (!bigbuf) {
+                               cERROR(1, ("No memory for large SMB response"));
+                               msleep(3000);
+                               /* retry will check if exiting */
+                               continue;
+                       }
+               } else if (isLargeBuf) {
+                       /* we are reusing a dirty large buf, clear its start */
+                       memset(bigbuf, 0, sizeof (struct smb_hdr));
                }
+
+               if (smallbuf == NULL) {
+                       smallbuf = cifs_small_buf_get();
+                       if (!smallbuf) {
+                               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) {
+               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"));
+                       cFYI(1, ("call to reconnect done"));
                        csocket = server->ssocket;
                        continue;
                } else if ((length == -ERESTARTSYS) || (length == -EAGAIN)) {
-                       set_current_state(TASK_INTERRUPTIBLE);
-                       schedule_timeout(1); /* minimum sleep to prevent looping
+                       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 */
+                       if (server->tcpStatus == CifsNew) {
+                               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) { 
+                       if (!try_to_freeze() && (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);
-               /* Ony 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));
-
-               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 = 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);
+               /* The right amount was read from socket - 4 bytes */
+               /* so we can now interpret the length field */
+
+               /* the first byte big endian of the length field,
+               is actually not part of the length but the type
+               with the most common, zero, as regular data */
+               temp = *((char *) smb_buffer);
+
+               /* Note that FC 1001 length is big endian on the wire, 
+               but we convert it here so it is always manipulated
+               as host byte order */
+               pdu_length = ntohl(smb_buffer->smb_buf_length);
+               smb_buffer->smb_buf_length = pdu_length;
+
+               cFYI(1,("rfc1002 length 0x%x)", pdu_length+4));
+
+               if (temp == (char) RFC1002_SESSION_KEEP_ALIVE) {
+                       continue; 
+               } else if (temp == (char)RFC1002_POSITIVE_SESSION_RESPONSE) {
+                       cFYI(1,("Good RFC 1002 session rsp"));
+                       continue;
+               } else if (temp == (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)",
+                               pdu_length));
+                       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 != sizeof (struct smb_hdr) - 1)
-                                   || (pdu_length >
-                                       CIFS_MAX_MSGSIZE + 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_lenght %d",
-                                               length, pdu_length));
-                                       cifs_dump_mem("Received Data is: ",temp,sizeof(struct smb_hdr));
-                                       /* 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 != (char) 0) {
+                       cERROR(1,("Unknown RFC 1002 frame"));
+                       cifs_dump_mem(" Received Data: ", (char *)smb_buffer,
+                                     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_SMALL_BUFFER_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)) {
+                       cifs_dump_mem("Bad SMB: ", smb_buffer, 48);
+                       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)) {
+                                                       mid_entry->multiRsp = 1;
+                                                       break;
+                                               } else {
+                                                       /* all parts received */
+                                                       mid_entry->multiEnd = 1;
+                                                       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;
+#ifdef CONFIG_CIFS_STATS2
+                               mid_entry->when_received = jiffies;
+#endif
+                               /* so we do not time out requests to  server
+                               which is still responding (since server could
+                               be busy but not dead) */
+                               server->lstrp = jiffies;
+                               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, server) == FALSE)
+                   && (isMultiRsp == FALSE)) {                          
+                       cERROR(1, ("No task to wake, unknown frame rcvd! NumMids %d", midCount.counter));
+                       cifs_dump_mem("Received Data is: ",(char *)smb_buffer,
+                                     sizeof(struct smb_hdr));
+#ifdef CONFIG_CIFS_DEBUG2
+                       cifs_dump_detail(smb_buffer);
+                       cifs_dump_mids(server);
+#endif /* CIFS_DEBUG2 */
+                       
                }
-       }
+       } /* 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,
@@ -449,12 +691,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);
@@ -463,49 +716,53 @@ 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)) {
+       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_POOL,
+                       length + cifs_min_rcv,
                        GFP_KERNEL);
        }
-
-       set_current_state(TASK_INTERRUPTIBLE);
-       schedule_timeout(HZ/4);
+       
+       complete_and_exit(&cifsd_complete, 0);
        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)
+cifs_parse_mount_options(char *options, const char *devname,struct smb_vol *vol)
 {
        char *value;
        char *data;
@@ -515,15 +772,23 @@ cifs_parse_mount_options(char *options, const char *devname, struct smb_vol *vol
        separator[0] = ',';
        separator[1] = 0; 
 
-       memset(vol->source_rfc1001_name,0x20,15);
-       for(i=0;i < strnlen(system_utsname.nodename,15);i++) {
-               /* 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]);
+       if (Local_System_Name[0] != 0)
+               memcpy(vol->source_rfc1001_name, Local_System_Name,15);
+       else {
+               char *nodename = utsname()->nodename;
+               int n = strnlen(nodename,15);
+               memset(vol->source_rfc1001_name,0x20,15);
+               for(i=0 ; i < n ; i++) {
+                       /* does not have to be perfect mapping since 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(nodename[i]);
+               }
        }
        vol->source_rfc1001_name[15] = 0;
-
+       /* null target name indicates to use *SMBSERVR default called name
+          if we end up sending RFC1001 session initialize */
+       vol->target_rfc1001_name[0] = 0;
        vol->linux_uid = current->uid;  /* current->euid instead? */
        vol->linux_gid = current->gid;
        vol->dir_mode = S_IRWXUGO;
@@ -532,6 +797,8 @@ cifs_parse_mount_options(char *options, const char *devname, struct smb_vol *vol
 
        /* vol->retry default is 0 (i.e. "soft" limited retry not hard retry) */
        vol->rw = TRUE;
+       /* default is always to request posix paths. */
+       vol->posix_paths = 1;
 
        if (!options)
                return 1;
@@ -550,11 +817,19 @@ 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 (!value || !*value) {
+
+               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) {
                                printk(KERN_WARNING
                                       "CIFS: invalid or missing username\n");
                                return 1;       /* needs_arg; */
+                       } else if(!*value) {
+                               /* null user, ie anonymous, authentication */
+                               vol->nullauth = 1;
                        }
                        if (strnlen(value, 200) < 200) {
                                vol->username = value;
@@ -563,9 +838,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
@@ -580,15 +864,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++;
                                }
@@ -596,22 +888,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 = kzalloc(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 = kzalloc(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) {
@@ -623,6 +925,44 @@ cifs_parse_mount_options(char *options, const char *devname, struct smb_vol *vol
                                printk(KERN_WARNING "CIFS: ip address too long\n");
                                return 1;
                        }
+                } else if (strnicmp(data, "sec", 3) == 0) { 
+                        if (!value || !*value) {
+                               cERROR(1,("no security value specified"));
+                                continue;
+                        } else if (strnicmp(value, "krb5i", 5) == 0) {
+                               vol->secFlg |= CIFSSEC_MAY_KRB5 | 
+                                       CIFSSEC_MUST_SIGN;
+                       } else if (strnicmp(value, "krb5p", 5) == 0) {
+                               /* vol->secFlg |= CIFSSEC_MUST_SEAL | 
+                                       CIFSSEC_MAY_KRB5; */ 
+                               cERROR(1,("Krb5 cifs privacy not supported"));
+                               return 1;
+                       } else if (strnicmp(value, "krb5", 4) == 0) {
+                               vol->secFlg |= CIFSSEC_MAY_KRB5;
+                       } else if (strnicmp(value, "ntlmv2i", 7) == 0) {
+                               vol->secFlg |= CIFSSEC_MAY_NTLMV2 |
+                                       CIFSSEC_MUST_SIGN;
+                       } else if (strnicmp(value, "ntlmv2", 6) == 0) {
+                               vol->secFlg |= CIFSSEC_MAY_NTLMV2;
+                       } else if (strnicmp(value, "ntlmi", 5) == 0) {
+                               vol->secFlg |= CIFSSEC_MAY_NTLM |
+                                       CIFSSEC_MUST_SIGN;
+                       } else if (strnicmp(value, "ntlm", 4) == 0) {
+                               /* ntlm is default so can be turned off too */
+                               vol->secFlg |= CIFSSEC_MAY_NTLM;
+                       } else if (strnicmp(value, "nontlm", 6) == 0) {
+                               /* BB is there a better way to do this? */
+                               vol->secFlg |= CIFSSEC_MAY_NTLMV2;
+#ifdef CONFIG_CIFS_WEAK_PW_HASH
+                       } else if (strnicmp(value, "lanman", 6) == 0) {
+                                vol->secFlg |= CIFSSEC_MAY_LANMAN;
+#endif
+                       } else if (strnicmp(value, "none", 4) == 0) {
+                               vol->nullauth = 1;
+                        } else {
+                                cERROR(1,("bad security option: %s", value));
+                                return 1;
+                        }
                } else if ((strnicmp(data, "unc", 3) == 0)
                           || (strnicmp(data, "target", 6) == 0)
                           || (strnicmp(data, "path", 4) == 0)) {
@@ -656,13 +996,35 @@ cifs_parse_mount_options(char *options, const char *devname, struct smb_vol *vol
                        }
                        /* BB are there cases in which a comma can be valid in
                        a domain name and need special handling? */
-                       if (strnlen(value, 65) < 65) {
+                       if (strnlen(value, 256) < 256) {
                                vol->domainname = value;
                                cFYI(1, ("Domain name set"));
                        } else {
                                printk(KERN_WARNING "CIFS: domain name too long\n");
                                return 1;
                        }
+                } else if (strnicmp(data, "prefixpath", 10) == 0) {
+                        if (!value || !*value) {
+                                printk(KERN_WARNING
+                                       "CIFS: invalid path prefix\n");
+                                return 1;       /* needs_arg; */
+                        }
+                        if ((temp_len = strnlen(value, 1024)) < 1024) {
+                               if(value[0] != '/')
+                                       temp_len++;  /* missing leading slash */
+                                vol->prepath = kmalloc(temp_len+1,GFP_KERNEL);
+                                if(vol->prepath == NULL)
+                                        return 1;
+                               if(value[0] != '/') {
+                                       vol->prepath[0] = '/';
+                                       strcpy(vol->prepath+1,value);
+                               } else
+                                       strcpy(vol->prepath,value);
+                               cFYI(1,("prefix path %s",vol->prepath));
+                        } else {
+                                printk(KERN_WARNING "CIFS: prefix too long\n");
+                                return 1;
+                        }
                } else if (strnicmp(data, "iocharset", 9) == 0) {
                        if (!value || !*value) {
                                printk(KERN_WARNING "CIFS: invalid iocharset specified\n");
@@ -692,7 +1054,12 @@ cifs_parse_mount_options(char *options, const char *devname, struct smb_vol *vol
                                vol->file_mode =
                                        simple_strtoul(value, &value, 0);
                        }
-               } else if (strnicmp(data, "dir_mode", 3) == 0) {
+               } else if (strnicmp(data, "dir_mode", 4) == 0) {
+                       if (value && *value) {
+                               vol->dir_mode =
+                                       simple_strtoul(value, &value, 0);
+                       }
+               } else if (strnicmp(data, "dirmode", 4) == 0) {
                        if (value && *value) {
                                vol->dir_mode =
                                        simple_strtoul(value, &value, 0);
@@ -736,12 +1103,38 @@ cifs_parse_mount_options(char *options, const char *devname, struct smb_vol *vol
                                /* The string has 16th byte zero still from
                                set at top of the function  */
                                if((i==15) && (value[i] != 0))
-                                       printk(KERN_WARNING "CIFS: netbiosname longer than 15 and was truncated.\n");
+                                       printk(KERN_WARNING "CIFS: netbiosname longer than 15 truncated.\n");
+                       }
+               } else if (strnicmp(data, "servern", 7) == 0) {
+                       /* servernetbiosname specified override *SMBSERVER */
+                       if (!value || !*value || (*value == ' ')) {
+                               cFYI(1,("empty server netbiosname specified"));
+                       } else {
+                               /* last byte, type, is 0x20 for servr type */
+                               memset(vol->target_rfc1001_name,0x20,16);
+
+                               for(i=0;i<15;i++) {
+                               /* BB are there cases in which a comma can be
+                                  valid in this workstation netbios name (and need
+                                  special handling)? */
+
+                               /* user or mount helper must uppercase netbiosname */
+                                       if (value[i]==0)
+                                               break;
+                                       else
+                                               vol->target_rfc1001_name[i] = value[i];
+                               }
+                               /* The string has 16th byte zero still from
+                                  set at top of the function  */
+                               if((i==15) && (value[i] != 0))
+                                       printk(KERN_WARNING "CIFS: server netbiosname longer than 15 truncated.\n");
                        }
                } else if (strnicmp(data, "credentials", 4) == 0) {
                        /* ignore */
                } else if (strnicmp(data, "version", 3) == 0) {
                        /* ignore */
+               } else if (strnicmp(data, "guest",5) == 0) {
+                       /* ignore */
                } else if (strnicmp(data, "rw", 2) == 0) {
                        vol->rw = TRUE;
                } else if ((strnicmp(data, "suid", 4) == 0) ||
@@ -768,6 +1161,31 @@ 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, "sfu", 3) == 0) {
+                        vol->sfu_emul = 1;
+                } else if (strnicmp(data, "nosfu", 5) == 0) {
+                        vol->sfu_emul = 0;
+               } else if (strnicmp(data, "posixpaths", 10) == 0) {
+                       vol->posix_paths = 1;
+               } else if (strnicmp(data, "noposixpaths", 12) == 0) {
+                       vol->posix_paths = 0;
+                } else if ((strnicmp(data, "nocase", 6) == 0) ||
+                          (strnicmp(data, "ignorecase", 10)  == 0)) {
+                        vol->nocase = 1;
+               } else if (strnicmp(data, "brl", 3) == 0) {
+                       vol->nobrl =  0;
+               } else if ((strnicmp(data, "nobrl", 5) == 0) || 
+                          (strnicmp(data, "nolock", 6) == 0)) {
+                       vol->nobrl =  1;
+                       /* turn off mandatory locking in mode
+                       if remote locking is turned off since the
+                       local vfs will do advisory */
+                       if(vol->file_mode == (S_IALLUGO & ~(S_ISUID | S_IXGRP)))
+                               vol->file_mode = S_IALLUGO;
                } else if (strnicmp(data, "setuids", 7) == 0) {
                        vol->setuids = 1;
                } else if (strnicmp(data, "nosetuids", 9) == 0) {
@@ -780,6 +1198,35 @@ cifs_parse_mount_options(char *options, const char *devname, struct smb_vol *vol
                        vol->intr = 0;
                } else if (strnicmp(data, "intr", 4) == 0) {
                        vol->intr = 1;
+               } else if (strnicmp(data, "serverino",7) == 0) {
+                       vol->server_ino = 1;
+               } else if (strnicmp(data, "noserverino",9) == 0) {
+                       vol->server_ino = 0;
+               } else if (strnicmp(data, "cifsacl",7) == 0) {
+                       vol->cifs_acl = 1;
+               } else if (strnicmp(data, "nocifsacl", 9) == 0) {
+                       vol->cifs_acl = 0;
+               } else if (strnicmp(data, "acl",3) == 0) {
+                       vol->no_psx_acl = 0;
+               } else if (strnicmp(data, "noacl",5) == 0) {
+                       vol->no_psx_acl = 1;
+               } else if (strnicmp(data, "sign",4) == 0) {
+                       vol->secFlg |= CIFSSEC_MUST_SIGN;
+/*             } else if (strnicmp(data, "seal",4) == 0) {
+                       vol->secFlg |= CIFSSEC_MUST_SEAL; */
+               } else if (strnicmp(data, "direct",6) == 0) {
+                       vol->direct_io = 1;
+               } else if (strnicmp(data, "forcedirectio",13) == 0) {
+                       vol->direct_io = 1;
+               } else if (strnicmp(data, "in6_addr",8) == 0) {
+                       if (!value || !*value) {
+                               vol->in6_addr = NULL;
+                       } else if (strnlen(value, 49) == 48) {
+                               vol->in6_addr = value;
+                       } else {
+                               printk(KERN_WARNING "CIFS: ip v6 address not 48 characters long\n");
+                               return 1;
+                       }
                } else if (strnicmp(data, "noac", 4) == 0) {
                        printk(KERN_WARNING "CIFS: Mount option noac not supported. Instead set /proc/fs/cifs/LookupCacheEnabled to 0\n");
                } else
@@ -807,26 +1254,30 @@ 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;
 }
 
 static struct cifsSesInfo *
-cifs_find_tcp_session(__u32 new_target_ip_addr,
+cifs_find_tcp_session(struct in_addr * target_ip_addr, 
+               struct in6_addr *target_ip6_addr,
                 char *userName, struct TCP_Server_Info **psrvTcp)
 {
        struct list_head *tmp;
        struct cifsSesInfo *ses;
-
        *psrvTcp = NULL;
        read_lock(&GlobalSMBSeslock);
+
        list_for_each(tmp, &GlobalSMBSessionList) {
                ses = list_entry(tmp, struct cifsSesInfo, cifsSessionList);
                if (ses->server) {
-                       if (ses->server->addr.sockAddr.sin_addr.s_addr ==
-                           new_target_ip_addr) {
+                       if((target_ip_addr && 
+                               (ses->server->addr.sockAddr.sin_addr.s_addr
+                                 == target_ip_addr->s_addr)) || (target_ip6_addr
+                               && memcmp(&ses->server->addr.sockAddr6.sin6_addr,
+                                       target_ip6_addr,sizeof(*target_ip6_addr)))){
                                /* BB lock server and tcp session and increment use count here?? */
                                *psrvTcp = ses->server; /* found a match on the TCP session */
                                /* BB check if reconnection needed */
@@ -845,40 +1296,42 @@ cifs_find_tcp_session(__u32 new_target_ip_addr,
 }
 
 static struct cifsTconInfo *
-find_unc(__u32 new_target_ip_addr, char *uncName, char *userName)
+find_unc(__be32 new_target_ip_addr, char *uncName, char *userName)
 {
        struct list_head *tmp;
        struct cifsTconInfo *tcon;
 
        read_lock(&GlobalSMBSeslock);
        list_for_each(tmp, &GlobalTreeConnectionList) {
-               cFYI(1, ("Next tcon - "));
+               cFYI(1, ("Next tcon"));
                tcon = list_entry(tmp, struct cifsTconInfo, cifsConnectionList);
                if (tcon->ses) {
                        if (tcon->ses->server) {
                                cFYI(1,
-                                    (" old ip addr: %x == new ip %x ?",
+                                    ("old ip addr: %x == new ip %x ?",
                                      tcon->ses->server->addr.sockAddr.sin_addr.
                                      s_addr, new_target_ip_addr));
                                if (tcon->ses->server->addr.sockAddr.sin_addr.
                                    s_addr == new_target_ip_addr) {
-       /* BB lock tcon and server and tcp session and increment use count here? */
+       /* BB lock tcon, server and tcp session and increment use count here? */
                                        /* found a match on the TCP session */
                                        /* BB check if reconnection needed */
-                                       cFYI(1,("Matched ip, old UNC: %s == new: %s ?",
+                                       cFYI(1,("IP match, old UNC: %s new: %s",
                                              tcon->treeName, uncName));
                                        if (strncmp
                                            (tcon->treeName, uncName,
                                             MAX_TREE_SIZE) == 0) {
                                                cFYI(1,
-                                                    ("Matched UNC, old user: %s == new: %s ?",
+                                                    ("and old usr: %s new: %s",
                                                      tcon->treeName, uncName));
                                                if (strncmp
                                                    (tcon->ses->userName,
                                                     userName,
                                                     MAX_USERNAME_SIZE) == 0) {
                                                        read_unlock(&GlobalSMBSeslock);
-                                                       return tcon;/* also matched user (smb session)*/
+                                                       /* matched smb session
+                                                       (user name */
+                                                       return tcon;
                                                }
                                        }
                                }
@@ -891,21 +1344,21 @@ find_unc(__u32 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 
                tcon to it unmount it if fail */
 
-       if(referrals)
-               kfree(referrals);
+       kfree(referrals);
 
        return rc;
 }
@@ -913,7 +1366,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;
@@ -938,7 +1392,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;
 }
@@ -960,11 +1414,11 @@ static void rfc1002mangle(char * target,char * source, unsigned int length)
 
 static int
 ipv4_connect(struct sockaddr_in *psin_server, struct socket **csocket, 
-                        char * netbios_name)
+            char * netbios_name, char * target_name)
 {
        int rc = 0;
        int connected = 0;
-       unsigned short int orig_port = 0;
+       __be16 orig_port = 0;
 
        if(*csocket == NULL) {
                rc = sock_create_kern(PF_INET, SOCK_STREAM, IPPROTO_TCP, csocket);
@@ -1025,21 +1479,33 @@ ipv4_connect(struct sockaddr_in *psin_server, struct socket **csocket,
        /* Eventually check for other socket options to change from 
                the default. sock_setsockopt not used because it expects 
                user space buffer */
+        cFYI(1,("sndbuf %d rcvbuf %d rcvtimeo 0x%lx",(*csocket)->sk->sk_sndbuf,
+                (*csocket)->sk->sk_rcvbuf, (*csocket)->sk->sk_rcvtimeo));
        (*csocket)->sk->sk_rcvtimeo = 7 * HZ;
+       /* make the bufsizes depend on wsize/rsize and max requests */
+       if((*csocket)->sk->sk_sndbuf < (200 * 1024))
+               (*csocket)->sk->sk_sndbuf = 200 * 1024;
+       if((*csocket)->sk->sk_rcvbuf < (140 * 1024))
+               (*csocket)->sk->sk_rcvbuf = 140 * 1024;
 
        /* send RFC1001 sessinit */
-
-       if(psin_server->sin_port == htons(139)) {
+       if(psin_server->sin_port == htons(RFC1001_PORT)) {
                /* some servers require RFC1001 sessinit before sending
                negprot - BB check reconnection in case where second 
                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 = kzalloc(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,
-                               DEFAULT_CIFS_CALLED_NAME,16);
+                       if(target_name && (target_name[0] != 0)) {
+                               rfc1002mangle(ses_init_buf->trailer.session_req.called_name,
+                                       target_name, 16);
+                       } else {
+                               rfc1002mangle(ses_init_buf->trailer.session_req.called_name,
+                                       DEFAULT_CIFS_CALLED_NAME,16);
+                       }
+
                        ses_init_buf->trailer.session_req.calling_len = 32;
                        /* calling name ends in null (byte 16) from old smb
                        convention. */
@@ -1058,6 +1524,14 @@ ipv4_connect(struct sockaddr_in *psin_server, struct socket **csocket,
                        rc = smb_send(*csocket, smb_buf, 0x44,
                                (struct sockaddr *)psin_server);
                        kfree(ses_init_buf);
+                       msleep(1); /* RFC1001 layer in at least one server 
+                                     requires very short break before negprot
+                                     presumably because not expecting negprot
+                                     to follow so fast.  This is a simple
+                                     solution that works without 
+                                     complicating the code and causes no
+                                     significant slowing down on mount
+                                     for everyone else */
                }
                /* else the negprot may still work without this 
                even though malloc failed */
@@ -1072,6 +1546,7 @@ ipv6_connect(struct sockaddr_in6 *psin_server, struct socket **csocket)
 {
        int rc = 0;
        int connected = 0;
+       __be16 orig_port = 0;
 
        if(*csocket == NULL) {
                rc = sock_create_kern(PF_INET6, SOCK_STREAM, IPPROTO_TCP, csocket);
@@ -1097,6 +1572,10 @@ ipv6_connect(struct sockaddr_in6 *psin_server, struct socket **csocket)
        } 
 
        if(!connected) {
+               /* save original port so we can retry user specified port  
+                       later if fall back ports fail this time  */
+
+               orig_port = psin_server->sin6_port;
                /* do not retry on the same port we just failed on */
                if(psin_server->sin6_port != htons(CIFS_PORT)) {
                        psin_server->sin6_port = htons(CIFS_PORT);
@@ -1119,6 +1598,8 @@ ipv6_connect(struct sockaddr_in6 *psin_server, struct socket **csocket)
        /* give up here - unless we want to retry on different
                protocol families some day */
        if (!connected) {
+               if(orig_port)
+                       psin_server->sin6_port = orig_port;
                cFYI(1,("Error %d connecting to server via ipv6",rc));
                sock_release(*csocket);
                *csocket = NULL;
@@ -1138,6 +1619,7 @@ cifs_mount(struct super_block *sb, struct cifs_sb_info *cifs_sb,
 {
        int rc = 0;
        int xid;
+       int address_type = AF_INET;
        struct socket *csocket = NULL;
        struct sockaddr_in sin_server;
        struct sockaddr_in6 sin_server6;
@@ -1153,25 +1635,26 @@ cifs_mount(struct super_block *sb, struct cifs_sb_info *cifs_sb,
        
        memset(&volume_info,0,sizeof(struct smb_vol));
        if (cifs_parse_mount_options(mount_data, devname, &volume_info)) {
-               if(volume_info.UNC)
-                       kfree(volume_info.UNC);
-               if(volume_info.password)
-                       kfree(volume_info.password);
+               kfree(volume_info.UNC);
+               kfree(volume_info.password);
+               kfree(volume_info.prepath);
                FreeXid(xid);
                return -EINVAL;
        }
 
        if (volume_info.username) {
+               /* BB fixme parse for domain name here */
                cFYI(1, ("Username: %s ", volume_info.username));
 
+       } else if (volume_info.nullauth) {
+               cFYI(1,("null user"));
        } else {
-               cifserror("No username specified ");
+               cifserror("No username specified");
         /* In userspace mount helper we can get user name from alternate
            locations such as env variables and files on disk */
-               if(volume_info.UNC)
-                       kfree(volume_info.UNC);
-               if(volume_info.password)
-                       kfree(volume_info.password);
+               kfree(volume_info.UNC);
+               kfree(volume_info.password);
+               kfree(volume_info.prepath);
                FreeXid(xid);
                return -EINVAL;
        }
@@ -1179,17 +1662,20 @@ cifs_mount(struct super_block *sb, struct cifs_sb_info *cifs_sb,
        if (volume_info.UNCip && volume_info.UNC) {
                rc = cifs_inet_pton(AF_INET, volume_info.UNCip,&sin_server.sin_addr.s_addr);
 
-               if(rc == 0) {
+               if(rc <= 0) {
                        /* not ipv4 address, try ipv6 */
                        rc = cifs_inet_pton(AF_INET6,volume_info.UNCip,&sin_server6.sin6_addr.in6_u); 
-               } 
+                       if(rc > 0)
+                               address_type = AF_INET6;
+               } else {
+                       address_type = AF_INET;
+               }
        
-               if(rc != 1) {
+               if(rc <= 0) {
                        /* we failed translating address */
-                       if(volume_info.UNC)
-                               kfree(volume_info.UNC);
-                       if(volume_info.password)
-                               kfree(volume_info.password);
+                       kfree(volume_info.UNC);
+                       kfree(volume_info.password);
+                       kfree(volume_info.prepath);
                        FreeXid(xid);
                        return -EINVAL;
                }
@@ -1200,19 +1686,17 @@ cifs_mount(struct super_block *sb, struct cifs_sb_info *cifs_sb,
        } else if (volume_info.UNCip){
                /* BB using ip addr as server name connect to the DFS root below */
                cERROR(1,("Connecting to DFS root not implemented yet"));
-               if(volume_info.UNC)
-                       kfree(volume_info.UNC);
-               if(volume_info.password)
-                       kfree(volume_info.password);
+               kfree(volume_info.UNC);
+               kfree(volume_info.password);
+               kfree(volume_info.prepath);
                FreeXid(xid);
                return -EINVAL;
        } else /* which servers DFS root would we conect to */ {
                cERROR(1,
-                      ("CIFS mount error: No UNC path (e.g. -o unc=//192.168.1.100/public) specified  "));
-               if(volume_info.UNC)
-                       kfree(volume_info.UNC);
-               if(volume_info.password)
-                       kfree(volume_info.password);
+                      ("CIFS mount error: No UNC path (e.g. -o unc=//192.168.1.100/public) specified"));
+               kfree(volume_info.UNC);
+               kfree(volume_info.password);
+               kfree(volume_info.prepath);
                FreeXid(xid);
                return -EINVAL;
        }
@@ -1225,35 +1709,49 @@ cifs_mount(struct super_block *sb, struct cifs_sb_info *cifs_sb,
                cifs_sb->local_nls = load_nls(volume_info.iocharset);
                if(cifs_sb->local_nls == NULL) {
                        cERROR(1,("CIFS mount error: iocharset %s not found",volume_info.iocharset));
-                       if(volume_info.UNC)
-                               kfree(volume_info.UNC);
-                       if(volume_info.password)
-                               kfree(volume_info.password);
+                       kfree(volume_info.UNC);
+                       kfree(volume_info.password);
+                       kfree(volume_info.prepath);
                        FreeXid(xid);
                        return -ELIBACC;
                }
        }
 
-       existingCifsSes =
-           cifs_find_tcp_session(sin_server.sin_addr.s_addr,
-                            volume_info.username, &srvTcp);
+       if(address_type == AF_INET)
+               existingCifsSes = cifs_find_tcp_session(&sin_server.sin_addr,
+                       NULL /* no ipv6 addr */,
+                       volume_info.username, &srvTcp);
+       else if(address_type == AF_INET6)
+               existingCifsSes = cifs_find_tcp_session(NULL /* no ipv4 addr */,
+                       &sin_server6.sin6_addr,
+                       volume_info.username, &srvTcp);
+       else {
+               kfree(volume_info.UNC);
+               kfree(volume_info.password);
+               kfree(volume_info.prepath);
+               FreeXid(xid);
+               return -EINVAL;
+       }
+
+
        if (srvTcp) {
-               cFYI(1, ("Existing tcp session with server found "));                
+               cFYI(1, ("Existing tcp session with server found"));                
        } else {        /* create socket */
                if(volume_info.port)
                        sin_server.sin_port = htons(volume_info.port);
                else
                        sin_server.sin_port = 0;
-               rc = ipv4_connect(&sin_server,&csocket,volume_info.source_rfc1001_name);
+               rc = ipv4_connect(&sin_server,&csocket,
+                                 volume_info.source_rfc1001_name,
+                                 volume_info.target_rfc1001_name);
                if (rc < 0) {
                        cERROR(1,
                               ("Error connecting to IPv4 socket. Aborting operation"));
                        if(csocket != NULL)
                                sock_release(csocket);
-                       if(volume_info.UNC)
-                               kfree(volume_info.UNC);
-                       if(volume_info.password)
-                               kfree(volume_info.password);
+                       kfree(volume_info.UNC);
+                       kfree(volume_info.password);
+                       kfree(volume_info.prepath);
                        FreeXid(xid);
                        return rc;
                }
@@ -1262,10 +1760,9 @@ cifs_mount(struct super_block *sb, struct cifs_sb_info *cifs_sb,
                if (srvTcp == NULL) {
                        rc = -ENOMEM;
                        sock_release(csocket);
-                       if(volume_info.UNC)
-                               kfree(volume_info.UNC);
-                       if(volume_info.password)
-                               kfree(volume_info.password);
+                       kfree(volume_info.UNC);
+                       kfree(volume_info.password);
+                       kfree(volume_info.prepath);
                        FreeXid(xid);
                        return rc;
                } else {
@@ -1283,20 +1780,32 @@ cifs_mount(struct super_block *sb, struct cifs_sb_info *cifs_sb,
                        so no need to spinlock this init of tcpStatus */
                        srvTcp->tcpStatus = CifsNew;
                        init_MUTEX(&srvTcp->tcpSem);
-                       kernel_thread((void *)(void *)cifs_demultiplex_thread, srvTcp,
+                       rc = (int)kernel_thread((void *)(void *)cifs_demultiplex_thread, srvTcp,
                                      CLONE_FS | CLONE_FILES | CLONE_VM);
+                       if(rc < 0) {
+                               rc = -ENOMEM;
+                               sock_release(csocket);
+                               kfree(volume_info.UNC);
+                               kfree(volume_info.password);
+                               kfree(volume_info.prepath);
+                               FreeXid(xid);
+                               return rc;
+                       }
+                       wait_for_completion(&cifsd_complete);
+                       rc = 0;
                        memcpy(srvTcp->workstation_RFC1001_name, volume_info.source_rfc1001_name,16);
+                       memcpy(srvTcp->server_RFC1001_name, volume_info.target_rfc1001_name,16);
+                       srvTcp->sequence_number = 0;
                }
        }
 
        if (existingCifsSes) {
                pSesInfo = existingCifsSes;
-               cFYI(1, ("Existing smb sess found "));
-               if(volume_info.password)
-                       kfree(volume_info.password);
+               cFYI(1, ("Existing smb sess found"));
+               kfree(volume_info.password);
                /* volume_info.UNC freed at end of function */
        } else if (!rc) {
-               cFYI(1, ("Existing smb sess not found "));
+               cFYI(1, ("Existing smb sess not found"));
                pSesInfo = sesInfoAlloc();
                if (pSesInfo == NULL)
                        rc = -ENOMEM;
@@ -1313,55 +1822,107 @@ cifs_mount(struct super_block *sb, struct cifs_sb_info *cifs_sb,
                        if (volume_info.username)
                                strncpy(pSesInfo->userName,
                                        volume_info.username,MAX_USERNAME_SIZE);
-                       if (volume_info.domainname)
-                               strncpy(pSesInfo->domainName,
-                                       volume_info.domainname,MAX_USERNAME_SIZE);
+                       if (volume_info.domainname) {
+                               int len = strlen(volume_info.domainname);
+                               pSesInfo->domainName = 
+                                       kmalloc(len + 1, GFP_KERNEL);
+                               if(pSesInfo->domainName)
+                                       strcpy(pSesInfo->domainName,
+                                               volume_info.domainname);
+                       }
                        pSesInfo->linux_uid = volume_info.linux_uid;
+                       pSesInfo->overrideSecFlg = volume_info.secFlg;
                        down(&pSesInfo->sesSem);
+                       /* BB FIXME need to pass vol->secFlgs BB */
                        rc = cifs_setup_session(xid,pSesInfo, cifs_sb->local_nls);
                        up(&pSesInfo->sesSem);
                        if(!rc)
                                atomic_inc(&srvTcp->socketUseCount);
                } else
-                       if(volume_info.password)
-                               kfree(volume_info.password);
+                       kfree(volume_info.password);
        }
     
        /* 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 > CIFSMaxBufSize) {
+                       cERROR(1,("rsize %d too large, using MaxBufSize",
+                               volume_info.rsize));
+                       cifs_sb->rsize = CIFSMaxBufSize;
+               } else 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))
+               else /* default */
+                       cifs_sb->rsize = CIFSMaxBufSize;
+
+               if(volume_info.wsize > PAGEVEC_SIZE * PAGE_CACHE_SIZE) {
+                       cERROR(1,("wsize %d too large using 4096 instead",
+                                 volume_info.wsize));
+                       cifs_sb->wsize = 4096;
+               } else if(volume_info.wsize)
                        cifs_sb->wsize = volume_info.wsize;
                else
-                       cifs_sb->wsize = srvTcp->maxBuf - MAX_CIFS_HDR_SIZE; /* 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)"));
+                       cifs_sb->wsize = 
+                               min_t(const int, PAGEVEC_SIZE * PAGE_CACHE_SIZE,
+                                       127*1024);
+                       /* old default of CIFSMaxBufSize was too small now
+                          that SMB Write2 can send multiple pages in kvec.   
+                          RFC1001 does not describe what happens when frame
+                          bigger than 128K is sent so use that as max in
+                          conjunction with 52K kvec constraint on arch with 4K
+                          page size  */
+
+               if(cifs_sb->rsize < 2048) {
+                       cifs_sb->rsize = 2048; 
+                       /* Windows ME may prefer this */
+                       cFYI(1,("readsize set to minimum 2048"));
                }
+               /* calculate prepath */
+               cifs_sb->prepath = volume_info.prepath;
+               if(cifs_sb->prepath) {
+                       cifs_sb->prepathlen = strlen(cifs_sb->prepath);
+                       cifs_sb->prepath[0] = CIFS_DIR_SEP(cifs_sb);
+                       volume_info.prepath = NULL;
+               } else 
+                       cifs_sb->prepathlen = 0;
                cifs_sb->mnt_uid = volume_info.linux_uid;
                cifs_sb->mnt_gid = volume_info.linux_gid;
                cifs_sb->mnt_file_mode = volume_info.file_mode;
                cifs_sb->mnt_dir_mode = volume_info.dir_mode;
-               cFYI(1,("file mode: 0x%x  dir mode: 0x%x",cifs_sb->mnt_file_mode,cifs_sb->mnt_dir_mode));
+               cFYI(1,("file mode: 0x%x  dir mode: 0x%x",
+                       cifs_sb->mnt_file_mode,cifs_sb->mnt_dir_mode));
 
                if(volume_info.noperm)
                        cifs_sb->mnt_cifs_flags |= CIFS_MOUNT_NO_PERM;
                if(volume_info.setuids)
                        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.sfu_emul)
+                       cifs_sb->mnt_cifs_flags |= CIFS_MOUNT_UNX_EMUL;
+               if(volume_info.nobrl)
+                       cifs_sb->mnt_cifs_flags |= CIFS_MOUNT_NO_BRL;
+               if(volume_info.cifs_acl)
+                       cifs_sb->mnt_cifs_flags |= CIFS_MOUNT_CIFS_ACL;
+
+               if(volume_info.direct_io) {
+                       cFYI(1,("mounting share using direct i/o"));
+                       cifs_sb->mnt_cifs_flags |= CIFS_MOUNT_DIRECT_IO;
+               }
 
                tcon =
                    find_unc(sin_server.sin_addr.s_addr, volume_info.UNC,
                             volume_info.username);
                if (tcon) {
-                       cFYI(1, ("Found match on UNC path "));
+                       cFYI(1, ("Found match on UNC path"));
                        /* we can have only one retry value for a connection
                           to a share so for resources mounted more than once
                           to the same server share the last value passed in 
                           for the retry flag is used */
                        tcon->retry = volume_info.retry;
+                       tcon->nocase = volume_info.nocase;
                } else {
                        tcon = tconInfoAlloc();
                        if (tcon == NULL)
@@ -1373,13 +1934,11 @@ 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);
-                                       if(volume_info.UNC)
-                                               kfree(volume_info.UNC);
+                                       rc = connect_to_dfs_path(xid, pSesInfo,
+                                                       "", cifs_sb->local_nls,
+                                                       cifs_sb->mnt_cifs_flags & 
+                                                         CIFS_MOUNT_MAP_SPECIAL_CHR);
+                                       kfree(volume_info.UNC);
                                        FreeXid(xid);
                                        return -ENODEV;
                                } else {
@@ -1391,6 +1950,7 @@ cifs_mount(struct super_block *sb, struct cifs_sb_info *cifs_sb,
                                if (!rc) {
                                        atomic_inc(&pSesInfo->inUse);
                                        tcon->retry = volume_info.retry;
+                                       tcon->nocase = volume_info.nocase;
                                }
                        }
                }
@@ -1402,6 +1962,8 @@ cifs_mount(struct super_block *sb, struct cifs_sb_info *cifs_sb,
                        sb->s_maxbytes = (u64) 1 << 31; /* 2 GB */
        }
 
+       sb->s_time_gran = 100;
+
 /* on error free sesinfo and tcon struct if needed */
        if (rc) {
                /* if session setup failed, use count is zero but
@@ -1410,13 +1972,15 @@ cifs_mount(struct super_block *sb, struct cifs_sb_info *cifs_sb,
                        spin_lock(&GlobalMid_Lock);
                        srvTcp->tcpStatus = CifsExiting;
                        spin_unlock(&GlobalMid_Lock);
-                       if(srvTcp->tsk)
+                       if(srvTcp->tsk) {
                                send_sig(SIGKILL,srvTcp->tsk,1);
+                               wait_for_completion(&cifsd_complete);
+                       }
                }
                 /* 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)) {
@@ -1424,8 +1988,10 @@ cifs_mount(struct super_block *sb, struct cifs_sb_info *cifs_sb,
                                        temp_rc = CIFSSMBLogoff(xid, pSesInfo);
                                        /* if the socketUseCount is now zero */
                                        if((temp_rc == -ESHUTDOWN) &&
-                                          (pSesInfo->server->tsk))
+                                          (pSesInfo->server->tsk)) {
                                                send_sig(SIGKILL,pSesInfo->server->tsk,1);
+                                               wait_for_completion(&cifsd_complete);
+                                       }
                                } else
                                        cFYI(1, ("No session or bad tcon"));
                                sesInfoFree(pSesInfo);
@@ -1437,26 +2003,71 @@ cifs_mount(struct super_block *sb, struct cifs_sb_info *cifs_sb,
                cifs_sb->tcon = tcon;
                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);
-               if (tcon->ses->capabilities & CAP_UNIX)
-                       CIFSSMBQFSUnixInfo(xid, tcon, cifs_sb->local_nls);
-       }
+               /* do not care if following two calls succeed - informational */
+               CIFSSMBQFSDeviceInfo(xid, tcon);
+               CIFSSMBQFSAttributeInfo(xid, tcon);
+
+               if (tcon->ses->capabilities & CAP_UNIX) {
+                       if(!CIFSSMBQFSUnixInfo(xid, tcon)) {
+                               __u64 cap = 
+                                      le64_to_cpu(tcon->fsUnixInfo.Capability);
+                               cap &= CIFS_UNIX_CAP_MASK;
+                               if(volume_info.no_psx_acl)
+                                       cap &= ~CIFS_UNIX_POSIX_ACL_CAP;
+                               else if(CIFS_UNIX_POSIX_ACL_CAP & cap) {
+                                       cFYI(1,("negotiated posix acl support"));
+                                       sb->s_flags |= MS_POSIXACL;
+                               }
 
-       /* volume_info.password is freed above when existing session found
-       (in which case it is not needed anymore) but when new sesion is created
-       the password ptr is put in the new session structure (in which case the
+                               if(volume_info.posix_paths == 0)
+                                       cap &= ~CIFS_UNIX_POSIX_PATHNAMES_CAP;
+                               else if(cap & CIFS_UNIX_POSIX_PATHNAMES_CAP) {
+                                       cFYI(1,("negotiate posix pathnames"));
+                                       cifs_sb->mnt_cifs_flags |= 
+                                               CIFS_MOUNT_POSIX_PATHS;
+                               }
+                                       
+                               cFYI(1,("Negotiate caps 0x%x",(int)cap));
+#ifdef CONFIG_CIFS_DEBUG2
+                               if(cap & CIFS_UNIX_FCNTL_CAP)
+                                       cFYI(1,("FCNTL cap"));
+                               if(cap & CIFS_UNIX_EXTATTR_CAP)
+                                       cFYI(1,("EXTATTR cap"));
+                               if(cap & CIFS_UNIX_POSIX_PATHNAMES_CAP)
+                                       cFYI(1,("POSIX path cap"));
+                               if(cap & CIFS_UNIX_XATTR_CAP)
+                                       cFYI(1,("XATTR cap"));
+                               if(cap & CIFS_UNIX_POSIX_ACL_CAP)
+                                       cFYI(1,("POSIX ACL cap"));
+#endif /* CIFS_DEBUG2 */
+                               if (CIFSSMBSetFSUnixInfo(xid, tcon, cap)) {
+                                       cFYI(1,("setting capabilities failed"));
+                               }
+                       }
+               }
+               if (!(tcon->ses->capabilities & CAP_LARGE_WRITE_X))
+                       cifs_sb->wsize = min(cifs_sb->wsize,
+                                            (tcon->ses->server->maxBuf -
+                                             MAX_CIFS_HDR_SIZE));
+               if (!(tcon->ses->capabilities & CAP_LARGE_READ_X))
+                        cifs_sb->rsize = min(cifs_sb->rsize,
+                                             (tcon->ses->server->maxBuf -
+                                              MAX_CIFS_HDR_SIZE));
+       }
+
+       /* volume_info.password is freed above when existing session found
+       (in which case it is not needed anymore) but when new sesion is created
+       the password ptr is put in the new session structure (in which case the
        password will be freed at unmount time) */
-       if(volume_info.UNC)
-               kfree(volume_info.UNC);
+       kfree(volume_info.UNC);
+       kfree(volume_info.prepath);
        FreeXid(xid);
        return rc;
 }
 
 static int
 CIFSSessSetup(unsigned int xid, struct cifsSesInfo *ses,
-             char session_key[CIFS_SESSION_KEY_SIZE],
+             char session_key[CIFS_SESS_KEY_SIZE],
              const struct nls_table *nls_codepage)
 {
        struct smb_hdr *smb_buffer;
@@ -1464,17 +2075,22 @@ CIFSSessSetup(unsigned int xid, struct cifsSesInfo *ses,
        SESSION_SETUP_ANDX *pSMB;
        SESSION_SETUP_ANDX *pSMBr;
        char *bcc_ptr;
-       char *user = ses->userName;
-       char *domain = ses->domainName;
+       char *user;
+       char *domain;
        int rc = 0;
        int remaining_words = 0;
        int bytes_returned = 0;
        int len;
+       __u32 capabilities;
+       __u16 count;
 
-       cFYI(1, ("In sesssetup "));
-
+       cFYI(1, ("In sesssetup"));
+       if(ses == NULL)
+               return -EINVAL;
+       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;
@@ -1484,6 +2100,7 @@ CIFSSessSetup(unsigned int xid, struct cifsSesInfo *ses,
        header_assemble(smb_buffer, SMB_COM_SESSION_SETUP_ANDX,
                        NULL /* no tCon exists yet */ , 13 /* wct */ );
 
+       smb_buffer->Mid = GetNextMid(ses->server);
        pSMB->req_no_secext.AndXCommand = 0xFF;
        pSMB->req_no_secext.MaxBufferSize = cpu_to_le16(ses->server->maxBuf);
        pSMB->req_no_secext.MaxMpxCount = cpu_to_le16(ses->server->maxReq);
@@ -1491,67 +2108,68 @@ CIFSSessSetup(unsigned int xid, struct cifsSesInfo *ses,
        if(ses->server->secMode & (SECMODE_SIGN_REQUIRED | SECMODE_SIGN_ENABLED))
                smb_buffer->Flags2 |= SMBFLG2_SECURITY_SIGNATURE;
 
-       pSMB->req_no_secext.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;
-               pSMB->req_no_secext.Capabilities |= CAP_UNICODE;
+               capabilities |= CAP_UNICODE;
        }
        if (ses->capabilities & CAP_STATUS32) {
                smb_buffer->Flags2 |= SMBFLG2_ERR_STATUS;
-               pSMB->req_no_secext.Capabilities |= CAP_STATUS32;
+               capabilities |= CAP_STATUS32;
        }
        if (ses->capabilities & CAP_DFS) {
                smb_buffer->Flags2 |= SMBFLG2_DFS;
-               pSMB->req_no_secext.Capabilities |= CAP_DFS;
+               capabilities |= CAP_DFS;
        }
-       pSMB->req_no_secext.Capabilities =
-           cpu_to_le32(pSMB->req_no_secext.Capabilities);
-       /* pSMB->req_no_secext.CaseInsensitivePasswordLength =
-          CIFS_SESSION_KEY_SIZE; */
-       pSMB->req_no_secext.CaseInsensitivePasswordLength = 0;
+       pSMB->req_no_secext.Capabilities = cpu_to_le32(capabilities);
+
+       pSMB->req_no_secext.CaseInsensitivePasswordLength = 
+               cpu_to_le16(CIFS_SESS_KEY_SIZE);
+
        pSMB->req_no_secext.CaseSensitivePasswordLength =
-           cpu_to_le16(CIFS_SESSION_KEY_SIZE);
+           cpu_to_le16(CIFS_SESS_KEY_SIZE);
        bcc_ptr = pByteArea(smb_buffer);
-       /* memcpy(bcc_ptr, (char *) lm_session_key, CIFS_SESSION_KEY_SIZE);
-          bcc_ptr += CIFS_SESSION_KEY_SIZE; */
-       memcpy(bcc_ptr, (char *) session_key, CIFS_SESSION_KEY_SIZE);
-       bcc_ptr += CIFS_SESSION_KEY_SIZE;
+       memcpy(bcc_ptr, (char *) session_key, CIFS_SESS_KEY_SIZE);
+       bcc_ptr += CIFS_SESS_KEY_SIZE;
+       memcpy(bcc_ptr, (char *) session_key, CIFS_SESS_KEY_SIZE);
+       bcc_ptr += CIFS_SESS_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++;
                }
                if(user == NULL)
-                       bytes_returned = 0; /* skill null user */
+                       bytes_returned = 0; /* skip null user */
                else
                        bytes_returned =
-                               cifs_strtoUCS((wchar_t *) bcc_ptr, user, 100,
+                               cifs_strtoUCS((__le16 *) 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 =
-                           cifs_strtoUCS((wchar_t *) bcc_ptr,
+                           cifs_strtoUCS((__le16 *) bcc_ptr,
                                          "CIFS_LINUX_DOM", 32, nls_codepage);
                else
                        bytes_returned =
-                           cifs_strtoUCS((wchar_t *) bcc_ptr, domain, 64,
+                           cifs_strtoUCS((__le16 *) bcc_ptr, domain, 64,
                                          nls_codepage);
                bcc_ptr += 2 * bytes_returned;
                bcc_ptr += 2;
                bytes_returned =
-                   cifs_strtoUCS((wchar_t *) bcc_ptr, "Linux version ",
+                   cifs_strtoUCS((__le16 *) bcc_ptr, "Linux version ",
                                  32, nls_codepage);
                bcc_ptr += 2 * bytes_returned;
                bytes_returned =
-                   cifs_strtoUCS((wchar_t *) bcc_ptr, UTS_RELEASE, 32,
-                                 nls_codepage);
+                   cifs_strtoUCS((__le16 *) bcc_ptr, utsname()->release,
+                                 32, nls_codepage);
                bcc_ptr += 2 * bytes_returned;
                bcc_ptr += 2;
                bytes_returned =
-                   cifs_strtoUCS((wchar_t *) bcc_ptr, CIFS_NETWORK_OPSYS,
+                   cifs_strtoUCS((__le16 *) bcc_ptr, CIFS_NETWORK_OPSYS,
                                  64, nls_codepage);
                bcc_ptr += 2 * bytes_returned;
                bcc_ptr += 2;
@@ -1573,14 +2191,14 @@ CIFSSessSetup(unsigned int xid, struct cifsSesInfo *ses,
                }
                strcpy(bcc_ptr, "Linux version ");
                bcc_ptr += strlen("Linux version ");
-               strcpy(bcc_ptr, UTS_RELEASE);
-               bcc_ptr += strlen(UTS_RELEASE) + 1;
+               strcpy(bcc_ptr, utsname()->release);
+               bcc_ptr += strlen(utsname()->release) + 1;
                strcpy(bcc_ptr, CIFS_NETWORK_OPSYS);
                bcc_ptr += strlen(CIFS_NETWORK_OPSYS) + 1;
        }
-       BCC(smb_buffer) = (long) bcc_ptr - (long) pByteArea(smb_buffer);
-       smb_buffer->smb_buf_length += BCC(smb_buffer);
-       BCC(smb_buffer) = cpu_to_le16(BCC(smb_buffer));
+       count = (long) bcc_ptr - (long) pByteArea(smb_buffer);
+       smb_buffer->smb_buf_length += count;
+       pSMB->req_no_secext.ByteCount = cpu_to_le16(count);
 
        rc = SendReceive(xid, ses, smb_buffer, smb_buffer_response,
                         &bytes_returned, 1);
@@ -1588,373 +2206,139 @@ CIFSSessSetup(unsigned int xid, struct cifsSesInfo *ses,
 /* rc = map_smb_to_linux_error(smb_buffer_response); now done in SendReceive */
        } else if ((smb_buffer_response->WordCount == 3)
                   || (smb_buffer_response->WordCount == 4)) {
-               pSMBr->resp.Action = le16_to_cpu(pSMBr->resp.Action);
-               if (pSMBr->resp.Action & GUEST_LOGIN)
+               __u16 action = le16_to_cpu(pSMBr->resp.Action);
+               __u16 blob_len = le16_to_cpu(pSMBr->resp.SecurityBlobLength);
+               if (action & GUEST_LOGIN)
                        cFYI(1, (" Guest login"));      /* do we want to mark SesInfo struct ? */
-               if (ses) {
-                       ses->Suid = smb_buffer_response->Uid;   /* UID left in wire format (le) */
-                       cFYI(1, ("UID = %d ", ses->Suid));
+               ses->Suid = smb_buffer_response->Uid;   /* UID left in wire format (le) */
+               cFYI(1, ("UID = %d ", ses->Suid));
          /* response can have either 3 or 4 word count - Samba sends 3 */
-                       bcc_ptr = pByteArea(smb_buffer_response);       
-                       if ((pSMBr->resp.hdr.WordCount == 3)
-                           || ((pSMBr->resp.hdr.WordCount == 4)
-                               && (pSMBr->resp.SecurityBlobLength <
-                                   pSMBr->resp.ByteCount))) {
-                               if (pSMBr->resp.hdr.WordCount == 4)
-                                       bcc_ptr +=
-                                           pSMBr->resp.SecurityBlobLength;
-
-                               if (smb_buffer->Flags2 & SMBFLG2_UNICODE) {
-                                       if ((long) (bcc_ptr) % 2) {
-                                               remaining_words =
-                                                   (BCC(smb_buffer_response)
-                                                    - 1) / 2;
-                                               bcc_ptr++;      /* Unicode strings must be word aligned */
-                                       } else {
-                                               remaining_words =
-                                                   BCC
-                                                   (smb_buffer_response) / 2;
-                                       }
-                                       len =
-                                           UniStrnlen((wchar_t *) bcc_ptr,
-                                                      remaining_words - 1);
+               bcc_ptr = pByteArea(smb_buffer_response);       
+               if ((pSMBr->resp.hdr.WordCount == 3)
+                   || ((pSMBr->resp.hdr.WordCount == 4)
+                       && (blob_len < pSMBr->resp.ByteCount))) {
+                       if (pSMBr->resp.hdr.WordCount == 4)
+                               bcc_ptr += blob_len;
+
+                       if (smb_buffer->Flags2 & SMBFLG2_UNICODE) {
+                               if ((long) (bcc_ptr) % 2) {
+                                       remaining_words =
+                                           (BCC(smb_buffer_response) - 1) /2;
+                                       bcc_ptr++;      /* Unicode strings must be word aligned */
+                               } else {
+                                       remaining_words =
+                                               BCC(smb_buffer_response) / 2;
+                               }
+                               len =
+                                   UniStrnlen((wchar_t *) bcc_ptr,
+                                              remaining_words - 1);
 /* 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);
-                                       cifs_strfromUCS_le(ses->serverOS,
-                                                          (wchar_t *)bcc_ptr, len,nls_codepage);
+                               if(ses->serverOS)
+                                       kfree(ses->serverOS);
+                               ses->serverOS = kzalloc(2 * (len + 1), GFP_KERNEL);
+                               if(ses->serverOS == NULL)
+                                       goto sesssetup_nomem;
+                               cifs_strfromUCS_le(ses->serverOS,
+                                          (__le16 *)bcc_ptr, len,nls_codepage);
+                               bcc_ptr += 2 * (len + 1);
+                               remaining_words -= len + 1;
+                               ses->serverOS[2 * len] = 0;
+                               ses->serverOS[1 + (2 * len)] = 0;
+                               if (remaining_words > 0) {
+                                       len = UniStrnlen((wchar_t *)bcc_ptr,
+                                                        remaining_words-1);
+                                       kfree(ses->serverNOS);
+                                       ses->serverNOS = kzalloc(2 * (len + 1),GFP_KERNEL);
+                                       if(ses->serverNOS == NULL)
+                                               goto sesssetup_nomem;
+                                       cifs_strfromUCS_le(ses->serverNOS,
+                                                          (__le16 *)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;
-                                       ses->serverOS[2 * len] = 0;
-                                       ses->serverOS[1 + (2 * len)] = 0;
                                        if (remaining_words > 0) {
-                                               len = UniStrnlen((wchar_t *)bcc_ptr,
-                                                                remaining_words
-                                                                - 1);
-                                               ses->serverNOS =cifs_kcalloc(2 * (len + 1),GFP_KERNEL);
-                                               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;
-                                               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);
-                                                       cifs_strfromUCS_le(ses->serverDomain,
-                                                            (wchar_t *)bcc_ptr,len,nls_codepage);
-                                                       bcc_ptr += 2 * (len + 1);
-                                                       ses->serverDomain[2*len] = 0;
-                                                       ses->serverDomain[1+(2*len)] = 0;
-                                               } /* else no more room so create dummy domain string */
-                                               else
-                                                       ses->serverDomain =
-                                                           cifs_kcalloc(2,
-                                                                   GFP_KERNEL);
-                                       } else {        /* no room so create dummy domain and NOS string */
+                                               if(ses->serverDomain)
+                                                       kfree(ses->serverDomain);
                                                ses->serverDomain =
-                                                   cifs_kcalloc(2, GFP_KERNEL);
-                                               ses->serverNOS =
-                                                   cifs_kcalloc(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);
-                                               strncpy(ses->serverOS,bcc_ptr, len);
-
-                                               bcc_ptr += len;
-                                               bcc_ptr[0] = 0; /* null terminate the string */
-                                               bcc_ptr++;
-
-                                               len = strnlen(bcc_ptr, 1024);
-                                               ses->serverNOS = cifs_kcalloc(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);
-                                               strncpy(ses->serverDomain, bcc_ptr, len);
-                                               bcc_ptr += len;
-                                               bcc_ptr[0] = 0;
-                                               bcc_ptr++;
-                                       } else
-                                               cFYI(1,
-                                                    ("Variable field of length %d extends beyond end of smb ",
-                                                     len));
-                               }
-                       } else {
-                               cERROR(1,
-                                      (" Security Blob Length extends beyond end of SMB"));
-                       }
-               } else {
-                       cERROR(1, ("No session structure passed in."));
-               }
-       } else {
-               cERROR(1,
-                      (" Invalid Word count %d: ",
-                       smb_buffer_response->WordCount));
-               rc = -EIO;
-       }
-       
-       if (smb_buffer)
-               cifs_buf_release(smb_buffer);
-
-       return rc;
-}
-
-static int
-CIFSSpnegoSessSetup(unsigned int xid, struct cifsSesInfo *ses,
-               char *SecurityBlob,int SecurityBlobLength,
-               const struct nls_table *nls_codepage)
-{
-       struct smb_hdr *smb_buffer;
-       struct smb_hdr *smb_buffer_response;
-       SESSION_SETUP_ANDX *pSMB;
-       SESSION_SETUP_ANDX *pSMBr;
-       char *bcc_ptr;
-       char *user = ses->userName;
-       char *domain = ses->domainName;
-       int rc = 0;
-       int remaining_words = 0;
-       int bytes_returned = 0;
-       int len;
-
-       cFYI(1, ("In spnego sesssetup "));
-
-       smb_buffer = cifs_buf_get();
-       if (smb_buffer == 0) {
-               return -ENOMEM;
-       }
-       smb_buffer_response = smb_buffer;
-       pSMBr = pSMB = (SESSION_SETUP_ANDX *) smb_buffer;
-
-       /* send SMBsessionSetup here */
-       header_assemble(smb_buffer, SMB_COM_SESSION_SETUP_ANDX,
-                       NULL /* no tCon exists yet */ , 12 /* wct */ );
-       pSMB->req.hdr.Flags2 |= SMBFLG2_EXT_SEC;
-       pSMB->req.AndXCommand = 0xFF;
-       pSMB->req.MaxBufferSize = cpu_to_le16(ses->server->maxBuf);
-       pSMB->req.MaxMpxCount = cpu_to_le16(ses->server->maxReq);
-
-       if(ses->server->secMode & (SECMODE_SIGN_REQUIRED | SECMODE_SIGN_ENABLED))
-               smb_buffer->Flags2 |= SMBFLG2_SECURITY_SIGNATURE;
-
-       pSMB->req.Capabilities =
-           CAP_LARGE_FILES | CAP_NT_SMBS | CAP_LEVEL_II_OPLOCKS |
-           CAP_EXTENDED_SECURITY;
-       if (ses->capabilities & CAP_UNICODE) {
-               smb_buffer->Flags2 |= SMBFLG2_UNICODE;
-               pSMB->req.Capabilities |= CAP_UNICODE;
-       }
-       if (ses->capabilities & CAP_STATUS32) {
-               smb_buffer->Flags2 |= SMBFLG2_ERR_STATUS;
-               pSMB->req.Capabilities |= CAP_STATUS32;
-       }
-       if (ses->capabilities & CAP_DFS) {
-               smb_buffer->Flags2 |= SMBFLG2_DFS;
-               pSMB->req.Capabilities |= CAP_DFS;
-       }
-       pSMB->req.Capabilities = cpu_to_le32(pSMB->req.Capabilities);
-
-       pSMB->req.SecurityBlobLength = cpu_to_le16(SecurityBlobLength);
-       bcc_ptr = pByteArea(smb_buffer);
-       memcpy(bcc_ptr, SecurityBlob, SecurityBlobLength);
-       bcc_ptr += SecurityBlobLength;
-
-       if (ses->capabilities & CAP_UNICODE) {
-               if ((long) bcc_ptr % 2) {       /* must be word aligned for Unicode strings */
-                       *bcc_ptr = 0;
-                       bcc_ptr++;
-               }
-               bytes_returned =
-                   cifs_strtoUCS((wchar_t *) bcc_ptr, user, 100, nls_codepage);
-               bcc_ptr += 2 * bytes_returned;  /* convert num of 16 bit words to bytes */
-               bcc_ptr += 2;   /* trailing null */
-               if (domain == NULL)
-                       bytes_returned =
-                           cifs_strtoUCS((wchar_t *) bcc_ptr,
-                                         "CIFS_LINUX_DOM", 32, nls_codepage);
-               else
-                       bytes_returned =
-                           cifs_strtoUCS((wchar_t *) bcc_ptr, domain, 64,
-                                         nls_codepage);
-               bcc_ptr += 2 * bytes_returned;
-               bcc_ptr += 2;
-               bytes_returned =
-                   cifs_strtoUCS((wchar_t *) bcc_ptr, "Linux version ",
-                                 32, nls_codepage);
-               bcc_ptr += 2 * bytes_returned;
-               bytes_returned =
-                   cifs_strtoUCS((wchar_t *) bcc_ptr, UTS_RELEASE, 32,
-                                 nls_codepage);
-               bcc_ptr += 2 * bytes_returned;
-               bcc_ptr += 2;
-               bytes_returned =
-                   cifs_strtoUCS((wchar_t *) bcc_ptr, CIFS_NETWORK_OPSYS,
-                                 64, nls_codepage);
-               bcc_ptr += 2 * bytes_returned;
-               bcc_ptr += 2;
-       } else {
-               strncpy(bcc_ptr, user, 200);
-               bcc_ptr += strnlen(user, 200);
-               *bcc_ptr = 0;
-               bcc_ptr++;
-               if (domain == NULL) {
-                       strcpy(bcc_ptr, "CIFS_LINUX_DOM");
-                       bcc_ptr += strlen("CIFS_LINUX_DOM") + 1;
-               } else {
-                       strncpy(bcc_ptr, domain, 64);
-                       bcc_ptr += strnlen(domain, 64);
-                       *bcc_ptr = 0;
-                       bcc_ptr++;
-               }
-               strcpy(bcc_ptr, "Linux version ");
-               bcc_ptr += strlen("Linux version ");
-               strcpy(bcc_ptr, UTS_RELEASE);
-               bcc_ptr += strlen(UTS_RELEASE) + 1;
-               strcpy(bcc_ptr, CIFS_NETWORK_OPSYS);
-               bcc_ptr += strlen(CIFS_NETWORK_OPSYS) + 1;
-       }
-       BCC(smb_buffer) = (long) bcc_ptr - (long) pByteArea(smb_buffer);
-       smb_buffer->smb_buf_length += BCC(smb_buffer);
-       BCC(smb_buffer) = cpu_to_le16(BCC(smb_buffer));
-
-       rc = SendReceive(xid, ses, smb_buffer, smb_buffer_response,
-                        &bytes_returned, 1);
-       if (rc) {
-/*    rc = map_smb_to_linux_error(smb_buffer_response);  *//* done in SendReceive now */
-       } else if ((smb_buffer_response->WordCount == 3)
-                  || (smb_buffer_response->WordCount == 4)) {
-               pSMBr->resp.Action = le16_to_cpu(pSMBr->resp.Action);
-               pSMBr->resp.SecurityBlobLength =
-                   le16_to_cpu(pSMBr->resp.SecurityBlobLength);
-               if (pSMBr->resp.Action & GUEST_LOGIN)
-                       cFYI(1, (" Guest login"));      /* BB do we want to set anything in SesInfo struct ? */
-               if (ses) {
-                       ses->Suid = smb_buffer_response->Uid;   /* UID left in wire format (le) */
-                       cFYI(1, ("UID = %d ", ses->Suid));
-                       bcc_ptr = pByteArea(smb_buffer_response);       /* response can have either 3 or 4 word count - Samba sends 3 */
-
-                       /* BB Fix below to make endian neutral !! */
-
-                       if ((pSMBr->resp.hdr.WordCount == 3)
-                           || ((pSMBr->resp.hdr.WordCount == 4)
-                               && (pSMBr->resp.SecurityBlobLength <
-                                   pSMBr->resp.ByteCount))) {
-                               if (pSMBr->resp.hdr.WordCount == 4) {
-                                       bcc_ptr +=
-                                           pSMBr->resp.SecurityBlobLength;
-                                       cFYI(1,
-                                            ("Security Blob Length %d ",
-                                             pSMBr->resp.SecurityBlobLength));
-                               }
-
-                               if (smb_buffer->Flags2 & SMBFLG2_UNICODE) {
-                                       if ((long) (bcc_ptr) % 2) {
-                                               remaining_words =
-                                                   (BCC(smb_buffer_response)
-                                                    - 1) / 2;
-                                               bcc_ptr++;      /* Unicode strings must be word aligned */
-                                       } else {
-                                               remaining_words =
-                                                   BCC
-                                                   (smb_buffer_response) / 2;
-                                       }
-                                       len =
-                                           UniStrnlen((wchar_t *) bcc_ptr,
-                                                      remaining_words - 1);
-/* 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);
-                                       cifs_strfromUCS_le(ses->serverOS,
-                                                          (wchar_t *)
-                                                          bcc_ptr, len,
-                                                          nls_codepage);
-                                       bcc_ptr += 2 * (len + 1);
-                                       remaining_words -= len + 1;
-                                       ses->serverOS[2 * len] = 0;
-                                       ses->serverOS[1 + (2 * len)] = 0;
-                                       if (remaining_words > 0) {
-                                               len = UniStrnlen((wchar_t *)bcc_ptr,
-                                                                remaining_words
-                                                                - 1);
-                                               ses->serverNOS =
-                                                   cifs_kcalloc(2 * (len + 1),
-                                                           GFP_KERNEL);
-                                               cifs_strfromUCS_le(ses->serverNOS,
-                                                                  (wchar_t *)bcc_ptr,
-                                                                  len,
-                                                                  nls_codepage);
+                                                   kzalloc(2*(len+1),GFP_KERNEL);
+                                               if(ses->serverDomain == NULL)
+                                                       goto sesssetup_nomem;
+                                               cifs_strfromUCS_le(ses->serverDomain,
+                                                    (__le16 *)bcc_ptr,len,nls_codepage);
                                                bcc_ptr += 2 * (len + 1);
-                                               ses->serverNOS[2 * len] = 0;
-                                               ses->serverNOS[1 + (2 * len)] = 0;
-                                               remaining_words -= len + 1;
-                                               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);
-                                                       cifs_strfromUCS_le(ses->serverDomain,
-                                                            (wchar_t *)bcc_ptr, 
-                                 len,
-                                                            nls_codepage);
-                                                       bcc_ptr += 2*(len+1);
-                                                       ses->serverDomain[2*len] = 0;
-                                                       ses->serverDomain[1+(2*len)] = 0;
-                                               } /* else no more room so create dummy domain string */
-                                               else
-                                                       ses->serverDomain =
-                                                           cifs_kcalloc(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[2*len] = 0;
+                                               ses->serverDomain[1+(2*len)] = 0;
+                                       } /* else no more room so create dummy domain string */
+                                       else {
+                                               if(ses->serverDomain)
+                                                       kfree(ses->serverDomain);
+                                               ses->serverDomain = 
+                                                       kzalloc(2, GFP_KERNEL);
                                        }
-                               } else {        /* ASCII */
-
-                                       len = strnlen(bcc_ptr, 1024);
-                                       if (((long) bcc_ptr + len) - (long)
-                                           pByteArea(smb_buffer_response)
+                               } 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 */
+                                       kfree(ses->serverDomain);
+                                       ses->serverDomain =
+                                           kzalloc(2, GFP_KERNEL);
+                                       kfree(ses->serverNOS);
+                                       ses->serverNOS =
+                                           kzalloc(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);
-                                               strncpy(ses->serverOS, bcc_ptr, len);
+                                       kfree(ses->serverOS);
+                                       ses->serverOS = kzalloc(len + 1,GFP_KERNEL);
+                                       if(ses->serverOS == NULL)
+                                               goto sesssetup_nomem;
+                                       strncpy(ses->serverOS,bcc_ptr, len);
 
-                                               bcc_ptr += len;
-                                               bcc_ptr[0] = 0; /* null terminate the string */
-                                               bcc_ptr++;
+                                       bcc_ptr += len;
+                                       bcc_ptr[0] = 0; /* null terminate the string */
+                                       bcc_ptr++;
 
-                                               len = strnlen(bcc_ptr, 1024);
-                                               ses->serverNOS = cifs_kcalloc(len + 1,GFP_KERNEL);
-                                               strncpy(ses->serverNOS, bcc_ptr, len);
-                                               bcc_ptr += len;
-                                               bcc_ptr[0] = 0;
-                                               bcc_ptr++;
+                                       len = strnlen(bcc_ptr, 1024);
+                                       kfree(ses->serverNOS);
+                                       ses->serverNOS = kzalloc(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);
-                                               strncpy(ses->serverDomain, bcc_ptr, len);
-                                               bcc_ptr += len;
-                                               bcc_ptr[0] = 0;
-                                               bcc_ptr++;
-                                       } else
-                                               cFYI(1,
-                                                    ("Variable field of length %d extends beyond end of smb ",
-                                                     len));
-                               }
-                       } else {
-                               cERROR(1,
-                                      (" Security Blob Length extends beyond end of SMB"));
+                                       len = strnlen(bcc_ptr, 1024);
+                                       if(ses->serverDomain)
+                                               kfree(ses->serverDomain);
+                                       ses->serverDomain = kzalloc(len + 1,GFP_KERNEL);
+                                       if(ses->serverDomain == NULL)
+                                               goto sesssetup_nomem;
+                                       strncpy(ses->serverDomain, bcc_ptr, len);
+                                       bcc_ptr += len;
+                                       bcc_ptr[0] = 0;
+                                       bcc_ptr++;
+                               } else
+                                       cFYI(1,
+                                            ("Variable field of length %d extends beyond end of smb ",
+                                             len));
                        }
                } else {
-                       cERROR(1, ("No session structure passed in."));
+                       cERROR(1,
+                              (" Security Blob Length extends beyond end of SMB"));
                }
        } else {
                cERROR(1,
@@ -1962,7 +2346,9 @@ CIFSSpnegoSessSetup(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);
 
@@ -1979,7 +2365,7 @@ CIFSNTLMSSPNegotiateSessSetup(unsigned int xid,
        SESSION_SETUP_ANDX *pSMB;
        SESSION_SETUP_ANDX *pSMBr;
        char *bcc_ptr;
-       char *domain = ses->domainName;
+       char *domain;
        int rc = 0;
        int remaining_words = 0;
        int bytes_returned = 0;
@@ -1987,11 +2373,16 @@ CIFSNTLMSSPNegotiateSessSetup(unsigned int xid,
        int SecurityBlobLength = sizeof (NEGOTIATE_MESSAGE);
        PNEGOTIATE_MESSAGE SecurityBlob;
        PCHALLENGE_MESSAGE SecurityBlob2;
+       __u32 negotiate_flags, capabilities;
+       __u16 count;
 
-       cFYI(1, ("In NTLMSSP sesssetup (negotiate) "));
+       cFYI(1, ("In NTLMSSP sesssetup (negotiate)"));
+       if(ses == NULL)
+               return -EINVAL;
+       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;
@@ -2001,6 +2392,8 @@ CIFSNTLMSSPNegotiateSessSetup(unsigned int xid,
        /* send SMBsessionSetup here */
        header_assemble(smb_buffer, SMB_COM_SESSION_SETUP_ANDX,
                        NULL /* no tCon exists yet */ , 12 /* wct */ );
+
+       smb_buffer->Mid = GetNextMid(ses->server);
        pSMB->req.hdr.Flags2 |= SMBFLG2_EXT_SEC;
        pSMB->req.hdr.Flags |= (SMBFLG_CASELESS | SMBFLG_CANONICAL_PATH_FORMAT);
 
@@ -2011,35 +2404,35 @@ CIFSNTLMSSPNegotiateSessSetup(unsigned int xid,
        if(ses->server->secMode & (SECMODE_SIGN_REQUIRED | SECMODE_SIGN_ENABLED))
                smb_buffer->Flags2 |= SMBFLG2_SECURITY_SIGNATURE;
 
-       pSMB->req.Capabilities =
-           CAP_LARGE_FILES | CAP_NT_SMBS | CAP_LEVEL_II_OPLOCKS |
+       capabilities = CAP_LARGE_FILES | CAP_NT_SMBS | CAP_LEVEL_II_OPLOCKS |
            CAP_EXTENDED_SECURITY;
        if (ses->capabilities & CAP_UNICODE) {
                smb_buffer->Flags2 |= SMBFLG2_UNICODE;
-               pSMB->req.Capabilities |= CAP_UNICODE;
+               capabilities |= CAP_UNICODE;
        }
        if (ses->capabilities & CAP_STATUS32) {
                smb_buffer->Flags2 |= SMBFLG2_ERR_STATUS;
-               pSMB->req.Capabilities |= CAP_STATUS32;
+               capabilities |= CAP_STATUS32;
        }
        if (ses->capabilities & CAP_DFS) {
                smb_buffer->Flags2 |= SMBFLG2_DFS;
-               pSMB->req.Capabilities |= CAP_DFS;
+               capabilities |= CAP_DFS;
        }
-       pSMB->req.Capabilities = cpu_to_le32(pSMB->req.Capabilities);
+       pSMB->req.Capabilities = cpu_to_le32(capabilities);
 
        bcc_ptr = (char *) &pSMB->req.SecurityBlob;
        SecurityBlob = (PNEGOTIATE_MESSAGE) bcc_ptr;
        strncpy(SecurityBlob->Signature, NTLMSSP_SIGNATURE, 8);
        SecurityBlob->MessageType = NtLmNegotiate;
-       SecurityBlob->NegotiateFlags =
+       negotiate_flags =
            NTLMSSP_NEGOTIATE_UNICODE | NTLMSSP_NEGOTIATE_OEM |
-           NTLMSSP_REQUEST_TARGET | NTLMSSP_NEGOTIATE_NTLM | 0x80000000 |
+           NTLMSSP_REQUEST_TARGET | NTLMSSP_NEGOTIATE_NTLM |
+           NTLMSSP_NEGOTIATE_56 |
            /* NTLMSSP_NEGOTIATE_ALWAYS_SIGN | */ NTLMSSP_NEGOTIATE_128;
        if(sign_CIFS_PDUs)
-               SecurityBlob->NegotiateFlags |= NTLMSSP_NEGOTIATE_SIGN;
-       if(ntlmv2_support)
-               SecurityBlob->NegotiateFlags |= NTLMSSP_NEGOTIATE_NTLMV2;
+               negotiate_flags |= NTLMSSP_NEGOTIATE_SIGN;
+/*     if(ntlmv2_support)
+               negotiate_flags |= NTLMSSP_NEGOTIATE_NTLMV2;*/
        /* setup pointers to domain name and workstation name */
        bcc_ptr += SecurityBlobLength;
 
@@ -2047,26 +2440,11 @@ CIFSNTLMSSPNegotiateSessSetup(unsigned int xid,
        SecurityBlob->WorkstationName.Length = 0;
        SecurityBlob->WorkstationName.MaximumLength = 0;
 
-       if (domain == NULL) {
-               SecurityBlob->DomainName.Buffer = 0;
-               SecurityBlob->DomainName.Length = 0;
-               SecurityBlob->DomainName.MaximumLength = 0;
-       } else {
-               SecurityBlob->NegotiateFlags |=
-                   NTLMSSP_NEGOTIATE_DOMAIN_SUPPLIED;
-               strncpy(bcc_ptr, domain, 63);
-               SecurityBlob->DomainName.Length = strnlen(domain, 64);
-               SecurityBlob->DomainName.MaximumLength =
-                   cpu_to_le16(SecurityBlob->DomainName.Length);
-               SecurityBlob->DomainName.Buffer =
-                   cpu_to_le32((long) &SecurityBlob->
-                               DomainString -
-                               (long) &SecurityBlob->Signature);
-               bcc_ptr += SecurityBlob->DomainName.Length;
-               SecurityBlobLength += SecurityBlob->DomainName.Length;
-               SecurityBlob->DomainName.Length =
-                   cpu_to_le16(SecurityBlob->DomainName.Length);
-       }
+       /* Domain not sent on first Sesssetup in NTLMSSP, instead it is sent
+       along with username on auth request (ie the response to challenge) */
+       SecurityBlob->DomainName.Buffer = 0;
+       SecurityBlob->DomainName.Length = 0;
+       SecurityBlob->DomainName.MaximumLength = 0;
        if (ses->capabilities & CAP_UNICODE) {
                if ((long) bcc_ptr % 2) {
                        *bcc_ptr = 0;
@@ -2074,16 +2452,16 @@ CIFSNTLMSSPNegotiateSessSetup(unsigned int xid,
                }
 
                bytes_returned =
-                   cifs_strtoUCS((wchar_t *) bcc_ptr, "Linux version ",
+                   cifs_strtoUCS((__le16 *) bcc_ptr, "Linux version ",
                                  32, nls_codepage);
                bcc_ptr += 2 * bytes_returned;
                bytes_returned =
-                   cifs_strtoUCS((wchar_t *) bcc_ptr, UTS_RELEASE, 32,
+                   cifs_strtoUCS((__le16 *) bcc_ptr, utsname()->release, 32,
                                  nls_codepage);
                bcc_ptr += 2 * bytes_returned;
                bcc_ptr += 2;   /* null terminate Linux version */
                bytes_returned =
-                   cifs_strtoUCS((wchar_t *) bcc_ptr, CIFS_NETWORK_OPSYS,
+                   cifs_strtoUCS((__le16 *) bcc_ptr, CIFS_NETWORK_OPSYS,
                                  64, nls_codepage);
                bcc_ptr += 2 * bytes_returned;
                *(bcc_ptr + 1) = 0;
@@ -2095,35 +2473,34 @@ CIFSNTLMSSPNegotiateSessSetup(unsigned int xid,
        } else {                /* ASCII */
                strcpy(bcc_ptr, "Linux version ");
                bcc_ptr += strlen("Linux version ");
-               strcpy(bcc_ptr, UTS_RELEASE);
-               bcc_ptr += strlen(UTS_RELEASE) + 1;
+               strcpy(bcc_ptr, utsname()->release);
+               bcc_ptr += strlen(utsname()->release) + 1;
                strcpy(bcc_ptr, CIFS_NETWORK_OPSYS);
                bcc_ptr += strlen(CIFS_NETWORK_OPSYS) + 1;
                bcc_ptr++;      /* empty domain field */
                *bcc_ptr = 0;
        }
-       SecurityBlob->NegotiateFlags =
-           cpu_to_le32(SecurityBlob->NegotiateFlags);
+       SecurityBlob->NegotiateFlags = cpu_to_le32(negotiate_flags);
        pSMB->req.SecurityBlobLength = cpu_to_le16(SecurityBlobLength);
-       BCC(smb_buffer) = (long) bcc_ptr - (long) pByteArea(smb_buffer);
-       smb_buffer->smb_buf_length += BCC(smb_buffer);
-       BCC(smb_buffer) = cpu_to_le16(BCC(smb_buffer));
+       count = (long) bcc_ptr - (long) pByteArea(smb_buffer);
+       smb_buffer->smb_buf_length += count;
+       pSMB->req.ByteCount = cpu_to_le16(count);
 
        rc = SendReceive(xid, ses, smb_buffer, smb_buffer_response,
                         &bytes_returned, 1);
 
        if (smb_buffer_response->Status.CifsError ==
-           (NT_STATUS_MORE_PROCESSING_REQUIRED))
+           cpu_to_le32(NT_STATUS_MORE_PROCESSING_REQUIRED))
                rc = 0;
 
        if (rc) {
 /*    rc = map_smb_to_linux_error(smb_buffer_response);  *//* done in SendReceive now */
        } else if ((smb_buffer_response->WordCount == 3)
                   || (smb_buffer_response->WordCount == 4)) {
-               pSMBr->resp.Action = le16_to_cpu(pSMBr->resp.Action);
-               pSMBr->resp.SecurityBlobLength =
-                   le16_to_cpu(pSMBr->resp.SecurityBlobLength);
-               if (pSMBr->resp.Action & GUEST_LOGIN)
+               __u16 action = le16_to_cpu(pSMBr->resp.Action);
+               __u16 blob_len = le16_to_cpu(pSMBr->resp.SecurityBlobLength);
+
+               if (action & GUEST_LOGIN)
                        cFYI(1, (" Guest login"));      
         /* Do we want to set anything in SesInfo struct when guest login? */
 
@@ -2137,34 +2514,34 @@ CIFSNTLMSSPNegotiateSessSetup(unsigned int xid,
                              SecurityBlob2->MessageType));
                } else if (ses) {
                        ses->Suid = smb_buffer_response->Uid; /* UID left in le format */ 
-                       cFYI(1, ("UID = %d ", ses->Suid));
+                       cFYI(1, ("UID = %d", ses->Suid));
                        if ((pSMBr->resp.hdr.WordCount == 3)
                            || ((pSMBr->resp.hdr.WordCount == 4)
-                               && (pSMBr->resp.SecurityBlobLength <
+                               && (blob_len <
                                    pSMBr->resp.ByteCount))) {
+
                                if (pSMBr->resp.hdr.WordCount == 4) {
-                                       bcc_ptr +=
-                                           pSMBr->resp.SecurityBlobLength;
-                                       cFYI(1,
-                                            ("Security Blob Length %d ",
-                                             pSMBr->resp.SecurityBlobLength));
+                                       bcc_ptr += blob_len;
+                                       cFYI(1, ("Security Blob Length %d",
+                                             blob_len));
                                }
 
-                               cFYI(1, ("NTLMSSP Challenge rcvd "));
+                               cFYI(1, ("NTLMSSP Challenge rcvd"));
 
                                memcpy(ses->server->cryptKey,
                                       SecurityBlob2->Challenge,
                                       CIFS_CRYPTO_KEY_SIZE);
-                               if(SecurityBlob2->NegotiateFlags & NTLMSSP_NEGOTIATE_NTLMV2)
+                               if(SecurityBlob2->NegotiateFlags & 
+                                       cpu_to_le32(NTLMSSP_NEGOTIATE_NTLMV2))
                                        *pNTLMv2_flag = TRUE;
 
                                if((SecurityBlob2->NegotiateFlags & 
-                                       NTLMSSP_NEGOTIATE_ALWAYS_SIGN
+                                       cpu_to_le32(NTLMSSP_NEGOTIATE_ALWAYS_SIGN)
                                        || (sign_CIFS_PDUs > 1))
                                                ses->server->secMode |= 
                                                        SECMODE_SIGN_REQUIRED;  
                                if ((SecurityBlob2->NegotiateFlags & 
-                                       NTLMSSP_NEGOTIATE_SIGN) && (sign_CIFS_PDUs))
+                                       cpu_to_le32(NTLMSSP_NEGOTIATE_SIGN)) && (sign_CIFS_PDUs))
                                                ses->server->secMode |= 
                                                        SECMODE_SIGN_ENABLED;
 
@@ -2185,10 +2562,12 @@ CIFSNTLMSSPNegotiateSessSetup(unsigned int xid,
 /* 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  */
+                                       if(ses->serverOS)
+                                               kfree(ses->serverOS);
                                        ses->serverOS =
-                                           cifs_kcalloc(2 * (len + 1), GFP_KERNEL);
+                                           kzalloc(2 * (len + 1), GFP_KERNEL);
                                        cifs_strfromUCS_le(ses->serverOS,
-                                                          (wchar_t *)
+                                                          (__le16 *)
                                                           bcc_ptr, len,
                                                           nls_codepage);
                                        bcc_ptr += 2 * (len + 1);
@@ -2200,12 +2579,13 @@ CIFSNTLMSSPNegotiateSessSetup(unsigned int xid,
                                                                 bcc_ptr,
                                                                 remaining_words
                                                                 - 1);
+                                               kfree(ses->serverNOS);
                                                ses->serverNOS =
-                                                   cifs_kcalloc(2 * (len + 1),
+                                                   kzalloc(2 * (len + 1),
                                                            GFP_KERNEL);
                                                cifs_strfromUCS_le(ses->
                                                                   serverNOS,
-                                                                  (wchar_t *)
+                                                                  (__le16 *)
                                                                   bcc_ptr,
                                                                   len,
                                                                   nls_codepage);
@@ -2217,48 +2597,47 @@ CIFSNTLMSSPNegotiateSessSetup(unsigned int xid,
                                                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) */
+                                                       kfree(ses->serverDomain);
                                                        ses->serverDomain =
-                                                           cifs_kcalloc(2 *
+                                                           kzalloc(2 *
                                                                    (len +
                                                                     1),
                                                                    GFP_KERNEL);
                                                        cifs_strfromUCS_le
-                                                           (ses->
-                                                            serverDomain,
-                                                            (wchar_t *)
-                                                            bcc_ptr, len,
-                                                            nls_codepage);
+                                                           (ses->serverDomain,
+                                                            (__le16 *)bcc_ptr,
+                                                            len, nls_codepage);
                                                        bcc_ptr +=
                                                            2 * (len + 1);
-                                                       ses->
-                                                           serverDomain[2
-                                                                        * len]
+                                                       ses->serverDomain[2*len]
                                                            = 0;
-                                                       ses->
-                                                           serverDomain[1
-                                                                        +
-                                                                        (2
-                                                                         *
-                                                                         len)]
+                                                       ses->serverDomain
+                                                               [1 + (2 * len)]
                                                            = 0;
                                                } /* else no more room so create dummy domain string */
-                                               else
+                                               else {
+                                                       kfree(ses->serverDomain);
                                                        ses->serverDomain =
-                                                           cifs_kcalloc(2,
+                                                           kzalloc(2,
                                                                    GFP_KERNEL);
+                                               }
                                        } else {        /* no room so create dummy domain and NOS string */
+                                               kfree(ses->serverDomain);
                                                ses->serverDomain =
-                                                   cifs_kcalloc(2, GFP_KERNEL);
+                                                   kzalloc(2, GFP_KERNEL);
+                                               kfree(ses->serverNOS);
                                                ses->serverNOS =
-                                                   cifs_kcalloc(2, GFP_KERNEL);
+                                                   kzalloc(2, GFP_KERNEL);
                                        }
                                } else {        /* ASCII */
                                        len = strnlen(bcc_ptr, 1024);
                                        if (((long) bcc_ptr + len) - (long)
                                            pByteArea(smb_buffer_response)
                                            <= BCC(smb_buffer_response)) {
+                                               if(ses->serverOS)
+                                                       kfree(ses->serverOS);
                                                ses->serverOS =
-                                                   cifs_kcalloc(len + 1,
+                                                   kzalloc(len + 1,
                                                            GFP_KERNEL);
                                                strncpy(ses->serverOS,
                                                        bcc_ptr, len);
@@ -2268,8 +2647,9 @@ CIFSNTLMSSPNegotiateSessSetup(unsigned int xid,
                                                bcc_ptr++;
 
                                                len = strnlen(bcc_ptr, 1024);
+                                               kfree(ses->serverNOS);
                                                ses->serverNOS =
-                                                   cifs_kcalloc(len + 1,
+                                                   kzalloc(len + 1,
                                                            GFP_KERNEL);
                                                strncpy(ses->serverNOS, bcc_ptr, len);
                                                bcc_ptr += len;
@@ -2277,8 +2657,9 @@ CIFSNTLMSSPNegotiateSessSetup(unsigned int xid,
                                                bcc_ptr++;
 
                                                len = strnlen(bcc_ptr, 1024);
+                                               kfree(ses->serverDomain);
                                                ses->serverDomain =
-                                                   cifs_kcalloc(len + 1,
+                                                   kzalloc(len + 1,
                                                            GFP_KERNEL);
                                                strncpy(ses->serverDomain, bcc_ptr, len);       
                                                bcc_ptr += len;
@@ -2286,7 +2667,7 @@ CIFSNTLMSSPNegotiateSessSetup(unsigned int xid,
                                                bcc_ptr++;
                                        } else
                                                cFYI(1,
-                                                    ("Variable field of length %d extends beyond end of smb ",
+                                                    ("Variable field of length %d extends beyond end of smb",
                                                      len));
                                }
                        } else {
@@ -2298,7 +2679,7 @@ CIFSNTLMSSPNegotiateSessSetup(unsigned int xid,
                }
        } else {
                cERROR(1,
-                      (" Invalid Word count %d: ",
+                      (" Invalid Word count %d:",
                        smb_buffer_response->WordCount));
                rc = -EIO;
        }
@@ -2308,7 +2689,6 @@ CIFSNTLMSSPNegotiateSessSetup(unsigned int xid,
 
        return rc;
 }
-
 static int
 CIFSNTLMSSPAuthSessSetup(unsigned int xid, struct cifsSesInfo *ses,
                char *ntlm_session_key, int ntlmv2_flag,
@@ -2319,19 +2699,24 @@ CIFSNTLMSSPAuthSessSetup(unsigned int xid, struct cifsSesInfo *ses,
        SESSION_SETUP_ANDX *pSMB;
        SESSION_SETUP_ANDX *pSMBr;
        char *bcc_ptr;
-       char *user = ses->userName;
-       char *domain = ses->domainName;
+       char *user;
+       char *domain;
        int rc = 0;
        int remaining_words = 0;
        int bytes_returned = 0;
        int len;
        int SecurityBlobLength = sizeof (AUTHENTICATE_MESSAGE);
        PAUTHENTICATE_MESSAGE SecurityBlob;
+       __u32 negotiate_flags, capabilities;
+       __u16 count;
 
        cFYI(1, ("In NTLMSSPSessSetup (Authenticate)"));
-
+       if(ses == NULL)
+               return -EINVAL;
+       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;
@@ -2341,6 +2726,8 @@ CIFSNTLMSSPAuthSessSetup(unsigned int xid, struct cifsSesInfo *ses,
        /* send SMBsessionSetup here */
        header_assemble(smb_buffer, SMB_COM_SESSION_SETUP_ANDX,
                        NULL /* no tCon exists yet */ , 12 /* wct */ );
+
+       smb_buffer->Mid = GetNextMid(ses->server);
        pSMB->req.hdr.Flags |= (SMBFLG_CASELESS | SMBFLG_CANONICAL_PATH_FORMAT);
        pSMB->req.hdr.Flags2 |= SMBFLG2_EXT_SEC;
        pSMB->req.AndXCommand = 0xFF;
@@ -2352,36 +2739,35 @@ CIFSNTLMSSPAuthSessSetup(unsigned int xid, struct cifsSesInfo *ses,
        if(ses->server->secMode & (SECMODE_SIGN_REQUIRED | SECMODE_SIGN_ENABLED))
                smb_buffer->Flags2 |= SMBFLG2_SECURITY_SIGNATURE;
 
-       pSMB->req.Capabilities =
-           CAP_LARGE_FILES | CAP_NT_SMBS | CAP_LEVEL_II_OPLOCKS |
+       capabilities = CAP_LARGE_FILES | CAP_NT_SMBS | CAP_LEVEL_II_OPLOCKS |
            CAP_EXTENDED_SECURITY;
        if (ses->capabilities & CAP_UNICODE) {
                smb_buffer->Flags2 |= SMBFLG2_UNICODE;
-               pSMB->req.Capabilities |= CAP_UNICODE;
+               capabilities |= CAP_UNICODE;
        }
        if (ses->capabilities & CAP_STATUS32) {
                smb_buffer->Flags2 |= SMBFLG2_ERR_STATUS;
-               pSMB->req.Capabilities |= CAP_STATUS32;
+               capabilities |= CAP_STATUS32;
        }
        if (ses->capabilities & CAP_DFS) {
                smb_buffer->Flags2 |= SMBFLG2_DFS;
-               pSMB->req.Capabilities |= CAP_DFS;
+               capabilities |= CAP_DFS;
        }
-       pSMB->req.Capabilities = cpu_to_le32(pSMB->req.Capabilities);
+       pSMB->req.Capabilities = cpu_to_le32(capabilities);
 
        bcc_ptr = (char *) &pSMB->req.SecurityBlob;
        SecurityBlob = (PAUTHENTICATE_MESSAGE) bcc_ptr;
        strncpy(SecurityBlob->Signature, NTLMSSP_SIGNATURE, 8);
        SecurityBlob->MessageType = NtLmAuthenticate;
        bcc_ptr += SecurityBlobLength;
-       SecurityBlob->NegotiateFlags =
+       negotiate_flags = 
            NTLMSSP_NEGOTIATE_UNICODE | NTLMSSP_REQUEST_TARGET |
            NTLMSSP_NEGOTIATE_NTLM | NTLMSSP_NEGOTIATE_TARGET_INFO |
            0x80000000 | NTLMSSP_NEGOTIATE_128;
        if(sign_CIFS_PDUs)
-               SecurityBlob->NegotiateFlags |= /* NTLMSSP_NEGOTIATE_ALWAYS_SIGN |*/ NTLMSSP_NEGOTIATE_SIGN;
+               negotiate_flags |= /* NTLMSSP_NEGOTIATE_ALWAYS_SIGN |*/ NTLMSSP_NEGOTIATE_SIGN;
        if(ntlmv2_flag)
-               SecurityBlob->NegotiateFlags |= NTLMSSP_NEGOTIATE_NTLMV2;
+               negotiate_flags |= NTLMSSP_NEGOTIATE_NTLMV2;
 
 /* setup pointers to domain name and workstation name */
 
@@ -2397,14 +2783,14 @@ CIFSNTLMSSPAuthSessSetup(unsigned int xid, struct cifsSesInfo *ses,
        SecurityBlob->LmChallengeResponse.Buffer = 0;
 
        SecurityBlob->NtChallengeResponse.Length =
-           cpu_to_le16(CIFS_SESSION_KEY_SIZE);
+           cpu_to_le16(CIFS_SESS_KEY_SIZE);
        SecurityBlob->NtChallengeResponse.MaximumLength =
-           cpu_to_le16(CIFS_SESSION_KEY_SIZE);
-       memcpy(bcc_ptr, ntlm_session_key, CIFS_SESSION_KEY_SIZE);
+           cpu_to_le16(CIFS_SESS_KEY_SIZE);
+       memcpy(bcc_ptr, ntlm_session_key, CIFS_SESS_KEY_SIZE);
        SecurityBlob->NtChallengeResponse.Buffer =
            cpu_to_le32(SecurityBlobLength);
-       SecurityBlobLength += CIFS_SESSION_KEY_SIZE;
-       bcc_ptr += CIFS_SESSION_KEY_SIZE;
+       SecurityBlobLength += CIFS_SESS_KEY_SIZE;
+       bcc_ptr += CIFS_SESS_KEY_SIZE;
 
        if (ses->capabilities & CAP_UNICODE) {
                if (domain == NULL) {
@@ -2412,39 +2798,39 @@ CIFSNTLMSSPAuthSessSetup(unsigned int xid, struct cifsSesInfo *ses,
                        SecurityBlob->DomainName.Length = 0;
                        SecurityBlob->DomainName.MaximumLength = 0;
                } else {
-                       SecurityBlob->DomainName.Length =
-                           cifs_strtoUCS((wchar_t *) bcc_ptr, domain, 64,
+                       __u16 len =
+                           cifs_strtoUCS((__le16 *) bcc_ptr, domain, 64,
                                          nls_codepage);
-                       SecurityBlob->DomainName.Length *= 2;
+                       len *= 2;
                        SecurityBlob->DomainName.MaximumLength =
-                           cpu_to_le16(SecurityBlob->DomainName.Length);
+                           cpu_to_le16(len);
                        SecurityBlob->DomainName.Buffer =
                            cpu_to_le32(SecurityBlobLength);
-                       bcc_ptr += SecurityBlob->DomainName.Length;
-                       SecurityBlobLength += SecurityBlob->DomainName.Length;
+                       bcc_ptr += len;
+                       SecurityBlobLength += len;
                        SecurityBlob->DomainName.Length =
-                           cpu_to_le16(SecurityBlob->DomainName.Length);
+                           cpu_to_le16(len);
                }
                if (user == NULL) {
                        SecurityBlob->UserName.Buffer = 0;
                        SecurityBlob->UserName.Length = 0;
                        SecurityBlob->UserName.MaximumLength = 0;
                } else {
-                       SecurityBlob->UserName.Length =
-                           cifs_strtoUCS((wchar_t *) bcc_ptr, user, 64,
+                       __u16 len =
+                           cifs_strtoUCS((__le16 *) bcc_ptr, user, 64,
                                          nls_codepage);
-                       SecurityBlob->UserName.Length *= 2;
+                       len *= 2;
                        SecurityBlob->UserName.MaximumLength =
-                           cpu_to_le16(SecurityBlob->UserName.Length);
+                           cpu_to_le16(len);
                        SecurityBlob->UserName.Buffer =
                            cpu_to_le32(SecurityBlobLength);
-                       bcc_ptr += SecurityBlob->UserName.Length;
-                       SecurityBlobLength += SecurityBlob->UserName.Length;
+                       bcc_ptr += len;
+                       SecurityBlobLength += len;
                        SecurityBlob->UserName.Length =
-                           cpu_to_le16(SecurityBlob->UserName.Length);
+                           cpu_to_le16(len);
                }
 
-               /* SecurityBlob->WorkstationName.Length = cifs_strtoUCS((wchar_t *) bcc_ptr, "AMACHINE",64, nls_codepage);
+               /* SecurityBlob->WorkstationName.Length = cifs_strtoUCS((__le16 *) bcc_ptr, "AMACHINE",64, nls_codepage);
                   SecurityBlob->WorkstationName.Length *= 2;
                   SecurityBlob->WorkstationName.MaximumLength = cpu_to_le16(SecurityBlob->WorkstationName.Length);
                   SecurityBlob->WorkstationName.Buffer = cpu_to_le32(SecurityBlobLength);
@@ -2457,16 +2843,16 @@ CIFSNTLMSSPAuthSessSetup(unsigned int xid, struct cifsSesInfo *ses,
                        bcc_ptr++;
                }
                bytes_returned =
-                   cifs_strtoUCS((wchar_t *) bcc_ptr, "Linux version ",
+                   cifs_strtoUCS((__le16 *) bcc_ptr, "Linux version ",
                                  32, nls_codepage);
                bcc_ptr += 2 * bytes_returned;
                bytes_returned =
-                   cifs_strtoUCS((wchar_t *) bcc_ptr, UTS_RELEASE, 32,
+                   cifs_strtoUCS((__le16 *) bcc_ptr, utsname()->release, 32,
                                  nls_codepage);
                bcc_ptr += 2 * bytes_returned;
                bcc_ptr += 2;   /* null term version string */
                bytes_returned =
-                   cifs_strtoUCS((wchar_t *) bcc_ptr, CIFS_NETWORK_OPSYS,
+                   cifs_strtoUCS((__le16 *) bcc_ptr, CIFS_NETWORK_OPSYS,
                                  64, nls_codepage);
                bcc_ptr += 2 * bytes_returned;
                *(bcc_ptr + 1) = 0;
@@ -2481,52 +2867,50 @@ CIFSNTLMSSPAuthSessSetup(unsigned int xid, struct cifsSesInfo *ses,
                        SecurityBlob->DomainName.Length = 0;
                        SecurityBlob->DomainName.MaximumLength = 0;
                } else {
-                       SecurityBlob->NegotiateFlags |=
-                           NTLMSSP_NEGOTIATE_DOMAIN_SUPPLIED;
+                       __u16 len;
+                       negotiate_flags |= NTLMSSP_NEGOTIATE_DOMAIN_SUPPLIED;
                        strncpy(bcc_ptr, domain, 63);
-                       SecurityBlob->DomainName.Length = strnlen(domain, 64);
+                       len = strnlen(domain, 64);
                        SecurityBlob->DomainName.MaximumLength =
-                           cpu_to_le16(SecurityBlob->DomainName.Length);
+                           cpu_to_le16(len);
                        SecurityBlob->DomainName.Buffer =
                            cpu_to_le32(SecurityBlobLength);
-                       bcc_ptr += SecurityBlob->DomainName.Length;
-                       SecurityBlobLength += SecurityBlob->DomainName.Length;
-                       SecurityBlob->DomainName.Length =
-                           cpu_to_le16(SecurityBlob->DomainName.Length);
+                       bcc_ptr += len;
+                       SecurityBlobLength += len;
+                       SecurityBlob->DomainName.Length = cpu_to_le16(len);
                }
                if (user == NULL) {
                        SecurityBlob->UserName.Buffer = 0;
                        SecurityBlob->UserName.Length = 0;
                        SecurityBlob->UserName.MaximumLength = 0;
                } else {
+                       __u16 len;
                        strncpy(bcc_ptr, user, 63);
-                       SecurityBlob->UserName.Length = strnlen(user, 64);
+                       len = strnlen(user, 64);
                        SecurityBlob->UserName.MaximumLength =
-                           cpu_to_le16(SecurityBlob->UserName.Length);
+                           cpu_to_le16(len);
                        SecurityBlob->UserName.Buffer =
                            cpu_to_le32(SecurityBlobLength);
-                       bcc_ptr += SecurityBlob->UserName.Length;
-                       SecurityBlobLength += SecurityBlob->UserName.Length;
-                       SecurityBlob->UserName.Length =
-                           cpu_to_le16(SecurityBlob->UserName.Length);
+                       bcc_ptr += len;
+                       SecurityBlobLength += len;
+                       SecurityBlob->UserName.Length = cpu_to_le16(len);
                }
                /* BB fill in our workstation name if known BB */
 
                strcpy(bcc_ptr, "Linux version ");
                bcc_ptr += strlen("Linux version ");
-               strcpy(bcc_ptr, UTS_RELEASE);
-               bcc_ptr += strlen(UTS_RELEASE) + 1;
+               strcpy(bcc_ptr, utsname()->release);
+               bcc_ptr += strlen(utsname()->release) + 1;
                strcpy(bcc_ptr, CIFS_NETWORK_OPSYS);
                bcc_ptr += strlen(CIFS_NETWORK_OPSYS) + 1;
                bcc_ptr++;      /* null domain */
                *bcc_ptr = 0;
        }
-       SecurityBlob->NegotiateFlags =
-           cpu_to_le32(SecurityBlob->NegotiateFlags);
+       SecurityBlob->NegotiateFlags = cpu_to_le32(negotiate_flags);
        pSMB->req.SecurityBlobLength = cpu_to_le16(SecurityBlobLength);
-       BCC(smb_buffer) = (long) bcc_ptr - (long) pByteArea(smb_buffer);
-       smb_buffer->smb_buf_length += BCC(smb_buffer);
-       BCC(smb_buffer) = cpu_to_le16(BCC(smb_buffer));
+       count = (long) bcc_ptr - (long) pByteArea(smb_buffer);
+       smb_buffer->smb_buf_length += count;
+       pSMB->req.ByteCount = cpu_to_le16(count);
 
        rc = SendReceive(xid, ses, smb_buffer, smb_buffer_response,
                         &bytes_returned, 1);
@@ -2534,10 +2918,10 @@ CIFSNTLMSSPAuthSessSetup(unsigned int xid, struct cifsSesInfo *ses,
 /*    rc = map_smb_to_linux_error(smb_buffer_response);  *//* done in SendReceive now */
        } else if ((smb_buffer_response->WordCount == 3)
                   || (smb_buffer_response->WordCount == 4)) {
-               pSMBr->resp.Action = le16_to_cpu(pSMBr->resp.Action);
-               pSMBr->resp.SecurityBlobLength =
+               __u16 action = le16_to_cpu(pSMBr->resp.Action);
+               __u16 blob_len =
                    le16_to_cpu(pSMBr->resp.SecurityBlobLength);
-               if (pSMBr->resp.Action & GUEST_LOGIN)
+               if (action & GUEST_LOGIN)
                        cFYI(1, (" Guest login"));      /* BB do we want to set anything in SesInfo struct ? */
 /*        if(SecurityBlob2->MessageType != NtLm??){                               
                  cFYI("Unexpected message type on auth response is %d ")); 
@@ -2551,14 +2935,14 @@ CIFSNTLMSSPAuthSessSetup(unsigned int xid, struct cifsSesInfo *ses,
             /* response can have either 3 or 4 word count - Samba sends 3 */
                        if ((pSMBr->resp.hdr.WordCount == 3)
                            || ((pSMBr->resp.hdr.WordCount == 4)
-                               && (pSMBr->resp.SecurityBlobLength <
+                               && (blob_len <
                                    pSMBr->resp.ByteCount))) {
                                if (pSMBr->resp.hdr.WordCount == 4) {
                                        bcc_ptr +=
-                                           pSMBr->resp.SecurityBlobLength;
+                                           blob_len;
                                        cFYI(1,
                                             ("Security Blob Length %d ",
-                                             pSMBr->resp.SecurityBlobLength));
+                                             blob_len));
                                }
 
                                cFYI(1,
@@ -2578,10 +2962,12 @@ CIFSNTLMSSPAuthSessSetup(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  */
+                                       if(ses->serverOS)
+                                               kfree(ses->serverOS);
                                        ses->serverOS =
-                                           cifs_kcalloc(2 * (len + 1), GFP_KERNEL);
+                                           kzalloc(2 * (len + 1), GFP_KERNEL);
                                        cifs_strfromUCS_le(ses->serverOS,
-                                                          (wchar_t *)
+                                                          (__le16 *)
                                                           bcc_ptr, len,
                                                           nls_codepage);
                                        bcc_ptr += 2 * (len + 1);
@@ -2593,12 +2979,13 @@ CIFSNTLMSSPAuthSessSetup(unsigned int xid, struct cifsSesInfo *ses,
                                                                 bcc_ptr,
                                                                 remaining_words
                                                                 - 1);
+                                               kfree(ses->serverNOS);
                                                ses->serverNOS =
-                                                   cifs_kcalloc(2 * (len + 1),
+                                                   kzalloc(2 * (len + 1),
                                                            GFP_KERNEL);
                                                cifs_strfromUCS_le(ses->
                                                                   serverNOS,
-                                                                  (wchar_t *)
+                                                                  (__le16 *)
                                                                   bcc_ptr,
                                                                   len,
                                                                   nls_codepage);
@@ -2609,15 +2996,17 @@ CIFSNTLMSSPAuthSessSetup(unsigned int xid, struct cifsSesInfo *ses,
                                                if (remaining_words > 0) {
                                                        len = UniStrnlen((wchar_t *) bcc_ptr, remaining_words); 
      /* last string not always null terminated (e.g. for Windows XP & 2000) */
+                                                       if(ses->serverDomain)
+                                                               kfree(ses->serverDomain);
                                                        ses->serverDomain =
-                                                           cifs_kcalloc(2 *
+                                                           kzalloc(2 *
                                                                    (len +
                                                                     1),
                                                                    GFP_KERNEL);
                                                        cifs_strfromUCS_le
                                                            (ses->
                                                             serverDomain,
-                                                            (wchar_t *)
+                                                            (__le16 *)
                                                             bcc_ptr, len,
                                                             nls_codepage);
                                                        bcc_ptr +=
@@ -2634,18 +3023,26 @@ CIFSNTLMSSPAuthSessSetup(unsigned int xid, struct cifsSesInfo *ses,
                                                                          len)]
                                                            = 0;
                                                } /* else no more room so create dummy domain string */
-                                               else
-                                                       ses->serverDomain = cifs_kcalloc(2,GFP_KERNEL);
+                                               else {
+                                                       if(ses->serverDomain)
+                                                               kfree(ses->serverDomain);
+                                                       ses->serverDomain = kzalloc(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);
+                                               if(ses->serverDomain)
+                                                       kfree(ses->serverDomain);
+                                               ses->serverDomain = kzalloc(2, GFP_KERNEL);
+                                               kfree(ses->serverNOS);
+                                               ses->serverNOS = kzalloc(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);
+                                               if(ses->serverOS)
+                                                       kfree(ses->serverOS);
+                                               ses->serverOS = kzalloc(len + 1,GFP_KERNEL);
                                                strncpy(ses->serverOS,bcc_ptr, len);
 
                                                bcc_ptr += len;
@@ -2653,14 +3050,17 @@ CIFSNTLMSSPAuthSessSetup(unsigned int xid, struct cifsSesInfo *ses,
                                                bcc_ptr++;
 
                                                len = strnlen(bcc_ptr, 1024);
-                                               ses->serverNOS = cifs_kcalloc(len+1,GFP_KERNEL);
+                                               kfree(ses->serverNOS);
+                                               ses->serverNOS = kzalloc(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);
+                                               if(ses->serverDomain)
+                                                       kfree(ses->serverDomain);
+                                               ses->serverDomain = kzalloc(len+1,GFP_KERNEL);
                                                strncpy(ses->serverDomain, bcc_ptr, len);
                                                bcc_ptr += len;
                                                bcc_ptr[0] = 0;
@@ -2699,32 +3099,64 @@ CIFSTCon(unsigned int xid, struct cifsSesInfo *ses,
        struct smb_hdr *smb_buffer_response;
        TCONX_REQ *pSMB;
        TCONX_RSP *pSMBr;
-       char *bcc_ptr;
+       unsigned char *bcc_ptr;
        int rc = 0;
        int length;
+       __u16 count;
 
        if (ses == NULL)
                return -EIO;
 
        smb_buffer = cifs_buf_get();
-       if (smb_buffer == 0) {
+       if (smb_buffer == NULL) {
                return -ENOMEM;
        }
        smb_buffer_response = smb_buffer;
 
        header_assemble(smb_buffer, SMB_COM_TREE_CONNECT_ANDX,
                        NULL /*no tid */ , 4 /*wct */ );
+
+       smb_buffer->Mid = GetNextMid(ses->server);
        smb_buffer->Uid = ses->Suid;
        pSMB = (TCONX_REQ *) smb_buffer;
        pSMBr = (TCONX_RSP *) smb_buffer_response;
 
        pSMB->AndXCommand = 0xFF;
        pSMB->Flags = cpu_to_le16(TCON_EXTENDED_SECINFO);
-       pSMB->PasswordLength = cpu_to_le16(1);  /* minimum */
-       bcc_ptr = &(pSMB->Password[0]);
-       bcc_ptr++;              /* skip password */
+       bcc_ptr = &pSMB->Password[0];
+       if((ses->server->secMode) & SECMODE_USER) {
+               pSMB->PasswordLength = cpu_to_le16(1);  /* minimum */
+               *bcc_ptr = 0; /* password is null byte */
+               bcc_ptr++;              /* skip password */
+               /* already aligned so no need to do it below */
+       } else {
+               pSMB->PasswordLength = cpu_to_le16(CIFS_SESS_KEY_SIZE);
+               /* BB FIXME add code to fail this if NTLMv2 or Kerberos
+                  specified as required (when that support is added to
+                  the vfs in the future) as only NTLM or the much
+                  weaker LANMAN (which we do not send by default) is accepted
+                  by Samba (not sure whether other servers allow
+                  NTLMv2 password here) */
+#ifdef CONFIG_CIFS_WEAK_PW_HASH
+               if((extended_security & CIFSSEC_MAY_LANMAN) && 
+                       (ses->server->secType == LANMAN))
+                       calc_lanman_hash(ses, bcc_ptr);
+               else
+#endif /* CIFS_WEAK_PW_HASH */
+               SMBNTencrypt(ses->password,
+                            ses->server->cryptKey,
+                            bcc_ptr);
+
+               bcc_ptr += CIFS_SESS_KEY_SIZE;
+               if(ses->capabilities & CAP_UNICODE) {
+                       /* must align unicode strings */
+                       *bcc_ptr = 0; /* null byte password */
+                       bcc_ptr++;
+               }
+       }
 
-       if(ses->server->secMode & (SECMODE_SIGN_REQUIRED | SECMODE_SIGN_ENABLED))
+       if(ses->server->secMode & 
+                       (SECMODE_SIGN_REQUIRED | SECMODE_SIGN_ENABLED))
                smb_buffer->Flags2 |= SMBFLG2_SECURITY_SIGNATURE;
 
        if (ses->capabilities & CAP_STATUS32) {
@@ -2736,27 +3168,28 @@ CIFSTCon(unsigned int xid, struct cifsSesInfo *ses,
        if (ses->capabilities & CAP_UNICODE) {
                smb_buffer->Flags2 |= SMBFLG2_UNICODE;
                length =
-                   cifs_strtoUCS((wchar_t *) bcc_ptr, tree, 100, nls_codepage);
-               bcc_ptr += 2 * length;  /* convert num of 16 bit words to bytes */
+                   cifs_strtoUCS((__le16 *) bcc_ptr, tree, 
+                       6 /* max utf8 char length in bytes */ * 
+                       (/* server len*/ + 256 /* share len */), nls_codepage);
+               bcc_ptr += 2 * length;  /* convert num 16 bit words to bytes */
                bcc_ptr += 2;   /* skip trailing null */
        } else {                /* ASCII */
-
                strcpy(bcc_ptr, tree);
                bcc_ptr += strlen(tree) + 1;
        }
        strcpy(bcc_ptr, "?????");
        bcc_ptr += strlen("?????");
        bcc_ptr += 1;
-       BCC(smb_buffer) = (long) bcc_ptr - (long) pByteArea(smb_buffer);
-       smb_buffer->smb_buf_length += BCC(smb_buffer);
-       BCC(smb_buffer) = cpu_to_le16(BCC(smb_buffer));
+       count = bcc_ptr - &pSMB->Password[0];
+       pSMB->hdr.smb_buf_length += count;
+       pSMB->ByteCount = cpu_to_le16(count);
 
        rc = SendReceive(xid, ses, smb_buffer, smb_buffer_response, &length, 0);
 
        /* if (rc) rc = map_smb_to_linux_error(smb_buffer_response); */
        /* above now done in SendReceive */
        if ((rc == 0) && (tcon != NULL)) {
-        tcon->tidStatus = CifsGood;
+               tcon->tidStatus = CifsGood;
                tcon->tid = smb_buffer_response->Tid;
                bcc_ptr = pByteArea(smb_buffer_response);
                length = strnlen(bcc_ptr, BCC(smb_buffer_response) - 2);
@@ -2765,15 +3198,14 @@ CIFSTCon(unsigned int xid, struct cifsSesInfo *ses,
                strncpy(tcon->treeName, tree, MAX_TREE_SIZE);
                if (smb_buffer->Flags2 & SMBFLG2_UNICODE) {
                        length = UniStrnlen((wchar_t *) bcc_ptr, 512);
-                       if (((long) bcc_ptr + (2 * length)) -
-                           (long) pByteArea(smb_buffer_response) <=
+                       if ((bcc_ptr + (2 * length)) -
+                            pByteArea(smb_buffer_response) <=
                            BCC(smb_buffer_response)) {
-                               if(tcon->nativeFileSystem)
-                                       kfree(tcon->nativeFileSystem);
+                               kfree(tcon->nativeFileSystem);
                                tcon->nativeFileSystem =
-                                   cifs_kcalloc(length + 2, GFP_KERNEL);
+                                   kzalloc(length + 2, GFP_KERNEL);
                                cifs_strfromUCS_le(tcon->nativeFileSystem,
-                                                  (wchar_t *) bcc_ptr,
+                                                  (__le16 *) bcc_ptr,
                                                   length, nls_codepage);
                                bcc_ptr += 2 * length;
                                bcc_ptr[0] = 0; /* null terminate the string */
@@ -2783,19 +3215,23 @@ CIFSTCon(unsigned int xid, struct cifsSesInfo *ses,
                        /* else do not bother copying these informational fields */
                } else {
                        length = strnlen(bcc_ptr, 1024);
-                       if (((long) bcc_ptr + length) -
-                           (long) pByteArea(smb_buffer_response) <=
+                       if ((bcc_ptr + length) -
+                           pByteArea(smb_buffer_response) <=
                            BCC(smb_buffer_response)) {
-                               if(tcon->nativeFileSystem)
-                                       kfree(tcon->nativeFileSystem);
+                               kfree(tcon->nativeFileSystem);
                                tcon->nativeFileSystem =
-                                   cifs_kcalloc(length + 1, GFP_KERNEL);
+                                   kzalloc(length + 1, GFP_KERNEL);
                                strncpy(tcon->nativeFileSystem, bcc_ptr,
                                        length);
                        }
                        /* else do not bother copying these informational fields */
                }
-               tcon->Flags = le16_to_cpu(pSMBr->OptionalSupport);
+               if((smb_buffer_response->WordCount == 3) ||
+                        (smb_buffer_response->WordCount == 7))
+                       /* field is in same location */
+                       tcon->Flags = le16_to_cpu(pSMBr->OptionalSupport);
+               else
+                       tcon->Flags = 0;
                cFYI(1, ("Tcon flags: 0x%x ", tcon->Flags));
        } else if ((rc == 0) && tcon == NULL) {
         /* all we need to save for IPC$ connection */
@@ -2814,6 +3250,7 @@ cifs_umount(struct super_block *sb, struct cifs_sb_info *cifs_sb)
        int xid;
        struct cifsSesInfo *ses = NULL;
        struct task_struct *cifsd_task;
+       char * tmp;
 
        xid = GetXid();
 
@@ -2835,7 +3272,10 @@ 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);
+                                       wait_for_completion(&cifsd_complete);
+                               }
                                rc = 0;
                        } /* else - we have an smb session
                                left on this socket do not kill cifsd */
@@ -2844,10 +3284,12 @@ cifs_umount(struct super_block *sb, struct cifs_sb_info *cifs_sb)
        }
        
        cifs_sb->tcon = NULL;
-       if (ses) {
-               set_current_state(TASK_INTERRUPTIBLE);
-               schedule_timeout(HZ / 2);
-       }
+       tmp = cifs_sb->prepath;
+       cifs_sb->prepathlen = 0;
+       cifs_sb->prepath = NULL;
+       kfree(tmp);
+       if (ses)
+               schedule_timeout_interruptible(msecs_to_jiffies(500));
        if (ses)
                sesInfoFree(ses);
 
@@ -2859,8 +3301,9 @@ int cifs_setup_session(unsigned int xid, struct cifsSesInfo *pSesInfo,
                                           struct nls_table * nls_info)
 {
        int rc = 0;
-       char ntlm_session_key[CIFS_SESSION_KEY_SIZE];
+       char ntlm_session_key[CIFS_SESS_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 */ {
@@ -2879,28 +3322,30 @@ int cifs_setup_session(unsigned int xid, struct cifsSesInfo *pSesInfo,
                        spin_unlock(&GlobalMid_Lock);
 
                }
+               first_time = 1;
        }
        if (!rc) {
+               pSesInfo->flags = 0;
                pSesInfo->capabilities = pSesInfo->server->capabilities;
                if(linuxExtEnabled == 0)
                        pSesInfo->capabilities &= (~CAP_UNIX);
-               pSesInfo->sequence_number = 0;
-               cFYI(1,("Security Mode: 0x%x Capabilities: 0x%x Time Zone: %d",
+       /*      pSesInfo->sequence_number = 0;*/
+               cFYI(1,("Security Mode: 0x%x Capabilities: 0x%x TimeAdjust: %d",
                        pSesInfo->server->secMode,
                        pSesInfo->server->capabilities,
-                       pSesInfo->server->timeZone));
-               if (extended_security
-                               && (pSesInfo->capabilities & CAP_EXTENDED_SECURITY)
+                       pSesInfo->server->timeAdj));
+               if(experimEnabled < 2)
+                       rc = CIFS_SessSetup(xid, pSesInfo,
+                                           first_time, nls_info);
+               else if (extended_security
+                               && (pSesInfo->capabilities 
+                                       & CAP_EXTENDED_SECURITY)
                                && (pSesInfo->server->secType == NTLMSSP)) {
-                       cFYI(1, ("New style sesssetup "));
-                       rc = CIFSSpnegoSessSetup(xid, pSesInfo,
-                               NULL /* security blob */, 
-                               0 /* blob length */,
-                               nls_info);
+                       rc = -EOPNOTSUPP;
                } else if (extended_security
                           && (pSesInfo->capabilities & CAP_EXTENDED_SECURITY)
                           && (pSesInfo->server->secType == RawNTLMSSP)) {
-                       cFYI(1, ("NTLMSSP sesssetup "));
+                       cFYI(1, ("NTLMSSP sesssetup"));
                        rc = CIFSNTLMSSPNegotiateSessSetup(xid,
                                                pSesInfo,
                                                &ntlmv2_flag,
@@ -2908,26 +3353,36 @@ int cifs_setup_session(unsigned int xid, struct cifsSesInfo *pSesInfo,
                        if (!rc) {
                                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);
+                                       cFYI(1,("more secure NTLM ver2 hash"));
+                                       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 */
@@ -2943,8 +3398,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);
                }
@@ -2955,6 +3413,7 @@ int cifs_setup_session(unsigned int xid, struct cifsSesInfo *pSesInfo,
                        pSesInfo->status = CifsGood;
                }
        }
+ss_err_exit:
        return rc;
 }