--- linux-2.6.13/fs/cifs/asn1.c
+++ linux-2.6.13/fs/cifs/asn1.c
@@ -191,7 +191,8 @@
 		   unsigned char **eoc,
 		   unsigned int *cls, unsigned int *con, unsigned int *tag)
 {
-	unsigned int def, len;
+	unsigned int def = 0; 
+	unsigned int len = 0;
 
 	if (!asn1_id_decode(ctx, cls, con, tag))
 		return 0;
@@ -466,7 +467,7 @@
 	asn1_open(&ctx, security_blob, length);
 
 	if (asn1_header_decode(&ctx, &end, &cls, &con, &tag) == 0) {
-		cFYI(1, ("Error decoding negTokenInit header "));
+		cFYI(1, ("Error decoding negTokenInit header"));
 		return 0;
 	} else if ((cls != ASN1_APL) || (con != ASN1_CON)
 		   || (tag != ASN1_EOC)) {
@@ -494,7 +495,7 @@
 		}
 
 		if (asn1_header_decode(&ctx, &end, &cls, &con, &tag) == 0) {
-			cFYI(1, ("Error decoding negTokenInit "));
+			cFYI(1, ("Error decoding negTokenInit"));
 			return 0;
 		} else if ((cls != ASN1_CTX) || (con != ASN1_CON)
 			   || (tag != ASN1_EOC)) {
@@ -504,7 +505,7 @@
 		}
 
 		if (asn1_header_decode(&ctx, &end, &cls, &con, &tag) == 0) {
-			cFYI(1, ("Error decoding negTokenInit "));
+			cFYI(1, ("Error decoding negTokenInit"));
 			return 0;
 		} else if ((cls != ASN1_UNI) || (con != ASN1_CON)
 			   || (tag != ASN1_SEQ)) {
@@ -514,7 +515,7 @@
 		}
 
 		if (asn1_header_decode(&ctx, &end, &cls, &con, &tag) == 0) {
-			cFYI(1, ("Error decoding 2nd part of negTokenInit "));
+			cFYI(1, ("Error decoding 2nd part of negTokenInit"));
 			return 0;
 		} else if ((cls != ASN1_CTX) || (con != ASN1_CON)
 			   || (tag != ASN1_EOC)) {
@@ -526,7 +527,7 @@
 
 		if (asn1_header_decode
 		    (&ctx, &sequence_end, &cls, &con, &tag) == 0) {
-			cFYI(1, ("Error decoding 2nd part of negTokenInit "));
+			cFYI(1, ("Error decoding 2nd part of negTokenInit"));
 			return 0;
 		} else if ((cls != ASN1_UNI) || (con != ASN1_CON)
 			   || (tag != ASN1_SEQ)) {
@@ -552,7 +553,6 @@
 					   *(oid + 3)));
 					rc = compare_oid(oid, oidlen, NTLMSSP_OID,
 						 NTLMSSP_OID_LEN);
-					if(oid)
 						kfree(oid);
 					if (rc)
 						use_ntlmssp = TRUE;
--- linux-2.6.13/fs/cifs/AUTHORS
+++ linux-2.6.13/fs/cifs/AUTHORS
@@ -32,6 +32,10 @@
 Jesper Juhl (in particular for lots of whitespace/formatting cleanup)
 Vince Negri and Dave Stahl (for finding an important caching bug)
 Adrian Bunk (kcalloc cleanups)
+Miklos Szeredi 
+Kazeon team for various fixes especially for 2.4 version.
+Asser Ferno (Change Notify support)
+Shaggy (Dave Kleikamp) for inumerable small fs suggestions and some good cleanup
 
 Test case and Bug Report contributors
 -------------------------------------
--- linux-2.6.13/fs/cifs/CHANGES
+++ linux-2.6.13/fs/cifs/CHANGES
@@ -1,8 +1,116 @@
+Version 1.45
+------------
+Do not time out lockw calls when using posix extensions. Do not
+time out requests if server still responding reasonably fast
+on requests on other threads
+
+Version 1.44
+------------
+Rewritten sessionsetup support, including support for legacy SMB
+session setup needed for OS/2 and older servers such as Windows 95 and 98.
+Fix oops on ls to OS/2 servers.  Add support for level 1 FindFirst
+so we can do search (ls etc.) to OS/2.  Do not send NTCreateX
+or recent levels of FindFirst unless server says it supports NT SMBs
+(instead use legacy equivalents from LANMAN dialect). Fix to allow
+NTLMv2 authentication support (now can use stronger password hashing
+on mount if corresponding /proc/fs/cifs/SecurityFlags is set (0x4004).
+Allow override of global cifs security flags on mount via "sec=" option(s).
+
+Version 1.43
+------------
+POSIX locking to servers which support CIFS POSIX Extensions
+(disabled by default controlled by proc/fs/cifs/Experimental).
+Handle conversion of long share names (especially Asian languages)
+to Unicode during mount. Fix memory leak in sess struct on reconnect.
+Fix rare oops after acpi suspend.  Fix O_TRUNC opens to overwrite on
+cifs open which helps rare case when setpathinfo fails or server does
+not support it. 
+
+Version 1.42
+------------
+Fix slow oplock break when mounted to different servers at the same time and
+the tids match and we try to find matching fid on wrong server. Fix read
+looping when signing required by server (2.6.16 kernel only). Fix readdir
+vs. rename race which could cause each to hang. Return . and .. even
+if server does not.  Allow searches to skip first three entries and
+begin at any location. Fix oops in find_writeable_file.
+
+Version 1.41
+------------
+Fix NTLMv2 security (can be enabled in /proc/fs/cifs) so customers can
+configure stronger authentication.  Fix sfu symlinks so they can
+be followed (not just recognized).  Fix wraparound of bcc on
+read responses when buffer size over 64K and also fix wrap of
+max smb buffer size when CIFSMaxBufSize over 64K.  Fix oops in
+cifs_user_read and cifs_readpages (when EAGAIN on send of smb
+on socket is returned over and over).  Add POSIX (advisory) byte range
+locking support (requires server with newest CIFS UNIX Extensions
+to the protocol implemented). Slow down negprot slightly in port 139
+RFC1001 case to give session_init time on buggy servers.
+
+Version 1.40
+------------
+Use fsuid (fsgid) more consistently instead of uid (gid). Improve performance
+of readpages by eliminating one extra memcpy. Allow update of file size
+from remote server even if file is open for write as long as mount is
+directio.  Recognize share mode security and send NTLM encrypted password
+on tree connect if share mode negotiated.
+
+Version 1.39
+------------
+Defer close of a file handle slightly if pending writes depend on that handle
+(this reduces the EBADF bad file handle errors that can be logged under heavy
+stress on writes). Modify cifs Kconfig options to expose CONFIG_CIFS_STATS2 
+Fix SFU style symlinks and mknod needed for servers which do not support the
+CIFS Unix Extensions.  Fix setfacl/getfacl on bigendian. Timeout negative
+dentries so files that the client sees as deleted but that later get created
+on the server will be recognized.  Add client side permission check on setattr.
+Timeout stuck requests better (where server has never responded or sent corrupt
+responses)
+
+Version 1.38
+------------
+Fix tcp socket retransmission timeouts (e.g. on ENOSPACE from the socket)
+to be smaller at first (but increasing) so large write performance performance
+over GigE is better.  Do not hang thread on illegal byte range lock response
+from Windows (Windows can send an RFC1001 size which does not match smb size) by
+allowing an SMBs TCP length to be up to a few bytes longer than it should be.
+wsize and rsize can now be larger than negotiated buffer size if server
+supports large readx/writex, even when directio mount flag not specified.
+Write size will in many cases now be 16K instead of 4K which greatly helps
+file copy performance on lightly loaded networks.  Fix oops in dnotify
+when experimental config flag enabled. Make cifsFYI more granular.
+
+Version 1.37
+------------
+Fix readdir caching when unlink removes file in current search buffer,
+and this is followed by a rewind search to just before the deleted entry.
+Do not attempt to set ctime unless atime and/or mtime change requested
+(most servers throw it away anyway). Fix length check of received smbs
+to be more accurate. Fix big endian problem with mapchars mount option,
+and with a field returned by statfs.
+
+Version 1.36
+------------
+Add support for mounting to older pre-CIFS servers such as Windows9x and ME.
+For these older servers, add option for passing netbios name of server in
+on mount (servernetbiosname).  Add suspend support for power management, to
+avoid cifsd thread preventing software suspend from working.
+Add mount option for disabling the default behavior of sending byte range lock
+requests to the server (necessary for certain applications which break with
+mandatory lock behavior such as Evolution), and also mount option for
+requesting case insensitive matching for path based requests (requesting
+case sensitive is the default).
+
 Version 1.35
 ------------
 Add writepage performance improvements.  Fix path name conversions
 for long filenames on mounts which were done with "mapchars" mount option
-specified.
+specified.  Ensure multiplex ids do not collide.  Fix case in which 
+rmmod can oops if done soon after last unmount.  Fix truncated
+search (readdir) output when resume filename was a long filename.
+Fix filename conversion when mapchars mount option was specified and
+filename was a long filename.
 
 Version 1.34
 ------------
@@ -11,7 +119,7 @@
 kills the cifsd thread (NB: killing the cifs kernel threads is not
 recommended, unmount and rmmod cifs will kill them when they are
 no longer needed).  Fix readdir to ASCII servers (ie older servers
-which do not support Unicode) and also require asterik.
+which do not support Unicode) and also require asterisk.
 Fix out of memory case in which data could be written one page
 off in the page cache.
 
@@ -101,7 +209,7 @@
 
 Version 1.25
 ------------
-Fix internationlization problem in cifs readdir with filenames that map to 
+Fix internationalization problem in cifs readdir with filenames that map to 
 longer UTF8 strings than the string on the wire was in Unicode.  Add workaround
 for readdir to netapp servers. Fix search rewind (seek into readdir to return 
 non-consecutive entries).  Do not do readdir when server negotiates 
@@ -276,7 +384,7 @@
 page cache could contain stale data, and write through did
 not occur often enough while file was still open when read ahead
 (read oplock) not allowed.  Treat "sep=" when first mount option
-as an overrride of comma as the default separator between mount
+as an override of comma as the default separator between mount
 options. 
 
 Version 1.01
@@ -286,7 +394,7 @@
 Version 1.00
 ------------
 Gracefully clean up failed mounts when attempting to mount to servers such as
-Windows 98 that terminate tcp sessions during prototocol negotiation.  Handle
+Windows 98 that terminate tcp sessions during protocol negotiation.  Handle
 embedded commas in mount parsing of passwords.
 
 Version 0.99
@@ -295,7 +403,7 @@
 instance is closed so that the client does not continue using stale local
 copy rather than later modified server copy of file.  Do not reconnect
 when server drops the tcp session prematurely before negotiate
-protocol response.  Fix oops in roepen_file when dentry freed.  Allow
+protocol response.  Fix oops in reopen_file when dentry freed.  Allow
 the support for CIFS Unix Extensions to be disabled via proc interface.
 
 Version 0.98
@@ -637,7 +745,7 @@
 Version 0.41
 ------------
 Various minor fixes for Connectathon Posix "basic" file i/o test suite.  Directory caching fixed so hardlinked
-files now return the correct rumber of links on fstat as they are repeatedly linked and unlinked.
+files now return the correct number of links on fstat as they are repeatedly linked and unlinked.
 
 Version 0.40
 ------------
@@ -704,7 +812,7 @@
 and cleaned them up and made them more consistent with other cifs functions. 
 
 7) Server support for Unix extensions is now fully detected and FindFirst is implemented both ways 
-(with or without Unix exentions) but FindNext and QueryPathInfo with the Unix extensions are not completed,
+(with or without Unix extensions) but FindNext and QueryPathInfo with the Unix extensions are not completed,
 nor is the symlink support using the Unix extensions
 
 8) Started adding the readlink and follow_link code 
--- linux-2.6.13/fs/cifs/cifsacl.h
+++ linux-2.6.13/fs/cifs/cifsacl.h
@@ -0,0 +1,38 @@
+/*
+ *   fs/cifs/cifsacl.h
+ *
+ *   Copyright (c) International Business Machines  Corp., 2005
+ *   Author(s): Steve French (sfrench@us.ibm.com)
+ *
+ *   This library is free software; you can redistribute it and/or modify
+ *   it under the terms of the GNU Lesser General Public License as published
+ *   by the Free Software Foundation; either version 2.1 of the License, or
+ *   (at your option) any later version.
+ *
+ *   This library is distributed in the hope that it will be useful,
+ *   but WITHOUT ANY WARRANTY; without even the implied warranty of
+ *   MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See
+ *   the GNU Lesser General Public License for more details.
+ *
+ *   You should have received a copy of the GNU Lesser General Public License
+ *   along with this library; if not, write to the Free Software
+ *   Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
+ */
+
+#ifndef _CIFSACL_H
+#define _CIFSACL_H
+
+struct cifs_sid {
+	__u8 revision; /* revision level */
+	__u8 num_subauths;
+	__u8 authority[6];
+	__u32 sub_auth[4];
+	/* next sub_auth if any ... */
+} __attribute__((packed));
+
+/* everyone */
+extern const struct cifs_sid sid_everyone;
+/* group users */
+extern const struct cifs_sid sid_user;
+
+#endif /* _CIFSACL_H */
--- linux-2.6.13/fs/cifs/cifs_debug.c
+++ linux-2.6.13/fs/cifs/cifs_debug.c
@@ -39,7 +39,7 @@
 	char *charptr = data;
 	char buf[10], line[80];
 
-	printk(KERN_DEBUG "%s: dump of %d bytes of data at 0x%p\n\n", 
+	printk(KERN_DEBUG "%s: dump of %d bytes of data at 0x%p\n", 
 		label, length, data);
 	for (i = 0; i < length; i += 16) {
 		line[0] = 0;
@@ -57,6 +57,57 @@
 	}
 }
 
+#ifdef CONFIG_CIFS_DEBUG2
+void cifs_dump_detail(struct smb_hdr * smb)
+{
+	cERROR(1,("Cmd: %d Err: 0x%x Flags: 0x%x Flgs2: 0x%x Mid: %d Pid: %d",
+		  smb->Command, smb->Status.CifsError,
+		  smb->Flags, smb->Flags2, smb->Mid, smb->Pid));
+	cERROR(1,("smb buf %p len %d", smb, smbCalcSize_LE(smb)));
+}
+
+
+void cifs_dump_mids(struct TCP_Server_Info * server)
+{
+	struct list_head *tmp;
+	struct mid_q_entry * mid_entry;
+
+	if(server == NULL)
+		return;
+
+	cERROR(1,("Dump pending requests:"));
+	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) {
+			cERROR(1,("State: %d Cmd: %d Pid: %d Tsk: %p Mid %d",
+				mid_entry->midState,
+				(int)mid_entry->command,
+				mid_entry->pid,
+				mid_entry->tsk,
+				mid_entry->mid));
+#ifdef CONFIG_CIFS_STATS2
+			cERROR(1,("IsLarge: %d buf: %p time rcv: %ld now: %ld",
+				mid_entry->largeBuf,
+				mid_entry->resp_buf,
+				mid_entry->when_received,
+				jiffies));
+#endif /* STATS2 */
+			cERROR(1,("IsMult: %d IsEnd: %d", mid_entry->multiRsp,
+				  mid_entry->multiEnd));
+			if(mid_entry->resp_buf) {
+				cifs_dump_detail(mid_entry->resp_buf);
+				cifs_dump_mem("existing buf: ",
+					mid_entry->resp_buf,
+					62 /* fixme */);
+			}
+			
+		}
+	}
+	spin_unlock(&GlobalMid_Lock);
+}
+#endif /* CONFIG_CIFS_DEBUG2 */
+
 #ifdef CONFIG_PROC_FS
 static int
 cifs_debug_data_read(char *buf, char **beginBuffer, off_t offset,
@@ -73,7 +124,6 @@
 
 	*beginBuffer = buf + offset;
 
-	
 	length =
 	    sprintf(buf,
 		    "Display Internal CIFS Data Structures for Debugging\n"
@@ -81,6 +131,8 @@
 	buf += length;
 	length = sprintf(buf,"CIFS Version %s\n",CIFS_VERSION);
 	buf += length;
+	length = sprintf(buf,"Active VFS Requests: %d\n", GlobalTotalActiveXid);
+	buf += length;
 	length = sprintf(buf, "Servers:");
 	buf += length;
 
@@ -97,7 +149,7 @@
 		} else {
 			length =
 			    sprintf(buf,
-				    "\n%d) Name: %s  Domain: %s Mounts: %d ServerOS: %s  \n\tServerNOS: %s\tCapabilities: 0x%x\n\tSMB session status: %d\t",
+				    "\n%d) Name: %s  Domain: %s Mounts: %d OS: %s  \n\tNOS: %s\tCapability: 0x%x\n\tSMB session status: %d\t",
 				i, ses->serverName, ses->serverDomain,
 				atomic_read(&ses->inUse),
 				ses->serverOS, ses->serverNOS,
@@ -105,12 +157,18 @@
 			buf += length;
 		}
 		if(ses->server) {
-			buf += sprintf(buf, "TCP status: %d\n\tLocal Users To Server: %d SecMode: 0x%x Req Active: %d",
+			buf += sprintf(buf, "TCP status: %d\n\tLocal Users To Server: %d SecMode: 0x%x Req On Wire: %d",
 				ses->server->tcpStatus,
 				atomic_read(&ses->server->socketUseCount),
 				ses->server->secMode,
 				atomic_read(&ses->server->inFlight));
 			
+#ifdef CONFIG_CIFS_STATS2
+			buf += sprintf(buf, " In Send: %d In MaxReq Wait: %d",
+				atomic_read(&ses->server->inSend), 
+				atomic_read(&ses->server->num_waiters));
+#endif
+
 			length = sprintf(buf, "\nMIDs:\n");
 			buf += length;
 
@@ -149,7 +207,7 @@
 		dev_type = le32_to_cpu(tcon->fsDevInfo.DeviceType);
 		length =
 		    sprintf(buf,
-			    "\n%d) %s Uses: %d Type: %s Characteristics: 0x%x Attributes: 0x%x\nPathComponentMax: %d Status: %d",
+			    "\n%d) %s Uses: %d Type: %s DevInfo: 0x%x Attributes: 0x%x\nPathComponentMax: %d Status: %d",
 			    i, tcon->treeName,
 			    atomic_read(&tcon->useCount),
 			    tcon->nativeFileSystem,
@@ -195,6 +253,53 @@
 }
 
 #ifdef CONFIG_CIFS_STATS
+
+static int
+cifs_stats_write(struct file *file, const char __user *buffer,
+               unsigned long count, void *data)
+{
+        char c;
+        int rc;
+	struct list_head *tmp;
+	struct cifsTconInfo *tcon;
+
+        rc = get_user(c, buffer);
+        if (rc)
+                return rc;
+
+        if (c == '1' || c == 'y' || c == 'Y' || c == '0') {
+		read_lock(&GlobalSMBSeslock);
+#ifdef CONFIG_CIFS_STATS2
+		atomic_set(&totBufAllocCount, 0);
+		atomic_set(&totSmBufAllocCount, 0);
+#endif /* CONFIG_CIFS_STATS2 */
+		list_for_each(tmp, &GlobalTreeConnectionList) {
+			tcon = list_entry(tmp, struct cifsTconInfo,
+					cifsConnectionList);
+			atomic_set(&tcon->num_smbs_sent, 0);
+			atomic_set(&tcon->num_writes, 0);
+			atomic_set(&tcon->num_reads, 0);
+			atomic_set(&tcon->num_oplock_brks, 0);
+			atomic_set(&tcon->num_opens, 0);
+			atomic_set(&tcon->num_closes, 0);
+			atomic_set(&tcon->num_deletes, 0);
+			atomic_set(&tcon->num_mkdirs, 0);
+			atomic_set(&tcon->num_rmdirs, 0);
+			atomic_set(&tcon->num_renames, 0);
+			atomic_set(&tcon->num_t2renames, 0);
+			atomic_set(&tcon->num_ffirst, 0);
+			atomic_set(&tcon->num_fnext, 0);
+			atomic_set(&tcon->num_fclose, 0);
+			atomic_set(&tcon->num_hardlinks, 0);
+			atomic_set(&tcon->num_symlinks, 0);
+			atomic_set(&tcon->num_locks, 0);
+		}
+		read_unlock(&GlobalSMBSeslock);
+	}
+
+        return count;
+}
+
 static int
 cifs_stats_read(char *buf, char **beginBuffer, off_t offset,
 		  int count, int *eof, void *data)
@@ -225,6 +330,14 @@
 			smBufAllocCount.counter,cifs_min_small);
 	length += item_length;
 	buf += item_length;
+#ifdef CONFIG_CIFS_STATS2
+        item_length = sprintf(buf, "Total Large %d Small %d Allocations\n",
+				atomic_read(&totBufAllocCount),
+		                atomic_read(&totSmBufAllocCount));
+	length += item_length;
+	buf += item_length;
+#endif /* CONFIG_CIFS_STATS2 */
+
 	item_length = 
 		sprintf(buf,"Operations (MIDs): %d\n",
 			midCount.counter);
@@ -254,35 +367,51 @@
 			buf += sprintf(buf, "\tDISCONNECTED ");
 			length += 14;
 		}
-		item_length = sprintf(buf,"\nSMBs: %d Oplock Breaks: %d",
+		item_length = sprintf(buf, "\nSMBs: %d Oplock Breaks: %d",
 			atomic_read(&tcon->num_smbs_sent),
 			atomic_read(&tcon->num_oplock_brks));
 		buf += item_length;
 		length += item_length;
-		item_length = sprintf(buf,"\nReads: %d Bytes %lld",
+		item_length = sprintf(buf, "\nReads:  %d Bytes: %lld",
 			atomic_read(&tcon->num_reads),
 			(long long)(tcon->bytes_read));
 		buf += item_length;
 		length += item_length;
-		item_length = sprintf(buf,"\nWrites: %d Bytes: %lld",
+		item_length = sprintf(buf, "\nWrites: %d Bytes: %lld",
 			atomic_read(&tcon->num_writes),
 			(long long)(tcon->bytes_written));
 		buf += item_length;
 		length += item_length;
 		item_length = sprintf(buf,
-			"\nOpens: %d Deletes: %d\nMkdirs: %d Rmdirs: %d",
+			"\nLocks: %d HardLinks: %d Symlinks: %d",
+                        atomic_read(&tcon->num_locks),
+			atomic_read(&tcon->num_hardlinks),
+			atomic_read(&tcon->num_symlinks));
+                buf += item_length;
+                length += item_length;
+
+		item_length = sprintf(buf, "\nOpens: %d Closes: %d Deletes: %d",
 			atomic_read(&tcon->num_opens),
-			atomic_read(&tcon->num_deletes),
+			atomic_read(&tcon->num_closes),
+			atomic_read(&tcon->num_deletes));
+		buf += item_length;
+		length += item_length;
+		item_length = sprintf(buf, "\nMkdirs: %d Rmdirs: %d",
 			atomic_read(&tcon->num_mkdirs),
 			atomic_read(&tcon->num_rmdirs));
 		buf += item_length;
 		length += item_length;
-		item_length = sprintf(buf,
-			"\nRenames: %d T2 Renames %d",
+		item_length = sprintf(buf, "\nRenames: %d T2 Renames %d",
 			atomic_read(&tcon->num_renames),
 			atomic_read(&tcon->num_t2renames));
 		buf += item_length;
 		length += item_length;
+		item_length = sprintf(buf, "\nFindFirst: %d FNext %d FClose %d",
+			atomic_read(&tcon->num_ffirst),
+			atomic_read(&tcon->num_fnext),
+			atomic_read(&tcon->num_fclose));
+		buf += item_length;
+		length += item_length;
 	}
 	read_unlock(&GlobalSMBSeslock);
 
@@ -316,14 +445,14 @@
 static write_proc_t traceSMB_write;
 static read_proc_t multiuser_mount_read;
 static write_proc_t multiuser_mount_write;
-static read_proc_t extended_security_read;
-static write_proc_t extended_security_write;
-static read_proc_t ntlmv2_enabled_read;
+static read_proc_t security_flags_read;
+static write_proc_t security_flags_write;
+/* static read_proc_t ntlmv2_enabled_read;
 static write_proc_t ntlmv2_enabled_write;
 static read_proc_t packet_signing_enabled_read;
-static write_proc_t packet_signing_enabled_write;
-static read_proc_t quotaEnabled_read;
-static write_proc_t quotaEnabled_write;
+static write_proc_t packet_signing_enabled_write;*/
+static read_proc_t experimEnabled_read;
+static write_proc_t experimEnabled_write;
 static read_proc_t linuxExtensionsEnabled_read;
 static write_proc_t linuxExtensionsEnabled_write;
 
@@ -341,8 +470,10 @@
 				cifs_debug_data_read, NULL);
 
 #ifdef CONFIG_CIFS_STATS
-	create_proc_read_entry("Stats", 0, proc_fs_cifs,
+	pde = create_proc_read_entry("Stats", 0, proc_fs_cifs,
 				cifs_stats_read, NULL);
+	if (pde)
+		pde->write_proc = cifs_stats_write;
 #endif
 	pde = create_proc_read_entry("cifsFYI", 0, proc_fs_cifs,
 				cifsFYI_read, NULL);
@@ -360,10 +491,10 @@
 	if (pde)
 		pde->write_proc = oplockEnabled_write;
 
-	pde = create_proc_read_entry("ReenableOldCifsReaddirCode", 0, proc_fs_cifs,
-				quotaEnabled_read, NULL);
+	pde = create_proc_read_entry("Experimental", 0, proc_fs_cifs,
+				experimEnabled_read, NULL);
 	if (pde)
-		pde->write_proc = quotaEnabled_write;
+		pde->write_proc = experimEnabled_write;
 
 	pde = create_proc_read_entry("LinuxExtensionsEnabled", 0, proc_fs_cifs,
 				linuxExtensionsEnabled_read, NULL);
@@ -377,10 +508,10 @@
 		pde->write_proc = multiuser_mount_write;
 
 	pde =
-	    create_proc_read_entry("ExtendedSecurity", 0, proc_fs_cifs,
-				extended_security_read, NULL);
+	    create_proc_read_entry("SecurityFlags", 0, proc_fs_cifs,
+				security_flags_read, NULL);
 	if (pde)
-		pde->write_proc = extended_security_write;
+		pde->write_proc = security_flags_write;
 
 	pde =
 	create_proc_read_entry("LookupCacheEnabled", 0, proc_fs_cifs,
@@ -388,7 +519,7 @@
 	if (pde)
 		pde->write_proc = lookupFlag_write;
 
-	pde =
+/*	pde =
 	    create_proc_read_entry("NTLMV2Enabled", 0, proc_fs_cifs,
 				ntlmv2_enabled_read, NULL);
 	if (pde)
@@ -398,7 +529,7 @@
 	    create_proc_read_entry("PacketSigningEnabled", 0, proc_fs_cifs,
 				packet_signing_enabled_read, NULL);
 	if (pde)
-		pde->write_proc = packet_signing_enabled_write;
+		pde->write_proc = packet_signing_enabled_write;*/
 }
 
 void
@@ -415,11 +546,11 @@
 #endif
 	remove_proc_entry("MultiuserMount", proc_fs_cifs);
 	remove_proc_entry("OplockEnabled", proc_fs_cifs);
-	remove_proc_entry("NTLMV2Enabled",proc_fs_cifs);
-	remove_proc_entry("ExtendedSecurity",proc_fs_cifs);
-	remove_proc_entry("PacketSigningEnabled",proc_fs_cifs);
+/*	remove_proc_entry("NTLMV2Enabled",proc_fs_cifs); */
+	remove_proc_entry("SecurityFlags",proc_fs_cifs);
+/*	remove_proc_entry("PacketSigningEnabled",proc_fs_cifs); */
 	remove_proc_entry("LinuxExtensionsEnabled",proc_fs_cifs);
-	remove_proc_entry("ReenableOldCifsReaddirCode",proc_fs_cifs);
+	remove_proc_entry("Experimental",proc_fs_cifs);
 	remove_proc_entry("LookupCacheEnabled",proc_fs_cifs);
 	remove_proc_entry("cifs", proc_root_fs);
 }
@@ -459,6 +590,8 @@
 		cifsFYI = 0;
 	else if (c == '1' || c == 'y' || c == 'Y')
 		cifsFYI = 1;
+	else if((c > '1') && (c <= '9'))
+		cifsFYI = (int) (c - '0'); /* see cifs_debug.h for meanings */
 
 	return count;
 }
@@ -503,14 +636,13 @@
 }
 
 static int
-quotaEnabled_read(char *page, char **start, off_t off,
+experimEnabled_read(char *page, char **start, off_t off,
                    int count, int *eof, void *data)
 {
         int len;
 
         len = sprintf(page, "%d\n", experimEnabled);
-/* could also check if quotas are enabled in kernel
-	as a whole first */
+
         len -= off;
         *start = page + off;
 
@@ -525,7 +657,7 @@
         return len;
 }
 static int
-quotaEnabled_write(struct file *file, const char __user *buffer,
+experimEnabled_write(struct file *file, const char __user *buffer,
                     unsigned long count, void *data)
 {
         char c;
@@ -538,6 +670,8 @@
                 experimEnabled = 0;
         else if (c == '1' || c == 'y' || c == 'Y')
                 experimEnabled = 1;
+	else if (c == '2')
+		experimEnabled = 2;
 
         return count;
 }
@@ -549,8 +683,6 @@
         int len;
 
         len = sprintf(page, "%d\n", linuxExtEnabled);
-/* could also check if quotas are enabled in kernel
-	as a whole first */
         len -= off;
         *start = page + off;
 
@@ -700,12 +832,12 @@
 }
 
 static int
-extended_security_read(char *page, char **start, off_t off,
+security_flags_read(char *page, char **start, off_t off,
 		       int count, int *eof, void *data)
 {
 	int len;
 
-	len = sprintf(page, "%d\n", extended_security);
+	len = sprintf(page, "0x%x\n", extended_security);
 
 	len -= off;
 	*start = page + off;
@@ -721,24 +853,52 @@
 	return len;
 }
 static int
-extended_security_write(struct file *file, const char __user *buffer,
+security_flags_write(struct file *file, const char __user *buffer,
 			unsigned long count, void *data)
 {
+	unsigned int flags;
+	char flags_string[12];
 	char c;
-	int rc;
 
-	rc = get_user(c, buffer);
-	if (rc)
-		return rc;
+	if((count < 1) || (count > 11))
+		return -EINVAL;
+
+	memset(flags_string, 0, 12);
+
+	if(copy_from_user(flags_string, buffer, count))
+		return -EFAULT;
+
+	if(count < 3) {
+		/* single char or single char followed by null */
+		c = flags_string[0];
 	if (c == '0' || c == 'n' || c == 'N')
-		extended_security = 0;
+			extended_security = CIFSSEC_DEF; /* default */
 	else if (c == '1' || c == 'y' || c == 'Y')
-		extended_security = 1;
+			extended_security = CIFSSEC_MAX;
+		return count;
+	}
+	/* else we have a number */
+
+	flags = simple_strtoul(flags_string, NULL, 0);
+
+	cFYI(1,("sec flags 0x%x", flags));
+
+	if(flags <= 0)  {
+		cERROR(1,("invalid security flags %s",flags_string));
+		return -EINVAL;
+	}
 
+	if(flags & ~CIFSSEC_MASK) {
+		cERROR(1,("attempt to set unsupported security flags 0x%x",
+			flags & ~CIFSSEC_MASK));
+		return -EINVAL;
+	}
+	/* flags look ok - update the global security flags for cifs module */
+	extended_security = flags;
 	return count;
 }
 
-static int
+/* static int
 ntlmv2_enabled_read(char *page, char **start, off_t off,
 		       int count, int *eof, void *data)
 {
@@ -773,6 +933,8 @@
 		ntlmv2_support = 0;
 	else if (c == '1' || c == 'y' || c == 'Y')
 		ntlmv2_support = 1;
+	else if (c == '2')
+		ntlmv2_support = 2;
 
 	return count;
 }
@@ -816,7 +978,7 @@
 		sign_CIFS_PDUs = 2;
 
 	return count;
-}
+} */
 
 
 #endif
--- linux-2.6.13/fs/cifs/cifs_debug.h
+++ linux-2.6.13/fs/cifs/cifs_debug.h
@@ -24,8 +24,15 @@
 #define _H_CIFS_DEBUG
 
 void cifs_dump_mem(char *label, void *data, int length);
+#ifdef CONFIG_CIFS_DEBUG2
+void cifs_dump_detail(struct smb_hdr *);
+void cifs_dump_mids(struct TCP_Server_Info *);
+#endif
 extern int traceSMB;		/* flag which enables the function below */
 void dump_smb(struct smb_hdr *, int);
+#define CIFS_INFO	0x01
+#define CIFS_RC  	0x02
+#define CIFS_TIMER	0x04
 
 /*
  *	debug ON
@@ -36,7 +43,7 @@
 
 /* information message: e.g., configuration, major event */
 extern int cifsFYI;
-#define cifsfyi(format,arg...) if (cifsFYI) printk(KERN_DEBUG " " __FILE__ ": " format "\n" "" , ## arg)
+#define cifsfyi(format,arg...) if (cifsFYI & CIFS_INFO) printk(KERN_DEBUG " " __FILE__ ": " format "\n" "" , ## arg)
 
 #define cFYI(button,prspec) if (button) cifsfyi prspec
 
--- linux-2.6.13/fs/cifs/cifsencrypt.c
+++ linux-2.6.13/fs/cifs/cifsencrypt.c
@@ -1,7 +1,7 @@
 /*
  *   fs/cifs/cifsencrypt.c
  *
- *   Copyright (C) International Business Machines  Corp., 2003
+ *   Copyright (C) International Business Machines  Corp., 2005,2006
  *   Author(s): Steve French (sfrench@us.ibm.com)
  *
  *   This library is free software; you can redistribute it and/or modify
@@ -26,6 +26,8 @@
 #include "md5.h"
 #include "cifs_unicode.h"
 #include "cifsproto.h"
+#include <linux/ctype.h>
+#include <linux/random.h>
 
 /* Calculate and return the CIFS signature based on the mac key and the smb pdu */
 /* the 16 byte signature must be allocated by the caller  */
@@ -35,8 +37,11 @@
 
 extern void mdfour(unsigned char *out, unsigned char *in, int n);
 extern void E_md4hash(const unsigned char *passwd, unsigned char *p16);
+extern void SMBencrypt(unsigned char *passwd, unsigned char *c8,
+                       unsigned char *p24);
 	
-static int cifs_calculate_signature(const struct smb_hdr * cifs_pdu, const char * key, char * signature)
+static int cifs_calculate_signature(const struct smb_hdr * cifs_pdu, 
+				    const char * key, char * signature)
 {
 	struct	MD5Context context;
 
@@ -44,7 +49,7 @@
 		return -EINVAL;
 
 	MD5Init(&context);
-	MD5Update(&context,key,CIFS_SESSION_KEY_SIZE+16);
+	MD5Update(&context,key,CIFS_SESS_KEY_SIZE+16);
 	MD5Update(&context,cifs_pdu->Protocol,cifs_pdu->smb_buf_length);
 	MD5Final(signature,&context);
 	return 0;
@@ -56,9 +61,6 @@
 	int rc = 0;
 	char smb_signature[20];
 
-	/* BB remember to initialize sequence number elsewhere and initialize mac_signing key elsewhere BB */
-	/* BB remember to add code to save expected sequence number in midQ entry BB */
-
 	if((cifs_pdu == NULL) || (server == NULL))
 		return -EINVAL;
 
@@ -82,6 +84,72 @@
 	return rc;
 }
 
+static int cifs_calc_signature2(const struct kvec * iov, int n_vec,
+				const char * key, char * signature)
+{
+	struct  MD5Context context;
+	int i;
+
+	if((iov == NULL) || (signature == NULL))
+		return -EINVAL;
+
+	MD5Init(&context);
+	MD5Update(&context,key,CIFS_SESS_KEY_SIZE+16);
+	for(i=0;i<n_vec;i++) {
+		if(iov[i].iov_base == NULL) {
+			cERROR(1,("null iovec entry"));
+			return -EIO;
+		} else if(iov[i].iov_len == 0)
+			break; /* bail out if we are sent nothing to sign */
+		/* The first entry includes a length field (which does not get 
+		   signed that occupies the first 4 bytes before the header */
+		if(i==0) {
+			if (iov[0].iov_len <= 8 ) /* cmd field at offset 9 */
+				break; /* nothing to sign or corrupt header */
+			MD5Update(&context,iov[0].iov_base+4, iov[0].iov_len-4);
+		} else
+			MD5Update(&context,iov[i].iov_base, iov[i].iov_len);
+	}
+
+	MD5Final(signature,&context);
+
+	return 0;
+}
+
+
+int cifs_sign_smb2(struct kvec * iov, int n_vec, struct TCP_Server_Info *server,
+		   __u32 * pexpected_response_sequence_number)
+{
+	int rc = 0;
+	char smb_signature[20];
+	struct smb_hdr * cifs_pdu = iov[0].iov_base;
+
+	if((cifs_pdu == NULL) || (server == NULL))
+		return -EINVAL;
+
+	if((cifs_pdu->Flags2 & SMBFLG2_SECURITY_SIGNATURE) == 0)
+		return rc;
+
+        spin_lock(&GlobalMid_Lock);
+        cifs_pdu->Signature.Sequence.SequenceNumber = 
+				cpu_to_le32(server->sequence_number);
+        cifs_pdu->Signature.Sequence.Reserved = 0;
+
+        *pexpected_response_sequence_number = server->sequence_number++;
+        server->sequence_number++;
+        spin_unlock(&GlobalMid_Lock);
+
+        rc = cifs_calc_signature2(iov, n_vec, server->mac_signing_key,
+				      smb_signature);
+        if(rc)
+                memset(cifs_pdu->Signature.SecuritySignature, 0, 8);
+        else
+                memcpy(cifs_pdu->Signature.SecuritySignature, smb_signature, 8);
+
+        return rc;
+
+}
+
 int cifs_verify_signature(struct smb_hdr * cifs_pdu, const char * mac_key,
 	__u32 expected_sequence_number)
 {
@@ -140,16 +208,17 @@
 
 	E_md4hash(password, temp_key);
 	mdfour(key,temp_key,16);
-	memcpy(key+16,rn, CIFS_SESSION_KEY_SIZE);
+	memcpy(key+16,rn, CIFS_SESS_KEY_SIZE);
 	return 0;
 }
 
-int CalcNTLMv2_partial_mac_key(struct cifsSesInfo * ses, struct nls_table * nls_info)
+int CalcNTLMv2_partial_mac_key(struct cifsSesInfo * ses, 
+				const struct nls_table * nls_info)
 {
 	char temp_hash[16];
 	struct HMACMD5Context ctx;
 	char * ucase_buf;
-	wchar_t * unicode_buf;
+	__le16 * unicode_buf;
 	unsigned int i,user_name_len,dom_name_len;
 
 	if(ses == NULL)
@@ -161,6 +230,8 @@
 	user_name_len = strlen(ses->userName);
 	if(user_name_len > MAX_USERNAME_SIZE)
 		return -EINVAL;
+	if(ses->domainName == NULL)
+		return -EINVAL; /* BB should we use CIFS_LINUX_DOM */
 	dom_name_len = strlen(ses->domainName);
 	if(dom_name_len > MAX_USERNAME_SIZE)
 		return -EINVAL;
@@ -195,15 +266,131 @@
 	kfree(unicode_buf);
 	return 0;
 }
-void CalcNTLMv2_response(const struct cifsSesInfo * ses,char * v2_session_response)
+
+#ifdef CONFIG_CIFS_WEAK_PW_HASH
+void calc_lanman_hash(struct cifsSesInfo * ses, char * lnm_session_key)
+{
+	int i;
+	char password_with_pad[CIFS_ENCPWD_SIZE];
+
+	if(ses->server == NULL)
+		return;
+
+	memset(password_with_pad, 0, CIFS_ENCPWD_SIZE);
+	strncpy(password_with_pad, ses->password, CIFS_ENCPWD_SIZE);
+
+	if((ses->server->secMode & SECMODE_PW_ENCRYPT) == 0)
+		if(extended_security & CIFSSEC_MAY_PLNTXT) {
+			memcpy(lnm_session_key, password_with_pad, CIFS_ENCPWD_SIZE); 
+			return;
+		}
+
+	/* calculate old style session key */
+	/* calling toupper is less broken than repeatedly
+	calling nls_toupper would be since that will never
+	work for UTF8, but neither handles multibyte code pages
+	but the only alternative would be converting to UCS-16 (Unicode)
+	(using a routine something like UniStrupr) then
+	uppercasing and then converting back from Unicode - which
+	would only worth doing it if we knew it were utf8. Basically
+	utf8 and other multibyte codepages each need their own strupper
+	function since a byte at a time will ont work. */
+
+	for(i = 0; i < CIFS_ENCPWD_SIZE; i++) {
+		password_with_pad[i] = toupper(password_with_pad[i]);
+	}
+
+	SMBencrypt(password_with_pad, ses->server->cryptKey, lnm_session_key);
+	/* clear password before we return/free memory */
+	memset(password_with_pad, 0, CIFS_ENCPWD_SIZE);
+}
+#endif /* CIFS_WEAK_PW_HASH */
+
+static int calc_ntlmv2_hash(struct cifsSesInfo *ses, 
+			    const struct nls_table * nls_cp)
+{
+	int rc = 0;
+	int len;
+	char nt_hash[16];
+	struct HMACMD5Context * pctxt;
+	wchar_t * user;
+	wchar_t * domain;
+
+	pctxt = kmalloc(sizeof(struct HMACMD5Context), GFP_KERNEL);
+
+	if(pctxt == NULL)
+		return -ENOMEM;
+
+	/* calculate md4 hash of password */
+	E_md4hash(ses->password, nt_hash);
+
+	/* convert Domainname to unicode and uppercase */
+	hmac_md5_init_limK_to_64(nt_hash, 16, pctxt);
+
+	/* convert ses->userName to unicode and uppercase */
+	len = strlen(ses->userName);
+	user = kmalloc(2 + (len * 2), GFP_KERNEL);
+	if(user == NULL)
+		goto calc_exit_2;
+	len = cifs_strtoUCS(user, ses->userName, len, nls_cp);
+	UniStrupr(user);
+	hmac_md5_update((char *)user, 2*len, pctxt);
+
+	/* convert ses->domainName to unicode and uppercase */
+	if(ses->domainName) {
+		len = strlen(ses->domainName);
+
+        	domain = kmalloc(2 + (len * 2), GFP_KERNEL);
+		if(domain == NULL)
+			goto calc_exit_1;
+		len = cifs_strtoUCS(domain, ses->domainName, len, nls_cp);
+		UniStrupr(domain);
+
+		hmac_md5_update((char *)domain, 2*len, pctxt);
+	
+		kfree(domain);
+	}
+calc_exit_1:
+	kfree(user);
+calc_exit_2:
+	/* BB FIXME what about bytes 24 through 40 of the signing key? 
+	   compare with the NTLM example */
+	hmac_md5_final(ses->server->mac_signing_key, pctxt);
+
+	return rc;
+}
+
+void setup_ntlmv2_rsp(struct cifsSesInfo * ses, char * resp_buf, 
+		      const struct nls_table * nls_cp)
+{
+	int rc;
+	struct ntlmv2_resp * buf = (struct ntlmv2_resp *)resp_buf;
+
+	buf->blob_signature = cpu_to_le32(0x00000101);
+	buf->reserved = 0;
+	buf->time = cpu_to_le64(cifs_UnixTimeToNT(CURRENT_TIME));
+	get_random_bytes(&buf->client_chal, sizeof(buf->client_chal));
+	buf->reserved2 = 0;
+	buf->names[0].type = 0;
+	buf->names[0].length = 0;
+
+	/* calculate buf->ntlmv2_hash */
+	rc = calc_ntlmv2_hash(ses, nls_cp);
+	if(rc)
+		cERROR(1,("could not get v2 hash rc %d",rc));
+	CalcNTLMv2_response(ses, resp_buf);
+}
+
+void CalcNTLMv2_response(const struct cifsSesInfo * ses, char * v2_session_response)
 {
 	struct HMACMD5Context context;
+	/* rest of v2 struct already generated */
 	memcpy(v2_session_response + 8, ses->server->cryptKey,8);
-	/* gen_blob(v2_session_response + 16); */
 	hmac_md5_init_limK_to_64(ses->server->mac_signing_key, 16, &context);
 
-	hmac_md5_update(ses->server->cryptKey,8,&context);
-/*	hmac_md5_update(v2_session_response+16)client thing,8,&context); */ /* BB fix */
+	hmac_md5_update(v2_session_response+8, 
+			sizeof(struct ntlmv2_resp) - 8, &context);
 
 	hmac_md5_final(v2_session_response,&context);
+/*	cifs_dump_mem("v2_sess_rsp: ", v2_session_response, 32); */
 }
--- linux-2.6.13/fs/cifs/cifsfs.c
+++ linux-2.6.13/fs/cifs/cifsfs.c
@@ -32,6 +32,7 @@
 #include <linux/seq_file.h>
 #include <linux/vfs.h>
 #include <linux/mempool.h>
+#include <linux/delay.h>
 #include "cifsfs.h"
 #include "cifspdu.h"
 #define DECLARE_GLOBALS_HERE
@@ -40,6 +41,9 @@
 #include "cifs_debug.h"
 #include "cifs_fs_sb.h"
 #include <linux/mm.h>
+#if LINUX_VERSION_CODE < KERNEL_VERSION(2,6,9)
+#include <linux/moduleparam.h>
+#endif
 #define CIFS_MAGIC_NUMBER 0xFF534D42	/* the first four bytes of SMB PDUs */
 
 #ifdef CONFIG_CIFS_QUOTA
@@ -54,11 +58,13 @@
 unsigned int linuxExtEnabled = 1;
 unsigned int lookupCacheEnabled = 1;
 unsigned int multiuser_mount = 0;
-unsigned int extended_security = 0;
-unsigned int ntlmv2_support = 0;
+unsigned int extended_security = CIFSSEC_DEF;
+/* unsigned int ntlmv2_support = 0; */
 unsigned int sign_CIFS_PDUs = 1;
 extern struct task_struct * oplockThread; /* remove sparse warning */
 struct task_struct * oplockThread = NULL;
+extern struct task_struct * dnotifyThread; /* remove sparse warning */
+struct task_struct * dnotifyThread = NULL;
 unsigned int CIFSMaxBufSize = CIFS_MAX_MSGSIZE;
 module_param(CIFSMaxBufSize, int, 0);
 MODULE_PARM_DESC(CIFSMaxBufSize,"Network buffer size (not including header). Default: 16384 Range: 8192 to 130048");
@@ -73,6 +79,7 @@
 MODULE_PARM_DESC(cifs_max_pending,"Simultaneous requests to server. Default: 50 Range: 2 to 256");
 
 static DECLARE_COMPLETION(cifs_oplock_exited);
+static DECLARE_COMPLETION(cifs_dnotify_exited);
 
 extern mempool_t *cifs_sm_req_poolp;
 extern mempool_t *cifs_req_poolp;
@@ -89,13 +96,10 @@
 	int rc = 0;
 
 	sb->s_flags |= MS_NODIRATIME; /* and probably even noatime */
-	sb->s_fs_info = kmalloc(sizeof(struct cifs_sb_info),GFP_KERNEL);
+	sb->s_fs_info = kzalloc(sizeof(struct cifs_sb_info),GFP_KERNEL);
 	cifs_sb = CIFS_SB(sb);
 	if(cifs_sb == NULL)
 		return -ENOMEM;
-	else
-		memset(cifs_sb,0,sizeof(struct cifs_sb_info));
-	
 
 	rc = cifs_mount(sb, cifs_sb, data, devname);
 
@@ -166,6 +170,20 @@
 	return;
 }
 
+#if LINUX_VERSION_CODE < KERNEL_VERSION(2, 6, 16)
+#if LINUX_VERSION_CODE != KERNEL_VERSION(2, 6, 9)
+void * kzalloc(size_t size, unsigned flgs)
+{
+	void * buf;
+	buf = kmalloc(size, flgs);
+	if(buf != NULL)
+		memset(buf, 0, size);
+	return buf;
+}
+#endif
+#endif
+
+
 static int
 cifs_statfs(struct super_block *sb, struct kstatfs *buf)
 {
@@ -202,6 +220,10 @@
 #endif /* CIFS_EXPERIMENTAL */
 	rc = CIFSSMBQFSInfo(xid, pTcon, buf);
 
+	/* Old Windows servers do not support level 103, retry with level 
+	   one if old server failed the previous call */ 
+	if(rc)
+		rc = SMBOldQFSInfo(xid, pTcon, buf);
 	/*     
 	   int f_type;
 	   __fsid_t f_fsid;
@@ -224,7 +246,11 @@
 		on the client (above and beyond ACL on servers) for  
 		servers which do not support setting and viewing mode bits,
 		so allowing client to check permissions is useful */ 
+#if LINUX_VERSION_CODE < KERNEL_VERSION(2,6,10) 
+		return vfs_permission(inode, mask);
+#else
 		return generic_permission(inode, mask, NULL);
+#endif /* LINUX version */
 }
 
 static kmem_cache_t *cifs_inode_cachep;
@@ -253,7 +279,7 @@
 	cifs_inode->clientCanCacheAll = FALSE;
 	cifs_inode->vfs_inode.i_blksize = CIFS_MAX_MSGSIZE;
 	cifs_inode->vfs_inode.i_blkbits = 14;  /* 2**14 = CIFS_MAX_MSGSIZE */
-
+	cifs_inode->vfs_inode.i_flags = S_NOATIME | S_NOCMTIME;
 	INIT_LIST_HEAD(&cifs_inode->openFileList);
 	return &cifs_inode->vfs_inode;
 }
@@ -398,6 +424,40 @@
 };
 #endif
 
+static void cifs_umount_begin(struct super_block * sblock)
+{
+	struct cifs_sb_info *cifs_sb;
+	struct cifsTconInfo * tcon;
+
+	cifs_sb = CIFS_SB(sblock);
+	if(cifs_sb == NULL)
+		return;
+
+	tcon = cifs_sb->tcon;
+	if(tcon == NULL)
+		return;
+	down(&tcon->tconSem);
+	if (atomic_read(&tcon->useCount) == 1)
+		tcon->tidStatus = CifsExiting;
+	up(&tcon->tconSem);
+
+	/* cancel_brl_requests(tcon); */ /* BB mark all brl mids as exiting */
+	/* cancel_notify_requests(tcon); */
+	if(tcon->ses && tcon->ses->server)
+	{
+		cFYI(1,("wake up tasks now - umount begin not complete"));
+		wake_up_all(&tcon->ses->server->request_q);
+		wake_up_all(&tcon->ses->server->response_q);
+		msleep(1); /* yield */
+		/* we have to kick the requests once more */
+		wake_up_all(&tcon->ses->server->response_q);
+		msleep(1);
+	}
+/* BB FIXME - finish add checks for tidStatus BB */
+
+	return;
+}
+
 static int cifs_remount(struct super_block *sb, int *flags, char *data)
 {
 	*flags |= MS_NODIRATIME;
@@ -415,7 +475,7 @@
    unless later we add lazy close of inodes or unless the kernel forgets to call
    us with the same number of releases (closes) as opens */
 	.show_options = cifs_show_options,
-/*    .umount_begin   = cifs_umount_begin, *//* consider adding in the future */
+	.umount_begin   = cifs_umount_begin,
 	.remount_fs = cifs_remount,
 };
 
@@ -443,56 +503,40 @@
 	return sb;
 }
 
-static ssize_t
-cifs_read_wrapper(struct file * file, char __user *read_data, size_t read_size,
-          loff_t * poffset)
+static ssize_t cifs_file_writev(struct file *file, const struct iovec *iov,
+				unsigned long nr_segs, loff_t *ppos)
 {
-	if(file->f_dentry == NULL)
-		return -EIO;
-	else if(file->f_dentry->d_inode == NULL)
-		return -EIO;
-
-	cFYI(1,("In read_wrapper size %zd at %lld",read_size,*poffset));
+	struct inode *inode = file->f_dentry->d_inode;
+	ssize_t written;
 
-	if(CIFS_I(file->f_dentry->d_inode)->clientCanCacheRead) {
-		return generic_file_read(file,read_data,read_size,poffset);
-	} else {
-		/* BB do we need to lock inode from here until after invalidate? */
-/*		if(file->f_dentry->d_inode->i_mapping) {
-			filemap_fdatawrite(file->f_dentry->d_inode->i_mapping);
-			filemap_fdatawait(file->f_dentry->d_inode->i_mapping);
-		}*/
-/*		cifs_revalidate(file->f_dentry);*/ /* BB fixme */
-
-		/* BB we should make timer configurable - perhaps 
-		   by simply calling cifs_revalidate here */
-		/* invalidate_remote_inode(file->f_dentry->d_inode);*/
-		return generic_file_read(file,read_data,read_size,poffset);
-	}
+	written = generic_file_writev(file, iov, nr_segs, ppos);
+	if (!CIFS_I(inode)->clientCanCacheAll)
+		filemap_fdatawrite(inode->i_mapping);
+	return written;
 }
 
-static ssize_t
-cifs_write_wrapper(struct file * file, const char __user *write_data,
-           size_t write_size, loff_t * poffset) 
+static ssize_t cifs_file_aio_write(struct kiocb *iocb, const char __user *buf,
+				   size_t count, loff_t pos)
 {
+	struct inode *inode = iocb->ki_filp->f_dentry->d_inode;
 	ssize_t written;
 
-	if(file->f_dentry == NULL)
-		return -EIO;
-	else if(file->f_dentry->d_inode == NULL)
-		return -EIO;
-
-	cFYI(1,("In write_wrapper size %zd at %lld",write_size,*poffset));
-
-	written = generic_file_write(file,write_data,write_size,poffset);
-	if(!CIFS_I(file->f_dentry->d_inode)->clientCanCacheAll)  {
-		if(file->f_dentry->d_inode->i_mapping) {
-			filemap_fdatawrite(file->f_dentry->d_inode->i_mapping);
-		}
-	}
+	written = generic_file_aio_write(iocb, buf, count, pos);
+	if (!CIFS_I(inode)->clientCanCacheAll)
+		filemap_fdatawrite(inode->i_mapping);
 	return written;
 }
 
+static loff_t cifs_llseek(struct file *file, loff_t offset, int origin)
+{
+	/* origin == SEEK_END => we must revalidate the cached file length */
+	if (origin == 2) {
+		int retval = cifs_revalidate(file->f_dentry);
+		if (retval < 0)
+			return (loff_t)retval;
+	}
+	return remote_llseek(file, offset, origin);
+}
 
 static struct file_system_type cifs_fs_type = {
 	.owner = THIS_MODULE,
@@ -538,9 +582,13 @@
 };
 
 struct inode_operations cifs_symlink_inode_ops = {
+#if LINUX_VERSION_CODE < KERNEL_VERSION(2,6,9)
+	.readlink = cifs_readlink,
+#else
 	.readlink = generic_readlink, 
-	.follow_link = cifs_follow_link,
 	.put_link = cifs_put_link,
+#endif
+	.follow_link = cifs_follow_link,
 	.permission = cifs_permission,
 	/* BB add the following two eventually */
 	/* revalidate: cifs_revalidate,
@@ -554,8 +602,12 @@
 };
 
 struct file_operations cifs_file_ops = {
-	.read = cifs_read_wrapper,
-	.write = cifs_write_wrapper, 
+	.read = do_sync_read,
+	.write = do_sync_write,
+	.readv = generic_file_readv,
+	.writev = cifs_file_writev,
+	.aio_read = generic_file_aio_read,
+	.aio_write = cifs_file_aio_write,
 	.open = cifs_open,
 	.release = cifs_close,
 	.lock = cifs_lock,
@@ -563,15 +615,12 @@
 	.flush = cifs_flush,
 	.mmap  = cifs_file_mmap,
 	.sendfile = generic_file_sendfile,
+	.llseek = cifs_llseek,
 #ifdef CONFIG_CIFS_POSIX
 	.ioctl	= cifs_ioctl,
 #endif /* CONFIG_CIFS_POSIX */
 
 #ifdef CONFIG_CIFS_EXPERIMENTAL
-	.readv = generic_file_readv,
-	.writev = generic_file_writev,
-	.aio_read = generic_file_aio_read,
-	.aio_write = generic_file_aio_write,
 	.dir_notify = cifs_dir_notify,
 #endif /* CONFIG_CIFS_EXPERIMENTAL */
 };
@@ -590,12 +639,53 @@
 #ifdef CONFIG_CIFS_POSIX
 	.ioctl  = cifs_ioctl,
 #endif /* CONFIG_CIFS_POSIX */
+	.llseek = cifs_llseek,
+#ifdef CONFIG_CIFS_EXPERIMENTAL
+	.dir_notify = cifs_dir_notify,
+#endif /* CONFIG_CIFS_EXPERIMENTAL */
+};
+struct file_operations cifs_file_nobrl_ops = {
+	.read = do_sync_read,
+	.write = do_sync_write,
+	.readv = generic_file_readv,
+	.writev = cifs_file_writev,
+	.aio_read = generic_file_aio_read,
+	.aio_write = cifs_file_aio_write,
+	.open = cifs_open,
+	.release = cifs_close,
+	.fsync = cifs_fsync,
+	.flush = cifs_flush,
+	.mmap  = cifs_file_mmap,
+	.sendfile = generic_file_sendfile,
+	.llseek = cifs_llseek,
+#ifdef CONFIG_CIFS_POSIX
+	.ioctl	= cifs_ioctl,
+#endif /* CONFIG_CIFS_POSIX */
 
 #ifdef CONFIG_CIFS_EXPERIMENTAL
 	.dir_notify = cifs_dir_notify,
 #endif /* CONFIG_CIFS_EXPERIMENTAL */
 };
 
+struct file_operations cifs_file_direct_nobrl_ops = {
+	/* no mmap, no aio, no readv - 
+	   BB reevaluate whether they can be done with directio, no cache */
+	.read = cifs_user_read,
+	.write = cifs_user_write,
+	.open = cifs_open,
+	.release = cifs_close,
+	.fsync = cifs_fsync,
+	.flush = cifs_flush,
+	.sendfile = generic_file_sendfile, /* BB removeme BB */
+#ifdef CONFIG_CIFS_POSIX
+	.ioctl  = cifs_ioctl,
+#endif /* CONFIG_CIFS_POSIX */
+	.llseek = cifs_llseek,
+#ifdef CONFIG_CIFS_EXPERIMENTAL
+	.dir_notify = cifs_dir_notify,
+#endif /* CONFIG_CIFS_EXPERIMENTAL */
+};
+
 struct file_operations cifs_dir_ops = {
 	.readdir = cifs_readdir,
 	.release = cifs_closedir,
@@ -674,7 +764,7 @@
 		kmem_cache_destroy(cifs_req_cachep);
 		return -ENOMEM;
 	}
-	/* 256 (MAX_CIFS_HDR_SIZE bytes is enough for most SMB responses and
+	/* MAX_CIFS_SMALL_BUFFER_SIZE bytes is enough for most SMB responses and
 	almost all handle based requests (but not write response, nor is it
 	sufficient for path based requests).  A smaller size would have
 	been more efficient (compacting multiple slab items on one 4k page) 
@@ -683,7 +773,8 @@
 	efficient to alloc 1 per page off the slab compared to 17K (5page) 
 	alloc of large cifs buffers even when page debugging is on */
 	cifs_sm_req_cachep = kmem_cache_create("cifs_small_rq",
-			MAX_CIFS_HDR_SIZE, 0, SLAB_HWCACHE_ALIGN, NULL, NULL);
+			MAX_CIFS_SMALL_BUFFER_SIZE, 0, SLAB_HWCACHE_ALIGN, 
+			NULL, NULL);
 	if (cifs_sm_req_cachep == NULL) {
 		mempool_destroy(cifs_req_poolp);
 		kmem_cache_destroy(cifs_req_cachep);
@@ -781,9 +872,11 @@
 
 	oplockThread = current;
 	do {
-		set_current_state(TASK_INTERRUPTIBLE);
+#if LINUX_VERSION_CODE > KERNEL_VERSION(2, 6, 12)
+		if (try_to_freeze()) 
+			continue;
+#endif
 		
-		schedule_timeout(1*HZ);  
 		spin_lock(&GlobalMid_Lock);
 		if(list_empty(&GlobalOplock_Q)) {
 			spin_unlock(&GlobalMid_Lock);
@@ -801,9 +894,9 @@
 				DeleteOplockQEntry(oplock_item);
 				/* can not grab inode sem here since it would
 				deadlock when oplock received on delete 
-				since vfs_unlink holds the i_sem across
+				since vfs_unlink holds the i_mutex across
 				the call */
-				/* down(&inode->i_sem);*/
+				/* mutex_lock(&inode->i_mutex);*/
 				if (S_ISREG(inode->i_mode)) {
 					rc = filemap_fdatawrite(inode->i_mapping);
 					if(CIFS_I(inode)->clientCanCacheRead == 0) {
@@ -812,7 +905,7 @@
 					}
 				} else
 					rc = 0;
-				/* up(&inode->i_sem);*/
+				/* mutex_unlock(&inode->i_mutex);*/
 				if (rc)
 					CIFS_I(inode)->write_behind_rc = rc;
 				cFYI(1,("Oplock flush inode %p rc %d",inode,rc));
@@ -832,10 +925,44 @@
 				}
 			} else
 				spin_unlock(&GlobalMid_Lock);
+			set_current_state(TASK_INTERRUPTIBLE);
+			schedule_timeout(1);  /* yield in case q were corrupt */
 		}
 	} while(!signal_pending(current));
-	complete_and_exit (&cifs_oplock_exited, 0);
 	oplockThread = NULL;
+	complete_and_exit (&cifs_oplock_exited, 0);
+}
+
+static int cifs_dnotify_thread(void * dummyarg)
+{
+	struct list_head *tmp;
+	struct cifsSesInfo *ses;
+
+	daemonize("cifsdnotifyd");
+	allow_signal(SIGTERM);
+
+	dnotifyThread = current;
+	do {
+#if LINUX_VERSION_CODE > KERNEL_VERSION(2, 6, 12)
+		if (try_to_freeze())
+			continue;
+#endif
+		set_current_state(TASK_INTERRUPTIBLE);
+		schedule_timeout(15*HZ);
+		read_lock(&GlobalSMBSeslock);
+		/* check if any stuck requests that need
+		   to be woken up and wakeq so the
+		   thread can wake up and error out */
+		list_for_each(tmp, &GlobalSMBSessionList) {
+			ses = list_entry(tmp, struct cifsSesInfo, 
+				cifsSessionList);
+			if(ses && ses->server && 
+			     atomic_read(&ses->server->inFlight))
+				wake_up_all(&ses->server->response_q);
+		}
+		read_unlock(&GlobalSMBSeslock);
+	} while(!signal_pending(current));
+	complete_and_exit (&cifs_dnotify_exited, 0);
 }
 
 static int __init
@@ -849,6 +976,10 @@
 	INIT_LIST_HEAD(&GlobalSMBSessionList);
 	INIT_LIST_HEAD(&GlobalTreeConnectionList);
 	INIT_LIST_HEAD(&GlobalOplock_Q);
+#ifdef CONFIG_CIFS_EXPERIMENTAL
+	INIT_LIST_HEAD(&GlobalDnotifyReqList);
+	INIT_LIST_HEAD(&GlobalDnotifyRsp_Q);
+#endif	
 /*
  *  Initialize Global counters
  */
@@ -859,6 +990,12 @@
 	atomic_set(&tconInfoReconnectCount, 0);
 
 	atomic_set(&bufAllocCount, 0);
+	atomic_set(&smBufAllocCount, 0);
+#ifdef CONFIG_CIFS_STATS2
+	atomic_set(&totBufAllocCount, 0);
+	atomic_set(&totSmBufAllocCount, 0);
+#endif /* CONFIG_CIFS_STATS2 */
+
 	atomic_set(&midCount, 0);
 	GlobalCurrentXid = 0;
 	GlobalTotalActiveXid = 0;
@@ -884,11 +1021,17 @@
 				if (!rc) {                
 					rc = (int)kernel_thread(cifs_oplock_thread, NULL, 
 						CLONE_FS | CLONE_FILES | CLONE_VM);
+					if(rc > 0) {
+						rc = (int)kernel_thread(cifs_dnotify_thread, NULL,
+							CLONE_FS | CLONE_FILES | CLONE_VM);
 					if(rc > 0)
 						return 0;
 					else 
+							cERROR(1,("error %d create dnotify thread", rc));
+					} else {
 						cERROR(1,("error %d create oplock thread",rc));
 				}
+				}
 				cifs_destroy_request_bufs();
 			}
 			cifs_destroy_mids();
@@ -916,6 +1059,10 @@
 		send_sig(SIGTERM, oplockThread, 1);
 		wait_for_completion(&cifs_oplock_exited);
 	}
+	if(dnotifyThread) {
+		send_sig(SIGTERM, dnotifyThread, 1);
+		wait_for_completion(&cifs_dnotify_exited);
+	}
 }
 
 MODULE_AUTHOR("Steve French <sfrench@us.ibm.com>");
--- linux-2.6.13/fs/cifs/cifsfs.h
+++ linux-2.6.13/fs/cifs/cifsfs.h
@@ -31,8 +31,12 @@
 #ifndef TRUE
 #define TRUE 1
 #endif
-
+#include <linux/version.h>
+#if LINUX_VERSION_CODE < KERNEL_VERSION(2,6,11)
+#define current_fs_time(arg) CURRENT_TIME
+#endif
 extern struct address_space_operations cifs_addr_ops;
+extern struct address_space_operations cifs_addr_ops_smallbuf;
 
 /* Functions related to super block operations */
 extern struct super_operations cifs_super_ops;
@@ -42,8 +46,12 @@
 
 /* Functions related to inodes */
 extern struct inode_operations cifs_dir_inode_ops;
+#if LINUX_VERSION_CODE > KERNEL_VERSION(2, 5, 0)
 extern int cifs_create(struct inode *, struct dentry *, int, 
 		       struct nameidata *);
+#else
+extern int cifs_create(struct inode *, struct dentry *, int);
+#endif
 extern struct dentry * cifs_lookup(struct inode *, struct dentry *,
 				  struct nameidata *);
 extern int cifs_unlink(struct inode *, struct dentry *);
@@ -63,6 +71,8 @@
 /* Functions related to files and directories */
 extern struct file_operations cifs_file_ops;
 extern struct file_operations cifs_file_direct_ops; /* if directio mount */
+extern struct file_operations cifs_file_nobrl_ops;
+extern struct file_operations cifs_file_direct_nobrl_ops; /* if directio mount */
 extern int cifs_open(struct inode *inode, struct file *file);
 extern int cifs_close(struct inode *inode, struct file *file);
 extern int cifs_closedir(struct inode *inode, struct file *file);
@@ -81,10 +91,16 @@
 
 /* Functions related to dir entries */
 extern struct dentry_operations cifs_dentry_ops;
+extern struct dentry_operations cifs_ci_dentry_ops;
 
 /* Functions related to symlinks */
+#if LINUX_VERSION_CODE > KERNEL_VERSION(2,6,12)
 extern void *cifs_follow_link(struct dentry *direntry, struct nameidata *nd);
 extern void cifs_put_link(struct dentry *direntry, struct nameidata *nd, void *);
+#else
+extern int cifs_follow_link(struct dentry *direntry, struct nameidata *nd);
+extern void cifs_put_link(struct dentry *direntry, struct nameidata *nd);
+#endif
 extern int cifs_readlink(struct dentry *direntry, char __user *buffer, 
 			 int buflen);
 extern int cifs_symlink(struct inode *inode, struct dentry *direntry,
@@ -96,5 +112,5 @@
 extern ssize_t	cifs_listxattr(struct dentry *, char *, size_t);
 extern int cifs_ioctl (struct inode * inode, struct file * filep,
 		       unsigned int command, unsigned long arg);
-#define CIFS_VERSION   "1.35"
+#define CIFS_VERSION   "1.45"
 #endif				/* _CIFSFS_H */
--- linux-2.6.13/fs/cifs/cifs_fs_sb.h
+++ linux-2.6.13/fs/cifs/cifs_fs_sb.h
@@ -24,6 +24,10 @@
 #define CIFS_MOUNT_DIRECT_IO    8 /* do not write nor read through page cache */
 #define CIFS_MOUNT_NO_XATTR  0x10 /* if set - disable xattr support */
 #define CIFS_MOUNT_MAP_SPECIAL_CHR 0x20 /* remap illegal chars in filenames */
+#define CIFS_MOUNT_POSIX_PATHS	0x40 /* Negotiate posix pathnames if possible. */
+#define CIFS_MOUNT_UNX_EMUL	0x80 /* Network compat with SFUnix emulation */
+#define CIFS_MOUNT_NO_BRL	0x100 /* No sending byte range locks to srv */
+#define CIFS_MOUNT_CIFS_ACL	0x200 /* send ACL requests to non-POSIX srv */
 
 struct cifs_sb_info {
 	struct cifsTconInfo *tcon;	/* primary mount */
--- linux-2.6.13/fs/cifs/cifsglob.h
+++ linux-2.6.13/fs/cifs/cifsglob.h
@@ -1,7 +1,7 @@
 /*
  *   fs/cifs/cifsglob.h
  *
- *   Copyright (C) International Business Machines  Corp., 2002,2005
+ *   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
@@ -17,6 +17,7 @@
  */
 #include <linux/in.h>
 #include <linux/in6.h>
+#include <linux/version.h>
 #include "cifs_fs_sb.h"
 /*
  * The sizes of various internal tables and strings
@@ -88,7 +89,8 @@
 };
 
 enum securityEnum {
-	NTLM = 0,		/* Legacy NTLM012 auth with NTLM hash */
+	LANMAN = 0,             /* Legacy LANMAN auth */
+	NTLM,			/* Legacy NTLM012 auth with NTLM hash */
 	NTLMv2,			/* Legacy NTLM auth with NTLMv2 hash */
 	RawNTLMSSP,		/* NTLMSSP without SPNEGO */
 	NTLMSSP,		/* NTLMSSP via SPNEGO */
@@ -110,8 +112,9 @@
  */
 
 struct TCP_Server_Info {
-	char server_Name[SERVER_NAME_LEN_WITH_NULL];	/* 15 chars + X'20'in 16th */
-	char unicode_server_Name[SERVER_NAME_LEN_WITH_NULL * 2];	/* Unicode version of server_Name */
+	/* 15 character server name + 0x20 16th byte indicating type = srv */
+	char server_RFC1001_name[SERVER_NAME_LEN_WITH_NULL];
+	char unicode_server_Name[SERVER_NAME_LEN_WITH_NULL * 2];
 	struct socket *ssocket;
 	union {
 		struct sockaddr_in sockAddr;
@@ -129,6 +132,10 @@
 	unsigned svlocal:1;	/* local server or remote */
 	atomic_t socketUseCount; /* number of open cifs sessions on socket */
 	atomic_t inFlight;  /* number of requests on the wire to server */
+#ifdef CONFIG_CIFS_STATS2
+	atomic_t inSend; /* requests trying to send */
+	atomic_t num_waiters;   /* blocked waiting to get in sendrecv */
+#endif
 	enum statusEnum tcpStatus; /* what we think the status is */
 	struct semaphore tcpSem;
 	struct task_struct *tsk;
@@ -147,10 +154,13 @@
 	/* (returned on Negotiate */
 	int capabilities; /* allow selective disabling of caps by smb sess */
 	__u16 timeZone;
+	__u16 CurrentMid;         /* multiplex id - rotating counter */
 	char cryptKey[CIFS_CRYPTO_KEY_SIZE];
-	char workstation_RFC1001_name[16]; /* 16th byte is always zero */
+	/* 16th byte of RFC1001 workstation name is always null */
+	char workstation_RFC1001_name[SERVER_NAME_LEN_WITH_NULL];
 	__u32 sequence_number; /* needed for CIFS PDU signature */
-	char mac_signing_key[CIFS_SESSION_KEY_SIZE + 16]; 
+	char mac_signing_key[CIFS_SESS_KEY_SIZE + 16];
+	unsigned long lstrp; /* when we got last response from this server */
 };
 
 /*
@@ -172,10 +182,13 @@
 struct cifsSesInfo {
 	struct list_head cifsSessionList;
 	struct semaphore sesSem;
+#if 0
 	struct cifsUidInfo *uidInfo;	/* pointer to user info */
+#endif
 	struct TCP_Server_Info *server;	/* pointer to server info */
 	atomic_t inUse; /* # of mounts (tree connections) on this ses */
 	enum statusEnum status;
+	unsigned overrideSecFlg;  /* if non-zero override global sec flags */
 	__u16 ipc_tid;		/* special tid for connection to IPC share */
 	__u16 flags;
 	char *serverOS;		/* name of operating system underlying server */
@@ -187,7 +200,7 @@
 	char serverName[SERVER_NAME_LEN_WITH_NULL * 2];	/* BB make bigger for 
 				TCP names - will ipv6 and sctp addresses fit? */
 	char userName[MAX_USERNAME_SIZE + 1];
-	char domainName[MAX_USERNAME_SIZE + 1];
+	char * domainName;
 	char * password;
 };
 /* session flags */
@@ -202,31 +215,55 @@
 	struct list_head openFileList;
 	struct semaphore tconSem;
 	struct cifsSesInfo *ses;	/* pointer to session associated with */
-	char treeName[MAX_TREE_SIZE + 1]; /* UNC name of resource (in ASCII not UTF) */
+	char treeName[MAX_TREE_SIZE + 1]; /* UNC name of resource in ASCII */
 	char *nativeFileSystem;
 	__u16 tid;		/* The 2 byte tree id */
 	__u16 Flags;		/* optional support bits */
 	enum statusEnum tidStatus;
-	atomic_t useCount;	/* how many mounts (explicit or implicit) to this share */
+	atomic_t useCount;	/* how many explicit/implicit mounts to share */
 #ifdef CONFIG_CIFS_STATS
 	atomic_t num_smbs_sent;
 	atomic_t num_writes;
 	atomic_t num_reads;
 	atomic_t num_oplock_brks;
 	atomic_t num_opens;
+	atomic_t num_closes;
 	atomic_t num_deletes;
 	atomic_t num_mkdirs;
 	atomic_t num_rmdirs;
 	atomic_t num_renames;
 	atomic_t num_t2renames;
+	atomic_t num_ffirst;
+	atomic_t num_fnext;
+	atomic_t num_fclose;
+	atomic_t num_hardlinks;
+	atomic_t num_symlinks;
+	atomic_t num_locks;
+	atomic_t num_acl_get;
+	atomic_t num_acl_set;
+#ifdef CONFIG_CIFS_STATS2
+	unsigned long long time_writes;
+	unsigned long long time_reads;
+	unsigned long long time_opens;
+	unsigned long long time_deletes;
+	unsigned long long time_closes;
+	unsigned long long time_mkdirs;
+	unsigned long long time_rmdirs;
+	unsigned long long time_renames;
+	unsigned long long time_t2renames;
+	unsigned long long time_ffirst;
+	unsigned long long time_fnext;
+	unsigned long long time_fclose;
+#endif /* CONFIG_CIFS_STATS2 */
 	__u64    bytes_read;
 	__u64    bytes_written;
 	spinlock_t stat_lock;
-#endif
+#endif /* CONFIG_CIFS_STATS */
 	FILE_SYSTEM_DEVICE_INFO fsDevInfo;
-	FILE_SYSTEM_ATTRIBUTE_INFO fsAttrInfo;	/* ok if file system name truncated */
+	FILE_SYSTEM_ATTRIBUTE_INFO fsAttrInfo; /* ok if fs name truncated */
 	FILE_SYSTEM_UNIX_INFO fsUnixInfo;
 	unsigned retry:1;
+	unsigned nocase:1;
 	/* BB add field for back pointer to sb struct? */
 };
 
@@ -256,6 +293,7 @@
 	unsigned endOfSearch:1;
 	unsigned emptyDir:1;
 	unsigned unicode:1;
+	unsigned smallBuf:1; /* so we know which buf_release function to call */
 };
 
 struct cifsFileInfo {
@@ -270,9 +308,9 @@
 	struct inode * pInode; /* needed for oplock break */
 	unsigned closePend:1;	/* file is marked to close */
 	unsigned invalidHandle:1;  /* file closed via session abend */
+	atomic_t wrtPending;   /* handle in use - defer close */
 	struct semaphore fh_sem; /* prevents reopen race after dead ses*/
 	char * search_resume_name; /* BB removeme BB */
-	unsigned int resume_name_length; /* BB removeme - field renamed and moved BB */
 	struct cifs_search_info srch_inf;
 };
 
@@ -294,6 +332,7 @@
 	struct inode vfs_inode;
 };
 
+#if LINUX_VERSION_CODE > KERNEL_VERSION(2, 5, 0)
 static inline struct cifsInodeInfo *
 CIFS_I(struct inode *inode)
 {
@@ -305,7 +344,55 @@
 {
 	return sb->s_fs_info;
 }
+#else
+static inline struct cifsInodeInfo *
+CIFS_I(struct inode *inode)
+{
+	return (struct cifsInodeInfo *)&(inode->u);
+}
+
+static inline struct cifs_sb_info *
+CIFS_SB(struct super_block *sb)
+{
+	return (struct cifs_sb_info *) &(sb->u);
+}
+#endif
+
+static inline char CIFS_DIR_SEP(const struct cifs_sb_info *cifs_sb)
+{
+	if (cifs_sb->mnt_cifs_flags & CIFS_MOUNT_POSIX_PATHS)
+		return '/';
+	else
+		return '\\';
+}
+
+#ifdef CONFIG_CIFS_STATS
+#define cifs_stats_inc atomic_inc
+
+static inline void cifs_stats_bytes_written(struct cifsTconInfo *tcon,
+					    unsigned int bytes)
+{
+	if (bytes) {
+		spin_lock(&tcon->stat_lock);
+		tcon->bytes_written += bytes;
+		spin_unlock(&tcon->stat_lock);
+	}
+}
+
+static inline void cifs_stats_bytes_read(struct cifsTconInfo *tcon,
+					 unsigned int bytes)
+{
+	spin_lock(&tcon->stat_lock);
+	tcon->bytes_read += bytes;
+	spin_unlock(&tcon->stat_lock);
+}
+#else
+
+#define  cifs_stats_inc(field) do {} while(0)
+#define  cifs_stats_bytes_written(tcon, bytes) do {} while(0)
+#define  cifs_stats_bytes_read(tcon, bytes) do {} while(0)
 
+#endif
 
 /* one of these for every pending CIFS request to the server */
 struct mid_q_entry {
@@ -313,15 +400,19 @@
 	__u16 mid;		/* multiplex id */
 	__u16 pid;		/* process id */
 	__u32 sequence_number;  /* for CIFS signing */
-	struct timeval when_sent;	/* time when smb sent */
+	unsigned long when_alloc;  /* when mid was created */
+#ifdef CONFIG_CIFS_STATS2
+	unsigned long when_sent; /* time when smb send finished */
+	unsigned long when_received; /* when demux complete (taken off wire) */
+#endif
 	struct cifsSesInfo *ses;	/* smb was sent to this server */
 	struct task_struct *tsk;	/* task waiting for response */
 	struct smb_hdr *resp_buf;	/* response buffer */
 	int midState;	/* wish this were enum but can not pass to wait_event */
 	__u8 command;	/* smb command code */
-	unsigned multiPart:1;	/* multiple responses to one SMB request */
 	unsigned largeBuf:1;    /* if valid response, is pointer to large buf */
-	unsigned multiResp:1;   /* multiple trans2 responses for one request  */
+	unsigned multiRsp:1;   /* multiple trans2 responses for one request  */
+	unsigned multiEnd:1; /* both received */
 };
 
 struct oplock_q_entry {
@@ -331,14 +422,62 @@
 	__u16 netfid;
 };
 
+/* for pending dnotify requests */
+struct dir_notify_req {
+       struct list_head lhead;
+       __le16 Pid;
+       __le16 PidHigh;
+       __u16 Mid;
+       __u16 Tid;
+       __u16 Uid;
+       __u16 netfid;
+       __u32 filter; /* CompletionFilter (for multishot) */
+       int multishot;
+       struct file * pfile;
+};
+
 #define   MID_FREE 0
 #define   MID_REQUEST_ALLOCATED 1
 #define   MID_REQUEST_SUBMITTED 2
 #define   MID_RESPONSE_RECEIVED 4
 #define   MID_RETRY_NEEDED      8 /* session closed while this request out */
 #define   MID_NO_RESP_NEEDED 0x10
-#define   MID_SMALL_BUFFER   0x20 /* 112 byte response buffer instead of 4K */
 
+/* Types of response buffer returned from SendReceive2 */
+#define   CIFS_NO_BUFFER        0    /* Response buffer not returned */
+#define   CIFS_SMALL_BUFFER     1
+#define   CIFS_LARGE_BUFFER     2
+#define   CIFS_IOVEC            4    /* array of response buffers */
+
+/* Security Flags: indicate type of session setup needed */
+#define   CIFSSEC_MAY_SIGN	0x00001
+#define   CIFSSEC_MAY_NTLM	0x00002
+#define   CIFSSEC_MAY_NTLMV2	0x00004
+#define   CIFSSEC_MAY_KRB5	0x00008
+#ifdef CONFIG_CIFS_WEAK_PW_HASH
+#define   CIFSSEC_MAY_LANMAN	0x00010
+#define   CIFSSEC_MAY_PLNTXT	0x00020
+#endif /* weak passwords */
+#define   CIFSSEC_MAY_SEAL	0x00040 /* not supported yet */
+
+#define   CIFSSEC_MUST_SIGN	0x01001
+/* note that only one of the following can be set so the
+result of setting MUST flags more than once will be to
+require use of the stronger protocol */
+#define   CIFSSEC_MUST_NTLM	0x02002
+#define   CIFSSEC_MUST_NTLMV2	0x04004
+#define   CIFSSEC_MUST_KRB5	0x08008
+#ifdef CONFIG_CIFS_WEAK_PW_HASH
+#define   CIFSSEC_MUST_LANMAN	0x10010
+#define   CIFSSEC_MUST_PLNTXT	0x20020
+#define   CIFSSEC_MASK          0x37037 /* current flags supported if weak */
+#else	  
+#define	  CIFSSEC_MASK          0x07007 /* flags supported if no weak config */
+#endif /* WEAK_PW_HASH */
+#define   CIFSSEC_MUST_SEAL	0x40040 /* not supported yet */
+
+#define   CIFSSEC_DEF  CIFSSEC_MAY_SIGN | CIFSSEC_MAY_NTLM | CIFSSEC_MAY_NTLMV2
+#define   CIFSSEC_MAX  CIFSSEC_MUST_SIGN | CIFSSEC_MUST_NTLMV2
 /*
  *****************************************************************
  * All constants go here
@@ -399,13 +538,16 @@
 
 GLOBAL_EXTERN struct list_head GlobalOplock_Q;
 
+GLOBAL_EXTERN struct list_head GlobalDnotifyReqList; /* Outstanding dir notify requests */
+GLOBAL_EXTERN struct list_head GlobalDnotifyRsp_Q;/* DirNotify response queue */
+
 /*
  * Global transaction id (XID) information
  */
 GLOBAL_EXTERN unsigned int GlobalCurrentXid;	/* protected by GlobalMid_Sem */
 GLOBAL_EXTERN unsigned int GlobalTotalActiveXid;	/* prot by GlobalMid_Sem */
 GLOBAL_EXTERN unsigned int GlobalMaxActiveXid;	/* prot by GlobalMid_Sem */
-GLOBAL_EXTERN spinlock_t GlobalMid_Lock;  /* protects above and list operations */
+GLOBAL_EXTERN spinlock_t GlobalMid_Lock;  /* protects above & list operations */
 					/* on midQ entries */
 GLOBAL_EXTERN char Local_System_Name[15];
 
@@ -419,7 +561,11 @@
 GLOBAL_EXTERN atomic_t tconInfoReconnectCount;
 
 /* Various Debug counters to remove someday (BB) */
-GLOBAL_EXTERN atomic_t bufAllocCount;
+GLOBAL_EXTERN atomic_t bufAllocCount;    /* current number allocated  */
+#ifdef CONFIG_CIFS_STATS2
+GLOBAL_EXTERN atomic_t totBufAllocCount; /* total allocated over all time */
+GLOBAL_EXTERN atomic_t totSmBufAllocCount;
+#endif
 GLOBAL_EXTERN atomic_t smBufAllocCount;      
 GLOBAL_EXTERN atomic_t midCount;
 
@@ -433,8 +579,8 @@
 GLOBAL_EXTERN unsigned int lookupCacheEnabled;
 GLOBAL_EXTERN unsigned int extended_security;	/* if on, session setup sent 
 				with more secure ntlmssp2 challenge/resp */
-GLOBAL_EXTERN unsigned int ntlmv2_support;  /* better optional password hash */
 GLOBAL_EXTERN unsigned int sign_CIFS_PDUs;  /* enable smb packet signing */
+GLOBAL_EXTERN unsigned int secFlags;
 GLOBAL_EXTERN unsigned int linuxExtEnabled;/*enable Linux/Unix CIFS extensions*/
 GLOBAL_EXTERN unsigned int CIFSMaxBufSize;  /* max size not including hdr */
 GLOBAL_EXTERN unsigned int cifs_min_rcv;    /* min size of big ntwrk buf pool */
--- linux-2.6.13/fs/cifs/cifspdu.h
+++ linux-2.6.13/fs/cifs/cifspdu.h
@@ -1,7 +1,7 @@
 /*
  *   fs/cifs/cifspdu.h
  *
- *   Copyright (c) International Business Machines  Corp., 2002
+ *   Copyright (c) International Business Machines  Corp., 2002,2005
  *   Author(s): Steve French (sfrench@us.ibm.com)
  *
  *   This library is free software; you can redistribute it and/or modify
@@ -24,8 +24,14 @@
 
 #include <net/sock.h>
 
+#ifdef CONFIG_CIFS_WEAK_PW_HASH
+#define LANMAN_PROT 0
+#define CIFS_PROT   1
+#else
 #define CIFS_PROT   0
-#define BAD_PROT    CIFS_PROT+1
+#endif
+#define POSIX_PROT  CIFS_PROT+1
+#define BAD_PROT 0xFFFF
 
 /* SMB command codes */
 /* Some commands have minimal (wct=0,bcc=0), or uninteresting, responses
@@ -36,9 +42,11 @@
 #define SMB_COM_CLOSE                 0x04 /* triv req/rsp, timestamp ignored */
 #define SMB_COM_DELETE                0x06 /* trivial response */
 #define SMB_COM_RENAME                0x07 /* trivial response */
+#define SMB_COM_QUERY_INFORMATION     0x08 /* aka getattr */
 #define SMB_COM_SETATTR               0x09 /* trivial response */
 #define SMB_COM_LOCKING_ANDX          0x24 /* trivial response */
 #define SMB_COM_COPY                  0x29 /* trivial rsp, fail filename ignrd*/
+#define SMB_COM_OPEN_ANDX             0x2D /* Legacy open for old servers */
 #define SMB_COM_READ_ANDX             0x2E
 #define SMB_COM_WRITE_ANDX            0x2F
 #define SMB_COM_TRANSACTION2          0x32
@@ -52,6 +60,7 @@
 #define SMB_COM_NT_TRANSACT           0xA0
 #define SMB_COM_NT_TRANSACT_SECONDARY 0xA1
 #define SMB_COM_NT_CREATE_ANDX        0xA2
+#define SMB_COM_NT_CANCEL             0xA4 /* no response */
 #define SMB_COM_NT_RENAME             0xA5 /* trivial response */
 
 /* Transact2 subcommand codes */
@@ -59,6 +68,7 @@
 #define TRANS2_FIND_FIRST             0x01
 #define TRANS2_FIND_NEXT              0x02
 #define TRANS2_QUERY_FS_INFORMATION   0x03
+#define TRANS2_SET_FS_INFORMATION     0x04
 #define TRANS2_QUERY_PATH_INFORMATION 0x05
 #define TRANS2_SET_PATH_INFORMATION   0x06
 #define TRANS2_QUERY_FILE_INFORMATION 0x07
@@ -76,7 +86,11 @@
 #define NT_TRANSACT_GET_USER_QUOTA    0x07
 #define NT_TRANSACT_SET_USER_QUOTA    0x08
 
-#define MAX_CIFS_HDR_SIZE 256	/* chained NTCreateXReadX will probably be biggest */
+#define MAX_CIFS_SMALL_BUFFER_SIZE 448 /* big enough for most */
+/* future chained NTCreateXReadX bigger, but for time being NTCreateX biggest */
+/* among the requests (NTCreateX response is bigger with wct of 34) */
+#define MAX_CIFS_HDR_SIZE 0x58 /* 4 len + 32 hdr + (2*24 wct) + 2 bct + 2 pad */
+#define CIFS_SMALL_PATH 120 /* allows for (448-88)/3 */
 
 /* internal cifs vfs structures */
 /*****************************************************************
@@ -84,6 +98,15 @@
  *****************************************************************
  */
 
+#ifndef __le16
+#define __le16 __u16
+#define __le32 __u32
+#define __le64 __u64
+#define __be16 __u16
+#define __be32 __u32
+#define __be64 __u64
+#endif
+
 /*
  * Starting value for maximum SMB size negotiation
  */
@@ -102,7 +125,7 @@
 /*
  * Size of the session key (crypto key encrypted with the password
  */
-#define CIFS_SESSION_KEY_SIZE (24)
+#define CIFS_SESS_KEY_SIZE (24)
 
 /*
  * Maximum user name length
@@ -129,10 +152,11 @@
 /*
  * SMB flag definitions 
  */
-#define SMBFLG_EXTD_LOCK 0x01	/* server supports lock-read write-unlock primitives */
+#define SMBFLG_EXTD_LOCK 0x01	/* server supports lock-read write-unlock smb */
 #define SMBFLG_RCV_POSTED 0x02	/* obsolete */
 #define SMBFLG_RSVD 0x04
-#define SMBFLG_CASELESS 0x08	/* all pathnames treated as caseless (off implies case sensitive file handling requested) */
+#define SMBFLG_CASELESS 0x08	/* all pathnames treated as caseless (off
+				implies case sensitive file handling request) */
 #define SMBFLG_CANONICAL_PATH_FORMAT 0x10	/* obsolete */
 #define SMBFLG_OLD_OPLOCK 0x20	/* obsolete */
 #define SMBFLG_OLD_OPLOCK_NOTIFY 0x40	/* obsolete */
@@ -141,7 +165,8 @@
 /*
  * SMB flag2 definitions 
  */
-#define SMBFLG2_KNOWS_LONG_NAMES cpu_to_le16(1)	/* can send long (non-8.3) path names in response */
+#define SMBFLG2_KNOWS_LONG_NAMES cpu_to_le16(1)	/* can send long (non-8.3) 
+						   path names in response */
 #define SMBFLG2_KNOWS_EAS cpu_to_le16(2)
 #define SMBFLG2_SECURITY_SIGNATURE cpu_to_le16(4)
 #define SMBFLG2_IS_LONG_NAME cpu_to_le16(0x40)
@@ -193,7 +218,7 @@
 					 /* In summary - Relevant file       */
 					 /* access flags from CIFS are       */
 					 /* file_read_data, file_write_data  */
-					 /* file_execute, file_read_attributes */
+					 /* file_execute, file_read_attributes*/
 					 /* write_dac, and delete.           */
 
 /*
@@ -238,7 +263,8 @@
 #define ATTR_SPARSE    0x0200
 #define ATTR_REPARSE   0x0400
 #define ATTR_COMPRESSED 0x0800
-#define ATTR_OFFLINE    0x1000	/* ie file not immediately available - offline storage */
+#define ATTR_OFFLINE    0x1000	/* ie file not immediately available - 
+					on offline storage */
 #define ATTR_NOT_CONTENT_INDEXED 0x2000
 #define ATTR_ENCRYPTED  0x4000
 #define ATTR_POSIX_SEMANTICS 0x01000000
@@ -267,10 +293,18 @@
 /* CreateOptions */
 #define CREATE_NOT_FILE		0x00000001	/* if set must not be file */
 #define CREATE_WRITE_THROUGH	0x00000002
+#define CREATE_SEQUENTIAL       0x00000004
+#define CREATE_SYNC_ALERT       0x00000010
+#define CREATE_ASYNC_ALERT      0x00000020
 #define CREATE_NOT_DIR		0x00000040	/* if set must not be directory */
+#define CREATE_NO_EA_KNOWLEDGE  0x00000200
+#define CREATE_EIGHT_DOT_THREE  0x00000400
 #define CREATE_RANDOM_ACCESS	0x00000800
 #define CREATE_DELETE_ON_CLOSE	0x00001000
+#define CREATE_OPEN_BY_ID       0x00002000
 #define OPEN_REPARSE_POINT	0x00200000
+#define CREATE_OPTIONS_MASK     0x007FFFFF 
+#define CREATE_OPTION_SPECIAL   0x20000000   /* system. NB not sent over wire */
 
 /* ImpersonationLevel flags */
 #define SECURITY_ANONYMOUS      0
@@ -297,10 +331,10 @@
 #define GETU16(var)  (*((__u16 *)var))	/* BB check for endian issues */
 #define GETU32(var)  (*((__u32 *)var))	/* BB check for endian issues */
 
-#pragma pack(1)
-
 struct smb_hdr {
-	__u32 smb_buf_length;	/* big endian on wire *//* BB length is only two or three bytes - with one or two byte type preceding it but that is always zero - we could mask the type byte off just in case BB */
+	__u32 smb_buf_length;	/* big endian on wire *//* BB length is only two
+		or three bytes - with one or two byte type preceding it that are
+		zero - we could mask the type byte off just in case BB */
 	__u8 Protocol[4];
 	__u8 Command;
 	union {
@@ -308,9 +342,9 @@
 			__u8 ErrorClass;
 			__u8 Reserved;
 			__le16 Error;
-		} DosError;
+		} __attribute__((packed)) DosError;
 		__le32 CifsError;
-	} Status;
+	} __attribute__((packed)) Status;
 	__u8 Flags;
 	__le16 Flags2;		/* note: le */
 	__le16 PidHigh;
@@ -318,16 +352,16 @@
 		struct {
 			__le32 SequenceNumber;  /* le */
 			__u32 Reserved; /* zero */
-		} Sequence;
+		} __attribute__((packed)) Sequence;
 		__u8 SecuritySignature[8];	/* le */
-	} Signature;
+	} __attribute__((packed)) Signature;
 	__u8 pad[2];
 	__u16 Tid;
 	__le16 Pid;
 	__u16 Uid;
 	__u16 Mid;
 	__u8 WordCount;
-};
+} __attribute__((packed));
 /* given a pointer to an smb_hdr retrieve the value of byte count */
 #define BCC(smb_var) ( *(__u16 *)((char *)smb_var + sizeof(struct smb_hdr) + (2* smb_var->WordCount) ) )
 #define BCC_LE(smb_var) ( *(__le16 *)((char *)smb_var + sizeof(struct smb_hdr) + (2* smb_var->WordCount) ) )
@@ -379,7 +413,30 @@
 	struct smb_hdr hdr;	/* wct = 0 */
 	__le16 ByteCount;
 	unsigned char DialectsArray[1];
-} NEGOTIATE_REQ;
+} __attribute__((packed)) NEGOTIATE_REQ;
+
+/* Dialect index is 13 for LANMAN */
+
+typedef struct lanman_neg_rsp {
+	struct smb_hdr hdr;	/* wct = 13 */
+	__le16 DialectIndex;
+	__le16 SecurityMode;
+	__le16 MaxBufSize;
+	__le16 MaxMpxCount;
+	__le16 MaxNumberVcs;
+	__le16 RawMode;
+	__le32 SessionKey;
+	__le32 ServerTime;
+	__le16 ServerTimeZone;
+	__le16 EncryptionKeyLength;
+	__le16 Reserved;
+	__u16  ByteCount;
+	unsigned char EncryptionKey[1];
+} __attribute__((packed)) LANMAN_NEG_RSP;
+
+#define READ_RAW_ENABLE 1
+#define WRITE_RAW_ENABLE 2
+#define RAW_ENABLE (READ_RAW_ENABLE | WRITE_RAW_ENABLE)
 
 typedef struct negotiate_rsp {
 	struct smb_hdr hdr;	/* wct = 17 */
@@ -397,16 +454,16 @@
 	__u8 EncryptionKeyLength;
 	__u16 ByteCount;
 	union {
-		unsigned char EncryptionKey[1];	/* if cap extended security is off */
+		unsigned char EncryptionKey[1];	/* cap extended security off */
 		/* followed by Domain name - if extended security is off */
 		/* followed by 16 bytes of server GUID */
-		/* followed by security blob if cap_extended_security negotiated */
+		/* then security blob if cap_extended_security negotiated */
 		struct {
 			unsigned char GUID[16];
 			unsigned char SecurityBlob[1];
-		} extended_response;
-	} u;
-} NEGOTIATE_RSP;
+		} __attribute__((packed)) extended_response;
+	} __attribute__((packed)) u;
+} __attribute__((packed)) NEGOTIATE_RSP;
 
 /* SecurityMode bits */
 #define SECMODE_USER          0x01	/* off indicates share level security */
@@ -452,7 +509,8 @@
 		unsigned char SecurityBlob[1];	/* followed by */
 		/* STRING NativeOS */
 		/* STRING NativeLanMan */
-	} req;			/* NTLM request format (with extended security */
+	} __attribute__((packed)) req;	/* NTLM request format (with 
+					extended security */
 
 	struct {		/* request format */
 		struct smb_hdr hdr;	/* wct = 13 */
@@ -463,8 +521,8 @@
 		__le16 MaxMpxCount;
 		__le16 VcNumber;
 		__u32 SessionKey;
-		__le16 CaseInsensitivePasswordLength;	/* ASCII password length */
-		__le16 CaseSensitivePasswordLength;	/* Unicode password length */
+		__le16 CaseInsensitivePasswordLength; /* ASCII password len */
+		__le16 CaseSensitivePasswordLength; /* Unicode password length*/
 		__u32 Reserved;	/* see below */
 		__le32 Capabilities;
 		__le16 ByteCount;
@@ -474,7 +532,8 @@
 		/* STRING PrimaryDomain */
 		/* STRING NativeOS */
 		/* STRING NativeLanMan */
-	} req_no_secext;	/* NTLM request format (without extended security */
+	} __attribute__((packed)) req_no_secext; /* NTLM request format (without
+							extended security */
 
 	struct {		/* default (NTLM) response format */
 		struct smb_hdr hdr;	/* wct = 4 */
@@ -488,7 +547,7 @@
 /*      unsigned char  * NativeOS;      */
 /*	unsigned char  * NativeLanMan;  */
 /*      unsigned char  * PrimaryDomain; */
-	} resp;			/* NTLM response format (with or without extended security */
+	} __attribute__((packed)) resp;	/* NTLM response with or without extended sec*/
 
 	struct {		/* request format */
 		struct smb_hdr hdr;	/* wct = 10 */
@@ -499,15 +558,15 @@
 		__le16 MaxMpxCount;
 		__le16 VcNumber;
 		__u32 SessionKey;
-		__le16 PassswordLength;
-		__u32 Reserved;
+		__le16 PasswordLength;
+		__u32 Reserved; /* encrypt key len and offset */
 		__le16 ByteCount;
 		unsigned char AccountPassword[1];	/* followed by */
 		/* STRING AccountName */
 		/* STRING PrimaryDomain */
 		/* STRING NativeOS */
 		/* STRING NativeLanMan */
-	} old_req;		/* pre-NTLM (LANMAN2.1) request format */
+	} __attribute__((packed)) old_req; /* pre-NTLM (LANMAN2.1) req format */
 
 	struct {		/* default (NTLM) response format */
 		struct smb_hdr hdr;	/* wct = 3 */
@@ -519,8 +578,28 @@
 		unsigned char NativeOS[1];	/* followed by */
 /*	unsigned char * NativeLanMan; */
 /*      unsigned char * PrimaryDomain; */
-	} old_resp;		/* pre-NTLM (LANMAN2.1) response format */
-} SESSION_SETUP_ANDX;
+	} __attribute__((packed)) old_resp; /* pre-NTLM (LANMAN2.1) response */
+} __attribute__((packed)) SESSION_SETUP_ANDX;
+
+/* format of NLTMv2 Response ie "case sensitive password" hash when NTLMv2 */
+
+struct ntlmssp2_name {
+	__le16 type;
+	__le16 length;
+/*	char   name[length]; */
+} __attribute__((packed));
+
+struct ntlmv2_resp {
+	char ntlmv2_hash[CIFS_ENCPWD_SIZE];
+	__le32 blob_signature;
+	__u32  reserved;
+	__le64  time;
+	__u64  client_chal; /* random */
+	__u32  reserved2;
+	struct ntlmssp2_name names[1];
+	/* array of name entries could follow ending in minimum 4 byte struct */
+} __attribute__((packed));
+
 
 #define CIFS_NETWORK_OPSYS "CIFS VFS Client for Linux"
 
@@ -530,7 +609,8 @@
 #define CAP_NT_SMBS            0x00000010
 #define CAP_STATUS32           0x00000040
 #define CAP_LEVEL_II_OPLOCKS   0x00000080
-#define CAP_NT_FIND            0x00000200	/* reserved should be zero (presumably because NT_SMBs implies the same thing) */
+#define CAP_NT_FIND            0x00000200	/* reserved should be zero 
+				(because NT_SMBs implies the same thing?) */
 #define CAP_BULK_TRANSFER      0x20000000
 #define CAP_EXTENDED_SECURITY  0x80000000
 
@@ -548,10 +628,12 @@
 	unsigned char Password[1];	/* followed by */
 /* STRING Path    *//* \\server\share name */
 	/* STRING Service */
-} TCONX_REQ;
+} __attribute__((packed)) TCONX_REQ;
 
 typedef struct smb_com_tconx_rsp {
-	struct smb_hdr hdr;	/* wct = 3 *//* note that Win2000 has sent wct=7 in some cases on responses. Four unspecified words followed OptionalSupport */
+	struct smb_hdr hdr;	/* wct = 3 note that Win2000 has sent wct = 7
+				 in some cases on responses. Four unspecified
+				 words followed OptionalSupport */
 	__u8 AndXCommand;
 	__u8 AndXReserved;
 	__le16 AndXOffset;
@@ -559,13 +641,14 @@
 	__u16 ByteCount;
 	unsigned char Service[1];	/* always ASCII, not Unicode */
 	/* STRING NativeFileSystem */
-} TCONX_RSP;
+} __attribute__((packed)) TCONX_RSP;
 
 /* tree connect Flags */
 #define DISCONNECT_TID          0x0001
 #define TCON_EXTENDED_SECINFO   0x0008
 /* OptionalSupport bits */
-#define SMB_SUPPORT_SEARCH_BITS 0x0001	/* must have bits (exclusive searches suppt. */
+#define SMB_SUPPORT_SEARCH_BITS 0x0001	/* "must have" directory search bits
+					 (exclusive searches supported) */
 #define SMB_SHARE_IS_IN_DFS     0x0002
 
 typedef struct smb_com_logoff_andx_req {
@@ -574,7 +657,7 @@
 	__u8 AndXReserved;
 	__u16 AndXOffset;
 	__u16 ByteCount;
-} LOGOFF_ANDX_REQ;
+} __attribute__((packed)) LOGOFF_ANDX_REQ;
 
 typedef struct smb_com_logoff_andx_rsp {
 	struct smb_hdr hdr;	/* wct = 2 */
@@ -582,38 +665,41 @@
 	__u8 AndXReserved;
 	__u16 AndXOffset;
 	__u16 ByteCount;
-} LOGOFF_ANDX_RSP;
+} __attribute__((packed)) LOGOFF_ANDX_RSP;
 
-typedef union smb_com_tree_disconnect {	/* as an altetnative can use flag on tree_connect PDU to effect disconnect *//* probably the simplest SMB PDU */
+typedef union smb_com_tree_disconnect {	/* as an altetnative can use flag on 
+					tree_connect PDU to effect disconnect */
+					/* tdis is probably simplest SMB PDU */
 	struct {
 		struct smb_hdr hdr;	/* wct = 0 */
 		__u16 ByteCount;	/* bcc = 0 */
-	} req;
+	} __attribute__((packed)) req;
 	struct {
 		struct smb_hdr hdr;	/* wct = 0 */
 		__u16 ByteCount;	/* bcc = 0 */
-	} resp;
-} TREE_DISCONNECT;
+	} __attribute__((packed)) resp;
+} __attribute__((packed)) TREE_DISCONNECT;
 
 typedef struct smb_com_close_req {
 	struct smb_hdr hdr;	/* wct = 3 */
 	__u16 FileID;
 	__u32 LastWriteTime;	/* should be zero */
 	__u16 ByteCount;	/* 0 */
-} CLOSE_REQ;
+} __attribute__((packed)) CLOSE_REQ;
 
 typedef struct smb_com_close_rsp {
 	struct smb_hdr hdr;	/* wct = 0 */
 	__u16 ByteCount;	/* bct = 0 */
-} CLOSE_RSP;
+} __attribute__((packed)) CLOSE_RSP;
 
 typedef struct smb_com_findclose_req {
 	struct smb_hdr hdr; /* wct = 1 */
 	__u16 FileID;
 	__u16 ByteCount;    /* 0 */
-} FINDCLOSE_REQ;
+} __attribute__((packed)) FINDCLOSE_REQ;
 
 /* OpenFlags */
+#define REQ_MORE_INFO      0x00000001  /* legacy (OPEN_AND_X) only */
 #define REQ_OPLOCK         0x00000002
 #define REQ_BATCHOPLOCK    0x00000004
 #define REQ_OPENDIRONLY    0x00000008
@@ -637,7 +723,7 @@
 	__u8 SecurityFlags;
 	__le16 ByteCount;
 	char fileName[1];
-} OPEN_REQ;
+} __attribute__((packed)) OPEN_REQ;
 
 /* open response: oplock levels */
 #define OPLOCK_NONE  	 0
@@ -667,7 +753,63 @@
 	__le16 DeviceState;
 	__u8 DirectoryFlag;
 	__u16 ByteCount;	/* bct = 0 */
-} OPEN_RSP;
+} __attribute__((packed)) OPEN_RSP;
+
+/* format of legacy open request */
+typedef struct smb_com_openx_req {
+	struct smb_hdr	hdr;	/* wct = 15 */
+	__u8 AndXCommand;
+	__u8 AndXReserved;
+	__le16 AndXOffset;
+	__le16 OpenFlags;
+	__le16 Mode;
+	__le16 Sattr; /* search attributes */
+	__le16 FileAttributes;  /* dos attrs */
+	__le32 CreateTime; /* os2 format */
+	__le16 OpenFunction;
+	__le32 EndOfFile;
+	__le32 Timeout;
+	__le32 Reserved;
+	__le16  ByteCount;  /* file name follows */
+	char   fileName[1];
+} __attribute__((packed)) OPENX_REQ;
+
+typedef struct smb_com_openx_rsp {
+	struct smb_hdr	hdr;	/* wct = 15 */
+	__u8 AndXCommand;
+	__u8 AndXReserved;
+	__le16 AndXOffset;
+	__u16  Fid;
+	__le16 FileAttributes;
+	__le32 LastWriteTime; /* os2 format */
+	__le32 EndOfFile;
+	__le16 Access;
+	__le16 FileType;
+	__le16 IPCState;
+	__le16 Action;
+	__u32  FileId;
+	__u16  Reserved;
+	__u16  ByteCount;
+} __attribute__((packed)) OPENX_RSP; 
+
+/* Legacy write request for older servers */
+typedef struct smb_com_writex_req {
+        struct smb_hdr hdr;     /* wct = 12 */
+        __u8 AndXCommand;
+        __u8 AndXReserved;
+        __le16 AndXOffset;
+        __u16 Fid;
+        __le32 OffsetLow;
+        __u32 Reserved; /* Timeout */
+        __le16 WriteMode; /* 1 = write through */
+        __le16 Remaining;
+        __le16 Reserved2;
+        __le16 DataLengthLow;
+        __le16 DataOffset;
+        __le16 ByteCount;
+        __u8 Pad;               /* BB check for whether padded to DWORD boundary and optimum performance here */
+        char Data[0];
+} __attribute__((packed)) WRITEX_REQ;
 
 typedef struct smb_com_write_req {
 	struct smb_hdr hdr;	/* wct = 14 */
@@ -686,7 +828,7 @@
 	__le16 ByteCount;
 	__u8 Pad;		/* BB check for whether padded to DWORD boundary and optimum performance here */
 	char Data[0];
-} WRITE_REQ;
+} __attribute__((packed)) WRITE_REQ;
 
 typedef struct smb_com_write_rsp {
 	struct smb_hdr hdr;	/* wct = 6 */
@@ -698,7 +840,22 @@
 	__le16 CountHigh;
 	__u16  Reserved;
 	__u16 ByteCount;
-} WRITE_RSP;
+} __attribute__((packed)) WRITE_RSP;
+
+/* legacy read request for older servers */
+typedef struct smb_com_readx_req {
+        struct smb_hdr hdr;     /* wct = 10 */
+        __u8 AndXCommand;
+        __u8 AndXReserved;
+        __le16 AndXOffset;
+        __u16 Fid;
+        __le32 OffsetLow;
+        __le16 MaxCount;
+        __le16 MinCount;                /* obsolete */
+        __le32 Reserved;
+        __le16 Remaining;
+        __le16 ByteCount;
+} __attribute__((packed)) READX_REQ;
 
 typedef struct smb_com_read_req {
 	struct smb_hdr hdr;	/* wct = 12 */
@@ -713,7 +870,7 @@
 	__le16 Remaining;
 	__le32 OffsetHigh;
 	__le16 ByteCount;
-} READ_REQ;
+} __attribute__((packed)) READ_REQ;
 
 typedef struct smb_com_read_rsp {
 	struct smb_hdr hdr;	/* wct = 12 */
@@ -730,7 +887,7 @@
 	__u16 ByteCount;
 	__u8 Pad;		/* BB check for whether padded to DWORD boundary and optimum performance here */
 	char Data[1];
-} READ_RSP;
+} __attribute__((packed)) READ_RSP;
 
 typedef struct locking_andx_range {
 	__le16 Pid;
@@ -739,7 +896,7 @@
 	__le32 OffsetLow;
 	__le32 LengthHigh;
 	__le32 LengthLow;
-} LOCKING_ANDX_RANGE;
+} __attribute__((packed)) LOCKING_ANDX_RANGE;
 
 #define LOCKING_ANDX_SHARED_LOCK     0x01
 #define LOCKING_ANDX_OPLOCK_RELEASE  0x02
@@ -760,9 +917,12 @@
 	__le16 NumberOfLocks;
 	__le16 ByteCount;
 	LOCKING_ANDX_RANGE Locks[1];
-} LOCK_REQ;
-
+} __attribute__((packed)) LOCK_REQ;
 
+/* lock type */
+#define CIFS_RDLCK	0
+#define CIFS_WRLCK	1
+#define CIFS_UNLCK      2
 typedef struct cifs_posix_lock {
 	__le16  lock_type;  /* 0 = Read, 1 = Write, 2 = Unlock */
 	__le16  lock_flags; /* 1 = Wait (only valid for setlock) */
@@ -770,7 +930,7 @@
 	__le64	start;
 	__le64	length;
 	/* BB what about additional owner info to identify network client */
-} CIFS_POSIX_LOCK;
+} __attribute__((packed)) CIFS_POSIX_LOCK;
 
 typedef struct smb_com_lock_rsp {
 	struct smb_hdr hdr;	/* wct = 2 */
@@ -778,7 +938,7 @@
 	__u8 AndXReserved;
 	__le16 AndXOffset;
 	__u16 ByteCount;
-} LOCK_RSP;
+} __attribute__((packed)) LOCK_RSP;
 
 typedef struct smb_com_rename_req {
 	struct smb_hdr hdr;	/* wct = 1 */
@@ -788,7 +948,7 @@
 	unsigned char OldFileName[1];
 	/* followed by __u8 BufferFormat2 */
 	/* followed by NewFileName */
-} RENAME_REQ;
+} __attribute__((packed)) RENAME_REQ;
 
 	/* copy request flags */
 #define COPY_MUST_BE_FILE      0x0001
@@ -808,7 +968,7 @@
 	unsigned char OldFileName[1];
 	/* followed by __u8 BufferFormat2 */
 	/* followed by NewFileName string */
-} COPY_REQ;
+} __attribute__((packed)) COPY_REQ;
 
 typedef struct smb_com_copy_rsp {
 	struct smb_hdr hdr;     /* wct = 1 */
@@ -816,7 +976,7 @@
 	__u16 ByteCount;    /* may be zero */
 	__u8 BufferFormat;  /* 0x04 - only present if errored file follows */
 	unsigned char ErrorFileName[1]; /* only present if error in copy */
-} COPY_RSP;
+} __attribute__((packed)) COPY_RSP;
 
 #define CREATE_HARD_LINK		0x103
 #define MOVEFILE_COPY_ALLOWED		0x0002
@@ -832,12 +992,12 @@
 	unsigned char OldFileName[1];
 	/* followed by __u8 BufferFormat2 */
 	/* followed by NewFileName */
-} NT_RENAME_REQ;
+} __attribute__((packed)) NT_RENAME_REQ;
 
 typedef struct smb_com_rename_rsp {
 	struct smb_hdr hdr;	/* wct = 0 */
 	__u16 ByteCount;	/* bct = 0 */
-} RENAME_RSP;
+} __attribute__((packed)) RENAME_RSP;
 
 typedef struct smb_com_delete_file_req {
 	struct smb_hdr hdr;	/* wct = 1 */
@@ -845,36 +1005,52 @@
 	__le16 ByteCount;
 	__u8 BufferFormat;	/* 4 = ASCII */
 	unsigned char fileName[1];
-} DELETE_FILE_REQ;
+} __attribute__((packed)) DELETE_FILE_REQ;
 
 typedef struct smb_com_delete_file_rsp {
 	struct smb_hdr hdr;	/* wct = 0 */
 	__u16 ByteCount;	/* bct = 0 */
-} DELETE_FILE_RSP;
+} __attribute__((packed)) DELETE_FILE_RSP;
 
 typedef struct smb_com_delete_directory_req {
 	struct smb_hdr hdr;	/* wct = 0 */
 	__le16 ByteCount;
 	__u8 BufferFormat;	/* 4 = ASCII */
 	unsigned char DirName[1];
-} DELETE_DIRECTORY_REQ;
+} __attribute__((packed)) DELETE_DIRECTORY_REQ;
 
 typedef struct smb_com_delete_directory_rsp {
 	struct smb_hdr hdr;	/* wct = 0 */
 	__u16 ByteCount;	/* bct = 0 */
-} DELETE_DIRECTORY_RSP;
+} __attribute__((packed)) DELETE_DIRECTORY_RSP;
 
 typedef struct smb_com_create_directory_req {
 	struct smb_hdr hdr;	/* wct = 0 */
 	__le16 ByteCount;
 	__u8 BufferFormat;	/* 4 = ASCII */
 	unsigned char DirName[1];
-} CREATE_DIRECTORY_REQ;
+} __attribute__((packed)) CREATE_DIRECTORY_REQ;
 
 typedef struct smb_com_create_directory_rsp {
 	struct smb_hdr hdr;	/* wct = 0 */
 	__u16 ByteCount;	/* bct = 0 */
-} CREATE_DIRECTORY_RSP;
+} __attribute__((packed)) CREATE_DIRECTORY_RSP;
+
+typedef struct smb_com_query_information_req {
+	struct smb_hdr hdr;     /* wct = 0 */
+	__le16 ByteCount;	/* 1 + namelen + 1 */
+	__u8 BufferFormat;      /* 4 = ASCII */
+	unsigned char FileName[1];
+} __attribute__((packed)) QUERY_INFORMATION_REQ;
+
+typedef struct smb_com_query_information_rsp {
+	struct smb_hdr hdr;     /* wct = 10 */
+	__le16 attr;
+	__le32  last_write_time;
+	__le32 size;
+	__u16  reserved[5];
+	__le16 ByteCount;	/* bcc = 0 */
+} __attribute__((packed)) QUERY_INFORMATION_RSP;
 
 typedef struct smb_com_setattr_req {
 	struct smb_hdr hdr; /* wct = 8 */
@@ -885,19 +1061,58 @@
 	__u16  ByteCount;
 	__u8   BufferFormat; /* 4 = ASCII */
 	unsigned char fileName[1];
-} SETATTR_REQ;
+} __attribute__((packed)) SETATTR_REQ;
 
 typedef struct smb_com_setattr_rsp {
 	struct smb_hdr hdr;     /* wct = 0 */
 	__u16 ByteCount;        /* bct = 0 */
-} SETATTR_RSP;
+} __attribute__((packed)) SETATTR_RSP;
 
 /* empty wct response to setattr */
 
-/***************************************************/
+/*******************************************************/
 /* NT Transact structure defintions follow         */
-/* Currently only ioctl and notify are implemented */
-/***************************************************/
+/* Currently only ioctl, acl (get security descriptor) */  
+/* and notify are implemented                          */
+/*******************************************************/
+typedef struct smb_com_ntransact_req {
+        struct smb_hdr hdr; /* wct >= 19 */
+        __u8 MaxSetupCount;
+        __u16 Reserved;
+        __le32 TotalParameterCount;
+        __le32 TotalDataCount;
+        __le32 MaxParameterCount;
+        __le32 MaxDataCount;
+        __le32 ParameterCount;
+        __le32 ParameterOffset;
+        __le32 DataCount;
+        __le32 DataOffset;
+        __u8 SetupCount; /* four setup words follow subcommand */
+        /* SNIA spec incorrectly included spurious pad here */
+        __le16 SubCommand; /* 2 = IOCTL/FSCTL */
+	/* SetupCount words follow then */ 
+        __le16 ByteCount;
+        __u8 Pad[3];
+        __u8 Parms[0];
+} __attribute__((packed)) NTRANSACT_REQ;
+
+typedef struct smb_com_ntransact_rsp {
+	struct smb_hdr hdr;     /* wct = 18 */
+	__u8 Reserved[3];
+	__le32 TotalParameterCount;
+	__le32 TotalDataCount;
+	__le32 ParameterCount;
+	__le32 ParameterOffset;
+	__le32 ParameterDisplacement;
+	__le32 DataCount;
+	__le32 DataOffset;
+	__le32 DataDisplacement;
+	__u8 SetupCount;   /* 0 */
+	__u16 ByteCount;
+        /* __u8 Pad[3]; */
+	/* parms and data follow */
+} __attribute__((packed)) NTRANSACT_RSP;
+
 typedef struct smb_com_transaction_ioctl_req {
 	struct smb_hdr hdr;	/* wct = 23 */
 	__u8 MaxSetupCount;
@@ -912,15 +1127,15 @@
 	__le32 DataOffset;
 	__u8 SetupCount; /* four setup words follow subcommand */
 	/* SNIA spec incorrectly included spurious pad here */
-	__le16 SubCommand;/* 2 = IOCTL/FSCTL */
+	__le16 SubCommand; /* 2 = IOCTL/FSCTL */
 	__le32 FunctionCode;
 	__u16 Fid;
-	__u8 IsFsctl;    /* 1 = File System Control, 0 = device control (IOCTL)*/
-	__u8 IsRootFlag; /* 1 = apply command to root of share (must be DFS share)*/
+	__u8 IsFsctl;  /* 1 = File System Control 0 = device control (IOCTL) */
+	__u8 IsRootFlag; /* 1 = apply command to root of share (must be DFS) */
 	__le16 ByteCount;
 	__u8 Pad[3];
 	__u8 Data[1];
-} TRANSACT_IOCTL_REQ;
+} __attribute__((packed)) TRANSACT_IOCTL_REQ;
 
 typedef struct smb_com_transaction_ioctl_rsp {
 	struct smb_hdr hdr;	/* wct = 19 */
@@ -936,8 +1151,34 @@
 	__u8 SetupCount;	/* 1 */
 	__le16 ReturnedDataLen;
 	__u16 ByteCount;
+} __attribute__((packed)) TRANSACT_IOCTL_RSP;
+
+#define CIFS_ACL_OWNER 1
+#define CIFS_ACL_GROUP 2
+#define CIFS_ACL_DACL  4
+#define CIFS_ACL_SACL  8
+
+typedef struct smb_com_transaction_qsec_req {
+	struct smb_hdr hdr;     /* wct = 19 */
+	__u8 MaxSetupCount;
+	__u16 Reserved;
+	__le32 TotalParameterCount;
+	__le32 TotalDataCount;
+	__le32 MaxParameterCount;
+	__le32 MaxDataCount;
+	__le32 ParameterCount;
+	__le32 ParameterOffset;
+	__le32 DataCount;
+	__le32 DataOffset;
+	__u8 SetupCount; /* no setup words follow subcommand */
+	/* SNIA spec incorrectly included spurious pad here */
+	__le16 SubCommand; /* 6 = QUERY_SECURITY_DESC */
+	__le16 ByteCount; /* bcc = 3 + 8 */
 	__u8 Pad[3];
-} TRANSACT_IOCTL_RSP;
+	__u16 Fid;
+	__u16 Reserved2;
+	__le32 AclFlags;
+} __attribute__((packed)) QUERY_SEC_DESC_REQ;
 
 typedef struct smb_com_transaction_change_notify_req {
 	struct smb_hdr hdr;     /* wct = 23 */
@@ -961,8 +1202,10 @@
 	__le16 ByteCount;
 /* __u8 Pad[3];*/
 /*	__u8 Data[1];*/
-} TRANSACT_CHANGE_NOTIFY_REQ;
+} __attribute__((packed)) TRANSACT_CHANGE_NOTIFY_REQ;
 
+/* BB eventually change to use generic ntransact rsp struct 
+      and validation routine */
 typedef struct smb_com_transaction_change_notify_rsp {
 	struct smb_hdr hdr;	/* wct = 18 */
 	__u8 Reserved[3];
@@ -977,7 +1220,7 @@
 	__u8 SetupCount;   /* 0 */
 	__u16 ByteCount;
 	/* __u8 Pad[3]; */
-} TRANSACT_CHANGE_NOTIFY_RSP;
+} __attribute__((packed)) TRANSACT_CHANGE_NOTIFY_RSP;
 /* Completion Filter flags for Notify */
 #define FILE_NOTIFY_CHANGE_FILE_NAME    0x00000001
 #define FILE_NOTIFY_CHANGE_DIR_NAME     0x00000002
@@ -1008,7 +1251,7 @@
 	__le32 Action;
 	__le32 FileNameLength;
 	__u8  FileName[0];
-}; 
+} __attribute__((packed)); 
 
 struct reparse_data {
 	__u32	ReparseTag;
@@ -1019,7 +1262,7 @@
 	__u16	TargetNameOffset;
 	__u16	TargetNameLen;
 	char	LinkNamesBuf[1];
-};
+} __attribute__((packed));
 
 struct cifs_quota_data {
 	__u32	rsrvd1;  /* 0 */
@@ -1029,7 +1272,7 @@
 	__u64	soft_limit;
 	__u64	hard_limit;
 	char	sid[1];  /* variable size? */
-};
+} __attribute__((packed));
 
 /* quota sub commands */
 #define QUOTA_LIST_CONTINUE	    0
@@ -1055,12 +1298,12 @@
 	__u8 Reserved3;
 	__le16 SubCommand; /* 1st setup word - SetupCount words follow */
 	__le16 ByteCount;
-};
+} __attribute__((packed));
 
 struct smb_t2_req {
 	struct smb_hdr hdr;
 	struct trans2_req t2_req;
-};
+} __attribute__((packed));
 
 struct trans2_resp {
 	/* struct smb_hdr hdr precedes. Note wct = 10 + setup count */
@@ -1079,12 +1322,12 @@
 	__u16 ByteCount;
 	__u16 Reserved2;*/	
 	/* data area follows */
-};
+} __attribute__((packed));
 
 struct smb_t2_rsp {
 	struct smb_hdr hdr;
 	struct trans2_resp t2_rsp;
-};
+} __attribute__((packed));
 
 /* PathInfo/FileInfo infolevels */
 #define SMB_INFO_STANDARD                   1
@@ -1140,6 +1383,9 @@
 #define SMB_FILE_MAXIMUM_INFO           0x40d
 
 /* Find File infolevels */
+#define SMB_FIND_FILE_INFO_STANDARD       0x001
+#define SMB_FIND_FILE_QUERY_EA_SIZE       0x002
+#define SMB_FIND_FILE_QUERY_EAS_FROM_LIST 0x003
 #define SMB_FIND_FILE_DIRECTORY_INFO      0x101
 #define SMB_FIND_FILE_FULL_DIRECTORY_INFO 0x102
 #define SMB_FIND_FILE_NAMES_INFO          0x103
@@ -1171,14 +1417,14 @@
 	__le16 InformationLevel;
 	__u32 Reserved4;
 	char FileName[1];
-} TRANSACTION2_QPI_REQ;
+} __attribute__((packed)) TRANSACTION2_QPI_REQ;
 
 typedef struct smb_com_transaction2_qpi_rsp {
 	struct smb_hdr hdr;	/* wct = 10 + SetupCount */
 	struct trans2_resp t2;
 	__u16 ByteCount;
 	__u16 Reserved2;	/* parameter word reserved - present for infolevels > 100 */
-} TRANSACTION2_QPI_RSP;
+} __attribute__((packed)) TRANSACTION2_QPI_RSP;
 
 typedef struct smb_com_transaction2_spi_req {
 	struct smb_hdr hdr;	/* wct = 15 */
@@ -1204,21 +1450,21 @@
 	__le16 InformationLevel;
 	__u32 Reserved4;
 	char FileName[1];
-} TRANSACTION2_SPI_REQ;
+} __attribute__((packed)) TRANSACTION2_SPI_REQ;
 
 typedef struct smb_com_transaction2_spi_rsp {
 	struct smb_hdr hdr;	/* wct = 10 + SetupCount */
 	struct trans2_resp t2;
 	__u16 ByteCount;
 	__u16 Reserved2;	/* parameter word reserved - present for infolevels > 100 */
-} TRANSACTION2_SPI_RSP;
+} __attribute__((packed)) TRANSACTION2_SPI_RSP;
 
 struct set_file_rename {
 	__le32 overwrite;   /* 1 = overwrite dest */
 	__u32 root_fid;   /* zero */
 	__le32 target_name_len;
 	char  target_name[0];  /* Must be unicode */
-};
+} __attribute__((packed));
 
 struct smb_com_transaction2_sfi_req {
 	struct smb_hdr hdr;	/* wct = 15 */
@@ -1244,7 +1490,7 @@
 	__u16 Fid;
 	__le16 InformationLevel;
 	__u16 Reserved4;	
-};
+} __attribute__((packed));
 
 struct smb_com_transaction2_sfi_rsp {
 	struct smb_hdr hdr;	/* wct = 10 + SetupCount */
@@ -1252,7 +1498,7 @@
 	__u16 ByteCount;
 	__u16 Reserved2;	/* parameter word reserved - 
 					present for infolevels > 100 */
-};
+} __attribute__((packed));
 
 struct smb_t2_qfi_req {
         struct	smb_hdr hdr;
@@ -1260,7 +1506,7 @@
 	__u8	Pad;
 	__u16	Fid;
 	__le16	InformationLevel;
-};
+} __attribute__((packed));
 
 struct smb_t2_qfi_rsp {
         struct smb_hdr hdr;     /* wct = 10 + SetupCount */
@@ -1268,7 +1514,7 @@
         __u16 ByteCount;
         __u16 Reserved2;        /* parameter word reserved - 
 					present for infolevels > 100 */
-};
+} __attribute__((packed));
 
 /*
  * Flags on T2 FINDFIRST and FINDNEXT 
@@ -1310,13 +1556,13 @@
 	__le16 InformationLevel;
 	__le32 SearchStorageType;
 	char FileName[1];
-} TRANSACTION2_FFIRST_REQ;
+} __attribute__((packed)) TRANSACTION2_FFIRST_REQ;
 
 typedef struct smb_com_transaction2_ffirst_rsp {
 	struct smb_hdr hdr;	/* wct = 10 */
 	struct trans2_resp t2;
 	__u16 ByteCount;
-} TRANSACTION2_FFIRST_RSP;
+} __attribute__((packed)) TRANSACTION2_FFIRST_RSP;
 
 typedef struct smb_com_transaction2_ffirst_rsp_parms {
 	__u16 SearchHandle;
@@ -1324,7 +1570,7 @@
 	__le16 EndofSearch;
 	__le16 EAErrorOffset;
 	__le16 LastNameOffset;
-} T2_FFIRST_RSP_PARMS;
+} __attribute__((packed)) T2_FFIRST_RSP_PARMS;
 
 typedef struct smb_com_transaction2_fnext_req {
 	struct smb_hdr hdr;	/* wct = 15 */
@@ -1352,20 +1598,20 @@
 	__u32 ResumeKey;
 	__le16 SearchFlags;
 	char ResumeFileName[1];
-} TRANSACTION2_FNEXT_REQ;
+} __attribute__((packed)) TRANSACTION2_FNEXT_REQ;
 
 typedef struct smb_com_transaction2_fnext_rsp {
 	struct smb_hdr hdr;	/* wct = 10 */
 	struct trans2_resp t2;
 	__u16 ByteCount;
-} TRANSACTION2_FNEXT_RSP;
+} __attribute__((packed)) TRANSACTION2_FNEXT_RSP;
 
 typedef struct smb_com_transaction2_fnext_rsp_parms {
 	__le16 SearchCount;
 	__le16 EndofSearch;
 	__le16 EAErrorOffset;
 	__le16 LastNameOffset;
-} T2_FNEXT_RSP_PARMS;
+} __attribute__((packed)) T2_FNEXT_RSP_PARMS;
 
 /* QFSInfo Levels */
 #define SMB_INFO_ALLOCATION         1
@@ -1402,14 +1648,51 @@
 	__le16 ByteCount;
 	__u8 Pad;
 	__le16 InformationLevel;
-} TRANSACTION2_QFSI_REQ;
+} __attribute__((packed)) TRANSACTION2_QFSI_REQ;
 
 typedef struct smb_com_transaction_qfsi_rsp {
 	struct smb_hdr hdr;	/* wct = 10 + SetupCount */
 	struct trans2_resp t2;
 	__u16 ByteCount;
 	__u8 Pad;		/* may be three bytes *//* followed by data area */
-} TRANSACTION2_QFSI_RSP;
+} __attribute__((packed)) TRANSACTION2_QFSI_RSP;
+
+
+/* SETFSInfo Levels */
+#define SMB_SET_CIFS_UNIX_INFO    0x200
+typedef struct smb_com_transaction2_setfsi_req {
+	struct smb_hdr hdr;	/* wct = 15 */
+	__le16 TotalParameterCount;
+	__le16 TotalDataCount;
+	__le16 MaxParameterCount;
+	__le16 MaxDataCount;
+	__u8 MaxSetupCount;
+	__u8 Reserved;
+	__le16 Flags;
+	__le32 Timeout;
+	__u16 Reserved2;
+	__le16 ParameterCount;	/* 4 */
+	__le16 ParameterOffset;
+	__le16 DataCount;	/* 12 */
+	__le16 DataOffset;
+	__u8 SetupCount;	/* one */
+	__u8 Reserved3;
+	__le16 SubCommand;	/* TRANS2_SET_FS_INFORMATION */
+	__le16 ByteCount;
+	__u8 Pad;
+	__u16 FileNum;		/* Parameters start. */
+	__le16 InformationLevel;/* Parameters end. */
+	__le16 ClientUnixMajor; /* Data start. */
+	__le16 ClientUnixMinor;
+	__le64 ClientUnixCap;   /* Data end */
+} __attribute__((packed)) TRANSACTION2_SETFSI_REQ;
+
+typedef struct smb_com_transaction2_setfsi_rsp {
+	struct smb_hdr hdr;	/* wct = 10 */
+	struct trans2_resp t2;
+	__u16 ByteCount;
+} __attribute__((packed)) TRANSACTION2_SETFSI_RSP;
+
 
 typedef struct smb_com_transaction2_get_dfs_refer_req {
 	struct smb_hdr hdr;	/* wct = 15 */
@@ -1433,7 +1716,7 @@
 	__u8 Pad[3];		/* Win2K has sent 0x0F01 (max resp length perhaps?) followed by one byte pad - doesn't seem to matter though */
 	__le16 MaxReferralLevel;
 	char RequestFileName[1];
-} TRANSACTION2_GET_DFS_REFER_REQ;
+} __attribute__((packed)) TRANSACTION2_GET_DFS_REFER_REQ;
 
 typedef struct dfs_referral_level_3 {
 	__le16 VersionNumber;
@@ -1445,7 +1728,7 @@
 	__le16 DfsPathOffset;
 	__le16 DfsAlternatePathOffset;
 	__le16 NetworkAddressOffset;
-} REFERRAL3;
+} __attribute__((packed)) REFERRAL3;
 
 typedef struct smb_com_transaction_get_dfs_refer_rsp {
 	struct smb_hdr hdr;	/* wct = 10 */
@@ -1458,7 +1741,7 @@
 	__u16 Pad2;
 	REFERRAL3 referrals[1];	/* array of level 3 dfs_referral structures */
 	/* followed by the strings pointed to by the referral structures */
-} TRANSACTION2_GET_DFS_REFER_RSP;
+} __attribute__((packed)) TRANSACTION2_GET_DFS_REFER_RSP;
 
 /* DFS Flags */
 #define DFSREF_REFERRAL_SERVER  0x0001
@@ -1512,7 +1795,7 @@
 	unsigned char versionMinor;
 	unsigned long type;
 	unsigned int commentOffset;
-};
+} __attribute__((packed));
 
 /*
  * The following structure is the format of the data returned on a NetShareEnum
@@ -1524,39 +1807,61 @@
 	char pad;
 	unsigned short type;
 	unsigned int commentOffset;
-};
+} __attribute__((packed));
 
 struct aliasInfo {
 	char aliasName[9];
 	char pad;
 	unsigned int commentOffset;
 	unsigned char type[2];
-};
+} __attribute__((packed));
 
 struct aliasInfo92 {
 	int aliasNameOffset;
 	int serverNameOffset;
 	int shareNameOffset;
-};
+} __attribute__((packed));
 
 typedef struct {
 	__le64 TotalAllocationUnits;
 	__le64 FreeAllocationUnits;
 	__le32 SectorsPerAllocationUnit;
 	__le32 BytesPerSector;
-} FILE_SYSTEM_INFO;		/* size info, level 0x103 */
+} __attribute__((packed)) FILE_SYSTEM_INFO;		/* size info, level 0x103 */
+
+typedef struct {
+	__le32 fsid;
+	__le32 SectorsPerAllocationUnit;
+	__le32 TotalAllocationUnits;
+	__le32 FreeAllocationUnits;
+	__le16  BytesPerSector;
+} __attribute__((packed)) FILE_SYSTEM_ALLOC_INFO;
 
 typedef struct {
 	__le16 MajorVersionNumber;
 	__le16 MinorVersionNumber;
 	__le64 Capability;
-} FILE_SYSTEM_UNIX_INFO;	/* Unix extensions info, level 0x200 */
+} __attribute__((packed)) FILE_SYSTEM_UNIX_INFO;	/* Unix extensions info, level 0x200 */
+
+/* Version numbers for CIFS UNIX major and minor. */
+#define CIFS_UNIX_MAJOR_VERSION 1
+#define CIFS_UNIX_MINOR_VERSION 0
+
 /* Linux/Unix extensions capability flags */
 #define CIFS_UNIX_FCNTL_CAP             0x00000001 /* support for fcntl locks */
 #define CIFS_UNIX_POSIX_ACL_CAP         0x00000002 /* support getfacl/setfacl */
 #define CIFS_UNIX_XATTR_CAP             0x00000004 /* support new namespace   */
 #define CIFS_UNIX_EXTATTR_CAP           0x00000008 /* support chattr/chflag   */
+#define CIFS_UNIX_POSIX_PATHNAMES_CAP   0x00000010 /* Allow POSIX path chars  */
+#ifdef CONFIG_CIFS_POSIX
+#define CIFS_UNIX_CAP_MASK              0x0000001b
+#else 
+#define CIFS_UNIX_CAP_MASK              0x00000013
+#endif /* CONFIG_CIFS_POSIX */
+
+
 #define CIFS_POSIX_EXTENSIONS           0x00000010 /* support for new QFSInfo */
+
 typedef struct {
 	/* For undefined recommended transfer size return -1 in that field */
 	__le32 OptimalTransferSize;  /* bsize on some os, iosize on other os */
@@ -1577,7 +1882,7 @@
 	__le64 FileSysIdentifier;   /* fsid */
 	/* NB Namelen comes from FILE_SYSTEM_ATTRIBUTE_INFO call */
 	/* NB flags can come from FILE_SYSTEM_DEVICE_INFO call   */
-} FILE_SYSTEM_POSIX_INFO;
+} __attribute__((packed)) FILE_SYSTEM_POSIX_INFO;
 
 /* DeviceType Flags */
 #define FILE_DEVICE_CD_ROM              0x00000002
@@ -1602,14 +1907,14 @@
 typedef struct {
 	__le32 DeviceType;
 	__le32 DeviceCharacteristics;
-} FILE_SYSTEM_DEVICE_INFO;	/* device info, level 0x104 */
+} __attribute__((packed)) FILE_SYSTEM_DEVICE_INFO; /* device info level 0x104 */
 
 typedef struct {
 	__le32 Attributes;
 	__le32 MaxPathNameComponentLength;
 	__le32 FileSystemNameLen;
-	char FileSystemName[52]; /* do not really need to save this - so potentially get only subset of name */
-} FILE_SYSTEM_ATTRIBUTE_INFO;
+	char FileSystemName[52]; /* do not have to save this - get subset? */
+} __attribute__((packed)) FILE_SYSTEM_ATTRIBUTE_INFO;
 
 /******************************************************************************/
 /* QueryFileInfo/QueryPathinfo (also for SetPath/SetFile) data buffer formats */
@@ -1636,7 +1941,7 @@
 	__le32 AlignmentRequirement;
 	__le32 FileNameLength;
 	char FileName[1];
-} FILE_ALL_INFO;		/* level 0x107 QPathInfo */
+} __attribute__((packed)) FILE_ALL_INFO;		/* level 0x107 QPathInfo */
 
 /* defines for enumerating possible values of the Unix type field below */
 #define UNIX_FILE      0
@@ -1660,11 +1965,11 @@
 	__u64 UniqueId;
 	__le64 Permissions;
 	__le64 Nlinks;
-} FILE_UNIX_BASIC_INFO;		/* level 0x200 QPathInfo */
+} __attribute__((packed)) FILE_UNIX_BASIC_INFO;		/* level 0x200 QPathInfo */
 
 typedef struct {
 	char LinkDest[1];
-} FILE_UNIX_LINK_INFO;		/* level 0x201 QPathInfo */
+} __attribute__((packed)) FILE_UNIX_LINK_INFO;		/* level 0x201 QPathInfo */
 
 /* The following three structures are needed only for
 	setting time to NT4 and some older servers via
@@ -1673,13 +1978,13 @@
 	__u16 Day:5;
 	__u16 Month:4;
 	__u16 Year:7;
-} SMB_DATE;
+} __attribute__((packed)) SMB_DATE;
 
 typedef struct {
 	__u16 TwoSeconds:5;
 	__u16 Minutes:6;
 	__u16 Hours:5;
-} SMB_TIME;
+} __attribute__((packed)) SMB_TIME;
 
 typedef struct {
 	__le16 CreationDate; /* SMB Date see above */
@@ -1692,7 +1997,7 @@
 	__le32 AllocationSize;
 	__le16 Attributes; /* verify not u32 */
 	__le32 EASize;
-} FILE_INFO_STANDARD;  /* level 1 SetPath/FileInfo */
+} __attribute__((packed)) FILE_INFO_STANDARD;  /* level 1 SetPath/FileInfo */
 
 typedef struct {
 	__le64 CreationTime;
@@ -1701,19 +2006,20 @@
 	__le64 ChangeTime;
 	__le32 Attributes;
 	__u32 Pad;
-} FILE_BASIC_INFO;		/* size info, level 0x101 */
+} __attribute__((packed)) FILE_BASIC_INFO;		/* size info, level 0x101 */
 
 struct file_allocation_info {
 	__le64 AllocationSize; /* Note old Samba srvr rounds this up too much */
-};	/* size used on disk, level 0x103 for set, 0x105 for query */
+} __attribute__((packed));	/* size used on disk, for level 0x103 for set,
+				   0x105 for query */
 
 struct file_end_of_file_info {
 	__le64 FileSize;		/* offset to end of file */
-};	/* size info, level 0x104 for set, 0x106 for query */
+} __attribute__((packed));	/* size info, level 0x104 for set, 0x106 for query */
 
 struct file_alt_name_info {
 	__u8   alt_name[1];
-};      /* level 0x0108 */
+} __attribute__((packed));      /* level 0x0108 */
 
 struct file_stream_info {
 	__le32 number_of_streams;  /* BB check sizes and verify location */
@@ -1730,7 +2036,7 @@
 	__u8   ch_shift;
 	__u8   cl_shift;
 	__u8   pad[3];
-};      /* level 0x10b */
+} __attribute__((packed));      /* level 0x10b */
 
 /* POSIX ACL set/query path info structures */
 #define CIFS_ACL_VERSION 1
@@ -1738,7 +2044,7 @@
 	__u8  cifs_e_tag;
 	__u8  cifs_e_perm;
 	__le64 cifs_uid; /* or gid */
-}; 
+} __attribute__((packed)); 
 
 struct cifs_posix_acl { /* access conrol list  (ACL) */
 	__le16	version;
@@ -1747,7 +2053,7 @@
 	struct cifs_posix_ace ace_array[0];
 	/* followed by
 	struct cifs_posix_ace default_ace_arraay[] */
-};  /* level 0x204 */
+} __attribute__((packed));  /* level 0x204 */
 
 /* types of access control entries already defined in posix_acl.h */
 /* #define CIFS_POSIX_ACL_USER_OBJ	 0x01
@@ -1766,15 +2072,15 @@
 
 struct file_internal_info {
 	__u64  UniqueId; /* inode number */
-};      /* level 0x3ee */
+} __attribute__((packed));      /* level 0x3ee */
 struct file_mode_info {
 	__le32	Mode;
-};      /* level 0x3f8 */
+} __attribute__((packed));      /* level 0x3f8 */
 
 struct file_attrib_tag {
 	__le32 Attribute;
 	__le32 ReparseTag;
-};      /* level 0x40b */
+} __attribute__((packed));      /* level 0x40b */
 
 
 /********************************************************/
@@ -1798,7 +2104,7 @@
 	__le64 Permissions;
 	__le64 Nlinks;
 	char FileName[1];
-} FILE_UNIX_INFO; /* level 0x202 */
+} __attribute__((packed)) FILE_UNIX_INFO; /* level 0x202 */
 
 typedef struct {
 	__le32 NextEntryOffset;
@@ -1812,7 +2118,7 @@
 	__le32 ExtFileAttributes;
 	__le32 FileNameLength;
 	char FileName[1];
-} FILE_DIRECTORY_INFO;   /* level 0x101 FF response data area */
+} __attribute__((packed)) FILE_DIRECTORY_INFO;   /* level 0x101 FF resp data */
 
 typedef struct {
 	__le32 NextEntryOffset;
@@ -1827,7 +2133,7 @@
 	__le32 FileNameLength;
 	__le32 EaSize; /* length of the xattrs */
 	char FileName[1];
-} FILE_FULL_DIRECTORY_INFO;   /* level 0x102 FF response data area */
+} __attribute__((packed)) FILE_FULL_DIRECTORY_INFO; /* level 0x102 rsp data */
 
 typedef struct {
 	__le32 NextEntryOffset;
@@ -1844,7 +2150,7 @@
 	__le32 Reserved;
 	__u64 UniqueId; /* inode num - le since Samba puts ino in low 32 bit*/
 	char FileName[1];
-} SEARCH_ID_FULL_DIR_INFO;   /* level 0x105 FF response data area */
+} __attribute__((packed)) SEARCH_ID_FULL_DIR_INFO; /* level 0x105 FF rsp data */
 
 typedef struct {
 	__le32 NextEntryOffset;
@@ -1862,18 +2168,39 @@
 	__u8   Reserved;
 	__u8   ShortName[12];
 	char FileName[1];
-} FILE_BOTH_DIRECTORY_INFO;   /* level 0x104 FF response data area */
+} __attribute__((packed)) FILE_BOTH_DIRECTORY_INFO; /* level 0x104 FFrsp data */
+
+typedef struct {
+	__u32  ResumeKey;
+	__le16 CreationDate; /* SMB Date */
+	__le16 CreationTime; /* SMB Time */
+	__le16 LastAccessDate;
+	__le16 LastAccessTime;
+	__le16 LastWriteDate;
+	__le16 LastWriteTime;
+	__le32 DataSize; /* File Size (EOF) */
+	__le32 AllocationSize;
+	__le16 Attributes; /* verify not u32 */
+	__u8   FileNameLength;
+	char FileName[1];
+} __attribute__((packed)) FIND_FILE_STANDARD_INFO; /* level 0x1 FF resp data */
 
 
+struct win_dev {
+	unsigned char type[8]; /* IntxCHR or IntxBLK */
+	__le64 major;
+	__le64 minor;	
+} __attribute__((packed));
+
 struct gea {
 	unsigned char name_len;
 	char name[1];
-};
+} __attribute__((packed));
 
 struct gealist {
 	unsigned long list_len;
 	struct gea list[1];
-};
+} __attribute__((packed));
 
 struct fea {
 	unsigned char EA_flags;
@@ -1881,21 +2208,21 @@
 	__le16 value_len;
 	char name[1];
 	/* optionally followed by value */
-};
+} __attribute__((packed));
 /* flags for _FEA.fEA */
 #define FEA_NEEDEA         0x80	/* need EA bit */
 
 struct fealist {
 	__le32 list_len;
 	struct fea list[1];
-};
+} __attribute__((packed));
 
 /* used to hold an arbitrary blob of data */
 struct data_blob {
 	__u8 *data;
 	size_t length;
 	void (*free) (struct data_blob * data_blob);
-};
+} __attribute__((packed));
 
 
 #ifdef CONFIG_CIFS_POSIX
@@ -1907,18 +2234,17 @@
 	perhaps add a CreateDevice - to create Pipes and other special .inodes
 	Also note POSIX open flags
 	2) Close - to return the last write time to do cache across close more safely
-	3) PosixQFSInfo - to return statfs info
-	4) FindFirst return unique inode number - what about resume key, two forms short (matches readdir) and full (enough info to cache inodes)
-	5) Mkdir - set mode
+	3) FindFirst return unique inode number - what about resume key, two 
+	forms short (matches readdir) and full (enough info to cache inodes)
+	4) Mkdir - set mode
 	
 	And under consideration: 
-	6) FindClose2 (return nanosecond timestamp ??)
-	7) Use nanosecond timestamps throughout all time fields if 
+	5) FindClose2 (return nanosecond timestamp ??)
+	6) Use nanosecond timestamps throughout all time fields if 
 	   corresponding attribute flag is set
-	8) sendfile - handle based copy
-	9) Direct i/o
-	10) "POSIX ACL" support
-	11) Misc fcntls?
+	7) sendfile - handle based copy
+	8) Direct i/o
+	9) Misc fcntls?
 	
 	what about fixing 64 bit alignment
 	
@@ -1974,7 +2300,7 @@
 	
  */
 
-/* xsymlink is a symlink format that can be used
+/* xsymlink is a symlink format (used by MacOS) that can be used
    to save symlink info in a regular file when 
    mounted to operating systems that do not
    support the cifs Unix extensions or EAs (for xattr
@@ -1999,7 +2325,7 @@
 	char cr2;        /* \n */
 /* if room left, then end with \n then 0x20s by convention but not required */
 	char path[1024];  
-};
+} __attribute__((packed));
 
 typedef struct file_xattr_info {
 	/* BB do we need another field for flags? BB */
@@ -2007,7 +2333,7 @@
 	__u32 xattr_value_len;
 	char  xattr_name[0];
 	/* followed by xattr_value[xattr_value_len], no pad */
-} FILE_XATTR_INFO;	/* extended attribute, info level 0x205 */
+} __attribute__((packed)) FILE_XATTR_INFO;	/* extended attribute, info level 0x205 */
 
 
 /* flags for chattr command */
@@ -2033,10 +2359,8 @@
 typedef struct file_chattr_info {
 	__le64	mask; /* list of all possible attribute bits */
 	__le64	mode; /* list of actual attribute bits on this inode */
-} FILE_CHATTR_INFO;  /* ext attributes (chattr, chflags) level 0x206 */
+} __attribute__((packed)) FILE_CHATTR_INFO;  /* ext attributes (chattr, chflags) level 0x206 */
 
 #endif 
 
-#pragma pack()			/* resume default structure packing */
-
 #endif				/* _CIFSPDU_H */
--- linux-2.6.13/fs/cifs/cifsproto.h
+++ linux-2.6.13/fs/cifs/cifsproto.h
@@ -1,7 +1,7 @@
 /*
  *   fs/cifs/cifsproto.h
  *
- *   Copyright (c) International Business Machines  Corp., 2002,2005
+ *   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
@@ -21,9 +21,18 @@
 #ifndef _CIFSPROTO_H
 #define _CIFSPROTO_H
 #include <linux/nls.h>
+#include <linux/version.h>
 
 struct statfs;
 
+#if LINUX_VERSION_CODE < KERNEL_VERSION(2,6,8)
+#define kvec iovec
+#endif
+
+#ifndef msleep
+#define msleep(x) { set_current_state(TASK_UNINTERRUPTIBLE); schedule_timeout(x * HZ / 1000); }
+#endif
+
 /*
  *****************************************************************
  * All Prototypes
@@ -47,24 +56,41 @@
 			struct smb_hdr * /* input */ ,
 			struct smb_hdr * /* out */ ,
 			int * /* bytes returned */ , const int long_op);
+extern int SendReceive2(const unsigned int /* xid */ , struct cifsSesInfo *,
+			struct kvec *, int /* nvec to send */, 
+			int * /* type of buf returned */ , const int long_op);
 extern int checkSMBhdr(struct smb_hdr *smb, __u16 mid);
 extern int checkSMB(struct smb_hdr *smb, __u16 mid, int length);
-extern int is_valid_oplock_break(struct smb_hdr *smb);
+extern int is_valid_oplock_break(struct smb_hdr *smb, struct TCP_Server_Info *);
 extern int is_size_safe_to_change(struct cifsInodeInfo *);
+extern struct cifsFileInfo *find_writable_file(struct cifsInodeInfo *);
 extern unsigned int smbCalcSize(struct smb_hdr *ptr);
+extern unsigned int smbCalcSize_LE(struct smb_hdr *ptr);
 extern int decode_negTokenInit(unsigned char *security_blob, int length,
 			enum securityEnum *secType);
 extern int cifs_inet_pton(int, char * source, void *dst);
 extern int map_smb_to_linux_error(struct smb_hdr *smb);
 extern void header_assemble(struct smb_hdr *, char /* command */ ,
-			const struct cifsTconInfo *, int /* specifies length
-			    of fixed section (word count) in two byte units */
-			);
+			    const struct cifsTconInfo *, int /* length of
+			    fixed section (word count) in two byte units */);
+extern int small_smb_init_no_tc(const int smb_cmd, const int wct,
+				struct cifsSesInfo *ses,
+				void ** request_buf);
+extern int CIFS_SessSetup(unsigned int xid, struct cifsSesInfo *ses,
+			     const int stage, 
+			     const struct nls_table *nls_cp);
+extern __u16 GetNextMid(struct TCP_Server_Info *server);
 extern struct oplock_q_entry * AllocOplockQEntry(struct inode *, u16, 
 						 struct cifsTconInfo *);
 extern void DeleteOplockQEntry(struct oplock_q_entry *);
+#if LINUX_VERSION_CODE > KERNEL_VERSION(2,5,0)
 extern struct timespec cifs_NTtimeToUnix(u64 /* utc nanoseconds since 1601 */ );
 extern u64 cifs_UnixTimeToNT(struct timespec);
+#else
+extern u64 cifs_UnixTimeToNT(time_t);
+extern time_t cifs_NTtimeToUnix(u64 /* utc nanoseconds since 1601 */ );
+#endif
+
 extern int cifs_get_inode_info(struct inode **pinode,
 			const unsigned char *search_path, 
 			FILE_ALL_INFO * pfile_info,
@@ -89,7 +115,8 @@
 
 extern int CIFSFindFirst(const int xid, struct cifsTconInfo *tcon,
             const char *searchName, const struct nls_table *nls_codepage,
-            __u16 *searchHandle, struct cifs_search_info * psrch_inf, int map);
+		__u16 *searchHandle, struct cifs_search_info * psrch_inf, 
+		int map, const char dirsep);
 
 extern int CIFSFindNext(const int xid, struct cifsTconInfo *tcon,
             __u16 searchHandle, struct cifs_search_info * psrch_inf);
@@ -101,6 +128,10 @@
 			const unsigned char *searchName,
 			FILE_ALL_INFO * findData,
 			const struct nls_table *nls_codepage, int remap);
+extern int SMBQueryInformation(const int xid, struct cifsTconInfo *tcon,
+                        const unsigned char *searchName,
+                        FILE_ALL_INFO * findData,
+                        const struct nls_table *nls_codepage, int remap);
 
 extern int CIFSSMBUnixQPathInfo(const int xid,
 			struct cifsTconInfo *tcon,
@@ -123,14 +154,30 @@
 			unsigned int *pnum_referrals, 
 			unsigned char ** preferrals,
 			int remap);
+#if LINUX_VERSION_CODE > KERNEL_VERSION(2, 5, 0)
 extern int CIFSSMBQFSInfo(const int xid, struct cifsTconInfo *tcon,
 			struct kstatfs *FSData);
+extern int SMBOldQFSInfo(const int xid, struct cifsTconInfo *tcon,
+			struct kstatfs *FSData);
+#else
+extern int CIFSSMBQFSInfo(const int xid, struct cifsTconInfo *tcon,
+                        struct statfs *FSData);
+extern int SMBOldQFSInfo(const int xid, struct cifsTconInfo *tcon,
+                        struct statfs *FSData);
+#endif
+extern int CIFSSMBSetFSUnixInfo(const int xid, struct cifsTconInfo *tcon,
+			__u64 cap);
+
 extern int CIFSSMBQFSAttributeInfo(const int xid,
 			struct cifsTconInfo *tcon);
 extern int CIFSSMBQFSDeviceInfo(const int xid, struct cifsTconInfo *tcon);
 extern int CIFSSMBQFSUnixInfo(const int xid, struct cifsTconInfo *tcon);
 extern int CIFSSMBQFSPosixInfo(const int xid, struct cifsTconInfo *tcon,
+#if LINUX_VERSION_CODE > KERNEL_VERSION(2, 5, 0)
 			struct kstatfs *FSData);
+#else
+			struct statfs  *FSData);
+#endif
 
 extern int CIFSSMBSetTimes(const int xid, struct cifsTconInfo *tcon,
 			const char *fileName, const FILE_BASIC_INFO * data,
@@ -207,27 +254,31 @@
 			const int access_flags, const int omode,
 			__u16 * netfid, int *pOplock, FILE_ALL_INFO *,
 			const struct nls_table *nls_codepage, int remap);
+extern int SMBLegacyOpen(const int xid, struct cifsTconInfo *tcon,
+			const char *fileName, const int disposition,
+			const int access_flags, const int omode,
+			__u16 * netfid, int *pOplock, FILE_ALL_INFO *,
+			const struct nls_table *nls_codepage, int remap);
 extern int CIFSSMBClose(const int xid, struct cifsTconInfo *tcon,
 			const int smb_file_id);
 
 extern int CIFSSMBRead(const int xid, struct cifsTconInfo *tcon,
 			const int netfid, unsigned int count,
-			const __u64 lseek, unsigned int *nbytes, char **buf);
+                        const __u64 lseek, unsigned int *nbytes, char **buf,
+			int * return_buf_type);
 extern int CIFSSMBWrite(const int xid, struct cifsTconInfo *tcon,
 			const int netfid, const unsigned int count,
 			const __u64 lseek, unsigned int *nbytes,
 			const char *buf, const char __user *ubuf, 
 			const int long_op);
-#ifdef CONFIG_CIFS_EXPERIMENTAL
 extern int CIFSSMBWrite2(const int xid, struct cifsTconInfo *tcon,
 			const int netfid, const unsigned int count,
 			const __u64 offset, unsigned int *nbytes, 
-			const char __user *buf,const int long_op);
+			struct kvec *iov, const int nvec, const int long_op);
 extern int CIFSGetSrvInodeNumber(const int xid, struct cifsTconInfo *tcon,
 			const unsigned char *searchName, __u64 * inode_number,
 			const struct nls_table *nls_codepage, 
 			int remap_special_chars);
-#endif /* CONFIG_CIFS_EXPERIMENTAL */
 extern int cifs_convertUCSpath(char *target, const __le16 *source, int maxlen,
 			const struct nls_table * codepage);
 extern int cifsConvertToUCS(__le16 * target, const char *source, int maxlen,
@@ -238,7 +289,10 @@
 			const __u64 offset, const __u32 numUnlock,
 			const __u32 numLock, const __u8 lockType,
 			const int waitFlag);
-
+extern int CIFSSMBPosixLock(const int xid, struct cifsTconInfo *tcon,
+			const __u16 smb_file_id, const int get_flag,
+			const __u64 len, struct file_lock *, 
+			const __u16 lock_type, const int waitFlag);
 extern int CIFSSMBTDis(const int xid, struct cifsTconInfo *tcon);
 extern int CIFSSMBLogoff(const int xid, struct cifsSesInfo *ses);
 
@@ -250,11 +304,19 @@
 extern int cifs_reconnect(struct TCP_Server_Info *server);
 
 extern int cifs_sign_smb(struct smb_hdr *, struct TCP_Server_Info *,__u32 *);
+extern int cifs_sign_smb2(struct kvec *iov, int n_vec, struct TCP_Server_Info *,
+			  __u32 *);
 extern int cifs_verify_signature(struct smb_hdr *, const char * mac_key,
 	__u32 expected_sequence_number);
 extern int cifs_calculate_mac_key(char * key,const char * rn,const char * pass);
-extern int CalcNTLMv2_partial_mac_key(struct cifsSesInfo *, struct nls_table *);
-extern void CalcNTLMv2_response(const struct cifsSesInfo *,char * );
+extern int CalcNTLMv2_partial_mac_key(struct cifsSesInfo *, 
+			const struct nls_table *);
+extern void CalcNTLMv2_response(const struct cifsSesInfo *, char * );
+extern void setup_ntlmv2_rsp(struct cifsSesInfo *, char *, 
+			     const struct nls_table *);
+#ifdef CONFIG_CIFS_WEAK_PW_HASH
+extern void calc_lanman_hash(struct cifsSesInfo * ses, char * lnm_session_key);
+#endif /* CIFS_WEAK_PW_HASH */
 extern int CIFSSMBCopy(int xid,
 			struct cifsTconInfo *source_tcon,
 			const char *fromName,
@@ -264,7 +326,8 @@
 			int remap_special_chars);
 extern int CIFSSMBNotify(const int xid, struct cifsTconInfo *tcon, 
 			const int notify_subdirs,const __u16 netfid,
-			__u32 filter, const struct nls_table *nls_codepage);
+			__u32 filter, struct file * file, int multishot, 
+			const struct nls_table *nls_codepage);
 extern ssize_t CIFSSMBQAllEAs(const int xid, struct cifsTconInfo *tcon,
 			const unsigned char *searchName, char * EAData,
 			size_t bufsize, const struct nls_table *nls_codepage,
@@ -277,6 +340,9 @@
 		const char *fileName, const char * ea_name, 
 		const void * ea_value, const __u16 ea_value_len, 
 		const struct nls_table *nls_codepage, int remap_special_chars);
+extern int CIFSSMBGetCIFSACL(const int xid, struct cifsTconInfo *tcon,
+			__u16 fid, char *acl_inf, const int buflen,
+			const int acl_type /* ACCESS vs. DEFAULT */);
 extern int CIFSSMBGetPosixACL(const int xid, struct cifsTconInfo *tcon,
 		const unsigned char *searchName,
 		char *acl_inf, const int buflen,const int acl_type,
@@ -287,4 +353,9 @@
 		const struct nls_table *nls_codepage, int remap_special_chars);
 extern int CIFSGetExtAttr(const int xid, struct cifsTconInfo *tcon,
                 const int netfid, __u64 * pExtAttrBits, __u64 *pMask);
+#if LINUX_VERSION_CODE < KERNEL_VERSION(2, 6, 16)
+#if LINUX_VERSION_CODE != KERNEL_VERSION(2, 6, 9)
+extern void * kzalloc(size_t size, unsigned flgs); /* workaround RHEL4 */
+#endif
+#endif
 #endif			/* _CIFSPROTO_H */
--- linux-2.6.13/fs/cifs/cifssmb.c
+++ linux-2.6.13/fs/cifs/cifssmb.c
@@ -1,7 +1,7 @@
 /*
  *   fs/cifs/cifssmb.c
  *
- *   Copyright (C) International Business Machines  Corp., 2002,2005
+ *   Copyright (C) International Business Machines  Corp., 2002,2006
  *   Author(s): Steve French (sfrench@us.ibm.com)
  *
  *   Contains the routines for constructing the SMB PDUs themselves
@@ -30,21 +30,28 @@
 #include <linux/fs.h>
 #include <linux/kernel.h>
 #include <linux/vfs.h>
+#include <linux/version.h>
+#if LINUX_VERSION_CODE > KERNEL_VERSION(2, 5, 0)
 #include <linux/posix_acl_xattr.h>
+#endif
 #include <asm/uaccess.h>
 #include "cifspdu.h"
 #include "cifsglob.h"
 #include "cifsproto.h"
 #include "cifs_unicode.h"
 #include "cifs_debug.h"
+#include "cifsacl.h"
 
 #ifdef CONFIG_CIFS_POSIX
 static struct {
 	int index;
 	char *name;
 } protocols[] = {
+#ifdef CONFIG_CIFS_WEAK_PW_HASH
+	{LANMAN_PROT, "\2LM1.2X002"},
+#endif /* weak password hashing for legacy clients */
 	{CIFS_PROT, "\2NT LM 0.12"}, 
-	{CIFS_PROT, "\2POSIX 2"},
+	{POSIX_PROT, "\2POSIX 2"},
 	{BAD_PROT, "\2"}
 };
 #else
@@ -52,11 +59,29 @@
 	int index;
 	char *name;
 } protocols[] = {
+#ifdef CONFIG_CIFS_WEAK_PW_HASH
+	{LANMAN_PROT, "\2LM1.2X002"},
+#endif /* weak password hashing for legacy clients */
 	{CIFS_PROT, "\2NT LM 0.12"}, 
 	{BAD_PROT, "\2"}
 };
 #endif
 
+/* define the number of elements in the cifs dialect array */
+#ifdef CONFIG_CIFS_POSIX
+#ifdef CONFIG_CIFS_WEAK_PW_HASH
+#define CIFS_NUM_PROT 3
+#else
+#define CIFS_NUM_PROT 2
+#endif /* CIFS_WEAK_PW_HASH */
+#else /* not posix */
+#ifdef CONFIG_CIFS_WEAK_PW_HASH
+#define CIFS_NUM_PROT 2
+#else
+#define CIFS_NUM_PROT 1
+#endif /* CONFIG_CIFS_WEAK_PW_HASH */
+#endif /* CIFS_POSIX */
+
 
 /* Mark as invalid, all open files on tree connections since they
    were closed when session to server was lost */
@@ -90,6 +115,18 @@
 	   check for tcp and smb session status done differently
 	   for those three - in the calling routine */
 	if(tcon) {
+		if(tcon->tidStatus == CifsExiting) {
+			/* only tree disconnect, open, and write,
+			(and ulogoff which does not have tcon)
+			are allowed as we start force umount */
+			if((smb_command != SMB_COM_WRITE_ANDX) && 
+			   (smb_command != SMB_COM_OPEN_ANDX) && 
+			   (smb_command != SMB_COM_TREE_DISCONNECT)) {
+				cFYI(1,("can not send cmd %d while umounting",
+					smb_command));
+				return -ENODEV;
+			}
+		}
 		if((tcon->ses) && (tcon->ses->status != CifsExiting) &&
 				  (tcon->ses->server)){
 			struct nls_table *nls_codepage;
@@ -97,8 +134,15 @@
 				   reconnect, should be greater than cifs socket
 				   timeout which is 7 seconds */
 			while(tcon->ses->server->tcpStatus == CifsNeedReconnect) {
+#if LINUX_VERSION_CODE < KERNEL_VERSION(2, 5, 0)
+				int timeout = 10 * HZ;
+				while ((tcon->ses->server->tcpStatus != CifsGood) && (timeout > 0)) {
+					timeout = interruptible_sleep_on_timeout(&tcon->ses->server->response_q,timeout);
+				}
+#else
 				wait_event_interruptible_timeout(tcon->ses->server->response_q,
 					(tcon->ses->server->tcpStatus == CifsGood), 10 * HZ);
+#endif
 				if(tcon->ses->server->tcpStatus == CifsNeedReconnect) {
 					/* on "soft" mounts we wait once */
 					if((tcon->retry == FALSE) || 
@@ -125,6 +169,9 @@
 				rc = CIFSTCon(0, tcon->ses, tcon->treeName, tcon
 					, nls_codepage);
 				up(&tcon->ses->sesSem);
+				/* BB FIXME add code to check if wsize needs
+				   update due to negotiated smb buffer size
+				   shrinking */
 				if(rc == 0)
 					atomic_inc(&tconInfoReconnectCount);
 
@@ -166,11 +213,35 @@
 
 	header_assemble((struct smb_hdr *) *request_buf, smb_command, tcon,wct);
 
-#ifdef CONFIG_CIFS_STATS
-        if(tcon != NULL) {
-                atomic_inc(&tcon->num_smbs_sent);
-        }
-#endif /* CONFIG_CIFS_STATS */
+        if(tcon != NULL)
+                cifs_stats_inc(&tcon->num_smbs_sent);
+
+	return rc;
+}
+
+int
+small_smb_init_no_tc(const int smb_command, const int wct, 
+		     struct cifsSesInfo *ses, void **request_buf)
+{
+	int rc;
+	struct smb_hdr * buffer;
+
+	rc = small_smb_init(smb_command, wct, NULL, request_buf);
+	if(rc)
+		return rc;
+
+	buffer = (struct smb_hdr *)*request_buf;
+	buffer->Mid = GetNextMid(ses->server);
+	if (ses->capabilities & CAP_UNICODE)
+		buffer->Flags2 |= SMBFLG2_UNICODE;
+	if (ses->capabilities & CAP_STATUS32)
+		buffer->Flags2 |= SMBFLG2_ERR_STATUS;
+
+	/* uid, tid can stay at zero as set in header assemble */
+
+	/* BB add support for turning on the signing when 
+	this function is used after 1st of session setup requests */
+
 	return rc;
 }  
 
@@ -186,6 +257,19 @@
 	   check for tcp and smb session status done differently
 	   for those three - in the calling routine */
 	if(tcon) {
+		if(tcon->tidStatus == CifsExiting) {
+			/* only tree disconnect, open, and write,
+			  (and ulogoff which does not have tcon)
+			  are allowed as we start force umount */
+			if((smb_command != SMB_COM_WRITE_ANDX) &&
+			   (smb_command != SMB_COM_OPEN_ANDX) &&
+			   (smb_command != SMB_COM_TREE_DISCONNECT)) {
+				cFYI(1,("can not send cmd %d while umounting",
+					smb_command));
+				return -ENODEV;
+			}
+		}
+
 		if((tcon->ses) && (tcon->ses->status != CifsExiting) && 
 				  (tcon->ses->server)){
 			struct nls_table *nls_codepage;
@@ -222,6 +306,9 @@
 				rc = CIFSTCon(0, tcon->ses, tcon->treeName,
 					      tcon, nls_codepage);
 				up(&tcon->ses->sesSem);
+				/* BB FIXME add code to check if wsize needs
+				update due to negotiated smb buffer size
+				shrinking */
 				if(rc == 0)
 					atomic_inc(&tconInfoReconnectCount);
 
@@ -264,16 +351,15 @@
     /* potential retries of smb operations it turns out we can determine */
     /* from the mid flags when the request buffer can be resent without  */
     /* having to use a second distinct buffer for the response */
+	if(response_buf)
 	*response_buf = *request_buf; 
 
 	header_assemble((struct smb_hdr *) *request_buf, smb_command, tcon,
 			wct /*wct */ );
 
-#ifdef CONFIG_CIFS_STATS
-        if(tcon != NULL) {
-                atomic_inc(&tcon->num_smbs_sent);
-        }
-#endif /* CONFIG_CIFS_STATS */
+        if(tcon != NULL)
+                cifs_stats_inc(&tcon->num_smbs_sent);
+
 	return rc;
 }
 
@@ -317,8 +403,10 @@
 	NEGOTIATE_RSP *pSMBr;
 	int rc = 0;
 	int bytes_returned;
+	int i;
 	struct TCP_Server_Info * server;
 	u16 count;
+	unsigned int secFlags;
 
 	if(ses->server)
 		server = ses->server;
@@ -331,44 +419,139 @@
 	if (rc)
 		return rc;
 
+	/* if any of auth flags (ie not sign or seal) are overriden use them */
+	if(ses->overrideSecFlg & (~(CIFSSEC_MUST_SIGN | CIFSSEC_MUST_SEAL)))
+		secFlags = ses->overrideSecFlg;
+	else /* if override flags set only sign/seal OR them with global auth */
+		secFlags = extended_security | ses->overrideSecFlg;
+
+	cFYI(1,("secFlags 0x%x",secFlags));
+
+	pSMB->hdr.Mid = GetNextMid(server);
 	pSMB->hdr.Flags2 |= SMBFLG2_UNICODE;
-	if (extended_security)
+	if((secFlags & CIFSSEC_MUST_KRB5) == CIFSSEC_MUST_KRB5)
 		pSMB->hdr.Flags2 |= SMBFLG2_EXT_SEC;
 
-	count = strlen(protocols[0].name) + 1;
-	strncpy(pSMB->DialectsArray, protocols[0].name, 30);	
-    /* null guaranteed to be at end of source and target buffers anyway */
-
+	count = 0;
+	for(i=0;i<CIFS_NUM_PROT;i++) {
+		strncpy(pSMB->DialectsArray+count, protocols[i].name, 16);
+		count += strlen(protocols[i].name) + 1;
+		/* null at end of source and target buffers anyway */
+	}
 	pSMB->hdr.smb_buf_length += count;
 	pSMB->ByteCount = cpu_to_le16(count);
 
 	rc = SendReceive(xid, ses, (struct smb_hdr *) pSMB,
 			 (struct smb_hdr *) pSMBr, &bytes_returned, 0);
-	if (rc == 0) {
+	if (rc != 0) 
+		goto neg_err_exit;
+
+	cFYI(1,("Dialect: %d", pSMBr->DialectIndex));
+	/* Check wct = 1 error case */
+	if((pSMBr->hdr.WordCount < 13) || (pSMBr->DialectIndex == BAD_PROT)) {
+		/* core returns wct = 1, but we do not ask for core - otherwise
+		small wct just comes when dialect index is -1 indicating we 
+		could not negotiate a common dialect */
+		rc = -EOPNOTSUPP;
+		goto neg_err_exit;
+#ifdef CONFIG_CIFS_WEAK_PW_HASH 
+	} else if((pSMBr->hdr.WordCount == 13)
+			&& (pSMBr->DialectIndex == LANMAN_PROT)) {
+		struct lanman_neg_rsp * rsp = (struct lanman_neg_rsp *)pSMBr;
+
+		if((secFlags & CIFSSEC_MAY_LANMAN) || 
+			(secFlags & CIFSSEC_MAY_PLNTXT))
+			server->secType = LANMAN;
+		else {
+			cERROR(1, ("mount failed weak security disabled"
+				   " in /proc/fs/cifs/SecurityFlags"));
+			rc = -EOPNOTSUPP;
+			goto neg_err_exit;
+		}	
+		server->secMode = (__u8)le16_to_cpu(rsp->SecurityMode);
+		server->maxReq = le16_to_cpu(rsp->MaxMpxCount);
+		server->maxBuf = min((__u32)le16_to_cpu(rsp->MaxBufSize),
+				(__u32)CIFSMaxBufSize + MAX_CIFS_HDR_SIZE);
+		GETU32(server->sessid) = le32_to_cpu(rsp->SessionKey);
+		/* even though we do not use raw we might as well set this
+		accurately, in case we ever find a need for it */
+		if((le16_to_cpu(rsp->RawMode) & RAW_ENABLE) == RAW_ENABLE) {
+			server->maxRw = 0xFF00;
+			server->capabilities = CAP_MPX_MODE | CAP_RAW_MODE;
+		} else {
+			server->maxRw = 0;/* we do not need to use raw anyway */
+			server->capabilities = CAP_MPX_MODE;
+		}
+		server->timeZone = le16_to_cpu(rsp->ServerTimeZone);
+
+		/* BB get server time for time conversions and add
+		code to use it and timezone since this is not UTC */	
+
+		if (rsp->EncryptionKeyLength == CIFS_CRYPTO_KEY_SIZE) {
+			memcpy(server->cryptKey, rsp->EncryptionKey,
+				CIFS_CRYPTO_KEY_SIZE);
+		} else if (server->secMode & SECMODE_PW_ENCRYPT) {
+			rc = -EIO; /* need cryptkey unless plain text */
+			goto neg_err_exit;
+		}
+
+		cFYI(1,("LANMAN negotiated"));
+		/* we will not end up setting signing flags - as no signing
+		was in LANMAN and server did not return the flags on */
+		goto signing_check;
+#else /* weak security disabled */
+	} else if(pSMBr->hdr.WordCount == 13) {
+		cERROR(1,("mount failed, cifs module not built "
+			  "with CIFS_WEAK_PW_HASH support"));
+			rc = -EOPNOTSUPP;
+#endif /* WEAK_PW_HASH */
+		goto neg_err_exit;
+	} else if(pSMBr->hdr.WordCount != 17) {
+		/* unknown wct */
+		rc = -EOPNOTSUPP;
+		goto neg_err_exit;
+	}
+	/* else wct == 17 NTLM */
 		server->secMode = pSMBr->SecurityMode;	
-		server->secType = NTLM; /* BB override default for 
-					   NTLMv2 or kerberos v5 */
-		/* one byte - no need to convert this or EncryptionKeyLen
-		   from little endian */
+	if((server->secMode & SECMODE_USER) == 0)
+		cFYI(1,("share mode security"));
+
+	if((server->secMode & SECMODE_PW_ENCRYPT) == 0)
+#ifdef CONFIG_CIFS_WEAK_PW_HASH
+		if ((secFlags & CIFSSEC_MAY_PLNTXT) == 0)
+#endif /* CIFS_WEAK_PW_HASH */
+			cERROR(1,("Server requests plain text password"
+				  " but client support disabled"));
+
+	if((secFlags & CIFSSEC_MUST_NTLMV2) == CIFSSEC_MUST_NTLMV2)
+		server->secType = NTLMv2;
+	else if(secFlags & CIFSSEC_MAY_NTLM)
+		server->secType = NTLM;
+	else if(secFlags & CIFSSEC_MAY_NTLMV2)
+		server->secType = NTLMv2;
+	/* else krb5 ... any others ... */
+
+	/* one byte, so no need to convert this or EncryptionKeyLen from
+	   little endian */
 		server->maxReq = le16_to_cpu(pSMBr->MaxMpxCount);
 		/* probably no need to store and check maxvcs */
-		server->maxBuf =
-			min(le32_to_cpu(pSMBr->MaxBufferSize),
+	server->maxBuf = min(le32_to_cpu(pSMBr->MaxBufferSize),
 			(__u32) CIFSMaxBufSize + MAX_CIFS_HDR_SIZE);
 		server->maxRw = le32_to_cpu(pSMBr->MaxRawSize);
-		cFYI(0, ("Max buf = %d ", ses->server->maxBuf));
+	cFYI(0, ("Max buf = %d", ses->server->maxBuf));
 		GETU32(ses->server->sessid) = le32_to_cpu(pSMBr->SessionKey);
 		server->capabilities = le32_to_cpu(pSMBr->Capabilities);
 		server->timeZone = le16_to_cpu(pSMBr->ServerTimeZone);	
-        /* BB with UTC do we ever need to be using srvr timezone? */
 		if (pSMBr->EncryptionKeyLength == CIFS_CRYPTO_KEY_SIZE) {
 			memcpy(server->cryptKey, pSMBr->u.EncryptionKey,
 			       CIFS_CRYPTO_KEY_SIZE);
 		} else if ((pSMBr->hdr.Flags2 & SMBFLG2_EXT_SEC)
 			   && (pSMBr->EncryptionKeyLength == 0)) {
 			/* decode security blob */
-		} else
-			rc = -EIO;
+	} else if (server->secMode & SECMODE_PW_ENCRYPT) {
+		rc = -EIO; /* no crypt key only if plain text pwd */
+		goto neg_err_exit;
+	}
 
 		/* BB might be helpful to save off the domain of server here */
 
@@ -380,25 +563,19 @@
 			else if (count == 16) {
 				server->secType = RawNTLMSSP;
 				if (server->socketUseCount.counter > 1) {
-					if (memcmp
-						(server->server_GUID,
+				if (memcmp(server->server_GUID,
 						pSMBr->u.extended_response.
 						GUID, 16) != 0) {
-						cFYI(1,
-						     ("UID of server does not match previous connection to same ip address"));
-						memcpy(server->
-							server_GUID,
-							pSMBr->u.
-							extended_response.
-							GUID, 16);
+					cFYI(1, ("server UID changed"));
+					memcpy(server->server_GUID,
+						pSMBr->u.extended_response.GUID,
+						16);
 					}
 				} else
 					memcpy(server->server_GUID,
-					       pSMBr->u.extended_response.
-					       GUID, 16);
+				       pSMBr->u.extended_response.GUID, 16);
 			} else {
-				rc = decode_negTokenInit(pSMBr->u.
-							 extended_response.
+			rc = decode_negTokenInit(pSMBr->u.extended_response.
 							 SecurityBlob,
 							 count - 16,
 							 &server->secType);
@@ -411,19 +588,30 @@
 			}
 		} else
 			server->capabilities &= ~CAP_EXTENDED_SECURITY;
+
+#ifdef CONFIG_CIFS_WEAK_PW_HASH
+signing_check:
+#endif
 		if(sign_CIFS_PDUs == FALSE) {        
 			if(server->secMode & SECMODE_SIGN_REQUIRED)
-				cERROR(1,
-				 ("Server requires /proc/fs/cifs/PacketSigningEnabled"));
-			server->secMode &= ~(SECMODE_SIGN_ENABLED | SECMODE_SIGN_REQUIRED);
+			cERROR(1,("Server requires "
+				 "/proc/fs/cifs/PacketSigningEnabled to be on"));
+		server->secMode &= 
+			~(SECMODE_SIGN_ENABLED | SECMODE_SIGN_REQUIRED);
 		} else if(sign_CIFS_PDUs == 1) {
 			if((server->secMode & SECMODE_SIGN_REQUIRED) == 0)
-				server->secMode &= ~(SECMODE_SIGN_ENABLED | SECMODE_SIGN_REQUIRED);
+			server->secMode &= 
+				~(SECMODE_SIGN_ENABLED | SECMODE_SIGN_REQUIRED);
+	} else if(sign_CIFS_PDUs == 2) {
+		if((server->secMode & 
+			(SECMODE_SIGN_ENABLED | SECMODE_SIGN_REQUIRED)) == 0) {
+			cERROR(1,("signing required but server lacks support"));
 		}
-				
 	}
-	if (pSMB)
+neg_err_exit:	
 		cifs_buf_release(pSMB);
+
+	cFYI(1,("negprot rc %d",rc));
 	return rc;
 }
 
@@ -518,6 +706,8 @@
 	smb_buffer_response = (struct smb_hdr *)pSMB; /* BB removeme BB */
 	
 	if(ses->server) {
+		pSMB->hdr.Mid = GetNextMid(ses->server);
+
 		if(ses->server->secMode & 
 		   (SECMODE_SIGN_REQUIRED | SECMODE_SIGN_ENABLED))
 			pSMB->hdr.Flags2 |= SMBFLG2_SECURITY_SIGNATURE;
@@ -537,9 +727,8 @@
 			rc = -ESHUTDOWN;
 		}
 	}
-	if (pSMB)
-		cifs_small_buf_release(pSMB);
 	up(&ses->sesSem);
+	cifs_small_buf_release(pSMB);
 
 	/* if session dead then we do not need to do ulogoff,
 		since server closed smb session, no sense reporting 
@@ -583,14 +772,10 @@
 	pSMB->ByteCount = cpu_to_le16(name_len + 1);
 	rc = SendReceive(xid, tcon->ses, (struct smb_hdr *) pSMB,
 			 (struct smb_hdr *) pSMBr, &bytes_returned, 0);
+	cifs_stats_inc(&tcon->num_deletes);
 	if (rc) {
 		cFYI(1, ("Error in RMFile = %d", rc));
 	} 
-#ifdef CONFIG_CIFS_STATS
-        else {
-		atomic_inc(&tcon->num_deletes);
-        }
-#endif
 
 	cifs_buf_release(pSMB);
 	if (rc == -EAGAIN)
@@ -632,14 +817,10 @@
 	pSMB->ByteCount = cpu_to_le16(name_len + 1);
 	rc = SendReceive(xid, tcon->ses, (struct smb_hdr *) pSMB,
 			 (struct smb_hdr *) pSMBr, &bytes_returned, 0);
+	cifs_stats_inc(&tcon->num_rmdirs);
 	if (rc) {
 		cFYI(1, ("Error in RMDir = %d", rc));
 	}
-#ifdef CONFIG_CIFS_STATS
-        else {
-		atomic_inc(&tcon->num_rmdirs);
-        }
-#endif
 
 	cifs_buf_release(pSMB);
 	if (rc == -EAGAIN)
@@ -680,20 +861,161 @@
 	pSMB->ByteCount = cpu_to_le16(name_len + 1);
 	rc = SendReceive(xid, tcon->ses, (struct smb_hdr *) pSMB,
 			 (struct smb_hdr *) pSMBr, &bytes_returned, 0);
+	cifs_stats_inc(&tcon->num_mkdirs);
 	if (rc) {
 		cFYI(1, ("Error in Mkdir = %d", rc));
 	}
-#ifdef CONFIG_CIFS_STATS
-        else {
-		atomic_inc(&tcon->num_mkdirs);
-        }
-#endif
+
 	cifs_buf_release(pSMB);
 	if (rc == -EAGAIN)
 		goto MkDirRetry;
 	return rc;
 }
 
+static __u16 convert_disposition(int disposition)
+{
+	__u16 ofun = 0;
+
+	switch (disposition) {
+		case FILE_SUPERSEDE:
+			ofun = SMBOPEN_OCREATE | SMBOPEN_OTRUNC;
+			break;
+		case FILE_OPEN:
+			ofun = SMBOPEN_OAPPEND;
+			break;
+		case FILE_CREATE:
+			ofun = SMBOPEN_OCREATE;
+			break;
+		case FILE_OPEN_IF:
+			ofun = SMBOPEN_OCREATE | SMBOPEN_OAPPEND;
+			break;
+		case FILE_OVERWRITE:
+			ofun = SMBOPEN_OTRUNC;
+			break;
+		case FILE_OVERWRITE_IF:
+			ofun = SMBOPEN_OCREATE | SMBOPEN_OTRUNC;
+			break;
+		default:
+			cFYI(1,("unknown disposition %d",disposition));
+			ofun =  SMBOPEN_OAPPEND; /* regular open */
+	}
+	return ofun;
+}
+
+int
+SMBLegacyOpen(const int xid, struct cifsTconInfo *tcon,
+	    const char *fileName, const int openDisposition,
+	    const int access_flags, const int create_options, __u16 * netfid,
+            int *pOplock, FILE_ALL_INFO * pfile_info,
+	    const struct nls_table *nls_codepage, int remap)
+{
+	int rc = -EACCES;
+	OPENX_REQ *pSMB = NULL;
+	OPENX_RSP *pSMBr = NULL;
+	int bytes_returned;
+	int name_len;
+	__u16 count;
+
+OldOpenRetry:
+	rc = smb_init(SMB_COM_OPEN_ANDX, 15, tcon, (void **) &pSMB,
+		      (void **) &pSMBr);
+	if (rc)
+		return rc;
+
+	pSMB->AndXCommand = 0xFF;       /* none */
+
+	if (pSMB->hdr.Flags2 & SMBFLG2_UNICODE) {
+		count = 1;      /* account for one byte pad to word boundary */
+		name_len =
+		   cifsConvertToUCS((__le16 *) (pSMB->fileName + 1),
+				    fileName, PATH_MAX, nls_codepage, remap);
+		name_len++;     /* trailing null */
+		name_len *= 2;
+	} else {                /* BB improve check for buffer overruns BB */
+		count = 0;      /* no pad */
+		name_len = strnlen(fileName, PATH_MAX);
+		name_len++;     /* trailing null */
+		strncpy(pSMB->fileName, fileName, name_len);
+	}
+	if (*pOplock & REQ_OPLOCK)
+		pSMB->OpenFlags = cpu_to_le16(REQ_OPLOCK);
+	else if (*pOplock & REQ_BATCHOPLOCK) {
+		pSMB->OpenFlags = cpu_to_le16(REQ_BATCHOPLOCK);
+	}
+	pSMB->OpenFlags |= cpu_to_le16(REQ_MORE_INFO);
+	/* BB fixme add conversion for access_flags to bits 0 - 2 of mode */
+	/* 0 = read
+	   1 = write
+	   2 = rw
+	   3 = execute
+        */
+	pSMB->Mode = cpu_to_le16(2);
+	pSMB->Mode |= cpu_to_le16(0x40); /* deny none */
+	/* set file as system file if special file such
+	   as fifo and server expecting SFU style and
+	   no Unix extensions */
+
+        if(create_options & CREATE_OPTION_SPECIAL)
+                pSMB->FileAttributes = cpu_to_le16(ATTR_SYSTEM);
+        else
+                pSMB->FileAttributes = cpu_to_le16(0/*ATTR_NORMAL*/); /* BB FIXME */
+
+	/* if ((omode & S_IWUGO) == 0)
+		pSMB->FileAttributes |= cpu_to_le32(ATTR_READONLY);*/
+	/*  Above line causes problems due to vfs splitting create into two
+	    pieces - need to set mode after file created not while it is
+	    being created */
+
+	/* BB FIXME BB */
+/*	pSMB->CreateOptions = cpu_to_le32(create_options & CREATE_OPTIONS_MASK); */
+	/* BB FIXME END BB */
+
+	pSMB->Sattr = cpu_to_le16(ATTR_HIDDEN | ATTR_SYSTEM | ATTR_DIRECTORY);
+	pSMB->OpenFunction = cpu_to_le16(convert_disposition(openDisposition));
+	count += name_len;
+	pSMB->hdr.smb_buf_length += count;
+
+	pSMB->ByteCount = cpu_to_le16(count);
+	/* long_op set to 1 to allow for oplock break timeouts */
+	rc = SendReceive(xid, tcon->ses, (struct smb_hdr *) pSMB,
+		         (struct smb_hdr *) pSMBr, &bytes_returned, 1);
+	cifs_stats_inc(&tcon->num_opens);
+	if (rc) {
+		cFYI(1, ("Error in Open = %d", rc));
+	} else {
+	/* BB verify if wct == 15 */
+
+/*		*pOplock = pSMBr->OplockLevel; */  /* BB take from action field BB */
+
+		*netfid = pSMBr->Fid;   /* cifs fid stays in le */
+		/* Let caller know file was created so we can set the mode. */
+		/* Do we care about the CreateAction in any other cases? */
+	/* BB FIXME BB */
+/*		if(cpu_to_le32(FILE_CREATE) == pSMBr->CreateAction)
+			*pOplock |= CIFS_CREATE_ACTION; */
+	/* BB FIXME END */
+
+		if(pfile_info) {
+			pfile_info->CreationTime = 0; /* BB convert CreateTime*/
+			pfile_info->LastAccessTime = 0; /* BB fixme */
+			pfile_info->LastWriteTime = 0; /* BB fixme */
+			pfile_info->ChangeTime = 0;  /* BB fixme */
+			pfile_info->Attributes =
+				cpu_to_le32(le16_to_cpu(pSMBr->FileAttributes)); 
+			/* the file_info buf is endian converted by caller */
+			pfile_info->AllocationSize =
+				cpu_to_le64(le32_to_cpu(pSMBr->EndOfFile));
+			pfile_info->EndOfFile = pfile_info->AllocationSize;
+			pfile_info->NumberOfLinks = cpu_to_le32(1);
+		}
+	}
+
+	cifs_buf_release(pSMB);
+	if (rc == -EAGAIN)
+		goto OldOpenRetry;
+	return rc;
+}
+
 int
 CIFSSMBOpen(const int xid, struct cifsTconInfo *tcon,
 	    const char *fileName, const int openDisposition,
@@ -738,6 +1060,12 @@
 	}
 	pSMB->DesiredAccess = cpu_to_le32(access_flags);
 	pSMB->AllocationSize = 0;
+	/* set file as system file if special file such
+	   as fifo and server expecting SFU style and
+	   no Unix extensions */
+	if(create_options & CREATE_OPTION_SPECIAL)
+		pSMB->FileAttributes = cpu_to_le32(ATTR_SYSTEM);
+	else
 	pSMB->FileAttributes = cpu_to_le32(ATTR_NORMAL);
 	/* XP does not handle ATTR_POSIX_SEMANTICS */
 	/* but it helps speed up case sensitive checks for other
@@ -752,7 +1080,7 @@
 		being created */
 	pSMB->ShareAccess = cpu_to_le32(FILE_SHARE_ALL);
 	pSMB->CreateDisposition = cpu_to_le32(openDisposition);
-	pSMB->CreateOptions = cpu_to_le32(create_options);
+	pSMB->CreateOptions = cpu_to_le32(create_options & CREATE_OPTIONS_MASK);
 	/* BB Expirement with various impersonation levels and verify */
 	pSMB->ImpersonationLevel = cpu_to_le32(SECURITY_IMPERSONATION);
 	pSMB->SecurityFlags =
@@ -765,6 +1093,7 @@
 	/* long_op set to 1 to allow for oplock break timeouts */
 	rc = SendReceive(xid, tcon->ses, (struct smb_hdr *) pSMB,
 			 (struct smb_hdr *) pSMBr, &bytes_returned, 1);
+	cifs_stats_inc(&tcon->num_opens);
 	if (rc) {
 		cFYI(1, ("Error in Open = %d", rc));
 	} else {
@@ -782,37 +1111,36 @@
 		    pfile_info->EndOfFile = pSMBr->EndOfFile;
 		    pfile_info->NumberOfLinks = cpu_to_le32(1);
 		}
-
-#ifdef CONFIG_CIFS_STATS
-		atomic_inc(&tcon->num_opens);
-#endif
 	}
+
 	cifs_buf_release(pSMB);
 	if (rc == -EAGAIN)
 		goto openRetry;
 	return rc;
 }
 
-/* If no buffer passed in, then caller wants to do the copy
-	as in the case of readpages so the SMB buffer must be
-	freed by the caller */
-
 int
 CIFSSMBRead(const int xid, struct cifsTconInfo *tcon,
 	    const int netfid, const unsigned int count,
-	    const __u64 lseek, unsigned int *nbytes, char **buf)
+            const __u64 lseek, unsigned int *nbytes, char **buf,
+	    int * pbuf_type)
 {
 	int rc = -EACCES;
 	READ_REQ *pSMB = NULL;
 	READ_RSP *pSMBr = NULL;
 	char *pReadData = NULL;
-	int bytes_returned;
+	int wct;
+	int resp_buf_type = 0;
+	struct kvec iov[1];
 
 	cFYI(1,("Reading %d bytes on fid %d",count,netfid));
+	if(tcon->ses->capabilities & CAP_LARGE_FILES)
+		wct = 12;
+	else
+		wct = 10; /* old style read */
 
 	*nbytes = 0;
-	rc = smb_init(SMB_COM_READ_ANDX, 12, tcon, (void **) &pSMB,
-		      (void **) &pSMBr);
+	rc = small_smb_init(SMB_COM_READ_ANDX, wct, tcon, (void **) &pSMB);
 	if (rc)
 		return rc;
 
@@ -823,14 +1151,30 @@
 	pSMB->AndXCommand = 0xFF;	/* none */
 	pSMB->Fid = netfid;
 	pSMB->OffsetLow = cpu_to_le32(lseek & 0xFFFFFFFF);
+	if(wct == 12)
 	pSMB->OffsetHigh = cpu_to_le32(lseek >> 32);
+	else if((lseek >> 32) > 0) /* can not handle this big offset for old */
+		return -EIO;
+
 	pSMB->Remaining = 0;
 	pSMB->MaxCount = cpu_to_le16(count & 0xFFFF);
 	pSMB->MaxCountHigh = cpu_to_le32(count >> 16);
-	pSMB->ByteCount = 0;  /* no need to do le conversion since it is 0 */
+	if(wct == 12)
+		pSMB->ByteCount = 0;  /* no need to do le conversion since 0 */
+	else {
+		/* old style read */
+		struct smb_com_readx_req * pSMBW =
+			(struct smb_com_readx_req *)pSMB;
+		pSMBW->ByteCount = 0;
+	}
 
-	rc = SendReceive(xid, tcon->ses, (struct smb_hdr *) pSMB,
-			 (struct smb_hdr *) pSMBr, &bytes_returned, 0);
+	iov[0].iov_base = (char *)pSMB;
+	iov[0].iov_len = pSMB->hdr.smb_buf_length + 4;
+	rc = SendReceive2(xid, tcon->ses, iov, 
+			  1 /* num iovecs */,
+			  &resp_buf_type, 0); 
+	cifs_stats_inc(&tcon->num_reads);
+	pSMBr = (READ_RSP *)iov[0].iov_base;
 	if (rc) {
 		cERROR(1, ("Send error in read = %d", rc));
 	} else {
@@ -846,8 +1190,7 @@
 			rc = -EIO;
 			*nbytes = 0;
 		} else {
-			pReadData =
-			    (char *) (&pSMBr->hdr.Protocol) +
+			pReadData = (char *) (&pSMBr->hdr.Protocol) +
 			    le16_to_cpu(pSMBr->DataOffset);
 /*			if(rc = copy_to_user(buf, pReadData, data_length)) {
 				cERROR(1,("Faulting on read rc = %d",rc));
@@ -857,16 +1200,28 @@
 			    memcpy(*buf,pReadData,data_length);
 		}
 	}
-	if(*buf)
-		cifs_buf_release(pSMB);
-	else
-		*buf = (char *)pSMB;
+
+/*	cifs_small_buf_release(pSMB); */ /* Freed earlier now in SendReceive2 */
+	if(*buf) {
+		if(resp_buf_type == CIFS_SMALL_BUFFER)
+			cifs_small_buf_release(iov[0].iov_base);
+		else if(resp_buf_type == CIFS_LARGE_BUFFER)
+			cifs_buf_release(iov[0].iov_base);
+	} else if(resp_buf_type != CIFS_NO_BUFFER) {
+		/* return buffer to caller to free */ 
+		*buf = iov[0].iov_base;		
+		if(resp_buf_type == CIFS_SMALL_BUFFER)
+			*pbuf_type = CIFS_SMALL_BUFFER;
+		else if(resp_buf_type == CIFS_LARGE_BUFFER)
+			*pbuf_type = CIFS_LARGE_BUFFER;
+	} /* else no valid buffer on return - leave as null */
 
 	/* Note: On -EAGAIN error only caller can retry on handle based calls 
 		since file handle passed in no longer valid */
 	return rc;
 }
 
+
 int
 CIFSSMBWrite(const int xid, struct cifsTconInfo *tcon,
 	     const int netfid, const unsigned int count,
@@ -876,12 +1231,20 @@
 	int rc = -EACCES;
 	WRITE_REQ *pSMB = NULL;
 	WRITE_RSP *pSMBr = NULL;
-	int bytes_returned;
+	int bytes_returned, wct;
 	__u32 bytes_sent;
 	__u16 byte_count;
 
 	/* cFYI(1,("write at %lld %d bytes",offset,count));*/
-	rc = smb_init(SMB_COM_WRITE_ANDX, 14, tcon, (void **) &pSMB,
+	if(tcon->ses == NULL)
+		return -ECONNABORTED;
+
+	if(tcon->ses->capabilities & CAP_LARGE_FILES)
+		wct = 14;
+	else
+		wct = 12;
+
+	rc = smb_init(SMB_COM_WRITE_ANDX, wct, tcon, (void **) &pSMB,
 		      (void **) &pSMBr);
 	if (rc)
 		return rc;
@@ -892,7 +1255,11 @@
 	pSMB->AndXCommand = 0xFF;	/* none */
 	pSMB->Fid = netfid;
 	pSMB->OffsetLow = cpu_to_le32(offset & 0xFFFFFFFF);
+	if(wct == 14) 
 	pSMB->OffsetHigh = cpu_to_le32(offset >> 32);
+	else if((offset >> 32) > 0) /* can not handle this big offset for old */
+		return -EIO;
+	
 	pSMB->Reserved = 0xFFFFFFFF;
 	pSMB->WriteMode = 0;
 	pSMB->Remaining = 0;
@@ -919,20 +1286,31 @@
 			cifs_buf_release(pSMB);
 			return -EFAULT;
 		}
-	} else {
+	} else if (count != 0) {
 		/* No buffer */
 		cifs_buf_release(pSMB);
 		return -EINVAL;
+	} /* else setting file size with write of zero bytes */
+	if(wct == 14)
+		byte_count = bytes_sent + 1; /* pad */
+	else /* wct == 12 */ {
+		byte_count = bytes_sent + 5; /* bigger pad, smaller smb hdr */
 	}
-
-	byte_count = bytes_sent + 1 /* pad */ ; /* BB fix this for sends > 64K */
 	pSMB->DataLengthLow = cpu_to_le16(bytes_sent & 0xFFFF);
 	pSMB->DataLengthHigh = cpu_to_le16(bytes_sent >> 16);
-	pSMB->hdr.smb_buf_length += bytes_sent+1;
+	pSMB->hdr.smb_buf_length += byte_count;
+
+	if(wct == 14)
 	pSMB->ByteCount = cpu_to_le16(byte_count);
+	else { /* old style write has byte count 4 bytes earlier so 4 bytes pad  */
+		struct smb_com_writex_req * pSMBW = 
+			(struct smb_com_writex_req *)pSMB;
+		pSMBW->ByteCount = cpu_to_le16(byte_count);
+	}
 
 	rc = SendReceive(xid, tcon->ses, (struct smb_hdr *) pSMB,
 			 (struct smb_hdr *) pSMBr, &bytes_returned, long_op);
+	cifs_stats_inc(&tcon->num_writes);
 	if (rc) {
 		cFYI(1, ("Send error in write = %d", rc));
 		*nbytes = 0;
@@ -950,26 +1328,27 @@
 	return rc;
 }
 
-#ifdef CONFIG_CIFS_EXPERIMENTAL
-int CIFSSMBWrite2(const int xid, struct cifsTconInfo *tcon,
+int
+CIFSSMBWrite2(const int xid, struct cifsTconInfo *tcon,
 	     const int netfid, const unsigned int count,
-	     const __u64 offset, unsigned int *nbytes, const char __user *buf,
-	     const int long_op)
+	     const __u64 offset, unsigned int *nbytes, struct kvec *iov,
+	     int n_vec, const int long_op)
 {
 	int rc = -EACCES;
 	WRITE_REQ *pSMB = NULL;
-	WRITE_RSP *pSMBr = NULL;
-	/*int bytes_returned;*/
-	unsigned bytes_sent;
-	__u16 byte_count;
+	int wct;
+	int smb_hdr_len;
+	int resp_buf_type = 0;
 
-	rc = small_smb_init(SMB_COM_WRITE_ANDX, 14, tcon, (void **) &pSMB);
+	cFYI(1,("write2 at %lld %d bytes", (long long)offset, count));
     
+	if(tcon->ses->capabilities & CAP_LARGE_FILES)
+		wct = 14;
+	else
+		wct = 12;
+	rc = small_smb_init(SMB_COM_WRITE_ANDX, wct, tcon, (void **) &pSMB);
 	if (rc)
 		return rc;
-	
-	pSMBr = (WRITE_RSP *)pSMB; /* BB removeme BB */
-
 	/* tcon and ses pointer are checked in smb_init */
 	if (tcon->ses->server == NULL)
 		return -ECONNABORTED;
@@ -977,39 +1356,67 @@
 	pSMB->AndXCommand = 0xFF; /* none */
 	pSMB->Fid = netfid;
 	pSMB->OffsetLow = cpu_to_le32(offset & 0xFFFFFFFF);
+	if(wct == 14)
 	pSMB->OffsetHigh = cpu_to_le32(offset >> 32);
+	else if((offset >> 32) > 0) /* can not handle this big offset for old */
+		return -EIO;
 	pSMB->Reserved = 0xFFFFFFFF;
 	pSMB->WriteMode = 0;
 	pSMB->Remaining = 0;
-	bytes_sent = (tcon->ses->server->maxBuf - MAX_CIFS_HDR_SIZE) & ~0xFF;
-	if (bytes_sent > count)
-		bytes_sent = count;
-	pSMB->DataLengthHigh = 0;
+
 	pSMB->DataOffset =
 	    cpu_to_le16(offsetof(struct smb_com_write_req,Data) - 4);
 
-	byte_count = bytes_sent + 1 /* pad */ ;
-	pSMB->DataLengthLow = cpu_to_le16(bytes_sent);
-	pSMB->DataLengthHigh = 0;
-	pSMB->hdr.smb_buf_length += byte_count;
-	pSMB->ByteCount = cpu_to_le16(byte_count);
-
-/*	rc = SendReceive2(xid, tcon->ses, (struct smb_hdr *) pSMB,
-			 (struct smb_hdr *) pSMBr, buf, buflen, &bytes_returned, long_op); */  /* BB fixme BB */
+	pSMB->DataLengthLow = cpu_to_le16(count & 0xFFFF);
+	pSMB->DataLengthHigh = cpu_to_le16(count >> 16);
+	smb_hdr_len = pSMB->hdr.smb_buf_length + 1; /* hdr + 1 byte pad */
+	if(wct == 14)
+		pSMB->hdr.smb_buf_length += count+1;
+	else /* wct == 12 */
+		pSMB->hdr.smb_buf_length += count+5; /* smb data starts later */ 
+	if(wct == 14)
+		pSMB->ByteCount = cpu_to_le16(count + 1);
+	else /* wct == 12 */ /* bigger pad, smaller smb hdr, keep offset ok */ {
+		struct smb_com_writex_req * pSMBW =
+				(struct smb_com_writex_req *)pSMB;
+		pSMBW->ByteCount = cpu_to_le16(count + 5);
+	}
+	iov[0].iov_base = pSMB;
+	if(wct == 14)
+		iov[0].iov_len = smb_hdr_len + 4;
+	else /* wct == 12 pad bigger by four bytes */
+		iov[0].iov_len = smb_hdr_len + 8;
+	
+
+	rc = SendReceive2(xid, tcon->ses, iov, n_vec + 1, &resp_buf_type,
+			  long_op);
+	cifs_stats_inc(&tcon->num_writes);
 	if (rc) {
-		cFYI(1, ("Send error in write2 (large write) = %d", rc));
+		cFYI(1, ("Send error Write2 = %d", rc));
 		*nbytes = 0;
-	} else
-		*nbytes = le16_to_cpu(pSMBr->Count);
+	} else if(resp_buf_type == 0) {
+		/* presumably this can not happen, but best to be safe */
+		rc = -EIO;
+		*nbytes = 0;
+	} else {
+		WRITE_RSP * pSMBr = (WRITE_RSP *)iov[0].iov_base;
+		*nbytes = le16_to_cpu(pSMBr->CountHigh);
+		*nbytes = (*nbytes) << 16;
+		*nbytes += le16_to_cpu(pSMBr->Count);
+	} 
 
-	cifs_small_buf_release(pSMB);
+/*	cifs_small_buf_release(pSMB); */ /* Freed earlier now in SendReceive2 */
+	if(resp_buf_type == CIFS_SMALL_BUFFER)
+		cifs_small_buf_release(iov[0].iov_base);
+	else if(resp_buf_type == CIFS_LARGE_BUFFER)
+		cifs_buf_release(iov[0].iov_base);
 
 	/* Note: On -EAGAIN error only caller can retry on handle based calls 
 		since file handle passed in no longer valid */
 
 	return rc;
 }
-#endif /* CIFS_EXPERIMENTAL */
+
 
 int
 CIFSSMBLock(const int xid, struct cifsTconInfo *tcon,
@@ -1065,7 +1472,7 @@
 
 	rc = SendReceive(xid, tcon->ses, (struct smb_hdr *) pSMB,
 			 (struct smb_hdr *) pSMBr, &bytes_returned, timeout);
-
+	cifs_stats_inc(&tcon->num_locks);
 	if (rc) {
 		cFYI(1, ("Send error in Lock = %d", rc));
 	}
@@ -1077,6 +1484,120 @@
 }
 
 int
+CIFSSMBPosixLock(const int xid, struct cifsTconInfo *tcon,
+		const __u16 smb_file_id, const int get_flag, const __u64 len,
+		struct file_lock *pLockData, const __u16 lock_type, 
+		const int waitFlag)
+{
+	struct smb_com_transaction2_sfi_req *pSMB  = NULL;
+	struct smb_com_transaction2_sfi_rsp *pSMBr = NULL;
+	char *data_offset;
+	struct cifs_posix_lock *parm_data;
+	int rc = 0;
+	int timeout = 0;
+	int bytes_returned = 0;
+	__u16 params, param_offset, offset, byte_count, count;
+
+	cFYI(1, ("Posix Lock"));
+
+	if(pLockData == NULL)
+		return EINVAL;
+
+	rc = small_smb_init(SMB_COM_TRANSACTION2, 15, tcon, (void **) &pSMB);
+
+	if (rc)
+		return rc;
+
+	pSMBr = (struct smb_com_transaction2_sfi_rsp *)pSMB;
+
+	params = 6; 
+	pSMB->MaxSetupCount = 0;
+	pSMB->Reserved = 0;
+	pSMB->Flags = 0;
+	pSMB->Reserved2 = 0;
+	param_offset = offsetof(struct smb_com_transaction2_sfi_req, Fid) - 4;
+	offset = param_offset + params;
+
+	data_offset = (char *) (&pSMB->hdr.Protocol) + offset;
+
+	count = sizeof(struct cifs_posix_lock);
+	pSMB->MaxParameterCount = cpu_to_le16(2);
+	pSMB->MaxDataCount = cpu_to_le16(1000); /* BB find max SMB PDU from sess */
+	pSMB->SetupCount = 1;
+	pSMB->Reserved3 = 0;
+	if(get_flag)
+		pSMB->SubCommand = cpu_to_le16(TRANS2_QUERY_FILE_INFORMATION);
+	else
+		pSMB->SubCommand = cpu_to_le16(TRANS2_SET_FILE_INFORMATION);
+	byte_count = 3 /* pad */  + params + count;
+	pSMB->DataCount = cpu_to_le16(count);
+	pSMB->ParameterCount = cpu_to_le16(params);
+	pSMB->TotalDataCount = pSMB->DataCount;
+	pSMB->TotalParameterCount = pSMB->ParameterCount;
+	pSMB->ParameterOffset = cpu_to_le16(param_offset);
+	parm_data = (struct cifs_posix_lock *) 
+			(((char *) &pSMB->hdr.Protocol) + offset);
+
+	parm_data->lock_type = cpu_to_le16(lock_type);
+	if(waitFlag) {
+		timeout = 3;  /* blocking operation, no timeout */
+		parm_data->lock_flags = cpu_to_le16(1);
+		pSMB->Timeout = cpu_to_le32(-1);
+	} else
+		pSMB->Timeout = 0;
+
+	parm_data->pid = cpu_to_le32(current->tgid);
+	parm_data->start = cpu_to_le64(pLockData->fl_start);
+	parm_data->length = cpu_to_le64(len);  /* normalize negative numbers */
+
+	pSMB->DataOffset = cpu_to_le16(offset);
+	pSMB->Fid = smb_file_id;
+	pSMB->InformationLevel = cpu_to_le16(SMB_SET_POSIX_LOCK);
+	pSMB->Reserved4 = 0;
+	pSMB->hdr.smb_buf_length += byte_count;
+	pSMB->ByteCount = cpu_to_le16(byte_count);
+	rc = SendReceive(xid, tcon->ses, (struct smb_hdr *) pSMB,
+			(struct smb_hdr *) pSMBr, &bytes_returned, timeout);
+	if (rc) {
+		cFYI(1, ("Send error in Posix Lock = %d", rc));
+	} else if (get_flag) {
+		/* lock structure can be returned on get */
+		__u16 data_offset;
+		__u16 data_count;
+		rc = validate_t2((struct smb_t2_rsp *)pSMBr);
+
+		if (rc || (pSMBr->ByteCount < sizeof(struct cifs_posix_lock))) {
+			rc = -EIO;      /* bad smb */
+			goto plk_err_exit;
+		}
+		if(pLockData == NULL) {
+			rc = -EINVAL;
+			goto plk_err_exit;
+		}
+		data_offset = le16_to_cpu(pSMBr->t2.DataOffset);
+		data_count  = le16_to_cpu(pSMBr->t2.DataCount);
+		if(data_count < sizeof(struct cifs_posix_lock)) {
+			rc = -EIO;
+			goto plk_err_exit;
+		}
+		parm_data = (struct cifs_posix_lock *)
+			((char *)&pSMBr->hdr.Protocol + data_offset);
+		if(parm_data->lock_type == cpu_to_le16(CIFS_UNLCK))
+			pLockData->fl_type = F_UNLCK;
+	}
+ 
+plk_err_exit:
+	if (pSMB)
+		cifs_small_buf_release(pSMB);
+
+	/* Note: On -EAGAIN error only caller can retry on handle based calls
+	   since file handle passed in no longer valid */
+
+	return rc;
+}
+
+
+int
 CIFSSMBClose(const int xid, struct cifsTconInfo *tcon, int smb_file_id)
 {
 	int rc = 0;
@@ -1099,6 +1620,7 @@
 	pSMB->ByteCount = 0;
 	rc = SendReceive(xid, tcon->ses, (struct smb_hdr *) pSMB,
 			 (struct smb_hdr *) pSMBr, &bytes_returned, 0);
+	cifs_stats_inc(&tcon->num_closes);
 	if (rc) {
 		if(rc!=-EINTR) {
 			/* EINTR is expected when user ctl-c to kill app */
@@ -1171,16 +1693,11 @@
 
 	rc = SendReceive(xid, tcon->ses, (struct smb_hdr *) pSMB,
 			 (struct smb_hdr *) pSMBr, &bytes_returned, 0);
+	cifs_stats_inc(&tcon->num_renames);
 	if (rc) {
 		cFYI(1, ("Send error in rename = %d", rc));
 	} 
 
-#ifdef CONFIG_CIFS_STATS
-	  else {
-		atomic_inc(&tcon->num_renames);
-	}
-#endif
-
 	cifs_buf_release(pSMB);
 
 	if (rc == -EAGAIN)
@@ -1255,14 +1772,11 @@
 	pSMB->ByteCount = cpu_to_le16(byte_count);
 	rc = SendReceive(xid, pTcon->ses, (struct smb_hdr *) pSMB,
                          (struct smb_hdr *) pSMBr, &bytes_returned, 0);
+	cifs_stats_inc(&pTcon->num_t2renames);
 	if (rc) {
 		cFYI(1,("Send error in Rename (by file handle) = %d", rc));
 	}
-#ifdef CONFIG_CIFS_STATS
-	  else {
-		atomic_inc(&pTcon->num_t2renames);
-	}
-#endif
+
 	cifs_buf_release(pSMB);
 
 	/* Note: On -EAGAIN error only caller can retry on handle based calls
@@ -1362,7 +1876,7 @@
 
 	if (pSMB->hdr.Flags2 & SMBFLG2_UNICODE) {
 		name_len =
-		    cifs_strtoUCS((wchar_t *) pSMB->FileName, fromName, PATH_MAX
+		    cifs_strtoUCS((__le16 *) pSMB->FileName, fromName, PATH_MAX
 				  /* find define for this maxpathcomponent */
 				  , nls_codepage);
 		name_len++;	/* trailing null */
@@ -1386,7 +1900,7 @@
 	data_offset = (char *) (&pSMB->hdr.Protocol) + offset;
 	if (pSMB->hdr.Flags2 & SMBFLG2_UNICODE) {
 		name_len_target =
-		    cifs_strtoUCS((wchar_t *) data_offset, toName, PATH_MAX
+		    cifs_strtoUCS((__le16 *) data_offset, toName, PATH_MAX
 				  /* find define for this maxpathcomponent */
 				  , nls_codepage);
 		name_len_target++;	/* trailing null */
@@ -1416,6 +1930,7 @@
 	pSMB->ByteCount = cpu_to_le16(byte_count);
 	rc = SendReceive(xid, tcon->ses, (struct smb_hdr *) pSMB,
 			 (struct smb_hdr *) pSMBr, &bytes_returned, 0);
+	cifs_stats_inc(&tcon->num_symlinks);
 	if (rc) {
 		cFYI(1,
 		     ("Send error in SetPathInfo (create symlink) = %d",
@@ -1505,6 +2020,7 @@
 	pSMB->ByteCount = cpu_to_le16(byte_count);
 	rc = SendReceive(xid, tcon->ses, (struct smb_hdr *) pSMB,
 			 (struct smb_hdr *) pSMBr, &bytes_returned, 0);
+	cifs_stats_inc(&tcon->num_hardlinks);
 	if (rc) {
 		cFYI(1, ("Send error in SetPathInfo (hard link) = %d", rc));
 	}
@@ -1575,6 +2091,7 @@
 
 	rc = SendReceive(xid, tcon->ses, (struct smb_hdr *) pSMB,
 			 (struct smb_hdr *) pSMBr, &bytes_returned, 0);
+	cifs_stats_inc(&tcon->num_hardlinks);
 	if (rc) {
 		cFYI(1, ("Send error in hard link (NT rename) = %d", rc));
 	}
@@ -1609,7 +2126,7 @@
 
 	if (pSMB->hdr.Flags2 & SMBFLG2_UNICODE) {
 		name_len =
-		    cifs_strtoUCS((wchar_t *) pSMB->FileName, searchName, PATH_MAX
+		    cifs_strtoUCS((__le16 *) pSMB->FileName, searchName, PATH_MAX
 				  /* find define for this maxpathcomponent */
 				  , nls_codepage);
 		name_len++;	/* trailing null */
@@ -1666,7 +2183,7 @@
 					min_t(const int, buflen,count) / 2);
 			/* BB FIXME investigate remapping reserved chars here */
 				cifs_strfromUCS_le(symlinkinfo,
-					(wchar_t *) ((char *)&pSMBr->hdr.Protocol +
+					(__le16 *) ((char *)&pSMBr->hdr.Protocol +
 						data_offset),
 					name_len, nls_codepage);
 			} else {
@@ -1685,6 +2202,90 @@
 	return rc;
 }
 
+/* Initialize NT TRANSACT SMB into small smb request buffer.
+   This assumes that all NT TRANSACTS that we init here have
+   total parm and data under about 400 bytes (to fit in small cifs
+   buffer size), which is the case so far, it easily fits. NB:
+	Setup words themselves and ByteCount
+	MaxSetupCount (size of returned setup area) and
+	MaxParameterCount (returned parms size) must be set by caller */
+static int 
+smb_init_ntransact(const __u16 sub_command, const int setup_count,
+		   const int parm_len, struct cifsTconInfo *tcon,
+		   void ** ret_buf)
+{
+	int rc;
+	__u32 temp_offset;
+	struct smb_com_ntransact_req * pSMB;
+
+	rc = small_smb_init(SMB_COM_NT_TRANSACT, 19 + setup_count, tcon,
+				(void **)&pSMB);
+	if (rc)
+		return rc;
+	*ret_buf = (void *)pSMB;
+	pSMB->Reserved = 0;
+	pSMB->TotalParameterCount = cpu_to_le32(parm_len);
+	pSMB->TotalDataCount  = 0;
+	pSMB->MaxDataCount = cpu_to_le32((tcon->ses->server->maxBuf -
+					  MAX_CIFS_HDR_SIZE) & 0xFFFFFF00);
+	pSMB->ParameterCount = pSMB->TotalParameterCount;
+	pSMB->DataCount  = pSMB->TotalDataCount;
+	temp_offset = offsetof(struct smb_com_ntransact_req, Parms) +
+			(setup_count * 2) - 4 /* for rfc1001 length itself */;
+	pSMB->ParameterOffset = cpu_to_le32(temp_offset);
+	pSMB->DataOffset = cpu_to_le32(temp_offset + parm_len);
+	pSMB->SetupCount = setup_count; /* no need to le convert byte fields */
+	pSMB->SubCommand = cpu_to_le16(sub_command);
+	return 0;
+}
+
+static int
+validate_ntransact(char * buf, char ** ppparm, char ** ppdata,
+		   int * pdatalen, int * pparmlen)
+{
+	char * end_of_smb;
+	__u32 data_count, data_offset, parm_count, parm_offset;
+	struct smb_com_ntransact_rsp * pSMBr;
+
+	if(buf == NULL)
+		return -EINVAL;
+
+	pSMBr = (struct smb_com_ntransact_rsp *)buf;
+
+	/* ByteCount was converted from little endian in SendReceive */
+	end_of_smb = 2 /* sizeof byte count */ + pSMBr->ByteCount + 
+			(char *)&pSMBr->ByteCount;
+
+		
+	data_offset = le32_to_cpu(pSMBr->DataOffset);
+	data_count = le32_to_cpu(pSMBr->DataCount);
+        parm_offset = le32_to_cpu(pSMBr->ParameterOffset);
+	parm_count = le32_to_cpu(pSMBr->ParameterCount);
+
+	*ppparm = (char *)&pSMBr->hdr.Protocol + parm_offset;
+	*ppdata = (char *)&pSMBr->hdr.Protocol + data_offset;
+
+	/* should we also check that parm and data areas do not overlap? */
+	if(*ppparm > end_of_smb) {
+		cFYI(1,("parms start after end of smb"));
+		return -EINVAL;
+	} else if(parm_count + *ppparm > end_of_smb) {
+		cFYI(1,("parm end after end of smb"));
+		return -EINVAL;
+	} else if(*ppdata > end_of_smb) {
+		cFYI(1,("data starts after end of smb"));
+		return -EINVAL;
+	} else if(data_count + *ppdata > end_of_smb) {
+		cFYI(1,("data %p + count %d (%p) ends after end of smb %p start %p",
+			*ppdata, data_count, (data_count + *ppdata), end_of_smb, pSMBr));  /* BB FIXME */
+		return -EINVAL;
+	} else if(parm_count + data_count > pSMBr->ByteCount) {
+		cFYI(1,("parm count and data count larger than SMB"));
+		return -EINVAL;
+	}
+	return 0;
+}
+
 int
 CIFSSMBQueryReparseLinkInfo(const int xid, struct cifsTconInfo *tcon,
 			const unsigned char *searchName,
@@ -1707,7 +2308,8 @@
 	pSMB->TotalDataCount = 0;
 	pSMB->MaxParameterCount = cpu_to_le32(2);
 	/* BB find exact data count max from sess structure BB */
-	pSMB->MaxDataCount = cpu_to_le32(4000);
+	pSMB->MaxDataCount = cpu_to_le32((tcon->ses->server->maxBuf -
+					  MAX_CIFS_HDR_SIZE) & 0xFFFFFF00);
 	pSMB->MaxSetupCount = 4;
 	pSMB->Reserved = 0;
 	pSMB->ParameterOffset = 0;
@@ -1734,7 +2336,9 @@
 			rc = -EIO;	/* bad smb */
 		else {
 			if(data_count && (data_count < 2048)) {
-				char * end_of_smb = pSMBr->ByteCount + (char *)&pSMBr->ByteCount;
+				char * end_of_smb = 2 /* sizeof byte count */ +
+						pSMBr->ByteCount +
+						(char *)&pSMBr->ByteCount;
 
 				struct reparse_data * reparse_buf = (struct reparse_data *)
 					((char *)&pSMBr->hdr.Protocol + data_offset);
@@ -1757,7 +2361,7 @@
 							reparse_buf->TargetNameOffset),
 							min(buflen/2, reparse_buf->TargetNameLen / 2)); 
 					cifs_strfromUCS_le(symlinkinfo,
-						(wchar_t *) (reparse_buf->LinkNamesBuf + 
+						(__le16 *) (reparse_buf->LinkNamesBuf + 
 						reparse_buf->TargetNameOffset),
 						name_len, nls_codepage);
 				} else { /* ASCII names */
@@ -1771,11 +2375,10 @@
 			}
 			symlinkinfo[buflen] = 0; /* just in case so the caller
 					does not go off the end of the buffer */
-			cFYI(1,("readlink result - %s ",symlinkinfo));
+			cFYI(1,("readlink result - %s",symlinkinfo));
 		}
 	}
 qreparse_out:
-	if (pSMB)
 		cifs_buf_release(pSMB);
 
 	/* Note: On -EAGAIN error only caller can retry on handle based calls
@@ -1783,16 +2386,16 @@
 
 	return rc;
 }
-
+#if LINUX_VERSION_CODE > KERNEL_VERSION(2, 5, 0)
 #ifdef CONFIG_CIFS_POSIX
 
 /*Convert an Access Control Entry from wire format to local POSIX xattr format*/
 static void cifs_convert_ace(posix_acl_xattr_entry * ace, struct cifs_posix_ace * cifs_ace)
 {
 	/* u8 cifs fields do not need le conversion */
-	ace->e_perm = (__u16)cifs_ace->cifs_e_perm; 
-	ace->e_tag  = (__u16)cifs_ace->cifs_e_tag;
-	ace->e_id   = (__u32)le64_to_cpu(cifs_ace->cifs_uid);
+	ace->e_perm = cpu_to_le16(cifs_ace->cifs_e_perm);
+	ace->e_tag  = cpu_to_le16(cifs_ace->cifs_e_tag);
+	ace->e_id   = cpu_to_le32(le64_to_cpu(cifs_ace->cifs_uid));
 	/* cFYI(1,("perm %d tag %d id %d",ace->e_perm,ace->e_tag,ace->e_id)); */
 
 	return;
@@ -1844,7 +2447,7 @@
 	} else if(size > buflen) {
 		return -ERANGE;
 	} else /* buffer big enough */ {
-		local_acl->a_version = POSIX_ACL_XATTR_VERSION;
+		local_acl->a_version = cpu_to_le32(POSIX_ACL_XATTR_VERSION);
 		for(i = 0;i < count ;i++) {
 			cifs_convert_ace(&local_acl->a_entries[i],pACE);
 			pACE ++;
@@ -1858,14 +2461,14 @@
 {
 	__u16 rc = 0; /* 0 = ACL converted ok */
 
-	cifs_ace->cifs_e_perm = (__u8)cpu_to_le16(local_ace->e_perm);
-	cifs_ace->cifs_e_tag =  (__u8)cpu_to_le16(local_ace->e_tag);
+	cifs_ace->cifs_e_perm = le16_to_cpu(local_ace->e_perm);
+	cifs_ace->cifs_e_tag =  le16_to_cpu(local_ace->e_tag);
 	/* BB is there a better way to handle the large uid? */
-	if(local_ace->e_id == -1) {
+	if(local_ace->e_id == cpu_to_le32(-1)) {
 	/* Probably no need to le convert -1 on any arch but can not hurt */
 		cifs_ace->cifs_uid = cpu_to_le64(-1);
 	} else 
-		cifs_ace->cifs_uid = (__u64)cpu_to_le32(local_ace->e_id);
+		cifs_ace->cifs_uid = cpu_to_le64(le32_to_cpu(local_ace->e_id));
         /*cFYI(1,("perm %d tag %d id %d",ace->e_perm,ace->e_tag,ace->e_id));*/
 	return rc;
 }
@@ -1885,16 +2488,17 @@
 
 	count = posix_acl_xattr_count((size_t)buflen);
 	cFYI(1,("setting acl with %d entries from buf of length %d and version of %d",
-		count,buflen,local_acl->a_version));
-	if(local_acl->a_version != 2) {
-		cFYI(1,("unknown POSIX ACL version %d",local_acl->a_version));
+		count, buflen, le32_to_cpu(local_acl->a_version)));
+	if(le32_to_cpu(local_acl->a_version) != 2) {
+		cFYI(1,("unknown POSIX ACL version %d",
+		     le32_to_cpu(local_acl->a_version)));
 		return 0;
 	}
 	cifs_acl->version = cpu_to_le16(1);
 	if(acl_type == ACL_TYPE_ACCESS) 
-		cifs_acl->access_entry_count = count;
+		cifs_acl->access_entry_count = cpu_to_le16(count);
 	else if(acl_type == ACL_TYPE_DEFAULT)
-		cifs_acl->default_entry_count = count;
+		cifs_acl->default_entry_count = cpu_to_le16(count);
 	else {
 		cFYI(1,("unknown ACL type %d",acl_type));
 		return 0;
@@ -1978,6 +2582,7 @@
 
 	rc = SendReceive(xid, tcon->ses, (struct smb_hdr *) pSMB,
 		(struct smb_hdr *) pSMBr, &bytes_returned, 0);
+	cifs_stats_inc(&tcon->num_acl_get);
 	if (rc) {
 		cFYI(1, ("Send error in Query POSIX ACL = %d", rc));
 	} else {
@@ -2164,6 +2769,153 @@
 
 
 #endif /* CONFIG_POSIX */
+#endif /* if version > 2.5 */
+
+/* security id for everyone */
+const struct cifs_sid sid_everyone = {1, 1, {0, 0, 0, 0, 0, 0}, {0, 0, 0, 0}};
+/* group users */
+const struct cifs_sid sid_user = {1, 2 , {0, 0, 0, 0, 0, 5}, {32, 545, 0, 0}};
+
+/* Convert CIFS ACL to POSIX form */
+static int parse_sec_desc(struct cifs_sid * psec_desc, int acl_len)
+{
+	return 0;
+}
+
+/* Get Security Descriptor (by handle) from remote server for a file or dir */
+int
+CIFSSMBGetCIFSACL(const int xid, struct cifsTconInfo *tcon, __u16 fid,
+         /*  BB fix up return info */ char *acl_inf, const int buflen, 
+		  const int acl_type /* ACCESS/DEFAULT not sure implication */)
+{
+	int rc = 0;
+	int buf_type = 0;
+	QUERY_SEC_DESC_REQ * pSMB;
+	struct kvec iov[1];
+
+	cFYI(1, ("GetCifsACL"));
+
+	rc = smb_init_ntransact(NT_TRANSACT_QUERY_SECURITY_DESC, 0, 
+			8 /* parm len */, tcon, (void **) &pSMB);
+	if (rc)
+		return rc;
+
+	pSMB->MaxParameterCount = cpu_to_le32(4);
+	/* BB TEST with big acls that might need to be e.g. larger than 16K */
+	pSMB->MaxSetupCount = 0;
+	pSMB->Fid = fid; /* file handle always le */
+	pSMB->AclFlags = cpu_to_le32(CIFS_ACL_OWNER | CIFS_ACL_GROUP |
+				     CIFS_ACL_DACL);
+	pSMB->ByteCount = cpu_to_le16(11); /* 3 bytes pad + 8 bytes parm */
+	pSMB->hdr.smb_buf_length += 11;
+	iov[0].iov_base = (char *)pSMB;
+	iov[0].iov_len = pSMB->hdr.smb_buf_length + 4;
+
+	rc = SendReceive2(xid, tcon->ses, iov, 1 /* num iovec */, &buf_type, 0);
+	cifs_stats_inc(&tcon->num_acl_get);
+	if (rc) {
+		cFYI(1, ("Send error in QuerySecDesc = %d", rc));
+	} else {                /* decode response */
+		struct cifs_sid * psec_desc;
+		__le32 * parm;
+		int parm_len;
+		int data_len;
+		int acl_len;
+		struct smb_com_ntransact_rsp * pSMBr;
+
+/* validate_nttransact */
+		rc = validate_ntransact(iov[0].iov_base, (char **)&parm, 
+					(char **)&psec_desc,
+					&parm_len, &data_len);
+		
+		if(rc)
+			goto qsec_out;
+		pSMBr = (struct smb_com_ntransact_rsp *)iov[0].iov_base;
+
+		cERROR(1,("smb %p parm %p data %p",pSMBr,parm,psec_desc));  /* BB removeme BB */
+
+		if (le32_to_cpu(pSMBr->ParameterCount) != 4) {
+			rc = -EIO;      /* bad smb */
+			goto qsec_out;
+		}
+
+/* BB check that data area is minimum length and as big as acl_len */
+
+		acl_len = le32_to_cpu(*(__le32 *)parm);
+		/* BB check if(acl_len > bufsize) */
+
+		parse_sec_desc(psec_desc, acl_len);
+	}
+qsec_out:
+	if(buf_type == CIFS_SMALL_BUFFER)
+		cifs_small_buf_release(iov[0].iov_base);
+	else if(buf_type == CIFS_LARGE_BUFFER)
+		cifs_buf_release(iov[0].iov_base);
+/*	cifs_small_buf_release(pSMB); */ /* Freed earlier now in SendReceive2 */
+	return rc;
+}
+
+
+/* Legacy Query Path Information call for lookup to old servers such
+   as Win9x/WinME */
+int SMBQueryInformation(const int xid, struct cifsTconInfo *tcon,
+                 const unsigned char *searchName,
+                 FILE_ALL_INFO * pFinfo,
+                 const struct nls_table *nls_codepage, int remap)
+{
+	QUERY_INFORMATION_REQ * pSMB;
+	QUERY_INFORMATION_RSP * pSMBr;
+	int rc = 0;
+	int bytes_returned;
+	int name_len;
+
+	cFYI(1, ("In SMBQPath path %s", searchName)); 
+QInfRetry:
+	rc = smb_init(SMB_COM_QUERY_INFORMATION, 0, tcon, (void **) &pSMB,
+                      (void **) &pSMBr);
+	if (rc)
+		return rc;
+
+	if (pSMB->hdr.Flags2 & SMBFLG2_UNICODE) {
+		name_len =
+                    cifsConvertToUCS((__le16 *) pSMB->FileName, searchName,
+                                     PATH_MAX, nls_codepage, remap);
+		name_len++;     /* trailing null */
+		name_len *= 2;
+	} else {               
+		name_len = strnlen(searchName, PATH_MAX);
+		name_len++;     /* trailing null */
+		strncpy(pSMB->FileName, searchName, name_len);
+	}
+	pSMB->BufferFormat = 0x04;
+	name_len++; /* account for buffer type byte */	
+	pSMB->hdr.smb_buf_length += (__u16) name_len;
+	pSMB->ByteCount = cpu_to_le16(name_len);
+
+	rc = SendReceive(xid, tcon->ses, (struct smb_hdr *) pSMB,
+                         (struct smb_hdr *) pSMBr, &bytes_returned, 0);
+	if (rc) {
+		cFYI(1, ("Send error in QueryInfo = %d", rc));
+	} else if (pFinfo) {            /* decode response */
+		memset(pFinfo, 0, sizeof(FILE_ALL_INFO));
+		pFinfo->AllocationSize =
+			cpu_to_le64(le32_to_cpu(pSMBr->size));
+		pFinfo->EndOfFile = pFinfo->AllocationSize;
+		pFinfo->Attributes =
+			cpu_to_le32(le16_to_cpu(pSMBr->attr));
+	} else
+		rc = -EIO; /* bad buffer passed in */
+
+	cifs_buf_release(pSMB);
+
+	if (rc == -EAGAIN)
+		goto QInfRetry;
+
+	return rc;
+}
+
+
+
 
 int
 CIFSSMBQPathInfo(const int xid, struct cifsTconInfo *tcon,
@@ -2396,7 +3148,7 @@
 	if (rc) {
 		cFYI(1, ("Send error in FindFileDirInfo = %d", rc));
 	} else {		/* decode response */
-
+		cifs_stats_inc(&tcon->num_ffirst);
 		/* BB fill in */
 	}
 
@@ -2414,7 +3166,7 @@
 	      const char *searchName, 
 	      const struct nls_table *nls_codepage,
 	      __u16 *	pnetfid,
-	      struct cifs_search_info * psrch_inf, int remap)
+	      struct cifs_search_info * psrch_inf, int remap, const char dirsep)
 {
 /* level 257 SMB_ */
 	TRANSACTION2_FFIRST_REQ *pSMB = NULL;
@@ -2441,7 +3193,7 @@
 		it got remapped to 0xF03A as if it were part of the
 		directory name instead of a wildcard */
 		name_len *= 2;
-		pSMB->FileName[name_len] = '\\';
+		pSMB->FileName[name_len] = dirsep;
 		pSMB->FileName[name_len+1] = 0;
 		pSMB->FileName[name_len+2] = '*';
 		pSMB->FileName[name_len+3] = 0;
@@ -2455,7 +3207,7 @@
 		if(name_len > buffersize-header)
 			free buffer exit; BB */
 		strncpy(pSMB->FileName, searchName, name_len);
-		pSMB->FileName[name_len] = '\\';
+		pSMB->FileName[name_len] = dirsep;
 		pSMB->FileName[name_len+1] = '*';
 		pSMB->FileName[name_len+2] = 0;
 		name_len += 3;
@@ -2475,7 +3227,8 @@
 	pSMB->TotalParameterCount = cpu_to_le16(params);
 	pSMB->ParameterCount = pSMB->TotalParameterCount;
 	pSMB->ParameterOffset = cpu_to_le16(
-	  offsetof(struct smb_com_transaction2_ffirst_req, SearchAttributes) - 4);
+	      offsetof(struct smb_com_transaction2_ffirst_req, SearchAttributes)
+		- 4);
 	pSMB->DataCount = 0;
 	pSMB->DataOffset = 0;
 	pSMB->SetupCount = 1;	/* one byte, no need to make endian neutral */
@@ -2496,12 +3249,13 @@
 
 	rc = SendReceive(xid, tcon->ses, (struct smb_hdr *) pSMB,
 			 (struct smb_hdr *) pSMBr, &bytes_returned, 0);
+	cifs_stats_inc(&tcon->num_ffirst);
 
-	if (rc) {/* BB add logic to retry regular search if Unix search rejected unexpectedly by server */
+	if (rc) {/* BB add logic to retry regular search if Unix search
+			rejected unexpectedly by server */
 		/* BB Add code to handle unsupported level rc */
 		cFYI(1, ("Error in FindFirst = %d", rc));
 
-		if (pSMB)
 			cifs_buf_release(pSMB);
 
 		/* BB eventually could optimize out free and realloc of buf */
@@ -2518,6 +3272,7 @@
 				psrch_inf->unicode = FALSE;
 
 			psrch_inf->ntwrk_buf_start = (char *)pSMBr;
+			psrch_inf->smallBuf = 0;
 			psrch_inf->srch_entries_start = 
 				(char *) &pSMBr->hdr.Protocol + 
 					le16_to_cpu(pSMBr->t2.DataOffset);
@@ -2530,7 +3285,7 @@
 				psrch_inf->endOfSearch = FALSE;
 
 			psrch_inf->entries_in_buffer  = le16_to_cpu(parms->SearchCount);
-			psrch_inf->index_of_last_entry = 
+			psrch_inf->index_of_last_entry = 2 /* skip . and .. */ +
 				psrch_inf->entries_in_buffer;
 			*pnetfid = parms->SearchHandle;
 		} else {
@@ -2617,7 +3372,7 @@
                                                                                               
 	rc = SendReceive(xid, tcon->ses, (struct smb_hdr *) pSMB,
 			(struct smb_hdr *) pSMBr, &bytes_returned, 0);
-                                                                                              
+	cifs_stats_inc(&tcon->num_fnext);
 	if (rc) {
 		if (rc == -EBADF) {
 			psrch_inf->endOfSearch = TRUE;
@@ -2638,9 +3393,14 @@
 			parms = (T2_FNEXT_RSP_PARMS *)response_data;
 			response_data = (char *)&pSMBr->hdr.Protocol +
 				le16_to_cpu(pSMBr->t2.DataOffset);
+			if(psrch_inf->smallBuf)
+				cifs_small_buf_release(
+					psrch_inf->ntwrk_buf_start);
+			else
 			cifs_buf_release(psrch_inf->ntwrk_buf_start);
 			psrch_inf->srch_entries_start = response_data;
 			psrch_inf->ntwrk_buf_start = (char *)pSMB;
+			psrch_inf->smallBuf = 0;
 			if(parms->EndofSearch)
 				psrch_inf->endOfSearch = TRUE;
 			else
@@ -2694,6 +3454,7 @@
 	if (rc) {
 		cERROR(1, ("Send error in FindClose = %d", rc));
 	}
+	cifs_stats_inc(&tcon->num_fclose);
 	cifs_small_buf_release(pSMB);
 
 	/* Since session is dead, search handle closed on server already */
@@ -2703,7 +3464,6 @@
 	return rc;
 }
 
-#ifdef CONFIG_CIFS_EXPERIMENTAL
 int
 CIFSGetSrvInodeNumber(const int xid, struct cifsTconInfo *tcon,
                 const unsigned char *searchName,
@@ -2797,7 +3557,6 @@
 		goto GetInodeNumberRetry;
 	return rc;
 }
-#endif /* CIFS_EXPERIMENTAL */
 
 int
 CIFSGetDFSRefer(const int xid, struct cifsSesInfo *ses,
@@ -2828,6 +3587,9 @@
 	if (rc)
 		return rc;
 
+	/* server pointer checked in called function, 
+	but should never be null here anyway */
+	pSMB->hdr.Mid = GetNextMid(ses->server);
 	pSMB->hdr.Tid = ses->ipc_tid;
 	pSMB->hdr.Uid = ses->Suid;
 	if (ses->capabilities & CAP_STATUS32) {
@@ -2946,7 +3708,7 @@
 				temp = ((char *)referrals) + le16_to_cpu(referrals->DfsPathOffset);
 				if (pSMBr->hdr.Flags2 & SMBFLG2_UNICODE) {
 					cifs_strfromUCS_le(*targetUNCs,
-						(wchar_t *) temp, name_len, nls_codepage);
+						(__le16 *) temp, name_len, nls_codepage);
 				} else {
 					strncpy(*targetUNCs,temp,name_len);
 				}
@@ -2968,8 +3730,102 @@
 	return rc;
 }
 
+/* Query File System Info such as free space to old servers such as Win 9x */
+int
+#if LINUX_VERSION_CODE > KERNEL_VERSION(2, 5, 0)
+SMBOldQFSInfo(const int xid, struct cifsTconInfo *tcon, struct kstatfs *FSData)
+#else
+SMBOldQFSInfo(const int xid, struct cifsTconInfo *tcon, struct statfs *FSData)
+#endif
+{
+/* level 0x01 SMB_QUERY_FILE_SYSTEM_INFO */
+	TRANSACTION2_QFSI_REQ *pSMB = NULL;
+	TRANSACTION2_QFSI_RSP *pSMBr = NULL;
+	FILE_SYSTEM_ALLOC_INFO *response_data;
+	int rc = 0;
+	int bytes_returned = 0;
+	__u16 params, byte_count;
+
+	cFYI(1, ("OldQFSInfo"));
+oldQFSInfoRetry:
+	rc = smb_init(SMB_COM_TRANSACTION2, 15, tcon, (void **) &pSMB,
+		(void **) &pSMBr);
+	if (rc)
+		return rc;
+	rc = smb_init(SMB_COM_TRANSACTION2, 15, tcon, (void **) &pSMB,
+		      (void **) &pSMBr);
+	if (rc)
+		return rc;
+
+	params = 2;     /* level */
+	pSMB->TotalDataCount = 0;
+	pSMB->MaxParameterCount = cpu_to_le16(2);
+	pSMB->MaxDataCount = cpu_to_le16(1000);
+	pSMB->MaxSetupCount = 0;
+	pSMB->Reserved = 0;
+	pSMB->Flags = 0;
+	pSMB->Timeout = 0;
+	pSMB->Reserved2 = 0;
+	byte_count = params + 1 /* pad */ ;
+	pSMB->TotalParameterCount = cpu_to_le16(params);
+	pSMB->ParameterCount = pSMB->TotalParameterCount;
+	pSMB->ParameterOffset = cpu_to_le16(offsetof(
+	struct smb_com_transaction2_qfsi_req, InformationLevel) - 4);
+	pSMB->DataCount = 0;
+	pSMB->DataOffset = 0;
+	pSMB->SetupCount = 1;
+	pSMB->Reserved3 = 0;
+	pSMB->SubCommand = cpu_to_le16(TRANS2_QUERY_FS_INFORMATION);
+	pSMB->InformationLevel = cpu_to_le16(SMB_INFO_ALLOCATION);
+	pSMB->hdr.smb_buf_length += byte_count;
+	pSMB->ByteCount = cpu_to_le16(byte_count);
+
+	rc = SendReceive(xid, tcon->ses, (struct smb_hdr *) pSMB,
+		(struct smb_hdr *) pSMBr, &bytes_returned, 0);
+	if (rc) {
+		cFYI(1, ("Send error in QFSInfo = %d", rc));
+	} else {                /* decode response */
+		rc = validate_t2((struct smb_t2_rsp *)pSMBr);
+
+		if (rc || (pSMBr->ByteCount < 18))
+			rc = -EIO;      /* bad smb */
+		else {
+			__u16 data_offset = le16_to_cpu(pSMBr->t2.DataOffset);
+			cFYI(1,("qfsinf resp BCC: %d  Offset %d",
+				 pSMBr->ByteCount, data_offset));
+
+			response_data =
+				(FILE_SYSTEM_ALLOC_INFO *) 
+				(((char *) &pSMBr->hdr.Protocol) + data_offset);
+			FSData->f_bsize =
+				le16_to_cpu(response_data->BytesPerSector) *
+				le32_to_cpu(response_data->
+					SectorsPerAllocationUnit);
+			FSData->f_blocks =
+				le32_to_cpu(response_data->TotalAllocationUnits);
+			FSData->f_bfree = FSData->f_bavail =
+				le32_to_cpu(response_data->FreeAllocationUnits);
+			cFYI(1,
+			     ("Blocks: %lld  Free: %lld Block size %ld",
+			      (unsigned long long)FSData->f_blocks,
+			      (unsigned long long)FSData->f_bfree,
+			      FSData->f_bsize));
+		}
+	}
+	cifs_buf_release(pSMB);
+
+	if (rc == -EAGAIN)
+		goto oldQFSInfoRetry;
+
+	return rc;
+}
+
 int
+#if LINUX_VERSION_CODE > KERNEL_VERSION(2, 5, 0)
 CIFSSMBQFSInfo(const int xid, struct cifsTconInfo *tcon, struct kstatfs *FSData)
+#else
+CIFSSMBQFSInfo(const int xid, struct cifsTconInfo *tcon, struct statfs *FSData)
+#endif
 {
 /* level 0x103 SMB_QUERY_FILE_SYSTEM_INFO */
 	TRANSACTION2_QFSI_REQ *pSMB = NULL;
@@ -2989,7 +3845,7 @@
 	params = 2;	/* level */
 	pSMB->TotalDataCount = 0;
 	pSMB->MaxParameterCount = cpu_to_le16(2);
-	pSMB->MaxDataCount = cpu_to_le16(1000);	/* BB find exact max SMB PDU from sess structure BB */
+	pSMB->MaxDataCount = cpu_to_le16(1000);
 	pSMB->MaxSetupCount = 0;
 	pSMB->Reserved = 0;
 	pSMB->Flags = 0;
@@ -3012,17 +3868,14 @@
 	rc = SendReceive(xid, tcon->ses, (struct smb_hdr *) pSMB,
 			 (struct smb_hdr *) pSMBr, &bytes_returned, 0);
 	if (rc) {
-		cERROR(1, ("Send error in QFSInfo = %d", rc));
+		cFYI(1, ("Send error in QFSInfo = %d", rc));
 	} else {		/* decode response */
                 rc = validate_t2((struct smb_t2_rsp *)pSMBr);
 
-		if (rc || (pSMBr->ByteCount < 24)) /* BB alsO CHEck enough total bytes returned */
+		if (rc || (pSMBr->ByteCount < 24))
 			rc = -EIO;	/* bad smb */
 		else {
 			__u16 data_offset = le16_to_cpu(pSMBr->t2.DataOffset);
-			cFYI(1,
-				("Decoding qfsinfo response.  BCC: %d  Offset %d",
-				pSMBr->ByteCount, data_offset));
 
 			response_data =
 			    (FILE_SYSTEM_INFO
@@ -3257,10 +4110,86 @@
 	return rc;
 }
 
+int
+CIFSSMBSetFSUnixInfo(const int xid, struct cifsTconInfo *tcon, __u64 cap)
+{
+/* level 0x200  SMB_SET_CIFS_UNIX_INFO */
+	TRANSACTION2_SETFSI_REQ *pSMB = NULL;
+	TRANSACTION2_SETFSI_RSP *pSMBr = NULL;
+	int rc = 0;
+	int bytes_returned = 0;
+	__u16 params, param_offset, offset, byte_count;
+
+	cFYI(1, ("In SETFSUnixInfo"));
+SETFSUnixRetry:
+	/* BB switch to small buf init to save memory */
+	rc = smb_init(SMB_COM_TRANSACTION2, 15, tcon, (void **) &pSMB,
+		      (void **) &pSMBr);
+	if (rc)
+		return rc;
+
+	params = 4;	/* 2 bytes zero followed by info level. */
+	pSMB->MaxSetupCount = 0;
+	pSMB->Reserved = 0;
+	pSMB->Flags = 0;
+	pSMB->Timeout = 0;
+	pSMB->Reserved2 = 0;
+	param_offset = offsetof(struct smb_com_transaction2_setfsi_req, FileNum) - 4;
+	offset = param_offset + params;
+
+	pSMB->MaxParameterCount = cpu_to_le16(4);
+	pSMB->MaxDataCount = cpu_to_le16(100);	/* BB find exact max SMB PDU from sess structure BB */
+	pSMB->SetupCount = 1;
+	pSMB->Reserved3 = 0;
+	pSMB->SubCommand = cpu_to_le16(TRANS2_SET_FS_INFORMATION);
+	byte_count = 1 /* pad */ + params + 12;
+
+	pSMB->DataCount = cpu_to_le16(12);
+	pSMB->ParameterCount = cpu_to_le16(params);
+	pSMB->TotalDataCount = pSMB->DataCount;
+	pSMB->TotalParameterCount = pSMB->ParameterCount;
+	pSMB->ParameterOffset = cpu_to_le16(param_offset);
+	pSMB->DataOffset = cpu_to_le16(offset);
+
+	/* Params. */
+	pSMB->FileNum = 0;
+	pSMB->InformationLevel = cpu_to_le16(SMB_SET_CIFS_UNIX_INFO);
+
+	/* Data. */
+	pSMB->ClientUnixMajor = cpu_to_le16(CIFS_UNIX_MAJOR_VERSION);
+	pSMB->ClientUnixMinor = cpu_to_le16(CIFS_UNIX_MINOR_VERSION);
+	pSMB->ClientUnixCap = cpu_to_le64(cap);
+
+	pSMB->hdr.smb_buf_length += byte_count;
+	pSMB->ByteCount = cpu_to_le16(byte_count);
+
+	rc = SendReceive(xid, tcon->ses, (struct smb_hdr *) pSMB,
+			 (struct smb_hdr *) pSMBr, &bytes_returned, 0);
+	if (rc) {
+		cERROR(1, ("Send error in SETFSUnixInfo = %d", rc));
+	} else {		/* decode response */
+		rc = validate_t2((struct smb_t2_rsp *)pSMBr);
+		if (rc) {
+			rc = -EIO;	/* bad smb */
+		}
+	}
+	cifs_buf_release(pSMB);
+
+	if (rc == -EAGAIN)
+		goto SETFSUnixRetry;
+
+	return rc;
+}
+
+
 
 int
 CIFSSMBQFSPosixInfo(const int xid, struct cifsTconInfo *tcon,
+#if LINUX_VERSION_CODE > KERNEL_VERSION(2, 5, 0)
 		   struct kstatfs *FSData)
+#else
+		   struct statfs  *FSData)
+#endif
 {
 /* level 0x201  SMB_QUERY_CIFS_POSIX_INFO */
 	TRANSACTION2_QFSI_REQ *pSMB = NULL;
@@ -3321,16 +4250,16 @@
 					le64_to_cpu(response_data->TotalBlocks);
 			FSData->f_bfree =
 			    le64_to_cpu(response_data->BlocksAvail);
-			if(response_data->UserBlocksAvail == -1) {
+			if(response_data->UserBlocksAvail == cpu_to_le64(-1)) {
 				FSData->f_bavail = FSData->f_bfree;
 			} else {
 				FSData->f_bavail =
 					le64_to_cpu(response_data->UserBlocksAvail);
 			}
-			if(response_data->TotalFileNodes != -1)
+			if(response_data->TotalFileNodes != cpu_to_le64(-1))
 				FSData->f_files =
 					le64_to_cpu(response_data->TotalFileNodes);
-			if(response_data->FreeFileNodes != -1)
+			if(response_data->FreeFileNodes != cpu_to_le64(-1))
 				FSData->f_ffree =
 					le64_to_cpu(response_data->FreeFileNodes);
 		}
@@ -3384,7 +4313,7 @@
 	params = 6 + name_len;
 	data_count = sizeof (struct file_end_of_file_info);
 	pSMB->MaxParameterCount = cpu_to_le16(2);
-	pSMB->MaxDataCount = cpu_to_le16(1000);	/* BB find max SMB size from sess */
+	pSMB->MaxDataCount = cpu_to_le16(4100);
 	pSMB->MaxSetupCount = 0;
 	pSMB->Reserved = 0;
 	pSMB->Flags = 0;
@@ -3840,11 +4769,13 @@
 
 int CIFSSMBNotify(const int xid, struct cifsTconInfo *tcon, 
 			const int notify_subdirs, const __u16 netfid,
-			__u32 filter, const struct nls_table *nls_codepage)
+		  __u32 filter, struct file * pfile, int multishot, 
+		  const struct nls_table *nls_codepage)
 {
 	int rc = 0;
 	struct smb_com_transaction_change_notify_req * pSMB = NULL;
-	struct smb_com_transaction_change_notify_rsp * pSMBr = NULL;
+	struct smb_com_ntransaction_change_notify_rsp * pSMBr = NULL;
+	struct dir_notify_req *dnotify_req;
 	int bytes_returned;
 
 	cFYI(1, ("In CIFSSMBNotify for file handle %d",(int)netfid));
@@ -3858,6 +4789,10 @@
 	pSMB->MaxParameterCount = cpu_to_le32(2);
 	/* BB find exact data count max from sess structure BB */
 	pSMB->MaxDataCount = 0; /* same in little endian or be */
+/* BB VERIFY verify which is correct for above BB */
+	pSMB->MaxDataCount = cpu_to_le32((tcon->ses->server->maxBuf -
+					     MAX_CIFS_HDR_SIZE) & 0xFFFFFF00);
+
 	pSMB->MaxSetupCount = 4;
 	pSMB->Reserved = 0;
 	pSMB->ParameterOffset = 0;
@@ -3877,6 +4812,28 @@
 			(struct smb_hdr *) pSMBr, &bytes_returned, -1);
 	if (rc) {
 		cFYI(1, ("Error in Notify = %d", rc));
+	} else {
+		/* Add file to outstanding requests */
+		/* BB change to kmem cache alloc */	
+		dnotify_req = (struct dir_notify_req *) kmalloc(
+						sizeof(struct dir_notify_req),
+						 GFP_KERNEL);
+		if(dnotify_req) {
+			dnotify_req->Pid = pSMB->hdr.Pid;
+			dnotify_req->PidHigh = pSMB->hdr.PidHigh;
+			dnotify_req->Mid = pSMB->hdr.Mid;
+			dnotify_req->Tid = pSMB->hdr.Tid;
+			dnotify_req->Uid = pSMB->hdr.Uid;
+			dnotify_req->netfid = netfid;
+			dnotify_req->pfile = pfile;
+			dnotify_req->filter = filter;
+			dnotify_req->multishot = multishot;
+			spin_lock(&GlobalMid_Lock);
+			list_add_tail(&dnotify_req->lhead, 
+					&GlobalDnotifyReqList);
+			spin_unlock(&GlobalMid_Lock);
+		} else 
+			rc = -ENOMEM;
 	}
 	cifs_buf_release(pSMB);
 	return rc;	
--- linux-2.6.13/fs/cifs/cifs_unicode.c
+++ linux-2.6.13/fs/cifs/cifs_unicode.c
@@ -1,7 +1,7 @@
 /*
  *   fs/cifs/cifs_unicode.c
  *
- *   Copyright (c) International Business Machines  Corp., 2000,2002
+ *   Copyright (c) International Business Machines  Corp., 2000,2005
  *   Modified by Steve French (sfrench@us.ibm.com)
  *
  *   This program is free software;  you can redistribute it and/or modify
@@ -22,6 +22,7 @@
 #include "cifs_unicode.h"
 #include "cifs_uniupr.h"
 #include "cifspdu.h"
+#include "cifsglob.h"
 #include "cifs_debug.h"
 
 /*
@@ -31,7 +32,7 @@
  *
  */
 int
-cifs_strfromUCS_le(char *to, const wchar_t * from,	/* LITTLE ENDIAN */
+cifs_strfromUCS_le(char *to, const __le16 * from,	
 		   int len, const struct nls_table *codepage)
 {
 	int i;
@@ -60,24 +61,26 @@
  *
  */
 int
-cifs_strtoUCS(wchar_t * to, const char *from, int len,
+cifs_strtoUCS(__le16 * to, const char *from, int len,
 	      const struct nls_table *codepage)
 {
 	int charlen;
 	int i;
+	wchar_t * wchar_to = (wchar_t *)to; /* needed to quiet sparse */  
 
 	for (i = 0; len && *from; i++, from += charlen, len -= charlen) {
 
 		/* works for 2.4.0 kernel or later */
-		charlen = codepage->char2uni(from, len, &to[i]);
+		charlen = codepage->char2uni(from, len, &wchar_to[i]);
 		if (charlen < 1) {
 			cERROR(1,
 			       ("cifs_strtoUCS: char2uni returned %d",
 				charlen));
-			to[i] = cpu_to_le16(0x003f);	/* a question mark */
+			/* A question mark */
+			to[i] = cpu_to_le16(0x003f);
 			charlen = 1;
 		} else 
-			to[i] = cpu_to_le16(to[i]);
+			to[i] = cpu_to_le16(wchar_to[i]);
 
 	}
 
--- linux-2.6.13/fs/cifs/cifs_unicode.h
+++ linux-2.6.13/fs/cifs/cifs_unicode.h
@@ -5,7 +5,7 @@
  *     Convert a unicode character to upper or lower case using
  *     compressed tables.
  *
- *   Copyright (c) International Business Machines  Corp., 2000,2002
+ *   Copyright (c) International Business Machines  Corp., 2000,2005555555555555555555555555555555555555555555555555555555
  *
  *   This program is free software;  you can redistribute it and/or modify
  *   it under the terms of the GNU General Public License as published by
@@ -59,8 +59,13 @@
 #endif				/* UNIUPR_NOLOWER */
 
 #ifdef __KERNEL__
-int cifs_strfromUCS_le(char *, const wchar_t *, int, const struct nls_table *);
-int cifs_strtoUCS(wchar_t *, const char *, int, const struct nls_table *);
+#ifndef __le16
+int cifs_strfromUCS_le(char *, const __u16 *, int, const struct nls_table *);
+int cifs_strtoUCS(__u16 *, const char *, int, const struct nls_table *);
+#else
+int cifs_strfromUCS_le(char *, const __le16 *, int, const struct nls_table *);
+int cifs_strtoUCS(__le16 *, const char *, int, const struct nls_table *);
+#endif
 #endif
 
 /*
--- linux-2.6.13/fs/cifs/cifs_uniupr.h
+++ linux-2.6.13/fs/cifs/cifs_uniupr.h
@@ -242,7 +242,7 @@
 /*
  * Lower Case Range
  */
-const static struct UniCaseRange CifsUniLowerRange[] = {
+static const struct UniCaseRange CifsUniLowerRange[] = {
 	0x0380, 0x03ab, UniCaseRangeL0380,
 	0x0400, 0x042f, UniCaseRangeL0400,
 	0x0490, 0x04cb, UniCaseRangeL0490,
--- linux-2.6.13/fs/cifs/cn_cifs.h
+++ linux-2.6.13/fs/cifs/cn_cifs.h
@@ -0,0 +1,37 @@
+/*
+ *   fs/cifs/cn_cifs.h
+ *
+ *   Copyright (c) International Business Machines  Corp., 2002
+ *   Author(s): Steve French (sfrench@us.ibm.com)
+ *
+ *   This library is free software; you can redistribute it and/or modify
+ *   it under the terms of the GNU Lesser General Public License as published
+ *   by the Free Software Foundation; either version 2.1 of the License, or
+ *   (at your option) any later version.
+ *
+ *   This library is distributed in the hope that it will be useful,
+ *   but WITHOUT ANY WARRANTY; without even the implied warranty of
+ *   MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See
+ *   the GNU Lesser General Public License for more details.
+ *
+ *   You should have received a copy of the GNU Lesser General Public License
+ *   along with this library; if not, write to the Free Software
+ *   Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
+ */
+
+#ifndef _CN_CIFS_H
+#define _CN_CIFS_H
+#ifdef CONFIG_CIFS_UPCALL
+#include <linux/types.h>
+#include <linux/connector.h>
+
+struct cifs_upcall {
+	char signature[4]; /* CIFS */
+	enum command {
+		CIFS_GET_IP = 0x00000001,   /* get ip address for hostname */
+		CIFS_GET_SECBLOB = 0x00000002, /* get SPNEGO wrapped blob */
+	} command;
+	/* union cifs upcall data follows */
+};
+#endif /* CIFS_UPCALL */
+#endif /* _CN_CIFS_H */
--- linux-2.6.13/fs/cifs/connect.c
+++ linux-2.6.13/fs/cifs/connect.c
@@ -1,7 +1,7 @@
 /*
  *   fs/cifs/connect.c
  *
- *   Copyright (C) International Business Machines  Corp., 2002,2005
+ *   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
@@ -27,8 +27,13 @@
 #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/version.h>
+#if LINUX_VERSION_CODE > KERNEL_VERSION(2, 5, 0)
+#include <linux/mempool.h>
+#include <linux/pagevec.h>
+#endif
 #include <asm/uaccess.h>
 #include <asm/processor.h>
 #include "cifspdu.h"
@@ -40,16 +45,26 @@
 #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);
+#if LINUX_VERSION_CODE < KERNEL_VERSION(2, 6, 7)
+#define sock_create_kern sock_create
+#endif
+static DECLARE_COMPLETION(cifsd_complete);
+
 extern void SMBNTencrypt(unsigned char *passwd, unsigned char *c8,
 			 unsigned char *p24);
 
+#if LINUX_VERSION_CODE > KERNEL_VERSION(2, 5, 0)
 extern mempool_t *cifs_req_poolp;
+#else /* old 2.4 kernel */
+#ifndef PAGEVEC_SIZE
+#define PAGEVEC_SIZE 14
+#endif
+#endif
 
 struct smb_vol {
 	char *username;
@@ -60,20 +75,28 @@
 	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;
+	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;
@@ -82,7 +105,8 @@
 
 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);
 
@@ -170,14 +194,19 @@
 
 	while ((server->tcpStatus != CifsExiting) && (server->tcpStatus != CifsGood))
 	{
+#if LINUX_VERSION_CODE > KERNEL_VERSION(2, 6, 12)
+		try_to_freeze();
+#endif
 		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) {
+			cFYI(1,("reconnect error %d",rc));
 			msleep(3000);
 		} else {
 			atomic_inc(&tcpSesReconnectCount);
@@ -293,12 +322,12 @@
 	byte_count += total_in_buf2;
 	BCC_LE(pTargetSMB) = cpu_to_le16(byte_count);
 
-	byte_count = be32_to_cpu(pTargetSMB->smb_buf_length);
+	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 = cpu_to_be32(byte_count);
+	pTargetSMB->smb_buf_length = byte_count;
 
 	if(remaining == total_in_buf2) {
 		cFYI(1,("found the last secondary response"));
@@ -323,13 +352,21 @@
 	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;
-
+#if LINUX_VERSION_CODE < KERNEL_VERSION(2, 6, 8)
+	mm_segment_t temp_fs;
+#endif
+
+#if LINUX_VERSION_CODE < KERNEL_VERSION(2, 5, 0)
+	daemonize();
+	sprintf(current->comm,"cifsd");
+#else
 	daemonize("cifsd");
 	allow_signal(SIGKILL);
+#endif
 	current->flags |= PF_MEMALLOC;
 	server->tsk = current;	/* save process info to wake at shutdown */
 	cFYI(1, ("Demultiplex PID: %d", current->pid));
@@ -337,30 +374,42 @@
 	atomic_inc(&tcpSesAllocCount);
 	length = tcpSesAllocCount.counter;
 	write_unlock(&GlobalSMBSeslock);
+	complete(&cifsd_complete);
+#if LINUX_VERSION_CODE > KERNEL_VERSION(2, 6, 10)
 	if(length  > 1) {
 		mempool_resize(cifs_req_poolp,
 			length + cifs_min_rcv,
 			GFP_KERNEL);
 	}
+#endif
+
+#if LINUX_VERSION_CODE < KERNEL_VERSION(2, 6, 8)
+	temp_fs = get_fs();	/* we must turn off socket api parm checking */
+	set_fs(get_ds());
+#endif
 
 	while (server->tcpStatus != CifsExiting) {
+#if LINUX_VERSION_CODE > KERNEL_VERSION(2, 6, 12)
+		if (try_to_freeze())
+			continue;
+#endif
 		if (bigbuf == NULL) {
 			bigbuf = cifs_buf_get();
-			if(bigbuf == NULL) {
-				cERROR(1,("No memory for large SMB response"));
+			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 dirtry large buf, clear its start */
+		} 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 == NULL) {
-				cERROR(1,("No memory for SMB response"));
+			if (!smallbuf) {
+				cERROR(1, ("No memory for SMB response"));
 				msleep(1000);
 				/* retry will check if exiting */
 				continue;
@@ -376,16 +425,21 @@
 		iov.iov_len = 4;
 		smb_msg.msg_control = NULL;
 		smb_msg.msg_controllen = 0;
+#if LINUX_VERSION_CODE < KERNEL_VERSION(2, 6, 8)
+		smb_msg.msg_iov = &iov;
+		smb_msg.msg_iovlen = 1;
 		length =
-		    kernel_recvmsg(csocket, &smb_msg,
+			sock_recvmsg(csocket, &smb_msg, 4 /* RFC1001 len */, 0);
+#else
+		length = kernel_recvmsg(csocket, &smb_msg,
 				 &iov, 1, 4, 0 /* BB see socket.h flags */);
-
-		if(server->tcpStatus == CifsExiting) {
+#endif
+		if (server->tcpStatus == CifsExiting) {
 			break;
 		} else if (server->tcpStatus == CifsNeedReconnect) {
-			cFYI(1,("Reconnect 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)) {
@@ -394,15 +448,19 @@
 				tcpStatus CifsNeedReconnect if server hung */
 			continue;
 		} else if (length <= 0) {
-			if(server->tcpStatus == CifsNew) {
-				cFYI(1,("tcp session abend after SMBnegprot"));
+			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 LINUX_VERSION_CODE > KERNEL_VERSION(2, 6, 12)
+			if (!try_to_freeze() && (length == -EINTR)) {
+#else
+			if (length == -EINTR) {
+#endif
 				cFYI(1,("cifsd thread killed"));
 				break;
 			}
@@ -422,22 +480,32 @@
 			continue;
 		}
 
-		/* the right amount was read from socket - 4 bytes */
+		/* 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);
-		cFYI(1,("rfc1002 length(big endian)0x%x)", pdu_length+4));
+		smb_buffer->smb_buf_length = pdu_length;
+
+		cFYI(1,("rfc1002 length 0x%x)", pdu_length+4));
 
-		temp = (char *) smb_buffer;
-		if (temp[0] == (char) RFC1002_SESSION_KEEP_ALIVE) {
+		if (temp == (char) RFC1002_SESSION_KEEP_ALIVE) {
 			continue; 
-		} else if (temp[0] == (char)RFC1002_POSITIVE_SESSION_RESPONSE) {
+		} else if (temp == (char)RFC1002_POSITIVE_SESSION_RESPONSE) {
 			cFYI(1,("Good RFC 1002 session rsp"));
 			continue;
-		} else if (temp[0] == (char)RFC1002_NEGATIVE_SESSION_RESPONSE) {
+		} 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)",
-				temp[4]));
+				pdu_length));
 			if(server->tcpStatus == CifsNew) {
 				/* if nack on negprot (rather than 
 				ret of smb negprot error) reconnecting
@@ -459,9 +527,10 @@
 				wake_up(&server->response_q);
 				continue;
 			}
-		} else if (temp[0] != (char) 0) {
+		} else if (temp != (char) 0) {
 			cERROR(1,("Unknown RFC 1002 frame"));
-			cifs_dump_mem(" Received Data: ", temp, length);
+			cifs_dump_mem(" Received Data: ", (char *)smb_buffer,
+				      length);
 			cifs_reconnect(server);
 			csocket = server->ssocket;
 			continue;
@@ -481,7 +550,7 @@
 		/* else length ok */
 		reconnect = 0;
 
-		if(pdu_length > MAX_CIFS_HDR_SIZE - 4) {
+		if(pdu_length > MAX_CIFS_SMALL_BUFFER_SIZE - 4) {
 			isLargeBuf = TRUE;
 			memcpy(bigbuf, smallbuf, 4);
 			smb_buffer = bigbuf;
@@ -491,8 +560,13 @@
 		iov.iov_len = pdu_length;
 		for (total_read = 0; total_read < pdu_length; 
 		     total_read += length) {
+#if LINUX_VERSION_CODE < KERNEL_VERSION(2, 6, 8)
+			length = sock_recvmsg(csocket, &smb_msg,
+				pdu_length - total_read, 0);
+#else
 			length = kernel_recvmsg(csocket, &smb_msg, &iov, 1,
 						pdu_length - total_read, 0);
+#endif
 			if((server->tcpStatus == CifsExiting) ||
 			    (length == -EINTR)) {
 				/* then will exit */
@@ -530,8 +604,8 @@
 	
 
 		dump_smb(smb_buffer, length);
-		if (checkSMB (smb_buffer, smb_buffer->Mid, total_read+4)) {
-			cERROR(1, ("Bad SMB Received "));
+		if (checkSMB(smb_buffer, smb_buffer->Mid, total_read+4)) {
+			cifs_dump_mem("Bad SMB: ", smb_buffer, 48);
 			continue;
 		}
 
@@ -551,9 +625,11 @@
 						/* 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 {
@@ -579,6 +655,13 @@
 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;
 			}
 		}
@@ -593,10 +676,16 @@
 					smallbuf = NULL;
 			}
 			wake_up_process(task_to_wake);
-		} else if ((is_valid_oplock_break(smb_buffer) == FALSE)
+		} else if ((is_valid_oplock_break(smb_buffer, server) == FALSE)
 		    && (isMultiRsp == FALSE)) {                          
-			cERROR(1, ("No task to wake, unknown frame rcvd!"));
-			cifs_dump_mem("Received Data is: ",temp,sizeof(struct smb_hdr));
+			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 */
 
@@ -624,6 +713,10 @@
 		sock_release(csocket);
 		server->ssocket = NULL;
 	}
+
+#if LINUX_VERSION_CODE < KERNEL_VERSION(2, 6, 8)
+	set_fs(temp_fs);
+#endif
 	/* buffer usuallly freed in free_mid - need to free it here on exit */
 	if (bigbuf != NULL)
 		cifs_buf_release(bigbuf);
@@ -674,7 +767,7 @@
 		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
@@ -705,13 +798,15 @@
 	write_unlock(&GlobalSMBSeslock);
 
 	kfree(server);
+#if LINUX_VERSION_CODE > KERNEL_VERSION(2, 5, 0)
 	if(length  > 0) {
 		mempool_resize(cifs_req_poolp,
 			length + cifs_min_rcv,
 			GFP_KERNEL);
 	}
+#endif
 	
-	msleep(250);
+	complete_and_exit(&cifsd_complete, 0);
 	return 0;
 }
 
@@ -735,7 +830,9 @@
 			toupper(system_utsname.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;
@@ -744,6 +841,8 @@
 
 	/* 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;
@@ -836,7 +935,7 @@
 				/* go from value to value + temp_len condensing 
 				double commas to singles. Note that this ends up
 				allocating a few bytes too many, which is ok */
-				vol->password = kcalloc(1, temp_len, GFP_KERNEL);
+				vol->password = kzalloc(temp_len, GFP_KERNEL);
 				if(vol->password == NULL) {
 					printk("CIFS: no memory for pass\n");
 					return 1;
@@ -851,7 +950,7 @@
 				}
 				vol->password[j] = 0;
 			} else {
-				vol->password = kcalloc(1, 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;
@@ -867,6 +966,44 @@
 				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)) {
@@ -900,7 +1037,7 @@
 			}
 			/* 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 {
@@ -985,7 +1122,31 @@
 				/* 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 */
@@ -1023,6 +1184,27 @@
 			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) {
@@ -1039,10 +1221,18 @@
 			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) {
@@ -1185,7 +1375,6 @@
 		the helper that resolves tcp names, mount to it, try to 
 		tcon to it unmount it if fail */
 
-	if(referrals)
 		kfree(referrals);
 
 	return rc;
@@ -1242,7 +1431,7 @@
 
 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;
@@ -1257,7 +1446,11 @@
 		} else {
 		/* BB other socket options to set KEEPALIVE, NODELAY? */
 			cFYI(1,("Socket created"));
+#if LINUX_VERSION_CODE > KERNEL_VERSION(2, 5, 0)
 			(*csocket)->sk->sk_allocation = GFP_NOFS; 
+#else
+			(*csocket)->sk->allocation = GFP_NOFS;
+#endif
 		}
 	}
 
@@ -1307,21 +1500,43 @@
 	/* Eventually check for other socket options to change from 
 		the default. sock_setsockopt not used because it expects 
 		user space buffer */
+#if LINUX_VERSION_CODE > KERNEL_VERSION(2, 5, 0)
+	 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;
+#else
+         cFYI(1,("sndbuf %d rcvbuf %d rcvtimeo 0x%lx",(*csocket)->sk->sndbuf,
+                 (*csocket)->sk->rcvbuf, (*csocket)->sk->rcvtimeo));
+        (*csocket)->sk->rcvtimeo = 7 * HZ;
+        /* make the bufsizes depend on wsize/rsize and max requests */
+        if((*csocket)->sk->sndbuf < (200 * 1024))
+                (*csocket)->sk->sndbuf = 200 * 1024;
+        if((*csocket)->sk->rcvbuf < (140 * 1024))
+                (*csocket)->sk->rcvbuf = 140 * 1024;
+#endif
 	/* send RFC1001 sessinit */
-
 	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 = kcalloc(1, 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;
+			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. */
@@ -1340,6 +1555,14 @@
 			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 */
@@ -1365,7 +1588,11 @@
 		} else {
 		/* BB other socket options to set KEEPALIVE, NODELAY? */
 			 cFYI(1,("ipv6 Socket created"));
+#if LINUX_VERSION_CODE > KERNEL_VERSION(2, 5, 0)
 			(*csocket)->sk->sk_allocation = GFP_NOFS;
+#else
+			(*csocket)->sk->allocation = GFP_NOFS;
+#endif
 		}
 	}
 
@@ -1416,7 +1643,11 @@
 	/* Eventually check for other socket options to change from 
 		the default. sock_setsockopt not used because it expects 
 		user space buffer */
+#if LINUX_VERSION_CODE > KERNEL_VERSION(2, 5, 0)
 	(*csocket)->sk->sk_rcvtimeo = 7 * HZ;
+#else
+	(*csocket)->sk->rcvtimeo = 7 * HZ;
+#endif
 		
 	return rc;
 }
@@ -1443,9 +1674,7 @@
 	
 	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);
 		FreeXid(xid);
 		return -EINVAL;
@@ -1456,12 +1685,10 @@
 		cFYI(1, ("Username: %s ", volume_info.username));
 
 	} 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);
 		FreeXid(xid);
 		return -EINVAL;
@@ -1481,9 +1708,7 @@
        
 		if(rc <= 0) {
 			/* we failed translating address */
-			if(volume_info.UNC)
 				kfree(volume_info.UNC);
-			if(volume_info.password)
 				kfree(volume_info.password);
 			FreeXid(xid);
 			return -EINVAL;
@@ -1495,18 +1720,14 @@
 	} 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);
 		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)
+		       ("CIFS mount error: No UNC path (e.g. -o unc=//192.168.1.100/public) specified"));
 			kfree(volume_info.UNC);
-		if(volume_info.password)
 			kfree(volume_info.password);
 		FreeXid(xid);
 		return -EINVAL;
@@ -1520,9 +1741,7 @@
 		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);
 			FreeXid(xid);
 			return -ELIBACC;
@@ -1538,9 +1757,7 @@
 			&sin_server6.sin6_addr,
 			volume_info.username, &srvTcp);
 	else {
-		if(volume_info.UNC)
 			kfree(volume_info.UNC);
-		if(volume_info.password)
 			kfree(volume_info.password);
 		FreeXid(xid);
 		return -EINVAL;
@@ -1548,21 +1765,21 @@
 
 
 	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);
 			FreeXid(xid);
 			return rc;
@@ -1572,9 +1789,7 @@
 		if (srvTcp == NULL) {
 			rc = -ENOMEM;
 			sock_release(csocket);
-			if(volume_info.UNC)
 				kfree(volume_info.UNC);
-			if(volume_info.password)
 				kfree(volume_info.password);
 			FreeXid(xid);
 			return rc;
@@ -1598,27 +1813,26 @@
 			if(rc < 0) {
 				rc = -ENOMEM;
 				sock_release(csocket);
-				if(volume_info.UNC)
 					kfree(volume_info.UNC);
-				if(volume_info.password)
 					kfree(volume_info.password);
 				FreeXid(xid);
 				return rc;
-			} else
+			}
+			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)
+		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;
@@ -1635,39 +1849,65 @@
 			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);
 	}
     
 	/* search for existing tcon to this server share */
 	if (!rc) {
-		if((volume_info.rsize) && (volume_info.rsize <= CIFSMaxBufSize))
+		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 <= CIFSMaxBufSize))
+		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 = CIFSMaxBufSize; /* default */
-		if(cifs_sb->rsize < PAGE_CACHE_SIZE) {
-			cifs_sb->rsize = PAGE_CACHE_SIZE;
-			cERROR(1,("Attempt to set readsize for mount to less than one page (4096)"));
+			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"));
 		}
 		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;
@@ -1679,8 +1919,15 @@
 			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) {
-			cERROR(1,("mounting share using direct i/o"));
+			cFYI(1,("mounting share using direct i/o"));
 			cifs_sb->mnt_cifs_flags |= CIFS_MOUNT_DIRECT_IO;
 		}
 
@@ -1688,12 +1935,13 @@
 		    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)
@@ -1709,7 +1957,6 @@
 							"", cifs_sb->local_nls,
 							cifs_sb->mnt_cifs_flags & 
 							  CIFS_MOUNT_MAP_SPECIAL_CHR);
-					if(volume_info.UNC)
 						kfree(volume_info.UNC);
 					FreeXid(xid);
 					return -ENODEV;
@@ -1722,6 +1969,7 @@
 				if (!rc) {
 					atomic_inc(&pSesInfo->inUse);
 					tcon->retry = volume_info.retry;
+					tcon->nocase = volume_info.nocase;
 				}
 			}
 		}
@@ -1732,8 +1980,9 @@
 		} else
 			sb->s_maxbytes = (u64) 1 << 31;	/* 2 GB */
 	}
-
+#if LINUX_VERSION_CODE > KERNEL_VERSION(2, 6, 10)
 	sb->s_time_gran = 100;
+#endif
 
 /* on error free sesinfo and tcon struct if needed */
 	if (rc) {
@@ -1743,8 +1992,10 @@
 			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 */
@@ -1757,8 +2008,10 @@
 					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);
@@ -1770,26 +2023,66 @@
 		cifs_sb->tcon = tcon;
 		tcon->ses = pSesInfo;
 
-		/* do not care if following two calls succeed - informational only */
+		/* 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)) {
-				if(!volume_info.no_psx_acl) {
-					if(CIFS_UNIX_POSIX_ACL_CAP & 
-					   le64_to_cpu(tcon->fsUnixInfo.Capability))
-						cFYI(1,("server negotiated posix acl support"));
+				__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) {
+#if LINUX_VERSION_CODE > KERNEL_VERSION(2, 5, 0)
+					cFYI(1,("negotiated posix acl support"));
 						sb->s_flags |= MS_POSIXACL;
+#else
+					cFYI(1,("ACLs not supported"));
+#endif
+				}
+
+				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);
 	FreeXid(xid);
 	return rc;
@@ -1797,7 +2090,7 @@
 
 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;
@@ -1814,7 +2107,7 @@
 	__u32 capabilities;
 	__u16 count;
 
-	cFYI(1, ("In sesssetup "));
+	cFYI(1, ("In sesssetup"));
 	if(ses == NULL)
 		return -EINVAL;
 	user = ses->userName;
@@ -1830,6 +2123,7 @@
 	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);
@@ -1854,15 +2148,15 @@
 	pSMB->req_no_secext.Capabilities = cpu_to_le32(capabilities);
 
 	pSMB->req_no_secext.CaseInsensitivePasswordLength = 
-		cpu_to_le16(CIFS_SESSION_KEY_SIZE);
+		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 *) 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 */
@@ -1870,35 +2164,35 @@
 			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);
 		/* 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, system_utsname.release,
+		    cifs_strtoUCS((__le16 *) bcc_ptr, system_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;
@@ -1964,11 +2258,13 @@
 /* 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 = kcalloc(1, 2 * (len + 1), GFP_KERNEL);
+				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,
-					   (wchar_t *)bcc_ptr, len,nls_codepage);
+					   (__le16 *)bcc_ptr, len,nls_codepage);
 				bcc_ptr += 2 * (len + 1);
 				remaining_words -= len + 1;
 				ses->serverOS[2 * len] = 0;
@@ -1976,11 +2272,12 @@
 				if (remaining_words > 0) {
 					len = UniStrnlen((wchar_t *)bcc_ptr,
 							 remaining_words-1);
-					ses->serverNOS = kcalloc(1, 2 * (len + 1),GFP_KERNEL);
+					kfree(ses->serverNOS);
+					ses->serverNOS = kzalloc(2 * (len + 1),GFP_KERNEL);
 					if(ses->serverNOS == NULL)
 						goto sesssetup_nomem;
 					cifs_strfromUCS_le(ses->serverNOS,
-							   (wchar_t *)bcc_ptr,len,nls_codepage);
+							   (__le16 *)bcc_ptr,len,nls_codepage);
 					bcc_ptr += 2 * (len + 1);
 					ses->serverNOS[2 * len] = 0;
 					ses->serverNOS[1 + (2 * len)] = 0;
@@ -1993,34 +2290,42 @@
 					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) */
+						if(ses->serverDomain)
+							kfree(ses->serverDomain);
 						ses->serverDomain =
-						    kcalloc(1, 2*(len+1),GFP_KERNEL);
+						    kzalloc(2*(len+1),GFP_KERNEL);
 						if(ses->serverDomain == NULL)
 							goto sesssetup_nomem;
 						cifs_strfromUCS_le(ses->serverDomain,
-						     (wchar_t *)bcc_ptr,len,nls_codepage);
+						     (__le16 *)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
+					else {
+						if(ses->serverDomain)
+							kfree(ses->serverDomain);
 						ses->serverDomain = 
-							kcalloc(1, 2, GFP_KERNEL);
+							kzalloc(2, GFP_KERNEL);
+					}
 				} else {	/* no room so create dummy domain and NOS string */
 					/* if these kcallocs fail not much we
 					   can do, but better to not fail the
 					   sesssetup itself */
+					kfree(ses->serverDomain);
 					ses->serverDomain =
-					    kcalloc(1, 2, GFP_KERNEL);
+					    kzalloc(2, GFP_KERNEL);
+					kfree(ses->serverNOS);
 					ses->serverNOS =
-					    kcalloc(1, 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)) {
-					ses->serverOS = kcalloc(1, len + 1,GFP_KERNEL);
+					kfree(ses->serverOS);
+					ses->serverOS = kzalloc(len + 1,GFP_KERNEL);
 					if(ses->serverOS == NULL)
 						goto sesssetup_nomem;
 					strncpy(ses->serverOS,bcc_ptr, len);
@@ -2030,7 +2335,8 @@
 					bcc_ptr++;
 
 					len = strnlen(bcc_ptr, 1024);
-					ses->serverNOS = kcalloc(1, len + 1,GFP_KERNEL);
+					kfree(ses->serverNOS);
+					ses->serverNOS = kzalloc(len + 1,GFP_KERNEL);
 					if(ses->serverNOS == NULL)
 						goto sesssetup_nomem;
 					strncpy(ses->serverNOS, bcc_ptr, len);
@@ -2039,7 +2345,9 @@
 					bcc_ptr++;
 
 					len = strnlen(bcc_ptr, 1024);
-					ses->serverDomain = kcalloc(1, len + 1,GFP_KERNEL);
+					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);
@@ -2071,270 +2379,6 @@
 }
 
 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;
-	char *domain;
-	int rc = 0;
-	int remaining_words = 0;
-	int bytes_returned = 0;
-	int len;
-	__u32 capabilities;
-	__u16 count;
-
-	cFYI(1, ("In spnego sesssetup "));
-	if(ses == NULL)
-		return -EINVAL;
-	user = ses->userName;
-	domain = ses->domainName;
-
-	smb_buffer = cifs_buf_get();
-	if (smb_buffer == NULL) {
-		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;
-
-	capabilities = CAP_LARGE_FILES | CAP_NT_SMBS | CAP_LEVEL_II_OPLOCKS |
-	    CAP_EXTENDED_SECURITY;
-	if (ses->capabilities & CAP_UNICODE) {
-		smb_buffer->Flags2 |= SMBFLG2_UNICODE;
-		capabilities |= CAP_UNICODE;
-	}
-	if (ses->capabilities & CAP_STATUS32) {
-		smb_buffer->Flags2 |= SMBFLG2_ERR_STATUS;
-		capabilities |= CAP_STATUS32;
-	}
-	if (ses->capabilities & CAP_DFS) {
-		smb_buffer->Flags2 |= SMBFLG2_DFS;
-		capabilities |= CAP_DFS;
-	}
-	pSMB->req.Capabilities = cpu_to_le32(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, system_utsname.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, system_utsname.release);
-		bcc_ptr += strlen(system_utsname.release) + 1;
-		strcpy(bcc_ptr, CIFS_NETWORK_OPSYS);
-		bcc_ptr += strlen(CIFS_NETWORK_OPSYS) + 1;
-	}
-	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 (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)) {
-		__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"));	/* 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)
-				&& (blob_len <
-				    pSMBr->resp.ByteCount))) {
-				if (pSMBr->resp.hdr.WordCount == 4) {
-					bcc_ptr +=
-					    blob_len;
-					cFYI(1,
-					     ("Security Blob Length %d ",
-					      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 =
-					    kcalloc(1, 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 =
-						    kcalloc(1, 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);	
-                            /* last string is not always null terminated (for e.g. for Windows XP & 2000) */
-							ses->serverDomain = kcalloc(1, 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 =
-							    kcalloc(1, 2,GFP_KERNEL);
-					} else {	/* no room so create dummy domain and NOS string */
-						ses->serverDomain = kcalloc(1, 2, GFP_KERNEL);
-						ses->serverNOS = kcalloc(1, 2, GFP_KERNEL);
-					}
-				} else {	/* ASCII */
-
-					len = strnlen(bcc_ptr, 1024);
-					if (((long) bcc_ptr + len) - (long)
-					    pByteArea(smb_buffer_response)
-					    <= BCC(smb_buffer_response)) {
-						ses->serverOS = kcalloc(1, 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 = kcalloc(1, len + 1,GFP_KERNEL);
-						strncpy(ses->serverNOS, bcc_ptr, len);
-						bcc_ptr += len;
-						bcc_ptr[0] = 0;
-						bcc_ptr++;
-
-						len = strnlen(bcc_ptr, 1024);
-						ses->serverDomain = kcalloc(1, 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
 CIFSNTLMSSPNegotiateSessSetup(unsigned int xid,
 			      struct cifsSesInfo *ses, int * pNTLMv2_flag,
 			      const struct nls_table *nls_codepage)
@@ -2355,7 +2399,7 @@
 	__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;
@@ -2371,6 +2415,8 @@
 	/* 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);
 
@@ -2403,12 +2449,13 @@
 	SecurityBlob->MessageType = NtLmNegotiate;
 	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)
 		negotiate_flags |= NTLMSSP_NEGOTIATE_SIGN;
-	if(ntlmv2_support)
-		negotiate_flags |= NTLMSSP_NEGOTIATE_NTLMV2;
+/*	if(ntlmv2_support)
+		negotiate_flags |= NTLMSSP_NEGOTIATE_NTLMV2;*/
 	/* setup pointers to domain name and workstation name */
 	bcc_ptr += SecurityBlobLength;
 
@@ -2416,26 +2463,11 @@
 	SecurityBlob->WorkstationName.Length = 0;
 	SecurityBlob->WorkstationName.MaximumLength = 0;
 
-	if (domain == NULL) {
+	/* 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;
-	} else {
-		__u16 len;
-		negotiate_flags |= NTLMSSP_NEGOTIATE_DOMAIN_SUPPLIED;
-		strncpy(bcc_ptr, domain, 63);
-		len = strnlen(domain, 64);
-		SecurityBlob->DomainName.MaximumLength =
-		    cpu_to_le16(len);
-		SecurityBlob->DomainName.Buffer =
-		    cpu_to_le32((long) &SecurityBlob->
-				DomainString -
-				(long) &SecurityBlob->Signature);
-		bcc_ptr += len;
-		SecurityBlobLength += len;
-		SecurityBlob->DomainName.Length =
-		    cpu_to_le16(len);
-	}
 	if (ses->capabilities & CAP_UNICODE) {
 		if ((long) bcc_ptr % 2) {
 			*bcc_ptr = 0;
@@ -2443,16 +2475,16 @@
 		}
 
 		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, system_utsname.release, 32,
+		    cifs_strtoUCS((__le16 *) bcc_ptr, system_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;
@@ -2505,7 +2537,7 @@
 			      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)
 				&& (blob_len <
@@ -2513,17 +2545,17 @@
 
 				if (pSMBr->resp.hdr.WordCount == 4) {
 					bcc_ptr += blob_len;
-					cFYI(1,
-					     ("Security Blob Length %d ",
+					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 & cpu_to_le32(NTLMSSP_NEGOTIATE_NTLMV2))
+				if(SecurityBlob2->NegotiateFlags & 
+					cpu_to_le32(NTLMSSP_NEGOTIATE_NTLMV2))
 					*pNTLMv2_flag = TRUE;
 
 				if((SecurityBlob2->NegotiateFlags & 
@@ -2553,10 +2585,12 @@
 /* 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 =
-					    kcalloc(1, 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);
@@ -2568,12 +2602,13 @@
 								 bcc_ptr,
 								 remaining_words
 								 - 1);
+						kfree(ses->serverNOS);
 						ses->serverNOS =
-						    kcalloc(1, 2 * (len + 1),
+						    kzalloc(2 * (len + 1),
 							    GFP_KERNEL);
 						cifs_strfromUCS_le(ses->
 								   serverNOS,
-								   (wchar_t *)
+								   (__le16 *)
 								   bcc_ptr,
 								   len,
 								   nls_codepage);
@@ -2585,48 +2620,47 @@
 						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 =
-							    kcalloc(1, 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 =
-							    kcalloc(1, 2,
+							    kzalloc(2,
 								    GFP_KERNEL);
+						}
 					} else {	/* no room so create dummy domain and NOS string */
+						kfree(ses->serverDomain);
 						ses->serverDomain =
-						    kcalloc(1, 2, GFP_KERNEL);
+						    kzalloc(2, GFP_KERNEL);
+						kfree(ses->serverNOS);
 						ses->serverNOS =
-						    kcalloc(1, 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 =
-						    kcalloc(1, len + 1,
+						    kzalloc(len + 1,
 							    GFP_KERNEL);
 						strncpy(ses->serverOS,
 							bcc_ptr, len);
@@ -2636,8 +2670,9 @@
 						bcc_ptr++;
 
 						len = strnlen(bcc_ptr, 1024);
+						kfree(ses->serverNOS);
 						ses->serverNOS =
-						    kcalloc(1, len + 1,
+						    kzalloc(len + 1,
 							    GFP_KERNEL);
 						strncpy(ses->serverNOS, bcc_ptr, len);
 						bcc_ptr += len;
@@ -2645,8 +2680,9 @@
 						bcc_ptr++;
 
 						len = strnlen(bcc_ptr, 1024);
+						kfree(ses->serverDomain);
 						ses->serverDomain =
-						    kcalloc(1, len + 1,
+						    kzalloc(len + 1,
 							    GFP_KERNEL);
 						strncpy(ses->serverDomain, bcc_ptr, len);	
 						bcc_ptr += len;
@@ -2654,7 +2690,7 @@
 						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 {
@@ -2666,7 +2702,7 @@
 		}
 	} else {
 		cERROR(1,
-		       (" Invalid Word count %d: ",
+		       (" Invalid Word count %d:",
 			smb_buffer_response->WordCount));
 		rc = -EIO;
 	}
@@ -2713,6 +2749,8 @@
 	/* 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;
@@ -2768,14 +2806,14 @@
 	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) {
@@ -2784,7 +2822,7 @@
 			SecurityBlob->DomainName.MaximumLength = 0;
 		} else {
 			__u16 len =
-			    cifs_strtoUCS((wchar_t *) bcc_ptr, domain, 64,
+			    cifs_strtoUCS((__le16 *) bcc_ptr, domain, 64,
 					  nls_codepage);
 			len *= 2;
 			SecurityBlob->DomainName.MaximumLength =
@@ -2802,7 +2840,7 @@
 			SecurityBlob->UserName.MaximumLength = 0;
 		} else {
 			__u16 len =
-			    cifs_strtoUCS((wchar_t *) bcc_ptr, user, 64,
+			    cifs_strtoUCS((__le16 *) bcc_ptr, user, 64,
 					  nls_codepage);
 			len *= 2;
 			SecurityBlob->UserName.MaximumLength =
@@ -2815,7 +2853,7 @@
 			    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);
@@ -2828,16 +2866,16 @@
 			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, system_utsname.release, 32,
+		    cifs_strtoUCS((__le16 *) bcc_ptr, system_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;
@@ -2947,10 +2985,12 @@
 /* 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 =
-					    kcalloc(1, 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);
@@ -2962,12 +3002,13 @@
 								 bcc_ptr,
 								 remaining_words
 								 - 1);
+						kfree(ses->serverNOS);
 						ses->serverNOS =
-						    kcalloc(1, 2 * (len + 1),
+						    kzalloc(2 * (len + 1),
 							    GFP_KERNEL);
 						cifs_strfromUCS_le(ses->
 								   serverNOS,
-								   (wchar_t *)
+								   (__le16 *)
 								   bcc_ptr,
 								   len,
 								   nls_codepage);
@@ -2978,15 +3019,17 @@
 						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 =
-							    kcalloc(1, 2 *
+							    kzalloc(2 *
 								    (len +
 								     1),
 								    GFP_KERNEL);
 							cifs_strfromUCS_le
 							    (ses->
 							     serverDomain,
-							     (wchar_t *)
+							     (__le16 *)
 							     bcc_ptr, len,
 							     nls_codepage);
 							bcc_ptr +=
@@ -3003,18 +3046,26 @@
 									  len)]
 							    = 0;
 						} /* else no more room so create dummy domain string */
-						else
-							ses->serverDomain = kcalloc(1, 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 = kcalloc(1, 2, GFP_KERNEL);
-						ses->serverNOS = kcalloc(1, 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 = kcalloc(1, 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;
@@ -3022,14 +3073,17 @@
 						bcc_ptr++;
 
 						len = strnlen(bcc_ptr, 1024);
-						ses->serverNOS = kcalloc(1, 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 = kcalloc(1, 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;
@@ -3084,17 +3138,48 @@
 
 	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];
+	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) {
@@ -3106,11 +3191,12 @@
 	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;
 	}
@@ -3138,12 +3224,11 @@
 			if ((bcc_ptr + (2 * length)) -
 			     pByteArea(smb_buffer_response) <=
 			    BCC(smb_buffer_response)) {
-				if(tcon->nativeFileSystem)
 					kfree(tcon->nativeFileSystem);
 				tcon->nativeFileSystem =
-				    kcalloc(1, 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 */
@@ -3156,16 +3241,18 @@
 			if ((bcc_ptr + length) -
 			    pByteArea(smb_buffer_response) <=
 			    BCC(smb_buffer_response)) {
-				if(tcon->nativeFileSystem)
 					kfree(tcon->nativeFileSystem);
 				tcon->nativeFileSystem =
-				    kcalloc(1, length + 1, GFP_KERNEL);
+				    kzalloc(length + 1, GFP_KERNEL);
 				strncpy(tcon->nativeFileSystem, bcc_ptr,
 					length);
 			}
 			/* else do not bother copying these informational fields */
 		}
+		if(smb_buffer_response->WordCount == 3)
 		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 */
@@ -3205,8 +3292,10 @@
 				return 0;
 			} else if (rc == -ESHUTDOWN) {
 				cFYI(1,("Waking up socket by sending it signal"));
-				if(cifsd_task)
+				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 */
@@ -3215,10 +3304,13 @@
 	}
 	
 	cifs_sb->tcon = NULL;
-	if (ses) {
+	if (ses)
+#if LINUX_VERSION_CODE < KERNEL_VERSION(2, 6, 14)
 		set_current_state(TASK_INTERRUPTIBLE);
 		schedule_timeout(HZ / 2);
-	}
+#else
+		schedule_timeout_interruptible(msecs_to_jiffies(500));
+#endif
 	if (ses)
 		sesInfoFree(ses);
 
@@ -3230,7 +3322,7 @@
 					   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;
 
@@ -3262,18 +3354,17 @@
 			pSesInfo->server->secMode,
 			pSesInfo->server->capabilities,
 			pSesInfo->server->timeZone));
-		if (extended_security
+		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,
--- linux-2.6.13/fs/cifs/dir.c
+++ linux-2.6.13/fs/cifs/dir.c
@@ -3,7 +3,7 @@
  *
  *   vfs operations that deal with dentries
  * 
- *   Copyright (C) International Business Machines  Corp., 2002,2003
+ *   Copyright (C) International Business Machines  Corp., 2002,2005
  *   Author(s): Steve French (sfrench@us.ibm.com)
  *
  *   This library is free software; you can redistribute it and/or modify
@@ -23,13 +23,19 @@
 #include <linux/fs.h>
 #include <linux/stat.h>
 #include <linux/slab.h>
+#include <linux/version.h>
+#if LINUX_VERSION_CODE > KERNEL_VERSION(2, 5, 0)
 #include <linux/namei.h>
+#endif
 #include "cifsfs.h"
 #include "cifspdu.h"
 #include "cifsglob.h"
 #include "cifsproto.h"
 #include "cifs_debug.h"
 #include "cifs_fs_sb.h"
+#if LINUX_VERSION_CODE < KERNEL_VERSION(2,6,9)
+#include <linux/ctype.h>
+#endif
 
 void
 renew_parental_timestamps(struct dentry *direntry)
@@ -48,12 +54,14 @@
 	struct dentry *temp;
 	int namelen = 0;
 	char *full_path;
+	char dirsep;
 
 	if(direntry == NULL)
 		return NULL;  /* not much we can do if dentry is freed and
 		we need to reopen the file after it was closed implicitly
 		when the server crashed */
 
+	dirsep = CIFS_DIR_SEP(CIFS_SB(direntry->d_sb));
 cifs_bp_rename_retry:
 	for (temp = direntry; !IS_ROOT(temp);) {
 		namelen += (1 + temp->d_name.len);
@@ -74,7 +82,7 @@
 		if (namelen < 0) {
 			break;
 		} else {
-			full_path[namelen] = '\\';
+			full_path[namelen] = dirsep;
 			strncpy(full_path + namelen + 1, temp->d_name.name,
 				temp->d_name.len);
 			cFYI(0, (" name: %s ", full_path + namelen));
@@ -111,11 +119,15 @@
 	full_path[namelen+2] = 0;
 BB remove above eight lines BB */
 
-/* Inode operations in similar order to how they appear in the Linux file fs.h */
+/* Inode operations in similar order to how they appear in Linux file fs.h */
 
 int
+#if LINUX_VERSION_CODE > KERNEL_VERSION(2, 5, 0)
 cifs_create(struct inode *inode, struct dentry *direntry, int mode,
 		struct nameidata *nd)
+#else
+cifs_create(struct inode *inode, struct dentry *direntry, int mode)
+#endif
 {
 	int rc = -ENOENT;
 	int xid;
@@ -137,32 +149,34 @@
 	cifs_sb = CIFS_SB(inode->i_sb);
 	pTcon = cifs_sb->tcon;
 
-	down(&direntry->d_sb->s_vfs_rename_sem);
 	full_path = build_path_from_dentry(direntry);
-	up(&direntry->d_sb->s_vfs_rename_sem);
 	if(full_path == NULL) {
 		FreeXid(xid);
 		return -ENOMEM;
 	}
 
-	if(nd) {
-		if ((nd->intent.open.flags & O_ACCMODE) == O_RDONLY)
-			desiredAccess = GENERIC_READ;
-		else if ((nd->intent.open.flags & O_ACCMODE) == O_WRONLY) {
-			desiredAccess = GENERIC_WRITE;
+#if LINUX_VERSION_CODE > KERNEL_VERSION(2, 5, 0)
+	if(nd && (nd->flags & LOOKUP_OPEN)) {
+#if LINUX_VERSION_CODE == KERNEL_VERSION(2,6,5) /* SUSE included Lustre patch */
+		int oflags = nd->intent.it_flags;
+#else
+		int oflags = nd->intent.open.flags;
+#endif
+
+		desiredAccess = 0;
+		if (oflags & FMODE_READ)
+			desiredAccess |= GENERIC_READ;
+		if (oflags & FMODE_WRITE) {
+			desiredAccess |= GENERIC_WRITE;
+			if (!(oflags & FMODE_READ))
 			write_only = TRUE;
-		} else if ((nd->intent.open.flags & O_ACCMODE) == O_RDWR) {
-			/* GENERIC_ALL is too much permission to request */
-			/* can cause unnecessary access denied on create */
-			/* desiredAccess = GENERIC_ALL; */
-			desiredAccess = GENERIC_READ | GENERIC_WRITE;
 		}
 
-		if((nd->intent.open.flags & (O_CREAT | O_EXCL)) == (O_CREAT | O_EXCL))
+		if((oflags & (O_CREAT | O_EXCL)) == (O_CREAT | O_EXCL))
 			disposition = FILE_CREATE;
-		else if((nd->intent.open.flags & (O_CREAT | O_TRUNC)) == (O_CREAT | O_TRUNC))
+		else if((oflags & (O_CREAT | O_TRUNC)) == (O_CREAT | O_TRUNC))
 			disposition = FILE_OVERWRITE_IF;
-		else if((nd->intent.open.flags & O_CREAT) == O_CREAT)
+		else if((oflags & O_CREAT) == O_CREAT)
 			disposition = FILE_OPEN_IF;
 		else {
 			cFYI(1,("Create flag not set in create function"));
@@ -172,6 +186,9 @@
 	/* BB add processing to set equivalent of mode - e.g. via CreateX with ACLs */
 	if (oplockEnabled)
 		oplock = REQ_OPLOCK;
+#else
+	desiredAccess = GENERIC_WRITE;
+#endif
 
 	buf = kmalloc(sizeof(FILE_ALL_INFO),GFP_KERNEL);
 	if(buf == NULL) {
@@ -179,13 +196,23 @@
 		FreeXid(xid);
 		return -ENOMEM;
 	}
-
+	if (cifs_sb->tcon->ses->capabilities & CAP_NT_SMBS) 
 	rc = CIFSSMBOpen(xid, pTcon, full_path, disposition,
 			 desiredAccess, CREATE_NOT_DIR,
 			 &fileHandle, &oplock, buf, cifs_sb->local_nls,
 			 cifs_sb->mnt_cifs_flags & CIFS_MOUNT_MAP_SPECIAL_CHR);
+	else
+		rc = -EIO; /* no NT SMB support fall into legacy open below */
+
+	if(rc == -EIO) {
+		/* old server, retry the open legacy style */
+		rc = SMBLegacyOpen(xid, pTcon, full_path, disposition,
+			desiredAccess, CREATE_NOT_DIR,
+			&fileHandle, &oplock, buf, cifs_sb->local_nls,
+			cifs_sb->mnt_cifs_flags & CIFS_MOUNT_MAP_SPECIAL_CHR);
+	} 
 	if (rc) {
-		cFYI(1, ("cifs_create returned 0x%x ", rc));
+		cFYI(1, ("cifs_create returned 0x%x", rc));
 	} else {
 		/* If Open reported that we actually created a file
 		then we now have to set the mode if possible */
@@ -193,8 +220,8 @@
 			(oplock & CIFS_CREATE_ACTION))
 			if(cifs_sb->mnt_cifs_flags & CIFS_MOUNT_SET_UID) {
 				CIFSSMBUnixSetPerms(xid, pTcon, full_path, mode,
-					(__u64)current->euid,
-					(__u64)current->egid,
+					(__u64)current->fsuid,
+					(__u64)current->fsgid,
 					0 /* dev */,
 					cifs_sb->local_nls, 
 					cifs_sb->mnt_cifs_flags & 
@@ -209,7 +236,7 @@
 						CIFS_MOUNT_MAP_SPECIAL_CHR);
 			}
 		else {
-			/* BB implement via Windows security descriptors */
+			/* BB implement mode setting via Windows security descriptors */
 			/* eg CIFSSMBWinSetPerms(xid,pTcon,full_path,mode,-1,-1,local_nls);*/
 			/* could set r/o dos attribute if mode & 0222 == 0 */
 		}
@@ -221,28 +248,38 @@
 		else {
 			rc = cifs_get_inode_info(&newinode, full_path,
 						 buf, inode->i_sb,xid);
-			if(newinode)
+			if(newinode) {
 				newinode->i_mode = mode;
+				if((oplock & CIFS_CREATE_ACTION) &&
+				  (cifs_sb->mnt_cifs_flags & 
+				     CIFS_MOUNT_SET_UID)) {
+					newinode->i_uid = current->fsuid;
+					newinode->i_gid = current->fsgid;
+				}
+			}
 		}
 
 		if (rc != 0) {
-			cFYI(1,("Create worked but get_inode_info failed with rc = %d",
+			cFYI(1,
+			     ("Create worked but get_inode_info failed rc = %d",
 			      rc));
 		} else {
+			if (pTcon->nocase)
+				direntry->d_op = &cifs_ci_dentry_ops;
+			else
 			direntry->d_op = &cifs_dentry_ops;
 			d_instantiate(direntry, newinode);
 		}
+#if LINUX_VERSION_CODE > KERNEL_VERSION(2, 5, 0)
 		if((nd->flags & LOOKUP_OPEN) == FALSE) {
 			/* mknod case - do not leave file open */
 			CIFSSMBClose(xid, pTcon, fileHandle);
 		} else if(newinode) {
 			pCifsFile =
-			   kmalloc(sizeof (struct cifsFileInfo), GFP_KERNEL);
+			   kzalloc(sizeof (struct cifsFileInfo), GFP_KERNEL);
 			
 			if(pCifsFile == NULL)
 				goto cifs_create_out;
-			memset((char *)pCifsFile, 0,
-			       sizeof (struct cifsFileInfo));
 			pCifsFile->netfid = fileHandle;
 			pCifsFile->pid = current->tgid;
 			pCifsFile->pInode = newinode;
@@ -273,6 +310,9 @@
 			}
 			write_unlock(&GlobalSMBSeslock);
 		}
+#else /* 2.4 does not pass open flags so must reopen on cifs_open */
+		CIFSSMBClose(xid, pTcon, fileHandle);
+#endif
 	} 
 cifs_create_out:
 	kfree(buf);
@@ -281,7 +321,8 @@
 	return rc;
 }
 
-int cifs_mknod(struct inode *inode, struct dentry *direntry, int mode, dev_t device_number) 
+int cifs_mknod(struct inode *inode, struct dentry *direntry, int mode, 
+		dev_t device_number) 
 {
 	int rc = -EPERM;
 	int xid;
@@ -290,24 +331,23 @@
 	char *full_path = NULL;
 	struct inode * newinode = NULL;
 
+#if LINUX_VERSION_CODE > KERNEL_VERSION(2, 5, 0)
 	if (!old_valid_dev(device_number))
 		return -EINVAL;
+#endif
 
 	xid = GetXid();
 
 	cifs_sb = CIFS_SB(inode->i_sb);
 	pTcon = cifs_sb->tcon;
 
-	down(&direntry->d_sb->s_vfs_rename_sem);
 	full_path = build_path_from_dentry(direntry);
-	up(&direntry->d_sb->s_vfs_rename_sem);
 	if(full_path == NULL)
 		rc = -ENOMEM;
-	
-	if (full_path && (pTcon->ses->capabilities & CAP_UNIX)) {
+	else if (pTcon->ses->capabilities & CAP_UNIX) {
 		if(cifs_sb->mnt_cifs_flags & CIFS_MOUNT_SET_UID) {
 			rc = CIFSSMBUnixSetPerms(xid, pTcon, full_path,
-				mode,(__u64)current->euid,(__u64)current->egid,
+				mode,(__u64)current->fsuid,(__u64)current->fsgid,
 				device_number, cifs_sb->local_nls,
 				cifs_sb->mnt_cifs_flags & 
 					CIFS_MOUNT_MAP_SPECIAL_CHR);
@@ -322,10 +362,80 @@
 		if(!rc) {
 			rc = cifs_get_inode_info_unix(&newinode, full_path,
 						inode->i_sb,xid);
+			if (pTcon->nocase)
+				direntry->d_op = &cifs_ci_dentry_ops;
+			else
 			direntry->d_op = &cifs_dentry_ops;
 			if(rc == 0)
 				d_instantiate(direntry, newinode);
 		}
+	} else {
+		if(cifs_sb->mnt_cifs_flags & CIFS_MOUNT_UNX_EMUL) {
+			int oplock = 0;
+			u16 fileHandle;
+			FILE_ALL_INFO * buf;
+
+			cFYI(1,("sfu compat create special file"));
+
+			buf = kmalloc(sizeof(FILE_ALL_INFO),GFP_KERNEL);
+			if(buf == NULL) {
+				kfree(full_path);
+				FreeXid(xid);
+				return -ENOMEM;
+			}
+
+			rc = CIFSSMBOpen(xid, pTcon, full_path,
+					 FILE_CREATE, /* fail if exists */
+					 GENERIC_WRITE /* BB would 
+					  WRITE_OWNER | WRITE_DAC be better? */,
+					 /* Create a file and set the
+					    file attribute to SYSTEM */
+					 CREATE_NOT_DIR | CREATE_OPTION_SPECIAL,
+					 &fileHandle, &oplock, buf,
+					 cifs_sb->local_nls,
+					 cifs_sb->mnt_cifs_flags & 
+					    CIFS_MOUNT_MAP_SPECIAL_CHR);
+
+			/* BB FIXME - add handling for backlevel servers
+			   which need legacy open and check for all
+			   calls to SMBOpen for fallback to 
+			   SMBLeagcyOpen */
+			if(!rc) {
+				/* BB Do not bother to decode buf since no
+				   local inode yet to put timestamps in,
+				   but we can reuse it safely */
+				int bytes_written;
+				struct win_dev *pdev;
+				pdev = (struct win_dev *)buf;
+				if(S_ISCHR(mode)) {
+					memcpy(pdev->type, "IntxCHR", 8);
+					pdev->major =
+					      cpu_to_le64(MAJOR(device_number));
+					pdev->minor = 
+					      cpu_to_le64(MINOR(device_number));
+					rc = CIFSSMBWrite(xid, pTcon,
+						fileHandle,
+						sizeof(struct win_dev),
+						0, &bytes_written, (char *)pdev,
+						NULL, 0);
+				} else if(S_ISBLK(mode)) {
+					memcpy(pdev->type, "IntxBLK", 8);
+					pdev->major =
+					      cpu_to_le64(MAJOR(device_number));
+					pdev->minor =
+					      cpu_to_le64(MINOR(device_number));
+					rc = CIFSSMBWrite(xid, pTcon,
+						fileHandle,
+						sizeof(struct win_dev),
+						0, &bytes_written, (char *)pdev,
+						NULL, 0);
+				} /* else if(S_ISFIFO */
+				CIFSSMBClose(xid, pTcon, fileHandle);
+				d_drop(direntry);
+			}
+			kfree(buf);
+			/* add code here to set EAs */
+		}
 	}
 
 	kfree(full_path);
@@ -357,6 +467,20 @@
 	cifs_sb = CIFS_SB(parent_dir_inode->i_sb);
 	pTcon = cifs_sb->tcon;
 
+	/*
+	 * Don't allow the separator character in a path component.
+	 * The VFS will not allow "/", but "\" is allowed by posix.
+	 */
+	if (!(cifs_sb->mnt_cifs_flags & CIFS_MOUNT_POSIX_PATHS)) {
+		int i;
+		for (i = 0; i < direntry->d_name.len; i++)
+			if (direntry->d_name.name[i] == '\\') {
+				cFYI(1, ("Invalid file name"));
+				FreeXid(xid);
+				return ERR_PTR(-EINVAL);
+			}
+	}
+
 	/* can not grab the rename sem here since it would
 	deadlock in the cases (beginning of sys_rename itself)
 	in which we already have the sb rename sem */
@@ -382,15 +506,26 @@
 					 parent_dir_inode->i_sb,xid);
 
 	if ((rc == 0) && (newInode != NULL)) {
+		if (pTcon->nocase)
+			direntry->d_op = &cifs_ci_dentry_ops;
+		else
 		direntry->d_op = &cifs_dentry_ops;
 		d_add(direntry, newInode);
 
-		/* since paths are not looked up by component - the parent directories are presumed to be good here */
+		/* since paths are not looked up by component - the parent 
+		   directories are presumed to be good here */
 		renew_parental_timestamps(direntry);
 
 	} else if (rc == -ENOENT) {
 		rc = 0;
+		direntry->d_time = jiffies;
+		if (pTcon->nocase)
+			direntry->d_op = &cifs_ci_dentry_ops;
+		else
+			direntry->d_op = &cifs_dentry_ops;
 		d_add(direntry, NULL);
+	/*	if it was once a directory (but how can we tell?) we could do  
+			shrink_dcache_parent(direntry); */
 	} else {
 		cERROR(1,("Error 0x%x on cifs_get_inode_info in lookup of %s",
 			   rc,full_path));
@@ -409,20 +544,19 @@
 {
 	int isValid = 1;
 
-/*	lock_kernel(); *//* surely we do not want to lock the kernel for a whole network round trip which could take seconds */
-
 	if (direntry->d_inode) {
 		if (cifs_revalidate(direntry)) {
-			/* unlock_kernel(); */
 			return 0;
 		}
 	} else {
-		cFYI(1,
-		     ("In cifs_d_revalidate with no inode but name = %s and dentry 0x%p",
-		      direntry->d_name.name, direntry));
+		cFYI(1, ("neg dentry 0x%p name = %s",
+			 direntry, direntry->d_name.name));
+		if(time_after(jiffies, direntry->d_time + HZ) || 
+			!lookupCacheEnabled) {
+			d_drop(direntry);
+			isValid = 0;
+		} 
 	}
-
-/*    unlock_kernel(); */
 
 	return isValid;
 }
@@ -441,3 +575,46 @@
 /* d_delete:       cifs_d_delete,       *//* not needed except for debugging */
 	/* no need for d_hash, d_compare, d_release, d_iput ... yet. BB confirm this BB */
 };
+
+#if LINUX_VERSION_CODE < KERNEL_VERSION(2,6,9)
+#define nls_tolower(cp, name) tolower(name)
+#define nls_strnicmp(cp, name1, name2, len) strnicmp(name1, name2, len)
+#endif
+static int cifs_ci_hash(struct dentry *dentry, struct qstr *q)
+{
+	struct nls_table *codepage = CIFS_SB(dentry->d_inode->i_sb)->local_nls;
+	unsigned long hash;
+	int i;
+
+	hash = init_name_hash();
+	for (i = 0; i < q->len; i++)
+		hash = partial_name_hash(nls_tolower(codepage, q->name[i]),
+					 hash);
+	q->hash = end_name_hash(hash);
+
+	return 0;
+}
+
+static int cifs_ci_compare(struct dentry *dentry, struct qstr *a,
+			   struct qstr *b)
+{
+	struct nls_table *codepage = CIFS_SB(dentry->d_inode->i_sb)->local_nls;
+
+	if ((a->len == b->len) &&
+	    (nls_strnicmp(codepage, a->name, b->name, a->len) == 0)) {
+		/*
+		 * To preserve case, don't let an existing negative dentry's
+		 * case take precedence.  If a is not a negative dentry, this
+		 * should have no side effects
+		 */
+		memcpy((unsigned char *)a->name, b->name, a->len);
+		return 0;
+	}
+	return 1;
+}
+
+struct dentry_operations cifs_ci_dentry_ops = {
+	.d_revalidate = cifs_d_revalidate,
+	.d_hash = cifs_ci_hash,
+	.d_compare = cifs_ci_compare,
+};
--- linux-2.6.13/fs/cifs/fcntl.c
+++ linux-2.6.13/fs/cifs/fcntl.c
@@ -78,30 +78,34 @@
 	__u32 filter = FILE_NOTIFY_CHANGE_NAME | FILE_NOTIFY_CHANGE_ATTRIBUTES;
 	__u16 netfid;
 
+
+	if(experimEnabled == 0)
+		return 0;
+
 	xid = GetXid();
 	cifs_sb = CIFS_SB(file->f_dentry->d_sb);
 	pTcon = cifs_sb->tcon;
 
-	down(&file->f_dentry->d_sb->s_vfs_rename_sem);
 	full_path = build_path_from_dentry(file->f_dentry);
-	up(&file->f_dentry->d_sb->s_vfs_rename_sem);
 
 	if(full_path == NULL) {
 		rc = -ENOMEM;
 	} else {
-		cERROR(1,("cifs dir notify on file %s with arg 0x%lx",full_path,arg)); /* BB removeme BB */
+		cFYI(1,("dir notify on file %s Arg 0x%lx",full_path,arg));
 		rc = CIFSSMBOpen(xid, pTcon, full_path, FILE_OPEN, 
 			GENERIC_READ | SYNCHRONIZE, 0 /* create options */,
 			&netfid, &oplock,NULL, cifs_sb->local_nls,
 			cifs_sb->mnt_cifs_flags & CIFS_MOUNT_MAP_SPECIAL_CHR);
 		/* BB fixme - add this handle to a notify handle list */
 		if(rc) {
-			cERROR(1,("Could not open directory for notify"));  /* BB remove BB */
+			cFYI(1,("Could not open directory for notify"));
 		} else {
 			filter = convert_to_cifs_notify_flags(arg);
 			if(filter != 0) {
-				rc = CIFSSMBNotify(xid, pTcon, 0 /* no subdirs */, netfid, 
-					filter, cifs_sb->local_nls);
+				rc = CIFSSMBNotify(xid, pTcon, 
+					0 /* no subdirs */, netfid,
+					filter, file, arg & DN_MULTISHOT,
+					cifs_sb->local_nls);
 			} else {
 				rc = -EINVAL;
 			}
@@ -109,7 +113,7 @@
 			it would close automatically but may be a way
 			to do it easily when inode freed or when
 			notify info is cleared/changed */
-            cERROR(1,("notify rc %d",rc));
+			cFYI(1,("notify rc %d",rc));
 		}
 	}
 	
--- linux-2.6.13/fs/cifs/file.c
+++ linux-2.6.13/fs/cifs/file.c
@@ -21,11 +21,15 @@
  *   Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
  */
 #include <linux/fs.h>
+#include <linux/backing-dev.h>
 #include <linux/stat.h>
 #include <linux/fcntl.h>
+#include <linux/mpage.h>
 #include <linux/pagemap.h>
 #include <linux/pagevec.h>
 #include <linux/smp_lock.h>
+#include <linux/writeback.h>
+#include <linux/delay.h>
 #include <asm/div64.h>
 #include "cifsfs.h"
 #include "cifspdu.h"
@@ -47,6 +51,11 @@
 	private_data->pInode = inode;
 	private_data->invalidHandle = FALSE;
 	private_data->closePend = FALSE;
+	/* we have to track num writers to the inode, since writepages
+	does not tell us which handle the write is for so there can
+	be a close (overlapping with write) of the filehandle that
+	cifs_writepages chose to use */
+	atomic_set(&private_data->wrtPending,0); 
 
 	return private_data;
 }
@@ -75,6 +84,8 @@
 		return FILE_OVERWRITE_IF;
 	else if ((flags & O_CREAT) == O_CREAT)
 		return FILE_OPEN_IF;
+	else if ((flags & O_TRUNC) == O_TRUNC)
+		return FILE_OVERWRITE;
 	else
 		return FILE_OPEN;
 }
@@ -99,7 +110,6 @@
 			 &pCifsInode->openFileList);
 	}
 	write_unlock(&GlobalSMBSeslock);
-	write_unlock(&file->f_owner.lock);
 	if (pCifsInode->clientCanCacheRead) {
 		/* we have the inode open somewhere else
 		   no need to discard cache data */
@@ -118,8 +128,12 @@
 		if (file->f_dentry->d_inode->i_mapping) {
 		/* BB no need to lock inode until after invalidate
 		   since namei code should already have it locked? */
+#if LINUX_VERSION_CODE > KERNEL_VERSION(2, 6, 15)
+			filemap_write_and_wait(file->f_dentry->d_inode->i_mapping);
+#else
 			filemap_fdatawrite(file->f_dentry->d_inode->i_mapping);
 			filemap_fdatawait(file->f_dentry->d_inode->i_mapping);
+#endif
 		}
 		cFYI(1, ("invalidating remote inode since open detected it "
 			 "changed"));
@@ -191,13 +205,11 @@
 		} else {
 			if (file->f_flags & O_EXCL)
 				cERROR(1, ("could not find file instance for "
-					   "new file %p ", file));
+					   "new file %p", file));
 		}
 	}
 
-	down(&inode->i_sb->s_vfs_rename_sem);
 	full_path = build_path_from_dentry(file->f_dentry);
-	up(&inode->i_sb->s_vfs_rename_sem);
 	if (full_path == NULL) {
 		FreeXid(xid);
 		return -ENOMEM;
@@ -252,12 +264,24 @@
 		rc = -ENOMEM;
 		goto out;
 	}
-	rc = CIFSSMBOpen(xid, pTcon, full_path, disposition, desiredAccess,
-			 CREATE_NOT_DIR, &netfid, &oplock, buf,
+
+	if (cifs_sb->tcon->ses->capabilities & CAP_NT_SMBS)
+		rc = CIFSSMBOpen(xid, pTcon, full_path, disposition, 
+			 desiredAccess, CREATE_NOT_DIR, &netfid, &oplock, buf,
+			 cifs_sb->local_nls, cifs_sb->mnt_cifs_flags
+				 & CIFS_MOUNT_MAP_SPECIAL_CHR);
+	else
+		rc = -EIO; /* no NT SMB support fall into legacy open below */
+
+	if (rc == -EIO) {
+		/* Old server, try legacy style OpenX */
+		rc = SMBLegacyOpen(xid, pTcon, full_path, disposition,
+			desiredAccess, CREATE_NOT_DIR, &netfid, &oplock, buf,
 			 cifs_sb->local_nls, cifs_sb->mnt_cifs_flags
 				 & CIFS_MOUNT_MAP_SPECIAL_CHR);
+	}
 	if (rc) {
-		cFYI(1, ("cifs_open returned 0x%x ", rc));
+		cFYI(1, ("cifs_open returned 0x%x", rc));
 		goto out;
 	}
 	file->private_data =
@@ -267,7 +291,6 @@
 		goto out;
 	}
 	pCifsFile = cifs_init_private(file->private_data, inode, file, netfid);
-	write_lock(&file->f_owner.lock);
 	write_lock(&GlobalSMBSeslock);
 	list_add(&pCifsFile->tlist, &pTcon->openFileList);
 
@@ -278,7 +301,6 @@
 					    &oplock, buf, full_path, xid);
 	} else {
 		write_unlock(&GlobalSMBSeslock);
-		write_unlock(&file->f_owner.lock);
 	}
 
 	if (oplock & CIFS_CREATE_ACTION) {           
@@ -394,8 +416,8 @@
 				CIFS_MOUNT_MAP_SPECIAL_CHR);
 	if (rc) {
 		up(&pCifsFile->fh_sem);
-		cFYI(1, ("cifs_open returned 0x%x ", rc));
-		cFYI(1, ("oplock: %d ", oplock));
+		cFYI(1, ("cifs_open returned 0x%x", rc));
+		cFYI(1, ("oplock: %d", oplock));
 	} else {
 		pCifsFile->netfid = netfid;
 		pCifsFile->invalidHandle = FALSE;
@@ -403,8 +425,13 @@
 		pCifsInode = CIFS_I(inode);
 		if (pCifsInode) {
 			if (can_flush) {
+#if LINUX_VERSION_CODE > KERNEL_VERSION(2, 6, 15)
+				filemap_write_and_wait(inode->i_mapping);
+#else
 				filemap_fdatawrite(inode->i_mapping);
 				filemap_fdatawait(inode->i_mapping);
+#endif
+
 			/* temporarily disable caching while we
 			   go to server to get inode info */
 				pCifsInode->clientCanCacheAll = FALSE;
@@ -458,22 +485,32 @@
 	pTcon = cifs_sb->tcon;
 	if (pSMBFile) {
 		pSMBFile->closePend = TRUE;
-		write_lock(&file->f_owner.lock);
 		if (pTcon) {
 			/* no sense reconnecting to close a file that is
 			   already closed */
 			if (pTcon->tidStatus != CifsNeedReconnect) {
-				write_unlock(&file->f_owner.lock);
+				int timeout = 2;
+				while((atomic_read(&pSMBFile->wrtPending) != 0)
+					 && (timeout < 1000) ) {
+					/* Give write a better chance to get to
+					server ahead of the close.  We do not
+					want to add a wait_q here as it would
+					increase the memory utilization as
+					the struct would be in each open file,
+					but this should give enough time to 
+					clear the socket */
+					cERROR(1,("close with pending writes"));
+					msleep(timeout);
+					timeout *= 4;
+				} 
 				rc = CIFSSMBClose(xid, pTcon,
 						  pSMBFile->netfid);
-				write_lock(&file->f_owner.lock);
 			}
 		}
 		write_lock(&GlobalSMBSeslock);
 		list_del(&pSMBFile->flist);
 		list_del(&pSMBFile->tlist);
 		write_unlock(&GlobalSMBSeslock);
-		write_unlock(&file->f_owner.lock);
 		kfree(pSMBFile->search_resume_name);
 		kfree(file->private_data);
 		file->private_data = NULL;
@@ -501,7 +538,7 @@
 	    (struct cifsFileInfo *)file->private_data;
 	char *ptmp;
 
-	cFYI(1, ("Closedir inode = 0x%p with ", inode));
+	cFYI(1, ("Closedir inode = 0x%p", inode));
 
 	xid = GetXid();
 
@@ -523,13 +560,16 @@
 		}
 		ptmp = pCFileStruct->srch_inf.ntwrk_buf_start;
 		if (ptmp) {
-   /* BB removeme BB */	cFYI(1, ("freeing smb buf in srch struct in closedir"));
+			cFYI(1, ("closedir free smb buf in srch struct"));
 			pCFileStruct->srch_inf.ntwrk_buf_start = NULL;
+			if(pCFileStruct->srch_inf.smallBuf)
+				cifs_small_buf_release(ptmp);
+			else
 			cifs_buf_release(ptmp);
 		}
 		ptmp = pCFileStruct->search_resume_name;
 		if (ptmp) {
-   /* BB removeme BB */	cFYI(1, ("freeing resume name in closedir"));
+			cFYI(1, ("closedir free resume name"));
 			pCFileStruct->search_resume_name = NULL;
 			kfree(ptmp);
 		}
@@ -544,13 +584,14 @@
 int cifs_lock(struct file *file, int cmd, struct file_lock *pfLock)
 {
 	int rc, xid;
-	__u32 lockType = LOCKING_ANDX_LARGE_FILES;
 	__u32 numLock = 0;
 	__u32 numUnlock = 0;
 	__u64 length;
 	int wait_flag = FALSE;
 	struct cifs_sb_info *cifs_sb;
 	struct cifsTconInfo *pTcon;
+	__u16 netfid;
+	__u8 lockType = LOCKING_ANDX_LARGE_FILES;
 
 	length = 1 + pfLock->fl_end - pfLock->fl_start;
 	rc = -EACCES;
@@ -562,16 +603,16 @@
 	        pfLock->fl_end));
 
 	if (pfLock->fl_flags & FL_POSIX)
-		cFYI(1, ("Posix "));
+		cFYI(1, ("Posix"));
 	if (pfLock->fl_flags & FL_FLOCK)
-		cFYI(1, ("Flock "));
+		cFYI(1, ("Flock"));
 	if (pfLock->fl_flags & FL_SLEEP) {
-		cFYI(1, ("Blocking lock "));
+		cFYI(1, ("Blocking lock"));
 		wait_flag = TRUE;
 	}
 	if (pfLock->fl_flags & FL_ACCESS)
 		cFYI(1, ("Process suspended by mandatory locking - "
-			 "not implemented yet "));
+			 "not implemented yet"));
 	if (pfLock->fl_flags & FL_LEASE)
 		cFYI(1, ("Lease on file - not implemented yet"));
 	if (pfLock->fl_flags & 
@@ -582,21 +623,23 @@
 		cFYI(1, ("F_WRLCK "));
 		numLock = 1;
 	} else if (pfLock->fl_type == F_UNLCK) {
-		cFYI(1, ("F_UNLCK "));
+		cFYI(1, ("F_UNLCK"));
 		numUnlock = 1;
+		/* Check if unlock includes more than
+		one lock range */
 	} else if (pfLock->fl_type == F_RDLCK) {
-		cFYI(1, ("F_RDLCK "));
+		cFYI(1, ("F_RDLCK"));
 		lockType |= LOCKING_ANDX_SHARED_LOCK;
 		numLock = 1;
 	} else if (pfLock->fl_type == F_EXLCK) {
-		cFYI(1, ("F_EXLCK "));
+		cFYI(1, ("F_EXLCK"));
 		numLock = 1;
 	} else if (pfLock->fl_type == F_SHLCK) {
-		cFYI(1, ("F_SHLCK "));
+		cFYI(1, ("F_SHLCK"));
 		lockType |= LOCKING_ANDX_SHARED_LOCK;
 		numLock = 1;
 	} else
-		cFYI(1, ("Unknown type of lock "));
+		cFYI(1, ("Unknown type of lock"));
 
 	cifs_sb = CIFS_SB(file->f_dentry->d_sb);
 	pTcon = cifs_sb->tcon;
@@ -605,27 +648,40 @@
 		FreeXid(xid);
 		return -EBADF;
 	}
+	netfid = ((struct cifsFileInfo *)file->private_data)->netfid;
+
 
+	/* BB add code here to normalize offset and length to
+	account for negative length which we can not accept over the
+	wire */
 	if (IS_GETLK(cmd)) {
-		rc = CIFSSMBLock(xid, pTcon,
-				 ((struct cifsFileInfo *)file->
-				  private_data)->netfid,
-				 length,
-				 pfLock->fl_start, 0, 1, lockType,
-				 0 /* wait flag */ );
+		if((cifs_sb->tcon->ses->capabilities & CAP_UNIX) &&
+		   (CIFS_UNIX_FCNTL_CAP & 
+			le64_to_cpu(cifs_sb->tcon->fsUnixInfo.Capability))) {
+			int posix_lock_type;
+			if(lockType & LOCKING_ANDX_SHARED_LOCK)
+				posix_lock_type = CIFS_RDLCK;
+			else
+				posix_lock_type = CIFS_WRLCK;
+			rc = CIFSSMBPosixLock(xid, pTcon, netfid, 1 /* get */,
+					length,	pfLock,
+					posix_lock_type, wait_flag);
+			FreeXid(xid);
+			return rc;
+		}
+
+		/* BB we could chain these into one lock request BB */
+		rc = CIFSSMBLock(xid, pTcon, netfid, length, pfLock->fl_start,
+				 0, 1, lockType, 0 /* wait flag */ );
 		if (rc == 0) {
-			rc = CIFSSMBLock(xid, pTcon,
-					 ((struct cifsFileInfo *) file->
-					  private_data)->netfid,
-					 length,
+			rc = CIFSSMBLock(xid, pTcon, netfid, length, 
 					 pfLock->fl_start, 1 /* numUnlock */ ,
 					 0 /* numLock */ , lockType,
 					 0 /* wait flag */ );
 			pfLock->fl_type = F_UNLCK;
 			if (rc != 0)
 				cERROR(1, ("Error unlocking previously locked "
-					   "range %d during test of lock ",
-					   rc));
+					   "range %d during test of lock", rc));
 			rc = 0;
 
 		} else {
@@ -637,14 +693,33 @@
 		FreeXid(xid);
 		return rc;
 	}
+	if ((cifs_sb->tcon->ses->capabilities & CAP_UNIX) &&
+		(CIFS_UNIX_FCNTL_CAP &
+			 le64_to_cpu(cifs_sb->tcon->fsUnixInfo.Capability))) {
+		int posix_lock_type;
+		if(lockType & LOCKING_ANDX_SHARED_LOCK)
+			posix_lock_type = CIFS_RDLCK;
+		else
+			posix_lock_type = CIFS_WRLCK;
 
-	rc = CIFSSMBLock(xid, pTcon,
-			 ((struct cifsFileInfo *) file->private_data)->
-			 netfid, length,
-			 pfLock->fl_start, numUnlock, numLock, lockType,
-			 wait_flag);
+		if(numUnlock == 1)
+			posix_lock_type = CIFS_UNLCK;
+		else if(numLock == 0) {
+			/* if no lock or unlock then nothing
+			to do since we do not know what it is */
+			FreeXid(xid);
+			return -EOPNOTSUPP;
+		}
+		rc = CIFSSMBPosixLock(xid, pTcon, netfid, 0 /* set */,
+				      length, pfLock,
+				      posix_lock_type, wait_flag);
+	} else
+		rc = CIFSSMBLock(xid, pTcon, netfid, length, pfLock->fl_start,
+				numUnlock, numLock, lockType, wait_flag);
+#if LINUX_VERSION_CODE > KERNEL_VERSION(2,6,8)
 	if (pfLock->fl_flags & FL_POSIX)
 		posix_lock_file_wait(file, pfLock);
+#endif
 	FreeXid(xid);
 	return rc;
 }
@@ -744,14 +819,7 @@
 				    15 seconds is plenty */
 	}
 
-#ifdef CONFIG_CIFS_STATS
-	if (total_written > 0) {
-		atomic_inc(&pTcon->num_writes);
-		spin_lock(&pTcon->stat_lock);
-		pTcon->bytes_written += total_written;
-		spin_unlock(&pTcon->stat_lock);
-	}
-#endif		
+	cifs_stats_bytes_written(pTcon, total_written);
 
 	/* since the write may have blocked check these pointers again */
 	if (file->f_dentry) {
@@ -791,9 +859,8 @@
 
 	pTcon = cifs_sb->tcon;
 
-	/* cFYI(1,
-	   (" write %d bytes to offset %lld of %s", write_size,
-	   *poffset, file->f_dentry->d_name.name)); */
+	cFYI(1,("write %zd bytes to offset %lld of %s", write_size,
+	   *poffset, file->f_dentry->d_name.name));
 
 	if (file->private_data == NULL)
 		return -EBADF;
@@ -846,13 +913,31 @@
 				if (rc != 0)
 					break;
 			}
-
+			if(experimEnabled || (pTcon->ses->server &&
+				((pTcon->ses->server->secMode & 
+				(SECMODE_SIGN_REQUIRED | SECMODE_SIGN_ENABLED))
+				== 0))) {
+				struct kvec iov[2];
+				unsigned int len;
+
+				len = min((size_t)cifs_sb->wsize,
+					  write_size - total_written);
+				/* iov[0] is reserved for smb header */
+				iov[1].iov_base = (char *)write_data +
+						  total_written;
+				iov[1].iov_len = len;
+				rc = CIFSSMBWrite2(xid, pTcon,
+						open_file->netfid, len,
+						*poffset, &bytes_written,
+						iov, 1, long_op);
+			} else
 			rc = CIFSSMBWrite(xid, pTcon,
 				 open_file->netfid,
 				 min_t(const int, cifs_sb->wsize, 
 				       write_size - total_written),
 				 *poffset, &bytes_written,
-				 write_data + total_written, NULL, long_op);
+					 write_data + total_written,
+					 NULL, long_op);
 		}
 		if (rc || (bytes_written == 0)) {
 			if (total_written)
@@ -867,14 +952,7 @@
 				    15 seconds is plenty */
 	}
 
-#ifdef CONFIG_CIFS_STATS
-	if (total_written > 0) {
-		atomic_inc(&pTcon->num_writes);
-		spin_lock(&pTcon->stat_lock);
-		pTcon->bytes_written += total_written;
-		spin_unlock(&pTcon->stat_lock);
-	}
-#endif		
+	cifs_stats_bytes_written(pTcon, total_written);
 
 	/* since the write may have blocked check these pointers again */
 	if (file->f_dentry) {
@@ -893,6 +971,53 @@
 	return total_written;
 }
 
+struct cifsFileInfo *find_writable_file(struct cifsInodeInfo *cifs_inode)
+{
+	struct cifsFileInfo *open_file;
+	int rc;
+
+	/* Having a null inode here (because mapping->host was set to zero by
+	the VFS or MM) should not happen but we had reports of on oops (due to
+	it being zero) during stress testcases so we need to check for it */
+
+	if(cifs_inode == NULL) {
+		cERROR(1,("Null inode passed to cifs_writeable_file"));
+		dump_stack();
+		return NULL;
+	}
+
+	read_lock(&GlobalSMBSeslock);
+	list_for_each_entry(open_file, &cifs_inode->openFileList, flist) {
+		if (open_file->closePend)
+			continue;
+		if (open_file->pfile &&
+		    ((open_file->pfile->f_flags & O_RDWR) ||
+		     (open_file->pfile->f_flags & O_WRONLY))) {
+			atomic_inc(&open_file->wrtPending);
+			read_unlock(&GlobalSMBSeslock);
+			if((open_file->invalidHandle) && 
+			   (!open_file->closePend) /* BB fixme -since the second clause can not be true remove it BB */) {
+				rc = cifs_reopen_file(&cifs_inode->vfs_inode, 
+						      open_file->pfile, FALSE);
+				/* if it fails, try another handle - might be */
+				/* dangerous to hold up writepages with retry */
+				if(rc) {
+					cFYI(1,("failed on reopen file in wp"));
+					read_lock(&GlobalSMBSeslock);
+					/* can not use this handle, no write
+					pending on this one after all */
+					atomic_dec
+					     (&open_file->wrtPending);
+					continue;
+				}
+			}
+			return open_file;
+		}
+	}
+	read_unlock(&GlobalSMBSeslock);
+	return NULL;
+}
+
 static int cifs_partialpagewrite(struct page *page, unsigned from, unsigned to)
 {
 	struct address_space *mapping = page->mapping;
@@ -903,10 +1028,7 @@
 	struct cifs_sb_info *cifs_sb;
 	struct cifsTconInfo *pTcon;
 	struct inode *inode;
-	struct cifsInodeInfo *cifsInode;
-	struct cifsFileInfo *open_file = NULL;
-	struct list_head *tmp;
-	struct list_head *tmp1;
+	struct cifsFileInfo *open_file;
 
 	if (!mapping || !mapping->host)
 		return -EFAULT;
@@ -934,49 +1056,20 @@
 	if (mapping->host->i_size - offset < (loff_t)to)
 		to = (unsigned)(mapping->host->i_size - offset); 
 
-	cifsInode = CIFS_I(mapping->host);
-	read_lock(&GlobalSMBSeslock); 
-	/* BB we should start at the end */
-	list_for_each_safe(tmp, tmp1, &cifsInode->openFileList) {            
-		open_file = list_entry(tmp, struct cifsFileInfo, flist);
-		if (open_file->closePend)
-			continue;
-		/* We check if file is open for writing first */
-		if ((open_file->pfile) && 
-		   ((open_file->pfile->f_flags & O_RDWR) || 
-			(open_file->pfile->f_flags & O_WRONLY))) {
-			read_unlock(&GlobalSMBSeslock);
-			bytes_written = cifs_write(open_file->pfile,
-						write_data, to-from,
-						&offset);
-			read_lock(&GlobalSMBSeslock);
+	open_file = find_writable_file(CIFS_I(mapping->host));
+	if (open_file) {
+		bytes_written = cifs_write(open_file->pfile, write_data,
+					   to-from, &offset);
+		atomic_dec(&open_file->wrtPending);
 		/* Does mm or vfs already set times? */
-			inode->i_atime = 
-			inode->i_mtime = current_fs_time(inode->i_sb);
+		inode->i_atime = inode->i_mtime = current_fs_time(inode->i_sb);
 			if ((bytes_written > 0) && (offset)) {
 				rc = 0;
 			} else if (bytes_written < 0) {
-				if (rc == -EBADF) {
-				/* have seen a case in which kernel seemed to
-				   have closed/freed a file even with writes
-				   active so we might as well see if there are
-				   other file structs to try for the same
-				   inode before giving up */
-					continue;
-				} else
+			if (rc != -EBADF)
 					rc = bytes_written;
 			}
-			break;  /* now that we found a valid file handle and
-				   tried to write to it we are done, no sense
-				   continuing to loop looking for another */
-		}
-		if (tmp->next == NULL) {
-			cFYI(1, ("File instance %p removed", tmp));
-			break;
-		}
-	}
-	read_unlock(&GlobalSMBSeslock);
-	if (open_file == NULL) {
+	} else {
 		cFYI(1, ("No writeable filehandles for inode"));
 		rc = -EIO;
 	}
@@ -985,23 +1078,216 @@
 	return rc;
 }
 
-#if 0
+
+#if LINUX_VERSION_CODE > KERNEL_VERSION(2, 6, 14)
 static int cifs_writepages(struct address_space *mapping,
 	struct writeback_control *wbc)
 {
-	int rc = -EFAULT;
+	struct backing_dev_info *bdi = mapping->backing_dev_info;
+	unsigned int bytes_to_write;
+	unsigned int bytes_written;
+	struct cifs_sb_info *cifs_sb;
+	int done = 0;
+	pgoff_t end = -1;
+	pgoff_t index;
+	int is_range = 0;
+	struct kvec iov[32];
+	int len;
+	int n_iov = 0;
+	pgoff_t next;
+	int nr_pages;
+	__u64 offset = 0;
+	struct cifsFileInfo *open_file;
+	struct page *page;
+	struct pagevec pvec;
+	int rc = 0;
+	int scanned = 0;
 	int xid;
 
+	cifs_sb = CIFS_SB(mapping->host->i_sb);
+	
+	/*
+	 * If wsize is smaller that the page cache size, default to writing
+	 * one page at a time via cifs_writepage
+	 */
+	if (cifs_sb->wsize < PAGE_CACHE_SIZE)
+		return generic_writepages(mapping, wbc);
+
+	if((cifs_sb->tcon->ses) && (cifs_sb->tcon->ses->server))
+		if(cifs_sb->tcon->ses->server->secMode &
+                          (SECMODE_SIGN_REQUIRED | SECMODE_SIGN_ENABLED))
+			if(!experimEnabled)
+				return generic_writepages(mapping, wbc);
+
+	/*
+	 * BB: Is this meaningful for a non-block-device file system?
+	 * If it is, we should test it again after we do I/O
+	 */
+	if (wbc->nonblocking && bdi_write_congested(bdi)) {
+		wbc->encountered_congestion = 1;
+		return 0;
+	}
+
 	xid = GetXid();
 
-	/* Find contiguous pages then iterate through repeating
-	   call 16K write then Setpageuptodate or if LARGE_WRITE_X
-	   support then send larger writes via kevec so as to eliminate
-	   a memcpy */
+	pagevec_init(&pvec, 0);
+	if (wbc->sync_mode == WB_SYNC_NONE)
+		index = mapping->writeback_index; /* Start from prev offset */
+	else {
+		index = 0;
+		scanned = 1;
+	}
+	if (wbc->start || wbc->end) {
+		index = wbc->start >> PAGE_CACHE_SHIFT;
+		end = wbc->end >> PAGE_CACHE_SHIFT;
+		is_range = 1;
+		scanned = 1;
+	}
+retry:
+	while (!done && (index <= end) &&
+	       (nr_pages = pagevec_lookup_tag(&pvec, mapping, &index,
+			PAGECACHE_TAG_DIRTY,
+			min(end - index, (pgoff_t)PAGEVEC_SIZE - 1) + 1))) {
+		int first;
+		unsigned int i;
+
+		first = -1;
+		next = 0;
+		n_iov = 0;
+		bytes_to_write = 0;
+
+		for (i = 0; i < nr_pages; i++) {
+			page = pvec.pages[i];
+			/*
+			 * At this point we hold neither mapping->tree_lock nor
+			 * lock on the page itself: the page may be truncated or
+			 * invalidated (changing page->mapping to NULL), or even
+			 * swizzled back from swapper_space to tmpfs file
+			 * mapping
+			 */
+
+			if (first < 0)
+				lock_page(page);
+			else if (TestSetPageLocked(page))
+				break;
+
+			if (unlikely(page->mapping != mapping)) {
+				unlock_page(page);
+				break;
+			}
+
+			if (unlikely(is_range) && (page->index > end)) {
+				done = 1;
+				unlock_page(page);
+				break;
+			}
+
+			if (next && (page->index != next)) {
+				/* Not next consecutive page */
+				unlock_page(page);
+				break;
+			}
+
+			if (wbc->sync_mode != WB_SYNC_NONE)
+				wait_on_page_writeback(page);
+
+			if (PageWriteback(page) ||
+					!test_clear_page_dirty(page)) {
+				unlock_page(page);
+				break;
+			}
+
+			if (page_offset(page) >= mapping->host->i_size) {
+				done = 1;
+				unlock_page(page);
+				break;
+			}
+
+			/*
+			 * BB can we get rid of this?  pages are held by pvec
+			 */
+			page_cache_get(page);
+
+			len = min(mapping->host->i_size - page_offset(page),
+				  (loff_t)PAGE_CACHE_SIZE);
+
+			/* reserve iov[0] for the smb header */
+			n_iov++;
+			iov[n_iov].iov_base = kmap(page);
+			iov[n_iov].iov_len = len;
+			bytes_to_write += len;
+
+			if (first < 0) {
+				first = i;
+				offset = page_offset(page);
+			}
+			next = page->index + 1;
+			if (bytes_to_write + PAGE_CACHE_SIZE > cifs_sb->wsize)
+				break;
+		}
+		if (n_iov) {
+			/* Search for a writable handle every time we call
+			 * CIFSSMBWrite2.  We can't rely on the last handle
+			 * we used to still be valid
+			 */
+			open_file = find_writable_file(CIFS_I(mapping->host));
+			if (!open_file) {
+				cERROR(1, ("No writable handles for inode"));
+				rc = -EBADF;
+			} else {
+				rc = CIFSSMBWrite2(xid, cifs_sb->tcon,
+						   open_file->netfid,
+						   bytes_to_write, offset,
+						   &bytes_written, iov, n_iov,
+						   1);
+				atomic_dec(&open_file->wrtPending);
+				if (rc || bytes_written < bytes_to_write) {
+					cERROR(1,("Write2 ret %d, written = %d",
+						  rc, bytes_written));
+					/* BB what if continued retry is
+					   requested via mount flags? */
+					set_bit(AS_EIO, &mapping->flags);
+				} else {
+					cifs_stats_bytes_written(cifs_sb->tcon,
+								 bytes_written);
+				}
+			}
+			for (i = 0; i < n_iov; i++) {
+				page = pvec.pages[first + i];
+				/* Should we also set page error on
+				success rc but too little data written? */
+				/* BB investigate retry logic on temporary
+				server crash cases and how recovery works
+				when page marked as error */ 
+				if(rc)
+					SetPageError(page);
+				kunmap(page);
+				unlock_page(page);
+				page_cache_release(page);
+			}
+			if ((wbc->nr_to_write -= n_iov) <= 0)
+				done = 1;
+			index = next;
+		}
+		pagevec_release(&pvec);
+	}
+	if (!scanned && !done) {
+		/*
+		 * We hit the last page and there is more work to be done: wrap
+		 * back to the start of the file
+		 */
+		scanned = 1;
+		index = 0;
+		goto retry;
+	}
+	if (!is_range)
+		mapping->writeback_index = index;
+
 	FreeXid(xid);
+
 	return rc;
 }
-#endif
+#endif /* KERNEL_VERSION > 2.6.14 */
 
 static int cifs_writepage(struct page* page, struct writeback_control *wbc)
 {
@@ -1101,7 +1387,7 @@
 
 	xid = GetXid();
 
-	cFYI(1, ("Sync file - name: %s datasync: 0x%x ", 
+	cFYI(1, ("Sync file - name: %s datasync: 0x%x", 
 		dentry->d_name.name, datasync));
 	
 	rc = filemap_fdatawrite(inode->i_mapping);
@@ -1130,7 +1416,7 @@
 /*	fill in rpages then 
 	result = cifs_pagein_inode(inode, index, rpages); */ /* BB finish */
 
-/*	cFYI(1, ("rpages is %d for sync page of Index %ld ", rpages, index));
+/*	cFYI(1, ("rpages is %d for sync page of Index %ld", rpages, index));
 
 	if (rc < 0)
 		return rc;
@@ -1200,6 +1486,7 @@
 		rc = -EAGAIN;
 		smb_read_data = NULL;
 		while (rc == -EAGAIN) {
+			int buf_type = CIFS_NO_BUFFER;
 			if ((open_file->invalidHandle) && 
 			    (!open_file->closePend)) {
 				rc = cifs_reopen_file(file->f_dentry->d_inode,
@@ -1207,22 +1494,24 @@
 				if (rc != 0)
 					break;
 			}
-
 			rc = CIFSSMBRead(xid, pTcon,
 				 open_file->netfid,
 				 current_read_size, *poffset,
-				 &bytes_read, &smb_read_data);
-
+					 &bytes_read, &smb_read_data,
+					 &buf_type);
 			pSMBr = (struct smb_com_read_rsp *)smb_read_data;
+			if (smb_read_data) {
 			if (copy_to_user(current_offset, 
-					 smb_read_data + 4 /* RFC1001 hdr */
-					 + le16_to_cpu(pSMBr->DataOffset), 
+						smb_read_data +
+						4 /* RFC1001 length field */ +
+						le16_to_cpu(pSMBr->DataOffset),
 					 bytes_read)) {
 				rc = -EFAULT;
-				FreeXid(xid);
-				return rc;
             }
-			if (smb_read_data) {
+
+				if(buf_type == CIFS_SMALL_BUFFER)
+					cifs_small_buf_release(smb_read_data);
+				else if(buf_type == CIFS_LARGE_BUFFER)
 				cifs_buf_release(smb_read_data);
 				smb_read_data = NULL;
 			}
@@ -1235,12 +1524,7 @@
 				return rc;
 			}
 		} else {
-#ifdef CONFIG_CIFS_STATS
-			atomic_inc(&pTcon->num_reads);
-			spin_lock(&pTcon->stat_lock);
-			pTcon->bytes_read += total_read;
-			spin_unlock(&pTcon->stat_lock);
-#endif
+			cifs_stats_bytes_read(pTcon, bytes_read);
 			*poffset += bytes_read;
 		}
 	}
@@ -1261,6 +1545,7 @@
 	int xid;
 	char *current_offset;
 	struct cifsFileInfo *open_file;
+	int buf_type = CIFS_NO_BUFFER;
 
 	xid = GetXid();
 	cifs_sb = CIFS_SB(file->f_dentry->d_sb);
@@ -1280,6 +1565,13 @@
 	     total_read += bytes_read, current_offset += bytes_read) {
 		current_read_size = min_t(const int, read_size - total_read,
 					  cifs_sb->rsize);
+		/* For windows me and 9x we do not want to request more
+		than it negotiated since it will refuse the read then */
+		if((pTcon->ses) && 
+			!(pTcon->ses->capabilities & CAP_LARGE_FILES)) {
+			current_read_size = min_t(const int, current_read_size,
+					pTcon->ses->server->maxBuf - 128);
+		}
 		rc = -EAGAIN;
 		while (rc == -EAGAIN) {
 			if ((open_file->invalidHandle) && 
@@ -1289,11 +1581,11 @@
 				if (rc != 0)
 					break;
 			}
-
 			rc = CIFSSMBRead(xid, pTcon,
 				 open_file->netfid,
 				 current_read_size, *poffset,
-				 &bytes_read, &current_offset);
+					 &bytes_read, &current_offset,
+					 &buf_type);
 		}
 		if (rc || (bytes_read == 0)) {
 			if (total_read) {
@@ -1303,12 +1595,7 @@
 				return rc;
 			}
 		} else {
-#ifdef CONFIG_CIFS_STATS
-			atomic_inc(&pTcon->num_reads);
-			spin_lock(&pTcon->stat_lock);
-			pTcon->bytes_read += total_read;
-			spin_unlock(&pTcon->stat_lock);
-#endif
+			cifs_stats_bytes_read(pTcon, total_read);
 			*poffset += bytes_read;
 		}
 	}
@@ -1333,7 +1620,7 @@
 	return rc;
 }
 
-
+#if LINUX_VERSION_CODE > KERNEL_VERSION(2, 5, 0)
 static void cifs_copy_cache_pages(struct address_space *mapping, 
 	struct list_head *pages, int bytes_read, char *data,
 	struct pagevec *plru_pvec)
@@ -1396,6 +1683,7 @@
 	struct smb_com_read_rsp *pSMBr;
 	struct pagevec lru_pvec;
 	struct cifsFileInfo *open_file;
+	int buf_type = CIFS_NO_BUFFER;
 
 	xid = GetXid();
 	if (file->private_data == NULL) {
@@ -1454,10 +1742,14 @@
 			rc = CIFSSMBRead(xid, pTcon,
 				open_file->netfid,
 				read_size, offset,
-				&bytes_read, &smb_read_data);
-			/* BB need to check return code here */
+					 &bytes_read, &smb_read_data,
+					 &buf_type);
+			/* BB more RC checks ? */
 			if (rc== -EAGAIN) {
 				if (smb_read_data) {
+					if(buf_type == CIFS_SMALL_BUFFER)
+						cifs_small_buf_release(smb_read_data);
+					else if(buf_type == CIFS_LARGE_BUFFER)
 					cifs_buf_release(smb_read_data);
 					smb_read_data = NULL;
 				}
@@ -1480,12 +1772,7 @@
 				le16_to_cpu(pSMBr->DataOffset), &lru_pvec);
 
 			i +=  bytes_read >> PAGE_CACHE_SHIFT;
-#ifdef CONFIG_CIFS_STATS
-			atomic_inc(&pTcon->num_reads);
-			spin_lock(&pTcon->stat_lock);
-			pTcon->bytes_read += bytes_read;
-			spin_unlock(&pTcon->stat_lock);
-#endif
+			cifs_stats_bytes_read(pTcon, bytes_read);
 			if ((int)(bytes_read & PAGE_CACHE_MASK) != bytes_read) {
 				i++; /* account for partial page */
 
@@ -1520,6 +1807,9 @@
 			break;
 		}
 		if (smb_read_data) {
+			if(buf_type == CIFS_SMALL_BUFFER)
+				cifs_small_buf_release(smb_read_data);
+			else if(buf_type == CIFS_LARGE_BUFFER)
 			cifs_buf_release(smb_read_data);
 			smb_read_data = NULL;
 		}
@@ -1530,6 +1820,9 @@
 
 /* need to free smb_read_data buf before exit */
 	if (smb_read_data) {
+		if(buf_type == CIFS_SMALL_BUFFER)
+			cifs_small_buf_release(smb_read_data);
+		else if(buf_type == CIFS_LARGE_BUFFER)
 		cifs_buf_release(smb_read_data);
 		smb_read_data = NULL;
 	} 
@@ -1537,6 +1830,7 @@
 	FreeXid(xid);
 	return rc;
 }
+#endif
 
 static int cifs_readpage_worker(struct file *file, struct page *page,
 	loff_t *poffset)
@@ -1553,7 +1847,7 @@
 	if (rc < 0)
 		goto io_error;
 	else
-		cFYI(1, ("Bytes read %d ",rc));
+		cFYI(1, ("Bytes read %d",rc));
                                                                                                                            
 	file->f_dentry->d_inode->i_atime =
 		current_fs_time(file->f_dentry->d_inode->i_sb);
@@ -1603,39 +1897,30 @@
    page caching in the current Linux kernel design */
 int is_size_safe_to_change(struct cifsInodeInfo *cifsInode)
 {
-	struct list_head *tmp;
-	struct list_head *tmp1;
 	struct cifsFileInfo *open_file = NULL;
-	int rc = TRUE;
 
-	if (cifsInode == NULL)
-		return rc;
+	if (cifsInode)
+		open_file =  find_writable_file(cifsInode);
 
-	read_lock(&GlobalSMBSeslock); 
-	list_for_each_safe(tmp, tmp1, &cifsInode->openFileList) {            
-		open_file = list_entry(tmp, struct cifsFileInfo, flist);
-		if (open_file == NULL)
-			break;
-		if (open_file->closePend)
-			continue;
-	/* We check if file is open for writing,   
-	   BB we could supplement this with a check to see if file size
-	   changes have been flushed to server - ie inode metadata dirty */
-		if ((open_file->pfile) && 
-		    ((open_file->pfile->f_flags & O_RDWR) || 
-		    (open_file->pfile->f_flags & O_WRONLY))) {
-			rc = FALSE;
-			break;
-		}
-		if (tmp->next == NULL) {
-			cFYI(1, ("File instance %p removed", tmp));
-			break;
-		}
+	if(open_file) {
+		struct cifs_sb_info *cifs_sb;
+
+		/* there is not actually a write pending so let
+		this handle go free and allow it to
+		be closable if needed */
+		atomic_dec(&open_file->wrtPending);
+
+		cifs_sb = CIFS_SB(cifsInode->vfs_inode.i_sb);
+		if ( cifs_sb->mnt_cifs_flags & CIFS_MOUNT_DIRECT_IO ) {
+			/* since no page cache to corrupt on directio 
+			we can change size safely */
+			return 1;
 	}
-	read_unlock(&GlobalSMBSeslock);
-	return rc;
-}
 
+		return 0;
+	} else
+		return 1;
+}
 
 static int cifs_prepare_write(struct file *file, struct page *page,
 	unsigned from, unsigned to)
@@ -1674,8 +1959,31 @@
 
 struct address_space_operations cifs_addr_ops = {
 	.readpage = cifs_readpage,
+#if LINUX_VERSION_CODE > KERNEL_VERSION(2, 5, 0)
 	.readpages = cifs_readpages,
+#endif
+	.writepage = cifs_writepage,
+#if LINUX_VERSION_CODE > KERNEL_VERSION(2, 6, 14)
+	.writepages = cifs_writepages,
+#endif
+	.prepare_write = cifs_prepare_write,
+	.commit_write = cifs_commit_write,
+	.set_page_dirty = __set_page_dirty_nobuffers,
+	/* .sync_page = cifs_sync_page, */
+	/* .direct_IO = */
+};
+
+/*
+ * cifs_readpages requires the server to support a buffer large enough to
+ * contain the header plus one complete page of data.  Otherwise, we need
+ * to leave cifs_readpages out of the address space operations.
+ */
+struct address_space_operations cifs_addr_ops_smallbuf = {
+	.readpage = cifs_readpage,
 	.writepage = cifs_writepage,
+#if LINUX_VERSION_CODE > KERNEL_VERSION(2, 6, 14)
+	.writepages = cifs_writepages,
+#endif
 	.prepare_write = cifs_prepare_write,
 	.commit_write = cifs_commit_write,
 	.set_page_dirty = __set_page_dirty_nobuffers,
--- linux-2.6.13/fs/cifs/inode.c
+++ linux-2.6.13/fs/cifs/inode.c
@@ -41,7 +41,7 @@
 	char *tmp_path;
 
 	pTcon = cifs_sb->tcon;
-	cFYI(1, (" Getting info on %s ", search_path));
+	cFYI(1, ("Getting info on %s", search_path));
 	/* could have done a find first instead but this returns more info */
 	rc = CIFSSMBUnixQPathInfo(xid, pTcon, search_path, &findData,
 				  cifs_sb->local_nls, cifs_sb->mnt_cifs_flags &
@@ -97,9 +97,9 @@
 		inode = *pinode;
 		cifsInfo = CIFS_I(inode);
 
-		cFYI(1, (" Old time %ld ", cifsInfo->time));
+		cFYI(1, ("Old time %ld", cifsInfo->time));
 		cifsInfo->time = jiffies;
-		cFYI(1, (" New time %ld ", cifsInfo->time));
+		cFYI(1, ("New time %ld", cifsInfo->time));
 		/* this is ok to set on every inode revalidate */
 		atomic_set(&cifsInfo->inUse,1);
 
@@ -111,6 +111,9 @@
 		inode->i_ctime =
 		    cifs_NTtimeToUnix(le64_to_cpu(findData.LastStatusChange));
 		inode->i_mode = le64_to_cpu(findData.Permissions);
+		/* since we set the inode type below we need to mask off
+                   to avoid strange results if bits set above */
+                        inode->i_mode &= ~S_IFMT;
 		if (type == UNIX_FILE) {
 			inode->i_mode |= S_IFREG;
 		} else if (type == UNIX_SYMLINK) {
@@ -129,6 +132,10 @@
 			inode->i_mode |= S_IFIFO;
 		} else if (type == UNIX_SOCKET) {
 			inode->i_mode |= S_IFSOCK;
+		} else {
+			/* safest to call it a file if we do not know */
+			inode->i_mode |= S_IFREG;
+			cFYI(1,("unknown type %d",type));
 		}
 		inode->i_uid = le64_to_cpu(findData.Uid);
 		inode->i_gid = le64_to_cpu(findData.Gid);
@@ -137,8 +144,12 @@
 		if (is_size_safe_to_change(cifsInfo)) {
 		/* can not safely change the file size here if the
 		   client is writing to it due to potential races */
-
+#if LINUX_VERSION_CODE > KERNEL_VERSION(2, 5, 0)
 			i_size_write(inode, end_of_file);
+#else
+			inode->i_size = end_of_file;
+#endif
+
 
 		/* blksize needs to be multiple of two. So safer to default to
 		blksize and blkbits set in superblock so 2**blkbits and blksize
@@ -155,28 +166,41 @@
 		}
 
 		if (num_of_bytes < end_of_file)
-			cFYI(1, ("allocation size less than end of file "));
+			cFYI(1, ("allocation size less than end of file"));
 		cFYI(1,
 		     ("Size %ld and blocks %ld",
 		      (unsigned long) inode->i_size, inode->i_blocks));
 		if (S_ISREG(inode->i_mode)) {
-			cFYI(1, (" File inode "));
+			cFYI(1, ("File inode"));
 			inode->i_op = &cifs_file_inode_ops;
-			if (cifs_sb->mnt_cifs_flags & CIFS_MOUNT_DIRECT_IO)
-				inode->i_fop = &cifs_file_direct_ops;
+			if (cifs_sb->mnt_cifs_flags & CIFS_MOUNT_DIRECT_IO) {
+				if (cifs_sb->mnt_cifs_flags & CIFS_MOUNT_NO_BRL)
+					inode->i_fop = 
+						&cifs_file_direct_nobrl_ops;
 			else
+					inode->i_fop = &cifs_file_direct_ops;
+			} else if(cifs_sb->mnt_cifs_flags & CIFS_MOUNT_NO_BRL)
+				inode->i_fop = &cifs_file_nobrl_ops;
+			else /* not direct, send byte range locks */ 
 				inode->i_fop = &cifs_file_ops;
+
 			inode->i_data.a_ops = &cifs_addr_ops;
+#if LINUX_VERSION_CODE > KERNEL_VERSION(2, 5, 0)
+			/* check if server can support readpages */
+			if(pTcon->ses->server->maxBuf < 
+			    PAGE_CACHE_SIZE + MAX_CIFS_HDR_SIZE)
+				inode->i_data.a_ops = &cifs_addr_ops_smallbuf;
+#endif
 		} else if (S_ISDIR(inode->i_mode)) {
-			cFYI(1, (" Directory inode"));
+			cFYI(1, ("Directory inode"));
 			inode->i_op = &cifs_dir_inode_ops;
 			inode->i_fop = &cifs_dir_ops;
 		} else if (S_ISLNK(inode->i_mode)) {
-			cFYI(1, (" Symbolic Link inode "));
+			cFYI(1, ("Symbolic Link inode"));
 			inode->i_op = &cifs_symlink_inode_ops;
 		/* tmp_inode->i_fop = */ /* do not need to set to anything */
 		} else {
-			cFYI(1, (" Init special inode "));
+			cFYI(1, ("Init special inode"));
 			init_special_inode(inode, inode->i_mode,
 					   inode->i_rdev);
 		}
@@ -184,6 +208,112 @@
 	return rc;
 }
 
+static int decode_sfu_inode(struct inode * inode, __u64 size,
+			    const unsigned char *path,
+			    struct cifs_sb_info *cifs_sb, int xid)
+{
+	int rc;
+	int oplock = FALSE;
+	__u16 netfid;
+	struct cifsTconInfo *pTcon = cifs_sb->tcon;
+	char buf[24];
+	unsigned int bytes_read;
+	char * pbuf;
+
+	pbuf = buf;
+
+	if(size == 0) {
+		inode->i_mode |= S_IFIFO;
+		return 0;
+	} else if (size < 8) {
+		return -EINVAL;	 /* EOPNOTSUPP? */
+	}
+		
+	rc = CIFSSMBOpen(xid, pTcon, path, FILE_OPEN, GENERIC_READ,
+			 CREATE_NOT_DIR, &netfid, &oplock, NULL,
+			 cifs_sb->local_nls,
+			 cifs_sb->mnt_cifs_flags &
+				CIFS_MOUNT_MAP_SPECIAL_CHR);
+	if (rc==0) {
+		int buf_type = CIFS_NO_BUFFER;
+			/* Read header */
+		rc = CIFSSMBRead(xid, pTcon,
+			         netfid,
+				 24 /* length */, 0 /* offset */,
+				 &bytes_read, &pbuf, &buf_type);
+		if((rc == 0) && (bytes_read >= 8)) {
+			if(memcmp("IntxBLK", pbuf, 8) == 0) {
+				cFYI(1,("Block device"));
+				inode->i_mode |= S_IFBLK;
+				if(bytes_read == 24) {
+					/* we have enough to decode dev num */
+					__u64 mjr; /* major */
+					__u64 mnr; /* minor */
+					mjr = le64_to_cpu(*(__le64 *)(pbuf+8));
+					mnr = le64_to_cpu(*(__le64 *)(pbuf+16));
+					inode->i_rdev = MKDEV(mjr, mnr);
+				}
+			} else if(memcmp("IntxCHR", pbuf, 8) == 0) {
+				cFYI(1,("Char device"));
+				inode->i_mode |= S_IFCHR;
+				if(bytes_read == 24) {
+					/* we have enough to decode dev num */
+					__u64 mjr; /* major */
+					__u64 mnr; /* minor */
+					mjr = le64_to_cpu(*(__le64 *)(pbuf+8));
+					mnr = le64_to_cpu(*(__le64 *)(pbuf+16));
+					inode->i_rdev = MKDEV(mjr, mnr);
+                                }
+			} else if(memcmp("IntxLNK", pbuf, 7) == 0) {
+				cFYI(1,("Symlink"));
+				inode->i_mode |= S_IFLNK;
+			} else {
+				inode->i_mode |= S_IFREG; /* file? */
+				rc = -EOPNOTSUPP; 
+			}
+		} else {
+			inode->i_mode |= S_IFREG; /* then it is a file */
+			rc = -EOPNOTSUPP; /* or some unknown SFU type */	
+		}		
+		CIFSSMBClose(xid, pTcon, netfid);
+	}
+	return rc;
+	
+}
+
+#define SFBITS_MASK (S_ISVTX | S_ISGID | S_ISUID)  /* SETFILEBITS valid bits */
+
+static int get_sfu_uid_mode(struct inode * inode,
+			const unsigned char *path,
+			struct cifs_sb_info *cifs_sb, int xid)
+{
+#ifdef CONFIG_CIFS_XATTR
+	ssize_t rc;
+	char ea_value[4];
+	__u32 mode;
+
+	rc = CIFSSMBQueryEA(xid, cifs_sb->tcon, path, "SETFILEBITS",
+			ea_value, 4 /* size of buf */, cifs_sb->local_nls,
+                        cifs_sb->mnt_cifs_flags & CIFS_MOUNT_MAP_SPECIAL_CHR);
+	if(rc < 0)
+		return (int)rc;
+	else if (rc > 3) {
+		mode = le32_to_cpu(*((__le32 *)ea_value));
+		inode->i_mode &= ~SFBITS_MASK; 
+		cFYI(1,("special bits 0%o org mode 0%o", mode, inode->i_mode));
+		inode->i_mode = (mode &  SFBITS_MASK) | inode->i_mode;
+		cFYI(1,("special mode bits 0%o", mode));
+		return 0;
+	} else {
+		return 0;
+	}
+#else
+	return -EOPNOTSUPP;
+#endif
+
+		
+}
+
 int cifs_get_inode_info(struct inode **pinode,
 	const unsigned char *search_path, FILE_ALL_INFO *pfindData,
 	struct super_block *sb, int xid)
@@ -196,7 +326,7 @@
 	char *buf = NULL;
 
 	pTcon = cifs_sb->tcon;
-	cFYI(1,("Getting info on %s ", search_path));
+	cFYI(1,("Getting info on %s", search_path));
 
 	if ((pfindData == NULL) && (*pinode != NULL)) {
 		if (CIFS_I(*pinode)->clientCanCacheRead) {
@@ -215,6 +345,16 @@
 		rc = CIFSSMBQPathInfo(xid, pTcon, search_path, pfindData,
 			      cifs_sb->local_nls, cifs_sb->mnt_cifs_flags & 
 				CIFS_MOUNT_MAP_SPECIAL_CHR);
+		/* BB optimize code so we do not make the above call
+		when server claims no NT SMB support and the above call
+		failed at least once - set flag in tcon or mount */
+		if((rc == -EOPNOTSUPP) || (rc == -EINVAL)) {
+			rc = SMBQueryInformation(xid, pTcon, search_path,
+					pfindData, cifs_sb->local_nls, 
+					cifs_sb->mnt_cifs_flags &
+					  CIFS_MOUNT_MAP_SPECIAL_CHR);
+		}
+		
 	}
 	/* dump_mem("\nQPathInfo return data",&findData, sizeof(findData)); */
 	if (rc) {
@@ -267,7 +407,6 @@
 			   there Windows server or network appliances for which
 			   IndexNumber field is not guaranteed unique? */
 
-#ifdef CONFIG_CIFS_EXPERIMENTAL		
 			if (cifs_sb->mnt_cifs_flags & CIFS_MOUNT_SERVER_INUM){
 				int rc1 = 0;
 				__u64 inode_num;
@@ -283,35 +422,36 @@
 				} else /* do we need cast or hash to ino? */
 					(*pinode)->i_ino = inode_num;
 			} /* else ino incremented to unique num in new_inode*/
-#endif /* CIFS_EXPERIMENTAL */
 			insert_inode_hash(*pinode);
 		}
 		inode = *pinode;
 		cifsInfo = CIFS_I(inode);
 		cifsInfo->cifsAttrs = attr;
-		cFYI(1, (" Old time %ld ", cifsInfo->time));
+		cFYI(1, ("Old time %ld", cifsInfo->time));
 		cifsInfo->time = jiffies;
-		cFYI(1, (" New time %ld ", cifsInfo->time));
+		cFYI(1, ("New time %ld", cifsInfo->time));
 
 		/* blksize needs to be multiple of two. So safer to default to
 		blksize and blkbits set in superblock so 2**blkbits and blksize
 		will match rather than setting to:
 		(pTcon->ses->server->maxBuf - MAX_CIFS_HDR_SIZE) & 0xFFFFFE00;*/
 
-		/* Linux can not store file creation time unfortunately so we ignore it */
+		/* Linux can not store file creation time so ignore it */
 		inode->i_atime =
 		    cifs_NTtimeToUnix(le64_to_cpu(pfindData->LastAccessTime));
 		inode->i_mtime =
 		    cifs_NTtimeToUnix(le64_to_cpu(pfindData->LastWriteTime));
 		inode->i_ctime =
 		    cifs_NTtimeToUnix(le64_to_cpu(pfindData->ChangeTime));
-		cFYI(0, (" Attributes came in as 0x%x ", attr));
+		cFYI(0, ("Attributes came in as 0x%x", attr));
 
 		/* set default mode. will override for dirs below */
 		if (atomic_read(&cifsInfo->inUse) == 0)
 			/* new inode, can safely set these fields */
 			inode->i_mode = cifs_sb->mnt_file_mode;
-
+		else /* since we set the inode type below we need to mask off
+		     to avoid strange results if type changes and both get orred in */ 
+			inode->i_mode &= ~S_IFMT; 
 /*		if (attr & ATTR_REPARSE)  */
 		/* We no longer handle these as symlinks because we could not
 		   follow them due to the absolute path with drive letter */
@@ -320,6 +460,22 @@
 		   on dirs */
 			inode->i_mode = cifs_sb->mnt_dir_mode;
 			inode->i_mode |= S_IFDIR;
+		} else if ((cifs_sb->mnt_cifs_flags & CIFS_MOUNT_UNX_EMUL) &&
+			   (cifsInfo->cifsAttrs & ATTR_SYSTEM) &&
+			   /* No need to le64 convert size of zero */
+			   (pfindData->EndOfFile == 0)) {
+			inode->i_mode = cifs_sb->mnt_file_mode;
+			inode->i_mode |= S_IFIFO;
+/* BB Finish for SFU style symlinks and devices */
+		} else if ((cifs_sb->mnt_cifs_flags & CIFS_MOUNT_UNX_EMUL) &&
+			   (cifsInfo->cifsAttrs & ATTR_SYSTEM)) {
+			if (decode_sfu_inode(inode, 
+					 le64_to_cpu(pfindData->EndOfFile),
+					 search_path,
+					 cifs_sb, xid)) {
+				cFYI(1,("Unrecognized sfu inode type"));
+			}
+			cFYI(1,("sfu mode 0%o",inode->i_mode));
 		} else {
 			inode->i_mode |= S_IFREG;
 			/* treat the dos attribute of read-only as read-only
@@ -332,7 +488,11 @@
 		if (is_size_safe_to_change(cifsInfo)) {
 			/* can not safely change the file size here if the
 			   client is writing to it due to potential races */
+#if LINUX_VERSION_CODE > KERNEL_VERSION(2, 5, 0)
 			i_size_write(inode,le64_to_cpu(pfindData->EndOfFile));
+#else
+			inode->i_size = pfindData->EndOfFile;
+#endif
 
 			/* 512 bytes (2**9) is the fake blocksize that must be
 			   used for this calculation */
@@ -344,7 +504,10 @@
 
 		/* BB fill in uid and gid here? with help from winbind? 
 		   or retrieve from NTFS stream extended attribute */
-		if (atomic_read(&cifsInfo->inUse) == 0) {
+		if(cifs_sb->mnt_cifs_flags & CIFS_MOUNT_UNX_EMUL) {
+			/* fill in uid, gid, mode from server ACL */
+			get_sfu_uid_mode(inode, search_path, cifs_sb, xid);
+		} else if (atomic_read(&cifsInfo->inUse) == 0) {
 			inode->i_uid = cifs_sb->mnt_uid;
 			inode->i_gid = cifs_sb->mnt_gid;
 			/* set so we do not keep refreshing these fields with
@@ -353,19 +516,31 @@
 		}
 
 		if (S_ISREG(inode->i_mode)) {
-			cFYI(1, (" File inode "));
+			cFYI(1, ("File inode"));
 			inode->i_op = &cifs_file_inode_ops;
-			if (cifs_sb->mnt_cifs_flags & CIFS_MOUNT_DIRECT_IO)
-				inode->i_fop = &cifs_file_direct_ops;
+			if (cifs_sb->mnt_cifs_flags & CIFS_MOUNT_DIRECT_IO) {
+				if (cifs_sb->mnt_cifs_flags & CIFS_MOUNT_NO_BRL)
+					inode->i_fop =
+						&cifs_file_direct_nobrl_ops;
 			else
+					inode->i_fop = &cifs_file_direct_ops;
+			} else if(cifs_sb->mnt_cifs_flags & CIFS_MOUNT_NO_BRL)
+				inode->i_fop = &cifs_file_nobrl_ops;
+			else /* not direct, send byte range locks */
 				inode->i_fop = &cifs_file_ops;
+
 			inode->i_data.a_ops = &cifs_addr_ops;
+#if LINUX_VERSION_CODE > KERNEL_VERSION(2, 5, 0)
+			if(pTcon->ses->server->maxBuf < 
+			     PAGE_CACHE_SIZE + MAX_CIFS_HDR_SIZE)
+				inode->i_data.a_ops = &cifs_addr_ops_smallbuf;
+#endif
 		} else if (S_ISDIR(inode->i_mode)) {
-			cFYI(1, (" Directory inode "));
+			cFYI(1, ("Directory inode"));
 			inode->i_op = &cifs_dir_inode_ops;
 			inode->i_fop = &cifs_dir_ops;
 		} else if (S_ISLNK(inode->i_mode)) {
-			cFYI(1, (" Symbolic Link inode "));
+			cFYI(1, ("Symbolic Link inode"));
 			inode->i_op = &cifs_symlink_inode_ops;
 		} else {
 			init_special_inode(inode, inode->i_mode,
@@ -402,11 +577,14 @@
 	struct cifsInodeInfo *cifsInode;
 	FILE_BASIC_INFO *pinfo_buf;
 
-	cFYI(1, (" cifs_unlink, inode = 0x%p with ", inode));
+	cFYI(1, ("cifs_unlink, inode = 0x%p", inode));
 
 	xid = GetXid();
 
+	if(inode)
 	cifs_sb = CIFS_SB(inode->i_sb);
+	else
+		cifs_sb = CIFS_SB(direntry->d_sb);
 	pTcon = cifs_sb->tcon;
 
 	/* Unlink can be called from rename so we can not grab the sem here
@@ -446,9 +624,8 @@
 		}
 	} else if (rc == -EACCES) {
 		/* try only if r/o attribute set in local lookup data? */
-		pinfo_buf = kmalloc(sizeof(FILE_BASIC_INFO), GFP_KERNEL);
+		pinfo_buf = kzalloc(sizeof(FILE_BASIC_INFO), GFP_KERNEL);
 		if (pinfo_buf) {
-			memset(pinfo_buf, 0, sizeof(FILE_BASIC_INFO));
 			/* ATTRS set to normal clears r/o bit */
 			pinfo_buf->Attributes = cpu_to_le32(ATTR_NORMAL);
 			if (!(pTcon->ses->flags & CIFS_SES_NT4))
@@ -530,9 +707,11 @@
 					   when needed */
 		direntry->d_inode->i_ctime = current_fs_time(inode->i_sb);
 	}
+	if(inode) {
 	inode->i_ctime = inode->i_mtime = current_fs_time(inode->i_sb);
 	cifsInode = CIFS_I(inode);
 	cifsInode->time = 0;	/* force revalidate of dir as well */
+	}
 
 	kfree(full_path);
 	FreeXid(xid);
@@ -548,16 +727,14 @@
 	char *full_path = NULL;
 	struct inode *newinode = NULL;
 
-	cFYI(1, ("In cifs_mkdir, mode = 0x%x inode = 0x%p ", mode, inode));
+	cFYI(1, ("In cifs_mkdir, mode = 0x%x inode = 0x%p", mode, inode));
 
 	xid = GetXid();
 
 	cifs_sb = CIFS_SB(inode->i_sb);
 	pTcon = cifs_sb->tcon;
 
-	down(&inode->i_sb->s_vfs_rename_sem);
 	full_path = build_path_from_dentry(direntry);
-	up(&inode->i_sb->s_vfs_rename_sem);
 	if (full_path == NULL) {
 		FreeXid(xid);
 		return -ENOMEM;
@@ -566,7 +743,7 @@
 	rc = CIFSSMBMkDir(xid, pTcon, full_path, cifs_sb->local_nls,
 			  cifs_sb->mnt_cifs_flags & CIFS_MOUNT_MAP_SPECIAL_CHR);
 	if (rc) {
-		cFYI(1, ("cifs_mkdir returned 0x%x ", rc));
+		cFYI(1, ("cifs_mkdir returned 0x%x", rc));
 		d_drop(direntry);
 	} else {
 		inode->i_nlink++;
@@ -577,6 +754,9 @@
 			rc = cifs_get_inode_info(&newinode, full_path, NULL,
 						 inode->i_sb,xid);
 
+		if (pTcon->nocase)
+			direntry->d_op = &cifs_ci_dentry_ops;
+		else
 		direntry->d_op = &cifs_dentry_ops;
 		d_instantiate(direntry, newinode);
 		if (direntry->d_inode)
@@ -585,8 +765,8 @@
 			if (cifs_sb->mnt_cifs_flags & CIFS_MOUNT_SET_UID) {
 				CIFSSMBUnixSetPerms(xid, pTcon, full_path,
 						    mode,
-						    (__u64)current->euid,
-						    (__u64)current->egid,
+						    (__u64)current->fsuid,
+						    (__u64)current->fsgid,
 						    0 /* dev_t */,
 						    cifs_sb->local_nls,
 						    cifs_sb->mnt_cifs_flags &
@@ -603,6 +783,17 @@
 			/* BB to be implemented via Windows secrty descriptors
 			   eg CIFSSMBWinSetPerms(xid, pTcon, full_path, mode,
 						 -1, -1, local_nls); */
+			if(direntry->d_inode) {
+				direntry->d_inode->i_mode = mode;
+				direntry->d_inode->i_mode |= S_IFDIR;
+				if(cifs_sb->mnt_cifs_flags & 
+				     CIFS_MOUNT_SET_UID) {
+					direntry->d_inode->i_uid = 
+						current->fsuid;
+					direntry->d_inode->i_gid = 
+						current->fsgid;
+				}
+			}
 		}
 	}
 	kfree(full_path);
@@ -619,16 +810,14 @@
 	char *full_path = NULL;
 	struct cifsInodeInfo *cifsInode;
 
-	cFYI(1, (" cifs_rmdir, inode = 0x%p with ", inode));
+	cFYI(1, ("cifs_rmdir, inode = 0x%p", inode));
 
 	xid = GetXid();
 
 	cifs_sb = CIFS_SB(inode->i_sb);
 	pTcon = cifs_sb->tcon;
 
-	down(&inode->i_sb->s_vfs_rename_sem);
 	full_path = build_path_from_dentry(direntry);
-	up(&inode->i_sb->s_vfs_rename_sem);
 	if (full_path == NULL) {
 		FreeXid(xid);
 		return -ENOMEM;
@@ -639,7 +828,11 @@
 
 	if (!rc) {
 		inode->i_nlink--;
+#if LINUX_VERSION_CODE > KERNEL_VERSION(2, 5, 0)
 		i_size_write(direntry->d_inode,0);
+#else
+		direntry->d_inode->i_size = 0;
+#endif
 		direntry->d_inode->i_nlink = 0;
 	}
 
@@ -864,9 +1057,9 @@
 	}
 
 	/* can not grab this sem since kernel filesys locking documentation
-	   indicates i_sem may be taken by the kernel on lookup and rename
-	   which could deadlock if we grab the i_sem here as well */
-/*	down(&direntry->d_inode->i_sem);*/
+	   indicates i_mutex may be taken by the kernel on lookup and rename
+	   which could deadlock if we grab the i_mutex here as well */
+/*	mutex_lock(&direntry->d_inode->i_mutex);*/
 	/* need to write out dirty pages here  */
 	if (direntry->d_inode->i_mapping) {
 		/* do we need to lock inode until after invalidate completes
@@ -874,17 +1067,23 @@
 		filemap_fdatawrite(direntry->d_inode->i_mapping);
 	}
 	if (invalidate_inode) {
+	/* shrink_dcache not necessary now that cifs dentry ops
+	are exported for negative dentries */
+/*		if(S_ISDIR(direntry->d_inode->i_mode)) 
+			shrink_dcache_parent(direntry); */
+		if (S_ISREG(direntry->d_inode->i_mode)) {
 		if (direntry->d_inode->i_mapping)
 			filemap_fdatawait(direntry->d_inode->i_mapping);
 		/* may eventually have to do this for open files too */
 		if (list_empty(&(cifsInode->openFileList))) {
-			/* Has changed on server - flush read ahead pages */
+				/* changed on server - flush read ahead pages */
 			cFYI(1, ("Invalidating read ahead data on "
 				 "closed file"));
 			invalidate_remote_inode(direntry->d_inode);
 		}
 	}
-/*	up(&direntry->d_inode->i_sem); */
+	}
+/*	mutex_unlock(&direntry->d_inode->i_mutex); */
 	
 	kfree(full_path);
 	FreeXid(xid);
@@ -928,7 +1127,6 @@
 	struct cifsTconInfo *pTcon;
 	char *full_path = NULL;
 	int rc = -EACCES;
-	int found = FALSE;
 	struct cifsFileInfo *open_file = NULL;
 	FILE_BASIC_INFO time_buf;
 	int set_time = FALSE;
@@ -936,18 +1134,26 @@
 	__u64 uid = 0xFFFFFFFFFFFFFFFFULL;
 	__u64 gid = 0xFFFFFFFFFFFFFFFFULL;
 	struct cifsInodeInfo *cifsInode;
-	struct list_head *tmp;
 
 	xid = GetXid();
 
-	cFYI(1, (" In cifs_setattr, name = %s attrs->iavalid 0x%x ",
+	cFYI(1, ("setattr on file %s attrs->iavalid 0x%x",
 		 direntry->d_name.name, attrs->ia_valid));
+
 	cifs_sb = CIFS_SB(direntry->d_inode->i_sb);
 	pTcon = cifs_sb->tcon;
 
-	down(&direntry->d_sb->s_vfs_rename_sem);
+	if ((cifs_sb->mnt_cifs_flags & CIFS_MOUNT_NO_PERM) == 0) {
+		/* check if we have permission to change attrs */
+		rc = inode_change_ok(direntry->d_inode, attrs);
+		if(rc < 0) {
+			FreeXid(xid);
+			return rc;
+		} else
+			rc = 0;
+	}
+		
 	full_path = build_path_from_dentry(direntry);
-	up(&direntry->d_sb->s_vfs_rename_sem);
 	if (full_path == NULL) {
 		FreeXid(xid);
 		return -ENOMEM;
@@ -957,11 +1163,14 @@
 	/* BB check if we need to refresh inode from server now ? BB */
 
 	/* need to flush data before changing file size on server */
+#if LINUX_VERSION_CODE > KERNEL_VERSION(2, 6, 15)
+	filemap_write_and_wait(direntry->d_inode->i_mapping);
+#else
 	filemap_fdatawrite(direntry->d_inode->i_mapping);
 	filemap_fdatawait(direntry->d_inode->i_mapping);
+#endif
 
 	if (attrs->ia_valid & ATTR_SIZE) {
-		read_lock(&GlobalSMBSeslock);
 		/* To avoid spurious oplock breaks from server, in the case of
 		   inodes that we already have open, avoid doing path based
 		   setting of file size if we can do it by handle.
@@ -969,39 +1178,25 @@
 		   when the local oplock break takes longer to flush
 		   writebehind data than the SMB timeout for the SetPathInfo
 		   request would allow */
-		list_for_each(tmp, &cifsInode->openFileList) {
-			open_file = list_entry(tmp, struct cifsFileInfo,
-					       flist);
-			/* We check if file is open for writing first */
-			if ((open_file->pfile) &&
-			    ((open_file->pfile->f_flags & O_RDWR) ||
-			    (open_file->pfile->f_flags & O_WRONLY))) {
-				if (open_file->invalidHandle == FALSE) {
-					/* we found a valid, writeable network
-					   file handle to use to try to set the
-					   file size */
+
+		open_file = find_writable_file(cifsInode);
+		if (open_file) {
 					__u16 nfid = open_file->netfid;
 					__u32 npid = open_file->pid;
-					read_unlock(&GlobalSMBSeslock);
-					found = TRUE;
-					rc = CIFSSMBSetFileSize(xid, pTcon,
-						attrs->ia_size, nfid, npid,
-						FALSE);
-					cFYI(1, ("SetFileSize by handle "
-						 "(setattrs) rc = %d", rc));
-					/* Do not need reopen and retry on
-					   EAGAIN since we will retry by
-					   pathname below */
-
-					/* now that we found one valid file
-					   handle no sense continuing to loop
-					   trying others, so break here */
-					break;
-				}
-			}
+			rc = CIFSSMBSetFileSize(xid, pTcon, attrs->ia_size,
+						nfid, npid, FALSE);
+			atomic_dec(&open_file->wrtPending);
+			cFYI(1,("SetFSize for attrs rc = %d", rc));
+			if((rc == -EINVAL) || (rc == -EOPNOTSUPP)) {
+				int bytes_written;
+				rc = CIFSSMBWrite(xid, pTcon,
+						  nfid, 0, attrs->ia_size,
+						  &bytes_written, NULL, NULL,
+						  1 /* 45 seconds */);
+				cFYI(1,("Wrt seteof rc %d", rc));
 		}
-		if (found == FALSE)
-			read_unlock(&GlobalSMBSeslock);
+		} else 
+			rc = -EINVAL;
 
 		if (rc != 0) {
 			/* Set file size by pathname rather than by handle
@@ -1013,7 +1208,30 @@
 					   cifs_sb->local_nls, 
 					   cifs_sb->mnt_cifs_flags &
 						CIFS_MOUNT_MAP_SPECIAL_CHR);
-			cFYI(1, (" SetEOF by path (setattrs) rc = %d", rc));
+			cFYI(1, ("SetEOF by path (setattrs) rc = %d", rc));
+			if((rc == -EINVAL) || (rc == -EOPNOTSUPP)) {
+				__u16 netfid;
+				int oplock = FALSE;
+
+				rc = SMBLegacyOpen(xid, pTcon, full_path,
+					FILE_OPEN,
+					SYNCHRONIZE | FILE_WRITE_ATTRIBUTES,
+					CREATE_NOT_DIR, &netfid, &oplock,
+					NULL, cifs_sb->local_nls,
+					cifs_sb->mnt_cifs_flags &
+						CIFS_MOUNT_MAP_SPECIAL_CHR);
+				if (rc==0) {
+					int bytes_written;
+					rc = CIFSSMBWrite(xid, pTcon,
+							netfid, 0,
+							attrs->ia_size,
+							&bytes_written, NULL,
+							NULL, 1 /* 45 sec */);
+					cFYI(1,("wrt seteof rc %d",rc));
+					CIFSSMBClose(xid, pTcon, netfid);
+				}
+
+			}
 		}
 
 		/* Server is ok setting allocation size implicitly - no need
@@ -1026,24 +1244,22 @@
 			rc = vmtruncate(direntry->d_inode, attrs->ia_size);
 			cifs_truncate_page(direntry->d_inode->i_mapping,
 					   direntry->d_inode->i_size);
-		}
+		} else 
+			goto cifs_setattr_exit;
 	}
 	if (attrs->ia_valid & ATTR_UID) {
-		cFYI(1, (" CIFS - UID changed to %d", attrs->ia_uid));
+		cFYI(1, ("UID changed to %d", attrs->ia_uid));
 		uid = attrs->ia_uid;
-		/* entry->uid = cpu_to_le16(attr->ia_uid); */
 	}
 	if (attrs->ia_valid & ATTR_GID) {
-		cFYI(1, (" CIFS - GID changed to %d", attrs->ia_gid));
+		cFYI(1, ("GID changed to %d", attrs->ia_gid));
 		gid = attrs->ia_gid;
-		/* entry->gid = cpu_to_le16(attr->ia_gid); */
 	}
 
 	time_buf.Attributes = 0;
 	if (attrs->ia_valid & ATTR_MODE) {
-		cFYI(1, (" CIFS - Mode changed to 0x%x", attrs->ia_mode));
+		cFYI(1, ("Mode changed to 0x%x", attrs->ia_mode));
 		mode = attrs->ia_mode;
-		/* entry->mode = cpu_to_le16(attr->ia_mode); */
 	}
 
 	if ((cifs_sb->tcon->ses->capabilities & CAP_UNIX)
@@ -1053,6 +1269,7 @@
 					 cifs_sb->mnt_cifs_flags & 
 						CIFS_MOUNT_MAP_SPECIAL_CHR);
 	else if (attrs->ia_valid & ATTR_MODE) {
+		rc = 0;
 		if ((mode & S_IWUGO) == 0) /* not writeable */ {
 			if ((cifsInode->cifsAttrs & ATTR_READONLY) == 0)
 				time_buf.Attributes =
@@ -1083,18 +1300,24 @@
 		    cpu_to_le64(cifs_UnixTimeToNT(attrs->ia_mtime));
 	} else
 		time_buf.LastWriteTime = 0;
+	/* Do not set ctime explicitly unless other time
+	   stamps are changed explicitly (i.e. by utime()
+	   since we would then have a mix of client and
+	   server times */
 
-	if (attrs->ia_valid & ATTR_CTIME) {
+	if (set_time && (attrs->ia_valid & ATTR_CTIME)) {
 		set_time = TRUE;
-		cFYI(1, (" CIFS - CTIME changed ")); /* BB probably no need */
+		/* Although Samba throws this field away
+		it may be useful to Windows - but we do
+		not want to set ctime unless some other
+		timestamp is changing */
+		cFYI(1, ("CIFS - CTIME changed"));
 		time_buf.ChangeTime =
 		    cpu_to_le64(cifs_UnixTimeToNT(attrs->ia_ctime));
 	} else
 		time_buf.ChangeTime = 0;
 
 	if (set_time || time_buf.Attributes) {
-		/* BB what if setting one attribute fails (such as size) but
-		   time setting works? */
 		time_buf.CreationTime = 0;	/* do not change */
 		/* In the future we should experiment - try setting timestamps
 		   via Handle (SetFileInfo) instead of by path */
@@ -1133,12 +1356,21 @@
         	        		&time_buf, cifs_sb->local_nls); */
 			}
 		}
+		/* Even if error on time set, no sense failing the call if
+		the server would set the time to a reasonable value anyway,
+		and this check ensures that we are not being called from
+		sys_utimes in which case we ought to fail the call back to
+		the user when the server rejects the call */
+		if((rc) && (attrs->ia_valid &&
+			 (ATTR_MODE | ATTR_GID | ATTR_UID | ATTR_SIZE)))
+			rc = 0;
 	}
 
 	/* do not need local check to inode_check_ok since the server does
 	   that */
 	if (!rc)
 		rc = inode_setattr(direntry->d_inode, attrs);
+cifs_setattr_exit:
 	kfree(full_path);
 	FreeXid(xid);
 	return rc;
@@ -1146,7 +1378,7 @@
 
 void cifs_delete_inode(struct inode *inode)
 {
-	cFYI(1, ("In cifs_delete_inode, inode = 0x%p ", inode));
+	cFYI(1, ("In cifs_delete_inode, inode = 0x%p", inode));
 	/* may have to add back in if and when safe distributed caching of
 	   directories added e.g. via FindNotify */
 }
--- linux-2.6.13/fs/cifs/link.c
+++ linux-2.6.13/fs/cifs/link.c
@@ -48,10 +48,8 @@
 /* No need to check for cross device links since server will do that
    BB note DFS case in future though (when we may have to check) */
 
-	down(&inode->i_sb->s_vfs_rename_sem);
 	fromName = build_path_from_dentry(old_file);
 	toName = build_path_from_dentry(direntry);
-	up(&inode->i_sb->s_vfs_rename_sem);
 	if((fromName == NULL) || (toName == NULL)) {
 		rc = -ENOMEM;
 		goto cifs_hl_exit;
@@ -67,7 +65,7 @@
 					cifs_sb_target->local_nls, 
 					cifs_sb_target->mnt_cifs_flags &
 						CIFS_MOUNT_MAP_SPECIAL_CHR);
-		if(rc == -EIO)
+		if((rc == -EIO) || (rc == -EINVAL))
 			rc = -EOPNOTSUPP;  
 	}
 
@@ -84,16 +82,18 @@
 	cifsInode->time = 0;	/* will force revalidate to go get info when needed */
 
 cifs_hl_exit:
-	if (fromName)
 		kfree(fromName);
-	if (toName)
 		kfree(toName);
 	FreeXid(xid);
 	return rc;
 }
-
+#if LINUX_VERSION_CODE > KERNEL_VERSION(2,6,12)
 void *
 cifs_follow_link(struct dentry *direntry, struct nameidata *nd)
+#else
+int
+cifs_follow_link(struct dentry *direntry, struct nameidata *nd)
+#endif
 {
 	struct inode *inode = direntry->d_inode;
 	int rc = -EACCES;
@@ -105,9 +105,7 @@
 
 	xid = GetXid();
 
-	down(&direntry->d_sb->s_vfs_rename_sem);
 	full_path = build_path_from_dentry(direntry);
-	up(&direntry->d_sb->s_vfs_rename_sem);
 
 	if (!full_path)
 		goto out_no_free;
@@ -138,6 +136,9 @@
 /* BB Add special case check for Samba DFS symlinks */
 
 		target_path[PATH_MAX-1] = 0;
+#if LINUX_VERSION_CODE < KERNEL_VERSION(2,6,9) 
+		rc = vfs_follow_link(nd, target_path);
+#endif
 	} else {
 		kfree(target_path);
 		target_path = ERR_PTR(rc);
@@ -147,8 +148,14 @@
 	kfree(full_path);
 out_no_free:
 	FreeXid(xid);
+#if LINUX_VERSION_CODE > KERNEL_VERSION(2,6,8) 
 	nd_set_link(nd, target_path);
+#endif
+#if LINUX_VERSION_CODE > KERNEL_VERSION(2,6,12)
 	return NULL;	/* No cookie */
+#else
+	return 0;
+#endif
 }
 
 int
@@ -166,16 +173,14 @@
 	cifs_sb = CIFS_SB(inode->i_sb);
 	pTcon = cifs_sb->tcon;
 
-	down(&inode->i_sb->s_vfs_rename_sem);
 	full_path = build_path_from_dentry(direntry);
-	up(&inode->i_sb->s_vfs_rename_sem);
 
 	if(full_path == NULL) {
 		FreeXid(xid);
 		return -ENOMEM;
 	}
 
-	cFYI(1, ("Full path: %s ", full_path));
+	cFYI(1, ("Full path: %s", full_path));
 	cFYI(1, ("symname is %s", symname));
 
 	/* BB what if DFS and this volume is on different share? BB */
@@ -194,16 +199,17 @@
 						 inode->i_sb,xid);
 
 		if (rc != 0) {
-			cFYI(1,
-			     ("Create symlink worked but get_inode_info failed with rc = %d ",
+			cFYI(1, ("Create symlink ok, getinodeinfo fail rc = %d",
 			      rc));
 		} else {
+			if (pTcon->nocase)
+				direntry->d_op = &cifs_ci_dentry_ops;
+			else
 			direntry->d_op = &cifs_dentry_ops;
 			d_instantiate(direntry, newinode);
 		}
 	}
 
-	if (full_path)
 		kfree(full_path);
 	FreeXid(xid);
 	return rc;
@@ -250,7 +256,6 @@
 		len = buflen;
 	tmpbuffer = kmalloc(len,GFP_KERNEL);   
 	if(tmpbuffer == NULL) {
-		if (full_path)
 			kfree(full_path);
 		FreeXid(xid);
 		return -ENOMEM;
@@ -296,11 +301,10 @@
 					else {
 						cFYI(1,("num referral: %d",num_referrals));
 						if(referrals) {
-							cFYI(1,("referral string: %s ",referrals));
+							cFYI(1,("referral string: %s",referrals));
 							strncpy(tmpbuffer, referrals, len-1);                            
 						}
 					}
-					if(referrals)
 						kfree(referrals);
 					kfree(tmp_path);
 }
@@ -320,19 +324,21 @@
 		      rc));
 	}
 
-	if (tmpbuffer) {
 		kfree(tmpbuffer);
-	}
-	if (full_path) {
 		kfree(full_path);
-	}
 	FreeXid(xid);
 	return rc;
 }
 
+#if LINUX_VERSION_CODE > KERNEL_VERSION(2,6,12)
 void cifs_put_link(struct dentry *direntry, struct nameidata *nd, void *cookie)
+#else
+void cifs_put_link(struct dentry *direntry, struct nameidata *nd)
+#endif
 {
+#if LINUX_VERSION_CODE > KERNEL_VERSION(2,6,8)
 	char *p = nd_get_link(nd);
 	if (!IS_ERR(p))
 		kfree(p);
+#endif
 }
--- linux-2.6.13/fs/cifs/Makefile
+++ linux-2.6.13/fs/cifs/Makefile
@@ -3,4 +3,4 @@
 #
 obj-$(CONFIG_CIFS) += cifs.o
 
-cifs-objs := cifsfs.o cifssmb.o cifs_debug.o connect.o dir.o file.o inode.o link.o misc.o netmisc.o smbdes.o smbencrypt.o transport.o asn1.o md4.o md5.o cifs_unicode.o nterr.o xattr.o cifsencrypt.o fcntl.o readdir.o ioctl.o
+cifs-objs := cifsfs.o cifssmb.o cifs_debug.o connect.o dir.o file.o inode.o link.o misc.o netmisc.o smbdes.o smbencrypt.o transport.o asn1.o md4.o md5.o cifs_unicode.o nterr.o xattr.o cifsencrypt.o fcntl.o readdir.o ioctl.o sess.o
--- linux-2.6.13/fs/cifs/misc.c
+++ linux-2.6.13/fs/cifs/misc.c
@@ -1,7 +1,7 @@
 /*
  *   fs/cifs/misc.c
  *
- *   Copyright (C) International Business Machines  Corp., 2002,2004
+ *   Copyright (C) International Business Machines  Corp., 2002,2005
  *   Author(s): Steve French (sfrench@us.ibm.com)
  *
  *   This library is free software; you can redistribute it and/or modify
@@ -21,7 +21,10 @@
 
 #include <linux/slab.h>
 #include <linux/ctype.h>
+#include <linux/version.h>
+#if LINUX_VERSION_CODE > KERNEL_VERSION(2, 5, 0)
 #include <linux/mempool.h>
+#endif
 #include "cifspdu.h"
 #include "cifsglob.h"
 #include "cifsproto.h"
@@ -30,12 +33,15 @@
 #include "nterr.h"
 #include "cifs_unicode.h"
 
+#if LINUX_VERSION_CODE > KERNEL_VERSION(2, 5, 0)
 extern mempool_t *cifs_sm_req_poolp;
 extern mempool_t *cifs_req_poolp;
+#else
+extern kmem_cache_t *cifs_sm_req_cachep;
+extern kmem_cache_t *cifs_req_cachep;
+#endif
 extern struct task_struct * oplockThread;
 
-static __u16 GlobalMid;		/* multiplex id - rotating counter */
-
 /* The xid serves as a useful identifier for each incoming vfs request, 
    in a similar way to the mid which is useful to track each sent smb, 
    and CurrentXid can also provide a running counter (although it 
@@ -51,6 +57,8 @@
 	GlobalTotalActiveXid++;
 	if (GlobalTotalActiveXid > GlobalMaxActiveXid)
 		GlobalMaxActiveXid = GlobalTotalActiveXid;	/* keep high water mark for number of simultaneous vfs ops in our filesystem */
+	if(GlobalTotalActiveXid > 65000)
+		cFYI(1,("warning: more than 65000 requests active"));
 	xid = GlobalCurrentXid++;
 	spin_unlock(&GlobalMid_Lock);
 	return xid;
@@ -72,10 +80,9 @@
 	struct cifsSesInfo *ret_buf;
 
 	ret_buf =
-	    (struct cifsSesInfo *) kmalloc(sizeof (struct cifsSesInfo),
+	    (struct cifsSesInfo *) kzalloc(sizeof (struct cifsSesInfo),
 					   GFP_KERNEL);
 	if (ret_buf) {
-		memset(ret_buf, 0, sizeof (struct cifsSesInfo));
 		write_lock(&GlobalSMBSeslock);
 		atomic_inc(&sesInfoAllocCount);
 		ret_buf->status = CifsNew;
@@ -98,14 +105,11 @@
 	atomic_dec(&sesInfoAllocCount);
 	list_del(&buf_to_free->cifsSessionList);
 	write_unlock(&GlobalSMBSeslock);
-	if (buf_to_free->serverOS)
 		kfree(buf_to_free->serverOS);
-	if (buf_to_free->serverDomain)
 		kfree(buf_to_free->serverDomain);
-	if (buf_to_free->serverNOS)
 		kfree(buf_to_free->serverNOS);
-	if (buf_to_free->password)
 		kfree(buf_to_free->password);
+	kfree(buf_to_free->domainName);
 	kfree(buf_to_free);
 }
 
@@ -114,10 +118,9 @@
 {
 	struct cifsTconInfo *ret_buf;
 	ret_buf =
-	    (struct cifsTconInfo *) kmalloc(sizeof (struct cifsTconInfo),
+	    (struct cifsTconInfo *) kzalloc(sizeof (struct cifsTconInfo),
 					    GFP_KERNEL);
 	if (ret_buf) {
-		memset(ret_buf, 0, sizeof (struct cifsTconInfo));
 		write_lock(&GlobalSMBSeslock);
 		atomic_inc(&tconInfoAllocCount);
 		list_add(&ret_buf->cifsConnectionList,
@@ -144,7 +147,6 @@
 	atomic_dec(&tconInfoAllocCount);
 	list_del(&buf_to_free->cifsConnectionList);
 	write_unlock(&GlobalSMBSeslock);
-	if (buf_to_free->nativeFileSystem)
 		kfree(buf_to_free->nativeFileSystem);
 	kfree(buf_to_free);
 }
@@ -159,13 +161,20 @@
    albeit slightly larger than necessary and maxbuffersize 
    defaults to this and can not be bigger */
 	ret_buf =
+#if LINUX_VERSION_CODE > KERNEL_VERSION(2, 5, 0)
 	    (struct smb_hdr *) mempool_alloc(cifs_req_poolp, SLAB_KERNEL | SLAB_NOFS);
+#else
+	    (struct smb_hdr *) kmem_cache_alloc(cifs_req_cachep, SLAB_KERNEL);
+#endif
 
 	/* clear the first few header bytes */
 	/* for most paths, more is cleared in header_assemble */
 	if (ret_buf) {
 		memset(ret_buf, 0, sizeof(struct smb_hdr) + 3);
 		atomic_inc(&bufAllocCount);
+#ifdef CONFIG_CIFS_STATS2
+		atomic_inc(&totBufAllocCount);
+#endif /* CONFIG_CIFS_STATS2 */
 	}
 
 	return ret_buf;
@@ -179,8 +188,11 @@
 		/* cFYI(1, ("Null buffer passed to cifs_buf_release"));*/
 		return;
 	}
+#if LINUX_VERSION_CODE > KERNEL_VERSION(2, 5, 0)
 	mempool_free(buf_to_free,cifs_req_poolp);
-
+#else
+	kmem_cache_free(cifs_req_cachep, buf_to_free);
+#endif
 	atomic_dec(&bufAllocCount);
 	return;
 }
@@ -195,11 +207,19 @@
    albeit slightly larger than necessary and maxbuffersize 
    defaults to this and can not be bigger */
 	ret_buf =
+#if LINUX_VERSION_CODE > KERNEL_VERSION(2, 5, 0)
 	    (struct smb_hdr *) mempool_alloc(cifs_sm_req_poolp, SLAB_KERNEL | SLAB_NOFS);
+#else
+	    (struct smb_hdr *) kmem_cache_alloc(cifs_sm_req_cachep, SLAB_KERNEL);
+#endif
 	if (ret_buf) {
 	/* No need to clear memory here, cleared in header assemble */
 	/*	memset(ret_buf, 0, sizeof(struct smb_hdr) + 27);*/
 		atomic_inc(&smBufAllocCount);
+#ifdef CONFIG_CIFS_STATS2
+		atomic_inc(&totSmBufAllocCount);
+#endif /* CONFIG_CIFS_STATS2 */
+
 	}
 	return ret_buf;
 }
@@ -212,12 +232,86 @@
 		cFYI(1, ("Null buffer passed to cifs_small_buf_release"));
 		return;
 	}
+#if LINUX_VERSION_CODE > KERNEL_VERSION(2, 5, 0)
 	mempool_free(buf_to_free,cifs_sm_req_poolp);
+#else
+	kmem_cache_free(cifs_sm_req_cachep, buf_to_free);
+#endif
 
 	atomic_dec(&smBufAllocCount);
 	return;
 }
 
+/* 
+	Find a free multiplex id (SMB mid). Otherwise there could be
+	mid collisions which might cause problems, demultiplexing the
+	wrong response to this request. Multiplex ids could collide if
+	one of a series requests takes much longer than the others, or
+	if a very large number of long lived requests (byte range
+	locks or FindNotify requests) are pending.  No more than
+	64K-1 requests can be outstanding at one time.  If no 
+	mids are available, return zero.  A future optimization
+	could make the combination of mids and uid the key we use
+	to demultiplex on (rather than mid alone).  
+	In addition to the above check, the cifs demultiplex
+	code already used the command code as a secondary
+	check of the frame and if signing is negotiated the
+	response would be discarded if the mid were the same
+	but the signature was wrong.  Since the mid is not put in the
+	pending queue until later (when it is about to be dispatched)
+	we do have to limit the number of outstanding requests 
+	to somewhat less than 64K-1 although it is hard to imagine
+	so many threads being in the vfs at one time.
+*/
+__u16 GetNextMid(struct TCP_Server_Info *server)
+{
+	__u16 mid = 0;
+	__u16 last_mid;
+	int   collision;  
+
+	if(server == NULL)
+		return mid;
+
+	spin_lock(&GlobalMid_Lock);
+	last_mid = server->CurrentMid; /* we do not want to loop forever */
+	server->CurrentMid++;
+	/* This nested loop looks more expensive than it is.
+	In practice the list of pending requests is short, 
+	fewer than 50, and the mids are likely to be unique
+	on the first pass through the loop unless some request
+	takes longer than the 64 thousand requests before it
+	(and it would also have to have been a request that
+	 did not time out) */
+	while(server->CurrentMid != last_mid) {
+		struct list_head *tmp;
+		struct mid_q_entry *mid_entry;
+
+		collision = 0;
+		if(server->CurrentMid == 0)
+			server->CurrentMid++;
+
+		list_for_each(tmp, &server->pending_mid_q) {
+			mid_entry = list_entry(tmp, struct mid_q_entry, qhead);
+
+			if ((mid_entry->mid == server->CurrentMid) &&
+			    (mid_entry->midState == MID_REQUEST_SUBMITTED)) {
+				/* This mid is in use, try a different one */
+				collision = 1;
+				break;
+			}
+		}
+		if(collision == 0) {
+			mid = server->CurrentMid;
+			break;
+		}
+		server->CurrentMid++;
+	}
+	spin_unlock(&GlobalMid_Lock);
+	return mid;
+}
+
+/* NB: MID can not be set if treeCon not passed in, in that
+   case it is responsbility of caller to set the mid */
 void
 header_assemble(struct smb_hdr *buffer, char smb_command /* command */ ,
 		const struct cifsTconInfo *treeCon, int word_count
@@ -227,13 +321,14 @@
 	struct cifsSesInfo * ses;
 	char *temp = (char *) buffer;
 
-	memset(temp,0,MAX_CIFS_HDR_SIZE);
+	memset(temp,0,256); /* bigger than MAX_CIFS_HDR_SIZE */
 
 	buffer->smb_buf_length =
 	    (2 * word_count) + sizeof (struct smb_hdr) -
 	    4 /*  RFC 1001 length field does not count */  +
 	    2 /* for bcc field itself */ ;
-	/* Note that this is the only network field that has to be converted to big endian and it is done just before we send it */
+	/* Note that this is the only network field that has to be converted
+	   to big endian and it is done just before we send it */
 
 	buffer->Protocol[0] = 0xFF;
 	buffer->Protocol[1] = 'S';
@@ -245,8 +340,6 @@
 	buffer->Pid = cpu_to_le16((__u16)current->tgid);
 	buffer->PidHigh = cpu_to_le16((__u16)(current->tgid >> 16));
 	spin_lock(&GlobalMid_Lock);
-	GlobalMid++;
-	buffer->Mid = GlobalMid;
 	spin_unlock(&GlobalMid_Lock);
 	if (treeCon) {
 		buffer->Tid = treeCon->tid;
@@ -256,8 +349,9 @@
 			if (treeCon->ses->capabilities & CAP_STATUS32) {
 				buffer->Flags2 |= SMBFLG2_ERR_STATUS;
 			}
-
-			buffer->Uid = treeCon->ses->Suid;	/* always in LE format */
+			/* Uid is not converted */
+			buffer->Uid = treeCon->ses->Suid;
+			buffer->Mid = GetNextMid(treeCon->ses->server);
 			if(multiuser_mount != 0) {
 		/* For the multiuser case, there are few obvious technically  */
 		/* possible mechanisms to match the local linux user (uid)    */
@@ -283,12 +377,12 @@
 		/*  BB Add support for establishing new tCon and SMB Session  */
 		/*      with userid/password pairs found on the smb session   */ 
 		/*	for other target tcp/ip addresses 		BB    */
-				if(current->uid != treeCon->ses->linux_uid) {
-					cFYI(1,("Multiuser mode and UID did not match tcon uid "));
+				if(current->fsuid != treeCon->ses->linux_uid) {
+					cFYI(1,("Multiuser mode and UID did not match tcon uid"));
 					read_lock(&GlobalSMBSeslock);
 					list_for_each(temp_item, &GlobalSMBSessionList) {
 						ses = list_entry(temp_item, struct cifsSesInfo, cifsSessionList);
-						if(ses->linux_uid == current->uid) {
+						if(ses->linux_uid == current->fsuid) {
 							if(ses->server == treeCon->ses->server) {
 								cFYI(1,("found matching uid substitute right smb_uid"));  
 								buffer->Uid = ses->Suid;
@@ -305,6 +399,8 @@
 		}
 		if (treeCon->Flags & SMB_SHARE_IS_IN_DFS)
 			buffer->Flags2 |= SMBFLG2_DFS;
+		if (treeCon->nocase)
+			buffer->Flags  |= SMBFLG_CASELESS;
 		if((treeCon->ses) && (treeCon->ses->server))
 			if(treeCon->ses->server->secMode & 
 			  (SECMODE_SIGN_REQUIRED | SECMODE_SIGN_ENABLED))
@@ -330,12 +426,12 @@
 			if(smb->Command == SMB_COM_LOCKING_ANDX)
 				return 0;
 			else
-				cERROR(1, ("Rcvd Request not response "));         
+				cERROR(1, ("Rcvd Request not response"));         
 		}
 	} else { /* bad signature or mid */
 		if (*(__le32 *) smb->Protocol != cpu_to_le32(0x424d53ff))
 			cERROR(1,
-			       ("Bad protocol string signature header %x ",
+			       ("Bad protocol string signature header %x",
 				*(unsigned int *) smb->Protocol));
 		if (mid != smb->Mid)
 			cERROR(1, ("Mids do not match"));
@@ -347,10 +443,9 @@
 int
 checkSMB(struct smb_hdr *smb, __u16 mid, int length)
 {
-	__u32 len = be32_to_cpu(smb->smb_buf_length);
-	cFYI(0,
-	     ("Entering checkSMB with Length: %x, smb_buf_length: %x ",
-	      length, len));
+	__u32 len = smb->smb_buf_length;
+	__u32 clc_len;  /* calculated length */
+	cFYI(0, ("checkSMB Length: 0x%x, smb_buf_length: 0x%x", length, len));
 	if (((unsigned int)length < 2 + sizeof (struct smb_hdr)) ||
 	    (len > CIFSMaxBufSize + MAX_CIFS_HDR_SIZE - 4)) {
 		if ((unsigned int)length < 2 + sizeof (struct smb_hdr)) {
@@ -358,36 +453,59 @@
 				sizeof (struct smb_hdr) - 1)
 			    && (smb->Status.CifsError != 0)) {
 				smb->WordCount = 0;
-				return 0;	/* some error cases do not return wct and bcc */
+				/* some error cases do not return wct and bcc */
+				return 0;
 			} else {
 				cERROR(1, ("Length less than smb header size"));
 			}
-
 		}
 		if (len > CIFSMaxBufSize + MAX_CIFS_HDR_SIZE - 4)
-			cERROR(1,
-			       ("smb_buf_length greater than MaxBufSize"));
-		cERROR(1,
-		       ("bad smb detected. Illegal length. The mid=%d",
+			cERROR(1, ("smb length greater than MaxBufSize, mid=%d",
 			smb->Mid));
 		return 1;
 	}
 
 	if (checkSMBhdr(smb, mid))
 		return 1;
+	clc_len = smbCalcSize_LE(smb);
 
-	if ((4 + len != smbCalcSize(smb))
-	    || (4 + len != (unsigned int)length)) {
+	if(4 + len != (unsigned int)length) {
+		cERROR(1, ("Length read does not match RFC1001 length %d",len));
+		return 1;
+	}
+
+	if (4 + len != clc_len) {
+		/* check if bcc wrapped around for large read responses */
+		if((len > 64 * 1024) && (len > clc_len)) {
+			/* check if lengths match mod 64K */
+			if(((4 + len) & 0xFFFF) == (clc_len & 0xFFFF))
+				return 0; /* bcc wrapped */			
+		}
+		cFYI(1, ("Calculated size %d vs length %d mismatch for mid %d",
+				clc_len, 4 + len, smb->Mid));
+		/* Windows XP can return a few bytes too much, presumably
+		an illegal pad, at the end of byte range lock responses 
+		so we allow for that three byte pad, as long as actual
+		received length is as long or longer than calculated length */
+		/* We have now had to extend this more, since there is a 
+		case in which it needs to be bigger still to handle a
+		malformed response to transact2 findfirst from WinXP when
+		access denied is returned and thus bcc and wct are zero
+		but server says length is 0x21 bytes too long as if the server
+		forget to reset the smb rfc1001 length when it reset the
+		wct and bcc to minimum size and drop the t2 parms and data */
+		if((4+len > clc_len) && (len <= clc_len + 512))
 		return 0;
-	} else {
-		cERROR(1, ("smbCalcSize %x ", smbCalcSize(smb)));
-		cERROR(1,
-		       ("bad smb size detected. The Mid=%d", smb->Mid));
+		else {
+			cERROR(1, ("RFC1001 size %d bigger than SMB for Mid=%d",
+					len, smb->Mid));
 		return 1;
 	}
+	}
+	return 0;
 }
 int
-is_valid_oplock_break(struct smb_hdr *buf)
+is_valid_oplock_break(struct smb_hdr *buf, struct TCP_Server_Info *srv)
 {    
 	struct smb_com_lock_req * pSMB = (struct smb_com_lock_req *)buf;
 	struct list_head *tmp;
@@ -405,11 +523,12 @@
 		if(pSMBr->ByteCount > sizeof(struct file_notify_information)) {
 			data_offset = le32_to_cpu(pSMBr->DataOffset);
 
-			pnotify = (struct file_notify_information *)((char *)&pSMBr->hdr.Protocol
-				+ data_offset);
-			cFYI(1,("dnotify on %s with action: 0x%x",pnotify->FileName,
+			pnotify = (struct file_notify_information *)
+				((char *)&pSMBr->hdr.Protocol + data_offset);
+			cFYI(1,("dnotify on %s Action: 0x%x",pnotify->FileName,
 				pnotify->Action));  /* BB removeme BB */
-	             /*   cifs_dump_mem("Received notify Data is: ",buf,sizeof(struct smb_hdr)+60); */
+	             /*   cifs_dump_mem("Rcvd notify Data: ",buf,
+				sizeof(struct smb_hdr)+60); */
 			return TRUE;
 		}
 		if(pSMBr->hdr.Status.CifsError) {
@@ -447,10 +566,8 @@
 	read_lock(&GlobalSMBSeslock);
 	list_for_each(tmp, &GlobalTreeConnectionList) {
 		tcon = list_entry(tmp, struct cifsTconInfo, cifsConnectionList);
-		if (tcon->tid == buf->Tid) {
-#ifdef CONFIG_CIFS_STATS
-			atomic_inc(&tcon->num_oplock_brks);
-#endif
+		if ((tcon->tid == buf->Tid) && (srv == tcon->ses->server)) {
+			cifs_stats_inc(&tcon->num_oplock_brks);
 			list_for_each(tmp1,&tcon->openFileList){
 				netfile = list_entry(tmp1,struct cifsFileInfo,
 						     tlist);
@@ -603,9 +720,10 @@
 	int i,j,charlen;
 	int len_remaining = maxlen;
 	char src_char;
+	__u16 temp;
 
 	if(!mapChars) 
-		return cifs_strtoUCS((wchar_t *) target, source, PATH_MAX, cp);
+		return cifs_strtoUCS(target, source, PATH_MAX, cp);
 
 	for(i = 0, j = 0; i < maxlen; j++) {
 		src_char = source[i];
@@ -639,13 +757,14 @@
 				break;*/
 			default:
 				charlen = cp->char2uni(source+i,
-					len_remaining, target+j);
+					len_remaining, &temp);
 				/* if no match, use question mark, which
 				at least in some cases servers as wild card */
 				if(charlen < 1) {
 					target[j] = cpu_to_le16(0x003f);
 					charlen = 1;
-				}
+				} else
+					target[j] = cpu_to_le16(temp);
 				len_remaining -= charlen;
 				/* character may take more than one byte in the
 				   the source string, but will take exactly two
--- linux-2.6.13/fs/cifs/netmisc.c
+++ linux-2.6.13/fs/cifs/netmisc.c
@@ -84,11 +84,11 @@
 
 static const struct smb_to_posix_error mapping_table_ERRSRV[] = {
 	{ERRerror, -EIO},
-	{ERRbadpw, -EPERM},
+	{ERRbadpw, -EACCES},  /* was EPERM */
 	{ERRbadtype, -EREMOTE},
 	{ERRaccess, -EACCES},
 	{ERRinvtid, -ENXIO},
-	{ERRinvnetname, -ENODEV},
+	{ERRinvnetname, -ENXIO},
 	{ERRinvdevice, -ENXIO},
 	{ERRqfull, -ENOSPC},
 	{ERRqtoobig, -ENOSPC},
@@ -133,7 +133,6 @@
 int
 cifs_inet_pton(int address_family, char *cp,void *dst)
 {
-	struct in_addr address;
 	int value;
 	int digit;
 	int i;
@@ -190,8 +189,7 @@
 	if (value > addr_class_max[end - bytes])
 		return 0;
 
-	address.s_addr = *((__be32 *) bytes) | htonl(value);
-	*((__be32 *)dst) = address.s_addr;
+	*((__be32 *)dst) = *((__be32 *) bytes) | htonl(value);
 	return 1; /* success */
 }
 
@@ -332,7 +330,7 @@
 	ERRHRD, ERRgeneral, NT_STATUS_ACCOUNT_RESTRICTION}, {
 	ERRSRV, 2241, NT_STATUS_INVALID_LOGON_HOURS}, {
 	ERRSRV, 2240, NT_STATUS_INVALID_WORKSTATION}, {
-	ERRSRV, 2242, NT_STATUS_PASSWORD_EXPIRED}, {
+	ERRSRV, ERRpasswordExpired, NT_STATUS_PASSWORD_EXPIRED}, {
 	ERRSRV, 2239, NT_STATUS_ACCOUNT_DISABLED}, {
 	ERRHRD, ERRgeneral, NT_STATUS_NONE_MAPPED}, {
 	ERRHRD, ERRgeneral, NT_STATUS_TOO_MANY_LUIDS_REQUESTED}, {
@@ -678,7 +676,7 @@
 	ERRDOS, 193, NT_STATUS_IMAGE_CHECKSUM_MISMATCH}, {
 	ERRHRD, ERRgeneral, NT_STATUS_LOST_WRITEBEHIND_DATA}, {
 	ERRHRD, ERRgeneral, NT_STATUS_CLIENT_SERVER_PARAMETERS_INVALID}, {
-	ERRSRV, 2242, NT_STATUS_PASSWORD_MUST_CHANGE}, {
+	ERRSRV, ERRpasswordExpired, NT_STATUS_PASSWORD_MUST_CHANGE}, {
 	ERRHRD, ERRgeneral, NT_STATUS_NOT_FOUND}, {
 	ERRHRD, ERRgeneral, NT_STATUS_NOT_TINY_STREAM}, {
 	ERRHRD, ERRgeneral, NT_STATUS_RECOVERY_FAILURE}, {
@@ -815,7 +813,7 @@
 	if (smb->Flags2 & SMBFLG2_ERR_STATUS) {
 		/* translate the newer STATUS codes to old style errors and then to POSIX errors */
 		__u32 err = le32_to_cpu(smb->Status.CifsError);
-		if(cifsFYI)
+		if(cifsFYI & CIFS_RC)
 			cifs_print_status(err);
 		ntstatus_to_dos(err, &smberrclass, &smberrcode);
 	} else {
@@ -870,7 +868,14 @@
 smbCalcSize(struct smb_hdr *ptr)
 {
 	return (sizeof (struct smb_hdr) + (2 * ptr->WordCount) +
-		BCC(ptr));
+		2 /* size of the bcc field */ + BCC(ptr));
+}
+
+unsigned int
+smbCalcSize_LE(struct smb_hdr *ptr)
+{
+	return (sizeof (struct smb_hdr) + (2 * ptr->WordCount) +
+		2 /* size of the bcc field */ + le16_to_cpu(BCC_LE(ptr)));
 }
 
 /* The following are taken from fs/ntfs/util.c */
@@ -881,6 +886,8 @@
      * Convert the NT UTC (based 1601-01-01, in hundred nanosecond units)
      * into Unix UTC (based 1970-01-01, in seconds).
      */
+
+#if LINUX_VERSION_CODE > KERNEL_VERSION(2,5,0)
 struct timespec
 cifs_NTtimeToUnix(u64 ntutc)
 {
@@ -903,3 +910,4 @@
 	/* Convert to 100ns intervals and then add the NTFS time offset. */
 	return (u64) t.tv_sec * 10000000 + t.tv_nsec/100 + NTFS_TIME_OFFSET;
 }
+#endif
--- linux-2.6.13/fs/cifs/ntlmssp.h
+++ linux-2.6.13/fs/cifs/ntlmssp.h
@@ -1,7 +1,7 @@
 /*
  *   fs/cifs/ntlmssp.h
  *
- *   Copyright (c) International Business Machines  Corp., 2002
+ *   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
@@ -19,8 +19,6 @@
  *   Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA 
  */
 
-#pragma pack(1)
-
 #define NTLMSSP_SIGNATURE "NTLMSSP"
 /* Message Types */
 #define NtLmNegotiate     cpu_to_le32(1)
@@ -63,7 +61,7 @@
 	__le16 Length;
 	__le16 MaximumLength;
 	__le32 Buffer;		/* offset to buffer */
-} SECURITY_BUFFER;
+} __attribute__((packed)) SECURITY_BUFFER;
 
 typedef struct _NEGOTIATE_MESSAGE {
 	__u8 Signature[sizeof (NTLMSSP_SIGNATURE)];
@@ -73,7 +71,7 @@
 	SECURITY_BUFFER WorkstationName;	/* RFC 1001 and ASCII */
 	char DomainString[0];
 	/* followed by WorkstationString */
-} NEGOTIATE_MESSAGE, *PNEGOTIATE_MESSAGE;
+} __attribute__((packed)) NEGOTIATE_MESSAGE, *PNEGOTIATE_MESSAGE;
 
 typedef struct _CHALLENGE_MESSAGE {
 	__u8 Signature[sizeof (NTLMSSP_SIGNATURE)];
@@ -83,7 +81,7 @@
 	__u8 Challenge[CIFS_CRYPTO_KEY_SIZE];
 	__u8 Reserved[8];
 	SECURITY_BUFFER TargetInfoArray;
-} CHALLENGE_MESSAGE, *PCHALLENGE_MESSAGE;
+} __attribute__((packed)) CHALLENGE_MESSAGE, *PCHALLENGE_MESSAGE;
 
 typedef struct _AUTHENTICATE_MESSAGE {
 	__u8 Signature[sizeof (NTLMSSP_SIGNATURE)];
@@ -96,6 +94,4 @@
 	SECURITY_BUFFER SessionKey;
 	__le32 NegotiateFlags;
 	char UserString[0];
-} AUTHENTICATE_MESSAGE, *PAUTHENTICATE_MESSAGE;
-
-#pragma pack()			/* resume default structure packing */
+} __attribute__((packed)) AUTHENTICATE_MESSAGE, *PAUTHENTICATE_MESSAGE;
--- linux-2.6.13/fs/cifs/readdir.c
+++ linux-2.6.13/fs/cifs/readdir.c
@@ -21,6 +21,7 @@
  *   Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
  */
 #include <linux/fs.h>
+#include <linux/pagemap.h>
 #include <linux/stat.h>
 #include <linux/smp_lock.h>
 #include "cifspdu.h"
@@ -31,8 +32,8 @@
 #include "cifs_fs_sb.h"
 #include "cifsfs.h"
 
-/* BB fixme - add debug wrappers around this function to disable it fixme BB */
-/* static void dump_cifs_file_struct(struct file *file, char *label)
+#ifdef CONFIG_CIFS_DEBUG2
+static void dump_cifs_file_struct(struct file *file, char *label)
 {
 	struct cifsFileInfo * cf;
 
@@ -53,7 +54,8 @@
 		}
 		
 	}
-} */
+}
+#endif /* DEBUG2 */
 
 /* Returns one if new inode created (which therefore needs to be hashed) */
 /* Might check in the future if inode number changed so we can rehash inode */
@@ -91,6 +93,9 @@
 		}
 
 		*ptmp_inode = new_inode(file->f_dentry->d_sb);
+		if (pTcon->nocase)
+			tmp_dentry->d_op = &cifs_ci_dentry_ops;
+		else
 		tmp_dentry->d_op = &cifs_dentry_ops;
 		if(*ptmp_inode == NULL)
 			return rc;
@@ -104,32 +109,52 @@
 	return rc;
 }
 
-static void fill_in_inode(struct inode *tmp_inode,
-	FILE_DIRECTORY_INFO *pfindData, int *pobject_type, int isNewInode)
+static void fill_in_inode(struct inode *tmp_inode, int new_buf_type,
+		char * buf, int *pobject_type, int isNewInode)
 {
 	loff_t local_size;
 	struct timespec local_mtime;
 
 	struct cifsInodeInfo *cifsInfo = CIFS_I(tmp_inode);
 	struct cifs_sb_info *cifs_sb = CIFS_SB(tmp_inode->i_sb);
-	__u32 attr = le32_to_cpu(pfindData->ExtFileAttributes);
-	__u64 allocation_size = le64_to_cpu(pfindData->AllocationSize);
-	__u64 end_of_file = le64_to_cpu(pfindData->EndOfFile);
-
-	cifsInfo->cifsAttrs = attr;
-	cifsInfo->time = jiffies;
+	__u32 attr;
+	__u64 allocation_size;
+	__u64 end_of_file;
 
 	/* save mtime and size */
 	local_mtime = tmp_inode->i_mtime;
 	local_size  = tmp_inode->i_size;
 
-	/* Linux can not store file creation time unfortunately so ignore it */
+	if(new_buf_type) {
+		FILE_DIRECTORY_INFO *pfindData = (FILE_DIRECTORY_INFO *)buf;
+
+		attr = le32_to_cpu(pfindData->ExtFileAttributes);
+		allocation_size = le64_to_cpu(pfindData->AllocationSize);
+		end_of_file = le64_to_cpu(pfindData->EndOfFile);
 	tmp_inode->i_atime =
 	    cifs_NTtimeToUnix(le64_to_cpu(pfindData->LastAccessTime));
 	tmp_inode->i_mtime =
 	    cifs_NTtimeToUnix(le64_to_cpu(pfindData->LastWriteTime));
 	tmp_inode->i_ctime =
 	    cifs_NTtimeToUnix(le64_to_cpu(pfindData->ChangeTime));
+	} else { /* legacy, OS2 and DOS style */
+		FIND_FILE_STANDARD_INFO * pfindData = 
+			(FIND_FILE_STANDARD_INFO *)buf;
+
+		attr = le16_to_cpu(pfindData->Attributes);
+		allocation_size = le32_to_cpu(pfindData->AllocationSize);
+		end_of_file = le32_to_cpu(pfindData->DataSize);
+		tmp_inode->i_atime = CURRENT_TIME;
+		/* tmp_inode->i_mtime =  BB FIXME - add dos time handling
+		tmp_inode->i_ctime = 0;   BB FIXME */
+
+	}
+
+	/* Linux can not store file creation time unfortunately so ignore it */
+
+	cifsInfo->cifsAttrs = attr;
+	cifsInfo->time = jiffies;
+
 	/* treat dos attribute of read-only as read-only mode bit e.g. 555? */
 	/* 2767 perms - indicate mandatory locking */
 		/* BB fill in uid and gid here? with help from winbind? 
@@ -139,6 +164,11 @@
 		tmp_inode->i_gid = cifs_sb->mnt_gid;
 		/* set default mode. will override for dirs below */
 		tmp_inode->i_mode = cifs_sb->mnt_file_mode;
+	} else {
+		/* mask off the type bits since it gets set
+		below and we do not want to get two type
+		bits set */
+		tmp_inode->i_mode &= ~S_IFMT;
 	}
 
 	if (attr & ATTR_DIRECTORY) {
@@ -148,6 +178,19 @@
 			tmp_inode->i_mode = cifs_sb->mnt_dir_mode;
 		}
 		tmp_inode->i_mode |= S_IFDIR;
+	} else if ((cifs_sb->mnt_cifs_flags & CIFS_MOUNT_UNX_EMUL) && 
+		   (attr & ATTR_SYSTEM)) {
+		if (end_of_file == 0)  {
+			*pobject_type = DT_FIFO;
+			tmp_inode->i_mode |= S_IFIFO;
+		} else {
+			/* rather than get the type here, we mark the
+			inode as needing revalidate and get the real type
+			(blk vs chr vs. symlink) later ie in lookup */
+			*pobject_type = DT_REG;
+			tmp_inode->i_mode |= S_IFREG; 
+			cifsInfo->time = 0;	
+		}
 /* we no longer mark these because we could not follow them */
 /*        } else if (attr & ATTR_REPARSE) {
                 *pobject_type = DT_LNK;
@@ -183,15 +226,28 @@
 	if (S_ISREG(tmp_inode->i_mode)) {
 		cFYI(1, ("File inode"));
 		tmp_inode->i_op = &cifs_file_inode_ops;
-		if(cifs_sb->mnt_cifs_flags & CIFS_MOUNT_DIRECT_IO)
+		if(cifs_sb->mnt_cifs_flags & CIFS_MOUNT_DIRECT_IO) {
+			if(cifs_sb->mnt_cifs_flags & CIFS_MOUNT_NO_BRL)
+				tmp_inode->i_fop = &cifs_file_direct_nobrl_ops;
+			else
 			tmp_inode->i_fop = &cifs_file_direct_ops;
+		
+		} else if(cifs_sb->mnt_cifs_flags & CIFS_MOUNT_NO_BRL)
+			tmp_inode->i_fop = &cifs_file_nobrl_ops;
 		else
 			tmp_inode->i_fop = &cifs_file_ops;
+
+		if((cifs_sb->tcon) && (cifs_sb->tcon->ses) &&
+		   (cifs_sb->tcon->ses->server->maxBuf <
+			PAGE_CACHE_SIZE + MAX_CIFS_HDR_SIZE))
+			tmp_inode->i_data.a_ops = &cifs_addr_ops_smallbuf;
+		else
 		tmp_inode->i_data.a_ops = &cifs_addr_ops;
 
 		if(isNewInode)
-			return; /* No sense invalidating pages for new inode since we
-					   have not started caching readahead file data yet */
+			return; /* No sense invalidating pages for new inode
+				   since have not started caching readahead file
+				   data yet */
 
 		if (timespec_equal(&tmp_inode->i_mtime, &local_mtime) &&
 			(local_size == tmp_inode->i_size)) {
@@ -242,6 +298,9 @@
 	    cifs_NTtimeToUnix(le64_to_cpu(pfindData->LastStatusChange));
 
 	tmp_inode->i_mode = le64_to_cpu(pfindData->Permissions);
+	/* since we set the inode type below we need to mask off type
+           to avoid strange results if bits above were corrupt */
+        tmp_inode->i_mode &= ~S_IFMT;
 	if (type == UNIX_FILE) {
 		*pobject_type = DT_REG;
 		tmp_inode->i_mode |= S_IFREG;
@@ -267,6 +326,11 @@
 	} else if (type == UNIX_SOCKET) {
 		*pobject_type = DT_SOCK;
 		tmp_inode->i_mode |= S_IFSOCK;
+	} else {
+		/* safest to just call it a file */
+		*pobject_type = DT_REG;
+		tmp_inode->i_mode |= S_IFREG;
+		cFYI(1,("unknown inode type %d",type)); 
 	}
 
 	tmp_inode->i_uid = le64_to_cpu(pfindData->Uid);
@@ -286,10 +350,23 @@
 	if (S_ISREG(tmp_inode->i_mode)) {
 		cFYI(1, ("File inode"));
 		tmp_inode->i_op = &cifs_file_inode_ops;
-		if(cifs_sb->mnt_cifs_flags & CIFS_MOUNT_DIRECT_IO)
+
+		if(cifs_sb->mnt_cifs_flags & CIFS_MOUNT_DIRECT_IO) {
+			if(cifs_sb->mnt_cifs_flags & CIFS_MOUNT_NO_BRL)
+				tmp_inode->i_fop = &cifs_file_direct_nobrl_ops;
+			else
 			tmp_inode->i_fop = &cifs_file_direct_ops;
+		
+		} else if(cifs_sb->mnt_cifs_flags & CIFS_MOUNT_NO_BRL)
+			tmp_inode->i_fop = &cifs_file_nobrl_ops;
 		else
 			tmp_inode->i_fop = &cifs_file_ops;
+
+		if((cifs_sb->tcon) && (cifs_sb->tcon->ses) &&
+		   (cifs_sb->tcon->ses->server->maxBuf < 
+			PAGE_CACHE_SIZE + MAX_CIFS_HDR_SIZE))
+			tmp_inode->i_data.a_ops = &cifs_addr_ops_smallbuf;
+		else
 		tmp_inode->i_data.a_ops = &cifs_addr_ops;
 
 		if(isNewInode)
@@ -352,9 +429,7 @@
 	if(pTcon == NULL)
 		return -EINVAL;
 
-	down(&file->f_dentry->d_sb->s_vfs_rename_sem);
 	full_path = build_path_from_dentry(file->f_dentry);
-	up(&file->f_dentry->d_sb->s_vfs_rename_sem);
 
 	if(full_path == NULL) {
 		return -ENOMEM;
@@ -366,6 +441,9 @@
 	/* test for Unix extensions */
 	if (pTcon->ses->capabilities & CAP_UNIX) {
 		cifsFile->srch_inf.info_level = SMB_FIND_FILE_UNIX; 
+	} else if ((pTcon->ses->capabilities & 
+			(CAP_NT_SMBS | CAP_NT_FIND)) == 0) {
+		cifsFile->srch_inf.info_level = SMB_FIND_FILE_INFO_STANDARD;
 	} else if (cifs_sb->mnt_cifs_flags & CIFS_MOUNT_SERVER_INUM) {
 		cifsFile->srch_inf.info_level = SMB_FIND_FILE_ID_FULL_DIR_INFO;
 	} else /* not srvinos - BB fixme add check for backlevel? */ {
@@ -374,7 +452,8 @@
 
 	rc = CIFSFindFirst(xid, pTcon,full_path,cifs_sb->local_nls,
 		&cifsFile->netfid, &cifsFile->srch_inf,
-		cifs_sb->mnt_cifs_flags & CIFS_MOUNT_MAP_SPECIAL_CHR);
+		cifs_sb->mnt_cifs_flags & 
+			CIFS_MOUNT_MAP_SPECIAL_CHR, CIFS_DIR_SEP(cifs_sb));
 	if(rc == 0)
 		cifsFile->invalidHandle = FALSE;
 	if((rc == -EOPNOTSUPP) && 
@@ -400,11 +479,18 @@
 	return len << 1;
 }
 
-static char *nxt_dir_entry(char *old_entry, char *end_of_smb)
+static char *nxt_dir_entry(char *old_entry, char *end_of_smb, int level)
 {
 	char * new_entry;
 	FILE_DIRECTORY_INFO * pDirInfo = (FILE_DIRECTORY_INFO *)old_entry;
 
+	if(level == SMB_FIND_FILE_INFO_STANDARD) {
+		FIND_FILE_STANDARD_INFO * pfData;
+		pfData = (FIND_FILE_STANDARD_INFO *)pDirInfo;
+
+		new_entry = old_entry + sizeof(FIND_FILE_STANDARD_INFO) +
+				pfData->FileNameLength;
+	} else
 	new_entry = old_entry + le32_to_cpu(pDirInfo->NextEntryOffset);
 	cFYI(1,("new entry %p old entry %p",new_entry,old_entry));
 	/* validate that new_entry is not past end of SMB */
@@ -413,7 +499,10 @@
 		      ("search entry %p began after end of SMB %p old entry %p",
 			new_entry, end_of_smb, old_entry)); 
 		return NULL;
-	} else if (new_entry + sizeof(FILE_DIRECTORY_INFO) > end_of_smb) {
+	} else if(((level == SMB_FIND_FILE_INFO_STANDARD) &&
+		   (new_entry + sizeof(FIND_FILE_STANDARD_INFO) > end_of_smb)) ||
+		  ((level != SMB_FIND_FILE_INFO_STANDARD) &&
+		   (new_entry + sizeof(FILE_DIRECTORY_INFO) > end_of_smb)))  {
 		cERROR(1,("search entry %p extends after end of SMB %p",
 			new_entry, end_of_smb));
 		return NULL;
@@ -431,7 +520,7 @@
 	char * filename = NULL;
 	int len = 0; 
 
-	if(cfile->srch_inf.info_level == 0x202) {
+	if(cfile->srch_inf.info_level == SMB_FIND_FILE_UNIX) {
 		FILE_UNIX_INFO * pFindData = (FILE_UNIX_INFO *)current_entry;
 		filename = &pFindData->FileName[0];
 		if(cfile->srch_inf.unicode) {
@@ -440,26 +529,34 @@
 			/* BB should we make this strnlen of PATH_MAX? */
 			len = strnlen(filename, 5);
 		}
-	} else if(cfile->srch_inf.info_level == 0x101) {
+	} else if(cfile->srch_inf.info_level == SMB_FIND_FILE_DIRECTORY_INFO) {
 		FILE_DIRECTORY_INFO * pFindData = 
 			(FILE_DIRECTORY_INFO *)current_entry;
 		filename = &pFindData->FileName[0];
 		len = le32_to_cpu(pFindData->FileNameLength);
-	} else if(cfile->srch_inf.info_level == 0x102) {
+	} else if(cfile->srch_inf.info_level == 
+			SMB_FIND_FILE_FULL_DIRECTORY_INFO) {
 		FILE_FULL_DIRECTORY_INFO * pFindData = 
 			(FILE_FULL_DIRECTORY_INFO *)current_entry;
 		filename = &pFindData->FileName[0];
 		len = le32_to_cpu(pFindData->FileNameLength);
-	} else if(cfile->srch_inf.info_level == 0x105) {
+	} else if(cfile->srch_inf.info_level ==
+			SMB_FIND_FILE_ID_FULL_DIR_INFO) {
 		SEARCH_ID_FULL_DIR_INFO * pFindData = 
 			(SEARCH_ID_FULL_DIR_INFO *)current_entry;
 		filename = &pFindData->FileName[0];
 		len = le32_to_cpu(pFindData->FileNameLength);
-	} else if(cfile->srch_inf.info_level == 0x104) {
+	} else if(cfile->srch_inf.info_level == 
+			SMB_FIND_FILE_BOTH_DIRECTORY_INFO) {
 		FILE_BOTH_DIRECTORY_INFO * pFindData = 
 			(FILE_BOTH_DIRECTORY_INFO *)current_entry;
 		filename = &pFindData->FileName[0];
 		len = le32_to_cpu(pFindData->FileNameLength);
+	} else if(cfile->srch_inf.info_level == SMB_FIND_FILE_INFO_STANDARD) {
+		FIND_FILE_STANDARD_INFO * pFindData =
+			(FIND_FILE_STANDARD_INFO *)current_entry;
+		filename = &pFindData->FileName[0];
+		len = le32_to_cpu(pFindData->FileNameLength);
 	} else {
 		cFYI(1,("Unknown findfirst level %d",cfile->srch_inf.info_level));
 	}
@@ -491,6 +588,30 @@
 	return rc;
 }
 
+/* Check if directory that we are searching has changed so we can decide
+   whether we can use the cached search results from the previous search */
+static int is_dir_changed(struct file * file)
+{
+	struct inode * inode;
+	struct cifsInodeInfo *cifsInfo;
+
+	if(file->f_dentry == NULL)
+		return 0;
+
+	inode = file->f_dentry->d_inode;
+
+	if(inode == NULL)
+		return 0;
+
+	cifsInfo = CIFS_I(inode);
+
+	if(cifsInfo->time == 0)
+		return 1; /* directory was changed, perhaps due to unlink */
+	else
+		return 0;
+
+}
+
 /* find the corresponding entry in the search */
 /* Note that the SMB server returns search entries for . and .. which
    complicates logic here if we choose to parse for them and we do not
@@ -507,15 +628,27 @@
 	struct cifsFileInfo * cifsFile = file->private_data;
 	/* check if index in the buffer */
 	
-	if((cifsFile == NULL) || (ppCurrentEntry == NULL) || (num_to_ret == NULL))
+	if((cifsFile == NULL) || (ppCurrentEntry == NULL) || 
+	   (num_to_ret == NULL))
 		return -ENOENT;
 	
 	*ppCurrentEntry = NULL;
 	first_entry_in_buffer = 
 		cifsFile->srch_inf.index_of_last_entry - 
 			cifsFile->srch_inf.entries_in_buffer;
-/*	dump_cifs_file_struct(file, "In fce ");*/
-	if(index_to_find < first_entry_in_buffer) {
+
+	/* if first entry in buf is zero then is first buffer
+	in search response data which means it is likely . and ..
+	will be in this buffer, although some servers do not return
+	. and .. for the root of a drive and for those we need
+	to start two entries earlier */
+
+#ifdef CONFIG_CIFS_DEBUG2
+	dump_cifs_file_struct(file, "In fce ");
+#endif
+	if(((index_to_find < cifsFile->srch_inf.index_of_last_entry) && 
+	     is_dir_changed(file)) || 
+	   (index_to_find < first_entry_in_buffer)) {
 		/* close and restart search */
 		cFYI(1,("search backing up - close and restart search"));
 		cifsFile->invalidHandle = TRUE;
@@ -524,7 +657,12 @@
 		cifsFile->search_resume_name = NULL;
 		if(cifsFile->srch_inf.ntwrk_buf_start) {
 			cFYI(1,("freeing SMB ff cache buf on search rewind"));
-			cifs_buf_release(cifsFile->srch_inf.ntwrk_buf_start);
+			if(cifsFile->srch_inf.smallBuf)
+				cifs_small_buf_release(cifsFile->srch_inf.
+						ntwrk_buf_start);
+			else
+				cifs_buf_release(cifsFile->srch_inf.
+						ntwrk_buf_start);
 		}
 		rc = initiate_cifs_search(xid,file);
 		if(rc) {
@@ -536,7 +674,8 @@
 	while((index_to_find >= cifsFile->srch_inf.index_of_last_entry) && 
 	      (rc == 0) && (cifsFile->srch_inf.endOfSearch == FALSE)){
 	 	cFYI(1,("calling findnext2"));
-		rc = CIFSFindNext(xid,pTcon,cifsFile->netfid, &cifsFile->srch_inf);
+		rc = CIFSFindNext(xid,pTcon,cifsFile->netfid, 
+				  &cifsFile->srch_inf);
 		if(rc)
 			return -ENOENT;
 	}
@@ -548,25 +687,17 @@
 		char * end_of_smb = cifsFile->srch_inf.ntwrk_buf_start + 
 			smbCalcSize((struct smb_hdr *)
 				cifsFile->srch_inf.ntwrk_buf_start);
-/*	dump_cifs_file_struct(file,"found entry in fce "); */
+
+		current_entry = cifsFile->srch_inf.srch_entries_start;
 		first_entry_in_buffer = cifsFile->srch_inf.index_of_last_entry
 					- cifsFile->srch_inf.entries_in_buffer;
 		pos_in_buf = index_to_find - first_entry_in_buffer;
 		cFYI(1,("found entry - pos_in_buf %d",pos_in_buf)); 
-		current_entry = cifsFile->srch_inf.srch_entries_start;
+
 		for(i=0;(i<(pos_in_buf)) && (current_entry != NULL);i++) {
-			/* go entry to next entry figuring out which we need to start with */
-			/* if( . or ..)
-				skip */
-			rc = cifs_entry_is_dot(current_entry,cifsFile);
-			if(rc == 1) /* is . or .. so skip */ {
-				cFYI(1,("Entry is .")); /* BB removeme BB */
-				/* continue; */
-			} else if (rc == 2 ) {
-				cFYI(1,("Entry is ..")); /* BB removeme BB */
-				/* continue; */
-			}
-			current_entry = nxt_dir_entry(current_entry,end_of_smb);
+			/* go entry by entry figuring out which is first */
+			current_entry = nxt_dir_entry(current_entry,end_of_smb,
+						cifsFile->srch_inf.info_level);
 		}
 		if((current_entry == NULL) && (i < pos_in_buf)) {
 			/* BB fixme - check if we should flag this error */
@@ -582,11 +713,10 @@
 	}
 
 	if(pos_in_buf >= cifsFile->srch_inf.entries_in_buffer) {
-		cFYI(1,("can not return entries when pos_in_buf beyond last entry"));
+		cFYI(1,("can not return entries pos_in_buf beyond last entry"));
 		*num_to_ret = 0;
 	} else
 		*num_to_ret = cifsFile->srch_inf.entries_in_buffer - pos_in_buf;
-/*	dump_cifs_file_struct(file, "end fce ");*/
 
 	return rc;
 }
@@ -594,7 +724,7 @@
 /* inode num, inode type and filename returned */
 static int cifs_get_name_from_search_buf(struct qstr *pqst,
 	char *current_entry, __u16 level, unsigned int unicode,
-	struct cifs_sb_info * cifs_sb, ino_t *pinum)
+	struct cifs_sb_info * cifs_sb, int max_len, ino_t *pinum)
 {
 	int rc = 0;
 	unsigned int len = 0;
@@ -638,10 +768,22 @@
 			(FILE_BOTH_DIRECTORY_INFO *)current_entry;
 		filename = &pFindData->FileName[0];
 		len = le32_to_cpu(pFindData->FileNameLength);
+	} else if(level == SMB_FIND_FILE_INFO_STANDARD) {
+		FIND_FILE_STANDARD_INFO * pFindData =
+			(FIND_FILE_STANDARD_INFO *)current_entry;
+		filename = &pFindData->FileName[0];
+		/* one byte length, no name conversion */
+		len = (unsigned int)pFindData->FileNameLength;
 	} else {
 		cFYI(1,("Unknown findfirst level %d",level));
 		return -EINVAL;
 	}
+
+	if(len > max_len) {
+		cERROR(1,("bad search response length %d past smb end", len));
+		return -EINVAL;
+	}
+
 	if(unicode) {
 		/* BB fixme - test with long names */
 		/* Note converted filename can be longer than in unicode */
@@ -650,7 +792,7 @@
 					(__le16 *)filename, len/2, nlt);
 		else
 			pqst->len = cifs_strfromUCS_le((char *)pqst->name,
-					(wchar_t *)filename,len/2,nlt);
+					(__le16 *)filename,len/2,nlt);
 	} else {
 		pqst->name = filename;
 		pqst->len = len;
@@ -661,7 +803,7 @@
 }
 
 static int cifs_filldir(char *pfindEntry, struct file *file,
-	filldir_t filldir, void *direntry, char *scratch_buf)
+	filldir_t filldir, void *direntry, char *scratch_buf, int max_len)
 {
 	int rc = 0;
 	struct qstr qstring;
@@ -686,12 +828,18 @@
 	if(file->f_dentry == NULL)
 		return -ENOENT;
 
+	rc = cifs_entry_is_dot(pfindEntry,pCifsF);
+	/* skip . and .. since we added them first */
+	if(rc != 0) 
+		return 0;
+
 	cifs_sb = CIFS_SB(file->f_dentry->d_sb);
 
 	qstring.name = scratch_buf;
 	rc = cifs_get_name_from_search_buf(&qstring,pfindEntry,
 			pCifsF->srch_inf.info_level,
 			pCifsF->srch_inf.unicode,cifs_sb,
+			max_len,
 			&inum /* returned */);
 
 	if(rc)
@@ -713,15 +861,19 @@
 	/* we pass in rc below, indicating whether it is a new inode,
 	   so we can figure out whether to invalidate the inode cached
 	   data if the file has changed */
-	if(pCifsF->srch_inf.info_level == SMB_FIND_FILE_UNIX) {
+	if(pCifsF->srch_inf.info_level == SMB_FIND_FILE_UNIX)
 		unix_fill_in_inode(tmp_inode,
-				   (FILE_UNIX_INFO *)pfindEntry,&obj_type, rc);
-	} else {
-		fill_in_inode(tmp_inode,
-			      (FILE_DIRECTORY_INFO *)pfindEntry,&obj_type, rc);
-	}
+				   (FILE_UNIX_INFO *)pfindEntry,
+				   &obj_type, rc);
+	else if(pCifsF->srch_inf.info_level == SMB_FIND_FILE_INFO_STANDARD)
+		fill_in_inode(tmp_inode, 0 /* old level 1 buffer type */,
+				pfindEntry, &obj_type, rc);
+	else
+		fill_in_inode(tmp_inode, 1 /* NT */, pfindEntry, &obj_type, rc);
+	
 	
-	rc = filldir(direntry,qstring.name,qstring.len,file->f_pos,tmp_inode->i_ino,obj_type);
+	rc = filldir(direntry,qstring.name,qstring.len,file->f_pos,
+		     tmp_inode->i_ino,obj_type);
 	if(rc) {
 		cFYI(1,("filldir rc = %d",rc));
 	}
@@ -778,6 +930,12 @@
 		filename = &pFindData->FileName[0];
 		len = le32_to_cpu(pFindData->FileNameLength);
 		cifsFile->srch_inf.resume_key = pFindData->FileIndex;
+	} else if(level == SMB_FIND_FILE_INFO_STANDARD) {
+		FIND_FILE_STANDARD_INFO * pFindData =
+			(FIND_FILE_STANDARD_INFO *)current_entry;
+		filename = &pFindData->FileName[0];
+		/* one byte length, no name conversion */
+		len = (unsigned int)pFindData->FileNameLength;
 	} else {
 		cFYI(1,("Unknown findfirst level %d",level));
 		return -EINVAL;
@@ -798,6 +956,7 @@
 	int num_to_fill = 0;
 	char * tmp_buf = NULL;
 	char * end_of_smb;
+	int max_len;
 
 	xid = GetXid();
 
@@ -805,33 +964,30 @@
 		FreeXid(xid);
 		return -EIO;
 	}
-/*	dump_cifs_file_struct(file, "Begin rdir "); */
 
 	cifs_sb = CIFS_SB(file->f_dentry->d_sb);
 	pTcon = cifs_sb->tcon;
 	if(pTcon == NULL)
 		return -EINVAL;
 
-/*	cFYI(1,("readdir2 pos: %lld",file->f_pos)); */
-
 	switch ((int) file->f_pos) {
 	case 0:
-		/*if (filldir(direntry, ".", 1, file->f_pos,
+		if (filldir(direntry, ".", 1, file->f_pos,
 		     file->f_dentry->d_inode->i_ino, DT_DIR) < 0) {
-			cERROR(1, ("Filldir for current dir failed "));
+			cERROR(1, ("Filldir for current dir failed"));
 			rc = -ENOMEM;
 			break;
 		}
-		file->f_pos++; */
+		file->f_pos++;
 	case 1:
-		/* if (filldir(direntry, "..", 2, file->f_pos,
+		if (filldir(direntry, "..", 2, file->f_pos,
 		     file->f_dentry->d_parent->d_inode->i_ino, DT_DIR) < 0) {
-			cERROR(1, ("Filldir for parent dir failed "));
+			cERROR(1, ("Filldir for parent dir failed"));
 			rc = -ENOMEM;
 			break;
 		}
-		file->f_pos++; */
-	case 2:
+		file->f_pos++;
+	default:
 		/* 1) If search is active, 
 			is in current search buffer? 
 			if it before then restart search
@@ -845,7 +1001,6 @@
 				return rc;
 			}
 		}
-	default:
 		if(file->private_data == NULL) {
 			rc = -EINVAL;
 			FreeXid(xid);
@@ -865,9 +1020,6 @@
 		kfree(cifsFile->search_resume_name);
 		cifsFile->search_resume_name = NULL; */
 
-		/* BB account for . and .. in f_pos as special case */
-		/* dump_cifs_file_struct(file, "rdir after default ");*/
-
 		rc = find_cifs_entry(xid,pTcon, file,
 				&current_entry,&num_to_fill);
 		if(rc) {
@@ -881,9 +1033,10 @@
 		}
 		cFYI(1,("loop through %d times filling dir for net buf %p",
 			num_to_fill,cifsFile->srch_inf.ntwrk_buf_start)); 
-		end_of_smb = cifsFile->srch_inf.ntwrk_buf_start +
-			smbCalcSize((struct smb_hdr *)
+		max_len = smbCalcSize((struct smb_hdr *)
 				    cifsFile->srch_inf.ntwrk_buf_start);
+		end_of_smb = cifsFile->srch_inf.ntwrk_buf_start + max_len;
+
 		/* To be safe - for UCS to UTF-8 with strings loaded
 		with the rare long characters alloc more to account for
 		such multibyte target UTF-8 characters. cifs_unicode.c,
@@ -896,24 +1049,27 @@
 					  num_to_fill, i));
 				break;
 			}
-
+			/* if buggy server returns . and .. late do
+			we want to check for that here? */
 			rc = cifs_filldir(current_entry, file, 
-					filldir, direntry,tmp_buf);
+					filldir, direntry, tmp_buf, max_len);
 			file->f_pos++;
-			if(file->f_pos == cifsFile->srch_inf.index_of_last_entry) {
+			if(file->f_pos == 
+				cifsFile->srch_inf.index_of_last_entry) {
 				cFYI(1,("last entry in buf at pos %lld %s",
-					file->f_pos,tmp_buf)); /* BB removeme BB */
+					file->f_pos,tmp_buf));
 				cifs_save_resume_key(current_entry,cifsFile);
 				break;
 			} else 
-				current_entry = nxt_dir_entry(current_entry,end_of_smb);
+				current_entry = 
+					nxt_dir_entry(current_entry, end_of_smb,
+						cifsFile->srch_inf.info_level);
 		}
 		kfree(tmp_buf);
 		break;
 	} /* end switch */
 
 rddir2_exit:
-	/* dump_cifs_file_struct(file, "end rdir ");  */
 	FreeXid(xid);
 	return rc;
 }
--- linux-2.6.13/fs/cifs/README
+++ linux-2.6.13/fs/cifs/README
@@ -278,7 +278,9 @@
 		(such as Windows), permissions can also be checked at the
 		client, and a crude form of client side permission checking 
 		can be enabled by specifying file_mode and dir_mode on 
-		the client
+		the client.  Note that the mount.cifs helper must be
+		at version 1.10 or higher to support specifying the uid
+		(or gid) in non-numberic form.
   gid		If CIFS Unix extensions are not supported by the server
 		this overrides the default gid for inodes.
   file_mode     If CIFS Unix extensions are not supported by the server
@@ -294,8 +296,10 @@
 		during the local client kernel build will be used.
 		If server does not support Unicode, this parameter is
 		unused.
-  rsize		default read size
-  wsize		default write size
+  rsize		default read size (usually 16K)
+  wsize		default write size (usually 16K, 32K is often better over GigE)
+		maximum wsize currently allowed by CIFS is 57344 (14 4096 byte
+		pages)
   rw		mount the network share read-write (note that the
 		server may still consider the share read-only)
   ro		mount network share read-only
@@ -343,7 +347,10 @@
 		client system. It is typically only needed when the server
 		supports the CIFS Unix Extensions but the UIDs/GIDs on the
 		client and server system do not match closely enough to allow
-		access by the user doing the mount.
+		access by the user doing the mount, but it may be useful with
+		non CIFS Unix Extension mounts for cases in which the default
+		mode is specified on the mount but is not to be enforced on the
+		client (e.g. perhaps when MultiUserMount is enabled)
 		Note that this does not affect the normal ACL check on the
 		target machine done by the server software (of the server
 		ACL against the user name provided at mount time).
@@ -366,15 +373,21 @@
   setuids       If the CIFS Unix extensions are negotiated with the server
 		the client will attempt to set the effective uid and gid of
 		the local process on newly created files, directories, and
-		devices (create, mkdir, mknod).
+		devices (create, mkdir, mknod).  If the CIFS Unix Extensions
+		are not negotiated, for newly created files and directories
+		instead of using the default uid and gid specified on the
+		the mount, cache the new file's uid and gid locally which means
+		that the uid for the file can change when the inode is
+	        reloaded (or the user remounts the share).
   nosetuids     The client will not attempt to set the uid and gid on
 		on newly created files, directories, and devices (create, 
 		mkdir, mknod) which will result in the server setting the
 		uid and gid to the default (usually the server uid of the
 		user who mounted the share).  Letting the server (rather than
-		the client) set the uid and gid is the default. This
-		parameter has no effect if the CIFS Unix Extensions are not
-		negotiated.
+		the client) set the uid and gid is the default. If the CIFS
+		Unix Extensions are not negotiated then the uid and gid for
+		new files will appear to be the uid (gid) of the mounter or the
+		uid (gid) parameter specified on the mount.
   netbiosname   When mounting to servers via port 139, specifies the RFC1001
 		source name to use to represent the client netbios machine 
 		name when doing the RFC1001 netbios session initialize.
@@ -407,8 +420,44 @@
 		This has no effect if the server does not support
 		Unicode on the wire.
  nomapchars     Do not translate any of these seven characters (default).
+ nocase         Request case insensitive path name matching (case
+		sensitive is the default if the server suports it).
+ posixpaths     If CIFS Unix extensions are supported, attempt to
+		negotiate posix path name support which allows certain
+		characters forbidden in typical CIFS filenames, without
+		requiring remapping. (default)
+ noposixpaths   If CIFS Unix extensions are supported, do not request
+		posix path name support (this may cause servers to
+		reject creatingfile with certain reserved characters).
+ nobrl          Do not send byte range lock requests to the server.
+		This is necessary for certain applications that break
+		with cifs style mandatory byte range locks (and most
+		cifs servers do not yet support requesting advisory
+		byte range locks).
  remount        remount the share (often used to change from ro to rw mounts
 	        or vice versa)
+ sfu            When the CIFS Unix Extensions are not negotiated, attempt to
+		create device files and fifos in a format compatible with
+		Services for Unix (SFU).  In addition retrieve bits 10-12
+		of the mode via the SETFILEBITS extended attribute (as
+		SFU does).  In the future the bottom 9 bits of the mode
+		mode also will be emulated using queries of the security
+		descriptor (ACL).
+ sign           Must use packet signing (helps avoid unwanted data modification
+		by intermediate systems in the route).  Note that signing
+		does not work with lanman or plaintext authentication.
+ sec            Security mode.  Allowed values are:
+			none	attempt to connection as a null user (no name)
+			krb5    Use Kerberos version 5 authentication
+			krb5i   Use Kerberos authentication and packet signing
+			ntlm    Use NTLM password hashing (default)
+			ntlmi   Use NTLM password hashing with signing (if
+				/proc/fs/cifs/PacketSigningEnabled on or if
+				server requires signing also can be the default) 
+			ntlmv2  Use NTLMv2 password hashing      
+			ntlmv2i Use NTLMv2 password hashing with packet signing
+			lanman  (if configured in kernel config) use older
+				lanman hash
 		
 The mount.cifs mount helper also accepts a few mount options before -o
 including:
@@ -441,14 +490,34 @@
 			it.  If set to two, cifs packet signing is
 			required even if the server considers packet
 			signing optional. (default 1)
+SecurityFlags		Flags which control security negotiation and
+			also packet signing. Authentication (may/must)
+			flags (e.g. for NTLM and/or NTLMv2) may be combined with
+			the signing flags.  Specifying two different password
+			hashing mechanisms (as "must use") on the other hand 
+			does not make much sense. Default flags are 
+				0x07007 
+			(NTLM, NTLMv2 and packet signing allowed).  Maximum 
+			allowable flags if you want to allow mounts to servers
+			using weaker password hashes is 0x37037 (lanman,
+			plaintext, ntlm, ntlmv2, signing allowed):
+ 
+			may use packet signing 				0x00001
+			must use packet signing				0x01001
+			may use NTLM (most common password hash)	0x00002
+			must use NTLM					0x02002
+			may use NTLMv2					0x00004
+			must use NTLMv2					0x04004
+			may use Kerberos security (not implemented yet) 0x00008
+			must use Kerberos (not implemented yet)         0x08008
+			may use lanman (weak) password hash  		0x00010
+			must use lanman password hash			0x10010
+			may use plaintext passwords    			0x00020
+			must use plaintext passwords			0x20020
+			(reserved for future packet encryption)		0x00040
+
 cifsFYI			If set to one, additional debug information is
 			logged to the system error log. (default 0)
-ExtendedSecurity	If set to one, SPNEGO session establishment
-			is allowed which enables more advanced 
-			secure CIFS session establishment (default 0)
-NTLMV2Enabled		If set to one, more secure password hashes
-			are used when the server supports them and
-			when kerberos is not negotiated (default 0)
 traceSMB		If set to one, debug information is logged to the
 			system error log with the start of smb requests
 			and responses (default 0)
@@ -467,15 +536,30 @@
 			support and want to map the uid and gid fields 
 			to values supplied at mount (rather than the 
 			actual values, then set this to zero. (default 1)
+Experimental            When set to 1 used to enable certain experimental
+			features (currently enables multipage writes
+			when signing is enabled, the multipage write
+			performance enhancement was disabled when
+			signing turned on in case buffer was modified
+			just before it was sent, also this flag will
+			be used to use the new experimental sessionsetup
+			code).
 
 These experimental features and tracing can be enabled by changing flags in 
 /proc/fs/cifs (after the cifs module has been installed or built into the 
 kernel, e.g.  insmod cifs).  To enable a feature set it to 1 e.g.  to enable 
 tracing to the kernel message log type: 
 
-	echo 1 > /proc/fs/cifs/cifsFYI
+	echo 7 > /proc/fs/cifs/cifsFYI
 	
-and for more extensive tracing including the start of smb requests and responses
+cifsFYI functions as a bit mask. Setting it to 1 enables additional kernel
+logging of various informational messages.  2 enables logging of non-zero
+SMB return codes while 4 enables logging of requests that take longer
+than one second to complete (except for byte range lock requests). 
+Setting it to 4 requires defining CONFIG_CIFS_STATS2 manually in the
+source code (typically by setting it in the beginning of cifsglob.h),
+and setting it to seven enables all three.  Finally, tracing
+the start of smb requests and responses can be enabled via:
 
 	echo 1 > /proc/fs/cifs/traceSMB
 
--- linux-2.6.13/fs/cifs/rfc1002pdu.h
+++ linux-2.6.13/fs/cifs/rfc1002pdu.h
@@ -21,16 +21,14 @@
  *   Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA 
  */
 
-#pragma pack(1)
-
 /* NB: unlike smb/cifs packets, the RFC1002 structures are big endian */
 
 	/* RFC 1002 session packet types */
-#define RFC1002_SESSION_MESASAGE 0x00
+#define RFC1002_SESSION_MESSAGE 0x00
 #define RFC1002_SESSION_REQUEST  0x81
 #define RFC1002_POSITIVE_SESSION_RESPONSE 0x82
 #define RFC1002_NEGATIVE_SESSION_RESPONSE 0x83
-#define RFC1002_RETARGET_SESSION_RESPONSE 0x83
+#define RFC1002_RETARGET_SESSION_RESPONSE 0x84
 #define RFC1002_SESSION_KEEP_ALIVE 0x85
 
 	/* RFC 1002 flags (only one defined */
@@ -48,17 +46,17 @@
 			__u8 calling_len;
 			__u8 calling_name[32];
 			__u8 scope2; /* null */
-		} session_req;
+		} __attribute__((packed)) session_req;
 		struct {
 			__u32 retarget_ip_addr;
 			__u16 port;
-		} retarget_resp;
+		} __attribute__((packed)) retarget_resp;
 		__u8 neg_ses_resp_error_code;
 		/* POSITIVE_SESSION_RESPONSE packet does not include trailer.
 		SESSION_KEEP_ALIVE packet also does not include a trailer.
 		Trailer for the SESSION_MESSAGE packet is SMB/CIFS header */
-	} trailer;
-};
+	} __attribute__((packed)) trailer;
+} __attribute__((packed));
 
 /* Negative Session Response error codes */
 #define RFC1002_NOT_LISTENING_CALLED  0x80 /* not listening on called name */
@@ -74,6 +72,3 @@
 (tcp name) or ip address or an /etc/hosts equivalent mapping to ip address.*/
 
 #define DEFAULT_CIFS_CALLED_NAME  "*SMBSERVER      "
-
-#pragma pack()		/* resume default structure packing */
-                                                             
--- linux-2.6.13/fs/cifs/sess.c
+++ linux-2.6.13/fs/cifs/sess.c
@@ -0,0 +1,538 @@
+/*
+ *   fs/cifs/sess.c
+ *
+ *   SMB/CIFS session setup handling routines
+ *
+ *   Copyright (c) International Business Machines  Corp., 2006
+ *   Author(s): Steve French (sfrench@us.ibm.com)
+ *
+ *   This library is free software; you can redistribute it and/or modify
+ *   it under the terms of the GNU Lesser General Public License as published
+ *   by the Free Software Foundation; either version 2.1 of the License, or
+ *   (at your option) any later version.
+ *
+ *   This library is distributed in the hope that it will be useful,
+ *   but WITHOUT ANY WARRANTY; without even the implied warranty of
+ *   MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See
+ *   the GNU Lesser General Public License for more details.
+ *
+ *   You should have received a copy of the GNU Lesser General Public License
+ *   along with this library; if not, write to the Free Software
+ *   Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
+ */
+
+#include "cifspdu.h"
+#include "cifsglob.h"
+#include "cifsproto.h"
+#include "cifs_unicode.h"
+#include "cifs_debug.h"
+#include "ntlmssp.h"
+#include "nterr.h"
+#include <linux/utsname.h>
+
+extern void SMBNTencrypt(unsigned char *passwd, unsigned char *c8,
+                         unsigned char *p24);
+
+static __u32 cifs_ssetup_hdr(struct cifsSesInfo *ses, SESSION_SETUP_ANDX *pSMB)
+{
+	__u32 capabilities = 0;
+
+	/* init fields common to all four types of SessSetup */
+	/* note that header is initialized to zero in header_assemble */
+	pSMB->req.AndXCommand = 0xFF;
+	pSMB->req.MaxBufferSize = cpu_to_le16(ses->server->maxBuf);
+	pSMB->req.MaxMpxCount = cpu_to_le16(ses->server->maxReq);
+
+	/* Now no need to set SMBFLG_CASELESS or obsolete CANONICAL PATH */
+
+	/* BB verify whether signing required on neg or just on auth frame 
+	   (and NTLM case) */
+
+	capabilities = CAP_LARGE_FILES | CAP_NT_SMBS | CAP_LEVEL_II_OPLOCKS |
+			CAP_LARGE_WRITE_X | CAP_LARGE_READ_X;
+
+	if(ses->server->secMode & (SECMODE_SIGN_REQUIRED | SECMODE_SIGN_ENABLED))
+		pSMB->req.hdr.Flags2 |= SMBFLG2_SECURITY_SIGNATURE;
+
+	if (ses->capabilities & CAP_UNICODE) {
+		pSMB->req.hdr.Flags2 |= SMBFLG2_UNICODE;
+		capabilities |= CAP_UNICODE;
+	}
+	if (ses->capabilities & CAP_STATUS32) {
+		pSMB->req.hdr.Flags2 |= SMBFLG2_ERR_STATUS;
+		capabilities |= CAP_STATUS32;
+	}
+	if (ses->capabilities & CAP_DFS) {
+		pSMB->req.hdr.Flags2 |= SMBFLG2_DFS;
+		capabilities |= CAP_DFS;
+	}
+	if (ses->capabilities & CAP_UNIX) {
+		capabilities |= CAP_UNIX;
+	}
+
+	/* BB check whether to init vcnum BB */
+	return capabilities;
+}
+
+static void unicode_ssetup_strings(char ** pbcc_area, struct cifsSesInfo *ses,
+			    const struct nls_table * nls_cp)
+{
+	char * bcc_ptr = *pbcc_area;
+	int bytes_ret = 0;
+
+	/* BB FIXME add check that strings total less
+	than 335 or will need to send them as arrays */
+
+	/* unicode strings, must be word aligned before the call */
+/*	if ((long) bcc_ptr % 2)	{
+		*bcc_ptr = 0;
+		bcc_ptr++;
+	} */
+	/* copy user */
+	if(ses->userName == NULL) {
+		/* BB what about null user mounts - check that we do this BB */
+	} else { /* 300 should be long enough for any conceivable user name */
+		bytes_ret = cifs_strtoUCS((__le16 *) bcc_ptr, ses->userName,
+					  300, nls_cp);
+	}
+	bcc_ptr += 2 * bytes_ret;
+	bcc_ptr += 2; /* account for null termination */
+	/* copy domain */
+	if(ses->domainName == NULL)
+		bytes_ret = cifs_strtoUCS((__le16 *) bcc_ptr,
+					  "CIFS_LINUX_DOM", 32, nls_cp);
+	else
+		bytes_ret = cifs_strtoUCS((__le16 *) bcc_ptr, ses->domainName, 
+					  256, nls_cp);
+	bcc_ptr += 2 * bytes_ret;
+	bcc_ptr += 2;  /* account for null terminator */
+
+	/* Copy OS version */
+	bytes_ret = cifs_strtoUCS((__le16 *)bcc_ptr, "Linux version ", 32,
+				  nls_cp);
+	bcc_ptr += 2 * bytes_ret;
+	bytes_ret = cifs_strtoUCS((__le16 *) bcc_ptr, system_utsname.release,
+				  32, nls_cp);
+	bcc_ptr += 2 * bytes_ret;
+	bcc_ptr += 2; /* trailing null */
+
+	bytes_ret = cifs_strtoUCS((__le16 *) bcc_ptr, CIFS_NETWORK_OPSYS,
+                                  32, nls_cp);
+	bcc_ptr += 2 * bytes_ret;
+	bcc_ptr += 2; /* trailing null */
+
+	*pbcc_area = bcc_ptr;
+}
+
+static void ascii_ssetup_strings(char ** pbcc_area, struct cifsSesInfo *ses,
+			  const struct nls_table * nls_cp)
+{
+	char * bcc_ptr = *pbcc_area;
+
+	/* copy user */
+	/* BB what about null user mounts - check that we do this BB */
+        /* copy user */
+        if(ses->userName == NULL) {
+                /* BB what about null user mounts - check that we do this BB */
+        } else { /* 300 should be long enough for any conceivable user name */
+                strncpy(bcc_ptr, ses->userName, 300);
+        }
+	/* BB improve check for overflow */
+        bcc_ptr += strnlen(ses->userName, 300);
+	*bcc_ptr = 0;
+        bcc_ptr++; /* account for null termination */
+
+        /* copy domain */
+	
+        if(ses->domainName == NULL) {
+                strcpy(bcc_ptr, "CIFS_LINUX_DOM");
+		bcc_ptr += 14;  /* strlen(CIFS_LINUX_DOM) */
+ 	} else {
+                strncpy(bcc_ptr, ses->domainName, 256); 
+		bcc_ptr += strnlen(ses->domainName, 256);
+	}
+	*bcc_ptr = 0;
+	bcc_ptr++;
+
+	/* BB check for overflow here */
+
+	strcpy(bcc_ptr, "Linux version ");
+	bcc_ptr += strlen("Linux version ");
+	strcpy(bcc_ptr, system_utsname.release);
+	bcc_ptr += strlen(system_utsname.release) + 1;
+
+	strcpy(bcc_ptr, CIFS_NETWORK_OPSYS);
+	bcc_ptr += strlen(CIFS_NETWORK_OPSYS) + 1;
+
+        *pbcc_area = bcc_ptr;
+}
+
+static int decode_unicode_ssetup(char ** pbcc_area, int bleft, struct cifsSesInfo *ses,
+                            const struct nls_table * nls_cp)
+{
+	int rc = 0;
+	int words_left, len;
+	char * data = *pbcc_area;
+
+
+
+	cFYI(1,("bleft %d",bleft));
+
+
+	/* word align, if bytes remaining is not even */
+	if(bleft % 2) {
+		bleft--;
+		data++;
+	}
+	words_left = bleft / 2;
+
+	/* save off server operating system */
+	len = UniStrnlen((wchar_t *) data, words_left);
+
+/* 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(len >= words_left)
+		return rc;
+
+	if(ses->serverOS)
+		kfree(ses->serverOS);
+	/* UTF-8 string will not grow more than four times as big as UCS-16 */
+	ses->serverOS = kzalloc(4 * len, GFP_KERNEL);
+	if(ses->serverOS != NULL) {
+		cifs_strfromUCS_le(ses->serverOS, (__le16 *)data, len,
+				   nls_cp);
+	}
+	data += 2 * (len + 1);
+	words_left -= len + 1;
+
+	/* save off server network operating system */
+	len = UniStrnlen((wchar_t *) data, words_left);
+
+	if(len >= words_left)
+		return rc;
+
+	if(ses->serverNOS)
+		kfree(ses->serverNOS);
+	ses->serverNOS = kzalloc(4 * len, GFP_KERNEL); /* BB this is wrong length FIXME BB */
+	if(ses->serverNOS != NULL) {
+		cifs_strfromUCS_le(ses->serverNOS, (__le16 *)data, len,
+				   nls_cp);
+		if(strncmp(ses->serverNOS, "NT LAN Manager 4",16) == 0) {
+			cFYI(1,("NT4 server"));
+			ses->flags |= CIFS_SES_NT4;
+		}
+	}
+	data += 2 * (len + 1);
+	words_left -= len + 1;
+
+        /* save off server domain */
+        len = UniStrnlen((wchar_t *) data, words_left);
+
+        if(len > words_left)
+                return rc;
+
+        if(ses->serverDomain)
+                kfree(ses->serverDomain);
+        ses->serverDomain = kzalloc(2 * (len + 1), GFP_KERNEL); /* BB FIXME wrong length */
+        if(ses->serverDomain != NULL) {
+                cifs_strfromUCS_le(ses->serverDomain, (__le16 *)data, len,
+                                   nls_cp);
+                ses->serverDomain[2*len] = 0;
+                ses->serverDomain[(2*len) + 1] = 0;
+        }
+        data += 2 * (len + 1);
+        words_left -= len + 1;
+	
+	cFYI(1,("words left: %d",words_left));
+
+	return rc;
+}
+
+static int decode_ascii_ssetup(char ** pbcc_area, int bleft, struct cifsSesInfo *ses,
+                            const struct nls_table * nls_cp)
+{
+	int rc = 0;
+	int len;
+	char * bcc_ptr = *pbcc_area;
+
+	cFYI(1,("decode sessetup ascii. bleft %d", bleft));
+	
+	len = strnlen(bcc_ptr, bleft);
+	if(len >= bleft)
+		return rc;
+	
+	if(ses->serverOS)
+		kfree(ses->serverOS);
+
+	ses->serverOS = kzalloc(len + 1, GFP_KERNEL);
+	if(ses->serverOS)
+		strncpy(ses->serverOS, bcc_ptr, len);
+
+	bcc_ptr += len + 1;
+	bleft -= len + 1;
+
+	len = strnlen(bcc_ptr, bleft);
+	if(len >= bleft)
+		return rc;
+
+	if(ses->serverNOS)
+		kfree(ses->serverNOS);
+
+	ses->serverNOS = kzalloc(len + 1, GFP_KERNEL);
+	if(ses->serverNOS)
+		strncpy(ses->serverNOS, bcc_ptr, len);
+
+	bcc_ptr += len + 1;
+	bleft -= len + 1;
+
+        len = strnlen(bcc_ptr, bleft);
+        if(len > bleft)
+                return rc;
+
+        if(ses->serverDomain)
+                kfree(ses->serverDomain);
+
+        ses->serverDomain = kzalloc(len + 1, GFP_KERNEL);
+        if(ses->serverOS)
+                strncpy(ses->serverOS, bcc_ptr, len);
+
+        bcc_ptr += len + 1;
+	bleft -= len + 1;
+
+	cFYI(1,("ascii: bytes left %d",bleft));
+
+	return rc;
+}
+
+int 
+CIFS_SessSetup(unsigned int xid, struct cifsSesInfo *ses, int first_time,
+		const struct nls_table *nls_cp)
+{
+	int rc = 0;
+	int wct;
+	struct smb_hdr *smb_buf;
+	char *bcc_ptr;
+	char *str_area;
+	SESSION_SETUP_ANDX *pSMB;
+	__u32 capabilities;
+	int count;
+	int resp_buf_type = 0;
+	struct kvec iov[2];
+	enum securityEnum type;
+	__u16 action;
+	int bytes_remaining;
+
+	if(ses == NULL)
+		return -EINVAL;
+
+	type = ses->server->secType;
+
+	cFYI(1,("sess setup type %d",type));
+	if(type == LANMAN) {
+#ifndef CONFIG_CIFS_WEAK_PW_HASH
+		/* LANMAN and plaintext are less secure and off by default.
+		So we make this explicitly be turned on in kconfig (in the
+		build) and turned on at runtime (changed from the default)
+		in proc/fs/cifs or via mount parm.  Unfortunately this is
+		needed for old Win (e.g. Win95), some obscure NAS and OS/2 */
+		return -EOPNOTSUPP;
+#endif
+		wct = 10; /* lanman 2 style sessionsetup */
+	} else if((type == NTLM) || (type == NTLMv2)) { 
+		/* For NTLMv2 failures eventually may need to retry NTLM */
+		wct = 13; /* old style NTLM sessionsetup */
+	} else /* same size for negotiate or auth, NTLMSSP or extended security */
+		wct = 12;
+
+	rc = small_smb_init_no_tc(SMB_COM_SESSION_SETUP_ANDX, wct, ses,
+			    (void **)&smb_buf);
+	if(rc)
+		return rc;
+
+	pSMB = (SESSION_SETUP_ANDX *)smb_buf;
+
+	capabilities = cifs_ssetup_hdr(ses, pSMB);
+
+	/* we will send the SMB in two pieces,
+	a fixed length beginning part, and a
+	second part which will include the strings
+	and rest of bcc area, in order to avoid having
+	to do a large buffer 17K allocation */
+        iov[0].iov_base = (char *)pSMB;
+        iov[0].iov_len = smb_buf->smb_buf_length + 4;
+
+	/* 2000 big enough to fit max user, domain, NOS name etc. */
+	str_area = kmalloc(2000, GFP_KERNEL);
+	bcc_ptr = str_area;
+
+	if(type == LANMAN) {
+#ifdef CONFIG_CIFS_WEAK_PW_HASH
+		char lnm_session_key[CIFS_SESS_KEY_SIZE];
+
+		/* no capabilities flags in old lanman negotiation */
+
+		pSMB->old_req.PasswordLength = CIFS_SESS_KEY_SIZE; 
+		/* BB calculate hash with password */
+		/* and copy into bcc */
+
+		calc_lanman_hash(ses, lnm_session_key);
+
+/* #ifdef CONFIG_CIFS_DEBUG2
+		cifs_dump_mem("cryptkey: ",ses->server->cryptKey,
+			CIFS_SESS_KEY_SIZE);
+#endif */
+		memcpy(bcc_ptr, (char *)lnm_session_key, CIFS_SESS_KEY_SIZE);
+		bcc_ptr += CIFS_SESS_KEY_SIZE;
+
+		/* can not sign if LANMAN negotiated so no need
+		to calculate signing key? but what if server
+		changed to do higher than lanman dialect and
+		we reconnected would we ever calc signing_key? */
+
+		cFYI(1,("Negotiating LANMAN setting up strings"));
+		/* Unicode not allowed for LANMAN dialects */
+		ascii_ssetup_strings(&bcc_ptr, ses, nls_cp);
+#endif    
+	} else if (type == NTLM) {
+		char ntlm_session_key[CIFS_SESS_KEY_SIZE];
+
+		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_SESS_KEY_SIZE);
+	
+		/* calculate session key */
+		SMBNTencrypt(ses->password, ses->server->cryptKey,
+			     ntlm_session_key);
+
+		if(first_time) /* should this be moved into common code 
+				  with similar ntlmv2 path? */
+			cifs_calculate_mac_key(ses->server->mac_signing_key,
+				ntlm_session_key, ses->password);
+		/* copy session key */
+
+		memcpy(bcc_ptr, (char *)ntlm_session_key,CIFS_SESS_KEY_SIZE);
+		bcc_ptr += CIFS_SESS_KEY_SIZE;
+		memcpy(bcc_ptr, (char *)ntlm_session_key,CIFS_SESS_KEY_SIZE);
+		bcc_ptr += CIFS_SESS_KEY_SIZE;
+		if(ses->capabilities & CAP_UNICODE) {
+			/* unicode strings must be word aligned */
+			if (iov[0].iov_len % 2) {
+				*bcc_ptr = 0;
+				bcc_ptr++;		
+			}	
+			unicode_ssetup_strings(&bcc_ptr, ses, nls_cp);
+		} else
+			ascii_ssetup_strings(&bcc_ptr, ses, nls_cp);
+	} else if (type == NTLMv2) {
+		char * v2_sess_key = 
+			kmalloc(sizeof(struct ntlmv2_resp), GFP_KERNEL);
+
+		/* BB FIXME change all users of v2_sess_key to
+		   struct ntlmv2_resp */
+
+		if(v2_sess_key == NULL) {
+			cifs_small_buf_release(smb_buf);
+			return -ENOMEM;
+		}
+
+		pSMB->req_no_secext.Capabilities = cpu_to_le32(capabilities);
+
+		/* LM2 password would be here if we supported it */
+		pSMB->req_no_secext.CaseInsensitivePasswordLength = 0;
+		/*	cpu_to_le16(LM2_SESS_KEY_SIZE); */
+
+		pSMB->req_no_secext.CaseSensitivePasswordLength =
+			cpu_to_le16(sizeof(struct ntlmv2_resp));
+
+		/* calculate session key */
+		setup_ntlmv2_rsp(ses, v2_sess_key, nls_cp);
+		if(first_time) /* should this be moved into common code
+			          with similar ntlmv2 path? */
+		/*   cifs_calculate_ntlmv2_mac_key(ses->server->mac_signing_key,
+				response BB FIXME, v2_sess_key); */
+
+		/* copy session key */
+
+	/*	memcpy(bcc_ptr, (char *)ntlm_session_key,LM2_SESS_KEY_SIZE);
+		bcc_ptr += LM2_SESS_KEY_SIZE; */
+		memcpy(bcc_ptr, (char *)v2_sess_key, sizeof(struct ntlmv2_resp));
+		bcc_ptr += sizeof(struct ntlmv2_resp);
+		kfree(v2_sess_key);
+		if(ses->capabilities & CAP_UNICODE) {
+			if(iov[0].iov_len % 2) {
+				*bcc_ptr = 0;
+			}	bcc_ptr++;
+			unicode_ssetup_strings(&bcc_ptr, ses, nls_cp);
+		} else
+			ascii_ssetup_strings(&bcc_ptr, ses, nls_cp);
+	} else /* NTLMSSP or SPNEGO */ {
+		pSMB->req.hdr.Flags2 |= SMBFLG2_EXT_SEC;
+		capabilities |= CAP_EXTENDED_SECURITY;
+		pSMB->req.Capabilities = cpu_to_le32(capabilities);
+		/* BB set password lengths */
+	}
+
+	count = (long) bcc_ptr - (long) str_area;
+	smb_buf->smb_buf_length += count;
+
+	BCC_LE(smb_buf) = cpu_to_le16(count);
+
+	iov[1].iov_base = str_area;
+	iov[1].iov_len = count; 
+	rc = SendReceive2(xid, ses, iov, 2 /* num_iovecs */, &resp_buf_type, 0);
+	/* SMB request buf freed in SendReceive2 */
+
+	cFYI(1,("ssetup rc from sendrecv2 is %d",rc));
+	if(rc)
+		goto ssetup_exit;
+
+	pSMB = (SESSION_SETUP_ANDX *)iov[0].iov_base;
+	smb_buf = (struct smb_hdr *)iov[0].iov_base;
+
+	if((smb_buf->WordCount != 3) && (smb_buf->WordCount != 4)) {
+		rc = -EIO;
+		cERROR(1,("bad word count %d", smb_buf->WordCount));
+		goto ssetup_exit;
+	}
+	action = le16_to_cpu(pSMB->resp.Action);
+	if (action & GUEST_LOGIN)
+		cFYI(1, ("Guest login")); /* BB mark SesInfo struct? */
+	ses->Suid = smb_buf->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 */
+	/* and lanman response is 3 */
+	bytes_remaining = BCC(smb_buf);
+	bcc_ptr = pByteArea(smb_buf);
+
+	if(smb_buf->WordCount == 4) {
+		__u16 blob_len;
+		blob_len = le16_to_cpu(pSMB->resp.SecurityBlobLength);
+		bcc_ptr += blob_len;
+		if(blob_len > bytes_remaining) {
+			cERROR(1,("bad security blob length %d", blob_len));
+			rc = -EINVAL;
+			goto ssetup_exit;
+		}
+		bytes_remaining -= blob_len;
+	}	
+
+	/* BB check if Unicode and decode strings */
+	if(smb_buf->Flags2 & SMBFLG2_UNICODE)
+		rc = decode_unicode_ssetup(&bcc_ptr, bytes_remaining,
+						   ses, nls_cp);
+	else
+		rc = decode_ascii_ssetup(&bcc_ptr, bytes_remaining, ses,nls_cp);
+	
+ssetup_exit:
+	kfree(str_area);
+	if(resp_buf_type == CIFS_SMALL_BUFFER) {
+		cFYI(1,("ssetup freeing small buf %p", iov[0].iov_base));
+		cifs_small_buf_release(iov[0].iov_base);
+	} else if(resp_buf_type == CIFS_LARGE_BUFFER)
+		cifs_buf_release(iov[0].iov_base);
+
+	return rc;
+}
--- linux-2.6.13/fs/cifs/smbencrypt.c
+++ linux-2.6.13/fs/cifs/smbencrypt.c
@@ -30,6 +30,7 @@
 #include <linux/random.h>
 #include "cifs_unicode.h"
 #include "cifspdu.h"
+#include "cifsglob.h"
 #include "md5.h"
 #include "cifs_debug.h"
 #include "cifsencrypt.h"
--- linux-2.6.13/fs/cifs/TODO
+++ linux-2.6.13/fs/cifs/TODO
@@ -1,4 +1,4 @@
-version 1.34 April 29, 2005
+Version 1.39 November 30, 2005
 
 A Partial List of Missing Features
 ==================================
@@ -7,14 +7,14 @@
 for visible, important contributions to this module.  Here
 is a partial list of the known problems and missing features:
 
-a) Support for SecurityDescriptors for chmod/chgrp/chown so
-these can be supported for Windows servers
+a) Support for SecurityDescriptors(Windows/CIFS ACLs) for chmod/chgrp/chown
+so that these operations can be supported to Windows servers
 
-b) Better pam/winbind integration (e.g. to handle uid mapping
-better)
+b) Mapping POSIX ACLs (and eventually NFSv4 ACLs) to CIFS
+SecurityDescriptors
 
-c) multi-user mounts - multiplexed sessionsetups over single vc
-(ie tcp session) - more testing needed
+c) Better pam/winbind integration (e.g. to handle uid mapping
+better)
 
 d) Kerberos/SPNEGO session setup support - (started)
 
@@ -29,12 +29,17 @@
 using FindNotify or equivalent.  - (started)
 
 g) A few byte range testcases fail due to POSIX vs. Windows/CIFS
-style byte range lock differences
+style byte range lock differences.  Save byte range locks so
+reconnect can replay them.  
 
-h) quota support
+h) Support unlock all (unlock 0,MAX_OFFSET)
+by unlocking all known byte range locks that we locked on the file.
 
-j) finish writepages support (multi-page write behind for improved
-performance) and syncpage
+i) quota support (needs minor kernel change since quota calls
+to make it to network filesystems or deviceless filesystems)
+
+j) investigate sync behavior (including syncpage) and check  
+for proper behavior of intr/nointr
 
 k) hook lower into the sockets api (as NFS/SunRPC does) to avoid the
 extra copy in/out of the socket buffers in some cases.
@@ -53,24 +58,22 @@
 at a time when 8 pages or more are requested. In conjuntion
 add support for async_cifs_readpages.
 
-p) Add support for storing symlink and fifo info to Windows servers 
+p) Add support for storing symlink info to Windows servers 
 in the Extended Attribute format their SFU clients would recognize.
 
 q) Finish fcntl D_NOTIFY support so kde and gnome file list windows
-will autorefresh (started)
+will autorefresh (partially complete by Asser). Needs minor kernel
+vfs change to support removing D_NOTIFY on a file.   
 
 r) Add GUI tool to configure /proc/fs/cifs settings and for display of
 the CIFS statistics (started)
 
-q) implement support for security and trusted categories of xattrs
+s) implement support for security and trusted categories of xattrs
 (requires minor protocol extension) to enable better support for SELINUX
 
-r) Implement O_DIRECT flag on open (already supported on mount)
-
-s) Allow remapping of last remaining character (\) to +0xF000 which
-(this character is valid for POSIX but not for Windows)
+t) Implement O_DIRECT flag on open (already supported on mount)
 
-t) Create UID mapping facility so server UIDs can be mapped on a per
+u) Create UID mapping facility so server UIDs can be mapped on a per
 mount or a per server basis to client UIDs or nobody if no mapping
 exists.  This is helpful when Unix extensions are negotiated to
 allow better permission checking when UIDs differ on the server
@@ -78,6 +81,17 @@
 standard for asking the server for the corresponding name of a
 particular uid.
 
+v) Add support for CIFS Unix and also the newer POSIX extensions to the
+server side for Samba 4.
+
+w) Finish up the dos time conversion routines needed to return old server
+time to the client (default time, of now or time 0 is used now for these 
+very old servers)
+
+x) Add support for OS/2 (LANMAN 1.2 and LANMAN2.1 based SMB servers)
+
+y) Finish testing of Windows 9x/Windows ME server support (started).
+
 KNOWN BUGS (updated April 29, 2005)
 ====================================
 See http://bugzilla.samba.org - search on product "CifsVFS" for
--- linux-2.6.13/fs/cifs/transport.c
+++ linux-2.6.13/fs/cifs/transport.c
@@ -3,6 +3,7 @@
  *
  *   Copyright (C) International Business Machines  Corp., 2002,2005
  *   Author(s): Steve French (sfrench@us.ibm.com)
+ *   Jeremy Allison (jra@samba.org) 2006.
  *
  *   This library is free software; you can redistribute it and/or modify
  *   it under the terms of the GNU Lesser General Public License as published
@@ -49,7 +50,8 @@
 		return NULL;
 	}
 	
-	temp = (struct mid_q_entry *) mempool_alloc(cifs_mid_poolp,SLAB_KERNEL | SLAB_NOFS);
+	temp = (struct mid_q_entry *) mempool_alloc(cifs_mid_poolp,
+						    SLAB_KERNEL | SLAB_NOFS);
 	if (temp == NULL)
 		return temp;
 	else {
@@ -58,7 +60,9 @@
 		temp->pid = current->pid;
 		temp->command = smb_buffer->Command;
 		cFYI(1, ("For smb_command %d", temp->command));
-		do_gettimeofday(&temp->when_sent);
+	/*	do_gettimeofday(&temp->when_sent);*/ /* easier to use jiffies */
+		/* when mid allocated can be before when sent */
+		temp->when_alloc = jiffies;
 		temp->ses = ses;
 		temp->tsk = current;
 	}
@@ -74,6 +78,9 @@
 static void
 DeleteMidQEntry(struct mid_q_entry *midEntry)
 {
+#ifdef CONFIG_CIFS_STATS2
+	unsigned long now;
+#endif
 	spin_lock(&GlobalMid_Lock);
 	midEntry->midState = MID_FREE;
 	list_del(&midEntry->qhead);
@@ -83,6 +90,22 @@
 		cifs_buf_release(midEntry->resp_buf);
 	else
 		cifs_small_buf_release(midEntry->resp_buf);
+#ifdef CONFIG_CIFS_STATS2
+	now = jiffies;
+	/* commands taking longer than one second are indications that
+	   something is wrong, unless it is quite a slow link or server */
+	if((now - midEntry->when_alloc) > HZ) {
+		if((cifsFYI & CIFS_TIMER) && 
+		   (midEntry->command != SMB_COM_LOCKING_ANDX)) {
+			printk(KERN_DEBUG " CIFS slow rsp: cmd %d mid %d",
+			       midEntry->command, midEntry->mid);
+			printk(" A: 0x%lx S: 0x%lx R: 0x%lx\n",
+			       now - midEntry->when_alloc,
+			       now - midEntry->when_sent,
+			       now - midEntry->when_received);
+		}
+	}
+#endif
 	mempool_free(midEntry, cifs_mid_poolp);
 }
 
@@ -128,6 +151,9 @@
 	struct msghdr smb_msg;
 	struct kvec iov;
 	unsigned len = smb_buf_length + 4;
+#if LINUX_VERSION_CODE < KERNEL_VERSION(2, 6, 8)
+	mm_segment_t temp_fs;
+#endif
 
 	if(ssocket == NULL)
 		return -ENOTSOCK; /* BB eventually add reconnect code here */
@@ -136,6 +162,10 @@
 
 	smb_msg.msg_name = sin;
 	smb_msg.msg_namelen = sizeof (struct sockaddr);
+#if LINUX_VERSION_CODE < KERNEL_VERSION(2, 6, 8)
+	smb_msg.msg_iov = &iov;
+	smb_msg.msg_iovlen = 1;
+#endif
 	smb_msg.msg_control = NULL;
 	smb_msg.msg_controllen = 0;
 	smb_msg.msg_flags = MSG_DONTWAIT + MSG_NOSIGNAL; /* BB add more flags?*/
@@ -146,32 +176,48 @@
 	   Flags2 is converted in SendReceive */
 
 	smb_buffer->smb_buf_length = cpu_to_be32(smb_buffer->smb_buf_length);
-	cFYI(1, ("Sending smb of length %d ", smb_buf_length));
+	cFYI(1, ("Sending smb of length %d", smb_buf_length));
 	dump_smb(smb_buffer, len);
 
+#if LINUX_VERSION_CODE < KERNEL_VERSION(2, 6, 8)
+	temp_fs = get_fs();	/* we must turn off socket api parm checking */
+	set_fs(get_ds());
+#endif
 	while (len > 0) {
+#if LINUX_VERSION_CODE < KERNEL_VERSION(2, 6, 8)
+		rc = sock_sendmsg(ssocket, &smb_msg, len);
+#else
 		rc = kernel_sendmsg(ssocket, &smb_msg, &iov, 1, len);
+#endif
 		if ((rc == -ENOSPC) || (rc == -EAGAIN)) {
 			i++;
-			if(i > 60) {
+		/* smaller timeout here than send2 since smaller size */
+		/* Although it may not be required, this also is smaller 
+		   oplock break time */  
+			if(i > 12) {
 				cERROR(1,
-				   ("sends on sock %p stuck for 30 seconds",
+				   ("sends on sock %p stuck for 7 seconds",
 				    ssocket));
 				rc = -EAGAIN;
 				break;
 			}
-			msleep(500);
+			msleep(1 << i);
 			continue;
 		}
 		if (rc < 0) 
 			break;
+		else
+			i = 0; /* reset i after each successful send */
 		iov.iov_base += rc;
 		iov.iov_len -= rc;
 		len -= rc;
 	}
+#if LINUX_VERSION_CODE < KERNEL_VERSION(2, 6, 8)
+	set_fs(temp_fs);
+#endif
 
 	if (rc < 0) {
-		cERROR(1,("Error %d sending data on socket to server.", rc));
+		cERROR(1,("Error %d sending data on socket to server", rc));
 	} else {
 		rc = 0;
 	}
@@ -179,26 +225,23 @@
 	return rc;
 }
 
-#ifdef CIFS_EXPERIMENTAL
-/* BB finish off this function, adding support for writing set of pages as iovec */
-/* and also adding support for operations that need to parse the response smb    */
-
-int
-smb_sendv(struct socket *ssocket, struct smb_hdr *smb_buffer,
-	 unsigned int smb_buf_length, struct kvec * write_vector 
-	  /* page list */, struct sockaddr *sin)
+static int
+smb_send2(struct socket *ssocket, struct kvec *iov, int n_vec,
+	  struct sockaddr *sin)
 {
 	int rc = 0;
 	int i = 0;
 	struct msghdr smb_msg;
-	number_of_pages += 1; /* account for SMB header */
-	struct kvec * piov  = kmalloc(number_of_pages * sizeof(struct kvec));
-	unsigned len = smb_buf_length + 4;
+	struct smb_hdr *smb_buffer = iov[0].iov_base;
+	unsigned int len = iov[0].iov_len;
+	unsigned int total_len;
+	int first_vec = 0;
+#if LINUX_VERSION_CODE < KERNEL_VERSION(2, 6, 8)
+	mm_segment_t temp_fs;
+#endif
 
 	if(ssocket == NULL)
 		return -ENOTSOCK; /* BB eventually add reconnect code here */
-	iov.iov_base = smb_buffer;
-	iov.iov_len = len;
 
 	smb_msg.msg_name = sin;
 	smb_msg.msg_namelen = sizeof (struct sockaddr);
@@ -211,67 +254,106 @@
 	   cifssmb.c and RFC1001 len is converted to bigendian in smb_send 
 	   Flags2 is converted in SendReceive */
 
+
+	total_len = 0;
+	for (i = 0; i < n_vec; i++)
+		total_len += iov[i].iov_len;
+
 	smb_buffer->smb_buf_length = cpu_to_be32(smb_buffer->smb_buf_length);
-	cFYI(1, ("Sending smb of length %d ", smb_buf_length));
+	cFYI(1, ("Sending smb:  total_len %d", total_len));
 	dump_smb(smb_buffer, len);
 
-	while (len > 0) {
-		rc = kernel_sendmsg(ssocket, &smb_msg, &iov, number_of_pages, 
-				    len);
+#if LINUX_VERSION_CODE < KERNEL_VERSION(2, 6, 8)
+	temp_fs = get_fs();	/* we must turn off socket api parm checking */
+	set_fs(get_ds());
+#endif
+	while (total_len) {
+#if LINUX_VERSION_CODE < KERNEL_VERSION(2, 6, 8)
+		smb_msg.msg_iov = &iov[first_vec];
+		smb_msg.msg_iovlen = n_vec - first_vec;
+		rc = sock_sendmsg(ssocket, &smb_msg, total_len);
+#else
+		rc = kernel_sendmsg(ssocket, &smb_msg, &iov[first_vec],
+				    n_vec - first_vec, total_len);
+#endif
 		if ((rc == -ENOSPC) || (rc == -EAGAIN)) {
 			i++;
-			if(i > 60) {
+			if(i >= 14) {
 				cERROR(1,
-				   ("sends on sock %p stuck for 30 seconds",
+				   ("sends on sock %p stuck for 15 seconds",
 				    ssocket));
 				rc = -EAGAIN;
 				break;
 			}
-			msleep(500);
+			msleep(1 << i);
 			continue;
 		}
 		if (rc < 0) 
 			break;
-		iov.iov_base += rc;
-		iov.iov_len -= rc;
-		len -= rc;
+
+		if (rc >= total_len) {
+			WARN_ON(rc > total_len);
+			break;
+		}
+		if(rc == 0) {
+			/* should never happen, letting socket clear before
+			   retrying is our only obvious option here */
+			cERROR(1,("tcp sent no data"));
+			msleep(500);
+			continue;
+		}
+		total_len -= rc;
+		/* the line below resets i */
+		for (i = first_vec; i < n_vec; i++) {
+			if (iov[i].iov_len) {
+				if (rc > iov[i].iov_len) {
+					rc -= iov[i].iov_len;
+					iov[i].iov_len = 0;
+				} else {
+					iov[i].iov_base += rc;
+					iov[i].iov_len -= rc;
+					first_vec = i;
+					break;
 	}
+			}
+		}
+		i = 0; /* in case we get ENOSPC on the next send */
+	}
+#if LINUX_VERSION_CODE < KERNEL_VERSION(2, 6, 8)
+	set_fs(temp_fs);
+#endif
 
 	if (rc < 0) {
-		cERROR(1,("Error %d sending data on socket to server.", rc));
-	} else {
+		cERROR(1,("Error %d sending data on socket to server", rc));
+	} else
 		rc = 0;
-	}
 
 	return rc;
 }
 
-
 int
-CIFSSendRcv(const unsigned int xid, struct cifsSesInfo *ses,
-	    struct smb_hdr *in_buf, struct kvec * write_vector /* page list */, int *pbytes_returned, const int long_op)
+SendReceive2(const unsigned int xid, struct cifsSesInfo *ses, 
+	     struct kvec *iov, int n_vec, int * pRespBufType /* ret */, 
+	     const int long_op)
 {
 	int rc = 0;
-	unsigned long timeout = 15 * HZ;
-	struct mid_q_entry *midQ = NULL;
+	unsigned int receive_len;
+	unsigned long timeout;
+	struct mid_q_entry *midQ;
+	struct smb_hdr *in_buf = iov[0].iov_base;
 
-	if (ses == NULL) {
-		cERROR(1,("Null smb session"));
-		return -EIO;
-	}
-	if(ses->server == NULL) {
-		cERROR(1,("Null tcp session"));
+	*pRespBufType = CIFS_NO_BUFFER;  /* no response buf yet */
+
+	if ((ses == NULL) || (ses->server == NULL)) {
+		cifs_small_buf_release(in_buf);
+		cERROR(1,("Null session"));
 		return -EIO;
 	}
-	if(pbytes_returned == NULL)
-		return -EIO;
-	else
-		*pbytes_returned = 0;
-
-  
 
-	if(ses->server->tcpStatus == CIFS_EXITING)
+	if(ses->server->tcpStatus == CifsExiting) {
+		cifs_small_buf_release(in_buf);
 		return -ENOENT;
+	}
 
 	/* Ensure that we do not send more than 50 overlapping requests 
 	   to the same server. We may make this configurable later or
@@ -282,15 +364,23 @@
 	} else {
 		spin_lock(&GlobalMid_Lock); 
 		while(1) {        
-			if(atomic_read(&ses->server->inFlight) >= cifs_max_pending){
+			if(atomic_read(&ses->server->inFlight) >= 
+					cifs_max_pending){
 				spin_unlock(&GlobalMid_Lock);
+#ifdef CONFIG_CIFS_STATS2
+				atomic_inc(&ses->server->num_waiters);
+#endif
 				wait_event(ses->server->request_q,
 					atomic_read(&ses->server->inFlight)
 					 < cifs_max_pending);
+#ifdef CONFIG_CIFS_STATS2
+				atomic_dec(&ses->server->num_waiters);
+#endif
 				spin_lock(&GlobalMid_Lock);
 			} else {
 				if(ses->server->tcpStatus == CifsExiting) {
 					spin_unlock(&GlobalMid_Lock);
+					cifs_small_buf_release(in_buf);
 					return -ENOENT;
 				}
 
@@ -314,22 +404,23 @@
 
 	if (ses->server->tcpStatus == CifsExiting) {
 		rc = -ENOENT;
-		goto cifs_out_label;
+		goto out_unlock2;
 	} else if (ses->server->tcpStatus == CifsNeedReconnect) {
 		cFYI(1,("tcp session dead - return to caller to retry"));
 		rc = -EAGAIN;
-		goto cifs_out_label;
+		goto out_unlock2;
 	} else if (ses->status != CifsGood) {
 		/* check if SMB session is bad because we are setting it up */
 		if((in_buf->Command != SMB_COM_SESSION_SETUP_ANDX) && 
 			(in_buf->Command != SMB_COM_NEGOTIATE)) {
 			rc = -EAGAIN;
-			goto cifs_out_label;
+			goto out_unlock2;
 		} /* else ok - we are setting up session */
 	}
 	midQ = AllocMidQEntry(in_buf, ses);
 	if (midQ == NULL) {
 		up(&ses->server->tcpSem);
+		cifs_small_buf_release(in_buf);
 		/* If not lock req, update # of requests on wire to server */
 		if(long_op < 3) {
 			atomic_dec(&ses->server->inFlight); 
@@ -338,40 +429,183 @@
 		return -ENOMEM;
 	}
 
-	if (in_buf->smb_buf_length > CIFSMaxBufSize + MAX_CIFS_HDR_SIZE - 4) {
-		up(&ses->server->tcpSem);
-		cERROR(1,
-		       ("Illegal length, greater than maximum frame, %d ",
-			in_buf->smb_buf_length));
+ 	rc = cifs_sign_smb2(iov, n_vec, ses->server, &midQ->sequence_number);
+
+	midQ->midState = MID_REQUEST_SUBMITTED;
+#ifdef CONFIG_CIFS_STATS2
+	atomic_inc(&ses->server->inSend);
+#endif
+	rc = smb_send2(ses->server->ssocket, iov, n_vec,
+		      (struct sockaddr *) &(ses->server->addr.sockAddr));
+#ifdef CONFIG_CIFS_STATS2
+	atomic_dec(&ses->server->inSend);
+	midQ->when_sent = jiffies;
+#endif
+	if(rc < 0) {
 		DeleteMidQEntry(midQ);
+		up(&ses->server->tcpSem);
+		cifs_small_buf_release(in_buf);
 		/* If not lock req, update # of requests on wire to server */
 		if(long_op < 3) {
 			atomic_dec(&ses->server->inFlight); 
 			wake_up(&ses->server->request_q);
 		}
-		return -EIO;
+		return rc;
+	} else {
+		up(&ses->server->tcpSem);
+		cifs_small_buf_release(in_buf);
 	}
 
-	/* BB can we sign efficiently in this path? */
-	rc = cifs_sign_smb(in_buf, ses->server, &midQ->sequence_number);
+	if (long_op == -1)
+		goto cifs_no_response_exit2;
+	else if (long_op == 2) /* writes past end of file can take loong time */
+		timeout = 180 * HZ;
+	else if (long_op == 1)
+		timeout = 45 * HZ; /* should be greater than 
+			servers oplock break timeout (about 43 seconds) */
+	else if (long_op > 2) {
+		timeout = MAX_SCHEDULE_TIMEOUT;
+	} else
+		timeout = 15 * HZ;
+	/* wait for 15 seconds or until woken up due to response arriving or 
+	   due to last connection to this server being unmounted */
+	if (signal_pending(current)) {
+		/* if signal pending do not hold up user for full smb timeout
+		but we still give response a change to complete */
+		timeout = 2 * HZ;
+	}   
 
-	midQ->midState = MID_REQUEST_SUBMITTED;
-/*	rc = smb_sendv(ses->server->ssocket, in_buf, in_buf->smb_buf_length,
-		       piovec, 
-		       (struct sockaddr *) &(ses->server->addr.sockAddr));*/
-	if(rc < 0) {
+	/* No user interrupts in wait - wreaks havoc with performance */
+	if(timeout != MAX_SCHEDULE_TIMEOUT) {
+		unsigned long curr_timeout;
+
+		for (;;) {
+			curr_timeout = timeout + jiffies;
+			wait_event(ses->server->response_q,
+				(!(midQ->midState == MID_REQUEST_SUBMITTED)) || 
+				time_after(jiffies, curr_timeout) || 
+				((ses->server->tcpStatus != CifsGood) &&
+				 (ses->server->tcpStatus != CifsNew)));
+
+			if (time_after(jiffies, curr_timeout) &&
+				(midQ->midState == MID_REQUEST_SUBMITTED) &&
+				((ses->server->tcpStatus == CifsGood) ||
+				 (ses->server->tcpStatus == CifsNew))) {
+
+				unsigned long lrt;
+
+				/* We timed out. Is the server still
+				   sending replies ? */
+				spin_lock(&GlobalMid_Lock);
+				lrt = ses->server->lstrp;
+				spin_unlock(&GlobalMid_Lock);
+
+				/* Calculate 10 seconds past last receive time.
+				Although we prefer not to time out if the 
+				server is still responding - we will time
+				out if the server takes more than 15 (or 45 
+				or 180) seconds to respond to this request
+				and has not responded to any request from 
+				other threads on the client within 10 seconds */
+				lrt += (10 * HZ);
+				if (time_after(jiffies, lrt)) {
+					/* No replies for 10 seconds. */
+					cERROR(1,("server not responding"));
+					break;
+				}
+			} else {
+				break;
+			}
+		}
+	} else {
+		wait_event(ses->server->response_q,
+			(!(midQ->midState == MID_REQUEST_SUBMITTED)) || 
+			((ses->server->tcpStatus != CifsGood) &&
+			 (ses->server->tcpStatus != CifsNew)));
+	}
+
+	spin_lock(&GlobalMid_Lock);
+	if (midQ->resp_buf) {
+		spin_unlock(&GlobalMid_Lock);
+		receive_len = midQ->resp_buf->smb_buf_length;
+	} else {
+		cERROR(1,("No response to cmd %d mid %d",
+			midQ->command, midQ->mid));
+		if(midQ->midState == MID_REQUEST_SUBMITTED) {
+			if(ses->server->tcpStatus == CifsExiting)
+				rc = -EHOSTDOWN;
+			else {
+				ses->server->tcpStatus = CifsNeedReconnect;
+				midQ->midState = MID_RETRY_NEEDED;
+			}
+		}
+
+		if (rc != -EHOSTDOWN) {
+			if(midQ->midState == MID_RETRY_NEEDED) {
+				rc = -EAGAIN;
+				cFYI(1,("marking request for retry"));
+			} else {
+				rc = -EIO;
+			}
+		}
+		spin_unlock(&GlobalMid_Lock);
 		DeleteMidQEntry(midQ);
-		up(&ses->server->tcpSem);
 		/* If not lock req, update # of requests on wire to server */
 		if(long_op < 3) {
 			atomic_dec(&ses->server->inFlight); 
 			wake_up(&ses->server->request_q);
 		}
 		return rc;
-	} else
-		up(&ses->server->tcpSem);
-cifs_out_label:
-	if(midQ)
+	}
+  
+	if (receive_len > CIFSMaxBufSize + MAX_CIFS_HDR_SIZE) {
+		cERROR(1, ("Frame too large received.  Length: %d  Xid: %d",
+			receive_len, xid));
+		rc = -EIO;
+	} else {		/* rcvd frame is ok */
+		if (midQ->resp_buf && 
+			(midQ->midState == MID_RESPONSE_RECEIVED)) {
+
+			iov[0].iov_base = (char *)midQ->resp_buf;
+			if(midQ->largeBuf)
+				*pRespBufType = CIFS_LARGE_BUFFER;
+			else
+				*pRespBufType = CIFS_SMALL_BUFFER;
+			iov[0].iov_len = receive_len + 4;
+
+			dump_smb(midQ->resp_buf, 80);
+			/* convert the length into a more usable form */
+			if((receive_len > 24) &&
+			   (ses->server->secMode & (SECMODE_SIGN_REQUIRED |
+					SECMODE_SIGN_ENABLED))) {
+				rc = cifs_verify_signature(midQ->resp_buf,
+						ses->server->mac_signing_key,
+						midQ->sequence_number+1);
+				if(rc) {
+					cERROR(1,("Unexpected SMB signature"));
+					/* BB FIXME add code to kill session */
+				}
+			}
+
+			/* BB special case reconnect tid and uid here? */
+			/* BB special case Errbadpassword and pwdexpired here */
+			rc = map_smb_to_linux_error(midQ->resp_buf);
+
+			/* convert ByteCount if necessary */
+			if (receive_len >=
+			    sizeof (struct smb_hdr) -
+			    4 /* do not count RFC1001 header */  +
+			    (2 * midQ->resp_buf->WordCount) + 2 /* bcc */ )
+				BCC(midQ->resp_buf) = 
+					le16_to_cpu(BCC_LE(midQ->resp_buf));
+			midQ->resp_buf = NULL;  /* mark it so will not be freed
+						by DeleteMidQEntry */
+		} else {
+			rc = -EIO;
+			cFYI(1,("Bad MID state?"));
+		}
+	}
+cifs_no_response_exit2:
 	        DeleteMidQEntry(midQ);
                                                                                                                            
 	if(long_op < 3) {
@@ -380,10 +614,18 @@
 	}
 
 	return rc;
-}
 
+out_unlock2:
+	up(&ses->server->tcpSem);
+	cifs_small_buf_release(in_buf);
+	/* If not lock req, update # of requests on wire to server */
+	if(long_op < 3) {
+		atomic_dec(&ses->server->inFlight); 
+		wake_up(&ses->server->request_q);
+	}
 
-#endif /* CIFS_EXPERIMENTAL */
+	return rc;
+}
 
 int
 SendReceive(const unsigned int xid, struct cifsSesInfo *ses,
@@ -419,9 +661,15 @@
 			if(atomic_read(&ses->server->inFlight) >= 
 					cifs_max_pending){
 				spin_unlock(&GlobalMid_Lock);
+#ifdef CONFIG_CIFS_STATS2
+				atomic_inc(&ses->server->num_waiters);
+#endif
 				wait_event(ses->server->request_q,
 					atomic_read(&ses->server->inFlight)
 					 < cifs_max_pending);
+#ifdef CONFIG_CIFS_STATS2
+				atomic_dec(&ses->server->num_waiters);
+#endif
 				spin_lock(&GlobalMid_Lock);
 			} else {
 				if(ses->server->tcpStatus == CifsExiting) {
@@ -475,8 +723,7 @@
 
 	if (in_buf->smb_buf_length > CIFSMaxBufSize + MAX_CIFS_HDR_SIZE - 4) {
 		up(&ses->server->tcpSem);
-		cERROR(1,
-		       ("Illegal length, greater than maximum frame, %d ",
+		cERROR(1, ("Illegal length, greater than maximum frame, %d",
 			in_buf->smb_buf_length));
 		DeleteMidQEntry(midQ);
 		/* If not lock req, update # of requests on wire to server */
@@ -490,8 +737,15 @@
 	rc = cifs_sign_smb(in_buf, ses->server, &midQ->sequence_number);
 
 	midQ->midState = MID_REQUEST_SUBMITTED;
+#ifdef CONFIG_CIFS_STATS2
+	atomic_inc(&ses->server->inSend);
+#endif
 	rc = smb_send(ses->server->ssocket, in_buf, in_buf->smb_buf_length,
 		      (struct sockaddr *) &(ses->server->addr.sockAddr));
+#ifdef CONFIG_CIFS_STATS2
+	atomic_dec(&ses->server->inSend);
+	midQ->when_sent = jiffies;
+#endif
 	if(rc < 0) {
 		DeleteMidQEntry(midQ);
 		up(&ses->server->tcpSem);
@@ -506,7 +760,7 @@
 	if (long_op == -1)
 		goto cifs_no_response_exit;
 	else if (long_op == 2) /* writes past end of file can take loong time */
-		timeout = 300 * HZ;
+		timeout = 180 * HZ;
 	else if (long_op == 1)
 		timeout = 45 * HZ; /* should be greater than 
 			servers oplock break timeout (about 43 seconds) */
@@ -524,15 +778,43 @@
 
 	/* No user interrupts in wait - wreaks havoc with performance */
 	if(timeout != MAX_SCHEDULE_TIMEOUT) {
-		timeout += jiffies;
+		unsigned long curr_timeout;
+
+		for (;;) {
+			curr_timeout = timeout + jiffies;
 		wait_event(ses->server->response_q,
-			(!(midQ->midState & MID_REQUEST_SUBMITTED)) || 
-			time_after(jiffies, timeout) || 
+				(!(midQ->midState == MID_REQUEST_SUBMITTED)) || 
+				time_after(jiffies, curr_timeout) || 
 			((ses->server->tcpStatus != CifsGood) &&
 			 (ses->server->tcpStatus != CifsNew)));
+
+			if (time_after(jiffies, curr_timeout) &&
+				(midQ->midState == MID_REQUEST_SUBMITTED) &&
+				((ses->server->tcpStatus == CifsGood) ||
+				 (ses->server->tcpStatus == CifsNew))) {
+
+				unsigned long lrt;
+
+				/* We timed out. Is the server still
+				   sending replies ? */
+				spin_lock(&GlobalMid_Lock);
+				lrt = ses->server->lstrp;
+				spin_unlock(&GlobalMid_Lock);
+
+				/* Calculate 10 seconds past last receive time*/
+				lrt += (10 * HZ);
+				if (time_after(jiffies, lrt)) {
+					/* Server sent no reply in 10 seconds */
+					cERROR(1,("Server not responding"));
+					break;
+				}
+			} else {
+				break;
+			}
+		}
 	} else {
 		wait_event(ses->server->response_q,
-			(!(midQ->midState & MID_REQUEST_SUBMITTED)) || 
+			(!(midQ->midState == MID_REQUEST_SUBMITTED)) || 
 			((ses->server->tcpStatus != CifsGood) &&
 			 (ses->server->tcpStatus != CifsNew)));
 	}
@@ -540,9 +822,10 @@
 	spin_lock(&GlobalMid_Lock);
 	if (midQ->resp_buf) {
 		spin_unlock(&GlobalMid_Lock);
-		receive_len = be32_to_cpu(*(__be32 *)midQ->resp_buf);
+		receive_len = midQ->resp_buf->smb_buf_length;
 	} else {
-		cERROR(1,("No response buffer"));
+		cERROR(1,("No response for cmd %d mid %d",
+			  midQ->command, midQ->mid));
 		if(midQ->midState == MID_REQUEST_SUBMITTED) {
 			if(ses->server->tcpStatus == CifsExiting)
 				rc = -EHOSTDOWN;
@@ -607,10 +890,10 @@
 			    sizeof (struct smb_hdr) -
 			    4 /* do not count RFC1001 header */  +
 			    (2 * out_buf->WordCount) + 2 /* bcc */ )
-				BCC(out_buf) = le16_to_cpu(BCC(out_buf));
+				BCC(out_buf) = le16_to_cpu(BCC_LE(out_buf));
 		} else {
 			rc = -EIO;
-			cFYI(1,("Bad MID state? "));
+			cERROR(1,("Bad MID state?"));
 		}
 	}
 cifs_no_response_exit:
--- linux-2.6.13/fs/cifs/xattr.c
+++ linux-2.6.13/fs/cifs/xattr.c
@@ -62,9 +62,7 @@
 	cifs_sb = CIFS_SB(sb);
 	pTcon = cifs_sb->tcon;
                                                                                      
-	down(&sb->s_vfs_rename_sem);
 	full_path = build_path_from_dentry(direntry);
-	up(&sb->s_vfs_rename_sem);
 	if(full_path == NULL) {
 		FreeXid(xid);
 		return -ENOMEM;
@@ -87,7 +85,6 @@
 			cifs_sb->mnt_cifs_flags & CIFS_MOUNT_MAP_SPECIAL_CHR);
 	}
 remove_ea_exit:
-	if (full_path)
 		kfree(full_path);
 	FreeXid(xid);
 #endif
@@ -117,9 +114,7 @@
 	cifs_sb = CIFS_SB(sb);
 	pTcon = cifs_sb->tcon;
 
-	down(&sb->s_vfs_rename_sem);
 	full_path = build_path_from_dentry(direntry);
-	up(&sb->s_vfs_rename_sem);
 	if(full_path == NULL) {
 		FreeXid(xid);
 		return -ENOMEM;
@@ -132,7 +127,6 @@
 		returns as xattrs */
 	if(value_size > MAX_EA_VALUE_SIZE) {
 		cFYI(1,("size of EA value too large"));
-		if(full_path)
 			kfree(full_path);
 		FreeXid(xid);
 		return -EOPNOTSUPP;
@@ -195,7 +189,6 @@
 	}
 
 set_ea_exit:
-	if (full_path)
 		kfree(full_path);
 	FreeXid(xid);
 #endif
@@ -226,9 +219,7 @@
 	cifs_sb = CIFS_SB(sb);
 	pTcon = cifs_sb->tcon;
 
-	down(&sb->s_vfs_rename_sem);
 	full_path = build_path_from_dentry(direntry);
-	up(&sb->s_vfs_rename_sem);
 	if(full_path == NULL) {
 		FreeXid(xid);
 		return -ENOMEM;
@@ -257,7 +248,8 @@
 		rc = CIFSSMBQueryEA(xid,pTcon,full_path,ea_name,ea_value,
 			buf_size, cifs_sb->local_nls,
 			cifs_sb->mnt_cifs_flags & CIFS_MOUNT_MAP_SPECIAL_CHR);
-	} else if(strncmp(ea_name,POSIX_ACL_XATTR_ACCESS,strlen(POSIX_ACL_XATTR_ACCESS)) == 0) {
+	} else if(strncmp(ea_name,POSIX_ACL_XATTR_ACCESS,
+			  strlen(POSIX_ACL_XATTR_ACCESS)) == 0) {
 #ifdef CONFIG_CIFS_POSIX
 		if(sb->s_flags & MS_POSIXACL)
 			rc = CIFSSMBGetPosixACL(xid, pTcon, full_path,
@@ -265,10 +257,27 @@
 				cifs_sb->local_nls,
 				cifs_sb->mnt_cifs_flags & 
 					CIFS_MOUNT_MAP_SPECIAL_CHR);
+/*		else if(cifs_sb->mnt_cifs_flags & CIFS_MOUNT_CIFS_ACL) {
+			__u16 fid;
+			int oplock = FALSE;
+			rc = CIFSSMBOpen(xid, pTcon, full_path,
+					 FILE_OPEN, GENERIC_READ, 0, &fid,
+					 &oplock, NULL, cifs_sb->local_nls,
+					 cifs_sb->mnt_cifs_flags &
+					 CIFS_MOUNT_MAP_SPECIAL_CHR);
+			if(rc == 0) {
+				rc = CIFSSMBGetCIFSACL(xid, pTcon, fid,
+					ea_value, buf_size,
+					ACL_TYPE_ACCESS);
+				CIFSSMBClose(xid, pTcon, fid)
+			}
+		} */  /* BB enable after fixing up return data */
+                  		
 #else 
 		cFYI(1,("query POSIX ACL not supported yet"));
 #endif /* CONFIG_CIFS_POSIX */
-	} else if(strncmp(ea_name,POSIX_ACL_XATTR_DEFAULT,strlen(POSIX_ACL_XATTR_DEFAULT)) == 0) {
+	} else if(strncmp(ea_name,POSIX_ACL_XATTR_DEFAULT,
+			  strlen(POSIX_ACL_XATTR_DEFAULT)) == 0) {
 #ifdef CONFIG_CIFS_POSIX
 		if(sb->s_flags & MS_POSIXACL)
 			rc = CIFSSMBGetPosixACL(xid, pTcon, full_path,
@@ -298,7 +307,6 @@
 		rc = -EOPNOTSUPP; 
 
 get_ea_exit:
-	if (full_path)
 		kfree(full_path);
 	FreeXid(xid);
 #endif
@@ -327,9 +335,7 @@
 	cifs_sb = CIFS_SB(sb);
 	pTcon = cifs_sb->tcon;
 
-	down(&sb->s_vfs_rename_sem);
 	full_path = build_path_from_dentry(direntry);
-	up(&sb->s_vfs_rename_sem);
 	if(full_path == NULL) {
 		FreeXid(xid);
 		return -ENOMEM;
@@ -345,7 +351,6 @@
 				cifs_sb->mnt_cifs_flags & 
 					CIFS_MOUNT_MAP_SPECIAL_CHR);
 
-	if (full_path)
 		kfree(full_path);
 	FreeXid(xid);
 #endif
