18348SEric.Yu@Sun.COM /* 28348SEric.Yu@Sun.COM * CDDL HEADER START 38348SEric.Yu@Sun.COM * 48348SEric.Yu@Sun.COM * The contents of this file are subject to the terms of the 58348SEric.Yu@Sun.COM * Common Development and Distribution License (the "License"). 68348SEric.Yu@Sun.COM * You may not use this file except in compliance with the License. 78348SEric.Yu@Sun.COM * 88348SEric.Yu@Sun.COM * You can obtain a copy of the license at usr/src/OPENSOLARIS.LICENSE 98348SEric.Yu@Sun.COM * or http://www.opensolaris.org/os/licensing. 108348SEric.Yu@Sun.COM * See the License for the specific language governing permissions 118348SEric.Yu@Sun.COM * and limitations under the License. 128348SEric.Yu@Sun.COM * 138348SEric.Yu@Sun.COM * When distributing Covered Code, include this CDDL HEADER in each 148348SEric.Yu@Sun.COM * file and include the License file at usr/src/OPENSOLARIS.LICENSE. 158348SEric.Yu@Sun.COM * If applicable, add the following below this CDDL HEADER, with the 168348SEric.Yu@Sun.COM * fields enclosed by brackets "[]" replaced with your own identifying 178348SEric.Yu@Sun.COM * information: Portions Copyright [yyyy] [name of copyright owner] 188348SEric.Yu@Sun.COM * 198348SEric.Yu@Sun.COM * CDDL HEADER END 208348SEric.Yu@Sun.COM */ 218348SEric.Yu@Sun.COM 228348SEric.Yu@Sun.COM /* 2312198SEiji.Ota@Sun.COM * Copyright (c) 1999, 2010, Oracle and/or its affiliates. All rights reserved. 248348SEric.Yu@Sun.COM */ 258348SEric.Yu@Sun.COM 268348SEric.Yu@Sun.COM #include <sys/types.h> 278348SEric.Yu@Sun.COM #include <sys/param.h> 288348SEric.Yu@Sun.COM #include <sys/systm.h> 298348SEric.Yu@Sun.COM #include <sys/sysmacros.h> 308348SEric.Yu@Sun.COM #include <sys/debug.h> 318348SEric.Yu@Sun.COM #include <sys/cmn_err.h> 328348SEric.Yu@Sun.COM 338348SEric.Yu@Sun.COM #include <sys/stropts.h> 348348SEric.Yu@Sun.COM #include <sys/socket.h> 358348SEric.Yu@Sun.COM #include <sys/socketvar.h> 368348SEric.Yu@Sun.COM 378348SEric.Yu@Sun.COM #define _SUN_TPI_VERSION 2 388348SEric.Yu@Sun.COM #include <sys/tihdr.h> 398348SEric.Yu@Sun.COM #include <sys/sockio.h> 408348SEric.Yu@Sun.COM #include <sys/kmem_impl.h> 418348SEric.Yu@Sun.COM 428348SEric.Yu@Sun.COM #include <sys/strsubr.h> 438348SEric.Yu@Sun.COM #include <sys/strsun.h> 448348SEric.Yu@Sun.COM #include <sys/ddi.h> 458348SEric.Yu@Sun.COM #include <netinet/in.h> 468348SEric.Yu@Sun.COM #include <inet/ip.h> 478348SEric.Yu@Sun.COM 488348SEric.Yu@Sun.COM #include <fs/sockfs/sockcommon.h> 49*12643SAnders.Persson@Sun.COM #include <fs/sockfs/sockfilter_impl.h> 508348SEric.Yu@Sun.COM 518348SEric.Yu@Sun.COM #include <sys/socket_proto.h> 528348SEric.Yu@Sun.COM 538348SEric.Yu@Sun.COM #include <fs/sockfs/socktpi_impl.h> 549491SAnders.Persson@Sun.COM #include <fs/sockfs/sodirect.h> 558348SEric.Yu@Sun.COM #include <sys/tihdr.h> 568348SEric.Yu@Sun.COM #include <fs/sockfs/nl7c.h> 578348SEric.Yu@Sun.COM #include <inet/kssl/ksslapi.h> 588348SEric.Yu@Sun.COM 598348SEric.Yu@Sun.COM 608348SEric.Yu@Sun.COM extern int xnet_skip_checks; 618348SEric.Yu@Sun.COM extern int xnet_check_print; 628348SEric.Yu@Sun.COM 63*12643SAnders.Persson@Sun.COM static void so_queue_oob(struct sonode *, mblk_t *, size_t); 648348SEric.Yu@Sun.COM 658348SEric.Yu@Sun.COM 668348SEric.Yu@Sun.COM /*ARGSUSED*/ 678348SEric.Yu@Sun.COM int 688348SEric.Yu@Sun.COM so_accept_notsupp(struct sonode *lso, int fflag, 698348SEric.Yu@Sun.COM struct cred *cr, struct sonode **nsop) 708348SEric.Yu@Sun.COM { 718348SEric.Yu@Sun.COM return (EOPNOTSUPP); 728348SEric.Yu@Sun.COM } 738348SEric.Yu@Sun.COM 748348SEric.Yu@Sun.COM /*ARGSUSED*/ 758348SEric.Yu@Sun.COM int 768348SEric.Yu@Sun.COM so_listen_notsupp(struct sonode *so, int backlog, struct cred *cr) 778348SEric.Yu@Sun.COM { 788348SEric.Yu@Sun.COM return (EOPNOTSUPP); 798348SEric.Yu@Sun.COM } 808348SEric.Yu@Sun.COM 818348SEric.Yu@Sun.COM /*ARGSUSED*/ 828348SEric.Yu@Sun.COM int 838348SEric.Yu@Sun.COM so_getsockname_notsupp(struct sonode *so, struct sockaddr *sa, 848348SEric.Yu@Sun.COM socklen_t *len, struct cred *cr) 858348SEric.Yu@Sun.COM { 868348SEric.Yu@Sun.COM return (EOPNOTSUPP); 878348SEric.Yu@Sun.COM } 888348SEric.Yu@Sun.COM 898348SEric.Yu@Sun.COM /*ARGSUSED*/ 908348SEric.Yu@Sun.COM int 918348SEric.Yu@Sun.COM so_getpeername_notsupp(struct sonode *so, struct sockaddr *addr, 928348SEric.Yu@Sun.COM socklen_t *addrlen, boolean_t accept, struct cred *cr) 938348SEric.Yu@Sun.COM { 948348SEric.Yu@Sun.COM return (EOPNOTSUPP); 958348SEric.Yu@Sun.COM } 968348SEric.Yu@Sun.COM 978348SEric.Yu@Sun.COM /*ARGSUSED*/ 988348SEric.Yu@Sun.COM int 998348SEric.Yu@Sun.COM so_shutdown_notsupp(struct sonode *so, int how, struct cred *cr) 1008348SEric.Yu@Sun.COM { 1018348SEric.Yu@Sun.COM return (EOPNOTSUPP); 1028348SEric.Yu@Sun.COM } 1038348SEric.Yu@Sun.COM 1048348SEric.Yu@Sun.COM /*ARGSUSED*/ 1058348SEric.Yu@Sun.COM int 1068348SEric.Yu@Sun.COM so_sendmblk_notsupp(struct sonode *so, struct msghdr *msg, int fflag, 1078348SEric.Yu@Sun.COM struct cred *cr, mblk_t **mpp) 1088348SEric.Yu@Sun.COM { 1098348SEric.Yu@Sun.COM return (EOPNOTSUPP); 1108348SEric.Yu@Sun.COM } 1118348SEric.Yu@Sun.COM 1128348SEric.Yu@Sun.COM /* 1138348SEric.Yu@Sun.COM * Generic Socket Ops 1148348SEric.Yu@Sun.COM */ 1158348SEric.Yu@Sun.COM 1168348SEric.Yu@Sun.COM /* ARGSUSED */ 1178348SEric.Yu@Sun.COM int 1188348SEric.Yu@Sun.COM so_init(struct sonode *so, struct sonode *pso, struct cred *cr, int flags) 1198348SEric.Yu@Sun.COM { 1208348SEric.Yu@Sun.COM return (socket_init_common(so, pso, flags, cr)); 1218348SEric.Yu@Sun.COM } 1228348SEric.Yu@Sun.COM 1238348SEric.Yu@Sun.COM int 1248348SEric.Yu@Sun.COM so_bind(struct sonode *so, struct sockaddr *name, socklen_t namelen, 1258348SEric.Yu@Sun.COM int flags, struct cred *cr) 1268348SEric.Yu@Sun.COM { 1278348SEric.Yu@Sun.COM int error; 1288348SEric.Yu@Sun.COM 1298348SEric.Yu@Sun.COM SO_BLOCK_FALLBACK(so, SOP_BIND(so, name, namelen, flags, cr)); 1308348SEric.Yu@Sun.COM 1318348SEric.Yu@Sun.COM ASSERT(flags == _SOBIND_XPG4_2 || flags == _SOBIND_SOCKBSD); 1328348SEric.Yu@Sun.COM 1338348SEric.Yu@Sun.COM /* X/Open requires this check */ 1348348SEric.Yu@Sun.COM if ((so->so_state & SS_CANTSENDMORE) && !xnet_skip_checks) { 1358348SEric.Yu@Sun.COM if (xnet_check_print) { 1368348SEric.Yu@Sun.COM printf("sockfs: X/Open bind state check " 1378348SEric.Yu@Sun.COM "caused EINVAL\n"); 1388348SEric.Yu@Sun.COM } 1398348SEric.Yu@Sun.COM error = EINVAL; 1408348SEric.Yu@Sun.COM goto done; 1418348SEric.Yu@Sun.COM } 1428348SEric.Yu@Sun.COM 1438348SEric.Yu@Sun.COM /* 1448348SEric.Yu@Sun.COM * a bind to a NULL address is interpreted as unbind. So just 1458348SEric.Yu@Sun.COM * do the downcall. 1468348SEric.Yu@Sun.COM */ 1478348SEric.Yu@Sun.COM if (name == NULL) 1488348SEric.Yu@Sun.COM goto dobind; 1498348SEric.Yu@Sun.COM 1508348SEric.Yu@Sun.COM switch (so->so_family) { 1518348SEric.Yu@Sun.COM case AF_INET: 1528348SEric.Yu@Sun.COM if ((size_t)namelen != sizeof (sin_t)) { 1538348SEric.Yu@Sun.COM error = name->sa_family != so->so_family ? 1548348SEric.Yu@Sun.COM EAFNOSUPPORT : EINVAL; 1558348SEric.Yu@Sun.COM eprintsoline(so, error); 1568348SEric.Yu@Sun.COM goto done; 1578348SEric.Yu@Sun.COM } 1588348SEric.Yu@Sun.COM 1598348SEric.Yu@Sun.COM if ((flags & _SOBIND_XPG4_2) && 1608348SEric.Yu@Sun.COM (name->sa_family != so->so_family)) { 1618348SEric.Yu@Sun.COM /* 1628348SEric.Yu@Sun.COM * This check has to be made for X/Open 1638348SEric.Yu@Sun.COM * sockets however application failures have 1648348SEric.Yu@Sun.COM * been observed when it is applied to 1658348SEric.Yu@Sun.COM * all sockets. 1668348SEric.Yu@Sun.COM */ 1678348SEric.Yu@Sun.COM error = EAFNOSUPPORT; 1688348SEric.Yu@Sun.COM eprintsoline(so, error); 1698348SEric.Yu@Sun.COM goto done; 1708348SEric.Yu@Sun.COM } 1718348SEric.Yu@Sun.COM /* 1728348SEric.Yu@Sun.COM * Force a zero sa_family to match so_family. 1738348SEric.Yu@Sun.COM * 1748348SEric.Yu@Sun.COM * Some programs like inetd(1M) don't set the 1758348SEric.Yu@Sun.COM * family field. Other programs leave 1768348SEric.Yu@Sun.COM * sin_family set to garbage - SunOS 4.X does 1778348SEric.Yu@Sun.COM * not check the family field on a bind. 1788348SEric.Yu@Sun.COM * We use the family field that 1798348SEric.Yu@Sun.COM * was passed in to the socket() call. 1808348SEric.Yu@Sun.COM */ 1818348SEric.Yu@Sun.COM name->sa_family = so->so_family; 1828348SEric.Yu@Sun.COM break; 1838348SEric.Yu@Sun.COM 1848348SEric.Yu@Sun.COM case AF_INET6: { 1858348SEric.Yu@Sun.COM #ifdef DEBUG 1868348SEric.Yu@Sun.COM sin6_t *sin6 = (sin6_t *)name; 1878348SEric.Yu@Sun.COM #endif 1888348SEric.Yu@Sun.COM if ((size_t)namelen != sizeof (sin6_t)) { 1898348SEric.Yu@Sun.COM error = name->sa_family != so->so_family ? 1908348SEric.Yu@Sun.COM EAFNOSUPPORT : EINVAL; 1918348SEric.Yu@Sun.COM eprintsoline(so, error); 1928348SEric.Yu@Sun.COM goto done; 1938348SEric.Yu@Sun.COM } 1948348SEric.Yu@Sun.COM 1958348SEric.Yu@Sun.COM if (name->sa_family != so->so_family) { 1968348SEric.Yu@Sun.COM /* 1978348SEric.Yu@Sun.COM * With IPv6 we require the family to match 1988348SEric.Yu@Sun.COM * unlike in IPv4. 1998348SEric.Yu@Sun.COM */ 2008348SEric.Yu@Sun.COM error = EAFNOSUPPORT; 2018348SEric.Yu@Sun.COM eprintsoline(so, error); 2028348SEric.Yu@Sun.COM goto done; 2038348SEric.Yu@Sun.COM } 2048348SEric.Yu@Sun.COM #ifdef DEBUG 2058348SEric.Yu@Sun.COM /* 2068348SEric.Yu@Sun.COM * Verify that apps don't forget to clear 2078348SEric.Yu@Sun.COM * sin6_scope_id etc 2088348SEric.Yu@Sun.COM */ 2098348SEric.Yu@Sun.COM if (sin6->sin6_scope_id != 0 && 2108348SEric.Yu@Sun.COM !IN6_IS_ADDR_LINKSCOPE(&sin6->sin6_addr)) { 2118348SEric.Yu@Sun.COM zcmn_err(getzoneid(), CE_WARN, 2128348SEric.Yu@Sun.COM "bind with uninitialized sin6_scope_id " 2138348SEric.Yu@Sun.COM "(%d) on socket. Pid = %d\n", 2148348SEric.Yu@Sun.COM (int)sin6->sin6_scope_id, 2158348SEric.Yu@Sun.COM (int)curproc->p_pid); 2168348SEric.Yu@Sun.COM } 2178348SEric.Yu@Sun.COM if (sin6->__sin6_src_id != 0) { 2188348SEric.Yu@Sun.COM zcmn_err(getzoneid(), CE_WARN, 2198348SEric.Yu@Sun.COM "bind with uninitialized __sin6_src_id " 2208348SEric.Yu@Sun.COM "(%d) on socket. Pid = %d\n", 2218348SEric.Yu@Sun.COM (int)sin6->__sin6_src_id, 2228348SEric.Yu@Sun.COM (int)curproc->p_pid); 2238348SEric.Yu@Sun.COM } 2248348SEric.Yu@Sun.COM #endif /* DEBUG */ 2258348SEric.Yu@Sun.COM 2268348SEric.Yu@Sun.COM break; 2278348SEric.Yu@Sun.COM } 2288348SEric.Yu@Sun.COM default: 2298348SEric.Yu@Sun.COM /* Just pass the request to the protocol */ 2308348SEric.Yu@Sun.COM goto dobind; 2318348SEric.Yu@Sun.COM } 2328348SEric.Yu@Sun.COM 2338348SEric.Yu@Sun.COM /* 2348348SEric.Yu@Sun.COM * First we check if either NCA or KSSL has been enabled for 2358348SEric.Yu@Sun.COM * the requested address, and if so, we fall back to TPI. 2368348SEric.Yu@Sun.COM * If neither of those two services are enabled, then we just 2378348SEric.Yu@Sun.COM * pass the request to the protocol. 2388348SEric.Yu@Sun.COM * 2398348SEric.Yu@Sun.COM * Note that KSSL can only be enabled on a socket if NCA is NOT 2408348SEric.Yu@Sun.COM * enabled for that socket, hence the else-statement below. 2418348SEric.Yu@Sun.COM */ 2428348SEric.Yu@Sun.COM if (nl7c_enabled && ((so->so_family == AF_INET || 2438348SEric.Yu@Sun.COM so->so_family == AF_INET6) && 2448348SEric.Yu@Sun.COM nl7c_lookup_addr(name, namelen) != NULL)) { 2458348SEric.Yu@Sun.COM /* 2468348SEric.Yu@Sun.COM * NL7C is not supported in non-global zones, 2478348SEric.Yu@Sun.COM * we enforce this restriction here. 2488348SEric.Yu@Sun.COM */ 2498348SEric.Yu@Sun.COM if (so->so_zoneid == GLOBAL_ZONEID) { 2508348SEric.Yu@Sun.COM /* NCA should be used, so fall back to TPI */ 2518348SEric.Yu@Sun.COM error = so_tpi_fallback(so, cr); 2528348SEric.Yu@Sun.COM SO_UNBLOCK_FALLBACK(so); 2538348SEric.Yu@Sun.COM if (error) 2548348SEric.Yu@Sun.COM return (error); 2558348SEric.Yu@Sun.COM else 2568348SEric.Yu@Sun.COM return (SOP_BIND(so, name, namelen, flags, cr)); 2578348SEric.Yu@Sun.COM } 2588348SEric.Yu@Sun.COM } else if (so->so_type == SOCK_STREAM) { 2598348SEric.Yu@Sun.COM /* Check if KSSL has been configured for this address */ 2608348SEric.Yu@Sun.COM kssl_ent_t ent; 2618348SEric.Yu@Sun.COM kssl_endpt_type_t type; 2628348SEric.Yu@Sun.COM struct T_bind_req bind_req; 2638348SEric.Yu@Sun.COM mblk_t *mp; 2648348SEric.Yu@Sun.COM 2658348SEric.Yu@Sun.COM /* 2668348SEric.Yu@Sun.COM * TODO: Check with KSSL team if we could add a function call 2678348SEric.Yu@Sun.COM * that only queries whether KSSL is enabled for the given 2688348SEric.Yu@Sun.COM * address. 2698348SEric.Yu@Sun.COM */ 2708348SEric.Yu@Sun.COM bind_req.PRIM_type = T_BIND_REQ; 2718348SEric.Yu@Sun.COM bind_req.ADDR_length = namelen; 2728348SEric.Yu@Sun.COM bind_req.ADDR_offset = (t_scalar_t)sizeof (bind_req); 2738348SEric.Yu@Sun.COM mp = soallocproto2(&bind_req, sizeof (bind_req), 2748778SErik.Nordmark@Sun.COM name, namelen, 0, _ALLOC_SLEEP, cr); 2758348SEric.Yu@Sun.COM 2768348SEric.Yu@Sun.COM type = kssl_check_proxy(mp, so, &ent); 2778348SEric.Yu@Sun.COM freemsg(mp); 2788348SEric.Yu@Sun.COM 2798348SEric.Yu@Sun.COM if (type != KSSL_NO_PROXY) { 2808348SEric.Yu@Sun.COM /* 2818348SEric.Yu@Sun.COM * KSSL has been configured for this address, so 2828348SEric.Yu@Sun.COM * we must fall back to TPI. 2838348SEric.Yu@Sun.COM */ 2848348SEric.Yu@Sun.COM kssl_release_ent(ent, so, type); 2858348SEric.Yu@Sun.COM error = so_tpi_fallback(so, cr); 2868348SEric.Yu@Sun.COM SO_UNBLOCK_FALLBACK(so); 2878348SEric.Yu@Sun.COM if (error) 2888348SEric.Yu@Sun.COM return (error); 2898348SEric.Yu@Sun.COM else 2908348SEric.Yu@Sun.COM return (SOP_BIND(so, name, namelen, flags, cr)); 2918348SEric.Yu@Sun.COM } 2928348SEric.Yu@Sun.COM } 2938348SEric.Yu@Sun.COM 2948348SEric.Yu@Sun.COM dobind: 295*12643SAnders.Persson@Sun.COM if (so->so_filter_active == 0 || 296*12643SAnders.Persson@Sun.COM (error = sof_filter_bind(so, name, &namelen, cr)) < 0) { 297*12643SAnders.Persson@Sun.COM error = (*so->so_downcalls->sd_bind) 298*12643SAnders.Persson@Sun.COM (so->so_proto_handle, name, namelen, cr); 299*12643SAnders.Persson@Sun.COM } 3008348SEric.Yu@Sun.COM done: 3018348SEric.Yu@Sun.COM SO_UNBLOCK_FALLBACK(so); 3028348SEric.Yu@Sun.COM 3038348SEric.Yu@Sun.COM return (error); 3048348SEric.Yu@Sun.COM } 3058348SEric.Yu@Sun.COM 3068348SEric.Yu@Sun.COM int 3078348SEric.Yu@Sun.COM so_listen(struct sonode *so, int backlog, struct cred *cr) 3088348SEric.Yu@Sun.COM { 3098348SEric.Yu@Sun.COM int error = 0; 3108348SEric.Yu@Sun.COM 3118348SEric.Yu@Sun.COM ASSERT(MUTEX_NOT_HELD(&so->so_lock)); 3128348SEric.Yu@Sun.COM SO_BLOCK_FALLBACK(so, SOP_LISTEN(so, backlog, cr)); 3138348SEric.Yu@Sun.COM 314*12643SAnders.Persson@Sun.COM if ((so)->so_filter_active == 0 || 315*12643SAnders.Persson@Sun.COM (error = sof_filter_listen(so, &backlog, cr)) < 0) 316*12643SAnders.Persson@Sun.COM error = (*so->so_downcalls->sd_listen)(so->so_proto_handle, 317*12643SAnders.Persson@Sun.COM backlog, cr); 3188348SEric.Yu@Sun.COM 3198348SEric.Yu@Sun.COM SO_UNBLOCK_FALLBACK(so); 3208348SEric.Yu@Sun.COM 3218348SEric.Yu@Sun.COM return (error); 3228348SEric.Yu@Sun.COM } 3238348SEric.Yu@Sun.COM 3248348SEric.Yu@Sun.COM 3258348SEric.Yu@Sun.COM int 326*12643SAnders.Persson@Sun.COM so_connect(struct sonode *so, struct sockaddr *name, 3278348SEric.Yu@Sun.COM socklen_t namelen, int fflag, int flags, struct cred *cr) 3288348SEric.Yu@Sun.COM { 3298348SEric.Yu@Sun.COM int error = 0; 3308348SEric.Yu@Sun.COM sock_connid_t id; 3318348SEric.Yu@Sun.COM 3328348SEric.Yu@Sun.COM ASSERT(MUTEX_NOT_HELD(&so->so_lock)); 3338348SEric.Yu@Sun.COM SO_BLOCK_FALLBACK(so, SOP_CONNECT(so, name, namelen, fflag, flags, cr)); 3348348SEric.Yu@Sun.COM 3358348SEric.Yu@Sun.COM /* 3368348SEric.Yu@Sun.COM * If there is a pending error, return error 3378348SEric.Yu@Sun.COM * This can happen if a non blocking operation caused an error. 3388348SEric.Yu@Sun.COM */ 3398348SEric.Yu@Sun.COM 3408348SEric.Yu@Sun.COM if (so->so_error != 0) { 3418348SEric.Yu@Sun.COM mutex_enter(&so->so_lock); 3428348SEric.Yu@Sun.COM error = sogeterr(so, B_TRUE); 3438348SEric.Yu@Sun.COM mutex_exit(&so->so_lock); 3448348SEric.Yu@Sun.COM if (error != 0) 3458348SEric.Yu@Sun.COM goto done; 3468348SEric.Yu@Sun.COM } 3478348SEric.Yu@Sun.COM 348*12643SAnders.Persson@Sun.COM if (so->so_filter_active == 0 || 349*12643SAnders.Persson@Sun.COM (error = sof_filter_connect(so, (struct sockaddr *)name, 350*12643SAnders.Persson@Sun.COM &namelen, cr)) < 0) { 351*12643SAnders.Persson@Sun.COM error = (*so->so_downcalls->sd_connect)(so->so_proto_handle, 352*12643SAnders.Persson@Sun.COM name, namelen, &id, cr); 3538348SEric.Yu@Sun.COM 354*12643SAnders.Persson@Sun.COM if (error == EINPROGRESS) 355*12643SAnders.Persson@Sun.COM error = so_wait_connected(so, 356*12643SAnders.Persson@Sun.COM fflag & (FNONBLOCK|FNDELAY), id); 357*12643SAnders.Persson@Sun.COM } 3588348SEric.Yu@Sun.COM done: 3598348SEric.Yu@Sun.COM SO_UNBLOCK_FALLBACK(so); 3608348SEric.Yu@Sun.COM return (error); 3618348SEric.Yu@Sun.COM } 3628348SEric.Yu@Sun.COM 3638348SEric.Yu@Sun.COM /*ARGSUSED*/ 3648348SEric.Yu@Sun.COM int 3658348SEric.Yu@Sun.COM so_accept(struct sonode *so, int fflag, struct cred *cr, struct sonode **nsop) 3668348SEric.Yu@Sun.COM { 3678348SEric.Yu@Sun.COM int error = 0; 3688348SEric.Yu@Sun.COM struct sonode *nso; 3698348SEric.Yu@Sun.COM 3708348SEric.Yu@Sun.COM *nsop = NULL; 3718348SEric.Yu@Sun.COM 3728348SEric.Yu@Sun.COM SO_BLOCK_FALLBACK(so, SOP_ACCEPT(so, fflag, cr, nsop)); 3738348SEric.Yu@Sun.COM if ((so->so_state & SS_ACCEPTCONN) == 0) { 3748348SEric.Yu@Sun.COM SO_UNBLOCK_FALLBACK(so); 3758348SEric.Yu@Sun.COM return ((so->so_type == SOCK_DGRAM || so->so_type == SOCK_RAW) ? 3768348SEric.Yu@Sun.COM EOPNOTSUPP : EINVAL); 3778348SEric.Yu@Sun.COM } 3788348SEric.Yu@Sun.COM 3798348SEric.Yu@Sun.COM if ((error = so_acceptq_dequeue(so, (fflag & (FNONBLOCK|FNDELAY)), 3808348SEric.Yu@Sun.COM &nso)) == 0) { 3818348SEric.Yu@Sun.COM ASSERT(nso != NULL); 3828348SEric.Yu@Sun.COM 3838348SEric.Yu@Sun.COM /* finish the accept */ 384*12643SAnders.Persson@Sun.COM if ((so->so_filter_active > 0 && 385*12643SAnders.Persson@Sun.COM (error = sof_filter_accept(nso, cr)) > 0) || 386*12643SAnders.Persson@Sun.COM (error = (*so->so_downcalls->sd_accept)(so->so_proto_handle, 387*12643SAnders.Persson@Sun.COM nso->so_proto_handle, (sock_upper_handle_t)nso, cr)) != 0) { 3888348SEric.Yu@Sun.COM (void) socket_close(nso, 0, cr); 3898348SEric.Yu@Sun.COM socket_destroy(nso); 3908348SEric.Yu@Sun.COM } else { 3918348SEric.Yu@Sun.COM *nsop = nso; 3928348SEric.Yu@Sun.COM } 3938348SEric.Yu@Sun.COM } 3948348SEric.Yu@Sun.COM 3958348SEric.Yu@Sun.COM SO_UNBLOCK_FALLBACK(so); 3968348SEric.Yu@Sun.COM return (error); 3978348SEric.Yu@Sun.COM } 3988348SEric.Yu@Sun.COM 3998348SEric.Yu@Sun.COM int 4008348SEric.Yu@Sun.COM so_sendmsg(struct sonode *so, struct nmsghdr *msg, struct uio *uiop, 4018348SEric.Yu@Sun.COM struct cred *cr) 4028348SEric.Yu@Sun.COM { 4038348SEric.Yu@Sun.COM int error, flags; 4048348SEric.Yu@Sun.COM boolean_t dontblock; 4058348SEric.Yu@Sun.COM ssize_t orig_resid; 4068348SEric.Yu@Sun.COM mblk_t *mp; 4078348SEric.Yu@Sun.COM 4088348SEric.Yu@Sun.COM SO_BLOCK_FALLBACK(so, SOP_SENDMSG(so, msg, uiop, cr)); 4098348SEric.Yu@Sun.COM 4108348SEric.Yu@Sun.COM flags = msg->msg_flags; 4118348SEric.Yu@Sun.COM error = 0; 4128348SEric.Yu@Sun.COM dontblock = (flags & MSG_DONTWAIT) || 4138348SEric.Yu@Sun.COM (uiop->uio_fmode & (FNONBLOCK|FNDELAY)); 4148348SEric.Yu@Sun.COM 4158348SEric.Yu@Sun.COM if (!(flags & MSG_XPG4_2) && msg->msg_controllen != 0) { 4168348SEric.Yu@Sun.COM /* 4178348SEric.Yu@Sun.COM * Old way of passing fd's is not supported 4188348SEric.Yu@Sun.COM */ 4198348SEric.Yu@Sun.COM SO_UNBLOCK_FALLBACK(so); 4208348SEric.Yu@Sun.COM return (EOPNOTSUPP); 4218348SEric.Yu@Sun.COM } 4228348SEric.Yu@Sun.COM 4238348SEric.Yu@Sun.COM if ((so->so_mode & SM_ATOMIC) && 4248348SEric.Yu@Sun.COM uiop->uio_resid > so->so_proto_props.sopp_maxpsz && 4258348SEric.Yu@Sun.COM so->so_proto_props.sopp_maxpsz != -1) { 4268348SEric.Yu@Sun.COM SO_UNBLOCK_FALLBACK(so); 4278348SEric.Yu@Sun.COM return (EMSGSIZE); 4288348SEric.Yu@Sun.COM } 4298348SEric.Yu@Sun.COM 4308348SEric.Yu@Sun.COM /* 4318348SEric.Yu@Sun.COM * For atomic sends we will only do one iteration. 4328348SEric.Yu@Sun.COM */ 4338348SEric.Yu@Sun.COM do { 4348348SEric.Yu@Sun.COM if (so->so_state & SS_CANTSENDMORE) { 4358348SEric.Yu@Sun.COM error = EPIPE; 4368348SEric.Yu@Sun.COM break; 4378348SEric.Yu@Sun.COM } 4388348SEric.Yu@Sun.COM 4398348SEric.Yu@Sun.COM if (so->so_error != 0) { 4408348SEric.Yu@Sun.COM mutex_enter(&so->so_lock); 4418348SEric.Yu@Sun.COM error = sogeterr(so, B_TRUE); 4428348SEric.Yu@Sun.COM mutex_exit(&so->so_lock); 4438348SEric.Yu@Sun.COM if (error != 0) 4448348SEric.Yu@Sun.COM break; 4458348SEric.Yu@Sun.COM } 4468348SEric.Yu@Sun.COM 4478348SEric.Yu@Sun.COM /* 4488348SEric.Yu@Sun.COM * Send down OOB messages even if the send path is being 4498348SEric.Yu@Sun.COM * flow controlled (assuming the protocol supports OOB data). 4508348SEric.Yu@Sun.COM */ 4518348SEric.Yu@Sun.COM if (flags & MSG_OOB) { 4528348SEric.Yu@Sun.COM if ((so->so_mode & SM_EXDATA) == 0) { 4538348SEric.Yu@Sun.COM error = EOPNOTSUPP; 4548348SEric.Yu@Sun.COM break; 4558348SEric.Yu@Sun.COM } 456*12643SAnders.Persson@Sun.COM } else if (SO_SND_FLOWCTRLD(so)) { 4578348SEric.Yu@Sun.COM /* 4588348SEric.Yu@Sun.COM * Need to wait until the protocol is ready to receive 4598348SEric.Yu@Sun.COM * more data for transmission. 4608348SEric.Yu@Sun.COM */ 4618348SEric.Yu@Sun.COM if ((error = so_snd_wait_qnotfull(so, dontblock)) != 0) 4628348SEric.Yu@Sun.COM break; 4638348SEric.Yu@Sun.COM } 4648348SEric.Yu@Sun.COM 4658348SEric.Yu@Sun.COM /* 4668348SEric.Yu@Sun.COM * Time to send data to the protocol. We either copy the 4678348SEric.Yu@Sun.COM * data into mblks or pass the uio directly to the protocol. 4688348SEric.Yu@Sun.COM * We decide what to do based on the available down calls. 4698348SEric.Yu@Sun.COM */ 4708348SEric.Yu@Sun.COM if (so->so_downcalls->sd_send_uio != NULL) { 4718348SEric.Yu@Sun.COM error = (*so->so_downcalls->sd_send_uio) 4728348SEric.Yu@Sun.COM (so->so_proto_handle, uiop, msg, cr); 4738348SEric.Yu@Sun.COM if (error != 0) 4748348SEric.Yu@Sun.COM break; 4758348SEric.Yu@Sun.COM } else { 4768348SEric.Yu@Sun.COM /* save the resid in case of failure */ 4778348SEric.Yu@Sun.COM orig_resid = uiop->uio_resid; 4788348SEric.Yu@Sun.COM 4798348SEric.Yu@Sun.COM if ((mp = socopyinuio(uiop, 4808348SEric.Yu@Sun.COM so->so_proto_props.sopp_maxpsz, 4818348SEric.Yu@Sun.COM so->so_proto_props.sopp_wroff, 4828348SEric.Yu@Sun.COM so->so_proto_props.sopp_maxblk, 48311042SErik.Nordmark@Sun.COM so->so_proto_props.sopp_tail, &error)) == NULL) { 4848348SEric.Yu@Sun.COM break; 4858348SEric.Yu@Sun.COM } 4868348SEric.Yu@Sun.COM ASSERT(uiop->uio_resid >= 0); 4878348SEric.Yu@Sun.COM 488*12643SAnders.Persson@Sun.COM if (so->so_filter_active > 0 && 489*12643SAnders.Persson@Sun.COM ((mp = SOF_FILTER_DATA_OUT(so, mp, msg, cr, 490*12643SAnders.Persson@Sun.COM &error)) == NULL)) { 491*12643SAnders.Persson@Sun.COM if (error != 0) 492*12643SAnders.Persson@Sun.COM break; 493*12643SAnders.Persson@Sun.COM continue; 494*12643SAnders.Persson@Sun.COM } 4958348SEric.Yu@Sun.COM error = (*so->so_downcalls->sd_send) 4968348SEric.Yu@Sun.COM (so->so_proto_handle, mp, msg, cr); 4978348SEric.Yu@Sun.COM if (error != 0) { 4988348SEric.Yu@Sun.COM /* 4998348SEric.Yu@Sun.COM * The send failed. We do not have to free the 5008348SEric.Yu@Sun.COM * mblks, because that is the protocol's 5018348SEric.Yu@Sun.COM * responsibility. However, uio_resid must 5028348SEric.Yu@Sun.COM * remain accurate, so adjust that here. 5038348SEric.Yu@Sun.COM */ 5048348SEric.Yu@Sun.COM uiop->uio_resid = orig_resid; 5058348SEric.Yu@Sun.COM break; 5068348SEric.Yu@Sun.COM } 5078348SEric.Yu@Sun.COM } 5088348SEric.Yu@Sun.COM } while (uiop->uio_resid > 0); 5098348SEric.Yu@Sun.COM 5108348SEric.Yu@Sun.COM SO_UNBLOCK_FALLBACK(so); 5118348SEric.Yu@Sun.COM 5128348SEric.Yu@Sun.COM return (error); 5138348SEric.Yu@Sun.COM } 5148348SEric.Yu@Sun.COM 5158348SEric.Yu@Sun.COM int 516*12643SAnders.Persson@Sun.COM so_sendmblk_impl(struct sonode *so, struct nmsghdr *msg, int fflag, 517*12643SAnders.Persson@Sun.COM struct cred *cr, mblk_t **mpp, sof_instance_t *fil, 518*12643SAnders.Persson@Sun.COM boolean_t fil_inject) 5198348SEric.Yu@Sun.COM { 5208348SEric.Yu@Sun.COM int error; 5218348SEric.Yu@Sun.COM boolean_t dontblock; 5228348SEric.Yu@Sun.COM size_t size; 5238348SEric.Yu@Sun.COM mblk_t *mp = *mpp; 5248348SEric.Yu@Sun.COM 525*12643SAnders.Persson@Sun.COM if (so->so_downcalls->sd_send == NULL) 526*12643SAnders.Persson@Sun.COM return (EOPNOTSUPP); 5278348SEric.Yu@Sun.COM 5288348SEric.Yu@Sun.COM error = 0; 5298348SEric.Yu@Sun.COM dontblock = (msg->msg_flags & MSG_DONTWAIT) || 5308348SEric.Yu@Sun.COM (fflag & (FNONBLOCK|FNDELAY)); 5318348SEric.Yu@Sun.COM size = msgdsize(mp); 5328348SEric.Yu@Sun.COM 5338348SEric.Yu@Sun.COM if ((so->so_mode & SM_ATOMIC) && 5348348SEric.Yu@Sun.COM size > so->so_proto_props.sopp_maxpsz && 5358348SEric.Yu@Sun.COM so->so_proto_props.sopp_maxpsz != -1) { 5368348SEric.Yu@Sun.COM SO_UNBLOCK_FALLBACK(so); 5378348SEric.Yu@Sun.COM return (EMSGSIZE); 5388348SEric.Yu@Sun.COM } 5398348SEric.Yu@Sun.COM 5408348SEric.Yu@Sun.COM while (mp != NULL) { 5418348SEric.Yu@Sun.COM mblk_t *nmp, *last_mblk; 5428348SEric.Yu@Sun.COM size_t mlen; 5438348SEric.Yu@Sun.COM 5448348SEric.Yu@Sun.COM if (so->so_state & SS_CANTSENDMORE) { 5458348SEric.Yu@Sun.COM error = EPIPE; 5468348SEric.Yu@Sun.COM break; 5478348SEric.Yu@Sun.COM } 5488348SEric.Yu@Sun.COM if (so->so_error != 0) { 5498348SEric.Yu@Sun.COM mutex_enter(&so->so_lock); 5508348SEric.Yu@Sun.COM error = sogeterr(so, B_TRUE); 5518348SEric.Yu@Sun.COM mutex_exit(&so->so_lock); 5528348SEric.Yu@Sun.COM if (error != 0) 5538348SEric.Yu@Sun.COM break; 5548348SEric.Yu@Sun.COM } 555*12643SAnders.Persson@Sun.COM /* Socket filters are not flow controlled */ 556*12643SAnders.Persson@Sun.COM if (SO_SND_FLOWCTRLD(so) && !fil_inject) { 5578348SEric.Yu@Sun.COM /* 5588348SEric.Yu@Sun.COM * Need to wait until the protocol is ready to receive 5598348SEric.Yu@Sun.COM * more data for transmission. 5608348SEric.Yu@Sun.COM */ 5618348SEric.Yu@Sun.COM if ((error = so_snd_wait_qnotfull(so, dontblock)) != 0) 5628348SEric.Yu@Sun.COM break; 5638348SEric.Yu@Sun.COM } 5648348SEric.Yu@Sun.COM 5658348SEric.Yu@Sun.COM /* 5668348SEric.Yu@Sun.COM * We only allow so_maxpsz of data to be sent down to 5678348SEric.Yu@Sun.COM * the protocol at time. 5688348SEric.Yu@Sun.COM */ 5698348SEric.Yu@Sun.COM mlen = MBLKL(mp); 5708348SEric.Yu@Sun.COM nmp = mp->b_cont; 5718348SEric.Yu@Sun.COM last_mblk = mp; 5728348SEric.Yu@Sun.COM while (nmp != NULL) { 5738348SEric.Yu@Sun.COM mlen += MBLKL(nmp); 5748348SEric.Yu@Sun.COM if (mlen > so->so_proto_props.sopp_maxpsz) { 5758348SEric.Yu@Sun.COM last_mblk->b_cont = NULL; 5768348SEric.Yu@Sun.COM break; 5778348SEric.Yu@Sun.COM } 5788348SEric.Yu@Sun.COM last_mblk = nmp; 5798348SEric.Yu@Sun.COM nmp = nmp->b_cont; 5808348SEric.Yu@Sun.COM } 5818348SEric.Yu@Sun.COM 582*12643SAnders.Persson@Sun.COM if (so->so_filter_active > 0 && 583*12643SAnders.Persson@Sun.COM (mp = SOF_FILTER_DATA_OUT_FROM(so, fil, mp, msg, 584*12643SAnders.Persson@Sun.COM cr, &error)) == NULL) { 585*12643SAnders.Persson@Sun.COM *mpp = mp = nmp; 586*12643SAnders.Persson@Sun.COM if (error != 0) 587*12643SAnders.Persson@Sun.COM break; 588*12643SAnders.Persson@Sun.COM continue; 589*12643SAnders.Persson@Sun.COM } 5908348SEric.Yu@Sun.COM error = (*so->so_downcalls->sd_send) 5918348SEric.Yu@Sun.COM (so->so_proto_handle, mp, msg, cr); 5928348SEric.Yu@Sun.COM if (error != 0) { 5938348SEric.Yu@Sun.COM /* 5948348SEric.Yu@Sun.COM * The send failed. The protocol will free the mblks 5958348SEric.Yu@Sun.COM * that were sent down. Let the caller deal with the 5968348SEric.Yu@Sun.COM * rest. 5978348SEric.Yu@Sun.COM */ 5988348SEric.Yu@Sun.COM *mpp = nmp; 5998348SEric.Yu@Sun.COM break; 6008348SEric.Yu@Sun.COM } 6018348SEric.Yu@Sun.COM 6028348SEric.Yu@Sun.COM *mpp = mp = nmp; 6038348SEric.Yu@Sun.COM } 604*12643SAnders.Persson@Sun.COM /* Let the filter know whether the protocol is flow controlled */ 605*12643SAnders.Persson@Sun.COM if (fil_inject && error == 0 && SO_SND_FLOWCTRLD(so)) 606*12643SAnders.Persson@Sun.COM error = ENOSPC; 607*12643SAnders.Persson@Sun.COM 608*12643SAnders.Persson@Sun.COM return (error); 609*12643SAnders.Persson@Sun.COM } 610*12643SAnders.Persson@Sun.COM 611*12643SAnders.Persson@Sun.COM #pragma inline(so_sendmblk_impl) 612*12643SAnders.Persson@Sun.COM 613*12643SAnders.Persson@Sun.COM int 614*12643SAnders.Persson@Sun.COM so_sendmblk(struct sonode *so, struct nmsghdr *msg, int fflag, 615*12643SAnders.Persson@Sun.COM struct cred *cr, mblk_t **mpp) 616*12643SAnders.Persson@Sun.COM { 617*12643SAnders.Persson@Sun.COM int error; 618*12643SAnders.Persson@Sun.COM 619*12643SAnders.Persson@Sun.COM SO_BLOCK_FALLBACK(so, SOP_SENDMBLK(so, msg, fflag, cr, mpp)); 620*12643SAnders.Persson@Sun.COM 621*12643SAnders.Persson@Sun.COM if ((so->so_mode & SM_SENDFILESUPP) == 0) { 622*12643SAnders.Persson@Sun.COM SO_UNBLOCK_FALLBACK(so); 623*12643SAnders.Persson@Sun.COM return (EOPNOTSUPP); 624*12643SAnders.Persson@Sun.COM } 625*12643SAnders.Persson@Sun.COM 626*12643SAnders.Persson@Sun.COM error = so_sendmblk_impl(so, msg, fflag, cr, mpp, so->so_filter_top, 627*12643SAnders.Persson@Sun.COM B_FALSE); 6288348SEric.Yu@Sun.COM 6298348SEric.Yu@Sun.COM SO_UNBLOCK_FALLBACK(so); 6308348SEric.Yu@Sun.COM 6318348SEric.Yu@Sun.COM return (error); 6328348SEric.Yu@Sun.COM } 6338348SEric.Yu@Sun.COM 6348348SEric.Yu@Sun.COM int 6358348SEric.Yu@Sun.COM so_shutdown(struct sonode *so, int how, struct cred *cr) 6368348SEric.Yu@Sun.COM { 6378348SEric.Yu@Sun.COM int error; 6388348SEric.Yu@Sun.COM 6398348SEric.Yu@Sun.COM SO_BLOCK_FALLBACK(so, SOP_SHUTDOWN(so, how, cr)); 6408348SEric.Yu@Sun.COM 6418348SEric.Yu@Sun.COM /* 6428348SEric.Yu@Sun.COM * SunOS 4.X has no check for datagram sockets. 6438348SEric.Yu@Sun.COM * 5.X checks that it is connected (ENOTCONN) 6448348SEric.Yu@Sun.COM * X/Open requires that we check the connected state. 6458348SEric.Yu@Sun.COM */ 6468348SEric.Yu@Sun.COM if (!(so->so_state & SS_ISCONNECTED)) { 6478348SEric.Yu@Sun.COM if (!xnet_skip_checks) { 6488348SEric.Yu@Sun.COM error = ENOTCONN; 6498348SEric.Yu@Sun.COM if (xnet_check_print) { 6508348SEric.Yu@Sun.COM printf("sockfs: X/Open shutdown check " 6518348SEric.Yu@Sun.COM "caused ENOTCONN\n"); 6528348SEric.Yu@Sun.COM } 6538348SEric.Yu@Sun.COM } 6548348SEric.Yu@Sun.COM goto done; 6558348SEric.Yu@Sun.COM } 6568348SEric.Yu@Sun.COM 657*12643SAnders.Persson@Sun.COM if (so->so_filter_active == 0 || 658*12643SAnders.Persson@Sun.COM (error = sof_filter_shutdown(so, &how, cr)) < 0) 659*12643SAnders.Persson@Sun.COM error = ((*so->so_downcalls->sd_shutdown)(so->so_proto_handle, 660*12643SAnders.Persson@Sun.COM how, cr)); 6618348SEric.Yu@Sun.COM 6628348SEric.Yu@Sun.COM /* 6638348SEric.Yu@Sun.COM * Protocol agreed to shutdown. We need to flush the 6648348SEric.Yu@Sun.COM * receive buffer if the receive side is being shutdown. 6658348SEric.Yu@Sun.COM */ 6668348SEric.Yu@Sun.COM if (error == 0 && how != SHUT_WR) { 6678348SEric.Yu@Sun.COM mutex_enter(&so->so_lock); 6688348SEric.Yu@Sun.COM /* wait for active reader to finish */ 6698348SEric.Yu@Sun.COM (void) so_lock_read(so, 0); 6708348SEric.Yu@Sun.COM 6718348SEric.Yu@Sun.COM so_rcv_flush(so); 6728348SEric.Yu@Sun.COM 6738348SEric.Yu@Sun.COM so_unlock_read(so); 6748348SEric.Yu@Sun.COM mutex_exit(&so->so_lock); 6758348SEric.Yu@Sun.COM } 6768348SEric.Yu@Sun.COM 6778348SEric.Yu@Sun.COM done: 6788348SEric.Yu@Sun.COM SO_UNBLOCK_FALLBACK(so); 6798348SEric.Yu@Sun.COM return (error); 6808348SEric.Yu@Sun.COM } 6818348SEric.Yu@Sun.COM 6828348SEric.Yu@Sun.COM int 6838348SEric.Yu@Sun.COM so_getsockname(struct sonode *so, struct sockaddr *addr, 6848348SEric.Yu@Sun.COM socklen_t *addrlen, struct cred *cr) 6858348SEric.Yu@Sun.COM { 6868348SEric.Yu@Sun.COM int error; 6878348SEric.Yu@Sun.COM 6888348SEric.Yu@Sun.COM SO_BLOCK_FALLBACK(so, SOP_GETSOCKNAME(so, addr, addrlen, cr)); 6898348SEric.Yu@Sun.COM 690*12643SAnders.Persson@Sun.COM if (so->so_filter_active == 0 || 691*12643SAnders.Persson@Sun.COM (error = sof_filter_getsockname(so, addr, addrlen, cr)) < 0) 692*12643SAnders.Persson@Sun.COM error = (*so->so_downcalls->sd_getsockname) 693*12643SAnders.Persson@Sun.COM (so->so_proto_handle, addr, addrlen, cr); 6948348SEric.Yu@Sun.COM 6958348SEric.Yu@Sun.COM SO_UNBLOCK_FALLBACK(so); 6968348SEric.Yu@Sun.COM return (error); 6978348SEric.Yu@Sun.COM } 6988348SEric.Yu@Sun.COM 6998348SEric.Yu@Sun.COM int 7008348SEric.Yu@Sun.COM so_getpeername(struct sonode *so, struct sockaddr *addr, 7018348SEric.Yu@Sun.COM socklen_t *addrlen, boolean_t accept, struct cred *cr) 7028348SEric.Yu@Sun.COM { 7038348SEric.Yu@Sun.COM int error; 7048348SEric.Yu@Sun.COM 7058348SEric.Yu@Sun.COM SO_BLOCK_FALLBACK(so, SOP_GETPEERNAME(so, addr, addrlen, accept, cr)); 7068348SEric.Yu@Sun.COM 7078348SEric.Yu@Sun.COM if (accept) { 7088348SEric.Yu@Sun.COM error = (*so->so_downcalls->sd_getpeername) 7098348SEric.Yu@Sun.COM (so->so_proto_handle, addr, addrlen, cr); 7108348SEric.Yu@Sun.COM } else if (!(so->so_state & SS_ISCONNECTED)) { 7118348SEric.Yu@Sun.COM error = ENOTCONN; 7128348SEric.Yu@Sun.COM } else if ((so->so_state & SS_CANTSENDMORE) && !xnet_skip_checks) { 7138348SEric.Yu@Sun.COM /* Added this check for X/Open */ 7148348SEric.Yu@Sun.COM error = EINVAL; 7158348SEric.Yu@Sun.COM if (xnet_check_print) { 7168348SEric.Yu@Sun.COM printf("sockfs: X/Open getpeername check => EINVAL\n"); 7178348SEric.Yu@Sun.COM } 718*12643SAnders.Persson@Sun.COM } else if (so->so_filter_active == 0 || 719*12643SAnders.Persson@Sun.COM (error = sof_filter_getpeername(so, addr, addrlen, cr)) < 0) { 7208348SEric.Yu@Sun.COM error = (*so->so_downcalls->sd_getpeername) 7218348SEric.Yu@Sun.COM (so->so_proto_handle, addr, addrlen, cr); 7228348SEric.Yu@Sun.COM } 7238348SEric.Yu@Sun.COM 7248348SEric.Yu@Sun.COM SO_UNBLOCK_FALLBACK(so); 7258348SEric.Yu@Sun.COM return (error); 7268348SEric.Yu@Sun.COM } 7278348SEric.Yu@Sun.COM 7288348SEric.Yu@Sun.COM int 7298348SEric.Yu@Sun.COM so_getsockopt(struct sonode *so, int level, int option_name, 7308348SEric.Yu@Sun.COM void *optval, socklen_t *optlenp, int flags, struct cred *cr) 7318348SEric.Yu@Sun.COM { 7328348SEric.Yu@Sun.COM int error = 0; 7338348SEric.Yu@Sun.COM 734*12643SAnders.Persson@Sun.COM if (level == SOL_FILTER) 735*12643SAnders.Persson@Sun.COM return (sof_getsockopt(so, option_name, optval, optlenp, cr)); 736*12643SAnders.Persson@Sun.COM 7378348SEric.Yu@Sun.COM SO_BLOCK_FALLBACK(so, 7388348SEric.Yu@Sun.COM SOP_GETSOCKOPT(so, level, option_name, optval, optlenp, flags, cr)); 7398348SEric.Yu@Sun.COM 740*12643SAnders.Persson@Sun.COM if ((so->so_filter_active == 0 || 741*12643SAnders.Persson@Sun.COM (error = sof_filter_getsockopt(so, level, option_name, optval, 742*12643SAnders.Persson@Sun.COM optlenp, cr)) < 0) && 743*12643SAnders.Persson@Sun.COM (error = socket_getopt_common(so, level, option_name, optval, 744*12643SAnders.Persson@Sun.COM optlenp, flags)) < 0) { 7458348SEric.Yu@Sun.COM error = (*so->so_downcalls->sd_getsockopt) 7468348SEric.Yu@Sun.COM (so->so_proto_handle, level, option_name, optval, optlenp, 7478348SEric.Yu@Sun.COM cr); 7488348SEric.Yu@Sun.COM if (error == ENOPROTOOPT) { 7498348SEric.Yu@Sun.COM if (level == SOL_SOCKET) { 7508348SEric.Yu@Sun.COM /* 7518348SEric.Yu@Sun.COM * If a protocol does not support a particular 7528348SEric.Yu@Sun.COM * socket option, set can fail (not allowed) 7538348SEric.Yu@Sun.COM * but get can not fail. This is the previous 7548348SEric.Yu@Sun.COM * sockfs bahvior. 7558348SEric.Yu@Sun.COM */ 7568348SEric.Yu@Sun.COM switch (option_name) { 7578348SEric.Yu@Sun.COM case SO_LINGER: 7588348SEric.Yu@Sun.COM if (*optlenp < (t_uscalar_t) 7598348SEric.Yu@Sun.COM sizeof (struct linger)) { 7608348SEric.Yu@Sun.COM error = EINVAL; 7618348SEric.Yu@Sun.COM break; 7628348SEric.Yu@Sun.COM } 7638348SEric.Yu@Sun.COM error = 0; 7648348SEric.Yu@Sun.COM bzero(optval, sizeof (struct linger)); 7658348SEric.Yu@Sun.COM *optlenp = sizeof (struct linger); 7668348SEric.Yu@Sun.COM break; 7678348SEric.Yu@Sun.COM case SO_RCVTIMEO: 7688348SEric.Yu@Sun.COM case SO_SNDTIMEO: 7698348SEric.Yu@Sun.COM if (*optlenp < (t_uscalar_t) 7708348SEric.Yu@Sun.COM sizeof (struct timeval)) { 7718348SEric.Yu@Sun.COM error = EINVAL; 7728348SEric.Yu@Sun.COM break; 7738348SEric.Yu@Sun.COM } 7748348SEric.Yu@Sun.COM error = 0; 7758348SEric.Yu@Sun.COM bzero(optval, sizeof (struct timeval)); 7768348SEric.Yu@Sun.COM *optlenp = sizeof (struct timeval); 7778348SEric.Yu@Sun.COM break; 7788348SEric.Yu@Sun.COM case SO_SND_BUFINFO: 7798348SEric.Yu@Sun.COM if (*optlenp < (t_uscalar_t) 7808348SEric.Yu@Sun.COM sizeof (struct so_snd_bufinfo)) { 7818348SEric.Yu@Sun.COM error = EINVAL; 7828348SEric.Yu@Sun.COM break; 7838348SEric.Yu@Sun.COM } 7848348SEric.Yu@Sun.COM error = 0; 7858348SEric.Yu@Sun.COM bzero(optval, 7868348SEric.Yu@Sun.COM sizeof (struct so_snd_bufinfo)); 7878348SEric.Yu@Sun.COM *optlenp = 7888348SEric.Yu@Sun.COM sizeof (struct so_snd_bufinfo); 7898348SEric.Yu@Sun.COM break; 7908348SEric.Yu@Sun.COM case SO_DEBUG: 7918348SEric.Yu@Sun.COM case SO_REUSEADDR: 7928348SEric.Yu@Sun.COM case SO_KEEPALIVE: 7938348SEric.Yu@Sun.COM case SO_DONTROUTE: 7948348SEric.Yu@Sun.COM case SO_BROADCAST: 7958348SEric.Yu@Sun.COM case SO_USELOOPBACK: 7968348SEric.Yu@Sun.COM case SO_OOBINLINE: 7978348SEric.Yu@Sun.COM case SO_DGRAM_ERRIND: 7988348SEric.Yu@Sun.COM case SO_SNDBUF: 7998348SEric.Yu@Sun.COM case SO_RCVBUF: 8008348SEric.Yu@Sun.COM error = 0; 8018348SEric.Yu@Sun.COM *((int32_t *)optval) = 0; 8028348SEric.Yu@Sun.COM *optlenp = sizeof (int32_t); 8038348SEric.Yu@Sun.COM break; 8048348SEric.Yu@Sun.COM default: 8058348SEric.Yu@Sun.COM break; 8068348SEric.Yu@Sun.COM } 8078348SEric.Yu@Sun.COM } 8088348SEric.Yu@Sun.COM } 8098348SEric.Yu@Sun.COM } 8108348SEric.Yu@Sun.COM 8118348SEric.Yu@Sun.COM SO_UNBLOCK_FALLBACK(so); 8128348SEric.Yu@Sun.COM return (error); 8138348SEric.Yu@Sun.COM } 8148348SEric.Yu@Sun.COM 8158348SEric.Yu@Sun.COM int 8168348SEric.Yu@Sun.COM so_setsockopt(struct sonode *so, int level, int option_name, 8178348SEric.Yu@Sun.COM const void *optval, socklen_t optlen, struct cred *cr) 8188348SEric.Yu@Sun.COM { 8198348SEric.Yu@Sun.COM int error = 0; 8208612SAnders.Persson@Sun.COM struct timeval tl; 8218612SAnders.Persson@Sun.COM const void *opt = optval; 8228348SEric.Yu@Sun.COM 823*12643SAnders.Persson@Sun.COM if (level == SOL_FILTER) 824*12643SAnders.Persson@Sun.COM return (sof_setsockopt(so, option_name, optval, optlen, cr)); 825*12643SAnders.Persson@Sun.COM 8268348SEric.Yu@Sun.COM SO_BLOCK_FALLBACK(so, 8278348SEric.Yu@Sun.COM SOP_SETSOCKOPT(so, level, option_name, optval, optlen, cr)); 8288348SEric.Yu@Sun.COM 8298348SEric.Yu@Sun.COM /* X/Open requires this check */ 8308348SEric.Yu@Sun.COM if (so->so_state & SS_CANTSENDMORE && !xnet_skip_checks) { 8318348SEric.Yu@Sun.COM SO_UNBLOCK_FALLBACK(so); 8328348SEric.Yu@Sun.COM if (xnet_check_print) 8338348SEric.Yu@Sun.COM printf("sockfs: X/Open setsockopt check => EINVAL\n"); 8348348SEric.Yu@Sun.COM return (EINVAL); 8358348SEric.Yu@Sun.COM } 8368348SEric.Yu@Sun.COM 837*12643SAnders.Persson@Sun.COM if (so->so_filter_active > 0 && 838*12643SAnders.Persson@Sun.COM (error = sof_filter_setsockopt(so, level, option_name, 839*12643SAnders.Persson@Sun.COM (void *)optval, &optlen, cr)) >= 0) 840*12643SAnders.Persson@Sun.COM goto done; 841*12643SAnders.Persson@Sun.COM 8428465SEric.Yu@Sun.COM if (level == SOL_SOCKET) { 8438465SEric.Yu@Sun.COM switch (option_name) { 8448465SEric.Yu@Sun.COM case SO_RCVTIMEO: 8458465SEric.Yu@Sun.COM case SO_SNDTIMEO: { 8468586Sshenjian /* 8478586Sshenjian * We pass down these two options to protocol in order 8488586Sshenjian * to support some third part protocols which need to 8498586Sshenjian * know them. For those protocols which don't care 8508586Sshenjian * these two options, simply return 0. 8518586Sshenjian */ 8528465SEric.Yu@Sun.COM clock_t t_usec; 8538348SEric.Yu@Sun.COM 8548575Sshenjian if (get_udatamodel() == DATAMODEL_NONE || 8558575Sshenjian get_udatamodel() == DATAMODEL_NATIVE) { 8568489Sshenjian if (optlen != sizeof (struct timeval)) { 8578489Sshenjian error = EINVAL; 8588489Sshenjian goto done; 8598489Sshenjian } 8608489Sshenjian bcopy((struct timeval *)optval, &tl, 8618489Sshenjian sizeof (struct timeval)); 8628489Sshenjian } else { 8638489Sshenjian if (optlen != sizeof (struct timeval32)) { 8648489Sshenjian error = EINVAL; 8658489Sshenjian goto done; 8668489Sshenjian } 8678489Sshenjian TIMEVAL32_TO_TIMEVAL(&tl, 8688489Sshenjian (struct timeval32 *)optval); 8698465SEric.Yu@Sun.COM } 8708612SAnders.Persson@Sun.COM opt = &tl; 8718612SAnders.Persson@Sun.COM optlen = sizeof (tl); 8728489Sshenjian t_usec = tl.tv_sec * 1000 * 1000 + tl.tv_usec; 8738465SEric.Yu@Sun.COM mutex_enter(&so->so_lock); 8748465SEric.Yu@Sun.COM if (option_name == SO_RCVTIMEO) 8758465SEric.Yu@Sun.COM so->so_rcvtimeo = drv_usectohz(t_usec); 8768465SEric.Yu@Sun.COM else 8778465SEric.Yu@Sun.COM so->so_sndtimeo = drv_usectohz(t_usec); 8788465SEric.Yu@Sun.COM mutex_exit(&so->so_lock); 8798586Sshenjian break; 8808348SEric.Yu@Sun.COM } 8818465SEric.Yu@Sun.COM case SO_RCVBUF: 8828465SEric.Yu@Sun.COM /* 8838465SEric.Yu@Sun.COM * XXX XPG 4.2 applications retrieve SO_RCVBUF from 8848465SEric.Yu@Sun.COM * sockfs since the transport might adjust the value 8858465SEric.Yu@Sun.COM * and not return exactly what was set by the 8868465SEric.Yu@Sun.COM * application. 8878465SEric.Yu@Sun.COM */ 8888465SEric.Yu@Sun.COM so->so_xpg_rcvbuf = *(int32_t *)optval; 8898465SEric.Yu@Sun.COM break; 8908465SEric.Yu@Sun.COM } 8918348SEric.Yu@Sun.COM } 8928348SEric.Yu@Sun.COM error = (*so->so_downcalls->sd_setsockopt) 8938612SAnders.Persson@Sun.COM (so->so_proto_handle, level, option_name, opt, optlen, cr); 8948489Sshenjian done: 8958348SEric.Yu@Sun.COM SO_UNBLOCK_FALLBACK(so); 8968348SEric.Yu@Sun.COM return (error); 8978348SEric.Yu@Sun.COM } 8988348SEric.Yu@Sun.COM 8998348SEric.Yu@Sun.COM int 9008348SEric.Yu@Sun.COM so_ioctl(struct sonode *so, int cmd, intptr_t arg, int mode, 9018348SEric.Yu@Sun.COM struct cred *cr, int32_t *rvalp) 9028348SEric.Yu@Sun.COM { 9038348SEric.Yu@Sun.COM int error = 0; 9048348SEric.Yu@Sun.COM 9058348SEric.Yu@Sun.COM SO_BLOCK_FALLBACK(so, SOP_IOCTL(so, cmd, arg, mode, cr, rvalp)); 9068348SEric.Yu@Sun.COM 9078348SEric.Yu@Sun.COM /* 9088348SEric.Yu@Sun.COM * If there is a pending error, return error 9098348SEric.Yu@Sun.COM * This can happen if a non blocking operation caused an error. 9108348SEric.Yu@Sun.COM */ 9118348SEric.Yu@Sun.COM if (so->so_error != 0) { 9128348SEric.Yu@Sun.COM mutex_enter(&so->so_lock); 9138348SEric.Yu@Sun.COM error = sogeterr(so, B_TRUE); 9148348SEric.Yu@Sun.COM mutex_exit(&so->so_lock); 9158348SEric.Yu@Sun.COM if (error != 0) 9168348SEric.Yu@Sun.COM goto done; 9178348SEric.Yu@Sun.COM } 9188348SEric.Yu@Sun.COM 9198348SEric.Yu@Sun.COM /* 9208348SEric.Yu@Sun.COM * calling strioc can result in the socket falling back to TPI, 9218348SEric.Yu@Sun.COM * if that is supported. 9228348SEric.Yu@Sun.COM */ 923*12643SAnders.Persson@Sun.COM if ((so->so_filter_active == 0 || 924*12643SAnders.Persson@Sun.COM (error = sof_filter_ioctl(so, cmd, arg, mode, 925*12643SAnders.Persson@Sun.COM rvalp, cr)) < 0) && 926*12643SAnders.Persson@Sun.COM (error = socket_ioctl_common(so, cmd, arg, mode, cr, rvalp)) < 0 && 9278348SEric.Yu@Sun.COM (error = socket_strioc_common(so, cmd, arg, mode, cr, rvalp)) < 0) { 9288348SEric.Yu@Sun.COM error = (*so->so_downcalls->sd_ioctl)(so->so_proto_handle, 9298348SEric.Yu@Sun.COM cmd, arg, mode, rvalp, cr); 9308348SEric.Yu@Sun.COM } 9318348SEric.Yu@Sun.COM 9328348SEric.Yu@Sun.COM done: 9338348SEric.Yu@Sun.COM SO_UNBLOCK_FALLBACK(so); 9348348SEric.Yu@Sun.COM 9358348SEric.Yu@Sun.COM return (error); 9368348SEric.Yu@Sun.COM } 9378348SEric.Yu@Sun.COM 9388348SEric.Yu@Sun.COM int 9398348SEric.Yu@Sun.COM so_poll(struct sonode *so, short events, int anyyet, short *reventsp, 9408348SEric.Yu@Sun.COM struct pollhead **phpp) 9418348SEric.Yu@Sun.COM { 9428348SEric.Yu@Sun.COM int state = so->so_state; 9438348SEric.Yu@Sun.COM *reventsp = 0; 9448348SEric.Yu@Sun.COM 9458861SRao.Shoaib@Sun.COM /* 9468861SRao.Shoaib@Sun.COM * In sockets the errors are represented as input/output events 9478861SRao.Shoaib@Sun.COM */ 9488348SEric.Yu@Sun.COM if (so->so_error != 0 && 9498861SRao.Shoaib@Sun.COM ((POLLIN|POLLRDNORM|POLLOUT) & events) != 0) { 9508348SEric.Yu@Sun.COM *reventsp = (POLLIN|POLLRDNORM|POLLOUT) & events; 9518348SEric.Yu@Sun.COM return (0); 9528348SEric.Yu@Sun.COM } 9538348SEric.Yu@Sun.COM 9548348SEric.Yu@Sun.COM /* 9558861SRao.Shoaib@Sun.COM * If the socket is in a state where it can send data 9568861SRao.Shoaib@Sun.COM * turn on POLLWRBAND and POLLOUT events. 9578348SEric.Yu@Sun.COM */ 9588861SRao.Shoaib@Sun.COM if ((so->so_mode & SM_CONNREQUIRED) == 0 || (state & SS_ISCONNECTED)) { 9598861SRao.Shoaib@Sun.COM /* 9608861SRao.Shoaib@Sun.COM * out of band data is allowed even if the connection 9618861SRao.Shoaib@Sun.COM * is flow controlled 9628861SRao.Shoaib@Sun.COM */ 9638861SRao.Shoaib@Sun.COM *reventsp |= POLLWRBAND & events; 964*12643SAnders.Persson@Sun.COM if (!SO_SND_FLOWCTRLD(so)) { 9658861SRao.Shoaib@Sun.COM /* 9668861SRao.Shoaib@Sun.COM * As long as there is buffer to send data 9678861SRao.Shoaib@Sun.COM * turn on POLLOUT events 9688861SRao.Shoaib@Sun.COM */ 9698861SRao.Shoaib@Sun.COM *reventsp |= POLLOUT & events; 9708861SRao.Shoaib@Sun.COM } 9718348SEric.Yu@Sun.COM } 9728348SEric.Yu@Sun.COM 9738348SEric.Yu@Sun.COM /* 9748348SEric.Yu@Sun.COM * Turn on POLLIN whenever there is data on the receive queue, 9758348SEric.Yu@Sun.COM * or the socket is in a state where no more data will be received. 9768348SEric.Yu@Sun.COM * Also, if the socket is accepting connections, flip the bit if 9778348SEric.Yu@Sun.COM * there is something on the queue. 9788427SAnders.Persson@Sun.COM * 9798427SAnders.Persson@Sun.COM * We do an initial check for events without holding locks. However, 9808427SAnders.Persson@Sun.COM * if there are no event available, then we redo the check for POLLIN 9818427SAnders.Persson@Sun.COM * events under the lock. 9828348SEric.Yu@Sun.COM */ 9838348SEric.Yu@Sun.COM 9848348SEric.Yu@Sun.COM /* Pending connections */ 985*12643SAnders.Persson@Sun.COM if (!list_is_empty(&so->so_acceptq_list)) 9868348SEric.Yu@Sun.COM *reventsp |= (POLLIN|POLLRDNORM) & events; 9878348SEric.Yu@Sun.COM 9888348SEric.Yu@Sun.COM /* Data */ 9898348SEric.Yu@Sun.COM /* so_downcalls is null for sctp */ 9908348SEric.Yu@Sun.COM if (so->so_downcalls != NULL && so->so_downcalls->sd_poll != NULL) { 9918348SEric.Yu@Sun.COM *reventsp |= (*so->so_downcalls->sd_poll) 9928348SEric.Yu@Sun.COM (so->so_proto_handle, events & SO_PROTO_POLLEV, anyyet, 9938348SEric.Yu@Sun.COM CRED()) & events; 9948348SEric.Yu@Sun.COM ASSERT((*reventsp & ~events) == 0); 9958348SEric.Yu@Sun.COM /* do not recheck events */ 9968348SEric.Yu@Sun.COM events &= ~SO_PROTO_POLLEV; 9978348SEric.Yu@Sun.COM } else { 9988348SEric.Yu@Sun.COM if (SO_HAVE_DATA(so)) 9998348SEric.Yu@Sun.COM *reventsp |= (POLLIN|POLLRDNORM) & events; 10008348SEric.Yu@Sun.COM 10018348SEric.Yu@Sun.COM /* Urgent data */ 10028861SRao.Shoaib@Sun.COM if ((state & SS_OOBPEND) != 0) { 10038861SRao.Shoaib@Sun.COM *reventsp |= (POLLRDBAND | POLLPRI) & events; 10048861SRao.Shoaib@Sun.COM } 10058348SEric.Yu@Sun.COM } 10068348SEric.Yu@Sun.COM 10078348SEric.Yu@Sun.COM if (!*reventsp && !anyyet) { 10088348SEric.Yu@Sun.COM /* Check for read events again, but this time under lock */ 10098348SEric.Yu@Sun.COM if (events & (POLLIN|POLLRDNORM)) { 10108348SEric.Yu@Sun.COM mutex_enter(&so->so_lock); 1011*12643SAnders.Persson@Sun.COM if (SO_HAVE_DATA(so) || 1012*12643SAnders.Persson@Sun.COM !list_is_empty(&so->so_acceptq_list)) { 10138348SEric.Yu@Sun.COM mutex_exit(&so->so_lock); 10148348SEric.Yu@Sun.COM *reventsp |= (POLLIN|POLLRDNORM) & events; 10158348SEric.Yu@Sun.COM return (0); 10168348SEric.Yu@Sun.COM } else { 10178348SEric.Yu@Sun.COM so->so_pollev |= SO_POLLEV_IN; 10188348SEric.Yu@Sun.COM mutex_exit(&so->so_lock); 10198348SEric.Yu@Sun.COM } 10208348SEric.Yu@Sun.COM } 10218348SEric.Yu@Sun.COM *phpp = &so->so_poll_list; 10228348SEric.Yu@Sun.COM } 10238348SEric.Yu@Sun.COM return (0); 10248348SEric.Yu@Sun.COM } 10258348SEric.Yu@Sun.COM 10268348SEric.Yu@Sun.COM /* 10278348SEric.Yu@Sun.COM * Generic Upcalls 10288348SEric.Yu@Sun.COM */ 10298348SEric.Yu@Sun.COM void 10308348SEric.Yu@Sun.COM so_connected(sock_upper_handle_t sock_handle, sock_connid_t id, 10318348SEric.Yu@Sun.COM cred_t *peer_cred, pid_t peer_cpid) 10328348SEric.Yu@Sun.COM { 10338348SEric.Yu@Sun.COM struct sonode *so = (struct sonode *)sock_handle; 10348348SEric.Yu@Sun.COM 10358348SEric.Yu@Sun.COM mutex_enter(&so->so_lock); 10368348SEric.Yu@Sun.COM ASSERT(so->so_proto_handle != NULL); 10378348SEric.Yu@Sun.COM 10388348SEric.Yu@Sun.COM if (peer_cred != NULL) { 10398348SEric.Yu@Sun.COM if (so->so_peercred != NULL) 10408348SEric.Yu@Sun.COM crfree(so->so_peercred); 10418348SEric.Yu@Sun.COM crhold(peer_cred); 10428348SEric.Yu@Sun.COM so->so_peercred = peer_cred; 10438348SEric.Yu@Sun.COM so->so_cpid = peer_cpid; 10448348SEric.Yu@Sun.COM } 10458348SEric.Yu@Sun.COM 10468348SEric.Yu@Sun.COM so->so_proto_connid = id; 10478348SEric.Yu@Sun.COM soisconnected(so); 10488348SEric.Yu@Sun.COM /* 10498348SEric.Yu@Sun.COM * Wake ones who're waiting for conn to become established. 10508348SEric.Yu@Sun.COM */ 10518348SEric.Yu@Sun.COM so_notify_connected(so); 10528348SEric.Yu@Sun.COM } 10538348SEric.Yu@Sun.COM 10548348SEric.Yu@Sun.COM int 10558348SEric.Yu@Sun.COM so_disconnected(sock_upper_handle_t sock_handle, sock_connid_t id, int error) 10568348SEric.Yu@Sun.COM { 10578348SEric.Yu@Sun.COM struct sonode *so = (struct sonode *)sock_handle; 1058*12643SAnders.Persson@Sun.COM boolean_t connect_failed; 10598348SEric.Yu@Sun.COM 10608348SEric.Yu@Sun.COM mutex_enter(&so->so_lock); 1061*12643SAnders.Persson@Sun.COM connect_failed = so->so_state & SS_ISCONNECTED; 10628348SEric.Yu@Sun.COM so->so_proto_connid = id; 10638348SEric.Yu@Sun.COM soisdisconnected(so, error); 1064*12643SAnders.Persson@Sun.COM so_notify_disconnected(so, connect_failed, error); 10658348SEric.Yu@Sun.COM 10668348SEric.Yu@Sun.COM return (0); 10678348SEric.Yu@Sun.COM } 10688348SEric.Yu@Sun.COM 10698348SEric.Yu@Sun.COM void 10708348SEric.Yu@Sun.COM so_opctl(sock_upper_handle_t sock_handle, sock_opctl_action_t action, 10718348SEric.Yu@Sun.COM uintptr_t arg) 10728348SEric.Yu@Sun.COM { 10738348SEric.Yu@Sun.COM struct sonode *so = (struct sonode *)sock_handle; 10748348SEric.Yu@Sun.COM 10758348SEric.Yu@Sun.COM switch (action) { 10768348SEric.Yu@Sun.COM case SOCK_OPCTL_SHUT_SEND: 10778348SEric.Yu@Sun.COM mutex_enter(&so->so_lock); 10788348SEric.Yu@Sun.COM socantsendmore(so); 10798348SEric.Yu@Sun.COM so_notify_disconnecting(so); 10808348SEric.Yu@Sun.COM break; 10818348SEric.Yu@Sun.COM case SOCK_OPCTL_SHUT_RECV: { 10828348SEric.Yu@Sun.COM mutex_enter(&so->so_lock); 10838348SEric.Yu@Sun.COM socantrcvmore(so); 10848348SEric.Yu@Sun.COM so_notify_eof(so); 10858348SEric.Yu@Sun.COM break; 10868348SEric.Yu@Sun.COM } 10878348SEric.Yu@Sun.COM case SOCK_OPCTL_ENAB_ACCEPT: 10888348SEric.Yu@Sun.COM mutex_enter(&so->so_lock); 10898348SEric.Yu@Sun.COM so->so_state |= SS_ACCEPTCONN; 10908348SEric.Yu@Sun.COM so->so_backlog = (unsigned int)arg; 1091*12643SAnders.Persson@Sun.COM /* 1092*12643SAnders.Persson@Sun.COM * The protocol can stop generating newconn upcalls when 1093*12643SAnders.Persson@Sun.COM * the backlog is full, so to make sure the listener does 1094*12643SAnders.Persson@Sun.COM * not end up with a queue full of deferred connections 1095*12643SAnders.Persson@Sun.COM * we reduce the backlog by one. Thus the listener will 1096*12643SAnders.Persson@Sun.COM * start closing deferred connections before the backlog 1097*12643SAnders.Persson@Sun.COM * is full. 1098*12643SAnders.Persson@Sun.COM */ 1099*12643SAnders.Persson@Sun.COM if (so->so_filter_active > 0) 1100*12643SAnders.Persson@Sun.COM so->so_backlog = MAX(1, so->so_backlog - 1); 11018348SEric.Yu@Sun.COM mutex_exit(&so->so_lock); 11028348SEric.Yu@Sun.COM break; 11038348SEric.Yu@Sun.COM default: 11048348SEric.Yu@Sun.COM ASSERT(0); 11058348SEric.Yu@Sun.COM break; 11068348SEric.Yu@Sun.COM } 11078348SEric.Yu@Sun.COM } 11088348SEric.Yu@Sun.COM 11098348SEric.Yu@Sun.COM void 11108348SEric.Yu@Sun.COM so_txq_full(sock_upper_handle_t sock_handle, boolean_t qfull) 11118348SEric.Yu@Sun.COM { 11128348SEric.Yu@Sun.COM struct sonode *so = (struct sonode *)sock_handle; 11138348SEric.Yu@Sun.COM 11148348SEric.Yu@Sun.COM if (qfull) { 11158348SEric.Yu@Sun.COM so_snd_qfull(so); 11168348SEric.Yu@Sun.COM } else { 11178348SEric.Yu@Sun.COM so_snd_qnotfull(so); 11188348SEric.Yu@Sun.COM mutex_enter(&so->so_lock); 1119*12643SAnders.Persson@Sun.COM /* so_notify_writable drops so_lock */ 11208348SEric.Yu@Sun.COM so_notify_writable(so); 11218348SEric.Yu@Sun.COM } 11228348SEric.Yu@Sun.COM } 11238348SEric.Yu@Sun.COM 11248348SEric.Yu@Sun.COM sock_upper_handle_t 11258348SEric.Yu@Sun.COM so_newconn(sock_upper_handle_t parenthandle, 11268348SEric.Yu@Sun.COM sock_lower_handle_t proto_handle, sock_downcalls_t *sock_downcalls, 11278348SEric.Yu@Sun.COM struct cred *peer_cred, pid_t peer_cpid, sock_upcalls_t **sock_upcallsp) 11288348SEric.Yu@Sun.COM { 11298348SEric.Yu@Sun.COM struct sonode *so = (struct sonode *)parenthandle; 11308348SEric.Yu@Sun.COM struct sonode *nso; 11318348SEric.Yu@Sun.COM int error; 11328348SEric.Yu@Sun.COM 11338348SEric.Yu@Sun.COM ASSERT(proto_handle != NULL); 11348348SEric.Yu@Sun.COM 11358348SEric.Yu@Sun.COM if ((so->so_state & SS_ACCEPTCONN) == 0 || 1136*12643SAnders.Persson@Sun.COM (so->so_acceptq_len >= so->so_backlog && 1137*12643SAnders.Persson@Sun.COM (so->so_filter_active == 0 || !sof_sonode_drop_deferred(so)))) { 1138*12643SAnders.Persson@Sun.COM return (NULL); 1139*12643SAnders.Persson@Sun.COM } 11408348SEric.Yu@Sun.COM 11418348SEric.Yu@Sun.COM nso = socket_newconn(so, proto_handle, sock_downcalls, SOCKET_NOSLEEP, 11428348SEric.Yu@Sun.COM &error); 11438348SEric.Yu@Sun.COM if (nso == NULL) 11448348SEric.Yu@Sun.COM return (NULL); 11458348SEric.Yu@Sun.COM 11468348SEric.Yu@Sun.COM if (peer_cred != NULL) { 11478348SEric.Yu@Sun.COM crhold(peer_cred); 11488348SEric.Yu@Sun.COM nso->so_peercred = peer_cred; 11498348SEric.Yu@Sun.COM nso->so_cpid = peer_cpid; 11508348SEric.Yu@Sun.COM } 1151*12643SAnders.Persson@Sun.COM nso->so_listener = so; 11528348SEric.Yu@Sun.COM 11538820SAnders.Persson@Sun.COM /* 11548820SAnders.Persson@Sun.COM * The new socket (nso), proto_handle and sock_upcallsp are all 11558820SAnders.Persson@Sun.COM * valid at this point. But as soon as nso is placed in the accept 11568820SAnders.Persson@Sun.COM * queue that can no longer be assumed (since an accept() thread may 11578820SAnders.Persson@Sun.COM * pull it off the queue and close the socket). 11588820SAnders.Persson@Sun.COM */ 11598820SAnders.Persson@Sun.COM *sock_upcallsp = &so_upcalls; 11608820SAnders.Persson@Sun.COM 1161*12643SAnders.Persson@Sun.COM mutex_enter(&so->so_acceptq_lock); 1162*12643SAnders.Persson@Sun.COM if (so->so_state & (SS_CLOSING|SS_FALLBACK_PENDING|SS_FALLBACK_COMP)) { 1163*12643SAnders.Persson@Sun.COM mutex_exit(&so->so_acceptq_lock); 1164*12643SAnders.Persson@Sun.COM ASSERT(nso->so_count == 1); 1165*12643SAnders.Persson@Sun.COM nso->so_count--; 1166*12643SAnders.Persson@Sun.COM /* drop proto ref */ 1167*12643SAnders.Persson@Sun.COM VN_RELE(SOTOV(nso)); 1168*12643SAnders.Persson@Sun.COM socket_destroy(nso); 1169*12643SAnders.Persson@Sun.COM return (NULL); 1170*12643SAnders.Persson@Sun.COM } else { 1171*12643SAnders.Persson@Sun.COM so->so_acceptq_len++; 1172*12643SAnders.Persson@Sun.COM if (nso->so_state & SS_FIL_DEFER) { 1173*12643SAnders.Persson@Sun.COM list_insert_tail(&so->so_acceptq_defer, nso); 1174*12643SAnders.Persson@Sun.COM mutex_exit(&so->so_acceptq_lock); 1175*12643SAnders.Persson@Sun.COM } else { 1176*12643SAnders.Persson@Sun.COM list_insert_tail(&so->so_acceptq_list, nso); 1177*12643SAnders.Persson@Sun.COM cv_signal(&so->so_acceptq_cv); 1178*12643SAnders.Persson@Sun.COM mutex_exit(&so->so_acceptq_lock); 1179*12643SAnders.Persson@Sun.COM mutex_enter(&so->so_lock); 1180*12643SAnders.Persson@Sun.COM so_notify_newconn(so); 1181*12643SAnders.Persson@Sun.COM } 11828820SAnders.Persson@Sun.COM 1183*12643SAnders.Persson@Sun.COM return ((sock_upper_handle_t)nso); 1184*12643SAnders.Persson@Sun.COM } 11858348SEric.Yu@Sun.COM } 11868348SEric.Yu@Sun.COM 11878348SEric.Yu@Sun.COM void 11888348SEric.Yu@Sun.COM so_set_prop(sock_upper_handle_t sock_handle, struct sock_proto_props *soppp) 11898348SEric.Yu@Sun.COM { 11908348SEric.Yu@Sun.COM struct sonode *so; 11918348SEric.Yu@Sun.COM 11928348SEric.Yu@Sun.COM so = (struct sonode *)sock_handle; 11938348SEric.Yu@Sun.COM 11948348SEric.Yu@Sun.COM mutex_enter(&so->so_lock); 11958348SEric.Yu@Sun.COM 11968348SEric.Yu@Sun.COM if (soppp->sopp_flags & SOCKOPT_MAXBLK) 11978348SEric.Yu@Sun.COM so->so_proto_props.sopp_maxblk = soppp->sopp_maxblk; 11988348SEric.Yu@Sun.COM if (soppp->sopp_flags & SOCKOPT_WROFF) 11998348SEric.Yu@Sun.COM so->so_proto_props.sopp_wroff = soppp->sopp_wroff; 12008348SEric.Yu@Sun.COM if (soppp->sopp_flags & SOCKOPT_TAIL) 12018348SEric.Yu@Sun.COM so->so_proto_props.sopp_tail = soppp->sopp_tail; 12028348SEric.Yu@Sun.COM if (soppp->sopp_flags & SOCKOPT_RCVHIWAT) 12038348SEric.Yu@Sun.COM so->so_proto_props.sopp_rxhiwat = soppp->sopp_rxhiwat; 12048348SEric.Yu@Sun.COM if (soppp->sopp_flags & SOCKOPT_RCVLOWAT) 12058348SEric.Yu@Sun.COM so->so_proto_props.sopp_rxlowat = soppp->sopp_rxlowat; 12068348SEric.Yu@Sun.COM if (soppp->sopp_flags & SOCKOPT_MAXPSZ) 12078348SEric.Yu@Sun.COM so->so_proto_props.sopp_maxpsz = soppp->sopp_maxpsz; 12088348SEric.Yu@Sun.COM if (soppp->sopp_flags & SOCKOPT_MINPSZ) 12098348SEric.Yu@Sun.COM so->so_proto_props.sopp_minpsz = soppp->sopp_minpsz; 12108348SEric.Yu@Sun.COM if (soppp->sopp_flags & SOCKOPT_ZCOPY) { 12118348SEric.Yu@Sun.COM if (soppp->sopp_zcopyflag & ZCVMSAFE) { 12128348SEric.Yu@Sun.COM so->so_proto_props.sopp_zcopyflag |= STZCVMSAFE; 12138348SEric.Yu@Sun.COM so->so_proto_props.sopp_zcopyflag &= ~STZCVMUNSAFE; 12148348SEric.Yu@Sun.COM } else if (soppp->sopp_zcopyflag & ZCVMUNSAFE) { 12158348SEric.Yu@Sun.COM so->so_proto_props.sopp_zcopyflag |= STZCVMUNSAFE; 12168348SEric.Yu@Sun.COM so->so_proto_props.sopp_zcopyflag &= ~STZCVMSAFE; 12178348SEric.Yu@Sun.COM } 12188348SEric.Yu@Sun.COM 12198348SEric.Yu@Sun.COM if (soppp->sopp_zcopyflag & COPYCACHED) { 12208348SEric.Yu@Sun.COM so->so_proto_props.sopp_zcopyflag |= STRCOPYCACHED; 12218348SEric.Yu@Sun.COM } 12228348SEric.Yu@Sun.COM } 12238348SEric.Yu@Sun.COM if (soppp->sopp_flags & SOCKOPT_OOBINLINE) 12248348SEric.Yu@Sun.COM so->so_proto_props.sopp_oobinline = soppp->sopp_oobinline; 12258348SEric.Yu@Sun.COM if (soppp->sopp_flags & SOCKOPT_RCVTIMER) 12268348SEric.Yu@Sun.COM so->so_proto_props.sopp_rcvtimer = soppp->sopp_rcvtimer; 12278348SEric.Yu@Sun.COM if (soppp->sopp_flags & SOCKOPT_RCVTHRESH) 12288348SEric.Yu@Sun.COM so->so_proto_props.sopp_rcvthresh = soppp->sopp_rcvthresh; 12298348SEric.Yu@Sun.COM if (soppp->sopp_flags & SOCKOPT_MAXADDRLEN) 12308348SEric.Yu@Sun.COM so->so_proto_props.sopp_maxaddrlen = soppp->sopp_maxaddrlen; 123110103SAnders.Persson@Sun.COM if (soppp->sopp_flags & SOCKOPT_LOOPBACK) 123210103SAnders.Persson@Sun.COM so->so_proto_props.sopp_loopback = soppp->sopp_loopback; 12338348SEric.Yu@Sun.COM 12348348SEric.Yu@Sun.COM mutex_exit(&so->so_lock); 12358348SEric.Yu@Sun.COM 1236*12643SAnders.Persson@Sun.COM if (so->so_filter_active > 0) { 1237*12643SAnders.Persson@Sun.COM sof_instance_t *inst; 1238*12643SAnders.Persson@Sun.COM ssize_t maxblk; 1239*12643SAnders.Persson@Sun.COM ushort_t wroff, tail; 1240*12643SAnders.Persson@Sun.COM maxblk = so->so_proto_props.sopp_maxblk; 1241*12643SAnders.Persson@Sun.COM wroff = so->so_proto_props.sopp_wroff; 1242*12643SAnders.Persson@Sun.COM tail = so->so_proto_props.sopp_tail; 1243*12643SAnders.Persson@Sun.COM for (inst = so->so_filter_bottom; inst != NULL; 1244*12643SAnders.Persson@Sun.COM inst = inst->sofi_prev) { 1245*12643SAnders.Persson@Sun.COM if (SOF_INTERESTED(inst, mblk_prop)) { 1246*12643SAnders.Persson@Sun.COM (*inst->sofi_ops->sofop_mblk_prop)( 1247*12643SAnders.Persson@Sun.COM (sof_handle_t)inst, inst->sofi_cookie, 1248*12643SAnders.Persson@Sun.COM &maxblk, &wroff, &tail); 1249*12643SAnders.Persson@Sun.COM } 1250*12643SAnders.Persson@Sun.COM } 1251*12643SAnders.Persson@Sun.COM mutex_enter(&so->so_lock); 1252*12643SAnders.Persson@Sun.COM so->so_proto_props.sopp_maxblk = maxblk; 1253*12643SAnders.Persson@Sun.COM so->so_proto_props.sopp_wroff = wroff; 1254*12643SAnders.Persson@Sun.COM so->so_proto_props.sopp_tail = tail; 1255*12643SAnders.Persson@Sun.COM mutex_exit(&so->so_lock); 1256*12643SAnders.Persson@Sun.COM } 12578348SEric.Yu@Sun.COM #ifdef DEBUG 12588348SEric.Yu@Sun.COM soppp->sopp_flags &= ~(SOCKOPT_MAXBLK | SOCKOPT_WROFF | SOCKOPT_TAIL | 12598348SEric.Yu@Sun.COM SOCKOPT_RCVHIWAT | SOCKOPT_RCVLOWAT | SOCKOPT_MAXPSZ | 12608348SEric.Yu@Sun.COM SOCKOPT_ZCOPY | SOCKOPT_OOBINLINE | SOCKOPT_RCVTIMER | 126110103SAnders.Persson@Sun.COM SOCKOPT_RCVTHRESH | SOCKOPT_MAXADDRLEN | SOCKOPT_MINPSZ | 126210103SAnders.Persson@Sun.COM SOCKOPT_LOOPBACK); 12638348SEric.Yu@Sun.COM ASSERT(soppp->sopp_flags == 0); 12648348SEric.Yu@Sun.COM #endif 12658348SEric.Yu@Sun.COM } 12668348SEric.Yu@Sun.COM 12678348SEric.Yu@Sun.COM /* ARGSUSED */ 12688348SEric.Yu@Sun.COM ssize_t 1269*12643SAnders.Persson@Sun.COM so_queue_msg_impl(struct sonode *so, mblk_t *mp, 1270*12643SAnders.Persson@Sun.COM size_t msg_size, int flags, int *errorp, boolean_t *force_pushp, 1271*12643SAnders.Persson@Sun.COM sof_instance_t *filter) 12728348SEric.Yu@Sun.COM { 12738348SEric.Yu@Sun.COM boolean_t force_push = B_TRUE; 12748348SEric.Yu@Sun.COM int space_left; 12758348SEric.Yu@Sun.COM sodirect_t *sodp = so->so_direct; 12768348SEric.Yu@Sun.COM 12778348SEric.Yu@Sun.COM ASSERT(errorp != NULL); 12788348SEric.Yu@Sun.COM *errorp = 0; 12798348SEric.Yu@Sun.COM if (mp == NULL) { 128012198SEiji.Ota@Sun.COM if (so->so_downcalls->sd_recv_uio != NULL) { 12818348SEric.Yu@Sun.COM mutex_enter(&so->so_lock); 12828348SEric.Yu@Sun.COM /* the notify functions will drop the lock */ 12838348SEric.Yu@Sun.COM if (flags & MSG_OOB) 12848348SEric.Yu@Sun.COM so_notify_oobdata(so, IS_SO_OOB_INLINE(so)); 12858348SEric.Yu@Sun.COM else 12868348SEric.Yu@Sun.COM so_notify_data(so, msg_size); 12878348SEric.Yu@Sun.COM return (0); 12888348SEric.Yu@Sun.COM } 128912198SEiji.Ota@Sun.COM ASSERT(msg_size == 0); 12908348SEric.Yu@Sun.COM mutex_enter(&so->so_lock); 1291*12643SAnders.Persson@Sun.COM goto space_check; 12928348SEric.Yu@Sun.COM } 12938348SEric.Yu@Sun.COM 12948348SEric.Yu@Sun.COM ASSERT(mp->b_next == NULL); 12958348SEric.Yu@Sun.COM ASSERT(DB_TYPE(mp) == M_DATA || DB_TYPE(mp) == M_PROTO); 12968348SEric.Yu@Sun.COM ASSERT(msg_size == msgdsize(mp)); 12978348SEric.Yu@Sun.COM 12988348SEric.Yu@Sun.COM if (DB_TYPE(mp) == M_PROTO && !__TPI_PRIM_ISALIGNED(mp->b_rptr)) { 12998348SEric.Yu@Sun.COM /* The read pointer is not aligned correctly for TPI */ 13008348SEric.Yu@Sun.COM zcmn_err(getzoneid(), CE_WARN, 13018348SEric.Yu@Sun.COM "sockfs: Unaligned TPI message received. rptr = %p\n", 13028348SEric.Yu@Sun.COM (void *)mp->b_rptr); 13038348SEric.Yu@Sun.COM freemsg(mp); 13049491SAnders.Persson@Sun.COM mutex_enter(&so->so_lock); 13059491SAnders.Persson@Sun.COM if (sodp != NULL) 13069491SAnders.Persson@Sun.COM SOD_UIOAFINI(sodp); 1307*12643SAnders.Persson@Sun.COM goto space_check; 1308*12643SAnders.Persson@Sun.COM } 13098348SEric.Yu@Sun.COM 1310*12643SAnders.Persson@Sun.COM if (so->so_filter_active > 0) { 1311*12643SAnders.Persson@Sun.COM for (; filter != NULL; filter = filter->sofi_prev) { 1312*12643SAnders.Persson@Sun.COM if (!SOF_INTERESTED(filter, data_in)) 1313*12643SAnders.Persson@Sun.COM continue; 1314*12643SAnders.Persson@Sun.COM mp = (*filter->sofi_ops->sofop_data_in)( 1315*12643SAnders.Persson@Sun.COM (sof_handle_t)filter, filter->sofi_cookie, mp, 1316*12643SAnders.Persson@Sun.COM flags, &msg_size); 1317*12643SAnders.Persson@Sun.COM ASSERT(msgdsize(mp) == msg_size); 1318*12643SAnders.Persson@Sun.COM DTRACE_PROBE2(filter__data, (sof_instance_t), filter, 1319*12643SAnders.Persson@Sun.COM (mblk_t *), mp); 1320*12643SAnders.Persson@Sun.COM /* Data was consumed/dropped, just do space check */ 1321*12643SAnders.Persson@Sun.COM if (msg_size == 0) { 1322*12643SAnders.Persson@Sun.COM mutex_enter(&so->so_lock); 1323*12643SAnders.Persson@Sun.COM goto space_check; 1324*12643SAnders.Persson@Sun.COM } 1325*12643SAnders.Persson@Sun.COM } 13268348SEric.Yu@Sun.COM } 13278348SEric.Yu@Sun.COM 1328*12643SAnders.Persson@Sun.COM if (flags & MSG_OOB) { 1329*12643SAnders.Persson@Sun.COM so_queue_oob(so, mp, msg_size); 1330*12643SAnders.Persson@Sun.COM mutex_enter(&so->so_lock); 1331*12643SAnders.Persson@Sun.COM goto space_check; 1332*12643SAnders.Persson@Sun.COM } 1333*12643SAnders.Persson@Sun.COM 1334*12643SAnders.Persson@Sun.COM if (force_pushp != NULL) 1335*12643SAnders.Persson@Sun.COM force_push = *force_pushp; 1336*12643SAnders.Persson@Sun.COM 13378348SEric.Yu@Sun.COM mutex_enter(&so->so_lock); 13388963SAnders.Persson@Sun.COM if (so->so_state & (SS_FALLBACK_DRAIN | SS_FALLBACK_COMP)) { 13399491SAnders.Persson@Sun.COM if (sodp != NULL) 13409491SAnders.Persson@Sun.COM SOD_DISABLE(sodp); 13418348SEric.Yu@Sun.COM mutex_exit(&so->so_lock); 13428348SEric.Yu@Sun.COM *errorp = EOPNOTSUPP; 13438348SEric.Yu@Sun.COM return (-1); 13448348SEric.Yu@Sun.COM } 1345*12643SAnders.Persson@Sun.COM if (so->so_state & (SS_CANTRCVMORE | SS_CLOSING)) { 13468348SEric.Yu@Sun.COM freemsg(mp); 13479491SAnders.Persson@Sun.COM if (sodp != NULL) 13489491SAnders.Persson@Sun.COM SOD_DISABLE(sodp); 13498348SEric.Yu@Sun.COM mutex_exit(&so->so_lock); 13508348SEric.Yu@Sun.COM return (0); 13518348SEric.Yu@Sun.COM } 13528348SEric.Yu@Sun.COM 13538348SEric.Yu@Sun.COM /* process the mblk via I/OAT if capable */ 13549491SAnders.Persson@Sun.COM if (sodp != NULL && sodp->sod_enabled) { 13558348SEric.Yu@Sun.COM if (DB_TYPE(mp) == M_DATA) { 13569491SAnders.Persson@Sun.COM sod_uioa_mblk_init(sodp, mp, msg_size); 13578348SEric.Yu@Sun.COM } else { 13588348SEric.Yu@Sun.COM SOD_UIOAFINI(sodp); 13598348SEric.Yu@Sun.COM } 13608348SEric.Yu@Sun.COM } 13618348SEric.Yu@Sun.COM 13628348SEric.Yu@Sun.COM if (mp->b_next == NULL) { 13638348SEric.Yu@Sun.COM so_enqueue_msg(so, mp, msg_size); 13648348SEric.Yu@Sun.COM } else { 13658348SEric.Yu@Sun.COM do { 13668348SEric.Yu@Sun.COM mblk_t *nmp; 13678348SEric.Yu@Sun.COM 13688348SEric.Yu@Sun.COM if ((nmp = mp->b_next) != NULL) { 13698348SEric.Yu@Sun.COM mp->b_next = NULL; 13708348SEric.Yu@Sun.COM } 13718348SEric.Yu@Sun.COM so_enqueue_msg(so, mp, msgdsize(mp)); 13728348SEric.Yu@Sun.COM mp = nmp; 13738348SEric.Yu@Sun.COM } while (mp != NULL); 13748348SEric.Yu@Sun.COM } 13758348SEric.Yu@Sun.COM 13768348SEric.Yu@Sun.COM space_left = so->so_rcvbuf - so->so_rcv_queued; 13778348SEric.Yu@Sun.COM if (space_left <= 0) { 13788348SEric.Yu@Sun.COM so->so_flowctrld = B_TRUE; 13798348SEric.Yu@Sun.COM *errorp = ENOSPC; 13808348SEric.Yu@Sun.COM space_left = -1; 13818348SEric.Yu@Sun.COM } 13828348SEric.Yu@Sun.COM 13838348SEric.Yu@Sun.COM if (force_push || so->so_rcv_queued >= so->so_rcv_thresh || 13849491SAnders.Persson@Sun.COM so->so_rcv_queued >= so->so_rcv_wanted) { 13858348SEric.Yu@Sun.COM SOCKET_TIMER_CANCEL(so); 13868348SEric.Yu@Sun.COM /* 13878348SEric.Yu@Sun.COM * so_notify_data will release the lock 13888348SEric.Yu@Sun.COM */ 13898348SEric.Yu@Sun.COM so_notify_data(so, so->so_rcv_queued); 13908348SEric.Yu@Sun.COM 13918348SEric.Yu@Sun.COM if (force_pushp != NULL) 13928348SEric.Yu@Sun.COM *force_pushp = B_TRUE; 13938348SEric.Yu@Sun.COM goto done; 13948348SEric.Yu@Sun.COM } else if (so->so_rcv_timer_tid == 0) { 13958348SEric.Yu@Sun.COM /* Make sure the recv push timer is running */ 13968348SEric.Yu@Sun.COM SOCKET_TIMER_START(so); 13978348SEric.Yu@Sun.COM } 13988348SEric.Yu@Sun.COM 13998348SEric.Yu@Sun.COM done_unlock: 14008348SEric.Yu@Sun.COM mutex_exit(&so->so_lock); 14018348SEric.Yu@Sun.COM done: 14028348SEric.Yu@Sun.COM return (space_left); 1403*12643SAnders.Persson@Sun.COM 1404*12643SAnders.Persson@Sun.COM space_check: 1405*12643SAnders.Persson@Sun.COM space_left = so->so_rcvbuf - so->so_rcv_queued; 1406*12643SAnders.Persson@Sun.COM if (space_left <= 0) { 1407*12643SAnders.Persson@Sun.COM so->so_flowctrld = B_TRUE; 1408*12643SAnders.Persson@Sun.COM *errorp = ENOSPC; 1409*12643SAnders.Persson@Sun.COM space_left = -1; 1410*12643SAnders.Persson@Sun.COM } 1411*12643SAnders.Persson@Sun.COM goto done_unlock; 1412*12643SAnders.Persson@Sun.COM } 1413*12643SAnders.Persson@Sun.COM 1414*12643SAnders.Persson@Sun.COM #pragma inline(so_queue_msg_impl) 1415*12643SAnders.Persson@Sun.COM 1416*12643SAnders.Persson@Sun.COM ssize_t 1417*12643SAnders.Persson@Sun.COM so_queue_msg(sock_upper_handle_t sock_handle, mblk_t *mp, 1418*12643SAnders.Persson@Sun.COM size_t msg_size, int flags, int *errorp, boolean_t *force_pushp) 1419*12643SAnders.Persson@Sun.COM { 1420*12643SAnders.Persson@Sun.COM struct sonode *so = (struct sonode *)sock_handle; 1421*12643SAnders.Persson@Sun.COM 1422*12643SAnders.Persson@Sun.COM return (so_queue_msg_impl(so, mp, msg_size, flags, errorp, force_pushp, 1423*12643SAnders.Persson@Sun.COM so->so_filter_bottom)); 14248348SEric.Yu@Sun.COM } 14258348SEric.Yu@Sun.COM 14268348SEric.Yu@Sun.COM /* 14278348SEric.Yu@Sun.COM * Set the offset of where the oob data is relative to the bytes in 14288348SEric.Yu@Sun.COM * queued. Also generate SIGURG 14298348SEric.Yu@Sun.COM */ 14308348SEric.Yu@Sun.COM void 14318348SEric.Yu@Sun.COM so_signal_oob(sock_upper_handle_t sock_handle, ssize_t offset) 14328348SEric.Yu@Sun.COM { 14338348SEric.Yu@Sun.COM struct sonode *so; 14348348SEric.Yu@Sun.COM 14358348SEric.Yu@Sun.COM ASSERT(offset >= 0); 14368348SEric.Yu@Sun.COM so = (struct sonode *)sock_handle; 14378348SEric.Yu@Sun.COM mutex_enter(&so->so_lock); 14389491SAnders.Persson@Sun.COM if (so->so_direct != NULL) 14399491SAnders.Persson@Sun.COM SOD_UIOAFINI(so->so_direct); 14408348SEric.Yu@Sun.COM 14418348SEric.Yu@Sun.COM /* 14428348SEric.Yu@Sun.COM * New urgent data on the way so forget about any old 14438348SEric.Yu@Sun.COM * urgent data. 14448348SEric.Yu@Sun.COM */ 14458348SEric.Yu@Sun.COM so->so_state &= ~(SS_HAVEOOBDATA|SS_HADOOBDATA); 14468348SEric.Yu@Sun.COM 14478348SEric.Yu@Sun.COM /* 14488348SEric.Yu@Sun.COM * Record that urgent data is pending. 14498348SEric.Yu@Sun.COM */ 14508348SEric.Yu@Sun.COM so->so_state |= SS_OOBPEND; 14518348SEric.Yu@Sun.COM 14528348SEric.Yu@Sun.COM if (so->so_oobmsg != NULL) { 14538348SEric.Yu@Sun.COM dprintso(so, 1, ("sock: discarding old oob\n")); 14548348SEric.Yu@Sun.COM freemsg(so->so_oobmsg); 14558348SEric.Yu@Sun.COM so->so_oobmsg = NULL; 14568348SEric.Yu@Sun.COM } 14578348SEric.Yu@Sun.COM 14588348SEric.Yu@Sun.COM /* 14598348SEric.Yu@Sun.COM * set the offset where the urgent byte is 14608348SEric.Yu@Sun.COM */ 14618348SEric.Yu@Sun.COM so->so_oobmark = so->so_rcv_queued + offset; 14628348SEric.Yu@Sun.COM if (so->so_oobmark == 0) 14638348SEric.Yu@Sun.COM so->so_state |= SS_RCVATMARK; 14648348SEric.Yu@Sun.COM else 14658348SEric.Yu@Sun.COM so->so_state &= ~SS_RCVATMARK; 14668348SEric.Yu@Sun.COM 14678348SEric.Yu@Sun.COM so_notify_oobsig(so); 14688348SEric.Yu@Sun.COM } 14698348SEric.Yu@Sun.COM 14708348SEric.Yu@Sun.COM /* 14718348SEric.Yu@Sun.COM * Queue the OOB byte 14728348SEric.Yu@Sun.COM */ 14738348SEric.Yu@Sun.COM static void 1474*12643SAnders.Persson@Sun.COM so_queue_oob(struct sonode *so, mblk_t *mp, size_t len) 14758348SEric.Yu@Sun.COM { 14768348SEric.Yu@Sun.COM mutex_enter(&so->so_lock); 14779491SAnders.Persson@Sun.COM if (so->so_direct != NULL) 14789491SAnders.Persson@Sun.COM SOD_UIOAFINI(so->so_direct); 14798348SEric.Yu@Sun.COM 14808348SEric.Yu@Sun.COM ASSERT(mp != NULL); 14818348SEric.Yu@Sun.COM if (!IS_SO_OOB_INLINE(so)) { 14828348SEric.Yu@Sun.COM so->so_oobmsg = mp; 14838348SEric.Yu@Sun.COM so->so_state |= SS_HAVEOOBDATA; 14848348SEric.Yu@Sun.COM } else { 14858348SEric.Yu@Sun.COM so_enqueue_msg(so, mp, len); 14868348SEric.Yu@Sun.COM } 14878348SEric.Yu@Sun.COM 14888348SEric.Yu@Sun.COM so_notify_oobdata(so, IS_SO_OOB_INLINE(so)); 14898348SEric.Yu@Sun.COM } 14908348SEric.Yu@Sun.COM 14918348SEric.Yu@Sun.COM int 14928348SEric.Yu@Sun.COM so_close(struct sonode *so, int flag, struct cred *cr) 14938348SEric.Yu@Sun.COM { 14948348SEric.Yu@Sun.COM int error; 14958348SEric.Yu@Sun.COM 14968348SEric.Yu@Sun.COM /* 1497*12643SAnders.Persson@Sun.COM * No new data will be enqueued once the CLOSING flag is set. 14988348SEric.Yu@Sun.COM */ 14998348SEric.Yu@Sun.COM mutex_enter(&so->so_lock); 1500*12643SAnders.Persson@Sun.COM so->so_state |= SS_CLOSING; 15018399SRao.Shoaib@Sun.COM ASSERT(so_verify_oobstate(so)); 15028348SEric.Yu@Sun.COM so_rcv_flush(so); 15038348SEric.Yu@Sun.COM mutex_exit(&so->so_lock); 15048348SEric.Yu@Sun.COM 1505*12643SAnders.Persson@Sun.COM if (so->so_state & SS_ACCEPTCONN) { 1506*12643SAnders.Persson@Sun.COM /* 1507*12643SAnders.Persson@Sun.COM * We grab and release the accept lock to ensure that any 1508*12643SAnders.Persson@Sun.COM * thread about to insert a socket in so_newconn completes 1509*12643SAnders.Persson@Sun.COM * before we flush the queue. Any thread calling so_newconn 1510*12643SAnders.Persson@Sun.COM * after we drop the lock will observe the SS_CLOSING flag, 1511*12643SAnders.Persson@Sun.COM * which will stop it from inserting the socket in the queue. 1512*12643SAnders.Persson@Sun.COM */ 1513*12643SAnders.Persson@Sun.COM mutex_enter(&so->so_acceptq_lock); 1514*12643SAnders.Persson@Sun.COM mutex_exit(&so->so_acceptq_lock); 1515*12643SAnders.Persson@Sun.COM 1516*12643SAnders.Persson@Sun.COM so_acceptq_flush(so, B_TRUE); 1517*12643SAnders.Persson@Sun.COM } 1518*12643SAnders.Persson@Sun.COM 1519*12643SAnders.Persson@Sun.COM if (so->so_filter_active > 0) 1520*12643SAnders.Persson@Sun.COM sof_sonode_closing(so); 1521*12643SAnders.Persson@Sun.COM 1522*12643SAnders.Persson@Sun.COM error = (*so->so_downcalls->sd_close)(so->so_proto_handle, flag, cr); 1523*12643SAnders.Persson@Sun.COM switch (error) { 1524*12643SAnders.Persson@Sun.COM default: 1525*12643SAnders.Persson@Sun.COM /* Protocol made a synchronous close; remove proto ref */ 1526*12643SAnders.Persson@Sun.COM VN_RELE(SOTOV(so)); 1527*12643SAnders.Persson@Sun.COM break; 1528*12643SAnders.Persson@Sun.COM case EINPROGRESS: 1529*12643SAnders.Persson@Sun.COM /* 1530*12643SAnders.Persson@Sun.COM * Protocol is in the process of closing, it will make a 1531*12643SAnders.Persson@Sun.COM * 'closed' upcall to remove the reference. 1532*12643SAnders.Persson@Sun.COM */ 1533*12643SAnders.Persson@Sun.COM error = 0; 1534*12643SAnders.Persson@Sun.COM break; 1535*12643SAnders.Persson@Sun.COM } 1536*12643SAnders.Persson@Sun.COM 15378348SEric.Yu@Sun.COM return (error); 15388348SEric.Yu@Sun.COM } 15398348SEric.Yu@Sun.COM 1540*12643SAnders.Persson@Sun.COM /* 1541*12643SAnders.Persson@Sun.COM * Upcall made by the protocol when it's doing an asynchronous close. It 1542*12643SAnders.Persson@Sun.COM * will drop the protocol's reference on the socket. 1543*12643SAnders.Persson@Sun.COM */ 1544*12643SAnders.Persson@Sun.COM void 1545*12643SAnders.Persson@Sun.COM so_closed(sock_upper_handle_t sock_handle) 1546*12643SAnders.Persson@Sun.COM { 1547*12643SAnders.Persson@Sun.COM struct sonode *so = (struct sonode *)sock_handle; 1548*12643SAnders.Persson@Sun.COM 1549*12643SAnders.Persson@Sun.COM VN_RELE(SOTOV(so)); 1550*12643SAnders.Persson@Sun.COM } 1551*12643SAnders.Persson@Sun.COM 15528348SEric.Yu@Sun.COM void 15538348SEric.Yu@Sun.COM so_zcopy_notify(sock_upper_handle_t sock_handle) 15548348SEric.Yu@Sun.COM { 15558348SEric.Yu@Sun.COM struct sonode *so = (struct sonode *)sock_handle; 15568348SEric.Yu@Sun.COM 15578348SEric.Yu@Sun.COM mutex_enter(&so->so_lock); 15588348SEric.Yu@Sun.COM so->so_copyflag |= STZCNOTIFY; 15598348SEric.Yu@Sun.COM cv_broadcast(&so->so_copy_cv); 15608348SEric.Yu@Sun.COM mutex_exit(&so->so_lock); 15618348SEric.Yu@Sun.COM } 15628348SEric.Yu@Sun.COM 15638348SEric.Yu@Sun.COM void 15648348SEric.Yu@Sun.COM so_set_error(sock_upper_handle_t sock_handle, int error) 15658348SEric.Yu@Sun.COM { 15668348SEric.Yu@Sun.COM struct sonode *so = (struct sonode *)sock_handle; 15678348SEric.Yu@Sun.COM 15688348SEric.Yu@Sun.COM mutex_enter(&so->so_lock); 15698348SEric.Yu@Sun.COM 15708348SEric.Yu@Sun.COM soseterror(so, error); 15718348SEric.Yu@Sun.COM 15728348SEric.Yu@Sun.COM so_notify_error(so); 15738348SEric.Yu@Sun.COM } 15748348SEric.Yu@Sun.COM 15758348SEric.Yu@Sun.COM /* 15768348SEric.Yu@Sun.COM * so_recvmsg - read data from the socket 15778348SEric.Yu@Sun.COM * 15788348SEric.Yu@Sun.COM * There are two ways of obtaining data; either we ask the protocol to 15798348SEric.Yu@Sun.COM * copy directly into the supplied buffer, or we copy data from the 15808348SEric.Yu@Sun.COM * sonode's receive queue. The decision which one to use depends on 15818348SEric.Yu@Sun.COM * whether the protocol has a sd_recv_uio down call. 15828348SEric.Yu@Sun.COM */ 15838348SEric.Yu@Sun.COM int 15848348SEric.Yu@Sun.COM so_recvmsg(struct sonode *so, struct nmsghdr *msg, struct uio *uiop, 15858348SEric.Yu@Sun.COM struct cred *cr) 15868348SEric.Yu@Sun.COM { 15878348SEric.Yu@Sun.COM rval_t rval; 15888348SEric.Yu@Sun.COM int flags = 0; 15898348SEric.Yu@Sun.COM t_uscalar_t controllen, namelen; 15908348SEric.Yu@Sun.COM int error = 0; 15918348SEric.Yu@Sun.COM int ret; 15928348SEric.Yu@Sun.COM mblk_t *mctlp = NULL; 15938348SEric.Yu@Sun.COM union T_primitives *tpr; 15948348SEric.Yu@Sun.COM void *control; 15958348SEric.Yu@Sun.COM ssize_t saved_resid; 15968348SEric.Yu@Sun.COM struct uio *suiop; 15978348SEric.Yu@Sun.COM 15988348SEric.Yu@Sun.COM SO_BLOCK_FALLBACK(so, SOP_RECVMSG(so, msg, uiop, cr)); 15998348SEric.Yu@Sun.COM 16008348SEric.Yu@Sun.COM if ((so->so_state & (SS_ISCONNECTED|SS_CANTRCVMORE)) == 0 && 16018348SEric.Yu@Sun.COM (so->so_mode & SM_CONNREQUIRED)) { 16028348SEric.Yu@Sun.COM SO_UNBLOCK_FALLBACK(so); 16038348SEric.Yu@Sun.COM return (ENOTCONN); 16048348SEric.Yu@Sun.COM } 16058348SEric.Yu@Sun.COM 16068348SEric.Yu@Sun.COM if (msg->msg_flags & MSG_PEEK) 16078348SEric.Yu@Sun.COM msg->msg_flags &= ~MSG_WAITALL; 16088348SEric.Yu@Sun.COM 16098348SEric.Yu@Sun.COM if (so->so_mode & SM_ATOMIC) 16108348SEric.Yu@Sun.COM msg->msg_flags |= MSG_TRUNC; 16118348SEric.Yu@Sun.COM 16128348SEric.Yu@Sun.COM if (msg->msg_flags & MSG_OOB) { 16138348SEric.Yu@Sun.COM if ((so->so_mode & SM_EXDATA) == 0) { 16148348SEric.Yu@Sun.COM error = EOPNOTSUPP; 16158348SEric.Yu@Sun.COM } else if (so->so_downcalls->sd_recv_uio != NULL) { 16168348SEric.Yu@Sun.COM error = (*so->so_downcalls->sd_recv_uio) 16178348SEric.Yu@Sun.COM (so->so_proto_handle, uiop, msg, cr); 16188348SEric.Yu@Sun.COM } else { 16198348SEric.Yu@Sun.COM error = sorecvoob(so, msg, uiop, msg->msg_flags, 16208348SEric.Yu@Sun.COM IS_SO_OOB_INLINE(so)); 16218348SEric.Yu@Sun.COM } 16228348SEric.Yu@Sun.COM SO_UNBLOCK_FALLBACK(so); 16238348SEric.Yu@Sun.COM return (error); 16248348SEric.Yu@Sun.COM } 16258348SEric.Yu@Sun.COM 16268348SEric.Yu@Sun.COM /* 16278348SEric.Yu@Sun.COM * If the protocol has the recv down call, then pass the request 16288348SEric.Yu@Sun.COM * down. 16298348SEric.Yu@Sun.COM */ 16308348SEric.Yu@Sun.COM if (so->so_downcalls->sd_recv_uio != NULL) { 16318348SEric.Yu@Sun.COM error = (*so->so_downcalls->sd_recv_uio) 16328348SEric.Yu@Sun.COM (so->so_proto_handle, uiop, msg, cr); 16338348SEric.Yu@Sun.COM SO_UNBLOCK_FALLBACK(so); 16348348SEric.Yu@Sun.COM return (error); 16358348SEric.Yu@Sun.COM } 16368348SEric.Yu@Sun.COM 16378348SEric.Yu@Sun.COM /* 16388348SEric.Yu@Sun.COM * Reading data from the socket buffer 16398348SEric.Yu@Sun.COM */ 16408348SEric.Yu@Sun.COM flags = msg->msg_flags; 16418348SEric.Yu@Sun.COM msg->msg_flags = 0; 16428348SEric.Yu@Sun.COM 16438348SEric.Yu@Sun.COM /* 16448348SEric.Yu@Sun.COM * Set msg_controllen and msg_namelen to zero here to make it 16458348SEric.Yu@Sun.COM * simpler in the cases that no control or name is returned. 16468348SEric.Yu@Sun.COM */ 16478348SEric.Yu@Sun.COM controllen = msg->msg_controllen; 16488348SEric.Yu@Sun.COM namelen = msg->msg_namelen; 16498348SEric.Yu@Sun.COM msg->msg_controllen = 0; 16508348SEric.Yu@Sun.COM msg->msg_namelen = 0; 16518348SEric.Yu@Sun.COM 16528348SEric.Yu@Sun.COM mutex_enter(&so->so_lock); 16538348SEric.Yu@Sun.COM /* Set SOREADLOCKED */ 16548348SEric.Yu@Sun.COM error = so_lock_read_intr(so, 16558348SEric.Yu@Sun.COM uiop->uio_fmode | ((flags & MSG_DONTWAIT) ? FNONBLOCK : 0)); 16568348SEric.Yu@Sun.COM mutex_exit(&so->so_lock); 16578348SEric.Yu@Sun.COM if (error) { 16588348SEric.Yu@Sun.COM SO_UNBLOCK_FALLBACK(so); 16598348SEric.Yu@Sun.COM return (error); 16608348SEric.Yu@Sun.COM } 16618348SEric.Yu@Sun.COM 16628348SEric.Yu@Sun.COM suiop = sod_rcv_init(so, flags, &uiop); 16638348SEric.Yu@Sun.COM retry: 16648348SEric.Yu@Sun.COM saved_resid = uiop->uio_resid; 16658348SEric.Yu@Sun.COM error = so_dequeue_msg(so, &mctlp, uiop, &rval, flags); 16668348SEric.Yu@Sun.COM if (error != 0) { 16678348SEric.Yu@Sun.COM goto out; 16688348SEric.Yu@Sun.COM } 16698348SEric.Yu@Sun.COM /* 16708348SEric.Yu@Sun.COM * For datagrams the MOREDATA flag is used to set MSG_TRUNC. 16718348SEric.Yu@Sun.COM * For non-datagrams MOREDATA is used to set MSG_EOR. 16728348SEric.Yu@Sun.COM */ 16738348SEric.Yu@Sun.COM ASSERT(!(rval.r_val1 & MORECTL)); 16748348SEric.Yu@Sun.COM if ((rval.r_val1 & MOREDATA) && (so->so_mode & SM_ATOMIC)) 16758348SEric.Yu@Sun.COM msg->msg_flags |= MSG_TRUNC; 16768348SEric.Yu@Sun.COM if (mctlp == NULL) { 16778348SEric.Yu@Sun.COM dprintso(so, 1, ("so_recvmsg: got M_DATA\n")); 16788348SEric.Yu@Sun.COM 16798348SEric.Yu@Sun.COM mutex_enter(&so->so_lock); 16808348SEric.Yu@Sun.COM /* Set MSG_EOR based on MOREDATA */ 16818348SEric.Yu@Sun.COM if (!(rval.r_val1 & MOREDATA)) { 16828348SEric.Yu@Sun.COM if (so->so_state & SS_SAVEDEOR) { 16838348SEric.Yu@Sun.COM msg->msg_flags |= MSG_EOR; 16848348SEric.Yu@Sun.COM so->so_state &= ~SS_SAVEDEOR; 16858348SEric.Yu@Sun.COM } 16868348SEric.Yu@Sun.COM } 16878348SEric.Yu@Sun.COM /* 16888348SEric.Yu@Sun.COM * If some data was received (i.e. not EOF) and the 16898348SEric.Yu@Sun.COM * read/recv* has not been satisfied wait for some more. 16908348SEric.Yu@Sun.COM */ 16918348SEric.Yu@Sun.COM if ((flags & MSG_WAITALL) && !(msg->msg_flags & MSG_EOR) && 16928348SEric.Yu@Sun.COM uiop->uio_resid != saved_resid && uiop->uio_resid > 0) { 16938348SEric.Yu@Sun.COM mutex_exit(&so->so_lock); 16949752SAnders.Persson@Sun.COM flags |= MSG_NOMARK; 16958348SEric.Yu@Sun.COM goto retry; 16968348SEric.Yu@Sun.COM } 16978348SEric.Yu@Sun.COM 16988348SEric.Yu@Sun.COM goto out_locked; 16998348SEric.Yu@Sun.COM } 17009752SAnders.Persson@Sun.COM /* so_queue_msg has already verified length and alignment */ 17018348SEric.Yu@Sun.COM tpr = (union T_primitives *)mctlp->b_rptr; 17028348SEric.Yu@Sun.COM dprintso(so, 1, ("so_recvmsg: type %d\n", tpr->type)); 17038348SEric.Yu@Sun.COM switch (tpr->type) { 17048348SEric.Yu@Sun.COM case T_DATA_IND: { 17058348SEric.Yu@Sun.COM /* 17068348SEric.Yu@Sun.COM * Set msg_flags to MSG_EOR based on 17078348SEric.Yu@Sun.COM * MORE_flag and MOREDATA. 17088348SEric.Yu@Sun.COM */ 17098348SEric.Yu@Sun.COM mutex_enter(&so->so_lock); 17108348SEric.Yu@Sun.COM so->so_state &= ~SS_SAVEDEOR; 17118348SEric.Yu@Sun.COM if (!(tpr->data_ind.MORE_flag & 1)) { 17128348SEric.Yu@Sun.COM if (!(rval.r_val1 & MOREDATA)) 17138348SEric.Yu@Sun.COM msg->msg_flags |= MSG_EOR; 17148348SEric.Yu@Sun.COM else 17158348SEric.Yu@Sun.COM so->so_state |= SS_SAVEDEOR; 17168348SEric.Yu@Sun.COM } 17178348SEric.Yu@Sun.COM freemsg(mctlp); 17188348SEric.Yu@Sun.COM /* 17198348SEric.Yu@Sun.COM * If some data was received (i.e. not EOF) and the 17208348SEric.Yu@Sun.COM * read/recv* has not been satisfied wait for some more. 17218348SEric.Yu@Sun.COM */ 17228348SEric.Yu@Sun.COM if ((flags & MSG_WAITALL) && !(msg->msg_flags & MSG_EOR) && 17238348SEric.Yu@Sun.COM uiop->uio_resid != saved_resid && uiop->uio_resid > 0) { 17248348SEric.Yu@Sun.COM mutex_exit(&so->so_lock); 17259752SAnders.Persson@Sun.COM flags |= MSG_NOMARK; 17268348SEric.Yu@Sun.COM goto retry; 17278348SEric.Yu@Sun.COM } 17288348SEric.Yu@Sun.COM goto out_locked; 17298348SEric.Yu@Sun.COM } 17308348SEric.Yu@Sun.COM case T_UNITDATA_IND: { 17318348SEric.Yu@Sun.COM void *addr; 17328348SEric.Yu@Sun.COM t_uscalar_t addrlen; 17338348SEric.Yu@Sun.COM void *abuf; 17348348SEric.Yu@Sun.COM t_uscalar_t optlen; 17358348SEric.Yu@Sun.COM void *opt; 17368348SEric.Yu@Sun.COM 17378348SEric.Yu@Sun.COM if (namelen != 0) { 17388348SEric.Yu@Sun.COM /* Caller wants source address */ 17398348SEric.Yu@Sun.COM addrlen = tpr->unitdata_ind.SRC_length; 17408348SEric.Yu@Sun.COM addr = sogetoff(mctlp, tpr->unitdata_ind.SRC_offset, 17418348SEric.Yu@Sun.COM addrlen, 1); 17428348SEric.Yu@Sun.COM if (addr == NULL) { 17438348SEric.Yu@Sun.COM freemsg(mctlp); 17448348SEric.Yu@Sun.COM error = EPROTO; 17458348SEric.Yu@Sun.COM eprintsoline(so, error); 17468348SEric.Yu@Sun.COM goto out; 17478348SEric.Yu@Sun.COM } 17488348SEric.Yu@Sun.COM ASSERT(so->so_family != AF_UNIX); 17498348SEric.Yu@Sun.COM } 17508348SEric.Yu@Sun.COM optlen = tpr->unitdata_ind.OPT_length; 17518348SEric.Yu@Sun.COM if (optlen != 0) { 17528348SEric.Yu@Sun.COM t_uscalar_t ncontrollen; 17538348SEric.Yu@Sun.COM 17548348SEric.Yu@Sun.COM /* 17558348SEric.Yu@Sun.COM * Extract any source address option. 17568348SEric.Yu@Sun.COM * Determine how large cmsg buffer is needed. 17578348SEric.Yu@Sun.COM */ 17588348SEric.Yu@Sun.COM opt = sogetoff(mctlp, tpr->unitdata_ind.OPT_offset, 17598348SEric.Yu@Sun.COM optlen, __TPI_ALIGN_SIZE); 17608348SEric.Yu@Sun.COM 17618348SEric.Yu@Sun.COM if (opt == NULL) { 17628348SEric.Yu@Sun.COM freemsg(mctlp); 17638348SEric.Yu@Sun.COM error = EPROTO; 17648348SEric.Yu@Sun.COM eprintsoline(so, error); 17658348SEric.Yu@Sun.COM goto out; 17668348SEric.Yu@Sun.COM } 17678348SEric.Yu@Sun.COM if (so->so_family == AF_UNIX) 17688348SEric.Yu@Sun.COM so_getopt_srcaddr(opt, optlen, &addr, &addrlen); 17698348SEric.Yu@Sun.COM ncontrollen = so_cmsglen(mctlp, opt, optlen, 17708348SEric.Yu@Sun.COM !(flags & MSG_XPG4_2)); 17718348SEric.Yu@Sun.COM if (controllen != 0) 17728348SEric.Yu@Sun.COM controllen = ncontrollen; 17738348SEric.Yu@Sun.COM else if (ncontrollen != 0) 17748348SEric.Yu@Sun.COM msg->msg_flags |= MSG_CTRUNC; 17758348SEric.Yu@Sun.COM } else { 17768348SEric.Yu@Sun.COM controllen = 0; 17778348SEric.Yu@Sun.COM } 17788348SEric.Yu@Sun.COM 17798348SEric.Yu@Sun.COM if (namelen != 0) { 17808348SEric.Yu@Sun.COM /* 17818348SEric.Yu@Sun.COM * Return address to caller. 17828348SEric.Yu@Sun.COM * Caller handles truncation if length 17838348SEric.Yu@Sun.COM * exceeds msg_namelen. 17848348SEric.Yu@Sun.COM * NOTE: AF_UNIX NUL termination is ensured by 17858348SEric.Yu@Sun.COM * the sender's copyin_name(). 17868348SEric.Yu@Sun.COM */ 17878348SEric.Yu@Sun.COM abuf = kmem_alloc(addrlen, KM_SLEEP); 17888348SEric.Yu@Sun.COM 17898348SEric.Yu@Sun.COM bcopy(addr, abuf, addrlen); 17908348SEric.Yu@Sun.COM msg->msg_name = abuf; 17918348SEric.Yu@Sun.COM msg->msg_namelen = addrlen; 17928348SEric.Yu@Sun.COM } 17938348SEric.Yu@Sun.COM 17948348SEric.Yu@Sun.COM if (controllen != 0) { 17958348SEric.Yu@Sun.COM /* 17968348SEric.Yu@Sun.COM * Return control msg to caller. 17978348SEric.Yu@Sun.COM * Caller handles truncation if length 17988348SEric.Yu@Sun.COM * exceeds msg_controllen. 17998348SEric.Yu@Sun.COM */ 18008348SEric.Yu@Sun.COM control = kmem_zalloc(controllen, KM_SLEEP); 18018348SEric.Yu@Sun.COM 18028348SEric.Yu@Sun.COM error = so_opt2cmsg(mctlp, opt, optlen, 18038348SEric.Yu@Sun.COM !(flags & MSG_XPG4_2), control, controllen); 18048348SEric.Yu@Sun.COM if (error) { 18058348SEric.Yu@Sun.COM freemsg(mctlp); 18068348SEric.Yu@Sun.COM if (msg->msg_namelen != 0) 18078348SEric.Yu@Sun.COM kmem_free(msg->msg_name, 18088348SEric.Yu@Sun.COM msg->msg_namelen); 18098348SEric.Yu@Sun.COM kmem_free(control, controllen); 18108348SEric.Yu@Sun.COM eprintsoline(so, error); 18118348SEric.Yu@Sun.COM goto out; 18128348SEric.Yu@Sun.COM } 18138348SEric.Yu@Sun.COM msg->msg_control = control; 18148348SEric.Yu@Sun.COM msg->msg_controllen = controllen; 18158348SEric.Yu@Sun.COM } 18168348SEric.Yu@Sun.COM 18178348SEric.Yu@Sun.COM freemsg(mctlp); 18188348SEric.Yu@Sun.COM goto out; 18198348SEric.Yu@Sun.COM } 18208348SEric.Yu@Sun.COM case T_OPTDATA_IND: { 18218348SEric.Yu@Sun.COM struct T_optdata_req *tdr; 18228348SEric.Yu@Sun.COM void *opt; 18238348SEric.Yu@Sun.COM t_uscalar_t optlen; 18248348SEric.Yu@Sun.COM 18258348SEric.Yu@Sun.COM tdr = (struct T_optdata_req *)mctlp->b_rptr; 18268348SEric.Yu@Sun.COM optlen = tdr->OPT_length; 18278348SEric.Yu@Sun.COM if (optlen != 0) { 18288348SEric.Yu@Sun.COM t_uscalar_t ncontrollen; 18298348SEric.Yu@Sun.COM /* 18308348SEric.Yu@Sun.COM * Determine how large cmsg buffer is needed. 18318348SEric.Yu@Sun.COM */ 18328348SEric.Yu@Sun.COM opt = sogetoff(mctlp, 18338348SEric.Yu@Sun.COM tpr->optdata_ind.OPT_offset, optlen, 18348348SEric.Yu@Sun.COM __TPI_ALIGN_SIZE); 18358348SEric.Yu@Sun.COM 18368348SEric.Yu@Sun.COM if (opt == NULL) { 18378348SEric.Yu@Sun.COM freemsg(mctlp); 18388348SEric.Yu@Sun.COM error = EPROTO; 18398348SEric.Yu@Sun.COM eprintsoline(so, error); 18408348SEric.Yu@Sun.COM goto out; 18418348SEric.Yu@Sun.COM } 18428348SEric.Yu@Sun.COM 18438348SEric.Yu@Sun.COM ncontrollen = so_cmsglen(mctlp, opt, optlen, 18448348SEric.Yu@Sun.COM !(flags & MSG_XPG4_2)); 18458348SEric.Yu@Sun.COM if (controllen != 0) 18468348SEric.Yu@Sun.COM controllen = ncontrollen; 18478348SEric.Yu@Sun.COM else if (ncontrollen != 0) 18488348SEric.Yu@Sun.COM msg->msg_flags |= MSG_CTRUNC; 18498348SEric.Yu@Sun.COM } else { 18508348SEric.Yu@Sun.COM controllen = 0; 18518348SEric.Yu@Sun.COM } 18528348SEric.Yu@Sun.COM 18538348SEric.Yu@Sun.COM if (controllen != 0) { 18548348SEric.Yu@Sun.COM /* 18558348SEric.Yu@Sun.COM * Return control msg to caller. 18568348SEric.Yu@Sun.COM * Caller handles truncation if length 18578348SEric.Yu@Sun.COM * exceeds msg_controllen. 18588348SEric.Yu@Sun.COM */ 18598348SEric.Yu@Sun.COM control = kmem_zalloc(controllen, KM_SLEEP); 18608348SEric.Yu@Sun.COM 18618348SEric.Yu@Sun.COM error = so_opt2cmsg(mctlp, opt, optlen, 18628348SEric.Yu@Sun.COM !(flags & MSG_XPG4_2), control, controllen); 18638348SEric.Yu@Sun.COM if (error) { 18648348SEric.Yu@Sun.COM freemsg(mctlp); 18658348SEric.Yu@Sun.COM kmem_free(control, controllen); 18668348SEric.Yu@Sun.COM eprintsoline(so, error); 18678348SEric.Yu@Sun.COM goto out; 18688348SEric.Yu@Sun.COM } 18698348SEric.Yu@Sun.COM msg->msg_control = control; 18708348SEric.Yu@Sun.COM msg->msg_controllen = controllen; 18718348SEric.Yu@Sun.COM } 18728348SEric.Yu@Sun.COM 18738348SEric.Yu@Sun.COM /* 18748348SEric.Yu@Sun.COM * Set msg_flags to MSG_EOR based on 18758348SEric.Yu@Sun.COM * DATA_flag and MOREDATA. 18768348SEric.Yu@Sun.COM */ 18778348SEric.Yu@Sun.COM mutex_enter(&so->so_lock); 18788348SEric.Yu@Sun.COM so->so_state &= ~SS_SAVEDEOR; 18798348SEric.Yu@Sun.COM if (!(tpr->data_ind.MORE_flag & 1)) { 18808348SEric.Yu@Sun.COM if (!(rval.r_val1 & MOREDATA)) 18818348SEric.Yu@Sun.COM msg->msg_flags |= MSG_EOR; 18828348SEric.Yu@Sun.COM else 18838348SEric.Yu@Sun.COM so->so_state |= SS_SAVEDEOR; 18848348SEric.Yu@Sun.COM } 18858348SEric.Yu@Sun.COM freemsg(mctlp); 18868348SEric.Yu@Sun.COM /* 18878348SEric.Yu@Sun.COM * If some data was received (i.e. not EOF) and the 18888348SEric.Yu@Sun.COM * read/recv* has not been satisfied wait for some more. 18898348SEric.Yu@Sun.COM * Not possible to wait if control info was received. 18908348SEric.Yu@Sun.COM */ 18918348SEric.Yu@Sun.COM if ((flags & MSG_WAITALL) && !(msg->msg_flags & MSG_EOR) && 18928348SEric.Yu@Sun.COM controllen == 0 && 18938348SEric.Yu@Sun.COM uiop->uio_resid != saved_resid && uiop->uio_resid > 0) { 18948348SEric.Yu@Sun.COM mutex_exit(&so->so_lock); 18959752SAnders.Persson@Sun.COM flags |= MSG_NOMARK; 18968348SEric.Yu@Sun.COM goto retry; 18978348SEric.Yu@Sun.COM } 18988348SEric.Yu@Sun.COM goto out_locked; 18998348SEric.Yu@Sun.COM } 19008348SEric.Yu@Sun.COM default: 19018348SEric.Yu@Sun.COM cmn_err(CE_CONT, "so_recvmsg bad type %x \n", 19028348SEric.Yu@Sun.COM tpr->type); 19038348SEric.Yu@Sun.COM freemsg(mctlp); 19048348SEric.Yu@Sun.COM error = EPROTO; 19058348SEric.Yu@Sun.COM ASSERT(0); 19068348SEric.Yu@Sun.COM } 19078348SEric.Yu@Sun.COM out: 19088348SEric.Yu@Sun.COM mutex_enter(&so->so_lock); 19098348SEric.Yu@Sun.COM out_locked: 19108348SEric.Yu@Sun.COM ret = sod_rcv_done(so, suiop, uiop); 19118348SEric.Yu@Sun.COM if (ret != 0 && error == 0) 19128348SEric.Yu@Sun.COM error = ret; 19138348SEric.Yu@Sun.COM 19148348SEric.Yu@Sun.COM so_unlock_read(so); /* Clear SOREADLOCKED */ 19158348SEric.Yu@Sun.COM mutex_exit(&so->so_lock); 19168348SEric.Yu@Sun.COM 19178348SEric.Yu@Sun.COM SO_UNBLOCK_FALLBACK(so); 19188348SEric.Yu@Sun.COM 19198348SEric.Yu@Sun.COM return (error); 19208348SEric.Yu@Sun.COM } 19218348SEric.Yu@Sun.COM 19228348SEric.Yu@Sun.COM sonodeops_t so_sonodeops = { 19238348SEric.Yu@Sun.COM so_init, /* sop_init */ 19248348SEric.Yu@Sun.COM so_accept, /* sop_accept */ 19258348SEric.Yu@Sun.COM so_bind, /* sop_bind */ 19268348SEric.Yu@Sun.COM so_listen, /* sop_listen */ 19278348SEric.Yu@Sun.COM so_connect, /* sop_connect */ 19288348SEric.Yu@Sun.COM so_recvmsg, /* sop_recvmsg */ 19298348SEric.Yu@Sun.COM so_sendmsg, /* sop_sendmsg */ 19308348SEric.Yu@Sun.COM so_sendmblk, /* sop_sendmblk */ 19318348SEric.Yu@Sun.COM so_getpeername, /* sop_getpeername */ 19328348SEric.Yu@Sun.COM so_getsockname, /* sop_getsockname */ 19338348SEric.Yu@Sun.COM so_shutdown, /* sop_shutdown */ 19348348SEric.Yu@Sun.COM so_getsockopt, /* sop_getsockopt */ 19358348SEric.Yu@Sun.COM so_setsockopt, /* sop_setsockopt */ 19368348SEric.Yu@Sun.COM so_ioctl, /* sop_ioctl */ 19378348SEric.Yu@Sun.COM so_poll, /* sop_poll */ 19388348SEric.Yu@Sun.COM so_close, /* sop_close */ 19398348SEric.Yu@Sun.COM }; 19408348SEric.Yu@Sun.COM 19418348SEric.Yu@Sun.COM sock_upcalls_t so_upcalls = { 19428348SEric.Yu@Sun.COM so_newconn, 19438348SEric.Yu@Sun.COM so_connected, 19448348SEric.Yu@Sun.COM so_disconnected, 19458348SEric.Yu@Sun.COM so_opctl, 19468348SEric.Yu@Sun.COM so_queue_msg, 19478348SEric.Yu@Sun.COM so_set_prop, 19488348SEric.Yu@Sun.COM so_txq_full, 19498348SEric.Yu@Sun.COM so_signal_oob, 19508348SEric.Yu@Sun.COM so_zcopy_notify, 1951*12643SAnders.Persson@Sun.COM so_set_error, 1952*12643SAnders.Persson@Sun.COM so_closed 19538348SEric.Yu@Sun.COM }; 1954