147505b8bSThomas Gleixner // SPDX-License-Identifier: GPL-2.0-or-later
260c778b2SVlad Yasevich /* SCTP kernel implementation
31da177e4SLinus Torvalds * (C) Copyright IBM Corp. 2001, 2004
41da177e4SLinus Torvalds * Copyright (c) 1999-2000 Cisco, Inc.
51da177e4SLinus Torvalds * Copyright (c) 1999-2001 Motorola, Inc.
61da177e4SLinus Torvalds * Copyright (c) 2001 Intel Corp.
71da177e4SLinus Torvalds * Copyright (c) 2001 La Monte H.P. Yarroll
81da177e4SLinus Torvalds *
960c778b2SVlad Yasevich * This file is part of the SCTP kernel implementation
101da177e4SLinus Torvalds *
111da177e4SLinus Torvalds * This module provides the abstraction for an SCTP association.
121da177e4SLinus Torvalds *
131da177e4SLinus Torvalds * Please send any bug reports or fixes you make to the
141da177e4SLinus Torvalds * email address(es):
1591705c61SDaniel Borkmann * lksctp developers <linux-sctp@vger.kernel.org>
161da177e4SLinus Torvalds *
171da177e4SLinus Torvalds * Written or modified by:
181da177e4SLinus Torvalds * La Monte H.P. Yarroll <piggy@acm.org>
191da177e4SLinus Torvalds * Karl Knutson <karl@athena.chicago.il.us>
201da177e4SLinus Torvalds * Jon Grimm <jgrimm@us.ibm.com>
211da177e4SLinus Torvalds * Xingang Guo <xingang.guo@intel.com>
221da177e4SLinus Torvalds * Hui Huang <hui.huang@nokia.com>
231da177e4SLinus Torvalds * Sridhar Samudrala <sri@us.ibm.com>
241da177e4SLinus Torvalds * Daisy Chang <daisyc@us.ibm.com>
251da177e4SLinus Torvalds * Ryan Layer <rmlayer@us.ibm.com>
261da177e4SLinus Torvalds * Kevin Gao <kevin.gao@intel.com>
271da177e4SLinus Torvalds */
281da177e4SLinus Torvalds
29145ce502SJoe Perches #define pr_fmt(fmt) KBUILD_MODNAME ": " fmt
30145ce502SJoe Perches
311da177e4SLinus Torvalds #include <linux/types.h>
321da177e4SLinus Torvalds #include <linux/fcntl.h>
331da177e4SLinus Torvalds #include <linux/poll.h>
341da177e4SLinus Torvalds #include <linux/init.h>
351da177e4SLinus Torvalds
361da177e4SLinus Torvalds #include <linux/slab.h>
371da177e4SLinus Torvalds #include <linux/in.h>
381da177e4SLinus Torvalds #include <net/ipv6.h>
391da177e4SLinus Torvalds #include <net/sctp/sctp.h>
401da177e4SLinus Torvalds #include <net/sctp/sm.h>
411da177e4SLinus Torvalds
421da177e4SLinus Torvalds /* Forward declarations for internal functions. */
43b82e8f31SDaniel Borkmann static void sctp_select_active_and_retran_path(struct sctp_association *asoc);
44c4028958SDavid Howells static void sctp_assoc_bh_rcv(struct work_struct *work);
45a08de64dSVlad Yasevich static void sctp_assoc_free_asconf_acks(struct sctp_association *asoc);
468b4472ccSWei Yongjun static void sctp_assoc_free_asconf_queue(struct sctp_association *asoc);
471da177e4SLinus Torvalds
481da177e4SLinus Torvalds /* 1st Level Abstractions. */
491da177e4SLinus Torvalds
501da177e4SLinus Torvalds /* Initialize a new association from provided memory. */
sctp_association_init(struct sctp_association * asoc,const struct sctp_endpoint * ep,const struct sock * sk,enum sctp_scope scope,gfp_t gfp)511c662018SXin Long static struct sctp_association *sctp_association_init(
521c662018SXin Long struct sctp_association *asoc,
531da177e4SLinus Torvalds const struct sctp_endpoint *ep,
541da177e4SLinus Torvalds const struct sock *sk,
551c662018SXin Long enum sctp_scope scope, gfp_t gfp)
561da177e4SLinus Torvalds {
571da177e4SLinus Torvalds struct sctp_sock *sp;
583c918704SXin Long struct sctp_paramhdr *p;
5958194778SXin Long int i;
601da177e4SLinus Torvalds
611da177e4SLinus Torvalds /* Retrieve the SCTP per socket area. */
621da177e4SLinus Torvalds sp = sctp_sk((struct sock *)sk);
631da177e4SLinus Torvalds
641da177e4SLinus Torvalds /* Discarding const is appropriate here. */
651da177e4SLinus Torvalds asoc->ep = (struct sctp_endpoint *)ep;
661da177e4SLinus Torvalds asoc->base.sk = (struct sock *)sk;
6731243461SXin Long asoc->base.net = sock_net(sk);
682e0c9e79SDaniel Borkmann
692e0c9e79SDaniel Borkmann sctp_endpoint_hold(asoc->ep);
701da177e4SLinus Torvalds sock_hold(asoc->base.sk);
711da177e4SLinus Torvalds
721da177e4SLinus Torvalds /* Initialize the common base substructure. */
731da177e4SLinus Torvalds asoc->base.type = SCTP_EP_TYPE_ASSOCIATION;
741da177e4SLinus Torvalds
751da177e4SLinus Torvalds /* Initialize the object handling fields. */
76c638457aSReshetova, Elena refcount_set(&asoc->base.refcnt, 1);
771da177e4SLinus Torvalds
781da177e4SLinus Torvalds /* Initialize the bind addr area. */
791da177e4SLinus Torvalds sctp_bind_addr_init(&asoc->base.bind_addr, ep->base.bind_addr.port);
801da177e4SLinus Torvalds
811da177e4SLinus Torvalds asoc->state = SCTP_STATE_CLOSED;
8252db882fSDaniel Borkmann asoc->cookie_life = ms_to_ktime(sp->assocparams.sasoc_cookie_life);
83f68b2e05SVlad Yasevich asoc->user_frag = sp->user_frag;
841da177e4SLinus Torvalds
851da177e4SLinus Torvalds /* Set the association max_retrans and RTO values from the
861da177e4SLinus Torvalds * socket values.
871da177e4SLinus Torvalds */
881da177e4SLinus Torvalds asoc->max_retrans = sp->assocparams.sasoc_asocmaxrxt;
898add543eSXin Long asoc->pf_retrans = sp->pf_retrans;
9034515e94SXin Long asoc->ps_retrans = sp->ps_retrans;
91aef587beSXin Long asoc->pf_expose = sp->pf_expose;
925aa93bcfSNeil Horman
931da177e4SLinus Torvalds asoc->rto_initial = msecs_to_jiffies(sp->rtoinfo.srto_initial);
941da177e4SLinus Torvalds asoc->rto_max = msecs_to_jiffies(sp->rtoinfo.srto_max);
951da177e4SLinus Torvalds asoc->rto_min = msecs_to_jiffies(sp->rtoinfo.srto_min);
961da177e4SLinus Torvalds
9752ccb8e9SFrank Filz /* Initialize the association's heartbeat interval based on the
9852ccb8e9SFrank Filz * sock configured value.
9952ccb8e9SFrank Filz */
10052ccb8e9SFrank Filz asoc->hbinterval = msecs_to_jiffies(sp->hbinterval);
101d1e462a7SXin Long asoc->probe_interval = msecs_to_jiffies(sp->probe_interval);
10252ccb8e9SFrank Filz
103e8a3001cSXin Long asoc->encap_port = sp->encap_port;
104e8a3001cSXin Long
10552ccb8e9SFrank Filz /* Initialize path max retrans value. */
10652ccb8e9SFrank Filz asoc->pathmaxrxt = sp->pathmaxrxt;
10752ccb8e9SFrank Filz
1088a9c58d2SXin Long asoc->flowlabel = sp->flowlabel;
1098a9c58d2SXin Long asoc->dscp = sp->dscp;
1108a9c58d2SXin Long
11152ccb8e9SFrank Filz /* Set association default SACK delay */
11252ccb8e9SFrank Filz asoc->sackdelay = msecs_to_jiffies(sp->sackdelay);
113d364d927SWei Yongjun asoc->sackfreq = sp->sackfreq;
11452ccb8e9SFrank Filz
11552ccb8e9SFrank Filz /* Set the association default flags controlling
11652ccb8e9SFrank Filz * Heartbeat, SACK delay, and Path MTU Discovery.
11752ccb8e9SFrank Filz */
11852ccb8e9SFrank Filz asoc->param_flags = sp->param_flags;
11952ccb8e9SFrank Filz
1209d2c881aSwangweidong /* Initialize the maximum number of new data packets that can be sent
1211da177e4SLinus Torvalds * in a burst.
1221da177e4SLinus Torvalds */
12370331571SVlad Yasevich asoc->max_burst = sp->max_burst;
1241da177e4SLinus Torvalds
125a1e3a059SXin Long asoc->subscribe = sp->subscribe;
126a1e3a059SXin Long
1271e7d3d90SVladislav Yasevich /* initialize association timers */
1281e7d3d90SVladislav Yasevich asoc->timeouts[SCTP_EVENT_TIMEOUT_T1_COOKIE] = asoc->rto_initial;
1291e7d3d90SVladislav Yasevich asoc->timeouts[SCTP_EVENT_TIMEOUT_T1_INIT] = asoc->rto_initial;
1301e7d3d90SVladislav Yasevich asoc->timeouts[SCTP_EVENT_TIMEOUT_T2_SHUTDOWN] = asoc->rto_initial;
1311e7d3d90SVladislav Yasevich
1321e7d3d90SVladislav Yasevich /* sctpimpguide Section 2.12.2
1331e7d3d90SVladislav Yasevich * If the 'T5-shutdown-guard' timer is used, it SHOULD be set to the
1341e7d3d90SVladislav Yasevich * recommended value of 5 times 'RTO.Max'.
1351e7d3d90SVladislav Yasevich */
1361e7d3d90SVladislav Yasevich asoc->timeouts[SCTP_EVENT_TIMEOUT_T5_SHUTDOWN_GUARD]
1371e7d3d90SVladislav Yasevich = 5 * asoc->rto_max;
1381e7d3d90SVladislav Yasevich
13952ccb8e9SFrank Filz asoc->timeouts[SCTP_EVENT_TIMEOUT_SACK] = asoc->sackdelay;
140*271f031fSNikolay Kuratov asoc->timeouts[SCTP_EVENT_TIMEOUT_AUTOCLOSE] =
141*271f031fSNikolay Kuratov (unsigned long)sp->autoclose * HZ;
1421e7d3d90SVladislav Yasevich
143421f91d2SUwe Kleine-König /* Initializes the timers */
144b24b8a24SPavel Emelyanov for (i = SCTP_EVENT_TIMEOUT_NONE; i < SCTP_NUM_TIMEOUT_TYPES; ++i)
1459c3b5751SKees Cook timer_setup(&asoc->timers[i], sctp_timer_events[i], 0);
1461da177e4SLinus Torvalds
1471da177e4SLinus Torvalds /* Pull default initialization values from the sock options.
1481da177e4SLinus Torvalds * Note: This assumes that the values have already been
1491da177e4SLinus Torvalds * validated in the sock.
1501da177e4SLinus Torvalds */
1511da177e4SLinus Torvalds asoc->c.sinit_max_instreams = sp->initmsg.sinit_max_instreams;
1521da177e4SLinus Torvalds asoc->c.sinit_num_ostreams = sp->initmsg.sinit_num_ostreams;
1531da177e4SLinus Torvalds asoc->max_init_attempts = sp->initmsg.sinit_max_attempts;
1541da177e4SLinus Torvalds
1551da177e4SLinus Torvalds asoc->max_init_timeo =
1561da177e4SLinus Torvalds msecs_to_jiffies(sp->initmsg.sinit_max_init_timeo);
1571da177e4SLinus Torvalds
1581da177e4SLinus Torvalds /* Set the local window size for receive.
1591da177e4SLinus Torvalds * This is also the rcvbuf space per association.
1601da177e4SLinus Torvalds * RFC 6 - A SCTP receiver MUST be able to receive a minimum of
1611da177e4SLinus Torvalds * 1500 bytes in one SCTP packet.
1621da177e4SLinus Torvalds */
163049b3ff5SNeil Horman if ((sk->sk_rcvbuf/2) < SCTP_DEFAULT_MINWINDOW)
1641da177e4SLinus Torvalds asoc->rwnd = SCTP_DEFAULT_MINWINDOW;
1651da177e4SLinus Torvalds else
166049b3ff5SNeil Horman asoc->rwnd = sk->sk_rcvbuf/2;
1671da177e4SLinus Torvalds
1681da177e4SLinus Torvalds asoc->a_rwnd = asoc->rwnd;
1691da177e4SLinus Torvalds
1701da177e4SLinus Torvalds /* Use my own max window until I learn something better. */
1711da177e4SLinus Torvalds asoc->peer.rwnd = SCTP_DEFAULT_MAXWINDOW;
1721da177e4SLinus Torvalds
173049b3ff5SNeil Horman /* Initialize the receive memory counter */
174049b3ff5SNeil Horman atomic_set(&asoc->rmem_alloc, 0);
175049b3ff5SNeil Horman
1761da177e4SLinus Torvalds init_waitqueue_head(&asoc->wait);
1771da177e4SLinus Torvalds
1781da177e4SLinus Torvalds asoc->c.my_vtag = sctp_generate_tag(ep);
1791da177e4SLinus Torvalds asoc->c.my_port = ep->base.bind_addr.port;
1801da177e4SLinus Torvalds
1811da177e4SLinus Torvalds asoc->c.initial_tsn = sctp_generate_tsn(ep);
1821da177e4SLinus Torvalds
1831da177e4SLinus Torvalds asoc->next_tsn = asoc->c.initial_tsn;
1841da177e4SLinus Torvalds
1851da177e4SLinus Torvalds asoc->ctsn_ack_point = asoc->next_tsn - 1;
1861da177e4SLinus Torvalds asoc->adv_peer_ack_point = asoc->ctsn_ack_point;
1871da177e4SLinus Torvalds asoc->highest_sacked = asoc->ctsn_ack_point;
1881da177e4SLinus Torvalds asoc->last_cwr_tsn = asoc->ctsn_ack_point;
1891da177e4SLinus Torvalds
1901da177e4SLinus Torvalds /* ADDIP Section 4.1 Asconf Chunk Procedures
1911da177e4SLinus Torvalds *
1921da177e4SLinus Torvalds * When an endpoint has an ASCONF signaled change to be sent to the
1931da177e4SLinus Torvalds * remote endpoint it should do the following:
1941da177e4SLinus Torvalds * ...
1951da177e4SLinus Torvalds * A2) a serial number should be assigned to the chunk. The serial
1961da177e4SLinus Torvalds * number SHOULD be a monotonically increasing number. The serial
1971da177e4SLinus Torvalds * numbers SHOULD be initialized at the start of the
1981da177e4SLinus Torvalds * association to the same value as the initial TSN.
1991da177e4SLinus Torvalds */
2001da177e4SLinus Torvalds asoc->addip_serial = asoc->c.initial_tsn;
201cc16f00fSXin Long asoc->strreset_outseq = asoc->c.initial_tsn;
2021da177e4SLinus Torvalds
20379af02c2SDavid S. Miller INIT_LIST_HEAD(&asoc->addip_chunk_list);
204a08de64dSVlad Yasevich INIT_LIST_HEAD(&asoc->asconf_ack_list);
2051da177e4SLinus Torvalds
2061da177e4SLinus Torvalds /* Make an empty list of remote transport addresses. */
2071da177e4SLinus Torvalds INIT_LIST_HEAD(&asoc->peer.transport_addr_list);
2081da177e4SLinus Torvalds
2091da177e4SLinus Torvalds /* RFC 2960 5.1 Normal Establishment of an Association
2101da177e4SLinus Torvalds *
2111da177e4SLinus Torvalds * After the reception of the first data chunk in an
2121da177e4SLinus Torvalds * association the endpoint must immediately respond with a
2131da177e4SLinus Torvalds * sack to acknowledge the data chunk. Subsequent
2141da177e4SLinus Torvalds * acknowledgements should be done as described in Section
2151da177e4SLinus Torvalds * 6.2.
2161da177e4SLinus Torvalds *
2171da177e4SLinus Torvalds * [We implement this by telling a new association that it
2181da177e4SLinus Torvalds * already received one packet.]
2191da177e4SLinus Torvalds */
2201da177e4SLinus Torvalds asoc->peer.sack_needed = 1;
2214244854dSNeil Horman asoc->peer.sack_generation = 1;
2221da177e4SLinus Torvalds
2231da177e4SLinus Torvalds /* Create an input queue. */
2241da177e4SLinus Torvalds sctp_inq_init(&asoc->base.inqueue);
225c4028958SDavid Howells sctp_inq_set_th_handler(&asoc->base.inqueue, sctp_assoc_bh_rcv);
2261da177e4SLinus Torvalds
2271da177e4SLinus Torvalds /* Create an output queue. */
2281da177e4SLinus Torvalds sctp_outq_init(asoc, &asoc->outqueue);
2291da177e4SLinus Torvalds
2306fdfdef7SAlexey Kodanev sctp_ulpq_init(&asoc->ulpq, asoc);
2311da177e4SLinus Torvalds
232181d8d20SXin Long if (sctp_stream_init(&asoc->stream, asoc->c.sinit_num_ostreams, 0, gfp))
233181d8d20SXin Long goto stream_free;
2343dbcc105SXin Long
2354135cce7SXin Long /* Initialize default path MTU. */
2364135cce7SXin Long asoc->pathmtu = sp->pathmtu;
2374135cce7SXin Long sctp_assoc_update_frag_point(asoc);
2384135cce7SXin Long
2391da177e4SLinus Torvalds /* Assume that peer would support both address types unless we are
2401da177e4SLinus Torvalds * told otherwise.
2411da177e4SLinus Torvalds */
2421da177e4SLinus Torvalds asoc->peer.ipv4_address = 1;
243a2c39584SWei Yongjun if (asoc->base.sk->sk_family == PF_INET6)
2441da177e4SLinus Torvalds asoc->peer.ipv6_address = 1;
2451da177e4SLinus Torvalds INIT_LIST_HEAD(&asoc->asocs);
2461da177e4SLinus Torvalds
2471da177e4SLinus Torvalds asoc->default_stream = sp->default_stream;
2481da177e4SLinus Torvalds asoc->default_ppid = sp->default_ppid;
2491da177e4SLinus Torvalds asoc->default_flags = sp->default_flags;
2501da177e4SLinus Torvalds asoc->default_context = sp->default_context;
2511da177e4SLinus Torvalds asoc->default_timetolive = sp->default_timetolive;
2526ab792f5SIvan Skytte Jorgensen asoc->default_rcv_context = sp->default_rcv_context;
2531da177e4SLinus Torvalds
254a29a5bd4SVlad Yasevich /* AUTH related initializations */
255a29a5bd4SVlad Yasevich INIT_LIST_HEAD(&asoc->endpoint_shared_keys);
25658194778SXin Long if (sctp_auth_asoc_copy_shkeys(ep, asoc, gfp))
2573dbcc105SXin Long goto stream_free;
258a29a5bd4SVlad Yasevich
259a29a5bd4SVlad Yasevich asoc->active_key_id = ep->active_key_id;
2609fb657aeSXin Long asoc->strreset_enable = ep->strreset_enable;
261a29a5bd4SVlad Yasevich
262a29a5bd4SVlad Yasevich /* Save the hmacs and chunks list into this association */
263a29a5bd4SVlad Yasevich if (ep->auth_hmacs_list)
264a29a5bd4SVlad Yasevich memcpy(asoc->c.auth_hmacs, ep->auth_hmacs_list,
265a29a5bd4SVlad Yasevich ntohs(ep->auth_hmacs_list->param_hdr.length));
266a29a5bd4SVlad Yasevich if (ep->auth_chunk_list)
267a29a5bd4SVlad Yasevich memcpy(asoc->c.auth_chunks, ep->auth_chunk_list,
268a29a5bd4SVlad Yasevich ntohs(ep->auth_chunk_list->param_hdr.length));
269a29a5bd4SVlad Yasevich
270a29a5bd4SVlad Yasevich /* Get the AUTH random number for this association */
2713c918704SXin Long p = (struct sctp_paramhdr *)asoc->c.auth_random;
272a29a5bd4SVlad Yasevich p->type = SCTP_PARAM_RANDOM;
2733c918704SXin Long p->length = htons(sizeof(*p) + SCTP_AUTH_RANDOM_LENGTH);
274a29a5bd4SVlad Yasevich get_random_bytes(p+1, SCTP_AUTH_RANDOM_LENGTH);
275a29a5bd4SVlad Yasevich
2761da177e4SLinus Torvalds return asoc;
2771da177e4SLinus Torvalds
2783dbcc105SXin Long stream_free:
279cee360abSXin Long sctp_stream_free(&asoc->stream);
2801da177e4SLinus Torvalds sock_put(asoc->base.sk);
2812e0c9e79SDaniel Borkmann sctp_endpoint_put(asoc->ep);
2821da177e4SLinus Torvalds return NULL;
2831da177e4SLinus Torvalds }
2841da177e4SLinus Torvalds
2851da177e4SLinus Torvalds /* Allocate and initialize a new association */
sctp_association_new(const struct sctp_endpoint * ep,const struct sock * sk,enum sctp_scope scope,gfp_t gfp)2861da177e4SLinus Torvalds struct sctp_association *sctp_association_new(const struct sctp_endpoint *ep,
2871da177e4SLinus Torvalds const struct sock *sk,
2881c662018SXin Long enum sctp_scope scope, gfp_t gfp)
2891da177e4SLinus Torvalds {
2901da177e4SLinus Torvalds struct sctp_association *asoc;
2911da177e4SLinus Torvalds
292939cfa75SDaniel Borkmann asoc = kzalloc(sizeof(*asoc), gfp);
2931da177e4SLinus Torvalds if (!asoc)
2941da177e4SLinus Torvalds goto fail;
2951da177e4SLinus Torvalds
2961da177e4SLinus Torvalds if (!sctp_association_init(asoc, ep, sk, scope, gfp))
2971da177e4SLinus Torvalds goto fail_init;
2981da177e4SLinus Torvalds
2991da177e4SLinus Torvalds SCTP_DBG_OBJCNT_INC(assoc);
300bb33381dSDaniel Borkmann
301bb33381dSDaniel Borkmann pr_debug("Created asoc %p\n", asoc);
3021da177e4SLinus Torvalds
3031da177e4SLinus Torvalds return asoc;
3041da177e4SLinus Torvalds
3051da177e4SLinus Torvalds fail_init:
3061da177e4SLinus Torvalds kfree(asoc);
3071da177e4SLinus Torvalds fail:
3081da177e4SLinus Torvalds return NULL;
3091da177e4SLinus Torvalds }
3101da177e4SLinus Torvalds
3111da177e4SLinus Torvalds /* Free this association if possible. There may still be users, so
3121da177e4SLinus Torvalds * the actual deallocation may be delayed.
3131da177e4SLinus Torvalds */
sctp_association_free(struct sctp_association * asoc)3141da177e4SLinus Torvalds void sctp_association_free(struct sctp_association *asoc)
3151da177e4SLinus Torvalds {
3161da177e4SLinus Torvalds struct sock *sk = asoc->base.sk;
3171da177e4SLinus Torvalds struct sctp_transport *transport;
3181da177e4SLinus Torvalds struct list_head *pos, *temp;
3191da177e4SLinus Torvalds int i;
3201da177e4SLinus Torvalds
321de76e695SVlad Yasevich /* Only real associations count against the endpoint, so
322de76e695SVlad Yasevich * don't bother for if this is a temporary association.
323de76e695SVlad Yasevich */
324d3217b15SXufeng Zhang if (!list_empty(&asoc->asocs)) {
3251da177e4SLinus Torvalds list_del(&asoc->asocs);
3261da177e4SLinus Torvalds
327de76e695SVlad Yasevich /* Decrement the backlog value for a TCP-style listening
328de76e695SVlad Yasevich * socket.
329de76e695SVlad Yasevich */
3301da177e4SLinus Torvalds if (sctp_style(sk, TCP) && sctp_sstate(sk, LISTENING))
3317976a11bSEric Dumazet sk_acceptq_removed(sk);
332de76e695SVlad Yasevich }
3331da177e4SLinus Torvalds
3341da177e4SLinus Torvalds /* Mark as dead, so other users can know this structure is
3351da177e4SLinus Torvalds * going away.
3361da177e4SLinus Torvalds */
3370022d2ddSDaniel Borkmann asoc->base.dead = true;
3381da177e4SLinus Torvalds
3391da177e4SLinus Torvalds /* Dispose of any data lying around in the outqueue. */
3401da177e4SLinus Torvalds sctp_outq_free(&asoc->outqueue);
3411da177e4SLinus Torvalds
3421da177e4SLinus Torvalds /* Dispose of any pending messages for the upper layer. */
3431da177e4SLinus Torvalds sctp_ulpq_free(&asoc->ulpq);
3441da177e4SLinus Torvalds
3451da177e4SLinus Torvalds /* Dispose of any pending chunks on the inqueue. */
3461da177e4SLinus Torvalds sctp_inq_free(&asoc->base.inqueue);
3471da177e4SLinus Torvalds
3488e1ee18cSVlad Yasevich sctp_tsnmap_free(&asoc->peer.tsn_map);
3498e1ee18cSVlad Yasevich
350a8386317SXin Long /* Free stream information. */
351cee360abSXin Long sctp_stream_free(&asoc->stream);
3521da177e4SLinus Torvalds
3537b9438deSXin Long if (asoc->strreset_chunk)
3547b9438deSXin Long sctp_chunk_free(asoc->strreset_chunk);
3557b9438deSXin Long
3561da177e4SLinus Torvalds /* Clean up the bound address list. */
3571da177e4SLinus Torvalds sctp_bind_addr_free(&asoc->base.bind_addr);
3581da177e4SLinus Torvalds
3591da177e4SLinus Torvalds /* Do we need to go through all of our timers and
3601da177e4SLinus Torvalds * delete them? To be safe we will try to delete all, but we
3611da177e4SLinus Torvalds * should be able to go through and make a guess based
3621da177e4SLinus Torvalds * on our state.
3631da177e4SLinus Torvalds */
3641da177e4SLinus Torvalds for (i = SCTP_EVENT_TIMEOUT_NONE; i < SCTP_NUM_TIMEOUT_TYPES; ++i) {
36525cc4ae9SYing Xue if (del_timer(&asoc->timers[i]))
3661da177e4SLinus Torvalds sctp_association_put(asoc);
3671da177e4SLinus Torvalds }
3681da177e4SLinus Torvalds
3691da177e4SLinus Torvalds /* Free peer's cached cookie. */
3701da177e4SLinus Torvalds kfree(asoc->peer.cookie);
371730fc3d0SVlad Yasevich kfree(asoc->peer.peer_random);
372730fc3d0SVlad Yasevich kfree(asoc->peer.peer_chunks);
373730fc3d0SVlad Yasevich kfree(asoc->peer.peer_hmacs);
3741da177e4SLinus Torvalds
3751da177e4SLinus Torvalds /* Release the transport structures. */
3761da177e4SLinus Torvalds list_for_each_safe(pos, temp, &asoc->peer.transport_addr_list) {
3771da177e4SLinus Torvalds transport = list_entry(pos, struct sctp_transport, transports);
37845122ca2SThomas Graf list_del_rcu(pos);
3794f008781SXin Long sctp_unhash_transport(transport);
3801da177e4SLinus Torvalds sctp_transport_free(transport);
3811da177e4SLinus Torvalds }
3821da177e4SLinus Torvalds
3833f7a87d2SFrank Filz asoc->peer.transport_count = 0;
3843f7a87d2SFrank Filz
385a000c01eSWei Yongjun sctp_asconf_queue_teardown(asoc);
3861da177e4SLinus Torvalds
3878a07eb0aSMichio Honda /* Free pending address space being deleted */
3888a07eb0aSMichio Honda kfree(asoc->asconf_addr_del_pending);
3898a07eb0aSMichio Honda
390a29a5bd4SVlad Yasevich /* AUTH - Free the endpoint shared keys */
391a29a5bd4SVlad Yasevich sctp_auth_destroy_keys(&asoc->endpoint_shared_keys);
392a29a5bd4SVlad Yasevich
393a29a5bd4SVlad Yasevich /* AUTH - Free the association shared key */
394a29a5bd4SVlad Yasevich sctp_auth_key_put(asoc->asoc_shared_key);
395a29a5bd4SVlad Yasevich
3961da177e4SLinus Torvalds sctp_association_put(asoc);
3971da177e4SLinus Torvalds }
3981da177e4SLinus Torvalds
3991da177e4SLinus Torvalds /* Cleanup and free up an association. */
sctp_association_destroy(struct sctp_association * asoc)4001da177e4SLinus Torvalds static void sctp_association_destroy(struct sctp_association *asoc)
4011da177e4SLinus Torvalds {
402bb33381dSDaniel Borkmann if (unlikely(!asoc->base.dead)) {
403bb33381dSDaniel Borkmann WARN(1, "Attempt to destroy undead association %p!\n", asoc);
404bb33381dSDaniel Borkmann return;
405bb33381dSDaniel Borkmann }
4061da177e4SLinus Torvalds
4071da177e4SLinus Torvalds sctp_endpoint_put(asoc->ep);
4081da177e4SLinus Torvalds sock_put(asoc->base.sk);
4091da177e4SLinus Torvalds
4101da177e4SLinus Torvalds if (asoc->assoc_id != 0) {
4111da177e4SLinus Torvalds spin_lock_bh(&sctp_assocs_id_lock);
4121da177e4SLinus Torvalds idr_remove(&sctp_assocs_id, asoc->assoc_id);
4131da177e4SLinus Torvalds spin_unlock_bh(&sctp_assocs_id_lock);
4141da177e4SLinus Torvalds }
4151da177e4SLinus Torvalds
416547b792cSIlpo Järvinen WARN_ON(atomic_read(&asoc->rmem_alloc));
417049b3ff5SNeil Horman
418fb6df5a6SXin Long kfree_rcu(asoc, rcu);
4191da177e4SLinus Torvalds SCTP_DBG_OBJCNT_DEC(assoc);
4201da177e4SLinus Torvalds }
4211da177e4SLinus Torvalds
4221da177e4SLinus Torvalds /* Change the primary destination address for the peer. */
sctp_assoc_set_primary(struct sctp_association * asoc,struct sctp_transport * transport)4231da177e4SLinus Torvalds void sctp_assoc_set_primary(struct sctp_association *asoc,
4241da177e4SLinus Torvalds struct sctp_transport *transport)
4251da177e4SLinus Torvalds {
426319fa2a2SVlad Yasevich int changeover = 0;
427319fa2a2SVlad Yasevich
428319fa2a2SVlad Yasevich /* it's a changeover only if we already have a primary path
429319fa2a2SVlad Yasevich * that we are changing
430319fa2a2SVlad Yasevich */
431319fa2a2SVlad Yasevich if (asoc->peer.primary_path != NULL &&
432319fa2a2SVlad Yasevich asoc->peer.primary_path != transport)
433319fa2a2SVlad Yasevich changeover = 1 ;
434319fa2a2SVlad Yasevich
4351da177e4SLinus Torvalds asoc->peer.primary_path = transport;
43650ce4c09SJonas Falkevik sctp_ulpevent_notify_peer_addr_change(transport,
4375cd0b917SXin Long SCTP_ADDR_MADE_PRIM, 0);
4381da177e4SLinus Torvalds
4391da177e4SLinus Torvalds /* Set a default msg_name for events. */
4401da177e4SLinus Torvalds memcpy(&asoc->peer.primary_addr, &transport->ipaddr,
4411da177e4SLinus Torvalds sizeof(union sctp_addr));
4421da177e4SLinus Torvalds
4431da177e4SLinus Torvalds /* If the primary path is changing, assume that the
4441da177e4SLinus Torvalds * user wants to use this new path.
4451da177e4SLinus Torvalds */
446ad8fec17SSridhar Samudrala if ((transport->state == SCTP_ACTIVE) ||
447ad8fec17SSridhar Samudrala (transport->state == SCTP_UNKNOWN))
4481da177e4SLinus Torvalds asoc->peer.active_path = transport;
4491da177e4SLinus Torvalds
4501da177e4SLinus Torvalds /*
4511da177e4SLinus Torvalds * SFR-CACC algorithm:
4521da177e4SLinus Torvalds * Upon the receipt of a request to change the primary
4531da177e4SLinus Torvalds * destination address, on the data structure for the new
4541da177e4SLinus Torvalds * primary destination, the sender MUST do the following:
4551da177e4SLinus Torvalds *
4561da177e4SLinus Torvalds * 1) If CHANGEOVER_ACTIVE is set, then there was a switch
4571da177e4SLinus Torvalds * to this destination address earlier. The sender MUST set
4581da177e4SLinus Torvalds * CYCLING_CHANGEOVER to indicate that this switch is a
4591da177e4SLinus Torvalds * double switch to the same destination address.
460e0e9db17SVlad Yasevich *
461e0e9db17SVlad Yasevich * Really, only bother is we have data queued or outstanding on
462e0e9db17SVlad Yasevich * the association.
4631da177e4SLinus Torvalds */
464e0e9db17SVlad Yasevich if (!asoc->outqueue.outstanding_bytes && !asoc->outqueue.out_qlen)
465e0e9db17SVlad Yasevich return;
466e0e9db17SVlad Yasevich
4671da177e4SLinus Torvalds if (transport->cacc.changeover_active)
468319fa2a2SVlad Yasevich transport->cacc.cycling_changeover = changeover;
4691da177e4SLinus Torvalds
4701da177e4SLinus Torvalds /* 2) The sender MUST set CHANGEOVER_ACTIVE to indicate that
4711da177e4SLinus Torvalds * a changeover has occurred.
4721da177e4SLinus Torvalds */
473319fa2a2SVlad Yasevich transport->cacc.changeover_active = changeover;
4741da177e4SLinus Torvalds
4751da177e4SLinus Torvalds /* 3) The sender MUST store the next TSN to be sent in
4761da177e4SLinus Torvalds * next_tsn_at_change.
4771da177e4SLinus Torvalds */
4781da177e4SLinus Torvalds transport->cacc.next_tsn_at_change = asoc->next_tsn;
4791da177e4SLinus Torvalds }
4801da177e4SLinus Torvalds
4813f7a87d2SFrank Filz /* Remove a transport from an association. */
sctp_assoc_rm_peer(struct sctp_association * asoc,struct sctp_transport * peer)4823f7a87d2SFrank Filz void sctp_assoc_rm_peer(struct sctp_association *asoc,
4833f7a87d2SFrank Filz struct sctp_transport *peer)
4843f7a87d2SFrank Filz {
4853f7a87d2SFrank Filz struct sctp_transport *transport;
486df132effSXin Long struct list_head *pos;
487df132effSXin Long struct sctp_chunk *ch;
4883f7a87d2SFrank Filz
489bb33381dSDaniel Borkmann pr_debug("%s: association:%p addr:%pISpc\n",
490bb33381dSDaniel Borkmann __func__, asoc, &peer->ipaddr.sa);
4913f7a87d2SFrank Filz
4923f7a87d2SFrank Filz /* If we are to remove the current retran_path, update it
4933f7a87d2SFrank Filz * to the next peer before removing this peer from the list.
4943f7a87d2SFrank Filz */
4953f7a87d2SFrank Filz if (asoc->peer.retran_path == peer)
4963f7a87d2SFrank Filz sctp_assoc_update_retran_path(asoc);
4973f7a87d2SFrank Filz
4983f7a87d2SFrank Filz /* Remove this peer from the list. */
49945122ca2SThomas Graf list_del_rcu(&peer->transports);
5004f008781SXin Long /* Remove this peer from the transport hashtable */
5014f008781SXin Long sctp_unhash_transport(peer);
5023f7a87d2SFrank Filz
5033f7a87d2SFrank Filz /* Get the first transport of asoc. */
5043f7a87d2SFrank Filz pos = asoc->peer.transport_addr_list.next;
5053f7a87d2SFrank Filz transport = list_entry(pos, struct sctp_transport, transports);
5063f7a87d2SFrank Filz
5073f7a87d2SFrank Filz /* Update any entries that match the peer to be deleted. */
5083f7a87d2SFrank Filz if (asoc->peer.primary_path == peer)
5093f7a87d2SFrank Filz sctp_assoc_set_primary(asoc, transport);
5103f7a87d2SFrank Filz if (asoc->peer.active_path == peer)
5113f7a87d2SFrank Filz asoc->peer.active_path = transport;
5129494c7c5SWei Yongjun if (asoc->peer.retran_path == peer)
5139494c7c5SWei Yongjun asoc->peer.retran_path = transport;
5143f7a87d2SFrank Filz if (asoc->peer.last_data_from == peer)
5153f7a87d2SFrank Filz asoc->peer.last_data_from = transport;
5163f7a87d2SFrank Filz
5177b9438deSXin Long if (asoc->strreset_chunk &&
5187b9438deSXin Long asoc->strreset_chunk->transport == peer) {
5197b9438deSXin Long asoc->strreset_chunk->transport = transport;
5207b9438deSXin Long sctp_transport_reset_reconf_timer(transport);
5217b9438deSXin Long }
5227b9438deSXin Long
5233f7a87d2SFrank Filz /* If we remove the transport an INIT was last sent to, set it to
5243f7a87d2SFrank Filz * NULL. Combined with the update of the retran path above, this
5253f7a87d2SFrank Filz * will cause the next INIT to be sent to the next available
5263f7a87d2SFrank Filz * transport, maintaining the cycle.
5273f7a87d2SFrank Filz */
5283f7a87d2SFrank Filz if (asoc->init_last_sent_to == peer)
5293f7a87d2SFrank Filz asoc->init_last_sent_to = NULL;
5303f7a87d2SFrank Filz
5316345b199SWei Yongjun /* If we remove the transport an SHUTDOWN was last sent to, set it
5326345b199SWei Yongjun * to NULL. Combined with the update of the retran path above, this
5336345b199SWei Yongjun * will cause the next SHUTDOWN to be sent to the next available
5346345b199SWei Yongjun * transport, maintaining the cycle.
5356345b199SWei Yongjun */
5366345b199SWei Yongjun if (asoc->shutdown_last_sent_to == peer)
5376345b199SWei Yongjun asoc->shutdown_last_sent_to = NULL;
5386345b199SWei Yongjun
53910a43ceaSWei Yongjun /* If we remove the transport an ASCONF was last sent to, set it to
54010a43ceaSWei Yongjun * NULL.
54110a43ceaSWei Yongjun */
54210a43ceaSWei Yongjun if (asoc->addip_last_asconf &&
54310a43ceaSWei Yongjun asoc->addip_last_asconf->transport == peer)
54410a43ceaSWei Yongjun asoc->addip_last_asconf->transport = NULL;
54510a43ceaSWei Yongjun
54631b02e15SVlad Yasevich /* If we have something on the transmitted list, we have to
54731b02e15SVlad Yasevich * save it off. The best place is the active path.
54831b02e15SVlad Yasevich */
54931b02e15SVlad Yasevich if (!list_empty(&peer->transmitted)) {
55031b02e15SVlad Yasevich struct sctp_transport *active = asoc->peer.active_path;
55131b02e15SVlad Yasevich
55231b02e15SVlad Yasevich /* Reset the transport of each chunk on this list */
55331b02e15SVlad Yasevich list_for_each_entry(ch, &peer->transmitted,
55431b02e15SVlad Yasevich transmitted_list) {
55531b02e15SVlad Yasevich ch->transport = NULL;
55631b02e15SVlad Yasevich ch->rtt_in_progress = 0;
55731b02e15SVlad Yasevich }
55831b02e15SVlad Yasevich
55931b02e15SVlad Yasevich list_splice_tail_init(&peer->transmitted,
56031b02e15SVlad Yasevich &active->transmitted);
56131b02e15SVlad Yasevich
56231b02e15SVlad Yasevich /* Start a T3 timer here in case it wasn't running so
56331b02e15SVlad Yasevich * that these migrated packets have a chance to get
5642bccbadfSwangweidong * retransmitted.
56531b02e15SVlad Yasevich */
56631b02e15SVlad Yasevich if (!timer_pending(&active->T3_rtx_timer))
56731b02e15SVlad Yasevich if (!mod_timer(&active->T3_rtx_timer,
56831b02e15SVlad Yasevich jiffies + active->rto))
56931b02e15SVlad Yasevich sctp_transport_hold(active);
57031b02e15SVlad Yasevich }
57131b02e15SVlad Yasevich
572df132effSXin Long list_for_each_entry(ch, &asoc->outqueue.out_chunk_list, list)
573df132effSXin Long if (ch->transport == peer)
574df132effSXin Long ch->transport = NULL;
575df132effSXin Long
5763f7a87d2SFrank Filz asoc->peer.transport_count--;
5773f7a87d2SFrank Filz
57850ce4c09SJonas Falkevik sctp_ulpevent_notify_peer_addr_change(peer, SCTP_ADDR_REMOVED, 0);
5793f7a87d2SFrank Filz sctp_transport_free(peer);
5803f7a87d2SFrank Filz }
5813f7a87d2SFrank Filz
5821da177e4SLinus Torvalds /* Add a transport address to an association. */
sctp_assoc_add_peer(struct sctp_association * asoc,const union sctp_addr * addr,const gfp_t gfp,const int peer_state)5831da177e4SLinus Torvalds struct sctp_transport *sctp_assoc_add_peer(struct sctp_association *asoc,
5841da177e4SLinus Torvalds const union sctp_addr *addr,
585dd0fc66fSAl Viro const gfp_t gfp,
5863f7a87d2SFrank Filz const int peer_state)
5871da177e4SLinus Torvalds {
5881da177e4SLinus Torvalds struct sctp_transport *peer;
5891da177e4SLinus Torvalds struct sctp_sock *sp;
5901da177e4SLinus Torvalds unsigned short port;
5911da177e4SLinus Torvalds
5921da177e4SLinus Torvalds sp = sctp_sk(asoc->base.sk);
5931da177e4SLinus Torvalds
5941da177e4SLinus Torvalds /* AF_INET and AF_INET6 share common port field. */
5954bdf4b5fSAl Viro port = ntohs(addr->v4.sin_port);
5961da177e4SLinus Torvalds
597bb33381dSDaniel Borkmann pr_debug("%s: association:%p addr:%pISpc state:%d\n", __func__,
598bb33381dSDaniel Borkmann asoc, &addr->sa, peer_state);
5993f7a87d2SFrank Filz
6001da177e4SLinus Torvalds /* Set the port if it has not been set yet. */
6011da177e4SLinus Torvalds if (0 == asoc->peer.port)
6021da177e4SLinus Torvalds asoc->peer.port = port;
6031da177e4SLinus Torvalds
6041da177e4SLinus Torvalds /* Check to see if this is a duplicate. */
6051da177e4SLinus Torvalds peer = sctp_assoc_lookup_paddr(asoc, addr);
6063f7a87d2SFrank Filz if (peer) {
607add52379SVlad Yasevich /* An UNKNOWN state is only set on transports added by
608add52379SVlad Yasevich * user in sctp_connectx() call. Such transports should be
609add52379SVlad Yasevich * considered CONFIRMED per RFC 4960, Section 5.4.
610add52379SVlad Yasevich */
611ad8fec17SSridhar Samudrala if (peer->state == SCTP_UNKNOWN) {
6123f7a87d2SFrank Filz peer->state = SCTP_ACTIVE;
613ad8fec17SSridhar Samudrala }
6141da177e4SLinus Torvalds return peer;
6153f7a87d2SFrank Filz }
6161da177e4SLinus Torvalds
6174e7696d9SXin Long peer = sctp_transport_new(asoc->base.net, addr, gfp);
6181da177e4SLinus Torvalds if (!peer)
6191da177e4SLinus Torvalds return NULL;
6201da177e4SLinus Torvalds
6211da177e4SLinus Torvalds sctp_transport_set_owner(peer, asoc);
6221da177e4SLinus Torvalds
62352ccb8e9SFrank Filz /* Initialize the peer's heartbeat interval based on the
62452ccb8e9SFrank Filz * association configured value.
62552ccb8e9SFrank Filz */
62652ccb8e9SFrank Filz peer->hbinterval = asoc->hbinterval;
627d1e462a7SXin Long peer->probe_interval = asoc->probe_interval;
62852ccb8e9SFrank Filz
629e8a3001cSXin Long peer->encap_port = asoc->encap_port;
630e8a3001cSXin Long
63152ccb8e9SFrank Filz /* Set the path max_retrans. */
63252ccb8e9SFrank Filz peer->pathmaxrxt = asoc->pathmaxrxt;
63352ccb8e9SFrank Filz
6342bccbadfSwangweidong /* And the partial failure retrans threshold */
6355aa93bcfSNeil Horman peer->pf_retrans = asoc->pf_retrans;
63634515e94SXin Long /* And the primary path switchover retrans threshold */
63734515e94SXin Long peer->ps_retrans = asoc->ps_retrans;
6385aa93bcfSNeil Horman
63952ccb8e9SFrank Filz /* Initialize the peer's SACK delay timeout based on the
64052ccb8e9SFrank Filz * association configured value.
64152ccb8e9SFrank Filz */
64252ccb8e9SFrank Filz peer->sackdelay = asoc->sackdelay;
643d364d927SWei Yongjun peer->sackfreq = asoc->sackfreq;
64452ccb8e9SFrank Filz
6454be4139fSXin Long if (addr->sa.sa_family == AF_INET6) {
6464be4139fSXin Long __be32 info = addr->v6.sin6_flowinfo;
6474be4139fSXin Long
6484be4139fSXin Long if (info) {
6494be4139fSXin Long peer->flowlabel = ntohl(info & IPV6_FLOWLABEL_MASK);
6504be4139fSXin Long peer->flowlabel |= SCTP_FLOWLABEL_SET_MASK;
6514be4139fSXin Long } else {
6528a9c58d2SXin Long peer->flowlabel = asoc->flowlabel;
6534be4139fSXin Long }
6544be4139fSXin Long }
6558a9c58d2SXin Long peer->dscp = asoc->dscp;
6568a9c58d2SXin Long
65752ccb8e9SFrank Filz /* Enable/disable heartbeat, SACK delay, and path MTU discovery
65852ccb8e9SFrank Filz * based on association setting.
65952ccb8e9SFrank Filz */
66052ccb8e9SFrank Filz peer->param_flags = asoc->param_flags;
66152ccb8e9SFrank Filz
6621da177e4SLinus Torvalds /* Initialize the pmtu of the transport. */
663800e00c1SMarcelo Ricardo Leitner sctp_transport_route(peer, NULL, sp);
6641da177e4SLinus Torvalds
6651da177e4SLinus Torvalds /* If this is the first transport addr on this association,
6661da177e4SLinus Torvalds * initialize the association PMTU to the peer's PMTU.
6671da177e4SLinus Torvalds * If not and the current association PMTU is higher than the new
6681da177e4SLinus Torvalds * peer's PMTU, reset the association PMTU to the new peer's PMTU.
6691da177e4SLinus Torvalds */
670c4b2893dSMarcelo Ricardo Leitner sctp_assoc_set_pmtu(asoc, asoc->pathmtu ?
671c4b2893dSMarcelo Ricardo Leitner min_t(int, peer->pathmtu, asoc->pathmtu) :
672c4b2893dSMarcelo Ricardo Leitner peer->pathmtu);
673bb33381dSDaniel Borkmann
6746d0ccbacSFlorian Westphal peer->pmtu_pending = 0;
6751da177e4SLinus Torvalds
6761da177e4SLinus Torvalds /* The asoc->peer.port might not be meaningful yet, but
6771da177e4SLinus Torvalds * initialize the packet structure anyway.
6781da177e4SLinus Torvalds */
6791da177e4SLinus Torvalds sctp_packet_init(&peer->packet, peer, asoc->base.bind_addr.port,
6801da177e4SLinus Torvalds asoc->peer.port);
6811da177e4SLinus Torvalds
6821da177e4SLinus Torvalds /* 7.2.1 Slow-Start
6831da177e4SLinus Torvalds *
6841da177e4SLinus Torvalds * o The initial cwnd before DATA transmission or after a sufficiently
6851da177e4SLinus Torvalds * long idle period MUST be set to
6861da177e4SLinus Torvalds * min(4*MTU, max(2*MTU, 4380 bytes))
6871da177e4SLinus Torvalds *
6881da177e4SLinus Torvalds * o The initial value of ssthresh MAY be arbitrarily high
6891da177e4SLinus Torvalds * (for example, implementations MAY use the size of the
6901da177e4SLinus Torvalds * receiver advertised window).
6911da177e4SLinus Torvalds */
69252ccb8e9SFrank Filz peer->cwnd = min(4*asoc->pathmtu, max_t(__u32, 2*asoc->pathmtu, 4380));
6931da177e4SLinus Torvalds
6941da177e4SLinus Torvalds /* At this point, we may not have the receiver's advertised window,
6951da177e4SLinus Torvalds * so initialize ssthresh to the default value and it will be set
6961da177e4SLinus Torvalds * later when we process the INIT.
6971da177e4SLinus Torvalds */
6981da177e4SLinus Torvalds peer->ssthresh = SCTP_DEFAULT_MAXWINDOW;
6991da177e4SLinus Torvalds
7001da177e4SLinus Torvalds peer->partial_bytes_acked = 0;
7011da177e4SLinus Torvalds peer->flight_size = 0;
70246d5a808SVlad Yasevich peer->burst_limited = 0;
7031da177e4SLinus Torvalds
7041da177e4SLinus Torvalds /* Set the transport's RTO.initial value */
7051da177e4SLinus Torvalds peer->rto = asoc->rto_initial;
706196d6759SMichele Baldessari sctp_max_rto(asoc, peer);
7071da177e4SLinus Torvalds
7083f7a87d2SFrank Filz /* Set the peer's active state. */
7093f7a87d2SFrank Filz peer->state = peer_state;
7103f7a87d2SFrank Filz
7117fda702fSXin Long /* Add this peer into the transport hashtable */
7127fda702fSXin Long if (sctp_hash_transport(peer)) {
7137fda702fSXin Long sctp_transport_free(peer);
7147fda702fSXin Long return NULL;
7157fda702fSXin Long }
7167fda702fSXin Long
7177307e4faSXin Long sctp_transport_pl_reset(peer);
7187307e4faSXin Long
7191da177e4SLinus Torvalds /* Attach the remote transport to our asoc. */
72045122ca2SThomas Graf list_add_tail_rcu(&peer->transports, &asoc->peer.transport_addr_list);
7213f7a87d2SFrank Filz asoc->peer.transport_count++;
7221da177e4SLinus Torvalds
72350ce4c09SJonas Falkevik sctp_ulpevent_notify_peer_addr_change(peer, SCTP_ADDR_ADDED, 0);
7244b774032SXin Long
7251da177e4SLinus Torvalds /* If we do not yet have a primary path, set one. */
7261da177e4SLinus Torvalds if (!asoc->peer.primary_path) {
7271da177e4SLinus Torvalds sctp_assoc_set_primary(asoc, peer);
7281da177e4SLinus Torvalds asoc->peer.retran_path = peer;
7291da177e4SLinus Torvalds }
7301da177e4SLinus Torvalds
731fbdf501cSVlad Yasevich if (asoc->peer.active_path == asoc->peer.retran_path &&
732fbdf501cSVlad Yasevich peer->state != SCTP_UNCONFIRMED) {
7331da177e4SLinus Torvalds asoc->peer.retran_path = peer;
7343f7a87d2SFrank Filz }
7351da177e4SLinus Torvalds
7361da177e4SLinus Torvalds return peer;
7371da177e4SLinus Torvalds }
7381da177e4SLinus Torvalds
7391da177e4SLinus Torvalds /* Delete a transport address from an association. */
sctp_assoc_del_peer(struct sctp_association * asoc,const union sctp_addr * addr)7401da177e4SLinus Torvalds void sctp_assoc_del_peer(struct sctp_association *asoc,
7411da177e4SLinus Torvalds const union sctp_addr *addr)
7421da177e4SLinus Torvalds {
7431da177e4SLinus Torvalds struct list_head *pos;
7441da177e4SLinus Torvalds struct list_head *temp;
7451da177e4SLinus Torvalds struct sctp_transport *transport;
7461da177e4SLinus Torvalds
7471da177e4SLinus Torvalds list_for_each_safe(pos, temp, &asoc->peer.transport_addr_list) {
7481da177e4SLinus Torvalds transport = list_entry(pos, struct sctp_transport, transports);
7491da177e4SLinus Torvalds if (sctp_cmp_addr_exact(addr, &transport->ipaddr)) {
7503f7a87d2SFrank Filz /* Do book keeping for removing the peer and free it. */
7513f7a87d2SFrank Filz sctp_assoc_rm_peer(asoc, transport);
7521da177e4SLinus Torvalds break;
7531da177e4SLinus Torvalds }
7541da177e4SLinus Torvalds }
7551da177e4SLinus Torvalds }
7561da177e4SLinus Torvalds
7571da177e4SLinus Torvalds /* Lookup a transport by address. */
sctp_assoc_lookup_paddr(const struct sctp_association * asoc,const union sctp_addr * address)7581da177e4SLinus Torvalds struct sctp_transport *sctp_assoc_lookup_paddr(
7591da177e4SLinus Torvalds const struct sctp_association *asoc,
7601da177e4SLinus Torvalds const union sctp_addr *address)
7611da177e4SLinus Torvalds {
7621da177e4SLinus Torvalds struct sctp_transport *t;
7631da177e4SLinus Torvalds
7641da177e4SLinus Torvalds /* Cycle through all transports searching for a peer address. */
7651da177e4SLinus Torvalds
7669dbc15f0SRobert P. J. Day list_for_each_entry(t, &asoc->peer.transport_addr_list,
7679dbc15f0SRobert P. J. Day transports) {
7681da177e4SLinus Torvalds if (sctp_cmp_addr_exact(address, &t->ipaddr))
7691da177e4SLinus Torvalds return t;
7701da177e4SLinus Torvalds }
7711da177e4SLinus Torvalds
7721da177e4SLinus Torvalds return NULL;
7731da177e4SLinus Torvalds }
7741da177e4SLinus Torvalds
77542e30bf3SVlad Yasevich /* Remove all transports except a give one */
sctp_assoc_del_nonprimary_peers(struct sctp_association * asoc,struct sctp_transport * primary)77642e30bf3SVlad Yasevich void sctp_assoc_del_nonprimary_peers(struct sctp_association *asoc,
77742e30bf3SVlad Yasevich struct sctp_transport *primary)
77842e30bf3SVlad Yasevich {
77942e30bf3SVlad Yasevich struct sctp_transport *temp;
78042e30bf3SVlad Yasevich struct sctp_transport *t;
78142e30bf3SVlad Yasevich
78242e30bf3SVlad Yasevich list_for_each_entry_safe(t, temp, &asoc->peer.transport_addr_list,
78342e30bf3SVlad Yasevich transports) {
78442e30bf3SVlad Yasevich /* if the current transport is not the primary one, delete it */
78542e30bf3SVlad Yasevich if (t != primary)
78642e30bf3SVlad Yasevich sctp_assoc_rm_peer(asoc, t);
78742e30bf3SVlad Yasevich }
78842e30bf3SVlad Yasevich }
78942e30bf3SVlad Yasevich
7901da177e4SLinus Torvalds /* Engage in transport control operations.
7911da177e4SLinus Torvalds * Mark the transport up or down and send a notification to the user.
7921da177e4SLinus Torvalds * Select and update the new active and retran paths.
7931da177e4SLinus Torvalds */
sctp_assoc_control_transport(struct sctp_association * asoc,struct sctp_transport * transport,enum sctp_transport_cmd command,sctp_sn_error_t error)7941da177e4SLinus Torvalds void sctp_assoc_control_transport(struct sctp_association *asoc,
7951da177e4SLinus Torvalds struct sctp_transport *transport,
7960ceaeebeSXin Long enum sctp_transport_cmd command,
7971da177e4SLinus Torvalds sctp_sn_error_t error)
7981da177e4SLinus Torvalds {
799768e1518SXin Long int spc_state = SCTP_ADDR_AVAILABLE;
8005aa93bcfSNeil Horman bool ulp_notify = true;
8011da177e4SLinus Torvalds
8021da177e4SLinus Torvalds /* Record the transition on the transport. */
8031da177e4SLinus Torvalds switch (command) {
8041da177e4SLinus Torvalds case SCTP_TRANSPORT_UP:
8051ae4114dSVlad Yasevich /* If we are moving from UNCONFIRMED state due
8061ae4114dSVlad Yasevich * to heartbeat success, report the SCTP_ADDR_CONFIRMED
8071ae4114dSVlad Yasevich * state to the user, otherwise report SCTP_ADDR_AVAILABLE.
8081ae4114dSVlad Yasevich */
809768e1518SXin Long if (transport->state == SCTP_PF &&
810768e1518SXin Long asoc->pf_expose != SCTP_PF_EXPOSE_ENABLE)
8115aa93bcfSNeil Horman ulp_notify = false;
812768e1518SXin Long else if (transport->state == SCTP_UNCONFIRMED &&
813768e1518SXin Long error == SCTP_HEARTBEAT_SUCCESS)
814768e1518SXin Long spc_state = SCTP_ADDR_CONFIRMED;
815768e1518SXin Long
8161ae4114dSVlad Yasevich transport->state = SCTP_ACTIVE;
8177307e4faSXin Long sctp_transport_pl_reset(transport);
8181da177e4SLinus Torvalds break;
8191da177e4SLinus Torvalds
8201da177e4SLinus Torvalds case SCTP_TRANSPORT_DOWN:
82140187886SVlad Yasevich /* If the transport was never confirmed, do not transition it
82240187886SVlad Yasevich * to inactive state. Also, release the cached route since
82340187886SVlad Yasevich * there may be a better route next time.
824cc75689aSVlad Yasevich */
825768e1518SXin Long if (transport->state != SCTP_UNCONFIRMED) {
8263f7a87d2SFrank Filz transport->state = SCTP_INACTIVE;
8277307e4faSXin Long sctp_transport_pl_reset(transport);
828768e1518SXin Long spc_state = SCTP_ADDR_UNREACHABLE;
829768e1518SXin Long } else {
830c86a773cSJulian Anastasov sctp_transport_dst_release(transport);
831061079acSzhuyj ulp_notify = false;
83240187886SVlad Yasevich }
8331da177e4SLinus Torvalds break;
8341da177e4SLinus Torvalds
8355aa93bcfSNeil Horman case SCTP_TRANSPORT_PF:
8365aa93bcfSNeil Horman transport->state = SCTP_PF;
837768e1518SXin Long if (asoc->pf_expose != SCTP_PF_EXPOSE_ENABLE)
8385aa93bcfSNeil Horman ulp_notify = false;
839768e1518SXin Long else
840768e1518SXin Long spc_state = SCTP_ADDR_POTENTIALLY_FAILED;
8415aa93bcfSNeil Horman break;
8425aa93bcfSNeil Horman
8431da177e4SLinus Torvalds default:
8441da177e4SLinus Torvalds return;
8453ff50b79SStephen Hemminger }
8461da177e4SLinus Torvalds
847b82e8f31SDaniel Borkmann /* Generate and send a SCTP_PEER_ADDR_CHANGE notification
848b82e8f31SDaniel Borkmann * to the user.
8491da177e4SLinus Torvalds */
8504b774032SXin Long if (ulp_notify)
85150ce4c09SJonas Falkevik sctp_ulpevent_notify_peer_addr_change(transport,
8524b774032SXin Long spc_state, error);
8531da177e4SLinus Torvalds
8541da177e4SLinus Torvalds /* Select new active and retran paths. */
855b82e8f31SDaniel Borkmann sctp_select_active_and_retran_path(asoc);
8561da177e4SLinus Torvalds }
8571da177e4SLinus Torvalds
8581da177e4SLinus Torvalds /* Hold a reference to an association. */
sctp_association_hold(struct sctp_association * asoc)8591da177e4SLinus Torvalds void sctp_association_hold(struct sctp_association *asoc)
8601da177e4SLinus Torvalds {
861c638457aSReshetova, Elena refcount_inc(&asoc->base.refcnt);
8621da177e4SLinus Torvalds }
8631da177e4SLinus Torvalds
8641da177e4SLinus Torvalds /* Release a reference to an association and cleanup
8651da177e4SLinus Torvalds * if there are no more references.
8661da177e4SLinus Torvalds */
sctp_association_put(struct sctp_association * asoc)8671da177e4SLinus Torvalds void sctp_association_put(struct sctp_association *asoc)
8681da177e4SLinus Torvalds {
869c638457aSReshetova, Elena if (refcount_dec_and_test(&asoc->base.refcnt))
8701da177e4SLinus Torvalds sctp_association_destroy(asoc);
8711da177e4SLinus Torvalds }
8721da177e4SLinus Torvalds
8731da177e4SLinus Torvalds /* Allocate the next TSN, Transmission Sequence Number, for the given
8741da177e4SLinus Torvalds * association.
8751da177e4SLinus Torvalds */
sctp_association_get_next_tsn(struct sctp_association * asoc)8761da177e4SLinus Torvalds __u32 sctp_association_get_next_tsn(struct sctp_association *asoc)
8771da177e4SLinus Torvalds {
8781da177e4SLinus Torvalds /* From Section 1.6 Serial Number Arithmetic:
8791da177e4SLinus Torvalds * Transmission Sequence Numbers wrap around when they reach
8801da177e4SLinus Torvalds * 2**32 - 1. That is, the next TSN a DATA chunk MUST use
8811da177e4SLinus Torvalds * after transmitting TSN = 2*32 - 1 is TSN = 0.
8821da177e4SLinus Torvalds */
8831da177e4SLinus Torvalds __u32 retval = asoc->next_tsn;
8841da177e4SLinus Torvalds asoc->next_tsn++;
8851da177e4SLinus Torvalds asoc->unack_data++;
8861da177e4SLinus Torvalds
8871da177e4SLinus Torvalds return retval;
8881da177e4SLinus Torvalds }
8891da177e4SLinus Torvalds
8901da177e4SLinus Torvalds /* Compare two addresses to see if they match. Wildcard addresses
8911da177e4SLinus Torvalds * only match themselves.
8921da177e4SLinus Torvalds */
sctp_cmp_addr_exact(const union sctp_addr * ss1,const union sctp_addr * ss2)8931da177e4SLinus Torvalds int sctp_cmp_addr_exact(const union sctp_addr *ss1,
8941da177e4SLinus Torvalds const union sctp_addr *ss2)
8951da177e4SLinus Torvalds {
8961da177e4SLinus Torvalds struct sctp_af *af;
8971da177e4SLinus Torvalds
8981da177e4SLinus Torvalds af = sctp_get_af_specific(ss1->sa.sa_family);
8991da177e4SLinus Torvalds if (unlikely(!af))
9001da177e4SLinus Torvalds return 0;
9011da177e4SLinus Torvalds
9021da177e4SLinus Torvalds return af->cmp_addr(ss1, ss2);
9031da177e4SLinus Torvalds }
9041da177e4SLinus Torvalds
9051da177e4SLinus Torvalds /* Return an ecne chunk to get prepended to a packet.
9061da177e4SLinus Torvalds * Note: We are sly and return a shared, prealloced chunk. FIXME:
9071da177e4SLinus Torvalds * No we don't, but we could/should.
9081da177e4SLinus Torvalds */
sctp_get_ecne_prepend(struct sctp_association * asoc)9091da177e4SLinus Torvalds struct sctp_chunk *sctp_get_ecne_prepend(struct sctp_association *asoc)
9101da177e4SLinus Torvalds {
9118b7318d3Swangweidong if (!asoc->need_ecne)
9128b7318d3Swangweidong return NULL;
9131da177e4SLinus Torvalds
9141da177e4SLinus Torvalds /* Send ECNE if needed.
9151da177e4SLinus Torvalds * Not being able to allocate a chunk here is not deadly.
9161da177e4SLinus Torvalds */
9178b7318d3Swangweidong return sctp_make_ecne(asoc, asoc->last_ecne_tsn);
9181da177e4SLinus Torvalds }
9191da177e4SLinus Torvalds
9201da177e4SLinus Torvalds /*
9211da177e4SLinus Torvalds * Find which transport this TSN was sent on.
9221da177e4SLinus Torvalds */
sctp_assoc_lookup_tsn(struct sctp_association * asoc,__u32 tsn)9231da177e4SLinus Torvalds struct sctp_transport *sctp_assoc_lookup_tsn(struct sctp_association *asoc,
9241da177e4SLinus Torvalds __u32 tsn)
9251da177e4SLinus Torvalds {
9261da177e4SLinus Torvalds struct sctp_transport *active;
9271da177e4SLinus Torvalds struct sctp_transport *match;
9281da177e4SLinus Torvalds struct sctp_transport *transport;
9291da177e4SLinus Torvalds struct sctp_chunk *chunk;
930dbc16db1SAl Viro __be32 key = htonl(tsn);
9311da177e4SLinus Torvalds
9321da177e4SLinus Torvalds match = NULL;
9331da177e4SLinus Torvalds
9341da177e4SLinus Torvalds /*
9351da177e4SLinus Torvalds * FIXME: In general, find a more efficient data structure for
9361da177e4SLinus Torvalds * searching.
9371da177e4SLinus Torvalds */
9381da177e4SLinus Torvalds
9391da177e4SLinus Torvalds /*
9401da177e4SLinus Torvalds * The general strategy is to search each transport's transmitted
9411da177e4SLinus Torvalds * list. Return which transport this TSN lives on.
9421da177e4SLinus Torvalds *
9431da177e4SLinus Torvalds * Let's be hopeful and check the active_path first.
9441da177e4SLinus Torvalds * Another optimization would be to know if there is only one
9451da177e4SLinus Torvalds * outbound path and not have to look for the TSN at all.
9461da177e4SLinus Torvalds *
9471da177e4SLinus Torvalds */
9481da177e4SLinus Torvalds
9491da177e4SLinus Torvalds active = asoc->peer.active_path;
9501da177e4SLinus Torvalds
9519dbc15f0SRobert P. J. Day list_for_each_entry(chunk, &active->transmitted,
9529dbc15f0SRobert P. J. Day transmitted_list) {
9531da177e4SLinus Torvalds
9541da177e4SLinus Torvalds if (key == chunk->subh.data_hdr->tsn) {
9551da177e4SLinus Torvalds match = active;
9561da177e4SLinus Torvalds goto out;
9571da177e4SLinus Torvalds }
9581da177e4SLinus Torvalds }
9591da177e4SLinus Torvalds
9601da177e4SLinus Torvalds /* If not found, go search all the other transports. */
9619dbc15f0SRobert P. J. Day list_for_each_entry(transport, &asoc->peer.transport_addr_list,
9629dbc15f0SRobert P. J. Day transports) {
9631da177e4SLinus Torvalds
9641da177e4SLinus Torvalds if (transport == active)
9652317f449SXufeng Zhang continue;
9669dbc15f0SRobert P. J. Day list_for_each_entry(chunk, &transport->transmitted,
9679dbc15f0SRobert P. J. Day transmitted_list) {
9681da177e4SLinus Torvalds if (key == chunk->subh.data_hdr->tsn) {
9691da177e4SLinus Torvalds match = transport;
9701da177e4SLinus Torvalds goto out;
9711da177e4SLinus Torvalds }
9721da177e4SLinus Torvalds }
9731da177e4SLinus Torvalds }
9741da177e4SLinus Torvalds out:
9751da177e4SLinus Torvalds return match;
9761da177e4SLinus Torvalds }
9771da177e4SLinus Torvalds
9781da177e4SLinus Torvalds /* Do delayed input processing. This is scheduled by sctp_rcv(). */
sctp_assoc_bh_rcv(struct work_struct * work)979c4028958SDavid Howells static void sctp_assoc_bh_rcv(struct work_struct *work)
9801da177e4SLinus Torvalds {
981c4028958SDavid Howells struct sctp_association *asoc =
982c4028958SDavid Howells container_of(work, struct sctp_association,
983c4028958SDavid Howells base.inqueue.immediate);
9844e7696d9SXin Long struct net *net = asoc->base.net;
985bfc6f827SXin Long union sctp_subtype subtype;
9861da177e4SLinus Torvalds struct sctp_endpoint *ep;
9871da177e4SLinus Torvalds struct sctp_chunk *chunk;
9881da177e4SLinus Torvalds struct sctp_inq *inqueue;
98959d8d443SXin Long int first_time = 1; /* is this the first time through the loop */
9901da177e4SLinus Torvalds int error = 0;
99159d8d443SXin Long int state;
9921da177e4SLinus Torvalds
9931da177e4SLinus Torvalds /* The association should be held so we should be safe. */
9941da177e4SLinus Torvalds ep = asoc->ep;
9951da177e4SLinus Torvalds
9961da177e4SLinus Torvalds inqueue = &asoc->base.inqueue;
9971da177e4SLinus Torvalds sctp_association_hold(asoc);
9981da177e4SLinus Torvalds while (NULL != (chunk = sctp_inq_pop(inqueue))) {
9991da177e4SLinus Torvalds state = asoc->state;
10001da177e4SLinus Torvalds subtype = SCTP_ST_CHUNK(chunk->chunk_hdr->type);
10011da177e4SLinus Torvalds
100259d8d443SXin Long /* If the first chunk in the packet is AUTH, do special
100359d8d443SXin Long * processing specified in Section 6.3 of SCTP-AUTH spec
100459d8d443SXin Long */
100559d8d443SXin Long if (first_time && subtype.chunk == SCTP_CID_AUTH) {
100659d8d443SXin Long struct sctp_chunkhdr *next_hdr;
100759d8d443SXin Long
100859d8d443SXin Long next_hdr = sctp_inq_peek(inqueue);
100959d8d443SXin Long if (!next_hdr)
101059d8d443SXin Long goto normal;
101159d8d443SXin Long
101259d8d443SXin Long /* If the next chunk is COOKIE-ECHO, skip the AUTH
101359d8d443SXin Long * chunk while saving a pointer to it so we can do
101459d8d443SXin Long * Authentication later (during cookie-echo
101559d8d443SXin Long * processing).
101659d8d443SXin Long */
101759d8d443SXin Long if (next_hdr->type == SCTP_CID_COOKIE_ECHO) {
101859d8d443SXin Long chunk->auth_chunk = skb_clone(chunk->skb,
101959d8d443SXin Long GFP_ATOMIC);
102059d8d443SXin Long chunk->auth = 1;
102159d8d443SXin Long continue;
102259d8d443SXin Long }
102359d8d443SXin Long }
102459d8d443SXin Long
102559d8d443SXin Long normal:
1026bbd0d598SVlad Yasevich /* SCTP-AUTH, Section 6.3:
1027bbd0d598SVlad Yasevich * The receiver has a list of chunk types which it expects
1028bbd0d598SVlad Yasevich * to be received only after an AUTH-chunk. This list has
1029bbd0d598SVlad Yasevich * been sent to the peer during the association setup. It
1030bbd0d598SVlad Yasevich * MUST silently discard these chunks if they are not placed
1031bbd0d598SVlad Yasevich * after an AUTH chunk in the packet.
1032bbd0d598SVlad Yasevich */
1033bbd0d598SVlad Yasevich if (sctp_auth_recv_cid(subtype.chunk, asoc) && !chunk->auth)
1034bbd0d598SVlad Yasevich continue;
1035bbd0d598SVlad Yasevich
10361da177e4SLinus Torvalds /* Remember where the last DATA chunk came from so we
10371da177e4SLinus Torvalds * know where to send the SACK.
10381da177e4SLinus Torvalds */
10391da177e4SLinus Torvalds if (sctp_chunk_is_data(chunk))
10401da177e4SLinus Torvalds asoc->peer.last_data_from = chunk->transport;
1041196d6759SMichele Baldessari else {
104255e26eb9SEric W. Biederman SCTP_INC_STATS(net, SCTP_MIB_INCTRLCHUNKS);
1043196d6759SMichele Baldessari asoc->stats.ictrlchunks++;
1044196d6759SMichele Baldessari if (chunk->chunk_hdr->type == SCTP_CID_SACK)
1045196d6759SMichele Baldessari asoc->stats.isacks++;
1046196d6759SMichele Baldessari }
10471da177e4SLinus Torvalds
10481da177e4SLinus Torvalds if (chunk->transport)
1049e575235fSDaniel Borkmann chunk->transport->last_time_heard = ktime_get();
10501da177e4SLinus Torvalds
10511da177e4SLinus Torvalds /* Run through the state machine. */
105255e26eb9SEric W. Biederman error = sctp_do_sm(net, SCTP_EVENT_T_CHUNK, subtype,
10531da177e4SLinus Torvalds state, ep, asoc, chunk, GFP_ATOMIC);
10541da177e4SLinus Torvalds
10551da177e4SLinus Torvalds /* Check to see if the association is freed in response to
10561da177e4SLinus Torvalds * the incoming chunk. If so, get out of the while loop.
10571da177e4SLinus Torvalds */
10581da177e4SLinus Torvalds if (asoc->base.dead)
10591da177e4SLinus Torvalds break;
10601da177e4SLinus Torvalds
10611da177e4SLinus Torvalds /* If there is an error on chunk, discard this packet. */
10621da177e4SLinus Torvalds if (error && chunk)
10631da177e4SLinus Torvalds chunk->pdiscard = 1;
106459d8d443SXin Long
106559d8d443SXin Long if (first_time)
106659d8d443SXin Long first_time = 0;
10671da177e4SLinus Torvalds }
10681da177e4SLinus Torvalds sctp_association_put(asoc);
10691da177e4SLinus Torvalds }
10701da177e4SLinus Torvalds
10711da177e4SLinus Torvalds /* This routine moves an association from its old sk to a new sk. */
sctp_assoc_migrate(struct sctp_association * assoc,struct sock * newsk)10721da177e4SLinus Torvalds void sctp_assoc_migrate(struct sctp_association *assoc, struct sock *newsk)
10731da177e4SLinus Torvalds {
10741da177e4SLinus Torvalds struct sctp_sock *newsp = sctp_sk(newsk);
10751da177e4SLinus Torvalds struct sock *oldsk = assoc->base.sk;
10761da177e4SLinus Torvalds
10771da177e4SLinus Torvalds /* Delete the association from the old endpoint's list of
10781da177e4SLinus Torvalds * associations.
10791da177e4SLinus Torvalds */
10801da177e4SLinus Torvalds list_del_init(&assoc->asocs);
10811da177e4SLinus Torvalds
10821da177e4SLinus Torvalds /* Decrement the backlog value for a TCP-style socket. */
10831da177e4SLinus Torvalds if (sctp_style(oldsk, TCP))
10847976a11bSEric Dumazet sk_acceptq_removed(oldsk);
10851da177e4SLinus Torvalds
10861da177e4SLinus Torvalds /* Release references to the old endpoint and the sock. */
10871da177e4SLinus Torvalds sctp_endpoint_put(assoc->ep);
10881da177e4SLinus Torvalds sock_put(assoc->base.sk);
10891da177e4SLinus Torvalds
10901da177e4SLinus Torvalds /* Get a reference to the new endpoint. */
10911da177e4SLinus Torvalds assoc->ep = newsp->ep;
10921da177e4SLinus Torvalds sctp_endpoint_hold(assoc->ep);
10931da177e4SLinus Torvalds
10941da177e4SLinus Torvalds /* Get a reference to the new sock. */
10951da177e4SLinus Torvalds assoc->base.sk = newsk;
10961da177e4SLinus Torvalds sock_hold(assoc->base.sk);
10971da177e4SLinus Torvalds
10981da177e4SLinus Torvalds /* Add the association to the new endpoint's list of associations. */
10991da177e4SLinus Torvalds sctp_endpoint_add_asoc(newsp->ep, assoc);
11001da177e4SLinus Torvalds }
11011da177e4SLinus Torvalds
11021da177e4SLinus Torvalds /* Update an association (possibly from unexpected COOKIE-ECHO processing). */
sctp_assoc_update(struct sctp_association * asoc,struct sctp_association * new)11035ee8aa68SXin Long int sctp_assoc_update(struct sctp_association *asoc,
11041da177e4SLinus Torvalds struct sctp_association *new)
11051da177e4SLinus Torvalds {
11061da177e4SLinus Torvalds struct sctp_transport *trans;
11071da177e4SLinus Torvalds struct list_head *pos, *temp;
11081da177e4SLinus Torvalds
11091da177e4SLinus Torvalds /* Copy in new parameters of peer. */
11101da177e4SLinus Torvalds asoc->c = new->c;
11111da177e4SLinus Torvalds asoc->peer.rwnd = new->peer.rwnd;
11121da177e4SLinus Torvalds asoc->peer.sack_needed = new->peer.sack_needed;
11131be9a950SDaniel Borkmann asoc->peer.auth_capable = new->peer.auth_capable;
11141da177e4SLinus Torvalds asoc->peer.i = new->peer.i;
11155ee8aa68SXin Long
11165ee8aa68SXin Long if (!sctp_tsnmap_init(&asoc->peer.tsn_map, SCTP_TSN_MAP_INITIAL,
11175ee8aa68SXin Long asoc->peer.i.initial_tsn, GFP_ATOMIC))
11185ee8aa68SXin Long return -ENOMEM;
11191da177e4SLinus Torvalds
11201da177e4SLinus Torvalds /* Remove any peer addresses not present in the new association. */
11211da177e4SLinus Torvalds list_for_each_safe(pos, temp, &asoc->peer.transport_addr_list) {
11221da177e4SLinus Torvalds trans = list_entry(pos, struct sctp_transport, transports);
11230c42749cSVlad Yasevich if (!sctp_assoc_lookup_paddr(new, &trans->ipaddr)) {
11240c42749cSVlad Yasevich sctp_assoc_rm_peer(asoc, trans);
11250c42749cSVlad Yasevich continue;
11260c42749cSVlad Yasevich }
1127749bf921SVlad Yasevich
1128749bf921SVlad Yasevich if (asoc->state >= SCTP_STATE_ESTABLISHED)
1129749bf921SVlad Yasevich sctp_transport_reset(trans);
11301da177e4SLinus Torvalds }
11311da177e4SLinus Torvalds
11321da177e4SLinus Torvalds /* If the case is A (association restart), use
11331da177e4SLinus Torvalds * initial_tsn as next_tsn. If the case is B, use
11341da177e4SLinus Torvalds * current next_tsn in case data sent to peer
11351da177e4SLinus Torvalds * has been discarded and needs retransmission.
11361da177e4SLinus Torvalds */
11371da177e4SLinus Torvalds if (asoc->state >= SCTP_STATE_ESTABLISHED) {
11381da177e4SLinus Torvalds asoc->next_tsn = new->next_tsn;
11391da177e4SLinus Torvalds asoc->ctsn_ack_point = new->ctsn_ack_point;
11401da177e4SLinus Torvalds asoc->adv_peer_ack_point = new->adv_peer_ack_point;
11411da177e4SLinus Torvalds
11421da177e4SLinus Torvalds /* Reinitialize SSN for both local streams
11431da177e4SLinus Torvalds * and peer's streams.
11441da177e4SLinus Torvalds */
1145cee360abSXin Long sctp_stream_clear(&asoc->stream);
11461da177e4SLinus Torvalds
11470b58a811SVlad Yasevich /* Flush the ULP reassembly and ordered queue.
11480b58a811SVlad Yasevich * Any data there will now be stale and will
11490b58a811SVlad Yasevich * cause problems.
11500b58a811SVlad Yasevich */
11510b58a811SVlad Yasevich sctp_ulpq_flush(&asoc->ulpq);
11520b58a811SVlad Yasevich
1153749bf921SVlad Yasevich /* reset the overall association error count so
1154749bf921SVlad Yasevich * that the restarted association doesn't get torn
1155749bf921SVlad Yasevich * down on the next retransmission timer.
1156749bf921SVlad Yasevich */
1157749bf921SVlad Yasevich asoc->overall_error_count = 0;
1158749bf921SVlad Yasevich
11591da177e4SLinus Torvalds } else {
11601da177e4SLinus Torvalds /* Add any peer addresses from the new association. */
11619dbc15f0SRobert P. J. Day list_for_each_entry(trans, &new->peer.transport_addr_list,
11625ee8aa68SXin Long transports)
11632222a780SXin Long if (!sctp_assoc_add_peer(asoc, &trans->ipaddr,
11645ee8aa68SXin Long GFP_ATOMIC, trans->state))
11655ee8aa68SXin Long return -ENOMEM;
11661da177e4SLinus Torvalds
11671da177e4SLinus Torvalds asoc->ctsn_ack_point = asoc->next_tsn - 1;
11681da177e4SLinus Torvalds asoc->adv_peer_ack_point = asoc->ctsn_ack_point;
11693ab21379SXin Long
1170cee360abSXin Long if (sctp_state(asoc, COOKIE_WAIT))
1171cee360abSXin Long sctp_stream_update(&asoc->stream, &new->stream);
117207d93967SVlad Yasevich
11734abf5a65SXin Long /* get a new assoc id if we don't have one yet. */
11745ee8aa68SXin Long if (sctp_assoc_set_id(asoc, GFP_ATOMIC))
11755ee8aa68SXin Long return -ENOMEM;
117607d93967SVlad Yasevich }
1177a29a5bd4SVlad Yasevich
11789d2c881aSwangweidong /* SCTP-AUTH: Save the peer parameters from the new associations
1179730fc3d0SVlad Yasevich * and also move the association shared keys over
1180730fc3d0SVlad Yasevich */
1181730fc3d0SVlad Yasevich kfree(asoc->peer.peer_random);
1182730fc3d0SVlad Yasevich asoc->peer.peer_random = new->peer.peer_random;
1183730fc3d0SVlad Yasevich new->peer.peer_random = NULL;
1184730fc3d0SVlad Yasevich
1185730fc3d0SVlad Yasevich kfree(asoc->peer.peer_chunks);
1186730fc3d0SVlad Yasevich asoc->peer.peer_chunks = new->peer.peer_chunks;
1187730fc3d0SVlad Yasevich new->peer.peer_chunks = NULL;
1188730fc3d0SVlad Yasevich
1189730fc3d0SVlad Yasevich kfree(asoc->peer.peer_hmacs);
1190730fc3d0SVlad Yasevich asoc->peer.peer_hmacs = new->peer.peer_hmacs;
1191730fc3d0SVlad Yasevich new->peer.peer_hmacs = NULL;
1192730fc3d0SVlad Yasevich
11935ee8aa68SXin Long return sctp_auth_asoc_init_active_key(asoc, GFP_ATOMIC);
11941da177e4SLinus Torvalds }
11951da177e4SLinus Torvalds
11961da177e4SLinus Torvalds /* Update the retran path for sending a retransmitted packet.
11974c47af4dSDaniel Borkmann * See also RFC4960, 6.4. Multi-Homed SCTP Endpoints:
11984c47af4dSDaniel Borkmann *
11994c47af4dSDaniel Borkmann * When there is outbound data to send and the primary path
12004c47af4dSDaniel Borkmann * becomes inactive (e.g., due to failures), or where the
12014c47af4dSDaniel Borkmann * SCTP user explicitly requests to send data to an
12024c47af4dSDaniel Borkmann * inactive destination transport address, before reporting
12034c47af4dSDaniel Borkmann * an error to its ULP, the SCTP endpoint should try to send
12044c47af4dSDaniel Borkmann * the data to an alternate active destination transport
12054c47af4dSDaniel Borkmann * address if one exists.
12064c47af4dSDaniel Borkmann *
12074c47af4dSDaniel Borkmann * When retransmitting data that timed out, if the endpoint
12084c47af4dSDaniel Borkmann * is multihomed, it should consider each source-destination
12094c47af4dSDaniel Borkmann * address pair in its retransmission selection policy.
12104c47af4dSDaniel Borkmann * When retransmitting timed-out data, the endpoint should
12114c47af4dSDaniel Borkmann * attempt to pick the most divergent source-destination
12124c47af4dSDaniel Borkmann * pair from the original source-destination pair to which
12134c47af4dSDaniel Borkmann * the packet was transmitted.
12144c47af4dSDaniel Borkmann *
12154c47af4dSDaniel Borkmann * Note: Rules for picking the most divergent source-destination
12164c47af4dSDaniel Borkmann * pair are an implementation decision and are not specified
12174c47af4dSDaniel Borkmann * within this document.
12184c47af4dSDaniel Borkmann *
12194c47af4dSDaniel Borkmann * Our basic strategy is to round-robin transports in priorities
12202103d6b8SDenys Vlasenko * according to sctp_trans_score() e.g., if no such
12214c47af4dSDaniel Borkmann * transport with state SCTP_ACTIVE exists, round-robin through
12224c47af4dSDaniel Borkmann * SCTP_UNKNOWN, etc. You get the picture.
12231da177e4SLinus Torvalds */
sctp_trans_score(const struct sctp_transport * trans)12244c47af4dSDaniel Borkmann static u8 sctp_trans_score(const struct sctp_transport *trans)
12254c47af4dSDaniel Borkmann {
12262103d6b8SDenys Vlasenko switch (trans->state) {
12272103d6b8SDenys Vlasenko case SCTP_ACTIVE:
12282103d6b8SDenys Vlasenko return 3; /* best case */
12292103d6b8SDenys Vlasenko case SCTP_UNKNOWN:
12302103d6b8SDenys Vlasenko return 2;
12312103d6b8SDenys Vlasenko case SCTP_PF:
12322103d6b8SDenys Vlasenko return 1;
12332103d6b8SDenys Vlasenko default: /* case SCTP_INACTIVE */
12342103d6b8SDenys Vlasenko return 0; /* worst case */
12352103d6b8SDenys Vlasenko }
12364c47af4dSDaniel Borkmann }
12374c47af4dSDaniel Borkmann
sctp_trans_elect_tie(struct sctp_transport * trans1,struct sctp_transport * trans2)1238a7288c4dSDaniel Borkmann static struct sctp_transport *sctp_trans_elect_tie(struct sctp_transport *trans1,
1239a7288c4dSDaniel Borkmann struct sctp_transport *trans2)
1240a7288c4dSDaniel Borkmann {
1241a7288c4dSDaniel Borkmann if (trans1->error_count > trans2->error_count) {
1242a7288c4dSDaniel Borkmann return trans2;
1243a7288c4dSDaniel Borkmann } else if (trans1->error_count == trans2->error_count &&
1244a7288c4dSDaniel Borkmann ktime_after(trans2->last_time_heard,
1245a7288c4dSDaniel Borkmann trans1->last_time_heard)) {
1246a7288c4dSDaniel Borkmann return trans2;
1247a7288c4dSDaniel Borkmann } else {
1248a7288c4dSDaniel Borkmann return trans1;
1249a7288c4dSDaniel Borkmann }
1250a7288c4dSDaniel Borkmann }
1251a7288c4dSDaniel Borkmann
sctp_trans_elect_best(struct sctp_transport * curr,struct sctp_transport * best)12524c47af4dSDaniel Borkmann static struct sctp_transport *sctp_trans_elect_best(struct sctp_transport *curr,
12534c47af4dSDaniel Borkmann struct sctp_transport *best)
12544c47af4dSDaniel Borkmann {
1255a7288c4dSDaniel Borkmann u8 score_curr, score_best;
1256a7288c4dSDaniel Borkmann
1257ea4f19c1SDaniel Borkmann if (best == NULL || curr == best)
12584c47af4dSDaniel Borkmann return curr;
12594c47af4dSDaniel Borkmann
1260a7288c4dSDaniel Borkmann score_curr = sctp_trans_score(curr);
1261a7288c4dSDaniel Borkmann score_best = sctp_trans_score(best);
1262a7288c4dSDaniel Borkmann
1263a7288c4dSDaniel Borkmann /* First, try a score-based selection if both transport states
1264a7288c4dSDaniel Borkmann * differ. If we're in a tie, lets try to make a more clever
1265a7288c4dSDaniel Borkmann * decision here based on error counts and last time heard.
1266a7288c4dSDaniel Borkmann */
1267a7288c4dSDaniel Borkmann if (score_curr > score_best)
1268a7288c4dSDaniel Borkmann return curr;
1269a7288c4dSDaniel Borkmann else if (score_curr == score_best)
127039d2adebSXin Long return sctp_trans_elect_tie(best, curr);
1271a7288c4dSDaniel Borkmann else
1272a7288c4dSDaniel Borkmann return best;
12734c47af4dSDaniel Borkmann }
12744c47af4dSDaniel Borkmann
sctp_assoc_update_retran_path(struct sctp_association * asoc)12751da177e4SLinus Torvalds void sctp_assoc_update_retran_path(struct sctp_association *asoc)
12761da177e4SLinus Torvalds {
12774c47af4dSDaniel Borkmann struct sctp_transport *trans = asoc->peer.retran_path;
12784c47af4dSDaniel Borkmann struct sctp_transport *trans_next = NULL;
12791da177e4SLinus Torvalds
12804c47af4dSDaniel Borkmann /* We're done as we only have the one and only path. */
12814141ddc0SGui Jianfeng if (asoc->peer.transport_count == 1)
12824141ddc0SGui Jianfeng return;
12834c47af4dSDaniel Borkmann /* If active_path and retran_path are the same and active,
12844c47af4dSDaniel Borkmann * then this is the only active path. Use it.
12854141ddc0SGui Jianfeng */
12864c47af4dSDaniel Borkmann if (asoc->peer.active_path == asoc->peer.retran_path &&
12874c47af4dSDaniel Borkmann asoc->peer.active_path->state == SCTP_ACTIVE)
12884c47af4dSDaniel Borkmann return;
12894c47af4dSDaniel Borkmann
12904c47af4dSDaniel Borkmann /* Iterate from retran_path's successor back to retran_path. */
12914c47af4dSDaniel Borkmann for (trans = list_next_entry(trans, transports); 1;
12924c47af4dSDaniel Borkmann trans = list_next_entry(trans, transports)) {
12934c47af4dSDaniel Borkmann /* Manually skip the head element. */
12944c47af4dSDaniel Borkmann if (&trans->transports == &asoc->peer.transport_addr_list)
12954c47af4dSDaniel Borkmann continue;
12964c47af4dSDaniel Borkmann if (trans->state == SCTP_UNCONFIRMED)
12974c47af4dSDaniel Borkmann continue;
12984c47af4dSDaniel Borkmann trans_next = sctp_trans_elect_best(trans, trans_next);
12994c47af4dSDaniel Borkmann /* Active is good enough for immediate return. */
13004c47af4dSDaniel Borkmann if (trans_next->state == SCTP_ACTIVE)
13014c47af4dSDaniel Borkmann break;
13024c47af4dSDaniel Borkmann /* We've reached the end, time to update path. */
13034c47af4dSDaniel Borkmann if (trans == asoc->peer.retran_path)
13044141ddc0SGui Jianfeng break;
13054141ddc0SGui Jianfeng }
13064141ddc0SGui Jianfeng
13074c47af4dSDaniel Borkmann asoc->peer.retran_path = trans_next;
13081da177e4SLinus Torvalds
13094c47af4dSDaniel Borkmann pr_debug("%s: association:%p updated new path to addr:%pISpc\n",
13104c47af4dSDaniel Borkmann __func__, asoc, &asoc->peer.retran_path->ipaddr.sa);
13111da177e4SLinus Torvalds }
13121da177e4SLinus Torvalds
sctp_select_active_and_retran_path(struct sctp_association * asoc)1313b82e8f31SDaniel Borkmann static void sctp_select_active_and_retran_path(struct sctp_association *asoc)
1314b82e8f31SDaniel Borkmann {
1315b82e8f31SDaniel Borkmann struct sctp_transport *trans, *trans_pri = NULL, *trans_sec = NULL;
1316a7288c4dSDaniel Borkmann struct sctp_transport *trans_pf = NULL;
1317b82e8f31SDaniel Borkmann
1318b82e8f31SDaniel Borkmann /* Look for the two most recently used active transports. */
1319b82e8f31SDaniel Borkmann list_for_each_entry(trans, &asoc->peer.transport_addr_list,
1320b82e8f31SDaniel Borkmann transports) {
1321a7288c4dSDaniel Borkmann /* Skip uninteresting transports. */
1322b82e8f31SDaniel Borkmann if (trans->state == SCTP_INACTIVE ||
1323a7288c4dSDaniel Borkmann trans->state == SCTP_UNCONFIRMED)
1324b82e8f31SDaniel Borkmann continue;
1325a7288c4dSDaniel Borkmann /* Keep track of the best PF transport from our
1326a7288c4dSDaniel Borkmann * list in case we don't find an active one.
1327a7288c4dSDaniel Borkmann */
1328a7288c4dSDaniel Borkmann if (trans->state == SCTP_PF) {
1329a7288c4dSDaniel Borkmann trans_pf = sctp_trans_elect_best(trans, trans_pf);
1330a7288c4dSDaniel Borkmann continue;
1331a7288c4dSDaniel Borkmann }
1332a7288c4dSDaniel Borkmann /* For active transports, pick the most recent ones. */
1333b82e8f31SDaniel Borkmann if (trans_pri == NULL ||
1334e575235fSDaniel Borkmann ktime_after(trans->last_time_heard,
1335e575235fSDaniel Borkmann trans_pri->last_time_heard)) {
1336b82e8f31SDaniel Borkmann trans_sec = trans_pri;
1337b82e8f31SDaniel Borkmann trans_pri = trans;
1338b82e8f31SDaniel Borkmann } else if (trans_sec == NULL ||
1339e575235fSDaniel Borkmann ktime_after(trans->last_time_heard,
1340e575235fSDaniel Borkmann trans_sec->last_time_heard)) {
1341b82e8f31SDaniel Borkmann trans_sec = trans;
1342b82e8f31SDaniel Borkmann }
1343b82e8f31SDaniel Borkmann }
1344b82e8f31SDaniel Borkmann
1345b82e8f31SDaniel Borkmann /* RFC 2960 6.4 Multi-Homed SCTP Endpoints
1346b82e8f31SDaniel Borkmann *
1347b82e8f31SDaniel Borkmann * By default, an endpoint should always transmit to the primary
1348b82e8f31SDaniel Borkmann * path, unless the SCTP user explicitly specifies the
1349b82e8f31SDaniel Borkmann * destination transport address (and possibly source transport
1350b82e8f31SDaniel Borkmann * address) to use. [If the primary is active but not most recent,
1351b82e8f31SDaniel Borkmann * bump the most recently used transport.]
1352b82e8f31SDaniel Borkmann */
1353b82e8f31SDaniel Borkmann if ((asoc->peer.primary_path->state == SCTP_ACTIVE ||
1354b82e8f31SDaniel Borkmann asoc->peer.primary_path->state == SCTP_UNKNOWN) &&
1355b82e8f31SDaniel Borkmann asoc->peer.primary_path != trans_pri) {
1356b82e8f31SDaniel Borkmann trans_sec = trans_pri;
1357b82e8f31SDaniel Borkmann trans_pri = asoc->peer.primary_path;
1358b82e8f31SDaniel Borkmann }
1359b82e8f31SDaniel Borkmann
1360b82e8f31SDaniel Borkmann /* We did not find anything useful for a possible retransmission
13615e80a0ccSRandy Dunlap * path; either primary path that we found is the same as
1362b82e8f31SDaniel Borkmann * the current one, or we didn't generally find an active one.
1363b82e8f31SDaniel Borkmann */
1364b82e8f31SDaniel Borkmann if (trans_sec == NULL)
1365b82e8f31SDaniel Borkmann trans_sec = trans_pri;
1366b82e8f31SDaniel Borkmann
1367b82e8f31SDaniel Borkmann /* If we failed to find a usable transport, just camp on the
1368aa4a83eeSDaniel Borkmann * active or pick a PF iff it's the better choice.
1369b82e8f31SDaniel Borkmann */
1370b82e8f31SDaniel Borkmann if (trans_pri == NULL) {
1371aa4a83eeSDaniel Borkmann trans_pri = sctp_trans_elect_best(asoc->peer.active_path, trans_pf);
1372aa4a83eeSDaniel Borkmann trans_sec = trans_pri;
1373b82e8f31SDaniel Borkmann }
1374b82e8f31SDaniel Borkmann
1375b82e8f31SDaniel Borkmann /* Set the active and retran transports. */
1376b82e8f31SDaniel Borkmann asoc->peer.active_path = trans_pri;
1377b82e8f31SDaniel Borkmann asoc->peer.retran_path = trans_sec;
1378b82e8f31SDaniel Borkmann }
1379b82e8f31SDaniel Borkmann
13804c47af4dSDaniel Borkmann struct sctp_transport *
sctp_assoc_choose_alter_transport(struct sctp_association * asoc,struct sctp_transport * last_sent_to)13814c47af4dSDaniel Borkmann sctp_assoc_choose_alter_transport(struct sctp_association *asoc,
13824c47af4dSDaniel Borkmann struct sctp_transport *last_sent_to)
13833f7a87d2SFrank Filz {
13849919b455SWei Yongjun /* If this is the first time packet is sent, use the active path,
13859919b455SWei Yongjun * else use the retran path. If the last packet was sent over the
13863f7a87d2SFrank Filz * retran path, update the retran path and use it.
13873f7a87d2SFrank Filz */
13884c47af4dSDaniel Borkmann if (last_sent_to == NULL) {
13891da177e4SLinus Torvalds return asoc->peer.active_path;
13904c47af4dSDaniel Borkmann } else {
13919919b455SWei Yongjun if (last_sent_to == asoc->peer.retran_path)
13921da177e4SLinus Torvalds sctp_assoc_update_retran_path(asoc);
13934c47af4dSDaniel Borkmann
13941da177e4SLinus Torvalds return asoc->peer.retran_path;
13951da177e4SLinus Torvalds }
13961da177e4SLinus Torvalds }
13971da177e4SLinus Torvalds
sctp_assoc_update_frag_point(struct sctp_association * asoc)13982f5e3c9dSMarcelo Ricardo Leitner void sctp_assoc_update_frag_point(struct sctp_association *asoc)
13992f5e3c9dSMarcelo Ricardo Leitner {
14002f5e3c9dSMarcelo Ricardo Leitner int frag = sctp_mtu_payload(sctp_sk(asoc->base.sk), asoc->pathmtu,
14012f5e3c9dSMarcelo Ricardo Leitner sctp_datachk_len(&asoc->stream));
14022f5e3c9dSMarcelo Ricardo Leitner
14032f5e3c9dSMarcelo Ricardo Leitner if (asoc->user_frag)
14042f5e3c9dSMarcelo Ricardo Leitner frag = min_t(int, frag, asoc->user_frag);
14052f5e3c9dSMarcelo Ricardo Leitner
14062f5e3c9dSMarcelo Ricardo Leitner frag = min_t(int, frag, SCTP_MAX_CHUNK_LEN -
14072f5e3c9dSMarcelo Ricardo Leitner sctp_datachk_len(&asoc->stream));
14082f5e3c9dSMarcelo Ricardo Leitner
14092f5e3c9dSMarcelo Ricardo Leitner asoc->frag_point = SCTP_TRUNC4(frag);
14102f5e3c9dSMarcelo Ricardo Leitner }
14112f5e3c9dSMarcelo Ricardo Leitner
sctp_assoc_set_pmtu(struct sctp_association * asoc,__u32 pmtu)1412c4b2893dSMarcelo Ricardo Leitner void sctp_assoc_set_pmtu(struct sctp_association *asoc, __u32 pmtu)
1413c4b2893dSMarcelo Ricardo Leitner {
14142f5e3c9dSMarcelo Ricardo Leitner if (asoc->pathmtu != pmtu) {
1415c4b2893dSMarcelo Ricardo Leitner asoc->pathmtu = pmtu;
14162f5e3c9dSMarcelo Ricardo Leitner sctp_assoc_update_frag_point(asoc);
14172f5e3c9dSMarcelo Ricardo Leitner }
1418c4b2893dSMarcelo Ricardo Leitner
1419c4b2893dSMarcelo Ricardo Leitner pr_debug("%s: asoc:%p, pmtu:%d, frag_point:%d\n", __func__, asoc,
1420c4b2893dSMarcelo Ricardo Leitner asoc->pathmtu, asoc->frag_point);
1421c4b2893dSMarcelo Ricardo Leitner }
1422c4b2893dSMarcelo Ricardo Leitner
14231da177e4SLinus Torvalds /* Update the association's pmtu and frag_point by going through all the
14241da177e4SLinus Torvalds * transports. This routine is called when a transport's PMTU has changed.
14251da177e4SLinus Torvalds */
sctp_assoc_sync_pmtu(struct sctp_association * asoc)14263ebfdf08SXin Long void sctp_assoc_sync_pmtu(struct sctp_association *asoc)
14271da177e4SLinus Torvalds {
14281da177e4SLinus Torvalds struct sctp_transport *t;
14291da177e4SLinus Torvalds __u32 pmtu = 0;
14301da177e4SLinus Torvalds
14311da177e4SLinus Torvalds if (!asoc)
14321da177e4SLinus Torvalds return;
14331da177e4SLinus Torvalds
14341da177e4SLinus Torvalds /* Get the lowest pmtu of all the transports. */
14356ff0f871SMarcelo Ricardo Leitner list_for_each_entry(t, &asoc->peer.transport_addr_list, transports) {
14368a479491SVlad Yasevich if (t->pmtu_pending && t->dst) {
1437d805397cSXin Long sctp_transport_update_pmtu(t,
1438d805397cSXin Long atomic_read(&t->mtu_info));
14398a479491SVlad Yasevich t->pmtu_pending = 0;
14408a479491SVlad Yasevich }
144152ccb8e9SFrank Filz if (!pmtu || (t->pathmtu < pmtu))
144252ccb8e9SFrank Filz pmtu = t->pathmtu;
14431da177e4SLinus Torvalds }
14441da177e4SLinus Torvalds
1445c4b2893dSMarcelo Ricardo Leitner sctp_assoc_set_pmtu(asoc, pmtu);
14461da177e4SLinus Torvalds }
14471da177e4SLinus Torvalds
14481da177e4SLinus Torvalds /* Should we send a SACK to update our peer? */
sctp_peer_needs_update(struct sctp_association * asoc)1449ce4a03dbSwangweidong static inline bool sctp_peer_needs_update(struct sctp_association *asoc)
14501da177e4SLinus Torvalds {
14514e7696d9SXin Long struct net *net = asoc->base.net;
14524e7696d9SXin Long
14531da177e4SLinus Torvalds switch (asoc->state) {
14541da177e4SLinus Torvalds case SCTP_STATE_ESTABLISHED:
14551da177e4SLinus Torvalds case SCTP_STATE_SHUTDOWN_PENDING:
14561da177e4SLinus Torvalds case SCTP_STATE_SHUTDOWN_RECEIVED:
14571da177e4SLinus Torvalds case SCTP_STATE_SHUTDOWN_SENT:
14581da177e4SLinus Torvalds if ((asoc->rwnd > asoc->a_rwnd) &&
145990f2f531SVlad Yasevich ((asoc->rwnd - asoc->a_rwnd) >= max_t(__u32,
1460e1fc3b14SEric W. Biederman (asoc->base.sk->sk_rcvbuf >> net->sctp.rwnd_upd_shift),
146190f2f531SVlad Yasevich asoc->pathmtu)))
1462ce4a03dbSwangweidong return true;
14631da177e4SLinus Torvalds break;
14641da177e4SLinus Torvalds default:
14651da177e4SLinus Torvalds break;
14661da177e4SLinus Torvalds }
1467ce4a03dbSwangweidong return false;
14681da177e4SLinus Torvalds }
14691da177e4SLinus Torvalds
1470362d5204SDaniel Borkmann /* Increase asoc's rwnd by len and send any window update SACK if needed. */
sctp_assoc_rwnd_increase(struct sctp_association * asoc,unsigned int len)1471362d5204SDaniel Borkmann void sctp_assoc_rwnd_increase(struct sctp_association *asoc, unsigned int len)
14721da177e4SLinus Torvalds {
14731da177e4SLinus Torvalds struct sctp_chunk *sack;
14741da177e4SLinus Torvalds struct timer_list *timer;
14751da177e4SLinus Torvalds
1476362d5204SDaniel Borkmann if (asoc->rwnd_over) {
1477362d5204SDaniel Borkmann if (asoc->rwnd_over >= len) {
1478362d5204SDaniel Borkmann asoc->rwnd_over -= len;
1479362d5204SDaniel Borkmann } else {
1480362d5204SDaniel Borkmann asoc->rwnd += (len - asoc->rwnd_over);
1481362d5204SDaniel Borkmann asoc->rwnd_over = 0;
1482362d5204SDaniel Borkmann }
1483362d5204SDaniel Borkmann } else {
1484362d5204SDaniel Borkmann asoc->rwnd += len;
1485362d5204SDaniel Borkmann }
14861da177e4SLinus Torvalds
1487362d5204SDaniel Borkmann /* If we had window pressure, start recovering it
1488362d5204SDaniel Borkmann * once our rwnd had reached the accumulated pressure
1489362d5204SDaniel Borkmann * threshold. The idea is to recover slowly, but up
1490362d5204SDaniel Borkmann * to the initial advertised window.
1491362d5204SDaniel Borkmann */
14921636098cSMarcelo Ricardo Leitner if (asoc->rwnd_press) {
1493362d5204SDaniel Borkmann int change = min(asoc->pathmtu, asoc->rwnd_press);
1494362d5204SDaniel Borkmann asoc->rwnd += change;
1495362d5204SDaniel Borkmann asoc->rwnd_press -= change;
1496362d5204SDaniel Borkmann }
14974d3c46e6SVlad Yasevich
1498362d5204SDaniel Borkmann pr_debug("%s: asoc:%p rwnd increased by %d to (%u, %u) - %u\n",
1499362d5204SDaniel Borkmann __func__, asoc, len, asoc->rwnd, asoc->rwnd_over,
1500362d5204SDaniel Borkmann asoc->a_rwnd);
15011da177e4SLinus Torvalds
15021da177e4SLinus Torvalds /* Send a window update SACK if the rwnd has increased by at least the
15031da177e4SLinus Torvalds * minimum of the association's PMTU and half of the receive buffer.
15041da177e4SLinus Torvalds * The algorithm used is similar to the one described in
15051da177e4SLinus Torvalds * Section 4.2.3.3 of RFC 1122.
15061da177e4SLinus Torvalds */
1507362d5204SDaniel Borkmann if (sctp_peer_needs_update(asoc)) {
15081da177e4SLinus Torvalds asoc->a_rwnd = asoc->rwnd;
1509bb33381dSDaniel Borkmann
1510bb33381dSDaniel Borkmann pr_debug("%s: sending window update SACK- asoc:%p rwnd:%u "
1511bb33381dSDaniel Borkmann "a_rwnd:%u\n", __func__, asoc, asoc->rwnd,
1512bb33381dSDaniel Borkmann asoc->a_rwnd);
1513bb33381dSDaniel Borkmann
15141da177e4SLinus Torvalds sack = sctp_make_sack(asoc);
15151da177e4SLinus Torvalds if (!sack)
15161da177e4SLinus Torvalds return;
15171da177e4SLinus Torvalds
15181da177e4SLinus Torvalds asoc->peer.sack_needed = 0;
15191da177e4SLinus Torvalds
1520cea8768fSMarcelo Ricardo Leitner sctp_outq_tail(&asoc->outqueue, sack, GFP_ATOMIC);
15211da177e4SLinus Torvalds
15221da177e4SLinus Torvalds /* Stop the SACK timer. */
15231da177e4SLinus Torvalds timer = &asoc->timers[SCTP_EVENT_TIMEOUT_SACK];
152425cc4ae9SYing Xue if (del_timer(timer))
15251da177e4SLinus Torvalds sctp_association_put(asoc);
15261da177e4SLinus Torvalds }
15271da177e4SLinus Torvalds }
15281da177e4SLinus Torvalds
1529362d5204SDaniel Borkmann /* Decrease asoc's rwnd by len. */
sctp_assoc_rwnd_decrease(struct sctp_association * asoc,unsigned int len)1530362d5204SDaniel Borkmann void sctp_assoc_rwnd_decrease(struct sctp_association *asoc, unsigned int len)
1531362d5204SDaniel Borkmann {
1532362d5204SDaniel Borkmann int rx_count;
1533362d5204SDaniel Borkmann int over = 0;
1534362d5204SDaniel Borkmann
1535362d5204SDaniel Borkmann if (unlikely(!asoc->rwnd || asoc->rwnd_over))
1536362d5204SDaniel Borkmann pr_debug("%s: association:%p has asoc->rwnd:%u, "
1537362d5204SDaniel Borkmann "asoc->rwnd_over:%u!\n", __func__, asoc,
1538362d5204SDaniel Borkmann asoc->rwnd, asoc->rwnd_over);
1539362d5204SDaniel Borkmann
1540362d5204SDaniel Borkmann if (asoc->ep->rcvbuf_policy)
1541362d5204SDaniel Borkmann rx_count = atomic_read(&asoc->rmem_alloc);
1542362d5204SDaniel Borkmann else
1543362d5204SDaniel Borkmann rx_count = atomic_read(&asoc->base.sk->sk_rmem_alloc);
1544362d5204SDaniel Borkmann
1545362d5204SDaniel Borkmann /* If we've reached or overflowed our receive buffer, announce
1546362d5204SDaniel Borkmann * a 0 rwnd if rwnd would still be positive. Store the
15475e80a0ccSRandy Dunlap * potential pressure overflow so that the window can be restored
1548362d5204SDaniel Borkmann * back to original value.
1549362d5204SDaniel Borkmann */
1550362d5204SDaniel Borkmann if (rx_count >= asoc->base.sk->sk_rcvbuf)
1551362d5204SDaniel Borkmann over = 1;
1552362d5204SDaniel Borkmann
1553362d5204SDaniel Borkmann if (asoc->rwnd >= len) {
1554362d5204SDaniel Borkmann asoc->rwnd -= len;
1555362d5204SDaniel Borkmann if (over) {
1556362d5204SDaniel Borkmann asoc->rwnd_press += asoc->rwnd;
1557362d5204SDaniel Borkmann asoc->rwnd = 0;
1558362d5204SDaniel Borkmann }
1559362d5204SDaniel Borkmann } else {
156058b94d88SMarcelo Ricardo Leitner asoc->rwnd_over += len - asoc->rwnd;
1561362d5204SDaniel Borkmann asoc->rwnd = 0;
1562362d5204SDaniel Borkmann }
1563362d5204SDaniel Borkmann
1564362d5204SDaniel Borkmann pr_debug("%s: asoc:%p rwnd decreased by %d to (%u, %u, %u)\n",
1565362d5204SDaniel Borkmann __func__, asoc, len, asoc->rwnd, asoc->rwnd_over,
1566362d5204SDaniel Borkmann asoc->rwnd_press);
1567362d5204SDaniel Borkmann }
15681da177e4SLinus Torvalds
15691da177e4SLinus Torvalds /* Build the bind address list for the association based on info from the
15701da177e4SLinus Torvalds * local endpoint and the remote peer.
15711da177e4SLinus Torvalds */
sctp_assoc_set_bind_addr_from_ep(struct sctp_association * asoc,enum sctp_scope scope,gfp_t gfp)15723182cd84SAlexey Dobriyan int sctp_assoc_set_bind_addr_from_ep(struct sctp_association *asoc,
15731c662018SXin Long enum sctp_scope scope, gfp_t gfp)
15741da177e4SLinus Torvalds {
1575471e39dfSMarcelo Ricardo Leitner struct sock *sk = asoc->base.sk;
15761da177e4SLinus Torvalds int flags;
15771da177e4SLinus Torvalds
15781da177e4SLinus Torvalds /* Use scoping rules to determine the subset of addresses from
15791da177e4SLinus Torvalds * the endpoint.
15801da177e4SLinus Torvalds */
1581471e39dfSMarcelo Ricardo Leitner flags = (PF_INET6 == sk->sk_family) ? SCTP_ADDR6_ALLOWED : 0;
1582471e39dfSMarcelo Ricardo Leitner if (!inet_v6_ipv6only(sk))
1583471e39dfSMarcelo Ricardo Leitner flags |= SCTP_ADDR4_ALLOWED;
15841da177e4SLinus Torvalds if (asoc->peer.ipv4_address)
15851da177e4SLinus Torvalds flags |= SCTP_ADDR4_PEERSUPP;
15861da177e4SLinus Torvalds if (asoc->peer.ipv6_address)
15871da177e4SLinus Torvalds flags |= SCTP_ADDR6_PEERSUPP;
15881da177e4SLinus Torvalds
15894e7696d9SXin Long return sctp_bind_addr_copy(asoc->base.net,
15904db67e80SEric W. Biederman &asoc->base.bind_addr,
15911da177e4SLinus Torvalds &asoc->ep->base.bind_addr,
15921da177e4SLinus Torvalds scope, gfp, flags);
15931da177e4SLinus Torvalds }
15941da177e4SLinus Torvalds
15951da177e4SLinus Torvalds /* Build the association's bind address list from the cookie. */
sctp_assoc_set_bind_addr_from_cookie(struct sctp_association * asoc,struct sctp_cookie * cookie,gfp_t gfp)15961da177e4SLinus Torvalds int sctp_assoc_set_bind_addr_from_cookie(struct sctp_association *asoc,
15973182cd84SAlexey Dobriyan struct sctp_cookie *cookie,
1598dd0fc66fSAl Viro gfp_t gfp)
15991da177e4SLinus Torvalds {
1600f97278ffSXin Long struct sctp_init_chunk *peer_init = (struct sctp_init_chunk *)(cookie + 1);
1601f97278ffSXin Long int var_size2 = ntohs(peer_init->chunk_hdr.length);
16021da177e4SLinus Torvalds int var_size3 = cookie->raw_addr_list_len;
1603f97278ffSXin Long __u8 *raw = (__u8 *)peer_init + var_size2;
16041da177e4SLinus Torvalds
16051da177e4SLinus Torvalds return sctp_raw_to_bind_addrs(&asoc->base.bind_addr, raw, var_size3,
16061da177e4SLinus Torvalds asoc->ep->base.bind_addr.port, gfp);
16071da177e4SLinus Torvalds }
16081da177e4SLinus Torvalds
16091da177e4SLinus Torvalds /* Lookup laddr in the bind address list of an association. */
sctp_assoc_lookup_laddr(struct sctp_association * asoc,const union sctp_addr * laddr)16101da177e4SLinus Torvalds int sctp_assoc_lookup_laddr(struct sctp_association *asoc,
16111da177e4SLinus Torvalds const union sctp_addr *laddr)
16121da177e4SLinus Torvalds {
1613559cf710SVlad Yasevich int found = 0;
16141da177e4SLinus Torvalds
16151da177e4SLinus Torvalds if ((asoc->base.bind_addr.port == ntohs(laddr->v4.sin_port)) &&
16161da177e4SLinus Torvalds sctp_bind_addr_match(&asoc->base.bind_addr, laddr,
1617559cf710SVlad Yasevich sctp_sk(asoc->base.sk)))
16181da177e4SLinus Torvalds found = 1;
16191da177e4SLinus Torvalds
16201da177e4SLinus Torvalds return found;
16211da177e4SLinus Torvalds }
162207d93967SVlad Yasevich
162307d93967SVlad Yasevich /* Set an association id for a given association */
sctp_assoc_set_id(struct sctp_association * asoc,gfp_t gfp)162407d93967SVlad Yasevich int sctp_assoc_set_id(struct sctp_association *asoc, gfp_t gfp)
162507d93967SVlad Yasevich {
1626d0164adcSMel Gorman bool preload = gfpflags_allow_blocking(gfp);
162794960e8cSTejun Heo int ret;
1628c6ba68a2SVlad Yasevich
1629c6ba68a2SVlad Yasevich /* If the id is already assigned, keep it. */
1630c6ba68a2SVlad Yasevich if (asoc->assoc_id)
163194960e8cSTejun Heo return 0;
163207d93967SVlad Yasevich
163394960e8cSTejun Heo if (preload)
163494960e8cSTejun Heo idr_preload(gfp);
163507d93967SVlad Yasevich spin_lock_bh(&sctp_assocs_id_lock);
163680df2704SXin Long /* 0, 1, 2 are used as SCTP_FUTURE_ASSOC, SCTP_CURRENT_ASSOC and
163780df2704SXin Long * SCTP_ALL_ASSOC, so an available id must be > SCTP_ALL_ASSOC.
163880df2704SXin Long */
163980df2704SXin Long ret = idr_alloc_cyclic(&sctp_assocs_id, asoc, SCTP_ALL_ASSOC + 1, 0,
164080df2704SXin Long GFP_NOWAIT);
164107d93967SVlad Yasevich spin_unlock_bh(&sctp_assocs_id_lock);
164294960e8cSTejun Heo if (preload)
164394960e8cSTejun Heo idr_preload_end();
164494960e8cSTejun Heo if (ret < 0)
164594960e8cSTejun Heo return ret;
164607d93967SVlad Yasevich
164794960e8cSTejun Heo asoc->assoc_id = (sctp_assoc_t)ret;
164894960e8cSTejun Heo return 0;
164907d93967SVlad Yasevich }
1650a08de64dSVlad Yasevich
16518b4472ccSWei Yongjun /* Free the ASCONF queue */
sctp_assoc_free_asconf_queue(struct sctp_association * asoc)16528b4472ccSWei Yongjun static void sctp_assoc_free_asconf_queue(struct sctp_association *asoc)
16538b4472ccSWei Yongjun {
16548b4472ccSWei Yongjun struct sctp_chunk *asconf;
16558b4472ccSWei Yongjun struct sctp_chunk *tmp;
16568b4472ccSWei Yongjun
16578b4472ccSWei Yongjun list_for_each_entry_safe(asconf, tmp, &asoc->addip_chunk_list, list) {
16588b4472ccSWei Yongjun list_del_init(&asconf->list);
16598b4472ccSWei Yongjun sctp_chunk_free(asconf);
16608b4472ccSWei Yongjun }
16618b4472ccSWei Yongjun }
16628b4472ccSWei Yongjun
1663a08de64dSVlad Yasevich /* Free asconf_ack cache */
sctp_assoc_free_asconf_acks(struct sctp_association * asoc)1664a08de64dSVlad Yasevich static void sctp_assoc_free_asconf_acks(struct sctp_association *asoc)
1665a08de64dSVlad Yasevich {
1666a08de64dSVlad Yasevich struct sctp_chunk *ack;
1667a08de64dSVlad Yasevich struct sctp_chunk *tmp;
1668a08de64dSVlad Yasevich
1669a08de64dSVlad Yasevich list_for_each_entry_safe(ack, tmp, &asoc->asconf_ack_list,
1670a08de64dSVlad Yasevich transmitted_list) {
1671a08de64dSVlad Yasevich list_del_init(&ack->transmitted_list);
1672a08de64dSVlad Yasevich sctp_chunk_free(ack);
1673a08de64dSVlad Yasevich }
1674a08de64dSVlad Yasevich }
1675a08de64dSVlad Yasevich
1676a08de64dSVlad Yasevich /* Clean up the ASCONF_ACK queue */
sctp_assoc_clean_asconf_ack_cache(const struct sctp_association * asoc)1677a08de64dSVlad Yasevich void sctp_assoc_clean_asconf_ack_cache(const struct sctp_association *asoc)
1678a08de64dSVlad Yasevich {
1679a08de64dSVlad Yasevich struct sctp_chunk *ack;
1680a08de64dSVlad Yasevich struct sctp_chunk *tmp;
1681a08de64dSVlad Yasevich
1682a08de64dSVlad Yasevich /* We can remove all the entries from the queue up to
1683a08de64dSVlad Yasevich * the "Peer-Sequence-Number".
1684a08de64dSVlad Yasevich */
1685a08de64dSVlad Yasevich list_for_each_entry_safe(ack, tmp, &asoc->asconf_ack_list,
1686a08de64dSVlad Yasevich transmitted_list) {
1687a08de64dSVlad Yasevich if (ack->subh.addip_hdr->serial ==
1688a08de64dSVlad Yasevich htonl(asoc->peer.addip_serial))
1689a08de64dSVlad Yasevich break;
1690a08de64dSVlad Yasevich
1691a08de64dSVlad Yasevich list_del_init(&ack->transmitted_list);
1692a08de64dSVlad Yasevich sctp_chunk_free(ack);
1693a08de64dSVlad Yasevich }
1694a08de64dSVlad Yasevich }
1695a08de64dSVlad Yasevich
1696a08de64dSVlad Yasevich /* Find the ASCONF_ACK whose serial number matches ASCONF */
sctp_assoc_lookup_asconf_ack(const struct sctp_association * asoc,__be32 serial)1697a08de64dSVlad Yasevich struct sctp_chunk *sctp_assoc_lookup_asconf_ack(
1698a08de64dSVlad Yasevich const struct sctp_association *asoc,
1699a08de64dSVlad Yasevich __be32 serial)
1700a08de64dSVlad Yasevich {
1701a8699814SWei Yongjun struct sctp_chunk *ack;
1702a08de64dSVlad Yasevich
1703a08de64dSVlad Yasevich /* Walk through the list of cached ASCONF-ACKs and find the
1704a08de64dSVlad Yasevich * ack chunk whose serial number matches that of the request.
1705a08de64dSVlad Yasevich */
1706a08de64dSVlad Yasevich list_for_each_entry(ack, &asoc->asconf_ack_list, transmitted_list) {
1707b69040d8SDaniel Borkmann if (sctp_chunk_pending(ack))
1708b69040d8SDaniel Borkmann continue;
1709a08de64dSVlad Yasevich if (ack->subh.addip_hdr->serial == serial) {
1710a08de64dSVlad Yasevich sctp_chunk_hold(ack);
1711a8699814SWei Yongjun return ack;
1712a08de64dSVlad Yasevich }
1713a08de64dSVlad Yasevich }
1714a08de64dSVlad Yasevich
1715a8699814SWei Yongjun return NULL;
1716a08de64dSVlad Yasevich }
1717a000c01eSWei Yongjun
sctp_asconf_queue_teardown(struct sctp_association * asoc)1718a000c01eSWei Yongjun void sctp_asconf_queue_teardown(struct sctp_association *asoc)
1719a000c01eSWei Yongjun {
1720a000c01eSWei Yongjun /* Free any cached ASCONF_ACK chunk. */
1721a000c01eSWei Yongjun sctp_assoc_free_asconf_acks(asoc);
1722a000c01eSWei Yongjun
1723a000c01eSWei Yongjun /* Free the ASCONF queue. */
1724a000c01eSWei Yongjun sctp_assoc_free_asconf_queue(asoc);
1725a000c01eSWei Yongjun
1726a000c01eSWei Yongjun /* Free any cached ASCONF chunk. */
1727a000c01eSWei Yongjun if (asoc->addip_last_asconf)
1728a000c01eSWei Yongjun sctp_chunk_free(asoc->addip_last_asconf);
1729a000c01eSWei Yongjun }
1730