1163953Srrs/*- 2169382Srrs * Copyright (c) 2001-2007, by Cisco Systems, Inc. All rights reserved. 3235828Stuexen * Copyright (c) 2008-2012, by Randall Stewart. All rights reserved. 4235828Stuexen * Copyright (c) 2008-2012, by Michael Tuexen. All rights reserved. 5163953Srrs * 6163953Srrs * Redistribution and use in source and binary forms, with or without 7163953Srrs * modification, are permitted provided that the following conditions are met: 8163953Srrs * 9163953Srrs * a) Redistributions of source code must retain the above copyright notice, 10228653Stuexen * this list of conditions and the following disclaimer. 11163953Srrs * 12163953Srrs * b) Redistributions in binary form must reproduce the above copyright 13163953Srrs * notice, this list of conditions and the following disclaimer in 14228653Stuexen * the documentation and/or other materials provided with the distribution. 15163953Srrs * 16163953Srrs * c) Neither the name of Cisco Systems, Inc. nor the names of its 17163953Srrs * contributors may be used to endorse or promote products derived 18163953Srrs * from this software without specific prior written permission. 19163953Srrs * 20163953Srrs * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS 21163953Srrs * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, 22163953Srrs * THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE 23163953Srrs * ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE 24163953Srrs * LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR 25163953Srrs * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF 26163953Srrs * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS 27163953Srrs * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN 28163953Srrs * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) 29163953Srrs * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF 30163953Srrs * THE POSSIBILITY OF SUCH DAMAGE. 31163953Srrs */ 32163953Srrs 33163953Srrs#include <sys/cdefs.h> 34163953Srrs__FBSDID("$FreeBSD$"); 35235828Stuexen 36163953Srrs#include <netinet/sctp_os.h> 37163953Srrs#include <netinet/sctp_pcb.h> 38170744Srrs#include <netinet/sctputil.h> 39170744Srrs#include <netinet/sctp_var.h> 40170744Srrs#include <netinet/sctp_var.h> 41170744Srrs#include <netinet/sctp_sysctl.h> 42163953Srrs#include <netinet/sctp.h> 43163953Srrs#include <netinet/sctp_uio.h> 44163953Srrs#include <netinet/sctp_peeloff.h> 45163953Srrs#include <netinet/sctputil.h> 46163953Srrs#include <netinet/sctp_auth.h> 47163953Srrs 48163953Srrs 49163953Srrsint 50163953Srrssctp_can_peel_off(struct socket *head, sctp_assoc_t assoc_id) 51163953Srrs{ 52163953Srrs struct sctp_inpcb *inp; 53163953Srrs struct sctp_tcb *stcb; 54171477Srrs uint32_t state; 55163953Srrs 56232723Stuexen if (head == NULL) { 57232726Stuexen SCTP_LTRACE_ERR_RET(NULL, NULL, NULL, SCTP_FROM_SCTP_PEELOFF, EBADF); 58232723Stuexen return (EBADF); 59232723Stuexen } 60163953Srrs inp = (struct sctp_inpcb *)head->so_pcb; 61163953Srrs if (inp == NULL) { 62232726Stuexen SCTP_LTRACE_ERR_RET(NULL, NULL, NULL, SCTP_FROM_SCTP_PEELOFF, EFAULT); 63163953Srrs return (EFAULT); 64163953Srrs } 65233004Stuexen if ((inp->sctp_flags & SCTP_PCB_FLAGS_TCPTYPE) || 66233004Stuexen (inp->sctp_flags & SCTP_PCB_FLAGS_IN_TCPPOOL)) { 67233004Stuexen SCTP_LTRACE_ERR_RET(inp, NULL, NULL, SCTP_FROM_SCTP_PEELOFF, EOPNOTSUPP); 68233004Stuexen return (EOPNOTSUPP); 69233004Stuexen } 70163953Srrs stcb = sctp_findassociation_ep_asocid(inp, assoc_id, 1); 71163953Srrs if (stcb == NULL) { 72172090Srrs SCTP_LTRACE_ERR_RET(inp, stcb, NULL, SCTP_FROM_SCTP_PEELOFF, ENOENT); 73172090Srrs return (ENOENT); 74163953Srrs } 75171477Srrs state = SCTP_GET_STATE((&stcb->asoc)); 76171477Srrs if ((state == SCTP_STATE_EMPTY) || 77243565Stuexen (state == SCTP_STATE_INUSE)) { 78171477Srrs SCTP_TCB_UNLOCK(stcb); 79171943Srrs SCTP_LTRACE_ERR_RET(inp, stcb, NULL, SCTP_FROM_SCTP_PEELOFF, ENOTCONN); 80171477Srrs return (ENOTCONN); 81171477Srrs } 82163953Srrs SCTP_TCB_UNLOCK(stcb); 83163953Srrs /* We are clear to peel this one off */ 84163953Srrs return (0); 85163953Srrs} 86163953Srrs 87163953Srrsint 88163953Srrssctp_do_peeloff(struct socket *head, struct socket *so, sctp_assoc_t assoc_id) 89163953Srrs{ 90163953Srrs struct sctp_inpcb *inp, *n_inp; 91163953Srrs struct sctp_tcb *stcb; 92171477Srrs uint32_t state; 93163953Srrs 94163953Srrs inp = (struct sctp_inpcb *)head->so_pcb; 95171943Srrs if (inp == NULL) { 96171943Srrs SCTP_LTRACE_ERR_RET(inp, NULL, NULL, SCTP_FROM_SCTP_PEELOFF, EFAULT); 97163953Srrs return (EFAULT); 98171943Srrs } 99163953Srrs stcb = sctp_findassociation_ep_asocid(inp, assoc_id, 1); 100171943Srrs if (stcb == NULL) { 101171943Srrs SCTP_LTRACE_ERR_RET(inp, NULL, NULL, SCTP_FROM_SCTP_PEELOFF, ENOTCONN); 102163953Srrs return (ENOTCONN); 103171943Srrs } 104171477Srrs state = SCTP_GET_STATE((&stcb->asoc)); 105171477Srrs if ((state == SCTP_STATE_EMPTY) || 106243565Stuexen (state == SCTP_STATE_INUSE)) { 107171477Srrs SCTP_TCB_UNLOCK(stcb); 108171943Srrs SCTP_LTRACE_ERR_RET(inp, NULL, NULL, SCTP_FROM_SCTP_PEELOFF, ENOTCONN); 109171477Srrs return (ENOTCONN); 110171477Srrs } 111163953Srrs n_inp = (struct sctp_inpcb *)so->so_pcb; 112163953Srrs n_inp->sctp_flags = (SCTP_PCB_FLAGS_UDPTYPE | 113163953Srrs SCTP_PCB_FLAGS_CONNECTED | 114163953Srrs SCTP_PCB_FLAGS_IN_TCPPOOL | /* Turn on Blocking IO */ 115163953Srrs (SCTP_PCB_COPY_FLAGS & inp->sctp_flags)); 116163953Srrs n_inp->sctp_socket = so; 117163953Srrs n_inp->sctp_features = inp->sctp_features; 118171990Srrs n_inp->sctp_mobility_features = inp->sctp_mobility_features; 119163953Srrs n_inp->sctp_frag_point = inp->sctp_frag_point; 120211944Stuexen n_inp->sctp_cmt_on_off = inp->sctp_cmt_on_off; 121270356Stuexen n_inp->ecn_supported = inp->ecn_supported; 122270357Stuexen n_inp->prsctp_supported = inp->prsctp_supported; 123270362Stuexen n_inp->auth_supported = inp->auth_supported; 124270362Stuexen n_inp->asconf_supported = inp->asconf_supported; 125270361Stuexen n_inp->reconfig_supported = inp->reconfig_supported; 126270359Stuexen n_inp->nrsack_supported = inp->nrsack_supported; 127270360Stuexen n_inp->pktdrop_supported = inp->pktdrop_supported; 128163953Srrs n_inp->partial_delivery_point = inp->partial_delivery_point; 129163953Srrs n_inp->sctp_context = inp->sctp_context; 130283724Stuexen n_inp->max_cwnd = inp->max_cwnd; 131233660Srrs n_inp->local_strreset_support = inp->local_strreset_support; 132163953Srrs n_inp->inp_starting_point_for_iterator = NULL; 133171990Srrs /* copy in the authentication parameters from the original endpoint */ 134171990Srrs if (n_inp->sctp_ep.local_hmacs) 135171990Srrs sctp_free_hmaclist(n_inp->sctp_ep.local_hmacs); 136171990Srrs n_inp->sctp_ep.local_hmacs = 137171990Srrs sctp_copy_hmaclist(inp->sctp_ep.local_hmacs); 138171990Srrs if (n_inp->sctp_ep.local_auth_chunks) 139171990Srrs sctp_free_chunklist(n_inp->sctp_ep.local_auth_chunks); 140171990Srrs n_inp->sctp_ep.local_auth_chunks = 141171990Srrs sctp_copy_chunklist(inp->sctp_ep.local_auth_chunks); 142171990Srrs (void)sctp_copy_skeylist(&inp->sctp_ep.shared_keys, 143171990Srrs &n_inp->sctp_ep.shared_keys); 144163953Srrs /* 145163953Srrs * Now we must move it from one hash table to another and get the 146163953Srrs * stcb in the right place. 147163953Srrs */ 148163953Srrs sctp_move_pcb_and_assoc(inp, n_inp, stcb); 149170056Srrs atomic_add_int(&stcb->asoc.refcnt, 1); 150170056Srrs SCTP_TCB_UNLOCK(stcb); 151163953Srrs 152175845Srwatson sctp_pull_off_control_to_new_inp(inp, n_inp, stcb, SBL_WAIT); 153170056Srrs atomic_subtract_int(&stcb->asoc.refcnt, 1); 154163953Srrs 155163953Srrs return (0); 156163953Srrs} 157