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 /*
233076c25aSStepan Zastupov * Copyright 2011 Nexenta Systems, Inc. All rights reserved.
243e95bd4aSAnders Persson * Copyright (c) 2008, 2010, Oracle and/or its affiliates. All rights reserved.
25907c2824SRobert Mustacchi * Copyright 2015, Joyent, Inc.
2615f90b02SGarrett D'Amore * Copyright 2022 Garrett D'Amore
270f1702c5SYu Xiangning */
280f1702c5SYu Xiangning
290f1702c5SYu Xiangning #include <sys/file.h>
300f1702c5SYu Xiangning #include <sys/stropts.h>
310f1702c5SYu Xiangning #include <sys/socket.h>
320f1702c5SYu Xiangning #include <sys/socketvar.h>
330f1702c5SYu Xiangning #include <sys/sysmacros.h>
340f1702c5SYu Xiangning #include <sys/filio.h> /* FIO* ioctls */
350f1702c5SYu Xiangning #include <sys/sockio.h> /* SIOC* ioctls */
363076c25aSStepan Zastupov #include <sys/poll_impl.h>
370f1702c5SYu Xiangning #include <sys/cmn_err.h>
380f1702c5SYu Xiangning #include <sys/ksocket.h>
390f1702c5SYu Xiangning #include <io/ksocket/ksocket_impl.h>
400f1702c5SYu Xiangning #include <fs/sockfs/sockcommon.h>
410f1702c5SYu Xiangning
420f1702c5SYu Xiangning #define SOCKETMOD_TCP "tcp"
430f1702c5SYu Xiangning #define SOCKETMOD_UDP "udp"
440f1702c5SYu Xiangning /*
450f1702c5SYu Xiangning * Kernel Sockets
460f1702c5SYu Xiangning *
470f1702c5SYu Xiangning * Mostly a wrapper around the private socket_* functions.
480f1702c5SYu Xiangning */
490f1702c5SYu Xiangning int
ksocket_socket(ksocket_t * ksp,int domain,int type,int protocol,int flags,struct cred * cr)500f1702c5SYu Xiangning ksocket_socket(ksocket_t *ksp, int domain, int type, int protocol, int flags,
510f1702c5SYu Xiangning struct cred *cr)
520f1702c5SYu Xiangning {
530f1702c5SYu Xiangning static const int version = SOV_DEFAULT;
540f1702c5SYu Xiangning int error = 0;
550f1702c5SYu Xiangning struct sonode *so;
560f1702c5SYu Xiangning *ksp = NULL;
570f1702c5SYu Xiangning
58de8c4a14SErik Nordmark /* All Solaris components should pass a cred for this operation. */
59de8c4a14SErik Nordmark ASSERT(cr != NULL);
60de8c4a14SErik Nordmark
610f1702c5SYu Xiangning ASSERT(flags == KSOCKET_SLEEP || flags == KSOCKET_NOSLEEP);
620f1702c5SYu Xiangning so = socket_create(domain, type, protocol, NULL, NULL, version, flags,
630f1702c5SYu Xiangning cr, &error);
640f1702c5SYu Xiangning if (so == NULL) {
650f1702c5SYu Xiangning if (error == EAFNOSUPPORT) {
660f1702c5SYu Xiangning char *mod = NULL;
670f1702c5SYu Xiangning
680f1702c5SYu Xiangning /*
69d0b12b66SToomas Soome * Could be that root file system is not loaded or
700f1702c5SYu Xiangning * soconfig has not run yet.
710f1702c5SYu Xiangning */
720f1702c5SYu Xiangning if (type == SOCK_STREAM && (domain == AF_INET ||
730f1702c5SYu Xiangning domain == AF_INET6) && (protocol == 0 ||
740f1702c5SYu Xiangning protocol == IPPROTO_TCP)) {
750f1702c5SYu Xiangning mod = SOCKETMOD_TCP;
760f1702c5SYu Xiangning } else if (type == SOCK_DGRAM && (domain == AF_INET ||
770f1702c5SYu Xiangning domain == AF_INET6) && (protocol == 0 ||
780f1702c5SYu Xiangning protocol == IPPROTO_UDP)) {
790f1702c5SYu Xiangning mod = SOCKETMOD_UDP;
800f1702c5SYu Xiangning } else {
810f1702c5SYu Xiangning return (EAFNOSUPPORT);
820f1702c5SYu Xiangning }
830f1702c5SYu Xiangning
840f1702c5SYu Xiangning so = socket_create(domain, type, protocol, NULL,
850f1702c5SYu Xiangning mod, version, flags, cr, &error);
860f1702c5SYu Xiangning if (so == NULL)
870f1702c5SYu Xiangning return (error);
880f1702c5SYu Xiangning } else {
890f1702c5SYu Xiangning return (error);
900f1702c5SYu Xiangning }
910f1702c5SYu Xiangning }
920f1702c5SYu Xiangning
930f1702c5SYu Xiangning so->so_mode |= SM_KERNEL;
940f1702c5SYu Xiangning
950f1702c5SYu Xiangning *ksp = SOTOKS(so);
960f1702c5SYu Xiangning
970f1702c5SYu Xiangning return (0);
980f1702c5SYu Xiangning }
990f1702c5SYu Xiangning int
ksocket_bind(ksocket_t ks,struct sockaddr * addr,socklen_t addrlen,struct cred * cr)1000f1702c5SYu Xiangning ksocket_bind(ksocket_t ks, struct sockaddr *addr, socklen_t addrlen,
1010f1702c5SYu Xiangning struct cred *cr)
1020f1702c5SYu Xiangning {
1030f1702c5SYu Xiangning int error;
1040f1702c5SYu Xiangning
105de8c4a14SErik Nordmark /* All Solaris components should pass a cred for this operation. */
106de8c4a14SErik Nordmark ASSERT(cr != NULL);
107de8c4a14SErik Nordmark
1080f1702c5SYu Xiangning if (!KSOCKET_VALID(ks))
1090f1702c5SYu Xiangning return (ENOTSOCK);
1100f1702c5SYu Xiangning
1110f1702c5SYu Xiangning error = socket_bind(KSTOSO(ks), addr, addrlen, _SOBIND_SOCKBSD, cr);
1120f1702c5SYu Xiangning
1130f1702c5SYu Xiangning return (error);
1140f1702c5SYu Xiangning }
1150f1702c5SYu Xiangning
1160f1702c5SYu Xiangning int
ksocket_listen(ksocket_t ks,int backlog,struct cred * cr)1170f1702c5SYu Xiangning ksocket_listen(ksocket_t ks, int backlog, struct cred *cr)
1180f1702c5SYu Xiangning {
119de8c4a14SErik Nordmark /* All Solaris components should pass a cred for this operation. */
120de8c4a14SErik Nordmark ASSERT(cr != NULL);
121de8c4a14SErik Nordmark
1220f1702c5SYu Xiangning if (!KSOCKET_VALID(ks))
1230f1702c5SYu Xiangning return (ENOTSOCK);
1240f1702c5SYu Xiangning
1250f1702c5SYu Xiangning return (socket_listen(KSTOSO(ks), backlog, cr));
1260f1702c5SYu Xiangning }
1270f1702c5SYu Xiangning
1280f1702c5SYu Xiangning int
ksocket_accept(ksocket_t ks,struct sockaddr * addr,socklen_t * addrlenp,ksocket_t * nks,struct cred * cr)1290f1702c5SYu Xiangning ksocket_accept(ksocket_t ks, struct sockaddr *addr,
1300f1702c5SYu Xiangning socklen_t *addrlenp, ksocket_t *nks, struct cred *cr)
1310f1702c5SYu Xiangning {
1320f1702c5SYu Xiangning int error;
1330f1702c5SYu Xiangning struct sonode *nso = NULL;
1340f1702c5SYu Xiangning
135de8c4a14SErik Nordmark /* All Solaris components should pass a cred for this operation. */
136de8c4a14SErik Nordmark ASSERT(cr != NULL);
137de8c4a14SErik Nordmark
1380f1702c5SYu Xiangning *nks = NULL;
1390f1702c5SYu Xiangning
1400f1702c5SYu Xiangning if (!KSOCKET_VALID(ks))
1410f1702c5SYu Xiangning return (ENOTSOCK);
1420f1702c5SYu Xiangning
1430f1702c5SYu Xiangning if (addr != NULL && addrlenp == NULL)
1440f1702c5SYu Xiangning return (EFAULT);
1450f1702c5SYu Xiangning
1460f1702c5SYu Xiangning error = socket_accept(KSTOSO(ks), KSOCKET_FMODE(ks), cr, &nso);
1470f1702c5SYu Xiangning if (error != 0)
1480f1702c5SYu Xiangning return (error);
1490f1702c5SYu Xiangning
1500f1702c5SYu Xiangning ASSERT(nso != NULL);
1510f1702c5SYu Xiangning
1520f1702c5SYu Xiangning nso->so_mode |= SM_KERNEL;
1530f1702c5SYu Xiangning
1540f1702c5SYu Xiangning if (addr != NULL && addrlenp != NULL) {
1550f1702c5SYu Xiangning error = socket_getpeername(nso, addr, addrlenp, B_TRUE, cr);
1560f1702c5SYu Xiangning if (error != 0) {
1570f1702c5SYu Xiangning (void) socket_close(nso, 0, cr);
1580f1702c5SYu Xiangning socket_destroy(nso);
1590f1702c5SYu Xiangning return ((error == ENOTCONN) ? ECONNABORTED : error);
1600f1702c5SYu Xiangning }
1610f1702c5SYu Xiangning }
1620f1702c5SYu Xiangning
1630f1702c5SYu Xiangning *nks = SOTOKS(nso);
1640f1702c5SYu Xiangning
1650f1702c5SYu Xiangning return (error);
1660f1702c5SYu Xiangning }
1670f1702c5SYu Xiangning
1680f1702c5SYu Xiangning int
ksocket_connect(ksocket_t ks,struct sockaddr * addr,socklen_t addrlen,struct cred * cr)1693e95bd4aSAnders Persson ksocket_connect(ksocket_t ks, struct sockaddr *addr, socklen_t addrlen,
1700f1702c5SYu Xiangning struct cred *cr)
1710f1702c5SYu Xiangning {
172de8c4a14SErik Nordmark /* All Solaris components should pass a cred for this operation. */
173de8c4a14SErik Nordmark ASSERT(cr != NULL);
174de8c4a14SErik Nordmark
1750f1702c5SYu Xiangning if (!KSOCKET_VALID(ks))
1760f1702c5SYu Xiangning return (ENOTSOCK);
1770f1702c5SYu Xiangning
1780f1702c5SYu Xiangning return (socket_connect(KSTOSO(ks), addr, addrlen,
1790f1702c5SYu Xiangning KSOCKET_FMODE(ks), 0, cr));
1800f1702c5SYu Xiangning }
1810f1702c5SYu Xiangning
1820f1702c5SYu Xiangning int
ksocket_send(ksocket_t ks,void * msg,size_t msglen,int flags,size_t * sent,struct cred * cr)1830f1702c5SYu Xiangning ksocket_send(ksocket_t ks, void *msg, size_t msglen, int flags,
1840f1702c5SYu Xiangning size_t *sent, struct cred *cr)
1850f1702c5SYu Xiangning {
1860f1702c5SYu Xiangning int error;
1870f1702c5SYu Xiangning struct nmsghdr msghdr;
1880f1702c5SYu Xiangning struct uio auio;
1890f1702c5SYu Xiangning struct iovec iov;
1900f1702c5SYu Xiangning
191de8c4a14SErik Nordmark /* All Solaris components should pass a cred for this operation. */
192de8c4a14SErik Nordmark ASSERT(cr != NULL);
193de8c4a14SErik Nordmark
1940f1702c5SYu Xiangning if (!KSOCKET_VALID(ks)) {
1950f1702c5SYu Xiangning if (sent != NULL)
1960f1702c5SYu Xiangning *sent = 0;
1970f1702c5SYu Xiangning return (ENOTSOCK);
1980f1702c5SYu Xiangning }
1990f1702c5SYu Xiangning
2000f1702c5SYu Xiangning iov.iov_base = msg;
2010f1702c5SYu Xiangning iov.iov_len = msglen;
2020f1702c5SYu Xiangning
2030f1702c5SYu Xiangning bzero(&auio, sizeof (struct uio));
2040f1702c5SYu Xiangning auio.uio_loffset = 0;
2050f1702c5SYu Xiangning auio.uio_iov = &iov;
2060f1702c5SYu Xiangning auio.uio_iovcnt = 1;
2070f1702c5SYu Xiangning auio.uio_resid = msglen;
2080f1702c5SYu Xiangning if (flags & MSG_USERSPACE)
2090f1702c5SYu Xiangning auio.uio_segflg = UIO_USERSPACE;
2100f1702c5SYu Xiangning else
2110f1702c5SYu Xiangning auio.uio_segflg = UIO_SYSSPACE;
2120f1702c5SYu Xiangning auio.uio_extflg = UIO_COPY_DEFAULT;
2130f1702c5SYu Xiangning auio.uio_limit = 0;
2140f1702c5SYu Xiangning auio.uio_fmode = KSOCKET_FMODE(ks);
2150f1702c5SYu Xiangning
2160f1702c5SYu Xiangning msghdr.msg_name = NULL;
2170f1702c5SYu Xiangning msghdr.msg_namelen = 0;
2180f1702c5SYu Xiangning msghdr.msg_control = NULL;
2190f1702c5SYu Xiangning msghdr.msg_controllen = 0;
2200f1702c5SYu Xiangning msghdr.msg_flags = flags | MSG_EOR;
2210f1702c5SYu Xiangning
2220f1702c5SYu Xiangning error = socket_sendmsg(KSTOSO(ks), &msghdr, &auio, cr);
2230f1702c5SYu Xiangning if (error != 0) {
2240f1702c5SYu Xiangning if (sent != NULL)
2250f1702c5SYu Xiangning *sent = 0;
2260f1702c5SYu Xiangning return (error);
2270f1702c5SYu Xiangning }
2280f1702c5SYu Xiangning
2290f1702c5SYu Xiangning if (sent != NULL)
2300f1702c5SYu Xiangning *sent = msglen - auio.uio_resid;
2310f1702c5SYu Xiangning return (0);
2320f1702c5SYu Xiangning }
2330f1702c5SYu Xiangning
2340f1702c5SYu 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)2350f1702c5SYu Xiangning ksocket_sendto(ksocket_t ks, void *msg, size_t msglen, int flags,
2360f1702c5SYu Xiangning struct sockaddr *name, socklen_t namelen, size_t *sent, struct cred *cr)
2370f1702c5SYu Xiangning {
2380f1702c5SYu Xiangning int error;
2390f1702c5SYu Xiangning struct nmsghdr msghdr;
2400f1702c5SYu Xiangning struct uio auio;
2410f1702c5SYu Xiangning struct iovec iov;
2420f1702c5SYu Xiangning
243de8c4a14SErik Nordmark /* All Solaris components should pass a cred for this operation. */
244de8c4a14SErik Nordmark ASSERT(cr != NULL);
245de8c4a14SErik Nordmark
2460f1702c5SYu Xiangning if (!KSOCKET_VALID(ks)) {
2470f1702c5SYu Xiangning if (sent != NULL)
2480f1702c5SYu Xiangning *sent = 0;
2490f1702c5SYu Xiangning return (ENOTSOCK);
2500f1702c5SYu Xiangning }
2510f1702c5SYu Xiangning
2520f1702c5SYu Xiangning iov.iov_base = msg;
2530f1702c5SYu Xiangning iov.iov_len = msglen;
2540f1702c5SYu Xiangning
2550f1702c5SYu Xiangning bzero(&auio, sizeof (struct uio));
2560f1702c5SYu Xiangning auio.uio_loffset = 0;
2570f1702c5SYu Xiangning auio.uio_iov = &iov;
2580f1702c5SYu Xiangning auio.uio_iovcnt = 1;
2590f1702c5SYu Xiangning auio.uio_resid = msglen;
2600f1702c5SYu Xiangning if (flags & MSG_USERSPACE)
2610f1702c5SYu Xiangning auio.uio_segflg = UIO_USERSPACE;
2620f1702c5SYu Xiangning else
2630f1702c5SYu Xiangning auio.uio_segflg = UIO_SYSSPACE;
2640f1702c5SYu Xiangning auio.uio_extflg = UIO_COPY_DEFAULT;
2650f1702c5SYu Xiangning auio.uio_limit = 0;
2660f1702c5SYu Xiangning auio.uio_fmode = KSOCKET_FMODE(ks);
2670f1702c5SYu Xiangning
2680f1702c5SYu Xiangning msghdr.msg_iov = &iov;
2690f1702c5SYu Xiangning msghdr.msg_iovlen = 1;
2700f1702c5SYu Xiangning msghdr.msg_name = (char *)name;
2710f1702c5SYu Xiangning msghdr.msg_namelen = namelen;
2720f1702c5SYu Xiangning msghdr.msg_control = NULL;
2730f1702c5SYu Xiangning msghdr.msg_controllen = 0;
2740f1702c5SYu Xiangning msghdr.msg_flags = flags | MSG_EOR;
2750f1702c5SYu Xiangning
2760f1702c5SYu Xiangning error = socket_sendmsg(KSTOSO(ks), &msghdr, &auio, cr);
2770f1702c5SYu Xiangning if (error != 0) {
2780f1702c5SYu Xiangning if (sent != NULL)
2790f1702c5SYu Xiangning *sent = 0;
2800f1702c5SYu Xiangning return (error);
2810f1702c5SYu Xiangning }
2820f1702c5SYu Xiangning if (sent != NULL)
2830f1702c5SYu Xiangning *sent = msglen - auio.uio_resid;
2840f1702c5SYu Xiangning return (0);
2850f1702c5SYu Xiangning }
2860f1702c5SYu Xiangning
2870f1702c5SYu Xiangning int
ksocket_sendmsg(ksocket_t ks,struct nmsghdr * msg,int flags,size_t * sent,struct cred * cr)2880f1702c5SYu Xiangning ksocket_sendmsg(ksocket_t ks, struct nmsghdr *msg, int flags,
2890f1702c5SYu Xiangning size_t *sent, struct cred *cr)
2900f1702c5SYu Xiangning {
2910f1702c5SYu Xiangning int error;
2920f1702c5SYu Xiangning ssize_t len;
2930f1702c5SYu Xiangning int i;
2940f1702c5SYu Xiangning struct uio auio;
2950f1702c5SYu Xiangning
296de8c4a14SErik Nordmark /* All Solaris components should pass a cred for this operation. */
297de8c4a14SErik Nordmark ASSERT(cr != NULL);
298de8c4a14SErik Nordmark
2990f1702c5SYu Xiangning if (!KSOCKET_VALID(ks)) {
3000f1702c5SYu Xiangning if (sent != NULL)
3010f1702c5SYu Xiangning *sent = 0;
3020f1702c5SYu Xiangning return (ENOTSOCK);
3030f1702c5SYu Xiangning }
3040f1702c5SYu Xiangning
3050f1702c5SYu Xiangning bzero(&auio, sizeof (struct uio));
3060f1702c5SYu Xiangning auio.uio_loffset = 0;
3070f1702c5SYu Xiangning auio.uio_iov = msg->msg_iov;
3080f1702c5SYu Xiangning auio.uio_iovcnt = msg->msg_iovlen;
3090f1702c5SYu Xiangning if (flags & MSG_USERSPACE)
3100f1702c5SYu Xiangning auio.uio_segflg = UIO_USERSPACE;
3110f1702c5SYu Xiangning else
3120f1702c5SYu Xiangning auio.uio_segflg = UIO_SYSSPACE;
3130f1702c5SYu Xiangning auio.uio_extflg = UIO_COPY_DEFAULT;
3140f1702c5SYu Xiangning auio.uio_limit = 0;
3150f1702c5SYu Xiangning auio.uio_fmode = KSOCKET_FMODE(ks);
3160f1702c5SYu Xiangning len = 0;
3170f1702c5SYu Xiangning for (i = 0; i < msg->msg_iovlen; i++) {
3180f1702c5SYu Xiangning ssize_t iovlen;
3190f1702c5SYu Xiangning iovlen = (msg->msg_iov)[i].iov_len;
3200f1702c5SYu Xiangning len += iovlen;
3210f1702c5SYu Xiangning if (len < 0 || iovlen < 0)
3220f1702c5SYu Xiangning return (EINVAL);
3230f1702c5SYu Xiangning }
3240f1702c5SYu Xiangning auio.uio_resid = len;
3250f1702c5SYu Xiangning
3260f1702c5SYu Xiangning msg->msg_flags = flags | MSG_EOR;
3270f1702c5SYu Xiangning
3280f1702c5SYu Xiangning error = socket_sendmsg(KSTOSO(ks), msg, &auio, cr);
3290f1702c5SYu Xiangning if (error != 0) {
3300f1702c5SYu Xiangning if (sent != NULL)
3310f1702c5SYu Xiangning *sent = 0;
3320f1702c5SYu Xiangning return (error);
3330f1702c5SYu Xiangning }
3340f1702c5SYu Xiangning
3350f1702c5SYu Xiangning if (sent != NULL)
3360f1702c5SYu Xiangning *sent = len - auio.uio_resid;
3370f1702c5SYu Xiangning return (0);
3380f1702c5SYu Xiangning }
3390f1702c5SYu Xiangning
3400f1702c5SYu Xiangning
3410f1702c5SYu Xiangning int
ksocket_recv(ksocket_t ks,void * msg,size_t msglen,int flags,size_t * recv,struct cred * cr)3420f1702c5SYu Xiangning ksocket_recv(ksocket_t ks, void *msg, size_t msglen, int flags,
3430f1702c5SYu Xiangning size_t *recv, struct cred *cr)
3440f1702c5SYu Xiangning {
3450f1702c5SYu Xiangning int error;
3460f1702c5SYu Xiangning struct nmsghdr msghdr;
3470f1702c5SYu Xiangning struct uio auio;
3480f1702c5SYu Xiangning struct iovec iov;
3490f1702c5SYu Xiangning
350de8c4a14SErik Nordmark /* All Solaris components should pass a cred for this operation. */
351de8c4a14SErik Nordmark ASSERT(cr != NULL);
352de8c4a14SErik Nordmark
3530f1702c5SYu Xiangning if (!KSOCKET_VALID(ks)) {
3540f1702c5SYu Xiangning if (recv != NULL)
3550f1702c5SYu Xiangning *recv = 0;
3560f1702c5SYu Xiangning return (ENOTSOCK);
3570f1702c5SYu Xiangning }
3580f1702c5SYu Xiangning
3590f1702c5SYu Xiangning iov.iov_base = msg;
3600f1702c5SYu Xiangning iov.iov_len = msglen;
3610f1702c5SYu Xiangning
3620f1702c5SYu Xiangning bzero(&auio, sizeof (struct uio));
3630f1702c5SYu Xiangning auio.uio_loffset = 0;
3640f1702c5SYu Xiangning auio.uio_iov = &iov;
3650f1702c5SYu Xiangning auio.uio_iovcnt = 1;
3660f1702c5SYu Xiangning auio.uio_resid = msglen;
3670f1702c5SYu Xiangning if (flags & MSG_USERSPACE)
3680f1702c5SYu Xiangning auio.uio_segflg = UIO_USERSPACE;
3690f1702c5SYu Xiangning else
3700f1702c5SYu Xiangning auio.uio_segflg = UIO_SYSSPACE;
3710f1702c5SYu Xiangning auio.uio_extflg = UIO_COPY_DEFAULT;
3720f1702c5SYu Xiangning auio.uio_limit = 0;
3730f1702c5SYu Xiangning auio.uio_fmode = KSOCKET_FMODE(ks);
3740f1702c5SYu Xiangning
3750f1702c5SYu Xiangning msghdr.msg_name = NULL;
3760f1702c5SYu Xiangning msghdr.msg_namelen = 0;
3770f1702c5SYu Xiangning msghdr.msg_control = NULL;
3780f1702c5SYu Xiangning msghdr.msg_controllen = 0;
3790f1702c5SYu Xiangning msghdr.msg_flags = flags & (MSG_OOB | MSG_PEEK | MSG_WAITALL |
3800f1702c5SYu Xiangning MSG_DONTWAIT | MSG_USERSPACE);
3810f1702c5SYu Xiangning
3820f1702c5SYu Xiangning error = socket_recvmsg(KSTOSO(ks), &msghdr, &auio, cr);
3830f1702c5SYu Xiangning if (error != 0) {
3840f1702c5SYu Xiangning if (recv != NULL)
3850f1702c5SYu Xiangning *recv = 0;
3860f1702c5SYu Xiangning return (error);
3870f1702c5SYu Xiangning }
3880f1702c5SYu Xiangning
3890f1702c5SYu Xiangning if (recv != NULL)
3900f1702c5SYu Xiangning *recv = msglen - auio.uio_resid;
3910f1702c5SYu Xiangning return (0);
3920f1702c5SYu Xiangning }
3930f1702c5SYu Xiangning
3940f1702c5SYu 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)3950f1702c5SYu Xiangning ksocket_recvfrom(ksocket_t ks, void *msg, size_t msglen, int flags,
3960f1702c5SYu Xiangning struct sockaddr *name, socklen_t *namelen, size_t *recv, struct cred *cr)
3970f1702c5SYu Xiangning {
3980f1702c5SYu Xiangning int error;
3990f1702c5SYu Xiangning struct nmsghdr msghdr;
4000f1702c5SYu Xiangning struct uio auio;
4010f1702c5SYu Xiangning struct iovec iov;
4020f1702c5SYu Xiangning
403de8c4a14SErik Nordmark /* All Solaris components should pass a cred for this operation. */
404de8c4a14SErik Nordmark ASSERT(cr != NULL);
405de8c4a14SErik Nordmark
4060f1702c5SYu Xiangning if (!KSOCKET_VALID(ks)) {
4070f1702c5SYu Xiangning if (recv != NULL)
4080f1702c5SYu Xiangning *recv = 0;
4090f1702c5SYu Xiangning return (ENOTSOCK);
4100f1702c5SYu Xiangning }
4110f1702c5SYu Xiangning
4120f1702c5SYu Xiangning iov.iov_base = msg;
4130f1702c5SYu Xiangning iov.iov_len = msglen;
4140f1702c5SYu Xiangning
4150f1702c5SYu Xiangning bzero(&auio, sizeof (struct uio));
4160f1702c5SYu Xiangning auio.uio_loffset = 0;
4170f1702c5SYu Xiangning auio.uio_iov = &iov;
4180f1702c5SYu Xiangning auio.uio_iovcnt = 1;
4190f1702c5SYu Xiangning auio.uio_resid = msglen;
4200f1702c5SYu Xiangning if (flags & MSG_USERSPACE)
4210f1702c5SYu Xiangning auio.uio_segflg = UIO_USERSPACE;
4220f1702c5SYu Xiangning else
4230f1702c5SYu Xiangning auio.uio_segflg = UIO_SYSSPACE;
4240f1702c5SYu Xiangning auio.uio_extflg = UIO_COPY_DEFAULT;
4250f1702c5SYu Xiangning auio.uio_limit = 0;
4260f1702c5SYu Xiangning auio.uio_fmode = KSOCKET_FMODE(ks);
4270f1702c5SYu Xiangning
4280f1702c5SYu Xiangning msghdr.msg_name = (char *)name;
4290f1702c5SYu Xiangning msghdr.msg_namelen = *namelen;
4300f1702c5SYu Xiangning msghdr.msg_control = NULL;
4310f1702c5SYu Xiangning msghdr.msg_controllen = 0;
4320f1702c5SYu Xiangning msghdr.msg_flags = flags & (MSG_OOB | MSG_PEEK | MSG_WAITALL |
4330f1702c5SYu Xiangning MSG_DONTWAIT | MSG_USERSPACE);
4340f1702c5SYu Xiangning
4350f1702c5SYu Xiangning error = socket_recvmsg(KSTOSO(ks), &msghdr, &auio, cr);
4360f1702c5SYu Xiangning if (error != 0) {
4370f1702c5SYu Xiangning if (recv != NULL)
4380f1702c5SYu Xiangning *recv = 0;
4390f1702c5SYu Xiangning return (error);
4400f1702c5SYu Xiangning }
4410f1702c5SYu Xiangning if (recv != NULL)
4420f1702c5SYu Xiangning *recv = msglen - auio.uio_resid;
4430f1702c5SYu Xiangning
4440f1702c5SYu Xiangning bcopy(msghdr.msg_name, name, msghdr.msg_namelen);
4450f1702c5SYu Xiangning bcopy(&msghdr.msg_namelen, namelen, sizeof (msghdr.msg_namelen));
4460f1702c5SYu Xiangning return (0);
4470f1702c5SYu Xiangning }
4480f1702c5SYu Xiangning
4490f1702c5SYu Xiangning int
ksocket_recvmsg(ksocket_t ks,struct nmsghdr * msg,int flags,size_t * recv,struct cred * cr)4500f1702c5SYu Xiangning ksocket_recvmsg(ksocket_t ks, struct nmsghdr *msg, int flags, size_t *recv,
4510f1702c5SYu Xiangning struct cred *cr)
4520f1702c5SYu Xiangning {
4530f1702c5SYu Xiangning int error;
4540f1702c5SYu Xiangning ssize_t len;
4550f1702c5SYu Xiangning int i;
4560f1702c5SYu Xiangning struct uio auio;
4570f1702c5SYu Xiangning
458de8c4a14SErik Nordmark /* All Solaris components should pass a cred for this operation. */
459de8c4a14SErik Nordmark ASSERT(cr != NULL);
460de8c4a14SErik Nordmark
4610f1702c5SYu Xiangning if (!KSOCKET_VALID(ks)) {
4620f1702c5SYu Xiangning if (recv != NULL)
4630f1702c5SYu Xiangning *recv = 0;
4640f1702c5SYu Xiangning return (ENOTSOCK);
4650f1702c5SYu Xiangning }
4660f1702c5SYu Xiangning
4670f1702c5SYu Xiangning bzero(&auio, sizeof (struct uio));
4680f1702c5SYu Xiangning auio.uio_loffset = 0;
4690f1702c5SYu Xiangning auio.uio_iov = msg->msg_iov;
4700f1702c5SYu Xiangning auio.uio_iovcnt = msg->msg_iovlen;
4710f1702c5SYu Xiangning if (msg->msg_flags & MSG_USERSPACE)
4720f1702c5SYu Xiangning auio.uio_segflg = UIO_USERSPACE;
4730f1702c5SYu Xiangning else
4740f1702c5SYu Xiangning auio.uio_segflg = UIO_SYSSPACE;
4750f1702c5SYu Xiangning auio.uio_extflg = UIO_COPY_DEFAULT;
4760f1702c5SYu Xiangning auio.uio_limit = 0;
4770f1702c5SYu Xiangning auio.uio_fmode = KSOCKET_FMODE(ks);
4780f1702c5SYu Xiangning len = 0;
4790f1702c5SYu Xiangning
4800f1702c5SYu Xiangning for (i = 0; i < msg->msg_iovlen; i++) {
4810f1702c5SYu Xiangning ssize_t iovlen;
4820f1702c5SYu Xiangning iovlen = (msg->msg_iov)[i].iov_len;
4830f1702c5SYu Xiangning len += iovlen;
4840f1702c5SYu Xiangning if (len < 0 || iovlen < 0)
4850f1702c5SYu Xiangning return (EINVAL);
4860f1702c5SYu Xiangning }
4870f1702c5SYu Xiangning auio.uio_resid = len;
4880f1702c5SYu Xiangning
4890f1702c5SYu Xiangning msg->msg_flags = flags & (MSG_OOB | MSG_PEEK | MSG_WAITALL |
4900f1702c5SYu Xiangning MSG_DONTWAIT | MSG_USERSPACE);
4910f1702c5SYu Xiangning
4920f1702c5SYu Xiangning error = socket_recvmsg(KSTOSO(ks), msg, &auio, cr);
4930f1702c5SYu Xiangning if (error != 0) {
4940f1702c5SYu Xiangning if (recv != NULL)
4950f1702c5SYu Xiangning *recv = 0;
4960f1702c5SYu Xiangning return (error);
4970f1702c5SYu Xiangning }
4980f1702c5SYu Xiangning if (recv != NULL)
4990f1702c5SYu Xiangning *recv = len - auio.uio_resid;
5000f1702c5SYu Xiangning return (0);
5010f1702c5SYu Xiangning
5020f1702c5SYu Xiangning }
5030f1702c5SYu Xiangning
5040f1702c5SYu Xiangning int
ksocket_shutdown(ksocket_t ks,int how,struct cred * cr)5050f1702c5SYu Xiangning ksocket_shutdown(ksocket_t ks, int how, struct cred *cr)
5060f1702c5SYu Xiangning {
5070f1702c5SYu Xiangning struct sonode *so;
5080f1702c5SYu Xiangning
509de8c4a14SErik Nordmark /* All Solaris components should pass a cred for this operation. */
510de8c4a14SErik Nordmark ASSERT(cr != NULL);
511de8c4a14SErik Nordmark
5120f1702c5SYu Xiangning if (!KSOCKET_VALID(ks))
5130f1702c5SYu Xiangning return (ENOTSOCK);
5140f1702c5SYu Xiangning
5150f1702c5SYu Xiangning so = KSTOSO(ks);
5160f1702c5SYu Xiangning
5170f1702c5SYu Xiangning return (socket_shutdown(so, how, cr));
5180f1702c5SYu Xiangning }
5190f1702c5SYu Xiangning
5200f1702c5SYu Xiangning int
ksocket_close(ksocket_t ks,struct cred * cr)5210f1702c5SYu Xiangning ksocket_close(ksocket_t ks, struct cred *cr)
5220f1702c5SYu Xiangning {
5230f1702c5SYu Xiangning struct sonode *so;
5240f1702c5SYu Xiangning so = KSTOSO(ks);
5250f1702c5SYu Xiangning
526de8c4a14SErik Nordmark /* All Solaris components should pass a cred for this operation. */
527de8c4a14SErik Nordmark ASSERT(cr != NULL);
528de8c4a14SErik Nordmark
5290f1702c5SYu Xiangning mutex_enter(&so->so_lock);
5300f1702c5SYu Xiangning
5310f1702c5SYu Xiangning if (!KSOCKET_VALID(ks)) {
5320f1702c5SYu Xiangning mutex_exit(&so->so_lock);
5330f1702c5SYu Xiangning return (ENOTSOCK);
5340f1702c5SYu Xiangning }
5350f1702c5SYu Xiangning
5360f1702c5SYu Xiangning so->so_state |= SS_CLOSING;
5370f1702c5SYu Xiangning
5380f1702c5SYu Xiangning if (so->so_count > 1) {
5390f1702c5SYu Xiangning mutex_enter(&so->so_acceptq_lock);
5400f1702c5SYu Xiangning cv_broadcast(&so->so_acceptq_cv);
5410f1702c5SYu Xiangning mutex_exit(&so->so_acceptq_lock);
5420f1702c5SYu Xiangning cv_broadcast(&so->so_rcv_cv);
5430f1702c5SYu Xiangning cv_broadcast(&so->so_state_cv);
5446a571a2dSAnders Persson cv_broadcast(&so->so_single_cv);
5456a571a2dSAnders Persson cv_broadcast(&so->so_read_cv);
5460f1702c5SYu Xiangning cv_broadcast(&so->so_snd_cv);
5470f1702c5SYu Xiangning cv_broadcast(&so->so_copy_cv);
5480f1702c5SYu Xiangning }
5490f1702c5SYu Xiangning while (so->so_count > 1)
5500f1702c5SYu Xiangning cv_wait(&so->so_closing_cv, &so->so_lock);
5510f1702c5SYu Xiangning
5520f1702c5SYu Xiangning mutex_exit(&so->so_lock);
5530f1702c5SYu Xiangning /* Remove callbacks, if any */
5540f1702c5SYu Xiangning (void) ksocket_setcallbacks(ks, NULL, NULL, cr);
5550f1702c5SYu Xiangning
5560f1702c5SYu Xiangning (void) socket_close(so, 0, cr);
5570f1702c5SYu Xiangning socket_destroy(so);
5580f1702c5SYu Xiangning
5590f1702c5SYu Xiangning return (0);
5600f1702c5SYu Xiangning }
5610f1702c5SYu Xiangning
5620f1702c5SYu Xiangning int
ksocket_getsockname(ksocket_t ks,struct sockaddr * addr,socklen_t * addrlen,struct cred * cr)5630f1702c5SYu Xiangning ksocket_getsockname(ksocket_t ks, struct sockaddr *addr, socklen_t *addrlen,
5640f1702c5SYu Xiangning struct cred *cr)
5650f1702c5SYu Xiangning {
5660f1702c5SYu Xiangning struct sonode *so;
5670f1702c5SYu Xiangning
568de8c4a14SErik Nordmark /* All Solaris components should pass a cred for this operation. */
569de8c4a14SErik Nordmark ASSERT(cr != NULL);
570de8c4a14SErik Nordmark
5710f1702c5SYu Xiangning if (!KSOCKET_VALID(ks))
5720f1702c5SYu Xiangning return (ENOTSOCK);
5730f1702c5SYu Xiangning
5740f1702c5SYu Xiangning so = KSTOSO(ks);
5750f1702c5SYu Xiangning
5760f1702c5SYu Xiangning if (addrlen == NULL || (addr == NULL && *addrlen != 0))
5770f1702c5SYu Xiangning return (EFAULT);
5780f1702c5SYu Xiangning
5790f1702c5SYu Xiangning return (socket_getsockname(so, addr, addrlen, cr));
5800f1702c5SYu Xiangning }
5810f1702c5SYu Xiangning
5820f1702c5SYu Xiangning int
ksocket_getpeername(ksocket_t ks,struct sockaddr * addr,socklen_t * addrlen,struct cred * cr)5830f1702c5SYu Xiangning ksocket_getpeername(ksocket_t ks, struct sockaddr *addr, socklen_t *addrlen,
5840f1702c5SYu Xiangning struct cred *cr)
5850f1702c5SYu Xiangning {
5860f1702c5SYu Xiangning struct sonode *so;
5870f1702c5SYu Xiangning
588de8c4a14SErik Nordmark /* All Solaris components should pass a cred for this operation. */
589de8c4a14SErik Nordmark ASSERT(cr != NULL);
590de8c4a14SErik Nordmark
5910f1702c5SYu Xiangning if (!KSOCKET_VALID(ks))
5920f1702c5SYu Xiangning return (ENOTSOCK);
5930f1702c5SYu Xiangning
5940f1702c5SYu Xiangning so = KSTOSO(ks);
5950f1702c5SYu Xiangning
5960f1702c5SYu Xiangning if (addrlen == NULL || (addr == NULL && *addrlen != 0))
5970f1702c5SYu Xiangning return (EFAULT);
5980f1702c5SYu Xiangning
5990f1702c5SYu Xiangning return (socket_getpeername(so, addr, addrlen, B_FALSE, cr));
6000f1702c5SYu Xiangning }
6010f1702c5SYu Xiangning
6020f1702c5SYu Xiangning int
ksocket_getsockopt(ksocket_t ks,int level,int optname,void * optval,int * optlen,struct cred * cr)6030f1702c5SYu Xiangning ksocket_getsockopt(ksocket_t ks, int level, int optname, void *optval,
6040f1702c5SYu Xiangning int *optlen, struct cred *cr)
6050f1702c5SYu Xiangning {
6060f1702c5SYu Xiangning struct sonode *so;
6070f1702c5SYu Xiangning
608de8c4a14SErik Nordmark /* All Solaris components should pass a cred for this operation. */
609de8c4a14SErik Nordmark ASSERT(cr != NULL);
610de8c4a14SErik Nordmark
6110f1702c5SYu Xiangning if (!KSOCKET_VALID(ks))
6120f1702c5SYu Xiangning return (ENOTSOCK);
6130f1702c5SYu Xiangning
6140f1702c5SYu Xiangning so = KSTOSO(ks);
6150f1702c5SYu Xiangning
6160f1702c5SYu Xiangning if (optlen == NULL)
6170f1702c5SYu Xiangning return (EFAULT);
6180f1702c5SYu Xiangning if (*optlen > SO_MAXARGSIZE)
6190f1702c5SYu Xiangning return (EINVAL);
6200f1702c5SYu Xiangning
6210f1702c5SYu Xiangning return (socket_getsockopt(so, level, optname, optval,
6220f1702c5SYu Xiangning (socklen_t *)optlen, 0, cr));
6230f1702c5SYu Xiangning }
6240f1702c5SYu Xiangning
6250f1702c5SYu Xiangning int
ksocket_setsockopt(ksocket_t ks,int level,int optname,const void * optval,int optlen,struct cred * cr)6260f1702c5SYu Xiangning ksocket_setsockopt(ksocket_t ks, int level, int optname, const void *optval,
6270f1702c5SYu Xiangning int optlen, struct cred *cr)
6280f1702c5SYu Xiangning {
6290f1702c5SYu Xiangning struct sonode *so;
6300f1702c5SYu Xiangning
631de8c4a14SErik Nordmark /* All Solaris components should pass a cred for this operation. */
632de8c4a14SErik Nordmark ASSERT(cr != NULL);
633de8c4a14SErik Nordmark
6340f1702c5SYu Xiangning if (!KSOCKET_VALID(ks))
6350f1702c5SYu Xiangning return (ENOTSOCK);
6360f1702c5SYu Xiangning
6370f1702c5SYu Xiangning so = KSTOSO(ks);
6380f1702c5SYu Xiangning
6390f1702c5SYu Xiangning if (optval == NULL)
6400f1702c5SYu Xiangning optlen = 0;
6410f1702c5SYu Xiangning
6420f1702c5SYu Xiangning return (socket_setsockopt(so, level, optname, optval,
6430f1702c5SYu Xiangning (t_uscalar_t)optlen, cr));
6440f1702c5SYu Xiangning }
6450f1702c5SYu Xiangning
6460f1702c5SYu Xiangning /* ARGSUSED */
6470f1702c5SYu Xiangning int
ksocket_setcallbacks(ksocket_t ks,ksocket_callbacks_t * cb,void * arg,struct cred * cr)6480f1702c5SYu Xiangning ksocket_setcallbacks(ksocket_t ks, ksocket_callbacks_t *cb, void *arg,
6490f1702c5SYu Xiangning struct cred *cr)
6500f1702c5SYu Xiangning {
6510f1702c5SYu Xiangning struct sonode *so;
6520f1702c5SYu Xiangning
653de8c4a14SErik Nordmark /* All Solaris components should pass a cred for this operation. */
654de8c4a14SErik Nordmark ASSERT(cr != NULL);
655de8c4a14SErik Nordmark
6560f1702c5SYu Xiangning if (!KSOCKET_VALID(ks))
6570f1702c5SYu Xiangning return (ENOTSOCK);
6580f1702c5SYu Xiangning
6590f1702c5SYu Xiangning so = KSTOSO(ks);
6600f1702c5SYu Xiangning
6610f1702c5SYu Xiangning if (cb == NULL && arg != NULL)
6620f1702c5SYu Xiangning return (EFAULT);
6630f1702c5SYu Xiangning if (cb == NULL) {
6640f1702c5SYu Xiangning mutex_enter(&so->so_lock);
6650f1702c5SYu Xiangning bzero(&(so->so_ksock_callbacks), sizeof (ksocket_callbacks_t));
6660f1702c5SYu Xiangning so->so_ksock_cb_arg = NULL;
6670f1702c5SYu Xiangning mutex_exit(&so->so_lock);
6680f1702c5SYu Xiangning } else {
6690f1702c5SYu Xiangning mutex_enter(&so->so_lock);
6700f1702c5SYu Xiangning SETCALLBACK(so, cb, connected, KSOCKET_CB_CONNECTED)
6710f1702c5SYu Xiangning SETCALLBACK(so, cb, connectfailed, KSOCKET_CB_CONNECTFAILED)
6720f1702c5SYu Xiangning SETCALLBACK(so, cb, disconnected, KSOCKET_CB_DISCONNECTED)
6730f1702c5SYu Xiangning SETCALLBACK(so, cb, newdata, KSOCKET_CB_NEWDATA)
6740f1702c5SYu Xiangning SETCALLBACK(so, cb, newconn, KSOCKET_CB_NEWCONN)
6750f1702c5SYu Xiangning SETCALLBACK(so, cb, cansend, KSOCKET_CB_CANSEND)
6760f1702c5SYu Xiangning SETCALLBACK(so, cb, oobdata, KSOCKET_CB_OOBDATA)
6770f1702c5SYu Xiangning SETCALLBACK(so, cb, cantsendmore, KSOCKET_CB_CANTSENDMORE)
6780f1702c5SYu Xiangning SETCALLBACK(so, cb, cantrecvmore, KSOCKET_CB_CANTRECVMORE)
6790f1702c5SYu Xiangning so->so_ksock_cb_arg = arg;
6800f1702c5SYu Xiangning mutex_exit(&so->so_lock);
6810f1702c5SYu Xiangning }
6820f1702c5SYu Xiangning return (0);
6830f1702c5SYu Xiangning }
6840f1702c5SYu Xiangning
6850f1702c5SYu Xiangning int
ksocket_ioctl(ksocket_t ks,int cmd,intptr_t arg,int * rvalp,struct cred * cr)6860f1702c5SYu Xiangning ksocket_ioctl(ksocket_t ks, int cmd, intptr_t arg, int *rvalp, struct cred *cr)
6870f1702c5SYu Xiangning {
6880f1702c5SYu Xiangning struct sonode *so;
6890f1702c5SYu Xiangning int rval;
6900f1702c5SYu Xiangning
691de8c4a14SErik Nordmark /* All Solaris components should pass a cred for this operation. */
692de8c4a14SErik Nordmark ASSERT(cr != NULL);
693de8c4a14SErik Nordmark
6940f1702c5SYu Xiangning if (!KSOCKET_VALID(ks))
6950f1702c5SYu Xiangning return (ENOTSOCK);
6960f1702c5SYu Xiangning
6970f1702c5SYu Xiangning so = KSTOSO(ks);
6980f1702c5SYu Xiangning
6990f1702c5SYu Xiangning switch (cmd) {
7000f1702c5SYu Xiangning default:
7010f1702c5SYu Xiangning /* STREAM iotcls are not supported */
7020f1702c5SYu Xiangning if ((cmd & 0xffffff00U) == STR) {
7030f1702c5SYu Xiangning rval = EOPNOTSUPP;
7040f1702c5SYu Xiangning } else {
7050f1702c5SYu Xiangning rval = socket_ioctl(so, cmd, arg,
7060f1702c5SYu Xiangning KSOCKET_FMODE(ks) | FKIOCTL, cr, rvalp);
7070f1702c5SYu Xiangning }
7080f1702c5SYu Xiangning break;
7090f1702c5SYu Xiangning case FIOASYNC:
7100f1702c5SYu Xiangning case SIOCSPGRP:
7110f1702c5SYu Xiangning case FIOSETOWN:
7120f1702c5SYu Xiangning case SIOCGPGRP:
7130f1702c5SYu Xiangning case FIOGETOWN:
7140f1702c5SYu Xiangning rval = EOPNOTSUPP;
7150f1702c5SYu Xiangning break;
7160f1702c5SYu Xiangning }
7170f1702c5SYu Xiangning
7180f1702c5SYu Xiangning return (rval);
7190f1702c5SYu Xiangning }
7200f1702c5SYu Xiangning
7213076c25aSStepan Zastupov /*
7223076c25aSStepan Zastupov * Wait for an input event, similar to t_kspoll().
7233076c25aSStepan Zastupov * Ideas and code borrowed from ../devpoll.c
7243076c25aSStepan Zastupov * Basically, setup just enough poll data structures so
7253076c25aSStepan Zastupov * we can block on a CV until timeout or pollwakeup().
7263076c25aSStepan Zastupov */
7273076c25aSStepan Zastupov int
ksocket_spoll(ksocket_t ks,int timo,short events,short * revents,struct cred * cr)7283076c25aSStepan Zastupov ksocket_spoll(ksocket_t ks, int timo, short events, short *revents,
7293076c25aSStepan Zastupov struct cred *cr)
7303076c25aSStepan Zastupov {
7313076c25aSStepan Zastupov struct sonode *so;
7323076c25aSStepan Zastupov pollhead_t *php, *php2;
7333076c25aSStepan Zastupov polldat_t *pdp;
7343076c25aSStepan Zastupov pollcache_t *pcp;
7353076c25aSStepan Zastupov int error;
7363076c25aSStepan Zastupov clock_t expires = 0;
7373076c25aSStepan Zastupov clock_t rval;
7383076c25aSStepan Zastupov
7393076c25aSStepan Zastupov /* All Solaris components should pass a cred for this operation. */
7403076c25aSStepan Zastupov ASSERT(cr != NULL);
7413076c25aSStepan Zastupov ASSERT(curthread->t_pollcache == NULL);
7423076c25aSStepan Zastupov
7433076c25aSStepan Zastupov if (revents == NULL)
7443076c25aSStepan Zastupov return (EINVAL);
7453076c25aSStepan Zastupov if (!KSOCKET_VALID(ks))
7463076c25aSStepan Zastupov return (ENOTSOCK);
7473076c25aSStepan Zastupov so = KSTOSO(ks);
7483076c25aSStepan Zastupov
7493076c25aSStepan Zastupov /*
7503076c25aSStepan Zastupov * Check if there are any events already pending.
7513076c25aSStepan Zastupov * If we're not willing to block, (timo == 0) then
7523076c25aSStepan Zastupov * pass "anyyet">0 to socket_poll so it can skip
7533076c25aSStepan Zastupov * some work. Othewise pass "anyyet"=0 and if
7543076c25aSStepan Zastupov * there are no events pending, it will fill in
7553076c25aSStepan Zastupov * the pollhead pointer we need for pollwakeup().
7563076c25aSStepan Zastupov *
7573076c25aSStepan Zastupov * XXX - pollrelock() logic needs to know which
7583076c25aSStepan Zastupov * which pollcache lock to grab. It'd be a
7593076c25aSStepan Zastupov * cleaner solution if we could pass pcp as
7603076c25aSStepan Zastupov * an arguement in VOP_POLL interface instead
7613076c25aSStepan Zastupov * of implicitly passing it using thread_t
7623076c25aSStepan Zastupov * struct. On the other hand, changing VOP_POLL
7633076c25aSStepan Zastupov * interface will require all driver/file system
7643076c25aSStepan Zastupov * poll routine to change. May want to revisit
7653076c25aSStepan Zastupov * the tradeoff later.
7663076c25aSStepan Zastupov */
7673076c25aSStepan Zastupov php = NULL;
7683076c25aSStepan Zastupov *revents = 0;
7693076c25aSStepan Zastupov pcp = pcache_alloc();
7703076c25aSStepan Zastupov pcache_create(pcp, 1);
7713076c25aSStepan Zastupov
7723076c25aSStepan Zastupov mutex_enter(&pcp->pc_lock);
7733076c25aSStepan Zastupov curthread->t_pollcache = pcp;
7743076c25aSStepan Zastupov error = socket_poll(so, (short)events, (timo == 0),
7753076c25aSStepan Zastupov revents, &php);
7763076c25aSStepan Zastupov curthread->t_pollcache = NULL;
7773076c25aSStepan Zastupov mutex_exit(&pcp->pc_lock);
7783076c25aSStepan Zastupov
7793076c25aSStepan Zastupov if (error != 0 || *revents != 0 || timo == 0)
7803076c25aSStepan Zastupov goto out;
7813076c25aSStepan Zastupov
7823076c25aSStepan Zastupov /*
7833076c25aSStepan Zastupov * Need to block. Did not get *revents, so the
7843076c25aSStepan Zastupov * php should be non-NULL, but let's verify.
7853076c25aSStepan Zastupov * Also compute when our sleep expires.
7863076c25aSStepan Zastupov */
7873076c25aSStepan Zastupov if (php == NULL) {
7883076c25aSStepan Zastupov error = EIO;
7893076c25aSStepan Zastupov goto out;
7903076c25aSStepan Zastupov }
7913076c25aSStepan Zastupov if (timo > 0)
7923076c25aSStepan Zastupov expires = ddi_get_lbolt() +
7933076c25aSStepan Zastupov MSEC_TO_TICK_ROUNDUP(timo);
7943076c25aSStepan Zastupov
7953076c25aSStepan Zastupov /*
7963076c25aSStepan Zastupov * Setup: pollhead -> polldat -> pollcache
7973076c25aSStepan Zastupov * needed for pollwakeup()
7983076c25aSStepan Zastupov * pdp should be freed by pcache_destroy
7993076c25aSStepan Zastupov */
8003076c25aSStepan Zastupov pdp = kmem_zalloc(sizeof (*pdp), KM_SLEEP);
8013076c25aSStepan Zastupov pdp->pd_fd = 0;
8023076c25aSStepan Zastupov pdp->pd_events = events;
8033076c25aSStepan Zastupov pdp->pd_pcache = pcp;
8043076c25aSStepan Zastupov pcache_insert_fd(pcp, pdp, 1);
805*2c76d751SPatrick Mooney polldat_associate(pdp, php);
8063076c25aSStepan Zastupov
8073076c25aSStepan Zastupov mutex_enter(&pcp->pc_lock);
8083076c25aSStepan Zastupov while (!(so->so_state & SS_CLOSING)) {
8093076c25aSStepan Zastupov pcp->pc_flag = 0;
8103076c25aSStepan Zastupov
8113076c25aSStepan Zastupov /* Ditto pcp comment above. */
8123076c25aSStepan Zastupov curthread->t_pollcache = pcp;
8133076c25aSStepan Zastupov error = socket_poll(so, (short)events, 0,
8143076c25aSStepan Zastupov revents, &php2);
8153076c25aSStepan Zastupov curthread->t_pollcache = NULL;
8163076c25aSStepan Zastupov ASSERT(php2 == php);
8173076c25aSStepan Zastupov
8183076c25aSStepan Zastupov if (error != 0 || *revents != 0)
8193076c25aSStepan Zastupov break;
8203076c25aSStepan Zastupov
821a5eb7107SBryan Cantrill if (pcp->pc_flag & PC_POLLWAKE)
8223076c25aSStepan Zastupov continue;
8233076c25aSStepan Zastupov
8243076c25aSStepan Zastupov if (timo == -1) {
8253076c25aSStepan Zastupov rval = cv_wait_sig(&pcp->pc_cv, &pcp->pc_lock);
8263076c25aSStepan Zastupov } else {
8273076c25aSStepan Zastupov rval = cv_timedwait_sig(&pcp->pc_cv, &pcp->pc_lock,
8283076c25aSStepan Zastupov expires);
8293076c25aSStepan Zastupov }
8303076c25aSStepan Zastupov if (rval <= 0) {
8313076c25aSStepan Zastupov if (rval == 0)
8323076c25aSStepan Zastupov error = EINTR;
8333076c25aSStepan Zastupov break;
8343076c25aSStepan Zastupov }
8353076c25aSStepan Zastupov }
8363076c25aSStepan Zastupov mutex_exit(&pcp->pc_lock);
8373076c25aSStepan Zastupov
838*2c76d751SPatrick Mooney polldat_disassociate(pdp);
839*2c76d751SPatrick Mooney pdp->pd_fd = 0;
8403076c25aSStepan Zastupov
8413076c25aSStepan Zastupov /*
8423076c25aSStepan Zastupov * pollwakeup() may still interact with this pollcache. Wait until
8433076c25aSStepan Zastupov * it is done.
8443076c25aSStepan Zastupov */
8453076c25aSStepan Zastupov mutex_enter(&pcp->pc_no_exit);
8463076c25aSStepan Zastupov ASSERT(pcp->pc_busy >= 0);
8473076c25aSStepan Zastupov while (pcp->pc_busy > 0)
8483076c25aSStepan Zastupov cv_wait(&pcp->pc_busy_cv, &pcp->pc_no_exit);
8493076c25aSStepan Zastupov mutex_exit(&pcp->pc_no_exit);
8503076c25aSStepan Zastupov out:
8513076c25aSStepan Zastupov pcache_destroy(pcp);
8523076c25aSStepan Zastupov return (error);
8533076c25aSStepan Zastupov }
8543076c25aSStepan Zastupov
8550f1702c5SYu Xiangning int
ksocket_sendmblk(ksocket_t ks,struct nmsghdr * msg,int flags,mblk_t ** mpp,cred_t * cr)8560f1702c5SYu Xiangning ksocket_sendmblk(ksocket_t ks, struct nmsghdr *msg, int flags,
8570f1702c5SYu Xiangning mblk_t **mpp, cred_t *cr)
8580f1702c5SYu Xiangning {
8590f1702c5SYu Xiangning struct sonode *so;
8600f1702c5SYu Xiangning int i_val;
8610f1702c5SYu Xiangning socklen_t val_len;
8620f1702c5SYu Xiangning mblk_t *mp = *mpp;
8630f1702c5SYu Xiangning int error;
8640f1702c5SYu Xiangning
865de8c4a14SErik Nordmark /* All Solaris components should pass a cred for this operation. */
866de8c4a14SErik Nordmark ASSERT(cr != NULL);
867de8c4a14SErik Nordmark
8680f1702c5SYu Xiangning if (!KSOCKET_VALID(ks))
8690f1702c5SYu Xiangning return (ENOTSOCK);
8700f1702c5SYu Xiangning
8710f1702c5SYu Xiangning so = KSTOSO(ks);
8720f1702c5SYu Xiangning
8730f1702c5SYu Xiangning if (flags & MSG_MBLK_QUICKRELE) {
8740f1702c5SYu Xiangning error = socket_getsockopt(so, SOL_SOCKET, SO_SND_COPYAVOID,
875de8c4a14SErik Nordmark &i_val, &val_len, 0, cr);
8760f1702c5SYu Xiangning if (error != 0)
8770f1702c5SYu Xiangning return (error);
8780f1702c5SYu Xiangning
8790f1702c5SYu Xiangning /* Zero copy is not enable */
8800f1702c5SYu Xiangning if (i_val == 0)
8810f1702c5SYu Xiangning return (ECANCELED);
8820f1702c5SYu Xiangning
8830f1702c5SYu Xiangning for (; mp != NULL; mp = mp->b_cont)
8840f1702c5SYu Xiangning mp->b_datap->db_struioflag |= STRUIO_ZC;
8850f1702c5SYu Xiangning }
8860f1702c5SYu Xiangning
8870f1702c5SYu Xiangning error = socket_sendmblk(so, msg, flags, cr, mpp);
8880f1702c5SYu Xiangning
8890f1702c5SYu Xiangning return (error);
8900f1702c5SYu Xiangning }
8910f1702c5SYu Xiangning
8920f1702c5SYu Xiangning
8930f1702c5SYu Xiangning void
ksocket_hold(ksocket_t ks)8940f1702c5SYu Xiangning ksocket_hold(ksocket_t ks)
8950f1702c5SYu Xiangning {
8960f1702c5SYu Xiangning struct sonode *so;
8970f1702c5SYu Xiangning so = KSTOSO(ks);
8980f1702c5SYu Xiangning
8990f1702c5SYu Xiangning if (!mutex_owned(&so->so_lock)) {
9000f1702c5SYu Xiangning mutex_enter(&so->so_lock);
9010f1702c5SYu Xiangning so->so_count++;
9020f1702c5SYu Xiangning mutex_exit(&so->so_lock);
9030f1702c5SYu Xiangning } else
9040f1702c5SYu Xiangning so->so_count++;
9050f1702c5SYu Xiangning }
9060f1702c5SYu Xiangning
9070f1702c5SYu Xiangning void
ksocket_rele(ksocket_t ks)9080f1702c5SYu Xiangning ksocket_rele(ksocket_t ks)
9090f1702c5SYu Xiangning {
9100f1702c5SYu Xiangning struct sonode *so;
9110f1702c5SYu Xiangning
9120f1702c5SYu Xiangning so = KSTOSO(ks);
9130f1702c5SYu Xiangning /*
9140f1702c5SYu Xiangning * When so_count equals 1 means no thread working on this ksocket
9150f1702c5SYu Xiangning */
9160f1702c5SYu Xiangning if (so->so_count < 2)
9170f1702c5SYu Xiangning cmn_err(CE_PANIC, "ksocket_rele: sonode ref count 0 or 1");
9180f1702c5SYu Xiangning
9190f1702c5SYu Xiangning if (!mutex_owned(&so->so_lock)) {
9200f1702c5SYu Xiangning mutex_enter(&so->so_lock);
9210f1702c5SYu Xiangning if (--so->so_count == 1)
9220f1702c5SYu Xiangning cv_signal(&so->so_closing_cv);
9230f1702c5SYu Xiangning mutex_exit(&so->so_lock);
9240f1702c5SYu Xiangning } else {
9250f1702c5SYu Xiangning if (--so->so_count == 1)
9260f1702c5SYu Xiangning cv_signal(&so->so_closing_cv);
9270f1702c5SYu Xiangning }
9280f1702c5SYu Xiangning }
929907c2824SRobert Mustacchi
930907c2824SRobert Mustacchi int
ksocket_krecv_set(ksocket_t ks,ksocket_krecv_f cb,void * arg)931907c2824SRobert Mustacchi ksocket_krecv_set(ksocket_t ks, ksocket_krecv_f cb, void *arg)
932907c2824SRobert Mustacchi {
933907c2824SRobert Mustacchi return (so_krecv_set(KSTOSO(ks), (so_krecv_f)cb, arg));
934907c2824SRobert Mustacchi }
935907c2824SRobert Mustacchi
936907c2824SRobert Mustacchi void
ksocket_krecv_unblock(ksocket_t ks)937907c2824SRobert Mustacchi ksocket_krecv_unblock(ksocket_t ks)
938907c2824SRobert Mustacchi {
939907c2824SRobert Mustacchi return (so_krecv_unblock(KSTOSO(ks)));
940907c2824SRobert Mustacchi }
941