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 /* 238348SEric.Yu@Sun.COM * Copyright 2008 Sun Microsystems, Inc. All rights reserved. 248348SEric.Yu@Sun.COM * Use is subject to license terms. 258348SEric.Yu@Sun.COM */ 268348SEric.Yu@Sun.COM 278348SEric.Yu@Sun.COM #include <sys/types.h> 288348SEric.Yu@Sun.COM #include <sys/param.h> 298348SEric.Yu@Sun.COM #include <sys/systm.h> 308348SEric.Yu@Sun.COM #include <sys/sysmacros.h> 318348SEric.Yu@Sun.COM #include <sys/debug.h> 328348SEric.Yu@Sun.COM #include <sys/cmn_err.h> 338348SEric.Yu@Sun.COM #include <sys/vfs.h> 348348SEric.Yu@Sun.COM #include <sys/policy.h> 358348SEric.Yu@Sun.COM #include <sys/modctl.h> 368348SEric.Yu@Sun.COM 378348SEric.Yu@Sun.COM #include <sys/sunddi.h> 388348SEric.Yu@Sun.COM 398348SEric.Yu@Sun.COM #include <sys/strsun.h> 408348SEric.Yu@Sun.COM #include <sys/stropts.h> 418348SEric.Yu@Sun.COM #include <sys/strsubr.h> 428348SEric.Yu@Sun.COM #include <sys/socket.h> 438348SEric.Yu@Sun.COM #include <sys/socketvar.h> 448348SEric.Yu@Sun.COM #include <sys/sodirect.h> 458348SEric.Yu@Sun.COM #include <sys/uio.h> 468348SEric.Yu@Sun.COM 478348SEric.Yu@Sun.COM #include <inet/ipclassifier.h> 488348SEric.Yu@Sun.COM #include <fs/sockfs/sockcommon.h> 498348SEric.Yu@Sun.COM #include <fs/sockfs/nl7c.h> 508399SRao.Shoaib@Sun.COM #include <fs/sockfs/socktpi.h> 518348SEric.Yu@Sun.COM #include <inet/ip.h> 528348SEric.Yu@Sun.COM 538348SEric.Yu@Sun.COM extern int xnet_skip_checks, xnet_check_print, xnet_truncate_print; 548348SEric.Yu@Sun.COM 558348SEric.Yu@Sun.COM static struct kmem_cache *sock_sod_cache; 568348SEric.Yu@Sun.COM 578348SEric.Yu@Sun.COM /* 588348SEric.Yu@Sun.COM * Common socket access functions. 598348SEric.Yu@Sun.COM * 608348SEric.Yu@Sun.COM * Instead of accessing the sonode switch directly (i.e., SOP_xxx()), 618348SEric.Yu@Sun.COM * the socket_xxx() function should be used. 628348SEric.Yu@Sun.COM */ 638348SEric.Yu@Sun.COM 648348SEric.Yu@Sun.COM /* 658348SEric.Yu@Sun.COM * Try to create a new sonode of the requested <family, type, protocol>. 668348SEric.Yu@Sun.COM */ 678348SEric.Yu@Sun.COM /* ARGSUSED */ 688348SEric.Yu@Sun.COM struct sonode * 698348SEric.Yu@Sun.COM socket_create(int family, int type, int protocol, char *devpath, char *mod, 708348SEric.Yu@Sun.COM int flags, int version, struct cred *cr, int *errorp) 718348SEric.Yu@Sun.COM { 728348SEric.Yu@Sun.COM struct sonode *so; 738348SEric.Yu@Sun.COM struct sockparams *sp = NULL; 748348SEric.Yu@Sun.COM 758348SEric.Yu@Sun.COM /* 768348SEric.Yu@Sun.COM * Look for a sockparams entry that match the given criteria. 778348SEric.Yu@Sun.COM * solookup() returns with the entry held. 788348SEric.Yu@Sun.COM */ 798348SEric.Yu@Sun.COM *errorp = solookup(family, type, protocol, &sp); 808348SEric.Yu@Sun.COM if (sp == NULL) { 818348SEric.Yu@Sun.COM int kmflags = (flags == SOCKET_SLEEP) ? KM_SLEEP : KM_NOSLEEP; 828348SEric.Yu@Sun.COM /* 838348SEric.Yu@Sun.COM * There is no matching sockparams entry. An ephemeral entry is 848348SEric.Yu@Sun.COM * created if the caller specifies a device or a socket module. 858348SEric.Yu@Sun.COM */ 868348SEric.Yu@Sun.COM if (devpath != NULL) { 878348SEric.Yu@Sun.COM sp = sockparams_hold_ephemeral_bydev(family, type, 888348SEric.Yu@Sun.COM protocol, devpath, kmflags, errorp); 898348SEric.Yu@Sun.COM } else if (mod != NULL) { 908348SEric.Yu@Sun.COM sp = sockparams_hold_ephemeral_bymod(family, type, 918348SEric.Yu@Sun.COM protocol, mod, kmflags, errorp); 928348SEric.Yu@Sun.COM } else { 938348SEric.Yu@Sun.COM return (NULL); 948348SEric.Yu@Sun.COM } 958348SEric.Yu@Sun.COM 968348SEric.Yu@Sun.COM if (sp == NULL) 978348SEric.Yu@Sun.COM return (NULL); 988348SEric.Yu@Sun.COM } 998348SEric.Yu@Sun.COM 1008348SEric.Yu@Sun.COM ASSERT(sp->sp_smod_info != NULL); 1018348SEric.Yu@Sun.COM ASSERT(flags == SOCKET_SLEEP || flags == SOCKET_NOSLEEP); 1028348SEric.Yu@Sun.COM so = sp->sp_smod_info->smod_sock_create_func(sp, family, type, 1038348SEric.Yu@Sun.COM protocol, version, flags, errorp, cr); 1048348SEric.Yu@Sun.COM if (so == NULL) { 1058348SEric.Yu@Sun.COM SOCKPARAMS_DEC_REF(sp); 1068348SEric.Yu@Sun.COM } else { 1078348SEric.Yu@Sun.COM if ((*errorp = SOP_INIT(so, NULL, cr, flags)) == 0) { 1088348SEric.Yu@Sun.COM /* Cannot fail, only bumps so_count */ 1098348SEric.Yu@Sun.COM (void) VOP_OPEN(&SOTOV(so), FREAD|FWRITE, cr, NULL); 1108348SEric.Yu@Sun.COM } else { 1118348SEric.Yu@Sun.COM socket_destroy(so); 1128348SEric.Yu@Sun.COM so = NULL; 1138348SEric.Yu@Sun.COM } 1148348SEric.Yu@Sun.COM } 1158348SEric.Yu@Sun.COM return (so); 1168348SEric.Yu@Sun.COM } 1178348SEric.Yu@Sun.COM 1188348SEric.Yu@Sun.COM struct sonode * 1198348SEric.Yu@Sun.COM socket_newconn(struct sonode *parent, sock_lower_handle_t lh, 1208348SEric.Yu@Sun.COM sock_downcalls_t *dc, int flags, int *errorp) 1218348SEric.Yu@Sun.COM { 1228348SEric.Yu@Sun.COM struct sonode *so; 1238348SEric.Yu@Sun.COM struct sockparams *sp; 1248348SEric.Yu@Sun.COM struct cred *cr; 1258348SEric.Yu@Sun.COM 1268348SEric.Yu@Sun.COM if ((cr = CRED()) == NULL) 1278348SEric.Yu@Sun.COM cr = kcred; 1288348SEric.Yu@Sun.COM 1298348SEric.Yu@Sun.COM sp = parent->so_sockparams; 1308348SEric.Yu@Sun.COM ASSERT(sp != NULL); 1318348SEric.Yu@Sun.COM 1328348SEric.Yu@Sun.COM so = sp->sp_smod_info->smod_sock_create_func(sp, parent->so_family, 1338348SEric.Yu@Sun.COM parent->so_type, parent->so_protocol, parent->so_version, flags, 1348348SEric.Yu@Sun.COM errorp, cr); 1358348SEric.Yu@Sun.COM if (so != NULL) { 1368348SEric.Yu@Sun.COM SOCKPARAMS_INC_REF(sp); 1378348SEric.Yu@Sun.COM 1388348SEric.Yu@Sun.COM so->so_proto_handle = lh; 1398348SEric.Yu@Sun.COM so->so_downcalls = dc; 1408348SEric.Yu@Sun.COM /* 1418348SEric.Yu@Sun.COM * This function may be called in interrupt context, and CRED() 1428348SEric.Yu@Sun.COM * will be NULL. In this case, pass in kcred. 1438348SEric.Yu@Sun.COM */ 1448348SEric.Yu@Sun.COM if ((*errorp = SOP_INIT(so, parent, cr, flags)) == 0) { 1458348SEric.Yu@Sun.COM /* Cannot fail, only bumps so_count */ 1468348SEric.Yu@Sun.COM (void) VOP_OPEN(&SOTOV(so), FREAD|FWRITE, cr, NULL); 1478348SEric.Yu@Sun.COM } else { 1488348SEric.Yu@Sun.COM socket_destroy(so); 1498348SEric.Yu@Sun.COM so = NULL; 1508348SEric.Yu@Sun.COM } 1518348SEric.Yu@Sun.COM } 1528348SEric.Yu@Sun.COM 1538348SEric.Yu@Sun.COM return (so); 1548348SEric.Yu@Sun.COM } 1558348SEric.Yu@Sun.COM 1568348SEric.Yu@Sun.COM /* 1578348SEric.Yu@Sun.COM * Bind local endpoint. 1588348SEric.Yu@Sun.COM */ 1598348SEric.Yu@Sun.COM int 1608348SEric.Yu@Sun.COM socket_bind(struct sonode *so, struct sockaddr *name, socklen_t namelen, 1618348SEric.Yu@Sun.COM int flags, cred_t *cr) 1628348SEric.Yu@Sun.COM { 1638348SEric.Yu@Sun.COM return (SOP_BIND(so, name, namelen, flags, cr)); 1648348SEric.Yu@Sun.COM } 1658348SEric.Yu@Sun.COM 1668348SEric.Yu@Sun.COM /* 1678348SEric.Yu@Sun.COM * Turn socket into a listen socket. 1688348SEric.Yu@Sun.COM */ 1698348SEric.Yu@Sun.COM int 1708348SEric.Yu@Sun.COM socket_listen(struct sonode *so, int backlog, cred_t *cr) 1718348SEric.Yu@Sun.COM { 1728348SEric.Yu@Sun.COM if (backlog < 0) { 1738348SEric.Yu@Sun.COM backlog = 0; 1748348SEric.Yu@Sun.COM } 1758348SEric.Yu@Sun.COM 1768348SEric.Yu@Sun.COM /* 1778348SEric.Yu@Sun.COM * Use the same qlimit as in BSD. BSD checks the qlimit 1788348SEric.Yu@Sun.COM * before queuing the next connection implying that a 1798348SEric.Yu@Sun.COM * listen(sock, 0) allows one connection to be queued. 1808348SEric.Yu@Sun.COM * BSD also uses 1.5 times the requested backlog. 1818348SEric.Yu@Sun.COM * 1828348SEric.Yu@Sun.COM * XNS Issue 4 required a strict interpretation of the backlog. 1838348SEric.Yu@Sun.COM * This has been waived subsequently for Issue 4 and the change 1848348SEric.Yu@Sun.COM * incorporated in XNS Issue 5. So we aren't required to do 1858348SEric.Yu@Sun.COM * anything special for XPG apps. 1868348SEric.Yu@Sun.COM */ 1878348SEric.Yu@Sun.COM if (backlog >= (INT_MAX - 1) / 3) 1888348SEric.Yu@Sun.COM backlog = INT_MAX; 1898348SEric.Yu@Sun.COM else 1908348SEric.Yu@Sun.COM backlog = backlog * 3 / 2 + 1; 1918348SEric.Yu@Sun.COM 1928348SEric.Yu@Sun.COM return (SOP_LISTEN(so, backlog, cr)); 1938348SEric.Yu@Sun.COM } 1948348SEric.Yu@Sun.COM 1958348SEric.Yu@Sun.COM /* 1968348SEric.Yu@Sun.COM * Accept incoming connection. 1978348SEric.Yu@Sun.COM */ 1988348SEric.Yu@Sun.COM int 1998348SEric.Yu@Sun.COM socket_accept(struct sonode *lso, int fflag, cred_t *cr, struct sonode **nsop) 2008348SEric.Yu@Sun.COM { 2018348SEric.Yu@Sun.COM return (SOP_ACCEPT(lso, fflag, cr, nsop)); 2028348SEric.Yu@Sun.COM } 2038348SEric.Yu@Sun.COM 2048348SEric.Yu@Sun.COM /* 2058348SEric.Yu@Sun.COM * Active open. 2068348SEric.Yu@Sun.COM */ 2078348SEric.Yu@Sun.COM int 2088348SEric.Yu@Sun.COM socket_connect(struct sonode *so, const struct sockaddr *name, 2098348SEric.Yu@Sun.COM socklen_t namelen, int fflag, int flags, cred_t *cr) 2108348SEric.Yu@Sun.COM { 2118348SEric.Yu@Sun.COM int error; 2128348SEric.Yu@Sun.COM 2138348SEric.Yu@Sun.COM /* 2148348SEric.Yu@Sun.COM * Handle a connect to a name parameter of type AF_UNSPEC like a 2158348SEric.Yu@Sun.COM * connect to a null address. This is the portable method to 2168348SEric.Yu@Sun.COM * unconnect a socket. 2178348SEric.Yu@Sun.COM */ 2188348SEric.Yu@Sun.COM if ((namelen >= sizeof (sa_family_t)) && 2198348SEric.Yu@Sun.COM (name->sa_family == AF_UNSPEC)) { 2208348SEric.Yu@Sun.COM name = NULL; 2218348SEric.Yu@Sun.COM namelen = 0; 2228348SEric.Yu@Sun.COM } 2238348SEric.Yu@Sun.COM 2248348SEric.Yu@Sun.COM error = SOP_CONNECT(so, name, namelen, fflag, flags, cr); 2258348SEric.Yu@Sun.COM 2268348SEric.Yu@Sun.COM if (error == EHOSTUNREACH && flags & _SOCONNECT_XPG4_2) { 2278348SEric.Yu@Sun.COM /* 2288348SEric.Yu@Sun.COM * X/Open specification contains a requirement that 2298348SEric.Yu@Sun.COM * ENETUNREACH be returned but does not require 2308348SEric.Yu@Sun.COM * EHOSTUNREACH. In order to keep the test suite 2318348SEric.Yu@Sun.COM * happy we mess with the errno here. 2328348SEric.Yu@Sun.COM */ 2338348SEric.Yu@Sun.COM error = ENETUNREACH; 2348348SEric.Yu@Sun.COM } 2358348SEric.Yu@Sun.COM 2368348SEric.Yu@Sun.COM return (error); 2378348SEric.Yu@Sun.COM } 2388348SEric.Yu@Sun.COM 2398348SEric.Yu@Sun.COM /* 2408348SEric.Yu@Sun.COM * Get address of remote node. 2418348SEric.Yu@Sun.COM */ 2428348SEric.Yu@Sun.COM int 2438348SEric.Yu@Sun.COM socket_getpeername(struct sonode *so, struct sockaddr *addr, 2448348SEric.Yu@Sun.COM socklen_t *addrlen, boolean_t accept, cred_t *cr) 2458348SEric.Yu@Sun.COM { 2468348SEric.Yu@Sun.COM ASSERT(*addrlen > 0); 2478348SEric.Yu@Sun.COM return (SOP_GETPEERNAME(so, addr, addrlen, accept, cr)); 2488348SEric.Yu@Sun.COM 2498348SEric.Yu@Sun.COM } 2508348SEric.Yu@Sun.COM 2518348SEric.Yu@Sun.COM /* 2528348SEric.Yu@Sun.COM * Get local address. 2538348SEric.Yu@Sun.COM */ 2548348SEric.Yu@Sun.COM int 2558348SEric.Yu@Sun.COM socket_getsockname(struct sonode *so, struct sockaddr *addr, 2568348SEric.Yu@Sun.COM socklen_t *addrlen, cred_t *cr) 2578348SEric.Yu@Sun.COM { 2588348SEric.Yu@Sun.COM return (SOP_GETSOCKNAME(so, addr, addrlen, cr)); 2598348SEric.Yu@Sun.COM 2608348SEric.Yu@Sun.COM } 2618348SEric.Yu@Sun.COM 2628348SEric.Yu@Sun.COM /* 2638348SEric.Yu@Sun.COM * Called from shutdown(). 2648348SEric.Yu@Sun.COM */ 2658348SEric.Yu@Sun.COM int 2668348SEric.Yu@Sun.COM socket_shutdown(struct sonode *so, int how, cred_t *cr) 2678348SEric.Yu@Sun.COM { 2688348SEric.Yu@Sun.COM return (SOP_SHUTDOWN(so, how, cr)); 2698348SEric.Yu@Sun.COM } 2708348SEric.Yu@Sun.COM 2718348SEric.Yu@Sun.COM /* 2728348SEric.Yu@Sun.COM * Get socket options. 2738348SEric.Yu@Sun.COM */ 2748348SEric.Yu@Sun.COM /*ARGSUSED*/ 2758348SEric.Yu@Sun.COM int 2768348SEric.Yu@Sun.COM socket_getsockopt(struct sonode *so, int level, int option_name, 2778348SEric.Yu@Sun.COM void *optval, socklen_t *optlenp, int flags, cred_t *cr) 2788348SEric.Yu@Sun.COM { 2798348SEric.Yu@Sun.COM return (SOP_GETSOCKOPT(so, level, option_name, optval, 2808348SEric.Yu@Sun.COM optlenp, flags, cr)); 2818348SEric.Yu@Sun.COM } 2828348SEric.Yu@Sun.COM 2838348SEric.Yu@Sun.COM /* 2848348SEric.Yu@Sun.COM * Set socket options 2858348SEric.Yu@Sun.COM */ 2868348SEric.Yu@Sun.COM int 2878348SEric.Yu@Sun.COM socket_setsockopt(struct sonode *so, int level, int option_name, 2888348SEric.Yu@Sun.COM const void *optval, t_uscalar_t optlen, cred_t *cr) 2898348SEric.Yu@Sun.COM { 2908348SEric.Yu@Sun.COM /* Caller allocates aligned optval, or passes null */ 2918348SEric.Yu@Sun.COM ASSERT(((uintptr_t)optval & (sizeof (t_scalar_t) - 1)) == 0); 2928348SEric.Yu@Sun.COM /* If optval is null optlen is 0, and vice-versa */ 2938348SEric.Yu@Sun.COM ASSERT(optval != NULL || optlen == 0); 2948348SEric.Yu@Sun.COM ASSERT(optlen != 0 || optval == NULL); 2958348SEric.Yu@Sun.COM 2968348SEric.Yu@Sun.COM /* No options should be zero-length */ 2978348SEric.Yu@Sun.COM if (optlen == 0) 2988348SEric.Yu@Sun.COM return (EINVAL); 2998348SEric.Yu@Sun.COM 3008348SEric.Yu@Sun.COM return (SOP_SETSOCKOPT(so, level, option_name, optval, optlen, cr)); 3018348SEric.Yu@Sun.COM } 3028348SEric.Yu@Sun.COM 3038348SEric.Yu@Sun.COM int 3048348SEric.Yu@Sun.COM socket_sendmsg(struct sonode *so, struct nmsghdr *msg, struct uio *uiop, 3058348SEric.Yu@Sun.COM cred_t *cr) 3068348SEric.Yu@Sun.COM { 3078348SEric.Yu@Sun.COM int error = 0; 3088348SEric.Yu@Sun.COM ssize_t orig_resid = uiop->uio_resid; 3098348SEric.Yu@Sun.COM 3108348SEric.Yu@Sun.COM /* 3118348SEric.Yu@Sun.COM * Do not bypass the cache if we are doing a local (AF_UNIX) write. 3128348SEric.Yu@Sun.COM */ 3138348SEric.Yu@Sun.COM if (so->so_family == AF_UNIX) 3148348SEric.Yu@Sun.COM uiop->uio_extflg |= UIO_COPY_CACHED; 3158348SEric.Yu@Sun.COM else 3168348SEric.Yu@Sun.COM uiop->uio_extflg &= ~UIO_COPY_CACHED; 3178348SEric.Yu@Sun.COM 3188348SEric.Yu@Sun.COM error = SOP_SENDMSG(so, msg, uiop, cr); 3198348SEric.Yu@Sun.COM switch (error) { 3208348SEric.Yu@Sun.COM default: 3218348SEric.Yu@Sun.COM break; 3228348SEric.Yu@Sun.COM case EINTR: 3238348SEric.Yu@Sun.COM case ETIME: 3248348SEric.Yu@Sun.COM case EWOULDBLOCK: 3258348SEric.Yu@Sun.COM /* We did a partial send */ 3268348SEric.Yu@Sun.COM if (uiop->uio_resid != orig_resid) 3278348SEric.Yu@Sun.COM error = 0; 3288348SEric.Yu@Sun.COM break; 3298348SEric.Yu@Sun.COM case EPIPE: 3308348SEric.Yu@Sun.COM if ((so->so_mode & SM_KERNEL) == 0) 3318348SEric.Yu@Sun.COM tsignal(curthread, SIGPIPE); 3328348SEric.Yu@Sun.COM break; 3338348SEric.Yu@Sun.COM } 3348348SEric.Yu@Sun.COM 3358348SEric.Yu@Sun.COM return (error); 3368348SEric.Yu@Sun.COM } 3378348SEric.Yu@Sun.COM 3388348SEric.Yu@Sun.COM int 3398348SEric.Yu@Sun.COM socket_sendmblk(struct sonode *so, struct nmsghdr *msg, int fflag, 3408348SEric.Yu@Sun.COM struct cred *cr, mblk_t **mpp) 3418348SEric.Yu@Sun.COM { 3428348SEric.Yu@Sun.COM int error = 0; 3438348SEric.Yu@Sun.COM 3448348SEric.Yu@Sun.COM error = SOP_SENDMBLK(so, msg, fflag, cr, mpp); 3458348SEric.Yu@Sun.COM if (error == EPIPE) { 3468348SEric.Yu@Sun.COM tsignal(curthread, SIGPIPE); 3478348SEric.Yu@Sun.COM } 3488348SEric.Yu@Sun.COM return (error); 3498348SEric.Yu@Sun.COM } 3508348SEric.Yu@Sun.COM 3518348SEric.Yu@Sun.COM int 3528348SEric.Yu@Sun.COM socket_recvmsg(struct sonode *so, struct nmsghdr *msg, struct uio *uiop, 3538348SEric.Yu@Sun.COM cred_t *cr) 3548348SEric.Yu@Sun.COM { 3558348SEric.Yu@Sun.COM int error; 3568348SEric.Yu@Sun.COM ssize_t orig_resid = uiop->uio_resid; 3578348SEric.Yu@Sun.COM 3588348SEric.Yu@Sun.COM /* 3598348SEric.Yu@Sun.COM * Do not bypass the cache when reading data, as the application 3608348SEric.Yu@Sun.COM * is likely to access the data shortly. 3618348SEric.Yu@Sun.COM */ 3628348SEric.Yu@Sun.COM uiop->uio_extflg |= UIO_COPY_CACHED; 3638348SEric.Yu@Sun.COM 3648348SEric.Yu@Sun.COM error = SOP_RECVMSG(so, msg, uiop, cr); 3658348SEric.Yu@Sun.COM 3668348SEric.Yu@Sun.COM switch (error) { 3678348SEric.Yu@Sun.COM case EINTR: 3688348SEric.Yu@Sun.COM case ETIME: 3698348SEric.Yu@Sun.COM case EWOULDBLOCK: 3708348SEric.Yu@Sun.COM /* We did a partial read */ 3718348SEric.Yu@Sun.COM if (uiop->uio_resid != orig_resid) 3728348SEric.Yu@Sun.COM error = 0; 3738348SEric.Yu@Sun.COM break; 3748348SEric.Yu@Sun.COM default: 3758348SEric.Yu@Sun.COM break; 3768348SEric.Yu@Sun.COM } 3778348SEric.Yu@Sun.COM return (error); 3788348SEric.Yu@Sun.COM } 3798348SEric.Yu@Sun.COM 3808348SEric.Yu@Sun.COM int 3818348SEric.Yu@Sun.COM socket_ioctl(struct sonode *so, int cmd, intptr_t arg, int mode, 3828348SEric.Yu@Sun.COM struct cred *cr, int32_t *rvalp) 3838348SEric.Yu@Sun.COM { 3848348SEric.Yu@Sun.COM return (SOP_IOCTL(so, cmd, arg, mode, cr, rvalp)); 3858348SEric.Yu@Sun.COM } 3868348SEric.Yu@Sun.COM 3878348SEric.Yu@Sun.COM int 3888348SEric.Yu@Sun.COM socket_poll(struct sonode *so, short events, int anyyet, short *reventsp, 3898348SEric.Yu@Sun.COM struct pollhead **phpp) 3908348SEric.Yu@Sun.COM { 3918348SEric.Yu@Sun.COM return (SOP_POLL(so, events, anyyet, reventsp, phpp)); 3928348SEric.Yu@Sun.COM } 3938348SEric.Yu@Sun.COM 3948348SEric.Yu@Sun.COM int 3958348SEric.Yu@Sun.COM socket_close(struct sonode *so, int flag, struct cred *cr) 3968348SEric.Yu@Sun.COM { 3978348SEric.Yu@Sun.COM return (VOP_CLOSE(SOTOV(so), flag, 1, 0, cr, NULL)); 3988348SEric.Yu@Sun.COM } 3998348SEric.Yu@Sun.COM 4008348SEric.Yu@Sun.COM int 4018348SEric.Yu@Sun.COM socket_close_internal(struct sonode *so, int flag, cred_t *cr) 4028348SEric.Yu@Sun.COM { 4038348SEric.Yu@Sun.COM ASSERT(so->so_count == 0); 4048348SEric.Yu@Sun.COM 4058348SEric.Yu@Sun.COM return (SOP_CLOSE(so, flag, cr)); 4068348SEric.Yu@Sun.COM } 4078348SEric.Yu@Sun.COM 4088348SEric.Yu@Sun.COM void 4098348SEric.Yu@Sun.COM socket_destroy(struct sonode *so) 4108348SEric.Yu@Sun.COM { 4118348SEric.Yu@Sun.COM vn_invalid(SOTOV(so)); 4128348SEric.Yu@Sun.COM VN_RELE(SOTOV(so)); 4138348SEric.Yu@Sun.COM } 4148348SEric.Yu@Sun.COM 4158348SEric.Yu@Sun.COM /* ARGSUSED */ 4168348SEric.Yu@Sun.COM void 4178348SEric.Yu@Sun.COM socket_destroy_internal(struct sonode *so, cred_t *cr) 4188348SEric.Yu@Sun.COM { 4198348SEric.Yu@Sun.COM struct sockparams *sp = so->so_sockparams; 4208348SEric.Yu@Sun.COM ASSERT(so->so_count == 0 && sp != NULL); 4218348SEric.Yu@Sun.COM 4228348SEric.Yu@Sun.COM sp->sp_smod_info->smod_sock_destroy_func(so); 4238348SEric.Yu@Sun.COM 4248348SEric.Yu@Sun.COM SOCKPARAMS_DEC_REF(sp); 4258348SEric.Yu@Sun.COM } 4268348SEric.Yu@Sun.COM 4278348SEric.Yu@Sun.COM /* 4288348SEric.Yu@Sun.COM * TODO Once the common vnode ops is available, then the vnops argument 4298348SEric.Yu@Sun.COM * should be removed. 4308348SEric.Yu@Sun.COM */ 4318348SEric.Yu@Sun.COM /*ARGSUSED*/ 4328348SEric.Yu@Sun.COM int 4338348SEric.Yu@Sun.COM sonode_constructor(void *buf, void *cdrarg, int kmflags) 4348348SEric.Yu@Sun.COM { 4358348SEric.Yu@Sun.COM struct sonode *so = buf; 4368348SEric.Yu@Sun.COM struct vnode *vp; 4378348SEric.Yu@Sun.COM 4388348SEric.Yu@Sun.COM vp = so->so_vnode = vn_alloc(kmflags); 4398348SEric.Yu@Sun.COM if (vp == NULL) { 4408348SEric.Yu@Sun.COM return (-1); 4418348SEric.Yu@Sun.COM } 4428348SEric.Yu@Sun.COM vp->v_data = so; 4438348SEric.Yu@Sun.COM vn_setops(vp, socket_vnodeops); 4448348SEric.Yu@Sun.COM 4458348SEric.Yu@Sun.COM so->so_priv = NULL; 4468348SEric.Yu@Sun.COM so->so_oobmsg = NULL; 4478348SEric.Yu@Sun.COM 4488348SEric.Yu@Sun.COM so->so_proto_handle = NULL; 4498348SEric.Yu@Sun.COM 4508348SEric.Yu@Sun.COM so->so_peercred = NULL; 4518348SEric.Yu@Sun.COM 4528348SEric.Yu@Sun.COM so->so_rcv_queued = 0; 4538348SEric.Yu@Sun.COM so->so_rcv_q_head = NULL; 4548348SEric.Yu@Sun.COM so->so_rcv_q_last_head = NULL; 4558348SEric.Yu@Sun.COM so->so_rcv_head = NULL; 4568348SEric.Yu@Sun.COM so->so_rcv_last_head = NULL; 4578348SEric.Yu@Sun.COM so->so_rcv_wanted = 0; 4588348SEric.Yu@Sun.COM so->so_rcv_timer_interval = SOCKET_NO_RCVTIMER; 4598348SEric.Yu@Sun.COM so->so_rcv_timer_tid = 0; 4608348SEric.Yu@Sun.COM so->so_rcv_thresh = 0; 4618348SEric.Yu@Sun.COM 4628348SEric.Yu@Sun.COM so->so_acceptq_head = NULL; 4638348SEric.Yu@Sun.COM so->so_acceptq_tail = &so->so_acceptq_head; 4648348SEric.Yu@Sun.COM so->so_acceptq_next = NULL; 4658348SEric.Yu@Sun.COM so->so_acceptq_len = 0; 4668348SEric.Yu@Sun.COM so->so_backlog = 0; 4678348SEric.Yu@Sun.COM 4688348SEric.Yu@Sun.COM so->so_snd_qfull = B_FALSE; 4698348SEric.Yu@Sun.COM 4708348SEric.Yu@Sun.COM mutex_init(&so->so_lock, NULL, MUTEX_DEFAULT, NULL); 4718348SEric.Yu@Sun.COM mutex_init(&so->so_acceptq_lock, NULL, MUTEX_DEFAULT, NULL); 4728348SEric.Yu@Sun.COM rw_init(&so->so_fallback_rwlock, NULL, RW_DEFAULT, NULL); 4738348SEric.Yu@Sun.COM cv_init(&so->so_state_cv, NULL, CV_DEFAULT, NULL); 4748348SEric.Yu@Sun.COM cv_init(&so->so_want_cv, NULL, CV_DEFAULT, NULL); 4758348SEric.Yu@Sun.COM 4768348SEric.Yu@Sun.COM cv_init(&so->so_acceptq_cv, NULL, CV_DEFAULT, NULL); 4778348SEric.Yu@Sun.COM cv_init(&so->so_snd_cv, NULL, CV_DEFAULT, NULL); 4788348SEric.Yu@Sun.COM cv_init(&so->so_rcv_cv, NULL, CV_DEFAULT, NULL); 4798348SEric.Yu@Sun.COM cv_init(&so->so_copy_cv, NULL, CV_DEFAULT, NULL); 4808348SEric.Yu@Sun.COM cv_init(&so->so_closing_cv, NULL, CV_DEFAULT, NULL); 4818348SEric.Yu@Sun.COM 4828348SEric.Yu@Sun.COM return (0); 4838348SEric.Yu@Sun.COM } 4848348SEric.Yu@Sun.COM 4858348SEric.Yu@Sun.COM /*ARGSUSED*/ 4868348SEric.Yu@Sun.COM void 4878348SEric.Yu@Sun.COM sonode_destructor(void *buf, void *cdrarg) 4888348SEric.Yu@Sun.COM { 4898348SEric.Yu@Sun.COM struct sonode *so = buf; 4908348SEric.Yu@Sun.COM struct vnode *vp = SOTOV(so); 4918348SEric.Yu@Sun.COM 4928348SEric.Yu@Sun.COM ASSERT(so->so_priv == NULL); 4938348SEric.Yu@Sun.COM ASSERT(so->so_peercred == NULL); 4948348SEric.Yu@Sun.COM 4958348SEric.Yu@Sun.COM ASSERT(so->so_oobmsg == NULL); 4968348SEric.Yu@Sun.COM 4978348SEric.Yu@Sun.COM ASSERT(so->so_rcv_q_head == NULL); 4988348SEric.Yu@Sun.COM 4998348SEric.Yu@Sun.COM ASSERT(so->so_acceptq_head == NULL); 5008348SEric.Yu@Sun.COM ASSERT(so->so_acceptq_tail == &so->so_acceptq_head); 5018348SEric.Yu@Sun.COM ASSERT(so->so_acceptq_next == NULL); 5028348SEric.Yu@Sun.COM 5038348SEric.Yu@Sun.COM ASSERT(vp->v_data == so); 5048348SEric.Yu@Sun.COM ASSERT(vn_matchops(vp, socket_vnodeops)); 5058348SEric.Yu@Sun.COM 5068348SEric.Yu@Sun.COM vn_free(vp); 5078348SEric.Yu@Sun.COM 5088348SEric.Yu@Sun.COM mutex_destroy(&so->so_lock); 5098348SEric.Yu@Sun.COM mutex_destroy(&so->so_acceptq_lock); 5108348SEric.Yu@Sun.COM rw_destroy(&so->so_fallback_rwlock); 5118348SEric.Yu@Sun.COM 5128348SEric.Yu@Sun.COM cv_destroy(&so->so_state_cv); 5138348SEric.Yu@Sun.COM cv_destroy(&so->so_want_cv); 5148348SEric.Yu@Sun.COM cv_destroy(&so->so_acceptq_cv); 5158348SEric.Yu@Sun.COM cv_destroy(&so->so_snd_cv); 5168348SEric.Yu@Sun.COM cv_destroy(&so->so_rcv_cv); 5178348SEric.Yu@Sun.COM cv_destroy(&so->so_closing_cv); 5188348SEric.Yu@Sun.COM } 5198348SEric.Yu@Sun.COM 5208348SEric.Yu@Sun.COM void 5218348SEric.Yu@Sun.COM sonode_init(struct sonode *so, struct sockparams *sp, int family, 5228348SEric.Yu@Sun.COM int type, int protocol, sonodeops_t *sops) 5238348SEric.Yu@Sun.COM { 5248348SEric.Yu@Sun.COM vnode_t *vp; 5258348SEric.Yu@Sun.COM 5268348SEric.Yu@Sun.COM vp = SOTOV(so); 5278348SEric.Yu@Sun.COM 5288348SEric.Yu@Sun.COM so->so_flag = 0; 5298348SEric.Yu@Sun.COM 5308348SEric.Yu@Sun.COM so->so_state = 0; 5318348SEric.Yu@Sun.COM so->so_mode = 0; 5328348SEric.Yu@Sun.COM 5338348SEric.Yu@Sun.COM so->so_count = 0; 5348348SEric.Yu@Sun.COM 5358348SEric.Yu@Sun.COM so->so_family = family; 5368348SEric.Yu@Sun.COM so->so_type = type; 5378348SEric.Yu@Sun.COM so->so_protocol = protocol; 5388348SEric.Yu@Sun.COM 5398348SEric.Yu@Sun.COM SOCK_CONNID_INIT(so->so_proto_connid); 5408348SEric.Yu@Sun.COM 5418348SEric.Yu@Sun.COM so->so_options = 0; 5428348SEric.Yu@Sun.COM so->so_linger.l_onoff = 0; 5438348SEric.Yu@Sun.COM so->so_linger.l_linger = 0; 5448348SEric.Yu@Sun.COM so->so_sndbuf = 0; 5458348SEric.Yu@Sun.COM so->so_error = 0; 5468348SEric.Yu@Sun.COM so->so_rcvtimeo = 0; 5478348SEric.Yu@Sun.COM so->so_sndtimeo = 0; 548*8465SEric.Yu@Sun.COM so->so_xpg_rcvbuf = 0; 5498348SEric.Yu@Sun.COM 5508348SEric.Yu@Sun.COM ASSERT(so->so_oobmsg == NULL); 5518348SEric.Yu@Sun.COM so->so_oobmark = 0; 5528348SEric.Yu@Sun.COM so->so_pgrp = 0; 5538348SEric.Yu@Sun.COM 5548348SEric.Yu@Sun.COM ASSERT(so->so_peercred == NULL); 5558348SEric.Yu@Sun.COM 5568348SEric.Yu@Sun.COM so->so_zoneid = getzoneid(); 5578348SEric.Yu@Sun.COM 5588348SEric.Yu@Sun.COM so->so_sockparams = sp; 5598348SEric.Yu@Sun.COM 5608348SEric.Yu@Sun.COM so->so_ops = sops; 5618348SEric.Yu@Sun.COM 5628399SRao.Shoaib@Sun.COM so->so_not_str = (sops != &sotpi_sonodeops); 5638399SRao.Shoaib@Sun.COM 5648348SEric.Yu@Sun.COM so->so_proto_handle = NULL; 5658348SEric.Yu@Sun.COM 5668348SEric.Yu@Sun.COM so->so_downcalls = NULL; 5678348SEric.Yu@Sun.COM 5688348SEric.Yu@Sun.COM so->so_copyflag = 0; 5698348SEric.Yu@Sun.COM 5708348SEric.Yu@Sun.COM ASSERT(so->so_acceptq_head == NULL); 5718348SEric.Yu@Sun.COM ASSERT(so->so_acceptq_tail == &so->so_acceptq_head); 5728348SEric.Yu@Sun.COM ASSERT(so->so_acceptq_next == NULL); 5738348SEric.Yu@Sun.COM 5748348SEric.Yu@Sun.COM vn_reinit(vp); 5758348SEric.Yu@Sun.COM vp->v_vfsp = rootvfs; 5768348SEric.Yu@Sun.COM vp->v_type = VSOCK; 5778348SEric.Yu@Sun.COM vp->v_rdev = sockdev; 5788348SEric.Yu@Sun.COM 5798348SEric.Yu@Sun.COM so->so_rcv_queued = 0; 5808348SEric.Yu@Sun.COM so->so_rcv_q_head = NULL; 5818348SEric.Yu@Sun.COM so->so_rcv_q_last_head = NULL; 5828348SEric.Yu@Sun.COM so->so_rcv_head = NULL; 5838348SEric.Yu@Sun.COM so->so_rcv_last_head = NULL; 5848348SEric.Yu@Sun.COM 5858348SEric.Yu@Sun.COM so->so_snd_qfull = B_FALSE; 5868348SEric.Yu@Sun.COM so->so_minpsz = 0; 5878348SEric.Yu@Sun.COM 5888348SEric.Yu@Sun.COM so->so_rcv_wakeup = B_FALSE; 5898348SEric.Yu@Sun.COM so->so_snd_wakeup = B_FALSE; 5908348SEric.Yu@Sun.COM so->so_flowctrld = B_FALSE; 5918348SEric.Yu@Sun.COM 5928348SEric.Yu@Sun.COM so->so_pollev = 0; 5938348SEric.Yu@Sun.COM bzero(&so->so_poll_list, sizeof (so->so_poll_list)); 5948348SEric.Yu@Sun.COM bzero(&so->so_proto_props, sizeof (struct sock_proto_props)); 5958348SEric.Yu@Sun.COM 5968348SEric.Yu@Sun.COM bzero(&(so->so_ksock_callbacks), sizeof (ksocket_callbacks_t)); 5978348SEric.Yu@Sun.COM so->so_ksock_cb_arg = NULL; 5988348SEric.Yu@Sun.COM 5998348SEric.Yu@Sun.COM so->so_max_addr_len = sizeof (struct sockaddr_storage); 6008348SEric.Yu@Sun.COM 6018348SEric.Yu@Sun.COM so->so_direct = NULL; 6028348SEric.Yu@Sun.COM 6038348SEric.Yu@Sun.COM vn_exists(vp); 6048348SEric.Yu@Sun.COM } 6058348SEric.Yu@Sun.COM 6068348SEric.Yu@Sun.COM void 6078348SEric.Yu@Sun.COM sonode_fini(struct sonode *so) 6088348SEric.Yu@Sun.COM { 6098348SEric.Yu@Sun.COM mblk_t *mp; 6108348SEric.Yu@Sun.COM vnode_t *vp; 6118348SEric.Yu@Sun.COM 6128348SEric.Yu@Sun.COM ASSERT(so->so_count == 0); 6138348SEric.Yu@Sun.COM 6148348SEric.Yu@Sun.COM if (so->so_rcv_timer_tid) { 6158348SEric.Yu@Sun.COM ASSERT(MUTEX_NOT_HELD(&so->so_lock)); 6168348SEric.Yu@Sun.COM (void) untimeout(so->so_rcv_timer_tid); 6178348SEric.Yu@Sun.COM so->so_rcv_timer_tid = 0; 6188348SEric.Yu@Sun.COM } 6198348SEric.Yu@Sun.COM 6208348SEric.Yu@Sun.COM so_acceptq_flush(so); 6218348SEric.Yu@Sun.COM 6228348SEric.Yu@Sun.COM if ((mp = so->so_oobmsg) != NULL) { 6238348SEric.Yu@Sun.COM freemsg(mp); 6248348SEric.Yu@Sun.COM so->so_oobmsg = NULL; 6258348SEric.Yu@Sun.COM so->so_state &= ~(SS_OOBPEND|SS_HAVEOOBDATA|SS_HADOOBDATA| 6268348SEric.Yu@Sun.COM SS_RCVATMARK); 6278348SEric.Yu@Sun.COM } 6288348SEric.Yu@Sun.COM 6298348SEric.Yu@Sun.COM if (so->so_poll_list.ph_list != NULL) { 6308348SEric.Yu@Sun.COM pollwakeup(&so->so_poll_list, POLLERR); 6318348SEric.Yu@Sun.COM pollhead_clean(&so->so_poll_list); 6328348SEric.Yu@Sun.COM } 6338348SEric.Yu@Sun.COM 6348348SEric.Yu@Sun.COM if (so->so_direct != NULL) { 6358348SEric.Yu@Sun.COM sodirect_t *sodp = so->so_direct; 6368348SEric.Yu@Sun.COM 6378348SEric.Yu@Sun.COM ASSERT(sodp->sod_uioafh == NULL); 6388348SEric.Yu@Sun.COM 6398348SEric.Yu@Sun.COM so->so_direct = NULL; 6408348SEric.Yu@Sun.COM kmem_cache_free(sock_sod_cache, sodp); 6418348SEric.Yu@Sun.COM } 6428348SEric.Yu@Sun.COM 6438348SEric.Yu@Sun.COM vp = SOTOV(so); 6448348SEric.Yu@Sun.COM vn_invalid(vp); 6458348SEric.Yu@Sun.COM 6468348SEric.Yu@Sun.COM if (so->so_peercred != NULL) { 6478348SEric.Yu@Sun.COM crfree(so->so_peercred); 6488348SEric.Yu@Sun.COM so->so_peercred = NULL; 6498348SEric.Yu@Sun.COM } 6508348SEric.Yu@Sun.COM } 6518348SEric.Yu@Sun.COM 6528348SEric.Yu@Sun.COM /* 6538348SEric.Yu@Sun.COM * This function is called at the beginning of recvmsg(). 6548348SEric.Yu@Sun.COM * 6558348SEric.Yu@Sun.COM * If I/OAT is enabled on this sonode, initialize the uioa state machine 6568348SEric.Yu@Sun.COM * with state UIOA_ALLOC. 6578348SEric.Yu@Sun.COM */ 6588348SEric.Yu@Sun.COM uio_t * 6598348SEric.Yu@Sun.COM sod_rcv_init(struct sonode *so, int flags, struct uio **uiopp) 6608348SEric.Yu@Sun.COM { 6618348SEric.Yu@Sun.COM struct uio *suiop; 6628348SEric.Yu@Sun.COM struct uio *uiop; 6638348SEric.Yu@Sun.COM sodirect_t *sodp = so->so_direct; 6648348SEric.Yu@Sun.COM 6658348SEric.Yu@Sun.COM if (sodp == NULL) 6668348SEric.Yu@Sun.COM return (NULL); 6678348SEric.Yu@Sun.COM 6688348SEric.Yu@Sun.COM suiop = NULL; 6698348SEric.Yu@Sun.COM uiop = *uiopp; 6708348SEric.Yu@Sun.COM 6718348SEric.Yu@Sun.COM mutex_enter(sodp->sod_lockp); 6728348SEric.Yu@Sun.COM if (uiop->uio_resid >= uioasync.mincnt && 6738348SEric.Yu@Sun.COM sodp != NULL && (sodp->sod_state & SOD_ENABLED) && 6748348SEric.Yu@Sun.COM uioasync.enabled && !(flags & MSG_PEEK) && 6758348SEric.Yu@Sun.COM !(so->so_state & SS_CANTRCVMORE)) { 6768348SEric.Yu@Sun.COM /* 6778348SEric.Yu@Sun.COM * Big enough I/O for uioa min setup and an sodirect socket 6788348SEric.Yu@Sun.COM * and sodirect enabled and uioa enabled and I/O will be done 6798348SEric.Yu@Sun.COM * and not EOF so initialize the sodirect_t uioa_t with "uiop". 6808348SEric.Yu@Sun.COM */ 6818348SEric.Yu@Sun.COM if (!uioainit(uiop, &sodp->sod_uioa)) { 6828348SEric.Yu@Sun.COM /* 6838348SEric.Yu@Sun.COM * Successful uioainit() so the uio_t part of the 6848348SEric.Yu@Sun.COM * uioa_t will be used for all uio_t work to follow, 6858348SEric.Yu@Sun.COM * we return the original "uiop" in "suiop". 6868348SEric.Yu@Sun.COM */ 6878348SEric.Yu@Sun.COM suiop = uiop; 6888348SEric.Yu@Sun.COM *uiopp = (uio_t *)&sodp->sod_uioa; 6898348SEric.Yu@Sun.COM /* 6908348SEric.Yu@Sun.COM * Before returning to the caller the passed in uio_t 6918348SEric.Yu@Sun.COM * "uiop" will be updated via a call to uioafini() 6928348SEric.Yu@Sun.COM * below. 6938348SEric.Yu@Sun.COM * 6948348SEric.Yu@Sun.COM * Note, the uioa.uioa_state isn't set to UIOA_ENABLED 6958348SEric.Yu@Sun.COM * here as first we have to uioamove() any currently 6968348SEric.Yu@Sun.COM * queued M_DATA mblk_t(s) so it will be done later. 6978348SEric.Yu@Sun.COM */ 6988348SEric.Yu@Sun.COM } 6998348SEric.Yu@Sun.COM /* 7008348SEric.Yu@Sun.COM * In either uioainit() success or not case note the number 7018348SEric.Yu@Sun.COM * of uio bytes the caller wants for sod framework and/or 7028348SEric.Yu@Sun.COM * transport (e.g. TCP) strategy. 7038348SEric.Yu@Sun.COM */ 7048348SEric.Yu@Sun.COM sodp->sod_want = uiop->uio_resid; 7058348SEric.Yu@Sun.COM } else if (sodp != NULL && (sodp->sod_state & SOD_ENABLED)) { 7068348SEric.Yu@Sun.COM /* 7078348SEric.Yu@Sun.COM * No uioa but still using sodirect so note the number of 7088348SEric.Yu@Sun.COM * uio bytes the caller wants for sodirect framework and/or 7098348SEric.Yu@Sun.COM * transport (e.g. TCP) strategy. 7108348SEric.Yu@Sun.COM */ 7118348SEric.Yu@Sun.COM sodp->sod_want = uiop->uio_resid; 7128348SEric.Yu@Sun.COM } 7138348SEric.Yu@Sun.COM mutex_exit(sodp->sod_lockp); 7148348SEric.Yu@Sun.COM 7158348SEric.Yu@Sun.COM return (suiop); 7168348SEric.Yu@Sun.COM } 7178348SEric.Yu@Sun.COM 7188348SEric.Yu@Sun.COM /* 7198348SEric.Yu@Sun.COM * This function is called at the end of recvmsg(), it finializes all the I/OAT 7208348SEric.Yu@Sun.COM * operations, and reset the uioa state to UIOA_ALLOC. 7218348SEric.Yu@Sun.COM */ 7228348SEric.Yu@Sun.COM int 7238348SEric.Yu@Sun.COM sod_rcv_done(struct sonode *so, struct uio *suiop, struct uio *uiop) 7248348SEric.Yu@Sun.COM { 7258348SEric.Yu@Sun.COM int error = 0; 7268348SEric.Yu@Sun.COM sodirect_t *sodp = so->so_direct; 7278348SEric.Yu@Sun.COM mblk_t *mp; 7288348SEric.Yu@Sun.COM 7298348SEric.Yu@Sun.COM if (sodp == NULL) { 7308348SEric.Yu@Sun.COM return (0); 7318348SEric.Yu@Sun.COM } 7328348SEric.Yu@Sun.COM 7338348SEric.Yu@Sun.COM ASSERT(MUTEX_HELD(sodp->sod_lockp)); 7348348SEric.Yu@Sun.COM /* Finish any sodirect and uioa processing */ 7358348SEric.Yu@Sun.COM if (suiop != NULL) { 7368348SEric.Yu@Sun.COM /* Finish any uioa_t processing */ 7378348SEric.Yu@Sun.COM 7388348SEric.Yu@Sun.COM ASSERT(uiop == (uio_t *)&sodp->sod_uioa); 7398348SEric.Yu@Sun.COM error = uioafini(suiop, (uioa_t *)uiop); 7408348SEric.Yu@Sun.COM if ((mp = sodp->sod_uioafh) != NULL) { 7418348SEric.Yu@Sun.COM sodp->sod_uioafh = NULL; 7428348SEric.Yu@Sun.COM sodp->sod_uioaft = NULL; 7438348SEric.Yu@Sun.COM freemsg(mp); 7448348SEric.Yu@Sun.COM } 7458348SEric.Yu@Sun.COM } 7468348SEric.Yu@Sun.COM ASSERT(sodp->sod_uioafh == NULL); 7478348SEric.Yu@Sun.COM if (!(sodp->sod_state & SOD_WAKE_NOT)) { 7488348SEric.Yu@Sun.COM /* Awoke */ 7498348SEric.Yu@Sun.COM sodp->sod_state &= SOD_WAKE_CLR; 7508348SEric.Yu@Sun.COM sodp->sod_state |= SOD_WAKE_NOT; 7518348SEric.Yu@Sun.COM } 7528348SEric.Yu@Sun.COM /* Last, clear sod_want value */ 7538348SEric.Yu@Sun.COM sodp->sod_want = 0; 7548348SEric.Yu@Sun.COM 7558348SEric.Yu@Sun.COM return (error); 7568348SEric.Yu@Sun.COM } 7578348SEric.Yu@Sun.COM 7588348SEric.Yu@Sun.COM /* 7598348SEric.Yu@Sun.COM * Schedule a uioamove() on a mblk. This is ususally called from 7608348SEric.Yu@Sun.COM * protocols (e.g. TCP) on a I/OAT enabled sonode. 7618348SEric.Yu@Sun.COM */ 7628348SEric.Yu@Sun.COM mblk_t * 7638348SEric.Yu@Sun.COM sod_uioa_mblk_init(struct sodirect_s *sodp, mblk_t *mp, size_t msg_size) 7648348SEric.Yu@Sun.COM { 7658348SEric.Yu@Sun.COM uioa_t *uioap = &sodp->sod_uioa; 7668348SEric.Yu@Sun.COM mblk_t *mp1 = mp; 7678348SEric.Yu@Sun.COM mblk_t *lmp = NULL; 7688348SEric.Yu@Sun.COM 7698348SEric.Yu@Sun.COM ASSERT(DB_TYPE(mp) == M_DATA); 7708348SEric.Yu@Sun.COM ASSERT(msg_size == msgdsize(mp)); 7718348SEric.Yu@Sun.COM 7728348SEric.Yu@Sun.COM /* Caller must have lock held */ 7738348SEric.Yu@Sun.COM ASSERT(MUTEX_HELD(sodp->sod_lockp)); 7748348SEric.Yu@Sun.COM 7758348SEric.Yu@Sun.COM if (uioap->uioa_state & UIOA_ENABLED) { 7768348SEric.Yu@Sun.COM /* Uioa is enabled */ 7778348SEric.Yu@Sun.COM 7788348SEric.Yu@Sun.COM if (msg_size > uioap->uio_resid) { 7798348SEric.Yu@Sun.COM /* 7808348SEric.Yu@Sun.COM * There isn't enough uio space for the mblk_t chain 7818348SEric.Yu@Sun.COM * so disable uioa such that this and any additional 7828348SEric.Yu@Sun.COM * mblk_t data is handled by the socket and schedule 7838348SEric.Yu@Sun.COM * the socket for wakeup to finish this uioa. 7848348SEric.Yu@Sun.COM */ 7858348SEric.Yu@Sun.COM uioap->uioa_state &= UIOA_CLR; 7868348SEric.Yu@Sun.COM uioap->uioa_state |= UIOA_FINI; 7878348SEric.Yu@Sun.COM if (sodp->sod_state & SOD_WAKE_NOT) { 7888348SEric.Yu@Sun.COM sodp->sod_state &= SOD_WAKE_CLR; 7898348SEric.Yu@Sun.COM sodp->sod_state |= SOD_WAKE_NEED; 7908348SEric.Yu@Sun.COM } 7918348SEric.Yu@Sun.COM return (mp); 7928348SEric.Yu@Sun.COM } 7938348SEric.Yu@Sun.COM do { 7948348SEric.Yu@Sun.COM uint32_t len = MBLKL(mp1); 7958348SEric.Yu@Sun.COM 7968348SEric.Yu@Sun.COM if (!uioamove(mp1->b_rptr, len, UIO_READ, uioap)) { 7978348SEric.Yu@Sun.COM /* Scheduled, mark dblk_t as such */ 7988348SEric.Yu@Sun.COM DB_FLAGS(mp1) |= DBLK_UIOA; 7998348SEric.Yu@Sun.COM } else { 8008348SEric.Yu@Sun.COM /* Error, turn off async processing */ 8018348SEric.Yu@Sun.COM uioap->uioa_state &= UIOA_CLR; 8028348SEric.Yu@Sun.COM uioap->uioa_state |= UIOA_FINI; 8038348SEric.Yu@Sun.COM break; 8048348SEric.Yu@Sun.COM } 8058348SEric.Yu@Sun.COM lmp = mp1; 8068348SEric.Yu@Sun.COM } while ((mp1 = mp1->b_cont) != NULL); 8078348SEric.Yu@Sun.COM 8088348SEric.Yu@Sun.COM if (mp1 != NULL || uioap->uio_resid == 0) { 8098348SEric.Yu@Sun.COM /* 8108348SEric.Yu@Sun.COM * Not all mblk_t(s) uioamoved (error) or all uio 8118348SEric.Yu@Sun.COM * space has been consumed so schedule the socket 8128348SEric.Yu@Sun.COM * for wakeup to finish this uio. 8138348SEric.Yu@Sun.COM */ 8148348SEric.Yu@Sun.COM sodp->sod_state &= SOD_WAKE_CLR; 8158348SEric.Yu@Sun.COM sodp->sod_state |= SOD_WAKE_NEED; 8168348SEric.Yu@Sun.COM 8178348SEric.Yu@Sun.COM /* Break the mblk chain if neccessary. */ 8188348SEric.Yu@Sun.COM if (mp1 != NULL && lmp != NULL) { 8198348SEric.Yu@Sun.COM mp->b_next = mp1; 8208348SEric.Yu@Sun.COM lmp->b_cont = NULL; 8218348SEric.Yu@Sun.COM } 8228348SEric.Yu@Sun.COM } 8238348SEric.Yu@Sun.COM } 8248348SEric.Yu@Sun.COM return (mp1); 8258348SEric.Yu@Sun.COM } 8268348SEric.Yu@Sun.COM 8278348SEric.Yu@Sun.COM /* 8288348SEric.Yu@Sun.COM * This function is called on a mblk that thas been successfully uioamoved(). 8298348SEric.Yu@Sun.COM */ 8308348SEric.Yu@Sun.COM void 8318348SEric.Yu@Sun.COM sod_uioa_mblk_done(sodirect_t *sodp, mblk_t *bp) 8328348SEric.Yu@Sun.COM { 8338348SEric.Yu@Sun.COM if (bp != NULL && (bp->b_datap->db_flags & DBLK_UIOA)) { 8348348SEric.Yu@Sun.COM /* 8358348SEric.Yu@Sun.COM * A uioa flaged mblk_t chain, already uio processed, 8368348SEric.Yu@Sun.COM * add it to the sodirect uioa pending free list. 8378348SEric.Yu@Sun.COM * 8388348SEric.Yu@Sun.COM * Note, a b_cont chain headed by a DBLK_UIOA enable 8398348SEric.Yu@Sun.COM * mblk_t must have all mblk_t(s) DBLK_UIOA enabled. 8408348SEric.Yu@Sun.COM */ 8418348SEric.Yu@Sun.COM mblk_t *bpt = sodp->sod_uioaft; 8428348SEric.Yu@Sun.COM 8438348SEric.Yu@Sun.COM ASSERT(sodp != NULL); 8448348SEric.Yu@Sun.COM 8458348SEric.Yu@Sun.COM /* 8468348SEric.Yu@Sun.COM * Add first mblk_t of "bp" chain to current sodirect uioa 8478348SEric.Yu@Sun.COM * free list tail mblk_t, if any, else empty list so new head. 8488348SEric.Yu@Sun.COM */ 8498348SEric.Yu@Sun.COM if (bpt == NULL) 8508348SEric.Yu@Sun.COM sodp->sod_uioafh = bp; 8518348SEric.Yu@Sun.COM else 8528348SEric.Yu@Sun.COM bpt->b_cont = bp; 8538348SEric.Yu@Sun.COM 8548348SEric.Yu@Sun.COM /* 8558348SEric.Yu@Sun.COM * Walk mblk_t "bp" chain to find tail and adjust rptr of 8568348SEric.Yu@Sun.COM * each to reflect that uioamove() has consumed all data. 8578348SEric.Yu@Sun.COM */ 8588348SEric.Yu@Sun.COM bpt = bp; 8598348SEric.Yu@Sun.COM for (;;) { 8608348SEric.Yu@Sun.COM ASSERT(bpt->b_datap->db_flags & DBLK_UIOA); 8618348SEric.Yu@Sun.COM 8628348SEric.Yu@Sun.COM bpt->b_rptr = bpt->b_wptr; 8638348SEric.Yu@Sun.COM if (bpt->b_cont == NULL) 8648348SEric.Yu@Sun.COM break; 8658348SEric.Yu@Sun.COM bpt = bpt->b_cont; 8668348SEric.Yu@Sun.COM } 8678348SEric.Yu@Sun.COM /* New sodirect uioa free list tail */ 8688348SEric.Yu@Sun.COM sodp->sod_uioaft = bpt; 8698348SEric.Yu@Sun.COM 8708348SEric.Yu@Sun.COM /* Only dequeue once with data returned per uioa_t */ 8718348SEric.Yu@Sun.COM if (sodp->sod_uioa.uioa_state & UIOA_ENABLED) { 8728348SEric.Yu@Sun.COM sodp->sod_uioa.uioa_state &= UIOA_CLR; 8738348SEric.Yu@Sun.COM sodp->sod_uioa.uioa_state |= UIOA_FINI; 8748348SEric.Yu@Sun.COM } 8758348SEric.Yu@Sun.COM } 8768348SEric.Yu@Sun.COM } 8778348SEric.Yu@Sun.COM 8788348SEric.Yu@Sun.COM /* 8798348SEric.Yu@Sun.COM * When transit from UIOA_INIT state to UIOA_ENABLE state in recvmsg(), call 8808348SEric.Yu@Sun.COM * this function on a non-STREAMS socket to schedule uioamove() on the data 8818348SEric.Yu@Sun.COM * that has already queued in this socket. 8828348SEric.Yu@Sun.COM */ 8838348SEric.Yu@Sun.COM void 8848348SEric.Yu@Sun.COM sod_uioa_so_init(struct sonode *so, struct sodirect_s *sodp, struct uio *uiop) 8858348SEric.Yu@Sun.COM { 8868348SEric.Yu@Sun.COM uioa_t *uioap = (uioa_t *)uiop; 8878348SEric.Yu@Sun.COM mblk_t *lbp; 8888348SEric.Yu@Sun.COM mblk_t *wbp; 8898348SEric.Yu@Sun.COM mblk_t *bp; 8908348SEric.Yu@Sun.COM int len; 8918348SEric.Yu@Sun.COM int error; 8928348SEric.Yu@Sun.COM boolean_t in_rcv_q = B_TRUE; 8938348SEric.Yu@Sun.COM 8948348SEric.Yu@Sun.COM ASSERT(MUTEX_HELD(sodp->sod_lockp)); 8958348SEric.Yu@Sun.COM ASSERT(&sodp->sod_uioa == uioap); 8968348SEric.Yu@Sun.COM 8978348SEric.Yu@Sun.COM /* 8988348SEric.Yu@Sun.COM * Walk first b_cont chain in sod_q 8998348SEric.Yu@Sun.COM * and schedule any M_DATA mblk_t's for uio asynchronous move. 9008348SEric.Yu@Sun.COM */ 9018348SEric.Yu@Sun.COM bp = so->so_rcv_q_head; 9028348SEric.Yu@Sun.COM 9038348SEric.Yu@Sun.COM again: 9048348SEric.Yu@Sun.COM /* Walk the chain */ 9058348SEric.Yu@Sun.COM lbp = NULL; 9068348SEric.Yu@Sun.COM wbp = bp; 9078348SEric.Yu@Sun.COM 9088348SEric.Yu@Sun.COM do { 9098348SEric.Yu@Sun.COM if (bp == NULL) 9108348SEric.Yu@Sun.COM break; 9118348SEric.Yu@Sun.COM 9128348SEric.Yu@Sun.COM if (wbp->b_datap->db_type != M_DATA) { 9138348SEric.Yu@Sun.COM /* Not M_DATA, no more uioa */ 9148348SEric.Yu@Sun.COM goto nouioa; 9158348SEric.Yu@Sun.COM } 9168348SEric.Yu@Sun.COM if ((len = wbp->b_wptr - wbp->b_rptr) > 0) { 9178348SEric.Yu@Sun.COM /* Have a M_DATA mblk_t with data */ 9188348SEric.Yu@Sun.COM if (len > uioap->uio_resid || (so->so_oobmark > 0 && 9198348SEric.Yu@Sun.COM len + uioap->uioa_mbytes >= so->so_oobmark)) { 9208348SEric.Yu@Sun.COM /* Not enough uio sapce, or beyond oobmark */ 9218348SEric.Yu@Sun.COM goto nouioa; 9228348SEric.Yu@Sun.COM } 9238348SEric.Yu@Sun.COM ASSERT(!(wbp->b_datap->db_flags & DBLK_UIOA)); 9248348SEric.Yu@Sun.COM error = uioamove(wbp->b_rptr, len, 9258348SEric.Yu@Sun.COM UIO_READ, uioap); 9268348SEric.Yu@Sun.COM if (!error) { 9278348SEric.Yu@Sun.COM /* Scheduled, mark dblk_t as such */ 9288348SEric.Yu@Sun.COM wbp->b_datap->db_flags |= DBLK_UIOA; 9298348SEric.Yu@Sun.COM } else { 9308348SEric.Yu@Sun.COM /* Break the mblk chain */ 9318348SEric.Yu@Sun.COM goto nouioa; 9328348SEric.Yu@Sun.COM } 9338348SEric.Yu@Sun.COM } 9348348SEric.Yu@Sun.COM /* Save last wbp processed */ 9358348SEric.Yu@Sun.COM lbp = wbp; 9368348SEric.Yu@Sun.COM } while ((wbp = wbp->b_cont) != NULL); 9378348SEric.Yu@Sun.COM 9388348SEric.Yu@Sun.COM if (in_rcv_q && (bp == NULL || bp->b_next == NULL)) { 9398348SEric.Yu@Sun.COM /* 9408348SEric.Yu@Sun.COM * We get here only once to process the sonode dump area 9418348SEric.Yu@Sun.COM * if so_rcv_q_head is NULL or all the mblks have been 9428348SEric.Yu@Sun.COM * successfully uioamoved()ed. 9438348SEric.Yu@Sun.COM */ 9448348SEric.Yu@Sun.COM in_rcv_q = B_FALSE; 9458348SEric.Yu@Sun.COM 9468348SEric.Yu@Sun.COM /* move to dump area */ 9478348SEric.Yu@Sun.COM bp = so->so_rcv_head; 9488348SEric.Yu@Sun.COM goto again; 9498348SEric.Yu@Sun.COM } 9508348SEric.Yu@Sun.COM 9518348SEric.Yu@Sun.COM return; 9528348SEric.Yu@Sun.COM 9538348SEric.Yu@Sun.COM nouioa: 9548348SEric.Yu@Sun.COM /* No more uioa */ 9558348SEric.Yu@Sun.COM uioap->uioa_state &= UIOA_CLR; 9568348SEric.Yu@Sun.COM uioap->uioa_state |= UIOA_FINI; 9578348SEric.Yu@Sun.COM 9588348SEric.Yu@Sun.COM /* 9598348SEric.Yu@Sun.COM * If we processed 1 or more mblk_t(s) then we need to split the 9608348SEric.Yu@Sun.COM * current mblk_t chain in 2 so that all the uioamove()ed mblk_t(s) 9618348SEric.Yu@Sun.COM * are in the current chain and the rest are in the following new 9628348SEric.Yu@Sun.COM * chain. 9638348SEric.Yu@Sun.COM */ 9648348SEric.Yu@Sun.COM if (lbp != NULL) { 9658348SEric.Yu@Sun.COM /* New end of current chain */ 9668348SEric.Yu@Sun.COM lbp->b_cont = NULL; 9678348SEric.Yu@Sun.COM 9688348SEric.Yu@Sun.COM /* Insert new chain wbp after bp */ 9698348SEric.Yu@Sun.COM if ((wbp->b_next = bp->b_next) == NULL) { 9708348SEric.Yu@Sun.COM /* 9718348SEric.Yu@Sun.COM * No need to grab so_lock, since sod_lockp 9728348SEric.Yu@Sun.COM * points to so_lock. 9738348SEric.Yu@Sun.COM */ 9748348SEric.Yu@Sun.COM if (in_rcv_q) 9758348SEric.Yu@Sun.COM so->so_rcv_q_last_head = wbp; 9768348SEric.Yu@Sun.COM else 9778348SEric.Yu@Sun.COM so->so_rcv_last_head = wbp; 9788348SEric.Yu@Sun.COM } 9798348SEric.Yu@Sun.COM bp->b_next = wbp; 9808348SEric.Yu@Sun.COM bp->b_next->b_prev = bp->b_prev; 9818348SEric.Yu@Sun.COM bp->b_prev = lbp; 9828348SEric.Yu@Sun.COM } 9838348SEric.Yu@Sun.COM } 9848348SEric.Yu@Sun.COM 9858348SEric.Yu@Sun.COM /* 9868348SEric.Yu@Sun.COM * Initialize sodirect data structures on a socket. 9878348SEric.Yu@Sun.COM */ 9888348SEric.Yu@Sun.COM void 9898348SEric.Yu@Sun.COM sod_sock_init(struct sonode *so, struct stdata *stp, sod_enq_func enq_func, 9908348SEric.Yu@Sun.COM sod_wakeup_func wake_func, kmutex_t *lockp) 9918348SEric.Yu@Sun.COM { 9928348SEric.Yu@Sun.COM sodirect_t *sodp; 9938348SEric.Yu@Sun.COM 9948348SEric.Yu@Sun.COM ASSERT(so->so_direct == NULL); 9958348SEric.Yu@Sun.COM 9968348SEric.Yu@Sun.COM so->so_state |= SS_SODIRECT; 9978348SEric.Yu@Sun.COM 9988348SEric.Yu@Sun.COM sodp = kmem_cache_alloc(sock_sod_cache, KM_SLEEP); 9998348SEric.Yu@Sun.COM sodp->sod_state = SOD_ENABLED | SOD_WAKE_NOT; 10008348SEric.Yu@Sun.COM sodp->sod_want = 0; 10018348SEric.Yu@Sun.COM sodp->sod_q = (stp != NULL) ? RD(stp->sd_wrq) : NULL; 10028348SEric.Yu@Sun.COM sodp->sod_enqueue = enq_func; 10038348SEric.Yu@Sun.COM sodp->sod_wakeup = wake_func; 10048348SEric.Yu@Sun.COM sodp->sod_uioafh = NULL; 10058348SEric.Yu@Sun.COM sodp->sod_uioaft = NULL; 10068348SEric.Yu@Sun.COM sodp->sod_lockp = lockp; 10078348SEric.Yu@Sun.COM /* 10088348SEric.Yu@Sun.COM * Remainder of the sod_uioa members are left uninitialized 10098348SEric.Yu@Sun.COM * but will be initialized later by uioainit() before uioa 10108348SEric.Yu@Sun.COM * is enabled. 10118348SEric.Yu@Sun.COM */ 10128348SEric.Yu@Sun.COM sodp->sod_uioa.uioa_state = UIOA_ALLOC; 10138348SEric.Yu@Sun.COM so->so_direct = sodp; 10148348SEric.Yu@Sun.COM if (stp != NULL) 10158348SEric.Yu@Sun.COM stp->sd_sodirect = sodp; 10168348SEric.Yu@Sun.COM } 10178348SEric.Yu@Sun.COM 10188348SEric.Yu@Sun.COM /* 10198348SEric.Yu@Sun.COM * Init the sodirect kmem cache while sockfs is loading. 10208348SEric.Yu@Sun.COM */ 10218348SEric.Yu@Sun.COM void 10228348SEric.Yu@Sun.COM sod_init() 10238348SEric.Yu@Sun.COM { 10248348SEric.Yu@Sun.COM /* Allocate sodirect_t kmem_cache */ 10258348SEric.Yu@Sun.COM sock_sod_cache = kmem_cache_create("sock_sod_cache", 10268348SEric.Yu@Sun.COM sizeof (sodirect_t), 0, NULL, NULL, NULL, NULL, NULL, 0); 10278348SEric.Yu@Sun.COM } 10288348SEric.Yu@Sun.COM 10298348SEric.Yu@Sun.COM ssize_t 10308348SEric.Yu@Sun.COM sod_uioa_mblk(struct sonode *so, mblk_t *mp) 10318348SEric.Yu@Sun.COM { 10328348SEric.Yu@Sun.COM sodirect_t *sodp = so->so_direct; 10338348SEric.Yu@Sun.COM 10348348SEric.Yu@Sun.COM ASSERT(sodp != NULL); 10358348SEric.Yu@Sun.COM ASSERT(MUTEX_HELD(sodp->sod_lockp)); 10368348SEric.Yu@Sun.COM 10378348SEric.Yu@Sun.COM ASSERT(sodp->sod_state & SOD_ENABLED); 10388348SEric.Yu@Sun.COM ASSERT(sodp->sod_uioa.uioa_state != (UIOA_ALLOC|UIOA_INIT)); 10398348SEric.Yu@Sun.COM 10408348SEric.Yu@Sun.COM ASSERT(sodp->sod_uioa.uioa_state & (UIOA_ENABLED|UIOA_FINI)); 10418348SEric.Yu@Sun.COM 10428348SEric.Yu@Sun.COM if (mp == NULL && so->so_rcv_q_head != NULL) { 10438348SEric.Yu@Sun.COM mp = so->so_rcv_q_head; 10448348SEric.Yu@Sun.COM ASSERT(mp->b_prev != NULL); 10458348SEric.Yu@Sun.COM mp->b_prev = NULL; 10468348SEric.Yu@Sun.COM so->so_rcv_q_head = mp->b_next; 10478348SEric.Yu@Sun.COM if (so->so_rcv_q_head == NULL) { 10488348SEric.Yu@Sun.COM so->so_rcv_q_last_head = NULL; 10498348SEric.Yu@Sun.COM } 10508348SEric.Yu@Sun.COM mp->b_next = NULL; 10518348SEric.Yu@Sun.COM } 10528348SEric.Yu@Sun.COM 10538348SEric.Yu@Sun.COM sod_uioa_mblk_done(sodp, mp); 10548348SEric.Yu@Sun.COM 10558348SEric.Yu@Sun.COM if (so->so_rcv_q_head == NULL && so->so_rcv_head != NULL && 10568348SEric.Yu@Sun.COM DB_TYPE(so->so_rcv_head) == M_DATA && 10578348SEric.Yu@Sun.COM (DB_FLAGS(so->so_rcv_head) & DBLK_UIOA)) { 10588348SEric.Yu@Sun.COM /* more arrived */ 10598348SEric.Yu@Sun.COM ASSERT(so->so_rcv_q_head == NULL); 10608348SEric.Yu@Sun.COM mp = so->so_rcv_head; 10618348SEric.Yu@Sun.COM so->so_rcv_head = mp->b_next; 10628348SEric.Yu@Sun.COM if (so->so_rcv_head == NULL) 10638348SEric.Yu@Sun.COM so->so_rcv_last_head = NULL; 10648348SEric.Yu@Sun.COM mp->b_prev = mp->b_next = NULL; 10658348SEric.Yu@Sun.COM sod_uioa_mblk_done(sodp, mp); 10668348SEric.Yu@Sun.COM } 10678348SEric.Yu@Sun.COM 10688348SEric.Yu@Sun.COM #ifdef DEBUG 10698348SEric.Yu@Sun.COM if (so->so_rcv_q_head != NULL) { 10708348SEric.Yu@Sun.COM mblk_t *m = so->so_rcv_q_head; 10718348SEric.Yu@Sun.COM while (m != NULL) { 10728348SEric.Yu@Sun.COM if (DB_FLAGS(m) & DBLK_UIOA) { 10738348SEric.Yu@Sun.COM cmn_err(CE_PANIC, "Unexpected I/OAT mblk %p" 10748348SEric.Yu@Sun.COM " in so_rcv_q_head.\n", (void *)m); 10758348SEric.Yu@Sun.COM } 10768348SEric.Yu@Sun.COM m = m->b_next; 10778348SEric.Yu@Sun.COM } 10788348SEric.Yu@Sun.COM } 10798348SEric.Yu@Sun.COM if (so->so_rcv_head != NULL) { 10808348SEric.Yu@Sun.COM mblk_t *m = so->so_rcv_head; 10818348SEric.Yu@Sun.COM while (m != NULL) { 10828348SEric.Yu@Sun.COM if (DB_FLAGS(m) & DBLK_UIOA) { 10838348SEric.Yu@Sun.COM cmn_err(CE_PANIC, "Unexpected I/OAT mblk %p" 10848348SEric.Yu@Sun.COM " in so_rcv_head.\n", (void *)m); 10858348SEric.Yu@Sun.COM } 10868348SEric.Yu@Sun.COM m = m->b_next; 10878348SEric.Yu@Sun.COM } 10888348SEric.Yu@Sun.COM } 10898348SEric.Yu@Sun.COM #endif 10908348SEric.Yu@Sun.COM return (sodp->sod_uioa.uioa_mbytes); 10918348SEric.Yu@Sun.COM } 1092