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> 50*8399SRao.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; 5488348SEric.Yu@Sun.COM 5498348SEric.Yu@Sun.COM ASSERT(so->so_oobmsg == NULL); 5508348SEric.Yu@Sun.COM so->so_oobmark = 0; 5518348SEric.Yu@Sun.COM so->so_pgrp = 0; 5528348SEric.Yu@Sun.COM 5538348SEric.Yu@Sun.COM ASSERT(so->so_peercred == NULL); 5548348SEric.Yu@Sun.COM 5558348SEric.Yu@Sun.COM so->so_zoneid = getzoneid(); 5568348SEric.Yu@Sun.COM 5578348SEric.Yu@Sun.COM so->so_sockparams = sp; 5588348SEric.Yu@Sun.COM 5598348SEric.Yu@Sun.COM so->so_ops = sops; 5608348SEric.Yu@Sun.COM 561*8399SRao.Shoaib@Sun.COM so->so_not_str = (sops != &sotpi_sonodeops); 562*8399SRao.Shoaib@Sun.COM 5638348SEric.Yu@Sun.COM so->so_proto_handle = NULL; 5648348SEric.Yu@Sun.COM 5658348SEric.Yu@Sun.COM so->so_downcalls = NULL; 5668348SEric.Yu@Sun.COM 5678348SEric.Yu@Sun.COM so->so_copyflag = 0; 5688348SEric.Yu@Sun.COM 5698348SEric.Yu@Sun.COM ASSERT(so->so_acceptq_head == NULL); 5708348SEric.Yu@Sun.COM ASSERT(so->so_acceptq_tail == &so->so_acceptq_head); 5718348SEric.Yu@Sun.COM ASSERT(so->so_acceptq_next == NULL); 5728348SEric.Yu@Sun.COM 5738348SEric.Yu@Sun.COM vn_reinit(vp); 5748348SEric.Yu@Sun.COM vp->v_vfsp = rootvfs; 5758348SEric.Yu@Sun.COM vp->v_type = VSOCK; 5768348SEric.Yu@Sun.COM vp->v_rdev = sockdev; 5778348SEric.Yu@Sun.COM 5788348SEric.Yu@Sun.COM so->so_rcv_queued = 0; 5798348SEric.Yu@Sun.COM so->so_rcv_q_head = NULL; 5808348SEric.Yu@Sun.COM so->so_rcv_q_last_head = NULL; 5818348SEric.Yu@Sun.COM so->so_rcv_head = NULL; 5828348SEric.Yu@Sun.COM so->so_rcv_last_head = NULL; 5838348SEric.Yu@Sun.COM 5848348SEric.Yu@Sun.COM so->so_snd_qfull = B_FALSE; 5858348SEric.Yu@Sun.COM so->so_minpsz = 0; 5868348SEric.Yu@Sun.COM 5878348SEric.Yu@Sun.COM so->so_rcv_wakeup = B_FALSE; 5888348SEric.Yu@Sun.COM so->so_snd_wakeup = B_FALSE; 5898348SEric.Yu@Sun.COM so->so_flowctrld = B_FALSE; 5908348SEric.Yu@Sun.COM 5918348SEric.Yu@Sun.COM so->so_pollev = 0; 5928348SEric.Yu@Sun.COM bzero(&so->so_poll_list, sizeof (so->so_poll_list)); 5938348SEric.Yu@Sun.COM bzero(&so->so_proto_props, sizeof (struct sock_proto_props)); 5948348SEric.Yu@Sun.COM 5958348SEric.Yu@Sun.COM bzero(&(so->so_ksock_callbacks), sizeof (ksocket_callbacks_t)); 5968348SEric.Yu@Sun.COM so->so_ksock_cb_arg = NULL; 5978348SEric.Yu@Sun.COM 5988348SEric.Yu@Sun.COM so->so_max_addr_len = sizeof (struct sockaddr_storage); 5998348SEric.Yu@Sun.COM 6008348SEric.Yu@Sun.COM so->so_direct = NULL; 6018348SEric.Yu@Sun.COM 6028348SEric.Yu@Sun.COM vn_exists(vp); 6038348SEric.Yu@Sun.COM } 6048348SEric.Yu@Sun.COM 6058348SEric.Yu@Sun.COM void 6068348SEric.Yu@Sun.COM sonode_fini(struct sonode *so) 6078348SEric.Yu@Sun.COM { 6088348SEric.Yu@Sun.COM mblk_t *mp; 6098348SEric.Yu@Sun.COM vnode_t *vp; 6108348SEric.Yu@Sun.COM 6118348SEric.Yu@Sun.COM ASSERT(so->so_count == 0); 6128348SEric.Yu@Sun.COM 6138348SEric.Yu@Sun.COM if (so->so_rcv_timer_tid) { 6148348SEric.Yu@Sun.COM ASSERT(MUTEX_NOT_HELD(&so->so_lock)); 6158348SEric.Yu@Sun.COM (void) untimeout(so->so_rcv_timer_tid); 6168348SEric.Yu@Sun.COM so->so_rcv_timer_tid = 0; 6178348SEric.Yu@Sun.COM } 6188348SEric.Yu@Sun.COM 6198348SEric.Yu@Sun.COM so_acceptq_flush(so); 6208348SEric.Yu@Sun.COM 6218348SEric.Yu@Sun.COM if ((mp = so->so_oobmsg) != NULL) { 6228348SEric.Yu@Sun.COM freemsg(mp); 6238348SEric.Yu@Sun.COM so->so_oobmsg = NULL; 6248348SEric.Yu@Sun.COM so->so_state &= ~(SS_OOBPEND|SS_HAVEOOBDATA|SS_HADOOBDATA| 6258348SEric.Yu@Sun.COM SS_RCVATMARK); 6268348SEric.Yu@Sun.COM } 6278348SEric.Yu@Sun.COM 6288348SEric.Yu@Sun.COM if (so->so_poll_list.ph_list != NULL) { 6298348SEric.Yu@Sun.COM pollwakeup(&so->so_poll_list, POLLERR); 6308348SEric.Yu@Sun.COM pollhead_clean(&so->so_poll_list); 6318348SEric.Yu@Sun.COM } 6328348SEric.Yu@Sun.COM 6338348SEric.Yu@Sun.COM if (so->so_direct != NULL) { 6348348SEric.Yu@Sun.COM sodirect_t *sodp = so->so_direct; 6358348SEric.Yu@Sun.COM 6368348SEric.Yu@Sun.COM ASSERT(sodp->sod_uioafh == NULL); 6378348SEric.Yu@Sun.COM 6388348SEric.Yu@Sun.COM so->so_direct = NULL; 6398348SEric.Yu@Sun.COM kmem_cache_free(sock_sod_cache, sodp); 6408348SEric.Yu@Sun.COM } 6418348SEric.Yu@Sun.COM 6428348SEric.Yu@Sun.COM vp = SOTOV(so); 6438348SEric.Yu@Sun.COM vn_invalid(vp); 6448348SEric.Yu@Sun.COM 6458348SEric.Yu@Sun.COM if (so->so_peercred != NULL) { 6468348SEric.Yu@Sun.COM crfree(so->so_peercred); 6478348SEric.Yu@Sun.COM so->so_peercred = NULL; 6488348SEric.Yu@Sun.COM } 6498348SEric.Yu@Sun.COM } 6508348SEric.Yu@Sun.COM 6518348SEric.Yu@Sun.COM /* 6528348SEric.Yu@Sun.COM * This function is called at the beginning of recvmsg(). 6538348SEric.Yu@Sun.COM * 6548348SEric.Yu@Sun.COM * If I/OAT is enabled on this sonode, initialize the uioa state machine 6558348SEric.Yu@Sun.COM * with state UIOA_ALLOC. 6568348SEric.Yu@Sun.COM */ 6578348SEric.Yu@Sun.COM uio_t * 6588348SEric.Yu@Sun.COM sod_rcv_init(struct sonode *so, int flags, struct uio **uiopp) 6598348SEric.Yu@Sun.COM { 6608348SEric.Yu@Sun.COM struct uio *suiop; 6618348SEric.Yu@Sun.COM struct uio *uiop; 6628348SEric.Yu@Sun.COM sodirect_t *sodp = so->so_direct; 6638348SEric.Yu@Sun.COM 6648348SEric.Yu@Sun.COM if (sodp == NULL) 6658348SEric.Yu@Sun.COM return (NULL); 6668348SEric.Yu@Sun.COM 6678348SEric.Yu@Sun.COM suiop = NULL; 6688348SEric.Yu@Sun.COM uiop = *uiopp; 6698348SEric.Yu@Sun.COM 6708348SEric.Yu@Sun.COM mutex_enter(sodp->sod_lockp); 6718348SEric.Yu@Sun.COM if (uiop->uio_resid >= uioasync.mincnt && 6728348SEric.Yu@Sun.COM sodp != NULL && (sodp->sod_state & SOD_ENABLED) && 6738348SEric.Yu@Sun.COM uioasync.enabled && !(flags & MSG_PEEK) && 6748348SEric.Yu@Sun.COM !(so->so_state & SS_CANTRCVMORE)) { 6758348SEric.Yu@Sun.COM /* 6768348SEric.Yu@Sun.COM * Big enough I/O for uioa min setup and an sodirect socket 6778348SEric.Yu@Sun.COM * and sodirect enabled and uioa enabled and I/O will be done 6788348SEric.Yu@Sun.COM * and not EOF so initialize the sodirect_t uioa_t with "uiop". 6798348SEric.Yu@Sun.COM */ 6808348SEric.Yu@Sun.COM if (!uioainit(uiop, &sodp->sod_uioa)) { 6818348SEric.Yu@Sun.COM /* 6828348SEric.Yu@Sun.COM * Successful uioainit() so the uio_t part of the 6838348SEric.Yu@Sun.COM * uioa_t will be used for all uio_t work to follow, 6848348SEric.Yu@Sun.COM * we return the original "uiop" in "suiop". 6858348SEric.Yu@Sun.COM */ 6868348SEric.Yu@Sun.COM suiop = uiop; 6878348SEric.Yu@Sun.COM *uiopp = (uio_t *)&sodp->sod_uioa; 6888348SEric.Yu@Sun.COM /* 6898348SEric.Yu@Sun.COM * Before returning to the caller the passed in uio_t 6908348SEric.Yu@Sun.COM * "uiop" will be updated via a call to uioafini() 6918348SEric.Yu@Sun.COM * below. 6928348SEric.Yu@Sun.COM * 6938348SEric.Yu@Sun.COM * Note, the uioa.uioa_state isn't set to UIOA_ENABLED 6948348SEric.Yu@Sun.COM * here as first we have to uioamove() any currently 6958348SEric.Yu@Sun.COM * queued M_DATA mblk_t(s) so it will be done later. 6968348SEric.Yu@Sun.COM */ 6978348SEric.Yu@Sun.COM } 6988348SEric.Yu@Sun.COM /* 6998348SEric.Yu@Sun.COM * In either uioainit() success or not case note the number 7008348SEric.Yu@Sun.COM * of uio bytes the caller wants for sod framework and/or 7018348SEric.Yu@Sun.COM * transport (e.g. TCP) strategy. 7028348SEric.Yu@Sun.COM */ 7038348SEric.Yu@Sun.COM sodp->sod_want = uiop->uio_resid; 7048348SEric.Yu@Sun.COM } else if (sodp != NULL && (sodp->sod_state & SOD_ENABLED)) { 7058348SEric.Yu@Sun.COM /* 7068348SEric.Yu@Sun.COM * No uioa but still using sodirect so note the number of 7078348SEric.Yu@Sun.COM * uio bytes the caller wants for sodirect framework and/or 7088348SEric.Yu@Sun.COM * transport (e.g. TCP) strategy. 7098348SEric.Yu@Sun.COM */ 7108348SEric.Yu@Sun.COM sodp->sod_want = uiop->uio_resid; 7118348SEric.Yu@Sun.COM } 7128348SEric.Yu@Sun.COM mutex_exit(sodp->sod_lockp); 7138348SEric.Yu@Sun.COM 7148348SEric.Yu@Sun.COM return (suiop); 7158348SEric.Yu@Sun.COM } 7168348SEric.Yu@Sun.COM 7178348SEric.Yu@Sun.COM /* 7188348SEric.Yu@Sun.COM * This function is called at the end of recvmsg(), it finializes all the I/OAT 7198348SEric.Yu@Sun.COM * operations, and reset the uioa state to UIOA_ALLOC. 7208348SEric.Yu@Sun.COM */ 7218348SEric.Yu@Sun.COM int 7228348SEric.Yu@Sun.COM sod_rcv_done(struct sonode *so, struct uio *suiop, struct uio *uiop) 7238348SEric.Yu@Sun.COM { 7248348SEric.Yu@Sun.COM int error = 0; 7258348SEric.Yu@Sun.COM sodirect_t *sodp = so->so_direct; 7268348SEric.Yu@Sun.COM mblk_t *mp; 7278348SEric.Yu@Sun.COM 7288348SEric.Yu@Sun.COM if (sodp == NULL) { 7298348SEric.Yu@Sun.COM return (0); 7308348SEric.Yu@Sun.COM } 7318348SEric.Yu@Sun.COM 7328348SEric.Yu@Sun.COM ASSERT(MUTEX_HELD(sodp->sod_lockp)); 7338348SEric.Yu@Sun.COM /* Finish any sodirect and uioa processing */ 7348348SEric.Yu@Sun.COM if (suiop != NULL) { 7358348SEric.Yu@Sun.COM /* Finish any uioa_t processing */ 7368348SEric.Yu@Sun.COM 7378348SEric.Yu@Sun.COM ASSERT(uiop == (uio_t *)&sodp->sod_uioa); 7388348SEric.Yu@Sun.COM error = uioafini(suiop, (uioa_t *)uiop); 7398348SEric.Yu@Sun.COM if ((mp = sodp->sod_uioafh) != NULL) { 7408348SEric.Yu@Sun.COM sodp->sod_uioafh = NULL; 7418348SEric.Yu@Sun.COM sodp->sod_uioaft = NULL; 7428348SEric.Yu@Sun.COM freemsg(mp); 7438348SEric.Yu@Sun.COM } 7448348SEric.Yu@Sun.COM } 7458348SEric.Yu@Sun.COM ASSERT(sodp->sod_uioafh == NULL); 7468348SEric.Yu@Sun.COM if (!(sodp->sod_state & SOD_WAKE_NOT)) { 7478348SEric.Yu@Sun.COM /* Awoke */ 7488348SEric.Yu@Sun.COM sodp->sod_state &= SOD_WAKE_CLR; 7498348SEric.Yu@Sun.COM sodp->sod_state |= SOD_WAKE_NOT; 7508348SEric.Yu@Sun.COM } 7518348SEric.Yu@Sun.COM /* Last, clear sod_want value */ 7528348SEric.Yu@Sun.COM sodp->sod_want = 0; 7538348SEric.Yu@Sun.COM 7548348SEric.Yu@Sun.COM return (error); 7558348SEric.Yu@Sun.COM } 7568348SEric.Yu@Sun.COM 7578348SEric.Yu@Sun.COM /* 7588348SEric.Yu@Sun.COM * Schedule a uioamove() on a mblk. This is ususally called from 7598348SEric.Yu@Sun.COM * protocols (e.g. TCP) on a I/OAT enabled sonode. 7608348SEric.Yu@Sun.COM */ 7618348SEric.Yu@Sun.COM mblk_t * 7628348SEric.Yu@Sun.COM sod_uioa_mblk_init(struct sodirect_s *sodp, mblk_t *mp, size_t msg_size) 7638348SEric.Yu@Sun.COM { 7648348SEric.Yu@Sun.COM uioa_t *uioap = &sodp->sod_uioa; 7658348SEric.Yu@Sun.COM mblk_t *mp1 = mp; 7668348SEric.Yu@Sun.COM mblk_t *lmp = NULL; 7678348SEric.Yu@Sun.COM 7688348SEric.Yu@Sun.COM ASSERT(DB_TYPE(mp) == M_DATA); 7698348SEric.Yu@Sun.COM ASSERT(msg_size == msgdsize(mp)); 7708348SEric.Yu@Sun.COM 7718348SEric.Yu@Sun.COM /* Caller must have lock held */ 7728348SEric.Yu@Sun.COM ASSERT(MUTEX_HELD(sodp->sod_lockp)); 7738348SEric.Yu@Sun.COM 7748348SEric.Yu@Sun.COM if (uioap->uioa_state & UIOA_ENABLED) { 7758348SEric.Yu@Sun.COM /* Uioa is enabled */ 7768348SEric.Yu@Sun.COM 7778348SEric.Yu@Sun.COM if (msg_size > uioap->uio_resid) { 7788348SEric.Yu@Sun.COM /* 7798348SEric.Yu@Sun.COM * There isn't enough uio space for the mblk_t chain 7808348SEric.Yu@Sun.COM * so disable uioa such that this and any additional 7818348SEric.Yu@Sun.COM * mblk_t data is handled by the socket and schedule 7828348SEric.Yu@Sun.COM * the socket for wakeup to finish this uioa. 7838348SEric.Yu@Sun.COM */ 7848348SEric.Yu@Sun.COM uioap->uioa_state &= UIOA_CLR; 7858348SEric.Yu@Sun.COM uioap->uioa_state |= UIOA_FINI; 7868348SEric.Yu@Sun.COM if (sodp->sod_state & SOD_WAKE_NOT) { 7878348SEric.Yu@Sun.COM sodp->sod_state &= SOD_WAKE_CLR; 7888348SEric.Yu@Sun.COM sodp->sod_state |= SOD_WAKE_NEED; 7898348SEric.Yu@Sun.COM } 7908348SEric.Yu@Sun.COM return (mp); 7918348SEric.Yu@Sun.COM } 7928348SEric.Yu@Sun.COM do { 7938348SEric.Yu@Sun.COM uint32_t len = MBLKL(mp1); 7948348SEric.Yu@Sun.COM 7958348SEric.Yu@Sun.COM if (!uioamove(mp1->b_rptr, len, UIO_READ, uioap)) { 7968348SEric.Yu@Sun.COM /* Scheduled, mark dblk_t as such */ 7978348SEric.Yu@Sun.COM DB_FLAGS(mp1) |= DBLK_UIOA; 7988348SEric.Yu@Sun.COM } else { 7998348SEric.Yu@Sun.COM /* Error, turn off async processing */ 8008348SEric.Yu@Sun.COM uioap->uioa_state &= UIOA_CLR; 8018348SEric.Yu@Sun.COM uioap->uioa_state |= UIOA_FINI; 8028348SEric.Yu@Sun.COM break; 8038348SEric.Yu@Sun.COM } 8048348SEric.Yu@Sun.COM lmp = mp1; 8058348SEric.Yu@Sun.COM } while ((mp1 = mp1->b_cont) != NULL); 8068348SEric.Yu@Sun.COM 8078348SEric.Yu@Sun.COM if (mp1 != NULL || uioap->uio_resid == 0) { 8088348SEric.Yu@Sun.COM /* 8098348SEric.Yu@Sun.COM * Not all mblk_t(s) uioamoved (error) or all uio 8108348SEric.Yu@Sun.COM * space has been consumed so schedule the socket 8118348SEric.Yu@Sun.COM * for wakeup to finish this uio. 8128348SEric.Yu@Sun.COM */ 8138348SEric.Yu@Sun.COM sodp->sod_state &= SOD_WAKE_CLR; 8148348SEric.Yu@Sun.COM sodp->sod_state |= SOD_WAKE_NEED; 8158348SEric.Yu@Sun.COM 8168348SEric.Yu@Sun.COM /* Break the mblk chain if neccessary. */ 8178348SEric.Yu@Sun.COM if (mp1 != NULL && lmp != NULL) { 8188348SEric.Yu@Sun.COM mp->b_next = mp1; 8198348SEric.Yu@Sun.COM lmp->b_cont = NULL; 8208348SEric.Yu@Sun.COM } 8218348SEric.Yu@Sun.COM } 8228348SEric.Yu@Sun.COM } 8238348SEric.Yu@Sun.COM return (mp1); 8248348SEric.Yu@Sun.COM } 8258348SEric.Yu@Sun.COM 8268348SEric.Yu@Sun.COM /* 8278348SEric.Yu@Sun.COM * This function is called on a mblk that thas been successfully uioamoved(). 8288348SEric.Yu@Sun.COM */ 8298348SEric.Yu@Sun.COM void 8308348SEric.Yu@Sun.COM sod_uioa_mblk_done(sodirect_t *sodp, mblk_t *bp) 8318348SEric.Yu@Sun.COM { 8328348SEric.Yu@Sun.COM if (bp != NULL && (bp->b_datap->db_flags & DBLK_UIOA)) { 8338348SEric.Yu@Sun.COM /* 8348348SEric.Yu@Sun.COM * A uioa flaged mblk_t chain, already uio processed, 8358348SEric.Yu@Sun.COM * add it to the sodirect uioa pending free list. 8368348SEric.Yu@Sun.COM * 8378348SEric.Yu@Sun.COM * Note, a b_cont chain headed by a DBLK_UIOA enable 8388348SEric.Yu@Sun.COM * mblk_t must have all mblk_t(s) DBLK_UIOA enabled. 8398348SEric.Yu@Sun.COM */ 8408348SEric.Yu@Sun.COM mblk_t *bpt = sodp->sod_uioaft; 8418348SEric.Yu@Sun.COM 8428348SEric.Yu@Sun.COM ASSERT(sodp != NULL); 8438348SEric.Yu@Sun.COM 8448348SEric.Yu@Sun.COM /* 8458348SEric.Yu@Sun.COM * Add first mblk_t of "bp" chain to current sodirect uioa 8468348SEric.Yu@Sun.COM * free list tail mblk_t, if any, else empty list so new head. 8478348SEric.Yu@Sun.COM */ 8488348SEric.Yu@Sun.COM if (bpt == NULL) 8498348SEric.Yu@Sun.COM sodp->sod_uioafh = bp; 8508348SEric.Yu@Sun.COM else 8518348SEric.Yu@Sun.COM bpt->b_cont = bp; 8528348SEric.Yu@Sun.COM 8538348SEric.Yu@Sun.COM /* 8548348SEric.Yu@Sun.COM * Walk mblk_t "bp" chain to find tail and adjust rptr of 8558348SEric.Yu@Sun.COM * each to reflect that uioamove() has consumed all data. 8568348SEric.Yu@Sun.COM */ 8578348SEric.Yu@Sun.COM bpt = bp; 8588348SEric.Yu@Sun.COM for (;;) { 8598348SEric.Yu@Sun.COM ASSERT(bpt->b_datap->db_flags & DBLK_UIOA); 8608348SEric.Yu@Sun.COM 8618348SEric.Yu@Sun.COM bpt->b_rptr = bpt->b_wptr; 8628348SEric.Yu@Sun.COM if (bpt->b_cont == NULL) 8638348SEric.Yu@Sun.COM break; 8648348SEric.Yu@Sun.COM bpt = bpt->b_cont; 8658348SEric.Yu@Sun.COM } 8668348SEric.Yu@Sun.COM /* New sodirect uioa free list tail */ 8678348SEric.Yu@Sun.COM sodp->sod_uioaft = bpt; 8688348SEric.Yu@Sun.COM 8698348SEric.Yu@Sun.COM /* Only dequeue once with data returned per uioa_t */ 8708348SEric.Yu@Sun.COM if (sodp->sod_uioa.uioa_state & UIOA_ENABLED) { 8718348SEric.Yu@Sun.COM sodp->sod_uioa.uioa_state &= UIOA_CLR; 8728348SEric.Yu@Sun.COM sodp->sod_uioa.uioa_state |= UIOA_FINI; 8738348SEric.Yu@Sun.COM } 8748348SEric.Yu@Sun.COM } 8758348SEric.Yu@Sun.COM } 8768348SEric.Yu@Sun.COM 8778348SEric.Yu@Sun.COM /* 8788348SEric.Yu@Sun.COM * When transit from UIOA_INIT state to UIOA_ENABLE state in recvmsg(), call 8798348SEric.Yu@Sun.COM * this function on a non-STREAMS socket to schedule uioamove() on the data 8808348SEric.Yu@Sun.COM * that has already queued in this socket. 8818348SEric.Yu@Sun.COM */ 8828348SEric.Yu@Sun.COM void 8838348SEric.Yu@Sun.COM sod_uioa_so_init(struct sonode *so, struct sodirect_s *sodp, struct uio *uiop) 8848348SEric.Yu@Sun.COM { 8858348SEric.Yu@Sun.COM uioa_t *uioap = (uioa_t *)uiop; 8868348SEric.Yu@Sun.COM mblk_t *lbp; 8878348SEric.Yu@Sun.COM mblk_t *wbp; 8888348SEric.Yu@Sun.COM mblk_t *bp; 8898348SEric.Yu@Sun.COM int len; 8908348SEric.Yu@Sun.COM int error; 8918348SEric.Yu@Sun.COM boolean_t in_rcv_q = B_TRUE; 8928348SEric.Yu@Sun.COM 8938348SEric.Yu@Sun.COM ASSERT(MUTEX_HELD(sodp->sod_lockp)); 8948348SEric.Yu@Sun.COM ASSERT(&sodp->sod_uioa == uioap); 8958348SEric.Yu@Sun.COM 8968348SEric.Yu@Sun.COM /* 8978348SEric.Yu@Sun.COM * Walk first b_cont chain in sod_q 8988348SEric.Yu@Sun.COM * and schedule any M_DATA mblk_t's for uio asynchronous move. 8998348SEric.Yu@Sun.COM */ 9008348SEric.Yu@Sun.COM bp = so->so_rcv_q_head; 9018348SEric.Yu@Sun.COM 9028348SEric.Yu@Sun.COM again: 9038348SEric.Yu@Sun.COM /* Walk the chain */ 9048348SEric.Yu@Sun.COM lbp = NULL; 9058348SEric.Yu@Sun.COM wbp = bp; 9068348SEric.Yu@Sun.COM 9078348SEric.Yu@Sun.COM do { 9088348SEric.Yu@Sun.COM if (bp == NULL) 9098348SEric.Yu@Sun.COM break; 9108348SEric.Yu@Sun.COM 9118348SEric.Yu@Sun.COM if (wbp->b_datap->db_type != M_DATA) { 9128348SEric.Yu@Sun.COM /* Not M_DATA, no more uioa */ 9138348SEric.Yu@Sun.COM goto nouioa; 9148348SEric.Yu@Sun.COM } 9158348SEric.Yu@Sun.COM if ((len = wbp->b_wptr - wbp->b_rptr) > 0) { 9168348SEric.Yu@Sun.COM /* Have a M_DATA mblk_t with data */ 9178348SEric.Yu@Sun.COM if (len > uioap->uio_resid || (so->so_oobmark > 0 && 9188348SEric.Yu@Sun.COM len + uioap->uioa_mbytes >= so->so_oobmark)) { 9198348SEric.Yu@Sun.COM /* Not enough uio sapce, or beyond oobmark */ 9208348SEric.Yu@Sun.COM goto nouioa; 9218348SEric.Yu@Sun.COM } 9228348SEric.Yu@Sun.COM ASSERT(!(wbp->b_datap->db_flags & DBLK_UIOA)); 9238348SEric.Yu@Sun.COM error = uioamove(wbp->b_rptr, len, 9248348SEric.Yu@Sun.COM UIO_READ, uioap); 9258348SEric.Yu@Sun.COM if (!error) { 9268348SEric.Yu@Sun.COM /* Scheduled, mark dblk_t as such */ 9278348SEric.Yu@Sun.COM wbp->b_datap->db_flags |= DBLK_UIOA; 9288348SEric.Yu@Sun.COM } else { 9298348SEric.Yu@Sun.COM /* Break the mblk chain */ 9308348SEric.Yu@Sun.COM goto nouioa; 9318348SEric.Yu@Sun.COM } 9328348SEric.Yu@Sun.COM } 9338348SEric.Yu@Sun.COM /* Save last wbp processed */ 9348348SEric.Yu@Sun.COM lbp = wbp; 9358348SEric.Yu@Sun.COM } while ((wbp = wbp->b_cont) != NULL); 9368348SEric.Yu@Sun.COM 9378348SEric.Yu@Sun.COM if (in_rcv_q && (bp == NULL || bp->b_next == NULL)) { 9388348SEric.Yu@Sun.COM /* 9398348SEric.Yu@Sun.COM * We get here only once to process the sonode dump area 9408348SEric.Yu@Sun.COM * if so_rcv_q_head is NULL or all the mblks have been 9418348SEric.Yu@Sun.COM * successfully uioamoved()ed. 9428348SEric.Yu@Sun.COM */ 9438348SEric.Yu@Sun.COM in_rcv_q = B_FALSE; 9448348SEric.Yu@Sun.COM 9458348SEric.Yu@Sun.COM /* move to dump area */ 9468348SEric.Yu@Sun.COM bp = so->so_rcv_head; 9478348SEric.Yu@Sun.COM goto again; 9488348SEric.Yu@Sun.COM } 9498348SEric.Yu@Sun.COM 9508348SEric.Yu@Sun.COM return; 9518348SEric.Yu@Sun.COM 9528348SEric.Yu@Sun.COM nouioa: 9538348SEric.Yu@Sun.COM /* No more uioa */ 9548348SEric.Yu@Sun.COM uioap->uioa_state &= UIOA_CLR; 9558348SEric.Yu@Sun.COM uioap->uioa_state |= UIOA_FINI; 9568348SEric.Yu@Sun.COM 9578348SEric.Yu@Sun.COM /* 9588348SEric.Yu@Sun.COM * If we processed 1 or more mblk_t(s) then we need to split the 9598348SEric.Yu@Sun.COM * current mblk_t chain in 2 so that all the uioamove()ed mblk_t(s) 9608348SEric.Yu@Sun.COM * are in the current chain and the rest are in the following new 9618348SEric.Yu@Sun.COM * chain. 9628348SEric.Yu@Sun.COM */ 9638348SEric.Yu@Sun.COM if (lbp != NULL) { 9648348SEric.Yu@Sun.COM /* New end of current chain */ 9658348SEric.Yu@Sun.COM lbp->b_cont = NULL; 9668348SEric.Yu@Sun.COM 9678348SEric.Yu@Sun.COM /* Insert new chain wbp after bp */ 9688348SEric.Yu@Sun.COM if ((wbp->b_next = bp->b_next) == NULL) { 9698348SEric.Yu@Sun.COM /* 9708348SEric.Yu@Sun.COM * No need to grab so_lock, since sod_lockp 9718348SEric.Yu@Sun.COM * points to so_lock. 9728348SEric.Yu@Sun.COM */ 9738348SEric.Yu@Sun.COM if (in_rcv_q) 9748348SEric.Yu@Sun.COM so->so_rcv_q_last_head = wbp; 9758348SEric.Yu@Sun.COM else 9768348SEric.Yu@Sun.COM so->so_rcv_last_head = wbp; 9778348SEric.Yu@Sun.COM } 9788348SEric.Yu@Sun.COM bp->b_next = wbp; 9798348SEric.Yu@Sun.COM bp->b_next->b_prev = bp->b_prev; 9808348SEric.Yu@Sun.COM bp->b_prev = lbp; 9818348SEric.Yu@Sun.COM } 9828348SEric.Yu@Sun.COM } 9838348SEric.Yu@Sun.COM 9848348SEric.Yu@Sun.COM /* 9858348SEric.Yu@Sun.COM * Initialize sodirect data structures on a socket. 9868348SEric.Yu@Sun.COM */ 9878348SEric.Yu@Sun.COM void 9888348SEric.Yu@Sun.COM sod_sock_init(struct sonode *so, struct stdata *stp, sod_enq_func enq_func, 9898348SEric.Yu@Sun.COM sod_wakeup_func wake_func, kmutex_t *lockp) 9908348SEric.Yu@Sun.COM { 9918348SEric.Yu@Sun.COM sodirect_t *sodp; 9928348SEric.Yu@Sun.COM 9938348SEric.Yu@Sun.COM ASSERT(so->so_direct == NULL); 9948348SEric.Yu@Sun.COM 9958348SEric.Yu@Sun.COM so->so_state |= SS_SODIRECT; 9968348SEric.Yu@Sun.COM 9978348SEric.Yu@Sun.COM sodp = kmem_cache_alloc(sock_sod_cache, KM_SLEEP); 9988348SEric.Yu@Sun.COM sodp->sod_state = SOD_ENABLED | SOD_WAKE_NOT; 9998348SEric.Yu@Sun.COM sodp->sod_want = 0; 10008348SEric.Yu@Sun.COM sodp->sod_q = (stp != NULL) ? RD(stp->sd_wrq) : NULL; 10018348SEric.Yu@Sun.COM sodp->sod_enqueue = enq_func; 10028348SEric.Yu@Sun.COM sodp->sod_wakeup = wake_func; 10038348SEric.Yu@Sun.COM sodp->sod_uioafh = NULL; 10048348SEric.Yu@Sun.COM sodp->sod_uioaft = NULL; 10058348SEric.Yu@Sun.COM sodp->sod_lockp = lockp; 10068348SEric.Yu@Sun.COM /* 10078348SEric.Yu@Sun.COM * Remainder of the sod_uioa members are left uninitialized 10088348SEric.Yu@Sun.COM * but will be initialized later by uioainit() before uioa 10098348SEric.Yu@Sun.COM * is enabled. 10108348SEric.Yu@Sun.COM */ 10118348SEric.Yu@Sun.COM sodp->sod_uioa.uioa_state = UIOA_ALLOC; 10128348SEric.Yu@Sun.COM so->so_direct = sodp; 10138348SEric.Yu@Sun.COM if (stp != NULL) 10148348SEric.Yu@Sun.COM stp->sd_sodirect = sodp; 10158348SEric.Yu@Sun.COM } 10168348SEric.Yu@Sun.COM 10178348SEric.Yu@Sun.COM /* 10188348SEric.Yu@Sun.COM * Init the sodirect kmem cache while sockfs is loading. 10198348SEric.Yu@Sun.COM */ 10208348SEric.Yu@Sun.COM void 10218348SEric.Yu@Sun.COM sod_init() 10228348SEric.Yu@Sun.COM { 10238348SEric.Yu@Sun.COM /* Allocate sodirect_t kmem_cache */ 10248348SEric.Yu@Sun.COM sock_sod_cache = kmem_cache_create("sock_sod_cache", 10258348SEric.Yu@Sun.COM sizeof (sodirect_t), 0, NULL, NULL, NULL, NULL, NULL, 0); 10268348SEric.Yu@Sun.COM } 10278348SEric.Yu@Sun.COM 10288348SEric.Yu@Sun.COM ssize_t 10298348SEric.Yu@Sun.COM sod_uioa_mblk(struct sonode *so, mblk_t *mp) 10308348SEric.Yu@Sun.COM { 10318348SEric.Yu@Sun.COM sodirect_t *sodp = so->so_direct; 10328348SEric.Yu@Sun.COM 10338348SEric.Yu@Sun.COM ASSERT(sodp != NULL); 10348348SEric.Yu@Sun.COM ASSERT(MUTEX_HELD(sodp->sod_lockp)); 10358348SEric.Yu@Sun.COM 10368348SEric.Yu@Sun.COM ASSERT(sodp->sod_state & SOD_ENABLED); 10378348SEric.Yu@Sun.COM ASSERT(sodp->sod_uioa.uioa_state != (UIOA_ALLOC|UIOA_INIT)); 10388348SEric.Yu@Sun.COM 10398348SEric.Yu@Sun.COM ASSERT(sodp->sod_uioa.uioa_state & (UIOA_ENABLED|UIOA_FINI)); 10408348SEric.Yu@Sun.COM 10418348SEric.Yu@Sun.COM if (mp == NULL && so->so_rcv_q_head != NULL) { 10428348SEric.Yu@Sun.COM mp = so->so_rcv_q_head; 10438348SEric.Yu@Sun.COM ASSERT(mp->b_prev != NULL); 10448348SEric.Yu@Sun.COM mp->b_prev = NULL; 10458348SEric.Yu@Sun.COM so->so_rcv_q_head = mp->b_next; 10468348SEric.Yu@Sun.COM if (so->so_rcv_q_head == NULL) { 10478348SEric.Yu@Sun.COM so->so_rcv_q_last_head = NULL; 10488348SEric.Yu@Sun.COM } 10498348SEric.Yu@Sun.COM mp->b_next = NULL; 10508348SEric.Yu@Sun.COM } 10518348SEric.Yu@Sun.COM 10528348SEric.Yu@Sun.COM sod_uioa_mblk_done(sodp, mp); 10538348SEric.Yu@Sun.COM 10548348SEric.Yu@Sun.COM if (so->so_rcv_q_head == NULL && so->so_rcv_head != NULL && 10558348SEric.Yu@Sun.COM DB_TYPE(so->so_rcv_head) == M_DATA && 10568348SEric.Yu@Sun.COM (DB_FLAGS(so->so_rcv_head) & DBLK_UIOA)) { 10578348SEric.Yu@Sun.COM /* more arrived */ 10588348SEric.Yu@Sun.COM ASSERT(so->so_rcv_q_head == NULL); 10598348SEric.Yu@Sun.COM mp = so->so_rcv_head; 10608348SEric.Yu@Sun.COM so->so_rcv_head = mp->b_next; 10618348SEric.Yu@Sun.COM if (so->so_rcv_head == NULL) 10628348SEric.Yu@Sun.COM so->so_rcv_last_head = NULL; 10638348SEric.Yu@Sun.COM mp->b_prev = mp->b_next = NULL; 10648348SEric.Yu@Sun.COM sod_uioa_mblk_done(sodp, mp); 10658348SEric.Yu@Sun.COM } 10668348SEric.Yu@Sun.COM 10678348SEric.Yu@Sun.COM #ifdef DEBUG 10688348SEric.Yu@Sun.COM if (so->so_rcv_q_head != NULL) { 10698348SEric.Yu@Sun.COM mblk_t *m = so->so_rcv_q_head; 10708348SEric.Yu@Sun.COM while (m != NULL) { 10718348SEric.Yu@Sun.COM if (DB_FLAGS(m) & DBLK_UIOA) { 10728348SEric.Yu@Sun.COM cmn_err(CE_PANIC, "Unexpected I/OAT mblk %p" 10738348SEric.Yu@Sun.COM " in so_rcv_q_head.\n", (void *)m); 10748348SEric.Yu@Sun.COM } 10758348SEric.Yu@Sun.COM m = m->b_next; 10768348SEric.Yu@Sun.COM } 10778348SEric.Yu@Sun.COM } 10788348SEric.Yu@Sun.COM if (so->so_rcv_head != NULL) { 10798348SEric.Yu@Sun.COM mblk_t *m = so->so_rcv_head; 10808348SEric.Yu@Sun.COM while (m != NULL) { 10818348SEric.Yu@Sun.COM if (DB_FLAGS(m) & DBLK_UIOA) { 10828348SEric.Yu@Sun.COM cmn_err(CE_PANIC, "Unexpected I/OAT mblk %p" 10838348SEric.Yu@Sun.COM " in so_rcv_head.\n", (void *)m); 10848348SEric.Yu@Sun.COM } 10858348SEric.Yu@Sun.COM m = m->b_next; 10868348SEric.Yu@Sun.COM } 10878348SEric.Yu@Sun.COM } 10888348SEric.Yu@Sun.COM #endif 10898348SEric.Yu@Sun.COM return (sodp->sod_uioa.uioa_mbytes); 10908348SEric.Yu@Sun.COM } 1091