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 /*
23*12643SAnders.Persson@Sun.COM * Copyright (c) 2007, 2010, Oracle and/or its affiliates. All rights reserved.
248348SEric.Yu@Sun.COM */
258348SEric.Yu@Sun.COM
268348SEric.Yu@Sun.COM #include <sys/types.h>
278348SEric.Yu@Sun.COM #include <sys/t_lock.h>
288348SEric.Yu@Sun.COM #include <sys/param.h>
298348SEric.Yu@Sun.COM #include <sys/systm.h>
308348SEric.Yu@Sun.COM #include <sys/buf.h>
318348SEric.Yu@Sun.COM #include <sys/vfs.h>
328348SEric.Yu@Sun.COM #include <sys/vnode.h>
338348SEric.Yu@Sun.COM #include <sys/debug.h>
348348SEric.Yu@Sun.COM #include <sys/errno.h>
358348SEric.Yu@Sun.COM #include <sys/stropts.h>
368348SEric.Yu@Sun.COM #include <sys/cmn_err.h>
378348SEric.Yu@Sun.COM #include <sys/sysmacros.h>
3811537SCasper.Dik@Sun.COM #include <sys/policy.h>
398348SEric.Yu@Sun.COM
408348SEric.Yu@Sun.COM #include <sys/filio.h>
418348SEric.Yu@Sun.COM #include <sys/sockio.h>
428348SEric.Yu@Sun.COM
438348SEric.Yu@Sun.COM #include <sys/project.h>
448348SEric.Yu@Sun.COM #include <sys/tihdr.h>
458348SEric.Yu@Sun.COM #include <sys/strsubr.h>
468348SEric.Yu@Sun.COM
478348SEric.Yu@Sun.COM #include <sys/socket.h>
488348SEric.Yu@Sun.COM #include <sys/socketvar.h>
498348SEric.Yu@Sun.COM #include <sys/strsun.h>
508348SEric.Yu@Sun.COM
518348SEric.Yu@Sun.COM #include <sys/tsol/label.h>
528348SEric.Yu@Sun.COM
538348SEric.Yu@Sun.COM #include <inet/sdp_itf.h>
548348SEric.Yu@Sun.COM #include "socksdp.h"
558348SEric.Yu@Sun.COM #include <fs/sockfs/sockcommon.h>
568348SEric.Yu@Sun.COM
578348SEric.Yu@Sun.COM /*
588348SEric.Yu@Sun.COM * SDP sockfs sonode operations
598348SEric.Yu@Sun.COM */
608348SEric.Yu@Sun.COM static int sosdp_init(struct sonode *, struct sonode *, struct cred *, int);
618348SEric.Yu@Sun.COM static int sosdp_accept(struct sonode *, int, struct cred *, struct sonode **);
628348SEric.Yu@Sun.COM static int sosdp_bind(struct sonode *, struct sockaddr *, socklen_t, int,
638348SEric.Yu@Sun.COM struct cred *);
648348SEric.Yu@Sun.COM static int sosdp_listen(struct sonode *, int, struct cred *);
65*12643SAnders.Persson@Sun.COM static int sosdp_connect(struct sonode *, struct sockaddr *, socklen_t,
668348SEric.Yu@Sun.COM int, int, struct cred *);
678348SEric.Yu@Sun.COM static int sosdp_recvmsg(struct sonode *, struct nmsghdr *, struct uio *,
688348SEric.Yu@Sun.COM struct cred *);
698348SEric.Yu@Sun.COM static int sosdp_sendmsg(struct sonode *, struct nmsghdr *, struct uio *,
708348SEric.Yu@Sun.COM struct cred *);
718348SEric.Yu@Sun.COM static int sosdp_getpeername(struct sonode *, struct sockaddr *, socklen_t *,
728348SEric.Yu@Sun.COM boolean_t, struct cred *);
738348SEric.Yu@Sun.COM static int sosdp_getsockname(struct sonode *, struct sockaddr *, socklen_t *,
748348SEric.Yu@Sun.COM struct cred *);
758348SEric.Yu@Sun.COM static int sosdp_shutdown(struct sonode *, int, struct cred *);
768348SEric.Yu@Sun.COM static int sosdp_getsockopt(struct sonode *, int, int, void *, socklen_t *,
778348SEric.Yu@Sun.COM int, struct cred *);
788348SEric.Yu@Sun.COM static int sosdp_setsockopt(struct sonode *, int, int, const void *,
798348SEric.Yu@Sun.COM socklen_t, struct cred *);
808348SEric.Yu@Sun.COM static int sosdp_ioctl(struct sonode *, int, intptr_t, int, struct cred *,
818348SEric.Yu@Sun.COM int32_t *);
828348SEric.Yu@Sun.COM static int sosdp_poll(struct sonode *, short, int, short *,
838348SEric.Yu@Sun.COM struct pollhead **);
848348SEric.Yu@Sun.COM static int sosdp_close(struct sonode *, int, struct cred *);
858348SEric.Yu@Sun.COM void sosdp_fini(struct sonode *, struct cred *);
868348SEric.Yu@Sun.COM
878348SEric.Yu@Sun.COM
888348SEric.Yu@Sun.COM /*
898348SEric.Yu@Sun.COM * Socket upcalls
908348SEric.Yu@Sun.COM */
918348SEric.Yu@Sun.COM static void *sdp_sock_newconn(void *parenthandle, void *connind);
928348SEric.Yu@Sun.COM static void sdp_sock_connected(void *handle);
938348SEric.Yu@Sun.COM static void sdp_sock_disconnected(void *handle, int error);
948348SEric.Yu@Sun.COM static void sdp_sock_connfail(void *handle, int error);
958348SEric.Yu@Sun.COM static int sdp_sock_recv(void *handle, mblk_t *mp, int flags);
968348SEric.Yu@Sun.COM static void sdp_sock_xmitted(void *handle, int txqueued);
978348SEric.Yu@Sun.COM static void sdp_sock_urgdata(void *handle);
988348SEric.Yu@Sun.COM static void sdp_sock_ordrel(void *handle);
998348SEric.Yu@Sun.COM
1008348SEric.Yu@Sun.COM sonodeops_t sosdp_sonodeops = {
1018348SEric.Yu@Sun.COM sosdp_init, /* sop_init */
1028348SEric.Yu@Sun.COM sosdp_accept, /* sop_accept */
1038348SEric.Yu@Sun.COM sosdp_bind, /* sop_bind */
1048348SEric.Yu@Sun.COM sosdp_listen, /* sop_listen */
1058348SEric.Yu@Sun.COM sosdp_connect, /* sop_connect */
1068348SEric.Yu@Sun.COM sosdp_recvmsg, /* sop_recvmsg */
1078348SEric.Yu@Sun.COM sosdp_sendmsg, /* sop_sendmsg */
1088348SEric.Yu@Sun.COM so_sendmblk_notsupp, /* sop_sendmblk */
1098348SEric.Yu@Sun.COM sosdp_getpeername, /* sop_getpeername */
1108348SEric.Yu@Sun.COM sosdp_getsockname, /* sop_getsockname */
1118348SEric.Yu@Sun.COM sosdp_shutdown, /* sop_shutdown */
1128348SEric.Yu@Sun.COM sosdp_getsockopt, /* sop_getsockopt */
1138348SEric.Yu@Sun.COM sosdp_setsockopt, /* sop_setsockopt */
1148348SEric.Yu@Sun.COM sosdp_ioctl, /* sop_ioctl */
1158348SEric.Yu@Sun.COM sosdp_poll, /* sop_poll */
1168348SEric.Yu@Sun.COM sosdp_close, /* sop_close */
1178348SEric.Yu@Sun.COM };
1188348SEric.Yu@Sun.COM
1198348SEric.Yu@Sun.COM sdp_upcalls_t sosdp_sock_upcalls = {
1208348SEric.Yu@Sun.COM sdp_sock_newconn,
1218348SEric.Yu@Sun.COM sdp_sock_connected,
1228348SEric.Yu@Sun.COM sdp_sock_disconnected,
1238348SEric.Yu@Sun.COM sdp_sock_connfail,
1248348SEric.Yu@Sun.COM sdp_sock_recv,
1258348SEric.Yu@Sun.COM sdp_sock_xmitted,
1268348SEric.Yu@Sun.COM sdp_sock_urgdata,
1278348SEric.Yu@Sun.COM sdp_sock_ordrel,
1288348SEric.Yu@Sun.COM };
1298348SEric.Yu@Sun.COM
1308348SEric.Yu@Sun.COM /* ARGSUSED */
1318348SEric.Yu@Sun.COM static int
sosdp_init(struct sonode * so,struct sonode * pso,struct cred * cr,int flags)1328348SEric.Yu@Sun.COM sosdp_init(struct sonode *so, struct sonode *pso, struct cred *cr, int flags)
1338348SEric.Yu@Sun.COM {
1348348SEric.Yu@Sun.COM int error = 0;
1358348SEric.Yu@Sun.COM sdp_sockbuf_limits_t sbl;
1368348SEric.Yu@Sun.COM sdp_upcalls_t *upcalls;
1378348SEric.Yu@Sun.COM
1388348SEric.Yu@Sun.COM if (pso != NULL) {
1398348SEric.Yu@Sun.COM /* passive open, just inherit settings from parent */
1408348SEric.Yu@Sun.COM
1418348SEric.Yu@Sun.COM mutex_enter(&so->so_lock);
1428348SEric.Yu@Sun.COM
1438348SEric.Yu@Sun.COM so->so_state |= (SS_ISBOUND | SS_ISCONNECTED |
1448348SEric.Yu@Sun.COM (pso->so_state & SS_ASYNC));
1458348SEric.Yu@Sun.COM sosdp_so_inherit(pso, so);
1468348SEric.Yu@Sun.COM so->so_proto_props = pso->so_proto_props;
1478348SEric.Yu@Sun.COM
1488348SEric.Yu@Sun.COM mutex_exit(&so->so_lock);
1498348SEric.Yu@Sun.COM
1508348SEric.Yu@Sun.COM return (0);
1518348SEric.Yu@Sun.COM }
1528348SEric.Yu@Sun.COM
15311537SCasper.Dik@Sun.COM if ((error = secpolicy_basic_net_access(cr)) != 0)
15411537SCasper.Dik@Sun.COM return (error);
15511537SCasper.Dik@Sun.COM
1568348SEric.Yu@Sun.COM upcalls = &sosdp_sock_upcalls;
1578348SEric.Yu@Sun.COM
1588348SEric.Yu@Sun.COM so->so_proto_handle = (sock_lower_handle_t)sdp_create(so, NULL,
1598348SEric.Yu@Sun.COM so->so_family, SDP_CAN_BLOCK, upcalls, &sbl, cr, &error);
1608348SEric.Yu@Sun.COM if (so->so_proto_handle == NULL)
1618348SEric.Yu@Sun.COM return (ENOMEM);
1628348SEric.Yu@Sun.COM
1638348SEric.Yu@Sun.COM so->so_rcvbuf = sbl.sbl_rxbuf;
1648348SEric.Yu@Sun.COM so->so_rcvlowat = sbl.sbl_rxlowat;
1658348SEric.Yu@Sun.COM so->so_sndbuf = sbl.sbl_txbuf;
1668348SEric.Yu@Sun.COM so->so_sndlowat = sbl.sbl_txlowat;
1678348SEric.Yu@Sun.COM
1688348SEric.Yu@Sun.COM return (error);
1698348SEric.Yu@Sun.COM }
1708348SEric.Yu@Sun.COM
1718348SEric.Yu@Sun.COM /*
1728348SEric.Yu@Sun.COM * Accept incoming connection.
1738348SEric.Yu@Sun.COM */
1748348SEric.Yu@Sun.COM /* ARGSUSED */
1758348SEric.Yu@Sun.COM static int
sosdp_accept(struct sonode * lso,int fflag,struct cred * cr,struct sonode ** nsop)1768348SEric.Yu@Sun.COM sosdp_accept(struct sonode *lso, int fflag, struct cred *cr,
1778348SEric.Yu@Sun.COM struct sonode **nsop)
1788348SEric.Yu@Sun.COM {
1798348SEric.Yu@Sun.COM int error = 0;
1808348SEric.Yu@Sun.COM struct sonode *nso;
1818348SEric.Yu@Sun.COM
1828348SEric.Yu@Sun.COM dprint(3, ("sosdp_accept: so:%p so_proto_handle:%p", (void *)lso,
1838348SEric.Yu@Sun.COM (void *)lso->so_proto_handle));
1848348SEric.Yu@Sun.COM
1858348SEric.Yu@Sun.COM if (!(lso->so_state & SS_ACCEPTCONN)) {
1868348SEric.Yu@Sun.COM /*
1878348SEric.Yu@Sun.COM * Not a listen socket.
1888348SEric.Yu@Sun.COM */
1898348SEric.Yu@Sun.COM eprintsoline(lso, EINVAL);
1908348SEric.Yu@Sun.COM return (EINVAL);
1918348SEric.Yu@Sun.COM }
1928348SEric.Yu@Sun.COM /*
1938348SEric.Yu@Sun.COM * Returns right away if socket is nonblocking.
1948348SEric.Yu@Sun.COM */
1958348SEric.Yu@Sun.COM error = so_acceptq_dequeue(lso, (fflag & (FNONBLOCK|FNDELAY)), &nso);
1968348SEric.Yu@Sun.COM if (error != 0) {
1978348SEric.Yu@Sun.COM eprintsoline(lso, error);
1988348SEric.Yu@Sun.COM dprint(4, ("sosdp_accept: failed %d:lso:%p so_proto_handle:%p",
1998348SEric.Yu@Sun.COM error, (void *)lso, (void *)lso->so_proto_handle));
2008348SEric.Yu@Sun.COM return (error);
2018348SEric.Yu@Sun.COM }
2028348SEric.Yu@Sun.COM
2038348SEric.Yu@Sun.COM dprint(2, ("sosdp_accept: new %p\n", (void *)nso));
2048348SEric.Yu@Sun.COM *nsop = nso;
2058348SEric.Yu@Sun.COM
2068348SEric.Yu@Sun.COM return (0);
2078348SEric.Yu@Sun.COM }
2088348SEric.Yu@Sun.COM
2098348SEric.Yu@Sun.COM /*
2108348SEric.Yu@Sun.COM * Bind local endpoint.
2118348SEric.Yu@Sun.COM */
2128348SEric.Yu@Sun.COM /* ARGSUSED */
2138348SEric.Yu@Sun.COM int
sosdp_bind(struct sonode * so,struct sockaddr * name,socklen_t namelen,int flags,struct cred * cr)2148348SEric.Yu@Sun.COM sosdp_bind(struct sonode *so, struct sockaddr *name, socklen_t namelen,
2158348SEric.Yu@Sun.COM int flags, struct cred *cr)
2168348SEric.Yu@Sun.COM {
2178348SEric.Yu@Sun.COM int error = 0;
2188348SEric.Yu@Sun.COM
2198348SEric.Yu@Sun.COM if (!(flags & _SOBIND_LOCK_HELD)) {
2208348SEric.Yu@Sun.COM mutex_enter(&so->so_lock);
2218348SEric.Yu@Sun.COM so_lock_single(so); /* Set SOLOCKED */
2228348SEric.Yu@Sun.COM } else {
2238348SEric.Yu@Sun.COM ASSERT(MUTEX_HELD(&so->so_lock));
2248348SEric.Yu@Sun.COM ASSERT(so->so_flag & SOLOCKED);
2258348SEric.Yu@Sun.COM }
2268348SEric.Yu@Sun.COM
2278348SEric.Yu@Sun.COM if ((so->so_state & SS_ISBOUND) || name == NULL || namelen == 0) {
2288348SEric.Yu@Sun.COM /*
2298348SEric.Yu@Sun.COM * Multiple binds not allowed for any SDP socket.
2308348SEric.Yu@Sun.COM * Also binding with null address is not supported.
2318348SEric.Yu@Sun.COM */
2328348SEric.Yu@Sun.COM error = EINVAL;
2338348SEric.Yu@Sun.COM eprintsoline(so, error);
2348348SEric.Yu@Sun.COM goto done;
2358348SEric.Yu@Sun.COM }
2368348SEric.Yu@Sun.COM
2378348SEric.Yu@Sun.COM /*
2388348SEric.Yu@Sun.COM * X/Open requires this check
2398348SEric.Yu@Sun.COM */
2408348SEric.Yu@Sun.COM if (so->so_state & SS_CANTSENDMORE) {
2418348SEric.Yu@Sun.COM error = EINVAL;
2428348SEric.Yu@Sun.COM goto done;
2438348SEric.Yu@Sun.COM }
2448348SEric.Yu@Sun.COM
2458348SEric.Yu@Sun.COM /*
2468348SEric.Yu@Sun.COM * Protocol module does address family checks
2478348SEric.Yu@Sun.COM */
2488348SEric.Yu@Sun.COM mutex_exit(&so->so_lock);
2498348SEric.Yu@Sun.COM
2508348SEric.Yu@Sun.COM error = sdp_bind((struct sdp_conn_struct_t *)so->so_proto_handle,
2518348SEric.Yu@Sun.COM name, namelen);
2528348SEric.Yu@Sun.COM
2538348SEric.Yu@Sun.COM mutex_enter(&so->so_lock);
2548348SEric.Yu@Sun.COM
2558348SEric.Yu@Sun.COM if (error == 0) {
2568348SEric.Yu@Sun.COM so->so_state |= SS_ISBOUND;
2578348SEric.Yu@Sun.COM } else {
2588348SEric.Yu@Sun.COM eprintsoline(so, error);
2598348SEric.Yu@Sun.COM }
2608348SEric.Yu@Sun.COM done:
2618348SEric.Yu@Sun.COM if (!(flags & _SOBIND_LOCK_HELD)) {
2628348SEric.Yu@Sun.COM so_unlock_single(so, SOLOCKED);
2638348SEric.Yu@Sun.COM mutex_exit(&so->so_lock);
2648348SEric.Yu@Sun.COM } else {
2658348SEric.Yu@Sun.COM /* If the caller held the lock don't release it here */
2668348SEric.Yu@Sun.COM ASSERT(MUTEX_HELD(&so->so_lock));
2678348SEric.Yu@Sun.COM ASSERT(so->so_flag & SOLOCKED);
2688348SEric.Yu@Sun.COM }
2698348SEric.Yu@Sun.COM return (error);
2708348SEric.Yu@Sun.COM }
2718348SEric.Yu@Sun.COM
2728348SEric.Yu@Sun.COM /*
2738348SEric.Yu@Sun.COM * Turn socket into a listen socket.
2748348SEric.Yu@Sun.COM */
2758348SEric.Yu@Sun.COM /* ARGSUSED */
2768348SEric.Yu@Sun.COM static int
sosdp_listen(struct sonode * so,int backlog,struct cred * cr)2778348SEric.Yu@Sun.COM sosdp_listen(struct sonode *so, int backlog, struct cred *cr)
2788348SEric.Yu@Sun.COM {
2798348SEric.Yu@Sun.COM int error = 0;
2808348SEric.Yu@Sun.COM
2818348SEric.Yu@Sun.COM mutex_enter(&so->so_lock);
2828348SEric.Yu@Sun.COM so_lock_single(so);
2838348SEric.Yu@Sun.COM
2848348SEric.Yu@Sun.COM /*
2858348SEric.Yu@Sun.COM * If this socket is trying to do connect, or if it has
2868348SEric.Yu@Sun.COM * been connected, disallow.
2878348SEric.Yu@Sun.COM */
2888348SEric.Yu@Sun.COM if (so->so_state & (SS_ISCONNECTING | SS_ISCONNECTED |
2898348SEric.Yu@Sun.COM SS_ISDISCONNECTING | SS_CANTRCVMORE | SS_CANTSENDMORE)) {
2908348SEric.Yu@Sun.COM error = EINVAL;
2918348SEric.Yu@Sun.COM eprintsoline(so, EINVAL);
2928348SEric.Yu@Sun.COM goto done;
2938348SEric.Yu@Sun.COM }
2948348SEric.Yu@Sun.COM /*
2958348SEric.Yu@Sun.COM * If listen() is only called to change backlog, we don't
2968348SEric.Yu@Sun.COM * need to notify protocol module.
2978348SEric.Yu@Sun.COM */
2988348SEric.Yu@Sun.COM if (so->so_state & SS_ACCEPTCONN) {
2998348SEric.Yu@Sun.COM so->so_backlog = backlog;
3008348SEric.Yu@Sun.COM goto done;
3018348SEric.Yu@Sun.COM }
3028348SEric.Yu@Sun.COM
3038348SEric.Yu@Sun.COM mutex_exit(&so->so_lock);
3048348SEric.Yu@Sun.COM
3058348SEric.Yu@Sun.COM error = sdp_listen((struct sdp_conn_struct_t *)so->so_proto_handle,
3068348SEric.Yu@Sun.COM backlog);
3078348SEric.Yu@Sun.COM
3088348SEric.Yu@Sun.COM mutex_enter(&so->so_lock);
3098348SEric.Yu@Sun.COM if (error == 0) {
3108348SEric.Yu@Sun.COM so->so_state |= (SS_ACCEPTCONN | SS_ISBOUND);
3118348SEric.Yu@Sun.COM so->so_backlog = backlog;
3128348SEric.Yu@Sun.COM } else {
3138348SEric.Yu@Sun.COM eprintsoline(so, error);
3148348SEric.Yu@Sun.COM }
3158348SEric.Yu@Sun.COM done:
3168348SEric.Yu@Sun.COM so_unlock_single(so, SOLOCKED);
3178348SEric.Yu@Sun.COM mutex_exit(&so->so_lock);
3188348SEric.Yu@Sun.COM
3198348SEric.Yu@Sun.COM return (error);
3208348SEric.Yu@Sun.COM }
3218348SEric.Yu@Sun.COM
3228348SEric.Yu@Sun.COM /*
3238348SEric.Yu@Sun.COM * Active open.
3248348SEric.Yu@Sun.COM */
3258348SEric.Yu@Sun.COM /*ARGSUSED*/
3268348SEric.Yu@Sun.COM static int
sosdp_connect(struct sonode * so,struct sockaddr * name,socklen_t namelen,int fflag,int flags,struct cred * cr)327*12643SAnders.Persson@Sun.COM sosdp_connect(struct sonode *so, struct sockaddr *name,
3288348SEric.Yu@Sun.COM socklen_t namelen, int fflag, int flags, struct cred *cr)
3298348SEric.Yu@Sun.COM {
3308348SEric.Yu@Sun.COM int error = 0;
3318348SEric.Yu@Sun.COM
3328348SEric.Yu@Sun.COM mutex_enter(&so->so_lock);
3338348SEric.Yu@Sun.COM so_lock_single(so);
3348348SEric.Yu@Sun.COM
3358348SEric.Yu@Sun.COM /*
3368348SEric.Yu@Sun.COM * Can't connect() after listen(), or if the socket is already
3378348SEric.Yu@Sun.COM * connected.
3388348SEric.Yu@Sun.COM */
3398348SEric.Yu@Sun.COM if (so->so_state & (SS_ACCEPTCONN|SS_ISCONNECTED|SS_ISCONNECTING)) {
3408348SEric.Yu@Sun.COM if (so->so_state & SS_ISCONNECTED) {
3418348SEric.Yu@Sun.COM error = EISCONN;
3428348SEric.Yu@Sun.COM } else if (so->so_state & SS_ISCONNECTING) {
3438348SEric.Yu@Sun.COM error = EALREADY;
3448348SEric.Yu@Sun.COM } else {
3458348SEric.Yu@Sun.COM error = EOPNOTSUPP;
3468348SEric.Yu@Sun.COM }
3478348SEric.Yu@Sun.COM eprintsoline(so, error);
3488348SEric.Yu@Sun.COM goto done;
3498348SEric.Yu@Sun.COM }
3508348SEric.Yu@Sun.COM
3518348SEric.Yu@Sun.COM /*
3528348SEric.Yu@Sun.COM * check for failure of an earlier call
3538348SEric.Yu@Sun.COM */
3548348SEric.Yu@Sun.COM if (so->so_error != 0) {
3558348SEric.Yu@Sun.COM error = sogeterr(so, B_TRUE);
3568348SEric.Yu@Sun.COM eprintsoline(so, error);
3578348SEric.Yu@Sun.COM goto done;
3588348SEric.Yu@Sun.COM }
3598348SEric.Yu@Sun.COM
3608348SEric.Yu@Sun.COM /*
3618348SEric.Yu@Sun.COM * Connection is closing, or closed, don't allow reconnect.
3628348SEric.Yu@Sun.COM * TCP allows this to proceed, but the socket remains unwriteable.
3638348SEric.Yu@Sun.COM * BSD returns EINVAL.
3648348SEric.Yu@Sun.COM */
3658348SEric.Yu@Sun.COM if (so->so_state & (SS_ISDISCONNECTING|SS_CANTRCVMORE|
3668348SEric.Yu@Sun.COM SS_CANTSENDMORE)) {
3678348SEric.Yu@Sun.COM error = EINVAL;
3688348SEric.Yu@Sun.COM eprintsoline(so, error);
3698348SEric.Yu@Sun.COM goto done;
3708348SEric.Yu@Sun.COM }
3718348SEric.Yu@Sun.COM if (name == NULL || namelen == 0) {
3728348SEric.Yu@Sun.COM eprintsoline(so, EINVAL);
3738348SEric.Yu@Sun.COM goto done;
3748348SEric.Yu@Sun.COM }
3758348SEric.Yu@Sun.COM soisconnecting(so);
3768348SEric.Yu@Sun.COM mutex_exit(&so->so_lock);
3778348SEric.Yu@Sun.COM
3788348SEric.Yu@Sun.COM error = sdp_connect((struct sdp_conn_struct_t *)so->so_proto_handle,
3798348SEric.Yu@Sun.COM name, namelen);
3808348SEric.Yu@Sun.COM
3818348SEric.Yu@Sun.COM mutex_enter(&so->so_lock);
3828348SEric.Yu@Sun.COM if (error == 0) {
3838348SEric.Yu@Sun.COM /*
3848348SEric.Yu@Sun.COM * Allow other threads to access the socket
3858348SEric.Yu@Sun.COM */
3868348SEric.Yu@Sun.COM error = sowaitconnected(so, fflag, 0);
3878348SEric.Yu@Sun.COM dprint(4,
3888348SEric.Yu@Sun.COM ("sosdp_connect: wait on so:%p "
3898348SEric.Yu@Sun.COM "so_proto_handle:%p failed:%d",
3908348SEric.Yu@Sun.COM (void *)so, (void *)so->so_proto_handle, error));
3918348SEric.Yu@Sun.COM }
3928348SEric.Yu@Sun.COM
3938348SEric.Yu@Sun.COM switch (error) {
3948348SEric.Yu@Sun.COM case 0:
3958348SEric.Yu@Sun.COM case EINPROGRESS:
3968348SEric.Yu@Sun.COM case EALREADY:
3978348SEric.Yu@Sun.COM case EINTR:
3988348SEric.Yu@Sun.COM /* Non-fatal errors */
3998348SEric.Yu@Sun.COM so->so_state |= SS_ISBOUND;
4008348SEric.Yu@Sun.COM break;
4018348SEric.Yu@Sun.COM default:
4028348SEric.Yu@Sun.COM /* clear SS_ISCONNECTING in case it was set */
4038348SEric.Yu@Sun.COM so->so_state &= ~SS_ISCONNECTING;
4048348SEric.Yu@Sun.COM break;
4058348SEric.Yu@Sun.COM }
4068348SEric.Yu@Sun.COM done:
4078348SEric.Yu@Sun.COM so_unlock_single(so, SOLOCKED);
4088348SEric.Yu@Sun.COM mutex_exit(&so->so_lock);
4098348SEric.Yu@Sun.COM return (error);
4108348SEric.Yu@Sun.COM }
4118348SEric.Yu@Sun.COM
4128348SEric.Yu@Sun.COM /*
4138348SEric.Yu@Sun.COM * Receive data.
4148348SEric.Yu@Sun.COM */
4158348SEric.Yu@Sun.COM /* ARGSUSED */
4168348SEric.Yu@Sun.COM int
sosdp_recvmsg(struct sonode * so,struct nmsghdr * msg,struct uio * uiop,struct cred * cr)4178348SEric.Yu@Sun.COM sosdp_recvmsg(struct sonode *so, struct nmsghdr *msg, struct uio *uiop,
4188348SEric.Yu@Sun.COM struct cred *cr)
4198348SEric.Yu@Sun.COM {
4208348SEric.Yu@Sun.COM int flags, error = 0;
4218348SEric.Yu@Sun.COM int size;
4228348SEric.Yu@Sun.COM
4238348SEric.Yu@Sun.COM flags = msg->msg_flags;
4248348SEric.Yu@Sun.COM msg->msg_flags = 0;
4258348SEric.Yu@Sun.COM
4268348SEric.Yu@Sun.COM
4278348SEric.Yu@Sun.COM if (!(so->so_state & (SS_ISCONNECTED|SS_ISCONNECTING|
4288348SEric.Yu@Sun.COM SS_CANTRCVMORE))) {
4298348SEric.Yu@Sun.COM return (ENOTCONN);
4308348SEric.Yu@Sun.COM }
4318348SEric.Yu@Sun.COM
4328348SEric.Yu@Sun.COM /*
4338348SEric.Yu@Sun.COM * flag possibilities:
4348348SEric.Yu@Sun.COM *
4358348SEric.Yu@Sun.COM * MSG_PEEK Don't consume data
4368348SEric.Yu@Sun.COM * MSG_WAITALL Wait for full quantity of data (ignored if MSG_PEEK)
4378348SEric.Yu@Sun.COM * MSG_DONTWAIT Non-blocking (same as FNDELAY | FNONBLOCK)
4388348SEric.Yu@Sun.COM *
4398348SEric.Yu@Sun.COM * MSG_WAITALL can return less than the full buffer if either
4408348SEric.Yu@Sun.COM *
4418348SEric.Yu@Sun.COM * 1. we would block and we are non-blocking
4428348SEric.Yu@Sun.COM * 2. a full message cannot be delivered
4438348SEric.Yu@Sun.COM *
4448348SEric.Yu@Sun.COM */
4458348SEric.Yu@Sun.COM
4468348SEric.Yu@Sun.COM mutex_enter(&so->so_lock);
4478348SEric.Yu@Sun.COM
4488348SEric.Yu@Sun.COM /*
4498348SEric.Yu@Sun.COM * Allow just one reader at a time.
4508348SEric.Yu@Sun.COM */
4518348SEric.Yu@Sun.COM error = so_lock_read_intr(so,
4528348SEric.Yu@Sun.COM uiop->uio_fmode | ((flags & MSG_DONTWAIT) ? FNONBLOCK : 0));
4538348SEric.Yu@Sun.COM if (error != 0) {
4548348SEric.Yu@Sun.COM mutex_exit(&so->so_lock);
4558348SEric.Yu@Sun.COM return (error);
4568348SEric.Yu@Sun.COM }
4578348SEric.Yu@Sun.COM size = uiop->uio_resid;
4588348SEric.Yu@Sun.COM mutex_exit(&so->so_lock);
4598348SEric.Yu@Sun.COM
4608348SEric.Yu@Sun.COM if (!(so->so_state & SS_CANTRCVMORE)) {
4618348SEric.Yu@Sun.COM if (uiop->uio_fmode & (FNDELAY|FNONBLOCK)) {
4628348SEric.Yu@Sun.COM flags |= MSG_DONTWAIT;
4638348SEric.Yu@Sun.COM }
4648348SEric.Yu@Sun.COM error = sdp_recv(
4658348SEric.Yu@Sun.COM (struct sdp_conn_struct_t *)so->so_proto_handle, msg,
4668348SEric.Yu@Sun.COM size, flags, uiop);
4678348SEric.Yu@Sun.COM } else {
4688348SEric.Yu@Sun.COM msg->msg_controllen = 0;
4698348SEric.Yu@Sun.COM msg->msg_namelen = 0;
4708348SEric.Yu@Sun.COM }
4718348SEric.Yu@Sun.COM done:
4728348SEric.Yu@Sun.COM mutex_enter(&so->so_lock);
4738348SEric.Yu@Sun.COM so_unlock_read(so);
4748348SEric.Yu@Sun.COM mutex_exit(&so->so_lock);
4758348SEric.Yu@Sun.COM return (error);
4768348SEric.Yu@Sun.COM }
4778348SEric.Yu@Sun.COM
4788348SEric.Yu@Sun.COM /*
4798348SEric.Yu@Sun.COM * Send message.
4808348SEric.Yu@Sun.COM */
4818348SEric.Yu@Sun.COM /* ARGSUSED */
4828348SEric.Yu@Sun.COM static int
sosdp_sendmsg(struct sonode * so,struct nmsghdr * msg,struct uio * uiop,struct cred * cr)4838348SEric.Yu@Sun.COM sosdp_sendmsg(struct sonode *so, struct nmsghdr *msg, struct uio *uiop,
4848348SEric.Yu@Sun.COM struct cred *cr)
4858348SEric.Yu@Sun.COM {
4868348SEric.Yu@Sun.COM int flags;
4878348SEric.Yu@Sun.COM ssize_t count;
4888348SEric.Yu@Sun.COM int error;
4898348SEric.Yu@Sun.COM
4908348SEric.Yu@Sun.COM ASSERT(so->so_type == SOCK_STREAM);
4918348SEric.Yu@Sun.COM
4928348SEric.Yu@Sun.COM dprint(4, ("sosdp_sendmsg: so:%p so_proto_handle:%p",
4938348SEric.Yu@Sun.COM (void *)so, (void *)so->so_proto_handle));
4948348SEric.Yu@Sun.COM
4958348SEric.Yu@Sun.COM flags = msg->msg_flags;
4968348SEric.Yu@Sun.COM
4978348SEric.Yu@Sun.COM if (msg->msg_controllen != 0) {
4988348SEric.Yu@Sun.COM return (EOPNOTSUPP);
4998348SEric.Yu@Sun.COM }
5008348SEric.Yu@Sun.COM
5018348SEric.Yu@Sun.COM mutex_enter(&so->so_lock);
5028348SEric.Yu@Sun.COM if (so->so_state & SS_CANTSENDMORE) {
5038348SEric.Yu@Sun.COM mutex_exit(&so->so_lock);
5048348SEric.Yu@Sun.COM return (EPIPE);
5058348SEric.Yu@Sun.COM }
5068348SEric.Yu@Sun.COM
5078348SEric.Yu@Sun.COM if (so->so_error != 0) {
5088348SEric.Yu@Sun.COM error = sogeterr(so, B_TRUE);
5098348SEric.Yu@Sun.COM mutex_exit(&so->so_lock);
5108348SEric.Yu@Sun.COM return (error);
5118348SEric.Yu@Sun.COM }
5128348SEric.Yu@Sun.COM
5138348SEric.Yu@Sun.COM if (uiop->uio_fmode & (FNDELAY|FNONBLOCK))
5148348SEric.Yu@Sun.COM flags |= MSG_DONTWAIT;
5158348SEric.Yu@Sun.COM
5168348SEric.Yu@Sun.COM count = uiop->uio_resid;
5178348SEric.Yu@Sun.COM
5188348SEric.Yu@Sun.COM if (!(so->so_state & (SS_ISCONNECTING | SS_ISCONNECTED))) {
5198348SEric.Yu@Sun.COM dprint(4, ("sosdp_sendmsg: invalid state: <%x>",
5208348SEric.Yu@Sun.COM so->so_state));
5218348SEric.Yu@Sun.COM mutex_exit(&so->so_lock);
5228348SEric.Yu@Sun.COM return (ENOTCONN);
5238348SEric.Yu@Sun.COM }
5248348SEric.Yu@Sun.COM
5258348SEric.Yu@Sun.COM mutex_exit(&so->so_lock);
5268348SEric.Yu@Sun.COM error = sdp_send((struct sdp_conn_struct_t *)so->so_proto_handle,
5278348SEric.Yu@Sun.COM msg, count, flags, uiop);
5288348SEric.Yu@Sun.COM
5298348SEric.Yu@Sun.COM return (error);
5308348SEric.Yu@Sun.COM }
5318348SEric.Yu@Sun.COM
5328348SEric.Yu@Sun.COM /*
5338348SEric.Yu@Sun.COM * Get address of remote node.
5348348SEric.Yu@Sun.COM */
5358348SEric.Yu@Sun.COM /* ARGSUSED */
5368348SEric.Yu@Sun.COM static int
sosdp_getpeername(struct sonode * so,struct sockaddr * addr,socklen_t * addrlen,boolean_t accept,struct cred * cr)5378348SEric.Yu@Sun.COM sosdp_getpeername(struct sonode *so, struct sockaddr *addr, socklen_t *addrlen,
5388348SEric.Yu@Sun.COM boolean_t accept, struct cred *cr)
5398348SEric.Yu@Sun.COM {
5408348SEric.Yu@Sun.COM
5418348SEric.Yu@Sun.COM if (!accept && !(so->so_state & SS_ISCONNECTED)) {
5428348SEric.Yu@Sun.COM return (ENOTCONN);
5438348SEric.Yu@Sun.COM } else {
5448348SEric.Yu@Sun.COM return (sdp_getpeername(
5458348SEric.Yu@Sun.COM (struct sdp_conn_struct_t *)so->so_proto_handle,
5468348SEric.Yu@Sun.COM addr, addrlen));
5478348SEric.Yu@Sun.COM }
5488348SEric.Yu@Sun.COM }
5498348SEric.Yu@Sun.COM
5508348SEric.Yu@Sun.COM /*
5518348SEric.Yu@Sun.COM * Get local address.
5528348SEric.Yu@Sun.COM */
5538348SEric.Yu@Sun.COM /* ARGSUSED */
5548348SEric.Yu@Sun.COM static int
sosdp_getsockname(struct sonode * so,struct sockaddr * addr,socklen_t * addrlen,struct cred * cr)5558348SEric.Yu@Sun.COM sosdp_getsockname(struct sonode *so, struct sockaddr *addr, socklen_t *addrlen,
5568348SEric.Yu@Sun.COM struct cred *cr)
5578348SEric.Yu@Sun.COM {
5588348SEric.Yu@Sun.COM mutex_enter(&so->so_lock);
5598348SEric.Yu@Sun.COM
5608348SEric.Yu@Sun.COM if (!(so->so_state & SS_ISBOUND)) {
5618348SEric.Yu@Sun.COM /*
5628348SEric.Yu@Sun.COM * Zero address, except for address family
5638348SEric.Yu@Sun.COM */
5648348SEric.Yu@Sun.COM if (so->so_family == AF_INET || so->so_family == AF_INET6) {
5658348SEric.Yu@Sun.COM bzero(addr, *addrlen);
5668348SEric.Yu@Sun.COM *addrlen = (so->so_family == AF_INET6) ?
5678348SEric.Yu@Sun.COM sizeof (struct sockaddr_in6) :
5688348SEric.Yu@Sun.COM sizeof (struct sockaddr_in);
5698348SEric.Yu@Sun.COM addr->sa_family = so->so_family;
5708348SEric.Yu@Sun.COM }
5718348SEric.Yu@Sun.COM mutex_exit(&so->so_lock);
5728348SEric.Yu@Sun.COM return (0);
5738348SEric.Yu@Sun.COM } else {
5748348SEric.Yu@Sun.COM mutex_exit(&so->so_lock);
5758348SEric.Yu@Sun.COM return (sdp_getsockname(
5768348SEric.Yu@Sun.COM (struct sdp_conn_struct_t *)so->so_proto_handle,
5778348SEric.Yu@Sun.COM addr, addrlen));
5788348SEric.Yu@Sun.COM }
5798348SEric.Yu@Sun.COM }
5808348SEric.Yu@Sun.COM
5818348SEric.Yu@Sun.COM /*
5828348SEric.Yu@Sun.COM * Called from shutdown().
5838348SEric.Yu@Sun.COM */
5848348SEric.Yu@Sun.COM /* ARGSUSED */
5858348SEric.Yu@Sun.COM static int
sosdp_shutdown(struct sonode * so,int how,struct cred * cr)5868348SEric.Yu@Sun.COM sosdp_shutdown(struct sonode *so, int how, struct cred *cr)
5878348SEric.Yu@Sun.COM {
5888348SEric.Yu@Sun.COM uint_t state_change;
5898348SEric.Yu@Sun.COM int error = 0;
5908348SEric.Yu@Sun.COM
5918348SEric.Yu@Sun.COM mutex_enter(&so->so_lock);
5928348SEric.Yu@Sun.COM so_lock_single(so);
5938348SEric.Yu@Sun.COM /*
5948348SEric.Yu@Sun.COM * Record the current state and then perform any state changes.
5958348SEric.Yu@Sun.COM * Then use the difference between the old and new states to
5968348SEric.Yu@Sun.COM * determine which needs to be done.
5978348SEric.Yu@Sun.COM */
5988348SEric.Yu@Sun.COM state_change = so->so_state;
5998348SEric.Yu@Sun.COM if (!(state_change & SS_ISCONNECTED)) {
6008348SEric.Yu@Sun.COM error = ENOTCONN;
6018348SEric.Yu@Sun.COM goto done;
6028348SEric.Yu@Sun.COM }
6038348SEric.Yu@Sun.COM
6048348SEric.Yu@Sun.COM switch (how) {
6058348SEric.Yu@Sun.COM case SHUT_RD:
6068348SEric.Yu@Sun.COM socantrcvmore(so);
6078348SEric.Yu@Sun.COM break;
6088348SEric.Yu@Sun.COM case SHUT_WR:
6098348SEric.Yu@Sun.COM socantsendmore(so);
6108348SEric.Yu@Sun.COM break;
6118348SEric.Yu@Sun.COM case SHUT_RDWR:
6128348SEric.Yu@Sun.COM socantsendmore(so);
6138348SEric.Yu@Sun.COM socantrcvmore(so);
6148348SEric.Yu@Sun.COM break;
6158348SEric.Yu@Sun.COM default:
6168348SEric.Yu@Sun.COM error = EINVAL;
6178348SEric.Yu@Sun.COM goto done;
6188348SEric.Yu@Sun.COM }
6198348SEric.Yu@Sun.COM
6208348SEric.Yu@Sun.COM state_change = so->so_state & ~state_change;
6218348SEric.Yu@Sun.COM
6228348SEric.Yu@Sun.COM if (state_change & SS_CANTSENDMORE) {
6238348SEric.Yu@Sun.COM so->so_state |= SS_ISDISCONNECTING;
6248348SEric.Yu@Sun.COM }
6258348SEric.Yu@Sun.COM so_notify_shutdown(so);
6268348SEric.Yu@Sun.COM
6278348SEric.Yu@Sun.COM if (state_change & SS_CANTSENDMORE) {
6288348SEric.Yu@Sun.COM error = sdp_shutdown(
6298348SEric.Yu@Sun.COM (struct sdp_conn_struct_t *)so->so_proto_handle, how);
6308348SEric.Yu@Sun.COM }
6318348SEric.Yu@Sun.COM
6328348SEric.Yu@Sun.COM mutex_enter(&so->so_lock);
6338348SEric.Yu@Sun.COM done:
6348348SEric.Yu@Sun.COM so_unlock_single(so, SOLOCKED);
6358348SEric.Yu@Sun.COM mutex_exit(&so->so_lock);
6368348SEric.Yu@Sun.COM
6378348SEric.Yu@Sun.COM /*
6388348SEric.Yu@Sun.COM * HACK: sdp_disconnect() may return EWOULDBLOCK. But this error is
6398348SEric.Yu@Sun.COM * not documented in standard socket API. Catch it here.
6408348SEric.Yu@Sun.COM */
6418348SEric.Yu@Sun.COM if (error == EWOULDBLOCK)
6428348SEric.Yu@Sun.COM error = 0;
6438348SEric.Yu@Sun.COM return (error);
6448348SEric.Yu@Sun.COM }
6458348SEric.Yu@Sun.COM
6468348SEric.Yu@Sun.COM /*
6478348SEric.Yu@Sun.COM * Get socket options.
6488348SEric.Yu@Sun.COM */
6498348SEric.Yu@Sun.COM /*ARGSUSED*/
6508348SEric.Yu@Sun.COM static int
sosdp_getsockopt(struct sonode * so,int level,int option_name,void * optval,socklen_t * optlenp,int flags,struct cred * cr)6518348SEric.Yu@Sun.COM sosdp_getsockopt(struct sonode *so, int level, int option_name,
6528348SEric.Yu@Sun.COM void *optval, socklen_t *optlenp, int flags, struct cred *cr)
6538348SEric.Yu@Sun.COM {
6548348SEric.Yu@Sun.COM int error = 0;
6558348SEric.Yu@Sun.COM void *option = NULL;
6568348SEric.Yu@Sun.COM socklen_t maxlen = *optlenp, len, optlen;
6578348SEric.Yu@Sun.COM uint32_t value;
6588348SEric.Yu@Sun.COM uint8_t buffer[4];
6598348SEric.Yu@Sun.COM void *optbuf = &buffer;
6608348SEric.Yu@Sun.COM
6618348SEric.Yu@Sun.COM
6628348SEric.Yu@Sun.COM mutex_enter(&so->so_lock);
6638348SEric.Yu@Sun.COM
6648348SEric.Yu@Sun.COM if (level == SOL_SOCKET) {
6658348SEric.Yu@Sun.COM switch (option_name) {
6668348SEric.Yu@Sun.COM case SO_TYPE:
6678348SEric.Yu@Sun.COM case SO_ERROR:
6688348SEric.Yu@Sun.COM case SO_DEBUG:
6698348SEric.Yu@Sun.COM case SO_ACCEPTCONN:
6708348SEric.Yu@Sun.COM case SO_REUSEADDR:
6718348SEric.Yu@Sun.COM case SO_KEEPALIVE:
6728348SEric.Yu@Sun.COM case SO_DONTROUTE:
6738348SEric.Yu@Sun.COM case SO_BROADCAST:
6748348SEric.Yu@Sun.COM case SO_USELOOPBACK:
6758348SEric.Yu@Sun.COM case SO_OOBINLINE:
6768348SEric.Yu@Sun.COM case SO_SNDBUF:
6778348SEric.Yu@Sun.COM case SO_RCVBUF:
6788348SEric.Yu@Sun.COM case SO_SNDLOWAT:
6798348SEric.Yu@Sun.COM case SO_RCVLOWAT:
6808348SEric.Yu@Sun.COM case SO_DGRAM_ERRIND:
6818348SEric.Yu@Sun.COM if (maxlen < (t_uscalar_t)sizeof (int32_t)) {
6828348SEric.Yu@Sun.COM error = EINVAL;
6838348SEric.Yu@Sun.COM eprintsoline(so, error);
6848348SEric.Yu@Sun.COM goto done;
6858348SEric.Yu@Sun.COM }
6868348SEric.Yu@Sun.COM break;
6878348SEric.Yu@Sun.COM case SO_LINGER:
6888348SEric.Yu@Sun.COM if (maxlen < (t_uscalar_t)sizeof (struct linger)) {
6898348SEric.Yu@Sun.COM error = EINVAL;
6908348SEric.Yu@Sun.COM eprintsoline(so, error);
6918348SEric.Yu@Sun.COM goto done;
6928348SEric.Yu@Sun.COM }
6938348SEric.Yu@Sun.COM break;
6948348SEric.Yu@Sun.COM }
6958348SEric.Yu@Sun.COM len = (t_uscalar_t)sizeof (uint32_t); /* Default */
6968348SEric.Yu@Sun.COM option = &value;
6978348SEric.Yu@Sun.COM
6988348SEric.Yu@Sun.COM switch (option_name) {
6998348SEric.Yu@Sun.COM case SO_TYPE:
7008348SEric.Yu@Sun.COM value = so->so_type;
7018348SEric.Yu@Sun.COM goto copyout;
7028348SEric.Yu@Sun.COM
7038348SEric.Yu@Sun.COM case SO_ERROR:
7048348SEric.Yu@Sun.COM value = sogeterr(so, B_TRUE);
7058348SEric.Yu@Sun.COM goto copyout;
7068348SEric.Yu@Sun.COM
7078348SEric.Yu@Sun.COM case SO_ACCEPTCONN:
7088348SEric.Yu@Sun.COM value = (so->so_state & SS_ACCEPTCONN) ?
7098348SEric.Yu@Sun.COM SO_ACCEPTCONN : 0;
7108348SEric.Yu@Sun.COM goto copyout;
7118348SEric.Yu@Sun.COM
7128348SEric.Yu@Sun.COM case SO_DEBUG:
7138348SEric.Yu@Sun.COM case SO_REUSEADDR:
7148348SEric.Yu@Sun.COM case SO_KEEPALIVE:
7158348SEric.Yu@Sun.COM case SO_DONTROUTE:
7168348SEric.Yu@Sun.COM case SO_BROADCAST:
7178348SEric.Yu@Sun.COM case SO_USELOOPBACK:
7188348SEric.Yu@Sun.COM case SO_OOBINLINE:
7198348SEric.Yu@Sun.COM case SO_DGRAM_ERRIND:
7208348SEric.Yu@Sun.COM value = (so->so_options & option_name);
7218348SEric.Yu@Sun.COM goto copyout;
7228348SEric.Yu@Sun.COM
7238348SEric.Yu@Sun.COM /*
7248348SEric.Yu@Sun.COM * The following options are only returned by sockfs
7258348SEric.Yu@Sun.COM * when sdp_get_opt() fails.
7268348SEric.Yu@Sun.COM */
7278348SEric.Yu@Sun.COM
7288348SEric.Yu@Sun.COM case SO_LINGER:
7298348SEric.Yu@Sun.COM option = &so->so_linger;
7308348SEric.Yu@Sun.COM len = (t_uscalar_t)sizeof (struct linger);
7318348SEric.Yu@Sun.COM break;
7328348SEric.Yu@Sun.COM case SO_SNDBUF:
7338348SEric.Yu@Sun.COM value = so->so_sndbuf;
7348348SEric.Yu@Sun.COM len = (t_uscalar_t)sizeof (int);
7358348SEric.Yu@Sun.COM goto copyout;
7368348SEric.Yu@Sun.COM
7378348SEric.Yu@Sun.COM case SO_RCVBUF:
7388348SEric.Yu@Sun.COM value = so->so_rcvbuf;
7398348SEric.Yu@Sun.COM len = (t_uscalar_t)sizeof (int);
7408348SEric.Yu@Sun.COM goto copyout;
7418348SEric.Yu@Sun.COM
7428348SEric.Yu@Sun.COM case SO_SNDLOWAT:
7438348SEric.Yu@Sun.COM value = so->so_sndlowat;
7448348SEric.Yu@Sun.COM len = (t_uscalar_t)sizeof (int);
7458348SEric.Yu@Sun.COM goto copyout;
7468348SEric.Yu@Sun.COM
7478348SEric.Yu@Sun.COM case SO_RCVLOWAT:
7488348SEric.Yu@Sun.COM value = so->so_rcvlowat;
7498348SEric.Yu@Sun.COM len = (t_uscalar_t)sizeof (int);
7508348SEric.Yu@Sun.COM goto copyout;
7518348SEric.Yu@Sun.COM
7528348SEric.Yu@Sun.COM default:
7538348SEric.Yu@Sun.COM option = NULL;
7548348SEric.Yu@Sun.COM break;
7558348SEric.Yu@Sun.COM }
7568348SEric.Yu@Sun.COM }
7578348SEric.Yu@Sun.COM if (maxlen > sizeof (buffer)) {
7588348SEric.Yu@Sun.COM optbuf = kmem_alloc(maxlen, KM_SLEEP);
7598348SEric.Yu@Sun.COM }
7608348SEric.Yu@Sun.COM optlen = maxlen;
7618348SEric.Yu@Sun.COM mutex_exit(&so->so_lock);
7628348SEric.Yu@Sun.COM error = sdp_get_opt((struct sdp_conn_struct_t *)so->so_proto_handle,
7638348SEric.Yu@Sun.COM level, option_name, optbuf, &optlen);
7648348SEric.Yu@Sun.COM mutex_enter(&so->so_lock);
7658348SEric.Yu@Sun.COM ASSERT(optlen <= maxlen);
7668348SEric.Yu@Sun.COM if (error != 0) {
7678348SEric.Yu@Sun.COM if (option == NULL) {
7688348SEric.Yu@Sun.COM /* We have no fallback value */
7698348SEric.Yu@Sun.COM eprintsoline(so, error);
7708348SEric.Yu@Sun.COM goto free;
7718348SEric.Yu@Sun.COM }
7728348SEric.Yu@Sun.COM error = 0;
7738348SEric.Yu@Sun.COM goto copyout;
7748348SEric.Yu@Sun.COM }
7758348SEric.Yu@Sun.COM
7768348SEric.Yu@Sun.COM option = optbuf;
7778348SEric.Yu@Sun.COM len = optlen;
7788348SEric.Yu@Sun.COM
7798348SEric.Yu@Sun.COM copyout:
7808348SEric.Yu@Sun.COM len = MIN(len, maxlen);
7818348SEric.Yu@Sun.COM bcopy(option, optval, len);
7828348SEric.Yu@Sun.COM *optlenp = len;
7838348SEric.Yu@Sun.COM
7848348SEric.Yu@Sun.COM free:
7858348SEric.Yu@Sun.COM if (optbuf != &buffer) {
7868348SEric.Yu@Sun.COM kmem_free(optbuf, maxlen);
7878348SEric.Yu@Sun.COM }
7888348SEric.Yu@Sun.COM done:
7898348SEric.Yu@Sun.COM mutex_exit(&so->so_lock);
7908348SEric.Yu@Sun.COM return (error);
7918348SEric.Yu@Sun.COM }
7928348SEric.Yu@Sun.COM
7938348SEric.Yu@Sun.COM /*
7948348SEric.Yu@Sun.COM * Set socket options
7958348SEric.Yu@Sun.COM */
7968348SEric.Yu@Sun.COM /* ARGSUSED */
7978348SEric.Yu@Sun.COM static int
sosdp_setsockopt(struct sonode * so,int level,int option_name,const void * optval,t_uscalar_t optlen,struct cred * cr)7988348SEric.Yu@Sun.COM sosdp_setsockopt(struct sonode *so, int level, int option_name,
7998348SEric.Yu@Sun.COM const void *optval, t_uscalar_t optlen, struct cred *cr)
8008348SEric.Yu@Sun.COM {
8018348SEric.Yu@Sun.COM void *conn = NULL;
8028348SEric.Yu@Sun.COM int error = 0;
8038348SEric.Yu@Sun.COM
8048348SEric.Yu@Sun.COM if (so->so_state & SS_CANTSENDMORE) {
8058348SEric.Yu@Sun.COM return (EINVAL);
8068348SEric.Yu@Sun.COM }
8078348SEric.Yu@Sun.COM
8088348SEric.Yu@Sun.COM mutex_enter(&so->so_lock);
8098348SEric.Yu@Sun.COM so_lock_single(so);
8108348SEric.Yu@Sun.COM
8118348SEric.Yu@Sun.COM if (so->so_type == SOCK_STREAM) {
8128348SEric.Yu@Sun.COM conn = (void *)so->so_proto_handle;
8138348SEric.Yu@Sun.COM }
8148348SEric.Yu@Sun.COM
8158348SEric.Yu@Sun.COM dprint(2, ("sosdp_setsockopt (%d) - conn %p %d %d \n",
8168348SEric.Yu@Sun.COM so->so_type, conn, level, option_name));
8178348SEric.Yu@Sun.COM
8188348SEric.Yu@Sun.COM if (conn != NULL) {
8198348SEric.Yu@Sun.COM mutex_exit(&so->so_lock);
8208348SEric.Yu@Sun.COM error = sdp_set_opt((struct sdp_conn_struct_t *)conn, level,
8218348SEric.Yu@Sun.COM option_name, optval, optlen);
8228348SEric.Yu@Sun.COM mutex_enter(&so->so_lock);
8238348SEric.Yu@Sun.COM }
8248348SEric.Yu@Sun.COM
8258348SEric.Yu@Sun.COM /*
8268348SEric.Yu@Sun.COM * Check for SOL_SOCKET options and record their values.
8278348SEric.Yu@Sun.COM * If we know about a SOL_SOCKET parameter and the transport
8288348SEric.Yu@Sun.COM * failed it with TBADOPT or TOUTSTATE (i.e. ENOPROTOOPT or
8298348SEric.Yu@Sun.COM * EPROTO) we let the setsockopt succeed.
8308348SEric.Yu@Sun.COM */
8318348SEric.Yu@Sun.COM if (level == SOL_SOCKET) {
8328348SEric.Yu@Sun.COM boolean_t handled = B_FALSE;
8338348SEric.Yu@Sun.COM
8348348SEric.Yu@Sun.COM /* Check parameters */
8358348SEric.Yu@Sun.COM switch (option_name) {
8368348SEric.Yu@Sun.COM case SO_DEBUG:
8378348SEric.Yu@Sun.COM case SO_REUSEADDR:
8388348SEric.Yu@Sun.COM case SO_KEEPALIVE:
8398348SEric.Yu@Sun.COM case SO_DONTROUTE:
8408348SEric.Yu@Sun.COM case SO_BROADCAST:
8418348SEric.Yu@Sun.COM case SO_USELOOPBACK:
8428348SEric.Yu@Sun.COM case SO_OOBINLINE:
8438348SEric.Yu@Sun.COM case SO_SNDBUF:
8448348SEric.Yu@Sun.COM case SO_RCVBUF:
8458348SEric.Yu@Sun.COM case SO_SNDLOWAT:
8468348SEric.Yu@Sun.COM case SO_RCVLOWAT:
8478348SEric.Yu@Sun.COM case SO_DGRAM_ERRIND:
8488348SEric.Yu@Sun.COM if (optlen != (t_uscalar_t)sizeof (int32_t)) {
8498348SEric.Yu@Sun.COM error = EINVAL;
8508348SEric.Yu@Sun.COM eprintsoline(so, error);
8518348SEric.Yu@Sun.COM goto done;
8528348SEric.Yu@Sun.COM }
8538348SEric.Yu@Sun.COM ASSERT(optval);
8548348SEric.Yu@Sun.COM handled = B_TRUE;
8558348SEric.Yu@Sun.COM break;
8568348SEric.Yu@Sun.COM case SO_LINGER:
8578348SEric.Yu@Sun.COM if (optlen != (t_uscalar_t)sizeof (struct linger)) {
8588348SEric.Yu@Sun.COM error = EINVAL;
8598348SEric.Yu@Sun.COM eprintsoline(so, error);
8608348SEric.Yu@Sun.COM goto done;
8618348SEric.Yu@Sun.COM }
8628348SEric.Yu@Sun.COM ASSERT(optval);
8638348SEric.Yu@Sun.COM handled = B_TRUE;
8648348SEric.Yu@Sun.COM break;
8658348SEric.Yu@Sun.COM }
8668348SEric.Yu@Sun.COM
8678348SEric.Yu@Sun.COM #define intvalue (*(int32_t *)optval)
8688348SEric.Yu@Sun.COM
8698348SEric.Yu@Sun.COM switch (option_name) {
8708348SEric.Yu@Sun.COM case SO_TYPE:
8718348SEric.Yu@Sun.COM case SO_ERROR:
8728348SEric.Yu@Sun.COM case SO_ACCEPTCONN:
8738348SEric.Yu@Sun.COM /* Can't be set */
8748348SEric.Yu@Sun.COM error = ENOPROTOOPT;
8758348SEric.Yu@Sun.COM goto done;
8768348SEric.Yu@Sun.COM case SO_LINGER: {
8778348SEric.Yu@Sun.COM struct linger *l = (struct linger *)optval;
8788348SEric.Yu@Sun.COM
8798348SEric.Yu@Sun.COM so->so_linger.l_linger = l->l_linger;
8808348SEric.Yu@Sun.COM if (l->l_onoff) {
8818348SEric.Yu@Sun.COM so->so_linger.l_onoff = SO_LINGER;
8828348SEric.Yu@Sun.COM so->so_options |= SO_LINGER;
8838348SEric.Yu@Sun.COM } else {
8848348SEric.Yu@Sun.COM so->so_linger.l_onoff = 0;
8858348SEric.Yu@Sun.COM so->so_options &= ~SO_LINGER;
8868348SEric.Yu@Sun.COM }
8878348SEric.Yu@Sun.COM break;
8888348SEric.Yu@Sun.COM }
8898348SEric.Yu@Sun.COM
8908348SEric.Yu@Sun.COM case SO_DEBUG:
8918348SEric.Yu@Sun.COM case SO_REUSEADDR:
8928348SEric.Yu@Sun.COM case SO_KEEPALIVE:
8938348SEric.Yu@Sun.COM case SO_DONTROUTE:
8948348SEric.Yu@Sun.COM case SO_BROADCAST:
8958348SEric.Yu@Sun.COM case SO_USELOOPBACK:
8968348SEric.Yu@Sun.COM case SO_OOBINLINE:
8978348SEric.Yu@Sun.COM case SO_DGRAM_ERRIND:
8988348SEric.Yu@Sun.COM if (intvalue != 0) {
8998348SEric.Yu@Sun.COM dprintso(so, 1,
9008348SEric.Yu@Sun.COM ("sosdp_setsockopt: setting 0x%x\n",
9018348SEric.Yu@Sun.COM option_name));
9028348SEric.Yu@Sun.COM so->so_options |= option_name;
9038348SEric.Yu@Sun.COM } else {
9048348SEric.Yu@Sun.COM dprintso(so, 1,
9058348SEric.Yu@Sun.COM ("sosdp_setsockopt: clearing 0x%x\n",
9068348SEric.Yu@Sun.COM option_name));
9078348SEric.Yu@Sun.COM so->so_options &= ~option_name;
9088348SEric.Yu@Sun.COM }
9098348SEric.Yu@Sun.COM break;
9108348SEric.Yu@Sun.COM
9118348SEric.Yu@Sun.COM case SO_SNDBUF:
9128348SEric.Yu@Sun.COM so->so_sndbuf = intvalue;
9138348SEric.Yu@Sun.COM if (so->so_sndlowat > so->so_sndbuf) {
9148348SEric.Yu@Sun.COM so->so_sndlowat = so->so_sndbuf;
9158348SEric.Yu@Sun.COM }
9168348SEric.Yu@Sun.COM break;
9178348SEric.Yu@Sun.COM case SO_RCVBUF:
9188348SEric.Yu@Sun.COM so->so_rcvbuf = intvalue;
9198348SEric.Yu@Sun.COM if (so->so_rcvlowat > so->so_rcvbuf) {
9208348SEric.Yu@Sun.COM so->so_rcvlowat = so->so_rcvbuf;
9218348SEric.Yu@Sun.COM }
9228348SEric.Yu@Sun.COM break;
9238348SEric.Yu@Sun.COM case SO_SNDLOWAT:
9248348SEric.Yu@Sun.COM if (so->so_sndlowat > so->so_sndbuf) {
9258348SEric.Yu@Sun.COM so->so_sndlowat = so->so_sndbuf;
9268348SEric.Yu@Sun.COM }
9278348SEric.Yu@Sun.COM break;
9288348SEric.Yu@Sun.COM case SO_RCVLOWAT:
9298348SEric.Yu@Sun.COM if (so->so_rcvlowat > so->so_rcvbuf) {
9308348SEric.Yu@Sun.COM so->so_rcvlowat = so->so_rcvbuf;
9318348SEric.Yu@Sun.COM }
9328348SEric.Yu@Sun.COM break;
9338348SEric.Yu@Sun.COM }
9348348SEric.Yu@Sun.COM #undef intvalue
9358348SEric.Yu@Sun.COM
9368348SEric.Yu@Sun.COM if (error != 0) {
9378348SEric.Yu@Sun.COM if ((error == ENOPROTOOPT || error == EPROTO ||
9388348SEric.Yu@Sun.COM error == EINVAL) && handled) {
9398348SEric.Yu@Sun.COM dprintso(so, 1,
9408348SEric.Yu@Sun.COM ("sosdp_setsockopt: ignoring error %d "
9418348SEric.Yu@Sun.COM "for 0x%x\n", error, option_name));
9428348SEric.Yu@Sun.COM error = 0;
9438348SEric.Yu@Sun.COM }
9448348SEric.Yu@Sun.COM }
9458348SEric.Yu@Sun.COM }
9468348SEric.Yu@Sun.COM
9478348SEric.Yu@Sun.COM done:
9488348SEric.Yu@Sun.COM so_unlock_single(so, SOLOCKED);
9498348SEric.Yu@Sun.COM mutex_exit(&so->so_lock);
9508348SEric.Yu@Sun.COM
9518348SEric.Yu@Sun.COM return (error);
9528348SEric.Yu@Sun.COM }
9538348SEric.Yu@Sun.COM
9548348SEric.Yu@Sun.COM /* ARGSUSED */
9558348SEric.Yu@Sun.COM static int
sosdp_ioctl(struct sonode * so,int cmd,intptr_t arg,int mode,struct cred * cr,int32_t * rvalp)9568348SEric.Yu@Sun.COM sosdp_ioctl(struct sonode *so, int cmd, intptr_t arg, int mode,
9578348SEric.Yu@Sun.COM struct cred *cr, int32_t *rvalp)
9588348SEric.Yu@Sun.COM {
9598348SEric.Yu@Sun.COM int32_t value;
9608348SEric.Yu@Sun.COM int error, intval;
9618348SEric.Yu@Sun.COM pid_t pid;
9628348SEric.Yu@Sun.COM
9638348SEric.Yu@Sun.COM /* handle socket specific ioctls */
9648348SEric.Yu@Sun.COM switch (cmd) {
9658348SEric.Yu@Sun.COM case FIONBIO:
9668348SEric.Yu@Sun.COM if (so_copyin((void *)arg, &value, sizeof (int32_t),
9678348SEric.Yu@Sun.COM (mode & (int)FKIOCTL))) {
9688348SEric.Yu@Sun.COM return (EFAULT);
9698348SEric.Yu@Sun.COM }
9708348SEric.Yu@Sun.COM mutex_enter(&so->so_lock);
9718348SEric.Yu@Sun.COM if (value != 0) {
9728348SEric.Yu@Sun.COM so->so_state |= SS_NDELAY;
9738348SEric.Yu@Sun.COM } else {
9748348SEric.Yu@Sun.COM so->so_state &= ~SS_NDELAY;
9758348SEric.Yu@Sun.COM }
9768348SEric.Yu@Sun.COM mutex_exit(&so->so_lock);
9778348SEric.Yu@Sun.COM return (0);
9788348SEric.Yu@Sun.COM
9798348SEric.Yu@Sun.COM case FIOASYNC:
9808348SEric.Yu@Sun.COM if (so_copyin((void *)arg, &value, sizeof (int32_t),
9818348SEric.Yu@Sun.COM (mode & (int)FKIOCTL))) {
9828348SEric.Yu@Sun.COM return (EFAULT);
9838348SEric.Yu@Sun.COM }
9848348SEric.Yu@Sun.COM mutex_enter(&so->so_lock);
9858348SEric.Yu@Sun.COM
9868348SEric.Yu@Sun.COM if (value) {
9878348SEric.Yu@Sun.COM /* Turn on SIGIO */
9888348SEric.Yu@Sun.COM so->so_state |= SS_ASYNC;
9898348SEric.Yu@Sun.COM } else {
9908348SEric.Yu@Sun.COM /* Turn off SIGIO */
9918348SEric.Yu@Sun.COM so->so_state &= ~SS_ASYNC;
9928348SEric.Yu@Sun.COM }
9938348SEric.Yu@Sun.COM mutex_exit(&so->so_lock);
9948348SEric.Yu@Sun.COM return (0);
9958348SEric.Yu@Sun.COM
9968348SEric.Yu@Sun.COM case SIOCSPGRP:
9978348SEric.Yu@Sun.COM case FIOSETOWN:
9988348SEric.Yu@Sun.COM if (so_copyin((void *)arg, &pid, sizeof (pid_t),
9998348SEric.Yu@Sun.COM (mode & (int)FKIOCTL))) {
10008348SEric.Yu@Sun.COM return (EFAULT);
10018348SEric.Yu@Sun.COM }
10028348SEric.Yu@Sun.COM mutex_enter(&so->so_lock);
10038348SEric.Yu@Sun.COM
10048348SEric.Yu@Sun.COM error = (pid != so->so_pgrp) ? socket_chgpgrp(so, pid) : 0;
10058348SEric.Yu@Sun.COM mutex_exit(&so->so_lock);
10068348SEric.Yu@Sun.COM return (error);
10078348SEric.Yu@Sun.COM
10088348SEric.Yu@Sun.COM case SIOCGPGRP:
10098348SEric.Yu@Sun.COM case FIOGETOWN:
10108348SEric.Yu@Sun.COM if (so_copyout(&so->so_pgrp, (void *)arg,
10118348SEric.Yu@Sun.COM sizeof (pid_t), (mode & (int)FKIOCTL)))
10128348SEric.Yu@Sun.COM return (EFAULT);
10138348SEric.Yu@Sun.COM return (0);
10148348SEric.Yu@Sun.COM
10158348SEric.Yu@Sun.COM case SIOCATMARK:
10168348SEric.Yu@Sun.COM intval = 0;
10178348SEric.Yu@Sun.COM error = sdp_ioctl(
10188348SEric.Yu@Sun.COM (struct sdp_conn_struct_t *)so->so_proto_handle, cmd,
10198348SEric.Yu@Sun.COM &intval, cr);
10208348SEric.Yu@Sun.COM if (so_copyout(&intval, (void *)arg, sizeof (int),
10218348SEric.Yu@Sun.COM (mode & (int)FKIOCTL)))
10228348SEric.Yu@Sun.COM return (EFAULT);
10238348SEric.Yu@Sun.COM return (0);
10248348SEric.Yu@Sun.COM
10258348SEric.Yu@Sun.COM
10268348SEric.Yu@Sun.COM case SIOCSENABLESDP: {
10278348SEric.Yu@Sun.COM int32_t enable;
10288348SEric.Yu@Sun.COM
10298348SEric.Yu@Sun.COM /*
10308348SEric.Yu@Sun.COM * System wide enable SDP
10318348SEric.Yu@Sun.COM */
10328348SEric.Yu@Sun.COM
10338348SEric.Yu@Sun.COM if (so_copyin((void *)arg, &enable, sizeof (int32_t),
10348348SEric.Yu@Sun.COM mode & (int)FKIOCTL))
10358348SEric.Yu@Sun.COM return (EFAULT);
10368348SEric.Yu@Sun.COM
10378348SEric.Yu@Sun.COM error = sdp_ioctl(
10388348SEric.Yu@Sun.COM (struct sdp_conn_struct_t *)so->so_proto_handle, cmd,
10398348SEric.Yu@Sun.COM &enable, cr);
10408348SEric.Yu@Sun.COM if (so_copyout(&enable, (void *)arg,
10418348SEric.Yu@Sun.COM sizeof (int32_t), (mode & (int)FKIOCTL)))
10428348SEric.Yu@Sun.COM return (EFAULT);
10438348SEric.Yu@Sun.COM return (0);
10448348SEric.Yu@Sun.COM }
10458348SEric.Yu@Sun.COM /* from strioctl */
10468348SEric.Yu@Sun.COM case FIONREAD:
10478348SEric.Yu@Sun.COM /*
10488348SEric.Yu@Sun.COM * Return number of bytes of data in all data messages
10498348SEric.Yu@Sun.COM * in queue in "arg".
10508348SEric.Yu@Sun.COM * For stream socket, amount of available data.
10518348SEric.Yu@Sun.COM */
10528348SEric.Yu@Sun.COM if (so->so_state & SS_ACCEPTCONN) {
10538348SEric.Yu@Sun.COM intval = 0;
10548348SEric.Yu@Sun.COM } else {
10558348SEric.Yu@Sun.COM mutex_enter(&so->so_lock);
10568348SEric.Yu@Sun.COM intval = sdp_polldata(
10578348SEric.Yu@Sun.COM (struct sdp_conn_struct_t *)so->so_proto_handle,
10588348SEric.Yu@Sun.COM SDP_READ);
10598348SEric.Yu@Sun.COM mutex_exit(&so->so_lock);
10608348SEric.Yu@Sun.COM }
10618348SEric.Yu@Sun.COM if (so_copyout(&intval, (void *)arg, sizeof (intval),
10628348SEric.Yu@Sun.COM (mode & (int)FKIOCTL)))
10638348SEric.Yu@Sun.COM return (EFAULT);
10648348SEric.Yu@Sun.COM return (0);
10658348SEric.Yu@Sun.COM default:
10668348SEric.Yu@Sun.COM return (EINVAL);
10678348SEric.Yu@Sun.COM }
10688348SEric.Yu@Sun.COM }
10698348SEric.Yu@Sun.COM
10708348SEric.Yu@Sun.COM /*
10718348SEric.Yu@Sun.COM * Check socktpi_poll() on why so_lock is not held in this function.
10728348SEric.Yu@Sun.COM */
10738348SEric.Yu@Sun.COM static int
sosdp_poll(struct sonode * so,short events,int anyyet,short * reventsp,struct pollhead ** phpp)10748348SEric.Yu@Sun.COM sosdp_poll(struct sonode *so, short events, int anyyet, short *reventsp,
10758348SEric.Yu@Sun.COM struct pollhead **phpp)
10768348SEric.Yu@Sun.COM {
10778348SEric.Yu@Sun.COM short origevents = events;
10788348SEric.Yu@Sun.COM int so_state;
10798348SEric.Yu@Sun.COM
10808348SEric.Yu@Sun.COM so_state = so->so_state;
10818348SEric.Yu@Sun.COM
10828348SEric.Yu@Sun.COM ASSERT(so->so_version != SOV_STREAM);
10838348SEric.Yu@Sun.COM
10848348SEric.Yu@Sun.COM if (!(so_state & SS_ISCONNECTED) && (so->so_type == SOCK_STREAM)) {
10858348SEric.Yu@Sun.COM /*
10868348SEric.Yu@Sun.COM * Not connected yet - turn off write side events
10878348SEric.Yu@Sun.COM */
10888348SEric.Yu@Sun.COM events &= ~(POLLOUT|POLLWRBAND);
10898348SEric.Yu@Sun.COM }
10908348SEric.Yu@Sun.COM
10918348SEric.Yu@Sun.COM /*
10928348SEric.Yu@Sun.COM * Check for errors
10938348SEric.Yu@Sun.COM */
10948348SEric.Yu@Sun.COM if (so->so_error != 0 &&
10958348SEric.Yu@Sun.COM ((POLLIN|POLLRDNORM|POLLOUT) & origevents) != 0) {
10968348SEric.Yu@Sun.COM *reventsp = (POLLIN|POLLRDNORM|POLLOUT) & origevents;
10978348SEric.Yu@Sun.COM return (0);
10988348SEric.Yu@Sun.COM }
10998348SEric.Yu@Sun.COM
11008348SEric.Yu@Sun.COM *reventsp = 0;
11018348SEric.Yu@Sun.COM
11028348SEric.Yu@Sun.COM /*
11038348SEric.Yu@Sun.COM * Don't mark socket as writable until TX queued data is
11048348SEric.Yu@Sun.COM * below watermark.
11058348SEric.Yu@Sun.COM */
11068348SEric.Yu@Sun.COM if (so->so_type == SOCK_STREAM) {
11078348SEric.Yu@Sun.COM if (sdp_polldata(
11088348SEric.Yu@Sun.COM (struct sdp_conn_struct_t *)so->so_proto_handle,
11098348SEric.Yu@Sun.COM SDP_XMIT)) {
11108348SEric.Yu@Sun.COM *reventsp |= POLLOUT & events;
11118348SEric.Yu@Sun.COM }
11128348SEric.Yu@Sun.COM } else {
11138348SEric.Yu@Sun.COM *reventsp = 0;
11148348SEric.Yu@Sun.COM goto done;
11158348SEric.Yu@Sun.COM }
11168348SEric.Yu@Sun.COM
11178348SEric.Yu@Sun.COM if (sdp_polldata((struct sdp_conn_struct_t *)so->so_proto_handle,
11188348SEric.Yu@Sun.COM SDP_READ)) {
11198348SEric.Yu@Sun.COM *reventsp |= (POLLIN|POLLRDNORM) & events;
11208348SEric.Yu@Sun.COM }
11218348SEric.Yu@Sun.COM
1122*12643SAnders.Persson@Sun.COM if ((so_state & SS_CANTRCVMORE) || (so->so_acceptq_len > 0)) {
11238348SEric.Yu@Sun.COM *reventsp |= (POLLIN|POLLRDNORM) & events;
11248348SEric.Yu@Sun.COM }
11258348SEric.Yu@Sun.COM
11268348SEric.Yu@Sun.COM done:
11278348SEric.Yu@Sun.COM if (!*reventsp && !anyyet) {
11288348SEric.Yu@Sun.COM *phpp = &so->so_poll_list;
11298348SEric.Yu@Sun.COM }
11308348SEric.Yu@Sun.COM
11318348SEric.Yu@Sun.COM return (0);
11328348SEric.Yu@Sun.COM }
11338348SEric.Yu@Sun.COM
11348348SEric.Yu@Sun.COM /* ARGSUSED */
11358348SEric.Yu@Sun.COM static int
sosdp_close(struct sonode * so,int flag,struct cred * cr)11368348SEric.Yu@Sun.COM sosdp_close(struct sonode *so, int flag, struct cred *cr)
11378348SEric.Yu@Sun.COM {
11388348SEric.Yu@Sun.COM int error = 0;
11398348SEric.Yu@Sun.COM
11408348SEric.Yu@Sun.COM mutex_enter(&so->so_lock);
11418348SEric.Yu@Sun.COM so_lock_single(so);
11428348SEric.Yu@Sun.COM /*
11438348SEric.Yu@Sun.COM * Need to set flags as there might be ops in progress on
11448348SEric.Yu@Sun.COM * this socket.
11458348SEric.Yu@Sun.COM *
11468348SEric.Yu@Sun.COM * If socket already disconnected/disconnecting,
11478348SEric.Yu@Sun.COM * don't send signal (again).
11488348SEric.Yu@Sun.COM */
11498348SEric.Yu@Sun.COM soisdisconnected(so, 0);
11508348SEric.Yu@Sun.COM mutex_exit(&so->so_lock);
11518348SEric.Yu@Sun.COM
11528348SEric.Yu@Sun.COM /*
11538348SEric.Yu@Sun.COM * Initiate connection shutdown.
11548348SEric.Yu@Sun.COM */
11558348SEric.Yu@Sun.COM error = sdp_disconnect((struct sdp_conn_struct_t *)so->so_proto_handle,
11568348SEric.Yu@Sun.COM flag);
11578348SEric.Yu@Sun.COM
11588348SEric.Yu@Sun.COM mutex_enter(&so->so_lock);
11598348SEric.Yu@Sun.COM so_unlock_single(so, SOLOCKED);
1160*12643SAnders.Persson@Sun.COM so_notify_disconnected(so, B_FALSE, error);
11618348SEric.Yu@Sun.COM
11628348SEric.Yu@Sun.COM return (error);
11638348SEric.Yu@Sun.COM }
11648348SEric.Yu@Sun.COM
11658348SEric.Yu@Sun.COM /* ARGSUSED */
11668348SEric.Yu@Sun.COM void
sosdp_fini(struct sonode * so,struct cred * cr)11678348SEric.Yu@Sun.COM sosdp_fini(struct sonode *so, struct cred *cr)
11688348SEric.Yu@Sun.COM {
11698348SEric.Yu@Sun.COM dprint(3, ("sosdp_fini: so:%p so_proto_handle:%p", (void *)so,
11708348SEric.Yu@Sun.COM (void *)so->so_proto_handle));
11718348SEric.Yu@Sun.COM
11728348SEric.Yu@Sun.COM ASSERT(so->so_ops == &sosdp_sonodeops);
11738348SEric.Yu@Sun.COM
11748348SEric.Yu@Sun.COM if (so->so_proto_handle != NULL)
11758348SEric.Yu@Sun.COM sdp_close((struct sdp_conn_struct_t *)so->so_proto_handle);
11768348SEric.Yu@Sun.COM so->so_proto_handle = NULL;
11778348SEric.Yu@Sun.COM
11788348SEric.Yu@Sun.COM mutex_enter(&so->so_lock);
11798348SEric.Yu@Sun.COM
118010836SAnders.Persson@Sun.COM so_acceptq_flush(so, B_TRUE);
11818348SEric.Yu@Sun.COM
11828348SEric.Yu@Sun.COM mutex_exit(&so->so_lock);
11838348SEric.Yu@Sun.COM
11848348SEric.Yu@Sun.COM sonode_fini(so);
11858348SEric.Yu@Sun.COM }
11868348SEric.Yu@Sun.COM
11878348SEric.Yu@Sun.COM /*
11888348SEric.Yu@Sun.COM * Upcalls from SDP
11898348SEric.Yu@Sun.COM */
11908348SEric.Yu@Sun.COM
11918348SEric.Yu@Sun.COM /*
11928348SEric.Yu@Sun.COM * Incoming connection on listen socket.
11938348SEric.Yu@Sun.COM */
11948348SEric.Yu@Sun.COM static void *
sdp_sock_newconn(void * parenthandle,void * connind)11958348SEric.Yu@Sun.COM sdp_sock_newconn(void *parenthandle, void *connind)
11968348SEric.Yu@Sun.COM {
11978348SEric.Yu@Sun.COM struct sonode *lso = parenthandle;
11988348SEric.Yu@Sun.COM struct sonode *nso;
11998348SEric.Yu@Sun.COM int error;
12008348SEric.Yu@Sun.COM
12018348SEric.Yu@Sun.COM ASSERT(lso->so_state & SS_ACCEPTCONN);
12028348SEric.Yu@Sun.COM ASSERT(lso->so_proto_handle != NULL); /* closed conn */
12038348SEric.Yu@Sun.COM ASSERT(lso->so_type == SOCK_STREAM);
12048348SEric.Yu@Sun.COM
12058348SEric.Yu@Sun.COM dprint(3, ("sosdp_newconn A: so:%p so_proto_handle:%p", (void *)lso,
12068348SEric.Yu@Sun.COM (void *)lso->so_proto_handle));
12078348SEric.Yu@Sun.COM
12088348SEric.Yu@Sun.COM /*
12098348SEric.Yu@Sun.COM * Check current # of queued conns against backlog
12108348SEric.Yu@Sun.COM */
12118348SEric.Yu@Sun.COM if (lso->so_rcv_queued >= lso->so_backlog) {
12128348SEric.Yu@Sun.COM return (NULL);
12138348SEric.Yu@Sun.COM }
12148348SEric.Yu@Sun.COM
12158348SEric.Yu@Sun.COM nso = socket_newconn(lso, connind, NULL, SOCKET_NOSLEEP, &error);
12168348SEric.Yu@Sun.COM if (nso == NULL) {
12178348SEric.Yu@Sun.COM eprintsoline(lso, error);
12188348SEric.Yu@Sun.COM return (NULL);
12198348SEric.Yu@Sun.COM }
12208348SEric.Yu@Sun.COM
12218348SEric.Yu@Sun.COM dprint(2, ("sdp_stream_newconn: new %p\n", (void *)nso));
12228348SEric.Yu@Sun.COM
12238348SEric.Yu@Sun.COM (void) so_acceptq_enqueue(lso, nso);
12248348SEric.Yu@Sun.COM
12258348SEric.Yu@Sun.COM mutex_enter(&lso->so_lock);
12268348SEric.Yu@Sun.COM so_notify_newconn(lso);
12278348SEric.Yu@Sun.COM return (nso);
12288348SEric.Yu@Sun.COM }
12298348SEric.Yu@Sun.COM
12308348SEric.Yu@Sun.COM /*
12318348SEric.Yu@Sun.COM * For outgoing connections, the connection has been established.
12328348SEric.Yu@Sun.COM */
12338348SEric.Yu@Sun.COM static void
sdp_sock_connected(void * handle)12348348SEric.Yu@Sun.COM sdp_sock_connected(void *handle)
12358348SEric.Yu@Sun.COM {
12368348SEric.Yu@Sun.COM struct sonode *so = handle;
12378348SEric.Yu@Sun.COM
12388348SEric.Yu@Sun.COM ASSERT(so->so_type == SOCK_STREAM);
12398348SEric.Yu@Sun.COM dprint(3, ("sosdp_connected C: so:%p so_proto_handle:%p", (void *)so,
12408348SEric.Yu@Sun.COM (void *)so->so_proto_handle));
12418348SEric.Yu@Sun.COM
12428348SEric.Yu@Sun.COM mutex_enter(&so->so_lock);
12438348SEric.Yu@Sun.COM ASSERT(so->so_proto_handle); /* closed conn */
12448348SEric.Yu@Sun.COM
12458348SEric.Yu@Sun.COM ASSERT(!(so->so_state & SS_ACCEPTCONN));
12468348SEric.Yu@Sun.COM soisconnected(so);
12478348SEric.Yu@Sun.COM
12488348SEric.Yu@Sun.COM so_notify_connected(so);
12498348SEric.Yu@Sun.COM }
12508348SEric.Yu@Sun.COM
12518348SEric.Yu@Sun.COM /*
12528348SEric.Yu@Sun.COM * Connection got disconnected. Either with an error, or through
12538348SEric.Yu@Sun.COM * normal handshake.
12548348SEric.Yu@Sun.COM */
12558348SEric.Yu@Sun.COM static void
sdp_sock_disconnected(void * handle,int error)12568348SEric.Yu@Sun.COM sdp_sock_disconnected(void *handle, int error)
12578348SEric.Yu@Sun.COM {
12588348SEric.Yu@Sun.COM struct sonode *so = handle;
12598348SEric.Yu@Sun.COM
12608348SEric.Yu@Sun.COM ASSERT(so->so_type == SOCK_STREAM);
12618348SEric.Yu@Sun.COM dprint(2, ("sosdp_disconnected C: so:%p so_proto_handle:%p error:%d",
12628348SEric.Yu@Sun.COM (void *)so, (void *)so->so_proto_handle, error));
12638348SEric.Yu@Sun.COM
12648348SEric.Yu@Sun.COM mutex_enter(&so->so_lock);
12658348SEric.Yu@Sun.COM ASSERT(so->so_proto_handle != NULL); /* closed conn */
12668348SEric.Yu@Sun.COM
12678348SEric.Yu@Sun.COM soisdisconnected(so, error);
1268*12643SAnders.Persson@Sun.COM so_notify_disconnected(so, B_FALSE, error);
12698348SEric.Yu@Sun.COM }
12708348SEric.Yu@Sun.COM
12718348SEric.Yu@Sun.COM /*
12728348SEric.Yu@Sun.COM * Incoming data.
12738348SEric.Yu@Sun.COM */
12748348SEric.Yu@Sun.COM /*ARGSUSED*/
12758348SEric.Yu@Sun.COM static int
sdp_sock_recv(void * handle,mblk_t * mp,int flags)12768348SEric.Yu@Sun.COM sdp_sock_recv(void *handle, mblk_t *mp, int flags)
12778348SEric.Yu@Sun.COM {
12788348SEric.Yu@Sun.COM struct sonode *so = handle;
12798348SEric.Yu@Sun.COM
12808348SEric.Yu@Sun.COM ASSERT(so->so_type == SOCK_STREAM);
12818348SEric.Yu@Sun.COM
12828348SEric.Yu@Sun.COM mutex_enter(&so->so_lock);
12838348SEric.Yu@Sun.COM so_notify_data(so, 0);
12848348SEric.Yu@Sun.COM
12858348SEric.Yu@Sun.COM return (so->so_rcvbuf);
12868348SEric.Yu@Sun.COM }
12878348SEric.Yu@Sun.COM
12888348SEric.Yu@Sun.COM /*
12898348SEric.Yu@Sun.COM * TX queued data got acknowledged.
12908348SEric.Yu@Sun.COM */
12918348SEric.Yu@Sun.COM static void
sdp_sock_xmitted(void * handle,int writeable)12928348SEric.Yu@Sun.COM sdp_sock_xmitted(void *handle, int writeable)
12938348SEric.Yu@Sun.COM {
12948348SEric.Yu@Sun.COM struct sonode *so = handle;
12958348SEric.Yu@Sun.COM
12968348SEric.Yu@Sun.COM dprint(4, ("sosdp_sock_xmitted: so:%p so_proto_handle:%p txq:%d",
12978348SEric.Yu@Sun.COM (void *)so, (void *)so->so_proto_handle, writeable));
12988348SEric.Yu@Sun.COM mutex_enter(&so->so_lock);
12998348SEric.Yu@Sun.COM ASSERT(so->so_proto_handle != NULL); /* closed conn */
13008348SEric.Yu@Sun.COM
13018348SEric.Yu@Sun.COM
13028348SEric.Yu@Sun.COM /*
13038348SEric.Yu@Sun.COM * Only do pollwakeup if the amount of queued data is less than
13048348SEric.Yu@Sun.COM * watermark.
13058348SEric.Yu@Sun.COM */
13068348SEric.Yu@Sun.COM if (!writeable) {
13078348SEric.Yu@Sun.COM so_notify_writable(so);
13088348SEric.Yu@Sun.COM } else {
13098348SEric.Yu@Sun.COM mutex_exit(&so->so_lock);
13108348SEric.Yu@Sun.COM }
13118348SEric.Yu@Sun.COM }
13128348SEric.Yu@Sun.COM
13138348SEric.Yu@Sun.COM
13148348SEric.Yu@Sun.COM /*
13158348SEric.Yu@Sun.COM * SDP notifies socket for presence of urgent data.
13168348SEric.Yu@Sun.COM */
13178348SEric.Yu@Sun.COM static void
sdp_sock_urgdata(void * handle)13188348SEric.Yu@Sun.COM sdp_sock_urgdata(void *handle)
13198348SEric.Yu@Sun.COM {
13208348SEric.Yu@Sun.COM struct sonode *so = handle;
13218348SEric.Yu@Sun.COM
13228348SEric.Yu@Sun.COM ASSERT(so->so_type == SOCK_STREAM);
13238348SEric.Yu@Sun.COM
13248348SEric.Yu@Sun.COM mutex_enter(&so->so_lock);
13258348SEric.Yu@Sun.COM
13268348SEric.Yu@Sun.COM ASSERT(so->so_proto_handle != NULL); /* closed conn */
13278348SEric.Yu@Sun.COM so_notify_oobsig(so);
13288348SEric.Yu@Sun.COM }
13298348SEric.Yu@Sun.COM
13308348SEric.Yu@Sun.COM /*
13318348SEric.Yu@Sun.COM * SDP notifies socket about receiving of conn close request from peer side.
13328348SEric.Yu@Sun.COM */
13338348SEric.Yu@Sun.COM static void
sdp_sock_ordrel(void * handle)13348348SEric.Yu@Sun.COM sdp_sock_ordrel(void *handle)
13358348SEric.Yu@Sun.COM {
13368348SEric.Yu@Sun.COM struct sonode *so = handle;
13378348SEric.Yu@Sun.COM
13388348SEric.Yu@Sun.COM ASSERT(so->so_type == SOCK_STREAM);
13398348SEric.Yu@Sun.COM
13408348SEric.Yu@Sun.COM dprint(4, ("sdp_sock_ordrel : so:%p, so_proto_handle:%p",
13418348SEric.Yu@Sun.COM (void *)so, (void *)so->so_proto_handle));
13428348SEric.Yu@Sun.COM mutex_enter(&so->so_lock);
13438348SEric.Yu@Sun.COM socantrcvmore(so);
13448348SEric.Yu@Sun.COM so_notify_eof(so);
13458348SEric.Yu@Sun.COM }
13468348SEric.Yu@Sun.COM
13478348SEric.Yu@Sun.COM static void
sdp_sock_connfail(void * handle,int error)13488348SEric.Yu@Sun.COM sdp_sock_connfail(void *handle, int error)
13498348SEric.Yu@Sun.COM {
13508348SEric.Yu@Sun.COM struct sonode *so = handle;
13518348SEric.Yu@Sun.COM
13528348SEric.Yu@Sun.COM dprint(3, ("sosdp_conn Failed: so:%p so_proto_handle:%p", (void *)so,
13538348SEric.Yu@Sun.COM (void *)so->so_proto_handle));
13548348SEric.Yu@Sun.COM mutex_enter(&so->so_lock);
13558348SEric.Yu@Sun.COM ASSERT(so->so_proto_handle != NULL); /* closed conn */
13568348SEric.Yu@Sun.COM so->so_state &= ~(SS_ISCONNECTING|SS_ISCONNECTED|SS_ISDISCONNECTING);
13578348SEric.Yu@Sun.COM so->so_error = (ushort_t)error;
13588348SEric.Yu@Sun.COM mutex_exit(&so->so_lock);
13598348SEric.Yu@Sun.COM cv_broadcast(&so->so_state_cv);
13608348SEric.Yu@Sun.COM }
1361