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