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 /* 23c0dd49bdSEiji Ota * Copyright (c) 1999, 2010, Oracle and/or its affiliates. All rights reserved. 240f1702c5SYu Xiangning */ 250f1702c5SYu Xiangning 2668846fd0SBryan Cantrill /* 2768846fd0SBryan Cantrill * Copyright (c) 2014, Joyent, Inc. All rights reserved. 2868846fd0SBryan Cantrill */ 2968846fd0SBryan Cantrill 300f1702c5SYu Xiangning #include <sys/types.h> 310f1702c5SYu Xiangning #include <sys/param.h> 320f1702c5SYu Xiangning #include <sys/systm.h> 330f1702c5SYu Xiangning #include <sys/sysmacros.h> 340f1702c5SYu Xiangning #include <sys/debug.h> 350f1702c5SYu Xiangning #include <sys/cmn_err.h> 360f1702c5SYu Xiangning 370f1702c5SYu Xiangning #include <sys/stropts.h> 380f1702c5SYu Xiangning #include <sys/socket.h> 390f1702c5SYu Xiangning #include <sys/socketvar.h> 400f1702c5SYu Xiangning 410f1702c5SYu Xiangning #define _SUN_TPI_VERSION 2 420f1702c5SYu Xiangning #include <sys/tihdr.h> 430f1702c5SYu Xiangning #include <sys/sockio.h> 440f1702c5SYu Xiangning #include <sys/kmem_impl.h> 450f1702c5SYu Xiangning 460f1702c5SYu Xiangning #include <sys/strsubr.h> 470f1702c5SYu Xiangning #include <sys/strsun.h> 480f1702c5SYu Xiangning #include <sys/ddi.h> 490f1702c5SYu Xiangning #include <netinet/in.h> 500f1702c5SYu Xiangning #include <inet/ip.h> 510f1702c5SYu Xiangning 520f1702c5SYu Xiangning #include <fs/sockfs/sockcommon.h> 533e95bd4aSAnders Persson #include <fs/sockfs/sockfilter_impl.h> 540f1702c5SYu Xiangning 550f1702c5SYu Xiangning #include <sys/socket_proto.h> 560f1702c5SYu Xiangning 570f1702c5SYu Xiangning #include <fs/sockfs/socktpi_impl.h> 58bbc000e5SAnders Persson #include <fs/sockfs/sodirect.h> 590f1702c5SYu Xiangning #include <sys/tihdr.h> 600f1702c5SYu Xiangning #include <fs/sockfs/nl7c.h> 610f1702c5SYu Xiangning 620f1702c5SYu Xiangning extern int xnet_skip_checks; 630f1702c5SYu Xiangning extern int xnet_check_print; 640f1702c5SYu Xiangning 653e95bd4aSAnders Persson static void so_queue_oob(struct sonode *, mblk_t *, size_t); 660f1702c5SYu Xiangning 670f1702c5SYu Xiangning 680f1702c5SYu Xiangning /*ARGSUSED*/ 690f1702c5SYu Xiangning int 700f1702c5SYu Xiangning so_accept_notsupp(struct sonode *lso, int fflag, 710f1702c5SYu Xiangning struct cred *cr, struct sonode **nsop) 720f1702c5SYu Xiangning { 730f1702c5SYu Xiangning return (EOPNOTSUPP); 740f1702c5SYu Xiangning } 750f1702c5SYu Xiangning 760f1702c5SYu Xiangning /*ARGSUSED*/ 770f1702c5SYu Xiangning int 780f1702c5SYu Xiangning so_listen_notsupp(struct sonode *so, int backlog, struct cred *cr) 790f1702c5SYu Xiangning { 800f1702c5SYu Xiangning return (EOPNOTSUPP); 810f1702c5SYu Xiangning } 820f1702c5SYu Xiangning 830f1702c5SYu Xiangning /*ARGSUSED*/ 840f1702c5SYu Xiangning int 850f1702c5SYu Xiangning so_getsockname_notsupp(struct sonode *so, struct sockaddr *sa, 860f1702c5SYu Xiangning socklen_t *len, struct cred *cr) 870f1702c5SYu Xiangning { 880f1702c5SYu Xiangning return (EOPNOTSUPP); 890f1702c5SYu Xiangning } 900f1702c5SYu Xiangning 910f1702c5SYu Xiangning /*ARGSUSED*/ 920f1702c5SYu Xiangning int 930f1702c5SYu Xiangning so_getpeername_notsupp(struct sonode *so, struct sockaddr *addr, 940f1702c5SYu Xiangning socklen_t *addrlen, boolean_t accept, struct cred *cr) 950f1702c5SYu Xiangning { 960f1702c5SYu Xiangning return (EOPNOTSUPP); 970f1702c5SYu Xiangning } 980f1702c5SYu Xiangning 990f1702c5SYu Xiangning /*ARGSUSED*/ 1000f1702c5SYu Xiangning int 1010f1702c5SYu Xiangning so_shutdown_notsupp(struct sonode *so, int how, struct cred *cr) 1020f1702c5SYu Xiangning { 1030f1702c5SYu Xiangning return (EOPNOTSUPP); 1040f1702c5SYu Xiangning } 1050f1702c5SYu Xiangning 1060f1702c5SYu Xiangning /*ARGSUSED*/ 1070f1702c5SYu Xiangning int 1080f1702c5SYu Xiangning so_sendmblk_notsupp(struct sonode *so, struct msghdr *msg, int fflag, 1090f1702c5SYu Xiangning struct cred *cr, mblk_t **mpp) 1100f1702c5SYu Xiangning { 1110f1702c5SYu Xiangning return (EOPNOTSUPP); 1120f1702c5SYu Xiangning } 1130f1702c5SYu Xiangning 1140f1702c5SYu Xiangning /* 1150f1702c5SYu Xiangning * Generic Socket Ops 1160f1702c5SYu Xiangning */ 1170f1702c5SYu Xiangning 1180f1702c5SYu Xiangning /* ARGSUSED */ 1190f1702c5SYu Xiangning int 1200f1702c5SYu Xiangning so_init(struct sonode *so, struct sonode *pso, struct cred *cr, int flags) 1210f1702c5SYu Xiangning { 1220f1702c5SYu Xiangning return (socket_init_common(so, pso, flags, cr)); 1230f1702c5SYu Xiangning } 1240f1702c5SYu Xiangning 1250f1702c5SYu Xiangning int 1260f1702c5SYu Xiangning so_bind(struct sonode *so, struct sockaddr *name, socklen_t namelen, 1270f1702c5SYu Xiangning int flags, struct cred *cr) 1280f1702c5SYu Xiangning { 1290f1702c5SYu Xiangning int error; 1300f1702c5SYu Xiangning 1310f1702c5SYu Xiangning SO_BLOCK_FALLBACK(so, SOP_BIND(so, name, namelen, flags, cr)); 1320f1702c5SYu Xiangning 1330f1702c5SYu Xiangning ASSERT(flags == _SOBIND_XPG4_2 || flags == _SOBIND_SOCKBSD); 1340f1702c5SYu Xiangning 1350f1702c5SYu Xiangning /* X/Open requires this check */ 1360f1702c5SYu Xiangning if ((so->so_state & SS_CANTSENDMORE) && !xnet_skip_checks) { 1370f1702c5SYu Xiangning if (xnet_check_print) { 1380f1702c5SYu Xiangning printf("sockfs: X/Open bind state check " 1390f1702c5SYu Xiangning "caused EINVAL\n"); 1400f1702c5SYu Xiangning } 1410f1702c5SYu Xiangning error = EINVAL; 1420f1702c5SYu Xiangning goto done; 1430f1702c5SYu Xiangning } 1440f1702c5SYu Xiangning 1450f1702c5SYu Xiangning /* 1460f1702c5SYu Xiangning * a bind to a NULL address is interpreted as unbind. So just 1470f1702c5SYu Xiangning * do the downcall. 1480f1702c5SYu Xiangning */ 1490f1702c5SYu Xiangning if (name == NULL) 1500f1702c5SYu Xiangning goto dobind; 1510f1702c5SYu Xiangning 1520f1702c5SYu Xiangning switch (so->so_family) { 1530f1702c5SYu Xiangning case AF_INET: 1540f1702c5SYu Xiangning if ((size_t)namelen != sizeof (sin_t)) { 1550f1702c5SYu Xiangning error = name->sa_family != so->so_family ? 1560f1702c5SYu Xiangning EAFNOSUPPORT : EINVAL; 1570f1702c5SYu Xiangning eprintsoline(so, error); 1580f1702c5SYu Xiangning goto done; 1590f1702c5SYu Xiangning } 1600f1702c5SYu Xiangning 1610f1702c5SYu Xiangning if ((flags & _SOBIND_XPG4_2) && 1620f1702c5SYu Xiangning (name->sa_family != so->so_family)) { 1630f1702c5SYu Xiangning /* 1640f1702c5SYu Xiangning * This check has to be made for X/Open 1650f1702c5SYu Xiangning * sockets however application failures have 1660f1702c5SYu Xiangning * been observed when it is applied to 1670f1702c5SYu Xiangning * all sockets. 1680f1702c5SYu Xiangning */ 1690f1702c5SYu Xiangning error = EAFNOSUPPORT; 1700f1702c5SYu Xiangning eprintsoline(so, error); 1710f1702c5SYu Xiangning goto done; 1720f1702c5SYu Xiangning } 1730f1702c5SYu Xiangning /* 1740f1702c5SYu Xiangning * Force a zero sa_family to match so_family. 1750f1702c5SYu Xiangning * 1760f1702c5SYu Xiangning * Some programs like inetd(1M) don't set the 1770f1702c5SYu Xiangning * family field. Other programs leave 1780f1702c5SYu Xiangning * sin_family set to garbage - SunOS 4.X does 1790f1702c5SYu Xiangning * not check the family field on a bind. 1800f1702c5SYu Xiangning * We use the family field that 1810f1702c5SYu Xiangning * was passed in to the socket() call. 1820f1702c5SYu Xiangning */ 1830f1702c5SYu Xiangning name->sa_family = so->so_family; 1840f1702c5SYu Xiangning break; 1850f1702c5SYu Xiangning 1860f1702c5SYu Xiangning case AF_INET6: { 1870f1702c5SYu Xiangning #ifdef DEBUG 1880f1702c5SYu Xiangning sin6_t *sin6 = (sin6_t *)name; 1890f1702c5SYu Xiangning #endif 1900f1702c5SYu Xiangning if ((size_t)namelen != sizeof (sin6_t)) { 1910f1702c5SYu Xiangning error = name->sa_family != so->so_family ? 1920f1702c5SYu Xiangning EAFNOSUPPORT : EINVAL; 1930f1702c5SYu Xiangning eprintsoline(so, error); 1940f1702c5SYu Xiangning goto done; 1950f1702c5SYu Xiangning } 1960f1702c5SYu Xiangning 1970f1702c5SYu Xiangning if (name->sa_family != so->so_family) { 1980f1702c5SYu Xiangning /* 1990f1702c5SYu Xiangning * With IPv6 we require the family to match 2000f1702c5SYu Xiangning * unlike in IPv4. 2010f1702c5SYu Xiangning */ 2020f1702c5SYu Xiangning error = EAFNOSUPPORT; 2030f1702c5SYu Xiangning eprintsoline(so, error); 2040f1702c5SYu Xiangning goto done; 2050f1702c5SYu Xiangning } 2060f1702c5SYu Xiangning #ifdef DEBUG 2070f1702c5SYu Xiangning /* 2080f1702c5SYu Xiangning * Verify that apps don't forget to clear 2090f1702c5SYu Xiangning * sin6_scope_id etc 2100f1702c5SYu Xiangning */ 2110f1702c5SYu Xiangning if (sin6->sin6_scope_id != 0 && 2120f1702c5SYu Xiangning !IN6_IS_ADDR_LINKSCOPE(&sin6->sin6_addr)) { 2130f1702c5SYu Xiangning zcmn_err(getzoneid(), CE_WARN, 2140f1702c5SYu Xiangning "bind with uninitialized sin6_scope_id " 2150f1702c5SYu Xiangning "(%d) on socket. Pid = %d\n", 2160f1702c5SYu Xiangning (int)sin6->sin6_scope_id, 2170f1702c5SYu Xiangning (int)curproc->p_pid); 2180f1702c5SYu Xiangning } 2190f1702c5SYu Xiangning if (sin6->__sin6_src_id != 0) { 2200f1702c5SYu Xiangning zcmn_err(getzoneid(), CE_WARN, 2210f1702c5SYu Xiangning "bind with uninitialized __sin6_src_id " 2220f1702c5SYu Xiangning "(%d) on socket. Pid = %d\n", 2230f1702c5SYu Xiangning (int)sin6->__sin6_src_id, 2240f1702c5SYu Xiangning (int)curproc->p_pid); 2250f1702c5SYu Xiangning } 2260f1702c5SYu Xiangning #endif /* DEBUG */ 2270f1702c5SYu Xiangning 2280f1702c5SYu Xiangning break; 2290f1702c5SYu Xiangning } 2300f1702c5SYu Xiangning default: 2310f1702c5SYu Xiangning /* Just pass the request to the protocol */ 2320f1702c5SYu Xiangning goto dobind; 2330f1702c5SYu Xiangning } 2340f1702c5SYu Xiangning 2350f1702c5SYu Xiangning /* 2360f1702c5SYu Xiangning * First we check if either NCA or KSSL has been enabled for 2370f1702c5SYu Xiangning * the requested address, and if so, we fall back to TPI. 2380f1702c5SYu Xiangning * If neither of those two services are enabled, then we just 2390f1702c5SYu Xiangning * pass the request to the protocol. 2400f1702c5SYu Xiangning * 2410f1702c5SYu Xiangning * Note that KSSL can only be enabled on a socket if NCA is NOT 2420f1702c5SYu Xiangning * enabled for that socket, hence the else-statement below. 2430f1702c5SYu Xiangning */ 2440f1702c5SYu Xiangning if (nl7c_enabled && ((so->so_family == AF_INET || 2450f1702c5SYu Xiangning so->so_family == AF_INET6) && 2460f1702c5SYu Xiangning nl7c_lookup_addr(name, namelen) != NULL)) { 2470f1702c5SYu Xiangning /* 2480f1702c5SYu Xiangning * NL7C is not supported in non-global zones, 2490f1702c5SYu Xiangning * we enforce this restriction here. 2500f1702c5SYu Xiangning */ 2510f1702c5SYu Xiangning if (so->so_zoneid == GLOBAL_ZONEID) { 2520f1702c5SYu Xiangning /* NCA should be used, so fall back to TPI */ 2530f1702c5SYu Xiangning error = so_tpi_fallback(so, cr); 2540f1702c5SYu Xiangning SO_UNBLOCK_FALLBACK(so); 2550f1702c5SYu Xiangning if (error) 2560f1702c5SYu Xiangning return (error); 2570f1702c5SYu Xiangning else 2580f1702c5SYu Xiangning return (SOP_BIND(so, name, namelen, flags, cr)); 2590f1702c5SYu Xiangning } 2600f1702c5SYu Xiangning } 2610f1702c5SYu Xiangning 2620f1702c5SYu Xiangning dobind: 2633e95bd4aSAnders Persson if (so->so_filter_active == 0 || 2643e95bd4aSAnders Persson (error = sof_filter_bind(so, name, &namelen, cr)) < 0) { 2650f1702c5SYu Xiangning error = (*so->so_downcalls->sd_bind) 2660f1702c5SYu Xiangning (so->so_proto_handle, name, namelen, cr); 2673e95bd4aSAnders Persson } 2680f1702c5SYu Xiangning done: 2690f1702c5SYu Xiangning SO_UNBLOCK_FALLBACK(so); 2700f1702c5SYu Xiangning 2710f1702c5SYu Xiangning return (error); 2720f1702c5SYu Xiangning } 2730f1702c5SYu Xiangning 2740f1702c5SYu Xiangning int 2750f1702c5SYu Xiangning so_listen(struct sonode *so, int backlog, struct cred *cr) 2760f1702c5SYu Xiangning { 2770f1702c5SYu Xiangning int error = 0; 2780f1702c5SYu Xiangning 2790f1702c5SYu Xiangning ASSERT(MUTEX_NOT_HELD(&so->so_lock)); 2800f1702c5SYu Xiangning SO_BLOCK_FALLBACK(so, SOP_LISTEN(so, backlog, cr)); 2810f1702c5SYu Xiangning 2823e95bd4aSAnders Persson if ((so)->so_filter_active == 0 || 2833e95bd4aSAnders Persson (error = sof_filter_listen(so, &backlog, cr)) < 0) 2843e95bd4aSAnders Persson error = (*so->so_downcalls->sd_listen)(so->so_proto_handle, 2853e95bd4aSAnders Persson backlog, cr); 2860f1702c5SYu Xiangning 2870f1702c5SYu Xiangning SO_UNBLOCK_FALLBACK(so); 2880f1702c5SYu Xiangning 2890f1702c5SYu Xiangning return (error); 2900f1702c5SYu Xiangning } 2910f1702c5SYu Xiangning 2920f1702c5SYu Xiangning 2930f1702c5SYu Xiangning int 2943e95bd4aSAnders Persson so_connect(struct sonode *so, struct sockaddr *name, 2950f1702c5SYu Xiangning socklen_t namelen, int fflag, int flags, struct cred *cr) 2960f1702c5SYu Xiangning { 2970f1702c5SYu Xiangning int error = 0; 2980f1702c5SYu Xiangning sock_connid_t id; 2990f1702c5SYu Xiangning 3000f1702c5SYu Xiangning ASSERT(MUTEX_NOT_HELD(&so->so_lock)); 3010f1702c5SYu Xiangning SO_BLOCK_FALLBACK(so, SOP_CONNECT(so, name, namelen, fflag, flags, cr)); 3020f1702c5SYu Xiangning 3030f1702c5SYu Xiangning /* 3040f1702c5SYu Xiangning * If there is a pending error, return error 3050f1702c5SYu Xiangning * This can happen if a non blocking operation caused an error. 3060f1702c5SYu Xiangning */ 3070f1702c5SYu Xiangning 3080f1702c5SYu Xiangning if (so->so_error != 0) { 3090f1702c5SYu Xiangning mutex_enter(&so->so_lock); 3100f1702c5SYu Xiangning error = sogeterr(so, B_TRUE); 3110f1702c5SYu Xiangning mutex_exit(&so->so_lock); 3120f1702c5SYu Xiangning if (error != 0) 3130f1702c5SYu Xiangning goto done; 3140f1702c5SYu Xiangning } 3150f1702c5SYu Xiangning 3163e95bd4aSAnders Persson if (so->so_filter_active == 0 || 3173e95bd4aSAnders Persson (error = sof_filter_connect(so, (struct sockaddr *)name, 3183e95bd4aSAnders Persson &namelen, cr)) < 0) { 3190f1702c5SYu Xiangning error = (*so->so_downcalls->sd_connect)(so->so_proto_handle, 3200f1702c5SYu Xiangning name, namelen, &id, cr); 3210f1702c5SYu Xiangning 3220f1702c5SYu Xiangning if (error == EINPROGRESS) 3233e95bd4aSAnders Persson error = so_wait_connected(so, 3243e95bd4aSAnders Persson fflag & (FNONBLOCK|FNDELAY), id); 3253e95bd4aSAnders Persson } 3260f1702c5SYu Xiangning done: 3270f1702c5SYu Xiangning SO_UNBLOCK_FALLBACK(so); 3280f1702c5SYu Xiangning return (error); 3290f1702c5SYu Xiangning } 3300f1702c5SYu Xiangning 3310f1702c5SYu Xiangning /*ARGSUSED*/ 3320f1702c5SYu Xiangning int 3330f1702c5SYu Xiangning so_accept(struct sonode *so, int fflag, struct cred *cr, struct sonode **nsop) 3340f1702c5SYu Xiangning { 3350f1702c5SYu Xiangning int error = 0; 3360f1702c5SYu Xiangning struct sonode *nso; 3370f1702c5SYu Xiangning 3380f1702c5SYu Xiangning *nsop = NULL; 3390f1702c5SYu Xiangning 3400f1702c5SYu Xiangning SO_BLOCK_FALLBACK(so, SOP_ACCEPT(so, fflag, cr, nsop)); 3410f1702c5SYu Xiangning if ((so->so_state & SS_ACCEPTCONN) == 0) { 3420f1702c5SYu Xiangning SO_UNBLOCK_FALLBACK(so); 3430f1702c5SYu Xiangning return ((so->so_type == SOCK_DGRAM || so->so_type == SOCK_RAW) ? 3440f1702c5SYu Xiangning EOPNOTSUPP : EINVAL); 3450f1702c5SYu Xiangning } 3460f1702c5SYu Xiangning 3470f1702c5SYu Xiangning if ((error = so_acceptq_dequeue(so, (fflag & (FNONBLOCK|FNDELAY)), 3480f1702c5SYu Xiangning &nso)) == 0) { 3490f1702c5SYu Xiangning ASSERT(nso != NULL); 3500f1702c5SYu Xiangning 3510f1702c5SYu Xiangning /* finish the accept */ 3523e95bd4aSAnders Persson if ((so->so_filter_active > 0 && 3533e95bd4aSAnders Persson (error = sof_filter_accept(nso, cr)) > 0) || 3543e95bd4aSAnders Persson (error = (*so->so_downcalls->sd_accept)(so->so_proto_handle, 3553e95bd4aSAnders Persson nso->so_proto_handle, (sock_upper_handle_t)nso, cr)) != 0) { 3560f1702c5SYu Xiangning (void) socket_close(nso, 0, cr); 3570f1702c5SYu Xiangning socket_destroy(nso); 3580f1702c5SYu Xiangning } else { 3590f1702c5SYu Xiangning *nsop = nso; 3600f1702c5SYu Xiangning } 3610f1702c5SYu Xiangning } 3620f1702c5SYu Xiangning 3630f1702c5SYu Xiangning SO_UNBLOCK_FALLBACK(so); 3640f1702c5SYu Xiangning return (error); 3650f1702c5SYu Xiangning } 3660f1702c5SYu Xiangning 3670f1702c5SYu Xiangning int 3680f1702c5SYu Xiangning so_sendmsg(struct sonode *so, struct nmsghdr *msg, struct uio *uiop, 3690f1702c5SYu Xiangning struct cred *cr) 3700f1702c5SYu Xiangning { 3710f1702c5SYu Xiangning int error, flags; 3720f1702c5SYu Xiangning boolean_t dontblock; 3730f1702c5SYu Xiangning ssize_t orig_resid; 3740f1702c5SYu Xiangning mblk_t *mp; 3750f1702c5SYu Xiangning 3760f1702c5SYu Xiangning SO_BLOCK_FALLBACK(so, SOP_SENDMSG(so, msg, uiop, cr)); 3770f1702c5SYu Xiangning 3780f1702c5SYu Xiangning flags = msg->msg_flags; 3790f1702c5SYu Xiangning error = 0; 3800f1702c5SYu Xiangning dontblock = (flags & MSG_DONTWAIT) || 3810f1702c5SYu Xiangning (uiop->uio_fmode & (FNONBLOCK|FNDELAY)); 3820f1702c5SYu Xiangning 3830f1702c5SYu Xiangning if (!(flags & MSG_XPG4_2) && msg->msg_controllen != 0) { 3840f1702c5SYu Xiangning /* 3850f1702c5SYu Xiangning * Old way of passing fd's is not supported 3860f1702c5SYu Xiangning */ 3870f1702c5SYu Xiangning SO_UNBLOCK_FALLBACK(so); 3880f1702c5SYu Xiangning return (EOPNOTSUPP); 3890f1702c5SYu Xiangning } 3900f1702c5SYu Xiangning 3910f1702c5SYu Xiangning if ((so->so_mode & SM_ATOMIC) && 3920f1702c5SYu Xiangning uiop->uio_resid > so->so_proto_props.sopp_maxpsz && 3930f1702c5SYu Xiangning so->so_proto_props.sopp_maxpsz != -1) { 3940f1702c5SYu Xiangning SO_UNBLOCK_FALLBACK(so); 3950f1702c5SYu Xiangning return (EMSGSIZE); 3960f1702c5SYu Xiangning } 3970f1702c5SYu Xiangning 3980f1702c5SYu Xiangning /* 3990f1702c5SYu Xiangning * For atomic sends we will only do one iteration. 4000f1702c5SYu Xiangning */ 4010f1702c5SYu Xiangning do { 4020f1702c5SYu Xiangning if (so->so_state & SS_CANTSENDMORE) { 4030f1702c5SYu Xiangning error = EPIPE; 4040f1702c5SYu Xiangning break; 4050f1702c5SYu Xiangning } 4060f1702c5SYu Xiangning 4070f1702c5SYu Xiangning if (so->so_error != 0) { 4080f1702c5SYu Xiangning mutex_enter(&so->so_lock); 4090f1702c5SYu Xiangning error = sogeterr(so, B_TRUE); 4100f1702c5SYu Xiangning mutex_exit(&so->so_lock); 4110f1702c5SYu Xiangning if (error != 0) 4120f1702c5SYu Xiangning break; 4130f1702c5SYu Xiangning } 4140f1702c5SYu Xiangning 4150f1702c5SYu Xiangning /* 4160f1702c5SYu Xiangning * Send down OOB messages even if the send path is being 4170f1702c5SYu Xiangning * flow controlled (assuming the protocol supports OOB data). 4180f1702c5SYu Xiangning */ 4190f1702c5SYu Xiangning if (flags & MSG_OOB) { 4200f1702c5SYu Xiangning if ((so->so_mode & SM_EXDATA) == 0) { 4210f1702c5SYu Xiangning error = EOPNOTSUPP; 4220f1702c5SYu Xiangning break; 4230f1702c5SYu Xiangning } 4243e95bd4aSAnders Persson } else if (SO_SND_FLOWCTRLD(so)) { 4250f1702c5SYu Xiangning /* 4260f1702c5SYu Xiangning * Need to wait until the protocol is ready to receive 4270f1702c5SYu Xiangning * more data for transmission. 4280f1702c5SYu Xiangning */ 4290f1702c5SYu Xiangning if ((error = so_snd_wait_qnotfull(so, dontblock)) != 0) 4300f1702c5SYu Xiangning break; 4310f1702c5SYu Xiangning } 4320f1702c5SYu Xiangning 4330f1702c5SYu Xiangning /* 4340f1702c5SYu Xiangning * Time to send data to the protocol. We either copy the 4350f1702c5SYu Xiangning * data into mblks or pass the uio directly to the protocol. 4360f1702c5SYu Xiangning * We decide what to do based on the available down calls. 4370f1702c5SYu Xiangning */ 4380f1702c5SYu Xiangning if (so->so_downcalls->sd_send_uio != NULL) { 4390f1702c5SYu Xiangning error = (*so->so_downcalls->sd_send_uio) 4400f1702c5SYu Xiangning (so->so_proto_handle, uiop, msg, cr); 4410f1702c5SYu Xiangning if (error != 0) 4420f1702c5SYu Xiangning break; 4430f1702c5SYu Xiangning } else { 4440f1702c5SYu Xiangning /* save the resid in case of failure */ 4450f1702c5SYu Xiangning orig_resid = uiop->uio_resid; 4460f1702c5SYu Xiangning 4470f1702c5SYu Xiangning if ((mp = socopyinuio(uiop, 4480f1702c5SYu Xiangning so->so_proto_props.sopp_maxpsz, 4490f1702c5SYu Xiangning so->so_proto_props.sopp_wroff, 4500f1702c5SYu Xiangning so->so_proto_props.sopp_maxblk, 451bd670b35SErik Nordmark so->so_proto_props.sopp_tail, &error)) == NULL) { 4520f1702c5SYu Xiangning break; 4530f1702c5SYu Xiangning } 4540f1702c5SYu Xiangning ASSERT(uiop->uio_resid >= 0); 4550f1702c5SYu Xiangning 4563e95bd4aSAnders Persson if (so->so_filter_active > 0 && 4573e95bd4aSAnders Persson ((mp = SOF_FILTER_DATA_OUT(so, mp, msg, cr, 4583e95bd4aSAnders Persson &error)) == NULL)) { 4593e95bd4aSAnders Persson if (error != 0) 4603e95bd4aSAnders Persson break; 4613e95bd4aSAnders Persson continue; 4623e95bd4aSAnders Persson } 4630f1702c5SYu Xiangning error = (*so->so_downcalls->sd_send) 4640f1702c5SYu Xiangning (so->so_proto_handle, mp, msg, cr); 4650f1702c5SYu Xiangning if (error != 0) { 4660f1702c5SYu Xiangning /* 4670f1702c5SYu Xiangning * The send failed. We do not have to free the 4680f1702c5SYu Xiangning * mblks, because that is the protocol's 4690f1702c5SYu Xiangning * responsibility. However, uio_resid must 4700f1702c5SYu Xiangning * remain accurate, so adjust that here. 4710f1702c5SYu Xiangning */ 4720f1702c5SYu Xiangning uiop->uio_resid = orig_resid; 4730f1702c5SYu Xiangning break; 4740f1702c5SYu Xiangning } 4750f1702c5SYu Xiangning } 4760f1702c5SYu Xiangning } while (uiop->uio_resid > 0); 4770f1702c5SYu Xiangning 4780f1702c5SYu Xiangning SO_UNBLOCK_FALLBACK(so); 4790f1702c5SYu Xiangning 4800f1702c5SYu Xiangning return (error); 4810f1702c5SYu Xiangning } 4820f1702c5SYu Xiangning 4830f1702c5SYu Xiangning int 4843e95bd4aSAnders Persson so_sendmblk_impl(struct sonode *so, struct nmsghdr *msg, int fflag, 4853e95bd4aSAnders Persson struct cred *cr, mblk_t **mpp, sof_instance_t *fil, 4863e95bd4aSAnders Persson boolean_t fil_inject) 4870f1702c5SYu Xiangning { 4880f1702c5SYu Xiangning int error; 4890f1702c5SYu Xiangning boolean_t dontblock; 4900f1702c5SYu Xiangning size_t size; 4910f1702c5SYu Xiangning mblk_t *mp = *mpp; 4920f1702c5SYu Xiangning 4933e95bd4aSAnders Persson if (so->so_downcalls->sd_send == NULL) 4943e95bd4aSAnders Persson return (EOPNOTSUPP); 4950f1702c5SYu Xiangning 4960f1702c5SYu Xiangning error = 0; 4970f1702c5SYu Xiangning dontblock = (msg->msg_flags & MSG_DONTWAIT) || 4980f1702c5SYu Xiangning (fflag & (FNONBLOCK|FNDELAY)); 4990f1702c5SYu Xiangning size = msgdsize(mp); 5000f1702c5SYu Xiangning 5010f1702c5SYu Xiangning if ((so->so_mode & SM_ATOMIC) && 5020f1702c5SYu Xiangning size > so->so_proto_props.sopp_maxpsz && 5030f1702c5SYu Xiangning so->so_proto_props.sopp_maxpsz != -1) { 5040f1702c5SYu Xiangning SO_UNBLOCK_FALLBACK(so); 5050f1702c5SYu Xiangning return (EMSGSIZE); 5060f1702c5SYu Xiangning } 5070f1702c5SYu Xiangning 5080f1702c5SYu Xiangning while (mp != NULL) { 5090f1702c5SYu Xiangning mblk_t *nmp, *last_mblk; 5100f1702c5SYu Xiangning size_t mlen; 5110f1702c5SYu Xiangning 5120f1702c5SYu Xiangning if (so->so_state & SS_CANTSENDMORE) { 5130f1702c5SYu Xiangning error = EPIPE; 5140f1702c5SYu Xiangning break; 5150f1702c5SYu Xiangning } 5160f1702c5SYu Xiangning if (so->so_error != 0) { 5170f1702c5SYu Xiangning mutex_enter(&so->so_lock); 5180f1702c5SYu Xiangning error = sogeterr(so, B_TRUE); 5190f1702c5SYu Xiangning mutex_exit(&so->so_lock); 5200f1702c5SYu Xiangning if (error != 0) 5210f1702c5SYu Xiangning break; 5220f1702c5SYu Xiangning } 5233e95bd4aSAnders Persson /* Socket filters are not flow controlled */ 5243e95bd4aSAnders Persson if (SO_SND_FLOWCTRLD(so) && !fil_inject) { 5250f1702c5SYu Xiangning /* 5260f1702c5SYu Xiangning * Need to wait until the protocol is ready to receive 5270f1702c5SYu Xiangning * more data for transmission. 5280f1702c5SYu Xiangning */ 5290f1702c5SYu Xiangning if ((error = so_snd_wait_qnotfull(so, dontblock)) != 0) 5300f1702c5SYu Xiangning break; 5310f1702c5SYu Xiangning } 5320f1702c5SYu Xiangning 5330f1702c5SYu Xiangning /* 5340f1702c5SYu Xiangning * We only allow so_maxpsz of data to be sent down to 5350f1702c5SYu Xiangning * the protocol at time. 5360f1702c5SYu Xiangning */ 5370f1702c5SYu Xiangning mlen = MBLKL(mp); 5380f1702c5SYu Xiangning nmp = mp->b_cont; 5390f1702c5SYu Xiangning last_mblk = mp; 5400f1702c5SYu Xiangning while (nmp != NULL) { 5410f1702c5SYu Xiangning mlen += MBLKL(nmp); 5420f1702c5SYu Xiangning if (mlen > so->so_proto_props.sopp_maxpsz) { 5430f1702c5SYu Xiangning last_mblk->b_cont = NULL; 5440f1702c5SYu Xiangning break; 5450f1702c5SYu Xiangning } 5460f1702c5SYu Xiangning last_mblk = nmp; 5470f1702c5SYu Xiangning nmp = nmp->b_cont; 5480f1702c5SYu Xiangning } 5490f1702c5SYu Xiangning 5503e95bd4aSAnders Persson if (so->so_filter_active > 0 && 5513e95bd4aSAnders Persson (mp = SOF_FILTER_DATA_OUT_FROM(so, fil, mp, msg, 5523e95bd4aSAnders Persson cr, &error)) == NULL) { 5533e95bd4aSAnders Persson *mpp = mp = nmp; 5543e95bd4aSAnders Persson if (error != 0) 5553e95bd4aSAnders Persson break; 5563e95bd4aSAnders Persson continue; 5573e95bd4aSAnders Persson } 5580f1702c5SYu Xiangning error = (*so->so_downcalls->sd_send) 5590f1702c5SYu Xiangning (so->so_proto_handle, mp, msg, cr); 5600f1702c5SYu Xiangning if (error != 0) { 5610f1702c5SYu Xiangning /* 5620f1702c5SYu Xiangning * The send failed. The protocol will free the mblks 5630f1702c5SYu Xiangning * that were sent down. Let the caller deal with the 5640f1702c5SYu Xiangning * rest. 5650f1702c5SYu Xiangning */ 5660f1702c5SYu Xiangning *mpp = nmp; 5670f1702c5SYu Xiangning break; 5680f1702c5SYu Xiangning } 5690f1702c5SYu Xiangning 5700f1702c5SYu Xiangning *mpp = mp = nmp; 5710f1702c5SYu Xiangning } 5723e95bd4aSAnders Persson /* Let the filter know whether the protocol is flow controlled */ 5733e95bd4aSAnders Persson if (fil_inject && error == 0 && SO_SND_FLOWCTRLD(so)) 5743e95bd4aSAnders Persson error = ENOSPC; 5753e95bd4aSAnders Persson 5763e95bd4aSAnders Persson return (error); 5773e95bd4aSAnders Persson } 5783e95bd4aSAnders Persson 5793e95bd4aSAnders Persson #pragma inline(so_sendmblk_impl) 5803e95bd4aSAnders Persson 5813e95bd4aSAnders Persson int 5823e95bd4aSAnders Persson so_sendmblk(struct sonode *so, struct nmsghdr *msg, int fflag, 5833e95bd4aSAnders Persson struct cred *cr, mblk_t **mpp) 5843e95bd4aSAnders Persson { 5853e95bd4aSAnders Persson int error; 5863e95bd4aSAnders Persson 5873e95bd4aSAnders Persson SO_BLOCK_FALLBACK(so, SOP_SENDMBLK(so, msg, fflag, cr, mpp)); 5883e95bd4aSAnders Persson 5893e95bd4aSAnders Persson if ((so->so_mode & SM_SENDFILESUPP) == 0) { 5903e95bd4aSAnders Persson SO_UNBLOCK_FALLBACK(so); 5913e95bd4aSAnders Persson return (EOPNOTSUPP); 5923e95bd4aSAnders Persson } 5933e95bd4aSAnders Persson 5943e95bd4aSAnders Persson error = so_sendmblk_impl(so, msg, fflag, cr, mpp, so->so_filter_top, 5953e95bd4aSAnders Persson B_FALSE); 5960f1702c5SYu Xiangning 5970f1702c5SYu Xiangning SO_UNBLOCK_FALLBACK(so); 5980f1702c5SYu Xiangning 5990f1702c5SYu Xiangning return (error); 6000f1702c5SYu Xiangning } 6010f1702c5SYu Xiangning 6020f1702c5SYu Xiangning int 6030f1702c5SYu Xiangning so_shutdown(struct sonode *so, int how, struct cred *cr) 6040f1702c5SYu Xiangning { 6050f1702c5SYu Xiangning int error; 6060f1702c5SYu Xiangning 6070f1702c5SYu Xiangning SO_BLOCK_FALLBACK(so, SOP_SHUTDOWN(so, how, cr)); 6080f1702c5SYu Xiangning 6090f1702c5SYu Xiangning /* 6100f1702c5SYu Xiangning * SunOS 4.X has no check for datagram sockets. 6110f1702c5SYu Xiangning * 5.X checks that it is connected (ENOTCONN) 6120f1702c5SYu Xiangning * X/Open requires that we check the connected state. 6130f1702c5SYu Xiangning */ 6140f1702c5SYu Xiangning if (!(so->so_state & SS_ISCONNECTED)) { 6150f1702c5SYu Xiangning if (!xnet_skip_checks) { 6160f1702c5SYu Xiangning error = ENOTCONN; 6170f1702c5SYu Xiangning if (xnet_check_print) { 6180f1702c5SYu Xiangning printf("sockfs: X/Open shutdown check " 6190f1702c5SYu Xiangning "caused ENOTCONN\n"); 6200f1702c5SYu Xiangning } 6210f1702c5SYu Xiangning } 6220f1702c5SYu Xiangning goto done; 6230f1702c5SYu Xiangning } 6240f1702c5SYu Xiangning 6253e95bd4aSAnders Persson if (so->so_filter_active == 0 || 6263e95bd4aSAnders Persson (error = sof_filter_shutdown(so, &how, cr)) < 0) 6270f1702c5SYu Xiangning error = ((*so->so_downcalls->sd_shutdown)(so->so_proto_handle, 6280f1702c5SYu Xiangning how, cr)); 6290f1702c5SYu Xiangning 6300f1702c5SYu Xiangning /* 6310f1702c5SYu Xiangning * Protocol agreed to shutdown. We need to flush the 6320f1702c5SYu Xiangning * receive buffer if the receive side is being shutdown. 6330f1702c5SYu Xiangning */ 6340f1702c5SYu Xiangning if (error == 0 && how != SHUT_WR) { 6350f1702c5SYu Xiangning mutex_enter(&so->so_lock); 6360f1702c5SYu Xiangning /* wait for active reader to finish */ 6370f1702c5SYu Xiangning (void) so_lock_read(so, 0); 6380f1702c5SYu Xiangning 6390f1702c5SYu Xiangning so_rcv_flush(so); 6400f1702c5SYu Xiangning 6410f1702c5SYu Xiangning so_unlock_read(so); 6420f1702c5SYu Xiangning mutex_exit(&so->so_lock); 6430f1702c5SYu Xiangning } 6440f1702c5SYu Xiangning 6450f1702c5SYu Xiangning done: 6460f1702c5SYu Xiangning SO_UNBLOCK_FALLBACK(so); 6470f1702c5SYu Xiangning return (error); 6480f1702c5SYu Xiangning } 6490f1702c5SYu Xiangning 6500f1702c5SYu Xiangning int 6510f1702c5SYu Xiangning so_getsockname(struct sonode *so, struct sockaddr *addr, 6520f1702c5SYu Xiangning socklen_t *addrlen, struct cred *cr) 6530f1702c5SYu Xiangning { 6540f1702c5SYu Xiangning int error; 6550f1702c5SYu Xiangning 6560f1702c5SYu Xiangning SO_BLOCK_FALLBACK(so, SOP_GETSOCKNAME(so, addr, addrlen, cr)); 6570f1702c5SYu Xiangning 6583e95bd4aSAnders Persson if (so->so_filter_active == 0 || 6593e95bd4aSAnders Persson (error = sof_filter_getsockname(so, addr, addrlen, cr)) < 0) 6600f1702c5SYu Xiangning error = (*so->so_downcalls->sd_getsockname) 6610f1702c5SYu Xiangning (so->so_proto_handle, addr, addrlen, cr); 6620f1702c5SYu Xiangning 6630f1702c5SYu Xiangning SO_UNBLOCK_FALLBACK(so); 6640f1702c5SYu Xiangning return (error); 6650f1702c5SYu Xiangning } 6660f1702c5SYu Xiangning 6670f1702c5SYu Xiangning int 6680f1702c5SYu Xiangning so_getpeername(struct sonode *so, struct sockaddr *addr, 6690f1702c5SYu Xiangning socklen_t *addrlen, boolean_t accept, struct cred *cr) 6700f1702c5SYu Xiangning { 6710f1702c5SYu Xiangning int error; 6720f1702c5SYu Xiangning 6730f1702c5SYu Xiangning SO_BLOCK_FALLBACK(so, SOP_GETPEERNAME(so, addr, addrlen, accept, cr)); 6740f1702c5SYu Xiangning 6750f1702c5SYu Xiangning if (accept) { 6760f1702c5SYu Xiangning error = (*so->so_downcalls->sd_getpeername) 6770f1702c5SYu Xiangning (so->so_proto_handle, addr, addrlen, cr); 6780f1702c5SYu Xiangning } else if (!(so->so_state & SS_ISCONNECTED)) { 6790f1702c5SYu Xiangning error = ENOTCONN; 6800f1702c5SYu Xiangning } else if ((so->so_state & SS_CANTSENDMORE) && !xnet_skip_checks) { 6810f1702c5SYu Xiangning /* Added this check for X/Open */ 6820f1702c5SYu Xiangning error = EINVAL; 6830f1702c5SYu Xiangning if (xnet_check_print) { 6840f1702c5SYu Xiangning printf("sockfs: X/Open getpeername check => EINVAL\n"); 6850f1702c5SYu Xiangning } 6863e95bd4aSAnders Persson } else if (so->so_filter_active == 0 || 6873e95bd4aSAnders Persson (error = sof_filter_getpeername(so, addr, addrlen, cr)) < 0) { 6880f1702c5SYu Xiangning error = (*so->so_downcalls->sd_getpeername) 6890f1702c5SYu Xiangning (so->so_proto_handle, addr, addrlen, cr); 6900f1702c5SYu Xiangning } 6910f1702c5SYu Xiangning 6920f1702c5SYu Xiangning SO_UNBLOCK_FALLBACK(so); 6930f1702c5SYu Xiangning return (error); 6940f1702c5SYu Xiangning } 6950f1702c5SYu Xiangning 6960f1702c5SYu Xiangning int 6970f1702c5SYu Xiangning so_getsockopt(struct sonode *so, int level, int option_name, 6980f1702c5SYu Xiangning void *optval, socklen_t *optlenp, int flags, struct cred *cr) 6990f1702c5SYu Xiangning { 7000f1702c5SYu Xiangning int error = 0; 7010f1702c5SYu Xiangning 7023e95bd4aSAnders Persson if (level == SOL_FILTER) 7033e95bd4aSAnders Persson return (sof_getsockopt(so, option_name, optval, optlenp, cr)); 7043e95bd4aSAnders Persson 7050f1702c5SYu Xiangning SO_BLOCK_FALLBACK(so, 7060f1702c5SYu Xiangning SOP_GETSOCKOPT(so, level, option_name, optval, optlenp, flags, cr)); 7070f1702c5SYu Xiangning 7083e95bd4aSAnders Persson if ((so->so_filter_active == 0 || 7093e95bd4aSAnders Persson (error = sof_filter_getsockopt(so, level, option_name, optval, 7103e95bd4aSAnders Persson optlenp, cr)) < 0) && 7113e95bd4aSAnders Persson (error = socket_getopt_common(so, level, option_name, optval, 7123e95bd4aSAnders Persson optlenp, flags)) < 0) { 7130f1702c5SYu Xiangning error = (*so->so_downcalls->sd_getsockopt) 7140f1702c5SYu Xiangning (so->so_proto_handle, level, option_name, optval, optlenp, 7150f1702c5SYu Xiangning cr); 7160f1702c5SYu Xiangning if (error == ENOPROTOOPT) { 7170f1702c5SYu Xiangning if (level == SOL_SOCKET) { 7180f1702c5SYu Xiangning /* 7190f1702c5SYu Xiangning * If a protocol does not support a particular 7200f1702c5SYu Xiangning * socket option, set can fail (not allowed) 7210f1702c5SYu Xiangning * but get can not fail. This is the previous 7220f1702c5SYu Xiangning * sockfs bahvior. 7230f1702c5SYu Xiangning */ 7240f1702c5SYu Xiangning switch (option_name) { 7250f1702c5SYu Xiangning case SO_LINGER: 7260f1702c5SYu Xiangning if (*optlenp < (t_uscalar_t) 7270f1702c5SYu Xiangning sizeof (struct linger)) { 7280f1702c5SYu Xiangning error = EINVAL; 7290f1702c5SYu Xiangning break; 7300f1702c5SYu Xiangning } 7310f1702c5SYu Xiangning error = 0; 7320f1702c5SYu Xiangning bzero(optval, sizeof (struct linger)); 7330f1702c5SYu Xiangning *optlenp = sizeof (struct linger); 7340f1702c5SYu Xiangning break; 7350f1702c5SYu Xiangning case SO_RCVTIMEO: 7360f1702c5SYu Xiangning case SO_SNDTIMEO: 7370f1702c5SYu Xiangning if (*optlenp < (t_uscalar_t) 7380f1702c5SYu Xiangning sizeof (struct timeval)) { 7390f1702c5SYu Xiangning error = EINVAL; 7400f1702c5SYu Xiangning break; 7410f1702c5SYu Xiangning } 7420f1702c5SYu Xiangning error = 0; 7430f1702c5SYu Xiangning bzero(optval, sizeof (struct timeval)); 7440f1702c5SYu Xiangning *optlenp = sizeof (struct timeval); 7450f1702c5SYu Xiangning break; 7460f1702c5SYu Xiangning case SO_SND_BUFINFO: 7470f1702c5SYu Xiangning if (*optlenp < (t_uscalar_t) 7480f1702c5SYu Xiangning sizeof (struct so_snd_bufinfo)) { 7490f1702c5SYu Xiangning error = EINVAL; 7500f1702c5SYu Xiangning break; 7510f1702c5SYu Xiangning } 7520f1702c5SYu Xiangning error = 0; 7530f1702c5SYu Xiangning bzero(optval, 7540f1702c5SYu Xiangning sizeof (struct so_snd_bufinfo)); 7550f1702c5SYu Xiangning *optlenp = 7560f1702c5SYu Xiangning sizeof (struct so_snd_bufinfo); 7570f1702c5SYu Xiangning break; 7580f1702c5SYu Xiangning case SO_DEBUG: 7590f1702c5SYu Xiangning case SO_REUSEADDR: 760*78918900SArne Jansen case SO_REUSEPORT: 7610f1702c5SYu Xiangning case SO_KEEPALIVE: 7620f1702c5SYu Xiangning case SO_DONTROUTE: 7630f1702c5SYu Xiangning case SO_BROADCAST: 7640f1702c5SYu Xiangning case SO_USELOOPBACK: 7650f1702c5SYu Xiangning case SO_OOBINLINE: 7660f1702c5SYu Xiangning case SO_DGRAM_ERRIND: 7670f1702c5SYu Xiangning case SO_SNDBUF: 7680f1702c5SYu Xiangning case SO_RCVBUF: 7690f1702c5SYu Xiangning error = 0; 7700f1702c5SYu Xiangning *((int32_t *)optval) = 0; 7710f1702c5SYu Xiangning *optlenp = sizeof (int32_t); 7720f1702c5SYu Xiangning break; 7730f1702c5SYu Xiangning default: 7740f1702c5SYu Xiangning break; 7750f1702c5SYu Xiangning } 7760f1702c5SYu Xiangning } 7770f1702c5SYu Xiangning } 7780f1702c5SYu Xiangning } 7790f1702c5SYu Xiangning 7800f1702c5SYu Xiangning SO_UNBLOCK_FALLBACK(so); 7810f1702c5SYu Xiangning return (error); 7820f1702c5SYu Xiangning } 7830f1702c5SYu Xiangning 7840f1702c5SYu Xiangning int 7850f1702c5SYu Xiangning so_setsockopt(struct sonode *so, int level, int option_name, 7860f1702c5SYu Xiangning const void *optval, socklen_t optlen, struct cred *cr) 7870f1702c5SYu Xiangning { 7880f1702c5SYu Xiangning int error = 0; 7893986c91eSanders struct timeval tl; 7903986c91eSanders const void *opt = optval; 7910f1702c5SYu Xiangning 7923e95bd4aSAnders Persson if (level == SOL_FILTER) 7933e95bd4aSAnders Persson return (sof_setsockopt(so, option_name, optval, optlen, cr)); 7943e95bd4aSAnders Persson 7950f1702c5SYu Xiangning SO_BLOCK_FALLBACK(so, 7960f1702c5SYu Xiangning SOP_SETSOCKOPT(so, level, option_name, optval, optlen, cr)); 7970f1702c5SYu Xiangning 7980f1702c5SYu Xiangning /* X/Open requires this check */ 7990f1702c5SYu Xiangning if (so->so_state & SS_CANTSENDMORE && !xnet_skip_checks) { 8000f1702c5SYu Xiangning SO_UNBLOCK_FALLBACK(so); 8010f1702c5SYu Xiangning if (xnet_check_print) 8020f1702c5SYu Xiangning printf("sockfs: X/Open setsockopt check => EINVAL\n"); 8030f1702c5SYu Xiangning return (EINVAL); 8040f1702c5SYu Xiangning } 8050f1702c5SYu Xiangning 8063e95bd4aSAnders Persson if (so->so_filter_active > 0 && 8073e95bd4aSAnders Persson (error = sof_filter_setsockopt(so, level, option_name, 8083e95bd4aSAnders Persson (void *)optval, &optlen, cr)) >= 0) 8093e95bd4aSAnders Persson goto done; 8103e95bd4aSAnders Persson 811a5adac4dSYu Xiangning if (level == SOL_SOCKET) { 812a5adac4dSYu Xiangning switch (option_name) { 813a5adac4dSYu Xiangning case SO_RCVTIMEO: 814a5adac4dSYu Xiangning case SO_SNDTIMEO: { 81534dfe683Sshenjian /* 81634dfe683Sshenjian * We pass down these two options to protocol in order 81734dfe683Sshenjian * to support some third part protocols which need to 81834dfe683Sshenjian * know them. For those protocols which don't care 81934dfe683Sshenjian * these two options, simply return 0. 82034dfe683Sshenjian */ 8210f1702c5SYu Xiangning clock_t t_usec; 8220f1702c5SYu Xiangning 823e5083e81Sshenjian if (get_udatamodel() == DATAMODEL_NONE || 824e5083e81Sshenjian get_udatamodel() == DATAMODEL_NATIVE) { 82522238f73Sshenjian if (optlen != sizeof (struct timeval)) { 82622238f73Sshenjian error = EINVAL; 82722238f73Sshenjian goto done; 8280f1702c5SYu Xiangning } 82922238f73Sshenjian bcopy((struct timeval *)optval, &tl, 83022238f73Sshenjian sizeof (struct timeval)); 83122238f73Sshenjian } else { 83222238f73Sshenjian if (optlen != sizeof (struct timeval32)) { 83322238f73Sshenjian error = EINVAL; 83422238f73Sshenjian goto done; 83522238f73Sshenjian } 83622238f73Sshenjian TIMEVAL32_TO_TIMEVAL(&tl, 83722238f73Sshenjian (struct timeval32 *)optval); 83822238f73Sshenjian } 8393986c91eSanders opt = &tl; 8403986c91eSanders optlen = sizeof (tl); 84122238f73Sshenjian t_usec = tl.tv_sec * 1000 * 1000 + tl.tv_usec; 8420f1702c5SYu Xiangning mutex_enter(&so->so_lock); 8430f1702c5SYu Xiangning if (option_name == SO_RCVTIMEO) 8440f1702c5SYu Xiangning so->so_rcvtimeo = drv_usectohz(t_usec); 8450f1702c5SYu Xiangning else 8460f1702c5SYu Xiangning so->so_sndtimeo = drv_usectohz(t_usec); 8470f1702c5SYu Xiangning mutex_exit(&so->so_lock); 84834dfe683Sshenjian break; 8490f1702c5SYu Xiangning } 850a5adac4dSYu Xiangning case SO_RCVBUF: 851a5adac4dSYu Xiangning /* 852a5adac4dSYu Xiangning * XXX XPG 4.2 applications retrieve SO_RCVBUF from 853a5adac4dSYu Xiangning * sockfs since the transport might adjust the value 854a5adac4dSYu Xiangning * and not return exactly what was set by the 855a5adac4dSYu Xiangning * application. 856a5adac4dSYu Xiangning */ 857a5adac4dSYu Xiangning so->so_xpg_rcvbuf = *(int32_t *)optval; 858a5adac4dSYu Xiangning break; 859a5adac4dSYu Xiangning } 860a5adac4dSYu Xiangning } 8610f1702c5SYu Xiangning error = (*so->so_downcalls->sd_setsockopt) 8623986c91eSanders (so->so_proto_handle, level, option_name, opt, optlen, cr); 86322238f73Sshenjian done: 8640f1702c5SYu Xiangning SO_UNBLOCK_FALLBACK(so); 8650f1702c5SYu Xiangning return (error); 8660f1702c5SYu Xiangning } 8670f1702c5SYu Xiangning 8680f1702c5SYu Xiangning int 8690f1702c5SYu Xiangning so_ioctl(struct sonode *so, int cmd, intptr_t arg, int mode, 8700f1702c5SYu Xiangning struct cred *cr, int32_t *rvalp) 8710f1702c5SYu Xiangning { 8720f1702c5SYu Xiangning int error = 0; 8730f1702c5SYu Xiangning 8740f1702c5SYu Xiangning SO_BLOCK_FALLBACK(so, SOP_IOCTL(so, cmd, arg, mode, cr, rvalp)); 8750f1702c5SYu Xiangning 8760f1702c5SYu Xiangning /* 8770f1702c5SYu Xiangning * If there is a pending error, return error 8780f1702c5SYu Xiangning * This can happen if a non blocking operation caused an error. 8790f1702c5SYu Xiangning */ 8800f1702c5SYu Xiangning if (so->so_error != 0) { 8810f1702c5SYu Xiangning mutex_enter(&so->so_lock); 8820f1702c5SYu Xiangning error = sogeterr(so, B_TRUE); 8830f1702c5SYu Xiangning mutex_exit(&so->so_lock); 8840f1702c5SYu Xiangning if (error != 0) 8850f1702c5SYu Xiangning goto done; 8860f1702c5SYu Xiangning } 8870f1702c5SYu Xiangning 8880f1702c5SYu Xiangning /* 8890f1702c5SYu Xiangning * calling strioc can result in the socket falling back to TPI, 8900f1702c5SYu Xiangning * if that is supported. 8910f1702c5SYu Xiangning */ 8923e95bd4aSAnders Persson if ((so->so_filter_active == 0 || 8933e95bd4aSAnders Persson (error = sof_filter_ioctl(so, cmd, arg, mode, 8943e95bd4aSAnders Persson rvalp, cr)) < 0) && 8953e95bd4aSAnders Persson (error = socket_ioctl_common(so, cmd, arg, mode, cr, rvalp)) < 0 && 8960f1702c5SYu Xiangning (error = socket_strioc_common(so, cmd, arg, mode, cr, rvalp)) < 0) { 8970f1702c5SYu Xiangning error = (*so->so_downcalls->sd_ioctl)(so->so_proto_handle, 8980f1702c5SYu Xiangning cmd, arg, mode, rvalp, cr); 8990f1702c5SYu Xiangning } 9000f1702c5SYu Xiangning 9010f1702c5SYu Xiangning done: 9020f1702c5SYu Xiangning SO_UNBLOCK_FALLBACK(so); 9030f1702c5SYu Xiangning 9040f1702c5SYu Xiangning return (error); 9050f1702c5SYu Xiangning } 9060f1702c5SYu Xiangning 9070f1702c5SYu Xiangning int 9080f1702c5SYu Xiangning so_poll(struct sonode *so, short events, int anyyet, short *reventsp, 9090f1702c5SYu Xiangning struct pollhead **phpp) 9100f1702c5SYu Xiangning { 91168846fd0SBryan Cantrill int state = so->so_state, mask; 9120f1702c5SYu Xiangning *reventsp = 0; 9130f1702c5SYu Xiangning 914af89d820SRao Shoaib /* 915af89d820SRao Shoaib * In sockets the errors are represented as input/output events 916af89d820SRao Shoaib */ 9170f1702c5SYu Xiangning if (so->so_error != 0 && 9180f1702c5SYu Xiangning ((POLLIN|POLLRDNORM|POLLOUT) & events) != 0) { 9190f1702c5SYu Xiangning *reventsp = (POLLIN|POLLRDNORM|POLLOUT) & events; 9200f1702c5SYu Xiangning return (0); 9210f1702c5SYu Xiangning } 9220f1702c5SYu Xiangning 9230f1702c5SYu Xiangning /* 924af89d820SRao Shoaib * If the socket is in a state where it can send data 925af89d820SRao Shoaib * turn on POLLWRBAND and POLLOUT events. 9260f1702c5SYu Xiangning */ 927af89d820SRao Shoaib if ((so->so_mode & SM_CONNREQUIRED) == 0 || (state & SS_ISCONNECTED)) { 928af89d820SRao Shoaib /* 929af89d820SRao Shoaib * out of band data is allowed even if the connection 930af89d820SRao Shoaib * is flow controlled 931af89d820SRao Shoaib */ 932af89d820SRao Shoaib *reventsp |= POLLWRBAND & events; 9333e95bd4aSAnders Persson if (!SO_SND_FLOWCTRLD(so)) { 934af89d820SRao Shoaib /* 935af89d820SRao Shoaib * As long as there is buffer to send data 936af89d820SRao Shoaib * turn on POLLOUT events 937af89d820SRao Shoaib */ 9380f1702c5SYu Xiangning *reventsp |= POLLOUT & events; 9390f1702c5SYu Xiangning } 940af89d820SRao Shoaib } 9410f1702c5SYu Xiangning 9420f1702c5SYu Xiangning /* 9430f1702c5SYu Xiangning * Turn on POLLIN whenever there is data on the receive queue, 9440f1702c5SYu Xiangning * or the socket is in a state where no more data will be received. 9450f1702c5SYu Xiangning * Also, if the socket is accepting connections, flip the bit if 9460f1702c5SYu Xiangning * there is something on the queue. 947f0267584Sanders * 948f0267584Sanders * We do an initial check for events without holding locks. However, 949f0267584Sanders * if there are no event available, then we redo the check for POLLIN 950f0267584Sanders * events under the lock. 9510f1702c5SYu Xiangning */ 9520f1702c5SYu Xiangning 9530f1702c5SYu Xiangning /* Pending connections */ 9543e95bd4aSAnders Persson if (!list_is_empty(&so->so_acceptq_list)) 9550f1702c5SYu Xiangning *reventsp |= (POLLIN|POLLRDNORM) & events; 9560f1702c5SYu Xiangning 957a5eb7107SBryan Cantrill /* 958a5eb7107SBryan Cantrill * If we're looking for POLLRDHUP, indicate it if we have sent the 959a5eb7107SBryan Cantrill * last rx signal for the socket. 960a5eb7107SBryan Cantrill */ 961a5eb7107SBryan Cantrill if ((events & POLLRDHUP) && (state & SS_SENTLASTREADSIG)) 962a5eb7107SBryan Cantrill *reventsp |= POLLRDHUP; 963a5eb7107SBryan Cantrill 9640f1702c5SYu Xiangning /* Data */ 9650f1702c5SYu Xiangning /* so_downcalls is null for sctp */ 9660f1702c5SYu Xiangning if (so->so_downcalls != NULL && so->so_downcalls->sd_poll != NULL) { 9670f1702c5SYu Xiangning *reventsp |= (*so->so_downcalls->sd_poll) 9680f1702c5SYu Xiangning (so->so_proto_handle, events & SO_PROTO_POLLEV, anyyet, 9690f1702c5SYu Xiangning CRED()) & events; 9700f1702c5SYu Xiangning ASSERT((*reventsp & ~events) == 0); 9710f1702c5SYu Xiangning /* do not recheck events */ 9720f1702c5SYu Xiangning events &= ~SO_PROTO_POLLEV; 9730f1702c5SYu Xiangning } else { 9740f1702c5SYu Xiangning if (SO_HAVE_DATA(so)) 9750f1702c5SYu Xiangning *reventsp |= (POLLIN|POLLRDNORM) & events; 9760f1702c5SYu Xiangning 9770f1702c5SYu Xiangning /* Urgent data */ 978af89d820SRao Shoaib if ((state & SS_OOBPEND) != 0) { 979af89d820SRao Shoaib *reventsp |= (POLLRDBAND | POLLPRI) & events; 980af89d820SRao Shoaib } 98168846fd0SBryan Cantrill 98268846fd0SBryan Cantrill /* 98368846fd0SBryan Cantrill * If the socket has become disconnected, we set POLLHUP. 98468846fd0SBryan Cantrill * Note that if we are in this state, we will have set POLLIN 98568846fd0SBryan Cantrill * (SO_HAVE_DATA() is true on a disconnected socket), but not 98668846fd0SBryan Cantrill * POLLOUT (SS_ISCONNECTED is false). This is in keeping with 98768846fd0SBryan Cantrill * the semantics of POLLHUP, which is defined to be mutually 98868846fd0SBryan Cantrill * exclusive with respect to POLLOUT but not POLLIN. We are 98968846fd0SBryan Cantrill * therefore setting POLLHUP primarily for the benefit of 99068846fd0SBryan Cantrill * those not polling on POLLIN, as they have no other way of 99168846fd0SBryan Cantrill * knowing that the socket has been disconnected. 99268846fd0SBryan Cantrill */ 99368846fd0SBryan Cantrill mask = SS_SENTLASTREADSIG | SS_SENTLASTWRITESIG; 99468846fd0SBryan Cantrill 99568846fd0SBryan Cantrill if ((state & (mask | SS_ISCONNECTED)) == mask) 99668846fd0SBryan Cantrill *reventsp |= POLLHUP; 9970f1702c5SYu Xiangning } 9980f1702c5SYu Xiangning 999a5eb7107SBryan Cantrill if ((!*reventsp && !anyyet) || (events & POLLET)) { 10000f1702c5SYu Xiangning /* Check for read events again, but this time under lock */ 10010f1702c5SYu Xiangning if (events & (POLLIN|POLLRDNORM)) { 10020f1702c5SYu Xiangning mutex_enter(&so->so_lock); 10033e95bd4aSAnders Persson if (SO_HAVE_DATA(so) || 10043e95bd4aSAnders Persson !list_is_empty(&so->so_acceptq_list)) { 1005a5eb7107SBryan Cantrill if (events & POLLET) { 1006a5eb7107SBryan Cantrill so->so_pollev |= SO_POLLEV_IN; 1007a5eb7107SBryan Cantrill *phpp = &so->so_poll_list; 1008a5eb7107SBryan Cantrill } 1009a5eb7107SBryan Cantrill 10100f1702c5SYu Xiangning mutex_exit(&so->so_lock); 10110f1702c5SYu Xiangning *reventsp |= (POLLIN|POLLRDNORM) & events; 1012a5eb7107SBryan Cantrill 10130f1702c5SYu Xiangning return (0); 10140f1702c5SYu Xiangning } else { 10150f1702c5SYu Xiangning so->so_pollev |= SO_POLLEV_IN; 10160f1702c5SYu Xiangning mutex_exit(&so->so_lock); 10170f1702c5SYu Xiangning } 10180f1702c5SYu Xiangning } 10190f1702c5SYu Xiangning *phpp = &so->so_poll_list; 10200f1702c5SYu Xiangning } 10210f1702c5SYu Xiangning return (0); 10220f1702c5SYu Xiangning } 10230f1702c5SYu Xiangning 10240f1702c5SYu Xiangning /* 10250f1702c5SYu Xiangning * Generic Upcalls 10260f1702c5SYu Xiangning */ 10270f1702c5SYu Xiangning void 10280f1702c5SYu Xiangning so_connected(sock_upper_handle_t sock_handle, sock_connid_t id, 10290f1702c5SYu Xiangning cred_t *peer_cred, pid_t peer_cpid) 10300f1702c5SYu Xiangning { 10310f1702c5SYu Xiangning struct sonode *so = (struct sonode *)sock_handle; 10320f1702c5SYu Xiangning 10330f1702c5SYu Xiangning mutex_enter(&so->so_lock); 10340f1702c5SYu Xiangning ASSERT(so->so_proto_handle != NULL); 10350f1702c5SYu Xiangning 10360f1702c5SYu Xiangning if (peer_cred != NULL) { 10370f1702c5SYu Xiangning if (so->so_peercred != NULL) 10380f1702c5SYu Xiangning crfree(so->so_peercred); 10390f1702c5SYu Xiangning crhold(peer_cred); 10400f1702c5SYu Xiangning so->so_peercred = peer_cred; 10410f1702c5SYu Xiangning so->so_cpid = peer_cpid; 10420f1702c5SYu Xiangning } 10430f1702c5SYu Xiangning 10440f1702c5SYu Xiangning so->so_proto_connid = id; 10450f1702c5SYu Xiangning soisconnected(so); 10460f1702c5SYu Xiangning /* 10470f1702c5SYu Xiangning * Wake ones who're waiting for conn to become established. 10480f1702c5SYu Xiangning */ 10490f1702c5SYu Xiangning so_notify_connected(so); 10500f1702c5SYu Xiangning } 10510f1702c5SYu Xiangning 10520f1702c5SYu Xiangning int 10530f1702c5SYu Xiangning so_disconnected(sock_upper_handle_t sock_handle, sock_connid_t id, int error) 10540f1702c5SYu Xiangning { 10550f1702c5SYu Xiangning struct sonode *so = (struct sonode *)sock_handle; 10563e95bd4aSAnders Persson boolean_t connect_failed; 10570f1702c5SYu Xiangning 10580f1702c5SYu Xiangning mutex_enter(&so->so_lock); 105968846fd0SBryan Cantrill 106068846fd0SBryan Cantrill /* 106168846fd0SBryan Cantrill * If we aren't currently connected, then this isn't a disconnect but 106268846fd0SBryan Cantrill * rather a failure to connect. 106368846fd0SBryan Cantrill */ 106468846fd0SBryan Cantrill connect_failed = !(so->so_state & SS_ISCONNECTED); 106568846fd0SBryan Cantrill 10660f1702c5SYu Xiangning so->so_proto_connid = id; 10670f1702c5SYu Xiangning soisdisconnected(so, error); 10683e95bd4aSAnders Persson so_notify_disconnected(so, connect_failed, error); 10690f1702c5SYu Xiangning 10700f1702c5SYu Xiangning return (0); 10710f1702c5SYu Xiangning } 10720f1702c5SYu Xiangning 10730f1702c5SYu Xiangning void 10740f1702c5SYu Xiangning so_opctl(sock_upper_handle_t sock_handle, sock_opctl_action_t action, 10750f1702c5SYu Xiangning uintptr_t arg) 10760f1702c5SYu Xiangning { 10770f1702c5SYu Xiangning struct sonode *so = (struct sonode *)sock_handle; 10780f1702c5SYu Xiangning 10790f1702c5SYu Xiangning switch (action) { 10800f1702c5SYu Xiangning case SOCK_OPCTL_SHUT_SEND: 10810f1702c5SYu Xiangning mutex_enter(&so->so_lock); 10820f1702c5SYu Xiangning socantsendmore(so); 10830f1702c5SYu Xiangning so_notify_disconnecting(so); 10840f1702c5SYu Xiangning break; 10850f1702c5SYu Xiangning case SOCK_OPCTL_SHUT_RECV: { 10860f1702c5SYu Xiangning mutex_enter(&so->so_lock); 10870f1702c5SYu Xiangning socantrcvmore(so); 10880f1702c5SYu Xiangning so_notify_eof(so); 10890f1702c5SYu Xiangning break; 10900f1702c5SYu Xiangning } 10910f1702c5SYu Xiangning case SOCK_OPCTL_ENAB_ACCEPT: 10920f1702c5SYu Xiangning mutex_enter(&so->so_lock); 10930f1702c5SYu Xiangning so->so_state |= SS_ACCEPTCONN; 10940f1702c5SYu Xiangning so->so_backlog = (unsigned int)arg; 10953e95bd4aSAnders Persson /* 10963e95bd4aSAnders Persson * The protocol can stop generating newconn upcalls when 10973e95bd4aSAnders Persson * the backlog is full, so to make sure the listener does 10983e95bd4aSAnders Persson * not end up with a queue full of deferred connections 10993e95bd4aSAnders Persson * we reduce the backlog by one. Thus the listener will 11003e95bd4aSAnders Persson * start closing deferred connections before the backlog 11013e95bd4aSAnders Persson * is full. 11023e95bd4aSAnders Persson */ 11033e95bd4aSAnders Persson if (so->so_filter_active > 0) 11043e95bd4aSAnders Persson so->so_backlog = MAX(1, so->so_backlog - 1); 11050f1702c5SYu Xiangning mutex_exit(&so->so_lock); 11060f1702c5SYu Xiangning break; 11070f1702c5SYu Xiangning default: 11080f1702c5SYu Xiangning ASSERT(0); 11090f1702c5SYu Xiangning break; 11100f1702c5SYu Xiangning } 11110f1702c5SYu Xiangning } 11120f1702c5SYu Xiangning 11130f1702c5SYu Xiangning void 11140f1702c5SYu Xiangning so_txq_full(sock_upper_handle_t sock_handle, boolean_t qfull) 11150f1702c5SYu Xiangning { 11160f1702c5SYu Xiangning struct sonode *so = (struct sonode *)sock_handle; 11170f1702c5SYu Xiangning 11180f1702c5SYu Xiangning if (qfull) { 11190f1702c5SYu Xiangning so_snd_qfull(so); 11200f1702c5SYu Xiangning } else { 11210f1702c5SYu Xiangning so_snd_qnotfull(so); 11220f1702c5SYu Xiangning mutex_enter(&so->so_lock); 11233e95bd4aSAnders Persson /* so_notify_writable drops so_lock */ 11240f1702c5SYu Xiangning so_notify_writable(so); 11250f1702c5SYu Xiangning } 11260f1702c5SYu Xiangning } 11270f1702c5SYu Xiangning 11280f1702c5SYu Xiangning sock_upper_handle_t 11290f1702c5SYu Xiangning so_newconn(sock_upper_handle_t parenthandle, 11300f1702c5SYu Xiangning sock_lower_handle_t proto_handle, sock_downcalls_t *sock_downcalls, 11310f1702c5SYu Xiangning struct cred *peer_cred, pid_t peer_cpid, sock_upcalls_t **sock_upcallsp) 11320f1702c5SYu Xiangning { 11330f1702c5SYu Xiangning struct sonode *so = (struct sonode *)parenthandle; 11340f1702c5SYu Xiangning struct sonode *nso; 11350f1702c5SYu Xiangning int error; 11360f1702c5SYu Xiangning 11370f1702c5SYu Xiangning ASSERT(proto_handle != NULL); 11380f1702c5SYu Xiangning 11390f1702c5SYu Xiangning if ((so->so_state & SS_ACCEPTCONN) == 0 || 11403e95bd4aSAnders Persson (so->so_acceptq_len >= so->so_backlog && 11413e95bd4aSAnders Persson (so->so_filter_active == 0 || !sof_sonode_drop_deferred(so)))) { 11420f1702c5SYu Xiangning return (NULL); 11433e95bd4aSAnders Persson } 11440f1702c5SYu Xiangning 11450f1702c5SYu Xiangning nso = socket_newconn(so, proto_handle, sock_downcalls, SOCKET_NOSLEEP, 11460f1702c5SYu Xiangning &error); 11470f1702c5SYu Xiangning if (nso == NULL) 11480f1702c5SYu Xiangning return (NULL); 11490f1702c5SYu Xiangning 11500f1702c5SYu Xiangning if (peer_cred != NULL) { 11510f1702c5SYu Xiangning crhold(peer_cred); 11520f1702c5SYu Xiangning nso->so_peercred = peer_cred; 11530f1702c5SYu Xiangning nso->so_cpid = peer_cpid; 11540f1702c5SYu Xiangning } 11553e95bd4aSAnders Persson nso->so_listener = so; 11560f1702c5SYu Xiangning 1157d68ef20eSAnders Persson /* 1158d68ef20eSAnders Persson * The new socket (nso), proto_handle and sock_upcallsp are all 1159d68ef20eSAnders Persson * valid at this point. But as soon as nso is placed in the accept 1160d68ef20eSAnders Persson * queue that can no longer be assumed (since an accept() thread may 1161d68ef20eSAnders Persson * pull it off the queue and close the socket). 1162d68ef20eSAnders Persson */ 1163d68ef20eSAnders Persson *sock_upcallsp = &so_upcalls; 1164d68ef20eSAnders Persson 11653e95bd4aSAnders Persson mutex_enter(&so->so_acceptq_lock); 11663e95bd4aSAnders Persson if (so->so_state & (SS_CLOSING|SS_FALLBACK_PENDING|SS_FALLBACK_COMP)) { 11673e95bd4aSAnders Persson mutex_exit(&so->so_acceptq_lock); 11683e95bd4aSAnders Persson ASSERT(nso->so_count == 1); 11693e95bd4aSAnders Persson nso->so_count--; 1170b1cd7879SAnders Persson nso->so_listener = NULL; 11713e95bd4aSAnders Persson /* drop proto ref */ 11723e95bd4aSAnders Persson VN_RELE(SOTOV(nso)); 11733e95bd4aSAnders Persson socket_destroy(nso); 11743e95bd4aSAnders Persson return (NULL); 11753e95bd4aSAnders Persson } else { 11763e95bd4aSAnders Persson so->so_acceptq_len++; 11773e95bd4aSAnders Persson if (nso->so_state & SS_FIL_DEFER) { 11783e95bd4aSAnders Persson list_insert_tail(&so->so_acceptq_defer, nso); 11793e95bd4aSAnders Persson mutex_exit(&so->so_acceptq_lock); 11803e95bd4aSAnders Persson } else { 11813e95bd4aSAnders Persson list_insert_tail(&so->so_acceptq_list, nso); 11823e95bd4aSAnders Persson cv_signal(&so->so_acceptq_cv); 11833e95bd4aSAnders Persson mutex_exit(&so->so_acceptq_lock); 11840f1702c5SYu Xiangning mutex_enter(&so->so_lock); 11850f1702c5SYu Xiangning so_notify_newconn(so); 11863e95bd4aSAnders Persson } 11870f1702c5SYu Xiangning 11880f1702c5SYu Xiangning return ((sock_upper_handle_t)nso); 11890f1702c5SYu Xiangning } 11903e95bd4aSAnders Persson } 11910f1702c5SYu Xiangning 11920f1702c5SYu Xiangning void 11930f1702c5SYu Xiangning so_set_prop(sock_upper_handle_t sock_handle, struct sock_proto_props *soppp) 11940f1702c5SYu Xiangning { 11950f1702c5SYu Xiangning struct sonode *so; 11960f1702c5SYu Xiangning 11970f1702c5SYu Xiangning so = (struct sonode *)sock_handle; 11980f1702c5SYu Xiangning 11990f1702c5SYu Xiangning mutex_enter(&so->so_lock); 12000f1702c5SYu Xiangning 12010f1702c5SYu Xiangning if (soppp->sopp_flags & SOCKOPT_MAXBLK) 12020f1702c5SYu Xiangning so->so_proto_props.sopp_maxblk = soppp->sopp_maxblk; 12030f1702c5SYu Xiangning if (soppp->sopp_flags & SOCKOPT_WROFF) 12040f1702c5SYu Xiangning so->so_proto_props.sopp_wroff = soppp->sopp_wroff; 12050f1702c5SYu Xiangning if (soppp->sopp_flags & SOCKOPT_TAIL) 12060f1702c5SYu Xiangning so->so_proto_props.sopp_tail = soppp->sopp_tail; 12070f1702c5SYu Xiangning if (soppp->sopp_flags & SOCKOPT_RCVHIWAT) 12080f1702c5SYu Xiangning so->so_proto_props.sopp_rxhiwat = soppp->sopp_rxhiwat; 12090f1702c5SYu Xiangning if (soppp->sopp_flags & SOCKOPT_RCVLOWAT) 12100f1702c5SYu Xiangning so->so_proto_props.sopp_rxlowat = soppp->sopp_rxlowat; 12110f1702c5SYu Xiangning if (soppp->sopp_flags & SOCKOPT_MAXPSZ) 12120f1702c5SYu Xiangning so->so_proto_props.sopp_maxpsz = soppp->sopp_maxpsz; 12130f1702c5SYu Xiangning if (soppp->sopp_flags & SOCKOPT_MINPSZ) 12140f1702c5SYu Xiangning so->so_proto_props.sopp_minpsz = soppp->sopp_minpsz; 12150f1702c5SYu Xiangning if (soppp->sopp_flags & SOCKOPT_ZCOPY) { 12160f1702c5SYu Xiangning if (soppp->sopp_zcopyflag & ZCVMSAFE) { 12170f1702c5SYu Xiangning so->so_proto_props.sopp_zcopyflag |= STZCVMSAFE; 12180f1702c5SYu Xiangning so->so_proto_props.sopp_zcopyflag &= ~STZCVMUNSAFE; 12190f1702c5SYu Xiangning } else if (soppp->sopp_zcopyflag & ZCVMUNSAFE) { 12200f1702c5SYu Xiangning so->so_proto_props.sopp_zcopyflag |= STZCVMUNSAFE; 12210f1702c5SYu Xiangning so->so_proto_props.sopp_zcopyflag &= ~STZCVMSAFE; 12220f1702c5SYu Xiangning } 12230f1702c5SYu Xiangning 12240f1702c5SYu Xiangning if (soppp->sopp_zcopyflag & COPYCACHED) { 12250f1702c5SYu Xiangning so->so_proto_props.sopp_zcopyflag |= STRCOPYCACHED; 12260f1702c5SYu Xiangning } 12270f1702c5SYu Xiangning } 12280f1702c5SYu Xiangning if (soppp->sopp_flags & SOCKOPT_OOBINLINE) 12290f1702c5SYu Xiangning so->so_proto_props.sopp_oobinline = soppp->sopp_oobinline; 12300f1702c5SYu Xiangning if (soppp->sopp_flags & SOCKOPT_RCVTIMER) 12310f1702c5SYu Xiangning so->so_proto_props.sopp_rcvtimer = soppp->sopp_rcvtimer; 12320f1702c5SYu Xiangning if (soppp->sopp_flags & SOCKOPT_RCVTHRESH) 12330f1702c5SYu Xiangning so->so_proto_props.sopp_rcvthresh = soppp->sopp_rcvthresh; 12340f1702c5SYu Xiangning if (soppp->sopp_flags & SOCKOPT_MAXADDRLEN) 12350f1702c5SYu Xiangning so->so_proto_props.sopp_maxaddrlen = soppp->sopp_maxaddrlen; 1236081c0aa8SAnders Persson if (soppp->sopp_flags & SOCKOPT_LOOPBACK) 1237081c0aa8SAnders Persson so->so_proto_props.sopp_loopback = soppp->sopp_loopback; 12380f1702c5SYu Xiangning 12390f1702c5SYu Xiangning mutex_exit(&so->so_lock); 12400f1702c5SYu Xiangning 12413e95bd4aSAnders Persson if (so->so_filter_active > 0) { 12423e95bd4aSAnders Persson sof_instance_t *inst; 12433e95bd4aSAnders Persson ssize_t maxblk; 12443e95bd4aSAnders Persson ushort_t wroff, tail; 12453e95bd4aSAnders Persson maxblk = so->so_proto_props.sopp_maxblk; 12463e95bd4aSAnders Persson wroff = so->so_proto_props.sopp_wroff; 12473e95bd4aSAnders Persson tail = so->so_proto_props.sopp_tail; 12483e95bd4aSAnders Persson for (inst = so->so_filter_bottom; inst != NULL; 12493e95bd4aSAnders Persson inst = inst->sofi_prev) { 12503e95bd4aSAnders Persson if (SOF_INTERESTED(inst, mblk_prop)) { 12513e95bd4aSAnders Persson (*inst->sofi_ops->sofop_mblk_prop)( 12523e95bd4aSAnders Persson (sof_handle_t)inst, inst->sofi_cookie, 12533e95bd4aSAnders Persson &maxblk, &wroff, &tail); 12543e95bd4aSAnders Persson } 12553e95bd4aSAnders Persson } 12563e95bd4aSAnders Persson mutex_enter(&so->so_lock); 12573e95bd4aSAnders Persson so->so_proto_props.sopp_maxblk = maxblk; 12583e95bd4aSAnders Persson so->so_proto_props.sopp_wroff = wroff; 12593e95bd4aSAnders Persson so->so_proto_props.sopp_tail = tail; 12603e95bd4aSAnders Persson mutex_exit(&so->so_lock); 12613e95bd4aSAnders Persson } 12620f1702c5SYu Xiangning #ifdef DEBUG 12630f1702c5SYu Xiangning soppp->sopp_flags &= ~(SOCKOPT_MAXBLK | SOCKOPT_WROFF | SOCKOPT_TAIL | 12640f1702c5SYu Xiangning SOCKOPT_RCVHIWAT | SOCKOPT_RCVLOWAT | SOCKOPT_MAXPSZ | 12650f1702c5SYu Xiangning SOCKOPT_ZCOPY | SOCKOPT_OOBINLINE | SOCKOPT_RCVTIMER | 1266081c0aa8SAnders Persson SOCKOPT_RCVTHRESH | SOCKOPT_MAXADDRLEN | SOCKOPT_MINPSZ | 1267081c0aa8SAnders Persson SOCKOPT_LOOPBACK); 12680f1702c5SYu Xiangning ASSERT(soppp->sopp_flags == 0); 12690f1702c5SYu Xiangning #endif 12700f1702c5SYu Xiangning } 12710f1702c5SYu Xiangning 12720f1702c5SYu Xiangning /* ARGSUSED */ 12730f1702c5SYu Xiangning ssize_t 12743e95bd4aSAnders Persson so_queue_msg_impl(struct sonode *so, mblk_t *mp, 12753e95bd4aSAnders Persson size_t msg_size, int flags, int *errorp, boolean_t *force_pushp, 12763e95bd4aSAnders Persson sof_instance_t *filter) 12770f1702c5SYu Xiangning { 12780f1702c5SYu Xiangning boolean_t force_push = B_TRUE; 12790f1702c5SYu Xiangning int space_left; 12800f1702c5SYu Xiangning sodirect_t *sodp = so->so_direct; 12810f1702c5SYu Xiangning 12820f1702c5SYu Xiangning ASSERT(errorp != NULL); 12830f1702c5SYu Xiangning *errorp = 0; 12840f1702c5SYu Xiangning if (mp == NULL) { 1285c0dd49bdSEiji Ota if (so->so_downcalls->sd_recv_uio != NULL) { 12860f1702c5SYu Xiangning mutex_enter(&so->so_lock); 12870f1702c5SYu Xiangning /* the notify functions will drop the lock */ 12880f1702c5SYu Xiangning if (flags & MSG_OOB) 12890f1702c5SYu Xiangning so_notify_oobdata(so, IS_SO_OOB_INLINE(so)); 12900f1702c5SYu Xiangning else 12910f1702c5SYu Xiangning so_notify_data(so, msg_size); 12920f1702c5SYu Xiangning return (0); 12930f1702c5SYu Xiangning } 1294c0dd49bdSEiji Ota ASSERT(msg_size == 0); 12950f1702c5SYu Xiangning mutex_enter(&so->so_lock); 12963e95bd4aSAnders Persson goto space_check; 12970f1702c5SYu Xiangning } 12980f1702c5SYu Xiangning 12990f1702c5SYu Xiangning ASSERT(mp->b_next == NULL); 13000f1702c5SYu Xiangning ASSERT(DB_TYPE(mp) == M_DATA || DB_TYPE(mp) == M_PROTO); 13010f1702c5SYu Xiangning ASSERT(msg_size == msgdsize(mp)); 13020f1702c5SYu Xiangning 13030f1702c5SYu Xiangning if (DB_TYPE(mp) == M_PROTO && !__TPI_PRIM_ISALIGNED(mp->b_rptr)) { 13040f1702c5SYu Xiangning /* The read pointer is not aligned correctly for TPI */ 13050f1702c5SYu Xiangning zcmn_err(getzoneid(), CE_WARN, 13060f1702c5SYu Xiangning "sockfs: Unaligned TPI message received. rptr = %p\n", 13070f1702c5SYu Xiangning (void *)mp->b_rptr); 13080f1702c5SYu Xiangning freemsg(mp); 1309bbc000e5SAnders Persson mutex_enter(&so->so_lock); 1310bbc000e5SAnders Persson if (sodp != NULL) 13110f1702c5SYu Xiangning SOD_UIOAFINI(sodp); 13123e95bd4aSAnders Persson goto space_check; 13130f1702c5SYu Xiangning } 13140f1702c5SYu Xiangning 13153e95bd4aSAnders Persson if (so->so_filter_active > 0) { 13163e95bd4aSAnders Persson for (; filter != NULL; filter = filter->sofi_prev) { 13173e95bd4aSAnders Persson if (!SOF_INTERESTED(filter, data_in)) 13183e95bd4aSAnders Persson continue; 13193e95bd4aSAnders Persson mp = (*filter->sofi_ops->sofop_data_in)( 13203e95bd4aSAnders Persson (sof_handle_t)filter, filter->sofi_cookie, mp, 13213e95bd4aSAnders Persson flags, &msg_size); 13223e95bd4aSAnders Persson ASSERT(msgdsize(mp) == msg_size); 13233e95bd4aSAnders Persson DTRACE_PROBE2(filter__data, (sof_instance_t), filter, 13243e95bd4aSAnders Persson (mblk_t *), mp); 13253e95bd4aSAnders Persson /* Data was consumed/dropped, just do space check */ 13263e95bd4aSAnders Persson if (msg_size == 0) { 13273e95bd4aSAnders Persson mutex_enter(&so->so_lock); 13283e95bd4aSAnders Persson goto space_check; 13293e95bd4aSAnders Persson } 13303e95bd4aSAnders Persson } 13313e95bd4aSAnders Persson } 13323e95bd4aSAnders Persson 13333e95bd4aSAnders Persson if (flags & MSG_OOB) { 13343e95bd4aSAnders Persson so_queue_oob(so, mp, msg_size); 13353e95bd4aSAnders Persson mutex_enter(&so->so_lock); 13363e95bd4aSAnders Persson goto space_check; 13373e95bd4aSAnders Persson } 13383e95bd4aSAnders Persson 13393e95bd4aSAnders Persson if (force_pushp != NULL) 13403e95bd4aSAnders Persson force_push = *force_pushp; 13413e95bd4aSAnders Persson 13420f1702c5SYu Xiangning mutex_enter(&so->so_lock); 134341174437SAnders Persson if (so->so_state & (SS_FALLBACK_DRAIN | SS_FALLBACK_COMP)) { 1344bbc000e5SAnders Persson if (sodp != NULL) 13450f1702c5SYu Xiangning SOD_DISABLE(sodp); 13460f1702c5SYu Xiangning mutex_exit(&so->so_lock); 13470f1702c5SYu Xiangning *errorp = EOPNOTSUPP; 13480f1702c5SYu Xiangning return (-1); 13490f1702c5SYu Xiangning } 13503e95bd4aSAnders Persson if (so->so_state & (SS_CANTRCVMORE | SS_CLOSING)) { 13510f1702c5SYu Xiangning freemsg(mp); 1352bbc000e5SAnders Persson if (sodp != NULL) 13530f1702c5SYu Xiangning SOD_DISABLE(sodp); 13540f1702c5SYu Xiangning mutex_exit(&so->so_lock); 13550f1702c5SYu Xiangning return (0); 13560f1702c5SYu Xiangning } 13570f1702c5SYu Xiangning 13580f1702c5SYu Xiangning /* process the mblk via I/OAT if capable */ 1359bbc000e5SAnders Persson if (sodp != NULL && sodp->sod_enabled) { 13600f1702c5SYu Xiangning if (DB_TYPE(mp) == M_DATA) { 1361bbc000e5SAnders Persson sod_uioa_mblk_init(sodp, mp, msg_size); 13620f1702c5SYu Xiangning } else { 13630f1702c5SYu Xiangning SOD_UIOAFINI(sodp); 13640f1702c5SYu Xiangning } 13650f1702c5SYu Xiangning } 13660f1702c5SYu Xiangning 13670f1702c5SYu Xiangning if (mp->b_next == NULL) { 13680f1702c5SYu Xiangning so_enqueue_msg(so, mp, msg_size); 13690f1702c5SYu Xiangning } else { 13700f1702c5SYu Xiangning do { 13710f1702c5SYu Xiangning mblk_t *nmp; 13720f1702c5SYu Xiangning 13730f1702c5SYu Xiangning if ((nmp = mp->b_next) != NULL) { 13740f1702c5SYu Xiangning mp->b_next = NULL; 13750f1702c5SYu Xiangning } 13760f1702c5SYu Xiangning so_enqueue_msg(so, mp, msgdsize(mp)); 13770f1702c5SYu Xiangning mp = nmp; 13780f1702c5SYu Xiangning } while (mp != NULL); 13790f1702c5SYu Xiangning } 13800f1702c5SYu Xiangning 13810f1702c5SYu Xiangning space_left = so->so_rcvbuf - so->so_rcv_queued; 13820f1702c5SYu Xiangning if (space_left <= 0) { 13830f1702c5SYu Xiangning so->so_flowctrld = B_TRUE; 13840f1702c5SYu Xiangning *errorp = ENOSPC; 13850f1702c5SYu Xiangning space_left = -1; 13860f1702c5SYu Xiangning } 13870f1702c5SYu Xiangning 13880f1702c5SYu Xiangning if (force_push || so->so_rcv_queued >= so->so_rcv_thresh || 1389bbc000e5SAnders Persson so->so_rcv_queued >= so->so_rcv_wanted) { 13900f1702c5SYu Xiangning SOCKET_TIMER_CANCEL(so); 13910f1702c5SYu Xiangning /* 13920f1702c5SYu Xiangning * so_notify_data will release the lock 13930f1702c5SYu Xiangning */ 13940f1702c5SYu Xiangning so_notify_data(so, so->so_rcv_queued); 13950f1702c5SYu Xiangning 13960f1702c5SYu Xiangning if (force_pushp != NULL) 13970f1702c5SYu Xiangning *force_pushp = B_TRUE; 13980f1702c5SYu Xiangning goto done; 13990f1702c5SYu Xiangning } else if (so->so_rcv_timer_tid == 0) { 14000f1702c5SYu Xiangning /* Make sure the recv push timer is running */ 14010f1702c5SYu Xiangning SOCKET_TIMER_START(so); 14020f1702c5SYu Xiangning } 14030f1702c5SYu Xiangning 14040f1702c5SYu Xiangning done_unlock: 14050f1702c5SYu Xiangning mutex_exit(&so->so_lock); 14060f1702c5SYu Xiangning done: 14070f1702c5SYu Xiangning return (space_left); 14083e95bd4aSAnders Persson 14093e95bd4aSAnders Persson space_check: 14103e95bd4aSAnders Persson space_left = so->so_rcvbuf - so->so_rcv_queued; 14113e95bd4aSAnders Persson if (space_left <= 0) { 14123e95bd4aSAnders Persson so->so_flowctrld = B_TRUE; 14133e95bd4aSAnders Persson *errorp = ENOSPC; 14143e95bd4aSAnders Persson space_left = -1; 14153e95bd4aSAnders Persson } 14163e95bd4aSAnders Persson goto done_unlock; 14173e95bd4aSAnders Persson } 14183e95bd4aSAnders Persson 14193e95bd4aSAnders Persson #pragma inline(so_queue_msg_impl) 14203e95bd4aSAnders Persson 14213e95bd4aSAnders Persson ssize_t 14223e95bd4aSAnders Persson so_queue_msg(sock_upper_handle_t sock_handle, mblk_t *mp, 14233e95bd4aSAnders Persson size_t msg_size, int flags, int *errorp, boolean_t *force_pushp) 14243e95bd4aSAnders Persson { 14253e95bd4aSAnders Persson struct sonode *so = (struct sonode *)sock_handle; 14263e95bd4aSAnders Persson 14273e95bd4aSAnders Persson return (so_queue_msg_impl(so, mp, msg_size, flags, errorp, force_pushp, 14283e95bd4aSAnders Persson so->so_filter_bottom)); 14290f1702c5SYu Xiangning } 14300f1702c5SYu Xiangning 14310f1702c5SYu Xiangning /* 14320f1702c5SYu Xiangning * Set the offset of where the oob data is relative to the bytes in 14330f1702c5SYu Xiangning * queued. Also generate SIGURG 14340f1702c5SYu Xiangning */ 14350f1702c5SYu Xiangning void 14360f1702c5SYu Xiangning so_signal_oob(sock_upper_handle_t sock_handle, ssize_t offset) 14370f1702c5SYu Xiangning { 14380f1702c5SYu Xiangning struct sonode *so; 14390f1702c5SYu Xiangning 14400f1702c5SYu Xiangning ASSERT(offset >= 0); 14410f1702c5SYu Xiangning so = (struct sonode *)sock_handle; 14420f1702c5SYu Xiangning mutex_enter(&so->so_lock); 1443bbc000e5SAnders Persson if (so->so_direct != NULL) 14440f1702c5SYu Xiangning SOD_UIOAFINI(so->so_direct); 14450f1702c5SYu Xiangning 14460f1702c5SYu Xiangning /* 14470f1702c5SYu Xiangning * New urgent data on the way so forget about any old 14480f1702c5SYu Xiangning * urgent data. 14490f1702c5SYu Xiangning */ 14500f1702c5SYu Xiangning so->so_state &= ~(SS_HAVEOOBDATA|SS_HADOOBDATA); 14510f1702c5SYu Xiangning 14520f1702c5SYu Xiangning /* 14530f1702c5SYu Xiangning * Record that urgent data is pending. 14540f1702c5SYu Xiangning */ 14550f1702c5SYu Xiangning so->so_state |= SS_OOBPEND; 14560f1702c5SYu Xiangning 14570f1702c5SYu Xiangning if (so->so_oobmsg != NULL) { 14580f1702c5SYu Xiangning dprintso(so, 1, ("sock: discarding old oob\n")); 14590f1702c5SYu Xiangning freemsg(so->so_oobmsg); 14600f1702c5SYu Xiangning so->so_oobmsg = NULL; 14610f1702c5SYu Xiangning } 14620f1702c5SYu Xiangning 14630f1702c5SYu Xiangning /* 14640f1702c5SYu Xiangning * set the offset where the urgent byte is 14650f1702c5SYu Xiangning */ 14660f1702c5SYu Xiangning so->so_oobmark = so->so_rcv_queued + offset; 14670f1702c5SYu Xiangning if (so->so_oobmark == 0) 14680f1702c5SYu Xiangning so->so_state |= SS_RCVATMARK; 14690f1702c5SYu Xiangning else 14700f1702c5SYu Xiangning so->so_state &= ~SS_RCVATMARK; 14710f1702c5SYu Xiangning 14720f1702c5SYu Xiangning so_notify_oobsig(so); 14730f1702c5SYu Xiangning } 14740f1702c5SYu Xiangning 14750f1702c5SYu Xiangning /* 14760f1702c5SYu Xiangning * Queue the OOB byte 14770f1702c5SYu Xiangning */ 14780f1702c5SYu Xiangning static void 14793e95bd4aSAnders Persson so_queue_oob(struct sonode *so, mblk_t *mp, size_t len) 14800f1702c5SYu Xiangning { 14810f1702c5SYu Xiangning mutex_enter(&so->so_lock); 1482bbc000e5SAnders Persson if (so->so_direct != NULL) 14830f1702c5SYu Xiangning SOD_UIOAFINI(so->so_direct); 14840f1702c5SYu Xiangning 14850f1702c5SYu Xiangning ASSERT(mp != NULL); 14860f1702c5SYu Xiangning if (!IS_SO_OOB_INLINE(so)) { 14870f1702c5SYu Xiangning so->so_oobmsg = mp; 14880f1702c5SYu Xiangning so->so_state |= SS_HAVEOOBDATA; 14890f1702c5SYu Xiangning } else { 14900f1702c5SYu Xiangning so_enqueue_msg(so, mp, len); 14910f1702c5SYu Xiangning } 14920f1702c5SYu Xiangning 14930f1702c5SYu Xiangning so_notify_oobdata(so, IS_SO_OOB_INLINE(so)); 14940f1702c5SYu Xiangning } 14950f1702c5SYu Xiangning 14960f1702c5SYu Xiangning int 14970f1702c5SYu Xiangning so_close(struct sonode *so, int flag, struct cred *cr) 14980f1702c5SYu Xiangning { 14990f1702c5SYu Xiangning int error; 15000f1702c5SYu Xiangning 15010f1702c5SYu Xiangning /* 15023e95bd4aSAnders Persson * No new data will be enqueued once the CLOSING flag is set. 15030f1702c5SYu Xiangning */ 15040f1702c5SYu Xiangning mutex_enter(&so->so_lock); 15053e95bd4aSAnders Persson so->so_state |= SS_CLOSING; 1506d36be52eSRao Shoaib ASSERT(so_verify_oobstate(so)); 15070f1702c5SYu Xiangning so_rcv_flush(so); 15080f1702c5SYu Xiangning mutex_exit(&so->so_lock); 15090f1702c5SYu Xiangning 1510e82bc0baSAnders Persson if (so->so_filter_active > 0) 1511e82bc0baSAnders Persson sof_sonode_closing(so); 1512e82bc0baSAnders Persson 15133e95bd4aSAnders Persson if (so->so_state & SS_ACCEPTCONN) { 15143e95bd4aSAnders Persson /* 15153e95bd4aSAnders Persson * We grab and release the accept lock to ensure that any 15163e95bd4aSAnders Persson * thread about to insert a socket in so_newconn completes 15173e95bd4aSAnders Persson * before we flush the queue. Any thread calling so_newconn 15183e95bd4aSAnders Persson * after we drop the lock will observe the SS_CLOSING flag, 15193e95bd4aSAnders Persson * which will stop it from inserting the socket in the queue. 15203e95bd4aSAnders Persson */ 15213e95bd4aSAnders Persson mutex_enter(&so->so_acceptq_lock); 15223e95bd4aSAnders Persson mutex_exit(&so->so_acceptq_lock); 15233e95bd4aSAnders Persson 15243e95bd4aSAnders Persson so_acceptq_flush(so, B_TRUE); 15253e95bd4aSAnders Persson } 15263e95bd4aSAnders Persson 15273e95bd4aSAnders Persson error = (*so->so_downcalls->sd_close)(so->so_proto_handle, flag, cr); 15283e95bd4aSAnders Persson switch (error) { 15293e95bd4aSAnders Persson default: 15303e95bd4aSAnders Persson /* Protocol made a synchronous close; remove proto ref */ 15313e95bd4aSAnders Persson VN_RELE(SOTOV(so)); 15323e95bd4aSAnders Persson break; 15333e95bd4aSAnders Persson case EINPROGRESS: 15343e95bd4aSAnders Persson /* 15353e95bd4aSAnders Persson * Protocol is in the process of closing, it will make a 15363e95bd4aSAnders Persson * 'closed' upcall to remove the reference. 15373e95bd4aSAnders Persson */ 15383e95bd4aSAnders Persson error = 0; 15393e95bd4aSAnders Persson break; 15403e95bd4aSAnders Persson } 15413e95bd4aSAnders Persson 15420f1702c5SYu Xiangning return (error); 15430f1702c5SYu Xiangning } 15440f1702c5SYu Xiangning 15453e95bd4aSAnders Persson /* 15463e95bd4aSAnders Persson * Upcall made by the protocol when it's doing an asynchronous close. It 15473e95bd4aSAnders Persson * will drop the protocol's reference on the socket. 15483e95bd4aSAnders Persson */ 15493e95bd4aSAnders Persson void 15503e95bd4aSAnders Persson so_closed(sock_upper_handle_t sock_handle) 15513e95bd4aSAnders Persson { 15523e95bd4aSAnders Persson struct sonode *so = (struct sonode *)sock_handle; 15533e95bd4aSAnders Persson 15543e95bd4aSAnders Persson VN_RELE(SOTOV(so)); 15553e95bd4aSAnders Persson } 15563e95bd4aSAnders Persson 15570f1702c5SYu Xiangning void 15580f1702c5SYu Xiangning so_zcopy_notify(sock_upper_handle_t sock_handle) 15590f1702c5SYu Xiangning { 15600f1702c5SYu Xiangning struct sonode *so = (struct sonode *)sock_handle; 15610f1702c5SYu Xiangning 15620f1702c5SYu Xiangning mutex_enter(&so->so_lock); 15630f1702c5SYu Xiangning so->so_copyflag |= STZCNOTIFY; 15640f1702c5SYu Xiangning cv_broadcast(&so->so_copy_cv); 15650f1702c5SYu Xiangning mutex_exit(&so->so_lock); 15660f1702c5SYu Xiangning } 15670f1702c5SYu Xiangning 15680f1702c5SYu Xiangning void 15690f1702c5SYu Xiangning so_set_error(sock_upper_handle_t sock_handle, int error) 15700f1702c5SYu Xiangning { 15710f1702c5SYu Xiangning struct sonode *so = (struct sonode *)sock_handle; 15720f1702c5SYu Xiangning 15730f1702c5SYu Xiangning mutex_enter(&so->so_lock); 15740f1702c5SYu Xiangning 15750f1702c5SYu Xiangning soseterror(so, error); 15760f1702c5SYu Xiangning 15770f1702c5SYu Xiangning so_notify_error(so); 15780f1702c5SYu Xiangning } 15790f1702c5SYu Xiangning 15800f1702c5SYu Xiangning /* 15810f1702c5SYu Xiangning * so_recvmsg - read data from the socket 15820f1702c5SYu Xiangning * 15830f1702c5SYu Xiangning * There are two ways of obtaining data; either we ask the protocol to 15840f1702c5SYu Xiangning * copy directly into the supplied buffer, or we copy data from the 15850f1702c5SYu Xiangning * sonode's receive queue. The decision which one to use depends on 15860f1702c5SYu Xiangning * whether the protocol has a sd_recv_uio down call. 15870f1702c5SYu Xiangning */ 15880f1702c5SYu Xiangning int 15890f1702c5SYu Xiangning so_recvmsg(struct sonode *so, struct nmsghdr *msg, struct uio *uiop, 15900f1702c5SYu Xiangning struct cred *cr) 15910f1702c5SYu Xiangning { 15920f1702c5SYu Xiangning rval_t rval; 15930f1702c5SYu Xiangning int flags = 0; 15940f1702c5SYu Xiangning t_uscalar_t controllen, namelen; 15950f1702c5SYu Xiangning int error = 0; 15960f1702c5SYu Xiangning int ret; 15970f1702c5SYu Xiangning mblk_t *mctlp = NULL; 15980f1702c5SYu Xiangning union T_primitives *tpr; 15990f1702c5SYu Xiangning void *control; 16000f1702c5SYu Xiangning ssize_t saved_resid; 16010f1702c5SYu Xiangning struct uio *suiop; 16020f1702c5SYu Xiangning 16030f1702c5SYu Xiangning SO_BLOCK_FALLBACK(so, SOP_RECVMSG(so, msg, uiop, cr)); 16040f1702c5SYu Xiangning 16050f1702c5SYu Xiangning if ((so->so_state & (SS_ISCONNECTED|SS_CANTRCVMORE)) == 0 && 16060f1702c5SYu Xiangning (so->so_mode & SM_CONNREQUIRED)) { 16070f1702c5SYu Xiangning SO_UNBLOCK_FALLBACK(so); 16080f1702c5SYu Xiangning return (ENOTCONN); 16090f1702c5SYu Xiangning } 16100f1702c5SYu Xiangning 16110f1702c5SYu Xiangning if (msg->msg_flags & MSG_PEEK) 16120f1702c5SYu Xiangning msg->msg_flags &= ~MSG_WAITALL; 16130f1702c5SYu Xiangning 16140f1702c5SYu Xiangning if (so->so_mode & SM_ATOMIC) 16150f1702c5SYu Xiangning msg->msg_flags |= MSG_TRUNC; 16160f1702c5SYu Xiangning 16170f1702c5SYu Xiangning if (msg->msg_flags & MSG_OOB) { 16180f1702c5SYu Xiangning if ((so->so_mode & SM_EXDATA) == 0) { 16190f1702c5SYu Xiangning error = EOPNOTSUPP; 16200f1702c5SYu Xiangning } else if (so->so_downcalls->sd_recv_uio != NULL) { 16210f1702c5SYu Xiangning error = (*so->so_downcalls->sd_recv_uio) 16220f1702c5SYu Xiangning (so->so_proto_handle, uiop, msg, cr); 16230f1702c5SYu Xiangning } else { 16240f1702c5SYu Xiangning error = sorecvoob(so, msg, uiop, msg->msg_flags, 16250f1702c5SYu Xiangning IS_SO_OOB_INLINE(so)); 16260f1702c5SYu Xiangning } 16270f1702c5SYu Xiangning SO_UNBLOCK_FALLBACK(so); 16280f1702c5SYu Xiangning return (error); 16290f1702c5SYu Xiangning } 16300f1702c5SYu Xiangning 16310f1702c5SYu Xiangning /* 16320f1702c5SYu Xiangning * If the protocol has the recv down call, then pass the request 16330f1702c5SYu Xiangning * down. 16340f1702c5SYu Xiangning */ 16350f1702c5SYu Xiangning if (so->so_downcalls->sd_recv_uio != NULL) { 16360f1702c5SYu Xiangning error = (*so->so_downcalls->sd_recv_uio) 16370f1702c5SYu Xiangning (so->so_proto_handle, uiop, msg, cr); 16380f1702c5SYu Xiangning SO_UNBLOCK_FALLBACK(so); 16390f1702c5SYu Xiangning return (error); 16400f1702c5SYu Xiangning } 16410f1702c5SYu Xiangning 16420f1702c5SYu Xiangning /* 16430f1702c5SYu Xiangning * Reading data from the socket buffer 16440f1702c5SYu Xiangning */ 16450f1702c5SYu Xiangning flags = msg->msg_flags; 16460f1702c5SYu Xiangning msg->msg_flags = 0; 16470f1702c5SYu Xiangning 16480f1702c5SYu Xiangning /* 16490f1702c5SYu Xiangning * Set msg_controllen and msg_namelen to zero here to make it 16500f1702c5SYu Xiangning * simpler in the cases that no control or name is returned. 16510f1702c5SYu Xiangning */ 16520f1702c5SYu Xiangning controllen = msg->msg_controllen; 16530f1702c5SYu Xiangning namelen = msg->msg_namelen; 16540f1702c5SYu Xiangning msg->msg_controllen = 0; 16550f1702c5SYu Xiangning msg->msg_namelen = 0; 16560f1702c5SYu Xiangning 16570f1702c5SYu Xiangning mutex_enter(&so->so_lock); 16580f1702c5SYu Xiangning /* Set SOREADLOCKED */ 16590f1702c5SYu Xiangning error = so_lock_read_intr(so, 16600f1702c5SYu Xiangning uiop->uio_fmode | ((flags & MSG_DONTWAIT) ? FNONBLOCK : 0)); 16610f1702c5SYu Xiangning mutex_exit(&so->so_lock); 16620f1702c5SYu Xiangning if (error) { 16630f1702c5SYu Xiangning SO_UNBLOCK_FALLBACK(so); 16640f1702c5SYu Xiangning return (error); 16650f1702c5SYu Xiangning } 16660f1702c5SYu Xiangning 16670f1702c5SYu Xiangning suiop = sod_rcv_init(so, flags, &uiop); 16680f1702c5SYu Xiangning retry: 16690f1702c5SYu Xiangning saved_resid = uiop->uio_resid; 16700f1702c5SYu Xiangning error = so_dequeue_msg(so, &mctlp, uiop, &rval, flags); 16710f1702c5SYu Xiangning if (error != 0) { 16720f1702c5SYu Xiangning goto out; 16730f1702c5SYu Xiangning } 16740f1702c5SYu Xiangning /* 16750f1702c5SYu Xiangning * For datagrams the MOREDATA flag is used to set MSG_TRUNC. 16760f1702c5SYu Xiangning * For non-datagrams MOREDATA is used to set MSG_EOR. 16770f1702c5SYu Xiangning */ 16780f1702c5SYu Xiangning ASSERT(!(rval.r_val1 & MORECTL)); 16790f1702c5SYu Xiangning if ((rval.r_val1 & MOREDATA) && (so->so_mode & SM_ATOMIC)) 16800f1702c5SYu Xiangning msg->msg_flags |= MSG_TRUNC; 16810f1702c5SYu Xiangning if (mctlp == NULL) { 16820f1702c5SYu Xiangning dprintso(so, 1, ("so_recvmsg: got M_DATA\n")); 16830f1702c5SYu Xiangning 16840f1702c5SYu Xiangning mutex_enter(&so->so_lock); 16850f1702c5SYu Xiangning /* Set MSG_EOR based on MOREDATA */ 16860f1702c5SYu Xiangning if (!(rval.r_val1 & MOREDATA)) { 16870f1702c5SYu Xiangning if (so->so_state & SS_SAVEDEOR) { 16880f1702c5SYu Xiangning msg->msg_flags |= MSG_EOR; 16890f1702c5SYu Xiangning so->so_state &= ~SS_SAVEDEOR; 16900f1702c5SYu Xiangning } 16910f1702c5SYu Xiangning } 16920f1702c5SYu Xiangning /* 16930f1702c5SYu Xiangning * If some data was received (i.e. not EOF) and the 16940f1702c5SYu Xiangning * read/recv* has not been satisfied wait for some more. 16950f1702c5SYu Xiangning */ 16960f1702c5SYu Xiangning if ((flags & MSG_WAITALL) && !(msg->msg_flags & MSG_EOR) && 16970f1702c5SYu Xiangning uiop->uio_resid != saved_resid && uiop->uio_resid > 0) { 16980f1702c5SYu Xiangning mutex_exit(&so->so_lock); 16998591a19aSAnders Persson flags |= MSG_NOMARK; 17000f1702c5SYu Xiangning goto retry; 17010f1702c5SYu Xiangning } 17020f1702c5SYu Xiangning 17030f1702c5SYu Xiangning goto out_locked; 17040f1702c5SYu Xiangning } 17058591a19aSAnders Persson /* so_queue_msg has already verified length and alignment */ 17060f1702c5SYu Xiangning tpr = (union T_primitives *)mctlp->b_rptr; 17070f1702c5SYu Xiangning dprintso(so, 1, ("so_recvmsg: type %d\n", tpr->type)); 17080f1702c5SYu Xiangning switch (tpr->type) { 17090f1702c5SYu Xiangning case T_DATA_IND: { 17100f1702c5SYu Xiangning /* 17110f1702c5SYu Xiangning * Set msg_flags to MSG_EOR based on 17120f1702c5SYu Xiangning * MORE_flag and MOREDATA. 17130f1702c5SYu Xiangning */ 17140f1702c5SYu Xiangning mutex_enter(&so->so_lock); 17150f1702c5SYu Xiangning so->so_state &= ~SS_SAVEDEOR; 17160f1702c5SYu Xiangning if (!(tpr->data_ind.MORE_flag & 1)) { 17170f1702c5SYu Xiangning if (!(rval.r_val1 & MOREDATA)) 17180f1702c5SYu Xiangning msg->msg_flags |= MSG_EOR; 17190f1702c5SYu Xiangning else 17200f1702c5SYu Xiangning so->so_state |= SS_SAVEDEOR; 17210f1702c5SYu Xiangning } 17220f1702c5SYu Xiangning freemsg(mctlp); 17230f1702c5SYu Xiangning /* 17240f1702c5SYu Xiangning * If some data was received (i.e. not EOF) and the 17250f1702c5SYu Xiangning * read/recv* has not been satisfied wait for some more. 17260f1702c5SYu Xiangning */ 17270f1702c5SYu Xiangning if ((flags & MSG_WAITALL) && !(msg->msg_flags & MSG_EOR) && 17280f1702c5SYu Xiangning uiop->uio_resid != saved_resid && uiop->uio_resid > 0) { 17290f1702c5SYu Xiangning mutex_exit(&so->so_lock); 17308591a19aSAnders Persson flags |= MSG_NOMARK; 17310f1702c5SYu Xiangning goto retry; 17320f1702c5SYu Xiangning } 17330f1702c5SYu Xiangning goto out_locked; 17340f1702c5SYu Xiangning } 17350f1702c5SYu Xiangning case T_UNITDATA_IND: { 17360f1702c5SYu Xiangning void *addr; 17370f1702c5SYu Xiangning t_uscalar_t addrlen; 17380f1702c5SYu Xiangning void *abuf; 17390f1702c5SYu Xiangning t_uscalar_t optlen; 17400f1702c5SYu Xiangning void *opt; 17410f1702c5SYu Xiangning 17420f1702c5SYu Xiangning if (namelen != 0) { 17430f1702c5SYu Xiangning /* Caller wants source address */ 17440f1702c5SYu Xiangning addrlen = tpr->unitdata_ind.SRC_length; 17450f1702c5SYu Xiangning addr = sogetoff(mctlp, tpr->unitdata_ind.SRC_offset, 17460f1702c5SYu Xiangning addrlen, 1); 17470f1702c5SYu Xiangning if (addr == NULL) { 17480f1702c5SYu Xiangning freemsg(mctlp); 17490f1702c5SYu Xiangning error = EPROTO; 17500f1702c5SYu Xiangning eprintsoline(so, error); 17510f1702c5SYu Xiangning goto out; 17520f1702c5SYu Xiangning } 17530f1702c5SYu Xiangning ASSERT(so->so_family != AF_UNIX); 17540f1702c5SYu Xiangning } 17550f1702c5SYu Xiangning optlen = tpr->unitdata_ind.OPT_length; 17560f1702c5SYu Xiangning if (optlen != 0) { 17570f1702c5SYu Xiangning t_uscalar_t ncontrollen; 17580f1702c5SYu Xiangning 17590f1702c5SYu Xiangning /* 17600f1702c5SYu Xiangning * Extract any source address option. 17610f1702c5SYu Xiangning * Determine how large cmsg buffer is needed. 17620f1702c5SYu Xiangning */ 17630f1702c5SYu Xiangning opt = sogetoff(mctlp, tpr->unitdata_ind.OPT_offset, 17640f1702c5SYu Xiangning optlen, __TPI_ALIGN_SIZE); 17650f1702c5SYu Xiangning 17660f1702c5SYu Xiangning if (opt == NULL) { 17670f1702c5SYu Xiangning freemsg(mctlp); 17680f1702c5SYu Xiangning error = EPROTO; 17690f1702c5SYu Xiangning eprintsoline(so, error); 17700f1702c5SYu Xiangning goto out; 17710f1702c5SYu Xiangning } 17720f1702c5SYu Xiangning if (so->so_family == AF_UNIX) 17730f1702c5SYu Xiangning so_getopt_srcaddr(opt, optlen, &addr, &addrlen); 17740f1702c5SYu Xiangning ncontrollen = so_cmsglen(mctlp, opt, optlen, 17750f1702c5SYu Xiangning !(flags & MSG_XPG4_2)); 17760f1702c5SYu Xiangning if (controllen != 0) 17770f1702c5SYu Xiangning controllen = ncontrollen; 17780f1702c5SYu Xiangning else if (ncontrollen != 0) 17790f1702c5SYu Xiangning msg->msg_flags |= MSG_CTRUNC; 17800f1702c5SYu Xiangning } else { 17810f1702c5SYu Xiangning controllen = 0; 17820f1702c5SYu Xiangning } 17830f1702c5SYu Xiangning 17840f1702c5SYu Xiangning if (namelen != 0) { 17850f1702c5SYu Xiangning /* 17860f1702c5SYu Xiangning * Return address to caller. 17870f1702c5SYu Xiangning * Caller handles truncation if length 17880f1702c5SYu Xiangning * exceeds msg_namelen. 17890f1702c5SYu Xiangning * NOTE: AF_UNIX NUL termination is ensured by 17900f1702c5SYu Xiangning * the sender's copyin_name(). 17910f1702c5SYu Xiangning */ 17920f1702c5SYu Xiangning abuf = kmem_alloc(addrlen, KM_SLEEP); 17930f1702c5SYu Xiangning 17940f1702c5SYu Xiangning bcopy(addr, abuf, addrlen); 17950f1702c5SYu Xiangning msg->msg_name = abuf; 17960f1702c5SYu Xiangning msg->msg_namelen = addrlen; 17970f1702c5SYu Xiangning } 17980f1702c5SYu Xiangning 17990f1702c5SYu Xiangning if (controllen != 0) { 18000f1702c5SYu Xiangning /* 18010f1702c5SYu Xiangning * Return control msg to caller. 18020f1702c5SYu Xiangning * Caller handles truncation if length 18030f1702c5SYu Xiangning * exceeds msg_controllen. 18040f1702c5SYu Xiangning */ 18050f1702c5SYu Xiangning control = kmem_zalloc(controllen, KM_SLEEP); 18060f1702c5SYu Xiangning 18070f1702c5SYu Xiangning error = so_opt2cmsg(mctlp, opt, optlen, 18080f1702c5SYu Xiangning !(flags & MSG_XPG4_2), control, controllen); 18090f1702c5SYu Xiangning if (error) { 18100f1702c5SYu Xiangning freemsg(mctlp); 18110f1702c5SYu Xiangning if (msg->msg_namelen != 0) 18120f1702c5SYu Xiangning kmem_free(msg->msg_name, 18130f1702c5SYu Xiangning msg->msg_namelen); 18140f1702c5SYu Xiangning kmem_free(control, controllen); 18150f1702c5SYu Xiangning eprintsoline(so, error); 18160f1702c5SYu Xiangning goto out; 18170f1702c5SYu Xiangning } 18180f1702c5SYu Xiangning msg->msg_control = control; 18190f1702c5SYu Xiangning msg->msg_controllen = controllen; 18200f1702c5SYu Xiangning } 18210f1702c5SYu Xiangning 18220f1702c5SYu Xiangning freemsg(mctlp); 18230f1702c5SYu Xiangning goto out; 18240f1702c5SYu Xiangning } 18250f1702c5SYu Xiangning case T_OPTDATA_IND: { 18260f1702c5SYu Xiangning struct T_optdata_req *tdr; 18270f1702c5SYu Xiangning void *opt; 18280f1702c5SYu Xiangning t_uscalar_t optlen; 18290f1702c5SYu Xiangning 18300f1702c5SYu Xiangning tdr = (struct T_optdata_req *)mctlp->b_rptr; 18310f1702c5SYu Xiangning optlen = tdr->OPT_length; 18320f1702c5SYu Xiangning if (optlen != 0) { 18330f1702c5SYu Xiangning t_uscalar_t ncontrollen; 18340f1702c5SYu Xiangning /* 18350f1702c5SYu Xiangning * Determine how large cmsg buffer is needed. 18360f1702c5SYu Xiangning */ 18370f1702c5SYu Xiangning opt = sogetoff(mctlp, 18380f1702c5SYu Xiangning tpr->optdata_ind.OPT_offset, optlen, 18390f1702c5SYu Xiangning __TPI_ALIGN_SIZE); 18400f1702c5SYu Xiangning 18410f1702c5SYu Xiangning if (opt == NULL) { 18420f1702c5SYu Xiangning freemsg(mctlp); 18430f1702c5SYu Xiangning error = EPROTO; 18440f1702c5SYu Xiangning eprintsoline(so, error); 18450f1702c5SYu Xiangning goto out; 18460f1702c5SYu Xiangning } 18470f1702c5SYu Xiangning 18480f1702c5SYu Xiangning ncontrollen = so_cmsglen(mctlp, opt, optlen, 18490f1702c5SYu Xiangning !(flags & MSG_XPG4_2)); 18500f1702c5SYu Xiangning if (controllen != 0) 18510f1702c5SYu Xiangning controllen = ncontrollen; 18520f1702c5SYu Xiangning else if (ncontrollen != 0) 18530f1702c5SYu Xiangning msg->msg_flags |= MSG_CTRUNC; 18540f1702c5SYu Xiangning } else { 18550f1702c5SYu Xiangning controllen = 0; 18560f1702c5SYu Xiangning } 18570f1702c5SYu Xiangning 18580f1702c5SYu Xiangning if (controllen != 0) { 18590f1702c5SYu Xiangning /* 18600f1702c5SYu Xiangning * Return control msg to caller. 18610f1702c5SYu Xiangning * Caller handles truncation if length 18620f1702c5SYu Xiangning * exceeds msg_controllen. 18630f1702c5SYu Xiangning */ 18640f1702c5SYu Xiangning control = kmem_zalloc(controllen, KM_SLEEP); 18650f1702c5SYu Xiangning 18660f1702c5SYu Xiangning error = so_opt2cmsg(mctlp, opt, optlen, 18670f1702c5SYu Xiangning !(flags & MSG_XPG4_2), control, controllen); 18680f1702c5SYu Xiangning if (error) { 18690f1702c5SYu Xiangning freemsg(mctlp); 18700f1702c5SYu Xiangning kmem_free(control, controllen); 18710f1702c5SYu Xiangning eprintsoline(so, error); 18720f1702c5SYu Xiangning goto out; 18730f1702c5SYu Xiangning } 18740f1702c5SYu Xiangning msg->msg_control = control; 18750f1702c5SYu Xiangning msg->msg_controllen = controllen; 18760f1702c5SYu Xiangning } 18770f1702c5SYu Xiangning 18780f1702c5SYu Xiangning /* 18790f1702c5SYu Xiangning * Set msg_flags to MSG_EOR based on 18800f1702c5SYu Xiangning * DATA_flag and MOREDATA. 18810f1702c5SYu Xiangning */ 18820f1702c5SYu Xiangning mutex_enter(&so->so_lock); 18830f1702c5SYu Xiangning so->so_state &= ~SS_SAVEDEOR; 18840f1702c5SYu Xiangning if (!(tpr->data_ind.MORE_flag & 1)) { 18850f1702c5SYu Xiangning if (!(rval.r_val1 & MOREDATA)) 18860f1702c5SYu Xiangning msg->msg_flags |= MSG_EOR; 18870f1702c5SYu Xiangning else 18880f1702c5SYu Xiangning so->so_state |= SS_SAVEDEOR; 18890f1702c5SYu Xiangning } 18900f1702c5SYu Xiangning freemsg(mctlp); 18910f1702c5SYu Xiangning /* 18920f1702c5SYu Xiangning * If some data was received (i.e. not EOF) and the 18930f1702c5SYu Xiangning * read/recv* has not been satisfied wait for some more. 18940f1702c5SYu Xiangning * Not possible to wait if control info was received. 18950f1702c5SYu Xiangning */ 18960f1702c5SYu Xiangning if ((flags & MSG_WAITALL) && !(msg->msg_flags & MSG_EOR) && 18970f1702c5SYu Xiangning controllen == 0 && 18980f1702c5SYu Xiangning uiop->uio_resid != saved_resid && uiop->uio_resid > 0) { 18990f1702c5SYu Xiangning mutex_exit(&so->so_lock); 19008591a19aSAnders Persson flags |= MSG_NOMARK; 19010f1702c5SYu Xiangning goto retry; 19020f1702c5SYu Xiangning } 19030f1702c5SYu Xiangning goto out_locked; 19040f1702c5SYu Xiangning } 19050f1702c5SYu Xiangning default: 19060f1702c5SYu Xiangning cmn_err(CE_CONT, "so_recvmsg bad type %x \n", 19070f1702c5SYu Xiangning tpr->type); 19080f1702c5SYu Xiangning freemsg(mctlp); 19090f1702c5SYu Xiangning error = EPROTO; 19100f1702c5SYu Xiangning ASSERT(0); 19110f1702c5SYu Xiangning } 19120f1702c5SYu Xiangning out: 19130f1702c5SYu Xiangning mutex_enter(&so->so_lock); 19140f1702c5SYu Xiangning out_locked: 19150f1702c5SYu Xiangning ret = sod_rcv_done(so, suiop, uiop); 19160f1702c5SYu Xiangning if (ret != 0 && error == 0) 19170f1702c5SYu Xiangning error = ret; 19180f1702c5SYu Xiangning 19190f1702c5SYu Xiangning so_unlock_read(so); /* Clear SOREADLOCKED */ 19200f1702c5SYu Xiangning mutex_exit(&so->so_lock); 19210f1702c5SYu Xiangning 19220f1702c5SYu Xiangning SO_UNBLOCK_FALLBACK(so); 19230f1702c5SYu Xiangning 19240f1702c5SYu Xiangning return (error); 19250f1702c5SYu Xiangning } 19260f1702c5SYu Xiangning 19270f1702c5SYu Xiangning sonodeops_t so_sonodeops = { 19280f1702c5SYu Xiangning so_init, /* sop_init */ 19290f1702c5SYu Xiangning so_accept, /* sop_accept */ 19300f1702c5SYu Xiangning so_bind, /* sop_bind */ 19310f1702c5SYu Xiangning so_listen, /* sop_listen */ 19320f1702c5SYu Xiangning so_connect, /* sop_connect */ 19330f1702c5SYu Xiangning so_recvmsg, /* sop_recvmsg */ 19340f1702c5SYu Xiangning so_sendmsg, /* sop_sendmsg */ 19350f1702c5SYu Xiangning so_sendmblk, /* sop_sendmblk */ 19360f1702c5SYu Xiangning so_getpeername, /* sop_getpeername */ 19370f1702c5SYu Xiangning so_getsockname, /* sop_getsockname */ 19380f1702c5SYu Xiangning so_shutdown, /* sop_shutdown */ 19390f1702c5SYu Xiangning so_getsockopt, /* sop_getsockopt */ 19400f1702c5SYu Xiangning so_setsockopt, /* sop_setsockopt */ 19410f1702c5SYu Xiangning so_ioctl, /* sop_ioctl */ 19420f1702c5SYu Xiangning so_poll, /* sop_poll */ 19430f1702c5SYu Xiangning so_close, /* sop_close */ 19440f1702c5SYu Xiangning }; 19450f1702c5SYu Xiangning 19460f1702c5SYu Xiangning sock_upcalls_t so_upcalls = { 19470f1702c5SYu Xiangning so_newconn, 19480f1702c5SYu Xiangning so_connected, 19490f1702c5SYu Xiangning so_disconnected, 19500f1702c5SYu Xiangning so_opctl, 19510f1702c5SYu Xiangning so_queue_msg, 19520f1702c5SYu Xiangning so_set_prop, 19530f1702c5SYu Xiangning so_txq_full, 19540f1702c5SYu Xiangning so_signal_oob, 19550f1702c5SYu Xiangning so_zcopy_notify, 19563e95bd4aSAnders Persson so_set_error, 19573e95bd4aSAnders Persson so_closed 19580f1702c5SYu Xiangning }; 1959