tor-browser

The Tor Browser
git clone https://git.dasho.dev/tor-browser.git
Log | Files | Refs | README | LICENSE

sctp_peeloff.c (10547B)


      1 /*-
      2 * SPDX-License-Identifier: BSD-3-Clause
      3 *
      4 * Copyright (c) 2001-2007, by Cisco Systems, Inc. All rights reserved.
      5 * Copyright (c) 2008-2012, by Randall Stewart. All rights reserved.
      6 * Copyright (c) 2008-2012, by Michael Tuexen. 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 are met:
     10 *
     11 * a) Redistributions of source code must retain the above copyright notice,
     12 *    this list of conditions and the following disclaimer.
     13 *
     14 * b) Redistributions in binary form must reproduce the above copyright
     15 *    notice, this list of conditions and the following disclaimer in
     16 *    the documentation and/or other materials provided with the distribution.
     17 *
     18 * c) Neither the name of Cisco Systems, Inc. nor the names of its
     19 *    contributors may be used to endorse or promote products derived
     20 *    from this software without specific prior written permission.
     21 *
     22 * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
     23 * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO,
     24 * THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
     25 * ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE
     26 * LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
     27 * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
     28 * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
     29 * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
     30 * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
     31 * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF
     32 * THE POSSIBILITY OF SUCH DAMAGE.
     33 */
     34 
     35 #include <netinet/sctp_os.h>
     36 #include <netinet/sctp_pcb.h>
     37 #include <netinet/sctputil.h>
     38 #include <netinet/sctp_var.h>
     39 #include <netinet/sctp_var.h>
     40 #include <netinet/sctp_sysctl.h>
     41 #include <netinet/sctp.h>
     42 #include <netinet/sctp_uio.h>
     43 #include <netinet/sctp_peeloff.h>
     44 #include <netinet/sctputil.h>
     45 #include <netinet/sctp_auth.h>
     46 
     47 int
     48 sctp_can_peel_off(struct socket *head, sctp_assoc_t assoc_id)
     49 {
     50 struct sctp_inpcb *inp;
     51 struct sctp_tcb *stcb;
     52 uint32_t state;
     53 
     54 if (head == NULL) {
     55 	SCTP_LTRACE_ERR_RET(NULL, NULL, NULL, SCTP_FROM_SCTP_PEELOFF, EBADF);
     56 	return (EBADF);
     57 }
     58 inp = (struct sctp_inpcb *)head->so_pcb;
     59 if (inp == NULL) {
     60 	SCTP_LTRACE_ERR_RET(NULL, NULL, NULL, SCTP_FROM_SCTP_PEELOFF, EFAULT);
     61 	return (EFAULT);
     62 }
     63 if ((inp->sctp_flags & SCTP_PCB_FLAGS_TCPTYPE) ||
     64     (inp->sctp_flags & SCTP_PCB_FLAGS_IN_TCPPOOL)) {
     65 	SCTP_LTRACE_ERR_RET(inp, NULL, NULL, SCTP_FROM_SCTP_PEELOFF, EOPNOTSUPP);
     66 	return (EOPNOTSUPP);
     67 }
     68 stcb = sctp_findassociation_ep_asocid(inp, assoc_id, 1);
     69 if (stcb == NULL) {
     70 	SCTP_LTRACE_ERR_RET(inp, stcb, NULL, SCTP_FROM_SCTP_PEELOFF, ENOENT);
     71 	return (ENOENT);
     72 }
     73 state = SCTP_GET_STATE(stcb);
     74 if ((state == SCTP_STATE_EMPTY) ||
     75     (state == SCTP_STATE_INUSE)) {
     76 	SCTP_TCB_UNLOCK(stcb);
     77 	SCTP_LTRACE_ERR_RET(inp, stcb, NULL, SCTP_FROM_SCTP_PEELOFF, ENOTCONN);
     78 	return (ENOTCONN);
     79 }
     80 SCTP_TCB_UNLOCK(stcb);
     81 /* We are clear to peel this one off */
     82 return (0);
     83 }
     84 
     85 int
     86 sctp_do_peeloff(struct socket *head, struct socket *so, sctp_assoc_t assoc_id)
     87 {
     88 struct sctp_inpcb *inp, *n_inp;
     89 struct sctp_tcb *stcb;
     90 uint32_t state;
     91 
     92 inp = (struct sctp_inpcb *)head->so_pcb;
     93 if (inp == NULL) {
     94 	SCTP_LTRACE_ERR_RET(inp, NULL, NULL, SCTP_FROM_SCTP_PEELOFF, EFAULT);
     95 	return (EFAULT);
     96 }
     97 stcb = sctp_findassociation_ep_asocid(inp, assoc_id, 1);
     98 if (stcb == NULL) {
     99 	SCTP_LTRACE_ERR_RET(inp, NULL, NULL, SCTP_FROM_SCTP_PEELOFF, ENOTCONN);
    100 	return (ENOTCONN);
    101 }
    102 
    103 state = SCTP_GET_STATE(stcb);
    104 if ((state == SCTP_STATE_EMPTY) ||
    105     (state == SCTP_STATE_INUSE)) {
    106 	SCTP_TCB_UNLOCK(stcb);
    107 	SCTP_LTRACE_ERR_RET(inp, NULL, NULL, SCTP_FROM_SCTP_PEELOFF, ENOTCONN);
    108 	return (ENOTCONN);
    109 }
    110 
    111 n_inp = (struct sctp_inpcb *)so->so_pcb;
    112 n_inp->sctp_flags = (SCTP_PCB_FLAGS_UDPTYPE |
    113     SCTP_PCB_FLAGS_CONNECTED |
    114     SCTP_PCB_FLAGS_IN_TCPPOOL |	/* Turn on Blocking IO */
    115     (SCTP_PCB_COPY_FLAGS & inp->sctp_flags));
    116 n_inp->sctp_socket = so;
    117 n_inp->sctp_features = inp->sctp_features;
    118 n_inp->sctp_mobility_features = inp->sctp_mobility_features;
    119 n_inp->sctp_frag_point = inp->sctp_frag_point;
    120 n_inp->sctp_cmt_on_off = inp->sctp_cmt_on_off;
    121 n_inp->ecn_supported = inp->ecn_supported;
    122 n_inp->prsctp_supported = inp->prsctp_supported;
    123 n_inp->auth_supported = inp->auth_supported;
    124 n_inp->asconf_supported = inp->asconf_supported;
    125 n_inp->reconfig_supported = inp->reconfig_supported;
    126 n_inp->nrsack_supported = inp->nrsack_supported;
    127 n_inp->pktdrop_supported = inp->pktdrop_supported;
    128 n_inp->partial_delivery_point = inp->partial_delivery_point;
    129 n_inp->sctp_context = inp->sctp_context;
    130 n_inp->max_cwnd = inp->max_cwnd;
    131 n_inp->local_strreset_support = inp->local_strreset_support;
    132 /* copy in the authentication parameters from the original endpoint */
    133 if (n_inp->sctp_ep.local_hmacs)
    134 	sctp_free_hmaclist(n_inp->sctp_ep.local_hmacs);
    135 n_inp->sctp_ep.local_hmacs =
    136     sctp_copy_hmaclist(inp->sctp_ep.local_hmacs);
    137 if (n_inp->sctp_ep.local_auth_chunks)
    138 	sctp_free_chunklist(n_inp->sctp_ep.local_auth_chunks);
    139 n_inp->sctp_ep.local_auth_chunks =
    140     sctp_copy_chunklist(inp->sctp_ep.local_auth_chunks);
    141 (void)sctp_copy_skeylist(&inp->sctp_ep.shared_keys,
    142     &n_inp->sctp_ep.shared_keys);
    143 #if defined(__Userspace__)
    144 n_inp->ulp_info = inp->ulp_info;
    145 n_inp->recv_callback = inp->recv_callback;
    146 n_inp->send_callback = inp->send_callback;
    147 n_inp->send_sb_threshold = inp->send_sb_threshold;
    148 #endif
    149 /*
    150  * Now we must move it from one hash table to another and get the
    151  * stcb in the right place.
    152  */
    153 sctp_move_pcb_and_assoc(inp, n_inp, stcb);
    154 atomic_add_int(&stcb->asoc.refcnt, 1);
    155 SCTP_TCB_UNLOCK(stcb);
    156 
    157 #if defined(__FreeBSD__) && !defined(__Userspace__)
    158 sctp_pull_off_control_to_new_inp(inp, n_inp, stcb, SBL_WAIT);
    159 #else
    160 sctp_pull_off_control_to_new_inp(inp, n_inp, stcb, M_WAITOK);
    161 #endif
    162 atomic_subtract_int(&stcb->asoc.refcnt, 1);
    163 
    164 return (0);
    165 }
    166 
    167 #if defined(HAVE_SCTP_PEELOFF_SOCKOPT)
    168 struct socket *
    169 sctp_get_peeloff(struct socket *head, sctp_assoc_t assoc_id, int *error)
    170 {
    171 struct socket *newso;
    172 struct sctp_inpcb *inp, *n_inp;
    173 struct sctp_tcb *stcb;
    174 
    175 SCTPDBG(SCTP_DEBUG_PEEL1, "SCTP peel-off called\n");
    176 inp = (struct sctp_inpcb *)head->so_pcb;
    177 if (inp == NULL) {
    178 	SCTP_LTRACE_ERR_RET(inp, NULL, NULL, SCTP_FROM_SCTP_PEELOFF, EFAULT);
    179 	*error = EFAULT;
    180 	return (NULL);
    181 }
    182 stcb = sctp_findassociation_ep_asocid(inp, assoc_id, 1);
    183 if (stcb == NULL) {
    184 	SCTP_LTRACE_ERR_RET(inp, NULL, NULL, SCTP_FROM_SCTP_PEELOFF, ENOTCONN);
    185 	*error = ENOTCONN;
    186 	return (NULL);
    187 }
    188 atomic_add_int(&stcb->asoc.refcnt, 1);
    189 SCTP_TCB_UNLOCK(stcb);
    190 #if defined(__FreeBSD__) && !defined(__Userspace__)
    191 CURVNET_SET(head->so_vnet);
    192 #endif
    193 newso = sonewconn(head, SS_ISCONNECTED
    194 #if defined(__APPLE__) && !defined(__Userspace__)
    195     , NULL
    196 #endif
    197 	);
    198 #if defined(__FreeBSD__) && !defined(__Userspace__)
    199 CURVNET_RESTORE();
    200 #endif
    201 if (newso == NULL) {
    202 	SCTPDBG(SCTP_DEBUG_PEEL1, "sctp_peeloff:sonewconn failed\n");
    203 	SCTP_LTRACE_ERR_RET(NULL, stcb, NULL, SCTP_FROM_SCTP_PEELOFF, ENOMEM);
    204 	*error = ENOMEM;
    205 	atomic_subtract_int(&stcb->asoc.refcnt, 1);
    206 	return (NULL);
    207 
    208 }
    209 #if defined(__APPLE__) && !defined(__Userspace__)
    210   else {
    211 	SCTP_SOCKET_LOCK(newso, 1);
    212 }
    213 #endif
    214 SCTP_TCB_LOCK(stcb);
    215 atomic_subtract_int(&stcb->asoc.refcnt, 1);
    216 n_inp = (struct sctp_inpcb *)newso->so_pcb;
    217 SOCK_LOCK(head);
    218 n_inp->sctp_flags = (SCTP_PCB_FLAGS_UDPTYPE |
    219     SCTP_PCB_FLAGS_CONNECTED |
    220     SCTP_PCB_FLAGS_IN_TCPPOOL |	/* Turn on Blocking IO */
    221     (SCTP_PCB_COPY_FLAGS & inp->sctp_flags));
    222 n_inp->sctp_features = inp->sctp_features;
    223 n_inp->sctp_frag_point = inp->sctp_frag_point;
    224 n_inp->sctp_cmt_on_off = inp->sctp_cmt_on_off;
    225 n_inp->ecn_supported = inp->ecn_supported;
    226 n_inp->prsctp_supported = inp->prsctp_supported;
    227 n_inp->auth_supported = inp->auth_supported;
    228 n_inp->asconf_supported = inp->asconf_supported;
    229 n_inp->reconfig_supported = inp->reconfig_supported;
    230 n_inp->nrsack_supported = inp->nrsack_supported;
    231 n_inp->pktdrop_supported = inp->pktdrop_supported;
    232 n_inp->partial_delivery_point = inp->partial_delivery_point;
    233 n_inp->sctp_context = inp->sctp_context;
    234 n_inp->max_cwnd = inp->max_cwnd;
    235 n_inp->local_strreset_support = inp->local_strreset_support;
    236 n_inp->inp_starting_point_for_iterator = NULL;
    237 #if defined(__Userspace__)
    238 n_inp->ulp_info = inp->ulp_info;
    239 n_inp->recv_callback = inp->recv_callback;
    240 n_inp->send_callback = inp->send_callback;
    241 n_inp->send_sb_threshold = inp->send_sb_threshold;
    242 #endif
    243 
    244 /* copy in the authentication parameters from the original endpoint */
    245 if (n_inp->sctp_ep.local_hmacs)
    246 	sctp_free_hmaclist(n_inp->sctp_ep.local_hmacs);
    247 n_inp->sctp_ep.local_hmacs =
    248     sctp_copy_hmaclist(inp->sctp_ep.local_hmacs);
    249 if (n_inp->sctp_ep.local_auth_chunks)
    250 	sctp_free_chunklist(n_inp->sctp_ep.local_auth_chunks);
    251 n_inp->sctp_ep.local_auth_chunks =
    252     sctp_copy_chunklist(inp->sctp_ep.local_auth_chunks);
    253 (void)sctp_copy_skeylist(&inp->sctp_ep.shared_keys,
    254     &n_inp->sctp_ep.shared_keys);
    255 
    256 n_inp->sctp_socket = newso;
    257 if (sctp_is_feature_on(inp, SCTP_PCB_FLAGS_AUTOCLOSE)) {
    258 	sctp_feature_off(n_inp, SCTP_PCB_FLAGS_AUTOCLOSE);
    259 	n_inp->sctp_ep.auto_close_time = 0;
    260 	sctp_timer_stop(SCTP_TIMER_TYPE_AUTOCLOSE, n_inp, stcb, NULL,
    261 			SCTP_FROM_SCTP_PEELOFF + SCTP_LOC_1);
    262 }
    263 /* Turn off any non-blocking semantic. */
    264 SOCK_LOCK(newso);
    265 SCTP_CLEAR_SO_NBIO(newso);
    266 newso->so_state |= SS_ISCONNECTED;
    267 SOCK_UNLOCK(newso);
    268 /* We remove it right away */
    269 
    270 #ifdef SCTP_LOCK_LOGGING
    271 if (SCTP_BASE_SYSCTL(sctp_logging_level) & SCTP_LOCK_LOGGING_ENABLE) {
    272 	sctp_log_lock(inp, (struct sctp_tcb *)NULL, SCTP_LOG_LOCK_SOCK);
    273 }
    274 #endif
    275 TAILQ_REMOVE(&head->so_comp, newso, so_list);
    276 head->so_qlen--;
    277 SOCK_UNLOCK(head);
    278 /*
    279  * Now we must move it from one hash table to another and get the
    280  * stcb in the right place.
    281  */
    282 sctp_move_pcb_and_assoc(inp, n_inp, stcb);
    283 atomic_add_int(&stcb->asoc.refcnt, 1);
    284 SCTP_TCB_UNLOCK(stcb);
    285 /*
    286  * And now the final hack. We move data in the pending side i.e.
    287  * head to the new socket buffer. Let the GRUBBING begin :-0
    288  */
    289 #if defined(__FreeBSD__) && !defined(__Userspace__)
    290 sctp_pull_off_control_to_new_inp(inp, n_inp, stcb, SBL_WAIT);
    291 #else
    292 sctp_pull_off_control_to_new_inp(inp, n_inp, stcb, M_WAITOK);
    293 #endif
    294 atomic_subtract_int(&stcb->asoc.refcnt, 1);
    295 return (newso);
    296 }
    297 #endif