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 /*
233e95bd4aSAnders Persson * Copyright (c) 2005, 2010, Oracle and/or its affiliates. All rights reserved.
24f62993d9SBryan Cantrill * Copyright (c) 2015 Joyent, Inc. All rights reserved.
25*78a2e113SAndy Fiddaman * Copyright 2019 OmniOS Community Edition (OmniOSce) Association.
260f1702c5SYu Xiangning */
270f1702c5SYu Xiangning
280f1702c5SYu Xiangning #include <sys/types.h>
290f1702c5SYu Xiangning #include <sys/t_lock.h>
300f1702c5SYu Xiangning #include <sys/param.h>
310f1702c5SYu Xiangning #include <sys/systm.h>
320f1702c5SYu Xiangning #include <sys/buf.h>
330f1702c5SYu Xiangning #include <sys/vfs.h>
340f1702c5SYu Xiangning #include <sys/vnode.h>
350f1702c5SYu Xiangning #include <sys/debug.h>
360f1702c5SYu Xiangning #include <sys/errno.h>
370f1702c5SYu Xiangning #include <sys/stropts.h>
380f1702c5SYu Xiangning #include <sys/cmn_err.h>
390f1702c5SYu Xiangning #include <sys/sysmacros.h>
400f1702c5SYu Xiangning #include <sys/filio.h>
41634e26ecSCasper H.S. Dik #include <sys/policy.h>
420f1702c5SYu Xiangning
430f1702c5SYu Xiangning #include <sys/project.h>
440f1702c5SYu Xiangning #include <sys/tihdr.h>
450f1702c5SYu Xiangning #include <sys/strsubr.h>
460f1702c5SYu Xiangning #include <sys/esunddi.h>
470f1702c5SYu Xiangning #include <sys/ddi.h>
480f1702c5SYu Xiangning
490f1702c5SYu Xiangning #include <sys/sockio.h>
500f1702c5SYu Xiangning #include <sys/socket.h>
510f1702c5SYu Xiangning #include <sys/socketvar.h>
520f1702c5SYu Xiangning #include <sys/strsun.h>
530f1702c5SYu Xiangning
540f1702c5SYu Xiangning #include <netinet/sctp.h>
550f1702c5SYu Xiangning #include <inet/sctp_itf.h>
560f1702c5SYu Xiangning #include <fs/sockfs/sockcommon.h>
570f1702c5SYu Xiangning #include "socksctp.h"
580f1702c5SYu Xiangning
590f1702c5SYu Xiangning /*
600f1702c5SYu Xiangning * SCTP sockfs sonode operations, 1-1 socket
610f1702c5SYu Xiangning */
620f1702c5SYu Xiangning static int sosctp_init(struct sonode *, struct sonode *, struct cred *, int);
630f1702c5SYu Xiangning static int sosctp_accept(struct sonode *, int, struct cred *, struct sonode **);
640f1702c5SYu Xiangning static int sosctp_bind(struct sonode *, struct sockaddr *, socklen_t, int,
650f1702c5SYu Xiangning struct cred *);
660f1702c5SYu Xiangning static int sosctp_listen(struct sonode *, int, struct cred *);
673e95bd4aSAnders Persson static int sosctp_connect(struct sonode *, struct sockaddr *, socklen_t,
680f1702c5SYu Xiangning int, int, struct cred *);
690f1702c5SYu Xiangning static int sosctp_recvmsg(struct sonode *, struct nmsghdr *, struct uio *,
700f1702c5SYu Xiangning struct cred *);
710f1702c5SYu Xiangning static int sosctp_sendmsg(struct sonode *, struct nmsghdr *, struct uio *,
720f1702c5SYu Xiangning struct cred *);
730f1702c5SYu Xiangning static int sosctp_getpeername(struct sonode *, struct sockaddr *, socklen_t *,
740f1702c5SYu Xiangning boolean_t, struct cred *);
750f1702c5SYu Xiangning static int sosctp_getsockname(struct sonode *, struct sockaddr *, socklen_t *,
760f1702c5SYu Xiangning struct cred *);
770f1702c5SYu Xiangning static int sosctp_shutdown(struct sonode *, int, struct cred *);
780f1702c5SYu Xiangning static int sosctp_getsockopt(struct sonode *, int, int, void *, socklen_t *,
790f1702c5SYu Xiangning int, struct cred *);
800f1702c5SYu Xiangning static int sosctp_setsockopt(struct sonode *, int, int, const void *,
810f1702c5SYu Xiangning socklen_t, struct cred *);
820f1702c5SYu Xiangning static int sosctp_ioctl(struct sonode *, int, intptr_t, int, struct cred *,
830f1702c5SYu Xiangning int32_t *);
840f1702c5SYu Xiangning static int sosctp_close(struct sonode *, int, struct cred *);
850f1702c5SYu Xiangning void sosctp_fini(struct sonode *, struct cred *);
860f1702c5SYu Xiangning
870f1702c5SYu Xiangning /*
880f1702c5SYu Xiangning * SCTP sockfs sonode operations, 1-N socket
890f1702c5SYu Xiangning */
903e95bd4aSAnders Persson static int sosctp_seq_connect(struct sonode *, struct sockaddr *,
910f1702c5SYu Xiangning socklen_t, int, int, struct cred *);
920f1702c5SYu Xiangning static int sosctp_seq_sendmsg(struct sonode *, struct nmsghdr *, struct uio *,
930f1702c5SYu Xiangning struct cred *);
940f1702c5SYu Xiangning
950f1702c5SYu Xiangning /*
960f1702c5SYu Xiangning * Socket association upcalls, 1-N socket connection
970f1702c5SYu Xiangning */
980f1702c5SYu Xiangning sock_upper_handle_t sctp_assoc_newconn(sock_upper_handle_t,
990f1702c5SYu Xiangning sock_lower_handle_t, sock_downcalls_t *, struct cred *, pid_t,
1000f1702c5SYu Xiangning sock_upcalls_t **);
1010f1702c5SYu Xiangning static void sctp_assoc_connected(sock_upper_handle_t, sock_connid_t,
1020f1702c5SYu Xiangning struct cred *, pid_t);
1030f1702c5SYu Xiangning static int sctp_assoc_disconnected(sock_upper_handle_t, sock_connid_t, int);
1040f1702c5SYu Xiangning static void sctp_assoc_disconnecting(sock_upper_handle_t, sock_opctl_action_t,
1050f1702c5SYu Xiangning uintptr_t arg);
1060f1702c5SYu Xiangning static ssize_t sctp_assoc_recv(sock_upper_handle_t, mblk_t *, size_t, int,
1070f1702c5SYu Xiangning int *, boolean_t *);
1080f1702c5SYu Xiangning static void sctp_assoc_xmitted(sock_upper_handle_t, boolean_t);
1090f1702c5SYu Xiangning static void sctp_assoc_properties(sock_upper_handle_t,
1100f1702c5SYu Xiangning struct sock_proto_props *);
111*78a2e113SAndy Fiddaman static vnode_t *sctp_assoc_get_vnode(sock_upper_handle_t);
1120f1702c5SYu Xiangning
1130f1702c5SYu Xiangning sonodeops_t sosctp_sonodeops = {
1140f1702c5SYu Xiangning sosctp_init, /* sop_init */
1150f1702c5SYu Xiangning sosctp_accept, /* sop_accept */
1160f1702c5SYu Xiangning sosctp_bind, /* sop_bind */
1170f1702c5SYu Xiangning sosctp_listen, /* sop_listen */
1180f1702c5SYu Xiangning sosctp_connect, /* sop_connect */
1190f1702c5SYu Xiangning sosctp_recvmsg, /* sop_recvmsg */
1200f1702c5SYu Xiangning sosctp_sendmsg, /* sop_sendmsg */
1210f1702c5SYu Xiangning so_sendmblk_notsupp, /* sop_sendmblk */
1220f1702c5SYu Xiangning sosctp_getpeername, /* sop_getpeername */
1230f1702c5SYu Xiangning sosctp_getsockname, /* sop_getsockname */
1240f1702c5SYu Xiangning sosctp_shutdown, /* sop_shutdown */
1250f1702c5SYu Xiangning sosctp_getsockopt, /* sop_getsockopt */
1260f1702c5SYu Xiangning sosctp_setsockopt, /* sop_setsockopt */
1270f1702c5SYu Xiangning sosctp_ioctl, /* sop_ioctl */
1280f1702c5SYu Xiangning so_poll, /* sop_poll */
129*78a2e113SAndy Fiddaman sosctp_close, /* sop_close */
1300f1702c5SYu Xiangning };
1310f1702c5SYu Xiangning
1320f1702c5SYu Xiangning sonodeops_t sosctp_seq_sonodeops = {
1330f1702c5SYu Xiangning sosctp_init, /* sop_init */
1340f1702c5SYu Xiangning so_accept_notsupp, /* sop_accept */
1350f1702c5SYu Xiangning sosctp_bind, /* sop_bind */
1360f1702c5SYu Xiangning sosctp_listen, /* sop_listen */
1370f1702c5SYu Xiangning sosctp_seq_connect, /* sop_connect */
1380f1702c5SYu Xiangning sosctp_recvmsg, /* sop_recvmsg */
1390f1702c5SYu Xiangning sosctp_seq_sendmsg, /* sop_sendmsg */
1400f1702c5SYu Xiangning so_sendmblk_notsupp, /* sop_sendmblk */
1410f1702c5SYu Xiangning so_getpeername_notsupp, /* sop_getpeername */
1420f1702c5SYu Xiangning sosctp_getsockname, /* sop_getsockname */
1430f1702c5SYu Xiangning so_shutdown_notsupp, /* sop_shutdown */
1440f1702c5SYu Xiangning sosctp_getsockopt, /* sop_getsockopt */
1450f1702c5SYu Xiangning sosctp_setsockopt, /* sop_setsockopt */
1460f1702c5SYu Xiangning sosctp_ioctl, /* sop_ioctl */
1470f1702c5SYu Xiangning so_poll, /* sop_poll */
148*78a2e113SAndy Fiddaman sosctp_close, /* sop_close */
1490f1702c5SYu Xiangning };
1500f1702c5SYu Xiangning
151a215d4ebSKacheong Poon /* All the upcalls expect the upper handle to be sonode. */
1520f1702c5SYu Xiangning sock_upcalls_t sosctp_sock_upcalls = {
1530f1702c5SYu Xiangning so_newconn,
1540f1702c5SYu Xiangning so_connected,
1550f1702c5SYu Xiangning so_disconnected,
1560f1702c5SYu Xiangning so_opctl,
1570f1702c5SYu Xiangning so_queue_msg,
1580f1702c5SYu Xiangning so_set_prop,
1590f1702c5SYu Xiangning so_txq_full,
1600f1702c5SYu Xiangning NULL, /* su_signal_oob */
161*78a2e113SAndy Fiddaman NULL, /* su_signal_oob */
162*78a2e113SAndy Fiddaman NULL, /* su_set_error */
163*78a2e113SAndy Fiddaman NULL, /* su_closed */
164*78a2e113SAndy Fiddaman so_get_vnode /* su_get_vnode */
1650f1702c5SYu Xiangning };
1660f1702c5SYu Xiangning
167a215d4ebSKacheong Poon /* All the upcalls expect the upper handle to be sctp_sonode/sctp_soassoc. */
1680f1702c5SYu Xiangning sock_upcalls_t sosctp_assoc_upcalls = {
1690f1702c5SYu Xiangning sctp_assoc_newconn,
1700f1702c5SYu Xiangning sctp_assoc_connected,
1710f1702c5SYu Xiangning sctp_assoc_disconnected,
1720f1702c5SYu Xiangning sctp_assoc_disconnecting,
1730f1702c5SYu Xiangning sctp_assoc_recv,
1740f1702c5SYu Xiangning sctp_assoc_properties,
1750f1702c5SYu Xiangning sctp_assoc_xmitted,
1760f1702c5SYu Xiangning NULL, /* su_recv_space */
1770f1702c5SYu Xiangning NULL, /* su_signal_oob */
178*78a2e113SAndy Fiddaman NULL, /* su_set_error */
179*78a2e113SAndy Fiddaman NULL, /* su_closed */
180*78a2e113SAndy Fiddaman sctp_assoc_get_vnode
1810f1702c5SYu Xiangning };
1820f1702c5SYu Xiangning
1830f1702c5SYu Xiangning /* ARGSUSED */
1840f1702c5SYu Xiangning static int
sosctp_init(struct sonode * so,struct sonode * pso,struct cred * cr,int flags)1850f1702c5SYu Xiangning sosctp_init(struct sonode *so, struct sonode *pso, struct cred *cr, int flags)
1860f1702c5SYu Xiangning {
1870f1702c5SYu Xiangning struct sctp_sonode *ss;
1880f1702c5SYu Xiangning struct sctp_sonode *pss;
1890f1702c5SYu Xiangning sctp_sockbuf_limits_t sbl;
190634e26ecSCasper H.S. Dik int err;
1910f1702c5SYu Xiangning
1920f1702c5SYu Xiangning ss = SOTOSSO(so);
1930f1702c5SYu Xiangning
1940f1702c5SYu Xiangning if (pso != NULL) {
1950f1702c5SYu Xiangning /*
1960f1702c5SYu Xiangning * Passive open, just inherit settings from parent. We should
1970f1702c5SYu Xiangning * not end up here for SOCK_SEQPACKET type sockets, since no
1980f1702c5SYu Xiangning * new sonode is created in that case.
1990f1702c5SYu Xiangning */
2000f1702c5SYu Xiangning ASSERT(so->so_type == SOCK_STREAM);
2010f1702c5SYu Xiangning pss = SOTOSSO(pso);
2020f1702c5SYu Xiangning
2030f1702c5SYu Xiangning mutex_enter(&pso->so_lock);
2040f1702c5SYu Xiangning so->so_state |= (SS_ISBOUND | SS_ISCONNECTED |
2050f1702c5SYu Xiangning (pso->so_state & SS_ASYNC));
2060f1702c5SYu Xiangning sosctp_so_inherit(pss, ss);
2070f1702c5SYu Xiangning so->so_proto_props = pso->so_proto_props;
2080f1702c5SYu Xiangning so->so_mode = pso->so_mode;
2090f1702c5SYu Xiangning mutex_exit(&pso->so_lock);
2100f1702c5SYu Xiangning
2110f1702c5SYu Xiangning return (0);
2120f1702c5SYu Xiangning }
2130f1702c5SYu Xiangning
214a215d4ebSKacheong Poon if ((err = secpolicy_basic_net_access(cr)) != 0)
215a215d4ebSKacheong Poon return (err);
216a215d4ebSKacheong Poon
2170f1702c5SYu Xiangning if (so->so_type == SOCK_STREAM) {
218a215d4ebSKacheong Poon so->so_proto_handle = (sock_lower_handle_t)sctp_create(so,
219a215d4ebSKacheong Poon NULL, so->so_family, so->so_type, SCTP_CAN_BLOCK,
220a215d4ebSKacheong Poon &sosctp_sock_upcalls, &sbl, cr);
2210f1702c5SYu Xiangning so->so_mode = SM_CONNREQUIRED;
2220f1702c5SYu Xiangning } else {
2230f1702c5SYu Xiangning ASSERT(so->so_type == SOCK_SEQPACKET);
224a215d4ebSKacheong Poon so->so_proto_handle = (sock_lower_handle_t)sctp_create(ss,
225a215d4ebSKacheong Poon NULL, so->so_family, so->so_type, SCTP_CAN_BLOCK,
226a215d4ebSKacheong Poon &sosctp_assoc_upcalls, &sbl, cr);
2270f1702c5SYu Xiangning }
228634e26ecSCasper H.S. Dik
2290f1702c5SYu Xiangning if (so->so_proto_handle == NULL)
2300f1702c5SYu Xiangning return (ENOMEM);
2310f1702c5SYu Xiangning
2320f1702c5SYu Xiangning so->so_rcvbuf = sbl.sbl_rxbuf;
2330f1702c5SYu Xiangning so->so_rcvlowat = sbl.sbl_rxlowat;
2340f1702c5SYu Xiangning so->so_sndbuf = sbl.sbl_txbuf;
2350f1702c5SYu Xiangning so->so_sndlowat = sbl.sbl_txlowat;
2360f1702c5SYu Xiangning
2370f1702c5SYu Xiangning return (0);
2380f1702c5SYu Xiangning }
2390f1702c5SYu Xiangning
2400f1702c5SYu Xiangning /*
2410f1702c5SYu Xiangning * Accept incoming connection.
2420f1702c5SYu Xiangning */
2430f1702c5SYu Xiangning /*ARGSUSED*/
2440f1702c5SYu Xiangning static int
sosctp_accept(struct sonode * so,int fflag,struct cred * cr,struct sonode ** nsop)2450f1702c5SYu Xiangning sosctp_accept(struct sonode *so, int fflag, struct cred *cr,
2460f1702c5SYu Xiangning struct sonode **nsop)
2470f1702c5SYu Xiangning {
2480f1702c5SYu Xiangning int error = 0;
2490f1702c5SYu Xiangning
2500f1702c5SYu Xiangning if ((so->so_state & SS_ACCEPTCONN) == 0)
2510f1702c5SYu Xiangning return (EINVAL);
2520f1702c5SYu Xiangning
2530f1702c5SYu Xiangning error = so_acceptq_dequeue(so, (fflag & (FNONBLOCK|FNDELAY)), nsop);
2540f1702c5SYu Xiangning
2550f1702c5SYu Xiangning return (error);
2560f1702c5SYu Xiangning }
2570f1702c5SYu Xiangning
2580f1702c5SYu Xiangning /*
2590f1702c5SYu Xiangning * Bind local endpoint.
2600f1702c5SYu Xiangning */
2610f1702c5SYu Xiangning /*ARGSUSED*/
2620f1702c5SYu Xiangning static int
sosctp_bind(struct sonode * so,struct sockaddr * name,socklen_t namelen,int flags,struct cred * cr)2630f1702c5SYu Xiangning sosctp_bind(struct sonode *so, struct sockaddr *name, socklen_t namelen,
2640f1702c5SYu Xiangning int flags, struct cred *cr)
2650f1702c5SYu Xiangning {
2660f1702c5SYu Xiangning int error;
2670f1702c5SYu Xiangning
2680f1702c5SYu Xiangning if (!(flags & _SOBIND_LOCK_HELD)) {
2690f1702c5SYu Xiangning mutex_enter(&so->so_lock);
2700f1702c5SYu Xiangning so_lock_single(so); /* Set SOLOCKED */
2710f1702c5SYu Xiangning } else {
2720f1702c5SYu Xiangning ASSERT(MUTEX_HELD(&so->so_lock));
2730f1702c5SYu Xiangning }
2740f1702c5SYu Xiangning
2750f1702c5SYu Xiangning /*
2760f1702c5SYu Xiangning * X/Open requires this check
2770f1702c5SYu Xiangning */
2780f1702c5SYu Xiangning if (so->so_state & SS_CANTSENDMORE) {
2790f1702c5SYu Xiangning error = EINVAL;
2800f1702c5SYu Xiangning goto done;
2810f1702c5SYu Xiangning }
2820f1702c5SYu Xiangning
2830f1702c5SYu Xiangning
2840f1702c5SYu Xiangning /*
2850f1702c5SYu Xiangning * Protocol module does address family checks.
2860f1702c5SYu Xiangning */
2870f1702c5SYu Xiangning mutex_exit(&so->so_lock);
2880f1702c5SYu Xiangning
2890f1702c5SYu Xiangning error = sctp_bind((struct sctp_s *)so->so_proto_handle, name, namelen);
2900f1702c5SYu Xiangning
2910f1702c5SYu Xiangning mutex_enter(&so->so_lock);
2920f1702c5SYu Xiangning if (error == 0) {
2930f1702c5SYu Xiangning so->so_state |= SS_ISBOUND;
2940f1702c5SYu Xiangning } else {
2950f1702c5SYu Xiangning eprintsoline(so, error);
2960f1702c5SYu Xiangning }
2970f1702c5SYu Xiangning done:
2980f1702c5SYu Xiangning if (!(flags & _SOBIND_LOCK_HELD)) {
2990f1702c5SYu Xiangning so_unlock_single(so, SOLOCKED);
3000f1702c5SYu Xiangning mutex_exit(&so->so_lock);
3010f1702c5SYu Xiangning } else {
3020f1702c5SYu Xiangning /* If the caller held the lock don't release it here */
3030f1702c5SYu Xiangning ASSERT(MUTEX_HELD(&so->so_lock));
3040f1702c5SYu Xiangning ASSERT(so->so_flag & SOLOCKED);
3050f1702c5SYu Xiangning }
3060f1702c5SYu Xiangning
3070f1702c5SYu Xiangning return (error);
3080f1702c5SYu Xiangning }
3090f1702c5SYu Xiangning
3100f1702c5SYu Xiangning /*
3110f1702c5SYu Xiangning * Turn socket into a listen socket.
3120f1702c5SYu Xiangning */
3130f1702c5SYu Xiangning /* ARGSUSED */
3140f1702c5SYu Xiangning static int
sosctp_listen(struct sonode * so,int backlog,struct cred * cr)3150f1702c5SYu Xiangning sosctp_listen(struct sonode *so, int backlog, struct cred *cr)
3160f1702c5SYu Xiangning {
3170f1702c5SYu Xiangning int error = 0;
3180f1702c5SYu Xiangning
3190f1702c5SYu Xiangning mutex_enter(&so->so_lock);
3200f1702c5SYu Xiangning so_lock_single(so);
3210f1702c5SYu Xiangning
3220f1702c5SYu Xiangning /*
3230f1702c5SYu Xiangning * If this socket is trying to do connect, or if it has
3240f1702c5SYu Xiangning * been connected, disallow.
3250f1702c5SYu Xiangning */
3260f1702c5SYu Xiangning if (so->so_state & (SS_ISCONNECTING | SS_ISCONNECTED |
3270f1702c5SYu Xiangning SS_ISDISCONNECTING | SS_CANTRCVMORE | SS_CANTSENDMORE)) {
3280f1702c5SYu Xiangning error = EINVAL;
3290f1702c5SYu Xiangning eprintsoline(so, error);
3300f1702c5SYu Xiangning goto done;
3310f1702c5SYu Xiangning }
3320f1702c5SYu Xiangning
3330f1702c5SYu Xiangning if (backlog < 0) {
3340f1702c5SYu Xiangning backlog = 0;
3350f1702c5SYu Xiangning }
3360f1702c5SYu Xiangning
3370f1702c5SYu Xiangning /*
3380f1702c5SYu Xiangning * If listen() is only called to change backlog, we don't
3390f1702c5SYu Xiangning * need to notify protocol module.
3400f1702c5SYu Xiangning */
3410f1702c5SYu Xiangning if (so->so_state & SS_ACCEPTCONN) {
3420f1702c5SYu Xiangning so->so_backlog = backlog;
3430f1702c5SYu Xiangning goto done;
3440f1702c5SYu Xiangning }
3450f1702c5SYu Xiangning
3460f1702c5SYu Xiangning mutex_exit(&so->so_lock);
3470f1702c5SYu Xiangning error = sctp_listen((struct sctp_s *)so->so_proto_handle);
3480f1702c5SYu Xiangning mutex_enter(&so->so_lock);
3490f1702c5SYu Xiangning if (error == 0) {
3500f1702c5SYu Xiangning so->so_state |= (SS_ACCEPTCONN|SS_ISBOUND);
3510f1702c5SYu Xiangning so->so_backlog = backlog;
3520f1702c5SYu Xiangning } else {
3530f1702c5SYu Xiangning eprintsoline(so, error);
3540f1702c5SYu Xiangning }
3550f1702c5SYu Xiangning done:
3560f1702c5SYu Xiangning so_unlock_single(so, SOLOCKED);
3570f1702c5SYu Xiangning mutex_exit(&so->so_lock);
3580f1702c5SYu Xiangning
3590f1702c5SYu Xiangning return (error);
3600f1702c5SYu Xiangning }
3610f1702c5SYu Xiangning
3620f1702c5SYu Xiangning /*
3630f1702c5SYu Xiangning * Active open.
3640f1702c5SYu Xiangning */
3650f1702c5SYu Xiangning /*ARGSUSED*/
3660f1702c5SYu Xiangning static int
sosctp_connect(struct sonode * so,struct sockaddr * name,socklen_t namelen,int fflag,int flags,struct cred * cr)3673e95bd4aSAnders Persson sosctp_connect(struct sonode *so, struct sockaddr *name,
3680f1702c5SYu Xiangning socklen_t namelen, int fflag, int flags, struct cred *cr)
3690f1702c5SYu Xiangning {
3700f1702c5SYu Xiangning int error = 0;
371bd670b35SErik Nordmark pid_t pid = curproc->p_pid;
3720f1702c5SYu Xiangning
3730f1702c5SYu Xiangning ASSERT(so->so_type == SOCK_STREAM);
3740f1702c5SYu Xiangning
3750f1702c5SYu Xiangning mutex_enter(&so->so_lock);
3760f1702c5SYu Xiangning so_lock_single(so);
3770f1702c5SYu Xiangning
3780f1702c5SYu Xiangning /*
3790f1702c5SYu Xiangning * Can't connect() after listen(), or if the socket is already
3800f1702c5SYu Xiangning * connected.
3810f1702c5SYu Xiangning */
3820f1702c5SYu Xiangning if (so->so_state & (SS_ACCEPTCONN|SS_ISCONNECTED|SS_ISCONNECTING)) {
3830f1702c5SYu Xiangning if (so->so_state & SS_ISCONNECTED) {
3840f1702c5SYu Xiangning error = EISCONN;
3850f1702c5SYu Xiangning } else if (so->so_state & SS_ISCONNECTING) {
3860f1702c5SYu Xiangning error = EALREADY;
3870f1702c5SYu Xiangning } else {
3880f1702c5SYu Xiangning error = EOPNOTSUPP;
3890f1702c5SYu Xiangning }
3900f1702c5SYu Xiangning eprintsoline(so, error);
3910f1702c5SYu Xiangning goto done;
3920f1702c5SYu Xiangning }
3930f1702c5SYu Xiangning
3940f1702c5SYu Xiangning /*
3950f1702c5SYu Xiangning * Check for failure of an earlier call
3960f1702c5SYu Xiangning */
3970f1702c5SYu Xiangning if (so->so_error != 0) {
3980f1702c5SYu Xiangning error = sogeterr(so, B_TRUE);
3990f1702c5SYu Xiangning eprintsoline(so, error);
4000f1702c5SYu Xiangning goto done;
4010f1702c5SYu Xiangning }
4020f1702c5SYu Xiangning
4030f1702c5SYu Xiangning /*
4040f1702c5SYu Xiangning * Connection is closing, or closed, don't allow reconnect.
4050f1702c5SYu Xiangning * TCP allows this to proceed, but the socket remains unwriteable.
4060f1702c5SYu Xiangning * BSD returns EINVAL.
4070f1702c5SYu Xiangning */
4080f1702c5SYu Xiangning if (so->so_state & (SS_ISDISCONNECTING|SS_CANTRCVMORE|
4090f1702c5SYu Xiangning SS_CANTSENDMORE)) {
4100f1702c5SYu Xiangning error = EINVAL;
4110f1702c5SYu Xiangning eprintsoline(so, error);
4120f1702c5SYu Xiangning goto done;
4130f1702c5SYu Xiangning }
4140f1702c5SYu Xiangning
4150f1702c5SYu Xiangning if (name == NULL || namelen == 0) {
4160f1702c5SYu Xiangning error = EINVAL;
4170f1702c5SYu Xiangning eprintsoline(so, error);
4180f1702c5SYu Xiangning goto done;
4190f1702c5SYu Xiangning }
4200f1702c5SYu Xiangning
4210f1702c5SYu Xiangning soisconnecting(so);
4220f1702c5SYu Xiangning mutex_exit(&so->so_lock);
4230f1702c5SYu Xiangning
4240f1702c5SYu Xiangning error = sctp_connect((struct sctp_s *)so->so_proto_handle,
425bd670b35SErik Nordmark name, namelen, cr, pid);
4260f1702c5SYu Xiangning
4270f1702c5SYu Xiangning mutex_enter(&so->so_lock);
4280f1702c5SYu Xiangning if (error == 0) {
4290f1702c5SYu Xiangning /*
4300f1702c5SYu Xiangning * Allow other threads to access the socket
4310f1702c5SYu Xiangning */
4320f1702c5SYu Xiangning error = sowaitconnected(so, fflag, 0);
4330f1702c5SYu Xiangning }
4340f1702c5SYu Xiangning done:
4350f1702c5SYu Xiangning so_unlock_single(so, SOLOCKED);
4360f1702c5SYu Xiangning mutex_exit(&so->so_lock);
4370f1702c5SYu Xiangning return (error);
4380f1702c5SYu Xiangning }
4390f1702c5SYu Xiangning
4400f1702c5SYu Xiangning /*
4410f1702c5SYu Xiangning * Active open for 1-N sockets, create a new association and
4420f1702c5SYu Xiangning * call connect on that.
4430f1702c5SYu Xiangning * If there parent hasn't been bound yet (this is the first association),
4440f1702c5SYu Xiangning * make it so.
4450f1702c5SYu Xiangning */
4460f1702c5SYu Xiangning static int
sosctp_seq_connect(struct sonode * so,struct sockaddr * name,socklen_t namelen,int fflag,int flags,struct cred * cr)4473e95bd4aSAnders Persson sosctp_seq_connect(struct sonode *so, struct sockaddr *name,
4480f1702c5SYu Xiangning socklen_t namelen, int fflag, int flags, struct cred *cr)
4490f1702c5SYu Xiangning {
4500f1702c5SYu Xiangning struct sctp_soassoc *ssa;
4510f1702c5SYu Xiangning struct sctp_sonode *ss;
4520f1702c5SYu Xiangning int error;
4530f1702c5SYu Xiangning
4540f1702c5SYu Xiangning ASSERT(so->so_type == SOCK_SEQPACKET);
4550f1702c5SYu Xiangning
4560f1702c5SYu Xiangning mutex_enter(&so->so_lock);
4570f1702c5SYu Xiangning so_lock_single(so);
4580f1702c5SYu Xiangning
4590f1702c5SYu Xiangning if (name == NULL || namelen == 0) {
4600f1702c5SYu Xiangning error = EINVAL;
4610f1702c5SYu Xiangning eprintsoline(so, error);
4620f1702c5SYu Xiangning goto done;
4630f1702c5SYu Xiangning }
4640f1702c5SYu Xiangning
4650f1702c5SYu Xiangning ss = SOTOSSO(so);
4660f1702c5SYu Xiangning
4670f1702c5SYu Xiangning error = sosctp_assoc_createconn(ss, name, namelen, NULL, 0, fflag,
4680f1702c5SYu Xiangning cr, &ssa);
4690f1702c5SYu Xiangning if (error != 0) {
4700f1702c5SYu Xiangning if ((error == EHOSTUNREACH) && (flags & _SOCONNECT_XPG4_2)) {
4710f1702c5SYu Xiangning error = ENETUNREACH;
4720f1702c5SYu Xiangning }
4730f1702c5SYu Xiangning }
4740f1702c5SYu Xiangning if (ssa != NULL) {
4750f1702c5SYu Xiangning SSA_REFRELE(ss, ssa);
4760f1702c5SYu Xiangning }
4770f1702c5SYu Xiangning
4780f1702c5SYu Xiangning done:
4790f1702c5SYu Xiangning so_unlock_single(so, SOLOCKED);
4800f1702c5SYu Xiangning mutex_exit(&so->so_lock);
4810f1702c5SYu Xiangning return (error);
4820f1702c5SYu Xiangning }
4830f1702c5SYu Xiangning
4840f1702c5SYu Xiangning /*
4850f1702c5SYu Xiangning * Receive data.
4860f1702c5SYu Xiangning */
4870f1702c5SYu Xiangning /* ARGSUSED */
4880f1702c5SYu Xiangning static int
sosctp_recvmsg(struct sonode * so,struct nmsghdr * msg,struct uio * uiop,struct cred * cr)4890f1702c5SYu Xiangning sosctp_recvmsg(struct sonode *so, struct nmsghdr *msg, struct uio *uiop,
4900f1702c5SYu Xiangning struct cred *cr)
4910f1702c5SYu Xiangning {
4920f1702c5SYu Xiangning struct sctp_sonode *ss = SOTOSSO(so);
4930f1702c5SYu Xiangning struct sctp_soassoc *ssa = NULL;
4940f1702c5SYu Xiangning int flags, error = 0;
4950f1702c5SYu Xiangning struct T_unitdata_ind *tind;
496419dcee7SAnders Persson ssize_t orig_resid = uiop->uio_resid;
497a215d4ebSKacheong Poon int len, count, readcnt = 0;
4980f1702c5SYu Xiangning socklen_t controllen, namelen;
4990f1702c5SYu Xiangning void *opt;
5000f1702c5SYu Xiangning mblk_t *mp;
5010f1702c5SYu Xiangning rval_t rval;
5020f1702c5SYu Xiangning
5030f1702c5SYu Xiangning controllen = msg->msg_controllen;
5040f1702c5SYu Xiangning namelen = msg->msg_namelen;
5050f1702c5SYu Xiangning flags = msg->msg_flags;
5060f1702c5SYu Xiangning msg->msg_flags = 0;
5070f1702c5SYu Xiangning msg->msg_controllen = 0;
5080f1702c5SYu Xiangning msg->msg_namelen = 0;
5090f1702c5SYu Xiangning
5100f1702c5SYu Xiangning if (so->so_type == SOCK_STREAM) {
5110f1702c5SYu Xiangning if (!(so->so_state & (SS_ISCONNECTED|SS_ISCONNECTING|
5120f1702c5SYu Xiangning SS_CANTRCVMORE))) {
5130f1702c5SYu Xiangning return (ENOTCONN);
5140f1702c5SYu Xiangning }
5150f1702c5SYu Xiangning } else {
5160f1702c5SYu Xiangning /* NOTE: Will come here from vop_read() as well */
5170f1702c5SYu Xiangning /* For 1-N socket, recv() cannot be used. */
5180f1702c5SYu Xiangning if (namelen == 0)
5190f1702c5SYu Xiangning return (EOPNOTSUPP);
5200f1702c5SYu Xiangning /*
5210f1702c5SYu Xiangning * If there are no associations, and no new connections are
5220f1702c5SYu Xiangning * coming in, there's not going to be new messages coming
5230f1702c5SYu Xiangning * in either.
5240f1702c5SYu Xiangning */
525419dcee7SAnders Persson if (so->so_rcv_q_head == NULL && so->so_rcv_head == NULL &&
526419dcee7SAnders Persson ss->ss_assoccnt == 0 && !(so->so_state & SS_ACCEPTCONN)) {
5270f1702c5SYu Xiangning return (ENOTCONN);
5280f1702c5SYu Xiangning }
5290f1702c5SYu Xiangning }
5300f1702c5SYu Xiangning
5310f1702c5SYu Xiangning /*
5320f1702c5SYu Xiangning * out-of-band data not supported.
5330f1702c5SYu Xiangning */
5340f1702c5SYu Xiangning if (flags & MSG_OOB) {
5350f1702c5SYu Xiangning return (EOPNOTSUPP);
5360f1702c5SYu Xiangning }
5370f1702c5SYu Xiangning
5380f1702c5SYu Xiangning /*
5390f1702c5SYu Xiangning * flag possibilities:
5400f1702c5SYu Xiangning *
5410f1702c5SYu Xiangning * MSG_PEEK Don't consume data
5420f1702c5SYu Xiangning * MSG_WAITALL Wait for full quantity of data (ignored if MSG_PEEK)
5430f1702c5SYu Xiangning * MSG_DONTWAIT Non-blocking (same as FNDELAY | FNONBLOCK)
5440f1702c5SYu Xiangning *
5450f1702c5SYu Xiangning * MSG_WAITALL can return less than the full buffer if either
5460f1702c5SYu Xiangning *
5470f1702c5SYu Xiangning * 1. we would block and we are non-blocking
5480f1702c5SYu Xiangning * 2. a full message cannot be delivered
5490f1702c5SYu Xiangning *
5500f1702c5SYu Xiangning * Given that we always get a full message from proto below,
5510f1702c5SYu Xiangning * MSG_WAITALL is not meaningful.
5520f1702c5SYu Xiangning */
5530f1702c5SYu Xiangning
5540f1702c5SYu Xiangning mutex_enter(&so->so_lock);
5550f1702c5SYu Xiangning
5560f1702c5SYu Xiangning /*
5570f1702c5SYu Xiangning * Allow just one reader at a time.
5580f1702c5SYu Xiangning */
5590f1702c5SYu Xiangning error = so_lock_read_intr(so,
5600f1702c5SYu Xiangning uiop->uio_fmode | ((flags & MSG_DONTWAIT) ? FNONBLOCK : 0));
5610f1702c5SYu Xiangning if (error) {
5620f1702c5SYu Xiangning mutex_exit(&so->so_lock);
5630f1702c5SYu Xiangning return (error);
5640f1702c5SYu Xiangning }
5650f1702c5SYu Xiangning mutex_exit(&so->so_lock);
5660f1702c5SYu Xiangning again:
5670f1702c5SYu Xiangning error = so_dequeue_msg(so, &mp, uiop, &rval, flags | MSG_DUPCTRL);
5680f1702c5SYu Xiangning if (mp != NULL) {
5690f1702c5SYu Xiangning if (so->so_type == SOCK_SEQPACKET) {
5700f1702c5SYu Xiangning ssa = *(struct sctp_soassoc **)DB_BASE(mp);
5710f1702c5SYu Xiangning }
5720f1702c5SYu Xiangning
5730f1702c5SYu Xiangning tind = (struct T_unitdata_ind *)mp->b_rptr;
5740f1702c5SYu Xiangning
5750f1702c5SYu Xiangning len = tind->SRC_length;
5760f1702c5SYu Xiangning
5770f1702c5SYu Xiangning if (namelen > 0 && len > 0) {
5780f1702c5SYu Xiangning
5790f1702c5SYu Xiangning opt = sogetoff(mp, tind->SRC_offset, len, 1);
5800f1702c5SYu Xiangning
5810f1702c5SYu Xiangning ASSERT(opt != NULL);
5820f1702c5SYu Xiangning
5830f1702c5SYu Xiangning msg->msg_name = kmem_alloc(len, KM_SLEEP);
5840f1702c5SYu Xiangning msg->msg_namelen = len;
5850f1702c5SYu Xiangning
5860f1702c5SYu Xiangning bcopy(opt, msg->msg_name, len);
5870f1702c5SYu Xiangning }
5880f1702c5SYu Xiangning
5890f1702c5SYu Xiangning len = tind->OPT_length;
5900f1702c5SYu Xiangning if (controllen == 0) {
5910f1702c5SYu Xiangning if (len > 0) {
5920f1702c5SYu Xiangning msg->msg_flags |= MSG_CTRUNC;
5930f1702c5SYu Xiangning }
5940f1702c5SYu Xiangning } else if (len > 0) {
5950f1702c5SYu Xiangning opt = sogetoff(mp, tind->OPT_offset, len,
5960f1702c5SYu Xiangning __TPI_ALIGN_SIZE);
5970f1702c5SYu Xiangning
5980f1702c5SYu Xiangning ASSERT(opt != NULL);
5990f1702c5SYu Xiangning sosctp_pack_cmsg(opt, msg, len);
6000f1702c5SYu Xiangning }
6010f1702c5SYu Xiangning
6020f1702c5SYu Xiangning if (mp->b_flag & SCTP_NOTIFICATION) {
6030f1702c5SYu Xiangning msg->msg_flags |= MSG_NOTIFICATION;
6040f1702c5SYu Xiangning }
6050f1702c5SYu Xiangning
606a215d4ebSKacheong Poon if (!(mp->b_flag & SCTP_PARTIAL_DATA) &&
607a215d4ebSKacheong Poon !(rval.r_val1 & MOREDATA)) {
6080f1702c5SYu Xiangning msg->msg_flags |= MSG_EOR;
609a215d4ebSKacheong Poon }
6100f1702c5SYu Xiangning freemsg(mp);
6110f1702c5SYu Xiangning }
6120f1702c5SYu Xiangning done:
613419dcee7SAnders Persson if (!(flags & MSG_PEEK))
614419dcee7SAnders Persson readcnt = orig_resid - uiop->uio_resid;
6150f1702c5SYu Xiangning /*
6160f1702c5SYu Xiangning * Determine if we need to update SCTP about the buffer
6170f1702c5SYu Xiangning * space. For performance reason, we cannot update SCTP
6180f1702c5SYu Xiangning * every time a message is read. The socket buffer low
6190f1702c5SYu Xiangning * watermark is used as the threshold.
6200f1702c5SYu Xiangning */
6210f1702c5SYu Xiangning if (ssa == NULL) {
6220f1702c5SYu Xiangning mutex_enter(&so->so_lock);
6230f1702c5SYu Xiangning count = so->so_rcvbuf - so->so_rcv_queued;
6240f1702c5SYu Xiangning
6250f1702c5SYu Xiangning ASSERT(so->so_rcv_q_head != NULL ||
6260f1702c5SYu Xiangning so->so_rcv_head != NULL ||
6270f1702c5SYu Xiangning so->so_rcv_queued == 0);
6280f1702c5SYu Xiangning
6290f1702c5SYu Xiangning so_unlock_read(so);
6300f1702c5SYu Xiangning
631a215d4ebSKacheong Poon /*
632a215d4ebSKacheong Poon * so_dequeue_msg() sets r_val2 to true if flow control was
633a215d4ebSKacheong Poon * cleared and we need to update SCTP. so_flowctrld was
634a215d4ebSKacheong Poon * cleared in so_dequeue_msg() via so_check_flow_control().
635a215d4ebSKacheong Poon */
636a215d4ebSKacheong Poon if (rval.r_val2) {
637a215d4ebSKacheong Poon mutex_exit(&so->so_lock);
6380f1702c5SYu Xiangning sctp_recvd((struct sctp_s *)so->so_proto_handle, count);
639a215d4ebSKacheong Poon } else {
640a215d4ebSKacheong Poon mutex_exit(&so->so_lock);
6410f1702c5SYu Xiangning }
6420f1702c5SYu Xiangning } else {
643419dcee7SAnders Persson /*
644419dcee7SAnders Persson * Each association keeps track of how much data it has
645419dcee7SAnders Persson * queued; we need to update the value here. Note that this
646419dcee7SAnders Persson * is slightly different from SOCK_STREAM type sockets, which
647419dcee7SAnders Persson * does not need to update the byte count, as it is already
648419dcee7SAnders Persson * done in so_dequeue_msg().
649419dcee7SAnders Persson */
6500f1702c5SYu Xiangning mutex_enter(&so->so_lock);
651a215d4ebSKacheong Poon ssa->ssa_rcv_queued -= readcnt;
6520f1702c5SYu Xiangning count = so->so_rcvbuf - ssa->ssa_rcv_queued;
6530f1702c5SYu Xiangning
6540f1702c5SYu Xiangning so_unlock_read(so);
6550f1702c5SYu Xiangning
656a215d4ebSKacheong Poon if (readcnt > 0 && ssa->ssa_flowctrld &&
657a215d4ebSKacheong Poon ssa->ssa_rcv_queued < so->so_rcvlowat) {
6580f1702c5SYu Xiangning /*
659a215d4ebSKacheong Poon * Need to clear ssa_flowctrld, different from 1-1
660a215d4ebSKacheong Poon * style.
6610f1702c5SYu Xiangning */
662a215d4ebSKacheong Poon ssa->ssa_flowctrld = B_FALSE;
6630f1702c5SYu Xiangning mutex_exit(&so->so_lock);
664a215d4ebSKacheong Poon sctp_recvd(ssa->ssa_conn, count);
6650f1702c5SYu Xiangning mutex_enter(&so->so_lock);
6660f1702c5SYu Xiangning }
667a215d4ebSKacheong Poon
6680f1702c5SYu Xiangning /*
6690f1702c5SYu Xiangning * MOREDATA flag is set if all data could not be copied
6700f1702c5SYu Xiangning */
6710f1702c5SYu Xiangning if (!(flags & MSG_PEEK) && !(rval.r_val1 & MOREDATA)) {
6720f1702c5SYu Xiangning SSA_REFRELE(ss, ssa);
6730f1702c5SYu Xiangning }
6740f1702c5SYu Xiangning mutex_exit(&so->so_lock);
6750f1702c5SYu Xiangning }
6760f1702c5SYu Xiangning
6770f1702c5SYu Xiangning return (error);
6780f1702c5SYu Xiangning }
6790f1702c5SYu Xiangning
6800f1702c5SYu Xiangning int
sosctp_uiomove(mblk_t * hdr_mp,ssize_t count,ssize_t blk_size,int wroff,struct uio * uiop,int flags)6810f1702c5SYu Xiangning sosctp_uiomove(mblk_t *hdr_mp, ssize_t count, ssize_t blk_size, int wroff,
682bd670b35SErik Nordmark struct uio *uiop, int flags)
6830f1702c5SYu Xiangning {
6840f1702c5SYu Xiangning ssize_t size;
6850f1702c5SYu Xiangning int error;
6860f1702c5SYu Xiangning mblk_t *mp;
6870f1702c5SYu Xiangning dblk_t *dp;
6880f1702c5SYu Xiangning
689d496d3f8SErik Nordmark if (blk_size == INFPSZ)
690d496d3f8SErik Nordmark blk_size = count;
691d496d3f8SErik Nordmark
6920f1702c5SYu Xiangning /*
6930f1702c5SYu Xiangning * Loop until we have all data copied into mblk's.
6940f1702c5SYu Xiangning */
6950f1702c5SYu Xiangning while (count > 0) {
6960f1702c5SYu Xiangning size = MIN(count, blk_size);
6970f1702c5SYu Xiangning
6980f1702c5SYu Xiangning /*
6990f1702c5SYu Xiangning * As a message can be splitted up and sent in different
7000f1702c5SYu Xiangning * packets, each mblk will have the extra space before
7010f1702c5SYu Xiangning * data to accommodate what SCTP wants to put in there.
7020f1702c5SYu Xiangning */
703bd670b35SErik Nordmark while ((mp = allocb(size + wroff, BPRI_MED)) == NULL) {
7040f1702c5SYu Xiangning if ((uiop->uio_fmode & (FNDELAY|FNONBLOCK)) ||
7050f1702c5SYu Xiangning (flags & MSG_DONTWAIT)) {
7060f1702c5SYu Xiangning return (EAGAIN);
7070f1702c5SYu Xiangning }
7080f1702c5SYu Xiangning if ((error = strwaitbuf(size + wroff, BPRI_MED))) {
7090f1702c5SYu Xiangning return (error);
7100f1702c5SYu Xiangning }
7110f1702c5SYu Xiangning }
7120f1702c5SYu Xiangning
7130f1702c5SYu Xiangning dp = mp->b_datap;
7140f1702c5SYu Xiangning dp->db_cpid = curproc->p_pid;
7150f1702c5SYu Xiangning ASSERT(wroff <= dp->db_lim - mp->b_wptr);
7160f1702c5SYu Xiangning mp->b_rptr += wroff;
7170f1702c5SYu Xiangning error = uiomove(mp->b_rptr, size, UIO_WRITE, uiop);
7180f1702c5SYu Xiangning if (error != 0) {
7190f1702c5SYu Xiangning freeb(mp);
7200f1702c5SYu Xiangning return (error);
7210f1702c5SYu Xiangning }
7220f1702c5SYu Xiangning mp->b_wptr = mp->b_rptr + size;
7230f1702c5SYu Xiangning count -= size;
7240f1702c5SYu Xiangning hdr_mp->b_cont = mp;
7250f1702c5SYu Xiangning hdr_mp = mp;
7260f1702c5SYu Xiangning }
7270f1702c5SYu Xiangning return (0);
7280f1702c5SYu Xiangning }
7290f1702c5SYu Xiangning
7300f1702c5SYu Xiangning /*
7310f1702c5SYu Xiangning * Send message.
7320f1702c5SYu Xiangning */
7330f1702c5SYu Xiangning static int
sosctp_sendmsg(struct sonode * so,struct nmsghdr * msg,struct uio * uiop,struct cred * cr)7340f1702c5SYu Xiangning sosctp_sendmsg(struct sonode *so, struct nmsghdr *msg, struct uio *uiop,
7350f1702c5SYu Xiangning struct cred *cr)
7360f1702c5SYu Xiangning {
7370f1702c5SYu Xiangning mblk_t *mctl;
7380f1702c5SYu Xiangning struct cmsghdr *cmsg;
7390f1702c5SYu Xiangning struct sctp_sndrcvinfo *sinfo;
7400f1702c5SYu Xiangning int optlen, flags, fflag;
7410f1702c5SYu Xiangning ssize_t count, msglen;
7420f1702c5SYu Xiangning int error;
7430f1702c5SYu Xiangning
7440f1702c5SYu Xiangning ASSERT(so->so_type == SOCK_STREAM);
7450f1702c5SYu Xiangning
7460f1702c5SYu Xiangning flags = msg->msg_flags;
7470f1702c5SYu Xiangning if (flags & MSG_OOB) {
7480f1702c5SYu Xiangning /*
7490f1702c5SYu Xiangning * No out-of-band data support.
7500f1702c5SYu Xiangning */
7510f1702c5SYu Xiangning return (EOPNOTSUPP);
7520f1702c5SYu Xiangning }
7530f1702c5SYu Xiangning
7540f1702c5SYu Xiangning if (msg->msg_controllen != 0) {
7550f1702c5SYu Xiangning optlen = msg->msg_controllen;
7560f1702c5SYu Xiangning cmsg = sosctp_find_cmsg(msg->msg_control, optlen, SCTP_SNDRCV);
7570f1702c5SYu Xiangning if (cmsg != NULL) {
7580f1702c5SYu Xiangning if (cmsg->cmsg_len <
7590f1702c5SYu Xiangning (sizeof (*sinfo) + sizeof (*cmsg))) {
7600f1702c5SYu Xiangning eprintsoline(so, EINVAL);
7610f1702c5SYu Xiangning return (EINVAL);
7620f1702c5SYu Xiangning }
7630f1702c5SYu Xiangning sinfo = (struct sctp_sndrcvinfo *)(cmsg + 1);
7640f1702c5SYu Xiangning
7650f1702c5SYu Xiangning /* Both flags should not be set together. */
7660f1702c5SYu Xiangning if ((sinfo->sinfo_flags & MSG_EOF) &&
7670f1702c5SYu Xiangning (sinfo->sinfo_flags & MSG_ABORT)) {
7680f1702c5SYu Xiangning eprintsoline(so, EINVAL);
7690f1702c5SYu Xiangning return (EINVAL);
7700f1702c5SYu Xiangning }
7710f1702c5SYu Xiangning
7720f1702c5SYu Xiangning /* Initiate a graceful shutdown. */
7730f1702c5SYu Xiangning if (sinfo->sinfo_flags & MSG_EOF) {
7740f1702c5SYu Xiangning /* Can't include data in MSG_EOF message. */
7750f1702c5SYu Xiangning if (uiop->uio_resid != 0) {
7760f1702c5SYu Xiangning eprintsoline(so, EINVAL);
7770f1702c5SYu Xiangning return (EINVAL);
7780f1702c5SYu Xiangning }
7790f1702c5SYu Xiangning
7800f1702c5SYu Xiangning /*
7810f1702c5SYu Xiangning * This is the same sequence as done in
7820f1702c5SYu Xiangning * shutdown(SHUT_WR).
7830f1702c5SYu Xiangning */
7840f1702c5SYu Xiangning mutex_enter(&so->so_lock);
7850f1702c5SYu Xiangning so_lock_single(so);
7860f1702c5SYu Xiangning socantsendmore(so);
7870f1702c5SYu Xiangning cv_broadcast(&so->so_snd_cv);
7880f1702c5SYu Xiangning so->so_state |= SS_ISDISCONNECTING;
7890f1702c5SYu Xiangning mutex_exit(&so->so_lock);
7900f1702c5SYu Xiangning
7910f1702c5SYu Xiangning pollwakeup(&so->so_poll_list, POLLOUT);
7920f1702c5SYu Xiangning sctp_recvd((struct sctp_s *)so->so_proto_handle,
7930f1702c5SYu Xiangning so->so_rcvbuf);
7940f1702c5SYu Xiangning error = sctp_disconnect(
7950f1702c5SYu Xiangning (struct sctp_s *)so->so_proto_handle);
7960f1702c5SYu Xiangning
7970f1702c5SYu Xiangning mutex_enter(&so->so_lock);
7980f1702c5SYu Xiangning so_unlock_single(so, SOLOCKED);
7990f1702c5SYu Xiangning mutex_exit(&so->so_lock);
8000f1702c5SYu Xiangning return (error);
8010f1702c5SYu Xiangning }
8020f1702c5SYu Xiangning }
8030f1702c5SYu Xiangning } else {
8040f1702c5SYu Xiangning optlen = 0;
8050f1702c5SYu Xiangning }
8060f1702c5SYu Xiangning
8070f1702c5SYu Xiangning mutex_enter(&so->so_lock);
8080f1702c5SYu Xiangning for (;;) {
8090f1702c5SYu Xiangning if (so->so_state & SS_CANTSENDMORE) {
8100f1702c5SYu Xiangning mutex_exit(&so->so_lock);
8110f1702c5SYu Xiangning return (EPIPE);
8120f1702c5SYu Xiangning }
8130f1702c5SYu Xiangning
8140f1702c5SYu Xiangning if (so->so_error != 0) {
8150f1702c5SYu Xiangning error = sogeterr(so, B_TRUE);
8160f1702c5SYu Xiangning mutex_exit(&so->so_lock);
8170f1702c5SYu Xiangning return (error);
8180f1702c5SYu Xiangning }
8190f1702c5SYu Xiangning
8200f1702c5SYu Xiangning if (!so->so_snd_qfull)
8210f1702c5SYu Xiangning break;
8220f1702c5SYu Xiangning
8230f1702c5SYu Xiangning if (so->so_state & SS_CLOSING) {
8240f1702c5SYu Xiangning mutex_exit(&so->so_lock);
8250f1702c5SYu Xiangning return (EINTR);
8260f1702c5SYu Xiangning }
8270f1702c5SYu Xiangning /*
8280f1702c5SYu Xiangning * Xmit window full in a blocking socket.
8290f1702c5SYu Xiangning */
8300f1702c5SYu Xiangning if ((uiop->uio_fmode & (FNDELAY|FNONBLOCK)) ||
8310f1702c5SYu Xiangning (flags & MSG_DONTWAIT)) {
8320f1702c5SYu Xiangning mutex_exit(&so->so_lock);
8330f1702c5SYu Xiangning return (EAGAIN);
8340f1702c5SYu Xiangning } else {
8350f1702c5SYu Xiangning /*
8360f1702c5SYu Xiangning * Wait for space to become available and try again.
8370f1702c5SYu Xiangning */
8380f1702c5SYu Xiangning error = cv_wait_sig(&so->so_snd_cv, &so->so_lock);
8390f1702c5SYu Xiangning if (!error) { /* signal */
8400f1702c5SYu Xiangning mutex_exit(&so->so_lock);
8410f1702c5SYu Xiangning return (EINTR);
8420f1702c5SYu Xiangning }
8430f1702c5SYu Xiangning }
8440f1702c5SYu Xiangning }
8450f1702c5SYu Xiangning msglen = count = uiop->uio_resid;
8460f1702c5SYu Xiangning
8470f1702c5SYu Xiangning /* Don't allow sending a message larger than the send buffer size. */
8480f1702c5SYu Xiangning /* XXX Transport module need to enforce this */
8490f1702c5SYu Xiangning if (msglen > so->so_sndbuf) {
8500f1702c5SYu Xiangning mutex_exit(&so->so_lock);
8510f1702c5SYu Xiangning return (EMSGSIZE);
8520f1702c5SYu Xiangning }
8530f1702c5SYu Xiangning
8540f1702c5SYu Xiangning /*
8550f1702c5SYu Xiangning * Allow piggybacking data on handshake messages (SS_ISCONNECTING).
8560f1702c5SYu Xiangning */
8570f1702c5SYu Xiangning if (!(so->so_state & (SS_ISCONNECTING | SS_ISCONNECTED))) {
8580f1702c5SYu Xiangning /*
8590f1702c5SYu Xiangning * We need to check here for listener so that the
8600f1702c5SYu Xiangning * same error will be returned as with a TCP socket.
8610f1702c5SYu Xiangning * In this case, sosctp_connect() returns EOPNOTSUPP
8620f1702c5SYu Xiangning * while a TCP socket returns ENOTCONN instead. Catch it
8630f1702c5SYu Xiangning * here to have the same behavior as a TCP socket.
8640f1702c5SYu Xiangning *
8650f1702c5SYu Xiangning * We also need to make sure that the peer address is
8660f1702c5SYu Xiangning * provided before we attempt to do the connect.
8670f1702c5SYu Xiangning */
8680f1702c5SYu Xiangning if ((so->so_state & SS_ACCEPTCONN) ||
8690f1702c5SYu Xiangning msg->msg_name == NULL) {
8700f1702c5SYu Xiangning mutex_exit(&so->so_lock);
8710f1702c5SYu Xiangning error = ENOTCONN;
8720f1702c5SYu Xiangning goto error_nofree;
8730f1702c5SYu Xiangning }
8740f1702c5SYu Xiangning mutex_exit(&so->so_lock);
8750f1702c5SYu Xiangning fflag = uiop->uio_fmode;
8760f1702c5SYu Xiangning if (flags & MSG_DONTWAIT) {
8770f1702c5SYu Xiangning fflag |= FNDELAY;
8780f1702c5SYu Xiangning }
8790f1702c5SYu Xiangning error = sosctp_connect(so, msg->msg_name, msg->msg_namelen,
8800f1702c5SYu Xiangning fflag, (so->so_version == SOV_XPG4_2) * _SOCONNECT_XPG4_2,
8810f1702c5SYu Xiangning cr);
8820f1702c5SYu Xiangning if (error) {
8830f1702c5SYu Xiangning /*
8840f1702c5SYu Xiangning * Check for non-fatal errors, socket connected
8850f1702c5SYu Xiangning * while the lock had been lifted.
8860f1702c5SYu Xiangning */
8870f1702c5SYu Xiangning if (error != EISCONN && error != EALREADY) {
8880f1702c5SYu Xiangning goto error_nofree;
8890f1702c5SYu Xiangning }
8900f1702c5SYu Xiangning error = 0;
8910f1702c5SYu Xiangning }
8920f1702c5SYu Xiangning } else {
8930f1702c5SYu Xiangning mutex_exit(&so->so_lock);
8940f1702c5SYu Xiangning }
8950f1702c5SYu Xiangning
8960f1702c5SYu Xiangning mctl = sctp_alloc_hdr(msg->msg_name, msg->msg_namelen,
8970f1702c5SYu Xiangning msg->msg_control, optlen, SCTP_CAN_BLOCK);
8980f1702c5SYu Xiangning if (mctl == NULL) {
8990f1702c5SYu Xiangning error = EINTR;
9000f1702c5SYu Xiangning goto error_nofree;
9010f1702c5SYu Xiangning }
9020f1702c5SYu Xiangning
9030f1702c5SYu Xiangning /* Copy in the message. */
904a215d4ebSKacheong Poon if ((error = sosctp_uiomove(mctl, count, so->so_proto_props.sopp_maxblk,
905a215d4ebSKacheong Poon so->so_proto_props.sopp_wroff, uiop, flags)) != 0) {
9060f1702c5SYu Xiangning goto error_ret;
9070f1702c5SYu Xiangning }
9080f1702c5SYu Xiangning error = sctp_sendmsg((struct sctp_s *)so->so_proto_handle, mctl, 0);
9090f1702c5SYu Xiangning if (error == 0)
9100f1702c5SYu Xiangning return (0);
9110f1702c5SYu Xiangning
9120f1702c5SYu Xiangning error_ret:
9130f1702c5SYu Xiangning freemsg(mctl);
9140f1702c5SYu Xiangning error_nofree:
9150f1702c5SYu Xiangning mutex_enter(&so->so_lock);
9160f1702c5SYu Xiangning if ((error == EPIPE) && (so->so_state & SS_CANTSENDMORE)) {
9170f1702c5SYu Xiangning /*
9180f1702c5SYu Xiangning * We received shutdown between the time lock was
9190f1702c5SYu Xiangning * lifted and call to sctp_sendmsg().
9200f1702c5SYu Xiangning */
9210f1702c5SYu Xiangning mutex_exit(&so->so_lock);
9220f1702c5SYu Xiangning return (EPIPE);
9230f1702c5SYu Xiangning }
9240f1702c5SYu Xiangning mutex_exit(&so->so_lock);
9250f1702c5SYu Xiangning return (error);
9260f1702c5SYu Xiangning }
9270f1702c5SYu Xiangning
9280f1702c5SYu Xiangning /*
9290f1702c5SYu Xiangning * Send message on 1-N socket. Connects automatically if there is
9300f1702c5SYu Xiangning * no association.
9310f1702c5SYu Xiangning */
9320f1702c5SYu Xiangning static int
sosctp_seq_sendmsg(struct sonode * so,struct nmsghdr * msg,struct uio * uiop,struct cred * cr)9330f1702c5SYu Xiangning sosctp_seq_sendmsg(struct sonode *so, struct nmsghdr *msg, struct uio *uiop,
9340f1702c5SYu Xiangning struct cred *cr)
9350f1702c5SYu Xiangning {
9360f1702c5SYu Xiangning struct sctp_sonode *ss;
9370f1702c5SYu Xiangning struct sctp_soassoc *ssa;
9380f1702c5SYu Xiangning struct cmsghdr *cmsg;
9390f1702c5SYu Xiangning struct sctp_sndrcvinfo *sinfo;
9400f1702c5SYu Xiangning int aid = 0;
9410f1702c5SYu Xiangning mblk_t *mctl;
9420f1702c5SYu Xiangning int namelen, optlen, flags;
9430f1702c5SYu Xiangning ssize_t count, msglen;
9440f1702c5SYu Xiangning int error;
9450f1702c5SYu Xiangning uint16_t s_flags = 0;
9460f1702c5SYu Xiangning
9470f1702c5SYu Xiangning ASSERT(so->so_type == SOCK_SEQPACKET);
9480f1702c5SYu Xiangning
9490f1702c5SYu Xiangning /*
9500f1702c5SYu Xiangning * There shouldn't be problems with alignment, as the memory for
9510f1702c5SYu Xiangning * msg_control was alloced with kmem_alloc.
9520f1702c5SYu Xiangning */
9530f1702c5SYu Xiangning cmsg = sosctp_find_cmsg(msg->msg_control, msg->msg_controllen,
9540f1702c5SYu Xiangning SCTP_SNDRCV);
9550f1702c5SYu Xiangning if (cmsg != NULL) {
9560f1702c5SYu Xiangning if (cmsg->cmsg_len < (sizeof (*sinfo) + sizeof (*cmsg))) {
9570f1702c5SYu Xiangning eprintsoline(so, EINVAL);
9580f1702c5SYu Xiangning return (EINVAL);
9590f1702c5SYu Xiangning }
9600f1702c5SYu Xiangning sinfo = (struct sctp_sndrcvinfo *)(cmsg + 1);
9610f1702c5SYu Xiangning s_flags = sinfo->sinfo_flags;
9620f1702c5SYu Xiangning aid = sinfo->sinfo_assoc_id;
9630f1702c5SYu Xiangning }
9640f1702c5SYu Xiangning
9650f1702c5SYu Xiangning ss = SOTOSSO(so);
9660f1702c5SYu Xiangning namelen = msg->msg_namelen;
9670f1702c5SYu Xiangning
9680f1702c5SYu Xiangning if (msg->msg_controllen > 0) {
9690f1702c5SYu Xiangning optlen = msg->msg_controllen;
9700f1702c5SYu Xiangning } else {
9710f1702c5SYu Xiangning optlen = 0;
9720f1702c5SYu Xiangning }
9730f1702c5SYu Xiangning
9740f1702c5SYu Xiangning mutex_enter(&so->so_lock);
9750f1702c5SYu Xiangning
9760f1702c5SYu Xiangning /*
9770f1702c5SYu Xiangning * If there is no association id, connect to address specified
9780f1702c5SYu Xiangning * in msg_name. Otherwise look up the association using the id.
9790f1702c5SYu Xiangning */
9800f1702c5SYu Xiangning if (aid == 0) {
9810f1702c5SYu Xiangning /*
9820f1702c5SYu Xiangning * Connect and shutdown cannot be done together, so check for
9830f1702c5SYu Xiangning * MSG_EOF.
9840f1702c5SYu Xiangning */
9850f1702c5SYu Xiangning if (msg->msg_name == NULL || namelen == 0 ||
9860f1702c5SYu Xiangning (s_flags & MSG_EOF)) {
9870f1702c5SYu Xiangning error = EINVAL;
9880f1702c5SYu Xiangning eprintsoline(so, error);
9890f1702c5SYu Xiangning goto done;
9900f1702c5SYu Xiangning }
9910f1702c5SYu Xiangning flags = uiop->uio_fmode;
9920f1702c5SYu Xiangning if (msg->msg_flags & MSG_DONTWAIT) {
9930f1702c5SYu Xiangning flags |= FNDELAY;
9940f1702c5SYu Xiangning }
9950f1702c5SYu Xiangning so_lock_single(so);
9960f1702c5SYu Xiangning error = sosctp_assoc_createconn(ss, msg->msg_name, namelen,
9970f1702c5SYu Xiangning msg->msg_control, optlen, flags, cr, &ssa);
9980f1702c5SYu Xiangning if (error) {
9990f1702c5SYu Xiangning if ((so->so_version == SOV_XPG4_2) &&
10000f1702c5SYu Xiangning (error == EHOSTUNREACH)) {
10010f1702c5SYu Xiangning error = ENETUNREACH;
10020f1702c5SYu Xiangning }
10030f1702c5SYu Xiangning if (ssa == NULL) {
10040f1702c5SYu Xiangning /*
10050f1702c5SYu Xiangning * Fatal error during connect(). Bail out.
10060f1702c5SYu Xiangning * If ssa exists, it means that the handshake
10070f1702c5SYu Xiangning * is in progress.
10080f1702c5SYu Xiangning */
10090f1702c5SYu Xiangning eprintsoline(so, error);
10100f1702c5SYu Xiangning so_unlock_single(so, SOLOCKED);
10110f1702c5SYu Xiangning goto done;
10120f1702c5SYu Xiangning }
10130f1702c5SYu Xiangning /*
10140f1702c5SYu Xiangning * All the errors are non-fatal ones, don't return
10150f1702c5SYu Xiangning * e.g. EINPROGRESS from sendmsg().
10160f1702c5SYu Xiangning */
10170f1702c5SYu Xiangning error = 0;
10180f1702c5SYu Xiangning }
10190f1702c5SYu Xiangning so_unlock_single(so, SOLOCKED);
10200f1702c5SYu Xiangning } else {
10210f1702c5SYu Xiangning if ((error = sosctp_assoc(ss, aid, &ssa)) != 0) {
10220f1702c5SYu Xiangning eprintsoline(so, error);
10230f1702c5SYu Xiangning goto done;
10240f1702c5SYu Xiangning }
10250f1702c5SYu Xiangning }
10260f1702c5SYu Xiangning
10270f1702c5SYu Xiangning /*
10280f1702c5SYu Xiangning * Now we have an association.
10290f1702c5SYu Xiangning */
10300f1702c5SYu Xiangning flags = msg->msg_flags;
10310f1702c5SYu Xiangning
10320f1702c5SYu Xiangning /*
10330f1702c5SYu Xiangning * MSG_EOF initiates graceful shutdown.
10340f1702c5SYu Xiangning */
10350f1702c5SYu Xiangning if (s_flags & MSG_EOF) {
10360f1702c5SYu Xiangning if (uiop->uio_resid) {
10370f1702c5SYu Xiangning /*
10380f1702c5SYu Xiangning * Can't include data in MSG_EOF message.
10390f1702c5SYu Xiangning */
10400f1702c5SYu Xiangning error = EINVAL;
10410f1702c5SYu Xiangning } else {
10420f1702c5SYu Xiangning mutex_exit(&so->so_lock);
10430f1702c5SYu Xiangning ssa->ssa_state |= SS_ISDISCONNECTING;
1044a215d4ebSKacheong Poon sctp_recvd(ssa->ssa_conn, so->so_rcvbuf);
1045a215d4ebSKacheong Poon error = sctp_disconnect(ssa->ssa_conn);
10460f1702c5SYu Xiangning mutex_enter(&so->so_lock);
10470f1702c5SYu Xiangning }
10480f1702c5SYu Xiangning goto refrele;
10490f1702c5SYu Xiangning }
10500f1702c5SYu Xiangning
10510f1702c5SYu Xiangning for (;;) {
10520f1702c5SYu Xiangning if (ssa->ssa_state & SS_CANTSENDMORE) {
10530f1702c5SYu Xiangning SSA_REFRELE(ss, ssa);
10540f1702c5SYu Xiangning mutex_exit(&so->so_lock);
10550f1702c5SYu Xiangning return (EPIPE);
10560f1702c5SYu Xiangning }
10570f1702c5SYu Xiangning if (ssa->ssa_error != 0) {
10580f1702c5SYu Xiangning error = ssa->ssa_error;
10590f1702c5SYu Xiangning ssa->ssa_error = 0;
10600f1702c5SYu Xiangning goto refrele;
10610f1702c5SYu Xiangning }
10620f1702c5SYu Xiangning
10630f1702c5SYu Xiangning if (!ssa->ssa_snd_qfull)
10640f1702c5SYu Xiangning break;
10650f1702c5SYu Xiangning
10660f1702c5SYu Xiangning if (so->so_state & SS_CLOSING) {
10670f1702c5SYu Xiangning error = EINTR;
10680f1702c5SYu Xiangning goto refrele;
10690f1702c5SYu Xiangning }
10700f1702c5SYu Xiangning if ((uiop->uio_fmode & (FNDELAY|FNONBLOCK)) ||
10710f1702c5SYu Xiangning (flags & MSG_DONTWAIT)) {
10720f1702c5SYu Xiangning error = EAGAIN;
10730f1702c5SYu Xiangning goto refrele;
10740f1702c5SYu Xiangning } else {
10750f1702c5SYu Xiangning /*
10760f1702c5SYu Xiangning * Wait for space to become available and try again.
10770f1702c5SYu Xiangning */
10780f1702c5SYu Xiangning error = cv_wait_sig(&so->so_snd_cv, &so->so_lock);
10790f1702c5SYu Xiangning if (!error) { /* signal */
10800f1702c5SYu Xiangning error = EINTR;
10810f1702c5SYu Xiangning goto refrele;
10820f1702c5SYu Xiangning }
10830f1702c5SYu Xiangning }
10840f1702c5SYu Xiangning }
10850f1702c5SYu Xiangning
10860f1702c5SYu Xiangning msglen = count = uiop->uio_resid;
10870f1702c5SYu Xiangning
10880f1702c5SYu Xiangning /* Don't allow sending a message larger than the send buffer size. */
10890f1702c5SYu Xiangning if (msglen > so->so_sndbuf) {
10900f1702c5SYu Xiangning error = EMSGSIZE;
10910f1702c5SYu Xiangning goto refrele;
10920f1702c5SYu Xiangning }
10930f1702c5SYu Xiangning
10940f1702c5SYu Xiangning /*
10950f1702c5SYu Xiangning * Update TX buffer usage here so that we can lift the socket lock.
10960f1702c5SYu Xiangning */
10970f1702c5SYu Xiangning mutex_exit(&so->so_lock);
10980f1702c5SYu Xiangning
10990f1702c5SYu Xiangning mctl = sctp_alloc_hdr(msg->msg_name, namelen, msg->msg_control,
11000f1702c5SYu Xiangning optlen, SCTP_CAN_BLOCK);
11010f1702c5SYu Xiangning if (mctl == NULL) {
11020f1702c5SYu Xiangning error = EINTR;
11030f1702c5SYu Xiangning goto lock_rele;
11040f1702c5SYu Xiangning }
11050f1702c5SYu Xiangning
11060f1702c5SYu Xiangning /* Copy in the message. */
11070f1702c5SYu Xiangning if ((error = sosctp_uiomove(mctl, count, ssa->ssa_wrsize,
1108bd670b35SErik Nordmark ssa->ssa_wroff, uiop, flags)) != 0) {
11090f1702c5SYu Xiangning goto lock_rele;
11100f1702c5SYu Xiangning }
11110f1702c5SYu Xiangning error = sctp_sendmsg((struct sctp_s *)ssa->ssa_conn, mctl, 0);
11120f1702c5SYu Xiangning lock_rele:
11130f1702c5SYu Xiangning mutex_enter(&so->so_lock);
11140f1702c5SYu Xiangning if (error != 0) {
11150f1702c5SYu Xiangning freemsg(mctl);
11160f1702c5SYu Xiangning if ((error == EPIPE) && (ssa->ssa_state & SS_CANTSENDMORE)) {
11170f1702c5SYu Xiangning /*
11180f1702c5SYu Xiangning * We received shutdown between the time lock was
11190f1702c5SYu Xiangning * lifted and call to sctp_sendmsg().
11200f1702c5SYu Xiangning */
11210f1702c5SYu Xiangning SSA_REFRELE(ss, ssa);
11220f1702c5SYu Xiangning mutex_exit(&so->so_lock);
11230f1702c5SYu Xiangning return (EPIPE);
11240f1702c5SYu Xiangning }
11250f1702c5SYu Xiangning }
11260f1702c5SYu Xiangning
11270f1702c5SYu Xiangning refrele:
11280f1702c5SYu Xiangning SSA_REFRELE(ss, ssa);
11290f1702c5SYu Xiangning done:
11300f1702c5SYu Xiangning mutex_exit(&so->so_lock);
11310f1702c5SYu Xiangning return (error);
11320f1702c5SYu Xiangning }
11330f1702c5SYu Xiangning
11340f1702c5SYu Xiangning /*
11350f1702c5SYu Xiangning * Get address of remote node.
11360f1702c5SYu Xiangning */
11370f1702c5SYu Xiangning /* ARGSUSED */
11380f1702c5SYu Xiangning static int
sosctp_getpeername(struct sonode * so,struct sockaddr * addr,socklen_t * addrlen,boolean_t accept,struct cred * cr)11390f1702c5SYu Xiangning sosctp_getpeername(struct sonode *so, struct sockaddr *addr, socklen_t *addrlen,
11400f1702c5SYu Xiangning boolean_t accept, struct cred *cr)
11410f1702c5SYu Xiangning {
11420f1702c5SYu Xiangning return (sctp_getpeername((struct sctp_s *)so->so_proto_handle, addr,
11430f1702c5SYu Xiangning addrlen));
11440f1702c5SYu Xiangning }
11450f1702c5SYu Xiangning
11460f1702c5SYu Xiangning /*
11470f1702c5SYu Xiangning * Get local address.
11480f1702c5SYu Xiangning */
11490f1702c5SYu Xiangning /* ARGSUSED */
11500f1702c5SYu Xiangning static int
sosctp_getsockname(struct sonode * so,struct sockaddr * addr,socklen_t * addrlen,struct cred * cr)11510f1702c5SYu Xiangning sosctp_getsockname(struct sonode *so, struct sockaddr *addr, socklen_t *addrlen,
11520f1702c5SYu Xiangning struct cred *cr)
11530f1702c5SYu Xiangning {
11540f1702c5SYu Xiangning return (sctp_getsockname((struct sctp_s *)so->so_proto_handle, addr,
11550f1702c5SYu Xiangning addrlen));
11560f1702c5SYu Xiangning }
11570f1702c5SYu Xiangning
11580f1702c5SYu Xiangning /*
11590f1702c5SYu Xiangning * Called from shutdown().
11600f1702c5SYu Xiangning */
11610f1702c5SYu Xiangning /* ARGSUSED */
11620f1702c5SYu Xiangning static int
sosctp_shutdown(struct sonode * so,int how,struct cred * cr)11630f1702c5SYu Xiangning sosctp_shutdown(struct sonode *so, int how, struct cred *cr)
11640f1702c5SYu Xiangning {
11650f1702c5SYu Xiangning uint_t state_change;
11660f1702c5SYu Xiangning int wakesig = 0;
11670f1702c5SYu Xiangning int error = 0;
11680f1702c5SYu Xiangning
11690f1702c5SYu Xiangning mutex_enter(&so->so_lock);
11700f1702c5SYu Xiangning /*
11710f1702c5SYu Xiangning * Record the current state and then perform any state changes.
11720f1702c5SYu Xiangning * Then use the difference between the old and new states to
11730f1702c5SYu Xiangning * determine which needs to be done.
11740f1702c5SYu Xiangning */
11750f1702c5SYu Xiangning state_change = so->so_state;
11760f1702c5SYu Xiangning
11770f1702c5SYu Xiangning switch (how) {
11780f1702c5SYu Xiangning case SHUT_RD:
11790f1702c5SYu Xiangning socantrcvmore(so);
11800f1702c5SYu Xiangning break;
11810f1702c5SYu Xiangning case SHUT_WR:
11820f1702c5SYu Xiangning socantsendmore(so);
11830f1702c5SYu Xiangning break;
11840f1702c5SYu Xiangning case SHUT_RDWR:
11850f1702c5SYu Xiangning socantsendmore(so);
11860f1702c5SYu Xiangning socantrcvmore(so);
11870f1702c5SYu Xiangning break;
11880f1702c5SYu Xiangning default:
11890f1702c5SYu Xiangning mutex_exit(&so->so_lock);
11900f1702c5SYu Xiangning return (EINVAL);
11910f1702c5SYu Xiangning }
11920f1702c5SYu Xiangning
11930f1702c5SYu Xiangning state_change = so->so_state & ~state_change;
11940f1702c5SYu Xiangning
11950f1702c5SYu Xiangning if (state_change & SS_CANTRCVMORE) {
11960f1702c5SYu Xiangning if (so->so_rcv_q_head == NULL) {
11970f1702c5SYu Xiangning cv_signal(&so->so_rcv_cv);
11980f1702c5SYu Xiangning }
11990f1702c5SYu Xiangning wakesig = POLLIN|POLLRDNORM;
12000f1702c5SYu Xiangning
12010f1702c5SYu Xiangning socket_sendsig(so, SOCKETSIG_READ);
12020f1702c5SYu Xiangning }
12030f1702c5SYu Xiangning if (state_change & SS_CANTSENDMORE) {
12040f1702c5SYu Xiangning cv_broadcast(&so->so_snd_cv);
12050f1702c5SYu Xiangning wakesig |= POLLOUT;
12060f1702c5SYu Xiangning
12070f1702c5SYu Xiangning so->so_state |= SS_ISDISCONNECTING;
12080f1702c5SYu Xiangning }
12090f1702c5SYu Xiangning mutex_exit(&so->so_lock);
12100f1702c5SYu Xiangning
12110f1702c5SYu Xiangning pollwakeup(&so->so_poll_list, wakesig);
12120f1702c5SYu Xiangning
12130f1702c5SYu Xiangning if (state_change & SS_CANTSENDMORE) {
12140f1702c5SYu Xiangning sctp_recvd((struct sctp_s *)so->so_proto_handle, so->so_rcvbuf);
12150f1702c5SYu Xiangning error = sctp_disconnect((struct sctp_s *)so->so_proto_handle);
12160f1702c5SYu Xiangning }
12170f1702c5SYu Xiangning
12180f1702c5SYu Xiangning /*
12190f1702c5SYu Xiangning * HACK: sctp_disconnect() may return EWOULDBLOCK. But this error is
12200f1702c5SYu Xiangning * not documented in standard socket API. Catch it here.
12210f1702c5SYu Xiangning */
12220f1702c5SYu Xiangning if (error == EWOULDBLOCK)
12230f1702c5SYu Xiangning error = 0;
12240f1702c5SYu Xiangning return (error);
12250f1702c5SYu Xiangning }
12260f1702c5SYu Xiangning
12270f1702c5SYu Xiangning /*
12280f1702c5SYu Xiangning * Get socket options.
12290f1702c5SYu Xiangning */
12300f1702c5SYu Xiangning /*ARGSUSED5*/
12310f1702c5SYu Xiangning static int
sosctp_getsockopt(struct sonode * so,int level,int option_name,void * optval,socklen_t * optlenp,int flags,struct cred * cr)12320f1702c5SYu Xiangning sosctp_getsockopt(struct sonode *so, int level, int option_name,
12330f1702c5SYu Xiangning void *optval, socklen_t *optlenp, int flags, struct cred *cr)
12340f1702c5SYu Xiangning {
12352b36adecSRao Shoaib socklen_t maxlen = *optlenp;
12362b36adecSRao Shoaib socklen_t len;
12372b36adecSRao Shoaib socklen_t optlen;
12382b36adecSRao Shoaib uint8_t buffer[4];
12392b36adecSRao Shoaib void *optbuf = &buffer;
12402b36adecSRao Shoaib int error = 0;
12412b36adecSRao Shoaib
12422b36adecSRao Shoaib if (level == SOL_SOCKET) {
12432b36adecSRao Shoaib switch (option_name) {
12442b36adecSRao Shoaib /* Not supported options */
12452b36adecSRao Shoaib case SO_SNDTIMEO:
12462b36adecSRao Shoaib case SO_RCVTIMEO:
12472b36adecSRao Shoaib case SO_EXCLBIND:
12482c632ad5SAnders Persson eprintsoline(so, ENOPROTOOPT);
12492c632ad5SAnders Persson return (ENOPROTOOPT);
12502c632ad5SAnders Persson default:
12512c632ad5SAnders Persson error = socket_getopt_common(so, level, option_name,
12522c632ad5SAnders Persson optval, optlenp, flags);
12532c632ad5SAnders Persson if (error >= 0)
12542c632ad5SAnders Persson return (error);
12552c632ad5SAnders Persson /* Pass the request to the protocol */
12562b36adecSRao Shoaib break;
12572b36adecSRao Shoaib }
12582b36adecSRao Shoaib }
12592b36adecSRao Shoaib
12600f1702c5SYu Xiangning if (level == IPPROTO_SCTP) {
12610f1702c5SYu Xiangning /*
12620f1702c5SYu Xiangning * Should go through ioctl().
12630f1702c5SYu Xiangning */
12640f1702c5SYu Xiangning return (EINVAL);
12650f1702c5SYu Xiangning }
12662b36adecSRao Shoaib
12672b36adecSRao Shoaib if (maxlen > sizeof (buffer)) {
12682b36adecSRao Shoaib optbuf = kmem_alloc(maxlen, KM_SLEEP);
12692b36adecSRao Shoaib }
12702b36adecSRao Shoaib optlen = maxlen;
12712b36adecSRao Shoaib
12722b36adecSRao Shoaib /*
12732b36adecSRao Shoaib * If the resulting optlen is greater than the provided maxlen, then
12742b36adecSRao Shoaib * we sliently trucate.
12752b36adecSRao Shoaib */
12762b36adecSRao Shoaib error = sctp_get_opt((struct sctp_s *)so->so_proto_handle, level,
12772b36adecSRao Shoaib option_name, optbuf, &optlen);
12782b36adecSRao Shoaib
12792b36adecSRao Shoaib if (error != 0) {
12802b36adecSRao Shoaib eprintsoline(so, error);
12812b36adecSRao Shoaib goto free;
12822b36adecSRao Shoaib }
12832b36adecSRao Shoaib len = optlen;
12842b36adecSRao Shoaib
12852b36adecSRao Shoaib copyout:
12862b36adecSRao Shoaib
12872b36adecSRao Shoaib len = MIN(len, maxlen);
12882b36adecSRao Shoaib bcopy(optbuf, optval, len);
12892b36adecSRao Shoaib *optlenp = optlen;
12902b36adecSRao Shoaib free:
12912b36adecSRao Shoaib if (optbuf != &buffer) {
12922b36adecSRao Shoaib kmem_free(optbuf, maxlen);
12932b36adecSRao Shoaib }
12942c632ad5SAnders Persson
12952b36adecSRao Shoaib return (error);
12960f1702c5SYu Xiangning }
12970f1702c5SYu Xiangning
12980f1702c5SYu Xiangning /*
12990f1702c5SYu Xiangning * Set socket options
13000f1702c5SYu Xiangning */
13010f1702c5SYu Xiangning /* ARGSUSED */
13020f1702c5SYu Xiangning static int
sosctp_setsockopt(struct sonode * so,int level,int option_name,const void * optval,t_uscalar_t optlen,struct cred * cr)13030f1702c5SYu Xiangning sosctp_setsockopt(struct sonode *so, int level, int option_name,
13040f1702c5SYu Xiangning const void *optval, t_uscalar_t optlen, struct cred *cr)
13050f1702c5SYu Xiangning {
13060f1702c5SYu Xiangning struct sctp_sonode *ss = SOTOSSO(so);
13070f1702c5SYu Xiangning struct sctp_soassoc *ssa = NULL;
13080f1702c5SYu Xiangning sctp_assoc_t id;
13090f1702c5SYu Xiangning int error, rc;
13100f1702c5SYu Xiangning void *conn = NULL;
13110f1702c5SYu Xiangning
13120f1702c5SYu Xiangning mutex_enter(&so->so_lock);
13130f1702c5SYu Xiangning
13140f1702c5SYu Xiangning /*
13150f1702c5SYu Xiangning * For some SCTP level options, one can select the association this
13160f1702c5SYu Xiangning * applies to.
13170f1702c5SYu Xiangning */
13180f1702c5SYu Xiangning if (so->so_type == SOCK_STREAM) {
13190f1702c5SYu Xiangning conn = so->so_proto_handle;
13200f1702c5SYu Xiangning } else {
13210f1702c5SYu Xiangning /*
13220f1702c5SYu Xiangning * SOCK_SEQPACKET only
13230f1702c5SYu Xiangning */
13240f1702c5SYu Xiangning id = 0;
13250f1702c5SYu Xiangning if (level == IPPROTO_SCTP) {
13260f1702c5SYu Xiangning switch (option_name) {
13270f1702c5SYu Xiangning case SCTP_RTOINFO:
13280f1702c5SYu Xiangning case SCTP_ASSOCINFO:
13290f1702c5SYu Xiangning case SCTP_SET_PEER_PRIMARY_ADDR:
13300f1702c5SYu Xiangning case SCTP_PRIMARY_ADDR:
13310f1702c5SYu Xiangning case SCTP_PEER_ADDR_PARAMS:
13320f1702c5SYu Xiangning /*
13330f1702c5SYu Xiangning * Association ID is the first element
13340f1702c5SYu Xiangning * params struct
13350f1702c5SYu Xiangning */
13360f1702c5SYu Xiangning if (optlen < sizeof (sctp_assoc_t)) {
13370f1702c5SYu Xiangning error = EINVAL;
13380f1702c5SYu Xiangning eprintsoline(so, error);
13390f1702c5SYu Xiangning goto done;
13400f1702c5SYu Xiangning }
13410f1702c5SYu Xiangning id = *(sctp_assoc_t *)optval;
13420f1702c5SYu Xiangning break;
13430f1702c5SYu Xiangning case SCTP_DEFAULT_SEND_PARAM:
13440f1702c5SYu Xiangning if (optlen != sizeof (struct sctp_sndrcvinfo)) {
13450f1702c5SYu Xiangning error = EINVAL;
13460f1702c5SYu Xiangning eprintsoline(so, error);
13470f1702c5SYu Xiangning goto done;
13480f1702c5SYu Xiangning }
13490f1702c5SYu Xiangning id = ((struct sctp_sndrcvinfo *)
13500f1702c5SYu Xiangning optval)->sinfo_assoc_id;
13510f1702c5SYu Xiangning break;
13520f1702c5SYu Xiangning case SCTP_INITMSG:
13530f1702c5SYu Xiangning /*
13540f1702c5SYu Xiangning * Only applies to future associations
13550f1702c5SYu Xiangning */
13560f1702c5SYu Xiangning conn = so->so_proto_handle;
13570f1702c5SYu Xiangning break;
13580f1702c5SYu Xiangning default:
13590f1702c5SYu Xiangning break;
13600f1702c5SYu Xiangning }
13610f1702c5SYu Xiangning } else if (level == SOL_SOCKET) {
13620f1702c5SYu Xiangning if (option_name == SO_LINGER) {
13630f1702c5SYu Xiangning error = EOPNOTSUPP;
13640f1702c5SYu Xiangning eprintsoline(so, error);
13650f1702c5SYu Xiangning goto done;
13660f1702c5SYu Xiangning }
13670f1702c5SYu Xiangning /*
13680f1702c5SYu Xiangning * These 2 options are applied to all associations.
13690f1702c5SYu Xiangning * The other socket level options are only applied
13700f1702c5SYu Xiangning * to the socket (not associations).
13710f1702c5SYu Xiangning */
13720f1702c5SYu Xiangning if ((option_name != SO_RCVBUF) &&
13730f1702c5SYu Xiangning (option_name != SO_SNDBUF)) {
13740f1702c5SYu Xiangning conn = so->so_proto_handle;
13750f1702c5SYu Xiangning }
13760f1702c5SYu Xiangning } else {
13770f1702c5SYu Xiangning conn = NULL;
13780f1702c5SYu Xiangning }
13790f1702c5SYu Xiangning
13800f1702c5SYu Xiangning /*
13810f1702c5SYu Xiangning * If association ID was specified, do op on that assoc.
13820f1702c5SYu Xiangning * Otherwise set the default setting of a socket.
13830f1702c5SYu Xiangning */
13840f1702c5SYu Xiangning if (id != 0) {
13850f1702c5SYu Xiangning if ((error = sosctp_assoc(ss, id, &ssa)) != 0) {
13860f1702c5SYu Xiangning eprintsoline(so, error);
13870f1702c5SYu Xiangning goto done;
13880f1702c5SYu Xiangning }
13890f1702c5SYu Xiangning conn = ssa->ssa_conn;
13900f1702c5SYu Xiangning }
13910f1702c5SYu Xiangning }
13920f1702c5SYu Xiangning dprint(2, ("sosctp_setsockopt %p (%d) - conn %p %d %d id:%d\n",
13930f1702c5SYu Xiangning (void *)ss, so->so_type, (void *)conn, level, option_name, id));
13940f1702c5SYu Xiangning
13950f1702c5SYu Xiangning ASSERT(ssa == NULL || (ssa != NULL && conn != NULL));
13960f1702c5SYu Xiangning if (conn != NULL) {
13970f1702c5SYu Xiangning mutex_exit(&so->so_lock);
13980f1702c5SYu Xiangning error = sctp_set_opt((struct sctp_s *)conn, level, option_name,
13990f1702c5SYu Xiangning optval, optlen);
14000f1702c5SYu Xiangning mutex_enter(&so->so_lock);
14010f1702c5SYu Xiangning if (ssa != NULL)
14020f1702c5SYu Xiangning SSA_REFRELE(ss, ssa);
14030f1702c5SYu Xiangning } else {
14040f1702c5SYu Xiangning /*
14050f1702c5SYu Xiangning * 1-N socket, and we have to apply the operation to ALL
14060f1702c5SYu Xiangning * associations. Like with anything of this sort, the
14070f1702c5SYu Xiangning * problem is what to do if the operation fails.
14080f1702c5SYu Xiangning * Just try to apply the setting to everyone, but store
14090f1702c5SYu Xiangning * error number if someone returns such. And since we are
14100f1702c5SYu Xiangning * looping through all possible aids, some of them can be
14110f1702c5SYu Xiangning * invalid. We just ignore this kind (sosctp_assoc()) of
14120f1702c5SYu Xiangning * errors.
14130f1702c5SYu Xiangning */
14140f1702c5SYu Xiangning sctp_assoc_t aid;
14150f1702c5SYu Xiangning
14160f1702c5SYu Xiangning mutex_exit(&so->so_lock);
14170f1702c5SYu Xiangning error = sctp_set_opt((struct sctp_s *)so->so_proto_handle,
14180f1702c5SYu Xiangning level, option_name, optval, optlen);
14190f1702c5SYu Xiangning mutex_enter(&so->so_lock);
14200f1702c5SYu Xiangning for (aid = 1; aid < ss->ss_maxassoc; aid++) {
14210f1702c5SYu Xiangning if (sosctp_assoc(ss, aid, &ssa) != 0)
14220f1702c5SYu Xiangning continue;
14230f1702c5SYu Xiangning mutex_exit(&so->so_lock);
14240f1702c5SYu Xiangning rc = sctp_set_opt((struct sctp_s *)ssa->ssa_conn, level,
14250f1702c5SYu Xiangning option_name, optval, optlen);
14260f1702c5SYu Xiangning mutex_enter(&so->so_lock);
14270f1702c5SYu Xiangning SSA_REFRELE(ss, ssa);
14280f1702c5SYu Xiangning if (error == 0) {
14290f1702c5SYu Xiangning error = rc;
14300f1702c5SYu Xiangning }
14310f1702c5SYu Xiangning }
14320f1702c5SYu Xiangning }
14330f1702c5SYu Xiangning done:
14340f1702c5SYu Xiangning mutex_exit(&so->so_lock);
14350f1702c5SYu Xiangning return (error);
14360f1702c5SYu Xiangning }
14370f1702c5SYu Xiangning
14380f1702c5SYu Xiangning /*ARGSUSED*/
14390f1702c5SYu Xiangning static int
sosctp_ioctl(struct sonode * so,int cmd,intptr_t arg,int mode,struct cred * cr,int32_t * rvalp)14400f1702c5SYu Xiangning sosctp_ioctl(struct sonode *so, int cmd, intptr_t arg, int mode,
14410f1702c5SYu Xiangning struct cred *cr, int32_t *rvalp)
14420f1702c5SYu Xiangning {
14430f1702c5SYu Xiangning struct sctp_sonode *ss;
14440f1702c5SYu Xiangning int32_t value;
14450f1702c5SYu Xiangning int error;
14460f1702c5SYu Xiangning int intval;
14470f1702c5SYu Xiangning pid_t pid;
14480f1702c5SYu Xiangning struct sctp_soassoc *ssa;
14490f1702c5SYu Xiangning void *conn;
14500f1702c5SYu Xiangning void *buf;
14510f1702c5SYu Xiangning STRUCT_DECL(sctpopt, opt);
14520f1702c5SYu Xiangning uint32_t optlen;
14530f1702c5SYu Xiangning int buflen;
14540f1702c5SYu Xiangning
14550f1702c5SYu Xiangning ss = SOTOSSO(so);
14560f1702c5SYu Xiangning
14570f1702c5SYu Xiangning /* handle socket specific ioctls */
14580f1702c5SYu Xiangning switch (cmd) {
14590f1702c5SYu Xiangning case FIONBIO:
14600f1702c5SYu Xiangning if (so_copyin((void *)arg, &value, sizeof (int32_t),
14610f1702c5SYu Xiangning (mode & (int)FKIOCTL))) {
14620f1702c5SYu Xiangning return (EFAULT);
14630f1702c5SYu Xiangning }
14640f1702c5SYu Xiangning mutex_enter(&so->so_lock);
14650f1702c5SYu Xiangning if (value) {
14660f1702c5SYu Xiangning so->so_state |= SS_NDELAY;
14670f1702c5SYu Xiangning } else {
14680f1702c5SYu Xiangning so->so_state &= ~SS_NDELAY;
14690f1702c5SYu Xiangning }
14700f1702c5SYu Xiangning mutex_exit(&so->so_lock);
14710f1702c5SYu Xiangning return (0);
14720f1702c5SYu Xiangning
14730f1702c5SYu Xiangning case FIOASYNC:
14740f1702c5SYu Xiangning if (so_copyin((void *)arg, &value, sizeof (int32_t),
14750f1702c5SYu Xiangning (mode & (int)FKIOCTL))) {
14760f1702c5SYu Xiangning return (EFAULT);
14770f1702c5SYu Xiangning }
14780f1702c5SYu Xiangning mutex_enter(&so->so_lock);
14790f1702c5SYu Xiangning
14800f1702c5SYu Xiangning if (value) {
14810f1702c5SYu Xiangning /* Turn on SIGIO */
14820f1702c5SYu Xiangning so->so_state |= SS_ASYNC;
14830f1702c5SYu Xiangning } else {
14840f1702c5SYu Xiangning /* Turn off SIGIO */
14850f1702c5SYu Xiangning so->so_state &= ~SS_ASYNC;
14860f1702c5SYu Xiangning }
14870f1702c5SYu Xiangning mutex_exit(&so->so_lock);
14880f1702c5SYu Xiangning return (0);
14890f1702c5SYu Xiangning
14900f1702c5SYu Xiangning case SIOCSPGRP:
14910f1702c5SYu Xiangning case FIOSETOWN:
14920f1702c5SYu Xiangning if (so_copyin((void *)arg, &pid, sizeof (pid_t),
14930f1702c5SYu Xiangning (mode & (int)FKIOCTL))) {
14940f1702c5SYu Xiangning return (EFAULT);
14950f1702c5SYu Xiangning }
14960f1702c5SYu Xiangning mutex_enter(&so->so_lock);
14970f1702c5SYu Xiangning
14980f1702c5SYu Xiangning error = (pid != so->so_pgrp) ? socket_chgpgrp(so, pid) : 0;
14990f1702c5SYu Xiangning mutex_exit(&so->so_lock);
15000f1702c5SYu Xiangning return (error);
15010f1702c5SYu Xiangning
15020f1702c5SYu Xiangning case SIOCGPGRP:
15030f1702c5SYu Xiangning case FIOGETOWN:
15040f1702c5SYu Xiangning if (so_copyout(&so->so_pgrp, (void *)arg,
15050f1702c5SYu Xiangning sizeof (pid_t), (mode & (int)FKIOCTL)))
15060f1702c5SYu Xiangning return (EFAULT);
15070f1702c5SYu Xiangning return (0);
15080f1702c5SYu Xiangning
15090f1702c5SYu Xiangning case FIONREAD:
15100f1702c5SYu Xiangning /* XXX: Cannot be used unless standard buffer is used */
15110f1702c5SYu Xiangning /*
15120f1702c5SYu Xiangning * Return number of bytes of data in all data messages
15130f1702c5SYu Xiangning * in queue in "arg".
15140f1702c5SYu Xiangning * For stream socket, amount of available data.
15150f1702c5SYu Xiangning * For sock_dgram, # of available bytes + addresses.
15160f1702c5SYu Xiangning */
15170f1702c5SYu Xiangning intval = (so->so_state & SS_ACCEPTCONN) ? 0 :
15180f1702c5SYu Xiangning MIN(so->so_rcv_queued, INT_MAX);
15190f1702c5SYu Xiangning if (so_copyout(&intval, (void *)arg, sizeof (intval),
15200f1702c5SYu Xiangning (mode & (int)FKIOCTL)))
15210f1702c5SYu Xiangning return (EFAULT);
15220f1702c5SYu Xiangning return (0);
15230f1702c5SYu Xiangning case SIOCATMARK:
15240f1702c5SYu Xiangning /*
15250f1702c5SYu Xiangning * No support for urgent data.
15260f1702c5SYu Xiangning */
15270f1702c5SYu Xiangning intval = 0;
15280f1702c5SYu Xiangning
15290f1702c5SYu Xiangning if (so_copyout(&intval, (void *)arg, sizeof (int),
15300f1702c5SYu Xiangning (mode & (int)FKIOCTL)))
15310f1702c5SYu Xiangning return (EFAULT);
15320f1702c5SYu Xiangning return (0);
1533de8c4a14SErik Nordmark case _I_GETPEERCRED: {
1534de8c4a14SErik Nordmark int error = 0;
1535de8c4a14SErik Nordmark
1536de8c4a14SErik Nordmark if ((mode & FKIOCTL) == 0)
1537de8c4a14SErik Nordmark return (EINVAL);
1538de8c4a14SErik Nordmark
1539de8c4a14SErik Nordmark mutex_enter(&so->so_lock);
1540de8c4a14SErik Nordmark if ((so->so_mode & SM_CONNREQUIRED) == 0) {
1541de8c4a14SErik Nordmark error = ENOTSUP;
1542de8c4a14SErik Nordmark } else if ((so->so_state & SS_ISCONNECTED) == 0) {
1543de8c4a14SErik Nordmark error = ENOTCONN;
1544de8c4a14SErik Nordmark } else if (so->so_peercred != NULL) {
1545de8c4a14SErik Nordmark k_peercred_t *kp = (k_peercred_t *)arg;
1546de8c4a14SErik Nordmark kp->pc_cr = so->so_peercred;
1547de8c4a14SErik Nordmark kp->pc_cpid = so->so_cpid;
1548de8c4a14SErik Nordmark crhold(so->so_peercred);
1549de8c4a14SErik Nordmark } else {
1550de8c4a14SErik Nordmark error = EINVAL;
1551de8c4a14SErik Nordmark }
1552de8c4a14SErik Nordmark mutex_exit(&so->so_lock);
1553de8c4a14SErik Nordmark return (error);
1554de8c4a14SErik Nordmark }
15550f1702c5SYu Xiangning case SIOCSCTPGOPT:
15560f1702c5SYu Xiangning STRUCT_INIT(opt, mode);
15570f1702c5SYu Xiangning
15580f1702c5SYu Xiangning if (so_copyin((void *)arg, STRUCT_BUF(opt), STRUCT_SIZE(opt),
15590f1702c5SYu Xiangning (mode & (int)FKIOCTL))) {
15600f1702c5SYu Xiangning return (EFAULT);
15610f1702c5SYu Xiangning }
15620f1702c5SYu Xiangning if ((optlen = STRUCT_FGET(opt, sopt_len)) > SO_MAXARGSIZE)
15630f1702c5SYu Xiangning return (EINVAL);
15640f1702c5SYu Xiangning
15650f1702c5SYu Xiangning /*
15660f1702c5SYu Xiangning * Find the correct sctp_t based on whether it is 1-N socket
15670f1702c5SYu Xiangning * or not.
15680f1702c5SYu Xiangning */
15690f1702c5SYu Xiangning intval = STRUCT_FGET(opt, sopt_aid);
15700f1702c5SYu Xiangning mutex_enter(&so->so_lock);
15710f1702c5SYu Xiangning if ((so->so_type == SOCK_SEQPACKET) && intval) {
15720f1702c5SYu Xiangning if ((error = sosctp_assoc(ss, intval, &ssa)) != 0) {
15730f1702c5SYu Xiangning mutex_exit(&so->so_lock);
15740f1702c5SYu Xiangning return (error);
15750f1702c5SYu Xiangning }
15760f1702c5SYu Xiangning conn = ssa->ssa_conn;
15770f1702c5SYu Xiangning ASSERT(conn != NULL);
15780f1702c5SYu Xiangning } else {
15790f1702c5SYu Xiangning conn = so->so_proto_handle;
15800f1702c5SYu Xiangning ssa = NULL;
15810f1702c5SYu Xiangning }
15820f1702c5SYu Xiangning mutex_exit(&so->so_lock);
15830f1702c5SYu Xiangning
15840f1702c5SYu Xiangning /* Copyin the option buffer and then call sctp_get_opt(). */
15850f1702c5SYu Xiangning buflen = optlen;
15860f1702c5SYu Xiangning /* Let's allocate a buffer enough to hold an int */
15870f1702c5SYu Xiangning if (buflen < sizeof (uint32_t))
15880f1702c5SYu Xiangning buflen = sizeof (uint32_t);
15890f1702c5SYu Xiangning buf = kmem_alloc(buflen, KM_SLEEP);
15900f1702c5SYu Xiangning if (so_copyin(STRUCT_FGETP(opt, sopt_val), buf, optlen,
15910f1702c5SYu Xiangning (mode & (int)FKIOCTL))) {
15920f1702c5SYu Xiangning if (ssa != NULL) {
15930f1702c5SYu Xiangning mutex_enter(&so->so_lock);
15940f1702c5SYu Xiangning SSA_REFRELE(ss, ssa);
15950f1702c5SYu Xiangning mutex_exit(&so->so_lock);
15960f1702c5SYu Xiangning }
15970f1702c5SYu Xiangning kmem_free(buf, buflen);
15980f1702c5SYu Xiangning return (EFAULT);
15990f1702c5SYu Xiangning }
16000f1702c5SYu Xiangning /* The option level has to be IPPROTO_SCTP */
16010f1702c5SYu Xiangning error = sctp_get_opt((struct sctp_s *)conn, IPPROTO_SCTP,
16020f1702c5SYu Xiangning STRUCT_FGET(opt, sopt_name), buf, &optlen);
16030f1702c5SYu Xiangning if (ssa != NULL) {
16040f1702c5SYu Xiangning mutex_enter(&so->so_lock);
16050f1702c5SYu Xiangning SSA_REFRELE(ss, ssa);
16060f1702c5SYu Xiangning mutex_exit(&so->so_lock);
16070f1702c5SYu Xiangning }
16080f1702c5SYu Xiangning optlen = MIN(buflen, optlen);
16090f1702c5SYu Xiangning /* No error, copyout the result with the correct buf len. */
16100f1702c5SYu Xiangning if (error == 0) {
16110f1702c5SYu Xiangning STRUCT_FSET(opt, sopt_len, optlen);
16120f1702c5SYu Xiangning if (so_copyout(STRUCT_BUF(opt), (void *)arg,
16130f1702c5SYu Xiangning STRUCT_SIZE(opt), (mode & (int)FKIOCTL))) {
16140f1702c5SYu Xiangning error = EFAULT;
16150f1702c5SYu Xiangning } else if (so_copyout(buf, STRUCT_FGETP(opt, sopt_val),
16160f1702c5SYu Xiangning optlen, (mode & (int)FKIOCTL))) {
16170f1702c5SYu Xiangning error = EFAULT;
16180f1702c5SYu Xiangning }
16190f1702c5SYu Xiangning }
16200f1702c5SYu Xiangning kmem_free(buf, buflen);
16210f1702c5SYu Xiangning return (error);
16220f1702c5SYu Xiangning
16230f1702c5SYu Xiangning case SIOCSCTPSOPT:
16240f1702c5SYu Xiangning STRUCT_INIT(opt, mode);
16250f1702c5SYu Xiangning
16260f1702c5SYu Xiangning if (so_copyin((void *)arg, STRUCT_BUF(opt), STRUCT_SIZE(opt),
16270f1702c5SYu Xiangning (mode & (int)FKIOCTL))) {
16280f1702c5SYu Xiangning return (EFAULT);
16290f1702c5SYu Xiangning }
16300f1702c5SYu Xiangning if ((optlen = STRUCT_FGET(opt, sopt_len)) > SO_MAXARGSIZE)
16310f1702c5SYu Xiangning return (EINVAL);
16320f1702c5SYu Xiangning
16330f1702c5SYu Xiangning /*
16340f1702c5SYu Xiangning * Find the correct sctp_t based on whether it is 1-N socket
16350f1702c5SYu Xiangning * or not.
16360f1702c5SYu Xiangning */
16370f1702c5SYu Xiangning intval = STRUCT_FGET(opt, sopt_aid);
16380f1702c5SYu Xiangning mutex_enter(&so->so_lock);
16390f1702c5SYu Xiangning if (intval != 0) {
16400f1702c5SYu Xiangning if ((error = sosctp_assoc(ss, intval, &ssa)) != 0) {
16410f1702c5SYu Xiangning mutex_exit(&so->so_lock);
16420f1702c5SYu Xiangning return (error);
16430f1702c5SYu Xiangning }
16440f1702c5SYu Xiangning conn = ssa->ssa_conn;
16450f1702c5SYu Xiangning ASSERT(conn != NULL);
16460f1702c5SYu Xiangning } else {
16470f1702c5SYu Xiangning conn = so->so_proto_handle;
16480f1702c5SYu Xiangning ssa = NULL;
16490f1702c5SYu Xiangning }
16500f1702c5SYu Xiangning mutex_exit(&so->so_lock);
16510f1702c5SYu Xiangning
16520f1702c5SYu Xiangning /* Copyin the option buffer and then call sctp_set_opt(). */
16530f1702c5SYu Xiangning buf = kmem_alloc(optlen, KM_SLEEP);
16540f1702c5SYu Xiangning if (so_copyin(STRUCT_FGETP(opt, sopt_val), buf, optlen,
16550f1702c5SYu Xiangning (mode & (int)FKIOCTL))) {
16560f1702c5SYu Xiangning if (ssa != NULL) {
16570f1702c5SYu Xiangning mutex_enter(&so->so_lock);
16580f1702c5SYu Xiangning SSA_REFRELE(ss, ssa);
16590f1702c5SYu Xiangning mutex_exit(&so->so_lock);
16600f1702c5SYu Xiangning }
16610f1702c5SYu Xiangning kmem_free(buf, intval);
16620f1702c5SYu Xiangning return (EFAULT);
16630f1702c5SYu Xiangning }
16640f1702c5SYu Xiangning /* The option level has to be IPPROTO_SCTP */
16650f1702c5SYu Xiangning error = sctp_set_opt((struct sctp_s *)conn, IPPROTO_SCTP,
16660f1702c5SYu Xiangning STRUCT_FGET(opt, sopt_name), buf, optlen);
16670f1702c5SYu Xiangning if (ssa) {
16680f1702c5SYu Xiangning mutex_enter(&so->so_lock);
16690f1702c5SYu Xiangning SSA_REFRELE(ss, ssa);
16700f1702c5SYu Xiangning mutex_exit(&so->so_lock);
16710f1702c5SYu Xiangning }
16720f1702c5SYu Xiangning kmem_free(buf, optlen);
16730f1702c5SYu Xiangning return (error);
16740f1702c5SYu Xiangning
16750f1702c5SYu Xiangning case SIOCSCTPPEELOFF: {
16760f1702c5SYu Xiangning struct sonode *nso;
16770f1702c5SYu Xiangning struct sctp_uc_swap us;
16780f1702c5SYu Xiangning int nfd;
16790f1702c5SYu Xiangning struct file *nfp;
16800f1702c5SYu Xiangning struct vnode *nvp = NULL;
16810f1702c5SYu Xiangning struct sockparams *sp;
16820f1702c5SYu Xiangning
16830f1702c5SYu Xiangning dprint(2, ("sctppeeloff %p\n", (void *)ss));
16840f1702c5SYu Xiangning
16850f1702c5SYu Xiangning if (so->so_type != SOCK_SEQPACKET) {
16860f1702c5SYu Xiangning return (EOPNOTSUPP);
16870f1702c5SYu Xiangning }
16880f1702c5SYu Xiangning if (so_copyin((void *)arg, &intval, sizeof (intval),
16890f1702c5SYu Xiangning (mode & (int)FKIOCTL))) {
16900f1702c5SYu Xiangning return (EFAULT);
16910f1702c5SYu Xiangning }
16920f1702c5SYu Xiangning if (intval == 0) {
16930f1702c5SYu Xiangning return (EINVAL);
16940f1702c5SYu Xiangning }
16950f1702c5SYu Xiangning
16960f1702c5SYu Xiangning /*
16970f1702c5SYu Xiangning * Find sockparams. This is different from parent's entry,
16980f1702c5SYu Xiangning * as the socket type is different.
16990f1702c5SYu Xiangning */
17000f1702c5SYu Xiangning error = solookup(so->so_family, SOCK_STREAM, so->so_protocol,
17010f1702c5SYu Xiangning &sp);
1702e4b767e8SAnders Persson if (error != 0)
1703e4b767e8SAnders Persson return (error);
17040f1702c5SYu Xiangning
17050f1702c5SYu Xiangning /*
17060f1702c5SYu Xiangning * Allocate the user fd.
17070f1702c5SYu Xiangning */
17080f1702c5SYu Xiangning if ((nfd = ufalloc(0)) == -1) {
17090f1702c5SYu Xiangning eprintsoline(so, EMFILE);
171024101488SAnders Persson SOCKPARAMS_DEC_REF(sp);
17110f1702c5SYu Xiangning return (EMFILE);
17120f1702c5SYu Xiangning }
17130f1702c5SYu Xiangning
17140f1702c5SYu Xiangning /*
17150f1702c5SYu Xiangning * Copy the fd out.
17160f1702c5SYu Xiangning */
17170f1702c5SYu Xiangning if (so_copyout(&nfd, (void *)arg, sizeof (nfd),
17180f1702c5SYu Xiangning (mode & (int)FKIOCTL))) {
17190f1702c5SYu Xiangning error = EFAULT;
17200f1702c5SYu Xiangning goto err;
17210f1702c5SYu Xiangning }
17220f1702c5SYu Xiangning mutex_enter(&so->so_lock);
17230f1702c5SYu Xiangning
17240f1702c5SYu Xiangning /*
17250f1702c5SYu Xiangning * Don't use sosctp_assoc() in order to peel off disconnected
17260f1702c5SYu Xiangning * associations.
17270f1702c5SYu Xiangning */
17280f1702c5SYu Xiangning ssa = ((uint32_t)intval >= ss->ss_maxassoc) ? NULL :
17290f1702c5SYu Xiangning ss->ss_assocs[intval].ssi_assoc;
17300f1702c5SYu Xiangning if (ssa == NULL) {
17310f1702c5SYu Xiangning mutex_exit(&so->so_lock);
17320f1702c5SYu Xiangning error = EINVAL;
17330f1702c5SYu Xiangning goto err;
17340f1702c5SYu Xiangning }
17350f1702c5SYu Xiangning SSA_REFHOLD(ssa);
17360f1702c5SYu Xiangning
17370f1702c5SYu Xiangning nso = socksctp_create(sp, so->so_family, SOCK_STREAM,
17380f1702c5SYu Xiangning so->so_protocol, so->so_version, SOCKET_NOSLEEP,
17390f1702c5SYu Xiangning &error, cr);
17400f1702c5SYu Xiangning if (nso == NULL) {
17410f1702c5SYu Xiangning SSA_REFRELE(ss, ssa);
17420f1702c5SYu Xiangning mutex_exit(&so->so_lock);
17430f1702c5SYu Xiangning goto err;
17440f1702c5SYu Xiangning }
17450f1702c5SYu Xiangning nvp = SOTOV(nso);
17460f1702c5SYu Xiangning so_lock_single(so);
17470f1702c5SYu Xiangning mutex_exit(&so->so_lock);
1748e4b767e8SAnders Persson
1749e4b767e8SAnders Persson /* cannot fail, only inheriting properties */
1750e4b767e8SAnders Persson (void) sosctp_init(nso, so, CRED(), 0);
1751e4b767e8SAnders Persson
1752e4b767e8SAnders Persson /*
1753e4b767e8SAnders Persson * We have a single ref on the new socket. This is normally
1754e4b767e8SAnders Persson * handled by socket_{create,newconn}, but since they are not
1755e4b767e8SAnders Persson * used we have to do it here.
1756e4b767e8SAnders Persson */
1757e4b767e8SAnders Persson nso->so_count = 1;
1758e4b767e8SAnders Persson
1759e4b767e8SAnders Persson us.sus_handle = nso;
17600f1702c5SYu Xiangning us.sus_upcalls = &sosctp_sock_upcalls;
17610f1702c5SYu Xiangning
17620f1702c5SYu Xiangning /*
17630f1702c5SYu Xiangning * Upcalls to new socket are blocked for the duration of
17640f1702c5SYu Xiangning * downcall.
17650f1702c5SYu Xiangning */
17660f1702c5SYu Xiangning mutex_enter(&nso->so_lock);
17670f1702c5SYu Xiangning
17680f1702c5SYu Xiangning error = sctp_set_opt((struct sctp_s *)ssa->ssa_conn,
17690f1702c5SYu Xiangning IPPROTO_SCTP, SCTP_UC_SWAP, &us, sizeof (us));
17700f1702c5SYu Xiangning if (error) {
17710f1702c5SYu Xiangning goto peelerr;
17720f1702c5SYu Xiangning }
17730f1702c5SYu Xiangning error = falloc(nvp, FWRITE|FREAD, &nfp, NULL);
17740f1702c5SYu Xiangning if (error) {
17750f1702c5SYu Xiangning goto peelerr;
17760f1702c5SYu Xiangning }
17770f1702c5SYu Xiangning
17780f1702c5SYu Xiangning /*
17790f1702c5SYu Xiangning * fill in the entries that falloc reserved
17800f1702c5SYu Xiangning */
17810f1702c5SYu Xiangning nfp->f_vnode = nvp;
17820f1702c5SYu Xiangning mutex_exit(&nfp->f_tlock);
17830f1702c5SYu Xiangning setf(nfd, nfp);
17840f1702c5SYu Xiangning
17850f1702c5SYu Xiangning mutex_enter(&so->so_lock);
17860f1702c5SYu Xiangning
17870f1702c5SYu Xiangning sosctp_assoc_move(ss, SOTOSSO(nso), ssa);
17880f1702c5SYu Xiangning
17890f1702c5SYu Xiangning mutex_exit(&nso->so_lock);
17900f1702c5SYu Xiangning
17910f1702c5SYu Xiangning ssa->ssa_conn = NULL;
17920f1702c5SYu Xiangning sosctp_assoc_free(ss, ssa);
17930f1702c5SYu Xiangning
17940f1702c5SYu Xiangning so_unlock_single(so, SOLOCKED);
17950f1702c5SYu Xiangning mutex_exit(&so->so_lock);
17960f1702c5SYu Xiangning
17970f1702c5SYu Xiangning return (0);
17980f1702c5SYu Xiangning
17990f1702c5SYu Xiangning err:
180024101488SAnders Persson SOCKPARAMS_DEC_REF(sp);
18010f1702c5SYu Xiangning setf(nfd, NULL);
18020f1702c5SYu Xiangning eprintsoline(so, error);
18030f1702c5SYu Xiangning return (error);
18040f1702c5SYu Xiangning
18050f1702c5SYu Xiangning peelerr:
18060f1702c5SYu Xiangning mutex_exit(&nso->so_lock);
18070f1702c5SYu Xiangning mutex_enter(&so->so_lock);
18080f1702c5SYu Xiangning ASSERT(nso->so_count == 1);
18090f1702c5SYu Xiangning nso->so_count = 0;
18100f1702c5SYu Xiangning so_unlock_single(so, SOLOCKED);
18110f1702c5SYu Xiangning SSA_REFRELE(ss, ssa);
18120f1702c5SYu Xiangning mutex_exit(&so->so_lock);
18130f1702c5SYu Xiangning
18140f1702c5SYu Xiangning setf(nfd, NULL);
18150f1702c5SYu Xiangning ASSERT(nvp->v_count == 1);
18160f1702c5SYu Xiangning socket_destroy(nso);
18170f1702c5SYu Xiangning eprintsoline(so, error);
18180f1702c5SYu Xiangning return (error);
18190f1702c5SYu Xiangning }
18200f1702c5SYu Xiangning default:
18210f1702c5SYu Xiangning return (EINVAL);
18220f1702c5SYu Xiangning }
18230f1702c5SYu Xiangning }
18240f1702c5SYu Xiangning
18250f1702c5SYu Xiangning /*ARGSUSED*/
18260f1702c5SYu Xiangning static int
sosctp_close(struct sonode * so,int flag,struct cred * cr)18270f1702c5SYu Xiangning sosctp_close(struct sonode *so, int flag, struct cred *cr)
18280f1702c5SYu Xiangning {
18290f1702c5SYu Xiangning struct sctp_sonode *ss;
18300f1702c5SYu Xiangning struct sctp_sa_id *ssi;
18310f1702c5SYu Xiangning struct sctp_soassoc *ssa;
18320f1702c5SYu Xiangning int32_t i;
18330f1702c5SYu Xiangning
18340f1702c5SYu Xiangning ss = SOTOSSO(so);
18350f1702c5SYu Xiangning
18360f1702c5SYu Xiangning /*
1837a215d4ebSKacheong Poon * Initiate connection shutdown. Tell SCTP if there is any data
1838a215d4ebSKacheong Poon * left unread.
18390f1702c5SYu Xiangning */
18400f1702c5SYu Xiangning sctp_recvd((struct sctp_s *)so->so_proto_handle,
18410f1702c5SYu Xiangning so->so_rcvbuf - so->so_rcv_queued);
18420f1702c5SYu Xiangning (void) sctp_disconnect((struct sctp_s *)so->so_proto_handle);
18430f1702c5SYu Xiangning
18440f1702c5SYu Xiangning /*
18450f1702c5SYu Xiangning * New associations can't come in, but old ones might get
18460f1702c5SYu Xiangning * closed in upcall. Protect against that by taking a reference
18470f1702c5SYu Xiangning * on the association.
18480f1702c5SYu Xiangning */
18490f1702c5SYu Xiangning mutex_enter(&so->so_lock);
18500f1702c5SYu Xiangning ssi = ss->ss_assocs;
18510f1702c5SYu Xiangning for (i = 0; i < ss->ss_maxassoc; i++, ssi++) {
18520f1702c5SYu Xiangning if ((ssa = ssi->ssi_assoc) != NULL) {
18530f1702c5SYu Xiangning SSA_REFHOLD(ssa);
18540f1702c5SYu Xiangning sosctp_assoc_isdisconnected(ssa, 0);
18550f1702c5SYu Xiangning mutex_exit(&so->so_lock);
18560f1702c5SYu Xiangning
1857a215d4ebSKacheong Poon sctp_recvd(ssa->ssa_conn, so->so_rcvbuf -
1858a215d4ebSKacheong Poon ssa->ssa_rcv_queued);
1859a215d4ebSKacheong Poon (void) sctp_disconnect(ssa->ssa_conn);
18600f1702c5SYu Xiangning
18610f1702c5SYu Xiangning mutex_enter(&so->so_lock);
18620f1702c5SYu Xiangning SSA_REFRELE(ss, ssa);
18630f1702c5SYu Xiangning }
18640f1702c5SYu Xiangning }
18650f1702c5SYu Xiangning mutex_exit(&so->so_lock);
18660f1702c5SYu Xiangning
18670f1702c5SYu Xiangning return (0);
18680f1702c5SYu Xiangning }
18690f1702c5SYu Xiangning
18700f1702c5SYu Xiangning /*
18710f1702c5SYu Xiangning * Closes incoming connections which were never accepted, frees
18720f1702c5SYu Xiangning * resources.
18730f1702c5SYu Xiangning */
18740f1702c5SYu Xiangning /* ARGSUSED */
18750f1702c5SYu Xiangning void
sosctp_fini(struct sonode * so,struct cred * cr)18760f1702c5SYu Xiangning sosctp_fini(struct sonode *so, struct cred *cr)
18770f1702c5SYu Xiangning {
18780f1702c5SYu Xiangning struct sctp_sonode *ss;
18790f1702c5SYu Xiangning struct sctp_sa_id *ssi;
18800f1702c5SYu Xiangning struct sctp_soassoc *ssa;
18810f1702c5SYu Xiangning int32_t i;
18820f1702c5SYu Xiangning
18830f1702c5SYu Xiangning ss = SOTOSSO(so);
18840f1702c5SYu Xiangning
18850f1702c5SYu Xiangning ASSERT(so->so_ops == &sosctp_sonodeops ||
18860f1702c5SYu Xiangning so->so_ops == &sosctp_seq_sonodeops);
18870f1702c5SYu Xiangning
18880f1702c5SYu Xiangning /* We are the sole owner of so now */
18890f1702c5SYu Xiangning mutex_enter(&so->so_lock);
18900f1702c5SYu Xiangning
18910f1702c5SYu Xiangning /* Free all pending connections */
18922320a8c1SAnders Persson so_acceptq_flush(so, B_TRUE);
18930f1702c5SYu Xiangning
18940f1702c5SYu Xiangning ssi = ss->ss_assocs;
18950f1702c5SYu Xiangning for (i = 0; i < ss->ss_maxassoc; i++, ssi++) {
18960f1702c5SYu Xiangning if ((ssa = ssi->ssi_assoc) != NULL) {
18970f1702c5SYu Xiangning SSA_REFHOLD(ssa);
18980f1702c5SYu Xiangning mutex_exit(&so->so_lock);
18990f1702c5SYu Xiangning
19000f1702c5SYu Xiangning sctp_close((struct sctp_s *)ssa->ssa_conn);
19010f1702c5SYu Xiangning
19020f1702c5SYu Xiangning mutex_enter(&so->so_lock);
19030f1702c5SYu Xiangning ssa->ssa_conn = NULL;
19040f1702c5SYu Xiangning sosctp_assoc_free(ss, ssa);
19050f1702c5SYu Xiangning }
19060f1702c5SYu Xiangning }
19070f1702c5SYu Xiangning if (ss->ss_assocs != NULL) {
19080f1702c5SYu Xiangning ASSERT(ss->ss_assoccnt == 0);
19090f1702c5SYu Xiangning kmem_free(ss->ss_assocs,
19100f1702c5SYu Xiangning ss->ss_maxassoc * sizeof (struct sctp_sa_id));
19110f1702c5SYu Xiangning }
19120f1702c5SYu Xiangning mutex_exit(&so->so_lock);
19130f1702c5SYu Xiangning
19140f1702c5SYu Xiangning if (so->so_proto_handle)
19150f1702c5SYu Xiangning sctp_close((struct sctp_s *)so->so_proto_handle);
19160f1702c5SYu Xiangning so->so_proto_handle = NULL;
19170f1702c5SYu Xiangning
1918a215d4ebSKacheong Poon /*
1919a215d4ebSKacheong Poon * Note until sctp_close() is called, SCTP can still send up
1920a215d4ebSKacheong Poon * messages, such as event notifications. So we should flush
1921a215d4ebSKacheong Poon * the recevie buffer after calling sctp_close().
1922a215d4ebSKacheong Poon */
1923a215d4ebSKacheong Poon mutex_enter(&so->so_lock);
1924a215d4ebSKacheong Poon so_rcv_flush(so);
1925a215d4ebSKacheong Poon mutex_exit(&so->so_lock);
1926a215d4ebSKacheong Poon
19270f1702c5SYu Xiangning sonode_fini(so);
19280f1702c5SYu Xiangning }
19290f1702c5SYu Xiangning
19300f1702c5SYu Xiangning /*
19310f1702c5SYu Xiangning * Upcalls from SCTP
19320f1702c5SYu Xiangning */
19330f1702c5SYu Xiangning
19340f1702c5SYu Xiangning /*
19350f1702c5SYu Xiangning * This is the upcall function for 1-N (SOCK_SEQPACKET) socket when a new
19360f1702c5SYu Xiangning * association is created. Note that the first argument (handle) is of type
19370f1702c5SYu Xiangning * sctp_sonode *, which is the one changed to a listener for new
19380f1702c5SYu Xiangning * associations. All the other upcalls for 1-N socket take sctp_soassoc *
19390f1702c5SYu Xiangning * as handle. The only exception is the su_properties upcall, which
19400f1702c5SYu Xiangning * can take both types as handle.
19410f1702c5SYu Xiangning */
19420f1702c5SYu Xiangning /* ARGSUSED */
19430f1702c5SYu Xiangning sock_upper_handle_t
sctp_assoc_newconn(sock_upper_handle_t parenthandle,sock_lower_handle_t connind,sock_downcalls_t * dc,struct cred * peer_cred,pid_t peer_cpid,sock_upcalls_t ** ucp)19440f1702c5SYu Xiangning sctp_assoc_newconn(sock_upper_handle_t parenthandle,
19450f1702c5SYu Xiangning sock_lower_handle_t connind, sock_downcalls_t *dc,
19460f1702c5SYu Xiangning struct cred *peer_cred, pid_t peer_cpid, sock_upcalls_t **ucp)
19470f1702c5SYu Xiangning {
1948a215d4ebSKacheong Poon struct sctp_sonode *lss = (struct sctp_sonode *)parenthandle;
1949a215d4ebSKacheong Poon struct sonode *lso = &lss->ss_so;
19500f1702c5SYu Xiangning struct sctp_soassoc *ssa;
19510f1702c5SYu Xiangning sctp_assoc_t id;
19520f1702c5SYu Xiangning
19530f1702c5SYu Xiangning ASSERT(lss->ss_type == SOSCTP_SOCKET);
19540f1702c5SYu Xiangning ASSERT(lso->so_state & SS_ACCEPTCONN);
19550f1702c5SYu Xiangning ASSERT(lso->so_proto_handle != NULL); /* closed conn */
19560f1702c5SYu Xiangning ASSERT(lso->so_type == SOCK_SEQPACKET);
19570f1702c5SYu Xiangning
19580f1702c5SYu Xiangning mutex_enter(&lso->so_lock);
19590f1702c5SYu Xiangning
19600f1702c5SYu Xiangning if ((id = sosctp_aid_get(lss)) == -1) {
19610f1702c5SYu Xiangning /*
19620f1702c5SYu Xiangning * Array not large enough; increase size.
19630f1702c5SYu Xiangning */
19640f1702c5SYu Xiangning if (sosctp_aid_grow(lss, lss->ss_maxassoc, KM_NOSLEEP) < 0) {
19650f1702c5SYu Xiangning mutex_exit(&lso->so_lock);
19660f1702c5SYu Xiangning return (NULL);
19670f1702c5SYu Xiangning }
19680f1702c5SYu Xiangning id = sosctp_aid_get(lss);
19690f1702c5SYu Xiangning ASSERT(id != -1);
19700f1702c5SYu Xiangning }
19710f1702c5SYu Xiangning
19720f1702c5SYu Xiangning /*
19730f1702c5SYu Xiangning * Create soassoc for this connection
19740f1702c5SYu Xiangning */
19750f1702c5SYu Xiangning ssa = sosctp_assoc_create(lss, KM_NOSLEEP);
19760f1702c5SYu Xiangning if (ssa == NULL) {
19770f1702c5SYu Xiangning mutex_exit(&lso->so_lock);
19780f1702c5SYu Xiangning return (NULL);
19790f1702c5SYu Xiangning }
19800f1702c5SYu Xiangning sosctp_aid_reserve(lss, id, 1);
19810f1702c5SYu Xiangning lss->ss_assocs[id].ssi_assoc = ssa;
19820f1702c5SYu Xiangning ++lss->ss_assoccnt;
19830f1702c5SYu Xiangning ssa->ssa_id = id;
19840f1702c5SYu Xiangning ssa->ssa_conn = (struct sctp_s *)connind;
19850f1702c5SYu Xiangning ssa->ssa_state = (SS_ISBOUND | SS_ISCONNECTED);
19860f1702c5SYu Xiangning ssa->ssa_wroff = lss->ss_wroff;
19870f1702c5SYu Xiangning ssa->ssa_wrsize = lss->ss_wrsize;
19880f1702c5SYu Xiangning
19890f1702c5SYu Xiangning mutex_exit(&lso->so_lock);
19900f1702c5SYu Xiangning
19910f1702c5SYu Xiangning *ucp = &sosctp_assoc_upcalls;
19920f1702c5SYu Xiangning
19930f1702c5SYu Xiangning return ((sock_upper_handle_t)ssa);
19940f1702c5SYu Xiangning }
19950f1702c5SYu Xiangning
19960f1702c5SYu Xiangning /* ARGSUSED */
19970f1702c5SYu Xiangning static void
sctp_assoc_connected(sock_upper_handle_t handle,sock_connid_t id,struct cred * peer_cred,pid_t peer_cpid)19980f1702c5SYu Xiangning sctp_assoc_connected(sock_upper_handle_t handle, sock_connid_t id,
19990f1702c5SYu Xiangning struct cred *peer_cred, pid_t peer_cpid)
20000f1702c5SYu Xiangning {
20010f1702c5SYu Xiangning struct sctp_soassoc *ssa = (struct sctp_soassoc *)handle;
20020f1702c5SYu Xiangning struct sonode *so = &ssa->ssa_sonode->ss_so;
20030f1702c5SYu Xiangning
20040f1702c5SYu Xiangning ASSERT(so->so_type == SOCK_SEQPACKET);
20050f1702c5SYu Xiangning ASSERT(ssa->ssa_conn);
20060f1702c5SYu Xiangning
20070f1702c5SYu Xiangning mutex_enter(&so->so_lock);
20080f1702c5SYu Xiangning sosctp_assoc_isconnected(ssa);
20090f1702c5SYu Xiangning mutex_exit(&so->so_lock);
20100f1702c5SYu Xiangning }
20110f1702c5SYu Xiangning
20120f1702c5SYu Xiangning /* ARGSUSED */
20130f1702c5SYu Xiangning static int
sctp_assoc_disconnected(sock_upper_handle_t handle,sock_connid_t id,int error)20140f1702c5SYu Xiangning sctp_assoc_disconnected(sock_upper_handle_t handle, sock_connid_t id, int error)
20150f1702c5SYu Xiangning {
20160f1702c5SYu Xiangning struct sctp_soassoc *ssa = (struct sctp_soassoc *)handle;
20170f1702c5SYu Xiangning struct sonode *so = &ssa->ssa_sonode->ss_so;
20180f1702c5SYu Xiangning int ret;
20190f1702c5SYu Xiangning
20200f1702c5SYu Xiangning ASSERT(so->so_type == SOCK_SEQPACKET);
20210f1702c5SYu Xiangning ASSERT(ssa->ssa_conn != NULL);
20220f1702c5SYu Xiangning
20230f1702c5SYu Xiangning mutex_enter(&so->so_lock);
20240f1702c5SYu Xiangning sosctp_assoc_isdisconnected(ssa, error);
20250f1702c5SYu Xiangning if (ssa->ssa_refcnt == 1) {
20260f1702c5SYu Xiangning ret = 1;
20270f1702c5SYu Xiangning ssa->ssa_conn = NULL;
20280f1702c5SYu Xiangning } else {
20290f1702c5SYu Xiangning ret = 0;
20300f1702c5SYu Xiangning }
20310f1702c5SYu Xiangning SSA_REFRELE(SOTOSSO(so), ssa);
20320f1702c5SYu Xiangning
20330f1702c5SYu Xiangning cv_broadcast(&so->so_snd_cv);
20340f1702c5SYu Xiangning
20350f1702c5SYu Xiangning mutex_exit(&so->so_lock);
20360f1702c5SYu Xiangning
20370f1702c5SYu Xiangning return (ret);
20380f1702c5SYu Xiangning }
20390f1702c5SYu Xiangning
20400f1702c5SYu Xiangning /* ARGSUSED */
20410f1702c5SYu Xiangning static void
sctp_assoc_disconnecting(sock_upper_handle_t handle,sock_opctl_action_t action,uintptr_t arg)20420f1702c5SYu Xiangning sctp_assoc_disconnecting(sock_upper_handle_t handle, sock_opctl_action_t action,
20430f1702c5SYu Xiangning uintptr_t arg)
20440f1702c5SYu Xiangning {
20450f1702c5SYu Xiangning struct sctp_soassoc *ssa = (struct sctp_soassoc *)handle;
20460f1702c5SYu Xiangning struct sonode *so = &ssa->ssa_sonode->ss_so;
20470f1702c5SYu Xiangning
20480f1702c5SYu Xiangning ASSERT(so->so_type == SOCK_SEQPACKET);
20490f1702c5SYu Xiangning ASSERT(ssa->ssa_conn != NULL);
20500f1702c5SYu Xiangning ASSERT(action == SOCK_OPCTL_SHUT_SEND);
20510f1702c5SYu Xiangning
20520f1702c5SYu Xiangning mutex_enter(&so->so_lock);
20530f1702c5SYu Xiangning sosctp_assoc_isdisconnecting(ssa);
20540f1702c5SYu Xiangning mutex_exit(&so->so_lock);
20550f1702c5SYu Xiangning }
20560f1702c5SYu Xiangning
20570f1702c5SYu Xiangning /* ARGSUSED */
20580f1702c5SYu Xiangning static ssize_t
sctp_assoc_recv(sock_upper_handle_t handle,mblk_t * mp,size_t len,int flags,int * errorp,boolean_t * forcepush)20590f1702c5SYu Xiangning sctp_assoc_recv(sock_upper_handle_t handle, mblk_t *mp, size_t len, int flags,
20600f1702c5SYu Xiangning int *errorp, boolean_t *forcepush)
20610f1702c5SYu Xiangning {
20620f1702c5SYu Xiangning struct sctp_soassoc *ssa = (struct sctp_soassoc *)handle;
20630f1702c5SYu Xiangning struct sctp_sonode *ss = ssa->ssa_sonode;
20640f1702c5SYu Xiangning struct sonode *so = &ss->ss_so;
20650f1702c5SYu Xiangning struct T_unitdata_ind *tind;
20660f1702c5SYu Xiangning mblk_t *mp2;
20670f1702c5SYu Xiangning union sctp_notification *sn;
20680f1702c5SYu Xiangning struct sctp_sndrcvinfo *sinfo;
2069419dcee7SAnders Persson ssize_t space_available;
20700f1702c5SYu Xiangning
20710f1702c5SYu Xiangning ASSERT(ssa->ssa_type == SOSCTP_ASSOC);
20720f1702c5SYu Xiangning ASSERT(so->so_type == SOCK_SEQPACKET);
20730f1702c5SYu Xiangning ASSERT(ssa->ssa_conn != NULL); /* closed conn */
20740f1702c5SYu Xiangning ASSERT(mp != NULL);
20750f1702c5SYu Xiangning
20760f1702c5SYu Xiangning ASSERT(errorp != NULL);
20770f1702c5SYu Xiangning *errorp = 0;
20780f1702c5SYu Xiangning
20790f1702c5SYu Xiangning /*
20800f1702c5SYu Xiangning * Should be getting T_unitdata_req's only.
20810f1702c5SYu Xiangning * Must have address as part of packet.
20820f1702c5SYu Xiangning */
20830f1702c5SYu Xiangning tind = (struct T_unitdata_ind *)mp->b_rptr;
20840f1702c5SYu Xiangning ASSERT((DB_TYPE(mp) == M_PROTO) &&
20850f1702c5SYu Xiangning (tind->PRIM_type == T_UNITDATA_IND));
20860f1702c5SYu Xiangning ASSERT(tind->SRC_length);
20870f1702c5SYu Xiangning
20880f1702c5SYu Xiangning mutex_enter(&so->so_lock);
20890f1702c5SYu Xiangning
20900f1702c5SYu Xiangning /*
20910f1702c5SYu Xiangning * For notify messages, need to fill in association id.
20920f1702c5SYu Xiangning * For data messages, sndrcvinfo could be in ancillary data.
20930f1702c5SYu Xiangning */
2094866a73c2SRao Shoaib if (mp->b_flag & SCTP_NOTIFICATION) {
20950f1702c5SYu Xiangning mp2 = mp->b_cont;
20960f1702c5SYu Xiangning sn = (union sctp_notification *)mp2->b_rptr;
20970f1702c5SYu Xiangning switch (sn->sn_header.sn_type) {
20980f1702c5SYu Xiangning case SCTP_ASSOC_CHANGE:
20990f1702c5SYu Xiangning sn->sn_assoc_change.sac_assoc_id = ssa->ssa_id;
21000f1702c5SYu Xiangning break;
21010f1702c5SYu Xiangning case SCTP_PEER_ADDR_CHANGE:
21020f1702c5SYu Xiangning sn->sn_paddr_change.spc_assoc_id = ssa->ssa_id;
21030f1702c5SYu Xiangning break;
21040f1702c5SYu Xiangning case SCTP_REMOTE_ERROR:
21050f1702c5SYu Xiangning sn->sn_remote_error.sre_assoc_id = ssa->ssa_id;
21060f1702c5SYu Xiangning break;
21070f1702c5SYu Xiangning case SCTP_SEND_FAILED:
21080f1702c5SYu Xiangning sn->sn_send_failed.ssf_assoc_id = ssa->ssa_id;
21090f1702c5SYu Xiangning break;
21100f1702c5SYu Xiangning case SCTP_SHUTDOWN_EVENT:
21110f1702c5SYu Xiangning sn->sn_shutdown_event.sse_assoc_id = ssa->ssa_id;
21120f1702c5SYu Xiangning break;
21130f1702c5SYu Xiangning case SCTP_ADAPTATION_INDICATION:
21140f1702c5SYu Xiangning sn->sn_adaptation_event.sai_assoc_id = ssa->ssa_id;
21150f1702c5SYu Xiangning break;
21160f1702c5SYu Xiangning case SCTP_PARTIAL_DELIVERY_EVENT:
21170f1702c5SYu Xiangning sn->sn_pdapi_event.pdapi_assoc_id = ssa->ssa_id;
21180f1702c5SYu Xiangning break;
21190f1702c5SYu Xiangning default:
21200f1702c5SYu Xiangning ASSERT(0);
21210f1702c5SYu Xiangning break;
21220f1702c5SYu Xiangning }
21230f1702c5SYu Xiangning } else {
21240f1702c5SYu Xiangning if (tind->OPT_length > 0) {
21250f1702c5SYu Xiangning struct cmsghdr *cmsg;
21260f1702c5SYu Xiangning char *cend;
21270f1702c5SYu Xiangning
21280f1702c5SYu Xiangning cmsg = (struct cmsghdr *)
21290f1702c5SYu Xiangning ((uchar_t *)mp->b_rptr + tind->OPT_offset);
21300f1702c5SYu Xiangning cend = (char *)cmsg + tind->OPT_length;
21310f1702c5SYu Xiangning for (;;) {
21320f1702c5SYu Xiangning if ((char *)(cmsg + 1) > cend ||
21330f1702c5SYu Xiangning ((char *)cmsg + cmsg->cmsg_len) > cend) {
21340f1702c5SYu Xiangning break;
21350f1702c5SYu Xiangning }
21360f1702c5SYu Xiangning if ((cmsg->cmsg_level == IPPROTO_SCTP) &&
21370f1702c5SYu Xiangning (cmsg->cmsg_type == SCTP_SNDRCV)) {
21380f1702c5SYu Xiangning sinfo = (struct sctp_sndrcvinfo *)
21390f1702c5SYu Xiangning (cmsg + 1);
21400f1702c5SYu Xiangning sinfo->sinfo_assoc_id = ssa->ssa_id;
21410f1702c5SYu Xiangning break;
21420f1702c5SYu Xiangning }
21430f1702c5SYu Xiangning if (cmsg->cmsg_len > 0) {
21440f1702c5SYu Xiangning cmsg = (struct cmsghdr *)
21450f1702c5SYu Xiangning ((uchar_t *)cmsg + cmsg->cmsg_len);
21460f1702c5SYu Xiangning } else {
21470f1702c5SYu Xiangning break;
21480f1702c5SYu Xiangning }
21490f1702c5SYu Xiangning }
21500f1702c5SYu Xiangning }
21510f1702c5SYu Xiangning }
21520f1702c5SYu Xiangning
21530f1702c5SYu Xiangning /*
21540f1702c5SYu Xiangning * SCTP has reserved space in the header for storing a pointer.
21550f1702c5SYu Xiangning * Put the pointer to assocation there, and queue the data.
21560f1702c5SYu Xiangning */
21570f1702c5SYu Xiangning SSA_REFHOLD(ssa);
21580f1702c5SYu Xiangning ASSERT((mp->b_rptr - DB_BASE(mp)) >= sizeof (ssa));
21590f1702c5SYu Xiangning *(struct sctp_soassoc **)DB_BASE(mp) = ssa;
21600f1702c5SYu Xiangning
2161419dcee7SAnders Persson ssa->ssa_rcv_queued += len;
2162419dcee7SAnders Persson space_available = so->so_rcvbuf - ssa->ssa_rcv_queued;
2163a215d4ebSKacheong Poon if (space_available <= 0)
2164a215d4ebSKacheong Poon ssa->ssa_flowctrld = B_TRUE;
2165a215d4ebSKacheong Poon
2166419dcee7SAnders Persson so_enqueue_msg(so, mp, len);
2167419dcee7SAnders Persson
2168419dcee7SAnders Persson /* so_notify_data drops so_lock */
2169419dcee7SAnders Persson so_notify_data(so, len);
21700f1702c5SYu Xiangning
2171419dcee7SAnders Persson return (space_available);
21720f1702c5SYu Xiangning }
21730f1702c5SYu Xiangning
21740f1702c5SYu Xiangning static void
sctp_assoc_xmitted(sock_upper_handle_t handle,boolean_t qfull)21750f1702c5SYu Xiangning sctp_assoc_xmitted(sock_upper_handle_t handle, boolean_t qfull)
21760f1702c5SYu Xiangning {
21770f1702c5SYu Xiangning struct sctp_soassoc *ssa = (struct sctp_soassoc *)handle;
21780f1702c5SYu Xiangning struct sctp_sonode *ss = ssa->ssa_sonode;
21790f1702c5SYu Xiangning
21800f1702c5SYu Xiangning ASSERT(ssa->ssa_type == SOSCTP_ASSOC);
21810f1702c5SYu Xiangning ASSERT(ss->ss_so.so_type == SOCK_SEQPACKET);
21820f1702c5SYu Xiangning ASSERT(ssa->ssa_conn != NULL);
21830f1702c5SYu Xiangning
21840f1702c5SYu Xiangning mutex_enter(&ss->ss_so.so_lock);
21850f1702c5SYu Xiangning
21860f1702c5SYu Xiangning ssa->ssa_snd_qfull = qfull;
21870f1702c5SYu Xiangning
21880f1702c5SYu Xiangning /*
21890f1702c5SYu Xiangning * Wake blocked writers.
21900f1702c5SYu Xiangning */
21910f1702c5SYu Xiangning cv_broadcast(&ss->ss_so.so_snd_cv);
21920f1702c5SYu Xiangning
21930f1702c5SYu Xiangning mutex_exit(&ss->ss_so.so_lock);
21940f1702c5SYu Xiangning }
21950f1702c5SYu Xiangning
2196*78a2e113SAndy Fiddaman static vnode_t *
sctp_assoc_get_vnode(sock_upper_handle_t handle)2197*78a2e113SAndy Fiddaman sctp_assoc_get_vnode(sock_upper_handle_t handle)
2198*78a2e113SAndy Fiddaman {
2199*78a2e113SAndy Fiddaman struct sctp_soassoc *ssa = (struct sctp_soassoc *)handle;
2200*78a2e113SAndy Fiddaman struct sonode *so;
2201*78a2e113SAndy Fiddaman
2202*78a2e113SAndy Fiddaman if (ssa->ssa_type == SOSCTP_ASSOC)
2203*78a2e113SAndy Fiddaman so = &ssa->ssa_sonode->ss_so;
2204*78a2e113SAndy Fiddaman else
2205*78a2e113SAndy Fiddaman so = &((struct sctp_sonode *)handle)->ss_so;
2206*78a2e113SAndy Fiddaman
2207*78a2e113SAndy Fiddaman return (so_get_vnode((sock_upper_handle_t)so));
2208*78a2e113SAndy Fiddaman }
2209*78a2e113SAndy Fiddaman
22100f1702c5SYu Xiangning static void
sctp_assoc_properties(sock_upper_handle_t handle,struct sock_proto_props * soppp)22110f1702c5SYu Xiangning sctp_assoc_properties(sock_upper_handle_t handle,
22120f1702c5SYu Xiangning struct sock_proto_props *soppp)
22130f1702c5SYu Xiangning {
22140f1702c5SYu Xiangning struct sctp_soassoc *ssa = (struct sctp_soassoc *)handle;
2215a215d4ebSKacheong Poon struct sonode *so;
22160f1702c5SYu Xiangning
22170f1702c5SYu Xiangning if (ssa->ssa_type == SOSCTP_ASSOC) {
2218a215d4ebSKacheong Poon so = &ssa->ssa_sonode->ss_so;
22190f1702c5SYu Xiangning
2220a215d4ebSKacheong Poon mutex_enter(&so->so_lock);
2221a215d4ebSKacheong Poon
2222a215d4ebSKacheong Poon /* Per assoc_id properties. */
2223a215d4ebSKacheong Poon if (soppp->sopp_flags & SOCKOPT_WROFF)
22240f1702c5SYu Xiangning ssa->ssa_wroff = soppp->sopp_wroff;
2225a215d4ebSKacheong Poon if (soppp->sopp_flags & SOCKOPT_MAXBLK)
22260f1702c5SYu Xiangning ssa->ssa_wrsize = soppp->sopp_maxblk;
22270f1702c5SYu Xiangning } else {
2228a215d4ebSKacheong Poon so = &((struct sctp_sonode *)handle)->ss_so;
2229a215d4ebSKacheong Poon mutex_enter(&so->so_lock);
22300f1702c5SYu Xiangning
2231a215d4ebSKacheong Poon if (soppp->sopp_flags & SOCKOPT_WROFF)
2232a215d4ebSKacheong Poon so->so_proto_props.sopp_wroff = soppp->sopp_wroff;
2233a215d4ebSKacheong Poon if (soppp->sopp_flags & SOCKOPT_MAXBLK)
2234a215d4ebSKacheong Poon so->so_proto_props.sopp_maxblk = soppp->sopp_maxblk;
2235a215d4ebSKacheong Poon if (soppp->sopp_flags & SOCKOPT_RCVHIWAT) {
2236a215d4ebSKacheong Poon ssize_t lowat;
2237a215d4ebSKacheong Poon
2238a215d4ebSKacheong Poon so->so_rcvbuf = soppp->sopp_rxhiwat;
2239a215d4ebSKacheong Poon /*
2240a215d4ebSKacheong Poon * The low water mark should be adjusted properly
2241a215d4ebSKacheong Poon * if the high water mark is changed. It should
2242a215d4ebSKacheong Poon * not be bigger than 1/4 of high water mark.
2243a215d4ebSKacheong Poon */
2244a215d4ebSKacheong Poon lowat = soppp->sopp_rxhiwat >> 2;
2245a215d4ebSKacheong Poon if (so->so_rcvlowat > lowat) {
2246a215d4ebSKacheong Poon /* Sanity check... */
2247a215d4ebSKacheong Poon if (lowat == 0)
2248a215d4ebSKacheong Poon so->so_rcvlowat = soppp->sopp_rxhiwat;
2249a215d4ebSKacheong Poon else
2250a215d4ebSKacheong Poon so->so_rcvlowat = lowat;
2251a215d4ebSKacheong Poon }
22520f1702c5SYu Xiangning }
22530f1702c5SYu Xiangning }
2254a215d4ebSKacheong Poon mutex_exit(&so->so_lock);
22550f1702c5SYu Xiangning }
2256