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