18e8caf97SThomas Gleixner // SPDX-License-Identifier: GPL-2.0-or-later 260c778b2SVlad Yasevich /* SCTP kernel implementation 31da177e4SLinus Torvalds * Copyright (c) 1999-2000 Cisco, Inc. 41da177e4SLinus Torvalds * Copyright (c) 1999-2001 Motorola, Inc. 51da177e4SLinus Torvalds * Copyright (c) 2001-2002 International Business Machines, Corp. 61da177e4SLinus Torvalds * Copyright (c) 2001 Intel Corp. 71da177e4SLinus Torvalds * Copyright (c) 2001 Nokia, Inc. 81da177e4SLinus Torvalds * Copyright (c) 2001 La Monte H.P. Yarroll 91da177e4SLinus Torvalds * 1060c778b2SVlad Yasevich * This file is part of the SCTP kernel implementation 111da177e4SLinus Torvalds * 121da177e4SLinus Torvalds * This abstraction represents an SCTP endpoint. 131da177e4SLinus Torvalds * 141da177e4SLinus Torvalds * Please send any bug reports or fixes you make to the 151da177e4SLinus Torvalds * email address(es): 1691705c61SDaniel Borkmann * lksctp developers <linux-sctp@vger.kernel.org> 171da177e4SLinus Torvalds * 181da177e4SLinus Torvalds * Written or modified by: 191da177e4SLinus Torvalds * La Monte H.P. Yarroll <piggy@acm.org> 201da177e4SLinus Torvalds * Karl Knutson <karl@athena.chicago.il.us> 211da177e4SLinus Torvalds * Jon Grimm <jgrimm@austin.ibm.com> 221da177e4SLinus Torvalds * Daisy Chang <daisyc@us.ibm.com> 231da177e4SLinus Torvalds * Dajiang Zhang <dajiang.zhang@nokia.com> 241da177e4SLinus Torvalds */ 251da177e4SLinus Torvalds 261da177e4SLinus Torvalds #include <linux/types.h> 271da177e4SLinus Torvalds #include <linux/slab.h> 281da177e4SLinus Torvalds #include <linux/in.h> 291da177e4SLinus Torvalds #include <linux/random.h> /* get_random_bytes() */ 301da177e4SLinus Torvalds #include <net/sock.h> 311da177e4SLinus Torvalds #include <net/ipv6.h> 321da177e4SLinus Torvalds #include <net/sctp/sctp.h> 331da177e4SLinus Torvalds #include <net/sctp/sm.h> 341da177e4SLinus Torvalds 351da177e4SLinus Torvalds /* Forward declarations for internal helpers. */ 36c4028958SDavid Howells static void sctp_endpoint_bh_rcv(struct work_struct *work); 371da177e4SLinus Torvalds 381da177e4SLinus Torvalds /* 391da177e4SLinus Torvalds * Initialize the base fields of the endpoint structure. 401da177e4SLinus Torvalds */ 411da177e4SLinus Torvalds static struct sctp_endpoint *sctp_endpoint_init(struct sctp_endpoint *ep, 423182cd84SAlexey Dobriyan struct sock *sk, 43dd0fc66fSAl Viro gfp_t gfp) 441da177e4SLinus Torvalds { 45e1fc3b14SEric W. Biederman struct net *net = sock_net(sk); 46a29a5bd4SVlad Yasevich struct sctp_hmac_algo_param *auth_hmacs = NULL; 47a29a5bd4SVlad Yasevich struct sctp_chunks_param *auth_chunks = NULL; 48a29a5bd4SVlad Yasevich struct sctp_shared_key *null_key; 49a29a5bd4SVlad Yasevich int err; 50a29a5bd4SVlad Yasevich 51b68dbcabSVlad Yasevich ep->digest = kzalloc(SCTP_SIGNATURE_SIZE, gfp); 52b68dbcabSVlad Yasevich if (!ep->digest) 53b68dbcabSVlad Yasevich return NULL; 54b68dbcabSVlad Yasevich 55b14878ccSVlad Yasevich ep->auth_enable = net->sctp.auth_enable; 56b14878ccSVlad Yasevich if (ep->auth_enable) { 57a29a5bd4SVlad Yasevich /* Allocate space for HMACS and CHUNKS authentication 58a29a5bd4SVlad Yasevich * variables. There are arrays that we encode directly 59a29a5bd4SVlad Yasevich * into parameters to make the rest of the operations easier. 60a29a5bd4SVlad Yasevich */ 61acafe7e3SKees Cook auth_hmacs = kzalloc(struct_size(auth_hmacs, hmac_ids, 62acafe7e3SKees Cook SCTP_AUTH_NUM_HMACS), gfp); 63a29a5bd4SVlad Yasevich if (!auth_hmacs) 64a29a5bd4SVlad Yasevich goto nomem; 65a29a5bd4SVlad Yasevich 66a762a9d9SXin Long auth_chunks = kzalloc(sizeof(*auth_chunks) + 67a29a5bd4SVlad Yasevich SCTP_NUM_CHUNK_TYPES, gfp); 68a29a5bd4SVlad Yasevich if (!auth_chunks) 69a29a5bd4SVlad Yasevich goto nomem; 70a29a5bd4SVlad Yasevich 71a29a5bd4SVlad Yasevich /* Initialize the HMACS parameter. 72a29a5bd4SVlad Yasevich * SCTP-AUTH: Section 3.3 73a29a5bd4SVlad Yasevich * Every endpoint supporting SCTP chunk authentication MUST 74a29a5bd4SVlad Yasevich * support the HMAC based on the SHA-1 algorithm. 75a29a5bd4SVlad Yasevich */ 76a29a5bd4SVlad Yasevich auth_hmacs->param_hdr.type = SCTP_PARAM_HMAC_ALGO; 77a29a5bd4SVlad Yasevich auth_hmacs->param_hdr.length = 783c918704SXin Long htons(sizeof(struct sctp_paramhdr) + 2); 79a29a5bd4SVlad Yasevich auth_hmacs->hmac_ids[0] = htons(SCTP_AUTH_HMAC_ID_SHA1); 80a29a5bd4SVlad Yasevich 81a29a5bd4SVlad Yasevich /* Initialize the CHUNKS parameter */ 82a29a5bd4SVlad Yasevich auth_chunks->param_hdr.type = SCTP_PARAM_CHUNKS; 833c918704SXin Long auth_chunks->param_hdr.length = 843c918704SXin Long htons(sizeof(struct sctp_paramhdr)); 85a29a5bd4SVlad Yasevich 86a29a5bd4SVlad Yasevich /* If the Add-IP functionality is enabled, we must 87a29a5bd4SVlad Yasevich * authenticate, ASCONF and ASCONF-ACK chunks 88a29a5bd4SVlad Yasevich */ 89e1fc3b14SEric W. Biederman if (net->sctp.addip_enable) { 90a29a5bd4SVlad Yasevich auth_chunks->chunks[0] = SCTP_CID_ASCONF; 91a29a5bd4SVlad Yasevich auth_chunks->chunks[1] = SCTP_CID_ASCONF_ACK; 92cb0dc77dSAl Viro auth_chunks->param_hdr.length = 933c918704SXin Long htons(sizeof(struct sctp_paramhdr) + 2); 94a29a5bd4SVlad Yasevich } 9560208f79SXin Long 9660208f79SXin Long /* Allocate and initialize transorms arrays for supported 9760208f79SXin Long * HMACs. 9860208f79SXin Long */ 9960208f79SXin Long err = sctp_auth_init_hmacs(ep, gfp); 10060208f79SXin Long if (err) 10160208f79SXin Long goto nomem; 102a29a5bd4SVlad Yasevich } 103a29a5bd4SVlad Yasevich 1041da177e4SLinus Torvalds /* Initialize the base structure. */ 1051da177e4SLinus Torvalds /* What type of endpoint are we? */ 1061da177e4SLinus Torvalds ep->base.type = SCTP_EP_TYPE_SOCKET; 1071da177e4SLinus Torvalds 1081da177e4SLinus Torvalds /* Initialize the basic object fields. */ 109c638457aSReshetova, Elena refcount_set(&ep->base.refcnt, 1); 1100022d2ddSDaniel Borkmann ep->base.dead = false; 1111da177e4SLinus Torvalds 1121da177e4SLinus Torvalds /* Create an input queue. */ 1131da177e4SLinus Torvalds sctp_inq_init(&ep->base.inqueue); 1141da177e4SLinus Torvalds 1151da177e4SLinus Torvalds /* Set its top-half handler */ 116c4028958SDavid Howells sctp_inq_set_th_handler(&ep->base.inqueue, sctp_endpoint_bh_rcv); 1171da177e4SLinus Torvalds 1181da177e4SLinus Torvalds /* Initialize the bind addr area */ 1191da177e4SLinus Torvalds sctp_bind_addr_init(&ep->base.bind_addr, 0); 1201da177e4SLinus Torvalds 1211da177e4SLinus Torvalds /* Remember who we are attached to. */ 1221da177e4SLinus Torvalds ep->base.sk = sk; 1231da177e4SLinus Torvalds sock_hold(ep->base.sk); 1241da177e4SLinus Torvalds 1251da177e4SLinus Torvalds /* Create the lists of associations. */ 1261da177e4SLinus Torvalds INIT_LIST_HEAD(&ep->asocs); 1271da177e4SLinus Torvalds 1281da177e4SLinus Torvalds /* Use SCTP specific send buffer space queues. */ 129e1fc3b14SEric W. Biederman ep->sndbuf_policy = net->sctp.sndbuf_policy; 1304d93df0aSNeil Horman 131561b1733SWei Yongjun sk->sk_data_ready = sctp_data_ready; 1321da177e4SLinus Torvalds sk->sk_write_space = sctp_write_space; 1331da177e4SLinus Torvalds sock_set_flag(sk, SOCK_USE_WRITE_QUEUE); 1341da177e4SLinus Torvalds 135049b3ff5SNeil Horman /* Get the receive buffer policy for this endpoint */ 136e1fc3b14SEric W. Biederman ep->rcvbuf_policy = net->sctp.rcvbuf_policy; 137049b3ff5SNeil Horman 1381da177e4SLinus Torvalds /* Initialize the secret key used with cookie. */ 139570617e7SDaniel Borkmann get_random_bytes(ep->secret_key, sizeof(ep->secret_key)); 1401da177e4SLinus Torvalds 141a29a5bd4SVlad Yasevich /* SCTP-AUTH extensions*/ 142a29a5bd4SVlad Yasevich INIT_LIST_HEAD(&ep->endpoint_shared_keys); 14381ce0dbcSDan Carpenter null_key = sctp_auth_shkey_create(0, gfp); 144a29a5bd4SVlad Yasevich if (!null_key) 14560208f79SXin Long goto nomem_shkey; 146a29a5bd4SVlad Yasevich 147a29a5bd4SVlad Yasevich list_add(&null_key->key_list, &ep->endpoint_shared_keys); 148a29a5bd4SVlad Yasevich 149a29a5bd4SVlad Yasevich /* Add the null key to the endpoint shared keys list and 150a29a5bd4SVlad Yasevich * set the hmcas and chunks pointers. 151a29a5bd4SVlad Yasevich */ 152a29a5bd4SVlad Yasevich ep->auth_hmacs_list = auth_hmacs; 153a29a5bd4SVlad Yasevich ep->auth_chunk_list = auth_chunks; 15428aa4c26SXin Long ep->prsctp_enable = net->sctp.prsctp_enable; 155c28445c3SXin Long ep->reconf_enable = net->sctp.reconf_enable; 156a29a5bd4SVlad Yasevich 1571da177e4SLinus Torvalds return ep; 158a29a5bd4SVlad Yasevich 15960208f79SXin Long nomem_shkey: 16060208f79SXin Long sctp_auth_destroy_hmacs(ep->auth_hmacs); 161a29a5bd4SVlad Yasevich nomem: 162a29a5bd4SVlad Yasevich /* Free all allocations */ 163a29a5bd4SVlad Yasevich kfree(auth_hmacs); 164a29a5bd4SVlad Yasevich kfree(auth_chunks); 165a29a5bd4SVlad Yasevich kfree(ep->digest); 166a29a5bd4SVlad Yasevich return NULL; 167a29a5bd4SVlad Yasevich 1681da177e4SLinus Torvalds } 1691da177e4SLinus Torvalds 1701da177e4SLinus Torvalds /* Create a sctp_endpoint with all that boring stuff initialized. 1711da177e4SLinus Torvalds * Returns NULL if there isn't enough memory. 1721da177e4SLinus Torvalds */ 173dd0fc66fSAl Viro struct sctp_endpoint *sctp_endpoint_new(struct sock *sk, gfp_t gfp) 1741da177e4SLinus Torvalds { 1751da177e4SLinus Torvalds struct sctp_endpoint *ep; 1761da177e4SLinus Torvalds 1771da177e4SLinus Torvalds /* Build a local endpoint. */ 178939cfa75SDaniel Borkmann ep = kzalloc(sizeof(*ep), gfp); 1791da177e4SLinus Torvalds if (!ep) 1801da177e4SLinus Torvalds goto fail; 181939cfa75SDaniel Borkmann 1821da177e4SLinus Torvalds if (!sctp_endpoint_init(ep, sk, gfp)) 1831da177e4SLinus Torvalds goto fail_init; 184ff2266cdSDaniel Borkmann 1851da177e4SLinus Torvalds SCTP_DBG_OBJCNT_INC(ep); 1861da177e4SLinus Torvalds return ep; 1871da177e4SLinus Torvalds 1881da177e4SLinus Torvalds fail_init: 1891da177e4SLinus Torvalds kfree(ep); 1901da177e4SLinus Torvalds fail: 1911da177e4SLinus Torvalds return NULL; 1921da177e4SLinus Torvalds } 1931da177e4SLinus Torvalds 1941da177e4SLinus Torvalds /* Add an association to an endpoint. */ 1951da177e4SLinus Torvalds void sctp_endpoint_add_asoc(struct sctp_endpoint *ep, 1961da177e4SLinus Torvalds struct sctp_association *asoc) 1971da177e4SLinus Torvalds { 1981da177e4SLinus Torvalds struct sock *sk = ep->base.sk; 1991da177e4SLinus Torvalds 200de76e695SVlad Yasevich /* If this is a temporary association, don't bother 201de76e695SVlad Yasevich * since we'll be removing it shortly and don't 202de76e695SVlad Yasevich * want anyone to find it anyway. 203de76e695SVlad Yasevich */ 204de76e695SVlad Yasevich if (asoc->temp) 205de76e695SVlad Yasevich return; 206de76e695SVlad Yasevich 2071da177e4SLinus Torvalds /* Now just add it to our list of asocs */ 2081da177e4SLinus Torvalds list_add_tail(&asoc->asocs, &ep->asocs); 2091da177e4SLinus Torvalds 2101da177e4SLinus Torvalds /* Increment the backlog value for a TCP-style listening socket. */ 2111da177e4SLinus Torvalds if (sctp_style(sk, TCP) && sctp_sstate(sk, LISTENING)) 2121da177e4SLinus Torvalds sk->sk_ack_backlog++; 2131da177e4SLinus Torvalds } 2141da177e4SLinus Torvalds 2151da177e4SLinus Torvalds /* Free the endpoint structure. Delay cleanup until 2161da177e4SLinus Torvalds * all users have released their reference count on this structure. 2171da177e4SLinus Torvalds */ 2181da177e4SLinus Torvalds void sctp_endpoint_free(struct sctp_endpoint *ep) 2191da177e4SLinus Torvalds { 2200022d2ddSDaniel Borkmann ep->base.dead = true; 221cfdeef32SVlad Yasevich 222cbabf463SYafang Shao inet_sk_set_state(ep->base.sk, SCTP_SS_CLOSED); 223cfdeef32SVlad Yasevich 224cfdeef32SVlad Yasevich /* Unlink this endpoint, so we can't find it again! */ 225cfdeef32SVlad Yasevich sctp_unhash_endpoint(ep); 226cfdeef32SVlad Yasevich 2271da177e4SLinus Torvalds sctp_endpoint_put(ep); 2281da177e4SLinus Torvalds } 2291da177e4SLinus Torvalds 2301da177e4SLinus Torvalds /* Final destructor for endpoint. */ 2311da177e4SLinus Torvalds static void sctp_endpoint_destroy(struct sctp_endpoint *ep) 2321da177e4SLinus Torvalds { 2330a2fbac1SDaniel Borkmann struct sock *sk; 2341da177e4SLinus Torvalds 235bb33381dSDaniel Borkmann if (unlikely(!ep->base.dead)) { 236bb33381dSDaniel Borkmann WARN(1, "Attempt to destroy undead endpoint %p!\n", ep); 237bb33381dSDaniel Borkmann return; 238bb33381dSDaniel Borkmann } 2391da177e4SLinus Torvalds 240b68dbcabSVlad Yasevich /* Free the digest buffer */ 241b68dbcabSVlad Yasevich kfree(ep->digest); 242b68dbcabSVlad Yasevich 243a29a5bd4SVlad Yasevich /* SCTP-AUTH: Free up AUTH releated data such as shared keys 244a29a5bd4SVlad Yasevich * chunks and hmacs arrays that were allocated 245a29a5bd4SVlad Yasevich */ 246a29a5bd4SVlad Yasevich sctp_auth_destroy_keys(&ep->endpoint_shared_keys); 247a29a5bd4SVlad Yasevich kfree(ep->auth_hmacs_list); 248a29a5bd4SVlad Yasevich kfree(ep->auth_chunk_list); 249a29a5bd4SVlad Yasevich 250a29a5bd4SVlad Yasevich /* AUTH - Free any allocated HMAC transform containers */ 251a29a5bd4SVlad Yasevich sctp_auth_destroy_hmacs(ep->auth_hmacs); 252a29a5bd4SVlad Yasevich 2531da177e4SLinus Torvalds /* Cleanup. */ 2541da177e4SLinus Torvalds sctp_inq_free(&ep->base.inqueue); 2551da177e4SLinus Torvalds sctp_bind_addr_free(&ep->base.bind_addr); 2561da177e4SLinus Torvalds 257570617e7SDaniel Borkmann memset(ep->secret_key, 0, sizeof(ep->secret_key)); 258b5c37fe6SDaniel Borkmann 2590a2fbac1SDaniel Borkmann sk = ep->base.sk; 2600a2fbac1SDaniel Borkmann /* Remove and free the port */ 2610a2fbac1SDaniel Borkmann if (sctp_sk(sk)->bind_hash) 2620a2fbac1SDaniel Borkmann sctp_put_port(sk); 2630a2fbac1SDaniel Borkmann 26486fdb344SXin Long sctp_sk(sk)->ep = NULL; 2657f304b9eSXin Long /* Give up our hold on the sock */ 2660a2fbac1SDaniel Borkmann sock_put(sk); 2671da177e4SLinus Torvalds 2681da177e4SLinus Torvalds kfree(ep); 2691da177e4SLinus Torvalds SCTP_DBG_OBJCNT_DEC(ep); 2701da177e4SLinus Torvalds } 2711da177e4SLinus Torvalds 2721da177e4SLinus Torvalds /* Hold a reference to an endpoint. */ 2731da177e4SLinus Torvalds void sctp_endpoint_hold(struct sctp_endpoint *ep) 2741da177e4SLinus Torvalds { 275c638457aSReshetova, Elena refcount_inc(&ep->base.refcnt); 2761da177e4SLinus Torvalds } 2771da177e4SLinus Torvalds 2781da177e4SLinus Torvalds /* Release a reference to an endpoint and clean up if there are 2791da177e4SLinus Torvalds * no more references. 2801da177e4SLinus Torvalds */ 2811da177e4SLinus Torvalds void sctp_endpoint_put(struct sctp_endpoint *ep) 2821da177e4SLinus Torvalds { 283c638457aSReshetova, Elena if (refcount_dec_and_test(&ep->base.refcnt)) 2841da177e4SLinus Torvalds sctp_endpoint_destroy(ep); 2851da177e4SLinus Torvalds } 2861da177e4SLinus Torvalds 2871da177e4SLinus Torvalds /* Is this the endpoint we are looking for? */ 2881da177e4SLinus Torvalds struct sctp_endpoint *sctp_endpoint_is_match(struct sctp_endpoint *ep, 2894cdadcbcSEric W. Biederman struct net *net, 2901da177e4SLinus Torvalds const union sctp_addr *laddr) 2911da177e4SLinus Torvalds { 292559cf710SVlad Yasevich struct sctp_endpoint *retval = NULL; 2931da177e4SLinus Torvalds 2944cdadcbcSEric W. Biederman if ((htons(ep->base.bind_addr.port) == laddr->v4.sin_port) && 2954cdadcbcSEric W. Biederman net_eq(sock_net(ep->base.sk), net)) { 2961da177e4SLinus Torvalds if (sctp_bind_addr_match(&ep->base.bind_addr, laddr, 297559cf710SVlad Yasevich sctp_sk(ep->base.sk))) 2981da177e4SLinus Torvalds retval = ep; 2991da177e4SLinus Torvalds } 3001da177e4SLinus Torvalds 3011da177e4SLinus Torvalds return retval; 3021da177e4SLinus Torvalds } 3031da177e4SLinus Torvalds 3041da177e4SLinus Torvalds /* Find the association that goes with this chunk. 3054f008781SXin Long * We lookup the transport from hashtable at first, then get association 3064f008781SXin Long * through t->assoc. 3071da177e4SLinus Torvalds */ 308c79c0666SXin Long struct sctp_association *sctp_endpoint_lookup_assoc( 3091da177e4SLinus Torvalds const struct sctp_endpoint *ep, 3101da177e4SLinus Torvalds const union sctp_addr *paddr, 3111da177e4SLinus Torvalds struct sctp_transport **transport) 3121da177e4SLinus Torvalds { 313123ed979SVlad Yasevich struct sctp_association *asoc = NULL; 3144f008781SXin Long struct sctp_transport *t; 3151da177e4SLinus Torvalds 3161da177e4SLinus Torvalds *transport = NULL; 317deb85a6eSVlad Yasevich 318deb85a6eSVlad Yasevich /* If the local port is not set, there can't be any associations 319deb85a6eSVlad Yasevich * on this endpoint. 320deb85a6eSVlad Yasevich */ 321deb85a6eSVlad Yasevich if (!ep->base.bind_addr.port) 3225cb2cd68SXin Long return NULL; 3235cb2cd68SXin Long 3245cb2cd68SXin Long rcu_read_lock(); 3254f008781SXin Long t = sctp_epaddr_lookup_transport(ep, paddr); 326dd7445adSXin Long if (!t) 3274f008781SXin Long goto out; 328deb85a6eSVlad Yasevich 329123ed979SVlad Yasevich *transport = t; 3304f008781SXin Long asoc = t->asoc; 331deb85a6eSVlad Yasevich out: 3325cb2cd68SXin Long rcu_read_unlock(); 333123ed979SVlad Yasevich return asoc; 3341da177e4SLinus Torvalds } 3351da177e4SLinus Torvalds 3361da177e4SLinus Torvalds /* Look for any peeled off association from the endpoint that matches the 3371da177e4SLinus Torvalds * given peer address. 3381da177e4SLinus Torvalds */ 33953066538SXin Long bool sctp_endpoint_is_peeled_off(struct sctp_endpoint *ep, 3401da177e4SLinus Torvalds const union sctp_addr *paddr) 3411da177e4SLinus Torvalds { 3421da177e4SLinus Torvalds struct sctp_sockaddr_entry *addr; 3431da177e4SLinus Torvalds struct sctp_bind_addr *bp; 3444110cc25SEric W. Biederman struct net *net = sock_net(ep->base.sk); 3451da177e4SLinus Torvalds 3461da177e4SLinus Torvalds bp = &ep->base.bind_addr; 347559cf710SVlad Yasevich /* This function is called with the socket lock held, 348559cf710SVlad Yasevich * so the address_list can not change. 349559cf710SVlad Yasevich */ 350559cf710SVlad Yasevich list_for_each_entry(addr, &bp->address_list, list) { 3514110cc25SEric W. Biederman if (sctp_has_association(net, &addr->a, paddr)) 35253066538SXin Long return true; 3531da177e4SLinus Torvalds } 3541da177e4SLinus Torvalds 35553066538SXin Long return false; 3561da177e4SLinus Torvalds } 3571da177e4SLinus Torvalds 3581da177e4SLinus Torvalds /* Do delayed input processing. This is scheduled by sctp_rcv(). 3591da177e4SLinus Torvalds * This may be called on BH or task time. 3601da177e4SLinus Torvalds */ 361c4028958SDavid Howells static void sctp_endpoint_bh_rcv(struct work_struct *work) 3621da177e4SLinus Torvalds { 363c4028958SDavid Howells struct sctp_endpoint *ep = 364c4028958SDavid Howells container_of(work, struct sctp_endpoint, 365c4028958SDavid Howells base.inqueue.immediate); 3661da177e4SLinus Torvalds struct sctp_association *asoc; 3671da177e4SLinus Torvalds struct sock *sk; 36855e26eb9SEric W. Biederman struct net *net; 3691da177e4SLinus Torvalds struct sctp_transport *transport; 3701da177e4SLinus Torvalds struct sctp_chunk *chunk; 3711da177e4SLinus Torvalds struct sctp_inq *inqueue; 372bfc6f827SXin Long union sctp_subtype subtype; 37352106019SXin Long enum sctp_state state; 3741da177e4SLinus Torvalds int error = 0; 37542b2aa86SJustin P. Mattock int first_time = 1; /* is this the first time through the loop */ 3761da177e4SLinus Torvalds 3771da177e4SLinus Torvalds if (ep->base.dead) 3781da177e4SLinus Torvalds return; 3791da177e4SLinus Torvalds 3801da177e4SLinus Torvalds asoc = NULL; 3811da177e4SLinus Torvalds inqueue = &ep->base.inqueue; 3821da177e4SLinus Torvalds sk = ep->base.sk; 38355e26eb9SEric W. Biederman net = sock_net(sk); 3841da177e4SLinus Torvalds 3851da177e4SLinus Torvalds while (NULL != (chunk = sctp_inq_pop(inqueue))) { 3861da177e4SLinus Torvalds subtype = SCTP_ST_CHUNK(chunk->chunk_hdr->type); 3871da177e4SLinus Torvalds 388bbd0d598SVlad Yasevich /* If the first chunk in the packet is AUTH, do special 389bbd0d598SVlad Yasevich * processing specified in Section 6.3 of SCTP-AUTH spec 390bbd0d598SVlad Yasevich */ 391bbd0d598SVlad Yasevich if (first_time && (subtype.chunk == SCTP_CID_AUTH)) { 392bbd0d598SVlad Yasevich struct sctp_chunkhdr *next_hdr; 393bbd0d598SVlad Yasevich 394bbd0d598SVlad Yasevich next_hdr = sctp_inq_peek(inqueue); 395bbd0d598SVlad Yasevich if (!next_hdr) 396bbd0d598SVlad Yasevich goto normal; 397bbd0d598SVlad Yasevich 398bbd0d598SVlad Yasevich /* If the next chunk is COOKIE-ECHO, skip the AUTH 399bbd0d598SVlad Yasevich * chunk while saving a pointer to it so we can do 400bbd0d598SVlad Yasevich * Authentication later (during cookie-echo 401bbd0d598SVlad Yasevich * processing). 402bbd0d598SVlad Yasevich */ 403bbd0d598SVlad Yasevich if (next_hdr->type == SCTP_CID_COOKIE_ECHO) { 404bbd0d598SVlad Yasevich chunk->auth_chunk = skb_clone(chunk->skb, 405bbd0d598SVlad Yasevich GFP_ATOMIC); 406bbd0d598SVlad Yasevich chunk->auth = 1; 407bbd0d598SVlad Yasevich continue; 408bbd0d598SVlad Yasevich } 409bbd0d598SVlad Yasevich } 410bbd0d598SVlad Yasevich normal: 4111da177e4SLinus Torvalds /* We might have grown an association since last we 4121da177e4SLinus Torvalds * looked, so try again. 4131da177e4SLinus Torvalds * 4141da177e4SLinus Torvalds * This happens when we've just processed our 4151da177e4SLinus Torvalds * COOKIE-ECHO chunk. 4161da177e4SLinus Torvalds */ 4171da177e4SLinus Torvalds if (NULL == chunk->asoc) { 4181da177e4SLinus Torvalds asoc = sctp_endpoint_lookup_assoc(ep, 4191da177e4SLinus Torvalds sctp_source(chunk), 4201da177e4SLinus Torvalds &transport); 4211da177e4SLinus Torvalds chunk->asoc = asoc; 4221da177e4SLinus Torvalds chunk->transport = transport; 4231da177e4SLinus Torvalds } 4241da177e4SLinus Torvalds 4251da177e4SLinus Torvalds state = asoc ? asoc->state : SCTP_STATE_CLOSED; 426bbd0d598SVlad Yasevich if (sctp_auth_recv_cid(subtype.chunk, asoc) && !chunk->auth) 427bbd0d598SVlad Yasevich continue; 4281da177e4SLinus Torvalds 4291da177e4SLinus Torvalds /* Remember where the last DATA chunk came from so we 4301da177e4SLinus Torvalds * know where to send the SACK. 4311da177e4SLinus Torvalds */ 4321da177e4SLinus Torvalds if (asoc && sctp_chunk_is_data(chunk)) 4331da177e4SLinus Torvalds asoc->peer.last_data_from = chunk->transport; 434196d6759SMichele Baldessari else { 435b01a2407SEric W. Biederman SCTP_INC_STATS(sock_net(ep->base.sk), SCTP_MIB_INCTRLCHUNKS); 436196d6759SMichele Baldessari if (asoc) 437196d6759SMichele Baldessari asoc->stats.ictrlchunks++; 438196d6759SMichele Baldessari } 4391da177e4SLinus Torvalds 4401da177e4SLinus Torvalds if (chunk->transport) 441e575235fSDaniel Borkmann chunk->transport->last_time_heard = ktime_get(); 4421da177e4SLinus Torvalds 44355e26eb9SEric W. Biederman error = sctp_do_sm(net, SCTP_EVENT_T_CHUNK, subtype, state, 4441da177e4SLinus Torvalds ep, asoc, chunk, GFP_ATOMIC); 4451da177e4SLinus Torvalds 4461da177e4SLinus Torvalds if (error && chunk) 4471da177e4SLinus Torvalds chunk->pdiscard = 1; 4481da177e4SLinus Torvalds 4491da177e4SLinus Torvalds /* Check to see if the endpoint is freed in response to 4501da177e4SLinus Torvalds * the incoming chunk. If so, get out of the while loop. 4511da177e4SLinus Torvalds */ 4521da177e4SLinus Torvalds if (!sctp_sk(sk)->ep) 4531da177e4SLinus Torvalds break; 454bbd0d598SVlad Yasevich 455bbd0d598SVlad Yasevich if (first_time) 456bbd0d598SVlad Yasevich first_time = 0; 4571da177e4SLinus Torvalds } 4581da177e4SLinus Torvalds } 459