18c2ecf20Sopenharmony_ci// SPDX-License-Identifier: GPL-2.0-or-later 28c2ecf20Sopenharmony_ci/* SCTP kernel implementation 38c2ecf20Sopenharmony_ci * (C) Copyright IBM Corp. 2001, 2004 48c2ecf20Sopenharmony_ci * Copyright (c) 1999-2000 Cisco, Inc. 58c2ecf20Sopenharmony_ci * Copyright (c) 1999-2001 Motorola, Inc. 68c2ecf20Sopenharmony_ci * Copyright (c) 2001 Intel Corp. 78c2ecf20Sopenharmony_ci * Copyright (c) 2001 La Monte H.P. Yarroll 88c2ecf20Sopenharmony_ci * 98c2ecf20Sopenharmony_ci * This file is part of the SCTP kernel implementation 108c2ecf20Sopenharmony_ci * 118c2ecf20Sopenharmony_ci * This module provides the abstraction for an SCTP association. 128c2ecf20Sopenharmony_ci * 138c2ecf20Sopenharmony_ci * Please send any bug reports or fixes you make to the 148c2ecf20Sopenharmony_ci * email address(es): 158c2ecf20Sopenharmony_ci * lksctp developers <linux-sctp@vger.kernel.org> 168c2ecf20Sopenharmony_ci * 178c2ecf20Sopenharmony_ci * Written or modified by: 188c2ecf20Sopenharmony_ci * La Monte H.P. Yarroll <piggy@acm.org> 198c2ecf20Sopenharmony_ci * Karl Knutson <karl@athena.chicago.il.us> 208c2ecf20Sopenharmony_ci * Jon Grimm <jgrimm@us.ibm.com> 218c2ecf20Sopenharmony_ci * Xingang Guo <xingang.guo@intel.com> 228c2ecf20Sopenharmony_ci * Hui Huang <hui.huang@nokia.com> 238c2ecf20Sopenharmony_ci * Sridhar Samudrala <sri@us.ibm.com> 248c2ecf20Sopenharmony_ci * Daisy Chang <daisyc@us.ibm.com> 258c2ecf20Sopenharmony_ci * Ryan Layer <rmlayer@us.ibm.com> 268c2ecf20Sopenharmony_ci * Kevin Gao <kevin.gao@intel.com> 278c2ecf20Sopenharmony_ci */ 288c2ecf20Sopenharmony_ci 298c2ecf20Sopenharmony_ci#define pr_fmt(fmt) KBUILD_MODNAME ": " fmt 308c2ecf20Sopenharmony_ci 318c2ecf20Sopenharmony_ci#include <linux/types.h> 328c2ecf20Sopenharmony_ci#include <linux/fcntl.h> 338c2ecf20Sopenharmony_ci#include <linux/poll.h> 348c2ecf20Sopenharmony_ci#include <linux/init.h> 358c2ecf20Sopenharmony_ci 368c2ecf20Sopenharmony_ci#include <linux/slab.h> 378c2ecf20Sopenharmony_ci#include <linux/in.h> 388c2ecf20Sopenharmony_ci#include <net/ipv6.h> 398c2ecf20Sopenharmony_ci#include <net/sctp/sctp.h> 408c2ecf20Sopenharmony_ci#include <net/sctp/sm.h> 418c2ecf20Sopenharmony_ci 428c2ecf20Sopenharmony_ci/* Forward declarations for internal functions. */ 438c2ecf20Sopenharmony_cistatic void sctp_select_active_and_retran_path(struct sctp_association *asoc); 448c2ecf20Sopenharmony_cistatic void sctp_assoc_bh_rcv(struct work_struct *work); 458c2ecf20Sopenharmony_cistatic void sctp_assoc_free_asconf_acks(struct sctp_association *asoc); 468c2ecf20Sopenharmony_cistatic void sctp_assoc_free_asconf_queue(struct sctp_association *asoc); 478c2ecf20Sopenharmony_ci 488c2ecf20Sopenharmony_ci/* 1st Level Abstractions. */ 498c2ecf20Sopenharmony_ci 508c2ecf20Sopenharmony_ci/* Initialize a new association from provided memory. */ 518c2ecf20Sopenharmony_cistatic struct sctp_association *sctp_association_init( 528c2ecf20Sopenharmony_ci struct sctp_association *asoc, 538c2ecf20Sopenharmony_ci const struct sctp_endpoint *ep, 548c2ecf20Sopenharmony_ci const struct sock *sk, 558c2ecf20Sopenharmony_ci enum sctp_scope scope, gfp_t gfp) 568c2ecf20Sopenharmony_ci{ 578c2ecf20Sopenharmony_ci struct sctp_sock *sp; 588c2ecf20Sopenharmony_ci struct sctp_paramhdr *p; 598c2ecf20Sopenharmony_ci int i; 608c2ecf20Sopenharmony_ci 618c2ecf20Sopenharmony_ci /* Retrieve the SCTP per socket area. */ 628c2ecf20Sopenharmony_ci sp = sctp_sk((struct sock *)sk); 638c2ecf20Sopenharmony_ci 648c2ecf20Sopenharmony_ci /* Discarding const is appropriate here. */ 658c2ecf20Sopenharmony_ci asoc->ep = (struct sctp_endpoint *)ep; 668c2ecf20Sopenharmony_ci asoc->base.sk = (struct sock *)sk; 678c2ecf20Sopenharmony_ci asoc->base.net = sock_net(sk); 688c2ecf20Sopenharmony_ci 698c2ecf20Sopenharmony_ci sctp_endpoint_hold(asoc->ep); 708c2ecf20Sopenharmony_ci sock_hold(asoc->base.sk); 718c2ecf20Sopenharmony_ci 728c2ecf20Sopenharmony_ci /* Initialize the common base substructure. */ 738c2ecf20Sopenharmony_ci asoc->base.type = SCTP_EP_TYPE_ASSOCIATION; 748c2ecf20Sopenharmony_ci 758c2ecf20Sopenharmony_ci /* Initialize the object handling fields. */ 768c2ecf20Sopenharmony_ci refcount_set(&asoc->base.refcnt, 1); 778c2ecf20Sopenharmony_ci 788c2ecf20Sopenharmony_ci /* Initialize the bind addr area. */ 798c2ecf20Sopenharmony_ci sctp_bind_addr_init(&asoc->base.bind_addr, ep->base.bind_addr.port); 808c2ecf20Sopenharmony_ci 818c2ecf20Sopenharmony_ci asoc->state = SCTP_STATE_CLOSED; 828c2ecf20Sopenharmony_ci asoc->cookie_life = ms_to_ktime(sp->assocparams.sasoc_cookie_life); 838c2ecf20Sopenharmony_ci asoc->user_frag = sp->user_frag; 848c2ecf20Sopenharmony_ci 858c2ecf20Sopenharmony_ci /* Set the association max_retrans and RTO values from the 868c2ecf20Sopenharmony_ci * socket values. 878c2ecf20Sopenharmony_ci */ 888c2ecf20Sopenharmony_ci asoc->max_retrans = sp->assocparams.sasoc_asocmaxrxt; 898c2ecf20Sopenharmony_ci asoc->pf_retrans = sp->pf_retrans; 908c2ecf20Sopenharmony_ci asoc->ps_retrans = sp->ps_retrans; 918c2ecf20Sopenharmony_ci asoc->pf_expose = sp->pf_expose; 928c2ecf20Sopenharmony_ci 938c2ecf20Sopenharmony_ci asoc->rto_initial = msecs_to_jiffies(sp->rtoinfo.srto_initial); 948c2ecf20Sopenharmony_ci asoc->rto_max = msecs_to_jiffies(sp->rtoinfo.srto_max); 958c2ecf20Sopenharmony_ci asoc->rto_min = msecs_to_jiffies(sp->rtoinfo.srto_min); 968c2ecf20Sopenharmony_ci 978c2ecf20Sopenharmony_ci /* Initialize the association's heartbeat interval based on the 988c2ecf20Sopenharmony_ci * sock configured value. 998c2ecf20Sopenharmony_ci */ 1008c2ecf20Sopenharmony_ci asoc->hbinterval = msecs_to_jiffies(sp->hbinterval); 1018c2ecf20Sopenharmony_ci 1028c2ecf20Sopenharmony_ci /* Initialize path max retrans value. */ 1038c2ecf20Sopenharmony_ci asoc->pathmaxrxt = sp->pathmaxrxt; 1048c2ecf20Sopenharmony_ci 1058c2ecf20Sopenharmony_ci asoc->flowlabel = sp->flowlabel; 1068c2ecf20Sopenharmony_ci asoc->dscp = sp->dscp; 1078c2ecf20Sopenharmony_ci 1088c2ecf20Sopenharmony_ci /* Set association default SACK delay */ 1098c2ecf20Sopenharmony_ci asoc->sackdelay = msecs_to_jiffies(sp->sackdelay); 1108c2ecf20Sopenharmony_ci asoc->sackfreq = sp->sackfreq; 1118c2ecf20Sopenharmony_ci 1128c2ecf20Sopenharmony_ci /* Set the association default flags controlling 1138c2ecf20Sopenharmony_ci * Heartbeat, SACK delay, and Path MTU Discovery. 1148c2ecf20Sopenharmony_ci */ 1158c2ecf20Sopenharmony_ci asoc->param_flags = sp->param_flags; 1168c2ecf20Sopenharmony_ci 1178c2ecf20Sopenharmony_ci /* Initialize the maximum number of new data packets that can be sent 1188c2ecf20Sopenharmony_ci * in a burst. 1198c2ecf20Sopenharmony_ci */ 1208c2ecf20Sopenharmony_ci asoc->max_burst = sp->max_burst; 1218c2ecf20Sopenharmony_ci 1228c2ecf20Sopenharmony_ci asoc->subscribe = sp->subscribe; 1238c2ecf20Sopenharmony_ci 1248c2ecf20Sopenharmony_ci /* initialize association timers */ 1258c2ecf20Sopenharmony_ci asoc->timeouts[SCTP_EVENT_TIMEOUT_T1_COOKIE] = asoc->rto_initial; 1268c2ecf20Sopenharmony_ci asoc->timeouts[SCTP_EVENT_TIMEOUT_T1_INIT] = asoc->rto_initial; 1278c2ecf20Sopenharmony_ci asoc->timeouts[SCTP_EVENT_TIMEOUT_T2_SHUTDOWN] = asoc->rto_initial; 1288c2ecf20Sopenharmony_ci 1298c2ecf20Sopenharmony_ci /* sctpimpguide Section 2.12.2 1308c2ecf20Sopenharmony_ci * If the 'T5-shutdown-guard' timer is used, it SHOULD be set to the 1318c2ecf20Sopenharmony_ci * recommended value of 5 times 'RTO.Max'. 1328c2ecf20Sopenharmony_ci */ 1338c2ecf20Sopenharmony_ci asoc->timeouts[SCTP_EVENT_TIMEOUT_T5_SHUTDOWN_GUARD] 1348c2ecf20Sopenharmony_ci = 5 * asoc->rto_max; 1358c2ecf20Sopenharmony_ci 1368c2ecf20Sopenharmony_ci asoc->timeouts[SCTP_EVENT_TIMEOUT_SACK] = asoc->sackdelay; 1378c2ecf20Sopenharmony_ci asoc->timeouts[SCTP_EVENT_TIMEOUT_AUTOCLOSE] = sp->autoclose * HZ; 1388c2ecf20Sopenharmony_ci 1398c2ecf20Sopenharmony_ci /* Initializes the timers */ 1408c2ecf20Sopenharmony_ci for (i = SCTP_EVENT_TIMEOUT_NONE; i < SCTP_NUM_TIMEOUT_TYPES; ++i) 1418c2ecf20Sopenharmony_ci timer_setup(&asoc->timers[i], sctp_timer_events[i], 0); 1428c2ecf20Sopenharmony_ci 1438c2ecf20Sopenharmony_ci /* Pull default initialization values from the sock options. 1448c2ecf20Sopenharmony_ci * Note: This assumes that the values have already been 1458c2ecf20Sopenharmony_ci * validated in the sock. 1468c2ecf20Sopenharmony_ci */ 1478c2ecf20Sopenharmony_ci asoc->c.sinit_max_instreams = sp->initmsg.sinit_max_instreams; 1488c2ecf20Sopenharmony_ci asoc->c.sinit_num_ostreams = sp->initmsg.sinit_num_ostreams; 1498c2ecf20Sopenharmony_ci asoc->max_init_attempts = sp->initmsg.sinit_max_attempts; 1508c2ecf20Sopenharmony_ci 1518c2ecf20Sopenharmony_ci asoc->max_init_timeo = 1528c2ecf20Sopenharmony_ci msecs_to_jiffies(sp->initmsg.sinit_max_init_timeo); 1538c2ecf20Sopenharmony_ci 1548c2ecf20Sopenharmony_ci /* Set the local window size for receive. 1558c2ecf20Sopenharmony_ci * This is also the rcvbuf space per association. 1568c2ecf20Sopenharmony_ci * RFC 6 - A SCTP receiver MUST be able to receive a minimum of 1578c2ecf20Sopenharmony_ci * 1500 bytes in one SCTP packet. 1588c2ecf20Sopenharmony_ci */ 1598c2ecf20Sopenharmony_ci if ((sk->sk_rcvbuf/2) < SCTP_DEFAULT_MINWINDOW) 1608c2ecf20Sopenharmony_ci asoc->rwnd = SCTP_DEFAULT_MINWINDOW; 1618c2ecf20Sopenharmony_ci else 1628c2ecf20Sopenharmony_ci asoc->rwnd = sk->sk_rcvbuf/2; 1638c2ecf20Sopenharmony_ci 1648c2ecf20Sopenharmony_ci asoc->a_rwnd = asoc->rwnd; 1658c2ecf20Sopenharmony_ci 1668c2ecf20Sopenharmony_ci /* Use my own max window until I learn something better. */ 1678c2ecf20Sopenharmony_ci asoc->peer.rwnd = SCTP_DEFAULT_MAXWINDOW; 1688c2ecf20Sopenharmony_ci 1698c2ecf20Sopenharmony_ci /* Initialize the receive memory counter */ 1708c2ecf20Sopenharmony_ci atomic_set(&asoc->rmem_alloc, 0); 1718c2ecf20Sopenharmony_ci 1728c2ecf20Sopenharmony_ci init_waitqueue_head(&asoc->wait); 1738c2ecf20Sopenharmony_ci 1748c2ecf20Sopenharmony_ci asoc->c.my_vtag = sctp_generate_tag(ep); 1758c2ecf20Sopenharmony_ci asoc->c.my_port = ep->base.bind_addr.port; 1768c2ecf20Sopenharmony_ci 1778c2ecf20Sopenharmony_ci asoc->c.initial_tsn = sctp_generate_tsn(ep); 1788c2ecf20Sopenharmony_ci 1798c2ecf20Sopenharmony_ci asoc->next_tsn = asoc->c.initial_tsn; 1808c2ecf20Sopenharmony_ci 1818c2ecf20Sopenharmony_ci asoc->ctsn_ack_point = asoc->next_tsn - 1; 1828c2ecf20Sopenharmony_ci asoc->adv_peer_ack_point = asoc->ctsn_ack_point; 1838c2ecf20Sopenharmony_ci asoc->highest_sacked = asoc->ctsn_ack_point; 1848c2ecf20Sopenharmony_ci asoc->last_cwr_tsn = asoc->ctsn_ack_point; 1858c2ecf20Sopenharmony_ci 1868c2ecf20Sopenharmony_ci /* ADDIP Section 4.1 Asconf Chunk Procedures 1878c2ecf20Sopenharmony_ci * 1888c2ecf20Sopenharmony_ci * When an endpoint has an ASCONF signaled change to be sent to the 1898c2ecf20Sopenharmony_ci * remote endpoint it should do the following: 1908c2ecf20Sopenharmony_ci * ... 1918c2ecf20Sopenharmony_ci * A2) a serial number should be assigned to the chunk. The serial 1928c2ecf20Sopenharmony_ci * number SHOULD be a monotonically increasing number. The serial 1938c2ecf20Sopenharmony_ci * numbers SHOULD be initialized at the start of the 1948c2ecf20Sopenharmony_ci * association to the same value as the initial TSN. 1958c2ecf20Sopenharmony_ci */ 1968c2ecf20Sopenharmony_ci asoc->addip_serial = asoc->c.initial_tsn; 1978c2ecf20Sopenharmony_ci asoc->strreset_outseq = asoc->c.initial_tsn; 1988c2ecf20Sopenharmony_ci 1998c2ecf20Sopenharmony_ci INIT_LIST_HEAD(&asoc->addip_chunk_list); 2008c2ecf20Sopenharmony_ci INIT_LIST_HEAD(&asoc->asconf_ack_list); 2018c2ecf20Sopenharmony_ci 2028c2ecf20Sopenharmony_ci /* Make an empty list of remote transport addresses. */ 2038c2ecf20Sopenharmony_ci INIT_LIST_HEAD(&asoc->peer.transport_addr_list); 2048c2ecf20Sopenharmony_ci 2058c2ecf20Sopenharmony_ci /* RFC 2960 5.1 Normal Establishment of an Association 2068c2ecf20Sopenharmony_ci * 2078c2ecf20Sopenharmony_ci * After the reception of the first data chunk in an 2088c2ecf20Sopenharmony_ci * association the endpoint must immediately respond with a 2098c2ecf20Sopenharmony_ci * sack to acknowledge the data chunk. Subsequent 2108c2ecf20Sopenharmony_ci * acknowledgements should be done as described in Section 2118c2ecf20Sopenharmony_ci * 6.2. 2128c2ecf20Sopenharmony_ci * 2138c2ecf20Sopenharmony_ci * [We implement this by telling a new association that it 2148c2ecf20Sopenharmony_ci * already received one packet.] 2158c2ecf20Sopenharmony_ci */ 2168c2ecf20Sopenharmony_ci asoc->peer.sack_needed = 1; 2178c2ecf20Sopenharmony_ci asoc->peer.sack_generation = 1; 2188c2ecf20Sopenharmony_ci 2198c2ecf20Sopenharmony_ci /* Create an input queue. */ 2208c2ecf20Sopenharmony_ci sctp_inq_init(&asoc->base.inqueue); 2218c2ecf20Sopenharmony_ci sctp_inq_set_th_handler(&asoc->base.inqueue, sctp_assoc_bh_rcv); 2228c2ecf20Sopenharmony_ci 2238c2ecf20Sopenharmony_ci /* Create an output queue. */ 2248c2ecf20Sopenharmony_ci sctp_outq_init(asoc, &asoc->outqueue); 2258c2ecf20Sopenharmony_ci 2268c2ecf20Sopenharmony_ci if (!sctp_ulpq_init(&asoc->ulpq, asoc)) 2278c2ecf20Sopenharmony_ci goto fail_init; 2288c2ecf20Sopenharmony_ci 2298c2ecf20Sopenharmony_ci if (sctp_stream_init(&asoc->stream, asoc->c.sinit_num_ostreams, 0, gfp)) 2308c2ecf20Sopenharmony_ci goto stream_free; 2318c2ecf20Sopenharmony_ci 2328c2ecf20Sopenharmony_ci /* Initialize default path MTU. */ 2338c2ecf20Sopenharmony_ci asoc->pathmtu = sp->pathmtu; 2348c2ecf20Sopenharmony_ci sctp_assoc_update_frag_point(asoc); 2358c2ecf20Sopenharmony_ci 2368c2ecf20Sopenharmony_ci /* Assume that peer would support both address types unless we are 2378c2ecf20Sopenharmony_ci * told otherwise. 2388c2ecf20Sopenharmony_ci */ 2398c2ecf20Sopenharmony_ci asoc->peer.ipv4_address = 1; 2408c2ecf20Sopenharmony_ci if (asoc->base.sk->sk_family == PF_INET6) 2418c2ecf20Sopenharmony_ci asoc->peer.ipv6_address = 1; 2428c2ecf20Sopenharmony_ci INIT_LIST_HEAD(&asoc->asocs); 2438c2ecf20Sopenharmony_ci 2448c2ecf20Sopenharmony_ci asoc->default_stream = sp->default_stream; 2458c2ecf20Sopenharmony_ci asoc->default_ppid = sp->default_ppid; 2468c2ecf20Sopenharmony_ci asoc->default_flags = sp->default_flags; 2478c2ecf20Sopenharmony_ci asoc->default_context = sp->default_context; 2488c2ecf20Sopenharmony_ci asoc->default_timetolive = sp->default_timetolive; 2498c2ecf20Sopenharmony_ci asoc->default_rcv_context = sp->default_rcv_context; 2508c2ecf20Sopenharmony_ci 2518c2ecf20Sopenharmony_ci /* AUTH related initializations */ 2528c2ecf20Sopenharmony_ci INIT_LIST_HEAD(&asoc->endpoint_shared_keys); 2538c2ecf20Sopenharmony_ci if (sctp_auth_asoc_copy_shkeys(ep, asoc, gfp)) 2548c2ecf20Sopenharmony_ci goto stream_free; 2558c2ecf20Sopenharmony_ci 2568c2ecf20Sopenharmony_ci asoc->active_key_id = ep->active_key_id; 2578c2ecf20Sopenharmony_ci asoc->strreset_enable = ep->strreset_enable; 2588c2ecf20Sopenharmony_ci 2598c2ecf20Sopenharmony_ci /* Save the hmacs and chunks list into this association */ 2608c2ecf20Sopenharmony_ci if (ep->auth_hmacs_list) 2618c2ecf20Sopenharmony_ci memcpy(asoc->c.auth_hmacs, ep->auth_hmacs_list, 2628c2ecf20Sopenharmony_ci ntohs(ep->auth_hmacs_list->param_hdr.length)); 2638c2ecf20Sopenharmony_ci if (ep->auth_chunk_list) 2648c2ecf20Sopenharmony_ci memcpy(asoc->c.auth_chunks, ep->auth_chunk_list, 2658c2ecf20Sopenharmony_ci ntohs(ep->auth_chunk_list->param_hdr.length)); 2668c2ecf20Sopenharmony_ci 2678c2ecf20Sopenharmony_ci /* Get the AUTH random number for this association */ 2688c2ecf20Sopenharmony_ci p = (struct sctp_paramhdr *)asoc->c.auth_random; 2698c2ecf20Sopenharmony_ci p->type = SCTP_PARAM_RANDOM; 2708c2ecf20Sopenharmony_ci p->length = htons(sizeof(*p) + SCTP_AUTH_RANDOM_LENGTH); 2718c2ecf20Sopenharmony_ci get_random_bytes(p+1, SCTP_AUTH_RANDOM_LENGTH); 2728c2ecf20Sopenharmony_ci 2738c2ecf20Sopenharmony_ci return asoc; 2748c2ecf20Sopenharmony_ci 2758c2ecf20Sopenharmony_cistream_free: 2768c2ecf20Sopenharmony_ci sctp_stream_free(&asoc->stream); 2778c2ecf20Sopenharmony_cifail_init: 2788c2ecf20Sopenharmony_ci sock_put(asoc->base.sk); 2798c2ecf20Sopenharmony_ci sctp_endpoint_put(asoc->ep); 2808c2ecf20Sopenharmony_ci return NULL; 2818c2ecf20Sopenharmony_ci} 2828c2ecf20Sopenharmony_ci 2838c2ecf20Sopenharmony_ci/* Allocate and initialize a new association */ 2848c2ecf20Sopenharmony_cistruct sctp_association *sctp_association_new(const struct sctp_endpoint *ep, 2858c2ecf20Sopenharmony_ci const struct sock *sk, 2868c2ecf20Sopenharmony_ci enum sctp_scope scope, gfp_t gfp) 2878c2ecf20Sopenharmony_ci{ 2888c2ecf20Sopenharmony_ci struct sctp_association *asoc; 2898c2ecf20Sopenharmony_ci 2908c2ecf20Sopenharmony_ci asoc = kzalloc(sizeof(*asoc), gfp); 2918c2ecf20Sopenharmony_ci if (!asoc) 2928c2ecf20Sopenharmony_ci goto fail; 2938c2ecf20Sopenharmony_ci 2948c2ecf20Sopenharmony_ci if (!sctp_association_init(asoc, ep, sk, scope, gfp)) 2958c2ecf20Sopenharmony_ci goto fail_init; 2968c2ecf20Sopenharmony_ci 2978c2ecf20Sopenharmony_ci SCTP_DBG_OBJCNT_INC(assoc); 2988c2ecf20Sopenharmony_ci 2998c2ecf20Sopenharmony_ci pr_debug("Created asoc %p\n", asoc); 3008c2ecf20Sopenharmony_ci 3018c2ecf20Sopenharmony_ci return asoc; 3028c2ecf20Sopenharmony_ci 3038c2ecf20Sopenharmony_cifail_init: 3048c2ecf20Sopenharmony_ci kfree(asoc); 3058c2ecf20Sopenharmony_cifail: 3068c2ecf20Sopenharmony_ci return NULL; 3078c2ecf20Sopenharmony_ci} 3088c2ecf20Sopenharmony_ci 3098c2ecf20Sopenharmony_ci/* Free this association if possible. There may still be users, so 3108c2ecf20Sopenharmony_ci * the actual deallocation may be delayed. 3118c2ecf20Sopenharmony_ci */ 3128c2ecf20Sopenharmony_civoid sctp_association_free(struct sctp_association *asoc) 3138c2ecf20Sopenharmony_ci{ 3148c2ecf20Sopenharmony_ci struct sock *sk = asoc->base.sk; 3158c2ecf20Sopenharmony_ci struct sctp_transport *transport; 3168c2ecf20Sopenharmony_ci struct list_head *pos, *temp; 3178c2ecf20Sopenharmony_ci int i; 3188c2ecf20Sopenharmony_ci 3198c2ecf20Sopenharmony_ci /* Only real associations count against the endpoint, so 3208c2ecf20Sopenharmony_ci * don't bother for if this is a temporary association. 3218c2ecf20Sopenharmony_ci */ 3228c2ecf20Sopenharmony_ci if (!list_empty(&asoc->asocs)) { 3238c2ecf20Sopenharmony_ci list_del(&asoc->asocs); 3248c2ecf20Sopenharmony_ci 3258c2ecf20Sopenharmony_ci /* Decrement the backlog value for a TCP-style listening 3268c2ecf20Sopenharmony_ci * socket. 3278c2ecf20Sopenharmony_ci */ 3288c2ecf20Sopenharmony_ci if (sctp_style(sk, TCP) && sctp_sstate(sk, LISTENING)) 3298c2ecf20Sopenharmony_ci sk_acceptq_removed(sk); 3308c2ecf20Sopenharmony_ci } 3318c2ecf20Sopenharmony_ci 3328c2ecf20Sopenharmony_ci /* Mark as dead, so other users can know this structure is 3338c2ecf20Sopenharmony_ci * going away. 3348c2ecf20Sopenharmony_ci */ 3358c2ecf20Sopenharmony_ci asoc->base.dead = true; 3368c2ecf20Sopenharmony_ci 3378c2ecf20Sopenharmony_ci /* Dispose of any data lying around in the outqueue. */ 3388c2ecf20Sopenharmony_ci sctp_outq_free(&asoc->outqueue); 3398c2ecf20Sopenharmony_ci 3408c2ecf20Sopenharmony_ci /* Dispose of any pending messages for the upper layer. */ 3418c2ecf20Sopenharmony_ci sctp_ulpq_free(&asoc->ulpq); 3428c2ecf20Sopenharmony_ci 3438c2ecf20Sopenharmony_ci /* Dispose of any pending chunks on the inqueue. */ 3448c2ecf20Sopenharmony_ci sctp_inq_free(&asoc->base.inqueue); 3458c2ecf20Sopenharmony_ci 3468c2ecf20Sopenharmony_ci sctp_tsnmap_free(&asoc->peer.tsn_map); 3478c2ecf20Sopenharmony_ci 3488c2ecf20Sopenharmony_ci /* Free stream information. */ 3498c2ecf20Sopenharmony_ci sctp_stream_free(&asoc->stream); 3508c2ecf20Sopenharmony_ci 3518c2ecf20Sopenharmony_ci if (asoc->strreset_chunk) 3528c2ecf20Sopenharmony_ci sctp_chunk_free(asoc->strreset_chunk); 3538c2ecf20Sopenharmony_ci 3548c2ecf20Sopenharmony_ci /* Clean up the bound address list. */ 3558c2ecf20Sopenharmony_ci sctp_bind_addr_free(&asoc->base.bind_addr); 3568c2ecf20Sopenharmony_ci 3578c2ecf20Sopenharmony_ci /* Do we need to go through all of our timers and 3588c2ecf20Sopenharmony_ci * delete them? To be safe we will try to delete all, but we 3598c2ecf20Sopenharmony_ci * should be able to go through and make a guess based 3608c2ecf20Sopenharmony_ci * on our state. 3618c2ecf20Sopenharmony_ci */ 3628c2ecf20Sopenharmony_ci for (i = SCTP_EVENT_TIMEOUT_NONE; i < SCTP_NUM_TIMEOUT_TYPES; ++i) { 3638c2ecf20Sopenharmony_ci if (del_timer(&asoc->timers[i])) 3648c2ecf20Sopenharmony_ci sctp_association_put(asoc); 3658c2ecf20Sopenharmony_ci } 3668c2ecf20Sopenharmony_ci 3678c2ecf20Sopenharmony_ci /* Free peer's cached cookie. */ 3688c2ecf20Sopenharmony_ci kfree(asoc->peer.cookie); 3698c2ecf20Sopenharmony_ci kfree(asoc->peer.peer_random); 3708c2ecf20Sopenharmony_ci kfree(asoc->peer.peer_chunks); 3718c2ecf20Sopenharmony_ci kfree(asoc->peer.peer_hmacs); 3728c2ecf20Sopenharmony_ci 3738c2ecf20Sopenharmony_ci /* Release the transport structures. */ 3748c2ecf20Sopenharmony_ci list_for_each_safe(pos, temp, &asoc->peer.transport_addr_list) { 3758c2ecf20Sopenharmony_ci transport = list_entry(pos, struct sctp_transport, transports); 3768c2ecf20Sopenharmony_ci list_del_rcu(pos); 3778c2ecf20Sopenharmony_ci sctp_unhash_transport(transport); 3788c2ecf20Sopenharmony_ci sctp_transport_free(transport); 3798c2ecf20Sopenharmony_ci } 3808c2ecf20Sopenharmony_ci 3818c2ecf20Sopenharmony_ci asoc->peer.transport_count = 0; 3828c2ecf20Sopenharmony_ci 3838c2ecf20Sopenharmony_ci sctp_asconf_queue_teardown(asoc); 3848c2ecf20Sopenharmony_ci 3858c2ecf20Sopenharmony_ci /* Free pending address space being deleted */ 3868c2ecf20Sopenharmony_ci kfree(asoc->asconf_addr_del_pending); 3878c2ecf20Sopenharmony_ci 3888c2ecf20Sopenharmony_ci /* AUTH - Free the endpoint shared keys */ 3898c2ecf20Sopenharmony_ci sctp_auth_destroy_keys(&asoc->endpoint_shared_keys); 3908c2ecf20Sopenharmony_ci 3918c2ecf20Sopenharmony_ci /* AUTH - Free the association shared key */ 3928c2ecf20Sopenharmony_ci sctp_auth_key_put(asoc->asoc_shared_key); 3938c2ecf20Sopenharmony_ci 3948c2ecf20Sopenharmony_ci sctp_association_put(asoc); 3958c2ecf20Sopenharmony_ci} 3968c2ecf20Sopenharmony_ci 3978c2ecf20Sopenharmony_ci/* Cleanup and free up an association. */ 3988c2ecf20Sopenharmony_cistatic void sctp_association_destroy(struct sctp_association *asoc) 3998c2ecf20Sopenharmony_ci{ 4008c2ecf20Sopenharmony_ci if (unlikely(!asoc->base.dead)) { 4018c2ecf20Sopenharmony_ci WARN(1, "Attempt to destroy undead association %p!\n", asoc); 4028c2ecf20Sopenharmony_ci return; 4038c2ecf20Sopenharmony_ci } 4048c2ecf20Sopenharmony_ci 4058c2ecf20Sopenharmony_ci sctp_endpoint_put(asoc->ep); 4068c2ecf20Sopenharmony_ci sock_put(asoc->base.sk); 4078c2ecf20Sopenharmony_ci 4088c2ecf20Sopenharmony_ci if (asoc->assoc_id != 0) { 4098c2ecf20Sopenharmony_ci spin_lock_bh(&sctp_assocs_id_lock); 4108c2ecf20Sopenharmony_ci idr_remove(&sctp_assocs_id, asoc->assoc_id); 4118c2ecf20Sopenharmony_ci spin_unlock_bh(&sctp_assocs_id_lock); 4128c2ecf20Sopenharmony_ci } 4138c2ecf20Sopenharmony_ci 4148c2ecf20Sopenharmony_ci WARN_ON(atomic_read(&asoc->rmem_alloc)); 4158c2ecf20Sopenharmony_ci 4168c2ecf20Sopenharmony_ci kfree_rcu(asoc, rcu); 4178c2ecf20Sopenharmony_ci SCTP_DBG_OBJCNT_DEC(assoc); 4188c2ecf20Sopenharmony_ci} 4198c2ecf20Sopenharmony_ci 4208c2ecf20Sopenharmony_ci/* Change the primary destination address for the peer. */ 4218c2ecf20Sopenharmony_civoid sctp_assoc_set_primary(struct sctp_association *asoc, 4228c2ecf20Sopenharmony_ci struct sctp_transport *transport) 4238c2ecf20Sopenharmony_ci{ 4248c2ecf20Sopenharmony_ci int changeover = 0; 4258c2ecf20Sopenharmony_ci 4268c2ecf20Sopenharmony_ci /* it's a changeover only if we already have a primary path 4278c2ecf20Sopenharmony_ci * that we are changing 4288c2ecf20Sopenharmony_ci */ 4298c2ecf20Sopenharmony_ci if (asoc->peer.primary_path != NULL && 4308c2ecf20Sopenharmony_ci asoc->peer.primary_path != transport) 4318c2ecf20Sopenharmony_ci changeover = 1 ; 4328c2ecf20Sopenharmony_ci 4338c2ecf20Sopenharmony_ci asoc->peer.primary_path = transport; 4348c2ecf20Sopenharmony_ci sctp_ulpevent_notify_peer_addr_change(transport, 4358c2ecf20Sopenharmony_ci SCTP_ADDR_MADE_PRIM, 0); 4368c2ecf20Sopenharmony_ci 4378c2ecf20Sopenharmony_ci /* Set a default msg_name for events. */ 4388c2ecf20Sopenharmony_ci memcpy(&asoc->peer.primary_addr, &transport->ipaddr, 4398c2ecf20Sopenharmony_ci sizeof(union sctp_addr)); 4408c2ecf20Sopenharmony_ci 4418c2ecf20Sopenharmony_ci /* If the primary path is changing, assume that the 4428c2ecf20Sopenharmony_ci * user wants to use this new path. 4438c2ecf20Sopenharmony_ci */ 4448c2ecf20Sopenharmony_ci if ((transport->state == SCTP_ACTIVE) || 4458c2ecf20Sopenharmony_ci (transport->state == SCTP_UNKNOWN)) 4468c2ecf20Sopenharmony_ci asoc->peer.active_path = transport; 4478c2ecf20Sopenharmony_ci 4488c2ecf20Sopenharmony_ci /* 4498c2ecf20Sopenharmony_ci * SFR-CACC algorithm: 4508c2ecf20Sopenharmony_ci * Upon the receipt of a request to change the primary 4518c2ecf20Sopenharmony_ci * destination address, on the data structure for the new 4528c2ecf20Sopenharmony_ci * primary destination, the sender MUST do the following: 4538c2ecf20Sopenharmony_ci * 4548c2ecf20Sopenharmony_ci * 1) If CHANGEOVER_ACTIVE is set, then there was a switch 4558c2ecf20Sopenharmony_ci * to this destination address earlier. The sender MUST set 4568c2ecf20Sopenharmony_ci * CYCLING_CHANGEOVER to indicate that this switch is a 4578c2ecf20Sopenharmony_ci * double switch to the same destination address. 4588c2ecf20Sopenharmony_ci * 4598c2ecf20Sopenharmony_ci * Really, only bother is we have data queued or outstanding on 4608c2ecf20Sopenharmony_ci * the association. 4618c2ecf20Sopenharmony_ci */ 4628c2ecf20Sopenharmony_ci if (!asoc->outqueue.outstanding_bytes && !asoc->outqueue.out_qlen) 4638c2ecf20Sopenharmony_ci return; 4648c2ecf20Sopenharmony_ci 4658c2ecf20Sopenharmony_ci if (transport->cacc.changeover_active) 4668c2ecf20Sopenharmony_ci transport->cacc.cycling_changeover = changeover; 4678c2ecf20Sopenharmony_ci 4688c2ecf20Sopenharmony_ci /* 2) The sender MUST set CHANGEOVER_ACTIVE to indicate that 4698c2ecf20Sopenharmony_ci * a changeover has occurred. 4708c2ecf20Sopenharmony_ci */ 4718c2ecf20Sopenharmony_ci transport->cacc.changeover_active = changeover; 4728c2ecf20Sopenharmony_ci 4738c2ecf20Sopenharmony_ci /* 3) The sender MUST store the next TSN to be sent in 4748c2ecf20Sopenharmony_ci * next_tsn_at_change. 4758c2ecf20Sopenharmony_ci */ 4768c2ecf20Sopenharmony_ci transport->cacc.next_tsn_at_change = asoc->next_tsn; 4778c2ecf20Sopenharmony_ci} 4788c2ecf20Sopenharmony_ci 4798c2ecf20Sopenharmony_ci/* Remove a transport from an association. */ 4808c2ecf20Sopenharmony_civoid sctp_assoc_rm_peer(struct sctp_association *asoc, 4818c2ecf20Sopenharmony_ci struct sctp_transport *peer) 4828c2ecf20Sopenharmony_ci{ 4838c2ecf20Sopenharmony_ci struct sctp_transport *transport; 4848c2ecf20Sopenharmony_ci struct list_head *pos; 4858c2ecf20Sopenharmony_ci struct sctp_chunk *ch; 4868c2ecf20Sopenharmony_ci 4878c2ecf20Sopenharmony_ci pr_debug("%s: association:%p addr:%pISpc\n", 4888c2ecf20Sopenharmony_ci __func__, asoc, &peer->ipaddr.sa); 4898c2ecf20Sopenharmony_ci 4908c2ecf20Sopenharmony_ci /* If we are to remove the current retran_path, update it 4918c2ecf20Sopenharmony_ci * to the next peer before removing this peer from the list. 4928c2ecf20Sopenharmony_ci */ 4938c2ecf20Sopenharmony_ci if (asoc->peer.retran_path == peer) 4948c2ecf20Sopenharmony_ci sctp_assoc_update_retran_path(asoc); 4958c2ecf20Sopenharmony_ci 4968c2ecf20Sopenharmony_ci /* Remove this peer from the list. */ 4978c2ecf20Sopenharmony_ci list_del_rcu(&peer->transports); 4988c2ecf20Sopenharmony_ci /* Remove this peer from the transport hashtable */ 4998c2ecf20Sopenharmony_ci sctp_unhash_transport(peer); 5008c2ecf20Sopenharmony_ci 5018c2ecf20Sopenharmony_ci /* Get the first transport of asoc. */ 5028c2ecf20Sopenharmony_ci pos = asoc->peer.transport_addr_list.next; 5038c2ecf20Sopenharmony_ci transport = list_entry(pos, struct sctp_transport, transports); 5048c2ecf20Sopenharmony_ci 5058c2ecf20Sopenharmony_ci /* Update any entries that match the peer to be deleted. */ 5068c2ecf20Sopenharmony_ci if (asoc->peer.primary_path == peer) 5078c2ecf20Sopenharmony_ci sctp_assoc_set_primary(asoc, transport); 5088c2ecf20Sopenharmony_ci if (asoc->peer.active_path == peer) 5098c2ecf20Sopenharmony_ci asoc->peer.active_path = transport; 5108c2ecf20Sopenharmony_ci if (asoc->peer.retran_path == peer) 5118c2ecf20Sopenharmony_ci asoc->peer.retran_path = transport; 5128c2ecf20Sopenharmony_ci if (asoc->peer.last_data_from == peer) 5138c2ecf20Sopenharmony_ci asoc->peer.last_data_from = transport; 5148c2ecf20Sopenharmony_ci 5158c2ecf20Sopenharmony_ci if (asoc->strreset_chunk && 5168c2ecf20Sopenharmony_ci asoc->strreset_chunk->transport == peer) { 5178c2ecf20Sopenharmony_ci asoc->strreset_chunk->transport = transport; 5188c2ecf20Sopenharmony_ci sctp_transport_reset_reconf_timer(transport); 5198c2ecf20Sopenharmony_ci } 5208c2ecf20Sopenharmony_ci 5218c2ecf20Sopenharmony_ci /* If we remove the transport an INIT was last sent to, set it to 5228c2ecf20Sopenharmony_ci * NULL. Combined with the update of the retran path above, this 5238c2ecf20Sopenharmony_ci * will cause the next INIT to be sent to the next available 5248c2ecf20Sopenharmony_ci * transport, maintaining the cycle. 5258c2ecf20Sopenharmony_ci */ 5268c2ecf20Sopenharmony_ci if (asoc->init_last_sent_to == peer) 5278c2ecf20Sopenharmony_ci asoc->init_last_sent_to = NULL; 5288c2ecf20Sopenharmony_ci 5298c2ecf20Sopenharmony_ci /* If we remove the transport an SHUTDOWN was last sent to, set it 5308c2ecf20Sopenharmony_ci * to NULL. Combined with the update of the retran path above, this 5318c2ecf20Sopenharmony_ci * will cause the next SHUTDOWN to be sent to the next available 5328c2ecf20Sopenharmony_ci * transport, maintaining the cycle. 5338c2ecf20Sopenharmony_ci */ 5348c2ecf20Sopenharmony_ci if (asoc->shutdown_last_sent_to == peer) 5358c2ecf20Sopenharmony_ci asoc->shutdown_last_sent_to = NULL; 5368c2ecf20Sopenharmony_ci 5378c2ecf20Sopenharmony_ci /* If we remove the transport an ASCONF was last sent to, set it to 5388c2ecf20Sopenharmony_ci * NULL. 5398c2ecf20Sopenharmony_ci */ 5408c2ecf20Sopenharmony_ci if (asoc->addip_last_asconf && 5418c2ecf20Sopenharmony_ci asoc->addip_last_asconf->transport == peer) 5428c2ecf20Sopenharmony_ci asoc->addip_last_asconf->transport = NULL; 5438c2ecf20Sopenharmony_ci 5448c2ecf20Sopenharmony_ci /* If we have something on the transmitted list, we have to 5458c2ecf20Sopenharmony_ci * save it off. The best place is the active path. 5468c2ecf20Sopenharmony_ci */ 5478c2ecf20Sopenharmony_ci if (!list_empty(&peer->transmitted)) { 5488c2ecf20Sopenharmony_ci struct sctp_transport *active = asoc->peer.active_path; 5498c2ecf20Sopenharmony_ci 5508c2ecf20Sopenharmony_ci /* Reset the transport of each chunk on this list */ 5518c2ecf20Sopenharmony_ci list_for_each_entry(ch, &peer->transmitted, 5528c2ecf20Sopenharmony_ci transmitted_list) { 5538c2ecf20Sopenharmony_ci ch->transport = NULL; 5548c2ecf20Sopenharmony_ci ch->rtt_in_progress = 0; 5558c2ecf20Sopenharmony_ci } 5568c2ecf20Sopenharmony_ci 5578c2ecf20Sopenharmony_ci list_splice_tail_init(&peer->transmitted, 5588c2ecf20Sopenharmony_ci &active->transmitted); 5598c2ecf20Sopenharmony_ci 5608c2ecf20Sopenharmony_ci /* Start a T3 timer here in case it wasn't running so 5618c2ecf20Sopenharmony_ci * that these migrated packets have a chance to get 5628c2ecf20Sopenharmony_ci * retransmitted. 5638c2ecf20Sopenharmony_ci */ 5648c2ecf20Sopenharmony_ci if (!timer_pending(&active->T3_rtx_timer)) 5658c2ecf20Sopenharmony_ci if (!mod_timer(&active->T3_rtx_timer, 5668c2ecf20Sopenharmony_ci jiffies + active->rto)) 5678c2ecf20Sopenharmony_ci sctp_transport_hold(active); 5688c2ecf20Sopenharmony_ci } 5698c2ecf20Sopenharmony_ci 5708c2ecf20Sopenharmony_ci list_for_each_entry(ch, &asoc->outqueue.out_chunk_list, list) 5718c2ecf20Sopenharmony_ci if (ch->transport == peer) 5728c2ecf20Sopenharmony_ci ch->transport = NULL; 5738c2ecf20Sopenharmony_ci 5748c2ecf20Sopenharmony_ci asoc->peer.transport_count--; 5758c2ecf20Sopenharmony_ci 5768c2ecf20Sopenharmony_ci sctp_ulpevent_notify_peer_addr_change(peer, SCTP_ADDR_REMOVED, 0); 5778c2ecf20Sopenharmony_ci sctp_transport_free(peer); 5788c2ecf20Sopenharmony_ci} 5798c2ecf20Sopenharmony_ci 5808c2ecf20Sopenharmony_ci/* Add a transport address to an association. */ 5818c2ecf20Sopenharmony_cistruct sctp_transport *sctp_assoc_add_peer(struct sctp_association *asoc, 5828c2ecf20Sopenharmony_ci const union sctp_addr *addr, 5838c2ecf20Sopenharmony_ci const gfp_t gfp, 5848c2ecf20Sopenharmony_ci const int peer_state) 5858c2ecf20Sopenharmony_ci{ 5868c2ecf20Sopenharmony_ci struct sctp_transport *peer; 5878c2ecf20Sopenharmony_ci struct sctp_sock *sp; 5888c2ecf20Sopenharmony_ci unsigned short port; 5898c2ecf20Sopenharmony_ci 5908c2ecf20Sopenharmony_ci sp = sctp_sk(asoc->base.sk); 5918c2ecf20Sopenharmony_ci 5928c2ecf20Sopenharmony_ci /* AF_INET and AF_INET6 share common port field. */ 5938c2ecf20Sopenharmony_ci port = ntohs(addr->v4.sin_port); 5948c2ecf20Sopenharmony_ci 5958c2ecf20Sopenharmony_ci pr_debug("%s: association:%p addr:%pISpc state:%d\n", __func__, 5968c2ecf20Sopenharmony_ci asoc, &addr->sa, peer_state); 5978c2ecf20Sopenharmony_ci 5988c2ecf20Sopenharmony_ci /* Set the port if it has not been set yet. */ 5998c2ecf20Sopenharmony_ci if (0 == asoc->peer.port) 6008c2ecf20Sopenharmony_ci asoc->peer.port = port; 6018c2ecf20Sopenharmony_ci 6028c2ecf20Sopenharmony_ci /* Check to see if this is a duplicate. */ 6038c2ecf20Sopenharmony_ci peer = sctp_assoc_lookup_paddr(asoc, addr); 6048c2ecf20Sopenharmony_ci if (peer) { 6058c2ecf20Sopenharmony_ci /* An UNKNOWN state is only set on transports added by 6068c2ecf20Sopenharmony_ci * user in sctp_connectx() call. Such transports should be 6078c2ecf20Sopenharmony_ci * considered CONFIRMED per RFC 4960, Section 5.4. 6088c2ecf20Sopenharmony_ci */ 6098c2ecf20Sopenharmony_ci if (peer->state == SCTP_UNKNOWN) { 6108c2ecf20Sopenharmony_ci peer->state = SCTP_ACTIVE; 6118c2ecf20Sopenharmony_ci } 6128c2ecf20Sopenharmony_ci return peer; 6138c2ecf20Sopenharmony_ci } 6148c2ecf20Sopenharmony_ci 6158c2ecf20Sopenharmony_ci peer = sctp_transport_new(asoc->base.net, addr, gfp); 6168c2ecf20Sopenharmony_ci if (!peer) 6178c2ecf20Sopenharmony_ci return NULL; 6188c2ecf20Sopenharmony_ci 6198c2ecf20Sopenharmony_ci sctp_transport_set_owner(peer, asoc); 6208c2ecf20Sopenharmony_ci 6218c2ecf20Sopenharmony_ci /* Initialize the peer's heartbeat interval based on the 6228c2ecf20Sopenharmony_ci * association configured value. 6238c2ecf20Sopenharmony_ci */ 6248c2ecf20Sopenharmony_ci peer->hbinterval = asoc->hbinterval; 6258c2ecf20Sopenharmony_ci 6268c2ecf20Sopenharmony_ci /* Set the path max_retrans. */ 6278c2ecf20Sopenharmony_ci peer->pathmaxrxt = asoc->pathmaxrxt; 6288c2ecf20Sopenharmony_ci 6298c2ecf20Sopenharmony_ci /* And the partial failure retrans threshold */ 6308c2ecf20Sopenharmony_ci peer->pf_retrans = asoc->pf_retrans; 6318c2ecf20Sopenharmony_ci /* And the primary path switchover retrans threshold */ 6328c2ecf20Sopenharmony_ci peer->ps_retrans = asoc->ps_retrans; 6338c2ecf20Sopenharmony_ci 6348c2ecf20Sopenharmony_ci /* Initialize the peer's SACK delay timeout based on the 6358c2ecf20Sopenharmony_ci * association configured value. 6368c2ecf20Sopenharmony_ci */ 6378c2ecf20Sopenharmony_ci peer->sackdelay = asoc->sackdelay; 6388c2ecf20Sopenharmony_ci peer->sackfreq = asoc->sackfreq; 6398c2ecf20Sopenharmony_ci 6408c2ecf20Sopenharmony_ci if (addr->sa.sa_family == AF_INET6) { 6418c2ecf20Sopenharmony_ci __be32 info = addr->v6.sin6_flowinfo; 6428c2ecf20Sopenharmony_ci 6438c2ecf20Sopenharmony_ci if (info) { 6448c2ecf20Sopenharmony_ci peer->flowlabel = ntohl(info & IPV6_FLOWLABEL_MASK); 6458c2ecf20Sopenharmony_ci peer->flowlabel |= SCTP_FLOWLABEL_SET_MASK; 6468c2ecf20Sopenharmony_ci } else { 6478c2ecf20Sopenharmony_ci peer->flowlabel = asoc->flowlabel; 6488c2ecf20Sopenharmony_ci } 6498c2ecf20Sopenharmony_ci } 6508c2ecf20Sopenharmony_ci peer->dscp = asoc->dscp; 6518c2ecf20Sopenharmony_ci 6528c2ecf20Sopenharmony_ci /* Enable/disable heartbeat, SACK delay, and path MTU discovery 6538c2ecf20Sopenharmony_ci * based on association setting. 6548c2ecf20Sopenharmony_ci */ 6558c2ecf20Sopenharmony_ci peer->param_flags = asoc->param_flags; 6568c2ecf20Sopenharmony_ci 6578c2ecf20Sopenharmony_ci /* Initialize the pmtu of the transport. */ 6588c2ecf20Sopenharmony_ci sctp_transport_route(peer, NULL, sp); 6598c2ecf20Sopenharmony_ci 6608c2ecf20Sopenharmony_ci /* If this is the first transport addr on this association, 6618c2ecf20Sopenharmony_ci * initialize the association PMTU to the peer's PMTU. 6628c2ecf20Sopenharmony_ci * If not and the current association PMTU is higher than the new 6638c2ecf20Sopenharmony_ci * peer's PMTU, reset the association PMTU to the new peer's PMTU. 6648c2ecf20Sopenharmony_ci */ 6658c2ecf20Sopenharmony_ci sctp_assoc_set_pmtu(asoc, asoc->pathmtu ? 6668c2ecf20Sopenharmony_ci min_t(int, peer->pathmtu, asoc->pathmtu) : 6678c2ecf20Sopenharmony_ci peer->pathmtu); 6688c2ecf20Sopenharmony_ci 6698c2ecf20Sopenharmony_ci peer->pmtu_pending = 0; 6708c2ecf20Sopenharmony_ci 6718c2ecf20Sopenharmony_ci /* The asoc->peer.port might not be meaningful yet, but 6728c2ecf20Sopenharmony_ci * initialize the packet structure anyway. 6738c2ecf20Sopenharmony_ci */ 6748c2ecf20Sopenharmony_ci sctp_packet_init(&peer->packet, peer, asoc->base.bind_addr.port, 6758c2ecf20Sopenharmony_ci asoc->peer.port); 6768c2ecf20Sopenharmony_ci 6778c2ecf20Sopenharmony_ci /* 7.2.1 Slow-Start 6788c2ecf20Sopenharmony_ci * 6798c2ecf20Sopenharmony_ci * o The initial cwnd before DATA transmission or after a sufficiently 6808c2ecf20Sopenharmony_ci * long idle period MUST be set to 6818c2ecf20Sopenharmony_ci * min(4*MTU, max(2*MTU, 4380 bytes)) 6828c2ecf20Sopenharmony_ci * 6838c2ecf20Sopenharmony_ci * o The initial value of ssthresh MAY be arbitrarily high 6848c2ecf20Sopenharmony_ci * (for example, implementations MAY use the size of the 6858c2ecf20Sopenharmony_ci * receiver advertised window). 6868c2ecf20Sopenharmony_ci */ 6878c2ecf20Sopenharmony_ci peer->cwnd = min(4*asoc->pathmtu, max_t(__u32, 2*asoc->pathmtu, 4380)); 6888c2ecf20Sopenharmony_ci 6898c2ecf20Sopenharmony_ci /* At this point, we may not have the receiver's advertised window, 6908c2ecf20Sopenharmony_ci * so initialize ssthresh to the default value and it will be set 6918c2ecf20Sopenharmony_ci * later when we process the INIT. 6928c2ecf20Sopenharmony_ci */ 6938c2ecf20Sopenharmony_ci peer->ssthresh = SCTP_DEFAULT_MAXWINDOW; 6948c2ecf20Sopenharmony_ci 6958c2ecf20Sopenharmony_ci peer->partial_bytes_acked = 0; 6968c2ecf20Sopenharmony_ci peer->flight_size = 0; 6978c2ecf20Sopenharmony_ci peer->burst_limited = 0; 6988c2ecf20Sopenharmony_ci 6998c2ecf20Sopenharmony_ci /* Set the transport's RTO.initial value */ 7008c2ecf20Sopenharmony_ci peer->rto = asoc->rto_initial; 7018c2ecf20Sopenharmony_ci sctp_max_rto(asoc, peer); 7028c2ecf20Sopenharmony_ci 7038c2ecf20Sopenharmony_ci /* Set the peer's active state. */ 7048c2ecf20Sopenharmony_ci peer->state = peer_state; 7058c2ecf20Sopenharmony_ci 7068c2ecf20Sopenharmony_ci /* Add this peer into the transport hashtable */ 7078c2ecf20Sopenharmony_ci if (sctp_hash_transport(peer)) { 7088c2ecf20Sopenharmony_ci sctp_transport_free(peer); 7098c2ecf20Sopenharmony_ci return NULL; 7108c2ecf20Sopenharmony_ci } 7118c2ecf20Sopenharmony_ci 7128c2ecf20Sopenharmony_ci /* Attach the remote transport to our asoc. */ 7138c2ecf20Sopenharmony_ci list_add_tail_rcu(&peer->transports, &asoc->peer.transport_addr_list); 7148c2ecf20Sopenharmony_ci asoc->peer.transport_count++; 7158c2ecf20Sopenharmony_ci 7168c2ecf20Sopenharmony_ci sctp_ulpevent_notify_peer_addr_change(peer, SCTP_ADDR_ADDED, 0); 7178c2ecf20Sopenharmony_ci 7188c2ecf20Sopenharmony_ci /* If we do not yet have a primary path, set one. */ 7198c2ecf20Sopenharmony_ci if (!asoc->peer.primary_path) { 7208c2ecf20Sopenharmony_ci sctp_assoc_set_primary(asoc, peer); 7218c2ecf20Sopenharmony_ci asoc->peer.retran_path = peer; 7228c2ecf20Sopenharmony_ci } 7238c2ecf20Sopenharmony_ci 7248c2ecf20Sopenharmony_ci if (asoc->peer.active_path == asoc->peer.retran_path && 7258c2ecf20Sopenharmony_ci peer->state != SCTP_UNCONFIRMED) { 7268c2ecf20Sopenharmony_ci asoc->peer.retran_path = peer; 7278c2ecf20Sopenharmony_ci } 7288c2ecf20Sopenharmony_ci 7298c2ecf20Sopenharmony_ci return peer; 7308c2ecf20Sopenharmony_ci} 7318c2ecf20Sopenharmony_ci 7328c2ecf20Sopenharmony_ci/* Delete a transport address from an association. */ 7338c2ecf20Sopenharmony_civoid sctp_assoc_del_peer(struct sctp_association *asoc, 7348c2ecf20Sopenharmony_ci const union sctp_addr *addr) 7358c2ecf20Sopenharmony_ci{ 7368c2ecf20Sopenharmony_ci struct list_head *pos; 7378c2ecf20Sopenharmony_ci struct list_head *temp; 7388c2ecf20Sopenharmony_ci struct sctp_transport *transport; 7398c2ecf20Sopenharmony_ci 7408c2ecf20Sopenharmony_ci list_for_each_safe(pos, temp, &asoc->peer.transport_addr_list) { 7418c2ecf20Sopenharmony_ci transport = list_entry(pos, struct sctp_transport, transports); 7428c2ecf20Sopenharmony_ci if (sctp_cmp_addr_exact(addr, &transport->ipaddr)) { 7438c2ecf20Sopenharmony_ci /* Do book keeping for removing the peer and free it. */ 7448c2ecf20Sopenharmony_ci sctp_assoc_rm_peer(asoc, transport); 7458c2ecf20Sopenharmony_ci break; 7468c2ecf20Sopenharmony_ci } 7478c2ecf20Sopenharmony_ci } 7488c2ecf20Sopenharmony_ci} 7498c2ecf20Sopenharmony_ci 7508c2ecf20Sopenharmony_ci/* Lookup a transport by address. */ 7518c2ecf20Sopenharmony_cistruct sctp_transport *sctp_assoc_lookup_paddr( 7528c2ecf20Sopenharmony_ci const struct sctp_association *asoc, 7538c2ecf20Sopenharmony_ci const union sctp_addr *address) 7548c2ecf20Sopenharmony_ci{ 7558c2ecf20Sopenharmony_ci struct sctp_transport *t; 7568c2ecf20Sopenharmony_ci 7578c2ecf20Sopenharmony_ci /* Cycle through all transports searching for a peer address. */ 7588c2ecf20Sopenharmony_ci 7598c2ecf20Sopenharmony_ci list_for_each_entry(t, &asoc->peer.transport_addr_list, 7608c2ecf20Sopenharmony_ci transports) { 7618c2ecf20Sopenharmony_ci if (sctp_cmp_addr_exact(address, &t->ipaddr)) 7628c2ecf20Sopenharmony_ci return t; 7638c2ecf20Sopenharmony_ci } 7648c2ecf20Sopenharmony_ci 7658c2ecf20Sopenharmony_ci return NULL; 7668c2ecf20Sopenharmony_ci} 7678c2ecf20Sopenharmony_ci 7688c2ecf20Sopenharmony_ci/* Remove all transports except a give one */ 7698c2ecf20Sopenharmony_civoid sctp_assoc_del_nonprimary_peers(struct sctp_association *asoc, 7708c2ecf20Sopenharmony_ci struct sctp_transport *primary) 7718c2ecf20Sopenharmony_ci{ 7728c2ecf20Sopenharmony_ci struct sctp_transport *temp; 7738c2ecf20Sopenharmony_ci struct sctp_transport *t; 7748c2ecf20Sopenharmony_ci 7758c2ecf20Sopenharmony_ci list_for_each_entry_safe(t, temp, &asoc->peer.transport_addr_list, 7768c2ecf20Sopenharmony_ci transports) { 7778c2ecf20Sopenharmony_ci /* if the current transport is not the primary one, delete it */ 7788c2ecf20Sopenharmony_ci if (t != primary) 7798c2ecf20Sopenharmony_ci sctp_assoc_rm_peer(asoc, t); 7808c2ecf20Sopenharmony_ci } 7818c2ecf20Sopenharmony_ci} 7828c2ecf20Sopenharmony_ci 7838c2ecf20Sopenharmony_ci/* Engage in transport control operations. 7848c2ecf20Sopenharmony_ci * Mark the transport up or down and send a notification to the user. 7858c2ecf20Sopenharmony_ci * Select and update the new active and retran paths. 7868c2ecf20Sopenharmony_ci */ 7878c2ecf20Sopenharmony_civoid sctp_assoc_control_transport(struct sctp_association *asoc, 7888c2ecf20Sopenharmony_ci struct sctp_transport *transport, 7898c2ecf20Sopenharmony_ci enum sctp_transport_cmd command, 7908c2ecf20Sopenharmony_ci sctp_sn_error_t error) 7918c2ecf20Sopenharmony_ci{ 7928c2ecf20Sopenharmony_ci int spc_state = SCTP_ADDR_AVAILABLE; 7938c2ecf20Sopenharmony_ci bool ulp_notify = true; 7948c2ecf20Sopenharmony_ci 7958c2ecf20Sopenharmony_ci /* Record the transition on the transport. */ 7968c2ecf20Sopenharmony_ci switch (command) { 7978c2ecf20Sopenharmony_ci case SCTP_TRANSPORT_UP: 7988c2ecf20Sopenharmony_ci /* If we are moving from UNCONFIRMED state due 7998c2ecf20Sopenharmony_ci * to heartbeat success, report the SCTP_ADDR_CONFIRMED 8008c2ecf20Sopenharmony_ci * state to the user, otherwise report SCTP_ADDR_AVAILABLE. 8018c2ecf20Sopenharmony_ci */ 8028c2ecf20Sopenharmony_ci if (transport->state == SCTP_PF && 8038c2ecf20Sopenharmony_ci asoc->pf_expose != SCTP_PF_EXPOSE_ENABLE) 8048c2ecf20Sopenharmony_ci ulp_notify = false; 8058c2ecf20Sopenharmony_ci else if (transport->state == SCTP_UNCONFIRMED && 8068c2ecf20Sopenharmony_ci error == SCTP_HEARTBEAT_SUCCESS) 8078c2ecf20Sopenharmony_ci spc_state = SCTP_ADDR_CONFIRMED; 8088c2ecf20Sopenharmony_ci 8098c2ecf20Sopenharmony_ci transport->state = SCTP_ACTIVE; 8108c2ecf20Sopenharmony_ci break; 8118c2ecf20Sopenharmony_ci 8128c2ecf20Sopenharmony_ci case SCTP_TRANSPORT_DOWN: 8138c2ecf20Sopenharmony_ci /* If the transport was never confirmed, do not transition it 8148c2ecf20Sopenharmony_ci * to inactive state. Also, release the cached route since 8158c2ecf20Sopenharmony_ci * there may be a better route next time. 8168c2ecf20Sopenharmony_ci */ 8178c2ecf20Sopenharmony_ci if (transport->state != SCTP_UNCONFIRMED) { 8188c2ecf20Sopenharmony_ci transport->state = SCTP_INACTIVE; 8198c2ecf20Sopenharmony_ci spc_state = SCTP_ADDR_UNREACHABLE; 8208c2ecf20Sopenharmony_ci } else { 8218c2ecf20Sopenharmony_ci sctp_transport_dst_release(transport); 8228c2ecf20Sopenharmony_ci ulp_notify = false; 8238c2ecf20Sopenharmony_ci } 8248c2ecf20Sopenharmony_ci break; 8258c2ecf20Sopenharmony_ci 8268c2ecf20Sopenharmony_ci case SCTP_TRANSPORT_PF: 8278c2ecf20Sopenharmony_ci transport->state = SCTP_PF; 8288c2ecf20Sopenharmony_ci if (asoc->pf_expose != SCTP_PF_EXPOSE_ENABLE) 8298c2ecf20Sopenharmony_ci ulp_notify = false; 8308c2ecf20Sopenharmony_ci else 8318c2ecf20Sopenharmony_ci spc_state = SCTP_ADDR_POTENTIALLY_FAILED; 8328c2ecf20Sopenharmony_ci break; 8338c2ecf20Sopenharmony_ci 8348c2ecf20Sopenharmony_ci default: 8358c2ecf20Sopenharmony_ci return; 8368c2ecf20Sopenharmony_ci } 8378c2ecf20Sopenharmony_ci 8388c2ecf20Sopenharmony_ci /* Generate and send a SCTP_PEER_ADDR_CHANGE notification 8398c2ecf20Sopenharmony_ci * to the user. 8408c2ecf20Sopenharmony_ci */ 8418c2ecf20Sopenharmony_ci if (ulp_notify) 8428c2ecf20Sopenharmony_ci sctp_ulpevent_notify_peer_addr_change(transport, 8438c2ecf20Sopenharmony_ci spc_state, error); 8448c2ecf20Sopenharmony_ci 8458c2ecf20Sopenharmony_ci /* Select new active and retran paths. */ 8468c2ecf20Sopenharmony_ci sctp_select_active_and_retran_path(asoc); 8478c2ecf20Sopenharmony_ci} 8488c2ecf20Sopenharmony_ci 8498c2ecf20Sopenharmony_ci/* Hold a reference to an association. */ 8508c2ecf20Sopenharmony_civoid sctp_association_hold(struct sctp_association *asoc) 8518c2ecf20Sopenharmony_ci{ 8528c2ecf20Sopenharmony_ci refcount_inc(&asoc->base.refcnt); 8538c2ecf20Sopenharmony_ci} 8548c2ecf20Sopenharmony_ci 8558c2ecf20Sopenharmony_ci/* Release a reference to an association and cleanup 8568c2ecf20Sopenharmony_ci * if there are no more references. 8578c2ecf20Sopenharmony_ci */ 8588c2ecf20Sopenharmony_civoid sctp_association_put(struct sctp_association *asoc) 8598c2ecf20Sopenharmony_ci{ 8608c2ecf20Sopenharmony_ci if (refcount_dec_and_test(&asoc->base.refcnt)) 8618c2ecf20Sopenharmony_ci sctp_association_destroy(asoc); 8628c2ecf20Sopenharmony_ci} 8638c2ecf20Sopenharmony_ci 8648c2ecf20Sopenharmony_ci/* Allocate the next TSN, Transmission Sequence Number, for the given 8658c2ecf20Sopenharmony_ci * association. 8668c2ecf20Sopenharmony_ci */ 8678c2ecf20Sopenharmony_ci__u32 sctp_association_get_next_tsn(struct sctp_association *asoc) 8688c2ecf20Sopenharmony_ci{ 8698c2ecf20Sopenharmony_ci /* From Section 1.6 Serial Number Arithmetic: 8708c2ecf20Sopenharmony_ci * Transmission Sequence Numbers wrap around when they reach 8718c2ecf20Sopenharmony_ci * 2**32 - 1. That is, the next TSN a DATA chunk MUST use 8728c2ecf20Sopenharmony_ci * after transmitting TSN = 2*32 - 1 is TSN = 0. 8738c2ecf20Sopenharmony_ci */ 8748c2ecf20Sopenharmony_ci __u32 retval = asoc->next_tsn; 8758c2ecf20Sopenharmony_ci asoc->next_tsn++; 8768c2ecf20Sopenharmony_ci asoc->unack_data++; 8778c2ecf20Sopenharmony_ci 8788c2ecf20Sopenharmony_ci return retval; 8798c2ecf20Sopenharmony_ci} 8808c2ecf20Sopenharmony_ci 8818c2ecf20Sopenharmony_ci/* Compare two addresses to see if they match. Wildcard addresses 8828c2ecf20Sopenharmony_ci * only match themselves. 8838c2ecf20Sopenharmony_ci */ 8848c2ecf20Sopenharmony_ciint sctp_cmp_addr_exact(const union sctp_addr *ss1, 8858c2ecf20Sopenharmony_ci const union sctp_addr *ss2) 8868c2ecf20Sopenharmony_ci{ 8878c2ecf20Sopenharmony_ci struct sctp_af *af; 8888c2ecf20Sopenharmony_ci 8898c2ecf20Sopenharmony_ci af = sctp_get_af_specific(ss1->sa.sa_family); 8908c2ecf20Sopenharmony_ci if (unlikely(!af)) 8918c2ecf20Sopenharmony_ci return 0; 8928c2ecf20Sopenharmony_ci 8938c2ecf20Sopenharmony_ci return af->cmp_addr(ss1, ss2); 8948c2ecf20Sopenharmony_ci} 8958c2ecf20Sopenharmony_ci 8968c2ecf20Sopenharmony_ci/* Return an ecne chunk to get prepended to a packet. 8978c2ecf20Sopenharmony_ci * Note: We are sly and return a shared, prealloced chunk. FIXME: 8988c2ecf20Sopenharmony_ci * No we don't, but we could/should. 8998c2ecf20Sopenharmony_ci */ 9008c2ecf20Sopenharmony_cistruct sctp_chunk *sctp_get_ecne_prepend(struct sctp_association *asoc) 9018c2ecf20Sopenharmony_ci{ 9028c2ecf20Sopenharmony_ci if (!asoc->need_ecne) 9038c2ecf20Sopenharmony_ci return NULL; 9048c2ecf20Sopenharmony_ci 9058c2ecf20Sopenharmony_ci /* Send ECNE if needed. 9068c2ecf20Sopenharmony_ci * Not being able to allocate a chunk here is not deadly. 9078c2ecf20Sopenharmony_ci */ 9088c2ecf20Sopenharmony_ci return sctp_make_ecne(asoc, asoc->last_ecne_tsn); 9098c2ecf20Sopenharmony_ci} 9108c2ecf20Sopenharmony_ci 9118c2ecf20Sopenharmony_ci/* 9128c2ecf20Sopenharmony_ci * Find which transport this TSN was sent on. 9138c2ecf20Sopenharmony_ci */ 9148c2ecf20Sopenharmony_cistruct sctp_transport *sctp_assoc_lookup_tsn(struct sctp_association *asoc, 9158c2ecf20Sopenharmony_ci __u32 tsn) 9168c2ecf20Sopenharmony_ci{ 9178c2ecf20Sopenharmony_ci struct sctp_transport *active; 9188c2ecf20Sopenharmony_ci struct sctp_transport *match; 9198c2ecf20Sopenharmony_ci struct sctp_transport *transport; 9208c2ecf20Sopenharmony_ci struct sctp_chunk *chunk; 9218c2ecf20Sopenharmony_ci __be32 key = htonl(tsn); 9228c2ecf20Sopenharmony_ci 9238c2ecf20Sopenharmony_ci match = NULL; 9248c2ecf20Sopenharmony_ci 9258c2ecf20Sopenharmony_ci /* 9268c2ecf20Sopenharmony_ci * FIXME: In general, find a more efficient data structure for 9278c2ecf20Sopenharmony_ci * searching. 9288c2ecf20Sopenharmony_ci */ 9298c2ecf20Sopenharmony_ci 9308c2ecf20Sopenharmony_ci /* 9318c2ecf20Sopenharmony_ci * The general strategy is to search each transport's transmitted 9328c2ecf20Sopenharmony_ci * list. Return which transport this TSN lives on. 9338c2ecf20Sopenharmony_ci * 9348c2ecf20Sopenharmony_ci * Let's be hopeful and check the active_path first. 9358c2ecf20Sopenharmony_ci * Another optimization would be to know if there is only one 9368c2ecf20Sopenharmony_ci * outbound path and not have to look for the TSN at all. 9378c2ecf20Sopenharmony_ci * 9388c2ecf20Sopenharmony_ci */ 9398c2ecf20Sopenharmony_ci 9408c2ecf20Sopenharmony_ci active = asoc->peer.active_path; 9418c2ecf20Sopenharmony_ci 9428c2ecf20Sopenharmony_ci list_for_each_entry(chunk, &active->transmitted, 9438c2ecf20Sopenharmony_ci transmitted_list) { 9448c2ecf20Sopenharmony_ci 9458c2ecf20Sopenharmony_ci if (key == chunk->subh.data_hdr->tsn) { 9468c2ecf20Sopenharmony_ci match = active; 9478c2ecf20Sopenharmony_ci goto out; 9488c2ecf20Sopenharmony_ci } 9498c2ecf20Sopenharmony_ci } 9508c2ecf20Sopenharmony_ci 9518c2ecf20Sopenharmony_ci /* If not found, go search all the other transports. */ 9528c2ecf20Sopenharmony_ci list_for_each_entry(transport, &asoc->peer.transport_addr_list, 9538c2ecf20Sopenharmony_ci transports) { 9548c2ecf20Sopenharmony_ci 9558c2ecf20Sopenharmony_ci if (transport == active) 9568c2ecf20Sopenharmony_ci continue; 9578c2ecf20Sopenharmony_ci list_for_each_entry(chunk, &transport->transmitted, 9588c2ecf20Sopenharmony_ci transmitted_list) { 9598c2ecf20Sopenharmony_ci if (key == chunk->subh.data_hdr->tsn) { 9608c2ecf20Sopenharmony_ci match = transport; 9618c2ecf20Sopenharmony_ci goto out; 9628c2ecf20Sopenharmony_ci } 9638c2ecf20Sopenharmony_ci } 9648c2ecf20Sopenharmony_ci } 9658c2ecf20Sopenharmony_ciout: 9668c2ecf20Sopenharmony_ci return match; 9678c2ecf20Sopenharmony_ci} 9688c2ecf20Sopenharmony_ci 9698c2ecf20Sopenharmony_ci/* Do delayed input processing. This is scheduled by sctp_rcv(). */ 9708c2ecf20Sopenharmony_cistatic void sctp_assoc_bh_rcv(struct work_struct *work) 9718c2ecf20Sopenharmony_ci{ 9728c2ecf20Sopenharmony_ci struct sctp_association *asoc = 9738c2ecf20Sopenharmony_ci container_of(work, struct sctp_association, 9748c2ecf20Sopenharmony_ci base.inqueue.immediate); 9758c2ecf20Sopenharmony_ci struct net *net = asoc->base.net; 9768c2ecf20Sopenharmony_ci union sctp_subtype subtype; 9778c2ecf20Sopenharmony_ci struct sctp_endpoint *ep; 9788c2ecf20Sopenharmony_ci struct sctp_chunk *chunk; 9798c2ecf20Sopenharmony_ci struct sctp_inq *inqueue; 9808c2ecf20Sopenharmony_ci int first_time = 1; /* is this the first time through the loop */ 9818c2ecf20Sopenharmony_ci int error = 0; 9828c2ecf20Sopenharmony_ci int state; 9838c2ecf20Sopenharmony_ci 9848c2ecf20Sopenharmony_ci /* The association should be held so we should be safe. */ 9858c2ecf20Sopenharmony_ci ep = asoc->ep; 9868c2ecf20Sopenharmony_ci 9878c2ecf20Sopenharmony_ci inqueue = &asoc->base.inqueue; 9888c2ecf20Sopenharmony_ci sctp_association_hold(asoc); 9898c2ecf20Sopenharmony_ci while (NULL != (chunk = sctp_inq_pop(inqueue))) { 9908c2ecf20Sopenharmony_ci state = asoc->state; 9918c2ecf20Sopenharmony_ci subtype = SCTP_ST_CHUNK(chunk->chunk_hdr->type); 9928c2ecf20Sopenharmony_ci 9938c2ecf20Sopenharmony_ci /* If the first chunk in the packet is AUTH, do special 9948c2ecf20Sopenharmony_ci * processing specified in Section 6.3 of SCTP-AUTH spec 9958c2ecf20Sopenharmony_ci */ 9968c2ecf20Sopenharmony_ci if (first_time && subtype.chunk == SCTP_CID_AUTH) { 9978c2ecf20Sopenharmony_ci struct sctp_chunkhdr *next_hdr; 9988c2ecf20Sopenharmony_ci 9998c2ecf20Sopenharmony_ci next_hdr = sctp_inq_peek(inqueue); 10008c2ecf20Sopenharmony_ci if (!next_hdr) 10018c2ecf20Sopenharmony_ci goto normal; 10028c2ecf20Sopenharmony_ci 10038c2ecf20Sopenharmony_ci /* If the next chunk is COOKIE-ECHO, skip the AUTH 10048c2ecf20Sopenharmony_ci * chunk while saving a pointer to it so we can do 10058c2ecf20Sopenharmony_ci * Authentication later (during cookie-echo 10068c2ecf20Sopenharmony_ci * processing). 10078c2ecf20Sopenharmony_ci */ 10088c2ecf20Sopenharmony_ci if (next_hdr->type == SCTP_CID_COOKIE_ECHO) { 10098c2ecf20Sopenharmony_ci chunk->auth_chunk = skb_clone(chunk->skb, 10108c2ecf20Sopenharmony_ci GFP_ATOMIC); 10118c2ecf20Sopenharmony_ci chunk->auth = 1; 10128c2ecf20Sopenharmony_ci continue; 10138c2ecf20Sopenharmony_ci } 10148c2ecf20Sopenharmony_ci } 10158c2ecf20Sopenharmony_ci 10168c2ecf20Sopenharmony_cinormal: 10178c2ecf20Sopenharmony_ci /* SCTP-AUTH, Section 6.3: 10188c2ecf20Sopenharmony_ci * The receiver has a list of chunk types which it expects 10198c2ecf20Sopenharmony_ci * to be received only after an AUTH-chunk. This list has 10208c2ecf20Sopenharmony_ci * been sent to the peer during the association setup. It 10218c2ecf20Sopenharmony_ci * MUST silently discard these chunks if they are not placed 10228c2ecf20Sopenharmony_ci * after an AUTH chunk in the packet. 10238c2ecf20Sopenharmony_ci */ 10248c2ecf20Sopenharmony_ci if (sctp_auth_recv_cid(subtype.chunk, asoc) && !chunk->auth) 10258c2ecf20Sopenharmony_ci continue; 10268c2ecf20Sopenharmony_ci 10278c2ecf20Sopenharmony_ci /* Remember where the last DATA chunk came from so we 10288c2ecf20Sopenharmony_ci * know where to send the SACK. 10298c2ecf20Sopenharmony_ci */ 10308c2ecf20Sopenharmony_ci if (sctp_chunk_is_data(chunk)) 10318c2ecf20Sopenharmony_ci asoc->peer.last_data_from = chunk->transport; 10328c2ecf20Sopenharmony_ci else { 10338c2ecf20Sopenharmony_ci SCTP_INC_STATS(net, SCTP_MIB_INCTRLCHUNKS); 10348c2ecf20Sopenharmony_ci asoc->stats.ictrlchunks++; 10358c2ecf20Sopenharmony_ci if (chunk->chunk_hdr->type == SCTP_CID_SACK) 10368c2ecf20Sopenharmony_ci asoc->stats.isacks++; 10378c2ecf20Sopenharmony_ci } 10388c2ecf20Sopenharmony_ci 10398c2ecf20Sopenharmony_ci if (chunk->transport) 10408c2ecf20Sopenharmony_ci chunk->transport->last_time_heard = ktime_get(); 10418c2ecf20Sopenharmony_ci 10428c2ecf20Sopenharmony_ci /* Run through the state machine. */ 10438c2ecf20Sopenharmony_ci error = sctp_do_sm(net, SCTP_EVENT_T_CHUNK, subtype, 10448c2ecf20Sopenharmony_ci state, ep, asoc, chunk, GFP_ATOMIC); 10458c2ecf20Sopenharmony_ci 10468c2ecf20Sopenharmony_ci /* Check to see if the association is freed in response to 10478c2ecf20Sopenharmony_ci * the incoming chunk. If so, get out of the while loop. 10488c2ecf20Sopenharmony_ci */ 10498c2ecf20Sopenharmony_ci if (asoc->base.dead) 10508c2ecf20Sopenharmony_ci break; 10518c2ecf20Sopenharmony_ci 10528c2ecf20Sopenharmony_ci /* If there is an error on chunk, discard this packet. */ 10538c2ecf20Sopenharmony_ci if (error && chunk) 10548c2ecf20Sopenharmony_ci chunk->pdiscard = 1; 10558c2ecf20Sopenharmony_ci 10568c2ecf20Sopenharmony_ci if (first_time) 10578c2ecf20Sopenharmony_ci first_time = 0; 10588c2ecf20Sopenharmony_ci } 10598c2ecf20Sopenharmony_ci sctp_association_put(asoc); 10608c2ecf20Sopenharmony_ci} 10618c2ecf20Sopenharmony_ci 10628c2ecf20Sopenharmony_ci/* This routine moves an association from its old sk to a new sk. */ 10638c2ecf20Sopenharmony_civoid sctp_assoc_migrate(struct sctp_association *assoc, struct sock *newsk) 10648c2ecf20Sopenharmony_ci{ 10658c2ecf20Sopenharmony_ci struct sctp_sock *newsp = sctp_sk(newsk); 10668c2ecf20Sopenharmony_ci struct sock *oldsk = assoc->base.sk; 10678c2ecf20Sopenharmony_ci 10688c2ecf20Sopenharmony_ci /* Delete the association from the old endpoint's list of 10698c2ecf20Sopenharmony_ci * associations. 10708c2ecf20Sopenharmony_ci */ 10718c2ecf20Sopenharmony_ci list_del_init(&assoc->asocs); 10728c2ecf20Sopenharmony_ci 10738c2ecf20Sopenharmony_ci /* Decrement the backlog value for a TCP-style socket. */ 10748c2ecf20Sopenharmony_ci if (sctp_style(oldsk, TCP)) 10758c2ecf20Sopenharmony_ci sk_acceptq_removed(oldsk); 10768c2ecf20Sopenharmony_ci 10778c2ecf20Sopenharmony_ci /* Release references to the old endpoint and the sock. */ 10788c2ecf20Sopenharmony_ci sctp_endpoint_put(assoc->ep); 10798c2ecf20Sopenharmony_ci sock_put(assoc->base.sk); 10808c2ecf20Sopenharmony_ci 10818c2ecf20Sopenharmony_ci /* Get a reference to the new endpoint. */ 10828c2ecf20Sopenharmony_ci assoc->ep = newsp->ep; 10838c2ecf20Sopenharmony_ci sctp_endpoint_hold(assoc->ep); 10848c2ecf20Sopenharmony_ci 10858c2ecf20Sopenharmony_ci /* Get a reference to the new sock. */ 10868c2ecf20Sopenharmony_ci assoc->base.sk = newsk; 10878c2ecf20Sopenharmony_ci sock_hold(assoc->base.sk); 10888c2ecf20Sopenharmony_ci 10898c2ecf20Sopenharmony_ci /* Add the association to the new endpoint's list of associations. */ 10908c2ecf20Sopenharmony_ci sctp_endpoint_add_asoc(newsp->ep, assoc); 10918c2ecf20Sopenharmony_ci} 10928c2ecf20Sopenharmony_ci 10938c2ecf20Sopenharmony_ci/* Update an association (possibly from unexpected COOKIE-ECHO processing). */ 10948c2ecf20Sopenharmony_ciint sctp_assoc_update(struct sctp_association *asoc, 10958c2ecf20Sopenharmony_ci struct sctp_association *new) 10968c2ecf20Sopenharmony_ci{ 10978c2ecf20Sopenharmony_ci struct sctp_transport *trans; 10988c2ecf20Sopenharmony_ci struct list_head *pos, *temp; 10998c2ecf20Sopenharmony_ci 11008c2ecf20Sopenharmony_ci /* Copy in new parameters of peer. */ 11018c2ecf20Sopenharmony_ci asoc->c = new->c; 11028c2ecf20Sopenharmony_ci asoc->peer.rwnd = new->peer.rwnd; 11038c2ecf20Sopenharmony_ci asoc->peer.sack_needed = new->peer.sack_needed; 11048c2ecf20Sopenharmony_ci asoc->peer.auth_capable = new->peer.auth_capable; 11058c2ecf20Sopenharmony_ci asoc->peer.i = new->peer.i; 11068c2ecf20Sopenharmony_ci 11078c2ecf20Sopenharmony_ci if (!sctp_tsnmap_init(&asoc->peer.tsn_map, SCTP_TSN_MAP_INITIAL, 11088c2ecf20Sopenharmony_ci asoc->peer.i.initial_tsn, GFP_ATOMIC)) 11098c2ecf20Sopenharmony_ci return -ENOMEM; 11108c2ecf20Sopenharmony_ci 11118c2ecf20Sopenharmony_ci /* Remove any peer addresses not present in the new association. */ 11128c2ecf20Sopenharmony_ci list_for_each_safe(pos, temp, &asoc->peer.transport_addr_list) { 11138c2ecf20Sopenharmony_ci trans = list_entry(pos, struct sctp_transport, transports); 11148c2ecf20Sopenharmony_ci if (!sctp_assoc_lookup_paddr(new, &trans->ipaddr)) { 11158c2ecf20Sopenharmony_ci sctp_assoc_rm_peer(asoc, trans); 11168c2ecf20Sopenharmony_ci continue; 11178c2ecf20Sopenharmony_ci } 11188c2ecf20Sopenharmony_ci 11198c2ecf20Sopenharmony_ci if (asoc->state >= SCTP_STATE_ESTABLISHED) 11208c2ecf20Sopenharmony_ci sctp_transport_reset(trans); 11218c2ecf20Sopenharmony_ci } 11228c2ecf20Sopenharmony_ci 11238c2ecf20Sopenharmony_ci /* If the case is A (association restart), use 11248c2ecf20Sopenharmony_ci * initial_tsn as next_tsn. If the case is B, use 11258c2ecf20Sopenharmony_ci * current next_tsn in case data sent to peer 11268c2ecf20Sopenharmony_ci * has been discarded and needs retransmission. 11278c2ecf20Sopenharmony_ci */ 11288c2ecf20Sopenharmony_ci if (asoc->state >= SCTP_STATE_ESTABLISHED) { 11298c2ecf20Sopenharmony_ci asoc->next_tsn = new->next_tsn; 11308c2ecf20Sopenharmony_ci asoc->ctsn_ack_point = new->ctsn_ack_point; 11318c2ecf20Sopenharmony_ci asoc->adv_peer_ack_point = new->adv_peer_ack_point; 11328c2ecf20Sopenharmony_ci 11338c2ecf20Sopenharmony_ci /* Reinitialize SSN for both local streams 11348c2ecf20Sopenharmony_ci * and peer's streams. 11358c2ecf20Sopenharmony_ci */ 11368c2ecf20Sopenharmony_ci sctp_stream_clear(&asoc->stream); 11378c2ecf20Sopenharmony_ci 11388c2ecf20Sopenharmony_ci /* Flush the ULP reassembly and ordered queue. 11398c2ecf20Sopenharmony_ci * Any data there will now be stale and will 11408c2ecf20Sopenharmony_ci * cause problems. 11418c2ecf20Sopenharmony_ci */ 11428c2ecf20Sopenharmony_ci sctp_ulpq_flush(&asoc->ulpq); 11438c2ecf20Sopenharmony_ci 11448c2ecf20Sopenharmony_ci /* reset the overall association error count so 11458c2ecf20Sopenharmony_ci * that the restarted association doesn't get torn 11468c2ecf20Sopenharmony_ci * down on the next retransmission timer. 11478c2ecf20Sopenharmony_ci */ 11488c2ecf20Sopenharmony_ci asoc->overall_error_count = 0; 11498c2ecf20Sopenharmony_ci 11508c2ecf20Sopenharmony_ci } else { 11518c2ecf20Sopenharmony_ci /* Add any peer addresses from the new association. */ 11528c2ecf20Sopenharmony_ci list_for_each_entry(trans, &new->peer.transport_addr_list, 11538c2ecf20Sopenharmony_ci transports) 11548c2ecf20Sopenharmony_ci if (!sctp_assoc_add_peer(asoc, &trans->ipaddr, 11558c2ecf20Sopenharmony_ci GFP_ATOMIC, trans->state)) 11568c2ecf20Sopenharmony_ci return -ENOMEM; 11578c2ecf20Sopenharmony_ci 11588c2ecf20Sopenharmony_ci asoc->ctsn_ack_point = asoc->next_tsn - 1; 11598c2ecf20Sopenharmony_ci asoc->adv_peer_ack_point = asoc->ctsn_ack_point; 11608c2ecf20Sopenharmony_ci 11618c2ecf20Sopenharmony_ci if (sctp_state(asoc, COOKIE_WAIT)) 11628c2ecf20Sopenharmony_ci sctp_stream_update(&asoc->stream, &new->stream); 11638c2ecf20Sopenharmony_ci 11648c2ecf20Sopenharmony_ci /* get a new assoc id if we don't have one yet. */ 11658c2ecf20Sopenharmony_ci if (sctp_assoc_set_id(asoc, GFP_ATOMIC)) 11668c2ecf20Sopenharmony_ci return -ENOMEM; 11678c2ecf20Sopenharmony_ci } 11688c2ecf20Sopenharmony_ci 11698c2ecf20Sopenharmony_ci /* SCTP-AUTH: Save the peer parameters from the new associations 11708c2ecf20Sopenharmony_ci * and also move the association shared keys over 11718c2ecf20Sopenharmony_ci */ 11728c2ecf20Sopenharmony_ci kfree(asoc->peer.peer_random); 11738c2ecf20Sopenharmony_ci asoc->peer.peer_random = new->peer.peer_random; 11748c2ecf20Sopenharmony_ci new->peer.peer_random = NULL; 11758c2ecf20Sopenharmony_ci 11768c2ecf20Sopenharmony_ci kfree(asoc->peer.peer_chunks); 11778c2ecf20Sopenharmony_ci asoc->peer.peer_chunks = new->peer.peer_chunks; 11788c2ecf20Sopenharmony_ci new->peer.peer_chunks = NULL; 11798c2ecf20Sopenharmony_ci 11808c2ecf20Sopenharmony_ci kfree(asoc->peer.peer_hmacs); 11818c2ecf20Sopenharmony_ci asoc->peer.peer_hmacs = new->peer.peer_hmacs; 11828c2ecf20Sopenharmony_ci new->peer.peer_hmacs = NULL; 11838c2ecf20Sopenharmony_ci 11848c2ecf20Sopenharmony_ci return sctp_auth_asoc_init_active_key(asoc, GFP_ATOMIC); 11858c2ecf20Sopenharmony_ci} 11868c2ecf20Sopenharmony_ci 11878c2ecf20Sopenharmony_ci/* Update the retran path for sending a retransmitted packet. 11888c2ecf20Sopenharmony_ci * See also RFC4960, 6.4. Multi-Homed SCTP Endpoints: 11898c2ecf20Sopenharmony_ci * 11908c2ecf20Sopenharmony_ci * When there is outbound data to send and the primary path 11918c2ecf20Sopenharmony_ci * becomes inactive (e.g., due to failures), or where the 11928c2ecf20Sopenharmony_ci * SCTP user explicitly requests to send data to an 11938c2ecf20Sopenharmony_ci * inactive destination transport address, before reporting 11948c2ecf20Sopenharmony_ci * an error to its ULP, the SCTP endpoint should try to send 11958c2ecf20Sopenharmony_ci * the data to an alternate active destination transport 11968c2ecf20Sopenharmony_ci * address if one exists. 11978c2ecf20Sopenharmony_ci * 11988c2ecf20Sopenharmony_ci * When retransmitting data that timed out, if the endpoint 11998c2ecf20Sopenharmony_ci * is multihomed, it should consider each source-destination 12008c2ecf20Sopenharmony_ci * address pair in its retransmission selection policy. 12018c2ecf20Sopenharmony_ci * When retransmitting timed-out data, the endpoint should 12028c2ecf20Sopenharmony_ci * attempt to pick the most divergent source-destination 12038c2ecf20Sopenharmony_ci * pair from the original source-destination pair to which 12048c2ecf20Sopenharmony_ci * the packet was transmitted. 12058c2ecf20Sopenharmony_ci * 12068c2ecf20Sopenharmony_ci * Note: Rules for picking the most divergent source-destination 12078c2ecf20Sopenharmony_ci * pair are an implementation decision and are not specified 12088c2ecf20Sopenharmony_ci * within this document. 12098c2ecf20Sopenharmony_ci * 12108c2ecf20Sopenharmony_ci * Our basic strategy is to round-robin transports in priorities 12118c2ecf20Sopenharmony_ci * according to sctp_trans_score() e.g., if no such 12128c2ecf20Sopenharmony_ci * transport with state SCTP_ACTIVE exists, round-robin through 12138c2ecf20Sopenharmony_ci * SCTP_UNKNOWN, etc. You get the picture. 12148c2ecf20Sopenharmony_ci */ 12158c2ecf20Sopenharmony_cistatic u8 sctp_trans_score(const struct sctp_transport *trans) 12168c2ecf20Sopenharmony_ci{ 12178c2ecf20Sopenharmony_ci switch (trans->state) { 12188c2ecf20Sopenharmony_ci case SCTP_ACTIVE: 12198c2ecf20Sopenharmony_ci return 3; /* best case */ 12208c2ecf20Sopenharmony_ci case SCTP_UNKNOWN: 12218c2ecf20Sopenharmony_ci return 2; 12228c2ecf20Sopenharmony_ci case SCTP_PF: 12238c2ecf20Sopenharmony_ci return 1; 12248c2ecf20Sopenharmony_ci default: /* case SCTP_INACTIVE */ 12258c2ecf20Sopenharmony_ci return 0; /* worst case */ 12268c2ecf20Sopenharmony_ci } 12278c2ecf20Sopenharmony_ci} 12288c2ecf20Sopenharmony_ci 12298c2ecf20Sopenharmony_cistatic struct sctp_transport *sctp_trans_elect_tie(struct sctp_transport *trans1, 12308c2ecf20Sopenharmony_ci struct sctp_transport *trans2) 12318c2ecf20Sopenharmony_ci{ 12328c2ecf20Sopenharmony_ci if (trans1->error_count > trans2->error_count) { 12338c2ecf20Sopenharmony_ci return trans2; 12348c2ecf20Sopenharmony_ci } else if (trans1->error_count == trans2->error_count && 12358c2ecf20Sopenharmony_ci ktime_after(trans2->last_time_heard, 12368c2ecf20Sopenharmony_ci trans1->last_time_heard)) { 12378c2ecf20Sopenharmony_ci return trans2; 12388c2ecf20Sopenharmony_ci } else { 12398c2ecf20Sopenharmony_ci return trans1; 12408c2ecf20Sopenharmony_ci } 12418c2ecf20Sopenharmony_ci} 12428c2ecf20Sopenharmony_ci 12438c2ecf20Sopenharmony_cistatic struct sctp_transport *sctp_trans_elect_best(struct sctp_transport *curr, 12448c2ecf20Sopenharmony_ci struct sctp_transport *best) 12458c2ecf20Sopenharmony_ci{ 12468c2ecf20Sopenharmony_ci u8 score_curr, score_best; 12478c2ecf20Sopenharmony_ci 12488c2ecf20Sopenharmony_ci if (best == NULL || curr == best) 12498c2ecf20Sopenharmony_ci return curr; 12508c2ecf20Sopenharmony_ci 12518c2ecf20Sopenharmony_ci score_curr = sctp_trans_score(curr); 12528c2ecf20Sopenharmony_ci score_best = sctp_trans_score(best); 12538c2ecf20Sopenharmony_ci 12548c2ecf20Sopenharmony_ci /* First, try a score-based selection if both transport states 12558c2ecf20Sopenharmony_ci * differ. If we're in a tie, lets try to make a more clever 12568c2ecf20Sopenharmony_ci * decision here based on error counts and last time heard. 12578c2ecf20Sopenharmony_ci */ 12588c2ecf20Sopenharmony_ci if (score_curr > score_best) 12598c2ecf20Sopenharmony_ci return curr; 12608c2ecf20Sopenharmony_ci else if (score_curr == score_best) 12618c2ecf20Sopenharmony_ci return sctp_trans_elect_tie(best, curr); 12628c2ecf20Sopenharmony_ci else 12638c2ecf20Sopenharmony_ci return best; 12648c2ecf20Sopenharmony_ci} 12658c2ecf20Sopenharmony_ci 12668c2ecf20Sopenharmony_civoid sctp_assoc_update_retran_path(struct sctp_association *asoc) 12678c2ecf20Sopenharmony_ci{ 12688c2ecf20Sopenharmony_ci struct sctp_transport *trans = asoc->peer.retran_path; 12698c2ecf20Sopenharmony_ci struct sctp_transport *trans_next = NULL; 12708c2ecf20Sopenharmony_ci 12718c2ecf20Sopenharmony_ci /* We're done as we only have the one and only path. */ 12728c2ecf20Sopenharmony_ci if (asoc->peer.transport_count == 1) 12738c2ecf20Sopenharmony_ci return; 12748c2ecf20Sopenharmony_ci /* If active_path and retran_path are the same and active, 12758c2ecf20Sopenharmony_ci * then this is the only active path. Use it. 12768c2ecf20Sopenharmony_ci */ 12778c2ecf20Sopenharmony_ci if (asoc->peer.active_path == asoc->peer.retran_path && 12788c2ecf20Sopenharmony_ci asoc->peer.active_path->state == SCTP_ACTIVE) 12798c2ecf20Sopenharmony_ci return; 12808c2ecf20Sopenharmony_ci 12818c2ecf20Sopenharmony_ci /* Iterate from retran_path's successor back to retran_path. */ 12828c2ecf20Sopenharmony_ci for (trans = list_next_entry(trans, transports); 1; 12838c2ecf20Sopenharmony_ci trans = list_next_entry(trans, transports)) { 12848c2ecf20Sopenharmony_ci /* Manually skip the head element. */ 12858c2ecf20Sopenharmony_ci if (&trans->transports == &asoc->peer.transport_addr_list) 12868c2ecf20Sopenharmony_ci continue; 12878c2ecf20Sopenharmony_ci if (trans->state == SCTP_UNCONFIRMED) 12888c2ecf20Sopenharmony_ci continue; 12898c2ecf20Sopenharmony_ci trans_next = sctp_trans_elect_best(trans, trans_next); 12908c2ecf20Sopenharmony_ci /* Active is good enough for immediate return. */ 12918c2ecf20Sopenharmony_ci if (trans_next->state == SCTP_ACTIVE) 12928c2ecf20Sopenharmony_ci break; 12938c2ecf20Sopenharmony_ci /* We've reached the end, time to update path. */ 12948c2ecf20Sopenharmony_ci if (trans == asoc->peer.retran_path) 12958c2ecf20Sopenharmony_ci break; 12968c2ecf20Sopenharmony_ci } 12978c2ecf20Sopenharmony_ci 12988c2ecf20Sopenharmony_ci asoc->peer.retran_path = trans_next; 12998c2ecf20Sopenharmony_ci 13008c2ecf20Sopenharmony_ci pr_debug("%s: association:%p updated new path to addr:%pISpc\n", 13018c2ecf20Sopenharmony_ci __func__, asoc, &asoc->peer.retran_path->ipaddr.sa); 13028c2ecf20Sopenharmony_ci} 13038c2ecf20Sopenharmony_ci 13048c2ecf20Sopenharmony_cistatic void sctp_select_active_and_retran_path(struct sctp_association *asoc) 13058c2ecf20Sopenharmony_ci{ 13068c2ecf20Sopenharmony_ci struct sctp_transport *trans, *trans_pri = NULL, *trans_sec = NULL; 13078c2ecf20Sopenharmony_ci struct sctp_transport *trans_pf = NULL; 13088c2ecf20Sopenharmony_ci 13098c2ecf20Sopenharmony_ci /* Look for the two most recently used active transports. */ 13108c2ecf20Sopenharmony_ci list_for_each_entry(trans, &asoc->peer.transport_addr_list, 13118c2ecf20Sopenharmony_ci transports) { 13128c2ecf20Sopenharmony_ci /* Skip uninteresting transports. */ 13138c2ecf20Sopenharmony_ci if (trans->state == SCTP_INACTIVE || 13148c2ecf20Sopenharmony_ci trans->state == SCTP_UNCONFIRMED) 13158c2ecf20Sopenharmony_ci continue; 13168c2ecf20Sopenharmony_ci /* Keep track of the best PF transport from our 13178c2ecf20Sopenharmony_ci * list in case we don't find an active one. 13188c2ecf20Sopenharmony_ci */ 13198c2ecf20Sopenharmony_ci if (trans->state == SCTP_PF) { 13208c2ecf20Sopenharmony_ci trans_pf = sctp_trans_elect_best(trans, trans_pf); 13218c2ecf20Sopenharmony_ci continue; 13228c2ecf20Sopenharmony_ci } 13238c2ecf20Sopenharmony_ci /* For active transports, pick the most recent ones. */ 13248c2ecf20Sopenharmony_ci if (trans_pri == NULL || 13258c2ecf20Sopenharmony_ci ktime_after(trans->last_time_heard, 13268c2ecf20Sopenharmony_ci trans_pri->last_time_heard)) { 13278c2ecf20Sopenharmony_ci trans_sec = trans_pri; 13288c2ecf20Sopenharmony_ci trans_pri = trans; 13298c2ecf20Sopenharmony_ci } else if (trans_sec == NULL || 13308c2ecf20Sopenharmony_ci ktime_after(trans->last_time_heard, 13318c2ecf20Sopenharmony_ci trans_sec->last_time_heard)) { 13328c2ecf20Sopenharmony_ci trans_sec = trans; 13338c2ecf20Sopenharmony_ci } 13348c2ecf20Sopenharmony_ci } 13358c2ecf20Sopenharmony_ci 13368c2ecf20Sopenharmony_ci /* RFC 2960 6.4 Multi-Homed SCTP Endpoints 13378c2ecf20Sopenharmony_ci * 13388c2ecf20Sopenharmony_ci * By default, an endpoint should always transmit to the primary 13398c2ecf20Sopenharmony_ci * path, unless the SCTP user explicitly specifies the 13408c2ecf20Sopenharmony_ci * destination transport address (and possibly source transport 13418c2ecf20Sopenharmony_ci * address) to use. [If the primary is active but not most recent, 13428c2ecf20Sopenharmony_ci * bump the most recently used transport.] 13438c2ecf20Sopenharmony_ci */ 13448c2ecf20Sopenharmony_ci if ((asoc->peer.primary_path->state == SCTP_ACTIVE || 13458c2ecf20Sopenharmony_ci asoc->peer.primary_path->state == SCTP_UNKNOWN) && 13468c2ecf20Sopenharmony_ci asoc->peer.primary_path != trans_pri) { 13478c2ecf20Sopenharmony_ci trans_sec = trans_pri; 13488c2ecf20Sopenharmony_ci trans_pri = asoc->peer.primary_path; 13498c2ecf20Sopenharmony_ci } 13508c2ecf20Sopenharmony_ci 13518c2ecf20Sopenharmony_ci /* We did not find anything useful for a possible retransmission 13528c2ecf20Sopenharmony_ci * path; either primary path that we found is the same as 13538c2ecf20Sopenharmony_ci * the current one, or we didn't generally find an active one. 13548c2ecf20Sopenharmony_ci */ 13558c2ecf20Sopenharmony_ci if (trans_sec == NULL) 13568c2ecf20Sopenharmony_ci trans_sec = trans_pri; 13578c2ecf20Sopenharmony_ci 13588c2ecf20Sopenharmony_ci /* If we failed to find a usable transport, just camp on the 13598c2ecf20Sopenharmony_ci * active or pick a PF iff it's the better choice. 13608c2ecf20Sopenharmony_ci */ 13618c2ecf20Sopenharmony_ci if (trans_pri == NULL) { 13628c2ecf20Sopenharmony_ci trans_pri = sctp_trans_elect_best(asoc->peer.active_path, trans_pf); 13638c2ecf20Sopenharmony_ci trans_sec = trans_pri; 13648c2ecf20Sopenharmony_ci } 13658c2ecf20Sopenharmony_ci 13668c2ecf20Sopenharmony_ci /* Set the active and retran transports. */ 13678c2ecf20Sopenharmony_ci asoc->peer.active_path = trans_pri; 13688c2ecf20Sopenharmony_ci asoc->peer.retran_path = trans_sec; 13698c2ecf20Sopenharmony_ci} 13708c2ecf20Sopenharmony_ci 13718c2ecf20Sopenharmony_cistruct sctp_transport * 13728c2ecf20Sopenharmony_cisctp_assoc_choose_alter_transport(struct sctp_association *asoc, 13738c2ecf20Sopenharmony_ci struct sctp_transport *last_sent_to) 13748c2ecf20Sopenharmony_ci{ 13758c2ecf20Sopenharmony_ci /* If this is the first time packet is sent, use the active path, 13768c2ecf20Sopenharmony_ci * else use the retran path. If the last packet was sent over the 13778c2ecf20Sopenharmony_ci * retran path, update the retran path and use it. 13788c2ecf20Sopenharmony_ci */ 13798c2ecf20Sopenharmony_ci if (last_sent_to == NULL) { 13808c2ecf20Sopenharmony_ci return asoc->peer.active_path; 13818c2ecf20Sopenharmony_ci } else { 13828c2ecf20Sopenharmony_ci if (last_sent_to == asoc->peer.retran_path) 13838c2ecf20Sopenharmony_ci sctp_assoc_update_retran_path(asoc); 13848c2ecf20Sopenharmony_ci 13858c2ecf20Sopenharmony_ci return asoc->peer.retran_path; 13868c2ecf20Sopenharmony_ci } 13878c2ecf20Sopenharmony_ci} 13888c2ecf20Sopenharmony_ci 13898c2ecf20Sopenharmony_civoid sctp_assoc_update_frag_point(struct sctp_association *asoc) 13908c2ecf20Sopenharmony_ci{ 13918c2ecf20Sopenharmony_ci int frag = sctp_mtu_payload(sctp_sk(asoc->base.sk), asoc->pathmtu, 13928c2ecf20Sopenharmony_ci sctp_datachk_len(&asoc->stream)); 13938c2ecf20Sopenharmony_ci 13948c2ecf20Sopenharmony_ci if (asoc->user_frag) 13958c2ecf20Sopenharmony_ci frag = min_t(int, frag, asoc->user_frag); 13968c2ecf20Sopenharmony_ci 13978c2ecf20Sopenharmony_ci frag = min_t(int, frag, SCTP_MAX_CHUNK_LEN - 13988c2ecf20Sopenharmony_ci sctp_datachk_len(&asoc->stream)); 13998c2ecf20Sopenharmony_ci 14008c2ecf20Sopenharmony_ci asoc->frag_point = SCTP_TRUNC4(frag); 14018c2ecf20Sopenharmony_ci} 14028c2ecf20Sopenharmony_ci 14038c2ecf20Sopenharmony_civoid sctp_assoc_set_pmtu(struct sctp_association *asoc, __u32 pmtu) 14048c2ecf20Sopenharmony_ci{ 14058c2ecf20Sopenharmony_ci if (asoc->pathmtu != pmtu) { 14068c2ecf20Sopenharmony_ci asoc->pathmtu = pmtu; 14078c2ecf20Sopenharmony_ci sctp_assoc_update_frag_point(asoc); 14088c2ecf20Sopenharmony_ci } 14098c2ecf20Sopenharmony_ci 14108c2ecf20Sopenharmony_ci pr_debug("%s: asoc:%p, pmtu:%d, frag_point:%d\n", __func__, asoc, 14118c2ecf20Sopenharmony_ci asoc->pathmtu, asoc->frag_point); 14128c2ecf20Sopenharmony_ci} 14138c2ecf20Sopenharmony_ci 14148c2ecf20Sopenharmony_ci/* Update the association's pmtu and frag_point by going through all the 14158c2ecf20Sopenharmony_ci * transports. This routine is called when a transport's PMTU has changed. 14168c2ecf20Sopenharmony_ci */ 14178c2ecf20Sopenharmony_civoid sctp_assoc_sync_pmtu(struct sctp_association *asoc) 14188c2ecf20Sopenharmony_ci{ 14198c2ecf20Sopenharmony_ci struct sctp_transport *t; 14208c2ecf20Sopenharmony_ci __u32 pmtu = 0; 14218c2ecf20Sopenharmony_ci 14228c2ecf20Sopenharmony_ci if (!asoc) 14238c2ecf20Sopenharmony_ci return; 14248c2ecf20Sopenharmony_ci 14258c2ecf20Sopenharmony_ci /* Get the lowest pmtu of all the transports. */ 14268c2ecf20Sopenharmony_ci list_for_each_entry(t, &asoc->peer.transport_addr_list, transports) { 14278c2ecf20Sopenharmony_ci if (t->pmtu_pending && t->dst) { 14288c2ecf20Sopenharmony_ci sctp_transport_update_pmtu(t, 14298c2ecf20Sopenharmony_ci atomic_read(&t->mtu_info)); 14308c2ecf20Sopenharmony_ci t->pmtu_pending = 0; 14318c2ecf20Sopenharmony_ci } 14328c2ecf20Sopenharmony_ci if (!pmtu || (t->pathmtu < pmtu)) 14338c2ecf20Sopenharmony_ci pmtu = t->pathmtu; 14348c2ecf20Sopenharmony_ci } 14358c2ecf20Sopenharmony_ci 14368c2ecf20Sopenharmony_ci sctp_assoc_set_pmtu(asoc, pmtu); 14378c2ecf20Sopenharmony_ci} 14388c2ecf20Sopenharmony_ci 14398c2ecf20Sopenharmony_ci/* Should we send a SACK to update our peer? */ 14408c2ecf20Sopenharmony_cistatic inline bool sctp_peer_needs_update(struct sctp_association *asoc) 14418c2ecf20Sopenharmony_ci{ 14428c2ecf20Sopenharmony_ci struct net *net = asoc->base.net; 14438c2ecf20Sopenharmony_ci 14448c2ecf20Sopenharmony_ci switch (asoc->state) { 14458c2ecf20Sopenharmony_ci case SCTP_STATE_ESTABLISHED: 14468c2ecf20Sopenharmony_ci case SCTP_STATE_SHUTDOWN_PENDING: 14478c2ecf20Sopenharmony_ci case SCTP_STATE_SHUTDOWN_RECEIVED: 14488c2ecf20Sopenharmony_ci case SCTP_STATE_SHUTDOWN_SENT: 14498c2ecf20Sopenharmony_ci if ((asoc->rwnd > asoc->a_rwnd) && 14508c2ecf20Sopenharmony_ci ((asoc->rwnd - asoc->a_rwnd) >= max_t(__u32, 14518c2ecf20Sopenharmony_ci (asoc->base.sk->sk_rcvbuf >> net->sctp.rwnd_upd_shift), 14528c2ecf20Sopenharmony_ci asoc->pathmtu))) 14538c2ecf20Sopenharmony_ci return true; 14548c2ecf20Sopenharmony_ci break; 14558c2ecf20Sopenharmony_ci default: 14568c2ecf20Sopenharmony_ci break; 14578c2ecf20Sopenharmony_ci } 14588c2ecf20Sopenharmony_ci return false; 14598c2ecf20Sopenharmony_ci} 14608c2ecf20Sopenharmony_ci 14618c2ecf20Sopenharmony_ci/* Increase asoc's rwnd by len and send any window update SACK if needed. */ 14628c2ecf20Sopenharmony_civoid sctp_assoc_rwnd_increase(struct sctp_association *asoc, unsigned int len) 14638c2ecf20Sopenharmony_ci{ 14648c2ecf20Sopenharmony_ci struct sctp_chunk *sack; 14658c2ecf20Sopenharmony_ci struct timer_list *timer; 14668c2ecf20Sopenharmony_ci 14678c2ecf20Sopenharmony_ci if (asoc->rwnd_over) { 14688c2ecf20Sopenharmony_ci if (asoc->rwnd_over >= len) { 14698c2ecf20Sopenharmony_ci asoc->rwnd_over -= len; 14708c2ecf20Sopenharmony_ci } else { 14718c2ecf20Sopenharmony_ci asoc->rwnd += (len - asoc->rwnd_over); 14728c2ecf20Sopenharmony_ci asoc->rwnd_over = 0; 14738c2ecf20Sopenharmony_ci } 14748c2ecf20Sopenharmony_ci } else { 14758c2ecf20Sopenharmony_ci asoc->rwnd += len; 14768c2ecf20Sopenharmony_ci } 14778c2ecf20Sopenharmony_ci 14788c2ecf20Sopenharmony_ci /* If we had window pressure, start recovering it 14798c2ecf20Sopenharmony_ci * once our rwnd had reached the accumulated pressure 14808c2ecf20Sopenharmony_ci * threshold. The idea is to recover slowly, but up 14818c2ecf20Sopenharmony_ci * to the initial advertised window. 14828c2ecf20Sopenharmony_ci */ 14838c2ecf20Sopenharmony_ci if (asoc->rwnd_press) { 14848c2ecf20Sopenharmony_ci int change = min(asoc->pathmtu, asoc->rwnd_press); 14858c2ecf20Sopenharmony_ci asoc->rwnd += change; 14868c2ecf20Sopenharmony_ci asoc->rwnd_press -= change; 14878c2ecf20Sopenharmony_ci } 14888c2ecf20Sopenharmony_ci 14898c2ecf20Sopenharmony_ci pr_debug("%s: asoc:%p rwnd increased by %d to (%u, %u) - %u\n", 14908c2ecf20Sopenharmony_ci __func__, asoc, len, asoc->rwnd, asoc->rwnd_over, 14918c2ecf20Sopenharmony_ci asoc->a_rwnd); 14928c2ecf20Sopenharmony_ci 14938c2ecf20Sopenharmony_ci /* Send a window update SACK if the rwnd has increased by at least the 14948c2ecf20Sopenharmony_ci * minimum of the association's PMTU and half of the receive buffer. 14958c2ecf20Sopenharmony_ci * The algorithm used is similar to the one described in 14968c2ecf20Sopenharmony_ci * Section 4.2.3.3 of RFC 1122. 14978c2ecf20Sopenharmony_ci */ 14988c2ecf20Sopenharmony_ci if (sctp_peer_needs_update(asoc)) { 14998c2ecf20Sopenharmony_ci asoc->a_rwnd = asoc->rwnd; 15008c2ecf20Sopenharmony_ci 15018c2ecf20Sopenharmony_ci pr_debug("%s: sending window update SACK- asoc:%p rwnd:%u " 15028c2ecf20Sopenharmony_ci "a_rwnd:%u\n", __func__, asoc, asoc->rwnd, 15038c2ecf20Sopenharmony_ci asoc->a_rwnd); 15048c2ecf20Sopenharmony_ci 15058c2ecf20Sopenharmony_ci sack = sctp_make_sack(asoc); 15068c2ecf20Sopenharmony_ci if (!sack) 15078c2ecf20Sopenharmony_ci return; 15088c2ecf20Sopenharmony_ci 15098c2ecf20Sopenharmony_ci asoc->peer.sack_needed = 0; 15108c2ecf20Sopenharmony_ci 15118c2ecf20Sopenharmony_ci sctp_outq_tail(&asoc->outqueue, sack, GFP_ATOMIC); 15128c2ecf20Sopenharmony_ci 15138c2ecf20Sopenharmony_ci /* Stop the SACK timer. */ 15148c2ecf20Sopenharmony_ci timer = &asoc->timers[SCTP_EVENT_TIMEOUT_SACK]; 15158c2ecf20Sopenharmony_ci if (del_timer(timer)) 15168c2ecf20Sopenharmony_ci sctp_association_put(asoc); 15178c2ecf20Sopenharmony_ci } 15188c2ecf20Sopenharmony_ci} 15198c2ecf20Sopenharmony_ci 15208c2ecf20Sopenharmony_ci/* Decrease asoc's rwnd by len. */ 15218c2ecf20Sopenharmony_civoid sctp_assoc_rwnd_decrease(struct sctp_association *asoc, unsigned int len) 15228c2ecf20Sopenharmony_ci{ 15238c2ecf20Sopenharmony_ci int rx_count; 15248c2ecf20Sopenharmony_ci int over = 0; 15258c2ecf20Sopenharmony_ci 15268c2ecf20Sopenharmony_ci if (unlikely(!asoc->rwnd || asoc->rwnd_over)) 15278c2ecf20Sopenharmony_ci pr_debug("%s: association:%p has asoc->rwnd:%u, " 15288c2ecf20Sopenharmony_ci "asoc->rwnd_over:%u!\n", __func__, asoc, 15298c2ecf20Sopenharmony_ci asoc->rwnd, asoc->rwnd_over); 15308c2ecf20Sopenharmony_ci 15318c2ecf20Sopenharmony_ci if (asoc->ep->rcvbuf_policy) 15328c2ecf20Sopenharmony_ci rx_count = atomic_read(&asoc->rmem_alloc); 15338c2ecf20Sopenharmony_ci else 15348c2ecf20Sopenharmony_ci rx_count = atomic_read(&asoc->base.sk->sk_rmem_alloc); 15358c2ecf20Sopenharmony_ci 15368c2ecf20Sopenharmony_ci /* If we've reached or overflowed our receive buffer, announce 15378c2ecf20Sopenharmony_ci * a 0 rwnd if rwnd would still be positive. Store the 15388c2ecf20Sopenharmony_ci * potential pressure overflow so that the window can be restored 15398c2ecf20Sopenharmony_ci * back to original value. 15408c2ecf20Sopenharmony_ci */ 15418c2ecf20Sopenharmony_ci if (rx_count >= asoc->base.sk->sk_rcvbuf) 15428c2ecf20Sopenharmony_ci over = 1; 15438c2ecf20Sopenharmony_ci 15448c2ecf20Sopenharmony_ci if (asoc->rwnd >= len) { 15458c2ecf20Sopenharmony_ci asoc->rwnd -= len; 15468c2ecf20Sopenharmony_ci if (over) { 15478c2ecf20Sopenharmony_ci asoc->rwnd_press += asoc->rwnd; 15488c2ecf20Sopenharmony_ci asoc->rwnd = 0; 15498c2ecf20Sopenharmony_ci } 15508c2ecf20Sopenharmony_ci } else { 15518c2ecf20Sopenharmony_ci asoc->rwnd_over += len - asoc->rwnd; 15528c2ecf20Sopenharmony_ci asoc->rwnd = 0; 15538c2ecf20Sopenharmony_ci } 15548c2ecf20Sopenharmony_ci 15558c2ecf20Sopenharmony_ci pr_debug("%s: asoc:%p rwnd decreased by %d to (%u, %u, %u)\n", 15568c2ecf20Sopenharmony_ci __func__, asoc, len, asoc->rwnd, asoc->rwnd_over, 15578c2ecf20Sopenharmony_ci asoc->rwnd_press); 15588c2ecf20Sopenharmony_ci} 15598c2ecf20Sopenharmony_ci 15608c2ecf20Sopenharmony_ci/* Build the bind address list for the association based on info from the 15618c2ecf20Sopenharmony_ci * local endpoint and the remote peer. 15628c2ecf20Sopenharmony_ci */ 15638c2ecf20Sopenharmony_ciint sctp_assoc_set_bind_addr_from_ep(struct sctp_association *asoc, 15648c2ecf20Sopenharmony_ci enum sctp_scope scope, gfp_t gfp) 15658c2ecf20Sopenharmony_ci{ 15668c2ecf20Sopenharmony_ci struct sock *sk = asoc->base.sk; 15678c2ecf20Sopenharmony_ci int flags; 15688c2ecf20Sopenharmony_ci 15698c2ecf20Sopenharmony_ci /* Use scoping rules to determine the subset of addresses from 15708c2ecf20Sopenharmony_ci * the endpoint. 15718c2ecf20Sopenharmony_ci */ 15728c2ecf20Sopenharmony_ci flags = (PF_INET6 == sk->sk_family) ? SCTP_ADDR6_ALLOWED : 0; 15738c2ecf20Sopenharmony_ci if (!inet_v6_ipv6only(sk)) 15748c2ecf20Sopenharmony_ci flags |= SCTP_ADDR4_ALLOWED; 15758c2ecf20Sopenharmony_ci if (asoc->peer.ipv4_address) 15768c2ecf20Sopenharmony_ci flags |= SCTP_ADDR4_PEERSUPP; 15778c2ecf20Sopenharmony_ci if (asoc->peer.ipv6_address) 15788c2ecf20Sopenharmony_ci flags |= SCTP_ADDR6_PEERSUPP; 15798c2ecf20Sopenharmony_ci 15808c2ecf20Sopenharmony_ci return sctp_bind_addr_copy(asoc->base.net, 15818c2ecf20Sopenharmony_ci &asoc->base.bind_addr, 15828c2ecf20Sopenharmony_ci &asoc->ep->base.bind_addr, 15838c2ecf20Sopenharmony_ci scope, gfp, flags); 15848c2ecf20Sopenharmony_ci} 15858c2ecf20Sopenharmony_ci 15868c2ecf20Sopenharmony_ci/* Build the association's bind address list from the cookie. */ 15878c2ecf20Sopenharmony_ciint sctp_assoc_set_bind_addr_from_cookie(struct sctp_association *asoc, 15888c2ecf20Sopenharmony_ci struct sctp_cookie *cookie, 15898c2ecf20Sopenharmony_ci gfp_t gfp) 15908c2ecf20Sopenharmony_ci{ 15918c2ecf20Sopenharmony_ci int var_size2 = ntohs(cookie->peer_init->chunk_hdr.length); 15928c2ecf20Sopenharmony_ci int var_size3 = cookie->raw_addr_list_len; 15938c2ecf20Sopenharmony_ci __u8 *raw = (__u8 *)cookie->peer_init + var_size2; 15948c2ecf20Sopenharmony_ci 15958c2ecf20Sopenharmony_ci return sctp_raw_to_bind_addrs(&asoc->base.bind_addr, raw, var_size3, 15968c2ecf20Sopenharmony_ci asoc->ep->base.bind_addr.port, gfp); 15978c2ecf20Sopenharmony_ci} 15988c2ecf20Sopenharmony_ci 15998c2ecf20Sopenharmony_ci/* Lookup laddr in the bind address list of an association. */ 16008c2ecf20Sopenharmony_ciint sctp_assoc_lookup_laddr(struct sctp_association *asoc, 16018c2ecf20Sopenharmony_ci const union sctp_addr *laddr) 16028c2ecf20Sopenharmony_ci{ 16038c2ecf20Sopenharmony_ci int found = 0; 16048c2ecf20Sopenharmony_ci 16058c2ecf20Sopenharmony_ci if ((asoc->base.bind_addr.port == ntohs(laddr->v4.sin_port)) && 16068c2ecf20Sopenharmony_ci sctp_bind_addr_match(&asoc->base.bind_addr, laddr, 16078c2ecf20Sopenharmony_ci sctp_sk(asoc->base.sk))) 16088c2ecf20Sopenharmony_ci found = 1; 16098c2ecf20Sopenharmony_ci 16108c2ecf20Sopenharmony_ci return found; 16118c2ecf20Sopenharmony_ci} 16128c2ecf20Sopenharmony_ci 16138c2ecf20Sopenharmony_ci/* Set an association id for a given association */ 16148c2ecf20Sopenharmony_ciint sctp_assoc_set_id(struct sctp_association *asoc, gfp_t gfp) 16158c2ecf20Sopenharmony_ci{ 16168c2ecf20Sopenharmony_ci bool preload = gfpflags_allow_blocking(gfp); 16178c2ecf20Sopenharmony_ci int ret; 16188c2ecf20Sopenharmony_ci 16198c2ecf20Sopenharmony_ci /* If the id is already assigned, keep it. */ 16208c2ecf20Sopenharmony_ci if (asoc->assoc_id) 16218c2ecf20Sopenharmony_ci return 0; 16228c2ecf20Sopenharmony_ci 16238c2ecf20Sopenharmony_ci if (preload) 16248c2ecf20Sopenharmony_ci idr_preload(gfp); 16258c2ecf20Sopenharmony_ci spin_lock_bh(&sctp_assocs_id_lock); 16268c2ecf20Sopenharmony_ci /* 0, 1, 2 are used as SCTP_FUTURE_ASSOC, SCTP_CURRENT_ASSOC and 16278c2ecf20Sopenharmony_ci * SCTP_ALL_ASSOC, so an available id must be > SCTP_ALL_ASSOC. 16288c2ecf20Sopenharmony_ci */ 16298c2ecf20Sopenharmony_ci ret = idr_alloc_cyclic(&sctp_assocs_id, asoc, SCTP_ALL_ASSOC + 1, 0, 16308c2ecf20Sopenharmony_ci GFP_NOWAIT); 16318c2ecf20Sopenharmony_ci spin_unlock_bh(&sctp_assocs_id_lock); 16328c2ecf20Sopenharmony_ci if (preload) 16338c2ecf20Sopenharmony_ci idr_preload_end(); 16348c2ecf20Sopenharmony_ci if (ret < 0) 16358c2ecf20Sopenharmony_ci return ret; 16368c2ecf20Sopenharmony_ci 16378c2ecf20Sopenharmony_ci asoc->assoc_id = (sctp_assoc_t)ret; 16388c2ecf20Sopenharmony_ci return 0; 16398c2ecf20Sopenharmony_ci} 16408c2ecf20Sopenharmony_ci 16418c2ecf20Sopenharmony_ci/* Free the ASCONF queue */ 16428c2ecf20Sopenharmony_cistatic void sctp_assoc_free_asconf_queue(struct sctp_association *asoc) 16438c2ecf20Sopenharmony_ci{ 16448c2ecf20Sopenharmony_ci struct sctp_chunk *asconf; 16458c2ecf20Sopenharmony_ci struct sctp_chunk *tmp; 16468c2ecf20Sopenharmony_ci 16478c2ecf20Sopenharmony_ci list_for_each_entry_safe(asconf, tmp, &asoc->addip_chunk_list, list) { 16488c2ecf20Sopenharmony_ci list_del_init(&asconf->list); 16498c2ecf20Sopenharmony_ci sctp_chunk_free(asconf); 16508c2ecf20Sopenharmony_ci } 16518c2ecf20Sopenharmony_ci} 16528c2ecf20Sopenharmony_ci 16538c2ecf20Sopenharmony_ci/* Free asconf_ack cache */ 16548c2ecf20Sopenharmony_cistatic void sctp_assoc_free_asconf_acks(struct sctp_association *asoc) 16558c2ecf20Sopenharmony_ci{ 16568c2ecf20Sopenharmony_ci struct sctp_chunk *ack; 16578c2ecf20Sopenharmony_ci struct sctp_chunk *tmp; 16588c2ecf20Sopenharmony_ci 16598c2ecf20Sopenharmony_ci list_for_each_entry_safe(ack, tmp, &asoc->asconf_ack_list, 16608c2ecf20Sopenharmony_ci transmitted_list) { 16618c2ecf20Sopenharmony_ci list_del_init(&ack->transmitted_list); 16628c2ecf20Sopenharmony_ci sctp_chunk_free(ack); 16638c2ecf20Sopenharmony_ci } 16648c2ecf20Sopenharmony_ci} 16658c2ecf20Sopenharmony_ci 16668c2ecf20Sopenharmony_ci/* Clean up the ASCONF_ACK queue */ 16678c2ecf20Sopenharmony_civoid sctp_assoc_clean_asconf_ack_cache(const struct sctp_association *asoc) 16688c2ecf20Sopenharmony_ci{ 16698c2ecf20Sopenharmony_ci struct sctp_chunk *ack; 16708c2ecf20Sopenharmony_ci struct sctp_chunk *tmp; 16718c2ecf20Sopenharmony_ci 16728c2ecf20Sopenharmony_ci /* We can remove all the entries from the queue up to 16738c2ecf20Sopenharmony_ci * the "Peer-Sequence-Number". 16748c2ecf20Sopenharmony_ci */ 16758c2ecf20Sopenharmony_ci list_for_each_entry_safe(ack, tmp, &asoc->asconf_ack_list, 16768c2ecf20Sopenharmony_ci transmitted_list) { 16778c2ecf20Sopenharmony_ci if (ack->subh.addip_hdr->serial == 16788c2ecf20Sopenharmony_ci htonl(asoc->peer.addip_serial)) 16798c2ecf20Sopenharmony_ci break; 16808c2ecf20Sopenharmony_ci 16818c2ecf20Sopenharmony_ci list_del_init(&ack->transmitted_list); 16828c2ecf20Sopenharmony_ci sctp_chunk_free(ack); 16838c2ecf20Sopenharmony_ci } 16848c2ecf20Sopenharmony_ci} 16858c2ecf20Sopenharmony_ci 16868c2ecf20Sopenharmony_ci/* Find the ASCONF_ACK whose serial number matches ASCONF */ 16878c2ecf20Sopenharmony_cistruct sctp_chunk *sctp_assoc_lookup_asconf_ack( 16888c2ecf20Sopenharmony_ci const struct sctp_association *asoc, 16898c2ecf20Sopenharmony_ci __be32 serial) 16908c2ecf20Sopenharmony_ci{ 16918c2ecf20Sopenharmony_ci struct sctp_chunk *ack; 16928c2ecf20Sopenharmony_ci 16938c2ecf20Sopenharmony_ci /* Walk through the list of cached ASCONF-ACKs and find the 16948c2ecf20Sopenharmony_ci * ack chunk whose serial number matches that of the request. 16958c2ecf20Sopenharmony_ci */ 16968c2ecf20Sopenharmony_ci list_for_each_entry(ack, &asoc->asconf_ack_list, transmitted_list) { 16978c2ecf20Sopenharmony_ci if (sctp_chunk_pending(ack)) 16988c2ecf20Sopenharmony_ci continue; 16998c2ecf20Sopenharmony_ci if (ack->subh.addip_hdr->serial == serial) { 17008c2ecf20Sopenharmony_ci sctp_chunk_hold(ack); 17018c2ecf20Sopenharmony_ci return ack; 17028c2ecf20Sopenharmony_ci } 17038c2ecf20Sopenharmony_ci } 17048c2ecf20Sopenharmony_ci 17058c2ecf20Sopenharmony_ci return NULL; 17068c2ecf20Sopenharmony_ci} 17078c2ecf20Sopenharmony_ci 17088c2ecf20Sopenharmony_civoid sctp_asconf_queue_teardown(struct sctp_association *asoc) 17098c2ecf20Sopenharmony_ci{ 17108c2ecf20Sopenharmony_ci /* Free any cached ASCONF_ACK chunk. */ 17118c2ecf20Sopenharmony_ci sctp_assoc_free_asconf_acks(asoc); 17128c2ecf20Sopenharmony_ci 17138c2ecf20Sopenharmony_ci /* Free the ASCONF queue. */ 17148c2ecf20Sopenharmony_ci sctp_assoc_free_asconf_queue(asoc); 17158c2ecf20Sopenharmony_ci 17168c2ecf20Sopenharmony_ci /* Free any cached ASCONF chunk. */ 17178c2ecf20Sopenharmony_ci if (asoc->addip_last_asconf) 17188c2ecf20Sopenharmony_ci sctp_chunk_free(asoc->addip_last_asconf); 17198c2ecf20Sopenharmony_ci} 1720