xref: /titanic_51/usr/src/uts/common/fs/sockfs/socksyscalls.c (revision f50f46215b324b434dc67ea59c00d8ff92fb92ef)
17c478bd9Sstevel@tonic-gate /*
27c478bd9Sstevel@tonic-gate  * CDDL HEADER START
37c478bd9Sstevel@tonic-gate  *
47c478bd9Sstevel@tonic-gate  * The contents of this file are subject to the terms of the
52caf0dcdSrshoaib  * Common Development and Distribution License (the "License").
62caf0dcdSrshoaib  * You may not use this file except in compliance with the License.
77c478bd9Sstevel@tonic-gate  *
87c478bd9Sstevel@tonic-gate  * You can obtain a copy of the license at usr/src/OPENSOLARIS.LICENSE
97c478bd9Sstevel@tonic-gate  * or http://www.opensolaris.org/os/licensing.
107c478bd9Sstevel@tonic-gate  * See the License for the specific language governing permissions
117c478bd9Sstevel@tonic-gate  * and limitations under the License.
127c478bd9Sstevel@tonic-gate  *
137c478bd9Sstevel@tonic-gate  * When distributing Covered Code, include this CDDL HEADER in each
147c478bd9Sstevel@tonic-gate  * file and include the License file at usr/src/OPENSOLARIS.LICENSE.
157c478bd9Sstevel@tonic-gate  * If applicable, add the following below this CDDL HEADER, with the
167c478bd9Sstevel@tonic-gate  * fields enclosed by brackets "[]" replaced with your own identifying
177c478bd9Sstevel@tonic-gate  * information: Portions Copyright [yyyy] [name of copyright owner]
187c478bd9Sstevel@tonic-gate  *
197c478bd9Sstevel@tonic-gate  * CDDL HEADER END
207c478bd9Sstevel@tonic-gate  */
212caf0dcdSrshoaib 
227c478bd9Sstevel@tonic-gate /*
233e95bd4aSAnders Persson  * Copyright (c) 1995, 2010, Oracle and/or its affiliates. All rights reserved.
247c478bd9Sstevel@tonic-gate  */
257c478bd9Sstevel@tonic-gate 
26187670a0STheo Schlossnagle /* Copyright (c) 2013, OmniTI Computer Consulting, Inc. All rights reserved. */
2719581f84SAlexander Eremin /*
2819581f84SAlexander Eremin  * Copyright 2015 Nexenta Systems, Inc. All rights reserved.
2919581f84SAlexander Eremin  */
30187670a0STheo Schlossnagle 
317c478bd9Sstevel@tonic-gate #include <sys/types.h>
327c478bd9Sstevel@tonic-gate #include <sys/t_lock.h>
337c478bd9Sstevel@tonic-gate #include <sys/param.h>
347c478bd9Sstevel@tonic-gate #include <sys/systm.h>
357c478bd9Sstevel@tonic-gate #include <sys/buf.h>
367c478bd9Sstevel@tonic-gate #include <sys/conf.h>
377c478bd9Sstevel@tonic-gate #include <sys/cred.h>
387c478bd9Sstevel@tonic-gate #include <sys/kmem.h>
397c478bd9Sstevel@tonic-gate #include <sys/sysmacros.h>
407c478bd9Sstevel@tonic-gate #include <sys/vfs.h>
417c478bd9Sstevel@tonic-gate #include <sys/vnode.h>
427c478bd9Sstevel@tonic-gate #include <sys/debug.h>
437c478bd9Sstevel@tonic-gate #include <sys/errno.h>
447c478bd9Sstevel@tonic-gate #include <sys/time.h>
457c478bd9Sstevel@tonic-gate #include <sys/file.h>
467c478bd9Sstevel@tonic-gate #include <sys/user.h>
477c478bd9Sstevel@tonic-gate #include <sys/stream.h>
487c478bd9Sstevel@tonic-gate #include <sys/strsubr.h>
497c478bd9Sstevel@tonic-gate #include <sys/strsun.h>
5074024373Spr14459 #include <sys/sunddi.h>
517c478bd9Sstevel@tonic-gate #include <sys/esunddi.h>
527c478bd9Sstevel@tonic-gate #include <sys/flock.h>
537c478bd9Sstevel@tonic-gate #include <sys/modctl.h>
547c478bd9Sstevel@tonic-gate #include <sys/cmn_err.h>
557c478bd9Sstevel@tonic-gate #include <sys/vmsystm.h>
567c478bd9Sstevel@tonic-gate #include <sys/policy.h>
577c478bd9Sstevel@tonic-gate 
587c478bd9Sstevel@tonic-gate #include <sys/socket.h>
597c478bd9Sstevel@tonic-gate #include <sys/socketvar.h>
607c478bd9Sstevel@tonic-gate 
617c478bd9Sstevel@tonic-gate #include <sys/isa_defs.h>
627c478bd9Sstevel@tonic-gate #include <sys/inttypes.h>
637c478bd9Sstevel@tonic-gate #include <sys/systm.h>
647c478bd9Sstevel@tonic-gate #include <sys/cpuvar.h>
657c478bd9Sstevel@tonic-gate #include <sys/filio.h>
667c478bd9Sstevel@tonic-gate #include <sys/sendfile.h>
677c478bd9Sstevel@tonic-gate #include <sys/ddi.h>
687c478bd9Sstevel@tonic-gate #include <vm/seg.h>
697c478bd9Sstevel@tonic-gate #include <vm/seg_map.h>
707c478bd9Sstevel@tonic-gate #include <vm/seg_kpm.h>
710f1702c5SYu Xiangning 
727c478bd9Sstevel@tonic-gate #include <fs/sockfs/nl7c.h>
730f1702c5SYu Xiangning #include <fs/sockfs/sockcommon.h>
743e95bd4aSAnders Persson #include <fs/sockfs/sockfilter_impl.h>
750f1702c5SYu Xiangning #include <fs/sockfs/socktpi.h>
767c478bd9Sstevel@tonic-gate 
777c478bd9Sstevel@tonic-gate #ifdef SOCK_TEST
787c478bd9Sstevel@tonic-gate int do_useracc = 1;		/* Controlled by setting SO_DEBUG to 4 */
797c478bd9Sstevel@tonic-gate #else
807c478bd9Sstevel@tonic-gate #define	do_useracc	1
817c478bd9Sstevel@tonic-gate #endif /* SOCK_TEST */
827c478bd9Sstevel@tonic-gate 
837c478bd9Sstevel@tonic-gate extern int	xnet_truncate_print;
847c478bd9Sstevel@tonic-gate 
853e95bd4aSAnders Persson extern void	nl7c_init(void);
863e95bd4aSAnders Persson extern int	sockfs_defer_nl7c_init;
873e95bd4aSAnders Persson 
887c478bd9Sstevel@tonic-gate /*
897c478bd9Sstevel@tonic-gate  * Note: DEF_IOV_MAX is defined and used as it is in "fs/vncalls.c"
907c478bd9Sstevel@tonic-gate  *	 as there isn't a formal definition of IOV_MAX ???
917c478bd9Sstevel@tonic-gate  */
927c478bd9Sstevel@tonic-gate #define	MSG_MAXIOVLEN	16
937c478bd9Sstevel@tonic-gate 
947c478bd9Sstevel@tonic-gate /*
957c478bd9Sstevel@tonic-gate  * Kernel component of socket creation.
967c478bd9Sstevel@tonic-gate  *
977c478bd9Sstevel@tonic-gate  * The socket library determines which version number to use.
987c478bd9Sstevel@tonic-gate  * First the library calls this with a NULL devpath. If this fails
997c478bd9Sstevel@tonic-gate  * to find a transport (using solookup) the library will look in /etc/netconfig
1007c478bd9Sstevel@tonic-gate  * for the appropriate transport. If one is found it will pass in the
1017c478bd9Sstevel@tonic-gate  * devpath for the kernel to use.
1027c478bd9Sstevel@tonic-gate  */
1037c478bd9Sstevel@tonic-gate int
104187670a0STheo Schlossnagle so_socket(int family, int type_w_flags, int protocol, char *devpath,
105187670a0STheo Schlossnagle     int version)
1067c478bd9Sstevel@tonic-gate {
1077c478bd9Sstevel@tonic-gate 	struct sonode *so;
1087c478bd9Sstevel@tonic-gate 	vnode_t *vp;
1097c478bd9Sstevel@tonic-gate 	struct file *fp;
1107c478bd9Sstevel@tonic-gate 	int fd;
1117c478bd9Sstevel@tonic-gate 	int error;
112187670a0STheo Schlossnagle 	int type;
1137c478bd9Sstevel@tonic-gate 
114187670a0STheo Schlossnagle 	type = type_w_flags & SOCK_TYPE_MASK;
115a63a4ea3SKeith M Wesolowski 	type_w_flags &= ~SOCK_TYPE_MASK;
116a63a4ea3SKeith M Wesolowski 	if (type_w_flags & ~(SOCK_CLOEXEC|SOCK_NDELAY|SOCK_NONBLOCK))
117a63a4ea3SKeith M Wesolowski 		return (set_errno(EINVAL));
118a63a4ea3SKeith M Wesolowski 
1190f1702c5SYu Xiangning 	if (devpath != NULL) {
1200f1702c5SYu Xiangning 		char *buf;
1210f1702c5SYu Xiangning 		size_t kdevpathlen = 0;
1227c478bd9Sstevel@tonic-gate 
1230f1702c5SYu Xiangning 		buf = kmem_alloc(MAXPATHLEN, KM_SLEEP);
1240f1702c5SYu Xiangning 		if ((error = copyinstr(devpath, buf,
1250f1702c5SYu Xiangning 		    MAXPATHLEN, &kdevpathlen)) != 0) {
1260f1702c5SYu Xiangning 			kmem_free(buf, MAXPATHLEN);
1277c478bd9Sstevel@tonic-gate 			return (set_errno(error));
1287c478bd9Sstevel@tonic-gate 		}
1290f1702c5SYu Xiangning 		so = socket_create(family, type, protocol, buf, NULL,
1300f1702c5SYu Xiangning 		    SOCKET_SLEEP, version, CRED(), &error);
1310f1702c5SYu Xiangning 		kmem_free(buf, MAXPATHLEN);
1327c478bd9Sstevel@tonic-gate 	} else {
1330f1702c5SYu Xiangning 		so = socket_create(family, type, protocol, NULL, NULL,
1340f1702c5SYu Xiangning 		    SOCKET_SLEEP, version, CRED(), &error);
1357c478bd9Sstevel@tonic-gate 	}
1360f1702c5SYu Xiangning 	if (so == NULL)
1377c478bd9Sstevel@tonic-gate 		return (set_errno(error));
1387c478bd9Sstevel@tonic-gate 
1390f1702c5SYu Xiangning 	/* Allocate a file descriptor for the socket */
1400f1702c5SYu Xiangning 	vp = SOTOV(so);
1417c478bd9Sstevel@tonic-gate 	if (error = falloc(vp, FWRITE|FREAD, &fp, &fd)) {
1420f1702c5SYu Xiangning 		(void) socket_close(so, 0, CRED());
1430f1702c5SYu Xiangning 		socket_destroy(so);
1447c478bd9Sstevel@tonic-gate 		return (set_errno(error));
1457c478bd9Sstevel@tonic-gate 	}
1467c478bd9Sstevel@tonic-gate 
1477c478bd9Sstevel@tonic-gate 	/*
1487c478bd9Sstevel@tonic-gate 	 * Now fill in the entries that falloc reserved
1497c478bd9Sstevel@tonic-gate 	 */
150a63a4ea3SKeith M Wesolowski 	if (type_w_flags & SOCK_NDELAY) {
151a63a4ea3SKeith M Wesolowski 		so->so_state |= SS_NDELAY;
152a63a4ea3SKeith M Wesolowski 		fp->f_flag |= FNDELAY;
153a63a4ea3SKeith M Wesolowski 	}
154a63a4ea3SKeith M Wesolowski 	if (type_w_flags & SOCK_NONBLOCK) {
155a63a4ea3SKeith M Wesolowski 		so->so_state |= SS_NONBLOCK;
156a63a4ea3SKeith M Wesolowski 		fp->f_flag |= FNONBLOCK;
157a63a4ea3SKeith M Wesolowski 	}
1587c478bd9Sstevel@tonic-gate 	mutex_exit(&fp->f_tlock);
1597c478bd9Sstevel@tonic-gate 	setf(fd, fp);
160187670a0STheo Schlossnagle 	if ((type_w_flags & SOCK_CLOEXEC) != 0) {
161187670a0STheo Schlossnagle 		f_setfd(fd, FD_CLOEXEC);
162187670a0STheo Schlossnagle 	}
1637c478bd9Sstevel@tonic-gate 
1647c478bd9Sstevel@tonic-gate 	return (fd);
1657c478bd9Sstevel@tonic-gate }
1667c478bd9Sstevel@tonic-gate 
1677c478bd9Sstevel@tonic-gate /*
1687c478bd9Sstevel@tonic-gate  * Map from a file descriptor to a socket node.
1697c478bd9Sstevel@tonic-gate  * Returns with the file descriptor held i.e. the caller has to
1707c478bd9Sstevel@tonic-gate  * use releasef when done with the file descriptor.
1717c478bd9Sstevel@tonic-gate  */
172745b2690Stz204579 struct sonode *
1737c478bd9Sstevel@tonic-gate getsonode(int sock, int *errorp, file_t **fpp)
1747c478bd9Sstevel@tonic-gate {
1757c478bd9Sstevel@tonic-gate 	file_t *fp;
1767c478bd9Sstevel@tonic-gate 	vnode_t *vp;
1777c478bd9Sstevel@tonic-gate 	struct sonode *so;
1787c478bd9Sstevel@tonic-gate 
1797c478bd9Sstevel@tonic-gate 	if ((fp = getf(sock)) == NULL) {
1807c478bd9Sstevel@tonic-gate 		*errorp = EBADF;
1817c478bd9Sstevel@tonic-gate 		eprintline(*errorp);
1827c478bd9Sstevel@tonic-gate 		return (NULL);
1837c478bd9Sstevel@tonic-gate 	}
1847c478bd9Sstevel@tonic-gate 	vp = fp->f_vnode;
1857c478bd9Sstevel@tonic-gate 	/* Check if it is a socket */
1867c478bd9Sstevel@tonic-gate 	if (vp->v_type != VSOCK) {
1877c478bd9Sstevel@tonic-gate 		releasef(sock);
1887c478bd9Sstevel@tonic-gate 		*errorp = ENOTSOCK;
1897c478bd9Sstevel@tonic-gate 		eprintline(*errorp);
1907c478bd9Sstevel@tonic-gate 		return (NULL);
1917c478bd9Sstevel@tonic-gate 	}
1927c478bd9Sstevel@tonic-gate 	/*
1937c478bd9Sstevel@tonic-gate 	 * Use the stream head to find the real socket vnode.
1947c478bd9Sstevel@tonic-gate 	 * This is needed when namefs sits above sockfs.
1957c478bd9Sstevel@tonic-gate 	 */
1967c478bd9Sstevel@tonic-gate 	if (vp->v_stream) {
1977c478bd9Sstevel@tonic-gate 		ASSERT(vp->v_stream->sd_vnode);
1987c478bd9Sstevel@tonic-gate 		vp = vp->v_stream->sd_vnode;
1997c478bd9Sstevel@tonic-gate 
2007c478bd9Sstevel@tonic-gate 		so = VTOSO(vp);
2017c478bd9Sstevel@tonic-gate 		if (so->so_version == SOV_STREAM) {
2027c478bd9Sstevel@tonic-gate 			releasef(sock);
2037c478bd9Sstevel@tonic-gate 			*errorp = ENOTSOCK;
2047c478bd9Sstevel@tonic-gate 			eprintsoline(so, *errorp);
2057c478bd9Sstevel@tonic-gate 			return (NULL);
2067c478bd9Sstevel@tonic-gate 		}
2077c478bd9Sstevel@tonic-gate 	} else {
2087c478bd9Sstevel@tonic-gate 		so = VTOSO(vp);
2097c478bd9Sstevel@tonic-gate 	}
2107c478bd9Sstevel@tonic-gate 	if (fpp)
2117c478bd9Sstevel@tonic-gate 		*fpp = fp;
2127c478bd9Sstevel@tonic-gate 	return (so);
2137c478bd9Sstevel@tonic-gate }
2147c478bd9Sstevel@tonic-gate 
2157c478bd9Sstevel@tonic-gate /*
2167c478bd9Sstevel@tonic-gate  * Allocate and copyin a sockaddr.
2177c478bd9Sstevel@tonic-gate  * Ensures NULL termination for AF_UNIX addresses by extending them
2187c478bd9Sstevel@tonic-gate  * with one NULL byte if need be. Verifies that the length is not
2197c478bd9Sstevel@tonic-gate  * excessive to prevent an application from consuming all of kernel
2207c478bd9Sstevel@tonic-gate  * memory. Returns NULL when an error occurred.
2217c478bd9Sstevel@tonic-gate  */
2227c478bd9Sstevel@tonic-gate static struct sockaddr *
2237c478bd9Sstevel@tonic-gate copyin_name(struct sonode *so, struct sockaddr *name, socklen_t *namelenp,
2247c478bd9Sstevel@tonic-gate     int *errorp)
2257c478bd9Sstevel@tonic-gate {
2267c478bd9Sstevel@tonic-gate 	char	*faddr;
2277c478bd9Sstevel@tonic-gate 	size_t	namelen = (size_t)*namelenp;
2287c478bd9Sstevel@tonic-gate 
2297c478bd9Sstevel@tonic-gate 	ASSERT(namelen != 0);
2307c478bd9Sstevel@tonic-gate 	if (namelen > SO_MAXARGSIZE) {
2317c478bd9Sstevel@tonic-gate 		*errorp = EINVAL;
2327c478bd9Sstevel@tonic-gate 		eprintsoline(so, *errorp);
2337c478bd9Sstevel@tonic-gate 		return (NULL);
2347c478bd9Sstevel@tonic-gate 	}
2357c478bd9Sstevel@tonic-gate 
2367c478bd9Sstevel@tonic-gate 	faddr = (char *)kmem_alloc(namelen, KM_SLEEP);
2377c478bd9Sstevel@tonic-gate 	if (copyin(name, faddr, namelen)) {
2387c478bd9Sstevel@tonic-gate 		kmem_free(faddr, namelen);
2397c478bd9Sstevel@tonic-gate 		*errorp = EFAULT;
2407c478bd9Sstevel@tonic-gate 		eprintsoline(so, *errorp);
2417c478bd9Sstevel@tonic-gate 		return (NULL);
2427c478bd9Sstevel@tonic-gate 	}
2437c478bd9Sstevel@tonic-gate 
2447c478bd9Sstevel@tonic-gate 	/*
2457c478bd9Sstevel@tonic-gate 	 * Add space for NULL termination if needed.
2467c478bd9Sstevel@tonic-gate 	 * Do a quick check if the last byte is NUL.
2477c478bd9Sstevel@tonic-gate 	 */
2487c478bd9Sstevel@tonic-gate 	if (so->so_family == AF_UNIX && faddr[namelen - 1] != '\0') {
2497c478bd9Sstevel@tonic-gate 		/* Check if there is any NULL termination */
2507c478bd9Sstevel@tonic-gate 		size_t	i;
2517c478bd9Sstevel@tonic-gate 		int foundnull = 0;
2527c478bd9Sstevel@tonic-gate 
2537c478bd9Sstevel@tonic-gate 		for (i = sizeof (name->sa_family); i < namelen; i++) {
2547c478bd9Sstevel@tonic-gate 			if (faddr[i] == '\0') {
2557c478bd9Sstevel@tonic-gate 				foundnull = 1;
2567c478bd9Sstevel@tonic-gate 				break;
2577c478bd9Sstevel@tonic-gate 			}
2587c478bd9Sstevel@tonic-gate 		}
2597c478bd9Sstevel@tonic-gate 		if (!foundnull) {
2607c478bd9Sstevel@tonic-gate 			/* Add extra byte for NUL padding */
2617c478bd9Sstevel@tonic-gate 			char *nfaddr;
2627c478bd9Sstevel@tonic-gate 
2637c478bd9Sstevel@tonic-gate 			nfaddr = (char *)kmem_alloc(namelen + 1, KM_SLEEP);
2647c478bd9Sstevel@tonic-gate 			bcopy(faddr, nfaddr, namelen);
2657c478bd9Sstevel@tonic-gate 			kmem_free(faddr, namelen);
2667c478bd9Sstevel@tonic-gate 
2677c478bd9Sstevel@tonic-gate 			/* NUL terminate */
2687c478bd9Sstevel@tonic-gate 			nfaddr[namelen] = '\0';
2697c478bd9Sstevel@tonic-gate 			namelen++;
2707c478bd9Sstevel@tonic-gate 			ASSERT((socklen_t)namelen == namelen);
2717c478bd9Sstevel@tonic-gate 			*namelenp = (socklen_t)namelen;
2727c478bd9Sstevel@tonic-gate 			faddr = nfaddr;
2737c478bd9Sstevel@tonic-gate 		}
2747c478bd9Sstevel@tonic-gate 	}
2757c478bd9Sstevel@tonic-gate 	return ((struct sockaddr *)faddr);
2767c478bd9Sstevel@tonic-gate }
2777c478bd9Sstevel@tonic-gate 
2787c478bd9Sstevel@tonic-gate /*
2797c478bd9Sstevel@tonic-gate  * Copy from kaddr/klen to uaddr/ulen. Updates ulenp if non-NULL.
2807c478bd9Sstevel@tonic-gate  */
2817c478bd9Sstevel@tonic-gate static int
282*f50f4621SMarcel Telka copyout_arg(void *uaddr, socklen_t ulen, void *ulenp, void *kaddr,
283*f50f4621SMarcel Telka     socklen_t klen)
2847c478bd9Sstevel@tonic-gate {
2857c478bd9Sstevel@tonic-gate 	if (uaddr != NULL) {
2867c478bd9Sstevel@tonic-gate 		if (ulen > klen)
2877c478bd9Sstevel@tonic-gate 			ulen = klen;
2887c478bd9Sstevel@tonic-gate 
2897c478bd9Sstevel@tonic-gate 		if (ulen != 0) {
2907c478bd9Sstevel@tonic-gate 			if (copyout(kaddr, uaddr, ulen))
2917c478bd9Sstevel@tonic-gate 				return (EFAULT);
2927c478bd9Sstevel@tonic-gate 		}
2937c478bd9Sstevel@tonic-gate 	} else
2947c478bd9Sstevel@tonic-gate 		ulen = 0;
2957c478bd9Sstevel@tonic-gate 
2967c478bd9Sstevel@tonic-gate 	if (ulenp != NULL) {
2977c478bd9Sstevel@tonic-gate 		if (copyout(&ulen, ulenp, sizeof (ulen)))
2987c478bd9Sstevel@tonic-gate 			return (EFAULT);
2997c478bd9Sstevel@tonic-gate 	}
3007c478bd9Sstevel@tonic-gate 	return (0);
3017c478bd9Sstevel@tonic-gate }
3027c478bd9Sstevel@tonic-gate 
3037c478bd9Sstevel@tonic-gate /*
3047c478bd9Sstevel@tonic-gate  * Copy from kaddr/klen to uaddr/ulen. Updates ulenp if non-NULL.
3057c478bd9Sstevel@tonic-gate  * If klen is greater than ulen it still uses the non-truncated
3067c478bd9Sstevel@tonic-gate  * klen to update ulenp.
3077c478bd9Sstevel@tonic-gate  */
3087c478bd9Sstevel@tonic-gate static int
309*f50f4621SMarcel Telka copyout_name(void *uaddr, socklen_t ulen, void *ulenp, void *kaddr,
310*f50f4621SMarcel Telka     socklen_t klen)
3117c478bd9Sstevel@tonic-gate {
3127c478bd9Sstevel@tonic-gate 	if (uaddr != NULL) {
3137c478bd9Sstevel@tonic-gate 		if (ulen >= klen)
3147c478bd9Sstevel@tonic-gate 			ulen = klen;
3157c478bd9Sstevel@tonic-gate 		else if (ulen != 0 && xnet_truncate_print) {
3167c478bd9Sstevel@tonic-gate 			printf("sockfs: truncating copyout of address using "
3177c478bd9Sstevel@tonic-gate 			    "XNET semantics for pid = %d. Lengths %d, %d\n",
3187c478bd9Sstevel@tonic-gate 			    curproc->p_pid, klen, ulen);
3197c478bd9Sstevel@tonic-gate 		}
3207c478bd9Sstevel@tonic-gate 
3217c478bd9Sstevel@tonic-gate 		if (ulen != 0) {
3227c478bd9Sstevel@tonic-gate 			if (copyout(kaddr, uaddr, ulen))
3237c478bd9Sstevel@tonic-gate 				return (EFAULT);
3247c478bd9Sstevel@tonic-gate 		} else
3257c478bd9Sstevel@tonic-gate 			klen = 0;
3267c478bd9Sstevel@tonic-gate 	} else
3277c478bd9Sstevel@tonic-gate 		klen = 0;
3287c478bd9Sstevel@tonic-gate 
3297c478bd9Sstevel@tonic-gate 	if (ulenp != NULL) {
3307c478bd9Sstevel@tonic-gate 		if (copyout(&klen, ulenp, sizeof (klen)))
3317c478bd9Sstevel@tonic-gate 			return (EFAULT);
3327c478bd9Sstevel@tonic-gate 	}
3337c478bd9Sstevel@tonic-gate 	return (0);
3347c478bd9Sstevel@tonic-gate }
3357c478bd9Sstevel@tonic-gate 
3367c478bd9Sstevel@tonic-gate /*
3377c478bd9Sstevel@tonic-gate  * The socketpair() code in libsocket creates two sockets (using
3387c478bd9Sstevel@tonic-gate  * the /etc/netconfig fallback if needed) before calling this routine
3397c478bd9Sstevel@tonic-gate  * to connect the two sockets together.
3407c478bd9Sstevel@tonic-gate  *
3417c478bd9Sstevel@tonic-gate  * For a SOCK_STREAM socketpair a listener is needed - in that case this
3427c478bd9Sstevel@tonic-gate  * routine will create a new file descriptor as part of accepting the
3437c478bd9Sstevel@tonic-gate  * connection. The library socketpair() will check if svs[2] has changed
3447c478bd9Sstevel@tonic-gate  * in which case it will close the changed fd.
3457c478bd9Sstevel@tonic-gate  *
3467c478bd9Sstevel@tonic-gate  * Note that this code could use the TPI feature of accepting the connection
3477c478bd9Sstevel@tonic-gate  * on the listening endpoint. However, that would require significant changes
3487c478bd9Sstevel@tonic-gate  * to soaccept.
3497c478bd9Sstevel@tonic-gate  */
3507c478bd9Sstevel@tonic-gate int
3517c478bd9Sstevel@tonic-gate so_socketpair(int sv[2])
3527c478bd9Sstevel@tonic-gate {
3537c478bd9Sstevel@tonic-gate 	int svs[2];
3547c478bd9Sstevel@tonic-gate 	struct sonode *so1, *so2;
3557c478bd9Sstevel@tonic-gate 	int error;
3565dbfd19aSTheo Schlossnagle 	int orig_flags;
3577c478bd9Sstevel@tonic-gate 	struct sockaddr_ux *name;
3587c478bd9Sstevel@tonic-gate 	size_t namelen;
3590f1702c5SYu Xiangning 	sotpi_info_t *sti1;
3600f1702c5SYu Xiangning 	sotpi_info_t *sti2;
3617c478bd9Sstevel@tonic-gate 
362903a11ebSrh87107 	dprint(1, ("so_socketpair(%p)\n", (void *)sv));
3637c478bd9Sstevel@tonic-gate 
3647c478bd9Sstevel@tonic-gate 	error = useracc(sv, sizeof (svs), B_WRITE);
3657c478bd9Sstevel@tonic-gate 	if (error && do_useracc)
3667c478bd9Sstevel@tonic-gate 		return (set_errno(EFAULT));
3677c478bd9Sstevel@tonic-gate 
3687c478bd9Sstevel@tonic-gate 	if (copyin(sv, svs, sizeof (svs)))
3697c478bd9Sstevel@tonic-gate 		return (set_errno(EFAULT));
3707c478bd9Sstevel@tonic-gate 
3717c478bd9Sstevel@tonic-gate 	if ((so1 = getsonode(svs[0], &error, NULL)) == NULL)
3727c478bd9Sstevel@tonic-gate 		return (set_errno(error));
3737c478bd9Sstevel@tonic-gate 
3747c478bd9Sstevel@tonic-gate 	if ((so2 = getsonode(svs[1], &error, NULL)) == NULL) {
3757c478bd9Sstevel@tonic-gate 		releasef(svs[0]);
3767c478bd9Sstevel@tonic-gate 		return (set_errno(error));
3777c478bd9Sstevel@tonic-gate 	}
3787c478bd9Sstevel@tonic-gate 
3797c478bd9Sstevel@tonic-gate 	if (so1->so_family != AF_UNIX || so2->so_family != AF_UNIX) {
3807c478bd9Sstevel@tonic-gate 		error = EOPNOTSUPP;
3817c478bd9Sstevel@tonic-gate 		goto done;
3827c478bd9Sstevel@tonic-gate 	}
3837c478bd9Sstevel@tonic-gate 
3840f1702c5SYu Xiangning 	sti1 = SOTOTPI(so1);
3850f1702c5SYu Xiangning 	sti2 = SOTOTPI(so2);
3860f1702c5SYu Xiangning 
3877c478bd9Sstevel@tonic-gate 	/*
3887c478bd9Sstevel@tonic-gate 	 * The code below makes assumptions about the "sockfs" implementation.
3897c478bd9Sstevel@tonic-gate 	 * So make sure that the correct implementation is really used.
3907c478bd9Sstevel@tonic-gate 	 */
3917c478bd9Sstevel@tonic-gate 	ASSERT(so1->so_ops == &sotpi_sonodeops);
3927c478bd9Sstevel@tonic-gate 	ASSERT(so2->so_ops == &sotpi_sonodeops);
3937c478bd9Sstevel@tonic-gate 
3947c478bd9Sstevel@tonic-gate 	if (so1->so_type == SOCK_DGRAM) {
3957c478bd9Sstevel@tonic-gate 		/*
3967c478bd9Sstevel@tonic-gate 		 * Bind both sockets and connect them with each other.
3977c478bd9Sstevel@tonic-gate 		 * Need to allocate name/namelen for soconnect.
3987c478bd9Sstevel@tonic-gate 		 */
3990f1702c5SYu Xiangning 		error = socket_bind(so1, NULL, 0, _SOBIND_UNSPEC, CRED());
4007c478bd9Sstevel@tonic-gate 		if (error) {
4017c478bd9Sstevel@tonic-gate 			eprintsoline(so1, error);
4027c478bd9Sstevel@tonic-gate 			goto done;
4037c478bd9Sstevel@tonic-gate 		}
4040f1702c5SYu Xiangning 		error = socket_bind(so2, NULL, 0, _SOBIND_UNSPEC, CRED());
4057c478bd9Sstevel@tonic-gate 		if (error) {
4067c478bd9Sstevel@tonic-gate 			eprintsoline(so2, error);
4077c478bd9Sstevel@tonic-gate 			goto done;
4087c478bd9Sstevel@tonic-gate 		}
4097c478bd9Sstevel@tonic-gate 		namelen = sizeof (struct sockaddr_ux);
4107c478bd9Sstevel@tonic-gate 		name = kmem_alloc(namelen, KM_SLEEP);
4117c478bd9Sstevel@tonic-gate 		name->sou_family = AF_UNIX;
4120f1702c5SYu Xiangning 		name->sou_addr = sti2->sti_ux_laddr;
4130f1702c5SYu Xiangning 		error = socket_connect(so1,
4147c478bd9Sstevel@tonic-gate 		    (struct sockaddr *)name,
4157c478bd9Sstevel@tonic-gate 		    (socklen_t)namelen,
4160f1702c5SYu Xiangning 		    0, _SOCONNECT_NOXLATE, CRED());
4177c478bd9Sstevel@tonic-gate 		if (error) {
4187c478bd9Sstevel@tonic-gate 			kmem_free(name, namelen);
4197c478bd9Sstevel@tonic-gate 			eprintsoline(so1, error);
4207c478bd9Sstevel@tonic-gate 			goto done;
4217c478bd9Sstevel@tonic-gate 		}
4220f1702c5SYu Xiangning 		name->sou_addr = sti1->sti_ux_laddr;
4230f1702c5SYu Xiangning 		error = socket_connect(so2,
4247c478bd9Sstevel@tonic-gate 		    (struct sockaddr *)name,
4257c478bd9Sstevel@tonic-gate 		    (socklen_t)namelen,
4260f1702c5SYu Xiangning 		    0, _SOCONNECT_NOXLATE, CRED());
4277c478bd9Sstevel@tonic-gate 		kmem_free(name, namelen);
4287c478bd9Sstevel@tonic-gate 		if (error) {
4297c478bd9Sstevel@tonic-gate 			eprintsoline(so2, error);
4307c478bd9Sstevel@tonic-gate 			goto done;
4317c478bd9Sstevel@tonic-gate 		}
4327c478bd9Sstevel@tonic-gate 		releasef(svs[0]);
4337c478bd9Sstevel@tonic-gate 		releasef(svs[1]);
4347c478bd9Sstevel@tonic-gate 	} else {
4357c478bd9Sstevel@tonic-gate 		/*
4367c478bd9Sstevel@tonic-gate 		 * Bind both sockets, with so1 being a listener.
4377c478bd9Sstevel@tonic-gate 		 * Connect so2 to so1 - nonblocking to avoid waiting for
4387c478bd9Sstevel@tonic-gate 		 * soaccept to complete.
4397c478bd9Sstevel@tonic-gate 		 * Accept a connection on so1. Pass out the new fd as sv[0].
4407c478bd9Sstevel@tonic-gate 		 * The library will detect the changed fd and close
4417c478bd9Sstevel@tonic-gate 		 * the original one.
4427c478bd9Sstevel@tonic-gate 		 */
4437c478bd9Sstevel@tonic-gate 		struct sonode *nso;
4447c478bd9Sstevel@tonic-gate 		struct vnode *nvp;
4457c478bd9Sstevel@tonic-gate 		struct file *nfp;
4467c478bd9Sstevel@tonic-gate 		int nfd;
4477c478bd9Sstevel@tonic-gate 
4487c478bd9Sstevel@tonic-gate 		/*
4490f1702c5SYu Xiangning 		 * We could simply call socket_listen() here (which would do the
4507c478bd9Sstevel@tonic-gate 		 * binding automatically) if the code didn't rely on passing
4510f1702c5SYu Xiangning 		 * _SOBIND_NOXLATE to the TPI implementation of socket_bind().
4527c478bd9Sstevel@tonic-gate 		 */
4530f1702c5SYu Xiangning 		error = socket_bind(so1, NULL, 0, _SOBIND_UNSPEC|
4540f1702c5SYu Xiangning 		    _SOBIND_NOXLATE|_SOBIND_LISTEN|_SOBIND_SOCKETPAIR,
4550f1702c5SYu Xiangning 		    CRED());
4567c478bd9Sstevel@tonic-gate 		if (error) {
4577c478bd9Sstevel@tonic-gate 			eprintsoline(so1, error);
4587c478bd9Sstevel@tonic-gate 			goto done;
4597c478bd9Sstevel@tonic-gate 		}
4600f1702c5SYu Xiangning 		error = socket_bind(so2, NULL, 0, _SOBIND_UNSPEC, CRED());
4617c478bd9Sstevel@tonic-gate 		if (error) {
4627c478bd9Sstevel@tonic-gate 			eprintsoline(so2, error);
4637c478bd9Sstevel@tonic-gate 			goto done;
4647c478bd9Sstevel@tonic-gate 		}
4657c478bd9Sstevel@tonic-gate 
4667c478bd9Sstevel@tonic-gate 		namelen = sizeof (struct sockaddr_ux);
4677c478bd9Sstevel@tonic-gate 		name = kmem_alloc(namelen, KM_SLEEP);
4687c478bd9Sstevel@tonic-gate 		name->sou_family = AF_UNIX;
4690f1702c5SYu Xiangning 		name->sou_addr = sti1->sti_ux_laddr;
4700f1702c5SYu Xiangning 		error = socket_connect(so2,
4717c478bd9Sstevel@tonic-gate 		    (struct sockaddr *)name,
4727c478bd9Sstevel@tonic-gate 		    (socklen_t)namelen,
4730f1702c5SYu Xiangning 		    FNONBLOCK, _SOCONNECT_NOXLATE, CRED());
4747c478bd9Sstevel@tonic-gate 		kmem_free(name, namelen);
4757c478bd9Sstevel@tonic-gate 		if (error) {
4767c478bd9Sstevel@tonic-gate 			if (error != EINPROGRESS) {
4770f1702c5SYu Xiangning 				eprintsoline(so2, error); goto done;
4787c478bd9Sstevel@tonic-gate 			}
4797c478bd9Sstevel@tonic-gate 		}
4807c478bd9Sstevel@tonic-gate 
4810f1702c5SYu Xiangning 		error = socket_accept(so1, 0, CRED(), &nso);
4827c478bd9Sstevel@tonic-gate 		if (error) {
4837c478bd9Sstevel@tonic-gate 			eprintsoline(so1, error);
4847c478bd9Sstevel@tonic-gate 			goto done;
4857c478bd9Sstevel@tonic-gate 		}
4867c478bd9Sstevel@tonic-gate 
4877c478bd9Sstevel@tonic-gate 		/* wait for so2 being SS_CONNECTED ignoring signals */
4887c478bd9Sstevel@tonic-gate 		mutex_enter(&so2->so_lock);
4897c478bd9Sstevel@tonic-gate 		error = sowaitconnected(so2, 0, 1);
4907c478bd9Sstevel@tonic-gate 		mutex_exit(&so2->so_lock);
4917c478bd9Sstevel@tonic-gate 		if (error != 0) {
4920f1702c5SYu Xiangning 			(void) socket_close(nso, 0, CRED());
4930f1702c5SYu Xiangning 			socket_destroy(nso);
4947c478bd9Sstevel@tonic-gate 			eprintsoline(so2, error);
4957c478bd9Sstevel@tonic-gate 			goto done;
4967c478bd9Sstevel@tonic-gate 		}
4977c478bd9Sstevel@tonic-gate 
4980f1702c5SYu Xiangning 		nvp = SOTOV(nso);
4997c478bd9Sstevel@tonic-gate 		if (error = falloc(nvp, FWRITE|FREAD, &nfp, &nfd)) {
5000f1702c5SYu Xiangning 			(void) socket_close(nso, 0, CRED());
5010f1702c5SYu Xiangning 			socket_destroy(nso);
5027c478bd9Sstevel@tonic-gate 			eprintsoline(nso, error);
5037c478bd9Sstevel@tonic-gate 			goto done;
5047c478bd9Sstevel@tonic-gate 		}
5057c478bd9Sstevel@tonic-gate 		/*
506a63a4ea3SKeith M Wesolowski 		 * copy over FNONBLOCK and FNDELAY flags should they exist
507a63a4ea3SKeith M Wesolowski 		 */
508a63a4ea3SKeith M Wesolowski 		if (so1->so_state & SS_NONBLOCK)
509a63a4ea3SKeith M Wesolowski 			nfp->f_flag |= FNONBLOCK;
510a63a4ea3SKeith M Wesolowski 		if (so1->so_state & SS_NDELAY)
511a63a4ea3SKeith M Wesolowski 			nfp->f_flag |= FNDELAY;
512a63a4ea3SKeith M Wesolowski 
513a63a4ea3SKeith M Wesolowski 		/*
5147c478bd9Sstevel@tonic-gate 		 * fill in the entries that falloc reserved
5157c478bd9Sstevel@tonic-gate 		 */
5167c478bd9Sstevel@tonic-gate 		mutex_exit(&nfp->f_tlock);
5177c478bd9Sstevel@tonic-gate 		setf(nfd, nfp);
5187c478bd9Sstevel@tonic-gate 
519a63a4ea3SKeith M Wesolowski 		/*
520a63a4ea3SKeith M Wesolowski 		 * get the original flags before we release
521a63a4ea3SKeith M Wesolowski 		 */
522a63a4ea3SKeith M Wesolowski 		VERIFY(f_getfd_error(svs[0], &orig_flags) == 0);
523a63a4ea3SKeith M Wesolowski 
5247c478bd9Sstevel@tonic-gate 		releasef(svs[0]);
5257c478bd9Sstevel@tonic-gate 		releasef(svs[1]);
5265dbfd19aSTheo Schlossnagle 
5275dbfd19aSTheo Schlossnagle 		/*
5285dbfd19aSTheo Schlossnagle 		 * If FD_CLOEXEC was set on the filedescriptor we're
5295dbfd19aSTheo Schlossnagle 		 * swapping out, we should set it on the new one too.
5305dbfd19aSTheo Schlossnagle 		 */
5315dbfd19aSTheo Schlossnagle 		if (orig_flags & FD_CLOEXEC) {
5325dbfd19aSTheo Schlossnagle 			f_setfd(nfd, FD_CLOEXEC);
5335dbfd19aSTheo Schlossnagle 		}
5347c478bd9Sstevel@tonic-gate 
5357c478bd9Sstevel@tonic-gate 		/*
5367c478bd9Sstevel@tonic-gate 		 * The socketpair library routine will close the original
5377c478bd9Sstevel@tonic-gate 		 * svs[0] when this code passes out a different file
5387c478bd9Sstevel@tonic-gate 		 * descriptor.
5397c478bd9Sstevel@tonic-gate 		 */
5405dbfd19aSTheo Schlossnagle 		svs[0] = nfd;
5415dbfd19aSTheo Schlossnagle 
5427c478bd9Sstevel@tonic-gate 		if (copyout(svs, sv, sizeof (svs))) {
5437c478bd9Sstevel@tonic-gate 			(void) closeandsetf(nfd, NULL);
5447c478bd9Sstevel@tonic-gate 			eprintline(EFAULT);
5457c478bd9Sstevel@tonic-gate 			return (set_errno(EFAULT));
5467c478bd9Sstevel@tonic-gate 		}
5477c478bd9Sstevel@tonic-gate 	}
5487c478bd9Sstevel@tonic-gate 	return (0);
5497c478bd9Sstevel@tonic-gate 
5507c478bd9Sstevel@tonic-gate done:
5517c478bd9Sstevel@tonic-gate 	releasef(svs[0]);
5527c478bd9Sstevel@tonic-gate 	releasef(svs[1]);
5537c478bd9Sstevel@tonic-gate 	return (set_errno(error));
5547c478bd9Sstevel@tonic-gate }
5557c478bd9Sstevel@tonic-gate 
5567c478bd9Sstevel@tonic-gate int
5577c478bd9Sstevel@tonic-gate bind(int sock, struct sockaddr *name, socklen_t namelen, int version)
5587c478bd9Sstevel@tonic-gate {
5597c478bd9Sstevel@tonic-gate 	struct sonode *so;
5607c478bd9Sstevel@tonic-gate 	int error;
5617c478bd9Sstevel@tonic-gate 
5627c478bd9Sstevel@tonic-gate 	dprint(1, ("bind(%d, %p, %d)\n",
563903a11ebSrh87107 	    sock, (void *)name, namelen));
5647c478bd9Sstevel@tonic-gate 
5657c478bd9Sstevel@tonic-gate 	if ((so = getsonode(sock, &error, NULL)) == NULL)
5667c478bd9Sstevel@tonic-gate 		return (set_errno(error));
5677c478bd9Sstevel@tonic-gate 
5687c478bd9Sstevel@tonic-gate 	/* Allocate and copyin name */
5697c478bd9Sstevel@tonic-gate 	/*
5707c478bd9Sstevel@tonic-gate 	 * X/Open test does not expect EFAULT with NULL name and non-zero
5717c478bd9Sstevel@tonic-gate 	 * namelen.
5727c478bd9Sstevel@tonic-gate 	 */
5737c478bd9Sstevel@tonic-gate 	if (name != NULL && namelen != 0) {
5747c478bd9Sstevel@tonic-gate 		ASSERT(MUTEX_NOT_HELD(&so->so_lock));
5757c478bd9Sstevel@tonic-gate 		name = copyin_name(so, name, &namelen, &error);
5767c478bd9Sstevel@tonic-gate 		if (name == NULL) {
5777c478bd9Sstevel@tonic-gate 			releasef(sock);
5787c478bd9Sstevel@tonic-gate 			return (set_errno(error));
5797c478bd9Sstevel@tonic-gate 		}
5807c478bd9Sstevel@tonic-gate 	} else {
5817c478bd9Sstevel@tonic-gate 		name = NULL;
5827c478bd9Sstevel@tonic-gate 		namelen = 0;
5837c478bd9Sstevel@tonic-gate 	}
5847c478bd9Sstevel@tonic-gate 
5857c478bd9Sstevel@tonic-gate 	switch (version) {
5867c478bd9Sstevel@tonic-gate 	default:
5870f1702c5SYu Xiangning 		error = socket_bind(so, name, namelen, 0, CRED());
5887c478bd9Sstevel@tonic-gate 		break;
5897c478bd9Sstevel@tonic-gate 	case SOV_XPG4_2:
5900f1702c5SYu Xiangning 		error = socket_bind(so, name, namelen, _SOBIND_XPG4_2, CRED());
5917c478bd9Sstevel@tonic-gate 		break;
5927c478bd9Sstevel@tonic-gate 	case SOV_SOCKBSD:
5930f1702c5SYu Xiangning 		error = socket_bind(so, name, namelen, _SOBIND_SOCKBSD, CRED());
5947c478bd9Sstevel@tonic-gate 		break;
5957c478bd9Sstevel@tonic-gate 	}
5967c478bd9Sstevel@tonic-gate done:
5977c478bd9Sstevel@tonic-gate 	releasef(sock);
5987c478bd9Sstevel@tonic-gate 	if (name != NULL)
5997c478bd9Sstevel@tonic-gate 		kmem_free(name, (size_t)namelen);
6007c478bd9Sstevel@tonic-gate 
6017c478bd9Sstevel@tonic-gate 	if (error)
6027c478bd9Sstevel@tonic-gate 		return (set_errno(error));
6037c478bd9Sstevel@tonic-gate 	return (0);
6047c478bd9Sstevel@tonic-gate }
6057c478bd9Sstevel@tonic-gate 
6067c478bd9Sstevel@tonic-gate /* ARGSUSED2 */
6077c478bd9Sstevel@tonic-gate int
6087c478bd9Sstevel@tonic-gate listen(int sock, int backlog, int version)
6097c478bd9Sstevel@tonic-gate {
6107c478bd9Sstevel@tonic-gate 	struct sonode *so;
6117c478bd9Sstevel@tonic-gate 	int error;
6127c478bd9Sstevel@tonic-gate 
6137c478bd9Sstevel@tonic-gate 	dprint(1, ("listen(%d, %d)\n",
6147c478bd9Sstevel@tonic-gate 	    sock, backlog));
6157c478bd9Sstevel@tonic-gate 
6167c478bd9Sstevel@tonic-gate 	if ((so = getsonode(sock, &error, NULL)) == NULL)
6177c478bd9Sstevel@tonic-gate 		return (set_errno(error));
6187c478bd9Sstevel@tonic-gate 
6190f1702c5SYu Xiangning 	error = socket_listen(so, backlog, CRED());
6207c478bd9Sstevel@tonic-gate 
6217c478bd9Sstevel@tonic-gate 	releasef(sock);
6227c478bd9Sstevel@tonic-gate 	if (error)
6237c478bd9Sstevel@tonic-gate 		return (set_errno(error));
6247c478bd9Sstevel@tonic-gate 	return (0);
6257c478bd9Sstevel@tonic-gate }
6267c478bd9Sstevel@tonic-gate 
6275eaceb49STheo Schlossnagle /*ARGSUSED3*/
6287c478bd9Sstevel@tonic-gate int
6295dbfd19aSTheo Schlossnagle accept(int sock, struct sockaddr *name, socklen_t *namelenp, int version,
6305dbfd19aSTheo Schlossnagle     int flags)
6317c478bd9Sstevel@tonic-gate {
6327c478bd9Sstevel@tonic-gate 	struct sonode *so;
6337c478bd9Sstevel@tonic-gate 	file_t *fp;
6347c478bd9Sstevel@tonic-gate 	int error;
6357c478bd9Sstevel@tonic-gate 	socklen_t namelen;
6367c478bd9Sstevel@tonic-gate 	struct sonode *nso;
6377c478bd9Sstevel@tonic-gate 	struct vnode *nvp;
6387c478bd9Sstevel@tonic-gate 	struct file *nfp;
6397c478bd9Sstevel@tonic-gate 	int nfd;
6405dbfd19aSTheo Schlossnagle 	int ssflags;
6410f1702c5SYu Xiangning 	struct sockaddr *addrp;
6420f1702c5SYu Xiangning 	socklen_t addrlen;
6437c478bd9Sstevel@tonic-gate 
6447c478bd9Sstevel@tonic-gate 	dprint(1, ("accept(%d, %p, %p)\n",
645903a11ebSrh87107 	    sock, (void *)name, (void *)namelenp));
6467c478bd9Sstevel@tonic-gate 
6475dbfd19aSTheo Schlossnagle 	if (flags & ~(SOCK_CLOEXEC|SOCK_NONBLOCK|SOCK_NDELAY)) {
6485dbfd19aSTheo Schlossnagle 		return (set_errno(EINVAL));
6495dbfd19aSTheo Schlossnagle 	}
6505dbfd19aSTheo Schlossnagle 
6515dbfd19aSTheo Schlossnagle 	/* Translate SOCK_ flags to their SS_ variant */
6525dbfd19aSTheo Schlossnagle 	ssflags = 0;
6535dbfd19aSTheo Schlossnagle 	if (flags & SOCK_NONBLOCK)
6545dbfd19aSTheo Schlossnagle 		ssflags |= SS_NONBLOCK;
6555dbfd19aSTheo Schlossnagle 	if (flags & SOCK_NDELAY)
6565dbfd19aSTheo Schlossnagle 		ssflags |= SS_NDELAY;
6575dbfd19aSTheo Schlossnagle 
6587c478bd9Sstevel@tonic-gate 	if ((so = getsonode(sock, &error, &fp)) == NULL)
6597c478bd9Sstevel@tonic-gate 		return (set_errno(error));
6607c478bd9Sstevel@tonic-gate 
6617c478bd9Sstevel@tonic-gate 	if (name != NULL) {
6627c478bd9Sstevel@tonic-gate 		ASSERT(MUTEX_NOT_HELD(&so->so_lock));
6637c478bd9Sstevel@tonic-gate 		if (copyin(namelenp, &namelen, sizeof (namelen))) {
6647c478bd9Sstevel@tonic-gate 			releasef(sock);
6657c478bd9Sstevel@tonic-gate 			return (set_errno(EFAULT));
6667c478bd9Sstevel@tonic-gate 		}
6677c478bd9Sstevel@tonic-gate 		if (namelen != 0) {
6687c478bd9Sstevel@tonic-gate 			error = useracc(name, (size_t)namelen, B_WRITE);
6697c478bd9Sstevel@tonic-gate 			if (error && do_useracc) {
6707c478bd9Sstevel@tonic-gate 				releasef(sock);
6717c478bd9Sstevel@tonic-gate 				return (set_errno(EFAULT));
6727c478bd9Sstevel@tonic-gate 			}
6737c478bd9Sstevel@tonic-gate 		} else
6747c478bd9Sstevel@tonic-gate 			name = NULL;
6757c478bd9Sstevel@tonic-gate 	} else {
6767c478bd9Sstevel@tonic-gate 		namelen = 0;
6777c478bd9Sstevel@tonic-gate 	}
6787c478bd9Sstevel@tonic-gate 
6797c478bd9Sstevel@tonic-gate 	/*
6800f1702c5SYu Xiangning 	 * Allocate the user fd before socket_accept() in order to
6810f1702c5SYu Xiangning 	 * catch EMFILE errors before calling socket_accept().
6827c478bd9Sstevel@tonic-gate 	 */
6837c478bd9Sstevel@tonic-gate 	if ((nfd = ufalloc(0)) == -1) {
6847c478bd9Sstevel@tonic-gate 		eprintsoline(so, EMFILE);
6857c478bd9Sstevel@tonic-gate 		releasef(sock);
6867c478bd9Sstevel@tonic-gate 		return (set_errno(EMFILE));
6877c478bd9Sstevel@tonic-gate 	}
6880f1702c5SYu Xiangning 	error = socket_accept(so, fp->f_flag, CRED(), &nso);
6897c478bd9Sstevel@tonic-gate 	if (error) {
6907c478bd9Sstevel@tonic-gate 		setf(nfd, NULL);
6917f9e9054SJayakara Kini 		releasef(sock);
6927c478bd9Sstevel@tonic-gate 		return (set_errno(error));
6937c478bd9Sstevel@tonic-gate 	}
6947c478bd9Sstevel@tonic-gate 
6957c478bd9Sstevel@tonic-gate 	nvp = SOTOV(nso);
6967c478bd9Sstevel@tonic-gate 
6977c478bd9Sstevel@tonic-gate 	ASSERT(MUTEX_NOT_HELD(&nso->so_lock));
6980f1702c5SYu Xiangning 	if (namelen != 0) {
6990f1702c5SYu Xiangning 		addrlen = so->so_max_addr_len;
7000f1702c5SYu Xiangning 		addrp = (struct sockaddr *)kmem_alloc(addrlen, KM_SLEEP);
7010f1702c5SYu Xiangning 
7020f1702c5SYu Xiangning 		if ((error = socket_getpeername(nso, (struct sockaddr *)addrp,
7030f1702c5SYu Xiangning 		    &addrlen, B_TRUE, CRED())) == 0) {
7047c478bd9Sstevel@tonic-gate 			error = copyout_name(name, namelen, namelenp,
7050f1702c5SYu Xiangning 			    addrp, addrlen);
7060f1702c5SYu Xiangning 		} else {
7070f1702c5SYu Xiangning 			ASSERT(error == EINVAL || error == ENOTCONN);
7080f1702c5SYu Xiangning 			error = ECONNABORTED;
7090f1702c5SYu Xiangning 		}
7100f1702c5SYu Xiangning 		kmem_free(addrp, so->so_max_addr_len);
7110f1702c5SYu Xiangning 	}
7120f1702c5SYu Xiangning 
7137c478bd9Sstevel@tonic-gate 	if (error) {
7147c478bd9Sstevel@tonic-gate 		setf(nfd, NULL);
7150f1702c5SYu Xiangning 		(void) socket_close(nso, 0, CRED());
7160f1702c5SYu Xiangning 		socket_destroy(nso);
7177f9e9054SJayakara Kini 		releasef(sock);
7187c478bd9Sstevel@tonic-gate 		return (set_errno(error));
7197c478bd9Sstevel@tonic-gate 	}
7207c478bd9Sstevel@tonic-gate 	if (error = falloc(NULL, FWRITE|FREAD, &nfp, NULL)) {
7217c478bd9Sstevel@tonic-gate 		setf(nfd, NULL);
7220f1702c5SYu Xiangning 		(void) socket_close(nso, 0, CRED());
7230f1702c5SYu Xiangning 		socket_destroy(nso);
7247c478bd9Sstevel@tonic-gate 		eprintsoline(so, error);
7257f9e9054SJayakara Kini 		releasef(sock);
7267c478bd9Sstevel@tonic-gate 		return (set_errno(error));
7277c478bd9Sstevel@tonic-gate 	}
7287c478bd9Sstevel@tonic-gate 	/*
7297c478bd9Sstevel@tonic-gate 	 * fill in the entries that falloc reserved
7307c478bd9Sstevel@tonic-gate 	 */
7317c478bd9Sstevel@tonic-gate 	nfp->f_vnode = nvp;
7327c478bd9Sstevel@tonic-gate 	mutex_exit(&nfp->f_tlock);
7337c478bd9Sstevel@tonic-gate 	setf(nfd, nfp);
7347c478bd9Sstevel@tonic-gate 
7357c478bd9Sstevel@tonic-gate 	/*
7365dbfd19aSTheo Schlossnagle 	 * Act on SOCK_CLOEXEC from flags
7377c478bd9Sstevel@tonic-gate 	 */
7385dbfd19aSTheo Schlossnagle 	if (flags & SOCK_CLOEXEC) {
7395dbfd19aSTheo Schlossnagle 		f_setfd(nfd, FD_CLOEXEC);
7405dbfd19aSTheo Schlossnagle 	}
7415dbfd19aSTheo Schlossnagle 
7425dbfd19aSTheo Schlossnagle 	/*
7435dbfd19aSTheo Schlossnagle 	 * Copy FNDELAY and FNONBLOCK from listener to acceptor
7445dbfd19aSTheo Schlossnagle 	 * and from ssflags
7455dbfd19aSTheo Schlossnagle 	 */
7465dbfd19aSTheo Schlossnagle 	if ((ssflags | so->so_state) & (SS_NDELAY|SS_NONBLOCK)) {
7477c478bd9Sstevel@tonic-gate 		uint_t oflag = nfp->f_flag;
7487c478bd9Sstevel@tonic-gate 		int arg = 0;
7497c478bd9Sstevel@tonic-gate 
7505dbfd19aSTheo Schlossnagle 		if ((ssflags | so->so_state) & SS_NONBLOCK)
7517c478bd9Sstevel@tonic-gate 			arg |= FNONBLOCK;
7525dbfd19aSTheo Schlossnagle 		else if ((ssflags | so->so_state) & SS_NDELAY)
7537c478bd9Sstevel@tonic-gate 			arg |= FNDELAY;
7547c478bd9Sstevel@tonic-gate 
7557c478bd9Sstevel@tonic-gate 		/*
7567c478bd9Sstevel@tonic-gate 		 * This code is a simplification of the F_SETFL code in fcntl()
7577c478bd9Sstevel@tonic-gate 		 * Ignore any errors from VOP_SETFL.
7587c478bd9Sstevel@tonic-gate 		 */
759da6c28aaSamw 		if ((error = VOP_SETFL(nvp, oflag, arg, nfp->f_cred, NULL))
760da6c28aaSamw 		    != 0) {
7617c478bd9Sstevel@tonic-gate 			eprintsoline(so, error);
7627c478bd9Sstevel@tonic-gate 			error = 0;
7637c478bd9Sstevel@tonic-gate 		} else {
7647c478bd9Sstevel@tonic-gate 			mutex_enter(&nfp->f_tlock);
7657c478bd9Sstevel@tonic-gate 			nfp->f_flag &= ~FMASK | (FREAD|FWRITE);
7667c478bd9Sstevel@tonic-gate 			nfp->f_flag |= arg;
7677c478bd9Sstevel@tonic-gate 			mutex_exit(&nfp->f_tlock);
7687c478bd9Sstevel@tonic-gate 		}
7697c478bd9Sstevel@tonic-gate 	}
7707f9e9054SJayakara Kini 	releasef(sock);
7717c478bd9Sstevel@tonic-gate 	return (nfd);
7727c478bd9Sstevel@tonic-gate }
7737c478bd9Sstevel@tonic-gate 
7747c478bd9Sstevel@tonic-gate int
7757c478bd9Sstevel@tonic-gate connect(int sock, struct sockaddr *name, socklen_t namelen, int version)
7767c478bd9Sstevel@tonic-gate {
7777c478bd9Sstevel@tonic-gate 	struct sonode *so;
7787c478bd9Sstevel@tonic-gate 	file_t *fp;
7797c478bd9Sstevel@tonic-gate 	int error;
7807c478bd9Sstevel@tonic-gate 
7817c478bd9Sstevel@tonic-gate 	dprint(1, ("connect(%d, %p, %d)\n",
782903a11ebSrh87107 	    sock, (void *)name, namelen));
7837c478bd9Sstevel@tonic-gate 
7847c478bd9Sstevel@tonic-gate 	if ((so = getsonode(sock, &error, &fp)) == NULL)
7857c478bd9Sstevel@tonic-gate 		return (set_errno(error));
7867c478bd9Sstevel@tonic-gate 
7877c478bd9Sstevel@tonic-gate 	/* Allocate and copyin name */
7887c478bd9Sstevel@tonic-gate 	if (namelen != 0) {
7897c478bd9Sstevel@tonic-gate 		ASSERT(MUTEX_NOT_HELD(&so->so_lock));
7907c478bd9Sstevel@tonic-gate 		name = copyin_name(so, name, &namelen, &error);
7917c478bd9Sstevel@tonic-gate 		if (name == NULL) {
7927c478bd9Sstevel@tonic-gate 			releasef(sock);
7937c478bd9Sstevel@tonic-gate 			return (set_errno(error));
7947c478bd9Sstevel@tonic-gate 		}
7957c478bd9Sstevel@tonic-gate 	} else
7967c478bd9Sstevel@tonic-gate 		name = NULL;
7977c478bd9Sstevel@tonic-gate 
7980f1702c5SYu Xiangning 	error = socket_connect(so, name, namelen, fp->f_flag,
7990f1702c5SYu Xiangning 	    (version != SOV_XPG4_2) ? 0 : _SOCONNECT_XPG4_2, CRED());
8007c478bd9Sstevel@tonic-gate 	releasef(sock);
8017c478bd9Sstevel@tonic-gate 	if (name)
8027c478bd9Sstevel@tonic-gate 		kmem_free(name, (size_t)namelen);
8037c478bd9Sstevel@tonic-gate 	if (error)
8047c478bd9Sstevel@tonic-gate 		return (set_errno(error));
8057c478bd9Sstevel@tonic-gate 	return (0);
8067c478bd9Sstevel@tonic-gate }
8077c478bd9Sstevel@tonic-gate 
8087c478bd9Sstevel@tonic-gate /*ARGSUSED2*/
8097c478bd9Sstevel@tonic-gate int
8107c478bd9Sstevel@tonic-gate shutdown(int sock, int how, int version)
8117c478bd9Sstevel@tonic-gate {
8127c478bd9Sstevel@tonic-gate 	struct sonode *so;
8137c478bd9Sstevel@tonic-gate 	int error;
8147c478bd9Sstevel@tonic-gate 
8157c478bd9Sstevel@tonic-gate 	dprint(1, ("shutdown(%d, %d)\n",
8167c478bd9Sstevel@tonic-gate 	    sock, how));
8177c478bd9Sstevel@tonic-gate 
8187c478bd9Sstevel@tonic-gate 	if ((so = getsonode(sock, &error, NULL)) == NULL)
8197c478bd9Sstevel@tonic-gate 		return (set_errno(error));
8207c478bd9Sstevel@tonic-gate 
8210f1702c5SYu Xiangning 	error = socket_shutdown(so, how, CRED());
8227c478bd9Sstevel@tonic-gate 
8237c478bd9Sstevel@tonic-gate 	releasef(sock);
8247c478bd9Sstevel@tonic-gate 	if (error)
8257c478bd9Sstevel@tonic-gate 		return (set_errno(error));
8267c478bd9Sstevel@tonic-gate 	return (0);
8277c478bd9Sstevel@tonic-gate }
8287c478bd9Sstevel@tonic-gate 
8297c478bd9Sstevel@tonic-gate /*
8307c478bd9Sstevel@tonic-gate  * Common receive routine.
8317c478bd9Sstevel@tonic-gate  */
8327c478bd9Sstevel@tonic-gate static ssize_t
833*f50f4621SMarcel Telka recvit(int sock, struct nmsghdr *msg, struct uio *uiop, int flags,
834*f50f4621SMarcel Telka     socklen_t *namelenp, socklen_t *controllenp, int *flagsp)
8357c478bd9Sstevel@tonic-gate {
8367c478bd9Sstevel@tonic-gate 	struct sonode *so;
8377c478bd9Sstevel@tonic-gate 	file_t *fp;
8387c478bd9Sstevel@tonic-gate 	void *name;
8397c478bd9Sstevel@tonic-gate 	socklen_t namelen;
8407c478bd9Sstevel@tonic-gate 	void *control;
8417c478bd9Sstevel@tonic-gate 	socklen_t controllen;
8427c478bd9Sstevel@tonic-gate 	ssize_t len;
8437c478bd9Sstevel@tonic-gate 	int error;
8447c478bd9Sstevel@tonic-gate 
8457c478bd9Sstevel@tonic-gate 	if ((so = getsonode(sock, &error, &fp)) == NULL)
8467c478bd9Sstevel@tonic-gate 		return (set_errno(error));
8477c478bd9Sstevel@tonic-gate 
8487c478bd9Sstevel@tonic-gate 	len = uiop->uio_resid;
8497c478bd9Sstevel@tonic-gate 	uiop->uio_fmode = fp->f_flag;
8507c478bd9Sstevel@tonic-gate 	uiop->uio_extflg = UIO_COPY_CACHED;
8517c478bd9Sstevel@tonic-gate 
8527c478bd9Sstevel@tonic-gate 	name = msg->msg_name;
8537c478bd9Sstevel@tonic-gate 	namelen = msg->msg_namelen;
8547c478bd9Sstevel@tonic-gate 	control = msg->msg_control;
8557c478bd9Sstevel@tonic-gate 	controllen = msg->msg_controllen;
8567c478bd9Sstevel@tonic-gate 
8577c478bd9Sstevel@tonic-gate 	msg->msg_flags = flags & (MSG_OOB | MSG_PEEK | MSG_WAITALL |
8587c478bd9Sstevel@tonic-gate 	    MSG_DONTWAIT | MSG_XPG4_2);
8597c478bd9Sstevel@tonic-gate 
8600f1702c5SYu Xiangning 	error = socket_recvmsg(so, msg, uiop, CRED());
8617c478bd9Sstevel@tonic-gate 	if (error) {
8627c478bd9Sstevel@tonic-gate 		releasef(sock);
8637c478bd9Sstevel@tonic-gate 		return (set_errno(error));
8647c478bd9Sstevel@tonic-gate 	}
8657c478bd9Sstevel@tonic-gate 	lwp_stat_update(LWP_STAT_MSGRCV, 1);
8667c478bd9Sstevel@tonic-gate 	releasef(sock);
8677c478bd9Sstevel@tonic-gate 
8687c478bd9Sstevel@tonic-gate 	error = copyout_name(name, namelen, namelenp,
8697c478bd9Sstevel@tonic-gate 	    msg->msg_name, msg->msg_namelen);
8707c478bd9Sstevel@tonic-gate 	if (error)
8717c478bd9Sstevel@tonic-gate 		goto err;
8727c478bd9Sstevel@tonic-gate 
8737c478bd9Sstevel@tonic-gate 	if (flagsp != NULL) {
8747c478bd9Sstevel@tonic-gate 		/*
8757c478bd9Sstevel@tonic-gate 		 * Clear internal flag.
8767c478bd9Sstevel@tonic-gate 		 */
8777c478bd9Sstevel@tonic-gate 		msg->msg_flags &= ~MSG_XPG4_2;
8787c478bd9Sstevel@tonic-gate 
8797c478bd9Sstevel@tonic-gate 		/*
8807c478bd9Sstevel@tonic-gate 		 * Determine MSG_CTRUNC. sorecvmsg sets MSG_CTRUNC only
8817c478bd9Sstevel@tonic-gate 		 * when controllen is zero and there is control data to
8827c478bd9Sstevel@tonic-gate 		 * copy out.
8837c478bd9Sstevel@tonic-gate 		 */
8847c478bd9Sstevel@tonic-gate 		if (controllen != 0 &&
8857c478bd9Sstevel@tonic-gate 		    (msg->msg_controllen > controllen || control == NULL)) {
8867c478bd9Sstevel@tonic-gate 			dprint(1, ("recvit: CTRUNC %d %d %p\n",
8877c478bd9Sstevel@tonic-gate 			    msg->msg_controllen, controllen, control));
8887c478bd9Sstevel@tonic-gate 
8897c478bd9Sstevel@tonic-gate 			msg->msg_flags |= MSG_CTRUNC;
8907c478bd9Sstevel@tonic-gate 		}
8917c478bd9Sstevel@tonic-gate 		if (copyout(&msg->msg_flags, flagsp,
8927c478bd9Sstevel@tonic-gate 		    sizeof (msg->msg_flags))) {
8937c478bd9Sstevel@tonic-gate 			error = EFAULT;
8947c478bd9Sstevel@tonic-gate 			goto err;
8957c478bd9Sstevel@tonic-gate 		}
8967c478bd9Sstevel@tonic-gate 	}
8977c478bd9Sstevel@tonic-gate 	/*
8987c478bd9Sstevel@tonic-gate 	 * Note: This MUST be done last. There can be no "goto err" after this
8997c478bd9Sstevel@tonic-gate 	 * point since it could make so_closefds run twice on some part
9007c478bd9Sstevel@tonic-gate 	 * of the file descriptor array.
9017c478bd9Sstevel@tonic-gate 	 */
9027c478bd9Sstevel@tonic-gate 	if (controllen != 0) {
9037c478bd9Sstevel@tonic-gate 		if (!(flags & MSG_XPG4_2)) {
9047c478bd9Sstevel@tonic-gate 			/*
9057c478bd9Sstevel@tonic-gate 			 * Good old msg_accrights can only return a multiple
9067c478bd9Sstevel@tonic-gate 			 * of 4 bytes.
9077c478bd9Sstevel@tonic-gate 			 */
9087c478bd9Sstevel@tonic-gate 			controllen &= ~((int)sizeof (uint32_t) - 1);
9097c478bd9Sstevel@tonic-gate 		}
9107c478bd9Sstevel@tonic-gate 		error = copyout_arg(control, controllen, controllenp,
9117c478bd9Sstevel@tonic-gate 		    msg->msg_control, msg->msg_controllen);
9127c478bd9Sstevel@tonic-gate 		if (error)
9137c478bd9Sstevel@tonic-gate 			goto err;
9147c478bd9Sstevel@tonic-gate 
9157c478bd9Sstevel@tonic-gate 		if (msg->msg_controllen > controllen || control == NULL) {
9167c478bd9Sstevel@tonic-gate 			if (control == NULL)
9177c478bd9Sstevel@tonic-gate 				controllen = 0;
9187c478bd9Sstevel@tonic-gate 			so_closefds(msg->msg_control, msg->msg_controllen,
9197c478bd9Sstevel@tonic-gate 			    !(flags & MSG_XPG4_2), controllen);
9207c478bd9Sstevel@tonic-gate 		}
9217c478bd9Sstevel@tonic-gate 	}
9227c478bd9Sstevel@tonic-gate 	if (msg->msg_namelen != 0)
9237c478bd9Sstevel@tonic-gate 		kmem_free(msg->msg_name, (size_t)msg->msg_namelen);
9247c478bd9Sstevel@tonic-gate 	if (msg->msg_controllen != 0)
9257c478bd9Sstevel@tonic-gate 		kmem_free(msg->msg_control, (size_t)msg->msg_controllen);
9267c478bd9Sstevel@tonic-gate 	return (len - uiop->uio_resid);
9277c478bd9Sstevel@tonic-gate 
9287c478bd9Sstevel@tonic-gate err:
9297c478bd9Sstevel@tonic-gate 	/*
9307c478bd9Sstevel@tonic-gate 	 * If we fail and the control part contains file descriptors
9317c478bd9Sstevel@tonic-gate 	 * we have to close the fd's.
9327c478bd9Sstevel@tonic-gate 	 */
9337c478bd9Sstevel@tonic-gate 	if (msg->msg_controllen != 0)
9347c478bd9Sstevel@tonic-gate 		so_closefds(msg->msg_control, msg->msg_controllen,
9357c478bd9Sstevel@tonic-gate 		    !(flags & MSG_XPG4_2), 0);
9367c478bd9Sstevel@tonic-gate 	if (msg->msg_namelen != 0)
9377c478bd9Sstevel@tonic-gate 		kmem_free(msg->msg_name, (size_t)msg->msg_namelen);
9387c478bd9Sstevel@tonic-gate 	if (msg->msg_controllen != 0)
9397c478bd9Sstevel@tonic-gate 		kmem_free(msg->msg_control, (size_t)msg->msg_controllen);
9407c478bd9Sstevel@tonic-gate 	return (set_errno(error));
9417c478bd9Sstevel@tonic-gate }
9427c478bd9Sstevel@tonic-gate 
9437c478bd9Sstevel@tonic-gate /*
9447c478bd9Sstevel@tonic-gate  * Native system call
9457c478bd9Sstevel@tonic-gate  */
9467c478bd9Sstevel@tonic-gate ssize_t
9477c478bd9Sstevel@tonic-gate recv(int sock, void *buffer, size_t len, int flags)
9487c478bd9Sstevel@tonic-gate {
9497c478bd9Sstevel@tonic-gate 	struct nmsghdr lmsg;
9507c478bd9Sstevel@tonic-gate 	struct uio auio;
9517c478bd9Sstevel@tonic-gate 	struct iovec aiov[1];
9527c478bd9Sstevel@tonic-gate 
9537c478bd9Sstevel@tonic-gate 	dprint(1, ("recv(%d, %p, %ld, %d)\n",
9547c478bd9Sstevel@tonic-gate 	    sock, buffer, len, flags));
9557c478bd9Sstevel@tonic-gate 
9567c478bd9Sstevel@tonic-gate 	if ((ssize_t)len < 0) {
9577c478bd9Sstevel@tonic-gate 		return (set_errno(EINVAL));
9587c478bd9Sstevel@tonic-gate 	}
9597c478bd9Sstevel@tonic-gate 
9607c478bd9Sstevel@tonic-gate 	aiov[0].iov_base = buffer;
9617c478bd9Sstevel@tonic-gate 	aiov[0].iov_len = len;
9627c478bd9Sstevel@tonic-gate 	auio.uio_loffset = 0;
9637c478bd9Sstevel@tonic-gate 	auio.uio_iov = aiov;
9647c478bd9Sstevel@tonic-gate 	auio.uio_iovcnt = 1;
9657c478bd9Sstevel@tonic-gate 	auio.uio_resid = len;
9667c478bd9Sstevel@tonic-gate 	auio.uio_segflg = UIO_USERSPACE;
9677c478bd9Sstevel@tonic-gate 	auio.uio_limit = 0;
9687c478bd9Sstevel@tonic-gate 
9697c478bd9Sstevel@tonic-gate 	lmsg.msg_namelen = 0;
9707c478bd9Sstevel@tonic-gate 	lmsg.msg_controllen = 0;
9717c478bd9Sstevel@tonic-gate 	lmsg.msg_flags = 0;
9727c478bd9Sstevel@tonic-gate 	return (recvit(sock, &lmsg, &auio, flags, NULL, NULL, NULL));
9737c478bd9Sstevel@tonic-gate }
9747c478bd9Sstevel@tonic-gate 
9757c478bd9Sstevel@tonic-gate ssize_t
976*f50f4621SMarcel Telka recvfrom(int sock, void *buffer, size_t len, int flags, struct sockaddr *name,
977*f50f4621SMarcel Telka     socklen_t *namelenp)
9787c478bd9Sstevel@tonic-gate {
9797c478bd9Sstevel@tonic-gate 	struct nmsghdr lmsg;
9807c478bd9Sstevel@tonic-gate 	struct uio auio;
9817c478bd9Sstevel@tonic-gate 	struct iovec aiov[1];
9827c478bd9Sstevel@tonic-gate 
9837c478bd9Sstevel@tonic-gate 	dprint(1, ("recvfrom(%d, %p, %ld, %d, %p, %p)\n",
984903a11ebSrh87107 	    sock, buffer, len, flags, (void *)name, (void *)namelenp));
9857c478bd9Sstevel@tonic-gate 
9867c478bd9Sstevel@tonic-gate 	if ((ssize_t)len < 0) {
9877c478bd9Sstevel@tonic-gate 		return (set_errno(EINVAL));
9887c478bd9Sstevel@tonic-gate 	}
9897c478bd9Sstevel@tonic-gate 
9907c478bd9Sstevel@tonic-gate 	aiov[0].iov_base = buffer;
9917c478bd9Sstevel@tonic-gate 	aiov[0].iov_len = len;
9927c478bd9Sstevel@tonic-gate 	auio.uio_loffset = 0;
9937c478bd9Sstevel@tonic-gate 	auio.uio_iov = aiov;
9947c478bd9Sstevel@tonic-gate 	auio.uio_iovcnt = 1;
9957c478bd9Sstevel@tonic-gate 	auio.uio_resid = len;
9967c478bd9Sstevel@tonic-gate 	auio.uio_segflg = UIO_USERSPACE;
9977c478bd9Sstevel@tonic-gate 	auio.uio_limit = 0;
9987c478bd9Sstevel@tonic-gate 
9997c478bd9Sstevel@tonic-gate 	lmsg.msg_name = (char *)name;
10007c478bd9Sstevel@tonic-gate 	if (namelenp != NULL) {
10017c478bd9Sstevel@tonic-gate 		if (copyin(namelenp, &lmsg.msg_namelen,
10027c478bd9Sstevel@tonic-gate 		    sizeof (lmsg.msg_namelen)))
10037c478bd9Sstevel@tonic-gate 			return (set_errno(EFAULT));
10047c478bd9Sstevel@tonic-gate 	} else {
10057c478bd9Sstevel@tonic-gate 		lmsg.msg_namelen = 0;
10067c478bd9Sstevel@tonic-gate 	}
10077c478bd9Sstevel@tonic-gate 	lmsg.msg_controllen = 0;
10087c478bd9Sstevel@tonic-gate 	lmsg.msg_flags = 0;
10097c478bd9Sstevel@tonic-gate 
10107c478bd9Sstevel@tonic-gate 	return (recvit(sock, &lmsg, &auio, flags, namelenp, NULL, NULL));
10117c478bd9Sstevel@tonic-gate }
10127c478bd9Sstevel@tonic-gate 
10137c478bd9Sstevel@tonic-gate /*
10147c478bd9Sstevel@tonic-gate  * Uses the MSG_XPG4_2 flag to determine if the caller is using
10157c478bd9Sstevel@tonic-gate  * struct omsghdr or struct nmsghdr.
10167c478bd9Sstevel@tonic-gate  */
10177c478bd9Sstevel@tonic-gate ssize_t
10187c478bd9Sstevel@tonic-gate recvmsg(int sock, struct nmsghdr *msg, int flags)
10197c478bd9Sstevel@tonic-gate {
10207c478bd9Sstevel@tonic-gate 	STRUCT_DECL(nmsghdr, u_lmsg);
10217c478bd9Sstevel@tonic-gate 	STRUCT_HANDLE(nmsghdr, umsgptr);
10227c478bd9Sstevel@tonic-gate 	struct nmsghdr lmsg;
10237c478bd9Sstevel@tonic-gate 	struct uio auio;
10247c478bd9Sstevel@tonic-gate 	struct iovec aiov[MSG_MAXIOVLEN];
10257c478bd9Sstevel@tonic-gate 	int iovcnt;
10267c478bd9Sstevel@tonic-gate 	ssize_t len;
10277c478bd9Sstevel@tonic-gate 	int i;
10287c478bd9Sstevel@tonic-gate 	int *flagsp;
10297c478bd9Sstevel@tonic-gate 	model_t	model;
10307c478bd9Sstevel@tonic-gate 
10317c478bd9Sstevel@tonic-gate 	dprint(1, ("recvmsg(%d, %p, %d)\n",
1032903a11ebSrh87107 	    sock, (void *)msg, flags));
10337c478bd9Sstevel@tonic-gate 
10347c478bd9Sstevel@tonic-gate 	model = get_udatamodel();
10357c478bd9Sstevel@tonic-gate 	STRUCT_INIT(u_lmsg, model);
10367c478bd9Sstevel@tonic-gate 	STRUCT_SET_HANDLE(umsgptr, model, msg);
10377c478bd9Sstevel@tonic-gate 
10387c478bd9Sstevel@tonic-gate 	if (flags & MSG_XPG4_2) {
10397c478bd9Sstevel@tonic-gate 		if (copyin(msg, STRUCT_BUF(u_lmsg), STRUCT_SIZE(u_lmsg)))
10407c478bd9Sstevel@tonic-gate 			return (set_errno(EFAULT));
10417c478bd9Sstevel@tonic-gate 		flagsp = STRUCT_FADDR(umsgptr, msg_flags);
10427c478bd9Sstevel@tonic-gate 	} else {
10437c478bd9Sstevel@tonic-gate 		/*
10447c478bd9Sstevel@tonic-gate 		 * Assumes that nmsghdr and omsghdr are identically shaped
10457c478bd9Sstevel@tonic-gate 		 * except for the added msg_flags field.
10467c478bd9Sstevel@tonic-gate 		 */
10477c478bd9Sstevel@tonic-gate 		if (copyin(msg, STRUCT_BUF(u_lmsg),
10487c478bd9Sstevel@tonic-gate 		    SIZEOF_STRUCT(omsghdr, model)))
10497c478bd9Sstevel@tonic-gate 			return (set_errno(EFAULT));
10507c478bd9Sstevel@tonic-gate 		STRUCT_FSET(u_lmsg, msg_flags, 0);
10517c478bd9Sstevel@tonic-gate 		flagsp = NULL;
10527c478bd9Sstevel@tonic-gate 	}
10537c478bd9Sstevel@tonic-gate 
10547c478bd9Sstevel@tonic-gate 	/*
10557c478bd9Sstevel@tonic-gate 	 * Code below us will kmem_alloc memory and hang it
10567c478bd9Sstevel@tonic-gate 	 * off msg_control and msg_name fields. This forces
10577c478bd9Sstevel@tonic-gate 	 * us to copy the structure to its native form.
10587c478bd9Sstevel@tonic-gate 	 */
10597c478bd9Sstevel@tonic-gate 	lmsg.msg_name = STRUCT_FGETP(u_lmsg, msg_name);
10607c478bd9Sstevel@tonic-gate 	lmsg.msg_namelen = STRUCT_FGET(u_lmsg, msg_namelen);
10617c478bd9Sstevel@tonic-gate 	lmsg.msg_iov = STRUCT_FGETP(u_lmsg, msg_iov);
10627c478bd9Sstevel@tonic-gate 	lmsg.msg_iovlen = STRUCT_FGET(u_lmsg, msg_iovlen);
10637c478bd9Sstevel@tonic-gate 	lmsg.msg_control = STRUCT_FGETP(u_lmsg, msg_control);
10647c478bd9Sstevel@tonic-gate 	lmsg.msg_controllen = STRUCT_FGET(u_lmsg, msg_controllen);
10657c478bd9Sstevel@tonic-gate 	lmsg.msg_flags = STRUCT_FGET(u_lmsg, msg_flags);
10667c478bd9Sstevel@tonic-gate 
10677c478bd9Sstevel@tonic-gate 	iovcnt = lmsg.msg_iovlen;
10687c478bd9Sstevel@tonic-gate 
10697c478bd9Sstevel@tonic-gate 	if (iovcnt <= 0 || iovcnt > MSG_MAXIOVLEN) {
10707c478bd9Sstevel@tonic-gate 		return (set_errno(EMSGSIZE));
10717c478bd9Sstevel@tonic-gate 	}
10727c478bd9Sstevel@tonic-gate 
10737c478bd9Sstevel@tonic-gate #ifdef _SYSCALL32_IMPL
10747c478bd9Sstevel@tonic-gate 	/*
10757c478bd9Sstevel@tonic-gate 	 * 32-bit callers need to have their iovec expanded, while ensuring
10767c478bd9Sstevel@tonic-gate 	 * that they can't move more than 2Gbytes of data in a single call.
10777c478bd9Sstevel@tonic-gate 	 */
10787c478bd9Sstevel@tonic-gate 	if (model == DATAMODEL_ILP32) {
10797c478bd9Sstevel@tonic-gate 		struct iovec32 aiov32[MSG_MAXIOVLEN];
10807c478bd9Sstevel@tonic-gate 		ssize32_t count32;
10817c478bd9Sstevel@tonic-gate 
10827c478bd9Sstevel@tonic-gate 		if (copyin((struct iovec32 *)lmsg.msg_iov, aiov32,
10837c478bd9Sstevel@tonic-gate 		    iovcnt * sizeof (struct iovec32)))
10847c478bd9Sstevel@tonic-gate 			return (set_errno(EFAULT));
10857c478bd9Sstevel@tonic-gate 
10867c478bd9Sstevel@tonic-gate 		count32 = 0;
10877c478bd9Sstevel@tonic-gate 		for (i = 0; i < iovcnt; i++) {
10887c478bd9Sstevel@tonic-gate 			ssize32_t iovlen32;
10897c478bd9Sstevel@tonic-gate 
10907c478bd9Sstevel@tonic-gate 			iovlen32 = aiov32[i].iov_len;
10917c478bd9Sstevel@tonic-gate 			count32 += iovlen32;
10927c478bd9Sstevel@tonic-gate 			if (iovlen32 < 0 || count32 < 0)
10937c478bd9Sstevel@tonic-gate 				return (set_errno(EINVAL));
10947c478bd9Sstevel@tonic-gate 			aiov[i].iov_len = iovlen32;
10957c478bd9Sstevel@tonic-gate 			aiov[i].iov_base =
10967c478bd9Sstevel@tonic-gate 			    (caddr_t)(uintptr_t)aiov32[i].iov_base;
10977c478bd9Sstevel@tonic-gate 		}
10987c478bd9Sstevel@tonic-gate 	} else
10997c478bd9Sstevel@tonic-gate #endif /* _SYSCALL32_IMPL */
11007c478bd9Sstevel@tonic-gate 	if (copyin(lmsg.msg_iov, aiov, iovcnt * sizeof (struct iovec))) {
11017c478bd9Sstevel@tonic-gate 		return (set_errno(EFAULT));
11027c478bd9Sstevel@tonic-gate 	}
11037c478bd9Sstevel@tonic-gate 	len = 0;
11047c478bd9Sstevel@tonic-gate 	for (i = 0; i < iovcnt; i++) {
11057c478bd9Sstevel@tonic-gate 		ssize_t iovlen = aiov[i].iov_len;
11067c478bd9Sstevel@tonic-gate 		len += iovlen;
11077c478bd9Sstevel@tonic-gate 		if (iovlen < 0 || len < 0) {
11087c478bd9Sstevel@tonic-gate 			return (set_errno(EINVAL));
11097c478bd9Sstevel@tonic-gate 		}
11107c478bd9Sstevel@tonic-gate 	}
11117c478bd9Sstevel@tonic-gate 	auio.uio_loffset = 0;
11127c478bd9Sstevel@tonic-gate 	auio.uio_iov = aiov;
11137c478bd9Sstevel@tonic-gate 	auio.uio_iovcnt = iovcnt;
11147c478bd9Sstevel@tonic-gate 	auio.uio_resid = len;
11157c478bd9Sstevel@tonic-gate 	auio.uio_segflg = UIO_USERSPACE;
11167c478bd9Sstevel@tonic-gate 	auio.uio_limit = 0;
11177c478bd9Sstevel@tonic-gate 
11187c478bd9Sstevel@tonic-gate 	if (lmsg.msg_control != NULL &&
11197c478bd9Sstevel@tonic-gate 	    (do_useracc == 0 ||
11207c478bd9Sstevel@tonic-gate 	    useracc(lmsg.msg_control, lmsg.msg_controllen,
11217c478bd9Sstevel@tonic-gate 	    B_WRITE) != 0)) {
11227c478bd9Sstevel@tonic-gate 		return (set_errno(EFAULT));
11237c478bd9Sstevel@tonic-gate 	}
11247c478bd9Sstevel@tonic-gate 
11257c478bd9Sstevel@tonic-gate 	return (recvit(sock, &lmsg, &auio, flags,
11267c478bd9Sstevel@tonic-gate 	    STRUCT_FADDR(umsgptr, msg_namelen),
11277c478bd9Sstevel@tonic-gate 	    STRUCT_FADDR(umsgptr, msg_controllen), flagsp));
11287c478bd9Sstevel@tonic-gate }
11297c478bd9Sstevel@tonic-gate 
11307c478bd9Sstevel@tonic-gate /*
11317c478bd9Sstevel@tonic-gate  * Common send function.
11327c478bd9Sstevel@tonic-gate  */
11337c478bd9Sstevel@tonic-gate static ssize_t
11347c478bd9Sstevel@tonic-gate sendit(int sock, struct nmsghdr *msg, struct uio *uiop, int flags)
11357c478bd9Sstevel@tonic-gate {
11367c478bd9Sstevel@tonic-gate 	struct sonode *so;
11377c478bd9Sstevel@tonic-gate 	file_t *fp;
11387c478bd9Sstevel@tonic-gate 	void *name;
11397c478bd9Sstevel@tonic-gate 	socklen_t namelen;
11407c478bd9Sstevel@tonic-gate 	void *control;
11417c478bd9Sstevel@tonic-gate 	socklen_t controllen;
11427c478bd9Sstevel@tonic-gate 	ssize_t len;
11437c478bd9Sstevel@tonic-gate 	int error;
11447c478bd9Sstevel@tonic-gate 
11457c478bd9Sstevel@tonic-gate 	if ((so = getsonode(sock, &error, &fp)) == NULL)
11467c478bd9Sstevel@tonic-gate 		return (set_errno(error));
11477c478bd9Sstevel@tonic-gate 
11487c478bd9Sstevel@tonic-gate 	uiop->uio_fmode = fp->f_flag;
11497c478bd9Sstevel@tonic-gate 
11507c478bd9Sstevel@tonic-gate 	if (so->so_family == AF_UNIX)
11517c478bd9Sstevel@tonic-gate 		uiop->uio_extflg = UIO_COPY_CACHED;
11527c478bd9Sstevel@tonic-gate 	else
11537c478bd9Sstevel@tonic-gate 		uiop->uio_extflg = UIO_COPY_DEFAULT;
11547c478bd9Sstevel@tonic-gate 
11557c478bd9Sstevel@tonic-gate 	/* Allocate and copyin name and control */
11567c478bd9Sstevel@tonic-gate 	name = msg->msg_name;
11577c478bd9Sstevel@tonic-gate 	namelen = msg->msg_namelen;
11587c478bd9Sstevel@tonic-gate 	if (name != NULL && namelen != 0) {
11597c478bd9Sstevel@tonic-gate 		ASSERT(MUTEX_NOT_HELD(&so->so_lock));
11607c478bd9Sstevel@tonic-gate 		name = copyin_name(so,
11617c478bd9Sstevel@tonic-gate 		    (struct sockaddr *)name,
11627c478bd9Sstevel@tonic-gate 		    &namelen, &error);
11637c478bd9Sstevel@tonic-gate 		if (name == NULL)
11647c478bd9Sstevel@tonic-gate 			goto done3;
11657c478bd9Sstevel@tonic-gate 		/* copyin_name null terminates addresses for AF_UNIX */
11667c478bd9Sstevel@tonic-gate 		msg->msg_namelen = namelen;
11677c478bd9Sstevel@tonic-gate 		msg->msg_name = name;
11687c478bd9Sstevel@tonic-gate 	} else {
11697c478bd9Sstevel@tonic-gate 		msg->msg_name = name = NULL;
11707c478bd9Sstevel@tonic-gate 		msg->msg_namelen = namelen = 0;
11717c478bd9Sstevel@tonic-gate 	}
11727c478bd9Sstevel@tonic-gate 
11737c478bd9Sstevel@tonic-gate 	control = msg->msg_control;
11747c478bd9Sstevel@tonic-gate 	controllen = msg->msg_controllen;
11757c478bd9Sstevel@tonic-gate 	if ((control != NULL) && (controllen != 0)) {
11767c478bd9Sstevel@tonic-gate 		/*
11777c478bd9Sstevel@tonic-gate 		 * Verify that the length is not excessive to prevent
11787c478bd9Sstevel@tonic-gate 		 * an application from consuming all of kernel memory.
11797c478bd9Sstevel@tonic-gate 		 */
11807c478bd9Sstevel@tonic-gate 		if (controllen > SO_MAXARGSIZE) {
11817c478bd9Sstevel@tonic-gate 			error = EINVAL;
11827c478bd9Sstevel@tonic-gate 			goto done2;
11837c478bd9Sstevel@tonic-gate 		}
11847c478bd9Sstevel@tonic-gate 		control = kmem_alloc(controllen, KM_SLEEP);
11857c478bd9Sstevel@tonic-gate 
11867c478bd9Sstevel@tonic-gate 		ASSERT(MUTEX_NOT_HELD(&so->so_lock));
11877c478bd9Sstevel@tonic-gate 		if (copyin(msg->msg_control, control, controllen)) {
11887c478bd9Sstevel@tonic-gate 			error = EFAULT;
11897c478bd9Sstevel@tonic-gate 			goto done1;
11907c478bd9Sstevel@tonic-gate 		}
11917c478bd9Sstevel@tonic-gate 		msg->msg_control = control;
11927c478bd9Sstevel@tonic-gate 	} else {
11937c478bd9Sstevel@tonic-gate 		msg->msg_control = control = NULL;
11947c478bd9Sstevel@tonic-gate 		msg->msg_controllen = controllen = 0;
11957c478bd9Sstevel@tonic-gate 	}
11967c478bd9Sstevel@tonic-gate 
11977c478bd9Sstevel@tonic-gate 	len = uiop->uio_resid;
11987c478bd9Sstevel@tonic-gate 	msg->msg_flags = flags;
11997c478bd9Sstevel@tonic-gate 
12000f1702c5SYu Xiangning 	error = socket_sendmsg(so, msg, uiop, CRED());
12017c478bd9Sstevel@tonic-gate done1:
12027c478bd9Sstevel@tonic-gate 	if (control != NULL)
12037c478bd9Sstevel@tonic-gate 		kmem_free(control, controllen);
12047c478bd9Sstevel@tonic-gate done2:
12057c478bd9Sstevel@tonic-gate 	if (name != NULL)
12067c478bd9Sstevel@tonic-gate 		kmem_free(name, namelen);
12077c478bd9Sstevel@tonic-gate done3:
12087c478bd9Sstevel@tonic-gate 	if (error != 0) {
12097c478bd9Sstevel@tonic-gate 		releasef(sock);
12107c478bd9Sstevel@tonic-gate 		return (set_errno(error));
12117c478bd9Sstevel@tonic-gate 	}
12127c478bd9Sstevel@tonic-gate 	lwp_stat_update(LWP_STAT_MSGSND, 1);
12137c478bd9Sstevel@tonic-gate 	releasef(sock);
12147c478bd9Sstevel@tonic-gate 	return (len - uiop->uio_resid);
12157c478bd9Sstevel@tonic-gate }
12167c478bd9Sstevel@tonic-gate 
12177c478bd9Sstevel@tonic-gate /*
12187c478bd9Sstevel@tonic-gate  * Native system call
12197c478bd9Sstevel@tonic-gate  */
12207c478bd9Sstevel@tonic-gate ssize_t
12217c478bd9Sstevel@tonic-gate send(int sock, void *buffer, size_t len, int flags)
12227c478bd9Sstevel@tonic-gate {
12237c478bd9Sstevel@tonic-gate 	struct nmsghdr lmsg;
12247c478bd9Sstevel@tonic-gate 	struct uio auio;
12257c478bd9Sstevel@tonic-gate 	struct iovec aiov[1];
12267c478bd9Sstevel@tonic-gate 
12277c478bd9Sstevel@tonic-gate 	dprint(1, ("send(%d, %p, %ld, %d)\n",
12287c478bd9Sstevel@tonic-gate 	    sock, buffer, len, flags));
12297c478bd9Sstevel@tonic-gate 
12307c478bd9Sstevel@tonic-gate 	if ((ssize_t)len < 0) {
12317c478bd9Sstevel@tonic-gate 		return (set_errno(EINVAL));
12327c478bd9Sstevel@tonic-gate 	}
12337c478bd9Sstevel@tonic-gate 
12347c478bd9Sstevel@tonic-gate 	aiov[0].iov_base = buffer;
12357c478bd9Sstevel@tonic-gate 	aiov[0].iov_len = len;
12367c478bd9Sstevel@tonic-gate 	auio.uio_loffset = 0;
12377c478bd9Sstevel@tonic-gate 	auio.uio_iov = aiov;
12387c478bd9Sstevel@tonic-gate 	auio.uio_iovcnt = 1;
12397c478bd9Sstevel@tonic-gate 	auio.uio_resid = len;
12407c478bd9Sstevel@tonic-gate 	auio.uio_segflg = UIO_USERSPACE;
12417c478bd9Sstevel@tonic-gate 	auio.uio_limit = 0;
12427c478bd9Sstevel@tonic-gate 
12437c478bd9Sstevel@tonic-gate 	lmsg.msg_name = NULL;
12447c478bd9Sstevel@tonic-gate 	lmsg.msg_control = NULL;
12457c478bd9Sstevel@tonic-gate 	if (!(flags & MSG_XPG4_2)) {
12467c478bd9Sstevel@tonic-gate 		/*
12477c478bd9Sstevel@tonic-gate 		 * In order to be compatible with the libsocket/sockmod
12487c478bd9Sstevel@tonic-gate 		 * implementation we set EOR for all send* calls.
12497c478bd9Sstevel@tonic-gate 		 */
12507c478bd9Sstevel@tonic-gate 		flags |= MSG_EOR;
12517c478bd9Sstevel@tonic-gate 	}
12527c478bd9Sstevel@tonic-gate 	return (sendit(sock, &lmsg, &auio, flags));
12537c478bd9Sstevel@tonic-gate }
12547c478bd9Sstevel@tonic-gate 
12557c478bd9Sstevel@tonic-gate /*
12567c478bd9Sstevel@tonic-gate  * Uses the MSG_XPG4_2 flag to determine if the caller is using
12577c478bd9Sstevel@tonic-gate  * struct omsghdr or struct nmsghdr.
12587c478bd9Sstevel@tonic-gate  */
12597c478bd9Sstevel@tonic-gate ssize_t
12607c478bd9Sstevel@tonic-gate sendmsg(int sock, struct nmsghdr *msg, int flags)
12617c478bd9Sstevel@tonic-gate {
12627c478bd9Sstevel@tonic-gate 	struct nmsghdr lmsg;
12637c478bd9Sstevel@tonic-gate 	STRUCT_DECL(nmsghdr, u_lmsg);
12647c478bd9Sstevel@tonic-gate 	struct uio auio;
12657c478bd9Sstevel@tonic-gate 	struct iovec aiov[MSG_MAXIOVLEN];
12667c478bd9Sstevel@tonic-gate 	int iovcnt;
12677c478bd9Sstevel@tonic-gate 	ssize_t len;
12687c478bd9Sstevel@tonic-gate 	int i;
12697c478bd9Sstevel@tonic-gate 	model_t	model;
12707c478bd9Sstevel@tonic-gate 
1271903a11ebSrh87107 	dprint(1, ("sendmsg(%d, %p, %d)\n", sock, (void *)msg, flags));
12727c478bd9Sstevel@tonic-gate 
12737c478bd9Sstevel@tonic-gate 	model = get_udatamodel();
12747c478bd9Sstevel@tonic-gate 	STRUCT_INIT(u_lmsg, model);
12757c478bd9Sstevel@tonic-gate 
12767c478bd9Sstevel@tonic-gate 	if (flags & MSG_XPG4_2) {
12777c478bd9Sstevel@tonic-gate 		if (copyin(msg, (char *)STRUCT_BUF(u_lmsg),
12787c478bd9Sstevel@tonic-gate 		    STRUCT_SIZE(u_lmsg)))
12797c478bd9Sstevel@tonic-gate 			return (set_errno(EFAULT));
12807c478bd9Sstevel@tonic-gate 	} else {
12817c478bd9Sstevel@tonic-gate 		/*
12827c478bd9Sstevel@tonic-gate 		 * Assumes that nmsghdr and omsghdr are identically shaped
12837c478bd9Sstevel@tonic-gate 		 * except for the added msg_flags field.
12847c478bd9Sstevel@tonic-gate 		 */
12857c478bd9Sstevel@tonic-gate 		if (copyin(msg, (char *)STRUCT_BUF(u_lmsg),
12867c478bd9Sstevel@tonic-gate 		    SIZEOF_STRUCT(omsghdr, model)))
12877c478bd9Sstevel@tonic-gate 			return (set_errno(EFAULT));
12887c478bd9Sstevel@tonic-gate 		/*
12897c478bd9Sstevel@tonic-gate 		 * In order to be compatible with the libsocket/sockmod
12907c478bd9Sstevel@tonic-gate 		 * implementation we set EOR for all send* calls.
12917c478bd9Sstevel@tonic-gate 		 */
12927c478bd9Sstevel@tonic-gate 		flags |= MSG_EOR;
12937c478bd9Sstevel@tonic-gate 	}
12947c478bd9Sstevel@tonic-gate 
12957c478bd9Sstevel@tonic-gate 	/*
12967c478bd9Sstevel@tonic-gate 	 * Code below us will kmem_alloc memory and hang it
12977c478bd9Sstevel@tonic-gate 	 * off msg_control and msg_name fields. This forces
12987c478bd9Sstevel@tonic-gate 	 * us to copy the structure to its native form.
12997c478bd9Sstevel@tonic-gate 	 */
13007c478bd9Sstevel@tonic-gate 	lmsg.msg_name = STRUCT_FGETP(u_lmsg, msg_name);
13017c478bd9Sstevel@tonic-gate 	lmsg.msg_namelen = STRUCT_FGET(u_lmsg, msg_namelen);
13027c478bd9Sstevel@tonic-gate 	lmsg.msg_iov = STRUCT_FGETP(u_lmsg, msg_iov);
13037c478bd9Sstevel@tonic-gate 	lmsg.msg_iovlen = STRUCT_FGET(u_lmsg, msg_iovlen);
13047c478bd9Sstevel@tonic-gate 	lmsg.msg_control = STRUCT_FGETP(u_lmsg, msg_control);
13057c478bd9Sstevel@tonic-gate 	lmsg.msg_controllen = STRUCT_FGET(u_lmsg, msg_controllen);
13067c478bd9Sstevel@tonic-gate 	lmsg.msg_flags = STRUCT_FGET(u_lmsg, msg_flags);
13077c478bd9Sstevel@tonic-gate 
13087c478bd9Sstevel@tonic-gate 	iovcnt = lmsg.msg_iovlen;
13097c478bd9Sstevel@tonic-gate 
13107c478bd9Sstevel@tonic-gate 	if (iovcnt <= 0 || iovcnt > MSG_MAXIOVLEN) {
13117c478bd9Sstevel@tonic-gate 		/*
13127c478bd9Sstevel@tonic-gate 		 * Unless this is XPG 4.2 we allow iovcnt == 0 to
13137c478bd9Sstevel@tonic-gate 		 * be compatible with SunOS 4.X and 4.4BSD.
13147c478bd9Sstevel@tonic-gate 		 */
13157c478bd9Sstevel@tonic-gate 		if (iovcnt != 0 || (flags & MSG_XPG4_2))
13167c478bd9Sstevel@tonic-gate 			return (set_errno(EMSGSIZE));
13177c478bd9Sstevel@tonic-gate 	}
13187c478bd9Sstevel@tonic-gate 
13197c478bd9Sstevel@tonic-gate #ifdef _SYSCALL32_IMPL
13207c478bd9Sstevel@tonic-gate 	/*
13217c478bd9Sstevel@tonic-gate 	 * 32-bit callers need to have their iovec expanded, while ensuring
13227c478bd9Sstevel@tonic-gate 	 * that they can't move more than 2Gbytes of data in a single call.
13237c478bd9Sstevel@tonic-gate 	 */
13247c478bd9Sstevel@tonic-gate 	if (model == DATAMODEL_ILP32) {
13257c478bd9Sstevel@tonic-gate 		struct iovec32 aiov32[MSG_MAXIOVLEN];
13267c478bd9Sstevel@tonic-gate 		ssize32_t count32;
13277c478bd9Sstevel@tonic-gate 
13287c478bd9Sstevel@tonic-gate 		if (iovcnt != 0 &&
13297c478bd9Sstevel@tonic-gate 		    copyin((struct iovec32 *)lmsg.msg_iov, aiov32,
13307c478bd9Sstevel@tonic-gate 		    iovcnt * sizeof (struct iovec32)))
13317c478bd9Sstevel@tonic-gate 			return (set_errno(EFAULT));
13327c478bd9Sstevel@tonic-gate 
13337c478bd9Sstevel@tonic-gate 		count32 = 0;
13347c478bd9Sstevel@tonic-gate 		for (i = 0; i < iovcnt; i++) {
13357c478bd9Sstevel@tonic-gate 			ssize32_t iovlen32;
13367c478bd9Sstevel@tonic-gate 
13377c478bd9Sstevel@tonic-gate 			iovlen32 = aiov32[i].iov_len;
13387c478bd9Sstevel@tonic-gate 			count32 += iovlen32;
13397c478bd9Sstevel@tonic-gate 			if (iovlen32 < 0 || count32 < 0)
13407c478bd9Sstevel@tonic-gate 				return (set_errno(EINVAL));
13417c478bd9Sstevel@tonic-gate 			aiov[i].iov_len = iovlen32;
13427c478bd9Sstevel@tonic-gate 			aiov[i].iov_base =
13437c478bd9Sstevel@tonic-gate 			    (caddr_t)(uintptr_t)aiov32[i].iov_base;
13447c478bd9Sstevel@tonic-gate 		}
13457c478bd9Sstevel@tonic-gate 	} else
13467c478bd9Sstevel@tonic-gate #endif /* _SYSCALL32_IMPL */
13477c478bd9Sstevel@tonic-gate 	if (iovcnt != 0 &&
13487c478bd9Sstevel@tonic-gate 	    copyin(lmsg.msg_iov, aiov,
13497c478bd9Sstevel@tonic-gate 	    (unsigned)iovcnt * sizeof (struct iovec))) {
13507c478bd9Sstevel@tonic-gate 		return (set_errno(EFAULT));
13517c478bd9Sstevel@tonic-gate 	}
13527c478bd9Sstevel@tonic-gate 	len = 0;
13537c478bd9Sstevel@tonic-gate 	for (i = 0; i < iovcnt; i++) {
13547c478bd9Sstevel@tonic-gate 		ssize_t iovlen = aiov[i].iov_len;
13557c478bd9Sstevel@tonic-gate 		len += iovlen;
13567c478bd9Sstevel@tonic-gate 		if (iovlen < 0 || len < 0) {
13577c478bd9Sstevel@tonic-gate 			return (set_errno(EINVAL));
13587c478bd9Sstevel@tonic-gate 		}
13597c478bd9Sstevel@tonic-gate 	}
13607c478bd9Sstevel@tonic-gate 	auio.uio_loffset = 0;
13617c478bd9Sstevel@tonic-gate 	auio.uio_iov = aiov;
13627c478bd9Sstevel@tonic-gate 	auio.uio_iovcnt = iovcnt;
13637c478bd9Sstevel@tonic-gate 	auio.uio_resid = len;
13647c478bd9Sstevel@tonic-gate 	auio.uio_segflg = UIO_USERSPACE;
13657c478bd9Sstevel@tonic-gate 	auio.uio_limit = 0;
13667c478bd9Sstevel@tonic-gate 
13677c478bd9Sstevel@tonic-gate 	return (sendit(sock, &lmsg, &auio, flags));
13687c478bd9Sstevel@tonic-gate }
13697c478bd9Sstevel@tonic-gate 
13707c478bd9Sstevel@tonic-gate ssize_t
13717c478bd9Sstevel@tonic-gate sendto(int sock, void *buffer, size_t len, int flags,
13727c478bd9Sstevel@tonic-gate     struct sockaddr *name, socklen_t namelen)
13737c478bd9Sstevel@tonic-gate {
13747c478bd9Sstevel@tonic-gate 	struct nmsghdr lmsg;
13757c478bd9Sstevel@tonic-gate 	struct uio auio;
13767c478bd9Sstevel@tonic-gate 	struct iovec aiov[1];
13777c478bd9Sstevel@tonic-gate 
13787c478bd9Sstevel@tonic-gate 	dprint(1, ("sendto(%d, %p, %ld, %d, %p, %d)\n",
1379903a11ebSrh87107 	    sock, buffer, len, flags, (void *)name, namelen));
13807c478bd9Sstevel@tonic-gate 
13817c478bd9Sstevel@tonic-gate 	if ((ssize_t)len < 0) {
13827c478bd9Sstevel@tonic-gate 		return (set_errno(EINVAL));
13837c478bd9Sstevel@tonic-gate 	}
13847c478bd9Sstevel@tonic-gate 
13857c478bd9Sstevel@tonic-gate 	aiov[0].iov_base = buffer;
13867c478bd9Sstevel@tonic-gate 	aiov[0].iov_len = len;
13877c478bd9Sstevel@tonic-gate 	auio.uio_loffset = 0;
13887c478bd9Sstevel@tonic-gate 	auio.uio_iov = aiov;
13897c478bd9Sstevel@tonic-gate 	auio.uio_iovcnt = 1;
13907c478bd9Sstevel@tonic-gate 	auio.uio_resid = len;
13917c478bd9Sstevel@tonic-gate 	auio.uio_segflg = UIO_USERSPACE;
13927c478bd9Sstevel@tonic-gate 	auio.uio_limit = 0;
13937c478bd9Sstevel@tonic-gate 
13947c478bd9Sstevel@tonic-gate 	lmsg.msg_name = (char *)name;
13957c478bd9Sstevel@tonic-gate 	lmsg.msg_namelen = namelen;
13967c478bd9Sstevel@tonic-gate 	lmsg.msg_control = NULL;
13977c478bd9Sstevel@tonic-gate 	if (!(flags & MSG_XPG4_2)) {
13987c478bd9Sstevel@tonic-gate 		/*
13997c478bd9Sstevel@tonic-gate 		 * In order to be compatible with the libsocket/sockmod
14007c478bd9Sstevel@tonic-gate 		 * implementation we set EOR for all send* calls.
14017c478bd9Sstevel@tonic-gate 		 */
14027c478bd9Sstevel@tonic-gate 		flags |= MSG_EOR;
14037c478bd9Sstevel@tonic-gate 	}
14047c478bd9Sstevel@tonic-gate 	return (sendit(sock, &lmsg, &auio, flags));
14057c478bd9Sstevel@tonic-gate }
14067c478bd9Sstevel@tonic-gate 
14077c478bd9Sstevel@tonic-gate /*ARGSUSED3*/
14087c478bd9Sstevel@tonic-gate int
14097c478bd9Sstevel@tonic-gate getpeername(int sock, struct sockaddr *name, socklen_t *namelenp, int version)
14107c478bd9Sstevel@tonic-gate {
14117c478bd9Sstevel@tonic-gate 	struct sonode *so;
14127c478bd9Sstevel@tonic-gate 	int error;
14137c478bd9Sstevel@tonic-gate 	socklen_t namelen;
14140f1702c5SYu Xiangning 	socklen_t sock_addrlen;
14150f1702c5SYu Xiangning 	struct sockaddr *sock_addrp;
14167c478bd9Sstevel@tonic-gate 
14177c478bd9Sstevel@tonic-gate 	dprint(1, ("getpeername(%d, %p, %p)\n",
1418903a11ebSrh87107 	    sock, (void *)name, (void *)namelenp));
14197c478bd9Sstevel@tonic-gate 
14207c478bd9Sstevel@tonic-gate 	if ((so = getsonode(sock, &error, NULL)) == NULL)
14217c478bd9Sstevel@tonic-gate 		goto bad;
14227c478bd9Sstevel@tonic-gate 
14237c478bd9Sstevel@tonic-gate 	ASSERT(MUTEX_NOT_HELD(&so->so_lock));
14247c478bd9Sstevel@tonic-gate 	if (copyin(namelenp, &namelen, sizeof (namelen)) ||
14257c478bd9Sstevel@tonic-gate 	    (name == NULL && namelen != 0)) {
14267c478bd9Sstevel@tonic-gate 		error = EFAULT;
14277c478bd9Sstevel@tonic-gate 		goto rel_out;
14287c478bd9Sstevel@tonic-gate 	}
14290f1702c5SYu Xiangning 	sock_addrlen = so->so_max_addr_len;
14300f1702c5SYu Xiangning 	sock_addrp = (struct sockaddr *)kmem_alloc(sock_addrlen, KM_SLEEP);
14317c478bd9Sstevel@tonic-gate 
14320f1702c5SYu Xiangning 	if ((error = socket_getpeername(so, sock_addrp, &sock_addrlen,
14330f1702c5SYu Xiangning 	    B_FALSE, CRED())) == 0) {
14340f1702c5SYu Xiangning 		ASSERT(sock_addrlen <= so->so_max_addr_len);
14350f1702c5SYu Xiangning 		error = copyout_name(name, namelen, namelenp,
14360f1702c5SYu Xiangning 		    (void *)sock_addrp, sock_addrlen);
14377c478bd9Sstevel@tonic-gate 	}
14380f1702c5SYu Xiangning 	kmem_free(sock_addrp, so->so_max_addr_len);
14397c478bd9Sstevel@tonic-gate rel_out:
14407c478bd9Sstevel@tonic-gate 	releasef(sock);
14417c478bd9Sstevel@tonic-gate bad:	return (error != 0 ? set_errno(error) : 0);
14427c478bd9Sstevel@tonic-gate }
14437c478bd9Sstevel@tonic-gate 
14447c478bd9Sstevel@tonic-gate /*ARGSUSED3*/
14457c478bd9Sstevel@tonic-gate int
1446*f50f4621SMarcel Telka getsockname(int sock, struct sockaddr *name, socklen_t *namelenp, int version)
14477c478bd9Sstevel@tonic-gate {
14487c478bd9Sstevel@tonic-gate 	struct sonode *so;
14497c478bd9Sstevel@tonic-gate 	int error;
14500f1702c5SYu Xiangning 	socklen_t namelen, sock_addrlen;
14510f1702c5SYu Xiangning 	struct sockaddr *sock_addrp;
14527c478bd9Sstevel@tonic-gate 
14537c478bd9Sstevel@tonic-gate 	dprint(1, ("getsockname(%d, %p, %p)\n",
1454903a11ebSrh87107 	    sock, (void *)name, (void *)namelenp));
14557c478bd9Sstevel@tonic-gate 
14567c478bd9Sstevel@tonic-gate 	if ((so = getsonode(sock, &error, NULL)) == NULL)
14577c478bd9Sstevel@tonic-gate 		goto bad;
14587c478bd9Sstevel@tonic-gate 
14597c478bd9Sstevel@tonic-gate 	ASSERT(MUTEX_NOT_HELD(&so->so_lock));
14607c478bd9Sstevel@tonic-gate 	if (copyin(namelenp, &namelen, sizeof (namelen)) ||
14617c478bd9Sstevel@tonic-gate 	    (name == NULL && namelen != 0)) {
14627c478bd9Sstevel@tonic-gate 		error = EFAULT;
14637c478bd9Sstevel@tonic-gate 		goto rel_out;
14647c478bd9Sstevel@tonic-gate 	}
14657c478bd9Sstevel@tonic-gate 
14660f1702c5SYu Xiangning 	sock_addrlen = so->so_max_addr_len;
14670f1702c5SYu Xiangning 	sock_addrp = (struct sockaddr *)kmem_alloc(sock_addrlen, KM_SLEEP);
14680f1702c5SYu Xiangning 	if ((error = socket_getsockname(so, sock_addrp, &sock_addrlen,
14690f1702c5SYu Xiangning 	    CRED())) == 0) {
14707c478bd9Sstevel@tonic-gate 		ASSERT(MUTEX_NOT_HELD(&so->so_lock));
14710f1702c5SYu Xiangning 		ASSERT(sock_addrlen <= so->so_max_addr_len);
14727c478bd9Sstevel@tonic-gate 		error = copyout_name(name, namelen, namelenp,
14730f1702c5SYu Xiangning 		    (void *)sock_addrp, sock_addrlen);
14740f1702c5SYu Xiangning 	}
14750f1702c5SYu Xiangning 	kmem_free(sock_addrp, so->so_max_addr_len);
14767c478bd9Sstevel@tonic-gate rel_out:
14777c478bd9Sstevel@tonic-gate 	releasef(sock);
14787c478bd9Sstevel@tonic-gate bad:	return (error != 0 ? set_errno(error) : 0);
14797c478bd9Sstevel@tonic-gate }
14807c478bd9Sstevel@tonic-gate 
14817c478bd9Sstevel@tonic-gate /*ARGSUSED5*/
14827c478bd9Sstevel@tonic-gate int
1483*f50f4621SMarcel Telka getsockopt(int sock, int level, int option_name, void *option_value,
1484*f50f4621SMarcel Telka     socklen_t *option_lenp, int version)
14857c478bd9Sstevel@tonic-gate {
14867c478bd9Sstevel@tonic-gate 	struct sonode *so;
14877c478bd9Sstevel@tonic-gate 	socklen_t optlen, optlen_res;
14887c478bd9Sstevel@tonic-gate 	void *optval;
14897c478bd9Sstevel@tonic-gate 	int error;
14907c478bd9Sstevel@tonic-gate 
14917c478bd9Sstevel@tonic-gate 	dprint(1, ("getsockopt(%d, %d, %d, %p, %p)\n",
1492903a11ebSrh87107 	    sock, level, option_name, option_value, (void *)option_lenp));
14937c478bd9Sstevel@tonic-gate 
14947c478bd9Sstevel@tonic-gate 	if ((so = getsonode(sock, &error, NULL)) == NULL)
14957c478bd9Sstevel@tonic-gate 		return (set_errno(error));
14967c478bd9Sstevel@tonic-gate 
14977c478bd9Sstevel@tonic-gate 	ASSERT(MUTEX_NOT_HELD(&so->so_lock));
14987c478bd9Sstevel@tonic-gate 	if (copyin(option_lenp, &optlen, sizeof (optlen))) {
14997c478bd9Sstevel@tonic-gate 		releasef(sock);
15007c478bd9Sstevel@tonic-gate 		return (set_errno(EFAULT));
15017c478bd9Sstevel@tonic-gate 	}
15027c478bd9Sstevel@tonic-gate 	/*
15037c478bd9Sstevel@tonic-gate 	 * Verify that the length is not excessive to prevent
15047c478bd9Sstevel@tonic-gate 	 * an application from consuming all of kernel memory.
15057c478bd9Sstevel@tonic-gate 	 */
15067c478bd9Sstevel@tonic-gate 	if (optlen > SO_MAXARGSIZE) {
15077c478bd9Sstevel@tonic-gate 		error = EINVAL;
15087c478bd9Sstevel@tonic-gate 		releasef(sock);
15097c478bd9Sstevel@tonic-gate 		return (set_errno(error));
15107c478bd9Sstevel@tonic-gate 	}
15117c478bd9Sstevel@tonic-gate 	optval = kmem_alloc(optlen, KM_SLEEP);
15127c478bd9Sstevel@tonic-gate 	optlen_res = optlen;
15130f1702c5SYu Xiangning 	error = socket_getsockopt(so, level, option_name, optval,
15140f1702c5SYu Xiangning 	    &optlen_res, (version != SOV_XPG4_2) ? 0 : _SOGETSOCKOPT_XPG4_2,
15150f1702c5SYu Xiangning 	    CRED());
15167c478bd9Sstevel@tonic-gate 	releasef(sock);
15177c478bd9Sstevel@tonic-gate 	if (error) {
15187c478bd9Sstevel@tonic-gate 		kmem_free(optval, optlen);
15197c478bd9Sstevel@tonic-gate 		return (set_errno(error));
15207c478bd9Sstevel@tonic-gate 	}
15217c478bd9Sstevel@tonic-gate 	error = copyout_arg(option_value, optlen, option_lenp,
15227c478bd9Sstevel@tonic-gate 	    optval, optlen_res);
15237c478bd9Sstevel@tonic-gate 	kmem_free(optval, optlen);
15247c478bd9Sstevel@tonic-gate 	if (error)
15257c478bd9Sstevel@tonic-gate 		return (set_errno(error));
15267c478bd9Sstevel@tonic-gate 	return (0);
15277c478bd9Sstevel@tonic-gate }
15287c478bd9Sstevel@tonic-gate 
15297c478bd9Sstevel@tonic-gate /*ARGSUSED5*/
15307c478bd9Sstevel@tonic-gate int
1531*f50f4621SMarcel Telka setsockopt(int sock, int level, int option_name, void *option_value,
1532*f50f4621SMarcel Telka     socklen_t option_len, int version)
15337c478bd9Sstevel@tonic-gate {
15347c478bd9Sstevel@tonic-gate 	struct sonode *so;
15357c478bd9Sstevel@tonic-gate 	intptr_t buffer[2];
15367c478bd9Sstevel@tonic-gate 	void *optval = NULL;
15377c478bd9Sstevel@tonic-gate 	int error;
15387c478bd9Sstevel@tonic-gate 
15397c478bd9Sstevel@tonic-gate 	dprint(1, ("setsockopt(%d, %d, %d, %p, %d)\n",
15407c478bd9Sstevel@tonic-gate 	    sock, level, option_name, option_value, option_len));
15417c478bd9Sstevel@tonic-gate 
15427c478bd9Sstevel@tonic-gate 	if ((so = getsonode(sock, &error, NULL)) == NULL)
15437c478bd9Sstevel@tonic-gate 		return (set_errno(error));
15447c478bd9Sstevel@tonic-gate 
15457c478bd9Sstevel@tonic-gate 	if (option_value != NULL) {
15467c478bd9Sstevel@tonic-gate 		if (option_len != 0) {
15477c478bd9Sstevel@tonic-gate 			/*
15487c478bd9Sstevel@tonic-gate 			 * Verify that the length is not excessive to prevent
15497c478bd9Sstevel@tonic-gate 			 * an application from consuming all of kernel memory.
15507c478bd9Sstevel@tonic-gate 			 */
15517c478bd9Sstevel@tonic-gate 			if (option_len > SO_MAXARGSIZE) {
15527c478bd9Sstevel@tonic-gate 				error = EINVAL;
15537c478bd9Sstevel@tonic-gate 				goto done2;
15547c478bd9Sstevel@tonic-gate 			}
15557c478bd9Sstevel@tonic-gate 			optval = option_len <= sizeof (buffer) ?
15567c478bd9Sstevel@tonic-gate 			    &buffer : kmem_alloc((size_t)option_len, KM_SLEEP);
15577c478bd9Sstevel@tonic-gate 			ASSERT(MUTEX_NOT_HELD(&so->so_lock));
15587c478bd9Sstevel@tonic-gate 			if (copyin(option_value, optval, (size_t)option_len)) {
15597c478bd9Sstevel@tonic-gate 				error = EFAULT;
15607c478bd9Sstevel@tonic-gate 				goto done1;
15617c478bd9Sstevel@tonic-gate 			}
15627c478bd9Sstevel@tonic-gate 		}
15637c478bd9Sstevel@tonic-gate 	} else
15647c478bd9Sstevel@tonic-gate 		option_len = 0;
15657c478bd9Sstevel@tonic-gate 
15660f1702c5SYu Xiangning 	error = socket_setsockopt(so, level, option_name, optval,
15670f1702c5SYu Xiangning 	    (t_uscalar_t)option_len, CRED());
15687c478bd9Sstevel@tonic-gate done1:
15697c478bd9Sstevel@tonic-gate 	if (optval != buffer)
15707c478bd9Sstevel@tonic-gate 		kmem_free(optval, (size_t)option_len);
15717c478bd9Sstevel@tonic-gate done2:
15727c478bd9Sstevel@tonic-gate 	releasef(sock);
15737c478bd9Sstevel@tonic-gate 	if (error)
15747c478bd9Sstevel@tonic-gate 		return (set_errno(error));
15757c478bd9Sstevel@tonic-gate 	return (0);
15767c478bd9Sstevel@tonic-gate }
15777c478bd9Sstevel@tonic-gate 
15783e95bd4aSAnders Persson static int
15793e95bd4aSAnders Persson sockconf_add_sock(int family, int type, int protocol, char *name)
15807c478bd9Sstevel@tonic-gate {
15817c478bd9Sstevel@tonic-gate 	int error = 0;
15823e95bd4aSAnders Persson 	char *kdevpath = NULL;
15833e95bd4aSAnders Persson 	char *kmodule = NULL;
15843e95bd4aSAnders Persson 	char *buf = NULL;
15853e95bd4aSAnders Persson 	size_t pathlen = 0;
15863e95bd4aSAnders Persson 	struct sockparams *sp;
15877c478bd9Sstevel@tonic-gate 
15883e95bd4aSAnders Persson 	if (name == NULL)
15893e95bd4aSAnders Persson 		return (EINVAL);
15900f1702c5SYu Xiangning 	/*
15910f1702c5SYu Xiangning 	 * Copyin the name.
15927c478bd9Sstevel@tonic-gate 	 * This also makes it possible to check for too long pathnames.
15930f1702c5SYu Xiangning 	 * Compress the space needed for the name before passing it
15947c478bd9Sstevel@tonic-gate 	 * to soconfig - soconfig will store the string until
15957c478bd9Sstevel@tonic-gate 	 * the configuration is removed.
15967c478bd9Sstevel@tonic-gate 	 */
15977c478bd9Sstevel@tonic-gate 	buf = kmem_alloc(MAXPATHLEN, KM_SLEEP);
15980f1702c5SYu Xiangning 	if ((error = copyinstr(name, buf, MAXPATHLEN, &pathlen)) != 0) {
15997c478bd9Sstevel@tonic-gate 		kmem_free(buf, MAXPATHLEN);
16003e95bd4aSAnders Persson 		return (error);
16017c478bd9Sstevel@tonic-gate 	}
16020f1702c5SYu Xiangning 	if (strncmp(buf, "/dev", strlen("/dev")) == 0) {
16030f1702c5SYu Xiangning 		/* For device */
16047c478bd9Sstevel@tonic-gate 
16050f1702c5SYu Xiangning 		/*
16060f1702c5SYu Xiangning 		 * Special handling for NCA:
16070f1702c5SYu Xiangning 		 *
16080f1702c5SYu Xiangning 		 * DEV_NCA is never opened even if an application
16090f1702c5SYu Xiangning 		 * requests for AF_NCA. The device opened is instead a
16100f1702c5SYu Xiangning 		 * predefined AF_INET transport (NCA_INET_DEV).
16110f1702c5SYu Xiangning 		 *
16120f1702c5SYu Xiangning 		 * Prior to Volo (PSARC/2007/587) NCA would determine
16130f1702c5SYu Xiangning 		 * the device using a lookup, which worked then because
16140f1702c5SYu Xiangning 		 * all protocols were based on TPI. Since TPI is no
16150f1702c5SYu Xiangning 		 * longer the default, we have to explicitly state
16160f1702c5SYu Xiangning 		 * which device to use.
16170f1702c5SYu Xiangning 		 */
16180f1702c5SYu Xiangning 		if (strcmp(buf, NCA_DEV) == 0) {
16190f1702c5SYu Xiangning 			/* only support entry <28, 2, 0> */
16200f1702c5SYu Xiangning 			if (family != AF_NCA || type != SOCK_STREAM ||
16210f1702c5SYu Xiangning 			    protocol != 0) {
16220f1702c5SYu Xiangning 				kmem_free(buf, MAXPATHLEN);
16233e95bd4aSAnders Persson 				return (EINVAL);
16240f1702c5SYu Xiangning 			}
16250f1702c5SYu Xiangning 
16260f1702c5SYu Xiangning 			pathlen = strlen(NCA_INET_DEV) + 1;
16270f1702c5SYu Xiangning 			kdevpath = kmem_alloc(pathlen, KM_SLEEP);
16280f1702c5SYu Xiangning 			bcopy(NCA_INET_DEV, kdevpath, pathlen);
16290f1702c5SYu Xiangning 			kdevpath[pathlen - 1] = '\0';
16300f1702c5SYu Xiangning 		} else {
16310f1702c5SYu Xiangning 			kdevpath = kmem_alloc(pathlen, KM_SLEEP);
16320f1702c5SYu Xiangning 			bcopy(buf, kdevpath, pathlen);
16330f1702c5SYu Xiangning 			kdevpath[pathlen - 1] = '\0';
16340f1702c5SYu Xiangning 		}
16350f1702c5SYu Xiangning 	} else {
16360f1702c5SYu Xiangning 		/* For socket module */
16370f1702c5SYu Xiangning 		kmodule = kmem_alloc(pathlen, KM_SLEEP);
16380f1702c5SYu Xiangning 		bcopy(buf, kmodule, pathlen);
16390f1702c5SYu Xiangning 		kmodule[pathlen - 1] = '\0';
16400f1702c5SYu Xiangning 		pathlen = 0;
16410f1702c5SYu Xiangning 	}
16423e95bd4aSAnders Persson 	kmem_free(buf, MAXPATHLEN);
16433e95bd4aSAnders Persson 
16443e95bd4aSAnders Persson 	/* sockparams_create frees mod name and devpath upon failure */
16453e95bd4aSAnders Persson 	sp = sockparams_create(family, type, protocol, kmodule,
16463e95bd4aSAnders Persson 	    kdevpath, pathlen, 0, KM_SLEEP, &error);
16473e95bd4aSAnders Persson 	if (sp != NULL) {
16483e95bd4aSAnders Persson 		error = sockparams_add(sp);
16493e95bd4aSAnders Persson 		if (error != 0)
16503e95bd4aSAnders Persson 			sockparams_destroy(sp);
16510f1702c5SYu Xiangning 	}
16527c478bd9Sstevel@tonic-gate 
16533e95bd4aSAnders Persson 	return (error);
16547c478bd9Sstevel@tonic-gate }
16553e95bd4aSAnders Persson 
16563e95bd4aSAnders Persson static int
16573e95bd4aSAnders Persson sockconf_remove_sock(int family, int type, int protocol)
16583e95bd4aSAnders Persson {
16593e95bd4aSAnders Persson 	return (sockparams_delete(family, type, protocol));
16603e95bd4aSAnders Persson }
16613e95bd4aSAnders Persson 
16623e95bd4aSAnders Persson static int
16633e95bd4aSAnders Persson sockconfig_remove_filter(const char *uname)
16643e95bd4aSAnders Persson {
16653e95bd4aSAnders Persson 	char kname[SOF_MAXNAMELEN];
16663e95bd4aSAnders Persson 	size_t len;
16673e95bd4aSAnders Persson 	int error;
16683e95bd4aSAnders Persson 	sof_entry_t *ent;
16693e95bd4aSAnders Persson 
16703e95bd4aSAnders Persson 	if ((error = copyinstr(uname, kname, SOF_MAXNAMELEN, &len)) != 0)
16713e95bd4aSAnders Persson 		return (error);
16723e95bd4aSAnders Persson 
16733e95bd4aSAnders Persson 	ent = sof_entry_remove_by_name(kname);
16743e95bd4aSAnders Persson 	if (ent == NULL)
16753e95bd4aSAnders Persson 		return (ENXIO);
16763e95bd4aSAnders Persson 
16773e95bd4aSAnders Persson 	mutex_enter(&ent->sofe_lock);
16783e95bd4aSAnders Persson 	ASSERT(!(ent->sofe_flags & SOFEF_CONDEMED));
16793e95bd4aSAnders Persson 	if (ent->sofe_refcnt == 0) {
16803e95bd4aSAnders Persson 		mutex_exit(&ent->sofe_lock);
16813e95bd4aSAnders Persson 		sof_entry_free(ent);
16823e95bd4aSAnders Persson 	} else {
16833e95bd4aSAnders Persson 		/* let the last socket free the filter */
16843e95bd4aSAnders Persson 		ent->sofe_flags |= SOFEF_CONDEMED;
16853e95bd4aSAnders Persson 		mutex_exit(&ent->sofe_lock);
16863e95bd4aSAnders Persson 	}
16873e95bd4aSAnders Persson 
16883e95bd4aSAnders Persson 	return (0);
16893e95bd4aSAnders Persson }
16903e95bd4aSAnders Persson 
16913e95bd4aSAnders Persson static int
16923e95bd4aSAnders Persson sockconfig_add_filter(const char *uname, void *ufilpropp)
16933e95bd4aSAnders Persson {
16943e95bd4aSAnders Persson 	struct sockconfig_filter_props filprop;
16953e95bd4aSAnders Persson 	sof_entry_t *ent;
16963e95bd4aSAnders Persson 	int error;
16973e95bd4aSAnders Persson 	size_t tuplesz, len;
16983e95bd4aSAnders Persson 	char hintbuf[SOF_MAXNAMELEN];
16993e95bd4aSAnders Persson 
17003e95bd4aSAnders Persson 	ent = kmem_zalloc(sizeof (sof_entry_t), KM_SLEEP);
17013e95bd4aSAnders Persson 	mutex_init(&ent->sofe_lock, NULL, MUTEX_DEFAULT, NULL);
17023e95bd4aSAnders Persson 
17033e95bd4aSAnders Persson 	if ((error = copyinstr(uname, ent->sofe_name, SOF_MAXNAMELEN,
17043e95bd4aSAnders Persson 	    &len)) != 0) {
17053e95bd4aSAnders Persson 		sof_entry_free(ent);
17063e95bd4aSAnders Persson 		return (error);
17073e95bd4aSAnders Persson 	}
17083e95bd4aSAnders Persson 
17093e95bd4aSAnders Persson 	if (get_udatamodel() == DATAMODEL_NATIVE) {
17103e95bd4aSAnders Persson 		if (copyin(ufilpropp, &filprop, sizeof (filprop)) != 0) {
17113e95bd4aSAnders Persson 			sof_entry_free(ent);
17123e95bd4aSAnders Persson 			return (EFAULT);
17133e95bd4aSAnders Persson 		}
17143e95bd4aSAnders Persson 	}
17153e95bd4aSAnders Persson #ifdef	_SYSCALL32_IMPL
17163e95bd4aSAnders Persson 	else {
17173e95bd4aSAnders Persson 		struct sockconfig_filter_props32 filprop32;
17183e95bd4aSAnders Persson 
17193e95bd4aSAnders Persson 		if (copyin(ufilpropp, &filprop32, sizeof (filprop32)) != 0) {
17203e95bd4aSAnders Persson 			sof_entry_free(ent);
17213e95bd4aSAnders Persson 			return (EFAULT);
17223e95bd4aSAnders Persson 		}
17233e95bd4aSAnders Persson 		filprop.sfp_modname = (char *)(uintptr_t)filprop32.sfp_modname;
17243e95bd4aSAnders Persson 		filprop.sfp_autoattach = filprop32.sfp_autoattach;
17253e95bd4aSAnders Persson 		filprop.sfp_hint = filprop32.sfp_hint;
17263e95bd4aSAnders Persson 		filprop.sfp_hintarg = (char *)(uintptr_t)filprop32.sfp_hintarg;
17273e95bd4aSAnders Persson 		filprop.sfp_socktuple_cnt = filprop32.sfp_socktuple_cnt;
17283e95bd4aSAnders Persson 		filprop.sfp_socktuple =
17293e95bd4aSAnders Persson 		    (sof_socktuple_t *)(uintptr_t)filprop32.sfp_socktuple;
17303e95bd4aSAnders Persson 	}
17313e95bd4aSAnders Persson #endif	/* _SYSCALL32_IMPL */
17323e95bd4aSAnders Persson 
17333e95bd4aSAnders Persson 	if ((error = copyinstr(filprop.sfp_modname, ent->sofe_modname,
17343e95bd4aSAnders Persson 	    sizeof (ent->sofe_modname), &len)) != 0) {
17353e95bd4aSAnders Persson 		sof_entry_free(ent);
17363e95bd4aSAnders Persson 		return (error);
17373e95bd4aSAnders Persson 	}
17383e95bd4aSAnders Persson 
17393e95bd4aSAnders Persson 	/*
17403e95bd4aSAnders Persson 	 * A filter must specify at least one socket tuple.
17413e95bd4aSAnders Persson 	 */
17423e95bd4aSAnders Persson 	if (filprop.sfp_socktuple_cnt == 0 ||
17433e95bd4aSAnders Persson 	    filprop.sfp_socktuple_cnt > SOF_MAXSOCKTUPLECNT) {
17443e95bd4aSAnders Persson 		sof_entry_free(ent);
17453e95bd4aSAnders Persson 		return (EINVAL);
17463e95bd4aSAnders Persson 	}
17473e95bd4aSAnders Persson 	ent->sofe_flags = filprop.sfp_autoattach ? SOFEF_AUTO : SOFEF_PROG;
17483e95bd4aSAnders Persson 	ent->sofe_hint = filprop.sfp_hint;
17493e95bd4aSAnders Persson 
17503e95bd4aSAnders Persson 	/*
17513e95bd4aSAnders Persson 	 * Verify the hint, and copy in the hint argument, if necessary.
17523e95bd4aSAnders Persson 	 */
17533e95bd4aSAnders Persson 	switch (ent->sofe_hint) {
17543e95bd4aSAnders Persson 	case SOF_HINT_BEFORE:
17553e95bd4aSAnders Persson 	case SOF_HINT_AFTER:
17563e95bd4aSAnders Persson 		if ((error = copyinstr(filprop.sfp_hintarg, hintbuf,
17573e95bd4aSAnders Persson 		    sizeof (hintbuf), &len)) != 0) {
17583e95bd4aSAnders Persson 			sof_entry_free(ent);
17593e95bd4aSAnders Persson 			return (error);
17603e95bd4aSAnders Persson 		}
17613e95bd4aSAnders Persson 		ent->sofe_hintarg = kmem_alloc(len, KM_SLEEP);
17623e95bd4aSAnders Persson 		bcopy(hintbuf, ent->sofe_hintarg, len);
17633e95bd4aSAnders Persson 		/* FALLTHRU */
17643e95bd4aSAnders Persson 	case SOF_HINT_TOP:
17653e95bd4aSAnders Persson 	case SOF_HINT_BOTTOM:
17663e95bd4aSAnders Persson 		/* hints cannot be used with programmatic filters */
17673e95bd4aSAnders Persson 		if (ent->sofe_flags & SOFEF_PROG) {
17683e95bd4aSAnders Persson 			sof_entry_free(ent);
17693e95bd4aSAnders Persson 			return (EINVAL);
17703e95bd4aSAnders Persson 		}
17713e95bd4aSAnders Persson 		break;
17723e95bd4aSAnders Persson 	case SOF_HINT_NONE:
17733e95bd4aSAnders Persson 		break;
17743e95bd4aSAnders Persson 	default:
17753e95bd4aSAnders Persson 		/* bad hint value */
17763e95bd4aSAnders Persson 		sof_entry_free(ent);
17773e95bd4aSAnders Persson 		return (EINVAL);
17783e95bd4aSAnders Persson 	}
17793e95bd4aSAnders Persson 
17803e95bd4aSAnders Persson 	ent->sofe_socktuple_cnt = filprop.sfp_socktuple_cnt;
17813e95bd4aSAnders Persson 	tuplesz = sizeof (sof_socktuple_t) * ent->sofe_socktuple_cnt;
17823e95bd4aSAnders Persson 	ent->sofe_socktuple = kmem_alloc(tuplesz, KM_SLEEP);
17833e95bd4aSAnders Persson 
17843e95bd4aSAnders Persson 	if (get_udatamodel() == DATAMODEL_NATIVE) {
17853e95bd4aSAnders Persson 		if (copyin(filprop.sfp_socktuple, ent->sofe_socktuple,
17863e95bd4aSAnders Persson 		    tuplesz)) {
17873e95bd4aSAnders Persson 			sof_entry_free(ent);
17883e95bd4aSAnders Persson 			return (EFAULT);
17893e95bd4aSAnders Persson 		}
17903e95bd4aSAnders Persson 	}
17913e95bd4aSAnders Persson #ifdef	_SYSCALL32_IMPL
17923e95bd4aSAnders Persson 	else {
17933e95bd4aSAnders Persson 		int i;
17943e95bd4aSAnders Persson 		caddr_t data = (caddr_t)filprop.sfp_socktuple;
17953e95bd4aSAnders Persson 		sof_socktuple_t	*tup = ent->sofe_socktuple;
17963e95bd4aSAnders Persson 		sof_socktuple32_t tup32;
17973e95bd4aSAnders Persson 
17983e95bd4aSAnders Persson 		tup = ent->sofe_socktuple;
17993e95bd4aSAnders Persson 		for (i = 0; i < ent->sofe_socktuple_cnt; i++, tup++) {
18003e95bd4aSAnders Persson 			ASSERT(tup < ent->sofe_socktuple + tuplesz);
18013e95bd4aSAnders Persson 
18023e95bd4aSAnders Persson 			if (copyin(data, &tup32, sizeof (tup32)) != 0) {
18033e95bd4aSAnders Persson 				sof_entry_free(ent);
18043e95bd4aSAnders Persson 				return (EFAULT);
18053e95bd4aSAnders Persson 			}
18063e95bd4aSAnders Persson 			tup->sofst_family = tup32.sofst_family;
18073e95bd4aSAnders Persson 			tup->sofst_type = tup32.sofst_type;
18083e95bd4aSAnders Persson 			tup->sofst_protocol = tup32.sofst_protocol;
18093e95bd4aSAnders Persson 
18103e95bd4aSAnders Persson 			data += sizeof (tup32);
18113e95bd4aSAnders Persson 		}
18123e95bd4aSAnders Persson 	}
18133e95bd4aSAnders Persson #endif	/* _SYSCALL32_IMPL */
18143e95bd4aSAnders Persson 
18153e95bd4aSAnders Persson 	/* Sockets can start using the filter as soon as the filter is added */
18163e95bd4aSAnders Persson 	if ((error = sof_entry_add(ent)) != 0)
18173e95bd4aSAnders Persson 		sof_entry_free(ent);
18183e95bd4aSAnders Persson 
18193e95bd4aSAnders Persson 	return (error);
18203e95bd4aSAnders Persson }
18213e95bd4aSAnders Persson 
18223e95bd4aSAnders Persson /*
18233e95bd4aSAnders Persson  * Socket configuration system call. It is used to add and remove
18243e95bd4aSAnders Persson  * socket types.
18253e95bd4aSAnders Persson  */
18263e95bd4aSAnders Persson int
18273e95bd4aSAnders Persson sockconfig(int cmd, void *arg1, void *arg2, void *arg3, void *arg4)
18283e95bd4aSAnders Persson {
18293e95bd4aSAnders Persson 	int error = 0;
18303e95bd4aSAnders Persson 
18313e95bd4aSAnders Persson 	if (secpolicy_net_config(CRED(), B_FALSE) != 0)
18323e95bd4aSAnders Persson 		return (set_errno(EPERM));
18333e95bd4aSAnders Persson 
18343e95bd4aSAnders Persson 	if (sockfs_defer_nl7c_init) {
18353e95bd4aSAnders Persson 		nl7c_init();
18363e95bd4aSAnders Persson 		sockfs_defer_nl7c_init = 0;
18373e95bd4aSAnders Persson 	}
18383e95bd4aSAnders Persson 
18393e95bd4aSAnders Persson 	switch (cmd) {
18403e95bd4aSAnders Persson 	case SOCKCONFIG_ADD_SOCK:
18413e95bd4aSAnders Persson 		error = sockconf_add_sock((int)(uintptr_t)arg1,
18423e95bd4aSAnders Persson 		    (int)(uintptr_t)arg2, (int)(uintptr_t)arg3, arg4);
18433e95bd4aSAnders Persson 		break;
18443e95bd4aSAnders Persson 	case SOCKCONFIG_REMOVE_SOCK:
18453e95bd4aSAnders Persson 		error = sockconf_remove_sock((int)(uintptr_t)arg1,
18463e95bd4aSAnders Persson 		    (int)(uintptr_t)arg2, (int)(uintptr_t)arg3);
18473e95bd4aSAnders Persson 		break;
18483e95bd4aSAnders Persson 	case SOCKCONFIG_ADD_FILTER:
18493e95bd4aSAnders Persson 		error = sockconfig_add_filter((const char *)arg1, arg2);
18503e95bd4aSAnders Persson 		break;
18513e95bd4aSAnders Persson 	case SOCKCONFIG_REMOVE_FILTER:
18523e95bd4aSAnders Persson 		error = sockconfig_remove_filter((const char *)arg1);
18533e95bd4aSAnders Persson 		break;
185419581f84SAlexander Eremin 	case SOCKCONFIG_GET_SOCKTABLE:
185519581f84SAlexander Eremin 		error = sockparams_copyout_socktable((int)(uintptr_t)arg1);
185619581f84SAlexander Eremin 		break;
18573e95bd4aSAnders Persson 	default:
18583e95bd4aSAnders Persson #ifdef	DEBUG
18593e95bd4aSAnders Persson 		cmn_err(CE_NOTE, "sockconfig: unkonwn subcommand %d", cmd);
18603e95bd4aSAnders Persson #endif
18613e95bd4aSAnders Persson 		error = EINVAL;
18623e95bd4aSAnders Persson 		break;
18633e95bd4aSAnders Persson 	}
18643e95bd4aSAnders Persson 
18653e95bd4aSAnders Persson 	if (error != 0) {
18667c478bd9Sstevel@tonic-gate 		eprintline(error);
18677c478bd9Sstevel@tonic-gate 		return (set_errno(error));
18687c478bd9Sstevel@tonic-gate 	}
18697c478bd9Sstevel@tonic-gate 	return (0);
18707c478bd9Sstevel@tonic-gate }
18717c478bd9Sstevel@tonic-gate 
18727c478bd9Sstevel@tonic-gate 
18737c478bd9Sstevel@tonic-gate /*
18747c478bd9Sstevel@tonic-gate  * Sendfile is implemented through two schemes, direct I/O or by
18757c478bd9Sstevel@tonic-gate  * caching in the filesystem page cache. We cache the input file by
18767c478bd9Sstevel@tonic-gate  * default and use direct I/O only if sendfile_max_size is set
18777c478bd9Sstevel@tonic-gate  * appropriately as explained below. Note that this logic is consistent
18787c478bd9Sstevel@tonic-gate  * with other filesystems where caching is turned on by default
18797c478bd9Sstevel@tonic-gate  * unless explicitly turned off by using the DIRECTIO ioctl.
18807c478bd9Sstevel@tonic-gate  *
18817c478bd9Sstevel@tonic-gate  * We choose a slightly different scheme here. One can turn off
18827c478bd9Sstevel@tonic-gate  * caching by setting sendfile_max_size to 0. One can also enable
18837c478bd9Sstevel@tonic-gate  * caching of files <= sendfile_max_size by setting sendfile_max_size
18847c478bd9Sstevel@tonic-gate  * to an appropriate value. By default sendfile_max_size is set to the
18857c478bd9Sstevel@tonic-gate  * maximum value so that all files are cached. In future, we may provide
18867c478bd9Sstevel@tonic-gate  * better interfaces for caching the file.
18877c478bd9Sstevel@tonic-gate  *
18887c478bd9Sstevel@tonic-gate  * Sendfile through Direct I/O (Zero copy)
18897c478bd9Sstevel@tonic-gate  * --------------------------------------
18907c478bd9Sstevel@tonic-gate  *
18917c478bd9Sstevel@tonic-gate  * As disks are normally slower than the network, we can't have a
18927c478bd9Sstevel@tonic-gate  * single thread that reads the disk and writes to the network. We
18937c478bd9Sstevel@tonic-gate  * need to have parallelism. This is done by having the sendfile
18947c478bd9Sstevel@tonic-gate  * thread create another thread that reads from the filesystem
18957c478bd9Sstevel@tonic-gate  * and queues it for network processing. In this scheme, the data
18967c478bd9Sstevel@tonic-gate  * is never copied anywhere i.e it is zero copy unlike the other
18977c478bd9Sstevel@tonic-gate  * scheme.
18987c478bd9Sstevel@tonic-gate  *
18997c478bd9Sstevel@tonic-gate  * We have a sendfile queue (snfq) where each sendfile
19007c478bd9Sstevel@tonic-gate  * request (snf_req_t) is queued for processing by a thread. Number
19017c478bd9Sstevel@tonic-gate  * of threads is dynamically allocated and they exit if they are idling
19027c478bd9Sstevel@tonic-gate  * beyond a specified amount of time. When each request (snf_req_t) is
19037c478bd9Sstevel@tonic-gate  * processed by a thread, it produces a number of mblk_t structures to
19047c478bd9Sstevel@tonic-gate  * be consumed by the sendfile thread. snf_deque and snf_enque are
19057c478bd9Sstevel@tonic-gate  * used for consuming and producing mblks. Size of the filesystem
1906da6c28aaSamw  * read is determined by the tunable (sendfile_read_size). A single
19077c478bd9Sstevel@tonic-gate  * mblk holds sendfile_read_size worth of data (except the last
19087c478bd9Sstevel@tonic-gate  * read of the file) which is sent down as a whole to the network.
19097c478bd9Sstevel@tonic-gate  * sendfile_read_size is set to 1 MB as this seems to be the optimal
19107c478bd9Sstevel@tonic-gate  * value for the UFS filesystem backed by a striped storage array.
19117c478bd9Sstevel@tonic-gate  *
19127c478bd9Sstevel@tonic-gate  * Synchronisation between read (producer) and write (consumer) threads.
19137c478bd9Sstevel@tonic-gate  * --------------------------------------------------------------------
19147c478bd9Sstevel@tonic-gate  *
19157c478bd9Sstevel@tonic-gate  * sr_lock protects sr_ib_head and sr_ib_tail. The lock is held while
19167c478bd9Sstevel@tonic-gate  * adding and deleting items in this list. Error can happen anytime
19177c478bd9Sstevel@tonic-gate  * during read or write. There could be unprocessed mblks in the
19187c478bd9Sstevel@tonic-gate  * sr_ib_XXX list when a read or write error occurs. Whenever error
19197c478bd9Sstevel@tonic-gate  * is encountered, we need two things to happen :
19207c478bd9Sstevel@tonic-gate  *
19217c478bd9Sstevel@tonic-gate  * a) One of the threads need to clean the mblks.
19227c478bd9Sstevel@tonic-gate  * b) When one thread encounters an error, the other should stop.
19237c478bd9Sstevel@tonic-gate  *
1924da6c28aaSamw  * For (a), we don't want to penalize the reader thread as it could do
19257c478bd9Sstevel@tonic-gate  * some useful work processing other requests. For (b), the error can
19267c478bd9Sstevel@tonic-gate  * be detected by examining sr_read_error or sr_write_error.
19277c478bd9Sstevel@tonic-gate  * sr_lock protects sr_read_error and sr_write_error. If both reader and
19287c478bd9Sstevel@tonic-gate  * writer encounters error, we need to report the write error back to
19297c478bd9Sstevel@tonic-gate  * the application as that's what would have happened if the operations
19307c478bd9Sstevel@tonic-gate  * were done sequentially. With this in mind, following should work :
19317c478bd9Sstevel@tonic-gate  *
19327c478bd9Sstevel@tonic-gate  *	- Check for errors before read or write.
19337c478bd9Sstevel@tonic-gate  *	- If the reader encounters error, set the error in sr_read_error.
19347c478bd9Sstevel@tonic-gate  *	  Check sr_write_error, if it is set, send cv_signal as it is
19357c478bd9Sstevel@tonic-gate  *	  waiting for reader to complete. If it is not set, the writer
19367c478bd9Sstevel@tonic-gate  *	  is either running sinking data to the network or blocked
19377c478bd9Sstevel@tonic-gate  *        because of flow control. For handling the latter case, we
19387c478bd9Sstevel@tonic-gate  *	  always send a signal. In any case, it will examine sr_read_error
19397c478bd9Sstevel@tonic-gate  *	  and return. sr_read_error is marked with SR_READ_DONE to tell
19407c478bd9Sstevel@tonic-gate  *	  the writer that the reader is done in all the cases.
19417c478bd9Sstevel@tonic-gate  *	- If the writer encounters error, set the error in sr_write_error.
19427c478bd9Sstevel@tonic-gate  *	  The reader thread is either blocked because of flow control or
19437c478bd9Sstevel@tonic-gate  *	  running reading data from the disk. For the former, we need to
19447c478bd9Sstevel@tonic-gate  *	  wakeup the thread. Again to keep it simple, we always wake up
19457c478bd9Sstevel@tonic-gate  *	  the reader thread. Then, wait for the read thread to complete
19467c478bd9Sstevel@tonic-gate  *	  if it is not done yet. Cleanup and return.
19477c478bd9Sstevel@tonic-gate  *
19487c478bd9Sstevel@tonic-gate  * High and low water marks for the read thread.
19497c478bd9Sstevel@tonic-gate  * --------------------------------------------
19507c478bd9Sstevel@tonic-gate  *
19517c478bd9Sstevel@tonic-gate  * If sendfile() is used to send data over a slow network, we need to
19527c478bd9Sstevel@tonic-gate  * make sure that the read thread does not produce data at a faster
19537c478bd9Sstevel@tonic-gate  * rate than the network. This can happen if the disk is faster than
19547c478bd9Sstevel@tonic-gate  * the network. In such a case, we don't want to build a very large queue.
19557c478bd9Sstevel@tonic-gate  * But we would still like to get all of the network throughput possible.
19567c478bd9Sstevel@tonic-gate  * This implies that network should never block waiting for data.
19577c478bd9Sstevel@tonic-gate  * As there are lot of disk throughput/network throughput combinations
19587c478bd9Sstevel@tonic-gate  * possible, it is difficult to come up with an accurate number.
19597c478bd9Sstevel@tonic-gate  * A typical 10K RPM disk has a max seek latency 17ms and rotational
19607c478bd9Sstevel@tonic-gate  * latency of 3ms for reading a disk block. Thus, the total latency to
19617c478bd9Sstevel@tonic-gate  * initiate a new read, transfer data from the disk and queue for
19627c478bd9Sstevel@tonic-gate  * transmission would take about a max of 25ms. Todays max transfer rate
19637c478bd9Sstevel@tonic-gate  * for network is 100MB/sec. If the thread is blocked because of flow
19647c478bd9Sstevel@tonic-gate  * control, it would take 25ms to get new data ready for transmission.
19657c478bd9Sstevel@tonic-gate  * We have to make sure that network is not idling, while we are initiating
19667c478bd9Sstevel@tonic-gate  * new transfers. So, at 100MB/sec, to keep network busy we would need
1967da6c28aaSamw  * 2.5MB of data. Rounding off, we keep the low water mark to be 3MB of data.
19687c478bd9Sstevel@tonic-gate  * We need to pick a high water mark so that the woken up thread would
19697c478bd9Sstevel@tonic-gate  * do considerable work before blocking again to prevent thrashing. Currently,
19707c478bd9Sstevel@tonic-gate  * we pick this to be 10 times that of the low water mark.
19717c478bd9Sstevel@tonic-gate  *
19727c478bd9Sstevel@tonic-gate  * Sendfile with segmap caching (One copy from page cache to mblks).
19737c478bd9Sstevel@tonic-gate  * ----------------------------------------------------------------
19747c478bd9Sstevel@tonic-gate  *
19757c478bd9Sstevel@tonic-gate  * We use the segmap cache for caching the file, if the size of file
19767c478bd9Sstevel@tonic-gate  * is <= sendfile_max_size. In this case we don't use threads as VM
19777c478bd9Sstevel@tonic-gate  * is reasonably fast enough to keep up with the network. If the underlying
19787c478bd9Sstevel@tonic-gate  * transport allows, we call segmap_getmapflt() to map MAXBSIZE (8K) worth
19797c478bd9Sstevel@tonic-gate  * of data into segmap space, and use the virtual address from segmap
19807c478bd9Sstevel@tonic-gate  * directly through desballoc() to avoid copy. Once the transport is done
19817c478bd9Sstevel@tonic-gate  * with the data, the mapping will be released through segmap_release()
19827c478bd9Sstevel@tonic-gate  * called by the call-back routine.
19837c478bd9Sstevel@tonic-gate  *
19847c478bd9Sstevel@tonic-gate  * If zero-copy is not allowed by the transport, we simply call VOP_READ()
19857c478bd9Sstevel@tonic-gate  * to copy the data from the filesystem into our temporary network buffer.
19867c478bd9Sstevel@tonic-gate  *
19877c478bd9Sstevel@tonic-gate  * To disable caching, set sendfile_max_size to 0.
19887c478bd9Sstevel@tonic-gate  */
19897c478bd9Sstevel@tonic-gate 
19907c478bd9Sstevel@tonic-gate uint_t sendfile_read_size = 1024 * 1024;
19917c478bd9Sstevel@tonic-gate #define	SENDFILE_REQ_LOWAT	3 * 1024 * 1024
19927c478bd9Sstevel@tonic-gate uint_t sendfile_req_lowat = SENDFILE_REQ_LOWAT;
19937c478bd9Sstevel@tonic-gate uint_t sendfile_req_hiwat = 10 * SENDFILE_REQ_LOWAT;
19947c478bd9Sstevel@tonic-gate struct sendfile_stats sf_stats;
19957c478bd9Sstevel@tonic-gate struct sendfile_queue *snfq;
19967c478bd9Sstevel@tonic-gate clock_t snfq_timeout;
19977c478bd9Sstevel@tonic-gate off64_t sendfile_max_size;
19987c478bd9Sstevel@tonic-gate 
19997c478bd9Sstevel@tonic-gate static void snf_enque(snf_req_t *, mblk_t *);
20007c478bd9Sstevel@tonic-gate static mblk_t *snf_deque(snf_req_t *);
20017c478bd9Sstevel@tonic-gate 
20027c478bd9Sstevel@tonic-gate void
20037c478bd9Sstevel@tonic-gate sendfile_init(void)
20047c478bd9Sstevel@tonic-gate {
20057c478bd9Sstevel@tonic-gate 	snfq = kmem_zalloc(sizeof (struct sendfile_queue), KM_SLEEP);
20067c478bd9Sstevel@tonic-gate 
20077c478bd9Sstevel@tonic-gate 	mutex_init(&snfq->snfq_lock, NULL, MUTEX_DEFAULT, NULL);
20087c478bd9Sstevel@tonic-gate 	cv_init(&snfq->snfq_cv, NULL, CV_DEFAULT, NULL);
20097c478bd9Sstevel@tonic-gate 	snfq->snfq_max_threads = max_ncpus;
20107c478bd9Sstevel@tonic-gate 	snfq_timeout = SNFQ_TIMEOUT;
20117c478bd9Sstevel@tonic-gate 	/* Cache all files by default. */
20127c478bd9Sstevel@tonic-gate 	sendfile_max_size = MAXOFFSET_T;
20137c478bd9Sstevel@tonic-gate }
20147c478bd9Sstevel@tonic-gate 
20157c478bd9Sstevel@tonic-gate /*
20167c478bd9Sstevel@tonic-gate  * Queues a mblk_t for network processing.
20177c478bd9Sstevel@tonic-gate  */
20187c478bd9Sstevel@tonic-gate static void
20197c478bd9Sstevel@tonic-gate snf_enque(snf_req_t *sr, mblk_t *mp)
20207c478bd9Sstevel@tonic-gate {
20217c478bd9Sstevel@tonic-gate 	mp->b_next = NULL;
20227c478bd9Sstevel@tonic-gate 	mutex_enter(&sr->sr_lock);
20237c478bd9Sstevel@tonic-gate 	if (sr->sr_mp_head == NULL) {
20247c478bd9Sstevel@tonic-gate 		sr->sr_mp_head = sr->sr_mp_tail = mp;
20257c478bd9Sstevel@tonic-gate 		cv_signal(&sr->sr_cv);
20267c478bd9Sstevel@tonic-gate 	} else {
20277c478bd9Sstevel@tonic-gate 		sr->sr_mp_tail->b_next = mp;
20287c478bd9Sstevel@tonic-gate 		sr->sr_mp_tail = mp;
20297c478bd9Sstevel@tonic-gate 	}
20307c478bd9Sstevel@tonic-gate 	sr->sr_qlen += MBLKL(mp);
20317c478bd9Sstevel@tonic-gate 	while ((sr->sr_qlen > sr->sr_hiwat) &&
20327c478bd9Sstevel@tonic-gate 	    (sr->sr_write_error == 0)) {
20337c478bd9Sstevel@tonic-gate 		sf_stats.ss_full_waits++;
20347c478bd9Sstevel@tonic-gate 		cv_wait(&sr->sr_cv, &sr->sr_lock);
20357c478bd9Sstevel@tonic-gate 	}
20367c478bd9Sstevel@tonic-gate 	mutex_exit(&sr->sr_lock);
20377c478bd9Sstevel@tonic-gate }
20387c478bd9Sstevel@tonic-gate 
20397c478bd9Sstevel@tonic-gate /*
20407c478bd9Sstevel@tonic-gate  * De-queues a mblk_t for network processing.
20417c478bd9Sstevel@tonic-gate  */
20427c478bd9Sstevel@tonic-gate static mblk_t *
20437c478bd9Sstevel@tonic-gate snf_deque(snf_req_t *sr)
20447c478bd9Sstevel@tonic-gate {
20457c478bd9Sstevel@tonic-gate 	mblk_t *mp;
20467c478bd9Sstevel@tonic-gate 
20477c478bd9Sstevel@tonic-gate 	mutex_enter(&sr->sr_lock);
20487c478bd9Sstevel@tonic-gate 	/*
20497c478bd9Sstevel@tonic-gate 	 * If we have encountered an error on read or read is
20507c478bd9Sstevel@tonic-gate 	 * completed and no more mblks, return NULL.
20517c478bd9Sstevel@tonic-gate 	 * We need to check for NULL sr_mp_head also as
20527c478bd9Sstevel@tonic-gate 	 * the reads could have completed and there is
20537c478bd9Sstevel@tonic-gate 	 * nothing more to come.
20547c478bd9Sstevel@tonic-gate 	 */
20557c478bd9Sstevel@tonic-gate 	if (((sr->sr_read_error & ~SR_READ_DONE) != 0) ||
20567c478bd9Sstevel@tonic-gate 	    ((sr->sr_read_error & SR_READ_DONE) &&
20577c478bd9Sstevel@tonic-gate 	    sr->sr_mp_head == NULL)) {
20587c478bd9Sstevel@tonic-gate 		mutex_exit(&sr->sr_lock);
20597c478bd9Sstevel@tonic-gate 		return (NULL);
20607c478bd9Sstevel@tonic-gate 	}
20617c478bd9Sstevel@tonic-gate 	/*
20627c478bd9Sstevel@tonic-gate 	 * To start with neither SR_READ_DONE is marked nor
20637c478bd9Sstevel@tonic-gate 	 * the error is set. When we wake up from cv_wait,
20647c478bd9Sstevel@tonic-gate 	 * following are the possibilities :
20657c478bd9Sstevel@tonic-gate 	 *
20667c478bd9Sstevel@tonic-gate 	 *	a) sr_read_error is zero and mblks are queued.
20677c478bd9Sstevel@tonic-gate 	 *	b) sr_read_error is set to SR_READ_DONE
20687c478bd9Sstevel@tonic-gate 	 *	   and mblks are queued.
20697c478bd9Sstevel@tonic-gate 	 *	c) sr_read_error is set to SR_READ_DONE
20707c478bd9Sstevel@tonic-gate 	 *	   and no mblks.
20717c478bd9Sstevel@tonic-gate 	 *	d) sr_read_error is set to some error other
20727c478bd9Sstevel@tonic-gate 	 *	   than SR_READ_DONE.
20737c478bd9Sstevel@tonic-gate 	 */
20747c478bd9Sstevel@tonic-gate 
20757c478bd9Sstevel@tonic-gate 	while ((sr->sr_read_error == 0) && (sr->sr_mp_head == NULL)) {
20767c478bd9Sstevel@tonic-gate 		sf_stats.ss_empty_waits++;
20777c478bd9Sstevel@tonic-gate 		cv_wait(&sr->sr_cv, &sr->sr_lock);
20787c478bd9Sstevel@tonic-gate 	}
20797c478bd9Sstevel@tonic-gate 	/* Handle (a) and (b) first  - the normal case. */
20807c478bd9Sstevel@tonic-gate 	if (((sr->sr_read_error & ~SR_READ_DONE) == 0) &&
20817c478bd9Sstevel@tonic-gate 	    (sr->sr_mp_head != NULL)) {
20827c478bd9Sstevel@tonic-gate 		mp = sr->sr_mp_head;
20837c478bd9Sstevel@tonic-gate 		sr->sr_mp_head = mp->b_next;
20847c478bd9Sstevel@tonic-gate 		sr->sr_qlen -= MBLKL(mp);
20857c478bd9Sstevel@tonic-gate 		if (sr->sr_qlen < sr->sr_lowat)
20867c478bd9Sstevel@tonic-gate 			cv_signal(&sr->sr_cv);
20877c478bd9Sstevel@tonic-gate 		mutex_exit(&sr->sr_lock);
20887c478bd9Sstevel@tonic-gate 		mp->b_next = NULL;
20897c478bd9Sstevel@tonic-gate 		return (mp);
20907c478bd9Sstevel@tonic-gate 	}
20917c478bd9Sstevel@tonic-gate 	/* Handle (c) and (d). */
20927c478bd9Sstevel@tonic-gate 	mutex_exit(&sr->sr_lock);
20937c478bd9Sstevel@tonic-gate 	return (NULL);
20947c478bd9Sstevel@tonic-gate }
20957c478bd9Sstevel@tonic-gate 
20967c478bd9Sstevel@tonic-gate /*
20977c478bd9Sstevel@tonic-gate  * Reads data from the filesystem and queues it for network processing.
20987c478bd9Sstevel@tonic-gate  */
20997c478bd9Sstevel@tonic-gate void
21007c478bd9Sstevel@tonic-gate snf_async_read(snf_req_t *sr)
21017c478bd9Sstevel@tonic-gate {
21027c478bd9Sstevel@tonic-gate 	size_t iosize;
21037c478bd9Sstevel@tonic-gate 	u_offset_t fileoff;
21047c478bd9Sstevel@tonic-gate 	u_offset_t size;
21057c478bd9Sstevel@tonic-gate 	int ret_size;
21067c478bd9Sstevel@tonic-gate 	int error;
21077c478bd9Sstevel@tonic-gate 	file_t *fp;
21087c478bd9Sstevel@tonic-gate 	mblk_t *mp;
2109b273e065Skrishna 	struct vnode *vp;
2110b273e065Skrishna 	int extra = 0;
2111e116a42fSPrakash Jalan 	int maxblk = 0;
2112e116a42fSPrakash Jalan 	int wroff = 0;
2113e116a42fSPrakash Jalan 	struct sonode *so;
21147c478bd9Sstevel@tonic-gate 
21157c478bd9Sstevel@tonic-gate 	fp = sr->sr_fp;
21167c478bd9Sstevel@tonic-gate 	size = sr->sr_file_size;
21177c478bd9Sstevel@tonic-gate 	fileoff = sr->sr_file_off;
21187c478bd9Sstevel@tonic-gate 
21197c478bd9Sstevel@tonic-gate 	/*
21207c478bd9Sstevel@tonic-gate 	 * Ignore the error for filesystems that doesn't support DIRECTIO.
21217c478bd9Sstevel@tonic-gate 	 */
21227c478bd9Sstevel@tonic-gate 	(void) VOP_IOCTL(fp->f_vnode, _FIODIRECTIO, DIRECTIO_ON, 0,
2123da6c28aaSamw 	    kcred, NULL, NULL);
21247c478bd9Sstevel@tonic-gate 
2125e116a42fSPrakash Jalan 	vp = sr->sr_vp;
2126b273e065Skrishna 	if (vp->v_type == VSOCK) {
2127b273e065Skrishna 		stdata_t *stp;
2128b273e065Skrishna 
2129b273e065Skrishna 		/*
2130b273e065Skrishna 		 * Get the extra space to insert a header and a trailer.
2131b273e065Skrishna 		 */
2132e116a42fSPrakash Jalan 		so = VTOSO(vp);
2133b273e065Skrishna 		stp = vp->v_stream;
21340f1702c5SYu Xiangning 		if (stp == NULL) {
21350f1702c5SYu Xiangning 			wroff = so->so_proto_props.sopp_wroff;
21360f1702c5SYu Xiangning 			maxblk = so->so_proto_props.sopp_maxblk;
21370f1702c5SYu Xiangning 			extra = wroff + so->so_proto_props.sopp_tail;
21380f1702c5SYu Xiangning 		} else {
2139e116a42fSPrakash Jalan 			wroff = (int)(stp->sd_wroff);
2140e116a42fSPrakash Jalan 			maxblk = (int)(stp->sd_maxblk);
2141e116a42fSPrakash Jalan 			extra = wroff + (int)(stp->sd_tail);
2142b273e065Skrishna 		}
21430f1702c5SYu Xiangning 	}
2144b273e065Skrishna 
21457c478bd9Sstevel@tonic-gate 	while ((size != 0) && (sr->sr_write_error == 0)) {
21467c478bd9Sstevel@tonic-gate 
21477c478bd9Sstevel@tonic-gate 		iosize = (int)MIN(sr->sr_maxpsz, size);
21487c478bd9Sstevel@tonic-gate 
2149e116a42fSPrakash Jalan 		/*
21503e95bd4aSAnders Persson 		 * Socket filters can limit the mblk size,
21513e95bd4aSAnders Persson 		 * so limit reads to maxblk if there are
21523e95bd4aSAnders Persson 		 * filters present.
2153e116a42fSPrakash Jalan 		 */
21543e95bd4aSAnders Persson 		if (vp->v_type == VSOCK &&
2155dd49f125SAnders Persson 		    so->so_filter_active > 0 && maxblk != INFPSZ)
2156e116a42fSPrakash Jalan 			iosize = (int)MIN(iosize, maxblk);
2157e116a42fSPrakash Jalan 
2158de8c4a14SErik Nordmark 		if (is_system_labeled()) {
2159de8c4a14SErik Nordmark 			mp = allocb_cred(iosize + extra, CRED(),
2160de8c4a14SErik Nordmark 			    curproc->p_pid);
2161de8c4a14SErik Nordmark 		} else {
2162de8c4a14SErik Nordmark 			mp = allocb(iosize + extra, BPRI_MED);
2163de8c4a14SErik Nordmark 		}
2164de8c4a14SErik Nordmark 		if (mp == NULL) {
21657c478bd9Sstevel@tonic-gate 			error = EAGAIN;
21667c478bd9Sstevel@tonic-gate 			break;
21677c478bd9Sstevel@tonic-gate 		}
2168e116a42fSPrakash Jalan 
2169e116a42fSPrakash Jalan 		mp->b_rptr += wroff;
2170e116a42fSPrakash Jalan 
21717c478bd9Sstevel@tonic-gate 		ret_size = soreadfile(fp, mp->b_rptr, fileoff, &error, iosize);
21727c478bd9Sstevel@tonic-gate 
21737c478bd9Sstevel@tonic-gate 		/* Error or Reached EOF ? */
21747c478bd9Sstevel@tonic-gate 		if ((error != 0) || (ret_size == 0)) {
21757c478bd9Sstevel@tonic-gate 			freeb(mp);
21767c478bd9Sstevel@tonic-gate 			break;
21777c478bd9Sstevel@tonic-gate 		}
21787c478bd9Sstevel@tonic-gate 		mp->b_wptr = mp->b_rptr + ret_size;
21797c478bd9Sstevel@tonic-gate 
21807c478bd9Sstevel@tonic-gate 		snf_enque(sr, mp);
21817c478bd9Sstevel@tonic-gate 		size -= ret_size;
21827c478bd9Sstevel@tonic-gate 		fileoff += ret_size;
21837c478bd9Sstevel@tonic-gate 	}
21847c478bd9Sstevel@tonic-gate 	(void) VOP_IOCTL(fp->f_vnode, _FIODIRECTIO, DIRECTIO_OFF, 0,
2185da6c28aaSamw 	    kcred, NULL, NULL);
21867c478bd9Sstevel@tonic-gate 	mutex_enter(&sr->sr_lock);
21877c478bd9Sstevel@tonic-gate 	sr->sr_read_error = error;
21887c478bd9Sstevel@tonic-gate 	sr->sr_read_error |= SR_READ_DONE;
21897c478bd9Sstevel@tonic-gate 	cv_signal(&sr->sr_cv);
21907c478bd9Sstevel@tonic-gate 	mutex_exit(&sr->sr_lock);
21917c478bd9Sstevel@tonic-gate }
21927c478bd9Sstevel@tonic-gate 
21937c478bd9Sstevel@tonic-gate void
21947c478bd9Sstevel@tonic-gate snf_async_thread(void)
21957c478bd9Sstevel@tonic-gate {
21967c478bd9Sstevel@tonic-gate 	snf_req_t *sr;
21977c478bd9Sstevel@tonic-gate 	callb_cpr_t cprinfo;
21987c478bd9Sstevel@tonic-gate 	clock_t time_left = 1;
21997c478bd9Sstevel@tonic-gate 
22007c478bd9Sstevel@tonic-gate 	CALLB_CPR_INIT(&cprinfo, &snfq->snfq_lock, callb_generic_cpr, "snfq");
22017c478bd9Sstevel@tonic-gate 
22027c478bd9Sstevel@tonic-gate 	mutex_enter(&snfq->snfq_lock);
22037c478bd9Sstevel@tonic-gate 	for (;;) {
22047c478bd9Sstevel@tonic-gate 		/*
22057c478bd9Sstevel@tonic-gate 		 * If we didn't find a entry, then block until woken up
22067c478bd9Sstevel@tonic-gate 		 * again and then look through the queues again.
22077c478bd9Sstevel@tonic-gate 		 */
22087c478bd9Sstevel@tonic-gate 		while ((sr = snfq->snfq_req_head) == NULL) {
22097c478bd9Sstevel@tonic-gate 			CALLB_CPR_SAFE_BEGIN(&cprinfo);
22107c478bd9Sstevel@tonic-gate 			if (time_left <= 0) {
22117c478bd9Sstevel@tonic-gate 				snfq->snfq_svc_threads--;
22127c478bd9Sstevel@tonic-gate 				CALLB_CPR_EXIT(&cprinfo);
22137c478bd9Sstevel@tonic-gate 				thread_exit();
22147c478bd9Sstevel@tonic-gate 				/* NOTREACHED */
22157c478bd9Sstevel@tonic-gate 			}
22167c478bd9Sstevel@tonic-gate 			snfq->snfq_idle_cnt++;
22177c478bd9Sstevel@tonic-gate 
2218d3d50737SRafael Vanoni 			time_left = cv_reltimedwait(&snfq->snfq_cv,
2219d3d50737SRafael Vanoni 			    &snfq->snfq_lock, snfq_timeout, TR_CLOCK_TICK);
22207c478bd9Sstevel@tonic-gate 			snfq->snfq_idle_cnt--;
22217c478bd9Sstevel@tonic-gate 
22227c478bd9Sstevel@tonic-gate 			CALLB_CPR_SAFE_END(&cprinfo, &snfq->snfq_lock);
22237c478bd9Sstevel@tonic-gate 		}
22247c478bd9Sstevel@tonic-gate 		snfq->snfq_req_head = sr->sr_next;
22257c478bd9Sstevel@tonic-gate 		snfq->snfq_req_cnt--;
22267c478bd9Sstevel@tonic-gate 		mutex_exit(&snfq->snfq_lock);
22277c478bd9Sstevel@tonic-gate 		snf_async_read(sr);
22287c478bd9Sstevel@tonic-gate 		mutex_enter(&snfq->snfq_lock);
22297c478bd9Sstevel@tonic-gate 	}
22307c478bd9Sstevel@tonic-gate }
22317c478bd9Sstevel@tonic-gate 
22327c478bd9Sstevel@tonic-gate 
22337c478bd9Sstevel@tonic-gate snf_req_t *
22347c478bd9Sstevel@tonic-gate create_thread(int operation, struct vnode *vp, file_t *fp,
22357c478bd9Sstevel@tonic-gate     u_offset_t fileoff, u_offset_t size)
22367c478bd9Sstevel@tonic-gate {
22377c478bd9Sstevel@tonic-gate 	snf_req_t *sr;
22387c478bd9Sstevel@tonic-gate 	stdata_t *stp;
22397c478bd9Sstevel@tonic-gate 
22407c478bd9Sstevel@tonic-gate 	sr = (snf_req_t *)kmem_zalloc(sizeof (snf_req_t), KM_SLEEP);
22417c478bd9Sstevel@tonic-gate 
22427c478bd9Sstevel@tonic-gate 	sr->sr_vp = vp;
22437c478bd9Sstevel@tonic-gate 	sr->sr_fp = fp;
22447c478bd9Sstevel@tonic-gate 	stp = vp->v_stream;
22457c478bd9Sstevel@tonic-gate 
22467c478bd9Sstevel@tonic-gate 	/*
22477c478bd9Sstevel@tonic-gate 	 * store sd_qn_maxpsz into sr_maxpsz while we have stream head.
22487c478bd9Sstevel@tonic-gate 	 * stream might be closed before thread returns from snf_async_read.
22497c478bd9Sstevel@tonic-gate 	 */
22500f1702c5SYu Xiangning 	if (stp != NULL && stp->sd_qn_maxpsz > 0) {
22517c478bd9Sstevel@tonic-gate 		sr->sr_maxpsz = MIN(MAXBSIZE, stp->sd_qn_maxpsz);
22527c478bd9Sstevel@tonic-gate 	} else {
22537c478bd9Sstevel@tonic-gate 		sr->sr_maxpsz = MAXBSIZE;
22547c478bd9Sstevel@tonic-gate 	}
22557c478bd9Sstevel@tonic-gate 
22567c478bd9Sstevel@tonic-gate 	sr->sr_operation = operation;
22577c478bd9Sstevel@tonic-gate 	sr->sr_file_off = fileoff;
22587c478bd9Sstevel@tonic-gate 	sr->sr_file_size = size;
22597c478bd9Sstevel@tonic-gate 	sr->sr_hiwat = sendfile_req_hiwat;
22607c478bd9Sstevel@tonic-gate 	sr->sr_lowat = sendfile_req_lowat;
22617c478bd9Sstevel@tonic-gate 	mutex_init(&sr->sr_lock, NULL, MUTEX_DEFAULT, NULL);
22627c478bd9Sstevel@tonic-gate 	cv_init(&sr->sr_cv, NULL, CV_DEFAULT, NULL);
22637c478bd9Sstevel@tonic-gate 	/*
22647c478bd9Sstevel@tonic-gate 	 * See whether we need another thread for servicing this
22657c478bd9Sstevel@tonic-gate 	 * request. If there are already enough requests queued
22667c478bd9Sstevel@tonic-gate 	 * for the threads, create one if not exceeding
22677c478bd9Sstevel@tonic-gate 	 * snfq_max_threads.
22687c478bd9Sstevel@tonic-gate 	 */
22697c478bd9Sstevel@tonic-gate 	mutex_enter(&snfq->snfq_lock);
22707c478bd9Sstevel@tonic-gate 	if (snfq->snfq_req_cnt >= snfq->snfq_idle_cnt &&
22717c478bd9Sstevel@tonic-gate 	    snfq->snfq_svc_threads < snfq->snfq_max_threads) {
22727c478bd9Sstevel@tonic-gate 		(void) thread_create(NULL, 0, &snf_async_thread, 0, 0, &p0,
22737c478bd9Sstevel@tonic-gate 		    TS_RUN, minclsyspri);
22747c478bd9Sstevel@tonic-gate 		snfq->snfq_svc_threads++;
22757c478bd9Sstevel@tonic-gate 	}
22767c478bd9Sstevel@tonic-gate 	if (snfq->snfq_req_head == NULL) {
22777c478bd9Sstevel@tonic-gate 		snfq->snfq_req_head = snfq->snfq_req_tail = sr;
22787c478bd9Sstevel@tonic-gate 		cv_signal(&snfq->snfq_cv);
22797c478bd9Sstevel@tonic-gate 	} else {
22807c478bd9Sstevel@tonic-gate 		snfq->snfq_req_tail->sr_next = sr;
22817c478bd9Sstevel@tonic-gate 		snfq->snfq_req_tail = sr;
22827c478bd9Sstevel@tonic-gate 	}
22837c478bd9Sstevel@tonic-gate 	snfq->snfq_req_cnt++;
22847c478bd9Sstevel@tonic-gate 	mutex_exit(&snfq->snfq_lock);
22857c478bd9Sstevel@tonic-gate 	return (sr);
22867c478bd9Sstevel@tonic-gate }
22877c478bd9Sstevel@tonic-gate 
22887c478bd9Sstevel@tonic-gate int
22897c478bd9Sstevel@tonic-gate snf_direct_io(file_t *fp, file_t *rfp, u_offset_t fileoff, u_offset_t size,
22907c478bd9Sstevel@tonic-gate     ssize_t *count)
22917c478bd9Sstevel@tonic-gate {
22927c478bd9Sstevel@tonic-gate 	snf_req_t *sr;
22937c478bd9Sstevel@tonic-gate 	mblk_t *mp;
22947c478bd9Sstevel@tonic-gate 	int iosize;
22957c478bd9Sstevel@tonic-gate 	int error = 0;
22967c478bd9Sstevel@tonic-gate 	short fflag;
22977c478bd9Sstevel@tonic-gate 	struct vnode *vp;
22987c478bd9Sstevel@tonic-gate 	int ksize;
22990f1702c5SYu Xiangning 	struct nmsghdr msg;
23007c478bd9Sstevel@tonic-gate 
23017c478bd9Sstevel@tonic-gate 	ksize = 0;
23027c478bd9Sstevel@tonic-gate 	*count = 0;
23030f1702c5SYu Xiangning 	bzero(&msg, sizeof (msg));
23047c478bd9Sstevel@tonic-gate 
23057c478bd9Sstevel@tonic-gate 	vp = fp->f_vnode;
23067c478bd9Sstevel@tonic-gate 	fflag = fp->f_flag;
23077c478bd9Sstevel@tonic-gate 	if ((sr = create_thread(READ_OP, vp, rfp, fileoff, size)) == NULL)
23087c478bd9Sstevel@tonic-gate 		return (EAGAIN);
23097c478bd9Sstevel@tonic-gate 
23107c478bd9Sstevel@tonic-gate 	/*
23117c478bd9Sstevel@tonic-gate 	 * We check for read error in snf_deque. It has to check
23127c478bd9Sstevel@tonic-gate 	 * for successful READ_DONE and return NULL, and we might
23137c478bd9Sstevel@tonic-gate 	 * as well make an additional check there.
23147c478bd9Sstevel@tonic-gate 	 */
23157c478bd9Sstevel@tonic-gate 	while ((mp = snf_deque(sr)) != NULL) {
23167c478bd9Sstevel@tonic-gate 
23177c478bd9Sstevel@tonic-gate 		if (ISSIG(curthread, JUSTLOOKING)) {
23187c478bd9Sstevel@tonic-gate 			freeb(mp);
23197c478bd9Sstevel@tonic-gate 			error = EINTR;
23207c478bd9Sstevel@tonic-gate 			break;
23217c478bd9Sstevel@tonic-gate 		}
23227c478bd9Sstevel@tonic-gate 		iosize = MBLKL(mp);
23237c478bd9Sstevel@tonic-gate 
23240f1702c5SYu Xiangning 		error = socket_sendmblk(VTOSO(vp), &msg, fflag, CRED(), &mp);
23250f1702c5SYu Xiangning 
23260f1702c5SYu Xiangning 		if (error != 0) {
23270f1702c5SYu Xiangning 			if (mp != NULL)
23287c478bd9Sstevel@tonic-gate 				freeb(mp);
23297c478bd9Sstevel@tonic-gate 			break;
23307c478bd9Sstevel@tonic-gate 		}
23317c478bd9Sstevel@tonic-gate 		ksize += iosize;
23327c478bd9Sstevel@tonic-gate 	}
23337c478bd9Sstevel@tonic-gate 	*count = ksize;
23347c478bd9Sstevel@tonic-gate 
23357c478bd9Sstevel@tonic-gate 	mutex_enter(&sr->sr_lock);
23367c478bd9Sstevel@tonic-gate 	sr->sr_write_error = error;
23377c478bd9Sstevel@tonic-gate 	/* Look at the big comments on why we cv_signal here. */
23387c478bd9Sstevel@tonic-gate 	cv_signal(&sr->sr_cv);
23397c478bd9Sstevel@tonic-gate 
23407c478bd9Sstevel@tonic-gate 	/* Wait for the reader to complete always. */
23417c478bd9Sstevel@tonic-gate 	while (!(sr->sr_read_error & SR_READ_DONE)) {
23427c478bd9Sstevel@tonic-gate 		cv_wait(&sr->sr_cv, &sr->sr_lock);
23437c478bd9Sstevel@tonic-gate 	}
23447c478bd9Sstevel@tonic-gate 	/* If there is no write error, check for read error. */
23457c478bd9Sstevel@tonic-gate 	if (error == 0)
23467c478bd9Sstevel@tonic-gate 		error = (sr->sr_read_error & ~SR_READ_DONE);
23477c478bd9Sstevel@tonic-gate 
23487c478bd9Sstevel@tonic-gate 	if (error != 0) {
23497c478bd9Sstevel@tonic-gate 		mblk_t *next_mp;
23507c478bd9Sstevel@tonic-gate 
23517c478bd9Sstevel@tonic-gate 		mp = sr->sr_mp_head;
23527c478bd9Sstevel@tonic-gate 		while (mp != NULL) {
23537c478bd9Sstevel@tonic-gate 			next_mp = mp->b_next;
23547c478bd9Sstevel@tonic-gate 			mp->b_next = NULL;
23557c478bd9Sstevel@tonic-gate 			freeb(mp);
23567c478bd9Sstevel@tonic-gate 			mp = next_mp;
23577c478bd9Sstevel@tonic-gate 		}
23587c478bd9Sstevel@tonic-gate 	}
23597c478bd9Sstevel@tonic-gate 	mutex_exit(&sr->sr_lock);
23607c478bd9Sstevel@tonic-gate 	kmem_free(sr, sizeof (snf_req_t));
23617c478bd9Sstevel@tonic-gate 	return (error);
23627c478bd9Sstevel@tonic-gate }
23637c478bd9Sstevel@tonic-gate 
2364ead83321SVasumathi Sundaram - Sun Microsystems /* Maximum no.of pages allocated by vpm for sendfile at a time */
236531c2c73cSVasumathi Sundaram - Sun Microsystems #define	SNF_VPMMAXPGS	(VPMMAXPGS/2)
2366ead83321SVasumathi Sundaram - Sun Microsystems 
2367ead83321SVasumathi Sundaram - Sun Microsystems /*
2368ead83321SVasumathi Sundaram - Sun Microsystems  * Maximum no.of elements in the list returned by vpm, including
2369ead83321SVasumathi Sundaram - Sun Microsystems  * NULL for the last entry
2370ead83321SVasumathi Sundaram - Sun Microsystems  */
237131c2c73cSVasumathi Sundaram - Sun Microsystems #define	SNF_MAXVMAPS	(SNF_VPMMAXPGS + 1)
237231c2c73cSVasumathi Sundaram - Sun Microsystems 
237331c2c73cSVasumathi Sundaram - Sun Microsystems typedef struct {
2374ead83321SVasumathi Sundaram - Sun Microsystems 	unsigned int	snfv_ref;
237531c2c73cSVasumathi Sundaram - Sun Microsystems 	frtn_t		snfv_frtn;
237631c2c73cSVasumathi Sundaram - Sun Microsystems 	vnode_t		*snfv_vp;
2377ead83321SVasumathi Sundaram - Sun Microsystems 	struct vmap	snfv_vml[SNF_MAXVMAPS];
237831c2c73cSVasumathi Sundaram - Sun Microsystems } snf_vmap_desbinfo;
237931c2c73cSVasumathi Sundaram - Sun Microsystems 
23807c478bd9Sstevel@tonic-gate typedef struct {
23817c478bd9Sstevel@tonic-gate 	frtn_t		snfi_frtn;
23827c478bd9Sstevel@tonic-gate 	caddr_t		snfi_base;
23837c478bd9Sstevel@tonic-gate 	uint_t		snfi_mapoff;
23847c478bd9Sstevel@tonic-gate 	size_t		snfi_len;
23857c478bd9Sstevel@tonic-gate 	vnode_t		*snfi_vp;
23867c478bd9Sstevel@tonic-gate } snf_smap_desbinfo;
23877c478bd9Sstevel@tonic-gate 
2388ead83321SVasumathi Sundaram - Sun Microsystems /*
2389ead83321SVasumathi Sundaram - Sun Microsystems  * The callback function used for vpm mapped mblks called when the last ref of
2390ead83321SVasumathi Sundaram - Sun Microsystems  * the mblk is dropped which normally occurs when TCP receives the ack. But it
2391ead83321SVasumathi Sundaram - Sun Microsystems  * can be the driver too due to lazy reclaim.
2392ead83321SVasumathi Sundaram - Sun Microsystems  */
239331c2c73cSVasumathi Sundaram - Sun Microsystems void
239431c2c73cSVasumathi Sundaram - Sun Microsystems snf_vmap_desbfree(snf_vmap_desbinfo *snfv)
239531c2c73cSVasumathi Sundaram - Sun Microsystems {
2396ead83321SVasumathi Sundaram - Sun Microsystems 	ASSERT(snfv->snfv_ref != 0);
23971a5e258fSJosef 'Jeff' Sipek 	if (atomic_dec_32_nv(&snfv->snfv_ref) == 0) {
2398ead83321SVasumathi Sundaram - Sun Microsystems 		vpm_unmap_pages(snfv->snfv_vml, S_READ);
239931c2c73cSVasumathi Sundaram - Sun Microsystems 		VN_RELE(snfv->snfv_vp);
240031c2c73cSVasumathi Sundaram - Sun Microsystems 		kmem_free(snfv, sizeof (snf_vmap_desbinfo));
240131c2c73cSVasumathi Sundaram - Sun Microsystems 	}
240231c2c73cSVasumathi Sundaram - Sun Microsystems }
240331c2c73cSVasumathi Sundaram - Sun Microsystems 
24047c478bd9Sstevel@tonic-gate /*
2405ead83321SVasumathi Sundaram - Sun Microsystems  * The callback function used for segmap'ped mblks called when the last ref of
2406ead83321SVasumathi Sundaram - Sun Microsystems  * the mblk is dropped which normally occurs when TCP receives the ack. But it
2407ead83321SVasumathi Sundaram - Sun Microsystems  * can be the driver too due to lazy reclaim.
24087c478bd9Sstevel@tonic-gate  */
24097c478bd9Sstevel@tonic-gate void
24107c478bd9Sstevel@tonic-gate snf_smap_desbfree(snf_smap_desbinfo *snfi)
24117c478bd9Sstevel@tonic-gate {
24123b3d24f3SJayakara Kini 	if (! IS_KPM_ADDR(snfi->snfi_base)) {
24137c478bd9Sstevel@tonic-gate 		/*
24147c478bd9Sstevel@tonic-gate 		 * We don't need to call segmap_fault(F_SOFTUNLOCK) for
24157c478bd9Sstevel@tonic-gate 		 * segmap_kpm as long as the latter never falls back to
24167c478bd9Sstevel@tonic-gate 		 * "use_segmap_range". (See segmap_getmapflt().)
24177c478bd9Sstevel@tonic-gate 		 *
24187c478bd9Sstevel@tonic-gate 		 * Using S_OTHER saves an redundant hat_setref() in
24197c478bd9Sstevel@tonic-gate 		 * segmap_unlock()
24207c478bd9Sstevel@tonic-gate 		 */
24217c478bd9Sstevel@tonic-gate 		(void) segmap_fault(kas.a_hat, segkmap,
24221e0267ddSkrgopi 		    (caddr_t)(uintptr_t)(((uintptr_t)snfi->snfi_base +
24231e0267ddSkrgopi 		    snfi->snfi_mapoff) & PAGEMASK), snfi->snfi_len,
24241e0267ddSkrgopi 		    F_SOFTUNLOCK, S_OTHER);
24257c478bd9Sstevel@tonic-gate 	}
24267c478bd9Sstevel@tonic-gate 	(void) segmap_release(segkmap, snfi->snfi_base, SM_DONTNEED);
24277c478bd9Sstevel@tonic-gate 	VN_RELE(snfi->snfi_vp);
24287c478bd9Sstevel@tonic-gate 	kmem_free(snfi, sizeof (*snfi));
24297c478bd9Sstevel@tonic-gate }
24307c478bd9Sstevel@tonic-gate 
24317c478bd9Sstevel@tonic-gate /*
2432ead83321SVasumathi Sundaram - Sun Microsystems  * Use segmap or vpm instead of bcopy to send down a desballoca'ed, mblk.
2433ead83321SVasumathi Sundaram - Sun Microsystems  * When segmap is used, the mblk contains a segmap slot of no more
2434ead83321SVasumathi Sundaram - Sun Microsystems  * than MAXBSIZE.
2435ead83321SVasumathi Sundaram - Sun Microsystems  *
2436ead83321SVasumathi Sundaram - Sun Microsystems  * With vpm, a maximum of SNF_MAXVMAPS page-sized mappings can be obtained
2437ead83321SVasumathi Sundaram - Sun Microsystems  * in each iteration and sent by socket_sendmblk until an error occurs or
2438ead83321SVasumathi Sundaram - Sun Microsystems  * the requested size has been transferred. An mblk is esballoca'ed from
2439ead83321SVasumathi Sundaram - Sun Microsystems  * each mapped page and a chain of these mblk is sent to the transport layer.
2440ead83321SVasumathi Sundaram - Sun Microsystems  * vpm will be called to unmap the pages when all mblks have been freed by
2441ead83321SVasumathi Sundaram - Sun Microsystems  * free_func.
24427c478bd9Sstevel@tonic-gate  *
24437c478bd9Sstevel@tonic-gate  * At the end of the whole sendfile() operation, we wait till the data from
24447c478bd9Sstevel@tonic-gate  * the last mblk is ack'ed by the transport before returning so that the
24457c478bd9Sstevel@tonic-gate  * caller of sendfile() can safely modify the file content.
2446*f50f4621SMarcel Telka  *
2447*f50f4621SMarcel Telka  * The caller of this function should make sure that total_size does not exceed
2448*f50f4621SMarcel Telka  * the actual file size of fvp.
24497c478bd9Sstevel@tonic-gate  */
24507c478bd9Sstevel@tonic-gate int
2451ead83321SVasumathi Sundaram - Sun Microsystems snf_segmap(file_t *fp, vnode_t *fvp, u_offset_t fileoff, u_offset_t total_size,
24523b3d24f3SJayakara Kini     ssize_t *count, boolean_t nowait)
24537c478bd9Sstevel@tonic-gate {
24547c478bd9Sstevel@tonic-gate 	caddr_t base;
24557c478bd9Sstevel@tonic-gate 	int mapoff;
24567c478bd9Sstevel@tonic-gate 	vnode_t *vp;
2457ead83321SVasumathi Sundaram - Sun Microsystems 	mblk_t *mp = NULL;
2458ead83321SVasumathi Sundaram - Sun Microsystems 	int chain_size;
24597c478bd9Sstevel@tonic-gate 	int error;
246093b24f5eSBrian Utterback 	clock_t deadlk_wait;
24617c478bd9Sstevel@tonic-gate 	short fflag;
24627c478bd9Sstevel@tonic-gate 	int ksize;
24637c478bd9Sstevel@tonic-gate 	struct vattr va;
24647c478bd9Sstevel@tonic-gate 	boolean_t dowait = B_FALSE;
24650f1702c5SYu Xiangning 	struct nmsghdr msg;
24667c478bd9Sstevel@tonic-gate 
24677c478bd9Sstevel@tonic-gate 	vp = fp->f_vnode;
24687c478bd9Sstevel@tonic-gate 	fflag = fp->f_flag;
24697c478bd9Sstevel@tonic-gate 	ksize = 0;
24700f1702c5SYu Xiangning 	bzero(&msg, sizeof (msg));
24710f1702c5SYu Xiangning 
24727c478bd9Sstevel@tonic-gate 	for (;;) {
24737c478bd9Sstevel@tonic-gate 		if (ISSIG(curthread, JUSTLOOKING)) {
24747c478bd9Sstevel@tonic-gate 			error = EINTR;
24757c478bd9Sstevel@tonic-gate 			break;
24767c478bd9Sstevel@tonic-gate 		}
24773b3d24f3SJayakara Kini 
2478ead83321SVasumathi Sundaram - Sun Microsystems 		if (vpm_enable) {
2479ead83321SVasumathi Sundaram - Sun Microsystems 			snf_vmap_desbinfo *snfv;
2480ead83321SVasumathi Sundaram - Sun Microsystems 			mblk_t *nmp;
2481ead83321SVasumathi Sundaram - Sun Microsystems 			int mblk_size;
2482ead83321SVasumathi Sundaram - Sun Microsystems 			int maxsize;
2483ead83321SVasumathi Sundaram - Sun Microsystems 			int i;
248431c2c73cSVasumathi Sundaram - Sun Microsystems 
2485ead83321SVasumathi Sundaram - Sun Microsystems 			mapoff = fileoff & PAGEOFFSET;
2486ead83321SVasumathi Sundaram - Sun Microsystems 			maxsize = MIN((SNF_VPMMAXPGS * PAGESIZE), total_size);
2487ead83321SVasumathi Sundaram - Sun Microsystems 
2488ead83321SVasumathi Sundaram - Sun Microsystems 			snfv = kmem_zalloc(sizeof (snf_vmap_desbinfo),
2489ead83321SVasumathi Sundaram - Sun Microsystems 			    KM_SLEEP);
2490ead83321SVasumathi Sundaram - Sun Microsystems 
249193b24f5eSBrian Utterback 			/*
249293b24f5eSBrian Utterback 			 * Get vpm mappings for maxsize with read access.
249393b24f5eSBrian Utterback 			 * If the pages aren't available yet, we get
249493b24f5eSBrian Utterback 			 * DEADLK, so wait and try again a little later using
249593b24f5eSBrian Utterback 			 * an increasing wait. We might be here a long time.
249693b24f5eSBrian Utterback 			 *
249793b24f5eSBrian Utterback 			 * If delay_sig returns EINTR, be sure to exit and
249893b24f5eSBrian Utterback 			 * pass it up to the caller.
249993b24f5eSBrian Utterback 			 */
250093b24f5eSBrian Utterback 			deadlk_wait = 0;
250193b24f5eSBrian Utterback 			while ((error = vpm_map_pages(fvp, fileoff,
250293b24f5eSBrian Utterback 			    (size_t)maxsize, (VPM_FETCHPAGE), snfv->snfv_vml,
250393b24f5eSBrian Utterback 			    SNF_MAXVMAPS, NULL, S_READ)) == EDEADLK) {
250493b24f5eSBrian Utterback 				deadlk_wait += (deadlk_wait < 5) ? 1 : 4;
250593b24f5eSBrian Utterback 				if ((error = delay_sig(deadlk_wait)) != 0) {
250693b24f5eSBrian Utterback 					break;
250793b24f5eSBrian Utterback 				}
250893b24f5eSBrian Utterback 			}
250993b24f5eSBrian Utterback 			if (error != 0) {
251031c2c73cSVasumathi Sundaram - Sun Microsystems 				kmem_free(snfv, sizeof (snf_vmap_desbinfo));
251193b24f5eSBrian Utterback 				error = (error == EINTR) ? EINTR : EIO;
251231c2c73cSVasumathi Sundaram - Sun Microsystems 				goto out;
251331c2c73cSVasumathi Sundaram - Sun Microsystems 			}
251431c2c73cSVasumathi Sundaram - Sun Microsystems 			snfv->snfv_frtn.free_func = snf_vmap_desbfree;
251531c2c73cSVasumathi Sundaram - Sun Microsystems 			snfv->snfv_frtn.free_arg = (caddr_t)snfv;
251631c2c73cSVasumathi Sundaram - Sun Microsystems 
2517ead83321SVasumathi Sundaram - Sun Microsystems 			/* Construct the mblk chain from the page mappings */
2518ead83321SVasumathi Sundaram - Sun Microsystems 			chain_size = 0;
2519ead83321SVasumathi Sundaram - Sun Microsystems 			for (i = 0; (snfv->snfv_vml[i].vs_addr != NULL) &&
2520ead83321SVasumathi Sundaram - Sun Microsystems 			    total_size > 0; i++) {
2521ead83321SVasumathi Sundaram - Sun Microsystems 				ASSERT(chain_size < maxsize);
2522ead83321SVasumathi Sundaram - Sun Microsystems 				mblk_size = MIN(snfv->snfv_vml[i].vs_len -
2523ead83321SVasumathi Sundaram - Sun Microsystems 				    mapoff, total_size);
2524ead83321SVasumathi Sundaram - Sun Microsystems 				nmp = esballoca(
2525ead83321SVasumathi Sundaram - Sun Microsystems 				    (uchar_t *)snfv->snfv_vml[i].vs_addr +
2526ead83321SVasumathi Sundaram - Sun Microsystems 				    mapoff, mblk_size, BPRI_HI,
2527ead83321SVasumathi Sundaram - Sun Microsystems 				    &snfv->snfv_frtn);
2528ead83321SVasumathi Sundaram - Sun Microsystems 
2529ead83321SVasumathi Sundaram - Sun Microsystems 				/*
2530ead83321SVasumathi Sundaram - Sun Microsystems 				 * We return EAGAIN after unmapping the pages
2531ead83321SVasumathi Sundaram - Sun Microsystems 				 * if we cannot allocate the the head of the
2532ead83321SVasumathi Sundaram - Sun Microsystems 				 * chain. Otherwise, we continue sending the
2533ead83321SVasumathi Sundaram - Sun Microsystems 				 * mblks constructed so far.
2534ead83321SVasumathi Sundaram - Sun Microsystems 				 */
2535ead83321SVasumathi Sundaram - Sun Microsystems 				if (nmp == NULL) {
2536ead83321SVasumathi Sundaram - Sun Microsystems 					if (i == 0) {
2537ead83321SVasumathi Sundaram - Sun Microsystems 						vpm_unmap_pages(snfv->snfv_vml,
2538ead83321SVasumathi Sundaram - Sun Microsystems 						    S_READ);
2539ead83321SVasumathi Sundaram - Sun Microsystems 						kmem_free(snfv,
2540ead83321SVasumathi Sundaram - Sun Microsystems 						    sizeof (snf_vmap_desbinfo));
254131c2c73cSVasumathi Sundaram - Sun Microsystems 						error = EAGAIN;
254231c2c73cSVasumathi Sundaram - Sun Microsystems 						goto out;
254331c2c73cSVasumathi Sundaram - Sun Microsystems 					}
2544ead83321SVasumathi Sundaram - Sun Microsystems 					break;
2545ead83321SVasumathi Sundaram - Sun Microsystems 				}
254631c2c73cSVasumathi Sundaram - Sun Microsystems 				/* Mark this dblk with the zero-copy flag */
2547ead83321SVasumathi Sundaram - Sun Microsystems 				nmp->b_datap->db_struioflag |= STRUIO_ZC;
2548ead83321SVasumathi Sundaram - Sun Microsystems 				nmp->b_wptr += mblk_size;
2549ead83321SVasumathi Sundaram - Sun Microsystems 				chain_size += mblk_size;
2550ead83321SVasumathi Sundaram - Sun Microsystems 				fileoff += mblk_size;
2551ead83321SVasumathi Sundaram - Sun Microsystems 				total_size -= mblk_size;
2552ead83321SVasumathi Sundaram - Sun Microsystems 				snfv->snfv_ref++;
2553ead83321SVasumathi Sundaram - Sun Microsystems 				mapoff = 0;
2554ead83321SVasumathi Sundaram - Sun Microsystems 				if (i > 0)
2555ead83321SVasumathi Sundaram - Sun Microsystems 					linkb(mp, nmp);
2556ead83321SVasumathi Sundaram - Sun Microsystems 				else
2557ead83321SVasumathi Sundaram - Sun Microsystems 					mp = nmp;
255831c2c73cSVasumathi Sundaram - Sun Microsystems 			}
255931c2c73cSVasumathi Sundaram - Sun Microsystems 			VN_HOLD(fvp);
256031c2c73cSVasumathi Sundaram - Sun Microsystems 			snfv->snfv_vp = fvp;
256131c2c73cSVasumathi Sundaram - Sun Microsystems 		} else {
256231c2c73cSVasumathi Sundaram - Sun Microsystems 			/* vpm not supported. fallback to segmap */
2563ead83321SVasumathi Sundaram - Sun Microsystems 			snf_smap_desbinfo *snfi;
2564ead83321SVasumathi Sundaram - Sun Microsystems 
25657c478bd9Sstevel@tonic-gate 			mapoff = fileoff & MAXBOFFSET;
2566ead83321SVasumathi Sundaram - Sun Microsystems 			chain_size = MAXBSIZE - mapoff;
2567ead83321SVasumathi Sundaram - Sun Microsystems 			if (chain_size > total_size)
2568ead83321SVasumathi Sundaram - Sun Microsystems 				chain_size = total_size;
25697c478bd9Sstevel@tonic-gate 			/*
25707c478bd9Sstevel@tonic-gate 			 * we don't forcefault because we'll call
25717c478bd9Sstevel@tonic-gate 			 * segmap_fault(F_SOFTLOCK) next.
25727c478bd9Sstevel@tonic-gate 			 *
25737c478bd9Sstevel@tonic-gate 			 * S_READ will get the ref bit set (by either
25747c478bd9Sstevel@tonic-gate 			 * segmap_getmapflt() or segmap_fault()) and page
25757c478bd9Sstevel@tonic-gate 			 * shared locked.
25767c478bd9Sstevel@tonic-gate 			 */
2577ead83321SVasumathi Sundaram - Sun Microsystems 			base = segmap_getmapflt(segkmap, fvp, fileoff,
2578ead83321SVasumathi Sundaram - Sun Microsystems 			    chain_size, segmap_kpm ? SM_FAULT : 0, S_READ);
25797c478bd9Sstevel@tonic-gate 
25807c478bd9Sstevel@tonic-gate 			snfi = kmem_alloc(sizeof (*snfi), KM_SLEEP);
2581ead83321SVasumathi Sundaram - Sun Microsystems 			snfi->snfi_len = (size_t)roundup(mapoff+chain_size,
25827c478bd9Sstevel@tonic-gate 			    PAGESIZE)- (mapoff & PAGEMASK);
25837c478bd9Sstevel@tonic-gate 			/*
25847c478bd9Sstevel@tonic-gate 			 * We must call segmap_fault() even for segmap_kpm
25857c478bd9Sstevel@tonic-gate 			 * because that's how error gets returned.
25867c478bd9Sstevel@tonic-gate 			 * (segmap_getmapflt() never fails but segmap_fault()
25877c478bd9Sstevel@tonic-gate 			 * does.)
258893b24f5eSBrian Utterback 			 *
258993b24f5eSBrian Utterback 			 * If the pages aren't available yet, we get
259093b24f5eSBrian Utterback 			 * DEADLK, so wait and try again a little later using
259193b24f5eSBrian Utterback 			 * an increasing wait. We might be here a long time.
259293b24f5eSBrian Utterback 			 *
259393b24f5eSBrian Utterback 			 * If delay_sig returns EINTR, be sure to exit and
259493b24f5eSBrian Utterback 			 * pass it up to the caller.
25957c478bd9Sstevel@tonic-gate 			 */
259693b24f5eSBrian Utterback 			deadlk_wait = 0;
259793b24f5eSBrian Utterback 			while ((error = FC_ERRNO(segmap_fault(kas.a_hat,
259893b24f5eSBrian Utterback 			    segkmap, (caddr_t)(uintptr_t)(((uintptr_t)base +
259993b24f5eSBrian Utterback 			    mapoff) & PAGEMASK), snfi->snfi_len, F_SOFTLOCK,
260093b24f5eSBrian Utterback 			    S_READ))) == EDEADLK) {
260193b24f5eSBrian Utterback 				deadlk_wait += (deadlk_wait < 5) ? 1 : 4;
260293b24f5eSBrian Utterback 				if ((error = delay_sig(deadlk_wait)) != 0) {
260393b24f5eSBrian Utterback 					break;
260493b24f5eSBrian Utterback 				}
260593b24f5eSBrian Utterback 			}
260693b24f5eSBrian Utterback 			if (error != 0) {
26077c478bd9Sstevel@tonic-gate 				(void) segmap_release(segkmap, base, 0);
26087c478bd9Sstevel@tonic-gate 				kmem_free(snfi, sizeof (*snfi));
260993b24f5eSBrian Utterback 				error = (error == EINTR) ? EINTR : EIO;
26107c478bd9Sstevel@tonic-gate 				goto out;
26117c478bd9Sstevel@tonic-gate 			}
26127c478bd9Sstevel@tonic-gate 			snfi->snfi_frtn.free_func = snf_smap_desbfree;
26137c478bd9Sstevel@tonic-gate 			snfi->snfi_frtn.free_arg = (caddr_t)snfi;
26147c478bd9Sstevel@tonic-gate 			snfi->snfi_base = base;
26157c478bd9Sstevel@tonic-gate 			snfi->snfi_mapoff = mapoff;
2616ead83321SVasumathi Sundaram - Sun Microsystems 			mp = esballoca((uchar_t *)base + mapoff, chain_size,
261731c2c73cSVasumathi Sundaram - Sun Microsystems 			    BPRI_HI, &snfi->snfi_frtn);
26187c478bd9Sstevel@tonic-gate 
26193b3d24f3SJayakara Kini 			if (mp == NULL) {
26207c478bd9Sstevel@tonic-gate 				(void) segmap_fault(kas.a_hat, segkmap,
2621ead83321SVasumathi Sundaram - Sun Microsystems 				    (caddr_t)(uintptr_t)(((uintptr_t)base +
2622ead83321SVasumathi Sundaram - Sun Microsystems 				    mapoff) & PAGEMASK), snfi->snfi_len,
262331c2c73cSVasumathi Sundaram - Sun Microsystems 				    F_SOFTUNLOCK, S_OTHER);
26247c478bd9Sstevel@tonic-gate 				(void) segmap_release(segkmap, base, 0);
26257c478bd9Sstevel@tonic-gate 				kmem_free(snfi, sizeof (*snfi));
26267c478bd9Sstevel@tonic-gate 				freemsg(mp);
26277c478bd9Sstevel@tonic-gate 				error = EAGAIN;
26287c478bd9Sstevel@tonic-gate 				goto out;
26297c478bd9Sstevel@tonic-gate 			}
26307c478bd9Sstevel@tonic-gate 			VN_HOLD(fvp);
26317c478bd9Sstevel@tonic-gate 			snfi->snfi_vp = fvp;
2632ead83321SVasumathi Sundaram - Sun Microsystems 			mp->b_wptr += chain_size;
26337c478bd9Sstevel@tonic-gate 
26347c478bd9Sstevel@tonic-gate 			/* Mark this dblk with the zero-copy flag */
26353b3d24f3SJayakara Kini 			mp->b_datap->db_struioflag |= STRUIO_ZC;
2636ead83321SVasumathi Sundaram - Sun Microsystems 			fileoff += chain_size;
2637ead83321SVasumathi Sundaram - Sun Microsystems 			total_size -= chain_size;
263831c2c73cSVasumathi Sundaram - Sun Microsystems 		}
26397c478bd9Sstevel@tonic-gate 
2640ead83321SVasumathi Sundaram - Sun Microsystems 		if (total_size == 0 && !nowait) {
26417c478bd9Sstevel@tonic-gate 			ASSERT(!dowait);
26427c478bd9Sstevel@tonic-gate 			dowait = B_TRUE;
26433b3d24f3SJayakara Kini 			mp->b_datap->db_struioflag |= STRUIO_ZCNOTIFY;
26447c478bd9Sstevel@tonic-gate 		}
26457c478bd9Sstevel@tonic-gate 		VOP_RWUNLOCK(fvp, V_WRITELOCK_FALSE, NULL);
26460f1702c5SYu Xiangning 		error = socket_sendmblk(VTOSO(vp), &msg, fflag, CRED(), &mp);
26470f1702c5SYu Xiangning 		if (error != 0) {
2648ead83321SVasumathi Sundaram - Sun Microsystems 			/*
2649ead83321SVasumathi Sundaram - Sun Microsystems 			 * mp contains the mblks that were not sent by
2650ead83321SVasumathi Sundaram - Sun Microsystems 			 * socket_sendmblk. Use its size to update *count
2651ead83321SVasumathi Sundaram - Sun Microsystems 			 */
2652ead83321SVasumathi Sundaram - Sun Microsystems 			*count = ksize + (chain_size - msgdsize(mp));
26530f1702c5SYu Xiangning 			if (mp != NULL)
26547c478bd9Sstevel@tonic-gate 				freemsg(mp);
26557c478bd9Sstevel@tonic-gate 			return (error);
26567c478bd9Sstevel@tonic-gate 		}
2657ead83321SVasumathi Sundaram - Sun Microsystems 		ksize += chain_size;
2658ead83321SVasumathi Sundaram - Sun Microsystems 		if (total_size == 0)
26597c478bd9Sstevel@tonic-gate 			goto done;
26607c478bd9Sstevel@tonic-gate 
26617c478bd9Sstevel@tonic-gate 		(void) VOP_RWLOCK(fvp, V_WRITELOCK_FALSE, NULL);
26627c478bd9Sstevel@tonic-gate 		va.va_mask = AT_SIZE;
2663da6c28aaSamw 		error = VOP_GETATTR(fvp, &va, 0, kcred, NULL);
26647c478bd9Sstevel@tonic-gate 		if (error)
26657c478bd9Sstevel@tonic-gate 			break;
26667c478bd9Sstevel@tonic-gate 		/* Read as much as possible. */
26677c478bd9Sstevel@tonic-gate 		if (fileoff >= va.va_size)
26687c478bd9Sstevel@tonic-gate 			break;
2669ead83321SVasumathi Sundaram - Sun Microsystems 		if (total_size + fileoff > va.va_size)
2670ead83321SVasumathi Sundaram - Sun Microsystems 			total_size = va.va_size - fileoff;
26717c478bd9Sstevel@tonic-gate 	}
26727c478bd9Sstevel@tonic-gate out:
26737c478bd9Sstevel@tonic-gate 	VOP_RWUNLOCK(fvp, V_WRITELOCK_FALSE, NULL);
26747c478bd9Sstevel@tonic-gate done:
26757c478bd9Sstevel@tonic-gate 	*count = ksize;
26767c478bd9Sstevel@tonic-gate 	if (dowait) {
26777c478bd9Sstevel@tonic-gate 		stdata_t *stp;
26787c478bd9Sstevel@tonic-gate 
26797c478bd9Sstevel@tonic-gate 		stp = vp->v_stream;
26800f1702c5SYu Xiangning 		if (stp == NULL) {
26810f1702c5SYu Xiangning 			struct sonode *so;
26820f1702c5SYu Xiangning 			so = VTOSO(vp);
26830f1702c5SYu Xiangning 			error = so_zcopy_wait(so);
26840f1702c5SYu Xiangning 		} else {
26857c478bd9Sstevel@tonic-gate 			mutex_enter(&stp->sd_lock);
26867c478bd9Sstevel@tonic-gate 			while (!(stp->sd_flag & STZCNOTIFY)) {
2687a298cf18Samehta 				if (cv_wait_sig(&stp->sd_zcopy_wait,
2688a298cf18Samehta 				    &stp->sd_lock) == 0) {
2689a298cf18Samehta 					error = EINTR;
2690a298cf18Samehta 					break;
2691a298cf18Samehta 				}
26927c478bd9Sstevel@tonic-gate 			}
26937c478bd9Sstevel@tonic-gate 			stp->sd_flag &= ~STZCNOTIFY;
26947c478bd9Sstevel@tonic-gate 			mutex_exit(&stp->sd_lock);
26957c478bd9Sstevel@tonic-gate 		}
26960f1702c5SYu Xiangning 	}
26977c478bd9Sstevel@tonic-gate 	return (error);
26987c478bd9Sstevel@tonic-gate }
26997c478bd9Sstevel@tonic-gate 
27007c478bd9Sstevel@tonic-gate int
27017c478bd9Sstevel@tonic-gate snf_cache(file_t *fp, vnode_t *fvp, u_offset_t fileoff, u_offset_t size,
27027c478bd9Sstevel@tonic-gate     uint_t maxpsz, ssize_t *count)
27037c478bd9Sstevel@tonic-gate {
27047c478bd9Sstevel@tonic-gate 	struct vnode *vp;
27057c478bd9Sstevel@tonic-gate 	mblk_t *mp;
27067c478bd9Sstevel@tonic-gate 	int iosize;
2707b273e065Skrishna 	int extra = 0;
27087c478bd9Sstevel@tonic-gate 	int error;
27097c478bd9Sstevel@tonic-gate 	short fflag;
27107c478bd9Sstevel@tonic-gate 	int ksize;
27117c478bd9Sstevel@tonic-gate 	int ioflag;
27127c478bd9Sstevel@tonic-gate 	struct uio auio;
27137c478bd9Sstevel@tonic-gate 	struct iovec aiov;
27147c478bd9Sstevel@tonic-gate 	struct vattr va;
2715e116a42fSPrakash Jalan 	int maxblk = 0;
2716e116a42fSPrakash Jalan 	int wroff = 0;
2717e116a42fSPrakash Jalan 	struct sonode *so;
27180f1702c5SYu Xiangning 	struct nmsghdr msg;
27197c478bd9Sstevel@tonic-gate 
27207c478bd9Sstevel@tonic-gate 	vp = fp->f_vnode;
2721b273e065Skrishna 	if (vp->v_type == VSOCK) {
2722b273e065Skrishna 		stdata_t *stp;
2723b273e065Skrishna 
2724b273e065Skrishna 		/*
2725b273e065Skrishna 		 * Get the extra space to insert a header and a trailer.
2726b273e065Skrishna 		 */
2727e116a42fSPrakash Jalan 		so = VTOSO(vp);
2728b273e065Skrishna 		stp = vp->v_stream;
27290f1702c5SYu Xiangning 		if (stp == NULL) {
27300f1702c5SYu Xiangning 			wroff = so->so_proto_props.sopp_wroff;
27310f1702c5SYu Xiangning 			maxblk = so->so_proto_props.sopp_maxblk;
27320f1702c5SYu Xiangning 			extra = wroff + so->so_proto_props.sopp_tail;
27330f1702c5SYu Xiangning 		} else {
2734e116a42fSPrakash Jalan 			wroff = (int)(stp->sd_wroff);
2735e116a42fSPrakash Jalan 			maxblk = (int)(stp->sd_maxblk);
2736e116a42fSPrakash Jalan 			extra = wroff + (int)(stp->sd_tail);
2737b273e065Skrishna 		}
27380f1702c5SYu Xiangning 	}
27390f1702c5SYu Xiangning 	bzero(&msg, sizeof (msg));
27407c478bd9Sstevel@tonic-gate 	fflag = fp->f_flag;
27417c478bd9Sstevel@tonic-gate 	ksize = 0;
27427c478bd9Sstevel@tonic-gate 	auio.uio_iov = &aiov;
27437c478bd9Sstevel@tonic-gate 	auio.uio_iovcnt = 1;
27447c478bd9Sstevel@tonic-gate 	auio.uio_segflg = UIO_SYSSPACE;
27457c478bd9Sstevel@tonic-gate 	auio.uio_llimit = MAXOFFSET_T;
27467c478bd9Sstevel@tonic-gate 	auio.uio_fmode = fflag;
27477c478bd9Sstevel@tonic-gate 	auio.uio_extflg = UIO_COPY_CACHED;
27487c478bd9Sstevel@tonic-gate 	ioflag = auio.uio_fmode & (FSYNC|FDSYNC|FRSYNC);
27497c478bd9Sstevel@tonic-gate 	/* If read sync is not asked for, filter sync flags */
27507c478bd9Sstevel@tonic-gate 	if ((ioflag & FRSYNC) == 0)
27517c478bd9Sstevel@tonic-gate 		ioflag &= ~(FSYNC|FDSYNC);
27527c478bd9Sstevel@tonic-gate 	for (;;) {
27537c478bd9Sstevel@tonic-gate 		if (ISSIG(curthread, JUSTLOOKING)) {
27547c478bd9Sstevel@tonic-gate 			error = EINTR;
27557c478bd9Sstevel@tonic-gate 			break;
27567c478bd9Sstevel@tonic-gate 		}
27577c478bd9Sstevel@tonic-gate 		iosize = (int)MIN(maxpsz, size);
2758e116a42fSPrakash Jalan 
2759e116a42fSPrakash Jalan 		/*
27603e95bd4aSAnders Persson 		 * Socket filters can limit the mblk size,
27613e95bd4aSAnders Persson 		 * so limit reads to maxblk if there are
2762dd49f125SAnders Persson 		 * filters present.
2763e116a42fSPrakash Jalan 		 */
27643e95bd4aSAnders Persson 		if (vp->v_type == VSOCK &&
27653e95bd4aSAnders Persson 		    so->so_filter_active > 0 && maxblk != INFPSZ)
2766e116a42fSPrakash Jalan 			iosize = (int)MIN(iosize, maxblk);
2767e116a42fSPrakash Jalan 
2768de8c4a14SErik Nordmark 		if (is_system_labeled()) {
2769de8c4a14SErik Nordmark 			mp = allocb_cred(iosize + extra, CRED(),
2770de8c4a14SErik Nordmark 			    curproc->p_pid);
2771de8c4a14SErik Nordmark 		} else {
2772de8c4a14SErik Nordmark 			mp = allocb(iosize + extra, BPRI_MED);
2773de8c4a14SErik Nordmark 		}
2774de8c4a14SErik Nordmark 		if (mp == NULL) {
27757c478bd9Sstevel@tonic-gate 			error = EAGAIN;
27767c478bd9Sstevel@tonic-gate 			break;
27777c478bd9Sstevel@tonic-gate 		}
2778e116a42fSPrakash Jalan 
2779e116a42fSPrakash Jalan 		mp->b_rptr += wroff;
2780e116a42fSPrakash Jalan 
27817c478bd9Sstevel@tonic-gate 		aiov.iov_base = (caddr_t)mp->b_rptr;
27827c478bd9Sstevel@tonic-gate 		aiov.iov_len = iosize;
27837c478bd9Sstevel@tonic-gate 		auio.uio_loffset = fileoff;
27847c478bd9Sstevel@tonic-gate 		auio.uio_resid = iosize;
27857c478bd9Sstevel@tonic-gate 
27867c478bd9Sstevel@tonic-gate 		error = VOP_READ(fvp, &auio, ioflag, fp->f_cred, NULL);
27877c478bd9Sstevel@tonic-gate 		iosize -= auio.uio_resid;
27887c478bd9Sstevel@tonic-gate 
27897c478bd9Sstevel@tonic-gate 		if (error == EINTR && iosize != 0)
27907c478bd9Sstevel@tonic-gate 			error = 0;
27917c478bd9Sstevel@tonic-gate 
27927c478bd9Sstevel@tonic-gate 		if (error != 0 || iosize == 0) {
27937c478bd9Sstevel@tonic-gate 			freeb(mp);
27947c478bd9Sstevel@tonic-gate 			break;
27957c478bd9Sstevel@tonic-gate 		}
27967c478bd9Sstevel@tonic-gate 		mp->b_wptr = mp->b_rptr + iosize;
27977c478bd9Sstevel@tonic-gate 
27987c478bd9Sstevel@tonic-gate 		VOP_RWUNLOCK(fvp, V_WRITELOCK_FALSE, NULL);
27990f1702c5SYu Xiangning 
28000f1702c5SYu Xiangning 		error = socket_sendmblk(VTOSO(vp), &msg, fflag, CRED(), &mp);
28010f1702c5SYu Xiangning 
28020f1702c5SYu Xiangning 		if (error != 0) {
28037c478bd9Sstevel@tonic-gate 			*count = ksize;
28040f1702c5SYu Xiangning 			if (mp != NULL)
28057c478bd9Sstevel@tonic-gate 				freeb(mp);
28067c478bd9Sstevel@tonic-gate 			return (error);
28077c478bd9Sstevel@tonic-gate 		}
28087c478bd9Sstevel@tonic-gate 		ksize += iosize;
28097c478bd9Sstevel@tonic-gate 		size -= iosize;
28107c478bd9Sstevel@tonic-gate 		if (size == 0)
28117c478bd9Sstevel@tonic-gate 			goto done;
28127c478bd9Sstevel@tonic-gate 
28137c478bd9Sstevel@tonic-gate 		fileoff += iosize;
28147c478bd9Sstevel@tonic-gate 		(void) VOP_RWLOCK(fvp, V_WRITELOCK_FALSE, NULL);
28157c478bd9Sstevel@tonic-gate 		va.va_mask = AT_SIZE;
2816da6c28aaSamw 		error = VOP_GETATTR(fvp, &va, 0, kcred, NULL);
28177c478bd9Sstevel@tonic-gate 		if (error)
28187c478bd9Sstevel@tonic-gate 			break;
28197c478bd9Sstevel@tonic-gate 		/* Read as much as possible. */
28207c478bd9Sstevel@tonic-gate 		if (fileoff >= va.va_size)
28217c478bd9Sstevel@tonic-gate 			size = 0;
28227c478bd9Sstevel@tonic-gate 		else if (size + fileoff > va.va_size)
28237c478bd9Sstevel@tonic-gate 			size = va.va_size - fileoff;
28247c478bd9Sstevel@tonic-gate 	}
28257c478bd9Sstevel@tonic-gate 	VOP_RWUNLOCK(fvp, V_WRITELOCK_FALSE, NULL);
28267c478bd9Sstevel@tonic-gate done:
28277c478bd9Sstevel@tonic-gate 	*count = ksize;
28287c478bd9Sstevel@tonic-gate 	return (error);
28297c478bd9Sstevel@tonic-gate }
28307c478bd9Sstevel@tonic-gate 
28317c478bd9Sstevel@tonic-gate #if defined(_SYSCALL32_IMPL) || defined(_ILP32)
28327c478bd9Sstevel@tonic-gate /*
28337c478bd9Sstevel@tonic-gate  * Largefile support for 32 bit applications only.
28347c478bd9Sstevel@tonic-gate  */
28357c478bd9Sstevel@tonic-gate int
28367c478bd9Sstevel@tonic-gate sosendfile64(file_t *fp, file_t *rfp, const struct ksendfilevec64 *sfv,
28377c478bd9Sstevel@tonic-gate     ssize32_t *count32)
28387c478bd9Sstevel@tonic-gate {
28397c478bd9Sstevel@tonic-gate 	ssize32_t sfv_len;
28407c478bd9Sstevel@tonic-gate 	u_offset_t sfv_off, va_size;
28417c478bd9Sstevel@tonic-gate 	struct vnode *vp, *fvp, *realvp;
28427c478bd9Sstevel@tonic-gate 	struct vattr va;
28437c478bd9Sstevel@tonic-gate 	stdata_t *stp;
28447c478bd9Sstevel@tonic-gate 	ssize_t count = 0;
28457c478bd9Sstevel@tonic-gate 	int error = 0;
28467c478bd9Sstevel@tonic-gate 	boolean_t dozcopy = B_FALSE;
28477c478bd9Sstevel@tonic-gate 	uint_t maxpsz;
28487c478bd9Sstevel@tonic-gate 
28497c478bd9Sstevel@tonic-gate 	sfv_len = (ssize32_t)sfv->sfv_len;
28507c478bd9Sstevel@tonic-gate 	if (sfv_len < 0) {
28517c478bd9Sstevel@tonic-gate 		error = EINVAL;
28527c478bd9Sstevel@tonic-gate 		goto out;
28537c478bd9Sstevel@tonic-gate 	}
28547c478bd9Sstevel@tonic-gate 
28557c478bd9Sstevel@tonic-gate 	if (sfv_len == 0) goto out;
28567c478bd9Sstevel@tonic-gate 
28577c478bd9Sstevel@tonic-gate 	sfv_off = (u_offset_t)sfv->sfv_off;
28587c478bd9Sstevel@tonic-gate 
28597c478bd9Sstevel@tonic-gate 	/* Same checks as in pread */
28607c478bd9Sstevel@tonic-gate 	if (sfv_off > MAXOFFSET_T) {
28617c478bd9Sstevel@tonic-gate 		error = EINVAL;
28627c478bd9Sstevel@tonic-gate 		goto out;
28637c478bd9Sstevel@tonic-gate 	}
28647c478bd9Sstevel@tonic-gate 	if (sfv_off + sfv_len > MAXOFFSET_T)
28657c478bd9Sstevel@tonic-gate 		sfv_len = (ssize32_t)(MAXOFFSET_T - sfv_off);
28667c478bd9Sstevel@tonic-gate 
28677c478bd9Sstevel@tonic-gate 	/*
28687c478bd9Sstevel@tonic-gate 	 * There are no more checks on sfv_len. So, we cast it to
28697c478bd9Sstevel@tonic-gate 	 * u_offset_t and share the snf_direct_io/snf_cache code between
28707c478bd9Sstevel@tonic-gate 	 * 32 bit and 64 bit.
28717c478bd9Sstevel@tonic-gate 	 *
28727c478bd9Sstevel@tonic-gate 	 * TODO: should do nbl_need_check() like read()?
28737c478bd9Sstevel@tonic-gate 	 */
28747c478bd9Sstevel@tonic-gate 	if (sfv_len > sendfile_max_size) {
28757c478bd9Sstevel@tonic-gate 		sf_stats.ss_file_not_cached++;
28767c478bd9Sstevel@tonic-gate 		error = snf_direct_io(fp, rfp, sfv_off, (u_offset_t)sfv_len,
28777c478bd9Sstevel@tonic-gate 		    &count);
28787c478bd9Sstevel@tonic-gate 		goto out;
28797c478bd9Sstevel@tonic-gate 	}
28807c478bd9Sstevel@tonic-gate 	fvp = rfp->f_vnode;
2881da6c28aaSamw 	if (VOP_REALVP(fvp, &realvp, NULL) == 0)
28827c478bd9Sstevel@tonic-gate 		fvp = realvp;
28837c478bd9Sstevel@tonic-gate 	/*
28847c478bd9Sstevel@tonic-gate 	 * Grab the lock as a reader to prevent the file size
28857c478bd9Sstevel@tonic-gate 	 * from changing underneath.
28867c478bd9Sstevel@tonic-gate 	 */
28877c478bd9Sstevel@tonic-gate 	(void) VOP_RWLOCK(fvp, V_WRITELOCK_FALSE, NULL);
28887c478bd9Sstevel@tonic-gate 	va.va_mask = AT_SIZE;
2889da6c28aaSamw 	error = VOP_GETATTR(fvp, &va, 0, kcred, NULL);
28907c478bd9Sstevel@tonic-gate 	va_size = va.va_size;
2891a8e93a73Sdm120769 	if ((error != 0) || (va_size == 0) || (sfv_off >= va_size)) {
28927c478bd9Sstevel@tonic-gate 		VOP_RWUNLOCK(fvp, V_WRITELOCK_FALSE, NULL);
28937c478bd9Sstevel@tonic-gate 		goto out;
28947c478bd9Sstevel@tonic-gate 	}
28957c478bd9Sstevel@tonic-gate 	/* Read as much as possible. */
28967c478bd9Sstevel@tonic-gate 	if (sfv_off + sfv_len > va_size)
28977c478bd9Sstevel@tonic-gate 		sfv_len = va_size - sfv_off;
28987c478bd9Sstevel@tonic-gate 
28997c478bd9Sstevel@tonic-gate 	vp = fp->f_vnode;
29007c478bd9Sstevel@tonic-gate 	stp = vp->v_stream;
29017c478bd9Sstevel@tonic-gate 	/*
29027c478bd9Sstevel@tonic-gate 	 * When the NOWAIT flag is not set, we enable zero-copy only if the
29037c478bd9Sstevel@tonic-gate 	 * transfer size is large enough. This prevents performance loss
29047c478bd9Sstevel@tonic-gate 	 * when the caller sends the file piece by piece.
29057c478bd9Sstevel@tonic-gate 	 */
29067c478bd9Sstevel@tonic-gate 	if (sfv_len >= MAXBSIZE && (sfv_len >= (va_size >> 1) ||
29077c478bd9Sstevel@tonic-gate 	    (sfv->sfv_flag & SFV_NOWAIT) || sfv_len >= 0x1000000) &&
290874024373Spr14459 	    !vn_has_flocks(fvp) && !(fvp->v_flag & VNOMAP)) {
29090f1702c5SYu Xiangning 		uint_t copyflag;
29100f1702c5SYu Xiangning 		copyflag = stp != NULL ? stp->sd_copyflag :
29110f1702c5SYu Xiangning 		    VTOSO(vp)->so_proto_props.sopp_zcopyflag;
29120f1702c5SYu Xiangning 		if ((copyflag & (STZCVMSAFE|STZCVMUNSAFE)) == 0) {
29137c478bd9Sstevel@tonic-gate 			int on = 1;
29147c478bd9Sstevel@tonic-gate 
29150f1702c5SYu Xiangning 			if (socket_setsockopt(VTOSO(vp), SOL_SOCKET,
29160f1702c5SYu Xiangning 			    SO_SND_COPYAVOID, &on, sizeof (on), CRED()) == 0)
29177c478bd9Sstevel@tonic-gate 				dozcopy = B_TRUE;
29187c478bd9Sstevel@tonic-gate 		} else {
29190f1702c5SYu Xiangning 			dozcopy = copyflag & STZCVMSAFE;
29207c478bd9Sstevel@tonic-gate 		}
29217c478bd9Sstevel@tonic-gate 	}
29227c478bd9Sstevel@tonic-gate 	if (dozcopy) {
29237c478bd9Sstevel@tonic-gate 		sf_stats.ss_file_segmap++;
29247c478bd9Sstevel@tonic-gate 		error = snf_segmap(fp, fvp, sfv_off, (u_offset_t)sfv_len,
29253b3d24f3SJayakara Kini 		    &count, ((sfv->sfv_flag & SFV_NOWAIT) != 0));
29267c478bd9Sstevel@tonic-gate 	} else {
29270f1702c5SYu Xiangning 		if (vp->v_type == VSOCK && stp == NULL) {
29280f1702c5SYu Xiangning 			sonode_t *so = VTOSO(vp);
29290f1702c5SYu Xiangning 			maxpsz = so->so_proto_props.sopp_maxpsz;
29300f1702c5SYu Xiangning 		} else if (stp != NULL) {
29310f1702c5SYu Xiangning 			maxpsz = stp->sd_qn_maxpsz;
29320f1702c5SYu Xiangning 		} else {
29330f1702c5SYu Xiangning 			maxpsz = maxphys;
29340f1702c5SYu Xiangning 		}
29350f1702c5SYu Xiangning 
29360f1702c5SYu Xiangning 		if (maxpsz == INFPSZ)
29373b3d24f3SJayakara Kini 			maxpsz = maxphys;
29383b3d24f3SJayakara Kini 		else
29390f1702c5SYu Xiangning 			maxpsz = roundup(maxpsz, MAXBSIZE);
29407c478bd9Sstevel@tonic-gate 		sf_stats.ss_file_cached++;
29417c478bd9Sstevel@tonic-gate 		error = snf_cache(fp, fvp, sfv_off, (u_offset_t)sfv_len,
29427c478bd9Sstevel@tonic-gate 		    maxpsz, &count);
29437c478bd9Sstevel@tonic-gate 	}
29447c478bd9Sstevel@tonic-gate out:
29457c478bd9Sstevel@tonic-gate 	releasef(sfv->sfv_fd);
29467c478bd9Sstevel@tonic-gate 	*count32 = (ssize32_t)count;
29477c478bd9Sstevel@tonic-gate 	return (error);
29487c478bd9Sstevel@tonic-gate }
29497c478bd9Sstevel@tonic-gate #endif
29507c478bd9Sstevel@tonic-gate 
29517c478bd9Sstevel@tonic-gate #ifdef _SYSCALL32_IMPL
29527c478bd9Sstevel@tonic-gate /*
29537c478bd9Sstevel@tonic-gate  * recv32(), recvfrom32(), send32(), sendto32(): intentionally return a
29547c478bd9Sstevel@tonic-gate  * ssize_t rather than ssize32_t; see the comments above read32 for details.
29557c478bd9Sstevel@tonic-gate  */
29567c478bd9Sstevel@tonic-gate 
29577c478bd9Sstevel@tonic-gate ssize_t
29587c478bd9Sstevel@tonic-gate recv32(int32_t sock, caddr32_t buffer, size32_t len, int32_t flags)
29597c478bd9Sstevel@tonic-gate {
29607c478bd9Sstevel@tonic-gate 	return (recv(sock, (void *)(uintptr_t)buffer, (ssize32_t)len, flags));
29617c478bd9Sstevel@tonic-gate }
29627c478bd9Sstevel@tonic-gate 
29637c478bd9Sstevel@tonic-gate ssize_t
29647c478bd9Sstevel@tonic-gate recvfrom32(int32_t sock, caddr32_t buffer, size32_t len, int32_t flags,
29657c478bd9Sstevel@tonic-gate     caddr32_t name, caddr32_t namelenp)
29667c478bd9Sstevel@tonic-gate {
29677c478bd9Sstevel@tonic-gate 	return (recvfrom(sock, (void *)(uintptr_t)buffer, (ssize32_t)len, flags,
29687c478bd9Sstevel@tonic-gate 	    (void *)(uintptr_t)name, (void *)(uintptr_t)namelenp));
29697c478bd9Sstevel@tonic-gate }
29707c478bd9Sstevel@tonic-gate 
29717c478bd9Sstevel@tonic-gate ssize_t
29727c478bd9Sstevel@tonic-gate send32(int32_t sock, caddr32_t buffer, size32_t len, int32_t flags)
29737c478bd9Sstevel@tonic-gate {
29747c478bd9Sstevel@tonic-gate 	return (send(sock, (void *)(uintptr_t)buffer, (ssize32_t)len, flags));
29757c478bd9Sstevel@tonic-gate }
29767c478bd9Sstevel@tonic-gate 
29777c478bd9Sstevel@tonic-gate ssize_t
29787c478bd9Sstevel@tonic-gate sendto32(int32_t sock, caddr32_t buffer, size32_t len, int32_t flags,
29797c478bd9Sstevel@tonic-gate     caddr32_t name, socklen_t namelen)
29807c478bd9Sstevel@tonic-gate {
29817c478bd9Sstevel@tonic-gate 	return (sendto(sock, (void *)(uintptr_t)buffer, (ssize32_t)len, flags,
29827c478bd9Sstevel@tonic-gate 	    (void *)(uintptr_t)name, namelen));
29837c478bd9Sstevel@tonic-gate }
29847c478bd9Sstevel@tonic-gate #endif	/* _SYSCALL32_IMPL */
29857c478bd9Sstevel@tonic-gate 
29867c478bd9Sstevel@tonic-gate /*
2987da6c28aaSamw  * Function wrappers (mostly around the sonode switch) for
29887c478bd9Sstevel@tonic-gate  * backward compatibility.
29897c478bd9Sstevel@tonic-gate  */
29907c478bd9Sstevel@tonic-gate 
29917c478bd9Sstevel@tonic-gate int
29927c478bd9Sstevel@tonic-gate soaccept(struct sonode *so, int fflag, struct sonode **nsop)
29937c478bd9Sstevel@tonic-gate {
29940f1702c5SYu Xiangning 	return (socket_accept(so, fflag, CRED(), nsop));
29957c478bd9Sstevel@tonic-gate }
29967c478bd9Sstevel@tonic-gate 
29977c478bd9Sstevel@tonic-gate int
29987c478bd9Sstevel@tonic-gate sobind(struct sonode *so, struct sockaddr *name, socklen_t namelen,
29997c478bd9Sstevel@tonic-gate     int backlog, int flags)
30007c478bd9Sstevel@tonic-gate {
30017c478bd9Sstevel@tonic-gate 	int	error;
30027c478bd9Sstevel@tonic-gate 
30030f1702c5SYu Xiangning 	error = socket_bind(so, name, namelen, flags, CRED());
30047c478bd9Sstevel@tonic-gate 	if (error == 0 && backlog != 0)
30050f1702c5SYu Xiangning 		return (socket_listen(so, backlog, CRED()));
30067c478bd9Sstevel@tonic-gate 
30077c478bd9Sstevel@tonic-gate 	return (error);
30087c478bd9Sstevel@tonic-gate }
30097c478bd9Sstevel@tonic-gate 
30107c478bd9Sstevel@tonic-gate int
30117c478bd9Sstevel@tonic-gate solisten(struct sonode *so, int backlog)
30127c478bd9Sstevel@tonic-gate {
30130f1702c5SYu Xiangning 	return (socket_listen(so, backlog, CRED()));
30147c478bd9Sstevel@tonic-gate }
30157c478bd9Sstevel@tonic-gate 
30167c478bd9Sstevel@tonic-gate int
30173e95bd4aSAnders Persson soconnect(struct sonode *so, struct sockaddr *name, socklen_t namelen,
30187c478bd9Sstevel@tonic-gate     int fflag, int flags)
30197c478bd9Sstevel@tonic-gate {
30200f1702c5SYu Xiangning 	return (socket_connect(so, name, namelen, fflag, flags, CRED()));
30217c478bd9Sstevel@tonic-gate }
30227c478bd9Sstevel@tonic-gate 
30237c478bd9Sstevel@tonic-gate int
30247c478bd9Sstevel@tonic-gate sorecvmsg(struct sonode *so, struct nmsghdr *msg, struct uio *uiop)
30257c478bd9Sstevel@tonic-gate {
30260f1702c5SYu Xiangning 	return (socket_recvmsg(so, msg, uiop, CRED()));
30277c478bd9Sstevel@tonic-gate }
30287c478bd9Sstevel@tonic-gate 
30297c478bd9Sstevel@tonic-gate int
30307c478bd9Sstevel@tonic-gate sosendmsg(struct sonode *so, struct nmsghdr *msg, struct uio *uiop)
30317c478bd9Sstevel@tonic-gate {
30320f1702c5SYu Xiangning 	return (socket_sendmsg(so, msg, uiop, CRED()));
30337c478bd9Sstevel@tonic-gate }
30347c478bd9Sstevel@tonic-gate 
30357c478bd9Sstevel@tonic-gate int
30367c478bd9Sstevel@tonic-gate soshutdown(struct sonode *so, int how)
30377c478bd9Sstevel@tonic-gate {
30380f1702c5SYu Xiangning 	return (socket_shutdown(so, how, CRED()));
30397c478bd9Sstevel@tonic-gate }
30407c478bd9Sstevel@tonic-gate 
30417c478bd9Sstevel@tonic-gate int
30427c478bd9Sstevel@tonic-gate sogetsockopt(struct sonode *so, int level, int option_name, void *optval,
30437c478bd9Sstevel@tonic-gate     socklen_t *optlenp, int flags)
30447c478bd9Sstevel@tonic-gate {
30450f1702c5SYu Xiangning 	return (socket_getsockopt(so, level, option_name, optval, optlenp,
30460f1702c5SYu Xiangning 	    flags, CRED()));
30477c478bd9Sstevel@tonic-gate }
30487c478bd9Sstevel@tonic-gate 
30497c478bd9Sstevel@tonic-gate int
30507c478bd9Sstevel@tonic-gate sosetsockopt(struct sonode *so, int level, int option_name, const void *optval,
30517c478bd9Sstevel@tonic-gate     t_uscalar_t optlen)
30527c478bd9Sstevel@tonic-gate {
30530f1702c5SYu Xiangning 	return (socket_setsockopt(so, level, option_name, optval, optlen,
30540f1702c5SYu Xiangning 	    CRED()));
30557c478bd9Sstevel@tonic-gate }
30567c478bd9Sstevel@tonic-gate 
30577c478bd9Sstevel@tonic-gate /*
30587c478bd9Sstevel@tonic-gate  * Because this is backward compatibility interface it only needs to be
30597c478bd9Sstevel@tonic-gate  * able to handle the creation of TPI sockfs sockets.
30607c478bd9Sstevel@tonic-gate  */
30617c478bd9Sstevel@tonic-gate struct sonode *
30620f1702c5SYu Xiangning socreate(struct sockparams *sp, int family, int type, int protocol, int version,
30630f1702c5SYu Xiangning     int *errorp)
30647c478bd9Sstevel@tonic-gate {
30650f1702c5SYu Xiangning 	struct sonode *so;
30660f1702c5SYu Xiangning 
30670f1702c5SYu Xiangning 	ASSERT(sp != NULL);
30680f1702c5SYu Xiangning 
30690f1702c5SYu Xiangning 	so = sp->sp_smod_info->smod_sock_create_func(sp, family, type, protocol,
30700f1702c5SYu Xiangning 	    version, SOCKET_SLEEP, errorp, CRED());
30710f1702c5SYu Xiangning 	if (so == NULL) {
30720f1702c5SYu Xiangning 		SOCKPARAMS_DEC_REF(sp);
30730f1702c5SYu Xiangning 	} else {
30740f1702c5SYu Xiangning 		if ((*errorp = SOP_INIT(so, NULL, CRED(), SOCKET_SLEEP)) == 0) {
30750f1702c5SYu Xiangning 			/* Cannot fail, only bumps so_count */
30760f1702c5SYu Xiangning 			(void) VOP_OPEN(&SOTOV(so), FREAD|FWRITE, CRED(), NULL);
30770f1702c5SYu Xiangning 		} else {
30780f1702c5SYu Xiangning 			socket_destroy(so);
30790f1702c5SYu Xiangning 			so = NULL;
30800f1702c5SYu Xiangning 		}
30810f1702c5SYu Xiangning 	}
30820f1702c5SYu Xiangning 	return (so);
30837c478bd9Sstevel@tonic-gate }
3084