10f1702c5SYu Xiangning /* 20f1702c5SYu Xiangning * CDDL HEADER START 30f1702c5SYu Xiangning * 40f1702c5SYu Xiangning * The contents of this file are subject to the terms of the 50f1702c5SYu Xiangning * Common Development and Distribution License (the "License"). 60f1702c5SYu Xiangning * You may not use this file except in compliance with the License. 70f1702c5SYu Xiangning * 80f1702c5SYu Xiangning * You can obtain a copy of the license at usr/src/OPENSOLARIS.LICENSE 90f1702c5SYu Xiangning * or http://www.opensolaris.org/os/licensing. 100f1702c5SYu Xiangning * See the License for the specific language governing permissions 110f1702c5SYu Xiangning * and limitations under the License. 120f1702c5SYu Xiangning * 130f1702c5SYu Xiangning * When distributing Covered Code, include this CDDL HEADER in each 140f1702c5SYu Xiangning * file and include the License file at usr/src/OPENSOLARIS.LICENSE. 150f1702c5SYu Xiangning * If applicable, add the following below this CDDL HEADER, with the 160f1702c5SYu Xiangning * fields enclosed by brackets "[]" replaced with your own identifying 170f1702c5SYu Xiangning * information: Portions Copyright [yyyy] [name of copyright owner] 180f1702c5SYu Xiangning * 190f1702c5SYu Xiangning * CDDL HEADER END 200f1702c5SYu Xiangning */ 210f1702c5SYu Xiangning 220f1702c5SYu Xiangning /* 23*3e95bd4aSAnders Persson * Copyright (c) 2007, 2010, Oracle and/or its affiliates. All rights reserved. 240f1702c5SYu Xiangning */ 250f1702c5SYu Xiangning 260f1702c5SYu Xiangning #include <sys/types.h> 270f1702c5SYu Xiangning #include <sys/t_lock.h> 280f1702c5SYu Xiangning #include <sys/param.h> 290f1702c5SYu Xiangning #include <sys/systm.h> 300f1702c5SYu Xiangning #include <sys/buf.h> 310f1702c5SYu Xiangning #include <sys/vfs.h> 320f1702c5SYu Xiangning #include <sys/vnode.h> 330f1702c5SYu Xiangning #include <sys/debug.h> 340f1702c5SYu Xiangning #include <sys/errno.h> 350f1702c5SYu Xiangning #include <sys/stropts.h> 360f1702c5SYu Xiangning #include <sys/cmn_err.h> 370f1702c5SYu Xiangning #include <sys/sysmacros.h> 38634e26ecSCasper H.S. Dik #include <sys/policy.h> 390f1702c5SYu Xiangning 400f1702c5SYu Xiangning #include <sys/filio.h> 410f1702c5SYu Xiangning #include <sys/sockio.h> 420f1702c5SYu Xiangning 430f1702c5SYu Xiangning #include <sys/project.h> 440f1702c5SYu Xiangning #include <sys/tihdr.h> 450f1702c5SYu Xiangning #include <sys/strsubr.h> 460f1702c5SYu Xiangning 470f1702c5SYu Xiangning #include <sys/socket.h> 480f1702c5SYu Xiangning #include <sys/socketvar.h> 490f1702c5SYu Xiangning #include <sys/strsun.h> 500f1702c5SYu Xiangning 510f1702c5SYu Xiangning #include <sys/tsol/label.h> 520f1702c5SYu Xiangning 530f1702c5SYu Xiangning #include <inet/sdp_itf.h> 540f1702c5SYu Xiangning #include "socksdp.h" 550f1702c5SYu Xiangning #include <fs/sockfs/sockcommon.h> 560f1702c5SYu Xiangning 570f1702c5SYu Xiangning /* 580f1702c5SYu Xiangning * SDP sockfs sonode operations 590f1702c5SYu Xiangning */ 600f1702c5SYu Xiangning static int sosdp_init(struct sonode *, struct sonode *, struct cred *, int); 610f1702c5SYu Xiangning static int sosdp_accept(struct sonode *, int, struct cred *, struct sonode **); 620f1702c5SYu Xiangning static int sosdp_bind(struct sonode *, struct sockaddr *, socklen_t, int, 630f1702c5SYu Xiangning struct cred *); 640f1702c5SYu Xiangning static int sosdp_listen(struct sonode *, int, struct cred *); 65*3e95bd4aSAnders Persson static int sosdp_connect(struct sonode *, struct sockaddr *, socklen_t, 660f1702c5SYu Xiangning int, int, struct cred *); 670f1702c5SYu Xiangning static int sosdp_recvmsg(struct sonode *, struct nmsghdr *, struct uio *, 680f1702c5SYu Xiangning struct cred *); 690f1702c5SYu Xiangning static int sosdp_sendmsg(struct sonode *, struct nmsghdr *, struct uio *, 700f1702c5SYu Xiangning struct cred *); 710f1702c5SYu Xiangning static int sosdp_getpeername(struct sonode *, struct sockaddr *, socklen_t *, 720f1702c5SYu Xiangning boolean_t, struct cred *); 730f1702c5SYu Xiangning static int sosdp_getsockname(struct sonode *, struct sockaddr *, socklen_t *, 740f1702c5SYu Xiangning struct cred *); 750f1702c5SYu Xiangning static int sosdp_shutdown(struct sonode *, int, struct cred *); 760f1702c5SYu Xiangning static int sosdp_getsockopt(struct sonode *, int, int, void *, socklen_t *, 770f1702c5SYu Xiangning int, struct cred *); 780f1702c5SYu Xiangning static int sosdp_setsockopt(struct sonode *, int, int, const void *, 790f1702c5SYu Xiangning socklen_t, struct cred *); 800f1702c5SYu Xiangning static int sosdp_ioctl(struct sonode *, int, intptr_t, int, struct cred *, 810f1702c5SYu Xiangning int32_t *); 820f1702c5SYu Xiangning static int sosdp_poll(struct sonode *, short, int, short *, 830f1702c5SYu Xiangning struct pollhead **); 840f1702c5SYu Xiangning static int sosdp_close(struct sonode *, int, struct cred *); 850f1702c5SYu Xiangning void sosdp_fini(struct sonode *, struct cred *); 860f1702c5SYu Xiangning 870f1702c5SYu Xiangning 880f1702c5SYu Xiangning /* 890f1702c5SYu Xiangning * Socket upcalls 900f1702c5SYu Xiangning */ 910f1702c5SYu Xiangning static void *sdp_sock_newconn(void *parenthandle, void *connind); 920f1702c5SYu Xiangning static void sdp_sock_connected(void *handle); 930f1702c5SYu Xiangning static void sdp_sock_disconnected(void *handle, int error); 940f1702c5SYu Xiangning static void sdp_sock_connfail(void *handle, int error); 950f1702c5SYu Xiangning static int sdp_sock_recv(void *handle, mblk_t *mp, int flags); 960f1702c5SYu Xiangning static void sdp_sock_xmitted(void *handle, int txqueued); 970f1702c5SYu Xiangning static void sdp_sock_urgdata(void *handle); 980f1702c5SYu Xiangning static void sdp_sock_ordrel(void *handle); 990f1702c5SYu Xiangning 1000f1702c5SYu Xiangning sonodeops_t sosdp_sonodeops = { 1010f1702c5SYu Xiangning sosdp_init, /* sop_init */ 1020f1702c5SYu Xiangning sosdp_accept, /* sop_accept */ 1030f1702c5SYu Xiangning sosdp_bind, /* sop_bind */ 1040f1702c5SYu Xiangning sosdp_listen, /* sop_listen */ 1050f1702c5SYu Xiangning sosdp_connect, /* sop_connect */ 1060f1702c5SYu Xiangning sosdp_recvmsg, /* sop_recvmsg */ 1070f1702c5SYu Xiangning sosdp_sendmsg, /* sop_sendmsg */ 1080f1702c5SYu Xiangning so_sendmblk_notsupp, /* sop_sendmblk */ 1090f1702c5SYu Xiangning sosdp_getpeername, /* sop_getpeername */ 1100f1702c5SYu Xiangning sosdp_getsockname, /* sop_getsockname */ 1110f1702c5SYu Xiangning sosdp_shutdown, /* sop_shutdown */ 1120f1702c5SYu Xiangning sosdp_getsockopt, /* sop_getsockopt */ 1130f1702c5SYu Xiangning sosdp_setsockopt, /* sop_setsockopt */ 1140f1702c5SYu Xiangning sosdp_ioctl, /* sop_ioctl */ 1150f1702c5SYu Xiangning sosdp_poll, /* sop_poll */ 1160f1702c5SYu Xiangning sosdp_close, /* sop_close */ 1170f1702c5SYu Xiangning }; 1180f1702c5SYu Xiangning 1190f1702c5SYu Xiangning sdp_upcalls_t sosdp_sock_upcalls = { 1200f1702c5SYu Xiangning sdp_sock_newconn, 1210f1702c5SYu Xiangning sdp_sock_connected, 1220f1702c5SYu Xiangning sdp_sock_disconnected, 1230f1702c5SYu Xiangning sdp_sock_connfail, 1240f1702c5SYu Xiangning sdp_sock_recv, 1250f1702c5SYu Xiangning sdp_sock_xmitted, 1260f1702c5SYu Xiangning sdp_sock_urgdata, 1270f1702c5SYu Xiangning sdp_sock_ordrel, 1280f1702c5SYu Xiangning }; 1290f1702c5SYu Xiangning 1300f1702c5SYu Xiangning /* ARGSUSED */ 1310f1702c5SYu Xiangning static int 1320f1702c5SYu Xiangning sosdp_init(struct sonode *so, struct sonode *pso, struct cred *cr, int flags) 1330f1702c5SYu Xiangning { 1340f1702c5SYu Xiangning int error = 0; 1350f1702c5SYu Xiangning sdp_sockbuf_limits_t sbl; 1360f1702c5SYu Xiangning sdp_upcalls_t *upcalls; 1370f1702c5SYu Xiangning 1380f1702c5SYu Xiangning if (pso != NULL) { 1390f1702c5SYu Xiangning /* passive open, just inherit settings from parent */ 1400f1702c5SYu Xiangning 1410f1702c5SYu Xiangning mutex_enter(&so->so_lock); 1420f1702c5SYu Xiangning 1430f1702c5SYu Xiangning so->so_state |= (SS_ISBOUND | SS_ISCONNECTED | 1440f1702c5SYu Xiangning (pso->so_state & SS_ASYNC)); 1450f1702c5SYu Xiangning sosdp_so_inherit(pso, so); 1460f1702c5SYu Xiangning so->so_proto_props = pso->so_proto_props; 1470f1702c5SYu Xiangning 1480f1702c5SYu Xiangning mutex_exit(&so->so_lock); 1490f1702c5SYu Xiangning 1500f1702c5SYu Xiangning return (0); 1510f1702c5SYu Xiangning } 1520f1702c5SYu Xiangning 153634e26ecSCasper H.S. Dik if ((error = secpolicy_basic_net_access(cr)) != 0) 154634e26ecSCasper H.S. Dik return (error); 155634e26ecSCasper H.S. Dik 1560f1702c5SYu Xiangning upcalls = &sosdp_sock_upcalls; 1570f1702c5SYu Xiangning 1580f1702c5SYu Xiangning so->so_proto_handle = (sock_lower_handle_t)sdp_create(so, NULL, 1590f1702c5SYu Xiangning so->so_family, SDP_CAN_BLOCK, upcalls, &sbl, cr, &error); 1600f1702c5SYu Xiangning if (so->so_proto_handle == NULL) 1610f1702c5SYu Xiangning return (ENOMEM); 1620f1702c5SYu Xiangning 1630f1702c5SYu Xiangning so->so_rcvbuf = sbl.sbl_rxbuf; 1640f1702c5SYu Xiangning so->so_rcvlowat = sbl.sbl_rxlowat; 1650f1702c5SYu Xiangning so->so_sndbuf = sbl.sbl_txbuf; 1660f1702c5SYu Xiangning so->so_sndlowat = sbl.sbl_txlowat; 1670f1702c5SYu Xiangning 1680f1702c5SYu Xiangning return (error); 1690f1702c5SYu Xiangning } 1700f1702c5SYu Xiangning 1710f1702c5SYu Xiangning /* 1720f1702c5SYu Xiangning * Accept incoming connection. 1730f1702c5SYu Xiangning */ 1740f1702c5SYu Xiangning /* ARGSUSED */ 1750f1702c5SYu Xiangning static int 1760f1702c5SYu Xiangning sosdp_accept(struct sonode *lso, int fflag, struct cred *cr, 1770f1702c5SYu Xiangning struct sonode **nsop) 1780f1702c5SYu Xiangning { 1790f1702c5SYu Xiangning int error = 0; 1800f1702c5SYu Xiangning struct sonode *nso; 1810f1702c5SYu Xiangning 1820f1702c5SYu Xiangning dprint(3, ("sosdp_accept: so:%p so_proto_handle:%p", (void *)lso, 1830f1702c5SYu Xiangning (void *)lso->so_proto_handle)); 1840f1702c5SYu Xiangning 1850f1702c5SYu Xiangning if (!(lso->so_state & SS_ACCEPTCONN)) { 1860f1702c5SYu Xiangning /* 1870f1702c5SYu Xiangning * Not a listen socket. 1880f1702c5SYu Xiangning */ 1890f1702c5SYu Xiangning eprintsoline(lso, EINVAL); 1900f1702c5SYu Xiangning return (EINVAL); 1910f1702c5SYu Xiangning } 1920f1702c5SYu Xiangning /* 1930f1702c5SYu Xiangning * Returns right away if socket is nonblocking. 1940f1702c5SYu Xiangning */ 1950f1702c5SYu Xiangning error = so_acceptq_dequeue(lso, (fflag & (FNONBLOCK|FNDELAY)), &nso); 1960f1702c5SYu Xiangning if (error != 0) { 1970f1702c5SYu Xiangning eprintsoline(lso, error); 1980f1702c5SYu Xiangning dprint(4, ("sosdp_accept: failed %d:lso:%p so_proto_handle:%p", 1990f1702c5SYu Xiangning error, (void *)lso, (void *)lso->so_proto_handle)); 2000f1702c5SYu Xiangning return (error); 2010f1702c5SYu Xiangning } 2020f1702c5SYu Xiangning 2030f1702c5SYu Xiangning dprint(2, ("sosdp_accept: new %p\n", (void *)nso)); 2040f1702c5SYu Xiangning *nsop = nso; 2050f1702c5SYu Xiangning 2060f1702c5SYu Xiangning return (0); 2070f1702c5SYu Xiangning } 2080f1702c5SYu Xiangning 2090f1702c5SYu Xiangning /* 2100f1702c5SYu Xiangning * Bind local endpoint. 2110f1702c5SYu Xiangning */ 2120f1702c5SYu Xiangning /* ARGSUSED */ 2130f1702c5SYu Xiangning int 2140f1702c5SYu Xiangning sosdp_bind(struct sonode *so, struct sockaddr *name, socklen_t namelen, 2150f1702c5SYu Xiangning int flags, struct cred *cr) 2160f1702c5SYu Xiangning { 2170f1702c5SYu Xiangning int error = 0; 2180f1702c5SYu Xiangning 2190f1702c5SYu Xiangning if (!(flags & _SOBIND_LOCK_HELD)) { 2200f1702c5SYu Xiangning mutex_enter(&so->so_lock); 2210f1702c5SYu Xiangning so_lock_single(so); /* Set SOLOCKED */ 2220f1702c5SYu Xiangning } else { 2230f1702c5SYu Xiangning ASSERT(MUTEX_HELD(&so->so_lock)); 2240f1702c5SYu Xiangning ASSERT(so->so_flag & SOLOCKED); 2250f1702c5SYu Xiangning } 2260f1702c5SYu Xiangning 2270f1702c5SYu Xiangning if ((so->so_state & SS_ISBOUND) || name == NULL || namelen == 0) { 2280f1702c5SYu Xiangning /* 2290f1702c5SYu Xiangning * Multiple binds not allowed for any SDP socket. 2300f1702c5SYu Xiangning * Also binding with null address is not supported. 2310f1702c5SYu Xiangning */ 2320f1702c5SYu Xiangning error = EINVAL; 2330f1702c5SYu Xiangning eprintsoline(so, error); 2340f1702c5SYu Xiangning goto done; 2350f1702c5SYu Xiangning } 2360f1702c5SYu Xiangning 2370f1702c5SYu Xiangning /* 2380f1702c5SYu Xiangning * X/Open requires this check 2390f1702c5SYu Xiangning */ 2400f1702c5SYu Xiangning if (so->so_state & SS_CANTSENDMORE) { 2410f1702c5SYu Xiangning error = EINVAL; 2420f1702c5SYu Xiangning goto done; 2430f1702c5SYu Xiangning } 2440f1702c5SYu Xiangning 2450f1702c5SYu Xiangning /* 2460f1702c5SYu Xiangning * Protocol module does address family checks 2470f1702c5SYu Xiangning */ 2480f1702c5SYu Xiangning mutex_exit(&so->so_lock); 2490f1702c5SYu Xiangning 2500f1702c5SYu Xiangning error = sdp_bind((struct sdp_conn_struct_t *)so->so_proto_handle, 2510f1702c5SYu Xiangning name, namelen); 2520f1702c5SYu Xiangning 2530f1702c5SYu Xiangning mutex_enter(&so->so_lock); 2540f1702c5SYu Xiangning 2550f1702c5SYu Xiangning if (error == 0) { 2560f1702c5SYu Xiangning so->so_state |= SS_ISBOUND; 2570f1702c5SYu Xiangning } else { 2580f1702c5SYu Xiangning eprintsoline(so, error); 2590f1702c5SYu Xiangning } 2600f1702c5SYu Xiangning done: 2610f1702c5SYu Xiangning if (!(flags & _SOBIND_LOCK_HELD)) { 2620f1702c5SYu Xiangning so_unlock_single(so, SOLOCKED); 2630f1702c5SYu Xiangning mutex_exit(&so->so_lock); 2640f1702c5SYu Xiangning } else { 2650f1702c5SYu Xiangning /* If the caller held the lock don't release it here */ 2660f1702c5SYu Xiangning ASSERT(MUTEX_HELD(&so->so_lock)); 2670f1702c5SYu Xiangning ASSERT(so->so_flag & SOLOCKED); 2680f1702c5SYu Xiangning } 2690f1702c5SYu Xiangning return (error); 2700f1702c5SYu Xiangning } 2710f1702c5SYu Xiangning 2720f1702c5SYu Xiangning /* 2730f1702c5SYu Xiangning * Turn socket into a listen socket. 2740f1702c5SYu Xiangning */ 2750f1702c5SYu Xiangning /* ARGSUSED */ 2760f1702c5SYu Xiangning static int 2770f1702c5SYu Xiangning sosdp_listen(struct sonode *so, int backlog, struct cred *cr) 2780f1702c5SYu Xiangning { 2790f1702c5SYu Xiangning int error = 0; 2800f1702c5SYu Xiangning 2810f1702c5SYu Xiangning mutex_enter(&so->so_lock); 2820f1702c5SYu Xiangning so_lock_single(so); 2830f1702c5SYu Xiangning 2840f1702c5SYu Xiangning /* 2850f1702c5SYu Xiangning * If this socket is trying to do connect, or if it has 2860f1702c5SYu Xiangning * been connected, disallow. 2870f1702c5SYu Xiangning */ 2880f1702c5SYu Xiangning if (so->so_state & (SS_ISCONNECTING | SS_ISCONNECTED | 2890f1702c5SYu Xiangning SS_ISDISCONNECTING | SS_CANTRCVMORE | SS_CANTSENDMORE)) { 2900f1702c5SYu Xiangning error = EINVAL; 2910f1702c5SYu Xiangning eprintsoline(so, EINVAL); 2920f1702c5SYu Xiangning goto done; 2930f1702c5SYu Xiangning } 2940f1702c5SYu Xiangning /* 2950f1702c5SYu Xiangning * If listen() is only called to change backlog, we don't 2960f1702c5SYu Xiangning * need to notify protocol module. 2970f1702c5SYu Xiangning */ 2980f1702c5SYu Xiangning if (so->so_state & SS_ACCEPTCONN) { 2990f1702c5SYu Xiangning so->so_backlog = backlog; 3000f1702c5SYu Xiangning goto done; 3010f1702c5SYu Xiangning } 3020f1702c5SYu Xiangning 3030f1702c5SYu Xiangning mutex_exit(&so->so_lock); 3040f1702c5SYu Xiangning 3050f1702c5SYu Xiangning error = sdp_listen((struct sdp_conn_struct_t *)so->so_proto_handle, 3060f1702c5SYu Xiangning backlog); 3070f1702c5SYu Xiangning 3080f1702c5SYu Xiangning mutex_enter(&so->so_lock); 3090f1702c5SYu Xiangning if (error == 0) { 3100f1702c5SYu Xiangning so->so_state |= (SS_ACCEPTCONN | SS_ISBOUND); 3110f1702c5SYu Xiangning so->so_backlog = backlog; 3120f1702c5SYu Xiangning } else { 3130f1702c5SYu Xiangning eprintsoline(so, error); 3140f1702c5SYu Xiangning } 3150f1702c5SYu Xiangning done: 3160f1702c5SYu Xiangning so_unlock_single(so, SOLOCKED); 3170f1702c5SYu Xiangning mutex_exit(&so->so_lock); 3180f1702c5SYu Xiangning 3190f1702c5SYu Xiangning return (error); 3200f1702c5SYu Xiangning } 3210f1702c5SYu Xiangning 3220f1702c5SYu Xiangning /* 3230f1702c5SYu Xiangning * Active open. 3240f1702c5SYu Xiangning */ 3250f1702c5SYu Xiangning /*ARGSUSED*/ 3260f1702c5SYu Xiangning static int 327*3e95bd4aSAnders Persson sosdp_connect(struct sonode *so, struct sockaddr *name, 3280f1702c5SYu Xiangning socklen_t namelen, int fflag, int flags, struct cred *cr) 3290f1702c5SYu Xiangning { 3300f1702c5SYu Xiangning int error = 0; 3310f1702c5SYu Xiangning 3320f1702c5SYu Xiangning mutex_enter(&so->so_lock); 3330f1702c5SYu Xiangning so_lock_single(so); 3340f1702c5SYu Xiangning 3350f1702c5SYu Xiangning /* 3360f1702c5SYu Xiangning * Can't connect() after listen(), or if the socket is already 3370f1702c5SYu Xiangning * connected. 3380f1702c5SYu Xiangning */ 3390f1702c5SYu Xiangning if (so->so_state & (SS_ACCEPTCONN|SS_ISCONNECTED|SS_ISCONNECTING)) { 3400f1702c5SYu Xiangning if (so->so_state & SS_ISCONNECTED) { 3410f1702c5SYu Xiangning error = EISCONN; 3420f1702c5SYu Xiangning } else if (so->so_state & SS_ISCONNECTING) { 3430f1702c5SYu Xiangning error = EALREADY; 3440f1702c5SYu Xiangning } else { 3450f1702c5SYu Xiangning error = EOPNOTSUPP; 3460f1702c5SYu Xiangning } 3470f1702c5SYu Xiangning eprintsoline(so, error); 3480f1702c5SYu Xiangning goto done; 3490f1702c5SYu Xiangning } 3500f1702c5SYu Xiangning 3510f1702c5SYu Xiangning /* 3520f1702c5SYu Xiangning * check for failure of an earlier call 3530f1702c5SYu Xiangning */ 3540f1702c5SYu Xiangning if (so->so_error != 0) { 3550f1702c5SYu Xiangning error = sogeterr(so, B_TRUE); 3560f1702c5SYu Xiangning eprintsoline(so, error); 3570f1702c5SYu Xiangning goto done; 3580f1702c5SYu Xiangning } 3590f1702c5SYu Xiangning 3600f1702c5SYu Xiangning /* 3610f1702c5SYu Xiangning * Connection is closing, or closed, don't allow reconnect. 3620f1702c5SYu Xiangning * TCP allows this to proceed, but the socket remains unwriteable. 3630f1702c5SYu Xiangning * BSD returns EINVAL. 3640f1702c5SYu Xiangning */ 3650f1702c5SYu Xiangning if (so->so_state & (SS_ISDISCONNECTING|SS_CANTRCVMORE| 3660f1702c5SYu Xiangning SS_CANTSENDMORE)) { 3670f1702c5SYu Xiangning error = EINVAL; 3680f1702c5SYu Xiangning eprintsoline(so, error); 3690f1702c5SYu Xiangning goto done; 3700f1702c5SYu Xiangning } 3710f1702c5SYu Xiangning if (name == NULL || namelen == 0) { 3720f1702c5SYu Xiangning eprintsoline(so, EINVAL); 3730f1702c5SYu Xiangning goto done; 3740f1702c5SYu Xiangning } 3750f1702c5SYu Xiangning soisconnecting(so); 3760f1702c5SYu Xiangning mutex_exit(&so->so_lock); 3770f1702c5SYu Xiangning 3780f1702c5SYu Xiangning error = sdp_connect((struct sdp_conn_struct_t *)so->so_proto_handle, 3790f1702c5SYu Xiangning name, namelen); 3800f1702c5SYu Xiangning 3810f1702c5SYu Xiangning mutex_enter(&so->so_lock); 3820f1702c5SYu Xiangning if (error == 0) { 3830f1702c5SYu Xiangning /* 3840f1702c5SYu Xiangning * Allow other threads to access the socket 3850f1702c5SYu Xiangning */ 3860f1702c5SYu Xiangning error = sowaitconnected(so, fflag, 0); 3870f1702c5SYu Xiangning dprint(4, 3880f1702c5SYu Xiangning ("sosdp_connect: wait on so:%p " 3890f1702c5SYu Xiangning "so_proto_handle:%p failed:%d", 3900f1702c5SYu Xiangning (void *)so, (void *)so->so_proto_handle, error)); 3910f1702c5SYu Xiangning } 3920f1702c5SYu Xiangning 3930f1702c5SYu Xiangning switch (error) { 3940f1702c5SYu Xiangning case 0: 3950f1702c5SYu Xiangning case EINPROGRESS: 3960f1702c5SYu Xiangning case EALREADY: 3970f1702c5SYu Xiangning case EINTR: 3980f1702c5SYu Xiangning /* Non-fatal errors */ 3990f1702c5SYu Xiangning so->so_state |= SS_ISBOUND; 4000f1702c5SYu Xiangning break; 4010f1702c5SYu Xiangning default: 4020f1702c5SYu Xiangning /* clear SS_ISCONNECTING in case it was set */ 4030f1702c5SYu Xiangning so->so_state &= ~SS_ISCONNECTING; 4040f1702c5SYu Xiangning break; 4050f1702c5SYu Xiangning } 4060f1702c5SYu Xiangning done: 4070f1702c5SYu Xiangning so_unlock_single(so, SOLOCKED); 4080f1702c5SYu Xiangning mutex_exit(&so->so_lock); 4090f1702c5SYu Xiangning return (error); 4100f1702c5SYu Xiangning } 4110f1702c5SYu Xiangning 4120f1702c5SYu Xiangning /* 4130f1702c5SYu Xiangning * Receive data. 4140f1702c5SYu Xiangning */ 4150f1702c5SYu Xiangning /* ARGSUSED */ 4160f1702c5SYu Xiangning int 4170f1702c5SYu Xiangning sosdp_recvmsg(struct sonode *so, struct nmsghdr *msg, struct uio *uiop, 4180f1702c5SYu Xiangning struct cred *cr) 4190f1702c5SYu Xiangning { 4200f1702c5SYu Xiangning int flags, error = 0; 4210f1702c5SYu Xiangning int size; 4220f1702c5SYu Xiangning 4230f1702c5SYu Xiangning flags = msg->msg_flags; 4240f1702c5SYu Xiangning msg->msg_flags = 0; 4250f1702c5SYu Xiangning 4260f1702c5SYu Xiangning 4270f1702c5SYu Xiangning if (!(so->so_state & (SS_ISCONNECTED|SS_ISCONNECTING| 4280f1702c5SYu Xiangning SS_CANTRCVMORE))) { 4290f1702c5SYu Xiangning return (ENOTCONN); 4300f1702c5SYu Xiangning } 4310f1702c5SYu Xiangning 4320f1702c5SYu Xiangning /* 4330f1702c5SYu Xiangning * flag possibilities: 4340f1702c5SYu Xiangning * 4350f1702c5SYu Xiangning * MSG_PEEK Don't consume data 4360f1702c5SYu Xiangning * MSG_WAITALL Wait for full quantity of data (ignored if MSG_PEEK) 4370f1702c5SYu Xiangning * MSG_DONTWAIT Non-blocking (same as FNDELAY | FNONBLOCK) 4380f1702c5SYu Xiangning * 4390f1702c5SYu Xiangning * MSG_WAITALL can return less than the full buffer if either 4400f1702c5SYu Xiangning * 4410f1702c5SYu Xiangning * 1. we would block and we are non-blocking 4420f1702c5SYu Xiangning * 2. a full message cannot be delivered 4430f1702c5SYu Xiangning * 4440f1702c5SYu Xiangning */ 4450f1702c5SYu Xiangning 4460f1702c5SYu Xiangning mutex_enter(&so->so_lock); 4470f1702c5SYu Xiangning 4480f1702c5SYu Xiangning /* 4490f1702c5SYu Xiangning * Allow just one reader at a time. 4500f1702c5SYu Xiangning */ 4510f1702c5SYu Xiangning error = so_lock_read_intr(so, 4520f1702c5SYu Xiangning uiop->uio_fmode | ((flags & MSG_DONTWAIT) ? FNONBLOCK : 0)); 4530f1702c5SYu Xiangning if (error != 0) { 4540f1702c5SYu Xiangning mutex_exit(&so->so_lock); 4550f1702c5SYu Xiangning return (error); 4560f1702c5SYu Xiangning } 4570f1702c5SYu Xiangning size = uiop->uio_resid; 4580f1702c5SYu Xiangning mutex_exit(&so->so_lock); 4590f1702c5SYu Xiangning 4600f1702c5SYu Xiangning if (!(so->so_state & SS_CANTRCVMORE)) { 4610f1702c5SYu Xiangning if (uiop->uio_fmode & (FNDELAY|FNONBLOCK)) { 4620f1702c5SYu Xiangning flags |= MSG_DONTWAIT; 4630f1702c5SYu Xiangning } 4640f1702c5SYu Xiangning error = sdp_recv( 4650f1702c5SYu Xiangning (struct sdp_conn_struct_t *)so->so_proto_handle, msg, 4660f1702c5SYu Xiangning size, flags, uiop); 4670f1702c5SYu Xiangning } else { 4680f1702c5SYu Xiangning msg->msg_controllen = 0; 4690f1702c5SYu Xiangning msg->msg_namelen = 0; 4700f1702c5SYu Xiangning } 4710f1702c5SYu Xiangning done: 4720f1702c5SYu Xiangning mutex_enter(&so->so_lock); 4730f1702c5SYu Xiangning so_unlock_read(so); 4740f1702c5SYu Xiangning mutex_exit(&so->so_lock); 4750f1702c5SYu Xiangning return (error); 4760f1702c5SYu Xiangning } 4770f1702c5SYu Xiangning 4780f1702c5SYu Xiangning /* 4790f1702c5SYu Xiangning * Send message. 4800f1702c5SYu Xiangning */ 4810f1702c5SYu Xiangning /* ARGSUSED */ 4820f1702c5SYu Xiangning static int 4830f1702c5SYu Xiangning sosdp_sendmsg(struct sonode *so, struct nmsghdr *msg, struct uio *uiop, 4840f1702c5SYu Xiangning struct cred *cr) 4850f1702c5SYu Xiangning { 4860f1702c5SYu Xiangning int flags; 4870f1702c5SYu Xiangning ssize_t count; 4880f1702c5SYu Xiangning int error; 4890f1702c5SYu Xiangning 4900f1702c5SYu Xiangning ASSERT(so->so_type == SOCK_STREAM); 4910f1702c5SYu Xiangning 4920f1702c5SYu Xiangning dprint(4, ("sosdp_sendmsg: so:%p so_proto_handle:%p", 4930f1702c5SYu Xiangning (void *)so, (void *)so->so_proto_handle)); 4940f1702c5SYu Xiangning 4950f1702c5SYu Xiangning flags = msg->msg_flags; 4960f1702c5SYu Xiangning 4970f1702c5SYu Xiangning if (msg->msg_controllen != 0) { 4980f1702c5SYu Xiangning return (EOPNOTSUPP); 4990f1702c5SYu Xiangning } 5000f1702c5SYu Xiangning 5010f1702c5SYu Xiangning mutex_enter(&so->so_lock); 5020f1702c5SYu Xiangning if (so->so_state & SS_CANTSENDMORE) { 5030f1702c5SYu Xiangning mutex_exit(&so->so_lock); 5040f1702c5SYu Xiangning return (EPIPE); 5050f1702c5SYu Xiangning } 5060f1702c5SYu Xiangning 5070f1702c5SYu Xiangning if (so->so_error != 0) { 5080f1702c5SYu Xiangning error = sogeterr(so, B_TRUE); 5090f1702c5SYu Xiangning mutex_exit(&so->so_lock); 5100f1702c5SYu Xiangning return (error); 5110f1702c5SYu Xiangning } 5120f1702c5SYu Xiangning 5130f1702c5SYu Xiangning if (uiop->uio_fmode & (FNDELAY|FNONBLOCK)) 5140f1702c5SYu Xiangning flags |= MSG_DONTWAIT; 5150f1702c5SYu Xiangning 5160f1702c5SYu Xiangning count = uiop->uio_resid; 5170f1702c5SYu Xiangning 5180f1702c5SYu Xiangning if (!(so->so_state & (SS_ISCONNECTING | SS_ISCONNECTED))) { 5190f1702c5SYu Xiangning dprint(4, ("sosdp_sendmsg: invalid state: <%x>", 5200f1702c5SYu Xiangning so->so_state)); 5210f1702c5SYu Xiangning mutex_exit(&so->so_lock); 5220f1702c5SYu Xiangning return (ENOTCONN); 5230f1702c5SYu Xiangning } 5240f1702c5SYu Xiangning 5250f1702c5SYu Xiangning mutex_exit(&so->so_lock); 5260f1702c5SYu Xiangning error = sdp_send((struct sdp_conn_struct_t *)so->so_proto_handle, 5270f1702c5SYu Xiangning msg, count, flags, uiop); 5280f1702c5SYu Xiangning 5290f1702c5SYu Xiangning return (error); 5300f1702c5SYu Xiangning } 5310f1702c5SYu Xiangning 5320f1702c5SYu Xiangning /* 5330f1702c5SYu Xiangning * Get address of remote node. 5340f1702c5SYu Xiangning */ 5350f1702c5SYu Xiangning /* ARGSUSED */ 5360f1702c5SYu Xiangning static int 5370f1702c5SYu Xiangning sosdp_getpeername(struct sonode *so, struct sockaddr *addr, socklen_t *addrlen, 5380f1702c5SYu Xiangning boolean_t accept, struct cred *cr) 5390f1702c5SYu Xiangning { 5400f1702c5SYu Xiangning 5410f1702c5SYu Xiangning if (!accept && !(so->so_state & SS_ISCONNECTED)) { 5420f1702c5SYu Xiangning return (ENOTCONN); 5430f1702c5SYu Xiangning } else { 5440f1702c5SYu Xiangning return (sdp_getpeername( 5450f1702c5SYu Xiangning (struct sdp_conn_struct_t *)so->so_proto_handle, 5460f1702c5SYu Xiangning addr, addrlen)); 5470f1702c5SYu Xiangning } 5480f1702c5SYu Xiangning } 5490f1702c5SYu Xiangning 5500f1702c5SYu Xiangning /* 5510f1702c5SYu Xiangning * Get local address. 5520f1702c5SYu Xiangning */ 5530f1702c5SYu Xiangning /* ARGSUSED */ 5540f1702c5SYu Xiangning static int 5550f1702c5SYu Xiangning sosdp_getsockname(struct sonode *so, struct sockaddr *addr, socklen_t *addrlen, 5560f1702c5SYu Xiangning struct cred *cr) 5570f1702c5SYu Xiangning { 5580f1702c5SYu Xiangning mutex_enter(&so->so_lock); 5590f1702c5SYu Xiangning 5600f1702c5SYu Xiangning if (!(so->so_state & SS_ISBOUND)) { 5610f1702c5SYu Xiangning /* 5620f1702c5SYu Xiangning * Zero address, except for address family 5630f1702c5SYu Xiangning */ 5640f1702c5SYu Xiangning if (so->so_family == AF_INET || so->so_family == AF_INET6) { 5650f1702c5SYu Xiangning bzero(addr, *addrlen); 5660f1702c5SYu Xiangning *addrlen = (so->so_family == AF_INET6) ? 5670f1702c5SYu Xiangning sizeof (struct sockaddr_in6) : 5680f1702c5SYu Xiangning sizeof (struct sockaddr_in); 5690f1702c5SYu Xiangning addr->sa_family = so->so_family; 5700f1702c5SYu Xiangning } 5710f1702c5SYu Xiangning mutex_exit(&so->so_lock); 5720f1702c5SYu Xiangning return (0); 5730f1702c5SYu Xiangning } else { 5740f1702c5SYu Xiangning mutex_exit(&so->so_lock); 5750f1702c5SYu Xiangning return (sdp_getsockname( 5760f1702c5SYu Xiangning (struct sdp_conn_struct_t *)so->so_proto_handle, 5770f1702c5SYu Xiangning addr, addrlen)); 5780f1702c5SYu Xiangning } 5790f1702c5SYu Xiangning } 5800f1702c5SYu Xiangning 5810f1702c5SYu Xiangning /* 5820f1702c5SYu Xiangning * Called from shutdown(). 5830f1702c5SYu Xiangning */ 5840f1702c5SYu Xiangning /* ARGSUSED */ 5850f1702c5SYu Xiangning static int 5860f1702c5SYu Xiangning sosdp_shutdown(struct sonode *so, int how, struct cred *cr) 5870f1702c5SYu Xiangning { 5880f1702c5SYu Xiangning uint_t state_change; 5890f1702c5SYu Xiangning int error = 0; 5900f1702c5SYu Xiangning 5910f1702c5SYu Xiangning mutex_enter(&so->so_lock); 5920f1702c5SYu Xiangning so_lock_single(so); 5930f1702c5SYu Xiangning /* 5940f1702c5SYu Xiangning * Record the current state and then perform any state changes. 5950f1702c5SYu Xiangning * Then use the difference between the old and new states to 5960f1702c5SYu Xiangning * determine which needs to be done. 5970f1702c5SYu Xiangning */ 5980f1702c5SYu Xiangning state_change = so->so_state; 5990f1702c5SYu Xiangning if (!(state_change & SS_ISCONNECTED)) { 6000f1702c5SYu Xiangning error = ENOTCONN; 6010f1702c5SYu Xiangning goto done; 6020f1702c5SYu Xiangning } 6030f1702c5SYu Xiangning 6040f1702c5SYu Xiangning switch (how) { 6050f1702c5SYu Xiangning case SHUT_RD: 6060f1702c5SYu Xiangning socantrcvmore(so); 6070f1702c5SYu Xiangning break; 6080f1702c5SYu Xiangning case SHUT_WR: 6090f1702c5SYu Xiangning socantsendmore(so); 6100f1702c5SYu Xiangning break; 6110f1702c5SYu Xiangning case SHUT_RDWR: 6120f1702c5SYu Xiangning socantsendmore(so); 6130f1702c5SYu Xiangning socantrcvmore(so); 6140f1702c5SYu Xiangning break; 6150f1702c5SYu Xiangning default: 6160f1702c5SYu Xiangning error = EINVAL; 6170f1702c5SYu Xiangning goto done; 6180f1702c5SYu Xiangning } 6190f1702c5SYu Xiangning 6200f1702c5SYu Xiangning state_change = so->so_state & ~state_change; 6210f1702c5SYu Xiangning 6220f1702c5SYu Xiangning if (state_change & SS_CANTSENDMORE) { 6230f1702c5SYu Xiangning so->so_state |= SS_ISDISCONNECTING; 6240f1702c5SYu Xiangning } 6250f1702c5SYu Xiangning so_notify_shutdown(so); 6260f1702c5SYu Xiangning 6270f1702c5SYu Xiangning if (state_change & SS_CANTSENDMORE) { 6280f1702c5SYu Xiangning error = sdp_shutdown( 6290f1702c5SYu Xiangning (struct sdp_conn_struct_t *)so->so_proto_handle, how); 6300f1702c5SYu Xiangning } 6310f1702c5SYu Xiangning 6320f1702c5SYu Xiangning mutex_enter(&so->so_lock); 6330f1702c5SYu Xiangning done: 6340f1702c5SYu Xiangning so_unlock_single(so, SOLOCKED); 6350f1702c5SYu Xiangning mutex_exit(&so->so_lock); 6360f1702c5SYu Xiangning 6370f1702c5SYu Xiangning /* 6380f1702c5SYu Xiangning * HACK: sdp_disconnect() may return EWOULDBLOCK. But this error is 6390f1702c5SYu Xiangning * not documented in standard socket API. Catch it here. 6400f1702c5SYu Xiangning */ 6410f1702c5SYu Xiangning if (error == EWOULDBLOCK) 6420f1702c5SYu Xiangning error = 0; 6430f1702c5SYu Xiangning return (error); 6440f1702c5SYu Xiangning } 6450f1702c5SYu Xiangning 6460f1702c5SYu Xiangning /* 6470f1702c5SYu Xiangning * Get socket options. 6480f1702c5SYu Xiangning */ 6490f1702c5SYu Xiangning /*ARGSUSED*/ 6500f1702c5SYu Xiangning static int 6510f1702c5SYu Xiangning sosdp_getsockopt(struct sonode *so, int level, int option_name, 6520f1702c5SYu Xiangning void *optval, socklen_t *optlenp, int flags, struct cred *cr) 6530f1702c5SYu Xiangning { 6540f1702c5SYu Xiangning int error = 0; 6550f1702c5SYu Xiangning void *option = NULL; 6560f1702c5SYu Xiangning socklen_t maxlen = *optlenp, len, optlen; 6570f1702c5SYu Xiangning uint32_t value; 6580f1702c5SYu Xiangning uint8_t buffer[4]; 6590f1702c5SYu Xiangning void *optbuf = &buffer; 6600f1702c5SYu Xiangning 6610f1702c5SYu Xiangning 6620f1702c5SYu Xiangning mutex_enter(&so->so_lock); 6630f1702c5SYu Xiangning 6640f1702c5SYu Xiangning if (level == SOL_SOCKET) { 6650f1702c5SYu Xiangning switch (option_name) { 6660f1702c5SYu Xiangning case SO_TYPE: 6670f1702c5SYu Xiangning case SO_ERROR: 6680f1702c5SYu Xiangning case SO_DEBUG: 6690f1702c5SYu Xiangning case SO_ACCEPTCONN: 6700f1702c5SYu Xiangning case SO_REUSEADDR: 6710f1702c5SYu Xiangning case SO_KEEPALIVE: 6720f1702c5SYu Xiangning case SO_DONTROUTE: 6730f1702c5SYu Xiangning case SO_BROADCAST: 6740f1702c5SYu Xiangning case SO_USELOOPBACK: 6750f1702c5SYu Xiangning case SO_OOBINLINE: 6760f1702c5SYu Xiangning case SO_SNDBUF: 6770f1702c5SYu Xiangning case SO_RCVBUF: 6780f1702c5SYu Xiangning case SO_SNDLOWAT: 6790f1702c5SYu Xiangning case SO_RCVLOWAT: 6800f1702c5SYu Xiangning case SO_DGRAM_ERRIND: 6810f1702c5SYu Xiangning if (maxlen < (t_uscalar_t)sizeof (int32_t)) { 6820f1702c5SYu Xiangning error = EINVAL; 6830f1702c5SYu Xiangning eprintsoline(so, error); 6840f1702c5SYu Xiangning goto done; 6850f1702c5SYu Xiangning } 6860f1702c5SYu Xiangning break; 6870f1702c5SYu Xiangning case SO_LINGER: 6880f1702c5SYu Xiangning if (maxlen < (t_uscalar_t)sizeof (struct linger)) { 6890f1702c5SYu Xiangning error = EINVAL; 6900f1702c5SYu Xiangning eprintsoline(so, error); 6910f1702c5SYu Xiangning goto done; 6920f1702c5SYu Xiangning } 6930f1702c5SYu Xiangning break; 6940f1702c5SYu Xiangning } 6950f1702c5SYu Xiangning len = (t_uscalar_t)sizeof (uint32_t); /* Default */ 6960f1702c5SYu Xiangning option = &value; 6970f1702c5SYu Xiangning 6980f1702c5SYu Xiangning switch (option_name) { 6990f1702c5SYu Xiangning case SO_TYPE: 7000f1702c5SYu Xiangning value = so->so_type; 7010f1702c5SYu Xiangning goto copyout; 7020f1702c5SYu Xiangning 7030f1702c5SYu Xiangning case SO_ERROR: 7040f1702c5SYu Xiangning value = sogeterr(so, B_TRUE); 7050f1702c5SYu Xiangning goto copyout; 7060f1702c5SYu Xiangning 7070f1702c5SYu Xiangning case SO_ACCEPTCONN: 7080f1702c5SYu Xiangning value = (so->so_state & SS_ACCEPTCONN) ? 7090f1702c5SYu Xiangning SO_ACCEPTCONN : 0; 7100f1702c5SYu Xiangning goto copyout; 7110f1702c5SYu Xiangning 7120f1702c5SYu Xiangning case SO_DEBUG: 7130f1702c5SYu Xiangning case SO_REUSEADDR: 7140f1702c5SYu Xiangning case SO_KEEPALIVE: 7150f1702c5SYu Xiangning case SO_DONTROUTE: 7160f1702c5SYu Xiangning case SO_BROADCAST: 7170f1702c5SYu Xiangning case SO_USELOOPBACK: 7180f1702c5SYu Xiangning case SO_OOBINLINE: 7190f1702c5SYu Xiangning case SO_DGRAM_ERRIND: 7200f1702c5SYu Xiangning value = (so->so_options & option_name); 7210f1702c5SYu Xiangning goto copyout; 7220f1702c5SYu Xiangning 7230f1702c5SYu Xiangning /* 7240f1702c5SYu Xiangning * The following options are only returned by sockfs 7250f1702c5SYu Xiangning * when sdp_get_opt() fails. 7260f1702c5SYu Xiangning */ 7270f1702c5SYu Xiangning 7280f1702c5SYu Xiangning case SO_LINGER: 7290f1702c5SYu Xiangning option = &so->so_linger; 7300f1702c5SYu Xiangning len = (t_uscalar_t)sizeof (struct linger); 7310f1702c5SYu Xiangning break; 7320f1702c5SYu Xiangning case SO_SNDBUF: 7330f1702c5SYu Xiangning value = so->so_sndbuf; 7340f1702c5SYu Xiangning len = (t_uscalar_t)sizeof (int); 7350f1702c5SYu Xiangning goto copyout; 7360f1702c5SYu Xiangning 7370f1702c5SYu Xiangning case SO_RCVBUF: 7380f1702c5SYu Xiangning value = so->so_rcvbuf; 7390f1702c5SYu Xiangning len = (t_uscalar_t)sizeof (int); 7400f1702c5SYu Xiangning goto copyout; 7410f1702c5SYu Xiangning 7420f1702c5SYu Xiangning case SO_SNDLOWAT: 7430f1702c5SYu Xiangning value = so->so_sndlowat; 7440f1702c5SYu Xiangning len = (t_uscalar_t)sizeof (int); 7450f1702c5SYu Xiangning goto copyout; 7460f1702c5SYu Xiangning 7470f1702c5SYu Xiangning case SO_RCVLOWAT: 7480f1702c5SYu Xiangning value = so->so_rcvlowat; 7490f1702c5SYu Xiangning len = (t_uscalar_t)sizeof (int); 7500f1702c5SYu Xiangning goto copyout; 7510f1702c5SYu Xiangning 7520f1702c5SYu Xiangning default: 7530f1702c5SYu Xiangning option = NULL; 7540f1702c5SYu Xiangning break; 7550f1702c5SYu Xiangning } 7560f1702c5SYu Xiangning } 7570f1702c5SYu Xiangning if (maxlen > sizeof (buffer)) { 7580f1702c5SYu Xiangning optbuf = kmem_alloc(maxlen, KM_SLEEP); 7590f1702c5SYu Xiangning } 7600f1702c5SYu Xiangning optlen = maxlen; 7610f1702c5SYu Xiangning mutex_exit(&so->so_lock); 7620f1702c5SYu Xiangning error = sdp_get_opt((struct sdp_conn_struct_t *)so->so_proto_handle, 7630f1702c5SYu Xiangning level, option_name, optbuf, &optlen); 7640f1702c5SYu Xiangning mutex_enter(&so->so_lock); 7650f1702c5SYu Xiangning ASSERT(optlen <= maxlen); 7660f1702c5SYu Xiangning if (error != 0) { 7670f1702c5SYu Xiangning if (option == NULL) { 7680f1702c5SYu Xiangning /* We have no fallback value */ 7690f1702c5SYu Xiangning eprintsoline(so, error); 7700f1702c5SYu Xiangning goto free; 7710f1702c5SYu Xiangning } 7720f1702c5SYu Xiangning error = 0; 7730f1702c5SYu Xiangning goto copyout; 7740f1702c5SYu Xiangning } 7750f1702c5SYu Xiangning 7760f1702c5SYu Xiangning option = optbuf; 7770f1702c5SYu Xiangning len = optlen; 7780f1702c5SYu Xiangning 7790f1702c5SYu Xiangning copyout: 7800f1702c5SYu Xiangning len = MIN(len, maxlen); 7810f1702c5SYu Xiangning bcopy(option, optval, len); 7820f1702c5SYu Xiangning *optlenp = len; 7830f1702c5SYu Xiangning 7840f1702c5SYu Xiangning free: 7850f1702c5SYu Xiangning if (optbuf != &buffer) { 7860f1702c5SYu Xiangning kmem_free(optbuf, maxlen); 7870f1702c5SYu Xiangning } 7880f1702c5SYu Xiangning done: 7890f1702c5SYu Xiangning mutex_exit(&so->so_lock); 7900f1702c5SYu Xiangning return (error); 7910f1702c5SYu Xiangning } 7920f1702c5SYu Xiangning 7930f1702c5SYu Xiangning /* 7940f1702c5SYu Xiangning * Set socket options 7950f1702c5SYu Xiangning */ 7960f1702c5SYu Xiangning /* ARGSUSED */ 7970f1702c5SYu Xiangning static int 7980f1702c5SYu Xiangning sosdp_setsockopt(struct sonode *so, int level, int option_name, 7990f1702c5SYu Xiangning const void *optval, t_uscalar_t optlen, struct cred *cr) 8000f1702c5SYu Xiangning { 8010f1702c5SYu Xiangning void *conn = NULL; 8020f1702c5SYu Xiangning int error = 0; 8030f1702c5SYu Xiangning 8040f1702c5SYu Xiangning if (so->so_state & SS_CANTSENDMORE) { 8050f1702c5SYu Xiangning return (EINVAL); 8060f1702c5SYu Xiangning } 8070f1702c5SYu Xiangning 8080f1702c5SYu Xiangning mutex_enter(&so->so_lock); 8090f1702c5SYu Xiangning so_lock_single(so); 8100f1702c5SYu Xiangning 8110f1702c5SYu Xiangning if (so->so_type == SOCK_STREAM) { 8120f1702c5SYu Xiangning conn = (void *)so->so_proto_handle; 8130f1702c5SYu Xiangning } 8140f1702c5SYu Xiangning 8150f1702c5SYu Xiangning dprint(2, ("sosdp_setsockopt (%d) - conn %p %d %d \n", 8160f1702c5SYu Xiangning so->so_type, conn, level, option_name)); 8170f1702c5SYu Xiangning 8180f1702c5SYu Xiangning if (conn != NULL) { 8190f1702c5SYu Xiangning mutex_exit(&so->so_lock); 8200f1702c5SYu Xiangning error = sdp_set_opt((struct sdp_conn_struct_t *)conn, level, 8210f1702c5SYu Xiangning option_name, optval, optlen); 8220f1702c5SYu Xiangning mutex_enter(&so->so_lock); 8230f1702c5SYu Xiangning } 8240f1702c5SYu Xiangning 8250f1702c5SYu Xiangning /* 8260f1702c5SYu Xiangning * Check for SOL_SOCKET options and record their values. 8270f1702c5SYu Xiangning * If we know about a SOL_SOCKET parameter and the transport 8280f1702c5SYu Xiangning * failed it with TBADOPT or TOUTSTATE (i.e. ENOPROTOOPT or 8290f1702c5SYu Xiangning * EPROTO) we let the setsockopt succeed. 8300f1702c5SYu Xiangning */ 8310f1702c5SYu Xiangning if (level == SOL_SOCKET) { 8320f1702c5SYu Xiangning boolean_t handled = B_FALSE; 8330f1702c5SYu Xiangning 8340f1702c5SYu Xiangning /* Check parameters */ 8350f1702c5SYu Xiangning switch (option_name) { 8360f1702c5SYu Xiangning case SO_DEBUG: 8370f1702c5SYu Xiangning case SO_REUSEADDR: 8380f1702c5SYu Xiangning case SO_KEEPALIVE: 8390f1702c5SYu Xiangning case SO_DONTROUTE: 8400f1702c5SYu Xiangning case SO_BROADCAST: 8410f1702c5SYu Xiangning case SO_USELOOPBACK: 8420f1702c5SYu Xiangning case SO_OOBINLINE: 8430f1702c5SYu Xiangning case SO_SNDBUF: 8440f1702c5SYu Xiangning case SO_RCVBUF: 8450f1702c5SYu Xiangning case SO_SNDLOWAT: 8460f1702c5SYu Xiangning case SO_RCVLOWAT: 8470f1702c5SYu Xiangning case SO_DGRAM_ERRIND: 8480f1702c5SYu Xiangning if (optlen != (t_uscalar_t)sizeof (int32_t)) { 8490f1702c5SYu Xiangning error = EINVAL; 8500f1702c5SYu Xiangning eprintsoline(so, error); 8510f1702c5SYu Xiangning goto done; 8520f1702c5SYu Xiangning } 8530f1702c5SYu Xiangning ASSERT(optval); 8540f1702c5SYu Xiangning handled = B_TRUE; 8550f1702c5SYu Xiangning break; 8560f1702c5SYu Xiangning case SO_LINGER: 8570f1702c5SYu Xiangning if (optlen != (t_uscalar_t)sizeof (struct linger)) { 8580f1702c5SYu Xiangning error = EINVAL; 8590f1702c5SYu Xiangning eprintsoline(so, error); 8600f1702c5SYu Xiangning goto done; 8610f1702c5SYu Xiangning } 8620f1702c5SYu Xiangning ASSERT(optval); 8630f1702c5SYu Xiangning handled = B_TRUE; 8640f1702c5SYu Xiangning break; 8650f1702c5SYu Xiangning } 8660f1702c5SYu Xiangning 8670f1702c5SYu Xiangning #define intvalue (*(int32_t *)optval) 8680f1702c5SYu Xiangning 8690f1702c5SYu Xiangning switch (option_name) { 8700f1702c5SYu Xiangning case SO_TYPE: 8710f1702c5SYu Xiangning case SO_ERROR: 8720f1702c5SYu Xiangning case SO_ACCEPTCONN: 8730f1702c5SYu Xiangning /* Can't be set */ 8740f1702c5SYu Xiangning error = ENOPROTOOPT; 8750f1702c5SYu Xiangning goto done; 8760f1702c5SYu Xiangning case SO_LINGER: { 8770f1702c5SYu Xiangning struct linger *l = (struct linger *)optval; 8780f1702c5SYu Xiangning 8790f1702c5SYu Xiangning so->so_linger.l_linger = l->l_linger; 8800f1702c5SYu Xiangning if (l->l_onoff) { 8810f1702c5SYu Xiangning so->so_linger.l_onoff = SO_LINGER; 8820f1702c5SYu Xiangning so->so_options |= SO_LINGER; 8830f1702c5SYu Xiangning } else { 8840f1702c5SYu Xiangning so->so_linger.l_onoff = 0; 8850f1702c5SYu Xiangning so->so_options &= ~SO_LINGER; 8860f1702c5SYu Xiangning } 8870f1702c5SYu Xiangning break; 8880f1702c5SYu Xiangning } 8890f1702c5SYu Xiangning 8900f1702c5SYu Xiangning case SO_DEBUG: 8910f1702c5SYu Xiangning case SO_REUSEADDR: 8920f1702c5SYu Xiangning case SO_KEEPALIVE: 8930f1702c5SYu Xiangning case SO_DONTROUTE: 8940f1702c5SYu Xiangning case SO_BROADCAST: 8950f1702c5SYu Xiangning case SO_USELOOPBACK: 8960f1702c5SYu Xiangning case SO_OOBINLINE: 8970f1702c5SYu Xiangning case SO_DGRAM_ERRIND: 8980f1702c5SYu Xiangning if (intvalue != 0) { 8990f1702c5SYu Xiangning dprintso(so, 1, 9000f1702c5SYu Xiangning ("sosdp_setsockopt: setting 0x%x\n", 9010f1702c5SYu Xiangning option_name)); 9020f1702c5SYu Xiangning so->so_options |= option_name; 9030f1702c5SYu Xiangning } else { 9040f1702c5SYu Xiangning dprintso(so, 1, 9050f1702c5SYu Xiangning ("sosdp_setsockopt: clearing 0x%x\n", 9060f1702c5SYu Xiangning option_name)); 9070f1702c5SYu Xiangning so->so_options &= ~option_name; 9080f1702c5SYu Xiangning } 9090f1702c5SYu Xiangning break; 9100f1702c5SYu Xiangning 9110f1702c5SYu Xiangning case SO_SNDBUF: 9120f1702c5SYu Xiangning so->so_sndbuf = intvalue; 9130f1702c5SYu Xiangning if (so->so_sndlowat > so->so_sndbuf) { 9140f1702c5SYu Xiangning so->so_sndlowat = so->so_sndbuf; 9150f1702c5SYu Xiangning } 9160f1702c5SYu Xiangning break; 9170f1702c5SYu Xiangning case SO_RCVBUF: 9180f1702c5SYu Xiangning so->so_rcvbuf = intvalue; 9190f1702c5SYu Xiangning if (so->so_rcvlowat > so->so_rcvbuf) { 9200f1702c5SYu Xiangning so->so_rcvlowat = so->so_rcvbuf; 9210f1702c5SYu Xiangning } 9220f1702c5SYu Xiangning break; 9230f1702c5SYu Xiangning case SO_SNDLOWAT: 9240f1702c5SYu Xiangning if (so->so_sndlowat > so->so_sndbuf) { 9250f1702c5SYu Xiangning so->so_sndlowat = so->so_sndbuf; 9260f1702c5SYu Xiangning } 9270f1702c5SYu Xiangning break; 9280f1702c5SYu Xiangning case SO_RCVLOWAT: 9290f1702c5SYu Xiangning if (so->so_rcvlowat > so->so_rcvbuf) { 9300f1702c5SYu Xiangning so->so_rcvlowat = so->so_rcvbuf; 9310f1702c5SYu Xiangning } 9320f1702c5SYu Xiangning break; 9330f1702c5SYu Xiangning } 9340f1702c5SYu Xiangning #undef intvalue 9350f1702c5SYu Xiangning 9360f1702c5SYu Xiangning if (error != 0) { 9370f1702c5SYu Xiangning if ((error == ENOPROTOOPT || error == EPROTO || 9380f1702c5SYu Xiangning error == EINVAL) && handled) { 9390f1702c5SYu Xiangning dprintso(so, 1, 9400f1702c5SYu Xiangning ("sosdp_setsockopt: ignoring error %d " 9410f1702c5SYu Xiangning "for 0x%x\n", error, option_name)); 9420f1702c5SYu Xiangning error = 0; 9430f1702c5SYu Xiangning } 9440f1702c5SYu Xiangning } 9450f1702c5SYu Xiangning } 9460f1702c5SYu Xiangning 9470f1702c5SYu Xiangning done: 9480f1702c5SYu Xiangning so_unlock_single(so, SOLOCKED); 9490f1702c5SYu Xiangning mutex_exit(&so->so_lock); 9500f1702c5SYu Xiangning 9510f1702c5SYu Xiangning return (error); 9520f1702c5SYu Xiangning } 9530f1702c5SYu Xiangning 9540f1702c5SYu Xiangning /* ARGSUSED */ 9550f1702c5SYu Xiangning static int 9560f1702c5SYu Xiangning sosdp_ioctl(struct sonode *so, int cmd, intptr_t arg, int mode, 9570f1702c5SYu Xiangning struct cred *cr, int32_t *rvalp) 9580f1702c5SYu Xiangning { 9590f1702c5SYu Xiangning int32_t value; 9600f1702c5SYu Xiangning int error, intval; 9610f1702c5SYu Xiangning pid_t pid; 9620f1702c5SYu Xiangning 9630f1702c5SYu Xiangning /* handle socket specific ioctls */ 9640f1702c5SYu Xiangning switch (cmd) { 9650f1702c5SYu Xiangning case FIONBIO: 9660f1702c5SYu Xiangning if (so_copyin((void *)arg, &value, sizeof (int32_t), 9670f1702c5SYu Xiangning (mode & (int)FKIOCTL))) { 9680f1702c5SYu Xiangning return (EFAULT); 9690f1702c5SYu Xiangning } 9700f1702c5SYu Xiangning mutex_enter(&so->so_lock); 9710f1702c5SYu Xiangning if (value != 0) { 9720f1702c5SYu Xiangning so->so_state |= SS_NDELAY; 9730f1702c5SYu Xiangning } else { 9740f1702c5SYu Xiangning so->so_state &= ~SS_NDELAY; 9750f1702c5SYu Xiangning } 9760f1702c5SYu Xiangning mutex_exit(&so->so_lock); 9770f1702c5SYu Xiangning return (0); 9780f1702c5SYu Xiangning 9790f1702c5SYu Xiangning case FIOASYNC: 9800f1702c5SYu Xiangning if (so_copyin((void *)arg, &value, sizeof (int32_t), 9810f1702c5SYu Xiangning (mode & (int)FKIOCTL))) { 9820f1702c5SYu Xiangning return (EFAULT); 9830f1702c5SYu Xiangning } 9840f1702c5SYu Xiangning mutex_enter(&so->so_lock); 9850f1702c5SYu Xiangning 9860f1702c5SYu Xiangning if (value) { 9870f1702c5SYu Xiangning /* Turn on SIGIO */ 9880f1702c5SYu Xiangning so->so_state |= SS_ASYNC; 9890f1702c5SYu Xiangning } else { 9900f1702c5SYu Xiangning /* Turn off SIGIO */ 9910f1702c5SYu Xiangning so->so_state &= ~SS_ASYNC; 9920f1702c5SYu Xiangning } 9930f1702c5SYu Xiangning mutex_exit(&so->so_lock); 9940f1702c5SYu Xiangning return (0); 9950f1702c5SYu Xiangning 9960f1702c5SYu Xiangning case SIOCSPGRP: 9970f1702c5SYu Xiangning case FIOSETOWN: 9980f1702c5SYu Xiangning if (so_copyin((void *)arg, &pid, sizeof (pid_t), 9990f1702c5SYu Xiangning (mode & (int)FKIOCTL))) { 10000f1702c5SYu Xiangning return (EFAULT); 10010f1702c5SYu Xiangning } 10020f1702c5SYu Xiangning mutex_enter(&so->so_lock); 10030f1702c5SYu Xiangning 10040f1702c5SYu Xiangning error = (pid != so->so_pgrp) ? socket_chgpgrp(so, pid) : 0; 10050f1702c5SYu Xiangning mutex_exit(&so->so_lock); 10060f1702c5SYu Xiangning return (error); 10070f1702c5SYu Xiangning 10080f1702c5SYu Xiangning case SIOCGPGRP: 10090f1702c5SYu Xiangning case FIOGETOWN: 10100f1702c5SYu Xiangning if (so_copyout(&so->so_pgrp, (void *)arg, 10110f1702c5SYu Xiangning sizeof (pid_t), (mode & (int)FKIOCTL))) 10120f1702c5SYu Xiangning return (EFAULT); 10130f1702c5SYu Xiangning return (0); 10140f1702c5SYu Xiangning 10150f1702c5SYu Xiangning case SIOCATMARK: 10160f1702c5SYu Xiangning intval = 0; 10170f1702c5SYu Xiangning error = sdp_ioctl( 10180f1702c5SYu Xiangning (struct sdp_conn_struct_t *)so->so_proto_handle, cmd, 10190f1702c5SYu Xiangning &intval, cr); 10200f1702c5SYu Xiangning if (so_copyout(&intval, (void *)arg, sizeof (int), 10210f1702c5SYu Xiangning (mode & (int)FKIOCTL))) 10220f1702c5SYu Xiangning return (EFAULT); 10230f1702c5SYu Xiangning return (0); 10240f1702c5SYu Xiangning 10250f1702c5SYu Xiangning 10260f1702c5SYu Xiangning case SIOCSENABLESDP: { 10270f1702c5SYu Xiangning int32_t enable; 10280f1702c5SYu Xiangning 10290f1702c5SYu Xiangning /* 10300f1702c5SYu Xiangning * System wide enable SDP 10310f1702c5SYu Xiangning */ 10320f1702c5SYu Xiangning 10330f1702c5SYu Xiangning if (so_copyin((void *)arg, &enable, sizeof (int32_t), 10340f1702c5SYu Xiangning mode & (int)FKIOCTL)) 10350f1702c5SYu Xiangning return (EFAULT); 10360f1702c5SYu Xiangning 10370f1702c5SYu Xiangning error = sdp_ioctl( 10380f1702c5SYu Xiangning (struct sdp_conn_struct_t *)so->so_proto_handle, cmd, 10390f1702c5SYu Xiangning &enable, cr); 10400f1702c5SYu Xiangning if (so_copyout(&enable, (void *)arg, 10410f1702c5SYu Xiangning sizeof (int32_t), (mode & (int)FKIOCTL))) 10420f1702c5SYu Xiangning return (EFAULT); 10430f1702c5SYu Xiangning return (0); 10440f1702c5SYu Xiangning } 10450f1702c5SYu Xiangning /* from strioctl */ 10460f1702c5SYu Xiangning case FIONREAD: 10470f1702c5SYu Xiangning /* 10480f1702c5SYu Xiangning * Return number of bytes of data in all data messages 10490f1702c5SYu Xiangning * in queue in "arg". 10500f1702c5SYu Xiangning * For stream socket, amount of available data. 10510f1702c5SYu Xiangning */ 10520f1702c5SYu Xiangning if (so->so_state & SS_ACCEPTCONN) { 10530f1702c5SYu Xiangning intval = 0; 10540f1702c5SYu Xiangning } else { 10550f1702c5SYu Xiangning mutex_enter(&so->so_lock); 10560f1702c5SYu Xiangning intval = sdp_polldata( 10570f1702c5SYu Xiangning (struct sdp_conn_struct_t *)so->so_proto_handle, 10580f1702c5SYu Xiangning SDP_READ); 10590f1702c5SYu Xiangning mutex_exit(&so->so_lock); 10600f1702c5SYu Xiangning } 10610f1702c5SYu Xiangning if (so_copyout(&intval, (void *)arg, sizeof (intval), 10620f1702c5SYu Xiangning (mode & (int)FKIOCTL))) 10630f1702c5SYu Xiangning return (EFAULT); 10640f1702c5SYu Xiangning return (0); 10650f1702c5SYu Xiangning default: 10660f1702c5SYu Xiangning return (EINVAL); 10670f1702c5SYu Xiangning } 10680f1702c5SYu Xiangning } 10690f1702c5SYu Xiangning 10700f1702c5SYu Xiangning /* 10710f1702c5SYu Xiangning * Check socktpi_poll() on why so_lock is not held in this function. 10720f1702c5SYu Xiangning */ 10730f1702c5SYu Xiangning static int 10740f1702c5SYu Xiangning sosdp_poll(struct sonode *so, short events, int anyyet, short *reventsp, 10750f1702c5SYu Xiangning struct pollhead **phpp) 10760f1702c5SYu Xiangning { 10770f1702c5SYu Xiangning short origevents = events; 10780f1702c5SYu Xiangning int so_state; 10790f1702c5SYu Xiangning 10800f1702c5SYu Xiangning so_state = so->so_state; 10810f1702c5SYu Xiangning 10820f1702c5SYu Xiangning ASSERT(so->so_version != SOV_STREAM); 10830f1702c5SYu Xiangning 10840f1702c5SYu Xiangning if (!(so_state & SS_ISCONNECTED) && (so->so_type == SOCK_STREAM)) { 10850f1702c5SYu Xiangning /* 10860f1702c5SYu Xiangning * Not connected yet - turn off write side events 10870f1702c5SYu Xiangning */ 10880f1702c5SYu Xiangning events &= ~(POLLOUT|POLLWRBAND); 10890f1702c5SYu Xiangning } 10900f1702c5SYu Xiangning 10910f1702c5SYu Xiangning /* 10920f1702c5SYu Xiangning * Check for errors 10930f1702c5SYu Xiangning */ 10940f1702c5SYu Xiangning if (so->so_error != 0 && 10950f1702c5SYu Xiangning ((POLLIN|POLLRDNORM|POLLOUT) & origevents) != 0) { 10960f1702c5SYu Xiangning *reventsp = (POLLIN|POLLRDNORM|POLLOUT) & origevents; 10970f1702c5SYu Xiangning return (0); 10980f1702c5SYu Xiangning } 10990f1702c5SYu Xiangning 11000f1702c5SYu Xiangning *reventsp = 0; 11010f1702c5SYu Xiangning 11020f1702c5SYu Xiangning /* 11030f1702c5SYu Xiangning * Don't mark socket as writable until TX queued data is 11040f1702c5SYu Xiangning * below watermark. 11050f1702c5SYu Xiangning */ 11060f1702c5SYu Xiangning if (so->so_type == SOCK_STREAM) { 11070f1702c5SYu Xiangning if (sdp_polldata( 11080f1702c5SYu Xiangning (struct sdp_conn_struct_t *)so->so_proto_handle, 11090f1702c5SYu Xiangning SDP_XMIT)) { 11100f1702c5SYu Xiangning *reventsp |= POLLOUT & events; 11110f1702c5SYu Xiangning } 11120f1702c5SYu Xiangning } else { 11130f1702c5SYu Xiangning *reventsp = 0; 11140f1702c5SYu Xiangning goto done; 11150f1702c5SYu Xiangning } 11160f1702c5SYu Xiangning 11170f1702c5SYu Xiangning if (sdp_polldata((struct sdp_conn_struct_t *)so->so_proto_handle, 11180f1702c5SYu Xiangning SDP_READ)) { 11190f1702c5SYu Xiangning *reventsp |= (POLLIN|POLLRDNORM) & events; 11200f1702c5SYu Xiangning } 11210f1702c5SYu Xiangning 1122*3e95bd4aSAnders Persson if ((so_state & SS_CANTRCVMORE) || (so->so_acceptq_len > 0)) { 11230f1702c5SYu Xiangning *reventsp |= (POLLIN|POLLRDNORM) & events; 11240f1702c5SYu Xiangning } 11250f1702c5SYu Xiangning 11260f1702c5SYu Xiangning done: 11270f1702c5SYu Xiangning if (!*reventsp && !anyyet) { 11280f1702c5SYu Xiangning *phpp = &so->so_poll_list; 11290f1702c5SYu Xiangning } 11300f1702c5SYu Xiangning 11310f1702c5SYu Xiangning return (0); 11320f1702c5SYu Xiangning } 11330f1702c5SYu Xiangning 11340f1702c5SYu Xiangning /* ARGSUSED */ 11350f1702c5SYu Xiangning static int 11360f1702c5SYu Xiangning sosdp_close(struct sonode *so, int flag, struct cred *cr) 11370f1702c5SYu Xiangning { 11380f1702c5SYu Xiangning int error = 0; 11390f1702c5SYu Xiangning 11400f1702c5SYu Xiangning mutex_enter(&so->so_lock); 11410f1702c5SYu Xiangning so_lock_single(so); 11420f1702c5SYu Xiangning /* 11430f1702c5SYu Xiangning * Need to set flags as there might be ops in progress on 11440f1702c5SYu Xiangning * this socket. 11450f1702c5SYu Xiangning * 11460f1702c5SYu Xiangning * If socket already disconnected/disconnecting, 11470f1702c5SYu Xiangning * don't send signal (again). 11480f1702c5SYu Xiangning */ 11490f1702c5SYu Xiangning soisdisconnected(so, 0); 11500f1702c5SYu Xiangning mutex_exit(&so->so_lock); 11510f1702c5SYu Xiangning 11520f1702c5SYu Xiangning /* 11530f1702c5SYu Xiangning * Initiate connection shutdown. 11540f1702c5SYu Xiangning */ 11550f1702c5SYu Xiangning error = sdp_disconnect((struct sdp_conn_struct_t *)so->so_proto_handle, 11560f1702c5SYu Xiangning flag); 11570f1702c5SYu Xiangning 11580f1702c5SYu Xiangning mutex_enter(&so->so_lock); 11590f1702c5SYu Xiangning so_unlock_single(so, SOLOCKED); 1160*3e95bd4aSAnders Persson so_notify_disconnected(so, B_FALSE, error); 11610f1702c5SYu Xiangning 11620f1702c5SYu Xiangning return (error); 11630f1702c5SYu Xiangning } 11640f1702c5SYu Xiangning 11650f1702c5SYu Xiangning /* ARGSUSED */ 11660f1702c5SYu Xiangning void 11670f1702c5SYu Xiangning sosdp_fini(struct sonode *so, struct cred *cr) 11680f1702c5SYu Xiangning { 11690f1702c5SYu Xiangning dprint(3, ("sosdp_fini: so:%p so_proto_handle:%p", (void *)so, 11700f1702c5SYu Xiangning (void *)so->so_proto_handle)); 11710f1702c5SYu Xiangning 11720f1702c5SYu Xiangning ASSERT(so->so_ops == &sosdp_sonodeops); 11730f1702c5SYu Xiangning 11740f1702c5SYu Xiangning if (so->so_proto_handle != NULL) 11750f1702c5SYu Xiangning sdp_close((struct sdp_conn_struct_t *)so->so_proto_handle); 11760f1702c5SYu Xiangning so->so_proto_handle = NULL; 11770f1702c5SYu Xiangning 11780f1702c5SYu Xiangning mutex_enter(&so->so_lock); 11790f1702c5SYu Xiangning 11802320a8c1SAnders Persson so_acceptq_flush(so, B_TRUE); 11810f1702c5SYu Xiangning 11820f1702c5SYu Xiangning mutex_exit(&so->so_lock); 11830f1702c5SYu Xiangning 11840f1702c5SYu Xiangning sonode_fini(so); 11850f1702c5SYu Xiangning } 11860f1702c5SYu Xiangning 11870f1702c5SYu Xiangning /* 11880f1702c5SYu Xiangning * Upcalls from SDP 11890f1702c5SYu Xiangning */ 11900f1702c5SYu Xiangning 11910f1702c5SYu Xiangning /* 11920f1702c5SYu Xiangning * Incoming connection on listen socket. 11930f1702c5SYu Xiangning */ 11940f1702c5SYu Xiangning static void * 11950f1702c5SYu Xiangning sdp_sock_newconn(void *parenthandle, void *connind) 11960f1702c5SYu Xiangning { 11970f1702c5SYu Xiangning struct sonode *lso = parenthandle; 11980f1702c5SYu Xiangning struct sonode *nso; 11990f1702c5SYu Xiangning int error; 12000f1702c5SYu Xiangning 12010f1702c5SYu Xiangning ASSERT(lso->so_state & SS_ACCEPTCONN); 12020f1702c5SYu Xiangning ASSERT(lso->so_proto_handle != NULL); /* closed conn */ 12030f1702c5SYu Xiangning ASSERT(lso->so_type == SOCK_STREAM); 12040f1702c5SYu Xiangning 12050f1702c5SYu Xiangning dprint(3, ("sosdp_newconn A: so:%p so_proto_handle:%p", (void *)lso, 12060f1702c5SYu Xiangning (void *)lso->so_proto_handle)); 12070f1702c5SYu Xiangning 12080f1702c5SYu Xiangning /* 12090f1702c5SYu Xiangning * Check current # of queued conns against backlog 12100f1702c5SYu Xiangning */ 12110f1702c5SYu Xiangning if (lso->so_rcv_queued >= lso->so_backlog) { 12120f1702c5SYu Xiangning return (NULL); 12130f1702c5SYu Xiangning } 12140f1702c5SYu Xiangning 12150f1702c5SYu Xiangning nso = socket_newconn(lso, connind, NULL, SOCKET_NOSLEEP, &error); 12160f1702c5SYu Xiangning if (nso == NULL) { 12170f1702c5SYu Xiangning eprintsoline(lso, error); 12180f1702c5SYu Xiangning return (NULL); 12190f1702c5SYu Xiangning } 12200f1702c5SYu Xiangning 12210f1702c5SYu Xiangning dprint(2, ("sdp_stream_newconn: new %p\n", (void *)nso)); 12220f1702c5SYu Xiangning 12230f1702c5SYu Xiangning (void) so_acceptq_enqueue(lso, nso); 12240f1702c5SYu Xiangning 12250f1702c5SYu Xiangning mutex_enter(&lso->so_lock); 12260f1702c5SYu Xiangning so_notify_newconn(lso); 12270f1702c5SYu Xiangning return (nso); 12280f1702c5SYu Xiangning } 12290f1702c5SYu Xiangning 12300f1702c5SYu Xiangning /* 12310f1702c5SYu Xiangning * For outgoing connections, the connection has been established. 12320f1702c5SYu Xiangning */ 12330f1702c5SYu Xiangning static void 12340f1702c5SYu Xiangning sdp_sock_connected(void *handle) 12350f1702c5SYu Xiangning { 12360f1702c5SYu Xiangning struct sonode *so = handle; 12370f1702c5SYu Xiangning 12380f1702c5SYu Xiangning ASSERT(so->so_type == SOCK_STREAM); 12390f1702c5SYu Xiangning dprint(3, ("sosdp_connected C: so:%p so_proto_handle:%p", (void *)so, 12400f1702c5SYu Xiangning (void *)so->so_proto_handle)); 12410f1702c5SYu Xiangning 12420f1702c5SYu Xiangning mutex_enter(&so->so_lock); 12430f1702c5SYu Xiangning ASSERT(so->so_proto_handle); /* closed conn */ 12440f1702c5SYu Xiangning 12450f1702c5SYu Xiangning ASSERT(!(so->so_state & SS_ACCEPTCONN)); 12460f1702c5SYu Xiangning soisconnected(so); 12470f1702c5SYu Xiangning 12480f1702c5SYu Xiangning so_notify_connected(so); 12490f1702c5SYu Xiangning } 12500f1702c5SYu Xiangning 12510f1702c5SYu Xiangning /* 12520f1702c5SYu Xiangning * Connection got disconnected. Either with an error, or through 12530f1702c5SYu Xiangning * normal handshake. 12540f1702c5SYu Xiangning */ 12550f1702c5SYu Xiangning static void 12560f1702c5SYu Xiangning sdp_sock_disconnected(void *handle, int error) 12570f1702c5SYu Xiangning { 12580f1702c5SYu Xiangning struct sonode *so = handle; 12590f1702c5SYu Xiangning 12600f1702c5SYu Xiangning ASSERT(so->so_type == SOCK_STREAM); 12610f1702c5SYu Xiangning dprint(2, ("sosdp_disconnected C: so:%p so_proto_handle:%p error:%d", 12620f1702c5SYu Xiangning (void *)so, (void *)so->so_proto_handle, error)); 12630f1702c5SYu Xiangning 12640f1702c5SYu Xiangning mutex_enter(&so->so_lock); 12650f1702c5SYu Xiangning ASSERT(so->so_proto_handle != NULL); /* closed conn */ 12660f1702c5SYu Xiangning 12670f1702c5SYu Xiangning soisdisconnected(so, error); 1268*3e95bd4aSAnders Persson so_notify_disconnected(so, B_FALSE, error); 12690f1702c5SYu Xiangning } 12700f1702c5SYu Xiangning 12710f1702c5SYu Xiangning /* 12720f1702c5SYu Xiangning * Incoming data. 12730f1702c5SYu Xiangning */ 12740f1702c5SYu Xiangning /*ARGSUSED*/ 12750f1702c5SYu Xiangning static int 12760f1702c5SYu Xiangning sdp_sock_recv(void *handle, mblk_t *mp, int flags) 12770f1702c5SYu Xiangning { 12780f1702c5SYu Xiangning struct sonode *so = handle; 12790f1702c5SYu Xiangning 12800f1702c5SYu Xiangning ASSERT(so->so_type == SOCK_STREAM); 12810f1702c5SYu Xiangning 12820f1702c5SYu Xiangning mutex_enter(&so->so_lock); 12830f1702c5SYu Xiangning so_notify_data(so, 0); 12840f1702c5SYu Xiangning 12850f1702c5SYu Xiangning return (so->so_rcvbuf); 12860f1702c5SYu Xiangning } 12870f1702c5SYu Xiangning 12880f1702c5SYu Xiangning /* 12890f1702c5SYu Xiangning * TX queued data got acknowledged. 12900f1702c5SYu Xiangning */ 12910f1702c5SYu Xiangning static void 12920f1702c5SYu Xiangning sdp_sock_xmitted(void *handle, int writeable) 12930f1702c5SYu Xiangning { 12940f1702c5SYu Xiangning struct sonode *so = handle; 12950f1702c5SYu Xiangning 12960f1702c5SYu Xiangning dprint(4, ("sosdp_sock_xmitted: so:%p so_proto_handle:%p txq:%d", 12970f1702c5SYu Xiangning (void *)so, (void *)so->so_proto_handle, writeable)); 12980f1702c5SYu Xiangning mutex_enter(&so->so_lock); 12990f1702c5SYu Xiangning ASSERT(so->so_proto_handle != NULL); /* closed conn */ 13000f1702c5SYu Xiangning 13010f1702c5SYu Xiangning 13020f1702c5SYu Xiangning /* 13030f1702c5SYu Xiangning * Only do pollwakeup if the amount of queued data is less than 13040f1702c5SYu Xiangning * watermark. 13050f1702c5SYu Xiangning */ 13060f1702c5SYu Xiangning if (!writeable) { 13070f1702c5SYu Xiangning so_notify_writable(so); 13080f1702c5SYu Xiangning } else { 13090f1702c5SYu Xiangning mutex_exit(&so->so_lock); 13100f1702c5SYu Xiangning } 13110f1702c5SYu Xiangning } 13120f1702c5SYu Xiangning 13130f1702c5SYu Xiangning 13140f1702c5SYu Xiangning /* 13150f1702c5SYu Xiangning * SDP notifies socket for presence of urgent data. 13160f1702c5SYu Xiangning */ 13170f1702c5SYu Xiangning static void 13180f1702c5SYu Xiangning sdp_sock_urgdata(void *handle) 13190f1702c5SYu Xiangning { 13200f1702c5SYu Xiangning struct sonode *so = handle; 13210f1702c5SYu Xiangning 13220f1702c5SYu Xiangning ASSERT(so->so_type == SOCK_STREAM); 13230f1702c5SYu Xiangning 13240f1702c5SYu Xiangning mutex_enter(&so->so_lock); 13250f1702c5SYu Xiangning 13260f1702c5SYu Xiangning ASSERT(so->so_proto_handle != NULL); /* closed conn */ 13270f1702c5SYu Xiangning so_notify_oobsig(so); 13280f1702c5SYu Xiangning } 13290f1702c5SYu Xiangning 13300f1702c5SYu Xiangning /* 13310f1702c5SYu Xiangning * SDP notifies socket about receiving of conn close request from peer side. 13320f1702c5SYu Xiangning */ 13330f1702c5SYu Xiangning static void 13340f1702c5SYu Xiangning sdp_sock_ordrel(void *handle) 13350f1702c5SYu Xiangning { 13360f1702c5SYu Xiangning struct sonode *so = handle; 13370f1702c5SYu Xiangning 13380f1702c5SYu Xiangning ASSERT(so->so_type == SOCK_STREAM); 13390f1702c5SYu Xiangning 13400f1702c5SYu Xiangning dprint(4, ("sdp_sock_ordrel : so:%p, so_proto_handle:%p", 13410f1702c5SYu Xiangning (void *)so, (void *)so->so_proto_handle)); 13420f1702c5SYu Xiangning mutex_enter(&so->so_lock); 13430f1702c5SYu Xiangning socantrcvmore(so); 13440f1702c5SYu Xiangning so_notify_eof(so); 13450f1702c5SYu Xiangning } 13460f1702c5SYu Xiangning 13470f1702c5SYu Xiangning static void 13480f1702c5SYu Xiangning sdp_sock_connfail(void *handle, int error) 13490f1702c5SYu Xiangning { 13500f1702c5SYu Xiangning struct sonode *so = handle; 13510f1702c5SYu Xiangning 13520f1702c5SYu Xiangning dprint(3, ("sosdp_conn Failed: so:%p so_proto_handle:%p", (void *)so, 13530f1702c5SYu Xiangning (void *)so->so_proto_handle)); 13540f1702c5SYu Xiangning mutex_enter(&so->so_lock); 13550f1702c5SYu Xiangning ASSERT(so->so_proto_handle != NULL); /* closed conn */ 13560f1702c5SYu Xiangning so->so_state &= ~(SS_ISCONNECTING|SS_ISCONNECTED|SS_ISDISCONNECTING); 13570f1702c5SYu Xiangning so->so_error = (ushort_t)error; 13580f1702c5SYu Xiangning mutex_exit(&so->so_lock); 13590f1702c5SYu Xiangning cv_broadcast(&so->so_state_cv); 13600f1702c5SYu Xiangning } 1361