xref: /onnv-gate/usr/src/uts/common/fs/sockfs/socksyscalls.c (revision 7568:afb5433078f5)
10Sstevel@tonic-gate /*
20Sstevel@tonic-gate  * CDDL HEADER START
30Sstevel@tonic-gate  *
40Sstevel@tonic-gate  * The contents of this file are subject to the terms of the
51548Srshoaib  * Common Development and Distribution License (the "License").
61548Srshoaib  * You may not use this file except in compliance with the License.
70Sstevel@tonic-gate  *
80Sstevel@tonic-gate  * You can obtain a copy of the license at usr/src/OPENSOLARIS.LICENSE
90Sstevel@tonic-gate  * or http://www.opensolaris.org/os/licensing.
100Sstevel@tonic-gate  * See the License for the specific language governing permissions
110Sstevel@tonic-gate  * and limitations under the License.
120Sstevel@tonic-gate  *
130Sstevel@tonic-gate  * When distributing Covered Code, include this CDDL HEADER in each
140Sstevel@tonic-gate  * file and include the License file at usr/src/OPENSOLARIS.LICENSE.
150Sstevel@tonic-gate  * If applicable, add the following below this CDDL HEADER, with the
160Sstevel@tonic-gate  * fields enclosed by brackets "[]" replaced with your own identifying
170Sstevel@tonic-gate  * information: Portions Copyright [yyyy] [name of copyright owner]
180Sstevel@tonic-gate  *
190Sstevel@tonic-gate  * CDDL HEADER END
200Sstevel@tonic-gate  */
211548Srshoaib 
220Sstevel@tonic-gate /*
236240Skrishna  * Copyright 2008 Sun Microsystems, Inc.  All rights reserved.
240Sstevel@tonic-gate  * Use is subject to license terms.
250Sstevel@tonic-gate  */
260Sstevel@tonic-gate 
270Sstevel@tonic-gate #include <sys/types.h>
280Sstevel@tonic-gate #include <sys/t_lock.h>
290Sstevel@tonic-gate #include <sys/param.h>
300Sstevel@tonic-gate #include <sys/systm.h>
310Sstevel@tonic-gate #include <sys/buf.h>
320Sstevel@tonic-gate #include <sys/conf.h>
330Sstevel@tonic-gate #include <sys/cred.h>
340Sstevel@tonic-gate #include <sys/kmem.h>
350Sstevel@tonic-gate #include <sys/sysmacros.h>
360Sstevel@tonic-gate #include <sys/vfs.h>
370Sstevel@tonic-gate #include <sys/vnode.h>
380Sstevel@tonic-gate #include <sys/debug.h>
390Sstevel@tonic-gate #include <sys/errno.h>
400Sstevel@tonic-gate #include <sys/time.h>
410Sstevel@tonic-gate #include <sys/file.h>
420Sstevel@tonic-gate #include <sys/user.h>
430Sstevel@tonic-gate #include <sys/stream.h>
440Sstevel@tonic-gate #include <sys/strsubr.h>
450Sstevel@tonic-gate #include <sys/strsun.h>
464173Spr14459 #include <sys/sunddi.h>
470Sstevel@tonic-gate #include <sys/esunddi.h>
480Sstevel@tonic-gate #include <sys/flock.h>
490Sstevel@tonic-gate #include <sys/modctl.h>
500Sstevel@tonic-gate #include <sys/cmn_err.h>
510Sstevel@tonic-gate #include <sys/vmsystm.h>
520Sstevel@tonic-gate #include <sys/policy.h>
530Sstevel@tonic-gate 
540Sstevel@tonic-gate #include <sys/socket.h>
550Sstevel@tonic-gate #include <sys/socketvar.h>
560Sstevel@tonic-gate 
570Sstevel@tonic-gate #include <sys/isa_defs.h>
580Sstevel@tonic-gate #include <sys/inttypes.h>
590Sstevel@tonic-gate #include <sys/systm.h>
600Sstevel@tonic-gate #include <sys/cpuvar.h>
610Sstevel@tonic-gate #include <sys/filio.h>
620Sstevel@tonic-gate #include <sys/sendfile.h>
630Sstevel@tonic-gate #include <sys/ddi.h>
640Sstevel@tonic-gate #include <vm/seg.h>
650Sstevel@tonic-gate #include <vm/seg_map.h>
660Sstevel@tonic-gate #include <vm/seg_kpm.h>
670Sstevel@tonic-gate #include <fs/sockfs/nl7c.h>
680Sstevel@tonic-gate 
690Sstevel@tonic-gate #ifdef SOCK_TEST
700Sstevel@tonic-gate int do_useracc = 1;		/* Controlled by setting SO_DEBUG to 4 */
710Sstevel@tonic-gate #else
720Sstevel@tonic-gate #define	do_useracc	1
730Sstevel@tonic-gate #endif /* SOCK_TEST */
740Sstevel@tonic-gate 
750Sstevel@tonic-gate extern int xnet_truncate_print;
760Sstevel@tonic-gate 
770Sstevel@tonic-gate /*
780Sstevel@tonic-gate  * Note: DEF_IOV_MAX is defined and used as it is in "fs/vncalls.c"
790Sstevel@tonic-gate  *	 as there isn't a formal definition of IOV_MAX ???
800Sstevel@tonic-gate  */
810Sstevel@tonic-gate #define	MSG_MAXIOVLEN	16
820Sstevel@tonic-gate 
830Sstevel@tonic-gate /*
840Sstevel@tonic-gate  * Kernel component of socket creation.
850Sstevel@tonic-gate  *
860Sstevel@tonic-gate  * The socket library determines which version number to use.
870Sstevel@tonic-gate  * First the library calls this with a NULL devpath. If this fails
880Sstevel@tonic-gate  * to find a transport (using solookup) the library will look in /etc/netconfig
890Sstevel@tonic-gate  * for the appropriate transport. If one is found it will pass in the
900Sstevel@tonic-gate  * devpath for the kernel to use.
910Sstevel@tonic-gate  */
920Sstevel@tonic-gate int
930Sstevel@tonic-gate so_socket(int domain, int type, int protocol, char *devpath, int version)
940Sstevel@tonic-gate {
950Sstevel@tonic-gate 	vnode_t *accessvp;
960Sstevel@tonic-gate 	struct sonode *so;
970Sstevel@tonic-gate 	vnode_t *vp;
980Sstevel@tonic-gate 	struct file *fp;
990Sstevel@tonic-gate 	int fd;
1000Sstevel@tonic-gate 	int error;
1010Sstevel@tonic-gate 	boolean_t wildcard = B_FALSE;
1020Sstevel@tonic-gate 	int saved_error = 0;
1030Sstevel@tonic-gate 	int sdomain = domain;
1040Sstevel@tonic-gate 
1050Sstevel@tonic-gate 	dprint(1, ("so_socket(%d,%d,%d,%p,%d)\n",
1067240Srh87107 	    domain, type, protocol, (void *)devpath, version));
1070Sstevel@tonic-gate 
1080Sstevel@tonic-gate 	if (domain == AF_NCA) {
1090Sstevel@tonic-gate 		/*
1100Sstevel@tonic-gate 		 * The request is for an NCA socket so for NL7C use the
1110Sstevel@tonic-gate 		 * INET domain instead and mark NL7C_AF_NCA below.
1120Sstevel@tonic-gate 		 */
1130Sstevel@tonic-gate 		domain = AF_INET;
1140Sstevel@tonic-gate 		/*
1150Sstevel@tonic-gate 		 * NL7C is not supported in non-global zones,
1160Sstevel@tonic-gate 		 *  we enforce this restriction here.
1170Sstevel@tonic-gate 		 */
1180Sstevel@tonic-gate 		if (getzoneid() != GLOBAL_ZONEID) {
1190Sstevel@tonic-gate 			return (set_errno(ENOTSUP));
1200Sstevel@tonic-gate 		}
1210Sstevel@tonic-gate 	}
1220Sstevel@tonic-gate 
1230Sstevel@tonic-gate 	accessvp = solookup(domain, type, protocol, devpath, &error);
1240Sstevel@tonic-gate 	if (accessvp == NULL) {
1250Sstevel@tonic-gate 		/*
1260Sstevel@tonic-gate 		 * If there is either an EPROTONOSUPPORT or EPROTOTYPE error
1270Sstevel@tonic-gate 		 * it makes sense doing the wildcard lookup since the
1280Sstevel@tonic-gate 		 * protocol might not be in the table.
1290Sstevel@tonic-gate 		 */
1300Sstevel@tonic-gate 		if (devpath != NULL || protocol == 0 ||
1310Sstevel@tonic-gate 		    !(error == EPROTONOSUPPORT || error == EPROTOTYPE))
1320Sstevel@tonic-gate 			return (set_errno(error));
1330Sstevel@tonic-gate 
1340Sstevel@tonic-gate 		saved_error = error;
1350Sstevel@tonic-gate 
1360Sstevel@tonic-gate 		/*
1370Sstevel@tonic-gate 		 * Try wildcard lookup. Never use devpath for wildcards.
1380Sstevel@tonic-gate 		 */
1390Sstevel@tonic-gate 		accessvp = solookup(domain, type, 0, NULL, &error);
1400Sstevel@tonic-gate 		if (accessvp == NULL) {
1410Sstevel@tonic-gate 			/*
1420Sstevel@tonic-gate 			 * Can't find in kernel table - have library
1430Sstevel@tonic-gate 			 * fall back to /etc/netconfig and tell us
1440Sstevel@tonic-gate 			 * the devpath (The library will do this if it didn't
1450Sstevel@tonic-gate 			 * already pass in a devpath).
1460Sstevel@tonic-gate 			 */
1470Sstevel@tonic-gate 			if (saved_error != 0)
1480Sstevel@tonic-gate 				error = saved_error;
1490Sstevel@tonic-gate 			return (set_errno(error));
1500Sstevel@tonic-gate 		}
1510Sstevel@tonic-gate 		wildcard = B_TRUE;
1520Sstevel@tonic-gate 	}
1530Sstevel@tonic-gate 
1540Sstevel@tonic-gate 	/* Check the device policy */
1550Sstevel@tonic-gate 	if ((error = secpolicy_spec_open(CRED(),
1560Sstevel@tonic-gate 	    accessvp, FREAD|FWRITE)) != 0) {
1570Sstevel@tonic-gate 		return (set_errno(error));
1580Sstevel@tonic-gate 	}
1590Sstevel@tonic-gate 
1601548Srshoaib 	if (protocol == IPPROTO_SCTP) {
1610Sstevel@tonic-gate 		so = sosctp_create(accessvp, domain, type, protocol, version,
1620Sstevel@tonic-gate 		    NULL, &error);
1633422Snh145002 	} else if (protocol == PROTO_SDP) {
1643422Snh145002 		so = sosdp_create(accessvp, domain, type, protocol, version,
1653422Snh145002 		    NULL, &error);
1660Sstevel@tonic-gate 	} else {
1670Sstevel@tonic-gate 		so = sotpi_create(accessvp, domain, type, protocol, version,
1680Sstevel@tonic-gate 		    NULL, &error);
1690Sstevel@tonic-gate 	}
1700Sstevel@tonic-gate 	if (so == NULL) {
1710Sstevel@tonic-gate 		return (set_errno(error));
1720Sstevel@tonic-gate 	}
1730Sstevel@tonic-gate 	if (sdomain == AF_NCA && domain == AF_INET) {
1740Sstevel@tonic-gate 		so->so_nl7c_flags = NL7C_AF_NCA;
1750Sstevel@tonic-gate 	}
1760Sstevel@tonic-gate 	vp = SOTOV(so);
1770Sstevel@tonic-gate 
1780Sstevel@tonic-gate 	if (wildcard) {
1790Sstevel@tonic-gate 		/*
1800Sstevel@tonic-gate 		 * Issue SO_PROTOTYPE setsockopt.
1810Sstevel@tonic-gate 		 */
1820Sstevel@tonic-gate 		error = SOP_SETSOCKOPT(so, SOL_SOCKET, SO_PROTOTYPE,
1835227Stz204579 		    &protocol,
1845227Stz204579 		    (t_uscalar_t)sizeof (protocol));
1850Sstevel@tonic-gate 		if (error) {
1865331Samw 			(void) VOP_CLOSE(vp, 0, 1, 0, CRED(), NULL);
1870Sstevel@tonic-gate 			VN_RELE(vp);
1880Sstevel@tonic-gate 			/*
1890Sstevel@tonic-gate 			 * Setsockopt often fails with ENOPROTOOPT but socket()
1900Sstevel@tonic-gate 			 * should fail with EPROTONOSUPPORT/EPROTOTYPE.
1910Sstevel@tonic-gate 			 */
1920Sstevel@tonic-gate 			if (saved_error != 0 && error == ENOPROTOOPT)
1930Sstevel@tonic-gate 				error = saved_error;
1940Sstevel@tonic-gate 			else
1950Sstevel@tonic-gate 				error = EPROTONOSUPPORT;
1960Sstevel@tonic-gate 			return (set_errno(error));
1970Sstevel@tonic-gate 		}
1980Sstevel@tonic-gate 	}
1990Sstevel@tonic-gate 	if (error = falloc(vp, FWRITE|FREAD, &fp, &fd)) {
2005331Samw 		(void) VOP_CLOSE(vp, 0, 1, 0, CRED(), NULL);
2010Sstevel@tonic-gate 		VN_RELE(vp);
2020Sstevel@tonic-gate 		return (set_errno(error));
2030Sstevel@tonic-gate 	}
2040Sstevel@tonic-gate 
2050Sstevel@tonic-gate 	/*
2060Sstevel@tonic-gate 	 * Now fill in the entries that falloc reserved
2070Sstevel@tonic-gate 	 */
2080Sstevel@tonic-gate 	mutex_exit(&fp->f_tlock);
2090Sstevel@tonic-gate 	setf(fd, fp);
2100Sstevel@tonic-gate 
2110Sstevel@tonic-gate 	return (fd);
2120Sstevel@tonic-gate }
2130Sstevel@tonic-gate 
2140Sstevel@tonic-gate /*
2150Sstevel@tonic-gate  * Map from a file descriptor to a socket node.
2160Sstevel@tonic-gate  * Returns with the file descriptor held i.e. the caller has to
2170Sstevel@tonic-gate  * use releasef when done with the file descriptor.
2180Sstevel@tonic-gate  */
2195227Stz204579 struct sonode *
2200Sstevel@tonic-gate getsonode(int sock, int *errorp, file_t **fpp)
2210Sstevel@tonic-gate {
2220Sstevel@tonic-gate 	file_t *fp;
2230Sstevel@tonic-gate 	vnode_t *vp;
2240Sstevel@tonic-gate 	struct sonode *so;
2250Sstevel@tonic-gate 
2260Sstevel@tonic-gate 	if ((fp = getf(sock)) == NULL) {
2270Sstevel@tonic-gate 		*errorp = EBADF;
2280Sstevel@tonic-gate 		eprintline(*errorp);
2290Sstevel@tonic-gate 		return (NULL);
2300Sstevel@tonic-gate 	}
2310Sstevel@tonic-gate 	vp = fp->f_vnode;
2320Sstevel@tonic-gate 	/* Check if it is a socket */
2330Sstevel@tonic-gate 	if (vp->v_type != VSOCK) {
2340Sstevel@tonic-gate 		releasef(sock);
2350Sstevel@tonic-gate 		*errorp = ENOTSOCK;
2360Sstevel@tonic-gate 		eprintline(*errorp);
2370Sstevel@tonic-gate 		return (NULL);
2380Sstevel@tonic-gate 	}
2390Sstevel@tonic-gate 	/*
2400Sstevel@tonic-gate 	 * Use the stream head to find the real socket vnode.
2410Sstevel@tonic-gate 	 * This is needed when namefs sits above sockfs.
2420Sstevel@tonic-gate 	 */
2430Sstevel@tonic-gate 	if (vp->v_stream) {
2440Sstevel@tonic-gate 		ASSERT(vp->v_stream->sd_vnode);
2450Sstevel@tonic-gate 		vp = vp->v_stream->sd_vnode;
2460Sstevel@tonic-gate 
2470Sstevel@tonic-gate 		so = VTOSO(vp);
2480Sstevel@tonic-gate 		if (so->so_version == SOV_STREAM) {
2490Sstevel@tonic-gate 			releasef(sock);
2500Sstevel@tonic-gate 			*errorp = ENOTSOCK;
2510Sstevel@tonic-gate 			eprintsoline(so, *errorp);
2520Sstevel@tonic-gate 			return (NULL);
2530Sstevel@tonic-gate 		}
2540Sstevel@tonic-gate 	} else {
2550Sstevel@tonic-gate 		so = VTOSO(vp);
2560Sstevel@tonic-gate 	}
2570Sstevel@tonic-gate 	if (fpp)
2580Sstevel@tonic-gate 		*fpp = fp;
2590Sstevel@tonic-gate 	return (so);
2600Sstevel@tonic-gate }
2610Sstevel@tonic-gate 
2620Sstevel@tonic-gate /*
2630Sstevel@tonic-gate  * Allocate and copyin a sockaddr.
2640Sstevel@tonic-gate  * Ensures NULL termination for AF_UNIX addresses by extending them
2650Sstevel@tonic-gate  * with one NULL byte if need be. Verifies that the length is not
2660Sstevel@tonic-gate  * excessive to prevent an application from consuming all of kernel
2670Sstevel@tonic-gate  * memory. Returns NULL when an error occurred.
2680Sstevel@tonic-gate  */
2690Sstevel@tonic-gate static struct sockaddr *
2700Sstevel@tonic-gate copyin_name(struct sonode *so, struct sockaddr *name, socklen_t *namelenp,
2710Sstevel@tonic-gate 	    int *errorp)
2720Sstevel@tonic-gate {
2730Sstevel@tonic-gate 	char	*faddr;
2740Sstevel@tonic-gate 	size_t	namelen = (size_t)*namelenp;
2750Sstevel@tonic-gate 
2760Sstevel@tonic-gate 	ASSERT(namelen != 0);
2770Sstevel@tonic-gate 	if (namelen > SO_MAXARGSIZE) {
2780Sstevel@tonic-gate 		*errorp = EINVAL;
2790Sstevel@tonic-gate 		eprintsoline(so, *errorp);
2800Sstevel@tonic-gate 		return (NULL);
2810Sstevel@tonic-gate 	}
2820Sstevel@tonic-gate 
2830Sstevel@tonic-gate 	faddr = (char *)kmem_alloc(namelen, KM_SLEEP);
2840Sstevel@tonic-gate 	if (copyin(name, faddr, namelen)) {
2850Sstevel@tonic-gate 		kmem_free(faddr, namelen);
2860Sstevel@tonic-gate 		*errorp = EFAULT;
2870Sstevel@tonic-gate 		eprintsoline(so, *errorp);
2880Sstevel@tonic-gate 		return (NULL);
2890Sstevel@tonic-gate 	}
2900Sstevel@tonic-gate 
2910Sstevel@tonic-gate 	/*
2920Sstevel@tonic-gate 	 * Add space for NULL termination if needed.
2930Sstevel@tonic-gate 	 * Do a quick check if the last byte is NUL.
2940Sstevel@tonic-gate 	 */
2950Sstevel@tonic-gate 	if (so->so_family == AF_UNIX && faddr[namelen - 1] != '\0') {
2960Sstevel@tonic-gate 		/* Check if there is any NULL termination */
2970Sstevel@tonic-gate 		size_t	i;
2980Sstevel@tonic-gate 		int foundnull = 0;
2990Sstevel@tonic-gate 
3000Sstevel@tonic-gate 		for (i = sizeof (name->sa_family); i < namelen; i++) {
3010Sstevel@tonic-gate 			if (faddr[i] == '\0') {
3020Sstevel@tonic-gate 				foundnull = 1;
3030Sstevel@tonic-gate 				break;
3040Sstevel@tonic-gate 			}
3050Sstevel@tonic-gate 		}
3060Sstevel@tonic-gate 		if (!foundnull) {
3070Sstevel@tonic-gate 			/* Add extra byte for NUL padding */
3080Sstevel@tonic-gate 			char *nfaddr;
3090Sstevel@tonic-gate 
3100Sstevel@tonic-gate 			nfaddr = (char *)kmem_alloc(namelen + 1, KM_SLEEP);
3110Sstevel@tonic-gate 			bcopy(faddr, nfaddr, namelen);
3120Sstevel@tonic-gate 			kmem_free(faddr, namelen);
3130Sstevel@tonic-gate 
3140Sstevel@tonic-gate 			/* NUL terminate */
3150Sstevel@tonic-gate 			nfaddr[namelen] = '\0';
3160Sstevel@tonic-gate 			namelen++;
3170Sstevel@tonic-gate 			ASSERT((socklen_t)namelen == namelen);
3180Sstevel@tonic-gate 			*namelenp = (socklen_t)namelen;
3190Sstevel@tonic-gate 			faddr = nfaddr;
3200Sstevel@tonic-gate 		}
3210Sstevel@tonic-gate 	}
3220Sstevel@tonic-gate 	return ((struct sockaddr *)faddr);
3230Sstevel@tonic-gate }
3240Sstevel@tonic-gate 
3250Sstevel@tonic-gate /*
3260Sstevel@tonic-gate  * Copy from kaddr/klen to uaddr/ulen. Updates ulenp if non-NULL.
3270Sstevel@tonic-gate  */
3280Sstevel@tonic-gate static int
3290Sstevel@tonic-gate copyout_arg(void *uaddr, socklen_t ulen, void *ulenp,
3300Sstevel@tonic-gate 		void *kaddr, socklen_t klen)
3310Sstevel@tonic-gate {
3320Sstevel@tonic-gate 	if (uaddr != NULL) {
3330Sstevel@tonic-gate 		if (ulen > klen)
3340Sstevel@tonic-gate 			ulen = klen;
3350Sstevel@tonic-gate 
3360Sstevel@tonic-gate 		if (ulen != 0) {
3370Sstevel@tonic-gate 			if (copyout(kaddr, uaddr, ulen))
3380Sstevel@tonic-gate 				return (EFAULT);
3390Sstevel@tonic-gate 		}
3400Sstevel@tonic-gate 	} else
3410Sstevel@tonic-gate 		ulen = 0;
3420Sstevel@tonic-gate 
3430Sstevel@tonic-gate 	if (ulenp != NULL) {
3440Sstevel@tonic-gate 		if (copyout(&ulen, ulenp, sizeof (ulen)))
3450Sstevel@tonic-gate 			return (EFAULT);
3460Sstevel@tonic-gate 	}
3470Sstevel@tonic-gate 	return (0);
3480Sstevel@tonic-gate }
3490Sstevel@tonic-gate 
3500Sstevel@tonic-gate /*
3510Sstevel@tonic-gate  * Copy from kaddr/klen to uaddr/ulen. Updates ulenp if non-NULL.
3520Sstevel@tonic-gate  * If klen is greater than ulen it still uses the non-truncated
3530Sstevel@tonic-gate  * klen to update ulenp.
3540Sstevel@tonic-gate  */
3550Sstevel@tonic-gate static int
3560Sstevel@tonic-gate copyout_name(void *uaddr, socklen_t ulen, void *ulenp,
3570Sstevel@tonic-gate 		void *kaddr, socklen_t klen)
3580Sstevel@tonic-gate {
3590Sstevel@tonic-gate 	if (uaddr != NULL) {
3600Sstevel@tonic-gate 		if (ulen >= klen)
3610Sstevel@tonic-gate 			ulen = klen;
3620Sstevel@tonic-gate 		else if (ulen != 0 && xnet_truncate_print) {
3630Sstevel@tonic-gate 			printf("sockfs: truncating copyout of address using "
3640Sstevel@tonic-gate 			    "XNET semantics for pid = %d. Lengths %d, %d\n",
3650Sstevel@tonic-gate 			    curproc->p_pid, klen, ulen);
3660Sstevel@tonic-gate 		}
3670Sstevel@tonic-gate 
3680Sstevel@tonic-gate 		if (ulen != 0) {
3690Sstevel@tonic-gate 			if (copyout(kaddr, uaddr, ulen))
3700Sstevel@tonic-gate 				return (EFAULT);
3710Sstevel@tonic-gate 		} else
3720Sstevel@tonic-gate 			klen = 0;
3730Sstevel@tonic-gate 	} else
3740Sstevel@tonic-gate 		klen = 0;
3750Sstevel@tonic-gate 
3760Sstevel@tonic-gate 	if (ulenp != NULL) {
3770Sstevel@tonic-gate 		if (copyout(&klen, ulenp, sizeof (klen)))
3780Sstevel@tonic-gate 			return (EFAULT);
3790Sstevel@tonic-gate 	}
3800Sstevel@tonic-gate 	return (0);
3810Sstevel@tonic-gate }
3820Sstevel@tonic-gate 
3830Sstevel@tonic-gate /*
3840Sstevel@tonic-gate  * The socketpair() code in libsocket creates two sockets (using
3850Sstevel@tonic-gate  * the /etc/netconfig fallback if needed) before calling this routine
3860Sstevel@tonic-gate  * to connect the two sockets together.
3870Sstevel@tonic-gate  *
3880Sstevel@tonic-gate  * For a SOCK_STREAM socketpair a listener is needed - in that case this
3890Sstevel@tonic-gate  * routine will create a new file descriptor as part of accepting the
3900Sstevel@tonic-gate  * connection. The library socketpair() will check if svs[2] has changed
3910Sstevel@tonic-gate  * in which case it will close the changed fd.
3920Sstevel@tonic-gate  *
3930Sstevel@tonic-gate  * Note that this code could use the TPI feature of accepting the connection
3940Sstevel@tonic-gate  * on the listening endpoint. However, that would require significant changes
3950Sstevel@tonic-gate  * to soaccept.
3960Sstevel@tonic-gate  */
3970Sstevel@tonic-gate int
3980Sstevel@tonic-gate so_socketpair(int sv[2])
3990Sstevel@tonic-gate {
4000Sstevel@tonic-gate 	int svs[2];
4010Sstevel@tonic-gate 	struct sonode *so1, *so2;
4020Sstevel@tonic-gate 	int error;
4030Sstevel@tonic-gate 	struct sockaddr_ux *name;
4040Sstevel@tonic-gate 	size_t namelen;
4050Sstevel@tonic-gate 
4067240Srh87107 	dprint(1, ("so_socketpair(%p)\n", (void *)sv));
4070Sstevel@tonic-gate 
4080Sstevel@tonic-gate 	error = useracc(sv, sizeof (svs), B_WRITE);
4090Sstevel@tonic-gate 	if (error && do_useracc)
4100Sstevel@tonic-gate 		return (set_errno(EFAULT));
4110Sstevel@tonic-gate 
4120Sstevel@tonic-gate 	if (copyin(sv, svs, sizeof (svs)))
4130Sstevel@tonic-gate 		return (set_errno(EFAULT));
4140Sstevel@tonic-gate 
4150Sstevel@tonic-gate 	if ((so1 = getsonode(svs[0], &error, NULL)) == NULL)
4160Sstevel@tonic-gate 		return (set_errno(error));
4170Sstevel@tonic-gate 
4180Sstevel@tonic-gate 	if ((so2 = getsonode(svs[1], &error, NULL)) == NULL) {
4190Sstevel@tonic-gate 		releasef(svs[0]);
4200Sstevel@tonic-gate 		return (set_errno(error));
4210Sstevel@tonic-gate 	}
4220Sstevel@tonic-gate 
4230Sstevel@tonic-gate 	if (so1->so_family != AF_UNIX || so2->so_family != AF_UNIX) {
4240Sstevel@tonic-gate 		error = EOPNOTSUPP;
4250Sstevel@tonic-gate 		goto done;
4260Sstevel@tonic-gate 	}
4270Sstevel@tonic-gate 
4280Sstevel@tonic-gate 	/*
4290Sstevel@tonic-gate 	 * The code below makes assumptions about the "sockfs" implementation.
4300Sstevel@tonic-gate 	 * So make sure that the correct implementation is really used.
4310Sstevel@tonic-gate 	 */
4320Sstevel@tonic-gate 	ASSERT(so1->so_ops == &sotpi_sonodeops);
4330Sstevel@tonic-gate 	ASSERT(so2->so_ops == &sotpi_sonodeops);
4340Sstevel@tonic-gate 
4350Sstevel@tonic-gate 	if (so1->so_type == SOCK_DGRAM) {
4360Sstevel@tonic-gate 		/*
4370Sstevel@tonic-gate 		 * Bind both sockets and connect them with each other.
4380Sstevel@tonic-gate 		 * Need to allocate name/namelen for soconnect.
4390Sstevel@tonic-gate 		 */
4400Sstevel@tonic-gate 		error = SOP_BIND(so1, NULL, 0, _SOBIND_UNSPEC);
4410Sstevel@tonic-gate 		if (error) {
4420Sstevel@tonic-gate 			eprintsoline(so1, error);
4430Sstevel@tonic-gate 			goto done;
4440Sstevel@tonic-gate 		}
4450Sstevel@tonic-gate 		error = SOP_BIND(so2, NULL, 0, _SOBIND_UNSPEC);
4460Sstevel@tonic-gate 		if (error) {
4470Sstevel@tonic-gate 			eprintsoline(so2, error);
4480Sstevel@tonic-gate 			goto done;
4490Sstevel@tonic-gate 		}
4500Sstevel@tonic-gate 		namelen = sizeof (struct sockaddr_ux);
4510Sstevel@tonic-gate 		name = kmem_alloc(namelen, KM_SLEEP);
4520Sstevel@tonic-gate 		name->sou_family = AF_UNIX;
4530Sstevel@tonic-gate 		name->sou_addr = so2->so_ux_laddr;
4540Sstevel@tonic-gate 		error = SOP_CONNECT(so1,
4555227Stz204579 		    (struct sockaddr *)name,
4565227Stz204579 		    (socklen_t)namelen,
4575227Stz204579 		    0, _SOCONNECT_NOXLATE);
4580Sstevel@tonic-gate 		if (error) {
4590Sstevel@tonic-gate 			kmem_free(name, namelen);
4600Sstevel@tonic-gate 			eprintsoline(so1, error);
4610Sstevel@tonic-gate 			goto done;
4620Sstevel@tonic-gate 		}
4630Sstevel@tonic-gate 		name->sou_addr = so1->so_ux_laddr;
4640Sstevel@tonic-gate 		error = SOP_CONNECT(so2,
4655227Stz204579 		    (struct sockaddr *)name,
4665227Stz204579 		    (socklen_t)namelen,
4675227Stz204579 		    0, _SOCONNECT_NOXLATE);
4680Sstevel@tonic-gate 		kmem_free(name, namelen);
4690Sstevel@tonic-gate 		if (error) {
4700Sstevel@tonic-gate 			eprintsoline(so2, error);
4710Sstevel@tonic-gate 			goto done;
4720Sstevel@tonic-gate 		}
4730Sstevel@tonic-gate 		releasef(svs[0]);
4740Sstevel@tonic-gate 		releasef(svs[1]);
4750Sstevel@tonic-gate 	} else {
4760Sstevel@tonic-gate 		/*
4770Sstevel@tonic-gate 		 * Bind both sockets, with so1 being a listener.
4780Sstevel@tonic-gate 		 * Connect so2 to so1 - nonblocking to avoid waiting for
4790Sstevel@tonic-gate 		 * soaccept to complete.
4800Sstevel@tonic-gate 		 * Accept a connection on so1. Pass out the new fd as sv[0].
4810Sstevel@tonic-gate 		 * The library will detect the changed fd and close
4820Sstevel@tonic-gate 		 * the original one.
4830Sstevel@tonic-gate 		 */
4840Sstevel@tonic-gate 		struct sonode *nso;
4850Sstevel@tonic-gate 		struct vnode *nvp;
4860Sstevel@tonic-gate 		struct file *nfp;
4870Sstevel@tonic-gate 		int nfd;
4880Sstevel@tonic-gate 
4890Sstevel@tonic-gate 		/*
4900Sstevel@tonic-gate 		 * We could simply call SOP_LISTEN() here (which would do the
4910Sstevel@tonic-gate 		 * binding automatically) if the code didn't rely on passing
4920Sstevel@tonic-gate 		 * _SOBIND_NOXLATE to the TPI implementation of SOP_BIND().
4930Sstevel@tonic-gate 		 */
4940Sstevel@tonic-gate 		error = SOP_BIND(so1, NULL, 0, _SOBIND_UNSPEC|_SOBIND_NOXLATE|
4950Sstevel@tonic-gate 		    _SOBIND_LISTEN|_SOBIND_SOCKETPAIR);
4960Sstevel@tonic-gate 		if (error) {
4970Sstevel@tonic-gate 			eprintsoline(so1, error);
4980Sstevel@tonic-gate 			goto done;
4990Sstevel@tonic-gate 		}
5000Sstevel@tonic-gate 		error = SOP_BIND(so2, NULL, 0, _SOBIND_UNSPEC);
5010Sstevel@tonic-gate 		if (error) {
5020Sstevel@tonic-gate 			eprintsoline(so2, error);
5030Sstevel@tonic-gate 			goto done;
5040Sstevel@tonic-gate 		}
5050Sstevel@tonic-gate 
5060Sstevel@tonic-gate 		namelen = sizeof (struct sockaddr_ux);
5070Sstevel@tonic-gate 		name = kmem_alloc(namelen, KM_SLEEP);
5080Sstevel@tonic-gate 		name->sou_family = AF_UNIX;
5090Sstevel@tonic-gate 		name->sou_addr = so1->so_ux_laddr;
5100Sstevel@tonic-gate 		error = SOP_CONNECT(so2,
5115227Stz204579 		    (struct sockaddr *)name,
5125227Stz204579 		    (socklen_t)namelen,
5135227Stz204579 		    FNONBLOCK, _SOCONNECT_NOXLATE);
5140Sstevel@tonic-gate 		kmem_free(name, namelen);
5150Sstevel@tonic-gate 		if (error) {
5160Sstevel@tonic-gate 			if (error != EINPROGRESS) {
5170Sstevel@tonic-gate 				eprintsoline(so2, error);
5180Sstevel@tonic-gate 				goto done;
5190Sstevel@tonic-gate 			}
5200Sstevel@tonic-gate 		}
5210Sstevel@tonic-gate 
5220Sstevel@tonic-gate 		error = SOP_ACCEPT(so1, 0, &nso);
5230Sstevel@tonic-gate 		if (error) {
5240Sstevel@tonic-gate 			eprintsoline(so1, error);
5250Sstevel@tonic-gate 			goto done;
5260Sstevel@tonic-gate 		}
5270Sstevel@tonic-gate 
5280Sstevel@tonic-gate 		/* wait for so2 being SS_CONNECTED ignoring signals */
5290Sstevel@tonic-gate 		mutex_enter(&so2->so_lock);
5300Sstevel@tonic-gate 		error = sowaitconnected(so2, 0, 1);
5310Sstevel@tonic-gate 		mutex_exit(&so2->so_lock);
5320Sstevel@tonic-gate 		nvp = SOTOV(nso);
5330Sstevel@tonic-gate 		if (error != 0) {
5345331Samw 			(void) VOP_CLOSE(nvp, 0, 1, 0, CRED(), NULL);
5350Sstevel@tonic-gate 			VN_RELE(nvp);
5360Sstevel@tonic-gate 			eprintsoline(so2, error);
5370Sstevel@tonic-gate 			goto done;
5380Sstevel@tonic-gate 		}
5390Sstevel@tonic-gate 
5400Sstevel@tonic-gate 		if (error = falloc(nvp, FWRITE|FREAD, &nfp, &nfd)) {
5415331Samw 			(void) VOP_CLOSE(nvp, 0, 1, 0, CRED(), NULL);
5420Sstevel@tonic-gate 			VN_RELE(nvp);
5430Sstevel@tonic-gate 			eprintsoline(nso, error);
5440Sstevel@tonic-gate 			goto done;
5450Sstevel@tonic-gate 		}
5460Sstevel@tonic-gate 		/*
5470Sstevel@tonic-gate 		 * fill in the entries that falloc reserved
5480Sstevel@tonic-gate 		 */
5490Sstevel@tonic-gate 		mutex_exit(&nfp->f_tlock);
5500Sstevel@tonic-gate 		setf(nfd, nfp);
5510Sstevel@tonic-gate 
5520Sstevel@tonic-gate 		releasef(svs[0]);
5530Sstevel@tonic-gate 		releasef(svs[1]);
5540Sstevel@tonic-gate 		svs[0] = nfd;
5550Sstevel@tonic-gate 
5560Sstevel@tonic-gate 		/*
5570Sstevel@tonic-gate 		 * The socketpair library routine will close the original
5580Sstevel@tonic-gate 		 * svs[0] when this code passes out a different file
5590Sstevel@tonic-gate 		 * descriptor.
5600Sstevel@tonic-gate 		 */
5610Sstevel@tonic-gate 		if (copyout(svs, sv, sizeof (svs))) {
5620Sstevel@tonic-gate 			(void) closeandsetf(nfd, NULL);
5630Sstevel@tonic-gate 			eprintline(EFAULT);
5640Sstevel@tonic-gate 			return (set_errno(EFAULT));
5650Sstevel@tonic-gate 		}
5660Sstevel@tonic-gate 	}
5670Sstevel@tonic-gate 	return (0);
5680Sstevel@tonic-gate 
5690Sstevel@tonic-gate done:
5700Sstevel@tonic-gate 	releasef(svs[0]);
5710Sstevel@tonic-gate 	releasef(svs[1]);
5720Sstevel@tonic-gate 	return (set_errno(error));
5730Sstevel@tonic-gate }
5740Sstevel@tonic-gate 
5750Sstevel@tonic-gate int
5760Sstevel@tonic-gate bind(int sock, struct sockaddr *name, socklen_t namelen, int version)
5770Sstevel@tonic-gate {
5780Sstevel@tonic-gate 	struct sonode *so;
5790Sstevel@tonic-gate 	int error;
5800Sstevel@tonic-gate 
5810Sstevel@tonic-gate 	dprint(1, ("bind(%d, %p, %d)\n",
5827240Srh87107 	    sock, (void *)name, namelen));
5830Sstevel@tonic-gate 
5840Sstevel@tonic-gate 	if ((so = getsonode(sock, &error, NULL)) == NULL)
5850Sstevel@tonic-gate 		return (set_errno(error));
5860Sstevel@tonic-gate 
5870Sstevel@tonic-gate 	/* Allocate and copyin name */
5880Sstevel@tonic-gate 	/*
5890Sstevel@tonic-gate 	 * X/Open test does not expect EFAULT with NULL name and non-zero
5900Sstevel@tonic-gate 	 * namelen.
5910Sstevel@tonic-gate 	 */
5920Sstevel@tonic-gate 	if (name != NULL && namelen != 0) {
5930Sstevel@tonic-gate 		ASSERT(MUTEX_NOT_HELD(&so->so_lock));
5940Sstevel@tonic-gate 		name = copyin_name(so, name, &namelen, &error);
5950Sstevel@tonic-gate 		if (name == NULL) {
5960Sstevel@tonic-gate 			releasef(sock);
5970Sstevel@tonic-gate 			return (set_errno(error));
5980Sstevel@tonic-gate 		}
5990Sstevel@tonic-gate 	} else {
6000Sstevel@tonic-gate 		name = NULL;
6010Sstevel@tonic-gate 		namelen = 0;
6020Sstevel@tonic-gate 	}
6030Sstevel@tonic-gate 
6040Sstevel@tonic-gate 	switch (version) {
6050Sstevel@tonic-gate 	default:
6060Sstevel@tonic-gate 		error = SOP_BIND(so, name, namelen, 0);
6070Sstevel@tonic-gate 		break;
6080Sstevel@tonic-gate 	case SOV_XPG4_2:
6090Sstevel@tonic-gate 		error = SOP_BIND(so, name, namelen, _SOBIND_XPG4_2);
6100Sstevel@tonic-gate 		break;
6110Sstevel@tonic-gate 	case SOV_SOCKBSD:
6120Sstevel@tonic-gate 		error = SOP_BIND(so, name, namelen, _SOBIND_SOCKBSD);
6130Sstevel@tonic-gate 		break;
6140Sstevel@tonic-gate 	}
6150Sstevel@tonic-gate done:
6160Sstevel@tonic-gate 	releasef(sock);
6170Sstevel@tonic-gate 	if (name != NULL)
6180Sstevel@tonic-gate 		kmem_free(name, (size_t)namelen);
6190Sstevel@tonic-gate 
6200Sstevel@tonic-gate 	if (error)
6210Sstevel@tonic-gate 		return (set_errno(error));
6220Sstevel@tonic-gate 	return (0);
6230Sstevel@tonic-gate }
6240Sstevel@tonic-gate 
6250Sstevel@tonic-gate /* ARGSUSED2 */
6260Sstevel@tonic-gate int
6270Sstevel@tonic-gate listen(int sock, int backlog, int version)
6280Sstevel@tonic-gate {
6290Sstevel@tonic-gate 	struct sonode *so;
6300Sstevel@tonic-gate 	int error;
6310Sstevel@tonic-gate 
6320Sstevel@tonic-gate 	dprint(1, ("listen(%d, %d)\n",
6335227Stz204579 	    sock, backlog));
6340Sstevel@tonic-gate 
6350Sstevel@tonic-gate 	if ((so = getsonode(sock, &error, NULL)) == NULL)
6360Sstevel@tonic-gate 		return (set_errno(error));
6370Sstevel@tonic-gate 
6380Sstevel@tonic-gate 	error = SOP_LISTEN(so, backlog);
6390Sstevel@tonic-gate 
6400Sstevel@tonic-gate 	releasef(sock);
6410Sstevel@tonic-gate 	if (error)
6420Sstevel@tonic-gate 		return (set_errno(error));
6430Sstevel@tonic-gate 	return (0);
6440Sstevel@tonic-gate }
6450Sstevel@tonic-gate 
6460Sstevel@tonic-gate /*ARGSUSED3*/
6470Sstevel@tonic-gate int
6480Sstevel@tonic-gate accept(int sock, struct sockaddr *name, socklen_t *namelenp, int version)
6490Sstevel@tonic-gate {
6500Sstevel@tonic-gate 	struct sonode *so;
6510Sstevel@tonic-gate 	file_t *fp;
6520Sstevel@tonic-gate 	int error;
6530Sstevel@tonic-gate 	socklen_t namelen;
6540Sstevel@tonic-gate 	struct sonode *nso;
6550Sstevel@tonic-gate 	struct vnode *nvp;
6560Sstevel@tonic-gate 	struct file *nfp;
6570Sstevel@tonic-gate 	int nfd;
6580Sstevel@tonic-gate 
6590Sstevel@tonic-gate 	dprint(1, ("accept(%d, %p, %p)\n",
6607240Srh87107 	    sock, (void *)name, (void *)namelenp));
6610Sstevel@tonic-gate 
6620Sstevel@tonic-gate 	if ((so = getsonode(sock, &error, &fp)) == NULL)
6630Sstevel@tonic-gate 		return (set_errno(error));
6640Sstevel@tonic-gate 
6650Sstevel@tonic-gate 	if (name != NULL) {
6660Sstevel@tonic-gate 		ASSERT(MUTEX_NOT_HELD(&so->so_lock));
6670Sstevel@tonic-gate 		if (copyin(namelenp, &namelen, sizeof (namelen))) {
6680Sstevel@tonic-gate 			releasef(sock);
6690Sstevel@tonic-gate 			return (set_errno(EFAULT));
6700Sstevel@tonic-gate 		}
6710Sstevel@tonic-gate 		if (namelen != 0) {
6720Sstevel@tonic-gate 			error = useracc(name, (size_t)namelen, B_WRITE);
6730Sstevel@tonic-gate 			if (error && do_useracc) {
6740Sstevel@tonic-gate 				releasef(sock);
6750Sstevel@tonic-gate 				return (set_errno(EFAULT));
6760Sstevel@tonic-gate 			}
6770Sstevel@tonic-gate 		} else
6780Sstevel@tonic-gate 			name = NULL;
6790Sstevel@tonic-gate 	} else {
6800Sstevel@tonic-gate 		namelen = 0;
6810Sstevel@tonic-gate 	}
6820Sstevel@tonic-gate 
6830Sstevel@tonic-gate 	/*
6840Sstevel@tonic-gate 	 * Allocate the user fd before SOP_ACCEPT() in order to
6850Sstevel@tonic-gate 	 * catch EMFILE errors before calling SOP_ACCEPT().
6860Sstevel@tonic-gate 	 */
6870Sstevel@tonic-gate 	if ((nfd = ufalloc(0)) == -1) {
6880Sstevel@tonic-gate 		eprintsoline(so, EMFILE);
6890Sstevel@tonic-gate 		releasef(sock);
6900Sstevel@tonic-gate 		return (set_errno(EMFILE));
6910Sstevel@tonic-gate 	}
6920Sstevel@tonic-gate 	error = SOP_ACCEPT(so, fp->f_flag, &nso);
6930Sstevel@tonic-gate 	releasef(sock);
6940Sstevel@tonic-gate 	if (error) {
6950Sstevel@tonic-gate 		setf(nfd, NULL);
6960Sstevel@tonic-gate 		return (set_errno(error));
6970Sstevel@tonic-gate 	}
6980Sstevel@tonic-gate 
6990Sstevel@tonic-gate 	nvp = SOTOV(nso);
7000Sstevel@tonic-gate 
7010Sstevel@tonic-gate 	/*
7020Sstevel@tonic-gate 	 * so_faddr_sa can not go away even though we are not holding so_lock.
7030Sstevel@tonic-gate 	 * However, in theory its content could change from underneath us.
7040Sstevel@tonic-gate 	 * But this is not possible in practice since it can only
7050Sstevel@tonic-gate 	 * change due to either some socket system call
7060Sstevel@tonic-gate 	 * or due to a T_CONN_CON being received from the stream head.
7070Sstevel@tonic-gate 	 * Since the falloc/setf have not yet been done no thread
7080Sstevel@tonic-gate 	 * can do any system call on nso and T_CONN_CON can not arrive
7090Sstevel@tonic-gate 	 * on a socket that is already connected.
7100Sstevel@tonic-gate 	 * Thus there is no reason to hold so_lock here.
7110Sstevel@tonic-gate 	 *
7120Sstevel@tonic-gate 	 * SOP_ACCEPT() is required to have set the valid bit for the faddr,
7130Sstevel@tonic-gate 	 * but it could be instantly cleared by a disconnect from the transport.
7140Sstevel@tonic-gate 	 * For that reason we ignore it here.
7150Sstevel@tonic-gate 	 */
7160Sstevel@tonic-gate 	ASSERT(MUTEX_NOT_HELD(&nso->so_lock));
7170Sstevel@tonic-gate 	error = copyout_name(name, namelen, namelenp,
7180Sstevel@tonic-gate 	    nso->so_faddr_sa, (socklen_t)nso->so_faddr_len);
7190Sstevel@tonic-gate 	if (error) {
7200Sstevel@tonic-gate 		setf(nfd, NULL);
7215331Samw 		(void) VOP_CLOSE(nvp, 0, 1, 0, CRED(), NULL);
7220Sstevel@tonic-gate 		VN_RELE(nvp);
7230Sstevel@tonic-gate 		return (set_errno(error));
7240Sstevel@tonic-gate 	}
7250Sstevel@tonic-gate 	if (error = falloc(NULL, FWRITE|FREAD, &nfp, NULL)) {
7260Sstevel@tonic-gate 		setf(nfd, NULL);
7275331Samw 		(void) VOP_CLOSE(nvp, 0, 1, 0, CRED(), NULL);
7280Sstevel@tonic-gate 		VN_RELE(nvp);
7290Sstevel@tonic-gate 		eprintsoline(so, error);
7300Sstevel@tonic-gate 		return (set_errno(error));
7310Sstevel@tonic-gate 	}
7320Sstevel@tonic-gate 	/*
7330Sstevel@tonic-gate 	 * fill in the entries that falloc reserved
7340Sstevel@tonic-gate 	 */
7350Sstevel@tonic-gate 	nfp->f_vnode = nvp;
7360Sstevel@tonic-gate 	mutex_exit(&nfp->f_tlock);
7370Sstevel@tonic-gate 	setf(nfd, nfp);
7380Sstevel@tonic-gate 
7390Sstevel@tonic-gate 	/*
7400Sstevel@tonic-gate 	 * Copy FNDELAY and FNONBLOCK from listener to acceptor
7410Sstevel@tonic-gate 	 */
7420Sstevel@tonic-gate 	if (so->so_state & (SS_NDELAY|SS_NONBLOCK)) {
7430Sstevel@tonic-gate 		uint_t oflag = nfp->f_flag;
7440Sstevel@tonic-gate 		int arg = 0;
7450Sstevel@tonic-gate 
7460Sstevel@tonic-gate 		if (so->so_state & SS_NONBLOCK)
7470Sstevel@tonic-gate 			arg |= FNONBLOCK;
7480Sstevel@tonic-gate 		else if (so->so_state & SS_NDELAY)
7490Sstevel@tonic-gate 			arg |= FNDELAY;
7500Sstevel@tonic-gate 
7510Sstevel@tonic-gate 		/*
7520Sstevel@tonic-gate 		 * This code is a simplification of the F_SETFL code in fcntl()
7530Sstevel@tonic-gate 		 * Ignore any errors from VOP_SETFL.
7540Sstevel@tonic-gate 		 */
7555331Samw 		if ((error = VOP_SETFL(nvp, oflag, arg, nfp->f_cred, NULL))
7565331Samw 		    != 0) {
7570Sstevel@tonic-gate 			eprintsoline(so, error);
7580Sstevel@tonic-gate 			error = 0;
7590Sstevel@tonic-gate 		} else {
7600Sstevel@tonic-gate 			mutex_enter(&nfp->f_tlock);
7610Sstevel@tonic-gate 			nfp->f_flag &= ~FMASK | (FREAD|FWRITE);
7620Sstevel@tonic-gate 			nfp->f_flag |= arg;
7630Sstevel@tonic-gate 			mutex_exit(&nfp->f_tlock);
7640Sstevel@tonic-gate 		}
7650Sstevel@tonic-gate 	}
7660Sstevel@tonic-gate 	return (nfd);
7670Sstevel@tonic-gate }
7680Sstevel@tonic-gate 
7690Sstevel@tonic-gate int
7700Sstevel@tonic-gate connect(int sock, struct sockaddr *name, socklen_t namelen, int version)
7710Sstevel@tonic-gate {
7720Sstevel@tonic-gate 	struct sonode *so;
7730Sstevel@tonic-gate 	file_t *fp;
7740Sstevel@tonic-gate 	int error;
7750Sstevel@tonic-gate 
7760Sstevel@tonic-gate 	dprint(1, ("connect(%d, %p, %d)\n",
7777240Srh87107 	    sock, (void *)name, namelen));
7780Sstevel@tonic-gate 
7790Sstevel@tonic-gate 	if ((so = getsonode(sock, &error, &fp)) == NULL)
7800Sstevel@tonic-gate 		return (set_errno(error));
7810Sstevel@tonic-gate 
7820Sstevel@tonic-gate 	/* Allocate and copyin name */
7830Sstevel@tonic-gate 	if (namelen != 0) {
7840Sstevel@tonic-gate 		ASSERT(MUTEX_NOT_HELD(&so->so_lock));
7850Sstevel@tonic-gate 		name = copyin_name(so, name, &namelen, &error);
7860Sstevel@tonic-gate 		if (name == NULL) {
7870Sstevel@tonic-gate 			releasef(sock);
7880Sstevel@tonic-gate 			return (set_errno(error));
7890Sstevel@tonic-gate 		}
7900Sstevel@tonic-gate 	} else
7910Sstevel@tonic-gate 		name = NULL;
7920Sstevel@tonic-gate 
7930Sstevel@tonic-gate 	error = SOP_CONNECT(so, name, namelen, fp->f_flag,
7940Sstevel@tonic-gate 	    (version != SOV_XPG4_2) ? 0 : _SOCONNECT_XPG4_2);
7950Sstevel@tonic-gate 	releasef(sock);
7960Sstevel@tonic-gate 	if (name)
7970Sstevel@tonic-gate 		kmem_free(name, (size_t)namelen);
7980Sstevel@tonic-gate 	if (error)
7990Sstevel@tonic-gate 		return (set_errno(error));
8000Sstevel@tonic-gate 	return (0);
8010Sstevel@tonic-gate }
8020Sstevel@tonic-gate 
8030Sstevel@tonic-gate /*ARGSUSED2*/
8040Sstevel@tonic-gate int
8050Sstevel@tonic-gate shutdown(int sock, int how, int version)
8060Sstevel@tonic-gate {
8070Sstevel@tonic-gate 	struct sonode *so;
8080Sstevel@tonic-gate 	int error;
8090Sstevel@tonic-gate 
8100Sstevel@tonic-gate 	dprint(1, ("shutdown(%d, %d)\n",
8115227Stz204579 	    sock, how));
8120Sstevel@tonic-gate 
8130Sstevel@tonic-gate 	if ((so = getsonode(sock, &error, NULL)) == NULL)
8140Sstevel@tonic-gate 		return (set_errno(error));
8150Sstevel@tonic-gate 
8160Sstevel@tonic-gate 	error = SOP_SHUTDOWN(so, how);
8170Sstevel@tonic-gate 
8180Sstevel@tonic-gate 	releasef(sock);
8190Sstevel@tonic-gate 	if (error)
8200Sstevel@tonic-gate 		return (set_errno(error));
8210Sstevel@tonic-gate 	return (0);
8220Sstevel@tonic-gate }
8230Sstevel@tonic-gate 
8240Sstevel@tonic-gate /*
8250Sstevel@tonic-gate  * Common receive routine.
8260Sstevel@tonic-gate  */
8270Sstevel@tonic-gate static ssize_t
8280Sstevel@tonic-gate recvit(int sock,
8290Sstevel@tonic-gate 	struct nmsghdr *msg,
8300Sstevel@tonic-gate 	struct uio *uiop,
8310Sstevel@tonic-gate 	int flags,
8320Sstevel@tonic-gate 	socklen_t *namelenp,
8330Sstevel@tonic-gate 	socklen_t *controllenp,
8340Sstevel@tonic-gate 	int *flagsp)
8350Sstevel@tonic-gate {
8360Sstevel@tonic-gate 	struct sonode *so;
8370Sstevel@tonic-gate 	file_t *fp;
8380Sstevel@tonic-gate 	void *name;
8390Sstevel@tonic-gate 	socklen_t namelen;
8400Sstevel@tonic-gate 	void *control;
8410Sstevel@tonic-gate 	socklen_t controllen;
8420Sstevel@tonic-gate 	ssize_t len;
8430Sstevel@tonic-gate 	int error;
8440Sstevel@tonic-gate 
8450Sstevel@tonic-gate 	if ((so = getsonode(sock, &error, &fp)) == NULL)
8460Sstevel@tonic-gate 		return (set_errno(error));
8470Sstevel@tonic-gate 
8480Sstevel@tonic-gate 	len = uiop->uio_resid;
8490Sstevel@tonic-gate 	uiop->uio_fmode = fp->f_flag;
8500Sstevel@tonic-gate 	uiop->uio_extflg = UIO_COPY_CACHED;
8510Sstevel@tonic-gate 
8520Sstevel@tonic-gate 	name = msg->msg_name;
8530Sstevel@tonic-gate 	namelen = msg->msg_namelen;
8540Sstevel@tonic-gate 	control = msg->msg_control;
8550Sstevel@tonic-gate 	controllen = msg->msg_controllen;
8560Sstevel@tonic-gate 
8570Sstevel@tonic-gate 	msg->msg_flags = flags & (MSG_OOB | MSG_PEEK | MSG_WAITALL |
8580Sstevel@tonic-gate 	    MSG_DONTWAIT | MSG_XPG4_2);
8590Sstevel@tonic-gate 
8600Sstevel@tonic-gate 	error = SOP_RECVMSG(so, msg, uiop);
8610Sstevel@tonic-gate 	if (error) {
8620Sstevel@tonic-gate 		releasef(sock);
8630Sstevel@tonic-gate 		return (set_errno(error));
8640Sstevel@tonic-gate 	}
8650Sstevel@tonic-gate 	lwp_stat_update(LWP_STAT_MSGRCV, 1);
8660Sstevel@tonic-gate 	so_update_attrs(so, SOACC);
8670Sstevel@tonic-gate 	releasef(sock);
8680Sstevel@tonic-gate 
8690Sstevel@tonic-gate 	error = copyout_name(name, namelen, namelenp,
8700Sstevel@tonic-gate 	    msg->msg_name, msg->msg_namelen);
8710Sstevel@tonic-gate 	if (error)
8720Sstevel@tonic-gate 		goto err;
8730Sstevel@tonic-gate 
8740Sstevel@tonic-gate 	if (flagsp != NULL) {
8750Sstevel@tonic-gate 		/*
8760Sstevel@tonic-gate 		 * Clear internal flag.
8770Sstevel@tonic-gate 		 */
8780Sstevel@tonic-gate 		msg->msg_flags &= ~MSG_XPG4_2;
8790Sstevel@tonic-gate 
8800Sstevel@tonic-gate 		/*
8810Sstevel@tonic-gate 		 * Determine MSG_CTRUNC. sorecvmsg sets MSG_CTRUNC only
8820Sstevel@tonic-gate 		 * when controllen is zero and there is control data to
8830Sstevel@tonic-gate 		 * copy out.
8840Sstevel@tonic-gate 		 */
8850Sstevel@tonic-gate 		if (controllen != 0 &&
8860Sstevel@tonic-gate 		    (msg->msg_controllen > controllen || control == NULL)) {
8870Sstevel@tonic-gate 			dprint(1, ("recvit: CTRUNC %d %d %p\n",
8880Sstevel@tonic-gate 			    msg->msg_controllen, controllen, control));
8890Sstevel@tonic-gate 
8900Sstevel@tonic-gate 			msg->msg_flags |= MSG_CTRUNC;
8910Sstevel@tonic-gate 		}
8920Sstevel@tonic-gate 		if (copyout(&msg->msg_flags, flagsp,
8930Sstevel@tonic-gate 		    sizeof (msg->msg_flags))) {
8940Sstevel@tonic-gate 			error = EFAULT;
8950Sstevel@tonic-gate 			goto err;
8960Sstevel@tonic-gate 		}
8970Sstevel@tonic-gate 	}
8980Sstevel@tonic-gate 	/*
8990Sstevel@tonic-gate 	 * Note: This MUST be done last. There can be no "goto err" after this
9000Sstevel@tonic-gate 	 * point since it could make so_closefds run twice on some part
9010Sstevel@tonic-gate 	 * of the file descriptor array.
9020Sstevel@tonic-gate 	 */
9030Sstevel@tonic-gate 	if (controllen != 0) {
9040Sstevel@tonic-gate 		if (!(flags & MSG_XPG4_2)) {
9050Sstevel@tonic-gate 			/*
9060Sstevel@tonic-gate 			 * Good old msg_accrights can only return a multiple
9070Sstevel@tonic-gate 			 * of 4 bytes.
9080Sstevel@tonic-gate 			 */
9090Sstevel@tonic-gate 			controllen &= ~((int)sizeof (uint32_t) - 1);
9100Sstevel@tonic-gate 		}
9110Sstevel@tonic-gate 		error = copyout_arg(control, controllen, controllenp,
9120Sstevel@tonic-gate 		    msg->msg_control, msg->msg_controllen);
9130Sstevel@tonic-gate 		if (error)
9140Sstevel@tonic-gate 			goto err;
9150Sstevel@tonic-gate 
9160Sstevel@tonic-gate 		if (msg->msg_controllen > controllen || control == NULL) {
9170Sstevel@tonic-gate 			if (control == NULL)
9180Sstevel@tonic-gate 				controllen = 0;
9190Sstevel@tonic-gate 			so_closefds(msg->msg_control, msg->msg_controllen,
9200Sstevel@tonic-gate 			    !(flags & MSG_XPG4_2), controllen);
9210Sstevel@tonic-gate 		}
9220Sstevel@tonic-gate 	}
9230Sstevel@tonic-gate 	if (msg->msg_namelen != 0)
9240Sstevel@tonic-gate 		kmem_free(msg->msg_name, (size_t)msg->msg_namelen);
9250Sstevel@tonic-gate 	if (msg->msg_controllen != 0)
9260Sstevel@tonic-gate 		kmem_free(msg->msg_control, (size_t)msg->msg_controllen);
9270Sstevel@tonic-gate 	return (len - uiop->uio_resid);
9280Sstevel@tonic-gate 
9290Sstevel@tonic-gate err:
9300Sstevel@tonic-gate 	/*
9310Sstevel@tonic-gate 	 * If we fail and the control part contains file descriptors
9320Sstevel@tonic-gate 	 * we have to close the fd's.
9330Sstevel@tonic-gate 	 */
9340Sstevel@tonic-gate 	if (msg->msg_controllen != 0)
9350Sstevel@tonic-gate 		so_closefds(msg->msg_control, msg->msg_controllen,
9360Sstevel@tonic-gate 		    !(flags & MSG_XPG4_2), 0);
9370Sstevel@tonic-gate 	if (msg->msg_namelen != 0)
9380Sstevel@tonic-gate 		kmem_free(msg->msg_name, (size_t)msg->msg_namelen);
9390Sstevel@tonic-gate 	if (msg->msg_controllen != 0)
9400Sstevel@tonic-gate 		kmem_free(msg->msg_control, (size_t)msg->msg_controllen);
9410Sstevel@tonic-gate 	return (set_errno(error));
9420Sstevel@tonic-gate }
9430Sstevel@tonic-gate 
9440Sstevel@tonic-gate /*
9450Sstevel@tonic-gate  * Native system call
9460Sstevel@tonic-gate  */
9470Sstevel@tonic-gate ssize_t
9480Sstevel@tonic-gate recv(int sock, void *buffer, size_t len, int flags)
9490Sstevel@tonic-gate {
9500Sstevel@tonic-gate 	struct nmsghdr lmsg;
9510Sstevel@tonic-gate 	struct uio auio;
9520Sstevel@tonic-gate 	struct iovec aiov[1];
9530Sstevel@tonic-gate 
9540Sstevel@tonic-gate 	dprint(1, ("recv(%d, %p, %ld, %d)\n",
9555227Stz204579 	    sock, buffer, len, flags));
9560Sstevel@tonic-gate 
9570Sstevel@tonic-gate 	if ((ssize_t)len < 0) {
9580Sstevel@tonic-gate 		return (set_errno(EINVAL));
9590Sstevel@tonic-gate 	}
9600Sstevel@tonic-gate 
9610Sstevel@tonic-gate 	aiov[0].iov_base = buffer;
9620Sstevel@tonic-gate 	aiov[0].iov_len = len;
9630Sstevel@tonic-gate 	auio.uio_loffset = 0;
9640Sstevel@tonic-gate 	auio.uio_iov = aiov;
9650Sstevel@tonic-gate 	auio.uio_iovcnt = 1;
9660Sstevel@tonic-gate 	auio.uio_resid = len;
9670Sstevel@tonic-gate 	auio.uio_segflg = UIO_USERSPACE;
9680Sstevel@tonic-gate 	auio.uio_limit = 0;
9690Sstevel@tonic-gate 
9700Sstevel@tonic-gate 	lmsg.msg_namelen = 0;
9710Sstevel@tonic-gate 	lmsg.msg_controllen = 0;
9720Sstevel@tonic-gate 	lmsg.msg_flags = 0;
9730Sstevel@tonic-gate 	return (recvit(sock, &lmsg, &auio, flags, NULL, NULL, NULL));
9740Sstevel@tonic-gate }
9750Sstevel@tonic-gate 
9760Sstevel@tonic-gate ssize_t
9770Sstevel@tonic-gate recvfrom(int sock, void *buffer, size_t len, int flags,
9780Sstevel@tonic-gate 	struct sockaddr *name, socklen_t *namelenp)
9790Sstevel@tonic-gate {
9800Sstevel@tonic-gate 	struct nmsghdr lmsg;
9810Sstevel@tonic-gate 	struct uio auio;
9820Sstevel@tonic-gate 	struct iovec aiov[1];
9830Sstevel@tonic-gate 
9840Sstevel@tonic-gate 	dprint(1, ("recvfrom(%d, %p, %ld, %d, %p, %p)\n",
9857240Srh87107 	    sock, buffer, len, flags, (void *)name, (void *)namelenp));
9860Sstevel@tonic-gate 
9870Sstevel@tonic-gate 	if ((ssize_t)len < 0) {
9880Sstevel@tonic-gate 		return (set_errno(EINVAL));
9890Sstevel@tonic-gate 	}
9900Sstevel@tonic-gate 
9910Sstevel@tonic-gate 	aiov[0].iov_base = buffer;
9920Sstevel@tonic-gate 	aiov[0].iov_len = len;
9930Sstevel@tonic-gate 	auio.uio_loffset = 0;
9940Sstevel@tonic-gate 	auio.uio_iov = aiov;
9950Sstevel@tonic-gate 	auio.uio_iovcnt = 1;
9960Sstevel@tonic-gate 	auio.uio_resid = len;
9970Sstevel@tonic-gate 	auio.uio_segflg = UIO_USERSPACE;
9980Sstevel@tonic-gate 	auio.uio_limit = 0;
9990Sstevel@tonic-gate 
10000Sstevel@tonic-gate 	lmsg.msg_name = (char *)name;
10010Sstevel@tonic-gate 	if (namelenp != NULL) {
10020Sstevel@tonic-gate 		if (copyin(namelenp, &lmsg.msg_namelen,
10030Sstevel@tonic-gate 		    sizeof (lmsg.msg_namelen)))
10040Sstevel@tonic-gate 			return (set_errno(EFAULT));
10050Sstevel@tonic-gate 	} else {
10060Sstevel@tonic-gate 		lmsg.msg_namelen = 0;
10070Sstevel@tonic-gate 	}
10080Sstevel@tonic-gate 	lmsg.msg_controllen = 0;
10090Sstevel@tonic-gate 	lmsg.msg_flags = 0;
10100Sstevel@tonic-gate 
10110Sstevel@tonic-gate 	return (recvit(sock, &lmsg, &auio, flags, namelenp, NULL, NULL));
10120Sstevel@tonic-gate }
10130Sstevel@tonic-gate 
10140Sstevel@tonic-gate /*
10150Sstevel@tonic-gate  * Uses the MSG_XPG4_2 flag to determine if the caller is using
10160Sstevel@tonic-gate  * struct omsghdr or struct nmsghdr.
10170Sstevel@tonic-gate  */
10180Sstevel@tonic-gate ssize_t
10190Sstevel@tonic-gate recvmsg(int sock, struct nmsghdr *msg, int flags)
10200Sstevel@tonic-gate {
10210Sstevel@tonic-gate 	STRUCT_DECL(nmsghdr, u_lmsg);
10220Sstevel@tonic-gate 	STRUCT_HANDLE(nmsghdr, umsgptr);
10230Sstevel@tonic-gate 	struct nmsghdr lmsg;
10240Sstevel@tonic-gate 	struct uio auio;
10250Sstevel@tonic-gate 	struct iovec aiov[MSG_MAXIOVLEN];
10260Sstevel@tonic-gate 	int iovcnt;
10270Sstevel@tonic-gate 	ssize_t len;
10280Sstevel@tonic-gate 	int i;
10290Sstevel@tonic-gate 	int *flagsp;
10300Sstevel@tonic-gate 	model_t	model;
10310Sstevel@tonic-gate 
10320Sstevel@tonic-gate 	dprint(1, ("recvmsg(%d, %p, %d)\n",
10337240Srh87107 	    sock, (void *)msg, flags));
10340Sstevel@tonic-gate 
10350Sstevel@tonic-gate 	model = get_udatamodel();
10360Sstevel@tonic-gate 	STRUCT_INIT(u_lmsg, model);
10370Sstevel@tonic-gate 	STRUCT_SET_HANDLE(umsgptr, model, msg);
10380Sstevel@tonic-gate 
10390Sstevel@tonic-gate 	if (flags & MSG_XPG4_2) {
10400Sstevel@tonic-gate 		if (copyin(msg, STRUCT_BUF(u_lmsg), STRUCT_SIZE(u_lmsg)))
10410Sstevel@tonic-gate 			return (set_errno(EFAULT));
10420Sstevel@tonic-gate 		flagsp = STRUCT_FADDR(umsgptr, msg_flags);
10430Sstevel@tonic-gate 	} else {
10440Sstevel@tonic-gate 		/*
10450Sstevel@tonic-gate 		 * Assumes that nmsghdr and omsghdr are identically shaped
10460Sstevel@tonic-gate 		 * except for the added msg_flags field.
10470Sstevel@tonic-gate 		 */
10480Sstevel@tonic-gate 		if (copyin(msg, STRUCT_BUF(u_lmsg),
10490Sstevel@tonic-gate 		    SIZEOF_STRUCT(omsghdr, model)))
10500Sstevel@tonic-gate 			return (set_errno(EFAULT));
10510Sstevel@tonic-gate 		STRUCT_FSET(u_lmsg, msg_flags, 0);
10520Sstevel@tonic-gate 		flagsp = NULL;
10530Sstevel@tonic-gate 	}
10540Sstevel@tonic-gate 
10550Sstevel@tonic-gate 	/*
10560Sstevel@tonic-gate 	 * Code below us will kmem_alloc memory and hang it
10570Sstevel@tonic-gate 	 * off msg_control and msg_name fields. This forces
10580Sstevel@tonic-gate 	 * us to copy the structure to its native form.
10590Sstevel@tonic-gate 	 */
10600Sstevel@tonic-gate 	lmsg.msg_name = STRUCT_FGETP(u_lmsg, msg_name);
10610Sstevel@tonic-gate 	lmsg.msg_namelen = STRUCT_FGET(u_lmsg, msg_namelen);
10620Sstevel@tonic-gate 	lmsg.msg_iov = STRUCT_FGETP(u_lmsg, msg_iov);
10630Sstevel@tonic-gate 	lmsg.msg_iovlen = STRUCT_FGET(u_lmsg, msg_iovlen);
10640Sstevel@tonic-gate 	lmsg.msg_control = STRUCT_FGETP(u_lmsg, msg_control);
10650Sstevel@tonic-gate 	lmsg.msg_controllen = STRUCT_FGET(u_lmsg, msg_controllen);
10660Sstevel@tonic-gate 	lmsg.msg_flags = STRUCT_FGET(u_lmsg, msg_flags);
10670Sstevel@tonic-gate 
10680Sstevel@tonic-gate 	iovcnt = lmsg.msg_iovlen;
10690Sstevel@tonic-gate 
10700Sstevel@tonic-gate 	if (iovcnt <= 0 || iovcnt > MSG_MAXIOVLEN) {
10710Sstevel@tonic-gate 		return (set_errno(EMSGSIZE));
10720Sstevel@tonic-gate 	}
10730Sstevel@tonic-gate 
10740Sstevel@tonic-gate #ifdef _SYSCALL32_IMPL
10750Sstevel@tonic-gate 	/*
10760Sstevel@tonic-gate 	 * 32-bit callers need to have their iovec expanded, while ensuring
10770Sstevel@tonic-gate 	 * that they can't move more than 2Gbytes of data in a single call.
10780Sstevel@tonic-gate 	 */
10790Sstevel@tonic-gate 	if (model == DATAMODEL_ILP32) {
10800Sstevel@tonic-gate 		struct iovec32 aiov32[MSG_MAXIOVLEN];
10810Sstevel@tonic-gate 		ssize32_t count32;
10820Sstevel@tonic-gate 
10830Sstevel@tonic-gate 		if (copyin((struct iovec32 *)lmsg.msg_iov, aiov32,
10840Sstevel@tonic-gate 		    iovcnt * sizeof (struct iovec32)))
10850Sstevel@tonic-gate 			return (set_errno(EFAULT));
10860Sstevel@tonic-gate 
10870Sstevel@tonic-gate 		count32 = 0;
10880Sstevel@tonic-gate 		for (i = 0; i < iovcnt; i++) {
10890Sstevel@tonic-gate 			ssize32_t iovlen32;
10900Sstevel@tonic-gate 
10910Sstevel@tonic-gate 			iovlen32 = aiov32[i].iov_len;
10920Sstevel@tonic-gate 			count32 += iovlen32;
10930Sstevel@tonic-gate 			if (iovlen32 < 0 || count32 < 0)
10940Sstevel@tonic-gate 				return (set_errno(EINVAL));
10950Sstevel@tonic-gate 			aiov[i].iov_len = iovlen32;
10960Sstevel@tonic-gate 			aiov[i].iov_base =
10970Sstevel@tonic-gate 			    (caddr_t)(uintptr_t)aiov32[i].iov_base;
10980Sstevel@tonic-gate 		}
10990Sstevel@tonic-gate 	} else
11000Sstevel@tonic-gate #endif /* _SYSCALL32_IMPL */
11010Sstevel@tonic-gate 	if (copyin(lmsg.msg_iov, aiov, iovcnt * sizeof (struct iovec))) {
11020Sstevel@tonic-gate 		return (set_errno(EFAULT));
11030Sstevel@tonic-gate 	}
11040Sstevel@tonic-gate 	len = 0;
11050Sstevel@tonic-gate 	for (i = 0; i < iovcnt; i++) {
11060Sstevel@tonic-gate 		ssize_t iovlen = aiov[i].iov_len;
11070Sstevel@tonic-gate 		len += iovlen;
11080Sstevel@tonic-gate 		if (iovlen < 0 || len < 0) {
11090Sstevel@tonic-gate 			return (set_errno(EINVAL));
11100Sstevel@tonic-gate 		}
11110Sstevel@tonic-gate 	}
11120Sstevel@tonic-gate 	auio.uio_loffset = 0;
11130Sstevel@tonic-gate 	auio.uio_iov = aiov;
11140Sstevel@tonic-gate 	auio.uio_iovcnt = iovcnt;
11150Sstevel@tonic-gate 	auio.uio_resid = len;
11160Sstevel@tonic-gate 	auio.uio_segflg = UIO_USERSPACE;
11170Sstevel@tonic-gate 	auio.uio_limit = 0;
11180Sstevel@tonic-gate 
11190Sstevel@tonic-gate 	if (lmsg.msg_control != NULL &&
11200Sstevel@tonic-gate 	    (do_useracc == 0 ||
11210Sstevel@tonic-gate 	    useracc(lmsg.msg_control, lmsg.msg_controllen,
11225227Stz204579 	    B_WRITE) != 0)) {
11230Sstevel@tonic-gate 		return (set_errno(EFAULT));
11240Sstevel@tonic-gate 	}
11250Sstevel@tonic-gate 
11260Sstevel@tonic-gate 	return (recvit(sock, &lmsg, &auio, flags,
11275227Stz204579 	    STRUCT_FADDR(umsgptr, msg_namelen),
11285227Stz204579 	    STRUCT_FADDR(umsgptr, msg_controllen), flagsp));
11290Sstevel@tonic-gate }
11300Sstevel@tonic-gate 
11310Sstevel@tonic-gate /*
11320Sstevel@tonic-gate  * Common send function.
11330Sstevel@tonic-gate  */
11340Sstevel@tonic-gate static ssize_t
11350Sstevel@tonic-gate sendit(int sock, struct nmsghdr *msg, struct uio *uiop, int flags)
11360Sstevel@tonic-gate {
11370Sstevel@tonic-gate 	struct sonode *so;
11380Sstevel@tonic-gate 	file_t *fp;
11390Sstevel@tonic-gate 	void *name;
11400Sstevel@tonic-gate 	socklen_t namelen;
11410Sstevel@tonic-gate 	void *control;
11420Sstevel@tonic-gate 	socklen_t controllen;
11430Sstevel@tonic-gate 	ssize_t len;
11440Sstevel@tonic-gate 	int error;
11450Sstevel@tonic-gate 
11460Sstevel@tonic-gate 	if ((so = getsonode(sock, &error, &fp)) == NULL)
11470Sstevel@tonic-gate 		return (set_errno(error));
11480Sstevel@tonic-gate 
11490Sstevel@tonic-gate 	uiop->uio_fmode = fp->f_flag;
11500Sstevel@tonic-gate 
11510Sstevel@tonic-gate 	if (so->so_family == AF_UNIX)
11520Sstevel@tonic-gate 		uiop->uio_extflg = UIO_COPY_CACHED;
11530Sstevel@tonic-gate 	else
11540Sstevel@tonic-gate 		uiop->uio_extflg = UIO_COPY_DEFAULT;
11550Sstevel@tonic-gate 
11560Sstevel@tonic-gate 	/* Allocate and copyin name and control */
11570Sstevel@tonic-gate 	name = msg->msg_name;
11580Sstevel@tonic-gate 	namelen = msg->msg_namelen;
11590Sstevel@tonic-gate 	if (name != NULL && namelen != 0) {
11600Sstevel@tonic-gate 		ASSERT(MUTEX_NOT_HELD(&so->so_lock));
11610Sstevel@tonic-gate 		name = copyin_name(so,
11625227Stz204579 		    (struct sockaddr *)name,
11635227Stz204579 		    &namelen, &error);
11640Sstevel@tonic-gate 		if (name == NULL)
11650Sstevel@tonic-gate 			goto done3;
11660Sstevel@tonic-gate 		/* copyin_name null terminates addresses for AF_UNIX */
11670Sstevel@tonic-gate 		msg->msg_namelen = namelen;
11680Sstevel@tonic-gate 		msg->msg_name = name;
11690Sstevel@tonic-gate 	} else {
11700Sstevel@tonic-gate 		msg->msg_name = name = NULL;
11710Sstevel@tonic-gate 		msg->msg_namelen = namelen = 0;
11720Sstevel@tonic-gate 	}
11730Sstevel@tonic-gate 
11740Sstevel@tonic-gate 	control = msg->msg_control;
11750Sstevel@tonic-gate 	controllen = msg->msg_controllen;
11760Sstevel@tonic-gate 	if ((control != NULL) && (controllen != 0)) {
11770Sstevel@tonic-gate 		/*
11780Sstevel@tonic-gate 		 * Verify that the length is not excessive to prevent
11790Sstevel@tonic-gate 		 * an application from consuming all of kernel memory.
11800Sstevel@tonic-gate 		 */
11810Sstevel@tonic-gate 		if (controllen > SO_MAXARGSIZE) {
11820Sstevel@tonic-gate 			error = EINVAL;
11830Sstevel@tonic-gate 			goto done2;
11840Sstevel@tonic-gate 		}
11850Sstevel@tonic-gate 		control = kmem_alloc(controllen, KM_SLEEP);
11860Sstevel@tonic-gate 
11870Sstevel@tonic-gate 		ASSERT(MUTEX_NOT_HELD(&so->so_lock));
11880Sstevel@tonic-gate 		if (copyin(msg->msg_control, control, controllen)) {
11890Sstevel@tonic-gate 			error = EFAULT;
11900Sstevel@tonic-gate 			goto done1;
11910Sstevel@tonic-gate 		}
11920Sstevel@tonic-gate 		msg->msg_control = control;
11930Sstevel@tonic-gate 	} else {
11940Sstevel@tonic-gate 		msg->msg_control = control = NULL;
11950Sstevel@tonic-gate 		msg->msg_controllen = controllen = 0;
11960Sstevel@tonic-gate 	}
11970Sstevel@tonic-gate 
11980Sstevel@tonic-gate 	len = uiop->uio_resid;
11990Sstevel@tonic-gate 	msg->msg_flags = flags;
12000Sstevel@tonic-gate 
12010Sstevel@tonic-gate 	error = SOP_SENDMSG(so, msg, uiop);
12020Sstevel@tonic-gate done1:
12030Sstevel@tonic-gate 	if (control != NULL)
12040Sstevel@tonic-gate 		kmem_free(control, controllen);
12050Sstevel@tonic-gate done2:
12060Sstevel@tonic-gate 	if (name != NULL)
12070Sstevel@tonic-gate 		kmem_free(name, namelen);
12080Sstevel@tonic-gate done3:
12090Sstevel@tonic-gate 	if (error != 0) {
12100Sstevel@tonic-gate 		releasef(sock);
12110Sstevel@tonic-gate 		return (set_errno(error));
12120Sstevel@tonic-gate 	}
12130Sstevel@tonic-gate 	lwp_stat_update(LWP_STAT_MSGSND, 1);
12140Sstevel@tonic-gate 	so_update_attrs(so, SOMOD);
12150Sstevel@tonic-gate 	releasef(sock);
12160Sstevel@tonic-gate 	return (len - uiop->uio_resid);
12170Sstevel@tonic-gate }
12180Sstevel@tonic-gate 
12190Sstevel@tonic-gate /*
12200Sstevel@tonic-gate  * Native system call
12210Sstevel@tonic-gate  */
12220Sstevel@tonic-gate ssize_t
12230Sstevel@tonic-gate send(int sock, void *buffer, size_t len, int flags)
12240Sstevel@tonic-gate {
12250Sstevel@tonic-gate 	struct nmsghdr lmsg;
12260Sstevel@tonic-gate 	struct uio auio;
12270Sstevel@tonic-gate 	struct iovec aiov[1];
12280Sstevel@tonic-gate 
12290Sstevel@tonic-gate 	dprint(1, ("send(%d, %p, %ld, %d)\n",
12305227Stz204579 	    sock, buffer, len, flags));
12310Sstevel@tonic-gate 
12320Sstevel@tonic-gate 	if ((ssize_t)len < 0) {
12330Sstevel@tonic-gate 		return (set_errno(EINVAL));
12340Sstevel@tonic-gate 	}
12350Sstevel@tonic-gate 
12360Sstevel@tonic-gate 	aiov[0].iov_base = buffer;
12370Sstevel@tonic-gate 	aiov[0].iov_len = len;
12380Sstevel@tonic-gate 	auio.uio_loffset = 0;
12390Sstevel@tonic-gate 	auio.uio_iov = aiov;
12400Sstevel@tonic-gate 	auio.uio_iovcnt = 1;
12410Sstevel@tonic-gate 	auio.uio_resid = len;
12420Sstevel@tonic-gate 	auio.uio_segflg = UIO_USERSPACE;
12430Sstevel@tonic-gate 	auio.uio_limit = 0;
12440Sstevel@tonic-gate 
12450Sstevel@tonic-gate 	lmsg.msg_name = NULL;
12460Sstevel@tonic-gate 	lmsg.msg_control = NULL;
12470Sstevel@tonic-gate 	if (!(flags & MSG_XPG4_2)) {
12480Sstevel@tonic-gate 		/*
12490Sstevel@tonic-gate 		 * In order to be compatible with the libsocket/sockmod
12500Sstevel@tonic-gate 		 * implementation we set EOR for all send* calls.
12510Sstevel@tonic-gate 		 */
12520Sstevel@tonic-gate 		flags |= MSG_EOR;
12530Sstevel@tonic-gate 	}
12540Sstevel@tonic-gate 	return (sendit(sock, &lmsg, &auio, flags));
12550Sstevel@tonic-gate }
12560Sstevel@tonic-gate 
12570Sstevel@tonic-gate /*
12580Sstevel@tonic-gate  * Uses the MSG_XPG4_2 flag to determine if the caller is using
12590Sstevel@tonic-gate  * struct omsghdr or struct nmsghdr.
12600Sstevel@tonic-gate  */
12610Sstevel@tonic-gate ssize_t
12620Sstevel@tonic-gate sendmsg(int sock, struct nmsghdr *msg, int flags)
12630Sstevel@tonic-gate {
12640Sstevel@tonic-gate 	struct nmsghdr lmsg;
12650Sstevel@tonic-gate 	STRUCT_DECL(nmsghdr, u_lmsg);
12660Sstevel@tonic-gate 	struct uio auio;
12670Sstevel@tonic-gate 	struct iovec aiov[MSG_MAXIOVLEN];
12680Sstevel@tonic-gate 	int iovcnt;
12690Sstevel@tonic-gate 	ssize_t len;
12700Sstevel@tonic-gate 	int i;
12710Sstevel@tonic-gate 	model_t	model;
12720Sstevel@tonic-gate 
12737240Srh87107 	dprint(1, ("sendmsg(%d, %p, %d)\n", sock, (void *)msg, flags));
12740Sstevel@tonic-gate 
12750Sstevel@tonic-gate 	model = get_udatamodel();
12760Sstevel@tonic-gate 	STRUCT_INIT(u_lmsg, model);
12770Sstevel@tonic-gate 
12780Sstevel@tonic-gate 	if (flags & MSG_XPG4_2) {
12790Sstevel@tonic-gate 		if (copyin(msg, (char *)STRUCT_BUF(u_lmsg),
12800Sstevel@tonic-gate 		    STRUCT_SIZE(u_lmsg)))
12810Sstevel@tonic-gate 			return (set_errno(EFAULT));
12820Sstevel@tonic-gate 	} else {
12830Sstevel@tonic-gate 		/*
12840Sstevel@tonic-gate 		 * Assumes that nmsghdr and omsghdr are identically shaped
12850Sstevel@tonic-gate 		 * except for the added msg_flags field.
12860Sstevel@tonic-gate 		 */
12870Sstevel@tonic-gate 		if (copyin(msg, (char *)STRUCT_BUF(u_lmsg),
12880Sstevel@tonic-gate 		    SIZEOF_STRUCT(omsghdr, model)))
12890Sstevel@tonic-gate 			return (set_errno(EFAULT));
12900Sstevel@tonic-gate 		/*
12910Sstevel@tonic-gate 		 * In order to be compatible with the libsocket/sockmod
12920Sstevel@tonic-gate 		 * implementation we set EOR for all send* calls.
12930Sstevel@tonic-gate 		 */
12940Sstevel@tonic-gate 		flags |= MSG_EOR;
12950Sstevel@tonic-gate 	}
12960Sstevel@tonic-gate 
12970Sstevel@tonic-gate 	/*
12980Sstevel@tonic-gate 	 * Code below us will kmem_alloc memory and hang it
12990Sstevel@tonic-gate 	 * off msg_control and msg_name fields. This forces
13000Sstevel@tonic-gate 	 * us to copy the structure to its native form.
13010Sstevel@tonic-gate 	 */
13020Sstevel@tonic-gate 	lmsg.msg_name = STRUCT_FGETP(u_lmsg, msg_name);
13030Sstevel@tonic-gate 	lmsg.msg_namelen = STRUCT_FGET(u_lmsg, msg_namelen);
13040Sstevel@tonic-gate 	lmsg.msg_iov = STRUCT_FGETP(u_lmsg, msg_iov);
13050Sstevel@tonic-gate 	lmsg.msg_iovlen = STRUCT_FGET(u_lmsg, msg_iovlen);
13060Sstevel@tonic-gate 	lmsg.msg_control = STRUCT_FGETP(u_lmsg, msg_control);
13070Sstevel@tonic-gate 	lmsg.msg_controllen = STRUCT_FGET(u_lmsg, msg_controllen);
13080Sstevel@tonic-gate 	lmsg.msg_flags = STRUCT_FGET(u_lmsg, msg_flags);
13090Sstevel@tonic-gate 
13100Sstevel@tonic-gate 	iovcnt = lmsg.msg_iovlen;
13110Sstevel@tonic-gate 
13120Sstevel@tonic-gate 	if (iovcnt <= 0 || iovcnt > MSG_MAXIOVLEN) {
13130Sstevel@tonic-gate 		/*
13140Sstevel@tonic-gate 		 * Unless this is XPG 4.2 we allow iovcnt == 0 to
13150Sstevel@tonic-gate 		 * be compatible with SunOS 4.X and 4.4BSD.
13160Sstevel@tonic-gate 		 */
13170Sstevel@tonic-gate 		if (iovcnt != 0 || (flags & MSG_XPG4_2))
13180Sstevel@tonic-gate 			return (set_errno(EMSGSIZE));
13190Sstevel@tonic-gate 	}
13200Sstevel@tonic-gate 
13210Sstevel@tonic-gate #ifdef _SYSCALL32_IMPL
13220Sstevel@tonic-gate 	/*
13230Sstevel@tonic-gate 	 * 32-bit callers need to have their iovec expanded, while ensuring
13240Sstevel@tonic-gate 	 * that they can't move more than 2Gbytes of data in a single call.
13250Sstevel@tonic-gate 	 */
13260Sstevel@tonic-gate 	if (model == DATAMODEL_ILP32) {
13270Sstevel@tonic-gate 		struct iovec32 aiov32[MSG_MAXIOVLEN];
13280Sstevel@tonic-gate 		ssize32_t count32;
13290Sstevel@tonic-gate 
13300Sstevel@tonic-gate 		if (iovcnt != 0 &&
13310Sstevel@tonic-gate 		    copyin((struct iovec32 *)lmsg.msg_iov, aiov32,
13320Sstevel@tonic-gate 		    iovcnt * sizeof (struct iovec32)))
13330Sstevel@tonic-gate 			return (set_errno(EFAULT));
13340Sstevel@tonic-gate 
13350Sstevel@tonic-gate 		count32 = 0;
13360Sstevel@tonic-gate 		for (i = 0; i < iovcnt; i++) {
13370Sstevel@tonic-gate 			ssize32_t iovlen32;
13380Sstevel@tonic-gate 
13390Sstevel@tonic-gate 			iovlen32 = aiov32[i].iov_len;
13400Sstevel@tonic-gate 			count32 += iovlen32;
13410Sstevel@tonic-gate 			if (iovlen32 < 0 || count32 < 0)
13420Sstevel@tonic-gate 				return (set_errno(EINVAL));
13430Sstevel@tonic-gate 			aiov[i].iov_len = iovlen32;
13440Sstevel@tonic-gate 			aiov[i].iov_base =
13450Sstevel@tonic-gate 			    (caddr_t)(uintptr_t)aiov32[i].iov_base;
13460Sstevel@tonic-gate 		}
13470Sstevel@tonic-gate 	} else
13480Sstevel@tonic-gate #endif /* _SYSCALL32_IMPL */
13490Sstevel@tonic-gate 	if (iovcnt != 0 &&
13500Sstevel@tonic-gate 	    copyin(lmsg.msg_iov, aiov,
13510Sstevel@tonic-gate 	    (unsigned)iovcnt * sizeof (struct iovec))) {
13520Sstevel@tonic-gate 		return (set_errno(EFAULT));
13530Sstevel@tonic-gate 	}
13540Sstevel@tonic-gate 	len = 0;
13550Sstevel@tonic-gate 	for (i = 0; i < iovcnt; i++) {
13560Sstevel@tonic-gate 		ssize_t iovlen = aiov[i].iov_len;
13570Sstevel@tonic-gate 		len += iovlen;
13580Sstevel@tonic-gate 		if (iovlen < 0 || len < 0) {
13590Sstevel@tonic-gate 			return (set_errno(EINVAL));
13600Sstevel@tonic-gate 		}
13610Sstevel@tonic-gate 	}
13620Sstevel@tonic-gate 	auio.uio_loffset = 0;
13630Sstevel@tonic-gate 	auio.uio_iov = aiov;
13640Sstevel@tonic-gate 	auio.uio_iovcnt = iovcnt;
13650Sstevel@tonic-gate 	auio.uio_resid = len;
13660Sstevel@tonic-gate 	auio.uio_segflg = UIO_USERSPACE;
13670Sstevel@tonic-gate 	auio.uio_limit = 0;
13680Sstevel@tonic-gate 
13690Sstevel@tonic-gate 	return (sendit(sock, &lmsg, &auio, flags));
13700Sstevel@tonic-gate }
13710Sstevel@tonic-gate 
13720Sstevel@tonic-gate ssize_t
13730Sstevel@tonic-gate sendto(int sock, void *buffer, size_t len, int flags,
13740Sstevel@tonic-gate     struct sockaddr *name, socklen_t namelen)
13750Sstevel@tonic-gate {
13760Sstevel@tonic-gate 	struct nmsghdr lmsg;
13770Sstevel@tonic-gate 	struct uio auio;
13780Sstevel@tonic-gate 	struct iovec aiov[1];
13790Sstevel@tonic-gate 
13800Sstevel@tonic-gate 	dprint(1, ("sendto(%d, %p, %ld, %d, %p, %d)\n",
13817240Srh87107 	    sock, buffer, len, flags, (void *)name, namelen));
13820Sstevel@tonic-gate 
13830Sstevel@tonic-gate 	if ((ssize_t)len < 0) {
13840Sstevel@tonic-gate 		return (set_errno(EINVAL));
13850Sstevel@tonic-gate 	}
13860Sstevel@tonic-gate 
13870Sstevel@tonic-gate 	aiov[0].iov_base = buffer;
13880Sstevel@tonic-gate 	aiov[0].iov_len = len;
13890Sstevel@tonic-gate 	auio.uio_loffset = 0;
13900Sstevel@tonic-gate 	auio.uio_iov = aiov;
13910Sstevel@tonic-gate 	auio.uio_iovcnt = 1;
13920Sstevel@tonic-gate 	auio.uio_resid = len;
13930Sstevel@tonic-gate 	auio.uio_segflg = UIO_USERSPACE;
13940Sstevel@tonic-gate 	auio.uio_limit = 0;
13950Sstevel@tonic-gate 
13960Sstevel@tonic-gate 	lmsg.msg_name = (char *)name;
13970Sstevel@tonic-gate 	lmsg.msg_namelen = namelen;
13980Sstevel@tonic-gate 	lmsg.msg_control = NULL;
13990Sstevel@tonic-gate 	if (!(flags & MSG_XPG4_2)) {
14000Sstevel@tonic-gate 		/*
14010Sstevel@tonic-gate 		 * In order to be compatible with the libsocket/sockmod
14020Sstevel@tonic-gate 		 * implementation we set EOR for all send* calls.
14030Sstevel@tonic-gate 		 */
14040Sstevel@tonic-gate 		flags |= MSG_EOR;
14050Sstevel@tonic-gate 	}
14060Sstevel@tonic-gate 	return (sendit(sock, &lmsg, &auio, flags));
14070Sstevel@tonic-gate }
14080Sstevel@tonic-gate 
14090Sstevel@tonic-gate /*ARGSUSED3*/
14100Sstevel@tonic-gate int
14110Sstevel@tonic-gate getpeername(int sock, struct sockaddr *name, socklen_t *namelenp, int version)
14120Sstevel@tonic-gate {
14130Sstevel@tonic-gate 	struct sonode *so;
14140Sstevel@tonic-gate 	int error;
14150Sstevel@tonic-gate 	socklen_t namelen;
14160Sstevel@tonic-gate 	union {
14170Sstevel@tonic-gate 		struct sockaddr_in sin;
14180Sstevel@tonic-gate 		struct sockaddr_in6 sin6;
14190Sstevel@tonic-gate 	} sin;			/* Temporary buffer, common case */
14200Sstevel@tonic-gate 	void *addr;		/* Temporary buffer, uncommon case */
14210Sstevel@tonic-gate 	socklen_t addrlen, size;
14220Sstevel@tonic-gate 
14230Sstevel@tonic-gate 	dprint(1, ("getpeername(%d, %p, %p)\n",
14247240Srh87107 	    sock, (void *)name, (void *)namelenp));
14250Sstevel@tonic-gate 
14260Sstevel@tonic-gate 	if ((so = getsonode(sock, &error, NULL)) == NULL)
14270Sstevel@tonic-gate 		goto bad;
14280Sstevel@tonic-gate 
14290Sstevel@tonic-gate 	ASSERT(MUTEX_NOT_HELD(&so->so_lock));
14300Sstevel@tonic-gate 	if (copyin(namelenp, &namelen, sizeof (namelen)) ||
14310Sstevel@tonic-gate 	    (name == NULL && namelen != 0)) {
14320Sstevel@tonic-gate 		error = EFAULT;
14330Sstevel@tonic-gate 		goto rel_out;
14340Sstevel@tonic-gate 	}
14350Sstevel@tonic-gate 	/*
14360Sstevel@tonic-gate 	 * If a connect or accept has been done, unless we're an Xnet socket,
14370Sstevel@tonic-gate 	 * the remote address has already been updated in so_faddr_sa.
14380Sstevel@tonic-gate 	 */
14390Sstevel@tonic-gate 	if (so->so_version != SOV_SOCKSTREAM && so->so_version != SOV_SOCKBSD ||
14400Sstevel@tonic-gate 	    !(so->so_state & SS_FADDR_VALID)) {
14410Sstevel@tonic-gate 		if ((error = SOP_GETPEERNAME(so)) != 0)
14420Sstevel@tonic-gate 			goto rel_out;
14430Sstevel@tonic-gate 	}
14440Sstevel@tonic-gate 
14450Sstevel@tonic-gate 	if (so->so_faddr_maxlen <= sizeof (sin)) {
14460Sstevel@tonic-gate 		size = 0;
14470Sstevel@tonic-gate 		addr = &sin;
14480Sstevel@tonic-gate 	} else {
14490Sstevel@tonic-gate 		/*
14500Sstevel@tonic-gate 		 * Allocate temporary to avoid holding so_lock across
14510Sstevel@tonic-gate 		 * copyout
14520Sstevel@tonic-gate 		 */
14530Sstevel@tonic-gate 		size = so->so_faddr_maxlen;
14540Sstevel@tonic-gate 		addr = kmem_alloc(size, KM_SLEEP);
14550Sstevel@tonic-gate 	}
14560Sstevel@tonic-gate 	/* Prevent so_faddr_sa/len from changing while accessed */
14570Sstevel@tonic-gate 	mutex_enter(&so->so_lock);
14580Sstevel@tonic-gate 	if (!(so->so_state & SS_ISCONNECTED)) {
14590Sstevel@tonic-gate 		mutex_exit(&so->so_lock);
14600Sstevel@tonic-gate 		error = ENOTCONN;
14610Sstevel@tonic-gate 		goto free_out;
14620Sstevel@tonic-gate 	}
14630Sstevel@tonic-gate 	addrlen = so->so_faddr_len;
14640Sstevel@tonic-gate 	bcopy(so->so_faddr_sa, addr, addrlen);
14650Sstevel@tonic-gate 	mutex_exit(&so->so_lock);
14660Sstevel@tonic-gate 
14670Sstevel@tonic-gate 	ASSERT(MUTEX_NOT_HELD(&so->so_lock));
14680Sstevel@tonic-gate 	error = copyout_name(name, namelen, namelenp, addr,
14690Sstevel@tonic-gate 	    (so->so_state & SS_FADDR_NOXLATE) ? 0 : addrlen);
14700Sstevel@tonic-gate free_out:
14710Sstevel@tonic-gate 	if (size != 0)
14720Sstevel@tonic-gate 		kmem_free(addr, size);
14730Sstevel@tonic-gate rel_out:
14740Sstevel@tonic-gate 	releasef(sock);
14750Sstevel@tonic-gate bad:	return (error != 0 ? set_errno(error) : 0);
14760Sstevel@tonic-gate }
14770Sstevel@tonic-gate 
14780Sstevel@tonic-gate /*ARGSUSED3*/
14790Sstevel@tonic-gate int
14800Sstevel@tonic-gate getsockname(int sock, struct sockaddr *name,
14810Sstevel@tonic-gate 		socklen_t *namelenp, int version)
14820Sstevel@tonic-gate {
14830Sstevel@tonic-gate 	struct sonode *so;
14840Sstevel@tonic-gate 	int error;
14850Sstevel@tonic-gate 	socklen_t namelen;
14860Sstevel@tonic-gate 	union {
14870Sstevel@tonic-gate 		struct sockaddr_in sin;
14880Sstevel@tonic-gate 		struct sockaddr_in6 sin6;
14890Sstevel@tonic-gate 	} sin;			/* Temporary buffer, common case */
14900Sstevel@tonic-gate 	void *addr;		/* Temporary buffer, uncommon case */
14910Sstevel@tonic-gate 	socklen_t addrlen, size;
14920Sstevel@tonic-gate 
14930Sstevel@tonic-gate 	dprint(1, ("getsockname(%d, %p, %p)\n",
14947240Srh87107 	    sock, (void *)name, (void *)namelenp));
14950Sstevel@tonic-gate 
14960Sstevel@tonic-gate 	if ((so = getsonode(sock, &error, NULL)) == NULL)
14970Sstevel@tonic-gate 		goto bad;
14980Sstevel@tonic-gate 
14990Sstevel@tonic-gate 	ASSERT(MUTEX_NOT_HELD(&so->so_lock));
15000Sstevel@tonic-gate 	if (copyin(namelenp, &namelen, sizeof (namelen)) ||
15010Sstevel@tonic-gate 	    (name == NULL && namelen != 0)) {
15020Sstevel@tonic-gate 		error = EFAULT;
15030Sstevel@tonic-gate 		goto rel_out;
15040Sstevel@tonic-gate 	}
15050Sstevel@tonic-gate 
15060Sstevel@tonic-gate 	/*
15070Sstevel@tonic-gate 	 * If a bind or accept has been done, unless we're an Xnet endpoint,
15080Sstevel@tonic-gate 	 * the local address has already been updated in so_laddr_sa.
15090Sstevel@tonic-gate 	 */
15100Sstevel@tonic-gate 	if ((so->so_version != SOV_SOCKSTREAM &&
15110Sstevel@tonic-gate 	    so->so_version != SOV_SOCKBSD) ||
15120Sstevel@tonic-gate 	    !(so->so_state & SS_LADDR_VALID)) {
15130Sstevel@tonic-gate 		if ((error = SOP_GETSOCKNAME(so)) != 0)
15140Sstevel@tonic-gate 			goto rel_out;
15150Sstevel@tonic-gate 	}
15160Sstevel@tonic-gate 
15170Sstevel@tonic-gate 	if (so->so_laddr_maxlen <= sizeof (sin)) {
15180Sstevel@tonic-gate 		size = 0;
15190Sstevel@tonic-gate 		addr = &sin;
15200Sstevel@tonic-gate 	} else {
15210Sstevel@tonic-gate 		/*
15220Sstevel@tonic-gate 		 * Allocate temporary to avoid holding so_lock across
15230Sstevel@tonic-gate 		 * copyout
15240Sstevel@tonic-gate 		 */
15250Sstevel@tonic-gate 		size = so->so_laddr_maxlen;
15260Sstevel@tonic-gate 		addr = kmem_alloc(size, KM_SLEEP);
15270Sstevel@tonic-gate 	}
15280Sstevel@tonic-gate 	/* Prevent so_laddr_sa/len from changing while accessed */
15290Sstevel@tonic-gate 	mutex_enter(&so->so_lock);
15300Sstevel@tonic-gate 	addrlen = so->so_laddr_len;
15310Sstevel@tonic-gate 	bcopy(so->so_laddr_sa, addr, addrlen);
15320Sstevel@tonic-gate 	mutex_exit(&so->so_lock);
15330Sstevel@tonic-gate 
15340Sstevel@tonic-gate 	ASSERT(MUTEX_NOT_HELD(&so->so_lock));
15350Sstevel@tonic-gate 	error = copyout_name(name, namelen, namelenp,
15360Sstevel@tonic-gate 	    addr, addrlen);
15370Sstevel@tonic-gate 	if (size != 0)
15380Sstevel@tonic-gate 		kmem_free(addr, size);
15390Sstevel@tonic-gate rel_out:
15400Sstevel@tonic-gate 	releasef(sock);
15410Sstevel@tonic-gate bad:	return (error != 0 ? set_errno(error) : 0);
15420Sstevel@tonic-gate }
15430Sstevel@tonic-gate 
15440Sstevel@tonic-gate /*ARGSUSED5*/
15450Sstevel@tonic-gate int
15460Sstevel@tonic-gate getsockopt(int sock,
15470Sstevel@tonic-gate 	int level,
15480Sstevel@tonic-gate 	int option_name,
15490Sstevel@tonic-gate 	void *option_value,
15500Sstevel@tonic-gate 	socklen_t *option_lenp,
15510Sstevel@tonic-gate 	int version)
15520Sstevel@tonic-gate {
15530Sstevel@tonic-gate 	struct sonode *so;
15540Sstevel@tonic-gate 	socklen_t optlen, optlen_res;
15550Sstevel@tonic-gate 	void *optval;
15560Sstevel@tonic-gate 	int error;
15570Sstevel@tonic-gate 
15580Sstevel@tonic-gate 	dprint(1, ("getsockopt(%d, %d, %d, %p, %p)\n",
15597240Srh87107 	    sock, level, option_name, option_value, (void *)option_lenp));
15600Sstevel@tonic-gate 
15610Sstevel@tonic-gate 	if ((so = getsonode(sock, &error, NULL)) == NULL)
15620Sstevel@tonic-gate 		return (set_errno(error));
15630Sstevel@tonic-gate 
15640Sstevel@tonic-gate 	ASSERT(MUTEX_NOT_HELD(&so->so_lock));
15650Sstevel@tonic-gate 	if (copyin(option_lenp, &optlen, sizeof (optlen))) {
15660Sstevel@tonic-gate 		releasef(sock);
15670Sstevel@tonic-gate 		return (set_errno(EFAULT));
15680Sstevel@tonic-gate 	}
15690Sstevel@tonic-gate 	/*
15700Sstevel@tonic-gate 	 * Verify that the length is not excessive to prevent
15710Sstevel@tonic-gate 	 * an application from consuming all of kernel memory.
15720Sstevel@tonic-gate 	 */
15730Sstevel@tonic-gate 	if (optlen > SO_MAXARGSIZE) {
15740Sstevel@tonic-gate 		error = EINVAL;
15750Sstevel@tonic-gate 		releasef(sock);
15760Sstevel@tonic-gate 		return (set_errno(error));
15770Sstevel@tonic-gate 	}
15780Sstevel@tonic-gate 	optval = kmem_alloc(optlen, KM_SLEEP);
15790Sstevel@tonic-gate 	optlen_res = optlen;
15800Sstevel@tonic-gate 	error = SOP_GETSOCKOPT(so, level, option_name, optval,
15810Sstevel@tonic-gate 	    &optlen_res, (version != SOV_XPG4_2) ? 0 : _SOGETSOCKOPT_XPG4_2);
15820Sstevel@tonic-gate 	releasef(sock);
15830Sstevel@tonic-gate 	if (error) {
15840Sstevel@tonic-gate 		kmem_free(optval, optlen);
15850Sstevel@tonic-gate 		return (set_errno(error));
15860Sstevel@tonic-gate 	}
15870Sstevel@tonic-gate 	error = copyout_arg(option_value, optlen, option_lenp,
15880Sstevel@tonic-gate 	    optval, optlen_res);
15890Sstevel@tonic-gate 	kmem_free(optval, optlen);
15900Sstevel@tonic-gate 	if (error)
15910Sstevel@tonic-gate 		return (set_errno(error));
15920Sstevel@tonic-gate 	return (0);
15930Sstevel@tonic-gate }
15940Sstevel@tonic-gate 
15950Sstevel@tonic-gate /*ARGSUSED5*/
15960Sstevel@tonic-gate int
15970Sstevel@tonic-gate setsockopt(int sock,
15980Sstevel@tonic-gate 	int level,
15990Sstevel@tonic-gate 	int option_name,
16000Sstevel@tonic-gate 	void *option_value,
16010Sstevel@tonic-gate 	socklen_t option_len,
16020Sstevel@tonic-gate 	int version)
16030Sstevel@tonic-gate {
16040Sstevel@tonic-gate 	struct sonode *so;
16050Sstevel@tonic-gate 	intptr_t buffer[2];
16060Sstevel@tonic-gate 	void *optval = NULL;
16070Sstevel@tonic-gate 	int error;
16080Sstevel@tonic-gate 
16090Sstevel@tonic-gate 	dprint(1, ("setsockopt(%d, %d, %d, %p, %d)\n",
16105227Stz204579 	    sock, level, option_name, option_value, option_len));
16110Sstevel@tonic-gate 
16120Sstevel@tonic-gate 	if ((so = getsonode(sock, &error, NULL)) == NULL)
16130Sstevel@tonic-gate 		return (set_errno(error));
16140Sstevel@tonic-gate 
16150Sstevel@tonic-gate 	if (option_value != NULL) {
16160Sstevel@tonic-gate 		if (option_len != 0) {
16170Sstevel@tonic-gate 			/*
16180Sstevel@tonic-gate 			 * Verify that the length is not excessive to prevent
16190Sstevel@tonic-gate 			 * an application from consuming all of kernel memory.
16200Sstevel@tonic-gate 			 */
16210Sstevel@tonic-gate 			if (option_len > SO_MAXARGSIZE) {
16220Sstevel@tonic-gate 				error = EINVAL;
16230Sstevel@tonic-gate 				goto done2;
16240Sstevel@tonic-gate 			}
16250Sstevel@tonic-gate 			optval = option_len <= sizeof (buffer) ?
16260Sstevel@tonic-gate 			    &buffer : kmem_alloc((size_t)option_len, KM_SLEEP);
16270Sstevel@tonic-gate 			ASSERT(MUTEX_NOT_HELD(&so->so_lock));
16280Sstevel@tonic-gate 			if (copyin(option_value, optval, (size_t)option_len)) {
16290Sstevel@tonic-gate 				error = EFAULT;
16300Sstevel@tonic-gate 				goto done1;
16310Sstevel@tonic-gate 			}
16320Sstevel@tonic-gate 		}
16330Sstevel@tonic-gate 	} else
16340Sstevel@tonic-gate 		option_len = 0;
16350Sstevel@tonic-gate 
16360Sstevel@tonic-gate 	error = SOP_SETSOCKOPT(so, level, option_name, optval,
16370Sstevel@tonic-gate 	    (t_uscalar_t)option_len);
16380Sstevel@tonic-gate done1:
16390Sstevel@tonic-gate 	if (optval != buffer)
16400Sstevel@tonic-gate 		kmem_free(optval, (size_t)option_len);
16410Sstevel@tonic-gate done2:
16420Sstevel@tonic-gate 	releasef(sock);
16430Sstevel@tonic-gate 	if (error)
16440Sstevel@tonic-gate 		return (set_errno(error));
16450Sstevel@tonic-gate 	return (0);
16460Sstevel@tonic-gate }
16470Sstevel@tonic-gate 
16480Sstevel@tonic-gate /*
16490Sstevel@tonic-gate  * Add config info when devpath is non-NULL; delete info when devpath is NULL.
16500Sstevel@tonic-gate  * devpath is a user address.
16510Sstevel@tonic-gate  */
16520Sstevel@tonic-gate int
16530Sstevel@tonic-gate sockconfig(int domain, int type, int protocol, char *devpath)
16540Sstevel@tonic-gate {
16550Sstevel@tonic-gate 	char *kdevpath;		/* Copied in devpath string */
16560Sstevel@tonic-gate 	size_t kdevpathlen;
16570Sstevel@tonic-gate 	int error = 0;
16580Sstevel@tonic-gate 
16590Sstevel@tonic-gate 	dprint(1, ("sockconfig(%d, %d, %d, %p)\n",
16607240Srh87107 	    domain, type, protocol, (void *)devpath));
16610Sstevel@tonic-gate 
16620Sstevel@tonic-gate 	if (secpolicy_net_config(CRED(), B_FALSE) != 0)
16630Sstevel@tonic-gate 		return (set_errno(EPERM));
16640Sstevel@tonic-gate 
16650Sstevel@tonic-gate 	if (devpath == NULL) {
16660Sstevel@tonic-gate 		/* Deleting an entry */
16670Sstevel@tonic-gate 		kdevpath = NULL;
16680Sstevel@tonic-gate 		kdevpathlen = 0;
16690Sstevel@tonic-gate 	} else {
16700Sstevel@tonic-gate 		/*
16710Sstevel@tonic-gate 		 * Adding an entry.
16720Sstevel@tonic-gate 		 * Copyin the devpath.
16730Sstevel@tonic-gate 		 * This also makes it possible to check for too long pathnames.
16740Sstevel@tonic-gate 		 * Compress the space needed for the devpath before passing it
16750Sstevel@tonic-gate 		 * to soconfig - soconfig will store the string until
16760Sstevel@tonic-gate 		 * the configuration is removed.
16770Sstevel@tonic-gate 		 */
16780Sstevel@tonic-gate 		char *buf;
16790Sstevel@tonic-gate 
16800Sstevel@tonic-gate 		buf = kmem_alloc(MAXPATHLEN, KM_SLEEP);
16810Sstevel@tonic-gate 		if ((error = copyinstr(devpath, buf, MAXPATHLEN,
16820Sstevel@tonic-gate 		    &kdevpathlen)) != 0) {
16830Sstevel@tonic-gate 			kmem_free(buf, MAXPATHLEN);
16840Sstevel@tonic-gate 			goto done;
16850Sstevel@tonic-gate 		}
16860Sstevel@tonic-gate 
16870Sstevel@tonic-gate 		kdevpath = kmem_alloc(kdevpathlen, KM_SLEEP);
16880Sstevel@tonic-gate 		bcopy(buf, kdevpath, kdevpathlen);
16890Sstevel@tonic-gate 		kdevpath[kdevpathlen - 1] = '\0';
16900Sstevel@tonic-gate 
16910Sstevel@tonic-gate 		kmem_free(buf, MAXPATHLEN);
16920Sstevel@tonic-gate 	}
16930Sstevel@tonic-gate 	error = soconfig(domain, type, protocol, kdevpath, (int)kdevpathlen);
16940Sstevel@tonic-gate done:
16950Sstevel@tonic-gate 	if (error) {
16960Sstevel@tonic-gate 		eprintline(error);
16970Sstevel@tonic-gate 		return (set_errno(error));
16980Sstevel@tonic-gate 	}
16990Sstevel@tonic-gate 	return (0);
17000Sstevel@tonic-gate }
17010Sstevel@tonic-gate 
17020Sstevel@tonic-gate 
17030Sstevel@tonic-gate /*
17040Sstevel@tonic-gate  * Sendfile is implemented through two schemes, direct I/O or by
17050Sstevel@tonic-gate  * caching in the filesystem page cache. We cache the input file by
17060Sstevel@tonic-gate  * default and use direct I/O only if sendfile_max_size is set
17070Sstevel@tonic-gate  * appropriately as explained below. Note that this logic is consistent
17080Sstevel@tonic-gate  * with other filesystems where caching is turned on by default
17090Sstevel@tonic-gate  * unless explicitly turned off by using the DIRECTIO ioctl.
17100Sstevel@tonic-gate  *
17110Sstevel@tonic-gate  * We choose a slightly different scheme here. One can turn off
17120Sstevel@tonic-gate  * caching by setting sendfile_max_size to 0. One can also enable
17130Sstevel@tonic-gate  * caching of files <= sendfile_max_size by setting sendfile_max_size
17140Sstevel@tonic-gate  * to an appropriate value. By default sendfile_max_size is set to the
17150Sstevel@tonic-gate  * maximum value so that all files are cached. In future, we may provide
17160Sstevel@tonic-gate  * better interfaces for caching the file.
17170Sstevel@tonic-gate  *
17180Sstevel@tonic-gate  * Sendfile through Direct I/O (Zero copy)
17190Sstevel@tonic-gate  * --------------------------------------
17200Sstevel@tonic-gate  *
17210Sstevel@tonic-gate  * As disks are normally slower than the network, we can't have a
17220Sstevel@tonic-gate  * single thread that reads the disk and writes to the network. We
17230Sstevel@tonic-gate  * need to have parallelism. This is done by having the sendfile
17240Sstevel@tonic-gate  * thread create another thread that reads from the filesystem
17250Sstevel@tonic-gate  * and queues it for network processing. In this scheme, the data
17260Sstevel@tonic-gate  * is never copied anywhere i.e it is zero copy unlike the other
17270Sstevel@tonic-gate  * scheme.
17280Sstevel@tonic-gate  *
17290Sstevel@tonic-gate  * We have a sendfile queue (snfq) where each sendfile
17300Sstevel@tonic-gate  * request (snf_req_t) is queued for processing by a thread. Number
17310Sstevel@tonic-gate  * of threads is dynamically allocated and they exit if they are idling
17320Sstevel@tonic-gate  * beyond a specified amount of time. When each request (snf_req_t) is
17330Sstevel@tonic-gate  * processed by a thread, it produces a number of mblk_t structures to
17340Sstevel@tonic-gate  * be consumed by the sendfile thread. snf_deque and snf_enque are
17350Sstevel@tonic-gate  * used for consuming and producing mblks. Size of the filesystem
17365331Samw  * read is determined by the tunable (sendfile_read_size). A single
17370Sstevel@tonic-gate  * mblk holds sendfile_read_size worth of data (except the last
17380Sstevel@tonic-gate  * read of the file) which is sent down as a whole to the network.
17390Sstevel@tonic-gate  * sendfile_read_size is set to 1 MB as this seems to be the optimal
17400Sstevel@tonic-gate  * value for the UFS filesystem backed by a striped storage array.
17410Sstevel@tonic-gate  *
17420Sstevel@tonic-gate  * Synchronisation between read (producer) and write (consumer) threads.
17430Sstevel@tonic-gate  * --------------------------------------------------------------------
17440Sstevel@tonic-gate  *
17450Sstevel@tonic-gate  * sr_lock protects sr_ib_head and sr_ib_tail. The lock is held while
17460Sstevel@tonic-gate  * adding and deleting items in this list. Error can happen anytime
17470Sstevel@tonic-gate  * during read or write. There could be unprocessed mblks in the
17480Sstevel@tonic-gate  * sr_ib_XXX list when a read or write error occurs. Whenever error
17490Sstevel@tonic-gate  * is encountered, we need two things to happen :
17500Sstevel@tonic-gate  *
17510Sstevel@tonic-gate  * a) One of the threads need to clean the mblks.
17520Sstevel@tonic-gate  * b) When one thread encounters an error, the other should stop.
17530Sstevel@tonic-gate  *
17545331Samw  * For (a), we don't want to penalize the reader thread as it could do
17550Sstevel@tonic-gate  * some useful work processing other requests. For (b), the error can
17560Sstevel@tonic-gate  * be detected by examining sr_read_error or sr_write_error.
17570Sstevel@tonic-gate  * sr_lock protects sr_read_error and sr_write_error. If both reader and
17580Sstevel@tonic-gate  * writer encounters error, we need to report the write error back to
17590Sstevel@tonic-gate  * the application as that's what would have happened if the operations
17600Sstevel@tonic-gate  * were done sequentially. With this in mind, following should work :
17610Sstevel@tonic-gate  *
17620Sstevel@tonic-gate  * 	- Check for errors before read or write.
17630Sstevel@tonic-gate  *	- If the reader encounters error, set the error in sr_read_error.
17640Sstevel@tonic-gate  *	  Check sr_write_error, if it is set, send cv_signal as it is
17650Sstevel@tonic-gate  *	  waiting for reader to complete. If it is not set, the writer
17660Sstevel@tonic-gate  *	  is either running sinking data to the network or blocked
17670Sstevel@tonic-gate  *        because of flow control. For handling the latter case, we
17680Sstevel@tonic-gate  *	  always send a signal. In any case, it will examine sr_read_error
17690Sstevel@tonic-gate  *	  and return. sr_read_error is marked with SR_READ_DONE to tell
17700Sstevel@tonic-gate  *	  the writer that the reader is done in all the cases.
17710Sstevel@tonic-gate  *	- If the writer encounters error, set the error in sr_write_error.
17720Sstevel@tonic-gate  *	  The reader thread is either blocked because of flow control or
17730Sstevel@tonic-gate  *	  running reading data from the disk. For the former, we need to
17740Sstevel@tonic-gate  *	  wakeup the thread. Again to keep it simple, we always wake up
17750Sstevel@tonic-gate  *	  the reader thread. Then, wait for the read thread to complete
17760Sstevel@tonic-gate  *	  if it is not done yet. Cleanup and return.
17770Sstevel@tonic-gate  *
17780Sstevel@tonic-gate  * High and low water marks for the read thread.
17790Sstevel@tonic-gate  * --------------------------------------------
17800Sstevel@tonic-gate  *
17810Sstevel@tonic-gate  * If sendfile() is used to send data over a slow network, we need to
17820Sstevel@tonic-gate  * make sure that the read thread does not produce data at a faster
17830Sstevel@tonic-gate  * rate than the network. This can happen if the disk is faster than
17840Sstevel@tonic-gate  * the network. In such a case, we don't want to build a very large queue.
17850Sstevel@tonic-gate  * But we would still like to get all of the network throughput possible.
17860Sstevel@tonic-gate  * This implies that network should never block waiting for data.
17870Sstevel@tonic-gate  * As there are lot of disk throughput/network throughput combinations
17880Sstevel@tonic-gate  * possible, it is difficult to come up with an accurate number.
17890Sstevel@tonic-gate  * A typical 10K RPM disk has a max seek latency 17ms and rotational
17900Sstevel@tonic-gate  * latency of 3ms for reading a disk block. Thus, the total latency to
17910Sstevel@tonic-gate  * initiate a new read, transfer data from the disk and queue for
17920Sstevel@tonic-gate  * transmission would take about a max of 25ms. Todays max transfer rate
17930Sstevel@tonic-gate  * for network is 100MB/sec. If the thread is blocked because of flow
17940Sstevel@tonic-gate  * control, it would take 25ms to get new data ready for transmission.
17950Sstevel@tonic-gate  * We have to make sure that network is not idling, while we are initiating
17960Sstevel@tonic-gate  * new transfers. So, at 100MB/sec, to keep network busy we would need
17975331Samw  * 2.5MB of data. Rounding off, we keep the low water mark to be 3MB of data.
17980Sstevel@tonic-gate  * We need to pick a high water mark so that the woken up thread would
17990Sstevel@tonic-gate  * do considerable work before blocking again to prevent thrashing. Currently,
18000Sstevel@tonic-gate  * we pick this to be 10 times that of the low water mark.
18010Sstevel@tonic-gate  *
18020Sstevel@tonic-gate  * Sendfile with segmap caching (One copy from page cache to mblks).
18030Sstevel@tonic-gate  * ----------------------------------------------------------------
18040Sstevel@tonic-gate  *
18050Sstevel@tonic-gate  * We use the segmap cache for caching the file, if the size of file
18060Sstevel@tonic-gate  * is <= sendfile_max_size. In this case we don't use threads as VM
18070Sstevel@tonic-gate  * is reasonably fast enough to keep up with the network. If the underlying
18080Sstevel@tonic-gate  * transport allows, we call segmap_getmapflt() to map MAXBSIZE (8K) worth
18090Sstevel@tonic-gate  * of data into segmap space, and use the virtual address from segmap
18100Sstevel@tonic-gate  * directly through desballoc() to avoid copy. Once the transport is done
18110Sstevel@tonic-gate  * with the data, the mapping will be released through segmap_release()
18120Sstevel@tonic-gate  * called by the call-back routine.
18130Sstevel@tonic-gate  *
18140Sstevel@tonic-gate  * If zero-copy is not allowed by the transport, we simply call VOP_READ()
18150Sstevel@tonic-gate  * to copy the data from the filesystem into our temporary network buffer.
18160Sstevel@tonic-gate  *
18170Sstevel@tonic-gate  * To disable caching, set sendfile_max_size to 0.
18180Sstevel@tonic-gate  */
18190Sstevel@tonic-gate 
18200Sstevel@tonic-gate uint_t sendfile_read_size = 1024 * 1024;
18210Sstevel@tonic-gate #define	SENDFILE_REQ_LOWAT	3 * 1024 * 1024
18220Sstevel@tonic-gate uint_t sendfile_req_lowat = SENDFILE_REQ_LOWAT;
18230Sstevel@tonic-gate uint_t sendfile_req_hiwat = 10 * SENDFILE_REQ_LOWAT;
18240Sstevel@tonic-gate struct sendfile_stats sf_stats;
18250Sstevel@tonic-gate struct sendfile_queue *snfq;
18260Sstevel@tonic-gate clock_t snfq_timeout;
18270Sstevel@tonic-gate off64_t sendfile_max_size;
18280Sstevel@tonic-gate 
18290Sstevel@tonic-gate static void snf_enque(snf_req_t *, mblk_t *);
18300Sstevel@tonic-gate static mblk_t *snf_deque(snf_req_t *);
18310Sstevel@tonic-gate 
18320Sstevel@tonic-gate void
18330Sstevel@tonic-gate sendfile_init(void)
18340Sstevel@tonic-gate {
18350Sstevel@tonic-gate 	snfq = kmem_zalloc(sizeof (struct sendfile_queue), KM_SLEEP);
18360Sstevel@tonic-gate 
18370Sstevel@tonic-gate 	mutex_init(&snfq->snfq_lock, NULL, MUTEX_DEFAULT, NULL);
18380Sstevel@tonic-gate 	cv_init(&snfq->snfq_cv, NULL, CV_DEFAULT, NULL);
18390Sstevel@tonic-gate 	snfq->snfq_max_threads = max_ncpus;
18400Sstevel@tonic-gate 	snfq_timeout = SNFQ_TIMEOUT;
18410Sstevel@tonic-gate 	/* Cache all files by default. */
18420Sstevel@tonic-gate 	sendfile_max_size = MAXOFFSET_T;
18430Sstevel@tonic-gate }
18440Sstevel@tonic-gate 
18450Sstevel@tonic-gate /*
18460Sstevel@tonic-gate  * Queues a mblk_t for network processing.
18470Sstevel@tonic-gate  */
18480Sstevel@tonic-gate static void
18490Sstevel@tonic-gate snf_enque(snf_req_t *sr, mblk_t *mp)
18500Sstevel@tonic-gate {
18510Sstevel@tonic-gate 	mp->b_next = NULL;
18520Sstevel@tonic-gate 	mutex_enter(&sr->sr_lock);
18530Sstevel@tonic-gate 	if (sr->sr_mp_head == NULL) {
18540Sstevel@tonic-gate 		sr->sr_mp_head = sr->sr_mp_tail = mp;
18550Sstevel@tonic-gate 		cv_signal(&sr->sr_cv);
18560Sstevel@tonic-gate 	} else {
18570Sstevel@tonic-gate 		sr->sr_mp_tail->b_next = mp;
18580Sstevel@tonic-gate 		sr->sr_mp_tail = mp;
18590Sstevel@tonic-gate 	}
18600Sstevel@tonic-gate 	sr->sr_qlen += MBLKL(mp);
18610Sstevel@tonic-gate 	while ((sr->sr_qlen > sr->sr_hiwat) &&
18620Sstevel@tonic-gate 	    (sr->sr_write_error == 0)) {
18630Sstevel@tonic-gate 		sf_stats.ss_full_waits++;
18640Sstevel@tonic-gate 		cv_wait(&sr->sr_cv, &sr->sr_lock);
18650Sstevel@tonic-gate 	}
18660Sstevel@tonic-gate 	mutex_exit(&sr->sr_lock);
18670Sstevel@tonic-gate }
18680Sstevel@tonic-gate 
18690Sstevel@tonic-gate /*
18700Sstevel@tonic-gate  * De-queues a mblk_t for network processing.
18710Sstevel@tonic-gate  */
18720Sstevel@tonic-gate static mblk_t *
18730Sstevel@tonic-gate snf_deque(snf_req_t *sr)
18740Sstevel@tonic-gate {
18750Sstevel@tonic-gate 	mblk_t *mp;
18760Sstevel@tonic-gate 
18770Sstevel@tonic-gate 	mutex_enter(&sr->sr_lock);
18780Sstevel@tonic-gate 	/*
18790Sstevel@tonic-gate 	 * If we have encountered an error on read or read is
18800Sstevel@tonic-gate 	 * completed and no more mblks, return NULL.
18810Sstevel@tonic-gate 	 * We need to check for NULL sr_mp_head also as
18820Sstevel@tonic-gate 	 * the reads could have completed and there is
18830Sstevel@tonic-gate 	 * nothing more to come.
18840Sstevel@tonic-gate 	 */
18850Sstevel@tonic-gate 	if (((sr->sr_read_error & ~SR_READ_DONE) != 0) ||
18860Sstevel@tonic-gate 	    ((sr->sr_read_error & SR_READ_DONE) &&
18870Sstevel@tonic-gate 	    sr->sr_mp_head == NULL)) {
18880Sstevel@tonic-gate 		mutex_exit(&sr->sr_lock);
18890Sstevel@tonic-gate 		return (NULL);
18900Sstevel@tonic-gate 	}
18910Sstevel@tonic-gate 	/*
18920Sstevel@tonic-gate 	 * To start with neither SR_READ_DONE is marked nor
18930Sstevel@tonic-gate 	 * the error is set. When we wake up from cv_wait,
18940Sstevel@tonic-gate 	 * following are the possibilities :
18950Sstevel@tonic-gate 	 *
18960Sstevel@tonic-gate 	 *	a) sr_read_error is zero and mblks are queued.
18970Sstevel@tonic-gate 	 *	b) sr_read_error is set to SR_READ_DONE
18980Sstevel@tonic-gate 	 *	   and mblks are queued.
18990Sstevel@tonic-gate 	 *	c) sr_read_error is set to SR_READ_DONE
19000Sstevel@tonic-gate 	 *	   and no mblks.
19010Sstevel@tonic-gate 	 *	d) sr_read_error is set to some error other
19020Sstevel@tonic-gate 	 *	   than SR_READ_DONE.
19030Sstevel@tonic-gate 	 */
19040Sstevel@tonic-gate 
19050Sstevel@tonic-gate 	while ((sr->sr_read_error == 0) && (sr->sr_mp_head == NULL)) {
19060Sstevel@tonic-gate 		sf_stats.ss_empty_waits++;
19070Sstevel@tonic-gate 		cv_wait(&sr->sr_cv, &sr->sr_lock);
19080Sstevel@tonic-gate 	}
19090Sstevel@tonic-gate 	/* Handle (a) and (b) first  - the normal case. */
19100Sstevel@tonic-gate 	if (((sr->sr_read_error & ~SR_READ_DONE) == 0) &&
19110Sstevel@tonic-gate 	    (sr->sr_mp_head != NULL)) {
19120Sstevel@tonic-gate 		mp = sr->sr_mp_head;
19130Sstevel@tonic-gate 		sr->sr_mp_head = mp->b_next;
19140Sstevel@tonic-gate 		sr->sr_qlen -= MBLKL(mp);
19150Sstevel@tonic-gate 		if (sr->sr_qlen < sr->sr_lowat)
19160Sstevel@tonic-gate 			cv_signal(&sr->sr_cv);
19170Sstevel@tonic-gate 		mutex_exit(&sr->sr_lock);
19180Sstevel@tonic-gate 		mp->b_next = NULL;
19190Sstevel@tonic-gate 		return (mp);
19200Sstevel@tonic-gate 	}
19210Sstevel@tonic-gate 	/* Handle (c) and (d). */
19220Sstevel@tonic-gate 	mutex_exit(&sr->sr_lock);
19230Sstevel@tonic-gate 	return (NULL);
19240Sstevel@tonic-gate }
19250Sstevel@tonic-gate 
19260Sstevel@tonic-gate /*
19270Sstevel@tonic-gate  * Reads data from the filesystem and queues it for network processing.
19280Sstevel@tonic-gate  */
19290Sstevel@tonic-gate void
19300Sstevel@tonic-gate snf_async_read(snf_req_t *sr)
19310Sstevel@tonic-gate {
19320Sstevel@tonic-gate 	size_t iosize;
19330Sstevel@tonic-gate 	u_offset_t fileoff;
19340Sstevel@tonic-gate 	u_offset_t size;
19350Sstevel@tonic-gate 	int ret_size;
19360Sstevel@tonic-gate 	int error;
19370Sstevel@tonic-gate 	file_t *fp;
19380Sstevel@tonic-gate 	mblk_t *mp;
19396240Skrishna 	struct vnode *vp;
19406240Skrishna 	int extra = 0;
19410Sstevel@tonic-gate 
19420Sstevel@tonic-gate 	fp = sr->sr_fp;
19430Sstevel@tonic-gate 	size = sr->sr_file_size;
19440Sstevel@tonic-gate 	fileoff = sr->sr_file_off;
19450Sstevel@tonic-gate 
19460Sstevel@tonic-gate 	/*
19470Sstevel@tonic-gate 	 * Ignore the error for filesystems that doesn't support DIRECTIO.
19480Sstevel@tonic-gate 	 */
19490Sstevel@tonic-gate 	(void) VOP_IOCTL(fp->f_vnode, _FIODIRECTIO, DIRECTIO_ON, 0,
19505331Samw 	    kcred, NULL, NULL);
19510Sstevel@tonic-gate 
19526240Skrishna 	vp = fp->f_vnode;
19536240Skrishna 	if (vp->v_type == VSOCK) {
19546240Skrishna 		stdata_t *stp;
19556240Skrishna 
19566240Skrishna 		/*
19576240Skrishna 		 * Get the extra space to insert a header and a trailer.
19586240Skrishna 		 */
19596240Skrishna 		stp = vp->v_stream;
19606240Skrishna 		extra = (int)(stp->sd_wroff + stp->sd_tail);
19616240Skrishna 	}
19626240Skrishna 
19630Sstevel@tonic-gate 	while ((size != 0) && (sr->sr_write_error == 0)) {
19640Sstevel@tonic-gate 
19650Sstevel@tonic-gate 		iosize = (int)MIN(sr->sr_maxpsz, size);
19660Sstevel@tonic-gate 
19676240Skrishna 		if ((mp = allocb(iosize + extra, BPRI_MED)) == NULL) {
19680Sstevel@tonic-gate 			error = EAGAIN;
19690Sstevel@tonic-gate 			break;
19700Sstevel@tonic-gate 		}
19710Sstevel@tonic-gate 		ret_size = soreadfile(fp, mp->b_rptr, fileoff, &error, iosize);
19720Sstevel@tonic-gate 
19730Sstevel@tonic-gate 		/* Error or Reached EOF ? */
19740Sstevel@tonic-gate 		if ((error != 0) || (ret_size == 0)) {
19750Sstevel@tonic-gate 			freeb(mp);
19760Sstevel@tonic-gate 			break;
19770Sstevel@tonic-gate 		}
19780Sstevel@tonic-gate 		mp->b_wptr = mp->b_rptr + ret_size;
19790Sstevel@tonic-gate 
19800Sstevel@tonic-gate 		snf_enque(sr, mp);
19810Sstevel@tonic-gate 		size -= ret_size;
19820Sstevel@tonic-gate 		fileoff += ret_size;
19830Sstevel@tonic-gate 	}
19840Sstevel@tonic-gate 	(void) VOP_IOCTL(fp->f_vnode, _FIODIRECTIO, DIRECTIO_OFF, 0,
19855331Samw 	    kcred, NULL, NULL);
19860Sstevel@tonic-gate 	mutex_enter(&sr->sr_lock);
19870Sstevel@tonic-gate 	sr->sr_read_error = error;
19880Sstevel@tonic-gate 	sr->sr_read_error |= SR_READ_DONE;
19890Sstevel@tonic-gate 	cv_signal(&sr->sr_cv);
19900Sstevel@tonic-gate 	mutex_exit(&sr->sr_lock);
19910Sstevel@tonic-gate }
19920Sstevel@tonic-gate 
19930Sstevel@tonic-gate void
19940Sstevel@tonic-gate snf_async_thread(void)
19950Sstevel@tonic-gate {
19960Sstevel@tonic-gate 	snf_req_t *sr;
19970Sstevel@tonic-gate 	callb_cpr_t cprinfo;
19980Sstevel@tonic-gate 	clock_t time_left = 1;
19990Sstevel@tonic-gate 	clock_t now;
20000Sstevel@tonic-gate 
20010Sstevel@tonic-gate 	CALLB_CPR_INIT(&cprinfo, &snfq->snfq_lock, callb_generic_cpr, "snfq");
20020Sstevel@tonic-gate 
20030Sstevel@tonic-gate 	mutex_enter(&snfq->snfq_lock);
20040Sstevel@tonic-gate 	for (;;) {
20050Sstevel@tonic-gate 		/*
20060Sstevel@tonic-gate 		 * If we didn't find a entry, then block until woken up
20070Sstevel@tonic-gate 		 * again and then look through the queues again.
20080Sstevel@tonic-gate 		 */
20090Sstevel@tonic-gate 		while ((sr = snfq->snfq_req_head) == NULL) {
20100Sstevel@tonic-gate 			CALLB_CPR_SAFE_BEGIN(&cprinfo);
20110Sstevel@tonic-gate 			if (time_left <= 0) {
20120Sstevel@tonic-gate 				snfq->snfq_svc_threads--;
20130Sstevel@tonic-gate 				CALLB_CPR_EXIT(&cprinfo);
20140Sstevel@tonic-gate 				thread_exit();
20150Sstevel@tonic-gate 				/* NOTREACHED */
20160Sstevel@tonic-gate 			}
20170Sstevel@tonic-gate 			snfq->snfq_idle_cnt++;
20180Sstevel@tonic-gate 
20190Sstevel@tonic-gate 			time_to_wait(&now, snfq_timeout);
20200Sstevel@tonic-gate 			time_left = cv_timedwait(&snfq->snfq_cv,
20210Sstevel@tonic-gate 			    &snfq->snfq_lock, now);
20220Sstevel@tonic-gate 			snfq->snfq_idle_cnt--;
20230Sstevel@tonic-gate 
20240Sstevel@tonic-gate 			CALLB_CPR_SAFE_END(&cprinfo, &snfq->snfq_lock);
20250Sstevel@tonic-gate 		}
20260Sstevel@tonic-gate 		snfq->snfq_req_head = sr->sr_next;
20270Sstevel@tonic-gate 		snfq->snfq_req_cnt--;
20280Sstevel@tonic-gate 		mutex_exit(&snfq->snfq_lock);
20290Sstevel@tonic-gate 		snf_async_read(sr);
20300Sstevel@tonic-gate 		mutex_enter(&snfq->snfq_lock);
20310Sstevel@tonic-gate 	}
20320Sstevel@tonic-gate }
20330Sstevel@tonic-gate 
20340Sstevel@tonic-gate 
20350Sstevel@tonic-gate snf_req_t *
20360Sstevel@tonic-gate create_thread(int operation, struct vnode *vp, file_t *fp,
20370Sstevel@tonic-gate     u_offset_t fileoff, u_offset_t size)
20380Sstevel@tonic-gate {
20390Sstevel@tonic-gate 	snf_req_t *sr;
20400Sstevel@tonic-gate 	stdata_t *stp;
20410Sstevel@tonic-gate 
20420Sstevel@tonic-gate 	sr = (snf_req_t *)kmem_zalloc(sizeof (snf_req_t), KM_SLEEP);
20430Sstevel@tonic-gate 
20440Sstevel@tonic-gate 	sr->sr_vp = vp;
20450Sstevel@tonic-gate 	sr->sr_fp = fp;
20460Sstevel@tonic-gate 	stp = vp->v_stream;
20470Sstevel@tonic-gate 
20480Sstevel@tonic-gate 	/*
20490Sstevel@tonic-gate 	 * store sd_qn_maxpsz into sr_maxpsz while we have stream head.
20500Sstevel@tonic-gate 	 * stream might be closed before thread returns from snf_async_read.
20510Sstevel@tonic-gate 	 */
20520Sstevel@tonic-gate 	if (stp->sd_qn_maxpsz > 0) {
20530Sstevel@tonic-gate 		sr->sr_maxpsz = MIN(MAXBSIZE, stp->sd_qn_maxpsz);
20540Sstevel@tonic-gate 	} else {
20550Sstevel@tonic-gate 		sr->sr_maxpsz = MAXBSIZE;
20560Sstevel@tonic-gate 	}
20570Sstevel@tonic-gate 
20580Sstevel@tonic-gate 	sr->sr_operation = operation;
20590Sstevel@tonic-gate 	sr->sr_file_off = fileoff;
20600Sstevel@tonic-gate 	sr->sr_file_size = size;
20610Sstevel@tonic-gate 	sr->sr_hiwat = sendfile_req_hiwat;
20620Sstevel@tonic-gate 	sr->sr_lowat = sendfile_req_lowat;
20630Sstevel@tonic-gate 	mutex_init(&sr->sr_lock, NULL, MUTEX_DEFAULT, NULL);
20640Sstevel@tonic-gate 	cv_init(&sr->sr_cv, NULL, CV_DEFAULT, NULL);
20650Sstevel@tonic-gate 	/*
20660Sstevel@tonic-gate 	 * See whether we need another thread for servicing this
20670Sstevel@tonic-gate 	 * request. If there are already enough requests queued
20680Sstevel@tonic-gate 	 * for the threads, create one if not exceeding
20690Sstevel@tonic-gate 	 * snfq_max_threads.
20700Sstevel@tonic-gate 	 */
20710Sstevel@tonic-gate 	mutex_enter(&snfq->snfq_lock);
20720Sstevel@tonic-gate 	if (snfq->snfq_req_cnt >= snfq->snfq_idle_cnt &&
20730Sstevel@tonic-gate 	    snfq->snfq_svc_threads < snfq->snfq_max_threads) {
20740Sstevel@tonic-gate 		(void) thread_create(NULL, 0, &snf_async_thread, 0, 0, &p0,
20750Sstevel@tonic-gate 		    TS_RUN, minclsyspri);
20760Sstevel@tonic-gate 		snfq->snfq_svc_threads++;
20770Sstevel@tonic-gate 	}
20780Sstevel@tonic-gate 	if (snfq->snfq_req_head == NULL) {
20790Sstevel@tonic-gate 		snfq->snfq_req_head = snfq->snfq_req_tail = sr;
20800Sstevel@tonic-gate 		cv_signal(&snfq->snfq_cv);
20810Sstevel@tonic-gate 	} else {
20820Sstevel@tonic-gate 		snfq->snfq_req_tail->sr_next = sr;
20830Sstevel@tonic-gate 		snfq->snfq_req_tail = sr;
20840Sstevel@tonic-gate 	}
20850Sstevel@tonic-gate 	snfq->snfq_req_cnt++;
20860Sstevel@tonic-gate 	mutex_exit(&snfq->snfq_lock);
20870Sstevel@tonic-gate 	return (sr);
20880Sstevel@tonic-gate }
20890Sstevel@tonic-gate 
20900Sstevel@tonic-gate int
20910Sstevel@tonic-gate snf_direct_io(file_t *fp, file_t *rfp, u_offset_t fileoff, u_offset_t size,
20920Sstevel@tonic-gate     ssize_t *count)
20930Sstevel@tonic-gate {
20940Sstevel@tonic-gate 	snf_req_t *sr;
20950Sstevel@tonic-gate 	mblk_t *mp;
20960Sstevel@tonic-gate 	int iosize;
20970Sstevel@tonic-gate 	int error = 0;
20980Sstevel@tonic-gate 	short fflag;
20990Sstevel@tonic-gate 	struct vnode *vp;
21000Sstevel@tonic-gate 	int ksize;
21010Sstevel@tonic-gate 
21020Sstevel@tonic-gate 	ksize = 0;
21030Sstevel@tonic-gate 	*count = 0;
21040Sstevel@tonic-gate 
21050Sstevel@tonic-gate 	vp = fp->f_vnode;
21060Sstevel@tonic-gate 	fflag = fp->f_flag;
21070Sstevel@tonic-gate 	if ((sr = create_thread(READ_OP, vp, rfp, fileoff, size)) == NULL)
21080Sstevel@tonic-gate 		return (EAGAIN);
21090Sstevel@tonic-gate 
21100Sstevel@tonic-gate 	/*
21110Sstevel@tonic-gate 	 * We check for read error in snf_deque. It has to check
21120Sstevel@tonic-gate 	 * for successful READ_DONE and return NULL, and we might
21130Sstevel@tonic-gate 	 * as well make an additional check there.
21140Sstevel@tonic-gate 	 */
21150Sstevel@tonic-gate 	while ((mp = snf_deque(sr)) != NULL) {
21160Sstevel@tonic-gate 
21170Sstevel@tonic-gate 		if (ISSIG(curthread, JUSTLOOKING)) {
21180Sstevel@tonic-gate 			freeb(mp);
21190Sstevel@tonic-gate 			error = EINTR;
21200Sstevel@tonic-gate 			break;
21210Sstevel@tonic-gate 		}
21220Sstevel@tonic-gate 		iosize = MBLKL(mp);
21230Sstevel@tonic-gate 
21240Sstevel@tonic-gate 		if ((error = kstrwritemp(vp, mp, fflag)) != 0) {
21250Sstevel@tonic-gate 			freeb(mp);
21260Sstevel@tonic-gate 			break;
21270Sstevel@tonic-gate 		}
21280Sstevel@tonic-gate 		ksize += iosize;
21290Sstevel@tonic-gate 	}
21300Sstevel@tonic-gate 	*count = ksize;
21310Sstevel@tonic-gate 
21320Sstevel@tonic-gate 	mutex_enter(&sr->sr_lock);
21330Sstevel@tonic-gate 	sr->sr_write_error = error;
21340Sstevel@tonic-gate 	/* Look at the big comments on why we cv_signal here. */
21350Sstevel@tonic-gate 	cv_signal(&sr->sr_cv);
21360Sstevel@tonic-gate 
21370Sstevel@tonic-gate 	/* Wait for the reader to complete always. */
21380Sstevel@tonic-gate 	while (!(sr->sr_read_error & SR_READ_DONE)) {
21390Sstevel@tonic-gate 		cv_wait(&sr->sr_cv, &sr->sr_lock);
21400Sstevel@tonic-gate 	}
21410Sstevel@tonic-gate 	/* If there is no write error, check for read error. */
21420Sstevel@tonic-gate 	if (error == 0)
21430Sstevel@tonic-gate 		error = (sr->sr_read_error & ~SR_READ_DONE);
21440Sstevel@tonic-gate 
21450Sstevel@tonic-gate 	if (error != 0) {
21460Sstevel@tonic-gate 		mblk_t *next_mp;
21470Sstevel@tonic-gate 
21480Sstevel@tonic-gate 		mp = sr->sr_mp_head;
21490Sstevel@tonic-gate 		while (mp != NULL) {
21500Sstevel@tonic-gate 			next_mp = mp->b_next;
21510Sstevel@tonic-gate 			mp->b_next = NULL;
21520Sstevel@tonic-gate 			freeb(mp);
21530Sstevel@tonic-gate 			mp = next_mp;
21540Sstevel@tonic-gate 		}
21550Sstevel@tonic-gate 	}
21560Sstevel@tonic-gate 	mutex_exit(&sr->sr_lock);
21570Sstevel@tonic-gate 	kmem_free(sr, sizeof (snf_req_t));
21580Sstevel@tonic-gate 	return (error);
21590Sstevel@tonic-gate }
21600Sstevel@tonic-gate 
21610Sstevel@tonic-gate typedef struct {
21620Sstevel@tonic-gate 	frtn_t		snfi_frtn;
21630Sstevel@tonic-gate 	caddr_t		snfi_base;
21640Sstevel@tonic-gate 	uint_t		snfi_mapoff;
21650Sstevel@tonic-gate 	size_t		snfi_len;
21660Sstevel@tonic-gate 	vnode_t		*snfi_vp;
21670Sstevel@tonic-gate } snf_smap_desbinfo;
21680Sstevel@tonic-gate 
21690Sstevel@tonic-gate /*
21700Sstevel@tonic-gate  * The callback function when the last ref of the mblk is dropped,
21710Sstevel@tonic-gate  * normally occurs when TCP receives the ack. But it can be the driver
21720Sstevel@tonic-gate  * too due to lazy reclaim.
21730Sstevel@tonic-gate  */
21740Sstevel@tonic-gate void
21750Sstevel@tonic-gate snf_smap_desbfree(snf_smap_desbinfo *snfi)
21760Sstevel@tonic-gate {
2177*7568SJayakara.Kini@Sun.COM 	if (! IS_KPM_ADDR(snfi->snfi_base)) {
21780Sstevel@tonic-gate 		/*
21790Sstevel@tonic-gate 		 * We don't need to call segmap_fault(F_SOFTUNLOCK) for
21800Sstevel@tonic-gate 		 * segmap_kpm as long as the latter never falls back to
21810Sstevel@tonic-gate 		 * "use_segmap_range". (See segmap_getmapflt().)
21820Sstevel@tonic-gate 		 *
21830Sstevel@tonic-gate 		 * Using S_OTHER saves an redundant hat_setref() in
21840Sstevel@tonic-gate 		 * segmap_unlock()
21850Sstevel@tonic-gate 		 */
21860Sstevel@tonic-gate 		(void) segmap_fault(kas.a_hat, segkmap,
2187408Skrgopi 		    (caddr_t)(uintptr_t)(((uintptr_t)snfi->snfi_base +
2188408Skrgopi 		    snfi->snfi_mapoff) & PAGEMASK), snfi->snfi_len,
2189408Skrgopi 		    F_SOFTUNLOCK, S_OTHER);
21900Sstevel@tonic-gate 	}
21910Sstevel@tonic-gate 	(void) segmap_release(segkmap, snfi->snfi_base, SM_DONTNEED);
21920Sstevel@tonic-gate 	VN_RELE(snfi->snfi_vp);
21930Sstevel@tonic-gate 	kmem_free(snfi, sizeof (*snfi));
21940Sstevel@tonic-gate }
21950Sstevel@tonic-gate 
21960Sstevel@tonic-gate /*
2197*7568SJayakara.Kini@Sun.COM  * Use segmap instead of bcopy to send down a desballoca'ed, mblk.  The mblk
2198*7568SJayakara.Kini@Sun.COM  * contains a segmap slot of no more than MAXBSIZE.
21990Sstevel@tonic-gate  *
22000Sstevel@tonic-gate  * At the end of the whole sendfile() operation, we wait till the data from
22010Sstevel@tonic-gate  * the last mblk is ack'ed by the transport before returning so that the
22020Sstevel@tonic-gate  * caller of sendfile() can safely modify the file content.
22030Sstevel@tonic-gate  */
22040Sstevel@tonic-gate int
22050Sstevel@tonic-gate snf_segmap(file_t *fp, vnode_t *fvp, u_offset_t fileoff, u_offset_t size,
2206*7568SJayakara.Kini@Sun.COM     ssize_t *count, boolean_t nowait)
22070Sstevel@tonic-gate {
22080Sstevel@tonic-gate 	caddr_t base;
22090Sstevel@tonic-gate 	int mapoff;
22100Sstevel@tonic-gate 	vnode_t *vp;
2211*7568SJayakara.Kini@Sun.COM 	mblk_t *mp;
2212*7568SJayakara.Kini@Sun.COM 	int iosize;
22130Sstevel@tonic-gate 	int error;
22140Sstevel@tonic-gate 	short fflag;
22150Sstevel@tonic-gate 	int ksize;
22160Sstevel@tonic-gate 	snf_smap_desbinfo *snfi;
22170Sstevel@tonic-gate 	struct vattr va;
22180Sstevel@tonic-gate 	boolean_t dowait = B_FALSE;
22190Sstevel@tonic-gate 
22200Sstevel@tonic-gate 	vp = fp->f_vnode;
22210Sstevel@tonic-gate 	fflag = fp->f_flag;
22220Sstevel@tonic-gate 	ksize = 0;
22230Sstevel@tonic-gate 	for (;;) {
22240Sstevel@tonic-gate 		if (ISSIG(curthread, JUSTLOOKING)) {
22250Sstevel@tonic-gate 			error = EINTR;
22260Sstevel@tonic-gate 			break;
22270Sstevel@tonic-gate 		}
2228*7568SJayakara.Kini@Sun.COM 
2229*7568SJayakara.Kini@Sun.COM 		mapoff = fileoff & MAXBOFFSET;
2230*7568SJayakara.Kini@Sun.COM 		iosize = MAXBSIZE - mapoff;
2231*7568SJayakara.Kini@Sun.COM 		if (iosize > size)
2232*7568SJayakara.Kini@Sun.COM 			iosize = size;
2233*7568SJayakara.Kini@Sun.COM 		/*
2234*7568SJayakara.Kini@Sun.COM 		 * we don't forcefault because we'll call
2235*7568SJayakara.Kini@Sun.COM 		 * segmap_fault(F_SOFTLOCK) next.
2236*7568SJayakara.Kini@Sun.COM 		 *
2237*7568SJayakara.Kini@Sun.COM 		 * S_READ will get the ref bit set (by either
2238*7568SJayakara.Kini@Sun.COM 		 * segmap_getmapflt() or segmap_fault()) and page
2239*7568SJayakara.Kini@Sun.COM 		 * shared locked.
2240*7568SJayakara.Kini@Sun.COM 		 */
2241*7568SJayakara.Kini@Sun.COM 		base = segmap_getmapflt(segkmap, fvp, fileoff, iosize,
2242*7568SJayakara.Kini@Sun.COM 		    segmap_kpm ? SM_FAULT : 0, S_READ);
22430Sstevel@tonic-gate 
2244*7568SJayakara.Kini@Sun.COM 		snfi = kmem_alloc(sizeof (*snfi), KM_SLEEP);
2245*7568SJayakara.Kini@Sun.COM 		snfi->snfi_len = (size_t)roundup(mapoff+iosize,
2246*7568SJayakara.Kini@Sun.COM 		    PAGESIZE)- (mapoff & PAGEMASK);
2247*7568SJayakara.Kini@Sun.COM 		/*
2248*7568SJayakara.Kini@Sun.COM 		 * We must call segmap_fault() even for segmap_kpm
2249*7568SJayakara.Kini@Sun.COM 		 * because that's how error gets returned.
2250*7568SJayakara.Kini@Sun.COM 		 * (segmap_getmapflt() never fails but segmap_fault()
2251*7568SJayakara.Kini@Sun.COM 		 * does.)
2252*7568SJayakara.Kini@Sun.COM 		 */
2253*7568SJayakara.Kini@Sun.COM 		if (segmap_fault(kas.a_hat, segkmap,
2254*7568SJayakara.Kini@Sun.COM 		    (caddr_t)(uintptr_t)(((uintptr_t)base + mapoff) & PAGEMASK),
2255*7568SJayakara.Kini@Sun.COM 		    snfi->snfi_len, F_SOFTLOCK, S_READ) != 0) {
2256*7568SJayakara.Kini@Sun.COM 			(void) segmap_release(segkmap, base, 0);
2257*7568SJayakara.Kini@Sun.COM 			kmem_free(snfi, sizeof (*snfi));
2258*7568SJayakara.Kini@Sun.COM 			error = EIO;
2259*7568SJayakara.Kini@Sun.COM 			goto out;
2260*7568SJayakara.Kini@Sun.COM 		}
2261*7568SJayakara.Kini@Sun.COM 		snfi->snfi_frtn.free_func = snf_smap_desbfree;
2262*7568SJayakara.Kini@Sun.COM 		snfi->snfi_frtn.free_arg = (caddr_t)snfi;
2263*7568SJayakara.Kini@Sun.COM 		snfi->snfi_base = base;
2264*7568SJayakara.Kini@Sun.COM 		snfi->snfi_mapoff = mapoff;
2265*7568SJayakara.Kini@Sun.COM 		mp = esballoca((uchar_t *)base + mapoff, iosize, BPRI_HI,
2266*7568SJayakara.Kini@Sun.COM 		    &snfi->snfi_frtn);
22670Sstevel@tonic-gate 
2268*7568SJayakara.Kini@Sun.COM 		if (mp == NULL) {
2269*7568SJayakara.Kini@Sun.COM 			(void) segmap_fault(kas.a_hat, segkmap,
2270*7568SJayakara.Kini@Sun.COM 			    (caddr_t)(uintptr_t)(((uintptr_t)base + mapoff)
2271*7568SJayakara.Kini@Sun.COM 			    & PAGEMASK), snfi->snfi_len, F_SOFTUNLOCK, S_OTHER);
2272*7568SJayakara.Kini@Sun.COM 			(void) segmap_release(segkmap, base, 0);
2273*7568SJayakara.Kini@Sun.COM 			kmem_free(snfi, sizeof (*snfi));
2274*7568SJayakara.Kini@Sun.COM 			freemsg(mp);
2275*7568SJayakara.Kini@Sun.COM 			error = EAGAIN;
2276*7568SJayakara.Kini@Sun.COM 			goto out;
2277*7568SJayakara.Kini@Sun.COM 		}
2278*7568SJayakara.Kini@Sun.COM 		VN_HOLD(fvp);
2279*7568SJayakara.Kini@Sun.COM 		snfi->snfi_vp = fvp;
2280*7568SJayakara.Kini@Sun.COM 		mp->b_wptr += iosize;
22810Sstevel@tonic-gate 
2282*7568SJayakara.Kini@Sun.COM 		/* Mark this dblk with the zero-copy flag */
2283*7568SJayakara.Kini@Sun.COM 		mp->b_datap->db_struioflag |= STRUIO_ZC;
2284*7568SJayakara.Kini@Sun.COM 		fileoff += iosize;
2285*7568SJayakara.Kini@Sun.COM 		size -= iosize;
22860Sstevel@tonic-gate 
22870Sstevel@tonic-gate 		if (size == 0 && !nowait) {
22880Sstevel@tonic-gate 			ASSERT(!dowait);
22890Sstevel@tonic-gate 			dowait = B_TRUE;
2290*7568SJayakara.Kini@Sun.COM 			mp->b_datap->db_struioflag |= STRUIO_ZCNOTIFY;
22910Sstevel@tonic-gate 		}
22920Sstevel@tonic-gate 		VOP_RWUNLOCK(fvp, V_WRITELOCK_FALSE, NULL);
22930Sstevel@tonic-gate 		if ((error = kstrwritemp(vp, mp, fflag)) != 0) {
22940Sstevel@tonic-gate 			*count = ksize;
22950Sstevel@tonic-gate 			freemsg(mp);
22960Sstevel@tonic-gate 			return (error);
22970Sstevel@tonic-gate 		}
22980Sstevel@tonic-gate 		ksize += iosize;
22990Sstevel@tonic-gate 		if (size == 0)
23000Sstevel@tonic-gate 			goto done;
23010Sstevel@tonic-gate 
23020Sstevel@tonic-gate 		(void) VOP_RWLOCK(fvp, V_WRITELOCK_FALSE, NULL);
23030Sstevel@tonic-gate 		va.va_mask = AT_SIZE;
23045331Samw 		error = VOP_GETATTR(fvp, &va, 0, kcred, NULL);
23050Sstevel@tonic-gate 		if (error)
23060Sstevel@tonic-gate 			break;
23070Sstevel@tonic-gate 		/* Read as much as possible. */
23080Sstevel@tonic-gate 		if (fileoff >= va.va_size)
23090Sstevel@tonic-gate 			break;
23100Sstevel@tonic-gate 		if (size + fileoff > va.va_size)
23110Sstevel@tonic-gate 			size = va.va_size - fileoff;
23120Sstevel@tonic-gate 	}
23130Sstevel@tonic-gate out:
23140Sstevel@tonic-gate 	VOP_RWUNLOCK(fvp, V_WRITELOCK_FALSE, NULL);
23150Sstevel@tonic-gate done:
23160Sstevel@tonic-gate 	*count = ksize;
23170Sstevel@tonic-gate 	if (dowait) {
23180Sstevel@tonic-gate 		stdata_t *stp;
23190Sstevel@tonic-gate 
23200Sstevel@tonic-gate 		stp = vp->v_stream;
23210Sstevel@tonic-gate 		mutex_enter(&stp->sd_lock);
23220Sstevel@tonic-gate 		while (!(stp->sd_flag & STZCNOTIFY)) {
23233415Samehta 			if (cv_wait_sig(&stp->sd_zcopy_wait,
23245227Stz204579 			    &stp->sd_lock) == 0) {
23253415Samehta 				error = EINTR;
23263415Samehta 				break;
23273415Samehta 			}
23280Sstevel@tonic-gate 		}
23290Sstevel@tonic-gate 		stp->sd_flag &= ~STZCNOTIFY;
23300Sstevel@tonic-gate 		mutex_exit(&stp->sd_lock);
23310Sstevel@tonic-gate 	}
23320Sstevel@tonic-gate 	return (error);
23330Sstevel@tonic-gate }
23340Sstevel@tonic-gate 
23350Sstevel@tonic-gate int
23360Sstevel@tonic-gate snf_cache(file_t *fp, vnode_t *fvp, u_offset_t fileoff, u_offset_t size,
23370Sstevel@tonic-gate     uint_t maxpsz, ssize_t *count)
23380Sstevel@tonic-gate {
23390Sstevel@tonic-gate 	struct vnode *vp;
23400Sstevel@tonic-gate 	mblk_t *mp;
23410Sstevel@tonic-gate 	int iosize;
23426240Skrishna 	int extra = 0;
23430Sstevel@tonic-gate 	int error;
23440Sstevel@tonic-gate 	short fflag;
23450Sstevel@tonic-gate 	int ksize;
23460Sstevel@tonic-gate 	int ioflag;
23470Sstevel@tonic-gate 	struct uio auio;
23480Sstevel@tonic-gate 	struct iovec aiov;
23490Sstevel@tonic-gate 	struct vattr va;
23500Sstevel@tonic-gate 
23510Sstevel@tonic-gate 	vp = fp->f_vnode;
23526240Skrishna 	if (vp->v_type == VSOCK) {
23536240Skrishna 		stdata_t *stp;
23546240Skrishna 
23556240Skrishna 		/*
23566240Skrishna 		 * Get the extra space to insert a header and a trailer.
23576240Skrishna 		 */
23586240Skrishna 		stp = vp->v_stream;
23596240Skrishna 		extra = (int)(stp->sd_wroff + stp->sd_tail);
23606240Skrishna 	}
23616240Skrishna 
23620Sstevel@tonic-gate 	fflag = fp->f_flag;
23630Sstevel@tonic-gate 	ksize = 0;
23640Sstevel@tonic-gate 	auio.uio_iov = &aiov;
23650Sstevel@tonic-gate 	auio.uio_iovcnt = 1;
23660Sstevel@tonic-gate 	auio.uio_segflg = UIO_SYSSPACE;
23670Sstevel@tonic-gate 	auio.uio_llimit = MAXOFFSET_T;
23680Sstevel@tonic-gate 	auio.uio_fmode = fflag;
23690Sstevel@tonic-gate 	auio.uio_extflg = UIO_COPY_CACHED;
23700Sstevel@tonic-gate 	ioflag = auio.uio_fmode & (FSYNC|FDSYNC|FRSYNC);
23710Sstevel@tonic-gate 	/* If read sync is not asked for, filter sync flags */
23720Sstevel@tonic-gate 	if ((ioflag & FRSYNC) == 0)
23730Sstevel@tonic-gate 		ioflag &= ~(FSYNC|FDSYNC);
23740Sstevel@tonic-gate 	for (;;) {
23750Sstevel@tonic-gate 		if (ISSIG(curthread, JUSTLOOKING)) {
23760Sstevel@tonic-gate 			error = EINTR;
23770Sstevel@tonic-gate 			break;
23780Sstevel@tonic-gate 		}
23790Sstevel@tonic-gate 		iosize = (int)MIN(maxpsz, size);
23806240Skrishna 		if ((mp = allocb(iosize + extra, BPRI_MED)) == NULL) {
23810Sstevel@tonic-gate 			error = EAGAIN;
23820Sstevel@tonic-gate 			break;
23830Sstevel@tonic-gate 		}
23840Sstevel@tonic-gate 		aiov.iov_base = (caddr_t)mp->b_rptr;
23850Sstevel@tonic-gate 		aiov.iov_len = iosize;
23860Sstevel@tonic-gate 		auio.uio_loffset = fileoff;
23870Sstevel@tonic-gate 		auio.uio_resid = iosize;
23880Sstevel@tonic-gate 
23890Sstevel@tonic-gate 		error = VOP_READ(fvp, &auio, ioflag, fp->f_cred, NULL);
23900Sstevel@tonic-gate 		iosize -= auio.uio_resid;
23910Sstevel@tonic-gate 
23920Sstevel@tonic-gate 		if (error == EINTR && iosize != 0)
23930Sstevel@tonic-gate 			error = 0;
23940Sstevel@tonic-gate 
23950Sstevel@tonic-gate 		if (error != 0 || iosize == 0) {
23960Sstevel@tonic-gate 			freeb(mp);
23970Sstevel@tonic-gate 			break;
23980Sstevel@tonic-gate 		}
23990Sstevel@tonic-gate 		mp->b_wptr = mp->b_rptr + iosize;
24000Sstevel@tonic-gate 
24010Sstevel@tonic-gate 		VOP_RWUNLOCK(fvp, V_WRITELOCK_FALSE, NULL);
24020Sstevel@tonic-gate 		if ((error = kstrwritemp(vp, mp, fflag)) != 0) {
24030Sstevel@tonic-gate 			*count = ksize;
24040Sstevel@tonic-gate 			freeb(mp);
24050Sstevel@tonic-gate 			return (error);
24060Sstevel@tonic-gate 		}
24070Sstevel@tonic-gate 		ksize += iosize;
24080Sstevel@tonic-gate 		size -= iosize;
24090Sstevel@tonic-gate 		if (size == 0)
24100Sstevel@tonic-gate 			goto done;
24110Sstevel@tonic-gate 
24120Sstevel@tonic-gate 		fileoff += iosize;
24130Sstevel@tonic-gate 		(void) VOP_RWLOCK(fvp, V_WRITELOCK_FALSE, NULL);
24140Sstevel@tonic-gate 		va.va_mask = AT_SIZE;
24155331Samw 		error = VOP_GETATTR(fvp, &va, 0, kcred, NULL);
24160Sstevel@tonic-gate 		if (error)
24170Sstevel@tonic-gate 			break;
24180Sstevel@tonic-gate 		/* Read as much as possible. */
24190Sstevel@tonic-gate 		if (fileoff >= va.va_size)
24200Sstevel@tonic-gate 			size = 0;
24210Sstevel@tonic-gate 		else if (size + fileoff > va.va_size)
24220Sstevel@tonic-gate 			size = va.va_size - fileoff;
24230Sstevel@tonic-gate 	}
24240Sstevel@tonic-gate 	VOP_RWUNLOCK(fvp, V_WRITELOCK_FALSE, NULL);
24250Sstevel@tonic-gate done:
24260Sstevel@tonic-gate 	*count = ksize;
24270Sstevel@tonic-gate 	return (error);
24280Sstevel@tonic-gate }
24290Sstevel@tonic-gate 
24300Sstevel@tonic-gate #if defined(_SYSCALL32_IMPL) || defined(_ILP32)
24310Sstevel@tonic-gate /*
24320Sstevel@tonic-gate  * Largefile support for 32 bit applications only.
24330Sstevel@tonic-gate  */
24340Sstevel@tonic-gate int
24350Sstevel@tonic-gate sosendfile64(file_t *fp, file_t *rfp, const struct ksendfilevec64 *sfv,
24360Sstevel@tonic-gate     ssize32_t *count32)
24370Sstevel@tonic-gate {
24380Sstevel@tonic-gate 	ssize32_t sfv_len;
24390Sstevel@tonic-gate 	u_offset_t sfv_off, va_size;
24400Sstevel@tonic-gate 	struct vnode *vp, *fvp, *realvp;
24410Sstevel@tonic-gate 	struct vattr va;
24420Sstevel@tonic-gate 	stdata_t *stp;
24430Sstevel@tonic-gate 	ssize_t count = 0;
24440Sstevel@tonic-gate 	int error = 0;
24450Sstevel@tonic-gate 	boolean_t dozcopy = B_FALSE;
24460Sstevel@tonic-gate 	uint_t maxpsz;
24470Sstevel@tonic-gate 
24480Sstevel@tonic-gate 	sfv_len = (ssize32_t)sfv->sfv_len;
24490Sstevel@tonic-gate 	if (sfv_len < 0) {
24500Sstevel@tonic-gate 		error = EINVAL;
24510Sstevel@tonic-gate 		goto out;
24520Sstevel@tonic-gate 	}
24530Sstevel@tonic-gate 
24540Sstevel@tonic-gate 	if (sfv_len == 0) goto out;
24550Sstevel@tonic-gate 
24560Sstevel@tonic-gate 	sfv_off = (u_offset_t)sfv->sfv_off;
24570Sstevel@tonic-gate 
24580Sstevel@tonic-gate 	/* Same checks as in pread */
24590Sstevel@tonic-gate 	if (sfv_off > MAXOFFSET_T) {
24600Sstevel@tonic-gate 		error = EINVAL;
24610Sstevel@tonic-gate 		goto out;
24620Sstevel@tonic-gate 	}
24630Sstevel@tonic-gate 	if (sfv_off + sfv_len > MAXOFFSET_T)
24640Sstevel@tonic-gate 		sfv_len = (ssize32_t)(MAXOFFSET_T - sfv_off);
24650Sstevel@tonic-gate 
24660Sstevel@tonic-gate 	/*
24670Sstevel@tonic-gate 	 * There are no more checks on sfv_len. So, we cast it to
24680Sstevel@tonic-gate 	 * u_offset_t and share the snf_direct_io/snf_cache code between
24690Sstevel@tonic-gate 	 * 32 bit and 64 bit.
24700Sstevel@tonic-gate 	 *
24710Sstevel@tonic-gate 	 * TODO: should do nbl_need_check() like read()?
24720Sstevel@tonic-gate 	 */
24730Sstevel@tonic-gate 	if (sfv_len > sendfile_max_size) {
24740Sstevel@tonic-gate 		sf_stats.ss_file_not_cached++;
24750Sstevel@tonic-gate 		error = snf_direct_io(fp, rfp, sfv_off, (u_offset_t)sfv_len,
24760Sstevel@tonic-gate 		    &count);
24770Sstevel@tonic-gate 		goto out;
24780Sstevel@tonic-gate 	}
24790Sstevel@tonic-gate 	fvp = rfp->f_vnode;
24805331Samw 	if (VOP_REALVP(fvp, &realvp, NULL) == 0)
24810Sstevel@tonic-gate 		fvp = realvp;
24820Sstevel@tonic-gate 	/*
24830Sstevel@tonic-gate 	 * Grab the lock as a reader to prevent the file size
24840Sstevel@tonic-gate 	 * from changing underneath.
24850Sstevel@tonic-gate 	 */
24860Sstevel@tonic-gate 	(void) VOP_RWLOCK(fvp, V_WRITELOCK_FALSE, NULL);
24870Sstevel@tonic-gate 	va.va_mask = AT_SIZE;
24885331Samw 	error = VOP_GETATTR(fvp, &va, 0, kcred, NULL);
24890Sstevel@tonic-gate 	va_size = va.va_size;
24904649Sdm120769 	if ((error != 0) || (va_size == 0) || (sfv_off >= va_size)) {
24910Sstevel@tonic-gate 		VOP_RWUNLOCK(fvp, V_WRITELOCK_FALSE, NULL);
24920Sstevel@tonic-gate 		goto out;
24930Sstevel@tonic-gate 	}
24940Sstevel@tonic-gate 	/* Read as much as possible. */
24950Sstevel@tonic-gate 	if (sfv_off + sfv_len > va_size)
24960Sstevel@tonic-gate 		sfv_len = va_size - sfv_off;
24970Sstevel@tonic-gate 
24980Sstevel@tonic-gate 	vp = fp->f_vnode;
24990Sstevel@tonic-gate 	stp = vp->v_stream;
25000Sstevel@tonic-gate 	/*
25010Sstevel@tonic-gate 	 * When the NOWAIT flag is not set, we enable zero-copy only if the
25020Sstevel@tonic-gate 	 * transfer size is large enough. This prevents performance loss
25030Sstevel@tonic-gate 	 * when the caller sends the file piece by piece.
25040Sstevel@tonic-gate 	 */
25050Sstevel@tonic-gate 	if (sfv_len >= MAXBSIZE && (sfv_len >= (va_size >> 1) ||
25060Sstevel@tonic-gate 	    (sfv->sfv_flag & SFV_NOWAIT) || sfv_len >= 0x1000000) &&
25074173Spr14459 	    !vn_has_flocks(fvp) && !(fvp->v_flag & VNOMAP)) {
25080Sstevel@tonic-gate 		if ((stp->sd_copyflag & (STZCVMSAFE|STZCVMUNSAFE)) == 0) {
25090Sstevel@tonic-gate 			int on = 1;
25100Sstevel@tonic-gate 
25110Sstevel@tonic-gate 			if (SOP_SETSOCKOPT(VTOSO(vp), SOL_SOCKET,
25120Sstevel@tonic-gate 			    SO_SND_COPYAVOID, &on, sizeof (on)) == 0)
25130Sstevel@tonic-gate 				dozcopy = B_TRUE;
25140Sstevel@tonic-gate 		} else {
25150Sstevel@tonic-gate 			dozcopy = (stp->sd_copyflag & STZCVMSAFE);
25160Sstevel@tonic-gate 		}
25170Sstevel@tonic-gate 	}
25180Sstevel@tonic-gate 	if (dozcopy) {
25190Sstevel@tonic-gate 		sf_stats.ss_file_segmap++;
25200Sstevel@tonic-gate 		error = snf_segmap(fp, fvp, sfv_off, (u_offset_t)sfv_len,
2521*7568SJayakara.Kini@Sun.COM 		    &count, ((sfv->sfv_flag & SFV_NOWAIT) != 0));
25220Sstevel@tonic-gate 	} else {
2523*7568SJayakara.Kini@Sun.COM 		if (stp->sd_qn_maxpsz == INFPSZ)
2524*7568SJayakara.Kini@Sun.COM 			maxpsz = maxphys;
2525*7568SJayakara.Kini@Sun.COM 		else
2526*7568SJayakara.Kini@Sun.COM 			maxpsz = roundup(stp->sd_qn_maxpsz, MAXBSIZE);
25270Sstevel@tonic-gate 		sf_stats.ss_file_cached++;
25280Sstevel@tonic-gate 		error = snf_cache(fp, fvp, sfv_off, (u_offset_t)sfv_len,
25290Sstevel@tonic-gate 		    maxpsz, &count);
25300Sstevel@tonic-gate 	}
25310Sstevel@tonic-gate out:
25320Sstevel@tonic-gate 	releasef(sfv->sfv_fd);
25330Sstevel@tonic-gate 	*count32 = (ssize32_t)count;
25340Sstevel@tonic-gate 	return (error);
25350Sstevel@tonic-gate }
25360Sstevel@tonic-gate #endif
25370Sstevel@tonic-gate 
25380Sstevel@tonic-gate #ifdef _SYSCALL32_IMPL
25390Sstevel@tonic-gate /*
25400Sstevel@tonic-gate  * recv32(), recvfrom32(), send32(), sendto32(): intentionally return a
25410Sstevel@tonic-gate  * ssize_t rather than ssize32_t; see the comments above read32 for details.
25420Sstevel@tonic-gate  */
25430Sstevel@tonic-gate 
25440Sstevel@tonic-gate ssize_t
25450Sstevel@tonic-gate recv32(int32_t sock, caddr32_t buffer, size32_t len, int32_t flags)
25460Sstevel@tonic-gate {
25470Sstevel@tonic-gate 	return (recv(sock, (void *)(uintptr_t)buffer, (ssize32_t)len, flags));
25480Sstevel@tonic-gate }
25490Sstevel@tonic-gate 
25500Sstevel@tonic-gate ssize_t
25510Sstevel@tonic-gate recvfrom32(int32_t sock, caddr32_t buffer, size32_t len, int32_t flags,
25520Sstevel@tonic-gate 	caddr32_t name, caddr32_t namelenp)
25530Sstevel@tonic-gate {
25540Sstevel@tonic-gate 	return (recvfrom(sock, (void *)(uintptr_t)buffer, (ssize32_t)len, flags,
25550Sstevel@tonic-gate 	    (void *)(uintptr_t)name, (void *)(uintptr_t)namelenp));
25560Sstevel@tonic-gate }
25570Sstevel@tonic-gate 
25580Sstevel@tonic-gate ssize_t
25590Sstevel@tonic-gate send32(int32_t sock, caddr32_t buffer, size32_t len, int32_t flags)
25600Sstevel@tonic-gate {
25610Sstevel@tonic-gate 	return (send(sock, (void *)(uintptr_t)buffer, (ssize32_t)len, flags));
25620Sstevel@tonic-gate }
25630Sstevel@tonic-gate 
25640Sstevel@tonic-gate ssize_t
25650Sstevel@tonic-gate sendto32(int32_t sock, caddr32_t buffer, size32_t len, int32_t flags,
25660Sstevel@tonic-gate 	caddr32_t name, socklen_t namelen)
25670Sstevel@tonic-gate {
25680Sstevel@tonic-gate 	return (sendto(sock, (void *)(uintptr_t)buffer, (ssize32_t)len, flags,
25690Sstevel@tonic-gate 	    (void *)(uintptr_t)name, namelen));
25700Sstevel@tonic-gate }
25710Sstevel@tonic-gate #endif	/* _SYSCALL32_IMPL */
25720Sstevel@tonic-gate 
25730Sstevel@tonic-gate /*
25745331Samw  * Function wrappers (mostly around the sonode switch) for
25750Sstevel@tonic-gate  * backward compatibility.
25760Sstevel@tonic-gate  */
25770Sstevel@tonic-gate 
25780Sstevel@tonic-gate int
25790Sstevel@tonic-gate soaccept(struct sonode *so, int fflag, struct sonode **nsop)
25800Sstevel@tonic-gate {
25810Sstevel@tonic-gate 	return (SOP_ACCEPT(so, fflag, nsop));
25820Sstevel@tonic-gate }
25830Sstevel@tonic-gate 
25840Sstevel@tonic-gate int
25850Sstevel@tonic-gate sobind(struct sonode *so, struct sockaddr *name, socklen_t namelen,
25860Sstevel@tonic-gate     int backlog, int flags)
25870Sstevel@tonic-gate {
25880Sstevel@tonic-gate 	int	error;
25890Sstevel@tonic-gate 
25900Sstevel@tonic-gate 	error = SOP_BIND(so, name, namelen, flags);
25910Sstevel@tonic-gate 	if (error == 0 && backlog != 0)
25920Sstevel@tonic-gate 		return (SOP_LISTEN(so, backlog));
25930Sstevel@tonic-gate 
25940Sstevel@tonic-gate 	return (error);
25950Sstevel@tonic-gate }
25960Sstevel@tonic-gate 
25970Sstevel@tonic-gate int
25980Sstevel@tonic-gate solisten(struct sonode *so, int backlog)
25990Sstevel@tonic-gate {
26000Sstevel@tonic-gate 	return (SOP_LISTEN(so, backlog));
26010Sstevel@tonic-gate }
26020Sstevel@tonic-gate 
26030Sstevel@tonic-gate int
26040Sstevel@tonic-gate soconnect(struct sonode *so, const struct sockaddr *name, socklen_t namelen,
26050Sstevel@tonic-gate     int fflag, int flags)
26060Sstevel@tonic-gate {
26070Sstevel@tonic-gate 	return (SOP_CONNECT(so, name, namelen, fflag, flags));
26080Sstevel@tonic-gate }
26090Sstevel@tonic-gate 
26100Sstevel@tonic-gate int
26110Sstevel@tonic-gate sorecvmsg(struct sonode *so, struct nmsghdr *msg, struct uio *uiop)
26120Sstevel@tonic-gate {
26130Sstevel@tonic-gate 	return (SOP_RECVMSG(so, msg, uiop));
26140Sstevel@tonic-gate }
26150Sstevel@tonic-gate 
26160Sstevel@tonic-gate int
26170Sstevel@tonic-gate sosendmsg(struct sonode *so, struct nmsghdr *msg, struct uio *uiop)
26180Sstevel@tonic-gate {
26190Sstevel@tonic-gate 	return (SOP_SENDMSG(so, msg, uiop));
26200Sstevel@tonic-gate }
26210Sstevel@tonic-gate 
26220Sstevel@tonic-gate int
26230Sstevel@tonic-gate sogetpeername(struct sonode *so)
26240Sstevel@tonic-gate {
26250Sstevel@tonic-gate 	return (SOP_GETPEERNAME(so));
26260Sstevel@tonic-gate }
26270Sstevel@tonic-gate 
26280Sstevel@tonic-gate int
26290Sstevel@tonic-gate sogetsockname(struct sonode *so)
26300Sstevel@tonic-gate {
26310Sstevel@tonic-gate 	return (SOP_GETSOCKNAME(so));
26320Sstevel@tonic-gate }
26330Sstevel@tonic-gate 
26340Sstevel@tonic-gate int
26350Sstevel@tonic-gate soshutdown(struct sonode *so, int how)
26360Sstevel@tonic-gate {
26370Sstevel@tonic-gate 	return (SOP_SHUTDOWN(so, how));
26380Sstevel@tonic-gate }
26390Sstevel@tonic-gate 
26400Sstevel@tonic-gate int
26410Sstevel@tonic-gate sogetsockopt(struct sonode *so, int level, int option_name, void *optval,
26420Sstevel@tonic-gate     socklen_t *optlenp, int flags)
26430Sstevel@tonic-gate {
26440Sstevel@tonic-gate 	return (SOP_GETSOCKOPT(so, level, option_name, optval, optlenp,
26450Sstevel@tonic-gate 	    flags));
26460Sstevel@tonic-gate }
26470Sstevel@tonic-gate 
26480Sstevel@tonic-gate int
26490Sstevel@tonic-gate sosetsockopt(struct sonode *so, int level, int option_name, const void *optval,
26500Sstevel@tonic-gate     t_uscalar_t optlen)
26510Sstevel@tonic-gate {
26520Sstevel@tonic-gate 	return (SOP_SETSOCKOPT(so, level, option_name, optval, optlen));
26530Sstevel@tonic-gate }
26540Sstevel@tonic-gate 
26550Sstevel@tonic-gate /*
26560Sstevel@tonic-gate  * Because this is backward compatibility interface it only needs to be
26570Sstevel@tonic-gate  * able to handle the creation of TPI sockfs sockets.
26580Sstevel@tonic-gate  */
26590Sstevel@tonic-gate struct sonode *
26600Sstevel@tonic-gate socreate(vnode_t *accessvp, int domain, int type, int protocol, int version,
26610Sstevel@tonic-gate     struct sonode *tso, int *errorp)
26620Sstevel@tonic-gate {
26630Sstevel@tonic-gate 	return (sotpi_create(accessvp, domain, type, protocol, version, tso,
26640Sstevel@tonic-gate 	    errorp));
26650Sstevel@tonic-gate }
2666