changeset 12902:16985853e3aa

6957935 Only one standalone DFS namespace should be cached 6958322 Should allow setting and returning target priority info for DFS root target 6955030 assertion failed in thread_join() from smb_server_delete() 6950891 No "no matching rule" trace point for pid->sid 6957520 Sparc - System panics when running smbstat 6950103 Failed to open group database due to too many open files 6961197 SAMR requests failed due to context mismatch 6960835 Need to pass the share type to smbsrv 6952831 SMB level II oplocks 6955337 "Found in AD" tracepoint bogus for U->W with directory-based mapping 6960038 CIFS file ownership problem 6915527 libidmap should not export memdup() 6960283 Windows client dir /R option not listing NTFS named stream 6808472 SMB name space caching on clients 6966183 SMB/CIFS print service CUPS support 6966490 Validation support for NetrDfsSetInfo method, level 105 6962887 Restore kstats for SMB commands 6969600 ::smblist -r[v] crashed mdb 6968451 panic: smbsrv:smb_odir_open 6957572 Cifs server panics at ffffff000c895ad0 smbsrv:smb_user_delete+82 () with smbtorture test.
author joyce mcintosh <Joyce.McIntosh@Sun.COM>
date Thu, 22 Jul 2010 14:53:56 -0700
parents 7977d17e3193
children 2759f7cccf59
files usr/src/cmd/idmap/idmap/namemaps.h usr/src/cmd/idmap/idmapd/Makefile usr/src/cmd/idmap/idmapd/dbutils.c usr/src/cmd/idmap/idmapd/directory_provider_ad.c usr/src/cmd/idmap/idmapd/directory_provider_builtin.c usr/src/cmd/idmap/idmapd/directory_provider_nsswitch.c usr/src/cmd/idmap/idmapd/directory_server.c usr/src/cmd/idmap/idmapd/server.c usr/src/cmd/idmap/idmapd/wksids.c usr/src/cmd/mdb/common/modules/smbsrv/smbsrv.c usr/src/cmd/smbsrv/dtrace/msrpc.d usr/src/cmd/smbsrv/smbd/smbd_main.c usr/src/lib/Makefile usr/src/lib/libidmap/Makefile.com usr/src/lib/libidmap/common/directory_helper.c usr/src/lib/libidmap/common/directory_library_impl.h usr/src/lib/libidmap/common/llib-lidmap usr/src/lib/libidmap/common/mapfile-vers usr/src/lib/libidmap/common/miscutils.c usr/src/lib/libidmap/common/miscutils.h usr/src/lib/libshare/smb/libshare_smb.c usr/src/lib/libuutil/Makefile.com usr/src/lib/libuutil/common/libuutil.h usr/src/lib/libuutil/common/mapfile-vers usr/src/lib/libuutil/common/uu_alloc.c usr/src/lib/libuutil/common/uu_misc.c usr/src/lib/libuutil/common/uu_string.c usr/src/lib/smbsrv/libmlrpc/common/ndr_server.c usr/src/lib/smbsrv/libmlsvc/common/dfs.c usr/src/lib/smbsrv/libmlsvc/common/dfs.h usr/src/lib/smbsrv/libmlsvc/common/libmlsvc.h usr/src/lib/smbsrv/libmlsvc/common/mapfile-vers usr/src/lib/smbsrv/libmlsvc/common/mlsvc.h usr/src/lib/smbsrv/libmlsvc/common/mlsvc_init.c usr/src/lib/smbsrv/libmlsvc/common/netdfs.c usr/src/lib/smbsrv/libmlsvc/common/samr_clnt.c usr/src/lib/smbsrv/libmlsvc/common/samr_svc.c usr/src/lib/smbsrv/libmlsvc/common/smb_share.c usr/src/lib/smbsrv/libmlsvc/common/spoolss_svc.c usr/src/lib/smbsrv/libmlsvc/common/srvsvc_svc.c usr/src/lib/smbsrv/libsmb/common/libsmb.h usr/src/lib/smbsrv/libsmb/common/mapfile-vers usr/src/lib/smbsrv/libsmb/common/smb_cfg.c usr/src/lib/smbsrv/libsmb/common/smb_info.c usr/src/lib/smbsrv/libsmb/common/smb_kmod.c usr/src/uts/common/fs/smbsrv/smb_common_open.c usr/src/uts/common/fs/smbsrv/smb_create.c usr/src/uts/common/fs/smbsrv/smb_delete.c usr/src/uts/common/fs/smbsrv/smb_dispatch.c usr/src/uts/common/fs/smbsrv/smb_fem.c usr/src/uts/common/fs/smbsrv/smb_find.c usr/src/uts/common/fs/smbsrv/smb_fsops.c usr/src/uts/common/fs/smbsrv/smb_init.c usr/src/uts/common/fs/smbsrv/smb_kdoor.c usr/src/uts/common/fs/smbsrv/smb_kshare.c usr/src/uts/common/fs/smbsrv/smb_kutil.c usr/src/uts/common/fs/smbsrv/smb_lock.c usr/src/uts/common/fs/smbsrv/smb_locking_andx.c usr/src/uts/common/fs/smbsrv/smb_mangle_name.c usr/src/uts/common/fs/smbsrv/smb_negotiate.c usr/src/uts/common/fs/smbsrv/smb_node.c usr/src/uts/common/fs/smbsrv/smb_nt_create_andx.c usr/src/uts/common/fs/smbsrv/smb_nt_transact_create.c usr/src/uts/common/fs/smbsrv/smb_nt_transact_ioctl.c usr/src/uts/common/fs/smbsrv/smb_odir.c usr/src/uts/common/fs/smbsrv/smb_ofile.c usr/src/uts/common/fs/smbsrv/smb_open_andx.c usr/src/uts/common/fs/smbsrv/smb_opipe.c usr/src/uts/common/fs/smbsrv/smb_oplock.c usr/src/uts/common/fs/smbsrv/smb_pathname.c usr/src/uts/common/fs/smbsrv/smb_print.c usr/src/uts/common/fs/smbsrv/smb_query_fileinfo.c usr/src/uts/common/fs/smbsrv/smb_read.c usr/src/uts/common/fs/smbsrv/smb_rename.c usr/src/uts/common/fs/smbsrv/smb_server.c usr/src/uts/common/fs/smbsrv/smb_session.c usr/src/uts/common/fs/smbsrv/smb_session_setup_andx.c usr/src/uts/common/fs/smbsrv/smb_set_fileinfo.c usr/src/uts/common/fs/smbsrv/smb_tree.c usr/src/uts/common/fs/smbsrv/smb_tree_connect.c usr/src/uts/common/fs/smbsrv/smb_write.c usr/src/uts/common/fs/smbsrv/smb_write_raw.c usr/src/uts/common/smbsrv/Makefile usr/src/uts/common/smbsrv/ndl/samrpc.ndl usr/src/uts/common/smbsrv/ndl/security.ndl usr/src/uts/common/smbsrv/ndl/spoolss.ndl usr/src/uts/common/smbsrv/smb.h usr/src/uts/common/smbsrv/smb_dfs.h usr/src/uts/common/smbsrv/smb_ioctl.h usr/src/uts/common/smbsrv/smb_kproto.h usr/src/uts/common/smbsrv/smb_kstat.h usr/src/uts/common/smbsrv/smb_ktypes.h usr/src/uts/common/smbsrv/smb_share.h usr/src/uts/common/smbsrv/smb_vops.h usr/src/uts/common/smbsrv/smbinfo.h
diffstat 94 files changed, 5143 insertions(+), 1716 deletions(-) [+]
line wrap: on
line diff
--- a/usr/src/cmd/idmap/idmapd/Makefile	Thu Jul 22 12:31:36 2010 -0700
+++ b/usr/src/cmd/idmap/idmapd/Makefile	Thu Jul 22 14:53:56 2010 -0700
@@ -34,7 +34,7 @@
 	idmap_config.o			\
 	idmapd.o			\
 	init.o				\
-	idmap_lsa.o				\
+	idmap_lsa.o			\
 	nldaputils.o			\
 	rpc_svc.o			\
 	server.o			\
@@ -89,6 +89,7 @@
 	-ladutils \
 	-lumem \
 	-lnvpair \
+	-luutil \
 	-L $(ROOT)/usr/lib/smbsrv \
 	-lsmb
 
--- a/usr/src/cmd/idmap/idmapd/dbutils.c	Thu Jul 22 12:31:36 2010 -0700
+++ b/usr/src/cmd/idmap/idmapd/dbutils.c	Thu Jul 22 14:53:56 2010 -0700
@@ -41,6 +41,7 @@
 #include <assert.h>
 #include <sys/u8_textprep.h>
 #include <alloca.h>
+#include <libuutil.h>
 #include <note.h>
 
 #include "idmapd.h"
@@ -50,7 +51,6 @@
 #include "schema.h"
 #include "nldaputils.h"
 #include "idmap_lsa.h"
-#include "miscutils.h"
 
 
 static idmap_retcode sql_compile_n_step_once(sqlite *, char *,
@@ -59,8 +59,6 @@
 static idmap_retcode lookup_cache_name2sid(sqlite *, const char *,
 	    const char *, char **, char **, idmap_rid_t *, idmap_id_type *);
 
-#define	NELEM(a)	(sizeof (a) / sizeof ((a)[0]))
-
 #define	EMPTY_NAME(name)	(*name == 0 || strcmp(name, "\"\"") == 0)
 
 #define	DO_NOT_ALLOC_NEW_ID_MAPPING(req)\
@@ -2256,8 +2254,15 @@
 		}
 
 		if (IS_ID_SID(req->id1)) {
-			if (res->retcode != IDMAP_SUCCESS)
+			if (res->retcode == IDMAP_ERR_NOTFOUND) {
+				TRACE(req, res, "Not found in AD");
 				continue;
+			}
+			if (res->retcode != IDMAP_SUCCESS) {
+				TRACE(req, res, "AD lookup error=%d",
+				    res->retcode);
+				continue;
+			}
 			/* Evaluate result type */
 			switch (type) {
 			case IDMAP_USID:
@@ -2302,6 +2307,7 @@
 				res->retcode = IDMAP_ERR_SID;
 				break;
 			}
+			TRACE(req, res, "Found in AD");
 			if (res->retcode == IDMAP_SUCCESS &&
 			    req->id1name != NULL &&
 			    (req->id2name == NULL ||
@@ -2314,7 +2320,7 @@
 			if (res->retcode != IDMAP_SUCCESS) {
 				if ((!(IDMAP_FATAL_ERROR(res->retcode))) &&
 				    res->id.idmap_id_u.sid.prefix == NULL &&
-				    req->id2name == NULL) /* no winname */
+				    req->id2name == NULL) {
 					/*
 					 * If AD lookup by unixname or pid
 					 * failed with non fatal error
@@ -2324,7 +2330,20 @@
 					 * process other mapping
 					 * mechanisms for this request.
 					 */
-					res->retcode = IDMAP_SUCCESS;
+					if (res->retcode ==
+					    IDMAP_ERR_NOTFOUND) {
+						/* This is not an error */
+						res->retcode = IDMAP_SUCCESS;
+						TRACE(req, res,
+						    "Not found in AD");
+					} else {
+						TRACE(req, res,
+						"AD lookup error (ignored)");
+						res->retcode = IDMAP_SUCCESS;
+					}
+				} else {
+					TRACE(req, res, "AD lookup error");
+				}
 				continue;
 			}
 			/* Evaluate result type */
@@ -2339,6 +2358,7 @@
 				res->retcode = IDMAP_ERR_SID;
 				break;
 			}
+			TRACE(req, res, "Found in AD");
 		}
 	}
 
@@ -2535,7 +2555,7 @@
 			if (p != NULL) {
 				char *q;
 				q = req->id1name;
-				req->id1name = strndup(q, p - req->id1name);
+				req->id1name = uu_strndup(q, p - req->id1name);
 				req->id1domain = strdup(p+1);
 				free(q);
 				if (req->id1name == NULL ||
@@ -3126,6 +3146,7 @@
 			}
 			goto out;
 		} else if (r == SQLITE_DONE) {
+			TRACE(req, res, "No matching rule");
 			retcode = IDMAP_ERR_NOTFOUND;
 			goto out;
 		} else {
@@ -3523,7 +3544,6 @@
 		TRACE(req, res, "Rule-based mapping error=%d", retcode);
 		goto out;
 	}
-	TRACE(req, res, "No matching rule");
 
 do_eph:
 	/* If not found, do ephemeral mapping */
@@ -4390,7 +4410,6 @@
 	int		ncol, r;
 	int		want_wuser;
 	const char	*me = "name_based_mapping_pid2sid";
-	int 		non_wild_match = FALSE;
 	idmap_namerule	*rule = &res->info.how.idmap_how_u.rule;
 	int direction;
 
@@ -4459,28 +4478,10 @@
 
 			if (values[0][0] == '*') {
 				winname = unixname;
-				if (non_wild_match) {
-					/*
-					 * There were non-wildcard rules
-					 * where the Windows identity doesn't
-					 * exist. Return no mapping.
-					 */
-					retcode = IDMAP_ERR_NOMAPPING;
-					goto out;
-				}
 			} else {
-				/* Save first non-wild match rule */
-				if (!non_wild_match) {
-					idmap_namerule_set(rule, values[1],
-					    values[0], values[4],
-					    is_user,
-					    strtol(values[3], &end, 10),
-					    strtol(values[5], &end, 10),
-					    direction);
-					non_wild_match = TRUE;
-				}
 				winname = values[0];
 			}
+
 			want_wuser = res->id.idtype == IDMAP_USID ? 1
 			    : res->id.idtype == IDMAP_GSID ? 0
 			    : -1;
@@ -4509,28 +4510,34 @@
 			if (retcode == IDMAP_SUCCESS) {
 				break;
 			} else if (retcode == IDMAP_ERR_NOTFOUND) {
-				TRACE(req, res,
-				    "%s@%s not found, continuing",
-				    winname, windomain);
-				continue;
+				if (values[0][0] == '*') {
+					TRACE(req, res,
+					    "%s@%s not found, continuing",
+					    winname, windomain);
+					continue;
+				} else {
+					TRACE(req, res,
+					    "%s@%s not found",
+					    winname, windomain);
+					retcode = IDMAP_ERR_NOMAPPING;
+				}
 			} else {
 				TRACE(req, res,
 				    "Looking up %s@%s error=%d",
 				    winname, windomain, retcode);
 			}
 
+			idmap_namerule_set(rule, values[1],
+			    values[0], values[4], is_user,
+			    strtol(values[3], &end, 10),
+			    strtol(values[5], &end, 10),
+			    direction);
+
 			goto out;
 
 		} else if (r == SQLITE_DONE) {
-			/*
-			 * If there were non-wildcard rules where
-			 * Windows identity doesn't exist
-			 * return no mapping.
-			 */
-			if (non_wild_match)
-				retcode = IDMAP_ERR_NOMAPPING;
-			else
-				retcode = IDMAP_ERR_NOTFOUND;
+			TRACE(req, res, "No matching rule");
+			retcode = IDMAP_ERR_NOTFOUND;
 			goto out;
 		} else {
 			(void) sqlite_finalize(vm, &errmsg);
--- a/usr/src/cmd/idmap/idmapd/directory_provider_ad.c	Thu Jul 22 12:31:36 2010 -0700
+++ b/usr/src/cmd/idmap/idmapd/directory_provider_ad.c	Thu Jul 22 14:53:56 2010 -0700
@@ -20,8 +20,7 @@
  */
 
 /*
- * Copyright 2009 Sun Microsystems, Inc.  All rights reserved.
- * Use is subject to license terms.
+ * Copyright (c) 2009, 2010, Oracle and/or its affiliates. All rights reserved.
  */
 
 /*
@@ -36,6 +35,7 @@
 #include <stdlib.h>
 #include <netdb.h>
 #include <libadutils.h>
+#include <libuutil.h>
 #include <note.h>
 #include <assert.h>
 #include "directory.h"
@@ -43,7 +43,6 @@
 #include "idmapd.h"
 #include <rpcsvc/idmap_prot.h>
 #include "directory_server_impl.h"
-#include "miscutils.h"
 
 /*
  * Information required by the function that handles the callback from LDAP
@@ -85,7 +84,7 @@
 maybe_add_to_list(const char **list, const char *s)
 {
 	for (; *list != NULL; list++) {
-		if (strcaseeq(*list, s))
+		if (uu_strcaseeq(*list, s))
 			return;
 	}
 	*list = s;
@@ -117,7 +116,7 @@
 		 * Note that you must update MAX_EXTRA_ATTRS above if you
 		 * add to this list.
 		 */
-		if (strcaseeq(a, "x-sun-canonicalName")) {
+		if (uu_strcaseeq(a, "x-sun-canonicalName")) {
 			maybe_add_to_list(new_list, "sAMAccountName");
 			continue;
 		}
@@ -222,7 +221,7 @@
 
 			vw[0] = name;
 
-			if (streq(domain, "")) {
+			if (uu_streq(domain, "")) {
 				vw[1] = default_domain;
 			} else {
 				vw[1] = domain;
@@ -427,7 +426,7 @@
 			ldap_value_free_len(bv);
 			if (de != NULL)
 				goto err;
-		} else if (strcaseeq(a, "x-sun-canonicalName")) {
+		} else if (uu_strcaseeq(a, "x-sun-canonicalName")) {
 			bv = ldap_get_values_len(ld, msg, "sAMAccountName");
 			if (bv != NULL) {
 				int n = ldap_count_values_len(bv);
@@ -445,7 +444,7 @@
 						goto err;
 				}
 			}
-		} else if (strcaseeq(a, "x-sun-provider")) {
+		} else if (uu_strcaseeq(a, "x-sun-provider")) {
 			const char *provider = "LDAP-AD";
 			de = str_list_dav(val, &provider, 1);
 		}
@@ -492,7 +491,7 @@
 
 	for (i = 0; i < n; i++) {
 		dav[i].directory_value_rpc_val =
-		    memdup(bv[i]->bv_val, bv[i]->bv_len);
+		    uu_memdup(bv[i]->bv_val, bv[i]->bv_len);
 		if (dav[i].directory_value_rpc_val == NULL)
 			goto nomem;
 		dav[i].directory_value_rpc_len = bv[i]->bv_len;
--- a/usr/src/cmd/idmap/idmapd/directory_provider_builtin.c	Thu Jul 22 12:31:36 2010 -0700
+++ b/usr/src/cmd/idmap/idmapd/directory_provider_builtin.c	Thu Jul 22 14:53:56 2010 -0700
@@ -20,8 +20,7 @@
  */
 
 /*
- * Copyright 2010 Sun Microsystems, Inc.  All rights reserved.
- * Use is subject to license terms.
+ * Copyright (c) 2009, 2010, Oracle and/or its affiliates. All rights reserved.
  */
 
 /*
@@ -35,13 +34,13 @@
 #include <string.h>
 #include <stdlib.h>
 #include <netdb.h>
+#include <libuutil.h>
 #include <note.h>
 #include "idmapd.h"
 #include "directory.h"
 #include "directory_private.h"
 #include <rpcsvc/idmap_prot.h>
 #include "directory_server_impl.h"
-#include "miscutils.h"
 #include "sidutil.h"
 
 static directory_error_t sid_dav(directory_values_rpc *lvals,
@@ -91,7 +90,7 @@
 		 * End-to-end error injection point.
 		 * NEEDSWORK:  should probably eliminate this for production
 		 */
-		if (streq(id, " DEBUG BUILTIN ERROR ")) {
+		if (uu_streq(id, " DEBUG BUILTIN ERROR ")) {
 			directory_entry_set_error(&del[i],
 			    directory_error("Directory_provider_builtin.debug",
 			    "Directory_provider_builtin:  artificial error",
@@ -183,21 +182,22 @@
 		val->found = FALSE;
 		de = NULL;
 
-		if (strcaseeq(a, "uid")) {
+		if (uu_strcaseeq(a, "uid")) {
 			de = str_list_dav(val, &wksid->winname, 1);
-		} else if (strcaseeq(a, "uidNumber")) {
+		} else if (uu_strcaseeq(a, "uidNumber")) {
 			if (wksid->pid != IDMAP_SENTINEL_PID &&
 			    wksid->is_user) {
 				de = uint_list_dav(val, &wksid->pid, 1);
 			}
-		} else if (strcaseeq(a, "gidNumber")) {
+		} else if (uu_strcaseeq(a, "gidNumber")) {
 			if (wksid->pid != IDMAP_SENTINEL_PID &&
 			    !wksid->is_user) {
 				de = uint_list_dav(val, &wksid->pid, 1);
 			}
-		} else if (strcaseeq(a, "displayName") || strcaseeq(a, "cn")) {
+		} else if (uu_strcaseeq(a, "displayName") ||
+		    uu_strcaseeq(a, "cn")) {
 			de = str_list_dav(val, &wksid->winname, 1);
-		} else if (strcaseeq(a, "distinguishedName")) {
+		} else if (uu_strcaseeq(a, "distinguishedName")) {
 			char *container;
 			if (wksid->domain == NULL) {
 				container = "Users";
@@ -213,7 +213,7 @@
 			const char *cdn = dn;
 			de = str_list_dav(val, &cdn, 1);
 			free(dn);
-		} else if (strcaseeq(a, "objectClass")) {
+		} else if (uu_strcaseeq(a, "objectClass")) {
 			if (wksid->is_wuser) {
 				static const char *objectClasses[] = {
 					"top",
@@ -222,18 +222,18 @@
 					"user",
 				};
 				de = str_list_dav(val, objectClasses,
-				    NELEM(objectClasses));
+				    UU_NELEM(objectClasses));
 			} else {
 				static const char *objectClasses[] = {
 					"top",
 					"group",
 				};
 				de = str_list_dav(val, objectClasses,
-				    NELEM(objectClasses));
+				    UU_NELEM(objectClasses));
 			}
-		} else if (strcaseeq(a, "objectSid")) {
+		} else if (uu_strcaseeq(a, "objectSid")) {
 			de = sid_dav(val, wksid);
-		} else if (strcaseeq(a, "x-sun-canonicalName")) {
+		} else if (uu_strcaseeq(a, "x-sun-canonicalName")) {
 			char *canon;
 
 			if (wksid->domain == NULL) {
@@ -241,7 +241,7 @@
 				(void) asprintf(&canon, "%s@%s",
 				    wksid->winname, _idmapdstate.hostname);
 				UNLOCK_CONFIG();
-			} else if (streq(wksid->domain, "")) {
+			} else if (uu_streq(wksid->domain, "")) {
 				canon = strdup(wksid->winname);
 			} else {
 				(void) asprintf(&canon, "%s@%s",
@@ -253,7 +253,7 @@
 			const char *ccanon = canon;
 			de = str_list_dav(val, &ccanon, 1);
 			free(canon);
-		} else if (strcaseeq(a, "x-sun-provider")) {
+		} else if (uu_strcaseeq(a, "x-sun-provider")) {
 			const char *provider = "Builtin";
 			de = str_list_dav(val, &provider, 1);
 		}
--- a/usr/src/cmd/idmap/idmapd/directory_provider_nsswitch.c	Thu Jul 22 12:31:36 2010 -0700
+++ b/usr/src/cmd/idmap/idmapd/directory_provider_nsswitch.c	Thu Jul 22 14:53:56 2010 -0700
@@ -20,8 +20,7 @@
  */
 
 /*
- * Copyright 2009 Sun Microsystems, Inc.  All rights reserved.
- * Use is subject to license terms.
+ * Copyright (c) 2009, 2010, Oracle and/or its affiliates. All rights reserved.
  */
 
 /*
@@ -35,6 +34,7 @@
 #include <string.h>
 #include <stdlib.h>
 #include <netdb.h>
+#include <libuutil.h>
 #include <note.h>
 #include <errno.h>
 #include "idmapd.h"
@@ -42,7 +42,6 @@
 #include "directory_private.h"
 #include <rpcsvc/idmap_prot.h>
 #include "directory_server_impl.h"
-#include "miscutils.h"
 #include "sidutil.h"
 
 static directory_error_t machine_sid_dav(directory_values_rpc *lvals,
@@ -299,25 +298,25 @@
 			/*
 			 * Handle attributes for user entries.
 			 */
-			if (strcaseeq(a, "cn")) {
+			if (uu_strcaseeq(a, "cn")) {
 				const char *p = pwd->pw_name;
 				de = str_list_dav(val, &p, 1);
-			} else if (strcaseeq(a, "objectClass")) {
+			} else if (uu_strcaseeq(a, "objectClass")) {
 				static const char *objectClasses[] = {
 					"top",
 					"posixAccount",
 				};
 				de = str_list_dav(val, objectClasses,
-				    NELEM(objectClasses));
-			} else if (strcaseeq(a, "gidNumber")) {
+				    UU_NELEM(objectClasses));
+			} else if (uu_strcaseeq(a, "gidNumber")) {
 				de = uint_list_dav(val, &pwd->pw_gid, 1);
-			} else if (strcaseeq(a, "objectSid")) {
+			} else if (uu_strcaseeq(a, "objectSid")) {
 				de = machine_sid_dav(val,
 				    pwd->pw_uid + LOCALRID_UID_MIN);
-			} else if (strcaseeq(a, "displayName")) {
+			} else if (uu_strcaseeq(a, "displayName")) {
 				const char *p = pwd->pw_gecos;
 				de = str_list_dav(val, &p, 1);
-			} else if (strcaseeq(a, "distinguishedName")) {
+			} else if (uu_strcaseeq(a, "distinguishedName")) {
 				char *dn;
 				RDLOCK_CONFIG();
 				(void) asprintf(&dn,
@@ -329,21 +328,21 @@
 				const char *cdn = dn;
 				de = str_list_dav(val, &cdn, 1);
 				free(dn);
-			} else if (strcaseeq(a, "uid")) {
+			} else if (uu_strcaseeq(a, "uid")) {
 				const char *p = pwd->pw_name;
 				de = str_list_dav(val, &p, 1);
-			} else if (strcaseeq(a, "uidNumber")) {
+			} else if (uu_strcaseeq(a, "uidNumber")) {
 				de = uint_list_dav(val, &pwd->pw_uid, 1);
-			} else if (strcaseeq(a, "gecos")) {
+			} else if (uu_strcaseeq(a, "gecos")) {
 				const char *p = pwd->pw_gecos;
 				de = str_list_dav(val, &p, 1);
-			} else if (strcaseeq(a, "homeDirectory")) {
+			} else if (uu_strcaseeq(a, "homeDirectory")) {
 				const char *p = pwd->pw_dir;
 				de = str_list_dav(val, &p, 1);
-			} else if (strcaseeq(a, "loginShell")) {
+			} else if (uu_strcaseeq(a, "loginShell")) {
 				const char *p = pwd->pw_shell;
 				de = str_list_dav(val, &p, 1);
-			} else if (strcaseeq(a, "x-sun-canonicalName")) {
+			} else if (uu_strcaseeq(a, "x-sun-canonicalName")) {
 				char *canon;
 				RDLOCK_CONFIG();
 				(void) asprintf(&canon, "%s@%s",
@@ -354,7 +353,7 @@
 				const char *ccanon = canon;
 				de = str_list_dav(val, &ccanon, 1);
 				free(canon);
-			} else if (strcaseeq(a, "x-sun-provider")) {
+			} else if (uu_strcaseeq(a, "x-sun-provider")) {
 				const char *provider = "UNIX-passwd";
 				de = str_list_dav(val, &provider, 1);
 			}
@@ -362,25 +361,25 @@
 			/*
 			 * Handle attributes for group entries.
 			 */
-			if (strcaseeq(a, "cn")) {
+			if (uu_strcaseeq(a, "cn")) {
 				const char *p = grp->gr_name;
 				de = str_list_dav(val, &p, 1);
-			} else if (strcaseeq(a, "objectClass")) {
+			} else if (uu_strcaseeq(a, "objectClass")) {
 				static const char *objectClasses[] = {
 					"top",
 					"posixGroup",
 				};
 				de = str_list_dav(val, objectClasses,
-				    NELEM(objectClasses));
-			} else if (strcaseeq(a, "gidNumber")) {
+				    UU_NELEM(objectClasses));
+			} else if (uu_strcaseeq(a, "gidNumber")) {
 				de = uint_list_dav(val, &grp->gr_gid, 1);
-			} else if (strcaseeq(a, "objectSid")) {
+			} else if (uu_strcaseeq(a, "objectSid")) {
 				de = machine_sid_dav(val,
 				    grp->gr_gid + LOCALRID_GID_MIN);
-			} else if (strcaseeq(a, "displayName")) {
+			} else if (uu_strcaseeq(a, "displayName")) {
 				const char *p = grp->gr_name;
 				de = str_list_dav(val, &p, 1);
-			} else if (strcaseeq(a, "distinguishedName")) {
+			} else if (uu_strcaseeq(a, "distinguishedName")) {
 				char *dn;
 				RDLOCK_CONFIG();
 				(void) asprintf(&dn,
@@ -392,7 +391,7 @@
 				const char *cdn = dn;
 				de = str_list_dav(val, &cdn, 1);
 				free(dn);
-			} else if (strcaseeq(a, "memberUid")) {
+			} else if (uu_strcaseeq(a, "memberUid")) {
 				/*
 				 * NEEDSWORK:  There is probably a non-cast
 				 * way to do this, but I don't immediately
@@ -401,7 +400,7 @@
 				const char * const *members =
 				    (const char * const *)grp->gr_mem;
 				de = str_list_dav(val, members, 0);
-			} else if (strcaseeq(a, "x-sun-canonicalName")) {
+			} else if (uu_strcaseeq(a, "x-sun-canonicalName")) {
 				char *canon;
 				RDLOCK_CONFIG();
 				(void) asprintf(&canon, "%s@%s",
@@ -412,7 +411,7 @@
 				const char *ccanon = canon;
 				de = str_list_dav(val, &ccanon, 1);
 				free(canon);
-			} else if (strcaseeq(a, "x-sun-provider")) {
+			} else if (uu_strcaseeq(a, "x-sun-provider")) {
 				const char *provider = "UNIX-group";
 				de = str_list_dav(val, &provider, 1);
 			}
--- a/usr/src/cmd/idmap/idmapd/directory_server.c	Thu Jul 22 12:31:36 2010 -0700
+++ b/usr/src/cmd/idmap/idmapd/directory_server.c	Thu Jul 22 14:53:56 2010 -0700
@@ -20,8 +20,7 @@
  */
 
 /*
- * Copyright 2009 Sun Microsystems, Inc.  All rights reserved.
- * Use is subject to license terms.
+ * Copyright (c) 2009, 2010, Oracle and/or its affiliates. All rights reserved.
  */
 
 /*
@@ -37,6 +36,7 @@
 #include <pthread.h>
 #include <unistd.h>
 #include <string.h>
+#include <libuutil.h>
 #include <note.h>
 #include "idmapd.h"
 #include "directory.h"
@@ -45,7 +45,6 @@
 #include "directory_library_impl.h"
 #include "directory_server_impl.h"
 #include "sized_array.h"
-#include "miscutils.h"
 
 /*
  * Here's a list of all of the modules that provide directory
@@ -98,7 +97,7 @@
 		}
 	}
 
-	for (i = 0; i < NELEM(providers); i++) {
+	for (i = 0; i < UU_NELEM(providers); i++) {
 		de = providers[i]->get(entries, &ids, types,
 		    &attrs);
 		if (de != NULL)
@@ -176,7 +175,7 @@
 		int len;
 
 		len = strlen(str_list[i]);
-		dav[i].directory_value_rpc_val = memdup(str_list[i], len);
+		dav[i].directory_value_rpc_val = uu_memdup(str_list[i], len);
 		if (dav[i].directory_value_rpc_val == NULL)
 			goto nomem;
 		dav[i].directory_value_rpc_len = len;
@@ -224,7 +223,7 @@
 		(void) snprintf(buf, sizeof (buf), "%u", array[i]);
 
 		len = strlen(buf);
-		dav[i].directory_value_rpc_val = memdup(buf, len);
+		dav[i].directory_value_rpc_val = uu_memdup(buf, len);
 		if (dav[i].directory_value_rpc_val == NULL)
 			goto nomem;
 		dav[i].directory_value_rpc_len = len;
@@ -263,7 +262,7 @@
 	lvals->found = TRUE;
 
 	for (i = 0; i < n; i++) {
-		dav[i].directory_value_rpc_val = memdup(inbuf, sz);
+		dav[i].directory_value_rpc_val = uu_memdup(inbuf, sz);
 		if (dav[i].directory_value_rpc_val == NULL)
 			goto nomem;
 		dav[i].directory_value_rpc_len = sz;
--- a/usr/src/cmd/idmap/idmapd/server.c	Thu Jul 22 12:31:36 2010 -0700
+++ b/usr/src/cmd/idmap/idmapd/server.c	Thu Jul 22 14:53:56 2010 -0700
@@ -364,12 +364,6 @@
 				    "AD lookup - domain not found (ignored)");
 				continue;
 			}
-			if (res->retcode == IDMAP_SUCCESS)
-				TRACE(req, res, "Found in AD");
-			else if (res->retcode == IDMAP_ERR_NOTFOUND)
-				TRACE(req, res, "Not found in AD");
-			else
-				TRACE(req, res, "AD lookup error");
 		}
 	}
 
--- a/usr/src/cmd/idmap/idmapd/wksids.c	Thu Jul 22 12:31:36 2010 -0700
+++ b/usr/src/cmd/idmap/idmapd/wksids.c	Thu Jul 22 14:53:56 2010 -0700
@@ -30,8 +30,8 @@
 
 #include <assert.h>
 #include <string.h>
+#include <libuutil.h>
 #include "idmapd.h"
-#include "miscutils.h"
 
 /*
  * Table for well-known SIDs.
@@ -232,7 +232,7 @@
 	(void) strcpy(my_host_name, _idmapdstate.hostname);
 	UNLOCK_CONFIG();
 
-	for (i = 0; i < NELEM(wksids); i++) {
+	for (i = 0; i < UU_NELEM(wksids); i++) {
 		/* Check to see if this entry yields the desired type */
 		switch (type) {
 		case IDMAP_UID:
@@ -295,7 +295,7 @@
 	(void) strcpy(my_machine_sid, _idmapdstate.cfg->pgcfg.machine_sid);
 	UNLOCK_CONFIG();
 
-	for (i = 0; i < NELEM(wksids); i++) {
+	for (i = 0; i < UU_NELEM(wksids); i++) {
 		int sidcmp;
 
 		/* Check to see if this entry yields the desired type */
@@ -352,7 +352,7 @@
 	if (pid == IDMAP_SENTINEL_PID)
 		return (NULL);
 
-	for (i = 0; i < NELEM(wksids); i++) {
+	for (i = 0; i < UU_NELEM(wksids); i++) {
 		if (wksids[i].pid == pid &&
 		    wksids[i].is_user == is_user &&
 		    (wksids[i].direction == IDMAP_DIRECTION_BI ||
@@ -380,7 +380,7 @@
 	(void) strcpy(my_machine_sid, _idmapdstate.cfg->pgcfg.machine_sid);
 	UNLOCK_CONFIG();
 
-	for (i = 0; i < NELEM(wksids); i++) {
+	for (i = 0; i < UU_NELEM(wksids); i++) {
 		int len;
 		const char *prefix;
 		char *p;
--- a/usr/src/cmd/mdb/common/modules/smbsrv/smbsrv.c	Thu Jul 22 12:31:36 2010 -0700
+++ b/usr/src/cmd/mdb/common/modules/smbsrv/smbsrv.c	Thu Jul 22 14:53:56 2010 -0700
@@ -375,6 +375,8 @@
 static int smb_node_walk_init(mdb_walk_state_t *);
 static int smb_node_walk_step(mdb_walk_state_t *);
 static int smb_lock(uintptr_t, uint_t, int, const mdb_arg_t *);
+static int smb_oplock(uintptr_t, uint_t, int, const mdb_arg_t *);
+static int smb_oplock_grant(uintptr_t, uint_t, int, const mdb_arg_t *);
 static int smb_ace(uintptr_t, uint_t, int, const mdb_arg_t *);
 static int smb_ace_walk_init(mdb_walk_state_t *);
 static int smb_ace_walk_step(mdb_walk_state_t *);
@@ -443,8 +445,12 @@
 	    smb_dcmd_odir },
 	{   "smbofile",
 	    "[-v]",
-	    "print smb_odir_t information",
+	    "print smb_file_t information",
 	    smb_dcmd_ofile },
+	{   "smboplock", NULL,
+	    "print smb_oplock_t information", smb_oplock },
+	{   "smboplockgrant", NULL,
+	    "print smb_oplock_grant_t information", smb_oplock_grant },
 	{   "smbstat", NULL,
 	    "print all smb dispatched requests statistics",
 	    smb_stats },
@@ -799,7 +805,7 @@
 #define	SMB_REQUEST_BANNER	\
 	"%<b>%<u>%-?s %-?s %-14s %-14s %-16s %-32s%</u>%</b>\n"
 #define	SMB_REQUEST_FORMAT	\
-	"%-?p %-?p %e %e %-16s %s\n"
+	"%-?p %-?p %-14lld %-14lld %-16s %s\n"
 
 static int
 smb_dcmd_request(uintptr_t addr, uint_t flags, int argc, const mdb_arg_t *argv)
@@ -866,10 +872,12 @@
 			    "FID(file): %u (%p)\n"
 			    "PID: %u\n"
 			    "MID: %u\n\n"
-			    "waiting time: %1.3e\n"
-			    "running time: %1.3e",
-			    sr->first_smb_com, smb_com[sr->first_smb_com],
-			    sr->smb_com, smb_com[sr->smb_com],
+			    "waiting time: %lld\n"
+			    "running time: %lld\n",
+			    sr->first_smb_com,
+			    smb_com[sr->first_smb_com].smb_com,
+			    sr->smb_com,
+			    smb_com[sr->smb_com].smb_com,
 			    sr->sr_state, state,
 			    sr->smb_tid, sr->tid_tree,
 			    sr->smb_uid, sr->uid_user,
@@ -897,7 +905,7 @@
 			    waiting,
 			    running,
 			    state,
-			    smb_com[sr->smb_com]);
+			    smb_com[sr->smb_com].smb_com);
 		}
 	}
 	return (DCMD_OK);
@@ -1403,13 +1411,14 @@
 smb_node(uintptr_t addr, uint_t flags, int argc, const mdb_arg_t *argv)
 {
 	smb_node_t	node;
+	int		rc;
 	int		verbose = FALSE;
 	int		print_full_path = FALSE;
 	int		stack_trace = FALSE;
 	vnode_t		vnode;
 	char		od_name[MAXNAMELEN];
 	char		path_name[1024];
-	uintptr_t	list_addr;
+	uintptr_t	list_addr, oplock_addr;
 
 	if (mdb_getopts(argc, argv,
 	    'v', MDB_OPT_SETBITS, TRUE, &verbose,
@@ -1446,9 +1455,10 @@
 			    "%-18s "
 			    "%-6s "
 			    "%-6s "
+			    "%-8s "
 			    "%-6s%</u>%</b>\n",
 			    "ADDR", "VP", "NODE-NAME", "OFILES", "LOCKS",
-			    "REF");
+			    "OPLOCK", "REF");
 		}
 	}
 
@@ -1489,11 +1499,25 @@
 				}
 				(void) mdb_dec_indent(SMB_DCMD_INDENT);
 			}
+			if (node.n_oplock.ol_count == 0) {
+				mdb_printf("Opportunistic Locks: 0\n");
+			} else {
+				oplock_addr =
+				    addr + offsetof(smb_node_t, n_oplock);
+				mdb_printf("Opportunistic Lock: %p\n",
+				    oplock_addr);
+				rc = mdb_call_dcmd("smboplock", oplock_addr,
+				    flags, argc, argv);
+				if (rc != DCMD_OK)
+					return (rc);
+			}
 			mdb_printf("Reference Count: %u\n\n", node.n_refcnt);
 		} else {
-			mdb_printf("%-?p %-?p %-18s %-6d %-6d %-6d\n",
+			mdb_printf("%-?p %-?p %-18s %-6d %-6d %-8d %-6d ",
 			    addr, node.vp, od_name, node.n_ofile_list.ll_count,
-			    node.n_lock_list.ll_count, node.n_refcnt);
+			    node.n_lock_list.ll_count,
+			    node.n_oplock.ol_count, node.n_refcnt);
+
 			if (print_full_path)
 				mdb_printf("\t%s\n", path_name);
 		}
@@ -1713,6 +1737,99 @@
 }
 
 /*
+ * *****************************************************************************
+ * ************************** smb_oplock_grant_t *******************************
+ * *****************************************************************************
+ */
+/*ARGSUSED*/
+static int
+smb_oplock_grant(uintptr_t addr, uint_t flags, int argc, const mdb_arg_t *argv)
+{
+	smb_oplock_grant_t	grant;
+	char			 *level;
+
+	if (!(flags & DCMD_ADDRSPEC))
+		return (DCMD_USAGE);
+
+	/*
+	 * If this is the first invocation of the command, print a nice
+	 * header line for the output that will follow.
+	 */
+	if (DCMD_HDRSPEC(flags)) {
+		mdb_printf("%<u>%-16s %-10s %-16s%</u>\n",
+		    "Grants:", "LEVEL", "OFILE");
+	}
+
+	if (mdb_vread(&grant, sizeof (grant), addr) == sizeof (grant)) {
+		switch (grant.og_level) {
+		case SMB_OPLOCK_EXCLUSIVE:
+			level = "EXCLUSIVE";
+			break;
+		case SMB_OPLOCK_BATCH:
+			level = "BATCH";
+			break;
+		case SMB_OPLOCK_LEVEL_II:
+			level = "LEVEL_II";
+			break;
+		default:
+			level = "UNKNOWN";
+			break;
+		}
+
+		mdb_printf("%-16p %-10s %-16p", addr, level, grant.og_ofile);
+	}
+	return (DCMD_OK);
+}
+
+/*
+ * *****************************************************************************
+ * ***************************** smb_oplock_t **********************************
+ * *****************************************************************************
+ */
+/*ARGSUSED*/
+static int
+smb_oplock(uintptr_t addr, uint_t flags, int argc, const mdb_arg_t *argv)
+{
+	smb_oplock_t	oplock;
+	uintptr_t	list_addr;
+
+	if (!(flags & DCMD_ADDRSPEC))
+		return (DCMD_USAGE);
+
+	if (mdb_vread(&oplock, sizeof (oplock), addr) != sizeof (oplock)) {
+		mdb_warn("failed to read struct smb_oplock at %p", addr);
+		return (DCMD_ERR);
+	}
+
+	if (oplock.ol_count == 0)
+		return (DCMD_OK);
+
+	(void) mdb_inc_indent(SMB_DCMD_INDENT);
+	switch (oplock.ol_break) {
+	case SMB_OPLOCK_BREAK_TO_NONE:
+		mdb_printf("Break Pending: BREAK_TO_NONE\n");
+		break;
+	case SMB_OPLOCK_BREAK_TO_LEVEL_II:
+		mdb_printf(
+		    "Break Pending: BREAK_TO_LEVEL_II\n");
+		break;
+	default:
+		break;
+	}
+
+	list_addr = addr + offsetof(smb_oplock_t, ol_grants);
+
+	if (mdb_pwalk_dcmd("list", "smboplockgrant",
+	    argc, argv, list_addr)) {
+		mdb_warn("failed to walk oplock grants");
+	}
+
+	(void) mdb_dec_indent(SMB_DCMD_INDENT);
+
+	return (DCMD_OK);
+}
+
+/*
  * ::smbstat
  *
  * Prints SMB requests statistics.
--- a/usr/src/cmd/smbsrv/dtrace/msrpc.d	Thu Jul 22 12:31:36 2010 -0700
+++ b/usr/src/cmd/smbsrv/dtrace/msrpc.d	Thu Jul 22 14:53:56 2010 -0700
@@ -262,7 +262,7 @@
 /*
  * SAMR
  */
-pid$target::samr_s_ConnectAnon:entry,
+pid$target::samr_s_Connect:entry,
 pid$target::samr_s_CloseHandle:entry,
 pid$target::samr_s_LookupDomain:entry,
 pid$target::samr_s_EnumLocalDomains:entry,
@@ -275,14 +275,14 @@
 pid$target::samr_s_QueryUserInfo:entry,
 pid$target::samr_s_QueryUserGroups:entry,
 pid$target::samr_s_OpenGroup:entry,
-pid$target::samr_s_Connect:entry,
+pid$target::samr_s_Connect2:entry,
 pid$target::samr_s_GetUserPwInfo:entry,
 pid$target::samr_s_CreateUser:entry,
 pid$target::samr_s_ChangeUserPasswd:entry,
 pid$target::samr_s_GetDomainPwInfo:entry,
 pid$target::samr_s_SetUserInfo:entry,
-pid$target::samr_s_Connect3:entry,
 pid$target::samr_s_Connect4:entry,
+pid$target::samr_s_Connect5:entry,
 pid$target::samr_s_QueryDispInfo:entry,
 pid$target::samr_s_OpenAlias:entry,
 pid$target::samr_s_CreateDomainAlias:entry,
@@ -294,7 +294,7 @@
 {
 }
 
-pid$target::samr_s_ConnectAnon:return,
+pid$target::samr_s_Connect:return,
 pid$target::samr_s_CloseHandle:return,
 pid$target::samr_s_LookupDomain:return,
 pid$target::samr_s_EnumLocalDomains:return,
@@ -307,14 +307,14 @@
 pid$target::samr_s_QueryUserInfo:return,
 pid$target::samr_s_QueryUserGroups:return,
 pid$target::samr_s_OpenGroup:return,
-pid$target::samr_s_Connect:return,
+pid$target::samr_s_Connect2:return,
 pid$target::samr_s_GetUserPwInfo:return,
 pid$target::samr_s_CreateUser:return,
 pid$target::samr_s_ChangeUserPasswd:return,
 pid$target::samr_s_GetDomainPwInfo:return,
 pid$target::samr_s_SetUserInfo:return,
-pid$target::samr_s_Connect3:return,
 pid$target::samr_s_Connect4:return,
+pid$target::samr_s_Connect5:return,
 pid$target::samr_s_QueryDispInfo:return,
 pid$target::samr_s_OpenAlias:return,
 pid$target::samr_s_CreateDomainAlias:return,
--- a/usr/src/cmd/smbsrv/smbd/smbd_main.c	Thu Jul 22 12:31:36 2010 -0700
+++ b/usr/src/cmd/smbsrv/smbd/smbd_main.c	Thu Jul 22 14:53:56 2010 -0700
@@ -48,6 +48,7 @@
 #include <libgen.h>
 #include <pwd.h>
 #include <grp.h>
+#include <cups/cups.h>
 
 #include <smbsrv/smb_door.h>
 #include <smbsrv/smb_ioctl.h>
@@ -57,8 +58,10 @@
 #include <smbsrv/libmlsvc.h>
 #include "smbd.h"
 
+#define	SMB_CUPS_DOCNAME "generic_doc"
 #define	DRV_DEVICE_PATH	"/devices/pseudo/smbsrv@0:smbsrv"
 #define	SMB_DBDIR "/var/smb"
+#define	SMB_SPOOL_WAIT 2
 
 static void *smbd_nbt_listener(void *);
 static void *smbd_tcp_listener(void *);
@@ -88,6 +91,10 @@
 
 static pthread_t localtime_thr;
 
+static int smbd_spool_init(void);
+static void *smbd_spool_monitor(void *arg);
+static pthread_t smbd_spool_thr;
+
 static int smbd_refresh_init(void);
 static void smbd_refresh_fini(void);
 static void *smbd_refresh_monitor(void *);
@@ -134,6 +141,8 @@
 	uid_t			uid;
 	int			pfd = -1;
 	uint_t			sigval;
+	struct rlimit		rl;
+	int			orig_limit;
 
 	smbd.s_pname = basename(argv[0]);
 	openlog(smbd.s_pname, LOG_PID | LOG_NOWAIT, LOG_DAEMON);
@@ -159,6 +168,19 @@
 	if (smbd_already_running())
 		return (SMF_EXIT_OK);
 
+	/*
+	 * Raise the file descriptor limit to accommodate simultaneous user
+	 * authentications/file access.
+	 */
+	if ((getrlimit(RLIMIT_NOFILE, &rl) == 0) &&
+	    (rl.rlim_cur < rl.rlim_max)) {
+		orig_limit = rl.rlim_cur;
+		rl.rlim_cur = rl.rlim_max;
+		if (setrlimit(RLIMIT_NOFILE, &rl) != 0)
+			smbd_report("Failed to raise file descriptor limit"
+			    " from %d to %d", orig_limit, rl.rlim_cur);
+	}
+
 	(void) sigfillset(&set);
 	(void) sigdelset(&set, SIGABRT);
 
@@ -545,6 +567,13 @@
 		return (-1);
 	}
 
+	if (smbd_spool_init() != 0) {
+		smbd_report("failed to start print monitor: %s",
+		    strerror(errno));
+		(void) mutex_unlock(&smbd_service_mutex);
+		return (-1);
+	}
+
 	smbd.s_initialized = B_TRUE;
 	smbd_report("service initialized");
 	(void) cond_signal(&smbd_service_cv);
@@ -870,6 +899,63 @@
 }
 
 /*
+ * Initialization of the spool thread.
+ * Returns 0 on success, an error number if thread creation fails.
+ */
+
+static int
+smbd_spool_init(void)
+{
+	pthread_attr_t tattr;
+	int rc;
+
+	(void) pthread_attr_init(&tattr);
+	(void) pthread_attr_setdetachstate(&tattr, PTHREAD_CREATE_DETACHED);
+	rc = pthread_create(&smbd_spool_thr, &tattr, smbd_spool_monitor, 0);
+	(void) pthread_attr_destroy(&tattr);
+
+	return (rc);
+}
+
+/*
+ * This user thread blocks waiting for close print file
+ * in the kernel. It then uses the data returned from the ioctl
+ * to copy the spool file into the cups spooler.
+ * This function is really only used by Vista and Win7 clients,
+ * other versions of windows create only a zero size file and this
+ * be removed by spoolss_copy_spool_file function.
+ */
+
+/*ARGSUSED*/
+static void *
+smbd_spool_monitor(void *arg)
+{
+	uint32_t spool_num;
+	char username[MAXNAMELEN];
+	char path[MAXPATHLEN];
+	smb_inaddr_t ipaddr;
+	int error_retry_cnt = 5;
+
+	while (!smbd.s_shutting_down && (error_retry_cnt > 0)) {
+		errno = 0;
+
+		if (smb_kmod_get_spool_doc(&spool_num, username,
+		    path, &ipaddr) == 0) {
+			spoolss_copy_spool_file(&ipaddr,
+			    username, path, SMB_CUPS_DOCNAME);
+			error_retry_cnt = 5;
+		} else {
+			if (errno == ECANCELED)
+				break;
+
+			(void) sleep(SMB_SPOOL_WAIT);
+			error_retry_cnt--;
+		}
+	}
+	return (NULL);
+}
+
+/*
  * Initialization of the localtime thread.
  * Returns 0 on success, an error number if thread creation fails.
  */
--- a/usr/src/lib/Makefile	Thu Jul 22 12:31:36 2010 -0700
+++ b/usr/src/lib/Makefile	Thu Jul 22 14:53:56 2010 -0700
@@ -589,7 +589,7 @@
 libefi:		libuuid
 libfstyp:	libnvpair
 libelfsign:	libcryptoutil libkmf
-libidmap:	libadutils libldap5 libavl libsldap
+libidmap:	libadutils libldap5 libavl libsldap libuutil
 libipadm:	libnsl libinetutil libsocket libdlpi libnvpair libdhcpagent \
 		libdladm libsecdb
 libiscsit:	libc libnvpair libstmf libuuid libnsl
--- a/usr/src/lib/libidmap/Makefile.com	Thu Jul 22 12:31:36 2010 -0700
+++ b/usr/src/lib/libidmap/Makefile.com	Thu Jul 22 14:53:56 2010 -0700
@@ -34,7 +34,6 @@
 	sized_array.o		\
 	idmap_api.o		\
 	idmap_cache.o		\
-	miscutils.o		\
 	utils.o
 
 OBJECTS = $(LINT_OBJECTS)	\
@@ -44,7 +43,7 @@
 C99MODE = $(C99_ENABLE)
 
 LIBS =		$(DYNLIB) $(LINTLIB)
-LDLIBS +=	-lc -lavl -lnsl -lnvpair
+LDLIBS +=	-lc -lavl -lnsl -lnvpair -luutil
 
 SRCDIR =	../common
 $(LINTLIB):=	SRCS = $(SRCDIR)/$(LINTSRC)
--- a/usr/src/lib/libidmap/common/directory_helper.c	Thu Jul 22 12:31:36 2010 -0700
+++ b/usr/src/lib/libidmap/common/directory_helper.c	Thu Jul 22 14:53:56 2010 -0700
@@ -33,11 +33,11 @@
 
 #include <stdio.h>
 #include <string.h>
+#include <libuutil.h>
 #include <rpcsvc/idmap_prot.h>
 #include "directory.h"
 #include "directory_private.h"
 #include "directory_library_impl.h"
-#include "miscutils.h"
 #include "sidutil.h"
 
 /*
@@ -275,7 +275,7 @@
 is_in_list(char **list, char *val)
 {
 	for (; *list != NULL; list++) {
-		if (strcaseeq(*list, val))
+		if (uu_strcaseeq(*list, val))
 			return (B_TRUE);
 	}
 	return (B_FALSE);
@@ -287,12 +287,12 @@
 	uint64_t ret = 0;
 
 	for (; *objectClass != NULL; objectClass++) {
-		if (strcaseeq(*objectClass, "user") ||
-		    strcaseeq(*objectClass, "posixAccount"))
+		if (uu_strcaseeq(*objectClass, "user") ||
+		    uu_strcaseeq(*objectClass, "posixAccount"))
 			ret |= DIRECTORY_CLASS_USER;
 
-		if (strcaseeq(*objectClass, "group") ||
-		    strcaseeq(*objectClass, "posixGroup"))
+		if (uu_strcaseeq(*objectClass, "group") ||
+		    uu_strcaseeq(*objectClass, "posixGroup"))
 			ret |= DIRECTORY_CLASS_GROUP;
 	}
 
--- a/usr/src/lib/libidmap/common/directory_library_impl.h	Thu Jul 22 12:31:36 2010 -0700
+++ b/usr/src/lib/libidmap/common/directory_library_impl.h	Thu Jul 22 14:53:56 2010 -0700
@@ -20,8 +20,7 @@
  */
 
 /*
- * Copyright 2009 Sun Microsystems, Inc.  All rights reserved.
- * Use is subject to license terms.
+ * Copyright (c) 2009, 2010, Oracle and/or its affiliates. All rights reserved.
  */
 
 #ifndef _DIRECTORY_LIBRARY_IMPL_H
@@ -31,6 +30,8 @@
  * Internal implementation of the client side of directory lookup.
  */
 
+#include <rpcsvc/idmap_prot.h>
+
 #ifdef __cplusplus
 extern "C" {
 #endif
--- a/usr/src/lib/libidmap/common/llib-lidmap	Thu Jul 22 12:31:36 2010 -0700
+++ b/usr/src/lib/libidmap/common/llib-lidmap	Thu Jul 22 14:53:56 2010 -0700
@@ -19,15 +19,14 @@
  * CDDL HEADER END
  */
 /*
- * Copyright 2009 Sun Microsystems, Inc.  All rights reserved.
- * Use is subject to license terms.
+ * Copyright (c) 2007, 2010, Oracle and/or its affiliates. All rights reserved.
  */
 
 /* LINTLIBRARY */
 /* PROTOLIB1 */
 
-#include "idmap_impl.h"
-#include "miscutils.h"
+#include "idmap.h"
+#include "idmap_priv.h"
 #include "directory.h"
 #include "directory_private.h"
 #include "sized_array.h"
--- a/usr/src/lib/libidmap/common/mapfile-vers	Thu Jul 22 12:31:36 2010 -0700
+++ b/usr/src/lib/libidmap/common/mapfile-vers	Thu Jul 22 14:53:56 2010 -0700
@@ -60,7 +60,6 @@
 	directory_sid_from_group_name;
 	directory_sid_from_name;
 	directory_sid_from_user_name;
-	idmap_cache_get_data;
 	idmap_fini;
 	idmap_flush;
 	idmap_free;
@@ -110,7 +109,6 @@
 	idmap_udt_get_error_index;
 	idmap_udt_get_error_rule;
 	idmap_udt_rm_namerule;
-	memdup;
 	sid_free;
 	sid_from_le;
 	sid_fromstr;
@@ -120,9 +118,6 @@
 	sized_array;
 	sized_array_free;
 	sized_array_n;
-	strcaseeq;
-	streq;
-	strndup;
 	xdr_directory_entry_rpc;
 	xdr_directory_get_common_1_argument;
 	xdr_directory_results_rpc;
--- a/usr/src/lib/libidmap/common/miscutils.c	Thu Jul 22 12:31:36 2010 -0700
+++ /dev/null	Thu Jan 01 00:00:00 1970 +0000
@@ -1,124 +0,0 @@
-/*
- * CDDL HEADER START
- *
- * The contents of this file are subject to the terms of the
- * Common Development and Distribution License (the "License").
- * You may not use this file except in compliance with the License.
- *
- * You can obtain a copy of the license at usr/src/OPENSOLARIS.LICENSE
- * or http://www.opensolaris.org/os/licensing.
- * See the License for the specific language governing permissions
- * and limitations under the License.
- *
- * When distributing Covered Code, include this CDDL HEADER in each
- * file and include the License file at usr/src/OPENSOLARIS.LICENSE.
- * If applicable, add the following below this CDDL HEADER, with the
- * fields enclosed by brackets "[]" replaced with your own identifying
- * information: Portions Copyright [yyyy] [name of copyright owner]
- *
- * CDDL HEADER END
- */
-
-/*
- * Copyright 2009 Sun Microsystems, Inc.  All rights reserved.
- * Use is subject to license terms.
- */
-
-/*
- * Miscellaneous utility functions not specifically related to
- * the application.
- */
-
-#include <string.h>
-#include <sys/types.h>
-#include <stdarg.h>
-#include <stdio.h>
-#include <malloc.h>
-#include <ctype.h>
-#include "miscutils.h"
-
-/* Return true if strings are equal */
-boolean_t
-streq(const char *a, const char *b)
-{
-	return (strcmp(a, b) == 0);
-}
-
-/* Return true if strings are equal, case-insensitively */
-boolean_t
-strcaseeq(const char *a, const char *b)
-{
-	return (strcasecmp(a, b) == 0);
-}
-
-/* Return true if string a Begins With string b */
-boolean_t
-strbw(const char *a, const char *b)
-{
-	return (strncmp(a, b, strlen(b)) == 0);
-}
-
-/*
- * Duplicate up to n bytes of a string.  Kind of sort of like
- * strdup(strlcpy(s, n)).
- */
-char *
-strndup(const char *s, int n)
-{
-	int len;
-	char *p;
-
-	len = strnlen(s, n);
-	p = malloc(len + 1);
-	if (p == NULL)
-		return (NULL);
-
-	if (len > 0)
-		(void) memcpy(p, s, len);
-	p[len] = '\0';
-
-	return (p);
-}
-
-/*
- * Duplicate a block of memory.  Combines malloc with memcpy, much as
- * strdup combines malloc, strlen, and strcpy.
- */
-void *
-memdup(const void *buf, size_t sz)
-{
-	void *p;
-
-	p = malloc(sz);
-	if (p == NULL)
-		return (NULL);
-	(void) memcpy(p, buf, sz);
-	return (p);
-}
-
-/*
- * Dump a block of memory in hex+ascii, for debugging
- */
-void
-dump(FILE *out, const char *prefix, const void *buf, size_t len)
-{
-	const unsigned char *p = buf;
-	int i;
-
-	for (i = 0; i < len; i += 16) {
-		int j;
-
-		(void) fprintf(out, "%s", prefix);
-		for (j = 0; j < 16 && i + j < len; j++) {
-			(void) fprintf(out, "%2.2x ", p[i + j]);
-		}
-		for (; j < 16; j++) {
-			(void) fprintf(out, "   ");
-		}
-		for (j = 0; j < 16 && i + j < len; j++) {
-			(void) fprintf(out, "%c",
-			    isprint(p[i + j]) ? p[i + j] : '.');
-		}
-		(void) fprintf(out, "\n");
-	}
-}
--- a/usr/src/lib/libidmap/common/miscutils.h	Thu Jul 22 12:31:36 2010 -0700
+++ /dev/null	Thu Jan 01 00:00:00 1970 +0000
@@ -1,51 +0,0 @@
-/*
- * CDDL HEADER START
- *
- * The contents of this file are subject to the terms of the
- * Common Development and Distribution License (the "License").
- * You may not use this file except in compliance with the License.
- *
- * You can obtain a copy of the license at usr/src/OPENSOLARIS.LICENSE
- * or http://www.opensolaris.org/os/licensing.
- * See the License for the specific language governing permissions
- * and limitations under the License.
- *
- * When distributing Covered Code, include this CDDL HEADER in each
- * file and include the License file at usr/src/OPENSOLARIS.LICENSE.
- * If applicable, add the following below this CDDL HEADER, with the
- * fields enclosed by brackets "[]" replaced with your own identifying
- * information: Portions Copyright [yyyy] [name of copyright owner]
- *
- * CDDL HEADER END
- */
-
-/*
- * Copyright 2009 Sun Microsystems, Inc.  All rights reserved.
- * Use is subject to license terms.
- */
-
-#ifndef _MISCUTILS_H
-#define	_MISCUTILS_H
-
-/*
- * Miscellaneous functions and macros not directly related to the application.
- */
-
-#ifdef __cplusplus
-extern "C" {
-#endif
-
-#define	NELEM(a)	(sizeof (a) / sizeof ((a)[0]))
-
-boolean_t strcaseeq(const char *a, const char *b);
-boolean_t streq(const char *a, const char *b);
-char *strndup(const char *s, int n);
-boolean_t strbw(const char *a, const char *b);
-void *memdup(const void *buf, size_t sz);
-void dump(FILE *out, const char *prefix, const void *buf, size_t len);
-
-#ifdef __cplusplus
-}
-#endif
-
-#endif /* _MISCUTILS_H */
--- a/usr/src/lib/libshare/smb/libshare_smb.c	Thu Jul 22 12:31:36 2010 -0700
+++ b/usr/src/lib/libshare/smb/libshare_smb.c	Thu Jul 22 14:53:56 2010 -0700
@@ -912,6 +912,8 @@
 	{ SMB_CI_AUTOHOME_MAP, 0, MAX_VALUE_BUFLEN, path_validator, 0 },
 	{ SMB_CI_IPV6_ENABLE, 0, 0, true_false_validator,
 	    SMB_REFRESH_REFRESH },
+	{ SMB_CI_PRINT_ENABLE, 0, 0, true_false_validator,
+	    SMB_REFRESH_REFRESH },
 	{ SMB_CI_MAP, 0, MAX_VALUE_BUFLEN, cmd_validator, SMB_REFRESH_REFRESH },
 	{ SMB_CI_UNMAP, 0, MAX_VALUE_BUFLEN, cmd_validator,
 	    SMB_REFRESH_REFRESH },
--- a/usr/src/lib/libuutil/Makefile.com	Thu Jul 22 12:31:36 2010 -0700
+++ b/usr/src/lib/libuutil/Makefile.com	Thu Jul 22 14:53:56 2010 -0700
@@ -19,10 +19,7 @@
 # CDDL HEADER END
 #
 #
-# Copyright 2008 Sun Microsystems, Inc.  All rights reserved.
-# Use is subject to license terms.
-#
-# ident	"%Z%%M%	%I%	%E% SMI"
+# Copyright (c) 2004, 2010, Oracle and/or its affiliates. All rights reserved.
 #
 
 LIBRARY =	libuutil.a
@@ -38,6 +35,7 @@
 	uu_misc.o \
 	uu_open.o \
 	uu_pname.o \
+	uu_string.o \
 	uu_strtoint.o
 
 include ../../Makefile.lib
--- a/usr/src/lib/libuutil/common/libuutil.h	Thu Jul 22 12:31:36 2010 -0700
+++ b/usr/src/lib/libuutil/common/libuutil.h	Thu Jul 22 14:53:56 2010 -0700
@@ -19,8 +19,7 @@
  * CDDL HEADER END
  */
 /*
- * Copyright 2008 Sun Microsystems, Inc.  All rights reserved.
- * Use is subject to license terms.
+ * Copyright (c) 2004, 2010, Oracle and/or its affiliates. All rights reserved.
  */
 
 #ifndef	_LIBUUTIL_H
@@ -28,6 +27,7 @@
 
 #include <sys/types.h>
 #include <stdarg.h>
+#include <stdio.h>
 
 #ifdef	__cplusplus
 extern "C" {
@@ -142,12 +142,21 @@
 /*
  * Convenience functions.
  */
+#define	UU_NELEM(a)	(sizeof (a) / sizeof ((a)[0]))
+
 /*PRINTFLIKE1*/
 extern char *uu_msprintf(const char *format, ...);
 extern void *uu_zalloc(size_t);
 extern char *uu_strdup(const char *);
 extern void uu_free(void *);
 
+extern boolean_t uu_strcaseeq(const char *a, const char *b);
+extern boolean_t uu_streq(const char *a, const char *b);
+extern char *uu_strndup(const char *s, size_t n);
+extern boolean_t uu_strbw(const char *a, const char *b);
+extern void *uu_memdup(const void *buf, size_t sz);
+extern void uu_dump(FILE *out, const char *prefix, const void *buf, size_t len);
+
 /*
  * Comparison function type definition.
  *   Developers should be careful in their use of the _private argument. If you
--- a/usr/src/lib/libuutil/common/mapfile-vers	Thu Jul 22 12:31:36 2010 -0700
+++ b/usr/src/lib/libuutil/common/mapfile-vers	Thu Jul 22 14:53:56 2010 -0700
@@ -68,6 +68,7 @@
 	uu_dprintf_create;
 	uu_dprintf_destroy;
 	uu_dprintf_getname;
+	uu_dump;
 	uu_error;
 	uu_exit_fatal;
 	uu_exit_ok;
@@ -97,11 +98,16 @@
 	uu_list_walk_end;
 	uu_list_walk_next;
 	uu_list_walk_start;
+	uu_memdup;
 	uu_msprintf;
 	uu_open_tmp;
 	uu_setpname;
+	uu_strbw;
+	uu_strcaseeq;
 	uu_strdup;
+	uu_streq;
 	uu_strerror;
+	uu_strndup;
 	uu_strtoint;
 	uu_strtouint;
 	uu_vdie;
--- a/usr/src/lib/libuutil/common/uu_alloc.c	Thu Jul 22 12:31:36 2010 -0700
+++ b/usr/src/lib/libuutil/common/uu_alloc.c	Thu Jul 22 14:53:56 2010 -0700
@@ -19,8 +19,7 @@
  * CDDL HEADER END
  */
 /*
- * Copyright 2008 Sun Microsystems, Inc.  All rights reserved.
- * Use is subject to license terms.
+ * Copyright (c) 2004, 2010, Oracle and/or its affiliates. All rights reserved.
  */
 
 #include "libuutil_common.h"
@@ -67,6 +66,44 @@
 	return (buf);
 }
 
+/*
+ * Duplicate up to n bytes of a string.  Kind of sort of like
+ * strdup(strlcpy(s, n)).
+ */
+char *
+uu_strndup(const char *s, size_t n)
+{
+	size_t len;
+	char *p;
+
+	len = strnlen(s, n);
+	p = uu_zalloc(len + 1);
+	if (p == NULL)
+		return (NULL);
+
+	if (len > 0)
+		(void) memcpy(p, s, len);
+	p[len] = '\0';
+
+	return (p);
+}
+
+/*
+ * Duplicate a block of memory.  Combines malloc with memcpy, much as
+ * strdup combines malloc, strlen, and strcpy.
+ */
+void *
+uu_memdup(const void *buf, size_t sz)
+{
+	void *p;
+
+	p = uu_zalloc(sz);
+	if (p == NULL)
+		return (NULL);
+	(void) memcpy(p, buf, sz);
+	return (p);
+}
+
 char *
 uu_msprintf(const char *format, ...)
 {
--- a/usr/src/lib/libuutil/common/uu_misc.c	Thu Jul 22 12:31:36 2010 -0700
+++ b/usr/src/lib/libuutil/common/uu_misc.c	Thu Jul 22 14:53:56 2010 -0700
@@ -20,12 +20,9 @@
  */
 
 /*
- * Copyright 2007 Sun Microsystems, Inc.  All rights reserved.
- * Use is subject to license terms.
+ * Copyright (c) 2004, 2010, Oracle and/or its affiliates. All rights reserved.
  */
 
-#pragma ident	"%Z%%M%	%I%	%E% SMI"
-
 #include "libuutil_common.h"
 
 #include <assert.h>
@@ -39,6 +36,7 @@
 #include <sys/debug.h>
 #include <thread.h>
 #include <unistd.h>
+#include <ctype.h>
 
 #if !defined(TEXT_DOMAIN)
 #define	TEXT_DOMAIN "SYS_TEST"
@@ -253,3 +251,30 @@
 {
 	(void) pthread_atfork(uu_lockup, uu_release, uu_release_child);
 }
+
+/*
+ * Dump a block of memory in hex+ascii, for debugging
+ */
+void
+uu_dump(FILE *out, const char *prefix, const void *buf, size_t len)
+{
+	const unsigned char *p = buf;
+	int i;
+
+	for (i = 0; i < len; i += 16) {
+		int j;
+
+		(void) fprintf(out, "%s", prefix);
+		for (j = 0; j < 16 && i + j < len; j++) {
+			(void) fprintf(out, "%2.2x ", p[i + j]);
+		}
+		for (; j < 16; j++) {
+			(void) fprintf(out, "   ");
+		}
+		for (j = 0; j < 16 && i + j < len; j++) {
+			(void) fprintf(out, "%c",
+			    isprint(p[i + j]) ? p[i + j] : '.');
+		}
+		(void) fprintf(out, "\n");
+	}
+}
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/usr/src/lib/libuutil/common/uu_string.c	Thu Jul 22 14:53:56 2010 -0700
@@ -0,0 +1,56 @@
+/*
+ * CDDL HEADER START
+ *
+ * The contents of this file are subject to the terms of the
+ * Common Development and Distribution License (the "License").
+ * You may not use this file except in compliance with the License.
+ *
+ * You can obtain a copy of the license at usr/src/OPENSOLARIS.LICENSE
+ * or http://www.opensolaris.org/os/licensing.
+ * See the License for the specific language governing permissions
+ * and limitations under the License.
+ *
+ * When distributing Covered Code, include this CDDL HEADER in each
+ * file and include the License file at usr/src/OPENSOLARIS.LICENSE.
+ * If applicable, add the following below this CDDL HEADER, with the
+ * fields enclosed by brackets "[]" replaced with your own identifying
+ * information: Portions Copyright [yyyy] [name of copyright owner]
+ *
+ * CDDL HEADER END
+ */
+
+/*
+ * Copyright (c) 2009, 2010, Oracle and/or its affiliates. All rights reserved.
+ */
+
+/*
+ * String helper functions
+ */
+
+#include <string.h>
+#include <sys/types.h>
+#include <stdio.h>
+#include <malloc.h>
+#include <ctype.h>
+#include "libuutil.h"
+
+/* Return true if strings are equal */
+boolean_t
+uu_streq(const char *a, const char *b)
+{
+	return (strcmp(a, b) == 0);
+}
+
+/* Return true if strings are equal, case-insensitively */
+boolean_t
+uu_strcaseeq(const char *a, const char *b)
+{
+	return (strcasecmp(a, b) == 0);
+}
+
+/* Return true if string a Begins With string b */
+boolean_t
+uu_strbw(const char *a, const char *b)
+{
+	return (strncmp(a, b, strlen(b)) == 0);
+}
--- a/usr/src/lib/smbsrv/libmlrpc/common/ndr_server.c	Thu Jul 22 12:31:36 2010 -0700
+++ b/usr/src/lib/smbsrv/libmlrpc/common/ndr_server.c	Thu Jul 22 14:53:56 2010 -0700
@@ -19,8 +19,7 @@
  * CDDL HEADER END
  */
 /*
- * Copyright 2010 Sun Microsystems, Inc.  All rights reserved.
- * Use is subject to license terms.
+ * Copyright (c) 2007, 2010, Oracle and/or its affiliates. All rights reserved.
  */
 
 /*
@@ -405,6 +404,7 @@
 	}
 
 	np->np_buf = newbuf;
+	np->np_iov.iov_base = np->np_buf + np->np_uio.uio_offset;
 	np->np_uio.uio_resid += desired;
 	np->np_iov.iov_len += desired;
 	smb_tracef("ndr_pipe_grow: %d bytes", required);
--- a/usr/src/lib/smbsrv/libmlsvc/common/dfs.c	Thu Jul 22 12:31:36 2010 -0700
+++ b/usr/src/lib/smbsrv/libmlsvc/common/dfs.c	Thu Jul 22 14:53:56 2010 -0700
@@ -75,6 +75,14 @@
 static char dfs_nbname[NETBIOS_NAME_SZ];
 
 /*
+ * The name of cached namespace. This will be the only
+ * exported namespace until hosting multiple namespaces
+ * is supported
+ */
+static char dfs_cached_ns[MAXNAMELEN];
+static mutex_t dfs_nsmtx;
+
+/*
  * Lock for accessing root information (extended attribute)
  */
 static rwlock_t dfs_root_rwl;
@@ -86,6 +94,7 @@
  */
 static boolean_t dfs_namespace_findlink(const char *, char *, char *, size_t);
 static void *dfs_namespace_cache(void *);
+static boolean_t dfs_namespace_iscached(const char *);
 
 /*
  * Root functions
@@ -124,6 +133,8 @@
 static uint32_t dfs_cache_add_byunc(const char *, const char *, uint32_t);
 static void dfs_cache_populate(const char *, const char *);
 static int dfs_cache_cmp(const void *, const void *);
+static void dfs_cache_flush(const char *);
+static uint32_t dfs_cache_nscount(void);
 
 /*
  * Utility functions
@@ -234,7 +245,7 @@
 void /*ARGSUSED*/
 dfs_namespace_unload(const char *name)
 {
-	smb_cache_flush(&dfs_nscache);
+	dfs_cache_flush(name);
 }
 
 /*
@@ -254,6 +265,9 @@
 	if ((si.shr_flags & SMB_SHRF_DFSROOT) == 0)
 		return (ERROR_NOT_FOUND);
 
+	if (!dfs_namespace_iscached(name))
+		return (ERROR_NOT_FOUND);
+
 	if (path != NULL)
 		(void) strlcpy(path, si.shr_path, pathsz);
 
@@ -267,8 +281,6 @@
 uint32_t
 dfs_namespace_count(void)
 {
-	smb_shriter_t shi;
-	smb_share_t *si;
 	uint32_t nroot = 0;
 	int rc;
 
@@ -285,11 +297,7 @@
 		    "assuming one namespace exists", rc);
 	}
 
-	smb_shr_iterinit(&shi);
-	while ((si = smb_shr_iterate(&shi)) != NULL) {
-		if ((si->shr_flags & SMB_SHRF_DFSROOT) != 0)
-			nroot++;
-	}
+	nroot += dfs_cache_nscount();
 
 	return (nroot);
 }
@@ -317,11 +325,22 @@
 	if (smb_shr_get((char *)rootshr, &si) != NERR_Success)
 		return (NERR_NetNameNotFound);
 
-	if (si.shr_flags & SMB_SHRF_DFSROOT) {
-		/* Share is already a DFS root */
+	(void) mutex_lock(&dfs_nsmtx);
+	if (smb_strcasecmp(dfs_cached_ns, rootshr, 0) == 0) {
+		/* This DFS root is already exported */
+		(void) mutex_unlock(&dfs_nsmtx);
 		return (ERROR_FILE_EXISTS);
 	}
 
+	if (*dfs_cached_ns != '\0') {
+		syslog(LOG_WARNING, "dfs: trying to add %s namespace."
+		    " Only one standalone namespace is supported."
+		    " A namespace is already exported for %s",
+		    rootshr, dfs_cached_ns);
+		(void) mutex_unlock(&dfs_nsmtx);
+		return (ERROR_NOT_SUPPORTED);
+	}
+
 	bzero(&info, sizeof (info));
 	if (cmnt)
 		(void) strlcpy(info.i_comment, cmnt, sizeof (info.i_comment));
@@ -337,12 +356,18 @@
 	info.i_ntargets = 1;
 	info.i_targets = &t;
 
-	if ((status = dfs_root_add(si.shr_path, &info)) != ERROR_SUCCESS)
+	if ((status = dfs_root_add(si.shr_path, &info)) != ERROR_SUCCESS) {
+		(void) mutex_unlock(&dfs_nsmtx);
 		return (status);
+	}
 
 	status = srvsvc_shr_setdfsroot(&si, B_TRUE);
-	if (status == ERROR_SUCCESS)
+	if (status == ERROR_SUCCESS) {
 		(void) dfs_cache_add_byname(rootshr, NULL, DFS_OBJECT_ROOT);
+		(void) strlcpy(dfs_cached_ns, rootshr, sizeof (dfs_cached_ns));
+		(void) smb_config_setnum(SMB_CI_DFS_STDROOT_NUM, 1);
+	}
+	(void) mutex_unlock(&dfs_nsmtx);
 
 	return (status);
 }
@@ -372,6 +397,9 @@
 		syslog(LOG_WARNING, "dfs: failed to disable root share %s (%d)",
 		    name, status);
 
+	if (!dfs_namespace_iscached(name))
+		return (ERROR_SUCCESS);
+
 	smb_cache_iterinit(&dfs_nscache, &cursor);
 
 	while (smb_cache_iterate(&dfs_nscache, &cursor, &nscnode)) {
@@ -383,13 +411,32 @@
 			    nscnode.nsc_fspath, status);
 	}
 
-	smb_cache_flush(&dfs_nscache);
+	dfs_cache_flush(name);
 
 	/* TODO: remove empty dirs */
 	return (ERROR_SUCCESS);
 }
 
 /*
+ * Determines the DFS namespace flavor.
+ */
+uint32_t
+dfs_namespace_getflavor(const char *name)
+{
+	char rootdir[DFS_PATH_MAX];
+	dfs_info_t info;
+
+	if (dfs_namespace_path(name, rootdir, DFS_PATH_MAX) != ERROR_SUCCESS)
+		return (0);
+
+	/* get flavor info from state info (info level 2) */
+	if (dfs_root_getinfo(rootdir, &info, 2) != ERROR_SUCCESS)
+		return (0);
+
+	return (info.i_state & DFS_VOLUME_FLAVORS);
+}
+
+/*
  * ==================
  * Root API (public)
  * ==================
@@ -1050,6 +1097,24 @@
 		return (NULL);
 	}
 
+	/*
+	 * This check should be removed when multiple standalone
+	 * namespaces are supported.
+	 */
+	(void) mutex_lock(&dfs_nsmtx);
+	if (*dfs_cached_ns != '\0') {
+		syslog(LOG_WARNING, "dfs: trying to load %s namespace."
+		    " Only one standalone namespace is supported."
+		    " A namespace is already exported for %s",
+		    share, dfs_cached_ns);
+		(void) mutex_unlock(&dfs_nsmtx);
+		free(share);
+		return (NULL);
+	}
+	(void) strlcpy(dfs_cached_ns, share, sizeof (dfs_cached_ns));
+	(void) smb_config_setnum(SMB_CI_DFS_STDROOT_NUM, 1);
+	(void) mutex_unlock(&dfs_nsmtx);
+
 	(void) snprintf(uncpath, DFS_PATH_MAX, "\\\\%s\\%s", dfs_nbname, share);
 	(void) dfs_cache_add_byunc(uncpath, si.shr_path, DFS_OBJECT_ROOT);
 
@@ -1059,6 +1124,22 @@
 	return (NULL);
 }
 
+/*
+ * Checks whether the given name matches the name of
+ * the cached namespace.
+ */
+static boolean_t
+dfs_namespace_iscached(const char *name)
+{
+	boolean_t iscached;
+
+	(void) mutex_lock(&dfs_nsmtx);
+	iscached = (smb_strcasecmp(name, dfs_cached_ns, 0) == 0);
+	(void) mutex_unlock(&dfs_nsmtx);
+
+	return (iscached);
+}
+
 static int
 dfs_root_add(const char *rootdir, dfs_info_t *info)
 {
@@ -1216,6 +1297,10 @@
 	rc |= nvlist_add_string(nvl, "t_server", t->t_server);
 	rc |= nvlist_add_string(nvl, "t_share", t->t_share);
 	rc |= nvlist_add_uint32(nvl, "t_state", t->t_state);
+	rc |= nvlist_add_uint32(nvl, "t_priority_class",
+	    t->t_priority.p_class);
+	rc |= nvlist_add_uint16(nvl, "t_priority_rank",
+	    t->t_priority.p_rank);
 
 	if (rc == 0)
 		rc = nvlist_pack(nvl, buf, bufsz, NV_ENCODE_NATIVE, 0);
@@ -1236,6 +1321,9 @@
 	char *cmnt, *guid;
 	char *t_server, *t_share;
 	uint32_t t_state;
+	uint32_t t_priority_class;
+	uint16_t t_priority_rank;
+	boolean_t decode_priority = B_FALSE;
 	int rc;
 
 	if (nvlist_unpack(buf, bufsz, &nvl, 0) != 0)
@@ -1263,9 +1351,12 @@
 	case DFS_INFO_ALL:
 	case 3:
 	case 4:
+		/* need target information */
+		break;
 	case 6:
 	case 9:
-		/* need target information */
+		/* need target and priority information */
+		decode_priority = B_TRUE;
 		break;
 	default:
 		nvlist_free(nvl);
@@ -1288,6 +1379,23 @@
 	}
 	dfs_target_init(info->i_targets, t_server, t_share, t_state);
 
+	if (decode_priority) {
+		rc = nvlist_lookup_uint32(nvl, "t_priority_class",
+		    &t_priority_class);
+		if (rc == 0)
+			rc = nvlist_lookup_uint16(nvl, "t_priority_rank",
+			    &t_priority_rank);
+
+		if (rc != 0 && rc != ENOENT) {
+			nvlist_free(nvl);
+			free(info->i_targets);
+			return (ERROR_INTERNAL_ERROR);
+		} else if (rc == 0) {
+			info->i_targets->t_priority.p_class = t_priority_class;
+			info->i_targets->t_priority.p_rank = t_priority_rank;
+		}
+	}
+
 	nvlist_free(nvl);
 	return (ERROR_SUCCESS);
 }
@@ -1625,6 +1733,41 @@
 }
 
 /*
+ * If this namespace hasn't been cached then return
+ * without flushing the cache; otherwise clear the
+ * name and flush the cache.
+ */
+static void
+dfs_cache_flush(const char *name)
+{
+	(void) mutex_lock(&dfs_nsmtx);
+	if (smb_strcasecmp(name, dfs_cached_ns, 0) != 0) {
+		(void) mutex_unlock(&dfs_nsmtx);
+		return;
+	}
+	*dfs_cached_ns = '\0';
+	(void) smb_config_setnum(SMB_CI_DFS_STDROOT_NUM, 0);
+	(void) mutex_unlock(&dfs_nsmtx);
+
+	smb_cache_flush(&dfs_nscache);
+}
+
+/*
+ * Returns the number of cached namespaces
+ */
+static uint32_t
+dfs_cache_nscount(void)
+{
+	uint32_t nscount;
+
+	(void) mutex_lock(&dfs_nsmtx);
+	nscount = (*dfs_cached_ns == '\0') ? 0 : 1;
+	(void) mutex_unlock(&dfs_nsmtx);
+
+	return (nscount);
+}
+
+/*
  * Determines whether the given path is a directory.
  */
 static boolean_t
@@ -1639,36 +1782,103 @@
 }
 
 /*
- * Validates the given state based on the object type (root/link)
- * and whether it is the object's state or its target's state
+ * Validates the given state based on the object type (root/link), info
+ * level, and whether it is the object's state or its target's state
  */
 static uint32_t
-dfs_isvalidstate(uint32_t state, uint32_t type, boolean_t target)
+dfs_isvalidstate(uint32_t state, uint32_t type, boolean_t target,
+    uint32_t infolvl)
 {
 	uint32_t status = ERROR_SUCCESS;
 
-	if (type == DFS_OBJECT_ROOT) {
-		if (!target)
-			return (dfs_root_isvalidstate(state));
+	switch (infolvl) {
+	case 101:
+		if (type == DFS_OBJECT_ROOT) {
+			if (!target)
+				return (dfs_root_isvalidstate(state));
 
-		if (!dfs_target_isvalidstate(state))
-			status = ERROR_INVALID_PARAMETER;
-		else if (state == DFS_STORAGE_STATE_OFFLINE)
-			status = ERROR_NOT_SUPPORTED;
-	} else {
-		if (!target) {
-			if (!dfs_link_isvalidstate(state))
-				status = ERROR_INVALID_PARAMETER;
-		} else {
 			if (!dfs_target_isvalidstate(state))
 				status = ERROR_INVALID_PARAMETER;
+			else if (state == DFS_STORAGE_STATE_OFFLINE)
+				status = ERROR_NOT_SUPPORTED;
+		} else {
+			if (!target) {
+				if (!dfs_link_isvalidstate(state))
+					status = ERROR_INVALID_PARAMETER;
+			} else {
+				if (!dfs_target_isvalidstate(state))
+					status = ERROR_INVALID_PARAMETER;
+			}
 		}
+		break;
+
+	case 105:
+		if (state == 0)
+			return (ERROR_SUCCESS);
+
+		if (type == DFS_OBJECT_ROOT) {
+			switch (state) {
+			case DFS_VOLUME_STATE_OK:
+			case DFS_VOLUME_STATE_OFFLINE:
+			case DFS_VOLUME_STATE_ONLINE:
+			case DFS_VOLUME_STATE_RESYNCHRONIZE:
+			case DFS_VOLUME_STATE_STANDBY:
+				status = ERROR_NOT_SUPPORTED;
+				break;
+
+			default:
+				status = ERROR_INVALID_PARAMETER;
+			}
+		} else {
+			switch (state) {
+			case DFS_VOLUME_STATE_OK:
+			case DFS_VOLUME_STATE_OFFLINE:
+			case DFS_VOLUME_STATE_ONLINE:
+				break;
+
+			case DFS_VOLUME_STATE_RESYNCHRONIZE:
+			case DFS_VOLUME_STATE_STANDBY:
+				status = ERROR_NOT_SUPPORTED;
+				break;
+
+			default:
+				status = ERROR_INVALID_PARAMETER;
+			}
+		}
+		break;
+
+	default:
+		status = ERROR_INVALID_LEVEL;
 	}
 
 	return (status);
 }
 
 /*
+ * Validates the given property flag mask based on the object
+ * type (root/link) and namespace flavor.
+ */
+static uint32_t
+dfs_isvalidpropflagmask(uint32_t propflag_mask, uint32_t type,
+    uint32_t flavor)
+{
+	uint32_t flgs_not_supported;
+
+	flgs_not_supported = DFS_PROPERTY_FLAG_ROOT_SCALABILITY
+	    | DFS_PROPERTY_FLAG_CLUSTER_ENABLED
+	    | DFS_PROPERTY_FLAG_ABDE;
+
+	if (flavor == DFS_VOLUME_FLAVOR_STANDALONE) {
+		if (type == DFS_OBJECT_LINK)
+			flgs_not_supported |= DFS_PROPERTY_FLAG_SITE_COSTING;
+		if (propflag_mask & flgs_not_supported)
+			return (ERROR_NOT_SUPPORTED);
+	}
+
+	return (ERROR_SUCCESS);
+}
+
+/*
  * Based on the specified information level (infolvl) copy parts of the
  * information provided through newinfo into the existing information
  * (info) for the given object.
@@ -1699,7 +1909,7 @@
 	case 101:
 		state = (target_op)
 		    ? newinfo->i_targets->t_state : newinfo->i_state;
-		status = dfs_isvalidstate(state, type, target_op);
+		status = dfs_isvalidstate(state, type, target_op, 101);
 		if (status != ERROR_SUCCESS)
 			return (status);
 
@@ -1730,9 +1940,19 @@
 		break;
 
 	case 105:
+		status = dfs_isvalidstate(newinfo->i_state, type, B_FALSE, 105);
+		if (status != ERROR_SUCCESS)
+			return (status);
+
+		status = dfs_isvalidpropflagmask(newinfo->i_propflag_mask, type,
+		    newinfo->i_flavor);
+		if (status != ERROR_SUCCESS)
+			return (status);
+
 		(void) strlcpy(info->i_comment, newinfo->i_comment,
 		    sizeof (newinfo->i_comment));
-		info->i_state = newinfo->i_state;
+		if (newinfo->i_state != 0)
+			info->i_state = newinfo->i_state;
 		info->i_timeout = newinfo->i_timeout;
 		info->i_propflags = newinfo->i_propflags;
 		break;
--- a/usr/src/lib/smbsrv/libmlsvc/common/dfs.h	Thu Jul 22 12:31:36 2010 -0700
+++ b/usr/src/lib/smbsrv/libmlsvc/common/dfs.h	Thu Jul 22 14:53:56 2010 -0700
@@ -19,8 +19,7 @@
  * CDDL HEADER END
  */
 /*
- * Copyright 2010 Sun Microsystems, Inc.  All rights reserved.
- * Use is subject to license terms.
+ * Copyright (c) 2010, Oracle and/or its affiliates. All rights reserved.
  */
 
 #ifndef	_DFS_H
@@ -61,6 +60,7 @@
 uint32_t dfs_namespace_remove(const char *);
 void dfs_namespace_load(const char *);
 void dfs_namespace_unload(const char *);
+uint32_t dfs_namespace_getflavor(const char *);
 
 uint32_t dfs_root_getinfo(const char *, dfs_info_t *, uint32_t);
 uint32_t dfs_root_setinfo(const char *, dfs_info_t *, uint32_t);
--- a/usr/src/lib/smbsrv/libmlsvc/common/libmlsvc.h	Thu Jul 22 12:31:36 2010 -0700
+++ b/usr/src/lib/smbsrv/libmlsvc/common/libmlsvc.h	Thu Jul 22 14:53:56 2010 -0700
@@ -277,6 +277,10 @@
 uint32_t dfs_get_referrals(const char *, dfs_reftype_t, dfs_info_t *);
 void dfs_info_free(dfs_info_t *);
 
+/* spool functions */
+void spoolss_copy_spool_file(smb_inaddr_t *, char *, char *, char *);
+
+
 #ifdef	__cplusplus
 }
 #endif
--- a/usr/src/lib/smbsrv/libmlsvc/common/mapfile-vers	Thu Jul 22 12:31:36 2010 -0700
+++ b/usr/src/lib/smbsrv/libmlsvc/common/mapfile-vers	Thu Jul 22 14:53:56 2010 -0700
@@ -21,7 +21,6 @@
 #
 # Copyright (c) 2007, 2010, Oracle and/or its affiliates. All rights reserved.
 #
-#
 
 #
 # MAPFILE HEADER START
@@ -76,6 +75,7 @@
 	smb_shr_stop;
 	smb_token_destroy;
 	smb_token_log;
+	spoolss_copy_spool_file;
     local:
 	*;
 };
--- a/usr/src/lib/smbsrv/libmlsvc/common/mlsvc.h	Thu Jul 22 12:31:36 2010 -0700
+++ b/usr/src/lib/smbsrv/libmlsvc/common/mlsvc.h	Thu Jul 22 14:53:56 2010 -0700
@@ -19,13 +19,13 @@
  * CDDL HEADER END
  */
 /*
- * Copyright 2010 Sun Microsystems, Inc.  All rights reserved.
- * Use is subject to license terms.
+ * Copyright (c) 2008, 2010, Oracle and/or its affiliates. All rights reserved.
  */
 
 #ifndef _SMBSRV_MLSVC_H
 #define	_SMBSRV_MLSVC_H
 
+#include <cups/cups.h>
 #include <smbsrv/smb_share.h>
 #include <smbsrv/ndl/netlogon.ndl>
 
@@ -50,6 +50,7 @@
 
 void logr_finalize(void);
 void svcctl_finalize(void);
+void spoolss_finalize(void);
 void netdfs_finalize(void);
 
 int netr_open(char *, char *, mlsvc_handle_t *);
@@ -79,6 +80,26 @@
 void smb_quota_add_fs(const char *);
 void smb_quota_remove_fs(const char *);
 
+typedef struct smb_cups_ops {
+	void *cups_hdl;
+	cups_lang_t *(*cupsLangDefault)();
+	const char *(*cupsLangEncoding)(cups_lang_t *);
+	void (*cupsLangFree)(cups_lang_t *);
+	ipp_status_t (*cupsLastError)();
+	int (*cupsGetDests)(cups_dest_t **);
+	void (*cupsFreeDests)(int, cups_dest_t *);
+	ipp_t *(*cupsDoFileRequest)(http_t *, ipp_t *, const char *,
+	    const char *);
+	ipp_t *(*ippNew)();
+	void (*ippDelete)();
+	char *(*ippErrorString)();
+	ipp_attribute_t *(*ippAddString)();
+	void (*httpClose)(http_t *);
+	http_t *(*httpConnect)(const char *, int);
+} smb_cups_ops_t;
+
+smb_cups_ops_t *spoolss_cups_ops(void);
+
 #ifdef __cplusplus
 }
 #endif
--- a/usr/src/lib/smbsrv/libmlsvc/common/mlsvc_init.c	Thu Jul 22 12:31:36 2010 -0700
+++ b/usr/src/lib/smbsrv/libmlsvc/common/mlsvc_init.c	Thu Jul 22 14:53:56 2010 -0700
@@ -19,8 +19,7 @@
  * CDDL HEADER END
  */
 /*
- * Copyright 2010 Sun Microsystems, Inc.  All rights reserved.
- * Use is subject to license terms.
+ * Copyright (c) 2007, 2010, Oracle and/or its affiliates. All rights reserved.
  */
 
 #include <sys/errno.h>
@@ -85,6 +84,7 @@
 mlsvc_fini(void)
 {
 	smb_logon_fini();
+	spoolss_finalize();
 	svcctl_finalize();
 	logr_finalize();
 	netdfs_finalize();
--- a/usr/src/lib/smbsrv/libmlsvc/common/netdfs.c	Thu Jul 22 12:31:36 2010 -0700
+++ b/usr/src/lib/smbsrv/libmlsvc/common/netdfs.c	Thu Jul 22 14:53:56 2010 -0700
@@ -708,17 +708,13 @@
 	}
 
 	dfs_setpriv(PRIV_ON);
-
 	/* For now only allow a single standalone namespace */
-	if (dfs_namespace_count() == 0) {
+	if (dfs_namespace_count() == 0)
 		param->status = dfs_namespace_add(share, comment);
-		if (param->status == ERROR_SUCCESS)
-			(void) smb_config_setnum(SMB_CI_DFS_STDROOT_NUM, 1);
-	} else {
+	else
 		param->status = ERROR_NOT_SUPPORTED;
-	}
+	dfs_setpriv(PRIV_OFF);
 
-	dfs_setpriv(PRIV_OFF);
 	return (NDR_DRC_OK);
 }
 
@@ -737,13 +733,10 @@
 
 	dfs_setpriv(PRIV_ON);
 
-	if (ndr_is_admin(mxa)) {
+	if (ndr_is_admin(mxa))
 		param->status = dfs_namespace_remove(share);
-		if (param->status == ERROR_SUCCESS)
-			(void) smb_config_setnum(SMB_CI_DFS_STDROOT_NUM, 0);
-	} else {
+	else
 		param->status = ERROR_ACCESS_DENIED;
-	}
 
 	dfs_setpriv(PRIV_OFF);
 	return (NDR_DRC_OK);
@@ -879,6 +872,12 @@
 	if ((t_server == NULL) || (t_share == NULL))
 		return (ERROR_INVALID_PARAMETER);
 
+	if (netinfo->priority_class > DfsGlobalLowPriorityClass)
+		return (ERROR_INVALID_PARAMETER);
+
+	if (netinfo->priority_rank > DFS_PRIORITY_RANK_MAX)
+		return (ERROR_INVALID_PARAMETER);
+
 	bzero(&info, sizeof (dfs_info_t));
 	bzero(&target, sizeof (dfs_target_t));
 
@@ -905,15 +904,21 @@
 netdfs_setinfo_105(dfs_path_t *path, netdfs_info105_t *netinfo)
 {
 	dfs_info_t info;
-	uint32_t status;
+	uint32_t status, flavor;
 	char *cmnt = (char *)netinfo->comment;
 
 	bzero(&info, sizeof (dfs_info_t));
 
+	flavor = dfs_namespace_getflavor(path->p_unc.unc_share);
+	if (flavor == 0)
+		return (ERROR_INTERNAL_ERROR);
+	info.i_flavor = flavor;
+
 	if (cmnt != NULL)
 		(void) strlcpy(info.i_comment, cmnt, sizeof (info.i_comment));
 	info.i_state = netinfo->state;
 	info.i_timeout = netinfo->timeout;
+	info.i_propflag_mask = netinfo->property_flag_mask;
 	info.i_propflags =
 	    netinfo->property_flags & netinfo->property_flag_mask;
 
--- a/usr/src/lib/smbsrv/libmlsvc/common/samr_clnt.c	Thu Jul 22 12:31:36 2010 -0700
+++ b/usr/src/lib/smbsrv/libmlsvc/common/samr_clnt.c	Thu Jul 22 14:53:56 2010 -0700
@@ -54,8 +54,8 @@
 /*LINTED E_STATIC_UNUSED*/
 static DWORD samr_connect1(char *, char *, char *, DWORD, mlsvc_handle_t *);
 static DWORD samr_connect2(char *, char *, char *, DWORD, mlsvc_handle_t *);
-static DWORD samr_connect3(char *, char *, char *, DWORD, mlsvc_handle_t *);
 static DWORD samr_connect4(char *, char *, char *, DWORD, mlsvc_handle_t *);
+static DWORD samr_connect5(char *, char *, char *, DWORD, mlsvc_handle_t *);
 
 typedef DWORD (*samr_connop_t)(char *, char *, char *, DWORD,
     mlsvc_handle_t *);
@@ -109,8 +109,8 @@
  *
  *	Windows NT3.x:	SamrConnect
  *	Windows NT4.0:	SamrConnect2
- *	Windows 2000:	SamrConnect3
- *	Windows XP:	SamrConnect4
+ *	Windows 2000:	SamrConnect4
+ *	Windows XP:	SamrConnect5
  *
  * Try the calls from most recent to oldest until the server responds with
  * something other than an RPC protocol error.  We don't use the original
@@ -121,8 +121,8 @@
     mlsvc_handle_t *samr_handle)
 {
 	static samr_connop_t samr_connop[] = {
+		samr_connect5,
 		samr_connect4,
-		samr_connect3,
 		samr_connect2
 	};
 
@@ -137,16 +137,12 @@
 		status = (*samr_connop[i])(server, domain, username,
 		    access_mask, samr_handle);
 
-		if (status != NT_STATUS_UNSUCCESSFUL)
-			break;
+		if (status == NT_STATUS_SUCCESS)
+			return (0);
 	}
 
-	if (status != NT_STATUS_SUCCESS) {
-		ndr_rpc_unbind(samr_handle);
-		return (-1);
-	}
-
-	return (0);
+	ndr_rpc_unbind(samr_handle);
+	return (-1);
 }
 
 /*
@@ -163,12 +159,12 @@
 samr_connect1(char *server, char *domain, char *username, DWORD access_mask,
     mlsvc_handle_t *samr_handle)
 {
-	struct samr_ConnectAnon arg;
+	struct samr_Connect arg;
 	int opnum;
 	DWORD status;
 
-	bzero(&arg, sizeof (struct samr_ConnectAnon));
-	opnum = SAMR_OPNUM_ConnectAnon;
+	bzero(&arg, sizeof (struct samr_Connect));
+	opnum = SAMR_OPNUM_Connect;
 	status = NT_STATUS_SUCCESS;
 
 	arg.servername = ndr_rpc_malloc(samr_handle, sizeof (DWORD));
@@ -206,13 +202,13 @@
 samr_connect2(char *server, char *domain, char *username, DWORD access_mask,
     mlsvc_handle_t *samr_handle)
 {
-	struct samr_Connect arg;
+	struct samr_Connect2 arg;
 	int opnum;
 	DWORD status;
 	int len;
 
-	bzero(&arg, sizeof (struct samr_Connect));
-	opnum = SAMR_OPNUM_Connect;
+	bzero(&arg, sizeof (struct samr_Connect2));
+	opnum = SAMR_OPNUM_Connect2;
 	status = NT_STATUS_SUCCESS;
 
 	len = strlen(server) + 4;
@@ -237,22 +233,22 @@
 }
 
 /*
- * samr_connect3
+ * samr_connect4
  *
  * Connect to the SAM on a Windows 2000 domain controller.
  */
 /*ARGSUSED*/
 static DWORD
-samr_connect3(char *server, char *domain, char *username, DWORD access_mask,
+samr_connect4(char *server, char *domain, char *username, DWORD access_mask,
     mlsvc_handle_t *samr_handle)
 {
-	struct samr_Connect3 arg;
+	struct samr_Connect4 arg;
 	int opnum;
 	DWORD status;
 	int len;
 
-	bzero(&arg, sizeof (struct samr_Connect3));
-	opnum = SAMR_OPNUM_Connect3;
+	bzero(&arg, sizeof (struct samr_Connect4));
+	opnum = SAMR_OPNUM_Connect4;
 	status = NT_STATUS_SUCCESS;
 
 	len = strlen(server) + 4;
@@ -278,7 +274,7 @@
 }
 
 /*
- * samr_connect4
+ * samr_connect5
  *
  * Connect to the SAM on a Windows XP domain controller.  On Windows
  * XP, the server should be the fully qualified DNS domain name with
@@ -290,17 +286,17 @@
  */
 /*ARGSUSED*/
 static DWORD
-samr_connect4(char *server, char *domain, char *username, DWORD access_mask,
+samr_connect5(char *server, char *domain, char *username, DWORD access_mask,
     mlsvc_handle_t *samr_handle)
 {
-	struct samr_Connect4 arg;
+	struct samr_Connect5 arg;
 	int len;
 	int opnum;
 	DWORD status;
 	smb_domainex_t dinfo;
 
-	bzero(&arg, sizeof (struct samr_Connect4));
-	opnum = SAMR_OPNUM_Connect;
+	bzero(&arg, sizeof (struct samr_Connect5));
+	opnum = SAMR_OPNUM_Connect5;
 	status = NT_STATUS_SUCCESS;
 
 	if (!smb_domain_getinfo(&dinfo))
--- a/usr/src/lib/smbsrv/libmlsvc/common/samr_svc.c	Thu Jul 22 12:31:36 2010 -0700
+++ b/usr/src/lib/smbsrv/libmlsvc/common/samr_svc.c	Thu Jul 22 14:53:56 2010 -0700
@@ -213,7 +213,7 @@
 }
 
 /*
- * samr_s_ConnectAnon
+ * samr_s_Connect
  *
  * This is a request to connect to the local SAM database. We don't
  * support any form of update request and our database doesn't
@@ -223,9 +223,9 @@
  * Return a handle for use with subsequent SAM requests.
  */
 static int
-samr_s_ConnectAnon(void *arg, ndr_xa_t *mxa)
+samr_s_Connect(void *arg, ndr_xa_t *mxa)
 {
-	struct samr_ConnectAnon *param = arg;
+	struct samr_Connect *param = arg;
 	ndr_hdid_t *id;
 
 	id = samr_hdalloc(mxa, SAMR_KEY_CONNECT, SMB_DOMAIN_NULL, 0);
@@ -1082,7 +1082,7 @@
 }
 
 /*
- * samr_s_Connect
+ * samr_s_Connect2
  *
  * This is a request to connect to the local SAM database.
  * We don't support any form of update request and our database doesn't
@@ -1092,9 +1092,9 @@
  * Return a handle for use with subsequent SAM requests.
  */
 static int
-samr_s_Connect(void *arg, ndr_xa_t *mxa)
+samr_s_Connect2(void *arg, ndr_xa_t *mxa)
 {
-	struct samr_Connect *param = arg;
+	struct samr_Connect2 *param = arg;
 	ndr_hdid_t *id;
 
 	id = samr_hdalloc(mxa, SAMR_KEY_CONNECT, SMB_DOMAIN_NULL, 0);
@@ -1807,12 +1807,12 @@
 }
 
 /*
- * samr_s_Connect3
+ * samr_s_Connect4
  */
 static int
-samr_s_Connect3(void *arg, ndr_xa_t *mxa)
+samr_s_Connect4(void *arg, ndr_xa_t *mxa)
 {
-	struct samr_Connect3	*param = arg;
+	struct samr_Connect4	*param = arg;
 	ndr_hdid_t		*id;
 
 	id = samr_hdalloc(mxa, SAMR_KEY_CONNECT, SMB_DOMAIN_NULL, 0);
@@ -1828,23 +1828,23 @@
 }
 
 /*
- * samr_s_Connect4
+ * samr_s_Connect5
  *
- * This is the connect4 form of the connect request used by Windows XP.
+ * This is the connect5 form of the connect request used by Windows XP.
  * Returns an RPC fault for now.
  */
 /*ARGSUSED*/
 static int
-samr_s_Connect4(void *arg, ndr_xa_t *mxa)
+samr_s_Connect5(void *arg, ndr_xa_t *mxa)
 {
-	struct samr_Connect4 *param = arg;
+	struct samr_Connect5 *param = arg;
 
-	bzero(param, sizeof (struct samr_Connect4));
+	bzero(param, sizeof (struct samr_Connect5));
 	return (NDR_DRC_FAULT_REQUEST_OPNUM_INVALID);
 }
 
 static ndr_stub_table_t samr_stub_table[] = {
-	{ samr_s_ConnectAnon,		SAMR_OPNUM_ConnectAnon },
+	{ samr_s_Connect,		SAMR_OPNUM_Connect },
 	{ samr_s_CloseHandle,		SAMR_OPNUM_CloseHandle },
 	{ samr_s_LookupDomain,		SAMR_OPNUM_LookupDomain },
 	{ samr_s_EnumLocalDomains,	SAMR_OPNUM_EnumLocalDomains },
@@ -1857,14 +1857,14 @@
 	{ samr_s_QueryUserInfo,		SAMR_OPNUM_QueryUserInfo },
 	{ samr_s_QueryUserGroups,	SAMR_OPNUM_QueryUserGroups },
 	{ samr_s_OpenGroup,		SAMR_OPNUM_OpenGroup },
-	{ samr_s_Connect,		SAMR_OPNUM_Connect },
+	{ samr_s_Connect2,		SAMR_OPNUM_Connect2 },
 	{ samr_s_GetUserPwInfo,		SAMR_OPNUM_GetUserPwInfo },
 	{ samr_s_CreateUser,		SAMR_OPNUM_CreateUser },
 	{ samr_s_ChangeUserPasswd,	SAMR_OPNUM_ChangeUserPasswd },
 	{ samr_s_GetDomainPwInfo,	SAMR_OPNUM_GetDomainPwInfo },
 	{ samr_s_SetUserInfo,		SAMR_OPNUM_SetUserInfo },
-	{ samr_s_Connect3,		SAMR_OPNUM_Connect3 },
 	{ samr_s_Connect4,		SAMR_OPNUM_Connect4 },
+	{ samr_s_Connect5,		SAMR_OPNUM_Connect5 },
 	{ samr_s_QueryDispInfo,		SAMR_OPNUM_QueryDispInfo },
 	{ samr_s_OpenAlias,		SAMR_OPNUM_OpenAlias },
 	{ samr_s_CreateDomainAlias,	SAMR_OPNUM_CreateDomainAlias },
--- a/usr/src/lib/smbsrv/libmlsvc/common/smb_share.c	Thu Jul 22 12:31:36 2010 -0700
+++ b/usr/src/lib/smbsrv/libmlsvc/common/smb_share.c	Thu Jul 22 14:53:56 2010 -0700
@@ -43,6 +43,7 @@
 #include <pwd.h>
 #include <signal.h>
 #include <dirent.h>
+#include <dlfcn.h>
 
 #include <smbsrv/libsmb.h>
 #include <smbsrv/libsmbns.h>
@@ -51,6 +52,7 @@
 #include <smbsrv/smb.h>
 #include <mlsvc.h>
 #include <dfs.h>
+#include <cups/cups.h>
 
 #define	SMB_SHR_ERROR_THRESHOLD		3
 #define	SMB_SHR_CSC_BUFSZ		64
@@ -142,6 +144,7 @@
 static uint32_t smb_shr_sa_load(sa_share_t, sa_resource_t);
 static uint32_t smb_shr_sa_loadbyname(char *);
 static uint32_t smb_shr_sa_get(sa_share_t, sa_resource_t, smb_share_t *);
+static void smb_shr_load_cups_printers();
 
 /*
  * .ZFS management functions
@@ -448,6 +451,9 @@
 			/* If path is ZFS, add the .zfs/shares/<share> entry. */
 			smb_shr_zfs_add(si);
 
+			if ((si->shr_flags & SMB_SHRF_DFSROOT) != 0)
+				dfs_namespace_load(si->shr_name);
+
 			return (NERR_Success);
 		}
 	}
@@ -572,6 +578,7 @@
 	bcopy(from_si, &to_si, sizeof (smb_share_t));
 	(void) strlcpy(to_si.shr_name, to_name, sizeof (to_si.shr_name));
 
+
 	/* If path is ZFS, rename the .zfs/shares/<share> entry. */
 	smb_shr_zfs_rename(from_si, &to_si);
 
@@ -1394,8 +1401,10 @@
 
 	(void) smb_strlwr(si->shr_name);
 
-	if ((si->shr_type & STYPE_IPC) == 0)
+	if (((si->shr_type & STYPE_PRINTQ) == 0) &&
+	    (si->shr_type & STYPE_IPC) == 0)
 		si->shr_type = STYPE_DISKTREE;
+
 	si->shr_type |= smb_shr_is_special(cache_ent->shr_name);
 
 	if (smb_shr_is_admin(cache_ent->shr_name))
@@ -1456,9 +1465,12 @@
 	sa_group_t group, subgroup;
 	char *gstate;
 	boolean_t gdisabled;
-
-	if ((handle = smb_shr_sa_enter()) == NULL)
+	boolean_t printing_enabled;
+
+	if ((handle = smb_shr_sa_enter()) == NULL) {
+		syslog(LOG_ERR, "smb_shr_sa_loadall: ret NULL");
 		return (NULL);
+	}
 
 	for (group = sa_get_group(handle, NULL);
 	    group != NULL; group = sa_get_next_group(group)) {
@@ -1480,12 +1492,54 @@
 		}
 
 	}
-
 	smb_shr_sa_exit();
+	printing_enabled = smb_config_getbool(SMB_CI_PRINT_ENABLE);
+	if (printing_enabled)
+		smb_shr_load_cups_printers();
 	return (NULL);
 }
 
 /*
+ * Load print shares from cups
+ */
+static void
+smb_shr_load_cups_printers()
+{
+	uint32_t nerr;
+	int i;
+	cups_dest_t *dests;
+	int num_dests;
+	cups_dest_t *dest;
+	smb_share_t si;
+	smb_cups_ops_t	*cups;
+
+	if ((cups = spoolss_cups_ops()) == NULL)
+		return;
+
+	if (smb_shr_get(SMB_SHARE_PRINT, &si) != NERR_Success) {
+		syslog(LOG_DEBUG, "error getting print$");
+		return;
+	}
+
+	num_dests = cups->cupsGetDests(&dests);
+	for (i = num_dests, dest = dests; i > 0; i--, dest++) {
+		if (dest->instance == NULL) {
+			/*
+			 * Use the path from print$
+			 */
+			(void) strlcpy(si.shr_name, dest->name, MAXPATHLEN);
+			(void) strlcpy(si.shr_cmnt,
+			    SMB_SHARE_PRINT, SMB_SHARE_PRINT_LEN + 1);
+			si.shr_type = STYPE_PRINTQ;
+			nerr = smb_shr_add(&si);
+			if (nerr != NERR_Success)
+				break;
+		}
+	}
+	cups->cupsFreeDests(num_dests, dests);
+}
+
+/*
  * Load the shares contained in the specified group.
  *
  * Don't process groups on which the smb protocol is disabled.
@@ -1562,9 +1616,6 @@
 		return (status);
 	}
 
-	if ((si.shr_flags & SMB_SHRF_DFSROOT) != 0)
-		dfs_namespace_load(si.shr_name);
-
 	return (NERR_Success);
 }
 
@@ -2432,6 +2483,8 @@
 	if ((csc = smb_shr_sa_csc_name(si)) != NULL)
 		rc |= nvlist_add_string(smb, SHOPT_CSC, csc);
 
+	rc |= nvlist_add_uint32(smb, "type", si->shr_type);
+
 	rc |= nvlist_add_nvlist(share, "smb", smb);
 	rc |= nvlist_add_nvlist(list, si->shr_name, share);
 
--- a/usr/src/lib/smbsrv/libmlsvc/common/spoolss_svc.c	Thu Jul 22 12:31:36 2010 -0700
+++ b/usr/src/lib/smbsrv/libmlsvc/common/spoolss_svc.c	Thu Jul 22 14:53:56 2010 -0700
@@ -18,70 +18,138 @@
  *
  * CDDL HEADER END
  */
-
 /*
- * Copyright (c) 2008, 2010, Oracle and/or its affiliates. All rights reserved.
+ * Copyright (c) 2007, 2010, Oracle and/or its affiliates. All rights reserved.
  */
 
 /*
  * Printing and Spooling RPC service.
  */
-
+#include <unistd.h>
 #include <stdlib.h>
 #include <strings.h>
+#include <pthread.h>
+#include <synch.h>
 #include <smbsrv/libsmb.h>
 #include <smbsrv/libmlrpc.h>
 #include <smbsrv/libmlsvc.h>
+#include <smbsrv/ndl/ndrtypes.ndl>
 #include <smbsrv/ndl/spoolss.ndl>
+#include <smb/nterror.h>
 #include <smbsrv/smbinfo.h>
 #include <smbsrv/nmpipes.h>
+#include <wchar.h>
+#include <cups/cups.h>
+#include <fcntl.h>
+#include <sys/types.h>
+#include <sys/stat.h>
+#include <errno.h>
+#include <dlfcn.h>
+#include <mlsvc.h>
 
-int spoolss_s_OpenPrinter(void *, ndr_xa_t *);
-int spoolss_s_stub(void *, ndr_xa_t *);
+typedef struct smb_spool {
+	list_t sp_list;
+	int sp_cnt;
+	rwlock_t sp_rwl;
+	int sp_initialized;
+} smb_spool_t;
+
+static uint32_t spoolss_cnt;
+static uint32_t spoolss_jobnum = 1;
+static smb_spool_t spoolss_splist;
+static smb_cups_ops_t smb_cups;
+static mutex_t spoolss_cups_mutex;
+
+#define	SPOOLSS_PJOBLEN		256
+#define	SPOOLSS_JOB_NOT_ISSUED	3004
+#define	SPOOLSS_PRINTER		"Postscript"
+#define	SPOOLSS_FN_PREFIX	"cifsprintjob-"
+#define	SPOOLSS_CUPS_SPOOL_DIR	"//var//spool//cups"
+
+struct spoolss_printjob {
+	pid_t pj_pid;
+	int pj_sysjob;
+	int pj_fd;
+	time_t pj_start_time;
+	int pj_status;
+	size_t pj_size;
+	int pj_page_count;
+	boolean_t pj_isspooled;
+	boolean_t pj_jobnum;
+	char pj_filename[SPOOLSS_PJOBLEN];
+	char pj_jobname[SPOOLSS_PJOBLEN];
+	char pj_username[SPOOLSS_PJOBLEN];
+	char pj_queuename[SPOOLSS_PJOBLEN];
+};
+
+DECL_FIXUP_STRUCT(spoolss_GetPrinter_result_u);
+DECL_FIXUP_STRUCT(spoolss_GetPrinter_result);
+DECL_FIXUP_STRUCT(spoolss_GetPrinter);
+
+DECL_FIXUP_STRUCT(spoolss_RPC_V2_NOTIFY_INFO_DATA_DATA);
+DECL_FIXUP_STRUCT(spoolss_RPC_V2_NOTIFY_INFO_DATA);
+DECL_FIXUP_STRUCT(spoolss_RPC_V2_NOTIFY_INFO);
+DECL_FIXUP_STRUCT(spoolss_RFNPCNEX);
+
+uint32_t srvsvc_sd_set_relative(smb_sd_t *, uint8_t *);
+static int spoolss_s_make_sd(uint8_t *);
+static uint32_t spoolss_sd_format(smb_sd_t *);
+static int spoolss_find_fd(ndr_hdid_t *);
+static void spoolss_find_doc_and_print(ndr_hdid_t *);
+static void spoolss_add_spool_doc(smb_spooldoc_t *);
+static int spoolss_cups_init(void);
+static void spoolss_cups_fini(void);
+
+static int spoolss_s_OpenPrinter(void *, ndr_xa_t *);
+static int spoolss_s_ClosePrinter(void *, ndr_xa_t *);
+static int spoolss_s_AbortPrinter(void *, ndr_xa_t *);
+static int spoolss_s_ResetPrinter(void *, ndr_xa_t *);
+static int spoolss_s_GetPrinter(void *, ndr_xa_t *);
+static int spoolss_s_GetPrinterData(void *, ndr_xa_t *);
+static int spoolss_s_AddJob(void *, ndr_xa_t *);
+static int spoolss_s_GetJob(void *, ndr_xa_t *);
+static int spoolss_s_EnumJobs(void *, ndr_xa_t *);
+static int spoolss_s_ScheduleJob(void *, ndr_xa_t *);
+static int spoolss_s_StartDocPrinter(void *, ndr_xa_t *);
+static int spoolss_s_EndDocPrinter(void *, ndr_xa_t *);
+static int spoolss_s_StartPagePrinter(void *, ndr_xa_t *);
+static int spoolss_s_EndPagePrinter(void *, ndr_xa_t *);
+static int spoolss_s_rfnpcnex(void *, ndr_xa_t *);
+static int spoolss_s_WritePrinter(void *, ndr_xa_t *);
+static int spoolss_s_EnumForms(void *, ndr_xa_t *);
+static int spoolss_s_stub(void *, ndr_xa_t *);
 
 static ndr_stub_table_t spoolss_stub_table[] = {
+	{ spoolss_s_GetJob,		SPOOLSS_OPNUM_GetJob },
+	{ spoolss_s_EnumJobs,		SPOOLSS_OPNUM_EnumJobs },
+	{ spoolss_s_stub, SPOOLSS_OPNUM_DeletePrinter },
+	{ spoolss_s_GetPrinter,		SPOOLSS_OPNUM_GetPrinter },
+	{ spoolss_s_stub,		SPOOLSS_OPNUM_GetPrinterDriver },
+	{ spoolss_s_stub,		SPOOLSS_OPNUM_DeletePrinterDriver },
 	{ spoolss_s_OpenPrinter,	SPOOLSS_OPNUM_OpenPrinter },
-	{ spoolss_s_stub,	SPOOLSS_OPNUM_GetJob },
-	{ spoolss_s_stub,	SPOOLSS_OPNUM_DeletePrinter },
-	{ spoolss_s_stub,	SPOOLSS_OPNUM_GetPrinterDriver },
-	{ spoolss_s_stub,	SPOOLSS_OPNUM_DeletePrinterDriver },
-	{ spoolss_s_stub,	SPOOLSS_OPNUM_AddPrintProcessor },
-	{ spoolss_s_stub,	SPOOLSS_OPNUM_GetPrintProcessorDirectory },
-	{ spoolss_s_stub,	SPOOLSS_OPNUM_AbortPrinter },
-	{ spoolss_s_stub,	SPOOLSS_OPNUM_ReadPrinter },
-	{ spoolss_s_stub,	SPOOLSS_OPNUM_WaitForPrinterChange },
-	{ spoolss_s_stub,	SPOOLSS_OPNUM_AddForm },
-	{ spoolss_s_stub,	SPOOLSS_OPNUM_DeleteForm },
-	{ spoolss_s_stub,	SPOOLSS_OPNUM_GetForm },
-	{ spoolss_s_stub,	SPOOLSS_OPNUM_SetForm },
-	{ spoolss_s_stub,	SPOOLSS_OPNUM_EnumMonitors },
-	{ spoolss_s_stub,	SPOOLSS_OPNUM_AddPort },
-	{ spoolss_s_stub,	SPOOLSS_OPNUM_ConfigurePort },
-	{ spoolss_s_stub,	SPOOLSS_OPNUM_DeletePort },
-	{ spoolss_s_stub,	SPOOLSS_OPNUM_CreatePrinterIc },
-	{ spoolss_s_stub,	SPOOLSS_OPNUM_PlayDescriptionPrinterIc },
-	{ spoolss_s_stub,	SPOOLSS_OPNUM_DeletePrinterIc },
-	{ spoolss_s_stub,	SPOOLSS_OPNUM_AddPrinterConnection },
-	{ spoolss_s_stub,	SPOOLSS_OPNUM_DeletePrinterConnection },
-	{ spoolss_s_stub,	SPOOLSS_OPNUM_PrinterMessageBox },
-	{ spoolss_s_stub,	SPOOLSS_OPNUM_AddMonitor },
-	{ spoolss_s_stub,	SPOOLSS_OPNUM_DeleteMonitor },
-	{ spoolss_s_stub,	SPOOLSS_OPNUM_DeletePrintProcessor },
-	{ spoolss_s_stub,	SPOOLSS_OPNUM_AddPrintProvider },
-	{ spoolss_s_stub,	SPOOLSS_OPNUM_DeletePrintProvider },
-	{ spoolss_s_stub,	SPOOLSS_OPNUM_ResetPrinter },
-	{ spoolss_s_stub,	SPOOLSS_OPNUM_FindFirstChangeNotify },
-	{ spoolss_s_stub,	SPOOLSS_OPNUM_FindNextChangeNotify },
-	{ spoolss_s_stub,	SPOOLSS_OPNUM_RouterFindFirstNotify },
-	{ spoolss_s_stub,	SPOOLSS_OPNUM_ReplyOpenPrinter },
-	{ spoolss_s_stub,	SPOOLSS_OPNUM_RouterReplyPrinter },
-	{ spoolss_s_stub,	SPOOLSS_OPNUM_ReplyClosePrinter },
-	{ spoolss_s_stub,	SPOOLSS_OPNUM_AddPortEx },
-	{ spoolss_s_stub,	SPOOLSS_OPNUM_RemoteFindFirstChangeNotify },
-	{ spoolss_s_stub,	SPOOLSS_OPNUM_SpoolerInitialize },
-	{ spoolss_s_stub,	SPOOLSS_OPNUM_ResetPrinterEx },
-	{ spoolss_s_stub,	SPOOLSS_OPNUM_RouterRefreshChangeNotify },
-	{ spoolss_s_OpenPrinter,	SPOOLSS_OPNUM_OpenPrinter2 },
+	{ spoolss_s_StartDocPrinter,	SPOOLSS_OPNUM_StartDocPrinter },
+	{ spoolss_s_WritePrinter,	SPOOLSS_OPNUM_WritePrinter },
+	{ spoolss_s_EndDocPrinter,	SPOOLSS_OPNUM_EndDocPrinter },
+	{ spoolss_s_StartPagePrinter,	SPOOLSS_OPNUM_StartPagePrinter },
+	{ spoolss_s_EndPagePrinter,	SPOOLSS_OPNUM_EndPagePrinter },
+	{ spoolss_s_AbortPrinter,	SPOOLSS_OPNUM_AbortPrinter },
+	{ spoolss_s_ResetPrinter,	SPOOLSS_OPNUM_ResetPrinter },
+	{ spoolss_s_AddJob,		SPOOLSS_OPNUM_AddJob },
+	{ spoolss_s_ScheduleJob,    	SPOOLSS_OPNUM_ScheduleJob },
+	{ spoolss_s_GetPrinterData,	SPOOLSS_OPNUM_GetPrinterData },
+	{ spoolss_s_ClosePrinter,	SPOOLSS_OPNUM_ClosePrinter },
+	{ spoolss_s_EnumForms,		SPOOLSS_OPNUM_EnumForms },
+	{ spoolss_s_stub,		SPOOLSS_OPNUM_GetPrinterDriver2 },
+	{ spoolss_s_stub,		SPOOLSS_OPNUM_FCPN },
+	{ spoolss_s_stub,		SPOOLSS_OPNUM_ReplyOpenPrinter },
+	{ spoolss_s_stub,		SPOOLSS_OPNUM_ReplyClosePrinter },
+	{ spoolss_s_stub,		SPOOLSS_OPNUM_RFFPCNEX },
+	{ spoolss_s_rfnpcnex,		SPOOLSS_OPNUM_RFNPCNEX },
+	{ spoolss_s_stub,		SPOOLSS_OPNUM_RRPCN },
+	{ spoolss_s_OpenPrinter,	SPOOLSS_OPNUM_OpenPrinterEx },
+	{ spoolss_s_stub,		SPOOLSS_OPNUM_EnumPrinterData },
+	{ spoolss_s_stub,		SPOOLSS_OPNUM_EnumPrinterDataEx },
+	{ spoolss_s_stub,		SPOOLSS_OPNUM_EnumPrinterKey },
 	{0}
 };
 
@@ -90,7 +158,7 @@
 	"Print Spool Service",		/* desc */
 	"\\spoolss",			/* endpoint */
 	PIPE_SPOOLSS,			/* sec_addr_port */
-	"12345678-1234-abcd-ef000123456789ab",	1,	/* abstract */
+	"12345678-1234-abcd-ef00-0123456789ab",	1,	/* abstract */
 	NDR_TRANSFER_SYNTAX_UUID,		2,	/* transfer */
 	0,				/* no bind_instance_size */
 	0,				/* no bind_req() */
@@ -104,26 +172,980 @@
 spoolss_initialize(void)
 {
 	(void) ndr_svc_register(&spoolss_service);
+	(void) spoolss_cups_init();
 }
 
-int
+void
+spoolss_finalize(void)
+{
+	spoolss_cups_fini();
+}
+
+static int
 spoolss_s_OpenPrinter(void *arg, ndr_xa_t *mxa)
 {
 	struct spoolss_OpenPrinter *param = arg;
+	ndr_hdid_t *id;
 
-	bzero(param, sizeof (struct spoolss_OpenPrinter));
+	if ((id = ndr_hdalloc(mxa, 0)) == NULL) {
+		bzero(&param->handle, sizeof (spoolss_handle_t));
+		param->status = ERROR_NOT_ENOUGH_MEMORY;
+		return (NDR_DRC_OK);
+	}
+
+	bcopy(id, &param->handle, sizeof (spoolss_handle_t));
+	param->status = 0;
 
-	if (mxa == NULL)
-		param->status = NT_SC_ERROR(NT_STATUS_INVALID_PARAMETER);
-	else
-		param->status = NT_SC_ERROR(NT_STATUS_ACCESS_DENIED);
+	return (NDR_DRC_OK);
+}
+
+/*ARGSUSED*/
+static int
+spoolss_s_StartPagePrinter(void *arg, ndr_xa_t *mxa)
+{
+	struct spoolss_StartPagePrinter *param = arg;
+
+	param->status = ERROR_SUCCESS;
 
 	return (NDR_DRC_OK);
 }
 
 /*ARGSUSED*/
+static int
+spoolss_s_EndPagePrinter(void *arg, ndr_xa_t *mxa)
+{
+	struct spoolss_EndPagePrinter *param = arg;
+
+	param->status = ERROR_SUCCESS;
+
+	return (NDR_DRC_OK);
+}
+
+/*
+ *
+ * adds new spool doc to the tail.  used by windows
+ * XP and 2000 only
+ *
+ * Return values
+ *      smb_spooldoc_t - NULL if not found
+ */
+
+static void
+spoolss_add_spool_doc(smb_spooldoc_t *sp)
+{
+	(void) rw_wrlock(&spoolss_splist.sp_rwl);
+	if (!spoolss_splist.sp_initialized) {
+		list_create(&spoolss_splist.sp_list,
+		    sizeof (smb_spooldoc_t),
+		    offsetof(smb_spooldoc_t, sd_lnd));
+		spoolss_splist.sp_initialized = 1;
+	}
+	list_insert_tail(&spoolss_splist.sp_list, sp);
+	spoolss_splist.sp_cnt++;
+	(void) rw_unlock(&spoolss_splist.sp_rwl);
+}
+
+/*
+ *
+ * finds a completed spool doc using the RPC handle
+ * as the key, then prints the doc
+ *
+ * XP and 2000 only
+ *
+ */
+
+static void
+spoolss_find_doc_and_print(ndr_hdid_t *handle)
+{
+	smb_spooldoc_t *sp;
+
+	if (!spoolss_splist.sp_initialized) {
+		syslog(LOG_ERR, "spoolss_find_doc_and_print: not initialized");
+		return;
+	}
+	(void) rw_wrlock(&spoolss_splist.sp_rwl);
+	sp = list_head(&spoolss_splist.sp_list);
+	while (sp != NULL) {
+		/*
+		 * search the spooldoc list for a matching RPC handle
+		 * and use the info to pass to cups for printing
+		 */
+		if (!memcmp(handle, &(sp->sd_handle), sizeof (ndr_hdid_t))) {
+			spoolss_copy_spool_file(&sp->sd_ipaddr,
+			    sp->sd_username, sp->sd_path, sp->sd_doc_name);
+			(void) close(sp->sd_fd);
+			list_remove(&spoolss_splist.sp_list, sp);
+			free(sp);
+			(void) rw_unlock(&spoolss_splist.sp_rwl);
+			return;
+		}
+		sp = list_next(&spoolss_splist.sp_list, sp);
+	}
+	syslog(LOG_ERR, "spoolss_find_doc_and_print: handle not found");
+	(void) rw_unlock(&spoolss_splist.sp_rwl);
+}
+
+static int
+spoolss_find_fd(ndr_hdid_t *handle)
+{
+	smb_spooldoc_t *sp;
+
+	if (!spoolss_splist.sp_initialized) {
+		syslog(LOG_ERR, "spoolss_find_fd: not initialized");
+		return (-1);
+	}
+	(void) rw_rdlock(&spoolss_splist.sp_rwl);
+	sp = list_head(&spoolss_splist.sp_list);
+	while (sp != NULL) {
+		/*
+		 * check for a matching rpc handle in the
+		 * spooldoc list
+		 */
+		if (!memcmp(handle, &(sp->sd_handle), sizeof (ndr_hdid_t))) {
+			(void) rw_unlock(&spoolss_splist.sp_rwl);
+			return (sp->sd_fd);
+		}
+		sp = list_next(&spoolss_splist.sp_list, sp);
+	}
+	syslog(LOG_ERR, "spoolss_find_fd: handle not found");
+	(void) rw_unlock(&spoolss_splist.sp_rwl);
+	return (-1);
+}
+
+/*
+ * Windows XP and 2000 use this mechanism to write spool files.
+ * Creates a spool file fd to be used by spoolss_s_WritePrinter.
+ */
+static int
+spoolss_s_StartDocPrinter(void *arg, ndr_xa_t *mxa)
+{
+	struct spoolss_StartDocPrinter *param = arg;
+	ndr_hdid_t *id = (ndr_hdid_t *)&param->handle;
+	smb_spooldoc_t *spfile;
+	spoolss_DocInfo_t *docinfo;
+	char g_path[MAXPATHLEN];
+	smb_share_t si;
+	int rc;
+	int fd;
+
+	if (ndr_hdlookup(mxa, id) == NULL) {
+		syslog(LOG_ERR, "spoolss_s_StartDocPrinter: invalid handle");
+		param->status = ERROR_INVALID_HANDLE;
+		return (NDR_DRC_OK);
+	}
+
+	if ((docinfo = param->dinfo.DocInfoContainer) == NULL) {
+		param->status = ERROR_INVALID_PARAMETER;
+		return (NDR_DRC_OK);
+	}
+
+	if ((rc = smb_shr_get(SMB_SHARE_PRINT, &si)) != NERR_Success) {
+		syslog(LOG_INFO, "spoolss_s_StartDocPrinter: %s error=%d",
+		    SMB_SHARE_PRINT, rc);
+		param->status = rc;
+		return (NDR_DRC_OK);
+	}
+
+	if ((spfile = calloc(1, sizeof (smb_spooldoc_t))) == NULL) {
+		param->status = ERROR_NOT_ENOUGH_MEMORY;
+		return (NDR_DRC_OK);
+	}
+
+	if (docinfo->doc_name != NULL)
+		(void) strlcpy(spfile->sd_doc_name,
+		    (char *)docinfo->doc_name, MAXNAMELEN);
+	else
+		(void) strlcpy(spfile->sd_doc_name, "document", MAXNAMELEN);
+
+	if (docinfo->printer_name != NULL)
+		(void) strlcpy(spfile->sd_printer_name,
+		    (char *)docinfo->printer_name, MAXPATHLEN);
+	else
+		(void) strlcpy(spfile->sd_printer_name, "printer", MAXPATHLEN);
+
+	spfile->sd_ipaddr = mxa->pipe->np_user.ui_ipaddr;
+	(void) strlcpy((char *)spfile->sd_username,
+	    mxa->pipe->np_user.ui_account, MAXNAMELEN);
+	(void) memcpy(&spfile->sd_handle, &param->handle,
+	    sizeof (rpc_handle_t));
+	/*
+	 *	write temporary spool file to print$
+	 */
+	(void) snprintf(g_path, MAXPATHLEN, "%s/%s%d", si.shr_path,
+	    spfile->sd_username, spoolss_cnt);
+	atomic_inc_32(&spoolss_cnt);
+
+	fd = open(g_path, O_CREAT | O_RDWR, 0600);
+	if (fd == -1) {
+		syslog(LOG_INFO, "spoolss_s_StartDocPrinter: %s: %s",
+		    g_path, strerror(errno));
+		param->status = ERROR_OPEN_FAILED;
+		free(spfile);
+	} else {
+		(void) strlcpy((char *)spfile->sd_path, g_path, MAXPATHLEN);
+		spfile->sd_fd = (uint16_t)fd;
+		spoolss_add_spool_doc(spfile);
+		/*
+		 * JobId isn't used now, but if printQ management is added
+		 * this will have to be incremented per job submitted.
+		 */
+		param->JobId = 46;
+		param->status = ERROR_SUCCESS;
+	}
+	return (NDR_DRC_OK);
+}
+
+/*
+ * Windows XP and 2000 use this mechanism to write spool files
+ */
+
+/*ARGSUSED*/
+static int
+spoolss_s_EndDocPrinter(void *arg, ndr_xa_t *mxa)
+{
+	struct spoolss_EndDocPrinter *param = arg;
+
+	spoolss_find_doc_and_print((ndr_hdid_t *)&param->handle);
+	param->status = ERROR_SUCCESS;
+	return (NDR_DRC_OK);
+}
+
+/*ARGSUSED*/
+static int
+spoolss_s_AbortPrinter(void *arg, ndr_xa_t *mxa)
+{
+	struct spoolss_AbortPrinter *param = arg;
+
+	param->status = ERROR_SUCCESS;
+	return (NDR_DRC_OK);
+}
+
+/*ARGSUSED*/
+static int
+spoolss_s_ResetPrinter(void *arg, ndr_xa_t *mxa)
+{
+	struct spoolss_AbortPrinter *param = arg;
+
+	param->status = ERROR_SUCCESS;
+	return (NDR_DRC_OK);
+}
+
+static int
+spoolss_s_ClosePrinter(void *arg, ndr_xa_t *mxa)
+{
+	struct spoolss_ClosePrinter *param = arg;
+	ndr_hdid_t *id = (ndr_hdid_t *)&param->handle;
+	ndr_handle_t *hd;
+
+	if ((hd = ndr_hdlookup(mxa, id)) != NULL) {
+		free(hd->nh_data);
+		hd->nh_data = NULL;
+	}
+
+	ndr_hdfree(mxa, id);
+	bzero(&param->result_handle, sizeof (spoolss_handle_t));
+	param->status = ERROR_SUCCESS;
+	return (NDR_DRC_OK);
+}
+
+/*ARGSUSED*/
 int
+spoolss_s_EnumForms(void *arg, ndr_xa_t *mxa)
+{
+	struct spoolss_EnumForms *param = arg;
+	DWORD status = ERROR_SUCCESS;
+
+	param->status = status;
+	param->needed = 0;
+	return (NDR_DRC_OK);
+}
+
+/*ARGSUSED*/
+int
+spoolss_s_EnumJobs(void *arg, ndr_xa_t *mxa)
+{
+	struct spoolss_EnumJobs *param = arg;
+	DWORD status = ERROR_SUCCESS;
+
+	switch (param->level) {
+	case 1:
+	case 2:
+	case 3:
+	case 4:
+	default:
+		break;
+	}
+
+	param->status = status;
+	param->needed = 0;
+	param->needed2 = 0;
+	return (NDR_DRC_OK);
+}
+
+
+/*ARGSUSED*/
+static int
+spoolss_s_GetJob(void *arg, ndr_xa_t *mxa)
+{
+	struct spoolss_GetJob *param = arg;
+	DWORD status = ERROR_SUCCESS;
+
+	if (param->BufCount == 0)
+		param->status = ERROR_INSUFFICIENT_BUFFER;
+	else
+		param->status = status;
+	param->needed = 0;
+	return (NDR_DRC_OK);
+}
+
+
+/*ARGSUSED*/
+static int
+spoolss_s_ScheduleJob(void *arg, ndr_xa_t *mxa)
+{
+	struct spoolss_ScheduleJob *param = arg;
+	DWORD status = SPOOLSS_JOB_NOT_ISSUED;
+
+	param->status = status;
+	return (NDR_DRC_OK);
+}
+
+/*ARGSUSED*/
+static int
+spoolss_s_AddJob(void *arg, ndr_xa_t *mxa)
+{
+	struct spoolss_AddJob *param = arg;
+
+	param->status = ERROR_SUCCESS;
+	param->needed = 0;
+	return (NDR_DRC_OK);
+}
+
+/*ARGSUSED*/
+static int
+spoolss_s_rfnpcnex(void *arg, ndr_xa_t *mxa)
+{
+	struct spoolss_RFNPCNEX *param = arg;
+
+	param->ppinfo = 0;
+	param->status = ERROR_SUCCESS;
+	return (NDR_DRC_OK);
+}
+
+/*
+ * Use the RPC context handle to find the fd and write the document content.
+ */
+static int
+spoolss_s_WritePrinter(void *arg, ndr_xa_t *mxa)
+{
+	struct spoolss_WritePrinter *param = arg;
+	int written = 0;
+	ndr_hdid_t *id = (ndr_hdid_t *)&param->handle;
+	int spfd;
+
+	if (ndr_hdlookup(mxa, id) == NULL) {
+		param->written = 0;
+		param->status = ERROR_INVALID_HANDLE;
+		syslog(LOG_ERR, "spoolss_s_WritePrinter: invalid handle");
+		return (NDR_DRC_OK);
+	}
+
+	if ((spfd = spoolss_find_fd(id)) < 0) {
+		param->written = 0;
+		param->status = ERROR_INVALID_HANDLE;
+		syslog(LOG_ERR, "spoolss_s_WritePrinter: cannot find fd");
+		return (NDR_DRC_OK);
+	}
+
+	written = write(spfd, param->pBuf, param->BufCount);
+	if (written < param->BufCount) {
+		syslog(LOG_ERR, "spoolss_s_WritePrinter: write failed");
+		param->written = 0;
+		param->status = ERROR_CANTWRITE;
+		return (NDR_DRC_OK);
+	}
+
+	param->written = written;
+	param->status = ERROR_SUCCESS;
+	return (NDR_DRC_OK);
+}
+
+/*
+ * All versions of windows use this function to print
+ * spool files via the cups interface
+ */
+
+void
+spoolss_copy_spool_file(smb_inaddr_t *ipaddr, char *username,
+    char *path, char *doc_name)
+{
+	smb_cups_ops_t	*cups;
+	int		ret = 1;		/* Return value */
+	http_t		*http = NULL;		/* HTTP connection to server */
+	ipp_t		*request = NULL;	/* IPP Request */
+	ipp_t		*response = NULL;	/* IPP Response */
+	cups_lang_t	*language = NULL;	/* Default language */
+	char		uri[HTTP_MAX_URI];	/* printer-uri attribute */
+	char		new_jobname[SPOOLSS_PJOBLEN];
+	struct		spoolss_printjob pjob;
+	char 		clientname[INET6_ADDRSTRLEN];
+	struct stat 	sbuf;
+
+	if (stat(path, &sbuf)) {
+		syslog(LOG_INFO, "spoolss_copy_spool_file: %s: %s",
+		    path, strerror(errno));
+		return;
+	}
+
+	/*
+	 * Remove zero size files and return; these were inadvertantly
+	 * created by XP or 2000.
+	 */
+	if (sbuf.st_blocks == 0) {
+		if (remove(path))
+			syslog(LOG_INFO,
+			    "spoolss_copy_spool_file: cannot remove %s", path);
+		return;
+	}
+
+	if ((cups = spoolss_cups_ops()) == NULL)
+		return;
+
+	if ((http = cups->httpConnect("localhost", 631)) == NULL) {
+		syslog(LOG_INFO, "spoolss_copy_spool_file: cupsd not running");
+		return;
+	}
+
+	if ((request = cups->ippNew()) == NULL) {
+		syslog(LOG_INFO, "spoolss_copy_spool_file: ipp not running");
+		return;
+	}
+	request->request.op.operation_id = IPP_PRINT_JOB;
+	request->request.op.request_id = 1;
+	language = cups->cupsLangDefault();
+
+	cups->ippAddString(request, IPP_TAG_OPERATION, IPP_TAG_CHARSET,
+	    "attributes-charset", NULL, cups->cupsLangEncoding(language));
+
+	cups->ippAddString(request, IPP_TAG_OPERATION, IPP_TAG_LANGUAGE,
+	    "attributes-natural-language", NULL, language->language);
+
+	(void) snprintf(uri, sizeof (uri), "ipp://localhost/printers/%s",
+	    SPOOLSS_PRINTER);
+	pjob.pj_pid = pthread_self();
+	pjob.pj_sysjob = 10;
+	(void) strlcpy(pjob.pj_filename, path, SPOOLSS_PJOBLEN);
+	pjob.pj_start_time = time(NULL);
+	pjob.pj_status = 2;
+	pjob.pj_size = sbuf.st_blocks * 512;
+	pjob.pj_page_count = 1;
+	pjob.pj_isspooled = B_TRUE;
+	pjob.pj_jobnum = spoolss_jobnum;
+
+	(void) strlcpy(pjob.pj_jobname, doc_name, SPOOLSS_PJOBLEN);
+	(void) strlcpy(pjob.pj_username, username, SPOOLSS_PJOBLEN);
+	(void) strlcpy(pjob.pj_queuename, SPOOLSS_CUPS_SPOOL_DIR,
+	    SPOOLSS_PJOBLEN);
+	cups->ippAddString(request, IPP_TAG_OPERATION, IPP_TAG_URI,
+	    "printer-uri", NULL, uri);
+
+	cups->ippAddString(request, IPP_TAG_OPERATION, IPP_TAG_NAME,
+	    "requesting-user-name", NULL, pjob.pj_username);
+
+	if (smb_inet_ntop(ipaddr, clientname,
+	    SMB_IPSTRLEN(ipaddr->a_family)) == NULL) {
+		syslog(LOG_INFO, "spoolss_copy_spool_file: %s: unknown client",
+		    clientname);
+		goto out;
+	}
+	cups->ippAddString(request, IPP_TAG_OPERATION, IPP_TAG_NAME,
+	    "job-originating-host-name", NULL, clientname);
+
+	(void) snprintf(new_jobname, SPOOLSS_PJOBLEN, "%s%d",
+	    SPOOLSS_FN_PREFIX, pjob.pj_jobnum);
+	cups->ippAddString(request, IPP_TAG_OPERATION, IPP_TAG_NAME,
+	    "job-name", NULL, new_jobname);
+
+	(void) snprintf(uri, sizeof (uri) - 1, "/printers/%s", SPOOLSS_PRINTER);
+
+	response = cups->cupsDoFileRequest(http, request, uri,
+	    pjob.pj_filename);
+	if (response != NULL) {
+		if (response->request.status.status_code >= IPP_OK_CONFLICT) {
+			syslog(LOG_ERR,
+			    "spoolss_copy_spool_file: file print %s: %s",
+			    SPOOLSS_PRINTER,
+			    cups->ippErrorString(cups->cupsLastError()));
+		} else {
+			atomic_inc_32(&spoolss_jobnum);
+			ret = 0;
+		}
+	} else {
+		syslog(LOG_ERR,
+		    "spoolss_copy_spool_file: unable to print file to %s",
+		    cups->ippErrorString(cups->cupsLastError()));
+	}
+
+	if (ret == 0)
+		(void) unlink(pjob.pj_filename);
+
+out:
+	if (response)
+		cups->ippDelete(response);
+
+	if (language)
+		cups->cupsLangFree(language);
+
+	if (http)
+		cups->httpClose(http);
+}
+
+static int
+spoolss_s_GetPrinterData(void *arg, ndr_xa_t *mxa)
+{
+	struct spoolss_GetPrinterData *param = arg;
+	DWORD status = ERROR_SUCCESS;
+
+	if (param->Size > 0) {
+		param->Buf = NDR_NEWN(mxa, char, param->Size);
+		bzero(param->Buf, param->Size);
+	} else {
+		param->Buf = NDR_NEWN(mxa, uint32_t, 1);
+		param->Buf[0] = 1;
+		param->Buf[1] = 1;
+		param->Buf[2] = 2;
+		param->Buf[3] = 2;
+	}
+
+	/*
+	 * Increment pType if the Printer Data changes
+	 * as specified by Microsoft documentation
+	 */
+	param->pType = 1;
+	if (strcasecmp((char *)param->pValueName, "ChangeId") == 0) {
+		param->pType = 4;
+		param->Buf[3] = 0x00;
+		param->Buf[2] = 0x50;
+		param->Buf[1] = 0xac;
+		param->Buf[0] = 0xf2;
+	} else if (strcasecmp((char *)param->pValueName,
+	    "UISingleJobStatusString") == 0) {
+		status = ERROR_FILE_NOT_FOUND;
+	} else if (strcasecmp((char *)param->pValueName,
+	    "W3SvcInstalled") == 0) {
+		status = ERROR_FILE_NOT_FOUND;
+	} else if (strcasecmp((char *)param->pValueName,
+	    "PrintProcCaps_NT EMF 1.008") == 0) {
+		status = ERROR_FILE_NOT_FOUND;
+	} else if (strcasecmp((char *)param->pValueName, "OSVersion") == 0) {
+		param->Buf = NDR_NEWN(mxa, char, param->Size);
+		bzero(param->Buf, param->Size);
+		param->Buf[0] = 0x14;
+		param->Buf[1] = 0x01;
+		param->Buf[4] = 0x05;
+		param->Buf[12] = 0x93;
+		param->Buf[13] = 0x08;
+	}
+	param->status = status;
+	param->Needed = param->Size;
+	return (NDR_DRC_OK);
+}
+
+smb_cups_ops_t *
+spoolss_cups_ops(void)
+{
+	if (spoolss_cups_init() != 0)
+		return (NULL);
+
+	return (&smb_cups);
+}
+
+static int
+spoolss_cups_init(void)
+{
+	(void) mutex_lock(&spoolss_cups_mutex);
+
+	if (smb_cups.cups_hdl != NULL) {
+		(void) mutex_unlock(&spoolss_cups_mutex);
+		return (0);
+	}
+
+	if ((smb_cups.cups_hdl = dlopen("libcups.so.2", RTLD_NOW)) == NULL) {
+		(void) mutex_unlock(&spoolss_cups_mutex);
+		syslog(LOG_DEBUG, "spoolss_cups_init: cannot open libcups");
+		return (ENOENT);
+	}
+
+	smb_cups.cupsLangDefault =
+	    (cups_lang_t *(*)())dlsym(smb_cups.cups_hdl, "cupsLangDefault");
+	smb_cups.cupsLangEncoding = (const char *(*)(cups_lang_t *))
+	    dlsym(smb_cups.cups_hdl, "cupsLangEncoding");
+	smb_cups.cupsDoFileRequest =
+	    (ipp_t *(*)(http_t *, ipp_t *, const char *, const char *))
+	    dlsym(smb_cups.cups_hdl, "cupsDoFileRequest");
+	smb_cups.cupsLastError = (ipp_status_t (*)())
+	    dlsym(smb_cups.cups_hdl, "cupsLastError");
+	smb_cups.cupsLangFree = (void (*)(cups_lang_t *))
+	    dlsym(smb_cups.cups_hdl, "cupsLangFree");
+	smb_cups.cupsGetDests = (int (*)(cups_dest_t **))
+	    dlsym(smb_cups.cups_hdl, "cupsGetDests");
+	smb_cups.cupsFreeDests = (void (*)(int, cups_dest_t *))
+	    dlsym(smb_cups.cups_hdl, "cupsFreeDests");
+
+	smb_cups.httpClose = (void (*)(http_t *))
+	    dlsym(smb_cups.cups_hdl, "httpClose");
+	smb_cups.httpConnect = (http_t *(*)(const char *, int))
+	    dlsym(smb_cups.cups_hdl, "httpConnect");
+
+	smb_cups.ippNew = (ipp_t *(*)())dlsym(smb_cups.cups_hdl, "ippNew");
+	smb_cups.ippDelete = (void (*)())dlsym(smb_cups.cups_hdl, "ippDelete");
+	smb_cups.ippErrorString = (char *(*)())
+	    dlsym(smb_cups.cups_hdl, "ippErrorString");
+	smb_cups.ippAddString = (ipp_attribute_t *(*)())
+	    dlsym(smb_cups.cups_hdl, "ippAddString");
+
+	if (smb_cups.cupsLangDefault == NULL ||
+	    smb_cups.cupsLangEncoding == NULL ||
+	    smb_cups.cupsDoFileRequest == NULL ||
+	    smb_cups.cupsLastError == NULL ||
+	    smb_cups.cupsLangFree == NULL ||
+	    smb_cups.cupsGetDests == NULL ||
+	    smb_cups.cupsFreeDests == NULL ||
+	    smb_cups.ippNew == NULL ||
+	    smb_cups.httpClose == NULL ||
+	    smb_cups.httpConnect == NULL ||
+	    smb_cups.ippDelete == NULL ||
+	    smb_cups.ippErrorString == NULL ||
+	    smb_cups.ippAddString == NULL) {
+		smb_dlclose(smb_cups.cups_hdl);
+		smb_cups.cups_hdl = NULL;
+		(void) mutex_unlock(&spoolss_cups_mutex);
+		syslog(LOG_DEBUG, "spoolss_cups_init: cannot load libcups");
+		return (ENOENT);
+	}
+
+	(void) mutex_unlock(&spoolss_cups_mutex);
+	return (0);
+}
+
+static void
+spoolss_cups_fini(void)
+{
+	(void) mutex_lock(&spoolss_cups_mutex);
+
+	if (smb_cups.cups_hdl != NULL) {
+		smb_dlclose(smb_cups.cups_hdl);
+		smb_cups.cups_hdl = NULL;
+	}
+
+	(void) mutex_unlock(&spoolss_cups_mutex);
+}
+
+void
+smb_rpc_off(char *dst, char *src, uint32_t *offset, uint32_t *outoffset)
+{
+	int nwchars;
+	int bytes;
+
+	bytes = smb_wcequiv_strlen(src) + 2;
+	nwchars = strlen(src) + 1;
+	*offset -= bytes;
+	*outoffset = *offset;
+	/*LINTED E_BAD_PTR_CAST_ALIGN*/
+	(void) smb_mbstowcs(((smb_wchar_t *)(dst + *offset)), src, nwchars);
+}
+
+int
+spoolss_s_GetPrinter(void *arg, ndr_xa_t *mxa)
+{
+	struct spoolss_GetPrinter *param = arg;
+	struct spoolss_GetPrinter0 *pinfo0;
+	struct spoolss_GetPrinter1 *pinfo1;
+	struct spoolss_GetPrinter2 *pinfo2;
+	struct spoolss_DeviceMode *devmode2;
+	DWORD status = ERROR_SUCCESS;
+	char *wname;
+	uint32_t offset;
+	smb_inaddr_t ipaddr;
+	struct hostent *h;
+	char hname[MAXHOSTNAMELEN];
+	char soutbuf[MAXNAMELEN];
+	char poutbuf[MAXNAMELEN];
+	char ipstr[INET6_ADDRSTRLEN];
+	int error;
+	uint8_t *tmpbuf;
+
+	if (param->BufCount == 0) {
+		status = ERROR_INSUFFICIENT_BUFFER;
+		goto error_out;
+	}
+	param->Buf = NDR_NEWN(mxa, char, param->BufCount);
+	bzero(param->Buf, param->BufCount);
+	switch (param->switch_value) {
+	case 0:
+		/*LINTED E_BAD_PTR_CAST_ALIGN*/
+		pinfo0 = (struct spoolss_GetPrinter0 *)param->Buf;
+		break;
+	case 1:
+		/*LINTED E_BAD_PTR_CAST_ALIGN*/
+		pinfo1 = (struct spoolss_GetPrinter1 *)param->Buf;
+		break;
+	case 2:
+		/*LINTED E_BAD_PTR_CAST_ALIGN*/
+		pinfo2 = (struct spoolss_GetPrinter2 *)param->Buf;
+		break;
+	}
+	wname = (char *)param->Buf;
+
+	status = ERROR_INVALID_PARAMETER;
+	if (smb_gethostname(hname, MAXHOSTNAMELEN, 0) != 0) {
+		syslog(LOG_NOTICE, "spoolss_s_GetPrinter: gethostname failed");
+		goto error_out;
+	}
+	if ((h = smb_gethostbyname(hname, &error)) == NULL) {
+		syslog(LOG_NOTICE,
+		    "spoolss_s_GetPrinter: gethostbyname failed");
+		goto error_out;
+	}
+	bcopy(h->h_addr, &ipaddr, h->h_length);
+	ipaddr.a_family = h->h_addrtype;
+	freehostent(h);
+	if (smb_inet_ntop(&ipaddr, ipstr, SMB_IPSTRLEN(ipaddr.a_family))
+	    == NULL) {
+		syslog(LOG_NOTICE, "spoolss_s_GetPrinter: inet_ntop failed");
+		goto error_out;
+	}
+	status = ERROR_SUCCESS;
+	(void) snprintf(poutbuf, MAXNAMELEN, "\\\\%s\\%s",
+	    ipstr, SPOOLSS_PRINTER);
+	(void) snprintf(soutbuf, MAXNAMELEN, "\\\\%s", ipstr);
+	param->needed = 0;
+	switch (param->switch_value) {
+	case 0:
+		offset = 460;
+		smb_rpc_off(wname, "", &offset, &pinfo0->servername);
+		smb_rpc_off(wname, poutbuf, &offset, &pinfo0->printername);
+		pinfo0->cjobs = 0;
+		pinfo0->total_jobs = 6;
+		pinfo0->total_bytes = 1040771;
+		pinfo0->time0 = 0;
+		pinfo0->time1 = 0;
+		pinfo0->time2 = 3;
+		pinfo0->time3 = 0;
+		pinfo0->global_counter = 2162710;
+		pinfo0->total_pages = 21495865;
+		pinfo0->version = 10;
+		pinfo0->session_counter = 1;
+		pinfo0->job_error = 0x6;
+		pinfo0->change_id  = 0x1;
+		pinfo0->status = 0;
+		pinfo0->c_setprinter = 0;
+		break;
+	case 1:
+		pinfo1->flags = PRINTER_ENUM_ICON8;
+		offset = 460;
+		smb_rpc_off(wname, poutbuf, &offset, &pinfo1->flags);
+		smb_rpc_off(wname, poutbuf, &offset, &pinfo1->description);
+		smb_rpc_off(wname, poutbuf, &offset, &pinfo1->comment);
+		break;
+	case 2:
+		offset = param->BufCount;
+		smb_rpc_off(wname, soutbuf, &offset, &pinfo2->servername);
+		smb_rpc_off(wname, poutbuf, &offset, &pinfo2->printername);
+		smb_rpc_off(wname, SPOOLSS_PRINTER, &offset,
+		    &pinfo2->sharename);
+		smb_rpc_off(wname, "CIFS Printer Port", &offset,
+		    &pinfo2->portname);
+		smb_rpc_off(wname, "", &offset, &pinfo2->drivername);
+		smb_rpc_off(wname, SPOOLSS_PRINTER, &offset,
+		    &pinfo2->comment);
+		smb_rpc_off(wname, "farside", &offset, &pinfo2->location);
+		smb_rpc_off(wname, "farside", &offset, &pinfo2->sepfile);
+		smb_rpc_off(wname, "winprint", &offset,
+		    &pinfo2->printprocessor);
+		smb_rpc_off(wname, "RAW", &offset, &pinfo2->datatype);
+		smb_rpc_off(wname, "", &offset, &pinfo2->datatype);
+		pinfo2->attributes = 0x00001048;
+		pinfo2->status = 0x00000000;
+		pinfo2->starttime = 0;
+		pinfo2->untiltime = 0;
+		pinfo2->cjobs = 0;
+		pinfo2->averageppm = 0;
+		pinfo2->defaultpriority = 0;
+		pinfo2->devmode = 568; // offset
+		/*LINTED E_BAD_PTR_CAST_ALIGN*/
+		devmode2 = (struct spoolss_DeviceMode *)(param->Buf
+		    + pinfo2->devmode);
+		/*LINTED E_BAD_PTR_CAST_ALIGN*/
+		(void) smb_mbstowcs(((smb_wchar_t *)
+		    (devmode2->devicename)), (const char *)poutbuf, 25);
+		devmode2->specversion = 0x0401;
+		devmode2->driverversion = 1024;
+		devmode2->size = 220;
+		devmode2->driverextra_length = 0;
+		devmode2->fields = 0x00014713;
+		devmode2->orientation = 1;
+		devmode2->papersize = 1;
+		devmode2->paperlength = 0;
+		devmode2->paperwidth = 0;
+		devmode2->scale = 100;
+		devmode2->copies = 1;
+		devmode2->defaultsource = 15;
+		devmode2->printquality = 65532;
+		devmode2->color = 1;
+		devmode2->duplex = 1;
+		devmode2->yresolution = 1;
+		devmode2->ttoption = 1;
+		devmode2->collate = 0;
+		/*LINTED E_BAD_PTR_CAST_ALIGN*/
+		(void) smb_mbstowcs(((smb_wchar_t *)
+		    (devmode2->formname)), (const char *)"Letter", 6);
+		devmode2->logpixels = 0;
+		devmode2->bitsperpel = 0;
+		devmode2->pelswidth = 0;
+		devmode2->pelsheight = 0;
+		devmode2->displayflags = 0;
+		devmode2->displayfrequency = 0;
+		devmode2->icmmethod = 0;
+		devmode2->icmintent = 0;
+		devmode2->mediatype = 0;
+		devmode2->dithertype = 0;
+		devmode2->reserved1 = 0;
+		devmode2->reserved2 = 0;
+		devmode2->panningwidth = 0;
+		devmode2->panningheight = 0;
+
+		pinfo2->secdesc = 84;
+		tmpbuf = (uint8_t *)(pinfo2->secdesc + (uint8_t *)param->Buf);
+		error = spoolss_s_make_sd(tmpbuf);
+		param->needed = 712;
+		break;
+
+	default:
+		syslog(LOG_NOTICE, "spoolss_s_GetPrinter: INVALID_LEVEL");
+		status = ERROR_INVALID_LEVEL;
+		break;
+
+	}
+error_out:
+	param->status = status;
+	return (NDR_DRC_OK);
+}
+
+int
+spoolss_s_make_sd(uint8_t *sd_buf)
+{
+	smb_sd_t			sd;
+	uint32_t			status;
+
+	bzero(&sd, sizeof (smb_sd_t));
+
+	if ((status = spoolss_sd_format(&sd)) == ERROR_SUCCESS) {
+		status = srvsvc_sd_set_relative(&sd, sd_buf);
+		smb_sd_term(&sd);
+		return (NDR_DRC_OK);
+	}
+	syslog(LOG_NOTICE, "spoolss_s_make_sd: error status=%d", status);
+	smb_sd_term(&sd);
+	return (NDR_DRC_OK);
+}
+
+static uint32_t
+spoolss_sd_format(smb_sd_t *sd)
+{
+	smb_fssd_t	fs_sd;
+	acl_t		*acl;
+	uint32_t	status = ERROR_SUCCESS;
+
+	if (acl_fromtext("everyone@:full_set::allow", &acl) != 0) {
+		syslog(LOG_ERR, "spoolss_sd_format: NOT_ENOUGH_MEMORY");
+		return (ERROR_NOT_ENOUGH_MEMORY);
+	}
+	smb_fssd_init(&fs_sd, SMB_ALL_SECINFO, SMB_FSSD_FLAGS_DIR);
+	fs_sd.sd_uid = 0;
+	fs_sd.sd_gid = 0;
+	fs_sd.sd_zdacl = acl;
+	fs_sd.sd_zsacl = NULL;
+
+	if (smb_sd_fromfs(&fs_sd, sd) != NT_STATUS_SUCCESS) {
+		syslog(LOG_NOTICE, "spoolss_sd_format: ACCESS_DENIED");
+		status = ERROR_ACCESS_DENIED;
+	}
+	smb_fssd_term(&fs_sd);
+	return (status);
+}
+
+/*ARGSUSED*/
+static int
 spoolss_s_stub(void *arg, ndr_xa_t *mxa)
 {
 	return (NDR_DRC_FAULT_PARAM_0_UNIMPLEMENTED);
 }
+
+/*ARGSUSED*/
+void
+fixup_spoolss_RFNPCNEX(struct spoolss_RFNPCNEX *val)
+{
+	unsigned short size1 = 0;
+	unsigned short size2 = 0;
+	unsigned short size3 = 0;
+	struct spoolss_RPC_V2_NOTIFY_INFO *pinfo;
+
+	pinfo = val->ppinfo->pinfo;
+	switch (pinfo->aData->Reserved) {
+	case TABLE_STRING:
+		size1 = sizeof (struct STRING_CONTAINER);
+		break;
+	case TABLE_DWORD:
+		size1 = sizeof (DWORD) * 2;
+		break;
+	case TABLE_TIME:
+		size1 = sizeof (struct SYSTEMTIME_CONTAINER);
+		break;
+	case TABLE_DEVMODE:
+		size1 = sizeof (struct spoolssDevmodeContainer);
+		break;
+	case TABLE_SECURITY_DESCRIPTOR:
+		size1 = sizeof (struct SECURITY_CONTAINER);
+		break;
+	default:
+		return;
+	}
+	size2 = size1 + (2 * sizeof (DWORD));
+	size3 = size2 + sizeof (ndr_request_hdr_t) + sizeof (DWORD);
+
+	FIXUP_PDU_SIZE(spoolss_RPC_V2_NOTIFY_INFO_DATA_DATA, size1);
+	FIXUP_PDU_SIZE(spoolss_RPC_V2_NOTIFY_INFO_DATA, size2);
+	FIXUP_PDU_SIZE(spoolss_RPC_V2_NOTIFY_INFO, size3);
+	FIXUP_PDU_SIZE(spoolss_RFNPCNEX, size3);
+}
+
+void
+fixup_spoolss_GetPrinter(struct spoolss_GetPrinter *val)
+{
+	unsigned short size1 = 0;
+	unsigned short size2 = 0;
+	unsigned short size3 = 0;
+
+	switch (val->switch_value) {
+	CASE_INFO_ENT(spoolss_GetPrinter, 0);
+	CASE_INFO_ENT(spoolss_GetPrinter, 1);
+	CASE_INFO_ENT(spoolss_GetPrinter, 2);
+	CASE_INFO_ENT(spoolss_GetPrinter, 3);
+	CASE_INFO_ENT(spoolss_GetPrinter, 4);
+	CASE_INFO_ENT(spoolss_GetPrinter, 5);
+	CASE_INFO_ENT(spoolss_GetPrinter, 6);
+	CASE_INFO_ENT(spoolss_GetPrinter, 7);
+	CASE_INFO_ENT(spoolss_GetPrinter, 8);
+
+	default:
+		return;
+	};
+
+	size2 = size1 + (2 * sizeof (DWORD));
+	size3 = size2 + sizeof (ndr_request_hdr_t) + sizeof (DWORD);
+
+	FIXUP_PDU_SIZE(spoolss_GetPrinter_result_u, size1);
+	FIXUP_PDU_SIZE(spoolss_GetPrinter_result, size2);
+	FIXUP_PDU_SIZE(spoolss_GetPrinter, size3);
+}
--- a/usr/src/lib/smbsrv/libmlsvc/common/srvsvc_svc.c	Thu Jul 22 12:31:36 2010 -0700
+++ b/usr/src/lib/smbsrv/libmlsvc/common/srvsvc_svc.c	Thu Jul 22 14:53:56 2010 -0700
@@ -1330,6 +1330,7 @@
 srvsvc_get_share_flags(smb_share_t *si)
 {
 	uint32_t flags = 0;
+	boolean_t shortnames = B_TRUE;
 
 	switch (si->shr_flags & SMB_SHRF_CSC_MASK) {
 	case SMB_SHRF_CSC_DISABLED:
@@ -1352,6 +1353,12 @@
 	if (si->shr_flags & SMB_SHRF_ABE)
 		flags |= SHI1005_FLAGS_ACCESS_BASED_DIRECTORY_ENUM;
 
+	/* if 'smb' zfs property: shortnames=disabled */
+	if ((smb_kmod_shareinfo(si->shr_name, &shortnames) == 0) &&
+	    (shortnames == B_FALSE)) {
+		flags |= SHI1005_FLAGS_ALLOW_NAMESPACE_CACHING;
+	}
+
 	return (flags);
 }
 
--- a/usr/src/lib/smbsrv/libsmb/common/libsmb.h	Thu Jul 22 12:31:36 2010 -0700
+++ b/usr/src/lib/smbsrv/libsmb/common/libsmb.h	Thu Jul 22 14:53:56 2010 -0700
@@ -144,6 +144,7 @@
 	SMB_CI_KPASSWD_SEQNUM,
 	SMB_CI_NETLOGON_SEQNUM,
 	SMB_CI_IPV6_ENABLE,
+	SMB_CI_PRINT_ENABLE,
 	SMB_CI_MAP,
 	SMB_CI_UNMAP,
 	SMB_CI_DISPOSITION,
@@ -226,6 +227,23 @@
 extern void smb_config_setdomaininfo(char *, char *, char *, char *, char *);
 extern uint32_t smb_get_dcinfo(char *, uint32_t, smb_inaddr_t *);
 
+CONTEXT_HANDLE(rpc_handle) rpc_handle_t;
+
+typedef struct smb_spooldoc {
+	uint32_t	sd_magic;
+	list_node_t	sd_lnd;
+	smb_inaddr_t	sd_ipaddr;
+	int		sd_spool_num;
+	char		sd_username[MAXNAMELEN];
+	char		sd_path[MAXPATHLEN];
+	char		sd_doc_name[MAXNAMELEN];
+	char		sd_printer_name[MAXPATHLEN];
+	int32_t		sd_fd;
+	rpc_handle_t	sd_handle;
+} smb_spooldoc_t;
+
+int smb_kmod_get_spool_doc(uint32_t *, char *, char *, smb_inaddr_t *);
+
 /*
  * buffer context structure. This is used to keep track of the buffer
  * context.
@@ -889,6 +907,7 @@
 void smb_kmod_unbind(void);
 int smb_kmod_share(nvlist_t *);
 int smb_kmod_unshare(nvlist_t *);
+int smb_kmod_shareinfo(char *, boolean_t *);
 int smb_kmod_get_open_num(smb_opennum_t *);
 int smb_kmod_enum(smb_netsvc_t *);
 smb_netsvc_t *smb_kmod_enum_init(smb_svcenum_t *);
--- a/usr/src/lib/smbsrv/libsmb/common/mapfile-vers	Thu Jul 22 12:31:36 2010 -0700
+++ b/usr/src/lib/smbsrv/libsmb/common/mapfile-vers	Thu Jul 22 14:53:56 2010 -0700
@@ -220,12 +220,14 @@
 	smb_kmod_event_notify;
 	smb_kmod_file_close;
         smb_kmod_get_open_num;
+	smb_kmod_get_spool_doc;
 	smb_kmod_nbtlisten;
 	smb_kmod_nbtreceive;
 	smb_kmod_session_close;
 	smb_kmod_setcfg;
 	smb_kmod_setgmtoff;
 	smb_kmod_share;
+	smb_kmod_shareinfo;
 	smb_kmod_start;
 	smb_kmod_stop;
 	smb_kmod_tcplisten;
--- a/usr/src/lib/smbsrv/libsmb/common/smb_cfg.c	Thu Jul 22 12:31:36 2010 -0700
+++ b/usr/src/lib/smbsrv/libsmb/common/smb_cfg.c	Thu Jul 22 14:53:56 2010 -0700
@@ -128,6 +128,7 @@
 	{SMB_CI_NETLOGON_SEQNUM, "netlogon_seqnum", SCF_TYPE_INTEGER,
 	    0},
 	{SMB_CI_IPV6_ENABLE, "ipv6_enable", SCF_TYPE_BOOLEAN, 0},
+	{SMB_CI_PRINT_ENABLE, "print_enable", SCF_TYPE_BOOLEAN, 0},
 	{SMB_CI_MAP, "map", SCF_TYPE_ASTRING, SMB_CF_EXEC},
 	{SMB_CI_UNMAP, "unmap", SCF_TYPE_ASTRING, SMB_CF_EXEC},
 	{SMB_CI_DISPOSITION, "disposition", SCF_TYPE_ASTRING, SMB_CF_EXEC},
--- a/usr/src/lib/smbsrv/libsmb/common/smb_info.c	Thu Jul 22 12:31:36 2010 -0700
+++ b/usr/src/lib/smbsrv/libsmb/common/smb_info.c	Thu Jul 22 14:53:56 2010 -0700
@@ -89,6 +89,7 @@
 	kcfg->skc_signing_enable = smb_config_getbool(SMB_CI_SIGNING_ENABLE);
 	kcfg->skc_signing_required = smb_config_getbool(SMB_CI_SIGNING_REQD);
 	kcfg->skc_ipv6_enable = smb_config_getbool(SMB_CI_IPV6_ENABLE);
+	kcfg->skc_print_enable = smb_config_getbool(SMB_CI_PRINT_ENABLE);
 	kcfg->skc_oplock_enable = smb_config_getbool(SMB_CI_OPLOCK_ENABLE);
 	kcfg->skc_sync_enable = smb_config_getbool(SMB_CI_SYNC_ENABLE);
 	kcfg->skc_secmode = smb_config_get_secmode();
--- a/usr/src/lib/smbsrv/libsmb/common/smb_kmod.c	Thu Jul 22 12:31:36 2010 -0700
+++ b/usr/src/lib/smbsrv/libsmb/common/smb_kmod.c	Thu Jul 22 14:53:56 2010 -0700
@@ -78,6 +78,7 @@
 	ioc.sync_enable = cfg->skc_sync_enable;
 	ioc.secmode = cfg->skc_secmode;
 	ioc.ipv6_enable = cfg->skc_ipv6_enable;
+	ioc.print_enable = cfg->skc_print_enable;
 	ioc.exec_flags = cfg->skc_execflags;
 	ioc.version = cfg->skc_version;
 
@@ -213,6 +214,24 @@
 }
 
 int
+smb_kmod_shareinfo(char *shrname, boolean_t *shortnames)
+{
+	smb_ioc_shareinfo_t ioc;
+	int rc;
+
+	bzero(&ioc, sizeof (ioc));
+	(void) strlcpy(ioc.shrname, shrname, MAXNAMELEN);
+
+	rc = smb_kmod_ioctl(SMB_IOC_SHAREINFO, &ioc.hdr, sizeof (ioc));
+	if (rc == 0)
+		*shortnames = ioc.shortnames;
+	else
+		*shortnames = B_TRUE;
+
+	return (rc);
+}
+
+int
 smb_kmod_get_open_num(smb_opennum_t *opennum)
 {
 	smb_ioc_opennum_t ioc;
@@ -232,6 +251,24 @@
 	return (rc);
 }
 
+int
+smb_kmod_get_spool_doc(uint32_t *spool_num, char *username,
+    char *path, smb_inaddr_t *ipaddr)
+{
+	smb_ioc_spooldoc_t ioc;
+	int rc;
+
+	bzero(&ioc, sizeof (ioc));
+	rc = smb_kmod_ioctl(SMB_IOC_SPOOLDOC, &ioc.hdr, sizeof (ioc));
+	if (rc == 0) {
+		*spool_num = ioc.spool_num;
+		(void) strlcpy(username, ioc.username, MAXNAMELEN);
+		(void) strlcpy(path, ioc.path, MAXPATHLEN);
+		*ipaddr = ioc.ipaddr;
+	}
+	return (rc);
+}
+
 /*
  * Initialization for an smb_kmod_enum request.  If this call succeeds,
  * smb_kmod_enum_fini() must be called later to deallocate resources.
--- a/usr/src/uts/common/fs/smbsrv/smb_common_open.c	Thu Jul 22 12:31:36 2010 -0700
+++ b/usr/src/uts/common/fs/smbsrv/smb_common_open.c	Thu Jul 22 14:53:56 2010 -0700
@@ -43,6 +43,9 @@
 extern uint32_t smb_is_executable(char *);
 static void smb_delete_new_object(smb_request_t *);
 static int smb_set_open_timestamps(smb_request_t *, smb_ofile_t *, boolean_t);
+static void smb_open_oplock_break(smb_request_t *, smb_node_t *);
+static boolean_t smb_open_attr_only(smb_arg_open_t *);
+static boolean_t smb_open_overwrite(smb_arg_open_t *);
 
 /*
  * smb_access_generic_to_file
@@ -204,7 +207,6 @@
 	}
 
 	kmem_free(parg, sizeof (*parg));
-
 	return (status);
 }
 
@@ -232,10 +234,9 @@
  *
  * The following rules apply when processing a file open request:
  *
- * - Oplocks must be broken prior to share checking to prevent open
- * starvation due to batch oplocks.  Checking share reservations first
- * could potentially result in unnecessary open failures due to
- * open/close batching on the client.
+ * - Oplocks must be broken prior to share checking as the break may
+ *   cause other clients to close the file, which would affect sharing
+ *   checks.
  *
  * - Share checks must take place prior to access checks for correct
  * Windows semantics and to prevent unnecessary NFS delegation recalls.
@@ -243,7 +244,6 @@
  * - Oplocks must be acquired after open to ensure the correct
  * synchronization with NFS delegation and FEM installation.
  *
- *
  * DOS readonly bit rules
  *
  * 1. The creator of a readonly file can write to/modify the size of the file
@@ -315,6 +315,7 @@
 	int		lookup_flags = SMB_FOLLOW_LINKS;
 	uint32_t	uniq_fid;
 	smb_pathname_t	*pn = &op->fqi.fq_path;
+	smb_server_t	*sv = sr->sr_server;
 
 	is_dir = (op->create_options & FILE_DIRECTORY_FILE) ? 1 : 0;
 
@@ -341,7 +342,7 @@
 
 	if (sr->session->s_file_cnt >= SMB_SESSION_OFILE_MAX) {
 		ASSERT(sr->uid_user);
-		cmn_err(CE_NOTE, "smbd[%s\\%s]: TOO_MANY_OPENED_FILES",
+		cmn_err(CE_NOTE, "smbsrv[%s\\%s]: TOO_MANY_OPENED_FILES",
 		    sr->uid_user->u_domain, sr->uid_user->u_name);
 
 		smbsr_error(sr, NT_STATUS_TOO_MANY_OPENED_FILES,
@@ -360,12 +361,21 @@
 		break;
 
 	case STYPE_IPC:
+
+		if ((rc = smb_threshold_enter(&sv->sv_opipe_ct)) != 0) {
+			status = RPC_NT_SERVER_TOO_BUSY;
+			smbsr_error(sr, status, 0, 0);
+			return (status);
+		}
+
 		/*
 		 * No further processing for IPC, we need to either
 		 * raise an exception or return success here.
 		 */
 		if ((status = smb_opipe_open(sr)) != NT_STATUS_SUCCESS)
 			smbsr_error(sr, status, 0, 0);
+
+		smb_threshold_exit(&sv->sv_opipe_ct, sv);
 		return (status);
 
 	default:
@@ -558,8 +568,13 @@
 			}
 		}
 
-		if (smb_oplock_conflict(node, sr->session, op))
-			(void) smb_oplock_break(node, sr->session, B_FALSE);
+		/*
+		 * Oplock break is done prior to sharing checks as the break
+		 * may cause other clients to close the file which would
+		 * affect the sharing checks.
+		 */
+		smb_node_inc_opening_count(node);
+		smb_open_oplock_break(sr, node);
 
 		smb_node_wrlock(node);
 
@@ -573,6 +588,7 @@
 			    (!smb_sattr_check(op->fqi.fq_fattr.sa_dosattr,
 			    op->dattr))) {
 				smb_node_unlock(node);
+				smb_node_dec_opening_count(node);
 				smb_node_release(node);
 				smb_node_release(dnode);
 				smbsr_error(sr, NT_STATUS_ACCESS_DENIED,
@@ -586,6 +602,7 @@
 
 		if (status == NT_STATUS_SHARING_VIOLATION) {
 			smb_node_unlock(node);
+			smb_node_dec_opening_count(node);
 			smb_node_release(node);
 			smb_node_release(dnode);
 			return (status);
@@ -598,6 +615,7 @@
 			smb_fsop_unshrlock(sr->user_cr, node, uniq_fid);
 
 			smb_node_unlock(node);
+			smb_node_dec_opening_count(node);
 			smb_node_release(node);
 			smb_node_release(dnode);
 
@@ -619,6 +637,7 @@
 			if (smb_node_is_dir(node)) {
 				smb_fsop_unshrlock(sr->user_cr, node, uniq_fid);
 				smb_node_unlock(node);
+				smb_node_dec_opening_count(node);
 				smb_node_release(node);
 				smb_node_release(dnode);
 				smbsr_error(sr, NT_STATUS_ACCESS_DENIED,
@@ -641,6 +660,7 @@
 			if (rc != 0) {
 				smb_fsop_unshrlock(sr->user_cr, node, uniq_fid);
 				smb_node_unlock(node);
+				smb_node_dec_opening_count(node);
 				smb_node_release(node);
 				smb_node_release(dnode);
 				smbsr_errno(sr, rc);
@@ -657,6 +677,7 @@
 					smb_fsop_unshrlock(sr->user_cr, node,
 					    uniq_fid);
 					smb_node_unlock(node);
+					smb_node_dec_opening_count(node);
 					smb_node_release(node);
 					smb_node_release(dnode);
 					return (sr->smb_error.status);
@@ -741,6 +762,7 @@
 			}
 
 			node = op->fqi.fq_fnode;
+			smb_node_inc_opening_count(node);
 			smb_node_wrlock(node);
 
 			status = smb_fsop_shrlock(sr->user_cr, node, uniq_fid,
@@ -748,6 +770,7 @@
 
 			if (status == NT_STATUS_SHARING_VIOLATION) {
 				smb_node_unlock(node);
+				smb_node_dec_opening_count(node);
 				smb_delete_new_object(sr);
 				smb_node_release(node);
 				smb_node_unlock(dnode);
@@ -772,6 +795,7 @@
 			}
 
 			node = op->fqi.fq_fnode;
+			smb_node_inc_opening_count(node);
 			smb_node_wrlock(node);
 		}
 
@@ -833,6 +857,7 @@
 		if (created)
 			smb_delete_new_object(sr);
 		smb_node_unlock(node);
+		smb_node_dec_opening_count(node);
 		smb_node_release(node);
 		if (created)
 			smb_node_unlock(dnode);
@@ -861,12 +886,8 @@
 	sr->smb_fid = of->f_fid;
 	sr->fid_ofile = of;
 
-	smb_node_unlock(node);
-	if (created)
-		smb_node_unlock(dnode);
-
 	if (smb_node_is_file(node)) {
-		smb_oplock_acquire(node, of, op);
+		smb_oplock_acquire(sr, node, of);
 		op->dsize = op->fqi.fq_fattr.sa_vattr.va_size;
 	} else {
 		/* directory or symlink */
@@ -874,6 +895,12 @@
 		op->dsize = 0;
 	}
 
+	smb_node_dec_opening_count(node);
+
+	smb_node_unlock(node);
+	if (created)
+		smb_node_unlock(dnode);
+
 	smb_node_release(node);
 	smb_node_release(dnode);
 
@@ -881,6 +908,63 @@
 }
 
 /*
+ * smb_open_oplock_break
+ *
+ * If the node has an ofile opened with share access none,
+ * (smb_node_share_check = FALSE) only break BATCH oplock.
+ * Otherwise:
+ * If overwriting, break to SMB_OPLOCK_NONE, else
+ * If opening for anything other than attribute access,
+ * break oplock to LEVEL_II.
+ */
+static void
+smb_open_oplock_break(smb_request_t *sr, smb_node_t *node)
+{
+	smb_arg_open_t	*op = &sr->sr_open;
+	uint32_t	flags = 0;
+
+	if (!smb_node_share_check(node))
+		flags |= SMB_OPLOCK_BREAK_BATCH;
+
+	if (smb_open_overwrite(op)) {
+		flags |= SMB_OPLOCK_BREAK_TO_NONE;
+		(void) smb_oplock_break(sr, node, flags);
+	} else if (!smb_open_attr_only(op)) {
+		flags |= SMB_OPLOCK_BREAK_TO_LEVEL_II;
+		(void) smb_oplock_break(sr, node, flags);
+	}
+}
+
+/*
+ * smb_open_attr_only
+ *
+ * Determine if file is being opened for attribute access only.
+ * This is used to determine whether it is necessary to break
+ * existing oplocks on the file.
+ */
+static boolean_t
+smb_open_attr_only(smb_arg_open_t *op)
+{
+	if (((op->desired_access & ~(FILE_READ_ATTRIBUTES |
+	    FILE_WRITE_ATTRIBUTES | SYNCHRONIZE)) == 0) &&
+	    (op->create_disposition != FILE_SUPERSEDE) &&
+	    (op->create_disposition != FILE_OVERWRITE)) {
+		return (B_TRUE);
+	}
+	return (B_FALSE);
+}
+
+static boolean_t
+smb_open_overwrite(smb_arg_open_t *op)
+{
+	if ((op->create_disposition == FILE_SUPERSEDE) ||
+	    (op->create_disposition == FILE_OVERWRITE_IF) ||
+	    (op->create_disposition == FILE_OVERWRITE)) {
+		return (B_TRUE);
+	}
+	return (B_FALSE);
+}
+/*
  * smb_set_open_timestamps
  *
  * Last write time:
--- a/usr/src/uts/common/fs/smbsrv/smb_create.c	Thu Jul 22 12:31:36 2010 -0700
+++ b/usr/src/uts/common/fs/smbsrv/smb_create.c	Thu Jul 22 14:53:56 2010 -0700
@@ -19,8 +19,7 @@
  * CDDL HEADER END
  */
 /*
- * Copyright 2010 Sun Microsystems, Inc.  All rights reserved.
- * Use is subject to license terms.
+ * Copyright (c) 2007, 2010, Oracle and/or its affiliates. All rights reserved.
  */
 
 #include <smbsrv/smb_kproto.h>
@@ -199,6 +198,7 @@
 	} else {
 		op->op_oplock_level = SMB_OPLOCK_NONE;
 	}
+	op->op_oplock_levelII = B_FALSE;
 
 	status = smb_common_open(sr);
 
--- a/usr/src/uts/common/fs/smbsrv/smb_delete.c	Thu Jul 22 12:31:36 2010 -0700
+++ b/usr/src/uts/common/fs/smbsrv/smb_delete.c	Thu Jul 22 14:53:56 2010 -0700
@@ -478,7 +478,8 @@
 	fqi = &sr->arg.dirop.fqi;
 	node = fqi->fq_fnode;
 
-	(void) smb_oplock_break(node, sr->session, B_FALSE);
+	(void) smb_oplock_break(sr, node,
+	    SMB_OPLOCK_BREAK_TO_LEVEL_II | SMB_OPLOCK_BREAK_BATCH);
 
 	smb_node_start_crit(node, RW_READER);
 
--- a/usr/src/uts/common/fs/smbsrv/smb_dispatch.c	Thu Jul 22 12:31:36 2010 -0700
+++ b/usr/src/uts/common/fs/smbsrv/smb_dispatch.c	Thu Jul 22 14:53:56 2010 -0700
@@ -140,9 +140,13 @@
 #include <sys/sdt.h>
 #include <sys/spl.h>
 
+static int smb_legacy_dispatch_stats_update(kstat_t *, int);
 static int is_andx_com(unsigned char);
 static int smbsr_check_result(struct smb_request *, int, int);
 
+static kstat_t *smb_legacy_dispatch_ksp = NULL;
+static kmutex_t smb_legacy_dispatch_ksmtx;
+
 static smb_disp_entry_t	smb_disp_table[SMB_COM_NUM] = {
 	{ "SmbCreateDirectory", SMB_SDT_OPS(create_directory),  /* 0x00 000 */
 	    0x00, PC_NETWORK_PROGRAM_1_0 },
@@ -1180,13 +1184,44 @@
 void
 smb_dispatch_stats_init(smb_kstat_req_t *ksr)
 {
-	int	i;
+	kstat_named_t	*ksn;
+	int		ks_ndata;
+	int		i;
 
 	for (i = 0; i < SMB_COM_NUM; i++, ksr++) {
 		smb_latency_init(&smb_disp_table[i].sdt_lat);
 		(void) strlcpy(ksr->kr_name, smb_disp_table[i].sdt_name,
 		    sizeof (ksr->kr_name));
 	}
+	/* Legacy Statistics */
+	for (i = 0, ks_ndata = 0; i < SMB_COM_NUM; i++) {
+		if (smb_disp_table[i].sdt_function != smb_com_invalid)
+			ks_ndata++;
+	}
+
+	smb_legacy_dispatch_ksp = kstat_create(SMBSRV_KSTAT_MODULE, 0,
+	    SMBSRV_KSTAT_NAME_CMDS, SMBSRV_KSTAT_CLASS,
+	    KSTAT_TYPE_NAMED, ks_ndata, 0);
+
+	if (smb_legacy_dispatch_ksp != NULL) {
+		ksn = smb_legacy_dispatch_ksp->ks_data;
+
+		for (i = 0, ks_ndata = 0; i < SMB_COM_NUM; i++) {
+			if (smb_disp_table[i].sdt_function != smb_com_invalid) {
+				(void) strlcpy(ksn->name,
+				    smb_disp_table[i].sdt_name,
+				    sizeof (ksn->name));
+				ksn->data_type = KSTAT_DATA_UINT64;
+				++ksn;
+			}
+		}
+		mutex_init(&smb_legacy_dispatch_ksmtx, NULL,
+		    MUTEX_DEFAULT, NULL);
+		smb_legacy_dispatch_ksp->ks_update =
+		    smb_legacy_dispatch_stats_update;
+		smb_legacy_dispatch_ksp->ks_lock = &smb_legacy_dispatch_ksmtx;
+		kstat_install(smb_legacy_dispatch_ksp);
+	}
 }
 
 /*
@@ -1199,6 +1234,12 @@
 {
 	int	i;
 
+	if (smb_legacy_dispatch_ksp != NULL) {
+		kstat_delete(smb_legacy_dispatch_ksp);
+		mutex_destroy(&smb_legacy_dispatch_ksmtx);
+		smb_legacy_dispatch_ksp = NULL;
+	}
+
 	for (i = 0; i < SMB_COM_NUM; i++)
 		smb_latency_destroy(&smb_disp_table[i].sdt_lat);
 }
@@ -1232,3 +1273,37 @@
 		}
 	}
 }
+
+/*
+ * smb_legacy_dispatch_stats_update
+ *
+ * This callback function updates the smb_legacy_dispatch_kstat_data when kstat
+ * command is invoked.
+ */
+static int
+smb_legacy_dispatch_stats_update(kstat_t *ksp, int rw)
+{
+	kstat_named_t   *ksn;
+	int		i;
+
+	ASSERT(MUTEX_HELD(ksp->ks_lock));
+
+	switch (rw) {
+	case KSTAT_WRITE:
+		return (EACCES);
+
+	case KSTAT_READ:
+		ksn = ksp->ks_data;
+		for (i = 0; i < SMB_COM_NUM; i++) {
+			if (smb_disp_table[i].sdt_function != smb_com_invalid) {
+				ksn->value.ui64 =
+				    smb_disp_table[i].sdt_lat.ly_a_nreq;
+				++ksn;
+			}
+		}
+		return (0);
+
+	default:
+		return (EIO);
+	}
+}
--- a/usr/src/uts/common/fs/smbsrv/smb_fem.c	Thu Jul 22 12:31:36 2010 -0700
+++ b/usr/src/uts/common/fs/smbsrv/smb_fem.c	Thu Jul 22 14:53:56 2010 -0700
@@ -19,8 +19,7 @@
  * CDDL HEADER END
  */
 /*
- * Copyright 2010 Sun Microsystems, Inc.  All rights reserved.
- * Use is subject to license terms.
+ * Copyright (c) 2007, 2010, Oracle and/or its affiliates. All rights reserved.
  */
 
 #include <smbsrv/smb_kproto.h>
@@ -76,7 +75,7 @@
  */
 
 int smb_fem_oplock_install(smb_node_t *);
-void smb_fem_oplock_uninstall(smb_node_t *);
+int smb_fem_oplock_uninstall(smb_node_t *);
 
 static int smb_fem_oplock_open(femarg_t *, int, cred_t *,
     struct caller_context *);
@@ -89,8 +88,6 @@
 static int smb_fem_oplock_rwlock(femarg_t *, int, caller_context_t *);
 static int smb_fem_oplock_space(femarg_t *, int, flock64_t *, int,
     offset_t, cred_t *, caller_context_t *);
-static int smb_fem_oplock_setsecattr(femarg_t *, vsecattr_t *, int, cred_t *,
-    caller_context_t *);
 static int smb_fem_oplock_vnevent(femarg_t *, vnevent_t, vnode_t *, char *,
     caller_context_t *);
 
@@ -101,12 +98,11 @@
 	VOPNAME_SETATTR, { .femop_setattr = smb_fem_oplock_setattr },
 	VOPNAME_RWLOCK, { .femop_rwlock = smb_fem_oplock_rwlock },
 	VOPNAME_SPACE,	{ .femop_space = smb_fem_oplock_space },
-	VOPNAME_SETSECATTR, { .femop_setsecattr = smb_fem_oplock_setsecattr },
 	VOPNAME_VNEVENT, { .femop_vnevent = smb_fem_oplock_vnevent },
 	NULL, NULL
 };
 
-static int smb_fem_oplock_break(femarg_t *, caller_context_t *);
+static int smb_fem_oplock_break(femarg_t *, caller_context_t *, uint32_t);
 
 /*
  * smb_fem_init
@@ -179,10 +175,10 @@
 	    (fem_func_t)smb_node_ref, (fem_func_t)smb_node_release));
 }
 
-void
+int
 smb_fem_oplock_uninstall(smb_node_t *node)
 {
-	(void) fem_uninstall(node->vp, smb_oplock_ops, (void *)node);
+	return (fem_uninstall(node->vp, smb_oplock_ops, (void *)node));
 }
 
 /*
@@ -404,9 +400,15 @@
     cred_t		*cr,
     caller_context_t	*ct)
 {
-	int	rc;
+	int		rc;
+	uint32_t	flags;
 
-	rc = smb_fem_oplock_break(arg, ct);
+	if (mode & (FWRITE|FTRUNC))
+		flags = SMB_OPLOCK_BREAK_TO_NONE;
+	else
+		flags = SMB_OPLOCK_BREAK_TO_LEVEL_II;
+
+	rc = smb_fem_oplock_break(arg, ct, flags);
 	if (rc == 0)
 		rc = vnext_open(arg, mode, cr, ct);
 	return (rc);
@@ -427,7 +429,7 @@
 {
 	int	rc;
 
-	rc = smb_fem_oplock_break(arg, ct);
+	rc = smb_fem_oplock_break(arg, ct, SMB_OPLOCK_BREAK_TO_LEVEL_II);
 	if (rc == 0)
 		rc = vnext_read(arg, uiop, ioflag, cr, ct);
 	return (rc);
@@ -448,7 +450,7 @@
 {
 	int	rc;
 
-	rc = smb_fem_oplock_break(arg, ct);
+	rc = smb_fem_oplock_break(arg, ct, SMB_OPLOCK_BREAK_TO_NONE);
 	if (rc == 0)
 		rc = vnext_write(arg, uiop, ioflag, cr, ct);
 	return (rc);
@@ -462,9 +464,10 @@
     cred_t		*cr,
     caller_context_t	*ct)
 {
-	int	rc;
+	int	rc = 0;
 
-	rc = smb_fem_oplock_break(arg, ct);
+	if (vap->va_mask & AT_SIZE)
+		rc = smb_fem_oplock_break(arg, ct, SMB_OPLOCK_BREAK_TO_NONE);
 	if (rc == 0)
 		rc = vnext_setattr(arg, vap, flags, cr, ct);
 	return (rc);
@@ -476,14 +479,19 @@
     int			write_lock,
     caller_context_t	*ct)
 {
-	if (write_lock) {
-		int	rc;
+	int		rc;
+	uint32_t	flags;
 
-		rc = smb_fem_oplock_break(arg, ct);
-		if (rc != 0)
-			return (rc);
-	}
-	return (vnext_rwlock(arg, write_lock, ct));
+	if (write_lock)
+		flags = SMB_OPLOCK_BREAK_TO_NONE;
+	else
+		flags = SMB_OPLOCK_BREAK_TO_LEVEL_II;
+
+	rc = smb_fem_oplock_break(arg, ct, flags);
+	if (rc == 0)
+		rc = vnext_rwlock(arg, write_lock, ct);
+
+	return (rc);
 }
 
 static int
@@ -498,28 +506,12 @@
 {
 	int	rc;
 
-	rc = smb_fem_oplock_break(arg, ct);
+	rc = smb_fem_oplock_break(arg, ct, SMB_OPLOCK_BREAK_TO_NONE);
 	if (rc == 0)
 		rc = vnext_space(arg, cmd, bfp, flag, offset, cr, ct);
 	return (rc);
 }
 
-static int
-smb_fem_oplock_setsecattr(
-    femarg_t		*arg,
-    vsecattr_t		*vsap,
-    int			flag,
-    cred_t		*cr,
-    caller_context_t	*ct)
-{
-	int	rc;
-
-	rc = smb_fem_oplock_break(arg, ct);
-	if (rc == 0)
-		rc = vnext_setsecattr(arg, vsap, flag, cr, ct);
-	return (rc);
-}
-
 /*
  * smb_fem_oplock_vnevent()
  *
@@ -542,25 +534,32 @@
     char		*name,
     caller_context_t	*ct)
 {
-	int	rc;
+	int		rc;
+	uint32_t	flags;
 
 	switch (vnevent) {
 	case VE_REMOVE:
 	case VE_RENAME_DEST:
+		flags = SMB_OPLOCK_BREAK_TO_NONE | SMB_OPLOCK_BREAK_BATCH;
+		rc = smb_fem_oplock_break(arg, ct, flags);
+		break;
 	case VE_RENAME_SRC:
-		rc = smb_fem_oplock_break(arg, ct);
-		if (rc != 0)
-			return (rc);
+		flags = SMB_OPLOCK_BREAK_TO_LEVEL_II | SMB_OPLOCK_BREAK_BATCH;
+		rc = smb_fem_oplock_break(arg, ct, flags);
 		break;
-
 	default:
+		rc = 0;
 		break;
 	}
+
+	if (rc != 0)
+		return (rc);
+
 	return (vnext_vnevent(arg, vnevent, dvp, name, ct));
 }
 
 static int
-smb_fem_oplock_break(femarg_t *arg, caller_context_t *ct)
+smb_fem_oplock_break(femarg_t *arg, caller_context_t *ct, uint32_t flags)
 {
 	smb_node_t	*node;
 	int		rc;
@@ -568,22 +567,17 @@
 	node = (smb_node_t *)((arg)->fa_fnode->fn_available);
 	SMB_NODE_VALID(node);
 
-	if (ct == NULL) {
-		(void) smb_oplock_break(node, NULL, B_FALSE);
-		return (0);
-	}
-
-	if (ct->cc_caller_id == smb_ct.cc_caller_id)
+	if (ct && (ct->cc_caller_id == smb_ct.cc_caller_id))
 		return (0);
 
-	if (ct->cc_flags & CC_DONTBLOCK) {
-		if (smb_oplock_break(node, NULL, B_TRUE))
-			return (0);
-		ct->cc_flags |= CC_WOULDBLOCK;
-		rc = EAGAIN;
+	if (ct && (ct->cc_flags & CC_DONTBLOCK)) {
+		flags |= SMB_OPLOCK_BREAK_NOWAIT;
+		rc = smb_oplock_break(NULL, node, flags);
+		if (rc == EAGAIN)
+			ct->cc_flags |= CC_WOULDBLOCK;
 	} else {
-		(void) smb_oplock_break(node, NULL, B_FALSE);
-		rc = 0;
+		rc = smb_oplock_break(NULL, node, flags);
 	}
+
 	return (rc);
 }
--- a/usr/src/uts/common/fs/smbsrv/smb_find.c	Thu Jul 22 12:31:36 2010 -0700
+++ b/usr/src/uts/common/fs/smbsrv/smb_find.c	Thu Jul 22 14:53:56 2010 -0700
@@ -332,6 +332,8 @@
 			break;
 
 		if (*fileinfo.fi_shortname == '\0') {
+			if (smb_needs_mangled(fileinfo.fi_name))
+				continue;
 			(void) strlcpy(fileinfo.fi_shortname, fileinfo.fi_name,
 			    SMB_SHORTNAMELEN - 1);
 			if (to_upper)
@@ -476,6 +478,8 @@
 			break;
 
 		if (*fileinfo.fi_shortname == '\0') {
+			if (smb_needs_mangled(fileinfo.fi_name))
+				continue;
 			(void) strlcpy(fileinfo.fi_shortname, fileinfo.fi_name,
 			    SMB_SHORTNAMELEN - 1);
 		}
@@ -660,6 +664,8 @@
 			break;
 
 		if (*fileinfo.fi_shortname == '\0') {
+			if (smb_needs_mangled(fileinfo.fi_name))
+				continue;
 			(void) strlcpy(fileinfo.fi_shortname, fileinfo.fi_name,
 			    SMB_SHORTNAMELEN - 1);
 		}
--- a/usr/src/uts/common/fs/smbsrv/smb_fsops.c	Thu Jul 22 12:31:36 2010 -0700
+++ b/usr/src/uts/common/fs/smbsrv/smb_fsops.c	Thu Jul 22 14:53:56 2010 -0700
@@ -33,11 +33,6 @@
 
 extern caller_context_t smb_ct;
 
-extern int smb_fem_oplock_install(smb_node_t *);
-extern void smb_fem_oplock_uninstall(smb_node_t *);
-
-extern int smb_vop_other_opens(vnode_t *, int);
-
 static int smb_fsop_create_stream(smb_request_t *, cred_t *, smb_node_t *,
     char *, char *, int, smb_attr_t *, smb_node_t **);
 
@@ -120,31 +115,6 @@
 	smb_vop_close(node->vp, mode, cred);
 }
 
-int
-smb_fsop_oplock_install(smb_node_t *node, int mode)
-{
-	int rc;
-
-	if (smb_vop_other_opens(node->vp, mode))
-		return (EMFILE);
-
-	if ((rc = smb_fem_oplock_install(node)))
-		return (rc);
-
-	if (smb_vop_other_opens(node->vp, mode)) {
-		(void) smb_fem_oplock_uninstall(node);
-		return (EMFILE);
-	}
-
-	return (0);
-}
-
-void
-smb_fsop_oplock_uninstall(smb_node_t *node)
-{
-	smb_fem_oplock_uninstall(node);
-}
-
 static int
 smb_fsop_create_with_sd(smb_request_t *sr, cred_t *cr,
     smb_node_t *dnode, char *name,
@@ -354,7 +324,7 @@
 
 	/* Not a named stream */
 
-	if (smb_maybe_mangled(name)) {
+	if (SMB_TREE_SUPPORTS_SHORTNAMES(sr) && smb_maybe_mangled(name)) {
 		longname = kmem_alloc(MAXNAMELEN, KM_SLEEP);
 		rc = smb_unmangle(dnode, name, longname, MAXNAMELEN, flags);
 		kmem_free(longname, MAXNAMELEN);
@@ -584,7 +554,7 @@
 	if (SMB_TREE_SUPPORTS_ABE(sr))
 		flags |= SMB_ABE;
 
-	if (smb_maybe_mangled(name)) {
+	if (SMB_TREE_SUPPORTS_SHORTNAMES(sr) && smb_maybe_mangled(name)) {
 		longname = kmem_alloc(MAXNAMELEN, KM_SLEEP);
 		rc = smb_unmangle(dnode, name, longname, MAXNAMELEN, flags);
 		kmem_free(longname, MAXNAMELEN);
@@ -746,7 +716,8 @@
 		rc = smb_vop_remove(dnode->vp, name, flags, cr);
 
 		if (rc == ENOENT) {
-			if (!smb_maybe_mangled(name)) {
+			if (!SMB_TREE_SUPPORTS_SHORTNAMES(sr) ||
+			    !smb_maybe_mangled(name)) {
 				kmem_free(fname, MAXNAMELEN);
 				kmem_free(sname, MAXNAMELEN);
 				return (rc);
@@ -889,8 +860,10 @@
 	rc = smb_vop_rmdir(dnode->vp, name, flags, cr);
 
 	if (rc == ENOENT) {
-		if (!smb_maybe_mangled(name))
+		if (!SMB_TREE_SUPPORTS_SHORTNAMES(sr) ||
+		    !smb_maybe_mangled(name)) {
 			return (rc);
+		}
 
 		longname = kmem_alloc(MAXNAMELEN, KM_SLEEP);
 
@@ -1031,7 +1004,7 @@
 	if (SMB_TREE_SUPPORTS_ABE(sr))
 		flags |= SMB_ABE;
 
-	if (smb_maybe_mangled(to_name)) {
+	if (SMB_TREE_SUPPORTS_SHORTNAMES(sr) && smb_maybe_mangled(to_name)) {
 		longname = kmem_alloc(MAXNAMELEN, KM_SLEEP);
 		rc = smb_unmangle(to_dnode, to_name, longname,
 		    MAXNAMELEN, flags);
@@ -1492,8 +1465,9 @@
 	ASSERT(snode->n_magic == SMB_NODE_MAGIC);
 	ASSERT(snode->n_state != SMB_NODE_STATE_DESTROYING);
 
+	/* Requests for no access should be denied. */
 	if (faccess == 0)
-		return (NT_STATUS_SUCCESS);
+		return (NT_STATUS_ACCESS_DENIED);
 
 	if (SMB_TREE_IS_READONLY(sr)) {
 		if (faccess & (FILE_WRITE_DATA|FILE_APPEND_DATA|
@@ -1550,13 +1524,10 @@
 	    smb_node_is_symlink(snode))
 		acl_check = B_FALSE;
 
-	/*
-	 * Use the most restrictive parts of both faccess and the
-	 * share access.  An AND of the two value masks gives us that
-	 * since we've already converted to a mask of what we "can"
-	 * do.
-	 */
-	faccess &= sr->tid_tree->t_access;
+	/* Deny access based on the share access mask */
+
+	if ((faccess & ~sr->tid_tree->t_access) != 0)
+		return (NT_STATUS_ACCESS_DENIED);
 
 	if (acl_check) {
 		dir_vp = (snode->n_dnode) ? snode->n_dnode->vp : NULL;
@@ -1779,7 +1750,8 @@
 	    &ret_flags, root_node ? root_node->vp : NULL, &attr, cr);
 
 	if (rc != 0) {
-		if (!smb_maybe_mangled(name)) {
+		if (!SMB_TREE_SUPPORTS_SHORTNAMES(sr) ||
+		    !smb_maybe_mangled(name)) {
 			kmem_free(od_name, MAXNAMELEN);
 			return (rc);
 		}
--- a/usr/src/uts/common/fs/smbsrv/smb_init.c	Thu Jul 22 12:31:36 2010 -0700
+++ b/usr/src/uts/common/fs/smbsrv/smb_init.c	Thu Jul 22 14:53:56 2010 -0700
@@ -54,12 +54,18 @@
  * with Windows NT4.0. Previous experiments with NT4.0 resulted in directory
  * listing problems so this buffer size is configurable based on the end-user
  * environment. When in doubt use 37KB.
+ *
+ * smb_raw_mode: read_raw and write_raw supported (1) or NOT supported (0).
  */
 int	smb_maxbufsize = SMB_NT_MAXBUF;
+int	smb_oplock_levelII = 1;
 int	smb_oplock_timeout = OPLOCK_STD_TIMEOUT;
+int	smb_oplock_min_timeout = OPLOCK_MIN_TIMEOUT;
 int	smb_flush_required = 1;
 int	smb_dirsymlink_enable = 1;
 int	smb_sign_debug = 0;
+int	smb_raw_mode = 1;
+int	smb_shortnames = 1;
 uint_t	smb_audit_flags =
 #ifdef	DEBUG
     SMB_AUDIT_NODE;
@@ -68,6 +74,25 @@
 #endif
 
 /*
+ * Maximum number of simultaneous authentication, share mapping, pipe open
+ * requests to be processed.
+ */
+int	smb_ssetup_threshold = 256;
+int	smb_tcon_threshold = 1024;
+int	smb_opipe_threshold = 1024;
+
+/*
+ * Number of milliseconds that a request will be stalled if it comes in after
+ * the maximum number of inflight operations are being proccessed.
+ */
+int	smb_ssetup_timeout = (30 * 1000);
+int	smb_tcon_timeout = (30 * 1000);
+int	smb_opipe_timeout = (30 * 1000);
+
+int	smb_threshold_debug = 0;
+
+
+/*
  * *****************************************************************************
  * ********************** Static Variables / Module Linkage ********************
  * *****************************************************************************
@@ -257,6 +282,10 @@
 	case SMB_IOC_UNSHARE:
 		rc = smb_kshare_unexport_list(&ioc->ioc_share);
 		break;
+	case SMB_IOC_SHAREINFO:
+		rc = smb_kshare_info(&ioc->ioc_shareinfo);
+		copyout = B_TRUE;
+		break;
 	case SMB_IOC_NUMOPEN:
 		rc = smb_server_numopen(&ioc->ioc_opennum);
 		copyout = B_TRUE;
@@ -271,6 +300,10 @@
 	case SMB_IOC_FILE_CLOSE:
 		rc = smb_server_file_close(&ioc->ioc_fileid);
 		break;
+	case SMB_IOC_SPOOLDOC:
+		rc = smb_server_spooldoc(&ioc->ioc_spooldoc);
+		copyout = B_TRUE;
+		break;
 	default:
 		rc = ENOTTY;
 		break;
--- a/usr/src/uts/common/fs/smbsrv/smb_kdoor.c	Thu Jul 22 12:31:36 2010 -0700
+++ b/usr/src/uts/common/fs/smbsrv/smb_kdoor.c	Thu Jul 22 14:53:56 2010 -0700
@@ -19,8 +19,7 @@
  * CDDL HEADER END
  */
 /*
- * Copyright 2010 Sun Microsystems, Inc.  All rights reserved.
- * Use is subject to license terms.
+ * Copyright (c) 2007, 2010, Oracle and/or its affiliates. All rights reserved.
  */
 
 #include <sys/types.h>
@@ -133,7 +132,7 @@
 	if (rsp_data != NULL && rsp_xdr != NULL)
 		da.da_flags = SMB_DF_ASYNC;
 
-	if ((da.da_event = smb_event_create()) == NULL)
+	if ((da.da_event = smb_event_create(SMB_EVENT_TIMEOUT)) == NULL)
 		return (-1);
 
 	mutex_enter(&smb_kdoor_mutex);
--- a/usr/src/uts/common/fs/smbsrv/smb_kshare.c	Thu Jul 22 12:31:36 2010 -0700
+++ b/usr/src/uts/common/fs/smbsrv/smb_kshare.c	Thu Jul 22 14:53:56 2010 -0700
@@ -388,7 +388,6 @@
 	}
 
 	nvlist_free(shrlist);
-
 	return (0);
 }
 
@@ -448,6 +447,17 @@
 }
 
 /*
+ * Get properties (currently only shortname enablement)
+ * of specified share.
+ */
+int
+smb_kshare_info(smb_ioc_shareinfo_t *ioc)
+{
+	ioc->shortnames = smb_shortnames;
+	return (0);
+}
+
+/*
  * This function builds a response for a NetShareEnum RAP request.
  * List of shares is scanned twice. In the first round the total number
  * of shares which their OEM name is shorter than 13 chars (esi->es_ntotal)
@@ -589,7 +599,6 @@
 
 	key.shr_name = (char *)shrname;
 	shr = smb_avl_lookup(&smb_export.e_share_avl, &key);
-
 	return (shr);
 }
 
@@ -605,7 +614,6 @@
 	smb_avl_release(&smb_export.e_share_avl, shr);
 }
 
-
 /*
  * Add the given share in the specified server.
  * If the share is a disk share, smb_vfs_hold() is
@@ -795,6 +803,13 @@
 		return (NULL);
 	}
 
+	rc = nvlist_lookup_uint32(smb, "type", &tmp.shr_type);
+	if (rc != 0) {
+		cmn_err(CE_WARN, "kshare[%s]: failed getting the share type"
+		    " (%d)", tmp.shr_name, rc);
+		return (NULL);
+	}
+
 	(void) nvlist_lookup_string(smb, SHOPT_AD_CONTAINER,
 	    &tmp.shr_container);
 	(void) nvlist_lookup_string(smb, SHOPT_NONE, &tmp.shr_access_none);
@@ -815,7 +830,7 @@
 		rc = nvlist_lookup_uint32(smb, "uid", &tmp.shr_uid);
 		rc |= nvlist_lookup_uint32(smb, "gid", &tmp.shr_gid);
 		if (rc != 0) {
-			cmn_err(CE_WARN, "kshare: failed looking up UID/GID"
+			cmn_err(CE_WARN, "kshare: failed looking up uid/gid"
 			    " (%d)", rc);
 			return (NULL);
 		}
@@ -846,7 +861,7 @@
 
 	shr->shr_oemname = smb_kshare_oemname(shr->shr_name);
 	shr->shr_flags = tmp.shr_flags | smb_kshare_is_admin(shr->shr_name);
-	shr->shr_type = STYPE_DISKTREE | smb_kshare_is_special(shr->shr_name);
+	shr->shr_type = tmp.shr_type | smb_kshare_is_special(shr->shr_name);
 
 	shr->shr_uid = tmp.shr_uid;
 	shr->shr_gid = tmp.shr_gid;
--- a/usr/src/uts/common/fs/smbsrv/smb_kutil.c	Thu Jul 22 12:31:36 2010 -0700
+++ b/usr/src/uts/common/fs/smbsrv/smb_kutil.c	Thu Jul 22 14:53:56 2010 -0700
@@ -501,6 +501,7 @@
 	ll->ll_count = 0;
 	ll->ll_wrop = 0;
 	ll->ll_deleteq_count = 0;
+	ll->ll_flushing = B_FALSE;
 }
 
 /*
@@ -567,6 +568,11 @@
 	smb_dtor_t    *dtor;
 
 	mutex_enter(&ll->ll_mutex);
+	if (ll->ll_flushing) {
+		mutex_exit(&ll->ll_mutex);
+		return;
+	}
+	ll->ll_flushing = B_TRUE;
 
 	dtor = list_head(&ll->ll_deleteq);
 	while (dtor != NULL) {
@@ -583,6 +589,7 @@
 		mutex_enter(&ll->ll_mutex);
 		dtor = list_head(&ll->ll_deleteq);
 	}
+	ll->ll_flushing = B_FALSE;
 
 	mutex_exit(&ll->ll_mutex);
 }
@@ -2347,3 +2354,111 @@
 	scalehrtime(&kd->ku_wlentime);
 	scalehrtime(&kd->ku_wtime);
 }
+
+void
+smb_threshold_init(smb_cmd_threshold_t *ct, char *cmd, int threshold,
+    int timeout)
+{
+	bzero(ct, sizeof (smb_cmd_threshold_t));
+	mutex_init(&ct->ct_mutex, NULL, MUTEX_DEFAULT, NULL);
+	ct->ct_cmd = cmd;
+	ct->ct_threshold = threshold;
+	ct->ct_event = smb_event_create(timeout);
+	ct->ct_event_id = smb_event_txid(ct->ct_event);
+
+	if (smb_threshold_debug) {
+		cmn_err(CE_NOTE, "smb_threshold_init[%s]: threshold (%d), "
+		    "timeout (%d)", cmd, threshold, timeout);
+	}
+}
+
+/*
+ * This function must be called prior to SMB_SERVER_STATE_STOPPING state
+ * so that ct_event can be successfully removed from the event list.
+ * It should not be called when the server mutex is held or when the
+ * server is removed from the server list.
+ */
+void
+smb_threshold_fini(smb_cmd_threshold_t *ct)
+{
+	smb_event_destroy(ct->ct_event);
+	mutex_destroy(&ct->ct_mutex);
+	bzero(ct, sizeof (smb_cmd_threshold_t));
+}
+
+/*
+ * This threshold mechanism can be used to limit the number of simultaneous
+ * requests, which serves to limit the stress that can be applied to the
+ * service and also allows the service to respond to requests before the
+ * client times out and reports that the server is not responding,
+ *
+ * If the number of requests exceeds the threshold, new requests will be
+ * stalled until the number drops back to the threshold.  Stalled requests
+ * will be notified as appropriate, in which case 0 will be returned.
+ * If the timeout expires before the request is notified, a non-zero errno
+ * value will be returned.
+ *
+ * To avoid a flood of messages, the message rate is throttled as well.
+ */
+int
+smb_threshold_enter(smb_cmd_threshold_t *ct)
+{
+	int	rc;
+
+	mutex_enter(&ct->ct_mutex);
+	if (ct->ct_active_cnt >= ct->ct_threshold && ct->ct_event != NULL) {
+		atomic_inc_32(&ct->ct_blocked_cnt);
+
+		if (smb_threshold_debug) {
+			cmn_err(CE_NOTE, "smb_threshold_enter[%s]: blocked "
+			    "(blocked ops: %u, inflight ops: %u)",
+			    ct->ct_cmd, ct->ct_blocked_cnt, ct->ct_active_cnt);
+		}
+
+		mutex_exit(&ct->ct_mutex);
+
+		if ((rc = smb_event_wait(ct->ct_event)) != 0) {
+			if (rc == ECANCELED)
+				return (rc);
+
+			mutex_enter(&ct->ct_mutex);
+			if (ct->ct_active_cnt >= ct->ct_threshold) {
+
+				if ((ct->ct_error_cnt %
+				    SMB_THRESHOLD_REPORT_THROTTLE) == 0) {
+					cmn_err(CE_NOTE, "%s: server busy: "
+					    "threshold %d exceeded)",
+					    ct->ct_cmd, ct->ct_threshold);
+				}
+
+				atomic_inc_32(&ct->ct_error_cnt);
+				mutex_exit(&ct->ct_mutex);
+				return (rc);
+			}
+
+			mutex_exit(&ct->ct_mutex);
+
+		}
+
+		mutex_enter(&ct->ct_mutex);
+		atomic_dec_32(&ct->ct_blocked_cnt);
+		if (smb_threshold_debug) {
+			cmn_err(CE_NOTE, "smb_threshold_enter[%s]: resumed "
+			    "(blocked ops: %u, inflight ops: %u)", ct->ct_cmd,
+			    ct->ct_blocked_cnt, ct->ct_active_cnt);
+		}
+	}
+
+	atomic_inc_32(&ct->ct_active_cnt);
+	mutex_exit(&ct->ct_mutex);
+	return (0);
+}
+
+void
+smb_threshold_exit(smb_cmd_threshold_t *ct, smb_server_t *sv)
+{
+	mutex_enter(&ct->ct_mutex);
+	atomic_dec_32(&ct->ct_active_cnt);
+	mutex_exit(&ct->ct_mutex);
+	smb_event_notify(sv, ct->ct_event_id);
+}
--- a/usr/src/uts/common/fs/smbsrv/smb_lock.c	Thu Jul 22 12:31:36 2010 -0700
+++ b/usr/src/uts/common/fs/smbsrv/smb_lock.c	Thu Jul 22 14:53:56 2010 -0700
@@ -120,10 +120,13 @@
 /*
  * smb_lock_range
  *
- * checks for integrity of file lock operation for the given range of file data.
+ * Checks for integrity of file lock operation for the given range of file data.
  * This is performed by applying lock rules with all the elements of the node
  * lock list.
  *
+ * Break shared (levelII) oplocks. If there is an exclusive oplock, it is
+ * owned by this ofile and therefore should not be broken.
+ *
  * The function returns with new lock added if lock request is non-conflicting
  * with existing range lock for the file. Otherwise smb request is filed
  * without returning.
@@ -241,6 +244,9 @@
 	}
 	smb_llist_exit(&node->n_lock_list);
 
+	if (result == NT_STATUS_SUCCESS)
+		smb_oplock_break_levelII(node);
+
 	return (result);
 }
 
--- a/usr/src/uts/common/fs/smbsrv/smb_locking_andx.c	Thu Jul 22 12:31:36 2010 -0700
+++ b/usr/src/uts/common/fs/smbsrv/smb_locking_andx.c	Thu Jul 22 14:53:56 2010 -0700
@@ -240,6 +240,8 @@
 	DWORD		result;
 	int 		rc;
 	uint32_t	ltype;
+	smb_ofile_t	*ofile;
+	uint8_t		brk;
 
 	rc = smbsr_decode_vwv(sr, "4.wbblww", &sr->smb_fid, &lock_type,
 	    &oplock_level, &timeout, &unlock_num, &lock_num);
@@ -251,6 +253,7 @@
 		smbsr_error(sr, NT_STATUS_INVALID_HANDLE, ERRDOS, ERRbadfid);
 		return (SDRC_ERROR);
 	}
+	ofile = sr->fid_ofile;
 
 	if (lock_type & LOCKING_ANDX_SHARED_LOCK)
 		ltype = SMB_LOCK_TYPE_READONLY;
@@ -260,19 +263,11 @@
 	pid = sr->smb_pid;	/* Save the original pid */
 
 	if (lock_type & LOCKING_ANDX_OPLOCK_RELEASE) {
-		smb_oplock_release(sr->fid_ofile->f_node, sr->fid_ofile);
-		/*
-		 * According to the protocol:
-		 *
-		 * If the client sends an SMB_LOCKING_ANDX request with the
-		 * LOCKING_ANDX_OPLOCK_RELEASE flag set
-		 * and NumberOfLocks is zero,
-		 * the server does not send a response.
-		 *
-		 * I'm not sure if it's going to break anything if I change
-		 * it according to the protocol. So, I leave it unchanged
-		 * for now.
-		 */
+		if (oplock_level == 0)
+			brk = SMB_OPLOCK_BREAK_TO_NONE;
+		else
+			brk = SMB_OPLOCK_BREAK_TO_LEVEL_II;
+		smb_oplock_ack(ofile->f_node, ofile, brk);
 		if (unlock_num == 0 && lock_num == 0)
 			return (SDRC_NO_REPLY);
 	}
--- a/usr/src/uts/common/fs/smbsrv/smb_mangle_name.c	Thu Jul 22 12:31:36 2010 -0700
+++ b/usr/src/uts/common/fs/smbsrv/smb_mangle_name.c	Thu Jul 22 14:53:56 2010 -0700
@@ -55,41 +55,10 @@
 
 #define	isinvalid(c)	(strchr(invalid_dos_chars, c) || (c & 0x80))
 
-static boolean_t smb_is_reserved_dos_name(const char *name);
 static int smb_generate_mangle(uint64_t, char *, size_t);
 static char smb_mangle_char(char);
 
 /*
- * smb_match_name
- *
- * Don't match reserved dos filenames.
- * Check name to see if it matches pattern.
- * Generate the shortname (even if !smb_needs_mangled()) since names may
- * be mangled to address case conflicts) and check if shortname matches
- * pattern.
- *
- * Returns: B_TRUE  - if there is a match
- *          B_FALSE - otherwise
- */
-boolean_t
-smb_match_name(ino64_t fid, char *name, char *pattern)
-{
-	char shortname[SMB_SHORTNAMELEN];
-
-	if (smb_is_reserved_dos_name(name))
-		return (B_FALSE);
-
-	if (smb_match_ci(pattern, name))
-		return (B_TRUE);
-
-	smb_mangle(name, fid, shortname, SMB_SHORTNAMELEN);
-	if (smb_match_ci(pattern, shortname))
-		return (B_TRUE);
-
-	return (B_FALSE);
-}
-
-/*
  * Return true if name contains characters that are invalid in a file
  * name or it is a reserved DOS device name.  Otherwise, returns false.
  *
@@ -117,7 +86,7 @@
  * The device name should not be followed immediately by an extension,
  * for example, NUL.txt.
  */
-static boolean_t
+boolean_t
 smb_is_reserved_dos_name(const char *name)
 {
 	static char *cnames[] = { "CLOCK$", "COM1", "COM2", "COM3", "COM4",
--- a/usr/src/uts/common/fs/smbsrv/smb_negotiate.c	Thu Jul 22 12:31:36 2010 -0700
+++ b/usr/src/uts/common/fs/smbsrv/smb_negotiate.c	Thu Jul 22 14:53:56 2010 -0700
@@ -285,6 +285,7 @@
 {
 	smb_arg_negotiate_t	*negprot = sr->sr_negprot;
 	uint16_t		secmode;
+	uint16_t		rawmode = 0;
 	uint32_t		sesskey;
 	char			ipaddr_buf[INET6_ADDRSTRLEN];
 	char			*nbdomain;
@@ -320,7 +321,6 @@
 	    | CAP_NT_SMBS
 	    | CAP_STATUS32
 	    | CAP_NT_FIND
-	    | CAP_RAW_MODE
 	    | CAP_LEVEL_II_OPLOCKS
 	    | CAP_LOCK_AND_READ
 	    | CAP_RPC_REMOTE_APIS
@@ -328,6 +328,11 @@
 	    | CAP_LARGE_WRITEX
 	    | CAP_DFS;
 
+	if (smb_raw_mode) {
+		negprot->ni_capabilities |= CAP_RAW_MODE;
+		rawmode = 3;
+	}
+
 	if (smb_cap_passthru)
 		negprot->ni_capabilities |= CAP_INFOLEVEL_PASSTHRU;
 	else
@@ -366,7 +371,7 @@
 		    SMB_DOS_MAXBUF,		/* max buffer size */
 		    1,				/* max MPX */
 		    1,				/* max VCs */
-		    3,				/* raw mode (s/b 3) */
+		    rawmode,			/* read/write raw (s/b 3) */
 		    sesskey,			/* session key */
 		    negprot->ni_servertime.tv_sec, /* server date/time */
 		    negprot->ni_tzcorrection,
@@ -391,7 +396,7 @@
 		    SMB_DOS_MAXBUF,		/* max buffer size */
 		    1,				/* max MPX */
 		    1,				/* max VCs */
-		    3,				/* raw mode (s/b 3) */
+		    rawmode,			/* read/write raw (s/b 3) */
 		    sesskey,			/* session key */
 		    negprot->ni_servertime.tv_sec, /* server date/time */
 		    negprot->ni_tzcorrection,
--- a/usr/src/uts/common/fs/smbsrv/smb_node.c	Thu Jul 22 12:31:36 2010 -0700
+++ b/usr/src/uts/common/fs/smbsrv/smb_node.c	Thu Jul 22 14:53:56 2010 -0700
@@ -31,20 +31,11 @@
  *		    | T0
  *		    |
  *		    v
- *    +----------------------------+        T1
- *    |  SMB_NODE_STATE_AVAILABLE  |--------------------+
- *    +----------------------------+			|
- *		    |	     ^				|
- *		    |	     |				v
- *		    |	     |	  T2	+-------------------------------+
- *		    |	     |<---------| SMB_NODE_STATE_OPLOCK_GRANTED |
- *		    |	     |		+-------------------------------+
- *		    | T5     |				|
- *		    |	     |				| T3
- *		    |	     |				v
- *		    |	     |	  T4	+--------------------------------+
- *		    |	     +----------| SMB_NODE_STATE_OPLOCK_BREAKING |
- *		    |			+--------------------------------+
+ *    +----------------------------+
+ *    |  SMB_NODE_STATE_AVAILABLE  |
+ *    +----------------------------+
+ *		    |
+ *		    | T1
  *		    |
  *		    v
  *    +-----------------------------+
@@ -52,7 +43,7 @@
  *    +-----------------------------+
  *		    |
  *		    |
- *		    | T6
+ *		    | T2
  *		    |
  *		    +----------> Deletion/Free
  *
@@ -64,42 +55,11 @@
  *
  * Transition T1
  *
- *    This transition occurs smb_oplock_acquire() during an OPEN.
- *
- * Transition T2
- *
- *    This transition occurs in smb_oplock_release(). The events triggering
- *    it are:
- *
- *	- LockingAndX sent by the client that was granted the oplock.
- *	- Closing of the file.
- *
- * Transition T3
- *
- *    This transition occurs in smb_oplock_break(). The events triggering
- *    it are:
- *
- *	- Another client wants to open the file.
- *	- A client is trying to delete the file.
- *	- A client is trying to rename the file.
- *	- A client is trying to set/modify  the file attributes.
- *
- * Transition T4
- *
- *    This transition occurs in smb_oplock_release or smb_oplock_break(). The
- *    events triggering it are:
- *
- *	- The client that was granting the oplock releases it (close or
- *	  LockingAndx).
- *	- The time alloted to release the oplock expired.
- *
- * Transition T5
- *
  *    This transition occurs in smb_node_release(). If the reference count
  *    drops to zero the state is moved to SMB_NODE_STATE_DESTROYING and no more
  *    reference count will be given out for that node.
  *
- * Transition T6
+ * Transition T2
  *
  *    This transition occurs in smb_node_release(). The structure is deleted.
  *
@@ -332,8 +292,6 @@
 				DTRACE_PROBE1(smb_node_lookup_hit,
 				    smb_node_t *, node);
 				switch (node->n_state) {
-				case SMB_NODE_STATE_OPLOCK_GRANTED:
-				case SMB_NODE_STATE_OPLOCK_BREAKING:
 				case SMB_NODE_STATE_AVAILABLE:
 					/* The node was found. */
 					node->n_refcnt++;
@@ -457,8 +415,6 @@
 	mutex_enter(&node->n_mutex);
 	switch (node->n_state) {
 	case SMB_NODE_STATE_AVAILABLE:
-	case SMB_NODE_STATE_OPLOCK_GRANTED:
-	case SMB_NODE_STATE_OPLOCK_BREAKING:
 		node->n_refcnt++;
 		ASSERT(node->n_refcnt);
 		DTRACE_PROBE1(smb_node_ref_exit, smb_node_t *, node);
@@ -584,8 +540,6 @@
 	mutex_enter(&ret_node->n_mutex);
 	switch (ret_node->n_state) {
 	case SMB_NODE_STATE_AVAILABLE:
-	case SMB_NODE_STATE_OPLOCK_GRANTED:
-	case SMB_NODE_STATE_OPLOCK_BREAKING:
 		ret_node->n_dnode = to_dnode;
 		mutex_exit(&ret_node->n_mutex);
 		ASSERT(to_dnode->n_dnode != ret_node);
@@ -807,6 +761,29 @@
 		return (NT_STATUS_SUCCESS);
 }
 
+/*
+ * smb_node_share_check
+ *
+ * Returns: TRUE    - ofiles have non-zero share access
+ *          B_FALSE - ofile with share access NONE.
+ */
+boolean_t
+smb_node_share_check(smb_node_t *node)
+{
+	smb_ofile_t	*of;
+	boolean_t	status = B_TRUE;
+
+	SMB_NODE_VALID(node);
+
+	smb_llist_enter(&node->n_ofile_list, RW_READER);
+	of = smb_llist_head(&node->n_ofile_list);
+	if (of)
+		status = smb_ofile_share_check(of);
+	smb_llist_exit(&node->n_ofile_list);
+
+	return (status);
+}
+
 void
 smb_node_notify_change(smb_node_t *node)
 {
@@ -894,19 +871,6 @@
 	rw_exit(&node->n_lock);
 }
 
-uint32_t
-smb_node_get_ofile_count(smb_node_t *node)
-{
-	uint32_t	cntr;
-
-	SMB_NODE_VALID(node);
-
-	smb_llist_enter(&node->n_ofile_list, RW_READER);
-	cntr = smb_llist_get_count(&node->n_ofile_list);
-	smb_llist_exit(&node->n_ofile_list);
-	return (cntr);
-}
-
 void
 smb_node_add_ofile(smb_node_t *node, smb_ofile_t *of)
 {
@@ -957,17 +921,29 @@
 	smb_node_clear_cached_data(node);
 }
 
-uint32_t
-smb_node_get_open_ofiles(smb_node_t *node)
+/*
+ * smb_node_inc_opening_count
+ */
+void
+smb_node_inc_opening_count(smb_node_t *node)
 {
-	uint32_t	cnt;
-
 	SMB_NODE_VALID(node);
-
 	mutex_enter(&node->n_mutex);
-	cnt = node->n_open_count;
+	node->n_opening_count++;
 	mutex_exit(&node->n_mutex);
-	return (cnt);
+}
+
+/*
+ * smb_node_dec_opening_count
+ */
+void
+smb_node_dec_opening_count(smb_node_t *node)
+{
+	SMB_NODE_VALID(node);
+	mutex_enter(&node->n_mutex);
+	ASSERT(node->n_opening_count > 0);
+	node->n_opening_count--;
+	mutex_exit(&node->n_mutex);
 }
 
 /*
@@ -1106,6 +1082,10 @@
 	node->n_unode = NULL;
 	node->delete_on_close_cred = NULL;
 	node->n_delete_on_close_flags = 0;
+	node->n_oplock.ol_fem = B_FALSE;
+	node->n_oplock.ol_xthread = NULL;
+	node->n_oplock.ol_count = 0;
+	node->n_oplock.ol_break = SMB_OPLOCK_NO_BREAK;
 
 	(void) strlcpy(node->od_name, od_name, sizeof (node->od_name));
 	if (strcmp(od_name, XATTR_DIR) == 0)
@@ -1135,7 +1115,9 @@
 	VERIFY(!list_link_active(&node->n_lnd));
 	VERIFY(node->n_lock_list.ll_count == 0);
 	VERIFY(node->n_ofile_list.ll_count == 0);
+	VERIFY(node->n_oplock.ol_count == 0);
 	VERIFY(node->n_oplock.ol_xthread == NULL);
+	VERIFY(node->n_oplock.ol_fem == B_FALSE);
 	VERIFY(mutex_owner(&node->n_mutex) == NULL);
 	VERIFY(!RW_LOCK_HELD(&node->n_lock));
 	VN_RELE(node->vp);
@@ -1159,6 +1141,9 @@
 	smb_llist_constructor(&node->n_lock_list, sizeof (smb_lock_t),
 	    offsetof(smb_lock_t, l_lnd));
 	cv_init(&node->n_oplock.ol_cv, NULL, CV_DEFAULT, NULL);
+	mutex_init(&node->n_oplock.ol_mutex, NULL, MUTEX_DEFAULT, NULL);
+	list_create(&node->n_oplock.ol_grants, sizeof (smb_oplock_grant_t),
+	    offsetof(smb_oplock_grant_t, og_lnd));
 	rw_init(&node->n_lock, NULL, RW_DEFAULT, NULL);
 	mutex_init(&node->n_mutex, NULL, MUTEX_DEFAULT, NULL);
 	smb_node_create_audit_buf(node, kmflags);
@@ -1179,8 +1164,10 @@
 	mutex_destroy(&node->n_mutex);
 	rw_destroy(&node->n_lock);
 	cv_destroy(&node->n_oplock.ol_cv);
+	mutex_destroy(&node->n_oplock.ol_mutex);
 	smb_llist_destructor(&node->n_lock_list);
 	smb_llist_destructor(&node->n_ofile_list);
+	list_destroy(&node->n_oplock.ol_grants);
 }
 
 /*
@@ -1608,7 +1595,7 @@
  * request in smb_node_getattr and smb_node_setattr above.)
  * Timestamps remain cached while there are open ofiles for the node.
  * This includes open ofiles for named streams.
- * n_open_ofiles cannot be used as this doesn't include ofiles opened
+ * n_ofile_list cannot be used as this doesn't include ofiles opened
  * for the node's named streams. Thus n_timestamps contains a count
  * of open ofiles (t_open_ofiles), including named streams' ofiles,
  * to be used to control timestamp caching.
--- a/usr/src/uts/common/fs/smbsrv/smb_nt_create_andx.c	Thu Jul 22 12:31:36 2010 -0700
+++ b/usr/src/uts/common/fs/smbsrv/smb_nt_create_andx.c	Thu Jul 22 14:53:56 2010 -0700
@@ -19,8 +19,7 @@
  * CDDL HEADER END
  */
 /*
- * Copyright 2010 Sun Microsystems, Inc.  All rights reserved.
- * Use is subject to license terms.
+ * Copyright (c) 2007, 2010, Oracle and/or its affiliates. All rights reserved.
  */
 
 /*
@@ -231,7 +230,6 @@
 smb_com_nt_create_andx(struct smb_request *sr)
 {
 	struct open_param	*op = &sr->arg.open;
-	unsigned char		OplockLevel;
 	unsigned char		DirFlag;
 	smb_attr_t		attr;
 	smb_node_t		*node;
@@ -275,28 +273,14 @@
 		op->fqi.fq_dnode = op->dir->f_node;
 	}
 
+	op->op_oplock_levelII = B_TRUE;
+
 	if (smb_common_open(sr) != NT_STATUS_SUCCESS)
 		return (SDRC_ERROR);
 
 	switch (sr->tid_tree->t_res_type & STYPE_MASK) {
 	case STYPE_DISKTREE:
 	case STYPE_PRINTQ:
-		switch (op->op_oplock_level) {
-		case SMB_OPLOCK_EXCLUSIVE:
-			OplockLevel = 1;
-			break;
-		case SMB_OPLOCK_BATCH:
-			OplockLevel = 2;
-			break;
-		case SMB_OPLOCK_LEVEL_II:
-			OplockLevel = 3;
-			break;
-		case SMB_OPLOCK_NONE:
-		default:
-			OplockLevel = 0;
-			break;
-		}
-
 		if (op->create_options & FILE_DELETE_ON_CLOSE)
 			smb_ofile_set_delete_on_close(sr->fid_ofile);
 
@@ -312,7 +296,7 @@
 		    34,
 		    sr->andx_com,
 		    0x67,
-		    OplockLevel,
+		    op->op_oplock_level,
 		    sr->smb_fid,
 		    op->action_taken,
 		    &attr.sa_crtime,
@@ -329,12 +313,11 @@
 		break;
 
 	case STYPE_IPC:
-		OplockLevel = 0;
 		rc = smbsr_encode_result(sr, 34, 0, "bb.wbwlqqqqlqqwwbw",
 		    34,
 		    sr->andx_com,
 		    0x67,
-		    OplockLevel,
+		    0,
 		    sr->smb_fid,
 		    op->action_taken,
 		    0LL,
--- a/usr/src/uts/common/fs/smbsrv/smb_nt_transact_create.c	Thu Jul 22 12:31:36 2010 -0700
+++ b/usr/src/uts/common/fs/smbsrv/smb_nt_transact_create.c	Thu Jul 22 14:53:56 2010 -0700
@@ -19,8 +19,7 @@
  * CDDL HEADER END
  */
 /*
- * Copyright 2010 Sun Microsystems, Inc.  All rights reserved.
- * Use is subject to license terms.
+ * Copyright (c) 2007, 2010, Oracle and/or its affiliates. All rights reserved.
  */
 
 /*
@@ -140,7 +139,6 @@
 smb_nt_transact_create(smb_request_t *sr, smb_xa_t *xa)
 {
 	struct open_param *op = &sr->arg.open;
-	uint8_t			OplockLevel;
 	uint8_t			DirFlag;
 	smb_attr_t		attr;
 	smb_node_t		*node;
@@ -184,6 +182,8 @@
 		op->fqi.fq_dnode = op->dir->f_node;
 	}
 
+	op->op_oplock_levelII = B_TRUE;
+
 	status = smb_common_open(sr);
 
 	if (status != NT_STATUS_SUCCESS)
@@ -192,22 +192,6 @@
 	switch (sr->tid_tree->t_res_type & STYPE_MASK) {
 	case STYPE_DISKTREE:
 	case STYPE_PRINTQ:
-		switch (op->op_oplock_level) {
-		case SMB_OPLOCK_EXCLUSIVE:
-			OplockLevel = 1;
-			break;
-		case SMB_OPLOCK_BATCH:
-			OplockLevel = 2;
-			break;
-		case SMB_OPLOCK_LEVEL_II:
-			OplockLevel = 3;
-			break;
-		case SMB_OPLOCK_NONE:
-		default:
-			OplockLevel = 0;
-			break;
-		}
-
 		if (op->create_options & FILE_DELETE_ON_CLOSE)
 			smb_ofile_set_delete_on_close(sr->fid_ofile);
 
@@ -220,7 +204,7 @@
 		}
 
 		(void) smb_mbc_encodef(&xa->rep_param_mb, "b.wllTTTTlqqwwb",
-		    OplockLevel,
+		    op->op_oplock_level,
 		    sr->smb_fid,
 		    op->action_taken,
 		    0,	/* EaErrorOffset */
--- a/usr/src/uts/common/fs/smbsrv/smb_nt_transact_ioctl.c	Thu Jul 22 12:31:36 2010 -0700
+++ b/usr/src/uts/common/fs/smbsrv/smb_nt_transact_ioctl.c	Thu Jul 22 14:53:56 2010 -0700
@@ -19,8 +19,7 @@
  * CDDL HEADER END
  */
 /*
- * Copyright 2010 Sun Microsystems, Inc.  All rights reserved.
- * Use is subject to license terms.
+ * Copyright (c) 2007, 2010, Oracle and/or its affiliates. All rights reserved.
  */
 
 #include <smbsrv/smb_kproto.h>
@@ -34,6 +33,10 @@
 /*
  * This table defines the list of FSCTL values for which we'll
  * call a funtion to perform specific processing.
+ *
+ * Note: If support is added for FSCTL_SET_ZERO_DATA, it must break
+ * any oplocks on the file to none:
+ *   smb_oplock_break(sr, node, SMB_OPLOCK_BREAK_TO_NONE);
  */
 static struct {
 	uint32_t fcode;
--- a/usr/src/uts/common/fs/smbsrv/smb_odir.c	Thu Jul 22 12:31:36 2010 -0700
+++ b/usr/src/uts/common/fs/smbsrv/smb_odir.c	Thu Jul 22 14:53:56 2010 -0700
@@ -248,7 +248,7 @@
 #include <sys/extdirent.h>
 
 /* static functions */
-static smb_odir_t *smb_odir_create(smb_request_t *, smb_node_t *,
+static uint16_t smb_odir_create(smb_request_t *, smb_node_t *,
     char *, uint16_t, cred_t *);
 static int smb_odir_single_fileinfo(smb_request_t *, smb_odir_t *,
     smb_fileinfo_t *);
@@ -257,6 +257,7 @@
 static int smb_odir_next_odirent(smb_odir_t *, smb_odirent_t *);
 static boolean_t smb_odir_lookup_link(smb_request_t *, smb_odir_t *,
     char *, smb_node_t **);
+static boolean_t smb_odir_match_name(smb_odir_t *, smb_odirent_t *);
 
 
 /*
@@ -275,7 +276,7 @@
 	smb_tree_t	*tree;
 	smb_node_t	*dnode;
 	char		pattern[MAXNAMELEN];
-	smb_odir_t 	*od;
+	uint16_t 	odid;
 	cred_t		*cr;
 
 	ASSERT(sr);
@@ -313,9 +314,9 @@
 	else
 		cr = tree->t_user->u_cred;
 
-	od = smb_odir_create(sr, dnode, pattern, sattr, cr);
+	odid = smb_odir_create(sr, dnode, pattern, sattr, cr);
 	smb_node_release(dnode);
-	return (od ? od->d_odid : 0);
+	return (odid);
 }
 
 /*
@@ -333,7 +334,7 @@
 {
 	int		rc;
 	vnode_t		*xattr_dvp;
-	smb_odir_t	*od;
+	uint16_t	odid;
 	cred_t		*cr;
 	char		pattern[SMB_STREAM_PREFIX_LEN + 2];
 
@@ -370,14 +371,10 @@
 	}
 
 	(void) snprintf(pattern, sizeof (pattern), "%s*", SMB_STREAM_PREFIX);
-	od = smb_odir_create(sr, xattr_dnode, pattern, SMB_SEARCH_ATTRIBUTES,
+	odid = smb_odir_create(sr, xattr_dnode, pattern, SMB_SEARCH_ATTRIBUTES,
 	    cr);
 	smb_node_release(xattr_dnode);
-	if (od == NULL)
-		return (0);
-
-	od->d_flags |= SMB_ODIR_FLAG_XATTR;
-	return (od->d_odid);
+	return (odid);
 }
 
 /*
@@ -516,8 +513,7 @@
 	for (;;) {
 		if ((rc = smb_odir_next_odirent(od, odirent)) != 0)
 			break;
-		if (smb_match_name(odirent->od_ino, odirent->od_name,
-		    od->d_pattern))
+		if (smb_odir_match_name(od, odirent))
 			break;
 	}
 
@@ -605,8 +601,7 @@
 			    U8_VALIDATE_ENTIRE, &errnum) < 0)
 				continue;
 
-			if (!smb_match_name(odirent->od_ino, odirent->od_name,
-			    od->d_pattern))
+			if (!smb_odir_match_name(od, odirent))
 				continue;
 
 			rc = smb_odir_wildcard_fileinfo(sr, od, odirent,
@@ -811,7 +806,7 @@
  * smb_odir_create
  * Allocate and populate an odir obect and add it to the tree's list.
  */
-static smb_odir_t *
+static uint16_t
 smb_odir_create(smb_request_t *sr, smb_node_t *dnode,
     char *pattern, uint16_t sattr, cred_t *cr)
 {
@@ -831,7 +826,7 @@
 	if (smb_idpool_alloc(&tree->t_odid_pool, &odid)) {
 		smbsr_error(sr, NT_STATUS_TOO_MANY_OPENED_FILES,
 		    ERRDOS, ERROR_TOO_MANY_OPEN_FILES);
-		return (NULL);
+		return (0);
 	}
 
 	od = kmem_cache_alloc(tree->t_server->si_cache_odir, KM_SLEEP);
@@ -857,10 +852,14 @@
 		od->d_flags |= SMB_ODIR_FLAG_EDIRENT;
 	if (smb_tree_has_feature(tree, SMB_TREE_CASEINSENSITIVE))
 		od->d_flags |= SMB_ODIR_FLAG_IGNORE_CASE;
+	if (smb_tree_has_feature(tree, SMB_TREE_SHORTNAMES))
+		od->d_flags |= SMB_ODIR_FLAG_SHORTNAMES;
 	if (SMB_TREE_SUPPORTS_CATIA(sr))
 		od->d_flags |= SMB_ODIR_FLAG_CATIA;
 	if (SMB_TREE_SUPPORTS_ABE(sr))
 		od->d_flags |= SMB_ODIR_FLAG_ABE;
+	if (dnode->flags & NODE_XATTR_DIR)
+		od->d_flags |= SMB_ODIR_FLAG_XATTR;
 	od->d_eof = B_FALSE;
 
 	smb_llist_enter(&tree->t_odir_list, RW_WRITER);
@@ -868,7 +867,7 @@
 	smb_llist_exit(&tree->t_odir_list);
 
 	atomic_inc_32(&tree->t_session->s_dir_cnt);
-	return (od);
+	return (odid);
 }
 
 /*
@@ -1038,7 +1037,7 @@
 	int		rc;
 	smb_node_t	*fnode, *tgt_node;
 	smb_attr_t	attr;
-	ino64_t		ino;
+	ino64_t		fid;
 	char		*name;
 	boolean_t	case_conflict = B_FALSE;
 	int		lookup_flags, flags = 0;
@@ -1101,11 +1100,15 @@
 	}
 
 	name = fnode->od_name;
-	ino = attr.sa_vattr.va_nodeid;
-	if (case_conflict || smb_needs_mangled(name))
-		smb_mangle(name, ino, fileinfo->fi_shortname, SMB_SHORTNAMELEN);
-	if (case_conflict)
-		name = fileinfo->fi_shortname;
+	if (od->d_flags & SMB_ODIR_FLAG_SHORTNAMES) {
+		fid = attr.sa_vattr.va_nodeid;
+		if (case_conflict || smb_needs_mangled(name)) {
+			smb_mangle(name, fid, fileinfo->fi_shortname,
+			    SMB_SHORTNAMELEN);
+		}
+		if (case_conflict)
+			name = fileinfo->fi_shortname;
+	}
 
 	(void) strlcpy(fileinfo->fi_name, name, sizeof (fileinfo->fi_name));
 
@@ -1194,14 +1197,18 @@
 		return (ENOENT);
 	}
 
-	case_conflict = ((od->d_flags & SMB_ODIR_FLAG_IGNORE_CASE) &&
-	    (odirent->od_eflags & ED_CASE_CONFLICT));
-	if (case_conflict || smb_needs_mangled(odirent->od_name)) {
-		smb_mangle(odirent->od_name, odirent->od_ino,
-		    fileinfo->fi_shortname, SMB_SHORTNAMELEN);
+	name = odirent->od_name;
+	if (od->d_flags & SMB_ODIR_FLAG_SHORTNAMES) {
+		case_conflict = ((od->d_flags & SMB_ODIR_FLAG_IGNORE_CASE) &&
+		    (odirent->od_eflags & ED_CASE_CONFLICT));
+		if (case_conflict || smb_needs_mangled(name)) {
+			smb_mangle(name, odirent->od_ino,
+			    fileinfo->fi_shortname, SMB_SHORTNAMELEN);
+		}
+		if (case_conflict)
+			name = fileinfo->fi_shortname;
 	}
 
-	name = (case_conflict) ? fileinfo->fi_shortname : odirent->od_name;
 	(void) strlcpy(fileinfo->fi_name, name, sizeof (fileinfo->fi_name));
 
 	fileinfo->fi_cookie = (uint32_t)od->d_offset;
@@ -1261,3 +1268,34 @@
 
 	return (B_TRUE);
 }
+
+/*
+ * smb_odir_match_name
+ *
+ * Check if the directory entry name matches the search pattern:
+ * - Don't match reserved dos filenames.
+ * - Check if odirent->od_name matches od->d_pattern.
+ * - If shortnames are supported, generate the shortname from
+ *   odirent->od_name and check if it matches od->d_pattern.
+ */
+boolean_t
+smb_odir_match_name(smb_odir_t *od, smb_odirent_t *odirent)
+{
+	char	*name = odirent->od_name;
+	char	shortname[SMB_SHORTNAMELEN];
+	ino64_t	ino = odirent->od_ino;
+
+	if (smb_is_reserved_dos_name(name))
+		return (B_FALSE);
+
+	if (smb_match_ci(od->d_pattern, name))
+		return (B_TRUE);
+
+	if (od->d_flags & SMB_ODIR_FLAG_SHORTNAMES) {
+		smb_mangle(name, ino, shortname, SMB_SHORTNAMELEN);
+		if (smb_match_ci(od->d_pattern, shortname))
+			return (B_TRUE);
+	}
+
+	return (B_FALSE);
+}
--- a/usr/src/uts/common/fs/smbsrv/smb_ofile.c	Thu Jul 22 12:31:36 2010 -0700
+++ b/usr/src/uts/common/fs/smbsrv/smb_ofile.c	Thu Jul 22 14:53:56 2010 -0700
@@ -217,7 +217,6 @@
 	mutex_init(&of->f_mutex, NULL, MUTEX_DEFAULT, NULL);
 	of->f_state = SMB_OFILE_STATE_OPEN;
 
-
 	if (ftype == SMB_FTYPE_MESG_PIPE) {
 		of->f_pipe = smb_opipe_alloc(tree->t_server);
 		smb_server_inc_pipes(of->f_server);
@@ -338,15 +337,11 @@
 		ASSERT(of->f_refcnt);
 		ASSERT(of->f_state == SMB_OFILE_STATE_CLOSING);
 		of->f_state = SMB_OFILE_STATE_CLOSED;
-		mutex_exit(&of->f_mutex);
 		if (of->f_node != NULL) {
 			smb_node_dec_open_ofiles(of->f_node);
-			if (of->f_oplock_granted) {
-				smb_oplock_release(of->f_node, of);
-				of->f_oplock_granted = B_FALSE;
-			}
+			smb_oplock_release(of->f_node, of);
 		}
-		return;
+		break;
 	}
 	case SMB_OFILE_STATE_CLOSED:
 	case SMB_OFILE_STATE_CLOSING:
@@ -483,20 +478,11 @@
  * iteration may be in progress.
  */
 void
-smb_ofile_release(smb_ofile_t	*of)
+smb_ofile_release(smb_ofile_t *of)
 {
-	boolean_t	rb;
-
 	SMB_OFILE_VALID(of);
 
 	mutex_enter(&of->f_mutex);
-	if (of->f_oplock_exit) {
-		mutex_exit(&of->f_mutex);
-		rb = smb_oplock_broadcast(of->f_node);
-		mutex_enter(&of->f_mutex);
-		if (rb)
-			of->f_oplock_exit = B_FALSE;
-	}
 	ASSERT(of->f_refcnt);
 	of->f_refcnt--;
 	switch (of->f_state) {
@@ -517,6 +503,35 @@
 }
 
 /*
+ * smb_ofile_request_complete
+ *
+ * During oplock acquisition, all other oplock requests on the node
+ * are blocked until the acquire request completes and the response
+ * is on the wire.
+ * Call smb_oplock_broadcast to notify the node that the request
+ * has completed.
+ *
+ * THIS MECHANISM RELIES ON THE FACT THAT THE OFILE IS NOT REMOVED
+ * FROM THE SR UNTIL REQUEST COMPLETION (when the sr is destroyed)
+ */
+void
+smb_ofile_request_complete(smb_ofile_t *of)
+{
+	SMB_OFILE_VALID(of);
+
+	switch (of->f_ftype) {
+	case SMB_FTYPE_DISK:
+		ASSERT(of->f_node);
+		smb_oplock_broadcast(of->f_node);
+		break;
+	case SMB_FTYPE_MESG_PIPE:
+		break;
+	default:
+		break;
+	}
+}
+
+/*
  * smb_ofile_lookup_by_fid
  *
  * Find the open file whose fid matches the one specified in the request.
@@ -735,17 +750,6 @@
 	return (rc);
 }
 
-void
-smb_ofile_set_oplock_granted(smb_ofile_t *of)
-{
-	SMB_OFILE_VALID(of);
-	mutex_enter(&of->f_mutex);
-	ASSERT(!of->f_oplock_granted);
-	of->f_oplock_granted = B_TRUE;
-	of->f_oplock_exit = B_TRUE;
-	mutex_exit(&of->f_mutex);
-}
-
 /*
  * smb_ofile_pending_write_time
  *
@@ -994,6 +998,18 @@
 	return (NT_STATUS_SUCCESS);
 }
 
+/*
+ * smb_ofile_share_check
+ *
+ * Check if ofile was opened with share access NONE (0).
+ * Returns: B_TRUE  - share access non-zero
+ *          B_FALSE - share access NONE
+ */
+boolean_t
+smb_ofile_share_check(smb_ofile_t *of)
+{
+	return (!SMB_DENY_ALL(of->f_share_access));
+}
 
 /*
  * check file sharing rules for current open request
--- a/usr/src/uts/common/fs/smbsrv/smb_open_andx.c	Thu Jul 22 12:31:36 2010 -0700
+++ b/usr/src/uts/common/fs/smbsrv/smb_open_andx.c	Thu Jul 22 14:53:56 2010 -0700
@@ -19,8 +19,7 @@
  * CDDL HEADER END
  */
 /*
- * Copyright 2010 Sun Microsystems, Inc.  All rights reserved.
- * Use is subject to license terms.
+ * Copyright (c) 2007, 2010, Oracle and/or its affiliates. All rights reserved.
  */
 
 #include <smbsrv/smb_kproto.h>
@@ -264,6 +263,7 @@
 	} else {
 		op->op_oplock_level = SMB_OPLOCK_NONE;
 	}
+	op->op_oplock_levelII = B_FALSE;
 
 	if (smb_common_open(sr) != NT_STATUS_SUCCESS)
 		return (SDRC_ERROR);
@@ -372,6 +372,8 @@
 	if (op->omode & SMB_DA_WRITE_THROUGH)
 		op->create_options |= FILE_WRITE_THROUGH;
 
+	op->op_oplock_levelII = B_FALSE;
+
 	if (smb_common_open(sr) != NT_STATUS_SUCCESS)
 		return (SDRC_ERROR);
 
@@ -480,6 +482,7 @@
 	} else {
 		op->op_oplock_level = SMB_OPLOCK_NONE;
 	}
+	op->op_oplock_levelII = B_FALSE;
 
 	if (smb_common_open(sr) != NT_STATUS_SUCCESS)
 		return (SDRC_ERROR);
--- a/usr/src/uts/common/fs/smbsrv/smb_opipe.c	Thu Jul 22 12:31:36 2010 -0700
+++ b/usr/src/uts/common/fs/smbsrv/smb_opipe.c	Thu Jul 22 14:53:56 2010 -0700
@@ -235,7 +235,7 @@
 	uint32_t buflen = SMB_OPIPE_DOOR_BUFSIZE;
 	uint32_t len;
 
-	if ((opipe->p_event = smb_event_create()) == NULL)
+	if ((opipe->p_event = smb_event_create(SMB_EVENT_TIMEOUT)) == NULL)
 		return (-1);
 
 	smb_user_netinfo_init(user, userinfo);
--- a/usr/src/uts/common/fs/smbsrv/smb_oplock.c	Thu Jul 22 12:31:36 2010 -0700
+++ b/usr/src/uts/common/fs/smbsrv/smb_oplock.c	Thu Jul 22 14:53:56 2010 -0700
@@ -21,441 +21,809 @@
 /*
  * Copyright (c) 2007, 2010, Oracle and/or its affiliates. All rights reserved.
  */
+
 /*
- * SMB Locking library functions.
+ * smb_oplock_wait / smb_oplock_broadcast
+ * When an oplock is being acquired, we must ensure that the acquisition
+ * response is submitted to the network stack before any other operation
+ * is permitted on the oplock.
+ * In smb_oplock_acquire, oplock.ol_xthread is set to point to the worker
+ * thread processing the command that is granting the oplock.
+ * Other threads accessing the oplock will be suspended in smb_oplock_wait().
+ * They will be awakened when the worker thread referenced in 'ol_xthread'
+ * calls smb_oplock_broadcast().
  *
- * You will notice that the functions in this file exit the lock of the session
- * and reenter it before returning. They even assume that the lock has been
- * entered in READER mode. The reason for that is a potential deadlock that may
- * occur when an oplock needs to be broken and the function
- * smb_session_break_oplock() is called. It should be noticed that the mutex of
- * the smb node, the oplock of which needs to be broken, is also exited before
- * calling smb_session_break_oplock(). The reason for that is the same: avoiding
- * a deadlock. That complexity is due to the fact that the lock of the session
- * is held during the treatment of a request. That complexity will go away when
- * that is not the case anymore.
+ * The purpose of this mechanism is to prevent another thread from
+ * triggering an oplock break before the response conveying the grant
+ * has been sent.
  */
 
 #include <smbsrv/smb_kproto.h>
-#include <smbsrv/smb_fsops.h>
+#include <sys/nbmlock.h>
 #include <inet/tcp.h>
 
+#define	SMB_OPLOCK_IS_EXCLUSIVE(level)		\
+	(((level) == SMB_OPLOCK_EXCLUSIVE) ||	\
+	((level) == SMB_OPLOCK_BATCH))
+
+extern int smb_fem_oplock_install(smb_node_t *);
+extern int smb_fem_oplock_uninstall(smb_node_t *);
+
+static int smb_oplock_install_fem(smb_node_t *);
+static void smb_oplock_uninstall_fem(smb_node_t *);
+
 static void smb_oplock_wait(smb_node_t *);
+static void smb_oplock_wait_ack(smb_node_t *, uint32_t);
+static void smb_oplock_timedout(smb_node_t *);
+
+static smb_oplock_grant_t *smb_oplock_create_grant(smb_ofile_t *, uint8_t);
+void smb_oplock_delete_grant(smb_oplock_grant_t *);
+static int smb_oplock_insert_grant(smb_node_t *, smb_oplock_grant_t *);
+static void smb_oplock_remove_grant(smb_node_t *, smb_oplock_grant_t *);
+static smb_oplock_grant_t *smb_oplock_exclusive_grant(list_t *);
+static smb_oplock_grant_t *smb_oplock_find_grant(list_t *, smb_ofile_t *);
+
+static smb_oplock_break_t *smb_oplock_create_break(smb_node_t *);
+static smb_oplock_break_t *smb_oplock_get_break(void);
+static void smb_oplock_delete_break(smb_oplock_break_t *);
+static void smb_oplock_process_levelII_break(smb_node_t *);
+
+static void smb_oplock_break_thread();
+
+/* levelII oplock break requests (smb_oplock_break_t) */
+static boolean_t	smb_oplock_initialized = B_FALSE;
+static kmem_cache_t	*smb_oplock_break_cache = NULL;
+static kmem_cache_t	*smb_oplock_grant_cache = NULL;
+static smb_llist_t	smb_oplock_breaks;
+static smb_thread_t	smb_oplock_thread;
+
 
 /*
- *	Magic		0xFF 'S' 'M' 'B'
- *	smb_com 	a byte, the "first" command
- *	Error		a 4-byte union, ignored in a request
- *	smb_flg		a one byte set of eight flags
- *	smb_flg2	a two byte set of 16 flags
- *	.		twelve reserved bytes, have a role
- *			in connectionless transports (IPX, UDP?)
- *	smb_tid		a 16-bit tree ID, a mount point sorta,
- *			0xFFFF is this command does not have
- *			or require a tree context
- *	smb_pid		a 16-bit process ID
- *	smb_uid		a 16-bit user ID, specific to this "session"
- *			and mapped to a system (bona-fide) UID
- *	smb_mid		a 16-bit multiplex ID, used to differentiate
- *			multiple simultaneous requests from the same
- *			process (pid) (ref RPC "xid")
- *
- * SMB_COM_LOCKING_ANDX allows both locking and/or unlocking of file range(s).
- *
- *  Client Request                     Description
- *  ================================== =================================
- *
- *  UCHAR WordCount;                   Count of parameter words = 8
- *  UCHAR AndXCommand;                 Secondary (X) command;  0xFF = none
- *  UCHAR AndXReserved;                Reserved (must be 0)
- *  USHORT AndXOffset;                 Offset to next command WordCount
- *  USHORT Fid;                        File handle
- *  UCHAR LockType;                    See LockType table below
- *  UCHAR OplockLevel;                 The new oplock level
- *  ULONG Timeout;                     Milliseconds to wait for unlock
- *  USHORT NumberOfUnlocks;            Num. unlock range structs following
- *  USHORT NumberOfLocks;              Num. lock range structs following
- *  USHORT ByteCount;                  Count of data bytes
- *  LOCKING_ANDX_RANGE Unlocks[];      Unlock ranges
- *  LOCKING_ANDX_RANGE Locks[];        Lock ranges
+ * smb_oplock_init
  *
- *  LockType Flag Name            Value Description
- *  ============================  ===== ================================
- *
- *  LOCKING_ANDX_SHARED_LOCK      0x01  Read-only lock
- *  LOCKING_ANDX_OPLOCK_RELEASE   0x02  Oplock break notification
- *  LOCKING_ANDX_CHANGE_LOCKTYPE  0x04  Change lock type
- *  LOCKING_ANDX_CANCEL_LOCK      0x08  Cancel outstanding request
- *  LOCKING_ANDX_LARGE_FILES      0x10  Large file locking format
- *
- *  LOCKING_ANDX_RANGE Format
- *  =====================================================================
- *
- *  USHORT Pid;                        PID of process "owning" lock
- *  ULONG Offset;                      Offset to bytes to [un]lock
- *  ULONG Length;                      Number of bytes to [un]lock
- *
- *  Large File LOCKING_ANDX_RANGE Format
- *  =====================================================================
- *
- *  USHORT Pid;                        PID of process "owning" lock
- *  USHORT Pad;                        Pad to DWORD align (mbz)
- *  ULONG OffsetHigh;                  Offset to bytes to [un]lock
- *                                      (high)
- *  ULONG OffsetLow;                   Offset to bytes to [un]lock (low)
- *  ULONG LengthHigh;                  Number of bytes to [un]lock
- *                                      (high)
- *  ULONG LengthLow;                   Number of bytes to [un]lock (low)
- *
- *  Server Response                    Description
- *  ================================== =================================
- *
- *  UCHAR WordCount;                   Count of parameter words = 2
- *  UCHAR AndXCommand;                 Secondary (X) command;  0xFF =
- *                                      none
- *  UCHAR AndXReserved;                Reserved (must be 0)
- *  USHORT AndXOffset;                 Offset to next command WordCount
- *  USHORT ByteCount;                  Count of data bytes = 0
- *
+ * This function is not multi-thread safe. The caller must make sure only one
+ * thread makes the call.
+ */
+int
+smb_oplock_init(void)
+{
+	int rc;
+
+	if (smb_oplock_initialized)
+		return (0);
+
+	smb_oplock_break_cache = kmem_cache_create("smb_oplock_break_cache",
+	    sizeof (smb_oplock_break_t), 8, NULL, NULL, NULL, NULL, NULL, 0);
+
+	smb_oplock_grant_cache = kmem_cache_create("smb_oplock_grant_cache",
+	    sizeof (smb_oplock_grant_t), 8, NULL, NULL, NULL, NULL, NULL, 0);
+
+	smb_llist_constructor(&smb_oplock_breaks, sizeof (smb_oplock_break_t),
+	    offsetof(smb_oplock_break_t, ob_lnd));
+
+	smb_thread_init(&smb_oplock_thread, "smb_thread_oplock_break",
+	    smb_oplock_break_thread, NULL, NULL, NULL);
+
+	rc = smb_thread_start(&smb_oplock_thread);
+	if (rc != 0) {
+		smb_thread_destroy(&smb_oplock_thread);
+		smb_llist_destructor(&smb_oplock_breaks);
+		kmem_cache_destroy(smb_oplock_break_cache);
+		kmem_cache_destroy(smb_oplock_grant_cache);
+		return (rc);
+	}
+
+	smb_oplock_initialized = B_TRUE;
+	return (0);
+}
+
+/*
+ * smb_oplock_fini
+ * This function is not multi-thread safe. The caller must make sure only one
+ * thread makes the call.
  */
+void
+smb_oplock_fini(void)
+{
+	smb_oplock_break_t	*ob;
+
+	if (!smb_oplock_initialized)
+		return;
+
+	smb_thread_stop(&smb_oplock_thread);
+	smb_thread_destroy(&smb_oplock_thread);
+
+	while ((ob = smb_llist_head(&smb_oplock_breaks)) != NULL) {
+		SMB_OPLOCK_BREAK_VALID(ob);
+		smb_llist_remove(&smb_oplock_breaks, ob);
+		smb_oplock_delete_break(ob);
+	}
+	smb_llist_destructor(&smb_oplock_breaks);
+
+	kmem_cache_destroy(smb_oplock_break_cache);
+	kmem_cache_destroy(smb_oplock_grant_cache);
+}
+
+/*
+ * smb_oplock_install_fem
+ * Install fem monitor for cross protocol oplock breaking.
+ */
+static int
+smb_oplock_install_fem(smb_node_t *node)
+{
+	ASSERT(MUTEX_HELD(&node->n_oplock.ol_mutex));
+
+	if (node->n_oplock.ol_fem == B_FALSE) {
+		if (smb_fem_oplock_install(node) != 0) {
+			cmn_err(CE_NOTE, "No oplock granted: "
+			    "failed to install fem monitor %s",
+			    node->vp->v_path);
+			return (-1);
+		}
+		node->n_oplock.ol_fem = B_TRUE;
+	}
+	return (0);
+}
+
+/*
+ * smb_oplock_uninstall_fem
+ * Uninstall fem monitor for cross protocol oplock breaking.
+ */
+static void
+smb_oplock_uninstall_fem(smb_node_t *node)
+{
+	ASSERT(MUTEX_HELD(&node->n_oplock.ol_mutex));
+
+	if (node->n_oplock.ol_fem) {
+		if (smb_fem_oplock_uninstall(node) == 0) {
+			node->n_oplock.ol_fem = B_FALSE;
+		} else {
+			cmn_err(CE_NOTE,
+			    "failed to uninstall fem monitor %s",
+			    node->vp->v_path);
+		}
+	}
+}
 
 /*
  * smb_oplock_acquire
  *
- * Attempt to acquire an oplock. Note that the oplock granted may be
- * none, i.e. the oplock was not granted. The result of the acquisition is
- * provided in ol->ol_level.
- *
- * Grant an oplock to the requestor if this session is the only one
- * that has the file open, regardless of the number of instances of
- * the file opened by this session.
+ * Attempt to acquire an oplock. Clients will request EXCLUSIVE or BATCH,
+ * but might only be granted LEVEL_II or NONE.
  *
- * However, if there is no oplock on this file and there is already
- * at least one open, we will not grant an oplock, even if the only
- * existing opens are from the same client.  This is "server discretion."
+ * If oplocks are not supported on the tree, or node, grant NONE.
+ * If nobody else has the file open, grant the requested level.
+ * If any of the following are true, grant NONE:
+ * - there is an exclusive oplock on the node
+ * - op->op_oplock_levelII is B_FALSE (LEVEL_II not supported by open cmd.
+ * - LEVEL_II oplocks are not supported for the session
+ * - a BATCH oplock is requested on a named stream
+ * - there are any range locks on the node
+ * Otherwise, grant LEVEL_II.
  *
- * An oplock may need to be broken in order for one to be granted, and
- * depending on what action is taken by the other client (unlock or close),
- * an oplock may or may not be granted.  (The breaking of an oplock is
- * done earlier in the calling path.)
+ * ol->ol_xthread is set to the current thread to lock the oplock against
+ * other operations until the acquire response is on the wire. When the
+ * acquire response is on the wire, smb_oplock_broadcast() is called to
+ * reset ol->ol_xthread and wake any waiting threads.
  */
 void
-smb_oplock_acquire(smb_node_t *node, smb_ofile_t *of, smb_arg_open_t *op)
+smb_oplock_acquire(smb_request_t *sr, smb_node_t *node, smb_ofile_t *ofile)
 {
-	smb_session_t	*session;
-	smb_oplock_t	*ol;
-	clock_t		time;
+	smb_oplock_t		*ol;
+	smb_oplock_grant_t	*og;
+	list_t			*grants;
+	smb_arg_open_t		*op;
+	smb_tree_t		*tree;
+	smb_session_t		*session;
 
 	SMB_NODE_VALID(node);
-	SMB_OFILE_VALID(of);
+	SMB_OFILE_VALID(ofile);
 
-	ASSERT(node == SMB_OFILE_GET_NODE(of));
+	ASSERT(node == SMB_OFILE_GET_NODE(ofile));
 
-	session = SMB_OFILE_GET_SESSION(of);
+	op = &sr->sr_open;
+	tree = SMB_OFILE_GET_TREE(ofile);
+	session = SMB_OFILE_GET_SESSION(ofile);
 
-	if (!smb_session_oplocks_enable(session) ||
-	    smb_tree_has_feature(SMB_OFILE_GET_TREE(of), SMB_TREE_NO_OPLOCKS)) {
+	if (!smb_tree_has_feature(tree, SMB_TREE_OPLOCKS) ||
+	    (op->op_oplock_level == SMB_OPLOCK_NONE) ||
+	    ((op->op_oplock_level == SMB_OPLOCK_BATCH) &&
+	    SMB_IS_STREAM(node))) {
 		op->op_oplock_level = SMB_OPLOCK_NONE;
 		return;
 	}
 
 	ol = &node->n_oplock;
-	time = MSEC_TO_TICK(smb_oplock_timeout) + ddi_get_lbolt();
+	grants = &ol->ol_grants;
 
-	mutex_enter(&node->n_mutex);
+	mutex_enter(&ol->ol_mutex);
+	smb_oplock_wait(node);
+
+	nbl_start_crit(node->vp, RW_READER);
 
-	switch (node->n_state) {
-	case SMB_NODE_STATE_OPLOCK_GRANTED:
-		if (SMB_SESSION_GET_ID(session) == ol->ol_sess_id) {
-			mutex_exit(&node->n_mutex);
+	if ((node->n_open_count > 1) ||
+	    (node->n_opening_count > 1) ||
+	    smb_vop_other_opens(node->vp, ofile->f_mode)) {
+		if ((!op->op_oplock_levelII) ||
+		    (!smb_session_levelII_oplocks(session)) ||
+		    (smb_oplock_exclusive_grant(grants) != NULL) ||
+		    (smb_range_check(sr, node, 0, UINT64_MAX, B_TRUE) != 0)) {
+			op->op_oplock_level = SMB_OPLOCK_NONE;
+			nbl_end_crit(node->vp);
+			mutex_exit(&ol->ol_mutex);
 			return;
 		}
+
+		op->op_oplock_level = SMB_OPLOCK_LEVEL_II;
+	}
+
+	nbl_end_crit(node->vp);
+
+	og = smb_oplock_create_grant(ofile, op->op_oplock_level);
+	if (smb_oplock_insert_grant(node, og) != 0) {
+		smb_oplock_delete_grant(og);
+		op->op_oplock_level = SMB_OPLOCK_NONE;
+		mutex_exit(&ol->ol_mutex);
+		return;
+	}
+
+	ol->ol_xthread = curthread;
+	mutex_exit(&ol->ol_mutex);
+}
+
+/*
+ * smb_oplock_break
+ *
+ * Break granted oplocks according to the following rules:
+ *
+ * If there's an exclusive oplock granted on the node
+ *  - if the BREAK_BATCH flags is specified and the oplock is not
+ *    a batch oplock, no break is required.
+ *  - if the session doesn't support LEVEL II oplocks, and 'brk' is
+ *    BREAK_TO_LEVEL_II, do a BREAK_TO_NONE.
+ *  - if the oplock is already breaking update the break level (if
+ *    the requested break is to a lesser level), otherwise send an
+ *    oplock break.
+ *    Wait for acknowledgement of the break (unless NOWAIT flag is set)
+ *
+ * Otherwise:
+ * If there are level II oplocks granted on the node, and the flags
+ * indicate that they should be broken (BREAK_TO_NONE specified,
+ * BREAK_EXCLUSIVE, BREAK_BATCH not specified) queue the levelII
+ * break request for asynchronous processing.
+ *
+ * Returns:
+ *       0 - oplock broken (or no break required)
+ *  EAGAIN - oplock break request sent and would block
+ *           awaiting the reponse but NOWAIT was specified
+ */
+int
+smb_oplock_break(smb_request_t *sr, smb_node_t *node, uint32_t flags)
+{
+	smb_oplock_t		*ol;
+	smb_oplock_grant_t	*og;
+	list_t			*grants;
+	uint32_t		timeout;
+	uint8_t			brk;
+
+	SMB_NODE_VALID(node);
+	ol = &node->n_oplock;
+	grants = &ol->ol_grants;
+
+	mutex_enter(&ol->ol_mutex);
+	smb_oplock_wait(node);
+
+	og = list_head(grants);
+	if (og == NULL) {
+		mutex_exit(&ol->ol_mutex);
+		return (0);
+	}
+
+	SMB_OPLOCK_GRANT_VALID(og);
+
+	/* break levelII oplocks */
+	if (og->og_level == SMB_OPLOCK_LEVEL_II) {
+		mutex_exit(&ol->ol_mutex);
+
+		if ((flags & SMB_OPLOCK_BREAK_TO_NONE) &&
+		    !(flags & SMB_OPLOCK_BREAK_EXCLUSIVE) &&
+		    !(flags & SMB_OPLOCK_BREAK_BATCH))  {
+			smb_oplock_break_levelII(node);
+		}
+		return (0);
+	}
+
+	/* break exclusive oplock */
+	if ((flags & SMB_OPLOCK_BREAK_BATCH) &&
+	    (og->og_level != SMB_OPLOCK_BATCH)) {
+		mutex_exit(&ol->ol_mutex);
+		return (0);
+	}
+
+	if ((flags & SMB_OPLOCK_BREAK_TO_LEVEL_II) &&
+	    smb_session_levelII_oplocks(og->og_session)) {
+		brk = SMB_OPLOCK_BREAK_TO_LEVEL_II;
+	} else {
+		brk = SMB_OPLOCK_BREAK_TO_NONE;
+	}
+
+	switch (ol->ol_break) {
+	case SMB_OPLOCK_NO_BREAK:
+		ol->ol_break = brk;
+		smb_session_oplock_break(og->og_session,
+		    og->og_tid, og->og_fid, brk);
 		break;
-	case SMB_NODE_STATE_AVAILABLE:
-	case SMB_NODE_STATE_OPLOCK_BREAKING:
+	case SMB_OPLOCK_BREAK_TO_LEVEL_II:
+		if (brk == SMB_OPLOCK_BREAK_TO_NONE)
+			ol->ol_break = SMB_OPLOCK_BREAK_TO_NONE;
+		break;
+	case SMB_OPLOCK_BREAK_TO_NONE:
+	default:
+		break;
+	}
+
+	if (flags & SMB_OPLOCK_BREAK_NOWAIT) {
+		mutex_exit(&ol->ol_mutex);
+		return (EAGAIN);
+	}
+
+	if (sr && (sr->session == og->og_session) &&
+	    (sr->smb_uid == og->og_uid)) {
+		timeout = smb_oplock_min_timeout;
+	} else {
+		timeout = smb_oplock_timeout;
+	}
+
+	mutex_exit(&ol->ol_mutex);
+	smb_oplock_wait_ack(node, timeout);
+	return (0);
+}
+
+/*
+ * smb_oplock_break_levelII
+ *
+ * LevelII (shared) oplock breaks are processed asynchronously.
+ * Unlike exclusive oplock breaks, the thread initiating the break
+ * is NOT blocked while the request is processed.
+ *
+ * Create an oplock_break_request and add it to the list for async
+ * processing.
+ */
+void
+smb_oplock_break_levelII(smb_node_t *node)
+{
+	smb_oplock_break_t	*ob;
+
+	ob = smb_oplock_create_break(node);
+
+	smb_llist_enter(&smb_oplock_breaks, RW_WRITER);
+	smb_llist_insert_tail(&smb_oplock_breaks, ob);
+	smb_llist_exit(&smb_oplock_breaks);
+
+	smb_thread_signal(&smb_oplock_thread);
+}
+
+/*
+ * smb_oplock_break_thread
+ *
+ * The smb_oplock_thread is woken when an oplock break request is
+ * added to the list of pending levelII oplock break requests.
+ * Gets the oplock break request from the list, processes it and
+ * deletes it.
+ */
+/*ARGSUSED*/
+static void
+smb_oplock_break_thread(smb_thread_t *thread, void *arg)
+{
+	smb_oplock_break_t	*ob;
+
+	while (smb_thread_continue(thread)) {
+		while ((ob = smb_oplock_get_break()) != NULL) {
+			smb_oplock_process_levelII_break(ob->ob_node);
+			smb_oplock_delete_break(ob);
+		}
+	}
+}
+
+/*
+ * smb_oplock_get_break
+ *
+ * Remove and return the next oplock break request from the list
+ */
+static smb_oplock_break_t *
+smb_oplock_get_break(void)
+{
+	smb_oplock_break_t	*ob;
+
+	smb_llist_enter(&smb_oplock_breaks, RW_WRITER);
+	if ((ob = smb_llist_head(&smb_oplock_breaks)) != NULL) {
+		SMB_OPLOCK_BREAK_VALID(ob);
+		smb_llist_remove(&smb_oplock_breaks, ob);
+	}
+	smb_llist_exit(&smb_oplock_breaks);
+	return (ob);
+}
+
+/*
+ * smb_oplock_process_levelII_break
+ */
+void
+smb_oplock_process_levelII_break(smb_node_t *node)
+{
+	smb_oplock_t		*ol;
+	smb_oplock_grant_t	*og;
+	list_t			*grants;
+
+	if (!smb_oplock_levelII)
+		return;
+
+	ol = &node->n_oplock;
+	mutex_enter(&ol->ol_mutex);
+	smb_oplock_wait(node);
+	grants = &node->n_oplock.ol_grants;
+
+	while ((og = list_head(grants)) != NULL) {
+		SMB_OPLOCK_GRANT_VALID(og);
+
+		if (SMB_OPLOCK_IS_EXCLUSIVE(og->og_level))
+			break;
+
+		smb_session_oplock_break(og->og_session,
+		    og->og_tid, og->og_fid, SMB_OPLOCK_BREAK_TO_NONE);
+		smb_oplock_remove_grant(node, og);
+		smb_oplock_delete_grant(og);
+	}
+
+	mutex_exit(&ol->ol_mutex);
+}
+
+/*
+ * smb_oplock_wait_ack
+ *
+ * Timed wait for an oplock break acknowledgement (or oplock release).
+ */
+static void
+smb_oplock_wait_ack(smb_node_t *node, uint32_t timeout)
+{
+	smb_oplock_t	*ol;
+	clock_t		time;
+
+	ol = &node->n_oplock;
+	mutex_enter(&ol->ol_mutex);
+	time = MSEC_TO_TICK(timeout) + ddi_get_lbolt();
+
+	while (ol->ol_break != SMB_OPLOCK_NO_BREAK) {
+		if (cv_timedwait(&ol->ol_cv, &ol->ol_mutex, time) < 0) {
+			smb_oplock_timedout(node);
+			cv_broadcast(&ol->ol_cv);
+			break;
+		}
+	}
+	mutex_exit(&ol->ol_mutex);
+}
+
+/*
+ * smb_oplock_timedout
+ *
+ * An oplock break has not been acknowledged within timeout
+ * 'smb_oplock_timeout'.
+ * Set oplock grant to the desired break level.
+ */
+static void
+smb_oplock_timedout(smb_node_t *node)
+{
+	smb_oplock_t		*ol;
+	smb_oplock_grant_t	*og;
+	list_t			*grants;
+
+	ol = &node->n_oplock;
+	grants = &ol->ol_grants;
+
+	ASSERT(MUTEX_HELD(&ol->ol_mutex));
+
+	og = smb_oplock_exclusive_grant(grants);
+	if (og) {
+		switch (ol->ol_break) {
+		case SMB_OPLOCK_BREAK_TO_NONE:
+			og->og_level = SMB_OPLOCK_NONE;
+			smb_oplock_remove_grant(node, og);
+			smb_oplock_delete_grant(og);
+			break;
+		case SMB_OPLOCK_BREAK_TO_LEVEL_II:
+			og->og_level = SMB_OPLOCK_LEVEL_II;
+			break;
+		default:
+			SMB_PANIC();
+		}
+	}
+	ol->ol_break = SMB_OPLOCK_NO_BREAK;
+}
+
+/*
+ * smb_oplock_release
+ *
+ * Release the oplock granted on ofile 'of'.
+ * Wake any threads waiting for an oplock break acknowledgement for
+ * this oplock.
+ * This is called when the ofile is being closed.
+ */
+void
+smb_oplock_release(smb_node_t *node, smb_ofile_t *of)
+{
+	smb_oplock_t		*ol;
+	smb_oplock_grant_t	*og;
+	list_t			*grants;
+
+	ol = &node->n_oplock;
+	grants = &ol->ol_grants;
+
+	mutex_enter(&ol->ol_mutex);
+	smb_oplock_wait(node);
+
+	og = smb_oplock_find_grant(grants, of);
+	if (og) {
+		smb_oplock_remove_grant(node, og);
+		smb_oplock_delete_grant(og);
+
+		if (ol->ol_break != SMB_OPLOCK_NO_BREAK) {
+			ol->ol_break = SMB_OPLOCK_NO_BREAK;
+			cv_broadcast(&ol->ol_cv);
+		}
+	}
+
+	mutex_exit(&ol->ol_mutex);
+}
+
+/*
+ * smb_oplock_ack
+ *
+ * Process oplock acknowledgement received for ofile 'of'.
+ * - oplock.ol_break is the break level that was requested.
+ * - brk is the break level being acknowledged by the client.
+ *
+ * Update the oplock grant level to the lesser of ol_break and brk.
+ * If the grant is now SMB_OPLOCK_NONE, remove the grant from the
+ * oplock's grant list and delete it.
+ * If the requested break level (ol_break) was NONE and the brk is
+ * LEVEL_II, send another oplock break (NONE). Do not wait for an
+ * acknowledgement.
+ * Wake any threads waiting for the oplock break acknowledgement.
+ */
+void
+smb_oplock_ack(smb_node_t *node, smb_ofile_t *of, uint8_t brk)
+{
+	smb_oplock_t		*ol;
+	smb_oplock_grant_t	*og;
+	list_t			*grants;
+	boolean_t		brk_to_none = B_FALSE;
+
+	ol = &node->n_oplock;
+	grants = &ol->ol_grants;
+
+	mutex_enter(&ol->ol_mutex);
+	smb_oplock_wait(node);
+
+	if ((ol->ol_break == SMB_OPLOCK_NO_BREAK) ||
+	    ((og = smb_oplock_find_grant(grants, of)) == NULL)) {
+		mutex_exit(&ol->ol_mutex);
+		return;
+	}
+
+	switch (brk) {
+	case SMB_OPLOCK_BREAK_TO_NONE:
+		og->og_level = SMB_OPLOCK_NONE;
+		break;
+	case SMB_OPLOCK_BREAK_TO_LEVEL_II:
+		if (ol->ol_break == SMB_OPLOCK_BREAK_TO_LEVEL_II) {
+			og->og_level = SMB_OPLOCK_LEVEL_II;
+		} else {
+			/* SMB_OPLOCK_BREAK_TO_NONE */
+			og->og_level = SMB_OPLOCK_NONE;
+			brk_to_none = B_TRUE;
+		}
 		break;
 	default:
 		SMB_PANIC();
 	}
 
-	for (;;) {
-		int	rc;
-
-		smb_oplock_wait(node);
+	if (og->og_level == SMB_OPLOCK_NONE) {
+		smb_oplock_remove_grant(node, og);
+		smb_oplock_delete_grant(og);
+	}
 
-		if (node->n_state == SMB_NODE_STATE_AVAILABLE) {
-			if ((op->op_oplock_level == SMB_OPLOCK_LEVEL_II) ||
-			    (op->op_oplock_level == SMB_OPLOCK_NONE) ||
-			    (node->n_open_count > 1)) {
-				mutex_exit(&node->n_mutex);
-				op->op_oplock_level = SMB_OPLOCK_NONE;
-				return;
-			}
-			ol->ol_ofile = of;
-			ol->ol_sess_id = SMB_SESSION_GET_ID(session);
-			ol->ol_level = op->op_oplock_level;
-			ol->ol_xthread = curthread;
-			node->n_state = SMB_NODE_STATE_OPLOCK_GRANTED;
-			mutex_exit(&node->n_mutex);
-			if (smb_fsop_oplock_install(node, of->f_mode) == 0) {
-				smb_ofile_set_oplock_granted(of);
-				return;
-			}
-			mutex_enter(&node->n_mutex);
-			ASSERT(node->n_state == SMB_NODE_STATE_OPLOCK_GRANTED);
-			node->n_state = SMB_NODE_STATE_AVAILABLE;
-			ol->ol_xthread = NULL;
-			op->op_oplock_level = SMB_OPLOCK_NONE;
-			cv_broadcast(&ol->ol_cv);
-			break;
-		}
+	ol->ol_break = SMB_OPLOCK_NO_BREAK;
+	cv_broadcast(&ol->ol_cv);
 
-		if (node->n_state == SMB_NODE_STATE_OPLOCK_GRANTED) {
-			if (SMB_SESSION_GET_ID(session) == ol->ol_sess_id)
-				break;
-			node->n_state = SMB_NODE_STATE_OPLOCK_BREAKING;
-			mutex_exit(&node->n_mutex);
-			smb_session_oplock_break(
-			    SMB_OFILE_GET_SESSION(ol->ol_ofile), ol->ol_ofile);
-			mutex_enter(&node->n_mutex);
-			continue;
-		}
-
-		ASSERT(node->n_state == SMB_NODE_STATE_OPLOCK_BREAKING);
-
-		rc = cv_timedwait(&ol->ol_cv, &node->n_mutex, time);
+	if (brk_to_none) {
+		smb_session_oplock_break(of->f_session,
+		    of->f_tree->t_tid, of->f_fid,
+		    SMB_OPLOCK_BREAK_TO_NONE);
+	}
 
-		if (rc == -1) {
-			/*
-			 * Oplock release timed out.
-			 */
-			if (node->n_state == SMB_NODE_STATE_OPLOCK_BREAKING) {
-				node->n_state = SMB_NODE_STATE_AVAILABLE;
-				ol->ol_xthread = curthread;
-				mutex_exit(&node->n_mutex);
-				smb_fsop_oplock_uninstall(node);
-				mutex_enter(&node->n_mutex);
-				ol->ol_xthread = NULL;
-				cv_broadcast(&ol->ol_cv);
-			}
-		}
-	}
-	mutex_exit(&node->n_mutex);
+	mutex_exit(&ol->ol_mutex);
 }
 
 /*
- * smb_oplock_break
- *
- * The oplock break may succeed for multiple reasons: file close, oplock
- * release, holder connection dropped, requesting client disconnect etc.
- *
- * Returns:
+ * smb_oplock_broadcast
  *
- *	B_TRUE	The oplock is broken.
- *	B_FALSE	The oplock is being broken. This is returned if nowait is set
- *		to B_TRUE;
- */
-boolean_t
-smb_oplock_break(smb_node_t *node, smb_session_t *session, boolean_t nowait)
-{
-	smb_oplock_t	*ol;
-	clock_t		time;
-
-	SMB_NODE_VALID(node);
-	ol = &node->n_oplock;
-	time = MSEC_TO_TICK(smb_oplock_timeout) + ddi_get_lbolt();
-
-	if (session != NULL) {
-		mutex_enter(&node->n_mutex);
-		if (SMB_SESSION_GET_ID(session) == ol->ol_sess_id) {
-			mutex_exit(&node->n_mutex);
-			return (B_TRUE);
-		}
-	} else {
-		mutex_enter(&node->n_mutex);
-	}
-
-	for (;;) {
-		int	rc;
-
-		smb_oplock_wait(node);
-
-		if (node->n_state == SMB_NODE_STATE_AVAILABLE) {
-			mutex_exit(&node->n_mutex);
-			return (B_TRUE);
-		}
-
-		if (node->n_state == SMB_NODE_STATE_OPLOCK_GRANTED) {
-			node->n_state = SMB_NODE_STATE_OPLOCK_BREAKING;
-			mutex_exit(&node->n_mutex);
-			smb_session_oplock_break(
-			    SMB_OFILE_GET_SESSION(ol->ol_ofile), ol->ol_ofile);
-			mutex_enter(&node->n_mutex);
-			continue;
-		}
-
-		ASSERT(node->n_state == SMB_NODE_STATE_OPLOCK_BREAKING);
-		if (nowait) {
-			mutex_exit(&node->n_mutex);
-			return (B_FALSE);
-		}
-		rc = cv_timedwait(&ol->ol_cv, &node->n_mutex, time);
-		if (rc == -1) {
-			/*
-			 * Oplock release timed out.
-			 */
-			if (node->n_state == SMB_NODE_STATE_OPLOCK_BREAKING) {
-				node->n_state = SMB_NODE_STATE_AVAILABLE;
-				ol->ol_xthread = curthread;
-				mutex_exit(&node->n_mutex);
-				smb_fsop_oplock_uninstall(node);
-				mutex_enter(&node->n_mutex);
-				ol->ol_xthread = NULL;
-				cv_broadcast(&ol->ol_cv);
-				break;
-			}
-		}
-	}
-	mutex_exit(&node->n_mutex);
-	return (B_TRUE);
-}
-
-/*
- * smb_oplock_release
- *
- * This function releases the oplock on the node passed in. If other threads
- * were waiting for the oplock to be released they are signaled.
+ * ol->ol_xthread identifies the thread that was performing an oplock
+ * acquire. Other threads may be blocked awaiting completion of the
+ * acquire.
+ * If the calling thread is ol_ol_xthread, wake any waiting threads.
  */
 void
-smb_oplock_release(smb_node_t *node, smb_ofile_t *of)
+smb_oplock_broadcast(smb_node_t *node)
 {
 	smb_oplock_t	*ol;
 
 	SMB_NODE_VALID(node);
 	ol = &node->n_oplock;
 
-	mutex_enter(&node->n_mutex);
-	smb_oplock_wait(node);
-	switch (node->n_state) {
-	case SMB_NODE_STATE_AVAILABLE:
-		break;
-
-	case SMB_NODE_STATE_OPLOCK_GRANTED:
-	case SMB_NODE_STATE_OPLOCK_BREAKING:
-		if (ol->ol_ofile == of) {
-			node->n_state = SMB_NODE_STATE_AVAILABLE;
-			ol->ol_xthread = curthread;
-			mutex_exit(&node->n_mutex);
-			smb_fsop_oplock_uninstall(node);
-			mutex_enter(&node->n_mutex);
-			ol->ol_xthread = NULL;
-			cv_broadcast(&ol->ol_cv);
-		}
-		break;
-
-	default:
-		SMB_PANIC();
-	}
-	mutex_exit(&node->n_mutex);
-}
-
-/*
- * smb_oplock_conflict
- *
- * The two checks on "session" and "op" are primarily for the open path.
- * Other SMB functions may call smb_oplock_conflict() with a session
- * pointer so as to do the session check.
- */
-boolean_t
-smb_oplock_conflict(smb_node_t *node, smb_session_t *session,
-    smb_arg_open_t *op)
-{
-	boolean_t	rb;
-
-	SMB_NODE_VALID(node);
-	SMB_SESSION_VALID(session);
-
-	mutex_enter(&node->n_mutex);
-	smb_oplock_wait(node);
-	switch (node->n_state) {
-	case SMB_NODE_STATE_AVAILABLE:
-		rb = B_FALSE;
-		break;
-
-	case SMB_NODE_STATE_OPLOCK_GRANTED:
-	case SMB_NODE_STATE_OPLOCK_BREAKING:
-		if (SMB_SESSION_GET_ID(session) == node->n_oplock.ol_sess_id) {
-			rb = B_FALSE;
-			break;
-		}
-
-		if (op != NULL) {
-			if (((op->desired_access & ~(FILE_READ_ATTRIBUTES |
-			    FILE_WRITE_ATTRIBUTES | SYNCHRONIZE)) == 0) &&
-			    (op->create_disposition != FILE_SUPERSEDE) &&
-			    (op->create_disposition != FILE_OVERWRITE)) {
-				/* Attributs only */
-				rb = B_FALSE;
-				break;
-			}
-		}
-		rb = B_TRUE;
-		break;
-
-	default:
-		SMB_PANIC();
-	}
-	mutex_exit(&node->n_mutex);
-	return (rb);
-}
-
-/*
- * smb_oplock_broadcast
- *
- * The the calling thread has the pointer to its context stored in ol_thread
- * it resets that field. If any other thread is waiting for that field to
- * turn to NULL it is signaled.
- *
- * Returns:
- *	B_TRUE	Oplock unlocked
- *	B_FALSE	Oplock still locked
- */
-boolean_t
-smb_oplock_broadcast(smb_node_t *node)
-{
-	smb_oplock_t	*ol;
-	boolean_t	rb;
-
-	SMB_NODE_VALID(node);
-	ol = &node->n_oplock;
-	rb = B_FALSE;
-
-	mutex_enter(&node->n_mutex);
+	mutex_enter(&ol->ol_mutex);
 	if ((ol->ol_xthread != NULL) && (ol->ol_xthread == curthread)) {
 		ol->ol_xthread = NULL;
 		cv_broadcast(&ol->ol_cv);
-		rb = B_TRUE;
 	}
-	mutex_exit(&node->n_mutex);
-	return (rb);
+	mutex_exit(&ol->ol_mutex);
 }
 
 /*
  * smb_oplock_wait
  *
- * The mutex of the node must have been entered before calling this function.
- * If the field ol_xthread is not NULL and doesn't contain the pointer to the
- * context of the calling thread, the caller will sleep until that field is
- * reset (set to NULL).
+ * Wait for the completion of an oplock acquire.
+ * If ol_xthread is not NULL and doesn't contain the pointer to the
+ * context of the calling thread, the caller will sleep until the
+ * ol_xthread is reset to NULL (via smb_oplock_broadcast()).
  */
 static void
 smb_oplock_wait(smb_node_t *node)
 {
-	smb_oplock_t	*ol = &node->n_oplock;
+	smb_oplock_t	*ol;
+
+	ol = &node->n_oplock;
+	ASSERT(MUTEX_HELD(&ol->ol_mutex));
 
 	if ((ol->ol_xthread != NULL) && (ol->ol_xthread != curthread)) {
-		ASSERT(!MUTEX_HELD(&ol->ol_ofile->f_mutex));
 		while (ol->ol_xthread != NULL)
-			cv_wait(&ol->ol_cv, &node->n_mutex);
+			cv_wait(&ol->ol_cv, &ol->ol_mutex);
 	}
 }
+
+/*
+ * smb_oplock_create_grant
+ */
+static smb_oplock_grant_t *
+smb_oplock_create_grant(smb_ofile_t *of, uint8_t level)
+{
+	smb_oplock_grant_t	*og;
+
+	og = kmem_cache_alloc(smb_oplock_grant_cache, KM_SLEEP);
+	og->og_magic = SMB_OPLOCK_GRANT_MAGIC;
+	og->og_level = level;
+	og->og_ofile = of;
+	og->og_fid = of->f_fid;
+	og->og_tid = of->f_tree->t_tid;
+	og->og_uid = of->f_user->u_uid;
+	og->og_session = of->f_session;
+	return (og);
+}
+
+/*
+ * smb_oplock_delete_grant
+ */
+void
+smb_oplock_delete_grant(smb_oplock_grant_t *og)
+{
+	kmem_cache_free(smb_oplock_grant_cache, og);
+}
+
+/*
+ * smb_oplock_insert_grant
+ *
+ * If there are no grants in the oplock's list install the fem
+ * monitor.
+ * Insert the grant into the list and increment the grant count.
+ */
+static int
+smb_oplock_insert_grant(smb_node_t *node, smb_oplock_grant_t *og)
+{
+	smb_oplock_t *ol = &node->n_oplock;
+
+	ASSERT(MUTEX_HELD(&ol->ol_mutex));
+
+	if (ol->ol_count == 0) {
+		if (smb_oplock_install_fem(node) != 0)
+			return (-1);
+	}
+
+	list_insert_tail(&ol->ol_grants, og);
+	++ol->ol_count;
+	return (0);
+}
+
+/*
+ * smb_oplock_remove_grant
+ *
+ * Remove the oplock grant from the list, decrement the grant count
+ * and, if there are no other grants in the list, uninstall the fem
+ * monitor.
+ */
+static void
+smb_oplock_remove_grant(smb_node_t *node, smb_oplock_grant_t *og)
+{
+	smb_oplock_t *ol = &node->n_oplock;
+
+	ASSERT(MUTEX_HELD(&ol->ol_mutex));
+	ASSERT(ol->ol_count > 0);
+
+	list_remove(&ol->ol_grants, og);
+	if (--ol->ol_count == 0)
+		smb_oplock_uninstall_fem(node);
+}
+
+/*
+ * smb_oplock_exclusive_grant
+ *
+ * If an exclusive (EXCLUSIVE or BATCH) oplock grant exists,
+ * return it. Otherwise return NULL.
+ */
+static smb_oplock_grant_t *
+smb_oplock_exclusive_grant(list_t *grants)
+{
+	smb_oplock_grant_t	*og;
+
+	og = list_head(grants);
+	if (og) {
+		SMB_OPLOCK_GRANT_VALID(og);
+		if (SMB_OPLOCK_IS_EXCLUSIVE(og->og_level))
+			return (og);
+	}
+	return (NULL);
+}
+
+/*
+ * smb_oplock_find_grant
+ *
+ * Find oplock grant corresponding to the specified ofile.
+ */
+static smb_oplock_grant_t *
+smb_oplock_find_grant(list_t *grants, smb_ofile_t *ofile)
+{
+	smb_oplock_grant_t	*og = NULL;
+
+	for (og = list_head(grants);
+	    og != NULL;
+	    og = list_next(grants, og)) {
+		SMB_OPLOCK_GRANT_VALID(og);
+		if (og->og_ofile == ofile)
+			break;
+	}
+	return (og);
+}
+
+/*
+ * smb_oplock_create_break
+ */
+static smb_oplock_break_t *
+smb_oplock_create_break(smb_node_t *node)
+{
+	smb_oplock_break_t	*ob;
+
+	ob = kmem_cache_alloc(smb_oplock_break_cache, KM_SLEEP);
+
+	smb_node_ref(node);
+	ob->ob_magic = SMB_OPLOCK_BREAK_MAGIC;
+	ob->ob_node = node;
+
+	return (ob);
+}
+
+/*
+ * smb_oplock_delete_break
+ */
+static void
+smb_oplock_delete_break(smb_oplock_break_t *ob)
+{
+	smb_node_release(ob->ob_node);
+	kmem_cache_free(smb_oplock_break_cache, ob);
+}
--- a/usr/src/uts/common/fs/smbsrv/smb_pathname.c	Thu Jul 22 12:31:36 2010 -0700
+++ b/usr/src/uts/common/fs/smbsrv/smb_pathname.c	Thu Jul 22 14:53:56 2010 -0700
@@ -402,7 +402,8 @@
 		    &vp, rootvp, dnode->vp, &attr, cred);
 
 		if (err) {
-			if (!smb_maybe_mangled(component))
+			if (!SMB_TREE_SUPPORTS_SHORTNAMES(sr) ||
+			    !smb_maybe_mangled(component))
 				break;
 
 			if ((err = smb_unmangle(dnode, component,
--- a/usr/src/uts/common/fs/smbsrv/smb_print.c	Thu Jul 22 12:31:36 2010 -0700
+++ b/usr/src/uts/common/fs/smbsrv/smb_print.c	Thu Jul 22 14:53:56 2010 -0700
@@ -27,10 +27,15 @@
  */
 
 #include <smbsrv/smb_kproto.h>
+#include <sys/unistd.h>
+#include <sys/stat.h>
+#include <sys/types.h>
+#include <sys/fcntl.h>
+#include <smbsrv/smb_share.h>
 
 /*
- * Create a new printer file, which should be deleted automatically once
- * it has been closed and printed.
+ * Starts the creation of a new printer file, which will be deleted
+ * automatically once it has been closed and printed.
  *
  * SetupLength is the number of bytes in the first part of the resulting
  * print spool file which contains printer-specific control strings.
@@ -49,7 +54,6 @@
 smb_sdrc_t
 smb_pre_open_print_file(smb_request_t *sr)
 {
-	static uint32_t		tmp_id = 10000;
 	struct open_param	*op = &sr->arg.open;
 	char			*path;
 	char			*identifier;
@@ -57,9 +61,9 @@
 	uint16_t		setup;
 	uint16_t		mode;
 	int			rc;
+	static uint32_t		tmp_id = 10000;
 
 	bzero(op, sizeof (sr->arg.open));
-
 	rc = smbsr_decode_vwv(sr, "ww", &setup, &mode);
 	if (rc == 0)
 		rc = smbsr_decode_data(sr, "%S", sr, &identifier);
@@ -73,7 +77,6 @@
 
 	op->create_disposition = FILE_OVERWRITE_IF;
 	op->create_options = FILE_NON_DIRECTORY_FILE;
-
 	DTRACE_SMB_2(op__OpenPrintFile__start, smb_request_t *, sr,
 	    struct open_param *, op);
 
@@ -86,21 +89,53 @@
 	DTRACE_SMB_1(op__OpenPrintFile__done, smb_request_t *, sr);
 }
 
+/*
+ * Creates a new spool file which will be later copied and
+ * deleted by cupsd.  After the file is created, information
+ * related to the file will be placed in a spooldoc list
+ * to be later used by cupsd
+ *
+ * Return values
+ * 	rc 0 SDRC_SUCCESS
+ *	rc non-zero SDRC_ERROR
+ */
+
 smb_sdrc_t
 smb_com_open_print_file(smb_request_t *sr)
 {
-	int rc;
+	int 		rc;
+	smb_kspooldoc_t *sp;
+	smb_kshare_t 	*si;
+	struct open_param *op = &sr->arg.open;
 
 	if (!STYPE_ISPRN(sr->tid_tree->t_res_type)) {
+		cmn_err(CE_WARN, "smb_com_open_print_file: bad device");
 		smbsr_error(sr, NT_STATUS_BAD_DEVICE_TYPE,
 		    ERRDOS, ERROR_BAD_DEV_TYPE);
 		return (SDRC_ERROR);
 	}
-
-	if (smb_common_create(sr) != NT_STATUS_SUCCESS)
+	if ((rc = smb_common_create(sr)) != NT_STATUS_SUCCESS) {
+		cmn_err(CE_WARN, "smb_com_open_print_file: error rc=%d", rc);
 		return (SDRC_ERROR);
-
-	rc = smbsr_encode_result(sr, 1, 0, "bww", 1, sr->smb_fid, 0);
+	}
+	if ((rc = smbsr_encode_result(sr, 1, 0,
+	    "bww", 1, sr->smb_fid, 0)) == 0) {
+		if ((si = smb_kshare_lookup(SMB_SHARE_PRINT)) == NULL) {
+			cmn_err(CE_NOTE, "smb_com_open_print_file: SDRC_ERROR");
+			return (SDRC_ERROR);
+		}
+		sp = kmem_zalloc(sizeof (smb_kspooldoc_t), KM_SLEEP);
+		(void) snprintf(sp->sd_path, MAXPATHLEN, "%s/%s", si->shr_path,
+		    op->fqi.fq_path.pn_path);
+		sp->sd_spool_num = sr->sr_server->sp_info.sp_cnt;
+		sp->sd_ipaddr = sr->session->ipaddr;
+		(void) strlcpy(sp->sd_username, sr->uid_user->u_name,
+		    MAXNAMELEN);
+		sp->sd_fid = sr->smb_fid;
+		if (smb_spool_add_doc(sp))
+			kmem_free(sp, sizeof (smb_kspooldoc_t));
+		smb_kshare_release(si);
+	}
 	return ((rc == 0) ? SDRC_SUCCESS : SDRC_ERROR);
 }
 
@@ -130,16 +165,34 @@
 	DTRACE_SMB_1(op__ClosePrintFile__done, smb_request_t *, sr);
 }
 
+/*
+ *
+ * Adds the print file fid to a list to be used as a search
+ * key in the spooldoc list.  It then wakes up the smbd
+ * spool monitor thread to copy the spool file.
+ *
+ * Return values
+ * rc - 0 success
+ *
+ */
+
 smb_sdrc_t
 smb_com_close_print_file(smb_request_t *sr)
 {
+	smb_sdrc_t rc;
+
 	if (!STYPE_ISPRN(sr->tid_tree->t_res_type)) {
 		smbsr_error(sr, NT_STATUS_BAD_DEVICE_TYPE,
 		    ERRDOS, ERROR_BAD_DEV_TYPE);
+		cmn_err(CE_WARN, "smb_com_close_print_file: SDRC_ERROR");
 		return (SDRC_ERROR);
 	}
+	rc = smb_com_close(sr);
 
-	return (smb_com_close(sr));
+	(void) smb_spool_add_fid(sr->smb_fid);
+	cv_broadcast(&sr->sr_server->sp_info.sp_cv);
+
+	return (rc);
 }
 
 /*
--- a/usr/src/uts/common/fs/smbsrv/smb_query_fileinfo.c	Thu Jul 22 12:31:36 2010 -0700
+++ b/usr/src/uts/common/fs/smbsrv/smb_query_fileinfo.c	Thu Jul 22 14:53:56 2010 -0700
@@ -50,7 +50,7 @@
  * SMB_FILE_STANDARD_INFORMATION
  * SMB_FILE_INTERNAL_INFORMATION
  * SMB_FILE_EA_INFORMATION
- * SMB_FILE_ACCESS_INFORMATION - not yet supported quen query by path
+ * SMB_FILE_ACCESS_INFORMATION - not yet supported when query by path
  * SMB_FILE_NAME_INFORMATION
  * SMB_FILE_ALL_INFORMATION
  * SMB_FILE_ALT_NAME_INFORMATION - not valid for pipes
@@ -64,6 +64,12 @@
  * SMB_QUERY_INFORMATION2
  */
 
+/*
+ * SMB_STREAM_ENCODE_FIXED_SIZE:
+ * 2 dwords + 2 quadwords => 4 + 4 + 8 + 8 => 24
+ */
+#define	SMB_STREAM_ENCODE_FIXED_SZ	24
+
 typedef struct smb_queryinfo {
 	smb_node_t	*qi_node;	/* NULL for pipes */
 	smb_attr_t	qi_attr;
@@ -90,6 +96,7 @@
     uint16_t, smb_queryinfo_t *);
 static void smb_encode_stream_info(smb_request_t *, smb_xa_t *,
     smb_queryinfo_t *);
+static boolean_t smb_stream_fits(smb_request_t *, smb_xa_t *, char *, uint32_t);
 static int smb_query_pathname(smb_request_t *, smb_node_t *, boolean_t,
     smb_queryinfo_t *);
 static void smb_query_shortname(smb_node_t *, smb_queryinfo_t *);
@@ -598,8 +605,10 @@
  * entries. The entries that have been read so far are returned and
  * no error is reported.
  *
- * Offset calculation:
- * 2 dwords + 2 quadwords => 4 + 4 + 8 + 8 => 24
+ * If the response buffer is not large enough to return all of the
+ * named stream entries, the entries that do fit are returned and
+ * a warning code is set (NT_STATUS_BUFFER_OVERFLOW). The next_offset
+ * value in the last returned entry must be 0.
  */
 static void
 smb_encode_stream_info(smb_request_t *sr, smb_xa_t *xa, smb_queryinfo_t *qinfo)
@@ -647,20 +656,36 @@
 	if (!is_dir) {
 		stream_name = "::$DATA";
 		stream_nlen = smb_ascii_or_unicode_strlen(sr, stream_name);
+		next_offset = SMB_STREAM_ENCODE_FIXED_SZ + stream_nlen +
+		    smb_ascii_or_unicode_null_len(sr);
 
-		if (done)
-			next_offset = 0;
-		else
-			next_offset = 24 + stream_nlen +
-			    smb_ascii_or_unicode_null_len(sr);
+		/* Can unnamed stream fit in response buffer? */
+		if (MBC_ROOM_FOR(&xa->rep_data_mb, next_offset) == 0) {
+			done = B_TRUE;
+			smbsr_warn(sr, NT_STATUS_BUFFER_OVERFLOW,
+			    ERRDOS, ERROR_MORE_DATA);
+		} else {
+			/* Can first named stream fit in rsp buffer? */
+			if (!done && !smb_stream_fits(sr, xa, sinfo->si_name,
+			    next_offset)) {
+				done = B_TRUE;
+				smbsr_warn(sr, NT_STATUS_BUFFER_OVERFLOW,
+				    ERRDOS, ERROR_MORE_DATA);
+			}
 
-		(void) smb_mbc_encodef(&xa->rep_data_mb, "%llqqu", sr,
-		    next_offset, stream_nlen, datasz, allocsz, stream_name);
+			if (done)
+				next_offset = 0;
+
+			(void) smb_mbc_encodef(&xa->rep_data_mb, "%llqqu", sr,
+			    next_offset, stream_nlen, datasz, allocsz,
+			    stream_name);
+		}
 	}
 
 	/*
-	 * Since last packet does not have a pad we need to check
-	 * for the next stream before we encode the current one
+	 * If there is no next entry, or there is not enough space in
+	 * the response buffer for the next entry, the next_offset and
+	 * padding are 0.
 	 */
 	while (!done) {
 		stream_nlen = smb_ascii_or_unicode_strlen(sr, sinfo->si_name);
@@ -669,15 +694,28 @@
 		rc = smb_odir_read_streaminfo(sr, od, sinfo_next, &eos);
 		if ((rc != 0) || (eos)) {
 			done = B_TRUE;
-			next_offset = 0;
-			pad = 0;
 		} else {
-			next_offset = 24 + stream_nlen +
+			next_offset = SMB_STREAM_ENCODE_FIXED_SZ +
+			    stream_nlen +
 			    smb_ascii_or_unicode_null_len(sr);
 			pad = smb_pad_align(next_offset, 8);
 			next_offset += pad;
+
+			/* Can next named stream fit in response buffer? */
+			if (!smb_stream_fits(sr, xa, sinfo_next->si_name,
+			    next_offset)) {
+				done = B_TRUE;
+				smbsr_warn(sr, NT_STATUS_BUFFER_OVERFLOW,
+				    ERRDOS, ERROR_MORE_DATA);
+			}
 		}
-		(void) smb_mbc_encodef(&xa->rep_data_mb, "%llqqu#.",
+
+		if (done) {
+			next_offset = 0;
+			pad = 0;
+		}
+
+		rc = smb_mbc_encodef(&xa->rep_data_mb, "%llqqu#.",
 		    sr, next_offset, stream_nlen,
 		    sinfo->si_size, sinfo->si_alloc_size,
 		    sinfo->si_name, pad);
@@ -694,6 +732,32 @@
 }
 
 /*
+ * smb_stream_fits
+ *
+ * Check if the named stream entry can fit in the response buffer.
+ *
+ * Required space =
+ *	offset (size of current entry)
+ *	+ SMB_STREAM_ENCODE_FIXED_SIZE
+ *      + length of encoded stream name
+ *	+ length of null terminator
+ *	+ alignment padding
+ */
+static boolean_t
+smb_stream_fits(smb_request_t *sr, smb_xa_t *xa, char *name, uint32_t offset)
+{
+	uint32_t len, pad;
+
+	len = SMB_STREAM_ENCODE_FIXED_SZ +
+	    smb_ascii_or_unicode_strlen(sr, name) +
+	    smb_ascii_or_unicode_null_len(sr);
+	pad = smb_pad_align(len, 8);
+	len += pad;
+
+	return (MBC_ROOM_FOR(&xa->rep_data_mb, offset + len) != 0);
+}
+
+/*
  * smb_query_fileinfo
  *
  * Populate smb_queryinfo_t structure for SMB_FTYPE_DISK
@@ -705,6 +769,16 @@
 {
 	int rc = 0;
 
+	/* If shortname required but not supported -> OBJECT_NAME_NOT_FOUND */
+	if ((infolev == SMB_QUERY_FILE_ALT_NAME_INFO) ||
+	    (infolev == SMB_FILE_ALT_NAME_INFORMATION)) {
+		if (!smb_tree_has_feature(sr->tid_tree, SMB_TREE_SHORTNAMES)) {
+			smbsr_error(sr, NT_STATUS_OBJECT_NAME_NOT_FOUND,
+			    ERRDOS, ERROR_FILE_NOT_FOUND);
+			return (-1);
+		}
+	}
+
 	(void) bzero(qinfo, sizeof (smb_queryinfo_t));
 
 	if (smb_node_getattr(sr, node, &qinfo->qi_attr) != 0) {
@@ -830,8 +904,7 @@
 		smb_mangle(namep, qinfo->qi_attr.sa_vattr.va_nodeid,
 		    qinfo->qi_shortname, SMB_SHORTNAMELEN);
 	} else {
-		(void) strlcpy(qinfo->qi_shortname, namep,
-		    SMB_SHORTNAMELEN);
+		(void) strlcpy(qinfo->qi_shortname, namep, SMB_SHORTNAMELEN);
 		(void) smb_strupr(qinfo->qi_shortname);
 	}
 }
--- a/usr/src/uts/common/fs/smbsrv/smb_read.c	Thu Jul 22 12:31:36 2010 -0700
+++ b/usr/src/uts/common/fs/smbsrv/smb_read.c	Thu Jul 22 14:53:56 2010 -0700
@@ -19,13 +19,18 @@
  * CDDL HEADER END
  */
 /*
- * Copyright 2010 Sun Microsystems, Inc.  All rights reserved.
- * Use is subject to license terms.
+ * Copyright (c) 2007, 2010, Oracle and/or its affiliates. All rights reserved.
  */
 
 #include <smbsrv/smb_kproto.h>
 #include <smbsrv/smb_fsops.h>
 
+/*
+ * There may be oplock break requests waiting to be sent after
+ * a read raw request completes.
+ */
+#define	SMB_OPLOCK_BREAKS_PENDING(sr) \
+	!list_is_empty(&(sr)->session->s_oplock_brkreqs)
 
 /*
  * The maximum number of bytes to return from SMB Core
@@ -283,7 +288,12 @@
 	mbuf_chain_t	*mbc;
 
 	if (sr->session->s_state == SMB_SESSION_STATE_READ_RAW_ACTIVE) {
-		sr->session->s_state = SMB_SESSION_STATE_NEGOTIATED;
+		if (SMB_OPLOCK_BREAKS_PENDING(sr)) {
+			sr->session->s_state =
+			    SMB_SESSION_STATE_OPLOCK_BREAKING;
+		} else {
+			sr->session->s_state = SMB_SESSION_STATE_NEGOTIATED;
+		}
 
 		while ((mbc = list_head(&sr->session->s_oplock_brkreqs)) !=
 		    NULL) {
@@ -306,6 +316,9 @@
 {
 	smb_rw_param_t *param = sr->arg.rw;
 
+	if (!smb_raw_mode)
+		return (SDRC_DROP_VC);
+
 	switch (sr->session->s_state) {
 	case SMB_SESSION_STATE_NEGOTIATED:
 		sr->session->s_state = SMB_SESSION_STATE_READ_RAW_ACTIVE;
@@ -341,7 +354,8 @@
 	if (param->rw_mincnt > param->rw_count)
 		param->rw_mincnt = 0;
 
-	if (smb_common_read(sr, param) != 0) {
+	if ((smb_common_read(sr, param) != 0) ||
+	    (SMB_OPLOCK_BREAKS_PENDING(sr))) {
 		(void) smb_session_send(sr->session, 0, NULL);
 		m_freem(sr->raw_data.chain);
 		sr->raw_data.chain = NULL;
@@ -492,6 +506,12 @@
  * function.  We can't move the fid lookup here because lock-and-read
  * requires the fid to do locking before attempting the read.
  *
+ * Reading from a file should break oplocks on the file to LEVEL_II.
+ * A call to smb_oplock_break(SMB_OPLOCK_BREAK_TO_LEVEL_II) is not
+ * required as it is a no-op. If there's anything greater than a
+ * LEVEL_II oplock on the file, the oplock MUST be owned by the ofile
+ * on which the read is occuring and therefore would not be broken.
+ *
  * Returns errno values.
  */
 int
--- a/usr/src/uts/common/fs/smbsrv/smb_rename.c	Thu Jul 22 12:31:36 2010 -0700
+++ b/usr/src/uts/common/fs/smbsrv/smb_rename.c	Thu Jul 22 14:53:56 2010 -0700
@@ -19,8 +19,7 @@
  * CDDL HEADER END
  */
 /*
- * Copyright 2010 Sun Microsystems, Inc.  All rights reserved.
- * Use is subject to license terms.
+ * Copyright (c) 2007, 2010, Oracle and/or its affiliates. All rights reserved.
  */
 
 #include <sys/synch.h>
@@ -446,7 +445,8 @@
 			return (EEXIST);
 		}
 
-		(void) smb_oplock_break(dst_fnode, sr->session, B_FALSE);
+		(void) smb_oplock_break(sr, dst_fnode,
+		    SMB_OPLOCK_BREAK_TO_NONE | SMB_OPLOCK_BREAK_BATCH);
 
 		for (count = 0; count <= 3; count++) {
 			if (count) {
@@ -628,7 +628,7 @@
  * smb_rename_lookup_src
  *
  * Lookup the src node, checking for sharing violations and
- * breaking any existing oplock.
+ * breaking any existing BATCH oplock.
  * Populate sr->arg.dirop.fqi
  *
  * Upon success, the dnode and fnode will have holds and the
@@ -685,11 +685,12 @@
 	}
 
 	/*
-	 * Break the oplock before access checks. If a client
+	 * Break BATCH oplock before access checks. If a client
 	 * has a file open, this will force a flush or close,
 	 * which may affect the outcome of any share checking.
 	 */
-	(void) smb_oplock_break(src_node, sr->session, B_FALSE);
+	(void) smb_oplock_break(sr, src_node,
+	    SMB_OPLOCK_BREAK_TO_LEVEL_II | SMB_OPLOCK_BREAK_BATCH);
 
 	for (count = 0; count <= 3; count++) {
 		if (count) {
--- a/usr/src/uts/common/fs/smbsrv/smb_server.c	Thu Jul 22 12:31:36 2010 -0700
+++ b/usr/src/uts/common/fs/smbsrv/smb_server.c	Thu Jul 22 14:53:56 2010 -0700
@@ -229,8 +229,6 @@
 #include <smbsrv/smb_door.h>
 #include <smbsrv/smb_kstat.h>
 
-#define	SMB_EVENT_TIMEOUT		45	/* seconds */
-
 extern void smb_reply_notify_change_request(smb_request_t *);
 
 static void smb_server_kstat_init(smb_server_t *);
@@ -248,7 +246,6 @@
 static void smb_server_fsop_stop(smb_server_t *);
 static void smb_server_signal_listeners(smb_server_t *);
 static void smb_event_cancel(smb_server_t *, uint32_t);
-static void smb_event_notify(smb_server_t *, uint32_t);
 static uint32_t smb_event_alloc_txid(void);
 
 static void smb_server_disconnect_share(smb_session_list_t *, const char *);
@@ -257,6 +254,7 @@
     const char *);
 static int smb_server_fclose(smb_session_list_t *, uint32_t);
 static int smb_server_kstat_update(kstat_t *, int);
+static int smb_server_legacy_kstat_update(kstat_t *, int);
 
 int smb_event_debug = 0;
 
@@ -288,6 +286,8 @@
 			continue;
 		if (rc = smb_node_init())
 			continue;
+		if (rc = smb_oplock_init())
+			continue;
 		if (rc = smb_fem_init())
 			continue;
 		if (rc = smb_notify_init())
@@ -327,6 +327,7 @@
 		smb_notify_fini();
 		smb_fem_fini();
 		smb_node_fini();
+		smb_oplock_fini();
 		smb_vop_fini();
 		smb_mbc_fini();
 		smb_llist_destructor(&smb_servers);
@@ -372,6 +373,12 @@
 	smb_llist_constructor(&sv->sv_event_list, sizeof (smb_event_t),
 	    offsetof(smb_event_t, se_lnd));
 
+	smb_llist_constructor(&sv->sp_info.sp_list, sizeof (smb_kspooldoc_t),
+	    offsetof(smb_kspooldoc_t, sd_lnd));
+
+	smb_llist_constructor(&sv->sp_info.sp_fidlist,
+	    sizeof (smb_spoolfid_t), offsetof(smb_spoolfid_t, sf_lnd));
+
 	smb_session_list_constructor(&sv->sv_nbt_daemon.ld_session_list);
 	smb_session_list_constructor(&sv->sv_tcp_daemon.ld_session_list);
 
@@ -404,13 +411,24 @@
 	smb_server_kstat_init(sv);
 
 	mutex_init(&sv->sv_mutex, NULL, MUTEX_DEFAULT, NULL);
+	mutex_init(&sv->sp_info.sp_mutex, NULL, MUTEX_DEFAULT, NULL);
 	cv_init(&sv->sv_cv, NULL, CV_DEFAULT, NULL);
+	cv_init(&sv->sp_info.sp_cv, NULL, CV_DEFAULT, NULL);
+
 	sv->sv_state = SMB_SERVER_STATE_CREATED;
 	sv->sv_magic = SMB_SERVER_MAGIC;
 	sv->sv_zid = zid;
 
 	smb_llist_insert_tail(&smb_servers, sv);
 	smb_llist_exit(&smb_servers);
+
+	smb_threshold_init(&sv->sv_ssetup_ct, SMB_SSETUP_CMD,
+	    smb_ssetup_threshold, smb_ssetup_timeout);
+	smb_threshold_init(&sv->sv_tcon_ct, SMB_TCON_CMD, smb_tcon_threshold,
+	    smb_tcon_timeout);
+	smb_threshold_init(&sv->sv_opipe_ct, SMB_OPIPE_CMD, smb_opipe_threshold,
+	    smb_opipe_timeout);
+
 	return (0);
 }
 
@@ -432,6 +450,10 @@
 	if (rc != 0)
 		return (rc);
 
+	smb_threshold_fini(&sv->sv_ssetup_ct);
+	smb_threshold_fini(&sv->sv_tcon_ct);
+	smb_threshold_fini(&sv->sv_opipe_ct);
+
 	mutex_enter(&sv->sv_mutex);
 	switch (sv->sv_state) {
 	case SMB_SERVER_STATE_RUNNING:
@@ -440,6 +462,7 @@
 		smb_server_signal_listeners(sv);
 		nbt_tid = smb_server_listener_tid(&sv->sv_nbt_daemon);
 		tcp_tid = smb_server_listener_tid(&sv->sv_tcp_daemon);
+		cv_broadcast(&sv->sp_info.sp_cv);
 
 		sv->sv_state = SMB_SERVER_STATE_DELETING;
 		mutex_exit(&sv->sv_mutex);
@@ -630,6 +653,7 @@
 	case SMB_SERVER_STATE_RUNNING:
 		sv->sv_state = SMB_SERVER_STATE_STOPPING;
 		smb_server_signal_listeners(sv);
+		cv_broadcast(&sv->sp_info.sp_cv);
 		break;
 	default:
 		SMB_SERVER_STATE_VALID(sv->sv_state);
@@ -839,6 +863,54 @@
 	return (rc);
 }
 
+/*
+ * smb_server_spooldoc
+ *
+ * Waits for print file close broadcast.
+ * Gets the head of the fid list,
+ * then searches the spooldoc list and returns
+ * this info via the ioctl to user land.
+ *
+ * rc - 0 success
+ */
+
+int
+smb_server_spooldoc(smb_ioc_spooldoc_t *ioc)
+{
+	smb_server_t	*sv;
+	int		rc;
+	smb_kspooldoc_t *spdoc;
+	uint16_t	fid;
+
+	if ((rc = smb_server_lookup(&sv)) == 0) {
+		if (sv->sv_state != SMB_SERVER_STATE_RUNNING) {
+			smb_server_release(sv);
+			return (ECANCELED);
+		}
+		mutex_enter(&sv->sp_info.sp_mutex);
+		spdoc = kmem_zalloc(sizeof (smb_kspooldoc_t), KM_SLEEP);
+		cv_wait(&sv->sp_info.sp_cv, &sv->sp_info.sp_mutex);
+		if (sv->sv_state != SMB_SERVER_STATE_RUNNING)
+			rc = ECANCELED;
+		else {
+			fid = smb_spool_get_fid();
+			atomic_inc_32(&sv->sp_info.sp_cnt);
+			if (smb_spool_lookup_doc_byfid(fid, spdoc)) {
+				ioc->spool_num = spdoc->sd_spool_num;
+				ioc->ipaddr = spdoc->sd_ipaddr;
+				(void) strlcpy(ioc->path, spdoc->sd_path,
+				    MAXPATHLEN);
+				(void) strlcpy(ioc->username,
+				    spdoc->sd_username, MAXNAMELEN);
+			}
+		}
+		kmem_free(spdoc, sizeof (smb_kspooldoc_t));
+		mutex_exit(&sv->sp_info.sp_mutex);
+		smb_server_release(sv);
+	}
+	return (rc);
+}
+
 int
 smb_server_set_gmtoff(smb_ioc_gmt_t *ioc)
 {
@@ -1303,6 +1375,8 @@
 static void
 smb_server_kstat_init(smb_server_t *sv)
 {
+	char	name[KSTAT_STRLEN];
+
 	sv->sv_ksp = kstat_create_zone(SMBSRV_KSTAT_MODULE, sv->sv_zid,
 	    SMBSRV_KSTAT_STATISTICS, SMBSRV_KSTAT_CLASS, KSTAT_TYPE_RAW,
 	    sizeof (smbsrv_kstats_t), 0, sv->sv_zid);
@@ -1318,6 +1392,36 @@
 	} else {
 		cmn_err(CE_WARN, "SMB Server: Statistics unavailable");
 	}
+
+	(void) snprintf(name, sizeof (name), "%s%d",
+	    SMBSRV_KSTAT_NAME, sv->sv_zid);
+
+	sv->sv_legacy_ksp = kstat_create(SMBSRV_KSTAT_MODULE, sv->sv_zid,
+	    name, SMBSRV_KSTAT_CLASS, KSTAT_TYPE_NAMED,
+	    sizeof (smb_server_legacy_kstat_t) / sizeof (kstat_named_t), 0);
+
+	if (sv->sv_legacy_ksp != NULL) {
+		smb_server_legacy_kstat_t *ksd;
+
+		ksd = sv->sv_legacy_ksp->ks_data;
+
+		(void) strlcpy(ksd->ls_files.name, "open_files",
+		    sizeof (ksd->ls_files.name));
+		ksd->ls_files.data_type = KSTAT_DATA_UINT32;
+
+		(void) strlcpy(ksd->ls_trees.name, "connections",
+		    sizeof (ksd->ls_trees.name));
+		ksd->ls_trees.data_type = KSTAT_DATA_UINT32;
+
+		(void) strlcpy(ksd->ls_users.name, "connections",
+		    sizeof (ksd->ls_users.name));
+		ksd->ls_users.data_type = KSTAT_DATA_UINT32;
+
+		mutex_init(&sv->sv_legacy_ksmtx, NULL, MUTEX_DEFAULT, NULL);
+		sv->sv_legacy_ksp->ks_lock = &sv->sv_legacy_ksmtx;
+		sv->sv_legacy_ksp->ks_update = smb_server_legacy_kstat_update;
+		kstat_install(sv->sv_legacy_ksp);
+	}
 }
 
 /*
@@ -1326,6 +1430,12 @@
 static void
 smb_server_kstat_fini(smb_server_t *sv)
 {
+	if (sv->sv_legacy_ksp != NULL) {
+		kstat_delete(sv->sv_legacy_ksp);
+		mutex_destroy(&sv->sv_legacy_ksmtx);
+		sv->sv_legacy_ksp = NULL;
+	}
+
 	if (sv->sv_ksp != NULL) {
 		kstat_delete(sv->sv_ksp);
 		sv->sv_ksp = NULL;
@@ -1379,6 +1489,38 @@
 	return (EIO);
 }
 
+static int
+smb_server_legacy_kstat_update(kstat_t *ksp, int rw)
+{
+	smb_server_t			*sv;
+	smb_server_legacy_kstat_t	*ksd;
+	int				rc;
+
+	switch (rw) {
+	case KSTAT_WRITE:
+		rc = EACCES;
+		break;
+	case KSTAT_READ:
+		if (!smb_server_lookup(&sv)) {
+			ASSERT(MUTEX_HELD(ksp->ks_lock));
+			ASSERT(sv->sv_legacy_ksp == ksp);
+			ksd = (smb_server_legacy_kstat_t *)ksp->ks_data;
+			ksd->ls_files.value.ui32 = sv->sv_files + sv->sv_pipes;
+			ksd->ls_trees.value.ui32 = sv->sv_trees;
+			ksd->ls_users.value.ui32 = sv->sv_users;
+			smb_server_release(sv);
+			rc = 0;
+			break;
+		}
+		_NOTE(FALLTHRU)
+	default:
+		rc = EIO;
+		break;
+	}
+	return (rc);
+
+}
+
 /*
  * The mutex of the server must have been entered before calling this function.
  */
@@ -1547,7 +1689,7 @@
 static kt_did_t
 smb_server_listener_tid(smb_listener_daemon_t *ld)
 {
-	kt_did_t	tid;
+	kt_did_t	tid = 0;
 
 	if (ld->ld_ktdid != 0) {
 		tid = ld->ld_ktdid;
@@ -1769,6 +1911,7 @@
 	sv->sv_cfg.skc_sync_enable = ioc->sync_enable;
 	sv->sv_cfg.skc_secmode = ioc->secmode;
 	sv->sv_cfg.skc_ipv6_enable = ioc->ipv6_enable;
+	sv->sv_cfg.skc_print_enable = ioc->print_enable;
 	sv->sv_cfg.skc_execflags = ioc->exec_flags;
 	sv->sv_cfg.skc_version = ioc->version;
 	(void) strlcpy(sv->sv_cfg.skc_nbdomain, ioc->nbdomain,
@@ -1823,7 +1966,7 @@
 }
 
 smb_event_t *
-smb_event_create(void)
+smb_event_create(int timeout)
 {
 	smb_server_t	*sv;
 	smb_event_t	*event;
@@ -1844,6 +1987,7 @@
 	event->se_magic = SMB_EVENT_MAGIC;
 	event->se_txid = smb_event_alloc_txid();
 	event->se_server = sv;
+	event->se_timeout = timeout;
 
 	smb_llist_enter(&sv->sv_event_list, RW_WRITER);
 	smb_llist_insert_tail(&sv->sv_event_list, event);
@@ -1920,7 +2064,7 @@
 		if (event->se_errno != 0)
 			break;
 
-		if (event->se_waittime > SMB_EVENT_TIMEOUT) {
+		if (event->se_waittime > event->se_timeout) {
 			event->se_errno = ETIME;
 			break;
 		}
@@ -1978,7 +2122,7 @@
  * If txid is non-zero, notify the specified event.
  * Otherwise, notify all events.
  */
-static void
+void
 smb_event_notify(smb_server_t *sv, uint32_t txid)
 {
 	smb_event_t	*event;
@@ -2036,3 +2180,146 @@
 
 	return (txid_ret);
 }
+
+/*
+ * Called by the ioctl to find the corresponding
+ * spooldoc node.  removes node on success
+ *
+ * Return values
+ * rc
+ * B_FALSE - not found
+ * B_TRUE  - found
+ *
+ */
+
+boolean_t
+smb_spool_lookup_doc_byfid(uint16_t fid, smb_kspooldoc_t *spdoc)
+{
+	smb_kspooldoc_t *sp;
+	smb_llist_t	*splist;
+	smb_server_t	*sv;
+	int		rc;
+
+	rc = smb_server_lookup(&sv);
+	if (rc)
+		return (B_FALSE);
+
+	splist = &sv->sp_info.sp_list;
+	smb_llist_enter(splist, RW_WRITER);
+	sp = smb_llist_head(splist);
+	while (sp != NULL) {
+		/*
+		 * check for a matching fid
+		 */
+		if (sp->sd_fid == fid) {
+			*spdoc = *sp;
+			smb_llist_remove(splist, sp);
+			smb_llist_exit(splist);
+			kmem_free(sp, sizeof (smb_kspooldoc_t));
+			smb_server_release(sv);
+			return (B_TRUE);
+		}
+		sp = smb_llist_next(splist, sp);
+	}
+	cmn_err(CE_WARN, "smb_spool_lookup_user_byfid: no fid:%d", fid);
+	smb_llist_exit(splist);
+	smb_server_release(sv);
+	return (B_FALSE);
+}
+
+/*
+ * Adds the spool fid to a linked list to be used
+ * as a search key in the spooldoc queue
+ *
+ * Return values
+ *      rc non-zero error
+ *	rc zero success
+ *
+ */
+
+int
+smb_spool_add_fid(uint16_t fid)
+{
+	smb_llist_t	*fidlist;
+	smb_server_t	*sv;
+	smb_spoolfid_t  *sf;
+	int rc = 0;
+
+	rc = smb_server_lookup(&sv);
+	if (rc)
+		return (rc);
+
+	sf = kmem_zalloc(sizeof (smb_spoolfid_t), KM_SLEEP);
+	fidlist = &sv->sp_info.sp_fidlist;
+	smb_llist_enter(fidlist, RW_WRITER);
+	sf->sf_fid = fid;
+	smb_llist_insert_tail(fidlist, sf);
+	smb_llist_exit(fidlist);
+	smb_server_release(sv);
+	return (rc);
+}
+
+/*
+ * Called by the ioctl to get and remove the head of the fid list
+ *
+ * Return values
+ * int fd
+ * greater than 0 success
+ * 0 - error
+ *
+ */
+
+uint16_t
+smb_spool_get_fid()
+{
+	smb_spoolfid_t	*spfid;
+	smb_llist_t	*splist;
+	smb_server_t	*sv;
+	int 		rc = 0;
+	uint16_t	fid;
+
+	rc = smb_server_lookup(&sv);
+	if (rc)
+		return (0);
+
+	splist = &sv->sp_info.sp_fidlist;
+	smb_llist_enter(splist, RW_WRITER);
+	spfid = smb_llist_head(splist);
+	if (spfid != NULL) {
+		fid = spfid->sf_fid;
+		smb_llist_remove(&sv->sp_info.sp_fidlist, spfid);
+		kmem_free(spfid, sizeof (smb_spoolfid_t));
+	} else {
+		fid = 0;
+	}
+	smb_llist_exit(splist);
+	smb_server_release(sv);
+	return (fid);
+}
+
+/*
+ * Adds the spooldoc to the tail of the spooldoc list
+ *
+ * Return values
+ *      rc non-zero error
+ *	rc zero success
+ */
+int
+smb_spool_add_doc(smb_kspooldoc_t *sp)
+{
+	smb_llist_t	*splist;
+	smb_server_t	*sv;
+	int rc = 0;
+
+	rc = smb_server_lookup(&sv);
+	if (rc)
+		return (rc);
+
+	splist = &sv->sp_info.sp_list;
+	smb_llist_enter(splist, RW_WRITER);
+	sp->sd_spool_num = sv->sp_info.sp_cnt;
+	smb_llist_insert_tail(splist, sp);
+	smb_llist_exit(splist);
+	smb_server_release(sv);
+	return (rc);
+}
--- a/usr/src/uts/common/fs/smbsrv/smb_session.c	Thu Jul 22 12:31:36 2010 -0700
+++ b/usr/src/uts/common/fs/smbsrv/smb_session.c	Thu Jul 22 14:53:56 2010 -0700
@@ -1284,8 +1284,10 @@
 	ASSERT(sr->session);
 	ASSERT(sr->r_xa == NULL);
 
-	if (sr->fid_ofile != NULL)
+	if (sr->fid_ofile != NULL) {
+		smb_ofile_request_complete(sr->fid_ofile);
 		smb_ofile_release(sr->fid_ofile);
+	}
 
 	if (sr->tid_tree != NULL)
 		smb_tree_release(sr->tid_tree);
@@ -1334,17 +1336,22 @@
 		return (B_TRUE);
 }
 
+boolean_t
+smb_session_levelII_oplocks(smb_session_t *session)
+{
+	SMB_SESSION_VALID(session);
+	return (session->capabilities & CAP_LEVEL_II_OPLOCKS);
+}
+
 /*
- * smb_session_breaking_oplock
+ * smb_session_oplock_break
  *
- * This MUST be a cross-session call, i.e. the caller must be in a different
- * context than the one passed. The mutex of the SMB node requiring an oplock
- * break MUST be dropped before calling this function. This last requirement is
- * due to a potential deadlock that can occur when trying to enter the lock of
- * the session passed in.
+ * The session lock must NOT be held by the caller of this thread;
+ * as this would cause a deadlock.
  */
 void
-smb_session_oplock_break(smb_session_t *session, smb_ofile_t *of)
+smb_session_oplock_break(smb_session_t *session,
+    uint16_t tid, uint16_t fid, uint8_t brk)
 {
 	mbuf_chain_t	*mbc;
 
@@ -1352,17 +1359,19 @@
 
 	mbc = smb_mbc_alloc(MLEN);
 
-	(void) smb_mbc_encodef(mbc, "Mb19.wwwwbb3.ww10.",
+	(void) smb_mbc_encodef(mbc, "Mb19.wwwwbb3.wbb10.",
 	    SMB_COM_LOCKING_ANDX,
-	    SMB_TREE_GET_TID(SMB_OFILE_GET_TREE(of)),
+	    tid,
 	    0xFFFF, 0, 0xFFFF, 8, 0xFF,
-	    SMB_OFILE_GET_FID(of),
-	    LOCKING_ANDX_OPLOCK_RELEASE);
+	    fid,
+	    LOCKING_ANDX_OPLOCK_RELEASE,
+	    (brk == SMB_OPLOCK_BREAK_TO_LEVEL_II) ? 1 : 0);
 
 	smb_rwx_rwenter(&session->s_lock, RW_WRITER);
 	switch (session->s_state) {
 	case SMB_SESSION_STATE_NEGOTIATED:
 	case SMB_SESSION_STATE_OPLOCK_BREAKING:
+	case SMB_SESSION_STATE_WRITE_RAW_ACTIVE:
 		session->s_state = SMB_SESSION_STATE_OPLOCK_BREAKING;
 		(void) smb_session_send(session, 0, mbc);
 		smb_mbc_free(mbc);
--- a/usr/src/uts/common/fs/smbsrv/smb_session_setup_andx.c	Thu Jul 22 12:31:36 2010 -0700
+++ b/usr/src/uts/common/fs/smbsrv/smb_session_setup_andx.c	Thu Jul 22 14:53:56 2010 -0700
@@ -33,6 +33,8 @@
 
 static int smb_authenticate(smb_request_t *, smb_arg_sessionsetup_t *,
     smb_session_key_t **);
+static int smb_authenticate_core(smb_request_t *, smb_arg_sessionsetup_t *,
+    smb_session_key_t **);
 static cred_t *smb_cred_create(smb_token_t *);
 static void smb_cred_set_sid(smb_id_t *id, ksid_t *ksid);
 static ksidlist_t *smb_cred_set_sidlist(smb_ids_t *token_grps);
@@ -188,6 +190,9 @@
 		sinfo->ssi_capabilities |= CAP_LARGE_FILES |
 		    CAP_LARGE_READX | CAP_LARGE_WRITEX;
 
+	if (!smb_oplock_levelII)
+		sr->session->capabilities &= ~CAP_LEVEL_II_OPLOCKS;
+
 	sr->session->capabilities = sinfo->ssi_capabilities;
 
 	if (!(sr->session->signing.flags & SMB_SIGNING_ENABLED) &&
@@ -223,6 +228,23 @@
 	return ((rc == 0) ? SDRC_SUCCESS : SDRC_ERROR);
 }
 
+static int
+smb_authenticate(smb_request_t *sr, smb_arg_sessionsetup_t *sinfo,
+    smb_session_key_t **session_key)
+{
+	int		rc;
+	smb_server_t	*sv = sr->sr_server;
+
+	if (smb_threshold_enter(&sv->sv_ssetup_ct) != 0) {
+		smbsr_error(sr, RPC_NT_SERVER_TOO_BUSY, 0, 0);
+		return (-1);
+	}
+
+	rc = smb_authenticate_core(sr, sinfo, session_key);
+	smb_threshold_exit(&sv->sv_ssetup_ct, sv);
+	return (rc);
+}
+
 /*
  * Authenticate a user.  If the user has already been authenticated on
  * this session, we can simply dup the user and return.
@@ -232,7 +254,7 @@
  * generate a cred and new user based on the token.
  */
 static int
-smb_authenticate(smb_request_t *sr, smb_arg_sessionsetup_t *sinfo,
+smb_authenticate_core(smb_request_t *sr, smb_arg_sessionsetup_t *sinfo,
     smb_session_key_t **session_key)
 {
 	char		*hostname = sr->sr_cfg->skc_hostname;
--- a/usr/src/uts/common/fs/smbsrv/smb_set_fileinfo.c	Thu Jul 22 12:31:36 2010 -0700
+++ b/usr/src/uts/common/fs/smbsrv/smb_set_fileinfo.c	Thu Jul 22 14:53:56 2010 -0700
@@ -19,8 +19,7 @@
  * CDDL HEADER END
  */
 /*
- * Copyright 2010 Sun Microsystems, Inc.  All rights reserved.
- * Use is subject to license terms.
+ * Copyright (c) 2007, 2010, Oracle and/or its affiliates. All rights reserved.
  */
 
 /*
@@ -305,11 +304,6 @@
 		return (-1);
 	}
 
-	/* Break any conflicting oplock for subsequent attribute setting */
-	if (smb_oplock_conflict(node, sr->session, NULL)) {
-		(void) smb_oplock_break(node, sr->session, B_FALSE);
-	}
-
 	sinfo.si_xa = xa;
 	sinfo.si_infolev = infolev;
 	sinfo.si_node = node;
@@ -599,6 +593,11 @@
 		return (-1);
 	}
 
+	/* If opened by path, break exclusive oplock */
+	if (sr->fid_ofile == NULL)
+		(void) smb_oplock_break(sr, node,
+		    SMB_OPLOCK_BREAK_EXCLUSIVE | SMB_OPLOCK_BREAK_TO_NONE);
+
 	bzero(&attr, sizeof (smb_attr_t));
 	attr.sa_mask = SMB_AT_SIZE;
 	attr.sa_vattr.va_size = (u_offset_t)eof;
@@ -608,6 +607,7 @@
 		return (-1);
 	}
 
+	smb_oplock_break_levelII(node);
 	return (0);
 }
 
@@ -631,6 +631,11 @@
 		return (-1);
 	}
 
+	/* If opened by path, break exclusive oplock */
+	if (sr->fid_ofile == NULL)
+		(void) smb_oplock_break(sr, node,
+		    SMB_OPLOCK_BREAK_EXCLUSIVE | SMB_OPLOCK_BREAK_TO_NONE);
+
 	bzero(&attr, sizeof (smb_attr_t));
 	attr.sa_mask = SMB_AT_ALLOCSZ;
 	attr.sa_allocsz = (u_offset_t)allocsz;
@@ -640,6 +645,7 @@
 		return (-1);
 	}
 
+	smb_oplock_break_levelII(node);
 	return (0);
 }
 
@@ -711,10 +717,14 @@
 /*
  * smb_set_rename_info
  *
- * Explicity specified parameter validation rules:
+ * Explicitly specified parameter validation rules:
  * - If rootdir is not NULL respond with NT_STATUS_INVALID_PARAMETER.
  * - If the filename contains a separator character respond with
  *   NT_STATUS_INVALID_PARAMETER.
+ *
+ * Oplock break:
+ * Some Windows servers break BATCH oplocks prior to the rename.
+ * W2K3 does not. We behave as W2K3; we do not send an oplock break.
  */
 static int
 smb_set_rename_info(smb_request_t *sr, smb_setinfo_t *sinfo)
--- a/usr/src/uts/common/fs/smbsrv/smb_tree.c	Thu Jul 22 12:31:36 2010 -0700
+++ b/usr/src/uts/common/fs/smbsrv/smb_tree.c	Thu Jul 22 14:53:56 2010 -0700
@@ -166,9 +166,11 @@
 #include <smbsrv/smb_kproto.h>
 #include <smbsrv/smb_ktypes.h>
 #include <smbsrv/smb_fsops.h>
+#include <smbsrv/smb_share.h>
 
 int smb_tcon_mute = 0;
 
+static smb_tree_t *smb_tree_connect_core(smb_request_t *);
 static smb_tree_t *smb_tree_connect_disk(smb_request_t *, const char *);
 static smb_tree_t *smb_tree_connect_printq(smb_request_t *, const char *);
 static smb_tree_t *smb_tree_connect_ipc(smb_request_t *, const char *);
@@ -190,6 +192,22 @@
 static void smb_tree_netinfo_init(smb_tree_t *tree, smb_netconnectinfo_t *);
 static void smb_tree_netinfo_fini(smb_netconnectinfo_t *);
 
+smb_tree_t *
+smb_tree_connect(smb_request_t *sr)
+{
+	smb_tree_t	*tree;
+	smb_server_t	*sv = sr->sr_server;
+
+	if (smb_threshold_enter(&sv->sv_tcon_ct) != 0) {
+		smbsr_error(sr, RPC_NT_SERVER_TOO_BUSY, 0, 0);
+		return (NULL);
+	}
+
+	tree = smb_tree_connect_core(sr);
+	smb_threshold_exit(&sv->sv_tcon_ct, sv);
+	return (tree);
+}
+
 /*
  * Lookup the share name dispatch the appropriate stype handler.
  * Share names are case insensitive so we map the share name to
@@ -202,8 +220,8 @@
  *	COMM    Communications device
  *	?????   Any type of device (wildcard)
  */
-smb_tree_t *
-smb_tree_connect(smb_request_t *sr)
+static smb_tree_t *
+smb_tree_connect_core(smb_request_t *sr)
 {
 	char		*unc_path = sr->sr_tcon.path;
 	smb_tree_t	*tree = NULL;
@@ -223,6 +241,14 @@
 		smbsr_error(sr, 0, ERRSRV, ERRinvnetname);
 		return (NULL);
 	}
+
+	if (!strcasecmp(SMB_SHARE_PRINT, name)) {
+		smb_kshare_release(si);
+		smb_tree_log(sr, name, "access not permitted");
+		smbsr_error(sr, NT_STATUS_ACCESS_DENIED, ERRSRV, ERRaccess);
+		return (NULL);
+	}
+
 	sr->sr_tcon.si = si;
 
 	switch (si->shr_type & STYPE_MASK) {
@@ -681,6 +707,10 @@
 	if (si->shr_flags & SMB_SHRF_DFSROOT)
 		sr->sr_tcon.optional_support |= SMB_SHARE_IS_IN_DFS;
 
+	/* if 'smb' zfs property: shortnames=disabled */
+	if (!smb_shortnames)
+		sr->arg.tcon.optional_support |= SMB_UNIQUE_FILE_NAME;
+
 	tree = smb_tree_alloc(user, si, snode, access,
 	    sr->sr_cfg->skc_execflags);
 
@@ -835,6 +865,10 @@
 	tree = kmem_cache_alloc(user->u_server->si_cache_tree, KM_SLEEP);
 	bzero(tree, sizeof (smb_tree_t));
 
+	tree->t_user = user;
+	tree->t_session = user->u_session;
+	tree->t_server = user->u_server;
+
 	if (STYPE_ISDSK(stype) || STYPE_ISPRN(stype)) {
 		if (smb_tree_getattr(si, snode, tree) != 0) {
 			smb_idpool_free(&user->u_tid_pool, tid);
@@ -869,9 +903,6 @@
 
 	mutex_init(&tree->t_mutex, NULL, MUTEX_DEFAULT, NULL);
 
-	tree->t_user = user;
-	tree->t_session = user->u_session;
-	tree->t_server = user->u_server;
 	tree->t_refcnt = 1;
 	tree->t_tid = tid;
 	tree->t_res_type = stype;
@@ -1095,15 +1126,21 @@
 	if (si->shr_flags & SMB_SHRF_ABE)
 		flags |= SMB_TREE_ABE;
 
+	if (smb_session_oplocks_enable(tree->t_session)) {
+		/* if 'smb' zfs property: oplocks=enabled */
+		flags |= SMB_TREE_OPLOCKS;
+	}
+
+	/* if 'smb' zfs property: shortnames=enabled */
+	if (smb_shortnames)
+		flags |= SMB_TREE_SHORTNAMES;
+
 	if (vfsp->vfs_flag & VFS_RDONLY)
 		flags |= SMB_TREE_READONLY;
 
 	if (vfsp->vfs_flag & VFS_XATTR)
 		flags |= SMB_TREE_STREAMS;
 
-	if (vfs_optionisset(vfsp, MNTOPT_NOATIME, NULL))
-		flags |= SMB_TREE_NO_ATIME;
-
 	name = vfssw[vfsp->vfs_fstype].vsw_name;
 
 	for (i = 0; i < sizeof (smb_mtype) / sizeof (smb_mtype[0]); ++i) {
--- a/usr/src/uts/common/fs/smbsrv/smb_tree_connect.c	Thu Jul 22 12:31:36 2010 -0700
+++ b/usr/src/uts/common/fs/smbsrv/smb_tree_connect.c	Thu Jul 22 14:53:56 2010 -0700
@@ -23,7 +23,7 @@
  */
 
 #include <smbsrv/smb_kproto.h>
-
+#include <smbsrv/smb_share.h>
 
 /*
  * SmbTreeConnect: Map a share to a tree and obtain a tree-id (TID).
--- a/usr/src/uts/common/fs/smbsrv/smb_write.c	Thu Jul 22 12:31:36 2010 -0700
+++ b/usr/src/uts/common/fs/smbsrv/smb_write.c	Thu Jul 22 14:53:56 2010 -0700
@@ -490,6 +490,9 @@
 
 		smb_ofile_set_write_time_pending(ofile);
 
+		if (!smb_node_is_dir(node))
+			smb_oplock_break_levelII(node);
+
 		param->rw_count = lcount;
 		break;
 
--- a/usr/src/uts/common/fs/smbsrv/smb_write_raw.c	Thu Jul 22 12:31:36 2010 -0700
+++ b/usr/src/uts/common/fs/smbsrv/smb_write_raw.c	Thu Jul 22 14:53:56 2010 -0700
@@ -255,6 +255,12 @@
 	if (sr->session->s_state != SMB_SESSION_STATE_WRITE_RAW_ACTIVE)
 		return (SDRC_DROP_VC);
 
+	if (!smb_raw_mode) {
+		smbsr_error(sr, NT_STATUS_NOT_SUPPORTED, ERRDOS,
+		    ERROR_NOT_SUPPORTED);
+		return (SDRC_ERROR);
+	}
+
 	smbsr_lookup_file(sr);
 	if (sr->fid_ofile == NULL) {
 		smbsr_error(sr, NT_STATUS_INVALID_HANDLE, ERRDOS, ERRbadfid);
--- a/usr/src/uts/common/smbsrv/Makefile	Thu Jul 22 12:31:36 2010 -0700
+++ b/usr/src/uts/common/smbsrv/Makefile	Thu Jul 22 14:53:56 2010 -0700
@@ -72,6 +72,7 @@
 	netlogon.ndl		\
 	rpcpdu.ndl		\
 	samrpc.ndl		\
+	security.ndl		\
 	spoolss.ndl		\
 	srvsvc.ndl		\
 	svcctl.ndl		\
--- a/usr/src/uts/common/smbsrv/ndl/samrpc.ndl	Thu Jul 22 12:31:36 2010 -0700
+++ b/usr/src/uts/common/smbsrv/ndl/samrpc.ndl	Thu Jul 22 14:53:56 2010 -0700
@@ -32,7 +32,7 @@
 #include "ndrtypes.ndl"
 
 /* Windows NT */
-#define SAMR_OPNUM_ConnectAnon			0x00	/* SamrConnect */
+#define SAMR_OPNUM_Connect			0x00	/* SamrConnect */
 #define SAMR_OPNUM_CloseHandle			0x01
 #define SAMR_OPNUM_SetSecObject			0x02
 #define SAMR_OPNUM_QuerySecObject		0x03
@@ -91,16 +91,16 @@
 #define	SAMR_OPNUM_ChangeUserOemPassword	0x36
 #define SAMR_OPNUM_ChangeUserPasswd		0x37	/* UnicodePasswd */
 #define SAMR_OPNUM_GetDomainPwInfo		0x38
-#define SAMR_OPNUM_Connect			0x39	/* SamrConnect2 */
+#define SAMR_OPNUM_Connect2                     0x39    /* SamrConnect2 */
 #define SAMR_OPNUM_SetUserInfo			0x3a
 #define	SAMR_OPNUM_SetBootKeyInformation	0x3b
 #define	SAMR_OPNUM_GetBootKeyInformation	0x3c
-#define	SAMR_OPNUM_Connect2			0x3d	/* SamrConnect3 */
-#define	SAMR_OPNUM_Connect3			0x3e	/* SamrConnect4 */
+#define	SAMR_OPNUM_Connect3			0x3d	/* NotUsedOnWire */
+#define	SAMR_OPNUM_Connect4			0x3e	/* SamrConnect4 */
 #define	SAMR_OPNUM_ChangeUserUnicodePassword3	0x3f
 
 /* Windows XP and Windows Server 2003 */
-#define	SAMR_OPNUM_Connect4			0x40	/* SamrConnect5 */
+#define	SAMR_OPNUM_Connect5			0x40	/* SamrConnect5 */
 #define	SAMR_OPNUM_RidToSid                     0x41
 #define	SAMR_OPNUM_SetDSRMPassword              0x42
 #define	SAMR_OPNUM_ValidatePassword             0x43
@@ -362,12 +362,11 @@
 
 /*
  ***********************************************************************
- * ConnectAnon. It looks like the SAM handle is identical to an LSA
- * handle. See Connect.
+ * SamrConnect.
  ***********************************************************************
  */
-OPERATION(SAMR_OPNUM_ConnectAnon)
-struct samr_ConnectAnon {
+OPERATION(SAMR_OPNUM_Connect)
+struct samr_Connect {
 	IN	DWORD *servername;
 	IN	DWORD access_mask;
 	OUT	samr_handle_t handle;
@@ -377,12 +376,11 @@
 
 /*
  ***********************************************************************
- * Connect. I'm not sure what the difference is between Connect and 
- * ConnectAnon but this call seems to work better than ConnectAnon.
+ * SamrConnect2.
  ***********************************************************************
  */
-OPERATION(SAMR_OPNUM_Connect)
-struct samr_Connect {
+OPERATION(SAMR_OPNUM_Connect2)
+struct samr_Connect2 {
 	IN	LPTSTR servername;
 	IN	DWORD access_mask;
 	OUT	samr_handle_t handle;
@@ -392,14 +390,12 @@
 
 /*
  ***********************************************************************
- * SamrConnect3. A new form of connect first seen with Windows 2000.
+ * SamrConnect4. A new form of connect first seen with Windows 2000.
  * A new field has been added to the input request. Value: 0x00000002.
- * I haven't looked at the Win2K response yet to see if it differs
- * from SAMR_OPNUM_Connect.
  ***********************************************************************
  */
-OPERATION(SAMR_OPNUM_Connect3)
-struct samr_Connect3 {
+OPERATION(SAMR_OPNUM_Connect4)
+struct samr_Connect4 {
 	IN	LPTSTR servername;
 	IN	DWORD revision;
 	IN	DWORD access_mask;
@@ -410,7 +406,7 @@
 
 /*
  ***********************************************************************
- * SamrConnect4. A new form of connect first seen with Windows XP.
+ * SamrConnect5. A new form of connect first seen with Windows XP.
  * The server name is the fully qualified domain name, i.e.
  *	\\server.sun.com.
  *
@@ -437,8 +433,8 @@
 	DEFAULT	char *nullptr;
 };
 
-OPERATION(SAMR_OPNUM_Connect4)
-struct samr_Connect4 {
+OPERATION(SAMR_OPNUM_Connect5)
+struct samr_Connect5 {
 	IN		LPTSTR servername;
 	IN		DWORD access_mask;
 	INOUT	DWORD unknown2_00000001;
@@ -1426,8 +1422,8 @@
  */
 INTERFACE(0)
 union samr_interface {
-	CASE(SAMR_OPNUM_ConnectAnon)
-		struct samr_ConnectAnon		ConnectAnon;
+	CASE(SAMR_OPNUM_Connect)
+		struct samr_Connect		Connect;
 	CASE(SAMR_OPNUM_CloseHandle)
 		struct samr_CloseHandle		CloseHandle;
 	CASE(SAMR_OPNUM_LookupDomain)
@@ -1466,14 +1462,14 @@
 		struct samr_ChangeUserPasswd	ChangeUserPasswd;
 	CASE(SAMR_OPNUM_GetDomainPwInfo)
 		struct samr_GetDomainPwInfo	GetDomainPwInfo;
-	CASE(SAMR_OPNUM_Connect)
-		struct samr_Connect		Connect;
+	CASE(SAMR_OPNUM_Connect2)
+		struct samr_Connect2		Connect2;
 	CASE(SAMR_OPNUM_SetUserInfo)
 		struct samr_SetUserInfo		SetUserInfo;
-	CASE(SAMR_OPNUM_Connect3)
-		struct samr_Connect3		Connect3;
 	CASE(SAMR_OPNUM_Connect4)
 		struct samr_Connect4		Connect4;
+	CASE(SAMR_OPNUM_Connect5)
+		struct samr_Connect5		Connect5;
 	CASE(SAMR_OPNUM_QueryDispInfo)
 		struct samr_QueryDispInfo	QueryDispInfo;
 	CASE(SAMR_OPNUM_OpenAlias)
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/usr/src/uts/common/smbsrv/ndl/security.ndl	Thu Jul 22 14:53:56 2010 -0700
@@ -0,0 +1,347 @@
+/*
+ * CDDL HEADER START
+ *
+ * The contents of this file are subject to the terms of the
+ * Common Development and Distribution License (the "License").
+ * You may not use this file except in compliance with the License.
+ *
+ * You can obtain a copy of the license at usr/src/OPENSOLARIS.LICENSE
+ * or http://www.opensolaris.org/os/licensing.
+ * See the License for the specific language governing permissions
+ * and limitations under the License.
+ *
+ * When distributing Covered Code, include this CDDL HEADER in each
+ * file and include the License file at usr/src/OPENSOLARIS.LICENSE.
+ * If applicable, add the following below this CDDL HEADER, with the
+ * fields enclosed by brackets "[]" replaced with your own identifying
+ * information: Portions Copyright [yyyy] [name of copyright owner]
+ *
+ * CDDL HEADER END
+ */
+/*
+ * Copyright (c) 2010, Oracle and/or its affiliates. All rights reserved.
+ */
+
+#ifndef _SECURITY_NDL_
+#define	_SECURITY_NDL_
+
+#define	USE_UINT_ENUMS 1
+
+struct GUID {
+	DWORD time_low;
+	WORD time_mid;
+	WORD time_hi_and_version;
+	BYTE clock_seq[2];
+	BYTE node[6];
+};
+
+#define	SEC_MASK_GENERIC	0xF0000000
+#define	SEC_MASK_FLAGS		0x0F000000
+#define	SEC_MASK_STANDARD	0x00FF0000
+#define	SEC_MASK_SPECIFIC	0x0000FFFF
+#define	SEC_GENERIC_ALL		0x10000000
+#define	SEC_GENERIC_EXECUTE	0x20000000
+#define	SEC_GENERIC_WRITE	0x40000000
+#define	SEC_GENERIC_READ	0x80000000
+#define	SEC_FLAG_SYSTEM_SECURITY 0x01000000
+#define	SEC_FLAG_MAXIMUM_ALLOWED 0x02000000
+#define	SEC_STD_DELETE		0x00010000
+#define	SEC_STD_READ_CONTROL	0x00020000
+#define	SEC_STD_WRITE_DAC	0x00040000
+#define	SEC_STD_WRITE_OWNER	0x00080000
+#define	SEC_STD_SYNCHRONIZE	0x00100000
+#define	SEC_STD_REQUIRED	0x000F0000
+#define	SEC_STD_ALL		0x001F0000
+#define	SEC_FILE_READ_DATA	0x00000001
+#define	SEC_FILE_WRITE_DATA	0x00000002
+#define	SEC_FILE_APPEND_DATA	0x00000004
+#define	SEC_FILE_READ_EA	0x00000008
+#define	SEC_FILE_WRITE_EA	0x00000010
+#define	SEC_FILE_EXECUTE	0x00000020
+#define	SEC_FILE_READ_ATTRIBUTE	0x00000080
+#define	SEC_FILE_WRITE_ATTRIBUTE 0x00000100
+#define	SEC_FILE_ALL		0x000001ff
+#define	SEC_DIR_LIST		0x00000001
+#define	SEC_DIR_ADD_FILE	0x00000002
+#define	SEC_DIR_ADD_SUBDIR	0x00000004
+#define	SEC_DIR_READ_EA		0x00000008
+#define	SEC_DIR_WRITE_EA	0x00000010
+#define	SEC_DIR_TRAVERSE	0x00000020
+#define	SEC_DIR_DELETE_CHILD	0x00000040
+#define	SEC_DIR_READ_ATTRIBUTE	0x00000080
+#define	SEC_DIR_WRITE_ATTRIBUTE	0x00000100
+#define	SEC_REG_QUERY_VALUE	0x00000001
+#define	SEC_REG_SET_VALUE	0x00000002
+#define	SEC_REG_CREATE_SUBKEY	0x00000004
+#define	SEC_REG_ENUM_SUBKEYS	0x00000008
+#define	SEC_REG_NOTIFY		0x00000010
+#define	SEC_REG_CREATE_LINK	0x00000020
+#define	SEC_ADS_CREATE_CHILD	0x00000001
+#define	SEC_ADS_DELETE_CHILD	0x00000002
+#define	SEC_ADS_LIST		0x00000004
+#define	SEC_ADS_SELF_WRITE	0x00000008
+#define	SEC_ADS_READ_PROP	0x00000010
+#define	SEC_ADS_WRITE_PROP	0x00000020
+#define	SEC_ADS_DELETE_TREE	0x00000040
+#define	SEC_ADS_LIST_OBJECT	0x00000080
+#define	SEC_ADS_CONTROL_ACCESS	0x00000100
+#define	SEC_RIGHTS_FILE_READ	SEC_STD_READ_CONTROL|SEC_STD_SYNCHRONIZE|SEC_FILE_READ_DATA|SEC_FILE_READ_ATTRIBUTE|SEC_FILE_READ_EA
+#define	SEC_RIGHTS_FILE_WRITE	SEC_STD_READ_CONTROL|SEC_STD_SYNCHRONIZE|SEC_FILE_WRITE_DATA|SEC_FILE_WRITE_ATTRIBUTE|SEC_FILE_WRITE_EA|SEC_FILE_APPEND_DATA
+#define	SEC_RIGHTS_FILE_EXECUTE	SEC_STD_SYNCHRONIZE|SEC_STD_READ_CONTROL|SEC_FILE_READ_ATTRIBUTE|SEC_FILE_EXECUTE
+#define	SEC_RIGHTS_FILE_ALL	SEC_STD_ALL|SEC_FILE_ALL
+#define	SEC_RIGHTS_DIR_READ	SEC_RIGHTS_FILE_READ
+#define	SEC_RIGHTS_DIR_WRITE	SEC_RIGHTS_FILE_WRITE
+#define	SEC_RIGHTS_DIR_EXECUTE	SEC_RIGHTS_FILE_EXECUTE
+#define	SEC_RIGHTS_DIR_ALL	SEC_RIGHTS_FILE_ALL
+#define	SID_NULL		"S-1-0-0"
+#define	SID_WORLD_DOMAIN	"S-1-1"
+#define	SID_WORLD		"S-1-1-0"
+#define	SID_CREATOR_OWNER_DOMAIN "S-1-3"
+#define	SID_CREATOR_OWNER	"S-1-3-0"
+#define	SID_CREATOR_GROUP	"S-1-3-1"
+#define	SID_NT_AUTHORITY	"S-1-5"
+#define	SID_NT_DIALUP		"S-1-5-1"
+#define	SID_NT_NETWORK		"S-1-5-2"
+#define	SID_NT_BATCH		"S-1-5-3"
+#define	SID_NT_INTERACTIVE	"S-1-5-4"
+#define	SID_NT_SERVICE		"S-1-5-6"
+#define	SID_NT_ANONYMOUS	"S-1-5-7"
+#define	SID_NT_PROXY		"S-1-5-8"
+#define	SID_NT_ENTERPRISE_DCS	"S-1-5-9"
+#define	SID_NT_SELF		"S-1-5-10"
+#define	SID_NT_AUTHENTICATED_USERS "S-1-5-11"
+#define	SID_NT_RESTRICTED	"S-1-5-12"
+#define	SID_NT_TERMINAL_SERVER_USERS "S-1-5-13"
+#define	SID_NT_REMOTE_INTERACTIVE "S-1-5-14"
+#define	SID_NT_THIS_ORGANISATION  "S-1-5-15"
+#define	SID_NT_SYSTEM		"S-1-5-18"
+#define	SID_NT_LOCAL_SERVICE	"S-1-5-19"
+#define	SID_NT_NETWORK_SERVICE	"S-1-5-20"
+#define	SID_BUILTIN		"S-1-5-32"
+#define	SID_BUILTIN_ADMINISTRATORS "S-1-5-32-544"
+#define	SID_BUILTIN_USERS	"S-1-5-32-545"
+#define	SID_BUILTIN_GUESTS	"S-1-5-32-546"
+#define	SID_BUILTIN_POWER_USERS	"S-1-5-32-547"
+#define	SID_BUILTIN_ACCOUNT_OPERATORS	"S-1-5-32-548"
+#define	SID_BUILTIN_SERVER_OPERATORS	"S-1-5-32-549"
+#define	SID_BUILTIN_PRINT_OPERATORS	"S-1-5-32-550"
+#define	SID_BUILTIN_BACKUP_OPERATORS	"S-1-5-32-551"
+#define	SID_BUILTIN_REPLICATOR	"S-1-5-32-552"
+#define	SID_BUILTIN_RAS_SERVERS	"S-1-5-32-553"
+#define	SID_BUILTIN_PREW2K	"S-1-5-32-554"
+#define	DOMAIN_RID_LOGON	9
+#define	DOMAIN_RID_ADMINISTRATOR 500
+#define	DOMAIN_RID_GUEST	501
+#define	DOMAIN_RID_ADMINS	512
+#define	DOMAIN_RID_USERS	513
+#define	DOMAIN_RID_DCS		516
+#define	DOMAIN_RID_CERT_ADMINS	517
+#define	DOMAIN_RID_SCHEMA_ADMINS 518
+#define	DOMAIN_RID_ENTERPRISE_ADMINS 519
+#define	NT4_ACL_REVISION	SECURITY_ACL_REVISION_NT4
+#define	SD_REVISION		SECURITY_DESCRIPTOR_REVISION_1
+
+#ifndef USE_UINT_ENUMS
+	enum sec_privilege {
+	SEC_PRIV_SECURITY=1,
+	SEC_PRIV_BACKUP=2,
+	SEC_PRIV_RESTORE=3,
+	SEC_PRIV_SYSTEMTIME=4,
+	SEC_PRIV_SHUTDOWN=5,
+	SEC_PRIV_REMOTE_SHUTDOWN=6,
+	SEC_PRIV_TAKE_OWNERSHIP=7,
+	SEC_PRIV_DEBUG=8,
+	SEC_PRIV_SYSTEM_ENVIRONMENT=9,
+	SEC_PRIV_SYSTEM_PROFILE=10,
+	SEC_PRIV_PROFILE_SINGLE_PROCESS=11,
+	SEC_PRIV_INCREASE_BASE_PRIORITY=12,
+	SEC_PRIV_LOAD_DRIVER=13,
+	SEC_PRIV_CREATE_PAGEFILE=14,
+	SEC_PRIV_INCREASE_QUOTA=15,
+	SEC_PRIV_CHANGE_NOTIFY=16,
+	SEC_PRIV_UNDOCK=17,
+	SEC_PRIV_MANAGE_VOLUME=18,
+	SEC_PRIV_IMPERSONATE=19,
+	SEC_PRIV_CREATE_GLOBAL=20,
+	SEC_PRIV_ENABLE_DELEGATION=21,
+	SEC_PRIV_INTERACTIVE_LOGON=22,
+	SEC_PRIV_NETWORK_LOGON=23,
+	SEC_PRIV_REMOTE_INTERACTIVE_LOGON=24
+};
+#else
+
+#define	SEC_PRIV_SECURITY			1
+#define	SEC_PRIV_BACKUP				2
+#define	SEC_PRIV_RESTORE			3
+#define	SEC_PRIV_SYSTEMTIME			4
+#define	SEC_PRIV_SHUTDOWN			5
+#define	SEC_PRIV_REMOTE_SHUTDOWN		6
+#define	SEC_PRIV_TAKE_OWNERSHIP			7
+#define	SEC_PRIV_DEBUG				8
+#define	SEC_PRIV_SYSTEM_ENVIRONMENT		9
+#define	SEC_PRIV_SYSTEM_PROFILE			10
+#define	SEC_PRIV_PROFILE_SINGLE_PROCESS		11
+#define	SEC_PRIV_INCREASE_BASE_PRIORITY		12
+#define	SEC_PRIV_LOAD_DRIVER			13
+#define	SEC_PRIV_CREATE_PAGEFILE		14
+#define	SEC_PRIV_INCREASE_QUOTA			15
+#define	SEC_PRIV_CHANGE_NOTIFY			16
+#define	SEC_PRIV_UNDOCK				17
+#define	SEC_PRIV_MANAGE_VOLUME			18
+#define	SEC_PRIV_IMPERSONATE			19
+#define	SEC_PRIV_CREATE_GLOBAL			20
+#define	SEC_PRIV_ENABLE_DELEGATION		21
+#define	SEC_PRIV_INTERACTIVE_LOGON		22
+#define	SEC_PRIV_NETWORK_LOGON			23
+#define	SEC_PRIV_REMOTE_INTERACTIVE_LOGON	24
+#endif
+
+struct dom_sid {
+	BYTE sid_rev_num;
+	BYTE num_auths;
+	BYTE id_auth[6];
+	DWORD *sub_auths;
+};
+
+/*
+ * bitmap security_ace_flags
+ */
+#define	SEC_ACE_FLAG_OBJECT_INHERIT		0x01
+#define	SEC_ACE_FLAG_CONTAINER_INHERIT		0x02
+#define	SEC_ACE_FLAG_NO_PROPAGATE_INHERIT	0x04
+#define	SEC_ACE_FLAG_INHERIT_ONLY		0x08
+#define	SEC_ACE_FLAG_INHERITED_ACE		0x10
+#define	SEC_ACE_FLAG_VALID_INHERIT		0x0f
+#define	SEC_ACE_FLAG_SUCCESSFUL_ACCESS		0x40
+#define	SEC_ACE_FLAG_FAILED_ACCESS		0x80
+
+#ifndef USE_UINT_ENUMS
+enum security_ace_type {
+	SEC_ACE_TYPE_ACCESS_ALLOWED=0,
+	SEC_ACE_TYPE_ACCESS_DENIED=1,
+	SEC_ACE_TYPE_SYSTEM_AUDIT=2,
+	SEC_ACE_TYPE_SYSTEM_ALARM=3,
+	SEC_ACE_TYPE_ALLOWED_COMPOUND=4,
+	SEC_ACE_TYPE_ACCESS_ALLOWED_OBJECT=5,
+	SEC_ACE_TYPE_ACCESS_DENIED_OBJECT=6,
+	SEC_ACE_TYPE_SYSTEM_AUDIT_OBJECT=7,
+	SEC_ACE_TYPE_SYSTEM_ALARM_OBJECT=8
+};
+#else
+#define	SEC_ACE_TYPE_ACCESS_ALLOWED		0
+#define	SEC_ACE_TYPE_ACCESS_DENIED		1
+#define	SEC_ACE_TYPE_SYSTEM_AUDIT		2
+#define	SEC_ACE_TYPE_SYSTEM_ALARM		3
+#define	SEC_ACE_TYPE_ALLOWED_COMPOUND		4
+#define	SEC_ACE_TYPE_ACCESS_ALLOWED_OBJECT	5
+#define	SEC_ACE_TYPE_ACCESS_DENIED_OBJECT	6
+#define	SEC_ACE_TYPE_SYSTEM_AUDIT_OBJECT	7
+#define	SEC_ACE_TYPE_SYSTEM_ALARM_OBJECT	8
+#endif
+
+/*
+ * bitmap security_ace_object_flags
+ */
+#define	SEC_ACE_OBJECT_TYPE_PRESENT		0x00000001
+#define	SEC_ACE_INHERITED_OBJECT_TYPE_PRESENT	0x00000002
+
+union security_ace_object_type {
+	CASE(0) struct GUID type;
+};
+
+union security_ace_object_inherited_type {
+	CASE(0) struct GUID inherited_type;
+};
+
+struct security_ace_object {
+	DWORD flags;
+};
+
+union security_ace_object_ctr {
+	CASE(0) struct security_ace_object object;
+};
+
+struct security_ace {
+	DWORD security_ace_type;
+	BYTE flags;
+	WORD size;
+	DWORD access_mask;
+	struct dom_sid trustee;
+};
+
+#ifndef USE_UINT_ENUMS
+enum security_acl_revision {
+	SECURITY_ACL_REVISION_NT4=2,
+	SECURITY_ACL_REVISION_ADS=4
+};
+#else
+#define	SECURITY_ACL_REVISION_NT4	2
+#define	SECURITY_ACL_REVISION_ADS	4
+#endif
+
+struct security_acl {
+	DWORD security_acl_revision;
+	WORD size;
+	DWORD num_aces;
+	struct security_ace *aces;
+};
+
+#ifndef USE_UINT_ENUMS
+enum security_descriptor_revision {
+	SECURITY_DESCRIPTOR_REVISION_1=1
+};
+#else
+#define	SECURITY_DESCRIPTOR_REVISION_1	1
+#endif
+
+/*
+ * bitmap security_descriptor_type
+ */
+#define	SEC_DESC_OWNER_DEFAULTED	0x0001
+#define	SEC_DESC_GROUP_DEFAULTED	0x0002
+#define	SEC_DESC_DACL_PRESENT		0x0004
+#define	SEC_DESC_DACL_DEFAULTED		0x0008
+#define	SEC_DESC_SACL_PRESENT		0x0010
+#define	SEC_DESC_SACL_DEFAULTED		0x0020
+#define	SEC_DESC_DACL_TRUSTED		0x0040
+#define	SEC_DESC_SERVER_SECURITY	0x0080
+#define	SEC_DESC_DACL_AUTO_INHERIT_REQ	0x0100
+#define	SEC_DESC_SACL_AUTO_INHERIT_REQ	0x0200
+#define	SEC_DESC_DACL_AUTO_INHERITED	0x0400
+#define	SEC_DESC_SACL_AUTO_INHERITED	0x0800
+#define	SEC_DESC_DACL_PROTECTED		0x1000
+#define	SEC_DESC_SACL_PROTECTED		0x2000
+#define	SEC_DESC_RM_CONTROL_VALID	0x4000
+#define	SEC_DESC_SELF_RELATIVE		0x8000
+
+struct security_descriptor {
+	WORD revision;
+	WORD type;
+	DWORD ownersid;
+	DWORD groupsid;
+	DWORD sacl;
+	DWORD dacl;
+};
+
+struct sec_desc_buf {
+	DWORD sd_size;
+	struct security_descriptor *sd;
+};
+
+struct security_token {
+	struct dom_sid *user_sid;
+	struct dom_sid *group_sid;
+	DWORD num_sids;
+	DWORD privilege_mask1;
+	DWORD privilege_mask2;
+};
+
+/* 
+ * bitmap security_secinfo
+ */
+#define	SECINFO_OWNER		0x00000001
+#define	SECINFO_GROUP		0x00000002
+#define	SECINFO_DACL		0x00000004
+#define	SECINFO_SACL		0x00000008
+
+#endif /* _SECURITY_NDL_ */
--- a/usr/src/uts/common/smbsrv/ndl/spoolss.ndl	Thu Jul 22 12:31:36 2010 -0700
+++ b/usr/src/uts/common/smbsrv/ndl/spoolss.ndl	Thu Jul 22 14:53:56 2010 -0700
@@ -19,84 +19,132 @@
  * CDDL HEADER END
  */
 /*
- * Copyright 2008 Sun Microsystems, Inc.  All rights reserved.
- * Use is subject to license terms.
+ * Copyright (c) 2007, 2010, Oracle and/or its affiliates. All rights reserved.
  */
 
-#ifndef _MLSVC_SPOOLSS_NDL_
-#define _MLSVC_SPOOLSS_NDL_
-
-/*
- * Printing and Spooling RPC interface definition.
- */
+#ifndef _SPOOLSS_NDL_
+#define	_SPOOLSS_NDL_
 
 #include "ndrtypes.ndl"
-
+#include "security.ndl"
 
-/*
- * The spoolss opcodes.
- */
+#define TABLE_STRING 1
+#define TABLE_DWORD  2
+#define TABLE_TIME   3
+#define TABLE_DEVMODE 4
+#define TABLE_SECURITY_DESCRIPTOR 5
+
 #define SPOOLSS_OPNUM_OpenPrinter			0x01
 #define SPOOLSS_OPNUM_GetJob				0x03
+#define SPOOLSS_OPNUM_EnumJobs				0x04
 #define SPOOLSS_OPNUM_DeletePrinter			0x06
+#define SPOOLSS_OPNUM_GetPrinter			0x08
 #define SPOOLSS_OPNUM_GetPrinterDriver			0x0b
 #define SPOOLSS_OPNUM_DeletePrinterDriver		0x0d
-#define SPOOLSS_OPNUM_AddPrintProcessor			0x0e
-#define SPOOLSS_OPNUM_GetPrintProcessorDirectory	0x10
+#define SPOOLSS_OPNUM_StartDocPrinter			0x11
+#define SPOOLSS_OPNUM_StartPagePrinter			0x12
+#define SPOOLSS_OPNUM_WritePrinter			0x13
+#define SPOOLSS_OPNUM_EndPagePrinter			0x14
 #define SPOOLSS_OPNUM_AbortPrinter			0x15
-#define SPOOLSS_OPNUM_ReadPrinter			0x16
-#define SPOOLSS_OPNUM_WaitForPrinterChange		0x1c
-#define SPOOLSS_OPNUM_AddForm				0x1e
-#define SPOOLSS_OPNUM_DeleteForm			0x1f
-#define SPOOLSS_OPNUM_GetForm				0x20
-#define SPOOLSS_OPNUM_SetForm				0x21
-#define SPOOLSS_OPNUM_EnumMonitors			0x24
-#define SPOOLSS_OPNUM_AddPort				0x25
-#define SPOOLSS_OPNUM_ConfigurePort			0x26
-#define SPOOLSS_OPNUM_DeletePort			0x27
-#define SPOOLSS_OPNUM_CreatePrinterIc			0x28
-#define SPOOLSS_OPNUM_PlayDescriptionPrinterIc		0x29
-#define SPOOLSS_OPNUM_DeletePrinterIc			0x2a
-#define SPOOLSS_OPNUM_AddPrinterConnection		0x2b
-#define SPOOLSS_OPNUM_DeletePrinterConnection		0x2c
-#define SPOOLSS_OPNUM_PrinterMessageBox			0x2d
-#define SPOOLSS_OPNUM_AddMonitor			0x2e
-#define SPOOLSS_OPNUM_DeleteMonitor			0x2f
-#define SPOOLSS_OPNUM_DeletePrintProcessor		0x30
-#define SPOOLSS_OPNUM_AddPrintProvider			0x31
-#define SPOOLSS_OPNUM_DeletePrintProvider		0x32
+#define SPOOLSS_OPNUM_AddJob				0x18
+#define SPOOLSS_OPNUM_ScheduleJob			0x19
+#define SPOOLSS_OPNUM_GetPrinterData			0x1a
+#define SPOOLSS_OPNUM_ClosePrinter			0x1d
+#define SPOOLSS_OPNUM_EndDocPrinter			0x17
+#define SPOOLSS_OPNUM_EnumForms				0x22
+#define SPOOLSS_OPNUM_CreatePrinterIC			0x28
 #define SPOOLSS_OPNUM_ResetPrinter			0x34
-#define SPOOLSS_OPNUM_FindFirstChangeNotify		0x36
-#define SPOOLSS_OPNUM_FindNextChangeNotify		0x37
-#define SPOOLSS_OPNUM_RouterFindFirstNotify		0x39
+#define SPOOLSS_OPNUM_GetPrinterDriver2			0x35
+#define SPOOLSS_OPNUM_FCPN				0x38
 #define SPOOLSS_OPNUM_ReplyOpenPrinter			0x3a
-#define SPOOLSS_OPNUM_RouterReplyPrinter                0x3b
 #define SPOOLSS_OPNUM_ReplyClosePrinter			0x3c
-#define SPOOLSS_OPNUM_AddPortEx				0x3d
-#define SPOOLSS_OPNUM_RemoteFindFirstChangeNotify	0x3e
-#define SPOOLSS_OPNUM_SpoolerInitialize			0x3f
-#define SPOOLSS_OPNUM_ResetPrinterEx			0x40
-#define SPOOLSS_OPNUM_RouterRefreshChangeNotify		0x42
-#define SPOOLSS_OPNUM_OpenPrinter2			0x45
-
+#define SPOOLSS_OPNUM_RFFPCNEX				0x41
+#define SPOOLSS_OPNUM_RRPCN				0x42
+#define SPOOLSS_OPNUM_RFNPCNEX				0x43
+#define SPOOLSS_OPNUM_OpenPrinterEx			0x45
+#define SPOOLSS_OPNUM_EnumPrinterData			0x48
+#define SPOOLSS_OPNUM_EnumPrinterDataEx			0x4f
+#define SPOOLSS_OPNUM_EnumPrinterKey			0x50
 
 CONTEXT_HANDLE(spoolss_handle) spoolss_handle_t;
 
+struct spoolssDevmodeContainer {
+	BYTE 	DevContCount;
+  SIZE_IS(DevContCount)
+  	BYTE	*DevMode;
+};
 
-OPERATION(SPOOLSS_OPNUM_OpenPrinter)
-struct spoolss_OpenPrinter {
-	IN	DWORD dontcare;
-	OUT	spoolss_handle_t handle;
+
+struct spoolss_DeviceMode {
+	BYTE devicename[64];
+	WORD specversion;
+	WORD driverversion;
+	WORD size;
+	WORD driverextra_length;
+	DWORD	fields;
+	WORD orientation;
+	WORD papersize;
+	WORD paperlength;
+	WORD paperwidth;
+	WORD scale;
+	WORD copies;
+	WORD defaultsource;
+	WORD printquality;
+	WORD color;
+	WORD duplex;
+	WORD yresolution;
+	WORD ttoption;
+	WORD collate;
+	BYTE formname[64];
+	WORD logpixels;
+	DWORD	bitsperpel;
+	DWORD	pelswidth;
+	DWORD	pelsheight;
+	DWORD	displayflags;
+	DWORD	displayfrequency;
+	DWORD	icmmethod;
+	DWORD	icmintent;
+	DWORD	mediatype;
+	DWORD	dithertype;
+	DWORD	reserved1;
+	DWORD	reserved2;
+	DWORD	panningwidth;
+	DWORD	panningheight;
+	struct spoolssDevmodeContainer driverextra_data;
+};
+
+OPERATION(SPOOLSS_OPNUM_CreatePrinterIC)
+struct spoolss_CreatePrinterIC {
+	IN	spoolss_handle_t handle;
+	OUT	spoolss_handle_t gdi_handle;
+	IN	struct spoolssDevmodeContainer dmodeContainer;
 	OUT	DWORD status;
 };
 
-
-OPERATION(SPOOLSS_OPNUM_GetJob)
-struct spoolss_GetJob {
-	IN	DWORD dontcare;
+OPERATION(SPOOLSS_OPNUM_OpenPrinter)
+struct spoolss_OpenPrinter {
+	IN	LPTSTR printer_name;
+	OUT	spoolss_handle_t handle;
+	IN	LPTSTR data_type;
+	IN	struct spoolssDevmodeContainer dmodeContainer;
+	IN	DWORD AccessRequired;
 	OUT	DWORD status;
 };
 
+OPERATION(SPOOLSS_OPNUM_EnumJobs)
+struct spoolss_EnumJobs {
+	IN	spoolss_handle_t handle;
+	IN	DWORD FirstJob;
+	IN	DWORD NoJobs;
+	IN	DWORD level;
+	IN	DWORD Buf2;
+	IN	DWORD 	BufCount;
+		SIZE_IS(BufCount)
+  	OUT		BYTE *pJob;
+	OUT	DWORD needed;
+	OUT	DWORD needed2;
+	OUT	DWORD status;
+};
 
 OPERATION(SPOOLSS_OPNUM_DeletePrinter)
 struct spoolss_DeletePrinter {
@@ -104,6 +152,311 @@
 	OUT	DWORD status;
 };
 
+#define SPOOLSS_ARCHITECTURE_NT_X86	( "Windows NT x86" )
+struct spoolss_Time {
+	WORD year;
+	WORD month;
+	WORD day_of_week;
+	WORD day;
+	WORD hour;
+	WORD minute;
+	WORD second;
+	WORD millisecond;
+};
+
+struct spoolss_GetPrinter0 {
+	DWORD printername;
+	DWORD servername;
+	DWORD cjobs;
+	DWORD total_jobs;
+	DWORD total_bytes;
+	DWORD time0;
+	DWORD time1;
+	DWORD time2;
+	DWORD time3;
+	DWORD global_counter;
+	DWORD total_pages;
+	DWORD version;
+	DWORD ffreebuild;
+	DWORD cspooling;
+	DWORD cmaxspooling;
+	DWORD session_counter;
+	DWORD out_of_paper;
+	DWORD not_ready;
+	DWORD job_error;
+	DWORD num_processors;
+	DWORD type_processor;
+	DWORD high_part_total_bytes;
+	DWORD change_id;
+	DWORD last_error;
+	DWORD status;
+	DWORD enum_network_printers;
+	DWORD c_setprinter;
+	WORD processor_arch;
+	WORD processor_level;
+	DWORD ref;
+	DWORD reserved2;
+	DWORD reserved3;
+};
+
+/* bitmap spoolss_EnumPrinterFlags */
+#define PRINTER_ENUM_DEFAULT ( 0x00000001 )
+#define PRINTER_ENUM_LOCAL ( 0x00000002 )
+#define PRINTER_ENUM_CONNECTIONS ( 0x00000004 )
+#define PRINTER_ENUM_FAVORITE ( 0x00000004 )
+#define PRINTER_ENUM_NAME ( 0x00000008 )
+#define PRINTER_ENUM_REMOTE ( 0x00000010 )
+#define PRINTER_ENUM_SHARED ( 0x00000020 )
+#define PRINTER_ENUM_NETWORK ( 0x00000040 )
+#define PRINTER_ENUM_EXPAND ( 0x00004000 )
+#define PRINTER_ENUM_CONTAINER ( 0x00008000 )
+#define PRINTER_ENUM_ICON1 ( 0x00010000 )
+#define PRINTER_ENUM_ICON2 ( 0x00020000 )
+#define PRINTER_ENUM_ICON3 ( 0x00040000 )
+#define PRINTER_ENUM_ICON4 ( 0x00080000 )
+#define PRINTER_ENUM_ICON5 ( 0x00100000 )
+#define PRINTER_ENUM_ICON6 ( 0x00200000 )
+#define PRINTER_ENUM_ICON7 ( 0x00400000 )
+#define PRINTER_ENUM_ICON8 ( 0x00800000 )
+#define PRINTER_ENUM_HIDE ( 0x01000000 )
+
+struct spoolss_GetPrinter1 {
+	DWORD flags;
+	DWORD name;
+	DWORD description;
+	DWORD comment;
+};
+
+/* bitmap spoolss_PrinterAttributes */
+#define PRINTER_ATTRIBUTE_QUEUED ( 0x00000001 )
+#define PRINTER_ATTRIBUTE_DIRECT ( 0x00000002 )
+#define PRINTER_ATTRIBUTE_DEFAULT ( 0x00000004 )
+#define PRINTER_ATTRIBUTE_SHARED ( 0x00000008 )
+#define PRINTER_ATTRIBUTE_NETWORK ( 0x00000010 )
+#define PRINTER_ATTRIBUTE_HIDDEN ( 0x00000020 )
+#define PRINTER_ATTRIBUTE_LOCAL ( 0x00000040 )
+#define PRINTER_ATTRIBUTE_ENABLE_DEVQ ( 0x00000080 )
+#define PRINTER_ATTRIBUTE_KEEPPRINTEDJOBS ( 0x00000100 )
+#define PRINTER_ATTRIBUTE_DO_COMPLETE_FIRST ( 0x00000200 )
+#define PRINTER_ATTRIBUTE_WORK_OFFLINE ( 0x00000400 )
+#define PRINTER_ATTRIBUTE_ENABLE_BIDI ( 0x00000800 )
+#define PRINTER_ATTRIBUTE_RAW_ONLY ( 0x00001000 )
+#define PRINTER_ATTRIBUTE_PUBLISHED ( 0x00002000 )
+#define PRINTER_ATTRIBUTE_FAX ( 0x00004000 )
+#define PRINTER_ATTRIBUTE_TS ( 0x00008000 )
+
+/* bitmap spoolss_PrinterStatus */
+#define PRINTER_STATUS_PAUSED ( 0x00000001 )
+#define PRINTER_STATUS_ERROR ( 0x00000002 )
+#define PRINTER_STATUS_PENDING_DELETION ( 0x00000004 )
+#define PRINTER_STATUS_PAPER_JAM ( 0x00000008 )
+#define PRINTER_STATUS_PAPER_OUT ( 0x00000010 )
+#define PRINTER_STATUS_MANUAL_FEED ( 0x00000020 )
+#define PRINTER_STATUS_PAPER_PROBLEM ( 0x00000040 )
+#define PRINTER_STATUS_OFFLINE ( 0x00000080 )
+#define PRINTER_STATUS_IO_ACTIVE ( 0x00000100 )
+#define PRINTER_STATUS_BUSY ( 0x00000200 )
+#define PRINTER_STATUS_PRINTING ( 0x00000400 )
+#define PRINTER_STATUS_OUTPUT_BIN_FULL ( 0x00000800 )
+#define PRINTER_STATUS_NOT_AVAILABLE ( 0x00001000 )
+#define PRINTER_STATUS_WAITING ( 0x00002000 )
+#define PRINTER_STATUS_PROCESSING ( 0x00004000 )
+#define PRINTER_STATUS_INITIALIZING ( 0x00008000 )
+#define PRINTER_STATUS_WARMING_UP ( 0x00010000 )
+#define PRINTER_STATUS_TONER_LOW ( 0x00020000 )
+#define PRINTER_STATUS_NO_TONER ( 0x00040000 )
+#define PRINTER_STATUS_PAGE_PUNT ( 0x00080000 )
+#define PRINTER_STATUS_USER_INTERVENTION ( 0x00100000 )
+#define PRINTER_STATUS_OUT_OF_MEMORY ( 0x00200000 )
+#define PRINTER_STATUS_DOOR_OPEN ( 0x00400000 )
+#define PRINTER_STATUS_SERVER_UNKNOWN ( 0x00800000 )
+#define PRINTER_STATUS_POWER_SAVE ( 0x01000000 )
+
+struct spoolss_GetPrinter2 {
+	DWORD servername;
+	DWORD printername;
+	DWORD sharename;
+	DWORD portname;
+	DWORD drivername;
+	DWORD comment;
+	DWORD location;
+	DWORD devmode;
+	DWORD sepfile;
+	DWORD printprocessor;
+	DWORD datatype;
+	DWORD parameters;
+	DWORD secdesc; 
+	DWORD attributes;
+	DWORD priority;
+	DWORD defaultpriority;
+	DWORD starttime;
+	DWORD untiltime;
+	DWORD status;
+	DWORD cjobs;
+	DWORD averageppm;
+};
+
+typedef struct spoolss_GetPrinter2 spoolss_GetPrinter2_t;
+
+struct spoolss_GetPrinter3 {
+	DWORD dummy;
+};
+
+struct spoolss_GetPrinter4 {
+	DWORD printername;
+	DWORD servername;
+	DWORD attributes;
+};
+
+struct spoolss_GetPrinter5 {
+	DWORD printername;
+	DWORD portname;
+	DWORD attributes;
+	DWORD device_not_selected_timeout;
+	DWORD transmission_retry_timeout;
+};
+
+struct spoolss_GetPrinter6 {
+	DWORD status;
+};
+
+/* bitmap spoolss_DsPrintAction */
+#define DSPRINT_PUBLISH ( 0x00000001 )
+#define DSPRINT_UPDATE ( 0x00000002 )
+#define DSPRINT_UNPUBLISH ( 0x00000004 )
+#define DSPRINT_REPUBLISH ( 0x00000008 )
+#define DSPRINT_PENDING ( 0x80000000 )
+
+struct spoolss_GetPrinter7 {
+	DWORD guid;
+	DWORD action;
+};
+
+struct spoolss_GetPrinter8 {
+	DWORD flags;
+	DWORD name;
+	DWORD description;
+	DWORD comment;
+};
+
+union spoolss_GetPrinter_result_u {
+	UNION_INFO_ENT(0, spoolss_GetPrinter);
+	UNION_INFO_ENT(1, spoolss_GetPrinter);
+	UNION_INFO_ENT(2, spoolss_GetPrinter);
+	UNION_INFO_ENT(3, spoolss_GetPrinter);
+	UNION_INFO_ENT(4, spoolss_GetPrinter);
+	UNION_INFO_ENT(5, spoolss_GetPrinter);
+	UNION_INFO_ENT(6, spoolss_GetPrinter);
+	UNION_INFO_ENT(7, spoolss_GetPrinter);
+	UNION_INFO_ENT(8, spoolss_GetPrinter);
+	DEFAULT char *nullptr;
+};
+
+struct spoolss_GetPrinter_result {
+	DWORD switch_value;
+	SWITCH(switch_value)
+		union spoolss_GetPrinter_result_u ru;
+};
+
+struct spoolss_RPC_V2_NOTIFY_OPTIONS_TYPE {
+	WORD type;
+	WORD reserved0;
+	DWORD reserved1;
+	DWORD reserved2;
+	DWORD count;
+	SIZE_IS(count)
+		WORD *pFields;
+};
+
+struct spoolss_RPC_V2_NOTIFY_OPTIONS {
+	DWORD version;
+	DWORD reserved;
+	DWORD count;
+	SIZE_IS(count)
+		struct spoolss_RPC_V2_NOTIFY_OPTIONS_TYPE *ptypes;
+};
+
+struct SYSTEMTIME {
+	WORD year;
+	WORD month;
+	WORD dayofweek;
+	WORD day;
+	WORD hour;
+	WORD minute;
+	WORD second;
+	WORD millisecs;
+};
+
+struct SECURITY_CONTAINER {
+	DWORD count;
+	SIZE_IS(count)
+		BYTE *psecurity;
+};
+
+struct SYSTEMTIME_CONTAINER {
+	DWORD count;
+	struct SYSTEMTIME *psystemtime;
+};
+
+struct STRING_CONTAINER {
+	DWORD count;
+	SIZE_IS(count / 2)
+		LPTSTR pstring;
+};
+
+union spoolss_RPC_V2_NOTIFY_INFO_DATA_DATA {
+	CASE(TABLE_STRING)
+		struct STRING_CONTAINER pcont;
+	CASE(TABLE_DWORD)
+		DWORD data[2];
+	CASE(TABLE_TIME)
+		struct SYSTEMTIME_CONTAINER system_time;
+	CASE(TABLE_DEVMODE)
+		struct spoolssDevmodeContainer devmode;
+	CASE(TABLE_SECURITY_DESCRIPTOR)
+		struct SECURITY_CONTAINER security_descriptor;
+};
+
+struct spoolss_RPC_V2_NOTIFY_INFO_DATA {
+	WORD Type;
+	WORD Field;
+	DWORD Reserved;
+	DWORD Id;
+	SWITCH(Reserved & 0x0000FFFF)
+		union spoolss_RPC_V2_NOTIFY_INFO_DATA_DATA data;
+};
+
+struct spoolss_RPC_V2_NOTIFY_INFO {
+	DWORD Version;
+	DWORD Flags;
+	DWORD Count;
+	SIZE_IS(Count)
+		struct spoolss_RPC_V2_NOTIFY_INFO_DATA *aData;
+};
+	
+OPERATION(SPOOLSS_OPNUM_GetPrinter)
+struct spoolss_GetPrinter {
+	IN	spoolss_handle_t handle;
+	IN 	DWORD 	switch_value;
+  	IN	DWORD   Buf2;
+	IN	DWORD 	BufCount;
+		SIZE_IS(BufCount)
+  	OUT		BYTE *Buf;
+	OUT	DWORD needed;
+	OUT	DWORD status;
+};
+
+OPERATION(SPOOLSS_OPNUM_GetPrinterData)
+struct spoolss_GetPrinterData {
+	IN	spoolss_handle_t handle;
+	IN	REFERENCE LPTSTR pValueName;
+	OUT	DWORD pType;
+		SIZE_IS(Size)
+   	OUT	LPBYTE Buf;
+	IN	DWORD Size;
+	OUT	DWORD Needed;
+	OUT	DWORD status;
+};
 
 OPERATION(SPOOLSS_OPNUM_GetPrinterDriver)
 struct spoolss_GetPrinterDriver {
@@ -111,224 +464,142 @@
 	OUT	DWORD status;
 };
 
-
 OPERATION(SPOOLSS_OPNUM_DeletePrinterDriver)
 struct spoolss_DeletePrinterDriver {
 	IN	DWORD dontcare;
 	OUT	DWORD status;
 };
 
+struct spoolss_DocInfo {
+	LPTSTR doc_name;
+	LPTSTR printer_name;
+	LPTSTR type;
+};
+typedef struct spoolss_DocInfo spoolss_DocInfo_t;
 
-OPERATION(SPOOLSS_OPNUM_AddPrintProcessor)
-struct spoolss_AddPrintProcessor {
-	IN	DWORD dontcare;
+struct spoolss_DocInfo_Container {
+	DWORD level;
+	DWORD switch_value;
+	spoolss_DocInfo_t *DocInfoContainer;
+};
+typedef struct spoolss_DocInfo_Container spoolss_DocInfo_Container_t;
+
+OPERATION(SPOOLSS_OPNUM_StartDocPrinter)
+struct spoolss_StartDocPrinter {
+	IN	spoolss_handle_t handle;
+	IN	spoolss_DocInfo_Container_t dinfo;
+	OUT	DWORD JobId;
 	OUT	DWORD status;
 };
 
-
-OPERATION(SPOOLSS_OPNUM_GetPrintProcessorDirectory)
-struct spoolss_GetPrintProcessorDirectory {
-	IN	DWORD dontcare;
-	OUT	DWORD status;
-};
-
-
 OPERATION(SPOOLSS_OPNUM_AbortPrinter)
 struct spoolss_AbortPrinter {
-	IN	DWORD dontcare;
+	IN	spoolss_handle_t handle;
 	OUT	DWORD status;
 };
 
-
-OPERATION(SPOOLSS_OPNUM_ReadPrinter)
-struct spoolss_ReadPrinter {
-	IN	DWORD dontcare;
+OPERATION(SPOOLSS_OPNUM_ResetPrinter)
+struct spoolss_ResetPrinter {
+	IN	spoolss_handle_t handle;
 	OUT	DWORD status;
 };
 
-
-OPERATION(SPOOLSS_OPNUM_WaitForPrinterChange)
-struct spoolss_WaitForPrinterChange {
-	IN	DWORD dontcare;
+OPERATION(SPOOLSS_OPNUM_StartPagePrinter)
+struct spoolss_StartPagePrinter {
+	IN	spoolss_handle_t handle;
 	OUT	DWORD status;
 };
 
+OPERATION(SPOOLSS_OPNUM_EndPagePrinter)
+struct spoolss_EndPagePrinter {
+	IN	spoolss_handle_t handle;
+	OUT	DWORD status;
+};
 
-OPERATION(SPOOLSS_OPNUM_AddForm)
-struct spoolss_AddForm {
-	IN	DWORD dontcare;
+OPERATION(SPOOLSS_OPNUM_WritePrinter)
+struct spoolss_WritePrinter {
+	IN	spoolss_handle_t handle;
+	IN	DWORD BufCount;
+		SIZE_IS(BufCount)
+  	IN	REFERENCE LPBYTE pBuf;
+	OUT	DWORD written;
 	OUT	DWORD status;
 };
 
-
-OPERATION(SPOOLSS_OPNUM_DeleteForm)
-struct spoolss_DeleteForm {
-	IN	DWORD dontcare;
+OPERATION(SPOOLSS_OPNUM_ScheduleJob)
+struct spoolss_ScheduleJob {
+	IN	spoolss_handle_t handle;
+	IN 	DWORD 	JobId;
 	OUT	DWORD status;
 };
 
-
-OPERATION(SPOOLSS_OPNUM_GetForm)
-struct spoolss_GetForm {
-	IN	DWORD dontcare;
-	OUT	DWORD status;
-};
-
-
-OPERATION(SPOOLSS_OPNUM_SetForm)
-struct spoolss_SetForm {
-	IN	DWORD dontcare;
+OPERATION(SPOOLSS_OPNUM_GetJob)
+struct spoolss_GetJob {
+	IN	spoolss_handle_t handle;
+	IN 	DWORD 	JobId;
+	IN	DWORD 	level;
+		SIZE_IS(BufCount)
+  	INOUT		BYTE *pJob;
+	IN	DWORD BufCount;
+	OUT	DWORD needed;
 	OUT	DWORD status;
 };
 
-
-OPERATION(SPOOLSS_OPNUM_EnumMonitors)
-struct spoolss_EnumMonitors {
-	IN	DWORD dontcare;
+OPERATION(SPOOLSS_OPNUM_AddJob)
+struct spoolss_AddJob {
+	IN	spoolss_handle_t handle;
+	IN 	DWORD 	level;
+  	IN	DWORD   Buf2;
+	IN	DWORD 	BufCount;
+		SIZE_IS(BufCount)
+  	OUT		BYTE *pAddJob;
+	OUT	DWORD needed;
 	OUT	DWORD status;
 };
 
-
-OPERATION(SPOOLSS_OPNUM_AddPort)
-struct spoolss_AddPort {
-	IN	DWORD dontcare;
+OPERATION(SPOOLSS_OPNUM_ClosePrinter)
+struct spoolss_ClosePrinter {
+	IN	spoolss_handle_t handle;
+	OUT	spoolss_handle_t result_handle;
 	OUT	DWORD status;
 };
 
-
-OPERATION(SPOOLSS_OPNUM_ConfigurePort)
-struct spoolss_ConfigurePort {
-	IN	DWORD dontcare;
+OPERATION(SPOOLSS_OPNUM_EndDocPrinter)
+struct spoolss_EndDocPrinter {
+	IN	spoolss_handle_t handle;
 	OUT	DWORD status;
 };
 
-
-OPERATION(SPOOLSS_OPNUM_DeletePort)
-struct spoolss_DeletePort {
-	IN	DWORD dontcare;
+OPERATION(SPOOLSS_OPNUM_EnumForms)
+struct spoolss_EnumForms {
+	IN	spoolss_handle_t handle;
+	IN 	DWORD 	level;
+	IN	DWORD 	BufCount;
+		SIZE_IS(BufCount)
+  	INOUT		BYTE *pEnumForms;
+	OUT	DWORD needed;
+	OUT	DWORD pcRet;
 	OUT	DWORD status;
 };
 
-
-OPERATION(SPOOLSS_OPNUM_CreatePrinterIc)
-struct spoolss_CreatePrinterIc {
+OPERATION(SPOOLSS_OPNUM_GetPrinterDriver2)
+struct spoolss_GetPrinterDriver2 {
 	IN	DWORD dontcare;
 	OUT	DWORD status;
 };
 
-
-OPERATION(SPOOLSS_OPNUM_PlayDescriptionPrinterIc)
-struct spoolss_PlayDescriptionPrinterIc {
-	IN	DWORD dontcare;
-	OUT	DWORD status;
-};
-
-
-OPERATION(SPOOLSS_OPNUM_DeletePrinterIc)
-struct spoolss_DeletePrinterIc {
-	IN	DWORD dontcare;
-	OUT	DWORD status;
-};
-
-
-OPERATION(SPOOLSS_OPNUM_AddPrinterConnection)
-struct spoolss_AddPrinterConnection {
-	IN	DWORD dontcare;
-	OUT	DWORD status;
-};
-
-
-OPERATION(SPOOLSS_OPNUM_DeletePrinterConnection)
-struct spoolss_DeletePrinterConnection {
-	IN	DWORD dontcare;
-	OUT	DWORD status;
-};
-
-
-OPERATION(SPOOLSS_OPNUM_PrinterMessageBox)
-struct spoolss_PrinterMessageBox {
-	IN	DWORD dontcare;
-	OUT	DWORD status;
-};
-
-
-OPERATION(SPOOLSS_OPNUM_AddMonitor)
-struct spoolss_AddMonitor {
-	IN	DWORD dontcare;
-	OUT	DWORD status;
-};
-
-
-OPERATION(SPOOLSS_OPNUM_DeleteMonitor)
-struct spoolss_DeleteMonitor {
+OPERATION(SPOOLSS_OPNUM_FCPN)
+struct spoolss_FCPN {
 	IN	DWORD dontcare;
 	OUT	DWORD status;
 };
 
-
-OPERATION(SPOOLSS_OPNUM_DeletePrintProcessor)
-struct spoolss_DeletePrintProcessor {
-	IN	DWORD dontcare;
-	OUT	DWORD status;
-};
-
-
-OPERATION(SPOOLSS_OPNUM_AddPrintProvider)
-struct spoolss_AddPrintProvider {
-	IN	DWORD dontcare;
-	OUT	DWORD status;
-};
-
-
-OPERATION(SPOOLSS_OPNUM_DeletePrintProvider)
-struct spoolss_DeletePrintProvider {
-	IN	DWORD dontcare;
-	OUT	DWORD status;
-};
-
-
-OPERATION(SPOOLSS_OPNUM_ResetPrinter)
-struct spoolss_ResetPrinter {
-	IN	DWORD dontcare;
-	OUT	DWORD status;
-};
-
-
-OPERATION(SPOOLSS_OPNUM_FindFirstChangeNotify)
-struct spoolss_FindFirstChangeNotify {
-	IN	DWORD dontcare;
-	OUT	DWORD status;
-};
-
-
-OPERATION(SPOOLSS_OPNUM_FindNextChangeNotify)
-struct spoolss_FindNextChangeNotify {
-	IN	DWORD dontcare;
-	OUT	DWORD status;
-};
-
-
-OPERATION(SPOOLSS_OPNUM_RouterFindFirstNotify)
-struct spoolss_RouterFindFirstNotify {
-	IN	DWORD dontcare;
-	OUT	DWORD status;
-};
-
-
 OPERATION(SPOOLSS_OPNUM_ReplyOpenPrinter)
 struct spoolss_ReplyOpenPrinter {
 	IN	DWORD dontcare;
 	OUT	DWORD status;
 };
 
-
-OPERATION(SPOOLSS_OPNUM_RouterReplyPrinter)
-struct spoolss_RouterReplyPrinter {
-	IN	DWORD dontcare;
-	OUT	DWORD status;
-};
-
-
 OPERATION(SPOOLSS_OPNUM_ReplyClosePrinter)
 struct spoolss_ReplyClosePrinter {
 	IN	DWORD dontcare;
@@ -336,146 +607,127 @@
 };
 
 
-OPERATION(SPOOLSS_OPNUM_AddPortEx)
-struct spoolss_AddPortEx {
-	IN	DWORD dontcare;
+OPERATION(SPOOLSS_OPNUM_RFFPCNEX)
+struct spoolss_RFFPCNEX {
+	IN	spoolss_handle_t handle;
 	OUT	DWORD status;
 };
 
+struct spoolss_infores {
+	DWORD entriesread;
+	struct spoolss_RPC_V2_NOTIFY_INFO *pinfo;
+};
 
-OPERATION(SPOOLSS_OPNUM_RemoteFindFirstChangeNotify)
-struct spoolss_RemoteFindFirstChangeNotify {
-	IN	DWORD dontcare;
+OPERATION(SPOOLSS_OPNUM_RFNPCNEX)
+struct spoolss_RFNPCNEX {
+	IN	spoolss_handle_t handle;
+	IN 	DWORD color;
+	IN	struct spoolss_RPC_V2_NOTIFY_OPTIONS *poptions;
+	OUT	struct spoolss_infores *ppinfo;
 	OUT	DWORD status;
 };
 
-
-OPERATION(SPOOLSS_OPNUM_SpoolerInitialize)
-struct spoolss_SpoolerInitialize {
+OPERATION(SPOOLSS_OPNUM_RRPCN)
+struct spoolss_RRPCN {
 	IN	DWORD dontcare;
 	OUT	DWORD status;
 };
 
+OPERATION(SPOOLSS_OPNUM_OpenPrinterEx)
+struct spoolss_OpenPrinterEx {
+	IN	LPTSTR printer_name;
+	OUT	spoolss_handle_t handle;
+	OUT	DWORD status;
+};
 
-OPERATION(SPOOLSS_OPNUM_ResetPrinterEx)
-struct spoolss_ResetPrinterEx {
+OPERATION(SPOOLSS_OPNUM_EnumPrinterData)
+struct spoolss_EnumPrinterData {
 	IN	DWORD dontcare;
 	OUT	DWORD status;
 };
 
-
-OPERATION(SPOOLSS_OPNUM_RouterRefreshChangeNotify)
-struct spoolss_RouterRefreshChangeNotify {
+OPERATION(SPOOLSS_OPNUM_EnumPrinterDataEx)
+struct spoolss_EnumPrinterDataEx {
 	IN	DWORD dontcare;
 	OUT	DWORD status;
 };
 
-
-OPERATION(SPOOLSS_OPNUM_OpenPrinter2)
-struct spoolss_OpenPrinter2 {
+OPERATION(SPOOLSS_OPNUM_EnumPrinterKey)
+struct spoolss_EnumPrinterKey {
 	IN	DWORD dontcare;
-	OUT	spoolss_handle_t handle;
 	OUT	DWORD status;
 };
 
-
 /*
  ***********************************************************************
  * The spoolss interface definition.
  ***********************************************************************
  */
+
 INTERFACE(0)
 union spoolss_interface {
  	CASE(SPOOLSS_OPNUM_OpenPrinter)
-		struct spoolss_OpenPrinter		OpenPrinter;
- 	CASE(SPOOLSS_OPNUM_GetJob)
-		struct spoolss_GetJob			GetJob;
+		struct spoolss_OpenPrinter OpenPrinter;
+
 	CASE(SPOOLSS_OPNUM_DeletePrinter)
-		struct spoolss_DeletePrinter		DeletePrinter;
-	CASE(SPOOLSS_OPNUM_GetPrinterDriver)
-		struct spoolss_GetPrinterDriver		GetPrinterDriver;
-	CASE(SPOOLSS_OPNUM_DeletePrinterDriver)
-		struct spoolss_DeletePrinterDriver	DeletePrinterDriver;
-	CASE(SPOOLSS_OPNUM_AddPrintProcessor)
-		struct spoolss_AddPrintProcessor	AddPrintProcessor;
-	CASE(SPOOLSS_OPNUM_GetPrintProcessorDirectory)
-		struct spoolss_GetPrintProcessorDirectory
-						GetPrintProcessorDirectory;
+		struct spoolss_DeletePrinter DeletePrinter;
+
+	CASE(SPOOLSS_OPNUM_GetPrinter)
+		struct spoolss_GetPrinter GetPrinter;
+
+	CASE(SPOOLSS_OPNUM_GetPrinterData)
+		struct spoolss_GetPrinterData GetPrinterData;
+	
 	CASE(SPOOLSS_OPNUM_AbortPrinter)
-		struct spoolss_AbortPrinter		AbortPrinter;
-	CASE(SPOOLSS_OPNUM_ReadPrinter)
-		struct spoolss_ReadPrinter		ReadPrinter;
-	CASE(SPOOLSS_OPNUM_WaitForPrinterChange)
-		struct spoolss_WaitForPrinterChange	WaitForPrinterChange;
-	CASE(SPOOLSS_OPNUM_AddForm)
-		struct spoolss_AddForm			AddForm;
-	CASE(SPOOLSS_OPNUM_DeleteForm)
-		struct spoolss_DeleteForm		DeleteForm;
-	CASE(SPOOLSS_OPNUM_GetForm)
-		struct spoolss_GetForm			GetForm;
-	CASE(SPOOLSS_OPNUM_SetForm)
-		struct spoolss_SetForm			SetForm;
-	CASE(SPOOLSS_OPNUM_EnumMonitors)
-		struct spoolss_EnumMonitors		EnumMonitors;
-	CASE(SPOOLSS_OPNUM_AddPort)
-		struct spoolss_AddPort			AddPort;
-	CASE(SPOOLSS_OPNUM_ConfigurePort)
-		struct spoolss_ConfigurePort		ConfigurePort;
-	CASE(SPOOLSS_OPNUM_DeletePort)
-		struct spoolss_DeletePort		DeletePort;
-	CASE(SPOOLSS_OPNUM_CreatePrinterIc)
-		struct spoolss_CreatePrinterIc		CreatePrinterIc;
-	CASE(SPOOLSS_OPNUM_PlayDescriptionPrinterIc)
-		struct spoolss_PlayDescriptionPrinterIc
-						PlayDescriptionPrinterIc;
-	CASE(SPOOLSS_OPNUM_DeletePrinterIc)
-		struct spoolss_DeletePrinterIc		DeletePrinterIc;
-	CASE(SPOOLSS_OPNUM_AddPrinterConnection)
-		struct spoolss_AddPrinterConnection	AddPrinterConnection;
-	CASE(SPOOLSS_OPNUM_DeletePrinterConnection)
-		struct spoolss_DeletePrinterConnection	DeletePrinterConnection;
-	CASE(SPOOLSS_OPNUM_PrinterMessageBox)
-		struct spoolss_PrinterMessageBox	PrinterMessageBox;
-	CASE(SPOOLSS_OPNUM_AddMonitor)
-		struct spoolss_AddMonitor		AddMonitor;
-	CASE(SPOOLSS_OPNUM_DeleteMonitor)
-		struct spoolss_DeleteMonitor		DeleteMonitor;
-	CASE(SPOOLSS_OPNUM_DeletePrintProcessor)
-		struct spoolss_DeletePrintProcessor	DeletePrintProcessor;
-	CASE(SPOOLSS_OPNUM_AddPrintProvider)
-		struct spoolss_AddPrintProvider		AddPrintProvider;
-	CASE(SPOOLSS_OPNUM_DeletePrintProvider)
-		struct spoolss_DeletePrintProvider	DeletePrintProvider;
+		struct spoolss_AbortPrinter AbortPrinter;
+	
+	CASE(SPOOLSS_OPNUM_StartDocPrinter)
+		struct spoolss_StartDocPrinter StartDocPrinter;
+	
+	CASE(SPOOLSS_OPNUM_EndDocPrinter)
+		struct spoolss_EndDocPrinter EndDocPrinter;
+	
+	CASE(SPOOLSS_OPNUM_CreatePrinterIC)
+		struct spoolss_CreatePrinterIC CreatePrinterIC;
+	
 	CASE(SPOOLSS_OPNUM_ResetPrinter)
-		struct spoolss_ResetPrinter		ResetPrinter;
-	CASE(SPOOLSS_OPNUM_FindFirstChangeNotify)
-		struct spoolss_FindFirstChangeNotify	FindFirstChangeNotify;
-	CASE(SPOOLSS_OPNUM_FindNextChangeNotify)
-		struct spoolss_FindNextChangeNotify	FindNextChangeNotify;
-	CASE(SPOOLSS_OPNUM_RouterFindFirstNotify)
-		struct spoolss_RouterFindFirstNotify	RouterFindFirstNotify;
-	CASE(SPOOLSS_OPNUM_ReplyOpenPrinter)
-		struct spoolss_ReplyOpenPrinter		ReplyOpenPrinter;
-	CASE(SPOOLSS_OPNUM_RouterReplyPrinter)
-		struct spoolss_RouterReplyPrinter	RouterReplyPrinter;
-	CASE(SPOOLSS_OPNUM_ReplyClosePrinter)
-		struct spoolss_ReplyClosePrinter	ReplyClosePrinter;
-	CASE(SPOOLSS_OPNUM_AddPortEx)
-		struct spoolss_AddPortEx		AddPortEx;
-	CASE(SPOOLSS_OPNUM_RemoteFindFirstChangeNotify)
-		struct spoolss_RemoteFindFirstChangeNotify
-						RemoteFindFirstChangeNotify;
-	CASE(SPOOLSS_OPNUM_SpoolerInitialize)
-		struct spoolss_SpoolerInitialize	SpoolerInitialize;
-	CASE(SPOOLSS_OPNUM_ResetPrinterEx)
-		struct spoolss_ResetPrinterEx		ResetPrinterEx;
-	CASE(SPOOLSS_OPNUM_RouterRefreshChangeNotify)
-		struct spoolss_RouterRefreshChangeNotify
-						RouterRefreshChangeNotify;
-	CASE(SPOOLSS_OPNUM_OpenPrinter2)
-		struct spoolss_OpenPrinter2		OpenPrinter2;
+		struct spoolss_ResetPrinter ResetPrinter;
+	
+	CASE(SPOOLSS_OPNUM_WritePrinter)
+		struct spoolss_WritePrinter WritePrinter;
+	
+	CASE(SPOOLSS_OPNUM_StartPagePrinter)
+		struct spoolss_StartPagePrinter StartPagePrinter;
+	
+	CASE(SPOOLSS_OPNUM_EndPagePrinter)
+		struct spoolss_EndPagePrinter EndPagePrinter;
+	
+	CASE(SPOOLSS_OPNUM_ClosePrinter)
+		struct spoolss_ClosePrinter ClosePrinter;
+
+	CASE(SPOOLSS_OPNUM_OpenPrinterEx)
+		struct spoolss_OpenPrinterEx OpenPrinterEx;
+	
+	CASE(SPOOLSS_OPNUM_AddJob)
+		struct spoolss_AddJob AddJob;
+
+	CASE(SPOOLSS_OPNUM_GetJob)
+		struct spoolss_GetJob GetJob;
+
+	CASE(SPOOLSS_OPNUM_ScheduleJob)
+		struct spoolss_ScheduleJob ScheduleJob;
+
+	CASE(SPOOLSS_OPNUM_EnumForms)
+		struct spoolss_EnumForms EnumForms;
+
+	CASE(SPOOLSS_OPNUM_EnumJobs)
+		struct spoolss_EnumJobs EnumJobs;
+	
+	CASE(SPOOLSS_OPNUM_RFNPCNEX)
+		struct spoolss_RFNPCNEX RFNPCNEX;
+
 };
 typedef union spoolss_interface	spoolss_interface_t;
 EXTERNTYPEINFO(spoolss_interface)
 
-#endif /* _MLSVC_SPOOLSS_NDL_ */
+#endif /* _SPOOLSS_NDL_ */
--- a/usr/src/uts/common/smbsrv/smb.h	Thu Jul 22 12:31:36 2010 -0700
+++ b/usr/src/uts/common/smbsrv/smb.h	Thu Jul 22 14:53:56 2010 -0700
@@ -442,6 +442,7 @@
 #define	SMB_CSC_CACHE_NONE		0x000C
 
 #define	SHI1005_FLAGS_ACCESS_BASED_DIRECTORY_ENUM	0x0800
+#define	SHI1005_FLAGS_ALLOW_NAMESPACE_CACHING		0x0400
 
 /*
  * The subcommand codes, placed in SETUP[0], for named pipe operations are:
--- a/usr/src/uts/common/smbsrv/smb_dfs.h	Thu Jul 22 12:31:36 2010 -0700
+++ b/usr/src/uts/common/smbsrv/smb_dfs.h	Thu Jul 22 14:53:56 2010 -0700
@@ -19,8 +19,7 @@
  * CDDL HEADER END
  */
 /*
- * Copyright 2010 Sun Microsystems, Inc.  All rights reserved.
- * Use is subject to license terms.
+ * Copyright (c) 2010, Oracle and/or its affiliates. All rights reserved.
  */
 
 #ifndef _SMB_DFS_H
@@ -109,6 +108,8 @@
 	DfsGlobalLowPriorityClass	= 4
 } dfs_target_pclass_t;
 
+#define	DFS_PRIORITY_RANK_MAX		0x001F
+
 #define	DFS_PROPERTY_FLAG_INSITE_REFERRALS	0x00000001
 #define	DFS_PROPERTY_FLAG_ROOT_SCALABILITY	0x00000002
 #define	DFS_PROPERTY_FLAG_SITE_COSTING		0x00000004
@@ -171,10 +172,12 @@
 	char		i_guid[UUID_PRINTABLE_STRING_LENGTH];
 	uint32_t	i_state;
 	uint32_t	i_timeout;
+	uint32_t	i_propflag_mask;
 	uint32_t	i_propflags;
 	uint32_t	i_type;
 	uint32_t	i_ntargets;
 	dfs_target_t	*i_targets;
+	uint32_t	i_flavor;
 } dfs_info_t;
 
 #ifdef __cplusplus
--- a/usr/src/uts/common/smbsrv/smb_ioctl.h	Thu Jul 22 12:31:36 2010 -0700
+++ b/usr/src/uts/common/smbsrv/smb_ioctl.h	Thu Jul 22 14:53:56 2010 -0700
@@ -52,6 +52,8 @@
 #define	SMB_IOC_SESSION_CLOSE	_IOW(SMB_IOC_BASE, 13, int)
 #define	SMB_IOC_STOP		_IOW(SMB_IOC_BASE, 14, int)
 #define	SMB_IOC_EVENT		_IOW(SMB_IOC_BASE, 15, int)
+#define	SMB_IOC_SHAREINFO	_IOW(SMB_IOC_BASE, 16, int)
+#define	SMB_IOC_SPOOLDOC	_IOW(SMB_IOC_BASE, 17, int)
 
 typedef struct smb_ioc_header {
 	uint32_t	version;
@@ -60,6 +62,14 @@
 	int		cmd;
 } smb_ioc_header_t;
 
+typedef	struct smb_ioc_spooldoc {
+	smb_ioc_header_t hdr;
+	smb_inaddr_t	ipaddr;
+	uint32_t	spool_num;
+	char		username[MAXNAMELEN];
+	char		path[MAXPATHLEN];
+} smb_ioc_spooldoc_t;
+
 typedef	struct {
 	smb_ioc_header_t hdr;
 	int32_t 	offset;
@@ -71,6 +81,12 @@
 	char		shr[1];
 } smb_ioc_share_t;
 
+typedef struct smb_ioc_shareinfo {
+	smb_ioc_header_t hdr;
+	char		shrname[MAXNAMELEN];
+	uint32_t	shortnames;
+} smb_ioc_shareinfo_t;
+
 typedef	struct smb_ioc_listen {
 	smb_ioc_header_t hdr;
 	int		error;
@@ -150,6 +166,7 @@
 	int32_t		sync_enable;
 	int32_t		secmode;
 	int32_t		ipv6_enable;
+	int32_t		print_enable;
 	uint32_t	exec_flags;
 	smb_version_t	version;
 	char		nbdomain[NETBIOS_NAME_SZ];
@@ -170,6 +187,8 @@
 	smb_ioc_session_t	ioc_session;
 	smb_ioc_fileid_t	ioc_fileid;
 	smb_ioc_share_t		ioc_share;
+	smb_ioc_shareinfo_t	ioc_shareinfo;
+	smb_ioc_spooldoc_t	ioc_spooldoc;
 } smb_ioc_t;
 
 uint32_t smb_crc_gen(uint8_t *, size_t);
--- a/usr/src/uts/common/smbsrv/smb_kproto.h	Thu Jul 22 12:31:36 2010 -0700
+++ b/usr/src/uts/common/smbsrv/smb_kproto.h	Thu Jul 22 14:53:56 2010 -0700
@@ -54,9 +54,20 @@
 extern	int smb_maxbufsize;
 extern	int smb_flush_required;
 extern	int smb_dirsymlink_enable;
+extern	int smb_oplock_levelII;
 extern	int smb_oplock_timeout;
+extern	int smb_oplock_min_timeout;
+extern	int smb_shortnames;
 extern	int smb_sign_debug;
+extern	int smb_raw_mode;
 extern	uint_t smb_audit_flags;
+extern	int smb_ssetup_threshold;
+extern	int smb_tcon_threshold;
+extern	int smb_opipe_threshold;
+extern	int smb_ssetup_timeout;
+extern	int smb_tcon_timeout;
+extern	int smb_opipe_timeout;
+extern	int smb_threshold_debug;
 
 int		fd_dealloc(int);
 
@@ -198,37 +209,27 @@
 
 void smb_process_file_notify_change_queue(smb_ofile_t *of);
 
-void smb_oplock_acquire(smb_node_t *, smb_ofile_t *, smb_arg_open_t *);
-boolean_t smb_oplock_break(smb_node_t *, smb_session_t *, boolean_t);
+/*
+ * oplock functions - node operations
+ */
+int smb_oplock_init(void);
+void smb_oplock_fini(void);
+void smb_oplock_acquire(smb_request_t *sr, smb_node_t *, smb_ofile_t *);
 void smb_oplock_release(smb_node_t *, smb_ofile_t *);
-boolean_t smb_oplock_conflict(smb_node_t *, smb_session_t *, smb_arg_open_t *);
-boolean_t smb_oplock_broadcast(smb_node_t *);
+int smb_oplock_break(smb_request_t *, smb_node_t *, uint32_t);
+void smb_oplock_break_levelII(smb_node_t *);
+void smb_oplock_ack(smb_node_t *, smb_ofile_t *, uint8_t);
+void smb_oplock_broadcast(smb_node_t *);
 
 /*
- * macros used in oplock processing
- *
- * SMB_ATTR_ONLY_OPEN: Checks to see if this is
- * an attribute-only open with no contravening
- * dispositions.  Such an open cannot effect an
- * oplock break.  However, a contravening disposition
- * of FILE_SUPERSEDE or FILE_OVERWRITE can allow
- * an oplock break.
+ * range lock functions - node operations
  */
-
-#define	SMB_ATTR_ONLY_OPEN(op)					\
-	((op) && (op)->desired_access &&			\
-	(((op)->desired_access & ~(FILE_READ_ATTRIBUTES |	\
-	FILE_WRITE_ATTRIBUTES | SYNCHRONIZE)) == 0) &&		\
-	((op)->create_disposition != FILE_SUPERSEDE) &&		\
-	((op)->create_disposition != FILE_OVERWRITE))		\
-
 uint32_t smb_lock_get_lock_count(smb_node_t *, smb_ofile_t *);
 uint32_t smb_unlock_range(smb_request_t *, smb_node_t *,
     uint64_t, uint64_t);
 uint32_t smb_lock_range(smb_request_t *, uint64_t, uint64_t, uint32_t,
     uint32_t locktype);
 void smb_lock_range_error(smb_request_t *, uint32_t);
-
 DWORD smb_range_check(smb_request_t *, smb_node_t *, uint64_t, uint64_t,
     boolean_t);
 
@@ -236,8 +237,8 @@
 int smb_unmangle(smb_node_t *, char *, char *, int, uint32_t);
 boolean_t smb_needs_mangled(const char *);
 boolean_t smb_maybe_mangled(char *);
+boolean_t smb_is_reserved_dos_name(const char *);
 boolean_t smb_is_invalid_filename(const char *);
-boolean_t smb_match_name(ino64_t, char *, char *);
 
 void smbsr_cleanup(smb_request_t *sr);
 
@@ -382,6 +383,12 @@
 void smb_server_reconnection_check(smb_server_t *, smb_session_t *);
 void smb_server_get_cfg(smb_server_t *, smb_kmod_cfg_t *);
 
+int smb_server_spooldoc(smb_ioc_spooldoc_t *);
+int smb_spool_add_doc(smb_kspooldoc_t *);
+int smb_spool_add_fid(uint16_t);
+boolean_t smb_spool_lookup_doc_byfid(uint16_t, smb_kspooldoc_t *);
+uint16_t smb_spool_get_fid();
+
 void smb_server_inc_nbt_sess(smb_server_t *);
 void smb_server_dec_nbt_sess(smb_server_t *);
 void smb_server_inc_tcp_sess(smb_server_t *);
@@ -398,10 +405,11 @@
 void smb_server_add_txb(smb_server_t *, int64_t);
 void smb_server_inc_req(smb_server_t *);
 
-smb_event_t *smb_event_create(void);
+smb_event_t *smb_event_create(int);
 void smb_event_destroy(smb_event_t *);
 uint32_t smb_event_txid(smb_event_t *);
 int smb_event_wait(smb_event_t *);
+void smb_event_notify(smb_server_t *, uint32_t);
 
 /*
  * SMB node functions (file smb_node.c)
@@ -426,11 +434,12 @@
 void smb_node_rdlock(smb_node_t *);
 void smb_node_wrlock(smb_node_t *);
 void smb_node_unlock(smb_node_t *);
-uint32_t smb_node_get_ofile_count(smb_node_t *);
 void smb_node_add_ofile(smb_node_t *, smb_ofile_t *);
 void smb_node_rem_ofile(smb_node_t *, smb_ofile_t *);
 void smb_node_inc_open_ofiles(smb_node_t *);
 void smb_node_dec_open_ofiles(smb_node_t *);
+void smb_node_inc_opening_count(smb_node_t *);
+void smb_node_dec_opening_count(smb_node_t *);
 boolean_t smb_node_is_file(smb_node_t *);
 boolean_t smb_node_is_dir(smb_node_t *);
 boolean_t smb_node_is_symlink(smb_node_t *);
@@ -442,6 +451,7 @@
 uint32_t smb_node_open_check(smb_node_t *, uint32_t, uint32_t);
 DWORD smb_node_rename_check(smb_node_t *);
 DWORD smb_node_delete_check(smb_node_t *);
+boolean_t smb_node_share_check(smb_node_t *);
 void smb_node_notify_change(smb_node_t *);
 void smb_node_notify_parents(smb_node_t *);
 int smb_node_getattr(smb_request_t *, smb_node_t *, smb_attr_t *);
@@ -526,10 +536,11 @@
 void smb_session_getclient(smb_session_t *, char *, size_t);
 boolean_t smb_session_isclient(smb_session_t *, const char *);
 void smb_session_correct_keep_alive_values(smb_session_list_t *, uint32_t);
-void smb_session_oplock_break(smb_session_t *, smb_ofile_t *);
+void smb_session_oplock_break(smb_session_t *, uint16_t, uint16_t, uint8_t);
 int smb_session_send(smb_session_t *, uint8_t type, mbuf_chain_t *);
 int smb_session_xprt_gethdr(smb_session_t *, smb_xprt_t *);
 boolean_t smb_session_oplocks_enable(smb_session_t *);
+boolean_t smb_session_levelII_oplocks(smb_session_t *);
 
 #define	SMB_SESSION_GET_ID(s)	((s)->s_kid)
 
@@ -550,6 +561,7 @@
 int smb_ofile_seek(smb_ofile_t *, ushort_t, int32_t, uint32_t *);
 boolean_t smb_ofile_hold(smb_ofile_t *);
 void smb_ofile_release(smb_ofile_t *);
+void smb_ofile_request_complete(smb_ofile_t *);
 void smb_ofile_close_all(smb_tree_t *);
 void smb_ofile_close_all_by_pid(smb_tree_t *, uint16_t);
 void smb_ofile_set_flags(smb_ofile_t *, uint32_t);
@@ -558,8 +570,8 @@
 uint32_t smb_ofile_open_check(smb_ofile_t *, uint32_t, uint32_t);
 uint32_t smb_ofile_rename_check(smb_ofile_t *);
 uint32_t smb_ofile_delete_check(smb_ofile_t *);
+boolean_t smb_ofile_share_check(smb_ofile_t *);
 cred_t *smb_ofile_getcred(smb_ofile_t *);
-void smb_ofile_set_oplock_granted(smb_ofile_t *);
 void smb_ofile_set_delete_on_close(smb_ofile_t *);
 void smb_ofile_set_write_time_pending(smb_ofile_t *);
 boolean_t smb_ofile_write_time_pending(smb_ofile_t *);
@@ -808,6 +820,7 @@
 void smb_kshare_fini(void);
 int smb_kshare_export_list(smb_ioc_share_t *);
 int smb_kshare_unexport_list(smb_ioc_share_t *);
+int smb_kshare_info(smb_ioc_shareinfo_t *);
 void smb_kshare_enum(smb_enumshare_info_t *);
 smb_kshare_t *smb_kshare_lookup(const char *);
 void smb_kshare_release(smb_kshare_t *);
@@ -824,6 +837,10 @@
 void smb_avl_iterinit(smb_avl_t *, smb_avl_cursor_t *);
 void *smb_avl_iterate(smb_avl_t *, smb_avl_cursor_t *);
 
+void smb_threshold_init(smb_cmd_threshold_t *, char *, int, int);
+void smb_threshold_fini(smb_cmd_threshold_t *);
+int smb_threshold_enter(smb_cmd_threshold_t *);
+void smb_threshold_exit(smb_cmd_threshold_t *, smb_server_t *);
 #ifdef	__cplusplus
 }
 #endif
--- a/usr/src/uts/common/smbsrv/smb_kstat.h	Thu Jul 22 12:31:36 2010 -0700
+++ b/usr/src/uts/common/smbsrv/smb_kstat.h	Thu Jul 22 14:53:56 2010 -0700
@@ -63,6 +63,7 @@
 
 typedef struct smb_kstat_req {
 	char		kr_name[KSTAT_STRLEN];
+	char		kr_pad[(~(KSTAT_STRLEN & 0x07) + 1) & 0x07];
 	uint64_t	kr_sum;
 	uint64_t	kr_txb;
 	uint64_t	kr_rxb;
--- a/usr/src/uts/common/smbsrv/smb_ktypes.h	Thu Jul 22 12:31:36 2010 -0700
+++ b/usr/src/uts/common/smbsrv/smb_ktypes.h	Thu Jul 22 14:53:56 2010 -0700
@@ -386,6 +386,7 @@
 	kmutex_t	ll_mutex;
 	list_t		ll_deleteq;
 	uint32_t	ll_deleteq_count;
+	boolean_t	ll_flushing;
 } smb_llist_t;
 
 typedef struct smb_slist {
@@ -531,43 +532,67 @@
 
 #define	MBC_ROOM_FOR(b, n) (((b)->chain_offset + (n)) <= (b)->max_bytes)
 
+#define	OPLOCK_MIN_TIMEOUT	(5 * 1000)
+#define	OPLOCK_STD_TIMEOUT	(30 * 1000)
+
 /*
- * ol_sess_id:
- *
- *	ID of the session holding the oplock (if an oplock was granted).
- *
- * ol_xthread:
- *
- *	Worker thread treating the command that was granted the oplock. Until
- *	that thread is done with that command and has submitted the response
- *	to the network stack, all the other threads will be suspended in
- *	smb_oplock_enter(). They will be awaken when the worker thread
- *	referenced in 'ol_xthread' calls smb_oplock_broadcast().
- *
- *	The purpose of this mechanism is to prevent another thread from
- *	triggering a oplock break before the response conveying the grant
- *	has been sent.
- *
- * ol_ofile
- *
- *	Open file that was granted the oplock.
- *
- * ol_waiters_count
- *
- *	Number of threads waiting for a call to smb_oplock_broadcast().
- *
- * ol_level
- *
- *	Level of the oplock granted.
+ * Oplock break flags:
+ * SMB_OPLOCK_BREAK_EXCLUSIVE - only break exclusive oplock
+ * (type SMB_OPLOCK_EXCLUSIVE or SMB_OPLOCK_BATCH)
+ * SMB_OPLOCK_BREAK_BATCH - only break exclusive BATCH oplock
+ * SMB_OPLOCK_BREAK_NOWAIT - do not wait for oplock break ack
  */
+#define	SMB_OPLOCK_NO_BREAK		0x00
+#define	SMB_OPLOCK_BREAK_TO_NONE	0x01
+#define	SMB_OPLOCK_BREAK_TO_LEVEL_II	0x02
+#define	SMB_OPLOCK_BREAK_EXCLUSIVE	0x04
+#define	SMB_OPLOCK_BREAK_BATCH		0x08
+#define	SMB_OPLOCK_BREAK_NOWAIT		0x10
+
+/*
+ * Oplocks levels are defined to match the levels in the SMB
+ * protocol (nt_create_andx / nt_transact_create) and should
+ * not be changed
+ */
+#define	SMB_OPLOCK_NONE		0
+#define	SMB_OPLOCK_EXCLUSIVE	1
+#define	SMB_OPLOCK_BATCH	2
+#define	SMB_OPLOCK_LEVEL_II	3
+
 typedef struct smb_oplock {
-	uint64_t		ol_sess_id;
+	kmutex_t		ol_mutex;
 	kcondvar_t		ol_cv;
 	kthread_t		*ol_xthread;
-	struct smb_ofile	*ol_ofile;
-	uint8_t			ol_level;
+	boolean_t		ol_fem;		/* fem monitor installed? */
+	uint8_t			ol_break;
+	uint32_t		ol_count;	/* number of grants */
+	list_t			ol_grants;	/* list of smb_oplock_grant_t */
 } smb_oplock_t;
 
+#define	SMB_OPLOCK_GRANT_MAGIC	0x4F4C4B47	/* OLKG */
+#define	SMB_OPLOCK_GRANT_VALID(p) \
+	ASSERT((p)->og_magic == SMB_OPLOCK_GRANT_MAGIC)
+typedef struct smb_oplock_grant {
+	uint32_t		og_magic;
+	list_node_t		og_lnd;
+	uint8_t			og_level;
+	uint16_t		og_fid;
+	uint16_t		og_tid;
+	uint16_t		og_uid;
+	struct smb_session	*og_session;
+	struct smb_ofile	*og_ofile;
+} smb_oplock_grant_t;
+
+#define	SMB_OPLOCK_BREAK_MAGIC	0x4F4C4B42	/* OLKB */
+#define	SMB_OPLOCK_BREAK_VALID(p) \
+	ASSERT((p)->ob_magic == SMB_OPLOCK_BREAK_MAGIC)
+typedef struct smb_oplock_break {
+	uint32_t	ob_magic;
+	list_node_t	ob_lnd;
+	struct smb_node	*ob_node;
+} smb_oplock_break_t;
+
+
 #define	SMB_VFS_MAGIC	0x534D4256	/* 'SMBV' */
 
 typedef struct smb_vfs {
@@ -587,7 +612,7 @@
  * Timestamps remain cached while there are open ofiles for the node.
  * This includes open ofiles for named streams.  t_open_ofiles is a
  * count of open ofiles on the node, including named streams' ofiles,
- * n_open_ofiles cannot be used as it doesn't include ofiles opened
+ * n_open_count cannot be used as it doesn't include ofiles opened
  * for the node's named streams.
  */
 typedef struct smb_times {
@@ -604,8 +629,6 @@
 
 typedef enum {
 	SMB_NODE_STATE_AVAILABLE = 0,
-	SMB_NODE_STATE_OPLOCK_GRANTED,
-	SMB_NODE_STATE_OPLOCK_BREAKING,
 	SMB_NODE_STATE_DESTROYING
 } smb_node_state_t;
 
@@ -627,6 +650,7 @@
 	uint32_t		n_hashkey;
 	smb_llist_t		*n_hash_bucket;
 	uint32_t		n_open_count;
+	uint32_t		n_opening_count;
 	smb_llist_t		n_ofile_list;
 	smb_llist_t		n_lock_list;
 	struct smb_ofile	*readonly_creator;
@@ -1012,8 +1036,8 @@
 #define	SMB_TREE_CASEINSENSITIVE	0x00000008
 #define	SMB_TREE_NO_CASESENSITIVE	0x00000010
 #define	SMB_TREE_NO_EXPORT		0x00000020
-#define	SMB_TREE_NO_OPLOCKS		0x00000040
-#define	SMB_TREE_NO_ATIME		0x00000080
+#define	SMB_TREE_OPLOCKS		0x00000040
+#define	SMB_TREE_SHORTNAMES		0x00000080
 #define	SMB_TREE_XVATTR			0x00000100
 #define	SMB_TREE_DIRENTFLAGS		0x00000200
 #define	SMB_TREE_ACLONCREATE		0x00000400
@@ -1093,6 +1117,10 @@
 	(((sr) && (sr)->tid_tree) ?                                     \
 	smb_tree_has_feature((sr)->tid_tree, SMB_TREE_DFSROOT) : 0)
 
+#define	SMB_TREE_SUPPORTS_SHORTNAMES(sr)				\
+	(((sr) && (sr)->tid_tree) ?					\
+	smb_tree_has_feature((sr)->tid_tree, SMB_TREE_SHORTNAMES) : 0)
+
 /*
  * SMB_TREE_CONTAINS_NODE is used to check that a node is in the same
  * file system as the tree.
@@ -1225,8 +1253,6 @@
 	int			f_mode;
 	cred_t			*f_cr;
 	pid_t			f_pid;
-	boolean_t		f_oplock_granted;
-	boolean_t		f_oplock_exit;
 	uint32_t		f_explicit_times;
 	char			f_quota_resume[SMB_SID_STRSZ];
 } smb_ofile_t;
@@ -1243,6 +1269,7 @@
 #define	SMB_ODIR_FLAG_EDIRENT		0x0008
 #define	SMB_ODIR_FLAG_CATIA		0x0010
 #define	SMB_ODIR_FLAG_ABE		0x0020
+#define	SMB_ODIR_FLAG_SHORTNAMES	0x0040
 
 typedef enum {
 	SMB_ODIR_STATE_OPEN = 0,
@@ -1412,10 +1439,6 @@
 	uint16_t	flags;
 } smb_arg_dirop_t;
 
-#define	OPLOCK_MIN_TIMEOUT	(5 * 1000)
-#define	OPLOCK_STD_TIMEOUT	(15 * 1000)
-#define	OPLOCK_RETRIES		2
-
 typedef struct {
 	uint32_t status;
 	uint16_t errcls;
@@ -1445,14 +1468,10 @@
 	smb_ofile_t	*dir;
 	/* This is only set by NTTransactCreate */
 	struct smb_sd	*sd;
-	uint8_t		op_oplock_level;
+	uint8_t		op_oplock_level;	/* requested/granted level */
+	boolean_t	op_oplock_levelII;	/* TRUE if levelII supported */
 } smb_arg_open_t;
 
-#define	SMB_OPLOCK_NONE		0
-#define	SMB_OPLOCK_EXCLUSIVE	1
-#define	SMB_OPLOCK_BATCH	2
-#define	SMB_OPLOCK_LEVEL_II	3
-
 /*
  * SMB Request State Machine
  * -------------------------
@@ -1792,6 +1811,27 @@
 	smb_session_list_t	ld_session_list;
 } smb_listener_daemon_t;
 
+#define	SMB_SSETUP_CMD			"authentication"
+#define	SMB_TCON_CMD			"share mapping"
+#define	SMB_OPIPE_CMD			"pipe open"
+#define	SMB_THRESHOLD_REPORT_THROTTLE	50
+typedef struct smb_cmd_threshold {
+	char			*ct_cmd;
+	kmutex_t		ct_mutex;
+	volatile uint32_t	ct_active_cnt;
+	volatile uint32_t	ct_blocked_cnt;
+	volatile uint32_t	ct_error_cnt;
+	uint32_t		ct_threshold;
+	struct smb_event	*ct_event;
+	uint32_t		ct_event_id;
+} smb_cmd_threshold_t;
+
+typedef struct {
+	kstat_named_t		ls_files;
+	kstat_named_t		ls_trees;
+	kstat_named_t		ls_users;
+} smb_server_legacy_kstat_t;
+
 typedef enum smb_server_state {
 	SMB_SERVER_STATE_CREATED = 0,
 	SMB_SERVER_STATE_CONFIGURED,
@@ -1801,6 +1841,14 @@
 	SMB_SERVER_STATE_SENTINEL
 } smb_server_state_t;
 
+typedef struct {
+	kcondvar_t		sp_cv;
+	kmutex_t		sp_mutex;
+	uint32_t 		sp_cnt;
+	smb_llist_t		sp_list;
+	smb_llist_t		sp_fidlist;
+} smb_spool_t;
+
 #define	SMB_SERVER_STATE_VALID(S)               \
     ASSERT(((S) == SMB_SERVER_STATE_CREATED) || \
 	    ((S) == SMB_SERVER_STATE_CONFIGURED) || \
@@ -1857,24 +1905,47 @@
 	volatile uint64_t	sv_rxb;
 	volatile uint64_t	sv_nreq;
 	smb_srqueue_t		sv_srqueue;
+	smb_spool_t		sp_info;
+	smb_cmd_threshold_t	sv_ssetup_ct;
+	smb_cmd_threshold_t	sv_tcon_ct;
+	smb_cmd_threshold_t	sv_opipe_ct;
+	kstat_t			*sv_legacy_ksp;
+	kmutex_t		sv_legacy_ksmtx;
 } smb_server_t;
 
 #define	SMB_EVENT_MAGIC		0x45564E54	/* EVNT */
+#define	SMB_EVENT_TIMEOUT	45		/* seconds */
 #define	SMB_EVENT_VALID(e)	\
     ASSERT(((e) != NULL) && ((e)->se_magic == SMB_EVENT_MAGIC))
-
 typedef struct smb_event {
 	uint32_t		se_magic;
 	list_node_t		se_lnd;
 	kmutex_t		se_mutex;
 	kcondvar_t		se_cv;
-	struct smb_server	*se_server;
+	smb_server_t		*se_server;
 	uint32_t		se_txid;
 	boolean_t		se_notified;
 	int			se_waittime;
+	int			se_timeout;
 	int			se_errno;
 } smb_event_t;
 
+typedef struct smb_kspooldoc {
+	uint32_t	sd_magic;
+	list_node_t	sd_lnd;
+	smb_inaddr_t	sd_ipaddr;
+	uint32_t	sd_spool_num;
+	uint16_t	sd_fid;
+	char		sd_username[MAXNAMELEN];
+	char		sd_path[MAXPATHLEN];
+} smb_kspooldoc_t;
+
+typedef struct smb_spoolfid {
+	uint32_t	sf_magic;
+	list_node_t	sf_lnd;
+	uint16_t	sf_fid;
+} smb_spoolfid_t;
+
 #define	SMB_INFO_NETBIOS_SESSION_SVC_RUNNING	0x0001
 #define	SMB_INFO_NETBIOS_SESSION_SVC_FAILED	0x0002
 #define	SMB_INFO_USER_LEVEL_SECURITY		0x40000000
--- a/usr/src/uts/common/smbsrv/smb_share.h	Thu Jul 22 12:31:36 2010 -0700
+++ b/usr/src/uts/common/smbsrv/smb_share.h	Thu Jul 22 14:53:56 2010 -0700
@@ -173,6 +173,8 @@
 #define	SMB_SHRF_PERM		0x20000000
 #define	SMB_SHRF_AUTOHOME	0x40000000
 
+#define	SMB_SHARE_PRINT		"print$"
+#define	SMB_SHARE_PRINT_LEN	6
 /*
  * refcnt is currently only used for autohome.  autohome needs a refcnt
  * because a user can map his autohome share from more than one client
--- a/usr/src/uts/common/smbsrv/smb_vops.h	Thu Jul 22 12:31:36 2010 -0700
+++ b/usr/src/uts/common/smbsrv/smb_vops.h	Thu Jul 22 14:53:56 2010 -0700
@@ -19,8 +19,7 @@
  * CDDL HEADER END
  */
 /*
- * Copyright 2010 Sun Microsystems, Inc.  All rights reserved.
- * Use is subject to license terms.
+ * Copyright (c) 2007, 2010, Oracle and/or its affiliates. All rights reserved.
  */
 
 #ifndef _SMBSRV_SMB_VOPS_H
@@ -148,6 +147,8 @@
 
 int smb_vop_frlock(vnode_t *, cred_t *, int, flock64_t *);
 
+int smb_vop_other_opens(vnode_t *, int);
+
 void smb_vop_catia_v4tov5(char *, char *, int);
 char *smb_vop_catia_v5tov4(char *, char *, int);
 
--- a/usr/src/uts/common/smbsrv/smbinfo.h	Thu Jul 22 12:31:36 2010 -0700
+++ b/usr/src/uts/common/smbsrv/smbinfo.h	Thu Jul 22 14:53:56 2010 -0700
@@ -118,6 +118,7 @@
 	int32_t skc_sync_enable;
 	int32_t skc_secmode;
 	int32_t skc_ipv6_enable;
+	int32_t skc_print_enable;
 	uint32_t skc_execflags;
 	smb_version_t skc_version;
 	char skc_nbdomain[NETBIOS_NAME_SZ];