162306a36Sopenharmony_ci// SPDX-License-Identifier: GPL-2.0-or-later
262306a36Sopenharmony_ci/* SCTP kernel implementation
362306a36Sopenharmony_ci * Copyright (c) 1999-2000 Cisco, Inc.
462306a36Sopenharmony_ci * Copyright (c) 1999-2001 Motorola, Inc.
562306a36Sopenharmony_ci * Copyright (c) 2001-2002 International Business Machines, Corp.
662306a36Sopenharmony_ci * Copyright (c) 2001 Intel Corp.
762306a36Sopenharmony_ci * Copyright (c) 2001 Nokia, Inc.
862306a36Sopenharmony_ci * Copyright (c) 2001 La Monte H.P. Yarroll
962306a36Sopenharmony_ci *
1062306a36Sopenharmony_ci * This file is part of the SCTP kernel implementation
1162306a36Sopenharmony_ci *
1262306a36Sopenharmony_ci * This abstraction represents an SCTP endpoint.
1362306a36Sopenharmony_ci *
1462306a36Sopenharmony_ci * Please send any bug reports or fixes you make to the
1562306a36Sopenharmony_ci * email address(es):
1662306a36Sopenharmony_ci *    lksctp developers <linux-sctp@vger.kernel.org>
1762306a36Sopenharmony_ci *
1862306a36Sopenharmony_ci * Written or modified by:
1962306a36Sopenharmony_ci *    La Monte H.P. Yarroll <piggy@acm.org>
2062306a36Sopenharmony_ci *    Karl Knutson <karl@athena.chicago.il.us>
2162306a36Sopenharmony_ci *    Jon Grimm <jgrimm@austin.ibm.com>
2262306a36Sopenharmony_ci *    Daisy Chang <daisyc@us.ibm.com>
2362306a36Sopenharmony_ci *    Dajiang Zhang <dajiang.zhang@nokia.com>
2462306a36Sopenharmony_ci */
2562306a36Sopenharmony_ci
2662306a36Sopenharmony_ci#include <linux/types.h>
2762306a36Sopenharmony_ci#include <linux/slab.h>
2862306a36Sopenharmony_ci#include <linux/in.h>
2962306a36Sopenharmony_ci#include <linux/random.h>	/* get_random_bytes() */
3062306a36Sopenharmony_ci#include <net/sock.h>
3162306a36Sopenharmony_ci#include <net/ipv6.h>
3262306a36Sopenharmony_ci#include <net/sctp/sctp.h>
3362306a36Sopenharmony_ci#include <net/sctp/sm.h>
3462306a36Sopenharmony_ci
3562306a36Sopenharmony_ci/* Forward declarations for internal helpers. */
3662306a36Sopenharmony_cistatic void sctp_endpoint_bh_rcv(struct work_struct *work);
3762306a36Sopenharmony_ci
3862306a36Sopenharmony_ci/*
3962306a36Sopenharmony_ci * Initialize the base fields of the endpoint structure.
4062306a36Sopenharmony_ci */
4162306a36Sopenharmony_cistatic struct sctp_endpoint *sctp_endpoint_init(struct sctp_endpoint *ep,
4262306a36Sopenharmony_ci						struct sock *sk,
4362306a36Sopenharmony_ci						gfp_t gfp)
4462306a36Sopenharmony_ci{
4562306a36Sopenharmony_ci	struct net *net = sock_net(sk);
4662306a36Sopenharmony_ci	struct sctp_shared_key *null_key;
4762306a36Sopenharmony_ci
4862306a36Sopenharmony_ci	ep->digest = kzalloc(SCTP_SIGNATURE_SIZE, gfp);
4962306a36Sopenharmony_ci	if (!ep->digest)
5062306a36Sopenharmony_ci		return NULL;
5162306a36Sopenharmony_ci
5262306a36Sopenharmony_ci	ep->asconf_enable = net->sctp.addip_enable;
5362306a36Sopenharmony_ci	ep->auth_enable = net->sctp.auth_enable;
5462306a36Sopenharmony_ci	if (ep->auth_enable) {
5562306a36Sopenharmony_ci		if (sctp_auth_init(ep, gfp))
5662306a36Sopenharmony_ci			goto nomem;
5762306a36Sopenharmony_ci		if (ep->asconf_enable) {
5862306a36Sopenharmony_ci			sctp_auth_ep_add_chunkid(ep, SCTP_CID_ASCONF);
5962306a36Sopenharmony_ci			sctp_auth_ep_add_chunkid(ep, SCTP_CID_ASCONF_ACK);
6062306a36Sopenharmony_ci		}
6162306a36Sopenharmony_ci	}
6262306a36Sopenharmony_ci
6362306a36Sopenharmony_ci	/* Initialize the base structure. */
6462306a36Sopenharmony_ci	/* What type of endpoint are we?  */
6562306a36Sopenharmony_ci	ep->base.type = SCTP_EP_TYPE_SOCKET;
6662306a36Sopenharmony_ci
6762306a36Sopenharmony_ci	/* Initialize the basic object fields. */
6862306a36Sopenharmony_ci	refcount_set(&ep->base.refcnt, 1);
6962306a36Sopenharmony_ci	ep->base.dead = false;
7062306a36Sopenharmony_ci
7162306a36Sopenharmony_ci	/* Create an input queue.  */
7262306a36Sopenharmony_ci	sctp_inq_init(&ep->base.inqueue);
7362306a36Sopenharmony_ci
7462306a36Sopenharmony_ci	/* Set its top-half handler */
7562306a36Sopenharmony_ci	sctp_inq_set_th_handler(&ep->base.inqueue, sctp_endpoint_bh_rcv);
7662306a36Sopenharmony_ci
7762306a36Sopenharmony_ci	/* Initialize the bind addr area */
7862306a36Sopenharmony_ci	sctp_bind_addr_init(&ep->base.bind_addr, 0);
7962306a36Sopenharmony_ci
8062306a36Sopenharmony_ci	/* Create the lists of associations.  */
8162306a36Sopenharmony_ci	INIT_LIST_HEAD(&ep->asocs);
8262306a36Sopenharmony_ci
8362306a36Sopenharmony_ci	/* Use SCTP specific send buffer space queues.  */
8462306a36Sopenharmony_ci	ep->sndbuf_policy = net->sctp.sndbuf_policy;
8562306a36Sopenharmony_ci
8662306a36Sopenharmony_ci	sk->sk_data_ready = sctp_data_ready;
8762306a36Sopenharmony_ci	sk->sk_write_space = sctp_write_space;
8862306a36Sopenharmony_ci	sock_set_flag(sk, SOCK_USE_WRITE_QUEUE);
8962306a36Sopenharmony_ci
9062306a36Sopenharmony_ci	/* Get the receive buffer policy for this endpoint */
9162306a36Sopenharmony_ci	ep->rcvbuf_policy = net->sctp.rcvbuf_policy;
9262306a36Sopenharmony_ci
9362306a36Sopenharmony_ci	/* Initialize the secret key used with cookie. */
9462306a36Sopenharmony_ci	get_random_bytes(ep->secret_key, sizeof(ep->secret_key));
9562306a36Sopenharmony_ci
9662306a36Sopenharmony_ci	/* SCTP-AUTH extensions*/
9762306a36Sopenharmony_ci	INIT_LIST_HEAD(&ep->endpoint_shared_keys);
9862306a36Sopenharmony_ci	null_key = sctp_auth_shkey_create(0, gfp);
9962306a36Sopenharmony_ci	if (!null_key)
10062306a36Sopenharmony_ci		goto nomem_shkey;
10162306a36Sopenharmony_ci
10262306a36Sopenharmony_ci	list_add(&null_key->key_list, &ep->endpoint_shared_keys);
10362306a36Sopenharmony_ci
10462306a36Sopenharmony_ci	/* Add the null key to the endpoint shared keys list and
10562306a36Sopenharmony_ci	 * set the hmcas and chunks pointers.
10662306a36Sopenharmony_ci	 */
10762306a36Sopenharmony_ci	ep->prsctp_enable = net->sctp.prsctp_enable;
10862306a36Sopenharmony_ci	ep->reconf_enable = net->sctp.reconf_enable;
10962306a36Sopenharmony_ci	ep->ecn_enable = net->sctp.ecn_enable;
11062306a36Sopenharmony_ci
11162306a36Sopenharmony_ci	/* Remember who we are attached to.  */
11262306a36Sopenharmony_ci	ep->base.sk = sk;
11362306a36Sopenharmony_ci	ep->base.net = sock_net(sk);
11462306a36Sopenharmony_ci	sock_hold(ep->base.sk);
11562306a36Sopenharmony_ci
11662306a36Sopenharmony_ci	return ep;
11762306a36Sopenharmony_ci
11862306a36Sopenharmony_cinomem_shkey:
11962306a36Sopenharmony_ci	sctp_auth_free(ep);
12062306a36Sopenharmony_cinomem:
12162306a36Sopenharmony_ci	kfree(ep->digest);
12262306a36Sopenharmony_ci	return NULL;
12362306a36Sopenharmony_ci
12462306a36Sopenharmony_ci}
12562306a36Sopenharmony_ci
12662306a36Sopenharmony_ci/* Create a sctp_endpoint with all that boring stuff initialized.
12762306a36Sopenharmony_ci * Returns NULL if there isn't enough memory.
12862306a36Sopenharmony_ci */
12962306a36Sopenharmony_cistruct sctp_endpoint *sctp_endpoint_new(struct sock *sk, gfp_t gfp)
13062306a36Sopenharmony_ci{
13162306a36Sopenharmony_ci	struct sctp_endpoint *ep;
13262306a36Sopenharmony_ci
13362306a36Sopenharmony_ci	/* Build a local endpoint. */
13462306a36Sopenharmony_ci	ep = kzalloc(sizeof(*ep), gfp);
13562306a36Sopenharmony_ci	if (!ep)
13662306a36Sopenharmony_ci		goto fail;
13762306a36Sopenharmony_ci
13862306a36Sopenharmony_ci	if (!sctp_endpoint_init(ep, sk, gfp))
13962306a36Sopenharmony_ci		goto fail_init;
14062306a36Sopenharmony_ci
14162306a36Sopenharmony_ci	SCTP_DBG_OBJCNT_INC(ep);
14262306a36Sopenharmony_ci	return ep;
14362306a36Sopenharmony_ci
14462306a36Sopenharmony_cifail_init:
14562306a36Sopenharmony_ci	kfree(ep);
14662306a36Sopenharmony_cifail:
14762306a36Sopenharmony_ci	return NULL;
14862306a36Sopenharmony_ci}
14962306a36Sopenharmony_ci
15062306a36Sopenharmony_ci/* Add an association to an endpoint.  */
15162306a36Sopenharmony_civoid sctp_endpoint_add_asoc(struct sctp_endpoint *ep,
15262306a36Sopenharmony_ci			    struct sctp_association *asoc)
15362306a36Sopenharmony_ci{
15462306a36Sopenharmony_ci	struct sock *sk = ep->base.sk;
15562306a36Sopenharmony_ci
15662306a36Sopenharmony_ci	/* If this is a temporary association, don't bother
15762306a36Sopenharmony_ci	 * since we'll be removing it shortly and don't
15862306a36Sopenharmony_ci	 * want anyone to find it anyway.
15962306a36Sopenharmony_ci	 */
16062306a36Sopenharmony_ci	if (asoc->temp)
16162306a36Sopenharmony_ci		return;
16262306a36Sopenharmony_ci
16362306a36Sopenharmony_ci	/* Now just add it to our list of asocs */
16462306a36Sopenharmony_ci	list_add_tail(&asoc->asocs, &ep->asocs);
16562306a36Sopenharmony_ci
16662306a36Sopenharmony_ci	/* Increment the backlog value for a TCP-style listening socket. */
16762306a36Sopenharmony_ci	if (sctp_style(sk, TCP) && sctp_sstate(sk, LISTENING))
16862306a36Sopenharmony_ci		sk_acceptq_added(sk);
16962306a36Sopenharmony_ci}
17062306a36Sopenharmony_ci
17162306a36Sopenharmony_ci/* Free the endpoint structure.  Delay cleanup until
17262306a36Sopenharmony_ci * all users have released their reference count on this structure.
17362306a36Sopenharmony_ci */
17462306a36Sopenharmony_civoid sctp_endpoint_free(struct sctp_endpoint *ep)
17562306a36Sopenharmony_ci{
17662306a36Sopenharmony_ci	ep->base.dead = true;
17762306a36Sopenharmony_ci
17862306a36Sopenharmony_ci	inet_sk_set_state(ep->base.sk, SCTP_SS_CLOSED);
17962306a36Sopenharmony_ci
18062306a36Sopenharmony_ci	/* Unlink this endpoint, so we can't find it again! */
18162306a36Sopenharmony_ci	sctp_unhash_endpoint(ep);
18262306a36Sopenharmony_ci
18362306a36Sopenharmony_ci	sctp_endpoint_put(ep);
18462306a36Sopenharmony_ci}
18562306a36Sopenharmony_ci
18662306a36Sopenharmony_ci/* Final destructor for endpoint.  */
18762306a36Sopenharmony_cistatic void sctp_endpoint_destroy_rcu(struct rcu_head *head)
18862306a36Sopenharmony_ci{
18962306a36Sopenharmony_ci	struct sctp_endpoint *ep = container_of(head, struct sctp_endpoint, rcu);
19062306a36Sopenharmony_ci	struct sock *sk = ep->base.sk;
19162306a36Sopenharmony_ci
19262306a36Sopenharmony_ci	sctp_sk(sk)->ep = NULL;
19362306a36Sopenharmony_ci	sock_put(sk);
19462306a36Sopenharmony_ci
19562306a36Sopenharmony_ci	kfree(ep);
19662306a36Sopenharmony_ci	SCTP_DBG_OBJCNT_DEC(ep);
19762306a36Sopenharmony_ci}
19862306a36Sopenharmony_ci
19962306a36Sopenharmony_cistatic void sctp_endpoint_destroy(struct sctp_endpoint *ep)
20062306a36Sopenharmony_ci{
20162306a36Sopenharmony_ci	struct sock *sk;
20262306a36Sopenharmony_ci
20362306a36Sopenharmony_ci	if (unlikely(!ep->base.dead)) {
20462306a36Sopenharmony_ci		WARN(1, "Attempt to destroy undead endpoint %p!\n", ep);
20562306a36Sopenharmony_ci		return;
20662306a36Sopenharmony_ci	}
20762306a36Sopenharmony_ci
20862306a36Sopenharmony_ci	/* Free the digest buffer */
20962306a36Sopenharmony_ci	kfree(ep->digest);
21062306a36Sopenharmony_ci
21162306a36Sopenharmony_ci	/* SCTP-AUTH: Free up AUTH releated data such as shared keys
21262306a36Sopenharmony_ci	 * chunks and hmacs arrays that were allocated
21362306a36Sopenharmony_ci	 */
21462306a36Sopenharmony_ci	sctp_auth_destroy_keys(&ep->endpoint_shared_keys);
21562306a36Sopenharmony_ci	sctp_auth_free(ep);
21662306a36Sopenharmony_ci
21762306a36Sopenharmony_ci	/* Cleanup. */
21862306a36Sopenharmony_ci	sctp_inq_free(&ep->base.inqueue);
21962306a36Sopenharmony_ci	sctp_bind_addr_free(&ep->base.bind_addr);
22062306a36Sopenharmony_ci
22162306a36Sopenharmony_ci	memset(ep->secret_key, 0, sizeof(ep->secret_key));
22262306a36Sopenharmony_ci
22362306a36Sopenharmony_ci	sk = ep->base.sk;
22462306a36Sopenharmony_ci	/* Remove and free the port */
22562306a36Sopenharmony_ci	if (sctp_sk(sk)->bind_hash)
22662306a36Sopenharmony_ci		sctp_put_port(sk);
22762306a36Sopenharmony_ci
22862306a36Sopenharmony_ci	call_rcu(&ep->rcu, sctp_endpoint_destroy_rcu);
22962306a36Sopenharmony_ci}
23062306a36Sopenharmony_ci
23162306a36Sopenharmony_ci/* Hold a reference to an endpoint. */
23262306a36Sopenharmony_ciint sctp_endpoint_hold(struct sctp_endpoint *ep)
23362306a36Sopenharmony_ci{
23462306a36Sopenharmony_ci	return refcount_inc_not_zero(&ep->base.refcnt);
23562306a36Sopenharmony_ci}
23662306a36Sopenharmony_ci
23762306a36Sopenharmony_ci/* Release a reference to an endpoint and clean up if there are
23862306a36Sopenharmony_ci * no more references.
23962306a36Sopenharmony_ci */
24062306a36Sopenharmony_civoid sctp_endpoint_put(struct sctp_endpoint *ep)
24162306a36Sopenharmony_ci{
24262306a36Sopenharmony_ci	if (refcount_dec_and_test(&ep->base.refcnt))
24362306a36Sopenharmony_ci		sctp_endpoint_destroy(ep);
24462306a36Sopenharmony_ci}
24562306a36Sopenharmony_ci
24662306a36Sopenharmony_ci/* Is this the endpoint we are looking for?  */
24762306a36Sopenharmony_cistruct sctp_endpoint *sctp_endpoint_is_match(struct sctp_endpoint *ep,
24862306a36Sopenharmony_ci					       struct net *net,
24962306a36Sopenharmony_ci					       const union sctp_addr *laddr,
25062306a36Sopenharmony_ci					       int dif, int sdif)
25162306a36Sopenharmony_ci{
25262306a36Sopenharmony_ci	int bound_dev_if = READ_ONCE(ep->base.sk->sk_bound_dev_if);
25362306a36Sopenharmony_ci	struct sctp_endpoint *retval = NULL;
25462306a36Sopenharmony_ci
25562306a36Sopenharmony_ci	if (net_eq(ep->base.net, net) &&
25662306a36Sopenharmony_ci	    sctp_sk_bound_dev_eq(net, bound_dev_if, dif, sdif) &&
25762306a36Sopenharmony_ci	    (htons(ep->base.bind_addr.port) == laddr->v4.sin_port)) {
25862306a36Sopenharmony_ci		if (sctp_bind_addr_match(&ep->base.bind_addr, laddr,
25962306a36Sopenharmony_ci					 sctp_sk(ep->base.sk)))
26062306a36Sopenharmony_ci			retval = ep;
26162306a36Sopenharmony_ci	}
26262306a36Sopenharmony_ci
26362306a36Sopenharmony_ci	return retval;
26462306a36Sopenharmony_ci}
26562306a36Sopenharmony_ci
26662306a36Sopenharmony_ci/* Find the association that goes with this chunk.
26762306a36Sopenharmony_ci * We lookup the transport from hashtable at first, then get association
26862306a36Sopenharmony_ci * through t->assoc.
26962306a36Sopenharmony_ci */
27062306a36Sopenharmony_cistruct sctp_association *sctp_endpoint_lookup_assoc(
27162306a36Sopenharmony_ci	const struct sctp_endpoint *ep,
27262306a36Sopenharmony_ci	const union sctp_addr *paddr,
27362306a36Sopenharmony_ci	struct sctp_transport **transport)
27462306a36Sopenharmony_ci{
27562306a36Sopenharmony_ci	struct sctp_association *asoc = NULL;
27662306a36Sopenharmony_ci	struct sctp_transport *t;
27762306a36Sopenharmony_ci
27862306a36Sopenharmony_ci	*transport = NULL;
27962306a36Sopenharmony_ci
28062306a36Sopenharmony_ci	/* If the local port is not set, there can't be any associations
28162306a36Sopenharmony_ci	 * on this endpoint.
28262306a36Sopenharmony_ci	 */
28362306a36Sopenharmony_ci	if (!ep->base.bind_addr.port)
28462306a36Sopenharmony_ci		return NULL;
28562306a36Sopenharmony_ci
28662306a36Sopenharmony_ci	rcu_read_lock();
28762306a36Sopenharmony_ci	t = sctp_epaddr_lookup_transport(ep, paddr);
28862306a36Sopenharmony_ci	if (!t)
28962306a36Sopenharmony_ci		goto out;
29062306a36Sopenharmony_ci
29162306a36Sopenharmony_ci	*transport = t;
29262306a36Sopenharmony_ci	asoc = t->asoc;
29362306a36Sopenharmony_ciout:
29462306a36Sopenharmony_ci	rcu_read_unlock();
29562306a36Sopenharmony_ci	return asoc;
29662306a36Sopenharmony_ci}
29762306a36Sopenharmony_ci
29862306a36Sopenharmony_ci/* Look for any peeled off association from the endpoint that matches the
29962306a36Sopenharmony_ci * given peer address.
30062306a36Sopenharmony_ci */
30162306a36Sopenharmony_cibool sctp_endpoint_is_peeled_off(struct sctp_endpoint *ep,
30262306a36Sopenharmony_ci				 const union sctp_addr *paddr)
30362306a36Sopenharmony_ci{
30462306a36Sopenharmony_ci	int bound_dev_if = READ_ONCE(ep->base.sk->sk_bound_dev_if);
30562306a36Sopenharmony_ci	struct sctp_sockaddr_entry *addr;
30662306a36Sopenharmony_ci	struct net *net = ep->base.net;
30762306a36Sopenharmony_ci	struct sctp_bind_addr *bp;
30862306a36Sopenharmony_ci
30962306a36Sopenharmony_ci	bp = &ep->base.bind_addr;
31062306a36Sopenharmony_ci	/* This function is called with the socket lock held,
31162306a36Sopenharmony_ci	 * so the address_list can not change.
31262306a36Sopenharmony_ci	 */
31362306a36Sopenharmony_ci	list_for_each_entry(addr, &bp->address_list, list) {
31462306a36Sopenharmony_ci		if (sctp_has_association(net, &addr->a, paddr,
31562306a36Sopenharmony_ci					 bound_dev_if, bound_dev_if))
31662306a36Sopenharmony_ci			return true;
31762306a36Sopenharmony_ci	}
31862306a36Sopenharmony_ci
31962306a36Sopenharmony_ci	return false;
32062306a36Sopenharmony_ci}
32162306a36Sopenharmony_ci
32262306a36Sopenharmony_ci/* Do delayed input processing.  This is scheduled by sctp_rcv().
32362306a36Sopenharmony_ci * This may be called on BH or task time.
32462306a36Sopenharmony_ci */
32562306a36Sopenharmony_cistatic void sctp_endpoint_bh_rcv(struct work_struct *work)
32662306a36Sopenharmony_ci{
32762306a36Sopenharmony_ci	struct sctp_endpoint *ep =
32862306a36Sopenharmony_ci		container_of(work, struct sctp_endpoint,
32962306a36Sopenharmony_ci			     base.inqueue.immediate);
33062306a36Sopenharmony_ci	struct sctp_association *asoc;
33162306a36Sopenharmony_ci	struct sock *sk;
33262306a36Sopenharmony_ci	struct net *net;
33362306a36Sopenharmony_ci	struct sctp_transport *transport;
33462306a36Sopenharmony_ci	struct sctp_chunk *chunk;
33562306a36Sopenharmony_ci	struct sctp_inq *inqueue;
33662306a36Sopenharmony_ci	union sctp_subtype subtype;
33762306a36Sopenharmony_ci	enum sctp_state state;
33862306a36Sopenharmony_ci	int error = 0;
33962306a36Sopenharmony_ci	int first_time = 1;	/* is this the first time through the loop */
34062306a36Sopenharmony_ci
34162306a36Sopenharmony_ci	if (ep->base.dead)
34262306a36Sopenharmony_ci		return;
34362306a36Sopenharmony_ci
34462306a36Sopenharmony_ci	asoc = NULL;
34562306a36Sopenharmony_ci	inqueue = &ep->base.inqueue;
34662306a36Sopenharmony_ci	sk = ep->base.sk;
34762306a36Sopenharmony_ci	net = sock_net(sk);
34862306a36Sopenharmony_ci
34962306a36Sopenharmony_ci	while (NULL != (chunk = sctp_inq_pop(inqueue))) {
35062306a36Sopenharmony_ci		subtype = SCTP_ST_CHUNK(chunk->chunk_hdr->type);
35162306a36Sopenharmony_ci
35262306a36Sopenharmony_ci		/* If the first chunk in the packet is AUTH, do special
35362306a36Sopenharmony_ci		 * processing specified in Section 6.3 of SCTP-AUTH spec
35462306a36Sopenharmony_ci		 */
35562306a36Sopenharmony_ci		if (first_time && (subtype.chunk == SCTP_CID_AUTH)) {
35662306a36Sopenharmony_ci			struct sctp_chunkhdr *next_hdr;
35762306a36Sopenharmony_ci
35862306a36Sopenharmony_ci			next_hdr = sctp_inq_peek(inqueue);
35962306a36Sopenharmony_ci			if (!next_hdr)
36062306a36Sopenharmony_ci				goto normal;
36162306a36Sopenharmony_ci
36262306a36Sopenharmony_ci			/* If the next chunk is COOKIE-ECHO, skip the AUTH
36362306a36Sopenharmony_ci			 * chunk while saving a pointer to it so we can do
36462306a36Sopenharmony_ci			 * Authentication later (during cookie-echo
36562306a36Sopenharmony_ci			 * processing).
36662306a36Sopenharmony_ci			 */
36762306a36Sopenharmony_ci			if (next_hdr->type == SCTP_CID_COOKIE_ECHO) {
36862306a36Sopenharmony_ci				chunk->auth_chunk = skb_clone(chunk->skb,
36962306a36Sopenharmony_ci								GFP_ATOMIC);
37062306a36Sopenharmony_ci				chunk->auth = 1;
37162306a36Sopenharmony_ci				continue;
37262306a36Sopenharmony_ci			}
37362306a36Sopenharmony_ci		}
37462306a36Sopenharmony_cinormal:
37562306a36Sopenharmony_ci		/* We might have grown an association since last we
37662306a36Sopenharmony_ci		 * looked, so try again.
37762306a36Sopenharmony_ci		 *
37862306a36Sopenharmony_ci		 * This happens when we've just processed our
37962306a36Sopenharmony_ci		 * COOKIE-ECHO chunk.
38062306a36Sopenharmony_ci		 */
38162306a36Sopenharmony_ci		if (NULL == chunk->asoc) {
38262306a36Sopenharmony_ci			asoc = sctp_endpoint_lookup_assoc(ep,
38362306a36Sopenharmony_ci							  sctp_source(chunk),
38462306a36Sopenharmony_ci							  &transport);
38562306a36Sopenharmony_ci			chunk->asoc = asoc;
38662306a36Sopenharmony_ci			chunk->transport = transport;
38762306a36Sopenharmony_ci		}
38862306a36Sopenharmony_ci
38962306a36Sopenharmony_ci		state = asoc ? asoc->state : SCTP_STATE_CLOSED;
39062306a36Sopenharmony_ci		if (sctp_auth_recv_cid(subtype.chunk, asoc) && !chunk->auth)
39162306a36Sopenharmony_ci			continue;
39262306a36Sopenharmony_ci
39362306a36Sopenharmony_ci		/* Remember where the last DATA chunk came from so we
39462306a36Sopenharmony_ci		 * know where to send the SACK.
39562306a36Sopenharmony_ci		 */
39662306a36Sopenharmony_ci		if (asoc && sctp_chunk_is_data(chunk))
39762306a36Sopenharmony_ci			asoc->peer.last_data_from = chunk->transport;
39862306a36Sopenharmony_ci		else {
39962306a36Sopenharmony_ci			SCTP_INC_STATS(ep->base.net, SCTP_MIB_INCTRLCHUNKS);
40062306a36Sopenharmony_ci			if (asoc)
40162306a36Sopenharmony_ci				asoc->stats.ictrlchunks++;
40262306a36Sopenharmony_ci		}
40362306a36Sopenharmony_ci
40462306a36Sopenharmony_ci		if (chunk->transport)
40562306a36Sopenharmony_ci			chunk->transport->last_time_heard = ktime_get();
40662306a36Sopenharmony_ci
40762306a36Sopenharmony_ci		error = sctp_do_sm(net, SCTP_EVENT_T_CHUNK, subtype, state,
40862306a36Sopenharmony_ci				   ep, asoc, chunk, GFP_ATOMIC);
40962306a36Sopenharmony_ci
41062306a36Sopenharmony_ci		if (error && chunk)
41162306a36Sopenharmony_ci			chunk->pdiscard = 1;
41262306a36Sopenharmony_ci
41362306a36Sopenharmony_ci		/* Check to see if the endpoint is freed in response to
41462306a36Sopenharmony_ci		 * the incoming chunk. If so, get out of the while loop.
41562306a36Sopenharmony_ci		 */
41662306a36Sopenharmony_ci		if (!sctp_sk(sk)->ep)
41762306a36Sopenharmony_ci			break;
41862306a36Sopenharmony_ci
41962306a36Sopenharmony_ci		if (first_time)
42062306a36Sopenharmony_ci			first_time = 0;
42162306a36Sopenharmony_ci	}
42262306a36Sopenharmony_ci}
423