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