1/* $KAME: sctp_peeloff.c,v 1.13 2005/03/06 16:04:18 itojun Exp $ */ 2/* $NetBSD: sctp_peeloff.c,v 1.2 2016/04/25 21:21:02 rjs Exp $ */ 3 4/* 5 * Copyright (C) 2002, 2003 Cisco Systems Inc, 6 * All rights reserved. 7 * 8 * Redistribution and use in source and binary forms, with or without 9 * modification, are permitted provided that the following conditions 10 * are met: 11 * 1. Redistributions of source code must retain the above copyright 12 * notice, this list of conditions and the following disclaimer. 13 * 2. Redistributions in binary form must reproduce the above copyright 14 * notice, this list of conditions and the following disclaimer in the 15 * documentation and/or other materials provided with the distribution. 16 * 3. Neither the name of the project nor the names of its contributors 17 * may be used to endorse or promote products derived from this software 18 * without specific prior written permission. 19 * 20 * THIS SOFTWARE IS PROVIDED BY THE PROJECT AND CONTRIBUTORS ``AS IS'' AND 21 * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE 22 * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE 23 * ARE DISCLAIMED. IN NO EVENT SHALL THE PROJECT OR CONTRIBUTORS BE LIABLE 24 * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL 25 * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS 26 * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) 27 * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT 28 * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY 29 * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF 30 * SUCH DAMAGE. 31 */ 32#include <sys/cdefs.h> 33__KERNEL_RCSID(0, "$NetBSD: sctp_peeloff.c,v 1.2 2016/04/25 21:21:02 rjs Exp $"); 34 35#ifdef _KERNEL_OPT 36#include "opt_inet.h" 37#include "opt_ipsec.h" 38#include "opt_sctp.h" 39#endif /* _KERNEL_OPT */ 40 41#include <sys/param.h> 42#include <sys/systm.h> 43#include <sys/kernel.h> 44#include <sys/malloc.h> 45#include <sys/mbuf.h> 46#include <sys/domain.h> 47#include <sys/proc.h> 48#include <sys/protosw.h> 49#include <sys/socket.h> 50#include <sys/socketvar.h> 51#include <sys/sysctl.h> 52#include <sys/syslog.h> 53#include <net/if.h> 54#include <net/route.h> 55#include <netinet/in.h> 56#include <netinet/in_systm.h> 57#include <netinet/ip.h> 58#ifdef INET6 59#include <netinet/ip6.h> 60#endif 61#include <netinet/in_pcb.h> 62#include <netinet/in_var.h> 63#include <netinet/ip_var.h> 64#ifdef INET6 65#include <netinet6/ip6_var.h> 66#endif 67#include <netinet/ip_icmp.h> 68#include <netinet/icmp_var.h> 69#include <netinet/sctp_pcb.h> 70#include <netinet/sctp.h> 71#include <netinet/sctp_uio.h> 72#include <netinet/sctp_var.h> 73#include <netinet/sctp_peeloff.h> 74#include <netinet/sctputil.h> 75 76#ifdef IPSEC 77#include <netipsec/ipsec.h> 78#include <netipsec/key.h> 79#endif /*IPSEC*/ 80 81#ifdef SCTP_DEBUG 82extern u_int32_t sctp_debug_on; 83#endif /* SCTP_DEBUG */ 84 85 86int 87sctp_can_peel_off(struct socket *head, u_int32_t assoc_id) 88{ 89 struct sctp_inpcb *inp; 90 struct sctp_tcb *stcb; 91 inp = (struct sctp_inpcb *)head->so_pcb; 92 if (inp == NULL) { 93 return (EFAULT); 94 } 95 stcb = sctp_findassociation_ep_asocid(inp, assoc_id); 96 if (stcb == NULL) { 97 return (ENOTCONN); 98 } 99 /* We are clear to peel this one off */ 100 return (0); 101} 102 103int 104sctp_do_peeloff(struct socket *head, struct socket *so, u_int32_t assoc_id) 105{ 106 struct sctp_inpcb *inp, *n_inp; 107 struct sctp_tcb *stcb; 108 109 inp = (struct sctp_inpcb *)head->so_pcb; 110 if (inp == NULL) 111 return (EFAULT); 112 stcb = sctp_findassociation_ep_asocid(inp, assoc_id); 113 if (stcb == NULL) 114 return (ENOTCONN); 115 116 n_inp = (struct sctp_inpcb *)so->so_pcb; 117 n_inp->sctp_flags = (SCTP_PCB_FLAGS_UDPTYPE | 118 SCTP_PCB_FLAGS_CONNECTED | 119 SCTP_PCB_FLAGS_IN_TCPPOOL | /* Turn on Blocking IO */ 120 (SCTP_PCB_COPY_FLAGS & inp->sctp_flags)); 121 n_inp->sctp_socket = so; 122 123 /* 124 * Now we must move it from one hash table to another and get 125 * the stcb in the right place. 126 */ 127 sctp_move_pcb_and_assoc(inp, n_inp, stcb); 128 /* 129 * And now the final hack. We move data in the 130 * pending side i.e. head to the new socket 131 * buffer. Let the GRUBBING begin :-0 132 */ 133 sctp_grub_through_socket_buffer(inp, head, so, stcb); 134 return (0); 135} 136 137struct socket * 138sctp_get_peeloff(struct socket *head, u_int32_t assoc_id, int *error) 139{ 140 struct socket *newso; 141 struct sctp_inpcb *inp, *n_inp; 142 struct sctp_tcb *stcb; 143 144#ifdef SCTP_DEBUG 145 if (sctp_debug_on & SCTP_DEBUG_PEEL1) { 146 printf("SCTP peel-off called\n"); 147 } 148#endif /* SCTP_DEBUG */ 149 150 inp = (struct sctp_inpcb *)head->so_pcb; 151 if (inp == NULL) { 152 *error = EFAULT; 153 return (NULL); 154 } 155 stcb = sctp_findassociation_ep_asocid(inp, assoc_id); 156 if (stcb == NULL) { 157 *error = ENOTCONN; 158 return (NULL); 159 } 160 newso = sonewconn(head, SS_ISCONNECTED); 161 if (newso == NULL) { 162#ifdef SCTP_DEBUG 163 if (sctp_debug_on & SCTP_DEBUG_PEEL1) { 164 printf("sctp_peeloff:sonewconn failed err\n"); 165 } 166#endif /* SCTP_DEBUG */ 167 *error = ENOMEM; 168 SCTP_TCB_UNLOCK(stcb); 169 return (NULL); 170 } 171 n_inp = (struct sctp_inpcb *)newso->so_pcb; 172 SCTP_INP_WLOCK(n_inp); 173 n_inp->sctp_flags = (SCTP_PCB_FLAGS_UDPTYPE | 174 SCTP_PCB_FLAGS_CONNECTED | 175 SCTP_PCB_FLAGS_IN_TCPPOOL | /* Turn on Blocking IO */ 176 (SCTP_PCB_COPY_FLAGS & inp->sctp_flags)); 177 n_inp->sctp_socket = newso; 178 /* Turn off any non-blocking symantic. */ 179 newso->so_state &= ~SS_NBIO; 180 newso->so_state |= SS_ISCONNECTED; 181 /* We remove it right away */ 182 newso = TAILQ_FIRST(&head->so_q); 183 if (soqremque(newso, 1) == 0) 184 panic("sctp_peeloff"); 185 186 /* 187 * Now we must move it from one hash table to another and get 188 * the stcb in the right place. 189 */ 190 SCTP_INP_WUNLOCK(n_inp); 191 sctp_move_pcb_and_assoc(inp, n_inp, stcb); 192 /* 193 * And now the final hack. We move data in the 194 * pending side i.e. head to the new socket 195 * buffer. Let the GRUBBING begin :-0 196 */ 197 sctp_grub_through_socket_buffer(inp, head, newso, stcb); 198 SCTP_TCB_UNLOCK(stcb); 199 return (newso); 200} 201