18348SEric.Yu@Sun.COM /* 28348SEric.Yu@Sun.COM * CDDL HEADER START 38348SEric.Yu@Sun.COM * 48348SEric.Yu@Sun.COM * The contents of this file are subject to the terms of the 58348SEric.Yu@Sun.COM * Common Development and Distribution License (the "License"). 68348SEric.Yu@Sun.COM * You may not use this file except in compliance with the License. 78348SEric.Yu@Sun.COM * 88348SEric.Yu@Sun.COM * You can obtain a copy of the license at usr/src/OPENSOLARIS.LICENSE 98348SEric.Yu@Sun.COM * or http://www.opensolaris.org/os/licensing. 108348SEric.Yu@Sun.COM * See the License for the specific language governing permissions 118348SEric.Yu@Sun.COM * and limitations under the License. 128348SEric.Yu@Sun.COM * 138348SEric.Yu@Sun.COM * When distributing Covered Code, include this CDDL HEADER in each 148348SEric.Yu@Sun.COM * file and include the License file at usr/src/OPENSOLARIS.LICENSE. 158348SEric.Yu@Sun.COM * If applicable, add the following below this CDDL HEADER, with the 168348SEric.Yu@Sun.COM * fields enclosed by brackets "[]" replaced with your own identifying 178348SEric.Yu@Sun.COM * information: Portions Copyright [yyyy] [name of copyright owner] 188348SEric.Yu@Sun.COM * 198348SEric.Yu@Sun.COM * CDDL HEADER END 208348SEric.Yu@Sun.COM */ 218348SEric.Yu@Sun.COM 228348SEric.Yu@Sun.COM /* 238778SErik.Nordmark@Sun.COM * Copyright 2009 Sun Microsystems, Inc. All rights reserved. 248348SEric.Yu@Sun.COM * Use is subject to license terms. 258348SEric.Yu@Sun.COM */ 268348SEric.Yu@Sun.COM 278348SEric.Yu@Sun.COM #include <sys/types.h> 288348SEric.Yu@Sun.COM #include <sys/t_lock.h> 298348SEric.Yu@Sun.COM #include <sys/param.h> 308348SEric.Yu@Sun.COM #include <sys/systm.h> 318348SEric.Yu@Sun.COM #include <sys/buf.h> 328348SEric.Yu@Sun.COM #include <sys/vfs.h> 338348SEric.Yu@Sun.COM #include <sys/vnode.h> 348348SEric.Yu@Sun.COM #include <sys/debug.h> 358348SEric.Yu@Sun.COM #include <sys/errno.h> 368348SEric.Yu@Sun.COM #include <sys/stropts.h> 378348SEric.Yu@Sun.COM #include <sys/cmn_err.h> 388348SEric.Yu@Sun.COM #include <sys/sysmacros.h> 398348SEric.Yu@Sun.COM #include <sys/filio.h> 408348SEric.Yu@Sun.COM 418348SEric.Yu@Sun.COM #include <sys/project.h> 428348SEric.Yu@Sun.COM #include <sys/tihdr.h> 438348SEric.Yu@Sun.COM #include <sys/strsubr.h> 448348SEric.Yu@Sun.COM #include <sys/esunddi.h> 458348SEric.Yu@Sun.COM #include <sys/ddi.h> 468348SEric.Yu@Sun.COM 478348SEric.Yu@Sun.COM #include <sys/sockio.h> 488348SEric.Yu@Sun.COM #include <sys/socket.h> 498348SEric.Yu@Sun.COM #include <sys/socketvar.h> 508348SEric.Yu@Sun.COM #include <sys/strsun.h> 518348SEric.Yu@Sun.COM 528348SEric.Yu@Sun.COM #include <netinet/sctp.h> 538348SEric.Yu@Sun.COM #include <inet/sctp_itf.h> 548348SEric.Yu@Sun.COM #include <fs/sockfs/sockcommon.h> 558348SEric.Yu@Sun.COM #include "socksctp.h" 568348SEric.Yu@Sun.COM 578348SEric.Yu@Sun.COM /* 588348SEric.Yu@Sun.COM * SCTP sockfs sonode operations, 1-1 socket 598348SEric.Yu@Sun.COM */ 608348SEric.Yu@Sun.COM static int sosctp_init(struct sonode *, struct sonode *, struct cred *, int); 618348SEric.Yu@Sun.COM static int sosctp_accept(struct sonode *, int, struct cred *, struct sonode **); 628348SEric.Yu@Sun.COM static int sosctp_bind(struct sonode *, struct sockaddr *, socklen_t, int, 638348SEric.Yu@Sun.COM struct cred *); 648348SEric.Yu@Sun.COM static int sosctp_listen(struct sonode *, int, struct cred *); 658348SEric.Yu@Sun.COM static int sosctp_connect(struct sonode *, const struct sockaddr *, socklen_t, 668348SEric.Yu@Sun.COM int, int, struct cred *); 678348SEric.Yu@Sun.COM static int sosctp_recvmsg(struct sonode *, struct nmsghdr *, struct uio *, 688348SEric.Yu@Sun.COM struct cred *); 698348SEric.Yu@Sun.COM static int sosctp_sendmsg(struct sonode *, struct nmsghdr *, struct uio *, 708348SEric.Yu@Sun.COM struct cred *); 718348SEric.Yu@Sun.COM static int sosctp_getpeername(struct sonode *, struct sockaddr *, socklen_t *, 728348SEric.Yu@Sun.COM boolean_t, struct cred *); 738348SEric.Yu@Sun.COM static int sosctp_getsockname(struct sonode *, struct sockaddr *, socklen_t *, 748348SEric.Yu@Sun.COM struct cred *); 758348SEric.Yu@Sun.COM static int sosctp_shutdown(struct sonode *, int, struct cred *); 768348SEric.Yu@Sun.COM static int sosctp_getsockopt(struct sonode *, int, int, void *, socklen_t *, 778348SEric.Yu@Sun.COM int, struct cred *); 788348SEric.Yu@Sun.COM static int sosctp_setsockopt(struct sonode *, int, int, const void *, 798348SEric.Yu@Sun.COM socklen_t, struct cred *); 808348SEric.Yu@Sun.COM static int sosctp_ioctl(struct sonode *, int, intptr_t, int, struct cred *, 818348SEric.Yu@Sun.COM int32_t *); 828348SEric.Yu@Sun.COM static int sosctp_close(struct sonode *, int, struct cred *); 838348SEric.Yu@Sun.COM void sosctp_fini(struct sonode *, struct cred *); 848348SEric.Yu@Sun.COM 858348SEric.Yu@Sun.COM /* 868348SEric.Yu@Sun.COM * SCTP sockfs sonode operations, 1-N socket 878348SEric.Yu@Sun.COM */ 888348SEric.Yu@Sun.COM static int sosctp_seq_connect(struct sonode *, const struct sockaddr *, 898348SEric.Yu@Sun.COM socklen_t, int, int, struct cred *); 908348SEric.Yu@Sun.COM static int sosctp_seq_sendmsg(struct sonode *, struct nmsghdr *, struct uio *, 918348SEric.Yu@Sun.COM struct cred *); 928348SEric.Yu@Sun.COM 938348SEric.Yu@Sun.COM /* 948348SEric.Yu@Sun.COM * Socket association upcalls, 1-N socket connection 958348SEric.Yu@Sun.COM */ 968348SEric.Yu@Sun.COM sock_upper_handle_t sctp_assoc_newconn(sock_upper_handle_t, 978348SEric.Yu@Sun.COM sock_lower_handle_t, sock_downcalls_t *, struct cred *, pid_t, 988348SEric.Yu@Sun.COM sock_upcalls_t **); 998348SEric.Yu@Sun.COM static void sctp_assoc_connected(sock_upper_handle_t, sock_connid_t, 1008348SEric.Yu@Sun.COM struct cred *, pid_t); 1018348SEric.Yu@Sun.COM static int sctp_assoc_disconnected(sock_upper_handle_t, sock_connid_t, int); 1028348SEric.Yu@Sun.COM static void sctp_assoc_disconnecting(sock_upper_handle_t, sock_opctl_action_t, 1038348SEric.Yu@Sun.COM uintptr_t arg); 1048348SEric.Yu@Sun.COM static ssize_t sctp_assoc_recv(sock_upper_handle_t, mblk_t *, size_t, int, 1058348SEric.Yu@Sun.COM int *, boolean_t *); 1068348SEric.Yu@Sun.COM static void sctp_assoc_xmitted(sock_upper_handle_t, boolean_t); 1078348SEric.Yu@Sun.COM static void sctp_assoc_properties(sock_upper_handle_t, 1088348SEric.Yu@Sun.COM struct sock_proto_props *); 1098348SEric.Yu@Sun.COM 1108348SEric.Yu@Sun.COM sonodeops_t sosctp_sonodeops = { 1118348SEric.Yu@Sun.COM sosctp_init, /* sop_init */ 1128348SEric.Yu@Sun.COM sosctp_accept, /* sop_accept */ 1138348SEric.Yu@Sun.COM sosctp_bind, /* sop_bind */ 1148348SEric.Yu@Sun.COM sosctp_listen, /* sop_listen */ 1158348SEric.Yu@Sun.COM sosctp_connect, /* sop_connect */ 1168348SEric.Yu@Sun.COM sosctp_recvmsg, /* sop_recvmsg */ 1178348SEric.Yu@Sun.COM sosctp_sendmsg, /* sop_sendmsg */ 1188348SEric.Yu@Sun.COM so_sendmblk_notsupp, /* sop_sendmblk */ 1198348SEric.Yu@Sun.COM sosctp_getpeername, /* sop_getpeername */ 1208348SEric.Yu@Sun.COM sosctp_getsockname, /* sop_getsockname */ 1218348SEric.Yu@Sun.COM sosctp_shutdown, /* sop_shutdown */ 1228348SEric.Yu@Sun.COM sosctp_getsockopt, /* sop_getsockopt */ 1238348SEric.Yu@Sun.COM sosctp_setsockopt, /* sop_setsockopt */ 1248348SEric.Yu@Sun.COM sosctp_ioctl, /* sop_ioctl */ 1258348SEric.Yu@Sun.COM so_poll, /* sop_poll */ 1268348SEric.Yu@Sun.COM sosctp_close, /* sop_close */ 1278348SEric.Yu@Sun.COM }; 1288348SEric.Yu@Sun.COM 1298348SEric.Yu@Sun.COM sonodeops_t sosctp_seq_sonodeops = { 1308348SEric.Yu@Sun.COM sosctp_init, /* sop_init */ 1318348SEric.Yu@Sun.COM so_accept_notsupp, /* sop_accept */ 1328348SEric.Yu@Sun.COM sosctp_bind, /* sop_bind */ 1338348SEric.Yu@Sun.COM sosctp_listen, /* sop_listen */ 1348348SEric.Yu@Sun.COM sosctp_seq_connect, /* sop_connect */ 1358348SEric.Yu@Sun.COM sosctp_recvmsg, /* sop_recvmsg */ 1368348SEric.Yu@Sun.COM sosctp_seq_sendmsg, /* sop_sendmsg */ 1378348SEric.Yu@Sun.COM so_sendmblk_notsupp, /* sop_sendmblk */ 1388348SEric.Yu@Sun.COM so_getpeername_notsupp, /* sop_getpeername */ 1398348SEric.Yu@Sun.COM sosctp_getsockname, /* sop_getsockname */ 1408348SEric.Yu@Sun.COM so_shutdown_notsupp, /* sop_shutdown */ 1418348SEric.Yu@Sun.COM sosctp_getsockopt, /* sop_getsockopt */ 1428348SEric.Yu@Sun.COM sosctp_setsockopt, /* sop_setsockopt */ 1438348SEric.Yu@Sun.COM sosctp_ioctl, /* sop_ioctl */ 1448348SEric.Yu@Sun.COM so_poll, /* sop_poll */ 1458348SEric.Yu@Sun.COM sosctp_close, /* sop_close */ 1468348SEric.Yu@Sun.COM }; 1478348SEric.Yu@Sun.COM 1488348SEric.Yu@Sun.COM sock_upcalls_t sosctp_sock_upcalls = { 1498348SEric.Yu@Sun.COM so_newconn, 1508348SEric.Yu@Sun.COM so_connected, 1518348SEric.Yu@Sun.COM so_disconnected, 1528348SEric.Yu@Sun.COM so_opctl, 1538348SEric.Yu@Sun.COM so_queue_msg, 1548348SEric.Yu@Sun.COM so_set_prop, 1558348SEric.Yu@Sun.COM so_txq_full, 1568348SEric.Yu@Sun.COM NULL, /* su_signal_oob */ 1578348SEric.Yu@Sun.COM }; 1588348SEric.Yu@Sun.COM 1598348SEric.Yu@Sun.COM sock_upcalls_t sosctp_assoc_upcalls = { 1608348SEric.Yu@Sun.COM sctp_assoc_newconn, 1618348SEric.Yu@Sun.COM sctp_assoc_connected, 1628348SEric.Yu@Sun.COM sctp_assoc_disconnected, 1638348SEric.Yu@Sun.COM sctp_assoc_disconnecting, 1648348SEric.Yu@Sun.COM sctp_assoc_recv, 1658348SEric.Yu@Sun.COM sctp_assoc_properties, 1668348SEric.Yu@Sun.COM sctp_assoc_xmitted, 1678348SEric.Yu@Sun.COM NULL, /* su_recv_space */ 1688348SEric.Yu@Sun.COM NULL, /* su_signal_oob */ 1698348SEric.Yu@Sun.COM }; 1708348SEric.Yu@Sun.COM 1718348SEric.Yu@Sun.COM /* ARGSUSED */ 1728348SEric.Yu@Sun.COM static int 1738348SEric.Yu@Sun.COM sosctp_init(struct sonode *so, struct sonode *pso, struct cred *cr, int flags) 1748348SEric.Yu@Sun.COM { 1758348SEric.Yu@Sun.COM struct sctp_sonode *ss; 1768348SEric.Yu@Sun.COM struct sctp_sonode *pss; 1778348SEric.Yu@Sun.COM sctp_sockbuf_limits_t sbl; 1788348SEric.Yu@Sun.COM sock_upcalls_t *upcalls; 1798348SEric.Yu@Sun.COM 1808348SEric.Yu@Sun.COM ss = SOTOSSO(so); 1818348SEric.Yu@Sun.COM 1828348SEric.Yu@Sun.COM if (pso != NULL) { 1838348SEric.Yu@Sun.COM /* 1848348SEric.Yu@Sun.COM * Passive open, just inherit settings from parent. We should 1858348SEric.Yu@Sun.COM * not end up here for SOCK_SEQPACKET type sockets, since no 1868348SEric.Yu@Sun.COM * new sonode is created in that case. 1878348SEric.Yu@Sun.COM */ 1888348SEric.Yu@Sun.COM ASSERT(so->so_type == SOCK_STREAM); 1898348SEric.Yu@Sun.COM pss = SOTOSSO(pso); 1908348SEric.Yu@Sun.COM 1918348SEric.Yu@Sun.COM mutex_enter(&pso->so_lock); 1928348SEric.Yu@Sun.COM so->so_state |= (SS_ISBOUND | SS_ISCONNECTED | 1938348SEric.Yu@Sun.COM (pso->so_state & SS_ASYNC)); 1948348SEric.Yu@Sun.COM sosctp_so_inherit(pss, ss); 1958348SEric.Yu@Sun.COM so->so_proto_props = pso->so_proto_props; 1968348SEric.Yu@Sun.COM so->so_mode = pso->so_mode; 1978348SEric.Yu@Sun.COM mutex_exit(&pso->so_lock); 1988348SEric.Yu@Sun.COM 1998348SEric.Yu@Sun.COM return (0); 2008348SEric.Yu@Sun.COM } 2018348SEric.Yu@Sun.COM 2028348SEric.Yu@Sun.COM if (so->so_type == SOCK_STREAM) { 2038348SEric.Yu@Sun.COM upcalls = &sosctp_sock_upcalls; 2048348SEric.Yu@Sun.COM so->so_mode = SM_CONNREQUIRED; 2058348SEric.Yu@Sun.COM } else { 2068348SEric.Yu@Sun.COM ASSERT(so->so_type == SOCK_SEQPACKET); 2078348SEric.Yu@Sun.COM upcalls = &sosctp_assoc_upcalls; 2088348SEric.Yu@Sun.COM } 2098348SEric.Yu@Sun.COM so->so_proto_handle = (sock_lower_handle_t)sctp_create(so, NULL, 210*11042SErik.Nordmark@Sun.COM so->so_family, so->so_type, SCTP_CAN_BLOCK, upcalls, &sbl, cr); 2118348SEric.Yu@Sun.COM if (so->so_proto_handle == NULL) 2128348SEric.Yu@Sun.COM return (ENOMEM); 2138348SEric.Yu@Sun.COM 2148348SEric.Yu@Sun.COM so->so_rcvbuf = sbl.sbl_rxbuf; 2158348SEric.Yu@Sun.COM so->so_rcvlowat = sbl.sbl_rxlowat; 2168348SEric.Yu@Sun.COM so->so_sndbuf = sbl.sbl_txbuf; 2178348SEric.Yu@Sun.COM so->so_sndlowat = sbl.sbl_txlowat; 2188348SEric.Yu@Sun.COM 2198348SEric.Yu@Sun.COM return (0); 2208348SEric.Yu@Sun.COM } 2218348SEric.Yu@Sun.COM 2228348SEric.Yu@Sun.COM /* 2238348SEric.Yu@Sun.COM * Accept incoming connection. 2248348SEric.Yu@Sun.COM */ 2258348SEric.Yu@Sun.COM /*ARGSUSED*/ 2268348SEric.Yu@Sun.COM static int 2278348SEric.Yu@Sun.COM sosctp_accept(struct sonode *so, int fflag, struct cred *cr, 2288348SEric.Yu@Sun.COM struct sonode **nsop) 2298348SEric.Yu@Sun.COM { 2308348SEric.Yu@Sun.COM int error = 0; 2318348SEric.Yu@Sun.COM 2328348SEric.Yu@Sun.COM if ((so->so_state & SS_ACCEPTCONN) == 0) 2338348SEric.Yu@Sun.COM return (EINVAL); 2348348SEric.Yu@Sun.COM 2358348SEric.Yu@Sun.COM error = so_acceptq_dequeue(so, (fflag & (FNONBLOCK|FNDELAY)), nsop); 2368348SEric.Yu@Sun.COM 2378348SEric.Yu@Sun.COM return (error); 2388348SEric.Yu@Sun.COM } 2398348SEric.Yu@Sun.COM 2408348SEric.Yu@Sun.COM /* 2418348SEric.Yu@Sun.COM * Bind local endpoint. 2428348SEric.Yu@Sun.COM */ 2438348SEric.Yu@Sun.COM /*ARGSUSED*/ 2448348SEric.Yu@Sun.COM static int 2458348SEric.Yu@Sun.COM sosctp_bind(struct sonode *so, struct sockaddr *name, socklen_t namelen, 2468348SEric.Yu@Sun.COM int flags, struct cred *cr) 2478348SEric.Yu@Sun.COM { 2488348SEric.Yu@Sun.COM int error; 2498348SEric.Yu@Sun.COM 2508348SEric.Yu@Sun.COM if (!(flags & _SOBIND_LOCK_HELD)) { 2518348SEric.Yu@Sun.COM mutex_enter(&so->so_lock); 2528348SEric.Yu@Sun.COM so_lock_single(so); /* Set SOLOCKED */ 2538348SEric.Yu@Sun.COM } else { 2548348SEric.Yu@Sun.COM ASSERT(MUTEX_HELD(&so->so_lock)); 2558348SEric.Yu@Sun.COM } 2568348SEric.Yu@Sun.COM 2578348SEric.Yu@Sun.COM /* 2588348SEric.Yu@Sun.COM * X/Open requires this check 2598348SEric.Yu@Sun.COM */ 2608348SEric.Yu@Sun.COM if (so->so_state & SS_CANTSENDMORE) { 2618348SEric.Yu@Sun.COM error = EINVAL; 2628348SEric.Yu@Sun.COM goto done; 2638348SEric.Yu@Sun.COM } 2648348SEric.Yu@Sun.COM 2658348SEric.Yu@Sun.COM 2668348SEric.Yu@Sun.COM /* 2678348SEric.Yu@Sun.COM * Protocol module does address family checks. 2688348SEric.Yu@Sun.COM */ 2698348SEric.Yu@Sun.COM mutex_exit(&so->so_lock); 2708348SEric.Yu@Sun.COM 2718348SEric.Yu@Sun.COM error = sctp_bind((struct sctp_s *)so->so_proto_handle, name, namelen); 2728348SEric.Yu@Sun.COM 2738348SEric.Yu@Sun.COM mutex_enter(&so->so_lock); 2748348SEric.Yu@Sun.COM if (error == 0) { 2758348SEric.Yu@Sun.COM so->so_state |= SS_ISBOUND; 2768348SEric.Yu@Sun.COM } else { 2778348SEric.Yu@Sun.COM eprintsoline(so, error); 2788348SEric.Yu@Sun.COM } 2798348SEric.Yu@Sun.COM done: 2808348SEric.Yu@Sun.COM if (!(flags & _SOBIND_LOCK_HELD)) { 2818348SEric.Yu@Sun.COM so_unlock_single(so, SOLOCKED); 2828348SEric.Yu@Sun.COM mutex_exit(&so->so_lock); 2838348SEric.Yu@Sun.COM } else { 2848348SEric.Yu@Sun.COM /* If the caller held the lock don't release it here */ 2858348SEric.Yu@Sun.COM ASSERT(MUTEX_HELD(&so->so_lock)); 2868348SEric.Yu@Sun.COM ASSERT(so->so_flag & SOLOCKED); 2878348SEric.Yu@Sun.COM } 2888348SEric.Yu@Sun.COM 2898348SEric.Yu@Sun.COM return (error); 2908348SEric.Yu@Sun.COM } 2918348SEric.Yu@Sun.COM 2928348SEric.Yu@Sun.COM /* 2938348SEric.Yu@Sun.COM * Turn socket into a listen socket. 2948348SEric.Yu@Sun.COM */ 2958348SEric.Yu@Sun.COM /* ARGSUSED */ 2968348SEric.Yu@Sun.COM static int 2978348SEric.Yu@Sun.COM sosctp_listen(struct sonode *so, int backlog, struct cred *cr) 2988348SEric.Yu@Sun.COM { 2998348SEric.Yu@Sun.COM int error = 0; 3008348SEric.Yu@Sun.COM 3018348SEric.Yu@Sun.COM mutex_enter(&so->so_lock); 3028348SEric.Yu@Sun.COM so_lock_single(so); 3038348SEric.Yu@Sun.COM 3048348SEric.Yu@Sun.COM /* 3058348SEric.Yu@Sun.COM * If this socket is trying to do connect, or if it has 3068348SEric.Yu@Sun.COM * been connected, disallow. 3078348SEric.Yu@Sun.COM */ 3088348SEric.Yu@Sun.COM if (so->so_state & (SS_ISCONNECTING | SS_ISCONNECTED | 3098348SEric.Yu@Sun.COM SS_ISDISCONNECTING | SS_CANTRCVMORE | SS_CANTSENDMORE)) { 3108348SEric.Yu@Sun.COM error = EINVAL; 3118348SEric.Yu@Sun.COM eprintsoline(so, error); 3128348SEric.Yu@Sun.COM goto done; 3138348SEric.Yu@Sun.COM } 3148348SEric.Yu@Sun.COM 3158348SEric.Yu@Sun.COM if (backlog < 0) { 3168348SEric.Yu@Sun.COM backlog = 0; 3178348SEric.Yu@Sun.COM } 3188348SEric.Yu@Sun.COM 3198348SEric.Yu@Sun.COM /* 3208348SEric.Yu@Sun.COM * If listen() is only called to change backlog, we don't 3218348SEric.Yu@Sun.COM * need to notify protocol module. 3228348SEric.Yu@Sun.COM */ 3238348SEric.Yu@Sun.COM if (so->so_state & SS_ACCEPTCONN) { 3248348SEric.Yu@Sun.COM so->so_backlog = backlog; 3258348SEric.Yu@Sun.COM goto done; 3268348SEric.Yu@Sun.COM } 3278348SEric.Yu@Sun.COM 3288348SEric.Yu@Sun.COM mutex_exit(&so->so_lock); 3298348SEric.Yu@Sun.COM error = sctp_listen((struct sctp_s *)so->so_proto_handle); 3308348SEric.Yu@Sun.COM mutex_enter(&so->so_lock); 3318348SEric.Yu@Sun.COM if (error == 0) { 3328348SEric.Yu@Sun.COM so->so_state |= (SS_ACCEPTCONN|SS_ISBOUND); 3338348SEric.Yu@Sun.COM so->so_backlog = backlog; 3348348SEric.Yu@Sun.COM } else { 3358348SEric.Yu@Sun.COM eprintsoline(so, error); 3368348SEric.Yu@Sun.COM } 3378348SEric.Yu@Sun.COM done: 3388348SEric.Yu@Sun.COM so_unlock_single(so, SOLOCKED); 3398348SEric.Yu@Sun.COM mutex_exit(&so->so_lock); 3408348SEric.Yu@Sun.COM 3418348SEric.Yu@Sun.COM return (error); 3428348SEric.Yu@Sun.COM } 3438348SEric.Yu@Sun.COM 3448348SEric.Yu@Sun.COM /* 3458348SEric.Yu@Sun.COM * Active open. 3468348SEric.Yu@Sun.COM */ 3478348SEric.Yu@Sun.COM /*ARGSUSED*/ 3488348SEric.Yu@Sun.COM static int 3498348SEric.Yu@Sun.COM sosctp_connect(struct sonode *so, const struct sockaddr *name, 3508348SEric.Yu@Sun.COM socklen_t namelen, int fflag, int flags, struct cred *cr) 3518348SEric.Yu@Sun.COM { 3528348SEric.Yu@Sun.COM int error = 0; 353*11042SErik.Nordmark@Sun.COM pid_t pid = curproc->p_pid; 3548348SEric.Yu@Sun.COM 3558348SEric.Yu@Sun.COM ASSERT(so->so_type == SOCK_STREAM); 3568348SEric.Yu@Sun.COM 3578348SEric.Yu@Sun.COM mutex_enter(&so->so_lock); 3588348SEric.Yu@Sun.COM so_lock_single(so); 3598348SEric.Yu@Sun.COM 3608348SEric.Yu@Sun.COM /* 3618348SEric.Yu@Sun.COM * Can't connect() after listen(), or if the socket is already 3628348SEric.Yu@Sun.COM * connected. 3638348SEric.Yu@Sun.COM */ 3648348SEric.Yu@Sun.COM if (so->so_state & (SS_ACCEPTCONN|SS_ISCONNECTED|SS_ISCONNECTING)) { 3658348SEric.Yu@Sun.COM if (so->so_state & SS_ISCONNECTED) { 3668348SEric.Yu@Sun.COM error = EISCONN; 3678348SEric.Yu@Sun.COM } else if (so->so_state & SS_ISCONNECTING) { 3688348SEric.Yu@Sun.COM error = EALREADY; 3698348SEric.Yu@Sun.COM } else { 3708348SEric.Yu@Sun.COM error = EOPNOTSUPP; 3718348SEric.Yu@Sun.COM } 3728348SEric.Yu@Sun.COM eprintsoline(so, error); 3738348SEric.Yu@Sun.COM goto done; 3748348SEric.Yu@Sun.COM } 3758348SEric.Yu@Sun.COM 3768348SEric.Yu@Sun.COM /* 3778348SEric.Yu@Sun.COM * Check for failure of an earlier call 3788348SEric.Yu@Sun.COM */ 3798348SEric.Yu@Sun.COM if (so->so_error != 0) { 3808348SEric.Yu@Sun.COM error = sogeterr(so, B_TRUE); 3818348SEric.Yu@Sun.COM eprintsoline(so, error); 3828348SEric.Yu@Sun.COM goto done; 3838348SEric.Yu@Sun.COM } 3848348SEric.Yu@Sun.COM 3858348SEric.Yu@Sun.COM /* 3868348SEric.Yu@Sun.COM * Connection is closing, or closed, don't allow reconnect. 3878348SEric.Yu@Sun.COM * TCP allows this to proceed, but the socket remains unwriteable. 3888348SEric.Yu@Sun.COM * BSD returns EINVAL. 3898348SEric.Yu@Sun.COM */ 3908348SEric.Yu@Sun.COM if (so->so_state & (SS_ISDISCONNECTING|SS_CANTRCVMORE| 3918348SEric.Yu@Sun.COM SS_CANTSENDMORE)) { 3928348SEric.Yu@Sun.COM error = EINVAL; 3938348SEric.Yu@Sun.COM eprintsoline(so, error); 3948348SEric.Yu@Sun.COM goto done; 3958348SEric.Yu@Sun.COM } 3968348SEric.Yu@Sun.COM 3978348SEric.Yu@Sun.COM if (name == NULL || namelen == 0) { 3988348SEric.Yu@Sun.COM mutex_exit(&so->so_lock); 3998348SEric.Yu@Sun.COM error = EINVAL; 4008348SEric.Yu@Sun.COM eprintsoline(so, error); 4018348SEric.Yu@Sun.COM goto done; 4028348SEric.Yu@Sun.COM } 4038348SEric.Yu@Sun.COM 4048348SEric.Yu@Sun.COM soisconnecting(so); 4058348SEric.Yu@Sun.COM mutex_exit(&so->so_lock); 4068348SEric.Yu@Sun.COM 4078348SEric.Yu@Sun.COM error = sctp_connect((struct sctp_s *)so->so_proto_handle, 408*11042SErik.Nordmark@Sun.COM name, namelen, cr, pid); 4098348SEric.Yu@Sun.COM 4108348SEric.Yu@Sun.COM mutex_enter(&so->so_lock); 4118348SEric.Yu@Sun.COM if (error == 0) { 4128348SEric.Yu@Sun.COM /* 4138348SEric.Yu@Sun.COM * Allow other threads to access the socket 4148348SEric.Yu@Sun.COM */ 4158348SEric.Yu@Sun.COM error = sowaitconnected(so, fflag, 0); 4168348SEric.Yu@Sun.COM } 4178348SEric.Yu@Sun.COM done: 4188348SEric.Yu@Sun.COM so_unlock_single(so, SOLOCKED); 4198348SEric.Yu@Sun.COM mutex_exit(&so->so_lock); 4208348SEric.Yu@Sun.COM return (error); 4218348SEric.Yu@Sun.COM } 4228348SEric.Yu@Sun.COM 4238348SEric.Yu@Sun.COM /* 4248348SEric.Yu@Sun.COM * Active open for 1-N sockets, create a new association and 4258348SEric.Yu@Sun.COM * call connect on that. 4268348SEric.Yu@Sun.COM * If there parent hasn't been bound yet (this is the first association), 4278348SEric.Yu@Sun.COM * make it so. 4288348SEric.Yu@Sun.COM */ 4298348SEric.Yu@Sun.COM static int 4308348SEric.Yu@Sun.COM sosctp_seq_connect(struct sonode *so, const struct sockaddr *name, 4318348SEric.Yu@Sun.COM socklen_t namelen, int fflag, int flags, struct cred *cr) 4328348SEric.Yu@Sun.COM { 4338348SEric.Yu@Sun.COM struct sctp_soassoc *ssa; 4348348SEric.Yu@Sun.COM struct sctp_sonode *ss; 4358348SEric.Yu@Sun.COM int error; 4368348SEric.Yu@Sun.COM 4378348SEric.Yu@Sun.COM ASSERT(so->so_type == SOCK_SEQPACKET); 4388348SEric.Yu@Sun.COM 4398348SEric.Yu@Sun.COM mutex_enter(&so->so_lock); 4408348SEric.Yu@Sun.COM so_lock_single(so); 4418348SEric.Yu@Sun.COM 4428348SEric.Yu@Sun.COM if (name == NULL || namelen == 0) { 4438348SEric.Yu@Sun.COM error = EINVAL; 4448348SEric.Yu@Sun.COM eprintsoline(so, error); 4458348SEric.Yu@Sun.COM goto done; 4468348SEric.Yu@Sun.COM } 4478348SEric.Yu@Sun.COM 4488348SEric.Yu@Sun.COM ss = SOTOSSO(so); 4498348SEric.Yu@Sun.COM 4508348SEric.Yu@Sun.COM error = sosctp_assoc_createconn(ss, name, namelen, NULL, 0, fflag, 4518348SEric.Yu@Sun.COM cr, &ssa); 4528348SEric.Yu@Sun.COM if (error != 0) { 4538348SEric.Yu@Sun.COM if ((error == EHOSTUNREACH) && (flags & _SOCONNECT_XPG4_2)) { 4548348SEric.Yu@Sun.COM error = ENETUNREACH; 4558348SEric.Yu@Sun.COM } 4568348SEric.Yu@Sun.COM } 4578348SEric.Yu@Sun.COM if (ssa != NULL) { 4588348SEric.Yu@Sun.COM SSA_REFRELE(ss, ssa); 4598348SEric.Yu@Sun.COM } 4608348SEric.Yu@Sun.COM 4618348SEric.Yu@Sun.COM done: 4628348SEric.Yu@Sun.COM so_unlock_single(so, SOLOCKED); 4638348SEric.Yu@Sun.COM mutex_exit(&so->so_lock); 4648348SEric.Yu@Sun.COM return (error); 4658348SEric.Yu@Sun.COM } 4668348SEric.Yu@Sun.COM 4678348SEric.Yu@Sun.COM /* 4688348SEric.Yu@Sun.COM * Receive data. 4698348SEric.Yu@Sun.COM */ 4708348SEric.Yu@Sun.COM /* ARGSUSED */ 4718348SEric.Yu@Sun.COM static int 4728348SEric.Yu@Sun.COM sosctp_recvmsg(struct sonode *so, struct nmsghdr *msg, struct uio *uiop, 4738348SEric.Yu@Sun.COM struct cred *cr) 4748348SEric.Yu@Sun.COM { 4758348SEric.Yu@Sun.COM struct sctp_sonode *ss = SOTOSSO(so); 4768348SEric.Yu@Sun.COM struct sctp_soassoc *ssa = NULL; 4778348SEric.Yu@Sun.COM int flags, error = 0; 4788348SEric.Yu@Sun.COM struct T_unitdata_ind *tind; 4798941SAnders.Persson@Sun.COM ssize_t orig_resid = uiop->uio_resid; 4808348SEric.Yu@Sun.COM int len, count, readcnt = 0, rxqueued; 4818348SEric.Yu@Sun.COM socklen_t controllen, namelen; 4828348SEric.Yu@Sun.COM void *opt; 4838348SEric.Yu@Sun.COM mblk_t *mp; 4848348SEric.Yu@Sun.COM rval_t rval; 4858348SEric.Yu@Sun.COM 4868348SEric.Yu@Sun.COM controllen = msg->msg_controllen; 4878348SEric.Yu@Sun.COM namelen = msg->msg_namelen; 4888348SEric.Yu@Sun.COM flags = msg->msg_flags; 4898348SEric.Yu@Sun.COM msg->msg_flags = 0; 4908348SEric.Yu@Sun.COM msg->msg_controllen = 0; 4918348SEric.Yu@Sun.COM msg->msg_namelen = 0; 4928348SEric.Yu@Sun.COM 4938348SEric.Yu@Sun.COM if (so->so_type == SOCK_STREAM) { 4948348SEric.Yu@Sun.COM if (!(so->so_state & (SS_ISCONNECTED|SS_ISCONNECTING| 4958348SEric.Yu@Sun.COM SS_CANTRCVMORE))) { 4968348SEric.Yu@Sun.COM return (ENOTCONN); 4978348SEric.Yu@Sun.COM } 4988348SEric.Yu@Sun.COM } else { 4998348SEric.Yu@Sun.COM /* NOTE: Will come here from vop_read() as well */ 5008348SEric.Yu@Sun.COM /* For 1-N socket, recv() cannot be used. */ 5018348SEric.Yu@Sun.COM if (namelen == 0) 5028348SEric.Yu@Sun.COM return (EOPNOTSUPP); 5038348SEric.Yu@Sun.COM /* 5048348SEric.Yu@Sun.COM * If there are no associations, and no new connections are 5058348SEric.Yu@Sun.COM * coming in, there's not going to be new messages coming 5068348SEric.Yu@Sun.COM * in either. 5078348SEric.Yu@Sun.COM */ 5088941SAnders.Persson@Sun.COM if (so->so_rcv_q_head == NULL && so->so_rcv_head == NULL && 5098941SAnders.Persson@Sun.COM ss->ss_assoccnt == 0 && !(so->so_state & SS_ACCEPTCONN)) { 5108348SEric.Yu@Sun.COM return (ENOTCONN); 5118348SEric.Yu@Sun.COM } 5128348SEric.Yu@Sun.COM } 5138348SEric.Yu@Sun.COM 5148348SEric.Yu@Sun.COM /* 5158348SEric.Yu@Sun.COM * out-of-band data not supported. 5168348SEric.Yu@Sun.COM */ 5178348SEric.Yu@Sun.COM if (flags & MSG_OOB) { 5188348SEric.Yu@Sun.COM return (EOPNOTSUPP); 5198348SEric.Yu@Sun.COM } 5208348SEric.Yu@Sun.COM 5218348SEric.Yu@Sun.COM /* 5228348SEric.Yu@Sun.COM * flag possibilities: 5238348SEric.Yu@Sun.COM * 5248348SEric.Yu@Sun.COM * MSG_PEEK Don't consume data 5258348SEric.Yu@Sun.COM * MSG_WAITALL Wait for full quantity of data (ignored if MSG_PEEK) 5268348SEric.Yu@Sun.COM * MSG_DONTWAIT Non-blocking (same as FNDELAY | FNONBLOCK) 5278348SEric.Yu@Sun.COM * 5288348SEric.Yu@Sun.COM * MSG_WAITALL can return less than the full buffer if either 5298348SEric.Yu@Sun.COM * 5308348SEric.Yu@Sun.COM * 1. we would block and we are non-blocking 5318348SEric.Yu@Sun.COM * 2. a full message cannot be delivered 5328348SEric.Yu@Sun.COM * 5338348SEric.Yu@Sun.COM * Given that we always get a full message from proto below, 5348348SEric.Yu@Sun.COM * MSG_WAITALL is not meaningful. 5358348SEric.Yu@Sun.COM */ 5368348SEric.Yu@Sun.COM 5378348SEric.Yu@Sun.COM mutex_enter(&so->so_lock); 5388348SEric.Yu@Sun.COM 5398348SEric.Yu@Sun.COM /* 5408348SEric.Yu@Sun.COM * Allow just one reader at a time. 5418348SEric.Yu@Sun.COM */ 5428348SEric.Yu@Sun.COM error = so_lock_read_intr(so, 5438348SEric.Yu@Sun.COM uiop->uio_fmode | ((flags & MSG_DONTWAIT) ? FNONBLOCK : 0)); 5448348SEric.Yu@Sun.COM if (error) { 5458348SEric.Yu@Sun.COM mutex_exit(&so->so_lock); 5468348SEric.Yu@Sun.COM return (error); 5478348SEric.Yu@Sun.COM } 5488348SEric.Yu@Sun.COM mutex_exit(&so->so_lock); 5498348SEric.Yu@Sun.COM again: 5508348SEric.Yu@Sun.COM error = so_dequeue_msg(so, &mp, uiop, &rval, flags | MSG_DUPCTRL); 5518348SEric.Yu@Sun.COM if (mp != NULL) { 5528348SEric.Yu@Sun.COM if (so->so_type == SOCK_SEQPACKET) { 5538348SEric.Yu@Sun.COM ssa = *(struct sctp_soassoc **)DB_BASE(mp); 5548348SEric.Yu@Sun.COM } 5558348SEric.Yu@Sun.COM 5568348SEric.Yu@Sun.COM tind = (struct T_unitdata_ind *)mp->b_rptr; 5578348SEric.Yu@Sun.COM 5588348SEric.Yu@Sun.COM len = tind->SRC_length; 5598348SEric.Yu@Sun.COM 5608348SEric.Yu@Sun.COM if (namelen > 0 && len > 0) { 5618348SEric.Yu@Sun.COM 5628348SEric.Yu@Sun.COM opt = sogetoff(mp, tind->SRC_offset, len, 1); 5638348SEric.Yu@Sun.COM 5648348SEric.Yu@Sun.COM ASSERT(opt != NULL); 5658348SEric.Yu@Sun.COM 5668348SEric.Yu@Sun.COM msg->msg_name = kmem_alloc(len, KM_SLEEP); 5678348SEric.Yu@Sun.COM msg->msg_namelen = len; 5688348SEric.Yu@Sun.COM 5698348SEric.Yu@Sun.COM bcopy(opt, msg->msg_name, len); 5708348SEric.Yu@Sun.COM } 5718348SEric.Yu@Sun.COM 5728348SEric.Yu@Sun.COM len = tind->OPT_length; 5738348SEric.Yu@Sun.COM if (controllen == 0) { 5748348SEric.Yu@Sun.COM if (len > 0) { 5758348SEric.Yu@Sun.COM msg->msg_flags |= MSG_CTRUNC; 5768348SEric.Yu@Sun.COM } 5778348SEric.Yu@Sun.COM } else if (len > 0) { 5788348SEric.Yu@Sun.COM opt = sogetoff(mp, tind->OPT_offset, len, 5798348SEric.Yu@Sun.COM __TPI_ALIGN_SIZE); 5808348SEric.Yu@Sun.COM 5818348SEric.Yu@Sun.COM ASSERT(opt != NULL); 5828348SEric.Yu@Sun.COM sosctp_pack_cmsg(opt, msg, len); 5838348SEric.Yu@Sun.COM } 5848348SEric.Yu@Sun.COM 5858348SEric.Yu@Sun.COM if (mp->b_flag & SCTP_NOTIFICATION) { 5868348SEric.Yu@Sun.COM msg->msg_flags |= MSG_NOTIFICATION; 5878348SEric.Yu@Sun.COM } 5888348SEric.Yu@Sun.COM 5898348SEric.Yu@Sun.COM if (!(mp->b_flag & SCTP_PARTIAL_DATA)) 5908348SEric.Yu@Sun.COM msg->msg_flags |= MSG_EOR; 5918348SEric.Yu@Sun.COM freemsg(mp); 5928348SEric.Yu@Sun.COM } 5938348SEric.Yu@Sun.COM done: 5948941SAnders.Persson@Sun.COM if (!(flags & MSG_PEEK)) 5958941SAnders.Persson@Sun.COM readcnt = orig_resid - uiop->uio_resid; 5968348SEric.Yu@Sun.COM /* 5978348SEric.Yu@Sun.COM * Determine if we need to update SCTP about the buffer 5988348SEric.Yu@Sun.COM * space. For performance reason, we cannot update SCTP 5998348SEric.Yu@Sun.COM * every time a message is read. The socket buffer low 6008348SEric.Yu@Sun.COM * watermark is used as the threshold. 6018348SEric.Yu@Sun.COM */ 6028348SEric.Yu@Sun.COM if (ssa == NULL) { 6038348SEric.Yu@Sun.COM mutex_enter(&so->so_lock); 6048348SEric.Yu@Sun.COM rxqueued = so->so_rcv_queued; 6058348SEric.Yu@Sun.COM count = so->so_rcvbuf - so->so_rcv_queued; 6068348SEric.Yu@Sun.COM 6078348SEric.Yu@Sun.COM ASSERT(so->so_rcv_q_head != NULL || 6088348SEric.Yu@Sun.COM so->so_rcv_head != NULL || 6098348SEric.Yu@Sun.COM so->so_rcv_queued == 0); 6108348SEric.Yu@Sun.COM 6118348SEric.Yu@Sun.COM so_unlock_read(so); 6128348SEric.Yu@Sun.COM mutex_exit(&so->so_lock); 6138348SEric.Yu@Sun.COM 6148348SEric.Yu@Sun.COM if (readcnt > 0 && (((count > 0) && 6158941SAnders.Persson@Sun.COM ((rxqueued + readcnt) >= so->so_rcvlowat)) || 6168941SAnders.Persson@Sun.COM (rxqueued == 0))) { 6178348SEric.Yu@Sun.COM /* 6188348SEric.Yu@Sun.COM * If amount of queued data is higher than watermark, 6198348SEric.Yu@Sun.COM * updata SCTP's idea of available buffer space. 6208348SEric.Yu@Sun.COM */ 6218348SEric.Yu@Sun.COM sctp_recvd((struct sctp_s *)so->so_proto_handle, count); 6228348SEric.Yu@Sun.COM } 6238348SEric.Yu@Sun.COM } else { 6248941SAnders.Persson@Sun.COM /* 6258941SAnders.Persson@Sun.COM * Each association keeps track of how much data it has 6268941SAnders.Persson@Sun.COM * queued; we need to update the value here. Note that this 6278941SAnders.Persson@Sun.COM * is slightly different from SOCK_STREAM type sockets, which 6288941SAnders.Persson@Sun.COM * does not need to update the byte count, as it is already 6298941SAnders.Persson@Sun.COM * done in so_dequeue_msg(). 6308941SAnders.Persson@Sun.COM */ 6318348SEric.Yu@Sun.COM mutex_enter(&so->so_lock); 6328348SEric.Yu@Sun.COM rxqueued = ssa->ssa_rcv_queued; 6338348SEric.Yu@Sun.COM 6348348SEric.Yu@Sun.COM ssa->ssa_rcv_queued = rxqueued - readcnt; 6358348SEric.Yu@Sun.COM count = so->so_rcvbuf - ssa->ssa_rcv_queued; 6368348SEric.Yu@Sun.COM 6378348SEric.Yu@Sun.COM so_unlock_read(so); 6388348SEric.Yu@Sun.COM 6398348SEric.Yu@Sun.COM if (readcnt > 0 && 6408348SEric.Yu@Sun.COM (((count > 0) && (rxqueued >= so->so_rcvlowat)) || 6418348SEric.Yu@Sun.COM (ssa->ssa_rcv_queued == 0))) { 6428348SEric.Yu@Sun.COM /* 6438348SEric.Yu@Sun.COM * If amount of queued data is higher than watermark, 6448348SEric.Yu@Sun.COM * updata SCTP's idea of available buffer space. 6458348SEric.Yu@Sun.COM */ 6468348SEric.Yu@Sun.COM mutex_exit(&so->so_lock); 6478348SEric.Yu@Sun.COM 6488348SEric.Yu@Sun.COM sctp_recvd((struct sctp_s *)ssa->ssa_conn, count); 6498348SEric.Yu@Sun.COM 6508348SEric.Yu@Sun.COM mutex_enter(&so->so_lock); 6518348SEric.Yu@Sun.COM } 6528348SEric.Yu@Sun.COM /* 6538348SEric.Yu@Sun.COM * MOREDATA flag is set if all data could not be copied 6548348SEric.Yu@Sun.COM */ 6558348SEric.Yu@Sun.COM if (!(flags & MSG_PEEK) && !(rval.r_val1 & MOREDATA)) { 6568348SEric.Yu@Sun.COM SSA_REFRELE(ss, ssa); 6578348SEric.Yu@Sun.COM } 6588348SEric.Yu@Sun.COM mutex_exit(&so->so_lock); 6598348SEric.Yu@Sun.COM } 6608348SEric.Yu@Sun.COM 6618348SEric.Yu@Sun.COM return (error); 6628348SEric.Yu@Sun.COM } 6638348SEric.Yu@Sun.COM 6648348SEric.Yu@Sun.COM int 6658348SEric.Yu@Sun.COM sosctp_uiomove(mblk_t *hdr_mp, ssize_t count, ssize_t blk_size, int wroff, 666*11042SErik.Nordmark@Sun.COM struct uio *uiop, int flags) 6678348SEric.Yu@Sun.COM { 6688348SEric.Yu@Sun.COM ssize_t size; 6698348SEric.Yu@Sun.COM int error; 6708348SEric.Yu@Sun.COM mblk_t *mp; 6718348SEric.Yu@Sun.COM dblk_t *dp; 6728348SEric.Yu@Sun.COM 6739059SErik.Nordmark@Sun.COM if (blk_size == INFPSZ) 6749059SErik.Nordmark@Sun.COM blk_size = count; 6759059SErik.Nordmark@Sun.COM 6768348SEric.Yu@Sun.COM /* 6778348SEric.Yu@Sun.COM * Loop until we have all data copied into mblk's. 6788348SEric.Yu@Sun.COM */ 6798348SEric.Yu@Sun.COM while (count > 0) { 6808348SEric.Yu@Sun.COM size = MIN(count, blk_size); 6818348SEric.Yu@Sun.COM 6828348SEric.Yu@Sun.COM /* 6838348SEric.Yu@Sun.COM * As a message can be splitted up and sent in different 6848348SEric.Yu@Sun.COM * packets, each mblk will have the extra space before 6858348SEric.Yu@Sun.COM * data to accommodate what SCTP wants to put in there. 6868348SEric.Yu@Sun.COM */ 687*11042SErik.Nordmark@Sun.COM while ((mp = allocb(size + wroff, BPRI_MED)) == NULL) { 6888348SEric.Yu@Sun.COM if ((uiop->uio_fmode & (FNDELAY|FNONBLOCK)) || 6898348SEric.Yu@Sun.COM (flags & MSG_DONTWAIT)) { 6908348SEric.Yu@Sun.COM return (EAGAIN); 6918348SEric.Yu@Sun.COM } 6928348SEric.Yu@Sun.COM if ((error = strwaitbuf(size + wroff, BPRI_MED))) { 6938348SEric.Yu@Sun.COM return (error); 6948348SEric.Yu@Sun.COM } 6958348SEric.Yu@Sun.COM } 6968348SEric.Yu@Sun.COM 6978348SEric.Yu@Sun.COM dp = mp->b_datap; 6988348SEric.Yu@Sun.COM dp->db_cpid = curproc->p_pid; 6998348SEric.Yu@Sun.COM ASSERT(wroff <= dp->db_lim - mp->b_wptr); 7008348SEric.Yu@Sun.COM mp->b_rptr += wroff; 7018348SEric.Yu@Sun.COM error = uiomove(mp->b_rptr, size, UIO_WRITE, uiop); 7028348SEric.Yu@Sun.COM if (error != 0) { 7038348SEric.Yu@Sun.COM freeb(mp); 7048348SEric.Yu@Sun.COM return (error); 7058348SEric.Yu@Sun.COM } 7068348SEric.Yu@Sun.COM mp->b_wptr = mp->b_rptr + size; 7078348SEric.Yu@Sun.COM count -= size; 7088348SEric.Yu@Sun.COM hdr_mp->b_cont = mp; 7098348SEric.Yu@Sun.COM hdr_mp = mp; 7108348SEric.Yu@Sun.COM } 7118348SEric.Yu@Sun.COM return (0); 7128348SEric.Yu@Sun.COM } 7138348SEric.Yu@Sun.COM 7148348SEric.Yu@Sun.COM /* 7158348SEric.Yu@Sun.COM * Send message. 7168348SEric.Yu@Sun.COM */ 7178348SEric.Yu@Sun.COM static int 7188348SEric.Yu@Sun.COM sosctp_sendmsg(struct sonode *so, struct nmsghdr *msg, struct uio *uiop, 7198348SEric.Yu@Sun.COM struct cred *cr) 7208348SEric.Yu@Sun.COM { 7218348SEric.Yu@Sun.COM struct sctp_sonode *ss = SOTOSSO(so); 7228348SEric.Yu@Sun.COM mblk_t *mctl; 7238348SEric.Yu@Sun.COM struct cmsghdr *cmsg; 7248348SEric.Yu@Sun.COM struct sctp_sndrcvinfo *sinfo; 7258348SEric.Yu@Sun.COM int optlen, flags, fflag; 7268348SEric.Yu@Sun.COM ssize_t count, msglen; 7278348SEric.Yu@Sun.COM int error; 7288348SEric.Yu@Sun.COM 7298348SEric.Yu@Sun.COM ASSERT(so->so_type == SOCK_STREAM); 7308348SEric.Yu@Sun.COM 7318348SEric.Yu@Sun.COM flags = msg->msg_flags; 7328348SEric.Yu@Sun.COM if (flags & MSG_OOB) { 7338348SEric.Yu@Sun.COM /* 7348348SEric.Yu@Sun.COM * No out-of-band data support. 7358348SEric.Yu@Sun.COM */ 7368348SEric.Yu@Sun.COM return (EOPNOTSUPP); 7378348SEric.Yu@Sun.COM } 7388348SEric.Yu@Sun.COM 7398348SEric.Yu@Sun.COM if (msg->msg_controllen != 0) { 7408348SEric.Yu@Sun.COM optlen = msg->msg_controllen; 7418348SEric.Yu@Sun.COM cmsg = sosctp_find_cmsg(msg->msg_control, optlen, SCTP_SNDRCV); 7428348SEric.Yu@Sun.COM if (cmsg != NULL) { 7438348SEric.Yu@Sun.COM if (cmsg->cmsg_len < 7448348SEric.Yu@Sun.COM (sizeof (*sinfo) + sizeof (*cmsg))) { 7458348SEric.Yu@Sun.COM eprintsoline(so, EINVAL); 7468348SEric.Yu@Sun.COM return (EINVAL); 7478348SEric.Yu@Sun.COM } 7488348SEric.Yu@Sun.COM sinfo = (struct sctp_sndrcvinfo *)(cmsg + 1); 7498348SEric.Yu@Sun.COM 7508348SEric.Yu@Sun.COM /* Both flags should not be set together. */ 7518348SEric.Yu@Sun.COM if ((sinfo->sinfo_flags & MSG_EOF) && 7528348SEric.Yu@Sun.COM (sinfo->sinfo_flags & MSG_ABORT)) { 7538348SEric.Yu@Sun.COM eprintsoline(so, EINVAL); 7548348SEric.Yu@Sun.COM return (EINVAL); 7558348SEric.Yu@Sun.COM } 7568348SEric.Yu@Sun.COM 7578348SEric.Yu@Sun.COM /* Initiate a graceful shutdown. */ 7588348SEric.Yu@Sun.COM if (sinfo->sinfo_flags & MSG_EOF) { 7598348SEric.Yu@Sun.COM /* Can't include data in MSG_EOF message. */ 7608348SEric.Yu@Sun.COM if (uiop->uio_resid != 0) { 7618348SEric.Yu@Sun.COM eprintsoline(so, EINVAL); 7628348SEric.Yu@Sun.COM return (EINVAL); 7638348SEric.Yu@Sun.COM } 7648348SEric.Yu@Sun.COM 7658348SEric.Yu@Sun.COM /* 7668348SEric.Yu@Sun.COM * This is the same sequence as done in 7678348SEric.Yu@Sun.COM * shutdown(SHUT_WR). 7688348SEric.Yu@Sun.COM */ 7698348SEric.Yu@Sun.COM mutex_enter(&so->so_lock); 7708348SEric.Yu@Sun.COM so_lock_single(so); 7718348SEric.Yu@Sun.COM socantsendmore(so); 7728348SEric.Yu@Sun.COM cv_broadcast(&so->so_snd_cv); 7738348SEric.Yu@Sun.COM so->so_state |= SS_ISDISCONNECTING; 7748348SEric.Yu@Sun.COM mutex_exit(&so->so_lock); 7758348SEric.Yu@Sun.COM 7768348SEric.Yu@Sun.COM pollwakeup(&so->so_poll_list, POLLOUT); 7778348SEric.Yu@Sun.COM sctp_recvd((struct sctp_s *)so->so_proto_handle, 7788348SEric.Yu@Sun.COM so->so_rcvbuf); 7798348SEric.Yu@Sun.COM error = sctp_disconnect( 7808348SEric.Yu@Sun.COM (struct sctp_s *)so->so_proto_handle); 7818348SEric.Yu@Sun.COM 7828348SEric.Yu@Sun.COM mutex_enter(&so->so_lock); 7838348SEric.Yu@Sun.COM so_unlock_single(so, SOLOCKED); 7848348SEric.Yu@Sun.COM mutex_exit(&so->so_lock); 7858348SEric.Yu@Sun.COM return (error); 7868348SEric.Yu@Sun.COM } 7878348SEric.Yu@Sun.COM } 7888348SEric.Yu@Sun.COM } else { 7898348SEric.Yu@Sun.COM optlen = 0; 7908348SEric.Yu@Sun.COM } 7918348SEric.Yu@Sun.COM 7928348SEric.Yu@Sun.COM mutex_enter(&so->so_lock); 7938348SEric.Yu@Sun.COM for (;;) { 7948348SEric.Yu@Sun.COM if (so->so_state & SS_CANTSENDMORE) { 7958348SEric.Yu@Sun.COM mutex_exit(&so->so_lock); 7968348SEric.Yu@Sun.COM return (EPIPE); 7978348SEric.Yu@Sun.COM } 7988348SEric.Yu@Sun.COM 7998348SEric.Yu@Sun.COM if (so->so_error != 0) { 8008348SEric.Yu@Sun.COM error = sogeterr(so, B_TRUE); 8018348SEric.Yu@Sun.COM mutex_exit(&so->so_lock); 8028348SEric.Yu@Sun.COM return (error); 8038348SEric.Yu@Sun.COM } 8048348SEric.Yu@Sun.COM 8058348SEric.Yu@Sun.COM if (!so->so_snd_qfull) 8068348SEric.Yu@Sun.COM break; 8078348SEric.Yu@Sun.COM 8088348SEric.Yu@Sun.COM if (so->so_state & SS_CLOSING) { 8098348SEric.Yu@Sun.COM mutex_exit(&so->so_lock); 8108348SEric.Yu@Sun.COM return (EINTR); 8118348SEric.Yu@Sun.COM } 8128348SEric.Yu@Sun.COM /* 8138348SEric.Yu@Sun.COM * Xmit window full in a blocking socket. 8148348SEric.Yu@Sun.COM */ 8158348SEric.Yu@Sun.COM if ((uiop->uio_fmode & (FNDELAY|FNONBLOCK)) || 8168348SEric.Yu@Sun.COM (flags & MSG_DONTWAIT)) { 8178348SEric.Yu@Sun.COM mutex_exit(&so->so_lock); 8188348SEric.Yu@Sun.COM return (EAGAIN); 8198348SEric.Yu@Sun.COM } else { 8208348SEric.Yu@Sun.COM /* 8218348SEric.Yu@Sun.COM * Wait for space to become available and try again. 8228348SEric.Yu@Sun.COM */ 8238348SEric.Yu@Sun.COM error = cv_wait_sig(&so->so_snd_cv, &so->so_lock); 8248348SEric.Yu@Sun.COM if (!error) { /* signal */ 8258348SEric.Yu@Sun.COM mutex_exit(&so->so_lock); 8268348SEric.Yu@Sun.COM return (EINTR); 8278348SEric.Yu@Sun.COM } 8288348SEric.Yu@Sun.COM } 8298348SEric.Yu@Sun.COM } 8308348SEric.Yu@Sun.COM msglen = count = uiop->uio_resid; 8318348SEric.Yu@Sun.COM 8328348SEric.Yu@Sun.COM /* Don't allow sending a message larger than the send buffer size. */ 8338348SEric.Yu@Sun.COM /* XXX Transport module need to enforce this */ 8348348SEric.Yu@Sun.COM if (msglen > so->so_sndbuf) { 8358348SEric.Yu@Sun.COM mutex_exit(&so->so_lock); 8368348SEric.Yu@Sun.COM return (EMSGSIZE); 8378348SEric.Yu@Sun.COM } 8388348SEric.Yu@Sun.COM 8398348SEric.Yu@Sun.COM /* 8408348SEric.Yu@Sun.COM * Allow piggybacking data on handshake messages (SS_ISCONNECTING). 8418348SEric.Yu@Sun.COM */ 8428348SEric.Yu@Sun.COM if (!(so->so_state & (SS_ISCONNECTING | SS_ISCONNECTED))) { 8438348SEric.Yu@Sun.COM /* 8448348SEric.Yu@Sun.COM * We need to check here for listener so that the 8458348SEric.Yu@Sun.COM * same error will be returned as with a TCP socket. 8468348SEric.Yu@Sun.COM * In this case, sosctp_connect() returns EOPNOTSUPP 8478348SEric.Yu@Sun.COM * while a TCP socket returns ENOTCONN instead. Catch it 8488348SEric.Yu@Sun.COM * here to have the same behavior as a TCP socket. 8498348SEric.Yu@Sun.COM * 8508348SEric.Yu@Sun.COM * We also need to make sure that the peer address is 8518348SEric.Yu@Sun.COM * provided before we attempt to do the connect. 8528348SEric.Yu@Sun.COM */ 8538348SEric.Yu@Sun.COM if ((so->so_state & SS_ACCEPTCONN) || 8548348SEric.Yu@Sun.COM msg->msg_name == NULL) { 8558348SEric.Yu@Sun.COM mutex_exit(&so->so_lock); 8568348SEric.Yu@Sun.COM error = ENOTCONN; 8578348SEric.Yu@Sun.COM goto error_nofree; 8588348SEric.Yu@Sun.COM } 8598348SEric.Yu@Sun.COM mutex_exit(&so->so_lock); 8608348SEric.Yu@Sun.COM fflag = uiop->uio_fmode; 8618348SEric.Yu@Sun.COM if (flags & MSG_DONTWAIT) { 8628348SEric.Yu@Sun.COM fflag |= FNDELAY; 8638348SEric.Yu@Sun.COM } 8648348SEric.Yu@Sun.COM error = sosctp_connect(so, msg->msg_name, msg->msg_namelen, 8658348SEric.Yu@Sun.COM fflag, (so->so_version == SOV_XPG4_2) * _SOCONNECT_XPG4_2, 8668348SEric.Yu@Sun.COM cr); 8678348SEric.Yu@Sun.COM if (error) { 8688348SEric.Yu@Sun.COM /* 8698348SEric.Yu@Sun.COM * Check for non-fatal errors, socket connected 8708348SEric.Yu@Sun.COM * while the lock had been lifted. 8718348SEric.Yu@Sun.COM */ 8728348SEric.Yu@Sun.COM if (error != EISCONN && error != EALREADY) { 8738348SEric.Yu@Sun.COM goto error_nofree; 8748348SEric.Yu@Sun.COM } 8758348SEric.Yu@Sun.COM error = 0; 8768348SEric.Yu@Sun.COM } 8778348SEric.Yu@Sun.COM } else { 8788348SEric.Yu@Sun.COM mutex_exit(&so->so_lock); 8798348SEric.Yu@Sun.COM } 8808348SEric.Yu@Sun.COM 8818348SEric.Yu@Sun.COM mctl = sctp_alloc_hdr(msg->msg_name, msg->msg_namelen, 8828348SEric.Yu@Sun.COM msg->msg_control, optlen, SCTP_CAN_BLOCK); 8838348SEric.Yu@Sun.COM if (mctl == NULL) { 8848348SEric.Yu@Sun.COM error = EINTR; 8858348SEric.Yu@Sun.COM goto error_nofree; 8868348SEric.Yu@Sun.COM } 8878348SEric.Yu@Sun.COM 8888348SEric.Yu@Sun.COM /* Copy in the message. */ 8898348SEric.Yu@Sun.COM if ((error = sosctp_uiomove(mctl, count, ss->ss_wrsize, ss->ss_wroff, 890*11042SErik.Nordmark@Sun.COM uiop, flags)) != 0) { 8918348SEric.Yu@Sun.COM goto error_ret; 8928348SEric.Yu@Sun.COM } 8938348SEric.Yu@Sun.COM error = sctp_sendmsg((struct sctp_s *)so->so_proto_handle, mctl, 0); 8948348SEric.Yu@Sun.COM if (error == 0) 8958348SEric.Yu@Sun.COM return (0); 8968348SEric.Yu@Sun.COM 8978348SEric.Yu@Sun.COM error_ret: 8988348SEric.Yu@Sun.COM freemsg(mctl); 8998348SEric.Yu@Sun.COM error_nofree: 9008348SEric.Yu@Sun.COM mutex_enter(&so->so_lock); 9018348SEric.Yu@Sun.COM if ((error == EPIPE) && (so->so_state & SS_CANTSENDMORE)) { 9028348SEric.Yu@Sun.COM /* 9038348SEric.Yu@Sun.COM * We received shutdown between the time lock was 9048348SEric.Yu@Sun.COM * lifted and call to sctp_sendmsg(). 9058348SEric.Yu@Sun.COM */ 9068348SEric.Yu@Sun.COM mutex_exit(&so->so_lock); 9078348SEric.Yu@Sun.COM return (EPIPE); 9088348SEric.Yu@Sun.COM } 9098348SEric.Yu@Sun.COM mutex_exit(&so->so_lock); 9108348SEric.Yu@Sun.COM return (error); 9118348SEric.Yu@Sun.COM } 9128348SEric.Yu@Sun.COM 9138348SEric.Yu@Sun.COM /* 9148348SEric.Yu@Sun.COM * Send message on 1-N socket. Connects automatically if there is 9158348SEric.Yu@Sun.COM * no association. 9168348SEric.Yu@Sun.COM */ 9178348SEric.Yu@Sun.COM static int 9188348SEric.Yu@Sun.COM sosctp_seq_sendmsg(struct sonode *so, struct nmsghdr *msg, struct uio *uiop, 9198348SEric.Yu@Sun.COM struct cred *cr) 9208348SEric.Yu@Sun.COM { 9218348SEric.Yu@Sun.COM struct sctp_sonode *ss; 9228348SEric.Yu@Sun.COM struct sctp_soassoc *ssa; 9238348SEric.Yu@Sun.COM struct cmsghdr *cmsg; 9248348SEric.Yu@Sun.COM struct sctp_sndrcvinfo *sinfo; 9258348SEric.Yu@Sun.COM int aid = 0; 9268348SEric.Yu@Sun.COM mblk_t *mctl; 9278348SEric.Yu@Sun.COM int namelen, optlen, flags; 9288348SEric.Yu@Sun.COM ssize_t count, msglen; 9298348SEric.Yu@Sun.COM int error; 9308348SEric.Yu@Sun.COM uint16_t s_flags = 0; 9318348SEric.Yu@Sun.COM 9328348SEric.Yu@Sun.COM ASSERT(so->so_type == SOCK_SEQPACKET); 9338348SEric.Yu@Sun.COM 9348348SEric.Yu@Sun.COM /* 9358348SEric.Yu@Sun.COM * There shouldn't be problems with alignment, as the memory for 9368348SEric.Yu@Sun.COM * msg_control was alloced with kmem_alloc. 9378348SEric.Yu@Sun.COM */ 9388348SEric.Yu@Sun.COM cmsg = sosctp_find_cmsg(msg->msg_control, msg->msg_controllen, 9398348SEric.Yu@Sun.COM SCTP_SNDRCV); 9408348SEric.Yu@Sun.COM if (cmsg != NULL) { 9418348SEric.Yu@Sun.COM if (cmsg->cmsg_len < (sizeof (*sinfo) + sizeof (*cmsg))) { 9428348SEric.Yu@Sun.COM eprintsoline(so, EINVAL); 9438348SEric.Yu@Sun.COM return (EINVAL); 9448348SEric.Yu@Sun.COM } 9458348SEric.Yu@Sun.COM sinfo = (struct sctp_sndrcvinfo *)(cmsg + 1); 9468348SEric.Yu@Sun.COM s_flags = sinfo->sinfo_flags; 9478348SEric.Yu@Sun.COM aid = sinfo->sinfo_assoc_id; 9488348SEric.Yu@Sun.COM } 9498348SEric.Yu@Sun.COM 9508348SEric.Yu@Sun.COM ss = SOTOSSO(so); 9518348SEric.Yu@Sun.COM namelen = msg->msg_namelen; 9528348SEric.Yu@Sun.COM 9538348SEric.Yu@Sun.COM if (msg->msg_controllen > 0) { 9548348SEric.Yu@Sun.COM optlen = msg->msg_controllen; 9558348SEric.Yu@Sun.COM } else { 9568348SEric.Yu@Sun.COM optlen = 0; 9578348SEric.Yu@Sun.COM } 9588348SEric.Yu@Sun.COM 9598348SEric.Yu@Sun.COM mutex_enter(&so->so_lock); 9608348SEric.Yu@Sun.COM 9618348SEric.Yu@Sun.COM /* 9628348SEric.Yu@Sun.COM * If there is no association id, connect to address specified 9638348SEric.Yu@Sun.COM * in msg_name. Otherwise look up the association using the id. 9648348SEric.Yu@Sun.COM */ 9658348SEric.Yu@Sun.COM if (aid == 0) { 9668348SEric.Yu@Sun.COM /* 9678348SEric.Yu@Sun.COM * Connect and shutdown cannot be done together, so check for 9688348SEric.Yu@Sun.COM * MSG_EOF. 9698348SEric.Yu@Sun.COM */ 9708348SEric.Yu@Sun.COM if (msg->msg_name == NULL || namelen == 0 || 9718348SEric.Yu@Sun.COM (s_flags & MSG_EOF)) { 9728348SEric.Yu@Sun.COM error = EINVAL; 9738348SEric.Yu@Sun.COM eprintsoline(so, error); 9748348SEric.Yu@Sun.COM goto done; 9758348SEric.Yu@Sun.COM } 9768348SEric.Yu@Sun.COM flags = uiop->uio_fmode; 9778348SEric.Yu@Sun.COM if (msg->msg_flags & MSG_DONTWAIT) { 9788348SEric.Yu@Sun.COM flags |= FNDELAY; 9798348SEric.Yu@Sun.COM } 9808348SEric.Yu@Sun.COM so_lock_single(so); 9818348SEric.Yu@Sun.COM error = sosctp_assoc_createconn(ss, msg->msg_name, namelen, 9828348SEric.Yu@Sun.COM msg->msg_control, optlen, flags, cr, &ssa); 9838348SEric.Yu@Sun.COM if (error) { 9848348SEric.Yu@Sun.COM if ((so->so_version == SOV_XPG4_2) && 9858348SEric.Yu@Sun.COM (error == EHOSTUNREACH)) { 9868348SEric.Yu@Sun.COM error = ENETUNREACH; 9878348SEric.Yu@Sun.COM } 9888348SEric.Yu@Sun.COM if (ssa == NULL) { 9898348SEric.Yu@Sun.COM /* 9908348SEric.Yu@Sun.COM * Fatal error during connect(). Bail out. 9918348SEric.Yu@Sun.COM * If ssa exists, it means that the handshake 9928348SEric.Yu@Sun.COM * is in progress. 9938348SEric.Yu@Sun.COM */ 9948348SEric.Yu@Sun.COM eprintsoline(so, error); 9958348SEric.Yu@Sun.COM so_unlock_single(so, SOLOCKED); 9968348SEric.Yu@Sun.COM goto done; 9978348SEric.Yu@Sun.COM } 9988348SEric.Yu@Sun.COM /* 9998348SEric.Yu@Sun.COM * All the errors are non-fatal ones, don't return 10008348SEric.Yu@Sun.COM * e.g. EINPROGRESS from sendmsg(). 10018348SEric.Yu@Sun.COM */ 10028348SEric.Yu@Sun.COM error = 0; 10038348SEric.Yu@Sun.COM } 10048348SEric.Yu@Sun.COM so_unlock_single(so, SOLOCKED); 10058348SEric.Yu@Sun.COM } else { 10068348SEric.Yu@Sun.COM if ((error = sosctp_assoc(ss, aid, &ssa)) != 0) { 10078348SEric.Yu@Sun.COM eprintsoline(so, error); 10088348SEric.Yu@Sun.COM goto done; 10098348SEric.Yu@Sun.COM } 10108348SEric.Yu@Sun.COM } 10118348SEric.Yu@Sun.COM 10128348SEric.Yu@Sun.COM /* 10138348SEric.Yu@Sun.COM * Now we have an association. 10148348SEric.Yu@Sun.COM */ 10158348SEric.Yu@Sun.COM flags = msg->msg_flags; 10168348SEric.Yu@Sun.COM 10178348SEric.Yu@Sun.COM /* 10188348SEric.Yu@Sun.COM * MSG_EOF initiates graceful shutdown. 10198348SEric.Yu@Sun.COM */ 10208348SEric.Yu@Sun.COM if (s_flags & MSG_EOF) { 10218348SEric.Yu@Sun.COM if (uiop->uio_resid) { 10228348SEric.Yu@Sun.COM /* 10238348SEric.Yu@Sun.COM * Can't include data in MSG_EOF message. 10248348SEric.Yu@Sun.COM */ 10258348SEric.Yu@Sun.COM error = EINVAL; 10268348SEric.Yu@Sun.COM } else { 10278348SEric.Yu@Sun.COM mutex_exit(&so->so_lock); 10288348SEric.Yu@Sun.COM ssa->ssa_state |= SS_ISDISCONNECTING; 10298348SEric.Yu@Sun.COM sctp_recvd((struct sctp_s *)ssa->ssa_conn, 10308348SEric.Yu@Sun.COM so->so_rcvbuf); 10318348SEric.Yu@Sun.COM error = sctp_disconnect((struct sctp_s *)ssa->ssa_conn); 10328348SEric.Yu@Sun.COM mutex_enter(&so->so_lock); 10338348SEric.Yu@Sun.COM } 10348348SEric.Yu@Sun.COM goto refrele; 10358348SEric.Yu@Sun.COM } 10368348SEric.Yu@Sun.COM 10378348SEric.Yu@Sun.COM for (;;) { 10388348SEric.Yu@Sun.COM if (ssa->ssa_state & SS_CANTSENDMORE) { 10398348SEric.Yu@Sun.COM SSA_REFRELE(ss, ssa); 10408348SEric.Yu@Sun.COM mutex_exit(&so->so_lock); 10418348SEric.Yu@Sun.COM return (EPIPE); 10428348SEric.Yu@Sun.COM } 10438348SEric.Yu@Sun.COM if (ssa->ssa_error != 0) { 10448348SEric.Yu@Sun.COM error = ssa->ssa_error; 10458348SEric.Yu@Sun.COM ssa->ssa_error = 0; 10468348SEric.Yu@Sun.COM goto refrele; 10478348SEric.Yu@Sun.COM } 10488348SEric.Yu@Sun.COM 10498348SEric.Yu@Sun.COM if (!ssa->ssa_snd_qfull) 10508348SEric.Yu@Sun.COM break; 10518348SEric.Yu@Sun.COM 10528348SEric.Yu@Sun.COM if (so->so_state & SS_CLOSING) { 10538348SEric.Yu@Sun.COM error = EINTR; 10548348SEric.Yu@Sun.COM goto refrele; 10558348SEric.Yu@Sun.COM } 10568348SEric.Yu@Sun.COM if ((uiop->uio_fmode & (FNDELAY|FNONBLOCK)) || 10578348SEric.Yu@Sun.COM (flags & MSG_DONTWAIT)) { 10588348SEric.Yu@Sun.COM error = EAGAIN; 10598348SEric.Yu@Sun.COM goto refrele; 10608348SEric.Yu@Sun.COM } else { 10618348SEric.Yu@Sun.COM /* 10628348SEric.Yu@Sun.COM * Wait for space to become available and try again. 10638348SEric.Yu@Sun.COM */ 10648348SEric.Yu@Sun.COM error = cv_wait_sig(&so->so_snd_cv, &so->so_lock); 10658348SEric.Yu@Sun.COM if (!error) { /* signal */ 10668348SEric.Yu@Sun.COM error = EINTR; 10678348SEric.Yu@Sun.COM goto refrele; 10688348SEric.Yu@Sun.COM } 10698348SEric.Yu@Sun.COM } 10708348SEric.Yu@Sun.COM } 10718348SEric.Yu@Sun.COM 10728348SEric.Yu@Sun.COM msglen = count = uiop->uio_resid; 10738348SEric.Yu@Sun.COM 10748348SEric.Yu@Sun.COM /* Don't allow sending a message larger than the send buffer size. */ 10758348SEric.Yu@Sun.COM if (msglen > so->so_sndbuf) { 10768348SEric.Yu@Sun.COM error = EMSGSIZE; 10778348SEric.Yu@Sun.COM goto refrele; 10788348SEric.Yu@Sun.COM } 10798348SEric.Yu@Sun.COM 10808348SEric.Yu@Sun.COM /* 10818348SEric.Yu@Sun.COM * Update TX buffer usage here so that we can lift the socket lock. 10828348SEric.Yu@Sun.COM */ 10838348SEric.Yu@Sun.COM mutex_exit(&so->so_lock); 10848348SEric.Yu@Sun.COM 10858348SEric.Yu@Sun.COM mctl = sctp_alloc_hdr(msg->msg_name, namelen, msg->msg_control, 10868348SEric.Yu@Sun.COM optlen, SCTP_CAN_BLOCK); 10878348SEric.Yu@Sun.COM if (mctl == NULL) { 10888348SEric.Yu@Sun.COM error = EINTR; 10898348SEric.Yu@Sun.COM goto lock_rele; 10908348SEric.Yu@Sun.COM } 10918348SEric.Yu@Sun.COM 10928348SEric.Yu@Sun.COM /* Copy in the message. */ 10938348SEric.Yu@Sun.COM if ((error = sosctp_uiomove(mctl, count, ssa->ssa_wrsize, 1094*11042SErik.Nordmark@Sun.COM ssa->ssa_wroff, uiop, flags)) != 0) { 10958348SEric.Yu@Sun.COM goto lock_rele; 10968348SEric.Yu@Sun.COM } 10978348SEric.Yu@Sun.COM error = sctp_sendmsg((struct sctp_s *)ssa->ssa_conn, mctl, 0); 10988348SEric.Yu@Sun.COM lock_rele: 10998348SEric.Yu@Sun.COM mutex_enter(&so->so_lock); 11008348SEric.Yu@Sun.COM if (error != 0) { 11018348SEric.Yu@Sun.COM freemsg(mctl); 11028348SEric.Yu@Sun.COM if ((error == EPIPE) && (ssa->ssa_state & SS_CANTSENDMORE)) { 11038348SEric.Yu@Sun.COM /* 11048348SEric.Yu@Sun.COM * We received shutdown between the time lock was 11058348SEric.Yu@Sun.COM * lifted and call to sctp_sendmsg(). 11068348SEric.Yu@Sun.COM */ 11078348SEric.Yu@Sun.COM SSA_REFRELE(ss, ssa); 11088348SEric.Yu@Sun.COM mutex_exit(&so->so_lock); 11098348SEric.Yu@Sun.COM return (EPIPE); 11108348SEric.Yu@Sun.COM } 11118348SEric.Yu@Sun.COM } 11128348SEric.Yu@Sun.COM 11138348SEric.Yu@Sun.COM refrele: 11148348SEric.Yu@Sun.COM SSA_REFRELE(ss, ssa); 11158348SEric.Yu@Sun.COM done: 11168348SEric.Yu@Sun.COM mutex_exit(&so->so_lock); 11178348SEric.Yu@Sun.COM return (error); 11188348SEric.Yu@Sun.COM } 11198348SEric.Yu@Sun.COM 11208348SEric.Yu@Sun.COM /* 11218348SEric.Yu@Sun.COM * Get address of remote node. 11228348SEric.Yu@Sun.COM */ 11238348SEric.Yu@Sun.COM /* ARGSUSED */ 11248348SEric.Yu@Sun.COM static int 11258348SEric.Yu@Sun.COM sosctp_getpeername(struct sonode *so, struct sockaddr *addr, socklen_t *addrlen, 11268348SEric.Yu@Sun.COM boolean_t accept, struct cred *cr) 11278348SEric.Yu@Sun.COM { 11288348SEric.Yu@Sun.COM return (sctp_getpeername((struct sctp_s *)so->so_proto_handle, addr, 11298348SEric.Yu@Sun.COM addrlen)); 11308348SEric.Yu@Sun.COM } 11318348SEric.Yu@Sun.COM 11328348SEric.Yu@Sun.COM /* 11338348SEric.Yu@Sun.COM * Get local address. 11348348SEric.Yu@Sun.COM */ 11358348SEric.Yu@Sun.COM /* ARGSUSED */ 11368348SEric.Yu@Sun.COM static int 11378348SEric.Yu@Sun.COM sosctp_getsockname(struct sonode *so, struct sockaddr *addr, socklen_t *addrlen, 11388348SEric.Yu@Sun.COM struct cred *cr) 11398348SEric.Yu@Sun.COM { 11408348SEric.Yu@Sun.COM return (sctp_getsockname((struct sctp_s *)so->so_proto_handle, addr, 11418348SEric.Yu@Sun.COM addrlen)); 11428348SEric.Yu@Sun.COM } 11438348SEric.Yu@Sun.COM 11448348SEric.Yu@Sun.COM /* 11458348SEric.Yu@Sun.COM * Called from shutdown(). 11468348SEric.Yu@Sun.COM */ 11478348SEric.Yu@Sun.COM /* ARGSUSED */ 11488348SEric.Yu@Sun.COM static int 11498348SEric.Yu@Sun.COM sosctp_shutdown(struct sonode *so, int how, struct cred *cr) 11508348SEric.Yu@Sun.COM { 11518348SEric.Yu@Sun.COM uint_t state_change; 11528348SEric.Yu@Sun.COM int wakesig = 0; 11538348SEric.Yu@Sun.COM int error = 0; 11548348SEric.Yu@Sun.COM 11558348SEric.Yu@Sun.COM mutex_enter(&so->so_lock); 11568348SEric.Yu@Sun.COM /* 11578348SEric.Yu@Sun.COM * Record the current state and then perform any state changes. 11588348SEric.Yu@Sun.COM * Then use the difference between the old and new states to 11598348SEric.Yu@Sun.COM * determine which needs to be done. 11608348SEric.Yu@Sun.COM */ 11618348SEric.Yu@Sun.COM state_change = so->so_state; 11628348SEric.Yu@Sun.COM 11638348SEric.Yu@Sun.COM switch (how) { 11648348SEric.Yu@Sun.COM case SHUT_RD: 11658348SEric.Yu@Sun.COM socantrcvmore(so); 11668348SEric.Yu@Sun.COM break; 11678348SEric.Yu@Sun.COM case SHUT_WR: 11688348SEric.Yu@Sun.COM socantsendmore(so); 11698348SEric.Yu@Sun.COM break; 11708348SEric.Yu@Sun.COM case SHUT_RDWR: 11718348SEric.Yu@Sun.COM socantsendmore(so); 11728348SEric.Yu@Sun.COM socantrcvmore(so); 11738348SEric.Yu@Sun.COM break; 11748348SEric.Yu@Sun.COM default: 11758348SEric.Yu@Sun.COM mutex_exit(&so->so_lock); 11768348SEric.Yu@Sun.COM return (EINVAL); 11778348SEric.Yu@Sun.COM } 11788348SEric.Yu@Sun.COM 11798348SEric.Yu@Sun.COM state_change = so->so_state & ~state_change; 11808348SEric.Yu@Sun.COM 11818348SEric.Yu@Sun.COM if (state_change & SS_CANTRCVMORE) { 11828348SEric.Yu@Sun.COM if (so->so_rcv_q_head == NULL) { 11838348SEric.Yu@Sun.COM cv_signal(&so->so_rcv_cv); 11848348SEric.Yu@Sun.COM } 11858348SEric.Yu@Sun.COM wakesig = POLLIN|POLLRDNORM; 11868348SEric.Yu@Sun.COM 11878348SEric.Yu@Sun.COM socket_sendsig(so, SOCKETSIG_READ); 11888348SEric.Yu@Sun.COM } 11898348SEric.Yu@Sun.COM if (state_change & SS_CANTSENDMORE) { 11908348SEric.Yu@Sun.COM cv_broadcast(&so->so_snd_cv); 11918348SEric.Yu@Sun.COM wakesig |= POLLOUT; 11928348SEric.Yu@Sun.COM 11938348SEric.Yu@Sun.COM so->so_state |= SS_ISDISCONNECTING; 11948348SEric.Yu@Sun.COM } 11958348SEric.Yu@Sun.COM mutex_exit(&so->so_lock); 11968348SEric.Yu@Sun.COM 11978348SEric.Yu@Sun.COM pollwakeup(&so->so_poll_list, wakesig); 11988348SEric.Yu@Sun.COM 11998348SEric.Yu@Sun.COM if (state_change & SS_CANTSENDMORE) { 12008348SEric.Yu@Sun.COM sctp_recvd((struct sctp_s *)so->so_proto_handle, so->so_rcvbuf); 12018348SEric.Yu@Sun.COM error = sctp_disconnect((struct sctp_s *)so->so_proto_handle); 12028348SEric.Yu@Sun.COM } 12038348SEric.Yu@Sun.COM 12048348SEric.Yu@Sun.COM /* 12058348SEric.Yu@Sun.COM * HACK: sctp_disconnect() may return EWOULDBLOCK. But this error is 12068348SEric.Yu@Sun.COM * not documented in standard socket API. Catch it here. 12078348SEric.Yu@Sun.COM */ 12088348SEric.Yu@Sun.COM if (error == EWOULDBLOCK) 12098348SEric.Yu@Sun.COM error = 0; 12108348SEric.Yu@Sun.COM return (error); 12118348SEric.Yu@Sun.COM } 12128348SEric.Yu@Sun.COM 12138348SEric.Yu@Sun.COM /* 12148348SEric.Yu@Sun.COM * Get socket options. 12158348SEric.Yu@Sun.COM */ 12168348SEric.Yu@Sun.COM /*ARGSUSED5*/ 12178348SEric.Yu@Sun.COM static int 12188348SEric.Yu@Sun.COM sosctp_getsockopt(struct sonode *so, int level, int option_name, 12198348SEric.Yu@Sun.COM void *optval, socklen_t *optlenp, int flags, struct cred *cr) 12208348SEric.Yu@Sun.COM { 12218443SRao.Shoaib@Sun.COM socklen_t maxlen = *optlenp; 12228443SRao.Shoaib@Sun.COM socklen_t len; 12238443SRao.Shoaib@Sun.COM socklen_t optlen; 12248443SRao.Shoaib@Sun.COM uint8_t buffer[4]; 12258443SRao.Shoaib@Sun.COM void *optbuf = &buffer; 12268443SRao.Shoaib@Sun.COM int error = 0; 12278443SRao.Shoaib@Sun.COM 12288443SRao.Shoaib@Sun.COM if (level == SOL_SOCKET) { 12298443SRao.Shoaib@Sun.COM switch (option_name) { 12308443SRao.Shoaib@Sun.COM /* Not supported options */ 12318443SRao.Shoaib@Sun.COM case SO_SNDTIMEO: 12328443SRao.Shoaib@Sun.COM case SO_RCVTIMEO: 12338443SRao.Shoaib@Sun.COM case SO_EXCLBIND: 123410833SAnders.Persson@Sun.COM eprintsoline(so, ENOPROTOOPT); 123510833SAnders.Persson@Sun.COM return (ENOPROTOOPT); 123610833SAnders.Persson@Sun.COM default: 123710833SAnders.Persson@Sun.COM error = socket_getopt_common(so, level, option_name, 123810833SAnders.Persson@Sun.COM optval, optlenp, flags); 123910833SAnders.Persson@Sun.COM if (error >= 0) 124010833SAnders.Persson@Sun.COM return (error); 124110833SAnders.Persson@Sun.COM /* Pass the request to the protocol */ 12428443SRao.Shoaib@Sun.COM break; 12438443SRao.Shoaib@Sun.COM } 12448443SRao.Shoaib@Sun.COM } 12458443SRao.Shoaib@Sun.COM 12468348SEric.Yu@Sun.COM if (level == IPPROTO_SCTP) { 12478348SEric.Yu@Sun.COM /* 12488348SEric.Yu@Sun.COM * Should go through ioctl(). 12498348SEric.Yu@Sun.COM */ 12508348SEric.Yu@Sun.COM return (EINVAL); 12518348SEric.Yu@Sun.COM } 12528443SRao.Shoaib@Sun.COM 12538443SRao.Shoaib@Sun.COM if (maxlen > sizeof (buffer)) { 12548443SRao.Shoaib@Sun.COM optbuf = kmem_alloc(maxlen, KM_SLEEP); 12558443SRao.Shoaib@Sun.COM } 12568443SRao.Shoaib@Sun.COM optlen = maxlen; 12578443SRao.Shoaib@Sun.COM 12588443SRao.Shoaib@Sun.COM /* 12598443SRao.Shoaib@Sun.COM * If the resulting optlen is greater than the provided maxlen, then 12608443SRao.Shoaib@Sun.COM * we sliently trucate. 12618443SRao.Shoaib@Sun.COM */ 12628443SRao.Shoaib@Sun.COM error = sctp_get_opt((struct sctp_s *)so->so_proto_handle, level, 12638443SRao.Shoaib@Sun.COM option_name, optbuf, &optlen); 12648443SRao.Shoaib@Sun.COM 12658443SRao.Shoaib@Sun.COM if (error != 0) { 12668443SRao.Shoaib@Sun.COM eprintsoline(so, error); 12678443SRao.Shoaib@Sun.COM goto free; 12688443SRao.Shoaib@Sun.COM } 12698443SRao.Shoaib@Sun.COM len = optlen; 12708443SRao.Shoaib@Sun.COM 12718443SRao.Shoaib@Sun.COM copyout: 12728443SRao.Shoaib@Sun.COM 12738443SRao.Shoaib@Sun.COM len = MIN(len, maxlen); 12748443SRao.Shoaib@Sun.COM bcopy(optbuf, optval, len); 12758443SRao.Shoaib@Sun.COM *optlenp = optlen; 12768443SRao.Shoaib@Sun.COM free: 12778443SRao.Shoaib@Sun.COM if (optbuf != &buffer) { 12788443SRao.Shoaib@Sun.COM kmem_free(optbuf, maxlen); 12798443SRao.Shoaib@Sun.COM } 128010833SAnders.Persson@Sun.COM 12818443SRao.Shoaib@Sun.COM return (error); 12828348SEric.Yu@Sun.COM } 12838348SEric.Yu@Sun.COM 12848348SEric.Yu@Sun.COM /* 12858348SEric.Yu@Sun.COM * Set socket options 12868348SEric.Yu@Sun.COM */ 12878348SEric.Yu@Sun.COM /* ARGSUSED */ 12888348SEric.Yu@Sun.COM static int 12898348SEric.Yu@Sun.COM sosctp_setsockopt(struct sonode *so, int level, int option_name, 12908348SEric.Yu@Sun.COM const void *optval, t_uscalar_t optlen, struct cred *cr) 12918348SEric.Yu@Sun.COM { 12928348SEric.Yu@Sun.COM struct sctp_sonode *ss = SOTOSSO(so); 12938348SEric.Yu@Sun.COM struct sctp_soassoc *ssa = NULL; 12948348SEric.Yu@Sun.COM sctp_assoc_t id; 12958348SEric.Yu@Sun.COM int error, rc; 12968348SEric.Yu@Sun.COM void *conn = NULL; 12978348SEric.Yu@Sun.COM 12988348SEric.Yu@Sun.COM mutex_enter(&so->so_lock); 12998348SEric.Yu@Sun.COM 13008348SEric.Yu@Sun.COM /* 13018348SEric.Yu@Sun.COM * For some SCTP level options, one can select the association this 13028348SEric.Yu@Sun.COM * applies to. 13038348SEric.Yu@Sun.COM */ 13048348SEric.Yu@Sun.COM if (so->so_type == SOCK_STREAM) { 13058348SEric.Yu@Sun.COM conn = so->so_proto_handle; 13068348SEric.Yu@Sun.COM } else { 13078348SEric.Yu@Sun.COM /* 13088348SEric.Yu@Sun.COM * SOCK_SEQPACKET only 13098348SEric.Yu@Sun.COM */ 13108348SEric.Yu@Sun.COM id = 0; 13118348SEric.Yu@Sun.COM if (level == IPPROTO_SCTP) { 13128348SEric.Yu@Sun.COM switch (option_name) { 13138348SEric.Yu@Sun.COM case SCTP_RTOINFO: 13148348SEric.Yu@Sun.COM case SCTP_ASSOCINFO: 13158348SEric.Yu@Sun.COM case SCTP_SET_PEER_PRIMARY_ADDR: 13168348SEric.Yu@Sun.COM case SCTP_PRIMARY_ADDR: 13178348SEric.Yu@Sun.COM case SCTP_PEER_ADDR_PARAMS: 13188348SEric.Yu@Sun.COM /* 13198348SEric.Yu@Sun.COM * Association ID is the first element 13208348SEric.Yu@Sun.COM * params struct 13218348SEric.Yu@Sun.COM */ 13228348SEric.Yu@Sun.COM if (optlen < sizeof (sctp_assoc_t)) { 13238348SEric.Yu@Sun.COM error = EINVAL; 13248348SEric.Yu@Sun.COM eprintsoline(so, error); 13258348SEric.Yu@Sun.COM goto done; 13268348SEric.Yu@Sun.COM } 13278348SEric.Yu@Sun.COM id = *(sctp_assoc_t *)optval; 13288348SEric.Yu@Sun.COM break; 13298348SEric.Yu@Sun.COM case SCTP_DEFAULT_SEND_PARAM: 13308348SEric.Yu@Sun.COM if (optlen != sizeof (struct sctp_sndrcvinfo)) { 13318348SEric.Yu@Sun.COM error = EINVAL; 13328348SEric.Yu@Sun.COM eprintsoline(so, error); 13338348SEric.Yu@Sun.COM goto done; 13348348SEric.Yu@Sun.COM } 13358348SEric.Yu@Sun.COM id = ((struct sctp_sndrcvinfo *) 13368348SEric.Yu@Sun.COM optval)->sinfo_assoc_id; 13378348SEric.Yu@Sun.COM break; 13388348SEric.Yu@Sun.COM case SCTP_INITMSG: 13398348SEric.Yu@Sun.COM /* 13408348SEric.Yu@Sun.COM * Only applies to future associations 13418348SEric.Yu@Sun.COM */ 13428348SEric.Yu@Sun.COM conn = so->so_proto_handle; 13438348SEric.Yu@Sun.COM break; 13448348SEric.Yu@Sun.COM default: 13458348SEric.Yu@Sun.COM break; 13468348SEric.Yu@Sun.COM } 13478348SEric.Yu@Sun.COM } else if (level == SOL_SOCKET) { 13488348SEric.Yu@Sun.COM if (option_name == SO_LINGER) { 13498348SEric.Yu@Sun.COM error = EOPNOTSUPP; 13508348SEric.Yu@Sun.COM eprintsoline(so, error); 13518348SEric.Yu@Sun.COM goto done; 13528348SEric.Yu@Sun.COM } 13538348SEric.Yu@Sun.COM /* 13548348SEric.Yu@Sun.COM * These 2 options are applied to all associations. 13558348SEric.Yu@Sun.COM * The other socket level options are only applied 13568348SEric.Yu@Sun.COM * to the socket (not associations). 13578348SEric.Yu@Sun.COM */ 13588348SEric.Yu@Sun.COM if ((option_name != SO_RCVBUF) && 13598348SEric.Yu@Sun.COM (option_name != SO_SNDBUF)) { 13608348SEric.Yu@Sun.COM conn = so->so_proto_handle; 13618348SEric.Yu@Sun.COM } 13628348SEric.Yu@Sun.COM } else { 13638348SEric.Yu@Sun.COM conn = NULL; 13648348SEric.Yu@Sun.COM } 13658348SEric.Yu@Sun.COM 13668348SEric.Yu@Sun.COM /* 13678348SEric.Yu@Sun.COM * If association ID was specified, do op on that assoc. 13688348SEric.Yu@Sun.COM * Otherwise set the default setting of a socket. 13698348SEric.Yu@Sun.COM */ 13708348SEric.Yu@Sun.COM if (id != 0) { 13718348SEric.Yu@Sun.COM if ((error = sosctp_assoc(ss, id, &ssa)) != 0) { 13728348SEric.Yu@Sun.COM eprintsoline(so, error); 13738348SEric.Yu@Sun.COM goto done; 13748348SEric.Yu@Sun.COM } 13758348SEric.Yu@Sun.COM conn = ssa->ssa_conn; 13768348SEric.Yu@Sun.COM } 13778348SEric.Yu@Sun.COM } 13788348SEric.Yu@Sun.COM dprint(2, ("sosctp_setsockopt %p (%d) - conn %p %d %d id:%d\n", 13798348SEric.Yu@Sun.COM (void *)ss, so->so_type, (void *)conn, level, option_name, id)); 13808348SEric.Yu@Sun.COM 13818348SEric.Yu@Sun.COM ASSERT(ssa == NULL || (ssa != NULL && conn != NULL)); 13828348SEric.Yu@Sun.COM if (conn != NULL) { 13838348SEric.Yu@Sun.COM mutex_exit(&so->so_lock); 13848348SEric.Yu@Sun.COM error = sctp_set_opt((struct sctp_s *)conn, level, option_name, 13858348SEric.Yu@Sun.COM optval, optlen); 13868348SEric.Yu@Sun.COM mutex_enter(&so->so_lock); 13878348SEric.Yu@Sun.COM if (ssa != NULL) 13888348SEric.Yu@Sun.COM SSA_REFRELE(ss, ssa); 13898348SEric.Yu@Sun.COM } else { 13908348SEric.Yu@Sun.COM /* 13918348SEric.Yu@Sun.COM * 1-N socket, and we have to apply the operation to ALL 13928348SEric.Yu@Sun.COM * associations. Like with anything of this sort, the 13938348SEric.Yu@Sun.COM * problem is what to do if the operation fails. 13948348SEric.Yu@Sun.COM * Just try to apply the setting to everyone, but store 13958348SEric.Yu@Sun.COM * error number if someone returns such. And since we are 13968348SEric.Yu@Sun.COM * looping through all possible aids, some of them can be 13978348SEric.Yu@Sun.COM * invalid. We just ignore this kind (sosctp_assoc()) of 13988348SEric.Yu@Sun.COM * errors. 13998348SEric.Yu@Sun.COM */ 14008348SEric.Yu@Sun.COM sctp_assoc_t aid; 14018348SEric.Yu@Sun.COM 14028348SEric.Yu@Sun.COM mutex_exit(&so->so_lock); 14038348SEric.Yu@Sun.COM error = sctp_set_opt((struct sctp_s *)so->so_proto_handle, 14048348SEric.Yu@Sun.COM level, option_name, optval, optlen); 14058348SEric.Yu@Sun.COM mutex_enter(&so->so_lock); 14068348SEric.Yu@Sun.COM for (aid = 1; aid < ss->ss_maxassoc; aid++) { 14078348SEric.Yu@Sun.COM if (sosctp_assoc(ss, aid, &ssa) != 0) 14088348SEric.Yu@Sun.COM continue; 14098348SEric.Yu@Sun.COM mutex_exit(&so->so_lock); 14108348SEric.Yu@Sun.COM rc = sctp_set_opt((struct sctp_s *)ssa->ssa_conn, level, 14118348SEric.Yu@Sun.COM option_name, optval, optlen); 14128348SEric.Yu@Sun.COM mutex_enter(&so->so_lock); 14138348SEric.Yu@Sun.COM SSA_REFRELE(ss, ssa); 14148348SEric.Yu@Sun.COM if (error == 0) { 14158348SEric.Yu@Sun.COM error = rc; 14168348SEric.Yu@Sun.COM } 14178348SEric.Yu@Sun.COM } 14188348SEric.Yu@Sun.COM } 14198348SEric.Yu@Sun.COM done: 14208348SEric.Yu@Sun.COM mutex_exit(&so->so_lock); 14218348SEric.Yu@Sun.COM return (error); 14228348SEric.Yu@Sun.COM } 14238348SEric.Yu@Sun.COM 14248348SEric.Yu@Sun.COM /*ARGSUSED*/ 14258348SEric.Yu@Sun.COM static int 14268348SEric.Yu@Sun.COM sosctp_ioctl(struct sonode *so, int cmd, intptr_t arg, int mode, 14278348SEric.Yu@Sun.COM struct cred *cr, int32_t *rvalp) 14288348SEric.Yu@Sun.COM { 14298348SEric.Yu@Sun.COM struct sctp_sonode *ss; 14308348SEric.Yu@Sun.COM int32_t value; 14318348SEric.Yu@Sun.COM int error; 14328348SEric.Yu@Sun.COM int intval; 14338348SEric.Yu@Sun.COM pid_t pid; 14348348SEric.Yu@Sun.COM struct sctp_soassoc *ssa; 14358348SEric.Yu@Sun.COM void *conn; 14368348SEric.Yu@Sun.COM void *buf; 14378348SEric.Yu@Sun.COM STRUCT_DECL(sctpopt, opt); 14388348SEric.Yu@Sun.COM uint32_t optlen; 14398348SEric.Yu@Sun.COM int buflen; 14408348SEric.Yu@Sun.COM 14418348SEric.Yu@Sun.COM ss = SOTOSSO(so); 14428348SEric.Yu@Sun.COM 14438348SEric.Yu@Sun.COM /* handle socket specific ioctls */ 14448348SEric.Yu@Sun.COM switch (cmd) { 14458348SEric.Yu@Sun.COM case FIONBIO: 14468348SEric.Yu@Sun.COM if (so_copyin((void *)arg, &value, sizeof (int32_t), 14478348SEric.Yu@Sun.COM (mode & (int)FKIOCTL))) { 14488348SEric.Yu@Sun.COM return (EFAULT); 14498348SEric.Yu@Sun.COM } 14508348SEric.Yu@Sun.COM mutex_enter(&so->so_lock); 14518348SEric.Yu@Sun.COM if (value) { 14528348SEric.Yu@Sun.COM so->so_state |= SS_NDELAY; 14538348SEric.Yu@Sun.COM } else { 14548348SEric.Yu@Sun.COM so->so_state &= ~SS_NDELAY; 14558348SEric.Yu@Sun.COM } 14568348SEric.Yu@Sun.COM mutex_exit(&so->so_lock); 14578348SEric.Yu@Sun.COM return (0); 14588348SEric.Yu@Sun.COM 14598348SEric.Yu@Sun.COM case FIOASYNC: 14608348SEric.Yu@Sun.COM if (so_copyin((void *)arg, &value, sizeof (int32_t), 14618348SEric.Yu@Sun.COM (mode & (int)FKIOCTL))) { 14628348SEric.Yu@Sun.COM return (EFAULT); 14638348SEric.Yu@Sun.COM } 14648348SEric.Yu@Sun.COM mutex_enter(&so->so_lock); 14658348SEric.Yu@Sun.COM 14668348SEric.Yu@Sun.COM if (value) { 14678348SEric.Yu@Sun.COM /* Turn on SIGIO */ 14688348SEric.Yu@Sun.COM so->so_state |= SS_ASYNC; 14698348SEric.Yu@Sun.COM } else { 14708348SEric.Yu@Sun.COM /* Turn off SIGIO */ 14718348SEric.Yu@Sun.COM so->so_state &= ~SS_ASYNC; 14728348SEric.Yu@Sun.COM } 14738348SEric.Yu@Sun.COM mutex_exit(&so->so_lock); 14748348SEric.Yu@Sun.COM return (0); 14758348SEric.Yu@Sun.COM 14768348SEric.Yu@Sun.COM case SIOCSPGRP: 14778348SEric.Yu@Sun.COM case FIOSETOWN: 14788348SEric.Yu@Sun.COM if (so_copyin((void *)arg, &pid, sizeof (pid_t), 14798348SEric.Yu@Sun.COM (mode & (int)FKIOCTL))) { 14808348SEric.Yu@Sun.COM return (EFAULT); 14818348SEric.Yu@Sun.COM } 14828348SEric.Yu@Sun.COM mutex_enter(&so->so_lock); 14838348SEric.Yu@Sun.COM 14848348SEric.Yu@Sun.COM error = (pid != so->so_pgrp) ? socket_chgpgrp(so, pid) : 0; 14858348SEric.Yu@Sun.COM mutex_exit(&so->so_lock); 14868348SEric.Yu@Sun.COM return (error); 14878348SEric.Yu@Sun.COM 14888348SEric.Yu@Sun.COM case SIOCGPGRP: 14898348SEric.Yu@Sun.COM case FIOGETOWN: 14908348SEric.Yu@Sun.COM if (so_copyout(&so->so_pgrp, (void *)arg, 14918348SEric.Yu@Sun.COM sizeof (pid_t), (mode & (int)FKIOCTL))) 14928348SEric.Yu@Sun.COM return (EFAULT); 14938348SEric.Yu@Sun.COM return (0); 14948348SEric.Yu@Sun.COM 14958348SEric.Yu@Sun.COM case FIONREAD: 14968348SEric.Yu@Sun.COM /* XXX: Cannot be used unless standard buffer is used */ 14978348SEric.Yu@Sun.COM /* 14988348SEric.Yu@Sun.COM * Return number of bytes of data in all data messages 14998348SEric.Yu@Sun.COM * in queue in "arg". 15008348SEric.Yu@Sun.COM * For stream socket, amount of available data. 15018348SEric.Yu@Sun.COM * For sock_dgram, # of available bytes + addresses. 15028348SEric.Yu@Sun.COM */ 15038348SEric.Yu@Sun.COM intval = (so->so_state & SS_ACCEPTCONN) ? 0 : 15048348SEric.Yu@Sun.COM MIN(so->so_rcv_queued, INT_MAX); 15058348SEric.Yu@Sun.COM if (so_copyout(&intval, (void *)arg, sizeof (intval), 15068348SEric.Yu@Sun.COM (mode & (int)FKIOCTL))) 15078348SEric.Yu@Sun.COM return (EFAULT); 15088348SEric.Yu@Sun.COM return (0); 15098348SEric.Yu@Sun.COM case SIOCATMARK: 15108348SEric.Yu@Sun.COM /* 15118348SEric.Yu@Sun.COM * No support for urgent data. 15128348SEric.Yu@Sun.COM */ 15138348SEric.Yu@Sun.COM intval = 0; 15148348SEric.Yu@Sun.COM 15158348SEric.Yu@Sun.COM if (so_copyout(&intval, (void *)arg, sizeof (int), 15168348SEric.Yu@Sun.COM (mode & (int)FKIOCTL))) 15178348SEric.Yu@Sun.COM return (EFAULT); 15188348SEric.Yu@Sun.COM return (0); 15198778SErik.Nordmark@Sun.COM case _I_GETPEERCRED: { 15208778SErik.Nordmark@Sun.COM int error = 0; 15218778SErik.Nordmark@Sun.COM 15228778SErik.Nordmark@Sun.COM if ((mode & FKIOCTL) == 0) 15238778SErik.Nordmark@Sun.COM return (EINVAL); 15248778SErik.Nordmark@Sun.COM 15258778SErik.Nordmark@Sun.COM mutex_enter(&so->so_lock); 15268778SErik.Nordmark@Sun.COM if ((so->so_mode & SM_CONNREQUIRED) == 0) { 15278778SErik.Nordmark@Sun.COM error = ENOTSUP; 15288778SErik.Nordmark@Sun.COM } else if ((so->so_state & SS_ISCONNECTED) == 0) { 15298778SErik.Nordmark@Sun.COM error = ENOTCONN; 15308778SErik.Nordmark@Sun.COM } else if (so->so_peercred != NULL) { 15318778SErik.Nordmark@Sun.COM k_peercred_t *kp = (k_peercred_t *)arg; 15328778SErik.Nordmark@Sun.COM kp->pc_cr = so->so_peercred; 15338778SErik.Nordmark@Sun.COM kp->pc_cpid = so->so_cpid; 15348778SErik.Nordmark@Sun.COM crhold(so->so_peercred); 15358778SErik.Nordmark@Sun.COM } else { 15368778SErik.Nordmark@Sun.COM error = EINVAL; 15378778SErik.Nordmark@Sun.COM } 15388778SErik.Nordmark@Sun.COM mutex_exit(&so->so_lock); 15398778SErik.Nordmark@Sun.COM return (error); 15408778SErik.Nordmark@Sun.COM } 15418348SEric.Yu@Sun.COM case SIOCSCTPGOPT: 15428348SEric.Yu@Sun.COM STRUCT_INIT(opt, mode); 15438348SEric.Yu@Sun.COM 15448348SEric.Yu@Sun.COM if (so_copyin((void *)arg, STRUCT_BUF(opt), STRUCT_SIZE(opt), 15458348SEric.Yu@Sun.COM (mode & (int)FKIOCTL))) { 15468348SEric.Yu@Sun.COM return (EFAULT); 15478348SEric.Yu@Sun.COM } 15488348SEric.Yu@Sun.COM if ((optlen = STRUCT_FGET(opt, sopt_len)) > SO_MAXARGSIZE) 15498348SEric.Yu@Sun.COM return (EINVAL); 15508348SEric.Yu@Sun.COM 15518348SEric.Yu@Sun.COM /* 15528348SEric.Yu@Sun.COM * Find the correct sctp_t based on whether it is 1-N socket 15538348SEric.Yu@Sun.COM * or not. 15548348SEric.Yu@Sun.COM */ 15558348SEric.Yu@Sun.COM intval = STRUCT_FGET(opt, sopt_aid); 15568348SEric.Yu@Sun.COM mutex_enter(&so->so_lock); 15578348SEric.Yu@Sun.COM if ((so->so_type == SOCK_SEQPACKET) && intval) { 15588348SEric.Yu@Sun.COM if ((error = sosctp_assoc(ss, intval, &ssa)) != 0) { 15598348SEric.Yu@Sun.COM mutex_exit(&so->so_lock); 15608348SEric.Yu@Sun.COM return (error); 15618348SEric.Yu@Sun.COM } 15628348SEric.Yu@Sun.COM conn = ssa->ssa_conn; 15638348SEric.Yu@Sun.COM ASSERT(conn != NULL); 15648348SEric.Yu@Sun.COM } else { 15658348SEric.Yu@Sun.COM conn = so->so_proto_handle; 15668348SEric.Yu@Sun.COM ssa = NULL; 15678348SEric.Yu@Sun.COM } 15688348SEric.Yu@Sun.COM mutex_exit(&so->so_lock); 15698348SEric.Yu@Sun.COM 15708348SEric.Yu@Sun.COM /* Copyin the option buffer and then call sctp_get_opt(). */ 15718348SEric.Yu@Sun.COM buflen = optlen; 15728348SEric.Yu@Sun.COM /* Let's allocate a buffer enough to hold an int */ 15738348SEric.Yu@Sun.COM if (buflen < sizeof (uint32_t)) 15748348SEric.Yu@Sun.COM buflen = sizeof (uint32_t); 15758348SEric.Yu@Sun.COM buf = kmem_alloc(buflen, KM_SLEEP); 15768348SEric.Yu@Sun.COM if (so_copyin(STRUCT_FGETP(opt, sopt_val), buf, optlen, 15778348SEric.Yu@Sun.COM (mode & (int)FKIOCTL))) { 15788348SEric.Yu@Sun.COM if (ssa != NULL) { 15798348SEric.Yu@Sun.COM mutex_enter(&so->so_lock); 15808348SEric.Yu@Sun.COM SSA_REFRELE(ss, ssa); 15818348SEric.Yu@Sun.COM mutex_exit(&so->so_lock); 15828348SEric.Yu@Sun.COM } 15838348SEric.Yu@Sun.COM kmem_free(buf, buflen); 15848348SEric.Yu@Sun.COM return (EFAULT); 15858348SEric.Yu@Sun.COM } 15868348SEric.Yu@Sun.COM /* The option level has to be IPPROTO_SCTP */ 15878348SEric.Yu@Sun.COM error = sctp_get_opt((struct sctp_s *)conn, IPPROTO_SCTP, 15888348SEric.Yu@Sun.COM STRUCT_FGET(opt, sopt_name), buf, &optlen); 15898348SEric.Yu@Sun.COM if (ssa != NULL) { 15908348SEric.Yu@Sun.COM mutex_enter(&so->so_lock); 15918348SEric.Yu@Sun.COM SSA_REFRELE(ss, ssa); 15928348SEric.Yu@Sun.COM mutex_exit(&so->so_lock); 15938348SEric.Yu@Sun.COM } 15948348SEric.Yu@Sun.COM optlen = MIN(buflen, optlen); 15958348SEric.Yu@Sun.COM /* No error, copyout the result with the correct buf len. */ 15968348SEric.Yu@Sun.COM if (error == 0) { 15978348SEric.Yu@Sun.COM STRUCT_FSET(opt, sopt_len, optlen); 15988348SEric.Yu@Sun.COM if (so_copyout(STRUCT_BUF(opt), (void *)arg, 15998348SEric.Yu@Sun.COM STRUCT_SIZE(opt), (mode & (int)FKIOCTL))) { 16008348SEric.Yu@Sun.COM error = EFAULT; 16018348SEric.Yu@Sun.COM } else if (so_copyout(buf, STRUCT_FGETP(opt, sopt_val), 16028348SEric.Yu@Sun.COM optlen, (mode & (int)FKIOCTL))) { 16038348SEric.Yu@Sun.COM error = EFAULT; 16048348SEric.Yu@Sun.COM } 16058348SEric.Yu@Sun.COM } 16068348SEric.Yu@Sun.COM kmem_free(buf, buflen); 16078348SEric.Yu@Sun.COM return (error); 16088348SEric.Yu@Sun.COM 16098348SEric.Yu@Sun.COM case SIOCSCTPSOPT: 16108348SEric.Yu@Sun.COM STRUCT_INIT(opt, mode); 16118348SEric.Yu@Sun.COM 16128348SEric.Yu@Sun.COM if (so_copyin((void *)arg, STRUCT_BUF(opt), STRUCT_SIZE(opt), 16138348SEric.Yu@Sun.COM (mode & (int)FKIOCTL))) { 16148348SEric.Yu@Sun.COM return (EFAULT); 16158348SEric.Yu@Sun.COM } 16168348SEric.Yu@Sun.COM if ((optlen = STRUCT_FGET(opt, sopt_len)) > SO_MAXARGSIZE) 16178348SEric.Yu@Sun.COM return (EINVAL); 16188348SEric.Yu@Sun.COM 16198348SEric.Yu@Sun.COM /* 16208348SEric.Yu@Sun.COM * Find the correct sctp_t based on whether it is 1-N socket 16218348SEric.Yu@Sun.COM * or not. 16228348SEric.Yu@Sun.COM */ 16238348SEric.Yu@Sun.COM intval = STRUCT_FGET(opt, sopt_aid); 16248348SEric.Yu@Sun.COM mutex_enter(&so->so_lock); 16258348SEric.Yu@Sun.COM if (intval != 0) { 16268348SEric.Yu@Sun.COM if ((error = sosctp_assoc(ss, intval, &ssa)) != 0) { 16278348SEric.Yu@Sun.COM mutex_exit(&so->so_lock); 16288348SEric.Yu@Sun.COM return (error); 16298348SEric.Yu@Sun.COM } 16308348SEric.Yu@Sun.COM conn = ssa->ssa_conn; 16318348SEric.Yu@Sun.COM ASSERT(conn != NULL); 16328348SEric.Yu@Sun.COM } else { 16338348SEric.Yu@Sun.COM conn = so->so_proto_handle; 16348348SEric.Yu@Sun.COM ssa = NULL; 16358348SEric.Yu@Sun.COM } 16368348SEric.Yu@Sun.COM mutex_exit(&so->so_lock); 16378348SEric.Yu@Sun.COM 16388348SEric.Yu@Sun.COM /* Copyin the option buffer and then call sctp_set_opt(). */ 16398348SEric.Yu@Sun.COM buf = kmem_alloc(optlen, KM_SLEEP); 16408348SEric.Yu@Sun.COM if (so_copyin(STRUCT_FGETP(opt, sopt_val), buf, optlen, 16418348SEric.Yu@Sun.COM (mode & (int)FKIOCTL))) { 16428348SEric.Yu@Sun.COM if (ssa != NULL) { 16438348SEric.Yu@Sun.COM mutex_enter(&so->so_lock); 16448348SEric.Yu@Sun.COM SSA_REFRELE(ss, ssa); 16458348SEric.Yu@Sun.COM mutex_exit(&so->so_lock); 16468348SEric.Yu@Sun.COM } 16478348SEric.Yu@Sun.COM kmem_free(buf, intval); 16488348SEric.Yu@Sun.COM return (EFAULT); 16498348SEric.Yu@Sun.COM } 16508348SEric.Yu@Sun.COM /* The option level has to be IPPROTO_SCTP */ 16518348SEric.Yu@Sun.COM error = sctp_set_opt((struct sctp_s *)conn, IPPROTO_SCTP, 16528348SEric.Yu@Sun.COM STRUCT_FGET(opt, sopt_name), buf, optlen); 16538348SEric.Yu@Sun.COM if (ssa) { 16548348SEric.Yu@Sun.COM mutex_enter(&so->so_lock); 16558348SEric.Yu@Sun.COM SSA_REFRELE(ss, ssa); 16568348SEric.Yu@Sun.COM mutex_exit(&so->so_lock); 16578348SEric.Yu@Sun.COM } 16588348SEric.Yu@Sun.COM kmem_free(buf, optlen); 16598348SEric.Yu@Sun.COM return (error); 16608348SEric.Yu@Sun.COM 16618348SEric.Yu@Sun.COM case SIOCSCTPPEELOFF: { 16628348SEric.Yu@Sun.COM struct sonode *nso; 16638348SEric.Yu@Sun.COM struct sctp_uc_swap us; 16648348SEric.Yu@Sun.COM int nfd; 16658348SEric.Yu@Sun.COM struct file *nfp; 16668348SEric.Yu@Sun.COM struct vnode *nvp = NULL; 16678348SEric.Yu@Sun.COM struct sockparams *sp; 16688348SEric.Yu@Sun.COM 16698348SEric.Yu@Sun.COM dprint(2, ("sctppeeloff %p\n", (void *)ss)); 16708348SEric.Yu@Sun.COM 16718348SEric.Yu@Sun.COM if (so->so_type != SOCK_SEQPACKET) { 16728348SEric.Yu@Sun.COM return (EOPNOTSUPP); 16738348SEric.Yu@Sun.COM } 16748348SEric.Yu@Sun.COM if (so_copyin((void *)arg, &intval, sizeof (intval), 16758348SEric.Yu@Sun.COM (mode & (int)FKIOCTL))) { 16768348SEric.Yu@Sun.COM return (EFAULT); 16778348SEric.Yu@Sun.COM } 16788348SEric.Yu@Sun.COM if (intval == 0) { 16798348SEric.Yu@Sun.COM return (EINVAL); 16808348SEric.Yu@Sun.COM } 16818348SEric.Yu@Sun.COM 16828348SEric.Yu@Sun.COM /* 16838348SEric.Yu@Sun.COM * Find sockparams. This is different from parent's entry, 16848348SEric.Yu@Sun.COM * as the socket type is different. 16858348SEric.Yu@Sun.COM */ 16868348SEric.Yu@Sun.COM error = solookup(so->so_family, SOCK_STREAM, so->so_protocol, 16878348SEric.Yu@Sun.COM &sp); 16889184SAnders.Persson@Sun.COM if (error != 0) 16899184SAnders.Persson@Sun.COM return (error); 16908348SEric.Yu@Sun.COM 16918348SEric.Yu@Sun.COM /* 16928348SEric.Yu@Sun.COM * Allocate the user fd. 16938348SEric.Yu@Sun.COM */ 16948348SEric.Yu@Sun.COM if ((nfd = ufalloc(0)) == -1) { 16958348SEric.Yu@Sun.COM eprintsoline(so, EMFILE); 169610834SAnders.Persson@Sun.COM SOCKPARAMS_DEC_REF(sp); 16978348SEric.Yu@Sun.COM return (EMFILE); 16988348SEric.Yu@Sun.COM } 16998348SEric.Yu@Sun.COM 17008348SEric.Yu@Sun.COM /* 17018348SEric.Yu@Sun.COM * Copy the fd out. 17028348SEric.Yu@Sun.COM */ 17038348SEric.Yu@Sun.COM if (so_copyout(&nfd, (void *)arg, sizeof (nfd), 17048348SEric.Yu@Sun.COM (mode & (int)FKIOCTL))) { 17058348SEric.Yu@Sun.COM error = EFAULT; 17068348SEric.Yu@Sun.COM goto err; 17078348SEric.Yu@Sun.COM } 17088348SEric.Yu@Sun.COM mutex_enter(&so->so_lock); 17098348SEric.Yu@Sun.COM 17108348SEric.Yu@Sun.COM /* 17118348SEric.Yu@Sun.COM * Don't use sosctp_assoc() in order to peel off disconnected 17128348SEric.Yu@Sun.COM * associations. 17138348SEric.Yu@Sun.COM */ 17148348SEric.Yu@Sun.COM ssa = ((uint32_t)intval >= ss->ss_maxassoc) ? NULL : 17158348SEric.Yu@Sun.COM ss->ss_assocs[intval].ssi_assoc; 17168348SEric.Yu@Sun.COM if (ssa == NULL) { 17178348SEric.Yu@Sun.COM mutex_exit(&so->so_lock); 17188348SEric.Yu@Sun.COM error = EINVAL; 17198348SEric.Yu@Sun.COM goto err; 17208348SEric.Yu@Sun.COM } 17218348SEric.Yu@Sun.COM SSA_REFHOLD(ssa); 17228348SEric.Yu@Sun.COM 17238348SEric.Yu@Sun.COM nso = socksctp_create(sp, so->so_family, SOCK_STREAM, 17248348SEric.Yu@Sun.COM so->so_protocol, so->so_version, SOCKET_NOSLEEP, 17258348SEric.Yu@Sun.COM &error, cr); 17268348SEric.Yu@Sun.COM if (nso == NULL) { 17278348SEric.Yu@Sun.COM SSA_REFRELE(ss, ssa); 17288348SEric.Yu@Sun.COM mutex_exit(&so->so_lock); 17298348SEric.Yu@Sun.COM goto err; 17308348SEric.Yu@Sun.COM } 17318348SEric.Yu@Sun.COM nvp = SOTOV(nso); 17328348SEric.Yu@Sun.COM so_lock_single(so); 17338348SEric.Yu@Sun.COM mutex_exit(&so->so_lock); 17349184SAnders.Persson@Sun.COM 17359184SAnders.Persson@Sun.COM /* cannot fail, only inheriting properties */ 17369184SAnders.Persson@Sun.COM (void) sosctp_init(nso, so, CRED(), 0); 17379184SAnders.Persson@Sun.COM 17389184SAnders.Persson@Sun.COM /* 17399184SAnders.Persson@Sun.COM * We have a single ref on the new socket. This is normally 17409184SAnders.Persson@Sun.COM * handled by socket_{create,newconn}, but since they are not 17419184SAnders.Persson@Sun.COM * used we have to do it here. 17429184SAnders.Persson@Sun.COM */ 17439184SAnders.Persson@Sun.COM nso->so_count = 1; 17449184SAnders.Persson@Sun.COM 17459184SAnders.Persson@Sun.COM us.sus_handle = nso; 17468348SEric.Yu@Sun.COM us.sus_upcalls = &sosctp_sock_upcalls; 17478348SEric.Yu@Sun.COM 17488348SEric.Yu@Sun.COM /* 17498348SEric.Yu@Sun.COM * Upcalls to new socket are blocked for the duration of 17508348SEric.Yu@Sun.COM * downcall. 17518348SEric.Yu@Sun.COM */ 17528348SEric.Yu@Sun.COM mutex_enter(&nso->so_lock); 17538348SEric.Yu@Sun.COM 17548348SEric.Yu@Sun.COM error = sctp_set_opt((struct sctp_s *)ssa->ssa_conn, 17558348SEric.Yu@Sun.COM IPPROTO_SCTP, SCTP_UC_SWAP, &us, sizeof (us)); 17568348SEric.Yu@Sun.COM if (error) { 17578348SEric.Yu@Sun.COM goto peelerr; 17588348SEric.Yu@Sun.COM } 17598348SEric.Yu@Sun.COM error = falloc(nvp, FWRITE|FREAD, &nfp, NULL); 17608348SEric.Yu@Sun.COM if (error) { 17618348SEric.Yu@Sun.COM goto peelerr; 17628348SEric.Yu@Sun.COM } 17638348SEric.Yu@Sun.COM 17648348SEric.Yu@Sun.COM /* 17658348SEric.Yu@Sun.COM * fill in the entries that falloc reserved 17668348SEric.Yu@Sun.COM */ 17678348SEric.Yu@Sun.COM nfp->f_vnode = nvp; 17688348SEric.Yu@Sun.COM mutex_exit(&nfp->f_tlock); 17698348SEric.Yu@Sun.COM setf(nfd, nfp); 17708348SEric.Yu@Sun.COM 17718348SEric.Yu@Sun.COM mutex_enter(&so->so_lock); 17728348SEric.Yu@Sun.COM 17738348SEric.Yu@Sun.COM sosctp_assoc_move(ss, SOTOSSO(nso), ssa); 17748348SEric.Yu@Sun.COM 17758348SEric.Yu@Sun.COM mutex_exit(&nso->so_lock); 17768348SEric.Yu@Sun.COM 17778348SEric.Yu@Sun.COM ssa->ssa_conn = NULL; 17788348SEric.Yu@Sun.COM sosctp_assoc_free(ss, ssa); 17798348SEric.Yu@Sun.COM 17808348SEric.Yu@Sun.COM so_unlock_single(so, SOLOCKED); 17818348SEric.Yu@Sun.COM mutex_exit(&so->so_lock); 17828348SEric.Yu@Sun.COM 17838348SEric.Yu@Sun.COM return (0); 17848348SEric.Yu@Sun.COM 17858348SEric.Yu@Sun.COM err: 178610834SAnders.Persson@Sun.COM SOCKPARAMS_DEC_REF(sp); 17878348SEric.Yu@Sun.COM setf(nfd, NULL); 17888348SEric.Yu@Sun.COM eprintsoline(so, error); 17898348SEric.Yu@Sun.COM return (error); 17908348SEric.Yu@Sun.COM 17918348SEric.Yu@Sun.COM peelerr: 17928348SEric.Yu@Sun.COM mutex_exit(&nso->so_lock); 17938348SEric.Yu@Sun.COM mutex_enter(&so->so_lock); 17948348SEric.Yu@Sun.COM ASSERT(nso->so_count == 1); 17958348SEric.Yu@Sun.COM nso->so_count = 0; 17968348SEric.Yu@Sun.COM so_unlock_single(so, SOLOCKED); 17978348SEric.Yu@Sun.COM SSA_REFRELE(ss, ssa); 17988348SEric.Yu@Sun.COM mutex_exit(&so->so_lock); 17998348SEric.Yu@Sun.COM 18008348SEric.Yu@Sun.COM setf(nfd, NULL); 18018348SEric.Yu@Sun.COM ASSERT(nvp->v_count == 1); 18028348SEric.Yu@Sun.COM socket_destroy(nso); 18038348SEric.Yu@Sun.COM eprintsoline(so, error); 18048348SEric.Yu@Sun.COM return (error); 18058348SEric.Yu@Sun.COM } 18068348SEric.Yu@Sun.COM default: 18078348SEric.Yu@Sun.COM return (EINVAL); 18088348SEric.Yu@Sun.COM } 18098348SEric.Yu@Sun.COM } 18108348SEric.Yu@Sun.COM 18118348SEric.Yu@Sun.COM /*ARGSUSED*/ 18128348SEric.Yu@Sun.COM static int 18138348SEric.Yu@Sun.COM sosctp_close(struct sonode *so, int flag, struct cred *cr) 18148348SEric.Yu@Sun.COM { 18158348SEric.Yu@Sun.COM struct sctp_sonode *ss; 18168348SEric.Yu@Sun.COM struct sctp_sa_id *ssi; 18178348SEric.Yu@Sun.COM struct sctp_soassoc *ssa; 18188348SEric.Yu@Sun.COM int32_t i; 18198348SEric.Yu@Sun.COM 18208348SEric.Yu@Sun.COM ss = SOTOSSO(so); 18218348SEric.Yu@Sun.COM 18228348SEric.Yu@Sun.COM /* 18238348SEric.Yu@Sun.COM * Initiate connection shutdown. Update SCTP's receive 18248348SEric.Yu@Sun.COM * window. 18258348SEric.Yu@Sun.COM */ 18268348SEric.Yu@Sun.COM sctp_recvd((struct sctp_s *)so->so_proto_handle, 18278348SEric.Yu@Sun.COM so->so_rcvbuf - so->so_rcv_queued); 18288348SEric.Yu@Sun.COM (void) sctp_disconnect((struct sctp_s *)so->so_proto_handle); 18298348SEric.Yu@Sun.COM 18308348SEric.Yu@Sun.COM /* 18318348SEric.Yu@Sun.COM * New associations can't come in, but old ones might get 18328348SEric.Yu@Sun.COM * closed in upcall. Protect against that by taking a reference 18338348SEric.Yu@Sun.COM * on the association. 18348348SEric.Yu@Sun.COM */ 18358348SEric.Yu@Sun.COM mutex_enter(&so->so_lock); 18368348SEric.Yu@Sun.COM ssi = ss->ss_assocs; 18378348SEric.Yu@Sun.COM for (i = 0; i < ss->ss_maxassoc; i++, ssi++) { 18388348SEric.Yu@Sun.COM if ((ssa = ssi->ssi_assoc) != NULL) { 18398348SEric.Yu@Sun.COM SSA_REFHOLD(ssa); 18408348SEric.Yu@Sun.COM sosctp_assoc_isdisconnected(ssa, 0); 18418348SEric.Yu@Sun.COM mutex_exit(&so->so_lock); 18428348SEric.Yu@Sun.COM 18438348SEric.Yu@Sun.COM sctp_recvd((struct sctp_s *)ssa->ssa_conn, 18448348SEric.Yu@Sun.COM so->so_rcvbuf - ssa->ssa_rcv_queued); 18458348SEric.Yu@Sun.COM (void) sctp_disconnect((struct sctp_s *)ssa->ssa_conn); 18468348SEric.Yu@Sun.COM 18478348SEric.Yu@Sun.COM mutex_enter(&so->so_lock); 18488348SEric.Yu@Sun.COM SSA_REFRELE(ss, ssa); 18498348SEric.Yu@Sun.COM } 18508348SEric.Yu@Sun.COM } 18518348SEric.Yu@Sun.COM mutex_exit(&so->so_lock); 18528348SEric.Yu@Sun.COM 18538348SEric.Yu@Sun.COM return (0); 18548348SEric.Yu@Sun.COM } 18558348SEric.Yu@Sun.COM 18568348SEric.Yu@Sun.COM /* 18578348SEric.Yu@Sun.COM * Closes incoming connections which were never accepted, frees 18588348SEric.Yu@Sun.COM * resources. 18598348SEric.Yu@Sun.COM */ 18608348SEric.Yu@Sun.COM /* ARGSUSED */ 18618348SEric.Yu@Sun.COM void 18628348SEric.Yu@Sun.COM sosctp_fini(struct sonode *so, struct cred *cr) 18638348SEric.Yu@Sun.COM { 18648348SEric.Yu@Sun.COM struct sctp_sonode *ss; 18658348SEric.Yu@Sun.COM struct sctp_sa_id *ssi; 18668348SEric.Yu@Sun.COM struct sctp_soassoc *ssa; 18678348SEric.Yu@Sun.COM int32_t i; 18688348SEric.Yu@Sun.COM 18698348SEric.Yu@Sun.COM ss = SOTOSSO(so); 18708348SEric.Yu@Sun.COM 18718348SEric.Yu@Sun.COM ASSERT(so->so_ops == &sosctp_sonodeops || 18728348SEric.Yu@Sun.COM so->so_ops == &sosctp_seq_sonodeops); 18738348SEric.Yu@Sun.COM 18748348SEric.Yu@Sun.COM /* We are the sole owner of so now */ 18758348SEric.Yu@Sun.COM mutex_enter(&so->so_lock); 18768348SEric.Yu@Sun.COM 18778348SEric.Yu@Sun.COM so_rcv_flush(so); 18788348SEric.Yu@Sun.COM 18798348SEric.Yu@Sun.COM /* Free all pending connections */ 188010836SAnders.Persson@Sun.COM so_acceptq_flush(so, B_TRUE); 18818348SEric.Yu@Sun.COM 18828348SEric.Yu@Sun.COM ssi = ss->ss_assocs; 18838348SEric.Yu@Sun.COM for (i = 0; i < ss->ss_maxassoc; i++, ssi++) { 18848348SEric.Yu@Sun.COM if ((ssa = ssi->ssi_assoc) != NULL) { 18858348SEric.Yu@Sun.COM SSA_REFHOLD(ssa); 18868348SEric.Yu@Sun.COM mutex_exit(&so->so_lock); 18878348SEric.Yu@Sun.COM 18888348SEric.Yu@Sun.COM sctp_close((struct sctp_s *)ssa->ssa_conn); 18898348SEric.Yu@Sun.COM 18908348SEric.Yu@Sun.COM mutex_enter(&so->so_lock); 18918348SEric.Yu@Sun.COM ssa->ssa_conn = NULL; 18928348SEric.Yu@Sun.COM sosctp_assoc_free(ss, ssa); 18938348SEric.Yu@Sun.COM } 18948348SEric.Yu@Sun.COM } 18958348SEric.Yu@Sun.COM if (ss->ss_assocs != NULL) { 18968348SEric.Yu@Sun.COM ASSERT(ss->ss_assoccnt == 0); 18978348SEric.Yu@Sun.COM kmem_free(ss->ss_assocs, 18988348SEric.Yu@Sun.COM ss->ss_maxassoc * sizeof (struct sctp_sa_id)); 18998348SEric.Yu@Sun.COM } 19008348SEric.Yu@Sun.COM mutex_exit(&so->so_lock); 19018348SEric.Yu@Sun.COM 19028348SEric.Yu@Sun.COM if (so->so_proto_handle) 19038348SEric.Yu@Sun.COM sctp_close((struct sctp_s *)so->so_proto_handle); 19048348SEric.Yu@Sun.COM so->so_proto_handle = NULL; 19058348SEric.Yu@Sun.COM 19068348SEric.Yu@Sun.COM sonode_fini(so); 19078348SEric.Yu@Sun.COM } 19088348SEric.Yu@Sun.COM 19098348SEric.Yu@Sun.COM /* 19108348SEric.Yu@Sun.COM * Upcalls from SCTP 19118348SEric.Yu@Sun.COM */ 19128348SEric.Yu@Sun.COM 19138348SEric.Yu@Sun.COM /* 19148348SEric.Yu@Sun.COM * This is the upcall function for 1-N (SOCK_SEQPACKET) socket when a new 19158348SEric.Yu@Sun.COM * association is created. Note that the first argument (handle) is of type 19168348SEric.Yu@Sun.COM * sctp_sonode *, which is the one changed to a listener for new 19178348SEric.Yu@Sun.COM * associations. All the other upcalls for 1-N socket take sctp_soassoc * 19188348SEric.Yu@Sun.COM * as handle. The only exception is the su_properties upcall, which 19198348SEric.Yu@Sun.COM * can take both types as handle. 19208348SEric.Yu@Sun.COM */ 19218348SEric.Yu@Sun.COM /* ARGSUSED */ 19228348SEric.Yu@Sun.COM sock_upper_handle_t 19238348SEric.Yu@Sun.COM sctp_assoc_newconn(sock_upper_handle_t parenthandle, 19248348SEric.Yu@Sun.COM sock_lower_handle_t connind, sock_downcalls_t *dc, 19258348SEric.Yu@Sun.COM struct cred *peer_cred, pid_t peer_cpid, sock_upcalls_t **ucp) 19268348SEric.Yu@Sun.COM { 19278348SEric.Yu@Sun.COM struct sonode *lso = (struct sonode *)parenthandle; 19288348SEric.Yu@Sun.COM struct sctp_sonode *lss = SOTOSSO(lso); 19298348SEric.Yu@Sun.COM struct sctp_soassoc *ssa; 19308348SEric.Yu@Sun.COM sctp_assoc_t id; 19318348SEric.Yu@Sun.COM 19328348SEric.Yu@Sun.COM ASSERT(lss->ss_type == SOSCTP_SOCKET); 19338348SEric.Yu@Sun.COM ASSERT(lso->so_state & SS_ACCEPTCONN); 19348348SEric.Yu@Sun.COM ASSERT(lso->so_proto_handle != NULL); /* closed conn */ 19358348SEric.Yu@Sun.COM ASSERT(lso->so_type == SOCK_SEQPACKET); 19368348SEric.Yu@Sun.COM 19378348SEric.Yu@Sun.COM mutex_enter(&lso->so_lock); 19388348SEric.Yu@Sun.COM 19398348SEric.Yu@Sun.COM if ((id = sosctp_aid_get(lss)) == -1) { 19408348SEric.Yu@Sun.COM /* 19418348SEric.Yu@Sun.COM * Array not large enough; increase size. 19428348SEric.Yu@Sun.COM */ 19438348SEric.Yu@Sun.COM if (sosctp_aid_grow(lss, lss->ss_maxassoc, KM_NOSLEEP) < 0) { 19448348SEric.Yu@Sun.COM mutex_exit(&lso->so_lock); 19458348SEric.Yu@Sun.COM return (NULL); 19468348SEric.Yu@Sun.COM } 19478348SEric.Yu@Sun.COM id = sosctp_aid_get(lss); 19488348SEric.Yu@Sun.COM ASSERT(id != -1); 19498348SEric.Yu@Sun.COM } 19508348SEric.Yu@Sun.COM 19518348SEric.Yu@Sun.COM /* 19528348SEric.Yu@Sun.COM * Create soassoc for this connection 19538348SEric.Yu@Sun.COM */ 19548348SEric.Yu@Sun.COM ssa = sosctp_assoc_create(lss, KM_NOSLEEP); 19558348SEric.Yu@Sun.COM if (ssa == NULL) { 19568348SEric.Yu@Sun.COM mutex_exit(&lso->so_lock); 19578348SEric.Yu@Sun.COM return (NULL); 19588348SEric.Yu@Sun.COM } 19598348SEric.Yu@Sun.COM sosctp_aid_reserve(lss, id, 1); 19608348SEric.Yu@Sun.COM lss->ss_assocs[id].ssi_assoc = ssa; 19618348SEric.Yu@Sun.COM ++lss->ss_assoccnt; 19628348SEric.Yu@Sun.COM ssa->ssa_id = id; 19638348SEric.Yu@Sun.COM ssa->ssa_conn = (struct sctp_s *)connind; 19648348SEric.Yu@Sun.COM ssa->ssa_state = (SS_ISBOUND | SS_ISCONNECTED); 19658348SEric.Yu@Sun.COM ssa->ssa_wroff = lss->ss_wroff; 19668348SEric.Yu@Sun.COM ssa->ssa_wrsize = lss->ss_wrsize; 19678348SEric.Yu@Sun.COM 19688348SEric.Yu@Sun.COM mutex_exit(&lso->so_lock); 19698348SEric.Yu@Sun.COM 19708348SEric.Yu@Sun.COM *ucp = &sosctp_assoc_upcalls; 19718348SEric.Yu@Sun.COM 19728348SEric.Yu@Sun.COM return ((sock_upper_handle_t)ssa); 19738348SEric.Yu@Sun.COM } 19748348SEric.Yu@Sun.COM 19758348SEric.Yu@Sun.COM /* ARGSUSED */ 19768348SEric.Yu@Sun.COM static void 19778348SEric.Yu@Sun.COM sctp_assoc_connected(sock_upper_handle_t handle, sock_connid_t id, 19788348SEric.Yu@Sun.COM struct cred *peer_cred, pid_t peer_cpid) 19798348SEric.Yu@Sun.COM { 19808348SEric.Yu@Sun.COM struct sctp_soassoc *ssa = (struct sctp_soassoc *)handle; 19818348SEric.Yu@Sun.COM struct sonode *so = &ssa->ssa_sonode->ss_so; 19828348SEric.Yu@Sun.COM 19838348SEric.Yu@Sun.COM ASSERT(so->so_type == SOCK_SEQPACKET); 19848348SEric.Yu@Sun.COM ASSERT(ssa->ssa_conn); 19858348SEric.Yu@Sun.COM 19868348SEric.Yu@Sun.COM mutex_enter(&so->so_lock); 19878348SEric.Yu@Sun.COM sosctp_assoc_isconnected(ssa); 19888348SEric.Yu@Sun.COM mutex_exit(&so->so_lock); 19898348SEric.Yu@Sun.COM } 19908348SEric.Yu@Sun.COM 19918348SEric.Yu@Sun.COM /* ARGSUSED */ 19928348SEric.Yu@Sun.COM static int 19938348SEric.Yu@Sun.COM sctp_assoc_disconnected(sock_upper_handle_t handle, sock_connid_t id, int error) 19948348SEric.Yu@Sun.COM { 19958348SEric.Yu@Sun.COM struct sctp_soassoc *ssa = (struct sctp_soassoc *)handle; 19968348SEric.Yu@Sun.COM struct sonode *so = &ssa->ssa_sonode->ss_so; 19978348SEric.Yu@Sun.COM int ret; 19988348SEric.Yu@Sun.COM 19998348SEric.Yu@Sun.COM ASSERT(so->so_type == SOCK_SEQPACKET); 20008348SEric.Yu@Sun.COM ASSERT(ssa->ssa_conn != NULL); 20018348SEric.Yu@Sun.COM 20028348SEric.Yu@Sun.COM mutex_enter(&so->so_lock); 20038348SEric.Yu@Sun.COM sosctp_assoc_isdisconnected(ssa, error); 20048348SEric.Yu@Sun.COM if (ssa->ssa_refcnt == 1) { 20058348SEric.Yu@Sun.COM ret = 1; 20068348SEric.Yu@Sun.COM ssa->ssa_conn = NULL; 20078348SEric.Yu@Sun.COM } else { 20088348SEric.Yu@Sun.COM ret = 0; 20098348SEric.Yu@Sun.COM } 20108348SEric.Yu@Sun.COM SSA_REFRELE(SOTOSSO(so), ssa); 20118348SEric.Yu@Sun.COM 20128348SEric.Yu@Sun.COM cv_broadcast(&so->so_snd_cv); 20138348SEric.Yu@Sun.COM 20148348SEric.Yu@Sun.COM mutex_exit(&so->so_lock); 20158348SEric.Yu@Sun.COM 20168348SEric.Yu@Sun.COM return (ret); 20178348SEric.Yu@Sun.COM } 20188348SEric.Yu@Sun.COM 20198348SEric.Yu@Sun.COM /* ARGSUSED */ 20208348SEric.Yu@Sun.COM static void 20218348SEric.Yu@Sun.COM sctp_assoc_disconnecting(sock_upper_handle_t handle, sock_opctl_action_t action, 20228348SEric.Yu@Sun.COM uintptr_t arg) 20238348SEric.Yu@Sun.COM { 20248348SEric.Yu@Sun.COM struct sctp_soassoc *ssa = (struct sctp_soassoc *)handle; 20258348SEric.Yu@Sun.COM struct sonode *so = &ssa->ssa_sonode->ss_so; 20268348SEric.Yu@Sun.COM 20278348SEric.Yu@Sun.COM ASSERT(so->so_type == SOCK_SEQPACKET); 20288348SEric.Yu@Sun.COM ASSERT(ssa->ssa_conn != NULL); 20298348SEric.Yu@Sun.COM ASSERT(action == SOCK_OPCTL_SHUT_SEND); 20308348SEric.Yu@Sun.COM 20318348SEric.Yu@Sun.COM mutex_enter(&so->so_lock); 20328348SEric.Yu@Sun.COM sosctp_assoc_isdisconnecting(ssa); 20338348SEric.Yu@Sun.COM mutex_exit(&so->so_lock); 20348348SEric.Yu@Sun.COM } 20358348SEric.Yu@Sun.COM 20368348SEric.Yu@Sun.COM /* ARGSUSED */ 20378348SEric.Yu@Sun.COM static ssize_t 20388348SEric.Yu@Sun.COM sctp_assoc_recv(sock_upper_handle_t handle, mblk_t *mp, size_t len, int flags, 20398348SEric.Yu@Sun.COM int *errorp, boolean_t *forcepush) 20408348SEric.Yu@Sun.COM { 20418348SEric.Yu@Sun.COM struct sctp_soassoc *ssa = (struct sctp_soassoc *)handle; 20428348SEric.Yu@Sun.COM struct sctp_sonode *ss = ssa->ssa_sonode; 20438348SEric.Yu@Sun.COM struct sonode *so = &ss->ss_so; 20448348SEric.Yu@Sun.COM struct T_unitdata_ind *tind; 20458348SEric.Yu@Sun.COM mblk_t *mp2; 20468348SEric.Yu@Sun.COM union sctp_notification *sn; 20478348SEric.Yu@Sun.COM struct sctp_sndrcvinfo *sinfo; 20488941SAnders.Persson@Sun.COM ssize_t space_available; 20498348SEric.Yu@Sun.COM 20508348SEric.Yu@Sun.COM ASSERT(ssa->ssa_type == SOSCTP_ASSOC); 20518348SEric.Yu@Sun.COM ASSERT(so->so_type == SOCK_SEQPACKET); 20528348SEric.Yu@Sun.COM ASSERT(ssa->ssa_conn != NULL); /* closed conn */ 20538348SEric.Yu@Sun.COM ASSERT(mp != NULL); 20548348SEric.Yu@Sun.COM 20558348SEric.Yu@Sun.COM ASSERT(errorp != NULL); 20568348SEric.Yu@Sun.COM *errorp = 0; 20578348SEric.Yu@Sun.COM 20588348SEric.Yu@Sun.COM /* 20598348SEric.Yu@Sun.COM * Should be getting T_unitdata_req's only. 20608348SEric.Yu@Sun.COM * Must have address as part of packet. 20618348SEric.Yu@Sun.COM */ 20628348SEric.Yu@Sun.COM tind = (struct T_unitdata_ind *)mp->b_rptr; 20638348SEric.Yu@Sun.COM ASSERT((DB_TYPE(mp) == M_PROTO) && 20648348SEric.Yu@Sun.COM (tind->PRIM_type == T_UNITDATA_IND)); 20658348SEric.Yu@Sun.COM ASSERT(tind->SRC_length); 20668348SEric.Yu@Sun.COM 20678348SEric.Yu@Sun.COM mutex_enter(&so->so_lock); 20688348SEric.Yu@Sun.COM 20698348SEric.Yu@Sun.COM /* 20708348SEric.Yu@Sun.COM * For notify messages, need to fill in association id. 20718348SEric.Yu@Sun.COM * For data messages, sndrcvinfo could be in ancillary data. 20728348SEric.Yu@Sun.COM */ 207310686SRao.Shoaib@Sun.COM if (mp->b_flag & SCTP_NOTIFICATION) { 20748348SEric.Yu@Sun.COM mp2 = mp->b_cont; 20758348SEric.Yu@Sun.COM sn = (union sctp_notification *)mp2->b_rptr; 20768348SEric.Yu@Sun.COM switch (sn->sn_header.sn_type) { 20778348SEric.Yu@Sun.COM case SCTP_ASSOC_CHANGE: 20788348SEric.Yu@Sun.COM sn->sn_assoc_change.sac_assoc_id = ssa->ssa_id; 20798348SEric.Yu@Sun.COM break; 20808348SEric.Yu@Sun.COM case SCTP_PEER_ADDR_CHANGE: 20818348SEric.Yu@Sun.COM sn->sn_paddr_change.spc_assoc_id = ssa->ssa_id; 20828348SEric.Yu@Sun.COM break; 20838348SEric.Yu@Sun.COM case SCTP_REMOTE_ERROR: 20848348SEric.Yu@Sun.COM sn->sn_remote_error.sre_assoc_id = ssa->ssa_id; 20858348SEric.Yu@Sun.COM break; 20868348SEric.Yu@Sun.COM case SCTP_SEND_FAILED: 20878348SEric.Yu@Sun.COM sn->sn_send_failed.ssf_assoc_id = ssa->ssa_id; 20888348SEric.Yu@Sun.COM break; 20898348SEric.Yu@Sun.COM case SCTP_SHUTDOWN_EVENT: 20908348SEric.Yu@Sun.COM sn->sn_shutdown_event.sse_assoc_id = ssa->ssa_id; 20918348SEric.Yu@Sun.COM break; 20928348SEric.Yu@Sun.COM case SCTP_ADAPTATION_INDICATION: 20938348SEric.Yu@Sun.COM sn->sn_adaptation_event.sai_assoc_id = ssa->ssa_id; 20948348SEric.Yu@Sun.COM break; 20958348SEric.Yu@Sun.COM case SCTP_PARTIAL_DELIVERY_EVENT: 20968348SEric.Yu@Sun.COM sn->sn_pdapi_event.pdapi_assoc_id = ssa->ssa_id; 20978348SEric.Yu@Sun.COM break; 20988348SEric.Yu@Sun.COM default: 20998348SEric.Yu@Sun.COM ASSERT(0); 21008348SEric.Yu@Sun.COM break; 21018348SEric.Yu@Sun.COM } 21028348SEric.Yu@Sun.COM } else { 21038348SEric.Yu@Sun.COM if (tind->OPT_length > 0) { 21048348SEric.Yu@Sun.COM struct cmsghdr *cmsg; 21058348SEric.Yu@Sun.COM char *cend; 21068348SEric.Yu@Sun.COM 21078348SEric.Yu@Sun.COM cmsg = (struct cmsghdr *) 21088348SEric.Yu@Sun.COM ((uchar_t *)mp->b_rptr + tind->OPT_offset); 21098348SEric.Yu@Sun.COM cend = (char *)cmsg + tind->OPT_length; 21108348SEric.Yu@Sun.COM for (;;) { 21118348SEric.Yu@Sun.COM if ((char *)(cmsg + 1) > cend || 21128348SEric.Yu@Sun.COM ((char *)cmsg + cmsg->cmsg_len) > cend) { 21138348SEric.Yu@Sun.COM break; 21148348SEric.Yu@Sun.COM } 21158348SEric.Yu@Sun.COM if ((cmsg->cmsg_level == IPPROTO_SCTP) && 21168348SEric.Yu@Sun.COM (cmsg->cmsg_type == SCTP_SNDRCV)) { 21178348SEric.Yu@Sun.COM sinfo = (struct sctp_sndrcvinfo *) 21188348SEric.Yu@Sun.COM (cmsg + 1); 21198348SEric.Yu@Sun.COM sinfo->sinfo_assoc_id = ssa->ssa_id; 21208348SEric.Yu@Sun.COM break; 21218348SEric.Yu@Sun.COM } 21228348SEric.Yu@Sun.COM if (cmsg->cmsg_len > 0) { 21238348SEric.Yu@Sun.COM cmsg = (struct cmsghdr *) 21248348SEric.Yu@Sun.COM ((uchar_t *)cmsg + cmsg->cmsg_len); 21258348SEric.Yu@Sun.COM } else { 21268348SEric.Yu@Sun.COM break; 21278348SEric.Yu@Sun.COM } 21288348SEric.Yu@Sun.COM } 21298348SEric.Yu@Sun.COM } 21308348SEric.Yu@Sun.COM } 21318348SEric.Yu@Sun.COM 21328348SEric.Yu@Sun.COM /* 21338348SEric.Yu@Sun.COM * SCTP has reserved space in the header for storing a pointer. 21348348SEric.Yu@Sun.COM * Put the pointer to assocation there, and queue the data. 21358348SEric.Yu@Sun.COM */ 21368348SEric.Yu@Sun.COM SSA_REFHOLD(ssa); 21378348SEric.Yu@Sun.COM ASSERT((mp->b_rptr - DB_BASE(mp)) >= sizeof (ssa)); 21388348SEric.Yu@Sun.COM *(struct sctp_soassoc **)DB_BASE(mp) = ssa; 21398348SEric.Yu@Sun.COM 21408941SAnders.Persson@Sun.COM ssa->ssa_rcv_queued += len; 21418941SAnders.Persson@Sun.COM space_available = so->so_rcvbuf - ssa->ssa_rcv_queued; 21428941SAnders.Persson@Sun.COM so_enqueue_msg(so, mp, len); 21438348SEric.Yu@Sun.COM 21448941SAnders.Persson@Sun.COM /* so_notify_data drops so_lock */ 21458941SAnders.Persson@Sun.COM so_notify_data(so, len); 21468941SAnders.Persson@Sun.COM 21478941SAnders.Persson@Sun.COM return (space_available); 21488348SEric.Yu@Sun.COM } 21498348SEric.Yu@Sun.COM 21508348SEric.Yu@Sun.COM static void 21518348SEric.Yu@Sun.COM sctp_assoc_xmitted(sock_upper_handle_t handle, boolean_t qfull) 21528348SEric.Yu@Sun.COM { 21538348SEric.Yu@Sun.COM struct sctp_soassoc *ssa = (struct sctp_soassoc *)handle; 21548348SEric.Yu@Sun.COM struct sctp_sonode *ss = ssa->ssa_sonode; 21558348SEric.Yu@Sun.COM 21568348SEric.Yu@Sun.COM ASSERT(ssa->ssa_type == SOSCTP_ASSOC); 21578348SEric.Yu@Sun.COM ASSERT(ss->ss_so.so_type == SOCK_SEQPACKET); 21588348SEric.Yu@Sun.COM ASSERT(ssa->ssa_conn != NULL); 21598348SEric.Yu@Sun.COM 21608348SEric.Yu@Sun.COM mutex_enter(&ss->ss_so.so_lock); 21618348SEric.Yu@Sun.COM 21628348SEric.Yu@Sun.COM ssa->ssa_snd_qfull = qfull; 21638348SEric.Yu@Sun.COM 21648348SEric.Yu@Sun.COM /* 21658348SEric.Yu@Sun.COM * Wake blocked writers. 21668348SEric.Yu@Sun.COM */ 21678348SEric.Yu@Sun.COM cv_broadcast(&ss->ss_so.so_snd_cv); 21688348SEric.Yu@Sun.COM 21698348SEric.Yu@Sun.COM mutex_exit(&ss->ss_so.so_lock); 21708348SEric.Yu@Sun.COM } 21718348SEric.Yu@Sun.COM 21728348SEric.Yu@Sun.COM static void 21738348SEric.Yu@Sun.COM sctp_assoc_properties(sock_upper_handle_t handle, 21748348SEric.Yu@Sun.COM struct sock_proto_props *soppp) 21758348SEric.Yu@Sun.COM { 21768348SEric.Yu@Sun.COM struct sctp_soassoc *ssa = (struct sctp_soassoc *)handle; 21778348SEric.Yu@Sun.COM struct sctp_sonode *ss; 21788348SEric.Yu@Sun.COM 21798348SEric.Yu@Sun.COM if (ssa->ssa_type == SOSCTP_ASSOC) { 21808348SEric.Yu@Sun.COM ss = ssa->ssa_sonode; 21818348SEric.Yu@Sun.COM mutex_enter(&ss->ss_so.so_lock); 21828348SEric.Yu@Sun.COM 21838348SEric.Yu@Sun.COM /* 21848348SEric.Yu@Sun.COM * Only change them if they're set. 21858348SEric.Yu@Sun.COM */ 21868348SEric.Yu@Sun.COM if (soppp->sopp_wroff != 0) { 21878348SEric.Yu@Sun.COM ssa->ssa_wroff = soppp->sopp_wroff; 21888348SEric.Yu@Sun.COM } 21898348SEric.Yu@Sun.COM if (soppp->sopp_maxblk != 0) { 21908348SEric.Yu@Sun.COM ssa->ssa_wrsize = soppp->sopp_maxblk; 21918348SEric.Yu@Sun.COM } 21928348SEric.Yu@Sun.COM } else { 21938348SEric.Yu@Sun.COM ss = (struct sctp_sonode *)handle; 21948348SEric.Yu@Sun.COM mutex_enter(&ss->ss_so.so_lock); 21958348SEric.Yu@Sun.COM 21968348SEric.Yu@Sun.COM if (soppp->sopp_wroff != 0) { 21978348SEric.Yu@Sun.COM ss->ss_wroff = soppp->sopp_wroff; 21988348SEric.Yu@Sun.COM } 21998348SEric.Yu@Sun.COM if (soppp->sopp_maxblk != 0) { 22008348SEric.Yu@Sun.COM ss->ss_wrsize = soppp->sopp_maxblk; 22018348SEric.Yu@Sun.COM } 22028348SEric.Yu@Sun.COM } 22038348SEric.Yu@Sun.COM 22048348SEric.Yu@Sun.COM mutex_exit(&ss->ss_so.so_lock); 22058348SEric.Yu@Sun.COM } 2206