18c2ecf20Sopenharmony_ci// SPDX-License-Identifier: GPL-2.0-or-later
28c2ecf20Sopenharmony_ci/* SCTP kernel implementation
38c2ecf20Sopenharmony_ci * Copyright (c) 1999-2000 Cisco, Inc.
48c2ecf20Sopenharmony_ci * Copyright (c) 1999-2001 Motorola, Inc.
58c2ecf20Sopenharmony_ci * Copyright (c) 2001-2002 International Business Machines, Corp.
68c2ecf20Sopenharmony_ci * Copyright (c) 2001 Intel Corp.
78c2ecf20Sopenharmony_ci * Copyright (c) 2001 Nokia, Inc.
88c2ecf20Sopenharmony_ci * Copyright (c) 2001 La Monte H.P. Yarroll
98c2ecf20Sopenharmony_ci *
108c2ecf20Sopenharmony_ci * This file is part of the SCTP kernel implementation
118c2ecf20Sopenharmony_ci *
128c2ecf20Sopenharmony_ci * This abstraction represents an SCTP endpoint.
138c2ecf20Sopenharmony_ci *
148c2ecf20Sopenharmony_ci * Please send any bug reports or fixes you make to the
158c2ecf20Sopenharmony_ci * email address(es):
168c2ecf20Sopenharmony_ci *    lksctp developers <linux-sctp@vger.kernel.org>
178c2ecf20Sopenharmony_ci *
188c2ecf20Sopenharmony_ci * Written or modified by:
198c2ecf20Sopenharmony_ci *    La Monte H.P. Yarroll <piggy@acm.org>
208c2ecf20Sopenharmony_ci *    Karl Knutson <karl@athena.chicago.il.us>
218c2ecf20Sopenharmony_ci *    Jon Grimm <jgrimm@austin.ibm.com>
228c2ecf20Sopenharmony_ci *    Daisy Chang <daisyc@us.ibm.com>
238c2ecf20Sopenharmony_ci *    Dajiang Zhang <dajiang.zhang@nokia.com>
248c2ecf20Sopenharmony_ci */
258c2ecf20Sopenharmony_ci
268c2ecf20Sopenharmony_ci#include <linux/types.h>
278c2ecf20Sopenharmony_ci#include <linux/slab.h>
288c2ecf20Sopenharmony_ci#include <linux/in.h>
298c2ecf20Sopenharmony_ci#include <linux/random.h>	/* get_random_bytes() */
308c2ecf20Sopenharmony_ci#include <net/sock.h>
318c2ecf20Sopenharmony_ci#include <net/ipv6.h>
328c2ecf20Sopenharmony_ci#include <net/sctp/sctp.h>
338c2ecf20Sopenharmony_ci#include <net/sctp/sm.h>
348c2ecf20Sopenharmony_ci
358c2ecf20Sopenharmony_ci/* Forward declarations for internal helpers. */
368c2ecf20Sopenharmony_cistatic void sctp_endpoint_bh_rcv(struct work_struct *work);
378c2ecf20Sopenharmony_ci
388c2ecf20Sopenharmony_ci/*
398c2ecf20Sopenharmony_ci * Initialize the base fields of the endpoint structure.
408c2ecf20Sopenharmony_ci */
418c2ecf20Sopenharmony_cistatic struct sctp_endpoint *sctp_endpoint_init(struct sctp_endpoint *ep,
428c2ecf20Sopenharmony_ci						struct sock *sk,
438c2ecf20Sopenharmony_ci						gfp_t gfp)
448c2ecf20Sopenharmony_ci{
458c2ecf20Sopenharmony_ci	struct net *net = sock_net(sk);
468c2ecf20Sopenharmony_ci	struct sctp_shared_key *null_key;
478c2ecf20Sopenharmony_ci
488c2ecf20Sopenharmony_ci	ep->digest = kzalloc(SCTP_SIGNATURE_SIZE, gfp);
498c2ecf20Sopenharmony_ci	if (!ep->digest)
508c2ecf20Sopenharmony_ci		return NULL;
518c2ecf20Sopenharmony_ci
528c2ecf20Sopenharmony_ci	ep->asconf_enable = net->sctp.addip_enable;
538c2ecf20Sopenharmony_ci	ep->auth_enable = net->sctp.auth_enable;
548c2ecf20Sopenharmony_ci	if (ep->auth_enable) {
558c2ecf20Sopenharmony_ci		if (sctp_auth_init(ep, gfp))
568c2ecf20Sopenharmony_ci			goto nomem;
578c2ecf20Sopenharmony_ci		if (ep->asconf_enable) {
588c2ecf20Sopenharmony_ci			sctp_auth_ep_add_chunkid(ep, SCTP_CID_ASCONF);
598c2ecf20Sopenharmony_ci			sctp_auth_ep_add_chunkid(ep, SCTP_CID_ASCONF_ACK);
608c2ecf20Sopenharmony_ci		}
618c2ecf20Sopenharmony_ci	}
628c2ecf20Sopenharmony_ci
638c2ecf20Sopenharmony_ci	/* Initialize the base structure. */
648c2ecf20Sopenharmony_ci	/* What type of endpoint are we?  */
658c2ecf20Sopenharmony_ci	ep->base.type = SCTP_EP_TYPE_SOCKET;
668c2ecf20Sopenharmony_ci
678c2ecf20Sopenharmony_ci	/* Initialize the basic object fields. */
688c2ecf20Sopenharmony_ci	refcount_set(&ep->base.refcnt, 1);
698c2ecf20Sopenharmony_ci	ep->base.dead = false;
708c2ecf20Sopenharmony_ci
718c2ecf20Sopenharmony_ci	/* Create an input queue.  */
728c2ecf20Sopenharmony_ci	sctp_inq_init(&ep->base.inqueue);
738c2ecf20Sopenharmony_ci
748c2ecf20Sopenharmony_ci	/* Set its top-half handler */
758c2ecf20Sopenharmony_ci	sctp_inq_set_th_handler(&ep->base.inqueue, sctp_endpoint_bh_rcv);
768c2ecf20Sopenharmony_ci
778c2ecf20Sopenharmony_ci	/* Initialize the bind addr area */
788c2ecf20Sopenharmony_ci	sctp_bind_addr_init(&ep->base.bind_addr, 0);
798c2ecf20Sopenharmony_ci
808c2ecf20Sopenharmony_ci	/* Create the lists of associations.  */
818c2ecf20Sopenharmony_ci	INIT_LIST_HEAD(&ep->asocs);
828c2ecf20Sopenharmony_ci
838c2ecf20Sopenharmony_ci	/* Use SCTP specific send buffer space queues.  */
848c2ecf20Sopenharmony_ci	ep->sndbuf_policy = net->sctp.sndbuf_policy;
858c2ecf20Sopenharmony_ci
868c2ecf20Sopenharmony_ci	sk->sk_data_ready = sctp_data_ready;
878c2ecf20Sopenharmony_ci	sk->sk_write_space = sctp_write_space;
888c2ecf20Sopenharmony_ci	sock_set_flag(sk, SOCK_USE_WRITE_QUEUE);
898c2ecf20Sopenharmony_ci
908c2ecf20Sopenharmony_ci	/* Get the receive buffer policy for this endpoint */
918c2ecf20Sopenharmony_ci	ep->rcvbuf_policy = net->sctp.rcvbuf_policy;
928c2ecf20Sopenharmony_ci
938c2ecf20Sopenharmony_ci	/* Initialize the secret key used with cookie. */
948c2ecf20Sopenharmony_ci	get_random_bytes(ep->secret_key, sizeof(ep->secret_key));
958c2ecf20Sopenharmony_ci
968c2ecf20Sopenharmony_ci	/* SCTP-AUTH extensions*/
978c2ecf20Sopenharmony_ci	INIT_LIST_HEAD(&ep->endpoint_shared_keys);
988c2ecf20Sopenharmony_ci	null_key = sctp_auth_shkey_create(0, gfp);
998c2ecf20Sopenharmony_ci	if (!null_key)
1008c2ecf20Sopenharmony_ci		goto nomem_shkey;
1018c2ecf20Sopenharmony_ci
1028c2ecf20Sopenharmony_ci	list_add(&null_key->key_list, &ep->endpoint_shared_keys);
1038c2ecf20Sopenharmony_ci
1048c2ecf20Sopenharmony_ci	/* Add the null key to the endpoint shared keys list and
1058c2ecf20Sopenharmony_ci	 * set the hmcas and chunks pointers.
1068c2ecf20Sopenharmony_ci	 */
1078c2ecf20Sopenharmony_ci	ep->prsctp_enable = net->sctp.prsctp_enable;
1088c2ecf20Sopenharmony_ci	ep->reconf_enable = net->sctp.reconf_enable;
1098c2ecf20Sopenharmony_ci	ep->ecn_enable = net->sctp.ecn_enable;
1108c2ecf20Sopenharmony_ci
1118c2ecf20Sopenharmony_ci	/* Remember who we are attached to.  */
1128c2ecf20Sopenharmony_ci	ep->base.sk = sk;
1138c2ecf20Sopenharmony_ci	ep->base.net = sock_net(sk);
1148c2ecf20Sopenharmony_ci	sock_hold(ep->base.sk);
1158c2ecf20Sopenharmony_ci
1168c2ecf20Sopenharmony_ci	return ep;
1178c2ecf20Sopenharmony_ci
1188c2ecf20Sopenharmony_cinomem_shkey:
1198c2ecf20Sopenharmony_ci	sctp_auth_free(ep);
1208c2ecf20Sopenharmony_cinomem:
1218c2ecf20Sopenharmony_ci	kfree(ep->digest);
1228c2ecf20Sopenharmony_ci	return NULL;
1238c2ecf20Sopenharmony_ci
1248c2ecf20Sopenharmony_ci}
1258c2ecf20Sopenharmony_ci
1268c2ecf20Sopenharmony_ci/* Create a sctp_endpoint with all that boring stuff initialized.
1278c2ecf20Sopenharmony_ci * Returns NULL if there isn't enough memory.
1288c2ecf20Sopenharmony_ci */
1298c2ecf20Sopenharmony_cistruct sctp_endpoint *sctp_endpoint_new(struct sock *sk, gfp_t gfp)
1308c2ecf20Sopenharmony_ci{
1318c2ecf20Sopenharmony_ci	struct sctp_endpoint *ep;
1328c2ecf20Sopenharmony_ci
1338c2ecf20Sopenharmony_ci	/* Build a local endpoint. */
1348c2ecf20Sopenharmony_ci	ep = kzalloc(sizeof(*ep), gfp);
1358c2ecf20Sopenharmony_ci	if (!ep)
1368c2ecf20Sopenharmony_ci		goto fail;
1378c2ecf20Sopenharmony_ci
1388c2ecf20Sopenharmony_ci	if (!sctp_endpoint_init(ep, sk, gfp))
1398c2ecf20Sopenharmony_ci		goto fail_init;
1408c2ecf20Sopenharmony_ci
1418c2ecf20Sopenharmony_ci	SCTP_DBG_OBJCNT_INC(ep);
1428c2ecf20Sopenharmony_ci	return ep;
1438c2ecf20Sopenharmony_ci
1448c2ecf20Sopenharmony_cifail_init:
1458c2ecf20Sopenharmony_ci	kfree(ep);
1468c2ecf20Sopenharmony_cifail:
1478c2ecf20Sopenharmony_ci	return NULL;
1488c2ecf20Sopenharmony_ci}
1498c2ecf20Sopenharmony_ci
1508c2ecf20Sopenharmony_ci/* Add an association to an endpoint.  */
1518c2ecf20Sopenharmony_civoid sctp_endpoint_add_asoc(struct sctp_endpoint *ep,
1528c2ecf20Sopenharmony_ci			    struct sctp_association *asoc)
1538c2ecf20Sopenharmony_ci{
1548c2ecf20Sopenharmony_ci	struct sock *sk = ep->base.sk;
1558c2ecf20Sopenharmony_ci
1568c2ecf20Sopenharmony_ci	/* If this is a temporary association, don't bother
1578c2ecf20Sopenharmony_ci	 * since we'll be removing it shortly and don't
1588c2ecf20Sopenharmony_ci	 * want anyone to find it anyway.
1598c2ecf20Sopenharmony_ci	 */
1608c2ecf20Sopenharmony_ci	if (asoc->temp)
1618c2ecf20Sopenharmony_ci		return;
1628c2ecf20Sopenharmony_ci
1638c2ecf20Sopenharmony_ci	/* Now just add it to our list of asocs */
1648c2ecf20Sopenharmony_ci	list_add_tail(&asoc->asocs, &ep->asocs);
1658c2ecf20Sopenharmony_ci
1668c2ecf20Sopenharmony_ci	/* Increment the backlog value for a TCP-style listening socket. */
1678c2ecf20Sopenharmony_ci	if (sctp_style(sk, TCP) && sctp_sstate(sk, LISTENING))
1688c2ecf20Sopenharmony_ci		sk_acceptq_added(sk);
1698c2ecf20Sopenharmony_ci}
1708c2ecf20Sopenharmony_ci
1718c2ecf20Sopenharmony_ci/* Free the endpoint structure.  Delay cleanup until
1728c2ecf20Sopenharmony_ci * all users have released their reference count on this structure.
1738c2ecf20Sopenharmony_ci */
1748c2ecf20Sopenharmony_civoid sctp_endpoint_free(struct sctp_endpoint *ep)
1758c2ecf20Sopenharmony_ci{
1768c2ecf20Sopenharmony_ci	ep->base.dead = true;
1778c2ecf20Sopenharmony_ci
1788c2ecf20Sopenharmony_ci	inet_sk_set_state(ep->base.sk, SCTP_SS_CLOSED);
1798c2ecf20Sopenharmony_ci
1808c2ecf20Sopenharmony_ci	/* Unlink this endpoint, so we can't find it again! */
1818c2ecf20Sopenharmony_ci	sctp_unhash_endpoint(ep);
1828c2ecf20Sopenharmony_ci
1838c2ecf20Sopenharmony_ci	sctp_endpoint_put(ep);
1848c2ecf20Sopenharmony_ci}
1858c2ecf20Sopenharmony_ci
1868c2ecf20Sopenharmony_ci/* Final destructor for endpoint.  */
1878c2ecf20Sopenharmony_cistatic void sctp_endpoint_destroy_rcu(struct rcu_head *head)
1888c2ecf20Sopenharmony_ci{
1898c2ecf20Sopenharmony_ci	struct sctp_endpoint *ep = container_of(head, struct sctp_endpoint, rcu);
1908c2ecf20Sopenharmony_ci	struct sock *sk = ep->base.sk;
1918c2ecf20Sopenharmony_ci
1928c2ecf20Sopenharmony_ci	sctp_sk(sk)->ep = NULL;
1938c2ecf20Sopenharmony_ci	sock_put(sk);
1948c2ecf20Sopenharmony_ci
1958c2ecf20Sopenharmony_ci	kfree(ep);
1968c2ecf20Sopenharmony_ci	SCTP_DBG_OBJCNT_DEC(ep);
1978c2ecf20Sopenharmony_ci}
1988c2ecf20Sopenharmony_ci
1998c2ecf20Sopenharmony_cistatic void sctp_endpoint_destroy(struct sctp_endpoint *ep)
2008c2ecf20Sopenharmony_ci{
2018c2ecf20Sopenharmony_ci	struct sock *sk;
2028c2ecf20Sopenharmony_ci
2038c2ecf20Sopenharmony_ci	if (unlikely(!ep->base.dead)) {
2048c2ecf20Sopenharmony_ci		WARN(1, "Attempt to destroy undead endpoint %p!\n", ep);
2058c2ecf20Sopenharmony_ci		return;
2068c2ecf20Sopenharmony_ci	}
2078c2ecf20Sopenharmony_ci
2088c2ecf20Sopenharmony_ci	/* Free the digest buffer */
2098c2ecf20Sopenharmony_ci	kfree(ep->digest);
2108c2ecf20Sopenharmony_ci
2118c2ecf20Sopenharmony_ci	/* SCTP-AUTH: Free up AUTH releated data such as shared keys
2128c2ecf20Sopenharmony_ci	 * chunks and hmacs arrays that were allocated
2138c2ecf20Sopenharmony_ci	 */
2148c2ecf20Sopenharmony_ci	sctp_auth_destroy_keys(&ep->endpoint_shared_keys);
2158c2ecf20Sopenharmony_ci	sctp_auth_free(ep);
2168c2ecf20Sopenharmony_ci
2178c2ecf20Sopenharmony_ci	/* Cleanup. */
2188c2ecf20Sopenharmony_ci	sctp_inq_free(&ep->base.inqueue);
2198c2ecf20Sopenharmony_ci	sctp_bind_addr_free(&ep->base.bind_addr);
2208c2ecf20Sopenharmony_ci
2218c2ecf20Sopenharmony_ci	memset(ep->secret_key, 0, sizeof(ep->secret_key));
2228c2ecf20Sopenharmony_ci
2238c2ecf20Sopenharmony_ci	sk = ep->base.sk;
2248c2ecf20Sopenharmony_ci	/* Remove and free the port */
2258c2ecf20Sopenharmony_ci	if (sctp_sk(sk)->bind_hash)
2268c2ecf20Sopenharmony_ci		sctp_put_port(sk);
2278c2ecf20Sopenharmony_ci
2288c2ecf20Sopenharmony_ci	call_rcu(&ep->rcu, sctp_endpoint_destroy_rcu);
2298c2ecf20Sopenharmony_ci}
2308c2ecf20Sopenharmony_ci
2318c2ecf20Sopenharmony_ci/* Hold a reference to an endpoint. */
2328c2ecf20Sopenharmony_ciint sctp_endpoint_hold(struct sctp_endpoint *ep)
2338c2ecf20Sopenharmony_ci{
2348c2ecf20Sopenharmony_ci	return refcount_inc_not_zero(&ep->base.refcnt);
2358c2ecf20Sopenharmony_ci}
2368c2ecf20Sopenharmony_ci
2378c2ecf20Sopenharmony_ci/* Release a reference to an endpoint and clean up if there are
2388c2ecf20Sopenharmony_ci * no more references.
2398c2ecf20Sopenharmony_ci */
2408c2ecf20Sopenharmony_civoid sctp_endpoint_put(struct sctp_endpoint *ep)
2418c2ecf20Sopenharmony_ci{
2428c2ecf20Sopenharmony_ci	if (refcount_dec_and_test(&ep->base.refcnt))
2438c2ecf20Sopenharmony_ci		sctp_endpoint_destroy(ep);
2448c2ecf20Sopenharmony_ci}
2458c2ecf20Sopenharmony_ci
2468c2ecf20Sopenharmony_ci/* Is this the endpoint we are looking for?  */
2478c2ecf20Sopenharmony_cistruct sctp_endpoint *sctp_endpoint_is_match(struct sctp_endpoint *ep,
2488c2ecf20Sopenharmony_ci					       struct net *net,
2498c2ecf20Sopenharmony_ci					       const union sctp_addr *laddr)
2508c2ecf20Sopenharmony_ci{
2518c2ecf20Sopenharmony_ci	struct sctp_endpoint *retval = NULL;
2528c2ecf20Sopenharmony_ci
2538c2ecf20Sopenharmony_ci	if ((htons(ep->base.bind_addr.port) == laddr->v4.sin_port) &&
2548c2ecf20Sopenharmony_ci	    net_eq(ep->base.net, net)) {
2558c2ecf20Sopenharmony_ci		if (sctp_bind_addr_match(&ep->base.bind_addr, laddr,
2568c2ecf20Sopenharmony_ci					 sctp_sk(ep->base.sk)))
2578c2ecf20Sopenharmony_ci			retval = ep;
2588c2ecf20Sopenharmony_ci	}
2598c2ecf20Sopenharmony_ci
2608c2ecf20Sopenharmony_ci	return retval;
2618c2ecf20Sopenharmony_ci}
2628c2ecf20Sopenharmony_ci
2638c2ecf20Sopenharmony_ci/* Find the association that goes with this chunk.
2648c2ecf20Sopenharmony_ci * We lookup the transport from hashtable at first, then get association
2658c2ecf20Sopenharmony_ci * through t->assoc.
2668c2ecf20Sopenharmony_ci */
2678c2ecf20Sopenharmony_cistruct sctp_association *sctp_endpoint_lookup_assoc(
2688c2ecf20Sopenharmony_ci	const struct sctp_endpoint *ep,
2698c2ecf20Sopenharmony_ci	const union sctp_addr *paddr,
2708c2ecf20Sopenharmony_ci	struct sctp_transport **transport)
2718c2ecf20Sopenharmony_ci{
2728c2ecf20Sopenharmony_ci	struct sctp_association *asoc = NULL;
2738c2ecf20Sopenharmony_ci	struct sctp_transport *t;
2748c2ecf20Sopenharmony_ci
2758c2ecf20Sopenharmony_ci	*transport = NULL;
2768c2ecf20Sopenharmony_ci
2778c2ecf20Sopenharmony_ci	/* If the local port is not set, there can't be any associations
2788c2ecf20Sopenharmony_ci	 * on this endpoint.
2798c2ecf20Sopenharmony_ci	 */
2808c2ecf20Sopenharmony_ci	if (!ep->base.bind_addr.port)
2818c2ecf20Sopenharmony_ci		return NULL;
2828c2ecf20Sopenharmony_ci
2838c2ecf20Sopenharmony_ci	rcu_read_lock();
2848c2ecf20Sopenharmony_ci	t = sctp_epaddr_lookup_transport(ep, paddr);
2858c2ecf20Sopenharmony_ci	if (!t)
2868c2ecf20Sopenharmony_ci		goto out;
2878c2ecf20Sopenharmony_ci
2888c2ecf20Sopenharmony_ci	*transport = t;
2898c2ecf20Sopenharmony_ci	asoc = t->asoc;
2908c2ecf20Sopenharmony_ciout:
2918c2ecf20Sopenharmony_ci	rcu_read_unlock();
2928c2ecf20Sopenharmony_ci	return asoc;
2938c2ecf20Sopenharmony_ci}
2948c2ecf20Sopenharmony_ci
2958c2ecf20Sopenharmony_ci/* Look for any peeled off association from the endpoint that matches the
2968c2ecf20Sopenharmony_ci * given peer address.
2978c2ecf20Sopenharmony_ci */
2988c2ecf20Sopenharmony_cibool sctp_endpoint_is_peeled_off(struct sctp_endpoint *ep,
2998c2ecf20Sopenharmony_ci				 const union sctp_addr *paddr)
3008c2ecf20Sopenharmony_ci{
3018c2ecf20Sopenharmony_ci	struct sctp_sockaddr_entry *addr;
3028c2ecf20Sopenharmony_ci	struct net *net = ep->base.net;
3038c2ecf20Sopenharmony_ci	struct sctp_bind_addr *bp;
3048c2ecf20Sopenharmony_ci
3058c2ecf20Sopenharmony_ci	bp = &ep->base.bind_addr;
3068c2ecf20Sopenharmony_ci	/* This function is called with the socket lock held,
3078c2ecf20Sopenharmony_ci	 * so the address_list can not change.
3088c2ecf20Sopenharmony_ci	 */
3098c2ecf20Sopenharmony_ci	list_for_each_entry(addr, &bp->address_list, list) {
3108c2ecf20Sopenharmony_ci		if (sctp_has_association(net, &addr->a, paddr))
3118c2ecf20Sopenharmony_ci			return true;
3128c2ecf20Sopenharmony_ci	}
3138c2ecf20Sopenharmony_ci
3148c2ecf20Sopenharmony_ci	return false;
3158c2ecf20Sopenharmony_ci}
3168c2ecf20Sopenharmony_ci
3178c2ecf20Sopenharmony_ci/* Do delayed input processing.  This is scheduled by sctp_rcv().
3188c2ecf20Sopenharmony_ci * This may be called on BH or task time.
3198c2ecf20Sopenharmony_ci */
3208c2ecf20Sopenharmony_cistatic void sctp_endpoint_bh_rcv(struct work_struct *work)
3218c2ecf20Sopenharmony_ci{
3228c2ecf20Sopenharmony_ci	struct sctp_endpoint *ep =
3238c2ecf20Sopenharmony_ci		container_of(work, struct sctp_endpoint,
3248c2ecf20Sopenharmony_ci			     base.inqueue.immediate);
3258c2ecf20Sopenharmony_ci	struct sctp_association *asoc;
3268c2ecf20Sopenharmony_ci	struct sock *sk;
3278c2ecf20Sopenharmony_ci	struct net *net;
3288c2ecf20Sopenharmony_ci	struct sctp_transport *transport;
3298c2ecf20Sopenharmony_ci	struct sctp_chunk *chunk;
3308c2ecf20Sopenharmony_ci	struct sctp_inq *inqueue;
3318c2ecf20Sopenharmony_ci	union sctp_subtype subtype;
3328c2ecf20Sopenharmony_ci	enum sctp_state state;
3338c2ecf20Sopenharmony_ci	int error = 0;
3348c2ecf20Sopenharmony_ci	int first_time = 1;	/* is this the first time through the loop */
3358c2ecf20Sopenharmony_ci
3368c2ecf20Sopenharmony_ci	if (ep->base.dead)
3378c2ecf20Sopenharmony_ci		return;
3388c2ecf20Sopenharmony_ci
3398c2ecf20Sopenharmony_ci	asoc = NULL;
3408c2ecf20Sopenharmony_ci	inqueue = &ep->base.inqueue;
3418c2ecf20Sopenharmony_ci	sk = ep->base.sk;
3428c2ecf20Sopenharmony_ci	net = sock_net(sk);
3438c2ecf20Sopenharmony_ci
3448c2ecf20Sopenharmony_ci	while (NULL != (chunk = sctp_inq_pop(inqueue))) {
3458c2ecf20Sopenharmony_ci		subtype = SCTP_ST_CHUNK(chunk->chunk_hdr->type);
3468c2ecf20Sopenharmony_ci
3478c2ecf20Sopenharmony_ci		/* If the first chunk in the packet is AUTH, do special
3488c2ecf20Sopenharmony_ci		 * processing specified in Section 6.3 of SCTP-AUTH spec
3498c2ecf20Sopenharmony_ci		 */
3508c2ecf20Sopenharmony_ci		if (first_time && (subtype.chunk == SCTP_CID_AUTH)) {
3518c2ecf20Sopenharmony_ci			struct sctp_chunkhdr *next_hdr;
3528c2ecf20Sopenharmony_ci
3538c2ecf20Sopenharmony_ci			next_hdr = sctp_inq_peek(inqueue);
3548c2ecf20Sopenharmony_ci			if (!next_hdr)
3558c2ecf20Sopenharmony_ci				goto normal;
3568c2ecf20Sopenharmony_ci
3578c2ecf20Sopenharmony_ci			/* If the next chunk is COOKIE-ECHO, skip the AUTH
3588c2ecf20Sopenharmony_ci			 * chunk while saving a pointer to it so we can do
3598c2ecf20Sopenharmony_ci			 * Authentication later (during cookie-echo
3608c2ecf20Sopenharmony_ci			 * processing).
3618c2ecf20Sopenharmony_ci			 */
3628c2ecf20Sopenharmony_ci			if (next_hdr->type == SCTP_CID_COOKIE_ECHO) {
3638c2ecf20Sopenharmony_ci				chunk->auth_chunk = skb_clone(chunk->skb,
3648c2ecf20Sopenharmony_ci								GFP_ATOMIC);
3658c2ecf20Sopenharmony_ci				chunk->auth = 1;
3668c2ecf20Sopenharmony_ci				continue;
3678c2ecf20Sopenharmony_ci			}
3688c2ecf20Sopenharmony_ci		}
3698c2ecf20Sopenharmony_cinormal:
3708c2ecf20Sopenharmony_ci		/* We might have grown an association since last we
3718c2ecf20Sopenharmony_ci		 * looked, so try again.
3728c2ecf20Sopenharmony_ci		 *
3738c2ecf20Sopenharmony_ci		 * This happens when we've just processed our
3748c2ecf20Sopenharmony_ci		 * COOKIE-ECHO chunk.
3758c2ecf20Sopenharmony_ci		 */
3768c2ecf20Sopenharmony_ci		if (NULL == chunk->asoc) {
3778c2ecf20Sopenharmony_ci			asoc = sctp_endpoint_lookup_assoc(ep,
3788c2ecf20Sopenharmony_ci							  sctp_source(chunk),
3798c2ecf20Sopenharmony_ci							  &transport);
3808c2ecf20Sopenharmony_ci			chunk->asoc = asoc;
3818c2ecf20Sopenharmony_ci			chunk->transport = transport;
3828c2ecf20Sopenharmony_ci		}
3838c2ecf20Sopenharmony_ci
3848c2ecf20Sopenharmony_ci		state = asoc ? asoc->state : SCTP_STATE_CLOSED;
3858c2ecf20Sopenharmony_ci		if (sctp_auth_recv_cid(subtype.chunk, asoc) && !chunk->auth)
3868c2ecf20Sopenharmony_ci			continue;
3878c2ecf20Sopenharmony_ci
3888c2ecf20Sopenharmony_ci		/* Remember where the last DATA chunk came from so we
3898c2ecf20Sopenharmony_ci		 * know where to send the SACK.
3908c2ecf20Sopenharmony_ci		 */
3918c2ecf20Sopenharmony_ci		if (asoc && sctp_chunk_is_data(chunk))
3928c2ecf20Sopenharmony_ci			asoc->peer.last_data_from = chunk->transport;
3938c2ecf20Sopenharmony_ci		else {
3948c2ecf20Sopenharmony_ci			SCTP_INC_STATS(ep->base.net, SCTP_MIB_INCTRLCHUNKS);
3958c2ecf20Sopenharmony_ci			if (asoc)
3968c2ecf20Sopenharmony_ci				asoc->stats.ictrlchunks++;
3978c2ecf20Sopenharmony_ci		}
3988c2ecf20Sopenharmony_ci
3998c2ecf20Sopenharmony_ci		if (chunk->transport)
4008c2ecf20Sopenharmony_ci			chunk->transport->last_time_heard = ktime_get();
4018c2ecf20Sopenharmony_ci
4028c2ecf20Sopenharmony_ci		error = sctp_do_sm(net, SCTP_EVENT_T_CHUNK, subtype, state,
4038c2ecf20Sopenharmony_ci				   ep, asoc, chunk, GFP_ATOMIC);
4048c2ecf20Sopenharmony_ci
4058c2ecf20Sopenharmony_ci		if (error && chunk)
4068c2ecf20Sopenharmony_ci			chunk->pdiscard = 1;
4078c2ecf20Sopenharmony_ci
4088c2ecf20Sopenharmony_ci		/* Check to see if the endpoint is freed in response to
4098c2ecf20Sopenharmony_ci		 * the incoming chunk. If so, get out of the while loop.
4108c2ecf20Sopenharmony_ci		 */
4118c2ecf20Sopenharmony_ci		if (!sctp_sk(sk)->ep)
4128c2ecf20Sopenharmony_ci			break;
4138c2ecf20Sopenharmony_ci
4148c2ecf20Sopenharmony_ci		if (first_time)
4158c2ecf20Sopenharmony_ci			first_time = 0;
4168c2ecf20Sopenharmony_ci	}
4178c2ecf20Sopenharmony_ci}
418