xref: /titanic_41/usr/src/uts/common/io/ksocket/ksocket.c (revision 3076c25a759075dcc052165713ce638ecf989184)
10f1702c5SYu Xiangning /*
20f1702c5SYu Xiangning  * CDDL HEADER START
30f1702c5SYu Xiangning  *
40f1702c5SYu Xiangning  * The contents of this file are subject to the terms of the
50f1702c5SYu Xiangning  * Common Development and Distribution License (the "License").
60f1702c5SYu Xiangning  * You may not use this file except in compliance with the License.
70f1702c5SYu Xiangning  *
80f1702c5SYu Xiangning  * You can obtain a copy of the license at usr/src/OPENSOLARIS.LICENSE
90f1702c5SYu Xiangning  * or http://www.opensolaris.org/os/licensing.
100f1702c5SYu Xiangning  * See the License for the specific language governing permissions
110f1702c5SYu Xiangning  * and limitations under the License.
120f1702c5SYu Xiangning  *
130f1702c5SYu Xiangning  * When distributing Covered Code, include this CDDL HEADER in each
140f1702c5SYu Xiangning  * file and include the License file at usr/src/OPENSOLARIS.LICENSE.
150f1702c5SYu Xiangning  * If applicable, add the following below this CDDL HEADER, with the
160f1702c5SYu Xiangning  * fields enclosed by brackets "[]" replaced with your own identifying
170f1702c5SYu Xiangning  * information: Portions Copyright [yyyy] [name of copyright owner]
180f1702c5SYu Xiangning  *
190f1702c5SYu Xiangning  * CDDL HEADER END
200f1702c5SYu Xiangning  */
210f1702c5SYu Xiangning 
220f1702c5SYu Xiangning /*
23*3076c25aSStepan Zastupov  * Copyright 2011 Nexenta Systems, Inc.  All rights reserved.
243e95bd4aSAnders Persson  * Copyright (c) 2008, 2010, Oracle and/or its affiliates. All rights reserved.
250f1702c5SYu Xiangning  */
260f1702c5SYu Xiangning 
270f1702c5SYu Xiangning #include <sys/file.h>
280f1702c5SYu Xiangning #include <sys/stropts.h>
290f1702c5SYu Xiangning #include <sys/socket.h>
300f1702c5SYu Xiangning #include <sys/socketvar.h>
310f1702c5SYu Xiangning #include <sys/sysmacros.h>
320f1702c5SYu Xiangning #include <sys/filio.h>		/* FIO* ioctls */
330f1702c5SYu Xiangning #include <sys/sockio.h>		/* SIOC* ioctls */
34*3076c25aSStepan Zastupov #include <sys/poll_impl.h>
350f1702c5SYu Xiangning #include <sys/cmn_err.h>
360f1702c5SYu Xiangning #include <sys/ksocket.h>
370f1702c5SYu Xiangning #include <io/ksocket/ksocket_impl.h>
380f1702c5SYu Xiangning #include <fs/sockfs/sockcommon.h>
390f1702c5SYu Xiangning 
400f1702c5SYu Xiangning #define	SOCKETMOD_TCP	"tcp"
410f1702c5SYu Xiangning #define	SOCKETMOD_UDP	"udp"
420f1702c5SYu Xiangning /*
430f1702c5SYu Xiangning  * Kernel Sockets
440f1702c5SYu Xiangning  *
450f1702c5SYu Xiangning  * Mostly a wrapper around the private socket_* functions.
460f1702c5SYu Xiangning  */
470f1702c5SYu Xiangning int
ksocket_socket(ksocket_t * ksp,int domain,int type,int protocol,int flags,struct cred * cr)480f1702c5SYu Xiangning ksocket_socket(ksocket_t *ksp, int domain, int type, int protocol, int flags,
490f1702c5SYu Xiangning     struct cred *cr)
500f1702c5SYu Xiangning {
510f1702c5SYu Xiangning 	static const int version = SOV_DEFAULT;
520f1702c5SYu Xiangning 	int error = 0;
530f1702c5SYu Xiangning 	struct sonode *so;
540f1702c5SYu Xiangning 	*ksp = NULL;
550f1702c5SYu Xiangning 
56de8c4a14SErik Nordmark 	/* All Solaris components should pass a cred for this operation. */
57de8c4a14SErik Nordmark 	ASSERT(cr != NULL);
58de8c4a14SErik Nordmark 
59*3076c25aSStepan Zastupov 	if (domain == AF_NCA)
600f1702c5SYu Xiangning 		return (EAFNOSUPPORT);
610f1702c5SYu Xiangning 
620f1702c5SYu Xiangning 	ASSERT(flags == KSOCKET_SLEEP || flags == KSOCKET_NOSLEEP);
630f1702c5SYu Xiangning 	so = socket_create(domain, type, protocol, NULL, NULL, version, flags,
640f1702c5SYu Xiangning 	    cr, &error);
650f1702c5SYu Xiangning 	if (so == NULL) {
660f1702c5SYu Xiangning 		if (error == EAFNOSUPPORT) {
670f1702c5SYu Xiangning 			char *mod = NULL;
680f1702c5SYu Xiangning 
690f1702c5SYu Xiangning 			/*
700f1702c5SYu Xiangning 			 * Could be that root file sytem is not loaded or
710f1702c5SYu Xiangning 			 * soconfig has not run yet.
720f1702c5SYu Xiangning 			 */
730f1702c5SYu Xiangning 			if (type == SOCK_STREAM && (domain == AF_INET ||
740f1702c5SYu Xiangning 			    domain == AF_INET6) && (protocol == 0 ||
750f1702c5SYu Xiangning 			    protocol == IPPROTO_TCP)) {
760f1702c5SYu Xiangning 					mod = SOCKETMOD_TCP;
770f1702c5SYu Xiangning 			} else if (type == SOCK_DGRAM && (domain == AF_INET ||
780f1702c5SYu Xiangning 			    domain == AF_INET6) && (protocol == 0 ||
790f1702c5SYu Xiangning 			    protocol == IPPROTO_UDP)) {
800f1702c5SYu Xiangning 					mod = SOCKETMOD_UDP;
810f1702c5SYu Xiangning 			} else {
820f1702c5SYu Xiangning 				return (EAFNOSUPPORT);
830f1702c5SYu Xiangning 			}
840f1702c5SYu Xiangning 
850f1702c5SYu Xiangning 			so = socket_create(domain, type, protocol, NULL,
860f1702c5SYu Xiangning 			    mod, version, flags, cr, &error);
870f1702c5SYu Xiangning 			if (so == NULL)
880f1702c5SYu Xiangning 				return (error);
890f1702c5SYu Xiangning 		} else {
900f1702c5SYu Xiangning 			return (error);
910f1702c5SYu Xiangning 		}
920f1702c5SYu Xiangning 	}
930f1702c5SYu Xiangning 
940f1702c5SYu Xiangning 	so->so_mode |= SM_KERNEL;
950f1702c5SYu Xiangning 
960f1702c5SYu Xiangning 	*ksp = SOTOKS(so);
970f1702c5SYu Xiangning 
980f1702c5SYu Xiangning 	return (0);
990f1702c5SYu Xiangning }
1000f1702c5SYu Xiangning int
ksocket_bind(ksocket_t ks,struct sockaddr * addr,socklen_t addrlen,struct cred * cr)1010f1702c5SYu Xiangning ksocket_bind(ksocket_t ks, struct sockaddr *addr, socklen_t addrlen,
1020f1702c5SYu Xiangning     struct cred *cr)
1030f1702c5SYu Xiangning {
1040f1702c5SYu Xiangning 	int error;
1050f1702c5SYu Xiangning 
106de8c4a14SErik Nordmark 	/* All Solaris components should pass a cred for this operation. */
107de8c4a14SErik Nordmark 	ASSERT(cr != NULL);
108de8c4a14SErik Nordmark 
1090f1702c5SYu Xiangning 	if (!KSOCKET_VALID(ks))
1100f1702c5SYu Xiangning 		return (ENOTSOCK);
1110f1702c5SYu Xiangning 
1120f1702c5SYu Xiangning 	error = socket_bind(KSTOSO(ks), addr, addrlen, _SOBIND_SOCKBSD, cr);
1130f1702c5SYu Xiangning 
1140f1702c5SYu Xiangning 	return (error);
1150f1702c5SYu Xiangning }
1160f1702c5SYu Xiangning 
1170f1702c5SYu Xiangning int
ksocket_listen(ksocket_t ks,int backlog,struct cred * cr)1180f1702c5SYu Xiangning ksocket_listen(ksocket_t ks, int backlog, struct cred *cr)
1190f1702c5SYu Xiangning {
120de8c4a14SErik Nordmark 	/* All Solaris components should pass a cred for this operation. */
121de8c4a14SErik Nordmark 	ASSERT(cr != NULL);
122de8c4a14SErik Nordmark 
1230f1702c5SYu Xiangning 	if (!KSOCKET_VALID(ks))
1240f1702c5SYu Xiangning 		return (ENOTSOCK);
1250f1702c5SYu Xiangning 
1260f1702c5SYu Xiangning 	return (socket_listen(KSTOSO(ks), backlog, cr));
1270f1702c5SYu Xiangning }
1280f1702c5SYu Xiangning 
1290f1702c5SYu Xiangning int
ksocket_accept(ksocket_t ks,struct sockaddr * addr,socklen_t * addrlenp,ksocket_t * nks,struct cred * cr)1300f1702c5SYu Xiangning ksocket_accept(ksocket_t ks, struct sockaddr *addr,
1310f1702c5SYu Xiangning     socklen_t *addrlenp, ksocket_t *nks, struct cred *cr)
1320f1702c5SYu Xiangning {
1330f1702c5SYu Xiangning 	int error;
1340f1702c5SYu Xiangning 	struct sonode *nso = NULL;
1350f1702c5SYu Xiangning 
136de8c4a14SErik Nordmark 	/* All Solaris components should pass a cred for this operation. */
137de8c4a14SErik Nordmark 	ASSERT(cr != NULL);
138de8c4a14SErik Nordmark 
1390f1702c5SYu Xiangning 	*nks = NULL;
1400f1702c5SYu Xiangning 
1410f1702c5SYu Xiangning 	if (!KSOCKET_VALID(ks))
1420f1702c5SYu Xiangning 		return (ENOTSOCK);
1430f1702c5SYu Xiangning 
1440f1702c5SYu Xiangning 	if (addr != NULL && addrlenp == NULL)
1450f1702c5SYu Xiangning 		return (EFAULT);
1460f1702c5SYu Xiangning 
1470f1702c5SYu Xiangning 	error = socket_accept(KSTOSO(ks), KSOCKET_FMODE(ks), cr, &nso);
1480f1702c5SYu Xiangning 	if (error != 0)
1490f1702c5SYu Xiangning 		return (error);
1500f1702c5SYu Xiangning 
1510f1702c5SYu Xiangning 	ASSERT(nso != NULL);
1520f1702c5SYu Xiangning 
1530f1702c5SYu Xiangning 	nso->so_mode |= SM_KERNEL;
1540f1702c5SYu Xiangning 
1550f1702c5SYu Xiangning 	if (addr != NULL && addrlenp != NULL) {
1560f1702c5SYu Xiangning 		error = socket_getpeername(nso, addr, addrlenp, B_TRUE, cr);
1570f1702c5SYu Xiangning 		if (error != 0) {
1580f1702c5SYu Xiangning 			(void) socket_close(nso, 0, cr);
1590f1702c5SYu Xiangning 			socket_destroy(nso);
1600f1702c5SYu Xiangning 			return ((error == ENOTCONN) ? ECONNABORTED : error);
1610f1702c5SYu Xiangning 		}
1620f1702c5SYu Xiangning 	}
1630f1702c5SYu Xiangning 
1640f1702c5SYu Xiangning 	*nks = SOTOKS(nso);
1650f1702c5SYu Xiangning 
1660f1702c5SYu Xiangning 	return (error);
1670f1702c5SYu Xiangning }
1680f1702c5SYu Xiangning 
1690f1702c5SYu Xiangning int
ksocket_connect(ksocket_t ks,struct sockaddr * addr,socklen_t addrlen,struct cred * cr)1703e95bd4aSAnders Persson ksocket_connect(ksocket_t ks, struct sockaddr *addr, socklen_t addrlen,
1710f1702c5SYu Xiangning     struct cred *cr)
1720f1702c5SYu Xiangning {
173de8c4a14SErik Nordmark 	/* All Solaris components should pass a cred for this operation. */
174de8c4a14SErik Nordmark 	ASSERT(cr != NULL);
175de8c4a14SErik Nordmark 
1760f1702c5SYu Xiangning 	if (!KSOCKET_VALID(ks))
1770f1702c5SYu Xiangning 		return (ENOTSOCK);
1780f1702c5SYu Xiangning 
1790f1702c5SYu Xiangning 	return (socket_connect(KSTOSO(ks), addr, addrlen,
1800f1702c5SYu Xiangning 	    KSOCKET_FMODE(ks), 0, cr));
1810f1702c5SYu Xiangning }
1820f1702c5SYu Xiangning 
1830f1702c5SYu Xiangning int
ksocket_send(ksocket_t ks,void * msg,size_t msglen,int flags,size_t * sent,struct cred * cr)1840f1702c5SYu Xiangning ksocket_send(ksocket_t ks, void *msg, size_t msglen, int flags,
1850f1702c5SYu Xiangning     size_t *sent, struct cred *cr)
1860f1702c5SYu Xiangning {
1870f1702c5SYu Xiangning 	int error;
1880f1702c5SYu Xiangning 	struct nmsghdr msghdr;
1890f1702c5SYu Xiangning 	struct uio auio;
1900f1702c5SYu Xiangning 	struct iovec iov;
1910f1702c5SYu Xiangning 
192de8c4a14SErik Nordmark 	/* All Solaris components should pass a cred for this operation. */
193de8c4a14SErik Nordmark 	ASSERT(cr != NULL);
194de8c4a14SErik Nordmark 
1950f1702c5SYu Xiangning 	if (!KSOCKET_VALID(ks)) {
1960f1702c5SYu Xiangning 		if (sent != NULL)
1970f1702c5SYu Xiangning 			*sent = 0;
1980f1702c5SYu Xiangning 		return (ENOTSOCK);
1990f1702c5SYu Xiangning 	}
2000f1702c5SYu Xiangning 
2010f1702c5SYu Xiangning 	iov.iov_base = msg;
2020f1702c5SYu Xiangning 	iov.iov_len = msglen;
2030f1702c5SYu Xiangning 
2040f1702c5SYu Xiangning 	bzero(&auio, sizeof (struct uio));
2050f1702c5SYu Xiangning 	auio.uio_loffset = 0;
2060f1702c5SYu Xiangning 	auio.uio_iov = &iov;
2070f1702c5SYu Xiangning 	auio.uio_iovcnt = 1;
2080f1702c5SYu Xiangning 	auio.uio_resid = msglen;
2090f1702c5SYu Xiangning 	if (flags & MSG_USERSPACE)
2100f1702c5SYu Xiangning 		auio.uio_segflg = UIO_USERSPACE;
2110f1702c5SYu Xiangning 	else
2120f1702c5SYu Xiangning 		auio.uio_segflg = UIO_SYSSPACE;
2130f1702c5SYu Xiangning 	auio.uio_extflg = UIO_COPY_DEFAULT;
2140f1702c5SYu Xiangning 	auio.uio_limit = 0;
2150f1702c5SYu Xiangning 	auio.uio_fmode = KSOCKET_FMODE(ks);
2160f1702c5SYu Xiangning 
2170f1702c5SYu Xiangning 	msghdr.msg_name = NULL;
2180f1702c5SYu Xiangning 	msghdr.msg_namelen = 0;
2190f1702c5SYu Xiangning 	msghdr.msg_control = NULL;
2200f1702c5SYu Xiangning 	msghdr.msg_controllen = 0;
2210f1702c5SYu Xiangning 	msghdr.msg_flags = flags | MSG_EOR;
2220f1702c5SYu Xiangning 
2230f1702c5SYu Xiangning 	error = socket_sendmsg(KSTOSO(ks), &msghdr, &auio, cr);
2240f1702c5SYu Xiangning 	if (error != 0) {
2250f1702c5SYu Xiangning 		if (sent != NULL)
2260f1702c5SYu Xiangning 			*sent = 0;
2270f1702c5SYu Xiangning 		return (error);
2280f1702c5SYu Xiangning 	}
2290f1702c5SYu Xiangning 
2300f1702c5SYu Xiangning 	if (sent != NULL)
2310f1702c5SYu Xiangning 		*sent = msglen - auio.uio_resid;
2320f1702c5SYu Xiangning 	return (0);
2330f1702c5SYu Xiangning }
2340f1702c5SYu Xiangning 
2350f1702c5SYu Xiangning int
ksocket_sendto(ksocket_t ks,void * msg,size_t msglen,int flags,struct sockaddr * name,socklen_t namelen,size_t * sent,struct cred * cr)2360f1702c5SYu Xiangning ksocket_sendto(ksocket_t ks, void *msg, size_t msglen, int flags,
2370f1702c5SYu Xiangning     struct sockaddr *name, socklen_t namelen, size_t *sent, struct cred *cr)
2380f1702c5SYu Xiangning {
2390f1702c5SYu Xiangning 	int error;
2400f1702c5SYu Xiangning 	struct nmsghdr msghdr;
2410f1702c5SYu Xiangning 	struct uio auio;
2420f1702c5SYu Xiangning 	struct iovec iov;
2430f1702c5SYu Xiangning 
244de8c4a14SErik Nordmark 	/* All Solaris components should pass a cred for this operation. */
245de8c4a14SErik Nordmark 	ASSERT(cr != NULL);
246de8c4a14SErik Nordmark 
2470f1702c5SYu Xiangning 	if (!KSOCKET_VALID(ks)) {
2480f1702c5SYu Xiangning 		if (sent != NULL)
2490f1702c5SYu Xiangning 			*sent = 0;
2500f1702c5SYu Xiangning 		return (ENOTSOCK);
2510f1702c5SYu Xiangning 	}
2520f1702c5SYu Xiangning 
2530f1702c5SYu Xiangning 	iov.iov_base = msg;
2540f1702c5SYu Xiangning 	iov.iov_len = msglen;
2550f1702c5SYu Xiangning 
2560f1702c5SYu Xiangning 	bzero(&auio, sizeof (struct uio));
2570f1702c5SYu Xiangning 	auio.uio_loffset = 0;
2580f1702c5SYu Xiangning 	auio.uio_iov = &iov;
2590f1702c5SYu Xiangning 	auio.uio_iovcnt = 1;
2600f1702c5SYu Xiangning 	auio.uio_resid = msglen;
2610f1702c5SYu Xiangning 	if (flags & MSG_USERSPACE)
2620f1702c5SYu Xiangning 		auio.uio_segflg = UIO_USERSPACE;
2630f1702c5SYu Xiangning 	else
2640f1702c5SYu Xiangning 		auio.uio_segflg = UIO_SYSSPACE;
2650f1702c5SYu Xiangning 	auio.uio_extflg = UIO_COPY_DEFAULT;
2660f1702c5SYu Xiangning 	auio.uio_limit = 0;
2670f1702c5SYu Xiangning 	auio.uio_fmode = KSOCKET_FMODE(ks);
2680f1702c5SYu Xiangning 
2690f1702c5SYu Xiangning 	msghdr.msg_iov = &iov;
2700f1702c5SYu Xiangning 	msghdr.msg_iovlen = 1;
2710f1702c5SYu Xiangning 	msghdr.msg_name = (char *)name;
2720f1702c5SYu Xiangning 	msghdr.msg_namelen = namelen;
2730f1702c5SYu Xiangning 	msghdr.msg_control = NULL;
2740f1702c5SYu Xiangning 	msghdr.msg_controllen = 0;
2750f1702c5SYu Xiangning 	msghdr.msg_flags = flags | MSG_EOR;
2760f1702c5SYu Xiangning 
2770f1702c5SYu Xiangning 	error = socket_sendmsg(KSTOSO(ks), &msghdr, &auio, cr);
2780f1702c5SYu Xiangning 	if (error != 0) {
2790f1702c5SYu Xiangning 		if (sent != NULL)
2800f1702c5SYu Xiangning 			*sent = 0;
2810f1702c5SYu Xiangning 		return (error);
2820f1702c5SYu Xiangning 	}
2830f1702c5SYu Xiangning 	if (sent != NULL)
2840f1702c5SYu Xiangning 		*sent = msglen - auio.uio_resid;
2850f1702c5SYu Xiangning 	return (0);
2860f1702c5SYu Xiangning }
2870f1702c5SYu Xiangning 
2880f1702c5SYu Xiangning int
ksocket_sendmsg(ksocket_t ks,struct nmsghdr * msg,int flags,size_t * sent,struct cred * cr)2890f1702c5SYu Xiangning ksocket_sendmsg(ksocket_t ks, struct nmsghdr *msg, int flags,
2900f1702c5SYu Xiangning     size_t *sent, struct cred *cr)
2910f1702c5SYu Xiangning {
2920f1702c5SYu Xiangning 	int error;
2930f1702c5SYu Xiangning 	ssize_t len;
2940f1702c5SYu Xiangning 	int i;
2950f1702c5SYu Xiangning 	struct uio auio;
2960f1702c5SYu Xiangning 
297de8c4a14SErik Nordmark 	/* All Solaris components should pass a cred for this operation. */
298de8c4a14SErik Nordmark 	ASSERT(cr != NULL);
299de8c4a14SErik Nordmark 
3000f1702c5SYu Xiangning 	if (!KSOCKET_VALID(ks)) {
3010f1702c5SYu Xiangning 		if (sent != NULL)
3020f1702c5SYu Xiangning 			*sent = 0;
3030f1702c5SYu Xiangning 		return (ENOTSOCK);
3040f1702c5SYu Xiangning 	}
3050f1702c5SYu Xiangning 
3060f1702c5SYu Xiangning 	bzero(&auio, sizeof (struct uio));
3070f1702c5SYu Xiangning 	auio.uio_loffset = 0;
3080f1702c5SYu Xiangning 	auio.uio_iov = msg->msg_iov;
3090f1702c5SYu Xiangning 	auio.uio_iovcnt = msg->msg_iovlen;
3100f1702c5SYu Xiangning 	if (flags & MSG_USERSPACE)
3110f1702c5SYu Xiangning 		auio.uio_segflg = UIO_USERSPACE;
3120f1702c5SYu Xiangning 	else
3130f1702c5SYu Xiangning 		auio.uio_segflg = UIO_SYSSPACE;
3140f1702c5SYu Xiangning 	auio.uio_extflg = UIO_COPY_DEFAULT;
3150f1702c5SYu Xiangning 	auio.uio_limit = 0;
3160f1702c5SYu Xiangning 	auio.uio_fmode = KSOCKET_FMODE(ks);
3170f1702c5SYu Xiangning 	len = 0;
3180f1702c5SYu Xiangning 	for (i = 0; i < msg->msg_iovlen; i++) {
3190f1702c5SYu Xiangning 		ssize_t iovlen;
3200f1702c5SYu Xiangning 		iovlen = (msg->msg_iov)[i].iov_len;
3210f1702c5SYu Xiangning 		len += iovlen;
3220f1702c5SYu Xiangning 		if (len < 0 || iovlen < 0)
3230f1702c5SYu Xiangning 			return (EINVAL);
3240f1702c5SYu Xiangning 	}
3250f1702c5SYu Xiangning 	auio.uio_resid = len;
3260f1702c5SYu Xiangning 
3270f1702c5SYu Xiangning 	msg->msg_flags = flags | MSG_EOR;
3280f1702c5SYu Xiangning 
3290f1702c5SYu Xiangning 	error = socket_sendmsg(KSTOSO(ks), msg, &auio, cr);
3300f1702c5SYu Xiangning 	if (error != 0) {
3310f1702c5SYu Xiangning 		if (sent != NULL)
3320f1702c5SYu Xiangning 			*sent = 0;
3330f1702c5SYu Xiangning 		return (error);
3340f1702c5SYu Xiangning 	}
3350f1702c5SYu Xiangning 
3360f1702c5SYu Xiangning 	if (sent != NULL)
3370f1702c5SYu Xiangning 		*sent = len - auio.uio_resid;
3380f1702c5SYu Xiangning 	return (0);
3390f1702c5SYu Xiangning }
3400f1702c5SYu Xiangning 
3410f1702c5SYu Xiangning 
3420f1702c5SYu Xiangning int
ksocket_recv(ksocket_t ks,void * msg,size_t msglen,int flags,size_t * recv,struct cred * cr)3430f1702c5SYu Xiangning ksocket_recv(ksocket_t ks, void *msg, size_t msglen, int flags,
3440f1702c5SYu Xiangning     size_t *recv, struct cred *cr)
3450f1702c5SYu Xiangning {
3460f1702c5SYu Xiangning 	int error;
3470f1702c5SYu Xiangning 	struct nmsghdr msghdr;
3480f1702c5SYu Xiangning 	struct uio auio;
3490f1702c5SYu Xiangning 	struct iovec iov;
3500f1702c5SYu Xiangning 
351de8c4a14SErik Nordmark 	/* All Solaris components should pass a cred for this operation. */
352de8c4a14SErik Nordmark 	ASSERT(cr != NULL);
353de8c4a14SErik Nordmark 
3540f1702c5SYu Xiangning 	if (!KSOCKET_VALID(ks)) {
3550f1702c5SYu Xiangning 		if (recv != NULL)
3560f1702c5SYu Xiangning 			*recv = 0;
3570f1702c5SYu Xiangning 		return (ENOTSOCK);
3580f1702c5SYu Xiangning 	}
3590f1702c5SYu Xiangning 
3600f1702c5SYu Xiangning 	iov.iov_base = msg;
3610f1702c5SYu Xiangning 	iov.iov_len = msglen;
3620f1702c5SYu Xiangning 
3630f1702c5SYu Xiangning 	bzero(&auio, sizeof (struct uio));
3640f1702c5SYu Xiangning 	auio.uio_loffset = 0;
3650f1702c5SYu Xiangning 	auio.uio_iov = &iov;
3660f1702c5SYu Xiangning 	auio.uio_iovcnt = 1;
3670f1702c5SYu Xiangning 	auio.uio_resid = msglen;
3680f1702c5SYu Xiangning 	if (flags & MSG_USERSPACE)
3690f1702c5SYu Xiangning 		auio.uio_segflg = UIO_USERSPACE;
3700f1702c5SYu Xiangning 	else
3710f1702c5SYu Xiangning 		auio.uio_segflg = UIO_SYSSPACE;
3720f1702c5SYu Xiangning 	auio.uio_extflg = UIO_COPY_DEFAULT;
3730f1702c5SYu Xiangning 	auio.uio_limit = 0;
3740f1702c5SYu Xiangning 	auio.uio_fmode = KSOCKET_FMODE(ks);
3750f1702c5SYu Xiangning 
3760f1702c5SYu Xiangning 	msghdr.msg_name = NULL;
3770f1702c5SYu Xiangning 	msghdr.msg_namelen = 0;
3780f1702c5SYu Xiangning 	msghdr.msg_control = NULL;
3790f1702c5SYu Xiangning 	msghdr.msg_controllen = 0;
3800f1702c5SYu Xiangning 	msghdr.msg_flags = flags & (MSG_OOB | MSG_PEEK | MSG_WAITALL |
3810f1702c5SYu Xiangning 	    MSG_DONTWAIT | MSG_USERSPACE);
3820f1702c5SYu Xiangning 
3830f1702c5SYu Xiangning 	error = socket_recvmsg(KSTOSO(ks), &msghdr, &auio, cr);
3840f1702c5SYu Xiangning 	if (error != 0) {
3850f1702c5SYu Xiangning 		if (recv != NULL)
3860f1702c5SYu Xiangning 			*recv = 0;
3870f1702c5SYu Xiangning 		return (error);
3880f1702c5SYu Xiangning 	}
3890f1702c5SYu Xiangning 
3900f1702c5SYu Xiangning 	if (recv != NULL)
3910f1702c5SYu Xiangning 		*recv = msglen - auio.uio_resid;
3920f1702c5SYu Xiangning 	return (0);
3930f1702c5SYu Xiangning }
3940f1702c5SYu Xiangning 
3950f1702c5SYu Xiangning int
ksocket_recvfrom(ksocket_t ks,void * msg,size_t msglen,int flags,struct sockaddr * name,socklen_t * namelen,size_t * recv,struct cred * cr)3960f1702c5SYu Xiangning ksocket_recvfrom(ksocket_t ks, void *msg, size_t msglen, int flags,
3970f1702c5SYu Xiangning     struct sockaddr *name, socklen_t *namelen, size_t *recv, struct cred *cr)
3980f1702c5SYu Xiangning {
3990f1702c5SYu Xiangning 	int error;
4000f1702c5SYu Xiangning 	struct nmsghdr msghdr;
4010f1702c5SYu Xiangning 	struct uio auio;
4020f1702c5SYu Xiangning 	struct iovec iov;
4030f1702c5SYu Xiangning 
404de8c4a14SErik Nordmark 	/* All Solaris components should pass a cred for this operation. */
405de8c4a14SErik Nordmark 	ASSERT(cr != NULL);
406de8c4a14SErik Nordmark 
4070f1702c5SYu Xiangning 	if (!KSOCKET_VALID(ks)) {
4080f1702c5SYu Xiangning 		if (recv != NULL)
4090f1702c5SYu Xiangning 			*recv = 0;
4100f1702c5SYu Xiangning 		return (ENOTSOCK);
4110f1702c5SYu Xiangning 	}
4120f1702c5SYu Xiangning 
4130f1702c5SYu Xiangning 	iov.iov_base = msg;
4140f1702c5SYu Xiangning 	iov.iov_len = msglen;
4150f1702c5SYu Xiangning 
4160f1702c5SYu Xiangning 	bzero(&auio, sizeof (struct uio));
4170f1702c5SYu Xiangning 	auio.uio_loffset = 0;
4180f1702c5SYu Xiangning 	auio.uio_iov = &iov;
4190f1702c5SYu Xiangning 	auio.uio_iovcnt = 1;
4200f1702c5SYu Xiangning 	auio.uio_resid = msglen;
4210f1702c5SYu Xiangning 	if (flags & MSG_USERSPACE)
4220f1702c5SYu Xiangning 		auio.uio_segflg = UIO_USERSPACE;
4230f1702c5SYu Xiangning 	else
4240f1702c5SYu Xiangning 		auio.uio_segflg = UIO_SYSSPACE;
4250f1702c5SYu Xiangning 	auio.uio_extflg = UIO_COPY_DEFAULT;
4260f1702c5SYu Xiangning 	auio.uio_limit = 0;
4270f1702c5SYu Xiangning 	auio.uio_fmode = KSOCKET_FMODE(ks);
4280f1702c5SYu Xiangning 
4290f1702c5SYu Xiangning 	msghdr.msg_name = (char *)name;
4300f1702c5SYu Xiangning 	msghdr.msg_namelen = *namelen;
4310f1702c5SYu Xiangning 	msghdr.msg_control = NULL;
4320f1702c5SYu Xiangning 	msghdr.msg_controllen = 0;
4330f1702c5SYu Xiangning 	msghdr.msg_flags = flags & (MSG_OOB | MSG_PEEK | MSG_WAITALL |
4340f1702c5SYu Xiangning 	    MSG_DONTWAIT | MSG_USERSPACE);
4350f1702c5SYu Xiangning 
4360f1702c5SYu Xiangning 	error = socket_recvmsg(KSTOSO(ks), &msghdr, &auio, cr);
4370f1702c5SYu Xiangning 	if (error != 0) {
4380f1702c5SYu Xiangning 		if (recv != NULL)
4390f1702c5SYu Xiangning 			*recv = 0;
4400f1702c5SYu Xiangning 		return (error);
4410f1702c5SYu Xiangning 	}
4420f1702c5SYu Xiangning 	if (recv != NULL)
4430f1702c5SYu Xiangning 		*recv = msglen - auio.uio_resid;
4440f1702c5SYu Xiangning 
4450f1702c5SYu Xiangning 	bcopy(msghdr.msg_name, name, msghdr.msg_namelen);
4460f1702c5SYu Xiangning 	bcopy(&msghdr.msg_namelen, namelen, sizeof (msghdr.msg_namelen));
4470f1702c5SYu Xiangning 	return (0);
4480f1702c5SYu Xiangning }
4490f1702c5SYu Xiangning 
4500f1702c5SYu Xiangning int
ksocket_recvmsg(ksocket_t ks,struct nmsghdr * msg,int flags,size_t * recv,struct cred * cr)4510f1702c5SYu Xiangning ksocket_recvmsg(ksocket_t ks, struct nmsghdr *msg, int flags, size_t *recv,
4520f1702c5SYu Xiangning     struct cred *cr)
4530f1702c5SYu Xiangning {
4540f1702c5SYu Xiangning 	int error;
4550f1702c5SYu Xiangning 	ssize_t len;
4560f1702c5SYu Xiangning 	int i;
4570f1702c5SYu Xiangning 	struct uio auio;
4580f1702c5SYu Xiangning 
459de8c4a14SErik Nordmark 	/* All Solaris components should pass a cred for this operation. */
460de8c4a14SErik Nordmark 	ASSERT(cr != NULL);
461de8c4a14SErik Nordmark 
4620f1702c5SYu Xiangning 	if (!KSOCKET_VALID(ks)) {
4630f1702c5SYu Xiangning 		if (recv != NULL)
4640f1702c5SYu Xiangning 			*recv = 0;
4650f1702c5SYu Xiangning 		return (ENOTSOCK);
4660f1702c5SYu Xiangning 	}
4670f1702c5SYu Xiangning 
4680f1702c5SYu Xiangning 	bzero(&auio, sizeof (struct uio));
4690f1702c5SYu Xiangning 	auio.uio_loffset = 0;
4700f1702c5SYu Xiangning 	auio.uio_iov = msg->msg_iov;
4710f1702c5SYu Xiangning 	auio.uio_iovcnt = msg->msg_iovlen;
4720f1702c5SYu Xiangning 	if (msg->msg_flags & MSG_USERSPACE)
4730f1702c5SYu Xiangning 		auio.uio_segflg = UIO_USERSPACE;
4740f1702c5SYu Xiangning 	else
4750f1702c5SYu Xiangning 		auio.uio_segflg = UIO_SYSSPACE;
4760f1702c5SYu Xiangning 	auio.uio_extflg = UIO_COPY_DEFAULT;
4770f1702c5SYu Xiangning 	auio.uio_limit = 0;
4780f1702c5SYu Xiangning 	auio.uio_fmode = KSOCKET_FMODE(ks);
4790f1702c5SYu Xiangning 	len = 0;
4800f1702c5SYu Xiangning 
4810f1702c5SYu Xiangning 	for (i = 0; i < msg->msg_iovlen; i++) {
4820f1702c5SYu Xiangning 		ssize_t iovlen;
4830f1702c5SYu Xiangning 		iovlen = (msg->msg_iov)[i].iov_len;
4840f1702c5SYu Xiangning 		len += iovlen;
4850f1702c5SYu Xiangning 		if (len < 0 || iovlen < 0)
4860f1702c5SYu Xiangning 			return (EINVAL);
4870f1702c5SYu Xiangning 	}
4880f1702c5SYu Xiangning 	auio.uio_resid = len;
4890f1702c5SYu Xiangning 
4900f1702c5SYu Xiangning 	msg->msg_flags = flags & (MSG_OOB | MSG_PEEK | MSG_WAITALL |
4910f1702c5SYu Xiangning 	    MSG_DONTWAIT | MSG_USERSPACE);
4920f1702c5SYu Xiangning 
4930f1702c5SYu Xiangning 	error = socket_recvmsg(KSTOSO(ks), msg, &auio, cr);
4940f1702c5SYu Xiangning 	if (error != 0) {
4950f1702c5SYu Xiangning 		if (recv != NULL)
4960f1702c5SYu Xiangning 			*recv = 0;
4970f1702c5SYu Xiangning 		return (error);
4980f1702c5SYu Xiangning 	}
4990f1702c5SYu Xiangning 	if (recv != NULL)
5000f1702c5SYu Xiangning 		*recv = len - auio.uio_resid;
5010f1702c5SYu Xiangning 	return (0);
5020f1702c5SYu Xiangning 
5030f1702c5SYu Xiangning }
5040f1702c5SYu Xiangning 
5050f1702c5SYu Xiangning int
ksocket_shutdown(ksocket_t ks,int how,struct cred * cr)5060f1702c5SYu Xiangning ksocket_shutdown(ksocket_t ks, int how, struct cred *cr)
5070f1702c5SYu Xiangning {
5080f1702c5SYu Xiangning 	struct sonode *so;
5090f1702c5SYu Xiangning 
510de8c4a14SErik Nordmark 	/* All Solaris components should pass a cred for this operation. */
511de8c4a14SErik Nordmark 	ASSERT(cr != NULL);
512de8c4a14SErik Nordmark 
5130f1702c5SYu Xiangning 	if (!KSOCKET_VALID(ks))
5140f1702c5SYu Xiangning 		return (ENOTSOCK);
5150f1702c5SYu Xiangning 
5160f1702c5SYu Xiangning 	so = KSTOSO(ks);
5170f1702c5SYu Xiangning 
5180f1702c5SYu Xiangning 	return (socket_shutdown(so, how, cr));
5190f1702c5SYu Xiangning }
5200f1702c5SYu Xiangning 
5210f1702c5SYu Xiangning int
ksocket_close(ksocket_t ks,struct cred * cr)5220f1702c5SYu Xiangning ksocket_close(ksocket_t ks, struct cred *cr)
5230f1702c5SYu Xiangning {
5240f1702c5SYu Xiangning 	struct sonode *so;
5250f1702c5SYu Xiangning 	so = KSTOSO(ks);
5260f1702c5SYu Xiangning 
527de8c4a14SErik Nordmark 	/* All Solaris components should pass a cred for this operation. */
528de8c4a14SErik Nordmark 	ASSERT(cr != NULL);
529de8c4a14SErik Nordmark 
5300f1702c5SYu Xiangning 	mutex_enter(&so->so_lock);
5310f1702c5SYu Xiangning 
5320f1702c5SYu Xiangning 	if (!KSOCKET_VALID(ks)) {
5330f1702c5SYu Xiangning 		mutex_exit(&so->so_lock);
5340f1702c5SYu Xiangning 		return (ENOTSOCK);
5350f1702c5SYu Xiangning 	}
5360f1702c5SYu Xiangning 
5370f1702c5SYu Xiangning 	so->so_state |= SS_CLOSING;
5380f1702c5SYu Xiangning 
5390f1702c5SYu Xiangning 	if (so->so_count > 1) {
5400f1702c5SYu Xiangning 		mutex_enter(&so->so_acceptq_lock);
5410f1702c5SYu Xiangning 		cv_broadcast(&so->so_acceptq_cv);
5420f1702c5SYu Xiangning 		mutex_exit(&so->so_acceptq_lock);
5430f1702c5SYu Xiangning 		cv_broadcast(&so->so_rcv_cv);
5440f1702c5SYu Xiangning 		cv_broadcast(&so->so_state_cv);
5456a571a2dSAnders Persson 		cv_broadcast(&so->so_single_cv);
5466a571a2dSAnders Persson 		cv_broadcast(&so->so_read_cv);
5470f1702c5SYu Xiangning 		cv_broadcast(&so->so_snd_cv);
5480f1702c5SYu Xiangning 		cv_broadcast(&so->so_copy_cv);
5490f1702c5SYu Xiangning 	}
5500f1702c5SYu Xiangning 	while (so->so_count > 1)
5510f1702c5SYu Xiangning 		cv_wait(&so->so_closing_cv, &so->so_lock);
5520f1702c5SYu Xiangning 
5530f1702c5SYu Xiangning 	mutex_exit(&so->so_lock);
5540f1702c5SYu Xiangning 	/* Remove callbacks, if any */
5550f1702c5SYu Xiangning 	(void) ksocket_setcallbacks(ks, NULL, NULL, cr);
5560f1702c5SYu Xiangning 
5570f1702c5SYu Xiangning 	(void) socket_close(so, 0, cr);
5580f1702c5SYu Xiangning 	socket_destroy(so);
5590f1702c5SYu Xiangning 
5600f1702c5SYu Xiangning 	return (0);
5610f1702c5SYu Xiangning }
5620f1702c5SYu Xiangning 
5630f1702c5SYu Xiangning int
ksocket_getsockname(ksocket_t ks,struct sockaddr * addr,socklen_t * addrlen,struct cred * cr)5640f1702c5SYu Xiangning ksocket_getsockname(ksocket_t ks, struct sockaddr *addr, socklen_t *addrlen,
5650f1702c5SYu Xiangning     struct cred *cr)
5660f1702c5SYu Xiangning {
5670f1702c5SYu Xiangning 	struct sonode *so;
5680f1702c5SYu Xiangning 
569de8c4a14SErik Nordmark 	/* All Solaris components should pass a cred for this operation. */
570de8c4a14SErik Nordmark 	ASSERT(cr != NULL);
571de8c4a14SErik Nordmark 
5720f1702c5SYu Xiangning 	if (!KSOCKET_VALID(ks))
5730f1702c5SYu Xiangning 		return (ENOTSOCK);
5740f1702c5SYu Xiangning 
5750f1702c5SYu Xiangning 	so = KSTOSO(ks);
5760f1702c5SYu Xiangning 
5770f1702c5SYu Xiangning 	if (addrlen == NULL || (addr == NULL && *addrlen != 0))
5780f1702c5SYu Xiangning 		return (EFAULT);
5790f1702c5SYu Xiangning 
5800f1702c5SYu Xiangning 	return (socket_getsockname(so, addr, addrlen, cr));
5810f1702c5SYu Xiangning }
5820f1702c5SYu Xiangning 
5830f1702c5SYu Xiangning int
ksocket_getpeername(ksocket_t ks,struct sockaddr * addr,socklen_t * addrlen,struct cred * cr)5840f1702c5SYu Xiangning ksocket_getpeername(ksocket_t ks, struct sockaddr *addr, socklen_t *addrlen,
5850f1702c5SYu Xiangning     struct cred *cr)
5860f1702c5SYu Xiangning {
5870f1702c5SYu Xiangning 	struct sonode *so;
5880f1702c5SYu Xiangning 
589de8c4a14SErik Nordmark 	/* All Solaris components should pass a cred for this operation. */
590de8c4a14SErik Nordmark 	ASSERT(cr != NULL);
591de8c4a14SErik Nordmark 
5920f1702c5SYu Xiangning 	if (!KSOCKET_VALID(ks))
5930f1702c5SYu Xiangning 		return (ENOTSOCK);
5940f1702c5SYu Xiangning 
5950f1702c5SYu Xiangning 	so = KSTOSO(ks);
5960f1702c5SYu Xiangning 
5970f1702c5SYu Xiangning 	if (addrlen == NULL || (addr == NULL && *addrlen != 0))
5980f1702c5SYu Xiangning 		return (EFAULT);
5990f1702c5SYu Xiangning 
6000f1702c5SYu Xiangning 	return (socket_getpeername(so, addr, addrlen, B_FALSE, cr));
6010f1702c5SYu Xiangning }
6020f1702c5SYu Xiangning 
6030f1702c5SYu Xiangning int
ksocket_getsockopt(ksocket_t ks,int level,int optname,void * optval,int * optlen,struct cred * cr)6040f1702c5SYu Xiangning ksocket_getsockopt(ksocket_t ks, int level, int optname, void *optval,
6050f1702c5SYu Xiangning     int *optlen, struct cred *cr)
6060f1702c5SYu Xiangning {
6070f1702c5SYu Xiangning 	struct sonode *so;
6080f1702c5SYu Xiangning 
609de8c4a14SErik Nordmark 	/* All Solaris components should pass a cred for this operation. */
610de8c4a14SErik Nordmark 	ASSERT(cr != NULL);
611de8c4a14SErik Nordmark 
6120f1702c5SYu Xiangning 	if (!KSOCKET_VALID(ks))
6130f1702c5SYu Xiangning 		return (ENOTSOCK);
6140f1702c5SYu Xiangning 
6150f1702c5SYu Xiangning 	so = KSTOSO(ks);
6160f1702c5SYu Xiangning 
6170f1702c5SYu Xiangning 	if (optlen == NULL)
6180f1702c5SYu Xiangning 		return (EFAULT);
6190f1702c5SYu Xiangning 	if (*optlen > SO_MAXARGSIZE)
6200f1702c5SYu Xiangning 		return (EINVAL);
6210f1702c5SYu Xiangning 
6220f1702c5SYu Xiangning 	return (socket_getsockopt(so, level, optname, optval,
6230f1702c5SYu Xiangning 	    (socklen_t *)optlen, 0, cr));
6240f1702c5SYu Xiangning }
6250f1702c5SYu Xiangning 
6260f1702c5SYu Xiangning int
ksocket_setsockopt(ksocket_t ks,int level,int optname,const void * optval,int optlen,struct cred * cr)6270f1702c5SYu Xiangning ksocket_setsockopt(ksocket_t ks, int level, int optname, const void *optval,
6280f1702c5SYu Xiangning     int optlen, struct cred *cr)
6290f1702c5SYu Xiangning {
6300f1702c5SYu Xiangning 	struct sonode *so;
6310f1702c5SYu Xiangning 
632de8c4a14SErik Nordmark 	/* All Solaris components should pass a cred for this operation. */
633de8c4a14SErik Nordmark 	ASSERT(cr != NULL);
634de8c4a14SErik Nordmark 
6350f1702c5SYu Xiangning 	if (!KSOCKET_VALID(ks))
6360f1702c5SYu Xiangning 		return (ENOTSOCK);
6370f1702c5SYu Xiangning 
6380f1702c5SYu Xiangning 	so = KSTOSO(ks);
6390f1702c5SYu Xiangning 
6400f1702c5SYu Xiangning 	if (optval == NULL)
6410f1702c5SYu Xiangning 		optlen = 0;
6420f1702c5SYu Xiangning 
6430f1702c5SYu Xiangning 	return (socket_setsockopt(so, level, optname, optval,
6440f1702c5SYu Xiangning 	    (t_uscalar_t)optlen, cr));
6450f1702c5SYu Xiangning }
6460f1702c5SYu Xiangning 
6470f1702c5SYu Xiangning /* ARGSUSED */
6480f1702c5SYu Xiangning int
ksocket_setcallbacks(ksocket_t ks,ksocket_callbacks_t * cb,void * arg,struct cred * cr)6490f1702c5SYu Xiangning ksocket_setcallbacks(ksocket_t ks, ksocket_callbacks_t *cb, void *arg,
6500f1702c5SYu Xiangning     struct cred *cr)
6510f1702c5SYu Xiangning {
6520f1702c5SYu Xiangning 	struct sonode *so;
6530f1702c5SYu Xiangning 
654de8c4a14SErik Nordmark 	/* All Solaris components should pass a cred for this operation. */
655de8c4a14SErik Nordmark 	ASSERT(cr != NULL);
656de8c4a14SErik Nordmark 
6570f1702c5SYu Xiangning 	if (!KSOCKET_VALID(ks))
6580f1702c5SYu Xiangning 		return (ENOTSOCK);
6590f1702c5SYu Xiangning 
6600f1702c5SYu Xiangning 	so = KSTOSO(ks);
6610f1702c5SYu Xiangning 
6620f1702c5SYu Xiangning 	if (cb == NULL && arg != NULL)
6630f1702c5SYu Xiangning 		return (EFAULT);
6640f1702c5SYu Xiangning 	if (cb == NULL) {
6650f1702c5SYu Xiangning 		mutex_enter(&so->so_lock);
6660f1702c5SYu Xiangning 		bzero(&(so->so_ksock_callbacks), sizeof (ksocket_callbacks_t));
6670f1702c5SYu Xiangning 		so->so_ksock_cb_arg = NULL;
6680f1702c5SYu Xiangning 		mutex_exit(&so->so_lock);
6690f1702c5SYu Xiangning 	} else {
6700f1702c5SYu Xiangning 		mutex_enter(&so->so_lock);
6710f1702c5SYu Xiangning 		SETCALLBACK(so, cb, connected, KSOCKET_CB_CONNECTED)
6720f1702c5SYu Xiangning 		SETCALLBACK(so, cb, connectfailed, KSOCKET_CB_CONNECTFAILED)
6730f1702c5SYu Xiangning 		SETCALLBACK(so, cb, disconnected, KSOCKET_CB_DISCONNECTED)
6740f1702c5SYu Xiangning 		SETCALLBACK(so, cb, newdata, KSOCKET_CB_NEWDATA)
6750f1702c5SYu Xiangning 		SETCALLBACK(so, cb, newconn, KSOCKET_CB_NEWCONN)
6760f1702c5SYu Xiangning 		SETCALLBACK(so, cb, cansend, KSOCKET_CB_CANSEND)
6770f1702c5SYu Xiangning 		SETCALLBACK(so, cb, oobdata, KSOCKET_CB_OOBDATA)
6780f1702c5SYu Xiangning 		SETCALLBACK(so, cb, cantsendmore, KSOCKET_CB_CANTSENDMORE)
6790f1702c5SYu Xiangning 		SETCALLBACK(so, cb, cantrecvmore, KSOCKET_CB_CANTRECVMORE)
6800f1702c5SYu Xiangning 		so->so_ksock_cb_arg = arg;
6810f1702c5SYu Xiangning 		mutex_exit(&so->so_lock);
6820f1702c5SYu Xiangning 	}
6830f1702c5SYu Xiangning 	return (0);
6840f1702c5SYu Xiangning }
6850f1702c5SYu Xiangning 
6860f1702c5SYu Xiangning int
ksocket_ioctl(ksocket_t ks,int cmd,intptr_t arg,int * rvalp,struct cred * cr)6870f1702c5SYu Xiangning ksocket_ioctl(ksocket_t ks, int cmd, intptr_t arg, int *rvalp, struct cred *cr)
6880f1702c5SYu Xiangning {
6890f1702c5SYu Xiangning 	struct sonode *so;
6900f1702c5SYu Xiangning 	int rval;
6910f1702c5SYu Xiangning 
692de8c4a14SErik Nordmark 	/* All Solaris components should pass a cred for this operation. */
693de8c4a14SErik Nordmark 	ASSERT(cr != NULL);
694de8c4a14SErik Nordmark 
6950f1702c5SYu Xiangning 	if (!KSOCKET_VALID(ks))
6960f1702c5SYu Xiangning 		return (ENOTSOCK);
6970f1702c5SYu Xiangning 
6980f1702c5SYu Xiangning 	so = KSTOSO(ks);
6990f1702c5SYu Xiangning 
7000f1702c5SYu Xiangning 	switch (cmd) {
7010f1702c5SYu Xiangning 	default:
7020f1702c5SYu Xiangning 		/* STREAM iotcls are not supported */
7030f1702c5SYu Xiangning 		if ((cmd & 0xffffff00U) == STR) {
7040f1702c5SYu Xiangning 			rval = EOPNOTSUPP;
7050f1702c5SYu Xiangning 		} else {
7060f1702c5SYu Xiangning 			rval = socket_ioctl(so, cmd, arg,
7070f1702c5SYu Xiangning 			    KSOCKET_FMODE(ks) | FKIOCTL, cr, rvalp);
7080f1702c5SYu Xiangning 		}
7090f1702c5SYu Xiangning 		break;
7100f1702c5SYu Xiangning 	case FIOASYNC:
7110f1702c5SYu Xiangning 	case SIOCSPGRP:
7120f1702c5SYu Xiangning 	case FIOSETOWN:
7130f1702c5SYu Xiangning 	case SIOCGPGRP:
7140f1702c5SYu Xiangning 	case FIOGETOWN:
7150f1702c5SYu Xiangning 		rval = EOPNOTSUPP;
7160f1702c5SYu Xiangning 		break;
7170f1702c5SYu Xiangning 	}
7180f1702c5SYu Xiangning 
7190f1702c5SYu Xiangning 	return (rval);
7200f1702c5SYu Xiangning }
7210f1702c5SYu Xiangning 
722*3076c25aSStepan Zastupov /*
723*3076c25aSStepan Zastupov  * Wait for an input event, similar to t_kspoll().
724*3076c25aSStepan Zastupov  * Ideas and code borrowed from ../devpoll.c
725*3076c25aSStepan Zastupov  * Basically, setup just enough poll data structures so
726*3076c25aSStepan Zastupov  * we can block on a CV until timeout or pollwakeup().
727*3076c25aSStepan Zastupov  */
728*3076c25aSStepan Zastupov int
ksocket_spoll(ksocket_t ks,int timo,short events,short * revents,struct cred * cr)729*3076c25aSStepan Zastupov ksocket_spoll(ksocket_t ks, int timo, short events, short *revents,
730*3076c25aSStepan Zastupov     struct cred *cr)
731*3076c25aSStepan Zastupov {
732*3076c25aSStepan Zastupov 	struct		sonode *so;
733*3076c25aSStepan Zastupov 	pollhead_t	*php, *php2;
734*3076c25aSStepan Zastupov 	polldat_t	*pdp;
735*3076c25aSStepan Zastupov 	pollcache_t	*pcp;
736*3076c25aSStepan Zastupov 	int		error;
737*3076c25aSStepan Zastupov 	clock_t		expires = 0;
738*3076c25aSStepan Zastupov 	clock_t		rval;
739*3076c25aSStepan Zastupov 
740*3076c25aSStepan Zastupov 	/* All Solaris components should pass a cred for this operation. */
741*3076c25aSStepan Zastupov 	ASSERT(cr != NULL);
742*3076c25aSStepan Zastupov 	ASSERT(curthread->t_pollcache == NULL);
743*3076c25aSStepan Zastupov 
744*3076c25aSStepan Zastupov 	if (revents == NULL)
745*3076c25aSStepan Zastupov 		return (EINVAL);
746*3076c25aSStepan Zastupov 	if (!KSOCKET_VALID(ks))
747*3076c25aSStepan Zastupov 		return (ENOTSOCK);
748*3076c25aSStepan Zastupov 	so = KSTOSO(ks);
749*3076c25aSStepan Zastupov 
750*3076c25aSStepan Zastupov 	/*
751*3076c25aSStepan Zastupov 	 * Check if there are any events already pending.
752*3076c25aSStepan Zastupov 	 * If we're not willing to block, (timo == 0) then
753*3076c25aSStepan Zastupov 	 * pass "anyyet">0 to socket_poll so it can skip
754*3076c25aSStepan Zastupov 	 * some work.  Othewise pass "anyyet"=0 and if
755*3076c25aSStepan Zastupov 	 * there are no events pending, it will fill in
756*3076c25aSStepan Zastupov 	 * the pollhead pointer we need for pollwakeup().
757*3076c25aSStepan Zastupov 	 *
758*3076c25aSStepan Zastupov 	 * XXX - pollrelock() logic needs to know which
759*3076c25aSStepan Zastupov 	 * which pollcache lock to grab. It'd be a
760*3076c25aSStepan Zastupov 	 * cleaner solution if we could pass pcp as
761*3076c25aSStepan Zastupov 	 * an arguement in VOP_POLL interface instead
762*3076c25aSStepan Zastupov 	 * of implicitly passing it using thread_t
763*3076c25aSStepan Zastupov 	 * struct. On the other hand, changing VOP_POLL
764*3076c25aSStepan Zastupov 	 * interface will require all driver/file system
765*3076c25aSStepan Zastupov 	 * poll routine to change. May want to revisit
766*3076c25aSStepan Zastupov 	 * the tradeoff later.
767*3076c25aSStepan Zastupov 	 */
768*3076c25aSStepan Zastupov 	php = NULL;
769*3076c25aSStepan Zastupov 	*revents = 0;
770*3076c25aSStepan Zastupov 	pcp = pcache_alloc();
771*3076c25aSStepan Zastupov 	pcache_create(pcp, 1);
772*3076c25aSStepan Zastupov 
773*3076c25aSStepan Zastupov 	mutex_enter(&pcp->pc_lock);
774*3076c25aSStepan Zastupov 	curthread->t_pollcache = pcp;
775*3076c25aSStepan Zastupov 	error = socket_poll(so, (short)events, (timo == 0),
776*3076c25aSStepan Zastupov 	    revents, &php);
777*3076c25aSStepan Zastupov 	curthread->t_pollcache = NULL;
778*3076c25aSStepan Zastupov 	mutex_exit(&pcp->pc_lock);
779*3076c25aSStepan Zastupov 
780*3076c25aSStepan Zastupov 	if (error != 0 || *revents != 0 || timo == 0)
781*3076c25aSStepan Zastupov 		goto out;
782*3076c25aSStepan Zastupov 
783*3076c25aSStepan Zastupov 	/*
784*3076c25aSStepan Zastupov 	 * Need to block.  Did not get *revents, so the
785*3076c25aSStepan Zastupov 	 * php should be non-NULL, but let's verify.
786*3076c25aSStepan Zastupov 	 * Also compute when our sleep expires.
787*3076c25aSStepan Zastupov 	 */
788*3076c25aSStepan Zastupov 	if (php == NULL) {
789*3076c25aSStepan Zastupov 		error = EIO;
790*3076c25aSStepan Zastupov 		goto out;
791*3076c25aSStepan Zastupov 	}
792*3076c25aSStepan Zastupov 	if (timo > 0)
793*3076c25aSStepan Zastupov 		expires = ddi_get_lbolt() +
794*3076c25aSStepan Zastupov 		    MSEC_TO_TICK_ROUNDUP(timo);
795*3076c25aSStepan Zastupov 
796*3076c25aSStepan Zastupov 	/*
797*3076c25aSStepan Zastupov 	 * Setup: pollhead -> polldat -> pollcache
798*3076c25aSStepan Zastupov 	 * needed for pollwakeup()
799*3076c25aSStepan Zastupov 	 * pdp should be freed by pcache_destroy
800*3076c25aSStepan Zastupov 	 */
801*3076c25aSStepan Zastupov 	pdp = kmem_zalloc(sizeof (*pdp), KM_SLEEP);
802*3076c25aSStepan Zastupov 	pdp->pd_fd = 0;
803*3076c25aSStepan Zastupov 	pdp->pd_events = events;
804*3076c25aSStepan Zastupov 	pdp->pd_pcache = pcp;
805*3076c25aSStepan Zastupov 	pcache_insert_fd(pcp, pdp, 1);
806*3076c25aSStepan Zastupov 	pollhead_insert(php, pdp);
807*3076c25aSStepan Zastupov 	pdp->pd_php = php;
808*3076c25aSStepan Zastupov 
809*3076c25aSStepan Zastupov 	mutex_enter(&pcp->pc_lock);
810*3076c25aSStepan Zastupov 	while (!(so->so_state & SS_CLOSING)) {
811*3076c25aSStepan Zastupov 		pcp->pc_flag = 0;
812*3076c25aSStepan Zastupov 
813*3076c25aSStepan Zastupov 		/* Ditto pcp comment above. */
814*3076c25aSStepan Zastupov 		curthread->t_pollcache = pcp;
815*3076c25aSStepan Zastupov 		error = socket_poll(so, (short)events, 0,
816*3076c25aSStepan Zastupov 		    revents, &php2);
817*3076c25aSStepan Zastupov 		curthread->t_pollcache = NULL;
818*3076c25aSStepan Zastupov 		ASSERT(php2 == php);
819*3076c25aSStepan Zastupov 
820*3076c25aSStepan Zastupov 		if (error != 0 || *revents != 0)
821*3076c25aSStepan Zastupov 			break;
822*3076c25aSStepan Zastupov 
823*3076c25aSStepan Zastupov 		if (pcp->pc_flag & T_POLLWAKE)
824*3076c25aSStepan Zastupov 			continue;
825*3076c25aSStepan Zastupov 
826*3076c25aSStepan Zastupov 		if (timo == -1) {
827*3076c25aSStepan Zastupov 			rval = cv_wait_sig(&pcp->pc_cv, &pcp->pc_lock);
828*3076c25aSStepan Zastupov 		} else {
829*3076c25aSStepan Zastupov 			rval = cv_timedwait_sig(&pcp->pc_cv, &pcp->pc_lock,
830*3076c25aSStepan Zastupov 			    expires);
831*3076c25aSStepan Zastupov 		}
832*3076c25aSStepan Zastupov 		if (rval <= 0) {
833*3076c25aSStepan Zastupov 			if (rval == 0)
834*3076c25aSStepan Zastupov 				error = EINTR;
835*3076c25aSStepan Zastupov 			break;
836*3076c25aSStepan Zastupov 		}
837*3076c25aSStepan Zastupov 	}
838*3076c25aSStepan Zastupov 	mutex_exit(&pcp->pc_lock);
839*3076c25aSStepan Zastupov 
840*3076c25aSStepan Zastupov 	if (pdp->pd_php != NULL) {
841*3076c25aSStepan Zastupov 		pollhead_delete(pdp->pd_php, pdp);
842*3076c25aSStepan Zastupov 		pdp->pd_php = NULL;
843*3076c25aSStepan Zastupov 		pdp->pd_fd = NULL;
844*3076c25aSStepan Zastupov 	}
845*3076c25aSStepan Zastupov 
846*3076c25aSStepan Zastupov 	/*
847*3076c25aSStepan Zastupov 	 * pollwakeup() may still interact with this pollcache. Wait until
848*3076c25aSStepan Zastupov 	 * it is done.
849*3076c25aSStepan Zastupov 	 */
850*3076c25aSStepan Zastupov 	mutex_enter(&pcp->pc_no_exit);
851*3076c25aSStepan Zastupov 	ASSERT(pcp->pc_busy >= 0);
852*3076c25aSStepan Zastupov 	while (pcp->pc_busy > 0)
853*3076c25aSStepan Zastupov 		cv_wait(&pcp->pc_busy_cv, &pcp->pc_no_exit);
854*3076c25aSStepan Zastupov 	mutex_exit(&pcp->pc_no_exit);
855*3076c25aSStepan Zastupov out:
856*3076c25aSStepan Zastupov 	pcache_destroy(pcp);
857*3076c25aSStepan Zastupov 	return (error);
858*3076c25aSStepan Zastupov }
859*3076c25aSStepan Zastupov 
8600f1702c5SYu Xiangning int
ksocket_sendmblk(ksocket_t ks,struct nmsghdr * msg,int flags,mblk_t ** mpp,cred_t * cr)8610f1702c5SYu Xiangning ksocket_sendmblk(ksocket_t ks, struct nmsghdr *msg, int flags,
8620f1702c5SYu Xiangning     mblk_t **mpp, cred_t *cr)
8630f1702c5SYu Xiangning {
8640f1702c5SYu Xiangning 	struct		sonode *so;
8650f1702c5SYu Xiangning 	int		i_val;
8660f1702c5SYu Xiangning 	socklen_t	val_len;
8670f1702c5SYu Xiangning 	mblk_t		*mp = *mpp;
8680f1702c5SYu Xiangning 	int		error;
8690f1702c5SYu Xiangning 
870de8c4a14SErik Nordmark 	/* All Solaris components should pass a cred for this operation. */
871de8c4a14SErik Nordmark 	ASSERT(cr != NULL);
872de8c4a14SErik Nordmark 
8730f1702c5SYu Xiangning 	if (!KSOCKET_VALID(ks))
8740f1702c5SYu Xiangning 		return (ENOTSOCK);
8750f1702c5SYu Xiangning 
8760f1702c5SYu Xiangning 	so = KSTOSO(ks);
8770f1702c5SYu Xiangning 
8780f1702c5SYu Xiangning 	if (flags & MSG_MBLK_QUICKRELE) {
8790f1702c5SYu Xiangning 		error = socket_getsockopt(so, SOL_SOCKET, SO_SND_COPYAVOID,
880de8c4a14SErik Nordmark 		    &i_val, &val_len, 0, cr);
8810f1702c5SYu Xiangning 		if (error != 0)
8820f1702c5SYu Xiangning 			return (error);
8830f1702c5SYu Xiangning 
8840f1702c5SYu Xiangning 		/* Zero copy is not enable */
8850f1702c5SYu Xiangning 		if (i_val == 0)
8860f1702c5SYu Xiangning 			return (ECANCELED);
8870f1702c5SYu Xiangning 
8880f1702c5SYu Xiangning 		for (; mp != NULL; mp = mp->b_cont)
8890f1702c5SYu Xiangning 			mp->b_datap->db_struioflag |= STRUIO_ZC;
8900f1702c5SYu Xiangning 	}
8910f1702c5SYu Xiangning 
8920f1702c5SYu Xiangning 	error = socket_sendmblk(so, msg, flags, cr, mpp);
8930f1702c5SYu Xiangning 
8940f1702c5SYu Xiangning 	return (error);
8950f1702c5SYu Xiangning }
8960f1702c5SYu Xiangning 
8970f1702c5SYu Xiangning 
8980f1702c5SYu Xiangning void
ksocket_hold(ksocket_t ks)8990f1702c5SYu Xiangning ksocket_hold(ksocket_t ks)
9000f1702c5SYu Xiangning {
9010f1702c5SYu Xiangning 	struct sonode *so;
9020f1702c5SYu Xiangning 	so = KSTOSO(ks);
9030f1702c5SYu Xiangning 
9040f1702c5SYu Xiangning 	if (!mutex_owned(&so->so_lock)) {
9050f1702c5SYu Xiangning 		mutex_enter(&so->so_lock);
9060f1702c5SYu Xiangning 		so->so_count++;
9070f1702c5SYu Xiangning 		mutex_exit(&so->so_lock);
9080f1702c5SYu Xiangning 	} else
9090f1702c5SYu Xiangning 		so->so_count++;
9100f1702c5SYu Xiangning }
9110f1702c5SYu Xiangning 
9120f1702c5SYu Xiangning void
ksocket_rele(ksocket_t ks)9130f1702c5SYu Xiangning ksocket_rele(ksocket_t ks)
9140f1702c5SYu Xiangning {
9150f1702c5SYu Xiangning 	struct sonode *so;
9160f1702c5SYu Xiangning 
9170f1702c5SYu Xiangning 	so = KSTOSO(ks);
9180f1702c5SYu Xiangning 	/*
9190f1702c5SYu Xiangning 	 * When so_count equals 1 means no thread working on this ksocket
9200f1702c5SYu Xiangning 	 */
9210f1702c5SYu Xiangning 	if (so->so_count < 2)
9220f1702c5SYu Xiangning 		cmn_err(CE_PANIC, "ksocket_rele: sonode ref count 0 or 1");
9230f1702c5SYu Xiangning 
9240f1702c5SYu Xiangning 	if (!mutex_owned(&so->so_lock)) {
9250f1702c5SYu Xiangning 		mutex_enter(&so->so_lock);
9260f1702c5SYu Xiangning 		if (--so->so_count == 1)
9270f1702c5SYu Xiangning 			cv_signal(&so->so_closing_cv);
9280f1702c5SYu Xiangning 		mutex_exit(&so->so_lock);
9290f1702c5SYu Xiangning 	} else {
9300f1702c5SYu Xiangning 		if (--so->so_count == 1)
9310f1702c5SYu Xiangning 			cv_signal(&so->so_closing_cv);
9320f1702c5SYu Xiangning 	}
9330f1702c5SYu Xiangning }
934