xref: /onnv-gate/usr/src/uts/common/fs/smbsrv/smb_kutil.c (revision 12065:0e89d02a32ea)
111963SAfshin.Ardakani@Sun.COM /*
211963SAfshin.Ardakani@Sun.COM  * CDDL HEADER START
311963SAfshin.Ardakani@Sun.COM  *
411963SAfshin.Ardakani@Sun.COM  * The contents of this file are subject to the terms of the
511963SAfshin.Ardakani@Sun.COM  * Common Development and Distribution License (the "License").
611963SAfshin.Ardakani@Sun.COM  * You may not use this file except in compliance with the License.
711963SAfshin.Ardakani@Sun.COM  *
811963SAfshin.Ardakani@Sun.COM  * You can obtain a copy of the license at usr/src/OPENSOLARIS.LICENSE
911963SAfshin.Ardakani@Sun.COM  * or http://www.opensolaris.org/os/licensing.
1011963SAfshin.Ardakani@Sun.COM  * See the License for the specific language governing permissions
1111963SAfshin.Ardakani@Sun.COM  * and limitations under the License.
1211963SAfshin.Ardakani@Sun.COM  *
1311963SAfshin.Ardakani@Sun.COM  * When distributing Covered Code, include this CDDL HEADER in each
1411963SAfshin.Ardakani@Sun.COM  * file and include the License file at usr/src/OPENSOLARIS.LICENSE.
1511963SAfshin.Ardakani@Sun.COM  * If applicable, add the following below this CDDL HEADER, with the
1611963SAfshin.Ardakani@Sun.COM  * fields enclosed by brackets "[]" replaced with your own identifying
1711963SAfshin.Ardakani@Sun.COM  * information: Portions Copyright [yyyy] [name of copyright owner]
1811963SAfshin.Ardakani@Sun.COM  *
1911963SAfshin.Ardakani@Sun.COM  * CDDL HEADER END
2011963SAfshin.Ardakani@Sun.COM  */
2111963SAfshin.Ardakani@Sun.COM /*
22*12065SKeyur.Desai@Sun.COM  * Copyright (c) 2007, 2010, Oracle and/or its affiliates. All rights reserved.
2311963SAfshin.Ardakani@Sun.COM  */
2411963SAfshin.Ardakani@Sun.COM 
2511963SAfshin.Ardakani@Sun.COM #include <sys/param.h>
2611963SAfshin.Ardakani@Sun.COM #include <sys/types.h>
2711963SAfshin.Ardakani@Sun.COM #include <sys/tzfile.h>
2811963SAfshin.Ardakani@Sun.COM #include <sys/atomic.h>
2911963SAfshin.Ardakani@Sun.COM #include <sys/kidmap.h>
3011963SAfshin.Ardakani@Sun.COM #include <sys/time.h>
3111963SAfshin.Ardakani@Sun.COM #include <sys/cpuvar.h>
3211963SAfshin.Ardakani@Sun.COM #include <smbsrv/smb_kproto.h>
3311963SAfshin.Ardakani@Sun.COM #include <smbsrv/smb_fsops.h>
3411963SAfshin.Ardakani@Sun.COM #include <smbsrv/smbinfo.h>
3511963SAfshin.Ardakani@Sun.COM #include <smbsrv/smb_xdr.h>
3611963SAfshin.Ardakani@Sun.COM #include <smbsrv/smb_vops.h>
3711963SAfshin.Ardakani@Sun.COM #include <smbsrv/smb_idmap.h>
3811963SAfshin.Ardakani@Sun.COM 
3911963SAfshin.Ardakani@Sun.COM #include <sys/sid.h>
4011963SAfshin.Ardakani@Sun.COM #include <sys/priv_names.h>
4111963SAfshin.Ardakani@Sun.COM 
4211963SAfshin.Ardakani@Sun.COM static kmem_cache_t	*smb_dtor_cache;
4311963SAfshin.Ardakani@Sun.COM static boolean_t	smb_llist_initialized = B_FALSE;
4411963SAfshin.Ardakani@Sun.COM 
4511963SAfshin.Ardakani@Sun.COM static boolean_t smb_thread_continue_timedwait_locked(smb_thread_t *, int);
4611963SAfshin.Ardakani@Sun.COM 
4711963SAfshin.Ardakani@Sun.COM time_t tzh_leapcnt = 0;
4811963SAfshin.Ardakani@Sun.COM 
4911963SAfshin.Ardakani@Sun.COM struct tm
5011963SAfshin.Ardakani@Sun.COM *smb_gmtime_r(time_t *clock, struct tm *result);
5111963SAfshin.Ardakani@Sun.COM 
5211963SAfshin.Ardakani@Sun.COM time_t
5311963SAfshin.Ardakani@Sun.COM smb_timegm(struct tm *tm);
5411963SAfshin.Ardakani@Sun.COM 
5511963SAfshin.Ardakani@Sun.COM struct	tm {
5611963SAfshin.Ardakani@Sun.COM 	int	tm_sec;
5711963SAfshin.Ardakani@Sun.COM 	int	tm_min;
5811963SAfshin.Ardakani@Sun.COM 	int	tm_hour;
5911963SAfshin.Ardakani@Sun.COM 	int	tm_mday;
6011963SAfshin.Ardakani@Sun.COM 	int	tm_mon;
6111963SAfshin.Ardakani@Sun.COM 	int	tm_year;
6211963SAfshin.Ardakani@Sun.COM 	int	tm_wday;
6311963SAfshin.Ardakani@Sun.COM 	int	tm_yday;
6411963SAfshin.Ardakani@Sun.COM 	int	tm_isdst;
6511963SAfshin.Ardakani@Sun.COM };
6611963SAfshin.Ardakani@Sun.COM 
6711963SAfshin.Ardakani@Sun.COM static int days_in_month[] = {
6811963SAfshin.Ardakani@Sun.COM 	31, 28, 31, 30, 31, 30, 31, 31, 30, 31, 30, 31
6911963SAfshin.Ardakani@Sun.COM };
7011963SAfshin.Ardakani@Sun.COM 
7111963SAfshin.Ardakani@Sun.COM int
7211963SAfshin.Ardakani@Sun.COM smb_ascii_or_unicode_strlen(struct smb_request *sr, char *str)
7311963SAfshin.Ardakani@Sun.COM {
7411963SAfshin.Ardakani@Sun.COM 	if (sr->smb_flg2 & SMB_FLAGS2_UNICODE)
7511963SAfshin.Ardakani@Sun.COM 		return (smb_wcequiv_strlen(str));
7611963SAfshin.Ardakani@Sun.COM 	return (strlen(str));
7711963SAfshin.Ardakani@Sun.COM }
7811963SAfshin.Ardakani@Sun.COM 
7911963SAfshin.Ardakani@Sun.COM int
8011963SAfshin.Ardakani@Sun.COM smb_ascii_or_unicode_strlen_null(struct smb_request *sr, char *str)
8111963SAfshin.Ardakani@Sun.COM {
8211963SAfshin.Ardakani@Sun.COM 	if (sr->smb_flg2 & SMB_FLAGS2_UNICODE)
8311963SAfshin.Ardakani@Sun.COM 		return (smb_wcequiv_strlen(str) + 2);
8411963SAfshin.Ardakani@Sun.COM 	return (strlen(str) + 1);
8511963SAfshin.Ardakani@Sun.COM }
8611963SAfshin.Ardakani@Sun.COM 
8711963SAfshin.Ardakani@Sun.COM int
8811963SAfshin.Ardakani@Sun.COM smb_ascii_or_unicode_null_len(struct smb_request *sr)
8911963SAfshin.Ardakani@Sun.COM {
9011963SAfshin.Ardakani@Sun.COM 	if (sr->smb_flg2 & SMB_FLAGS2_UNICODE)
9111963SAfshin.Ardakani@Sun.COM 		return (2);
9211963SAfshin.Ardakani@Sun.COM 	return (1);
9311963SAfshin.Ardakani@Sun.COM }
9411963SAfshin.Ardakani@Sun.COM 
9511963SAfshin.Ardakani@Sun.COM /*
9611963SAfshin.Ardakani@Sun.COM  * Return B_TRUE if pattern contains wildcards
9711963SAfshin.Ardakani@Sun.COM  */
9811963SAfshin.Ardakani@Sun.COM boolean_t
9911963SAfshin.Ardakani@Sun.COM smb_contains_wildcards(const char *pattern)
10011963SAfshin.Ardakani@Sun.COM {
10111963SAfshin.Ardakani@Sun.COM 	static const char *wildcards = "*?";
10211963SAfshin.Ardakani@Sun.COM 
10311963SAfshin.Ardakani@Sun.COM 	return (strpbrk(pattern, wildcards) != NULL);
10411963SAfshin.Ardakani@Sun.COM }
10511963SAfshin.Ardakani@Sun.COM 
10611963SAfshin.Ardakani@Sun.COM /*
10711963SAfshin.Ardakani@Sun.COM  * When converting wildcards a '.' in a name is treated as a base and
10811963SAfshin.Ardakani@Sun.COM  * extension separator even if the name is longer than 8.3.
10911963SAfshin.Ardakani@Sun.COM  *
11011963SAfshin.Ardakani@Sun.COM  * The '*' character matches an entire part of the name.  For example,
11111963SAfshin.Ardakani@Sun.COM  * "*.abc" matches any name with an extension of "abc".
11211963SAfshin.Ardakani@Sun.COM  *
11311963SAfshin.Ardakani@Sun.COM  * The '?' character matches a single character.
11411963SAfshin.Ardakani@Sun.COM  * If the base contains all ? (8 or more) then it is treated as *.
11511963SAfshin.Ardakani@Sun.COM  * If the extension contains all ? (3 or more) then it is treated as *.
11611963SAfshin.Ardakani@Sun.COM  *
11711963SAfshin.Ardakani@Sun.COM  * Clients convert ASCII wildcards to Unicode wildcards as follows:
11811963SAfshin.Ardakani@Sun.COM  *
11911963SAfshin.Ardakani@Sun.COM  *	? is converted to >
12011963SAfshin.Ardakani@Sun.COM  *	. is converted to " if it is followed by ? or *
12111963SAfshin.Ardakani@Sun.COM  *	* is converted to < if it is followed by .
12211963SAfshin.Ardakani@Sun.COM  *
12311963SAfshin.Ardakani@Sun.COM  * Note that clients convert "*." to '< and drop the '.' but "*.txt"
12411963SAfshin.Ardakani@Sun.COM  * is sent as "<.TXT", i.e.
12511963SAfshin.Ardakani@Sun.COM  *
12611963SAfshin.Ardakani@Sun.COM  * 	dir *.		->	dir <
12711963SAfshin.Ardakani@Sun.COM  * 	dir *.txt	->	dir <.TXT
12811963SAfshin.Ardakani@Sun.COM  *
12911963SAfshin.Ardakani@Sun.COM  * Since " and < are illegal in Windows file names, we always convert
13011963SAfshin.Ardakani@Sun.COM  * these Unicode wildcards without checking the following character.
13111963SAfshin.Ardakani@Sun.COM  */
13211963SAfshin.Ardakani@Sun.COM void
13311963SAfshin.Ardakani@Sun.COM smb_convert_wildcards(char *pattern)
13411963SAfshin.Ardakani@Sun.COM {
13511963SAfshin.Ardakani@Sun.COM 	static char *match_all[] = {
13611963SAfshin.Ardakani@Sun.COM 		"*.",
13711963SAfshin.Ardakani@Sun.COM 		"*.*"
13811963SAfshin.Ardakani@Sun.COM 	};
13911963SAfshin.Ardakani@Sun.COM 	char	*extension;
14011963SAfshin.Ardakani@Sun.COM 	char	*p;
14111963SAfshin.Ardakani@Sun.COM 	int	len;
14211963SAfshin.Ardakani@Sun.COM 	int	i;
14311963SAfshin.Ardakani@Sun.COM 
14411963SAfshin.Ardakani@Sun.COM 	/*
14511963SAfshin.Ardakani@Sun.COM 	 * Special case "<" for "dir *.", and fast-track for "*".
14611963SAfshin.Ardakani@Sun.COM 	 */
14711963SAfshin.Ardakani@Sun.COM 	if ((*pattern == '<') || (*pattern == '*')) {
14811963SAfshin.Ardakani@Sun.COM 		if (*(pattern + 1) == '\0') {
14911963SAfshin.Ardakani@Sun.COM 			*pattern = '*';
15011963SAfshin.Ardakani@Sun.COM 			return;
15111963SAfshin.Ardakani@Sun.COM 		}
15211963SAfshin.Ardakani@Sun.COM 	}
15311963SAfshin.Ardakani@Sun.COM 
15411963SAfshin.Ardakani@Sun.COM 	for (p = pattern; *p != '\0'; ++p) {
15511963SAfshin.Ardakani@Sun.COM 		switch (*p) {
15611963SAfshin.Ardakani@Sun.COM 		case '<':
15711963SAfshin.Ardakani@Sun.COM 			*p = '*';
15811963SAfshin.Ardakani@Sun.COM 			break;
15911963SAfshin.Ardakani@Sun.COM 		case '>':
16011963SAfshin.Ardakani@Sun.COM 			*p = '?';
16111963SAfshin.Ardakani@Sun.COM 			break;
16211963SAfshin.Ardakani@Sun.COM 		case '\"':
16311963SAfshin.Ardakani@Sun.COM 			*p = '.';
16411963SAfshin.Ardakani@Sun.COM 			break;
16511963SAfshin.Ardakani@Sun.COM 		default:
16611963SAfshin.Ardakani@Sun.COM 			break;
16711963SAfshin.Ardakani@Sun.COM 		}
16811963SAfshin.Ardakani@Sun.COM 	}
16911963SAfshin.Ardakani@Sun.COM 
17011963SAfshin.Ardakani@Sun.COM 	/*
17111963SAfshin.Ardakani@Sun.COM 	 * Replace "????????.ext" with "*.ext".
17211963SAfshin.Ardakani@Sun.COM 	 */
17311963SAfshin.Ardakani@Sun.COM 	p = pattern;
17411963SAfshin.Ardakani@Sun.COM 	p += strspn(p, "?");
17511963SAfshin.Ardakani@Sun.COM 	if (*p == '.') {
17611963SAfshin.Ardakani@Sun.COM 		*p = '\0';
17711963SAfshin.Ardakani@Sun.COM 		len = strlen(pattern);
17811963SAfshin.Ardakani@Sun.COM 		*p = '.';
17911963SAfshin.Ardakani@Sun.COM 		if (len >= SMB_NAME83_BASELEN) {
18011963SAfshin.Ardakani@Sun.COM 			*pattern = '*';
18111963SAfshin.Ardakani@Sun.COM 			(void) strlcpy(pattern + 1, p, MAXPATHLEN - 1);
18211963SAfshin.Ardakani@Sun.COM 		}
18311963SAfshin.Ardakani@Sun.COM 	}
18411963SAfshin.Ardakani@Sun.COM 
18511963SAfshin.Ardakani@Sun.COM 	/*
18611963SAfshin.Ardakani@Sun.COM 	 * Replace "base.???" with 'base.*'.
18711963SAfshin.Ardakani@Sun.COM 	 */
18811963SAfshin.Ardakani@Sun.COM 	if ((extension = strrchr(pattern, '.')) != NULL) {
18911963SAfshin.Ardakani@Sun.COM 		p = ++extension;
19011963SAfshin.Ardakani@Sun.COM 		p += strspn(p, "?");
19111963SAfshin.Ardakani@Sun.COM 		if (*p == '\0') {
19211963SAfshin.Ardakani@Sun.COM 			len = strlen(extension);
19311963SAfshin.Ardakani@Sun.COM 			if (len >= SMB_NAME83_EXTLEN) {
19411963SAfshin.Ardakani@Sun.COM 				*extension = '\0';
19511963SAfshin.Ardakani@Sun.COM 				(void) strlcat(pattern, "*", MAXPATHLEN);
19611963SAfshin.Ardakani@Sun.COM 			}
19711963SAfshin.Ardakani@Sun.COM 		}
19811963SAfshin.Ardakani@Sun.COM 	}
19911963SAfshin.Ardakani@Sun.COM 
20011963SAfshin.Ardakani@Sun.COM 	/*
20111963SAfshin.Ardakani@Sun.COM 	 * Replace anything that matches an entry in match_all with "*".
20211963SAfshin.Ardakani@Sun.COM 	 */
20311963SAfshin.Ardakani@Sun.COM 	for (i = 0; i < sizeof (match_all) / sizeof (match_all[0]); ++i) {
20411963SAfshin.Ardakani@Sun.COM 		if (strcmp(pattern, match_all[i]) == 0) {
20511963SAfshin.Ardakani@Sun.COM 			(void) strlcpy(pattern, "*", MAXPATHLEN);
20611963SAfshin.Ardakani@Sun.COM 			break;
20711963SAfshin.Ardakani@Sun.COM 		}
20811963SAfshin.Ardakani@Sun.COM 	}
20911963SAfshin.Ardakani@Sun.COM }
21011963SAfshin.Ardakani@Sun.COM 
21111963SAfshin.Ardakani@Sun.COM /*
21211963SAfshin.Ardakani@Sun.COM  * smb_sattr_check
21311963SAfshin.Ardakani@Sun.COM  *
21411963SAfshin.Ardakani@Sun.COM  * Check file attributes against a search attribute (sattr) mask.
21511963SAfshin.Ardakani@Sun.COM  *
21611963SAfshin.Ardakani@Sun.COM  * Normal files, which includes READONLY and ARCHIVE, always pass
21711963SAfshin.Ardakani@Sun.COM  * this check.  If the DIRECTORY, HIDDEN or SYSTEM special attributes
21811963SAfshin.Ardakani@Sun.COM  * are set then they must appear in the search mask.  The special
21911963SAfshin.Ardakani@Sun.COM  * attributes are inclusive, i.e. all special attributes that appear
22011963SAfshin.Ardakani@Sun.COM  * in sattr must also appear in the file attributes for the check to
22111963SAfshin.Ardakani@Sun.COM  * pass.
22211963SAfshin.Ardakani@Sun.COM  *
22311963SAfshin.Ardakani@Sun.COM  * The following examples show how this works:
22411963SAfshin.Ardakani@Sun.COM  *
22511963SAfshin.Ardakani@Sun.COM  *		fileA:	READONLY
22611963SAfshin.Ardakani@Sun.COM  *		fileB:	0 (no attributes = normal file)
22711963SAfshin.Ardakani@Sun.COM  *		fileC:	READONLY, ARCHIVE
22811963SAfshin.Ardakani@Sun.COM  *		fileD:	HIDDEN
22911963SAfshin.Ardakani@Sun.COM  *		fileE:	READONLY, HIDDEN, SYSTEM
23011963SAfshin.Ardakani@Sun.COM  *		dirA:	DIRECTORY
23111963SAfshin.Ardakani@Sun.COM  *
23211963SAfshin.Ardakani@Sun.COM  * search attribute: 0
23311963SAfshin.Ardakani@Sun.COM  *		Returns: fileA, fileB and fileC.
23411963SAfshin.Ardakani@Sun.COM  * search attribute: HIDDEN
23511963SAfshin.Ardakani@Sun.COM  *		Returns: fileA, fileB, fileC and fileD.
23611963SAfshin.Ardakani@Sun.COM  * search attribute: SYSTEM
23711963SAfshin.Ardakani@Sun.COM  *		Returns: fileA, fileB and fileC.
23811963SAfshin.Ardakani@Sun.COM  * search attribute: DIRECTORY
23911963SAfshin.Ardakani@Sun.COM  *		Returns: fileA, fileB, fileC and dirA.
24011963SAfshin.Ardakani@Sun.COM  * search attribute: HIDDEN and SYSTEM
24111963SAfshin.Ardakani@Sun.COM  *		Returns: fileA, fileB, fileC, fileD and fileE.
24211963SAfshin.Ardakani@Sun.COM  *
24311963SAfshin.Ardakani@Sun.COM  * Returns true if the file and sattr match; otherwise, returns false.
24411963SAfshin.Ardakani@Sun.COM  */
24511963SAfshin.Ardakani@Sun.COM boolean_t
24611963SAfshin.Ardakani@Sun.COM smb_sattr_check(uint16_t dosattr, uint16_t sattr)
24711963SAfshin.Ardakani@Sun.COM {
24811963SAfshin.Ardakani@Sun.COM 	if ((dosattr & FILE_ATTRIBUTE_DIRECTORY) &&
24911963SAfshin.Ardakani@Sun.COM 	    !(sattr & FILE_ATTRIBUTE_DIRECTORY))
25011963SAfshin.Ardakani@Sun.COM 		return (B_FALSE);
25111963SAfshin.Ardakani@Sun.COM 
25211963SAfshin.Ardakani@Sun.COM 	if ((dosattr & FILE_ATTRIBUTE_HIDDEN) &&
25311963SAfshin.Ardakani@Sun.COM 	    !(sattr & FILE_ATTRIBUTE_HIDDEN))
25411963SAfshin.Ardakani@Sun.COM 		return (B_FALSE);
25511963SAfshin.Ardakani@Sun.COM 
25611963SAfshin.Ardakani@Sun.COM 	if ((dosattr & FILE_ATTRIBUTE_SYSTEM) &&
25711963SAfshin.Ardakani@Sun.COM 	    !(sattr & FILE_ATTRIBUTE_SYSTEM))
25811963SAfshin.Ardakani@Sun.COM 		return (B_FALSE);
25911963SAfshin.Ardakani@Sun.COM 
26011963SAfshin.Ardakani@Sun.COM 	return (B_TRUE);
26111963SAfshin.Ardakani@Sun.COM }
26211963SAfshin.Ardakani@Sun.COM 
26311963SAfshin.Ardakani@Sun.COM int
26411963SAfshin.Ardakani@Sun.COM microtime(timestruc_t *tvp)
26511963SAfshin.Ardakani@Sun.COM {
26611963SAfshin.Ardakani@Sun.COM 	tvp->tv_sec = gethrestime_sec();
26711963SAfshin.Ardakani@Sun.COM 	tvp->tv_nsec = 0;
26811963SAfshin.Ardakani@Sun.COM 	return (0);
26911963SAfshin.Ardakani@Sun.COM }
27011963SAfshin.Ardakani@Sun.COM 
27111963SAfshin.Ardakani@Sun.COM int32_t
27211963SAfshin.Ardakani@Sun.COM clock_get_milli_uptime()
27311963SAfshin.Ardakani@Sun.COM {
27411963SAfshin.Ardakani@Sun.COM 	return (TICK_TO_MSEC(ddi_get_lbolt()));
27511963SAfshin.Ardakani@Sun.COM }
27611963SAfshin.Ardakani@Sun.COM 
27711963SAfshin.Ardakani@Sun.COM int /*ARGSUSED*/
27811963SAfshin.Ardakani@Sun.COM smb_noop(void *p, size_t size, int foo)
27911963SAfshin.Ardakani@Sun.COM {
28011963SAfshin.Ardakani@Sun.COM 	return (0);
28111963SAfshin.Ardakani@Sun.COM }
28211963SAfshin.Ardakani@Sun.COM 
28311963SAfshin.Ardakani@Sun.COM /*
28411963SAfshin.Ardakani@Sun.COM  * smb_idpool_increment
28511963SAfshin.Ardakani@Sun.COM  *
28611963SAfshin.Ardakani@Sun.COM  * This function increments the ID pool by doubling the current size. This
28711963SAfshin.Ardakani@Sun.COM  * function assumes the caller entered the mutex of the pool.
28811963SAfshin.Ardakani@Sun.COM  */
28911963SAfshin.Ardakani@Sun.COM static int
29011963SAfshin.Ardakani@Sun.COM smb_idpool_increment(
29111963SAfshin.Ardakani@Sun.COM     smb_idpool_t	*pool)
29211963SAfshin.Ardakani@Sun.COM {
29311963SAfshin.Ardakani@Sun.COM 	uint8_t		*new_pool;
29411963SAfshin.Ardakani@Sun.COM 	uint32_t	new_size;
29511963SAfshin.Ardakani@Sun.COM 
29611963SAfshin.Ardakani@Sun.COM 	ASSERT(pool->id_magic == SMB_IDPOOL_MAGIC);
29711963SAfshin.Ardakani@Sun.COM 
29811963SAfshin.Ardakani@Sun.COM 	new_size = pool->id_size * 2;
29911963SAfshin.Ardakani@Sun.COM 	if (new_size <= SMB_IDPOOL_MAX_SIZE) {
30011963SAfshin.Ardakani@Sun.COM 		new_pool = kmem_alloc(new_size / 8, KM_NOSLEEP);
30111963SAfshin.Ardakani@Sun.COM 		if (new_pool) {
30211963SAfshin.Ardakani@Sun.COM 			bzero(new_pool, new_size / 8);
30311963SAfshin.Ardakani@Sun.COM 			bcopy(pool->id_pool, new_pool, pool->id_size / 8);
30411963SAfshin.Ardakani@Sun.COM 			kmem_free(pool->id_pool, pool->id_size / 8);
30511963SAfshin.Ardakani@Sun.COM 			pool->id_pool = new_pool;
30611963SAfshin.Ardakani@Sun.COM 			pool->id_free_counter += new_size - pool->id_size;
30711963SAfshin.Ardakani@Sun.COM 			pool->id_max_free_counter += new_size - pool->id_size;
30811963SAfshin.Ardakani@Sun.COM 			pool->id_size = new_size;
30911963SAfshin.Ardakani@Sun.COM 			pool->id_idx_msk = (new_size / 8) - 1;
31011963SAfshin.Ardakani@Sun.COM 			if (new_size >= SMB_IDPOOL_MAX_SIZE) {
31111963SAfshin.Ardakani@Sun.COM 				/* id -1 made unavailable */
31211963SAfshin.Ardakani@Sun.COM 				pool->id_pool[pool->id_idx_msk] = 0x80;
31311963SAfshin.Ardakani@Sun.COM 				pool->id_free_counter--;
31411963SAfshin.Ardakani@Sun.COM 				pool->id_max_free_counter--;
31511963SAfshin.Ardakani@Sun.COM 			}
31611963SAfshin.Ardakani@Sun.COM 			return (0);
31711963SAfshin.Ardakani@Sun.COM 		}
31811963SAfshin.Ardakani@Sun.COM 	}
31911963SAfshin.Ardakani@Sun.COM 	return (-1);
32011963SAfshin.Ardakani@Sun.COM }
32111963SAfshin.Ardakani@Sun.COM 
32211963SAfshin.Ardakani@Sun.COM /*
32311963SAfshin.Ardakani@Sun.COM  * smb_idpool_constructor
32411963SAfshin.Ardakani@Sun.COM  *
32511963SAfshin.Ardakani@Sun.COM  * This function initializes the pool structure provided.
32611963SAfshin.Ardakani@Sun.COM  */
32711963SAfshin.Ardakani@Sun.COM int
32811963SAfshin.Ardakani@Sun.COM smb_idpool_constructor(
32911963SAfshin.Ardakani@Sun.COM     smb_idpool_t	*pool)
33011963SAfshin.Ardakani@Sun.COM {
33111963SAfshin.Ardakani@Sun.COM 
33211963SAfshin.Ardakani@Sun.COM 	ASSERT(pool->id_magic != SMB_IDPOOL_MAGIC);
33311963SAfshin.Ardakani@Sun.COM 
33411963SAfshin.Ardakani@Sun.COM 	pool->id_size = SMB_IDPOOL_MIN_SIZE;
33511963SAfshin.Ardakani@Sun.COM 	pool->id_idx_msk = (SMB_IDPOOL_MIN_SIZE / 8) - 1;
33611963SAfshin.Ardakani@Sun.COM 	pool->id_free_counter = SMB_IDPOOL_MIN_SIZE - 1;
33711963SAfshin.Ardakani@Sun.COM 	pool->id_max_free_counter = SMB_IDPOOL_MIN_SIZE - 1;
33811963SAfshin.Ardakani@Sun.COM 	pool->id_bit = 0x02;
33911963SAfshin.Ardakani@Sun.COM 	pool->id_bit_idx = 1;
34011963SAfshin.Ardakani@Sun.COM 	pool->id_idx = 0;
34111963SAfshin.Ardakani@Sun.COM 	pool->id_pool = (uint8_t *)kmem_alloc((SMB_IDPOOL_MIN_SIZE / 8),
34211963SAfshin.Ardakani@Sun.COM 	    KM_SLEEP);
34311963SAfshin.Ardakani@Sun.COM 	bzero(pool->id_pool, (SMB_IDPOOL_MIN_SIZE / 8));
34411963SAfshin.Ardakani@Sun.COM 	/* -1 id made unavailable */
34511963SAfshin.Ardakani@Sun.COM 	pool->id_pool[0] = 0x01;		/* id 0 made unavailable */
34611963SAfshin.Ardakani@Sun.COM 	mutex_init(&pool->id_mutex, NULL, MUTEX_DEFAULT, NULL);
34711963SAfshin.Ardakani@Sun.COM 	pool->id_magic = SMB_IDPOOL_MAGIC;
34811963SAfshin.Ardakani@Sun.COM 	return (0);
34911963SAfshin.Ardakani@Sun.COM }
35011963SAfshin.Ardakani@Sun.COM 
35111963SAfshin.Ardakani@Sun.COM /*
35211963SAfshin.Ardakani@Sun.COM  * smb_idpool_destructor
35311963SAfshin.Ardakani@Sun.COM  *
35411963SAfshin.Ardakani@Sun.COM  * This function tears down and frees the resources associated with the
35511963SAfshin.Ardakani@Sun.COM  * pool provided.
35611963SAfshin.Ardakani@Sun.COM  */
35711963SAfshin.Ardakani@Sun.COM void
35811963SAfshin.Ardakani@Sun.COM smb_idpool_destructor(
35911963SAfshin.Ardakani@Sun.COM     smb_idpool_t	*pool)
36011963SAfshin.Ardakani@Sun.COM {
36111963SAfshin.Ardakani@Sun.COM 	ASSERT(pool->id_magic == SMB_IDPOOL_MAGIC);
36211963SAfshin.Ardakani@Sun.COM 	ASSERT(pool->id_free_counter == pool->id_max_free_counter);
36311963SAfshin.Ardakani@Sun.COM 	pool->id_magic = (uint32_t)~SMB_IDPOOL_MAGIC;
36411963SAfshin.Ardakani@Sun.COM 	mutex_destroy(&pool->id_mutex);
36511963SAfshin.Ardakani@Sun.COM 	kmem_free(pool->id_pool, (size_t)(pool->id_size / 8));
36611963SAfshin.Ardakani@Sun.COM }
36711963SAfshin.Ardakani@Sun.COM 
36811963SAfshin.Ardakani@Sun.COM /*
36911963SAfshin.Ardakani@Sun.COM  * smb_idpool_alloc
37011963SAfshin.Ardakani@Sun.COM  *
37111963SAfshin.Ardakani@Sun.COM  * This function allocates an ID from the pool provided.
37211963SAfshin.Ardakani@Sun.COM  */
37311963SAfshin.Ardakani@Sun.COM int
37411963SAfshin.Ardakani@Sun.COM smb_idpool_alloc(
37511963SAfshin.Ardakani@Sun.COM     smb_idpool_t	*pool,
37611963SAfshin.Ardakani@Sun.COM     uint16_t		*id)
37711963SAfshin.Ardakani@Sun.COM {
37811963SAfshin.Ardakani@Sun.COM 	uint32_t	i;
37911963SAfshin.Ardakani@Sun.COM 	uint8_t		bit;
38011963SAfshin.Ardakani@Sun.COM 	uint8_t		bit_idx;
38111963SAfshin.Ardakani@Sun.COM 	uint8_t		byte;
38211963SAfshin.Ardakani@Sun.COM 
38311963SAfshin.Ardakani@Sun.COM 	ASSERT(pool->id_magic == SMB_IDPOOL_MAGIC);
38411963SAfshin.Ardakani@Sun.COM 
38511963SAfshin.Ardakani@Sun.COM 	mutex_enter(&pool->id_mutex);
38611963SAfshin.Ardakani@Sun.COM 	if ((pool->id_free_counter == 0) && smb_idpool_increment(pool)) {
38711963SAfshin.Ardakani@Sun.COM 		mutex_exit(&pool->id_mutex);
38811963SAfshin.Ardakani@Sun.COM 		return (-1);
38911963SAfshin.Ardakani@Sun.COM 	}
39011963SAfshin.Ardakani@Sun.COM 
39111963SAfshin.Ardakani@Sun.COM 	i = pool->id_size;
39211963SAfshin.Ardakani@Sun.COM 	while (i) {
39311963SAfshin.Ardakani@Sun.COM 		bit = pool->id_bit;
39411963SAfshin.Ardakani@Sun.COM 		bit_idx = pool->id_bit_idx;
39511963SAfshin.Ardakani@Sun.COM 		byte = pool->id_pool[pool->id_idx];
39611963SAfshin.Ardakani@Sun.COM 		while (bit) {
39711963SAfshin.Ardakani@Sun.COM 			if (byte & bit) {
39811963SAfshin.Ardakani@Sun.COM 				bit = bit << 1;
39911963SAfshin.Ardakani@Sun.COM 				bit_idx++;
40011963SAfshin.Ardakani@Sun.COM 				continue;
40111963SAfshin.Ardakani@Sun.COM 			}
40211963SAfshin.Ardakani@Sun.COM 			pool->id_pool[pool->id_idx] |= bit;
40311963SAfshin.Ardakani@Sun.COM 			*id = (uint16_t)(pool->id_idx * 8 + (uint32_t)bit_idx);
40411963SAfshin.Ardakani@Sun.COM 			pool->id_free_counter--;
40511963SAfshin.Ardakani@Sun.COM 			pool->id_bit = bit;
40611963SAfshin.Ardakani@Sun.COM 			pool->id_bit_idx = bit_idx;
40711963SAfshin.Ardakani@Sun.COM 			mutex_exit(&pool->id_mutex);
40811963SAfshin.Ardakani@Sun.COM 			return (0);
40911963SAfshin.Ardakani@Sun.COM 		}
41011963SAfshin.Ardakani@Sun.COM 		pool->id_bit = 1;
41111963SAfshin.Ardakani@Sun.COM 		pool->id_bit_idx = 0;
41211963SAfshin.Ardakani@Sun.COM 		pool->id_idx++;
41311963SAfshin.Ardakani@Sun.COM 		pool->id_idx &= pool->id_idx_msk;
41411963SAfshin.Ardakani@Sun.COM 		--i;
41511963SAfshin.Ardakani@Sun.COM 	}
41611963SAfshin.Ardakani@Sun.COM 	/*
41711963SAfshin.Ardakani@Sun.COM 	 * This section of code shouldn't be reached. If there are IDs
41811963SAfshin.Ardakani@Sun.COM 	 * available and none could be found there's a problem.
41911963SAfshin.Ardakani@Sun.COM 	 */
42011963SAfshin.Ardakani@Sun.COM 	ASSERT(0);
42111963SAfshin.Ardakani@Sun.COM 	mutex_exit(&pool->id_mutex);
42211963SAfshin.Ardakani@Sun.COM 	return (-1);
42311963SAfshin.Ardakani@Sun.COM }
42411963SAfshin.Ardakani@Sun.COM 
42511963SAfshin.Ardakani@Sun.COM /*
42611963SAfshin.Ardakani@Sun.COM  * smb_idpool_free
42711963SAfshin.Ardakani@Sun.COM  *
42811963SAfshin.Ardakani@Sun.COM  * This function frees the ID provided.
42911963SAfshin.Ardakani@Sun.COM  */
43011963SAfshin.Ardakani@Sun.COM void
43111963SAfshin.Ardakani@Sun.COM smb_idpool_free(
43211963SAfshin.Ardakani@Sun.COM     smb_idpool_t	*pool,
43311963SAfshin.Ardakani@Sun.COM     uint16_t		id)
43411963SAfshin.Ardakani@Sun.COM {
43511963SAfshin.Ardakani@Sun.COM 	ASSERT(pool->id_magic == SMB_IDPOOL_MAGIC);
43611963SAfshin.Ardakani@Sun.COM 	ASSERT(id != 0);
43711963SAfshin.Ardakani@Sun.COM 	ASSERT(id != 0xFFFF);
43811963SAfshin.Ardakani@Sun.COM 
43911963SAfshin.Ardakani@Sun.COM 	mutex_enter(&pool->id_mutex);
44011963SAfshin.Ardakani@Sun.COM 	if (pool->id_pool[id >> 3] & (1 << (id & 7))) {
44111963SAfshin.Ardakani@Sun.COM 		pool->id_pool[id >> 3] &= ~(1 << (id & 7));
44211963SAfshin.Ardakani@Sun.COM 		pool->id_free_counter++;
44311963SAfshin.Ardakani@Sun.COM 		ASSERT(pool->id_free_counter <= pool->id_max_free_counter);
44411963SAfshin.Ardakani@Sun.COM 		mutex_exit(&pool->id_mutex);
44511963SAfshin.Ardakani@Sun.COM 		return;
44611963SAfshin.Ardakani@Sun.COM 	}
44711963SAfshin.Ardakani@Sun.COM 	/* Freeing a free ID. */
44811963SAfshin.Ardakani@Sun.COM 	ASSERT(0);
44911963SAfshin.Ardakani@Sun.COM 	mutex_exit(&pool->id_mutex);
45011963SAfshin.Ardakani@Sun.COM }
45111963SAfshin.Ardakani@Sun.COM 
45211963SAfshin.Ardakani@Sun.COM /*
45311963SAfshin.Ardakani@Sun.COM  * Initialize the llist delete queue object cache.
45411963SAfshin.Ardakani@Sun.COM  */
45511963SAfshin.Ardakani@Sun.COM void
45611963SAfshin.Ardakani@Sun.COM smb_llist_init(void)
45711963SAfshin.Ardakani@Sun.COM {
45811963SAfshin.Ardakani@Sun.COM 	if (smb_llist_initialized)
45911963SAfshin.Ardakani@Sun.COM 		return;
46011963SAfshin.Ardakani@Sun.COM 
46111963SAfshin.Ardakani@Sun.COM 	smb_dtor_cache = kmem_cache_create("smb_dtor_cache",
46211963SAfshin.Ardakani@Sun.COM 	    sizeof (smb_dtor_t), 8, NULL, NULL, NULL, NULL, NULL, 0);
46311963SAfshin.Ardakani@Sun.COM 
46411963SAfshin.Ardakani@Sun.COM 	smb_llist_initialized = B_TRUE;
46511963SAfshin.Ardakani@Sun.COM }
46611963SAfshin.Ardakani@Sun.COM 
46711963SAfshin.Ardakani@Sun.COM /*
46811963SAfshin.Ardakani@Sun.COM  * Destroy the llist delete queue object cache.
46911963SAfshin.Ardakani@Sun.COM  */
47011963SAfshin.Ardakani@Sun.COM void
47111963SAfshin.Ardakani@Sun.COM smb_llist_fini(void)
47211963SAfshin.Ardakani@Sun.COM {
47311963SAfshin.Ardakani@Sun.COM 	if (!smb_llist_initialized)
47411963SAfshin.Ardakani@Sun.COM 		return;
47511963SAfshin.Ardakani@Sun.COM 
47611963SAfshin.Ardakani@Sun.COM 	kmem_cache_destroy(smb_dtor_cache);
47711963SAfshin.Ardakani@Sun.COM 	smb_llist_initialized = B_FALSE;
47811963SAfshin.Ardakani@Sun.COM }
47911963SAfshin.Ardakani@Sun.COM 
48011963SAfshin.Ardakani@Sun.COM /*
48111963SAfshin.Ardakani@Sun.COM  * smb_llist_constructor
48211963SAfshin.Ardakani@Sun.COM  *
48311963SAfshin.Ardakani@Sun.COM  * This function initializes a locked list.
48411963SAfshin.Ardakani@Sun.COM  */
48511963SAfshin.Ardakani@Sun.COM void
48611963SAfshin.Ardakani@Sun.COM smb_llist_constructor(
48711963SAfshin.Ardakani@Sun.COM     smb_llist_t	*ll,
48811963SAfshin.Ardakani@Sun.COM     size_t	size,
48911963SAfshin.Ardakani@Sun.COM     size_t	offset)
49011963SAfshin.Ardakani@Sun.COM {
49111963SAfshin.Ardakani@Sun.COM 	rw_init(&ll->ll_lock, NULL, RW_DEFAULT, NULL);
49211963SAfshin.Ardakani@Sun.COM 	mutex_init(&ll->ll_mutex, NULL, MUTEX_DEFAULT, NULL);
49311963SAfshin.Ardakani@Sun.COM 	list_create(&ll->ll_list, size, offset);
49411963SAfshin.Ardakani@Sun.COM 	list_create(&ll->ll_deleteq, sizeof (smb_dtor_t),
49511963SAfshin.Ardakani@Sun.COM 	    offsetof(smb_dtor_t, dt_lnd));
49611963SAfshin.Ardakani@Sun.COM 	ll->ll_count = 0;
49711963SAfshin.Ardakani@Sun.COM 	ll->ll_wrop = 0;
49811963SAfshin.Ardakani@Sun.COM 	ll->ll_deleteq_count = 0;
49911963SAfshin.Ardakani@Sun.COM }
50011963SAfshin.Ardakani@Sun.COM 
50111963SAfshin.Ardakani@Sun.COM /*
50211963SAfshin.Ardakani@Sun.COM  * Flush the delete queue and destroy a locked list.
50311963SAfshin.Ardakani@Sun.COM  */
50411963SAfshin.Ardakani@Sun.COM void
50511963SAfshin.Ardakani@Sun.COM smb_llist_destructor(
50611963SAfshin.Ardakani@Sun.COM     smb_llist_t	*ll)
50711963SAfshin.Ardakani@Sun.COM {
50811963SAfshin.Ardakani@Sun.COM 	smb_llist_flush(ll);
50911963SAfshin.Ardakani@Sun.COM 
51011963SAfshin.Ardakani@Sun.COM 	ASSERT(ll->ll_count == 0);
51111963SAfshin.Ardakani@Sun.COM 	ASSERT(ll->ll_deleteq_count == 0);
51211963SAfshin.Ardakani@Sun.COM 
51311963SAfshin.Ardakani@Sun.COM 	rw_destroy(&ll->ll_lock);
51411963SAfshin.Ardakani@Sun.COM 	list_destroy(&ll->ll_list);
51511963SAfshin.Ardakani@Sun.COM 	list_destroy(&ll->ll_deleteq);
51611963SAfshin.Ardakani@Sun.COM 	mutex_destroy(&ll->ll_mutex);
51711963SAfshin.Ardakani@Sun.COM }
51811963SAfshin.Ardakani@Sun.COM 
51911963SAfshin.Ardakani@Sun.COM /*
52011963SAfshin.Ardakani@Sun.COM  * Post an object to the delete queue.  The delete queue will be processed
52111963SAfshin.Ardakani@Sun.COM  * during list exit or list destruction.  Objects are often posted for
52211963SAfshin.Ardakani@Sun.COM  * deletion during list iteration (while the list is locked) but that is
52311963SAfshin.Ardakani@Sun.COM  * not required, and an object can be posted at any time.
52411963SAfshin.Ardakani@Sun.COM  */
52511963SAfshin.Ardakani@Sun.COM void
52611963SAfshin.Ardakani@Sun.COM smb_llist_post(smb_llist_t *ll, void *object, smb_dtorproc_t dtorproc)
52711963SAfshin.Ardakani@Sun.COM {
52811963SAfshin.Ardakani@Sun.COM 	smb_dtor_t	*dtor;
52911963SAfshin.Ardakani@Sun.COM 
53011963SAfshin.Ardakani@Sun.COM 	ASSERT((object != NULL) && (dtorproc != NULL));
53111963SAfshin.Ardakani@Sun.COM 
53211963SAfshin.Ardakani@Sun.COM 	dtor = kmem_cache_alloc(smb_dtor_cache, KM_SLEEP);
53311963SAfshin.Ardakani@Sun.COM 	bzero(dtor, sizeof (smb_dtor_t));
53411963SAfshin.Ardakani@Sun.COM 	dtor->dt_magic = SMB_DTOR_MAGIC;
53511963SAfshin.Ardakani@Sun.COM 	dtor->dt_object = object;
53611963SAfshin.Ardakani@Sun.COM 	dtor->dt_proc = dtorproc;
53711963SAfshin.Ardakani@Sun.COM 
53811963SAfshin.Ardakani@Sun.COM 	mutex_enter(&ll->ll_mutex);
53911963SAfshin.Ardakani@Sun.COM 	list_insert_tail(&ll->ll_deleteq, dtor);
54011963SAfshin.Ardakani@Sun.COM 	++ll->ll_deleteq_count;
54111963SAfshin.Ardakani@Sun.COM 	mutex_exit(&ll->ll_mutex);
54211963SAfshin.Ardakani@Sun.COM }
54311963SAfshin.Ardakani@Sun.COM 
54411963SAfshin.Ardakani@Sun.COM /*
54511963SAfshin.Ardakani@Sun.COM  * Exit the list lock and process the delete queue.
54611963SAfshin.Ardakani@Sun.COM  */
54711963SAfshin.Ardakani@Sun.COM void
54811963SAfshin.Ardakani@Sun.COM smb_llist_exit(smb_llist_t *ll)
54911963SAfshin.Ardakani@Sun.COM {
55011963SAfshin.Ardakani@Sun.COM 	rw_exit(&ll->ll_lock);
55111963SAfshin.Ardakani@Sun.COM 	smb_llist_flush(ll);
55211963SAfshin.Ardakani@Sun.COM }
55311963SAfshin.Ardakani@Sun.COM 
55411963SAfshin.Ardakani@Sun.COM /*
55511963SAfshin.Ardakani@Sun.COM  * Flush the list delete queue.  The mutex is dropped across the destructor
55611963SAfshin.Ardakani@Sun.COM  * call in case this leads to additional objects being posted to the delete
55711963SAfshin.Ardakani@Sun.COM  * queue.
55811963SAfshin.Ardakani@Sun.COM  */
559*12065SKeyur.Desai@Sun.COM void
56011963SAfshin.Ardakani@Sun.COM smb_llist_flush(smb_llist_t *ll)
56111963SAfshin.Ardakani@Sun.COM {
56211963SAfshin.Ardakani@Sun.COM 	smb_dtor_t    *dtor;
56311963SAfshin.Ardakani@Sun.COM 
56411963SAfshin.Ardakani@Sun.COM 	mutex_enter(&ll->ll_mutex);
56511963SAfshin.Ardakani@Sun.COM 
56611963SAfshin.Ardakani@Sun.COM 	dtor = list_head(&ll->ll_deleteq);
56711963SAfshin.Ardakani@Sun.COM 	while (dtor != NULL) {
56811963SAfshin.Ardakani@Sun.COM 		SMB_DTOR_VALID(dtor);
56911963SAfshin.Ardakani@Sun.COM 		ASSERT((dtor->dt_object != NULL) && (dtor->dt_proc != NULL));
57011963SAfshin.Ardakani@Sun.COM 		list_remove(&ll->ll_deleteq, dtor);
57111963SAfshin.Ardakani@Sun.COM 		--ll->ll_deleteq_count;
57211963SAfshin.Ardakani@Sun.COM 		mutex_exit(&ll->ll_mutex);
57311963SAfshin.Ardakani@Sun.COM 
57411963SAfshin.Ardakani@Sun.COM 		dtor->dt_proc(dtor->dt_object);
57511963SAfshin.Ardakani@Sun.COM 
57611963SAfshin.Ardakani@Sun.COM 		dtor->dt_magic = (uint32_t)~SMB_DTOR_MAGIC;
57711963SAfshin.Ardakani@Sun.COM 		kmem_cache_free(smb_dtor_cache, dtor);
57811963SAfshin.Ardakani@Sun.COM 		mutex_enter(&ll->ll_mutex);
57911963SAfshin.Ardakani@Sun.COM 		dtor = list_head(&ll->ll_deleteq);
58011963SAfshin.Ardakani@Sun.COM 	}
58111963SAfshin.Ardakani@Sun.COM 
58211963SAfshin.Ardakani@Sun.COM 	mutex_exit(&ll->ll_mutex);
58311963SAfshin.Ardakani@Sun.COM }
58411963SAfshin.Ardakani@Sun.COM 
58511963SAfshin.Ardakani@Sun.COM /*
58611963SAfshin.Ardakani@Sun.COM  * smb_llist_upgrade
58711963SAfshin.Ardakani@Sun.COM  *
58811963SAfshin.Ardakani@Sun.COM  * This function tries to upgrade the lock of the locked list. It assumes the
58911963SAfshin.Ardakani@Sun.COM  * locked has already been entered in RW_READER mode. It first tries using the
59011963SAfshin.Ardakani@Sun.COM  * Solaris function rw_tryupgrade(). If that call fails the lock is released
59111963SAfshin.Ardakani@Sun.COM  * and reentered in RW_WRITER mode. In that last case a window is opened during
59211963SAfshin.Ardakani@Sun.COM  * which the contents of the list may have changed. The return code indicates
59311963SAfshin.Ardakani@Sun.COM  * whether or not the list was modified when the lock was exited.
59411963SAfshin.Ardakani@Sun.COM  */
59511963SAfshin.Ardakani@Sun.COM int smb_llist_upgrade(
59611963SAfshin.Ardakani@Sun.COM     smb_llist_t *ll)
59711963SAfshin.Ardakani@Sun.COM {
59811963SAfshin.Ardakani@Sun.COM 	uint64_t	wrop;
59911963SAfshin.Ardakani@Sun.COM 
60011963SAfshin.Ardakani@Sun.COM 	if (rw_tryupgrade(&ll->ll_lock) != 0) {
60111963SAfshin.Ardakani@Sun.COM 		return (0);
60211963SAfshin.Ardakani@Sun.COM 	}
60311963SAfshin.Ardakani@Sun.COM 	wrop = ll->ll_wrop;
60411963SAfshin.Ardakani@Sun.COM 	rw_exit(&ll->ll_lock);
60511963SAfshin.Ardakani@Sun.COM 	rw_enter(&ll->ll_lock, RW_WRITER);
60611963SAfshin.Ardakani@Sun.COM 	return (wrop != ll->ll_wrop);
60711963SAfshin.Ardakani@Sun.COM }
60811963SAfshin.Ardakani@Sun.COM 
60911963SAfshin.Ardakani@Sun.COM /*
61011963SAfshin.Ardakani@Sun.COM  * smb_llist_insert_head
61111963SAfshin.Ardakani@Sun.COM  *
61211963SAfshin.Ardakani@Sun.COM  * This function inserts the object passed a the beginning of the list. This
61311963SAfshin.Ardakani@Sun.COM  * function assumes the lock of the list has already been entered.
61411963SAfshin.Ardakani@Sun.COM  */
61511963SAfshin.Ardakani@Sun.COM void
61611963SAfshin.Ardakani@Sun.COM smb_llist_insert_head(
61711963SAfshin.Ardakani@Sun.COM     smb_llist_t	*ll,
61811963SAfshin.Ardakani@Sun.COM     void	*obj)
61911963SAfshin.Ardakani@Sun.COM {
62011963SAfshin.Ardakani@Sun.COM 	list_insert_head(&ll->ll_list, obj);
62111963SAfshin.Ardakani@Sun.COM 	++ll->ll_wrop;
62211963SAfshin.Ardakani@Sun.COM 	++ll->ll_count;
62311963SAfshin.Ardakani@Sun.COM }
62411963SAfshin.Ardakani@Sun.COM 
62511963SAfshin.Ardakani@Sun.COM /*
62611963SAfshin.Ardakani@Sun.COM  * smb_llist_insert_tail
62711963SAfshin.Ardakani@Sun.COM  *
62811963SAfshin.Ardakani@Sun.COM  * This function appends to the object passed to the list. This function assumes
62911963SAfshin.Ardakani@Sun.COM  * the lock of the list has already been entered.
63011963SAfshin.Ardakani@Sun.COM  *
63111963SAfshin.Ardakani@Sun.COM  */
63211963SAfshin.Ardakani@Sun.COM void
63311963SAfshin.Ardakani@Sun.COM smb_llist_insert_tail(
63411963SAfshin.Ardakani@Sun.COM     smb_llist_t	*ll,
63511963SAfshin.Ardakani@Sun.COM     void	*obj)
63611963SAfshin.Ardakani@Sun.COM {
63711963SAfshin.Ardakani@Sun.COM 	list_insert_tail(&ll->ll_list, obj);
63811963SAfshin.Ardakani@Sun.COM 	++ll->ll_wrop;
63911963SAfshin.Ardakani@Sun.COM 	++ll->ll_count;
64011963SAfshin.Ardakani@Sun.COM }
64111963SAfshin.Ardakani@Sun.COM 
64211963SAfshin.Ardakani@Sun.COM /*
64311963SAfshin.Ardakani@Sun.COM  * smb_llist_remove
64411963SAfshin.Ardakani@Sun.COM  *
64511963SAfshin.Ardakani@Sun.COM  * This function removes the object passed from the list. This function assumes
64611963SAfshin.Ardakani@Sun.COM  * the lock of the list has already been entered.
64711963SAfshin.Ardakani@Sun.COM  */
64811963SAfshin.Ardakani@Sun.COM void
64911963SAfshin.Ardakani@Sun.COM smb_llist_remove(
65011963SAfshin.Ardakani@Sun.COM     smb_llist_t	*ll,
65111963SAfshin.Ardakani@Sun.COM     void	*obj)
65211963SAfshin.Ardakani@Sun.COM {
65311963SAfshin.Ardakani@Sun.COM 	list_remove(&ll->ll_list, obj);
65411963SAfshin.Ardakani@Sun.COM 	++ll->ll_wrop;
65511963SAfshin.Ardakani@Sun.COM 	--ll->ll_count;
65611963SAfshin.Ardakani@Sun.COM }
65711963SAfshin.Ardakani@Sun.COM 
65811963SAfshin.Ardakani@Sun.COM /*
65911963SAfshin.Ardakani@Sun.COM  * smb_llist_get_count
66011963SAfshin.Ardakani@Sun.COM  *
66111963SAfshin.Ardakani@Sun.COM  * This function returns the number of elements in the specified list.
66211963SAfshin.Ardakani@Sun.COM  */
66311963SAfshin.Ardakani@Sun.COM uint32_t
66411963SAfshin.Ardakani@Sun.COM smb_llist_get_count(
66511963SAfshin.Ardakani@Sun.COM     smb_llist_t *ll)
66611963SAfshin.Ardakani@Sun.COM {
66711963SAfshin.Ardakani@Sun.COM 	return (ll->ll_count);
66811963SAfshin.Ardakani@Sun.COM }
66911963SAfshin.Ardakani@Sun.COM 
67011963SAfshin.Ardakani@Sun.COM /*
67111963SAfshin.Ardakani@Sun.COM  * smb_slist_constructor
67211963SAfshin.Ardakani@Sun.COM  *
67311963SAfshin.Ardakani@Sun.COM  * Synchronized list constructor.
67411963SAfshin.Ardakani@Sun.COM  */
67511963SAfshin.Ardakani@Sun.COM void
67611963SAfshin.Ardakani@Sun.COM smb_slist_constructor(
67711963SAfshin.Ardakani@Sun.COM     smb_slist_t	*sl,
67811963SAfshin.Ardakani@Sun.COM     size_t	size,
67911963SAfshin.Ardakani@Sun.COM     size_t	offset)
68011963SAfshin.Ardakani@Sun.COM {
68111963SAfshin.Ardakani@Sun.COM 	mutex_init(&sl->sl_mutex, NULL, MUTEX_DEFAULT, NULL);
68211963SAfshin.Ardakani@Sun.COM 	cv_init(&sl->sl_cv, NULL, CV_DEFAULT, NULL);
68311963SAfshin.Ardakani@Sun.COM 	list_create(&sl->sl_list, size, offset);
68411963SAfshin.Ardakani@Sun.COM 	sl->sl_count = 0;
68511963SAfshin.Ardakani@Sun.COM 	sl->sl_waiting = B_FALSE;
68611963SAfshin.Ardakani@Sun.COM }
68711963SAfshin.Ardakani@Sun.COM 
68811963SAfshin.Ardakani@Sun.COM /*
68911963SAfshin.Ardakani@Sun.COM  * smb_slist_destructor
69011963SAfshin.Ardakani@Sun.COM  *
69111963SAfshin.Ardakani@Sun.COM  * Synchronized list destructor.
69211963SAfshin.Ardakani@Sun.COM  */
69311963SAfshin.Ardakani@Sun.COM void
69411963SAfshin.Ardakani@Sun.COM smb_slist_destructor(
69511963SAfshin.Ardakani@Sun.COM     smb_slist_t	*sl)
69611963SAfshin.Ardakani@Sun.COM {
69711963SAfshin.Ardakani@Sun.COM 	ASSERT(sl->sl_count == 0);
69811963SAfshin.Ardakani@Sun.COM 
69911963SAfshin.Ardakani@Sun.COM 	mutex_destroy(&sl->sl_mutex);
70011963SAfshin.Ardakani@Sun.COM 	cv_destroy(&sl->sl_cv);
70111963SAfshin.Ardakani@Sun.COM 	list_destroy(&sl->sl_list);
70211963SAfshin.Ardakani@Sun.COM }
70311963SAfshin.Ardakani@Sun.COM 
70411963SAfshin.Ardakani@Sun.COM /*
70511963SAfshin.Ardakani@Sun.COM  * smb_slist_insert_head
70611963SAfshin.Ardakani@Sun.COM  *
70711963SAfshin.Ardakani@Sun.COM  * This function inserts the object passed a the beginning of the list.
70811963SAfshin.Ardakani@Sun.COM  */
70911963SAfshin.Ardakani@Sun.COM void
71011963SAfshin.Ardakani@Sun.COM smb_slist_insert_head(
71111963SAfshin.Ardakani@Sun.COM     smb_slist_t	*sl,
71211963SAfshin.Ardakani@Sun.COM     void	*obj)
71311963SAfshin.Ardakani@Sun.COM {
71411963SAfshin.Ardakani@Sun.COM 	mutex_enter(&sl->sl_mutex);
71511963SAfshin.Ardakani@Sun.COM 	list_insert_head(&sl->sl_list, obj);
71611963SAfshin.Ardakani@Sun.COM 	++sl->sl_count;
71711963SAfshin.Ardakani@Sun.COM 	mutex_exit(&sl->sl_mutex);
71811963SAfshin.Ardakani@Sun.COM }
71911963SAfshin.Ardakani@Sun.COM 
72011963SAfshin.Ardakani@Sun.COM /*
72111963SAfshin.Ardakani@Sun.COM  * smb_slist_insert_tail
72211963SAfshin.Ardakani@Sun.COM  *
72311963SAfshin.Ardakani@Sun.COM  * This function appends the object passed to the list.
72411963SAfshin.Ardakani@Sun.COM  */
72511963SAfshin.Ardakani@Sun.COM void
72611963SAfshin.Ardakani@Sun.COM smb_slist_insert_tail(
72711963SAfshin.Ardakani@Sun.COM     smb_slist_t	*sl,
72811963SAfshin.Ardakani@Sun.COM     void	*obj)
72911963SAfshin.Ardakani@Sun.COM {
73011963SAfshin.Ardakani@Sun.COM 	mutex_enter(&sl->sl_mutex);
73111963SAfshin.Ardakani@Sun.COM 	list_insert_tail(&sl->sl_list, obj);
73211963SAfshin.Ardakani@Sun.COM 	++sl->sl_count;
73311963SAfshin.Ardakani@Sun.COM 	mutex_exit(&sl->sl_mutex);
73411963SAfshin.Ardakani@Sun.COM }
73511963SAfshin.Ardakani@Sun.COM 
73611963SAfshin.Ardakani@Sun.COM /*
73711963SAfshin.Ardakani@Sun.COM  * smb_llist_remove
73811963SAfshin.Ardakani@Sun.COM  *
73911963SAfshin.Ardakani@Sun.COM  * This function removes the object passed by the caller from the list.
74011963SAfshin.Ardakani@Sun.COM  */
74111963SAfshin.Ardakani@Sun.COM void
74211963SAfshin.Ardakani@Sun.COM smb_slist_remove(
74311963SAfshin.Ardakani@Sun.COM     smb_slist_t	*sl,
74411963SAfshin.Ardakani@Sun.COM     void	*obj)
74511963SAfshin.Ardakani@Sun.COM {
74611963SAfshin.Ardakani@Sun.COM 	mutex_enter(&sl->sl_mutex);
74711963SAfshin.Ardakani@Sun.COM 	list_remove(&sl->sl_list, obj);
74811963SAfshin.Ardakani@Sun.COM 	if ((--sl->sl_count == 0) && (sl->sl_waiting)) {
74911963SAfshin.Ardakani@Sun.COM 		sl->sl_waiting = B_FALSE;
75011963SAfshin.Ardakani@Sun.COM 		cv_broadcast(&sl->sl_cv);
75111963SAfshin.Ardakani@Sun.COM 	}
75211963SAfshin.Ardakani@Sun.COM 	mutex_exit(&sl->sl_mutex);
75311963SAfshin.Ardakani@Sun.COM }
75411963SAfshin.Ardakani@Sun.COM 
75511963SAfshin.Ardakani@Sun.COM /*
75611963SAfshin.Ardakani@Sun.COM  * smb_slist_move_tail
75711963SAfshin.Ardakani@Sun.COM  *
75811963SAfshin.Ardakani@Sun.COM  * This function transfers all the contents of the synchronized list to the
75911963SAfshin.Ardakani@Sun.COM  * list_t provided. It returns the number of objects transferred.
76011963SAfshin.Ardakani@Sun.COM  */
76111963SAfshin.Ardakani@Sun.COM uint32_t
76211963SAfshin.Ardakani@Sun.COM smb_slist_move_tail(
76311963SAfshin.Ardakani@Sun.COM     list_t	*lst,
76411963SAfshin.Ardakani@Sun.COM     smb_slist_t	*sl)
76511963SAfshin.Ardakani@Sun.COM {
76611963SAfshin.Ardakani@Sun.COM 	uint32_t	rv;
76711963SAfshin.Ardakani@Sun.COM 
76811963SAfshin.Ardakani@Sun.COM 	mutex_enter(&sl->sl_mutex);
76911963SAfshin.Ardakani@Sun.COM 	rv = sl->sl_count;
77011963SAfshin.Ardakani@Sun.COM 	if (sl->sl_count) {
77111963SAfshin.Ardakani@Sun.COM 		list_move_tail(lst, &sl->sl_list);
77211963SAfshin.Ardakani@Sun.COM 		sl->sl_count = 0;
77311963SAfshin.Ardakani@Sun.COM 		if (sl->sl_waiting) {
77411963SAfshin.Ardakani@Sun.COM 			sl->sl_waiting = B_FALSE;
77511963SAfshin.Ardakani@Sun.COM 			cv_broadcast(&sl->sl_cv);
77611963SAfshin.Ardakani@Sun.COM 		}
77711963SAfshin.Ardakani@Sun.COM 	}
77811963SAfshin.Ardakani@Sun.COM 	mutex_exit(&sl->sl_mutex);
77911963SAfshin.Ardakani@Sun.COM 	return (rv);
78011963SAfshin.Ardakani@Sun.COM }
78111963SAfshin.Ardakani@Sun.COM 
78211963SAfshin.Ardakani@Sun.COM /*
78311963SAfshin.Ardakani@Sun.COM  * smb_slist_obj_move
78411963SAfshin.Ardakani@Sun.COM  *
78511963SAfshin.Ardakani@Sun.COM  * This function moves an object from one list to the end of the other list. It
78611963SAfshin.Ardakani@Sun.COM  * assumes the mutex of each list has been entered.
78711963SAfshin.Ardakani@Sun.COM  */
78811963SAfshin.Ardakani@Sun.COM void
78911963SAfshin.Ardakani@Sun.COM smb_slist_obj_move(
79011963SAfshin.Ardakani@Sun.COM     smb_slist_t	*dst,
79111963SAfshin.Ardakani@Sun.COM     smb_slist_t	*src,
79211963SAfshin.Ardakani@Sun.COM     void	*obj)
79311963SAfshin.Ardakani@Sun.COM {
79411963SAfshin.Ardakani@Sun.COM 	ASSERT(dst->sl_list.list_offset == src->sl_list.list_offset);
79511963SAfshin.Ardakani@Sun.COM 	ASSERT(dst->sl_list.list_size == src->sl_list.list_size);
79611963SAfshin.Ardakani@Sun.COM 
79711963SAfshin.Ardakani@Sun.COM 	list_remove(&src->sl_list, obj);
79811963SAfshin.Ardakani@Sun.COM 	list_insert_tail(&dst->sl_list, obj);
79911963SAfshin.Ardakani@Sun.COM 	dst->sl_count++;
80011963SAfshin.Ardakani@Sun.COM 	src->sl_count--;
80111963SAfshin.Ardakani@Sun.COM 	if ((src->sl_count == 0) && (src->sl_waiting)) {
80211963SAfshin.Ardakani@Sun.COM 		src->sl_waiting = B_FALSE;
80311963SAfshin.Ardakani@Sun.COM 		cv_broadcast(&src->sl_cv);
80411963SAfshin.Ardakani@Sun.COM 	}
80511963SAfshin.Ardakani@Sun.COM }
80611963SAfshin.Ardakani@Sun.COM 
80711963SAfshin.Ardakani@Sun.COM /*
80811963SAfshin.Ardakani@Sun.COM  * smb_slist_wait_for_empty
80911963SAfshin.Ardakani@Sun.COM  *
81011963SAfshin.Ardakani@Sun.COM  * This function waits for a list to be emptied.
81111963SAfshin.Ardakani@Sun.COM  */
81211963SAfshin.Ardakani@Sun.COM void
81311963SAfshin.Ardakani@Sun.COM smb_slist_wait_for_empty(
81411963SAfshin.Ardakani@Sun.COM     smb_slist_t	*sl)
81511963SAfshin.Ardakani@Sun.COM {
81611963SAfshin.Ardakani@Sun.COM 	mutex_enter(&sl->sl_mutex);
81711963SAfshin.Ardakani@Sun.COM 	while (sl->sl_count) {
81811963SAfshin.Ardakani@Sun.COM 		sl->sl_waiting = B_TRUE;
81911963SAfshin.Ardakani@Sun.COM 		cv_wait(&sl->sl_cv, &sl->sl_mutex);
82011963SAfshin.Ardakani@Sun.COM 	}
82111963SAfshin.Ardakani@Sun.COM 	mutex_exit(&sl->sl_mutex);
82211963SAfshin.Ardakani@Sun.COM }
82311963SAfshin.Ardakani@Sun.COM 
82411963SAfshin.Ardakani@Sun.COM /*
82511963SAfshin.Ardakani@Sun.COM  * smb_slist_exit
82611963SAfshin.Ardakani@Sun.COM  *
82711963SAfshin.Ardakani@Sun.COM  * This function exits the muetx of the list and signal the condition variable
82811963SAfshin.Ardakani@Sun.COM  * if the list is empty.
82911963SAfshin.Ardakani@Sun.COM  */
83011963SAfshin.Ardakani@Sun.COM void
83111963SAfshin.Ardakani@Sun.COM smb_slist_exit(smb_slist_t *sl)
83211963SAfshin.Ardakani@Sun.COM {
83311963SAfshin.Ardakani@Sun.COM 	if ((sl->sl_count == 0) && (sl->sl_waiting)) {
83411963SAfshin.Ardakani@Sun.COM 		sl->sl_waiting = B_FALSE;
83511963SAfshin.Ardakani@Sun.COM 		cv_broadcast(&sl->sl_cv);
83611963SAfshin.Ardakani@Sun.COM 	}
83711963SAfshin.Ardakani@Sun.COM 	mutex_exit(&sl->sl_mutex);
83811963SAfshin.Ardakani@Sun.COM }
83911963SAfshin.Ardakani@Sun.COM 
84011963SAfshin.Ardakani@Sun.COM /*
84111963SAfshin.Ardakani@Sun.COM  * smb_thread_entry_point
84211963SAfshin.Ardakani@Sun.COM  *
84311963SAfshin.Ardakani@Sun.COM  * Common entry point for all the threads created through smb_thread_start.
84411963SAfshin.Ardakani@Sun.COM  * The state of the thread is set to "running" at the beginning and moved to
84511963SAfshin.Ardakani@Sun.COM  * "exiting" just before calling thread_exit(). The condition variable is
84611963SAfshin.Ardakani@Sun.COM  *  also signaled.
84711963SAfshin.Ardakani@Sun.COM  */
84811963SAfshin.Ardakani@Sun.COM static void
84911963SAfshin.Ardakani@Sun.COM smb_thread_entry_point(
85011963SAfshin.Ardakani@Sun.COM     smb_thread_t	*thread)
85111963SAfshin.Ardakani@Sun.COM {
85211963SAfshin.Ardakani@Sun.COM 	ASSERT(thread->sth_magic == SMB_THREAD_MAGIC);
85311963SAfshin.Ardakani@Sun.COM 	mutex_enter(&thread->sth_mtx);
85411963SAfshin.Ardakani@Sun.COM 	ASSERT(thread->sth_state == SMB_THREAD_STATE_STARTING);
85511963SAfshin.Ardakani@Sun.COM 	thread->sth_th = curthread;
85611963SAfshin.Ardakani@Sun.COM 	thread->sth_did = thread->sth_th->t_did;
85711963SAfshin.Ardakani@Sun.COM 
85811963SAfshin.Ardakani@Sun.COM 	if (!thread->sth_kill) {
85911963SAfshin.Ardakani@Sun.COM 		thread->sth_state = SMB_THREAD_STATE_RUNNING;
86011963SAfshin.Ardakani@Sun.COM 		cv_signal(&thread->sth_cv);
86111963SAfshin.Ardakani@Sun.COM 		mutex_exit(&thread->sth_mtx);
86211963SAfshin.Ardakani@Sun.COM 		thread->sth_ep(thread, thread->sth_ep_arg);
86311963SAfshin.Ardakani@Sun.COM 		mutex_enter(&thread->sth_mtx);
86411963SAfshin.Ardakani@Sun.COM 	}
86511963SAfshin.Ardakani@Sun.COM 	thread->sth_th = NULL;
86611963SAfshin.Ardakani@Sun.COM 	thread->sth_state = SMB_THREAD_STATE_EXITING;
86711963SAfshin.Ardakani@Sun.COM 	cv_broadcast(&thread->sth_cv);
86811963SAfshin.Ardakani@Sun.COM 	mutex_exit(&thread->sth_mtx);
86911963SAfshin.Ardakani@Sun.COM 	thread_exit();
87011963SAfshin.Ardakani@Sun.COM }
87111963SAfshin.Ardakani@Sun.COM 
87211963SAfshin.Ardakani@Sun.COM /*
87311963SAfshin.Ardakani@Sun.COM  * smb_thread_init
87411963SAfshin.Ardakani@Sun.COM  */
87511963SAfshin.Ardakani@Sun.COM void
87611963SAfshin.Ardakani@Sun.COM smb_thread_init(
87711963SAfshin.Ardakani@Sun.COM     smb_thread_t	*thread,
87811963SAfshin.Ardakani@Sun.COM     char		*name,
87911963SAfshin.Ardakani@Sun.COM     smb_thread_ep_t	ep,
88011963SAfshin.Ardakani@Sun.COM     void		*ep_arg,
88111963SAfshin.Ardakani@Sun.COM     smb_thread_aw_t	aw,
88211963SAfshin.Ardakani@Sun.COM     void		*aw_arg)
88311963SAfshin.Ardakani@Sun.COM {
88411963SAfshin.Ardakani@Sun.COM 	ASSERT(thread->sth_magic != SMB_THREAD_MAGIC);
88511963SAfshin.Ardakani@Sun.COM 
88611963SAfshin.Ardakani@Sun.COM 	bzero(thread, sizeof (*thread));
88711963SAfshin.Ardakani@Sun.COM 
88811963SAfshin.Ardakani@Sun.COM 	(void) strlcpy(thread->sth_name, name, sizeof (thread->sth_name));
88911963SAfshin.Ardakani@Sun.COM 	thread->sth_ep = ep;
89011963SAfshin.Ardakani@Sun.COM 	thread->sth_ep_arg = ep_arg;
89111963SAfshin.Ardakani@Sun.COM 	thread->sth_aw = aw;
89211963SAfshin.Ardakani@Sun.COM 	thread->sth_aw_arg = aw_arg;
89311963SAfshin.Ardakani@Sun.COM 	thread->sth_state = SMB_THREAD_STATE_EXITED;
89411963SAfshin.Ardakani@Sun.COM 	mutex_init(&thread->sth_mtx, NULL, MUTEX_DEFAULT, NULL);
89511963SAfshin.Ardakani@Sun.COM 	cv_init(&thread->sth_cv, NULL, CV_DEFAULT, NULL);
89611963SAfshin.Ardakani@Sun.COM 	thread->sth_magic = SMB_THREAD_MAGIC;
89711963SAfshin.Ardakani@Sun.COM }
89811963SAfshin.Ardakani@Sun.COM 
89911963SAfshin.Ardakani@Sun.COM /*
90011963SAfshin.Ardakani@Sun.COM  * smb_thread_destroy
90111963SAfshin.Ardakani@Sun.COM  */
90211963SAfshin.Ardakani@Sun.COM void
90311963SAfshin.Ardakani@Sun.COM smb_thread_destroy(
90411963SAfshin.Ardakani@Sun.COM     smb_thread_t	*thread)
90511963SAfshin.Ardakani@Sun.COM {
90611963SAfshin.Ardakani@Sun.COM 	ASSERT(thread->sth_magic == SMB_THREAD_MAGIC);
90711963SAfshin.Ardakani@Sun.COM 	ASSERT(thread->sth_state == SMB_THREAD_STATE_EXITED);
90811963SAfshin.Ardakani@Sun.COM 	thread->sth_magic = 0;
90911963SAfshin.Ardakani@Sun.COM 	mutex_destroy(&thread->sth_mtx);
91011963SAfshin.Ardakani@Sun.COM 	cv_destroy(&thread->sth_cv);
91111963SAfshin.Ardakani@Sun.COM }
91211963SAfshin.Ardakani@Sun.COM 
91311963SAfshin.Ardakani@Sun.COM /*
91411963SAfshin.Ardakani@Sun.COM  * smb_thread_start
91511963SAfshin.Ardakani@Sun.COM  *
91611963SAfshin.Ardakani@Sun.COM  * This function starts a thread with the parameters provided. It waits until
91711963SAfshin.Ardakani@Sun.COM  * the state of the thread has been moved to running.
91811963SAfshin.Ardakani@Sun.COM  */
91911963SAfshin.Ardakani@Sun.COM /*ARGSUSED*/
92011963SAfshin.Ardakani@Sun.COM int
92111963SAfshin.Ardakani@Sun.COM smb_thread_start(
92211963SAfshin.Ardakani@Sun.COM     smb_thread_t	*thread)
92311963SAfshin.Ardakani@Sun.COM {
92411963SAfshin.Ardakani@Sun.COM 	int		rc = 0;
92511963SAfshin.Ardakani@Sun.COM 	kthread_t	*tmpthread;
92611963SAfshin.Ardakani@Sun.COM 
92711963SAfshin.Ardakani@Sun.COM 	ASSERT(thread->sth_magic == SMB_THREAD_MAGIC);
92811963SAfshin.Ardakani@Sun.COM 
92911963SAfshin.Ardakani@Sun.COM 	mutex_enter(&thread->sth_mtx);
93011963SAfshin.Ardakani@Sun.COM 	switch (thread->sth_state) {
93111963SAfshin.Ardakani@Sun.COM 	case SMB_THREAD_STATE_EXITED:
93211963SAfshin.Ardakani@Sun.COM 		thread->sth_state = SMB_THREAD_STATE_STARTING;
93311963SAfshin.Ardakani@Sun.COM 		mutex_exit(&thread->sth_mtx);
93411963SAfshin.Ardakani@Sun.COM 		tmpthread = thread_create(NULL, 0, smb_thread_entry_point,
93511963SAfshin.Ardakani@Sun.COM 		    thread, 0, &p0, TS_RUN, minclsyspri);
93611963SAfshin.Ardakani@Sun.COM 		ASSERT(tmpthread != NULL);
93711963SAfshin.Ardakani@Sun.COM 		mutex_enter(&thread->sth_mtx);
93811963SAfshin.Ardakani@Sun.COM 		while (thread->sth_state == SMB_THREAD_STATE_STARTING)
93911963SAfshin.Ardakani@Sun.COM 			cv_wait(&thread->sth_cv, &thread->sth_mtx);
94011963SAfshin.Ardakani@Sun.COM 		if (thread->sth_state != SMB_THREAD_STATE_RUNNING)
94111963SAfshin.Ardakani@Sun.COM 			rc = -1;
94211963SAfshin.Ardakani@Sun.COM 		break;
94311963SAfshin.Ardakani@Sun.COM 	default:
94411963SAfshin.Ardakani@Sun.COM 		ASSERT(0);
94511963SAfshin.Ardakani@Sun.COM 		rc = -1;
94611963SAfshin.Ardakani@Sun.COM 		break;
94711963SAfshin.Ardakani@Sun.COM 	}
94811963SAfshin.Ardakani@Sun.COM 	mutex_exit(&thread->sth_mtx);
94911963SAfshin.Ardakani@Sun.COM 	return (rc);
95011963SAfshin.Ardakani@Sun.COM }
95111963SAfshin.Ardakani@Sun.COM 
95211963SAfshin.Ardakani@Sun.COM /*
95311963SAfshin.Ardakani@Sun.COM  * smb_thread_stop
95411963SAfshin.Ardakani@Sun.COM  *
95511963SAfshin.Ardakani@Sun.COM  * This function signals a thread to kill itself and waits until the "exiting"
95611963SAfshin.Ardakani@Sun.COM  * state has been reached.
95711963SAfshin.Ardakani@Sun.COM  */
95811963SAfshin.Ardakani@Sun.COM void
95911963SAfshin.Ardakani@Sun.COM smb_thread_stop(
96011963SAfshin.Ardakani@Sun.COM     smb_thread_t	*thread)
96111963SAfshin.Ardakani@Sun.COM {
96211963SAfshin.Ardakani@Sun.COM 	ASSERT(thread->sth_magic == SMB_THREAD_MAGIC);
96311963SAfshin.Ardakani@Sun.COM 
96411963SAfshin.Ardakani@Sun.COM 	mutex_enter(&thread->sth_mtx);
96511963SAfshin.Ardakani@Sun.COM 	switch (thread->sth_state) {
96611963SAfshin.Ardakani@Sun.COM 	case SMB_THREAD_STATE_RUNNING:
96711963SAfshin.Ardakani@Sun.COM 	case SMB_THREAD_STATE_STARTING:
96811963SAfshin.Ardakani@Sun.COM 		if (!thread->sth_kill) {
96911963SAfshin.Ardakani@Sun.COM 			thread->sth_kill = B_TRUE;
97011963SAfshin.Ardakani@Sun.COM 			if (thread->sth_aw)
97111963SAfshin.Ardakani@Sun.COM 				thread->sth_aw(thread, thread->sth_aw_arg);
97211963SAfshin.Ardakani@Sun.COM 			cv_broadcast(&thread->sth_cv);
97311963SAfshin.Ardakani@Sun.COM 			while (thread->sth_state != SMB_THREAD_STATE_EXITING)
97411963SAfshin.Ardakani@Sun.COM 				cv_wait(&thread->sth_cv, &thread->sth_mtx);
97511963SAfshin.Ardakani@Sun.COM 			mutex_exit(&thread->sth_mtx);
97611963SAfshin.Ardakani@Sun.COM 			thread_join(thread->sth_did);
97711963SAfshin.Ardakani@Sun.COM 			mutex_enter(&thread->sth_mtx);
97811963SAfshin.Ardakani@Sun.COM 			thread->sth_state = SMB_THREAD_STATE_EXITED;
97911963SAfshin.Ardakani@Sun.COM 			thread->sth_did = 0;
98011963SAfshin.Ardakani@Sun.COM 			thread->sth_kill = B_FALSE;
98111963SAfshin.Ardakani@Sun.COM 			cv_broadcast(&thread->sth_cv);
98211963SAfshin.Ardakani@Sun.COM 			break;
98311963SAfshin.Ardakani@Sun.COM 		}
98411963SAfshin.Ardakani@Sun.COM 		/*FALLTHRU*/
98511963SAfshin.Ardakani@Sun.COM 
98611963SAfshin.Ardakani@Sun.COM 	case SMB_THREAD_STATE_EXITING:
98711963SAfshin.Ardakani@Sun.COM 		if (thread->sth_kill) {
98811963SAfshin.Ardakani@Sun.COM 			while (thread->sth_state != SMB_THREAD_STATE_EXITED)
98911963SAfshin.Ardakani@Sun.COM 				cv_wait(&thread->sth_cv, &thread->sth_mtx);
99011963SAfshin.Ardakani@Sun.COM 		} else {
99111963SAfshin.Ardakani@Sun.COM 			thread->sth_state = SMB_THREAD_STATE_EXITED;
99211963SAfshin.Ardakani@Sun.COM 			thread->sth_did = 0;
99311963SAfshin.Ardakani@Sun.COM 		}
99411963SAfshin.Ardakani@Sun.COM 		break;
99511963SAfshin.Ardakani@Sun.COM 
99611963SAfshin.Ardakani@Sun.COM 	case SMB_THREAD_STATE_EXITED:
99711963SAfshin.Ardakani@Sun.COM 		break;
99811963SAfshin.Ardakani@Sun.COM 
99911963SAfshin.Ardakani@Sun.COM 	default:
100011963SAfshin.Ardakani@Sun.COM 		ASSERT(0);
100111963SAfshin.Ardakani@Sun.COM 		break;
100211963SAfshin.Ardakani@Sun.COM 	}
100311963SAfshin.Ardakani@Sun.COM 	mutex_exit(&thread->sth_mtx);
100411963SAfshin.Ardakani@Sun.COM }
100511963SAfshin.Ardakani@Sun.COM 
100611963SAfshin.Ardakani@Sun.COM /*
100711963SAfshin.Ardakani@Sun.COM  * smb_thread_signal
100811963SAfshin.Ardakani@Sun.COM  *
100911963SAfshin.Ardakani@Sun.COM  * This function signals a thread.
101011963SAfshin.Ardakani@Sun.COM  */
101111963SAfshin.Ardakani@Sun.COM void
101211963SAfshin.Ardakani@Sun.COM smb_thread_signal(
101311963SAfshin.Ardakani@Sun.COM     smb_thread_t	*thread)
101411963SAfshin.Ardakani@Sun.COM {
101511963SAfshin.Ardakani@Sun.COM 	ASSERT(thread->sth_magic == SMB_THREAD_MAGIC);
101611963SAfshin.Ardakani@Sun.COM 
101711963SAfshin.Ardakani@Sun.COM 	mutex_enter(&thread->sth_mtx);
101811963SAfshin.Ardakani@Sun.COM 	switch (thread->sth_state) {
101911963SAfshin.Ardakani@Sun.COM 	case SMB_THREAD_STATE_RUNNING:
102011963SAfshin.Ardakani@Sun.COM 		if (thread->sth_aw)
102111963SAfshin.Ardakani@Sun.COM 			thread->sth_aw(thread, thread->sth_aw_arg);
102211963SAfshin.Ardakani@Sun.COM 		cv_signal(&thread->sth_cv);
102311963SAfshin.Ardakani@Sun.COM 		break;
102411963SAfshin.Ardakani@Sun.COM 
102511963SAfshin.Ardakani@Sun.COM 	default:
102611963SAfshin.Ardakani@Sun.COM 		break;
102711963SAfshin.Ardakani@Sun.COM 	}
102811963SAfshin.Ardakani@Sun.COM 	mutex_exit(&thread->sth_mtx);
102911963SAfshin.Ardakani@Sun.COM }
103011963SAfshin.Ardakani@Sun.COM 
103111963SAfshin.Ardakani@Sun.COM boolean_t
103211963SAfshin.Ardakani@Sun.COM smb_thread_continue(smb_thread_t *thread)
103311963SAfshin.Ardakani@Sun.COM {
103411963SAfshin.Ardakani@Sun.COM 	boolean_t result;
103511963SAfshin.Ardakani@Sun.COM 
103611963SAfshin.Ardakani@Sun.COM 	ASSERT(thread->sth_magic == SMB_THREAD_MAGIC);
103711963SAfshin.Ardakani@Sun.COM 
103811963SAfshin.Ardakani@Sun.COM 	mutex_enter(&thread->sth_mtx);
103911963SAfshin.Ardakani@Sun.COM 	result = smb_thread_continue_timedwait_locked(thread, 0);
104011963SAfshin.Ardakani@Sun.COM 	mutex_exit(&thread->sth_mtx);
104111963SAfshin.Ardakani@Sun.COM 
104211963SAfshin.Ardakani@Sun.COM 	return (result);
104311963SAfshin.Ardakani@Sun.COM }
104411963SAfshin.Ardakani@Sun.COM 
104511963SAfshin.Ardakani@Sun.COM boolean_t
104611963SAfshin.Ardakani@Sun.COM smb_thread_continue_nowait(smb_thread_t *thread)
104711963SAfshin.Ardakani@Sun.COM {
104811963SAfshin.Ardakani@Sun.COM 	boolean_t result;
104911963SAfshin.Ardakani@Sun.COM 
105011963SAfshin.Ardakani@Sun.COM 	ASSERT(thread->sth_magic == SMB_THREAD_MAGIC);
105111963SAfshin.Ardakani@Sun.COM 
105211963SAfshin.Ardakani@Sun.COM 	mutex_enter(&thread->sth_mtx);
105311963SAfshin.Ardakani@Sun.COM 	/*
105411963SAfshin.Ardakani@Sun.COM 	 * Setting ticks=-1 requests a non-blocking check.  We will
105511963SAfshin.Ardakani@Sun.COM 	 * still block if the thread is in "suspend" state.
105611963SAfshin.Ardakani@Sun.COM 	 */
105711963SAfshin.Ardakani@Sun.COM 	result = smb_thread_continue_timedwait_locked(thread, -1);
105811963SAfshin.Ardakani@Sun.COM 	mutex_exit(&thread->sth_mtx);
105911963SAfshin.Ardakani@Sun.COM 
106011963SAfshin.Ardakani@Sun.COM 	return (result);
106111963SAfshin.Ardakani@Sun.COM }
106211963SAfshin.Ardakani@Sun.COM 
106311963SAfshin.Ardakani@Sun.COM boolean_t
106411963SAfshin.Ardakani@Sun.COM smb_thread_continue_timedwait(smb_thread_t *thread, int seconds)
106511963SAfshin.Ardakani@Sun.COM {
106611963SAfshin.Ardakani@Sun.COM 	boolean_t result;
106711963SAfshin.Ardakani@Sun.COM 
106811963SAfshin.Ardakani@Sun.COM 	ASSERT(thread->sth_magic == SMB_THREAD_MAGIC);
106911963SAfshin.Ardakani@Sun.COM 
107011963SAfshin.Ardakani@Sun.COM 	mutex_enter(&thread->sth_mtx);
107111963SAfshin.Ardakani@Sun.COM 	result = smb_thread_continue_timedwait_locked(thread,
107211963SAfshin.Ardakani@Sun.COM 	    SEC_TO_TICK(seconds));
107311963SAfshin.Ardakani@Sun.COM 	mutex_exit(&thread->sth_mtx);
107411963SAfshin.Ardakani@Sun.COM 
107511963SAfshin.Ardakani@Sun.COM 	return (result);
107611963SAfshin.Ardakani@Sun.COM }
107711963SAfshin.Ardakani@Sun.COM 
107811963SAfshin.Ardakani@Sun.COM /*
107911963SAfshin.Ardakani@Sun.COM  * smb_thread_continue_timedwait_locked
108011963SAfshin.Ardakani@Sun.COM  *
108111963SAfshin.Ardakani@Sun.COM  * Internal only.  Ticks==-1 means don't block, Ticks == 0 means wait
108211963SAfshin.Ardakani@Sun.COM  * indefinitely
108311963SAfshin.Ardakani@Sun.COM  */
108411963SAfshin.Ardakani@Sun.COM static boolean_t
108511963SAfshin.Ardakani@Sun.COM smb_thread_continue_timedwait_locked(smb_thread_t *thread, int ticks)
108611963SAfshin.Ardakani@Sun.COM {
108711963SAfshin.Ardakani@Sun.COM 	boolean_t	result;
108811963SAfshin.Ardakani@Sun.COM 
108911963SAfshin.Ardakani@Sun.COM 	/* -1 means don't block */
109011963SAfshin.Ardakani@Sun.COM 	if (ticks != -1 && !thread->sth_kill) {
109111963SAfshin.Ardakani@Sun.COM 		if (ticks == 0) {
109211963SAfshin.Ardakani@Sun.COM 			cv_wait(&thread->sth_cv, &thread->sth_mtx);
109311963SAfshin.Ardakani@Sun.COM 		} else {
109411963SAfshin.Ardakani@Sun.COM 			(void) cv_reltimedwait(&thread->sth_cv,
109511963SAfshin.Ardakani@Sun.COM 			    &thread->sth_mtx, (clock_t)ticks, TR_CLOCK_TICK);
109611963SAfshin.Ardakani@Sun.COM 		}
109711963SAfshin.Ardakani@Sun.COM 	}
109811963SAfshin.Ardakani@Sun.COM 	result = (thread->sth_kill == 0);
109911963SAfshin.Ardakani@Sun.COM 
110011963SAfshin.Ardakani@Sun.COM 	return (result);
110111963SAfshin.Ardakani@Sun.COM }
110211963SAfshin.Ardakani@Sun.COM 
110311963SAfshin.Ardakani@Sun.COM void
110411963SAfshin.Ardakani@Sun.COM smb_thread_set_awaken(smb_thread_t *thread, smb_thread_aw_t new_aw_fn,
110511963SAfshin.Ardakani@Sun.COM     void *new_aw_arg)
110611963SAfshin.Ardakani@Sun.COM {
110711963SAfshin.Ardakani@Sun.COM 	ASSERT(thread->sth_magic == SMB_THREAD_MAGIC);
110811963SAfshin.Ardakani@Sun.COM 
110911963SAfshin.Ardakani@Sun.COM 	mutex_enter(&thread->sth_mtx);
111011963SAfshin.Ardakani@Sun.COM 	thread->sth_aw = new_aw_fn;
111111963SAfshin.Ardakani@Sun.COM 	thread->sth_aw_arg = new_aw_arg;
111211963SAfshin.Ardakani@Sun.COM 	mutex_exit(&thread->sth_mtx);
111311963SAfshin.Ardakani@Sun.COM }
111411963SAfshin.Ardakani@Sun.COM 
111511963SAfshin.Ardakani@Sun.COM /*
111611963SAfshin.Ardakani@Sun.COM  * smb_rwx_init
111711963SAfshin.Ardakani@Sun.COM  */
111811963SAfshin.Ardakani@Sun.COM void
111911963SAfshin.Ardakani@Sun.COM smb_rwx_init(
112011963SAfshin.Ardakani@Sun.COM     smb_rwx_t	*rwx)
112111963SAfshin.Ardakani@Sun.COM {
112211963SAfshin.Ardakani@Sun.COM 	bzero(rwx, sizeof (smb_rwx_t));
112311963SAfshin.Ardakani@Sun.COM 	cv_init(&rwx->rwx_cv, NULL, CV_DEFAULT, NULL);
112411963SAfshin.Ardakani@Sun.COM 	mutex_init(&rwx->rwx_mutex, NULL, MUTEX_DEFAULT, NULL);
112511963SAfshin.Ardakani@Sun.COM 	rw_init(&rwx->rwx_lock, NULL, RW_DEFAULT, NULL);
112611963SAfshin.Ardakani@Sun.COM }
112711963SAfshin.Ardakani@Sun.COM 
112811963SAfshin.Ardakani@Sun.COM /*
112911963SAfshin.Ardakani@Sun.COM  * smb_rwx_destroy
113011963SAfshin.Ardakani@Sun.COM  */
113111963SAfshin.Ardakani@Sun.COM void
113211963SAfshin.Ardakani@Sun.COM smb_rwx_destroy(
113311963SAfshin.Ardakani@Sun.COM     smb_rwx_t	*rwx)
113411963SAfshin.Ardakani@Sun.COM {
113511963SAfshin.Ardakani@Sun.COM 	mutex_destroy(&rwx->rwx_mutex);
113611963SAfshin.Ardakani@Sun.COM 	cv_destroy(&rwx->rwx_cv);
113711963SAfshin.Ardakani@Sun.COM 	rw_destroy(&rwx->rwx_lock);
113811963SAfshin.Ardakani@Sun.COM }
113911963SAfshin.Ardakani@Sun.COM 
114011963SAfshin.Ardakani@Sun.COM /*
114111963SAfshin.Ardakani@Sun.COM  * smb_rwx_rwexit
114211963SAfshin.Ardakani@Sun.COM  */
114311963SAfshin.Ardakani@Sun.COM void
114411963SAfshin.Ardakani@Sun.COM smb_rwx_rwexit(
114511963SAfshin.Ardakani@Sun.COM     smb_rwx_t	*rwx)
114611963SAfshin.Ardakani@Sun.COM {
114711963SAfshin.Ardakani@Sun.COM 	if (rw_write_held(&rwx->rwx_lock)) {
114811963SAfshin.Ardakani@Sun.COM 		ASSERT(rw_owner(&rwx->rwx_lock) == curthread);
114911963SAfshin.Ardakani@Sun.COM 		mutex_enter(&rwx->rwx_mutex);
115011963SAfshin.Ardakani@Sun.COM 		if (rwx->rwx_waiting) {
115111963SAfshin.Ardakani@Sun.COM 			rwx->rwx_waiting = B_FALSE;
115211963SAfshin.Ardakani@Sun.COM 			cv_broadcast(&rwx->rwx_cv);
115311963SAfshin.Ardakani@Sun.COM 		}
115411963SAfshin.Ardakani@Sun.COM 		mutex_exit(&rwx->rwx_mutex);
115511963SAfshin.Ardakani@Sun.COM 	}
115611963SAfshin.Ardakani@Sun.COM 	rw_exit(&rwx->rwx_lock);
115711963SAfshin.Ardakani@Sun.COM }
115811963SAfshin.Ardakani@Sun.COM 
115911963SAfshin.Ardakani@Sun.COM /*
116011963SAfshin.Ardakani@Sun.COM  * smb_rwx_rwupgrade
116111963SAfshin.Ardakani@Sun.COM  */
116211963SAfshin.Ardakani@Sun.COM krw_t
116311963SAfshin.Ardakani@Sun.COM smb_rwx_rwupgrade(
116411963SAfshin.Ardakani@Sun.COM     smb_rwx_t	*rwx)
116511963SAfshin.Ardakani@Sun.COM {
116611963SAfshin.Ardakani@Sun.COM 	if (rw_write_held(&rwx->rwx_lock)) {
116711963SAfshin.Ardakani@Sun.COM 		ASSERT(rw_owner(&rwx->rwx_lock) == curthread);
116811963SAfshin.Ardakani@Sun.COM 		return (RW_WRITER);
116911963SAfshin.Ardakani@Sun.COM 	}
117011963SAfshin.Ardakani@Sun.COM 	if (!rw_tryupgrade(&rwx->rwx_lock)) {
117111963SAfshin.Ardakani@Sun.COM 		rw_exit(&rwx->rwx_lock);
117211963SAfshin.Ardakani@Sun.COM 		rw_enter(&rwx->rwx_lock, RW_WRITER);
117311963SAfshin.Ardakani@Sun.COM 	}
117411963SAfshin.Ardakani@Sun.COM 	return (RW_READER);
117511963SAfshin.Ardakani@Sun.COM }
117611963SAfshin.Ardakani@Sun.COM 
117711963SAfshin.Ardakani@Sun.COM /*
117811963SAfshin.Ardakani@Sun.COM  * smb_rwx_rwrestore
117911963SAfshin.Ardakani@Sun.COM  */
118011963SAfshin.Ardakani@Sun.COM void
118111963SAfshin.Ardakani@Sun.COM smb_rwx_rwdowngrade(
118211963SAfshin.Ardakani@Sun.COM     smb_rwx_t	*rwx,
118311963SAfshin.Ardakani@Sun.COM     krw_t	mode)
118411963SAfshin.Ardakani@Sun.COM {
118511963SAfshin.Ardakani@Sun.COM 	ASSERT(rw_write_held(&rwx->rwx_lock));
118611963SAfshin.Ardakani@Sun.COM 	ASSERT(rw_owner(&rwx->rwx_lock) == curthread);
118711963SAfshin.Ardakani@Sun.COM 
118811963SAfshin.Ardakani@Sun.COM 	if (mode == RW_WRITER) {
118911963SAfshin.Ardakani@Sun.COM 		return;
119011963SAfshin.Ardakani@Sun.COM 	}
119111963SAfshin.Ardakani@Sun.COM 	ASSERT(mode == RW_READER);
119211963SAfshin.Ardakani@Sun.COM 	mutex_enter(&rwx->rwx_mutex);
119311963SAfshin.Ardakani@Sun.COM 	if (rwx->rwx_waiting) {
119411963SAfshin.Ardakani@Sun.COM 		rwx->rwx_waiting = B_FALSE;
119511963SAfshin.Ardakani@Sun.COM 		cv_broadcast(&rwx->rwx_cv);
119611963SAfshin.Ardakani@Sun.COM 	}
119711963SAfshin.Ardakani@Sun.COM 	mutex_exit(&rwx->rwx_mutex);
119811963SAfshin.Ardakani@Sun.COM 	rw_downgrade(&rwx->rwx_lock);
119911963SAfshin.Ardakani@Sun.COM }
120011963SAfshin.Ardakani@Sun.COM 
120111963SAfshin.Ardakani@Sun.COM /*
120211963SAfshin.Ardakani@Sun.COM  * smb_rwx_wait
120311963SAfshin.Ardakani@Sun.COM  *
120411963SAfshin.Ardakani@Sun.COM  * This function assumes the smb_rwx lock was enter in RW_READER or RW_WRITER
120511963SAfshin.Ardakani@Sun.COM  * mode. It will:
120611963SAfshin.Ardakani@Sun.COM  *
120711963SAfshin.Ardakani@Sun.COM  *	1) release the lock and save its current mode.
120811963SAfshin.Ardakani@Sun.COM  *	2) wait until the condition variable is signaled. This can happen for
120911963SAfshin.Ardakani@Sun.COM  *	   2 reasons: When a writer releases the lock or when the time out (if
121011963SAfshin.Ardakani@Sun.COM  *	   provided) expires.
121111963SAfshin.Ardakani@Sun.COM  *	3) re-acquire the lock in the mode saved in (1).
121211963SAfshin.Ardakani@Sun.COM  */
121311963SAfshin.Ardakani@Sun.COM int
121411963SAfshin.Ardakani@Sun.COM smb_rwx_rwwait(
121511963SAfshin.Ardakani@Sun.COM     smb_rwx_t	*rwx,
121611963SAfshin.Ardakani@Sun.COM     clock_t	timeout)
121711963SAfshin.Ardakani@Sun.COM {
121811963SAfshin.Ardakani@Sun.COM 	int	rc;
121911963SAfshin.Ardakani@Sun.COM 	krw_t	mode;
122011963SAfshin.Ardakani@Sun.COM 
122111963SAfshin.Ardakani@Sun.COM 	mutex_enter(&rwx->rwx_mutex);
122211963SAfshin.Ardakani@Sun.COM 	rwx->rwx_waiting = B_TRUE;
122311963SAfshin.Ardakani@Sun.COM 	mutex_exit(&rwx->rwx_mutex);
122411963SAfshin.Ardakani@Sun.COM 
122511963SAfshin.Ardakani@Sun.COM 	if (rw_write_held(&rwx->rwx_lock)) {
122611963SAfshin.Ardakani@Sun.COM 		ASSERT(rw_owner(&rwx->rwx_lock) == curthread);
122711963SAfshin.Ardakani@Sun.COM 		mode = RW_WRITER;
122811963SAfshin.Ardakani@Sun.COM 	} else {
122911963SAfshin.Ardakani@Sun.COM 		ASSERT(rw_read_held(&rwx->rwx_lock));
123011963SAfshin.Ardakani@Sun.COM 		mode = RW_READER;
123111963SAfshin.Ardakani@Sun.COM 	}
123211963SAfshin.Ardakani@Sun.COM 	rw_exit(&rwx->rwx_lock);
123311963SAfshin.Ardakani@Sun.COM 
123411963SAfshin.Ardakani@Sun.COM 	mutex_enter(&rwx->rwx_mutex);
123511963SAfshin.Ardakani@Sun.COM 	if (rwx->rwx_waiting) {
123611963SAfshin.Ardakani@Sun.COM 		if (timeout == -1) {
123711963SAfshin.Ardakani@Sun.COM 			rc = 1;
123811963SAfshin.Ardakani@Sun.COM 			cv_wait(&rwx->rwx_cv, &rwx->rwx_mutex);
123911963SAfshin.Ardakani@Sun.COM 		} else {
124011963SAfshin.Ardakani@Sun.COM 			rc = cv_reltimedwait(&rwx->rwx_cv, &rwx->rwx_mutex,
124111963SAfshin.Ardakani@Sun.COM 			    timeout, TR_CLOCK_TICK);
124211963SAfshin.Ardakani@Sun.COM 		}
124311963SAfshin.Ardakani@Sun.COM 	}
124411963SAfshin.Ardakani@Sun.COM 	mutex_exit(&rwx->rwx_mutex);
124511963SAfshin.Ardakani@Sun.COM 
124611963SAfshin.Ardakani@Sun.COM 	rw_enter(&rwx->rwx_lock, mode);
124711963SAfshin.Ardakani@Sun.COM 	return (rc);
124811963SAfshin.Ardakani@Sun.COM }
124911963SAfshin.Ardakani@Sun.COM 
125011963SAfshin.Ardakani@Sun.COM /*
125111963SAfshin.Ardakani@Sun.COM  * SMB ID mapping
125211963SAfshin.Ardakani@Sun.COM  *
125311963SAfshin.Ardakani@Sun.COM  * Solaris ID mapping service (aka Winchester) works with domain SIDs
125411963SAfshin.Ardakani@Sun.COM  * and RIDs where domain SIDs are in string format. CIFS service works
125511963SAfshin.Ardakani@Sun.COM  * with binary SIDs understandable by CIFS clients. A layer of SMB ID
125611963SAfshin.Ardakani@Sun.COM  * mapping functions are implemeted to hide the SID conversion details
125711963SAfshin.Ardakani@Sun.COM  * and also hide the handling of array of batch mapping requests.
125811963SAfshin.Ardakani@Sun.COM  *
125911963SAfshin.Ardakani@Sun.COM  * IMPORTANT NOTE The Winchester API requires a zone. Because CIFS server
126011963SAfshin.Ardakani@Sun.COM  * currently only runs in the global zone the global zone is specified.
126111963SAfshin.Ardakani@Sun.COM  * This needs to be fixed when the CIFS server supports zones.
126211963SAfshin.Ardakani@Sun.COM  */
126311963SAfshin.Ardakani@Sun.COM 
126411963SAfshin.Ardakani@Sun.COM static int smb_idmap_batch_binsid(smb_idmap_batch_t *sib);
126511963SAfshin.Ardakani@Sun.COM 
126611963SAfshin.Ardakani@Sun.COM /*
126711963SAfshin.Ardakani@Sun.COM  * smb_idmap_getid
126811963SAfshin.Ardakani@Sun.COM  *
126911963SAfshin.Ardakani@Sun.COM  * Maps the given Windows SID to a Solaris ID using the
127011963SAfshin.Ardakani@Sun.COM  * simple mapping API.
127111963SAfshin.Ardakani@Sun.COM  */
127211963SAfshin.Ardakani@Sun.COM idmap_stat
127311963SAfshin.Ardakani@Sun.COM smb_idmap_getid(smb_sid_t *sid, uid_t *id, int *idtype)
127411963SAfshin.Ardakani@Sun.COM {
127511963SAfshin.Ardakani@Sun.COM 	smb_idmap_t sim;
127611963SAfshin.Ardakani@Sun.COM 	char sidstr[SMB_SID_STRSZ];
127711963SAfshin.Ardakani@Sun.COM 
127811963SAfshin.Ardakani@Sun.COM 	smb_sid_tostr(sid, sidstr);
127911963SAfshin.Ardakani@Sun.COM 	if (smb_sid_splitstr(sidstr, &sim.sim_rid) != 0)
128011963SAfshin.Ardakani@Sun.COM 		return (IDMAP_ERR_SID);
128111963SAfshin.Ardakani@Sun.COM 	sim.sim_domsid = sidstr;
128211963SAfshin.Ardakani@Sun.COM 	sim.sim_id = id;
128311963SAfshin.Ardakani@Sun.COM 
128411963SAfshin.Ardakani@Sun.COM 	switch (*idtype) {
128511963SAfshin.Ardakani@Sun.COM 	case SMB_IDMAP_USER:
128611963SAfshin.Ardakani@Sun.COM 		sim.sim_stat = kidmap_getuidbysid(global_zone, sim.sim_domsid,
128711963SAfshin.Ardakani@Sun.COM 		    sim.sim_rid, sim.sim_id);
128811963SAfshin.Ardakani@Sun.COM 		break;
128911963SAfshin.Ardakani@Sun.COM 
129011963SAfshin.Ardakani@Sun.COM 	case SMB_IDMAP_GROUP:
129111963SAfshin.Ardakani@Sun.COM 		sim.sim_stat = kidmap_getgidbysid(global_zone, sim.sim_domsid,
129211963SAfshin.Ardakani@Sun.COM 		    sim.sim_rid, sim.sim_id);
129311963SAfshin.Ardakani@Sun.COM 		break;
129411963SAfshin.Ardakani@Sun.COM 
129511963SAfshin.Ardakani@Sun.COM 	case SMB_IDMAP_UNKNOWN:
129611963SAfshin.Ardakani@Sun.COM 		sim.sim_stat = kidmap_getpidbysid(global_zone, sim.sim_domsid,
129711963SAfshin.Ardakani@Sun.COM 		    sim.sim_rid, sim.sim_id, &sim.sim_idtype);
129811963SAfshin.Ardakani@Sun.COM 		break;
129911963SAfshin.Ardakani@Sun.COM 
130011963SAfshin.Ardakani@Sun.COM 	default:
130111963SAfshin.Ardakani@Sun.COM 		ASSERT(0);
130211963SAfshin.Ardakani@Sun.COM 		return (IDMAP_ERR_ARG);
130311963SAfshin.Ardakani@Sun.COM 	}
130411963SAfshin.Ardakani@Sun.COM 
130511963SAfshin.Ardakani@Sun.COM 	*idtype = sim.sim_idtype;
130611963SAfshin.Ardakani@Sun.COM 
130711963SAfshin.Ardakani@Sun.COM 	return (sim.sim_stat);
130811963SAfshin.Ardakani@Sun.COM }
130911963SAfshin.Ardakani@Sun.COM 
131011963SAfshin.Ardakani@Sun.COM /*
131111963SAfshin.Ardakani@Sun.COM  * smb_idmap_getsid
131211963SAfshin.Ardakani@Sun.COM  *
131311963SAfshin.Ardakani@Sun.COM  * Maps the given Solaris ID to a Windows SID using the
131411963SAfshin.Ardakani@Sun.COM  * simple mapping API.
131511963SAfshin.Ardakani@Sun.COM  */
131611963SAfshin.Ardakani@Sun.COM idmap_stat
131711963SAfshin.Ardakani@Sun.COM smb_idmap_getsid(uid_t id, int idtype, smb_sid_t **sid)
131811963SAfshin.Ardakani@Sun.COM {
131911963SAfshin.Ardakani@Sun.COM 	smb_idmap_t sim;
132011963SAfshin.Ardakani@Sun.COM 
132111963SAfshin.Ardakani@Sun.COM 	switch (idtype) {
132211963SAfshin.Ardakani@Sun.COM 	case SMB_IDMAP_USER:
132311963SAfshin.Ardakani@Sun.COM 		sim.sim_stat = kidmap_getsidbyuid(global_zone, id,
132411963SAfshin.Ardakani@Sun.COM 		    (const char **)&sim.sim_domsid, &sim.sim_rid);
132511963SAfshin.Ardakani@Sun.COM 		break;
132611963SAfshin.Ardakani@Sun.COM 
132711963SAfshin.Ardakani@Sun.COM 	case SMB_IDMAP_GROUP:
132811963SAfshin.Ardakani@Sun.COM 		sim.sim_stat = kidmap_getsidbygid(global_zone, id,
132911963SAfshin.Ardakani@Sun.COM 		    (const char **)&sim.sim_domsid, &sim.sim_rid);
133011963SAfshin.Ardakani@Sun.COM 		break;
133111963SAfshin.Ardakani@Sun.COM 
133211963SAfshin.Ardakani@Sun.COM 	case SMB_IDMAP_EVERYONE:
133311963SAfshin.Ardakani@Sun.COM 		/* Everyone S-1-1-0 */
133411963SAfshin.Ardakani@Sun.COM 		sim.sim_domsid = "S-1-1";
133511963SAfshin.Ardakani@Sun.COM 		sim.sim_rid = 0;
133611963SAfshin.Ardakani@Sun.COM 		sim.sim_stat = IDMAP_SUCCESS;
133711963SAfshin.Ardakani@Sun.COM 		break;
133811963SAfshin.Ardakani@Sun.COM 
133911963SAfshin.Ardakani@Sun.COM 	default:
134011963SAfshin.Ardakani@Sun.COM 		ASSERT(0);
134111963SAfshin.Ardakani@Sun.COM 		return (IDMAP_ERR_ARG);
134211963SAfshin.Ardakani@Sun.COM 	}
134311963SAfshin.Ardakani@Sun.COM 
134411963SAfshin.Ardakani@Sun.COM 	if (sim.sim_stat != IDMAP_SUCCESS)
134511963SAfshin.Ardakani@Sun.COM 		return (sim.sim_stat);
134611963SAfshin.Ardakani@Sun.COM 
134711963SAfshin.Ardakani@Sun.COM 	if (sim.sim_domsid == NULL)
134811963SAfshin.Ardakani@Sun.COM 		return (IDMAP_ERR_NOMAPPING);
134911963SAfshin.Ardakani@Sun.COM 
135011963SAfshin.Ardakani@Sun.COM 	sim.sim_sid = smb_sid_fromstr(sim.sim_domsid);
135111963SAfshin.Ardakani@Sun.COM 	if (sim.sim_sid == NULL)
135211963SAfshin.Ardakani@Sun.COM 		return (IDMAP_ERR_INTERNAL);
135311963SAfshin.Ardakani@Sun.COM 
135411963SAfshin.Ardakani@Sun.COM 	*sid = smb_sid_splice(sim.sim_sid, sim.sim_rid);
135511963SAfshin.Ardakani@Sun.COM 	smb_sid_free(sim.sim_sid);
135611963SAfshin.Ardakani@Sun.COM 	if (*sid == NULL)
135711963SAfshin.Ardakani@Sun.COM 		sim.sim_stat = IDMAP_ERR_INTERNAL;
135811963SAfshin.Ardakani@Sun.COM 
135911963SAfshin.Ardakani@Sun.COM 	return (sim.sim_stat);
136011963SAfshin.Ardakani@Sun.COM }
136111963SAfshin.Ardakani@Sun.COM 
136211963SAfshin.Ardakani@Sun.COM /*
136311963SAfshin.Ardakani@Sun.COM  * smb_idmap_batch_create
136411963SAfshin.Ardakani@Sun.COM  *
136511963SAfshin.Ardakani@Sun.COM  * Creates and initializes the context for batch ID mapping.
136611963SAfshin.Ardakani@Sun.COM  */
136711963SAfshin.Ardakani@Sun.COM idmap_stat
136811963SAfshin.Ardakani@Sun.COM smb_idmap_batch_create(smb_idmap_batch_t *sib, uint16_t nmap, int flags)
136911963SAfshin.Ardakani@Sun.COM {
137011963SAfshin.Ardakani@Sun.COM 	ASSERT(sib);
137111963SAfshin.Ardakani@Sun.COM 
137211963SAfshin.Ardakani@Sun.COM 	bzero(sib, sizeof (smb_idmap_batch_t));
137311963SAfshin.Ardakani@Sun.COM 
137411963SAfshin.Ardakani@Sun.COM 	sib->sib_idmaph = kidmap_get_create(global_zone);
137511963SAfshin.Ardakani@Sun.COM 
137611963SAfshin.Ardakani@Sun.COM 	sib->sib_flags = flags;
137711963SAfshin.Ardakani@Sun.COM 	sib->sib_nmap = nmap;
137811963SAfshin.Ardakani@Sun.COM 	sib->sib_size = nmap * sizeof (smb_idmap_t);
137911963SAfshin.Ardakani@Sun.COM 	sib->sib_maps = kmem_zalloc(sib->sib_size, KM_SLEEP);
138011963SAfshin.Ardakani@Sun.COM 
138111963SAfshin.Ardakani@Sun.COM 	return (IDMAP_SUCCESS);
138211963SAfshin.Ardakani@Sun.COM }
138311963SAfshin.Ardakani@Sun.COM 
138411963SAfshin.Ardakani@Sun.COM /*
138511963SAfshin.Ardakani@Sun.COM  * smb_idmap_batch_destroy
138611963SAfshin.Ardakani@Sun.COM  *
138711963SAfshin.Ardakani@Sun.COM  * Frees the batch ID mapping context.
138811963SAfshin.Ardakani@Sun.COM  * If ID mapping is Solaris -> Windows it frees memories
138911963SAfshin.Ardakani@Sun.COM  * allocated for binary SIDs.
139011963SAfshin.Ardakani@Sun.COM  */
139111963SAfshin.Ardakani@Sun.COM void
139211963SAfshin.Ardakani@Sun.COM smb_idmap_batch_destroy(smb_idmap_batch_t *sib)
139311963SAfshin.Ardakani@Sun.COM {
139411963SAfshin.Ardakani@Sun.COM 	char *domsid;
139511963SAfshin.Ardakani@Sun.COM 	int i;
139611963SAfshin.Ardakani@Sun.COM 
139711963SAfshin.Ardakani@Sun.COM 	ASSERT(sib);
139811963SAfshin.Ardakani@Sun.COM 	ASSERT(sib->sib_maps);
139911963SAfshin.Ardakani@Sun.COM 
140011963SAfshin.Ardakani@Sun.COM 	if (sib->sib_idmaph)
140111963SAfshin.Ardakani@Sun.COM 		kidmap_get_destroy(sib->sib_idmaph);
140211963SAfshin.Ardakani@Sun.COM 
140311963SAfshin.Ardakani@Sun.COM 	if (sib->sib_flags & SMB_IDMAP_ID2SID) {
140411963SAfshin.Ardakani@Sun.COM 		/*
140511963SAfshin.Ardakani@Sun.COM 		 * SIDs are allocated only when mapping
140611963SAfshin.Ardakani@Sun.COM 		 * UID/GID to SIDs
140711963SAfshin.Ardakani@Sun.COM 		 */
140811963SAfshin.Ardakani@Sun.COM 		for (i = 0; i < sib->sib_nmap; i++)
140911963SAfshin.Ardakani@Sun.COM 			smb_sid_free(sib->sib_maps[i].sim_sid);
141011963SAfshin.Ardakani@Sun.COM 	} else if (sib->sib_flags & SMB_IDMAP_SID2ID) {
141111963SAfshin.Ardakani@Sun.COM 		/*
141211963SAfshin.Ardakani@Sun.COM 		 * SID prefixes are allocated only when mapping
141311963SAfshin.Ardakani@Sun.COM 		 * SIDs to UID/GID
141411963SAfshin.Ardakani@Sun.COM 		 */
141511963SAfshin.Ardakani@Sun.COM 		for (i = 0; i < sib->sib_nmap; i++) {
141611963SAfshin.Ardakani@Sun.COM 			domsid = sib->sib_maps[i].sim_domsid;
141711963SAfshin.Ardakani@Sun.COM 			if (domsid)
141811963SAfshin.Ardakani@Sun.COM 				smb_mem_free(domsid);
141911963SAfshin.Ardakani@Sun.COM 		}
142011963SAfshin.Ardakani@Sun.COM 	}
142111963SAfshin.Ardakani@Sun.COM 
142211963SAfshin.Ardakani@Sun.COM 	if (sib->sib_size && sib->sib_maps)
142311963SAfshin.Ardakani@Sun.COM 		kmem_free(sib->sib_maps, sib->sib_size);
142411963SAfshin.Ardakani@Sun.COM }
142511963SAfshin.Ardakani@Sun.COM 
142611963SAfshin.Ardakani@Sun.COM /*
142711963SAfshin.Ardakani@Sun.COM  * smb_idmap_batch_getid
142811963SAfshin.Ardakani@Sun.COM  *
142911963SAfshin.Ardakani@Sun.COM  * Queue a request to map the given SID to a UID or GID.
143011963SAfshin.Ardakani@Sun.COM  *
143111963SAfshin.Ardakani@Sun.COM  * sim->sim_id should point to variable that's supposed to
143211963SAfshin.Ardakani@Sun.COM  * hold the returned UID/GID. This needs to be setup by caller
143311963SAfshin.Ardakani@Sun.COM  * of this function.
143411963SAfshin.Ardakani@Sun.COM  *
143511963SAfshin.Ardakani@Sun.COM  * If requested ID type is known, it's passed as 'idtype',
143611963SAfshin.Ardakani@Sun.COM  * if it's unknown it'll be returned in sim->sim_idtype.
143711963SAfshin.Ardakani@Sun.COM  */
143811963SAfshin.Ardakani@Sun.COM idmap_stat
143911963SAfshin.Ardakani@Sun.COM smb_idmap_batch_getid(idmap_get_handle_t *idmaph, smb_idmap_t *sim,
144011963SAfshin.Ardakani@Sun.COM     smb_sid_t *sid, int idtype)
144111963SAfshin.Ardakani@Sun.COM {
144211963SAfshin.Ardakani@Sun.COM 	char strsid[SMB_SID_STRSZ];
144311963SAfshin.Ardakani@Sun.COM 	idmap_stat idm_stat;
144411963SAfshin.Ardakani@Sun.COM 
144511963SAfshin.Ardakani@Sun.COM 	ASSERT(idmaph);
144611963SAfshin.Ardakani@Sun.COM 	ASSERT(sim);
144711963SAfshin.Ardakani@Sun.COM 	ASSERT(sid);
144811963SAfshin.Ardakani@Sun.COM 
144911963SAfshin.Ardakani@Sun.COM 	smb_sid_tostr(sid, strsid);
145011963SAfshin.Ardakani@Sun.COM 	if (smb_sid_splitstr(strsid, &sim->sim_rid) != 0)
145111963SAfshin.Ardakani@Sun.COM 		return (IDMAP_ERR_SID);
145211963SAfshin.Ardakani@Sun.COM 	sim->sim_domsid = smb_mem_strdup(strsid);
145311963SAfshin.Ardakani@Sun.COM 
145411963SAfshin.Ardakani@Sun.COM 	switch (idtype) {
145511963SAfshin.Ardakani@Sun.COM 	case SMB_IDMAP_USER:
145611963SAfshin.Ardakani@Sun.COM 		idm_stat = kidmap_batch_getuidbysid(idmaph, sim->sim_domsid,
145711963SAfshin.Ardakani@Sun.COM 		    sim->sim_rid, sim->sim_id, &sim->sim_stat);
145811963SAfshin.Ardakani@Sun.COM 		break;
145911963SAfshin.Ardakani@Sun.COM 
146011963SAfshin.Ardakani@Sun.COM 	case SMB_IDMAP_GROUP:
146111963SAfshin.Ardakani@Sun.COM 		idm_stat = kidmap_batch_getgidbysid(idmaph, sim->sim_domsid,
146211963SAfshin.Ardakani@Sun.COM 		    sim->sim_rid, sim->sim_id, &sim->sim_stat);
146311963SAfshin.Ardakani@Sun.COM 		break;
146411963SAfshin.Ardakani@Sun.COM 
146511963SAfshin.Ardakani@Sun.COM 	case SMB_IDMAP_UNKNOWN:
146611963SAfshin.Ardakani@Sun.COM 		idm_stat = kidmap_batch_getpidbysid(idmaph, sim->sim_domsid,
146711963SAfshin.Ardakani@Sun.COM 		    sim->sim_rid, sim->sim_id, &sim->sim_idtype,
146811963SAfshin.Ardakani@Sun.COM 		    &sim->sim_stat);
146911963SAfshin.Ardakani@Sun.COM 		break;
147011963SAfshin.Ardakani@Sun.COM 
147111963SAfshin.Ardakani@Sun.COM 	default:
147211963SAfshin.Ardakani@Sun.COM 		ASSERT(0);
147311963SAfshin.Ardakani@Sun.COM 		return (IDMAP_ERR_ARG);
147411963SAfshin.Ardakani@Sun.COM 	}
147511963SAfshin.Ardakani@Sun.COM 
147611963SAfshin.Ardakani@Sun.COM 	return (idm_stat);
147711963SAfshin.Ardakani@Sun.COM }
147811963SAfshin.Ardakani@Sun.COM 
147911963SAfshin.Ardakani@Sun.COM /*
148011963SAfshin.Ardakani@Sun.COM  * smb_idmap_batch_getsid
148111963SAfshin.Ardakani@Sun.COM  *
148211963SAfshin.Ardakani@Sun.COM  * Queue a request to map the given UID/GID to a SID.
148311963SAfshin.Ardakani@Sun.COM  *
148411963SAfshin.Ardakani@Sun.COM  * sim->sim_domsid and sim->sim_rid will contain the mapping
148511963SAfshin.Ardakani@Sun.COM  * result upon successful process of the batched request.
148611963SAfshin.Ardakani@Sun.COM  */
148711963SAfshin.Ardakani@Sun.COM idmap_stat
148811963SAfshin.Ardakani@Sun.COM smb_idmap_batch_getsid(idmap_get_handle_t *idmaph, smb_idmap_t *sim,
148911963SAfshin.Ardakani@Sun.COM     uid_t id, int idtype)
149011963SAfshin.Ardakani@Sun.COM {
149111963SAfshin.Ardakani@Sun.COM 	idmap_stat idm_stat;
149211963SAfshin.Ardakani@Sun.COM 
149311963SAfshin.Ardakani@Sun.COM 	switch (idtype) {
149411963SAfshin.Ardakani@Sun.COM 	case SMB_IDMAP_USER:
149511963SAfshin.Ardakani@Sun.COM 		idm_stat = kidmap_batch_getsidbyuid(idmaph, id,
149611963SAfshin.Ardakani@Sun.COM 		    (const char **)&sim->sim_domsid, &sim->sim_rid,
149711963SAfshin.Ardakani@Sun.COM 		    &sim->sim_stat);
149811963SAfshin.Ardakani@Sun.COM 		break;
149911963SAfshin.Ardakani@Sun.COM 
150011963SAfshin.Ardakani@Sun.COM 	case SMB_IDMAP_GROUP:
150111963SAfshin.Ardakani@Sun.COM 		idm_stat = kidmap_batch_getsidbygid(idmaph, id,
150211963SAfshin.Ardakani@Sun.COM 		    (const char **)&sim->sim_domsid, &sim->sim_rid,
150311963SAfshin.Ardakani@Sun.COM 		    &sim->sim_stat);
150411963SAfshin.Ardakani@Sun.COM 		break;
150511963SAfshin.Ardakani@Sun.COM 
150611963SAfshin.Ardakani@Sun.COM 	case SMB_IDMAP_OWNERAT:
150711963SAfshin.Ardakani@Sun.COM 		/* Current Owner S-1-5-32-766 */
150811963SAfshin.Ardakani@Sun.COM 		sim->sim_domsid = NT_BUILTIN_DOMAIN_SIDSTR;
150911963SAfshin.Ardakani@Sun.COM 		sim->sim_rid = SECURITY_CURRENT_OWNER_RID;
151011963SAfshin.Ardakani@Sun.COM 		sim->sim_stat = IDMAP_SUCCESS;
151111963SAfshin.Ardakani@Sun.COM 		idm_stat = IDMAP_SUCCESS;
151211963SAfshin.Ardakani@Sun.COM 		break;
151311963SAfshin.Ardakani@Sun.COM 
151411963SAfshin.Ardakani@Sun.COM 	case SMB_IDMAP_GROUPAT:
151511963SAfshin.Ardakani@Sun.COM 		/* Current Group S-1-5-32-767 */
151611963SAfshin.Ardakani@Sun.COM 		sim->sim_domsid = NT_BUILTIN_DOMAIN_SIDSTR;
151711963SAfshin.Ardakani@Sun.COM 		sim->sim_rid = SECURITY_CURRENT_GROUP_RID;
151811963SAfshin.Ardakani@Sun.COM 		sim->sim_stat = IDMAP_SUCCESS;
151911963SAfshin.Ardakani@Sun.COM 		idm_stat = IDMAP_SUCCESS;
152011963SAfshin.Ardakani@Sun.COM 		break;
152111963SAfshin.Ardakani@Sun.COM 
152211963SAfshin.Ardakani@Sun.COM 	case SMB_IDMAP_EVERYONE:
152311963SAfshin.Ardakani@Sun.COM 		/* Everyone S-1-1-0 */
152411963SAfshin.Ardakani@Sun.COM 		sim->sim_domsid = NT_WORLD_AUTH_SIDSTR;
152511963SAfshin.Ardakani@Sun.COM 		sim->sim_rid = 0;
152611963SAfshin.Ardakani@Sun.COM 		sim->sim_stat = IDMAP_SUCCESS;
152711963SAfshin.Ardakani@Sun.COM 		idm_stat = IDMAP_SUCCESS;
152811963SAfshin.Ardakani@Sun.COM 		break;
152911963SAfshin.Ardakani@Sun.COM 
153011963SAfshin.Ardakani@Sun.COM 	default:
153111963SAfshin.Ardakani@Sun.COM 		ASSERT(0);
153211963SAfshin.Ardakani@Sun.COM 		return (IDMAP_ERR_ARG);
153311963SAfshin.Ardakani@Sun.COM 	}
153411963SAfshin.Ardakani@Sun.COM 
153511963SAfshin.Ardakani@Sun.COM 	return (idm_stat);
153611963SAfshin.Ardakani@Sun.COM }
153711963SAfshin.Ardakani@Sun.COM 
153811963SAfshin.Ardakani@Sun.COM /*
153911963SAfshin.Ardakani@Sun.COM  * smb_idmap_batch_binsid
154011963SAfshin.Ardakani@Sun.COM  *
154111963SAfshin.Ardakani@Sun.COM  * Convert sidrids to binary sids
154211963SAfshin.Ardakani@Sun.COM  *
154311963SAfshin.Ardakani@Sun.COM  * Returns 0 if successful and non-zero upon failure.
154411963SAfshin.Ardakani@Sun.COM  */
154511963SAfshin.Ardakani@Sun.COM static int
154611963SAfshin.Ardakani@Sun.COM smb_idmap_batch_binsid(smb_idmap_batch_t *sib)
154711963SAfshin.Ardakani@Sun.COM {
154811963SAfshin.Ardakani@Sun.COM 	smb_sid_t *sid;
154911963SAfshin.Ardakani@Sun.COM 	smb_idmap_t *sim;
155011963SAfshin.Ardakani@Sun.COM 	int i;
155111963SAfshin.Ardakani@Sun.COM 
155211963SAfshin.Ardakani@Sun.COM 	if (sib->sib_flags & SMB_IDMAP_SID2ID)
155311963SAfshin.Ardakani@Sun.COM 		/* This operation is not required */
155411963SAfshin.Ardakani@Sun.COM 		return (0);
155511963SAfshin.Ardakani@Sun.COM 
155611963SAfshin.Ardakani@Sun.COM 	sim = sib->sib_maps;
155711963SAfshin.Ardakani@Sun.COM 	for (i = 0; i < sib->sib_nmap; sim++, i++) {
155811963SAfshin.Ardakani@Sun.COM 		ASSERT(sim->sim_domsid);
155911963SAfshin.Ardakani@Sun.COM 		if (sim->sim_domsid == NULL)
156011963SAfshin.Ardakani@Sun.COM 			return (1);
156111963SAfshin.Ardakani@Sun.COM 
156211963SAfshin.Ardakani@Sun.COM 		if ((sid = smb_sid_fromstr(sim->sim_domsid)) == NULL)
156311963SAfshin.Ardakani@Sun.COM 			return (1);
156411963SAfshin.Ardakani@Sun.COM 
156511963SAfshin.Ardakani@Sun.COM 		sim->sim_sid = smb_sid_splice(sid, sim->sim_rid);
156611963SAfshin.Ardakani@Sun.COM 		smb_sid_free(sid);
156711963SAfshin.Ardakani@Sun.COM 	}
156811963SAfshin.Ardakani@Sun.COM 
156911963SAfshin.Ardakani@Sun.COM 	return (0);
157011963SAfshin.Ardakani@Sun.COM }
157111963SAfshin.Ardakani@Sun.COM 
157211963SAfshin.Ardakani@Sun.COM /*
157311963SAfshin.Ardakani@Sun.COM  * smb_idmap_batch_getmappings
157411963SAfshin.Ardakani@Sun.COM  *
157511963SAfshin.Ardakani@Sun.COM  * trigger ID mapping service to get the mappings for queued
157611963SAfshin.Ardakani@Sun.COM  * requests.
157711963SAfshin.Ardakani@Sun.COM  *
157811963SAfshin.Ardakani@Sun.COM  * Checks the result of all the queued requests.
157911963SAfshin.Ardakani@Sun.COM  * If this is a Solaris -> Windows mapping it generates
158011963SAfshin.Ardakani@Sun.COM  * binary SIDs from returned (domsid, rid) pairs.
158111963SAfshin.Ardakani@Sun.COM  */
158211963SAfshin.Ardakani@Sun.COM idmap_stat
158311963SAfshin.Ardakani@Sun.COM smb_idmap_batch_getmappings(smb_idmap_batch_t *sib)
158411963SAfshin.Ardakani@Sun.COM {
158511963SAfshin.Ardakani@Sun.COM 	idmap_stat idm_stat = IDMAP_SUCCESS;
158611963SAfshin.Ardakani@Sun.COM 	int i;
158711963SAfshin.Ardakani@Sun.COM 
158811963SAfshin.Ardakani@Sun.COM 	idm_stat = kidmap_get_mappings(sib->sib_idmaph);
158911963SAfshin.Ardakani@Sun.COM 	if (idm_stat != IDMAP_SUCCESS)
159011963SAfshin.Ardakani@Sun.COM 		return (idm_stat);
159111963SAfshin.Ardakani@Sun.COM 
159211963SAfshin.Ardakani@Sun.COM 	/*
159311963SAfshin.Ardakani@Sun.COM 	 * Check the status for all the queued requests
159411963SAfshin.Ardakani@Sun.COM 	 */
159511963SAfshin.Ardakani@Sun.COM 	for (i = 0; i < sib->sib_nmap; i++) {
159611963SAfshin.Ardakani@Sun.COM 		if (sib->sib_maps[i].sim_stat != IDMAP_SUCCESS)
159711963SAfshin.Ardakani@Sun.COM 			return (sib->sib_maps[i].sim_stat);
159811963SAfshin.Ardakani@Sun.COM 	}
159911963SAfshin.Ardakani@Sun.COM 
160011963SAfshin.Ardakani@Sun.COM 	if (smb_idmap_batch_binsid(sib) != 0)
160111963SAfshin.Ardakani@Sun.COM 		idm_stat = IDMAP_ERR_OTHER;
160211963SAfshin.Ardakani@Sun.COM 
160311963SAfshin.Ardakani@Sun.COM 	return (idm_stat);
160411963SAfshin.Ardakani@Sun.COM }
160511963SAfshin.Ardakani@Sun.COM 
160611963SAfshin.Ardakani@Sun.COM uint64_t
160711963SAfshin.Ardakani@Sun.COM smb_time_unix_to_nt(timestruc_t *unix_time)
160811963SAfshin.Ardakani@Sun.COM {
160911963SAfshin.Ardakani@Sun.COM 	uint64_t nt_time;
161011963SAfshin.Ardakani@Sun.COM 
161111963SAfshin.Ardakani@Sun.COM 	if ((unix_time->tv_sec == 0) && (unix_time->tv_nsec == 0))
161211963SAfshin.Ardakani@Sun.COM 		return (0);
161311963SAfshin.Ardakani@Sun.COM 
161411963SAfshin.Ardakani@Sun.COM 	nt_time = unix_time->tv_sec;
161511963SAfshin.Ardakani@Sun.COM 	nt_time *= 10000000;  /* seconds to 100ns */
161611963SAfshin.Ardakani@Sun.COM 	nt_time += unix_time->tv_nsec / 100;
161711963SAfshin.Ardakani@Sun.COM 	return (nt_time + NT_TIME_BIAS);
161811963SAfshin.Ardakani@Sun.COM }
161911963SAfshin.Ardakani@Sun.COM 
162011963SAfshin.Ardakani@Sun.COM void
162111963SAfshin.Ardakani@Sun.COM smb_time_nt_to_unix(uint64_t nt_time, timestruc_t *unix_time)
162211963SAfshin.Ardakani@Sun.COM {
162311963SAfshin.Ardakani@Sun.COM 	uint32_t seconds;
162411963SAfshin.Ardakani@Sun.COM 
162511963SAfshin.Ardakani@Sun.COM 	ASSERT(unix_time);
162611963SAfshin.Ardakani@Sun.COM 
162711963SAfshin.Ardakani@Sun.COM 	if ((nt_time == 0) || (nt_time == -1)) {
162811963SAfshin.Ardakani@Sun.COM 		unix_time->tv_sec = 0;
162911963SAfshin.Ardakani@Sun.COM 		unix_time->tv_nsec = 0;
163011963SAfshin.Ardakani@Sun.COM 		return;
163111963SAfshin.Ardakani@Sun.COM 	}
163211963SAfshin.Ardakani@Sun.COM 
163311963SAfshin.Ardakani@Sun.COM 	nt_time -= NT_TIME_BIAS;
163411963SAfshin.Ardakani@Sun.COM 	seconds = nt_time / 10000000;
163511963SAfshin.Ardakani@Sun.COM 	unix_time->tv_sec = seconds;
163611963SAfshin.Ardakani@Sun.COM 	unix_time->tv_nsec = (nt_time  % 10000000) * 100;
163711963SAfshin.Ardakani@Sun.COM }
163811963SAfshin.Ardakani@Sun.COM 
163911963SAfshin.Ardakani@Sun.COM /*
164011963SAfshin.Ardakani@Sun.COM  * smb_time_gmt_to_local, smb_time_local_to_gmt
164111963SAfshin.Ardakani@Sun.COM  *
164211963SAfshin.Ardakani@Sun.COM  * Apply the gmt offset to convert between local time and gmt
164311963SAfshin.Ardakani@Sun.COM  */
164411963SAfshin.Ardakani@Sun.COM int32_t
164511963SAfshin.Ardakani@Sun.COM smb_time_gmt_to_local(smb_request_t *sr, int32_t gmt)
164611963SAfshin.Ardakani@Sun.COM {
164711963SAfshin.Ardakani@Sun.COM 	if ((gmt == 0) || (gmt == -1))
164811963SAfshin.Ardakani@Sun.COM 		return (0);
164911963SAfshin.Ardakani@Sun.COM 
165011963SAfshin.Ardakani@Sun.COM 	return (gmt - sr->sr_gmtoff);
165111963SAfshin.Ardakani@Sun.COM }
165211963SAfshin.Ardakani@Sun.COM 
165311963SAfshin.Ardakani@Sun.COM int32_t
165411963SAfshin.Ardakani@Sun.COM smb_time_local_to_gmt(smb_request_t *sr, int32_t local)
165511963SAfshin.Ardakani@Sun.COM {
165611963SAfshin.Ardakani@Sun.COM 	if ((local == 0) || (local == -1))
165711963SAfshin.Ardakani@Sun.COM 		return (0);
165811963SAfshin.Ardakani@Sun.COM 
165911963SAfshin.Ardakani@Sun.COM 	return (local + sr->sr_gmtoff);
166011963SAfshin.Ardakani@Sun.COM }
166111963SAfshin.Ardakani@Sun.COM 
166211963SAfshin.Ardakani@Sun.COM 
166311963SAfshin.Ardakani@Sun.COM /*
166411963SAfshin.Ardakani@Sun.COM  * smb_time_dos_to_unix
166511963SAfshin.Ardakani@Sun.COM  *
166611963SAfshin.Ardakani@Sun.COM  * Convert SMB_DATE & SMB_TIME values to a unix timestamp.
166711963SAfshin.Ardakani@Sun.COM  *
166811963SAfshin.Ardakani@Sun.COM  * A date/time field of 0 means that that server file system
166911963SAfshin.Ardakani@Sun.COM  * assigned value need not be changed. The behaviour when the
167011963SAfshin.Ardakani@Sun.COM  * date/time field is set to -1 is not documented but is
167111963SAfshin.Ardakani@Sun.COM  * generally treated like 0.
167211963SAfshin.Ardakani@Sun.COM  * If date or time is 0 or -1 the unix time is returned as 0
167311963SAfshin.Ardakani@Sun.COM  * so that the caller can identify and handle this special case.
167411963SAfshin.Ardakani@Sun.COM  */
167511963SAfshin.Ardakani@Sun.COM int32_t
167611963SAfshin.Ardakani@Sun.COM smb_time_dos_to_unix(int16_t date, int16_t time)
167711963SAfshin.Ardakani@Sun.COM {
167811963SAfshin.Ardakani@Sun.COM 	struct tm	atm;
167911963SAfshin.Ardakani@Sun.COM 
168011963SAfshin.Ardakani@Sun.COM 	if (((date == 0) || (time == 0)) ||
168111963SAfshin.Ardakani@Sun.COM 	    ((date == -1) || (time == -1))) {
168211963SAfshin.Ardakani@Sun.COM 		return (0);
168311963SAfshin.Ardakani@Sun.COM 	}
168411963SAfshin.Ardakani@Sun.COM 
168511963SAfshin.Ardakani@Sun.COM 	atm.tm_year = ((date >>  9) & 0x3F) + 80;
168611963SAfshin.Ardakani@Sun.COM 	atm.tm_mon  = ((date >>  5) & 0x0F) - 1;
168711963SAfshin.Ardakani@Sun.COM 	atm.tm_mday = ((date >>  0) & 0x1F);
168811963SAfshin.Ardakani@Sun.COM 	atm.tm_hour = ((time >> 11) & 0x1F);
168911963SAfshin.Ardakani@Sun.COM 	atm.tm_min  = ((time >>  5) & 0x3F);
169011963SAfshin.Ardakani@Sun.COM 	atm.tm_sec  = ((time >>  0) & 0x1F) << 1;
169111963SAfshin.Ardakani@Sun.COM 
169211963SAfshin.Ardakani@Sun.COM 	return (smb_timegm(&atm));
169311963SAfshin.Ardakani@Sun.COM }
169411963SAfshin.Ardakani@Sun.COM 
169511963SAfshin.Ardakani@Sun.COM void
169611963SAfshin.Ardakani@Sun.COM smb_time_unix_to_dos(int32_t ux_time, int16_t *date_p, int16_t *time_p)
169711963SAfshin.Ardakani@Sun.COM {
169811963SAfshin.Ardakani@Sun.COM 	struct tm	atm;
169911963SAfshin.Ardakani@Sun.COM 	int		i;
170011963SAfshin.Ardakani@Sun.COM 	time_t		tmp_time;
170111963SAfshin.Ardakani@Sun.COM 
170211963SAfshin.Ardakani@Sun.COM 	if (ux_time == 0) {
170311963SAfshin.Ardakani@Sun.COM 		*date_p = 0;
170411963SAfshin.Ardakani@Sun.COM 		*time_p = 0;
170511963SAfshin.Ardakani@Sun.COM 		return;
170611963SAfshin.Ardakani@Sun.COM 	}
170711963SAfshin.Ardakani@Sun.COM 
170811963SAfshin.Ardakani@Sun.COM 	tmp_time = (time_t)ux_time;
170911963SAfshin.Ardakani@Sun.COM 	(void) smb_gmtime_r(&tmp_time, &atm);
171011963SAfshin.Ardakani@Sun.COM 
171111963SAfshin.Ardakani@Sun.COM 	if (date_p) {
171211963SAfshin.Ardakani@Sun.COM 		i = 0;
171311963SAfshin.Ardakani@Sun.COM 		i += atm.tm_year - 80;
171411963SAfshin.Ardakani@Sun.COM 		i <<= 4;
171511963SAfshin.Ardakani@Sun.COM 		i += atm.tm_mon + 1;
171611963SAfshin.Ardakani@Sun.COM 		i <<= 5;
171711963SAfshin.Ardakani@Sun.COM 		i += atm.tm_mday;
171811963SAfshin.Ardakani@Sun.COM 
171911963SAfshin.Ardakani@Sun.COM 		*date_p = (short)i;
172011963SAfshin.Ardakani@Sun.COM 	}
172111963SAfshin.Ardakani@Sun.COM 	if (time_p) {
172211963SAfshin.Ardakani@Sun.COM 		i = 0;
172311963SAfshin.Ardakani@Sun.COM 		i += atm.tm_hour;
172411963SAfshin.Ardakani@Sun.COM 		i <<= 6;
172511963SAfshin.Ardakani@Sun.COM 		i += atm.tm_min;
172611963SAfshin.Ardakani@Sun.COM 		i <<= 5;
172711963SAfshin.Ardakani@Sun.COM 		i += atm.tm_sec >> 1;
172811963SAfshin.Ardakani@Sun.COM 
172911963SAfshin.Ardakani@Sun.COM 		*time_p = (short)i;
173011963SAfshin.Ardakani@Sun.COM 	}
173111963SAfshin.Ardakani@Sun.COM }
173211963SAfshin.Ardakani@Sun.COM 
173311963SAfshin.Ardakani@Sun.COM 
173411963SAfshin.Ardakani@Sun.COM /*
173511963SAfshin.Ardakani@Sun.COM  * smb_gmtime_r
173611963SAfshin.Ardakani@Sun.COM  *
173711963SAfshin.Ardakani@Sun.COM  * Thread-safe version of smb_gmtime. Returns a null pointer if either
173811963SAfshin.Ardakani@Sun.COM  * input parameter is a null pointer. Otherwise returns a pointer
173911963SAfshin.Ardakani@Sun.COM  * to result.
174011963SAfshin.Ardakani@Sun.COM  *
174111963SAfshin.Ardakani@Sun.COM  * Day of the week calculation: the Epoch was a thursday.
174211963SAfshin.Ardakani@Sun.COM  *
174311963SAfshin.Ardakani@Sun.COM  * There are no timezone corrections so tm_isdst and tm_gmtoff are
174411963SAfshin.Ardakani@Sun.COM  * always zero, and the zone is always WET.
174511963SAfshin.Ardakani@Sun.COM  */
174611963SAfshin.Ardakani@Sun.COM struct tm *
174711963SAfshin.Ardakani@Sun.COM smb_gmtime_r(time_t *clock, struct tm *result)
174811963SAfshin.Ardakani@Sun.COM {
174911963SAfshin.Ardakani@Sun.COM 	time_t tsec;
175011963SAfshin.Ardakani@Sun.COM 	int year;
175111963SAfshin.Ardakani@Sun.COM 	int month;
175211963SAfshin.Ardakani@Sun.COM 	int sec_per_month;
175311963SAfshin.Ardakani@Sun.COM 
175411963SAfshin.Ardakani@Sun.COM 	if (clock == 0 || result == 0)
175511963SAfshin.Ardakani@Sun.COM 		return (0);
175611963SAfshin.Ardakani@Sun.COM 
175711963SAfshin.Ardakani@Sun.COM 	bzero(result, sizeof (struct tm));
175811963SAfshin.Ardakani@Sun.COM 	tsec = *clock;
175911963SAfshin.Ardakani@Sun.COM 	tsec -= tzh_leapcnt;
176011963SAfshin.Ardakani@Sun.COM 
176111963SAfshin.Ardakani@Sun.COM 	result->tm_wday = tsec / SECSPERDAY;
176211963SAfshin.Ardakani@Sun.COM 	result->tm_wday = (result->tm_wday + TM_THURSDAY) % DAYSPERWEEK;
176311963SAfshin.Ardakani@Sun.COM 
176411963SAfshin.Ardakani@Sun.COM 	year = EPOCH_YEAR;
176511963SAfshin.Ardakani@Sun.COM 	while (tsec >= (isleap(year) ? (SECSPERDAY * DAYSPERLYEAR) :
176611963SAfshin.Ardakani@Sun.COM 	    (SECSPERDAY * DAYSPERNYEAR))) {
176711963SAfshin.Ardakani@Sun.COM 		if (isleap(year))
176811963SAfshin.Ardakani@Sun.COM 			tsec -= SECSPERDAY * DAYSPERLYEAR;
176911963SAfshin.Ardakani@Sun.COM 		else
177011963SAfshin.Ardakani@Sun.COM 			tsec -= SECSPERDAY * DAYSPERNYEAR;
177111963SAfshin.Ardakani@Sun.COM 
177211963SAfshin.Ardakani@Sun.COM 		++year;
177311963SAfshin.Ardakani@Sun.COM 	}
177411963SAfshin.Ardakani@Sun.COM 
177511963SAfshin.Ardakani@Sun.COM 	result->tm_year = year - TM_YEAR_BASE;
177611963SAfshin.Ardakani@Sun.COM 	result->tm_yday = tsec / SECSPERDAY;
177711963SAfshin.Ardakani@Sun.COM 
177811963SAfshin.Ardakani@Sun.COM 	for (month = TM_JANUARY; month <= TM_DECEMBER; ++month) {
177911963SAfshin.Ardakani@Sun.COM 		sec_per_month = days_in_month[month] * SECSPERDAY;
178011963SAfshin.Ardakani@Sun.COM 
178111963SAfshin.Ardakani@Sun.COM 		if (month == TM_FEBRUARY && isleap(year))
178211963SAfshin.Ardakani@Sun.COM 			sec_per_month += SECSPERDAY;
178311963SAfshin.Ardakani@Sun.COM 
178411963SAfshin.Ardakani@Sun.COM 		if (tsec < sec_per_month)
178511963SAfshin.Ardakani@Sun.COM 			break;
178611963SAfshin.Ardakani@Sun.COM 
178711963SAfshin.Ardakani@Sun.COM 		tsec -= sec_per_month;
178811963SAfshin.Ardakani@Sun.COM 	}
178911963SAfshin.Ardakani@Sun.COM 
179011963SAfshin.Ardakani@Sun.COM 	result->tm_mon = month;
179111963SAfshin.Ardakani@Sun.COM 	result->tm_mday = (tsec / SECSPERDAY) + 1;
179211963SAfshin.Ardakani@Sun.COM 	tsec %= SECSPERDAY;
179311963SAfshin.Ardakani@Sun.COM 	result->tm_sec = tsec % 60;
179411963SAfshin.Ardakani@Sun.COM 	tsec /= 60;
179511963SAfshin.Ardakani@Sun.COM 	result->tm_min = tsec % 60;
179611963SAfshin.Ardakani@Sun.COM 	tsec /= 60;
179711963SAfshin.Ardakani@Sun.COM 	result->tm_hour = (int)tsec;
179811963SAfshin.Ardakani@Sun.COM 
179911963SAfshin.Ardakani@Sun.COM 	return (result);
180011963SAfshin.Ardakani@Sun.COM }
180111963SAfshin.Ardakani@Sun.COM 
180211963SAfshin.Ardakani@Sun.COM 
180311963SAfshin.Ardakani@Sun.COM /*
180411963SAfshin.Ardakani@Sun.COM  * smb_timegm
180511963SAfshin.Ardakani@Sun.COM  *
180611963SAfshin.Ardakani@Sun.COM  * Converts the broken-down time in tm to a time value, i.e. the number
180711963SAfshin.Ardakani@Sun.COM  * of seconds since the Epoch (00:00:00 UTC, January 1, 1970). This is
180811963SAfshin.Ardakani@Sun.COM  * not a POSIX or ANSI function. Per the man page, the input values of
180911963SAfshin.Ardakani@Sun.COM  * tm_wday and tm_yday are ignored and, as the input data is assumed to
181011963SAfshin.Ardakani@Sun.COM  * represent GMT, we force tm_isdst and tm_gmtoff to 0.
181111963SAfshin.Ardakani@Sun.COM  *
181211963SAfshin.Ardakani@Sun.COM  * Before returning the clock time, we use smb_gmtime_r to set up tm_wday
181311963SAfshin.Ardakani@Sun.COM  * and tm_yday, and bring the other fields within normal range. I don't
181411963SAfshin.Ardakani@Sun.COM  * think this is really how it should be done but it's convenient for
181511963SAfshin.Ardakani@Sun.COM  * now.
181611963SAfshin.Ardakani@Sun.COM  */
181711963SAfshin.Ardakani@Sun.COM time_t
181811963SAfshin.Ardakani@Sun.COM smb_timegm(struct tm *tm)
181911963SAfshin.Ardakani@Sun.COM {
182011963SAfshin.Ardakani@Sun.COM 	time_t tsec;
182111963SAfshin.Ardakani@Sun.COM 	int dd;
182211963SAfshin.Ardakani@Sun.COM 	int mm;
182311963SAfshin.Ardakani@Sun.COM 	int yy;
182411963SAfshin.Ardakani@Sun.COM 	int year;
182511963SAfshin.Ardakani@Sun.COM 
182611963SAfshin.Ardakani@Sun.COM 	if (tm == 0)
182711963SAfshin.Ardakani@Sun.COM 		return (-1);
182811963SAfshin.Ardakani@Sun.COM 
182911963SAfshin.Ardakani@Sun.COM 	year = tm->tm_year + TM_YEAR_BASE;
183011963SAfshin.Ardakani@Sun.COM 	tsec = tzh_leapcnt;
183111963SAfshin.Ardakani@Sun.COM 
183211963SAfshin.Ardakani@Sun.COM 	for (yy = EPOCH_YEAR; yy < year; ++yy) {
183311963SAfshin.Ardakani@Sun.COM 		if (isleap(yy))
183411963SAfshin.Ardakani@Sun.COM 			tsec += SECSPERDAY * DAYSPERLYEAR;
183511963SAfshin.Ardakani@Sun.COM 		else
183611963SAfshin.Ardakani@Sun.COM 			tsec += SECSPERDAY * DAYSPERNYEAR;
183711963SAfshin.Ardakani@Sun.COM 	}
183811963SAfshin.Ardakani@Sun.COM 
183911963SAfshin.Ardakani@Sun.COM 	for (mm = TM_JANUARY; mm < tm->tm_mon; ++mm) {
184011963SAfshin.Ardakani@Sun.COM 		dd = days_in_month[mm] * SECSPERDAY;
184111963SAfshin.Ardakani@Sun.COM 
184211963SAfshin.Ardakani@Sun.COM 		if (mm == TM_FEBRUARY && isleap(year))
184311963SAfshin.Ardakani@Sun.COM 			dd += SECSPERDAY;
184411963SAfshin.Ardakani@Sun.COM 
184511963SAfshin.Ardakani@Sun.COM 		tsec += dd;
184611963SAfshin.Ardakani@Sun.COM 	}
184711963SAfshin.Ardakani@Sun.COM 
184811963SAfshin.Ardakani@Sun.COM 	tsec += (tm->tm_mday - 1) * SECSPERDAY;
184911963SAfshin.Ardakani@Sun.COM 	tsec += tm->tm_sec;
185011963SAfshin.Ardakani@Sun.COM 	tsec += tm->tm_min * SECSPERMIN;
185111963SAfshin.Ardakani@Sun.COM 	tsec += tm->tm_hour * SECSPERHOUR;
185211963SAfshin.Ardakani@Sun.COM 
185311963SAfshin.Ardakani@Sun.COM 	tm->tm_isdst = 0;
185411963SAfshin.Ardakani@Sun.COM 	(void) smb_gmtime_r(&tsec, tm);
185511963SAfshin.Ardakani@Sun.COM 	return (tsec);
185611963SAfshin.Ardakani@Sun.COM }
185711963SAfshin.Ardakani@Sun.COM 
185811963SAfshin.Ardakani@Sun.COM /*
185911963SAfshin.Ardakani@Sun.COM  * smb_cred_set_sid
186011963SAfshin.Ardakani@Sun.COM  *
186111963SAfshin.Ardakani@Sun.COM  * Initialize the ksid based on the given smb_id_t.
186211963SAfshin.Ardakani@Sun.COM  */
186311963SAfshin.Ardakani@Sun.COM static void
186411963SAfshin.Ardakani@Sun.COM smb_cred_set_sid(smb_id_t *id, ksid_t *ksid)
186511963SAfshin.Ardakani@Sun.COM {
186611963SAfshin.Ardakani@Sun.COM 	char sidstr[SMB_SID_STRSZ];
186711963SAfshin.Ardakani@Sun.COM 	int rc;
186811963SAfshin.Ardakani@Sun.COM 
186911963SAfshin.Ardakani@Sun.COM 	ASSERT(id);
187011963SAfshin.Ardakani@Sun.COM 	ASSERT(id->i_sid);
187111963SAfshin.Ardakani@Sun.COM 
187211963SAfshin.Ardakani@Sun.COM 	ksid->ks_id = id->i_id;
187311963SAfshin.Ardakani@Sun.COM 	smb_sid_tostr(id->i_sid, sidstr);
187411963SAfshin.Ardakani@Sun.COM 	rc = smb_sid_splitstr(sidstr, &ksid->ks_rid);
187511963SAfshin.Ardakani@Sun.COM 	ASSERT(rc == 0);
187611963SAfshin.Ardakani@Sun.COM 
187711963SAfshin.Ardakani@Sun.COM 	ksid->ks_attr = id->i_attrs;
187811963SAfshin.Ardakani@Sun.COM 	ksid->ks_domain = ksid_lookupdomain(sidstr);
187911963SAfshin.Ardakani@Sun.COM }
188011963SAfshin.Ardakani@Sun.COM 
188111963SAfshin.Ardakani@Sun.COM /*
188211963SAfshin.Ardakani@Sun.COM  * smb_cred_set_sidlist
188311963SAfshin.Ardakani@Sun.COM  *
188411963SAfshin.Ardakani@Sun.COM  * Allocate and initialize the ksidlist based on the Windows group list of the
188511963SAfshin.Ardakani@Sun.COM  * access token.
188611963SAfshin.Ardakani@Sun.COM  */
188711963SAfshin.Ardakani@Sun.COM static ksidlist_t *
188811963SAfshin.Ardakani@Sun.COM smb_cred_set_sidlist(smb_ids_t *token_grps)
188911963SAfshin.Ardakani@Sun.COM {
189011963SAfshin.Ardakani@Sun.COM 	int i;
189111963SAfshin.Ardakani@Sun.COM 	ksidlist_t *lp;
189211963SAfshin.Ardakani@Sun.COM 
189311963SAfshin.Ardakani@Sun.COM 	lp = kmem_zalloc(KSIDLIST_MEM(token_grps->i_cnt), KM_SLEEP);
189411963SAfshin.Ardakani@Sun.COM 	lp->ksl_ref = 1;
189511963SAfshin.Ardakani@Sun.COM 	lp->ksl_nsid = token_grps->i_cnt;
189611963SAfshin.Ardakani@Sun.COM 	lp->ksl_neid = 0;
189711963SAfshin.Ardakani@Sun.COM 
189811963SAfshin.Ardakani@Sun.COM 	for (i = 0; i < lp->ksl_nsid; i++) {
189911963SAfshin.Ardakani@Sun.COM 		smb_cred_set_sid(&token_grps->i_ids[i], &lp->ksl_sids[i]);
190011963SAfshin.Ardakani@Sun.COM 		if (lp->ksl_sids[i].ks_id > IDMAP_WK__MAX_GID)
190111963SAfshin.Ardakani@Sun.COM 			lp->ksl_neid++;
190211963SAfshin.Ardakani@Sun.COM 	}
190311963SAfshin.Ardakani@Sun.COM 
190411963SAfshin.Ardakani@Sun.COM 	return (lp);
190511963SAfshin.Ardakani@Sun.COM }
190611963SAfshin.Ardakani@Sun.COM 
190711963SAfshin.Ardakani@Sun.COM /*
190811963SAfshin.Ardakani@Sun.COM  * A Solaris credential (cred_t structure) will be allocated and
190911963SAfshin.Ardakani@Sun.COM  * initialized based on the given Windows style user access token.
191011963SAfshin.Ardakani@Sun.COM  *
191111963SAfshin.Ardakani@Sun.COM  * cred's gid is set to the primary group of the mapped Solaris user.
191211963SAfshin.Ardakani@Sun.COM  * When there is no such mapped user (i.e. the mapped UID is ephemeral)
191311963SAfshin.Ardakani@Sun.COM  * or his/her primary group could not be obtained, cred's gid is set to
191411963SAfshin.Ardakani@Sun.COM  * the mapped Solaris group of token's primary group.
191511963SAfshin.Ardakani@Sun.COM  */
191611963SAfshin.Ardakani@Sun.COM cred_t *
191711963SAfshin.Ardakani@Sun.COM smb_cred_create(smb_token_t *token, uint32_t *privileges)
191811963SAfshin.Ardakani@Sun.COM {
191911963SAfshin.Ardakani@Sun.COM 	ksid_t			ksid;
192011963SAfshin.Ardakani@Sun.COM 	ksidlist_t		*ksidlist = NULL;
192111963SAfshin.Ardakani@Sun.COM 	smb_posix_grps_t	*posix_grps;
192211963SAfshin.Ardakani@Sun.COM 	cred_t			*cr;
192311963SAfshin.Ardakani@Sun.COM 	gid_t			gid;
192411963SAfshin.Ardakani@Sun.COM 
192511963SAfshin.Ardakani@Sun.COM 	ASSERT(token);
192611963SAfshin.Ardakani@Sun.COM 	ASSERT(token->tkn_posix_grps);
192711963SAfshin.Ardakani@Sun.COM 	posix_grps = token->tkn_posix_grps;
192811963SAfshin.Ardakani@Sun.COM 
192911963SAfshin.Ardakani@Sun.COM 	ASSERT(privileges);
193011963SAfshin.Ardakani@Sun.COM 
193111963SAfshin.Ardakani@Sun.COM 	cr = crget();
193211963SAfshin.Ardakani@Sun.COM 	ASSERT(cr != NULL);
193311963SAfshin.Ardakani@Sun.COM 
193411963SAfshin.Ardakani@Sun.COM 	if (!IDMAP_ID_IS_EPHEMERAL(token->tkn_user.i_id) &&
193511963SAfshin.Ardakani@Sun.COM 	    (posix_grps->pg_ngrps != 0)) {
193611963SAfshin.Ardakani@Sun.COM 		gid = posix_grps->pg_grps[0];
193711963SAfshin.Ardakani@Sun.COM 	} else {
193811963SAfshin.Ardakani@Sun.COM 		gid = token->tkn_primary_grp.i_id;
193911963SAfshin.Ardakani@Sun.COM 	}
194011963SAfshin.Ardakani@Sun.COM 
194111963SAfshin.Ardakani@Sun.COM 	if (crsetugid(cr, token->tkn_user.i_id, gid) != 0) {
194211963SAfshin.Ardakani@Sun.COM 		crfree(cr);
194311963SAfshin.Ardakani@Sun.COM 		return (NULL);
194411963SAfshin.Ardakani@Sun.COM 	}
194511963SAfshin.Ardakani@Sun.COM 
194611963SAfshin.Ardakani@Sun.COM 	if (crsetgroups(cr, posix_grps->pg_ngrps, posix_grps->pg_grps) != 0) {
194711963SAfshin.Ardakani@Sun.COM 		crfree(cr);
194811963SAfshin.Ardakani@Sun.COM 		return (NULL);
194911963SAfshin.Ardakani@Sun.COM 	}
195011963SAfshin.Ardakani@Sun.COM 
195111963SAfshin.Ardakani@Sun.COM 	smb_cred_set_sid(&token->tkn_user, &ksid);
195211963SAfshin.Ardakani@Sun.COM 	crsetsid(cr, &ksid, KSID_USER);
195311963SAfshin.Ardakani@Sun.COM 	smb_cred_set_sid(&token->tkn_primary_grp, &ksid);
195411963SAfshin.Ardakani@Sun.COM 	crsetsid(cr, &ksid, KSID_GROUP);
195511963SAfshin.Ardakani@Sun.COM 	smb_cred_set_sid(&token->tkn_owner, &ksid);
195611963SAfshin.Ardakani@Sun.COM 	crsetsid(cr, &ksid, KSID_OWNER);
195711963SAfshin.Ardakani@Sun.COM 	ksidlist = smb_cred_set_sidlist(&token->tkn_win_grps);
195811963SAfshin.Ardakani@Sun.COM 	crsetsidlist(cr, ksidlist);
195911963SAfshin.Ardakani@Sun.COM 
196011963SAfshin.Ardakani@Sun.COM 	*privileges = 0;
196111963SAfshin.Ardakani@Sun.COM 
196211963SAfshin.Ardakani@Sun.COM 	if (smb_token_query_privilege(token, SE_BACKUP_LUID))
196311963SAfshin.Ardakani@Sun.COM 		*privileges |= SMB_USER_PRIV_BACKUP;
196411963SAfshin.Ardakani@Sun.COM 
196511963SAfshin.Ardakani@Sun.COM 	if (smb_token_query_privilege(token, SE_RESTORE_LUID))
196611963SAfshin.Ardakani@Sun.COM 		*privileges |= SMB_USER_PRIV_RESTORE;
196711963SAfshin.Ardakani@Sun.COM 
196811963SAfshin.Ardakani@Sun.COM 	if (smb_token_query_privilege(token, SE_TAKE_OWNERSHIP_LUID)) {
196911963SAfshin.Ardakani@Sun.COM 		*privileges |= SMB_USER_PRIV_TAKE_OWNERSHIP;
197011963SAfshin.Ardakani@Sun.COM 		(void) crsetpriv(cr, PRIV_FILE_CHOWN, NULL);
197111963SAfshin.Ardakani@Sun.COM 	}
197211963SAfshin.Ardakani@Sun.COM 
197311963SAfshin.Ardakani@Sun.COM 	if (smb_token_query_privilege(token, SE_SECURITY_LUID))
197411963SAfshin.Ardakani@Sun.COM 		*privileges |= SMB_USER_PRIV_SECURITY;
197511963SAfshin.Ardakani@Sun.COM 
197611963SAfshin.Ardakani@Sun.COM 	return (cr);
197711963SAfshin.Ardakani@Sun.COM }
197811963SAfshin.Ardakani@Sun.COM 
197911963SAfshin.Ardakani@Sun.COM /*
198011963SAfshin.Ardakani@Sun.COM  * smb_cred_rele
198111963SAfshin.Ardakani@Sun.COM  *
198211963SAfshin.Ardakani@Sun.COM  * The reference count of the user's credential will get decremented if it
198311963SAfshin.Ardakani@Sun.COM  * is non-zero. Otherwise, the credential will be freed.
198411963SAfshin.Ardakani@Sun.COM  */
198511963SAfshin.Ardakani@Sun.COM void
198611963SAfshin.Ardakani@Sun.COM smb_cred_rele(cred_t *cr)
198711963SAfshin.Ardakani@Sun.COM {
198811963SAfshin.Ardakani@Sun.COM 	ASSERT(cr);
198911963SAfshin.Ardakani@Sun.COM 	crfree(cr);
199011963SAfshin.Ardakani@Sun.COM }
199111963SAfshin.Ardakani@Sun.COM 
199211963SAfshin.Ardakani@Sun.COM /*
199311963SAfshin.Ardakani@Sun.COM  * smb_cred_is_member
199411963SAfshin.Ardakani@Sun.COM  *
199511963SAfshin.Ardakani@Sun.COM  * Same as smb_token_is_member. The only difference is that
199611963SAfshin.Ardakani@Sun.COM  * we compare the given SID against user SID and the ksidlist
199711963SAfshin.Ardakani@Sun.COM  * of the user's cred.
199811963SAfshin.Ardakani@Sun.COM  */
199911963SAfshin.Ardakani@Sun.COM int
200011963SAfshin.Ardakani@Sun.COM smb_cred_is_member(cred_t *cr, smb_sid_t *sid)
200111963SAfshin.Ardakani@Sun.COM {
200211963SAfshin.Ardakani@Sun.COM 	ksidlist_t *ksidlist;
200311963SAfshin.Ardakani@Sun.COM 	ksid_t ksid1, *ksid2;
200411963SAfshin.Ardakani@Sun.COM 	smb_id_t id;
200511963SAfshin.Ardakani@Sun.COM 	int i, rc = 0;
200611963SAfshin.Ardakani@Sun.COM 
200711963SAfshin.Ardakani@Sun.COM 	ASSERT(cr);
200811963SAfshin.Ardakani@Sun.COM 
200911963SAfshin.Ardakani@Sun.COM 	bzero(&id, sizeof (smb_id_t));
201011963SAfshin.Ardakani@Sun.COM 	id.i_sid = sid;
201111963SAfshin.Ardakani@Sun.COM 	smb_cred_set_sid(&id, &ksid1);
201211963SAfshin.Ardakani@Sun.COM 
201311963SAfshin.Ardakani@Sun.COM 	ksidlist = crgetsidlist(cr);
201411963SAfshin.Ardakani@Sun.COM 	ASSERT(ksidlist);
201511963SAfshin.Ardakani@Sun.COM 	ASSERT(ksid1.ks_domain);
201611963SAfshin.Ardakani@Sun.COM 	ASSERT(ksid1.ks_domain->kd_name);
201711963SAfshin.Ardakani@Sun.COM 
201811963SAfshin.Ardakani@Sun.COM 	i = 0;
201911963SAfshin.Ardakani@Sun.COM 	ksid2 = crgetsid(cr, KSID_USER);
202011963SAfshin.Ardakani@Sun.COM 	do {
202111963SAfshin.Ardakani@Sun.COM 		ASSERT(ksid2->ks_domain);
202211963SAfshin.Ardakani@Sun.COM 		ASSERT(ksid2->ks_domain->kd_name);
202311963SAfshin.Ardakani@Sun.COM 
202411963SAfshin.Ardakani@Sun.COM 		if (strcmp(ksid1.ks_domain->kd_name,
202511963SAfshin.Ardakani@Sun.COM 		    ksid2->ks_domain->kd_name) == 0 &&
202611963SAfshin.Ardakani@Sun.COM 		    ksid1.ks_rid == ksid2->ks_rid) {
202711963SAfshin.Ardakani@Sun.COM 			rc = 1;
202811963SAfshin.Ardakani@Sun.COM 			break;
202911963SAfshin.Ardakani@Sun.COM 		}
203011963SAfshin.Ardakani@Sun.COM 
203111963SAfshin.Ardakani@Sun.COM 		ksid2 = &ksidlist->ksl_sids[i];
203211963SAfshin.Ardakani@Sun.COM 	} while (i++ < ksidlist->ksl_nsid);
203311963SAfshin.Ardakani@Sun.COM 
203411963SAfshin.Ardakani@Sun.COM 	ksid_rele(&ksid1);
203511963SAfshin.Ardakani@Sun.COM 	return (rc);
203611963SAfshin.Ardakani@Sun.COM }
203711963SAfshin.Ardakani@Sun.COM 
203811963SAfshin.Ardakani@Sun.COM /*
203911963SAfshin.Ardakani@Sun.COM  * smb_cred_create_privs
204011963SAfshin.Ardakani@Sun.COM  *
204111963SAfshin.Ardakani@Sun.COM  * Creates a duplicate credential that contains system privileges for
204211963SAfshin.Ardakani@Sun.COM  * certain SMB privileges: Backup and Restore.
204311963SAfshin.Ardakani@Sun.COM  *
204411963SAfshin.Ardakani@Sun.COM  */
204511963SAfshin.Ardakani@Sun.COM cred_t *
204611963SAfshin.Ardakani@Sun.COM smb_cred_create_privs(cred_t *user_cr, uint32_t privileges)
204711963SAfshin.Ardakani@Sun.COM {
204811963SAfshin.Ardakani@Sun.COM 	cred_t *cr = NULL;
204911963SAfshin.Ardakani@Sun.COM 
205011963SAfshin.Ardakani@Sun.COM 	ASSERT(user_cr != NULL);
205111963SAfshin.Ardakani@Sun.COM 
205211963SAfshin.Ardakani@Sun.COM 	if (privileges & (SMB_USER_PRIV_BACKUP | SMB_USER_PRIV_RESTORE))
205311963SAfshin.Ardakani@Sun.COM 		cr = crdup(user_cr);
205411963SAfshin.Ardakani@Sun.COM 
205511963SAfshin.Ardakani@Sun.COM 	if (cr == NULL)
205611963SAfshin.Ardakani@Sun.COM 		return (NULL);
205711963SAfshin.Ardakani@Sun.COM 
205811963SAfshin.Ardakani@Sun.COM 	if (privileges & SMB_USER_PRIV_BACKUP) {
205911963SAfshin.Ardakani@Sun.COM 		(void) crsetpriv(cr, PRIV_FILE_DAC_READ,
206011963SAfshin.Ardakani@Sun.COM 		    PRIV_FILE_DAC_SEARCH, PRIV_SYS_MOUNT, NULL);
206111963SAfshin.Ardakani@Sun.COM 	}
206211963SAfshin.Ardakani@Sun.COM 
206311963SAfshin.Ardakani@Sun.COM 	if (privileges & SMB_USER_PRIV_RESTORE) {
206411963SAfshin.Ardakani@Sun.COM 		(void) crsetpriv(cr, PRIV_FILE_DAC_WRITE,
206511963SAfshin.Ardakani@Sun.COM 		    PRIV_FILE_CHOWN, PRIV_FILE_CHOWN_SELF,
206611963SAfshin.Ardakani@Sun.COM 		    PRIV_FILE_DAC_SEARCH, PRIV_FILE_LINK_ANY,
206711963SAfshin.Ardakani@Sun.COM 		    PRIV_FILE_OWNER, PRIV_FILE_SETID, PRIV_SYS_LINKDIR,
206811963SAfshin.Ardakani@Sun.COM 		    PRIV_SYS_MOUNT, NULL);
206911963SAfshin.Ardakani@Sun.COM 	}
207011963SAfshin.Ardakani@Sun.COM 
207111963SAfshin.Ardakani@Sun.COM 	return (cr);
207211963SAfshin.Ardakani@Sun.COM }
207311963SAfshin.Ardakani@Sun.COM 
207411963SAfshin.Ardakani@Sun.COM /*
207511963SAfshin.Ardakani@Sun.COM  * smb_pad_align
207611963SAfshin.Ardakani@Sun.COM  *
207711963SAfshin.Ardakani@Sun.COM  * Returns the number of bytes required to pad an offset to the
207811963SAfshin.Ardakani@Sun.COM  * specified alignment.
207911963SAfshin.Ardakani@Sun.COM  */
208011963SAfshin.Ardakani@Sun.COM uint32_t
208111963SAfshin.Ardakani@Sun.COM smb_pad_align(uint32_t offset, uint32_t align)
208211963SAfshin.Ardakani@Sun.COM {
208311963SAfshin.Ardakani@Sun.COM 	uint32_t pad = offset % align;
208411963SAfshin.Ardakani@Sun.COM 
208511963SAfshin.Ardakani@Sun.COM 	if (pad != 0)
208611963SAfshin.Ardakani@Sun.COM 		pad = align - pad;
208711963SAfshin.Ardakani@Sun.COM 
208811963SAfshin.Ardakani@Sun.COM 	return (pad);
208911963SAfshin.Ardakani@Sun.COM }
209011963SAfshin.Ardakani@Sun.COM 
209111963SAfshin.Ardakani@Sun.COM /*
209211963SAfshin.Ardakani@Sun.COM  * smb_panic
209311963SAfshin.Ardakani@Sun.COM  *
209411963SAfshin.Ardakani@Sun.COM  * Logs the file name, function name and line number passed in and panics the
209511963SAfshin.Ardakani@Sun.COM  * system.
209611963SAfshin.Ardakani@Sun.COM  */
209711963SAfshin.Ardakani@Sun.COM void
209811963SAfshin.Ardakani@Sun.COM smb_panic(char *file, const char *func, int line)
209911963SAfshin.Ardakani@Sun.COM {
210011963SAfshin.Ardakani@Sun.COM 	cmn_err(CE_PANIC, "%s:%s:%d\n", file, func, line);
210111963SAfshin.Ardakani@Sun.COM }
2102