xref: /openbmc/linux/net/sctp/associola.c (revision 9144f784f852f9a125cabe9927b986d909bfa439)
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